Android自签名证书问题
服务器给了一个自签名证书,ios那边可以使用,Android不能使用! 坑,自己搭服务器签名验证!,想看问题原因,直接移步最后!
生成自签名证书
//生成 rao.key,后面位数可以指定 需要设置密码,需要记住后面验证需要输入
openssl genrsa -idea -out rao.key 1024
// 生成证书请求 csr 文件,输入key密码,依次输入组织名称等信息 其中 Common Name 为域名或者ip,最后输入的密码为修改csr文件需要配置的
openssl req -new -key rao.key -out rao.csr
// 基于上面的文件生成证书,有效期一年
openssl x509 -req -days 365 -in rao.csr -signkey rao.key -out rao.crt
nginx配置https证书
//示例
server {
...
listen 443;
server_name www.rao.com;
ssl on;
#证书文件路径
ssl_certificate /etc/nginx/ssl_key/applelife.crt;
#key文件路劲
ssl_certificate_key /etc/nginx/ssl_key/applelife.key;
...
location / {
...
}
}
其他命令
//停止 需要输入设置的key密码
nginx -s stop -c /etc/nginx/nginx.conf
//启动
nginx -c /etc/nginx/nginx.conf
//检查语法
nignx -tc /etc/nginx/nginx.cof
//查看端口是否启用
netstat -luntp |grep 443
Android https代码
可以参考google官方代码 https://developer.android.com/training/articles/security-ssl
SSLContext provideSSLContext(Application app) {
try {
//加载需要信任的证书,crt格式和cer格式都可以,在windows中可以互转
//InputStream serverCer = app.getAssets().open("server.crt");
InputStream serverCer = app.getResources().openRawResource(R.raw.rao);
//InputStream fiddlerCer = app.getAssets().open("fiddlerroot.cer");
//InputStream fiddlerCer=app.getResources().openRawResource(R.raw.fiddlerRoot);
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null);
//如果要信任多个证书,就会存在多个serverCer,那么要分别加载到keyStore中
//别名可以随便命名,但不能重复
keyStore.setCertificateEntry("server", certificateFactory.generateCertificate(serverCer));
// keyStore.setCertificateEntry("fiddler", certificateFactory.generateCertificate(fiddlerCer));
try {
serverCer.close();
//fiddlerCer.close();
} catch (IOException e) {
e.printStackTrace();
}
SSLContext sslContext = SSLContext.getInstance("TLS");
TrustManagerFactory trustManagerFactory = TrustManagerFactory.
getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
//初始化keystore
sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());
return sslContext;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
...
builder.sslSocketFactory(sslContext.getSocketFactory());
...
问题异常
// 连接异常
HTTP FAILED: javax.net.ssl.SSLPeerUnverifiedException: Hostname 183.230.dd.156 not verified:
查找资料 在生成 .csr 的时候填入的很多信息中,包含了一个叫做 Common Name(CN)的 field,以前这个 CN 可以直接填写 server name 或者 IP,但之后规定了需要使用 Subject Alternative Name(SAN) 来指定 server name, IP
参考地址 https://tools.ietf.org/html/rfc2818#section-3.1
证书添加 subjectAltName
以现有证书添加 subjectAltName
// 命令
openssl x509 -req -extfile <(printf "subjectAltName=IP:localhost,DNS:www.xxx.com") -days 365 -in rao.csr -CA rao.crt -CAkey rao.key -CAcreateserial -out rao1.crt
至此 Android https问题得到解决
参考:https://www.jianshu.com/p/a56b2234da1a
参考 :https://moxo.io/blog/2017/08/01/problem-missing-subjectaltname-while-makeing-self-signed-cert/