C/C++ OpenSSL自适应格式解析证书二进制字节流

PEM格式与DER格式证书字节流自适应解析,代码如下:

cpp 复制代码
#include <openssl/bio.h>
#include <openssl/pem.h>
#include <openssl/x509.h>
#include <openssl/evp.h>
#include <stdio.h>

// Base64格式DER字节流Base64解码
unsigned char* base64_decode(const char* input, size_t* output_length) 
{
    BIO *b64, *bmem;
    char *buffer = (char *)malloc(strlen(input));
    memset(buffer, 0, strlen(input));
    b64 = BIO_new(BIO_f_base64());
    BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
    bmem = BIO_new_mem_buf(input, -1);
    bmem = BIO_push(b64, bmem);
    *output_length = BIO_read(bmem, buffer, strlen(input));
    BIO_free_all(bmem);
    return (unsigned char*)buffer;
}

X509* parse_certificate(const unsigned char *data, int data_len) {
    BIO *bio = BIO_new_mem_buf(data, data_len);
    X509 *cert = NULL;

    // 尝试PEM格式
    cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
    if (cert) {
        BIO_free_all(bio);
        return cert;
    }

    // 重置BIO并尝试DER格式
    BIO_reset(bio);
    if (cert) {
        cert = d2i_X509_bio(bio, NULL);
        BIO_free_all(bio);
        return cert;
    }

    // 释放BIO资源,并尝试Base64格式的DER(先对证书字节流进行Base64解码,再进行DER解析)
	BIO_free_all(bio);
	size_t der_length;
	unsigned char* der_data = base64_decode((char*)data, &der_length);
	bio = BIO_new_mem_buf(der_data, der_length);
	cert = d2i_X509_bio(bio, NULL);
	if (cert) 
	{
		printf("==== Base64 DER Format ====\n\r");
		BIO_free_all(bio);
		return cert;
	}
}

int main() {
    // PEM格式常见后缀为crt,DER格式常见后缀为cer(包括标准DER格式与Base64编码的DER格式)
    FILE *fp = fopen("cert.crt", "rb");
    // FILE *fp = fopen("cert.cer", "rb");
    if (!fp) {
        printf("无法打开证书文件\n");
        return 1;
    }
    
    // 获取文件字节长度
    fseek(fp, 0, SEEK_END);
    int data_len = ftell(fp);
    fseek(fp, 0, SEEK_SET);
    unsigned char *data = malloc(data_len);
    fread(data, 1, data_len, fp);
    fclose(fp);

    X509 *cert = parse_certificate(data, data_len);
    if (!cert) {
        printf("证书解析失败\n");
        free(data);
        return 1;
    }
    
    // 解析成功后,打印证书颁发者信息用于测试是否解析成功
    X509_NAME *issuer = X509_get_issuer_name(cert);
	if (issuer != NULL) 
	{
		char *issuer_str = X509_NAME_oneline(issuer, NULL, 0);
		if (issuer_str != NULL) 
		{
			printf("Issuer: %s\n", issuer_str);
			OPENSSL_free(issuer_str);
		}
	}

    X509_print_fp(stdout, cert);
    X509_free(cert);
    free(data);
    return 0;
}
相关推荐
Chen_harmony几秒前
一、C++入门基础
开发语言·c++
学逆向的4 分钟前
远程线程注入
开发语言·jvm·网络安全·win32
水饺编程12 分钟前
第1章,[Win32 章节]:Windows 的方方面面
c语言·c++·windows·visual studio
阡陌数智20 分钟前
RAG 系统的召回退化:向量库、分块、重排全链路问题排查与优化实践
开发语言·人工智能·语言模型·自然语言处理·推荐算法
我就是不信27 分钟前
用 C 语言实现一个支持 HTML 与视频的 HTTP(S) 服务器
c语言·html·音视频
geovindu28 分钟前
rust: Flyweight Pattern
开发语言·后端·设计模式·rust·享元模式·结构型模式
Helix25029 分钟前
2026编程入门指南:零基础如何科学选择第一门编程语言?
java·c语言·javascript·零基础·编程语言·python入门·编程就业
Escalating_xu1 小时前
【C 语言】字符函数和字符串函数:从 ctype 到 strtok、strerror 全面解析
java·c语言·开发语言
悠仁さん1 小时前
【C++】auto
java·前端·c++
郝学胜-神的一滴1 小时前
C++ Templates 07:编译报错和调试手段与实战技巧
开发语言·c++·后端·软件工程·visual studio