本地建立CA签发数字证书

CA简介

CA(Certificate Authority或Certification Authority,数字证书认证机构),是负责发放和管理数字证书的权威机构,承担公钥体系中公钥的合法性检验的责任。 CA中心为每个使用公开密钥的用户发放一个数字证书,数字证书的作用是证明证书中列出的用户合法拥有证书中列出的公开密钥。 CA机构的数字签名使得攻击者不能伪造和篡改证书。 为保证用户之间在网上传递信息的安全性、真实性、可靠性、完整性和不可抵赖性,不仅需要对用户的身份真实性进行验证, 也需要有一个具有权威性、公正性、唯一性的机构,负责签发(也称『颁发』)并管理安全证书。

其实,每个人都可以当CA。 以下基于Ubuntu来讲如何利用openssl来建立一个本地的CA,在命令行签发数字证书,并对证书进行认证。 (其它Linux和Mac,操作基本相同。)

默认配置

$ locate openssl.cnf
/etc/ssl/openssl.cnf
/usr/lib/ssl/openssl.cnf

/etc/ssl/openssl.cnf就是openssl的默认配置文件。 其中,比较重要的配置如下:

[ CA_default ]

dir             = ./demoCA              # Where everything is kept
certs           = $dir/certs            # Where the issued certs are kept
crl_dir         = $dir/crl              # Where the issued crl are kept
database        = $dir/index.txt        # database index file.
#unique_subject = no                    # Set to 'no' to allow creation of
                                        # several ctificates with same subject.
new_certs_dir   = $dir/newcerts         # default place for new certs.

certificate     = $dir/cacert.pem       # The CA certificate
serial          = $dir/serial           # The current serial number
crlnumber       = $dir/crlnumber        # the current crl number
                                        # must be commented out to leave a V1 CRL
crl             = $dir/crl.pem          # The current CRL
private_key     = $dir/private/cakey.pem# The private key
RANDFILE        = $dir/private/.rand    # private random number file

所以,默认情况下,需要在执行openssl的目录下准备一个demoCA,这样会比较方便。 下面用更简洁的方法来展示从签发根证书、到签发服务端证书的过程。

根证书

CA的根证书准备,只需要三步:

  1. 生成CA私钥
  2. 生成根证书签发申请文件
  3. 生成根证书

生成CA私钥

$ export CA_PWD=********
$ openssl genrsa -aes256 -passout pass:${CA_PWD} -out ca.key
Generating RSA private key, 2048 bit long modulus
..................+++
..+++
e is 65537 (0x10001)
$ cat ca.key
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,E2F90E5145E2F31E3D1C62805588F8EB

