实现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 = ; 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 ;
}

X509格式的证书校验(基于GMSSL2019-06-15版本)的更多相关文章

  1. 通过C#来加载X509格式证书文件并生成RSA对象

    private static RSACryptoServiceProvider GetPrivateKey(string priKeyFile, string keyPwd) { var pc = n ...

  2. 谈HTTPS中间人攻击与证书校验(二)

    上文说到HTTPS的三次握手:http://www.cnblogs.com/wh4am1/p/6616851.html 不懂的再回头去看看 三.中间人攻击 https握手过程的证书校验环节就是为了识别 ...

  3. TOMCAT 无法安装P7B格式的证书

    背景:通过按以下链接的方式生成了CSR文件,并申请到P7B格式的证书 现象:TOMCAT安装该证书时,要求输入Keystore key, 但是P7B证书自身并不携带私钥.导致无法通过TOMCAT安装该 ...

  4. cer pfx格式数字证书区别

    作为文件形式存在的证书一般有这几种格式: 1.带有私钥的证书 由Public Key Cryptography Standards #12,PKCS#12标准定义,包含了公钥和私钥的二进制格式的证书形 ...

  5. jjava Date格式是 May 07 17:44:06 CST 2018,怎么插入数据库中的timestamp格式中

    首先 我来记录下错误 死在时间格式转换错误手里了 大致就是时间格式转化失败 java代码中的May 07 17:44:06 CST 2018  是这个格式转换为 数据库的 yyyy-MM-dd HH: ...

  6. Java转换Json日期/Date(1487053489965+0800)/格式以及js时间格式 Tue Feb 14 2017 14:06:32 GMT+0800

    /Date(1487053489965+0800)/用Java怎么转换成yyyy-MM-dd的格式 Tue Feb 14 2017 14:06:32 GMT+0800用Java怎么转换成yyyy-MM ...

  7. [转]Apache的CRT格式SSL证书转换成IIS用的PFX格式

    转自:http://www.getvm.net/apache-crt-ssl-convert-to-iis-pfx/ Apache使用的SSL证书是.crt格式,如果你的网站从Apache换到了win ...

  8. 谈HTTPS中间人攻击与证书校验(一)

    一.前言 随着安全的普及,https通信应用越发广泛,但是由于对https不熟悉导致开发人员频繁错误的使用https,例如最常见的是未校验https证书从而导致“中间人攻击”,并且由于修复方案也一直是 ...

  9. 转:如何转换Android打包用jks格式keystore证书为Air用pkcs12格式p12证书

    转自:http://blog.k-res.net/archives/1539.html 如何转换Android打包用jks格式keystore证书为Air用pkcs12格式p12证书 六月 11, 2 ...

随机推荐

  1. 45. Jump Game II (JAVA)

    Given an array of non-negative integers, you are initially positioned at the first index of the arra ...

  2. Out of memory: Kill process 25280 (php-fpm) score 86 or sacrifice child

    php-fpm 耗尽服务器内存的办法 java服务今天突然宕机,通过 cat /var/log/messages进行查看,发现是系统内存溢出导致系统把java的进程杀掉了 使用top查看系统内存使用情 ...

  3. MongoDB入门_MongoDB安装与配置

    MongoDB运行环境 MongoDB环境:CentOS-6.7-i386 MongoDB版本:MongoDB 2.6.5 ssh工具:xshell 文本编辑工具:vim与editplus++ 编译M ...

  4. VS插件CodeRush for Visual Studio发布v18.2.9|附下载

    CodeRush能帮助你以极高的效率创建和维护源代码.Consume-first 申明,强大的模板,智能的选择工具,智能代码分析和创新的导航以及一个无与伦比的重构集,在它们的帮助下能够大大的提高你效率 ...

  5. 一、MyBatis基本使用,包括xml方式、注解方式、及动态SQL

    一.简介 发展历史:MyBatis 的前 身是 iBATIS.最初侧重于 密码软件的开发 , 后来发展成为一款基于 Java 的持久层框架. 定      位:MyBatis 是一款优秀的支持自定义 ...

  6. Kibana后台进程启动和关闭

    原创转载请注明出处:https://www.cnblogs.com/agilestyle/p/12073202.html 后台启动Kibana ./bin/kibana & 查找Kibana进 ...

  7. 去掉html中的标签

    //去掉html中的图片 String regEx_image = "(<img.*src\\s*=\\s*(.*?)[^>]*?>)"; Pattern p_s ...

  8. php array_push()函数 语法

    php array_push()函数 语法 作用:向第一个参数的数组尾部添加一个或多个元素(入栈),然后返回新数组的长度.博智达 语法:array_push(array,value1,value2.. ...

  9. CF786B Legacy 线段树优化建图 + spfa

    CodeForces 786B Rick和他的同事们做出了一种新的带放射性的婴儿食品(???根据图片和原文的确如此...),与此同时很多坏人正追赶着他们.因此Rick想在坏人们捉到他之前把他的遗产留给 ...

  10. [BZOJ3199][SDOI2013]escape:半平面交

    分析 好像叫V图什么的. 容易发现,对于每个点,其监视的范围就是这个点与其它所有点的垂直平分线分割平面后的半平面交.由于数据范围很小,所以我们可以直接枚举每个点,使用双端队列求出其监视的范围.若两个点 ...