C# Generate intermediate certificate from self signed root CA


username

I am using Visual Studio 2019 with c# and Bouncy Castlein version 1.8.5. I have been able to generate Certificate Authority(CA) successfully and now want to generate one Intermediate Certificate. In the current workflow, the CA certificate is returned as X509Certificate2-object , which I pass to generate the intermediate certificate. From there I want to read, PrivateKeybut doing so is cumbersome.

For CA generation (this CACertificateDetailsis a simple class to store the string to be passed):

public static X509Certificate2 GenerateCA(CACertificateDetails details)
{
    // generate a random number
    var random = GetSecureRandom();

    // init the certificate generator
    X509V3CertificateGenerator certificateGenerator = new X509V3CertificateGenerator();

    // serial number
    certificateGenerator.SetSerialNumber(SerialNumber(random));

    // set issuer and subject name
    var subjectDN = new X509Name(details.SubjectName);
    var issuerDN = new X509Name(details.IssuerName);
    certificateGenerator.SetIssuerDN(issuerDN);
    certificateGenerator.SetSubjectDN(subjectDN);

    // validation time
    var notBefore = DateTime.UtcNow.Date;
    var notAfter = notBefore.AddYears(details.ValidYears);
    certificateGenerator.SetNotBefore(notBefore);
    certificateGenerator.SetNotAfter(notAfter);

    // subject public Key
    AsymmetricCipherKeyPair subjectKeyPair;
    KeyGenerationParameters keyGenerationParameters = new KeyGenerationParameters(random, details.KeyStrength);
    RsaKeyPairGenerator keyPairGenerator = new RsaKeyPairGenerator();
    keyPairGenerator.Init(keyGenerationParameters);
    subjectKeyPair = keyPairGenerator.GenerateKeyPair();

    certificateGenerator.SetPublicKey(subjectKeyPair.Public);

    // set the hash algorithm
    AsymmetricCipherKeyPair issuerKeyPair = subjectKeyPair;
    ISignatureFactory signatureFactory = new Asn1SignatureFactory(PkcsObjectIdentifiers.Sha512WithRsaEncryption.ToString(), issuerKeyPair.Private, random);

    // generate the certificate
    var certificate = certificateGenerator.Generate(signatureFactory);
    var x509Certificate = new X509Certificate2(certificate.GetEncoded());

    PrivateKeyInfo info = PrivateKeyInfoFactory.CreatePrivateKeyInfo(subjectKeyPair.Private);
    Asn1Sequence seq = (Asn1Sequence)Asn1Object.FromByteArray(info.ParsePrivateKey().GetDerEncoded());
    if (seq.Count != 9)
    {
        throw new PemException("malformed sequence in RSA private key");
    }

    RsaPrivateKeyStructure rsa = RsaPrivateKeyStructure.GetInstance(seq);
    RsaPrivateCrtKeyParameters rsaparams = new RsaPrivateCrtKeyParameters(
        rsa.Modulus, rsa.PublicExponent, rsa.PrivateExponent, rsa.Prime1, rsa.Prime2, rsa.Exponent1, rsa.Exponent2, rsa.Coefficient);

    var convertedRsa = DotNetUtilities.ToRSA(rsaparams);
    var x509CertificateRet = x509Certificate.CopyWithPrivateKey(convertedRsa);
    x509CertificateRet.FriendlyName = details.FriendlyName;

    return x509CertificateRet;
}

The way to generate an intermediate certificate is as follows (the just generated CA is now passed as an object):

