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


    实现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, '');
        //重新开始读取文件
        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;
    }
  • 相关阅读:
    20200813质因数分解 --已知正整数n是两个不同的质数的乘积,试求出较大的那个质数 (奥赛一本通 P71 8)
    20200807求梯形面积,要求输入浮点数,输出精度为2位
    c++语言printf()输出格式大全 scanf()输入格式大全
    20200803给出一 名学生的语文和数学成绩,判断他是否恰好有一门课不及格(<60分),如果是输出1;否则输出0(奥赛一本通 p32 10)
    20200803-判断一个数能否同时被3,5,7整除(奥赛一本通 p32 9)
    20200802--利用公式 e=1+1/1!+1/2!+...+1/n!,求e的值, 要求保留小数点后10位(奥赛一本通 p67 2)
    20200802 给定正整数n,求不大于n的正整数的阶乘的和(即求1!+2!+...+n!),输出阶乘的和 (奥赛一本通p67 1题)
    线程
    mysql逻辑架构
    《python网络数据采集》笔记2
  • 原文地址:https://www.cnblogs.com/eaglexmw/p/11376639.html
Copyright © 2020-2023  润新知