TimeStampToken.cs 7.8 KB

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