文档章节

X509格式的证书校验(基于GMSSL2019-06-15版本)

o
 osc_bkdv2it5
发布于 2019/08/19 13:38
字数 1412
阅读 9
收藏 0

精选30+云产品,助力企业轻松上云!>>>

实现X509格式证书的链式校验

// cert_public.cpp : Defines the exported functions for the DLL application.
//

#include "stdafx.h"
#include <string.h>
#include <stdio.h>
#include <string>

#include <stdarg.h>

#include <openssl/pem.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>

#include "sm_public.h"

extern "C" {

/*****************************************************************************
* @brief    : 通过X509格式的字符串得到一个X509内部结构对象
* @author   : xiaomw
* @date     : 2019/8/13 
* @inparam  : plaintext X509格式的字符串
* @return   : 成功返回非0 失败返回0
*****************************************************************************/
CRYPT_SMDLL_C void* X509_Str2Object(const char *in)
{
    BIO *bio_obj = NULL;
    X509* x509_obj = NULL;

    //根据字符串内容,构造一个BIO对象
    bio_obj = BIO_new_mem_buf(in, strlen(in));
    if (NULL == bio_obj){
        return NULL;
    }

    //调用接口创建呗
    x509_obj = (X509 *) PEM_ASN1_read_bio((d2i_of_void *)d2i_X509, PEM_STRING_X509, bio_obj, NULL, NULL, NULL);

    //释放对象
    BIO_free(bio_obj);

    return x509_obj;
}

X509* _X509_RootCertStr2Object(const char *in)
{
    BIO *bio_obj = NULL;
    X509* x509_obj = NULL;
    X509_INFO *itmp  = NULL;
    STACK_OF(X509_INFO) *inf  = NULL;

    //根据字符串内容,构造一个BIO对象
    bio_obj = BIO_new_mem_buf(in, strlen(in));
    if (NULL == bio_obj){
        return NULL;
    }
    inf = PEM_X509_INFO_read_bio(bio_obj, NULL, NULL, NULL);
    //释放对象
    BIO_free(bio_obj);
    if (NULL == inf){
        return NULL;
    }

    for (int i = 0; i < sk_X509_INFO_num(inf); i++) {
        itmp = sk_X509_INFO_value(inf, i);
        if (itmp->x509) {
            //复制一个X509对象
            x509_obj = X509_dup(itmp->x509);
            sk_X509_INFO_pop_free(inf, X509_INFO_free);
            return x509_obj;
        }
    }
    sk_X509_INFO_pop_free(inf, X509_INFO_free);

    return NULL;
}

static UINT32 _x509_get_entry_value(const X509_NAME* x509_name, X509_NAME_ENTRY_TYPE nEntry, char* value)
{
    ASN1_STRING* strNameValue = NULL;
    const X509_NAME_ENTRY *x_name_entry = NULL;

    //获取到相应的NameEntry
    x_name_entry = X509_NAME_get_entry(x509_name, nEntry);
    if (NULL == x_name_entry)
    {
        return 1;
    }

    strNameValue = X509_NAME_ENTRY_get_data(x_name_entry);
    if (NULL == strNameValue)
    {
        return 1;
    }

    //拷贝内容
    lstrcpyA(value, (const char*)ASN1_STRING_data(strNameValue));

    return 0;
}

CRYPT_SMDLL_C UINT32 X509_GetIssuerName(const void* pX509_object, X509_NAME_ENTRY_TYPE nEntry, char* value)
{
    const X509_NAME* x_name = NULL;
    ASN1_STRING* strNameValue = NULL;
    const X509_NAME_ENTRY *x_name_entry = NULL;

    if (NULL == pX509_object)
    {
        return 1;
    }

    //校验nEntry
    if (nEntry < NID_commonName || nEntry > NID_organizationalUnitName)
    {
        return 1;
    }

    //获取到值
    x_name = X509_get_issuer_name((const X509*)pX509_object);
    if (NULL == x_name)
    {
        return 1;
    }

    //调用一样的接口返回
    return _x509_get_entry_value(x_name, nEntry, value);
}

CRYPT_SMDLL_C UINT32 X509_GetSubjectName(const void* pX509_object, X509_NAME_ENTRY_TYPE nEntry, char* value)
{
    const X509_NAME* x_name = NULL;
    ASN1_STRING* strNameValue = NULL;
    const X509_NAME_ENTRY *x_name_entry = NULL;

    if (NULL == pX509_object)
    {
        return 1;
    }

    //校验nEntry
    if (nEntry < NID_commonName || nEntry > NID_organizationalUnitName)
    {
        return 1;
    }

    //获取到值
    x_name = X509_get_subject_name((const X509*)pX509_object);
    if (NULL == x_name)
    {
        return 1;
    }

    //调用一样的接口返回
    return _x509_get_entry_value(x_name, nEntry, value);
}

class Mini_X509_Verify_Class
{
private:
    X509* x509_obj;
    X509_STORE * x509_store;
    STACK_OF(X509) * x509_chain;
    X509_STORE_CTX * x509_store_ctx;

public:
    Mini_X509_Verify_Class(): x509_obj(NULL), x509_store(NULL), x509_chain(NULL), x509_store_ctx(NULL){}
    ~Mini_X509_Verify_Class()
    {
        if (NULL != x509_obj){
            X509_free(x509_obj);
        }
        if (NULL != x509_store){
            X509_STORE_free(x509_store);
        }
        if (NULL != x509_chain){
            sk_X509_pop_free(x509_chain, X509_free);
        }
        if (NULL != x509_store_ctx){
            X509_STORE_CTX_cleanup(x509_store_ctx);
        }
    }

    UINT32 set_verify_cert(const char* cert)
    {
        x509_obj = (X509*)X509_Str2Object(cert);
        if (NULL == x509_obj){
            return 1;
        }
        return 0;
    }

    UINT32 add_root_cert(const char* root_cert)
    {
        //没有存储对象,则先创建一个
        if (NULL == x509_store){
            x509_store = X509_STORE_new();
            if (NULL == x509_store)
            {
                return 1;
            }
        }

        //得到X509对象
        X509* x509_root_obj = (X509*)_X509_RootCertStr2Object(root_cert);
        if (NULL == x509_root_obj){
            return 1;
        }
        //加入存储区
        if (0 == X509_STORE_add_cert(x509_store, x509_root_obj)){

            X509_free(x509_root_obj);
            return 1;
        }

        return 0;
    }

    UINT32 add_cert_chain(const char* cert_node)
    {
        //没有X509链,则先创建一个
        if (NULL == x509_chain){
            x509_chain = sk_X509_new_null();
            if (NULL == x509_chain)
            {
                return 1;
            }
        }

        //得到X509对象
        X509* x509_node_obj = (X509*)X509_Str2Object(cert_node);
        if (NULL == x509_node_obj){
            return 1;
        }
        //加入X509链
        if (0 == sk_X509_push(x509_chain, x509_node_obj)){

            X509_free(x509_node_obj);
            return 1;
        }

        return 0;
    }

    BOOL verify(X509* cert)
    {
        X509* pTemp = NULL;
        EVP_PKEY *pkey=NULL;
        // 每次都采取遍历证书的办法吧
        if (NULL != x509_chain){
            //获取链条总长度
            int nSize = sk_X509_num(x509_chain);
            for (int index = 0; index < nSize; index ++) {
                //取出相应的数值
                pTemp = sk_X509_value(x509_chain, index);
                //取出公钥
                pkey = X509_get_pubkey(pTemp);
                //测试能否验证过,能够验证过,递归下去验证
                if (X509_verify(cert, pkey)){
                    return verify(pTemp);
                }
            }
        }

        //如果链条中都验证不过,试一下根证书
        STACK_OF(X509_OBJECT) * root_obj = X509_STORE_get0_objects(x509_store);
        if (NULL == root_obj) {
            return FALSE;
        }
        int root_obj_num = sk_X509_OBJECT_num(root_obj);
        if (root_obj_num <= 0) {
            return FALSE;
        }

        X509 *root_cert = NULL;
        X509_OBJECT* x509_obj = NULL;
        for(int j = 0; j < root_obj_num; j ++){
            //取出OBJ
            x509_obj = sk_X509_OBJECT_value(root_obj, j);
            //取出证书
            root_cert = X509_OBJECT_get0_X509(x509_obj);
            //取出公钥
            pkey = X509_get_pubkey(root_cert);
            //测试能否验证过,能够验证过,返回成功
            if (X509_verify(cert, pkey)){
                return TRUE;
            }
        }

        return FALSE;
    }

    UINT32 verify_cert()
    {
        if (!x509_obj){
            return 1;
        }
        if (verify(x509_obj)) {
            return 0;
        }

        return 1;
    }
};


// 验证一个证书,输入根证书及相应的二级、三级...证书
UINT32 X509_Verify(const char *cert, const char* root_cert, UINT32 ulLevelNum, ...)
{
    UINT32 index = 0;
    va_list arg_ptr;
    const char* cert_node = NULL;
    Mini_X509_Verify_Class x509_verify;

    if (NULL == cert)
    {
        return 1;
    }
    if (NULL == root_cert)
    {
        return 1;
    }
    //最多支持6级
    if (ulLevelNum > 6)
    {
        return 1;
    }

    //存放待验证证书
    if (x509_verify.set_verify_cert(cert)) {
        return 1;
    }

    //存放根证书
    if (x509_verify.add_root_cert(root_cert)) {
        return 1;
    }

    va_start(arg_ptr, ulLevelNum);
    for(index = 0; index < ulLevelNum; index ++){
        cert_node = va_arg(arg_ptr, const char*);
        //存放证书链接
        if (x509_verify.add_cert_chain(cert_node)) {
            return 1;
        }
    }
    va_end(arg_ptr);

    //开始校验
    if (x509_verify.verify_cert()) {
        return 1;
    }

    return 0;
}

};

