web-dev-qa-db-ja.com

プレーンな公開キーをJavaキーストアにインポートする方法は?

単一の公開鍵(.pem)をJava鍵ストア(.jks)にインポートしたい。秘密鍵を持っていません。私が理解しているように、公開キーはJavaキーストアにインポートできるように、証明書としてラップする必要があります。

.pemコンテンツは次のようになります。

-----BEGIN PUBLIC KEY-----
key_content....
-----END PUBLIC KEY-----

Javaキーストアにインポートできるように、プレーンな公開鍵を証明書に変換する可能性はありますか?または、公開キーをJavaキーストアにインポートする他のオプションはありますか?

公開鍵を.pemから.derに変換するだけでは十分ではありません。公開鍵は、TLSではなく、プログラムによるデータの暗号化に使用されます。

1
trunkc

標準(または少なくとも従来の)証明書要求プロセスでは、公開鍵と一致する秘密鍵を認証する必要があります。 Javaのkeytoolユーティリティとopensslコマンドラインの事前にパッケージ化された操作は、他のいくつかの既存のQと同様に、この標準プロセスに制限されています。

ただし、基本的には必要ありません。証明書の秘密鍵issuer、名目上は認証局、およびそのCA鍵の証明書、またはそのような証明書に通常埋め込まれている少なくともいくつかの重要なメタデータがある限り、証明書を発行することが可能です。指定された子公開鍵の子証明書。

これは、OpenSSLでカスタムコードからlibcryptoのX509_*ルーチンを呼び出すことで実行できます。 in Java標準keytoolで使用されるクラスは正式にはJRE仕様の一部ではありませんが、オープンソースですが、BouncyCastleサードパーティライブラリ(bcprov + bcpkix )必要な機能を便利で文書化/保証された形式で直接公開しているので、それを示します。これにより、情報がほとんどない非常に最小限の証明書が作成され、特に、実際のCA発行の証明書に一般的に存在する拡張機能は作成されません。これで十分ではない場合は、より完全な質問をしてください。

簡単にするために、名前付きファイルから(サブジェクト)pubkey PEMを読み取り、名前付きエイリアスの名前付きファイル内のJKSからCAキーと証明書を読み取りました。これらの情報源は、必要に応じて他の情報源に置き換えることができます。また、デフォルトのスタックトレースを行うためにJavaを残して、エラー処理を実行していません。必要な場合があります。

import Java.security.*;
import Java.security.cert.X509Certificate;
import Java.security.interfaces.RSAPrivateKey;
import Java.util.Date;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;

static void Se179526FakeCert (String[] args) throws Exception {
    // pubkey.pem cakey.jks pw alias 
    Object spki  = new PEMParser (new FileReader (args[0])).readObject();
    KeyStore ks = KeyStore.getInstance("JKS"); 
    ks.load (new FileInputStream (args[1]), args[2].toCharArray());
    PrivateKey cakey = (PrivateKey) ks.getKey (args[3], args[2].toCharArray());
    X509Certificate cacert = (X509Certificate) ks.getCertificate (args[3]);
    Date now = new Date(), exp = new Date(now.getTime()+30*86400*1000); // 30 days validity

    ContentSigner signer = new JcaContentSignerBuilder ("SHA256with"+cakey.getAlgorithm()).build(cakey);
    byte[] enc = new X509v3CertificateBuilder(
            /*issuer*/new X500Name (cacert.getIssuerX500Principal().getName()), /*serial*/BigInteger.valueOf(now.getTime()),
            /*validity*/now, exp, /*subject*/new X500Name ("CN=dummy"), /*spki*/(SubjectPublicKeyInfo) spki 
        ) .build(signer) .getEncoded();
    // .addExtension's if&as needed before .build
    Certificate cert = CertificateFactory.getInstance ("X.509") .generateCertificate(new ByteArrayInputStream(enc));
    // could now store in a keystore; or to write out in PEM:
    JcaPEMWriter out = new JcaPEMWriter (new OutputStreamWriter (System.out));
    out.writeObject (cert); out.flush(); 
}
3

いいえ、秘密鍵を提供せずに有効な証明書を生成することはできません。証明書が必要な場合は、秘密鍵の所有者が証明書を要求する必要があります。

それ以外の場合は、誰でも自分の選択した公開鍵のドメインの証明書を作成できるため、証明書は意味がありません。

1
John Deters