openssl升级后ssh登录失败

我们目前大部分使用的openssl库还是基于TLS1.2协议的1.0.2版本系列,如果要支持更高的TLS1.3协议,就必须使用openssl的1.1.1版本或3.0版本 。升级openssl库有可能会导致SSL会话失败,我在升级 wincurl 时,意外的收获了一个函数 。这个函数非常的不起眼,但具有的现实意义却很大 。
大部分情况下如果你不调用该函数,并不影响SSL会话和通信,但有时会被某些服务器拒绝 。一旦被拒绝,查找具体的原因将变得非常痛苦 。这个函数的意义好比HTTP协议中HOST字段,它和NGINX反向代理的Server name有异曲同工之妙 。了解这个函数的意义 , 可能会让你今后在配置nginx反向代理时少走一些弯路 。
这个函数是 SSL_set_tlsext_host_name , 在介绍这个函数之前,我们先快速看看TLS协议和openssl的发展 。

虽然TLS1.3的标准自2018年就已发布,但目前国内几乎所有网站并没有增加对TLS 1.3的支持,大部分主流网站使用的还是基于TLS1.2的版本 。目前国内使用TLS1.3的好像只有知乎,其它诸如:新浪、网易、搜狐、腾讯、华为、京东、百度....都还是采用TLS1.2的标准 。
网站是否支持TLS1.3其实并不重要,重要的是浏览器是否支持TLS1.3协议 。好在目前市场上所有主流浏览器都已升级到了TLS1.3 。因此对于用户而言,不管是支持TLS1.3的网站还是支持TLS1.2的网站,访问起来都不是问题,或者说对终端用户而言这种访问是无感的 。
为何TLS3.0已经出现5年了,各大网络平台还是首选TLS1.2呢?估计还是出于对兼容和稳定的考虑 。如果贸然升级到1.3导致大量客户端无法访问从而丢失用户,是任何平台所无法承受的 。此外 , 支持TLS1.3的openssl版本也在不断完善中,在其未达到稳定前 , 最好还是使用稳定的1.2版本 。这大概就是目前几乎所有平台类网站还在使用TLS1.2的原因 。
此外 , 即使有的网站采用TLS1.3协议,也会继续提供对1.2的访问支持(向下兼容并保留所有TLS1.2的加密套件),除非该网站的运维人员强行使用TLS1.3的加密套件 。但如果这样做的话就会导致大量仍然使用1.2标准的客户端程序无法继续访问该网站,这也意味着该运维人员离下岗再就业不远了 。
这也是为什么我们即使不升级老版本的openssl库,也依然可以访问TLS1.3网站的原因 。
上面说的TLS1.2,1.3指的是TLS的协议 , 实现上述协议的是openssl库 。其中支持TLS1.3的openssl库目前有两个版本系列:一个是1.1.1系列 , 一个是3.0系列 。其中1.1.1更像是一个过渡版本,openssl团队承诺会支撑该版本到2023年9月11日,也就是明年911事件22周年之际(确实是一个值得纪念的日子)将停止更新1.1.1版本 。这就意味着大家还没开始普及使用1.1.1,它就已经结束了 。
【openssl升级后ssh登录失败】这个其实也不重要,因为3.0才是最终openssl的终极版本,直接跳过了2.0,从而体现了openssl的跨越式发展 。3.0版本是openssl团队主推版本 , 也是一个长期维护的版本,该版本会维护到2026年9月7日 。
虽然主流web浏览器都已支持TLS1.3,但浏览器只是客户端的一种,其它大部分客户端使用的还是openssl 1.0.2系列版本,甚至是1.0.1系列版本,也就是我们经常看到的libeay32.dll和ssleay32.dll 库,这些版本是不支持TLS1.3协议的 。比如工具类的postman、curl,以及应用类QQ、Foxmail、微信以及各种下载客户端程序 , 使用的可能还是老的openssl库 。openssl库在1.1.1及以上版本已经将库的导出名称改为libcrypto和libssl , 不过这只是前缀名 , 如果是1.1.1系列,则后缀为-1.1.dll,如果是3.0系列,则后缀为-3.dll,我们通过openssl的库名就能判断出该应用程序是否支持TLS1.3 。
升级到TLS1.3可以从openssl的官网(https://openssl.org)下载1.1.1或3.0版本的源码进行编译 。编译完毕后 , 我们只要替换openssl库,并重新配置并编译你的客户端程序即可 。
使用openssl库编写客户端程序的一般流程如下:先创建套接字,并连接到服务器,然后创建ssl,并绑定套接字,通过调动SSL_connect函数进行握手操作 , 成功后使用SSL_read和SSL_write进行业务通信 。
代码通常如下:
// 创建套接字,并连接到服务器 SOCKET s = socket(AF_INET, SOCK_STREAM, 0); struct hostent* hst = ::gethostbyname(pszServer); if(NULL == hst) return FALSE; unsigned long addr; struct sockaddr_in sockAddr; memcpy(&addr, hst->h_addr, hst->h_length); sockAddr.sin_family = AF_INET; sockAddr.sin_port = htons(nPort); sockAddr.sin_addr.S_un.S_addr = addr; // 连接到服务器 if(SOCKET_ERROR != ::connect(s, (struct sockaddr *)&sockAddr, sizeof(struct sockaddr_in))) return FALSE; // Openssl库初始化 OpenSSL_add_ssl_algorithms(); SSL_load_error_strings(); SSLeay_add_ssl_algorithms(); ERR_load_BIO_strings(); ctx = SSL_CTX_new(SSLv23_client_method()); // 创建ssl上下文,并绑定套接字 SSL* ssl = SSL_new (m_ctx); SSL_set_fd(m_ssl, s); // 开始ssl握手 int iRet = SSL_connect(m_ssl); if(1 != iRet) return FALSE; // 下面使用SSL_read或SSL_write进行通信


推荐阅读