github.com/volts-dev/volts@v0.0.0-20240120094013-5e9c65924106/transport/tls.go (about)

     1  package transport
     2  
     3  import (
     4  	"crypto/sha256"
     5  	"fmt"
     6  	"net/url"
     7  	"strconv"
     8  	"strings"
     9  
    10  	utls "github.com/refraction-networking/utls"
    11  )
    12  
    13  type (
    14  	Ja3 struct {
    15  		Ja3       string
    16  		UserAgent string
    17  		Hash      string
    18  	}
    19  )
    20  
    21  // greasePlaceholder is a random value (well, kindof '0x?a?a) specified in a
    22  // random RFC.
    23  const greasePlaceholder = 0x0a0a
    24  
    25  // ErrExtensionNotExist is returned when an extension is not supported by the library
    26  type ErrExtensionNotExist string
    27  
    28  // Error is the error value which contains the extension that does not exist
    29  func (e ErrExtensionNotExist) Error() string {
    30  	return fmt.Sprintf("Extension does not exist: %s\n", string(e))
    31  }
    32  
    33  // / extMap maps extension values to the TLSExtension object associated with the
    34  // number. Some values are not put in here because they must be applied in a
    35  // special way. For example, "10" is the SupportedCurves extension which is also
    36  // used to calculate the JA3 signature. These JA3-dependent values are applied
    37  // after the instantiation of the map.
    38  // https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml
    39  func newExtMap() map[string]utls.TLSExtension {
    40  	return map[string]utls.TLSExtension{
    41  		"0": &utls.SNIExtension{},
    42  		"5": &utls.StatusRequestExtension{},
    43  		// These are applied later
    44  		// "10": &tls.SupportedCurvesExtension{...}
    45  		// "11": &tls.SupportedPointsExtension{...}
    46  		"13": &utls.SignatureAlgorithmsExtension{
    47  			SupportedSignatureAlgorithms: []utls.SignatureScheme{
    48  				utls.ECDSAWithP256AndSHA256,
    49  				utls.ECDSAWithP384AndSHA384,
    50  				utls.ECDSAWithP521AndSHA512,
    51  				utls.PSSWithSHA256,
    52  				utls.PSSWithSHA384,
    53  				utls.PSSWithSHA512,
    54  				utls.PKCS1WithSHA256,
    55  				utls.PKCS1WithSHA384,
    56  				utls.PKCS1WithSHA512,
    57  				utls.ECDSAWithSHA1,
    58  				utls.PKCS1WithSHA1,
    59  			},
    60  		},
    61  		"16": &utls.ALPNExtension{
    62  			AlpnProtocols: []string{"h2", "http/1.1"},
    63  		},
    64  		"18": &utls.SCTExtension{},
    65  		"21": &utls.UtlsPaddingExtension{GetPaddingLen: utls.BoringPaddingStyle},
    66  		"22": &utls.GenericExtension{Id: 22}, // encrypt_then_mac
    67  		//"22": &utls.GenericExtension{Id: 0x16, Data: []uint8{}},
    68  		"23": &utls.ExtendedMasterSecretExtension{},
    69  		//"27": &utls.FakeCertCompressionAlgsExtension{},
    70  		"27": &utls.UtlsCompressCertExtension{
    71  			Algorithms: []utls.CertCompressionAlgo{utls.CertCompressionBrotli},
    72  		},
    73  		"28": &utls.FakeRecordSizeLimitExtension{}, //Limit: 0x4001
    74  		"35": &utls.SessionTicketExtension{},
    75  		"34": &utls.GenericExtension{Id: 34},
    76  		"41": &utls.GenericExtension{Id: 41}, //FIXME pre_shared_key
    77  		"43": &utls.SupportedVersionsExtension{Versions: []uint16{
    78  			// utls.GREASE_PLACEHOLDER, //可能导致版本错乱
    79  			// utls.VersionTLS13, // NOTE 不想支持的加上去会报错
    80  			utls.VersionTLS12,
    81  			utls.VersionTLS11,
    82  			utls.VersionTLS10}},
    83  		"44": &utls.CookieExtension{},
    84  		"45": &utls.PSKKeyExchangeModesExtension{
    85  			Modes: []uint8{utls.PskModeDHE},
    86  		},
    87  		"49": &utls.GenericExtension{Id: 49}, // post_handshake_auth
    88  		"50": &utls.GenericExtension{Id: 50}, // signature_algorithms_cert
    89  		//"51": &utls.KeyShareExtension{KeyShares: []utls.KeyShare{},},
    90  		"51": &utls.KeyShareExtension{KeyShares: []utls.KeyShare{
    91  			//	{Group: utls.GREASE_PLACEHOLDER, Data: []byte{0}}, //可能导致版本错乱
    92  			{Group: utls.X25519},
    93  			{Group: utls.CurveP256},
    94  			{Group: utls.CurveP384},
    95  			//{Group: utls.CurveP521},
    96  
    97  			// {Group: utls.CurveP384}, known bug missing correct extensions for handshake
    98  		}},
    99  		"30032": &utls.GenericExtension{Id: 0x7550, Data: []byte{0}}, //FIXME
   100  		"13172": &utls.NPNExtension{},
   101  		"65281": &utls.RenegotiationInfoExtension{
   102  			Renegotiation: utls.RenegotiateOnceAsClient,
   103  		},
   104  	}
   105  }
   106  
   107  func extsMapping(token string) utls.TLSExtension {
   108  	switch token {
   109  	case "0":
   110  		return &utls.SNIExtension{}
   111  	case "5":
   112  		return &utls.StatusRequestExtension{}
   113  		// These are applied later
   114  		// "10": &tls.SupportedCurvesExtension{...}
   115  		// "11": &tls.SupportedPointsExtension{...}
   116  	case "13":
   117  		return &utls.SignatureAlgorithmsExtension{
   118  			SupportedSignatureAlgorithms: []utls.SignatureScheme{
   119  				utls.ECDSAWithP256AndSHA256,
   120  				utls.ECDSAWithP384AndSHA384,
   121  				utls.ECDSAWithP521AndSHA512,
   122  				utls.PSSWithSHA256,
   123  				utls.PSSWithSHA384,
   124  				utls.PSSWithSHA512,
   125  				utls.PKCS1WithSHA256,
   126  				utls.PKCS1WithSHA384,
   127  				utls.PKCS1WithSHA512,
   128  				utls.ECDSAWithSHA1,
   129  				utls.PKCS1WithSHA1,
   130  			},
   131  		}
   132  	case "16":
   133  		return &utls.ALPNExtension{
   134  			AlpnProtocols: []string{"h2", "http/1.1"},
   135  		}
   136  	case "18":
   137  		return &utls.SCTExtension{}
   138  	case "21":
   139  		return &utls.UtlsPaddingExtension{GetPaddingLen: utls.BoringPaddingStyle}
   140  	case "22":
   141  		return &utls.GenericExtension{Id: 22} // encrypt_then_mac
   142  		//case "22": &utls.GenericExtension{Id: 0x16, Data: []uint8{}},
   143  	case "23":
   144  		return &utls.ExtendedMasterSecretExtension{}
   145  		//"27": &utls.FakeCertCompressionAlgsExtension{},
   146  	case "27":
   147  		return &utls.UtlsCompressCertExtension{
   148  			Algorithms: []utls.CertCompressionAlgo{utls.CertCompressionBrotli},
   149  		}
   150  	case "28":
   151  		return &utls.FakeRecordSizeLimitExtension{} //Limit: 0x4001
   152  	case "35":
   153  		return &utls.SessionTicketExtension{}
   154  	case "34":
   155  		return &utls.GenericExtension{Id: 34}
   156  	case "41":
   157  		return &utls.GenericExtension{Id: 41} //FIXME pre_shared_key
   158  	case "43":
   159  		return &utls.SupportedVersionsExtension{Versions: []uint16{
   160  			// utls.GREASE_PLACEHOLDER, //可能导致版本错乱
   161  			// utls.VersionTLS13, // NOTE 不想支持的加上去会报错
   162  			utls.VersionTLS12,
   163  			utls.VersionTLS11,
   164  			utls.VersionTLS10}}
   165  	case "44":
   166  		return &utls.CookieExtension{}
   167  	case "45":
   168  		return &utls.PSKKeyExchangeModesExtension{
   169  			Modes: []uint8{utls.PskModeDHE},
   170  		}
   171  	case "49":
   172  		return &utls.GenericExtension{Id: 49} // post_handshake_auth
   173  	case "50":
   174  		return &utls.GenericExtension{Id: 50} // signature_algorithms_cert
   175  		//"51": &utls.KeyShareExtension{KeyShares: []utls.KeyShare{},},
   176  	case "51":
   177  		return &utls.KeyShareExtension{KeyShares: []utls.KeyShare{
   178  			//	{Group: utls.GREASE_PLACEHOLDER, Data: []byte{0}}, //可能导致版本错乱
   179  			{Group: utls.X25519},
   180  			{Group: utls.CurveP256},
   181  			{Group: utls.CurveP384},
   182  			//{Group: utls.CurveP521},
   183  
   184  			// {Group: utls.CurveP384}, known bug missing correct extensions for handshake
   185  		}}
   186  	case "30032":
   187  		return &utls.GenericExtension{Id: 0x7550, Data: []byte{0}} //FIXME
   188  	case "13172":
   189  		return &utls.NPNExtension{}
   190  	case "65281":
   191  		return &utls.RenegotiationInfoExtension{
   192  			Renegotiation: utls.RenegotiateOnceAsClient,
   193  		}
   194  	}
   195  
   196  	return nil
   197  }
   198  
   199  // parseJA3 creates a ClientHelloSpec based on a JA3 string
   200  func parseJA3(ja3 string) (*utls.ClientHelloSpec, error) {
   201  	//tmpMap := newExtMap()
   202  	tokens := strings.Split(ja3, ",")
   203  
   204  	//version := tokens[0]
   205  	ciphers := strings.Split(tokens[1], "-")
   206  	extensions := strings.Split(tokens[2], "-")
   207  	curves := strings.Split(tokens[3], "-")
   208  	if len(curves) == 1 && curves[0] == "" {
   209  		curves = []string{}
   210  	}
   211  	pointFormats := strings.Split(tokens[4], "-")
   212  	if len(pointFormats) == 1 && pointFormats[0] == "" {
   213  		pointFormats = []string{}
   214  	}
   215  
   216  	// parse curves
   217  	var targetCurves []utls.CurveID
   218  	targetCurves = append(targetCurves, utls.CurveID(utls.CurveID(utls.GREASE_PLACEHOLDER))) //append grease for Chrome browsers
   219  	for _, c := range curves {
   220  		cid, err := strconv.ParseUint(c, 10, 16)
   221  		if err != nil {
   222  			return nil, err
   223  		}
   224  		targetCurves = append(targetCurves, utls.CurveID(cid))
   225  	}
   226  	//tmpMap["10"] = &utls.SupportedCurvesExtension{Curves: targetCurves}
   227  
   228  	// parse point formats
   229  	var targetPointFormats []byte
   230  	for _, p := range pointFormats {
   231  		pid, err := strconv.ParseUint(p, 10, 8)
   232  		if err != nil {
   233  			return nil, err
   234  		}
   235  		targetPointFormats = append(targetPointFormats, byte(pid))
   236  	}
   237  	//tmpMap["11"] = &utls.SupportedPointsExtension{SupportedPoints: targetPointFormats}
   238  
   239  	// build extenions list
   240  	var exts []utls.TLSExtension
   241  	for _, e := range extensions {
   242  		te := extsMapping(e)
   243  		if te == nil {
   244  			if e == "10" {
   245  				te = &utls.SupportedCurvesExtension{Curves: targetCurves}
   246  			}
   247  			if e == "11" {
   248  				te = &utls.SupportedPointsExtension{SupportedPoints: targetPointFormats}
   249  			}
   250  
   251  			if te == nil {
   252  				return nil, ErrExtensionNotExist(e)
   253  			}
   254  		}
   255  		//te, ok := tmpMap[e]
   256  		//if !ok {
   257  		//	return nil, ErrExtensionNotExist(e)
   258  		//}
   259  		exts = append(exts, te)
   260  	}
   261  	// build SSLVersion
   262  	//vid64, err := strconv.ParseUint(version, 10, 16)
   263  	//if err != nil {
   264  	//	return nil, err
   265  	//}
   266  	//vid := uint16(vid64)
   267  
   268  	// build CipherSuites
   269  	var suites []uint16
   270  	for _, c := range ciphers {
   271  		cid, err := strconv.ParseUint(c, 10, 16)
   272  		if err != nil {
   273  			return nil, err
   274  		}
   275  		suites = append(suites, uint16(cid))
   276  	}
   277  
   278  	return &utls.ClientHelloSpec{
   279  		//TLSVersMin:         vid,
   280  		//TLSVersMax:         vid,
   281  		CipherSuites:       suites,
   282  		CompressionMethods: []byte{0},
   283  		Extensions:         exts,
   284  		GetSessionID:       sha256.Sum256,
   285  	}, nil
   286  }
   287  
   288  func urlToHost(target *url.URL) *url.URL {
   289  	if !strings.Contains(target.Host, ":") {
   290  		if target.Scheme == "http" {
   291  			target.Host = target.Host + ":80"
   292  		} else if target.Scheme == "https" {
   293  			target.Host = target.Host + ":443"
   294  		}
   295  	}
   296  	return target
   297  }