OpenSSL

OpenSSL 是一个开源工具包,它实现了 SSL(安全套接字层)和 TLS(传输层安全)协议所需的协议和算法。该工具包包括一个通用加密 API、一个功能齐全的命令行实用程序,并使用 Apache 风格的许可证。本文将介绍 OpenSSL 命令行实用程序,并提供几个示例,说明如何使用 OpenSSL 来保护数据、管理数字证书和调试 SSL 通信。包含两个示例 shell 脚本来说明如何使用 OpenSSL 来监控安全的 Web 服务器,并在数字证书即将到期时提供通知。

获取和安装 OpenSSL

OpenSSL 的源代码可以从主要的 OpenSSL 网站或通过众多镜像之一获取。要从源代码安装 openssl,应下载最新的 tar 存档,解压缩并解压缩:

$ gunzip openssl-X.X.X.tar.gz

$ tar xfv openssl-X.X.X.tar

$ cd openssl-X.X.X

提取源代码后,应检查 INSTALL 文件。INSTALL 文件包含有关编译 OpenSSL 的详细信息,并描述了可用于构建过程的标志。要使用默认选项构建 openssl,可以执行 config 和 make 命令:

$ ./config

$ make

$ make install

config 命令将调用用 perl 编写的 Configure 脚本。为避免配置过程出现任何问题,您需要仔细检查是否安装了 perl 5.X 或更高版本。构建过程完成后,库和可执行文件将在 /usr/local/ssl 中可用。如果您希望更改默认安装位置,可以在 config 命令后附加“--prefix”选项。

使用 OpenSSL

一旦安装了 OpenSSL,就可以使用 openssl 命令访问命令行界面:

$ openssl help

openssl:Error: 'help' is an invalid command.

Standard commands
asn1parse      ca             ciphers        crl            crl2pkcs7      
dgst           dh             dhparam        dsa            dsaparam       
enc            engine         errstr         gendh          gendsa         
genrsa         nseq           ocsp           passwd         pkcs12         
pkcs7          pkcs8          rand           req            rsa            
rsautl         s_client       s_server       s_time         sess_id        
smime          speed          spkac          verify         version        
x509           

