LoginSignup
2
1

More than 5 years have passed since last update.

OpenSSL ソースリーディング その3

Last updated at Posted at 2018-06-27

前回からの続き。
SSL_readを見ます。

SSL_read

SSL_readはSSL/TLSの暗号データを復号し、読み取る関数です。
ただ、この関数でもコネクションがネゴシエーション状態にある場合はネゴシエーション処理を行います。

ssl/ssl_lib.c
int SSL_read(SSL *s, void *buf, int num) 
{
    if (s->handshake_func == NULL) {
        SSLerr(SSL_F_SSL_READ, SSL_R_UNINITIALIZED);
        return -1; 
    }

    if (s->shutdown & SSL_RECEIVED_SHUTDOWN) {
        s->rwstate = SSL_NOTHING;
        return (0);
    }           

    if ((s->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) {
        struct ssl_async_args args;

        args.s = s;
        args.buf = buf;
        args.num = num;
        args.type = READFUNC; 
        args.f.func_read = s->method->ssl_read;

        return ssl_start_async_job(s, &args, ssl_io_intern);
    } else {    
        return s->method->ssl_read(s, buf, num);
    }           
}           

基本的にはSSL_do_handshake関数と同じようなものです。
ただし、ハンドシェイク関数が設定されていない(=コネクト側かアクセプト側かが決定していない)場合や、受信サイドが切れている場合(close_notifyを受信している場合)は、受信処理を行いません。
それ以外の場合はssl_readハンドラが呼び出されます。
このハンドラは大体はssl3_read関数です。

ssl3_read

ssl3_read_internal関数を呼び出しているだけです。
1段階はさんでいるのは、SSL_peekによるバッファを消費しないで読み取る関数との区別をつけるためと思われます。
peekの場合は、ssl3_read_internalの第4引数を1にします。

ssl/s3_read.c
int ssl3_read(SSL *s, void *buf, int len) 
{
    return ssl3_read_internal(s, buf, len, 0);
}

ssl3_read_internal

暗号データをバイト数指定で読み取る関数です。
ここで呼び出されるssl_read_bytesハンドラは、大体はssl3_read_bytesになります。

ssl/s3_lib.c
static int ssl3_read_internal(SSL *s, void *buf, int len, int peek)
{
    int ret;

    clear_sys_error();
    if (s->s3->renegotiate)
        ssl3_renegotiate_check(s);
    s->s3->in_read_app_data = 1;
    ret =
        s->method->ssl_read_bytes(s, SSL3_RT_APPLICATION_DATA, NULL, buf, len,
                                  peek);
    if ((ret == -1) && (s->s3->in_read_app_data == 2)) {
        /*
         * ssl3_read_bytes decided to call s->handshake_func, which called
         * ssl3_read_bytes to read handshake data. However, ssl3_read_bytes
         * actually found application data and thinks that application data
         * makes sense here; so disable handshake processing and try to read
         * application data again.
         */
        ossl_statem_set_in_handshake(s, 1);
        ret =
            s->method->ssl_read_bytes(s, SSL3_RT_APPLICATION_DATA, NULL, buf,
                                      len, peek);
        ossl_statem_set_in_handshake(s, 0);
    } else
        s->s3->in_read_app_data = 0;

    return (ret);
}

SSL3_RT_APPLICATION_DATAを指定しているのは、これがssl3_read_internal関数からの呼び出しであることを示すようなもので、アプリケーションデータの読み込みを期待しています。

s->method->ssl_read_bytesの呼び出しを2回行っています。
2回目で行われるs->method->ssl_read_bytesは、ネゴシエーション中なのでSSL/TLSのネゴシエーションデータを期待していたのに、アプリケーションデータである場合です。
この状態に入るのは、クライアントへHelloRequestを送信した後、ネゴシエーションが始まっていない段階で、アプリケーションデータを受信した時です。
この場合、1回目の呼び出しでは、アプリケーションデータの読み込みの許可フラグ(in_read_app_data = 2)が設定され、処理を行わずに一旦関数から復帰します。
そして、2回目の呼び出しでは、ossl_statem_set_in_handshake(s, 1)を呼び出しておくことでハンドシェイクの処理に入ることを防止してから、アプリケーションデータの読み込み処理が行われます。

次回

次のssl3_read_bytes関数が長かったので一旦ここで切ります。
次はssl3_read_bytes関数を見ていきます。

2
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1