以Engine替換為出發點解析OpenSSL的SSL連接過程


SSL_new
   
    SSL_new沒有做什么實質性的工作
    1 分配SSL結構的存儲空間, 初始SSL結構中的成員, 成員初始化也比較好理解; 其中有些是復制SSL_CTX的;
      其中一個重要的就是分配SSL3_STATE結構;
    2 SSL結構是整個SSL通信過程需要使用的類似Win32編程過程中的handle一樣的東東, 自始至終都再用.
      SSL結構有點復雜: 包含了SSL3_STATE, SSL_CTX和SSL_SESSION結構;
      因為細節沒有一一列舉, 這里將SSL_new並做了初始化后的結構拷貝粘貼在此, 就可以看到, SSL_CTX的
      初始化已經在前面解讀過了:
-    s    0x015fb750
    version    0x00000300
    type    0x00000000
-    method    0x0027f268 SSLv3_client_data
    version    0x00000300
    ssl_new    0x002115a5 _ssl3_new
    ssl_clear    0x00211145 _ssl3_clear
    ssl_free    0x0021146a _ssl3_free
    ssl_accept    0x002113d9 _ssl_undefined_function
    ssl_connect    0x002115aa _ssl3_connect
    ssl_read    0x0021169a _ssl3_read
    ssl_peek    0x00211474 _ssl3_peek
    ssl_write    0x002110c3 _ssl3_write
    ssl_shutdown    0x002111fe _ssl3_shutdown
    ssl_renegotiate    0x002114a6 _ssl3_renegotiate
    ssl_renegotiate_check    0x0021155f _ssl3_renegotiate_check
    ssl_get_message    0x002114d3 _ssl3_get_message
    ssl_read_bytes    0x0021159b _ssl3_read_bytes
    ssl_write_bytes    0x00211749 _ssl3_write_bytes
    ssl_dispatch_alert    0x00211131 _ssl3_dispatch_alert
    ssl_ctrl    0x0021147e _ssl3_ctrl
    ssl_ctx_ctrl    0x0021151e _ssl3_ctx_ctrl
    get_cipher_by_char    0x00211037 _ssl3_get_cipher_by_char
    put_cipher_by_char    0x002116bd _ssl3_put_cipher_by_char
    ssl_pending    0x00211582 _ssl3_pending
    num_ciphers    0x002110eb _ssl3_num_ciphers
    get_cipher    0x0021162c _ssl3_get_cipher
    get_ssl_method    0x0022b380 ssl3_get_client_method(int)
    get_timeout    0x00232ab0 ssl3_default_timeout(void)
-    ssl3_enc    0x0027d5d8 SSLv3_enc_data
    enc    0x002115c3 _ssl3_enc
    mac    0x002115f5 _ssl3_mac
    setup_key_block    0x002116e0 _ssl3_setup_key_block
    generate_master_secret    0x002113b6 _ssl3_generate_master_secret
    change_cipher_state    0x0021119f _ssl3_change_cipher_state
    final_finish_mac    0x00211631 _ssl3_final_finish_mac
    finish_mac_length    0x00000024
    cert_verify_mac    0x0021163b _ssl3_cert_verify_mac
+    client_finished_label    0x00273b8c "CLNT"
    client_finished_label_len    0x00000004
+    server_finished_label    0x00273b84 "SRVR"
    server_finished_label_len    0x00000004
    alert_value    0x00211343 _ssl3_alert_code
    ssl_version    0x0021145b _ssl_undefined_void_function
    ssl_callback_ctrl    0x002110ff _ssl3_callback_ctrl
    ssl_ctx_callback_ctrl    0x0021129e _ssl3_ctx_callback_ctrl
+    rbio    0x00000000
+    wbio    0x00000000
+    bbio    0x00000000
    rwstate    0x00000001
    in_handshake    0x00000000
    handshake_func    0x00000000
    server    0x00000000
    new_session    0x00000000
    quiet_shutdown    0x00000000
    shutdown    0x00000000
    state    0x00005000
    rstate    0x000000f0
+    init_buf    0x00000000
    init_msg    0x00000000
    init_num    0x00000000
    init_off    0x00000000
+    packet    0x00000000 ""
    packet_length    0x00000000
+    s2    0x00000000
-    s3    0x015fbbf8
    flags    0x00000000
    delay_buf_pop_ret    0x00000000
+    read_sequence    0x015fbc00 ""
+    read_mac_secret    0x015fbc08 ""
+    write_sequence    0x015fbc48 ""
+    write_mac_secret    0x015fbc50 ""
+    server_random    0x015fbc90 ""
+    client_random    0x015fbcb0 ""
    need_empty_fragments    0x00000000
    empty_fragment_done    0x00000000
+    rbuf    {...}
+    wbuf    {...}
+    rrec    {...}
+    wrec    {...}
+    alert_fragment    0x015fbd48 ""
    alert_fragment_len    0x00000000
+    handshake_fragment    0x015fbd50 ""
    handshake_fragment_len    0x00000000
    wnum    0x00000000
    wpend_tot    0x00000000
    wpend_type    0x00000000
    wpend_ret    0x00000000