public static X509Certificate2 GenerateCertificate(CertificateDetails details, X509Certificate2 issuer)
{
    // generate a random number
    var random = GetSecureRandom();

    // init the certificate generator
    X509V3CertificateGenerator certificateGenerator = new X509V3CertificateGenerator();

    // serial number
    certificateGenerator.SetSerialNumber(SerialNumber(random));

    // set issuer and subject name
    var issuerDN = new X509Name(issuer.Issuer);
    certificateGenerator.SetIssuerDN(issuerDN);

    var distinguishedNames = DistinguishedName(details);
    var nameOids = new ArrayList(distinguishedNames.Select(x => x.Item1).ToArray());
    var nameValues = new ArrayList(distinguishedNames.Select(x => x.Item2).ToArray());
    var subjectDN = new X509Name(nameOids, nameValues);
    certificateGenerator.SetSubjectDN(subjectDN);

    // authority key identifier
    var authorityKeyIdentifier = new AuthorityKeyIdentifierStructure(DotNetUtilities.FromX509Certificate(issuer));
    certificateGenerator.AddExtension(X509Extensions.AuthorityKeyIdentifier.Id, false, authorityKeyIdentifier);

    // Basic Constraints - certificate is allowed to be used as intermediate.
    certificateGenerator.AddExtension(X509Extensions.BasicConstraints.Id, true, new BasicConstraints(details.IsIntermediateCertificate));

    // key usage
    if (!details.IsIntermediateCertificate)
    {
        certificateGenerator.AddExtension(X509Extensions.KeyUsage, true, new KeyUsage(KeyUsage.DigitalSignature | KeyUsage.DataEncipherment | KeyUsage.KeyAgreement));
        certificateGenerator.AddExtension(X509Extensions.ExtendedKeyUsage, true, new ExtendedKeyUsage(new[] { KeyPurposeID.IdKPServerAuth, KeyPurposeID.IdKPServerAuth }));
    }
    else
    {
        certificateGenerator.AddExtension(X509Extensions.KeyUsage, true, new KeyUsage(KeyUsage.DigitalSignature | KeyUsage.DataEncipherment | KeyUsage.KeyAgreement | KeyUsage.KeyCertSign));
        certificateGenerator.AddExtension(X509Extensions.ExtendedKeyUsage, true, new ExtendedKeyUsage(KeyPurposeID.AnyExtendedKeyUsage));
    }

    // validation time
    var notBefore = DateTime.UtcNow.Date;
    var notAfter = notBefore.AddYears(details.ValidYears);
    certificateGenerator.SetNotBefore(notBefore);
    certificateGenerator.SetNotAfter(notAfter);

    // subject public Key
    AsymmetricCipherKeyPair subjectKeyPair;
    KeyGenerationParameters keyGenerationParameters = new KeyGenerationParameters(random, details.KeyStrength);
    RsaKeyPairGenerator keyPairGenerator = new RsaKeyPairGenerator();
    keyPairGenerator.Init(keyGenerationParameters);
    subjectKeyPair = keyPairGenerator.GenerateKeyPair();

    certificateGenerator.SetPublicKey(subjectKeyPair.Public);

    // set the hash algorithm
    var issuerPrivateKey = TransformRSAPrivateKey(issuer.PrivateKey);
    ISignatureFactory signatureFactory = new Asn1SignatureFactory("SHA3-512withRSA", issuerPrivateKey, random);

    // generate the certificate
    var certificate = certificateGenerator.Generate(signatureFactory);

    PrivateKeyInfo info = PrivateKeyInfoFactory.CreatePrivateKeyInfo(subjectKeyPair.Private);
    var x509Certificate = new X509Certificate2(certificate.GetEncoded());

    Asn1Sequence seq = (Asn1Sequence)Asn1Object.FromByteArray(info.ParsePrivateKey().GetDerEncoded());
    if (seq.Count != 9)
    {
        throw new PemException("Malformed sequence in RSA private key");
    }

    RsaPrivateKeyStructure rsa = RsaPrivateKeyStructure.GetInstance(seq);
    RsaPrivateCrtKeyParameters rsaparams = new RsaPrivateCrtKeyParameters(
        rsa.Modulus, rsa.PublicExponent, rsa.PrivateExponent, rsa.Prime1, rsa.Prime2, rsa.Exponent1, rsa.Exponent2, rsa.Coefficient);

    x509Certificate.PrivateKey = DotNetUtilities.ToRSA(rsaparams);
    x509Certificate.FriendlyName = details.FriendlyName;

    return x509Certificate;
}

