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

相关文章

怎样通过分析GC日志来定位Java进程的内存问题

《怎样通过分析GC日志来定位Java进程的内存问题》:本文主要介绍怎样通过分析GC日志来定位Java进程的内存问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、GC 日志基础配置1. 启用详细 GC 日志2. 不同收集器的日志格式二、关键指标与分析维度1.

Spring Security中用户名和密码的验证完整流程

《SpringSecurity中用户名和密码的验证完整流程》本文给大家介绍SpringSecurity中用户名和密码的验证完整流程,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定... 首先创建了一个UsernamePasswordAuthenticationTChina编程oken对象,这是S

MySQL中的表连接原理分析

《MySQL中的表连接原理分析》:本文主要介绍MySQL中的表连接原理分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、背景2、环境3、表连接原理【1】驱动表和被驱动表【2】内连接【3】外连接【4编程】嵌套循环连接【5】join buffer4、总结1、背景

python中Hash使用场景分析

《python中Hash使用场景分析》Python的hash()函数用于获取对象哈希值,常用于字典和集合,不可变类型可哈希,可变类型不可,常见算法包括除法、乘法、平方取中和随机数哈希,各有优缺点,需根... 目录python中的 Hash除法哈希算法乘法哈希算法平方取中法随机数哈希算法小结在Python中,

Java Stream的distinct去重原理分析

《JavaStream的distinct去重原理分析》Javastream中的distinct方法用于去除流中的重复元素,它返回一个包含过滤后唯一元素的新流,该方法会根据元素的hashcode和eq... 目录一、distinct 的基础用法与核心特性二、distinct 的底层实现原理1. 顺序流中的去重

Android ViewBinding使用流程

《AndroidViewBinding使用流程》AndroidViewBinding是Jetpack组件,替代findViewById,提供类型安全、空安全和编译时检查,代码简洁且性能优化,相比Da... 目录一、核心概念二、ViewBinding优点三、使用流程1. 启用 ViewBinding (模块级

关于MyISAM和InnoDB对比分析

《关于MyISAM和InnoDB对比分析》:本文主要介绍关于MyISAM和InnoDB对比分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录开篇:从交通规则看存储引擎选择理解存储引擎的基本概念技术原理对比1. 事务支持:ACID的守护者2. 锁机制:并发控制的艺

javax.net.ssl.SSLHandshakeException:异常原因及解决方案

《javax.net.ssl.SSLHandshakeException:异常原因及解决方案》javax.net.ssl.SSLHandshakeException是一个SSL握手异常,通常在建立SS... 目录报错原因在程序中绕过服务器的安全验证注意点最后多说一句报错原因一般出现这种问题是因为目标服务器

SpringBoot整合Flowable实现工作流的详细流程

《SpringBoot整合Flowable实现工作流的详细流程》Flowable是一个使用Java编写的轻量级业务流程引擎,Flowable流程引擎可用于部署BPMN2.0流程定义,创建这些流程定义的... 目录1、流程引擎介绍2、创建项目3、画流程图4、开发接口4.1 Java 类梳理4.2 查看流程图4

java Long 与long之间的转换流程

《javaLong与long之间的转换流程》Long类提供了一些方法,用于在long和其他数据类型(如String)之间进行转换,本文将详细介绍如何在Java中实现Long和long之间的转换,感... 目录概述流程步骤1:将long转换为Long对象步骤2:将Longhttp://www.cppcns.c