+    wpend_buf    0x00000000 ""
+    finish_dgst1    {...}
+    finish_dgst2    {...}
    change_cipher_spec    0x00000000
    warn_alert    0x00000000
    fatal_alert    0x00000000
    alert_dispatch    0x00000000
+    send_alert    0x015fbd9c ""
    renegotiate    0x00000000
    total_renegotiations    0x00000000
    num_renegotiations    0x00000000
    in_read_app_data    0x00000000
+    tmp    {...}
+    d1    0x00000000
    read_ahead    0x00000000
    msg_callback    0x00000000
    msg_callback_arg    0x00000000
    hit    0x00000000
+    param    0x015fbbc0
+    cipher_list    0x00000000
+    cipher_list_by_id    0x00000000
+    enc_read_ctx    0x00000000
+    read_hash    0x00000000
+    expand    0x00000000
+    enc_write_ctx    0x00000000
+    write_hash    0x00000000
+    compress    0x00000000
+    cert    0x015fb870
    sid_ctx_length    0x00000000
+    sid_ctx    0x015fb7ec ""
+    session    0x00000000
    generate_session_id    0x00000000
    verify_mode    0x00000000
    verify_callback    0x00000000
    info_callback    0x00000000
    error    0x00000000
    error_code    0x00000000
-    ctx    0x015f71e0
+    method    0x0027f268 SSLv3_client_data
+    cipher_list    0x015f7bd8
+    cipher_list_by_id    0x015f7620
+    cert_store    0x015f7438
+    sessions    0x015f7368
    session_cache_size    0x00005000
+    session_cache_head    0x00000000
+    session_cache_tail    0x00000000
    session_cache_mode    0x00000002
    session_timeout    0x00001c20
    new_session_cb    0x00000000
    remove_session_cb    0x00000000
    get_session_cb    0x00000000
+    stats    {...}
    references    0x00000002
    app_verify_callback    0x00000000
    app_verify_arg    0x00000000
    default_passwd_callback    0x00000000
    default_passwd_callback_userdata    0x00000000
    client_cert_cb    0x00000000
    app_gen_cookie_cb    0x00000000
    app_verify_cookie_cb    0x00000000
+    ex_data    {...}
-    rsa_md5    0x00602310 md5_md
    type    0x00000004
    pkey_type    0x00000008
    md_size    0x00000010
    flags    0x00000000
    init    0x004cc470 init(env_md_ctx_st *)
    update    0x004cc4a0 update(env_md_ctx_st *, const void *, unsigned int)
    final    0x004cc4d0 final(env_md_ctx_st *, unsigned char *)
    copy    0x00000000
    cleanup    0x00000000
    sign    0x0043317f _RSA_sign
    verify    0x004310a0 _RSA_verify
+    required_pkey_type    0x0060233c
    block_size    0x00000040
    ctx_size    0x00000060
-    md5    0x00602310 md5_md
    type    0x00000004
    pkey_type    0x00000008
    md_size    0x00000010
    flags    0x00000000
    init    0x004cc470 init(env_md_ctx_st *)
    update    0x004cc4a0 update(env_md_ctx_st *, const void *, unsigned int)
    final    0x004cc4d0 final(env_md_ctx_st *, unsigned char *)
    copy    0x00000000
    cleanup    0x00000000
    sign    0x0043317f _RSA_sign
    verify    0x004310a0 _RSA_verify
+    required_pkey_type    0x0060233c
    block_size    0x00000040
    ctx_size    0x00000060
-    sha1    0x00602470 sha1_md
    type    0x00000040
    pkey_type    0x00000041
    md_size    0x00000014
    flags    0x00000000
    init    0x004cc700 init(env_md_ctx_st *)
    update    0x004cc730 update(env_md_ctx_st *, const void *, unsigned int)
    final    0x004cc760 final(env_md_ctx_st *, unsigned char *)
    copy    0x00000000
    cleanup    0x00000000
    sign    0x0043317f _RSA_sign
    verify    0x004310a0 _RSA_verify
+    required_pkey_type    0x0060249c
    block_size    0x00000040
    ctx_size    0x00000064
+    extra_certs    0x00000000
+    comp_methods    0x006e3a48
    info_callback    0x00000000
+    client_CA    0x015f7720
    options    0x00000000
    mode    0x00000000
    max_cert_list    0x00019000
-    cert    0x015f72f0
-    key    0x015f7318
-    x509    0x015f8cb8
-    cert_info    0x015f8d30
+    version    0x015f7b30
+    serialNumber    0x015f8d70
+    signature    0x006e9798
+    issuer    0x015f8d98
+    validity    0x006e4070
+    subject    0x015f7980
-    key    0x015f79d0
+    algor    0x015f79f8
-    public_key    0x015f7a18
    length    0x0000008c
    type    0x00000003
+    data    0x015fa410 "0亯亖"
    flags    0x00000008
-    pkey    0x015f8ee8
    type    0x00000006
    save_type    0x00000006
    references    0x00000001
