X509格式的证书校验(基于GMSSL2019-06-15版本)
阅读原文时间:2023年07月12日阅读:1

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

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

#include "stdafx.h"
#include
#include
#include

#include

#include
#include
#include

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

strNameValue = X509\_NAME\_ENTRY\_get\_data(x\_name\_entry);  
if (NULL == strNameValue)  
{  
    return ;  
}

//拷贝内容  
lstrcpyA(value, (const char\*)ASN1\_STRING\_data(strNameValue));

return ;  

}

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

//校验nEntry  
if (nEntry < NID\_commonName || nEntry > NID\_organizationalUnitName)  
{  
    return ;  
}

//获取到值  
x\_name = X509\_get\_issuer\_name((const X509\*)pX509\_object);  
if (NULL == x\_name)  
{  
    return ;  
}

//调用一样的接口返回  
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 ;  
}

//校验nEntry  
if (nEntry < NID\_commonName || nEntry > NID\_organizationalUnitName)  
{  
    return ;  
}

//获取到值  
x\_name = X509\_get\_subject\_name((const X509\*)pX509\_object);  
if (NULL == x\_name)  
{  
    return ;  
}

//调用一样的接口返回  
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 ;  
    }  
    return ;  
}

UINT32 add\_root\_cert(const char\* root\_cert)  
{  
    //没有存储对象,则先创建一个  
    if (NULL == x509\_store){  
        x509\_store = X509\_STORE\_new();  
        if (NULL == x509\_store)  
        {  
            return ;  
        }  
    }

    //得到X509对象  
    X509\* x509\_root\_obj = (X509\*)\_X509\_RootCertStr2Object(root\_cert);  
    if (NULL == x509\_root\_obj){  
        return ;  
    }  
    //加入存储区  
    if ( == X509\_STORE\_add\_cert(x509\_store, x509\_root\_obj)){

        X509\_free(x509\_root\_obj);  
        return ;  
    }

    return ;  
}

UINT32 add\_cert\_chain(const char\* cert\_node)  
{  
    //没有X509链,则先创建一个  
    if (NULL == x509\_chain){  
        x509\_chain = sk\_X509\_new\_null();  
        if (NULL == x509\_chain)  
        {  
            return ;  
        }  
    }

    //得到X509对象  
    X509\* x509\_node\_obj = (X509\*)X509\_Str2Object(cert\_node);  
    if (NULL == x509\_node\_obj){  
        return ;  
    }  
    //加入X509链  
    if ( == sk\_X509\_push(x509\_chain, x509\_node\_obj)){

        X509\_free(x509\_node\_obj);  
        return ;  
    }

    return ;  
}

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 = ; 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 <= ) {  
        return FALSE;  
    }

    X509 \*root\_cert = NULL;  
    X509\_OBJECT\* x509\_obj = NULL;  
    for(int j = ; 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 ;  
    }  
    if (verify(x509\_obj)) {  
        return ;  
    }

    return ;  
}  

};

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

if (NULL == cert)  
{  
    return ;  
}  
if (NULL == root\_cert)  
{  
    return ;  
}  
//最多支持6级  
if (ulLevelNum > )  
{  
    return ;  
}

//存放待验证证书  
if (x509\_verify.set\_verify\_cert(cert)) {  
    return ;  
}

//存放根证书  
if (x509\_verify.add\_root\_cert(root\_cert)) {  
    return ;  
}

va\_start(arg\_ptr, ulLevelNum);  
for(index = ; index < ulLevelNum; index ++){  
    cert\_node = va\_arg(arg\_ptr, const char\*);  
    //存放证书链接  
    if (x509\_verify.add\_cert\_chain(cert\_node)) {  
        return ;  
    }  
}  
va\_end(arg\_ptr);

//开始校验  
if (x509\_verify.verify\_cert()) {  
    return ;  
}

return ;  

}

};

DEMO验证代码

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

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

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

fclose(hSrcfile);

return TRUE;  

}

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

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

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

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

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

//直接调用接口验证吧  
if (X509\_Verify(cert\_file.c\_str(), root\_cert.c\_str(), argc - , cert\_chain\[\].c\_str(), cert\_chain\[\].c\_str(), cert\_chain\[\].c\_str(), cert\_chain\[\].c\_str(), cert\_chain\[\].c\_str(), cert\_chain\[\].c\_str())) {  
    std::cout << "验证证书文件失败" << std::endl;  
    return -;  
}

return ;  

}