简体   繁体   English

从证书别名到带有Java的包含私钥的PEM文件

[英]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 要在没有用户交互的情况下使用现有工具,可以使用RuntimeProcessBuilder

  • 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 CERTIFICATEEND 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.

相关问题 如何使用Java确定用于从.pem文件生成私钥的算法 - how to determine the algorithm used to generate a private key from a .pem file using java 将私钥从pem文件导入密钥库 - Import private key from pem file into keystore 从ASN1加密的pem证书中获取公钥和私钥 - Get public and private key from ASN1 encrypted pem certificate 使用 AWS SDK 为 Java 创建密钥对时创建包含私钥的 file.pem - create a file.pem containing the private key when creating a Key Pair using AWS SDK for Java InvalidKeyException:从Java中的PEM文件读取EC私钥时,密钥格式无效 - InvalidKeyException: invalid key format when reading EC Private Key from PEM file in Java java.security.InvalidKeyException:从PEM文件生成公钥,私钥时无效的密钥格式 - java.security.InvalidKeyException: invalid key format while generating public, private key from PEM file 如何使用Java代码将证书和私钥导出为单个文件? - How to export Certificate and private key as a single file using java code? 将PEM私钥文件转换为JAVA私钥对象 - Converting a PEM private key file to a JAVA PrivateKey Object JAVA:如何使用密码保护将私钥保存在pem文件中 - JAVA: How to save a private key in a pem file with password protection 哪里存储.pem文件(私钥)Android Java - Where to store .pem file (private key) android java
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM