基于openssl库函数完成CA对用户证书的认证

一.概述

  在上一篇博客:基于openssl工具完成自建CA以及为server,client颁发证书 中描述了基于openssl工具实现自建CA,并使用CA为server和client颁发证书,本节中将基于openssl工具提供的sdk函数完成CA对其颁发的用户证书做出认证,并考虑对CRL吊销列表的访问情况。

二.openssl - X509证书操做函数

  现有的证书大都采用X.509规范,主要同如下信息组成:版本号、证书序列号、有效期、拥有者信息、颁发者信息、其余扩展信息、拥有者的公钥、CA对以上信息的签名。
  OpenSSL实现了对X.509数字证书的全部操做。包括签发数字证书、解析和验证证书等。涉及证书操做的主要函数有验证证书(验证证书链、有效期、CRL)、解析证书(得到证书的版本、序列号、颁发者信息、主题信息、公钥、有效期等)。下面简要介绍下部分函数的原型:
2.1 DER编码转换为内部结构函数

X509 *d2i_X509(X509 **cert, unsigned char **d, int len);

函数功能:把一个DER编码的证书数据转化成OpenSSL内部结构体。
参数:cert:[OUT]X509结构体。 D:[IN]DER编码的证书数据指针地址。Len证书数据长度;
返回值:编码后的X509结构体数据
2.2 得到证书版本函数X509_get_version

#define X509_get_version(x)  ASN1_INTEGER_get((x)->cert_info->version)

参数:x:[IN]X509*结构体数据结构。
返回值:证书版本,数据类型“LONG”
2.3 得到证书序列号函数

ASN1_INTEGER *X509_get_serialNumber(X509 *x);

返回值:证书序列号,数据类型“ASN1_INTEGER”.
2.4 得到证书颁发者信息函数

X509_NAME *X509_get_issuer_name(X509 *a);

注*:X509_NAME结构体包括多个X509_NAME_ENTRY结构体。X509_NAME_ENTRY保存了颁发者的信息,这些信息包括对象和值(object 和value)。对象的类型包括国家、通用名、单位、组织、地区、邮件等。
2.5 得到证书拥有者信息函数

X509_NAME *X509_get_subject_name(X509 *a);

2.6 得到证书有效期的起始日期函数

#define X509_get_notBefore(x)        ((x)->cert_info-	>validity->notBefore)

返回值:证书起始有效期,数据类型“ASN1_TIME”
2.7 得到证书有效期的终止日期函数

#define X509_get_notAfter(x)           ((x)->cert_info->validity->notAfter)

2.8 得到证书公钥函数

EVP_PKEY *X509_get_pubkey(X509 *x);

2.9 建立和释放证书存储区

X509_STORE *X509_STORE_new(void);
Void X509_STORE_free(X509_STORE *v);

函数功能:建立和释放一个X509_STORE结构体,主要用于验证证书。
2.10 向证书存储区添加证书

Int X509_STORE_add_cert(X509_STORE *ctx, X509 *x);

函数功能:添加信任的根证书到证书存储区。
返回值:1成功,不然为0
2.11 向证书存储区添加证书吊销列表

Int X509_STORE_add_crl(X509_STORE *ctx, X509_CRL *x);

功能:添加CRL到证书存储区。
参数:x:证书吊销列表。Ctx:证书存储区。
返回值:1成功,不然为0。
2.12 建立证书存储区上下文环境函数

X509_STORE_CTX *X509_STORE_CTX_new(void);

返回值:操做成功返回证书存储区上下文环境指针,不然返回NULL。
2.13 释放证书存储区上下文环境

Void X509_STORE_CTX_free(X509_STORE_CTX *ctx);

2.14 初始化证书存储区上下文环境函数

Int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, X509 *x509, STACK_OF(X509) *chain);

函数功能:初始化证书存储区上下文环境,设置根证书、待验证的证书、CA证书链。
2.15 验证证书函数

Int X509_verify_cert(X509_STORE_CTX *ctx);

返回值:验证成功返回1,不然返回0函数

三.基于openssl提供的SDK库函数完成CA对用户证书的认证

以下代码主要实现的功能是:
1.加载CA根证书、用户证书、CRL吊销列表
2.设置是否进行CRL吊销列表查询
3.结合CRL(若是需要查询CRL)完成CA对用户证书的认证。

x509_test.cpp代码如下:

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

using namespace std;

