在C语言中获取证书信息通常使用OpenSSL库,该库提供了丰富的API来处理各种证书操作,以下是详细的步骤和代码示例:
在使用OpenSSL库之前,需要在系统中安装OpenSSL库,对于大多数Linux系统,可以使用包管理器来安装它,在Debian系的系统上,可以使用以下命令:
sudo apt-get update sudo apt-get install openssl libssl-dev
在Windows系统上,可以从OpenSSL官网下载并安装预编译的二进制文件。
1、初始化OpenSSL库:在使用OpenSSL库之前,需要初始化它,这包括加载错误字符串和添加SSL算法。
#include <openssl/bio.h> #include <openssl/ssl.h> #include <openssl/err.h> #include <openssl/x509.h> void init_openssl() { SSL_load_error_strings(); OpenSSL_add_ssl_algorithms(); } void cleanup_openssl() { EVP_cleanup(); }
2、读取证书文件:使用BIO_new_file
函数打开证书文件,然后使用PEM_read_bio_X509
函数读取证书。
X509* read_certificate(const char* cert_file) { BIO* cert_bio = BIO_new(BIO_s_file()); if (BIO_read_filename(cert_bio, cert_file) <= 0) { fprintf(stderr, "Error opening certificate file. "); return NULL; } X509* cert = PEM_read_bio_X509(cert_bio, NULL, 0, NULL); BIO_free(cert_bio); return cert; }
3、解析证书并提取信息:使用X509_NAME_oneline
函数获取证书颁发者和持有者的信息,并打印出来。
void print_certificate_info(X509* cert) { char* subj = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0); char* issuer = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0); printf("Subject: %s ", subj); printf("Issuer: %s ", issuer); OPENSSL_free(subj); OPENSSL_free(issuer); }
4、主函数:在主函数中,调用上述函数来读取和打印证书信息。
int main(int argc, char** argv) { if (argc != 2) { fprintf(stderr, "Usage: %s <cert_file> ", argv[0]); return EXIT_FAILURE; } const char* cert_file = argv[1]; init_openssl(); X509* cert = read_certificate(cert_file); if (cert) { print_certificate_info(cert); X509_free(cert); } cleanup_openssl(); return EXIT_SUCCESS; }
将上述代码保存为read_cert.c
,然后使用以下命令编译并运行:
gcc -o read_cert read_cert.c -lssl -lcrypto ./read_cert your_certificate.pem
your_certificate.pem
是你要读取的证书文件。
1、问:如果证书文件是DER编码的,应该如何读取?
答:对于DER编码的证书,可以使用d2i_X509
函数来读取,需要从文件中读取证书数据到内存中,然后使用d2i_X509
函数将其转换为X509
结构体,示例代码如下:
X509 *d2i_X509(x509cert, const unsigned charpp, long length); FILE *fp = fopen(filename, "rb"); if (fp == NULL) { fprintf(stderr, "Unable to open file %s ", filename); exit(EXIT_FAILURE); } fseek(fp, 0, SEEK_END); long fsize = ftell(fp); fseek(fp, 0, SEEK_SET); /* same as rewind(f); */ unsigned char *data = malloc(fsize + 1); fread(data, 1, fsize, fp); fclose(fp); data[fsize] = 0; X509 *cert = d2i_X509(NULL, &data, fsize); if (cert == NULL) { fprintf(stderr, "Failed to parse certificate "); exit(EXIT_FAILURE); } // Now you can use the cert variable to extract information from the certificate. X509_free(cert); free(data);
(注意:在实际使用中,请确保对data
进行适当的内存管理,以避免内存泄漏。)
2、问:如何验证证书的有效性?
答:验证证书的有效性通常涉及检查证书的签名、有效期、颁发者等信息,在OpenSSL中,可以使用X509_verify_cert
函数来验证证书的签名,还可以检查证书的有效期是否在当前时间范围内,示例代码如下:
int verify_certificate(X509 *cert) { // Check the certificate's validity period ASN1_TIME *notBefore = X509_get_notBefore(cert); ASN1_TIME *notAfter = X509_get_notAfter(cert); time_t now = time(NULL); BIO *bio = BIO_new(BIO_s_mem()); ASN1_TIME_print(bio, notBefore); char *notBeforeStr = strdup(BIO_gets(bio, NULL, 0)); BIO_free_all(bio); bio = BIO_new(BIO_s_mem()); ASN1_TIME_print(bio, notAfter); char *notAfterStr = strdup(BIO_gets(bio, NULL, 0)); BIO_free_all(bio); if (ASN1_TIME_check(bio_time_make(notBefore, NULL)) || ASN1_TIME_check(bio_time_make(notAfter, NULL))) { fprintf(stderr, "Certificate is not valid at current time. Not Before: %s, Not After: %s ", notBeforeStr, notAfterStr); free(notBeforeStr); free(notAfterStr); return 0; // Certificate is not valid } free(notBeforeStr); free(notAfterStr); // Verify the certificate's signature (assuming you have the CA's certificate) X509_STORE *store = X509_STORE_new(); X509_STORE_add_cert(store, caCert); // caCert is the CA's certificate X509_STORE_CTX *ctx = X509_STORE_CTX_new(); int result = X509_verify_cert(ctx, cert); X509_STORE_CTX_free(ctx); X509_STORE_free(store); return result; // Returns 1 on success, 0 on failure }