OpenSSL源码之session

       简单聊一聊openssl中session的实现。

       通常来说在传输层上面形成了流的概念,即由源IP,目的IP,源端口,目的端口,以及传输层的协议构成了网络中的一条虚拟传输线路,称之为流。由于网络协议是分层的,也就是说每一层都存在着相应的连接概念 ,因此流是传输层区分不同连接的概念,而对于http层来说区分不同http连接的方法可以使用不同的GET请求,不同的cookie,不同的UA等等,可以说是不同的请求头,因为承载什么样的数据其实不是网络协议的所规定的了。

       对于高层协议来说,不同会话之间的关系不能够简单的通过流来区分,因为同一条流上面可以承载多个会话,例如同一个tcp流上面可以有多个http连接,同一个tcp流上面也可以由多个ssl会话(重协商)。表示不同会话之间关系,在http协议中使用referer等头域,那么在ssl协议中使用session id等方式。 那么对于ssl层来说,区分不同连接的方法就是不同的client请求,包括版本,加密套件,不同的server hello等。在openssl源码中使用ssl_st来区分不同的会话连接,该结构体主要来进行ssl握手过程以及传输具体的应用数据。

       下面简单的说一下session id在openssl源码中是如何实现的。 整体的流程是很简单的: 1,初次会话连接过程在client hello中session id字段为空 。2,服务器生成session id 保存,同时传输给客户端。 3,下一次发出请求的时候client hello带上相应session id ,服务器决定是否复用。

       由于session id 是记录在ssl_session_st结构中,该结构来记录不同的会话信息,如下:

struct ssl_session_st { int ssl_version; /* what ssl version session info is being kept * in here? */ size_t master_key_length;

/* TLSv1.3 early_secret used for external PSKs */
unsigned char early_secret[EVP_MAX_MD_SIZE];
/*
 * For <=TLS1.2 this is the master_key. For TLS1.3 this is the resumption
 * master secret
 */
unsigned char master_key[TLS13_MAX_RESUMPTION_MASTER_LENGTH];
/* session_id - valid? */
size_t session_id_length;
unsigned char session_id[SSL_MAX_SSL_SESSION_ID_LENGTH];
/*
 * this is used to determine whether the session is being reused in the
 * appropriate context. It is up to the application to set this, via
 * SSL_new
 */
size_t sid_ctx_length;
unsigned char sid_ctx[SSL_MAX_SID_CTX_LENGTH];
ifndef OPENSSL_NO_PSK

char *psk_identity_hint;
char *psk_identity;
endif

/*
 * Used to indicate that session resumption is not allowed. Applications
 * can also set this bit for a new session via not_resumable_session_cb
 * to disable session caching and tickets.
 */
int not_resumable;
/* This is the cert and type for the other end. */
X509 *peer;
int peer_type;
/* Certificate chain peer sent. */
STACK_OF(X509) *peer_chain;
/*
 * when app_verify_callback accepts a session where the peer's
 * certificate is not ok, we must remember the error for session reuse:
 */
long verify_result;         /* only for servers */
CRYPTO_REF_COUNT references;
long timeout;
long time;
unsigned int compress_meth; /* Need to lookup the method */
const SSL_CIPHER *cipher;
unsigned long cipher_id;    /* when ASN.1 loaded, this needs to be used to
                             * load the 'cipher' structure */
STACK_OF(SSL_CIPHER) *ciphers; /* shared ciphers? */
CRYPTO_EX_DATA ex_data;     /* application specific data */
/*
 * These are used to make removal of session-ids more efficient and to
 * implement a maximum cache size.
 */
struct ssl_session_st *prev, *next;

struct {
    char *hostname;
ifndef OPENSSL_NO_EC

size_t ecpointformats_len;
    unsigned char *ecpointformats; /* peer's list */
endif /* OPENSSL_NO_EC */

size_t supportedgroups_len;
    uint16_t *supportedgroups; /* peer's list */
/* RFC4507 info */
    unsigned char *tick; /* Session ticket */
    size_t ticklen;      /* Session ticket length */
    /* Session lifetime hint in seconds */
    unsigned long tick_lifetime_hint;
    uint32_t tick_age_add;
    unsigned char *tick_nonce;
    size_t tick_nonce_len;
    int tick_identity;
    /* Max number of bytes that can be sent as early data */
    uint32_t max_early_data;
    /* The ALPN protocol selected for this session */
    unsigned char *alpn_selected;
    size_t alpn_selected_len;
} ext;
ifndef OPENSSL_NO_SRP

char *srp_username;
endif

uint32_t flags;
CRYPTO_RWLOCK *lock;
};

       openssl使用ssl_session_st结构来记录不同的会话信息,包括unsigned char master_key[TLS13_MAX_RESUMPTION_MASTER_LENGTH]主密钥信息,unsigned char session_id[SSL_MAX_SSL_SESSION_ID_LENGTH],具体的id字符串,X509 *peer证书信息,const SSL_CIPHER *cipher密钥信息等,可以看到这些信息是两个会话之间存在关联的一些要素。

       对于ssl_session_st这种会话消息的建立,openssl提供的函数是ssl_get_new_session,在openssl源码中,会话的建立有两处,分别位于客户端的处理流程tls_construct_client_hello函数中以及服务器的处理流程tls_post_process_client_hello函数中。

       在1.1.0f代码中ssl_get_new_session函数中在生成ssl_session_st这种结构类型变量的同时,还会生成相应的session id,在最新的代码中session id 的生成被分离成为一个单独的函数。session id 默认的生成函数为def_generate_session_id,然后调用相应的随机数生成函数。当然用户也可以设置自己的seession id生成函数,相应的设置函数为SSL_set_generate_session_id

       在生成每一个seession id 之后都会调用相应的SSL_has_matching_session_id函数来确保全局哈希表中的session id是唯一的,这个全局哈希表后面在说。ssl_get_prev_session(SSL *s, const PACKET *ext, const PACKET *session_id) 函数是根据一个session id 来获取相应的ssl_session_st结构体(这个函数有个缺点就是入参为PACKET *,然后在该函数内部做了转换PACKET_copy_all(session_id, data.session_id,sizeof(data.session_id), &local_len) 正常来说session_id是一个字符串数组,应该传输参数为字符串指针,相应的转换在ssl_get_prev_session之前完成才是最好的,这也是ssl代码写的不太好的原因) 该函数为唯一被调用的位置是在 tls_process_client_hello函数中,也就是服务器在读取client hello时候决定究竟是新建session还是复用以前的session。

       当然对于客户端来和服务器来说说这些session如何进行管理。在tls_finish_handshake中会调用ssl_update_cache函数来对客户端和服务器进行更新session相关内容。在ssl_update_cache函数中会调用SSL_CTX_add_session函数向全局的哈希表中增加前面所建立的session(这张哈希表是在SSL_CTX_new函数被调用的时候初始化的)。除此之外还会调用函数SSL_CTX_flush_sessions来保证客户端每存储255个session,主动老化一次哈希表,确保占用资源不会过多。 除此之外,对于新增的session,还需要调用SSL_SESSION_list_add函数,将相应的session变量加入到SSL_CTX变量中的ctx->session_cache_head 以及ctx->session_cache_tail构成的链表之中。

       那么服务器端允许多少个sessions呢?在SSL_CTX_new中默认了ret->session_cache_size = SSL_SESSION_CACHE_MAX_SIZE_DEFAULT;表示默认能够缓存的最大数量。当然也可以通过SSL_CTX_ctrl函数中的SSL_CTRL_SET_SESS_CACHE_SIZE分支来设置具体的 session_cache_size

       以上就是对于openssl session的一些理解。

       本文为CSDN村中少年原创文章,转载记得加上小尾巴偶,博主链接这里

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

村中少年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值