zoukankan      html  css  js  c++  java
  • SSL连接建立过程分析(1)

    Https协议:SSL建立过程分析

    web訪问的两种方式:

    http协议,我们普通情况下是通过它訪问web,由于它不要求太多的安全机制,使用起来也简单,非常多web网站也仅仅支持这样的方式下的訪问.

    https协议(Hypertext Transfer Protocol over Secure Socket Layer),对于安全性要求比較高的情况,能够通过它訪问web,比方工商银行https://www.icbc.com.cn/icbc/(当然也能够通过http协议訪问,仅仅是没那么安全了).其安全基础是SSL协议.

    SSL协议,当前版本号为3.1(SSL3.1就是TLS1.0)。它已被广泛地用于Web浏览器与server之间的身份认证和加密传输数据.它位于TCP/IP协议与各种应用层协议之间,为数据通讯提供安全支持。SSL协议可分为两层: SSL记录协议(SSL Record Protocol):它建立在可靠的传输协议(如TCP)之上,为高层协议提供数据封装、压缩、加密等基本功能的支持。 SSL握手协议(SSL Handshake Protocol):它建立在SSL记录协议之上,用于在实际的传输数据開始前,通讯两方进行身份认证、协商加密算法、交换加密密钥等。

    为了了解具体过程,能够通过网络抓包工具(Commview,Iris)分析https协议,SSL连接建立过程中,数据包交换情况.

    数据包分析过程用到的几个图.

    图,SSL Protocol Stack

     

    图.SSL Record Format

     

    图.SSL Record Protocol Payload

     

    图.Handshake Protocol Action

     

     

    它们来之.Cryptography and Network Security Principles and Practices, Fourth Edition-Chapter 17. Web Security-17.2. Secure Socket Layer and Transport Layer Security(password学与网络安全 原理与实践第四版,17章web安全,17.2节,SSL与TLS)详细细节參考本书.

    以下跟踪握手过程(图Handshake Protocol Action)中,数据包的交换.

    以为https方式訪问www.sun.com为样例,一般大型公司,银行的web都支持https訪问,如工商银行,sun,微软,IBM.

    在IE中输入:https://wwww.sun.com,由于这是https协议,所以在实际訪问web前,会建立SSL连接.

    通过Commview抓包工具,过滤443port(普通情况下,HTTPS使用port443,HTTP使用port80)能够得到数据包.

    数据包大致情况和(图Handshake Protocol Action)相应.

     

    SSL连接建立过程分析(1)

    1. 应用程序接口
    1.1 SSL初始化
    SSL_CTX* InitSSL(int server, char *cert, char *key, char *pw)
    {
        SSL_CTX* ctx;
        SSL_METHOD *meth;
        int status;
    // 算法初始化  
    // 载入SSL错误信息
        SSL_load_error_strings();
    // 加入SSL的加密/HASH算法
        SSLeay_add_ssl_algorithms();
    // 服务器还是客户端
        If(server)
     meth = SSLv23_server_method();
        else
     meth = SSLv23_client_method();
    // 建立新的SSL上下文
        ctx = SSL_CTX_new (meth);
        if(!ctx) return NULL;
    // 设置证书文件的口令
        SSL_CTX_set_default_passwd_cb_userdata(ctx, pw);
    //载入本地证书文件
        status=SSL_CTX_use_certificate_file(ctx, cert, SSL_FILETYPE_ASN1);
        if (status <= 0) {
            frintf(stderr, "Use cert fail, status=%d/n", status);
            goto bad;
        }
    // 载入私钥文件
        if (SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM) <= 0) {
            fprintf(stderr, "Use private key fail/n");
            goto bad;
        }
    // 检查证书和私钥是否匹配
        if (!SSL_CTX_check_private_key(ctx)) {
            fprintf("Private key does not match the certificate public key/n");
            goto bad;
        }
        fprintf("Cert and key OK/n");
        return ctx;
    bad:
        SSL_CTX_free (ctx);
        return NULL;
    }
    1.2 建立SSL新连接
    server:
    // 建立SSL
    ssl = SSL_new (ctx);
    // 将SSL与TCP socket连接
    SSL_set_fd (ssl, sd);
    //接受新SSL连接
    err = SSL_accept (ssl);
    client:
    // 建立SSL
    ssl = SSL_new (ctx);
    // 将SSL与TCP socket连接
    SSL_set_fd (ssl, sd);
    // SSL连接
    err = SSL_connect (ssl);

    server的SSL_accept()和client的SSL_connect()函数共同完毕SSL的握手协商过程。
     
    1.3 SSL通信
    和普通的read()/write()调用一样,用以下的函数完毕数据的SSL发送和接收,函数输入数据是明文,SSL自己主动将数据封装进SSL中:
    读/接收:SSL_read()
    写/发送:SSL_write()
    1.4 SSL释放
    SSL释放非常easy:
     SSL_free (ssl);
     
    2. SSL实现分析
    下面SSL源码取自openssl-0.9.7b。

    2.1 SSL_load_error_strings
    该函数载入错误字符串信息:
    void SSL_load_error_strings(void)
     {
    #ifndef OPENSSL_NO_ERR
     ERR_load_crypto_strings();
     ERR_load_SSL_strings();
    #endif
     }
    最后将会进入函数:
    static void err_load_strings(int lib, ERR_STRING_DATA *str)
     {
     while (str->error)
      {
      str->error|=ERR_PACK(lib,0,0);
      ERRFN(err_set_item)(str);
      str++;
      }
     }
    当中:
    #define ERR_PACK(l,f,r)  (((((unsigned long)l)&0xffL)*0x1000000)| /
        ((((unsigned long)f)&0xfffL)*0x1000)| /
        ((((unsigned long)r)&0xfffL)))
    #define ERRFN(a) err_fns->cb_##a
    ERRFN(err_set_item)(str)的实际函数实现为:
    static ERR_STRING_DATA *int_err_set_item(ERR_STRING_DATA *d)
     {
     ERR_STRING_DATA *p;
     LHASH *hash;
     err_fns_check();
     hash = ERRFN(err_get)(1);
     if (!hash)
      return NULL;
     CRYPTO_w_lock(CRYPTO_LOCK_ERR);
     p = (ERR_STRING_DATA *)lh_insert(hash, d);
     CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
     return p;
     }
    Lh_insert()将错误信息插入到一个链表中
    如关于加密算法的错误信息:
    /* crypto/err/err.c */
    static ERR_STRING_DATA ERR_str_functs[]=
    ……
    static ERR_STRING_DATA ERR_str_libraries[]=
    ……
    static ERR_STRING_DATA ERR_str_reasons[]=
    ……
     
    2.2 SSLeay_add_ssl_algorithms()
    这实际是个宏:
    #define OpenSSL_add_ssl_algorithms()    SSL_library_init()
    #define SSLeay_add_ssl_algorithms() SSL_library_init()
    实际函数为SSL_library_init(),函数比較简单,就是载入各种加密和HASH算法:
    /* ssl/ssl_algs.c */
    int SSL_library_init(void)
     {
    #ifndef OPENSSL_NO_DES
     EVP_add_cipher(EVP_des_cbc());
     EVP_add_cipher(EVP_des_ede3_cbc());
    #endif
    #ifndef OPENSSL_NO_IDEA
     EVP_add_cipher(EVP_idea_cbc());
    #endif
    #ifndef OPENSSL_NO_RC4
     EVP_add_cipher(EVP_rc4());
    #endif 
    #ifndef OPENSSL_NO_RC2
     EVP_add_cipher(EVP_rc2_cbc());
    #endif
    #ifndef OPENSSL_NO_AES
     EVP_add_cipher(EVP_aes_128_cbc());
     EVP_add_cipher(EVP_aes_192_cbc());
     EVP_add_cipher(EVP_aes_256_cbc());
    #endif
    #ifndef OPENSSL_NO_MD2
     EVP_add_digest(EVP_md2());
    #endif
    #ifndef OPENSSL_NO_MD5
     EVP_add_digest(EVP_md5());
     EVP_add_digest_alias(SN_md5,"ssl2-md5");
     EVP_add_digest_alias(SN_md5,"ssl3-md5");
    #endif
    #ifndef OPENSSL_NO_SHA
     EVP_add_digest(EVP_sha1()); /* RSA with sha1 */
     EVP_add_digest_alias(SN_sha1,"ssl3-sha1");
     EVP_add_digest_alias(SN_sha1WithRSAEncryption,SN_sha1WithRSA);
    #endif
    #if !defined(OPENSSL_NO_SHA) && !defined(OPENSSL_NO_DSA)
     EVP_add_digest(EVP_dss1()); /* DSA with sha1 */
     EVP_add_digest_alias(SN_dsaWithSHA1,SN_dsaWithSHA1_2);
     EVP_add_digest_alias(SN_dsaWithSHA1,"DSS1");
     EVP_add_digest_alias(SN_dsaWithSHA1,"dss1");
    #endif
     /* If you want support for phased out ciphers, add the following */
    #if 0
     EVP_add_digest(EVP_sha());
     EVP_add_digest(EVP_dss());
    #endif
     return(1);
     }

    2.3 SSL23_server_method()
    建立服务器端的方法库,这是个通用函数,可动态选择SSL协议。假设想固定协议,能够仅仅用SSLv2_server_method(), SSLv3_server_method() 等函数来初始化,该函数返回一个SSL_METHOD结构:
    /* ssl/ssl.h */
    /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
    typedef struct ssl_method_st
     {
     int version; // 版本号号
     int (*ssl_new)(SSL *s); // 建立新SSL
     void (*ssl_clear)(SSL *s); // 清除SSL
     void (*ssl_free)(SSL *s);  // 释放SSL
     int (*ssl_accept)(SSL *s); // server接受SSL连接
     int (*ssl_connect)(SSL *s); // client的SSL连接
     int (*ssl_read)(SSL *s,void *buf,int len); // SSL读
     int (*ssl_peek)(SSL *s,void *buf,int len); // SSL查看数据
     int (*ssl_write)(SSL *s,const void *buf,int len); // SSL写
     int (*ssl_shutdown)(SSL *s); // SSL半关闭
     int (*ssl_renegotiate)(SSL *s); // SSL重协商
     int (*ssl_renegotiate_check)(SSL *s); // SSL重协商检查
     long (*ssl_ctrl)(SSL *s,int cmd,long larg,void *parg); // SSL控制
     long (*ssl_ctx_ctrl)(SSL_CTX *ctx,int cmd,long larg,void *parg); //SSL上下文控制
     SSL_CIPHER *(*get_cipher_by_char)(const unsigned char *ptr); // 通过名称获取SSL的算法
     int (*put_cipher_by_char)(const SSL_CIPHER *cipher,unsigned char *ptr);
     int (*ssl_pending)(SSL *s);
     int (*num_ciphers)(void); // 算法数
     SSL_CIPHER *(*get_cipher)(unsigned ncipher); // 获取算法
     struct ssl_method_st *(*get_ssl_method)(int version);
     long (*get_timeout)(void); // 超时
     struct ssl3_enc_method *ssl3_enc; /* Extra SSLv3/TLS stuff */ // SSL3加密
     int (*ssl_version)(); // SSL版本号
     long (*ssl_callback_ctrl)(SSL *s, int cb_id, void (*fp)()); // SSL控制回调函数
     long (*ssl_ctx_callback_ctrl)(SSL_CTX *s, int cb_id, void (*fp)()); //SSL上下文控制回调函数
     } SSL_METHOD;

    /* ssl/s23_srvr.c */
    SSL_METHOD *SSLv23_server_method(void)
     {
     static int init=1;
    // 静态量,每一个进程仅仅初始化一次
     static SSL_METHOD SSLv23_server_data;
     if (init)
      {
      CRYPTO_w_lock(CRYPTO_LOCK_SSL_METHOD);
      if (init)
       {
    // ssl23的基本方法结构
       memcpy((char *)&SSLv23_server_data,
        (char *)sslv23_base_method(),sizeof(SSL_METHOD));
    // 服务器,所以要定义accept方法
       SSLv23_server_data.ssl_accept=ssl23_accept;
    // 依据SSL的版本号设置SSL的详细方法函数
       SSLv23_server_data.get_ssl_method=ssl23_get_server_method;
       init=0;
       }
      CRYPTO_w_unlock(CRYPTO_LOCK_SSL_METHOD);
      }
     return(&SSLv23_server_data);
     }

    static SSL_METHOD *ssl23_get_server_method(int ver)
     {
    #ifndef OPENSSL_NO_SSL2
     if (ver == SSL2_VERSION)
      return(SSLv2_server_method());
    #endif
     if (ver == SSL3_VERSION)
      return(SSLv3_server_method());
     else if (ver == TLS1_VERSION)
      return(TLSv1_server_method());
    // 随着TLS1.1(RFC4346)的推出,预计不久将出现TLSv1_1_server_method()
     else
      return(NULL);
     }
    // SSL23的方法基本数据定义
    /* ssl/s23_lib.c */
    SSL_METHOD *sslv23_base_method(void)
     {
     return(&SSLv23_data);
     }
    static SSL_METHOD SSLv23_data= {
     TLS1_VERSION,
     tls1_new,
     tls1_clear,
     tls1_free,
     ssl_undefined_function,
     ssl_undefined_function,
     ssl23_read,
     ssl23_peek,
     ssl23_write,
     ssl_undefined_function,
     ssl_undefined_function,
     ssl_ok,
     ssl3_ctrl,
     ssl3_ctx_ctrl,
     ssl23_get_cipher_by_char,
     ssl23_put_cipher_by_char,
     ssl_undefined_function,
     ssl23_num_ciphers,
     ssl23_get_cipher,
     ssl_bad_method,
     ssl23_default_timeout,
     &ssl3_undef_enc_method,
     ssl_undefined_function,
     ssl3_callback_ctrl,
     ssl3_ctx_callback_ctrl,
     };
    以SSL3的server方法函数为例,其它方法相似:
    /* ssl/s3_srvr.c */
    SSL_METHOD *SSLv3_server_method(void)
     {
     static int init=1;
     static SSL_METHOD SSLv3_server_data;
    // 仅仅初始化一次
     if (init)
      {
      CRYPTO_w_lock(CRYPTO_LOCK_SSL_METHOD);
      if (init)
       {
    // ssl3的基本方法结构
       memcpy((char *)&SSLv3_server_data,(char *)sslv3_base_method(),
        sizeof(SSL_METHOD));
    // ssl3的接受方法
       SSLv3_server_data.ssl_accept=ssl3_accept;
    // ssl3获取服务器的方法函数
       SSLv3_server_data.get_ssl_method=ssl3_get_server_method;
       init=0;
       }
       
      CRYPTO_w_unlock(CRYPTO_LOCK_SSL_METHOD);
      }
     return(&SSLv3_server_data);
     }
    // SSL3的方法基本数据定义
    /* ssl/s3_lib.c */
    static SSL_METHOD SSLv3_data= {
     SSL3_VERSION,
     ssl3_new,
     ssl3_clear,
     ssl3_free,
     ssl_undefined_function,
     ssl_undefined_function,
     ssl3_read,
     ssl3_peek,
     ssl3_write,
     ssl3_shutdown,
     ssl3_renegotiate,
     ssl3_renegotiate_check,
     ssl3_ctrl,
     ssl3_ctx_ctrl,
     ssl3_get_cipher_by_char,
     ssl3_put_cipher_by_char,
     ssl3_pending,
     ssl3_num_ciphers,
     ssl3_get_cipher,
     ssl_bad_method,
     ssl3_default_timeout,
     &SSLv3_enc_data,
     ssl_undefined_function,
     ssl3_callback_ctrl,
     ssl3_ctx_callback_ctrl,
     };
     
    2.4 SSL23_client_method()

    和server端的事实上是同样的,仅仅是不定义结构中的ssl_accept而是定义ssl_connnect:
    SSL_METHOD *SSLv23_client_method(void)
     {
     static int init=1;
     static SSL_METHOD SSLv23_client_data;
     if (init)
      {
      CRYPTO_w_lock(CRYPTO_LOCK_SSL_METHOD);
      if (init)
       {
       memcpy((char *)&SSLv23_client_data,
        (char *)sslv23_base_method(),sizeof(SSL_METHOD));
       SSLv23_client_data.ssl_connect=ssl23_connect;
       SSLv23_client_data.get_ssl_method=ssl23_get_client_method;
       init=0;
       }
      CRYPTO_w_unlock(CRYPTO_LOCK_SSL_METHOD);
      }
     return(&SSLv23_client_data);
     }
     
    2.5 SSL_CTX_new ()
    该函数依据SSL方法获取一个SSL上下文结构,该结构定义为:
    /* ssl/ssl.h */
    struct ssl_ctx_st
     {
     SSL_METHOD *method;
     STACK_OF(SSL_CIPHER) *cipher_list;
     /* same as above but sorted for lookup */
     STACK_OF(SSL_CIPHER) *cipher_list_by_id;
     struct x509_store_st /* X509_STORE */ *cert_store;
     struct lhash_st /* LHASH */ *sessions; /* a set of SSL_SESSIONs */
     /* Most session-ids that will be cached, default is
      * SSL_SESSION_CACHE_MAX_SIZE_DEFAULT. 0 is unlimited. */
     unsigned long session_cache_size;
     struct ssl_session_st *session_cache_head;
     struct ssl_session_st *session_cache_tail;
     /* This can have one of 2 values, ored together,
      * SSL_SESS_CACHE_CLIENT,
      * SSL_SESS_CACHE_SERVER,
      * Default is SSL_SESSION_CACHE_SERVER, which means only
      * SSL_accept which cache SSL_SESSIONS. */
     int session_cache_mode;
     /* If timeout is not 0, it is the default timeout value set
      * when SSL_new() is called.  This has been put in to make
      * life easier to set things up */
     long session_timeout;
     /* If this callback is not null, it will be called each
      * time a session id is added to the cache.  If this function
      * returns 1, it means that the callback will do a
      * SSL_SESSION_free() when it has finished using it.  Otherwise,
      * on 0, it means the callback has finished with it.
      * If remove_session_cb is not null, it will be called when
      * a session-id is removed from the cache.  After the call,
      * OpenSSL will SSL_SESSION_free() it. */
     int (*new_session_cb)(struct ssl_st *ssl,SSL_SESSION *sess);
     void (*remove_session_cb)(struct ssl_ctx_st *ctx,SSL_SESSION *sess);
     SSL_SESSION *(*get_session_cb)(struct ssl_st *ssl,
      unsigned char *data,int len,int *copy);
     struct
      {
      int sess_connect; /* SSL new conn - started */
      int sess_connect_renegotiate;/* SSL reneg - requested */
      int sess_connect_good; /* SSL new conne/reneg - finished */
      int sess_accept; /* SSL new accept - started */
      int sess_accept_renegotiate;/* SSL reneg - requested */
      int sess_accept_good; /* SSL accept/reneg - finished */
      int sess_miss;  /* session lookup misses  */
      int sess_timeout; /* reuse attempt on timeouted session */
      int sess_cache_full; /* session removed due to full cache */
      int sess_hit;  /* session reuse actually done */
      int sess_cb_hit; /* session-id that was not
          * in the cache was
          * passed back via the callback.  This
          * indicates that the application is
          * supplying session-id's from other
          * processes - spooky :-) */
      } stats;
     int references;
     /* if defined, these override the X509_verify_cert() calls */
     int (*app_verify_callback)(X509_STORE_CTX *, void *);
     void *app_verify_arg;
     /* before OpenSSL 0.9.7, 'app_verify_arg' was ignored
      * ('app_verify_callback' was called with just one argument) */
     /* Default password callback. */
     pem_password_cb *default_passwd_callback;
     /* Default password callback user data. */
     void *default_passwd_callback_userdata;
     /* get client cert callback */
     int (*client_cert_cb)(SSL *ssl, X509 **x509, EVP_PKEY **pkey);
     CRYPTO_EX_DATA ex_data;
     const EVP_MD *rsa_md5;/* For SSLv2 - name is 'ssl2-md5' */
     const EVP_MD *md5; /* For SSLv3/TLSv1 'ssl3-md5' */
     const EVP_MD *sha1;   /* For SSLv3/TLSv1 'ssl3->sha1' */
     STACK_OF(X509) *extra_certs;
     STACK_OF(SSL_COMP) *comp_methods; /* stack of SSL_COMP, SSLv3/TLSv1 */

     /* Default values used when no per-SSL value is defined follow */
     void (*info_callback)(const SSL *ssl,int type,int val); /* used if SSL's info_callback is NULL */
     /* what we put in client cert requests */
     STACK_OF(X509_NAME) *client_CA;

     /* Default values to use in SSL structures follow (these are copied by SSL_new) */
     unsigned long options;
     unsigned long mode;
     long max_cert_list;
     struct cert_st /* CERT */ *cert;
     int read_ahead;
     /* callback that allows applications to peek at protocol messages */
     void (*msg_callback)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg);
     void *msg_callback_arg;
     int verify_mode;
     int verify_depth;
     unsigned int sid_ctx_length;
     unsigned char sid_ctx[SSL_MAX_SID_CTX_LENGTH];
     int (*default_verify_callback)(int ok,X509_STORE_CTX *ctx); /* called 'verify_callback' in the SSL */
     /* Default generate session ID callback. */
     GEN_SESSION_CB generate_session_id;
     int purpose;  /* Purpose setting */
     int trust;  /* Trust setting */
     int quiet_shutdown;
     };

    typedef struct ssl_ctx_st SSL_CTX;
    /* ssl/ssl_lib.h */
    SSL_CTX *SSL_CTX_new(SSL_METHOD *meth)
     {
     SSL_CTX *ret=NULL;
     
     if (meth == NULL)
      {
      SSLerr(SSL_F_SSL_CTX_NEW,SSL_R_NULL_SSL_METHOD_PASSED);
      return(NULL);
      }
     if (SSL_get_ex_data_X509_STORE_CTX_idx() < 0)
      {
      SSLerr(SSL_F_SSL_CTX_NEW,SSL_R_X509_VERIFICATION_SETUP_PROBLEMS);
      goto err;
      }
    // 分配上下文的内存空间
     ret=(SSL_CTX *)OPENSSL_malloc(sizeof(SSL_CTX));
     if (ret == NULL)
      goto err;
     memset(ret,0,sizeof(SSL_CTX));
     
    // 初始化上下文的结构參数
     ret->method=meth;
     ret->cert_store=NULL;
     ret->session_cache_mode=SSL_SESS_CACHE_SERVER;
     ret->session_cache_size=SSL_SESSION_CACHE_MAX_SIZE_DEFAULT;
     ret->session_cache_head=NULL;
     ret->session_cache_tail=NULL;
     /* We take the system default */
     ret->session_timeout=meth->get_timeout();
     ret->new_session_cb=0;
     ret->remove_session_cb=0;
     ret->get_session_cb=0;
     ret->generate_session_id=0;
     memset((char *)&ret->stats,0,sizeof(ret->stats));
     ret->references=1;
     ret->quiet_shutdown=0;
    /* ret->cipher=NULL;*/
    /* ret->s2->challenge=NULL;
     ret->master_key=NULL;
     ret->key_arg=NULL;
     ret->s2->conn_id=NULL; */
     ret->info_callback=NULL;
     ret->app_verify_callback=0;
     ret->app_verify_arg=NULL;
     ret->max_cert_list=SSL_MAX_CERT_LIST_DEFAULT;
     ret->read_ahead=0;
     ret->msg_callback=0;
     ret->msg_callback_arg=NULL;
     ret->verify_mode=SSL_VERIFY_NONE;
     ret->verify_depth=-1; /* Don't impose a limit (but x509_lu.c does) */
     ret->sid_ctx_length=0;
     ret->default_verify_callback=NULL;
     if ((ret->cert=ssl_cert_new()) == NULL)
      goto err;
     ret->default_passwd_callback=0;
     ret->default_passwd_callback_userdata=NULL;
     ret->client_cert_cb=0;
     ret->sessions=lh_new(LHASH_HASH_FN(SSL_SESSION_hash),
       LHASH_COMP_FN(SSL_SESSION_cmp));
     if (ret->sessions == NULL) goto err;
     ret->cert_store=X509_STORE_new();
     if (ret->cert_store == NULL) goto err;
     
    // 建立加密算法链表
     ssl_create_cipher_list(ret->method,
      &ret->cipher_list,&ret->cipher_list_by_id,
      SSL_DEFAULT_CIPHER_LIST);
     if (ret->cipher_list == NULL
         || sk_SSL_CIPHER_num(ret->cipher_list) <= 0)
      {
      SSLerr(SSL_F_SSL_CTX_NEW,SSL_R_LIBRARY_HAS_NO_CIPHERS);
      goto err2;
      }
     
    // 定义上下文结构中HASH算法
     if ((ret->rsa_md5=EVP_get_digestbyname("ssl2-md5")) == NULL)
      {
      SSLerr(SSL_F_SSL_CTX_NEW,SSL_R_UNABLE_TO_LOAD_SSL2_MD5_ROUTINES);
      goto err2;
      }
     if ((ret->md5=EVP_get_digestbyname("ssl3-md5")) == NULL)
      {
      SSLerr(SSL_F_SSL_CTX_NEW,SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES);
      goto err2;
      }
     if ((ret->sha1=EVP_get_digestbyname("ssl3-sha1")) == NULL)
      {
      SSLerr(SSL_F_SSL_CTX_NEW,SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES);
      goto err2;
      }
     if ((ret->client_CA=sk_X509_NAME_new_null()) == NULL)
      goto err;
     
     CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL_CTX, ret, &ret->ex_data);
     ret->extra_certs=NULL;
    // 压缩算法
     ret->comp_methods=SSL_COMP_get_compression_methods();
     return(ret);
    err:
     SSLerr(SSL_F_SSL_CTX_NEW,ERR_R_MALLOC_FAILURE);
    err2:
     if (ret != NULL) SSL_CTX_free(ret);
     return(NULL);
     }

    ...待续...

     

  • 相关阅读:
    HDU 5585 Numbers
    HDU 3308 LCIS
    POJ 2991 Crane
    POJ 1436 Horizontally Visible Segments
    POJ 3667 Hotel
    HaiHongOJ 1003 God Wang
    【SDOI 2008】 递归数列
    5月19日省中提高组题解
    【HDU 1588】 Gauss Fibonacci
    【POJ 3233】Matrix Power Series
  • 原文地址:https://www.cnblogs.com/lcchuguo/p/4056506.html
Copyright © 2011-2022 走看看