opensll证书解析验证(1

X.509证书解析

结构体及部分接口说明

1、x509结构
x509_st
cert_info:证书主体信息;
sig_alg:签名算法;
signature:签名值,存放CA对该证书签名的结果;
valid:是否是合法证书,1为合法,0为未知;
references:引用次数,被引用一次则加一;
name:证书持有者信息;
ex_data:扩展数据结构,用于存放用户自定义的信息;
ex_pathlen:证书路径长度;
ex_kusage:密钥用法;
ex_xkusage:扩展密钥用法;
ex_nscert:Netscape证书类型;
skid:主体密钥标识;
akid:颁发者密钥标识;
policy_cache:各种策略缓存;
sha1_hash:存放证书的sha1摘要值;
aux:辅助信息;
2、常用接口
1)DER编码()转换为内部结构X509

X509 *d2i_X509(X509 **cert, unsigned char **d, int len);

2)获取证书版本号

#define X509_get_version(x)  ASN1_INTEGER_get((x)->cert_info->version)

3)获取颁发者信息

ASN1_INTEGER *X509_get_serialNumber(X509 *x);

4)获取序列号

ASN1_INTEGER *X509_get_serialNumber(X509 *x);

5)获取证书拥有者信息

X509_NAME *X509_get_subject_name(X509 *a);

6)获取起始日期和截至日期

#define X509_get_notBefore(x)        ((x)->cert_info->validity->notBefore)
#define X509_get_notAfter(x)           ((x)->cert_info->validity->notAfter)

7)获取证书公钥函数

EVP_PKEY *X509_get_pubkey(X509 *x);

8)验证证书
X509_verify_cert函数用于验证X.509证书的合法性。它执行以下验证步骤:

  1. 验证证书的签名:对于自签名证书,会使用证书本身作为公钥进行验证;对于由其他证书签发的证书,会使用签发者的公钥进行验证。
  2. 验证证书的有效期:检查证书的有效期限,包括起始时间(notBefore)和结束时间(notAfter)。
  3. 验证证书的主题和发行者:检查证书的主题(subject)和发行者(issuer),确保它们符合规范。
  4. 验证证书链:如果提供了CA证书链,会检查证书是否属于正确的证书链。
  5. 验证证书扩展:根据需要,可以验证证书的扩展字段,如密钥用法、扩展密钥用法等。
    如果所有的验证步骤都通过,X509_verify_cert函数将返回1,表示证书是合法的。否则,返回值将是0或负数,表示验证失败,并可以通过调用X509_STORE_CTX_get_error函数获取详细的错误代码。
    请注意,X509_verify_cert函数只执行基本的验证步骤。如果需要更复杂的验证,例如检查证书链中的中间证书、检查证书撤销列表(CRL)等,可能需要使用其他函数和工具来完成。

测试程序

cmakelist

project(parseCertTest C)
set(CMAKE_CXX_STANDARD)
aux_source_directory(. DIR_SRCS)
include_directories(../openssl)
link_directories(../third-Part/openssl/lib)
add_executable(parseCertTest ${DIR_SRCS})
#使用到的openssl里使用到的库需要包含,使用dlsym等需要链接dl库用于运行时动态获取	
target_link_libraries(parseCertTest PRIVATE crypto pthread ssl dl)

测试程序主要是提取信息,验证证书,提取公钥,需要终端打印信息可自行修改。

//
// Created by xw on 2023/7/10.
//

