我需要一些帮助来生成带有弹力城堡的PKCS12 pfx文件。
我正在使用休闲命令来生成PKCS12 pfx文件:
keytool -genkey -storetype PKCS12 -dname "CN=%CN, OU=%OU, O=Company, L=City, ST=State, C=US" -alias clientcert -keyalg RSA -keysize 2048 -keystore %keystore_name% -storepass %default_keystore_pwd% -keypass %default_keystore_pwd%
将ca.crt导入为根用户
keytool -import -trustcacerts -noprompt -alias root -file ca.crt -keystore %keystore_name% -storepass %default_keystore_pwd%
ca.crt 是用于签署生成的CSR的根证书
keytool -certreq -alias clientcert -keystore %keystore_name% -file clientcert.csr -keypass %default_keystore_pwd% -storepass %default_keystore_pwd%
这时我得到CSR,该CSR是通过 ca.crt
在专用服务器上签名的然后我将签名证书导入pfx:
keytool -import -alias clientcert -file signed.crt -keystore %keystore_name% -storepass %default_keystore_pwd% -keypass %default_keystore_pwd%
使用bouncycastle库,我正在创建CSR和私钥。然后,我用ca.crt在服务器上签署了CSR。
最终文件夹中有3个文件:
使用命令,我提供了更早的最终pfx文件,提取后如下所示:
keytool -list -rfc -keystore client_keystore.pfx
Enter keystore password:
Keystore type: jks
Keystore provider: SUN
Your keystore contains 2 entries
Alias name: clientcert
Creation date: Mar 22, 2019
Entry type: PrivateKeyEntry
Certificate chain length: 2
Certificate[1]:
-----BEGIN CERTIFICATE-----
//removed
-----END CERTIFICATE-----
Certificate[2]:
-----BEGIN CERTIFICATE-----
//removed
-----END CERTIFICATE-----
*******************************************
*******************************************
Alias name: root
Creation date: Apr 3, 2019
Entry type: trustedCertEntry
-----BEGIN CERTIFICATE-----
//removed
-----END CERTIFICATE-----
*******************************************
*******************************************
我已经签署了ca.crt,certificate.crt和private.key。 如何使用Bouncycastle库创建相同结构的pfx文件?
生成CSR和密钥:
public void TDE(string CName, string OUnit, string Country, string State, string City, string EmailAdr, string password)
{
AsymmetricCipherKeyPair pair;
Pkcs10CertificationRequest csr;
Asn1SignatureFactory signatureFactory;
var random = new SecureRandom(new CryptoApiRandomGenerator());
var values = new Dictionary<DerObjectIdentifier, string>
{
{X509Name.CN, CName},
{X509Name.OU, OUnit},
{X509Name.O, "Company"},
{X509Name.L, City},
{X509Name.ST, State},
{X509Name.C, Country},
{X509Name.EmailAddress, EmailAdr },
};
var extensions = new Dictionary<DerObjectIdentifier, X509Extension>()
{
{X509Extensions.BasicConstraints, new X509Extension(true, new DerOctetString(new BasicConstraints(false)))},
{X509Extensions.KeyUsage, new X509Extension(true, new DerOctetString(new KeyUsage(KeyUsage.DigitalSignature | KeyUsage.KeyEncipherment | KeyUsage.DataEncipherment | KeyUsage.NonRepudiation)))},
{X509Extensions.ExtendedKeyUsage, new X509Extension(false, new DerOctetString(new ExtendedKeyUsage(KeyPurposeID.IdKPServerAuth, KeyPurposeID.IdKPClientAuth)))},
};
var subject = new X509Name(values.Keys.Reverse().ToList(), values);
var gen = new RsaKeyPairGenerator();
gen.Init(new KeyGenerationParameters(random, 2048));
pair = gen.GenerateKeyPair();
signatureFactory = new Asn1SignatureFactory("SHA256withRSA", pair.Private);
extensions.Add(X509Extensions.SubjectKeyIdentifier, new X509Extension(false, new DerOctetString(new SubjectKeyIdentifierStructure(pair.Public))));
csr = new Pkcs10CertificationRequest(signatureFactory, subject, pair.Public, new DerSet(new AttributePkcs(PkcsObjectIdentifiers.Pkcs9AtExtensionRequest, new DerSet(new X509Extensions(extensions)))), pair.Private);
//Convert BouncyCastle csr to .PEM file.
var csrPem = new StringBuilder();
var csrPemWriter = new PemWriter(new StringWriter(csrPem));
csrPemWriter.WriteObject(csr);
csrPemWriter.Writer.Flush();
//Writes password to file
Directory.CreateDirectory(Environment.CurrentDirectory + "\\" + CName + "_" + OUnit);
File.AppendAllText(Environment.CurrentDirectory + "\\" + CName + "_" + OUnit + "\\key_password.txt", password);
//writes CSR to file
File.AppendAllText(Environment.CurrentDirectory + "\\" + CName + "_" + OUnit + "\\" + CName + "_csr", csrPem.ToString());
//Convert BouncyCastle Private Key to .PEM file.
var privateKeyPem = new StringBuilder();
var privateKeyPemWriter = new PemWriter(new StringWriter(privateKeyPem));
privateKeyPemWriter.WriteObject(pair.Private);
privateKeyPemWriter.Writer.Flush();
//privateKeyPem.ToString();
File.AppendAllText(Environment.CurrentDirectory + "\\" + CName + "_" + OUnit + "\\" + CName + "_" + OUnit + "_prvNE.key", privateKeyPem.ToString());
}
谢谢
答案 0 :(得分:0)
这个问题花了比我诚实的预期更长的时间来解决。显然,有多种方法可以使用各种方法来导出PFX或P12二进制格式,但是为了简单起见,我将使用BouncyCastle库。
首先,我使用的是克里斯托弗(Cristoph)的答案,您可以在https://stackoverflow.com/a/44798441/5797504处找到链接。本质上,它使用的是Pkcs12StoreBuilder
,它很干净而且很整洁,还使用了MemoryStream
,我不知道为什么,但是无论如何我还是会用它。
其次,我修改了答案以适应证书链和其他一些显而易见的事情。
最重要的部分是创建X509CertificateEntry[]
的数组,并从主证书/最终证书,中间CA(sub-CA)一直到根CA证书创建证书链。该数组将需要放入SetKeyEntry
方法参数中。
// create chain certificate
var rootCert = DotNetUtilities.FromX509Certificate(rootCA);
var endCert = DotNetUtilities.FromX509Certificate(x509Cert);
X509CertificateEntry[] chains = new X509CertificateEntry[2];
chains[0] = new X509CertificateEntry(endCert);
chains[1] = new X509CertificateEntry(rootCert);
////....
store.SetKeyEntry(commonName, new AsymmetricKeyEntry(privateKey), chains);
以下部分显示了有关如何创建PKCS12文件(无论是PFX文件还是P12文件)的完整方法。
如果要归功于克里斯托夫(Cristoph)作为原作者,我会给予荣誉。
public static byte[] CreatePkcs12File(X509Certificate2 x509Cert, X509Certificate2 rootCA, AsymmetricKeyParameter privateKey, string passphrase)
{
// create store entry
string commonName = x509Cert.GetNameInfo(X509NameType.SimpleName, false);
// create chain certificate
var rootCert = DotNetUtilities.FromX509Certificate(rootCA);
var endCert = DotNetUtilities.FromX509Certificate(x509Cert);
X509CertificateEntry[] chains = new X509CertificateEntry[2];
chains[0] = new X509CertificateEntry(endCert);
chains[1] = new X509CertificateEntry(rootCert);
// create certificate entry
var certEntry = new X509CertificateEntry(endCert);
string friendlyName = endCert.SubjectDN.ToString();
// get bytes of private key.
PrivateKeyInfo keyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(privateKey);
byte[] keyBytes = keyInfo.ToAsn1Object().GetEncoded();
var builder = new Pkcs12StoreBuilder();
builder.SetUseDerEncoding(true);
var store = builder.Build();
store.SetKeyEntry(commonName, new AsymmetricKeyEntry(privateKey), chains);
byte[] pfxBytes = null;
var password = passphrase;
using (MemoryStream stream = new MemoryStream())
{
store.Save(stream, password.ToCharArray(), new SecureRandom());
pfxBytes = stream.ToArray();
}
var result = Pkcs12Utilities.ConvertToDefiniteLength(pfxBytes);
return result;
}