头图

Chrome等浏览器已默认将HTTP连接标记为不安全,Docker等工具也极力推荐使用HTTPS通信。在自建服务时,也有许多场景需要自己签发证书。本文粗略记述相关步骤。

另,需要对外开放的服务,可以尝试Let's Encrypt项目。

关于签发

名词解析

参考: OpenSSL自签发配置有多域名或ip地址的证书
  • SSL:(Secure Socket Layer,安全套接字层)是在客户端和服务器之间建立一条SSL安全通道的安全协议
  • TLS:(Transport Layer Security,传输层安全协议),用于两个应用程序之间提供保密性和数据完整性
  • TLS的前身是SSL
  • OpenSSL是TLS/SSL协议的开源实现,提供开发库和命令行程序
  • HTTPS是HTTP的加密版,底层使用的加密协议是TLS

签发证书时的一些名词:

  • FQDN: fully qualified domain name, 完全限定域名, 域名的一种,能指定其在域名系统 (DNS) 树状图下的一个确实位置。完整域名由主机名称与母域名两部分所组成,例如有一部服务器的本地主机名为myhost,而其母域名为example.com,那指向该服务器的完整域名就是myhost.example.com
  • SAN: Subject Alternative Name, 主题备用名称, 是一项对X.509的扩展,它允许在安全证书中使用subjectAltName字段将多种值与证书关联,这些值被称为主题备用名称

    参考:What is the SSL Certificate Subject Alternative Name?

    The Subject Alternative Name (SAN) is an extension to the X.509 specification that allows users to specify additional host names for a single SSL certificate. The use of the SAN extension is standard practice for SSL certificates, and it’s on its way to replacing the use of the common name.

  • CSR: Certificate Signing Request, 凭证签发请求文件,一种包含凭证签发时所需的公钥及相关资讯的文件,不含私钥
  • CRL: Certificate revocation list, 尚未到期就被证书颁发机构吊销的数字证书的名单
  • DN: distinguished name, 专有名称

    • 证书持有人唯一的标识符, 这个名字在 Internet上应该是唯一的。DN由许多部分组成,看起来象这样:

      CN=Bob Allen, OU=Total Network Security Division
      O=Network Associates, Inc.
      C=US
  • CSR组成部分,CSR包含 information identifying the applicant and the applicant's public key that is used to verify the signature of the CSR - and the Distinguished Name (DN) that the certificate is for.

HTTPS原理

参考:什么是HTTPS?HTTPS原理

  • 通信双方通信时使用对称加密,所需性能损耗少
  • 对称加密使用的密钥由非对称加密传递,非对称加密的性能效率较低,但安全性更高
  • 通信发起方A需要验证收到的公钥没有被篡改、替换,使用CA对服务提供方B的公钥认证,并颁发数字证书
  • CA用自己的私钥加密B的公钥, 附带地区、机构等身份信息,生成数字证书,CA的公钥已经内置到A的系统中
  • A用内置CA公钥解密B发送的数字证书,如果解密成功,则说明其中公钥为B认证过的公钥,否则证书内容没有完整性,通信不安全

数字证书

参考:证书颁发机构, X.509

证书实际是由证书签证机关(CA)签发的对用户的公钥的认证;内容包括:电子签证机关的信息、公钥用户信息、公钥、权威机构的签字和有效期等等。

证书格式

当前,证书的格式和验证方法普遍遵循X.509 国际标准。  

  • X.509有多种常用的扩展名。不过其中的一些还用于其它用途,就是说具有这个扩展名的文件可能并不是证书,比如说可能只是保存了私钥。

    • .pem隐私增强型电子邮件 Privacy-Enhanced Mail,DER编码的证书再进行Base64编码的数据存放在"-----BEGIN CERTIFICATE-----"和"-----END CERTIFICATE-----"之中
    • .cer, .crt, .der – 通常是DER Distinguished Encoding Rules二进制格式的,但Base64编码后也很常见。
    • .p7b, .p7cPKCS#7 SignedData structure without data, just certificate(s) or CRL(s)
    • .p12PKCS#12格式,包含证书的同时可能还有带密码保护的私钥
    • .pfx – PFX,PKCS#12之前的格式(通常用PKCS#12格式,比如那些由IIS产生的PFX文件)

