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 }