podman+openresty+openssl,https双向认证demo测试

前言


暂不讨论https原理,单论配置的话:

1. https单项认证

  • server: server.crt + server.key
  • client: server_ca.crt

2. https双向认证

  • server: server.crt + server.key + client_ca.crt
  • client: server_ca.crt + client.crt + client.key

关于podman环境,可以参考:
https://www.cnblogs.com/brian-sun/p/16694334.html

OpenResty® 是一个基于 Nginx 与Lua 的高性能 Web 平台

正文


1. podman 拉取并配置 openresty

1. 检查podman镜像配置
$ cat /etc/containers/registries.conf
unqualified-search-registries = ["docker.io"]
[[registry]]
prefix = "docker.io"
insecure = false
blocked = false
location = "docker.io"
[[registry.mirror]]
# location = "j3m2itm3.mirror.aliyuncs.com"
location = "docker.mirrors.ustc.edu.cn"
2. 拉取openresty的 alpine 版本
podman pull openresty/openresty:alpine
3. 检查openresty镜像
$ podman images
# REPOSITORY                        TAG         IMAGE ID      CREATED        SIZE
# docker.io/openresty/openresty     alpine      e8525d25acd9  6 weeks ago    87.4 MB
4. 试启动openresty容器,拉取openresty到本地
# 启动openresty容器,将容器的80端口映射为本地的12123端口,允许容器登录,允许容器后台运行,命名容器名称为openresty
$ podman run -itd -p 12123:80 --name openresty openresty/openresty:alpine
474650d9317c37e31dad4a6dd9aa48260b35af35091e25204a7673119ee9ab9f
# 检查podman正在运行的全部容器
$ podman ps -a
CONTAINER ID  IMAGE                                 COMMAND               CREATED        STATUS            PORTS                  NAMES
474650d9317c  docker.io/openresty/openresty:alpine  /usr/local/openre...  4 seconds ago  Up 4 seconds ago  0.0.0.0:12123->80/tcp  openresty
# 拉取容器中的openresty文件夹到本地
$ podman cp openresty:/usr/local/openresty ./
# 停止并删除原容器(镜像文件可以理解为vmware中的.iso镜像,容器就是安装好的一个虚拟机,拉取容器中的文件夹为的是以后做文件映射,让容器使用本地的配置)
# podman stop 和 rm 后面可以跟容器的name或容器的id
$ podman stop openresty 
#openresty
$ podman rm openresty 
#22e336479ac85be56561b06fd7a9157ca3d720d53047893eba9590ed021961bf
$ podman ps -a
#CONTAINER ID  IMAGE       COMMAND     CREATED     STATUS      PORTS       NAMES
5. 用脚本启动podman openresty容器

start.sh

#!/bin/bash
#podman run -id --rm -p 12123:80/tcp -p 12443:443/tcp\
podman run -idt --rm -p 12123:80/tcp -p 12443:443/tcp\
    -v /home/brian/podman/openresty/openresty/nginx/conf:/usr/local/openresty/nginx/conf:Z \
    -v /home/brian/podman/openresty/openresty/nginx/html:/usr/local/openresty/nginx/html:Z \
    -v /home/brian/podman/openresty/openresty/nginx/logs:/usr/local/openresty/nginx/logs:Z \
    -v /etc/localtime:/etc/localtime \
    --name=openresty  --privileged=true openresty/openresty:alpine 
    #--name=openresty --net host  --privileged=true openresty/openresty:alpine 

其中 --rm 表示容器退出就自动删除容器
-v 表示文件映射,格式为 -v 本地文件:镜像内部文件,后面的:Z告诉Podman标注有私人非共享的标签内容
(参考Podman run -v /HOST-DIR:/CONTAINER-DIR:Z详解)

运行脚本,启动。
在浏览器中输入 http://你的ubuntu的ip:12123

2. openssl 制作证书

https双向认证,这里准备一个复杂一点的证书结构

1. 知识补充

在证书中:

Version: 版本号
Serial Number: 证书序列号
Signature Algorithm: 签名算法
Issuer: 签发者(签发证书的CA实体)
Subject: 证书主体(证书持有者实体)
Validity: 有效期
	Not Before: 开始生效时间
	Not After: 证书失效时间
Subject Public Key Info: 主体公钥信息
	Public Key Algorithm: 证书主题持有的公钥密钥算法
	RSA Public-Key: 具体的公钥数据

issure和subject 用 X.509 DN 表示,DN 是由 RDN构成的序列。RDN 用 “属性类型=属性值” 的形式表示。常用属性类型名如下:

属性类型名称 含义 简写
Common Name 通用名称 CN
Organizational Unit name 机构单元名称 OU
Organization name 机构名 O
Locality 地理位置 L
State or province name 州/省名 S
Country 国名 C

一般证书的签发流程是:

  • 申请者把自己的申请做成证书申请文件csr(csr中放入了申请者的公钥以及申请者的信息)
  • 然后把csr发送给签发者CA进行证书签发,签发过程就是CA用自己的私钥给csr生成签名,然后制作为证书文件(.crt或.pem)

nginx判定证书的时候,是根据证书中的两个字段:Issuer 和 Subject
如果 Issuer == Subject 那么 nginx 就会认为这是一个自签名的根证书
如果 Issuer != Subject 那么 nginx 就会认为这不是一个自签名的证书,验证时需要带上签发这个证书的根证书

正式使用时,subject 中的 CN 字段需要填写使用者的域名,也就是 nginx 所在主机的域名

2. 证书制作

本次使用的是符合x509标准的证书,openssl 工具生成比较简单。除此之外,还可以使用 c语言、python、java、或java提供的keytool工具生成,读者可以自行探索。
openssl 工具可以使用openssl.conf的形式进行更加专业的配置,此处只演示较为简单的命令行方式。
配置文件方式可参考:
OpenSSL自建CA和签发二级CA及颁发SSL证书
使用OpenSsl自己CA根证书,二级根证书和颁发证书(亲测步骤)

进入到你的物理机目录 "openresty/nginx/conf",新建一个目录 certs

cd /home/brian/podman/openresty/openresty/nginx/conf
mkdir certs
# 生成ROOT CA
openssl genrsa -out root_ca.key 2048
openssl req -x509 -new -nodes -key root_ca.key -subj "/CN=ROOT CA" -days 3650 -out root_ca.crt

# 生成SERVER CA 和 CLIENT CA
## 基本约束扩展,注明这个二级CA可以颁发证书,不添加则证书链无法认证
cat > certV3.ext << EOF
basicConstraints=CA:TRUE
EOF

## SERVER CA
openssl genrsa -out server_ca.key 2048
openssl req -new -key server_ca.key -subj "/CN=SERVER CA" -out server_ca.csr
openssl x509 -req -in server_ca.csr -CA root_ca.crt -CAkey root_ca.key -CAcreateserial   -extfile certV3.ext -out server_ca.crt -days 3650

## CLIENT CA
openssl genrsa -out client_ca.key 2048
openssl req -new -key client_ca.key -subj "/CN=CLIENT CA" -out client_ca.csr
openssl x509 -req -in client_ca.csr -CA root_ca.crt -CAkey root_ca.key -CAcreateserial   -extfile certV3.ext -out client_ca.crt -days 3650

# 生成server证书和client证书
## server
## 基本约束,声明证书用途为服务端证书,测试发现添加与否应该都可以
cat > certV3.ext << EOF
extendedKeyUsage=serverAuth
EOF
## 注意!!!server的subject中的CN一定要填自己的域名,https认证过程中会对比证书中的subject.CN和实际域名是否一致
openssl genrsa -out server.key 2048
openssl req -new -key server.key -subj "/CN=httpstst.com" -out server.csr
openssl x509 -req -in server.csr -CA server_ca.crt -CAkey server_ca.key -CAcreateserial  -extfile certV3.ext -out server.crt -days 3650

## client
## 基本约束,声明证书用途为客户端证书,测试发现添加与否应该都可以
cat > certV3.ext << EOF
extendedKeyUsage=clientAuth
EOF

