我有PEM格式的证书。假设我有我从google.com复制的证书。
所以,链条就是那个
Google信任服务-GlobalSign根CA-R2
-> Google Internet Authority G3
-> *。google.com
假设我拥有证书*.google.com
,并且我想让C程序使用Linux中的本地信任存储验证该证书。假设/etc/ssl/certs
。
我需要脱机而不连接服务器。我该怎么办?
答案 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