~ To be, or not to be, or to let it be. ~ null-i.net |
AndroidJava/TCPからSSLへの途中切り替え | |
TCPからSSLへ切り替える(2019-08-12) 概要†STARTTLSとか、接続済みのTCPセッションを「途中から」SSL/TLSに切り替える話です。 ふつう、httpsの通信とかはこんな流れです
そして、メールで使う STARTTLSとか、
この例で始まりの1, 2の部分は平文で(暗号化されていない通信) コードの例†まず、ソースコードから。 // TCPのソケットを作る SocketFactory sf = SocketFactory.getDefault(); Socket tcp_soc = sf.createSocket(host, port); InputStream tcp_in = tcp_soc.getInputStream(); OutputStream tcp_out = tcp_soc.getOutputStream(); // この時点で tcp_in/tcp_out を使って送受信ができるが、 // ここから更に、同じソケットをSSLへと切り替える SSLSocketFactory sf2 = (SSLSocketFactory) SSLSocketFactory.getDefault(); SSLSocket ssl_soc = (SSLSocket)sf2.createSocket( tcp_soc, tcp_soc.getInetAddress().getHostAddress(), tcp_soc.getPort(), true); ssl_soc.startHandshake(); /* 以降、それっぽいSSLの処理を入れる * SSLSession ssl_ses = ssl_soc.getSession(); * InputStream ssl_in = ssl_soc.getInputStream(); * ssl_out = ssl_soc.getOutputStream(); * など */ Androidで上記を実装する場合は、 // TCPから切り替えではなく、直接SSL接続する例 SocketFactory sf = SSLSocketFactory.getDefault(); ssl_soc = (SSLSocket) sf.createSocket(host, port); ここでSocketFactoryを使っているので、勘違いしてTCP〜SSLへの切り替えでも SSLハンドシェイクをTCPソケットでreadしてしまった件†上記の内容を踏まえて、さっそく実装しそこねたのですが、 Failure in SSL library, usually a protocol error これ、たしか以前に別件で TCP接続して送受信する際のイメージとして SocketFactory sf = SocketFactory.getDefault(); tcp_soc = sf.createSocket(host, port); InputStream tcp_in = tcp_soc.getInputStream(); tcp_out = tcp_soc.getOutputStream(); byte[] tmp = new byte[1024]; while(true){ int r_len = tcp_in.read(tmp, 0, 1024); // ここでブロックするので注意 if(r_len<0) break; // 終了の場合 //--- 以下、r_lenサイズ分、tmp から読み取る } //--- 以下、closeしたりする この状態から前述のように、 // クラス変数として boolean is_already_change_to_ssl; を用意しておいて while(true){ if(is_already_change_to_ssl){ // SSLへ変わったかどうか、フラグを別途立てる break; // TCPとしてのスレッドは終了、ただし、 // ソケットやinputStreamは closeしないこと、SSL側で使っているので。 } if( (tcp_soc != null && ! tcp_soc.isClosed() ) // 通信は継続中で、 && tcp_in.available() <= 0 // データ数が0以下ならリトライさせる ){ try{Thread.sleep(100);} // 数字は適当なミリ秒数 catch (Exception e){} //よしなに continue; } int r_len = tcp_in.read(tmp, 0, 1024); // ここでブロックするので注意 // 以下はよしなに // 通常のTCP読み取り後の処理 } 発想としては、read()のようなブロックする段階で判定すると手遅れなので、 |
|