/// <summary>
    /// Create a X509Certificate2 with a private key by combining
    /// the certificate with a private key from a PEM stream
    /// </summary>
    public static X509Certificate2 CreateCertificateWithPEMPrivateKey(
        X509Certificate2 certificate,
        byte[] pemDataBlob,
        string password = null)
    {
        AsymmetricKeyParameter privateKey = null;
        PemReader pemReader;

        using (StreamReader pemStreamReader = new StreamReader(new MemoryStream(pemDataBlob), Encoding.UTF8, true))
        {
            if (password == null)
            {
                pemReader = new PemReader(pemStreamReader);
            }
            else
            {
                Password pwFinder = new Password(password.ToCharArray());
                pemReader = new PemReader(pemStreamReader, pwFinder);
            }
            try
            {
                // find the private key in the PEM blob
                var pemObject = pemReader.ReadObject();
                while (pemObject != null)
                {
                    privateKey = pemObject as RsaPrivateCrtKeyParameters;
                    if (privateKey != null)
                    {
                        break;
                    }

                    AsymmetricCipherKeyPair keypair = pemObject as AsymmetricCipherKeyPair;
                    if (keypair != null)
                    {
                        privateKey = keypair.Private;
                        break;
                    }

                    // read next object
                    pemObject = pemReader.ReadObject();
                }
            }
            finally
            {
                pemReader.Reader.Dispose();
            }
        }

        if (privateKey == null)
        {
            throw new ServiceResultException("PEM data blob does not contain a private key.");
        }

        using (var cfrg = new CertificateFactoryRandomGenerator())
        {
            SecureRandom random = new SecureRandom(cfrg);
            Org.BouncyCastle.X509.X509Certificate x509 = new X509CertificateParser().ReadCertificate(certificate.RawData);
            return(CreateCertificateWithPrivateKey(x509, certificate.FriendlyName, privateKey, random));
        }
    }
    /// <summary>
    /// Creates a certificate signing request from an existing certificate.
    /// </summary>
    public static byte[] CreateSigningRequest(
        X509Certificate2 certificate,
        IList <String> domainNames = null
        )
    {
        using (var cfrg = new CertificateFactoryRandomGenerator())
        {
            SecureRandom random = new SecureRandom(cfrg);

            // try to get signing/private key from certificate passed in
            AsymmetricKeyParameter signingKey = GetPrivateKeyParameter(certificate);
            RsaKeyParameters       publicKey  = GetPublicKeyParameter(certificate);

            ISignatureFactory signatureFactory =
                new Asn1SignatureFactory(GetRSAHashAlgorithm(defaultHashSize), signingKey, random);

            Pkcs10CertificationRequest pkcs10CertificationRequest = new Pkcs10CertificationRequest(
                signatureFactory,
                new CertificateFactoryX509Name(certificate.Subject),
                publicKey,
                null,
                signingKey);

            return(pkcs10CertificationRequest.GetEncoded());
        }
    }