rSnW0uRYmbT+xcXI73jMoy8QgCJxZjhKSaqpmuvCsWBGAN1XZohHpyn2uJfhKl+f
4fHMUD6oLHsxtBejd310WZo4jrmN1mxVraAjWjuZLocWc3fA6sHMz/KVvyjQCKZx
5OwCzgzW7qzhLPfrce4UeinuBoUimY7+nXNFMK3mUMFaiFNM1jhsa9AUqxSGrpxz
+ESLCd+eq+jq7noUc7OYL/pUaY830XoFMNTfoIxrwPVz5cVhKzINnLBhgmBH2jGF
y4lKQzbVh9c9P02hnBG6RN/FYhl73UVJgjOPOkTCjoX4SivxrMUCOuL5D4ZoH/K5
D8TvjwfOW08c0Esg+R7bKHWkY7I+A/xFuAfPZPDsQKY0lDvBQDCgGTeR3uCXrIXt
ZCy9Wb5GSfgNQb0rWLL7NDjteoW1Yf7jXpYRbph5LEWFMbc0I5tk4C6YmABxzIbX
WGWVoD7pwzog8E93w3UzIQ/38U+KK0k0YT9XftVk/OTHPDHRPTLP3YL/QYFNxgHA
QACNup1Ql8RN8hHT+Pm0B4q1AHpbNc9N+gX5r2Ts6V/DyAnoc3yZeXv1pa4XY7So
PTwm/lOM4VPikIzaayJ29eh5CLEv4+EpjhwImI8bcpfWhPLL+K0v9SmW/5j1D8AL
KGtdctNtXw7D+87kVtZr7NUvLC8izMEU6PxMd8MkEu6Chc1cRtsyfbfLbmTUC9hE
OTQRiOW3U4gFkZVOr7cUmuV/t87MLtIm/JP7NN+ivOVojfSf4a0fKWYD7z2eLOIQ
7XxsfhAMhwOPB/KpaEK5UtKI9leXY9t4C1JO68t20TSbY36SgkBMi7MgdiiMo2KF
e3omI95zx4jS3Zc1Vb8BeBfNIKReuzoqlwyNVBzl5V8GIAMfSMk6WZ6KMRxc77yI
xac0p6lE/9aPnJ3W6XOsNw3ium63lkP8/F9OayOJVeH4VNWZc2RzGumB9mb/RriC
tGnXXuzKhfrEnsiz7OsCbWxRB6BSTHy/+enzkT8WCMSVYFqFSWtPbFoCo2XwwQY4
ACtn0RD7c3G+WTcyQtPVoaMGXIioJjfM8mb0efHRoC+bjcLlNpaNe36NtIEhiEEC
x421AQhHKV8XAjRU0qO0dCbsGwd9hlBny+gamBzsjsX/IPpJ6/z2lGl6QhF+XZS3
4zTyIkP6uhsx8W/hBWcZ1vI5i8PY3ZwiewiTQCiv0CNF/DxJQvDn/xkZxAHqx7DY
WinPJ6huwbk5XU147onSjxcyDjKaMQY27BgbS4WbkFXO/Ha+KXupMXBvmbfBHURJ
+EHByhkKexZZDT2Rtaxelh/1diYdUmeovocyx9IKnajuqZnPtw8jY+q6lYd2T92d
ksW1Kk97UduW6Gdg2FTzDRiAvZGvzHw6aT1pDP6lQMUGyvCmZHBrQzmETMw68kwr
IzHZxEtp//3bL1v45XnPoavGftz25AOVywcsILzlkr6T6tOxH7hVKdmoFTY3Mbrw
TWHCfY1PqzwpMC7lAh/mXs8ZhP/XcnOnuxcOHvWd1ER1HVZcCvp/C7bgA0W+g6QD
OFD06HWNmC0vQFqAKNN3VCjMjVoAc/uoXmELHNlFJ7VEYxfLNWqd0uRHLpY+isWY
-----END RSA PRIVATE KEY-----

OpenSSL通常使用PEM(Privacy Enbanced Mail)格式来保存私钥。 这里命名为ca.key,而非ca.pem,只求更直观。 (这个私钥,和ssh-keygen产生的RSA私钥,其实差不多。)

命令参数解释如下,详见《genrsa - OpenSSL》:

生成根证书签发申请文件

CSR(Cerificate Signing Request,证书请求文件)是用来提交给证书签发机构的文件。 用CA私钥给CSR文件签名后,就得到了根证书文件,也即公钥。

