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
[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
[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
[test1280@test1280 ~]$ go version
go version go1.13.6 linux/amd64
即在建TLS/SSL链时,服务端发送自身证书给客户端,客户端校验证书,判断服务端是否可信。
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
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解包:
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解包:
即在建TLS/SSL链时:
使用刚刚自建的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
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 双向校验"))
}
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解包: