github.com/mholt/caddy-l4@v0.0.0-20241104153248-ec8fae209322/modules/l4tls/parsehello.go (about)

     1  // Copyright 2020 Matthew Holt
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package l4tls
    16  
    17  import (
    18  	"crypto/tls"
    19  	"strings"
    20  
    21  	"golang.org/x/crypto/cryptobyte"
    22  )
    23  
    24  // Most of this file is borrowed from the Go standard library, ca. May 2020.
    25  // It was written by the Go Authors and has this copyright:
    26  //
    27  //    Copyright 2009 The Go Authors. All rights reserved.
    28  //    Use of this source code is governed by a BSD-style
    29  //    license that can be found in the LICENSE file.
    30  //
    31  // This code has been modified since then.
    32  
    33  func parseRawClientHello(data []byte) (info ClientHelloInfo) {
    34  	defer func() {
    35  		if len(info.SupportedVersions) == 0 {
    36  			info.SupportedVersions = supportedVersionsFromMax(info.Version)
    37  		}
    38  	}()
    39  
    40  	s := cryptobyte.String(data)
    41  
    42  	if !s.Skip(4) || // message type and uint24 length field
    43  		!s.ReadUint16(&info.Version) || !s.ReadBytes(&info.Random, 32) ||
    44  		!readUint8LengthPrefixed(&s, &info.SessionID) {
    45  		return
    46  	}
    47  
    48  	var cipherSuites cryptobyte.String
    49  	if !s.ReadUint16LengthPrefixed(&cipherSuites) {
    50  		return
    51  	}
    52  	for !cipherSuites.Empty() {
    53  		var suite uint16
    54  		if !cipherSuites.ReadUint16(&suite) {
    55  			return
    56  		}
    57  		if suite == scsvRenegotiation {
    58  			info.SecureRenegotiationSupported = true
    59  		}
    60  		info.CipherSuites = append(info.CipherSuites, suite)
    61  	}
    62  
    63  	if !readUint8LengthPrefixed(&s, &info.CompressionMethods) {
    64  		return
    65  	}
    66  
    67  	if s.Empty() {
    68  		// ClientHello is optionally followed by extension data
    69  		return
    70  	}
    71  
    72  	var extensions cryptobyte.String
    73  	if !s.ReadUint16LengthPrefixed(&extensions) || !s.Empty() {
    74  		return
    75  	}
    76  
    77  	for !extensions.Empty() {
    78  		var extension uint16
    79  		var extData cryptobyte.String
    80  		if !extensions.ReadUint16(&extension) ||
    81  			!extensions.ReadUint16LengthPrefixed(&extData) {
    82  			return
    83  		}
    84  
    85  		// record that client advertised support for this extension
    86  		info.Extensions = append(info.Extensions, extension)
    87  
    88  		switch extension {
    89  		case extensionServerName:
    90  			// RFC 6066, Section 3
    91  			var nameList cryptobyte.String
    92  			if !extData.ReadUint16LengthPrefixed(&nameList) || nameList.Empty() {
    93  				return
    94  			}
    95  			for !nameList.Empty() {
    96  				var nameType uint8
    97  				var serverName cryptobyte.String
    98  				if !nameList.ReadUint8(&nameType) ||
    99  					!nameList.ReadUint16LengthPrefixed(&serverName) ||
   100  					serverName.Empty() {
   101  					return
   102  				}
   103  				if nameType != 0 {
   104  					continue
   105  				}
   106  				if len(info.ServerName) != 0 {
   107  					// Multiple names of the same name_type are prohibited.
   108  					return
   109  				}
   110  				info.ServerName = string(serverName)
   111  				// An SNI value may not include a trailing dot.
   112  				if strings.HasSuffix(info.ServerName, ".") {
   113  					return
   114  				}
   115  			}
   116  		case extensionStatusRequest:
   117  			// RFC 4366, Section 3.6
   118  			var statusType uint8
   119  			var ignored cryptobyte.String
   120  			if !extData.ReadUint8(&statusType) ||
   121  				!extData.ReadUint16LengthPrefixed(&ignored) ||
   122  				!extData.ReadUint16LengthPrefixed(&ignored) {
   123  				return
   124  			}
   125  			info.OCSPStapling = statusType == statusTypeOCSP
   126  		case extensionSupportedCurves:
   127  			// RFC 4492, sections 5.1.1 and RFC 8446, Section 4.2.7
   128  			var curves cryptobyte.String
   129  			if !extData.ReadUint16LengthPrefixed(&curves) || curves.Empty() {
   130  				return
   131  			}
   132  			for !curves.Empty() {
   133  				var curve uint16
   134  				if !curves.ReadUint16(&curve) {
   135  					return
   136  				}
   137  				info.SupportedCurves = append(info.SupportedCurves, tls.CurveID(curve))
   138  			}
   139  		case extensionSupportedPoints:
   140  			// RFC 4492, Section 5.1.2
   141  			if !readUint8LengthPrefixed(&extData, &info.SupportedPoints) ||
   142  				len(info.SupportedPoints) == 0 {
   143  				return
   144  			}
   145  		case extensionSessionTicket:
   146  			// RFC 5077, Section 3.2
   147  			info.TicketSupported = true
   148  			extData.ReadBytes(&info.SessionTicket, len(extData))
   149  		case extensionSignatureAlgorithms:
   150  			// RFC 5246, Section 7.4.1.4.1
   151  			var sigAndAlgs cryptobyte.String
   152  			if !extData.ReadUint16LengthPrefixed(&sigAndAlgs) || sigAndAlgs.Empty() {
   153  				return
   154  			}
   155  			for !sigAndAlgs.Empty() {
   156  				var sigAndAlg uint16
   157  				if !sigAndAlgs.ReadUint16(&sigAndAlg) {
   158  					return
   159  				}
   160  				info.SignatureSchemes = append(
   161  					info.SignatureSchemes, tls.SignatureScheme(sigAndAlg))
   162  			}
   163  		case extensionSignatureAlgorithmsCert:
   164  			// RFC 8446, Section 4.2.3
   165  			var sigAndAlgs cryptobyte.String
   166  			if !extData.ReadUint16LengthPrefixed(&sigAndAlgs) || sigAndAlgs.Empty() {
   167  				return
   168  			}
   169  			for !sigAndAlgs.Empty() {
   170  				var sigAndAlg uint16
   171  				if !sigAndAlgs.ReadUint16(&sigAndAlg) {
   172  					return
   173  				}
   174  				info.SupportedSchemesCert = append(
   175  					info.SupportedSchemesCert, tls.SignatureScheme(sigAndAlg))
   176  			}
   177  		case extensionRenegotiationInfo:
   178  			// RFC 5746, Section 3.2
   179  			if !readUint8LengthPrefixed(&extData, &info.SecureRenegotiation) {
   180  				return
   181  			}
   182  			info.SecureRenegotiationSupported = true
   183  		case extensionALPN:
   184  			// RFC 7301, Section 3.1
   185  			var protoList cryptobyte.String
   186  			if !extData.ReadUint16LengthPrefixed(&protoList) || protoList.Empty() {
   187  				return
   188  			}
   189  			for !protoList.Empty() {
   190  				var proto cryptobyte.String
   191  				if !protoList.ReadUint8LengthPrefixed(&proto) || proto.Empty() {
   192  					return
   193  				}
   194  				info.SupportedProtos = append(info.SupportedProtos, string(proto))
   195  			}
   196  		case extensionSCT:
   197  			// RFC 6962, Section 3.3.1
   198  			info.SCTs = true
   199  		case extensionSupportedVersions:
   200  			// RFC 8446, Section 4.2.1
   201  			var versList cryptobyte.String
   202  			if !extData.ReadUint8LengthPrefixed(&versList) || versList.Empty() {
   203  				return
   204  			}
   205  			for !versList.Empty() {
   206  				var vers uint16
   207  				if !versList.ReadUint16(&vers) {
   208  					return
   209  				}
   210  				info.SupportedVersions = append(info.SupportedVersions, vers)
   211  			}
   212  		case extensionCookie:
   213  			// RFC 8446, Section 4.2.2
   214  			if !readUint16LengthPrefixed(&extData, &info.Cookie) ||
   215  				len(info.Cookie) == 0 {
   216  				return
   217  			}
   218  		case extensionKeyShare:
   219  			// RFC 8446, Section 4.2.8
   220  			var clientShares cryptobyte.String
   221  			if !extData.ReadUint16LengthPrefixed(&clientShares) {
   222  				return
   223  			}
   224  			for !clientShares.Empty() {
   225  				var ks KeyShare
   226  				if !clientShares.ReadUint16((*uint16)(&ks.Group)) ||
   227  					!readUint16LengthPrefixed(&clientShares, &ks.Data) ||
   228  					len(ks.Data) == 0 {
   229  					return
   230  				}
   231  				info.KeyShares = append(info.KeyShares, ks)
   232  			}
   233  		case extensionEarlyData:
   234  			// RFC 8446, Section 4.2.10
   235  			info.EarlyData = true
   236  		case extensionPSKModes:
   237  			// RFC 8446, Section 4.2.9
   238  			if !readUint8LengthPrefixed(&extData, &info.PSKModes) {
   239  				return
   240  			}
   241  		case extensionPreSharedKey:
   242  			// RFC 8446, Section 4.2.11
   243  			if !extensions.Empty() {
   244  				return // pre_shared_key must be the last extension
   245  			}
   246  			var identities cryptobyte.String
   247  			if !extData.ReadUint16LengthPrefixed(&identities) || identities.Empty() {
   248  				return
   249  			}
   250  			for !identities.Empty() {
   251  				var psk PSKIdentity
   252  				if !readUint16LengthPrefixed(&identities, &psk.label) ||
   253  					!identities.ReadUint32(&psk.obfuscatedTicketAge) ||
   254  					len(psk.label) == 0 {
   255  					return
   256  				}
   257  				info.PSKIdentities = append(info.PSKIdentities, psk)
   258  			}
   259  			var binders cryptobyte.String
   260  			if !extData.ReadUint16LengthPrefixed(&binders) || binders.Empty() {
   261  				return
   262  			}
   263  			for !binders.Empty() {
   264  				var binder []byte
   265  				if !readUint8LengthPrefixed(&binders, &binder) ||
   266  					len(binder) == 0 {
   267  					return
   268  				}
   269  				info.PSKBinders = append(info.PSKBinders, binder)
   270  			}
   271  		default:
   272  			// Ignore unknown extensions.
   273  			continue
   274  		}
   275  
   276  		if !extData.Empty() {
   277  			return
   278  		}
   279  	}
   280  
   281  	return
   282  }
   283  
   284  // allKnownVersions is all the TLS versions this package knows.
   285  var allKnownVersions = []uint16{
   286  	tls.VersionTLS13,
   287  	tls.VersionTLS12,
   288  	tls.VersionTLS11,
   289  	tls.VersionTLS10,
   290  }
   291  
   292  // supportedVersionsFromMax returns a list of supported versions derived from a
   293  // legacy maximum version value. Note that only versions supported by this
   294  // library are returned. Any newer peer will use allKnownVersions anyway.
   295  func supportedVersionsFromMax(maxVersion uint16) []uint16 {
   296  	versions := make([]uint16, 0, len(allKnownVersions))
   297  	for _, v := range allKnownVersions {
   298  		if v > maxVersion {
   299  			continue
   300  		}
   301  		versions = append(versions, v)
   302  	}
   303  	return versions
   304  }
   305  
   306  // readUint8LengthPrefixed acts like s.ReadUint8LengthPrefixed, but targets a
   307  // []byte instead of a cryptobyte.String.
   308  func readUint8LengthPrefixed(s *cryptobyte.String, out *[]byte) bool {
   309  	return s.ReadUint8LengthPrefixed((*cryptobyte.String)(out))
   310  }
   311  
   312  // readUint16LengthPrefixed acts like s.ReadUint16LengthPrefixed, but targets a
   313  // []byte instead of a cryptobyte.String.
   314  func readUint16LengthPrefixed(s *cryptobyte.String, out *[]byte) bool {
   315  	return s.ReadUint16LengthPrefixed((*cryptobyte.String)(out))
   316  }
   317  
   318  // TLS extension numbers
   319  const (
   320  	extensionServerName              uint16 = 0
   321  	extensionStatusRequest           uint16 = 5
   322  	extensionSupportedCurves         uint16 = 10 // supported_groups in TLS 1.3, see RFC 8446, Section 4.2.7
   323  	extensionSupportedPoints         uint16 = 11
   324  	extensionSignatureAlgorithms     uint16 = 13
   325  	extensionALPN                    uint16 = 16
   326  	extensionSCT                     uint16 = 18
   327  	extensionSessionTicket           uint16 = 35
   328  	extensionPreSharedKey            uint16 = 41
   329  	extensionEarlyData               uint16 = 42
   330  	extensionSupportedVersions       uint16 = 43
   331  	extensionCookie                  uint16 = 44
   332  	extensionPSKModes                uint16 = 45
   333  	extensionCertificateAuthorities  uint16 = 47
   334  	extensionSignatureAlgorithmsCert uint16 = 50
   335  	extensionKeyShare                uint16 = 51
   336  	extensionRenegotiationInfo       uint16 = 0xff01
   337  )
   338  
   339  // TLS signaling cipher suite values
   340  const (
   341  	scsvRenegotiation uint16 = 0x00ff
   342  )
   343  
   344  // TLS CertificateStatusType (RFC 3546)
   345  const (
   346  	statusTypeOCSP uint8 = 1
   347  )
   348  
   349  // KeyShare is a TLS 1.3 Key Share. See RFC 8446, Section 4.2.8.
   350  type KeyShare struct {
   351  	Group tls.CurveID
   352  	Data  []byte
   353  }
   354  
   355  // PSKIdentity is a TLS 1.3 PSK Identity.
   356  // Can be a Session Ticket, or a reference to a saved
   357  // session. See RFC 8446, Section 4.2.11.
   358  type PSKIdentity struct {
   359  	label               []byte
   360  	obfuscatedTicketAge uint32
   361  }