{"record":{"id":"6a3a3eceda133a8b","repo":"golang/go","slug":"tls-invalid-or-missing-psk-binders","errorCode":null,"errorMessage":"tls: invalid or missing PSK binders","messagePattern":"tls: invalid or missing PSK binders","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/tls/handshake_server_tls13.go","lineNumber":312,"sourceCode":"\n\tif c.config.SessionTicketsDisabled {\n\t\treturn nil\n\t}\n\n\tmodeOK := false\n\tfor _, mode := range hs.clientHello.pskModes {\n\t\tif mode == pskModeDHE {\n\t\t\tmodeOK = true\n\t\t\tbreak\n\t\t}\n\t}\n\tif !modeOK {\n\t\treturn nil\n\t}\n\n\tif len(hs.clientHello.pskIdentities) != len(hs.clientHello.pskBinders) {\n\t\tc.sendAlert(alertIllegalParameter)\n\t\treturn errors.New(\"tls: invalid or missing PSK binders\")\n\t}\n\tif len(hs.clientHello.pskIdentities) == 0 {\n\t\treturn nil\n\t}\n\n\tfor i, identity := range hs.clientHello.pskIdentities {\n\t\tif i >= maxClientPSKIdentities {\n\t\t\tbreak\n\t\t}\n\n\t\tvar sessionState *SessionState\n\t\tif c.config.UnwrapSession != nil {\n\t\t\tvar err error\n\t\t\tsessionState, err = c.config.UnwrapSession(identity.label, c.connectionStateLocked())\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tif sessionState == nil {","sourceCodeStart":294,"sourceCodeEnd":330,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/tls/handshake_server_tls13.go#L294-L330","documentation":"RFC 8446 §4.2.11 requires the number of PSK identities to equal the number of binders, in order. If len(pskIdentities) != len(pskBinders), the ClientHello is malformed; the server sends illegal_parameter.","triggerScenarios":"Client sends 3 identities but 2 binders, or any count mismatch. Occurs when a ClientHello is constructed with mismatched identity/binder lists.","commonSituations":"Buggy session-resumption code that appends an identity without its binder; fuzzers; attackers hand-crafting ClientHellos.","solutions":["Ensure each PSK identity has exactly one corresponding binder, in the same order","Use a compliant TLS library to construct the pre_shared_key extension rather than building it by hand"],"exampleFix":"// before\nidentities = []pskIdentity{a, b, c}\nbinders = [][]byte{ba, bb} // missing c\n\n// after\nidentities = []pskIdentity{a, b, c}\nbinders = [][]byte{ba, bb, bc}","handlingStrategy":"validation","validationCode":"// Client-side: before sending, assert identity/binder counts match.\nif len(pskIdentities) != len(pskBinders) {\n    return fmt.Errorf(\"psk mismatch: %d identities vs %d binders\", len(pskIdentities), len(pskBinders))\n}","typeGuard":null,"tryCatchPattern":"if err := tlsConn.Handshake(); err != nil {\n    if strings.Contains(err.Error(), \"invalid or missing PSK binders\") {\n        log.Printf(\"malformed pre_shared_key from %v\", remote)\n    }\n    c.Close()\n    return\n}","preventionTips":["Always append a binder for every identity you add, in order","Use a compliant TLS library to construct pre_shared_key rather than hand-building it"],"tags":["tls","go","psk","binder","rfc8446","compliance","handshake"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:31:55.035Z"}