CertificateStatus.cs 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  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.Ocsp;
  8. namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Tls
  9. {
  10. public sealed class CertificateStatus
  11. {
  12. private readonly short m_statusType;
  13. private readonly object m_response;
  14. public CertificateStatus(short statusType, object response)
  15. {
  16. if (!IsCorrectType(statusType, response))
  17. throw new ArgumentException("not an instance of the correct type", "response");
  18. this.m_statusType = statusType;
  19. this.m_response = response;
  20. }
  21. public short StatusType
  22. {
  23. get { return m_statusType; }
  24. }
  25. public object Response
  26. {
  27. get { return m_response; }
  28. }
  29. public OcspResponse OcspResponse
  30. {
  31. get
  32. {
  33. if (!IsCorrectType(CertificateStatusType.ocsp, m_response))
  34. throw new InvalidOperationException("'response' is not an OCSPResponse");
  35. return (OcspResponse)m_response;
  36. }
  37. }
  38. /// <summary>an <see cref="IList{T}"/> of (possibly null) <see cref="Asn1.Ocsp.OcspResponse"/>.</summary>
  39. public IList<OcspResponse> OcspResponseList
  40. {
  41. get
  42. {
  43. if (!IsCorrectType(CertificateStatusType.ocsp_multi, m_response))
  44. throw new InvalidOperationException("'response' is not an OCSPResponseList");
  45. return (IList<OcspResponse>)m_response;
  46. }
  47. }
  48. /// <summary>Encode this <see cref="CertificateStatus"/> to a <see cref="Stream"/>.</summary>
  49. /// <param name="output">the <see cref="Stream"/> to encode to.</param>
  50. /// <exception cref="IOException"/>
  51. public void Encode(Stream output)
  52. {
  53. TlsUtilities.WriteUint8(m_statusType, output);
  54. switch (m_statusType)
  55. {
  56. case CertificateStatusType.ocsp:
  57. {
  58. OcspResponse ocspResponse = (OcspResponse)m_response;
  59. byte[] derEncoding = ocspResponse.GetEncoded(Asn1Encodable.Der);
  60. TlsUtilities.WriteOpaque24(derEncoding, output);
  61. break;
  62. }
  63. case CertificateStatusType.ocsp_multi:
  64. {
  65. var ocspResponseList = (IList<OcspResponse>)m_response;
  66. int count = ocspResponseList.Count;
  67. var derEncodings = new List<byte[]>(count);
  68. long totalLength = 0;
  69. foreach (OcspResponse ocspResponse in ocspResponseList)
  70. {
  71. if (ocspResponse == null)
  72. {
  73. derEncodings.Add(TlsUtilities.EmptyBytes);
  74. }
  75. else
  76. {
  77. byte[] derEncoding = ocspResponse.GetEncoded(Asn1Encodable.Der);
  78. derEncodings.Add(derEncoding);
  79. totalLength += derEncoding.Length;
  80. }
  81. totalLength += 3;
  82. }
  83. TlsUtilities.CheckUint24(totalLength);
  84. TlsUtilities.WriteUint24((int)totalLength, output);
  85. foreach (byte[] derEncoding in derEncodings)
  86. {
  87. TlsUtilities.WriteOpaque24(derEncoding, output);
  88. }
  89. break;
  90. }
  91. default:
  92. throw new TlsFatalAlert(AlertDescription.internal_error);
  93. }
  94. }
  95. /// <summary>Parse a <see cref="CertificateStatus"/> from a <see cref="Stream"/>.</summary>
  96. /// <param name="context">the <see cref="TlsContext"/> of the current connection.</param>
  97. /// <param name="input">the <see cref="Stream"/> to parse from.</param>
  98. /// <returns>a <see cref="CertificateStatus"/> object.</returns>
  99. /// <exception cref="IOException"/>
  100. public static CertificateStatus Parse(TlsContext context, Stream input)
  101. {
  102. SecurityParameters securityParameters = context.SecurityParameters;
  103. Certificate peerCertificate = securityParameters.PeerCertificate;
  104. if (null == peerCertificate || peerCertificate.IsEmpty
  105. || CertificateType.X509 != peerCertificate.CertificateType)
  106. {
  107. throw new TlsFatalAlert(AlertDescription.internal_error);
  108. }
  109. int certificateCount = peerCertificate.Length;
  110. int statusRequestVersion = securityParameters.StatusRequestVersion;
  111. short status_type = TlsUtilities.ReadUint8(input);
  112. object response;
  113. switch (status_type)
  114. {
  115. case CertificateStatusType.ocsp:
  116. {
  117. RequireStatusRequestVersion(1, statusRequestVersion);
  118. byte[] derEncoding = TlsUtilities.ReadOpaque24(input, 1);
  119. response = ParseOcspResponse(derEncoding);
  120. break;
  121. }
  122. case CertificateStatusType.ocsp_multi:
  123. {
  124. RequireStatusRequestVersion(2, statusRequestVersion);
  125. byte[] ocsp_response_list = TlsUtilities.ReadOpaque24(input, 1);
  126. MemoryStream buf = new MemoryStream(ocsp_response_list, false);
  127. var ocspResponseList = new List<OcspResponse>();
  128. while (buf.Position < buf.Length)
  129. {
  130. if (ocspResponseList.Count >= certificateCount)
  131. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  132. int length = TlsUtilities.ReadUint24(buf);
  133. if (length < 1)
  134. {
  135. ocspResponseList.Add(null);
  136. }
  137. else
  138. {
  139. byte[] derEncoding = TlsUtilities.ReadFully(length, buf);
  140. ocspResponseList.Add(ParseOcspResponse(derEncoding));
  141. }
  142. }
  143. response = ocspResponseList;
  144. break;
  145. }
  146. default:
  147. throw new TlsFatalAlert(AlertDescription.decode_error);
  148. }
  149. return new CertificateStatus(status_type, response);
  150. }
  151. private static bool IsCorrectType(short statusType, object response)
  152. {
  153. switch (statusType)
  154. {
  155. case CertificateStatusType.ocsp:
  156. return response is OcspResponse;
  157. case CertificateStatusType.ocsp_multi:
  158. return IsOcspResponseList(response);
  159. default:
  160. throw new ArgumentException("unsupported CertificateStatusType", "statusType");
  161. }
  162. }
  163. private static bool IsOcspResponseList(object response)
  164. {
  165. return response is IList<OcspResponse> v && v.Count > 0;
  166. }
  167. /// <exception cref="IOException"/>
  168. private static OcspResponse ParseOcspResponse(byte[] derEncoding)
  169. {
  170. Asn1Object asn1 = TlsUtilities.ReadAsn1Object(derEncoding);
  171. OcspResponse ocspResponse = OcspResponse.GetInstance(asn1);
  172. TlsUtilities.RequireDerEncoding(ocspResponse, derEncoding);
  173. return ocspResponse;
  174. }
  175. /// <exception cref="IOException"/>
  176. private static void RequireStatusRequestVersion(int minVersion, int statusRequestVersion)
  177. {
  178. if (statusRequestVersion < minVersion)
  179. throw new TlsFatalAlert(AlertDescription.decode_error);
  180. }
  181. }
  182. }
  183. #pragma warning restore
  184. #endif