OpenSSL之X509证书用法

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenSSL之X509证书用法相关的知识,希望对你有一定的参考价值。

参考技术A 数字证书就是互联网通讯中标志通讯各方身份信息的一系列数据,提供了一种在Internet上验证您身份的方式,其作用类似于司机的驾驶执照或日常生活中的身份证。它是由一个由权威机构-----CA机构,又称为证书授权(Certificate Authorit y)中心发行的,人们可以在网上用它来识别对方的身份。数字证书是一个经证书授权 中心数字签名的包含公开密钥拥有者信息以及公开密钥的文件。最简单的证书包含一个公开密钥、名称以及证书授权中心的数字签名。一般情况下证书中还包括密钥的有效时间,发证机关(证书授权中心)的名称,该证书的序列号等信息,证书的格式遵循 ITUT X.509国际标准。
一个标准的X.509数字证书包含以下一些内容:
证书的版本信息;
证书的序列号,每个证书都有一个唯一的证书序列号;
证书所使用的签名算法;
证书的发行机构名称,命名规则一般采用X.500格式;
证书的有效期,现在通用的证书一般采用UTC时间格式,它的计时范围为1950-2049;
证书所有人的名称,命名规则一般采用X.500格式;
证书所有人的公开密钥;
证书发行者对证书的签名。

本文假设你已经安装好了OpenSSL,并且持有一份1.1.1的源码。
证书相关的头文件在x509.h和x509v3.h中、源文件在crypto/x509和crypto/x509v3目录中。

这个结构定义了证书申请信息主体。主要字段含义如下:
enc —— 内部编码运算结构,不参与DER编码。
version —— 版本号。
subject —— 申请者信息。
pubkey —— 申请者公钥。
attributes —— 可选属性信息。

这个结构定义了证书申请信息。主要字段含义如下:
req_info —— 版本号。
sig_alg —— 签名算法。
signature —— 申请者私钥签名。

这个结构定义了数字证书的信息主体。主要字段含义如下:
version —— 版本号。
serialNumber —— 证书的序列号。
signature —— 证书采用的签名算法。
issuer —— 证书的颁发者信息。
validity—— 证书的有效期。
subject —— 证书的持有者信息。
key —— 证书的持有者公钥。
issuerUID —— 颁发者唯一标识。
subjectUID —— 持有者唯一标识。
extensions —— 证书的扩展信息。

这个结构定义了完整的X509数字证书。主要字段含义如下:
cert_info —— 证书主体信息。
sig_alg —— 签名算法。
signature —— 签名值,存放CA对该证书采用sig_alg生成的结果。
siginf —— 算名算法信息描述。
ex_data —— 存放证书自定义信息,用于证书验证。
skid —— 主体密钥标识。
akid —— 颁发者密钥标识。
policy_cache —— 证书的策略缓存。
sha1_hash —— 存放证书的sha1摘要值。
aux —— 辅助信息。

在1.1.1中,大多数的数据结构已经不再向使用者开放,从封装的角度来看,这是更合理的。如果你在头文件中找不到结构定义,不妨去源码中搜一搜。

int X509_REQ_set_version(X509_REQ *x, long version);
设置证书请求的版本。
成功返回1,失败返回0。

long X509_REQ_get_version(const X509_REQ *req);
读取证书请求的版本。

X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_txt(X509_NAME_ENTRY **ne, const char *field, int type, const unsigned char *bytes, int len);
创建一个字符串内容项。
成功返回有效指针,失败返回NULL。

int X509_NAME_add_entry(X509_NAME *name, const X509_NAME_ENTRY *ne, int loc, int set);
将内容项加入到name集合中。
成功返回1,失败返回0。

X509_NAME_ENTRY *X509_NAME_get_entry(const X509_NAME *name, int loc);
从name集合中获取指定内容项。
成功返回有效指针,失败返回NULL。

X509_NAME_ENTRY *X509_NAME_delete_entry(X509_NAME *name, int loc);
从name集合中删除指定内容项。
成功返回有效指针,失败返回NULL。

int X509_REQ_set_subject_name(X509_REQ *req, X509_NAME *name);
设置证书请求的申请者信息。
成功返回1,失败返回0。

X509_NAME *X509_REQ_get_subject_name(const X509_REQ *req);
获取证书请求的申请者信息。
成功返回有效指针,失败返回NULL。

