友链
导航
These are the good times in your life,
so put on a smile and it'll be alright
友链
导航
#! /usr/bin/env bash # Create the CA Key and Certificate for signing Client Certs openssl genrsa -des3 -out ca.key 4096 openssl req -new -x509 -days 365 -key ca.key -out ca.crt # 或者 # Create the Server Key, CSR, and Certificate openssl genrsa -des3 -out server.key 1024 openssl req -new -key server.key -out server.csr # We're self signing our own server cert here. This is a no-no in production. openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt # Create the Client Key and CSR openssl genrsa -des3 -out client.key 1024 openssl req -new -key client.key -out client.csr # Sign the client certificate with our CA cert. Unlike signing our own server cert, this is what we want to do. # Serial should be different from the server one, otherwise curl will return NSS error -8054 openssl x509 -req -days 365 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 02 -out client.crt # Verify Server Certificate openssl verify -purpose sslserver -CAfile ca.crt server.crt # Verify Client Certificate openssl verify -purpose sslclient -CAfile ca.crt client.crt
#! /usr/bin/env bash # Create the CA Key and Certificate for signing Client Certs openssl req -nodes -new -x509 -keyout ca.key -out ca.crt # Create the Server Key, CSR, and Certificate openssl req -nodes -new -keyout server.key -out server.csr # We're self signing our own server cert here. This is a no-no in production. openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt # Create the Client Key and CSR openssl req -nodes -new -keyout client.key -out client.csr # Sign the client certificate with our CA cert. Unlike signing our own server cert, this is what we want to do. # Serial should be different from the server one, otherwise curl will return NSS error -8054 openssl x509 -req -days 365 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 02 -out client.crt # Verify Server Certificate openssl verify -purpose sslserver -CAfile ca.crt server.crt # Verify Client Certificate openssl verify -purpose sslclient -CAfile ca.crt client.crt
是否能用商业 CA 颁发的服务端证书来签署客户度端证书呢?这样客户端证书就能包含商业根证书、就应该显示安全了吧?
答案是:不能
通过 openssl 查看 crt.pem 内容的话,是会发现 CA 证书(Root certificate 根证书 或 Intermediate certificate 中介证书)和服务端证书(终端实体证书 End-entity or leaf certificate)其实是不同的,至少体现在:
openssl x509 -noout -text -in $YOUR_CERT X509v3 extensions: X509v3 Basic Constraints: - CA:TRUE + CA:FALSE
CA 肯定不会给普通公司颁发 CA 证书的,因为普通公司能任意颁发证书。
有的 CA 可以提供邮件客户端证书(即 SN 是邮箱)的服务,如 Comodo 和 StartSSL 但颁发证书一般需用户与 CA 做验证、下载
nginx 使用中介 CA (intermediate CA、链式证书)的配置要点:
$ openssl crl -text -noout -in mycrl.crl Last Update: Oct 19 16:55:48 2017 GMT Next Update: Nov 18 16:55:48 2017 GMT
# Bare Bones nginx config file. Replace with your appropriate paths user www-data www-data; worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; server { listen 443; ssl on; server_name example.com; error_page 495 496 497 https://www.google.com; # 定制 HTTPS 握手失败错误页 ssl_certificate /etc/nginx/certs/server.crt; ssl_certificate_key /etc/nginx/certs/server.key; ssl_client_certificate /etc/nginx/certs/ca.crt; ssl_verify_client optional; # ssl_verify_depth 2; location / { root /var/www/example.com/html; fastcgi_pass 127.0.0.1:9000; fastcgi_param SCRIPT_FILENAME /var/www/example.com/lib/Request.class.php; fastcgi_param VERIFIED $ssl_client_verify; fastcgi_param DN $ssl_client_s_dn; include fastcgi_params; } } }
# 不用证书访问 $ http --verify=no https://example.com/ # 用证书,会提示输入密码 $ http --verify=no --cert=client.crt --cert-key=client.key https://example.com/ # curl(on mac)可能不正常 $ curl -v -s -k --key client.key --cert client.crt https://example.com/
$ openssl s_client -connect foo.bar.com:443 # 能看到算法、服务端客户端的签名信息等 HEAD /static/css HTTP/1.0 HTTP/1.1 301 Moved Permanently Server: nginx Date: Thu, 10 May 2018 05:57:50 GMT Content-Type: text/html Content-Length: 178 Location: https://10.10.1.123/static/css/ <-- 暴露了内网信息 Connection: close closed
$ openssl pkcs12 -export -clcerts -in client.crt -inkey client.key -out client.p12 # 需要输入一个 p12 提取密码 $ openssl pkcs12 -export -clcerts -in client.crt -inkey client.key -out client.p12 -passout pass: # 不输或者用 pass:,最后生成的用不了 # 测试,123123 是密码 ---> 不一定行,还是用浏览器测试更准确 $ curl -v -s -k --cert client.p12:123123 https://example.com/ # 上面的命令可能不行,命令行还是得用 crt/key $ openssl pkcs12 -in mycert.p12 -out file.key.pem -nocerts -nodes $ openssl pkcs12 -in mycert.p12 -out file.crt.pem -clcerts -nokeys $ http --verify=no --cert=file.crt.pem --cert-key=file.key.pem https://www.secure.com/ # 或者双击、输入密码导入 mac, # 使用 safari 访问时,会要求 # 选证书。但用 chrome 还不行
如果 chrome 访问遇到浏览器报错 ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED,很可能是 mac/chrome 的兼容性问题,快用别的浏览器重试!
另外可以在 Keychain Access 修改 always allow 试试
Fixing ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED on macOS – Nicholas Sherlock
使用 CRL 必须有个 openssl 的配置文件:
Not all of the files you need for doing CRLs can be specified on the command line, however the config file to use can be (with -config <file>). Therefore, you really need to customise an openssl.cnf file for each CA you run before doing this step, otherwise you'll come unstuck. For an old but good guide on how to do this, see this archived page, or you can also look at this alternate guide.
生成这个配置文件:
[ ca ] default_ca = CA_default # The default ca section [ CA_default ] dir = . # top dir database = $dir/index.txt # index file. new_certs_dir = $dir/newcerts # new certs dir crl_dir = $dir/revoked certificate = $dir/cacert.pem # The CA cert serial = $dir/serial # serial no file private_key = $dir/private/cakey.pem# CA private key RANDFILE = $dir/private/.rand # random number file default_days = 365 # how long to certify for default_crl_days= 30 # how long before next CRL default_md = md5 # md to use policy = policy_any # default policy email_in_dn = no # Don't add the email into cert DN name_opt = ca_default # Subject name display option cert_opt = ca_default # Certificate display option copy_extensions = none # Don't copy extensions from request [ policy_any ] countryName = supplied stateOrProvinceName = optional organizationName = optional organizationalUnitName = optional commonName = supplied emailAddress = optional
使用 CRL:
# 创建索引文件(之前没有 conf 就没创建) $ touch index.txt # 生成 CRL $ openssl ca -gencrl -config ca.conf -keyfile ca.key -cert ca.crt -out revoked/crl.pem # 查看 CRL $ openssl crl -in revoked/crl.pem -noout -text > No Revoked Certificates # 过期一个 client $ openssl ca -config ca.conf -keyfile ca.key -cert ca.crt -revoke client.crt # 再次查看 CRL $ openssl crl -in revoked/crl.pem -noout -text > Revoked Certificates: > Serial Number: 02 # 包含 CRL 检查客户端证书: # 需要先拼接 crt 和 crl $ cat ca.crt revoked/crl.pem > ca-crt-crl.pem # 再做检查 $ openssl verify -crl_check -CAfile ca-crt-crl.pem client-crt.pem
参考:OpenSSL: Manually verify a certificate against a CRL - Raymii.org
在 nginx 中使用 CRL:
ssl_client_certificate /etc/nginx/certs.np/ca.crt; ssl_verify_client on; + ssl_crl /etc/nginx/certs.np/revoked/crl.pem;
用旧 client.key 访问会和没有 key 一样,被 nginx 拦截。
openssl 1.1.0 以上版本加入了 -CRLfile 参数,需要与 -crl_check 一起用。作用是不需手动吧 crt、crl 拼成一个文件了。
commit Add option to allow in-band CRL loading in verify utility. Add function · openssl/openssl@245d2ee