我想到了。问题在于X509证书本身是不够的。我还需要将私钥放入动态生成的密钥库中。看来BouncyCastle
PEMReader不能一次性处理带有证书和私钥的PEM文件,但它可以分别处理每个文件。我可以自己将PEM读取到内存中,并将其分成两个单独的流,然后将每个输入到一个单独的PEMReader。因为我知道我要处理的PEM文件将首先具有证书,然后具有私钥,所以我可以以健壮性为代价来简化代码。我也知道END
CERTIFICATE分隔符将始终被五个连字符包围。对我有用的实现是:
protected static SSLSocketFactory getSocketFactoryPEM(String pemPath) throws Exception { Security.addProvider(new BouncyCastleProvider()); SSLContext context = SSLContext.getInstance("TLS"); byte[] certAndKey = fileToBytes(new File(pemPath)); String delimiter = "-----END CERTIFICATE-----"; String[] tokens = new String(certAndKey).split(delimiter); byte[] certBytes = tokens[0].concat(delimiter).getBytes(); byte[] keyBytes = tokens[1].getBytes(); PEMReader reader; reader = new PEMReader(new InputStreamReader(new ByteArrayInputStream(certBytes))); X509Certificate cert = (X509Certificate)reader.readObject(); reader = new PEMReader(new InputStreamReader(new ByteArrayInputStream(keyBytes))); PrivateKey key = (PrivateKey)reader.readObject(); KeyStore keystore = KeyStore.getInstance("JKS"); keystore.load(null); keystore.setCertificateEntry("cert-alias", cert); keystore.setKeyEntry("key-alias", key, "changeit".toCharArray(), new Certificate[] {cert}); KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); kmf.init(keystore, "changeit".toCharArray()); KeyManager[] km = kmf.getKeyManagers(); context.init(km, null, null); return context.getSocketFactory();}更新 :似乎可以在没有BouncyCastle的情况下完成:
byte[] certAndKey = fileToBytes(new File(pemPath)); byte[] certBytes = parseDERFromPEM(certAndKey, "-----BEGIN CERTIFICATE-----", "-----END CERTIFICATE-----"); byte[] keyBytes = parseDERFromPEM(certAndKey, "-----BEGIN PRIVATE KEY-----", "-----END PRIVATE KEY-----"); X509Certificate cert = generateCertificateFromDER(certBytes); RSAPrivateKey key = generatePrivateKeyFromDER(keyBytes);
…
protected static byte[] parseDERFromPEM(byte[] pem, String beginDelimiter, String endDelimiter) { String data = new String(pem); String[] tokens = data.split(beginDelimiter); tokens = tokens[1].split(endDelimiter); return DatatypeConverter.parsebase64Binary(tokens[0]); }protected static RSAPrivateKey generatePrivateKeyFromDER(byte[] keyBytes) throws InvalidKeySpecException, NoSuchAlgorithmException { PKCS8EnpredKeySpec spec = new PKCS8EnpredKeySpec(keyBytes); KeyFactory factory = KeyFactory.getInstance("RSA"); return (RSAPrivateKey)factory.generatePrivate(spec); }protected static X509Certificate generateCertificateFromDER(byte[] certBytes) throws CertificateException { CertificateFactory factory = CertificateFactory.getInstance("X.509"); return (X509Certificate)factory.generateCertificate(new ByteArrayInputStream(certBytes)); }