openssl genrsa -out client.key 2048
openssl req -new -key client.key -subj "/CN=CLIENT" -out client.csr
openssl x509 -req -in client.csr -CA client_ca.crt -CAkey client_ca.key -CAcreateserial  -extfile certV3.ext -out client.crt -days 3650

# 将 CA 证书拼接为证书链,测试发现不一定要按照根证书在前的顺序,不过最好还是把根证书放到最前面
cat root_ca.crt server_ca.crt client_ca.crt > caAll.crt

几个证书查看指令:

# 查看csr证书申请文件
openssl req -noout -text -in server.csr

# 查看证书内容
openssl x509 -noout -text -in server.crt

3. openresty 配置 https 双向认证

1. 新建配置文件

在实体机 openresty/nginx/conf/sites-enabled 目录下执行

touch https.conf

新建配置文件 https.conf

2. 编辑配置文件

使用vim或nano或其它编辑器,打开 https.conf,编辑内容如下:

server {
        listen       443 ssl;
        server_name  httpstst.com;
        
        ssl_certificate      certs/server.crt;
        ssl_certificate_key  certs/server.key;
        ssl_client_certificate  certs/caAll.crt;
        ssl_verify_client on;
        
        #ssl_session_cache    shared:SSL:1m;
        ssl_session_timeout  5m;

        ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
        ssl_ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS;
        ssl_prefer_server_ciphers  on;

        location / {
                    root   html;
                    index  index.html index.htm;
                }
    }

其中如果只配置

ssl_certificate      certs/server.crt;
ssl_certificate_key  certs/server.key;

那么就是https单向认证;

配置完毕,执行脚本 ./start.sh
然后使用指令

podman ps -a

检查镜像是否启动
正常启动:

CONTAINER ID  IMAGE                                 COMMAND               CREATED         STATUS             PORTS                                          NAMES
ea379f5d44f0  docker.io/openresty/openresty:alpine  /usr/local/openre...  33 minutes ago  Up 33 minutes ago  0.0.0.0:12123->80/tcp, 0.0.0.0:12443->443/tcp  openresty

如果没有正常启动,大概率是nginx脚本 https.conf有问题,可以修改启动脚本 ./start.sh中的

podman run -idt --rm

修改为

podman run -it --rm

禁止openresty在后台运行,然后执行 ./start.sh 即可打印出详细报错信息

4. 测试环节

1. 本地 curl 测试

进入到存放证书的certs文件夹,执行curl指令访问https接口:

curl https://httpstst.com:12443 --cacert caAll.crt --resolve httpstst.com:12443:0.0.0.0 --cert client.crt --key client.key

其中:

  • https默认端口是443,我映射为物理机的12443端口了,所以直接访问12443端口;
  • --cacert 后跟ca证书链。因为是自签发的ca,不是官方ca,所以要添加ca证书链来验证。也可以添加参数 -k 来跳过证书ca验证;
    如果没有这个配置或者没有添加-k,会报错:
curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: https://curl.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.
  • --resolve httpstst.com:12443:0.0.0.0 添加自定义域名解析,因为httpstst.com并非正式申请注册的域名,官方的DNS无法解析httpstst.com。格式为 自己的域名:端口号:映射的IP。
    ps: 也可以不用这个选项,在 /etc/hosts文件中添加一条 0.0.0.0 httpstst.com,这种的风险就是万一有一天真想访问这个域名,很可能会访问你配置的ip;
  • --cert 后跟客户端证书
  • --key 后跟客户端私钥

访问成功,可以看到返回了:

<!DOCTYPE html>
<html>
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<meta content="utf-8" http-equiv="encoding">
<title>Welcome to OpenResty!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to OpenResty!</h1>
<p>If you see this page, the OpenResty web platform is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to our
<a href="https://openresty.org/">openresty.org</a> site<br/>
Commercial support is available at
<a href="https://openresty.com/">openresty.com</a>.</p>
<p>We have articles on troubleshooting issues like <a href="https://blog.openresty.com/en/lua-cpu-flame-graph/?src=wb">high CPU usage</a> and
<a href="https://blog.openresty.com/en/how-or-alloc-mem/">large memory usage</a> on <a href="https://blog.openresty.com/">our official blog site</a>.
<p><em>Thank you for flying <a href="https://openresty.org/">OpenResty</a>.</em></p>
</body>
</html>

