我使用 Java 上的 Bouncy Castle 库制作了 X509 证书。我需要为私钥设置一个密钥属性。
PKCS7 Data
Shrouded Keybag: pbeWithSHA1And3-KeyTripleDES-CBC, Iteration 1024
Bag Attributes
friendlyName: ASDF
localKeyID: XX XX XX XX
Microsoft CSP Name: Microsoft Software Key Storage Provider <--- (1)
Key Attributes: <No Attributes> <--- put HERE X509v3 Key Usage: 80
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----BEGIN ENCRYPTED PRIVATE KEY-----
...
-----END ENCRYPTED PRIVATE KEY-----
我需要将密钥用法设置为 80 --> X509v3 密钥用法:80。因为我使用椭圆曲线,如果没有这些属性,Windows Maquine 就无法识别。
我确实尝试过:
X509v3CertificateBuilder builder = new JcaX509v3CertificateBuilder(
issuerDNName,
serial,
startDate,
endDate,
tX500Name,
pubKey);
X509KeyUsage usage = new X509KeyUsage(X509KeyUsage.digitalSignature);
builder.addExtension(Extension.keyUsage, false, usage);
或者
builder.addExtension(
new ASN1ObjectIdentifier("2.5.29.15"),
true,
new X509KeyUsage(
X509KeyUsage.digitalSignature));
任何方法都行不通。我可以设置一个 Bag 属性 (1),这样:
PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier)privateKey;//pbeWithSHA1And3-KeyTripleDES-CBC
bagAttr.setBagAttribute(
MicrosoftObjectIdentifiers.microsoft.branch("17").branch("1"),// this OID corresponds to: 1.3.6.1.4.1.311.17.1
new DERBMPString("Microsoft Software Key Storage Provider"));
存在一个 PrivateKeyInfo 类,但我不知道如何使用它。
如果我使用 openssl,我需要—密钥签名选项。
openssl pkcs12 -export -in newcert.pem -inkey newreq.pem -name "MY CERTIFICATE" -certfile demoCA/cacert.pem -out mycert.p12 -keysig
OpenSSL文档
-keyex|—密钥签名 指定私钥用于密钥交换或仅用于签名。此选项仅由 MSIE 和类似的 MS 软件解释。通常,“出口级”软件只允许使用 512 位 RSA 密钥进行加密,但允许使用任意长度的密钥进行签名。-keysig 选项标记密钥仅用于签名。仅签名密钥可用于 S/MIME 签名、Authenticode(ActiveX 控件签名)和 SSL 客户端身份验证,但是由于存在错误,只有 MSIE 5.0 及更高版本支持使用仅签名密钥进行 SSL 客户端身份验证。
结果:
PKCS7 Data
Shrouded Keybag: pbeWithSHA1And3-KeyTripleDES-CBC, Iteration 2048
Bag Attributes
localKeyID: XX XX XX XX
friendlyName: ASDF
Microsoft CSP Name: ECDSA_P256#Microsoft Software key Service Provider
Key Attributes
X509v3 Key Usage: 80 <-- This
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----BEGIN ENCRYPTED PRIVATE KEY-----
...
-----END ENCRYPTED PRIVATE KEY-----
谢谢!
答案1
下面给出了带有密钥属性的稍微修改过的 pkcs12 创建代码。
private static void createPKCS12File(String alias, PrivateKey key,
X509Certificate cert, char[] password, OutputStream pfxOut)
throws Exception
{
PrivateKeyInfo pki = PrivateKeyInfo.getInstance(key.getEncoded());
X509KeyUsage usage = new X509KeyUsage(X509KeyUsage.digitalSignature);
DERSet usageSet = new DERSet(usage);
DERSequence attrib = new DERSequence(new ASN1Encodable[]
{new ASN1ObjectIdentifier("2.5.29.15"), usageSet});
pki = new PrivateKeyInfo(pki.getPrivateKeyAlgorithm(),
pki.parsePrivateKey(), new DLSet(attrib));
OutputEncryptor encOut = new JcePKCSPBEOutputEncryptorBuilder(
NISTObjectIdentifiers.id_aes256_CBC).setProvider("BC").build(
password);
PKCS12SafeBagBuilder certBuilder = new JcaPKCS12SafeBagBuilder(
cert);
certBuilder.addBagAttribute(
PKCS12SafeBag.friendlyNameAttribute, new DERBMPString(alias));
JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils();
SubjectKeyIdentifier pubKeyId = extUtils.createSubjectKeyIdentifier(
cert.getPublicKey());
certBuilder.addBagAttribute(PKCS12SafeBag.localKeyIdAttribute,
pubKeyId);
PKCS12SafeBagBuilder keyBagBuilder = new PKCS12SafeBagBuilder(pki,
encOut);
keyBagBuilder.addBagAttribute(PKCS12SafeBag.friendlyNameAttribute,
new DERBMPString(alias));
keyBagBuilder.addBagAttribute(PKCS12SafeBag.localKeyIdAttribute,
pubKeyId);
keyBagBuilder.addBagAttribute(new ASN1ObjectIdentifier(
"1.3.6.1.4.1.311.17.1"),
new DERBMPString("Microsoft Software Key Storage Provider"));
PKCS12PfxPduBuilder builder = new PKCS12PfxPduBuilder();
builder.addData(keyBagBuilder.build());
builder.addEncryptedData(new JcePKCSPBEOutputEncryptorBuilder(
PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC2_CBC).
setProvider("BC").build(password),
new PKCS12SafeBag[]{certBuilder.build()});
PKCS12PfxPdu pfx = builder.build(new JcePKCS12MacCalculatorBuilder(
NISTObjectIdentifiers.id_sha256), password);
pfxOut.write(pfx.getEncoded(ASN1Encoding.DL));
pfxOut.flush();
}