Search
Write a publication
Pull to refresh
0
0
Кирилл @MrFuNTiK

Программист С, С++.

Send message

Если речь об аутентичном CRL, выпущенном УЦ на момент действия сертификата, то этот CRL должен быть отклонен, если текущая дата больше даты notAfter в CRL. Если речь создании CRL третьей стороной от имени УЦ, то это уже компрометация УЦ, и вопрос должен решать CRL вышестоящего УЦ

Такова логика OpenSSL, и Вы с этим ничего не сделаете. Причем в данном примере коллбэк не подавляет ошибку, просто выводит код ошибки, а параметр ok пробрасывается без изменения. Но суть даже не в этом. OpenSSL не умеет собирать полную информацию, он всегда будет завершать функцию при возникновении первой же ошибки.

Недавно столкнулся с необходимостью при проверке подписи различать ошибки выполнения (например, ошибки выделения памяти) от криптографических (не сошелся хэш или подпись) и проверок цепочек сертификатов. Да еще и так, чтобы при обнаружении ошибок в крипте или цепочках проверка не завершалась, а продолжалась дальше. При ошибках выполнения, понятно, дальше идти не имеет смысла. Сложность кода сильно возрасла, причем пришлось забирать и править часть реализации OpenSSL. Квест был интересный, в прочем, он все еще в процессе.

Контексты OpenSSL действительно удобны. Здесь нет на мой взгляд существенного уточнения о том, что контекст проверки сертификата одноразовый, то есть после того, как контекст был использован для проверки одного сертификата, его нельзя сразу же повторно переиспользовать для проверки другого сертификата. Нужно либо сбрасывать контекст функцией X509_STORE_CTX_reset(), либо создавать новый, то есть как-то так:

STACK_OF( X509 )* certsToVerify = ...; // Сертификаты, которые собираемся
                                       // проверить.
STACK_OF( X509 )* untrusted = ...;     // Промежуточные недоверенные сертификаты,
                                       // которые могут быть использованы для
                                       // построения цепочек.
X509_STORE* store = ...;               // Хранилище доверенных сертификатов,
                                       // уже сконфигурированное нужным образом.

X509_STORE_CTX* ctx = X509_STORE_CTX_new();
if( !ctx )
{
    HandleError();
}

for( int i = 0; i < sk_X509_num( certsToVerify ); ++i )
{
    X509* cert = sk_X509_value( certsToVerify, i );
    if( !X509_STORE_CTX_init( ctx, store, cert, untrusted ) )
    {
        HandleError();
    }

    if( 1 > X509_STORE_CTX_verify( ctx ) )
    {
        const char* err = X509_verify_cert_error_string( X509_STORE_CTX_get_error( ctx ) );
        X509_NAME* X509_get_subject_name( cert );
        fprintf( stderr, "Verification failure: %s\n", err );
        X509_NAME_print_ex( stderr, name, 0, 0 );
    }
    X509_STORE_CTX_reset( ctx ); // Сбрасываем контекст для проверки следующего сертификата.
}

А сбрасывать контекст перед освобождением, как это делаете Вы, смысла не имеет.

Да и обертки над X509_STORE_load_path(), X509_STORE_load_file(), X509_STORE_add_cert() избыточны, так как функции OpenSSL возвращают 1 при успехе и 0 при ошибке, что и так без проблем кастится в плюсовый bool, а так только дополнительный вызов получается.

На самом деле проверка сертификатов - интересный процесс, там можно много разных коллбэков переопределить, задавать различные параметры проверки (например, время или назначение сертификата). Подумайте, может, захотите сделать более развернутую статью, многим будет полезно :)

Information

Rating
Does not participate
Location
Томск, Томская обл., Россия
Date of birth
Registered
Activity

Specialization

Backend Developer
Junior
Git
C++
C
Cmake