#include <stdio.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include "parseCertTest.h"
void printASN1Time(ASN1_TIME* Time)
{
    //BIO是一种用于进行输入/输出操作的抽象类型。它提供了一种统一的接口,可用于在不同的数据源和目标之间进行读写操作。
    BIO* bio = BIO_new(BIO_s_mem());
    if (bio == NULL) {
        printf("Failed to create BIO\n");
        return;
    }
    if (ASN1_TIME_print(bio, Time) <= 0) {
        printf("Failed to print ASN1_TIME\n");
        BIO_free(bio);
        return;
    }
    char buf[1024];
    //从bio对象中读取结果
    int len = BIO_read(bio, buf, sizeof(buf) - 1);
    if (len <= 0) {
        printf("Failed to read BIO\n");
        BIO_free(bio);
        return;
    }
    buf[len] = '\0';
    printf("ASN1_TIME: %s\n", buf);
    BIO_free(bio);
}
void print_public_key_bitstr(const X509 *cert) {
    const ASN1_BIT_STRING *bitstr = X509_get0_pubkey_bitstr(cert);
    if (bitstr == NULL) {
        printf("Failed to get public key bit string\n");
        return;
    }

    printf("Public Key Bit String: ");
    for (int i = 0; i < bitstr->length; i++) {
        //16进制直接输出
        printf("%02X", bitstr->data[i]);
    }
    printf("\n");
}
void printPublicKey(const EVP_PKEY *pubkey)
{
//    BIO *bio = BIO_new_fp(stdout, BIO_NOCLOSE);
    BIO* bio = BIO_new(BIO_s_mem());
    if (bio == NULL) {
        printf("Failed to create BIO\n");
        return;
    }

    if (EVP_PKEY_print_public(bio, pubkey, 0, NULL) != 1) {
        printf("Failed to print public key\n");
    }
    char buf[1024];
    int len = BIO_read(bio, buf, sizeof(buf) - 1);
    if (len <= 0) {
        printf("Failed to read BIO\n");
        BIO_free(bio);
        return;
    }else{
        buf[len] = '\0';
        //公钥的算法名称、参数和具体的公钥值(证书显示中除开前面10字节的数据)
        printf("ASN1_TIME: %s\n", buf);
    }
    BIO_free(bio);
}
int verifyCertificate(X509* cert)
{
    EVP_PKEY *pubkey = X509_get_pubkey(cert);
    printPublicKey(pubkey);
    print_public_key_bitstr(cert);
    //创建存储和管理证书的数据结构
    X509_STORE* store = X509_STORE_new();
    if (store == NULL) {
        printf("Failed to create X509_STORE\n");
        return 0;
    }
    //上下文对象 X509_STORE_CTX 证书 验证链 CRL等
    X509_STORE_CTX* ctx = X509_STORE_CTX_new();
    if (ctx == NULL) {
        printf("Failed to create X509_STORE_CTX\n");
        X509_STORE_free(store);
        return 0;
    }
    //证书添加到X509_STORE对象中
    if (X509_STORE_add_cert(store, cert) != 1) {
        printf("Failed to add certificate to X509_STORE\n");
        X509_STORE_CTX_free(ctx);
        X509_STORE_free(store);
        return 0;
    }
    //初始化ctx对象,传入证书和验证链
    if (X509_STORE_CTX_init(ctx, store, cert, NULL) != 1) {
        printf("Failed to initialize X509_STORE_CTX\n");
        X509_STORE_CTX_free(ctx);
        X509_STORE_free(store);
        return 0;
    }
    //验证合法性
    int result = X509_verify_cert(ctx);
    if (result != 1) {
        printf("Certificate verification failed\n");
        X509_STORE_CTX_free(ctx);
        X509_STORE_free(store);
        return 0;
    }

    X509_STORE_CTX_free(ctx);
    X509_STORE_free(store);

    return 1;
}

int main()
{
    int res = 0;
    setbuf(stdout, NULL);
    FILE *cert_file = fopen("cert.txt", "r");
    X509 *cert = PEM_read_X509(cert_file, NULL, NULL, NULL);
    fclose(cert_file);
//颁发者信息
    X509_NAME *issuer = X509_get_issuer_name(cert);
    //证书拥有者信息
    X509_NAME *subject = X509_get_subject_name(cert);
    ASN1_INTEGER *serial = X509_get_serialNumber(cert);
//起始时间和结束时间
    ASN1_TIME *not_before = X509_get_notBefore(cert);
    ASN1_TIME *not_after = X509_get_notAfter(cert);

    printASN1Time(not_before);
    printASN1Time(not_after);
//信息转换为可打印字符串
    printf("Issuer: %s\n", X509_NAME_oneline(issuer, NULL, 0));
    printf("Subject: %s\n", X509_NAME_oneline(subject, NULL, 0));

    res = verifyCertificate(cert);
// 释放资源
    X509_free(cert);
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值