int main(int argc, char **argv)
{
	//判断参数个数是否正确
	if(argc != 4)
	{
		printf("usage: %s ca_crt user_crt crl_file\n",argv[0]);
		return -1;
	}
	
	SSLeay_add_all_algorithms();

	X509_STORE_CTX *ctx = NULL;          // 证书存储区句柄
	X509_STORE *pCaCertStore = NULL;     // 证书存储区
	X509 *pCert = NULL;                  // X509 证书结构体,保存用户证书
	X509 *pCaCert = NULL;                // X509 证书结构体,保存根证书
	X509_CRL *Crl = NULL;                // X509_CRL 结构体,保存CRL
	STACK_OF(X509) *CertStack = NULL;

	BIO * pbio = NULL;
	
	/*********************************第一步:读取用户证书*************************************************/
	pbio = BIO_new_file(argv[2],"r");
	pCert = PEM_read_bio_X509(pbio,NULL,NULL,NULL);
	if(pCert == NULL)
	{
	  X509_free(pCert);
	  cout<<"读取用户证书失败!"<<endl;
	  return -1;
	}
	BIO_free(pbio);
	pbio = NULL;
	/*********************************第二步:读取CA根证书*************************************************/
	pbio = BIO_new_file(argv[1],"r");
	pCaCert = PEM_read_bio_X509(pbio,NULL,NULL,NULL);
	if(pCaCert == NULL)
	{
	  X509_free(pCaCert);
	  cout<<"打开根证书失败"<<endl;
	  return -1;
	}
	BIO_free(pbio);
	pbio = NULL;
	/*********************************第三步:读取CA根证书*************************************************/
	//读取CRL文件
	pbio = BIO_new_file(argv[3],"r");
    Crl = PEM_read_bio_X509_CRL(pbio,NULL,NULL,NULL);
    if (Crl==NULL)
	{
        X509_CRL_free(Crl);
		cout<<"读取吊销列表文件失败"<<endl;
        return -1 ;
    }
	BIO_free(pbio);
	pbio = NULL;

	//1.创建证书存储区
    pCaCertStore = X509_STORE_new(); 

    //设置检查CRL 标志位,如果设置此标志位,则检查CRL ,否则不检查CRL 。
	// X509_V_FLAG_IGNORE_CRITICAL 、
	// X509_V_FLAG_CB_ISSUER_CHECK 、
	// X509_V_FLAG_CRL_CHECK 、
	// X509_V_FLAG_CRL_CHECK│X509_V_FLAG_CRL_CHECK_ALL 等
	X509_STORE_set_flags(pCaCertStore,X509_V_FLAG_CRL_CHECK);				//验证CRL列表
	//X509_STORE_set_flags(pCaCertStore,X509_V_FLAG_IGNORE_CRITICAL);		//不验证CRL列表
	
    X509_STORE_add_cert(pCaCertStore,pCaCert);      // 2.添加根证书到证书存储区
    X509_STORE_add_crl(pCaCertStore,Crl);    		// 3.添加CRL到证书存储区

    ctx = X509_STORE_CTX_new();    			 		// 4.创建证书存储区上下文环境函数(产生一个操作句柄)

	//5.初始化证书存储区上下文环境(ctx),设置根证书(pCaCertStore)、待验证的证书(pCert)、CA证书链(CertStack=NULL)。
    int ret = X509_STORE_CTX_init(ctx,pCaCertStore,pCert,CertStack);   
    if (ret != 1)
    {
       cout<<"X509_STORE_CTX_init err"<<endl;

       X509_free(pCert);
       X509_free(pCaCert);
       X509_STORE_CTX_cleanup(ctx);
       X509_STORE_CTX_free(ctx);
       X509_STORE_free(pCaCertStore);
       return -1 ;
    }
    //6.验证用户证书,返回1表示验证成功,返回0表示验证失败
    ret = X509_verify_cert(ctx); 
    if (ret != 1)
    {
	   cout<<"证书验证失败!"<<endl;
       cout<<"verify cer err.error="<<ctx->error<<"info:"<<X509_verify_cert_error_string(ctx->error)<<endl;
    }
	else{
	   cout<<"证书验证成功!"<<endl;
	}

    // 释放内存
    X509_free(pCert);			//释放用户证书打开后占用的内存
    X509_free(pCaCert);			//释放CA根证书打开后占用的内存
	X509_CRL_free(Crl);			//释放CRL吊销列表打开后占用的内存
    X509_STORE_CTX_cleanup(ctx);	  //清除ctx的上下文配置
    X509_STORE_CTX_free(ctx);		  //释放证书存储区上下文环境函数,释放句柄
    X509_STORE_free(pCaCertStore);    //释放证书存储区

	return 0; 
}

四.测试方法及结果

首先确保环境中openssl工具安装完毕,使用下面编译指令对代码进行编译:

g++ x509_test.cpp -o x509_test -lssl -lcrypto -ldl -lcurses

x509_test.cpp为上述的源文件,生成的目标文件为x509_test,需要依赖的openssl库为ssl,crypto,dl,curses。
执行x509_test可执行文件如下:

./x509_test ca.crt user.crt testca.crl

  其中ca.crt表示CA根证书,user.crt表示由CA签发的用户证书,testca.crl表示由CA生成的CRL列表(证书撤销以及CRL列表生成方法见上一篇博客,见文始给出的链接)。
  若在X509_STORE_set_flags函数中开启了验证CRL列表的标志,则在CA验证user证书之前会先查询CRL列表,若验证成功,则执行结果如下:
在这里插入图片描述
若证书属于CA签发,但是以及被吊销,则验证结果如下:
在这里插入图片描述
若证书不属于CA签发,则验证结果如下:
在这里插入图片描述

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tutu-hu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值