Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,7 @@ linters:
checks:
- all
# TODO: Identify, fix, and remove violations of most of these rules
- -S1029 # Range over the string directly
- -SA1019 # Using a deprecated function, variable, constant or field
- -SA6003 # Converting a string to a slice of runes before ranging over it
- -ST1000 # Incorrect or missing package comment
- -ST1003 # Poorly chosen identifier
- -ST1005 # Incorrectly formatted error string
Expand Down
26 changes: 12 additions & 14 deletions va/caa.go
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,14 @@ type caaParameter struct {
val string
}

// ASCII alpha, digits, and hyphens in the middle.
// tag = (ALPHA / DIGIT) *( *("-") (ALPHA / DIGIT))
var caaParameterTagRegexp = regexp.MustCompile(`^[[:alnum:]](-*[[:alnum:]])*$`)

// ASCII without whitespace/semi-colons.
// value = *(%x21-3A / %x3C-7E)
var caaParameterValueRegexp = regexp.MustCompile(`^[\x21-\x3a\x3c-\x7e]*$`)

// parseCAARecord extracts the domain and parameters (if any) from a
// issue/issuewild CAA record. This follows RFC 8659 Section 4.2 and Section 4.3
// (https://www.rfc-editor.org/rfc/rfc8659.html#section-4). It returns the
Expand Down Expand Up @@ -450,23 +458,13 @@ func parseCAARecord(caa *dns.CAA) (string, []caaParameter, error) {
}

tag := strings.TrimFunc(tv[0], isWSP)
//lint:ignore S1029,SA6003 we iterate over runes because the RFC specifies ascii codepoints.
for _, r := range []rune(tag) {
// ASCII alpha/digits.
// tag = (ALPHA / DIGIT) *( *("-") (ALPHA / DIGIT))
if r < 0x30 || (r > 0x39 && r < 0x41) || (r > 0x5a && r < 0x61) || r > 0x7a {
return "", nil, fmt.Errorf("tag contains disallowed character: %q", tag)
}
if !caaParameterTagRegexp.MatchString(tag) {
return "", nil, fmt.Errorf("tag contains disallowed character: %q", tag)
}

value := strings.TrimFunc(tv[1], isWSP)
//lint:ignore S1029,SA6003 we iterate over runes because the RFC specifies ascii codepoints.
for _, r := range []rune(value) {
// ASCII without whitespace/semi-colons.
// value = *(%x21-3A / %x3C-7E)
if r < 0x21 || (r > 0x3a && r < 0x3c) || r > 0x7e {
return "", nil, fmt.Errorf("value contains disallowed character: %q", value)
}
if !caaParameterValueRegexp.MatchString(value) {
return "", nil, fmt.Errorf("value contains disallowed character: %q", value)
}

caaParameters = append(caaParameters, caaParameter{
Expand Down
38 changes: 37 additions & 1 deletion va/caa_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1673,8 +1673,44 @@ func TestExtractIssuerDomainAndParameters(t *testing.T) {
expectErrSubstr: "value contains disallowed character",
},
{
name: "hyphens in param tags are invalid",
name: "interior hyphens in param tags are valid",
value: "letsencrypt.org; 1=2; a-b=c",
wantDomain: "letsencrypt.org",
wantParameters: []caaParameter{{tag: "1", val: "2"}, {tag: "a-b", val: "c"}},
expectErrSubstr: "",
},
{
name: "multiple interior hyphens in param tags are valid",
value: "letsencrypt.org; 1=2; a-b-c=d",
wantDomain: "letsencrypt.org",
wantParameters: []caaParameter{{tag: "1", val: "2"}, {tag: "a-b-c", val: "d"}},
expectErrSubstr: "",
},
{
name: "consecutive interior hyphens in param tags are valid",
value: "letsencrypt.org; a--b=c",
wantDomain: "letsencrypt.org",
wantParameters: []caaParameter{{tag: "a--b", val: "c"}},
expectErrSubstr: "",
},
{
name: "leading hyphen in param tag is invalid",
value: "letsencrypt.org; -ab=c",
expectErrSubstr: "tag contains disallowed character",
},
{
name: "trailing hyphen in param tag is invalid",
value: "letsencrypt.org; ab-=c",
expectErrSubstr: "tag contains disallowed character",
},
{
name: "empty param tag is invalid",
value: "letsencrypt.org; =c",
expectErrSubstr: "tag contains disallowed character",
},
{
name: "empty param tag between valid params is invalid",
value: "letsencrypt.org; a=b; =c",
expectErrSubstr: "tag contains disallowed character",
},
{
Expand Down