PKCS#7 是签名或加密数据的格式标准,官方称之为容器。由于证书是可验真的签名数据,所以可以用SignedData结构表述。 .P7C文件是退化的SignedData结构,没有包括签名的数据。

PKCS#12 由PFX进化而来的用于交换公共的和私有的对象的标准格式。

PKCS 公钥加密标准(Public Key Cryptography Standards, PKCS),此一标准的设计与发布皆由RSA信息安全公司所制定。

证书链

为防止根证书被污染,通常使用根证书签发的中介证书为客户作数字签署,得到终端实体证书

中介证书的有效期会较根证书为短,并可能对不同类别的客户有不同的中介证书作分工。

终端实体证书不会用作签发其他证书。

多级证书间使用证书链传递信任信息

签发流程

  • 流程

  • 主要步骤

    1. 生成密钥对(key: private + public)
    2. 生成CSR,用私钥签名
    3. CA认证CSR(用私钥签名), 生成certificate

使用openssl自签证书链

基本操作

生成密钥

可以配置以下参数

  • Key algorithm: openssl支持RSA, DSA, ECDSA类型的key,web server通常使用RSA
  • Key size: 2048 bits RSA key被认为是安全的
  • Passphrase: optional, 可以让key安全存储、传输、备份,但使用时不方便,在生产环境中也不会过多增加安全性(存放在程序内存中,可以被取得)

    • 支持AES-128, AES-192, AES-256,分别对应参数-aes128, -aes192, -aes256
$ openssl genrsa -aes256 -out fd.key 2048
# 根据提示输入密码
创建CSR

CSR: Certificate Signing Request, a format request asking a CA to sign a certificate, 包含请求者的public key和一些身份信息

$ openssl req -new -key fd.key -out fd.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) [AU]:CN
State or Province Name (full name) [Some-State]:Jiangsu
Locality Name (eg, city) []:Nanjing
Organization Name (eg, company) [Internet Widgits Pty Ltd]:DafuTest
Organizational Unit Name (eg, section) []:IT
Common Name (e.g. server FQDN or YOUR name) []:www.dafu.com
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

challenge password, optional, 在吊销证书时,用于验证证书原来申请者身份的方式,很少有CA使用,不增加CSR安全性,建议留空

CSR配置文件

可以使用配置文件指定CSR必要信息,而避免交互式输入

$ opensll req -new -config fd.cnf -key fd.key -out fd.csr

配置文件如下:

[req]
prompt = no
distinguished_name = dn
req_extensions = ext
input_password = PASSPHRASE

[dn]
CN = www.feistyduck.com
emailAddress = webmaster@feistyduck.com
O = Feisty Duck Ltd
L = London
C = GB

[ext]
subjectAltName = DNS:www.feistyduck.com,DNS:feistyduck.com
自签证书

自己签发证书,而非向CA申请, 但需要另外添加信任

$ openssl x509 -req -days 365 -in fd.csr -signkey fd.key -out fd.crt
签发下级证书
参考:如何使用自签名 CA 和证书来保护个人在公网上的内容

用指定CA证书签发证书

$ openssl x509 -req -sha256 -in your-domain.com.csr -CA root.crt -CAkey root.key -CAcreateserial -out your-domain.com.crt -days 365 -extfile your-domain.com.ext

CAcreateserial 这个参数是比较有意思的,意思是如果证书没有 serial number 就创建一个,因为我们是签名,所以肯定会创建一个。序列号在这里的作用就是唯一标识一个证书,当有两个证书的时候,只有给这两个证书签名的 CA 和序列号都一样的情况下,我们才认为这两个证书是一致的。除了自定生成,还可以通过 -set_serial 手动指定一个序列号。

当使用 -CAcreateserial 参数之后,会自动创建一个和 CA 文件名相同的,但是后缀是 .srl 的文件。这里存储了上一次生成的序列号,每次调用的时候都会读取并 +1 。也就是说每一次生成的证书的序列号都比上一次的加了一。

