问题

I've recently been put in charge of mocking up an Apple product (iPhone Configuration Utility) in Java. One of the sections I've been a bit stuck on is a part about Exchange ActiveSync. In there, it allows you to select a certificate from your Keychain to use as credentials for your EAS account. After some research, I found that it's actually creating a PKCS12 keystore, inserting the private key of the certificate I selected, and encoding that into XML. So far not a big deal. If I create a .p12 file with Keychain Access it uploads without a problem. But I run into a problem when I try to bring that over to Java.

Say I export one of those certs that I had used earlier with the .p12 file as a .cer file (this is what we are expecting to get in the environment). Now when I upload it into Java I get a Certificate object as follows...

KeyStore ks = java.security.KeyStore.getInstance("PKCS12");

ks.load(null, "somePassword".toCharArray());

CertificateFactory cf = CertificateFactory.getInstance("X.509", new BouncyCastleProvider());

java.security.cert.Certificate userCert = cf.generateCertificate(new FileInputStream("/Users/me/Desktop/RecentlyExportedCert.cer"));

But when I try...

ks.setCertificateEntry("SomeAlias", userCert);

I get the exception...

java.security.KeyStoreException: TrustedCertEntry not supported

So from certs I move onto keys. But with those Certificates (I got the CA Cert as well), I'm only able to access the public key, not the private. And if I attempt to add the public key like so...

java.security.cert.Certificate[] chain = {CACert};

ks.setKeyEntry("SomeAlias", userCert.getPublicKey().getEncoded(), chain);

I get...

java.security.KeyStoreException: Private key is not stored as PKCS#8 EncryptedPrivateKeyInfo: java.io.IOException: DerValue.getOctetString, not an Octet String: 3

So now I'm here. Does anyone have any idea how to get a private key from a .cer file into a PKCS12 keystore in Java? Am I even on the right track?

Thanks in advance!

回答1:

The PKCS#12 format is intended for storing a private key associated with a certificate chain, and both are required (although you might not need the whole chain).

Although the PKCS12 keystore type does a good job for mapping this format to a Java KeyStore, not everything is supported for this reason.

What you're trying to do in your first attempt is storing a certificate on its own, which won't work.

What you're trying to do in your second attempt (ks.setKeyEntry("SomeAlias", userCert.getPublicKey().getEncoded(), chain)) is to for a public key in place of what should be a private key (see KeyStore#setKeyEntry).

.cer file tend to be just for certificates not private keys (although of course, the extension is ultimately just an indication). If you export your .cer file from Keychain Access.app, you won't get the private key with it (that's what the .p12 export format is for).

EDIT about KeychainStore:

If the reason you're trying to do this conversion is ultimately to access private keys and certificates that are already in the keychain you could load them from the KeychainStore directly:

KeyStore ks = KeyStore.getInstance("KeychainStore", "Apple");

ks.load(null, "-".toCharArray());

A couple of notes for this:

Any non-null, non-empty password will do to use the private key (e.g. "-".toCharArray()), as access will be prompted by the OS's security service (like it would in other applications).

As far as I'm aware, there is still a bug and it only allows access to one private key/certificate pair (even if a number of pairs of private key/certificate pairs are present in the keychain)

回答2:

http://www.docjar.com/html/api/org/bouncycastle/jce/examples/PKCS12Example.java.html

This is how to add a certificate with a associating private key to a PKCS12 keystore.

When you are using client authentication, the keystore needs to contain also the private key, in that case you use KeyStore.getInstance("PKCS12").

When youre not using client authentication but only server authentication(and private key will not be added to keystore, since it belongs to the server), its better to use

KeyStore.getInstance("JKS"), than you can add multiple certificates with an alias to that one keystore.

When you are using PKCS12, as far as I know, you can only add 1 certificate(you have to add the whole certificate chain) associated with the private key, you want to use for that certificate.

回答3:

I'm a couple years late to the party but this took me a few hours to get working correctly,

so I thought it was worth posting a working solution.

This solution uses 1) A .p12 / PKCS12 certificate

and 2) a CA not in the default TrustManager (and you want to add it programatically rather than adding to the default TrustManager). 3) No third party cryptography libraries, just HttpClient to bring it all together.

I've also added a few helpful keytool and openssl commands in the JavaDoc for working with certificates, as that is an art in itself.

// Stitch it all together with HttpClient

CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(getSSLSocketFactory()).build();

private SSLConnectionSocketFactory getSSLSocketFactory() {

try {

SSLContext sslContext = SSLContext.getInstance("TLS");

KeyManager[] keyManager = getKeyManager("pkcs12", "path/to/cert.p12"), "p12_password"));

TrustManager[] trustManager = getTrustManager("jks", "path/to/CA.truststore", "trust_store_password"));

sslContext.init(keyManager, trustManager, new SecureRandom());

return new SSLConnectionSocketFactory(sslContext);

} catch (Exception e) {

throw new RuntimeException("Unable to setup keystore and truststore", e);

}

}

/**

* Some useful commands for looking at the client certificate and private key:

* keytool -keystore certificate.p12 -list -storetype pkcs12 -v

* openssl pkcs12 -info -in certificate.p12

*/

private KeyManager[] getKeyManager(String keyStoreType, String keyStoreFile, String keyStorePassword) throws Exception {

KeyStore keyStore = KeyStore.getInstance(keyStoreType);

KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());

