Linux:curl 模拟 https(TLS/SSL)

Linux:curl 模拟 https(TLS/SSL)


1.命令总结

curl -v -k https://test1280:1280/
curl -v --cacert rootCA.pem https://test1280:1280/
curl -v --cacert rootCA.pem --cert client.crt --key client.key https://test1280:1280/

更多参考:https://blog.csdn.net/test1280/article/details/110862370


2.测试环境

2.1.操作系统

[test1280@test1280 ~]$ cat /etc/redhat-release 
CentOS release 6.8 (Final)
[test1280@test1280 ~]$ cat /proc/version 
Linux version 2.6.32-642.el6.x86_64 ([email protected]) (gcc version 4.4.7 20120313 (Red Hat 4.4.7-17) (GCC) ) #1 SMP Tue May 10 17:27:01 UTC 2016

2.2.curl版本

[test1280@test1280 ~]$ curl -V
curl 7.64.0 (x86_64-pc-linux-gnu) libcurl/7.64.0 OpenSSL/1.0.1e zlib/1.2.3
Release-Date: 2019-02-06
Protocols: dict file ftp ftps gopher http https imap imaps pop3 pop3s rtsp smb smbs smtp smtps telnet tftp 
Features: AsynchDNS IPv6 Largefile NTLM NTLM_WB SSL libz UnixSockets HTTPS-proxy

2.3.其他

[test1280@test1280 ~]$ go version
go version go1.13.6 linux/amd64

3.服务端https单向校验

即在建TLS/SSL链时,服务端发送自身证书给客户端,客户端校验证书,判断服务端是否可信。

3.1.模拟https服务端

https 服务端代码使用 Go 模拟实现:

package main

import (
	"log"
	"net/http"
)

func main() {
	http.HandleFunc("/", func (w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("HTTP/1.1 with TLS/SSL"))
	})
	log.Fatal(http.ListenAndServeTLS(":1280", "server.crt", "server.key", nil))
}

其中使用到两个文件:

server.crt:服务端证书
server.key:服务端私钥

我们创建自己的CA,并用自己的CA签发服务端证书。

# 创建CA私钥
$ openssl genrsa -out rootCA.key 2048

# 根据CA私钥创建CA证书
$ openssl req -x509 -new -nodes -key rootCA.key -days 365 -out rootCA.pem

此时,包含两个CA相关文件:

rootCA.key:CA私钥
rootCA.pem:CA证书

我们使用自建的CA,签发服务端证书:

# 创建服务端私钥
$ openssl genrsa -out server.key 2048

# 生成服务端证书签名请求CSR
$ openssl req -new -key server.key -out server.csr
# 注意,在Common Name,输入test1280,是客户端访问证书的域名。

# 使用CA,并依据服务端CSR,签名生成服务端证书
$ openssl x509 -req -in server.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out server.crt -days 365

此时,包含三个服务端相关文件:

server.crt:服务端证书
server.csr:服务端证书签名请求
server.key:服务端私钥

工作目录结构如下:

[test1280@test1280 curl-https]$ tree .
.
├── curl-https
├── go.mod
├── main.go
├── rootCA.key
├── rootCA.pem
├── rootCA.srl
├── server.crt
├── server.csr
└── server.key

0 directories, 9 files

启动服务端:

[test1280@test1280 curl-https]$ go run main.go 

3.2.curl 不校验服务端证书直接信任

curl -v -k https://test1280:1280/

开启 -k 参数:

man curl

-k/--insecure

  (SSL) This option explicitly allows curl to perform "insecure" SSL connections  and  transfers.  All
  SSL  connections  are  attempted  to  be made secure by using the CA certificate bundle installed by
  default. This makes all connections considered "insecure" fail unless -k/--insecure is used.

  See this online resource for further details: http://curl.haxx.se/docs/sslcerts.html

例如:

[test1280@test1280 curl-https]$ curl -v -k https://test1280:1280/
* Expire in 0 ms for 6 (transfer 0x1b973c0)
……
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Expire in 200 ms for 4 (transfer 0x1b973c0)
* Connected to test1280 (127.0.0.1) port 1280 (#0)
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
*   CAfile: /etc/pki/tls/certs/ca-bundle.crt
  CApath: none
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* NPN, negotiated HTTP1.1
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Next protocol (67):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* Server certificate:
*  subject: C=XX; L=Default City; O=Default Company Ltd; CN=test1280
*  start date: Dec  9 14:23:27 2020 GMT
*  expire date: Dec  9 14:23:27 2021 GMT
*  issuer: C=XX; L=Default City; O=Default Company Ltd
*  SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
> GET / HTTP/1.1
> Host: test1280:1280
> User-Agent: curl/7.64.0
> Accept: */*
> 
< HTTP/1.1 200 OK
< Date: Wed, 09 Dec 2020 14:30:45 GMT
< Content-Length: 21
< Content-Type: text/plain; charset=utf-8
< 
* Connection #0 to host test1280 left intact
HTTP/1.1 with TLS/SSL

抓包:

[root@test1280 ~]# tcpdump -i any port 1280 -s 0 -w 1280.cap
tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
^C15 packets captured
30 packets received by filter
0 packets dropped by kernel

wireshark解包:

Linux:curl 模拟 https(TLS/SSL)_第1张图片

3.3.curl 校验服务端证书(指定CA)

curl -v --cacert rootCA.pem https://test1280:1280/

开启 --cacert 参数,指定CA:

man curl

--cacert 

  (SSL) Tells curl to use the specified certificate file to verify the peer. The file may contain mul-
  tiple  CA  certificates.  The  certificate(s) must be in PEM format. Normally curl is built to use a
  default file for this, so this option is typically used to alter that default file.

  curl recognizes the environment variable named ’CURL_CA_BUNDLE’ if it is set,  and  uses  the  given
  path as a path to a CA cert bundle. This option overrides that variable.

  The  windows version of curl will automatically look for a CA certs file named ´curl-ca-bundle.crt´,
  either in the same directory as curl.exe, or in the Current Working  Directory,  or  in  any  folder
  along your PATH.

  If  curl is built against the NSS SSL library, the NSS PEM PKCS#11 module (libnsspem.so) needs to be
  available for this option to work properly.

  If this option is used several times, the last one will be used.

哪个CA签发的服务端证书,就应当将哪个CA的证书(PEM)添加到客户端cacert列表中。

例如:

[test1280@test1280 curl-https]$ curl -v --cacert rootCA.pem https://test1280:1280/
* Expire in 0 ms for 6 (transfer 0x15ca3c0)
……
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Expire in 200 ms for 4 (transfer 0x15ca3c0)
* Connected to test1280 (127.0.0.1) port 1280 (#0)
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
*   CAfile: rootCA.pem
  CApath: none
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* NPN, negotiated HTTP1.1
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Next protocol (67):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* Server certificate:
*  subject: C=XX; L=Default City; O=Default Company Ltd; CN=test1280
*  start date: Dec  9 14:23:27 2020 GMT
*  expire date: Dec  9 14:23:27 2021 GMT
*  common name: test1280 (matched)
*  issuer: C=XX; L=Default City; O=Default Company Ltd
*  SSL certificate verify ok.
> GET / HTTP/1.1
> Host: test1280:1280
> User-Agent: curl/7.64.0
> Accept: */*
> 
< HTTP/1.1 200 OK
< Date: Wed, 09 Dec 2020 14:41:47 GMT
< Content-Length: 21
< Content-Type: text/plain; charset=utf-8
< 
* Connection #0 to host test1280 left intact
HTTP/1.1 with TLS/SSL

抓包:

[root@test1280 ~]# tcpdump -i any port 1280 -s 0 -w 1280.cap
tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
^C16 packets captured
32 packets received by filter
0 packets dropped by kernel

wireshark解包:

Linux:curl 模拟 https(TLS/SSL)_第2张图片

4.服务端https双向校验

即在建TLS/SSL链时:

  • 服务端发送自身证书给客户端,客户端校验服务端证书
  • 客户端发送自身证书给服务端,服务端校验客户端证书

4.1.生成客户端证书

使用刚刚自建的CA,签发生成客户端证书:

# 生成客户端私钥
$ openssl genrsa -out client.key 2048

# 生成客户端证书签名请求CSR
$ openssl req -new -key client.key -out client.csr

# 使用CA,并依据客户端CSR,签名生成客户端证书
$ openssl x509 -req -in client.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out client.crt -days 365

此时,包含三个客户端相关文件:

client.crt:客户端证书
client.csr:客户端证书签名请求
client.key:客户端私钥

工作目录结构如下:

[test1280@test1280 curl-https]$ tree .
.
├── client.crt
├── client.csr
├── client.key
├── go.mod
├── main.go
├── rootCA.key
├── rootCA.pem
├── rootCA.srl
├── server.crt
├── server.csr
└── server.key

0 directories, 11 files

4.2.服务端双向认证代码

package main

import (
	"crypto/tls"
	"crypto/x509"
	"io/ioutil"
	"log"
	"net/http"
)

func main() {
	// 读取签发客户端证书的CA证书
	CACrt, err := ioutil.ReadFile("rootCA.pem")
	if err != nil {
		log.Fatalln(err)
	}
	// 创建用于信任校验客户端的CA证书池
	CAPool := x509.NewCertPool()
	// 添加CA证书到池(信任签发客户端证书的CA)
	CAPool.AppendCertsFromPEM(CACrt)

	server := &http.Server{
		Addr:    ":1280",
		Handler: &myHandler{},
		TLSConfig: &tls.Config{
			// 设置服务端对客户端的CA信任池
			ClientCAs:  CAPool,
			// 设置TLS/SSL鉴权认证时要求客户端提供其证书并校验
			ClientAuth: tls.RequireAndVerifyClientCert,
		},
	}

	// 设置:
	// * 服务端要发送给客户端认证的服务端证书
	// * 服务端自己的私钥,用以和客户端协商对称加解密密钥时的加解密
	log.Fatal(server.ListenAndServeTLS("server.crt", "server.key"))
}

type myHandler struct {
}

func (*myHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("HTTP/1.1 TLS/SSL 双向校验"))
}

