openssl - 数字证书的编程解析

原文链接: http://www.cangfengzhe.com/wangluoanquan/37.html

这篇文章主要介绍PKI公钥体系中非常核心元素——数字证书的编程解析。在SSL,SET等安全协议通信时,数字证书用于通信双方进行身份认证,并且依靠数字证书和非对称加密算法加密传输数据,或者根据数字证书协商通信双方的共享密钥。所以,用户想要开发自己的应用,实现身份认证,必须对数字证书进行解析。根据解析结果,符合一定条件的终端用户,才可以接入。

1、证书格式介绍

现有的数字证书大都采用了X.509规范,主要由一下信息组成:版本号,证书序列号,有效期(证书生效时间和失效时间),用户信息(姓名、单位、组织、城市、国家等),颁发者信息,其他扩展信息,拥有者的公钥,CA对证书整体的签名,如图1所示。

图1 X.509 V3数字证书格式

OPENSSL开发包中实现了对X.509证书解析的所有操作,如获得证书的版本、公钥、拥有者信息、颁发者信息、有效期等,下面就向大家介绍如何通过编程,解析出我们需要的证书信息。

2、证书解析编程实现

2.1 数据结构介绍

X.509证书在OPENSSL中定了专门的数据结构,方便用户对其操作,其结构如下所示:
struct x509_st
    {
        X509_CINF *cert_info;                    
        X509_ALGOR *sig_alg;                   
        ASN1_BIT_STRING *signature;                  
    int valid;
        int references;
        char *name;
        CRYPTO_EX_DATA ex_data;
        long ex_pathlen;
        long ex_pcpathlen;
        unsigned long ex_flags;
        unsigned long ex_kusage;
        unsigned long ex_xkusage;
        unsigned long ex_nscert;
        ASN1_OCTET_STRING *skid;
        struct AUTHORITY_KEYID_st *akid;
        X509_POLICY_CACHE *policy_cache;
#ifndef OPENSSL_NO_SHA
        unsigned char sha1_hash[SHA_DIGEST_LENGTH];
#endif 
        X509_CERT_AUX *aux;
        };

该结构表示了一个完整的数字证书。各项意义如下:
cert_info:证书主体信息;
sig_alg:签名算法;
signature:签名值,存放CA对该证书签名的结果;
valid:是否是合法证书,1为合法,0为未知;
references:引用次数,被引用一次则加一;
name:证书持有者信息;
ex_data:扩展数据结构,用于存放用户自定义的信息;
ex_pathlen:证书路径长度;
ex_kusage:密钥用法;
ex_xkusage:扩展密钥用法;
ex_nscert:Netscape证书类型;
skid:主体密钥标识;
akid:颁发者密钥标识;
policy_cache:各种策略缓存;
sha1_hash:存放证书的sha1摘要值;
aux:辅助信息;

其中,证书主体信息—X509_CINF结构体定义如下:
typedef struct x509_cinf_st
    {
        ASN1_INTEGER *version;                                       //证书版本
        ASN1_INTEGER *serialNumber;                              //序列号
        X509_ALGOR *signature;                                        //签名算法  
        X509_NAME *issuer;                                               //颁发者     
        X509_VAL *validity;                                                // 有效时间  
        X509_NAME *subject;                                            // 持有者     
        X509_PUBKEY *key;                                              // 公钥  
        ASN1_BIT_STRING *issuerUID;                          // 颁发者唯一标识    
        ASN1_BIT_STRING *subjectUID;                        // 持有者唯一标识     
        STACK_OF(X509_EXTENSION) *extensions;         // 扩展项     
    } X509_CINF;

2.2 函数介绍

根据上述结构体可知,我们可以通过编程,读取结构体中的证书信息,下面介绍一下几个常用的函数。

(1)编码转换函数

数字证书分为DER编码和PEM编码,所以对应的操作是不一样的。对于DER编码的证书,我们可以通过函数:X.509 * d2i_X509(x509 **cert , unsigned char **d , int len),返回一个X.509的结构体指针。而对于PEM编码的证书,我没找到一个函数来实现编码转换,但可以通过OPENSSL提供的BIO函数,实现这一功能:先调用BIO_new_file() 返回一个BIO结构体,然后通过 PEM_read_bio_X509() 返回一个X.509结构体。

(2)获得证书信息

其实获得证书信息的操作,仅仅是解析X509和X509_CINF结构体的操作,可以得到如:证书版本,颁发者信息,证书拥有者信息,有效期,证书公钥等信息,主要函数如下:
X509_get_version();              //获得证书版本;
X509_get_issuer_name();          //获得证书颁发者信息
X509_get_subjiect_name();        //获得证书拥有者信息
X509_get_notBefore();           //获得证书起始日期
X509_get_notAfter();            //获得证书终止日期
X509_get_pubkey();             //获得证书公钥

其中,函数具体的参数和使用,结合下面编程代码向大家介绍。

2.3编程实现

通过上述的函数和结构体的介绍,下面编程实现解析一个数字证书就非常简单了。在此,我编写了一个解析证书的软件,实现关键代码如下:
fp=fopen(filename.GetBuffer(0),"rb");
if(fp==NULL)
{
MessageBox("读取证书错误");
return ;
}
Certlen=fread(Cert,1,4096,fp);
fclose(fp);
//判断是否为DER编码的用户证书,并转化为X509结构体
pTmp=Cert;
usrCert = d2i_X509(NULL,(const unsigned char ** )&pTmp,Certlen);
if(usrCert==NULL)
{
BIO *b;
/* 判断是否为PEM格式的数字证书 */
b=BIO_new_file(filename.GetBuffer(0),"r");
usrCert=PEM_read_bio_X509(b,NULL,NULL,NULL);
BIO_free(b);
if(usrCert==NULL)
{
MessageBox("转化格式错误!");
    return;
}
}
//解析证书
X509_NAME *issuer = NULL;//X509_NAME结构体,保存证书颁发者信息
X509_NAME *subject = NULL;//X509_NAME结构体,保存证书拥有者信息
//获取证书版本
Version = X509_get_version(usrCert);
//获取证书颁发者信息,X509_NAME结构体保存了多项信息,包括国家、组织、部门、通用名、mail等。
issuer = X509_get_issuer_name(usrCert);
//获取X509_NAME条目个数
entriesNum = sk_X509_NAME_ENTRY_num(issuer->entries);
//循环读取各条目信息
for(i=0;i<entriesNum;i++)
{
//获取第I个条目值
name_entry = sk_X509_NAME_ENTRY_value(issuer->entries,i);
//获取对象ID
Nid = OBJ_obj2nid(name_entry->object);
//判断条目编码的类型
if(name_entry->value->type==V_ASN1_UTF8STRING)
//把UTF8编码数据转化成可见字符
{
nUtf8 = 2*name_entry->value->length;
pUtf8 = (unsigned short *)malloc(nUtf8);
memset(pUtf8,0,nUtf8);
rv = MultiByteToWideChar(
CP_UTF8,
0,
(char*)name_entry->value->data,
name_entry->value->length,
pUtf8,
nUtf8);
rv = WideCharToMultiByte(
CP_ACP,
0,
pUtf8,
rv,
(char*)msginfo,
nUtf8,
NULL,
NULL);
free(pUtf8);
pUtf8 = NULL;
msginfoLen = rv;
msginfo[msginfoLen]=‘\0‘;
}
else
{
msginfoLen=name_entry->value->length;
memcpy(msginfo,name_entry->value->data,msginfoLen);
msginfo[msginfoLen]=‘\0‘;
}
//根据NID打印出信息
switch(Nid)
{
case NID_countryName://国家
tmp.Format("issuer ‘s countryName:%s\n",msginfo);
        m_list.InsertString(-1,tmp);
        tmp.Empty();
break;
case NID_stateOrProvinceName://省
tmp.Format("issuer ‘s ProvinceName:%s\n",msginfo);
        m_list.InsertString(-1,tmp);
        tmp.Empty();
break;
case NID_localityName://地区
tmp.Format("issuer ‘s localityName:%s\n",msginfo);
        m_list.InsertString(-1,tmp);
        tmp.Empty();
break;
case NID_organizationName://组织
tmp.Format("issuer ‘s organizationName:%s\n",msginfo);
        m_list.InsertString(-1,tmp);
        tmp.Empty();
break;
case NID_organizationalUnitName://单位
tmp.Format("issuer ‘s organizationalUnitName:%s\n",msginfo);
        m_list.InsertString(-1,tmp);
        tmp.Empty();
break;
case NID_commonName://通用名
tmp.Format("issuer ‘s commonName:%s\n",msginfo);
        m_list.InsertString(-1,tmp);
        tmp.Empty();
break;
case NID_pkcs9_emailAddress://Mail
tmp.Format("issuer ‘s emailAddress:%s\n",msginfo);
        m_list.InsertString(-1,tmp);
        tmp.Empty();
break;
}//end switch
}
//获取证书主题信息,与前面类似,在此省略
subject = X509_get_subject_name(usrCert);
………