$ export validity=1461 # 4 years
$ openssl req -new -days ${validity} -subj "/C=CN/CN=example/DC=note/DC=qidong/DC=name" -key ca.key -passin pass:${CA_PWD} -out ca.csr
$ cat ca.csr
-----BEGIN CERTIFICATE REQUEST-----
MIICqDCCAZACAQAwYzELMAkGA1UEBhMCQ04xEDAOBgNVBAMMB2V4YW1wbGUxFDAS
BgoJkiaJk/IsZAEZFgRub3RlMRYwFAYKCZImiZPyLGQBGRYGcWlkb25nMRQwEgYK
CZImiZPyLGQBGRYEbmFtZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
ALjKishvKWYLSkd9K//nP1gymDxC7TTg/nDNr9ZyaU38jfJ480vJEiSNK8Um5YGx
68CDkGJKgWrytJhZbF3djXM2vV4m8DuZ+czwvqaQ2qrXVbZyYWlA3jDMBLxdHG1g
PhMnkJT8cnE/OlBhYoE4nyR6s+wCQfLs/WvMWAQkgS0EORFTgfXX66cSuz/d5isN
NN9N/E2B5toS/ywMgzHcLi312Fsk+z8q/kNbtXXGgtFkLQz2rwDvLyVMjx/HjZHV
1knXJb8M6RXoJSF8DNlEOTql21EWFfYto/tsT7OE7/1H+BS9XuoOYHf4FgZiRkyN
YVFnEiNdqR4XA1g8yjy0CUECAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQBOKL7t
iXL89x8ur7ObRx6VGX3zZFqnAEiE7HAMJbn3cJS7cyCrNlu5QKymnpMUiT3yJ+AL
WSBSrucCVAqW3bjXBy2EpRQLFz/qTaIQOZYFVIkKjDyBlkNdr/DBAl6u5NRkAUkd
uSX3DgdD2pNSHJIZIyrXyrdKcOO67OP4G0luK2qsniG6lCletqnvdqWLUYzXlfud
e4SET/TCHDBFo6IrCaShigyVWLGxxnSB937o/JgCMefhW349NAcLUevhwf5Mbt5k
ZuZ9wK6gQ5BYSrOVYdIMInbQyflPRt1T3TAp9R02l7QPBe0VIJhPcUQT+MQ4vQji
48g1y1m2CSEAAu1q
-----END CERTIFICATE REQUEST-----

命令参数解释如下,详见《req - OpenSSL》:

这个-subj看似杂乱无章,其实暗藏玄机。 它的本质就是一组键值对,一般形式为/type0=value0/type1=value1/type2=...。 但也并非毫无意义,一般采用RFC2253规范来指定一组信息。

String X.500 AttributeType
CN commonName
L localityName
ST stateOrProvinceName
O organizationName
OU organizationalUnitName
C countryName
STREET streetAddress
DC domainComponent
UID userid

上面的/C=CN/CN=example/DC=note/DC=qidong/DC=name,涵义可以对照得出,就是中国note.qidong.name的一个叫example的组件。 其中,省市街道这些信息略过没写。

生成根证书

$ openssl x509 -req -days ${validity} -sha1 -extensions v3_ca -signkey ca.key -passin pass:${CA_PWD} -in ca.csr -out ca.cer
Signature ok
subject=/C=CN/CN=example/DC=note/DC=qidong/DC=name
Getting Private key
$ cat ca.cer
-----BEGIN CERTIFICATE-----
MIIDQjCCAioCCQCGY66stRpanDANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJD
TjEQMA4GA1UEAwwHZXhhbXBsZTEUMBIGCgmSJomT8ixkARkWBG5vdGUxFjAUBgoJ
kiaJk/IsZAEZFgZxaWRvbmcxFDASBgoJkiaJk/IsZAEZFgRuYW1lMB4XDTE5MDEw
MzE0MTMwMFoXDTIzMDEwMzE0MTMwMFowYzELMAkGA1UEBhMCQ04xEDAOBgNVBAMM
B2V4YW1wbGUxFDASBgoJkiaJk/IsZAEZFgRub3RlMRYwFAYKCZImiZPyLGQBGRYG
cWlkb25nMRQwEgYKCZImiZPyLGQBGRYEbmFtZTCCASIwDQYJKoZIhvcNAQEBBQAD
ggEPADCCAQoCggEBALjKishvKWYLSkd9K//nP1gymDxC7TTg/nDNr9ZyaU38jfJ4
80vJEiSNK8Um5YGx68CDkGJKgWrytJhZbF3djXM2vV4m8DuZ+czwvqaQ2qrXVbZy
YWlA3jDMBLxdHG1gPhMnkJT8cnE/OlBhYoE4nyR6s+wCQfLs/WvMWAQkgS0EORFT
gfXX66cSuz/d5isNNN9N/E2B5toS/ywMgzHcLi312Fsk+z8q/kNbtXXGgtFkLQz2
rwDvLyVMjx/HjZHV1knXJb8M6RXoJSF8DNlEOTql21EWFfYto/tsT7OE7/1H+BS9
XuoOYHf4FgZiRkyNYVFnEiNdqR4XA1g8yjy0CUECAwEAATANBgkqhkiG9w0BAQUF
AAOCAQEAes70Mi8r/hALHVb0y1R4zRG0y2KEUCk51wt0vjWkJ1CrxYFOlEFhk//n
gGIlClJAn6nvXTvSMLoFzsXBjgkdqmKkqMUg32YFGhH+V1BsNBSjGGF89je/vaIw
3oGwnHsqkW8k0QNfgUM6ANrBfYkWAqJoMpok8JAmH9xslAFqEQtVs1PmOQAaGhg8
3dbw3U3iTSJ4TzB7swgCuFDJvn/bMLF2l8/vdIJrWIBFSOAJh5YupFqoLSYutjwp
mTbcJdoa1kYDYqqs4obQr8dOBYtv0F7udroepP+PkKxOEm0ucJByn9MypQEYxS7H
b5UjWd4rIFV+SBz9Yd5Apz8KYFpLpA==
-----END CERTIFICATE-----

