私は、SSL メッセージと非 SSL メッセージを同じポートで処理できるカスタム/スタンドアロン Java Web サーバーを実装する任務を負っています。
私はNIOサーバーを実装しましたが、非SSLリクエストに対しては非常にうまく機能しています。私はSSLの部分でかなりの時間を過ごしており、実際にいくつかのガイダンスを使用することができます.
これが私がこれまでに行ったことです。
SSL メッセージと非 SSL メッセージを区別するために、インバウンド要求の最初のバイトをチェックして、それが SSL/TLS メッセージかどうかを確認します。例:
byte a = read(buf);
if (totalBytesRead==1 && (a>19 && a<25)){
parseTLS(buf);
}
parseTLS() メソッドでは、次のように SSLEngine をインスタンス化します。
java.security.KeyStore ks = java.security.KeyStore.getInstance("JKS");
java.security.KeyStore ts = java.security.KeyStore.getInstance("JKS");
ks.load(new java.io.FileInputStream(keyStoreFile), passphrase);
ts.load(new java.io.FileInputStream(trustStoreFile), passphrase);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, passphrase);
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(ts);
SSLContext sslc = SSLContext.getInstance("TLS");
sslc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
SSLEngine serverEngine = sslc.createSSLEngine();
serverEngine.setUseClientMode(false);
serverEngine.setEnableSessionCreation(true);
serverEngine.setWantClientAuth(true);
SSLEngine がインスタンス化されたら、公式のJSSE サンプルからそのままコードを使用して、unwrap/wrap メソッドを使用してインバウンド データを処理します。
log("----");
serverResult = serverEngine.unwrap(inNetData, inAppData);
log("server unwrap: ", serverResult);
runDelegatedTasks(serverResult, serverEngine);
log("----");
serverResult = serverEngine.wrap(outAppData, outNetData);
log("server wrap: ", serverResult);
runDelegatedTasks(serverResult, serverEngine);
ハンドシェイクの最初の部分はうまく機能しているようです。クライアントはハンドシェイク メッセージを送信し、サーバーは 4 つのレコードを含むメッセージで応答します。
handshake (22)
- server_hello (2)
- certificate (11)
- server_key_exchange (12)
- certificate_request (13)
- server_hello_done (14)
次に、クライアントは次の 3 つの部分からなるメッセージを送信します。
handshake (22)
- certificate (11)
- client_key_exchange (16)
change_cipher_spec (20)
- client_hello (1)
handshake (22)
*** Encrypted Message ****
SSLEngine はクライアント リクエストをアンラップしてレコードを解析しますが、ラップ メソッドは OK/NEED_UNWRAP のハンドシェイク ステータスで 0 バイトを生成します。つまり、私がクライアントに送り返すものは何もなく、握手は金切り声で停止します。
これは私が立ち往生しているところです。
デバッガーで、SSLEngine、特に ServerHandshaker がピア証明書を見つけられないことがわかります。これは、長さが 0 バイトのクライアントからの証明書レコードを見ると明らかです。しかし、なぜ?
HelloServer の応答に何か問題があるとしか思えませんが、それを特定することはできません。サーバーは有効な証明書を送信しているようですが、クライアントは何も返していません。キーストアに問題はありますか? それともトラストストアですか?それとも、SSLEngine をインスタンス化する方法と関係がありますか? 私は困惑しています。
他のポイントを結合します。
- 上記のコード スニピットで参照されているキーストアとトラストストアは、次のチュートリアルを使用して作成されました: http://www.techbrainwave.com/?p=953
- サーバーをテストするクライアントとして Firefox 10 と IE 9 を使用しています。両方の Web クライアントで同じ結果が得られます。
- Sun/Oracle JDK 6 と、それにバンドルされている Java Secure Socket Extension (JSSE) を使用しています。
アドバイスをお待ちしておりますが、私が頭がおかしいとか、Netty や Grizzly などの既存のソリューションを使用するなどとは言わないでください。現時点ではオプションではありません。私は自分が間違っていることを理解したいだけです。
前もって感謝します!