[疑难杂症]系统时间不对导致SSL连接失败

问题描述

我们某安卓盒子的客户端,每次开机第一次连接服务器大概率出现ssl错误导致连接失败,openssl返回的错误是:

SSL_connect error:00000001:lib(0):func(0):reason(1)

抓取网络pcap包,发现在ssl握手时,客户端收到服务器的证书认为证书无效,但是同样的证书过一会再连接,又可以建立连接。此问题仅发生在某特定型号的盒子

问题分析

分析了一下证书的认证过程,无外乎判断一下证书有效时间,双方支持的加密格式等等,最终发现是安卓端的时间有问题:系统是不保存时间的,每次开机从网络校时,经常出现校时延误甚至校时失败,拿一个2014年的初始时间去检查证书的时间,所以认定证书“过期”了。

这里一个坑的地方是,盒子上面显示的是桌面app获取的时间,不是底层系统的时间,底层系统的时间可以在shell里通过date命令查看。

另外一个坑,openssl的错误信息可能一次get不完,需要get多次才能把所有信息打印出来,修正了一下打印错误信息的代码

                char error_str[256];
                while (rc != 0) {
                    ERR_error_string_n(rc, error_str, sizeof(error_str));
                    g_warning("%s: SSL_connect %s", c->name, error_str);
                    rc = ERR_get_error();
                }

所以问题完整错误信息应该是:

SSL_connect error:00000001:lib(0):func(0):reason(1)
SSL_connect error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed

问题解决

作为一个第三方应用开发人员,对android rom的bug无可奈何,普通应用连设置系统时间的权限都都没有。当然可以通过设置证书的有效期在2014年开始规避,这显然不是好办法。

比较合理的办法是通过我们app先获取一个正确时间,再拿这个时间去校准,而不是让openssl使用系统返回的时间。

修改openssl的库,让openssl提供一个可以设置校准时间的接口:

int SSL_connect_ptime(SSL *s, time_t ptime)
{
    if (ptime)
        X509_VERIFY_PARAM_set_time(s->param, ptime);

    return SSL_connect(s);
}

用过ssl的同学应该熟悉这个SSL_connect(),增加一个openssl的接口必须在util/libssl.num文件上加上你的函数名,注意后面的序号和版本号

 SSL_COMP_get_id                         412	1_1_0d	EXIST::FUNCTION:
 SSL_COMP_get0_name                      413	1_1_0d	EXIST::FUNCTION:
+SSL_connect_ptime                       414	1_1_0d	EXIST::FUNCTION:

更新

其实后面查看openssl的api,并不需要更改openssl的源代码:

	X509_VERIFY_PARAM_set_time(SSL_get0_param(c->ssl), ssl_time);

FIXED & END

你可能感兴趣的:(工作笔记)