簡體   English   中英

從證書別名到帶有Java的包含私鑰的PEM文件

[英]From certificate Alias to PEM File with private key included using Java

我有以下代碼使用別名生成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;
    }
}

這將創建cer文件

-----BEGIN CERTIFICATE-----
data
-----END CERTIFICATE-----

我希望能夠創建一個包含私鑰的PEM證書,這可能嗎? 如果沒有,為什么?

我不僅限於Java,而且可以自由使用任何Java API,但最好是盡可能減少用戶交互。

盡管我沒有看到它的文檔,但是根據消息來源,SunMSCAPI提供程序僅實現getEncoded的存根,並且無法導出Windows私鑰,因此您無法使用JCA進行此操作。

您當然可以編寫JNI或JNA來調用Windows CAPI,但這並不簡單。

要在沒有用戶交互的情況下使用現有工具,可以使用RuntimeProcessBuilder

  • 使用參數-exportpfx -user -p password certid filename運行certutil

  • 運行powershell並告訴它在cert:\\currentuser\\my選擇一個對象,然后調用Export('PFX','password')方法- 這里是計算機而非用戶cert的示例

  • 或僅在最近Export-PFXCertificate使用Export-PFXCertificate cmdlet 文檔在此處

然后,使用openssl pkcs12從pkcs12提取到PEM,或者如果您更喜歡Java,則通過以下方式:

  • 加載PKCS12密鑰庫並獲取PrivateKey條目

  • 調用getEncoded並像使用證書一樣將結果編碼為折疊(MIME)base64,除了使用-----BEGIN/END PRIVATE KEY-----

警告:Java會生成未加密的(PKCS8)私鑰,因此請確保沒有未經授權的用戶或程序可以訪問此文件,您的磁盤/文件系統或任何備份。

數字證書內部沒有私鑰(私鑰不是證書字段的一部分)。 證書和私鑰是相互獨立的實體,盡管它們是相關的 (一個沒有另一個就不可能存在)。

如果查看RFC 5280中的證書字段,您會發現只有公鑰是其中的一部分:

Certificate  ::=  SEQUENCE  {
    tbsCertificate       TBSCertificate,
    signatureAlgorithm   AlgorithmIdentifier,
    signatureValue       BIT STRING  }

TBSCertificate  ::=  SEQUENCE  {
      ... lots of fields
    subjectPublicKeyInfo SubjectPublicKeyInfo,
      ... lots of other fields
    }

subjectPublicKeyInfo是公鑰,沒有用於私鑰的字段。

這是因為證書本來就是公開的(您可以查看公鑰基礎結構的工作原理,以了解為什么公開證書的更多詳細信息)。

盡管證書是公開的,但在某處始終有一個對應的私鑰,通常由證書的所有者(最好是沒有其他人)持有。


無論如何,您獲得的文件(帶有BEGIN CERTIFICATEEND CERTIFICATE標頭)僅存在於數字證書中(而不是私鑰中)。

如果您具有私鑰和相應的證書,則可以創建一個包含兩者的文件。 此類文件的最常見格式為: JKS (也稱為Keystore)和PFX

還有另一種“格式”:Windows存儲庫(執行KeyStore.getInstance("Windows-MY")時正在讀取的存儲庫)。 我不知道文件的格式是什么,但是KeyStore類對其進行了抽象。

如果存在私鑰,則該私鑰將與它的相應證書一起使用同一別名。 您可以使用以下代碼檢查密鑰是否存在:

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);
}

獲得密鑰后,可以使用以下代碼將其保存到另一個密鑰庫中:

// 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());

上面的代碼創建包含證書和私鑰的文件outputfile.jks

如果您希望文件為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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM