CertificateRequest.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using System.Collections.Generic;
  5. using System.IO;
  6. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Asn1;
  7. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Asn1.X509;
  8. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  9. namespace Best.HTTP.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<SignatureAndHashAlgorithm> CheckSupportedSignatureAlgorithms(
  41. IList<SignatureAndHashAlgorithm> supportedSignatureAlgorithms, 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<SignatureAndHashAlgorithm> m_supportedSignatureAlgorithms;
  50. private readonly IList<SignatureAndHashAlgorithm> m_supportedSignatureAlgorithmsCert;
  51. private readonly IList<X509Name> 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{T}"/> of <see cref="X509Name"/>.</param>
  55. public CertificateRequest(short[] certificateTypes,
  56. IList<SignatureAndHashAlgorithm> supportedSignatureAlgorithms, IList<X509Name> 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,
  63. IList<SignatureAndHashAlgorithm> supportedSignatureAlgorithms,
  64. IList<SignatureAndHashAlgorithm> supportedSignatureAlgorithmsCert, IList<X509Name> certificateAuthorities)
  65. : this(certificateRequestContext, null,
  66. CheckSupportedSignatureAlgorithms(supportedSignatureAlgorithms, AlertDescription.internal_error),
  67. supportedSignatureAlgorithmsCert, certificateAuthorities)
  68. {
  69. /*
  70. * TODO[tls13] Removed certificateTypes, added certificate_request_context, added extensions
  71. * (required: signature_algorithms, optional: status_request, signed_certificate_timestamp,
  72. * certificate_authorities, oid_filters, signature_algorithms_cert)
  73. */
  74. }
  75. private CertificateRequest(byte[] certificateRequestContext, short[] certificateTypes,
  76. IList<SignatureAndHashAlgorithm> supportedSignatureAlgorithms,
  77. IList<SignatureAndHashAlgorithm> supportedSignatureAlgorithmsCert, IList<X509Name> certificateAuthorities)
  78. {
  79. if (null != certificateRequestContext && !TlsUtilities.IsValidUint8(certificateRequestContext.Length))
  80. throw new ArgumentException("cannot be longer than 255", "certificateRequestContext");
  81. if (null != certificateTypes
  82. && (certificateTypes.Length < 1 || !TlsUtilities.IsValidUint8(certificateTypes.Length)))
  83. {
  84. throw new ArgumentException("should have length from 1 to 255", "certificateTypes");
  85. }
  86. this.m_certificateRequestContext = TlsUtilities.Clone(certificateRequestContext);
  87. this.m_certificateTypes = certificateTypes;
  88. this.m_supportedSignatureAlgorithms = supportedSignatureAlgorithms;
  89. this.m_supportedSignatureAlgorithmsCert = supportedSignatureAlgorithmsCert;
  90. this.m_certificateAuthorities = certificateAuthorities;
  91. }
  92. public byte[] GetCertificateRequestContext()
  93. {
  94. return TlsUtilities.Clone(m_certificateRequestContext);
  95. }
  96. /// <returns>an array of certificate types</returns>
  97. /// <seealso cref="ClientCertificateType"/>
  98. public short[] CertificateTypes
  99. {
  100. get { return m_certificateTypes; }
  101. }
  102. /// <returns>an <see cref="IList{T}"/> of <see cref="SignatureAndHashAlgorithm"/> (or null before TLS 1.2).
  103. /// </returns>
  104. public IList<SignatureAndHashAlgorithm> SupportedSignatureAlgorithms
  105. {
  106. get { return m_supportedSignatureAlgorithms; }
  107. }
  108. /// <returns>an optional <see cref="IList{T}"/> of <see cref="SignatureAndHashAlgorithm"/>. May be non-null from
  109. /// TLS 1.3 onwards.</returns>
  110. public IList<SignatureAndHashAlgorithm> SupportedSignatureAlgorithmsCert
  111. {
  112. get { return m_supportedSignatureAlgorithmsCert; }
  113. }
  114. /// <returns>an <see cref="IList{T}"/> of <see cref="X509Name"/>.</returns>
  115. public IList<X509Name> CertificateAuthorities
  116. {
  117. get { return m_certificateAuthorities; }
  118. }
  119. public bool HasCertificateRequestContext(byte[] certificateRequestContext)
  120. {
  121. return Arrays.AreEqual(m_certificateRequestContext, certificateRequestContext);
  122. }
  123. /// <summary>Encode this <see cref="CertificateRequest"/> to a <see cref="Stream"/>.</summary>
  124. /// <param name="context">the <see cref="TlsContext"/> of the current connection.</param>
  125. /// <param name="output">the <see cref="Stream"/> to encode to.</param>
  126. /// <exception cref="IOException"/>
  127. public void Encode(TlsContext context, Stream output)
  128. {
  129. ProtocolVersion negotiatedVersion = context.ServerVersion;
  130. bool isTlsV12 = TlsUtilities.IsTlsV12(negotiatedVersion);
  131. bool isTlsV13 = TlsUtilities.IsTlsV13(negotiatedVersion);
  132. if (isTlsV13 != (null != m_certificateRequestContext) ||
  133. isTlsV13 != (null == m_certificateTypes) ||
  134. isTlsV12 != (null != m_supportedSignatureAlgorithms) ||
  135. (!isTlsV13 && (null != m_supportedSignatureAlgorithmsCert)))
  136. {
  137. throw new InvalidOperationException();
  138. }
  139. if (isTlsV13)
  140. {
  141. TlsUtilities.WriteOpaque8(m_certificateRequestContext, output);
  142. var extensions = new Dictionary<int, byte[]>();
  143. TlsExtensionsUtilities.AddSignatureAlgorithmsExtension(extensions, m_supportedSignatureAlgorithms);
  144. if (null != m_supportedSignatureAlgorithmsCert)
  145. {
  146. TlsExtensionsUtilities.AddSignatureAlgorithmsCertExtension(extensions,
  147. m_supportedSignatureAlgorithmsCert);
  148. }
  149. if (null != m_certificateAuthorities)
  150. {
  151. TlsExtensionsUtilities.AddCertificateAuthoritiesExtension(extensions, m_certificateAuthorities);
  152. }
  153. byte[] extEncoding = TlsProtocol.WriteExtensionsData(extensions);
  154. TlsUtilities.WriteOpaque16(extEncoding, output);
  155. return;
  156. }
  157. TlsUtilities.WriteUint8ArrayWithUint8Length(m_certificateTypes, output);
  158. if (isTlsV12)
  159. {
  160. // TODO Check whether SignatureAlgorithm.anonymous is allowed here
  161. TlsUtilities.EncodeSupportedSignatureAlgorithms(m_supportedSignatureAlgorithms, output);
  162. }
  163. if (m_certificateAuthorities == null || m_certificateAuthorities.Count < 1)
  164. {
  165. TlsUtilities.WriteUint16(0, output);
  166. }
  167. else
  168. {
  169. var derEncodings = new List<byte[]>(m_certificateAuthorities.Count);
  170. int totalLength = 0;
  171. foreach (X509Name certificateAuthority in m_certificateAuthorities)
  172. {
  173. byte[] derEncoding = certificateAuthority.GetEncoded(Asn1Encodable.Der);
  174. derEncodings.Add(derEncoding);
  175. totalLength += derEncoding.Length + 2;
  176. }
  177. TlsUtilities.CheckUint16(totalLength);
  178. TlsUtilities.WriteUint16(totalLength, output);
  179. foreach (byte[] derEncoding in derEncodings)
  180. {
  181. TlsUtilities.WriteOpaque16(derEncoding, output);
  182. }
  183. }
  184. }
  185. /// <summary>Parse a <see cref="CertificateRequest"/> from a <see cref="Stream"/></summary>
  186. /// <param name="context">the <see cref="TlsContext"/> of the current connection.</param>
  187. /// <param name="input">the <see cref="Stream"/> to parse from.</param>
  188. /// <returns>a <see cref="CertificateRequest"/> object.</returns>
  189. /// <exception cref="IOException"/>
  190. public static CertificateRequest Parse(TlsContext context, Stream input)
  191. {
  192. ProtocolVersion negotiatedVersion = context.ServerVersion;
  193. bool isTlsV13 = TlsUtilities.IsTlsV13(negotiatedVersion);
  194. if (isTlsV13)
  195. {
  196. byte[] certificateRequestContext = TlsUtilities.ReadOpaque8(input);
  197. /*
  198. * TODO[tls13] required: signature_algorithms; optional: status_request,
  199. * signed_certificate_timestamp, certificate_authorities, oid_filters,
  200. * signature_algorithms_cert
  201. */
  202. byte[] extEncoding = TlsUtilities.ReadOpaque16(input);
  203. var extensions = TlsProtocol.ReadExtensionsData13(HandshakeType.certificate_request, extEncoding);
  204. var supportedSignatureAlgorithms13 = CheckSupportedSignatureAlgorithms(
  205. TlsExtensionsUtilities.GetSignatureAlgorithmsExtension(extensions),
  206. AlertDescription.missing_extension);
  207. var supportedSignatureAlgorithmsCert13 = TlsExtensionsUtilities
  208. .GetSignatureAlgorithmsCertExtension(extensions);
  209. var certificateAuthorities13 = TlsExtensionsUtilities.GetCertificateAuthoritiesExtension(extensions);
  210. return new CertificateRequest(certificateRequestContext, supportedSignatureAlgorithms13,
  211. supportedSignatureAlgorithmsCert13, certificateAuthorities13);
  212. }
  213. bool isTLSv12 = TlsUtilities.IsTlsV12(negotiatedVersion);
  214. short[] certificateTypes = TlsUtilities.ReadUint8ArrayWithUint8Length(input, 1);
  215. IList<SignatureAndHashAlgorithm> supportedSignatureAlgorithms = null;
  216. if (isTLSv12)
  217. {
  218. supportedSignatureAlgorithms = TlsUtilities.ParseSupportedSignatureAlgorithms(input);
  219. }
  220. IList<X509Name> certificateAuthorities = null;
  221. {
  222. byte[] certAuthData = TlsUtilities.ReadOpaque16(input);
  223. if (certAuthData.Length > 0)
  224. {
  225. certificateAuthorities = new List<X509Name>();
  226. MemoryStream bis = new MemoryStream(certAuthData, false);
  227. do
  228. {
  229. byte[] derEncoding = TlsUtilities.ReadOpaque16(bis, 1);
  230. Asn1Object asn1 = TlsUtilities.ReadAsn1Object(derEncoding);
  231. X509Name ca = X509Name.GetInstance(asn1);
  232. TlsUtilities.RequireDerEncoding(ca, derEncoding);
  233. certificateAuthorities.Add(ca);
  234. }
  235. while (bis.Position < bis.Length);
  236. }
  237. }
  238. return new CertificateRequest(certificateTypes, supportedSignatureAlgorithms, certificateAuthorities);
  239. }
  240. }
  241. }
  242. #pragma warning restore
  243. #endif