OpenJDK8源码分析SSL握手流程

2024-06-07 21:38

本文主要是介绍OpenJDK8源码分析SSL握手流程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

准备

说明
  1. 示例项目地址:https://github.com/shenjy24/jackal-ssl
  2. JDK版本:OpenJDK8。
  3. 系统:MAC
  4. IDE: IDEA
安装OpenJDK
  1. 安装JDK
brew tap AdoptOpenJDK/openjdk
brew install caskroom/cask/brew-cask
brew cask install adoptopenjdk8
  1. IDEA更换JDK,使用openjdk替换sun jdk
Wireshark抓包

使用Wireshark抓包可以先了解到SSL通讯的大体流程,可以参考 Wireshark 抓包理解 HTTPS 请求流程 ,这篇文章详细分析了整个HTTPS通讯流程,包括TCP三次握手、SSL握手环节、TCP四次挥手。

SSL通信流程

SSL通信流程主要有以下四步:

  1. 加载密钥库,初始化SSLContext;
  2. 建立Socket连接;
  3. 进行SSL握手;
  4. 发送加密应用数据。
一. 初始化SSLContext
二. 建立Socket
服务端
  1. 创建ServerSocket

服务端使用SSLServerSocketFactoryImpl的createServerSocket方法来创建ServerSocket,该方法主要进行以下两件事:

(1) 调用native方法socketBind绑定服务端地址和端口,调用native方法socketListen进行监听。

(2) 进行SSL信息初始化,获取支持的加密套件和协议版本。

  1. accept()

(1) 通常我们会在循环中调用accept,accept会事先创建Socket,不过还没初始化;调用native方法socketAccept,该方法会发生阻塞,直到有客户端连接,此时返回初始化完毕的Socket,这里该Socket的实现为SSLSocket。具体代码可以参考ServerSocket的implAccept(Socket)方法。

(2) 当有客户端连接到来时,退出阻塞,返回SSLScoket;接着会初始化ServerHandshaker,初始化主要完成以下操作:

  • 将connectionState标记为cs_HANDSHAKE,表示还未经过握手环节。
  • 设置支持的协议版本列表、加密套件列表、是否需要客户端认证等。代码参考SSLSocketImpl的initHandshaker方法。
客户端
  1. 创建Socket

(1) 初始化Session,支持的协议版本、加密套件等;

(2) 使用native方法socketCreate创建Socket;构造URI socket:127.0.0.1:8080,使用native方法socketConnect发起连接;

(3) 初始化ClientHandshaker,与服务端的类似。

  1. 客户端连接成功之后,向服务器发送数据,最终会调用SSLSocketImpl的writeRecord方法。

(1) 判断connectionState是否为cs_HANDSHAKE,是的则调用kickstartHandshake开启握手环节,即发送 client_hello,握手环节下面再仔细分析。

三. SSL握手
时序图

在这里插入图片描述

流程详解
  1. 客户端第一次发送数据时,需要进行SSL握手,调用Handshaker的kickstart方法开启握手流程,此时客户端发送ClientHello消息,主要参数如下:
  • protocolVersion: 支持的最高协议版本
  • sessionId: 会话ID
  • cipherSuites: 支持的加密套件
  • clnt_random: 客户端随机数
  • compression_methods: 压缩算法(可选)
  • extensions: 拓展字段,会携带支持的签名算法列表。另外如果支持EC算法,还会携带相关参数。
  1. 服务端收到客户端的ClientHello之后,会进行以下操作,主要逻辑在ServerHandshaker中的clientHello方法中。

(1) 服务端发送ServerHello消息,主要参数如下:

  • protocolVersion: 从服务端支持的协议版本中选取的,该版本小于等于客户端发送过来的协议版本;
  • svr_random: 服务端随机数
  • sessionId: 会话ID
  • cipherSuite: 客户端发送过来的加密套件列表中选取的
  • compression_method: 压缩方法
  • extensions: 扩展字段

(2) 服务端发送CertificateMsg消息,主要向客户端发送服务端的证书。

(3) 服务端发送ServerKeyExchange消息,ServerKeyExchange是抽象基类,具体子类要看使用哪种密钥交换算法,这里发送的是DH_ServerKeyExchange。

主要参数如下:

  • protocolVersion: 协议版本
  • dh_p、dh_g、dh_Ys: 前两个是DH算法的参数,后一个是DH算法中的公钥
  • signature: 签名
  • preferableSignatureAlgorithm: 选中的签名算法