Example #3
0
        /// <summary>
        /// Create the RSA certificate as Pfx byte array with a private key.
        /// </summary>
        /// <returns>
        /// Returns the Pfx with certificate and private key.
        /// </returns>
        private byte[] CreatePfxForRSA(string passcode, ISignatureFactory signatureFactory = null)
        {
            // Cases locked out by API flow
            Debug.Assert(m_rsaPublicKey == null, "A public key is not supported for the certificate.");

            if (signatureFactory != null && IssuerCAKeyCert == null)
            {
                throw new NotSupportedException("Need an issuer certificate for a signature generator.");
            }

            if (IssuerCAKeyCert != null &&
                (!IssuerCAKeyCert.HasPrivateKey && signatureFactory == null))
            {
                throw new NotSupportedException("Need an issuer certificate with a private key or a signature generator.");
            }

            using (var cfrg = new CertificateFactoryRandomGenerator())
            {
                // cert generators
                SecureRandom random = new SecureRandom(cfrg);

                CreateDefaults(cfrg);

                X509V3CertificateGenerator cg = new X509V3CertificateGenerator();
                CreateMandatoryFields(cg);

                // create Private/Public Keypair
                var rsa = new RSACryptoServiceProvider(m_keySize == 0 ? X509Defaults.RSAKeySize : m_keySize);
                AsymmetricKeyParameter subjectPublicKey  = X509Utils.GetPublicKeyParameter(rsa);
                AsymmetricKeyParameter subjectPrivateKey = X509Utils.GetPrivateKeyParameter(rsa);

                cg.SetPublicKey(subjectPublicKey);

                CreateExtensions(cg, subjectPublicKey);

                // sign certificate
                if (signatureFactory == null)
                {
                    AsymmetricKeyParameter signingKey;
                    if (IssuerCAKeyCert != null)
                    {
                        // signed by issuer
                        signingKey = X509Utils.GetPrivateKeyParameter(IssuerCAKeyCert);
                    }
                    else
                    {
                        // self signed
                        signingKey = subjectPrivateKey;
                    }
                    signatureFactory = new Asn1SignatureFactory(
                        X509Utils.GetRSAHashAlgorithm(HashAlgorithmName), signingKey, random);
                }
                Org.BouncyCastle.X509.X509Certificate x509 = cg.Generate(signatureFactory);

                // note: this Pfx has a private key!
                return(X509Utils.CreatePfxWithPrivateKey(x509, null, subjectPrivateKey, passcode, random));
            }
        }
 /// <summary>
 /// Create a X509Certificate2 with a private key by combining
 /// the new certificate with a private key from an RSA key.
 /// </summary>
 public static X509Certificate2 CreateCertificateWithPrivateKey(
     X509Certificate2 certificate,
     RSA privatekey)
 {
     using (var cfrg = new CertificateFactoryRandomGenerator())
     {
         var random = new Org.BouncyCastle.Security.SecureRandom(cfrg);
         Org.BouncyCastle.X509.X509Certificate x509 = new Org.BouncyCastle.X509.X509CertificateParser().ReadCertificate(certificate.RawData);
         return(CreateCertificateWithPrivateKey(x509, certificate.FriendlyName, GetPrivateKeyParameter(privatekey), random));
     }
 }
        /// <summary>
        /// Create a Pfx with a private key by combining
        /// an existing X509Certificate2 and a RSA private key.
        /// </summary>
        public static byte[] CreatePfxWithRSAPrivateKey(
            X509Certificate2 certificate,
            string friendlyName,
            RSA privateKey,
            string passcode)
        {
            var x509 = new X509CertificateParser().ReadCertificate(certificate.RawData);

            using (var cfrg = new CertificateFactoryRandomGenerator())
            {
                return(X509Utils.CreatePfxWithPrivateKey(
                           x509, friendlyName,
                           X509Utils.GetPrivateKeyParameter(privateKey),
                           passcode,
                           new SecureRandom(cfrg)));
            }
        }
    /// <summary>
    /// Create a X509Certificate2 with a private key by combining
    /// the new certificate with a private key from an existing certificate
    /// </summary>
    public static X509Certificate2 CreateCertificateWithPrivateKey(
        X509Certificate2 certificate,
        X509Certificate2 certificateWithPrivateKey)
    {
        if (!certificateWithPrivateKey.HasPrivateKey)
        {
            throw new NotSupportedException("Need a certificate with a private key.");
        }

        if (!VerifyRSAKeyPair(certificate, certificateWithPrivateKey))
        {
            throw new NotSupportedException("The public and the private key pair doesn't match.");
        }

        using (var cfrg = new CertificateFactoryRandomGenerator())
        {
            SecureRandom random = new SecureRandom(cfrg);
            Org.BouncyCastle.X509.X509Certificate x509 = new X509CertificateParser().ReadCertificate(certificate.RawData);
            return(CreateCertificateWithPrivateKey(x509, certificate.FriendlyName, GetPrivateKeyParameter(certificateWithPrivateKey), random));
        }
    }
        /// <summary>
        /// Creates a certificate signing request from an
        /// existing certificate with a private key.
        /// </summary>
        public static byte[] CreateSigningRequest(
            X509Certificate2 certificate,
            IList <String> domainNames = null
            )
        {
            if (certificate == null)
            {
                throw new ArgumentNullException(nameof(certificate));
            }
            using (var cfrg = new CertificateFactoryRandomGenerator())
            {
                SecureRandom random = new SecureRandom(cfrg);

                // try to get signing/private key from certificate passed in
                AsymmetricKeyParameter signingKey = X509Utils.GetPrivateKeyParameter(certificate);
                RsaKeyParameters       publicKey  = X509Utils.GetPublicKeyParameter(certificate);

                ISignatureFactory signatureFactory =
                    new Asn1SignatureFactory(X509Utils.GetRSAHashAlgorithm(X509Defaults.HashAlgorithmName), signingKey, random);

                Asn1Set attributes = null;
                var     san        = X509Extensions.FindExtension <X509SubjectAltNameExtension>(certificate);
                X509SubjectAltNameExtension alternateName = new X509SubjectAltNameExtension(san, san.Critical);

                string applicationUri = null;
                domainNames = domainNames ?? new List <String>();
                if (alternateName != null)
                {
                    if (alternateName.Uris.Count > 0)
                    {
                        applicationUri = alternateName.Uris[0];
                    }
                    foreach (var name in alternateName.DomainNames)
                    {
                        if (!domainNames.Any(s => s.Equals(name, StringComparison.OrdinalIgnoreCase)))
                        {
                            domainNames.Add(name);
                        }
                    }
                    foreach (var ipAddress in alternateName.IPAddresses)
                    {
                        if (!domainNames.Any(s => s.Equals(ipAddress, StringComparison.OrdinalIgnoreCase)))
                        {
                            domainNames.Add(ipAddress);
                        }
                    }
                }

                // build CSR extensions
                var generalNames = new List <GeneralName>();

                if (applicationUri != null)
                {
                    generalNames.Add(new GeneralName(GeneralName.UniformResourceIdentifier, applicationUri));
                }

                if (domainNames.Count > 0)
                {
                    generalNames.AddRange(BouncyCastle.X509Extensions.CreateSubjectAlternateNameDomains(domainNames));
                }

                if (generalNames.Count > 0)
                {
                    IList oids   = new ArrayList();
                    IList values = new ArrayList();
                    oids.Add(Org.BouncyCastle.Asn1.X509.X509Extensions.SubjectAlternativeName);
                    values.Add(new Org.BouncyCastle.Asn1.X509.X509Extension(false,
                                                                            new DerOctetString(new GeneralNames(generalNames.ToArray()).GetDerEncoded())));
                    var attribute = new Org.BouncyCastle.Asn1.Pkcs.AttributePkcs(Org.BouncyCastle.Asn1.Pkcs.PkcsObjectIdentifiers.Pkcs9AtExtensionRequest,
                                                                                 new DerSet(new Org.BouncyCastle.Asn1.X509.X509Extensions(oids, values)));
                    attributes = new DerSet(attribute);
                }

                var pkcs10CertificationRequest = new Pkcs10CertificationRequest(
                    signatureFactory,
                    new CertificateFactoryX509Name(false, certificate.Subject),
                    publicKey,
                    attributes);

                return(pkcs10CertificationRequest.GetEncoded());
            }
        }
    /// <summary>
    /// Creates a certificate signing request from an existing certificate.
    /// </summary>
    public static byte[] CreateSigningRequest(
        X509Certificate2 certificate,
        IList <String> domainNames = null
        )
    {
        using (var cfrg = new CertificateFactoryRandomGenerator())
        {
            SecureRandom random = new SecureRandom(cfrg);

            // try to get signing/private key from certificate passed in
            AsymmetricKeyParameter signingKey = GetPrivateKeyParameter(certificate);
            RsaKeyParameters       publicKey  = GetPublicKeyParameter(certificate);

            ISignatureFactory signatureFactory =
                new Asn1SignatureFactory(GetRSAHashAlgorithm(defaultHashSize), signingKey, random);

            Asn1Set attributes = null;
            X509SubjectAltNameExtension alternateName = null;
            foreach (System.Security.Cryptography.X509Certificates.X509Extension extension in certificate.Extensions)
            {
                if (extension.Oid.Value == X509SubjectAltNameExtension.SubjectAltNameOid || extension.Oid.Value == X509SubjectAltNameExtension.SubjectAltName2Oid)
                {
                    alternateName = new X509SubjectAltNameExtension(extension, extension.Critical);
                    break;
                }
            }

            domainNames = domainNames ?? new List <String>();
            if (alternateName != null)
            {
                foreach (var name in alternateName.DomainNames)
                {
                    if (!domainNames.Any(s => s.Equals(name, StringComparison.OrdinalIgnoreCase)))
                    {
                        domainNames.Add(name);
                    }
                }
                foreach (var ipAddress in alternateName.IPAddresses)
                {
                    if (!domainNames.Any(s => s.Equals(ipAddress, StringComparison.OrdinalIgnoreCase)))
                    {
                        domainNames.Add(ipAddress);
                    }
                }
            }

            if (domainNames.Count > 0)
            {
                List <GeneralName> generalNames = CreateSubjectAlternateNameDomains(domainNames);
                if (generalNames.Count > 0)
                {
                    IList oids   = new ArrayList();
                    IList values = new ArrayList();
                    oids.Add(X509Extensions.SubjectAlternativeName);
                    values.Add(new Org.BouncyCastle.Asn1.X509.X509Extension(false,
                                                                            new DerOctetString(new GeneralNames(generalNames.ToArray()).GetDerEncoded())));

                    AttributePkcs attribute = new AttributePkcs(PkcsObjectIdentifiers.Pkcs9AtExtensionRequest,
                                                                new DerSet(new X509Extensions(oids, values)));

                    attributes = new DerSet(attribute);
                }
            }

            Pkcs10CertificationRequest pkcs10CertificationRequest = new Pkcs10CertificationRequest(
                signatureFactory,
                new CertificateFactoryX509Name(false, certificate.Subject),
                publicKey,
                attributes,
                signingKey);

            return(pkcs10CertificationRequest.GetEncoded());
        }
    }
    /// <summary>
    /// Revoke the CA signed certificate.
    /// The issuer CA public key, the private key and the crl reside in the storepath.
    /// The CRL number is increased by one and existing CRL for the issuer are deleted from the store.
    /// </summary>
    public static async Task <X509CRL> RevokeCertificateAsync(
        string storePath,
        X509Certificate2 certificate,
        string issuerKeyFilePassword = null
        )
    {
        X509CRL updatedCRL = null;

        try
        {
            string subjectName  = certificate.IssuerName.Name;
            string keyId        = null;
            string serialNumber = null;

            // caller may want to create empty CRL using the CA cert itself
            bool isCACert = IsCertificateAuthority(certificate);

            // find the authority key identifier.
            X509AuthorityKeyIdentifierExtension authority = FindAuthorityKeyIdentifier(certificate);

            if (authority != null)
            {
                keyId        = authority.KeyId;
                serialNumber = authority.SerialNumber;
            }
            else
            {
                throw new ArgumentException("Certificate does not contain an Authority Key");
            }

            if (!isCACert)
            {
                if (serialNumber == certificate.SerialNumber ||
                    Utils.CompareDistinguishedName(certificate.Subject, certificate.Issuer))
                {
                    throw new ServiceResultException(StatusCodes.BadCertificateInvalid, "Cannot revoke self signed certificates");
                }
            }

            X509Certificate2 certCA = null;
            using (ICertificateStore store = CertificateStoreIdentifier.OpenStore(storePath))
            {
                if (store == null)
                {
                    throw new ArgumentException("Invalid store path/type");
                }
                certCA = await FindIssuerCABySerialNumberAsync(store, certificate.Issuer, serialNumber);

                if (certCA == null)
                {
                    throw new ServiceResultException(StatusCodes.BadCertificateInvalid, "Cannot find issuer certificate in store.");
                }

                if (!certCA.HasPrivateKey)
                {
                    throw new ServiceResultException(StatusCodes.BadCertificateInvalid, "Issuer certificate has no private key, cannot revoke certificate.");
                }

                CertificateIdentifier certCAIdentifier = new CertificateIdentifier(certCA);
                certCAIdentifier.StorePath = storePath;
                certCAIdentifier.StoreType = CertificateStoreIdentifier.DetermineStoreType(storePath);
                X509Certificate2 certCAWithPrivateKey = await certCAIdentifier.LoadPrivateKey(issuerKeyFilePassword);

                if (certCAWithPrivateKey == null)
                {
                    throw new ServiceResultException(StatusCodes.BadCertificateInvalid, "Failed to load issuer private key. Is the password correct?");
                }

                List <X509CRL> certCACrl = store.EnumerateCRLs(certCA, false);

                using (var cfrg = new CertificateFactoryRandomGenerator())
                {
                    // cert generators
                    SecureRandom random          = new SecureRandom(cfrg);
                    BigInteger   crlSerialNumber = BigInteger.Zero;

                    Org.BouncyCastle.X509.X509Certificate bcCertCA = new X509CertificateParser().ReadCertificate(certCA.RawData);
                    AsymmetricKeyParameter signingKey = GetPrivateKeyParameter(certCAWithPrivateKey);

                    ISignatureFactory signatureFactory =
                        new Asn1SignatureFactory(GetRSAHashAlgorithm(defaultHashSize), signingKey, random);

                    X509V2CrlGenerator crlGen = new X509V2CrlGenerator();
                    crlGen.SetIssuerDN(bcCertCA.IssuerDN);
                    crlGen.SetThisUpdate(DateTime.UtcNow);
                    crlGen.SetNextUpdate(DateTime.UtcNow.AddMonths(12));

                    // merge all existing revocation list
                    X509CrlParser parser = new X509CrlParser();
                    foreach (X509CRL caCrl in certCACrl)
                    {
                        X509Crl crl = parser.ReadCrl(caCrl.RawData);
                        crlGen.AddCrl(crl);
                        var crlVersion = GetCrlNumber(crl);
                        if (crlVersion.IntValue > crlSerialNumber.IntValue)
                        {
                            crlSerialNumber = crlVersion;
                        }
                    }

                    if (isCACert)
                    {
                        // add a dummy revoked cert
                        crlGen.AddCrlEntry(BigInteger.One, DateTime.UtcNow, CrlReason.Superseded);
                    }
                    else
                    {
                        // add the revoked cert
                        crlGen.AddCrlEntry(GetSerialNumber(certificate), DateTime.UtcNow, CrlReason.PrivilegeWithdrawn);
                    }

                    crlGen.AddExtension(X509Extensions.AuthorityKeyIdentifier,
                                        false,
                                        new AuthorityKeyIdentifierStructure(bcCertCA));

                    // set new serial number
                    crlSerialNumber = crlSerialNumber.Add(BigInteger.One);
                    crlGen.AddExtension(X509Extensions.CrlNumber,
                                        false,
                                        new CrlNumber(crlSerialNumber));

                    // generate updated CRL
                    X509Crl updatedCrl = crlGen.Generate(signatureFactory);

                    // add updated CRL to store
                    updatedCRL = new X509CRL(updatedCrl.GetEncoded());
                    store.AddCRL(updatedCRL);

                    // delete outdated CRLs from store
                    foreach (X509CRL caCrl in certCACrl)
                    {
                        store.DeleteCRL(caCrl);
                    }
                }
                store.Close();
            }
        }
        catch (Exception e)
        {
            throw e;
        }
        return(updatedCRL);
    }
    /// <summary>
    /// Creates a self signed application instance certificate.
    /// </summary>
    /// <param name="storeType">Type of certificate store (Directory) <see cref="CertificateStoreType"/>.</param>
    /// <param name="storePath">The store path (syntax depends on storeType).</param>
    /// <param name="password">The password to use to protect the certificate.</param>
    /// <param name="applicationUri">The application uri (created if not specified).</param>
    /// <param name="applicationName">Name of the application (optional if subjectName is specified).</param>
    /// <param name="subjectName">The subject used to create the certificate (optional if applicationName is specified).</param>
    /// <param name="domainNames">The domain names that can be used to access the server machine (defaults to local computer name if not specified).</param>
    /// <param name="keySize">Size of the key (1024, 2048 or 4096).</param>
    /// <param name="startTime">The start time.</param>
    /// <param name="lifetimeInMonths">The lifetime of the key in months.</param>
    /// <param name="hashSizeInBits">The hash size in bits.</param>
    /// <param name="isCA">if set to <c>true</c> then a CA certificate is created.</param>
    /// <param name="issuerCAKeyCert">The CA cert with the CA private key.</param>
    /// <returns>The certificate with a private key.</returns>
    public static X509Certificate2 CreateCertificate(
        string storeType,
        string storePath,
        string password,
        string applicationUri,
        string applicationName,
        string subjectName,
        IList <String> domainNames,
        ushort keySize,
        DateTime startTime,
        ushort lifetimeInMonths,
        ushort hashSizeInBits,
        bool isCA = false,
        X509Certificate2 issuerCAKeyCert = null,
        byte[] publicKey = null)
    {
        if (issuerCAKeyCert != null)
        {
            if (!issuerCAKeyCert.HasPrivateKey)
            {
                throw new NotSupportedException("Cannot sign with a CA certificate without a private key.");
            }
        }

        if (publicKey != null && issuerCAKeyCert == null)
        {
            throw new NotSupportedException("Cannot use a public key without a CA certificate with a private key.");
        }

        // set default values.
        X509Name subjectDN = SetSuitableDefaults(
            ref applicationUri,
            ref applicationName,
            ref subjectName,
            ref domainNames,
            ref keySize,
            ref lifetimeInMonths);

        using (var cfrg = new CertificateFactoryRandomGenerator())
        {
            // cert generators
            SecureRandom random           = new SecureRandom(cfrg);
            X509V3CertificateGenerator cg = new X509V3CertificateGenerator();

            // Serial Number
            BigInteger serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random);
            cg.SetSerialNumber(serialNumber);

            // subject and issuer DN
            X509Name issuerDN = null;
            if (issuerCAKeyCert != null)
            {
                issuerDN = new CertificateFactoryX509Name(issuerCAKeyCert.Subject);
            }
            else
            {
                // self signed
                issuerDN = subjectDN;
            }
            cg.SetIssuerDN(issuerDN);
            cg.SetSubjectDN(subjectDN);

            // valid for
            cg.SetNotBefore(startTime);
            cg.SetNotAfter(startTime.AddMonths(lifetimeInMonths));

            // set Private/Public Key
            AsymmetricKeyParameter subjectPublicKey;
            AsymmetricKeyParameter subjectPrivateKey;
            if (publicKey == null)
            {
                var keyGenerationParameters = new KeyGenerationParameters(random, keySize);
                var keyPairGenerator        = new RsaKeyPairGenerator();
                keyPairGenerator.Init(keyGenerationParameters);
                AsymmetricCipherKeyPair subjectKeyPair = keyPairGenerator.GenerateKeyPair();
                subjectPublicKey  = subjectKeyPair.Public;
                subjectPrivateKey = subjectKeyPair.Private;
            }
            else
            {
                // special case, if a cert is signed by CA, the private key of the cert is not needed
                subjectPublicKey  = PublicKeyFactory.CreateKey(publicKey);
                subjectPrivateKey = null;
            }
            cg.SetPublicKey(subjectPublicKey);

            // add extensions
            // Subject key identifier
            cg.AddExtension(X509Extensions.SubjectKeyIdentifier.Id, false,
                            new SubjectKeyIdentifier(SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(subjectPublicKey)));

            // Basic constraints
            cg.AddExtension(X509Extensions.BasicConstraints.Id, true, new BasicConstraints(isCA));

            // Authority Key identifier references the issuer cert or itself when self signed
            AsymmetricKeyParameter issuerPublicKey;
            BigInteger             issuerSerialNumber;
            if (issuerCAKeyCert != null)
            {
                issuerPublicKey    = GetPublicKeyParameter(issuerCAKeyCert);
                issuerSerialNumber = GetSerialNumber(issuerCAKeyCert);
            }
            else
            {
                issuerPublicKey    = subjectPublicKey;
                issuerSerialNumber = serialNumber;
            }

            cg.AddExtension(X509Extensions.AuthorityKeyIdentifier.Id, false,
                            new AuthorityKeyIdentifier(SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(issuerPublicKey),
                                                       new GeneralNames(new GeneralName(issuerDN)), issuerSerialNumber));

            if (!isCA)
            {
                // Key usage
                cg.AddExtension(X509Extensions.KeyUsage, true,
                                new KeyUsage(KeyUsage.DataEncipherment | KeyUsage.DigitalSignature |
                                             KeyUsage.NonRepudiation | KeyUsage.KeyCertSign | KeyUsage.KeyEncipherment));

                // Extended Key usage
                cg.AddExtension(X509Extensions.ExtendedKeyUsage, true,
                                new ExtendedKeyUsage(new List <DerObjectIdentifier>()
                {
                    new DerObjectIdentifier("1.3.6.1.5.5.7.3.1"), // server auth
                    new DerObjectIdentifier("1.3.6.1.5.5.7.3.2"), // client auth
                }));

                // subject alternate name
                List <GeneralName> generalNames = new List <GeneralName>();
                generalNames.Add(new GeneralName(GeneralName.UniformResourceIdentifier, applicationUri));
                generalNames.AddRange(CreateSubjectAlternateNameDomains(domainNames));
                cg.AddExtension(X509Extensions.SubjectAlternativeName, false, new GeneralNames(generalNames.ToArray()));
            }
            else
            {
                // Key usage CA
                cg.AddExtension(X509Extensions.KeyUsage, true,
                                new KeyUsage(KeyUsage.CrlSign | KeyUsage.DigitalSignature | KeyUsage.KeyCertSign));
            }

            // sign certificate
            AsymmetricKeyParameter signingKey;
            if (issuerCAKeyCert != null)
            {
                // signed by issuer
                signingKey = GetPrivateKeyParameter(issuerCAKeyCert);
            }
            else
            {
                // self signed
                signingKey = subjectPrivateKey;
            }
            ISignatureFactory signatureFactory =
                new Asn1SignatureFactory(GetRSAHashAlgorithm(hashSizeInBits), signingKey, random);
            Org.BouncyCastle.X509.X509Certificate x509 = cg.Generate(signatureFactory);

            // convert to X509Certificate2
            X509Certificate2 certificate = null;
            if (subjectPrivateKey == null)
            {
                // create the cert without the private key
                certificate = new X509Certificate2(x509.GetEncoded());
            }
            else
            {
                // note: this cert has a private key!
                certificate = CreateCertificateWithPrivateKey(x509, null, subjectPrivateKey, random);
            }

            Utils.Trace(Utils.TraceMasks.Security, "Created new certificate: {0}", certificate.Thumbprint);

            // add cert to the store.
            if (!String.IsNullOrEmpty(storePath) && !String.IsNullOrEmpty(storeType))
            {
                using (ICertificateStore store = CertificateStoreIdentifier.CreateStore(storeType))
                {
                    if (store == null)
                    {
                        throw new ArgumentException("Invalid store type");
                    }

                    store.Open(storePath);
                    store.Add(certificate, password).Wait();
                    store.Close();
                }
            }

            return(certificate);
        }
    }
