openssl 自建证书
- 背景
- 根证书
-
- [1. 生成根证书私钥 (ECC 256 位,安全且性能好)](#1. 生成根证书私钥 (ECC 256 位,安全且性能好))
- [2. 生成根证书 (有效期 10 年)](#2. 生成根证书 (有效期 10 年))
- 服务器证书
-
- [1. 生成服务器私钥](#1. 生成服务器私钥)
- [2. 生成证书签名请求 (CSR)](#2. 生成证书签名请求 (CSR))
- [3. 用根证书签署服务器证书 (有效期 1 年)](#3. 用根证书签署服务器证书 (有效期 1 年))
- 验证证书
-
- 查看服务器证书内容
- [验证证书链(应该显示 ok)](#验证证书链(应该显示 ok))
- 浏览器导入根证书
- Netty开启wss
- 总结
背景
前提需要openssl 版本>1.1.1
最近做一个项目需要使用wss协议、类似与https,访问加密需要证书相关。了解了下证书相关内容记录一下。
根证书
1. 生成根证书私钥 (ECC 256 位,安全且性能好)
bash
openssl ecparam -name prime256v1 -genkey -noout -out ca-key.pem
2. 生成根证书 (有效期 10 年)
bash
openssl req -x509 -new -nodes -key ca-key.pem -sha256 -days 3650 \
-subj "/C=CN/ST=Beijing/L=Beijing/O=MyPrivateCA/CN=My Root CA" \
-addext "basicConstraints=critical,CA:TRUE,pathlen:0" \
-addext "keyUsage=critical,keyCertSign,cRLSign" \
-out ca-cert.crt
服务器证书
1. 生成服务器私钥
⚠️RSA 2048 位,兼容性最好
bash
openssl genrsa -out server-key.pem 2048
2. 生成证书签名请求 (CSR)
⚠️ CN 请改成你自己的域名或 IP,例如 localhost 或 192.168.1.100
bash
openssl req -new -key server-key.pem -sha256 \
-subj "/C=CN/ST=Beijing/L=Beijing/O=MyPrivateCA/CN=localhost" \
-addext "subjectAltName=DNS:localhost,IP:127.0.0.1" \
-out server.csr
3. 用根证书签署服务器证书 (有效期 1 年)
bash
openssl x509 -req -in server.csr -CA ca-cert.crt -CAkey ca-key.pem \
-CAcreateserial -out server-cert.crt -days 365 -sha256 \
-copy_extensions copy
验证证书
查看服务器证书内容
bash
openssl x509 -in server-cert.crt -text -noout
验证证书链(应该显示 ok)
bash
openssl verify -CAfile ca-cert.crt server-cert.crt
浏览器导入根证书
双击 ca-cert.crt → 选择"安装证书"
选择"本地计算机"(需要管理员权限)→ 下一步
选择"将所有的证书放入下列存储" → 点击"浏览"
选择"受信任的根证书颁发机构" → 确定 → 下一步 → 完成
重启浏览器(完全退出再打开)
Netty开启wss
证书处理
Netty 的 forServer(File certChainFile, File keyFile) 第一个文件必须是完整的证书链,顺序为:服务器证书 → 根证书。
bash
cat server-cert.crt ca-cert.crt > fullchain.crt
- 转换为 PKCS#8 格式
bash
openssl pkcs8 -topk8 -nocrypt -in server-key.pem -out server-key-pkcs8.pem
代码更改
java
public void start() {
bossGroup = new NioEventLoopGroup(1);
workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) {
try {
SslContext sslContext = SslContextBuilder.forServer(
new File("D:\\code\\ca\\fullchain.crt"),
new File("D:\\code\\ca\\server-key-pkcs8.pem")
).build();
ch.pipeline().addLast(sslContext.newHandler(ch.alloc()));
} catch (SSLException e) {
log.info("SslContext init failed !!!");
}
ch.pipeline().addLast(new HttpServerCodec());
ch.pipeline().addLast(new ChunkedWriteHandler());
ch.pipeline().addLast(new HttpObjectAggregator(65536));
ch.pipeline().addLast(new WebSocketServerProtocolHandler(path, null, true, 10 * 1024 * 1024));
ch.pipeline().addLast(webSocketFrameHandler);
}
});
ChannelFuture f = b.bind(port).sync();
log.info("Netty WebSocket Server started on port: {}", port);
// f.channel().closeFuture().sync(); // Don't block here as it's called from Spring's main thread
} catch (InterruptedException e) {
log.error("Netty WebSocket Server interrupted", e);
Thread.currentThread().interrupt();
}
}
验证结果

总结
基本流程
获取证书链:你访问 https:// 网站时,服务器会发送它的"服务器证书"以及所有必要的中间证书。如果网站证书缺少了关键的中间证书,浏览器就可能发出"连接不安全"的警告。
构建信任链:浏览器收到后,会尝试从"服务器证书"开始,一级一级地向上追溯签发者,直到找到一个它内置信任的"根证书"。这就构建了一条完整的信任链。
逐级验证签名:浏览器会从根证书开始,逐级向下验证签名。它会用上级证书的公钥,去解密和验证下一级证书的签名,以此来确认下一级证书确实是由自己签发的、内容没有被篡改。只要能成功追溯到受信任的根,链条就是有效的。
检查证书内容:在验证签名有效后,浏览器还会检查证书里的关键信息,是否与实际相符:
有效期:证书是否在有效期内。
域名匹配:证书里的域名是否和你浏览器地址栏里的域名完全一致。
是否被吊销:浏览器可能会通过在线证书状态协议(OCSP) 等方式,检查证书是否被颁发机构提前注销了。
netty使用wss
1、生成根证书(CA)和私钥(可用 openssl 命令)。
2、生成服务器证书私钥(RSA 或 EC),并转换为 PKCS#8。
3、用根证书签发服务器证书,得到 server-cert.crt。
4、将 server-cert.crt 和 ca-cert.crt 合并为 fullchain.crt(顺序:服务器证书在前,根证书在后)。
5、Netty 服务端配置:
java
SslContext sslCtx = SslContextBuilder.forServer(
new File("/path/to/fullchain.crt"),
new File("/path/to/server-key-pkcs8.pem")
).build();
6、将 ca-cert.crt 分发给所有客户端,并指导它们安装到受信任根证书存储区。
7、客户端使用 wss://your-server-domain 访问,一切正常。