DEMO验证代码

BOOL LoadCertFileToStr(const char* strFile, std::string& strBuff)
{
    // 打开文件,读取内容
    FILE * hSrcfile = NULL;
    fopen_s(&hSrcfile, strFile,"rb");
    if (hSrcfile == NULL) {
        return FALSE;
    }
    //读取文件
    fseek (hSrcfile, 0, SEEK_END);   ///将文件指针移动文件结尾
    long size = ftell (hSrcfile); ///求出当前文件指针距离文件开始的字节数

    //分配内存
    strBuff.resize(size + 1, '\0');
    //重新开始读取文件
    fseek (hSrcfile, 0, SEEK_SET);

    //读取文件
    fread(&strBuff[0], size,1, hSrcfile);

    fclose(hSrcfile);

    return TRUE;
}

int main(int argc, char* argv[])
{
    //cwSL3D_test_sum();//测试能否成功调用所有接口

    //至少两个证书文件
    if (argc < 3) {
        std::cout << "缺少证书文件" << std::endl;
        return -1;
    }
    if (argc > 9) {
        std::cout << "证书文件过多,目前不支持" << std::endl;
        return -1;
    }

    //第一个证书文件,根证书文件
    std::string root_cert;
    if (!LoadCertFileToStr(argv[1], root_cert)) {
        std::cout << "读取根证书文件失败" << std::endl;
        return -1;
    }

    //第二个证书文件,待验证的证书
    std::string cert_file;
    if (!LoadCertFileToStr(argv[2], cert_file)) {
        std::cout << "读取待验证证书文件失败" << std::endl;
        return -1;
    }

    //后续的证书文件,证书链条上的文件
    std::string cert_chain[6];
    for(int index = 0; index < 6 && index < argc - 3; index ++) {
        if (!LoadCertFileToStr(argv[index + 3], cert_chain[index])) {
            std::cout << "读取证书文件失败:" << argv[index + 2] << std::endl;
            return -1;
        }
    }

    //直接调用接口验证吧
    if (X509_Verify(cert_file.c_str(), root_cert.c_str(), argc - 3, cert_chain[0].c_str(), cert_chain[1].c_str(), cert_chain[2].c_str(), cert_chain[3].c_str(), cert_chain[4].c_str(), cert_chain[5].c_str())) {
        std::cout << "验证证书文件失败" << std::endl;
        return -1;
    }

    return 0;
}

 

