X509V3CertificateGenerator.cs 10 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. public void SetSignatureAlgorithm(
  104. string signatureAlgorithm)
  105. {
  106. this.signatureAlgorithm = signatureAlgorithm;
  107. try
  108. {
  109. sigOid = X509Utilities.GetAlgorithmOid(signatureAlgorithm);
  110. }
  111. catch (Exception)
  112. {
  113. throw new ArgumentException("Unknown signature type requested: " + signatureAlgorithm);
  114. }
  115. sigAlgId = X509Utilities.GetSigAlgID(sigOid, signatureAlgorithm);
  116. tbsGen.SetSignature(sigAlgId);
  117. }
  118. /// <summary>
  119. /// Set the subject unique ID - note: it is very rare that it is correct to do this.
  120. /// </summary>
  121. /// <param name="uniqueID"/>
  122. public void SetSubjectUniqueID(
  123. bool[] uniqueID)
  124. {
  125. tbsGen.SetSubjectUniqueID(booleanToBitString(uniqueID));
  126. }
  127. /// <summary>
  128. /// Set the issuer unique ID - note: it is very rare that it is correct to do this.
  129. /// </summary>
  130. /// <param name="uniqueID"/>
  131. public void SetIssuerUniqueID(
  132. bool[] uniqueID)
  133. {
  134. tbsGen.SetIssuerUniqueID(booleanToBitString(uniqueID));
  135. }
  136. private DerBitString booleanToBitString(
  137. bool[] id)
  138. {
  139. byte[] bytes = new byte[(id.Length + 7) / 8];
  140. for (int i = 0; i != id.Length; i++)
  141. {
  142. if (id[i])
  143. {
  144. bytes[i / 8] |= (byte)(1 << ((7 - (i % 8))));
  145. }
  146. }
  147. int pad = id.Length % 8;
  148. if (pad == 0)
  149. {
  150. return new DerBitString(bytes);
  151. }
  152. return new DerBitString(bytes, 8 - pad);
  153. }
  154. /// <summary>
  155. /// Add a given extension field for the standard extensions tag (tag 3).
  156. /// </summary>
  157. /// <param name="oid">string containing a dotted decimal Object Identifier.</param>
  158. /// <param name="critical">Is it critical.</param>
  159. /// <param name="extensionValue">The value.</param>
  160. public void AddExtension(
  161. string oid,
  162. bool critical,
  163. Asn1Encodable extensionValue)
  164. {
  165. extGenerator.AddExtension(new DerObjectIdentifier(oid), critical, extensionValue);
  166. }
  167. /// <summary>
  168. /// Add an extension to this certificate.
  169. /// </summary>
  170. /// <param name="oid">Its Object Identifier.</param>
  171. /// <param name="critical">Is it critical.</param>
  172. /// <param name="extensionValue">The value.</param>
  173. public void AddExtension(
  174. DerObjectIdentifier oid,
  175. bool critical,
  176. Asn1Encodable extensionValue)
  177. {
  178. extGenerator.AddExtension(oid, critical, extensionValue);
  179. }
  180. /// <summary>
  181. /// Add an extension using a string with a dotted decimal OID.
  182. /// </summary>
  183. /// <param name="oid">string containing a dotted decimal Object Identifier.</param>
  184. /// <param name="critical">Is it critical.</param>
  185. /// <param name="extensionValue">byte[] containing the value of this extension.</param>
  186. public void AddExtension(
  187. string oid,
  188. bool critical,
  189. byte[] extensionValue)
  190. {
  191. extGenerator.AddExtension(new DerObjectIdentifier(oid), critical, new DerOctetString(extensionValue));
  192. }
  193. /// <summary>
  194. /// Add an extension to this certificate.
  195. /// </summary>
  196. /// <param name="oid">Its Object Identifier.</param>
  197. /// <param name="critical">Is it critical.</param>
  198. /// <param name="extensionValue">byte[] containing the value of this extension.</param>
  199. public void AddExtension(
  200. DerObjectIdentifier oid,
  201. bool critical,
  202. byte[] extensionValue)
  203. {
  204. extGenerator.AddExtension(oid, critical, new DerOctetString(extensionValue));
  205. }
  206. /// <summary>
  207. /// Add a given extension field for the standard extensions tag (tag 3),
  208. /// copying the extension value from another certificate.
  209. /// </summary>
  210. public void CopyAndAddExtension(
  211. string oid,
  212. bool critical,
  213. X509Certificate cert)
  214. {
  215. CopyAndAddExtension(new DerObjectIdentifier(oid), critical, cert);
  216. }
  217. /**
  218. * add a given extension field for the standard extensions tag (tag 3)
  219. * copying the extension value from another certificate.
  220. * @throws CertificateParsingException if the extension cannot be extracted.
  221. */
  222. public void CopyAndAddExtension(
  223. DerObjectIdentifier oid,
  224. bool critical,
  225. X509Certificate cert)
  226. {
  227. Asn1OctetString extValue = cert.GetExtensionValue(oid);
  228. if (extValue == null)
  229. {
  230. throw new CertificateParsingException("extension " + oid + " not present");
  231. }
  232. try
  233. {
  234. Asn1Encodable value = X509ExtensionUtilities.FromExtensionValue(extValue);
  235. this.AddExtension(oid, critical, value);
  236. }
  237. catch (Exception e)
  238. {
  239. throw new CertificateParsingException(e.Message, e);
  240. }
  241. }
  242. /// <summary>
  243. /// Generate an X509Certificate.
  244. /// </summary>
  245. /// <param name="privateKey">The private key of the issuer that is signing this certificate.</param>
  246. /// <returns>An X509Certificate.</returns>
  247. public X509Certificate Generate(
  248. AsymmetricKeyParameter privateKey)
  249. {
  250. return Generate(privateKey, null);
  251. }
  252. /// <summary>
  253. /// Generate an X509Certificate using your own SecureRandom.
  254. /// </summary>
  255. /// <param name="privateKey">The private key of the issuer that is signing this certificate.</param>
  256. /// <param name="random">You Secure Random instance.</param>
  257. /// <returns>An X509Certificate.</returns>
  258. public X509Certificate Generate(
  259. AsymmetricKeyParameter privateKey,
  260. SecureRandom random)
  261. {
  262. return Generate(new Asn1SignatureFactory(signatureAlgorithm, privateKey, random));
  263. }
  264. /// <summary>
  265. /// Generate a new X509Certificate using the passed in SignatureCalculator.
  266. /// </summary>
  267. /// <param name="signatureCalculatorFactory">A signature calculator factory with the necessary algorithm details.</param>
  268. /// <returns>An X509Certificate.</returns>
  269. public X509Certificate Generate(ISignatureFactory signatureCalculatorFactory)
  270. {
  271. tbsGen.SetSignature ((AlgorithmIdentifier)signatureCalculatorFactory.AlgorithmDetails);
  272. if (!extGenerator.IsEmpty)
  273. {
  274. tbsGen.SetExtensions(extGenerator.Generate());
  275. }
  276. TbsCertificateStructure tbsCert = tbsGen.GenerateTbsCertificate();
  277. IStreamCalculator streamCalculator = signatureCalculatorFactory.CreateCalculator();
  278. byte[] encoded = tbsCert.GetDerEncoded();
  279. streamCalculator.Stream.Write(encoded, 0, encoded.Length);
  280. BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.Dispose(streamCalculator.Stream);
  281. return GenerateJcaObject(tbsCert, (AlgorithmIdentifier)signatureCalculatorFactory.AlgorithmDetails, ((IBlockResult)streamCalculator.GetResult()).Collect());
  282. }
  283. private X509Certificate GenerateJcaObject(
  284. TbsCertificateStructure tbsCert,
  285. AlgorithmIdentifier sigAlg,
  286. byte[] signature)
  287. {
  288. return new X509Certificate(
  289. new X509CertificateStructure(tbsCert, sigAlg, new DerBitString(signature)));
  290. }
  291. /// <summary>
  292. /// Allows enumeration of the signature names supported by the generator.
  293. /// </summary>
  294. public IEnumerable SignatureAlgNames
  295. {
  296. get { return X509Utilities.GetAlgNames(); }
  297. }
  298. }
  299. }
  300. #pragma warning restore
  301. #endif