Java的SSLContext工作原理

SSLContext 是 HTTPS、TLS、mTLS、OAuth2、OpenID Connect、Spring Security、HttpClient、Kafka、Redis SSL 等所有安全通信的底层核心。

很多人配置过:

1
2
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(...);

但不知道它到底在干什么。

实际上 SSLContext 可以理解为:

1
TLS运行时环境

或者:

1
TLS协议栈实例

类似于:

1
2
3
4
5
6
7
JDBC

Connection

TLS

SSLContext

一、SSLContext是什么

Java中的:

1
javax.net.ssl.SSLContext

负责管理:

1
2
3
4
5
6
证书
私钥
信任链
TLS协议
加密套件
随机数生成器

它本身不进行网络通信。

真正通信的是:

1
2
3
4
5
6
7
SSLSocket

SSLEngine

HttpsURLConnection

HttpClient

这些对象。

而它们都依赖:

1
SSLContext

提供安全能力。


二、整体架构

可以理解为:

1
2
3
4
5
6
7
             SSLContext

┌───────────┴───────────┐
│ │
TrustManager KeyManager
│ │
验证别人证书 提供自己的证书

其中:

1
TrustManager

负责:

1
我信任谁

1
KeyManager

负责:

1
我是谁

这是整个TLS最核心的思想。


三、单向TLS

普通HTTPS:

1
2
3
浏览器

服务器

浏览器验证服务器。

服务器不验证浏览器。


即:

1
2
3
4
5
客户端
TrustManager

服务器
KeyManager

浏览器:

1
验证服务器证书

服务器:

1
出示自己的证书

例如:

1
https://google.com

就是这样。


四、双向TLS(mTLS)

很多企业内部系统:

1
2
3
4
5
支付系统

银行系统

微服务调用

会使用:

1
Mutual TLS

即:

1
2
3
客户端验证服务器

服务器验证客户端

流程:

1
2
3
4
5
6
7
Client
↓证书
Server

Server
↓证书
Client

双方都要提供证书。


SSLContext中:

1
TrustManager

验证对方。


1
KeyManager

提供自己证书。


因此:

1
2
3
4
5
6
7
客户端
KeyManager
TrustManager

服务器
KeyManager
TrustManager

都需要。


五、SSLContext初始化

最经典代码:

1
2
3
4
5
6
7
8
SSLContext sslContext =
SSLContext.getInstance("TLS");

sslContext.init(
keyManagers,
trustManagers,
new SecureRandom()
);

这里有三个参数:

1
2
3
4
5
init(
KeyManager[],
TrustManager[],
SecureRandom
)

六、KeyManager是什么

负责:

1
2
提供证书
提供私钥

例如:

服务器有:

1
2
server.crt
server.key

TLS握手:

1
2
3
4
5
Client Hello

Server Hello

Certificate

到:

1
Certificate

阶段。


SSLContext会调用:

1
KeyManager

获取:

1
2
3
证书链

私钥

发送给客户端。


因此:

1
KeyManager

本质:

1
证书提供者

七、TrustManager是什么

负责:

1
验证对方证书

例如:

收到:

1
www.google.com

证书。


SSLContext调用:

1
TrustManager

检查:

1
2
3
4
5
6
7
CA签名

域名

有效期

证书链

验证成功:

1
TLS继续

失败:

1
SSLHandshakeException

八、KeyStore是什么

很多人把:

1
2
3
4
5
SSLContext

KeyManager

KeyStore

搞混。


KeyStore:

1
证书仓库

里面存:

1
2
3
4
5
私钥

证书

证书链

常见:

1
2
3
JKS

PKCS12

例如:

1
server.p12

加载:

1
2
3
4
KeyStore ks =
KeyStore.getInstance("PKCS12");

ks.load(...);

九、TrustStore是什么

TrustStore也是:

1
KeyStore

一种。


区别:

普通KeyStore:

1
存自己的证书

TrustStore:

1
存信任的CA

例如:

1
cacerts

JDK默认:

1
JAVA_HOME/lib/security/cacerts

(不同版本路径略有差异)


里面有:

1
2
3
4
5
DigiCert

GlobalSign

Let's Encrypt

等根证书。


十、TLS握手时SSLContext干了什么

假设:

1
HttpClient

访问:

1
https://api.example.com

流程:

Client Hello

发送:

1
2
3
4
5
TLS版本

Cipher Suites

随机数

Server Hello

服务器返回:

1
证书

SSLContext

调用:

1
TrustManager

验证:

1
证书链

验证:

1
2
3
4
5
Leaf

Intermediate

Root

一直到:

1
cacerts

中的根证书。


成功:

1
继续握手

失败:

1
SSLHandshakeException

十一、最经典报错

PKIX path building failed

例如:

1
2
PKIX path building failed
unable to find valid certification path

意思:

1
找不到可信CA

不是:

1
网络问题

而是:

1
TrustStore里面没有对应根证书

解决:

导入证书:

1
keytool -importcert

十二、很多公司这样关闭验证

开发环境经常看到:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
TrustManager[] trustAll =
{
new X509TrustManager()
{
public void checkServerTrusted(...) {}

public void checkClientTrusted(...) {}

public X509Certificate[]
getAcceptedIssuers()
{
return null;
}
}
};

然后:

1
2
3
4
5
sslContext.init(
null,
trustAll,
new SecureRandom()
);

效果:

1
信任所有证书

相当于:

1
证书验证彻底关闭

开发环境方便。

生产环境危险。


十三、Spring Boot里面在哪里

例如:

1
2
3
4
server:
ssl:
key-store: server.p12
key-store-password: 123456

Spring Boot启动:

1
2
3
4
5
6
7
Tomcat

SSLContext

KeyManager

读取server.p12

最终:

1
HTTPS端口启动

十四、SSLSocket 和 SSLEngine

SSLContext最终会生成:

1
SSLSocket

或者:

1
SSLEngine

SSLSocket:

1
阻塞IO

传统模式。


SSLEngine:

1
NIO

例如:

  • Netty
  • Tomcat NIO
  • Undertow
  • gRPC

底层大量使用。


架构:

1
2
3
4
5
6
7
SSLContext

SSLEngine

TLS协议实现

Socket

十五、JDK里的真实实现

你写:

1
SSLContext.getInstance("TLS")

实际上得到的是:

1
SunJSSE

实现。

JSSE 全称:

1
Java Secure Socket Extension

它是 Java TLS 的官方实现。


完整关系图可以记成:

1
2
3
4
5
6
7
8
9
10
11
12
13
SSLContext

├── KeyManager
│ └── 我的证书和私钥

├── TrustManager
│ └── 我信任的CA

├── SecureRandom

├── SSLSocket

└── SSLEngine

从 TLS 握手角度看:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
KeyManager

发送自己的证书

TrustManager

验证对方证书

SSLContext

组织整个TLS握手

SSLEngine/SSLSocket

真正执行加解密通信

所以一句话总结:

SSLContext 是 Java TLS 体系的总控制器,它管理证书、私钥、信任链和加密参数;KeyManager 负责“证明我是谁”,TrustManager 负责“判断你是谁”,两者共同完成 TLS 握手和安全通信。