自建CA并生成自签名SSL证书


前言

这是加密与认证系列的第五篇文章了,本来我是想把自建证书和nginx配置https访问总结到一起的,但是在实际操作的过程中我发现了很多细小的知识点,有些还是挺有意思的,这是一个不断自我提问不断寻求答案的过程,随着扩展的内容越来越多,我决定这篇只写自建CA和签名SSL证书这部分,至于nginx配置https访问放到后面再写吧。

相信点进这篇文章的人应该知道为什么要自建CA和自签名SSL证书了,因为买现成的SSL证书挺贵的,SSL证书通常有三种类型:域名级(DV)、企业级(OV)、增强级(EV),价格从每年几百元到上万元不等,再细分的话还有单域名证书、通配符证书、多域名证书等等,有些证书还可以追加域名。

这笔费用对于大厂来说可能不算什么,但是对于小产品来说,即使选择最便宜的证书也是一笔开销,比如在上一篇《根证书的应用和信任基础》提到的12306官网在2017以前使用的也是用的自签名证书,一般正式产品总会咬咬牙买个证书,但是如果是本地测试,或者局域内网的使用的产品使用自建的证书就足够了,相当于我们配了临时证书资源在开发新功能,等到真正对外发布时再替换成购买的证书也来的及,所以接下来我们就一起走一遍自建证书的流程。

一、一键生成自签名证书

总有心急的人想吃热豆腐,所以我把用到的命令写了一个脚本,只要输入几个自定义密码就可以完成CA证书和SSL证书的创建,前提是在你的电脑安装了openssl命令,在ubuntu上系统上默认就有,没有的自己安装一下吧。

命令脚本

将下列命令放到shell脚本文件onekeyssl中执行即可

#!/bin/bash

read -p "Enter your domain or ip [www.example.com/10.10.49.172]: " INPUT

echo "1. Create ca private key..."

openssl genrsa -des3 -out selfca.key 2048

echo "2. Create ca root certificate..."

openssl req -new -x509 -days 3650 -key selfca.key -subj "/C=CN/ST=BJ/L=BJ/O=MyRootCA/OU=MyCA/CN=CA" -out selfca.crt

echo "3. Create server key and certificate signing request..."

openssl req -newkey rsa:2048 -nodes -keyout server.key -subj "/C=CN/ST=BJ/L=BJ/O=MyRootServer/OU=MyServer/CN=$INPUT" -out server.csr

echo "4. Sign SSL certificate..."

openssl x509 -req -extfile <(printf "subjectAltName=IP:$INPUT") -days 3650 -in server.csr -CA selfca.crt -CAkey selfca.key -CAcreateserial -out server.crt

echo "5. Create end, next work..."
echo "Copy server.crt and server.key to your server machine"

执行结果

$ ./onekeyssl.sh
Enter your domain or ip [www.example.com/10.10.49.172]: 10.10.19.1
1. Create ca private key...
Generating RSA private key, 2048 bit long modulus (2 primes)
..................................................+++++
.....................................+++++
e is 65537 (0x010001)
Enter pass phrase for selfca.key:【输入自定义密码】
Verifying - Enter pass phrase for selfca.key:【重复密码】
2. Create ca root certificate...
Enter pass phrase for selfca.key:【重复密码】
3. Create server key and certificate signing request...
Generating a RSA private key
.............................................................+++++
..........+++++
writing new private key to 'server.key'
-----
4. Sign SSL certificate...
Signature ok
subject=C = CN, ST = BJ, L = BJ, O = MyRootServer, OU = MyServer, CN = 10.10.19.1
Getting CA Private Key
Enter pass phrase for selfca.key:【重复密码】
5. Create end, next work...
Copy server.crt and server.key to your server machine

分步来看看自建证书的过程

整个过程分为自建CA和自签名SSL证书两部分:

