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;
}