2016-09-08 11 views
2

acme4jを使用して、暗号化証明書を作成することを選択しました。これまでのところ、完全に機能しているようですが、登録を作成するJavaコードをいくつか持っていて、最終的に私のドメインのx509証明書を(証明書チェーンと共に)提示します。コードは私のJavaアプリケーションにうまく統合されており、証明書の更新のためのダウンタイムは必要ありません。驚くばかり。Java Webサーバーでの暗号化証明書の使用

ここから私はちょっと立ち往生しています。私のアプリケーションは、ちょうどメインアプリであり、私はプログラムでインスタンス化するundertowウェブサーバーが埋め込まれています。 httpsリスナーを作成するには、SSLContextオブジェクトを作成する必要があります。私はそれを再利用することができますので、私はディスクにletsencryptからもらったx509証明書を保存した:

... 
    X509Certificate x509 = cert.download(); 

    Path pemFile = pathTo(domain + ".pem"); 

    try (Writer writer = Files.newBufferedWriter(pemFile); JcaPEMWriter jcaPEMWriter = new JcaPEMWriter(writer)) { 
     jcaPEMWriter.writeObject(x509); 
    } 

そして証明書とすると、引き波のWebサーバーにそれを渡すことを自分のアプリケーションのリロードを起動時に:

CertificateFactory cf = CertificateFactory.getInstance("X.509"); 
    FileInputStream finStream = new FileInputStream(certFile.toFile()); 
    X509Certificate x509Certificate = (X509Certificate)cf.generateCertificate(finStream); 

    KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); 
    keyStore.load(null); 
    keyStore.setCertificateEntry("someAlias", x509Certificate); 

    TrustManagerFactory instance = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); 
    instance.init(keyStore); 

    SSLContext sslContext = SSLContext.getInstance("TLS"); 
    sslContext.init(null, instance.getTrustManagers(), null); 
    SSLContext.setDefault(sslContext); 

    Undertow.Builder builder = Undertow.builder(); 
    builder.addHttpsListener(httpsPort, ipAddress, sslContext); 

Chromeはちょうど_ERR_CONNECTION_CLOSED_が表示されるhttpsエンドポイントを試してみるまで、アプリは起動しますが、エラーや警告は表示されません。私が試してみて起こっていただきました!見に-Djavax.net.debug=allオン:

%% Initialized: [Session-12, SSL_NULL_WITH_NULL_NULL] 
XNIO-1 task-12, fatal error: 40: no cipher suites in common 
javax.net.ssl.SSLHandshakeException: no cipher suites in common 
%% Invalidated: [Session-12, SSL_NULL_WITH_NULL_NULL] 
XNIO-1 task-12, SEND TLSv1.1 ALERT: fatal, description = handshake_failure 
XNIO-1 task-12, WRITE: TLSv1.1 Alert, length = 2 
XNIO-1 I/O-2, fatal: engine already closed. Rethrowing javax.net.ssl.SSLHandshakeException: no cipher suites in common 
XNIO-1 I/O-2, called closeInbound() 
XNIO-1 I/O-2, fatal: engine already closed. Rethrowing javax.net.ssl.SSLException: Inbound closed before receiving peer's close_notify: possible truncation attack? 
2016-09-08 08:34:46,861 DEBUG [io] - UT005013: An IOException occurred 
java.io.IOException: javax.net.ssl.SSLException: Inbound closed before receiving peer's close_notify: possible truncation attack? 

私はここに、純粋なJavaソリューションを思い付くしようとしています。繰り返し可能なコードで、ソースコントロールにテストしてチェックインできるもの。可能であれば、JVM以外のマシンレベルを設定する必要はありません。

多くのハッカーと読書の後で、keytoolと私が発行された証明書チェーンのいくつかの組み合わせと、私が発行された証明書チェーンとルート証明書といくつかの/ none/allの中間letsencryptの証明書!真剣に?

「7.3.1.3。既存の証明書を使用する」セクションの指示hereに従ってみましたが、まったく同じエラーで終了します。

ご協力いただければ幸いです。

答えて

3

(任意の言語の)SSL/TLSサーバーは、証明書だけでなく、プライベートキーと証明書(ほとんどの場合証明書チェーン)を必要とします。 Java SSL/TLSサーバでは、TrustManagerではなくKeyManagerのprivatekey + certchainが必要です.SSL/TLSサーバ用にTrustManagerのみを設定することを推奨するアドバイスはまったく無能です。セクションでは、それは私が見たことがないと私はがほとんど記載されていないのOpenSSL、のほぼすべてのバージョンを使用していたバグを主張するものの、セクション7.3.1.4ものの、意味をなさないへのリンク7.3.1.3正しい方法をOpenSSL key + cert to Javaに変換します。これは、OpenSSL形式のキーと証明書の作成について説明した前のセクションと一致します。しかし、あなたはOpenSSLフォーマットを持っていません。

That acme4j page を正しく使用すると、「キーの別のペアを生成する」必要があると言う - ペアは、プライベートとパブリックの意味 - 以前の「使い方」のページは、CSRを生成し、どのように彼らのKeyPairUtilsをどうするかを語っていると、それを送信し、証明書とチェーンを取得します。1回の呼び出しを指定します。

X509Certificate[] chain = cert.downloadChain() 

LetsEncryptが賢明な場合に必要な機能です。 chain[0].getSubjectX500Principal()を見て、それがあなたのものかどうかを見てください。あなたはおそらく両方download()downloadChain()を行うと、最初にあなたの証明書を1列にそれらを一緒に置く必要がない場合:

X509Certificate[] fixchain = new X509Certificate [chain.length+1]; 
fixchain[0] = mycert; System.arraycopy (chain,0, fixchain,1, chain.length); 
chain = fixchain; // for simplicity 

を使用すると、証明書チェーンとキーペアを持っていたら、

char[] password = /* some value, should be secure if used for file, 
    if used only in memory doesn't really matter */ 
KeyStore ks = KeyStore.getInstance("jks"/*or default if you don't care*/); 
ks.load (null); // above line and this same as you have now 
ks.setKeyEntry ("alias", keypair.getPrivateKey(), password, chain); 
// this line different -- KeyEntry not CertificateEntry 

// if you want to save in a file for reuse 
try(OutputStream os = new FileOutputStream ("blah")){ ks.store (os, password); } 
// if you want to save somewhere else, extrapolate 

// if/when you want to run server 
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); 
kmf.init(ks, password); // same password as above (or when stored) 
// MAYBE TrustManager if you want to require certs FROM CLIENTS 
// in which case the certs you trust probably shouldn't be limited to LetsEncrypt 
SSLContext ctx = SSLContext.getInstance("TLS"; 
ctx.init(kmf.getKeyManagers(), null /*or tmf.getTrustManagers()*/, null); 
SSLContext.setDefault (ctx); // or otherwise use ctx 
ような何かを

証明書が実際に保管して読んでいなければならない場合は、人が&貼り付けなどをしない限り、PEMに変換する必要はありません。Java CertificateFactoryはDERとPEMの両方を少なくとも10年間処理しました。

関連する問題