自建CA:并不是要你自己搭建一个CA中心,这里的CA其实指的是创建自己的CA根证书,这样可以给其他人签署证书,但是这个CA根证书是你自己创建的,没有得到互联网的承认,也不会被正规CA认可,所以不具备通用和有效性,一般可以在内部网络使用。

自签名SSL证书:一般来说,我们的证书是要发给权威机构CA进行验证签署的,但是自签证书,就是自己给自己签署生成一份CA证书,或者用自建的CA根证书来签发的SSL证书,同样不具备互联网的通用和有效性,一般只用于测试环境或内部网络。

自建CA根证书

自建CA根证书也是分成两步

生成CA私钥

openssl genrsa -des3 -out selfca.key 2048

这条命令使用 OpenSSL 工具生成一个带有Triple-DES(3DES)加密的密码保护的2048位RSA私钥文件,各个参数的含义如下:

openssl: OpenSSL 工具的命令行执行器。

genrsa: 生成RSA密钥的命令。

-des3: 使用Triple-DES算法对生成的私钥进行加密,这会在生成私钥时要求你设置一个密码,以便在每次使用私钥时都需要提供密码。

-out selfca.key: 指定生成的私钥的输出文件名为 selfca.key,私钥文件将被保存在当前工作目录中。

2048: 指定生成的RSA私钥的位数为2048位,这是一种常见的安全密钥长度。

其中密码这一项在生成CA证书时我们是想加的,运行命令后需要输入一个自定义密码两次,以后每次使用这个私钥都要输入密码,但是在很多文章中你会发现他们有一步是要删除密码,原因是在一些自动化部署场景中,去掉私钥密码可以避免手动输入密码,使整个过程更加自动化,比如配置到Apache或者Nginx中时不必每次启动时输入密码,所以我们在后面生成服务器私钥时就不使用密码了。

带有密码的私钥内容

-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,2D6A221FF66727E0
vEzhQnjsKVBLw6tPNo6Dx7D8CyzhZdZYgfxuZBYP30cLWOORTpsS1q0txNMCaWoy
S79k0+qTgENne2oirALiCnPB5Rzf3vO6gv/KSScvEnGrZ6Q57i3xObhLYzCtKOAg
E6wSBBfbeC6cXczAFZ2ehnM42+Cv/9BX829X7BnbylNbaV1VXQTaEsmo+uWwx9dZ

C2udyFqENooTB7n1Qbtm3Fsruwgk/0IM3vSRk41/EWADabWs4tR/uXQmCPyxouHI
xhT3U4EeabyY8dyjSRCkzKPIEFl2HwnYQHZcDVUPD52uHEvA5M7c1QNgX2VmTXzP
AgSijAZHDrh6QWa+R9eqUVQShY4mAN7c1sv1or4ZckV7jQTbIBjUGcjhX1TooxX0
/RE/GLodSqD8wCkxjgD7uxy93oOLuV/9iDDsrI7VMrs5jlKhKEuPozc+Y+hERRBm
UUMbAE2JBW+jD/JzkmXL8w4AGU8wHeRI/FqKQXLbP6v3h+Yb4zP/aOVZ5mdWlHWT
1+BykB3qgKUqcn+FmRbodvK8C1G1opDchyomCToHzCGTDqAAcRPoNiB5z3jB+yPC
M0m83wI4rWYPghWL4hT7aZgI8l2xwTJfJfyJ+/6MfBZgh/qa4t703A==
-----END RSA PRIVATE KEY-----

不带密码的私钥内容

