summary refs log tree commit diff
path: root/crypto/src/x509/X509V3CertificateGenerator.cs
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/src/x509/X509V3CertificateGenerator.cs')
-rw-r--r--crypto/src/x509/X509V3CertificateGenerator.cs346
1 files changed, 346 insertions, 0 deletions
diff --git a/crypto/src/x509/X509V3CertificateGenerator.cs b/crypto/src/x509/X509V3CertificateGenerator.cs
new file mode 100644
index 000000000..bb0dd9cbc
--- /dev/null
+++ b/crypto/src/x509/X509V3CertificateGenerator.cs
@@ -0,0 +1,346 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.X509.Extension;
+
+namespace Org.BouncyCastle.X509
+{
+    /// <summary>
+    /// A class to Generate Version 3 X509Certificates.
+    /// </summary>
+    public class X509V3CertificateGenerator
+    {
+		private readonly X509ExtensionsGenerator extGenerator = new X509ExtensionsGenerator();
+
+		private V3TbsCertificateGenerator	tbsGen;
+        private DerObjectIdentifier			sigOid;
+        private AlgorithmIdentifier			sigAlgId;
+        private string						signatureAlgorithm;
+
+		public X509V3CertificateGenerator()
+        {
+            tbsGen = new V3TbsCertificateGenerator();
+        }
+
+		/// <summary>
+		/// Reset the Generator.
+		/// </summary>
+		public void Reset()
+		{
+			tbsGen = new V3TbsCertificateGenerator();
+			extGenerator.Reset();
+		}
+
+		/// <summary>
+        /// Set the certificate's serial number.
+        /// </summary>
+        /// <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.
+        /// You will be surprised how ugly a serial number collision can Get.</remarks>
+        /// <param name="serialNumber">The serial number.</param>
+        public void SetSerialNumber(
+			BigInteger serialNumber)
+        {
+			if (serialNumber.SignValue <= 0)
+			{
+				throw new ArgumentException("serial number must be a positive integer", "serialNumber");
+			}
+
+			tbsGen.SetSerialNumber(new DerInteger(serialNumber));
+        }
+
+		/// <summary>
+        /// Set the distinguished name of the issuer.
+        /// The issuer is the entity which is signing the certificate.
+        /// </summary>
+        /// <param name="issuer">The issuer's DN.</param>
+        public void SetIssuerDN(
+            X509Name issuer)
+        {
+            tbsGen.SetIssuer(issuer);
+        }
+
+		/// <summary>
+        /// Set the date that this certificate is to be valid from.
+        /// </summary>
+        /// <param name="date"/>
+        public void SetNotBefore(
+            DateTime date)
+        {
+            tbsGen.SetStartDate(new Time(date));
+        }
+
+        /// <summary>
+        /// Set the date after which this certificate will no longer be valid.
+        /// </summary>
+        /// <param name="date"/>
+        public void SetNotAfter(
+			DateTime date)
+        {
+            tbsGen.SetEndDate(new Time(date));
+        }
+
+		/// <summary>
+		/// Set the DN of the entity that this certificate is about.
+		/// </summary>
+		/// <param name="subject"/>
+        public void SetSubjectDN(
+			X509Name subject)
+        {
+            tbsGen.SetSubject(subject);
+        }
+
+		/// <summary>
+        /// Set the public key that this certificate identifies.
+        /// </summary>
+        /// <param name="publicKey"/>
+        public void SetPublicKey(
+			AsymmetricKeyParameter publicKey)
+        {
+            tbsGen.SetSubjectPublicKeyInfo(SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey));
+        }
+
+		/// <summary>
+        /// Set the signature algorithm that will be used to sign this certificate.
+        /// </summary>
+        /// <param name="signatureAlgorithm"/>
+        public void SetSignatureAlgorithm(
+			string signatureAlgorithm)
+        {
+			this.signatureAlgorithm = signatureAlgorithm;
+
+			try
+			{
+				sigOid = X509Utilities.GetAlgorithmOid(signatureAlgorithm);
+			}
+			catch (Exception)
+			{
+				throw new ArgumentException("Unknown signature type requested: " + signatureAlgorithm);
+			}
+
+			sigAlgId = X509Utilities.GetSigAlgID(sigOid, signatureAlgorithm);
+
+			tbsGen.SetSignature(sigAlgId);
+		}
+
+		/// <summary>
+		/// Set the subject unique ID - note: it is very rare that it is correct to do this.
+		/// </summary>
+		/// <param name="uniqueID"/>
+		public void SetSubjectUniqueID(
+			bool[] uniqueID)
+		{
+			tbsGen.SetSubjectUniqueID(booleanToBitString(uniqueID));
+		}
+
+		/// <summary>
+		/// Set the issuer unique ID - note: it is very rare that it is correct to do this.
+		/// </summary>
+		/// <param name="uniqueID"/>
+		public void SetIssuerUniqueID(
+			bool[] uniqueID)
+		{
+			tbsGen.SetIssuerUniqueID(booleanToBitString(uniqueID));
+		}
+
+		private DerBitString booleanToBitString(
+			bool[] id)
+		{
+			byte[] bytes = new byte[(id.Length + 7) / 8];
+
+			for (int i = 0; i != id.Length; i++)
+			{
+				if (id[i])
+				{
+					bytes[i / 8] |= (byte)(1 << ((7 - (i % 8))));
+				}
+			}
+
+			int pad = id.Length % 8;
+
+			if (pad == 0)
+			{
+				return new DerBitString(bytes);
+			}
+
+			return new DerBitString(bytes, 8 - pad);
+		}
+
+		/// <summary>
+		/// Add a given extension field for the standard extensions tag (tag 3).
+		/// </summary>
+		/// <param name="oid">string containing a dotted decimal Object Identifier.</param>
+		/// <param name="critical">Is it critical.</param>
+		/// <param name="extensionValue">The value.</param>
+		public void AddExtension(
+			string			oid,
+			bool			critical,
+			Asn1Encodable	extensionValue)
+		{
+			extGenerator.AddExtension(new DerObjectIdentifier(oid), critical, extensionValue);
+		}
+
+		/// <summary>
+        /// Add an extension to this certificate.
+        /// </summary>
+        /// <param name="oid">Its Object Identifier.</param>
+        /// <param name="critical">Is it critical.</param>
+        /// <param name="extensionValue">The value.</param>
+        public void AddExtension(
+			DerObjectIdentifier	oid,
+			bool				critical,
+			Asn1Encodable		extensionValue)
+        {
+			extGenerator.AddExtension(oid, critical, extensionValue);
+        }
+
+		/// <summary>
+		/// Add an extension using a string with a dotted decimal OID.
+		/// </summary>
+		/// <param name="oid">string containing a dotted decimal Object Identifier.</param>
+		/// <param name="critical">Is it critical.</param>
+		/// <param name="extensionValue">byte[] containing the value of this extension.</param>
+		public void AddExtension(
+			string	oid,
+			bool	critical,
+			byte[]	extensionValue)
+		{
+			extGenerator.AddExtension(new DerObjectIdentifier(oid), critical, new DerOctetString(extensionValue));
+		}
+
+		/// <summary>
+        /// Add an extension to this certificate.
+        /// </summary>
+        /// <param name="oid">Its Object Identifier.</param>
+        /// <param name="critical">Is it critical.</param>
+        /// <param name="extensionValue">byte[] containing the value of this extension.</param>
+        public void AddExtension(
+			DerObjectIdentifier	oid,
+			bool				critical,
+			byte[]				extensionValue)
+        {
+			extGenerator.AddExtension(oid, critical, new DerOctetString(extensionValue));
+        }
+
+		/// <summary>
+		/// Add a given extension field for the standard extensions tag (tag 3),
+		/// copying the extension value from another certificate.
+		/// </summary>
+		public void CopyAndAddExtension(
+			string			oid,
+			bool			critical,
+			X509Certificate	cert)
+		{
+			CopyAndAddExtension(new DerObjectIdentifier(oid), critical, cert);
+		}
+
+		/**
+		 * add a given extension field for the standard extensions tag (tag 3)
+		 * copying the extension value from another certificate.
+		 * @throws CertificateParsingException if the extension cannot be extracted.
+		 */
+		public void CopyAndAddExtension(
+			DerObjectIdentifier	oid,
+			bool				critical,
+			X509Certificate		cert)
+		{
+			Asn1OctetString extValue = cert.GetExtensionValue(oid);
+
+			if (extValue == null)
+			{
+				throw new CertificateParsingException("extension " + oid + " not present");
+			}
+
+			try
+			{
+				Asn1Encodable value = X509ExtensionUtilities.FromExtensionValue(extValue);
+
+				this.AddExtension(oid, critical, value);
+			}
+			catch (Exception e)
+			{
+				throw new CertificateParsingException(e.Message, e);
+			}
+		}
+
+		/// <summary>
+        /// Generate an X509Certificate.
+        /// </summary>
+        /// <param name="privateKey">The private key of the issuer that is signing this certificate.</param>
+        /// <returns>An X509Certificate.</returns>
+        public X509Certificate Generate(
+			AsymmetricKeyParameter privateKey)
+        {
+            return Generate(privateKey, null);
+        }
+
+		/// <summary>
+		/// Generate an X509Certificate using your own SecureRandom.
+		/// </summary>
+		/// <param name="privateKey">The private key of the issuer that is signing this certificate.</param>
+		/// <param name="random">You Secure Random instance.</param>
+		/// <returns>An X509Certificate.</returns>
+		public X509Certificate Generate(
+			AsymmetricKeyParameter	privateKey,
+			SecureRandom			random)
+		{
+			TbsCertificateStructure tbsCert = GenerateTbsCert();
+			byte[] signature;
+
+			try
+			{
+				signature = X509Utilities.GetSignatureForObject(
+					sigOid, signatureAlgorithm, privateKey, random, tbsCert);
+			}
+			catch (Exception e)
+			{
+				// TODO
+//				throw new ExtCertificateEncodingException("exception encoding TBS cert", e);
+				throw new CertificateEncodingException("exception encoding TBS cert", e);
+			}
+
+			try
+			{
+				return GenerateJcaObject(tbsCert, signature);
+			}
+			catch (CertificateParsingException e)
+			{
+				// TODO
+				// throw new ExtCertificateEncodingException("exception producing certificate object", e);
+				throw new CertificateEncodingException("exception producing certificate object", e);
+			}
+		}
+
+		private TbsCertificateStructure GenerateTbsCert()
+		{
+			if (!extGenerator.IsEmpty)
+			{
+				tbsGen.SetExtensions(extGenerator.Generate());
+			}
+
+			return tbsGen.GenerateTbsCertificate();
+		}
+
+		private X509Certificate GenerateJcaObject(
+			TbsCertificateStructure	tbsCert,
+			byte[]					signature)
+		{
+			return new X509Certificate(
+				new X509CertificateStructure(tbsCert, sigAlgId, new DerBitString(signature)));
+		}
+
+		/// <summary>
+		/// Allows enumeration of the signature names supported by the generator.
+		/// </summary>
+		public IEnumerable SignatureAlgNames
+		{
+			get { return X509Utilities.GetAlgNames(); }
+		}
+	}
+}