1. 情况说明
-
服务端证书
服务端的证书到18年6月26日过期,是自签发的。
image.png
- client的TrustManager
线上已运行流量的TrustManager如下,client依赖的iots.crt和服务端的证书相同
public class IotsTrustManager extends X509ExtendedTrustManager {
//根证书认证
private X509TrustManager rootTrusm;
public IotsTrustManager() throws Exception{
//CA根证书,可以从官网下载
InputStream in = iotsTrustManager.class.getResourceAsStream("/iots.crt");
CertificateFactory cf = CertificateFactory.getInstance("X.509");
Certificate ca = null;
try {
ca = cf.generateCertificate(in);
} catch (CertificateException e) {
throw e;
} finally {
in.close();
}
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
rootTrusm = (X509TrustManager) tmf.getTrustManagers()[0];
}
@Override
public void checkClientTrusted(X509Certificate[] arg0,
String arg1) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
//验证服务器证书合法性
rootTrusm.checkServerTrusted(chain, authType);
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType,
Socket socket) throws CertificateException {
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType,
SSLEngine engine) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType,
Socket socket) throws CertificateException {
//验证服务器证书合法性
//chain是服务端证书链,一般包含ca证书和服务端自己的证书,一般第一个是服务端自己证书
rootTrusm.checkServerTrusted(chain, authType);
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType,
SSLEngine engine) throws CertificateException {
//验证服务器证书合法性
//chain是服务端证书链,一般包含ca证书和服务端自己的证书,一般第一个是服务端自己证书
rootTrusm.checkServerTrusted(chain, authType);
}
}
2. 服务端证书过期后会发生什么?
2.1 首先分析下IotsTrustManager的原理。
IotsTrustManager加载了本地证书(证书包含CA、公钥、公司基本信息等)得到一个TrustManager,该trustManager收到服务端证书后会进行下面校验:
- 证书是否完整(通过验证签名判断证书是否被篡改)
- 自己是否信任服务端证书
client信任证书链中的某个证书后,则用该证书签发的证书都是被信任的。(一般直接信任CA,则CA下签发的所有证书都被信任。)
该例中的证书是自签名的,客户端只会收到一个证书,IotsTrustManager会校验服务端所发证书和本地证书的公钥是否一致、公司基本信息是否一致。
2.2 结果
IotsTrustManager不会校验服务端证书是否过期,client依赖的本地证书过期后也不会有问题,所以证书过期后对线上流量也没影响。
x509Certificate.checkValidity()
:会校验证书是否过期。
如果client的TrustManager是这样的,那么服务端证书过期后,TLS握手肯定失败。
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType,
Socket socket) throws CertificateException {
//验证服务器证书合法性
X509Certificate x509Certificate=chain[0];
//校验证书是否过期
x509Certificate.checkValidity();
rootTrusm.checkServerTrusted(chain, authType);
}
3. 证书升级
虽然证书过期对线上流量无影响,但平台一直用一个过期的证书太low了点吧,升!这次证书升级只升级服务端证书,client本地依赖的iots.crt还是老的6月26过期的证书(client都是设备,没法搞)。
新生成证书要求:公司的基本信息、公钥不能变,否则client会不信任新的证书。
证书升级步骤:
- 已有公钥(server.pem)和私钥(server.key)
- 生成证书签发签发文件server.csr,在该步需要输入公司基本信息,一定要保证这些基本信息和原有证书上的信息一致。(因为用于签发老证书的csr丢失了,所以重新生成。如果老证书的csr还存在,该步忽略,直接使用老证书的csr即可)
openssl req -utf8 -new -key server.key -out server.csr
- CA签发证书(这里是自签名),新的证书就生成了。
openssl x509 -req -in server.csr -signkey server.key -days 3650 -sha256 -out server.crt
- 证书和私钥打包成jks文件供服务端使用 (先生成了p12文件,再从p12转成jks)。
openssl pkcs12 -export -in server.crt -inkey server.key -out server_expire_test.p12 -name iots
keytool -importkeystore -srckeystore 3.p12 -srcstoretype PKCS12 -deststoretype JKS -destkeystore 3.jks
- 其他
下面以chrome为例说明不同浏览器对于不信任证书的处理。
会提示不安全的证书,但是TLS已经握手成功。点击继续前往XXXX
会继续发送业务数据。也就是虽然证书不被信任,但是通讯仍然是TLS的,但是所访问的站点可能是伪造的。
image.png
服务端显示握手成功

网友评论