2012-01-20 11 views
3

以下のMSDN:Asynchronous Socketのサンプルプログラムを見ました。私はプログラムを試して正常に実行しました。 TLS/SSLをサポートするために非同期ソケットを変更することは可能ですか?どうやってするの?TLS/SSLを使用した非同期ソケット

using System; 
using System.Net; 
using System.Net.Sockets; 
using System.Text; 
using System.Threading; 

// State object for reading client data asynchronously 
public class StateObject { 
    // Client socket. 
    public Socket workSocket = null; 

    // Size of receive buffer. 
    public const int BufferSize = 1024; 

    // Receive buffer. 
    public byte[] buffer = new byte[BufferSize]; 

    // Received data string. 
    public StringBuilder sb = new StringBuilder(); 
} 

public class AsynchronousSocketListener { 
    // Thread signal. 
    public static ManualResetEvent allDone = new ManualResetEvent(false); 

    public static void StartListening() { 
     // Data buffer for incoming data. 
     byte[] bytes = new Byte[1024]; 

     // Establish the local endpoint for the socket. 
     // The DNS name of the computer 
     // running the listener is "host.contoso.com". 
     IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName()); 
     IPAddress ipAddress = ipHostInfo.AddressList[0]; 
     IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000); 

     // Create a TCP/IP socket. 
     Socket listener = new Socket(AddressFamily.InterNetwork, 
     SocketType.Stream, ProtocolType.Tcp); 

     // Bind the socket to the local endpoint and listen for incoming connections. 
     try { 
      listener.Bind(localEndPoint); 
      listener.Listen(100); 

      while (true) { 
       // Set the event to nonsignaled state. 
       allDone.Reset(); 

       // Start an asynchronous socket to listen for connections. 
       Console.WriteLine("Waiting for a connection..."); 

       listener.BeginAccept(new AsyncCallback(AcceptCallback), listener); 

       // Wait until a connection is made before continuing. 
       allDone.WaitOne(); 
      } 
     } 
     catch (Exception e) { 
      Console.WriteLine(e.ToString()); 
     } 

     Console.WriteLine("\nPress ENTER to continue..."); 
     Console.Read();  
    } 

    public static void AcceptCallback(IAsyncResult ar) { 
     // Signal the main thread to continue. 
     allDone.Set(); 

     // Get the socket that handles the client request. 
     Socket listener = (Socket) ar.AsyncState; 
     Socket handler = listener.EndAccept(ar); 

     // Create the state object. 
     StateObject state = new StateObject(); 
     state.workSocket = handler; 
     handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, 
     new AsyncCallback(ReadCallback), state); 
    } 

    public static void ReadCallback(IAsyncResult ar) { 
     String content = String.Empty; 

     // Retrieve the state object and the handler socket 
     // from the asynchronous state object. 
     StateObject state = (StateObject) ar.AsyncState; 
     Socket handler = state.workSocket; 

     // Read data from the client socket. 
     int bytesRead = handler.EndReceive(ar); 

     if (bytesRead > 0) { 
      // There might be more data, so store the data received so far. 
      state.sb.Append(Encoding.ASCII.GetString(
      state.buffer,0,bytesRead)); 

      // Check for end-of-file tag. If it is not there, read 
      // more data. 
      content = state.sb.ToString(); 
      if (content.IndexOf("<EOF>") > -1) { 
       // All the data has been read from the 
       // client. Display it on the console. 
       Console.WriteLine("Read {0} bytes from socket. \n Data : {1}", 
       content.Length, content); 
       // Echo the data back to the client. 
       Send(handler, content); 
      } 
      else { 
       // Not all data received. Get more. 
       handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, 
       new AsyncCallback(ReadCallback), state); 
      } 
     } 
    } 

    private static void Send(Socket handler, String data) { 
     // Convert the string data to byte data using ASCII encoding. 
     byte[] byteData = Encoding.ASCII.GetBytes(data); 

     // Begin sending the data to the remote device. 
     handler.BeginSend(byteData, 0, byteData.Length, 0, 
     new AsyncCallback(SendCallback), handler); 
    } 

    private static void SendCallback(IAsyncResult ar) { 
     try { 
      // Retrieve the socket from the state object. 
      Socket handler = (Socket) ar.AsyncState; 

      // Complete sending the data to the remote device. 
      int bytesSent = handler.EndSend(ar); 
      Console.WriteLine("Sent {0} bytes to client.", bytesSent); 

      handler.Shutdown(SocketShutdown.Both); 
      handler.Close(); 

     } 
     catch (Exception e) { 
      Console.WriteLine(e.ToString()); 
     } 
    } 


    public static int Main(String[] args) { 
     StartListening(); 
     return 0; 
    } 
} 

答えて

1

C#でそれを行う方法がわからが、それはin Java using the SSLEngineを行うことができるわけではありません。このAPIは一般的にプログラムするのが難しいと認められています。ですから、SSL/TLS用の非同期ソケットを使用することは可能ですが、JavaのSSLEngineと同等のものはわかりません。おそらくC#にはこれのための別の(より良い?)APIがあります。

