PKI实验三版本一.docx
《PKI实验三版本一.docx》由会员分享,可在线阅读,更多相关《PKI实验三版本一.docx(33页珍藏版)》请在冰点文库上搜索。
PKI实验三版本一
电子科技大学信息与软件工程学院
标准实验报告
(实验)课程名称PKI技术
电子科技大学教务处制表
报告评分:
指导教师签字:
电子科技大学
实验报告
学生姓名:
杨岚青学号:
*************
*******
实验地点:
三教407
实验时间:
2015.11.22
一、实验室名称:
信息与软件工程学院通用计算机软件实验室
二、实验项目名称:
OpenSSL证书操作
三、实验学时:
4
四、实验原理:
X.509V3版本的数字证书包括以下内容:
证书的版本、序列号、签名算法、证书签发者的信息、证书拥有者的信息、有效期(起始日期和终止日期)、用户的公钥、证书扩展信息(包括证书策略、密钥用途等)、签发者签名算法标识和签名的结果等。
证书一般都是用DER编码。
OpenSSL可实现DER证书的数据转换,证书的验证、证书内容的获取等。
具体用到的函数如下:
(1)证书转换函数
函数功能:
把一个DER编码的证书数据转化为OpenSSL内部结构题,返回值为编码后的X509结构体数据。
函数定义:
X509*d2i_X509(X509**cert,unsignedchar**d,intlen);
参数说明:
cert:
X509结构体。
(2)证书版本获取函数
函数功能:
获取证书的版本,返回值为证书版本号,长整型。
函数定义:
LongX509_get_version(cert);
参数说明:
cert:
X509结构体。
(3)证书序列号获取函数
函数功能:
获取证书的序列号,返回值为证书的序列号,数据类型为“ASN1_INTEGER*”。
函数定义:
ASN1_INTEGER*X509_get_serialNumber(cert);
参数说明:
cert:
X509结构体。
(4)证书颁发者信息获取函数
函数功能:
获取证书颁发者的信息,返回值数据类型为“X509_NAME*”。
函数定义:
X509_NAME*X509_get_issuer_name(cert);
参数说明:
cert:
X509结构体。
(5)证书拥有者信息获取函数
函数功能:
获取证书使用者的信息,返回值数据类型为“X509_NAME*”。
函数定义:
X509_NAME*X509_get_subject_name(cert);
参数说明:
cert:
X509结构体。
(6)获取证书有效期函数
函数功能:
获得证书的有效期的起始日期和终止日期,返回数据类型为“ANS1_TIME*”。
函数定义:
ANS1_TIME*X509_get_notbefore(cert);
ANS1_TIME*X509_get_notafter(cert);
参数说明:
cert:
X509结构体。
(7)证书公钥获取函数
函数功能:
获取证书上的公钥,返回数据类型为“EVP_PKEY*”。
函数定义:
EVP_PKEY*X509_get_pubkey(cert);
cert:
X509结构体。
(8)证书存储区创建和释放函数
函数功能:
创建和释放一个X509_STORE结构体,用于证书的验证过程。
函数定义:
X509_STORE*X509_STORE_new(void);
VoidX509_STORE_free(X509_STORE*v);
(9)添加证书函数
函数功能:
向证书存储区添加信任的根证书。
函数定义:
intX509_STORE_add_cert(X509_STORE*ctx,X509*cert);
参数说明:
ctx:
X509_STORE类型数据,证书存储区。
cert:
X509结构体,受信任的根证书。
(10)添加证书撤销列表函数
函数功能:
向证书存储区添加证书撤销列表。
函数定义:
intX509_STORE_add_crl(X509_STORE*ctx,X509_CRT*x);
参数说明:
ctx:
X509_STORE*类型数据,证书存储区。
x:
X509_CRT*类型数据,证书撤销列表。
(11)创建和释放证书存储区上下文函数
函数功能:
为证书存储区上下文环境申请内存和释放内存。
函数定义:
X509_STORE_CTX*X509_STORE_CTX_new(void);
voidX509_STORE_CTX_free(X509_STORE*ctx);
(12)初始化证书存储区上下文函数
函数功能:
初始化证书存储区上下文,设置根证书、待验证的证书、CA证书信任链。
操作成功返回1,否则返回0。
函数定义:
IntX509_STORE_CTX_init(X509_STORE_CTX*ctx,X509_STORE*store,X509*x509,STACK_OF(X509)*chain);
参数说明:
ctx:
X509_STORE_CTX*类型数据,上下文。
store:
X509_STORE*类型数据,根证书存储区。
chain:
STACK_OF(X509)*,证书链。
(13)验证证书函数
函数功能:
检查证书链,依次验证上级CA对证书的签名,一直到根证书。
检查证书是否过期,是否已撤销以及其他证书策略。
函数定义:
intX509_verify_cert(X509_STORE_CTX*ctx);
参数说明:
ctx:
X509_STORE_CTX*类型数据,上下文。
五、实验目的:
利用OpenSSL实现对X.509数字证书的操作,包括证书的读取、证书的验证。
六、实验内容:
(1)证书信息读取,通过程序指令显示用户证书的版本号、序列号、颁发者、拥有者、有效期限和用户的公钥
(2)读取受信任的根证书、CA证书链、证书撤销列表和待验证的用户证书,并将其转换为X509结构体,最后验证该证书的合法性
七、实验器材(设备、元器件):
PC(Windows),VS2010,openssl配置环境
八、实验步骤:
在证书的使用过程中,需要获取证书的相关信息如序列号、颁发者的信息以及拥有者的信息,同时还需要验证证书的有效期、合法性以及证书信任链等。
本实验分为两部分:
证书信息读取和证书验证。
(一)证书信息读取
(1)定义一些必须的变量,用以存储证书和证书的相关信息。
参考代码如下:
unsignedcharusrCertificate[4096];//DER证书缓冲区
unsignedlongusrCertificateLen;//证书长度
X509*x509usrCert=NULL;//X509证书结构体
X509_NAME*issuer=NULL;//用于保存证书颁发者的信息
X509_NAME*subject=NULL;//用于保存证书拥有者的信息
X509_NAME_ENTRY*name_entry;//用于保存证书信息
ASN1_INTEGER*Serial=NULL;//用于保存证书序列号
ASN1_TIME*time;//用于保存证书有效期
EVP_PKEY*pubKey;//用于保存证书公钥
longVersion;//用于保存证书版本
(2)将用户的DER编码证书转化为X509结构体,并调用X509_get_***相关函数读取证书的相关信息,参考代码如下:
//调用d2i_X509函数,将用户的DER编码证书转化为X509结构体
X509usrCert=d2i_X509(NULL,&pTmp,usrCertificatelen);
//读取证书版本
Version=X509_get_version(X509usrCert);
//读取证书序列号
Serial=X509_get_serialNumber(X509usrCert);
//读取证书颁发者信息,包括国家、组织、部门、通用名、电子邮件地址等
issuer=X509_get_issuer_name(X509usrCert);
//读取证书拥有者信息,包括国家、组织、部门、通用名、电子邮件地址等
subject=X509_get_subject_name(X509usrCert);
//读取证书的生效日期和失效日期
time=X509_get_notBefore(X509usrCert);
time=X509_get_notBefore(X509usrCert);
//读取证书公钥
pubKey=X509_get_pubkey(X509usrCert);
(3)最后调用X509_free函数释放X509结构体内存。
证书信息读取的流程图如图1所示
图1证书信息读取流程图图2证书验证流程图
(二)证书验证
(1)定义一些必须的变量,用以存储CRL、根证书、待验证用户证书等。
参考代码如下:
unsignedcharderusrCert[4096];//DER证书缓冲区
unsignedlongderusrCertLen;//证书长度
unsignedcharderCrl[4096];//DER证书撤销列表缓冲区
unsignedlongderCrlLen;//证书撤销列表长度
unsignedcharderRootCert[4096];//DER根证书缓冲区
unsignedlongderRootCertLen;//根证书长度
X509_STORE_CTX*ctx=NULL;//证书存储区
X509*X509usrCert=NULL;//X509用户证书
X509*X509CACert=NULL;//X509CA证书
X509*X509RootCert=NULL;//X509根证书
X509_CRL*X509Crl=NULL;//X509证书撤销列表
STACK_OF(X509)*caCertStack=NULL;//CA证书链
X509_STORE*rootCertStore=NULL;//证书存储区
(2)读取受信任的根证书、CA证书链、证书撤销列表和待验证的用户证书,并将其转换为X509结构体。
参考代码如下:
//根证书转换
pTmp=derRootCert;
X509RootCert=d2i_X509(NULL,&pTmp,derRootCertLen);
//用户证书转换
pTmp=derusrCert;
X509usrCert=d2i_X509(NULL,&pTmp,usrCertLen);
//证书撤销列表转换
pTmp=derCrl;
X509Crl=d2i_X509(NULL,&pTmp,derCrlLen);
(3)添加受信任的根证书和证书撤销列表到证书存储区。
参考代码如下:
//新建X509证书存储区
rootCertStore=X509_Store_new();
//添加根证书
X509_STORE_add_cert(rootCertStore,X509RootCert);
//设置证书撤销列表标志位
X509_STORE_set_flags(rootCertStore,X509_V_FLAG_CRL_CHECK);
//添加证书撤销列表
X509_STORE_add_crl(rootCertStore,X509Crl);
(4)添加用户证书和CA证书链。
参考代码如下:
ctx=X509_STORE_CTX_new();
X509_STORE_CTX_init(ctx,rootCertStore,X509usrCert,caCertStack);
(5)验证证书。
X509_verify_cert(ctx);
(6)释放内存。
九、实验数据及结果分析:
在实验一和二的基础上,对之前生成的证书进行读取和验证
(注:
由于前两个实验结果疏于保存,所以这次试验选取的证书其实是助教给的两个“郭靖”“黄飞鸿”证书,之后的实验内容都是以此为基础)
首先是openssl环境配置;很麻烦,在Windows上面;
比如新建一个项目,没有添加路径是运行不了的。
幸好之前上学期做过openssl实验,所以只要在配置路径时加上引用的lib库,include库,以及配置链接器就可以正常引用openssl的相关函数。
以下步骤依次完成证书的读取和验证过程,参照指导书,列出流程:
证书信息读取的流程图如图1所示
实验代码:
#include
#include
#include
#include
#include
#include
#defineMAX_CERT_LEN4096
externenumFile_type{
ROOT_CA=1,
USER_CA=2,
CRL=4
}File_type;
externenumImformation_type{
CA_VERSION,
CA_SERIAL_NUMBER,
CA_NOT_BEFORE,
CA_NOT_AFTER,
CA_PUBLIC_KEY,
CA_COUNTRY_NUMBER=14,
CA_STATE_PROVINCE_NAME=16,
CA_LOCALITY_NAME=15,
CA_ORGANIZATION_NAME=17,
CA_ORGANIZATIONAL_UNIT_NAME=18,
CA_COMMON_NAME=13,
CA_PKCS9_EMAILADDRESS=48
}Imformation_type;
classCertVerfier{
private:
X509*rootCA;
X509*userCA;
X509_CRL*crl;
X509_STORE*rootCAstore;
X509_STORE_CTX*ctx;
STACK_OF(X509)*CAstack;
charmsginfo[1024];
voidDer2X509(constunsignedchar*der_buffer,intder_buffer_len,intfile_type);
public:
CertVerfier();
intLoadCertFile(constchar*filename,intfile_type);
intVerify();
constchar*Get_error_str();
constchar*Get_CA_information(intfile_type,intinformation_type,boolis_issuer_info=false);
intReset(intreset_type);
~CertVerfier();
};
//codebydnpbob
#include"cert_verify.h"
//privatefunction
voidCertVerfier:
:
Der2X509(constunsignedchar*der_buffer,intder_buffer_len,intfile_type){
switch(file_type){
caseROOT_CA:
if(!
rootCA)
rootCA=d2i_X509(NULL,&der_buffer,der_buffer_len);
break;
caseUSER_CA:
if(!
userCA)
userCA=d2i_X509(NULL,&der_buffer,der_buffer_len);
break;
caseCRL:
if(!
crl)
crl=d2i_X509_CRL(NULL,&der_buffer,der_buffer_len);
break;
}
}
//publicfunction
CertVerfier:
:
CertVerfier(){
rootCA=NULL;
userCA=NULL;
crl=NULL;
ctx=NULL;
rootCAstore=NULL;
CAstack=NULL;
}
intCertVerfier:
:
LoadCertFile(constchar*filename,intfile_type){
FILE*fp;
unsignedcharder_buffer[MAX_CERT_LEN];
intder_buffer_len;
if(file_type!
=ROOT_CA&&file_type!
=USER_CA&&file_type!
=CRL){
return-1;
}
fp=fopen(filename,"rb");
if(!
fp){
return-1;
}
if(file_type==ROOT_CA&&rootCA){
Reset(ROOT_CA);
}
if(file_type==USER_CA&&userCA){
Reset(USER_CA);
}
if(file_type==CRL&&crl){
Reset(CRL);
}
der_buffer_len=fread(der_buffer,1,MAX_CERT_LEN,fp);
Der2X509(der_buffer,der_buffer_len,file_type);
fclose(fp);
return0;
}
intCertVerfier:
:
Verify(){
if(rootCA&&userCA&&crl){
if(!
rootCAstore){
rootCAstore=X509_STORE_new();
X509_STORE_add_cert(rootCAstore,rootCA);
X509_STORE_set_flags(rootCAstore,X509_V_FLAG_CRL_CHECK);
X509_STORE_add_crl(rootCAstore,crl);
}
if(!
ctx){
ctx=X509_STORE_CTX_new();
X509_STORE_CTX_init(ctx,rootCAstore,userCA,CAstack);
}
returnX509_verify_cert(ctx);
}
else
return-1;
}
constchar*CertVerfier:
:
Get_error_str(){
if(ctx)
returnX509_verify_cert_error_string(ctx->error);
}
constchar*CertVerfier:
:
Get_CA_information(intfile_type,intinformation_type,boolis_issuer_info){
X509*CA;
X509_NAME*issuer_or_subject=NULL;
intentriesNum;
X509_NAME_ENTRY*name_entry;
ASN1_INTEGER*Serial=NULL;
ASN1_TIME*time;
EVP_PKEY*pubKey;
intVersion;
intNID;
unsignedcharderpubkey[1024],*Ptr;
intderpubkeyLen;
intmsginfoLen;
LPWSTRpUtf8=NULL;
intnUtf8;
intrv;
inti;
char*msginfo_temp;
switch(file_type){
caseROOT_CA:
CA=rootCA;
break;
caseUSER_CA:
CA=userCA;
break;
default:
returnNULL;
}
switch(information_type){
caseCA_VERSION:
Version=X509_get_version(CA);
itoa(Version,msginfo,10);
returnmsginfo;
caseCA_SERIAL_NUMBER:
Serial=X509_get_serialNumber(CA);
for(msginfo_temp=msginfo,i=0;ilength;i++,msginfo_temp+=2){
itoa(Serial->data[i],msginfo_temp,16);
if(Serial->data[i]<16){
*(msginfo_temp+1)=*msginfo_temp;
*msginfo_temp='0';
}
}
*(msginfo_temp+1)='\0';
returnmsginfo;
caseCA_NOT_BEFORE:
time=X509_get_notBefore(CA);
for(i=0;time->data[i]!
='\0';i++){
msginfo[i]=time->data[i];
}
msginfo[i]='\0';
returnmsginfo;
caseCA_NOT_AFTER:
time=X509_get_notAfter(CA);
for(i=0;time->data[i]!
='\0';i++){
msginfo[i]=time->data[i];
}
msginfo[i]='\0';
returnmsginfo;
caseCA_PUBLIC_KEY:
pubKey=X509_get_pubkey(CA);
Ptr=derpubkey;
derpubkeyLen=i2d_PublicKey(pubKey,&Ptr);
for(msginfo_temp=msginfo,i=0;iitoa(derpubkey[i],msginfo_temp,16);
if(derpubkey[i]<16){
*(msginfo_temp+1)=*msginfo_temp;
*msginfo_temp='0';
}
}
*(msginfo_temp+1)='\0';
returnmsginfo;
}