C++ 实现证书文件的X509验证
通过证书Server,验证证书的有效性
openssl实现了标准的x509v3数字证书,其源码在crypto/x509和crypto/x509v3中。其中x509目录实现了数字证书以及证书申请相关的各种函数,包括了X509和X509_REQ结构的设置、读取、打印和比较;数字证书的验证、摘要;各种公钥的导入导出等功能。x509v3目录主要实现了数字证书扩展项相关的函数。
在进行身份认证时,首先要对发送给服务器进行认证的x509证书有效性进行验证,在Openssl中,可以用一个API接口可以实现:int X509_verify_cert(X509_STORE_CTX *ctx);
接口中形参是X509_STORE_CTX(X509证书库上下文)类型,在X509证书库上下文中,存在一个X509证书库和一个待验证的X509证书,可以加入信任的证书链,也可以加入CRL证书链(证书撤销列表)
步骤:
1)初始化环境
a.新建证书存储区X509_STORE_new()
b.新建证书校验上下文X509_STORE_CTX_new()
2)导入根证书
a.读取CA证书,从DER编码格式化为X509结构d2i_X509()
b.将CA证书导入证书存储区X509_STORE_add_cert()
3)导入要校验的证书test
a.读取证书test,从DER编码格式化为X509结构d2i_X509()
b.在证书校验上下文初始化证书test,X509_STORE_CTX_init()
c.校验X509_verify_cert
代码:
1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 5 #include <openssl/evp.h> 6 #include <openssl/x509.h> 7 8 #define CERT_PATH "/home/ckelsel/work/rc4/cert" 9 #define ROOT_CERT "ca.cer" 10 #define WIN71H "win71h.cer" 11 #define WIN71Y "win71y.cer" 12 13 14 #define GET_DEFAULT_CA_CERT(str) sprintf(str, "%s/%s", CERT_PATH, ROOT_CERT) 15 #define GET_CUSTOM_CERT(str, path, name) sprintf(str, "%s/%s", path, name) 16 17 #define MAX_LEGTH 4096 18 19 20 int my_load_cert(unsigned char *str, unsigned long *str_len, 21 const char *verify_cert, const unsigned int cert_len) 22 { 23 FILE *fp; 24 fp = fopen(verify_cert, "rb"); 25 if ( NULL == fp) 26 { 27 fprintf(stderr, "fopen fail\n"); 28 return -1; 29 } 30 31 *str_len = fread(str, 1, cert_len, fp); 32 fclose(fp); 33 return 0; 34 } 35 36 X509 *der_to_x509(const unsigned char *der_str, unsigned int der_str_len) 37 { 38 X509 *x509; 39 x509 = d2i_X509(NULL, &der_str, der_str_len); 40 if ( NULL == x509 ) 41 { 42 fprintf(stderr, "d2i_X509 fail\n"); 43 44 return NULL; 45 } 46 return x509; 47 } 48 int x509_verify() 49 { 50 int ret; 51 char cert[MAX_LEGTH]; 52 53 unsigned char user_der[MAX_LEGTH]; 54 unsigned long user_der_len; 55 X509 *user = NULL; 56 57 unsigned char ca_der[MAX_LEGTH]; 58 unsigned long ca_der_len; 59 X509 *ca = NULL; 60 61 X509_STORE *ca_store = NULL; 62 X509_STORE_CTX *ctx = NULL; 63 STACK_OF(X509) *ca_stack = NULL; 64 65 /* x509初始化 */ 66 ca_store = X509_STORE_new(); 67 ctx = X509_STORE_CTX_new(); 68 69 /* root ca*/ 70 GET_DEFAULT_CA_CERT(cert); 71 /* 从文件中读取 */ 72 my_load_cert(ca_der, &ca_der_len, cert, MAX_LEGTH); 73 /* DER编码转X509结构 */ 74 ca = der_to_x509(ca_der, ca_der_len); 75 /* 加入证书存储区 */ 76 ret = X509_STORE_add_cert(ca_store, ca); 77 if ( ret != 1 ) 78 { 79 fprintf(stderr, "X509_STORE_add_cert fail, ret = %d\n", ret); 80 goto EXIT; 81 } 82 83 /* 需要校验的证书 */ 84 GET_CUSTOM_CERT(cert, CERT_PATH, WIN71H); 85 my_load_cert(user_der, &user_der_len, cert, MAX_LEGTH); 86 user = der_to_x509(user_der, user_der_len); 87 88 ret = X509_STORE_CTX_init(ctx, ca_store, user, ca_stack); 89 if ( ret != 1 ) 90 { 91 fprintf(stderr, "X509_STORE_CTX_init fail, ret = %d\n", ret); 92 goto EXIT; 93 } 94 95 //openssl-1.0.1c/crypto/x509/x509_vfy.h 96 ret = X509_verify_cert(ctx); 97 if ( ret != 1 ) 98 { 99 fprintf(stderr, "X509_verify_cert fail, ret = %d, error id = %d, %s\n", 100 ret, ctx->error, X509_verify_cert_error_string(ctx->error)); 101 goto EXIT; 102 } 103 EXIT: 104 X509_free(user); 105 X509_free(ca); 106 107 X509_STORE_CTX_cleanup(ctx); 108 X509_STORE_CTX_free(ctx); 109 110 X509_STORE_free(ca_store); 111 112 return ret == 1 ? 0 : -1; 113 } 114 115 int main() 116 { 117 OpenSSL_add_all_algorithms(); 118 x509_verify(); 119 return 0; 120 }
验证证书在本机是否受信 (Windows)
C#中可以实现证书文件的X509验证,从而验证证书在本机是否受信,代码很简单:
1 static void Main(string[] args) 2 { 3 //X509Certificate2 x509 = new X509Certificate2(); 4 byte[] certData = File.ReadAllBytes(@"path\to\file\test.cer"); 5 X509Certificate2 x509 = new X509Certificate2(certData); 6 string result; 7 System.Console.WriteLine(x509.Verify()); 8 }
在C++中需要读取系统store的所有证书,遍历并进行验证,代码如下,
- 本例中通过Wolfssl进行验证, 调用Openssl或微软MFC的接口也可以实现
1 int FunctionsV2::VerifyCertFile(const std::string strFilename, int& status) 2 { 3 status = 0; 4 PCCERT_CONTEXT pTargetCert = NULL; 5 6 HCERTSTORE hCertSys = CertOpenStore( 7 CERT_STORE_PROV_SYSTEM, 8 0, 9 NULL, 10 CERT_SYSTEM_STORE_CURRENT_USER, 11 L"CA"); 12 13 if (hCertSys == nullptr) 14 { 15 return -1; 16 } 17 18 X509* certification = X509_load_certificate_file(strFilename.c_str(), WOLFSSL_FILETYPE_ASN1); 19 20 do 21 { 22 if (pTargetCert = CertFindCertificateInStore( 23 hCertSys, // Store handle. 24 X509_ASN_ENCODING, // Encoding type. 25 0, // Not used. 26 CERT_FIND_SUBJECT_STR_A, // Find type. Find a string in the certificate's subject. 27 0, // The string to be searched for. 28 pTargetCert)) // Previous context. 29 { 30 WOLFSSL_CERT_MANAGER* cm = wolfSSL_CertManagerNew(); 31 wolfSSL_CertManagerLoadCABuffer(cm, pTargetCert->pbCertEncoded, pTargetCert->cbCertEncoded, WOLFSSL_FILETYPE_ASN1); 32 33 const unsigned char* der; 34 int der_length; 35 der = wolfSSL_X509_get_der(certification, &der_length); 36 int ret = wolfSSL_CertManagerVerifyBuffer(cm, der, der_length, SSL_FILETYPE_ASN1); 37 wolfSSL_CertManagerFree(cm); 38 if (ret == SSL_SUCCESS) 39 { 40 status = 1; 41 break; 42 } 43 } 44 45 } while (pTargetCert != NULL); 46 47 if (pTargetCert) 48 { 49 CertFreeCertificateContext(pTargetCert); 50 } 51 if (certification) 52 { 53 X509_free(certification); 54 } 55 56 return 0; 57 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具