{"record":{"id":"03db98b9427c4710","repo":"golang/go","slug":"tls-server-selected-an-invalid-psk","errorCode":null,"errorMessage":"tls: server selected an invalid PSK","messagePattern":"tls: server selected an invalid PSK","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/tls/handshake_client_tls13.go","lineNumber":447,"sourceCode":"\n\tif hs.serverHello.serverShare.group == 0 {\n\t\tc.sendAlert(alertIllegalParameter)\n\t\treturn errors.New(\"tls: server did not send a key share\")\n\t}\n\tif !slices.ContainsFunc(hs.hello.keyShares, func(ks keyShare) bool {\n\t\treturn ks.group == hs.serverHello.serverShare.group\n\t}) {\n\t\tc.sendAlert(alertIllegalParameter)\n\t\treturn errors.New(\"tls: server selected unsupported group\")\n\t}\n\n\tif !hs.serverHello.selectedIdentityPresent {\n\t\treturn nil\n\t}\n\n\tif int(hs.serverHello.selectedIdentity) >= len(hs.hello.pskIdentities) {\n\t\tc.sendAlert(alertIllegalParameter)\n\t\treturn errors.New(\"tls: server selected an invalid PSK\")\n\t}\n\n\tif len(hs.hello.pskIdentities) != 1 || hs.session == nil {\n\t\treturn c.sendAlert(alertInternalError)\n\t}\n\tpskSuite := cipherSuiteTLS13ByID(hs.session.cipherSuite)\n\tif pskSuite == nil {\n\t\treturn c.sendAlert(alertInternalError)\n\t}\n\tif pskSuite.hash != hs.suite.hash {\n\t\tc.sendAlert(alertIllegalParameter)\n\t\treturn errors.New(\"tls: server selected an invalid PSK and cipher suite pair\")\n\t}\n\n\ths.usingPSK = true\n\tc.didResume = true\n\tc.peerCertificates = hs.session.peerCertificates\n\tc.verifiedChains = hs.session.verifiedChains","sourceCodeStart":429,"sourceCodeEnd":465,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/tls/handshake_client_tls13.go#L429-L465","documentation":"Server selected a PSK identity index beyond what the client offered. RFC 8446 §4.2.11 requires the server's `pre_shared_key` identity index to be valid; Go checks `selectedIdentity < len(hs.hello.pskIdentities)` and sends `illegal_parameter` on violation. Indicates a server misuse of session resumption.","triggerScenarios":"ServerHello.selectedIdentityPresent is true and selectedIdentity >= the number of PSK identities the client sent. Reached whenever the server acknowledges a PSK the client did not offer.","commonSituations":"Buggy server resumption logic, mismatched session ticket caches, a server cluster with non-shared ticket keys selecting an out-of-range index, or fuzz/adversarial traffic.","solutions":["Report to the server operator — selected PSK index must be < number of client-offered identities.","Disable session resumption on the client (SetSessionCache(nil) and ClientSessionCache nil) to sidestep PSK negotiation while diagnosing.","Confirm the ClientHello actually carried the PSK identities you expected.","Check the server's ticket key rotation logic if you operate it."],"exampleFix":"// before: client resumption configured but server mishandles identity index\ncfg := &tls.Config{ClientSessionCache: tls.NewLRUClientSessionCache(10)}\n\n// after: temporarily disable resumption to confirm the cause\ncfg := &tls.Config{ClientSessionCache: nil}","handlingStrategy":"validation","validationCode":"// Pre-flight: if you disable resumption you cannot hit out-of-range PSK selection.\nif diagnosticallyResumptionBuggy {\n    cfg.ClientSessionCache = nil\n}","typeGuard":null,"tryCatchPattern":"if err := conn.Handshake(); err != nil {\n    if strings.Contains(err.Error(), \"invalid PSK\") {\n        // drop any cached ticket and retry once with a fresh handshake\n        if cfg.ClientSessionCache != nil { cfg.ClientSessionCache = nil }\n    }\n}","preventionTips":["Clear the ClientSessionCache after server config changes.","Do not share a session cache across connections to differently-configured servers.","Log PSK-related failures separately to spot server-side resumption bugs."],"tags":["tls","tls13","handshake","psk","session-resumption","protocol-violation","network","go"],"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:17:08.281Z"}