2012-10-01 150 views
4

我在尝试构建一个自我托管的服务,使用WebAPISSL,我需要能够自行生成SSL证书才能使用。我希望能够从C#这样做。我一直在玩BouncyCastle如何使用BouncyCastle生成根证书,然后生成由该根证书签名的站点证书?

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

我无法弄清楚如何使我的第二个证书引用我的根ca.我试过的一切都让我感到不可信的证书错误。任何帮助,将不胜感激。

+0

你可以发布你有问题的代码吗? – newfurniturey

回答

8

这就是我所做的(我正在使用DSA,但如果您使用RSA,只需更改密钥生成)。

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存储,以及客户端证书(也可能是在个人或ThirdParty商店)。

+0

我试图把这段代码放在一起。它抱怨BuildCertificateChainBC不存在。 GenerateDsaKeys也是如此。 – user1712714

+0

用该方法更新我的代码。缺少的方法不会做任何特殊的事情,如果需要,可以更改它们:更改RSA的DSA或不创建链。我必须用BouncyCastle课程玩很多东西来理解一些故障。 –

+0

@ ser1712714是否为您工作? –