C: клиентская программа сообщает о сбое проверки сертификата SSL с помощью localCA

#c #linux #ssl #openssl #rhel

#c #linux #ssl #openssl #rhel

Вопрос:

Я пишу простую клиент-серверную программу TLS для безопасного обмена данными по сети. Изначально я создаю и запускаю как клиент, так и сервер на одном компьютере под управлением RHEL 8.2.

Во-первых, я использую пользовательский самоподписанный ssl-сертификат и ключ для своих программ. Я поместил RootCA.crt (мой пользовательский сертификат CA в /root/CA/RootCA.crt). Также скопировал файл RootCA.pem в /etc/pki/ca-trust/source/anchors/ и update-ca-trust enable затем update-ca-trust extract выполнил установку сертификата в систему. (Не уверен, нужно ли мне перезагрузить систему, чтобы она вступила в силу.)

Первоначально клиент и сервер могли обмениваться данными с помощью протокола TLS, пока я не добавил часть проверки сертификата в код на стороне клиента.

Фрагмент проверки сертификата:

 ctx = SSL_CTX_new(method);   /* Create new context */
    if ( ctx == NULL )
    {
        ERR_print_errors_fp(stderr);
        abort();
    }

    SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);

    SSL_CTX_set_verify_depth(ctx, 4);

    const long flags = SSL_OP_NO_SSLv2 |
                        SSL_OP_NO_SSLv3 |
                        SSL_OP_NO_TLSv1 |
                        SSL_OP_NO_TLSv1_1 |
                        SSL_OP_NO_COMPRESSION;
    SSL_CTX_set_options(ctx, flags);

    if(SSL_CTX_load_verify_locations(ctx, NULL, 
                "/root/CA/") == 0){
        ERR_print_errors_fp(stderr);
        abort();
    }

ssl = SSL_new(ctx);      /* create new SSL connection state */
    SSL_set_fd(ssl, server);    /* attach the socket descriptor */
    if ( SSL_connect(ssl) == FAIL )   /* perform the connection */
        ERR_print_errors_fp(stderr);
    else
    {

        sprintf(acClientRequest, "%s", cpRequestMessage);   /* construct reply */
        printf("nnConnected with %s encryptionn", SSL_get_ciphe

}
 

когда я запускаю серверную и клиентскую программы, я вижу следующую ошибку messafe =>

Onclient: 140736372886336:ошибка: 1416F086: Процедуры SSL: tls_process_server_certificate:сбой проверки сертификата: ssl / statem / statem_clnt.c: 1915:

На сервере: 140736022137664: ошибка: 14094418: Процедуры SSL: ssl3_read_bytes: предупреждение tlsv1 неизвестно ca: ssl / record / rec_layer_s3.c: 1543: номер предупреждения SSL 48

Не уверен, что происходит не так с процессом проверки сертификата. Может кто-нибудь подсказать мне, как исправить эту ошибку?

Ответ №1:

Простого копирования вашего rootCA.crt файла /root/CA/ недостаточно.

SSL_CTX_load_verify_locations явно указывает, что файлы в этом каталоге должны использовать определенный формат:

Если CApath не равен NULL, он указывает на каталог, содержащий сертификаты CA в формате PEM. Каждый файл содержит по одному сертификату центра сертификации. Поиск файлов осуществляется по хэш-значению имени субъекта ЦС, которое, следовательно, должно быть доступно. Если существует более одного сертификата CA с одинаковым значением хэша имени, расширение должно быть другим (например, 9d66eef0.0, 9d66eef0.1 и т.д.). Поиск выполняется в порядке добавочного номера, независимо от других свойств сертификатов. Используйте утилиту c_rehash для создания необходимых ссылок.

Поэтому убедитесь, что ваш rootCa.crt файл находится в формате PEM. А затем сгенерируйте необходимый хэш и переименуйте его соответствующим образом. Следующая команда генерирует хэш-значение. Переименуйте файл в <hashvalue>.0 .

 openssl x509 -inform PEM -subject_hash_old -in rootCa.crt | head -1
 

Если ваш код все еще не работает, я бы сначала проверил, работает ли ваш код вообще. Для этого измените URL-адрес сервера на реальный сервер, который запрашивает сертификат HTTPS, которому уже доверяют в вашей системе.

Комментарии:

1. Я попытался переименовать CA.crt в <hashvalue>.0 в том же каталоге (/root/CA/). Но проблема сохраняется… Я также попытался подключиться к google.com порт: 443 и увидеть там ту же проблему. Похоже, есть какая-то проблема с моим клиентским кодом. Если я закомментирую действия SSL_CTX_set_verify SSL_CTX_set_verify_depth и SSL_CTX_load_verify_location в клиентском коде, я смогу увидеть, что соединение происходит нормально как с серверной программой, так и с google.com: 443. Не могли бы вы рассказать мне, как правильно проверить полученный сертификат сервера?

2. Наконец-то удалось устранить проблему. Изменен SSL_CTX_load_verify_location() вызов функции, чтобы указывать на сертификат RootCA напрямую, а не на каталог, содержащий сертификат. Например: `if(SSL_CTX_load_verify_locations(ctx, «/ root/CA / 01c81d11.0», NULL) <= 0){ ERR_print_errors_fp(stderr); abort(); } ` После изменения клиент и сервер могут снова обмениваться данными без ошибок. Также проверено путем изменения ключа сервера и сертификата на неподписанные, я вижу, что клиентская программа жалуется на ненадежный сертификат, полученный с сервера.