命令参数解释如下,详见《x509 - OpenSSL》:

签发证书

生成服务端私钥

$ export USER_PWD=********
$ openssl genrsa -aes256 -passout pass:${USER_PWD} -out server.key
Generating RSA private key, 2048 bit long modulus
...................................................................+++
.......................+++
e is 65537 (0x10001)
$ cat server.key
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,FB9145090BCC8CA2FEAB0939E40CA8DC

0mXI/ggnQ49E01XJNwLRC6ZbvhWJ8A7RAiiwQAomBcjCyxprjj+e6NFJPZcpvtJD
80q+7ZqWaTNbHfy+7A4oaZbuIBDK0RjxIET6aFBnWgYDBZPTXZ2kXafeXPJ4gpCG
ZXm0u1EqmmGTQcwHq6n/hdwwc9JFvOo1iPPn6/SIqKmZYgfFT9ueRW6EhhrsNpbt
JjfSUdHrWnSbzgZah6Eus/LKGNDnIQ3T9FVvwXoAQwKgD+VkWQIXooFf1zz7QE+d
jPeCSgYWkJOD9am/GrGxaKuZPlfDgKoz1hDChzMnsZvUZIDjHq4PN7NXBxd1m0Q9
tz952LE396zRZZM8FRH5/JmckJelGIsrwG/lXFk/i0KImpn/7Tb1BK76RIMthFdv
Fr1BGPqYMoNXb85Kg0hxVCULNpckUPG3M5Qo7bSRILyCxX2KpFKQLTH7Z3u31P9P
3m4V+hvgOFScCDWuEGmBEpINnnll139ZatInevaVC49oGGMUK+1Zhxw0707UqvvQ
XEWcdVlUZjbxVGhTCOLt7GCSSg1wumUOwSSbshu/WL1tmRCcwM/ZXUZjJTo2jnpy
cDnyMBYsSx4vLLgh2K1w6qqC1kWB2QRmnMvZ1SGSJdtevzfjMTNyUa+8wVp9k2xF
GbbauwMb4pQ2K53ux5Uzl+n1FYJvcImbLLzed5fUU2HOOSAPUIYH0a3VncN8H5Mf
HF4JquD4l32XLmFHS1d05oQTHeVfb8K94o1V7Z1mfgDqBIHjfj1jR/aCn+lGNwkC
a7rf1XJ2jCJk4gYktuGvlVL8jcD2srjUaXfEJh5Xhci5uL4Hp4CmqHi9r2BcnzTX
9b8gipjyAzebCqu7cQyVkDKTV/oezhfTMzzG7Ichd/iWYgtNrMPJI+CCvLE9Az2V
/dJzXdRTZIBrApK/mUnCqwC2qVm73zNdjUR2Xce7IY7vfEWUmerlLKGz5+mlgTyI
2o3gl+5bUII74mYMVkaoOiNCpAssXNmmBetpCdbCU/ij0kEBNBfMbjgdOJ1w2f1M
SI0R5+CeXtxeDtYDhRQJiufvDiAJl8HySgPLHrJWpAU2W7FY8yF8ix8HWnXRUFYw
IJwEBRY6X7QNgGYt4POivZocmdTp2p2+4z41SnTvemamR3qU/nx1toTnHZ19dRo9
hDDge7jzMrfjPe0ZlMiOUk8PVtScIY+h7U8CFSnnO4+I5MA8MNBHtbwL+/u6ss+M
sFr7N2KGBPVWXZtOkZkEZwWHxWIzZjZobXosaeQxgDfM7riObW8QiCfChqB5zigB
/G0oLf6qpVrwXP9fszGWmpXvRq81VbL66LFU+aLCIyICkVsp9Z7mJZ5H1M8Ki0CH
Z9NtZVI8fo2hyKe769wpf9hdWQeBSrm4iNn62RPR4UZpP/Kcm9kuiqV9DxKrNs1v
89CVL5DvH2JfziRk/OxlT2pzGttPNCTHkwAJkwpn3tVQZMR/uJMNgdEtvg4x4RRb
s85+WZCiETYF7d5p7GF6E8jnRnYwPsYdPAo7yCv83uNxBleiaqDFPKXSaJks6Z/v
id3n+bnWWJIq6HY4v9XAdXIle5UwU4NCvLZjwm0zxcc7d84f43l8kiGeEsH6R3LC
-----END RSA PRIVATE KEY-----

