git.prognetwork.ru/x0r/utls@v1.3.3/u_handshake_client.go (about)

     1  // Copyright 2022 uTLS 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  package tls
     6  
     7  import (
     8  	"bytes"
     9  	"compress/zlib"
    10  	"errors"
    11  	"fmt"
    12  	"io"
    13  
    14  	"github.com/andybalholm/brotli"
    15  	"github.com/klauspost/compress/zstd"
    16  )
    17  
    18  // This function is called by (*clientHandshakeStateTLS13).readServerCertificate()
    19  // to retrieve the certificate out of a message read by (*Conn).readHandshake()
    20  func (hs *clientHandshakeStateTLS13) utlsReadServerCertificate(msg any) (processedMsg any, err error) {
    21  	for _, ext := range hs.uconn.Extensions {
    22  		switch ext.(type) {
    23  		case *UtlsCompressCertExtension:
    24  			// Included Compressed Certificate extension
    25  			if len(hs.uconn.certCompressionAlgs) > 0 {
    26  				compressedCertMsg, ok := msg.(*utlsCompressedCertificateMsg)
    27  				if ok {
    28  					if err = transcriptMsg(compressedCertMsg, hs.transcript); err != nil {
    29  						return nil, err
    30  					}
    31  					msg, err = hs.decompressCert(*compressedCertMsg)
    32  					if err != nil {
    33  						return nil, fmt.Errorf("tls: failed to decompress certificate message: %w", err)
    34  					} else {
    35  						return msg, nil
    36  					}
    37  				}
    38  			}
    39  		default:
    40  			continue
    41  		}
    42  	}
    43  	return nil, nil
    44  }
    45  
    46  // called by (*clientHandshakeStateTLS13).utlsReadServerCertificate() when UtlsCompressCertExtension is used
    47  func (hs *clientHandshakeStateTLS13) decompressCert(m utlsCompressedCertificateMsg) (*certificateMsgTLS13, error) {
    48  	var (
    49  		decompressed io.Reader
    50  		compressed   = bytes.NewReader(m.compressedCertificateMessage)
    51  		c            = hs.c
    52  	)
    53  
    54  	// Check to see if the peer responded with an algorithm we advertised.
    55  	supportedAlg := false
    56  	for _, alg := range hs.uconn.certCompressionAlgs {
    57  		if m.algorithm == uint16(alg) {
    58  			supportedAlg = true
    59  		}
    60  	}
    61  	if !supportedAlg {
    62  		c.sendAlert(alertBadCertificate)
    63  		return nil, fmt.Errorf("unadvertised algorithm (%d)", m.algorithm)
    64  	}
    65  
    66  	switch CertCompressionAlgo(m.algorithm) {
    67  	case CertCompressionBrotli:
    68  		decompressed = brotli.NewReader(compressed)
    69  
    70  	case CertCompressionZlib:
    71  		rc, err := zlib.NewReader(compressed)
    72  		if err != nil {
    73  			c.sendAlert(alertBadCertificate)
    74  			return nil, fmt.Errorf("failed to open zlib reader: %w", err)
    75  		}
    76  		defer rc.Close()
    77  		decompressed = rc
    78  
    79  	case CertCompressionZstd:
    80  		rc, err := zstd.NewReader(compressed)
    81  		if err != nil {
    82  			c.sendAlert(alertBadCertificate)
    83  			return nil, fmt.Errorf("failed to open zstd reader: %w", err)
    84  		}
    85  		defer rc.Close()
    86  		decompressed = rc
    87  
    88  	default:
    89  		c.sendAlert(alertBadCertificate)
    90  		return nil, fmt.Errorf("unsupported algorithm (%d)", m.algorithm)
    91  	}
    92  
    93  	rawMsg := make([]byte, m.uncompressedLength+4) // +4 for message type and uint24 length field
    94  	rawMsg[0] = typeCertificate
    95  	rawMsg[1] = uint8(m.uncompressedLength >> 16)
    96  	rawMsg[2] = uint8(m.uncompressedLength >> 8)
    97  	rawMsg[3] = uint8(m.uncompressedLength)
    98  
    99  	n, err := decompressed.Read(rawMsg[4:])
   100  	if err != nil {
   101  		c.sendAlert(alertBadCertificate)
   102  		return nil, err
   103  	}
   104  	if n < len(rawMsg)-4 {
   105  		// If, after decompression, the specified length does not match the actual length, the party
   106  		// receiving the invalid message MUST abort the connection with the "bad_certificate" alert.
   107  		// https://datatracker.ietf.org/doc/html/rfc8879#section-4
   108  		c.sendAlert(alertBadCertificate)
   109  		return nil, fmt.Errorf("decompressed len (%d) does not match specified len (%d)", n, m.uncompressedLength)
   110  	}
   111  	certMsg := new(certificateMsgTLS13)
   112  	if !certMsg.unmarshal(rawMsg) {
   113  		return nil, c.sendAlert(alertUnexpectedMessage)
   114  	}
   115  	return certMsg, nil
   116  }
   117  
   118  // to be called in (*clientHandshakeStateTLS13).handshake(),
   119  // after hs.readServerFinished() and before hs.sendClientCertificate()
   120  func (hs *clientHandshakeStateTLS13) serverFinishedReceived() error {
   121  	if err := hs.sendClientEncryptedExtensions(); err != nil {
   122  		return err
   123  	}
   124  	return nil
   125  }
   126  
   127  func (hs *clientHandshakeStateTLS13) sendClientEncryptedExtensions() error {
   128  	c := hs.c
   129  	clientEncryptedExtensions := new(utlsClientEncryptedExtensionsMsg)
   130  	if c.utls.hasApplicationSettings {
   131  		clientEncryptedExtensions.hasApplicationSettings = true
   132  		clientEncryptedExtensions.applicationSettings = c.utls.localApplicationSettings
   133  		if _, err := c.writeHandshakeRecord(clientEncryptedExtensions, hs.transcript); err != nil {
   134  			return err
   135  		}
   136  	}
   137  
   138  	return nil
   139  }
   140  
   141  func (hs *clientHandshakeStateTLS13) utlsReadServerParameters(encryptedExtensions *encryptedExtensionsMsg) error {
   142  	hs.c.utls.hasApplicationSettings = encryptedExtensions.utls.hasApplicationSettings
   143  	hs.c.utls.peerApplicationSettings = encryptedExtensions.utls.applicationSettings
   144  
   145  	if hs.c.utls.hasApplicationSettings {
   146  		if hs.uconn.vers < VersionTLS13 {
   147  			return errors.New("tls: server sent application settings at invalid version")
   148  		}
   149  		if len(hs.uconn.clientProtocol) == 0 {
   150  			return errors.New("tls: server sent application settings without ALPN")
   151  		}
   152  
   153  		// Check if the ALPN selected by the server exists in the client's list.
   154  		if alps, ok := hs.uconn.config.ApplicationSettings[hs.serverHello.alpnProtocol]; ok {
   155  			hs.c.utls.localApplicationSettings = alps
   156  		} else {
   157  			// return errors.New("tls: server selected ALPN doesn't match a client ALPS")
   158  			return nil // ignore if client doesn't have ALPS in use.
   159  			// TODO: is this a issue or not?
   160  		}
   161  	}
   162  
   163  	return nil
   164  }