还可以通过添加参数 -v 的方式查看详细的https通讯过程

* Added httpstst.com:12443:0.0.0.0 to DNS cache
* Hostname httpstst.com was found in DNS cache
*   Trying 0.0.0.0:12443...
* Connected to httpstst.com (127.0.0.1) port 12443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
*  CAfile: caAll.crt
*  CApath: /etc/ssl/certs
* TLSv1.0 (OUT), TLS header, Certificate Status (22):
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS header, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS header, Finished (20):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, Request CERT (13):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.2 (OUT), TLS header, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* TLSv1.3 (OUT), TLS handshake, Certificate (11):
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* TLSv1.3 (OUT), TLS handshake, CERT verify (15):
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use http/1.1
* Server certificate:
*  subject: CN=httpstst.com
*  start date: Sep 19 08:26:33 2022 GMT
*  expire date: Sep 16 08:26:33 2032 GMT
*  common name: httpstst.com (matched)
*  issuer: CN=SERVER CA
*  SSL certificate verify ok.
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
> GET / HTTP/1.1
> Host: httpstst.com:12443
> User-Agent: curl/7.81.0
> Accept: */*
> 
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Server: openresty/1.21.4.1
< Date: Mon, 19 Sep 2022 09:22:28 GMT
< Content-Type: text/html
< Content-Length: 1097
< Last-Modified: Tue, 02 Aug 2022 08:14:27 GMT
< Connection: keep-alive
< ETag: "62e8dce3-449"
< Accept-Ranges: bytes
< 
<!DOCTYPE html>
...
2. openssl 测试
# 注意:一定不要写成 https://0.0.0.0:12443,添加了https://后openssl就识别不了了
openssl s_client -connect 0.0.0.0:12443 -servername httpstst.com

返回:

CONNECTED(00000003)
depth=0 CN = httpstst.com
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 CN = httpstst.com
verify error:num=21:unable to verify the first certificate
verify return:1
depth=0 CN = httpstst.com
verify return:1
---
Certificate chain
 0 s:CN = httpstst.com
   i:CN = SERVER CA
   a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256
   v:NotBefore: Sep 19 08:26:33 2022 GMT; NotAfter: Sep 16 08:26:33 2032 GMT
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIDEDCCAfigAwIBAgIUMXdNIxO1jK3nbIzblvdWhCITeAcwDQYJKoZIhvcNAQEL
BQAwFDESMBAGA1UEAwwJU0VSVkVSIENBMB4XDTIyMDkxOTA4MjYzM1oXDTMyMDkx
NjA4MjYzM1owFzEVMBMGA1UEAwwMaHR0cHN0c3QuY29tMIIBIjANBgkqhkiG9w0B
AQEFAAOCAQ8AMIIBCgKCAQEAlXh7Zr6XgSL+PKe7NV4v9LVieyn/n5iGemkmhq0n
opFBO/CcO3uJMkMPvjvtHRO+hC5+qgcuGH8OKcu7jRKKN/AfmX9MPr+Z69OnmV14
R504W8VjdBKyq5pRoTZn8165tDOgEOjw+YNpO8WdPSlcIxhIllq+UDF6S9MVPNcI
7zEyQ+janRfBGy1/y0Q2LRMx0uBqMmO5BfU5n4cu4F40T8cj/DUKUJMxHZnq91eW
N/RSeADsos01itRXSIpgq8sb5ELt1fMDGMizd7tElx8V5rRcAm5KidOQjr6+e9gm
7r3k9rv/OYj/5nID/fVIELivJR0x6rJvEGulMqDbBQvynQIDAQABo1cwVTATBgNV
HSUEDDAKBggrBgEFBQcDATAdBgNVHQ4EFgQUBwmZmXdJ+eervnfi3IVfdhK+YEIw
HwYDVR0jBBgwFoAU0IoGUViHqIg+8lYN72CP3BZKihUwDQYJKoZIhvcNAQELBQAD
ggEBAGl96s7ryBcnNhIADEzkTjIMMk4UHeRS7XvXM2o881uo3FyxQD+R4sLLRRbc
/ZtVVRxOftTQsXKWOx2Ys0l0aozKLExs7woyTwyCz2/HxOtAPG+Z8tqZ1eNF1kAb
ZASVt+biq3r7NG2vNuL1OvOH8GALADl+PpgHybZFZDR3i8I0fRgBWEaxZQE048g8
QtA/T27DR6Ci82yPoES8Bis4pxXJWbGQk9mCy2ZcHRMVo6SXCOFNEvdUEtKYJ6vA
9CoV0xJw8nT8IKD4CE8mNZX+YkwHhYW2YtvUlkAy2FmGsw28XQU/whT5cwNWZIqY
IL9TNZoqSVeKfa85/twdkZCPpHo=
-----END CERTIFICATE-----
subject=CN = httpstst.com
issuer=CN = SERVER CA
---
Acceptable client certificate CA names
CN = ROOT CA
CN = SERVER CA
CN = CLIENT CA
Requested Signature Algorithms: ECDSA+SHA256:ECDSA+SHA384:ECDSA+SHA512:Ed25519:Ed448:RSA-PSS+SHA256:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA-PSS+SHA256:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA+SHA256:RSA+SHA384:RSA+SHA512:ECDSA+SHA224:ECDSA+SHA1:RSA+SHA224:RSA+SHA1
Shared Requested Signature Algorithms: ECDSA+SHA256:ECDSA+SHA384:ECDSA+SHA512:Ed25519:Ed448:RSA-PSS+SHA256:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA-PSS+SHA256:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA+SHA256:RSA+SHA384:RSA+SHA512
Peer signing digest: SHA256
Peer signature type: RSA-PSS
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 1495 bytes and written 424 bytes
Verification error: unable to verify the first certificate
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Server public key is 2048 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 21 (unable to verify the first certificate)
---
---
Post-Handshake New Session Ticket arrived:
SSL-Session:
    Protocol  : TLSv1.3
    Cipher    : TLS_AES_256_GCM_SHA384
    Session-ID: FAC2FE1D2BC148DDF3DC5E96D1C6AF7FA0B67FD06222C3E6793B0EB6148C51C0
    Session-ID-ctx: 
    Resumption PSK: FA224BA78C71AF0DD6B07AA6031162B7EC725733D1392C909A52BB5F99B9A5ADA265DEC5499780F01C91B3EB9D306800
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    TLS session ticket lifetime hint: 300 (seconds)
    TLS session ticket:
    0000 - 4b 15 19 73 67 7e 86 ca-84 e8 40 87 50 2d 53 00   K..sg~....@.P-S.
    0010 - 78 bb ce d3 f8 f8 ad e4-72 8e 16 d0 84 13 f8 ba   x.......r.......
    0020 - e5 91 d3 8d a3 43 a8 fd-16 3e 9d 51 b9 4a 5f f7   .....C...>.Q.J_.
    0030 - 68 6d 21 da 19 97 a4 34-96 9b 1e 39 ed 24 1b 35   hm!....4...9.$.5
    0040 - 1a 70 cb e2 30 81 78 76-96 e7 e1 ba a1 7b a3 5a   .p..0.xv.....{.Z
    0050 - a6 45 d5 b5 a4 e9 26 8d-81 13 02 2a 27 79 77 b5   .E....&....*'yw.
    0060 - cb e3 b1 27 a4 3e 21 26-ac 03 40 3a ca cd 4d c1   ...'.>!&..@:..M.
    0070 - a8 eb 77 9a cb 85 3d 6e-06 38 68 0a 9a f9 c3 1d   ..w...=n.8h.....
    0080 - 2f f6 8d 7d 7f 60 9c fa-d2 27 4f 87 35 cd bb d4   /..}.`...'O.5...
    0090 - ea bb bb 7e 67 79 13 e4-b0 b0 f3 c6 9a 4e 42 94   ...~gy.......NB.
    00a0 - 84 59 a0 d0 57 b7 1a 9e-10 64 d0 19 03 ec 82 b5   .Y..W....d......
    00b0 - d2 ea 1f cd c7 47 46 ea-bb 56 de 23 a1 72 da 7e   .....GF..V.#.r.~
    00c0 - a6 eb 43 b8 28 ad 2c c4-f6 f1 06 13 7d 16 7a 98   ..C.(.,.....}.z.
    00d0 - 7c 31 1d 79 49 e2 f7 c1-d8 0b a4 b6 3d 3b f5 21   |1.yI.......=;.!
    00e0 - 08 17 d0 ae 97 e5 f1 28-85 ad a9 af 1e f5 2b 90   .......(......+.

    Start Time: 1663580120
    Timeout   : 7200 (sec)
    Verify return code: 21 (unable to verify the first certificate)
    Extended master secret: no
    Max Early Data: 0
---
read R BLOCK
---
Post-Handshake New Session Ticket arrived:
SSL-Session:
    Protocol  : TLSv1.3
    Cipher    : TLS_AES_256_GCM_SHA384
    Session-ID: E3E46FCF4E0C92288EB8B4E018E7E0E3CC535D5C9588F5C0C7806082B259774A
    Session-ID-ctx: 
    Resumption PSK: 42AEDC7D3BD9782ABD2BA44766111E912CE57E91A865A070B184C593FF9FF3397A1ED5F3D8759F733874FEF5A5A6F5CE
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    TLS session ticket lifetime hint: 300 (seconds)
    TLS session ticket:
    0000 - 4b 15 19 73 67 7e 86 ca-84 e8 40 87 50 2d 53 00   K..sg~....@.P-S.
    0010 - d4 b9 a2 5c 24 bf ac 7a-2b ad 04 b1 b8 51 80 af   ...\$..z+....Q..
    0020 - cf 7d 7d c3 6e 05 5d bb-68 d7 28 40 ef 81 30 da   .}}.n.].h.(@..0.
    0030 - da e0 fd 75 17 00 5c d2-69 2a 62 0d e9 45 c6 79   ...u..\.i*b..E.y
    0040 - 52 46 8a 1d f5 19 cc c0-e8 bc 9a da e4 b7 f3 05   RF..............
    0050 - be 8c bc 1c ac c0 5b 6b-33 b9 b3 3d b1 15 c4 9f   ......[k3..=....
    0060 - 66 bb d7 c1 5b c3 39 72-c0 5e 22 fb 05 36 28 dc   f...[.9r.^"..6(.
    0070 - 15 9a 32 c5 2a cc 43 e1-0d 19 0c 45 98 d1 eb 80   ..2.*.C....E....
    0080 - b7 7f 12 d2 bc 00 28 7b-79 9c 9c ae 27 d3 b0 0a   ......({y...'...
    0090 - 95 9d 1d d3 cf 5b b0 7a-7e 74 68 43 a4 2d ce bb   .....[.z~thC.-..
    00a0 - 5b 41 74 7c 00 38 58 02-3f 70 24 0c 14 a8 7f 7f   [At|.8X.?p$.....
    00b0 - 85 55 0e 82 56 87 db e1-9e f3 c7 d9 3c db 37 6e   .U..V.......<.7n
    00c0 - d4 5c 0c e8 95 1c 06 f0-87 26 af 6b 43 04 a0 ca   .\.......&.kC...
    00d0 - cb 75 04 c9 88 75 2a eb-b8 dd c7 37 5e d2 e3 d2   .u...u*....7^...
    00e0 - 85 8d 8b 82 33 85 ba f0-04 06 79 03 0c e4 b4 4e   ....3.....y....N

    Start Time: 1663580120
    Timeout   : 7200 (sec)
    Verify return code: 21 (unable to verify the first certificate)
    Extended master secret: no
    Max Early Data: 0
---
read R BLOCK

还可以用

openssl s_client -host 0.0.0.0 -port 12443 
3. 使用postman测试

使用postman在win10上进行测试,需要手动配置域名解析:
进入目录 C:\Windows\System32\drivers\etc
使用管理员权限编辑 hosts文件,添加一行:

你的ubuntu系统的ip httpstst.com

打开postman,点击右上角配置
打开ssl证书验证

配置ca证书链

配置客户端公私钥


配置号证书后,对地址https://httpstst.com发送get请求:

另一种配置,使用 openssl 将 client.crt 和 client.key 打包为 pkcs12 格式的 client.pfx, 导入到postman
(生成.pfx文件或.p12文件需要配置密码,我这里配置的是 httpstst,postman想使用.pfx也要填好密码)

openssl pkcs12 -export -in client.crt -inkey client.key -out client.pfx

4. 使用火狐浏览器验证
rm client.pfx
openssl pkcs12 -export -in client.crt -inkey client.key -out client.pfx

打开火狐浏览器->设置->搜索"证书"

点击查看证书->导入->导入自己的clinet.pfx

在浏览器网页输入:https://httpstst.com:12443访问,如果显示证书不安全,点击高级选项跳过验证,就可以看到:

5. python程序验证

运行环境:win10
运行程序:python3.8
程序如下:

# -*- coding:utf8 -*-
# python3 https client demo

import urllib.request

import ssl

if __name__ == '__main__':
    CA_FILE = "caAll.crt"
    KEY_FILE = "client.key"
    CERT_FILE = "client.crt"

    context = ssl.SSLContext(ssl.PROTOCOL_TLS)
    context.check_hostname = False
    context.load_cert_chain(certfile=CERT_FILE, keyfile=KEY_FILE)
    context.load_verify_locations(CA_FILE)
    context.verify_mode = ssl.CERT_REQUIRED
    try:
        # 通过request()方法创建一个请求:
        request = urllib.request.Request('https://httpstst.com:12443')
        res = urllib.request.urlopen(request, context=context)
        print(res.code)
        print(res.read().decode("utf-8"))
        print(vars(res))
    except Exception as ex:
        print("Found Error in auth phase:%s" % str(ex))

返回值:

200
<!DOCTYPE html>
<html>
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<meta content="utf-8" http-equiv="encoding">
<title>Welcome to OpenResty!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to OpenResty!</h1>
<p>If you see this page, the OpenResty web platform is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to our
<a href="https://openresty.org/">openresty.org</a> site<br/>
Commercial support is available at
<a href="https://openresty.com/">openresty.com</a>.</p>
<p>We have articles on troubleshooting issues like <a href="https://blog.openresty.com/en/lua-cpu-flame-graph/?src=wb">high CPU usage</a> and
<a href="https://blog.openresty.com/en/how-or-alloc-mem/">large memory usage</a> on <a href="https://blog.openresty.com/">our official blog site</a>.
<p><em>Thank you for flying <a href="https://openresty.org/">OpenResty</a>.</em></p>
</body>
</html>

{'fp': None, 'debuglevel': 0, '_method': 'GET', 'headers': <http.client.HTTPMessage object at 0x000002550BE8ECA0>, 'msg': 'OK', 'version': 11, 'status': 200, 'reason': 'OK', 'chunked': False, 'chunk_left': 'UNKNOWN', 'length': 0, 'will_close': True, 'code': 200, 'url': 'https://httpstst.com:12443'}
6. java

java验证不做详述,具体过程是:将客户端的公钥证书和私钥存为keystore,将ca证书循环加载存入另一个trust ksystore,然后通过ssl传给http,一定要把ca证书链全部加载。

参考


[1]. Podman run -v /HOST-DIR:/CONTAINER-DIR:Z详解
[2]. Nginx的双向认证
[3]. 巧用 Nginx 快速实现 HTTPS 双向认证
[4]. 使用OpenSSL创建多级CA证书链签发证书并导出为pkcs12/p12/pfx文件
[5]. OpenSSL自建CA和签发二级CA及颁发SSL证书
[6]. 使用OpenSsl自己CA根证书,二级根证书和颁发证书(亲测步骤)

posted @ 2022-09-19 18:37  BrianSun  阅读(2784)  评论(0编辑  收藏  举报