int X509_REQ_set_pubkey(X509_REQ *x, EVP_PKEY *pkey);
设置证书请求的申请者公钥。
成功返回1,失败返回0。

EVP_PKEY *X509_REQ_get_pubkey(X509_REQ *req);
获取证书请求的申请者公钥。
成功返回有效指针,失败返回NULL。

int X509_REQ_sign(X509_REQ *x, EVP_PKEY *pkey, const EVP_MD *md);
对证书请求结构进行签名。
成功返回签名长度,失败返回-1。

int X509_REQ_verify(X509_REQ *a, EVP_PKEY *r);
对证书请求结构进行签名验证。
成功返回1,失败返回0。

int X509_REQ_print(BIO *bp, X509_REQ *req);
打印证书请求结构。
成功返回1,失败返回0。

int X509_set_version(X509 *x, long version);
设置证书的版本。
成功返回1,失败返回0。

long X509_get_version(const X509 *x);
读取证书的版本。

int X509_set_issuer_name(X509 *x, X509_NAME *name);
设置证书的颁发者信息。
成功返回1,失败返回0。

X509_NAME *X509_get_issuer_name(const X509 *a);
获取证书的颁发者信息。
成功返回有效指针,失败返回NULL。

int X509_set_subject_name(X509 *x, X509_NAME *name);
设置证书的所有者信息。
成功返回1,失败返回0。

X509_NAME *X509_get_subject_name(const X509 *a);
获取证书的所有者信息。
成功返回有效指针,失败返回NULL。

int X509_set1_notBefore(X509 *x, const ASN1_TIME *tm);
int X509_set1_notAfter(X509 *x, const ASN1_TIME *tm);
设置证书的有效期。
成功返回1,失败返回0。

const ASN1_TIME * X509_get0_notBefore(const X509 *x);
const ASN1_TIME *X509_get0_notAfter(const X509 *x);
获取证书的有效期。
成功返回有效指针,失败返回NULL。

int X509_set_pubkey(X509 *x, EVP_PKEY *pkey);
设置证书的颂发者公钥。
成功返回1,失败返回0。

EVP_PKEY *X509_get_pubkey(X509 *x);
获取证书的颂发者公钥。
成功返回有效指针,失败返回NULL。

int X509_sign(X509 *x, EVP_PKEY *pkey, const EVP_MD *md);
对证书结构进行签名。成功返回签名长度。

int X509_verify(X509 *a, EVP_PKEY *r);
验证证书的签名。成功返回1,失败返回0。

int X509_print(BIO *bp, X509 *x);
打印证书结构。成功返回1,失败返回0。

int X509_check_issued(X509 *issuer, X509 *subject);
检查subject证书是否由issuer颁发。成功返回1,失败返回0。

下面这个例子演示如何使用API生成证书申请文件。

输出:
X509_REQ_set_version() ret:[1]
X509_NAME_ENTRY_create_by_txt() ret:[0x20ef2d0]
X509_NAME_add_entry() ret:[1]
X509_REQ_set_subject_name() ret:[1]
X509_REQ_set_pubkey() ret:[1]
X509_REQ_sign() ret:[64]
PEM_write_bio_X509_REQ() ret:[1]

生成的certreq.pem文件内容:
-----BEGIN CERTIFICATE REQUEST-----
MIHHMHMCAQEwEDEOMAwGA1UEKQwFemhhbjMwWjANBgkqhkiG9w0BAQEFAANJADBG
AkEAxYRRHNO231nDXzt1t6y21BDim3x5xeHDbdhvcP3GVi0reAh8qsd4PzJ9Z7AU
3NgSFunTfYJu4IdKO2ZNNv4uoQIBA6AAMA0GCSqGSIb3DQEBBQUAA0EAQmQRd9e+
ORnnsokq28fG3uImdtnI5lpjf/RLsOJ5QUvbBYcXsZ4poOB/PfBTXIDikX2eBB++
bpzxkTyonMg5TA==
-----END CERTIFICATE REQUEST-----

下面这个例子演示如何使用API读取并解码证书申请文件。

输出:
PEM_read_bio_X509_REQ() ret:[0x1157390]
X509_REQ_verify() ret:[1]
X509_REQ_get_subject_name() ret:[0x1157510]
zhan3

下面这个例子演示如何使用API生成证书文件。但是由于证书的结构非常复杂,这个例子仅仅操作了部分字段。

输出:
X509_set_version() ret:[1]
X509_NAME_ENTRY_create_by_txt() ret:[0x1a9c4d0]
X509_NAME_add_entry() ret:[1]
X509_set_subject_name() ret:[1]
X509_set_issuer_name() ret:[1]
X509_set1_notBefore() ret:[1]
X509_set1_notAfter() ret:[1]
X509_set_pubkey() ret:[1]
X509_sign() ret:[64]
PEM_write_bio_X509() ret:[1]

生成的cert.pem文件内容:
-----BEGIN CERTIFICATE-----
MIIBDDCBt6ADAgEBAgEAMA0GCSqGSIb3DQEBBQUAMBAxDjAMBgNVBCkMBXpoYW4z
MB4XDTIxMDkxMTEzNDkyOVoXDTIxMDkxMTEzNDkyOVowEDEOMAwGA1UEKQwFemhh
bjMwWjANBgkqhkiG9w0BAQEFAANJADBGAkEAvAYbGFNXsmDDYmWDsK6wRrL6/zyP
aJnKIfwHjLhK6f/6LVhHQCRhDPHlWR4lUAwRYzCh6Ypa21nk3mkPxAEOBQIBAzAN
BgkqhkiG9w0BAQUFAANBAGw7dvUpR8FBcuUkRDI/pK+dbYH1WKpUdi82QmATFLfR
4MhRAoybnhYlyxLA3D+c0NfBcl3vk3bhUa/K56ItmpU=
-----END CERTIFICATE-----

下面这个例子演示如何使用API读取并解码证书文件。

输出:
PEM_read_bio_X509() ret:[0x16eb930]
X509_verify() ret:[1]
X509_get_subject_name() ret:[0x16eb7e0]
zhan3

openssl用法详解

OpenSSL 是一个开源项目,其组成主要包括一下三个组件:

  • openssl:多用途的命令行工具

  • libcrypto:加密算法库

  • libssl:加密模块应用库,实现了ssl及tls

openssl可以实现:秘钥证书管理、对称加密和非对称加密 。

1、对称加密

对称加密需要使用的标准命令为 enc ,用法如下:

openssl enc -ciphername [-in filename] [-out filename] [-pass arg] [-e] [-d] [-a/-base64]
       [-A] [-k password] [-kfile filename] [-K key] [-iv IV] [-S salt] [-salt] [-nosalt] [-z] [-md]
       [-p] [-P] [-bufsize number] [-nopad] [-debug] [-none] [-engine id]

常用选项有:

-in filename:指定要加密的文件存放路径

-out filename:指定加密后的文件存放路径

-salt:自动插入一个随机数作为文件内容加密,默认选项

-e:可以指明一种加密算法,若不指的话将使用默认加密算法

-d:解密,解密时也可以指定算法,若不指定则使用默认算法,但一定要与加密时的算法一致

-a/-base64:使用-base64位编码格式

示例:
加密:]# openssl enc -e -des3 -a -salt -in fstab -out jiami
解密:]# openssl enc -d -des3 -a -salt -in fstab -out jiami

2、单向加密

单向加密需要使用的标准命令为 dgst ,用法如下:

openssl dgst [-md5|-md4|-md2|-sha1|-sha|-mdc2|-ripemd160|-dss1] [-c] [-d] [-hex] [-binary]
       [-out filename] [-sign filename] [-keyform arg] [-passin arg] [-verify filename] [-prverify
       filename] [-signature filename] [-hmac key] [file...]

常用选项有:

[-md5|-md4|-md2|-sha1|-sha|-mdc2|-ripemd160|-dss1] :指定一种加密算法

-out filename:将加密的内容保存到指定文件中

示例如下:

技术分享

单向加密除了 openssl dgst 工具还有: md5sum,sha1sum,sha224sum,sha256sum ,sha384sum,sha512sum

示例如下:

技术分享

3、生成密码

生成密码需要使用的标准命令为 passwd ,用法如下:

openssl passwd [-crypt] [-1] [-apr1] [-salt string] [-in file] [-stdin] [-noverify] [-quiet] [-table] {password}

常用选项有:

-1:使用md5加密算法

-salt string:加入随机数,最多8位随机数

