X509V3CertificateGenerator.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using System.Collections;
  5. using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1;
  6. using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1.X509;
  7. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto;
  8. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Operators;
  9. using BestHTTP.SecureProtocol.Org.BouncyCastle.Math;
  10. using BestHTTP.SecureProtocol.Org.BouncyCastle.Security;
  11. using BestHTTP.SecureProtocol.Org.BouncyCastle.Security.Certificates;
  12. using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  13. using BestHTTP.SecureProtocol.Org.BouncyCastle.X509.Extension;
  14. namespace BestHTTP.SecureProtocol.Org.BouncyCastle.X509
  15. {
  16. /// <summary>
  17. /// A class to Generate Version 3 X509Certificates.
  18. /// </summary>
  19. public class X509V3CertificateGenerator
  20. {
  21. private readonly X509ExtensionsGenerator extGenerator = new X509ExtensionsGenerator();
  22. private V3TbsCertificateGenerator tbsGen;
  23. private DerObjectIdentifier sigOid;
  24. private AlgorithmIdentifier sigAlgId;
  25. private string signatureAlgorithm;
  26. public X509V3CertificateGenerator()
  27. {
  28. tbsGen = new V3TbsCertificateGenerator();
  29. }
  30. /// <summary>
  31. /// Reset the Generator.
  32. /// </summary>
  33. public void Reset()
  34. {
  35. tbsGen = new V3TbsCertificateGenerator();
  36. extGenerator.Reset();
  37. }
  38. /// <summary>
  39. /// Set the certificate's serial number.
  40. /// </summary>
  41. /// <remarks>Make serial numbers long, if you have no serial number policy make sure the number is at least 16 bytes of secure random data.
  42. /// You will be surprised how ugly a serial number collision can Get.</remarks>
  43. /// <param name="serialNumber">The serial number.</param>
  44. public void SetSerialNumber(
  45. BigInteger serialNumber)
  46. {
  47. if (serialNumber.SignValue <= 0)
  48. {
  49. throw new ArgumentException("serial number must be a positive integer", "serialNumber");
  50. }
  51. tbsGen.SetSerialNumber(new DerInteger(serialNumber));
  52. }
  53. /// <summary>
  54. /// Set the distinguished name of the issuer.
  55. /// The issuer is the entity which is signing the certificate.
  56. /// </summary>
  57. /// <param name="issuer">The issuer's DN.</param>
  58. public void SetIssuerDN(
  59. X509Name issuer)
  60. {
  61. tbsGen.SetIssuer(issuer);
  62. }
  63. /// <summary>
  64. /// Set the date that this certificate is to be valid from.
  65. /// </summary>
  66. /// <param name="date"/>
  67. public void SetNotBefore(
  68. DateTime date)
  69. {
  70. tbsGen.SetStartDate(new Time(date));
  71. }
  72. /// <summary>
  73. /// Set the date after which this certificate will no longer be valid.
  74. /// </summary>
  75. /// <param name="date"/>
  76. public void SetNotAfter(
  77. DateTime date)
  78. {
  79. tbsGen.SetEndDate(new Time(date));
  80. }
  81. /// <summary>
  82. /// Set the DN of the entity that this certificate is about.
  83. /// </summary>
  84. /// <param name="subject"/>
  85. public void SetSubjectDN(
  86. X509Name subject)
  87. {
  88. tbsGen.SetSubject(subject);
  89. }
  90. /// <summary>
  91. /// Set the public key that this certificate identifies.
  92. /// </summary>
  93. /// <param name="publicKey"/>
  94. public void SetPublicKey(
  95. AsymmetricKeyParameter publicKey)
  96. {
  97. tbsGen.SetSubjectPublicKeyInfo(SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey));
  98. }
  99. /// <summary>
  100. /// Set the signature algorithm that will be used to sign this certificate.
  101. /// </summary>
  102. /// <param name="signatureAlgorithm"/>
  103. [Obsolete("Not needed if Generate used with an ISignatureFactory")]
  104. public void SetSignatureAlgorithm(
  105. string signatureAlgorithm)
  106. {
  107. this.signatureAlgorithm = signatureAlgorithm;
  108. try
  109. {
  110. sigOid = X509Utilities.GetAlgorithmOid(signatureAlgorithm);
  111. }
  112. catch (Exception)
  113. {
  114. throw new ArgumentException("Unknown signature type requested: " + signatureAlgorithm);
  115. }
  116. sigAlgId = X509Utilities.GetSigAlgID(sigOid, signatureAlgorithm);
  117. tbsGen.SetSignature(sigAlgId);
  118. }
  119. /// <summary>
  120. /// Set the subject unique ID - note: it is very rare that it is correct to do this.
  121. /// </summary>
  122. /// <param name="uniqueID"/>
  123. public void SetSubjectUniqueID(
  124. bool[] uniqueID)
  125. {
  126. tbsGen.SetSubjectUniqueID(booleanToBitString(uniqueID));
  127. }
  128. /// <summary>
  129. /// Set the issuer unique ID - note: it is very rare that it is correct to do this.
  130. /// </summary>
  131. /// <param name="uniqueID"/>
  132. public void SetIssuerUniqueID(
  133. bool[] uniqueID)
  134. {
  135. tbsGen.SetIssuerUniqueID(booleanToBitString(uniqueID));
  136. }
  137. private DerBitString booleanToBitString(
  138. bool[] id)
  139. {
  140. byte[] bytes = new byte[(id.Length + 7) / 8];
  141. for (int i = 0; i != id.Length; i++)
  142. {
  143. if (id[i])
  144. {
  145. bytes[i / 8] |= (byte)(1 << ((7 - (i % 8))));
  146. }
  147. }
  148. int pad = id.Length % 8;
  149. if (pad == 0)
  150. {
  151. return new DerBitString(bytes);
  152. }
  153. return new DerBitString(bytes, 8 - pad);
  154. }
  155. /// <summary>
  156. /// Add a given extension field for the standard extensions tag (tag 3).
  157. /// </summary>
  158. /// <param name="oid">string containing a dotted decimal Object Identifier.</param>
  159. /// <param name="critical">Is it critical.</param>
  160. /// <param name="extensionValue">The value.</param>
  161. public void AddExtension(
  162. string oid,
  163. bool critical,
  164. Asn1Encodable extensionValue)
  165. {
  166. extGenerator.AddExtension(new DerObjectIdentifier(oid), critical, extensionValue);
  167. }
  168. /// <summary>
  169. /// Add an extension to this certificate.
  170. /// </summary>
  171. /// <param name="oid">Its Object Identifier.</param>
  172. /// <param name="critical">Is it critical.</param>
  173. /// <param name="extensionValue">The value.</param>
  174. public void AddExtension(
  175. DerObjectIdentifier oid,
  176. bool critical,
  177. Asn1Encodable extensionValue)
  178. {
  179. extGenerator.AddExtension(oid, critical, extensionValue);
  180. }
  181. /// <summary>
  182. /// Add an extension using a string with a dotted decimal OID.
  183. /// </summary>
  184. /// <param name="oid">string containing a dotted decimal Object Identifier.</param>
  185. /// <param name="critical">Is it critical.</param>
  186. /// <param name="extensionValue">byte[] containing the value of this extension.</param>
  187. public void AddExtension(
  188. string oid,
  189. bool critical,
  190. byte[] extensionValue)
  191. {
  192. extGenerator.AddExtension(new DerObjectIdentifier(oid), critical, new DerOctetString(extensionValue));
  193. }
  194. /// <summary>
  195. /// Add an extension to this certificate.
  196. /// </summary>
  197. /// <param name="oid">Its Object Identifier.</param>
  198. /// <param name="critical">Is it critical.</param>
  199. /// <param name="extensionValue">byte[] containing the value of this extension.</param>
  200. public void AddExtension(
  201. DerObjectIdentifier oid,
  202. bool critical,
  203. byte[] extensionValue)
  204. {
  205. extGenerator.AddExtension(oid, critical, new DerOctetString(extensionValue));
  206. }
  207. /// <summary>
  208. /// Add a given extension field for the standard extensions tag (tag 3),
  209. /// copying the extension value from another certificate.
  210. /// </summary>
  211. public void CopyAndAddExtension(
  212. string oid,
  213. bool critical,
  214. X509Certificate cert)
  215. {
  216. CopyAndAddExtension(new DerObjectIdentifier(oid), critical, cert);
  217. }
  218. /**
  219. * add a given extension field for the standard extensions tag (tag 3)
  220. * copying the extension value from another certificate.
  221. * @throws CertificateParsingException if the extension cannot be extracted.
  222. */
  223. public void CopyAndAddExtension(
  224. DerObjectIdentifier oid,
  225. bool critical,
  226. X509Certificate cert)
  227. {
  228. Asn1OctetString extValue = cert.GetExtensionValue(oid);
  229. if (extValue == null)
  230. {
  231. throw new CertificateParsingException("extension " + oid + " not present");
  232. }
  233. try
  234. {
  235. Asn1Encodable value = X509ExtensionUtilities.FromExtensionValue(extValue);
  236. this.AddExtension(oid, critical, value);
  237. }
  238. catch (Exception e)
  239. {
  240. throw new CertificateParsingException(e.Message, e);
  241. }
  242. }
  243. /// <summary>
  244. /// Generate an X509Certificate.
  245. /// </summary>
  246. /// <param name="privateKey">The private key of the issuer that is signing this certificate.</param>
  247. /// <returns>An X509Certificate.</returns>
  248. [Obsolete("Use Generate with an ISignatureFactory")]
  249. public X509Certificate Generate(
  250. AsymmetricKeyParameter privateKey)
  251. {
  252. return Generate(privateKey, null);
  253. }
  254. /// <summary>
  255. /// Generate an X509Certificate using your own SecureRandom.
  256. /// </summary>
  257. /// <param name="privateKey">The private key of the issuer that is signing this certificate.</param>
  258. /// <param name="random">You Secure Random instance.</param>
  259. /// <returns>An X509Certificate.</returns>
  260. [Obsolete("Use Generate with an ISignatureFactory")]
  261. public X509Certificate Generate(
  262. AsymmetricKeyParameter privateKey,
  263. SecureRandom random)
  264. {
  265. return Generate(new Asn1SignatureFactory(signatureAlgorithm, privateKey, random));
  266. }
  267. /// <summary>
  268. /// Generate a new X509Certificate using the passed in SignatureCalculator.
  269. /// </summary>
  270. /// <param name="signatureCalculatorFactory">A signature calculator factory with the necessary algorithm details.</param>
  271. /// <returns>An X509Certificate.</returns>
  272. public X509Certificate Generate(ISignatureFactory signatureCalculatorFactory)
  273. {
  274. tbsGen.SetSignature ((AlgorithmIdentifier)signatureCalculatorFactory.AlgorithmDetails);
  275. if (!extGenerator.IsEmpty)
  276. {
  277. tbsGen.SetExtensions(extGenerator.Generate());
  278. }
  279. TbsCertificateStructure tbsCert = tbsGen.GenerateTbsCertificate();
  280. IStreamCalculator streamCalculator = signatureCalculatorFactory.CreateCalculator();
  281. byte[] encoded = tbsCert.GetDerEncoded();
  282. streamCalculator.Stream.Write(encoded, 0, encoded.Length);
  283. BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.Dispose(streamCalculator.Stream);
  284. return GenerateJcaObject(tbsCert, (AlgorithmIdentifier)signatureCalculatorFactory.AlgorithmDetails, ((IBlockResult)streamCalculator.GetResult()).Collect());
  285. }
  286. private X509Certificate GenerateJcaObject(
  287. TbsCertificateStructure tbsCert,
  288. AlgorithmIdentifier sigAlg,
  289. byte[] signature)
  290. {
  291. return new X509Certificate(
  292. new X509CertificateStructure(tbsCert, sigAlg, new DerBitString(signature)));
  293. }
  294. /// <summary>
  295. /// Allows enumeration of the signature names supported by the generator.
  296. /// </summary>
  297. public IEnumerable SignatureAlgNames
  298. {
  299. get { return X509Utilities.GetAlgNames(); }
  300. }
  301. }
  302. }
  303. #pragma warning restore
  304. #endif