这个server.key和前面的根证书私钥ca.key,没有本质上的不同,只是所属不同。

生成证书请求文件

$ openssl req -new -days ${validity} -subj "/C=CN/CN=example/DC=note/DC=qidong/DC=name" -key server.key -passin pass:${USER_PWD} -out server.csr
$ cat server.csr
-----BEGIN CERTIFICATE REQUEST-----
MIICqDCCAZACAQAwYzELMAkGA1UEBhMCQ04xEDAOBgNVBAMMB2V4YW1wbGUxFDAS
BgoJkiaJk/IsZAEZFgRub3RlMRYwFAYKCZImiZPyLGQBGRYGcWlkb25nMRQwEgYK
CZImiZPyLGQBGRYEbmFtZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
ANDdgvdDxcTRG/3CugKkBf55OJ/Znd/9OCDtHnTdtGv96dXybWg92lCvP2Pdm2ZV
UAiTl41t2MyXeq1BvWOSHlpD7+DJhctCAdgqF1ovU3dBanTK5cB8S8uLgAn7FHTz
Tjifuop3Cb5awPCI8PLDaiIi0tRzsFfXpmMizHrGBczhKODSYQpoHrWE3p20S+Rr
zpjLk6LwtfnbIVp7zPiS11tgKpqc1H3X+/npeK/9LsrOfm7rXkyOGhIhUYUARdjC
x6SYCJuf5QBad0WRV3wlFuDHsfMJGVXyVS2HxIEBPp+8fKSqePPyHG4AUsnyxjPL
HC+J1RhyAEKRh/fZt5/r3XcCAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQAxq5G1
0WB0XZf0cQv5JMuniV2W+wjma9mnHwCEAFgDY4dfuPWdsexSgg6AOKUcDZmu4hTG
qAJGKE8A9/OGN4U2rtwn6anwiksAA5kaRQICoTKECGT+iQbrYFoTWxB8N6mRanQL
17b7Pam21IoHAmhk6y0lrZOFE2BD1AQ+mo5aH1Nw9J4DmAqGxivAI9uC0nhAjR4h
kmlFDOkjYhRdrIYqbQwO3GYzjNYxqNlWivWbvEo7Zu0DuRCGho8mlhj5cOtYkQfb
0qoMzuKJg2n6BgSEiQbiEw7oej3x4+HoD/yNaB3jSW7fnl/Um3tFtd3fL/lH0SOr
SIAe5n8tSVqY+pF+
-----END CERTIFICATE REQUEST-----