keyStore.load(this.getClass().getClassLoader().getResourceAsStream(keyStoreFile), keyStorePassword.toCharArray());

kmf.init(keyStore, keyStorePassword.toCharArray());

return kmf.getKeyManagers();

}

/**

* Depending on what format (pem / cer / p12) you have received the CA in, you will need to use a combination of openssl and keytool

* to convert it to JKS format in order to be loaded into the truststore using the method below.

*

* You could of course use keytool to import this into the JREs TrustStore - my situation mandated I create it on the fly.

*

* Useful command to look at the CA certificate:

* keytool -keystore root_ca.truststore -list -storetype jks -v

*

*/

private TrustManager[] getTrustManager(String trustStoreType, String trustStoreFile, String trustStorePassword) throws Exception {

KeyStore trustStore = KeyStore.getInstance(trustStoreType);

TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());

trustStore.load(this.getClass().getClassLoader().getResourceAsStream(trustStoreFile), trustStorePassword.toCharArray());

tmf.init(trustStore);

return tmf.getTrustManagers();

}

来源:https://stackoverflow.com/questions/3614239/pkcs12-java-keystore-from-ca-and-user-certificate-in-java

java keystore ca_PKCS12 Java Keystore from CA and User certificate in java相关推荐

  1. JAVA Keytool工具生成Keystore和Truststore文件

    JAVA Keytool工具生成Keystore和Truststore文件 文章目录 JAVA Keytool工具生成Keystore和Truststore文件 生成含有一个私钥的keystore文件 ...

  2. 鸿蒙应用开发DevEco运行时出现java.io.IOException: Invalid keystore format

    Failed to load signer "signer #1" java.io.IOException: Invalid keystore format 开发鸿蒙系统组件时新建 ...

  3. 使用jks文件,本地运行没问题,打包到服务器出现java.io.IOException: Invalid keystore format

    错误信息: java.io.IOException: Invalid keystore formatat sun.security.provider.JavaKeyStore.engineLoad(J ...

  4. java keystore ca_简述keystore是什么?

    Keytool是一个Java数据证书的管理工具 ,Keytool将密钥(key)和证书(certificates)存在一个称为keystore的文件中. 在keystore里,包含两种数据: 密钥实体 ...

  5. Java 证书pem转KeyStore、jks文件

    一.服务端pem转KeyStore CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509 ...

  6. Java对PDF进行电子签章CA签名认证

    什么是CA? CA是认证中心的英文Certification Authority的缩写.它为电子商务环境中各个实体颁发数字证书,以证明各实体身份的真实性,并负责在交易中检验和管理证书:它是电子商务和网 ...

  7. Java实现自签名证书,CA颁发证书

    产生证书库,并创建CA    X500Name 就是你的个人信息了,查查JAVA API 就行了 import java.io.File; import java.io.FileInputStream ...

  8. Java与es8实战之二:Springboot集成es8的Java Client

    1. 导入依赖 <dependency><groupId>co.elastic.clients</groupId><artifactId>elastic ...

  9. java getiotype_坑爹微信之读取PKCS12流时出现的java.io.IOException: DerInputStream.getLength...

    背景 微信退款接口需要使用到证书,我参考微信的官方Demo进行,部分代码如下: char[] password = config.getMchID().toCharArray(); InputStre ...

最新文章

  1. Multisim 12.0 笔记
  2. 5月书讯:阳光穿过银杏树
  3. Unity开发NGUI代码实现ScrollView(放大视图)
  4. 企业微信的corpsecret在哪里?
  5. SQL语言之DQL语言学习(八)多表查询/链接查询 SQL92学习
  6. SpringBoot整合Spring Security——第三章异常处理
  7. 1万条数据大概占多大空间_「数据分析」Sqlserver的窗口函数的精彩应用之数据差距与数据岛...
  8. 解决linux vi报错 Can‘t open file for writing
  9. forth day ---内置函数、匿名函数
  10. 对waitpid 的学习
  11. 将重复数据删除技术应用于数据复制过程 分享修改删除
  12. 深入解读Linux进程调度系列(8)——调度与cgroup
  13. Android tips(十)--允许模拟位置在Android M下的坑
  14. ( 方框打勾 java_Java 11手册:Java 11是否在所有正确的方框中打勾?
  15. 暴走湖北五城,聊聊我的湖北印象
  16. oracle卸数的perl脚本,卸载cpan安装的所有perl模块
  17. 【OpenStack(Train版)安装部署(十六)】之Nova的API测试,报错处理
  18. #三、回测试验给我们的启示
  19. 全面解析NFT的流动性问题与解决方案
  20. android 动态渐变,Android 动态修改渐变 GradientDrawable

热门文章

  1. git如何选择性合并_小姐姐用 10 张动图,教会你 Git 命令使用
  2. python中elif和while简单介绍及注意事项(含笔记)
  3. 计算机简单故障时的排除方法,电脑简单故障排除解决办法大全
  4. java自定义标签简单_JSP 自定义标签之一 简单实例
  5. 熟悉linux运行环境,实验一 熟悉Ubuntu环境
  6. python写名片管理系统_Python实现名片管理系统
  7. Spring Boot 2.3.0 发布
  8. 2016,你最不应该错过的热门技术文章
  9. 论文浅尝 | 从知识图谱流中学习时序规则
  10. 2020国内互联网公司的开源项目及Github地址部分汇总