git.prognetwork.ru/x0r/utls@v1.3.3/u_clienthello_json.go (about) 1 package tls 2 3 import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 "os" 8 9 "github.com/gaukas/godicttls" 10 ) 11 12 var ErrUnknownExtension = errors.New("extension name is unknown to the dictionary") 13 14 type ClientHelloSpecJSONUnmarshaler struct { 15 CipherSuites *CipherSuitesJSONUnmarshaler `json:"cipher_suites"` 16 CompressionMethods *CompressionMethodsJSONUnmarshaler `json:"compression_methods"` 17 Extensions *TLSExtensionsJSONUnmarshaler `json:"extensions"` 18 TLSVersMin uint16 `json:"min_vers,omitempty"` // optional 19 TLSVersMax uint16 `json:"max_vers,omitempty"` // optional 20 } 21 22 func (chsju *ClientHelloSpecJSONUnmarshaler) ClientHelloSpec() ClientHelloSpec { 23 return ClientHelloSpec{ 24 CipherSuites: chsju.CipherSuites.CipherSuites(), 25 CompressionMethods: chsju.CompressionMethods.CompressionMethods(), 26 Extensions: chsju.Extensions.Extensions(), 27 TLSVersMin: chsju.TLSVersMin, 28 TLSVersMax: chsju.TLSVersMax, 29 } 30 } 31 32 type CipherSuitesJSONUnmarshaler struct { 33 cipherSuites []uint16 34 } 35 36 func (c *CipherSuitesJSONUnmarshaler) UnmarshalJSON(jsonStr []byte) error { 37 var cipherSuiteNames []string 38 if err := json.Unmarshal(jsonStr, &cipherSuiteNames); err != nil { 39 return err 40 } 41 42 for _, name := range cipherSuiteNames { 43 if name == "GREASE" { 44 c.cipherSuites = append(c.cipherSuites, GREASE_PLACEHOLDER) 45 continue 46 } 47 48 if id, ok := godicttls.DictCipherSuiteNameIndexed[name]; ok { 49 c.cipherSuites = append(c.cipherSuites, id) 50 } else { 51 return fmt.Errorf("unknown cipher suite name: %s", name) 52 } 53 } 54 55 return nil 56 } 57 58 func (c *CipherSuitesJSONUnmarshaler) CipherSuites() []uint16 { 59 return c.cipherSuites 60 } 61 62 type CompressionMethodsJSONUnmarshaler struct { 63 compressionMethods []uint8 64 } 65 66 func (c *CompressionMethodsJSONUnmarshaler) UnmarshalJSON(jsonStr []byte) error { 67 var compressionMethodNames []string 68 if err := json.Unmarshal(jsonStr, &compressionMethodNames); err != nil { 69 return err 70 } 71 72 for _, name := range compressionMethodNames { 73 if id, ok := godicttls.DictCompMethNameIndexed[name]; ok { 74 c.compressionMethods = append(c.compressionMethods, id) 75 } else { 76 return fmt.Errorf("unknown compression method name: %s", name) 77 } 78 } 79 80 return nil 81 } 82 83 func (c *CompressionMethodsJSONUnmarshaler) CompressionMethods() []uint8 { 84 return c.compressionMethods 85 } 86 87 type TLSExtensionsJSONUnmarshaler struct { 88 extensions []TLSExtensionJSON 89 } 90 91 func (e *TLSExtensionsJSONUnmarshaler) UnmarshalJSON(jsonStr []byte) error { 92 var accepters []tlsExtensionJSONAccepter 93 if err := json.Unmarshal(jsonStr, &accepters); err != nil { 94 return err 95 } 96 97 var exts []TLSExtensionJSON = make([]TLSExtensionJSON, 0, len(accepters)) 98 for _, accepter := range accepters { 99 if accepter.extNameOnly.Name == "GREASE" { 100 exts = append(exts, &UtlsGREASEExtension{}) 101 continue 102 } 103 104 if extID, ok := godicttls.DictExtTypeNameIndexed[accepter.extNameOnly.Name]; !ok { 105 return fmt.Errorf("%w: %s", ErrUnknownExtension, accepter.extNameOnly.Name) 106 } else { 107 // get extension type from ID 108 var ext TLSExtension = ExtensionFromID(extID) 109 if ext == nil { 110 // fallback to generic extension 111 ext = genericExtension(extID, accepter.extNameOnly.Name) 112 } 113 114 if extJsonCompatible, ok := ext.(TLSExtensionJSON); ok { 115 exts = append(exts, extJsonCompatible) 116 } else { 117 return fmt.Errorf("extension %d (%s) is not JSON compatible", extID, accepter.extNameOnly.Name) 118 } 119 } 120 } 121 122 // unmashal extensions 123 for idx, ext := range exts { 124 // json.Unmarshal will call the UnmarshalJSON method of the extension 125 if err := json.Unmarshal(accepters[idx].origJsonInput, ext); err != nil { 126 return err 127 } 128 } 129 130 e.extensions = exts 131 return nil 132 } 133 134 func (e *TLSExtensionsJSONUnmarshaler) Extensions() []TLSExtension { 135 var exts []TLSExtension = make([]TLSExtension, 0, len(e.extensions)) 136 for _, ext := range e.extensions { 137 exts = append(exts, ext) 138 } 139 return exts 140 } 141 142 func genericExtension(id uint16, name string) TLSExtension { 143 var warningMsg string = "WARNING: extension " 144 warningMsg += fmt.Sprintf("%d ", id) 145 if len(name) > 0 { 146 warningMsg += fmt.Sprintf("(%s) ", name) 147 } 148 warningMsg += "is falling back to generic extension" 149 warningMsg += "\n" 150 151 fmt.Fprint(os.Stderr, warningMsg) 152 153 // fallback to generic extension 154 return &GenericExtension{Id: id} 155 } 156 157 type tlsExtensionJSONAccepter struct { 158 extNameOnly struct { 159 Name string `json:"name"` 160 } 161 origJsonInput []byte 162 } 163 164 func (t *tlsExtensionJSONAccepter) UnmarshalJSON(jsonStr []byte) error { 165 t.origJsonInput = make([]byte, len(jsonStr)) 166 copy(t.origJsonInput, jsonStr) 167 return json.Unmarshal(jsonStr, &t.extNameOnly) 168 }