Общая документация 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