{"record":{"id":"615d3d6ebad4c16f","repo":"golang/go","slug":"tls-client-sent-encrypted-client-hello-extension-615d3d","errorCode":null,"errorMessage":"tls: client sent encrypted_client_hello extension but did not offer TLS 1.3","messagePattern":"tls: client sent encrypted_client_hello extension but did not offer TLS 1\\.3","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/tls/ech.go","lineNumber":398,"sourceCode":"\t\t// GREASE (Generate Random Extensions And Sustain Extensibility) is a mechanism used by\n\t\t// browsers like Chrome to ensure TLS implementations correctly ignore unknown values.\n\t\t// GREASE values follow a specific pattern: 0x?A0A, where ? can be any hex digit.\n\t\t// These values should be ignored when processing supported TLS versions.\n\t\tif v&0x0F0F == 0x0A0A && v&0xff == v>>8 {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Ensure at least TLS 1.3 is offered.\n\t\tif v == VersionTLS13 {\n\t\t\thasTLS13 = true\n\t\t} else if v < VersionTLS13 {\n\t\t\t// Reject if any non-GREASE value is below TLS 1.3, as ECH requires TLS 1.3+.\n\t\t\treturn nil, errors.New(\"tls: client sent encrypted_client_hello extension with unsupported versions\")\n\t\t}\n\t}\n\n\tif !hasTLS13 {\n\t\treturn nil, errors.New(\"tls: client sent encrypted_client_hello extension but did not offer TLS 1.3\")\n\t}\n\n\treturn inner, nil\n}\n\nfunc decryptECHPayload(context *hpke.Recipient, hello, payload []byte) ([]byte, error) {\n\touterAAD := bytes.Replace(hello[4:], payload, make([]byte, len(payload)), 1)\n\treturn context.Open(outerAAD, payload)\n}\n\nfunc generateOuterECHExt(id uint8, kdfID, aeadID uint16, encodedKey []byte, payload []byte) ([]byte, error) {\n\tvar b cryptobyte.Builder\n\tb.AddUint8(0) // outer\n\tb.AddUint16(kdfID)\n\tb.AddUint16(aeadID)\n\tb.AddUint8(id)\n\tb.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { b.AddBytes(encodedKey) })\n\tb.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { b.AddBytes(payload) })","sourceCodeStart":380,"sourceCodeEnd":416,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/tls/ech.go#L380-L416","documentation":"Thrown when the reconstructed ECH inner ClientHello's supported_versions extension does not include TLS 1.3 (0x0304) at all, yet no version below 1.3 was found either (otherwise error 568 would have fired first). This means all entries are GREASE values or hypothetical future versions above 1.3, with TLS 1.3 itself absent. A valid ECH client must offer TLS 1.3.","triggerScenarios":"The inner ClientHello's supported_versions extension contains only GREASE values (0x?A0A) and/or versions above TLS 1.3, with VersionTLS13 (0x0304) absent from the list.","commonSituations":"A malformed supported_versions extension in the inner hello that omits TLS 1.3. A client using an experimental future TLS version without including 1.3 as a fallback. Decryption corruption that alters the supported_versions extension data.","solutions":["Ensure the ECH client's inner ClientHello includes TLS 1.3 (0x0304) in supported_versions","Verify the client's tls.Config includes VersionTLS13 in its supported versions","Check for decryption key mismatches that could corrupt the supported_versions extension data","Update the client ECH library to ensure it always offers TLS 1.3"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Server-side: wrapped into errInvalidECHExt.\n// This is a client-side encoding issue; the server cannot prevent it.","preventionTips":["Ensure the ECH client always includes TLS 1.3 in supported_versions of the inner hello","Verify the client's supported versions list includes VersionTLS13","Test ECH clients against reference servers to catch version omission bugs"],"tags":["tls","ech","server-side","version-negotiation","tls13","rfc-9460"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:31:55.035Z"}