[疑难杂症]系统时间不对导致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:
FIXED & END
上一篇: openssl移植及错误解决