使用OpenSSL工具制作X.509证书的方法及其注意事项总结
怎样使用OpenSSL工具生成根证书与应用证书
本文由CSDN-蚍蜉撼青松 【主页:http://blog.csdn.net/howeverpf】原创。转载请注明出处!
零、写在前面
近期出于工作须要,倒腾了一下怎样生成X.509证书。在此过程中遇到一些问题。也查过网上非常多资料,磕磕碰碰,总算依照既定要求达到了目标。由于感觉网上的资料太散。查找起来不非常方便,所以在这里做一个总结。
基本的參考信息来源是下面三个:
- 《OpenSSL编程》(赵春平 著)【一本难得的中文资料,未出版】
- 《OpenSSL官方文档---OpenSSL命令》(英文),差点儿能够找到全部问题的答案和原因,可是由于非常多时候不知道问题出在哪里,所以还是须要另外查资料
- 《互动百科---SSL》,说明了证书中各DN字段的含义
一些前辈的博文,也对我高速定位问题提供了非常大的帮助,在此表示感谢!并列举例如以下:
- 博客园 - rusty,《Openssl使用生成CA总结》 ,提到了须要提前建好一些文件夹和文件
- 百度空间 - mars208,《使用openssl创建CA》,提到了签发策略的问题
- ChinaUnix - ehyyngp,《使用openssl签发证书》,提到了中级证书的签发问题
一、步骤简记
以生成一个二级证书链为例,将会用到下面命令:
// 生成顶级CA的公钥证书和私钥文件。有效期10年(RSA 1024bits,默认)
openssl req -new -x509 -days 3650 -keyout CARoot.key -out CARoot.crt
// 为顶级CA的私钥文件去除保护口令
openssl rsa -in CARoot.key -out CARoot.key
// 生成顶级CA的公钥证书和私钥文件。有效期15年(RSA 2048bits。指定)
openssl req -newkey rsa:2048 -x509 -days 5480 -keyout CARoot.key -out CARoot.crt
// 为顶级CA的私钥文件去除保护口令
openssl rsa -in CARoot.key -out CARoot.key
// 为应用证书/中级证书生成私钥文件
openssl genrsa -out app.key 2048
// 依据私钥文件。为应用证书/中级证书生成 csr 文件(证书请求文件)
openssl req -new -key app.key -out app.csr
// 使用CA的公私钥文件给 csr 文件签名,生成应用证书,有效期5年
openssl ca -in app.csr -out app.crt -cert CARoot.crt -keyfile CARoot.key -days 1826 -policy policy_anything
// 使用CA的公私钥文件给 csr 文件签名。生成中级证书,有效期5年
openssl ca -extensions v3_ca -in app.csr -out app.crt -cert CARoot.crt -keyfile CARoot.key -days 1826 -policy policy_anything
依据生成目标不同。以上命令能够分为三组。当中,前面两组都用于生成自签名的顶级CA(差别仅仅在于密钥长度不同),实际应用中仅仅需依据需求选择一组就可以。
最后一组用于生成非自签名的证书。包含中级证书与应用证书。所谓中级证书,是具有继续颁发下级证书权限的子CA。而本文中所说的应用证书,特指不能用来继续颁发下级证书,仅仅能用来证明个体身份的证书。顶级CA在签发二者的时候。仅仅是多少一个 -extensions v3_ca 选项的差别,这个选项赋予被签发的证书继续签发下级证书的权力。
【详參2.5[3]小节相关介绍】
二、各步具体解释
2.1 生成自签名根证书(即顶级CA)
典型演示样例:openssl req -new -x509 -days 5480 -keyout CA.key -out CA.crt
[1] 命令选项和參数解读
演示样例中,各选项(及參数)的意义例如以下:
req //使用openssl的req子命令
-new //生成新的证书请求
-x509 //生成自签名证书
-days 5480 //自签名证书的有效期5480天(15年)【仅当使用了 -x509 选项后有效】
-keyout CA.key //私钥文件名称指定为CA.key【此选项的一般作用是新生成文件命名。但若同一时候使用了-key选项,则此选项用于原私钥文件的更名】
-out CA.crt //指定输出所生成自签名证书的信息到文件。且文件名称为CA.crt【建议不要省略】
当中。-days。-keyout 两个选项能够省略,省略的话使用默认值。有效期默觉得 30 天【由程序内部在变量初始化的时候指定,与配置文件无关】。私钥文件名称的默认值由配置文件 openssl.cnf 中相关条目指定。没改过的话为 privkey.pem。
选项 -out 若是省略的话,openssl不会以文件形式输出生成的 证书/证书请求。而是会默认将文件的信息直接打印到屏幕上,这在大多数情况下,是不符合我们要求的。所以建议这个选项最好不要省略!
req子命令能够通过 -key 选项为证书请求指定使用一个已存在的私钥文件。但在演示样例中的情况下。尽管使用了-new 和 -x509两个选项。但没有使用 -key 选项,这时。req子命令会自己主动为自签名证书生成一个RSA私钥。密钥长度的默认值由配置文件 openssl.cnf 中的相关条目指定,没改过的话为 1024 bits。
[2] 关于私钥文件加密口令的指定
执行中会提示输入加密口令。例如以下:
writing new private key to 'CA.key'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
此口令用于加密私钥文件 CA.key 中的私钥信息,假设不想在执行过程中还要输入加密口令,则能够使用选项 -passout 在命令中直接指定。
选项 -passout 的使用形式为:
-passout arg
当中。arg是选项 -passout 的參数,其格式有多种。详參《OpenSSL官方文档》中关于"PASS_PHRASE_ARGUMENTS"的介绍。
本小节典型演示样例中的命令,能够用选项 -passout 改造例如以下:
openssl req -new -x509 -days 5480 -keyout CA.key -out CA.crt -passout pass:1314
由于Linux系统中能够使用history命令查看历史指令记录。所以出于安全方面的考量,一般如非必要。不建议在命令中直接指定口令。
这与mysql登录的时候不在 -p 选项里直接指定登录口令的原因是一致的。
[3] 关于证书请求文件里的DN字段
执行中会提示输入一些 Distinguished Name fields,即证书的识别名信息字段,简称为DN字段,例如以下:
You are about to be asked to enter information that will be incorporated into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [GB]:US
State or Province Name (full name) [Berkshire]:California
Locality Name (eg, city) [Newbury]:
Organization Name (eg, company) [My Company Ltd]:GeoAuth Inc.
Organizational Unit Name (eg, section) []:.
Common Name (eg, your name or your server's hostname) []:Authentication Global Root
Email Address []:.
这些DN字段大部分有默认值。默认值由配置文件 openssl.cnf中相关条目指定。如要在某一个DN字段使用默认值。则无需输入不论什么信息,直接点击"Enter"键;假设确实某个DN字段的值要置为空。则输入一个 '.' 后,点击"Enter"键。
这些DN字段主要是拿来识别证书持有者身份的,下表是关于它们的缩写、说明和一些填写说明。【此部分參考了互动百科的SSL条目】
DN字段名 | 缩写 | 说明 | 填写要求 |
Country Name | C | 证书持有者所在国家 | 要求填写国家代码,用2个字母表示 |
State or Province Name | ST | 证书持有者所在州或省份 | 填写全称。可省略不填 |
Locality Name | L | 证书持有者所在城市 | 可省略不填 |
Organization Name | O | 证书持有者所属组织或公司 | 不妨填一下 |
Organizational Unit Name | OU | 证书持有者所属部门 | 可省略不填 |
Common Name | CN | 证书持有者的通用名 | 必填。 对于非应用证书,它应该在一定程度上具有惟一性; 对于应用证书,一般填写服务器域名或通配符样式的域名。 |
Email Address | 证书持有者的通信邮箱 | 可省略不填 |
表2-1 DN字段的说明
注:表中所谓,证书不是应用证书时,其持有者的通用名要有“唯一性”。是指其通用名不要与一般主机上常见的信任证书列表或撤销证书列表中的证书产生反复。
假设不想在执行过程中逐个输入这些DN字段的值,则能够使用 -subj 选项在命令中直接指定。
选项 -subj 的使用形式为:
-subj arg
当中。arg是选项 -subj 的參数。其格式相似于:/type0=value0/type1=value1/type2=... 形式。
每个 /type=value 形式的单元,都相应了一个完整的DN字段。
当中,
- / 是每个DN字段的開始标志;
- type0、type1等等,就是表2-1中提到的DN字段名的缩写。
- =是DN字段的名和值之间的间隔符;
- value0、value1等等。就是原本你要在执行过程中逐个输入的DN字段的值。
对于您要将值置为空的DN字段,您能够略去不写。本小节典型演示样例中的命令,能够用 -subj 选项改造例如以下【略去了 L 与 OU 两个DN字段】:
openssl req -new -x509 -days 5480 -subj /C=US/ST=California/O=GeoAuth\ Inc./CN=Authentication\ Global\ Root -keyout CA.key -out CA.crt
须要特别注意的是,假设您设定的DN字段的值假设存在一些特殊字符【比方 (空格)、((半角左括号)、)(半角右括号)……】,必须经过\(反斜杆)转义。
上例中已经给出了空格转义的情况。
[4] 怎样指定自签名证书的密钥长度和类型
如前所述,演示样例仅仅能生成密钥长度为1024bits的RSA公私钥对。
假设要生成密钥长度不为1024bits的RSA公私钥对,或是其它类型的【比方DSA、EC】公私钥对。则必须使用选项 -newkey 来取代 -new 。
选项 -newkey 的使用方法比較复杂,如需具体了解,请參看《OpenSSL官方文档》的相关页面。本小节典型演示样例中的命令等效于下面命令:
openssl req -newkey rsa:1024 -x509 -days 5480 -keyout CA.key -out CA.crt
要生成一个密钥长度为2048bits的RSA公私钥对,命令为:
openssl req -newkey rsa:2048 -x509 -days 5480 -keyout CA2048.key -out CA2048.crt
2.2 为顶级CA的私钥文件去除加密保护
上节提到,顶级CA的私钥文件是经过加密保护的,以后每当需读取 CA.key 文件里的私钥信息时。都需输入解密口令。这样的做法适合有安全需求的场合。但假设觉得不方便,也能够去除这个口令。
典型演示样例:openssl rsa -in CA.key -out CA.key
[1] 命令选项和參数解读
演示样例中,各选项/參数的意义例如以下:
rsa //使用openssl的rsa子命令
-in CA.key //经加密保护的私钥文件
-out CA.key //解除加密保护后的私钥文件【能够改名】
[2] 关于私钥文件解密口令的指定
执行中会提示输入解密口令,例如以下:。
Enter pass phrase for CA.key:
writing RSA key
假设不想在执行过程中还要输入解密口令,则能够使用选项 -passin 在命令中直接指定。选项 -passin 的使用形式为:
-passin arg
当中。arg是选项 -passin 的參数,其格式同选项 -passout 的參数,详參《OpenSSL官方文档》中关于"PASS_PHRASE_ARGUMENTS"的介绍。
本小节典型演示样例中的命令。能够用选项 -passin 改造例如以下:
openssl rsa -in CA.key -out CA.key -passin pass:1314
基于同选项 -passout 一样的考量,一般不建议直接在命令中指定解密口令。
[3] rsa子命令的实际功能
rsa子命令的功能。更完整来说,应该是RSA密钥的管理。除了此处用到的去除加密保护。还能够用来:更换加解密口令。更换加解密算法【DES、三重DES、IDEA(官方文档上提到过,可是有些版本号好像不支持,比方说我安装的)、AES(官方文档上没提到。我安装的版本号支持)】,更换密钥文件的编码方式等等。
2.3 为应用证书/中级证书生成私钥文件
典型演示样例:openssl genrsa -out app.key 2048
[1] 命令选项和參数解读
演示样例中,各选项/參数的意义例如以下:
genrsa //使用openssl的genrsa子命令
-out app.key //指定输出生成的私钥信息到文件,且文件名称为app.key【建议别省略】
2048 //指定所生成私钥的比特长度【务必放在最后一个】
当中。选项 -out 若是省略的话,openssl不会以文件形式输出生成的 私钥信息,而是会默认将私钥的信息直接打印到屏幕上。这不符合我们的要求。
所以建议这个选项不要省略!
genrsa子命令还能够有其它一些选项及參数,但不论还有多少选项。都必须把指定私钥长度的參数放在最后一个。
【假设指定私钥长度的參数不是最后一个,则其后的參数好像会被舍弃。】
[2] 私钥文件的加密保护
本小节典型演示样例所给出的命令。生成的是未经不论什么加密保护的私钥文件。这样的方式用起来比較方便。但非常不安全。假设要为私钥文件附加加密保护。则有两种方式:
- A.在生成私钥文件的同一时候就指定输出前要用某种加密算法加密保护;
- B.生成明文的私钥文件后用 rsa 子命令附加某种加密算法的加密保护。
我计算机上安装的openssl版本号,在两种方式下都支持这些加密算法选项:-des,-des3。-aes128。-aes192。-aes256。以加密选用192位的AES算法为例,命令例如以下:
// 在生成私钥文件的同一时候就指定输出前要用192位的AES算法加密保护
openssl genrsa -aes192 -out app.key 1024
// 生成明文的私钥文件后用 rsa 子命令附加192位的AES算法加密保护
openssl rsa -aes192 -in app.key -out app.key
上例中的两个命令。都会要求在执行中输入加密口令。相同的。尽管不建议,可是openssl依旧支持在命令中使用选项 -passout 指定加密口令,选项 -passout 的使用方法參考2.1[2]小节。唯一须要额外注意的是,对于genrsa子命令。选项 -passout 应放在 指定密钥长度的參数 前面。
2.4 为应用证书/中级证书生成 csr 文件【证书请求文件】
典型演示样例:openssl req -key app.key -out app.csr
[1] 命令选项和參数解读
演示样例中。各选项/參数的意义例如以下:
req //使用openssl的req子命令
-new //生成新的证书请求
-key app.key //指定是为app.key文件里的私钥生成证书请求
-out app.csr //指定输出所生成证书请求的信息到文件。且文件名称为app.csr
这和2.1节使用的是openssl的同一个子命令。所以參数的意义非常多具有共通性。
命令执行中也会要求输入一些DN字段的值。參看本文2.1 [3] 小节中的相关介绍。
相同的。能够使用-subj选项在命令中直接指定这些DN字段的值。
2.5 为 csr 文件签名。生成应用证书/中级证书
典型演示样例:openssl ca -in app.csr -out app.crt -cert CA.crt -keyfile CA.key -days 1826 -policy policy_anything
[1] 命令选项和參数解读
演示样例中,各选项/參数的意义例如以下:
ca //使用openssl的ca子命令
-in app.csr //指定待签发证书的 CSR文件为 app.csr
-out app.crt //指定输出所签发证书的信息到文件。且文件名称为app.crt【建议不要省略】
-cert CA.crt //指定为应用/中级证书签名的CA的公钥证书为CA.crt【用到CA证书的持有者信息】
-keyfile CA.key //指定为应用/中级证书签名的CA的私钥文件为CA.key【用CA私钥实际执行签名】
-days 1826 //指定所签发证书的有效期为1826天(5年)
-policy policy_anything //指定签发策略为 policy_anything 【即,同意所签发证书的持有者信息和颁发者信息之间不遵守不论什么匹配策略】
当中。选项 -out 若是省略的话,openssl不会以文件形式输出生成的 应用证书/中级证书信息。而是会默认将证书的信息直接打印到屏幕上。这一般不符合我们的要求。
所以建议这个选项不要省略!
[2] 关于签发策略
在本节的典型演示样例中,我们使用了选项-policy来指定签发策略为 policy_anything。假设没有使用此选项,则签发策略使用由配置文件 openssl.cnf 中相关条目指定的默认策略。假设您没动过该配置文件的话,则默认策略为 policy_match。此策略要求CA的公钥证书和应用证书请求文件里的Country Name、State or Province Name、Organization Name这三个字段必须 match 【也就是一样】。假设您在应用证书请求文件里指定了和CA的公钥证书不一样的Country Name,且没有使用选项-policy,则会得到相似于下方的提示:
The countryName field needed to be the same in the
CA certificate (US) and the request (CN)
查看配置文件 openssl.cnf 中相关条目,我们能够看到下面内容,
# A few difference way of specifying how similar the request should look
# For type CA, the listed attributes must be the same, and the optional
# and supplied fields are just that :-)
policy = policy_match
# For the CA policy
[ policy_match ]
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
# For the 'anything' policy
# At this point in time, you must list all acceptable 'object'
# types.
[ policy_anything ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
看到这,原因就非常显然了。所以若是您要在应用证书请求文件里指定和CA的公钥证书不一样的C/ST/O。且要签名成功。则有下面三种方式:
- 加上-policy选项,指定本次使用的签发策略为 policy_anything;
- 将配置文件 openssl.cnf 中的默认策略由 policy_match改成 policy_anything;
- 将策略 policy_match 中的相关条目由 match改成 optional 。
为什么openssl会使用这样的默认策略呢?事实上非常easy,openssl认定。仅当您建立组织内部的信任关系时,您才须要自己做CA。
既然是组织内部的信任关系。当然CA和应用证书就该有一样的所在国家、所在省份,以及所属组织。
[3] 关于签发中级证书(二级/三级CA,子CA)
由本节典型演示样例命令生成的证书仅仅能作为应用证书,由于它不具有继续签署下级证书的权限。下图展示了中级证书与应用证书的差别。
图2-1 中级证书与应用证书的差别
由上图能够看出,二者主要是在证书的扩展字段Subject Type的取值有所不同。中级证书该字段取值为"CA",表明此证书依旧能够作为CA。继续签发下级证书;一般应用证书该字段的取值为"End Entity"。表明这已经是证书链的最后一个结点,自然也就不能继续签发下级证书。
查看配置文件 openssl.cnf 中相关条目。能够看到例如以下内容:
[ ca ]
default_ca = CA_default # The default ca section
……………………
[ CA_default ]
……………………
x509_extensions = usr_cert # The extentions to add to the cert
……………………
[ usr_cert ]
# These extensions are added when 'ca' signs a request.
# This goes against PKIX guidelines but some CAs do it and some software
# requires this to avoid interpreting an end user certificate as a CA.
basicConstraints=CA:FALSE
……………………
[ v3_ca ]
……………………
# This is what PKIX recommends but some broken software chokes on critical
# extensions.
#basicConstraints = critical,CA:true
# So we do this instead.
basicConstraints = CA:true
……………………
由此能够看出,为什么默认生成的都是纯应用证书。若要生成中级证书(通常是出于信任关系建立的便利)。则有下面方式:
- 上级CA在签署此证书时,加上 -extensions 选项。且选项參数设为 v3_ca (如步骤简记中所看到的);
- 将 CA_default 条目中 x509_extensions 的值由 usr_cert改为 v3_ca;
- 将 usr_cert 条目中 basicConstraints的值由 CA:FALSE 改为 CA:true;
[4] 关于批处理模式
执行本节典型演示样例命令生成证书时。会遇到相似于下面的提示:
Certificate is to be certified until Mar 27 03:44:08 2015 GMT (365 days)
Sign the certificate? [y/n]:y
1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
也就是说,这个命令是有交互的,你必须在执行过程中手工完毕两次确认输入。
但我们在自己生成证书链的时候,证书请求文件和CA证书都是由我们自己生成的,一般并不须要确认。另外,我们一旦须要用程序自己主动化/批量化处理。也会显得麻烦。
说究竟,一句话,假设你不想有交互。那么能够使用 -batch 选项。本小节典型演示样例中的命令,能够用选项 -batch 改造例如以下:
openssl ca -in app.csr -out app.crt -cert CA.crt -keyfile CA.key -days 1826 -policy policy_anything -batch
三、常见问题及其解决
留待下次补充。
------本文由CSDN-蚍蜉撼青松【主页:http://blog.csdn.net/howeverpf】原创,转载请注明出处!------