//获取证书生效日期
time = X509_get_notBefore(usrCert);
tmp.Format("Cert notBefore:%s\n",time->data);
m_list.InsertString(-1,tmp);
tmp.Empty();
//获取证书过期日期
time = X509_get_notAfter(usrCert);
tmp.Format("Cert notAfter:%s\n",time->data);
m_list.InsertString(-1,tmp);
tmp.Empty();
//获取证书公钥
pubKey = X509_get_pubkey(usrCert);
pTmp=derpubkey;
//把证书公钥转为DER编码的数据
derpubkeyLen=i2d_PublicKey(pubKey,&pTmp);
printf("PublicKey is: \n");
for(i = 0; i < derpubkeyLen; i++)
{
CString tmpp;
tmpp.Format("%02x", derpubkey[i]);
tmp=tmp+tmpp;
}
m_list.InsertString(-1,tmp);
   //释放结构体内存
X509_free(usrCert);

使用软件解析证书效果,如下图所示:

图2 解析效果

3、结束语

通过上述介绍,相信大家对数字证书又有了更进一步的了解。在开发网络通信软件,需要加入身份认证功能时,大家可以根据解析出来的证书信息,与自己的访问策略相对比,实现访问控制。

数字证书在信息安全中处于重要地位,随着密码学的发展,数字证书的应用也会越来越广。

时间: 2024-08-02 12:53:00

openssl - 数字证书的编程解析的相关文章

openssl数字证书常见格式与协议介绍

证书主要的文件类型和协议有: PEM.DER.PFX.JKS.KDB.CER.KEY.CSR.CRT.CRL .OCSP.SCEP等. PEM – Openssl使用 PEM(Privacy Enhanced Mail)格式来存放各种信息,它是 openssl 默认采用的信息存放方式.Openssl 中的 PEM 文件一般包含如下信息: 内容类型:表明本文件存放的是什么信息内容,它的形式为“——-BEGIN XXXX ——”,与结尾的“——END XXXX——”对应. 头信息:表明数据是如果被处

C#编程总结(十一)数字证书

C#编程总结(十一)数字证书 之前已经通过文章介绍了数字证书的基础知识,包括加密和数字签名. 具体可见: 1.C#编程总结(七)数据加密——附源码 2.C#编程总结(八)数字签名 这里来讲述数字证书的概念.作用.工作原理以及具体应用.希望能够给大家一个清晰的认识. 一.概念 数字证书就是互联网通讯中标志通讯各方身份信息的一串数字,提供了一种在Internet上验证通信实体身份的方式,其作用类似于司机的驾驶执照或日常生活中的身份证.它是由一个由权威机构-----CA机构,又称为证书授权(Certi

OpenSSL - 数据加密和数字证书

