如何使用 BouncyCastle 生成根证书,然后生成由该根证书签名的站点证书? [英] How do I use BouncyCastle to generate a Root Certificate and then a site certificate that is signed by that Root certificate?

查看:93
本文介绍了如何使用 BouncyCastle 生成根证书,然后生成由该根证书签名的站点证书?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试构建一个使用 WebAPISSL 的自托管服务,并且我需要能够自行生成 SSL 证书才能使用.我希望能够通过 C# 来完成这一切.我一直在玩 BouncyCastle.

I'm trying to build a self hosted service that uses WebAPI with SSL and I need to be able to self-generate SSL certificates to use. I want to be able to do this all from C#. I've been playing with BouncyCastle.

我需要生成 2 个证书,一个根证书和一个站点证书.然后我需要将它们安装在 Windows 中的正确位置.

I need to generate 2 certificates, a root and a site certificate. Then I need to install them in Windows in their correct places.

我不知道如何让我的第二个证书引用我的根 ca.我尝试过的所有事情都会让我遇到一个不受信任的证书错误.任何帮助将不胜感激.

I can't figure out how to make my second certificate reference my root ca. Everything I've tried just gets me an untrusted certificate error. Any help would be appreciated.

推荐答案

我就是这么做的(我用的是DSA,但是如果你用的是RSA,就改密钥生成).

This is what I do (I'm using DSA, but if you are using RSA, just change the key generation).

public void IssueClientFromCA()
{
    // get CA
    string caCn = "MyCA CommonName";
    Stream caCertFile = File.OpenRead(string.Format(@"{0}{1}", _certificatesDir, "MyCAFile.pfx"));
    char[] caPass = "passwordForThePfx".ToCharArray();

    Pkcs12Store store = new Pkcs12StoreBuilder().Build();
    store.Load(caCertFile, caPass);            
    var caCert = store.GetCertificate(caCn).Certificate;
    var caPrivKey = store.GetKey(caCn).Key;

    var clientCert = CertIssuer.GenerateDsaCertificateAsPkcs12(
        "My Client FriendlyName",
        "My Client SubjectName", 
        "GT",
        new DateTime(2011,9,19), 
        new DateTime(2014,9,18),
        "PFXPASS",
        caCert,
        caPrivKey);

    var saveAS = string.Format(@"{0}{1}", _certificatesDir, "clientCertFile.pfx");
    File.WriteAllBytes(saveAS, clientCert);
}

public static byte[] GenerateDsaCertificateAsPkcs12(
    string friendlyName,
    string subjectName,
    string country,
    DateTime validStartDate,
    DateTime validEndDate,
    string password,
    Org.BouncyCastle.X509.X509Certificate caCert,
    AsymmetricKeyParameter caPrivateKey)
{
    var keys = GenerateDsaKeys();

    #region build certificate
    var certGen = new X509V3CertificateGenerator();

    // build name attributes
    var nameOids = new ArrayList();
    nameOids.Add(Org.BouncyCastle.Asn1.X509.X509Name.CN);
    nameOids.Add(X509Name.O);
    nameOids.Add(X509Name.C);

    var nameValues = new ArrayList();
    nameValues.Add(friendlyName);
    nameValues.Add(subjectName);
    nameValues.Add(country);
    var subjectDN = new X509Name(nameOids, nameValues);

    // certificate fields
    certGen.SetSerialNumber(BigInteger.ValueOf(1));
    certGen.SetIssuerDN(caCert.SubjectDN);
    certGen.SetNotBefore(validStartDate);
    certGen.SetNotAfter(validEndDate);
    certGen.SetSubjectDN(subjectDN);
    certGen.SetPublicKey(keys.Public);
    certGen.SetSignatureAlgorithm("SHA1withDSA");

    // extended information
    certGen.AddExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(caCert.GetPublicKey()));
    certGen.AddExtension(X509Extensions.SubjectKeyIdentifier, false, new SubjectKeyIdentifierStructure(keys.Public));
    #endregion

    // generate x509 certificate
    var cert = certGen.Generate(caPrivateKey);
    //ert.Verify(caCert.GetPublicKey());

    var chain = new Dictionary<string, Org.BouncyCastle.X509.X509Certificate>();
    //chain.Add("CertiFirmas CA", caCert);
    var caCn = caCert.SubjectDN.GetValues(X509Name.CN)[0].ToString();
    chain.Add(caCn, caCert);

    // store the file
    return GeneratePkcs12(keys, cert, friendlyName, password, chain);
}

