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_Cvoid* 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){returnNULL;
}//调用接口创建呗 x509_obj = (X509 *) PEM_ASN1_read_bio((d2i_of_void *)d2i_X509, PEM_STRING_X509, bio_obj, NULL, NULL, NULL);//释放对象 BIO_free(bio_obj);returnx509_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){returnNULL;
}
inf=PEM_X509_INFO_read_bio(bio_obj, NULL, NULL, NULL);//释放对象 BIO_free(bio_obj);if (NULL ==inf){returnNULL;
}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);returnx509_obj;
}
}
sk_X509_INFO_pop_free(inf, X509_INFO_free);returnNULL;
}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);
}classMini_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)){returnverify(pTemp);
}
}
}//如果链条中都验证不过,试一下根证书 STACK_OF(X509_OBJECT) * root_obj =X509_STORE_get0_objects(x509_store);if (NULL ==root_obj) {returnFALSE;
}int root_obj_num =sk_X509_OBJECT_num(root_obj);if (root_obj_num <= 0) {returnFALSE;
}
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)){returnTRUE;
}
}returnFALSE;
}
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) {returnFALSE;
}//读取文件 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);returnTRUE;
}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::stringroot_cert;if (!LoadCertFileToStr(argv[1], root_cert)) {
std::cout<< "读取根证书文件失败" <<std::endl;return -1;
}//第二个证书文件,待验证的证书 std::stringcert_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;
}