o
粉丝 0
博文 500
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。
常见数字证书格式以及格式间转换

PKCS 全称是 Public-Key Cryptography Standards ,是由 RSA 实验室与其它安全系统开发商为促进公钥密码的发展而制订的一系列标准,PKCS 目前共发布过 15 个标准。 常用的有:PKCS#12 Perso...

醉公子
2016/06/28
21
0
X509证书格式

X509证书格式 X509证书格式 证书的格式遵循ITU-T X.509标准。该标准是为了保证使用数字证书的系统间的互操作性而制定的。X.509是国际标准化组织CCITT建议作为X.500目录检索的一部分提供安全目...

秋风醉了
2015/05/22
1K
1
PKCS 发布的15 个标准与X509

PKCS 发布的15 个标准,转自:http://falchion.iteye.com/blog/1472453 PKCS 全称是 Public-Key Cryptography Standards ,是由 RSA 实验室与其它安全系统开发商为促进公钥密码的发展而制订的...

jj_soft
2016/06/04
25
0
[转] 使用HTTPS在Nexus Repository Manager 3.0上搭建私有Docker仓库

FROM: https://www.hifreud.com/2018/06/06/03-nexus-docker-repository-with-ssl/ 搭建方式 搭建SSL的Nexus官方提供两种方式 第一种是反向代理服务器,Nexus Repository Manager使用HTTP对外...