同样,这里也是用的req子命令。 需要注意的是,在-subj中会指定证书目标的用户名与IP(或域名)。

使用根证书签发服务端证书

$ echo 00 > ca.srl
$ openssl x509 -req -days $validity -sha1 -extensions v3_ca -CAkey ca.key -passin pass:${CA_PWD} -CA ca.cer -CAserial ca.srl -in server.csr -out server.cer
Signature ok
subject=/C=CN/CN=example/DC=note/DC=qidong/DC=name
Getting CA Private Key
$ cat server.cer
-----BEGIN CERTIFICATE-----
MIIDOjCCAiICAQEwDQYJKoZIhvcNAQEFBQAwYzELMAkGA1UEBhMCQ04xEDAOBgNV
BAMMB2V4YW1wbGUxFDASBgoJkiaJk/IsZAEZFgRub3RlMRYwFAYKCZImiZPyLGQB
GRYGcWlkb25nMRQwEgYKCZImiZPyLGQBGRYEbmFtZTAeFw0xOTAxMDMxNDE3MDRa
Fw0yMzAxMDMxNDE3MDRaMGMxCzAJBgNVBAYTAkNOMRAwDgYDVQQDDAdleGFtcGxl
MRQwEgYKCZImiZPyLGQBGRYEbm90ZTEWMBQGCgmSJomT8ixkARkWBnFpZG9uZzEU
MBIGCgmSJomT8ixkARkWBG5hbWUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQDQ3YL3Q8XE0Rv9wroCpAX+eTif2Z3f/Tgg7R503bRr/enV8m1oPdpQrz9j
3ZtmVVAIk5eNbdjMl3qtQb1jkh5aQ+/gyYXLQgHYKhdaL1N3QWp0yuXAfEvLi4AJ
+xR08044n7qKdwm+WsDwiPDyw2oiItLUc7BX16ZjIsx6xgXM4Sjg0mEKaB61hN6d
tEvka86Yy5Oi8LX52yFae8z4ktdbYCqanNR91/v56Xiv/S7Kzn5u615MjhoSIVGF
AEXYwsekmAibn+UAWndFkVd8JRbgx7HzCRlV8lUth8SBAT6fvHykqnjz8hxuAFLJ
8sYzyxwvidUYcgBCkYf32bef6913AgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAFNe
DJQJb1KI9ncf/FlSuyFckyNHbqWoO8eVTCMm4X0n8EsaEojt6jw/s/ZjY2vJeq9N
3P9xWy/9TJp5N2yeaZeYeldJsyrlsAR+T2nXQSfsZy7hZ4ihH0DRgvdjNlnOzrnq
ddlMu4zPI0EQoIe6gyVIFFmWx0L409XwfhErVeY5W7Do3idRR4d0bSi1NpyeAQkU
7JJuJrCIGLHIocuSknlfAuh24evWtVnYOU0RkV1XkaaloIM5HHmtfo+5kPP0cXWe
3eDhn9yCowxoe4UkVDRl2J4cu6Yrui/Y7tfvS5blua2yZ047VojHwIAG9rX15BhY
g6ldcR4S6mPQ5y23Zcc=
-----END CERTIFICATE-----

认证刚签发的证书

$ openssl verify -CAfile ca.cer server.cer
server.cer: OK

参考《verify - OpenSSL》。

结语

以上展示了建立CA、签发证书并认证的完整过程。 虽然没有过多地介绍原理,但只要跟着手工执行一遍,比看完一篇原理详解的介绍文,还要更有实感。 不过,过程中省略了证书链、证书吊销等内容,并不完整。

刚才签发的证书,其实用途不大。 个人的CA,需要把根证书ca.cer交给用户,安装到系统或浏览器之类的客户端中,才能真正的起作用。 否则,在严格的证书验证策略下(这一般是默认策略),网络交互会失败。

参考


相关笔记