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;
}
相关推荐
不想写代码的星星1 小时前
虚函数表:C++ 多态背后的那个男人
c++
端平入洛2 天前
delete又未完全delete
c++
祈安_2 天前
C语言内存函数
c语言·后端
端平入洛3 天前
auto有时不auto
c++
郑州光合科技余经理4 天前
代码展示:PHP搭建海外版外卖系统源码解析
java·开发语言·前端·后端·系统架构·uni-app·php
feifeigo1234 天前
matlab画图工具
开发语言·matlab
dustcell.4 天前
haproxy七层代理
java·开发语言·前端
norlan_jame4 天前
C-PHY与D-PHY差异
c语言·开发语言
哇哈哈20214 天前
信号量和信号
linux·c++
多恩Stone4 天前
【C++入门扫盲1】C++ 与 Python:类型、编译器/解释器与 CPU 的关系
开发语言·c++·人工智能·python·算法·3d·aigc