TimeStampToken.cs 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using System.IO;
  5. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Asn1;
  6. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Asn1.Ess;
  7. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Asn1.Nist;
  8. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Asn1.Oiw;
  9. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Asn1.Pkcs;
  10. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Asn1.Tsp;
  11. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Asn1.X509;
  12. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Cms;
  13. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Security;
  14. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Security.Certificates;
  15. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  16. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities.Collections;
  17. using Best.HTTP.SecureProtocol.Org.BouncyCastle.X509;
  18. namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Tsp
  19. {
  20. public class TimeStampToken
  21. {
  22. private readonly CmsSignedData tsToken;
  23. private readonly SignerInformation tsaSignerInfo;
  24. // private readonly DateTime genTime;
  25. private readonly TimeStampTokenInfo tstInfo;
  26. private readonly CertID certID;
  27. public TimeStampToken(
  28. Asn1.Cms.ContentInfo contentInfo)
  29. : this(new CmsSignedData(contentInfo))
  30. {
  31. }
  32. public TimeStampToken(
  33. CmsSignedData signedData)
  34. {
  35. this.tsToken = signedData;
  36. if (!this.tsToken.SignedContentType.Equals(PkcsObjectIdentifiers.IdCTTstInfo))
  37. {
  38. throw new TspValidationException("ContentInfo object not for a time stamp.");
  39. }
  40. var signers = tsToken.GetSignerInfos().GetSigners();
  41. if (signers.Count != 1)
  42. {
  43. throw new ArgumentException("Time-stamp token signed by "
  44. + signers.Count
  45. + " signers, but it must contain just the TSA signature.");
  46. }
  47. var signerEnum = signers.GetEnumerator();
  48. signerEnum.MoveNext();
  49. tsaSignerInfo = signerEnum.Current;
  50. try
  51. {
  52. CmsProcessable content = tsToken.SignedContent;
  53. MemoryStream bOut = new MemoryStream();
  54. content.Write(bOut);
  55. this.tstInfo = new TimeStampTokenInfo(
  56. TstInfo.GetInstance(
  57. Asn1Object.FromByteArray(bOut.ToArray())));
  58. Asn1.Cms.Attribute attr = tsaSignerInfo.SignedAttributes[
  59. PkcsObjectIdentifiers.IdAASigningCertificate];
  60. // if (attr == null)
  61. // {
  62. // throw new TspValidationException(
  63. // "no signing certificate attribute found, time stamp invalid.");
  64. // }
  65. //
  66. // SigningCertificate signCert = SigningCertificate.GetInstance(
  67. // attr.AttrValues[0]);
  68. //
  69. // this.certID = EssCertID.GetInstance(signCert.GetCerts()[0]);
  70. if (attr != null)
  71. {
  72. if (attr.AttrValues[0] is SigningCertificateV2)
  73. {
  74. SigningCertificateV2 signCert = SigningCertificateV2.GetInstance(attr.AttrValues[0]);
  75. this.certID = new CertID(EssCertIDv2.GetInstance(signCert.GetCerts()[0]));
  76. }
  77. else
  78. {
  79. SigningCertificate signCert = SigningCertificate.GetInstance(attr.AttrValues[0]);
  80. this.certID = new CertID(EssCertID.GetInstance(signCert.GetCerts()[0]));
  81. }
  82. }
  83. else
  84. {
  85. attr = tsaSignerInfo.SignedAttributes[PkcsObjectIdentifiers.IdAASigningCertificateV2];
  86. if (attr == null)
  87. throw new TspValidationException("no signing certificate attribute found, time stamp invalid.");
  88. SigningCertificateV2 signCertV2 = SigningCertificateV2.GetInstance(attr.AttrValues[0]);
  89. this.certID = new CertID(EssCertIDv2.GetInstance(signCertV2.GetCerts()[0]));
  90. }
  91. }
  92. catch (CmsException e)
  93. {
  94. throw new TspException(e.Message, e.InnerException);
  95. }
  96. }
  97. public TimeStampTokenInfo TimeStampInfo
  98. {
  99. get { return tstInfo; }
  100. }
  101. public SignerID SignerID
  102. {
  103. get { return tsaSignerInfo.SignerID; }
  104. }
  105. public Asn1.Cms.AttributeTable SignedAttributes
  106. {
  107. get { return tsaSignerInfo.SignedAttributes; }
  108. }
  109. public Asn1.Cms.AttributeTable UnsignedAttributes
  110. {
  111. get { return tsaSignerInfo.UnsignedAttributes; }
  112. }
  113. public IStore<X509V2AttributeCertificate> GetAttributeCertificates() => tsToken.GetAttributeCertificates();
  114. public IStore<X509Certificate> GetCertificates() => tsToken.GetCertificates();
  115. public IStore<X509Crl> GetCrls() => tsToken.GetCrls();
  116. /**
  117. * Validate the time stamp token.
  118. * <p>
  119. * To be valid the token must be signed by the passed in certificate and
  120. * the certificate must be the one referred to by the SigningCertificate
  121. * attribute included in the hashed attributes of the token. The
  122. * certificate must also have the ExtendedKeyUsageExtension with only
  123. * KeyPurposeID.IdKPTimeStamping and have been valid at the time the
  124. * timestamp was created.
  125. * </p>
  126. * <p>
  127. * A successful call to validate means all the above are true.
  128. * </p>
  129. */
  130. public void Validate(
  131. X509Certificate cert)
  132. {
  133. try
  134. {
  135. byte[] hash = DigestUtilities.CalculateDigest(
  136. certID.GetHashAlgorithmName(), cert.GetEncoded());
  137. if (!Arrays.ConstantTimeAreEqual(certID.GetCertHash(), hash))
  138. throw new TspValidationException("certificate hash does not match certID hash.");
  139. if (certID.IssuerSerial != null)
  140. {
  141. if (!certID.IssuerSerial.Serial.HasValue(cert.SerialNumber))
  142. throw new TspValidationException("certificate serial number does not match certID for signature.");
  143. GeneralName[] names = certID.IssuerSerial.Issuer.GetNames();
  144. X509Name principal = PrincipalUtilities.GetIssuerX509Principal(cert);
  145. bool found = false;
  146. for (int i = 0; i != names.Length; i++)
  147. {
  148. if (names[i].TagNo == 4
  149. && X509Name.GetInstance(names[i].Name).Equivalent(principal))
  150. {
  151. found = true;
  152. break;
  153. }
  154. }
  155. if (!found)
  156. {
  157. throw new TspValidationException("certificate name does not match certID for signature. ");
  158. }
  159. }
  160. TspUtil.ValidateCertificate(cert);
  161. cert.CheckValidity(tstInfo.GenTime);
  162. if (!tsaSignerInfo.Verify(cert))
  163. {
  164. throw new TspValidationException("signature not created by certificate.");
  165. }
  166. }
  167. catch (CmsException e)
  168. {
  169. if (e.InnerException != null)
  170. {
  171. throw new TspException(e.Message, e.InnerException);
  172. }
  173. throw new TspException("CMS exception: " + e, e);
  174. }
  175. catch (CertificateEncodingException e)
  176. {
  177. throw new TspException("problem processing certificate: " + e, e);
  178. }
  179. catch (SecurityUtilityException e)
  180. {
  181. throw new TspException("cannot find algorithm: " + e.Message, e);
  182. }
  183. }
  184. /**
  185. * Return the underlying CmsSignedData object.
  186. *
  187. * @return the underlying CMS structure.
  188. */
  189. public CmsSignedData ToCmsSignedData()
  190. {
  191. return tsToken;
  192. }
  193. /**
  194. * Return a ASN.1 encoded byte stream representing the encoded object.
  195. *
  196. * @throws IOException if encoding fails.
  197. */
  198. public byte[] GetEncoded()
  199. {
  200. return tsToken.GetEncoded(Asn1Encodable.Der);
  201. }
  202. /**
  203. * return the ASN.1 encoded representation of this object using the specified encoding.
  204. *
  205. * @param encoding the ASN.1 encoding format to use ("BER" or "DER").
  206. */
  207. public byte[] GetEncoded(string encoding)
  208. {
  209. return tsToken.GetEncoded(encoding);
  210. }
  211. // perhaps this should be done using an interface on the ASN.1 classes...
  212. private class CertID
  213. {
  214. private EssCertID certID;
  215. private EssCertIDv2 certIDv2;
  216. internal CertID(EssCertID certID)
  217. {
  218. this.certID = certID;
  219. this.certIDv2 = null;
  220. }
  221. internal CertID(EssCertIDv2 certID)
  222. {
  223. this.certIDv2 = certID;
  224. this.certID = null;
  225. }
  226. public string GetHashAlgorithmName()
  227. {
  228. if (certID != null)
  229. return "SHA-1";
  230. if (NistObjectIdentifiers.IdSha256.Equals(certIDv2.HashAlgorithm.Algorithm))
  231. return "SHA-256";
  232. return certIDv2.HashAlgorithm.Algorithm.Id;
  233. }
  234. public AlgorithmIdentifier GetHashAlgorithm()
  235. {
  236. return (certID != null)
  237. ? new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1)
  238. : certIDv2.HashAlgorithm;
  239. }
  240. public byte[] GetCertHash()
  241. {
  242. return certID != null
  243. ? certID.GetCertHash()
  244. : certIDv2.GetCertHash();
  245. }
  246. public IssuerSerial IssuerSerial
  247. {
  248. get
  249. {
  250. return certID != null
  251. ? certID.IssuerSerial
  252. : certIDv2.IssuerSerial;
  253. }
  254. }
  255. }
  256. }
  257. }
  258. #pragma warning restore
  259. #endif