第 C-1 章 Linux 加密、签名和 SSL 握手机制

作者: Brinnatt 分类: ARM64 Linux 补充知识 发布时间: 2022-01-21 21:02

C1、基础知识

对称加密:加密解密使用同一密钥,加解密速度快。随着人数增多,密钥数量急增 n(n-1)/2。

非对称加密:使用公私钥配对加解密,速度慢。公钥是从私钥中提取出来的,一般拿对方公钥加密来保证数据安全性,拿自己的私钥加密来证明数据来源的身份。

单向加密:不算是加密,也常称为散列运算,用于生成独一无二的校验码(或称为指纹、特征码)来保证数据的完整性和一致性,如 MD5、SHA。具有雪崩效应,任何一点数据的改变,生成的校验码值变化非常大。

互联网数据安全可靠的条件:

  1. 数据来源可信,即数据发送者身份可信。
  2. 数据具备完整性,即数据未被修改过。
  3. 数据安全性,即数据不会被泄漏,他人截获后无法解密。

C2、互联网数据加密的细节

对数据加密的方法有三种:对称加密、私钥加密和公钥加密。三种方法只靠其中任意一种都有不可容忍的缺点,因此考虑将它们结合使用。

考虑这三种加密算法的特性,公私钥加密速度慢,对称加密快,所以可以首先对数据部分使用对称加密。再进一步考虑,公钥大家都可以获取,若使用自己私钥加密,数据被截获后直接就被破解,因此使用对方的公钥加密,又由于公钥加密速度慢,所以可以使用对方公钥对对称密钥部分进行加密。

数据的收取者解密时,将使用自己的私钥解密第一层,得到对称密钥和加密的数据,再使用对称密钥解密数据,这样就能获得最终数据。

如下图所示分别是加密和解密的全过程:

sym enc

加密的方法很多,但是上述方法是综合考虑互联网安全后较为成熟的一种简单加密方法。使用上述方法加密保证了数据的安全性,但是还未保证数据的完整性、一致性以及数据来源的可靠性。

C3、互联网数据签名的细节

在保证了数据的安全性后,还需要保证数据的完整性、一致性以及数据来源的可靠性。

对于数据的完整性和一致性,使用单向加密算法,通过 hash 函数计算出数据独一无二的校验码,这个校验码称为 "信息摘要(Message Digest)"

对于数据来源可靠性,使用自己的私钥加密即可验证身份,因为获得数据后使用公钥不能解密的就证明数据不是配对私钥加密的。但是私钥加密速度慢,所以只用私钥加密摘要信息,加密后的摘要信息称为 "数字签名(Signature)"

用户获得数字签名后的数据,首先使用数据来源方的公钥解密,这样获得了数据和信息摘要部分,并确认了数据来源的可靠性。由于这时候数据部分是没有被加密的,所以用户也可以使用同种单向加密算法计算出摘要信息,然后对比来源方的摘要信息和自己计算出的摘要信息,如果相等则证明数据完全未被修改过,是完整一致的。

因此只要使用数字签名就能保证数据来源的可靠性、数据的完整性和一致性。

如图所示分别是数字签名和确认数据的全过程:

signature

C4、互联网数据安全传输的细节

要在互联网上安全传输数据,要保证数据来源可靠、数据原始未被修改过、数据丢失不泄密。

如果数据传输双方张三和李四不在意数据丢失的泄露性,那么可以不对数据进行加密,只要数字签名即可。李四可以根据数字签名验证数据的来源及数据的完整性,若发现被修改后大不了不用了。

现在互联网上很多时候下载软件时就提供了签名验证,使用的就是这种机制,不管软件是否被截取,只要安装者能验证即可,如下图:

win2019 signature

如果在意数据泄漏呢?就需要将数字签名和加密结合起来使用。有两种方案:

  1. 先对数据加密,再对加密后的整体进行数字签名;

  2. 先对数据进行数字签名,再对签名后的整体进行加密。

在互联网上基本使用第二种方法,用户最终只对数据部分进行校验而不对加密后的数据进行校验。具体细节如下:首先进行数字签名,再使用对称加密加密签名后的整体,然后使用对方的公钥只加密对称密钥部分。这样即保证了加密速度,还保证了数据的安全性、可靠性和完整性。解密时反向进行即可。如图所示:

enc sig

但是这时还有一个漏洞,问题出在数字签名过程中私钥加密以及后面公钥解密的不安全性。

图中李四在拿公钥 A 解密的时候,这个公钥 A 真的是张三的公钥吗?也许张三传输公钥给李四的过程中被王五截断,王五声称自己是张三,并把自己的公钥给了李四,然后王五用自己的私钥对木马程序进行签名,进行对称加密后再使用李四的公钥加密,最后传输给李四,这样一来李四以为王五就是张三,导致的结果是李四对木马程序完全信任。

如何解决这个漏洞呢?只要保证李四获得的公钥 A 真的是来源于张三即可,如何保证呢?互联网之下,数据传输的两端可能谁都不认识谁,谁也不相信谁,所以最终还是依靠第三方组织——CA。

C5、CA、PKI 及信任 CA

ca sign

CA(Certificate Authority)是数字证书认证中心,常称为证书颁发机构,申请者提交自己的公钥和一些个人信息(如申请者国家,姓名,单位等)给 CA,CA 对申请者的这些信息单向加密生成摘要信息,然后使用自己的私钥加密整个摘要信息,这样就得到了 CA 对申请者的数字签名,在数字签名上再加上 CA 自己的一些信息(如 CA 的机构名称,CA 层次路径等)以及该证书的信息(如证书有效期限),就得到了所谓的数字证书。

如果某用户信任了该 CA,就获取了该 CA 的公钥(实际上信任 CA 的其中一个作用就是获取 CA 公钥),使用该公钥解密数字证书就可以验证申请者的信息以及申请者公钥的可靠性。

这里的关键是 CA 使用自己的私钥给申请者加密,那么如何保证 CA 是可信并且合法的呢?

  • 根 CA 是通过自签署数字证书的方式标榜自己的可信性和合法性,第一级子 CA 由根 CA 颁发合法数字证书,第二级直至所有的子 CA 都由上一级子 CA 颁发数字证书。
  • 对于多级子 CA 只需要信任根 CA 即可,因为获取了根 CA 的公钥,可以解密第一级子 CA 的证书并获取验证第一级子 CA 的公钥,层层递进,最终获取到为申请者颁发数字证书的机构并获取它的公钥。

另一种情况,虽然信任了根 CA,但如果根 CA 授权的某个二级或者某个二级授权的三级 CA 不在信任列表中,就需要将这个中间的 CA 补齐,否则中间出现断层,无法成功解密该中间 CA 颁发的证书。

  • 通常这种中间 CA 的证书称为 chain 证书,例如 "xxx.com.chain.crt"。
  • 如果购买的证书发给你的文件中包含了 chain.crt 文件,则说明他是中间 CA,且有些浏览器或操作系统中没有内置它的 CA,这时应该将 chain 证书也配置到 web server 上。

正是这些根 CA 和子 CA 组成了 PKI。

信任 CA 后,每次接收到需要解密的数字证书时,还要去该颁发机构指定网站的证书吊销列表(CRL)中查询该证书是否被吊销,对于吊销后的证书应该不予以信任,这是信任 CA 的第二个作用。导致证书被吊销的可能性不少,例如申请者的私钥被黑客获取,申请者申请吊销等。

也有公司使用自签的证书,例如某些银行、12306 有时候就要求下载证书并安装。使用自签证书的好处当然是省钱、方便啦。

C6、数字证书类型和内容

PKI 的两种实现方式 TLS 和 SSL 使用的证书格式都是 x509,TLSv1 和 SSLv3 基本等价,只不过 SSL 实现在 OSI 4 层模型中的应用层和传输层的中间,TLS 实现在传输层。

还有 PKI 的另一种实现方式 GPG,它的证书使用的不是 x509 格式。

数字证书中包含的信息有:申请者的公钥,证书有效期,证书合法拥有人,证书如何被使用,CA 的信息,CA 对申请者信息的数字签名。

win_certs1

C7、SSL/TLS 应用

SSL/TLS 协议是 HTTPS 中特别重要的一部分,HTTPS = HTTP + SSL/TLS,如今 SSL 已废弃,这里我们只讨论 HTTP + TLS。

  • HTTP 是明文传输协议,通信过程和数据传输都没有进行加密,也没有验证通信双方的身份。因此通信过程很容易遭到劫持、窃听、篡改等。
  • 为了解决 HTTP 协议的问题,HTTPS 引入了数据加密身份验证机制。在开始传输数据之前,通过安全可靠的 TLS 协议进行加密,从而保证后续加密传输数据的安全性。

C7.1、TLS 协议

传输层安全性协议(Transport Layer Security,TLS)及其前身安全套接层(Secure Sockets Layer,SSL)是一种安全协议,目的是为了保证网络通信安全数据完整性

受 TLS 协议保护的通信过程,具有以下一种或几种属性:

  • 连接是安全的:因为传输的数据进行了加密(使用对称加密算法)。并且对称加密的密钥是为每一个连接唯一生成的(基于 TLS 握手阶段协商的加密算法共享密钥)。
    • 其中,共享密钥的协商是安全可靠的。如果有攻击者修改了通信,那么该修改一定会被检测出来并被阻止。并且即使攻击者处于整个连接的中间(窃听 TLS 握手),也无法利用窃听到的密钥。
  • 连接是可靠的:发送的每条消息都会通过消息验证码(Message authentication code, MAC),来进行消息完整性检查。
  • 可以使用公钥对通信双方进行身份验证:该项一般只需要验证一方的身份(通常是服务端)。对于一些非常保密的应用,还是需要验证双方的身份。例如,金融机构往往只允许认证后的用户连入自己的网络。

TLS 协议包括两层:TLS 记录TLS 握手协议。本文主要讲述 TLS 握手协议。

由于诸多原因(主要是安全方面),SSL 协议的所有版本(SSL 1.0、SSL 2.0、SSL 3.0)都已弃用。并且 TLS 1.0、TLS 1.1 也在 2020 年弃用,因此目前主流的通信加密协议版本是 TLS 1.2 和 TLS 1.3。

C7.2、TLS 握手

带证书的双向身份验证的 TLS 握手如下图:

ssl handshake

  1. 第一次握手
    • 客户端发送 ClientHello 消息,其中包含支持的最高 TLS 协议版本随机数(稍后用于生成“会话密钥”)、加密算法列表(如 RSA 公钥加密)和压缩算法列表
      • 如果客户端正在尝试恢复握手,则它可以发送会话 ID。
      • 如果客户端可以使用应用协议协商,则它可能包括受支持的应用程序协议列表,例如 HTTP 2.0
    • 服务端回应 ServerHello 消息,其中包含要使用的 TLS 协议版本随机数(稍后用于生成“会话密钥”)、要使用的加密算法要使用的压缩算法
      • 为了确认恢复握手,则服务端可以发送会话 ID。
      • 要使用的协议版本应该是客户端和服务端都支持的最高版本。例如,客户端支持 TLS 1.1,服务端支持 TLS 1.2,则应该选择 TLS 1.1 版本。
  2. 第二次握手
    • 服务端发送其证书(可选,取决于使用的加密算法)
      • 目前主流的 RSA 算法就是基于证书的。使用证书也是更推荐的做法,因为相比于无证书的机制,使用证书更安全。
    • 服务端发送 ServerKeyExchange 消息(可选,取决于使用的加密算法。DHE 和 DH_anon 算法会发送该消息)。
    • 服务端发送 CertificateRequest 消息,请求获取客户端证书,以便进行相互认证(可选,如果是单向身份认证,通常是服务端认证,则不需要这一步)。
    • 服务端发送 ServerHelloDone 消息,表示服务端握手协商完成(注意,是协商完成,而不是整个 TLS 握手完成)。
    • 客户端校验服务端证书(如果证书不合法,客户端会向用户发出警告信息断开 TLS 握手)。
  3. 第三次握手
    • 客户端发送其证书,供服务端使用和校验(可选,如果是单向身份认证,通常是服务端认证,则不需要这一步)。
    • 客户端发送 ClientKeyExchange 消息(可选,同样取决于使用的加密算法。DHE 和 DH_anon 算法会用到),其中可能包含 Pre-Master-Secret、公钥。
      • Pre-Master-Secret (PMS,预主密钥) 是一个随机数,在发送之前,会使用服务端证书中的公钥对其进行加密。
    • 客户端发送一个 CertificateVerify 消息(可选,如果是单向身份认证,通常是服务端认证,则不需要这一步),其中包含使用客户端私钥对之前握手信息的签名。服务端可以使用客户端公钥来验证此签名,以确定客户端是否拥有此证书。
    • 到此为止,客户端和服务端都具有了三个随机数(两个随机数 + PMS),然后它们分别使用之前协商的对称加密算法三个随机数来生成 Master-Secret,用于加密之后传输的数据。
      • Master-Secret(MS,主密钥,也称为“会话密钥”)。
  4. 第四次挥手
    • 客户端发送 ChangeCipherSpec 记录,用于告诉服务端“之后的所有数据都将进行身份验证(如果服务端证书中存在加密参数,则会进行加密)”。具体如下:
      • 客户端发送经过身份验证和加密的 Finished 消息,其包含之前所有握手信息的 Hash 和 MAC
      • 服务端尝试解密 Finished 消息,获取并验证 Hash 和 MAC。如果解密或验证失败,则认为握手失败,断开 TLS 链接。
    • 服务端回应 ChangeCipherSpec 记录,同样用于告诉客户端“之后的所有数据都将进行身份验证(如果服务端证书中存在加密参数,则会进行加密)”。具体如下:
      • 服务端发送经过身份验证和加密的 Finished 消息,其包含之前所有握手信息的 Hash 和 MAC
      • 客户端执行与服务端上一步相同的解密和验证过程。

C7.2.1、TLS 证书校验

TLS 协议中重要的一环是如何校验证书的真实性。虽然有些 TLS 握手不需要证书(例如,使用 Diffie-Hellman(DH) 算法的 TLS 握手),但是这些情况都被证实不安全,而且很少使用。

要证明证书的真实性,通常依赖于一组受信任的第三方证书颁发机构(Certificate authorities, CA)。验证 TLS 证书有效性的方法如下:

  1. 检查证书是否是浏览器中受信任的根证书机构颁发。
    • 证书都是上级 CA 签发的,上级的 CA 可能还有上级,直到找到根证书。
  2. 检查证书中的证书吊销列表(CRL),看证书是否已经被吊销。
    • 证书被吊销后,会被记录在证书吊销列表中,CA 会定期发布 CRL。应用程序可以根据 CRL 来检查证书是否被吊销。
  3. 通过在线证书状态协议(OCSP)检查证书是否有效。
    • CA 会提供实时的查询接口,用来查询证书的有效性。在线实时查询会使得 TLS 握手时间延长,因为浏览器需要等待查询结束才能继续 TLS 握手。至于使用在线查询还是证书中的吊销列表,由浏览器决定。
  4. 检查证书是否过期。
  5. 检查域名和证书中的域名是否一致。
  6. 查询网站是否被列入了欺诈网站黑名单。
    • 这一步 IE7 会进行,IE7 会到欺诈网站数据库,查询网站是否被列入了欺诈黑名单。

经过了以上步骤,浏览器中才会显示安全锁的标志。任意一个步骤出问题,浏览器都无法建立安全链接,并最终提示“您的链接不是私密链接”。

C7.2.2、握手恢复

TLS 握手阶段使用了非对称加密(例如 RSA 算法),其计算消耗非常大,因此 TLS 握手机制中提供了会话恢复的功能,从而提高了握手中断后再次握手的性能。

有两种方法可以恢复会话:一种是 Session ID,另一种是 Session tickets。

  • Session ID 的思想很简单:每次会话都有一个 Session ID。如果 TLS 握手中断,下次重连的时候,只要客户端给出 Session ID,并且服务端有对应的记录,那么双方就可以使用之前的“会话密钥”,而不必重新计算生成。
    • 具体过程如下:在一次会话中,服务器发送 Session ID 作为 ServerHello 消息的一部分。客户端将此 Session ID 与服务端的 IP、TCP 端口相关联,以便下次重连时简化握手。服务端则会将此 Session ID 与之前协商的密钥相关联,特别是“会话密钥(Master-Secret)”。
    • Session ID 机制有一些弊端,例如:1、只能保留在一台服务器上。负载匀衡中,多台服务器之间往往没有同步 Session 信息,如果客户端的两次请求没有被同一台服务器处理,就无法通过 Session ID 恢复握手。2、服务端不好控制 Session ID 对应信息的失效时间。时间太短起不到作用,太长又占用服务器大量资源。
  • Session tickets 的出现就是为了 Session ID 机制的一些弊端。使用 Session tickets 时,服务器将会话状态存储在其中,然后将 Session tickets 加密后存储到客户端。客户端在恢复会话时,将 Session tickets 发送给服务端,服务器验证通过后,就可以使用其中的会话状态来恢复 TLS 握手。

C8、Openssl 命令

openssl 命令的格式是 "openssl command command-options args",command 部分有很多种命令,这些命令需要依赖于 openssl 命令才能执行,所以称为伪命令(pseudo-command),每个伪命令都有各自的功能,大部分 command 都可以直接 man command 查看命令的用法和功能。

C8.1、openssl 总指挥

[root@arm64v8 ~]# openssl help
# 支持的标准命令,即伪命令
Standard commands
asn1parse         ca                ciphers           cms               
crl               crl2pkcs7         dgst              dhparam           
dsa               dsaparam          ec                ecparam           
enc               engine            errstr            gendsa            
genpkey           genrsa            help              list              
nseq              ocsp              passwd            pkcs12            
pkcs7             pkcs8             pkey              pkeyparam         
pkeyutl           prime             rand              rehash            
req               rsa               rsautl            s_client          
s_server          s_time            sess_id           smime             
speed             spkac             srp               storeutl          
ts                verify            version           x509              

# 指定"dgst"命令时即单向加密支持的算法,实际上支持更多的算法,具体见dgst命令
Message Digest commands (see the `dgst' command for more details)
blake2b512        blake2s256        gost              md2               
md4               md5               rmd160            sha1              
sha224            sha256            sha3-224          sha3-256          
sha3-384          sha3-512          sha384            sha512            
sha512-224        sha512-256        shake128          shake256          
sm3               

# 指定对称加密"enc"时支持的对称加密算法
Cipher commands (see the `enc' command for more details)
aes-128-cbc       aes-128-ecb       aes-192-cbc       aes-192-ecb       
aes-256-cbc       aes-256-ecb       aria-128-cbc      aria-128-cfb      
aria-128-cfb1     aria-128-cfb8     aria-128-ctr      aria-128-ecb      
aria-128-ofb      aria-192-cbc      aria-192-cfb      aria-192-cfb1     
aria-192-cfb8     aria-192-ctr      aria-192-ecb      aria-192-ofb      
aria-256-cbc      aria-256-cfb      aria-256-cfb1     aria-256-cfb8     
aria-256-ctr      aria-256-ecb      aria-256-ofb      base64            
bf                bf-cbc            bf-cfb            bf-ecb            
bf-ofb            camellia-128-cbc  camellia-128-ecb  camellia-192-cbc  
camellia-192-ecb  camellia-256-cbc  camellia-256-ecb  cast              
cast-cbc          cast5-cbc         cast5-cfb         cast5-ecb         
cast5-ofb         des               des-cbc           des-cfb           
des-ecb           des-ede           des-ede-cbc       des-ede-cfb       
des-ede-ofb       des-ede3          des-ede3-cbc      des-ede3-cfb      
des-ede3-ofb      des-ofb           des3              desx              
idea              idea-cbc          idea-cfb          idea-ecb          
idea-ofb          rc2               rc2-40-cbc        rc2-64-cbc        
rc2-cbc           rc2-cfb           rc2-ecb           rc2-ofb           
rc4               rc4-40            rc5               rc5-cbc           
rc5-cfb           rc5-ecb           rc5-ofb           seed              
seed-cbc          seed-cfb          seed-ecb          seed-ofb          
sm4-cbc           sm4-cfb           sm4-ctr           sm4-ecb           
sm4-ofb           zlib              

[root@arm64v8 ~]#

以下是各伪命令的选项 "-passin" 和 "-passout" 可能使用到的密码传递格式,"-passin" 指的是传递解密时的密码,"-passout" 指的是传递加密输出文件时的密码。如果不给定密码格式,将提示从终端输入。

格式一:pass:password   :password表示传递的明文密码

格式二:env:var         :从环境变量var获取密码值

格式三:file:filename   :filename文件中的第一行为要传递的密码。
                        若filename同时传递给"-passin"和"-passout"选项,则filename的第一行为"-passin"的值,第二行为"-passout"的值

格式四:stdin           :从标准输入中获取要传递的密码

例如,要加密某个密钥文件,使得每次使用该密钥文件都需要输入密码,则使用 "-passout" 指定加密密码,当使用被加密的密钥文件时需要解密,使用 "-passin" 传递解密密码。

C8.2、openssl genrsa 命令

genrsa 用于生成 RSA 私钥,不会生成公钥,因为公钥从私钥提取,如果需要查看公钥或生成公钥,可以使用 openssl rsa 命令。

openssl genrsa [-out filename] [-passout arg] [-des] [-des3] [-idea] [numbits]

选项说明:

-out filename       :将生成的私钥保存至filename文件,若未指定输出文件,则为标准输出。

-numbits            :指定要生成的私钥的长度,默认为1024。该项必须为命令行的最后一项参数。

-des|-des3|-idea    :指定加密私钥文件用的算法,这样每次使用私钥文件都将输入密码,太麻烦所以很少使用。

-passout args       :加密私钥文件时,传递密码的格式,如果要加密私钥文件时单未指定该项,则提示输入密码。传递密码的args的格式见openssl密码格式。
  1. 生成 512 位的 rsa 私钥,输出到屏幕。

    [root@arm64v8 ~]# openssl genrsa 512
    Generating RSA private key, 512 bit long modulus (2 primes)
    .........+++++++++++++++++++++++++++
    .+++++++++++++++++++++++++++
    e is 65537 (0x010001)
    -----BEGIN RSA PRIVATE KEY-----
    MIIBPAIBAAJBAKmsQCqb2Hv0iJOC1sVUQ9cVHNliDMUSJwCjhCcc3VDRizcIUQFY
    Rb0CPWdcHZpUb045vYkN+UU8Y3d+v93nSM8CAwEAAQJBAIVM7pyLE+lOlH5PrKwb
    J7EyxReEEMRDHqFB1fFkm/uBXQNttrRzndoaRUzeFZW1xvE2hUAh1zgMt+uKk/Bj
    UwECIQDcRf+trjJZrbUywuI/4lIbQ2F+4nl92YJybWOb8fzBHQIhAMUxQkNfqoZS
    zPcJfawjgfJ56aJ0vrAdbVUnr+f2x1nbAiEA0w+PaY/cVumHEdiCicwF+HGb3cSL
    vPbJc3M1WpuIIFECIQCOyfyRjNSOL6b7u4OlApE2Y9EqMh9ip+xjnTljXu87wQIg
    PuXEyUOlRmyjhHQv8XemTn7hPC6ZlA21gnhquJyjGKw=
    -----END RSA PRIVATE KEY-----
    [root@arm64v8 ~]#
  2. 生成 512 位的 rsa 私钥,输出到指定的文件 genrsa.txt。

    [root@arm64v8 ~]# openssl genrsa -out genrsa.txt 512
    Generating RSA private key, 512 bit long modulus (2 primes)
    ..+++++++++++++++++++++++++++
    ...........+++++++++++++++++++++++++++
    e is 65537 (0x010001)
    
    [root@arm64v8 ~]# cat genrsa.txt 
    -----BEGIN RSA PRIVATE KEY-----
    MIIBOgIBAAJBAJ3Bb69wMzlfvm5MN94E90pmYbhbMEpndE00mPA8a7DyI3+ZIgBq
    GDnccn94v+T30g0n2h0WYRSLF9gXjXfOpzMCAwEAAQJAEEgiqsy9vLIxCVk8euGw
    VDF07H4c4dEDo+RF1KWnx79MhwncMZ6hpm85vezNhx9ntC6NQCwQQMScGdhRqFM7
    oQIhAMmUJ0Vp78wsrNMibfUUlzfr7asJL0ZuzVUlX0jjSVJHAiEAyFiBoqAPSszP
    8AK3szMzFAOe9InJHOMFfIMEIgn3LbUCICjFDThN19E8y+ucEA88jeUik5w/LE+b
    g24QM/hi9+ZrAiEAq24ATzWCoFCsxQSuR6pR1JhclYapDgy8DxTUnoPEe9kCIGCv
    Yksk/c/Z1EpCOJqM2r070B8kp6fbnbVBg8kxsWeR
    -----END RSA PRIVATE KEY-----
    [root@arm64v8 ~]#
  3. 加密私钥文件,加密的密码为 123456。

    [root@arm64v8 ~]# openssl genrsa -out genrsa.txt -des3 -passout pass:123456 512
    Generating RSA private key, 512 bit long modulus (2 primes)
    .+++++++++++++++++++++++++++
    .......+++++++++++++++++++++++++++
    e is 65537 (0x010001)
    [root@arm64v8 ~]# cat genrsa.txt 
    -----BEGIN RSA PRIVATE KEY-----
    Proc-Type: 4,ENCRYPTED
    DEK-Info: DES-EDE3-CBC,675B1CF877184FA9
    
    4F7K/9FTRrP+QGPUgQfUV165jZCHUN8c/Ml6qpcpL+yr+a0BSi3uzAmHSettJ1zv
    9b7vaFGfyIX3DfXzRpQFouZGhSQ7J0kKVeVOFJcxt4z956vh8zitbcie7I2uOdov
    WCy9ZAXlQWc4xN0knry0n66ShvItQRml+0l7I37feFKNqMPUMLUMAqmXg9wwpYdP
    prXt8kxzhGQ5AjbyH7JLR5wZTQfy5z3grWCAWOoqpVwu1zgWhzXkK3RKC8U7p4mr
    clo0glE1IZ9FKNCo6F3jQs5pktYy+Pmqlx8W4coAITiD/twrCk9GAx8toZq9qtxz
    H5iJRcdk8/BAuDRA3GCF6GUXT3j6GsCOrmNzLGOHzsqZ8Uc/wfqg199y7NVlvpnT
    CEDTW1MtQLwLKvQeHM+Z58sitp38CVc3l2YpkwtlGqM=
    -----END RSA PRIVATE KEY-----
    [root@arm64v8 ~]#
    • 一般情况下能用到的选项也就 "-out" 和 "numbits"。

C8.3、openssl rsa/pkey

openssl rsa 和 openssl pkey 分别是 RSA 密钥的处理工具和通用非对称密钥处理工具,它们用法基本一致,所以只举例说明 openssl rsa。

它们的用法很简单,基本上就是输入和输出私钥或公钥的作用。

openssl rsa     [-in filename] [-passin arg] [-passout arg] [-out filename]
                [-des|-des3|-idea] [-text] [-noout] [-pubin] [-pubout] [-check]

openssl pkey    [-passin arg] [-passout arg] [-in filename] [-out filename] [-cipher]
                [-text] [-noout] [-pubin] [-pubout]

[openssl rsa选项说明:]
-in filename        :指定密钥输入文件。默认读取的是私钥,若指定"-pubin"选项将表示读取公钥。将从该文件读取密钥,不指定时将从stdin读取。
-out filename       :指定密钥输出文件。默认输出私钥,若指定"-pubin"或"-pubout"选项都将输出公钥。不指定将输出到stdout。
-pubin              :指定该选项时,将显式表明从"-in filename"的filename中读取公钥,所以filename必须为公钥文件。
                    :不指定该选项时,默认是从filename中读取私钥。公钥文件可以通过文件中的公钥标识符
                    :"-----BEGIN PUBLIC KEY-----"和"-----END PUBLIC KEY-----"来辨别。

-pubout             :指定该选项时,将显示表明从"-in filename"的filename中提取公钥并输出,所以filename文件必须是私钥文件。
                    :不指定该选项时,默认输出私钥。当设置了"-pubin"时,默认也设置了"-pubout"。
                    :私钥文件可以通过文件中的私钥标识符"-----BEGIN PRIVATE KEY-----"和"-----END PRIVATE KEY-----"来辨别。

-noout              :控制不输出任何密钥信息。
-text               :转换输入和输出的密钥文件格式为纯文本格式。
-check              :检查RSA密钥是否完整未被修改过,只能检测私钥,因为公钥来源于私钥。因此选项-"in filename"的filename文件只能是私钥文件。
-des|-des3|-idea    :加密输出文件,使得每次读取输出文件时都需要提供密码。
-passin arg         :传递解密密钥文件的密码。密码格式见openssl密码格式。
-passout arg        :指定加密输出文件的密码。

[openssl pkey选项说明:]
-cipher:等价于openssl rsa的"-des|-des3|-idea",例如"-cipher des3"。
  1. 创建一个 rsa 私钥文件 genrsa.pri,然后从中提取 rsa 公钥到 rsa.pub 文件中。

    [root@arm64v8 ~]# openssl genrsa -out genrsa.pri
    Generating RSA private key, 2048 bit long modulus (2 primes)
    .................................................+++++
    .......................................................................+++++
    e is 65537 (0x010001)
    [root@arm64v8 ~]# 
    [root@arm64v8 ~]# openssl rsa -in genrsa.pri -pubout -out rsa.pub
    writing RSA key
    [root@arm64v8 ~]# cat genrsa.pri 
    -----BEGIN RSA PRIVATE KEY-----
    MIIEowIBAAKCAQEAwrel7mAXTCAbkTUmVRoqucE8neG3/nD9jk7GWZBS7djCyExi
    dwNnIMnyHQV9KghRNPkIwLH4mKJ8GCFBM/3RzTO+wNvIyWFGhu6Vo8qS3pSuqYF8
    9DIld8UCyP4NWtb1EwY2BRXqi9Kh8H9Mo1nf8ynL1Lj0QMUrTWGnX1kvEgSDI2/z
    Vg09O2BvEZZeGa0pATVRiUFPvbvmEe7XNj7XYkrQRDulpYTXbZAdzbF/XL6EOWOp
    o9pss5kWZaeYbLc1b6QCclxBWyhv8TEPNhmHRbu+y3gBOPIStgvDzSPZRgsY6AdD
    jw37pMCe4c6Xz0ZzI88N20RrAcEm+73iqc9zJQIDAQABAoIBACG7IKKHwOFuGnhw
    JaDOdKJTKEYNaQtJ1ZLGcLPpPYR4bV23ZcNKMp5KfYergMA8Sp0LmwmOiwsd8rNX
    Z20zRhnvIddU+5ZvJIGRaRjDqeenCA7TIKtI2JbD6TSaVgPrgu71v3voDQaFyYnY
    85TEp/f+wJGsLJvfzB2OkikBURckpZxMHJqR7TYFq23JR6q0LV9U8Ik12AWxX1BX
    0nHqZVEtmLz+Eb7MsdVNxhJFJiL2+Gz4Mad9HmFH4/o28yvdwLcCID8x5EwW9n5/
    cR5+5lO5QiZUMxXa2OccABAVBSAF8X987hLErQRJjmgoEtRGeKG3ZjsRb4nEjKUc
    CdqtbmECgYEA3/t9fKMXqutloSOXaf3S65HCfVO2M5FjNU0i+CRcX+WTCaFHMPZX
    H84U0PihkFXvsIrmcJWO6uBs00Kx5YV+qtV9i3LaJhyCBAjKX6hAqE48i/5VmQa2
    r0ZI5TGzPCvlmdte06dt53NZrtzlRESrPiPQGOjaOOgjVP1jXRpNcmkCgYEA3o04
    rw5zmnnyP4WT242dwvWtJNdkbt8KCgCA2vMEvHOzPtUhiZFWEN9Tt83i+/HVt9W1
    63i1lMHTl+Vyi2a83ne4quBXnOFEs/ym0vUk6RmOLIT4Kcdw4V/SOLvuaRSTRrCD
    PbHZ8dn9JOF52Ag4d3KuEwoZUikJwOi2rkSja10CgYBTUL8674fMQkfJiu21tX8R
    tWR9LfhmcjxPBWRunUfnPARX3rAWnGuIHyZLHVEr2WuRZfmWA2voHpccdoCp+eBG
    N6e9iXlwF8adLY/pyTJT6NZI1NCOXZry09gluTkMtt9vPdSmMm+FWrkPfIejv09b
    jALKYUNbS65o3OBrL2+DkQKBgC0RvGD3NEIcYAqtKnxT+Zb52c6UMCqj0Iyl/XJZ
    tKPVan9W+iu52wwfrfyTHVyYZQeNqAG/uEYf2pHwTXodnDIRXLx+IkAK/rbUe5RN
    QORT4I7zfq43TYzWsuP6axWsrQaryGg+FDz+QF2vq9UsFQNbnhUM/oO8+9StTBGO
    pOmhAoGBALQhQEVqq9lmKbJw/jq6IifnMmfE5J/6uWu9x9Ieu5gyuGtk/M2Skytw
    Dig9qgkz+uHJXPycy/PPetKdYskFBJdup4+UiEza/yPjLCNTKiwkJFBQjD1ZDmkE
    lPliqIxtrO9F0o6eszrAfG5f83xbjJiupkGx4JT1ejlkhp/LFAML
    -----END RSA PRIVATE KEY-----
    [root@arm64v8 ~]# cat rsa.pub 
    -----BEGIN PUBLIC KEY-----
    MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwrel7mAXTCAbkTUmVRoq
    ucE8neG3/nD9jk7GWZBS7djCyExidwNnIMnyHQV9KghRNPkIwLH4mKJ8GCFBM/3R
    zTO+wNvIyWFGhu6Vo8qS3pSuqYF89DIld8UCyP4NWtb1EwY2BRXqi9Kh8H9Mo1nf
    8ynL1Lj0QMUrTWGnX1kvEgSDI2/zVg09O2BvEZZeGa0pATVRiUFPvbvmEe7XNj7X
    YkrQRDulpYTXbZAdzbF/XL6EOWOpo9pss5kWZaeYbLc1b6QCclxBWyhv8TEPNhmH
    Rbu+y3gBOPIStgvDzSPZRgsY6AdDjw37pMCe4c6Xz0ZzI88N20RrAcEm+73iqc9z
    JQIDAQAB
    -----END PUBLIC KEY-----
    [root@arm64v8 ~]#
  2. 创建一个加密的 rsa 私钥文件 genrsaK.pri,然后从此文件输出公钥至文件 rsaK.pub。

    [root@arm64v8 ~]# openssl genrsa -out genrsaK.pri -des3 -passout pass:123456
    Generating RSA private key, 2048 bit long modulus (2 primes)
    .................+++++
    .......+++++
    e is 65537 (0x010001)
    [root@arm64v8 ~]#

    此时将提示输入密码才能读取该私钥文件:

    [root@arm64v8 ~]# openssl rsa -in genrsaK.pri -pubout -out rsaK.pub
    Enter pass phrase for genrsaK.pri:
    writing RSA key
    [root@arm64v8 ~]#

    可以使用 "-passin" 传递解密的密码:

    [root@arm64v8 ~]# cat rsaK.pub 
    -----BEGIN PUBLIC KEY-----
    MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuJgNmrIHgv4drnQBgXSZ
    UiGocHD1ZXjt8j7eObNUXIjAeHQvgJhnGoFzpRPgzfs1PfieRMSDMofQVTfPk5D0
    vdNzoCOtjnbwjD+52ub87cmKt40gU8XQ0TQomS3b70pYoCcoDrOTx3xbaJ9kHo6h
    gHN4l3ERfjR4SatU3PON3q0CeIoqYvt92rvA9ytByMhdwiq2Xye8GLvcuAMJfEKA
    VL4i68USZZj0yKaHAopAyWhOkecA+FMsTHOkSEhF/Qoehxt2RXmEE/heX0qJJ83l
    GdFi3OijMu0RaHFElRd8TOFgZ7Q6RnCbaEqKoRxVmaobNkDI+lM4dj6I53/pAvMq
    IQIDAQAB
    -----END PUBLIC KEY-----
    [root@arm64v8 ~]# openssl rsa -in genrsaK.pri -pubout -out rsaK1.pub -passin pass:123456
    writing RSA key
    [root@arm64v8 ~]# cat rsaK1.pub 
    -----BEGIN PUBLIC KEY-----
    MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuJgNmrIHgv4drnQBgXSZ
    UiGocHD1ZXjt8j7eObNUXIjAeHQvgJhnGoFzpRPgzfs1PfieRMSDMofQVTfPk5D0
    vdNzoCOtjnbwjD+52ub87cmKt40gU8XQ0TQomS3b70pYoCcoDrOTx3xbaJ9kHo6h
    gHN4l3ERfjR4SatU3PON3q0CeIoqYvt92rvA9ytByMhdwiq2Xye8GLvcuAMJfEKA
    VL4i68USZZj0yKaHAopAyWhOkecA+FMsTHOkSEhF/Qoehxt2RXmEE/heX0qJJ83l
    GdFi3OijMu0RaHFElRd8TOFgZ7Q6RnCbaEqKoRxVmaobNkDI+lM4dj6I53/pAvMq
    IQIDAQAB
    -----END PUBLIC KEY-----
    [root@arm64v8 ~]#
  3. 移除私钥文件或公钥文件的密码。只需直接输出到新文件即可。以已加密的私钥文件 genrsaK.pri 为例。

    # 将 genrsaK.pri 转成 genrsaNK.pri
    [root@arm64v8 ~]# openssl rsa -in genrsaK.pri -out genrsaNK.pri 
    Enter pass phrase for genrsaK.pri:
    writing RSA key
    
    # 原始 genrsaK.pri 需要密码
    [root@arm64v8 ~]# openssl rsa -in genrsaK.pri -pubout -out rsaK2.pub
    Enter pass phrase for genrsaK.pri:
    writing RSA key
    
    # 新 genrsaNK.pri 不需要密码
    [root@arm64v8 ~]# openssl rsa -in genrsaNK.pri -pubout -out rsaK3.pub
    writing RSA key
    [root@arm64v8 ~]#
  4. check 检测私钥文件的一致性,查看私钥文件被修改过。

    [root@arm64v8 ~]# openssl rsa -in genrsaK.pri -check
    Enter pass phrase for genrsaK.pri:
    RSA key ok
    writing RSA key
    -----BEGIN RSA PRIVATE KEY-----
    MIIEowIBAAKCAQEAuJgNmrIHgv4drnQBgXSZUiGocHD1ZXjt8j7eObNUXIjAeHQv
    gJhnGoFzpRPgzfs1PfieRMSDMofQVTfPk5D0vdNzoCOtjnbwjD+52ub87cmKt40g
    U8XQ0TQomS3b70pYoCcoDrOTx3xbaJ9kHo6hgHN4l3ERfjR4SatU3PON3q0CeIoq
    Yvt92rvA9ytByMhdwiq2Xye8GLvcuAMJfEKAVL4i68USZZj0yKaHAopAyWhOkecA
    +FMsTHOkSEhF/Qoehxt2RXmEE/heX0qJJ83lGdFi3OijMu0RaHFElRd8TOFgZ7Q6
    RnCbaEqKoRxVmaobNkDI+lM4dj6I53/pAvMqIQIDAQABAoIBADreItiGleasa4LK
    8//40zxiB3l0TI4Dtr5eVjhIfErWQasoQk3cTGUji2HFqReHWT9eHfsIQF7I+SN0
    HPqOa75txJ35QswAGk5ftEGfEGI0t8w5cWnF2AYfgCL5gP4a05CfbCLkGeiwO+Zt
    jlxAWDjCml6RbGa3DPVRckrUURYFw+yRKLgP/aGv9mo9WU5tBItdbg7w8BIIINyl
    93LilDSh+vUF6UsVHlv6093uS54JS+QBEaUVgo/d5AVoJp+Y87w8mP/lEcPw2/Pj
    cU39L7mTrt/m9Gr2/tzQZAe83n24Ap87w00Ge4sjaKhs0Wesw+uDOI60HL2W+Jsn
    mjCQ0MECgYEA3OYq6f5c1WbHZpEkEJ1J7iSkMkAElPo7P2Rm9C4vwK1ioEXZCvck
    3izPBQBHYGirMp1aYXJaZW5ypZ7EmZsxHynCjWhYG2YZjrLHC6oWnP57St854eZ3
    3aatcrw/l45kdMqvqGfx+YxqdyuX8K9g1Aib2rQdBeqgKeGOEWcMaI0CgYEA1e0M
    iCf0ehU6K4g6yiK+iMtP0evmjs4+7O8vEVNwGH3hd+Gi8uPqGaIMt/F6d5Kz398H
    VgEO4MTQlsB9shGZQ05y3KhvcB00TyZ4Woo6a73PytQcvtNMwjzAhtVznzy3zvXd
    r4Bm6V8+ipGGO81aPD+76J3CCV5ZwECv+edRNOUCgYAuY7vRZhSS0EHB3Wsofg+f
    jlxZHS6ZJq+4kVo5n1Vx7jePFvwMnHhGnDxhfXx/15tURs1LN5uaP4aeF2iMJZY8
    SCXOUoJmRpvJZuv8HB0hnSPBRn2+XgsAJle4h6YHKuUXzdTz1dhwIrfdDO+coQgB
    n0kzta1+p5Y5FWAjcXOepQKBgHnvKsR02bG4ZbaoaLIMicPY9v81Ue41+sH8NzzN
    7UfYgGpfbwy5AhdoOY2jE2YSdXp2Wm0YH03YgPhccYjM5SnrDiddzl7+FnHDALjC
    rzf4MfdvXY8bS1YvYKG6CrRJ3I8Xrys4qe/9PN2owvVVQEi1HzsgqJfEcq3VcTil
    M7FNAoGBAL0ULTYlRW5HGmYcABuoaCFizKTF4rUIVwxWQOB7D/nvCC1JptMCEXJM
    q0/r8pgNKWgYj1jBZEHaBFf7c6Ue/9pGq1ubhX62xyHvL653BP/BkRd43BR4E39m
    LB1rAQ1oj0eLL84BnAfolfWeRTqtlYpYZK2rY7fyYDFtyqR6Ftma
    -----END RSA PRIVATE KEY-----
    [root@arm64v8 ~]#

    现在随便修改下私钥文件,再检测。

    [root@arm64v8 ~]# openssl rsa -in genrsaK.pri -check
    unable to load Private Key
    [root@arm64v8 ~]#

一般来说,openssl rsa 的常用选项就只有 "-in filename"、"-out filename"、"-pubout"。

C8.4、openssl speed/rand

openssl speed

测试加密算法的性能,支持的算法有:

[root@arm64v8 ~]# openssl speed 
bf-cbc    des-cbc   dsa2048   idea      md5       rc2-cbc   rmd160    rsa2048   sha1      
blowfish  des-ede3  dsa512    idea-cbc  mdc2      rc4       rsa       rsa4096   
des       dsa1024   hmac      md2       rc2       rc5-cbc   rsa1024   rsa512

测试速度几秒钟一个指标,速度比较慢。如果不指定参数将测试所有支持的算法,所以会花很久时间,当前是 arm64v8 CPU 64 核,测完所有的算法花了十来分钟。

测试 dsa512、rsa512 和 rsa2048 加密速度如何。

[root@arm64v8 ~]# openssl speed dsa512 rsa512 rsa2048 
Doing 512 bits private rsa's for 10s: 90555 512 bits private RSA's in 9.99s
Doing 512 bits public rsa's for 10s: 1055092 512 bits public RSA's in 9.99s
Doing 2048 bits private rsa's for 10s: 2483 2048 bits private RSA's in 9.99s
Doing 2048 bits public rsa's for 10s: 92387 2048 bits public RSA's in 9.99s
Doing 512 bits sign dsa's for 10s: 47062 512 bits DSA signs in 9.96s
Doing 512 bits verify dsa's for 10s: 70780 512 bits DSA verify in 10.00s
OpenSSL 1.1.1d  10 Sep 2019
built on: Wed Apr  1 13:09:38 2020 UTC
options:bn(64,64) md2(char) rc4(char) des(int) aes(partial) idea(int) blowfish(ptr) 
compiler: gcc -fPIC -pthread -Wa,--noexecstack -Wall -O3 -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -specs=/usr/lib/rpm/kylin/kylin-hardened-cc1 -fasynchronous-unwind-tables -fstack-clash-protection -Wa,--noexecstack -specs=/usr/lib/rpm/kylin/kylin-hardened-ld -DOPENSSL_USE_NODELETE -DOPENSSL_PIC -DOPENSSL_CPUID_OBJ -DOPENSSL_BN_ASM_MONT -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DKECCAK1600_ASM -DVPAES_ASM -DECP_NISTZ256_ASM -DPOLY1305_ASM -DZLIB -DNDEBUG -DPURIFY -DDEVRANDOM="\"/dev/urandom\""
                  sign    verify    sign/s verify/s
rsa  512 bits 0.000110s 0.000009s   9064.6 105614.8
rsa 2048 bits 0.004023s 0.000108s    248.5   9247.9
                  sign    verify    sign/s verify/s
dsa  512 bits 0.000212s 0.000141s   4725.1   7078.0
[root@arm64v8 ~]#

在 10 秒时间内,rsa512 的私钥处理 90555 单位,而 rsa2048 仅处理 2483 单位,慢了 36 倍。

再看签名性能,dsa 算法只支持签名不支持加密,而 rsa 支持加密也支持签名。从上面的结果中可以看到 rsa512 的签名速度为每秒 9064.6,rsa2048 的签名速度为每秒 248.5,dsa512 的速度为 4725.1。

openssl rand

生成伪随机数。

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

选项说明:

-out        :指定随机数输出文件,否则输出到标准输出。

-rand file  :指定随机数种子文件。种子文件中的字符越随机,openssl rand生成随机数的速度越快,随机度越高。

-base64     :指定生成的随机数的编码格式为base64。

-hex        :指定生成的随机数的编码格式为hex。

num         :指定随机数的长度。

示例:

[root@arm64v8 ~]# openssl rand -base64 30;openssl rand -hex 30;openssl rand 30
0/C8hLTWfAs7RZgf6ch5Ot8ofF9dnkzZzHEbQAkB
570179fbe43fff480de8bdfaf953af7069ecbb4d949ca1ccae512c848db7
,?L慲鴷[root@arm64v8 ~]#
  • 可以看到,不指定 -base64 或 -hex 时生成的随机数是乱码随机数(其实是 2 进制),且没有 \n 符号。

C8.5、openssl passwd

该伪命令用于生成加密的密码。

[root@arm64v8 ~]# whatis passwd
passwd               (1)  - update user's authentication tokens
passwd               (5)  - password file
passwd [sslpasswd]   (1ssl)  - compute password hashes

直接 man passwd 会得到修改用户密码的 passwd 命令帮助,而不是 openssl passwd 的帮助,所以 man sslpasswd。

[root@arm64v8 ~]# man sslpasswd

NAME
       passwd - compute password hashes

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

使用 openssl passwd 支持 3 种加密算法方式:不指定算法时,默认使用 -crypt。

选项说明:
-crypt          :UNIX标准加密算法,此为默认算法。如果加盐(-salt)算密码,只取盐的前2位,2位后面的所有字符都忽略。
-1              :基于MD5的算法代号。
-apr1           :apache中使用的备选md5算法代号,不能和"-1"选项一起使用,因为apr1本身就默认了md5。
                :htpasswd工具生成的身份验证密码就是此方法。

-salt           :加密时加点盐,可以增加算法的复杂度。但加了盐会有副作用:盐相同,密码相同,加密的结果将一样。
-in file        :从文件中读取要计算的密码列表
-stdin          :从标准输入中获取要输入的密码
-quiet          :生成密码过程中不输出任何信息

在命令行中直接输入要加密的密码 password 或者使用 -salt 时,将不需要交互确认,否则会交互确认密码。

[root@arm64v8 ~]# openssl passwd 123456; openssl passwd 123456
nRgBheu5/bVuo
Jo4Lj42LyLIgY
[root@arm64v8 ~]#

由上面的测试可知,使用默认的 -crypt 加密的密码是随机的。但是加入盐后,如果密码一样,盐一样,那么加密结果一样。

[root@arm64v8 ~]# openssl passwd -salt 'xxx' 123456 ; openssl passwd -salt 'xxx' 123456
xxkVQ7YXT9yoE
xxkVQ7YXT9yoE
[root@arm64v8 ~]#
  • 同时也看到了 -crypt 加密算法只取盐的前两位。

如果盐的前两位和密码任意一个不一样,加密结果都不一样。

[root@arm64v8 ~]# openssl passwd -salt 'xyx' 123456;openssl passwd -salt 'xxx' 123456
xyJkVhXGAZ8tM
xxkVQ7YXT9yoE
[root@arm64v8 ~]#
  • 注意,默认的 -crypt 只取盐的前两位字符,所以只要盐的前两位一样,即使第三位不同,结果也是一样的。

    [root@arm64v8 ~]# openssl passwd -salt 'xyz' 123456 ; openssl passwd -salt 'xyy' 123456
    xyJkVhXGAZ8tM
    xyJkVhXGAZ8tM
    [root@arm64v8 ~]#

测试下 MD5 格式的加密算法。

[root@arm64v8 ~]# openssl passwd -1 123456 ; openssl passwd -1 123456
$1$j5XkPfZ2$qnX34A4Pol9FVPoorkMp7/
$1$yd3QwfZp$ygL/Ebh6M9cq69w0l8/od.
[root@arm64v8 ~]#
  • 可见,结果比 -crypt 的算法更长了,且不加盐时,密码生成是随机的。
[root@arm64v8 ~]# openssl passwd -1 -salt 'abcdefg' 123456 ; openssl passwd -1 -salt 'abcdefg' 123456
$1$abcdefg$a3UbImglR4PCA3x7OvwMX.
$1$abcdefg$a3UbImglR4PCA3x7OvwMX.
[root@arm64v8 ~]#
  • 可以看出,加了盐虽然复杂度增加了,但是也受到了"盐相同,密码相同,则加密结果相同"的限制。另外,盐的长度也不再限于 2 位了。

再为 apache 或 nginx 生成访问网页时身份验证的密码,即 basic authentication 验证方式的密码。

[root@arm64v8 ~]# openssl passwd -apr1  123456 ; openssl passwd -apr1 123456
$apr1$YkJeQZ3o$kYQ.vlHiAYPjMfPtLCstK0
$apr1$4eTu/zWN$CLxEqB0yz0KgI5x.Pn5ND0
[root@arm64v8 ~]#

[root@arm64v8 ~]# openssl passwd -apr1 -salt 'abcdefg' 123456 ;  openssl passwd -apr1 -salt 'abcdefg' 123456
$apr1$abcdefg$PCGBZd8XFTLOgZzLLU3K00
$apr1$abcdefg$PCGBZd8XFTLOgZzLLU3K00
[root@arm64v8 ~]#
  • 同样,加了盐就受到 "盐相同,密码相同则加密结果相同" 的限制。

C8.6、openssl dgst(生成和验证数字签名)

该伪命令是单向加密工具,用于生成文件的摘要信息,也可以进行数字签名,验证数字签名。

首先要明白的是,数字签名的过程是计算出数字摘要,然后使用私钥对数字摘要进行签名,而摘要是使用 md5、sha512 等算法计算得出的,理解了这一点,openssl dgst 命令的用法就完全掌握了。

openssl dgst    [-md5|-sha1|...] [-hex | -binary] [-out filename] [-sign filename]
                [-passin arg] [-verify filename] [-prverify filename] [-signature filename] [file...]

选项说明:

file...             :指定待签名的文件。
-hex                :以hex格式输出数字摘要。如果不以-hex显示,签名或验证签名时很可能乱码。
-binary             :以二进制格式输出数字摘要,或以二进制格式进行数字签名。这是默认格式。
-out filename       :指定输出文件,若不指定则输出到标准输出。
-sign filename      :使用filename中的私钥对file数字签名。签名时绝对不能加-hex等格式的选项,否则验证签名失败。
-signature filename :指定待验证的签名文件。
-verify filename    :使用filename中的公钥验证签名。
-prverify filename  :使用filename中的私钥验证签名。
-passin arg         :传递解密密码。若验证签名时实用的公钥或私钥文件是被加密过的,则需要传递密码来解密。
                    :密码的格式见"openssl 密码格式"

支持如下几种单向加密算法,即签名时使用的 hash 算法。

-md4            to use the md4 message digest algorithm
-md5            to use the md5 message digest algorithm
-ripemd160      to use the ripemd160 message digest algorithm
-sha            to use the sha message digest algorithm
-sha1           to use the sha1 message digest algorithm
-sha224         to use the sha224 message digest algorithm
-sha256         to use the sha256 message digest algorithm
-sha384         to use the sha384 message digest algorithm
-sha512         to use the sha512 message digest algorithm
-whirlpool      to use the whirlpool message digest algorithm
  • 注意:openssl dgst -md5 和 openssl md5 的作用是一样的,其他单向加密算法也一样,例如 openssl dgst -sha 等价于 openssl sha。
  1. 随机生成一段摘要信息。

    [root@arm64v8 ~]# echo 123456 | openssl md5
    (stdin)= f447b20a7fcbf53a5d5be013ea0b15af
  2. 对 /tmp/a.txt 文件生成 MD5 和 sha512 摘要信息。

    [root@arm64v8 ~]# openssl dgst -md5 /tmp/a.txt 
    MD5(/tmp/a.txt)= d41d8cd98f00b204e9800998ecf8427e
    
    [root@arm64v8 ~]# openssl sha512 /tmp/a.txt 
    SHA512(/tmp/a.txt)= cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e
  3. 生成一个私钥 genrsa.pri,然后使用该私钥对 /tmp/a.txt 文件签名。使用 -hex 选项,否则默认输出格式为二进制会乱码。

    [root@arm64v8 ~]# openssl genrsa -out genrsa.pri
    Generating RSA private key, 2048 bit long modulus
    .........+++
    ...............................................................................................+++
    e is 65537 (0x10001)
    [root@arm64v8 ~]# 
    [root@arm64v8 ~]# openssl dgst -md5 -hex -sign genrsa.pri /tmp/a.txt 
    RSA-MD5(/tmp/a.txt)= 4310425d7e758b4b5f52a4ec34497b7c2b6ea28b7e715ff20826942c19cd10d89908f0d749594fd6d078918b836d21c7402f11784e425b6f454041a60e19e09771e0b5ea8dab0ecb5ebe90cd8cb437200d5d27c804c847444c41744e121132a4c0f70c9dc2fcc31e2fb10641b68f849a271615522088ea9bf5e6fe35749037821fe7666f6b46f782fb2b5fcb3a46f1a7092714ce8bc37828722d55c0c8d105c2a83766f8601d8964fd0ae1053a785f324f7ada3bc03fa22b0d0a866346cf89f08d5a8f7dce864aab822d4f5ec8bb57626f3bd8c73e712d1b2673e91f652081ea4233e367e8a6aacd5e56a110fa1f3bde4853661de492156b760643277245d939
    [root@arm64v8 ~]#

    如果要验证签名,那么这个生成的签名要保存到一个文件中,且一定不能使用 "-hex" 选项,否则验证签名必失败。以下分别生成使用和不使用 hex 格式的签名文件以待验证签名测试。

    [root@arm64v8 ~]# openssl dgst -md5 -hex -out md5_hex.sign -sign genrsa.pvi /tmp/a.txt 
    [root@arm64v8 ~]# openssl dgst -md5 -out md5_nohex.sign -sign genrsa.pvi /tmp/a.txt
  4. 验证签名。验证签名的过程实际上是对待验证文件新生成签名,然后与已有签名文件进行比对,如果比对结果相同,则验证通过。所以,在验证签名时不仅要给定待验证的签名文件,也要给定相同的算法,相同的私钥或公钥文件以及待签名文件以生成新签名信息。

    以下先测试以私钥来验证数字签名文件。

    • 首先对未使用 hex 格式的签名文件 md5_nohex.sign 进行验证。由于生成 md5_nohex.sign 时使用的是 md5 算法,所以这里必须也要指定 md5 算法。

      [root@arm64v8 ~]# openssl dgst -md5 -prverify genrsa.pvi -signature md5_nohex.sign /tmp/a.txt 
      Verified OK
      [root@arm64v8 ~]#
    • 再对使用了 hex 格式的签名文件 md5_hex.sign 进行验证,不论在验证时是否使用了 hex 选项,结果都是验证失败。

      [root@arm64v8 ~]# openssl dgst -md5 -prverify genrsa.pvi -signature md5_hex.sign /tmp/a.txt 
      Verification Failure
      [root@arm64v8 ~]# 
      [root@arm64v8 ~]# openssl dgst -md5 -hex -prverify genrsa.pvi -signature md5_hex.sign /tmp/a.txt 
      Verification Failure
      [root@arm64v8 ~]#

    再测试使用公钥来验证数字签名。

    [root@arm64v8 ~]# openssl rsa -in genrsa.pvi -pubout -out rsa.pub
    writing RSA key
    [root@arm64v8 ~]# openssl dgst -md5 -verify rsa.pub -signature md5_nohex.sign /tmp/a.txt 
    Verified OK
    [root@arm64v8 ~]#

C8.7、openssl rsautl/pkeyutl(文件的非对称加密)

rsautl 是 rsa 的工具,相当于 rsa、dgst 的部分功能集合,可用于生成数字签名、验证数字签名、加密和解密文件

pkeyutl 是非对称加密的通用工具,大体上和 rsautl 的用法差不多,所以此处只解释 rsautl。

openssl rsautl  [-in file] [-out file] [-inkey file] [-pubin] [-certin]
                [-passin arg] [-sign] [-verify] [-encrypt] [-decrypt] [-hexdump]

openssl pkeyutl [-in file] [-out file] [-sigfile file] [-inkey file] [-passin arg]
                [-pubin] [-certin] [-sign] [-verify] [-encrypt] [-decrypt] [-hexdump]

共同的选项说明:
-in file        :指定输入文件
-out file       :指定输出文件
-inkey file     :指定密钥输入文件,默认是私钥文件,指定了"-pubin"则表示为公钥文件,使用"-certin"则表示为包含公钥的证书文件
-pubin          :指定"-inkey file"的file是公钥文件
-certin         :使用该选项时,表示"-inkey file"的file是包含公钥的证书文件
-passin arg     :传递解密密码。若验证签名时实用的公钥或私钥文件是被加密过的,则需要传递密码来解密。密码的格式见"openssl 密码格式"

[功能选项:]
-sign           :签名并输出签名结果,注意,该选项需要提供RSA私钥文件
-verify         :使用验证签名文件
-encrypt        :使用公钥加密文件
-decrypt        :使用私钥解密文件

[输出格式选项:]
-hexdump        :以hex方式输出

[openssl pkeyutl 选项说明:]
sigfile file    :待验证的签名文件
  • rsautl 命令的用法和 rsa、dgst 不太一样。

    • 首先,它的前提是已经有非对称密钥,所有的命令操作都用到公钥或私钥来处理;
    • 再者,该命令使用 -in 选项来指定输入文件,而不像 dgst 一样可以把输入文件放在命令的结尾;
    • 最后,该命令使用的密钥文件、签名文件、证书文件都通过 -inkey 选项指定,再通过各功能的选项搭配来实现对应的功能。
  • 注意 rsautl 和 pkeyutl 的缺陷是默认只能对短小的文件进行操作,否则将报类似如下的错误信息。

    140341340976968:error:0406C06E:rsa routines:RSA_padding_add_PKCS1_type_1:data too large for key size:rsa_pk1.c:73:

因为这两个工具签名和验证签名的功能和 openssl dgst 命令差不多,且自身又有缺陷,所以就不举例说明。此处仅给出对短小文件的非对称加密和解密示例。

  1. 使用公钥加密 b.txt 文件,注意待加密文件 b.txt 必须是短小文件,且不建议使用 -hexdump 输出,否则解密时可能超出文件的长度。

    [root@arm64v8 ~]# openssl genrsa -out genrsa.pri  # 生成私钥
    Generating RSA private key, 2048 bit long modulus
    .....................................................+++
    ...................+++
    e is 65537 (0x10001)
    [root@arm64v8 ~]# 
    [root@arm64v8 ~]# openssl rsa -in genrsa.pri -pubout -out rsa.pub    # 从私钥中提取公钥
    writing RSA key
    [root@arm64v8 ~]# 
    [root@arm64v8 ~]# openssl rsautl -encrypt -in b.txt -out b_crypt.txt -inkey rsa.pub -pubin
    [root@arm64v8 ~]#

    查看非对称加密后的文件 b_crypt.txt。

    [root@arm64v8 ~]# cat b_crypt.txt 
    ߕ{
     avM|Q\-=硪m懖ªeigϟǚi胯oy*7H沱~~4>y¯sൠ&B=#< i³Bn󒙣ȐBþZ¸¯=Y@M¨ޯΖ Ǟ:̙ !
                                                                      i£º
    쀒P[qꦓdׇ߫j󿿬ݻÿ_򮿱ڼk¼]װ¬<7{񨲢¹՝c栃âռ§°ܥ7#g󋉫EU#80Y^ʯ¹¹]>6»£򟋚¶6  ᘥWEZ¾¢
    ْꭍ   ¦[root@arm64v8 ~]# 
  2. 使用私钥解密 b_crypt.txt 文件。

    [root@arm64v8 ~]# cat b.txt 
    I am an example!
    [root@arm64v8 ~]# openssl rsautl -decrypt -in b_crypt.txt -out b_decrypt.txt -inkey genrsa.pri
    [root@arm64v8 ~]# cat b_decrypt.txt 
    I am an example!
    [root@arm64v8 ~]#

C8.8、openssl enc(对称加密)

对称加密工具。了解对称加密的原理后就很简单了,原理部分见下文。

OpenSSL 1.1.0:
openssl enc -ciphername [-help] [-ciphers] [-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 digest] [-p] [-P]
                        [-bufsize number] [-nopad] [-debug] [-none] [-engine id]

OpenSSL 1.1.1:
openssl enc -cipher [-help] [-ciphers] [-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 digest]
                    [-iter count] [-pbkdf2] [-p] [-P] [-bufsize number] [-nopad] [-debug]
                    [-none] [-rand file...] [-writerand file] [-engine id]

选项说明:

-ciphername     :指定对称加密算法(如des3),可独立于enc直接使用,如openssl des3或openssl enc -des3。
                :推荐在enc后使用,这样不依赖于硬件。

-in filename    :输入文件,不指定时默认是stdin。
-out filename   :输出文件,不指定时默认是stdout。
-e              :对输入文件加密操作,不指定时默认就是该选项。
-d              :对输入文件解密操作,只有显示指定该选项才是解密。
-pass           :传递加、解密时的明文密码。若验证签名时实用的公钥或私钥文件是被加密过的,则需要传递密码来解密。
                :密码的格式见"openssl 密码格式"。

-k              :已被"-pass"替代,现在还保留是为了兼容老版本的openssl。
-base64         :在加密后和解密前进行base64编码或解密,不指定时默认是二进制。
                :注意,编码不是加解密的一部分,而是加解密前后对数据的格式"整理"。

-a              :等价于-base64。
-salt           :单向加密时使用salt复杂化单向加密的结果,此为默认选项,且使用随机salt值。
-S salt         :不使用随机salt值,而是自定义salt值,但只能是16进制范围内字符的组合,即"0-9a-fA-F"的任意一个或多个组合。
-p              :打印加解密时salt值、key值和IV初始化向量值(也是复杂化加密的一种方式),解密时还输出解密结果,见后文示例。
-P              :和-p选项作用相同,但是打印时直接退出工具,不进行加密或解密操作。
-md             :指定单向加密算法,默认md5。该算法是拿来加密key部分的,见后文分析。

-pbkdf2         : 使用PBKDF2(Password-Based Key Derivation Function 2)算法。
-iter 100000    :覆盖密码的默认迭代次数。
                :在推导加密密钥时,对密码使用给定的迭代次数。高值会增加强制执行结果文件所需的时间。此选项允许使用PBKDF2算法来派生密钥。

支持的单向加密算法有:

-md4            to use the md4 message digest algorithm
-md5            to use the md5 message digest algorithm
-ripemd160      to use the ripemd160 message digest algorithm
-sha            to use the sha message digest algorithm
-sha1           to use the sha1 message digest algorithm
-sha224         to use the sha224 message digest algorithm
-sha256         to use the sha256 message digest algorithm
-sha384         to use the sha384 message digest algorithm
-sha512         to use the sha512 message digest algorithm
-whirlpool      to use the whirlpool message digest algorithm

支持的对称加密算法有:

-aes-128-cbc               -aes-128-cbc-hmac-sha1     -aes-128-cfb             
-aes-128-cfb1              -aes-128-cfb8              -aes-128-ctr             
-aes-128-ecb               -aes-128-gcm               -aes-128-ofb             
-aes-128-xts               -aes-192-cbc               -aes-192-cfb             
-aes-192-cfb1              -aes-192-cfb8              -aes-192-ctr             
-aes-192-ecb               -aes-192-gcm               -aes-192-ofb             
-aes-256-cbc               -aes-256-cbc-hmac-sha1     -aes-256-cfb             
-aes-256-cfb1              -aes-256-cfb8              -aes-256-ctr             
-aes-256-ecb               -aes-256-gcm               -aes-256-ofb             
-aes-256-xts               -aes128                    -aes192                  
-aes256                    -bf                        -bf-cbc                  
-bf-cfb                    -bf-ecb                    -bf-ofb                  
-blowfish                  -camellia-128-cbc          -camellia-128-cfb        
-camellia-128-cfb1         -camellia-128-cfb8         -camellia-128-ecb        
-camellia-128-ofb          -camellia-192-cbc          -camellia-192-cfb        
-camellia-192-cfb1         -camellia-192-cfb8         -camellia-192-ecb        
-camellia-192-ofb          -camellia-256-cbc          -camellia-256-cfb        
-camellia-256-cfb1         -camellia-256-cfb8         -camellia-256-ecb        
-camellia-256-ofb          -camellia128               -camellia192             
-camellia256               -cast                      -cast-cbc                
-cast5-cbc                 -cast5-cfb                 -cast5-ecb               
-cast5-ofb                 -des                       -des-cbc                 
-des-cfb                   -des-cfb1                  -des-cfb8                
-des-ecb                   -des-ede                   -des-ede-cbc             
-des-ede-cfb               -des-ede-ofb               -des-ede3                
-des-ede3-cbc              -des-ede3-cfb              -des-ede3-cfb1           
-des-ede3-cfb8             -des-ede3-ofb              -des-ofb                
-des3                      -desx                      -desx-cbc                
-id-aes128-GCM             -id-aes128-wrap            -id-aes128-wrap-pad      
-id-aes192-GCM             -id-aes192-wrap            -id-aes192-wrap-pad      
-id-aes256-GCM             -id-aes256-wrap            -id-aes256-wrap-pad      
-id-smime-alg-CMS3DESwrap  -idea                      -idea-cbc                 
-idea-cfb                  -idea-ecb                  -idea-ofb                
-rc2                       -rc2-40-cbc                -rc2-64-cbc              
-rc2-cbc                   -rc2-cfb                   -rc2-ecb                 
-rc2-ofb                   -rc4                       -rc4-40                  
-rc4-hmac-md5              -seed                      -seed-cbc                
-seed-cfb                  -seed-ecb                  -seed-ofb

对称加密和解密的原理说明:

  • 对称加解密时,它们使用的密码是完全相同的,例如 "123456",但这是密码,且是明文密码,非常不安全,所以应该对此简单密码进行复杂化。
    • 最直接的方法是使用单向加密计算出明文密码的 hash 值,单向加密后新生成的密码已经比较安全(称之为密钥比较好),可以作为对称加密时的对称密钥。
  • 另外,由于同一单向加密算法对相同明文密码的计算结果是完全一致的,这样解密时使用相同的单向加密算法就能计算出完全相同的密钥,也就是解密时的对称密钥。
    • 如果想要更安全,还可以在对称加密后对加密文件进行重新编码,如使用 "base64"、二进制或 hex 编码方式进行编码,但对应的在解密前就需要先解码,解码后才能解密。

对称加密和解密的过程总结:

  • 对称加密机制:根据指定的单向加密算法,对输入的明文密码进行单向加密(默认是 md5),得到固定长度的加密密钥,即对称密钥,再根据指定的对称加密算法,使用对称密钥加密文件,最后重新编码加密后的文件。即单向加密明文密码结果作为对称密钥、使用对称密钥加密文件、对文件重新编码。
  • 对称解密机制:先解码文件,再根据单向加密算法对解密时输入的明文密码计算得到对称密钥,用此对称密钥对称解密解码后的文件。

因此,解密过程中使用的解码方式、单向加密和对称加密算法都必须一致,且输入的密码必须是正确密码。但需要注意的一点是,解密时可以不指定 salt,因为加密时使用的 salt 会记录下来,解密时可以读取该 salt。

如下图所示,分别是加密和解密过程示意图:

openssl enc

以加密 /etc/fstab 的备份文件 /tmp/test.txt 为例:

  1. 首先测试 openssl enc 的编码功能。由于未指定密码选项 "-k" 或 "-pass",所以仅仅只进行编码而不进行加密,因此也不会提示输入密码。

    [root@arm64v8 ~]# openssl enc -a -in /tmp/test.txt -out test_base64.txt
    [root@arm64v8 ~]# 
    [root@arm64v8 ~]# cat test_base64.txt
    CiMKIyAvZXRjL2ZzdGFiCiMgQ3JlYXRlZCBieSBhbmFjb25kYSBvbiBXZWQgT2N0
    IDI3IDExOjE3OjI2IDIwMjEKIwojIEFjY2Vzc2libGUgZmlsZXN5c3RlbXMsIGJ5
    IHJlZmVyZW5jZSwgYXJlIG1haW50YWluZWQgdW5kZXIgJy9kZXYvZGlzay8nLgoj
    IFNlZSBtYW4gcGFnZXMgZnN0YWIoNSksIGZpbmRmcyg4KSwgbW91bnQoOCkgYW5k
    L29yIGJsa2lkKDgpIGZvciBtb3JlIGluZm8uCiMKIyBBZnRlciBlZGl0aW5nIHRo
    aXMgZmlsZSwgcnVuICdzeXN0ZW1jdGwgZGFlbW9uLXJlbG9hZCcgdG8gdXBkYXRl
    IHN5c3RlbWQKIyB1bml0cyBnZW5lcmF0ZWQgZnJvbSB0aGlzIGZpbGUuCiMKVVVJ
    RD04NjcyZGZmMS02OWEwLTQ1MzAtYTQxNS1kZTc5MGM2MDU0ZjUgLyAgICAgICAg
    ICAgICAgICAgICAgICAgeGZzICAgICBkZWZhdWx0cyAgICAgICAgMCAwClVVSUQ9
    YjMxMTVhMDYtZGM3Zi00M2U2LTlhYjQtZDY2NTE1MGY4NDFkIC9ib290ICAgICAg
    ICAgICAgICAgICAgIHhmcyAgICAgZGVmYXVsdHMgICAgICAgIDAgMApVVUlEPTRB
    RTYtODFCQyAgICAgICAgICAvYm9vdC9lZmkgICAgICAgICAgICAgICB2ZmF0ICAg
    IHVtYXNrPTAwNzcsc2hvcnRuYW1lPXdpbm50IDAgMgpVVUlEPTEzYzBmMjQ4LTlm
    ZjItNDBmZi05MTllLTZlMjg3NjJkOTYxOCBzd2FwICAgICAgICAgICAgICAgICAg
    ICBzd2FwICAgIGRlZmF1bHRzICAgICAgICAwIDAK
    [root@arm64v8 ~]#

    再以 base64 格式进行解码。

    [root@arm64v8 ~]# openssl enc -a -d -in test_base64.txt 
    
    #
    # /etc/fstab
    # Created by anaconda on Wed Oct 27 11:17:26 2021
    #
    # Accessible filesystems, by reference, are maintained under '/dev/disk/'.
    # See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info.
    #
    # After editing this file, run 'systemctl daemon-reload' to update systemd
    # units generated from this file.
    #
    UUID=8672dff1-69a0-4530-a415-de790c6054f5 /                       xfs     defaults        0 0
    UUID=b3115a06-dc7f-43e6-9ab4-d665150f841d /boot                   xfs     defaults        0 0
    UUID=4AE6-81BC                         /boot/efi               vfat    umask=0077,shortname=winnt 0 2
    UUID=13c0f248-9ff2-40ff-919e-6e28762d9618 swap                    swap    defaults        0 0
    [root@arm64v8 ~]#

    实际上,上述编码和解码的过程严格地说也是对称加密和解密,因为 openssl enc 默认会带上加密选项 "-e",只不过因为没有指定输入密码选项,使用的加密密码为空而已,且单向加密算法使用的也是默认值。解密时也一样。

  2. 测试使用 des3 对称加密算法加密 test.txt 文件。

    加密 /tmp/test.txt 输出加密文件 test.1:

    [root@arm64v8 ~]# openssl enc -a -des3 -in /tmp/test.txt -out test.1 -pass pass:123456 -md md5
    [root@arm64v8 ~]# 
    [root@arm64v8 ~]# cat test.1 
    U2FsdGVkX1+hcdk6exS60AIS5EL/HxU05gR2cIhDodfUTwRQUVD8HI1l8rFqOiRY
    JpX44CLSEzQE8mvjdEi0vHQsv5if6zUiWYn3eDULBHAhfF20U+FLXuUe2Jp8UoWZ
    9SC36AtgaKPkn370HSOVtIyfV5eIinjGaGW5Z94WQrxE1m9WuhllG46QoH11XSNK
    tpDxJf2SSCzHwGRS4pmcWw7SUbrWJGLmMv667Hs5p6qLvfu/xL6XF9FrKohzCTxD
    /N+9bILfazn6/pXNFv4CWBy8EJ+lOw2Y22yTl+rZddVCIRJ0Z5cJewLZuo2HgCPT
    x5YHetwYqeumB+safpoSCPQ770n07hsKZ11X8LSYqG2IgqLS2QakfK095wwNTaWq
    OZ2h0K/nx85QFm995mZei0C+VNDxfGVr704CzXTE5/mV7v9Tw3ZIcSrRflqDe3MU
    yG4Sdu4SOe2Z7FdfgxTvnbl4h8yLmkij9rLyH0YFe/pyUXy8U8hHBcb8DBL/d9uS
    EDQAh9Uk5mZ4NvdcvYnBz+1ybwK6Cj582ZRkBNJ9G4jlFo3w9tCJZ3ux/WEevrpi
    PvNsOJDhQmG15Xw/lXI9PHhKyrZEdY77PYIIyO+yi4KGdGFu4OOtyvsjeZs1DD5i
    PJuUXPHHkSN55IfR3wLHNkRogp/9OAdRltf8e0xdYPaWKB5zjdLQskkM74lrFwz5
    GXXev8WWYGEdlOPQUXPLx6TUhrgcbLohELvn3krawgrmqPRBFLRSKJeBt67V+paz
    4Nd6yVSyhYMyCq0VnzY8geOW+nURdVV93O/uJCaOL1SwFge5XXivIBTAudvuxola
    m+fsIsgzY9ONtnULhDRbPHq/E2RbnujbrlMIs2a4DedLcbTlqw6Eg1Uvqpxb7UgS
    BSiVDeFWLMdpdEmAziCe9POVIv44LrZYHEDwaSW2MVEF7UqEHYvTf/Uff12/afMH
    [root@arm64v8 ~]#

    解密文件 test.1:

    [root@arm64v8 ~]# openssl enc -a -des3 -d -in test.1 -out test.2 -pass pass:123456 -md md5
    [root@arm64v8 ~]# 
    [root@arm64v8 ~]# cat test.2 
    
    #
    # /etc/fstab
    # Created by anaconda on Wed Oct 27 11:17:26 2021
    #
    # Accessible filesystems, by reference, are maintained under '/dev/disk/'.
    # See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info.
    #
    # After editing this file, run 'systemctl daemon-reload' to update systemd
    # units generated from this file.
    #
    UUID=8672dff1-69a0-4530-a415-de790c6054f5 /                       xfs     defaults        0 0
    UUID=b3115a06-dc7f-43e6-9ab4-d665150f841d /boot                   xfs     defaults        0 0
    UUID=4AE6-81BC          /boot/efi               vfat    umask=0077,shortname=winnt 0 2
    UUID=13c0f248-9ff2-40ff-919e-6e28762d9618 swap                    swap    defaults        0 0
    [root@arm64v8 ~]#
  3. 加密时带上点盐 salt。其实不写时默认就已经加入了,只不过是加入随机盐值。使用 -S 可以指定明确要使用的盐的值。但是盐的值只能是 16 进制范围内字符的组合,即 "0-9a-fA-F" 的任意一个或多个组合。

    [root@arm64v8 ~]# openssl enc -a -des3 -S 'AaBb' -in /tmp/test.txt -out test.1 -pass pass:123456 -md md5
    hex string is too short, padding with zero bytes to length
    [root@arm64v8 ~]#

    解密。解密时不用指定 salt 值,即使指定了也不会影响解密结果:

    [root@arm64v8 ~]# openssl enc -a -des3 -d -in test.1 -pass pass:123456 -md md5
    #
    # /etc/fstab
    # Created by anaconda on Wed Oct 27 11:17:26 2021
    #
    # Accessible filesystems, by reference, are maintained under '/dev/disk/'.
    # See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info.
    #
    # After editing this file, run 'systemctl daemon-reload' to update systemd
    # units generated from this file.
    #
    UUID=8672dff1-69a0-4530-a415-de790c6054f5 /                       xfs     defaults        0 0
    UUID=b3115a06-dc7f-43e6-9ab4-d665150f841d /boot                   xfs     defaults        0 0
    UUID=4AE6-81BC          /boot/efi               vfat    umask=0077,shortname=winnt 0 2
    UUID=13c0f248-9ff2-40ff-919e-6e28762d9618 swap                    swap    defaults        0 0
    [root@arm64v8 ~]#
    
    [root@arm64v8 ~]# openssl enc -a -des3 -d -S 'Fabcxdasd' -in test.1 -pass pass:123456 -md md5
    #
    # /etc/fstab
    # Created by anaconda on Wed Oct 27 11:17:26 2021
    #
    # Accessible filesystems, by reference, are maintained under '/dev/disk/'.
    # See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info.
    #
    # After editing this file, run 'systemctl daemon-reload' to update systemd
    # units generated from this file.
    #
    UUID=8672dff1-69a0-4530-a415-de790c6054f5 /                       xfs     defaults        0 0
    UUID=b3115a06-dc7f-43e6-9ab4-d665150f841d /boot                   xfs     defaults        0 0
    UUID=4AE6-81BC          /boot/efi               vfat    umask=0077,shortname=winnt 0 2
    UUID=13c0f248-9ff2-40ff-919e-6e28762d9618 swap                    swap    defaults        0 0
    [root@arm64v8 ~]#
  4. 在测试下 "-p" 和 "-P" 选项的输出功能。小写字母 p 不仅输出密钥算法结果,还输出加解密的内容,而大写字母 P 则只输出密钥算法结果。

    加密时的情况:

    [root@arm64v8 ~]# openssl enc -a -des3 -S 'Fabc' -in /tmp/test.txt -out test.1 -pass pass:123456 -md md5 -p
    hex string is too short, padding with zero bytes to length
    salt=FABC000000000000
    key=885FC58E6C822AEFC8032B4B98FA0355F8482BD654739F3D
    iv =5128FDED01EE1499
    [root@arm64v8 ~]#
    • 其中 key 就是单向加密明文密码后得到的对称密钥,iv 是密码运算时使用的向量值。

    再看解密时的情况,此处加上了 salt:

    [root@arm64v8 ~]# openssl enc -a -des3 -d -S 'Fabc' -in test.1 -pass pass:123456 -md md5 -P
    salt=FABC000000000000
    key=885FC58E6C822AEFC8032B4B98FA0355F8482BD654739F3D
    iv =5128FDED01EE1499
    [root@arm64v8 ~]#

    若解密时不指定 salt,或者随意指定 salt,结果如下:

    [root@arm64v8 ~]# openssl enc -a -des3 -d -in test.1 -pass pass:123456 -md md5 -P
    salt=FABC000000000000
    key=885FC58E6C822AEFC8032B4B98FA0355F8482BD654739F3D
    iv =5128FDED01EE1499
    [root@arm64v8 ~]# 
    [root@arm64v8 ~]# openssl enc -a -des3 -S 'FabM' -d -in test.1 -pass pass:123456 -md md5 -P
    salt=FABC000000000000
    key=885FC58E6C822AEFC8032B4B98FA0355F8482BD654739F3D
    iv =5128FDED01EE1499
    [root@arm64v8 ~]#
    • 可见,解密时,只要指定和加密时相同编码格式和单向加密算法,密钥的结果就是一样的,且解密时明确指定 salt 是无意义的,因为它可以读取到加密时使用的 salt。

注意:openssl v1.1.0 和 v1.1.1 两个版本有一些区别,在 v1.1.1 上使用 DES3 算法时会出现 *** WARNING : deprecated key derivation used. Using -iter or -pbkdf2 would be better. 这个提示。如果换成这种算法 openssl enc -aes-256-cbc -md sha512 -pbkdf2 -iter 100000 -salt -in InputFilePath -out OutputFilePath 就可以解决。

C8.9、openssl dhparam(密钥交换)

openssl dhparam 用于生成和管理 dh 文件。dh(Diffie-Hellman) 是著名的密钥交换协议,或称为密钥协商协议,它可以保证通信双方安全地交换密钥。但注意,它不是加密算法,所以不提供加密功能,仅仅只是保护密钥交换的过程。在 openvpn 中就使用了该交换协议。

openssl dhparam 命令集合了老版本的 openssl dh 和 openssl gendh,后两者可能已经失效了,即使存在也仅表示未来另有用途。

openssl dhparam [-in filename] [-out filename] [-dsaparam] [-noout] [-text] [-rand file(s)] [numbits]

选项说明:
-in filename    :从filename文件中读取密钥交换协议参数。
-out filename   :输出密钥交换协议参数到filename文件。
-dsaparam       :指定此选项将使用dsa交换协议替代dh交换协议。虽然生成速度更快,但更不安全。
-noout          :禁止输出任何信息。
-text           :以文本格式输出dh协议。
-rand           :指定随机数种子文件。
numbits         :指定生成的长度。
[root@arm64v8 ~]# time openssl dhparam -out dh.pem 1024
Generating DH parameters, 1024 bit long safe prime, generator 2
This is going to take a long time
......
......
real    0m4.872s
user    0m4.855s
sys 0m0.010s
[root@arm64v8 ~]#
[root@arm64v8 ~]# time openssl dhparam -out dh.pem 2048
Generating DH parameters, 2048 bit long safe prime, generator 2
This is going to take a long time
......
......
real    2m47.160s
user    2m47.077s
sys     0m0.010s
[root@arm64v8 ~]#
[root@arm64v8 ~]# time openssl dhparam -rand rand.seed -out dh.pem 2048
0 semi-random bytes loaded
Generating DH parameters, 2048 bit long safe prime, generator 2
This is going to take a long time
......
......
real    1m28.874s
user    1m28.801s
sys 0m0.030s
[root@arm64v8 ~]#

注意:理论上指定更长长度生成文件需要花费的时间更多;同一生成条件下,指定随机数种子,时间相对短一些。在实际操作过程中,无论是 ARM64 CPU 还是 X86 CPU 同一生成条件下,所花费的时间也不固定,而且差别非常大,当然,这个并没有那么重要。

C8.10、openssl req(生成证书请求和自建 CA)

伪命令 req 大致有 3 个功能:生成证书请求文件、验证证书请求文件和创建根 CA。

openssl req 经常会依赖于配置文件(默认为 /etc/pki/tls/openssl.cnf)中的值。所以,先将 openssl req 的命令用法总结下,再简单说明下配置文件中和 req 有关的内容。

openssl req [-new] [-newkey rsa:bits] [-verify] [-x509] [-in filename] [-out filename] [-key filename] [-passin arg] [-passout arg] 
[-keyout filename] [-pubkey] [-nodes] [-[dgst]] [-config filename] [-subj arg] [-days n] [-set_serial n] [-extensions section]
[-reqexts section] [-utf8] [-nameopt] [-reqopt] [-subject] [-subj arg] [-text] [-noout] [-batch] [-verbose]

选项说明:
-new        :创建一个证书请求文件,会交互式提醒输入一些信息,这些交互选项以及交互选项信息的长度值以及其他一些扩展属性在配置文件(默认为
            :openssl.cnf,还有些辅助配置文件)中指定了默认值。如果没有指定"-key"选项,则会自动生成一个RSA私钥,该私钥的生成位置
            :也在openssl.cnf中指定了。如果指定了-x509选项,则表示创建的是自签署证书文件,而非证书请求文件
-newkey args:类似于"-new"选项,创建一个新的证书请求,并创建私钥。args的格式是"rsa:bits"(其他加密算法请查看man),其中bits
            :是rsa密钥的长度,如果bits省略了(即-newkey rsa),则长度根据配置文件中default_bits指令的值作为默认长度,默认该值为2048
            :如果指定了-x509选项,则表示创建的是自签署证书文件,而非证书请求文件
-nodes      :默认情况下,openssl req自动创建私钥时都要求加密并提示输入加密密码,指定该选项后则禁止对私钥文件加密
-key filename    :指定私钥的输入文件,创建证书请求时需要
-keyout filename :指定自动创建私钥时私钥的存放位置,若未指定该选项,则使用配置文件中default_keyfile指定的值,默认该值为privkey.pem
-[dgst]          :指定对创建请求时提供的申请者信息进行数字签名时的单向加密算法,如-md5/-sha1/-sha512等,
                 :若未指定则默认使用配置文件中default_md指定的值
-verify       :对证书请求文件进行数字签名验证
-x509         :指定该选项时,将生成一个自签署证书,而不是创建证书请求。一般用于测试或者为根CA创建自签名证书
-days n       :指定自签名证书的有效期限,默认30天,需要和"-x509"一起使用。
              :注意是自签名证书期限,而非请求的证书期限,因为证书的有效期是颁发者指定的,证书请求者指定有效期是没有意义的,
              :配置文件中的default_days指定了请求证书的有效期限,默认365天
-set_serial n :指定生成自签名证书时的证书序列号,该序列号将写入配置文件中serial指定的文件中,这样就不需要手动更新该序列号文件
              :支持数值和16进制值(0x开头),虽然也支持负数,但不建议
-in filename  :指定证书请求文件filename。注意,创建证书请求文件时是不需要指定该选项的
-out filename :证书请求或自签署证书的输出文件,也可以是其他内容的输出文件,不指定时默认stdout
-subj args    :替换或自定义证书请求时需要输入的信息,并输出修改后的请求信息。args的格式为"/type0=value0/type1=value1...",
              :如果value为空,则表示使用配置文件中指定的默认值,如果value值为".",则表示该项留空。其中可识别type(man req)有:
              :C是Country、ST是state、L是localcity、O是Organization、OU是Organization Unit、CN是common name等

【输出内容选项:】
-text         :以文本格式打印证书请求
-noout        :不输出部分信息
-subject      :输出证书请求文件中的subject(如果指定了x509,则打印证书中的subject)
-pubkey       :输出证书请求文件中的公钥

【配置文件项和杂项:】
-passin arg      :传递解密密码
-passout arg     :指定加密输出文件时的密码
-config filename :指定req的配置文件,指定后将忽略所有的其他配置文件。如果不指定则默认使用/etc/pki/tls/openssl.cnf中req段落的值
-batch           :非交互模式,直接从配置文件(默认/etc/pki/tls/openssl.cnf)中读取证书请求所需字段信息。但若不指定"-key"时,仍会询问key
-verbose         :显示操作执行的详细信息

以下则是配置文件中(默认 /etc/pki/tls/openssl.cnf)关于 req 段落的配置格式。

input_password  :密码输入文件,和命令行的"-passin"选项对应,密码格式以及意义见"openssl密码格式"
output_password :密码的输出文件,与命令行的"-passout"选项对应,密码格式以及意义见"openssl密码格式"
default_bits    :openssl req自动生成RSA私钥时的长度,不写时默认是512,命令行的"-new"和"-newkey"可能会用到它 
default_keyfile :默认的私钥输出文件,与命令行的"-keyout"选项对应 
encrypt_key     :当设置为no时,自动创建私钥时不会加密该私钥。设置为no时与命令行的"-nodes"等价。还有等价的兼容性写法:encry_rsa_key 
default_md      :指定创建证书请求时对申请者信息进行数字签名的单向加密算法,与命令行的"-[dgst]"对应 
prompt          :当指定为no时,则不提示输入证书请求的字段信息,而是直接从openssl.cnf中读取 
                :请小心设置该选项,很可能请求文件创建失败就是因为该选项设置为no 
distinguished_name:(DN)是一个扩展属性段落,用于指定证书请求时可被识别的字段名称。

以下是默认的配置文件格式及值。关于配置文件的详细分析见 "配置文件" 部分。

[ req ]
default_bits            = 2048
default_md              = sha1
default_keyfile         = privkey.pem
distinguished_name      = req_distinguished_name
attributes              = req_attributes
x509_extensions = v3_ca # The extentions to add to the self signed cert
string_mask = utf8only
[ req_distinguished_name ]
countryName                     = Country Name (2 letter code)
countryName_default             = XX
countryName_min                 = 2
countryName_max                 = 2
stateOrProvinceName             = State or Province Name (full name)
localityName                    = Locality Name (eg, city)
localityName_default    = Default City
0.organizationName              = Organization Name (eg, company)
0.organizationName_default      = Default Company Ltd
organizationalUnitName          = Organizational Unit Name (eg, section)
commonName                      = Common Name (eg, your name or your server\'s hostname)
commonName_max                  = 64
emailAddress                    = Email Address
emailAddress_max                = 64
  1. 第一步就是先创建出私钥 pri_key.pem。其实私钥文件是非必需的,因为 openssl req 在需要它的时候会自动创建在特定的路径下,此处为了举例说明,所以创建它。

    [root@arm64v8 ~]# openssl genrsa -out pri_key.pem
    Generating RSA private key, 2048 bit long modulus
    ....................................................................+++
    ............................+++
    e is 65537 (0x10001)
    [root@arm64v8 ~]#
  2. 根据私钥 pri_key.pem 生成一个新的证书请求文件。其中 "-new" 表示新生成一个新的证书请求文件,"-key" 指定私钥文件,"-out" 指定输出文件,此处输出文件即为证书请求文件。

    [root@arm64v8 ~]# openssl req -new -key pri_key.pem -out Brinnatt.csr
    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) [XX]:CN
    State or Province Name (full name) []:HN
    Locality Name (eg, city) [Default City]:CS
    Organization Name (eg, company) [Default Company Ltd]:Greatwall
    Organizational Unit Name (eg, section) []:Tech
    Common Name (eg, your name or your server's hostname) []:Brinnatt
    Email Address []:Brinnatt@gmail.com
    
    Please enter the following 'extra' attributes
    to be sent with your certificate request
    A challenge password []:
    An optional company name []:
    [root@arm64v8 ~]# ls
    Brinnatt.csr  pri_key.pem
    [root@arm64v8 ~]#
    • 在敲下回车键后,默认会进入交互模式让你提供你个人的信息,需要注意的是,如果某些信息不想填可以选择使用默认值,也可以选择留空不填,直接回车将选择使用默认值,输入点 "." 将表示该信息项留空。
    • 但某些项是必填项,否则未来证书签署时将失败。如 "Common Name",它表示的是为哪个域名、子域名或哪个主机申请证书,未来证书请求被签署后将只能应用于 "Common Name" 所指定的地址。
      • 具体哪些必填项还需要看所使用的配置文件(默认的配置文件为 /etc/pki/tls/openssl.cnf)中的定义,此处暂且不讨论配置相关内容,仅提供 Common Name 即可。
    • 除了 "-new" 选项,使用 "-newkey" 选项也能创建证书请求文件,此处暂不举例说明 "-newkey" 的用法,后文会有示例。
  3. 查看证书请求文件内容。

    现在已经生成了一个新的证书请求文件 Brinnatt.csr。查看下该证书请求文件的内容。

    [root@arm64v8 ~]# cat Brinnatt.csr 
    -----BEGIN CERTIFICATE REQUEST-----      # 证书请求的内容
    MIICxjCCAa4CAQAwgYAxCzAJBgNVBAYTAkNOMQswCQYDVQQIDAJITjELMAkGA1UE
    BwwCQ1MxEjAQBgNVBAoMCUdyZWF0d2FsbDENMAsGA1UECwwEVGVjaDERMA8GA1UE
    AwwIQnJpbm5hdHQxITAfBgkqhkiG9w0BCQEWEkJyaW5uYXR0QGdtYWlsLmNvbTCC
    ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKtYDo4JaMndsgCvfSXGyJuk
    F8GZQTPhXvmK52XWS2Iv1hfupg1fKl/OR8vWfla9Ie8C0uVGLd9hx3pJYxkQzwls
    9i+mfFSrZ0mT16/neFxmHxhtMxiteMGdxsQH5HhPwGhQNH36vq3ZjIsAKwxc5OUN
    DJfB2mJ1lLWmqPA6lNHq2+vnuh/SvYxs9DL4iH06NQaui8e12eR/2B3NaLigR2q3
    AhrB4+hUxC2+CAG3Z8g5D24lDf8GOeaZ1AtRcxgxpXUpMF9crPiDjXMCYkJV5Ez/
    M2kPpDXcHIyVajuGfWtviZcJ1VXv9I8rA0K+x+IyWkHE2vJgPlRajVV9+562MYEC
    AwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQCOvHJJOwe64WFURRElH9+YqJQwscJv
    4SMi/JD/RAX8yrlUCwudiFNqYDsLyj5CdFt6mwhut4hbF9h1Maigo9M4cIU2T75K
    YzKhN4KqvRc2EbCFrAK9HjBqwPyfnHo5Fu1oWp6Ns4Z+eZT3wVa7UvpOc9MpnZ7Z
    /GcpO/O1TsC0KgtwzYqPSX5Ba2tjAZ561/bZkvuXTCCYmiDtstK9//JowQo1M+Aj
    wpZEJGUKMwbW8N46+f4e157g0uduqZVIxEod0VF2N7IZARmmnbU0y1CCP8sP5R7P
    3An4ccLw73VljCJWn9+7QrYnGNQnUGo3kQcAb+aXUqDvCifFJtGE7uBu
    -----END CERTIFICATE REQUEST-----
    [root@arm64v8 ~]#

    更具体的可以使用 openssl req 命令查看。命令如下,其中 "-in" 选项指定的是证书请求文件。

    [root@arm64v8 ~]# openssl req -in Brinnatt.csr 
    -----BEGIN CERTIFICATE REQUEST-----      # 证书请求的内容
    MIICxjCCAa4CAQAwgYAxCzAJBgNVBAYTAkNOMQswCQYDVQQIDAJITjELMAkGA1UE
    BwwCQ1MxEjAQBgNVBAoMCUdyZWF0d2FsbDENMAsGA1UECwwEVGVjaDERMA8GA1UE
    AwwIQnJpbm5hdHQxITAfBgkqhkiG9w0BCQEWEkJyaW5uYXR0QGdtYWlsLmNvbTCC
    ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKtYDo4JaMndsgCvfSXGyJuk
    F8GZQTPhXvmK52XWS2Iv1hfupg1fKl/OR8vWfla9Ie8C0uVGLd9hx3pJYxkQzwls
    9i+mfFSrZ0mT16/neFxmHxhtMxiteMGdxsQH5HhPwGhQNH36vq3ZjIsAKwxc5OUN
    DJfB2mJ1lLWmqPA6lNHq2+vnuh/SvYxs9DL4iH06NQaui8e12eR/2B3NaLigR2q3
    AhrB4+hUxC2+CAG3Z8g5D24lDf8GOeaZ1AtRcxgxpXUpMF9crPiDjXMCYkJV5Ez/
    M2kPpDXcHIyVajuGfWtviZcJ1VXv9I8rA0K+x+IyWkHE2vJgPlRajVV9+562MYEC
    AwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQCOvHJJOwe64WFURRElH9+YqJQwscJv
    4SMi/JD/RAX8yrlUCwudiFNqYDsLyj5CdFt6mwhut4hbF9h1Maigo9M4cIU2T75K
    YzKhN4KqvRc2EbCFrAK9HjBqwPyfnHo5Fu1oWp6Ns4Z+eZT3wVa7UvpOc9MpnZ7Z
    /GcpO/O1TsC0KgtwzYqPSX5Ba2tjAZ561/bZkvuXTCCYmiDtstK9//JowQo1M+Aj
    wpZEJGUKMwbW8N46+f4e157g0uduqZVIxEod0VF2N7IZARmmnbU0y1CCP8sP5R7P
    3An4ccLw73VljCJWn9+7QrYnGNQnUGo3kQcAb+aXUqDvCifFJtGE7uBu
    -----END CERTIFICATE REQUEST-----
    [root@arm64v8 ~]#

    查看请求文件时,可以结合其他几个选项输出特定的内容。"-text" 选项表示以文本格式输出证书请求文件的内容。

    [root@arm64v8 ~]# openssl req -in Brinnatt.csr -text
    Certificate Request:                                             # 此为证书请求文件头
       Data:
           Version: 0 (0x0)
           Subject: C=CN, ST=HN, L=CS, O=Greatwall, OU=Tech, CN=Brinnatt/emailAddress=Brinnatt@gmail.com                          # 此为提供的个人信息,注意左侧标头为"Subject",这是很重要的一项
           Subject Public Key Info:
               Public Key Algorithm: rsaEncryption                      # 使用的公钥算法
                   Public-Key: (2048 bit)                               # 公钥的长度
                   Modulus:
                       00:ab:58:0e:8e:09:68:c9:dd:b2:00:af:7d:25:c6:
                       c8:9b:a4:17:c1:99:41:33:e1:5e:f9:8a:e7:65:d6:
                       4b:62:2f:d6:17:ee:a6:0d:5f:2a:5f:ce:47:cb:d6:
                       7e:56:bd:21:ef:02:d2:e5:46:2d:df:61:c7:7a:49:
                       63:19:10:cf:09:6c:f6:2f:a6:7c:54:ab:67:49:93:
                       d7:af:e7:78:5c:66:1f:18:6d:33:18:ad:78:c1:9d:
                       c6:c4:07:e4:78:4f:c0:68:50:34:7d:fa:be:ad:d9:
                       8c:8b:00:2b:0c:5c:e4:e5:0d:0c:97:c1:da:62:75:
                       94:b5:a6:a8:f0:3a:94:d1:ea:db:eb:e7:ba:1f:d2:
                       bd:8c:6c:f4:32:f8:88:7d:3a:35:06:ae:8b:c7:b5:
                       d9:e4:7f:d8:1d:cd:68:b8:a0:47:6a:b7:02:1a:c1:
                       e3:e8:54:c4:2d:be:08:01:b7:67:c8:39:0f:6e:25:
                       0d:ff:06:39:e6:99:d4:0b:51:73:18:31:a5:75:29:
                       30:5f:5c:ac:f8:83:8d:73:02:62:42:55:e4:4c:ff:
                       33:69:0f:a4:35:dc:1c:8c:95:6a:3b:86:7d:6b:6f:
                       89:97:09:d5:55:ef:f4:8f:2b:03:42:be:c7:e2:32:
                       5a:41:c4:da:f2:60:3e:54:5a:8d:55:7d:fb:9e:b6:
                       31:81
                   Exponent: 65537 (0x10001)
           Attributes:
               a0:00
       Signature Algorithm: sha256WithRSAEncryption                # 为请求文件数字签名时使用的算法
            8e:bc:72:49:3b:07:ba:e1:61:54:45:11:25:1f:df:98:a8:94:
            30:b1:c2:6f:e1:23:22:fc:90:ff:44:05:fc:ca:b9:54:0b:0b:
            9d:88:53:6a:60:3b:0b:ca:3e:42:74:5b:7a:9b:08:6e:b7:88:
            5b:17:d8:75:31:a8:a0:a3:d3:38:70:85:36:4f:be:4a:63:32:
            a1:37:82:aa:bd:17:36:11:b0:85:ac:02:bd:1e:30:6a:c0:fc:
            9f:9c:7a:39:16:ed:68:5a:9e:8d:b3:86:7e:79:94:f7:c1:56:
            bb:52:fa:4e:73:d3:29:9d:9e:d9:fc:67:29:3b:f3:b5:4e:c0:
            b4:2a:0b:70:cd:8a:8f:49:7e:41:6b:6b:63:01:9e:7a:d7:f6:
            d9:92:fb:97:4c:20:98:9a:20:ed:b2:d2:bd:ff:f2:68:c1:0a:
            35:33:e0:23:c2:96:44:24:65:0a:33:06:d6:f0:de:3a:f9:fe:
            1e:d7:9e:e0:d2:e7:6e:a9:95:48:c4:4a:1d:d1:51:76:37:b2:
            19:01:19:a6:9d:b5:34:cb:50:82:3f:cb:0f:e5:1e:cf:dc:09:
            f8:71:c2:f0:ef:75:65:8c:22:56:9f:df:bb:42:b6:27:18:d4:
            27:50:6a:37:91:07:00:6f:e6:97:52:a0:ef:0a:27:c5:26:d1:
            84:ee:e0:6e
    -----BEGIN CERTIFICATE REQUEST-----
    MIICxjCCAa4CAQAwgYAxCzAJBgNVBAYTAkNOMQswCQYDVQQIDAJITjELMAkGA1UE
    BwwCQ1MxEjAQBgNVBAoMCUdyZWF0d2FsbDENMAsGA1UECwwEVGVjaDERMA8GA1UE
    AwwIQnJpbm5hdHQxITAfBgkqhkiG9w0BCQEWEkJyaW5uYXR0QGdtYWlsLmNvbTCC
    ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKtYDo4JaMndsgCvfSXGyJuk
    F8GZQTPhXvmK52XWS2Iv1hfupg1fKl/OR8vWfla9Ie8C0uVGLd9hx3pJYxkQzwls
    9i+mfFSrZ0mT16/neFxmHxhtMxiteMGdxsQH5HhPwGhQNH36vq3ZjIsAKwxc5OUN
    DJfB2mJ1lLWmqPA6lNHq2+vnuh/SvYxs9DL4iH06NQaui8e12eR/2B3NaLigR2q3
    AhrB4+hUxC2+CAG3Z8g5D24lDf8GOeaZ1AtRcxgxpXUpMF9crPiDjXMCYkJV5Ez/
    M2kPpDXcHIyVajuGfWtviZcJ1VXv9I8rA0K+x+IyWkHE2vJgPlRajVV9+562MYEC
    AwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQCOvHJJOwe64WFURRElH9+YqJQwscJv
    4SMi/JD/RAX8yrlUCwudiFNqYDsLyj5CdFt6mwhut4hbF9h1Maigo9M4cIU2T75K
    YzKhN4KqvRc2EbCFrAK9HjBqwPyfnHo5Fu1oWp6Ns4Z+eZT3wVa7UvpOc9MpnZ7Z
    /GcpO/O1TsC0KgtwzYqPSX5Ba2tjAZ561/bZkvuXTCCYmiDtstK9//JowQo1M+Aj
    wpZEJGUKMwbW8N46+f4e157g0uduqZVIxEod0VF2N7IZARmmnbU0y1CCP8sP5R7P
    3An4ccLw73VljCJWn9+7QrYnGNQnUGo3kQcAb+aXUqDvCifFJtGE7uBu
    -----END CERTIFICATE REQUEST-----
    [root@arm64v8 ~]#

    将 "-text" 和 "-noout" 结合使用,则只输出证书请求的文件头部分。

    [root@arm64v8 ~]# openssl req -in Brinnatt.csr -noout -text
    Certificate Request:
       Data:
           Version: 0 (0x0)
           Subject: C=CN, ST=HN, L=CS, O=Greatwall, OU=Tech, CN=Brinnatt/emailAddress=Brinnatt@gmail.com
           Subject Public Key Info:
               Public Key Algorithm: rsaEncryption
                   Public-Key: (2048 bit)
                   Modulus:
                       00:ab:58:0e:8e:09:68:c9:dd:b2:00:af:7d:25:c6:
                       c8:9b:a4:17:c1:99:41:33:e1:5e:f9:8a:e7:65:d6:
                       4b:62:2f:d6:17:ee:a6:0d:5f:2a:5f:ce:47:cb:d6:
                       7e:56:bd:21:ef:02:d2:e5:46:2d:df:61:c7:7a:49:
                       63:19:10:cf:09:6c:f6:2f:a6:7c:54:ab:67:49:93:
                       d7:af:e7:78:5c:66:1f:18:6d:33:18:ad:78:c1:9d:
                       c6:c4:07:e4:78:4f:c0:68:50:34:7d:fa:be:ad:d9:
                       8c:8b:00:2b:0c:5c:e4:e5:0d:0c:97:c1:da:62:75:
                       94:b5:a6:a8:f0:3a:94:d1:ea:db:eb:e7:ba:1f:d2:
                       bd:8c:6c:f4:32:f8:88:7d:3a:35:06:ae:8b:c7:b5:
                       d9:e4:7f:d8:1d:cd:68:b8:a0:47:6a:b7:02:1a:c1:
                       e3:e8:54:c4:2d:be:08:01:b7:67:c8:39:0f:6e:25:
                       0d:ff:06:39:e6:99:d4:0b:51:73:18:31:a5:75:29:
                       30:5f:5c:ac:f8:83:8d:73:02:62:42:55:e4:4c:ff:
                       33:69:0f:a4:35:dc:1c:8c:95:6a:3b:86:7d:6b:6f:
                       89:97:09:d5:55:ef:f4:8f:2b:03:42:be:c7:e2:32:
                       5a:41:c4:da:f2:60:3e:54:5a:8d:55:7d:fb:9e:b6:
                       31:81
                   Exponent: 65537 (0x10001)
           Attributes:
               a0:00
       Signature Algorithm: sha256WithRSAEncryption
            8e:bc:72:49:3b:07:ba:e1:61:54:45:11:25:1f:df:98:a8:94:
            30:b1:c2:6f:e1:23:22:fc:90:ff:44:05:fc:ca:b9:54:0b:0b:
            9d:88:53:6a:60:3b:0b:ca:3e:42:74:5b:7a:9b:08:6e:b7:88:
            5b:17:d8:75:31:a8:a0:a3:d3:38:70:85:36:4f:be:4a:63:32:
            a1:37:82:aa:bd:17:36:11:b0:85:ac:02:bd:1e:30:6a:c0:fc:
            9f:9c:7a:39:16:ed:68:5a:9e:8d:b3:86:7e:79:94:f7:c1:56:
            bb:52:fa:4e:73:d3:29:9d:9e:d9:fc:67:29:3b:f3:b5:4e:c0:
            b4:2a:0b:70:cd:8a:8f:49:7e:41:6b:6b:63:01:9e:7a:d7:f6:
            d9:92:fb:97:4c:20:98:9a:20:ed:b2:d2:bd:ff:f2:68:c1:0a:
            35:33:e0:23:c2:96:44:24:65:0a:33:06:d6:f0:de:3a:f9:fe:
            1e:d7:9e:e0:d2:e7:6e:a9:95:48:c4:4a:1d:d1:51:76:37:b2:
            19:01:19:a6:9d:b5:34:cb:50:82:3f:cb:0f:e5:1e:cf:dc:09:
            f8:71:c2:f0:ef:75:65:8c:22:56:9f:df:bb:42:b6:27:18:d4:
            27:50:6a:37:91:07:00:6f:e6:97:52:a0:ef:0a:27:c5:26:d1:
            84:ee:e0:6e
    [root@arm64v8 ~]#

    还可以只输出 subject 部分的内容。

    [root@arm64v8 ~]# openssl req -in Brinnatt.csr -subject -noout
    subject=/C=CN/ST=HN/L=CS/O=Greatwall/OU=Tech/CN=Brinnatt/emailAddress=Brinnatt@gmail.com
    [root@arm64v8 ~]#

    也可以使用 "-pubkey" 输出证书请求文件中的公钥内容。如果从申请证书请求时所提供的私钥中提取出公钥,这两段公钥的内容是完全一致的。

    [root@arm64v8 ~]# openssl req -in Brinnatt.csr -pubkey -noout
    -----BEGIN PUBLIC KEY-----
    MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq1gOjgloyd2yAK99JcbI
    m6QXwZlBM+Fe+YrnZdZLYi/WF+6mDV8qX85Hy9Z+Vr0h7wLS5UYt32HHekljGRDP
    CWz2L6Z8VKtnSZPXr+d4XGYfGG0zGK14wZ3GxAfkeE/AaFA0ffq+rdmMiwArDFzk
    5Q0Ml8HaYnWUtaao8DqU0erb6+e6H9K9jGz0MviIfTo1Bq6Lx7XZ5H/YHc1ouKBH
    arcCGsHj6FTELb4IAbdnyDkPbiUN/wY55pnUC1FzGDGldSkwX1ys+IONcwJiQlXk
    TP8zaQ+kNdwcjJVqO4Z9a2+JlwnVVe/0jysDQr7H4jJaQcTa8mA+VFqNVX37nrYx
    gQIDAQAB
    -----END PUBLIC KEY-----
    [root@arm64v8 ~]#
    
    [root@arm64v8 ~]# openssl rsa -in pri_key.pem -pubout
    writing RSA key
    -----BEGIN PUBLIC KEY-----
    MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq1gOjgloyd2yAK99JcbI
    m6QXwZlBM+Fe+YrnZdZLYi/WF+6mDV8qX85Hy9Z+Vr0h7wLS5UYt32HHekljGRDP
    CWz2L6Z8VKtnSZPXr+d4XGYfGG0zGK14wZ3GxAfkeE/AaFA0ffq+rdmMiwArDFzk
    5Q0Ml8HaYnWUtaao8DqU0erb6+e6H9K9jGz0MviIfTo1Bq6Lx7XZ5H/YHc1ouKBH
    arcCGsHj6FTELb4IAbdnyDkPbiUN/wY55pnUC1FzGDGldSkwX1ys+IONcwJiQlXk
    TP8zaQ+kNdwcjJVqO4Z9a2+JlwnVVe/0jysDQr7H4jJaQcTa8mA+VFqNVX37nrYx
    gQIDAQAB
    -----END PUBLIC KEY-----
    [root@arm64v8 ~]#
  4. 指定证书请求文件中的签名算法。

    注意到证书请求文件的头部分有一项是 "Signature Algorithm",它表示使用的是哪种数字签名算法。默认使用的是 sha1,还支持 md5、sha512 等,更多可支持的签名算法见 "openssl dgst --help" 中所列出内容。例如此处指定 md5 算法。

    [root@arm64v8 ~]# openssl req -new -key pri_key.pem -out Brinnatt1.csr -md5
    [root@arm64v8 ~]# openssl req -in Brinnatt1.csr -noout -text | grep Algo
               Public Key Algorithm: rsaEncryption
       Signature Algorithm: md5WithRSAEncryption
    [root@arm64v8 ~]#
  5. 验证请求文件的数字签名,这样可以验证出证书请求文件是否被篡改过。下面的命令中 "-verify" 选项表示验证证书请求文件的数字签名。

    [root@arm64v8 ~]# openssl req -verify -in Brinnatt.csr
    verify OK
    -----BEGIN CERTIFICATE REQUEST-----
    MIICxjCCAa4CAQAwgYAxCzAJBgNVBAYTAkNOMQswCQYDVQQIDAJITjELMAkGA1UE
    BwwCQ1MxEjAQBgNVBAoMCUdyZWF0d2FsbDENMAsGA1UECwwEVGVjaDERMA8GA1UE
    AwwIQnJpbm5hdHQxITAfBgkqhkiG9w0BCQEWEkJyaW5uYXR0QGdtYWlsLmNvbTCC
    ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKtYDo4JaMndsgCvfSXGyJuk
    F8GZQTPhXvmK52XWS2Iv1hfupg1fKl/OR8vWfla9Ie8C0uVGLd9hx3pJYxkQzwls
    9i+mfFSrZ0mT16/neFxmHxhtMxiteMGdxsQH5HhPwGhQNH36vq3ZjIsAKwxc5OUN
    DJfB2mJ1lLWmqPA6lNHq2+vnuh/SvYxs9DL4iH06NQaui8e12eR/2B3NaLigR2q3
    AhrB4+hUxC2+CAG3Z8g5D24lDf8GOeaZ1AtRcxgxpXUpMF9crPiDjXMCYkJV5Ez/
    M2kPpDXcHIyVajuGfWtviZcJ1VXv9I8rA0K+x+IyWkHE2vJgPlRajVV9+562MYEC
    AwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQCOvHJJOwe64WFURRElH9+YqJQwscJv
    4SMi/JD/RAX8yrlUCwudiFNqYDsLyj5CdFt6mwhut4hbF9h1Maigo9M4cIU2T75K
    YzKhN4KqvRc2EbCFrAK9HjBqwPyfnHo5Fu1oWp6Ns4Z+eZT3wVa7UvpOc9MpnZ7Z
    /GcpO/O1TsC0KgtwzYqPSX5Ba2tjAZ561/bZkvuXTCCYmiDtstK9//JowQo1M+Aj
    wpZEJGUKMwbW8N46+f4e157g0uduqZVIxEod0VF2N7IZARmmnbU0y1CCP8sP5R7P
    3An4ccLw73VljCJWn9+7QrYnGNQnUGo3kQcAb+aXUqDvCifFJtGE7uBu
    -----END CERTIFICATE REQUEST-----
    [root@arm64v8 ~]#
    • 结果中第一行的 "verify OK" 表示证书请求文件是完整未被篡改过的,但同时输出了证书请求的内容。如果不想输出这部分内容,使用 "-noout" 选项即可。
  6. 自签署证书,可用于自建根 CA 时

    使用 openssl req 自签署证书时,需要使用 "-x509" 选项,由于是签署证书请求文件,所以可以指定 "-days" 指定所颁发的证书有效期。

    [root@arm64v8 ~]# openssl req -x509 -key pri_key.pem -in Brinnatt.csr -out CA.crt -days 365
    [root@arm64v8 ~]# cat CA.crt 
    -----BEGIN CERTIFICATE-----
    MIID1TCCAr2gAwIBAgIJAJXokBZ6BEoIMA0GCSqGSIb3DQEBCwUAMIGAMQswCQYD
    VQQGEwJDTjELMAkGA1UECAwCSE4xCzAJBgNVBAcMAkNTMRIwEAYDVQQKDAlHcmVh
    dHdhbGwxDTALBgNVBAsMBFRlY2gxETAPBgNVBAMMCEJyaW5uYXR0MSEwHwYJKoZI
    hvcNAQkBFhJCcmlubmF0dEBnbWFpbC5jb20wHhcNMjExMjE4MjAyNDU0WhcNMjIx
    MjE4MjAyNDU0WjCBgDELMAkGA1UEBhMCQ04xCzAJBgNVBAgMAkhOMQswCQYDVQQH
    DAJDUzESMBAGA1UECgwJR3JlYXR3YWxsMQ0wCwYDVQQLDARUZWNoMREwDwYDVQQD
    DAhCcmlubmF0dDEhMB8GCSqGSIb3DQEJARYSQnJpbm5hdHRAZ21haWwuY29tMIIB
    IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq1gOjgloyd2yAK99JcbIm6QX
    wZlBM+Fe+YrnZdZLYi/WF+6mDV8qX85Hy9Z+Vr0h7wLS5UYt32HHekljGRDPCWz2
    L6Z8VKtnSZPXr+d4XGYfGG0zGK14wZ3GxAfkeE/AaFA0ffq+rdmMiwArDFzk5Q0M
    l8HaYnWUtaao8DqU0erb6+e6H9K9jGz0MviIfTo1Bq6Lx7XZ5H/YHc1ouKBHarcC
    GsHj6FTELb4IAbdnyDkPbiUN/wY55pnUC1FzGDGldSkwX1ys+IONcwJiQlXkTP8z
    aQ+kNdwcjJVqO4Z9a2+JlwnVVe/0jysDQr7H4jJaQcTa8mA+VFqNVX37nrYxgQID
    AQABo1AwTjAdBgNVHQ4EFgQUWNNsDekmOc5lluWSE5BONGaTY/MwHwYDVR0jBBgw
    FoAUWNNsDekmOc5lluWSE5BONGaTY/MwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B
    AQsFAAOCAQEAidF45i1x9ej9D6HhGnOfsqV6U6yJMmTx+hkoji089pBQJy/pZO9Y
    6xzSx4m1IPS9nKH1KZRtk773r1RoS7tm1A0C8Q7OZCYqN/fUI4MNzkw+IXEyLZnX
    tf0ZAuk5XswQGhR3/bNijRAwRYnY8D7Y9TZGFiLZGs1/qN9LVbp+zlN8NYhYRQv1
    JXb/9R/QpPK/qLL3k1Uv63/IfDKGx2SlYCEr9pv8R9fy+fbKVkl/o6yTB0kZXtSP
    ePlN0trt5xp4kJN3ORHkdr9reIEP2VKU7DlIWofVSiJnqJpz8sHgiuYCvrSxEaBq
    YYkkdAebWnbisXLs8Yj6Vpe0kpINbPbhtg==
    -----END CERTIFICATE-----
    [root@arm64v8 ~]#
    • 由于 openssl req 命令的主要功能是创建和管理证书请求文件,所以没有提供对证书文件的管理能力,暂时也就只能通过 cat 来查看证书文件 CA.crt 了。

    • 实际上,"-x509" 选项和 "-new" 或 "-newkey" 配合使用时,可以不指定证书请求文件,它在自签署过程中将在内存中自动创建证书请求文件,当然,既然要创建证书请求文件,就需要人为输入申请者的信息了。例如:

      [root@arm64v8 ~]# openssl req -new -x509 -key pri_key.pem -out CAtest.crt -days 365 -subj /C=CN/ST=HN/L=CS/O=Greatwall/OU=Tech/CN=Brinnatt/emailAddress=Brinnatt@gmail.com
      [root@arm64v8 ~]# ls CAtest.crt 
      CAtest.crt
      [root@arm64v8 ~]#
      • 使用 "-x509" 选项后,"-new" 或 "-newkey" 将表示创建一个证书文件而不是一个证书请求文件。
      • 使用 "-subj" 选项一次性指定申请者信息更加方便。
  7. 让 openssl req 自动创建所需的私钥文件。

    在前面的所有例子中,在需要私钥的时候都明确使用了 "-key" 选项提供私钥。其实如果不提供,openssl req会在任何需要私钥的地方自动创建私钥,并保存在特定的位置,默认的保存位置为当前目录,文件名为privkey.pem,具体保存的位置和文件名由配置文件(默认为 /etc/pki/tls/openssl.cnf)决定,此处不讨论该文件。当然,openssl req 命令的 "-keyout" 选项可以指定私钥保存位置。

    [root@arm64v8 ~]# openssl req -new -out req.csr -subj /C=CN/ST=HN/L=CS/O=Greatwall/OU=Tech/CN=Brinnatt/emailAddress=Brinnatt@gmail.com
    Generating a 2048 bit RSA private key        # 自动创建私钥
    .........................................................................+++
    ............+++
    writing new private key to 'privkey.pem'
    Enter PEM pass phrase:                       # 要求输入加密私钥文件的密码,且要求长度为4-1024个字符
    Verifying - Enter PEM pass phrase:
    -----
    [root@arm64v8 ~]# ls
    privkey.pem  req.csr
    [root@arm64v8 ~]#
    • openssl req 在自动创建私钥时,将总是加密该私钥文件,并提示输入加密的密码。可以使用 "-nodes" 选项禁止加密私钥文件。

    • 指定自动创建私钥时,私钥文件的保存位置和文件名。使用 "-keyout" 选项。

      [root@arm64v8 ~]# openssl req -new -out req.csr -subj /C=CN/ST=HN/L=CS/O=Greatwall/OU=Tech/CN=Brinnatt/emailAddress=Brinnatt@gmail.com -nodes -keyout Brinnatt.key
      Generating a 2048 bit RSA private key
      .................+++
      ....................+++
      writing new private key to 'Brinnatt.key'
      -----
      [root@arm64v8 ~]# ls
      Brinnatt.key  req.csr
      [root@arm64v8 ~]#
  8. 使用 "-newkey" 选项。

    "-newkey" 选项和 "-new" 选项类似,只不过 "-newkey" 选项可以直接指定私钥的算法和长度,所以它主要用在 openssl req 自动创建私钥时。

    它的使用格式为 "-newkey arg",其中 arg 的格式为 "rsa:numbits",rsa 表示创建 rsa 私钥,numbits 表示私钥的长度,如果不给定长度(即 "-newkey rsa")则默认从配置文件中读取长度值。其实不止支持 rsa 私钥,只不过现在基本都是用 rsa 私钥,所以默认就使用 rsa。

    [root@arm64v8 ~]# openssl req -newkey rsa:2048 -out test.csr -nodes -keyout test.key -subj /C=CN/ST=HN/L=CS/O=Greatwall/OU=Tech/CN=Brinnatt/emailAddress=Brinnatt@gmail.com
    Generating a 2048 bit RSA private key
    ................................................................+++
    .........................................+++
    writing new private key to 'test.key'
    -----
    [root@arm64v8 ~]# ls
    test.csr  test.key
    [root@arm64v8 ~]#

C8.11、openssl 配置文件

/etc/pki/tls/openssl.cnf 该文件主要设置了证书请求、签名、crl 相关的配置。主要相关的伪命令为 ca 和 req。对于 x509 不用该配置文件。

该文件从功能结构上分为 4 个段落:默认段、ca 相关的段、req 相关的段、tsa 相关的段。每个段中都以 name=value 的格式定义。

该文件中没有被引用的段被视为忽略段,不会起到任何作用。每个段中可以书写哪些 name 以及它们的意义,可以 man 相关命令,如 man ca 可以查看 ca 相关段可以书写的 name,man req 可以查看 req 相关段可以书写的 name。

默认段

第一段是默认段,一般没有 section_name,但不是一定没有,可以自定义有名称的。

默认段中定义的是一些公共属性,当搜索一个给定名称的段时,将首先搜索有名称的段,当搜索不到匹配的段后会搜索默认段。

以下是默认段的内容。

HOME = .

RANDFILE = $ENV::HOME/.rnd

oid_section = new_oids
  • 仅定义了当前目录变量,以及随机数的文件路径变量。

  • 至于最后一行的 oid_section=new_oids 表示指向 [new_oids] 段。以下为 new_oids 段。

    [ new_oids ]
    
    tsa_policy1 = 1.2.3.4.1
    
    tsa_policy2 = 1.2.3.4.5.6
    
    tsa_policy3 = 1.2.3.4.5.7

ca 相关段

这些段定义 ca 相关的控制选项。以下为 ca 相关段内容。

####################################################################
[ ca ]
default_ca  = CA_default        /*The default ca section*/
####################################################################
[ CA_default ]

dir     = /etc/pki/CA                   /* Where everything is kept */
                                        /*  #### 这是第一个openssl目录结构中的目录 */
certs       = $dir/certs                /* Where the issued certs are kept(已颁发的证书路径,即CA或自签的) */
                                        /* #### 这是第二个openssl目录结构中的目录,但非必须 */
crl_dir     = $dir/crl                  /* Where the issued crl are kept(已颁发的crl存放目录) */
                                        /*  #### 这是第三个openssl目录结构中的目录*/
database    = $dir/index.txt            /* database index file */
#unique_subject = no                    /* 设置为yes则database文件中的subject列不能出现重复值 */
                                        /* 即不能为subject相同的证书或证书请求签名*/
                                        /* 建议设置为no,但为了保持老版本的兼容性默认是yes */
new_certs_dir = $dir/newcerts           /* default place for new certs(将来颁发的证书存放路径) */
                                        /* #### 这是第四个openssl目录结构中的目录 */
certificate = $dir/cacert.pem           /* The A certificate(CA自己的证书文件) */
serial      = $dir/serial               /* The current serial number(提供序列号的文件)*/
crlnumber   = $dir/crlnumber            /* the current crl number(当前crl序列号) */
crl     = $dir/crl.pem                  /* The current CRL(当前CRL) */
private_key = $dir/private/cakey.pem    /* The private key(签名时需要的私钥,即CA自己的私钥) */
RANDFILE    = $dir/private/.rand        /* private random number file(提供随机数种子的文件) */
x509_extensions = usr_cert              /* The extentions to add to the cert(添加到证书中的扩展项) */

/* 以下两行是关于证书展示格式的,虽非必须项,但推荐设置。一般就如下格式不用修改 */
name_opt    = ca_default                /* Subject Name options*/
cert_opt    = ca_default                /* Certificate field options */

/* 以下是copy_extensions扩展项,需谨慎使用 */
# copy_extensions = copy                /* 生成证书时扩展项的copy行为,可设置为none/copy/copyall */
                                        /* 不设置该name时默认为none */
                                        /* 建议简单使用时设置为none或不设置,且强烈建议不要设置为copyall */
# crl_extensions    = crl_ext
default_days    = 365                   /* how long to certify for(默认的证书有效期) */
default_crl_days= 30                    /* how long before next CRL(CRL的有效期) */
default_md  = default                   /* use public key default MD(默认摘要算法) */
preserve    = no                        /* keep passed DN ordering(Distinguished Name顺序,一般设置为no */
                                        /* 设置为yes仅为了和老版本的IE兼容)*/
policy      = policy_match              /* 证书匹配策略,此处表示引用[ policy_match ]的策略 */

/* 证书匹配策略定义了证书请求的DN字段(field)被CA签署时和CA证书的匹配规则 */
/* 对于CA证书请求,这些匹配规则必须要和父CA完全相同 */
[ policy_match ]
countryName = match                     /* match表示请求中填写的该字段信息要和CA证书中的匹配 */
stateOrProvinceName = match
organizationName    = match
organizationalUnitName  = optional      /* optional表示该字段信息可提供可不提供 */
commonName      = supplied              /* 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 

/* 以下是添加的扩展项usr_cert的内容 */
[ usr_cert ]
basicConstraints=CA:FALSE                       /* 基本约束,CA:FALSE表示该证书不能作为CA证书,即不能给其他人颁发证书 */
/* keyUsage = critical,keyCertSign,cRLSign */   /* 指定证书的目的,也就是限制证书的用法 */

/* 除了上面两个扩展项可能会修改下,其余的扩展项别管了,如下面的 */
nsComment  = "OpenSSL Generated Certificate" 
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer

req 相关段

[ req ]
default_bits    = 2048          /* 生成证书请求时用到的私钥的密钥长度 */
default_md      = sha1          /* 证书请求签名时的单向加密算法 */
default_keyfile = privkey.pem   /* 默认新创建的私钥存放位置, */
                                /* 如-new选项没指定-key时会自动创建私钥 */
                                /* -newkey选项也会自动创建私钥 */
distinguished_name  = req_distinguished_name    /* 可识别的字段名(常被简称为DN) */
                                                /* 引用req_distinguished_name段的设置 */
x509_extensions = v3_ca         /* 加入到自签证书中的扩展项 */
# req_extensions = v3_req       /* 加入到证书请求中的扩展项 */
attributes  = req_attributes    /* 证书请求的属性,引用req_attributes段的设置,可以不设置它 */

# encrypt_key = yes | no        /* 自动生成的私钥文件要加密否?一般设置no,和-nodes选项等价 */
/* 输入和输出私钥文件的密码,如果该私钥文件有密码,不写该设置则会提示输入 */
/* input_password = secret */
/* output_password = secret */

# prompt = yes | no             /* 设置为no将不提示输入DN field,而是直接从配置文件中读取,需要同时设置DN默认值,否则创建证书请求时将出错。 */
string_mask = utf8only

[ req_distinguished_name ]
/* 以下项均可指定可不指定,但ca段的policy中指定为match和supplied一定要指定。 */
/* 以下选项都可以自定义,如countryName = C,commonName = CN */
countryName             = Country Name (2 letter code)      /* 国家名(C) */
countryName_default     = XX                                /* 默认的国家名 */
countryName_min         = 2                                 /* 填写的国家名的最小字符长度 */
countryName_max         = 2                                 /* 填写的国家名的最大字符长度 */
stateOrProvinceName = State or Province Name (full name)    /* 省份(S) */
/* stateOrProvinceName_default = Default Province */
localityName = Locality Name (eg, city)                     /* 城市(LT) */
localityName_default = Default City
0.organizationName  = Organization Name (eg, company)       /* 公司(ON) */
0.organizationName_default = Default Company Ltd
organizationalUnitName = Organizational Unit Name (eg, section)     /* 部门(OU) */
/* organizationalUnitName_default = */
/* 以下的commonName(CN)一般必须给,如果作为CA,那么需要在ca的policy中定义CN = supplied */
/* CN定义的是将要申请SSL证书的域名或子域名或主机名。 */
/* 例如要为zhonghua.com申请ssl证书则填写zhonghua.com,而不能填写www.zhonghua.com */
/* 要为www.zhonghua.com申请SSL则填写www.zhonghua.com */
/* CN必须和将要访问的网站地址一样,否则访问时就会给出警告 */
/* 该项要填写正确,否则该请求被签名后证书中的CN与实际环境中的CN不对应,将无法提供证书服务 */
commonName  = Common Name (eg, your name or your server hostname)   /* 主机名(CN) */
commonName_max  = 64
emailAddress            = Email Address     /* Email地址,很多时候不需要该项的 */
emailAddress_max        = 64

[ req_attributes ] /* 该段是为了某些特定软件的运行需要而设定的, */
                   /* 现在一般都不需要提供challengepassword */
                   /* 所以该段几乎用不上 */
                   /* 所以不用管这段 */
challengePassword       = A challenge password
challengePassword_min   = 4
challengePassword_max   = 20
unstructuredName        = An optional company name
[ v3_req ]
/* Extensions to add to a certificate request */
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
[ v3_ca ]
/* Extensions for a typical CA */
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer
basicConstraints = CA:true
# keyUsage = cRLSign, keyCertSign  /* 典型的CA证书的使用方法设置,由于测试使用所以注释了 */
/* 如果真的需要申请为CA/*么该设置可以如此配置 */
  • 可以自定义 DN(Distinguished Name)段中的字段信息,注意 ca 段中的 policy 指定的匹配规则中如果指定了 match 或 supplied 的则 DN 中必须定义。

  • 例如下面的示例:由于只有 countryName、organizationName 和 commonName 被设定为 match 和 supplied,其余的都是 optional,所以在 DN 中可以只定义这 3 个字段,而且在 DN 中定义了自定义的名称。

    [policy_to_match]
    countryName = match
    stateOrProvinceName = optional
    organizationName = match
    organizationalUnitName = optional
    commonName = supplied
    emailAddress = optional
    [DN]
    countryName = "C"
    organizationName = "O"
    commonName = "Root CA"

C8.12、openssl ca(签署和自建 CA)

openssl ca  [-verbose] [-config filename] [-name section] [-gencrl] [-revoke file]
            [-status serial] [-updatedb] [-crl_reason reason] [-crl_hold instruction]
            [-crl_compromise time] [-crl_CA_compromise time] [-crldays days] [-crlhours hours]
            [-crlexts section] [-startdate date] [-enddate date] [-days arg] [-md arg]
            [-policy arg] [-keyfile arg] [-keyform PEM|DER] [-key arg] [-passin arg]
            [-cert file] [-selfsign] [-in file] [-out file] [-notext] [-outdir dir]
            [-infiles] [-spkac file] [-ss_cert file] [-preserveDN] [-noemailDN] [-batch]
            [-msie_hack] [-extensions section] [-extfile section] [-engine id] [-subj arg]
            [-utf8] [-multivalue-rdn]

【选项说明:】
-config filename    :指定要使用的配置文件,指定后将忽略openssl.cnf中指定的关于ca的配置选项。
-name section       :指定使用配置文件中的那个section。指定后将忽略openssl.cnf中的default_ca段。
-in filename        :指定要被CA签署的单个证书请求文件。根CA为其他证书签署时使用。
-infiles            :该选项只能是最后一个选项,该选项所接的所有参数都被认为是要被签署的证书请求文件,即一次性签署多个请求文件时使用的选项。
-selfsign           :自签署。指定-ss_cert选项时该选项被忽略。
-ss_cert filename   :将被CA自签署的单个证书文件。也就是说要重新签署证书。
-out filename       :证书的输出文件,同时也会输出到屏幕。不指定时默认输出到stdout。
-outdir dir_name    :证书的输出目录。指定该选项时,将自动在此目录下生成一个文件名包含16进制serial值的".pem"证书文件。
-cert               :CA自己的证书文件。
-keyfile filename   :指定签署证书请求时的私钥文件,即CA自己的私钥文件。
-key passwd_value   :指定私钥的加密密码。
-passin arg         :传递解密密码
-verbose            :打印操作执行时的详细信息
-notext             :禁止以文本格式将证书输出到"-out"指定的文件中
-days arg           :证书有效期限,从创建时刻开始算startdate,有效期结束点为enddate。
-startdate          :自定义证书的开始时间,和"-enddate"一起使用可以推算出证书有效期。
-enddate            :自定义证书的结束时间。
-md alg             :指定单向加密算法
-policy arg         :该选项是配置文件中的section内容,该选项指定了证书信息中的field部分是否需要强制提供还是要强制匹配,
                    :或者可提供可不提供。详细的见配置文件说明。
-extensions section :指定当前创建的证书使用配置文件中的哪个section作为扩展属性。
-batch              :签署时使用批处理模式,即非交互模式。该模式下不会有两次询问(是否签署、是否提交)。
-subj arg           :替换证书请求中的subject,格式/type0=value0/type1=value1/type2=...
  • ca 命令是用于签署证书的,所以它所需要的文件除了配置文件外就是私钥文件和证书请求文件,而签名后生成的文件是证书文件,因此使用 "-in" 指定的对象是待签署文件,"-infiles" 则是指定多个待签署文件,"-keyfile" 是指定私钥文件,"-out" 是指定输出的证书文件。

配置文件关于 ca 的部分,其中被标记为必须项的表示配置文件中或者命令行中必须给出该选项及其值。

new_certs_dir       :等同于"-outdir"选项。必须项
certificat          :等同于"-cert"选项,CA自己的证书文件。必须项
private_key         :等同于"-keyfile"选项,签署证书请求文件时的私钥文件,即CA自己的私钥文件。必须项
default_days        :等同于"-days"选项
default_startdate   :等同于"-startdate"选项。
default_enddate     :等同于"-enddate"选项。
default_md          :等同于"-md"选项。必须项
database            :openssl维护的数据库文件。存放证书条目信息及状态信息。必须项
serial              :已颁发证书的序列号(16进制)文件。必须项且该文件中必须存在一个序列值
unique_subject      :如果设置为yes,database中的subject列值必须不重复。如果设置为no,允许subject重复。默认是yes,
                    :这是为了兼容老版本的Openssl,推荐设置为no。
x509_extensions     :等同于"-extensions"选项。
policy              :等同于"-policy"选项。必须项
name_opt/cert_opt   :证书的展示格式,虽非必须但建议设置为ca_default,若不设置将默认使用老版本的证书格式(不建议如此)。
                    :伪命令ca无法直接设置这两个选项,而伪命令x509的"-nameopt"和"-certopt"选项可以分别设置。
copy_extensions     :决定证书请求中的扩展项如何处理的。如果设置为none或不写该选项,则扩展项被忽略并且不复制到证书中去。
                    :如果设置为copy,则证书请求中已存在而证书中不存在的扩展项将复制到证书中。
                    :如果设置为copyall,则证书请求中所有的扩展项都复制到证书中,此时若证书中已存在某扩展项,则先删除再复制。
                    :该选项的主要作用是允许证书请求为特定的扩展项如subjectAltName提供值。
                    :使用该选项前请先查看man ca中的WARNINGS部分。建议一般简单使用时设置为none或不设置。

用于签署证书请求、生成吊销列表 CRL 以及维护已颁发证书列表和这些证书状态的数据库。因为一般人无需管理 crl,所以本文只介绍 openssl ca 关于证书管理方面的功能。

证书请求文件使用 CA 的私钥签署之后就是证书,签署之后将证书发给申请者就是颁发证书。在签署时,为了保证证书的完整性和一致性,还应该对签署的证书生成数字摘要,即使用单向加密算法。

由于 openssl ca 命令对配置文件(默认为 /etc/pki/tls/openssl.cnf)的依赖性非常强,上一小节提前分析过,对照思考。

在配置文件中指定了签署证书时所需文件的结构,默认 openssl.cnf 中的结构要求如下:

[ CA_default ]
dir             = /etc/pki/CA             # 定义路径变量
certs           = $dir/certs              # 已颁发证书的保存目录
database        = $dir/index.txt          # 数据库索引文件
new_certs_dir   = $dir/newcerts           # 新签署的证书保存目录
certificate     = $dir/cacert.pem         # CA证书路径名
serial          = $dir/serial             # 当前证书序列号
private_key     = $dir/private/cakey.pem  # CA的私钥路径名
  • 其中目录 /etc/pki/CA/{certs,newcerts,private} 在安装 openssl 后就默认存在,所以无需独立创建,但证书的 database 文件 index.txt 和序列文件 serial 必须创建好,且序列号文件中得先给定一个序号,如 "01"。

    [root@arm64v8 ~]# touch /etc/pki/CA/index.txt 
    [root@arm64v8 ~]# echo "01" > /etc/pki/CA/serial
  • 另外,要签署证书请求,需要 CA 自己的私钥文件以及 CA 自己的证书,先创建好 CA 的私钥,存放位置为配置文件中 private_key 所指定的值,默认为 /etc/pki/CA/private/cakey.pem。

    [root@arm64v8 ~]# openssl genrsa -out /etc/pki/CA/private/cakey.pem
    Generating RSA private key, 2048 bit long modulus
    ........................................................................+++
    .......................................+++
    e is 65537 (0x10001)
    [root@arm64v8 ~]#
  1. 使用 openssl ca 自建 CA

    要提供 CA 自己的证书,测试环境下 CA 只能自签署,使用 openssl req -x509openssl x509openssl ca 都可以自签署证书请求文件,此处仅介绍 openssl ca 命令自身自签署的方法。

    先创建 CA 的证书请求文件,建议使用 CA 的私钥文件 /etc/pki/CA/private/cakey.pem 来创建待自签署的证书请求文件,虽非必须,但方便管理。创建请求文件时,其中 Country Name、State or Province Name、Organization Name 和 Common Name 默认是必须提供的。

    [root@arm64v8 ~]# openssl req -new -key /etc/pki/CA/private/cakey.pem -out rootCA.csr
    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) [XX]:CN
    State or Province Name (full name) []:HN
    Locality Name (eg, city) [Default City]:CS
    Organization Name (eg, company) [Default Company Ltd]:Greatwall
    Organizational Unit Name (eg, section) []:Tech
    Common Name (eg, your name or your server's hostname) []:brinnatt.com
    Email Address []:Brinnatt@gmail.com
    
    Please enter the following 'extra' attributes
    to be sent with your certificate request
    A challenge password []:
    An optional company name []:
    [root@arm64v8 ~]#

    然后使用 openssl ca 命令自签署该证书请求文件。如果有两次交互式询问则表示自签署将成功,如果失败,则考虑数据库文件 index.txt 是否创建、序列号文件 serial 是否存在且有序号值、私钥文件 cakey.pem 是否路径正确、创建证书请求文件时是否该提供的信息没有提供等情况。

    [root@arm64v8 ~]# openssl ca -selfsign -in rootCA.csr 
    Using configuration from /etc/pki/tls/openssl.cnf        # 默认采用/etc/pki/tls/openssl.cnf作为配置文件
    Check that the request matches the signature         # 验证证书请求文件的数字签名,确保该证书请求文件是完整未修改过的
    Signature ok
    Certificate Details:                                 # 待生成证书的信息
           Serial Number: 1 (0x1)                           # 序列号为1
           Validity
               Not Before: Dec 19 18:32:57 2021 GMT     # 证书有效期起始日为2021-12-19 18:32:57
               Not After : Dec 19 18:32:57 2022 GMT     # 证书有效期终止日为2022-12-19 18:32:57
           Subject:                                     # Subject信息,subject是非常重要的信息
               countryName               = CN
               stateOrProvinceName       = HN
               organizationName          = Greatwall
               organizationalUnitName    = Tech
               commonName                = brinnatt.com
               emailAddress              = Brinnatt@gmail.com
           X509v3 extensions:
               X509v3 Basic Constraints: 
                   CA:FALSE
               Netscape Comment: 
                   OpenSSL Generated Certificate
               X509v3 Subject Key Identifier: 
                   E4:85:FD:FB:5C:E3:E9:08:8F:43:E3:0E:BD:02:32:58:A8:28:9E:FB
               X509v3 Authority Key Identifier: 
                   keyid:E4:85:FD:FB:5C:E3:E9:08:8F:43:E3:0E:BD:02:32:58:A8:28:9E:FB
    
    Certificate is to be certified until Dec 19 18:32:57 2022 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        # 向数据库文件添加一条该证书的记录
    Certificate:                             # 该证书的信息
       Data:
           Version: 3 (0x2)
           Serial Number: 1 (0x1)
       Signature Algorithm: sha256WithRSAEncryption
           Issuer: C=CN, ST=HN, O=Greatwall, OU=Tech, CN=brinnatt.com/emailAddress=Brinnatt@gmail.com
           Validity
               Not Before: Dec 19 18:32:57 2021 GMT
               Not After : Dec 19 18:32:57 2022 GMT
           Subject: C=CN, ST=HN, O=Greatwall, OU=Tech, CN=brinnatt.com/emailAddress=Brinnatt@gmail.com
           Subject Public Key Info:
               Public Key Algorithm: rsaEncryption
                   Public-Key: (2048 bit)
                   Modulus:
                       00:cd:78:29:94:4e:97:df:73:b6:c8:2a:a2:b2:da:
                       d4:e4:e5:46:80:15:b2:bc:55:17:43:7d:16:be:1c:
                       ae:a1:d5:64:50:f4:eb:77:8a:c7:7f:f3:ba:1b:91:
                       94:81:61:3b:24:a2:c5:4f:95:7a:53:36:9e:b2:73:
                       11:7c:ed:e6:df:9a:e3:1e:2a:27:a1:d1:91:1a:ca:
                       3b:33:4c:a1:67:0c:a9:2a:11:f3:92:16:a8:e4:26:
                       80:d9:33:25:07:c2:2a:1e:1c:01:ad:f3:84:b0:14:
                       65:f0:7a:1d:17:8e:49:f0:d9:78:47:a3:3f:10:19:
                       f0:0b:d9:f7:30:f5:90:41:a4:b3:2e:ee:da:a4:85:
                       bd:e0:ac:98:99:1b:06:ba:b4:7f:30:b5:ef:2d:4d:
                       91:b0:65:00:ff:5b:26:fd:17:8b:37:d1:94:42:03:
                       13:56:9f:2f:9e:a6:5f:9e:34:f0:94:ca:2e:6d:06:
                       17:67:cf:58:0d:0a:ee:0a:b5:be:c5:9c:78:c3:ef:
                       d1:77:bc:fa:50:84:8b:94:db:91:d3:59:fb:cd:1d:
                       e1:ff:52:57:c6:11:c3:15:41:bb:54:a8:2f:8e:b2:
                       2a:ed:13:44:7a:27:fd:85:7d:23:d3:3f:41:25:63:
                       f9:4a:bc:60:49:5d:6b:31:be:92:e8:da:c2:99:76:
                       1c:35
                   Exponent: 65537 (0x10001)
           X509v3 extensions:
               X509v3 Basic Constraints: 
                   CA:FALSE
               Netscape Comment: 
                   OpenSSL Generated Certificate
               X509v3 Subject Key Identifier: 
                   E4:85:FD:FB:5C:E3:E9:08:8F:43:E3:0E:BD:02:32:58:A8:28:9E:FB
               X509v3 Authority Key Identifier: 
                   keyid:E4:85:FD:FB:5C:E3:E9:08:8F:43:E3:0E:BD:02:32:58:A8:28:9E:FB
    
       Signature Algorithm: sha256WithRSAEncryption
            5c:33:b7:f6:33:8a:c7:2f:df:c9:2d:90:24:ce:ca:2c:7e:31:
            5f:91:88:38:6c:c0:75:e8:c0:02:88:56:7b:94:19:42:60:b6:
            d4:b5:14:09:ba:c3:3a:86:df:1a:f6:bd:64:a4:b5:ee:18:b2:
            0d:ca:88:05:5d:41:3a:1c:04:4e:93:b5:c3:b8:d0:50:50:77:
            be:92:e1:91:3f:b1:38:1d:dd:b3:8a:87:8e:b1:fd:98:22:3b:
            a3:b0:9c:1c:97:ce:59:76:a4:5e:15:7f:bf:42:b0:2a:ed:98:
            d1:4b:de:f6:6c:42:5c:52:37:dc:54:7b:cc:41:eb:64:b9:e6:
            5d:1f:d8:95:42:c3:5f:44:d6:3f:e2:86:03:c3:87:85:94:d1:
            65:9e:53:b0:59:cc:a2:f5:6a:3e:3f:96:ae:9a:b5:57:23:75:
            2e:b7:88:6b:84:ac:c2:b6:44:94:60:ed:6b:92:56:e5:de:c9:
            74:46:55:d9:01:fb:71:b0:c0:49:b6:3c:08:1f:3d:42:8d:e9:
            45:03:e8:f8:4f:c3:25:70:15:d5:70:1a:32:aa:ca:f4:f6:a3:
            73:74:5e:9c:74:cd:59:d9:c9:6a:13:7c:ae:3d:04:0e:40:f8:
            c0:e6:a8:4f:41:09:aa:0f:c5:f0:2e:1a:05:bb:99:bd:5c:ec:
            91:78:20:8b
    -----BEGIN CERTIFICATE-----
    MIID5DCCAsygAwIBAgIBATANBgkqhkiG9w0BAQsFADB3MQswCQYDVQQGEwJDTjEL
    MAkGA1UECAwCSE4xEjAQBgNVBAoMCUdyZWF0d2FsbDENMAsGA1UECwwEVGVjaDEV
    MBMGA1UEAwwMYnJpbm5hdHQuY29tMSEwHwYJKoZIhvcNAQkBFhJCcmlubmF0dEBn
    bWFpbC5jb20wHhcNMjExMjE5MTgzMjU3WhcNMjIxMjE5MTgzMjU3WjB3MQswCQYD
    VQQGEwJDTjELMAkGA1UECAwCSE4xEjAQBgNVBAoMCUdyZWF0d2FsbDENMAsGA1UE
    CwwEVGVjaDEVMBMGA1UEAwwMYnJpbm5hdHQuY29tMSEwHwYJKoZIhvcNAQkBFhJC
    cmlubmF0dEBnbWFpbC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
    AQDNeCmUTpffc7bIKqKy2tTk5UaAFbK8VRdDfRa+HK6h1WRQ9Ot3isd/87obkZSB
    YTskosVPlXpTNp6ycxF87ebfmuMeKieh0ZEayjszTKFnDKkqEfOSFqjkJoDZMyUH
    wioeHAGt84SwFGXweh0Xjknw2XhHoz8QGfAL2fcw9ZBBpLMu7tqkhb3grJiZGwa6
    tH8wte8tTZGwZQD/Wyb9F4s30ZRCAxNWny+epl+eNPCUyi5tBhdnz1gNCu4Ktb7F
    nHjD79F3vPpQhIuU25HTWfvNHeH/UlfGEcMVQbtUqC+OsirtE0R6J/2FfSPTP0El
    Y/lKvGBJXWsxvpLo2sKZdhw1AgMBAAGjezB5MAkGA1UdEwQCMAAwLAYJYIZIAYb4
    QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBTk
    hf37XOPpCI9D4w69AjJYqCie+zAfBgNVHSMEGDAWgBTkhf37XOPpCI9D4w69AjJY
    qCie+zANBgkqhkiG9w0BAQsFAAOCAQEAXDO39jOKxy/fyS2QJM7KLH4xX5GIOGzA
    dejAAohWe5QZQmC21LUUCbrDOobfGva9ZKS17hiyDcqIBV1BOhwETpO1w7jQUFB3
    vpLhkT+xOB3ds4qHjrH9mCI7o7CcHJfOWXakXhV/v0KwKu2Y0Uve9mxCXFI33FR7
    zEHrZLnmXR/YlULDX0TWP+KGA8OHhZTRZZ5TsFnMovVqPj+Wrpq1VyN1LreIa4Ss
    wrZElGDta5JW5d7JdEZV2QH7cbDASbY8CB89Qo3pRQPo+E/DJXAV1XAaMqrK9Paj
    c3RenHTNWdnJahN8rj0EDkD4wOaoT0EJqg/F8C4aBbuZvVzskXggiw==
    -----END CERTIFICATE-----
    Data Base Updated
    [root@arm64v8 ~]#

    自签署成功后,在 /etc/pki/CA 目录下将生成一系列文件。

    [root@arm64v8 ~]# tree -C /etc/pki/CA
    /etc/pki/CA
    ├── certs
    ├── crl
    ├── index.txt
    ├── index.txt.attr
    ├── index.txt.old
    ├── newcerts
    │   └── 01.pem
    ├── private
    │   └── cakey.pem
    ├── serial
    └── serial.old
    
    4 directories, 7 files
    [root@arm64v8 ~]#
    • 其中 newcerts 目录下的 01.pem 即为刚才自签署的证书文件,因为它是 CA 自身的证书,所以根据配置文件中的 "certificate=$dir/cacert.pem" 项,应该将其放入 /etc/pki/CA 目录下,且命名为 cacert.pem,只有这样以后才能签署其它证书请求。

      [root@arm64v8 ~]# cp /etc/pki/CA/newcerts/01.pem /etc/pki/CA/cacert.pem
    • 至此,自建 CA 就完成了,查看下数据库索引文件和序列号文件。

      [root@arm64v8 ~]# cat /etc/pki/CA/index.txt
      V  221219183257Z       01  unknown /C=CN/ST=HN/O=Greatwall/OU=Tech/CN=brinnatt.com/emailAddress=Brinnatt@gmail.com
      [root@arm64v8 ~]# 
      [root@arm64v8 ~]# cat /etc/pki/CA/serial
      02
      [root@arm64v8 ~]#
      • 那么,下次签署证书请求时,序列号将是 "02"。

    自建 CA 过程总结如下:

    [root@aarch64 ~]# touch /etc/pki/CA/index.txt 
    [root@aarch64 ~]# echo "01" > /etc/pki/CA/serial
    [root@aarch64 ~]# openssl genrsa -out /etc/pki/CA/private/cakey.pem
    [root@aarch64 ~]# openssl req -new -key /etc/pki/CA/private/cakey.pem -out rootCA.csr
    [root@aarch64 ~]# openssl ca -selfsign -in rootCA.csr
    [root@aarch64 ~]# ls /etc/pki/CA/newcerts/01.pem 
    [root@aarch64 ~]# cp /etc/pki/CA/newcerts/01.pem /etc/pki/CA/cacert.pem
    • 以上过程是完全读取默认配置文件创建的,其实很多过程是没有那么严格的,openssl ca 命令自身可以指定很多选项覆盖配置文件中的项,但既然提供了默认的配置文件及目录结构,为了方便管理,仍然建议完全采用配置文件中的项。
  2. 为他人颁发证书。

    首先申请者创建一个证书请求文件。

    [root@aarch64 ~]# openssl req -new -keyout brinnatt.key -nodes -out brinnatt.csr
    Generating a 2048 bit RSA private key
    ..............................................................+++
    ....................................................................................................+++
    writing new private key to 'brinnatt.key'
    -----
    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) [XX]:CN
    State or Province Name (full name) []:HN
    Locality Name (eg, city) [Default City]:CS
    Organization Name (eg, company) [Default Company Ltd]:Greatwall
    Organizational Unit Name (eg, section) []:.
    Common Name (eg, your name or your server's hostname) []:brinnatt.com
    Email Address []:
    
    Please enter the following 'extra' attributes
    to be sent with your certificate request
    A challenge password []:
    An optional company name []:
    [root@aarch64 ~]#
    • 其中 Country Name、State or Province Name、Organization Name 和 Common Name 必须提供,且前三者必须和 CA 的 subject 中的对应项完全相同。这些是由配置文件中的匹配策略决定的。

      [ ca ]
      default_ca      = CA_default            # The default ca section
      [ CA_default ]
      policy          = policy_match
      [ policy_match ]
      countryName             = match
      stateOrProvinceName     = match
      organizationName        = match
      organizationalUnitName  = optional
      commonName              = supplied
      emailAddress            = optional
      • "match" 表示 openssl ca 要签署的证书请求文件中的项要和 CA 证书中的项匹配,即要相同,"supplied" 表示必须要提供的项,"optional" 表示可选项,所以可以留空。

    现在就可以将证书请求文件发送给 CA,让 CA 帮忙签署。签署成功后,查看下 /etc/pki/CA 下的文件结构。

    [root@aarch64 ~]# openssl ca -in brinnatt.csr
    [root@aarch64 ~]# tree -C /etc/pki/CA/
    /etc/pki/CA/
    ├── cacert.pem
    ├── certs
    ├── crl
    ├── index.txt
    ├── index.txt.attr
    ├── index.txt.attr.old
    ├── index.txt.old
    ├── newcerts
    │   ├── 01.pem
    │   └── 02.pem
    ├── private
    │   └── cakey.pem
    ├── serial
    └── serial.old
    
    4 directories, 10 files
    [root@aarch64 ~]#
    • 其中 "02.pem" 就是刚才签署成功的证书,将此证书发送给申请者即表示颁发完成。

    再看下数据库索引文件和序列号文件。

    [root@aarch64 ~]# cat /etc/pki/CA/index.txt
    V    221219185718Z       01  unknown /C=CN/ST=HN/O=Greatwall/OU=Tech/CN=brinnatt.com/emailAddress=Brinnatt@gmail.com
    V    221219205107Z       02  unknown /C=CN/ST=HN/O=Greatwall/CN=brinnatt.com
    [root@aarch64 ~]# 
    [root@aarch64 ~]# cat /etc/pki/CA/serial
    03
    [root@aarch64 ~]#

C8.13、openssl x509(签署和自签署)

主要用于输出证书信息,也能够签署证书请求文件、自签署、转换证书格式等。

openssl x509 工具不会使用 openssl 配置文件中的设定,而是完全需要自行设定或者使用该伪命令的默认值,它就像是一个完整的小型的 CA 工具箱

openssl x509    [-in filename] [-out filename] [-serial] [-hash] [-subject_hash]
                [-issuer_hash] [-subject] [-issuer] [-nameopt option] [-email]
                [-startdate] [-enddate] [-purpose] [-dates] [-modulus] [-pubkey]
                [-fingerprint] [-noout] [-days arg] [-set_serial n] [-signkey filename]
                [-x509toreq] [-req] [-CA filename] [-CAkey filename] [-CAcreateserial]
                [-CAserial filename] [-text] [-md2|-md5|-sha1|-mdc2] [-extfile filename]
                [-extensions section]

【输入输出选项:】
-in filename            :指定证书输入文件,若同时指定了"-req"选项,则表示输入文件为证书请求文件。
-out filename           :指定输出文件
-md2|-md5|-sha1|-mdc2   :指定单向加密的算法。

【信息输出选项:】
-text           :以text格式输出证书内容,即以最全格式输出,
                :包括public key,signature algorithms,issuer和subject names,serial number以及any trust settings.
-certopt option :自定义要输出的项
-noout          :禁止输出证书请求文件中的编码部分
-pubkey         :输出证书中的公钥
-modulus        :输出证书中公钥模块部分
-serial         :输出证书的序列号
-subject        :输出证书中的subject
-issuer         :输出证书中的issuer,即颁发者的subject
-subject_hash   :输出证书中subject的hash码
-issuer_hash    :输出证书中issuer(即颁发者的subject)的hash码
-hash           :等价于"-subject_hash",但此项是为了向后兼容才提供的选项
-email          :输出证书中的email地址,如果有email的话
-startdate      :输出证书有效期的起始日期
-enddate        :输出证书有效期的终止日期
-dates          :输出证书有效期,等价于"startdate+enddate"
-fingerprint    :输出指纹摘要信息

输出证书某些信息的时候,可以配合 "-noout "选项,然后再指定某些项来使用。例如:

[root@aarch64 ~]# openssl x509 -in /etc/pki/CA/newcerts/01.pem -noout -text
[root@aarch64 ~]# openssl x509 -in /etc/pki/CA/newcerts/01.pem -noout -serial
[root@aarch64 ~]# openssl x509 -in /etc/pki/CA/newcerts/01.pem -noout -subject
[root@aarch64 ~]# openssl x509 -in /etc/pki/CA/newcerts/01.pem -noout -issuer
[root@aarch64 ~]# openssl x509 -in /etc/pki/CA/newcerts/01.pem -noout -fingerprint
[root@aarch64 ~]# openssl x509 -in /etc/pki/CA/newcerts/01.pem -noout -issuer_hash
[root@aarch64 ~]# openssl x509 -in /etc/pki/CA/newcerts/01.pem -noout -startdate -enddate
【签署选项:】
******************************************************************************
        伪命令x509可以像openssl ca一样对证书或请求执行签名动作。注意,openssl x509         
        不读取配置文件,所有的一切配置都由x509自行提供,所以openssl x509像是一个"mini CA"    
******************************************************************************
-signkey filename   :该选项用于提供自签署时的私钥文件,自签署的输入文件"-in file"的file可以是证书请求文件,也可以是已签署过的证书。
                    :-days arg:指定证书有效期限,默认30天。

-x509toreq          :将已签署的证书转换回证书请求文件。需要使用"-signkey"选项来传递需要的私钥。
-req                :x509工具默认以证书文件做为inputfile(-in file),指定该选项将使得input file的file为证书请求文件。
-set_serial n       :指定证书序列号。该选项可以和"-singkey"或"-CA"选项一起使用。
                    :如果和"-CA"一起使用,则"-CAserial"或"-CAcreateserial"选项指定的serial值将失效。
                    :序列号可以使用数值或16进制值(0x开头)。也接受负值,但是不建议。

-CA filename        :指定签署时所使用的CA证书。该选项一般和"-req"选项一起使用,用于为证书请求文件签署。
-CAkey filename     :设置CA签署时使用的私钥文件。如果该选项没有指定,将假定CA私钥已经存在于CA自签名的证书文件中。
-CAserial filename  :设置CA使用的序列号文件。当使用"-CA"选项来签名时,它将会使用某个文件中指定的序列号来唯一标识此次签名后的证书文件。
                    :这个序列号文件的内容仅只有一行,这一行的值为16进制的数字。当某个序列号被使用后,该文件中的序列号将自动增加。
                    :默认序列号文件以CA证书文件基名加".srl"为后缀命名。如CA证书为"mycert.pem",则默认寻找的序列号文件为"mycert.srl"

-CAcreateserial     :当使用该选项时,如果CA使用的序列号文件不存在将自动创建:该文件将包含序列号值"02"并且此次签名后证书文件序列号为1。
                    :一般如果使用了"-CA"选项而序列号文件不存在将会产生错误"找不到srl文件"。

-extfile filename   :指定签名时包含要添加到证书中的扩展项的文件。
【CERTIFICATE EXTENSIONS】
-purpose            :选项检查证书的扩展项并决定该证书允许用于哪些方面,即证书使用目的范围。
basicConstraints    :该扩展项用于决定证书是否可以当作CA证书。格式为basicConstraints=CA:true | false
                    :1.如果CA的flag设置为true,那么该证书允许作为一个CA证书,即可以颁发下级证书或进行签名;
                    :2.如果CA的flag设置为false,那么该证书就不能作为CA,不能为下级颁发证书或签名;
                    :3.所有CA的证书中都必须设置CA的flag为true。
                    :4.如果basicConstraints扩展项未设置,那么证书被认为可疑的CA,即"possible CA"。

keyUsage            :该扩展项用于指定证书额外的使用限制,即也是使用目的的一种表现方式。
                    :1.如果keyUsage扩展项被指定,那么该证书将又有额外的使用限制。
                    :2.CA证书文件中必须至少设置keyUsage=keyCertSign。
                    :3.如果设置了keyUsage扩展项,那么不论是否使用了critical,都将被限制在指定的使用目的purpose上。

例如,使用 x509 工具自建 CA。由于 x509 无法建立证书请求文件,所以只能使用 openssl req 来生成请求文件,然后使用 x509 来自签署。自签署时,使用 "-req" 选项明确表示输入文件为证书请求文件,否则将默认以为是证书文件,再使用 "-signkey" 提供自签署时使用的私钥。

[root@aarch64 ~]# openssl req -new -keyout key.pem -out req.csr -nodes
[root@aarch64 ~]# openssl x509 -req -in req.csr -signkey key.pem -out x509.crt

x509 也可以用来签署他人的证书请求,即为他人颁发证书。注意,为他人颁发证书时,确保 serial 文件存在,建议使用自动创建的选项 "-CAcreateserial"。

[root@aarch64 ~]# ls
key.pem  req.csr
[root@aarch64 ~]# 
[root@aarch64 ~]# openssl x509 -req -in req.csr -CA /etc/pki/CA/cacert.pem -CAkey /etc/pki/CA/private/cakey.pem -out x509.crt -CAcreateserial
Signature ok
subject=/C=XX/L=Default City/O=Default Company Ltd
Getting CA Private Key
[root@aarch64 ~]# 
[root@aarch64 ~]# ls
key.pem  req.csr  x509.crt
[root@aarch64 ~]# 
标签云