Fork me on GitHub

SSL证书校验错误 Trust anchor for certification path not found

##问题描述
在使用 acme.sh脚本签发的Let’s Encrypt 免费SSL证书,在android中无法通过SSL系统验证,出现以下异常Trust anchor for certification path not found

1
2
3
javax.net.ssl.SSLHandshakeException:
java.security.cert.CertPathValidatorException:
Trust anchor for certification path not found.

问题发现

安卓客户端无法连接域名服务器,浏览器直接打开网址正常,ssl连接正常,在SDK里连接失败。

错误消息为:

1
2
3
javax.net.ssl.SSLHandshakeException:
java.security.cert.CertPathValidatorException:
Trust anchor for certification path not found.

问题原因

直接让 nginx配置文件使用了acme.sh脚本签发的<doman>.cer文件,这里面的文件都是内部使用,直接使用会导致服务器证书链配置错误,缺少中间证书设置。

解决方案:

stackoverflow

https://stackoverflow.com/questions/6825226/trust-anchor-not-found-for-android-ssl-connection

  1. 使用openssl检查证书
    1
    $ openssl s_client -debug -connect www.mafxcc.com:443

可能会出现:

1
$ Verify return code: 21 (unable to verify the first certificate)

而且在前面的输出里有:

1
2
3
4
5
6
depth=0 OU = Domain Control Validated, CN = www.domain.com
verify error:num=20:unable to get local issuer certificate
verify return:1 depth=0 OU = Domain Control Validated, CN = www.domain.com
verify error:num=27:certificate not trusted
verify return:1 depth=0 OU = Domain Control Validated, CN = www.domain.com
verify error:num=21:unable to verify the first certificate`

证书链只包含一个元素:

1
2
3
Certificate chain
0 s:CN = domain.com
i:C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3

但是应该有将一个链中的签名权限引用回安卓信任的权限(Verisign、GlobalSign等):

1
2
3
4
5
6
7
---
Certificate chain
0 s:CN = domain.com
i:C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
1 s:C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
i:O = Digital Signature Trust Co., CN = DST Root CA X3
---

  1. 在用acme.sh把证书生成以后, 需要把证书安装到真正需要用它的地方

注意: 默认生成的证书都放在安装目录下: ~/.acme.sh/.com/, 不要直接使用此目录下的文件, 例如:
不要直接让 nginx/apache 的配置文件使用这下面的文件. 这里面的文件都是内部使用, 而且目录结构可能会变化.

正确的使用方法是使用 --installcert 命令,并指定目标位置, 然后证书文件会被安装到相应的位置, 例如:

1
2
3
4
$ acme.sh --installcert -d <domain>.com \
--key-file /etc/nginx/ssl/<domain>.key \
--fullchain-file /etc/nginx/ssl/fullchain.cer \
--reloadcmd "service nginx force-reload"

最后

在 Nginx 的配置 ssl_certificate 使用 /etc/nginx/ssl/fullchain.cer ,而非 /etc/nginx/ssl/<domain>.cer !

重启 Nginx 后再次验证 SSL证书。