あなたは、ほぼ必然的に(Javaの経験に基づいていますが、これはC#でも同様に適用される)、このパスに沿って遭遇するいくつかの問題があります。SSLSocket sがと同様に振る舞うで公正な仕事をする傾向があるが

は、通常Socketの場合、SSL/TLSの性質上、わずかなエッジケースがあります。非同期I/Oでは、これらの相違の影響がさらに重要になります。これらの問題のいくつかは、this (rather long) answer to "Properly closing SSLSocket" (in Java)に記載されています。

さらに、一部のSSL/TLSビヘイビアは、アプリケーションレイヤーに関してはあまり定義されておらず、非同期動作で少し混乱しています。クライアント証明書の再交渉(または再交渉)を念頭に置いています。 SSL/TLSを使用すると、いずれの当事者も原則として再交渉ハンドシェイクを開始することができます。たとえば、Apache Httpdでクライアント証明書で1つのディレクトリのみを保護する場合、またはWebアプリケーションの一部だけがJavaコンテナ内にCLIENT-CERTを必要とする場合にこれを行います。クライアント証明書認証を使用する場合、IISでも既定で再ネゴシエーションが使用されます。これは、SSL/TLS接続の間にセカンドハンドシェイクを実行することから成ります(実際にクライアントからより多くの情報を得るには、そのクライアント証明書です)。

それが(通常はI/Oをブロックすると)働く

は、トラフィックはこのようになります(ここでは両方 SSLHTTP層):

C->S SSL Client Hello 
S->C SSL Server Hello, Certificate, Server Hello Done 
C->S SSL Client Key Exchange, Change Cipher Spec, Finished 
S->C SSL Change Cipher Spec 
(then encrypted) 
C->S SSL Finished 
C->S HTTP GET /.../ 
S->C SSL Hello Request 
C->S SSL Client Hello 
S->C SSL Server Hello, Certificate, Certificate Request, Server Hello Done 
C->S SSL Certificate, Client Key Exchange, Certificate Verify, Change Cipher 
Spec, Finished 
S->C SSL Change Cipher Spec 
C->S SSL Finished 
S->C HTTP 200 OK 

再交渉非同期モードでは、再以来、かなりトリッキーです同時に、トラフィックの両側にネゴシエーションを適用する必要があります。したがって、SSL/TLSセッションの基礎となるプロパティは、アプリケーションレイヤ(通常これを処理することは期待されていません)によって使用中に変更される可能性があります。一方の側では、特定のSSL/TLS設定を前提としてデータを送信している可能性がありますが、再ネゴシエーションが発生し、両者に影響します。

たとえば、このGrizzly issueに示すように、このすべての実装は難しい場合があります。

+0

ありがとうbruno、C#はSSLEngineをサポートしていません。非同期を組み合わせてSSLStreamを使用しようとしましたが、まだバグがあります。 –

+0

@JavaneseGirl、確かに、私がはっきりしない場合は申し訳ありません。私はそれが一般的に可能だと言っていましたが、あなたは 'SSLEngine'に似た何かが必​​要になるでしょう(私はあなたがサードパーティのライブラリを必要とするかもしれません)。 'SSLEngine'(Javaで)は実際のSSL/TLSの仕事のほとんどを行いますが、' wrap'/unwrap(いつものdocを参照してください)には、特に非同期モードでかなり手作業が必要です。正直言って、私は 'SSLStream'が何か類似のものをサポートしているかどうか分かりませんが、(特に私が言及した理論的な問題のために)プログラムが簡単であるとは想像できません。 – Bruno

+0

@JavaneseGirl私の答えを受け入れてくれてありがとう。あなたは比較的新しいユーザーだと思われます。だから、それは尋ねる人に答えを受け入れることを奨励していますが、そうすべき迅速な対応を強いられる気にはなりません。私の答えは不完全で(C#の解決策が欠けていた)、長い間開いておくことでより良い回答を得るかもしれません。 – Bruno

0

直接ソケット通信は、セッション OSIモデル層で動作します。 TLSとSSLはプレゼンテーションレイヤー(はセッションよりも高い)で動作します。 AFAIKでは、ソケットを直接使用することはできず、SSLまたはTLSレベルのセキュリティを持つことはできません。

Check out the OSI Model

+3

SSL/TLSの設計の目標の1つは、既存のセッション層の上に「セッション層」をエミュレートすることでした(トップセーフの1つにする)。これは、とにかくTCPソケットについて話しているときに、OSIモデルに直接飛び込むことは正しくないと言われています。 TCP/IPモデルは厳格ではありません。あなたがリンクしているウィキペディアのページにこれに関するセクションがあります。 – Bruno

+0

ありがとうブルーノ、私はそれをチェックします。 –

0

渡って走った、SslStreamクラスを使用しました。 .NETにSSLクライアント/サーバーを構築するために必要なものはすべてあります。非常に簡単に統合することができます。すべてのバージョンの.NETで動作します。

関連する問題