4.3.curl 模拟 https 客户端双向校验证书

curl -v --cacert rootCA.pem --cert client.crt --key client.key https://test1280:1280/

开启 --cacert rootCA.pem,想要认证服务端,需要指定CA,校验服务端证书

开启 --cert client.crt --key client.key,提供客户端证书,供给服务端校验客户端真伪

man curl

-E/--cert 

  (SSL) Tells curl to use the specified certificate file when getting a file with HTTPS or  FTPS.  The
  certificate must be in PEM format.  If the optional password isn’t specified, it will be queried for
  on the terminal. Note that this option assumes a "certificate" file that is the private key and  the
  private certificate concatenated! See --cert and --key to specify them independently.

  If curl is built against the NSS SSL library then this option can tell curl the nickname of the cer-
  tificate to use within the NSS database defined by the environment variable SSL_DIR (or  by  default
  /etc/pki/nssdb).  If  the  NSS  PEM PKCS#11 module (libnsspem.so) is available then PEM files may be
  loaded. If you want to use a file from the current directory, please precede it with "./" prefix, in
  order to avoid confusion with a nickname.

--key 

  (SSL/SSH)  Private  key file name. Allows you to provide your private key in this separate file. For
  SSH,  if  not  specified,  curl  tries  the  following   candidates   in   order:   ’~/.ssh/id_rsa’,
  ’~/.ssh/id_dsa’, ’./id_rsa’, ’./id_dsa’.

  If this option is used several times, the last one will be used.

例如:

[test1280@test1280 curl-https]$ curl -v --cacert rootCA.pem --cert client.crt --key client.key https://test1280:1280/
* Expire in 0 ms for 6 (transfer 0x1b873c0)
……
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Expire in 200 ms for 4 (transfer 0x1b873c0)
* Connected to test1280 (127.0.0.1) port 1280 (#0)
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
*   CAfile: rootCA.pem
  CApath: none
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* NPN, negotiated HTTP1.1
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Request CERT (13):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Certificate (11):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS handshake, CERT verify (15):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Next protocol (67):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* Server certificate:
*  subject: C=XX; L=Default City; O=Default Company Ltd; CN=test1280
*  start date: Dec  9 14:23:27 2020 GMT
*  expire date: Dec  9 14:23:27 2021 GMT
*  common name: test1280 (matched)
*  issuer: C=XX; L=Default City; O=Default Company Ltd
*  SSL certificate verify ok.
> GET / HTTP/1.1
> Host: test1280:1280
> User-Agent: curl/7.64.0
> Accept: */*
> 
< HTTP/1.1 200 OK
< Date: Wed, 09 Dec 2020 14:56:59 GMT
< Content-Length: 29
< Content-Type: text/plain; charset=utf-8
< 
* Connection #0 to host test1280 left intact
HTTP/1.1 TLS/SSL 双向校验

抓包:

[root@test1280 ~]# tcpdump -i any port 1280 -s 0 -w 1280.cap
tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
^C15 packets captured
30 packets received by filter
0 packets dropped by kernel

wireshark解包:

Linux:curl 模拟 https(TLS/SSL)_第3张图片

5.相关资料

  • https://blog.csdn.net/test1280/article/details/110862370

你可能感兴趣的:(网络技术,GO,Linux,https,ssl,http,curl,tls)