I can't TransformRSAPrivateKeyexecute the function online now , prov.ExportParameters(true)probably because I can't find the private key data, I 'm wondering since I copied it x509Certificate.CopyWithPrivateKey(convertedRsa)in the CA generation .

private static AsymmetricKeyParameter TransformRSAPrivateKey(AsymmetricAlgorithm privateKey)
{
    RSACryptoServiceProvider prov = privateKey as RSACryptoServiceProvider;
    RSAParameters parameters = prov.ExportParameters(true);

    return new RsaPrivateCrtKeyParameters(
        new BigInteger(1, parameters.Modulus),
        new BigInteger(1, parameters.Exponent),
        new BigInteger(1, parameters.D),
        new BigInteger(1, parameters.P),
        new BigInteger(1, parameters.Q),
        new BigInteger(1, parameters.DP),
        new BigInteger(1, parameters.DQ),
        new BigInteger(1, parameters.InverseQ));
}

How do I continue to generate (and sign) my CA with a CA Intermediate Certificate? I don't want to pass as AsymmetricKeyParameterseen in multiple examples on stackoverflow . At some point I might want to save the CA to disk and read it at another time to generate a certificate with the same CA. At that point, I won't have a CA generation workflow, and therefore no AsymmetricKeyParameterobjects.

username

Ok, the problem is in the following lines:

// set the hash algorithm
var issuerPrivateKey = TransformRSAPrivateKey(issuer.PrivateKey);
ISignatureFactory signatureFactory = new Asn1SignatureFactory("SHA3-512withRSA", issuerPrivateKey, random);

The X509Certificate2issuer certificate can be passed to the GenerateCertificatefunction as in the original post . The trick is to load the certificate with the flags into it X509KeyStorageFlags.Exportable, eg X509Certificate2(certificatePath, password, X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);.

Also, I changed the code to

// set the hash algorithm
var issuerPrivateKey = DotNetUtilities.GetKeyPair(issuerCA.PrivateKey).Private;
ISignatureFactory signatureFactory = new Asn1SignatureFactory(PkcsObjectIdentifiers.Sha512WithRsaEncryption.ToString(), issuerPrivateKey, random);

Related


C# Generate intermediate certificate from self signed root CA

username I am using Visual Studio 2019 with c# and Bouncy Castlein version 1.8.5. I have been able to generate Certificate Authority(CA) successfully and now want to generate one Intermediate Certificate. In the current workflow, the CA certificate is returned

C# Generate intermediate certificate from self signed root CA

username I am using Visual Studio 2019 with c# and Bouncy Castlein version 1.8.5. I have been able to generate Certificate Authority(CA) successfully and now want to generate one Intermediate Certificate. In the current workflow, the CA certificate is returned

C# Generate intermediate certificate from self signed root CA

username I am using Visual Studio 2019 with c# and Bouncy Castlein version 1.8.5. I have been able to generate Certificate Authority(CA) successfully and now want to generate one Intermediate Certificate. In the current workflow, the CA certificate is returned

C# Generate intermediate certificate from self signed root CA

username I am using Visual Studio 2019 with c# and Bouncy Castlein version 1.8.5. I have been able to generate Certificate Authority(CA) successfully and now want to generate one Intermediate Certificate. In the current workflow, the CA certificate is returned

C# Generate intermediate certificate from self signed root CA

username I am using Visual Studio 2019 with c# and Bouncy Castlein version 1.8.5. I have been able to generate Certificate Authority(CA) successfully and now want to generate one Intermediate Certificate. In the current workflow, the CA certificate is returned

Generate self-signed certificate with root CA signer

Ninja Ninja Scenario: I'm using PowerShell on Windows Server 2012r2 to generate a root certificate and want to use it to sign newly created intermediate and web certificates in a dynamically generated (and destroyed) dev/test environment. The scripts are deplo

Generate self-signed certificate with root CA signer

