{"record":{"id":"cf8d6834970e5c84","repo":"golang/go","slug":"tls-client-sent-unexpected-key-share-in-second-cl","errorCode":null,"errorMessage":"tls: client sent unexpected key share in second ClientHello","messagePattern":"tls: client sent unexpected key share in second ClientHello","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/tls/handshake_server_tls13.go","lineNumber":640,"sourceCode":"\t\t\techInner, err := decodeInnerClientHello(clientHello, encodedInner)\n\t\t\tif err != nil {\n\t\t\t\tc.sendAlert(alertIllegalParameter)\n\t\t\t\treturn nil, errors.New(\"tls: client sent invalid encrypted client hello extension\")\n\t\t\t}\n\n\t\t\tclientHello = echInner\n\t\t}\n\t}\n\n\tif len(clientHello.keyShares) != 1 {\n\t\tc.sendAlert(alertIllegalParameter)\n\t\treturn nil, errors.New(\"tls: client didn't send one key share in second ClientHello\")\n\t}\n\tks := &clientHello.keyShares[0]\n\n\tif ks.group != selectedGroup {\n\t\tc.sendAlert(alertIllegalParameter)\n\t\treturn nil, errors.New(\"tls: client sent unexpected key share in second ClientHello\")\n\t}\n\n\tif clientHello.earlyData {\n\t\tc.sendAlert(alertIllegalParameter)\n\t\treturn nil, errors.New(\"tls: client indicated early data in second ClientHello\")\n\t}\n\n\tif illegalClientHelloChange(clientHello, hs.clientHello) {\n\t\tc.sendAlert(alertIllegalParameter)\n\t\treturn nil, errors.New(\"tls: client illegally modified second ClientHello\")\n\t}\n\n\tc.didHRR = true\n\ths.clientHello = clientHello\n\treturn ks, nil\n}\n\n// illegalClientHelloChange reports whether the two ClientHello messages are","sourceCodeStart":622,"sourceCodeEnd":658,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/tls/handshake_server_tls13.go#L622-L658","documentation":"After a HelloRetryRequest the server expects the single key share in the client's second ClientHello to use the exact group the server selected in the HRR's selected_group field. This error fires when ks.group != selectedGroup. RFC 8446 Section 4.1.2 requires the client to generate a fresh key share for the server-requested group.","triggerScenarios":"The server sent a HelloRetryRequest asking for group X (e.g. X25519), but the client's retry ClientHello contains a key share for a different group Y (e.g. P-256), or it resent the original group. The server's selectedGroup variable was set during the initial ClientHello processing.","commonSituations":"Client misreads or ignores the HRR selected_group field; a proxy alters the HRR or the retry ClientHello; interoperability mismatch between client and server curve preferences; a client bug where it generates a key share for the wrong curve after HRR.","solutions":["Confirm the client reads the HelloRetryRequest's key_share extension selected_group and generates a matching key share.","Check that no intermediary (load balancer, TLS terminator) modifies the HRR selected_group value.","Test with a reference TLS 1.3 implementation to confirm the server's HRR is well-formed.","Inspect the packet capture: compare HRR selected_group vs. the key share group in the second ClientHello."],"exampleFix":"// No server-side fix; this is a client protocol-conformance issue.\n// Client must generate key share for the group the server requested in HRR:\n// before (buggy): keyShare.group = clientOriginalGroup\n// after (correct): keyShare.group = hrrSelectedGroup","handlingStrategy":"validation","validationCode":"// Client-side: validate key share group matches HRR before sending\nfunc validateKeyShareGroup(group CurveID, hrrSelectedGroup CurveID) error {\n    if group != hrrSelectedGroup {\n        return fmt.Errorf(\"key share group %v != HRR group %v\", group, hrrSelectedGroup)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"// Server-side: handle during Handshake()\nerr := conn.Handshake()\nif err != nil && strings.Contains(err.Error(), \"unexpected key share\") {\n    log.Printf(\"client sent wrong key share group after HRR: %v\", err)\n    conn.Close()\n}","preventionTips":["Verify client reads HRR selected_group correctly.","Test HRR flows in your interop suite.","Log which group the server requested vs. what the client sent."],"tags":["tls","tls13","handshake","helloretryrequest","key-share","server-side"],"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T08:17:17.861Z"}