-in file:对输入的文件内容进行加密

-stdion:对标准输入的内容进行加密

示例如下:

技术分享

4、生成随机数

生成随机数需要用到的标准命令为 rand ,用法如下:

openssl rand [-out file] [-rand file(s)] [-base64] [-hex] num

常用选项有:

-out file:将生成的随机数保存至指定文件中

-base64:使用base64 编码格式

-hex:使用16进制编码格式

示例如下:

技术分享

5、生成秘钥对

首先需要先使用 genrsa 标准命令生成私钥,然后再使用 rsa 标准命令从私钥中提取公钥。

genrsa 的用法如下:

openssl genrsa [-out filename] [-passout arg] [-des] [-des3] [-idea] [-f4] [-3] [-rand file(s)] [-engine id] [numbits]

常用选项有:

-out filename:将生成的私钥保存至指定的文件中

-des|-des3|-idea:不同的加密算法

numbits:指定生成私钥的大小,默认是2048

一般情况下秘钥文件的权限一定要控制好,只能自己读写,因此可以使用 umask 命令设置生成的私钥权限,示例如下:

技术分享

ras 的用法如下:

openssl rsa [-inform PEM|NET|DER] [-outform PEM|NET|DER] [-in filename] [-passin arg] [-out filename] [-passout arg]
       [-sgckey] [-des] [-des3] [-idea] [-text] [-noout] [-modulus] [-check] [-pubin] [-pubout] [-engine id]

常用选项:

-in filename:指明私钥文件

-out filename:指明将提取出的公钥保存至指定文件中 

-pubout:根据私钥提取出公钥 

示例如下:

技术分享

6、创建CA和申请证书

使用openssl工具创建CA证书和申请证书时,需要先查看配置文件,因为配置文件中对证书的名称和存放位置等相关信息都做了定义,具体可参考 /etc/pki/tls/openssl.cnf 文件。

技术分享

技术分享

(1)、创建自签证书

第一步:创建为 CA 提供所需的目录及文件

技术分享

第二步:指明证书的开始编号

]# echo 01 >> serial 

第三步:生成私钥,私钥的文件名与存放位置要与配置文件中的设置相匹配;

技术分享

第四步:生成自签证书,自签证书的存放位置也要与配置文件中的设置相匹配,生成证书时需要填写相应的信息;

技术分享

命令中用到的选项解释:

-new:表示生成一个新证书签署请求

-x509:专用于CA生成自签证书,如果不是自签证书则不需要此项

-key:生成请求时用到的私钥文件

-out:证书的保存路径

-days:证书的有效期限,单位是day(天),默认是365天

(2)颁发证书

在需要使用证书的主机上生成证书请求,以 httpd 服务为例,步骤如下:

第一步:在需要使用证书的主机上生成私钥,这个私钥文件的位置可以随意定

第二步:生成证书签署请求

第三步:将请求通过可靠方式发送给 CA 主机

技术分享

第四步:CA 服务器拿到证书签署请求文件后颁发证书,这一步是在 CA 服务器上做的

技术分享

查看证书信息的命令为:

技术分享

(3)吊销证书

吊销证书的步骤也是在CA服务器上执行的,以刚才新建的 httpd.crt 证书为例,吊销步骤如下:

第一步:在客户机上获取要吊销证书的 serial 和 subject 信息 

第二步:根据客户机提交的 serial 和 subject 信息,对比其余本机数据库 index.txt 中存储的是否一致 

第三步:执行吊销操作

技术分享

第四步:生成吊销证书的吊销编号 (第一次吊销证书时执行)

]# echo 01 > /etc/pki/CA/crlnumber

第五步:更新证书吊销列表

]# openssl ca -gencrl -out /etc/pki/CA/crl/ca.crl

查看 crl 文件命令:

]# openssl crl -in /etc/pki/CA/crl/ca.crl -noout -text

 

原文  http://www.178linux.com/48764

以上是关于OpenSSL之X509证书用法的主要内容,如果未能解决你的问题,请参考以下文章

使用 OpenSSL 以编程方式创建 X509 证书

python openssl x509怎么用

请教使用OpenSSL读写X509数字证书,有代码

(14) openssl x509(签署和自签署)

OpenSSL之genrsa&rsa&req&x509子命令用法

如何使用包括 CRL 分发点的 openssl 创建证书?