golang.org/x/net@v0.25.1-0.20240516223405-c87a5b62e243/quic/tls.go (about)

     1  // Copyright 2023 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build go1.21
     6  
     7  package quic
     8  
     9  import (
    10  	"context"
    11  	"crypto/tls"
    12  	"errors"
    13  	"fmt"
    14  	"net"
    15  	"time"
    16  )
    17  
    18  // startTLS starts the TLS handshake.
    19  func (c *Conn) startTLS(now time.Time, initialConnID []byte, peerHostname string, params transportParameters) error {
    20  	tlsConfig := c.config.TLSConfig
    21  	if a, _, err := net.SplitHostPort(peerHostname); err == nil {
    22  		peerHostname = a
    23  	}
    24  	if tlsConfig.ServerName == "" && peerHostname != "" {
    25  		tlsConfig = tlsConfig.Clone()
    26  		tlsConfig.ServerName = peerHostname
    27  	}
    28  
    29  	c.keysInitial = initialKeys(initialConnID, c.side)
    30  
    31  	qconfig := &tls.QUICConfig{TLSConfig: tlsConfig}
    32  	if c.side == clientSide {
    33  		c.tls = tls.QUICClient(qconfig)
    34  	} else {
    35  		c.tls = tls.QUICServer(qconfig)
    36  	}
    37  	c.tls.SetTransportParameters(marshalTransportParameters(params))
    38  	// TODO: We don't need or want a context for cancelation here,
    39  	// but users can use a context to plumb values through to hooks defined
    40  	// in the tls.Config. Pass through a context.
    41  	if err := c.tls.Start(context.TODO()); err != nil {
    42  		return err
    43  	}
    44  	return c.handleTLSEvents(now)
    45  }
    46  
    47  func (c *Conn) handleTLSEvents(now time.Time) error {
    48  	for {
    49  		e := c.tls.NextEvent()
    50  		if c.testHooks != nil {
    51  			c.testHooks.handleTLSEvent(e)
    52  		}
    53  		switch e.Kind {
    54  		case tls.QUICNoEvent:
    55  			return nil
    56  		case tls.QUICSetReadSecret:
    57  			if err := checkCipherSuite(e.Suite); err != nil {
    58  				return err
    59  			}
    60  			switch e.Level {
    61  			case tls.QUICEncryptionLevelHandshake:
    62  				c.keysHandshake.r.init(e.Suite, e.Data)
    63  			case tls.QUICEncryptionLevelApplication:
    64  				c.keysAppData.r.init(e.Suite, e.Data)
    65  			}
    66  		case tls.QUICSetWriteSecret:
    67  			if err := checkCipherSuite(e.Suite); err != nil {
    68  				return err
    69  			}
    70  			switch e.Level {
    71  			case tls.QUICEncryptionLevelHandshake:
    72  				c.keysHandshake.w.init(e.Suite, e.Data)
    73  			case tls.QUICEncryptionLevelApplication:
    74  				c.keysAppData.w.init(e.Suite, e.Data)
    75  			}
    76  		case tls.QUICWriteData:
    77  			var space numberSpace
    78  			switch e.Level {
    79  			case tls.QUICEncryptionLevelInitial:
    80  				space = initialSpace
    81  			case tls.QUICEncryptionLevelHandshake:
    82  				space = handshakeSpace
    83  			case tls.QUICEncryptionLevelApplication:
    84  				space = appDataSpace
    85  			default:
    86  				return fmt.Errorf("quic: internal error: write handshake data at level %v", e.Level)
    87  			}
    88  			c.crypto[space].write(e.Data)
    89  		case tls.QUICHandshakeDone:
    90  			if c.side == serverSide {
    91  				// "[...] the TLS handshake is considered confirmed
    92  				// at the server when the handshake completes."
    93  				// https://www.rfc-editor.org/rfc/rfc9001#section-4.1.2-1
    94  				c.confirmHandshake(now)
    95  			}
    96  			c.handshakeDone()
    97  		case tls.QUICTransportParameters:
    98  			params, err := unmarshalTransportParams(e.Data)
    99  			if err != nil {
   100  				return err
   101  			}
   102  			if err := c.receiveTransportParameters(params); err != nil {
   103  				return err
   104  			}
   105  		}
   106  	}
   107  }
   108  
   109  // handleCrypto processes data received in a CRYPTO frame.
   110  func (c *Conn) handleCrypto(now time.Time, space numberSpace, off int64, data []byte) error {
   111  	var level tls.QUICEncryptionLevel
   112  	switch space {
   113  	case initialSpace:
   114  		level = tls.QUICEncryptionLevelInitial
   115  	case handshakeSpace:
   116  		level = tls.QUICEncryptionLevelHandshake
   117  	case appDataSpace:
   118  		level = tls.QUICEncryptionLevelApplication
   119  	default:
   120  		return errors.New("quic: internal error: received CRYPTO frame in unexpected number space")
   121  	}
   122  	err := c.crypto[space].handleCrypto(off, data, func(b []byte) error {
   123  		return c.tls.HandleData(level, b)
   124  	})
   125  	if err != nil {
   126  		return err
   127  	}
   128  	return c.handleTLSEvents(now)
   129  }