tls.go中的流程梳理

文章目录

tls.go中的流程梳理

b站博主的 tls 加密过程
  1. 客户端发送ClentHello(tls版本 +加密套件+ 随机数1)
  2. 服务器发送ServerHello(tls版本 + 加密套件 +随机数2)
    1. 这个阶段之后,双方都知道了tls版本,选定的加密算法,两个随机数
  3. 服务器发送一个X.509证书,客户端用于验证且知道了服务器的公钥,用于后续传输数据加密
  4. 服务器发送它自己的公钥,若上一步有,则这一步不需要
  5. 服务器发送 server Hello Done
  6. 客户端生成 随机数3(预主密钥),并用服务器公钥发送给客户端
    1. 至此 双方都知道了3个随机数,根据3个随机数得到对称加密的秘钥
  7. Change Cipher Spec 表示随后的信息都将用双方商定的加密方法和密钥发送
自己推理的过程(未完待续)
发送ClientHello
  1. 客户端发送 Dial(network, addr string, config *Config) (*Conn, error)

首先调用了Dialer拨号方法得到了 rawConn,然后通过Client(conn net.Conn, config *Config)封装了tls包下的Conn结构。然后进行握手c.HandshakeContext

go 复制代码
// 重要代码  ctx context.Context 
func dial(ctx context.Context, netDialer *net.Dialer, network, addr string, config *Config) (*Conn, error) {
    rawConn, err := netDialer.DialContext(ctx, network, addr)
    
    // 获取主机名 hostname
    colonPos := strings.LastIndex(addr, ":")
    if colonPos == -1 {
        colonPos = len(addr)
    }
    hostname := addr[:colonPos]
    
    // 握手阶段 此处初始化了Client
    conn := Client(rawConn, config)
    if err := conn.HandshakeContext(ctx); err != nil {
        rawConn.Close()
        return nil, err
    }
    return conn, nil
}
  1. 分析 conn := Client(rawConn, config)

发现有一个函数 c.handshakeFn = c.clientHandshake 后续要用到

go 复制代码
func Client(conn net.Conn, config *Config) *Conn {
	c := &Conn{
		conn:     conn,
		config:   config,
		isClient: true,
	}
	c.handshakeFn = c.clientHandshake
	return c
}
  1. 点到 conn.HandshakeContext(ctx)分析
go 复制代码
// 删掉无关代码
func (c *Conn) handshakeContext(ctx context.Context) (ret error) {
	// 在此处做了 client 的 handshake
	c.handshakeErr = c.handshakeFn(handshakeCtx)
}
  1. 点到 c.handshakeFn(handshakeCtx)
go 复制代码
func (c *Conn) clientHandshake(ctx context.Context) (err error) {	
    // 此处初始化了 hello 报文
	hello, ecdheKey, err := c.makeClientHello()
}

// 下面的函数生成了 hello 报文  包括密钥空间 密钥等等
func (c *Conn) makeClientHello() (*clientHelloMsg, *ecdh.PrivateKey, error) {
	hello := &clientHelloMsg{
		vers:                         clientHelloVersion,
		compressionMethods:           []uint8{compressionNone},
		random:                       make([]byte, 32),
		extendedMasterSecret:         true,
		ocspStapling:                 true,
		scts:                         true,
		serverName:                   hostnameInSNI(config.ServerName),
		supportedCurves:              config.curvePreferences(),
		supportedPoints:              []uint8{pointFormatUncompressed},
		secureRenegotiationSupported: true,
		alpnProtocols:                config.NextProtos,
		supportedVersions:            supportedVersions,
	}
	var key *ecdh.PrivateKey
	return hello, key, nil
}
  1. 生成hello报文后,调用函数c.writeHandshakeRecord发送数据,c.readHandshake读取数据
go 复制代码
func (c *Conn) clientHandshake(ctx context.Context) (err error) {
	hello, ecdheKey, err := c.makeClientHello()
	
	if _, err := c.writeHandshakeRecord(hello, nil); err != nil {
		return err
	}

	// serverHelloMsg is not included in the transcript
	msg, err := c.readHandshake(nil)

	serverHello, ok := msg.(*serverHelloMsg)

	return nil
}
获取ServerHello

如上:在发送完ClientHello信息后使用c.readHandshake(),获取从服务器过来的ServerHello信息。然后是使用类型强转serverHello, ok := msg.(*serverHelloMsg)

然后根据SeverHello中选择的TLS版本和ClientHello中的版本范围进行校验。看服务器发送过来的TLS版本是否在ClientHello指定的范围中。

相关推荐
奈葵4 分钟前
Spring Boot/MVC
java·数据库·spring boot
lozhyf6 分钟前
Go语言-学习一
开发语言·学习·golang
leegong2311112 分钟前
Oracle、PostgreSQL该学哪一个?
数据库·postgresql·oracle
中东大鹅17 分钟前
MongoDB基本操作
数据库·分布式·mongodb·hbase
爱偷懒的程序源19 分钟前
解决go.mod文件中replace不生效的问题
开发语言·golang
夜光小兔纸39 分钟前
Oracle 普通用户连接hang住处理方法
运维·数据库·oracle
兩尛2 小时前
订单状态定时处理、来单提醒和客户催单(day10)
java·前端·数据库
web2u2 小时前
MySQL 中如何进行 SQL 调优?
java·数据库·后端·sql·mysql·缓存
h7997102 小时前
go学习杂记
开发语言·学习·golang
Ciderw3 小时前
Golang并发机制及CSP并发模型
开发语言·c++·后端·面试·golang·并发·共享内存