• 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);
     }

    ...待续...

     

  • 相关阅读:
    制作USB启动盘
    Custom Content and Formatting 富文本框批量上传 quill
    “从特殊到一般”的思想
    每个元素应该有 相同的概率 被返回。
    前缀和
    graphql 案例
    电脑关机后怎么计算时间 CMOS电池 时钟芯片 晶体振荡器 晶振 时钟晶振 谐振电容
    前端质量|基于业务驱动的前端性能有效实践案例
    Pull or Push
    分区表出现错误 分区错误
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/4238501.html
Copyright © 2020-2023  润新知