Example #11
0
    /// <summary>
    /// Creates a self signed application instance certificate.
    /// </summary>
    /// <param name="storeType">Type of certificate store (Directory) <see cref="CertificateStoreType"/>.</param>
    /// <param name="storePath">The store path (syntax depends on storeType).</param>
    /// <param name="password">The password to use to protect the certificate.</param>
    /// <param name="applicationUri">The application uri (created if not specified).</param>
    /// <param name="applicationName">Name of the application (optional if subjectName is specified).</param>
    /// <param name="subjectName">The subject used to create the certificate (optional if applicationName is specified).</param>
    /// <param name="domainNames">The domain names that can be used to access the server machine (defaults to local computer name if not specified).</param>
    /// <param name="keySize">Size of the key (1024, 2048 or 4096).</param>
    /// <param name="startTime">The start time.</param>
    /// <param name="lifetimeInMonths">The lifetime of the key in months.</param>
    /// <param name="hashSizeInBits">The hash size in bits.</param>
    /// <param name="isCA">if set to <c>true</c> then a CA certificate is created.</param>
    /// <param name="issuerCAKeyCert">The CA cert with the CA private key.</param>
    /// <returns>The certificate with a private key.</returns>
    public static X509Certificate2 CreateCertificate(
        string storeType,
        string storePath,
        string password,
        string applicationUri,
        string applicationName,
        string subjectName,
        IList <String> domainNames,
        ushort keySize,
        DateTime startTime,
        ushort lifetimeInMonths,
        ushort hashSizeInBits,
        bool isCA,
        X509Certificate2 issuerCAKeyCert)
    {
        if (issuerCAKeyCert != null)
        {
            if (!issuerCAKeyCert.HasPrivateKey)
            {
                throw new NotSupportedException("Cannot sign with a CA certificate without a private key.");
            }
        }

        // set default values.
        X509Name subjectDN = SetSuitableDefaults(
            ref applicationUri,
            ref applicationName,
            ref subjectName,
            ref domainNames,
            ref keySize,
            ref lifetimeInMonths,
            isCA);

        using (var cfrg = new CertificateFactoryRandomGenerator())
        {
            // cert generators
            SecureRandom random           = new SecureRandom(cfrg);
            X509V3CertificateGenerator cg = new X509V3CertificateGenerator();

            // Serial Number
            BigInteger serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random);
            cg.SetSerialNumber(serialNumber);

            X509Name issuerDN = null;
            if (issuerCAKeyCert != null)
            {
                issuerDN = new X509Name(true, issuerCAKeyCert.Subject.Replace("S=", "ST="));
            }
            else
            {
                // self signed
                issuerDN = subjectDN;
            }

            cg.SetIssuerDN(issuerDN);
            cg.SetSubjectDN(subjectDN);

            // valid for
            cg.SetNotBefore(startTime);
            cg.SetNotAfter(startTime.AddMonths(lifetimeInMonths));

            // Private/Public Key
            AsymmetricCipherKeyPair subjectKeyPair;
            var keyGenerationParameters = new KeyGenerationParameters(random, keySize);
            var keyPairGenerator        = new RsaKeyPairGenerator();
            keyPairGenerator.Init(keyGenerationParameters);
            subjectKeyPair = keyPairGenerator.GenerateKeyPair();
            cg.SetPublicKey(subjectKeyPair.Public);

            // add extensions
            // Subject key identifier
            cg.AddExtension(X509Extensions.SubjectKeyIdentifier.Id, false,
                            new SubjectKeyIdentifier(SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(subjectKeyPair.Public)));

            // Basic constraints
            cg.AddExtension(X509Extensions.BasicConstraints.Id, true, new BasicConstraints(isCA));

            // Authority Key identifier
            var issuerKeyPair      = subjectKeyPair;
            var issuerSerialNumber = serialNumber;
            cg.AddExtension(X509Extensions.AuthorityKeyIdentifier.Id, false,
                            new AuthorityKeyIdentifier(SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(subjectKeyPair.Public),
                                                       new GeneralNames(new GeneralName(issuerDN)), issuerSerialNumber));

            if (!isCA)
            {
                // Key usage
                cg.AddExtension(X509Extensions.KeyUsage, true,
                                new KeyUsage(KeyUsage.DataEncipherment | KeyUsage.DigitalSignature |
                                             KeyUsage.NonRepudiation | KeyUsage.KeyCertSign | KeyUsage.KeyEncipherment));

                // Extended Key usage
                cg.AddExtension(X509Extensions.ExtendedKeyUsage, true,
                                new ExtendedKeyUsage(new List <DerObjectIdentifier>()
                {
                    new DerObjectIdentifier("1.3.6.1.5.5.7.3.1"), // server auth
                    new DerObjectIdentifier("1.3.6.1.5.5.7.3.2"), // client auth
                }));

                // subject alternate name
                cg.AddExtension(X509Extensions.SubjectAlternativeName, false,
                                new GeneralNames(new GeneralName[] {
                    new GeneralName(GeneralName.UniformResourceIdentifier, applicationUri),
                    new GeneralName(GeneralName.DnsName, domainNames[0])
                }));
            }
            else
            {
                // Key usage CA
                cg.AddExtension(X509Extensions.KeyUsage, true,
                                new KeyUsage(KeyUsage.CrlSign | KeyUsage.DigitalSignature | KeyUsage.KeyCertSign));
            }

            // sign certificate
            AsymmetricKeyParameter privateKey = null;
            if (issuerCAKeyCert != null)
            {
                using (RSA rsa = issuerCAKeyCert.GetRSAPrivateKey())
                {
                    RSAParameters rsaParams = rsa.ExportParameters(true);
                    RsaPrivateCrtKeyParameters keyParams = new RsaPrivateCrtKeyParameters(
                        new BigInteger(1, rsaParams.Modulus),
                        new BigInteger(1, rsaParams.Exponent),
                        new BigInteger(1, rsaParams.D),
                        new BigInteger(1, rsaParams.P),
                        new BigInteger(1, rsaParams.Q),
                        new BigInteger(1, rsaParams.DP),
                        new BigInteger(1, rsaParams.DQ),
                        new BigInteger(1, rsaParams.InverseQ));
                    privateKey = keyParams;
                }
            }
            else
            {
                privateKey = subjectKeyPair.Private;
            }

            ISignatureFactory signatureFactory =
                new Asn1SignatureFactory((hashSizeInBits < 256) ? "SHA1WITHRSA" : "SHA256WITHRSA", privateKey, random);

            Org.BouncyCastle.X509.X509Certificate x509 = cg.Generate(signatureFactory);

            // create pkcs12 store for cert and private key
            X509Certificate2 certificate = null;
            using (MemoryStream pfxData = new MemoryStream())
            {
                Pkcs12Store            pkcsStore = new Pkcs12StoreBuilder().Build();
                X509CertificateEntry[] chain     = new X509CertificateEntry[1];
                string passcode = Guid.NewGuid().ToString();
                chain[0] = new X509CertificateEntry(x509);
                pkcsStore.SetKeyEntry(applicationName, new AsymmetricKeyEntry(subjectKeyPair.Private), chain);
                pkcsStore.Save(pfxData, passcode.ToCharArray(), random);

                // merge into X509Certificate2
                certificate = CreateCertificateFromPKCS12(pfxData.ToArray(), passcode);
            }

            Utils.Trace(Utils.TraceMasks.Security, "Created new certificate: {0}", certificate.Thumbprint);

            // add cert to the store.
            if (!String.IsNullOrEmpty(storePath))
            {
                ICertificateStore store = null;
                if (storeType == CertificateStoreType.X509Store)
                {
                    store = new X509CertificateStore();
                }
                else if (storeType == CertificateStoreType.Directory)
                {
                    store = new DirectoryCertificateStore();
                }
                else
                {
                    throw new ArgumentException("Invalid store type");
                }

                store.Open(storePath);
                store.Add(certificate, password);
                store.Close();
                store.Dispose();
            }

            // note: this cert has a private key!
            return(certificate);
        }
    }
    /// <summary>
    /// Revoke the certificate.
    /// The CRL number is increased by one and the new CRL is returned.
    /// </summary>
    public static X509CRL RevokeCertificate(
        X509Certificate2 issuerCertificate,
        List <X509CRL> issuerCrls,
        X509Certificate2Collection revokedCertificates
        )
    {
        if (!issuerCertificate.HasPrivateKey)
        {
            throw new ServiceResultException(StatusCodes.BadCertificateInvalid, "Issuer certificate has no private key, cannot revoke certificate.");
        }

        using (var cfrg = new CertificateFactoryRandomGenerator())
        {
            // cert generators
            SecureRandom random          = new SecureRandom(cfrg);
            BigInteger   crlSerialNumber = BigInteger.Zero;

            Org.BouncyCastle.X509.X509Certificate bcCertCA = new X509CertificateParser().ReadCertificate(issuerCertificate.RawData);
            AsymmetricKeyParameter signingKey = GetPrivateKeyParameter(issuerCertificate);

            ISignatureFactory signatureFactory =
                new Asn1SignatureFactory(GetRSAHashAlgorithm(defaultHashSize), signingKey, random);

            X509V2CrlGenerator crlGen = new X509V2CrlGenerator();
            crlGen.SetIssuerDN(bcCertCA.IssuerDN);
            crlGen.SetThisUpdate(DateTime.UtcNow);
            crlGen.SetNextUpdate(DateTime.UtcNow.AddMonths(12));

            // merge all existing revocation list
            if (issuerCrls != null)
            {
                X509CrlParser parser = new X509CrlParser();
                foreach (X509CRL issuerCrl in issuerCrls)
                {
                    X509Crl crl = parser.ReadCrl(issuerCrl.RawData);
                    crlGen.AddCrl(crl);
                    var crlVersion = GetCrlNumber(crl);
                    if (crlVersion.IntValue > crlSerialNumber.IntValue)
                    {
                        crlSerialNumber = crlVersion;
                    }
                }
            }

            DateTime now = DateTime.UtcNow;
            if (revokedCertificates == null || revokedCertificates.Count == 0)
            {
                // add a dummy revoked cert
                crlGen.AddCrlEntry(BigInteger.One, now, CrlReason.Unspecified);
            }
            else
            {
                // add the revoked cert
                foreach (var revokedCertificate in revokedCertificates)
                {
                    crlGen.AddCrlEntry(GetSerialNumber(revokedCertificate), now, CrlReason.PrivilegeWithdrawn);
                }
            }

            crlGen.AddExtension(X509Extensions.AuthorityKeyIdentifier,
                                false,
                                new AuthorityKeyIdentifierStructure(bcCertCA));

            // set new serial number
            crlSerialNumber = crlSerialNumber.Add(BigInteger.One);
            crlGen.AddExtension(X509Extensions.CrlNumber,
                                false,
                                new CrlNumber(crlSerialNumber));

            // generate updated CRL
            X509Crl updatedCrl = crlGen.Generate(signatureFactory);
            return(new X509CRL(updatedCrl.GetEncoded()));
        }
    }