[疑難雜症]系統時間不對導致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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章