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;
}
相关推荐
AI科技星3 分钟前
全域数学·第三部·数术几何部·平行网格卷 完整专著目录(含拓扑发展史+学科定位·终稿)
c语言·开发语言·网络·量子计算·agi
SunnyDays10115 分钟前
Java 读写 Excel 公式:从基础到高级的实战总结
java·开发语言·excel
wb043072017 分钟前
Java 26
java·开发语言
白露与泡影10 分钟前
JVM GC调优实战:从线上频繁Full GC到RT降低80%的全过程
java·开发语言·jvm
灰灰勇闯IT11 分钟前
pyasc:用 Python 调用 CANN 的推理能力
开发语言·python
汉克老师31 分钟前
GESP6级C++考试语法知识(十七、数据结构(三、认识队列 Queue))
数据结构·c++·队列·gesp6级·gesp六级·数组模拟队列
笨拙的老猴子1 小时前
[特殊字符] Java GC机制详解:G1、ZGC、Shenandoah全面解析与版本演进对比
java·开发语言
水木流年追梦1 小时前
大模型入门-Reward 奖励模型训练
开发语言·python·算法·leetcode·正则表达式
电子云与长程纠缠1 小时前
UE5制作六边形包裹球体效果
开发语言·python·ue5
枕星而眠1 小时前
Linux 四大进程/线程同步锁详解:互斥锁、读写锁、条件变量、文件锁
linux·c语言·后端·ubuntu·学习方法