//-----------下面的是CA证书和openssl相关的知识--------------
【ssl认证、证书】TLS/SSL双向认证概念、openssl genrsa示例
【ssl认证、证书】openssl genrsa 命令详解
【ssl认证、证书】SSL 证书基本概念、证书格式、openssl和keytool的区别
注意:这个扩展名是随便叫的,你叫.txt也行,这里是为了规范使用,便于识别,尽量采用下面标准后缀
OpenSSL执行过程:
//1、生成CA秘钥,过程中要输入密码,这里用123456
openssl genrsa -des3 -out ca.key 2048
查看ca.key的内容:
[root-controller-3:/home/ubuntu/test]$ cat ca.key
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,6034ECBB98C5D57B
Wnd0rLwfSvwpaQDPULnGyyzHp8j4ZG/q0vcTl/82MBpUIX5H+nQO1fjlZlnQUPR2
RnVSm+YAQET4MFERxQrJ4k4cmm3kpdMs/JhoEiWGPLGCJqPiXXhGsyNsdGAn/NHQ
IpUBrXZtxOegi2o5+YBgqwEpUSdy2/GI0WrcZGLeQtXQCLYxo/2ag//KQn4UBkoE
pJnZ+ChIVTr7qqwx97DWjHXqq6YQ684V/sTrypnTrcdtiTl1GKm30DaJWFA+pma0
du4vi2T0fkthwAhBmRbgyPrV0pk6cM6V+3lhX/3k9Shl1MQ1r5jyBCwmG5qmVPt7
tFgk2fCo0K2c5gkSK0oVKzx42TaHLHP5PCV3J+CHtkFmNrj/jX0UYUhucTjhQq0B
es2nGYo9lCzTY75qv4tfbXuKGdWmjXV0xWz/NZlR0CM7dbvHXg0NbtGkxX6ukhAu
AI3FATZwMndOTJpNwt+y2xrnjz2xVjJA9M4VbNkODEioHkhyDJZ8tnFzvywD0Svz
qkx38BAa0ecH03eLfdHiwejgjU+DQv4FGkrAGhMrYdq15gyjvDW2mDloNzf/ZFXX
r1Byqomoki/k5Cs3rdVA6SUnu5EbBQ0L4G1NUapgSotGmvG46rWwNPF7y+zAb/Hk
DuYHz13w6X0VQiiFs8G7PrZfIj81zFNTrWUzJlgozSfLOG9Ay82b9Bs6VN1130pm
UYYnSdOlNtsmlcTujXJI0OWiCq+Vvdh+j6iLIhQ/lT3srxY6R9RkV3nxgP04Xf36
0tXeONrxfp3X8SWw4WapjTAbvDueHr0yO2XjJRseP2wHEjYf4X6oqsF5A1GFcgDx
V2FA2IoRTSKkF3FZYu03QzZ6C+a7BDYNyerL5xQa6R2JLJWTVQBRBS1mH0d8flpa
X+AQUu6oI8wPmqIDw8Gupai5+TUTy8wVIUbD7NNH98Ow0KMM6WaHIlduAsy3jjY1
vJaCu/wDCR2madmWDxOlcKyXjcmsK/SexdJjJH6WkLEfKNm3Jby6Xkf49Igk//mt
BhDNZHrYKwBlF1hGMEMQ9MCorZND84nNoY+iSFS5noGhy7/Z9v8QJLXYe9tOMU7H
e/IYZa+IgUaeU/kXapWmQ53zDRQIKkvflWkoZlMEMrG1eYryQ4Cs87474O5RN3mn
g29L9OceSTQlwFG5oD567RNcips5xEYTDXtAq0hu8j8iwYkCPNceQyaum+4MvbYS
oiBHbd+N+7NCaIxs9RBM2cqqgOf0EMgbV2rNtJZHvL6MlxD66eFxNihe4u7xnTiZ
pqLEeihjKxTWbvPx0kKdcw9f2uCnmZtGcYSeZSmOfOQDdbw3WMyBsJBkC9+2+J2o
CRkCl90PiE7i4S/hR/0m7ONLqmKqHsuSj3Ai6nL8iJNJDMsJIp+miVTlFZhqFsag
6/mqIq3bYwQRTzF3L4yGII2iSXmW+p2obnz7YSlE32+cTcbvOm4LoPrcA878aUOD
CShHY5dO1FKzgq0hhoEVcSnnl61ORZJpH0HbarngKX7etsyMLq47OR7trdMBWI3O
Es6lueObyjP03bcT2lTF524f58hYIEVRmlPmEM7z9fDs0OH1VDPOA9xbLXCWjTV8
-----END RSA PRIVATE KEY-----
//2、生成CA证书请求文件,过程中输入密码:123456
openssl req -new -out ca.csr -key ca.key -keyform PEM -subj "/C=CN/ST=省/L=城市/O=单位/OU=部门/CN=域名或ip"
keyform和subj都是可选参数,只是提供更完善信息而已
.csr 是证书请求文件,是由 RFC 2986定义的PKCS10格式,包含部分/全部的请求证书的信息,比如,主题, 机构,国家等,并且包含了请求证书的公玥,这些被CA中心签名后返回一张证书。返回的证书是公钥证书(只包含公玥不含私钥)。
也就是说公司名称等这些参数是放在请求文件中的,并且含有公钥,一并交给CA机构,公钥怎么来的?是利用私钥生成的,因此这个步骤入参需要私钥
证书签名请求是申请人向证书颁发机构发送的一条消息,用于申请数字身份证书。
有 CSR 必定有 KEY,是成对的,CSR 最终变成为证书 crt,和私钥 key 配对使用。证书下发后,CSR 就没有用了,只是在交时候需要。
查看ca.csr:
[root-controller-3:/home/ubuntu/test]$ cat ca.csr
-----BEGIN CERTIFICATE REQUEST-----
MIICyDCCAbACAQAwgYIxCzAJBgNVBAYTAkNOMQ8wDQYDVQQIDAbDp8KcwoExFTAT
BgNVBAcMDMOlwp/CjsOlwrjCgjEVMBMGA1UECgwMw6XCjcKVw6TCvcKNMRUwEwYD
VQQLDAzDqcKDwqjDqcKXwqgxHTAbBgNVBAMMFMOlwp/Cn8OlwpDCjcOmwojClmlw
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxXTdnBNsceXd5cc8KZPI
dr6wZiAUwYNdnY+eprQXd52CBXhPAiV0VQlJkYfZZqPN60Lyl3KNqLpQIjR4fhka
yr5waeG+D+b9vhPMWPdp6C6xTbZ8bWlXdpWD5iOQUdk8/GAh7GiFZbow7aMoWqTk
TmtZZAU086msZ7VY5ArTy5oiiQNfk+OoRT3Qj2yoAlJTQ2zjbgz8NxK8AU6oaD9U
PoGVTDQkvQ5KhG+KjhQcbZkEb3cd24Q7lsL6WqRdx/c6yOrkpgN/B5rIjVPmVOUx
CFSl/5WapvWd4bBuWn9cODL7YPmGU+2TdqXPzzI1Y714NL/mIIHM9Pnr0XVLIa4g
FwIDAQABoAAwDQYJKoZIhvcNAQELBQADggEBAC4Xmz9hEb3qw4XBvsmvmK/Zcgiz
eNrkFwccCVOs/BVZcV3dCtBCnAkJzxpM5oR9/7FQPRg70AgRg/uJMeoCZgaTaIOr
vQgdzk49UquLZyJwDpbHc922BbdUSsPj6Y/7PKW8dWrkRtekntA11I6ifam0fgBv
vT4qyqkUFAS/EPPsErldHWLyk/0qJ9pOdam1MuETKvN07Twb5MBGVsDNPpB3eoM9
jXhGWehj0i74sSZb9eJoyDFfdvX1DFWphU+/5Djv4xANiBZbeCFN4FQOGPRS69YU
FRngPtshMVllDSNlmvWZE5Y/mz7p3/3WFn+xCPwbvFazD/+9A8QIuhCPcrQ=
-----END CERTIFICATE REQUEST-----
//3、生成CA自签名 根证书,过程中输入密码:123456
这一步是模拟CA公司执行的命令;之前的步骤私钥和请求文件都是客户自己生成的
openssl x509 -req -days 365 -in ca.csr -signkey ca.key -out ca.crt -CAcreateserial
生成了ca.crt ,查看ca.crt内容:
[root-controller-3:/home/ubuntu/test]$ cat ca.crt
-----BEGIN CERTIFICATE-----
MIIDgjCCAmoCCQDrYTDSFjBJdTANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMC
Q04xDzANBgNVBAgMBsOnwpzCgTEVMBMGA1UEBwwMw6XCn8KOw6XCuMKCMRUwEwYD
VQQKDAzDpcKNwpXDpMK9wo0xFTATBgNVBAsMDMOpwoPCqMOpwpfCqDEdMBsGA1UE
AwwUw6XCn8Kfw6XCkMKNw6bCiMKWaXAwHhcNMjMwMjA4MDY1MjM4WhcNMjQwMjA4
MDY1MjM4WjCBgjELMAkGA1UEBhMCQ04xDzANBgNVBAgMBsOnwpzCgTEVMBMGA1UE
BwwMw6XCn8KOw6XCuMKCMRUwEwYDVQQKDAzDpcKNwpXDpMK9wo0xFTATBgNVBAsM
DMOpwoPCqMOpwpfCqDEdMBsGA1UEAwwUw6XCn8Kfw6XCkMKNw6bCiMKWaXAwggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDFdN2cE2xx5d3lxzwpk8h2vrBm
IBTBg12dj56mtBd3nYIFeE8CJXRVCUmRh9lmo83rQvKXco2oulAiNHh+GRrKvnBp
4b4P5v2+E8xY92noLrFNtnxtaVd2lYPmI5BR2Tz8YCHsaIVlujDtoyhapOROa1lk
BTTzqaxntVjkCtPLmiKJA1+T46hFPdCPbKgCUlNDbONuDPw3ErwBTqhoP1Q+gZVM
NCS9DkqEb4qOFBxtmQRvdx3bhDuWwvpapF3H9zrI6uSmA38HmsiNU+ZU5TEIVKX/
lZqm9Z3hsG5af1w4Mvtg+YZT7ZN2pc/PMjVjvXg0v+Yggcz0+evRdUshriAXAgMB
AAEwDQYJKoZIhvcNAQELBQADggEBAMFNvG5Oma0jS7IUeVJjvJjwVnmS+ICAspVF
I8aKp3ArGYxS26YeTpr3jHznFJTDl6UzLRZfSSmRvk/zsNWIY8GHduq/c9lyQdG3
J1mKmmYgHWDkdyAY353nWUaYJtal6y5e1WhfQ6MyOd9uzigDpkBNFtXhyshcT24/
l64NGUQbvgrvXatbPdJyJf82ZUNGr6jnLL0nQ1ofkQ5D4tTi1Qk/4y6VBzqUQ2Z7
NWrHc3hgp4UylNV4UjM7WJ2nE/MdGMXWaXKSN7lo5bLGfKG9MIiWhXQCk6vTn3++
D9vkZzLLAS/QHw57WzXWOJYEiTt3BYBFcGybdg6y/pJwozy6LJI=
-----END CERTIFICATE-----
//4、生成server端秘钥,过程中输入密码:123456
openssl genrsa -des3 -out server.key 2048
生成了server.key
//5、生成server证书请求文件,过程中输入密码:123456
openssl req -new -key server.key -out server.csr -subj "/C=CN/ST=省/L=城市/O=单位/OU=部门/CN=域名或ip"
生成了server.csr
//6、生成自签名SSL证书,过程中输入密码:123456
这次和以上不一样,加上了一个中间人 CA
,表示这是由 CA 认可并颁发的证书
openssl x509 -req -in server.csr -out server.crt -signkey server.key -CA ca.crt -CAkey ca.key -days 365 -CAcreateserial
生成了server.crt
注意:生成了证书,证书内含有公钥,因此,不需要单独提供公钥
//7、生成client证书,与生成server证书过程一样,重复4-6步
分别生成 客户端密钥 client.key、客户端请求文件client.csr、客户端证书 client.crt
总结:请求文件是中间临时文件,不会在代码应用中体现,而密钥和证书都会在代码中体现
网上有一些http和https的SSL双向认证示例,没有挨个尝试,可自行搜索引擎。这里写一个Websocket的示例,仅供分享。
Python环境:3.6.6
依赖模块:websockets
这里引用了部分Websockets example中的示例代码,感谢!
server.py(server端代码)
#!/usr/bin/env python
import asyncio
import pathlib
import ssl
import websockets
async def hello(websocket, path):
name = await websocket.recv()
print(f"< {name}")
greeting = f"Hello {name}!"
await websocket.send(greeting)
print(f"> {greeting}")
//服务端声明CLIENT_AUTH
ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
//certfile和keyfile参数为,证书及文件的路径
ssl_context.load_cert_chain(certfile="cert/server.crt",keyfile="cert/server.key")
//load_verify_locations加载客户端证书
ssl_context.load_verify_locations("cert/client.crt")
ssl_context.verify_mode=ssl.CERT_REQUIRED
start_server = websockets.serve(
hello, "localhost", 1234, ssl=ssl_context
)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
client.py(client端代码)
#!/usr/bin/env python
import asyncio
import pathlib
import ssl
import websockets
//服务端声明SERVER_AUTH,并加载server端证书
ssl_context=ssl.create_default_context(ssl.Purpose.SERVER_AUTH,cafile="cert/server.crt")
ssl_context.check_hostname=False
//certfile和keyfile参数为,证书及文件的路径
ssl_context.load_cert_chain(certfile="cert/client.crt",keyfile="cert/client.key")
ssl_context.verify_mode=ssl.CERT_REQUIRED
async def hello():
uri = "wss://localhost:1234"
async with websockets.connect(
uri, ssl=ssl_context
) as websocket:
name = input("What's your name? ")
await websocket.send(name)
print(f"> {name}")
greeting = await websocket.recv()
print(f"< {greeting}")
asyncio.get_event_loop().run_until_complete(hello())
手把手实现TLS/SSL双向认证(附Websocket实现代码)