{"record":{"id":"1769fd73f71f4204","repo":"AdguardTeam/AdGuardHome","slug":"unknown-cipher-q","errorCode":null,"errorMessage":"unknown cipher %q","messagePattern":"unknown cipher %q","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/aghtls/aghtls.go","lineNumber":44,"sourceCode":"\n\tl.DebugContext(ctx, \"known ciphers\", \"ciphers\", cipherSuites)\n}\n\n// cipherSuites are a name-to-ID mapping of cipher suites from crypto/tls.  It\n// is filled by init.  It must not be modified.\nvar cipherSuites map[string]uint16\n\n// ParseCiphers parses a slice of cipher suites from cipher names.\nfunc ParseCiphers(cipherNames []string) (cipherIDs []uint16, err error) {\n\tif cipherNames == nil {\n\t\treturn nil, nil\n\t}\n\n\tcipherIDs = make([]uint16, 0, len(cipherNames))\n\tfor _, name := range cipherNames {\n\t\tid, ok := cipherSuites[name]\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"unknown cipher %q\", name)\n\t\t}\n\n\t\tcipherIDs = append(cipherIDs, id)\n\t}\n\n\treturn cipherIDs, nil\n}\n\n// SaferCipherSuites returns a set of default cipher suites with vulnerable and\n// weak cipher suites removed.\nfunc SaferCipherSuites() (safe []uint16) {\n\tfor _, s := range tls.CipherSuites() {\n\t\tswitch s.ID {\n\t\tcase\n\t\t\ttls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,\n\t\t\ttls.TLS_RSA_WITH_AES_128_CBC_SHA,\n\t\t\ttls.TLS_RSA_WITH_AES_256_CBC_SHA,\n\t\t\ttls.TLS_RSA_WITH_AES_128_CBC_SHA256,","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/AdguardTeam/AdGuardHome/blob/b41aefbe51c8dde65e2c50f093996afa0502edf9/internal/aghtls/aghtls.go#L26-L62","documentation":"ParseCiphers maps human-readable cipher-suite names (e.g. TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) to IDs; an unrecognized name yields this error. Only names present in the library's cipherSuites table are accepted.","triggerScenarios":"Passing a cipher name with a typo, wrong case, outdated name, or a name not in the supported cipherSuites map (e.g. TLS 1.3 suite names like TLS_AES_128_GCM_SHA256, which are configured differently, or CBC/3DES suites excluded from the table).","commonSituations":"Copying cipher lists from nginx/OpenSSL configs that include names Go's crypto/tls or this table doesn't support; upgrading Go versions where cipher lists changed; extra whitespace or commas producing empty/garbage tokens.","solutions":["Log the exact offending name and correct it against the supported table in aghtls (cipherSuites map)","Remove TLS 1.3 ciphers from the list — they are always enabled and not settable this way","Trim whitespace and drop empty tokens before parsing","Copy a known-good cipher list from the project's docs/tests"],"exampleFix":"// before\nciphers := []string{\"tls_ecdhe_rsa_with_aes_128_gcm_sha256\", \"TLS_AES_128_GCM_SHA256\"}\n\n// after\n// only TLS 1.2-style names, exact case, from the supported table\nciphers := []string{\"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256\"}","handlingStrategy":"validation","validationCode":"// validate against a known-good set before calling ParseCiphers:\nfor _, name := range cipherNames {\n    if !slices.Contains(supportedCipherNames, name) { return fmt.Errorf(\"bad cipher %q\", name) }\n}","typeGuard":"func isValidCipherName(name string, table map[string]uint16) bool { _, ok := table[name]; return ok }","tryCatchPattern":"ids, err := aghtls.ParseCiphers(names)\nif err != nil && strings.Contains(err.Error(), \"unknown cipher\") {\n    // strip the offending name and re-validate, or fail config load with a clear message\n}","preventionTips":["Source cipher lists from the library's supported table, not OpenSSL docs","Exclude TLS 1.3 suite names from configurable lists","Normalize input: trim spaces, drop empty tokens","Validate config at load time before the TLS listener starts"],"tags":["tls","cipher-suites","config-validation","crypto"],"backgroundTag":"tls-cipher-validation-failed","analyzedSha":"b41aefbe51c8dde65e2c50f093996afa0502edf9","analyzedAt":"2026-08-27T04:57:55.097Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}