[英]From certificate Alias to PEM File with private key included using Java
I have this code to generate a CER file using the alias: 我有以下代码使用别名生成CER文件:
public class TestFromAliasToCER {
public static final int KEY_SIZE = 1024;
public static final String BEGIN_CERT = "-----BEGIN CERTIFICATE-----";
public static final String END_CERT = "-----END CERTIFICATE-----";
public final static String LINE_SEPARATOR = System.getProperty("line.separator");
public static void main(String[] args) throws FileNotFoundException, IOException, NoSuchAlgorithmException, NoSuchProviderException, KeyStoreException, CertificateException {
KeyStore keyStore = KeyStore.getInstance ("Windows-MY");
keyStore.load (null, null);
Enumeration<String> aux = keyStore.aliases();
String alias = aux.nextElement();
X509Certificate certificate = (X509Certificate) keyStore.getCertificate (alias);
String certString = formatCrtFileContents(certificate);
PrintWriter out = new PrintWriter("cert.CER");
out.println(certString);
out.close();
}
public static String formatCrtFileContents(final Certificate certificate) throws CertificateEncodingException {
final Base64.Encoder encoder = Base64.getMimeEncoder(64, LINE_SEPARATOR.getBytes());
final byte[] rawCrtText = certificate.getEncoded();
final String encodedCertText = new String(encoder.encode(rawCrtText));
final String prettified_cert = BEGIN_CERT + LINE_SEPARATOR + encodedCertText + LINE_SEPARATOR + END_CERT;
return prettified_cert;
}
}
This creates the cer file with 这将创建cer文件
-----BEGIN CERTIFICATE-----
data
-----END CERTIFICATE-----
I want to be able to create a PEM Certificate with the private key included, is it possible? 我希望能够创建一个包含私钥的PEM证书,这可能吗? If not, why?
如果没有,为什么?
I'm not restricted to Java only and free to use any Java API, but preferable with the least user interaction as possible. 我不仅限于Java,而且可以自由使用任何Java API,但最好是尽可能减少用户交互。
Although I don't see it documented, according to the source the SunMSCAPI provider implements only a stub for getEncoded
and cannot export Windows privatekey so you can't do this with JCA. 尽管我没有看到它的文档,但是根据消息来源,SunMSCAPI提供程序仅实现
getEncoded
的存根,并且无法导出Windows私钥,因此您无法使用JCA进行此操作。
You could of course write JNI or JNA to call Windows CAPI, but that's not simple. 您当然可以编写JNI或JNA来调用Windows CAPI,但这并不简单。
To use existing tools without user interaction you can use Runtime
or ProcessBuilder
to 要在没有用户交互的情况下使用现有工具,可以使用
Runtime
或ProcessBuilder
run certutil
with arguments -exportpfx -user -p password certid filename
使用参数
-exportpfx -user -p password certid filename
运行certutil
run powershell
and tell it to select an object in cert:\\currentuser\\my
and invoke the Export('PFX','password')
method -- examples for machine rather than user cert here 运行
powershell
并告诉它在cert:\\currentuser\\my
选择一个对象,然后调用Export('PFX','password')
方法- 这里是计算机而非用户cert的示例
or in (only) recent powershell use Export-PFXCertificate
cmdlet documentation here 或仅在最近
Export-PFXCertificate
使用Export-PFXCertificate
cmdlet 文档在此处
and after any of these, extract from pkcs12 to PEM with openssl pkcs12
, or if you prefer with Java by: 然后,使用
openssl pkcs12
从pkcs12提取到PEM,或者如果您更喜欢Java,则通过以下方式:
load the PKCS12 keystore and get the PrivateKey entry 加载PKCS12密钥库并获取PrivateKey条目
call getEncoded
and encode the result in folded (MIME) base64 like you did for the certificate except use -----BEGIN/END PRIVATE KEY-----
调用
getEncoded
并像使用证书一样将结果编码为折叠(MIME)base64,除了使用-----BEGIN/END PRIVATE KEY-----
Warning: Java produces an unencrypted (PKCS8) privatekey, so make certain no unauthorized user or program ever has access to this file, your disk/filesystem or any backup(s). 警告:Java会生成未加密的(PKCS8)私钥,因此请确保没有未经授权的用户或程序可以访问此文件,您的磁盘/文件系统或任何备份。
A digital certificate doesn't have the private key inside it (the private key is not part of the certificate fields). 数字证书内部没有私钥(私钥不是证书字段的一部分)。 The certificate and the private key are separate entities, although they're related (one can't exist without the other).
证书和私钥是相互独立的实体,尽管它们是相关的 (一个没有另一个就不可能存在)。
If you take a look at the certificate fields in RFC 5280 , you'll see that only the public key is part of it: 如果查看RFC 5280中的证书字段,您会发现只有公钥是其中的一部分:
Certificate ::= SEQUENCE {
tbsCertificate TBSCertificate,
signatureAlgorithm AlgorithmIdentifier,
signatureValue BIT STRING }
TBSCertificate ::= SEQUENCE {
... lots of fields
subjectPublicKeyInfo SubjectPublicKeyInfo,
... lots of other fields
}
The subjectPublicKeyInfo
is the public key, and there's no field for the private key. subjectPublicKeyInfo
是公钥,没有用于私钥的字段。
That's because certificates are meant to be public (you can have more details on why they're public taking a look at how a Public Key Infrastructure works). 这是因为证书本来就是公开的(您可以查看公钥基础结构的工作原理,以了解为什么公开证书的更多详细信息)。
Although the certificate is public, there's always a correspondent private key somewhere, usually held by the certificate's owner (and ideally by no one else). 尽管证书是公开的,但在某处始终有一个对应的私钥,通常由证书的所有者(最好是没有其他人)持有。
Anyway, the file you've got (with BEGIN CERTIFICATE and END CERTIFICATE headers) in only the digital certificate (but not the private key). 无论如何,您获得的文件(带有BEGIN CERTIFICATE和END CERTIFICATE标头)仅存在于数字证书中(而不是私钥中)。
If you have the private key and the corresponding certificate, you can create a file that contains both. 如果您具有私钥和相应的证书,则可以创建一个包含两者的文件。 The most common formats for such file are: JKS (also known as Keystore) and PFX .
此类文件的最常见格式为: JKS (也称为Keystore)和PFX 。
There are also another "format": the Windows repository (the one you're reading when you do KeyStore.getInstance("Windows-MY")
). 还有另一种“格式”:Windows存储库(执行
KeyStore.getInstance("Windows-MY")
时正在读取的存储库)。 I don't know exactly in what format its files are, but the KeyStore
class abstracts it. 我不知道文件的格式是什么,但是
KeyStore
类对其进行了抽象。
If the private key is present, it will be together with its corresponding certificate, in the same alias. 如果存在私钥,则该私钥将与它的相应证书一起使用同一别名。 You can check if the key is present with this code:
您可以使用以下代码检查密钥是否存在:
String alias = aux.nextElement();
if (keyStore.isKeyEntry(alias)) { // alias contains a private key
Key key = keyStore.getKey(alias, "password".toCharArray()); // need to know the password
// key is the private key
// cert is the key's corresponding certificate
X509Certificate cert = (X509Certificate) keyStore.getCertificate(alias);
} else if (keyStore.isCertificateEntry(alias)) { // alias doesn't contain a key
X509Certificate cert = (X509Certificate) keyStore.getCertificate(alias);
}
After having the key, you can save it to another keystore with the following code: 获得密钥后,可以使用以下代码将其保存到另一个密钥库中:
// create another keystore
KeyStore output = KeyStore.getInstance("JKS");
// "alias" - choose to whatever name you want
// privateKey is the object you've got from keyStore.getKey()
// "password" is the password for this alias
// cert will be stored in the same alias
output.setKeyEntry("alias", privateKey, "password".toCharArray(), new Certificate[] { cert });
// save the keystore to a file
output.store(new FileOutputStream("outputfile.jks"), "keystore password".toCharArray());
The code above creates the file outputfile.jks
containing the certificate and the private key. 上面的代码创建包含证书和私钥的文件
outputfile.jks
。
If you want the file to be a PFX , you can change the code above to: 如果您希望文件为PFX ,则可以将上面的代码更改为:
// PKCS12 == PFX format
KeyStore output = KeyStore.getInstance("PKCS12");
// alternative: in pfx, I think that alias can't have specific passwords
// so you can use this as it doesn't require a password for the alias entry
output.setKeyEntry("alias", privateKey.getEncoded(), new Certificate[] { cert });
// change file extension to ".pfx"
output.store(new FileOutputStream("outputfile.pfx"), "keystore password".toCharArray());
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.