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;
}
相关推荐
D_evil__5 小时前
【Effective Modern C++】第二章 auto:6. 当auto推导的类型不符合要求时,使用显式类型初始化习惯用法
c++
哈哈不让取名字5 小时前
基于C++的爬虫框架
开发语言·c++·算法
花间相见5 小时前
【JAVA开发】—— Nginx服务器
java·开发语言·nginx
扶苏-su6 小时前
Java---Properties 类
java·开发语言
不忘不弃6 小时前
模拟内存分配器1
c语言
一条咸鱼_SaltyFish7 小时前
远程鉴权中心设计:HTTP 与 gRPC 的技术决策与实践
开发语言·网络·网络协议·程序人生·http·开源软件·个人开发
我即将远走丶或许也能高飞7 小时前
vuex 和 pinia 的学习使用
开发语言·前端·javascript
沐知全栈开发7 小时前
SQL LEN() 函数详解
开发语言
剑锋所指,所向披靡!8 小时前
C++之类模版
java·jvm·c++
钟离墨笺8 小时前
Go语言--2go基础-->基本数据类型
开发语言·前端·后端·golang