校验证书
参考:Get your certificate chain right
校验根证书
$ openssl verify root.crt

该证书必须已被添加到系统中,且信任

校验二级证书

$ openssl verify -CAfile root.crt intermediate.crt
cert.pem: OK
校验三级证书

$ openssl verify -CAfile ca.pem \
                 -untrusted intermediate.cert.pem \
                 cert.pem
相关参数
  • -untrusted <file>

    导入不受信任的证书(通常是intermedate CAs)来保证证书链顺利构建

  • -CAfile <file>

    导入受信任CA证书

其他常用操作

查看密钥

密钥以PEM格式存储,如下:

# cat fd.key
-----BEGIN RSA PRIVATE KEY-----
[...]
-----END RSA PRIVATE KEY-----

查看密钥内容:

$ openssl rsa -text -in fd.key
# 输出形如
RSA Private-Key: (2048 bit, 2 primes)
modulus:
    [...]
publicExponent: 65537 (0x10001)
privateExponent:
    [...]
prime1:
    [...]
prime2:
    [...]
exponent1:
    [...]
exponent2:
    [...]
coefficient:
    [...]
writing RSA key
-----BEGIN RSA PRIVATE KEY-----
[...]
-----END RSA PRIVATE KEY-----
提取公钥
$ openssl rsa -in fd.key -pubout -out fd-public.key
# cat fd-public.key
-----BEGIN PUBLIC KEY-----
[...]
-----END PUBLIC KEY-----
查看CSR内容
$ openssl req -text -in fd.csr -noout
# 输出类似
Certificate Request:
    Data:
        Version: 1 (0x0)
        Subject: C = CN, ST = Jiangsu, L = Nanjing, O = DafuTest, OU = IT, CN = www.dafu.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (2048 bit)
                Modulus:
                    [...]
                Exponent: 65537 (0x10001)
        Attributes:
            a0:00
    Signature Algorithm: sha256WithRSAEncryption
         [...]

签发过程

根证书
  1. 创建密钥

    $ openssl genrsa -out root.key 2048

可以使用-aes256参数加密,会提示输入密码

  1. 创建CSR

    $ openssl req -new -key root.key -out root.csr

交互输入信息

  1. 签发证书

    openssl x509 -req -days 365 -in root.csr -signkey root.key -out root.crt
中间证书
  1. 创建密钥

    $ openssl genrsa -out mid.key 2048
  2. 创建CSR

    $ openssl req -new -key mid.key -out mid.csr
  3. 签发证书

    • 需要另外允许中间证书签发下级证书,可以通过extension实现

      创建文件mid.ext

      basicConstraints = CA:TRUE
  • 用根证书签发中间证书

    openssl x509 -req -in mid.csr \
        -CA root.crt -CAkey root.key \
        -CAcreateserial \
        -out mid.crt \
        -days 365 \
        -extfile mid.ext
末端证书
  1. 创建密钥

    $ openssl genrsa -out server.key 2048
  2. 创建CSR

    $ openssl req -new -key server.key -out server.csr
  3. 签发证书

    • 需要指定SAN,目前许多服务通过SAN,代替CN,检查域名一致性

      创建文件server.ext, 格式参考: x509v3_config

      subjectAltName = @alt_names
      
      [alt_names]
      DNS.1 = your-domain.com
      DNS.2 = *.your-domain.com
      DNS.3 = *.api.your-domain.com
      IP = your-ip
  • 用根证书签发中间证书

    openssl x509 -req -in server.csr \
        -CA mid.crt -CAkey mid.key \
        -CAcreateserial \
        -out server.crt \
        -days 365 \
        -extfile server.ext

openssl命令参考

记录openssl常用命令及参数
genrsa

generates an RSA private key

  • 加密方式

    -aes128, -aes192, -aes256, -aria128, -aria192, -aria256, -camellia128, -camellia192, -camellia256, -des, -des3, -idea

    输出private key前用特定算法加密

  • -out <filename> 输出key到指定文件