-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEA6OCPgi1pUWdkS9DdR2mk6QJsE9i6rCgaDuk+xyi8Sdxp2u8r
f81ZrK4xUNUNTX8+lnj5WeolJ/Hk1o9I659oPkbWuw7yyuCBFbZ9m3goZCt2w+lc
csLw6o6XyGTUiptcgB/GmGcd/ua3REAt3l6uYn32vjeit5oX5xsmsUKbwpIH/B81
nMohd/t6m9c0h2mcVnUYDmUsV+hmgdASvkTSmvqHOUwV1qX/pQNgjR+auLiezoza
LmVkvtSI9/tX6sqtlyROn7ZFsUHJbYuyfOekqLCiY5Wo5ocSTqAd4n/JYmjA6anI
YGDXbLcP+075ZgkHSoR9ab4uFtghStx99QYwywIDAQABAoIBAQDWeWryE2y5wiVH
…
SdwHzniXCpBpNYB6XoV57bPpQiSCqVyT9Owd0A9csZf4905dOZg+/25K2TFmv7gG
fHN/4EkCgYEAz7VrytExyCm1B+7sFln7c1hjy5wzNaW2tYi08szvErJkpe3jz9HH
MLbTn+DrXZu76nsiXfQbTl7SpPQJptHctHx7K+9mykDaJNGDDNmJRKdwi8cfINrD
yYPab+aojwU1FZtF8EEXKjnzWIvmM8FO71ej+COUOmDxWCsDbpoHyhA=
-----END RSA PRIVATE KEY-----

生成CA自签名证书

openssl req -new -x509 -days 3650 -key selfca.key -subj "/C=CN/ST=BJ/L=BJ/O=MyRootCA/OU=MyCA/CN=CA" -out selfca.crt

这条命令使用 OpenSSL 工具生成自签名根证书(Root Certificate),各个参数的含义如下:

openssl req: 这是 OpenSSL 工具中用于处理证书签署请求(CSR)的命令。

-new: 表示创建新的 CSR。

-x509: 表示生成自签名的 X.509 证书,而不是生成 CSR。

-days 3650: 设置证书的有效期为 3650 天(10 年)。

-key selfca.key: 指定用于生成证书的私钥文件为 selfca.key

-subj "/C=CN/ST=BJ/L=BJ/O=MyRootCA/OU=MyCA/CN=CA": 设置证书主题(Subject)的信息。这里使用了简化的 Distinguished Name (DN),包括了国家(C=CN)、省/州(ST=BJ)、城市(L=BJ)、组织(O=MyRootCA)、组织单位(OU=MyCA)、通用名称(CN=CA)等信息。

-out selfca.crt: 指定生成的证书文件的输出路径和文件名,这里为 selfca.crt

至此我们就生成了一个自签名的CA根证书,如果把它加入到操作系统或浏览器的信任列表中,那么之后由他签发的SSL证书都可以被信任了,接下来我们开始用它来签发SSL证书。

自签名SSL证书

这个过程主要包括生成服务器密钥、构建签名请求和用CA签名证书三部分,其中前两步可以合并为一步:

生成服务器私钥和证书申请文件CRS

$ openssl req -newkey rsa:2048 -nodes -keyout server.key -subj "/C=CN/ST=BJ/L=BJ/O=MyRootServer/OU=MyServer/CN=10.10.49.172" -out server.csr

这条命令使用 OpenSSL 工具生成证书签署请求(CSR),各个参数的含义如下:

openssl req: 这是 OpenSSL 工具中用于处理证书签署请求(CSR)的命令。

-newkey rsa:2048: 创建一个新的 RSA 密钥对,其中包括一个 2048 位的 RSA 私钥和相应的公钥。

-nodes: 生成的私钥不使用密码进行加密。这意味着私钥文件 server.key 将不需要密码才能访问。

-keyout server.key: 指定生成的私钥文件的输出路径和文件名,这里为 server.key。

-subj "/C=CN/ST=BJ/L=BJ/O=MyRootServer/OU=MyServer/CN=10.10.49.172": 设置证书主题(Subject)的信息。这里使用了简化的 Distinguished Name (DN),包括了国家(C=CN)、省/州(ST=BJ)、城市(L=BJ)、组织(O=MyRootServer)、组织单位(OU=MyServer)、通用名称(CN=10.10.49.172)等信息。通用名称(CN)通常用于指定服务器的主机名或 IP 地址。

-out server.csr: 指定生成的证书签署请求文件的输出路径和文件名,这里为 server.csr

