我试图用Java生成客户端的最终证书。当我尝试使用我回馈给客户端的证书进行身份验证时,我收到了错误消息。错误是:
引起:sun.security.validator.ValidatorException:PKIX路径验证失败:java.security.cert.CertPathValidatorException:Path不与任何信任锚链接 引起:java.security.cert.CertPathValidatorException:Path不与任何信任锚链接
目前有一个openssl实现,它使用这些扩展字段生成最终证书:
#1: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: F4 67 78 E4 40 80 FB FA 43 F3 48 3D 37 66 AC E1 .gx.@...C.H=7f..
0010: 44 3B B5 F1 D;..
]
]
#2: ObjectId: 2.5.29.19 Criticality=false
BasicConstraints:[
CA:false
PathLen: undefined
]
#3: ObjectId: 2.5.29.37 Criticality=false
ExtendedKeyUsages [
clientAuth
]
#4: ObjectId: 2.5.29.15 Criticality=false
KeyUsage [
DigitalSignature
Non_repudiation
Key_Encipherment
]
#5: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 8F A6 A3 23 82 C9 20 2D 16 3E 3B 8E B5 D6 E2 8F ...#.. -.>;.....
0010: EF 85 12 4C ...L
]
]
所以我尝试在我的Java代码中做同样的事情(大部分代码都是我在网上找到的关于BouncyCastle证书生成的东西):
private static void createEndCert() throws Exception {
X500PrivateCredential rootCredential = readRootCredentials();
X500PrivateCredential interCredential = createIntermediateCredential(rootCredential.getPrivateKey(), rootCredential.getCertificate());
X500PrivateCredential endCredential = createEndEntityCredential(interCredential.getPrivateKey(), interCredential.getCertificate());
writePem(endCredential, "end.cert.pem");
}
}
// need to use existing certs and keys
private static X500PrivateCredential readRootCredentials() throws Exception {
File privateKeyFile = new File(System.getProperty("user.dir") + File.separator + "mykey.pem");
PEMParser pemParser = new PEMParser(new FileReader(privateKeyFile));
Object privateKeyInfo = pemParser.readObject();
JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
PrivateKey privateKey = converter.getPrivateKey((PrivateKeyInfo) privateKeyInfo);
CertificateFactory certficateFactory = CertificateFactory.getInstance("X.509");
FileInputStream fileInputStream = new FileInputStream(System.getProperty("user.dir") + File.separator + "mycert.pem");
X509Certificate cer = (X509Certificate) certficateFactory.generateCertificate(fileInputStream);
return new X500PrivateCredential(cer, privateKey, ROOT_ALIAS);
}
public static X500PrivateCredential createIntermediateCredential(PrivateKey caKey, X509Certificate caCert) throws Exception {
KeyPair interPair = generateRSAKeyPair(2048);
X509Certificate interCert = buildIntermediateCert(interPair.getPublic(), caKey, caCert);
return new X500PrivateCredential(interCert, interPair.getPrivate(), INTERMEDIATE_ALIAS);
}
public static X500PrivateCredential createEndEntityCredential(PrivateKey caKey, X509Certificate caCert) throws Exception {
KeyPair endPair = generateRSAKeyPair(2048);
X509Certificate endCert = buildEndEntityCert(endPair.getPublic(), caKey, caCert);
return new X500PrivateCredential(endCert, endPair.getPrivate(), END_ENTITY_ALIAS);
}
public static X509Certificate buildIntermediateCert(PublicKey intKey, PrivateKey caKey, X509Certificate caCert) throws Exception {
X509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(
caCert.getSubjectX500Principal(),
BigInteger.valueOf(1),
new Date(System.currentTimeMillis()),
new Date(System.currentTimeMillis() + VALIDITY_PERIOD),
new X500Principal("CN=Test CA Certificate"),
intKey);
JcaX509ExtensionUtils extensionUtils = new JcaX509ExtensionUtils();
certBuilder.addExtension(Extension.authorityKeyIdentifier, false, extensionUtils.createAuthorityKeyIdentifier(caCert))
.addExtension(Extension.subjectKeyIdentifier, false, extensionUtils.createSubjectKeyIdentifier(intKey))
.addExtension(Extension.basicConstraints, true, new BasicConstraints(0))
.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyCertSign | KeyUsage.cRLSign));
ContentSigner signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider("BC").build(caKey);
return new JcaX509CertificateConverter().setProvider("BC").getCertificate(certBuilder.build(signer));
}
public static X509Certificate buildEndEntityCert(PublicKey entityKey, PrivateKey caKey, X509Certificate caCert) throws Exception {
X509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(
caCert.getSubjectX500Principal(),
BigInteger.valueOf(1),
new Date(System.currentTimeMillis()),
new Date(System.currentTimeMillis() + VALIDITY_PERIOD),
new X500Principal("CN=Test End Entity Certificate"),
entityKey);
JcaX509ExtensionUtils extensionUtils = new JcaX509ExtensionUtils();
certBuilder.addExtension(Extension.authorityKeyIdentifier, false, extensionUtils.createAuthorityKeyIdentifier(caCert))
.addExtension(Extension.subjectKeyIdentifier, false, extensionUtils.createSubjectKeyIdentifier(entityKey))
.addExtension(Extension.basicConstraints, true, new BasicConstraints(false))
.addExtension(Extension.keyUsage, false, new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyEncipherment | KeyUsage.nonRepudiation))
.addExtension(Extension.extendedKeyUsage, false, new ExtendedKeyUsage(KeyPurposeId.id_kp_clientAuth));
ContentSigner signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider("BC").build(caKey);
return new JcaX509CertificateConverter().setProvider("BC").getCertificate(certBuilder.build(signer));
}
public static void writePEM(Object object, String filename) throws IOException {
FileWriter fileWriter = new FileWriter(filename);
JcaPEMWriter jcaPEMWriter = null;
try {
jcaPEMWriter = new JcaPEMWriter(fileWriter);
jcaPEMWriter.writeObject(object);
} finally {
jcaPEMWriter.close();
fileWriter.close();
}
}
和我输出的扩展名如下:
#1: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: 45 62 E9 13 ED 2E 3F 23 A7 A8 F1 B2 DC FE 47 5A Eb....?#......GZ
0010: E3 5E 88 EE .^..
]
[CN=ourcompany.com, OU=OurCompany]
SerialNumber: [ 01]
]
#2: ObjectId: 2.5.29.19 Criticality=false
BasicConstraints:[
CA:false
PathLen: undefined
]
#3: ObjectId: 2.5.29.37 Criticality=false
ExtendedKeyUsages [
clientAuth
]
#4: ObjectId: 2.5.29.15 Criticality=false
KeyUsage [
DigitalSignature
Non_repudiation
Key_Encipherment
]
#5: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 6F C2 81 A9 42 54 DF C2 44 1B 40 B3 A1 DD AF BD o...BT..D.@.....
0010: 87 3D 69 0F .=i.
]
]
我在第1节中看到,我在Java中创建的证书中的数据与openssl中存在的证书中的数据没有该数据。这是我的客户无法进行身份验证的原因吗?或者Java代码中有什么问题可以创建最终的crendential。感谢。