数字证书与cfssl工具链

分析数字证书原理,记录cfssl常用命令。

Posted by Cheney.Yin on October 14, 2021

1 什么是根证书?

参考

根证书是证书颁发机构(CA)的公钥证书,是在公开密钥基础建设中,信任链的起点。根证书没有上层机构再为其本身作数字签名,所以都是自签证书

2 X.509证书规范

参考

一般的,一个数字证书内容可能包括基本数据(版本、序列号)、所签名对象信息(签名算法类型、签发者信息、有效期、被签发人、签发的公开密钥)、CA 的数字签名等等。

目前使用最广泛的标准为 ITUISO 联合制定的 X.509 的 v3 版本规范(RFC 5280),其中定义了如下证书信息域:

  • 版本号(Version Number):规范的版本号,目前为版本 3,值为 0x2
  • 序列号(Serial Number):由 CA 维护的为它所颁发的每个证书分配的唯一的序列号,用来追踪和撤销证书。只要拥有签发者信息和序列号,就可以唯一标识一个证书。最大不能超过 20 个字节; 签名算法(Signature Algorithm):数字签名所采用的算法,如 sha256WithRSAEncryptionecdsa-with-SHA256
  • 颁发者(Issuer):颁发证书单位的标识信息,如 C=CN, ST=Beijing, L=Beijing, O=org.example.com, CN=ca.org.example.com
  • 有效期(Validity):证书的有效期限,包括起止时间;
  • 主体(Subject):证书拥有者的标识信息(Distinguished Name),如 C=CN, ST=Beijing, L=Beijing, CN=person.org.example.com
  • 主体的公钥信息(Subject Public Key Info):所保护的公钥相关的信息;
    • 公钥算法(Public Key Algorithm):公钥采用的算法;
    • 主体公钥(Subject Public Key):公钥的内容;
  • 颁发者唯一号(Issuer Unique Identifier):代表颁发者的唯一信息,仅 2、3 版本支持,可选;
  • 主体唯一号(Subject Unique Identifier):代表拥有证书实体的唯一信息,仅 2、3 版本支持,可选;
  • 扩展(Extensions,可选):可选的一些扩展。v3 中可能包括:
    • Subject Key Identifier:实体的密钥标识符,区分实体的多对密钥;

    • Basic Constraints:一般指明是否属于 CA

    • Authority Key Identifier:颁发这个证书的颁发者的公钥标识符;

    • CRL Distribution Points:撤销文件的发布地址;

    • Key Usage: 证书的用途或功能信息。 此外,证书的颁发者还需要对证书内容利用自己的私钥进行签名,以防止他人篡改证书内容。

3 CA签发证书原理


图1 数字证书认证中心签发证书


图2 服务端认证

4 实例步骤

参考

4.1 创建CA证书(即根证书)及其私钥

首先创建证书请求签名文件(CSR, CERTIFICATE SIGNING REQUEST)

1
 cfssl print-defaults csr > ca-csr.json

文件ca-csr.json为证书签名请求配置文件,其内容大致如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
    "CN": "example.net",
    "hosts": [
        "example.net",
        "www.example.net"
    ],
    "key": {
        "algo": "ecdsa",
        "size": 256
    },
    "names": [
        {
            "C": "US",
            "ST": "CA",
            "L": "San Francisco"
        }
    ]
}
  • CN:Common Name,所有csr文件都必须有字段。
  • 对于 SSL 证书,一般为网站域名。

  • 而对于代码签名证书则为申请单位名称。

  • 而对于客户端证书则为证书申请者的姓名。
  • hosts:网络请求url中的合法主机名或域名集合。
  • key:key字段是必须有的字段,其内容一般也比较固定就是:{"algo":"rsa”,"size":2048},表示使用的加密算法rsa,密文长度2048。
  • names:也是必须有字段,是证书对外公开显示的一些字段,常见如下:
    • C:即Country的简写,表示国家,例如中国为CN

    • L:即Locality的简写,表示所在地区或城市。

    • ST:表示所在州或省份。

    • O:表示所在单位或组织。

    • OU:显示其它内容。

参照如上规范,CSR配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 cat ./ca-csr.json
{
    "CN": "cheney.site",
    "hosts": [
        "cheney.site",
        "192.168.100.1"
    ],
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C": "CN",
            "ST": "JS",
            "L": "Wu Xi",
	    	"O": "cheney"
        }
    ]
}

通过如下命令,依据ca-csr.json生成CA证书(或根证书)。

1
cfssl gencert --initca ./ca-csr.json | cfssljson -bare ca

命令执行完毕后,目录下会得到3个文件,分别为ca.pemca-key.pemca.csr

