Как использовать openssl для проверки сертификата в PEM с локальным хранилищем доверия? - PullRequest
0 голосов
/ 28 августа 2018

У меня есть сертификат в формате PEM. Допустим, у меня есть сертификат, который я скопировал с google.com.

Итак, цепочка это

Google Trust Services-GlobalSign Root CA-R2

-> Google Internet Authority G3

-.> * Google.com

Предположим, что у меня есть сертификат *.google.com, и я хочу, чтобы программа на Си проверила этот сертификат в моем локальном хранилище доверенных сертификатов в Linux. Пусть скажут /etc/ssl/certs.

Мне нужно отключить его без подключения к серверу. Что я должен делать?

1 Ответ

0 голосов
/ 29 августа 2018

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

Фактическая функция проверки

Функциональность проверки сертификата (цепочки) обеспечивается функцией OpenSSL X509_verify_cert () . Возвращаемое значение 1 указывает на успешную проверку, 0 указывает на отсутствие успеха. Как видно из документации, функция требует только одного параметра типа X509_STORE_CTX, который представляет собой структуру, содержащую «контекст» (довольно неопределенный и чрезмерно используемый термин в OpenSSL, IMO) из коллекции X509 сертификатов. участие.

Настройка контекста хранилища сертификатов

Контекст хранилища сертификатов содержит информацию о доверенных сертификатах, недоверенных промежуточных сертификатах и ​​сертификате, подлежащем проверке. Он построен и инициализирован следующим образом:

store_ctx = X509_STORE_CTX_new();
X509_STORE_CTX_init(store_ctx, store, cert, intermediates)

Параметр store будет использоваться для хранения информации о доверенных сертификатах, параметр cert содержит сертификат для проверки, а параметр intermediates представляет собой стек ненадежных промежуточных сертификатов.

Параметр store

Тип X509_STORE может содержать набор сертификатов X509, и для проверки сертификата необходимо предоставить информацию о доверенных сертификатах. Поскольку вы указали, что у вас есть доверенные сертификаты в /etc/ssl/certs, это можно сделать следующим образом:

store = X509_STORE_new();
lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir());
X509_LOOKUP_add_dir(lookup, "/etc/ssl/certs", X509_FILETYPE_PEM);

Предполагается, что локальное хранилище доверенных сертификатов настроено правильно

Параметр cert`

Этот параметр содержит фактический сертификат, подлежащий проверке. Он может быть загружен из файла несколькими способами, один из них выглядит следующим образом:

bio_in = BIO_new_file(certFileName, "r");
result = PEM_read_bio_X509(bio_in, NULL, NULL, NULL);
BIO_free(bio_in);

Параметр intermediates

OpenSSL предоставляет API стека для обработки коллекций объектов. Параметр intermediates представляет собой стек объектов X509, который содержит промежуточные сертификаты между проверяемым сертификатом и доверенным сертификатом. В псевдокоде его можно заполнить следующим образом:

intermediates = sk_X509_new_null();
for (filename in certFilenames) do {
    icert = readCert(filename);
    sk_X509_push(intermediates, icert);
}

Это завершает объяснение, оно должно дать вам все необходимое для проверки цепочки.

** О сертификате в конце скачанной цепочки

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

Пример кода

Наконец: -)

#include <openssl/x509.h>
#include <openssl/x509_vfy.h>
#include <openssl/pem.h>

const char *trustedCertsPath = "/etc/ssl/certs";

int main(
    int argc,
    char **argv)
{
    X509 *cert = NULL;
    X509 *icert = NULL;
    STACK_OF(X509) *intermediates = NULL;
    X509_STORE *store = NULL;
    X509_LOOKUP *lookup = NULL;
    X509_STORE_CTX *store_ctx = NULL;
    BIO *bio_in = NULL;
    int currentArg = 1;
    int result = 0;

    store = X509_STORE_new();
    lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir());
    X509_LOOKUP_add_dir(lookup, trustedCertsPath, X509_FILETYPE_PEM);

    /* Certificate to be checked */
    bio_in = BIO_new_file(argv[currentArg++], "r");
    cert = PEM_read_bio_X509(bio_in, NULL, NULL, NULL);
    BIO_free(bio_in);

    /* Stack of untrusted intermediate certificates */
    intermediates = sk_X509_new_null();
    while (currentArg < argc) {
        bio_in = BIO_new_file(argv[currentArg++], "r");
        icert = PEM_read_bio_X509(bio_in, NULL, NULL, NULL);
        BIO_free(bio_in);
        sk_X509_push(intermediates, icert);
    }

    store_ctx = X509_STORE_CTX_new();
    X509_STORE_CTX_init(store_ctx, store, cert, intermediates);

    result = X509_verify_cert(store_ctx);
    printf("Result from X509_verify_cert is %d\n", result);

    sk_X509_pop_free(intermediates, X509_free);
    X509_STORE_CTX_cleanup(store_ctx);
    X509_STORE_CTX_free(store_ctx);
    X509_STORE_free(store);
}

Вы можете построить и запустить его следующим образом (где аргументы .pem - это имена файлов, содержащих ваш сертификат и промежуточные файлы в формате PEM:

$ gcc  main.c $(pkg-config openssl --libs) -o verify -Wall
$ ./verify \*.google.com.pem Google\ Internet\ Authority\ G3.pem
Result from X509_verify_cert is 1
...