(4) 服务端发送CertificateRequest消息,请求客户端证书。实际上大多数系统只要求单向认证,此步骤通常情况下会被忽略。

(5) 服务端发送ServerHelloDone消息。

  1. 客户端接收服务端发过来的SererHello消息,主要进行以下处理:设置协商好的协议版本、服务端随机数、加密套件、以及创建Session。

  2. 客户端接收服务端发过来的CertificateMsg消息,进行证书校验。

  3. 客户端接收服务端发过来的ServerKeyExchange消息,利用发过来的DH参数(dh_p,dh_p)创建DHCrypt,主要生成客户端的DH公钥,这些参数用于后续生成主密钥。

  4. 客户端接收服务端发过来的CertificateRequest消息,客户端会构造CertificateMsg消息(certRequest属性,此时还未完全初始化),但此时还不会立即发送给服务端。

  5. 客户端接收服务端发过来的ServerHelloDone消息,进行以下操作:

(1) 通过判断certRequest是否为空来判断是否需要发送客户端证书,如果需要客户端证书,则从KeyManager中获取客户端证书,构造Certificate握手消息发送给服务端。

(2) 客户端发送ClientKeyExchange握手消息,ClientKeyExchange是抽象基类,具体子类要看使用哪种密钥交换算法,这里发送的是DHClientKeyExchange,主要是客户端的DH公钥。

(3) 使用客户端DH参数和服务端DH公钥生成preMasterSecret,接着用preMasterSecret和prf函数生成masterSecret,session会存储masterSecret;用masterSecret和prf函数生成connectionKeys,connectionKeys包含clntWriteKey,svrWriteKey,clntWriteIV,svrWriteIV,clntMacSecret和svrMacSecret,这些参数用于后续生成通信的readCipher, readAuthenticator, writeCipher, writeAuthenticator。

(4) 客户端发送CertificateVerify握手消息;

(5) 客户端发送contentType为ct_change_cipher_spec的消息,握手消息的contentType为ct_handshake,利用clntWriteKey, clntWriteIV生成客户端的writeCipher,用于客户端读取数据时解密;利用clntMacSecret生成客户端的writeAuthenticator,用于对客户端数据进行签名。

(6) 客户端发送Finished握手消息;

  1. 服务端接收客户端发的Certificate消息,进行证书校验。

  2. 服务端接收客户端发的ClientKeyExchange消息,这里收到DHClientKeyExchange消息对象,进行以下操作:

(1) 根据服务端DH参数和客户端DH公钥计算出preMasterSecret;

(2) 利用preMasterSecret和prf函数生成masterSecret,session会存储masterSecret;

(3) 利用masterSecret和prf函数生成connectionKeys,connectionKeys包含clntWriteKey,svrWriteKey,clntWriteIV,svrWriteIV,clntMacSecret和svrMacSecret,这些参数用于后续生成通信的readCipher, readAuthenticator, writeCipher, writeAuthenticator。

  1. 服务端收到客户端发的CertificateVerify消息,主要对客户端证书进行验签。

  2. 服务端收到客户端发的change_cipher_spec消息,利用clntWriteKey, clntWriteIV生成服务端的readCipher,readCipher用于服务端读取数据时解密;利用clntMacSecret生成服务端的readAuthenticator,readAuthenticator用于对客户端数据进行验签。

  3. 服务端收到客户端发的Finished握手消息,进行以下操作:

(1) 对verifyData参数进行验证,用于判断双方生成的masterSecret是否一致。

(2) 发送contentType为ct_change_cipher_spec的消息,利用svrWriteKey和svrWriteIV生成服务端的writeCipher,用于服务端发送数据时进行加密;利用svrMAcSecret生成服务端的writeAuthenticator,用于对服务端的数据进行签名。

(3) 发送Finished握手消息。

  1. 客户端收到服务端发的change_cipher_spec消息,利用svrWriteKey, svrWriteIV生成客户端的readCipher,用于客户端读取数据时解密;利用svrMacSecret生成客户端的readAuthenticator,用于对服务端数据进行验签。

  2. 客户端收到服务端发的Finished消息,对verifyData参数进行验证,用于判断双方生成的masterSecret是否一致。

四. 发送应用数据