osc_z5nf1pyi
2019/02/25
1
0
https证书申请过程(用于nginx)

https证书申请过程 文章摘要 在上一篇文章完整搭建linux服务器中介绍了一台服务器从空的操作系统到最后应用通过 https 访问的完整过程,其中上篇文章中在介绍 https 申请时比较简单,这里专门...

科比可比克
03/26
27
0

没有更多内容

加载失败,请刷新页面

加载更多

dict.items()和dict.iteritems()有什么区别?

问题: Are there any applicable differences between dict.items() and dict.iteritems() ? dict.items()和dict.iteritems()之间是否有适用的区别? From the Python docs: 从Python文档中......

法国红酒甜
今天
20
0
R中“ =”和“ <-”赋值运算符有什么区别?

问题: What are the differences between the assignment operators = and <- in R? R中赋值运算符=和<-之间有什么区别? I know that operators are slightly different, as this example ......

fyin1314
今天
20
0
之间的区别 和

问题: I'm learning Spring 3 and I don't seem to grasp the functionality behind <context:annotation-config> and <context:component-scan> . 我正在学习Spring 3,并且似乎不太了解<......

javail
今天
15
0
业内首款,百度工业视觉智能平台全新亮相

本文作者:y****n 业内首款全国产化工业视觉智能平台——百度工业视觉智能平台亮相中国机器视觉展(Vision China),该平台所具有的核心AI能力完全自主可控,在质检、巡检等场景中具有高效、...

百度开发者中心
昨天
7
0
我们如何制作xkcd样式图? - How can we make xkcd style graphs?

问题: Apparently, folk have figured out how to make xkcd style graphs in Mathematica and in LaTeX . 显然,民间已经想出了如何在Mathematica和LaTeX中制作xkcd风格的图形。 Can we d......

富含淀粉
今天
10
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部