{"record":{"id":"cc0f2aa2a6091183","repo":"golang/go","slug":"tls-server-chose-an-unconfigured-cipher-suite","errorCode":null,"errorMessage":"tls: server chose an unconfigured cipher suite","messagePattern":"tls: server chose an unconfigured cipher suite","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/tls/handshake_client.go","lineNumber":634,"sourceCode":"\t\t}\n\t\tif err := hs.readFinished(c.serverFinished[:]); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif err := hs.saveSessionTicket(); err != nil {\n\t\treturn err\n\t}\n\n\tc.ekm = ekmFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.hello.random, hs.serverHello.random)\n\tc.isHandshakeComplete.Store(true)\n\n\treturn nil\n}\n\nfunc (hs *clientHandshakeState) pickCipherSuite() error {\n\tif hs.suite = mutualCipherSuite(hs.hello.cipherSuites, hs.serverHello.cipherSuite); hs.suite == nil {\n\t\ths.c.sendAlert(alertHandshakeFailure)\n\t\treturn errors.New(\"tls: server chose an unconfigured cipher suite\")\n\t}\n\n\ths.c.cipherSuite = hs.suite.id\n\treturn nil\n}\n\nfunc (hs *clientHandshakeState) doFullHandshake() error {\n\tc := hs.c\n\n\tmsg, err := c.readHandshake(&hs.finishedHash)\n\tif err != nil {\n\t\treturn err\n\t}\n\tcertMsg, ok := msg.(*certificateMsg)\n\tif !ok || len(certMsg.certificates) == 0 {\n\t\tc.sendAlert(alertUnexpectedMessage)\n\t\treturn unexpectedMessageError(certMsg, msg)\n\t}","sourceCodeStart":616,"sourceCodeEnd":652,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/tls/handshake_client.go#L616-L652","documentation":"pickCipherSuite calls mutualCipherSuite(hs.hello.cipherSuites, hs.serverHello.cipherSuite). It walks the client's offered list and returns nil if the server-chosen ID is not present. A conformant TLS server must pick a suite the client offered; selecting anything else is a protocol violation and aborts the handshake with alertHandshakeFailure.","triggerScenarios":"Config.CipherSuites is set to a restrictive list that has no overlap with what the server selected; FIPS-only Go build (GOEXPERIMENT=fips140) strips non-approved suites; server is misconfigured or being manipulated; server picked a disabled/weak suite like TLS_RSA_WITH_3DES_EDE_CBC_SHA.","commonSituations":"Pinning cipher suites too narrowly; FIPS 140-3 module build connecting to a server expecting non-approved suites; old server that only offers RC4/3DES; client and server on disjoint crypto policies.","solutions":["Leave Config.CipherSuites nil so Go uses its curated default suite list (includes modern AEAD TLS 1.2 and TLS 1.3 suites).","If you must pin, include at least one AEAD suite the server speaks: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 / TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 / TLS 1.3 suites.","Update the server's cipher configuration to offer suites the client supports.","Re-evaluate whether the FIPS build is appropriate for this peer."],"exampleFix":"// before: overly restrictive pinning\ncfg := &tls.Config{CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384}}\n// after: trust Go's defaults\ncfg := &tls.Config{}","handlingStrategy":"validation","validationCode":"// Validate that your pinned CipherSuites overlap with the defaults Go offers,\n// and include at least one AEAD suite.\nfunc validateCipherSuites(cs []uint16) error {\n    if len(cs) == 0 { return nil }\n    allowed := map[uint16]bool{\n        tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: true,\n        tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: true,\n        tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: true,\n        tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: true,\n        tls.TLS_AES_128_GCM_SHA256: true,\n        tls.TLS_AES_256_GCM_SHA384: true,\n        tls.TLS_CHACHA20_POLY1305_SHA256: true,\n    }\n    for _, c := range cs {\n        if !allowed[c] { return fmt.Errorf(\"unsupported/weak cipher suite: %x\", c) }\n    }\n    return nil\n}","typeGuard":"func isUnconfiguredCipherSuite(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"server chose an unconfigured cipher suite\")\n}","tryCatchPattern":"if _, err := tls.Dial(\"tcp\", addr, cfg); err != nil {\n    if isUnconfiguredCipherSuite(err) {\n        // Retry once with the default suite list.\n        cfg.CipherSuites = nil\n        _, err = tls.Dial(\"tcp\", addr, cfg)\n    }\n}","preventionTips":["Leave Config.CipherSuites nil unless you have a hard requirement.","If pinning, always include at least one AEAD suite the server speaks.","Re-evaluate FIPS builds when peers change."],"tags":["tls","cipher-suites","config","handshake"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}