功能应用: 消息摘要,给文件或数据生成消息摘要,消息摘要只能校验数据的完整性,如SHA.MD5 数据加密和解密:对数据进行加密解密,OpenSSL实现了所有加密算法 数字证书:可以通过命令行或代码生成证书,证书内包含了公钥 数字签名:利用加密算法对数据进行签名,验证数据来源可靠性,如RSA 随机数字:产生可靠的随机数 加密算法: HASH算法:SHA.MD5等,不可逆加密,用于校验数据的完整性. 对称加密算法:DES.3DES.DESX等,双方使用相同的密钥进行加密解密. 非对称算法:RSA.E

OpenSSL 与 SSL 数字证书概念贴

SSL/TLS 介绍见文章 SSL/TLS原理详解. 如果你想快速自建CA然后签发数字证书,请移步 基于OpenSSL自建CA和颁发SSL证书. 首先简单区分一下HTTPS.SSL.OpenSSL三者的关系: SSL是在客户端和服务器之间建立一条SSL安全通道的安全协议,而OpenSSL是TLS/SSL协议的开源实现,提供开发库和命令行程序.常说的HTTPS是HTTP的加密版,底层使用的加密协议是SSL. 1.PKI.CA与证书 PKI 就是 Public KeyInfrastructure 的

数字证书、CA及PKI,openssl使用

对称加密:DES,3DES AES 功能:只能保证机密性 非对称加密:(公钥加密):是通过数学函数来算出的.常用的RSA,DSS(只能加密,不能签名),ECC(椭圆曲线算法,要比RSA还要安全,但是不成熟) 功能:身份验证,密钥交换,机密性 单向加密:提取数据的特征码.MD5,SHA1 SHA2 SHA3(安全哈希算法) 功能:数据完整性 1.发送方使用选定的单向加密算法计算原始数据的特征码. 2.发送方使用自己的私钥加密特征码,附加于原始数据后面. 3.发送方生成一次性对称密钥,并使用此密钥加

用Keytool和OpenSSL生成和签发数字证书

一)keytool生成私钥文件(.key)和签名请求文件(.csr),openssl签发数字证书      J2SDK在目录%JAVA_HOME%/bin提供了密钥库管理工具Keytool,用于管理密钥.证书和证书链.Keytool工具的命令在JavaSE6中已经改变,不过以前的命令仍然支持.Keytool也可以用来管理对称加密算法中的密钥. 最简单的命令是生成一个自签名的证书,并把它放到指定的keystore文件中: keytool -genkey -alias tomcat -keyalg

转: 数字证书原理 https 完整过程解析

点评: 讲的非常的详细与全面,值得一看. 转: http://www.cnblogs.com/JeffreySun/archive/2010/06/24/1627247.html 文中首先解释了加密解密的一些基础知识和概念,然后通过一个加密通信过程的例子说明了加密算法的作用,以及数字证书的出现所起的作用.接着对数字证书做一个详细的解释,并讨论一下windows中数字证书的管理,最后演示使用makecert生成数字证书.如果发现文中有错误的地方,或者有什么地方说得不够清楚,欢迎指出! 1.基础知识

常见的数字证书格式与格式转换

常见的数字证书格式 CER后缀的证书文件有两种编码:第一种是DER二进制编码,第二种是:ASE64编码(也就是.pem)  p7b一般是证书链,里面包括1个到多个证书  pfx是指以pkcs#12格式存储证书的公钥和相应私钥. 在Security编程中,有几种典型的密码交换信息文件格式:  DER-encoded certificate: .cer, .crt  PEM-encoded message: .pem  PKCS#12 Personal Information Exchange: .

HTTPS中的对称密钥加密,公开密钥加密,数字证书

HTTPS中的对称密钥加密,公开密钥加密,数字证书 密钥 我们将未加密的内容称为明文,加密之后的内容称为密文. 简单来说,要加密一段明文,可以将这段内容输入到一个加密函数中,输出密文.但这种简单的加密方式存在被人盗取到加密函数从而破解明文的危险,且加密函数一般构成复杂,一旦被盗取更换成本较高. 于是人们想出了一个办法,在加密函数中再添加一个参数,这个参数只有通信双方知道,没有参数则无法正确解密出密码.这个参数被称为密钥.对于同一个加密函数而言,密钥值的不同则加密方式也不同,得出的密文也就不同.这