rsa

The rsa command processes RSA keys. They can be converted between various forms and their components printed out.

  • -text 用encoded version 和 plain text形式打印various public/private key
  • -noout 不输出encoded version的key
  • -in <filename> 指定读取key的文件,如果没有指定,从standard input中获取
  • -out <filename> 指定输出key的文件,如果没有指定,默认为standard output,输出文件名不能与-in输入文件名相同
  • -pubout 输出内容为public key,默认是private key。如果输入为public key,该选项自动指定
  • 加密方式

    -aes128, -aes192, -aes256, -aria128, -aria192, -aria256, -camellia128, -camellia192, -camellia256, -des, -des3, -idea

    输出private key前用特定算法加密

req

The req command primarily creates and processes certificate requests in PKCS#10 format. It can additionally create self signed certificates for use as root CAs for example.

  • -key <filename> 指定读取private key的文件,
  • -new 生成a new certifacate,交互式输入证书相关信息,如果不使用该选项,会使用配置文件中信息生成private key

    $ openssl req -newkey rsa:2048 -keyout key.pem -out req.pem
    # 等价于
    $ openssl genrsa -out key.pem 2038
    $ openssl req -new -key key.pem -out req.pem
  • -newkey creates a new certificate request and a new private key. 具体配置参数见文档
  • -keyout 新创建的private key的文件名,默认按配置文件中指定filename
  • -x509 outputs a self signed certificate instead of a certificate request

    • 通常用于生成测试证书或者 a self signed root CA.
    • 需要的extensions通过配置文件指定
    • 除非指定set_serial选项,否则使用一个large random number作为serial number
    • 如果使用-in选项指定CSR,将其转换为自签证书,否则生成一个新的CSR
  • -days 证书有效时间,正整数,默认30, 仅当指定-x509时有效
  • -text 文本形式打印证书
  • -in <filename> 指定读取CSR文件,不指定指定从standard input获取。仅当新建request的选项(-new, -newkey)未指定时有效
  • -noout 不输出加密格式的request
x509

多用途证书工具

  • 展示证书信息
  • 转换证书为各种格式
  • 签发CSR
  • 修改证书信任信息

常用参数:

  • -req 指定该选项时输入为CSR,不指定默输入为证书
  • -days <arg> 证书有效时间,默认为30天,不能与-preserve_dates同时出现
  • -signkey 使用指定的private key签名输入文件

    • 如果输入的是证书,会改变以下内容:

      • issuer name 设置为 subject name
      • public key 变为指定值
      • start date 设为当前时间
      • end date 根据-days参数设置
      • 除非指定-clrext选项,否则certificate extensions都不生效
    • 如果输入是CSR

      • 使用指定private key创建self signed certificate
      • 证书subject name 同 CSR
  • -in 指定读取文件名,否则从standard input获取
  • -out 指定输出文件名,否则输出至standard output

其他工具推荐

  • FiloSottile/mkcert 一个开发环境快速配置本地信任证书的方便小工具

Nginx反选代理配置https

一般配置

server {
    listen 8445 ssl;
    keepalive_timeout 70;

    # allow large uploads of files
    client_max_body_size 5G;

    ssl_certificate path_to_server_crt.crt;
    ssl_certificate_key path_to_server_key.key;  # key通过权限隔离
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers HIGH:!aNULL:!MD5;

    location / {
        proxy_pass http://127.0.0.1:8083/;
        proxy_set_header Host $host:$server_port;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto "https";
    }
}

证书链

假设根证书已经在客户主机添加信任,有中间证书bundle.crt, 下级证书www.example.com.crt

生成证书链(注意顺序)

$ cat www.example.com.crt bundle.crt > www.example.com.chained.crt

配置Nginx

server {
    listen              443;
    server_name         www.example.com;
    ssl                 on;
    ssl_certificate     www.example.com.chained.crt;
    ssl_certificate_key www.example.com.key;
    ...
}

控维通信
11 声望1 粉丝

专业从事卫星通信产品研发、生产制造及服务的高科技企业。