在 C 客户端/服务器应用程序上重用 SSL 会话

Posted

技术标签:

【中文标题】在 C 客户端/服务器应用程序上重用 SSL 会话【英文标题】:reuse SSL session on C client/server application 【发布时间】:2013-01-18 11:24:18 【问题描述】:

我正在编写一个客户端/服务器应用程序,我们将使用 SSL 通信。我很难弄清楚为什么外部缓存不起作用。我不想使用内部缓存,因为我想将会话存储在数据库中。尽管我已经为SSL_CTX_sess_set_get_cbSSL_CTX_sess_set_new_cb, SSL_CTX_sess_set_get_cb 注册了一个callabck,但不会在服务器端调用它,并且在每次连接时都会创建一个新的SSL_SESSION。客户端似乎没有在握手时发送 session_id 但我不确定并且不知道如何测试它。在客户端,我使用 SSL_set_session 将会话附加到 SSL 连接,并且我在 Ubuntu 上使用 openSSL 0.9.8。

//for server side
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER | SSL_SESS_CACHE_NO_INTERNAL | SSL_SESS_CACHE_NO_AUTO_CLEAR );

//for client side
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL | SSL_SESS_CACHE_NO_AUTO_CLEAR );

基本上客户端和服务器的流程都是这样的。为了清楚起见,我删除了错误处理。如果成功,应用程序将通过所有这些。

SSL_library_init();
SSL_load_error_strings();

ctx = SSL_CTX_new( SSLv23_method() );

SSL_CTX_set_info_callback(ctx, &apps_ssl_info_callback );
SSL_CTX_load_verify_locations( ctx,calist_file, calist_path );
SSL_CTX_set_default_verify_paths(ctx);
SSL_CTX_use_certificate_file(ctx,certfile,SSL_FILETYPE_PEM);
SSL_CTX_set_default_passwd_cb(ctx,password_cb);
SSL_CTX_set_default_passwd_cb_userdata(ctx, password );
SSL_CTX_use_PrivateKey_file(ctx,keyfile,SSL_FILETYPE_PEM);
SSL_CTX_check_private_key(ctx) );
SSL_CTX_set_default_passwd_cb(ctx,password_cb);
SSL_CTX_set_default_passwd_cb_userdata(ctx, password );
SSL_CTX_use_PrivateKey_file(ctx,keyfile,SSL_FILETYPE_PEM);
SSL_CTX_check_private_key(ctx);
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE, verify_callback);
SSL_CTX_set_client_CA_list( ctx, SSL_load_client_CA_file( calist_file ) );
SSL_CTX_set_verify_depth(ctx,2);

/我的例程处理获取 DH 参数并创建 RSA 临时密钥和随机性/

RAND_load_file( random, SIZE );
load_dh_params(ctx,DHFILE); 
generate_eph_rsa_key(ctx);

SSL_CTX_set_session_id_context(ctx,(void*)&s_server_session_id_context,sizeof (s_server_session_id_context) );
mydata_index = SSL_get_ex_new_index(0, "mydata index", NULL, NULL, NULL);

SSL_CTX_set_session_cache_mode(ctx, (ctx, SSL_SESS_CACHE_SERVER | SSL_SESS_CACHE_NO_INTERNAL |  SSL_SESS_CACHE_NO_AUTO_CLEAR );
SSL_CTX_sess_set_get_cb(ctx, get_session_cb);
SSL_CTX_sess_set_new_cb(ctx, new_session_cb );
SSL_CTX_sess_set_remove_cb(ctx, remove_session_cb );

我想要的是当客户端连接时应该调用 get_session_cb 并且在那里我将根据一些标准选择会话 ID(将来会话 ID 将具有某种含义(主机 ID)不仅仅是随机数,而是这个部分它现在没有实施)。如果没有符合我的条件的会话,则应用程序将通过 new_session_cb 创建一个。服务器应该具有相同的行为,首先将尝试在其会话池中查找会话,如果查找不成功,则仅创建一个新会话。

我不确定我想要为客户提供的东西是否真的可行。所以这就是我什至尝试获得一个会话并通过 SSL_set_session( ssl, session ) 手动设置它的方式。

谢谢,

【问题讨论】:

【参考方案1】:

如果没有看到您的代码中的所有其他 OpenSSL 调用,很难说,我们真的需要一个独立的示例来展示该问题。话虽如此,这听起来像是使用会话票证扩展的RFC 5077 server-stateless 会话恢复可能会出现问题。关闭它可以避免我在外部会话中遇到的一些问题:

SSL_CTX_set_options(sslctx, SSL_OP_NO_TICKET);

但是,如果您想走服务器无状态会话恢复之路,则完全可以预料,在服务器端不会调用您的外部会话缓存——这正是没有服务器的会话恢复点——状态。

【讨论】:

(OpenSSL 1.1.1) 我有一种情况,在服务器端成功调用BIO_do_handshake 后,我无法获得有效的会话 ID(在服务器端) - 它返回长度 0 (另外,没有调用与会话 ID 相关的回调)——我想这毕竟是“server-stateless”的意义所在。但是,客户端(第三方应用程序)稍后仍然能够使用其 ClientHello 消息中的有效会话 ID 进行连接。添加 SSL_CTX_set_options(sslctx, SSL_OP_NO_TICKET) 为我“修复”了这个问题 - 服务器在握手后现在有一个有效的会话 ID。

以上是关于在 C 客户端/服务器应用程序上重用 SSL 会话的主要内容,如果未能解决你的问题,请参考以下文章

ssl缓存是啥意思

SSL缓存是啥

让 pyOpenSSL 客户端使用 SSL 会话恢复

如何在 Android 上进行 SSL 会话恢复

重用 HttpURLConnection 以保持会话活动

SSL 重点SSL会话步骤