Ninja Ninja Scenario: I'm using PowerShell on Windows Server 2012r2 to generate a root certificate and want to use it to sign newly created intermediate and web certificates in a dynamically generated (and destroyed) dev/test environment. The scripts are deplo

Generate self-signed certificate with root CA signer

Ninja Ninja Scenario: I'm using PowerShell on Windows Server 2012r2 to generate a root certificate and want to use it to sign newly created intermediate and web certificates in a dynamically generated (and destroyed) dev/test environment. The scripts are deplo

OpenSSL Self-Signed Root CA Certificate: Set Start Date

Kampar I'm using the following setup (using OpenSSL 1.0.1 14 Mar 2012) to create a small test CA with my own self signed certificate. The problem I'm having is that if I look at the start date of the CA's own certificate, it will create it for tomorrow (and I

OpenSSL Self-Signed Root CA Certificate: Set Start Date

Kampar I'm using the following setup (using OpenSSL 1.0.1 14 Mar 2012) to create a small test CA with my own self signed certificate. The problem I'm having is that if I look at the start date of the CA's own certificate, it will create it for tomorrow (and I

OpenSSL Self-Signed Root CA Certificate: Set Start Date

Kampar I'm using the following setup (using OpenSSL 1.0.1 14 Mar 2012) to create a small test CA with my own self signed certificate. My problem is that if I look at the start date of the CA's own certificate, it will create that certificate for tomorrow (and

OpenSSL Self-Signed Root CA Certificate: Set Start Date

Kampar I'm using the following setup (using OpenSSL 1.0.1 14 Mar 2012) to create a small test CA with my own self signed certificate. The problem I'm having is that if I look at the start date of the CA's own certificate, it will create it for tomorrow (and I

Self-signed certificate with CA

Jawad-Dev: I am working on a solution for file encryption via a combination of RSA and AES. RSA is basically used here for a handshake to encrypt a symmetric key and decrypt with the key pair at the receiver side. I have used Java keystore for private key and

Self-signed certificate with CA

Jawad-Dev: I am working on a solution for file encryption via a combination of RSA and AES. RSA is basically used here for a handshake to encrypt a symmetric key and decrypt with the key pair at the receiver side. I have used Java keystore for private key and

Self-signed certificate with CA

Jawad-Dev: I am working on a solution for file encryption via a combination of RSA and AES. RSA is basically used here for a handshake to encrypt a symmetric key and decrypt with the key pair at the receiver side. I have used Java keystore for private key and

Self-signed certificate with CA

Jawad-Dev: I am working on a solution for file encryption via a combination of RSA and AES. RSA is basically used here for a handshake to encrypt a symmetric key and decrypt with the key pair at the receiver side. I have used Java keystore for private key and

Trusted CA on self-signed certificate

horny I have an old Linux based embedded device from a project about ten years ago. The device has no built-in UI, keyboard or anything like that, just a small web server to control it. I have since forgotten the passcode on the device and the company that ori

Trusted CA on self-signed certificate

horny I have an old Linux based embedded device from a project about ten years ago. The device has no built-in UI, keyboard or anything like that, just a small web server to control it. I have since forgotten the passcode on the device and the company that ori

Find out if a certificate is self-signed or CA-signed

Nishan: I have a web application that allows users to upload pkcs12. I store pkcs12 as binary in database. Is there any way for me to know if the certificate in pkcs12 is self signed or CA signed? I am running a java web application on tomcat and can use opens

Find out if a certificate is self-signed or CA-signed

Nishan: I have a web application that allows users to upload pkcs12. I store pkcs12 as binary in database. Is there any way for me to know if the certificate in pkcs12 is self signed or CA signed? I am running a java web application on tomcat and can use opens

Find out if a certificate is self-signed or CA-signed

Nishan: I have a web application that allows users to upload pkcs12. I store pkcs12 as binary in database. Is there any way for me to know if the certificate in pkcs12 is self signed or CA signed? I am running a java web application on tomcat and can use opens