X509Crl.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  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 System.Text;
  7. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Asn1;
  8. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Asn1.Utilities;
  9. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Asn1.X509;
  10. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto;
  11. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Operators;
  12. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Math;
  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.Encoders;
  17. using Best.HTTP.SecureProtocol.Org.BouncyCastle.X509.Extension;
  18. namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.X509
  19. {
  20. /**
  21. * The following extensions are listed in RFC 2459 as relevant to CRLs
  22. *
  23. * Authority Key Identifier
  24. * Issuer Alternative Name
  25. * CRL Number
  26. * Delta CRL Indicator (critical)
  27. * Issuing Distribution Point (critical)
  28. */
  29. public class X509Crl
  30. : X509ExtensionBase
  31. // TODO Add interface Crl?
  32. {
  33. private class CachedEncoding
  34. {
  35. private readonly byte[] encoding;
  36. private readonly CrlException exception;
  37. internal CachedEncoding(byte[] encoding, CrlException exception)
  38. {
  39. this.encoding = encoding;
  40. this.exception = exception;
  41. }
  42. internal byte[] Encoding
  43. {
  44. get { return encoding; }
  45. }
  46. internal byte[] GetEncoded()
  47. {
  48. if (null != exception)
  49. throw exception;
  50. if (null == encoding)
  51. throw new CrlException();
  52. return encoding;
  53. }
  54. }
  55. private readonly CertificateList c;
  56. private readonly string sigAlgName;
  57. private readonly byte[] sigAlgParams;
  58. private readonly bool isIndirect;
  59. private readonly object cacheLock = new object();
  60. private CachedEncoding cachedEncoding;
  61. private volatile bool hashValueSet;
  62. private volatile int hashValue;
  63. public X509Crl(byte[] encoding)
  64. : this(CertificateList.GetInstance(encoding))
  65. {
  66. }
  67. public X509Crl(CertificateList c)
  68. {
  69. this.c = c;
  70. try
  71. {
  72. this.sigAlgName = X509SignatureUtilities.GetSignatureName(c.SignatureAlgorithm);
  73. Asn1Encodable parameters = c.SignatureAlgorithm.Parameters;
  74. this.sigAlgParams = (null == parameters) ? null : parameters.GetEncoded(Asn1Encodable.Der);
  75. this.isIndirect = IsIndirectCrl;
  76. }
  77. catch (Exception e)
  78. {
  79. throw new CrlException("CRL contents invalid: " + e);
  80. }
  81. }
  82. public virtual CertificateList CertificateList
  83. {
  84. get { return c; }
  85. }
  86. protected override X509Extensions GetX509Extensions()
  87. {
  88. return c.Version >= 2
  89. ? c.TbsCertList.Extensions
  90. : null;
  91. }
  92. public virtual void Verify(
  93. AsymmetricKeyParameter publicKey)
  94. {
  95. Verify(new Asn1VerifierFactoryProvider(publicKey));
  96. }
  97. /// <summary>
  98. /// Verify the CRL's signature using a verifier created using the passed in verifier provider.
  99. /// </summary>
  100. /// <param name="verifierProvider">An appropriate provider for verifying the CRL's signature.</param>
  101. /// <returns>True if the signature is valid.</returns>
  102. /// <exception cref="Exception">If verifier provider is not appropriate or the CRL algorithm is invalid.</exception>
  103. public virtual void Verify(
  104. IVerifierFactoryProvider verifierProvider)
  105. {
  106. CheckSignature(verifierProvider.CreateVerifierFactory(c.SignatureAlgorithm));
  107. }
  108. protected virtual void CheckSignature(
  109. IVerifierFactory verifier)
  110. {
  111. // TODO Compare IsAlgIDEqual in X509Certificate.CheckSignature
  112. if (!c.SignatureAlgorithm.Equals(c.TbsCertList.Signature))
  113. throw new CrlException("Signature algorithm on CertificateList does not match TbsCertList.");
  114. byte[] b = GetTbsCertList();
  115. IStreamCalculator<IVerifier> streamCalculator = verifier.CreateCalculator();
  116. using (var stream = streamCalculator.Stream)
  117. {
  118. stream.Write(b, 0, b.Length);
  119. }
  120. if (!streamCalculator.GetResult().IsVerified(GetSignature()))
  121. throw new InvalidKeyException("CRL does not verify with supplied public key.");
  122. }
  123. public virtual int Version
  124. {
  125. get { return c.Version; }
  126. }
  127. public virtual X509Name IssuerDN
  128. {
  129. get { return c.Issuer; }
  130. }
  131. public virtual DateTime ThisUpdate
  132. {
  133. get { return c.ThisUpdate.ToDateTime(); }
  134. }
  135. public virtual DateTime? NextUpdate => c.NextUpdate?.ToDateTime();
  136. private ISet<X509CrlEntry> LoadCrlEntries()
  137. {
  138. var entrySet = new HashSet<X509CrlEntry>();
  139. var revoked = c.GetRevokedCertificateEnumeration();
  140. X509Name previousCertificateIssuer = IssuerDN;
  141. foreach (CrlEntry entry in revoked)
  142. {
  143. X509CrlEntry crlEntry = new X509CrlEntry(entry, isIndirect, previousCertificateIssuer);
  144. entrySet.Add(crlEntry);
  145. previousCertificateIssuer = crlEntry.GetCertificateIssuer();
  146. }
  147. return entrySet;
  148. }
  149. public virtual X509CrlEntry GetRevokedCertificate(
  150. BigInteger serialNumber)
  151. {
  152. var certs = c.GetRevokedCertificateEnumeration();
  153. X509Name previousCertificateIssuer = IssuerDN;
  154. foreach (CrlEntry entry in certs)
  155. {
  156. X509CrlEntry crlEntry = new X509CrlEntry(entry, isIndirect, previousCertificateIssuer);
  157. if (serialNumber.Equals(entry.UserCertificate.Value))
  158. {
  159. return crlEntry;
  160. }
  161. previousCertificateIssuer = crlEntry.GetCertificateIssuer();
  162. }
  163. return null;
  164. }
  165. public virtual ISet<X509CrlEntry> GetRevokedCertificates()
  166. {
  167. var entrySet = LoadCrlEntries();
  168. if (entrySet.Count > 0)
  169. return entrySet;
  170. return null;
  171. }
  172. public virtual byte[] GetTbsCertList()
  173. {
  174. try
  175. {
  176. return c.TbsCertList.GetDerEncoded();
  177. }
  178. catch (Exception e)
  179. {
  180. throw new CrlException(e.ToString());
  181. }
  182. }
  183. public virtual byte[] GetSignature()
  184. {
  185. return c.GetSignatureOctets();
  186. }
  187. public virtual string SigAlgName
  188. {
  189. get { return sigAlgName; }
  190. }
  191. public virtual string SigAlgOid
  192. {
  193. get { return c.SignatureAlgorithm.Algorithm.Id; }
  194. }
  195. public virtual byte[] GetSigAlgParams()
  196. {
  197. return Arrays.Clone(sigAlgParams);
  198. }
  199. /// <summary>
  200. /// Return the DER encoding of this CRL.
  201. /// </summary>
  202. /// <returns>A byte array containing the DER encoding of this CRL.</returns>
  203. /// <exception cref="CrlException">If there is an error encoding the CRL.</exception>
  204. public virtual byte[] GetEncoded()
  205. {
  206. return Arrays.Clone(GetCachedEncoding().GetEncoded());
  207. }
  208. public override bool Equals(object other)
  209. {
  210. if (this == other)
  211. return true;
  212. X509Crl that = other as X509Crl;
  213. if (null == that)
  214. return false;
  215. if (this.hashValueSet && that.hashValueSet)
  216. {
  217. if (this.hashValue != that.hashValue)
  218. return false;
  219. }
  220. else if (null == this.cachedEncoding || null == that.cachedEncoding)
  221. {
  222. DerBitString signature = c.Signature;
  223. if (null != signature && !signature.Equals(that.c.Signature))
  224. return false;
  225. }
  226. byte[] thisEncoding = this.GetCachedEncoding().Encoding;
  227. byte[] thatEncoding = that.GetCachedEncoding().Encoding;
  228. return null != thisEncoding
  229. && null != thatEncoding
  230. && Arrays.AreEqual(thisEncoding, thatEncoding);
  231. }
  232. public override int GetHashCode()
  233. {
  234. if (!hashValueSet)
  235. {
  236. byte[] thisEncoding = this.GetCachedEncoding().Encoding;
  237. hashValue = Arrays.GetHashCode(thisEncoding);
  238. hashValueSet = true;
  239. }
  240. return hashValue;
  241. }
  242. /**
  243. * Returns a string representation of this CRL.
  244. *
  245. * @return a string representation of this CRL.
  246. */
  247. public override string ToString()
  248. {
  249. StringBuilder buf = new StringBuilder();
  250. buf.Append(" Version: ").Append(this.Version).AppendLine();
  251. buf.Append(" IssuerDN: ").Append(this.IssuerDN).AppendLine();
  252. buf.Append(" This update: ").Append(this.ThisUpdate).AppendLine();
  253. buf.Append(" Next update: ").Append(this.NextUpdate).AppendLine();
  254. buf.Append(" Signature Algorithm: ").Append(this.SigAlgName).AppendLine();
  255. byte[] sig = this.GetSignature();
  256. buf.Append(" Signature: ");
  257. buf.Append(Hex.ToHexString(sig, 0, 20)).AppendLine();
  258. for (int i = 20; i < sig.Length; i += 20)
  259. {
  260. int count = System.Math.Min(20, sig.Length - i);
  261. buf.Append(" ");
  262. buf.Append(Hex.ToHexString(sig, i, count)).AppendLine();
  263. }
  264. X509Extensions extensions = c.TbsCertList.Extensions;
  265. if (extensions != null)
  266. {
  267. var e = extensions.ExtensionOids.GetEnumerator();
  268. if (e.MoveNext())
  269. {
  270. buf.Append(" Extensions: ").AppendLine();
  271. }
  272. do
  273. {
  274. DerObjectIdentifier oid = e.Current;
  275. X509Extension ext = extensions.GetExtension(oid);
  276. if (ext.Value != null)
  277. {
  278. Asn1Object asn1Value = X509ExtensionUtilities.FromExtensionValue(ext.Value);
  279. buf.Append(" critical(").Append(ext.IsCritical).Append(") ");
  280. try
  281. {
  282. if (oid.Equals(X509Extensions.CrlNumber))
  283. {
  284. buf.Append(new CrlNumber(DerInteger.GetInstance(asn1Value).PositiveValue)).AppendLine();
  285. }
  286. else if (oid.Equals(X509Extensions.DeltaCrlIndicator))
  287. {
  288. buf.Append(
  289. "Base CRL: "
  290. + new CrlNumber(DerInteger.GetInstance(
  291. asn1Value).PositiveValue))
  292. .AppendLine();
  293. }
  294. else if (oid.Equals(X509Extensions.IssuingDistributionPoint))
  295. {
  296. buf.Append(IssuingDistributionPoint.GetInstance((Asn1Sequence) asn1Value)).AppendLine();
  297. }
  298. else if (oid.Equals(X509Extensions.CrlDistributionPoints))
  299. {
  300. buf.Append(CrlDistPoint.GetInstance((Asn1Sequence) asn1Value)).AppendLine();
  301. }
  302. else if (oid.Equals(X509Extensions.FreshestCrl))
  303. {
  304. buf.Append(CrlDistPoint.GetInstance((Asn1Sequence) asn1Value)).AppendLine();
  305. }
  306. else
  307. {
  308. buf.Append(oid.Id);
  309. buf.Append(" value = ").Append(
  310. Asn1Dump.DumpAsString(asn1Value))
  311. .AppendLine();
  312. }
  313. }
  314. catch (Exception)
  315. {
  316. buf.Append(oid.Id);
  317. buf.Append(" value = ").Append("*****").AppendLine();
  318. }
  319. }
  320. else
  321. {
  322. buf.AppendLine();
  323. }
  324. }
  325. while (e.MoveNext());
  326. }
  327. var certSet = GetRevokedCertificates();
  328. if (certSet != null)
  329. {
  330. foreach (X509CrlEntry entry in certSet)
  331. {
  332. buf.Append(entry);
  333. buf.AppendLine();
  334. }
  335. }
  336. return buf.ToString();
  337. }
  338. /**
  339. * Checks whether the given certificate is on this CRL.
  340. *
  341. * @param cert the certificate to check for.
  342. * @return true if the given certificate is on this CRL,
  343. * false otherwise.
  344. */
  345. // public bool IsRevoked(
  346. // Certificate cert)
  347. // {
  348. // if (!cert.getType().Equals("X.509"))
  349. // {
  350. // throw new RuntimeException("X.509 CRL used with non X.509 Cert");
  351. // }
  352. public virtual bool IsRevoked(
  353. X509Certificate cert)
  354. {
  355. CrlEntry[] certs = c.GetRevokedCertificates();
  356. if (certs != null)
  357. {
  358. BigInteger serial = cert.SerialNumber;
  359. for (int i = 0; i < certs.Length; i++)
  360. {
  361. if (certs[i].UserCertificate.HasValue(serial))
  362. return true;
  363. }
  364. }
  365. return false;
  366. }
  367. protected virtual bool IsIndirectCrl
  368. {
  369. get
  370. {
  371. Asn1OctetString idp = GetExtensionValue(X509Extensions.IssuingDistributionPoint);
  372. bool isIndirect = false;
  373. try
  374. {
  375. if (idp != null)
  376. {
  377. isIndirect = IssuingDistributionPoint.GetInstance(
  378. X509ExtensionUtilities.FromExtensionValue(idp)).IsIndirectCrl;
  379. }
  380. }
  381. catch (Exception e)
  382. {
  383. // TODO
  384. // throw new ExtCrlException("Exception reading IssuingDistributionPoint", e);
  385. throw new CrlException("Exception reading IssuingDistributionPoint" + e);
  386. }
  387. return isIndirect;
  388. }
  389. }
  390. private CachedEncoding GetCachedEncoding()
  391. {
  392. lock (cacheLock)
  393. {
  394. if (null != cachedEncoding)
  395. return cachedEncoding;
  396. }
  397. byte[] encoding = null;
  398. CrlException exception = null;
  399. try
  400. {
  401. encoding = c.GetEncoded(Asn1Encodable.Der);
  402. }
  403. catch (IOException e)
  404. {
  405. exception = new CrlException("Failed to DER-encode CRL", e);
  406. }
  407. CachedEncoding temp = new CachedEncoding(encoding, exception);
  408. lock (cacheLock)
  409. {
  410. if (null == cachedEncoding)
  411. {
  412. cachedEncoding = temp;
  413. }
  414. return cachedEncoding;
  415. }
  416. }
  417. }
  418. }
  419. #pragma warning restore
  420. #endif