Message Digest commands (see the `dgst' command for more details)
md2            md4            md5            mdc2           rmd160         
sha            sha1           

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    base64         bf             bf-cbc         bf-cfb         
bf-ecb         bf-ofb         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        

OpenSSL 无法识别帮助命令,因此会打印所有可用的菜单选项。可以使用 list-standard-commands、list-message-digest-commands 和 list-cipher-commands 选项单独访问各个帮助屏幕(标准命令、消息摘要和密码命令):

$ openssl list-standard-commands

$ openssl list-message-digest-commands

$ openssl list-cipher-commands

要获取有关每个选项的详细信息,请参考 openssl(1) 联机帮助页。现在我们知道了如何调用 OpenSSL 命令行,让我们玩得开心吧!

计算和验证校验和

Internet 越来越多地用于分发源代码和二进制软件包。当其中一台软件分发服务器遭到破坏时,软件包的完整性就会受到质疑。为确保软件未被篡改,可以使用消息摘要来创建文件的数字指纹。消息摘要的工作原理是获取一个可变长度的文件,并通过散列算法运行它以产生一个固定长度的输出(数字指纹)。这个操作很容易进行,但是逆向操作却是极其困难的。一旦计算出指纹,就可以通过安全通道将其分发给客户端,并用于确保文件内容没有更改。

OpenSSL 支持多种消息摘要算法,包括:MD2、MD4、MD5、SHA、SHA1、MDC2 和 Ripe MD160。每个算法都可以通过将算法名称传递给 dgst 命令来调用,或者直接传递给 openssl 命令。以下示例利用 dgst 选项计算 /etc/secure/data 的 MD5 摘要:

$ openssl dgst -md5 /etc/secure/data

MD5(/etc/secure/data)= f268fc3e92ef844117365a3368b8fe45

以下示例将摘要算法直接传递给 openssl,并生成 /etc/secure/data 的 MD5 校验和:

$ openssl md5 /etc/secure/data

MD5(/etc/secure/data)= f268fc3e92ef844117365a3368b8fe45

OpenSSL 还可以与 find 结合为多个文件生成指纹:

$ find /etc -type f | xargs openssl md5 > /etc/secure/md5_sigs.txt

这将创建 /etc 目录中所有文件的 MD5 哈希。如果您需要检查/etc 中的文件是否被修改,您可以将当前指纹与上面计算的指纹进行比较。应将包含指纹的文件复制到只读媒体,并存储在安全位置。

加密数据

加密是获取数据(通常称为明文)并将其转换为与原始数据无法区分的替代形式(通常称为密文)的过程。数据加密过程通常需要一个密钥,并利用一组算法将明文数据转换为密文。

对称密钥算法(也称为共享秘密算法)使用相同的密钥来加密和解密数据。公钥算法(也称为非对称算法)使用不同的密钥进行加密和解密。公钥算法之所以得名,是因为其中一个密钥(公钥)可以分发给其他人,而用该密钥加密的数据只能用相关的私钥解密。

OpenSSL 支持多种对称密钥算法,包括:DES、3DES、IDEA、Blowfish 和 AES。每个对称密钥算法都可以通过将算法名称传递给 enc 命令来调用,或者直接传递给 openssl 命令。以下示例使用 Blowfish 算法加密名为 passwd 的文件:

$ openssl bf -e -in /etc/secure/passwd -out /etc/secure/passwd.enc.bf

enter bf-cbc encryption password:
Verifying - enter bf-cbc encryption password

The encrypted version of passwd will be placed in
/etc/secure/passwd.enc.bf.  The following example utilizes 3DES and
the enc command to encrypt the file sensitive_data. The encrypted
contents are placed in /etc/secure/sensitive_data.enc.3des:

$ openssl enc -e -3des -in /etc/secure/sensitive_data -out /etc/secure/sensitive_data.enc.3des

enter bf-cbc encryption password:
Verifying - enter bf-cbc encryption password:

有时,将加密文件的内容发送给同事或朋友可能是有益的。加密数据为二进制格式,难以嵌入电子邮件。OpenSSL 支持 base64 标准,可用于将二进制数据表示为 ASCII 文本。要使用 AES-128 算法加密文件,并对内容进行 base64 编码,可以将“-base64”和“-aes128”参数传递给 openssl:

$ openssl enc -base64 -e -aes128 -in /etc/secure/data -out /etc/secure/data.enc.aes128.b64

enter bf-cbc encryption password:
Verifying - enter bf-cbc encryption password:

如果您选择使用电子邮件或其他不安全的数据传输工具来发送加密数据,强烈建议您为加密文件创建数字签名或指纹。这将确保加密的内容在传输过程中没有被篡改。

解密数据

要解密先前加密的文件,可以将“-d”选项传递给 enc 选项,或作为参数传递给加密算法。以下示例显示了如何解密之前使用 3DES 算法加密的文件 /etc/secure/sensitive_data.enc.3des:

$ openssl enc -des3 -d -in /etc/secure/sensitive_data.enc.3des -out /etc/secure/sensitive_data

这会将解密的文件内容放在文件 /etc/secure/sensitive_data 中。如果您希望在终端上查看文本文件的内容,可以将 openssl 的输出通过管道传送到您喜欢的寻呼机:

$ openssl enc -des3 -d -in /etc/secure/services.bf | more

生成密码文件条目

OpenSSL 可用于通过 passwd 命令生成密码哈希。此工具可用于自动配置用户,或进行系统范围的密码更新。以下示例显示了如何生成密码字符串“blah”的 MD5 哈希:

$ echo blah | openssl passwd -stdin -1

“-1”选项表示应该使用MD5消息摘要算法,“-stdin”表示passwd将通过标准输入传递。如果您的身份验证系统不支持 MD5,则可以使用 crypt 创建密码:

$ echo blah | openssl passwd -stdin -crypt -salt GH

这将生成带有盐“GH”的密码“blah”的加密版本。

数字证书

数字证书是一种电子“驾照”,用于证明客户端或服务器的身份。证书颁发机构 (CA) 负责颁发数字证书,并证明请求证书的实体的身份。数字证书包含几条信息,包括:证书版本、唯一标识证书的序列号、标识颁发证书的组织的属性(颁发者)、证书有效日期范围、属性(主题) 来标识证书颁发给的站点,以及数字签名。客户端和服务器使用数字签名来确保证书所代表的个人实际上就是他们所说的那个人。

当组织想要从证书颁发机构请求数字证书时,他们需要提交证书签名请求 (CSR)。证书签名请求包含公钥、用于唯一标识站点的通用名称(例如www.example.com)和用于标识组织的位置信息。以下示例显示了如何生成证书签名请求:

$ openssl req -new -outform PEM -keyform PEM -keyout secret.key -out cert.csr -newkey rsa:1024

Generating a 1024 bit RSA private key
.............++++++
..............................................++++++
writing new private key to 'secret.key'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
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) [AU]:US
State or Province Name (full name) [Some-State]:Georgia
Locality Name (eg, city) []:Atlanta
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Example
Organizational Unit Name (eg, section) []:
Common Name (eg, YOUR name) []:www.example.com
Email Address []: sysadmin@example.com
 
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

在请求生成过程中,会生成两个 1024 位 RSA 密钥,并收集各种信息。openssl 实用程序将提示输入密码短语,用于加密私钥的内容。生成密钥后,私钥将被 PEM 编码并放置在文件 secret.key 中。证书签名请求放置在文件 cert.csr 中。该文件包含公钥、位置信息和用于唯一标识站点的通用名称。您可以使用 req 命令打印证书签名请求的内容:

$ openssl -req -in cert.csr -text

验证证书签名请求后,您可以将内容提交给您最喜欢的证书颁发机构。证书颁发机构将使用此文件的内容及其私钥来生成数字签名。证书颁发机构还将分配一个到期日期,并结合附加属性来唯一标识证书颁发机构。

显示数字证书的内容

数字证书可以以多种格式存储。两种最常见的格式是 PEM(隐私增强邮件)和 DER(确定编码规则)。OpenSSL 可以使用 x509 命令打印两种证书格式的内容。以下示例将打印 PEM 编码证书 cert.crt.pem 的内容:

$ openssl x509 -in cert.crt.pem -inform PEM -text -noout

OpenSSL 还允许您打印证书的各个属性:

$ openssl x509 -in cert.crt.der -inform PEM -noout -enddate

这将仅打印证书 cert.crt.der 的到期数据。

证书类型之间的转换

如上所述,数字证书可以以多种格式存储。当证书需要在异构 Web 服务器之间迁移或在应用程序组件之间分发时,这可能会导致问题。OpenSSL 提供 x509 选项来在 PEM 和 DER 编码证书之间进行转换。以下示例将 PEM 编码的证书转换为 DER 格式:

$ openssl x509 -in cert.crt.pem -inform PEM -out cert.crt.der -outform DER

证书转换后,将放置在文件 cert.der.crt 中。以下示例将 DER 格式的证书转换为 PEM 格式:

$ openssl x509 -in cert.crt.der -inform DER -out cert.crt.pem -outform PEM

OpenSSL pkcs12 命令可用于导入和导出存储在 PKCS#12 数据库中的证书。以下示例将从 PKCS#12 数据库中导出别名为 Server-Cert 的证书:

$ openssl pkcs12 -export Server-Cert -in cert.db.pkcs12 -out cert.crt.p12

导出证书后,可以使用 pkcs12 命令将其转换为 PEM 或 DER 格式:

$ openssl pkcs12 -in cert.crt.p12 -out cert.crt.pem

使用 OpenSSL 监控安全的 Web 服务器连接

SSL的服务检查 脚本可以用来检查是否启用了SSL的网站正在处理新的连接。调用 openssl s_client 选项,并将 HTTP GET 请求传递到 Web 服务器。如果服务器未能返回有效响应,则会通过系统日志记录一条消息,并向随叫随到的寻呼机发送一封电子邮件。该脚本可以通过 cron 定期运行,或者修改为在系统启动时作为守护程序连续运行。

检查过期的网站证书

可以部署数字证书来验证客户端,并证明服务器的身份。颁发数字证书时,会分配一个到期日期,以确保受损证书不会有无限的生命周期。在 SSL 连接建立期间,客户端和服务器通常会检查分配给证书的到期日期。当服务器证书过期时,客户会收到警告消息,这可能会导致潜在的混淆。过期的证书也可能导致服务中断。为了提供惊人的功能来解决这个问题,我开发了ssl-cert-check

ssl-cert-check 是一个使用 GNU 日期和 openssl s_client 命令行选项的 bash 脚本。ssl-cert-check 支持交互和批量操作,可以配置为在证书即将过期时发送电子邮件。ssl-cert-check 在没有任何选项的情况下调用时将打印详细的帮助屏幕:

$ ssl-cert-check

Usage: ssl-cert-check [ -e email address ] [ -x days ] [-q] [-a] [-h] [-i] [-n]
       { [ -s common_name ] && [ -p port] } || { [ -f cert_file ] } || { [ -c certificate file ] }

  -a                : Send a warning message through E-mail 
  -c cert file      : Print the expiration date for the PEM or PKCS12 formatted certificate in cert file
  -e E-mail address : E-mail address to send expiration notices
  -f cert file      : File with a list of FQDNs and ports
  -h                : Print this screen
  -i                : Print the issuer of the certificate
  -k password       : PKCS12 file password
  -n                : Run as a Nagios plugin
  -p port           : Port to connect to (interactive mode)
  -s commmon name   : Server to connect to (interactive mode)
  -q                : Don't print anything on the console
  -x days           : Certificate expiration interval (eg. if cert_date < days)

以下命令可用于查看在端口 443 上运行的 prefetch.net Web 服务器的证书到期日期:

$ ssl-cert-check -s prefetch.net -p 443

Host                           Status   Expires              Days Left
prefetch.net:443               Valid    May 24 2005          363  

该脚本也可以以批处理模式运行,这将导致 ssl-cert-check 处理域和 TCP 端口组合的完整列表:

$ cat ssldomains

www.spotch.com 443
mail.prefetch.net 995
prefetch.net 443

$ ssl-cert-check -b -f ssldomains

Host                           Status   Expires              Days Left
www.spotch.com:443             Down     ?                    ?   
mail.prefetch.net:995          Expired  Oct 30 2002          -574 
prefetch.net:443               Valid    May 24 2005          363  

ssl-cert-check 还提供了在证书准备到期时发出警报(通过电子邮件)的功能。此功能与安静的操作模式相结合,将允许 ssl-cert-check 轻松集成到调度工具中:

$ ssl-cert-check -b -f ssldomains -q -a -x 90 -e root

这将导致 ssl-cert-check 检查文件 ssldomains 中列出的所有域,如果证书将在 90 天或更短的时间内到期,则向根发送电子邮件。

结论

在本文中,我试图介绍几个示例,说明如何使用 OpenSSL 来保护数据和排除 SSL 通信故障。我还提供了两个示例脚本,可用于检查证书是否过期以及启用 SSL 的 Web 服务器的状态。大多数书店的大部分内容和完整的课程都已创建来解释密码学、加密、SSL 和 TLS。这篇文章几乎没有触及可用内容的表面。与所有软件一样,在任何生产环境中使用之前,应彻底测试这些示例。

参考

撰写本文时使用了以下参考资料:

致谢

Ryan 感谢 OpenSSL 开发人员以及所有为本文讨论的加密算法和协议的设计和实现投入时间和精力的人们。

最后更新于