8

私は、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 などの既存のソリューションを使用するなどとは言わないでください。現時点ではオプションではありません。私は自分が間違っていることを理解したいだけです。

前もって感謝します!

4

1 に答える 1

9

NEED_UNWRAP を取得したので、アンラップを行います。これにより、BUFFER_UNDERFLOW が発生する可能性があります。つまり、読み取りを実行してラップ解除を再試行する必要があります。

同様に、NEED_WRAP を取得した場合は、ラップを実行します。これにより、BUFFER_OVERFLOW が発生する可能性があります。これは、書き込みを実行してラップを再試行する必要があることを意味します。

そのラップまたはアンラップは、ラップまたはアンラップという別の操作を行うように指示する場合があります。

指示されたことを実行するだけです。

于 2012-03-07T22:00:32.420 に答える