Получение сертификатов сайта

Практически любая, сколь-нибудь не стандартная задача выливается в часы малопродуктивного гугления, что печалит. Сегодня я искал ответ на вопрос, как в OSX получить сертификаты сайта, с которым ты планируешь общаться по HTTPS. До кучи дело осложняется тем, что все должно работать не только напрямую, но и через прокси.
Если говорить о Windows, данная задача решается довольно просто, благодаря библиотеке WinHTTP (кажется, ее так звать) и функции WinHttpQueryOption с флагом WINHTTP_OPTION_SERVER_CERT_CONTEXT, но мне-то нужно решение для OSX! И оно было найдено, как и ожидалось, в дебрях очень любимой мной библиотеки cURL.
Изначально я присматривался к функции обратного вызова, регистрируемой посредствам CURLOPT_SSL_CTX_FUNCTION. Решение, на первый взгляд годное, т.к. позволяет получить SSL_CTX, используя который можно вызвать SSL_connect и т.д. Но, оставался не решенным вопрос как добыть из cURL сокет установленного соединения, да и вообще, выглядело все это дело очень и очень криво.
Второй вариант оказался куда как более удачным: комбинация curl_easy_getinfo с CURLINFO_CERTINFO позволяет сделать практически то, что мне нужно:

// ...
curl_easy_setopt(curl, CURLOPT_CERTINFO, 1L);
// ...
union {
    struct curl_slist    *to_info;
    struct curl_certinfo *to_certinfo;
} ptr;

ptr.to_info = NULL;

res = curl_easy_getinfo(curl, CURLINFO_CERTINFO, &ptr.to_info);

if(!res && ptr.to_info) {

    for(int i = 0; i < ptr.to_certinfo->num_of_certs; i++) {
        for(struct curl_slist *slist = ptr.to_certinfo->certinfo[i]; slist; slist = slist->next)
        {
            if(strstr(slist->data, "Cert:"))
                printf("%s\n", slist->data+strlen("Cert:"));
        }
    }
}

Остается самая малость – слегка изменить конфигурацию cURL. Во-первых, так как нужно гарантировано получать сертификат вне зависимости от того, был ли он корректно проверен про цепочке, необходимо отключить проверки хоста и канала: CURLOPT_SSL_VERIFYPEER и CURLOPT_SSL_VERIFYHOST. Во-вторых, нужен именно сертификат, а не содержимое доступное по URL, что cURL так же может организовать, если об этом правильно попросить: CURLOPT_CONNECT_ONLY.
Сертификат возвращается в формате X.509 и может быть легко открыт любой стандартной читалкой сертификатов или OpenSSL-подобной библиотекой.

Leave a Reply