客户端发送数据时使用writeAuthenticator进行签名,再使用writeCipher对数据进行加密,然后发送给服务端;服务端收到数据后使用readCipher对数据进行解密,再使用readAuthenticator进行验签。服务端发送数据给客户端也是同理。

这篇关于OpenJDK8源码分析SSL握手流程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1040374

相关文章

MySQL 临时表与复制表操作全流程案例

《MySQL临时表与复制表操作全流程案例》本文介绍MySQL临时表与复制表的区别与使用,涵盖生命周期、存储机制、操作限制、创建方法及常见问题,本文结合实例代码给大家介绍的非常详细,感兴趣的朋友跟随小... 目录一、mysql 临时表(一)核心特性拓展(二)操作全流程案例1. 复杂查询中的临时表应用2. 临时

Android 缓存日志Logcat导出与分析最佳实践

《Android缓存日志Logcat导出与分析最佳实践》本文全面介绍AndroidLogcat缓存日志的导出与分析方法,涵盖按进程、缓冲区类型及日志级别过滤,自动化工具使用,常见问题解决方案和最佳实... 目录android 缓存日志(Logcat)导出与分析全攻略为什么要导出缓存日志?按需过滤导出1. 按

MySQL 升级到8.4版本的完整流程及操作方法

《MySQL升级到8.4版本的完整流程及操作方法》本文详细说明了MySQL升级至8.4的完整流程,涵盖升级前准备(备份、兼容性检查)、支持路径(原地、逻辑导出、复制)、关键变更(空间索引、保留关键字... 目录一、升级前准备 (3.1 Before You Begin)二、升级路径 (3.2 Upgrade

Linux中的HTTPS协议原理分析

《Linux中的HTTPS协议原理分析》文章解释了HTTPS的必要性:HTTP明文传输易被篡改和劫持,HTTPS通过非对称加密协商对称密钥、CA证书认证和混合加密机制,有效防范中间人攻击,保障通信安全... 目录一、什么是加密和解密?二、为什么需要加密?三、常见的加密方式3.1 对称加密3.2非对称加密四、

MySQL中读写分离方案对比分析与选型建议

《MySQL中读写分离方案对比分析与选型建议》MySQL读写分离是提升数据库可用性和性能的常见手段,本文将围绕现实生产环境中常见的几种读写分离模式进行系统对比,希望对大家有所帮助... 目录一、问题背景介绍二、多种解决方案对比2.1 原生mysql主从复制2.2 Proxy层中间件:ProxySQL2.3

python使用Akshare与Streamlit实现股票估值分析教程(图文代码)

《python使用Akshare与Streamlit实现股票估值分析教程(图文代码)》入职测试中的一道题,要求:从Akshare下载某一个股票近十年的财务报表包括,资产负债表,利润表,现金流量表,保存... 目录一、前言二、核心知识点梳理1、Akshare数据获取2、Pandas数据处理3、Matplotl

python panda库从基础到高级操作分析

《pythonpanda库从基础到高级操作分析》本文介绍了Pandas库的核心功能,包括处理结构化数据的Series和DataFrame数据结构,数据读取、清洗、分组聚合、合并、时间序列分析及大数据... 目录1. Pandas 概述2. 基本操作:数据读取与查看3. 索引操作:精准定位数据4. Group

MySQL中EXISTS与IN用法使用与对比分析

《MySQL中EXISTS与IN用法使用与对比分析》在MySQL中,EXISTS和IN都用于子查询中根据另一个查询的结果来过滤主查询的记录,本文将基于工作原理、效率和应用场景进行全面对比... 目录一、基本用法详解1. IN 运算符2. EXISTS 运算符二、EXISTS 与 IN 的选择策略三、性能对比

MySQL 内存使用率常用分析语句

《MySQL内存使用率常用分析语句》用户整理了MySQL内存占用过高的分析方法,涵盖操作系统层确认及数据库层bufferpool、内存模块差值、线程状态、performance_schema性能数据... 目录一、 OS层二、 DB层1. 全局情况2. 内存占js用详情最近连续遇到mysql内存占用过高导致

深度解析Nginx日志分析与499状态码问题解决

《深度解析Nginx日志分析与499状态码问题解决》在Web服务器运维和性能优化过程中,Nginx日志是排查问题的重要依据,本文将围绕Nginx日志分析、499状态码的成因、排查方法及解决方案展开讨论... 目录前言1. Nginx日志基础1.1 Nginx日志存放位置1.2 Nginx日志格式2. 499