private static byte[] GeneratePkcs12(AsymmetricCipherKeyPair keys, Org.BouncyCastle.X509.X509Certificate cert, string friendlyName, string password,
    Dictionary<string, Org.BouncyCastle.X509.X509Certificate> chain)
{
    var chainCerts = new List<X509CertificateEntry>();

    // Create the PKCS12 store
    Pkcs12Store store = new Pkcs12StoreBuilder().Build();

    // Add a Certificate entry
    X509CertificateEntry certEntry = new X509CertificateEntry(cert);
    store.SetCertificateEntry(friendlyName, certEntry); // use DN as the Alias.
    //chainCerts.Add(certEntry);

    // Add chain entries
    var additionalCertsAsBytes = new List<byte[]>();
    if (chain != null && chain.Count > 0)
    {
        foreach (var additionalCert in chain)
        {
            additionalCertsAsBytes.Add(additionalCert.Value.GetEncoded());
        }
    }

    if (chain != null && chain.Count > 0)
    {
        var addicionalCertsAsX09Chain = BuildCertificateChainBC(cert.GetEncoded(), additionalCertsAsBytes);

        foreach (var addCertAsX09 in addicionalCertsAsX09Chain)
        {
            chainCerts.Add(new X509CertificateEntry(addCertAsX09));
        }
    }

    // Add a key entry
    AsymmetricKeyEntry keyEntry = new AsymmetricKeyEntry(keys.Private);

    // no chain
    store.SetKeyEntry(friendlyName, keyEntry, new X509CertificateEntry[] { certEntry });

    using (var memoryStream = new MemoryStream())
    {
        store.Save(memoryStream, password.ToCharArray(), new SecureRandom());
        return memoryStream.ToArray();
    }
}

一些缺失的方法:

static IEnumerable<Org.BouncyCastle.X509.X509Certificate> BuildCertificateChainBC(byte[] primary, IEnumerable<byte[]> additional)
{
    X509CertificateParser parser = new X509CertificateParser();
    PkixCertPathBuilder builder = new PkixCertPathBuilder();

    // Separate root from itermediate
    var intermediateCerts = new List<Org.BouncyCastle.X509.X509Certificate>();
    HashSet rootCerts = new HashSet();

    foreach (byte[] cert in additional)
    {
        var x509Cert = parser.ReadCertificate(cert);

        // Separate root and subordinate certificates
        if (x509Cert.IssuerDN.Equivalent(x509Cert.SubjectDN))
            rootCerts.Add(new TrustAnchor(x509Cert, null));
        else
            intermediateCerts.Add(x509Cert);
    }

    // Create chain for this certificate
    X509CertStoreSelector holder = new X509CertStoreSelector();
    holder.Certificate = parser.ReadCertificate(primary);

    // WITHOUT THIS LINE BUILDER CANNOT BEGIN BUILDING THE CHAIN
    intermediateCerts.Add(holder.Certificate);

    PkixBuilderParameters builderParams = new PkixBuilderParameters(rootCerts, holder);
    builderParams.IsRevocationEnabled = false;

    X509CollectionStoreParameters intermediateStoreParameters =
        new X509CollectionStoreParameters(intermediateCerts);

    builderParams.AddStore(X509StoreFactory.Create(
        "Certificate/Collection", intermediateStoreParameters));

    PkixCertPathBuilderResult result = builder.Build(builderParams);

    return result.CertPath.Certificates.Cast<Org.BouncyCastle.X509.X509Certificate>();
}

private static AsymmetricCipherKeyPair GenerateDsaKeys()
{
    DSACryptoServiceProvider DSA = new DSACryptoServiceProvider();
    var dsaParams = DSA.ExportParameters(true);
    AsymmetricCipherKeyPair keys = DotNetUtilities.GetDsaKeyPair(dsaParams);
    return keys;
}

另外:您必须将您的 CA 证书安装到客户端计算机上的受信任 CA 存储中,以及客户端证书(它可以在个人或第三方存储中).

Also: you have to install you CA certificate into the Trusted CAs store in the client machine, as well as the client certificate (it could be in the Personal or ThirdParty store).

这篇关于如何使用 BouncyCastle 生成根证书,然后生成由该根证书签名的站点证书?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