boost::asioで簡単SSL通信

SSLって何?

  • なんか暗号化するやつやろ
  • 認証がどーのこーの
  • 安全っぽい

っちゅう人向けに、とりあえずSSLの簡単な解説から。
通信、認証の手順はググればようけ出てくるからパスで。

OSI参照モデルとIP、TCPのパケット構成を知ってたらSSLは簡単

IPパケットの構成:IPヘッダー+TCPパケット
TCPパケットの構成:TCPヘッダー+上位層で作られたデータ


上位層で作られたデータっちゅうのは、
HTTPとかFTPでクライアントがサーバーにデータを送信する例やと
コマンドのことやと思ってもらったらええかな。


普通はアプリケーション層で作られたデータを指すわけやけど、
SSL通信やとアプリケーション層とトランスポート層の間にある
セッション層でデータを暗号化するだけ。


つまり、
(非SSLTCPパケットの構成:TCPヘッダー+上位層で作られたデータ
SSLTCPパケットの構成:TCPヘッダー+上位層で作られたデータを暗号化したもの
これだけの話。

さて本題

boost::asioでSSLクライアントを実装してみる。
どんな時に使えるかっちゅうと、ブラウザみたいなHTTPクライアントを作る時とか、
メーラーを作る時とか、FTPクライアントを作る時とかに、SSL通信に対応させたい場合。
いわゆるHTTPSとか、SMTP over SSLとか、FTPSってやつ。

まずはboost::asioでHTTP通信

#include <iostream>
#include <boost/asio.hpp>

int main() {
    try {
        // ネットワークI/O用
        boost::asio::io_service io_service;
        // ネームサーバーに問い合わせて名前解決してくれる
        boost::asio::ip::tcp::resolver resolver( io_service );
        // リゾルバにお願いする内容
        boost::asio::ip::tcp::resolver::query query( "xxx.com", "http" );
        // リゾルバにお願いして見つかったホスト(複数あるかも)
        boost::asio::ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve( query );
        // EOFみたいなやつ
        boost::asio::ip::tcp::resolver::iterator end;
        // エラーの内容("ホストが見つからんかった"で初期化)
        boost::system::error_code error = boost::asio::error::host_not_found;

        // リゾルバにお願いして見つかったホストに接続
        boost::asio::ip::tcp::socket socket( io_service );
        while( error && endpoint_iterator != end )
        {
            socket.close();
            // ちゃんと繋がったらerrorはNULLになる
            socket.connect( *endpoint_iterator++, error );
        }

        // 繋がったホストに送信するリクエストの内容
        boost::asio::streambuf request;
        std::ostream request_stream( &request );

        request_stream << "GET /index.html HTTP/1.0\r\n";
        request_stream << "Host: xxx.com\r\n";
        request_stream << "\r\n";

        // ソケットに書き込み
        boost::asio::write( socket, request );

        // 受信したレスポンスの内容
        boost::asio::streambuf response;
        while( boost::asio::read( socket, response, boost::asio::transfer_at_least( 1 ), error ) ) {
            std::cout << &response;
        }

        // 受信時にエラーが発生したらthrow
        if( error != boost::asio::error::eof ) {
            throw boost::system::system_error( error );
        }
    }
    catch( std::exception& e ) {
        std::cout << "Exception: " << e.what() << std::endl;
    }

    return 0;
}

長くなってもたから

続き(boost::asio::ssl)は次回。