我正在尝试编写 C 代码来验证证书,包括检查 CRL 以检查它是否被撤销。
这是证书链,为了隐私和简洁而进行了编辑:
mycert.pem
Subject: MyCompany
Issuer: CA1
Authority Information Access: https://.../ca1.pem
CRL Distribution Points: https://.../crl.pem
ca1.pem
Subject: CA1
Issuer: Root
Authority Information Access: https://.../root.pem
CRL Distribution Points: :https://.../ca_crl.pem
CRL Issuer: Root
root.pem
Subject: Root
Issuer: Root
验证这条链很简单:
$ cat root.pem ca1.pem > chain.pem
$ openssl verify -CAfile chain.pem mycert.pem
mycert.pem: OK
mycert.pem 和 ca1.pem 都有关联的 CRL:
crl.pem
Issuer: CA2
Authority Information Access: https://.../ca2.pem
ca_crl.pem
Issuer: Root
crl.pem 由第二个互证书 (ca2.pem) 签名,具有相同的根证书:
ca2.pem
Subject: CA2
Issuer: Root
Authority Information Access: https://.../root.pem
CRL Distribution Points: https://.../ca_crl.pem
我可以通过这种方式使用 openssl 验证 mycert.pem:
$ openssl verify -CAfile chain.pem -CRLfile ca_crl.pem -CRLfile crl.pem -untrusted ca2.pem -crl_check -extended_crl mycert.pem
mycert.pem: OK
(使用
-untrusted
作为我应该能够信任的证书很奇怪,但我发现一些帖子使用这种方法而不质疑它。如果这是错误的,请随时提及!)
我现在正在尝试将此命令翻译为 C 代码,但我无法使其工作。这是一段简单的代码,可以重现该命令的行为:
#include <openssl/x509.h>
#include <openssl/x509_vfy.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <stdio.h>
X509 *cert_load(const char *filename) {
X509 *cert = NULL;
FILE *fp = fopen(filename, "r");
if (fp) {
cert = PEM_read_X509(fp, NULL, NULL, NULL);
fclose(fp);
}
return cert;
}
X509_CRL *crl_load(const char *filename) {
X509_CRL *crl = NULL;
FILE *fp = fopen(filename, "r");
if (fp) {
crl = PEM_read_X509_CRL(fp, NULL, NULL, NULL);
fclose(fp);
}
return crl;
}
int main() {
OpenSSL_add_all_algorithms();
ERR_load_crypto_strings();
int ret;
X509_STORE *store = X509_STORE_new();
X509_STORE_CTX *ctx = X509_STORE_CTX_new();
X509 *mycert = cert_load("mycert.pem");
X509 *ca1_cert = cert_load("ca1.pem");
X509 *ca2_cert = cert_load("ca2.pem");
X509 *root_cert = cert_load("root.pem");
X509_CRL *crl = crl_load("crl.pem");
X509_CRL *ca_crl = crl_load("ca_crl.pem");
STACK_OF(X509) *chain = sk_X509_new_null();
STACK_OF(X509) *untrusted = sk_X509_new_null();
if (!mycert || !ca1_cert || !ca2_cert || !root_cert || !crl || !ca_crl) {
printf("Error loading certificates or CRL\n");
return 1;
}
sk_X509_push(chain, ca1_cert);
sk_X509_push(untrusted, ca2_cert);
X509_STORE_add_crl(store, crl);
X509_STORE_add_crl(store, ca_crl);
// X509_V_FLAG_EXTENDED_CRL_SUPPORT: enable checking indirect CRL
X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL | X509_V_FLAG_EXTENDED_CRL_SUPPORT);
X509_STORE_add_cert(store, root_cert);
X509_STORE_CTX_init(ctx, store, mycert, chain);
X509_STORE_CTX_set0_untrusted(ctx, untrusted);
ret = X509_verify_cert(ctx);
if (ret == 1) {
printf("Verification successful\n");
} else {
int error = X509_STORE_CTX_get_error(ctx);
printf("Verification failed: %s\n", X509_verify_cert_error_string(error));
}
X509_STORE_CTX_free(ctx);
X509_STORE_free(store);
sk_X509_pop_free(chain, X509_free);
sk_X509_pop_free(untrusted, X509_free);
X509_free(mycert);
X509_free(ca1_cert);
X509_free(ca2_cert);
X509_free(root_cert);
X509_CRL_free(crl);
X509_CRL_free(ca_crl);
EVP_cleanup();
ERR_free_strings();
return ret;
}
运行上面的代码,我得到
KO: unable to get local issuer certificate
。
我尝试评论这一行:
X509_STORE_CTX_set0_untrusted(ctx, untrusted);
,它给出了KO: unable to get certificate CRL
。
如果我也注释掉这一行:
X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL | X509_V_FLAG_EXTENDED_CRL_SUPPORT);
,则验证成功。
如何构建“不受信任”的链,使其依赖于根证书,并且 CRL 被视为对我的证书有效?
#include <openssl/x509.h>
#include <openssl/x509_vfy.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <stdio.h>
// Function to load a certificate from a file
X509 *cert_load(const char *filename) {
X509 *cert = NULL;
FILE *fp = fopen(filename, "r");
if (fp) {
cert = PEM_read_X509(fp, NULL, NULL, NULL);
fclose(fp);
} else {
// Added error message if file cannot be opened
fprintf(stderr, "Error opening certificate file %s\n", filename);
}
return cert;
}
// Function to load a CRL from a file
X509_CRL *crl_load(const char *filename) {
X509_CRL *crl = NULL;
FILE *fp = fopen(filename, "r");
if (fp) {
crl = PEM_read_X509_CRL(fp, NULL, NULL, NULL);
fclose(fp);
} else {
// Improved: Added error message if file cannot be opened
fprintf(stderr, "Error opening CRL file %s\n", filename);
}
return crl;
}
int main() {
OpenSSL_add_all_algorithms();
ERR_load_crypto_strings();
int ret;
X509_STORE *store = X509_STORE_new();
X509_STORE_CTX *ctx = X509_STORE_CTX_new();
X509 *mycert = cert_load("mycert.pem");
X509 *ca1_cert = cert_load("ca1.pem");
X509 *ca2_cert = cert_load("ca2.pem");
X509 *root_cert = cert_load("root.pem");
X509_CRL *crl = crl_load("crl.pem");
X509_CRL *ca_crl = crl_load("ca_crl.pem");
STACK_OF(X509) *chain = sk_X509_new_null();
STACK_OF(X509) *untrusted = sk_X509_new_null();
// Check if all certificates and CRLs are loaded successfully
if (!mycert || !ca1_cert || !ca2_cert || !root_cert || !crl || !ca_crl) {
fprintf(stderr, "Error loading certificates or CRL\n");
return 1;
}
sk_X509_push(chain, ca1_cert);
sk_X509_push(untrusted, ca2_cert);
X509_STORE_add_crl(store, crl);
X509_STORE_add_crl(store, ca_crl);
// Set flags for CRL checking
X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL | X509_V_FLAG_EXTENDED_CRL_SUPPORT);
X509_STORE_add_cert(store, root_cert);
X509_STORE_CTX_init(ctx, store, mycert, chain);
X509_STORE_CTX_set0_untrusted(ctx, untrusted);
ret = X509_verify_cert(ctx);
if (ret == 1) {
printf("Verification successful\n");
} else {
int error = X509_STORE_CTX_get_error(ctx);
printf("Verification failed: %s\n", X509_verify_cert_error_string(error));
}
X509_STORE_CTX_free(ctx);
X509_STORE_free(store);
sk_X509_pop_free(chain, X509_free);
sk_X509_pop_free(untrusted, X509_free);
X509_free(mycert);
// Free additional resources
X509_free(ca1_cert);
X509_free(ca2_cert);
X509_free(root_cert);
X509_CRL_free(crl);
X509_CRL_free(ca_crl);
return 0;
}
尝试这样的事情^