|
~ To be, or not to be, or to think about it tomorrow. ~ 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()のようなブロックする段階で判定すると手遅れなので、 |
|