使用CA根证书签名SSL证书

$ openssl x509 -req -extfile <(printf "subjectAltName=IP:10.10.49.172") -days 3650 -in server.csr -CA selfca.crt -CAkey selfca.key -CAcreateserial -out server.crt

这条命令使用 OpenSSL 工具签署证书签署请求(CSR)并生成证书,并且带有SAN信息,各个参数的含义如下:

`openssl x509`: 这是 OpenSSL 工具中用于处理 X.509 证书的命令。

`-req`: 表示输入的文件是证书签署请求(CSR)。

`-extfile <(printf "subjectAltName=IP:10.10.49.172[,DNS:<YOUR_DOMAIN>,...]")`: 使用扩展文件,该文件包含了额外的证书扩展信息。在这里,subjectAltName 扩展用于指定主体的备用名称(Subject Alternative Name),这里指定了 IP 地址 10.10.49.172。你也可以在方括号中添加其他主机名或 IP 地址,用逗号分隔。

`-days 3650`: 设置生成的证书的有效期为 3650 天(10 年)。

`-in server.csr`: 指定输入的证书签署请求文件,这里为 server.csr。
`
-CA selfca.crt`: 指定用于签署证书的 CA 证书文件,这里为 selfca.crt。

`-CAkey selfca.key`: 指定用于签署证书的 CA 私钥文件,这里为 selfca.key。

`-CAcreateserial`: 创建一个新的序列号文件,该文件用于跟踪 CA 签署的证书的唯一性。

`-out server.crt`: 指定生成的证书文件的输出路径和文件名,这里为 server.crt。

SAN(Subject Alternative Name)是 X.509 证书的一种扩展,用于指定除主题(Subject)之外的其他标识信息。主要用于解决传统的基于主题(Subject)的身份验证方式可能存在的限制,特别是在一个证书需要覆盖多个主机名或 IP 地址的情况下。

SAN 扩展可以包含多个备用名称(Alternative Name),这些备用名称可以是:

  • DNS Name(域名): 用于指定主机名,可以是域名或子域名。
  • IP Address(IP 地址): 用于指定 IP 地址。
  • Email Address(电子邮件地址): 用于指定电子邮件地址。
  • URI(统一资源标识符): 用于指定统一资源标识符。
  • Directory Name(目录名称): 用于指定目录名。

在实际使用中,SAN 可以解决多种问题,例如:

多域 SSL 证书: 当一个 SSL 证书需要覆盖多个域名时,可以使用 SAN 扩展。

IP 地址验证: 当需要确保证书可以与特定 IP 地址关联时,可以使用 SAN 扩展。

多级子域名: 当证书需要覆盖主域和多级子域时,可以使用 SAN 扩展。

SAN 扩展通常在证书签署请求(CSR)或证书颁发时指定,并在证书中进行存储。在 OpenSSl 命令中,使用 -extfile 选项指定一个包含 SAN 信息的文件,通过该文件可以指定多个备用名称。

最终的文件列表

至此CA根证书和自签名SSL证书就生成好了,我们一共收获到了5个文件,作用分别如下:

  • selfca.key:CA私钥,用于后续签名SSL证书
  • selfca.crt:CA根证书,用于后续签名SSL证书,需要加入到操作系统或浏览器的信任列表中
  • server.key:服务器私钥,需要配置到https服务,比如Apache和Nginx配置文件中
  • server.csr:证书签署请求文件,后续没用了
  • server.crt:自签名SSL证书,需要配置到https服务,比如Apache和Nginx配置文件中,这就是代表服务器的身份证件

如果想查询证书信息同样可以使用 openssl 命令查询

