如何使用openssl在带有本地信任存储的PEM中验证证书?

时间:2018-08-28 10:00:36

标签: c openssl certificate x509certificate x509

我有PEM格式的证书。假设我有我从google.com复制的证书。

所以,链条就是那个

Google信任服务-GlobalSign根CA-R2

-> Google Internet Authority G3

-> *。google.com

假设我拥有证书*.google.com,并且我想让C程序使用Linux中的本地信任存储验证该证书。假设/etc/ssl/certs

我需要脱机而不连接服务器。我该怎么办?

1 个答案:

答案 0 :(得分:0)

围绕该主题的整体OpenSSL文档非常有限,并且到处都有断开的链接,因此我的方法可能不是唯一的或最佳的方法。据我所知,验证证书(链)是按照以下步骤进行的,以相反的顺序展开,因为我认为这样可以更好地理解。有关生成的代码,请参见此答案的结尾。为了简洁起见,所有代码都省略了错误检查。另外,没有解释证书吊销列表(CRL)的加载,我认为这超出了您的问题范围。

实际验证功能

OpenSSL函数X509_verify_cert()提供了用于验证证书(链)的功能。返回值1表示验证成功,0表示未成功。正如您在文档中所看到的,该函数只需要一个类型为X509_STORE_CTX的参数,它是一个结构,该结构保存{{的集合”的“上下文”(在OpenSSL,IMO中是相当模糊和过度使用的术语) 1}}个证书。

设置证书存储上下文

证书存储上下文包含有关受信任证书,不受信任中间证书和要验证的证书的信息。它的构造和初始化如下:

X509

store_ctx = X509_STORE_CTX_new(); X509_STORE_CTX_init(store_ctx, store, cert, intermediates) 参数将用于包含有关受信任证书的信息,store参数将包含要验证的证书,并且cert参数是不信任中间证书的堆栈

intermediates参数

store类型能够包含一组X509证书,并且为了验证证书的目的,需要提供有关受信任证书的信息。由于您表示自己在X509_STORE中拥有受信任的证书,因此可以按照以下步骤进行操作:

/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); 参数

OpenSSL提供了stack API来处理对象的集合。 intermediates参数是intermediates对象的堆栈,其中包含要测试的证书和受信任的证书之间的中间证书。用伪代码可以如下填充:

X509

到此结束了解释,这将为您提供验证链所需的一切。

**关于下载链末尾的证书

下载链末尾的证书通常包含在本地信任库中。一些实验表明,您实际上可以将其提供给verify函数,就好像它是不受信任的中间体一样,也可以忽略它。两者似乎都以正确验证的链条结尾。

代码示例

最后:-)

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