Xiaopei's DokuWiki

These are the good times in your life,
so put on a smile and it'll be alright

User Tools

Site Tools


it:https

HTTPS

客户端证书

生成 CA、服务端证书、客户端证书

create-certs.sh
#! /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
create-certs-nopwd.sh
#! /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 是邮箱)的服务,如 ComodoStartSSL 但颁发证书一般需用户与 CA 做验证、下载

配置 nginx

nginx 使用中介 CA (intermediate CA、链式证书)的配置要点:

  1. ssl_client_certificate 所用的证书为链式证书
  2. 要修改 ssl_verify_depth 的值为 CA 的链式层数
  3. 如果用 ssl_crl,则 crl 文件需要为 root crl 和 intermediate crl 的拼接
  4. 如果用 crl 一定要注意 default_crl_days 的配置,默认是 30 天,如果过期未替换,会 (12:CRL has expired)
    $ 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   
nginx.conf
# 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/

ssl 的 telnet

浏览器使用 p12

$ 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 / Certificate Revokation List

使用 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.

生成这个配置文件:

/homw/www/ca/ca.conf
[ 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

it/https.txt · Last modified: 2018/07/07 21:00 by admin