$  openssl x509 -text -noout -in server.crt
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            56:76:35:2c:61:a5:a0:7c:8c:3b:26:93:db:c2:95:a7:18:f9:95:f0
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = CN, ST = BJ, L = BJ, O = MyRootCA, OU = MyCA, CN = CA
        Validity
            Not Before: Nov 30 14:43:32 2023 GMT
            Not After : Nov 27 14:43:32 2033 GMT
        Subject: C = CN, ST = BJ, L = BJ, O = MyRootServer, OU = MyServer, CN = 10.10.17.2
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (2048 bit)
                Modulus:
                    00:b3:41:7c:58:c7:13:c1:c9:af:5b:d6:7d:cb:9a:
                    04:f1:73:5f:60:c4:43:df:4e:26:f5:4d:da:48:f6:
                    4f:13:90:c0:6f:17:a8:44:00:9c:3f:a5:f1:5e:6c:
                    28:15:74:5f:c7:c5:0c:bf:a1:7b:b3:31:ac:7c:67:
                    59:58:f6:33:cd:bb:a6:45:85:98:21:c1:79:2c:b9:
                    d2:46:9e:9c:ef:59:ba:d4:0d:fb:4c:86:81:a1:4c:
                    a8:47:d7:4c:cf:13:89:8b:d2:6d:68:85:8f:10:26:
                    87:15:73:ee:e6:14:36:f2:09:d3:c9:2f:f5:bf:c6:
                    e1:ec:ee:54:06:82:83:ee:f7:70:e1:50:2e:a0:44:
                    ce:e1:a4:f9:68:4e:e5:b4:be:39:77:02:1b:ca:c2:
                    c9:55:72:d1:56:ca:e4:47:67:54:1b:d8:a2:83:29:
                    02:0a:1a:b3:81:22:a0:fb:84:cf:d7:43:1c:be:37:
                    bf:9e:04:95:ad:2e:20:ca:2f:04:c8:ef:92:26:7f:
                    5c:f9:1c:94:6d:e5:7b:93:2a:51:fa:d2:e1:a8:87:
                    d4:f8:aa:6d:38:d0:6a:19:8f:48:9d:3a:c3:40:bd:
                    e9:00:ff:cf:f6:67:08:7e:ec:f2:e6:3b:b1:f5:c9:
                    ea:f9:52:5c:f4:68:6b:ee:15:b4:fc:ce:44:6d:86:
                    4d:ef
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Alternative Name:
                IP Address:10.10.17.2
    Signature Algorithm: sha256WithRSAEncryption
         26:c8:f8:bd:dc:a3:67:86:e9:a9:81:ce:1a:be:a4:be:c2:f0:
         10:cf:9f:30:1a:a8:40:ee:1a:41:ab:87:33:7e:35:2c:f0:3b:
         9b:62:79:82:fe:7c:63:6e:e8:65:a7:2d:2e:aa:d9:73:2d:58:
         a1:b6:70:ae:33:5f:28:27:52:a0:06:d9:37:d4:a8:70:85:73:
         34:a4:a0:f4:f0:da:4c:9a:61:ab:74:9d:2f:ff:56:be:e4:7a:
         c8:af:7e:f6:8a:4c:52:dc:13:db:9a:33:63:cb:79:b0:18:78:
         f4:9e:af:dd:02:54:0b:94:b0:94:29:77:92:ae:7a:35:ca:00:
         28:bc:be:c1:a1:1a:47:1b:72:5d:2c:1d:0e:79:e6:45:0e:3e:
         e1:25:dc:4c:e0:cb:a0:2a:ad:98:02:d1:e3:92:68:5a:37:89:
         5e:36:54:ec:ed:8a:b4:8b:f7:26:a9:4e:89:15:5e:ed:b1:26:
         45:b4:03:99:37:74:c1:4c:d4:11:eb:42:3d:a4:3f:a8:30:99:
         a0:61:08:85:f7:9e:4e:15:21:37:c3:61:ea:7e:24:3d:73:85:
         44:28:b1:be:b5:27:26:df:38:49:43:ce:b9:96:f9:48:d4:15:
         4b:49:e6:6c:9e:e1:21:d1:25:af:da:76:e2:7e:ca:da:9e:30:
         60:77:53:70

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值