-    pkey    {...}
+    ptr    0x015f8f18 ""
-    rsa    0x015f8f18
    pad    0x00000000
    version    0x00000000
+    meth    0x0063e958 rsa_pkcs1_eay_meth
    engine    0x00000000
+    n    0x015f9008
+    e    0x015f90d8
+    d    0x00000000
+    p    0x00000000
+    q    0x00000000
+    dmp1    0x00000000
+    dmq1    0x00000000
+    iqmp    0x00000000
+    ex_data    {...}
    references    0x00000001
    flags    0x00000006
+    _method_mod_n    0x00000000
+    _method_mod_p    0x00000000
+    _method_mod_q    0x00000000
+    bignum_data    0x00000000 ""
    blinding    0x00000000
    mt_blinding    0x00000000
+    dsa    0x015f8f18
+    dh    0x015f8f18
    ec    0x015f8f18
    save_parameters    0x00000001
+    attributes    0x00000000
+    issuerUID    0x00000000
+    subjectUID    0x00000000
+    extensions    0x015fa208
+    sig_alg    0x015f7a40
+    signature    0x015f7a60
    valid    0x00000000
    references    0x00000002
+    name    0x015fa868 "/C=CN/ST=Chongqing/O=YZ/OU=YZ/CN=sslsocketclient/emailAddress=sslsocketclient@yunzhen.com"
+    ex_data    {...}
    ex_pathlen    0xffffffff
    ex_pcpathlen    0x00000000
    ex_flags    0x00000000
    ex_kusage    0x00000000
    ex_xkusage    0x00000000
    ex_nscert    0x00000000
+    skid    0x00000000
+    akid    0x00000000
    policy_cache    0x00000000
+    sha1_hash    0x015f8cfc ""
+    aux    0x00000000
-    privatekey    0x015f9128
    type    0x00000006
    save_type    0x00000006
    references    0x00000003
-    pkey    {...}
+    ptr    0x015faf00 ""
-    rsa    0x015faf00
    pad    0x00000000
    version    0x00000000
+    meth    0x0063e958 rsa_pkcs1_eay_meth
    engine    0x00000000
+    n    0x015f9158
+    e    0x015faf70
+    d    0x015f9288
+    p    0x015f9350
+    q    0x015f93e0
+    dmp1    0x015f9470
+    dmq1    0x015fafc0
+    iqmp    0x015fb048
+    ex_data    {...}
    references    0x00000001
    flags    0x00000006
+    _method_mod_n    0x00000000
+    _method_mod_p    0x00000000
+    _method_mod_q    0x00000000
+    bignum_data    0x00000000 ""
    blinding    0x00000000
    mt_blinding    0x00000000
+    dsa    0x015faf00
+    dh    0x015faf00
    ec    0x015faf00
    save_parameters    0x00000001
+    attributes    0x00000000
    valid    0x00000000
    mask    0x00000000
    export_mask    0x00000000
+    rsa_tmp    0x00000000
    rsa_tmp_cb    0x00000000
+    dh_tmp    0x00000000
    dh_tmp_cb    0x00000000
    ecdh_tmp    0x00000000
    ecdh_tmp_cb    0x00000000
+    pkeys    0x015f7318
    references    0x00000001
    read_ahead    0x00000000
    msg_callback    0x00000000
    msg_callback_arg    0x00000000
    verify_mode    0x00000000
    sid_ctx_length    0x00000000
+    sid_ctx    0x015f72a8 ""
    default_verify_callback    0x00000000
    generate_session_id    0x00000000
+    param    0x015f76e8
    quiet_shutdown    0x00000000
    debug    0x00000000
    verify_result    0x00000000
-    ex_data    {...}
+    sk    0x00000000
    dummy    0x00000000
+    client_CA    0x00000000
    references    0x00000001
    options    0x00000000
    mode    0x00000000
    max_cert_list    0x00019000
    first_packet    0x00000000
    client_version    0x00000300

//////////////////////////////////////////////////////////

接下來是SSL_set_fd, 將要通信的socket設置給SSL結構
   
    眾所周知, OpenSSL封裝了了一套稱為BIO的統一stream I/O機制,
    stream包括stdin, stdout, stderr, FILE,     socket等, 以上是常用的,
    其實BIO的功能很強大, 還不止這些. 挺好用;

    SSL_set_fd就是先構建一個socket類型的BIO, 然后設置fd. BIO->num就是fd
    記住, 以后在觀察socket時, 可以看這個成員的值.

    將此BIO指針分別賦值給SSL->rbio和SSL->wbio;

    return 1表示成功, 0表示失敗, OpenSSL的返回值很多都是采用這種風格.

//////////////////////////////////////////////////////////
接下來就是SSL_connect, 馬上進入SSL的握手過程.
    
    SSL_connect過程分為幾步完成, 應該有個狀態管理, SS::state應該是記錄狀態的.

    1 第一步
        初始狀態(client): (SSL* s)
        s->server=0;
        s->shutdown=0;
        s->state=SSL_ST_CONNECT|SSL_ST_BEFORE;
        s->handshake_func=s->method->ssl_connect;

        SSL_connect連接調用的是SSL_METHOD::ssl_connect函數.
       
        1) 生成隨機數, 這里第一次用到了與engine有關系的東西;
           首先調用的RAND_add, 看起來RAND_METHOD::add回調似乎有必要關注;
           這應該是設置隨機種子; 這里面用到了SHA1_MD. 不管它, 沒有時間去理解他的
           隨機數實現算法.
        2) ERR_clear_error: 清空該線程相關的ERR_STATE表
           clear_sys_error: Win32 SetLastError(0), !defined(WIN32) errno = 0
          
           這里看到了OpenSSL的error管理機制, 記得不久前, 想自己實現一個lasterror機制
           才發現簡單幾句代碼沒有辦法實現, Windows的GetLastError是線程隔離的, 應該與
           OpenSSL在這里實現的機制差不多. 而OpenSSL的ERROR還要強大一些, 還會反饋調用
           堆棧, 最大16層, 到時候有空了一定看一下: crypto\err\err.c
           ERR_clear_error大意是從一個與線程id相關的hash表, 返回ERR_STATE指針; 如果
           沒有, 就分配一個新的, 放到hash表中.

        3) s->in_handshake++; // 還不知道是干什么
           前面已經看到, s->state設置為SSL_ST_CONNECT|SSL_ST_BEFORE
           這里比較!(s->state & SSL_ST_INIT) || s->state & SSL_ST_BEFORE) SSL_clear
           #define SSL_ST_INIT (SSL_ST_CONNECT|SSL_ST_ACCEPT)
           這里執行的是一些清理工作, 當SSL斷開或者shutdown后, 重新調用SSL_connect時, 需要
           檢測標志再次清理.

        4) 檢測版本標志, 是不是SSLV3, 否則出錯.
           設置s->type = SSL_ST_CONNECT;
           分配s->init_buf. max_len:0x5558, 初始數據:0, 長度:SSL3_RT_MAX_PLAIN_LENGTH

        5) ssl3_setup_buffers: 分配讀寫buffer
           分配s->s3->rbuf, s->s3->wbuf, 這里可以看到buf長度為:
           rbuf len= 0x4805, wbuf len = 0x490a.
           做過測試, ssl write一次最大長度為16K, 也就是0x4000. 與這里的buffer分配有關.
           我們可以在ssl3.h中找到
            #define SSL3_RT_MAX_PLAIN_LENGTH        16384    // 正好16K
           這里讀寫buffer為什么要長一點呢:
            #define SSL3_RT_MAX_COMPRESSED_LENGTH    (1024+SSL3_RT_MAX_PLAIN_LENGTH)
            #define SSL3_RT_MAX_ENCRYPTED_LENGTH        (1024+SSL3_RT_MAX_COMPRESSED_LENGTH)
            #define SSL3_RT_MAX_PACKET_SIZE            (SSL3_RT_MAX_ENCRYPTED_LENGTH+SSL3_RT_HEADER_LENGTH)
            在分配寫buffer時, SSL3_RT_MAX_PACKET_SIZE+256. 哈哈. 我也經常這么干.
           然后分s->bbio, 不知道, 看注釋/* used during session-id reuse to concatenate messages */

         6) ssl3_init_finished_mac
            這個函數就兩個語句:
            EVP_DigestInit_ex(&(s->s3->finish_dgst1),s->ctx->md5, NULL);
            EVP_DigestInit_ex(&(s->s3->finish_dgst2),s->ctx->sha1, NULL);
            EVP_DigestInit_ex用到了Engine的EVP_MD的init回調, 當這里卻強制將Engine設置為空了.
            意味着在初始化是, 就要將Engine植入, 否則我們的Engine怎么得到調用呢?

            ***********************************
            結論: 還得依靠ENGINE_set_default_digests來設置EVP_MD. - 正確
            ***********************************
           
            OpenSSL 1.0.1c中, 該函數的實現, 已經完全不同. 不過無論是1.0.1c還0.9.8a版本, 在調用
            EVP_DigestInit_ex時, 都在engine參數位置填了NULL. 看來上面的結論沒有問題;
            在EVP_DigestInit_ex內部, 會調用ENGINE_get_digest_engine獲得EVP_MD, 這是根據nid在
            digest table中去選. 如果我們調用ENGINE_set_default_digests的話, 會在digest table
            中找到我們設置的EVP_MD, 就不會調用Engine中實現的MD回調. 而不會調默認的MD回調了.
           
            這里, 順便注意到了一個問題, 看下面的代碼, 這是在EVP_DigestInit_ex中的代碼:
            const EVP_MD *d = ENGINE_get_digest(impl, type->type);
            if(!d)
                {
                /* Same comment from evp_enc.c */
                EVPerr(EVP_F_EVP_DIGESTINIT_EX,EVP_R_INITIALIZATION_ERROR);
                return 0;
                }
            這里看起來設置了Engine, 仿佛就要實現Engine所列出的全部函數一樣. 黑老子一大跳.
            仔細看ENGINE_set_default_digests的代碼, 設置default engine時, 其實只是設置某一方面的
            比如digest, cipher, rsa等, 而且是根據nid來在一個全局ENGINE_PILE hash表中進行檢索的.
            比如, digest, 就是在tb_digest.c中申明的全局變量:
            static ENGINE_TABLE *digest_table = NULL;
            struct st_engine_table
                {
                LHASH_OF(ENGINE_PILE) piles;
                };
            可以在crypto\engine目錄可以看到, 有很多tb_打頭的文件, 每個文件中, 都有一個ENGINE_TABLE
            類型的全局變量個, 作用跟*digest_table一樣.

            而且, 如果找不到Engine的話, 就會調用對應的確實回調函數來替代; 這下終於放心了!!!!!!!

        7) 變換狀態:
            s->state=SSL3_ST_CW_CLNT_HELLO_A;
            #define SSL3_ST_CW_CLNT_HELLO_A        (0x110|SSL_ST_CONNECT)
       
        8) 狀態管理
           在寫代碼時, 經常遇到要執行一系列步驟, 每個步驟都有自己的狀態, 不知道C代碼的狀態管理
           "模式", 經常都寫得很"散", 狀態設置到處都是, 一不小心就搞錯. 雖然很少出錯, 當寫這部分
           代碼時, 確費盡"心血", 精力高度集中. 而且維護起來比較麻煩;
          
           OpenSSL在這里用了一個for(;;)+swithe(state), 將狀態管理統一在一處, 值得學習;
           初始時, switch case SSL_ST_CONNECT:..., 執行初始化, 設置狀態; 進入下次循環, 如此.
           汗!!!!

        9) 開始向server say hello了.
           這里要用到s->init_buf, 參見前面4)步:
           分配s->init_buf. max_len:0x5558, 初始數據:0, 長度:SSL3_RT_MAX_PLAIN_LENGTH
          
           首先建立session: ssl_get_new_session
           調用: SSL_SESSION_new, 新建session, 除了設置session timeout外, 其他沒什么;
           注意SSL_CTX中也有一個timeout, 這里session中也有一個timeout.
           ssl_ctx->timeout: 7200, session->timeout: 60 *5 + 4. 不同, new完成后, 這個
           session->timeout = ssl_ctx->timeout; // 7200. 2小時為准;

           session_id長度, 32字節; 這里還沒有session_id, session_id是和server協商后server
           發給client的.

           發送的數據:
           0~3 - 空置
           4~5 - ssl->version, 4=version >> 8: 03, 5=ver&0xff:00
           6~37 - random, s->s3->client_random, 產生隨機數時, 只產生了28bytes, 拷貝了32bytes
           38 - s->session->session_id_length:0
           41~42 ciphers by bytes, 沒兩個字節, 表示一個算法, 由算法ID取最低2個字節. 共1B個算法
                 39 00 38 00 35 00 16 00 13 00 0A 00 33 00 32 00 2F 00
                 07 00 66 00 05 00 04 00 63 00 62 00 61 00 15 00 12 00
                 09 00 65 00 64 00 60 00 14 00 11 00 08 00 06 00 03
           95 - s->ctx->comp_methods 壓縮算法的個數, 但為0. 最后放到95位置時, 硬性+1
           96 - NULL表示結束

           長度: 不算0~3的空置, len = 93, 0x5d
           最后填0~3, 0: SSL3_MT_CLIENT_HELLO -- 1
           bigendian: len, 占3個字節: 00 00 5d

        10) 轉換狀態: s->state=SSL3_ST_CW_CLNT_HELLO_B;
            設置s->init_num = 97, s->init_off = 0
            ssl3_do_write(s, SSL3_RT_HANDSHAKE); // type - SSL3_RT_HANDSHAKE
            ->call ssl3_write_bytes(s,type,&s->init_buf->data[s->init_off],s->init_num)
            寫完成后, 如果type == SSL3_RT_HANDSHAKE
            ssl3_finish_mac(s,(unsigned char *)&s->init_buf->data[s->init_off],ret);
            ssl3_finish_mac 只做了digestupdate, 還沒有digestfinal.

        11) client say hello 完成. 狀態轉換:
            s->state=SSL3_ST_CR_SRVR_HELLO_A;

        12 獲得ssl3_get_server_hello, 獲得server端返回的hello信息,server返回的hello信息中,
           包含了session_id和選定的算法byte(0x35 AES256_SHA)
           server在第一次say hello時, 已經選定算法了, ssl3_choose_cipher這個函數實現了此功能

           枚舉client所有的ssl_clipher.
           然后用server的cert
           通過調用:
           ssl_set_cert_masks(cert, client_ssl_cipher);
           來決定一個mask和export mask - 簡寫emask
           

           -    cert        0x0182ca68
            +    key            0x0182ca90--|
                valid        0x00000000    |
                mask        0x00000000    |
                export_mask    0x00000000    |
            +    rsa_tmp        0x00000000    |
                rsa_tmp_cb    0x00000000    |
            +    dh_tmp        0x00000000    |
                dh_tmp_cb    0x00000000    |
                ecdh_tmp    0x00000000    |
                ecdh_tmp_cb    0x00000000    |
            +    pkeys        0x0182ca90<-|
                references    0x00000001

                prio = clnt;
                allow = srvr;

                dh_dsa            0
                dh_rsa            0
                dh_tmp            0
                dsa_sign        0
                mask            0
                rsa_enc            1
                rsa_enc_export    1
                rsa_sign        0
                rsa_tmp            0
                rsa_tmp_export    0
               
                // 只有SSL_PKEY_RSA_ENC有數據, 其他的沒有數據

                #define SSL_C_EXPORT_PKEYLENGTH(cipher) cipher->algo_strength & 0x00000008 ? 512 : 1024;
                kl=SSL_C_EXPORT_PKEYLENGTH(cipher);

                cpk= &(c->pkeys[SSL_PKEY_RSA_ENC]);
                rsa_enc= (cpk->x509 != NULL && cpk->privatekey != NULL);
                rsa_enc_export=(rsa_enc && EVP_PKEY_size(cpk->privatekey)*8 <= kl);

                rsa_tmp=(c->rsa_tmp != NULL || c->rsa_tmp_cb != NULL);
                rsa_tmp_export=(c->rsa_tmp_cb != NULL || (rsa_tmp && RSA_size(c->rsa_tmp)*8 <= kl));

                if (rsa_enc || (rsa_tmp && rsa_sign))
                    mask|=SSL_kRSA;
                if (rsa_enc_export || (rsa_tmp_export && (rsa_sign || rsa_enc)))
                    emask|=SSL_kRSA;
               
                // #define SSL_kRSA        0x00000001L /* RSA key exchange */
               
                if (rsa_enc || rsa_sign)
                {
                    mask|=SSL_aRSA;
                    emask|=SSL_aRSA;
                }
                // #define SSL_aRSA        0x00000100L /* Authenticate with RSA */               

                #define SSL_aNULL         0x00000800L /* no Authenticate, ADH */
                mask|=SSL_aNULL;        // mask: 0x00000901
                emask|=SSL_aNULL;        // emask: 0x00000901

                c->mask=mask;
                c->export_mask=emask;
                c->valid=1;

                //#define SSL_MKEY_MASK        0x000000FFL    // key exchange
                //#define SSL_AUTH_MASK        0x00007F00L    // authenticate
                //#define SSL_ENC_MASK        0x043F8000L    // cipher encode, symmetric
                //#define SSL_MAC_MASK        0x00c00000L    // hash algorithm
                //#define SSL_SSL_MASK        0x03000000L    // ssl version

                alg=c->algorithms&(SSL_MKEY_MASK|SSL_AUTH_MASK);
               
                #define SSL_EXPORT 0x00000002L
                #define SSL_IS_EXPORT(a)    ((a)&SSL_EXPORT)               
                #define SSL_C_IS_EXPORT(c)    SSL_IS_EXPORT((c)->algo_strength)

                當alg
                if(SSL_C_IS_EXPORT(c))
                    ok=((alg & emask) == alg)?1:0;
                else
                    ok=((alg & mask) == alg)?1:0;

        因為是循環枚舉, OpenSSL最先發現cipher->name == AES256_SHA, id == 0x03000035的算法
        滿足. AES256_SHA算法ID的宏定義為TLS1_CK_RSA_WITH_AES_256_SHA, 根據選擇過程.
        首先計算mask和emask, 依據是證書中的密鑰交換算法和認證算法. 以及密鑰長度 小於等於kl, kl
        的計算方式見前面ssl_set_cert_masks.
            typedef struct ssl_cipher_st {
                int valid;
                const char *name;                /* text name */
                unsigned long id;                /* id, 4 bytes, first is version */
                unsigned long algorithms;        /* what ciphers are used */
                unsigned long algo_strength;    /* strength and export flags */
                unsigned long algorithm2;        /* Extra flags */
                int strength_bits;                /* Number of bits really used */
                int alg_bits;                    /* Number of bits for algorithm */
                unsigned long mask;                /* used for matching */
                unsigned long mask_strength;    /* also used for matching */
            } SSL_CIPHER;

            {
            1,                                                /* valid */
            TLS1_TXT_RSA_WITH_AES_256_SHA,                    /* text name */
            TLS1_CK_RSA_WITH_AES_256_SHA,                    /* id, 4 bytes, first is version */
            SSL_kRSA|SSL_aRSA|SSL_AES|SSL_SHA |SSL_TLSV1,    /* what ciphers are used */
            SSL_NOT_EXP|SSL_HIGH,    // 0x81                    /* strength and export flags */
            0,                                                /* Extra flags */
            256,                                            /* Number of bits really used */
            256,                                            /* Number of bits for algorithm */
            SSL_ALL_CIPHERS,                                /* used for matching */
            SSL_ALL_STRENGTHS,                                /* also used for matching */
            },

            kl = 1024
            {
            1,
            TLS1_TXT_RSA_WITH_AES_128_SHA,
            TLS1_CK_RSA_WITH_AES_128_SHA,
            SSL_kRSA|SSL_aRSA|SSL_AES|SSL_SHA |SSL_TLSV1,
            SSL_NOT_EXP|SSL_MEDIUM,    // 0x41
            0,
            128,
            128,
            SSL_ALL_CIPHERS,
            SSL_ALL_STRENGTHS,
            },

        OpenSSL的策略是最先找到的匹配, 修改ok的值, 繼續枚舉, 中間發現:SSL3_CK_RSA_DES_192_CBC3_SHA
        也滿足條件, DES不是我們支持的. 讓其繼續循環. 循環到第8個時, 找到了AES128_SHA. ok!!!!!
        在server支持的cipherlist中查找, 找到, choose_cipher完成.

        看來我們的解決方案只有修改OpenSSL代碼了.
        修改ssl_set_cert_masks不合適, 涉及點比較多. 直接修改: ssl3_choose_cipher

        //////////////////////////////////////////////////////////////////
        增加條件限定:
        (cipher->algorithms & SSL_ENC_MASK) & SSL_AES -> 將條件限定在AES
        (cipher->algorithms & SSL_MAC_MASK) & SSL_SHA -> 將條件限定在SHA1
        cipher->alg_bits == 128
        這三個條件下來, 就能夠確保選中我們的算法了.
        ///////////////////////////////////////////////////////////////////

        哇哦! 發現一個函數, 可以搞定:SSL_CTX_set_cipher_list(ctx, "AES128-SHA");       
        rule_str不用填哪個帶"!-+@"的晦澀的語法. 直接填算法名稱即可, 算法名稱在ssl3.h和tls1.h中定義.
        后來還發現apps\s_client.c挺有參考價值.

        找到自己想要的東西了, 接下來就沒詳細跟蹤了.
        先回頭寫Engine, 有時間再來將這個流程搞通並梳理清除.

        大概是以下的流程:
        接下來是驗證證書. client會將證書鏈以DER的編碼格式傳遞到server端, server端在驗證了client端的
        證書后. 接下來會獲得       

        在接下來是協商在以后通信過程中要用到的對稱算法, 對稱算法的user key計算比較復雜, 不過好在
        我們不需要關心.

        再接下來就是finish mac了. 用master_key, ssl3_pad_1和2做hash, 先做MD5, 然后在MD5的基礎
        上做SHA1.  finish mac是干什么的, 沒詳細探索.

        我們可以從這一堆的SSL狀態宏定義中看到SSL_connect的處理順序:
        /* write to server */
        #define SSL3_ST_CW_CLNT_HELLO_A                (0x110|SSL_ST_CONNECT)
        #define SSL3_ST_CW_CLNT_HELLO_B                (0x111|SSL_ST_CONNECT)
        /* read from server */
        #define SSL3_ST_CR_SRVR_HELLO_A                (0x120|SSL_ST_CONNECT)
        #define SSL3_ST_CR_SRVR_HELLO_B                (0x121|SSL_ST_CONNECT)
        #define DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A    (0x126|SSL_ST_CONNECT)
        #define DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B    (0x127|SSL_ST_CONNECT)
        #define SSL3_ST_CR_CERT_A                    (0x130|SSL_ST_CONNECT)
        #define SSL3_ST_CR_CERT_B                    (0x131|SSL_ST_CONNECT)
        #define SSL3_ST_CR_KEY_EXCH_A                (0x140|SSL_ST_CONNECT)
        #define SSL3_ST_CR_KEY_EXCH_B                (0x141|SSL_ST_CONNECT)
        #define SSL3_ST_CR_CERT_REQ_A                (0x150|SSL_ST_CONNECT)
        #define SSL3_ST_CR_CERT_REQ_B                (0x151|SSL_ST_CONNECT)
        #define SSL3_ST_CR_SRVR_DONE_A                (0x160|SSL_ST_CONNECT)
        #define SSL3_ST_CR_SRVR_DONE_B                (0x161|SSL_ST_CONNECT)
        /* write to server */
        #define SSL3_ST_CW_CERT_A                    (0x170|SSL_ST_CONNECT)
        #define SSL3_ST_CW_CERT_B                    (0x171|SSL_ST_CONNECT)
        #define SSL3_ST_CW_CERT_C                    (0x172|SSL_ST_CONNECT)
        #define SSL3_ST_CW_CERT_D                    (0x173|SSL_ST_CONNECT)
        #define SSL3_ST_CW_KEY_EXCH_A                (0x180|SSL_ST_CONNECT)
        #define SSL3_ST_CW_KEY_EXCH_B                (0x181|SSL_ST_CONNECT)
        #define SSL3_ST_CW_CERT_VRFY_A                (0x190|SSL_ST_CONNECT)
        #define SSL3_ST_CW_CERT_VRFY_B                (0x191|SSL_ST_CONNECT)
        #define SSL3_ST_CW_CHANGE_A                    (0x1A0|SSL_ST_CONNECT)
        #define SSL3_ST_CW_CHANGE_B                    (0x1A1|SSL_ST_CONNECT)
        #define SSL3_ST_CW_FINISHED_A                (0x1B0|SSL_ST_CONNECT)
        #define SSL3_ST_CW_FINISHED_B                (0x1B1|SSL_ST_CONNECT)
        /* read from server */
        #define SSL3_ST_CR_CHANGE_A                    (0x1C0|SSL_ST_CONNECT)
        #define SSL3_ST_CR_CHANGE_B                    (0x1C1|SSL_ST_CONNECT)
        #define SSL3_ST_CR_FINISHED_A                (0x1D0|SSL_ST_CONNECT)
        #define SSL3_ST_CR_FINISHED_B                (0x1D1|SSL_ST_CONNECT)

        /* server */
        /* extra state */
        #define SSL3_ST_SW_FLUSH                    (0x100|SSL_ST_ACCEPT)
        /* read from client */
        /* Do not change the number values, they do matter */
        #define SSL3_ST_SR_CLNT_HELLO_A                (0x110|SSL_ST_ACCEPT)
        #define SSL3_ST_SR_CLNT_HELLO_B                (0x111|SSL_ST_ACCEPT)
        #define SSL3_ST_SR_CLNT_HELLO_C                (0x112|SSL_ST_ACCEPT)
        /* write to client */
        #define DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A    (0x113|SSL_ST_ACCEPT)
        #define DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B    (0x114|SSL_ST_ACCEPT)
        #define SSL3_ST_SW_HELLO_REQ_A                (0x120|SSL_ST_ACCEPT)
        #define SSL3_ST_SW_HELLO_REQ_B                (0x121|SSL_ST_ACCEPT)
        #define SSL3_ST_SW_HELLO_REQ_C                (0x122|SSL_ST_ACCEPT)
        #define SSL3_ST_SW_SRVR_HELLO_A                (0x130|SSL_ST_ACCEPT)
        #define SSL3_ST_SW_SRVR_HELLO_B                (0x131|SSL_ST_ACCEPT)
        #define SSL3_ST_SW_CERT_A                    (0x140|SSL_ST_ACCEPT)
        #define SSL3_ST_SW_CERT_B                    (0x141|SSL_ST_ACCEPT)
        #define SSL3_ST_SW_KEY_EXCH_A                (0x150|SSL_ST_ACCEPT)
        #define SSL3_ST_SW_KEY_EXCH_B                (0x151|SSL_ST_ACCEPT)
        #define SSL3_ST_SW_CERT_REQ_A                (0x160|SSL_ST_ACCEPT)
        #define SSL3_ST_SW_CERT_REQ_B                (0x161|SSL_ST_ACCEPT)
        #define SSL3_ST_SW_SRVR_DONE_A                (0x170|SSL_ST_ACCEPT)
        #define SSL3_ST_SW_SRVR_DONE_B                (0x171|SSL_ST_ACCEPT)
        /* read from client */
        #define SSL3_ST_SR_CERT_A                    (0x180|SSL_ST_ACCEPT)
        #define SSL3_ST_SR_CERT_B                    (0x181|SSL_ST_ACCEPT)
        #define SSL3_ST_SR_KEY_EXCH_A                (0x190|SSL_ST_ACCEPT)
        #define SSL3_ST_SR_KEY_EXCH_B                (0x191|SSL_ST_ACCEPT)
        #define SSL3_ST_SR_CERT_VRFY_A                (0x1A0|SSL_ST_ACCEPT)
        #define SSL3_ST_SR_CERT_VRFY_B                (0x1A1|SSL_ST_ACCEPT)
        #define SSL3_ST_SR_CHANGE_A                    (0x1B0|SSL_ST_ACCEPT)
        #define SSL3_ST_SR_CHANGE_B                    (0x1B1|SSL_ST_ACCEPT)
        #define SSL3_ST_SR_FINISHED_A                (0x1C0|SSL_ST_ACCEPT)
        #define SSL3_ST_SR_FINISHED_B                (0x1C1|SSL_ST_ACCEPT)
        /* write to client */
        #define SSL3_ST_SW_CHANGE_A                    (0x1D0|SSL_ST_ACCEPT)
        #define SSL3_ST_SW_CHANGE_B                    (0x1D1|SSL_ST_ACCEPT)
        #define SSL3_ST_SW_FINISHED_A                (0x1E0|SSL_ST_ACCEPT)
        #define SSL3_ST_SW_FINISHED_B                (0x1E1|SSL_ST_ACCEPT)

        /////////////////////////////////////////////////////

        還好沒有放棄跟蹤, 在對server端的trace執行過程中, server端調用ssl3_get_client_key_exchange
        時, 在收到client送來的協商密鑰后, 會要用到s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey進行
        解密. 調用函數為: RSA_private_decrypt. 因為client端生成exchange key后, 會用server端的pubkey
        進行加密, 然后發送給server, 所以, 此時當然要解密;

        在加密前, 會判斷s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey是否為空. 所以, 我們在使用硬件
        Engine時, 還是要調用SSL_CTX_use_PrivateKey, 只是這里我們的Private的EVP_Key完全可用只包含
        公鑰的RSA代替. RSA_private_decrypt內部會調用rsa->meth->rsa_priv_dec來解密. 此時應該執行的
        是我們Engine的RSA解密函數.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM