package resolution import ( "strings" "testing" mcat "git.novox.be/novox/mesh-sdk/go/catalogue" ) // A line break, a carriage return or a NUL in any string of any setting is refused, at any depth, keys too — // where a layer is judged, which is both where it is kept and where it is composed (novox/hq issue 339). func TestASettingHoldsOneLine(t *testing.T) { m := mcat.Manifest{Module: "mailu"} for _, v := range []any{"a\nDEBUG=1", "a\rb", "a\x00b", []any{"ok", "x\ny"}, map[string]any{"k": []any{"ok", map[string]any{"deep": "x\ny"}}}, map[string]any{"k\nx": "v"}} { if err := JudgeSettings(m, []mcat.Layer{{From: "home", Values: map[string]any{"v": v}}}, false); err == nil || !strings.Contains(err.Error(), "line break") { t.Errorf("%q: %v", v, err) } } if err := JudgeSettings(m, []mcat.Layer{{From: "home", Values: map[string]any{"v\nPATH": "x"}}}, false); err == nil { t.Error("a line break in a key was taken") } if err := JudgeSettings(m, []mcat.Layer{{From: "home", Values: map[string]any{"v": "one line", "n": 3.0, "l": []any{"a", "b"}}}}, false); err != nil { t.Errorf("one line each: %v", err) } } // Lines are allowed in one setting only: step-ca's `root`, as certificates that encoding/pem decodes and // x509.ParseCertificate parses (novox/hq issue 339). Any other module or key, another label, or a block that is // not a certificate is refused like any other line break. func TestOnlyTheAuthoritysRootMayHoldLines(t *testing.T) { ca := mcat.Manifest{Module: "step-ca"} judge := func(m mcat.Manifest, key, v string) error { return JudgeSettings(m, []mcat.Layer{{From: "anchor", Values: map[string]any{key: v}}}, false) } for _, ok := range []string{servedRoot, servedRoot + servedRoot, strings.TrimSuffix(servedRoot, "\n")} { if err := judge(ca, "root", ok); err != nil { t.Errorf("the authority's root: %v", err) } } body := strings.TrimSuffix(strings.TrimPrefix(servedRoot, "-----BEGIN CERTIFICATE-----\n"), "-----END CERTIFICATE-----\n") for name, bad := range map[string]string{ "a line after it": servedRoot + "PATH=/tmp\n", "a line before it": "PATH=\n" + servedRoot, "another label": "-----BEGIN PRIVATE KEY-----\n" + body + "-----END PRIVATE KEY-----\n", "headers": "-----BEGIN CERTIFICATE-----\nProc-Type: 4,ENCRYPTED\n\n" + body + "-----END CERTIFICATE-----\n", "base64 that is no cert": "-----BEGIN CERTIFICATE-----\nMIIBeDCCAR2gAwIBAgIQfake000000000000000000000000\n-----END CERTIFICATE-----\n", "carriage returns": strings.ReplaceAll(servedRoot, "\n", "\r\n"), } { if err := judge(ca, "root", bad); err == nil { t.Errorf("%s was taken", name) } } if err := judge(ca, "other", servedRoot); err == nil { t.Error("a certificate in another key of the authority was taken") } if err := judge(mcat.Manifest{Module: "mailu"}, "root", servedRoot); err == nil { t.Error("a certificate in another module's setting was taken") } if err := JudgeSettings(ca, []mcat.Layer{{From: "anchor", Values: map[string]any{"root": []any{servedRoot}}}}, false); err == nil { t.Error("a certificate below the top of the setting was taken") } } // Every character a reader takes as the end of a line is refused, not only \n and \r: vertical tab, form feed, // NEL and the Unicode line and paragraph separators (novox/hq issue 339). func TestEveryLineEndIsRefused(t *testing.T) { m := mcat.Manifest{Module: "mailu"} for _, v := range []string{"a\vb", "a\fb", "a\u0085b", "a\u2028b", "a\u2029b"} { if err := JudgeSettings(m, []mcat.Layer{{From: "home", Values: map[string]any{"v": v}}}, false); err == nil || !strings.Contains(err.Error(), "line break") { t.Errorf("%q: %v", v, err) } } }