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;
}
相关推荐
zh73142 小时前
typephp的编译核心phpx原理解析
android·java·开发语言
warpdrivelabs3 小时前
Codex 开源 harness 全面了解
开发语言·人工智能
1000世界小札5 小时前
《大话数据结构》第9章精读:归并排序与快速排序完整 C++ 实现
数据结构·c++·算法
2601_956121978 小时前
背包基础篇(01、完全、分组、多重、混合)
c++·算法·动态规划
丰锋ff8 小时前
基于 Qt 的智能门禁系统(二)
开发语言·qt
fpcc8 小时前
跟我学C++中级篇——编译期的条件选择
开发语言·c++
SomeB1oody8 小时前
【RustyML入门】6.3. 并行归约
开发语言·后端·机器学习·rust·教程
mqiqe9 小时前
AgentScope Java 2.0 协议集成全景解析:A2A、AG-UI、Agent Protocol 三大开放协议实战指南
java·开发语言·ui
lzhdim9 小时前
12、JavaScript常见的内存泄露问题 - JavaScript学习系列文章
开发语言·前端·javascript·学习·ecmascript
脉动数据行情9 小时前
Java 实现台股 TWSE/TPEx 行情采集(个股 + K 线)
java·开发语言·twse·tpex·台股