CertificateRequest.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using System.Collections;
  5. using System.IO;
  6. using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1;
  7. using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1.X509;
  8. using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  9. namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Tls
  10. {
  11. /// <summary>Parsing and encoding of a <i>CertificateRequest</i> struct from RFC 4346.</summary>
  12. /// <remarks>
  13. /// <pre>
  14. /// struct {
  15. /// ClientCertificateType certificate_types&lt;1..2^8-1&gt;;
  16. /// DistinguishedName certificate_authorities&lt;3..2^16-1&gt;;
  17. /// } CertificateRequest;
  18. /// </pre>
  19. /// Updated for RFC 5246:
  20. /// <pre>
  21. /// struct {
  22. /// ClientCertificateType certificate_types &lt;1..2 ^ 8 - 1&gt;;
  23. /// SignatureAndHashAlgorithm supported_signature_algorithms &lt;2 ^ 16 - 1&gt;;
  24. /// DistinguishedName certificate_authorities &lt;0..2 ^ 16 - 1&gt;;
  25. /// } CertificateRequest;
  26. /// </pre>
  27. /// Revised for RFC 8446:
  28. /// <pre>
  29. /// struct {
  30. /// opaque certificate_request_context &lt;0..2 ^ 8 - 1&gt;;
  31. /// Extension extensions &lt;2..2 ^ 16 - 1&gt;;
  32. /// } CertificateRequest;
  33. /// </pre>
  34. /// </remarks>
  35. /// <seealso cref="ClientCertificateType"/>
  36. /// <seealso cref="X509Name"/>
  37. public sealed class CertificateRequest
  38. {
  39. /// <exception cref="IOException"/>
  40. private static IList CheckSupportedSignatureAlgorithms(IList supportedSignatureAlgorithms,
  41. short alertDescription)
  42. {
  43. if (null == supportedSignatureAlgorithms)
  44. throw new TlsFatalAlert(alertDescription, "'signature_algorithms' is required");
  45. return supportedSignatureAlgorithms;
  46. }
  47. private readonly byte[] m_certificateRequestContext;
  48. private readonly short[] m_certificateTypes;
  49. private readonly IList m_supportedSignatureAlgorithms;
  50. private readonly IList m_supportedSignatureAlgorithmsCert;
  51. private readonly IList m_certificateAuthorities;
  52. /// <param name="certificateTypes">see <see cref="ClientCertificateType"/> for valid constants.</param>
  53. /// <param name="supportedSignatureAlgorithms"></param>
  54. /// <param name="certificateAuthorities">an <see cref="IList"/> of <see cref="X509Name"/>.</param>
  55. public CertificateRequest(short[] certificateTypes, IList supportedSignatureAlgorithms,
  56. IList certificateAuthorities)
  57. : this(null, certificateTypes, supportedSignatureAlgorithms, null, certificateAuthorities)
  58. {
  59. }
  60. // TODO[tls13] Prefer to manage the certificateRequestContext internally only?
  61. /// <exception cref="IOException"/>
  62. public CertificateRequest(byte[] certificateRequestContext, IList supportedSignatureAlgorithms,
  63. IList supportedSignatureAlgorithmsCert, IList certificateAuthorities)
  64. : this(certificateRequestContext, null,
  65. CheckSupportedSignatureAlgorithms(supportedSignatureAlgorithms, AlertDescription.internal_error),
  66. supportedSignatureAlgorithmsCert, certificateAuthorities)
  67. {
  68. /*
  69. * TODO[tls13] Removed certificateTypes, added certificate_request_context, added extensions
  70. * (required: signature_algorithms, optional: status_request, signed_certificate_timestamp,
  71. * certificate_authorities, oid_filters, signature_algorithms_cert)
  72. */
  73. }
  74. private CertificateRequest(byte[] certificateRequestContext, short[] certificateTypes,
  75. IList supportedSignatureAlgorithms, IList supportedSignatureAlgorithmsCert, IList certificateAuthorities)
  76. {
  77. if (null != certificateRequestContext && !TlsUtilities.IsValidUint8(certificateRequestContext.Length))
  78. throw new ArgumentException("cannot be longer than 255", "certificateRequestContext");
  79. if (null != certificateTypes
  80. && (certificateTypes.Length < 1 || !TlsUtilities.IsValidUint8(certificateTypes.Length)))
  81. {
  82. throw new ArgumentException("should have length from 1 to 255", "certificateTypes");
  83. }
  84. this.m_certificateRequestContext = TlsUtilities.Clone(certificateRequestContext);
  85. this.m_certificateTypes = certificateTypes;
  86. this.m_supportedSignatureAlgorithms = supportedSignatureAlgorithms;
  87. this.m_supportedSignatureAlgorithmsCert = supportedSignatureAlgorithmsCert;
  88. this.m_certificateAuthorities = certificateAuthorities;
  89. }
  90. public byte[] GetCertificateRequestContext()
  91. {
  92. return TlsUtilities.Clone(m_certificateRequestContext);
  93. }
  94. /// <returns>an array of certificate types</returns>
  95. /// <seealso cref="ClientCertificateType"/>
  96. public short[] CertificateTypes
  97. {
  98. get { return m_certificateTypes; }
  99. }
  100. /// <returns>an <see cref="IList"/> of <see cref="SignatureAndHashAlgorithm"/> (or null before TLS 1.2).
  101. /// </returns>
  102. public IList SupportedSignatureAlgorithms
  103. {
  104. get { return m_supportedSignatureAlgorithms; }
  105. }
  106. /// <returns>an optional <see cref="IList"/> of <see cref="SignatureAndHashAlgorithm"/>. May be non-null from
  107. /// TLS 1.3 onwards.</returns>
  108. public IList SupportedSignatureAlgorithmsCert
  109. {
  110. get { return m_supportedSignatureAlgorithmsCert; }
  111. }
  112. /// <returns>an <see cref="IList"/> of <see cref="X509Name"/>.</returns>
  113. public IList CertificateAuthorities
  114. {
  115. get { return m_certificateAuthorities; }
  116. }
  117. public bool HasCertificateRequestContext(byte[] certificateRequestContext)
  118. {
  119. return Arrays.AreEqual(m_certificateRequestContext, certificateRequestContext);
  120. }
  121. /// <summary>Encode this <see cref="CertificateRequest"/> to a <see cref="Stream"/>.</summary>
  122. /// <param name="context">the <see cref="TlsContext"/> of the current connection.</param>
  123. /// <param name="output">the <see cref="Stream"/> to encode to.</param>
  124. /// <exception cref="IOException"/>
  125. public void Encode(TlsContext context, Stream output)
  126. {
  127. ProtocolVersion negotiatedVersion = context.ServerVersion;
  128. bool isTlsV12 = TlsUtilities.IsTlsV12(negotiatedVersion);
  129. bool isTlsV13 = TlsUtilities.IsTlsV13(negotiatedVersion);
  130. if (isTlsV13 != (null != m_certificateRequestContext) ||
  131. isTlsV13 != (null == m_certificateTypes) ||
  132. isTlsV12 != (null != m_supportedSignatureAlgorithms) ||
  133. (!isTlsV13 && (null != m_supportedSignatureAlgorithmsCert)))
  134. {
  135. throw new InvalidOperationException();
  136. }
  137. if (isTlsV13)
  138. {
  139. TlsUtilities.WriteOpaque8(m_certificateRequestContext, output);
  140. IDictionary extensions = BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.CreateHashtable();
  141. TlsExtensionsUtilities.AddSignatureAlgorithmsExtension(extensions, m_supportedSignatureAlgorithms);
  142. if (null != m_supportedSignatureAlgorithmsCert)
  143. {
  144. TlsExtensionsUtilities.AddSignatureAlgorithmsCertExtension(extensions,
  145. m_supportedSignatureAlgorithmsCert);
  146. }
  147. if (null != m_certificateAuthorities)
  148. {
  149. TlsExtensionsUtilities.AddCertificateAuthoritiesExtension(extensions, m_certificateAuthorities);
  150. }
  151. byte[] extEncoding = TlsProtocol.WriteExtensionsData(extensions);
  152. TlsUtilities.WriteOpaque16(extEncoding, output);
  153. return;
  154. }
  155. TlsUtilities.WriteUint8ArrayWithUint8Length(m_certificateTypes, output);
  156. if (isTlsV12)
  157. {
  158. // TODO Check whether SignatureAlgorithm.anonymous is allowed here
  159. TlsUtilities.EncodeSupportedSignatureAlgorithms(m_supportedSignatureAlgorithms, output);
  160. }
  161. if (m_certificateAuthorities == null || m_certificateAuthorities.Count < 1)
  162. {
  163. TlsUtilities.WriteUint16(0, output);
  164. }
  165. else
  166. {
  167. IList derEncodings = BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.CreateArrayList(m_certificateAuthorities.Count);
  168. int totalLength = 0;
  169. foreach (X509Name certificateAuthority in m_certificateAuthorities)
  170. {
  171. byte[] derEncoding = certificateAuthority.GetEncoded(Asn1Encodable.Der);
  172. derEncodings.Add(derEncoding);
  173. totalLength += derEncoding.Length + 2;
  174. }
  175. TlsUtilities.CheckUint16(totalLength);
  176. TlsUtilities.WriteUint16(totalLength, output);
  177. foreach (byte[] derEncoding in derEncodings)
  178. {
  179. TlsUtilities.WriteOpaque16(derEncoding, output);
  180. }
  181. }
  182. }
  183. /// <summary>Parse a <see cref="CertificateRequest"/> from a <see cref="Stream"/></summary>
  184. /// <param name="context">the <see cref="TlsContext"/> of the current connection.</param>
  185. /// <param name="input">the <see cref="Stream"/> to parse from.</param>
  186. /// <returns>a <see cref="CertificateRequest"/> object.</returns>
  187. /// <exception cref="IOException"/>
  188. public static CertificateRequest Parse(TlsContext context, Stream input)
  189. {
  190. ProtocolVersion negotiatedVersion = context.ServerVersion;
  191. bool isTlsV13 = TlsUtilities.IsTlsV13(negotiatedVersion);
  192. if (isTlsV13)
  193. {
  194. byte[] certificateRequestContext = TlsUtilities.ReadOpaque8(input);
  195. /*
  196. * TODO[tls13] required: signature_algorithms; optional: status_request,
  197. * signed_certificate_timestamp, certificate_authorities, oid_filters,
  198. * signature_algorithms_cert
  199. */
  200. byte[] extEncoding = TlsUtilities.ReadOpaque16(input);
  201. IDictionary extensions = TlsProtocol.ReadExtensionsData13(HandshakeType.certificate_request,
  202. extEncoding);
  203. IList supportedSignatureAlgorithms13 = CheckSupportedSignatureAlgorithms(
  204. TlsExtensionsUtilities.GetSignatureAlgorithmsExtension(extensions),
  205. AlertDescription.missing_extension);
  206. IList supportedSignatureAlgorithmsCert13 = TlsExtensionsUtilities
  207. .GetSignatureAlgorithmsCertExtension(extensions);
  208. IList certificateAuthorities13 = TlsExtensionsUtilities.GetCertificateAuthoritiesExtension(extensions);
  209. return new CertificateRequest(certificateRequestContext, supportedSignatureAlgorithms13,
  210. supportedSignatureAlgorithmsCert13, certificateAuthorities13);
  211. }
  212. bool isTLSv12 = TlsUtilities.IsTlsV12(negotiatedVersion);
  213. short[] certificateTypes = TlsUtilities.ReadUint8ArrayWithUint8Length(input, 1);
  214. IList supportedSignatureAlgorithms = null;
  215. if (isTLSv12)
  216. {
  217. supportedSignatureAlgorithms = TlsUtilities.ParseSupportedSignatureAlgorithms(input);
  218. }
  219. IList certificateAuthorities = null;
  220. {
  221. byte[] certAuthData = TlsUtilities.ReadOpaque16(input);
  222. if (certAuthData.Length > 0)
  223. {
  224. certificateAuthorities = BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.CreateArrayList();
  225. MemoryStream bis = new MemoryStream(certAuthData, false);
  226. do
  227. {
  228. byte[] derEncoding = TlsUtilities.ReadOpaque16(bis, 1);
  229. Asn1Object asn1 = TlsUtilities.ReadDerObject(derEncoding);
  230. certificateAuthorities.Add(X509Name.GetInstance(asn1));
  231. }
  232. while (bis.Position < bis.Length);
  233. }
  234. }
  235. return new CertificateRequest(certificateTypes, supportedSignatureAlgorithms, certificateAuthorities);
  236. }
  237. }
  238. }
  239. #pragma warning restore
  240. #endif