{"record":{"id":"567a47951db092ba","repo":"golang/go","slug":"tls-initial-handshake-had-non-empty-renegotiation-567a47","errorCode":null,"errorMessage":"tls: initial handshake had non-empty renegotiation extension","messagePattern":"tls: initial handshake had non-empty renegotiation extension","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/tls/handshake_server_tls13.go","lineNumber":157,"sourceCode":"\t\t\tbreak\n\t\t}\n\t}\n\n\tif len(hs.clientHello.compressionMethods) != 1 ||\n\t\ths.clientHello.compressionMethods[0] != compressionNone {\n\t\tc.sendAlert(alertIllegalParameter)\n\t\treturn errors.New(\"tls: TLS 1.3 client supports illegal compression methods\")\n\t}\n\n\ths.hello.random = make([]byte, 32)\n\tif _, err := io.ReadFull(c.config.rand(), hs.hello.random); err != nil {\n\t\tc.sendAlert(alertInternalError)\n\t\treturn err\n\t}\n\n\tif len(hs.clientHello.secureRenegotiation) != 0 {\n\t\tc.sendAlert(alertHandshakeFailure)\n\t\treturn errors.New(\"tls: initial handshake had non-empty renegotiation extension\")\n\t}\n\n\tif hs.clientHello.earlyData && c.quic != nil {\n\t\tif len(hs.clientHello.pskIdentities) == 0 {\n\t\t\tc.sendAlert(alertIllegalParameter)\n\t\t\treturn errors.New(\"tls: early_data without pre_shared_key\")\n\t\t}\n\t} else if hs.clientHello.earlyData {\n\t\t// See RFC 8446, Section 4.2.10 for the complicated behavior required\n\t\t// here. The scenario is that a different server at our address offered\n\t\t// to accept early data in the past, which we can't handle. For now, all\n\t\t// 0-RTT enabled session tickets need to expire before a Go server can\n\t\t// replace a server or join a pool. That's the same requirement that\n\t\t// applies to mixing or replacing with any TLS 1.2 server.\n\t\tc.sendAlert(alertUnsupportedExtension)\n\t\treturn errors.New(\"tls: client sent unexpected early data\")\n\t}\n","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/tls/handshake_server_tls13.go#L139-L175","documentation":"TLS 1.3 removed renegotiation entirely; the renegotiation_info (0xff01) extension must not appear with content on an initial handshake (RFC 8446 §4.2.2). If hs.clientHello.secureRenegotiation is non-empty on the first handshake, the server sends handshake_failure and aborts.","triggerScenarios":"A client sends a non-empty renegotiation_info extension in the initial ClientHello. Common with TLS 1.2-aware clients that always populate renegotiation_info, or middleboxes that inject it.","commonSituations":"Older OpenSSL/GnuTLS clients that unconditionally carry renegotiation_info; legacy middleboxes/proxies; TLS 1.2 clients being upgraded mid-stream to talk to a TLS 1.3 server.","solutions":["Update the client to a TLS 1.3-aware version that omits renegotiation_info for 1.3 handshakes","If a middlebox injects the extension, remove or upgrade the middlebox","Disable client-side renegotiation_info advertisement for TLS 1.3 connections"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := tlsConn.Handshake(); err != nil {\n    if strings.Contains(err.Error(), \"non-empty renegotiation extension\") {\n        log.Printf(\"client sent renegotiation_info on TLS 1.3 from %v\", remote)\n    }\n    c.Close()\n    return\n}","preventionTips":["Update TLS 1.2-era clients so they omit renegotiation_info for TLS 1.3","Audit middleboxes that may inject renegotiation_info"],"tags":["tls","go","renegotiation","rfc8446","compliance","handshake"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}