文件 说明
ca.pem CA证书文件,包含认证中心的公钥
ca-key.pem CA证书的私钥文件。
ca.csr CA证书的认证请求文件。

CA证书用于签发其它证书,需要为CA认证中心配置其功能项。通过如下命令可以获取CA配置模板。

1
cfssl print-defaults config > ca.config

CA配置的基本内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
    "signing": {
        "default": {
            "expiry": "168h"
        },
        "profiles": {
            "www": {
                "expiry": "8760h",
                "usages": [
                    "signing",
                    "key encipherment",
                    "server auth"
                ]
            },
            "client": {
                "expiry": "8760h",
                "usages": [
                    "signing",
                    "key encipherment",
                    "client auth"
                ]
            }
        }
    }
}
  • expiry:表示签发过期时间。

  • profiles:配置各类使用场景,每类使用场景有expiry(过期时间)和usages(功能用途)组成。

    • usages:可选功能包括签名(signing)、加密(key encipherment)、服务端认证(server auth)、客户端认证(client auth)等。

参照上述规范,CA配置实例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
    "signing": {
        "default": {
            "expiry": "43800h"
        },
        "profiles": {
            "server": {
                "expiry": "43800h",
                "usages": [
                    "signing",
                    "key encipherment",
                    "server auth"
                ]
            }
        }
    }
}

这里,过期时间为5年,server场景下签发证书可用于签名、加密以及服务端认证。

4.2 签发证书

接下来,为一组服务器(IP:192.168.100.120~122)签发server证书。

首先,准备一份证书签名请求文件server-csr.json,其内容规范同步骤1CSR一致。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
    "CN": "cheney.server",
    "hosts": [
        "192.168.100.120",
		"192.168.100.121",
		"192.168.100.122"
    ],
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C": "CN",
            "ST": "JS",
            "L": "Wu Xi",
	    	"O": "cheney"
        }
    ]
}

然后,由认证中心使用根证书(ca.pemca-key.pem)和场景配置(ca-config.json)生成server证书。

1
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem --config=ca-config.json --profile=server server-csr.json | cfssljson -bare server

命令执行完毕后,执行目录下会生成3个文件(server.pemserver-key.pemserver.csr)。

4.3 验证

常用的验证工具有opensslcfssl-certinfo

openssl命令如下:

1
openssl x509 -in server.pem -text -noout

校验要注意以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
Issuer: C = CN, ST = JS, L = Wu Xi, O = cheney, CN = cheney.site
...
Subject: C = CN, ST = JS, L = Wu Xi, O = cheney, CN = cheney.server
...
X509v3 Key Usage: critical
	Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
	TLS Web Server Authentication
            ...
            ...
X509v3 Subject Alternative Name:
	IP Address:192.168.100.120, IP Address:192.168.100.121, IP Address:192.168.100.122
  • Issuer要与ca-csr.json的定义一致。
  • Subject要与server-csr.json的定义一致。
  • x509v3 Key Usagex509v3 Extended Key Usage要与ca-config.jsonserver场景一致。
  • X509v3 Subject Alternative Name要与server-csr.jsonhosts一致。 cfssl-certinfo命令如下:
1
cfssl-certinfo -cert server.pem

其校验主要关注subjectissuersans即可。

openssl命令提供了链式校验,

1
2
3
4
5
openssl verify -verbose -show_chain --CAfile ../ca.pem  ./server.pem
./server.pem: OK
Chain:
depth=0: C = CN, ST = JS, L = Wu Xi, CN = registry.cheney.io (untrusted)
depth=1: C = CN, ST = JS, L = Wu Xi, CN = cheney.io

返回OK,则表示验证成功,说明server.pem是由ca.pem签发的。

注意,在认证链上证书的CN要唯一,否则认证失败。

4.4 本地安装CA根证书

在ssl认证过程中,需要判定证书是否可信,即证书是否为可信的CA机构签发的。ssl需要在本地按照证书提供的Issuer检索本地是否存在可信的CA根证书。可以通过如下方式手动安装CA证书

ca.pem转为ca.crt(二进制),

1
openssl x509 -outform DER -in ./ca.pem -out ./ca.crt

ca.crt拷贝到/etc/ca-certificates/trust-source/anchors/目录下,

1
sudo cp ./ca.crt /etc/ca-certificates/trust-source/anchors/ca.crt

最后执行update-ca-trust

1
sudo update-ca-trust

命令执行成功后,可以从/etc/ssl/cert.pem文件中找到ca.crt的内容,也可以从/etc/ssl/certs/找到相关文件。

注意,更新可信CA后,只有执行命令的当前进程和新的进程生效。