diff --git a/v3/lints/cabf_br/lint_fqdn_contains_non_ldh_label.go b/v3/lints/cabf_br/lint_fqdn_contains_non_ldh_label.go new file mode 100644 index 000000000..6758a61c0 --- /dev/null +++ b/v3/lints/cabf_br/lint_fqdn_contains_non_ldh_label.go @@ -0,0 +1,67 @@ +/* + * ZLint Copyright 2021 Regents of the University of Michigan + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package cabf_br + +import ( + "regexp" + "strings" + + "github.com/zmap/zcrypto/x509" + "github.com/zmap/zlint/v3/lint" + "github.com/zmap/zlint/v3/util" +) + +func init() { + lint.RegisterLint(&lint.Lint{ + Name: "e_fqdn_contains_non_ldh_label", + Description: "The Fully‐Qualified Domain Name or the FQDN portion of the Wildcard Domain Name contained in the entry MUST be composed entirely of LDH Labels", + Citation: "BR 7.1.4.2.1", + Source: lint.CABFBaselineRequirements, + EffectiveDate: util.CABFBRs_1_8_0_Date, + Lint: NewFQDNContainsNonLDHLabel, + }) +} + +var nonLDHCharacterRegex = regexp.MustCompile(`[^a-zA-Z0-9\-]`) + +type FQDNContainsNonLDHLabel struct{} + +func NewFQDNContainsNonLDHLabel() lint.LintInterface { + return &FQDNContainsNonLDHLabel{} +} + +func (l *FQDNContainsNonLDHLabel) CheckApplies(c *x509.Certificate) bool { + return util.IsSubscriberCert(c) && util.DNSNamesExist(c) +} + +func IsLDHLabel(label string) bool { + return len(label) > 0 && + len(label) <= 63 && + !nonLDHCharacterRegex.MatchString(label) && + !strings.HasPrefix(label, "-") && + !strings.HasSuffix(label, "-") +} + +func (l *FQDNContainsNonLDHLabel) Execute(c *x509.Certificate) *lint.LintResult { + for _, dns := range c.DNSNames { + fqdnPortion := util.RemovePrependedWildcard(dns) + + if !util.AllLabelsSatisfyPredicate(fqdnPortion, IsLDHLabel) { + return &lint.LintResult{Status: lint.Error} + } + } + + return &lint.LintResult{Status: lint.Pass} +} diff --git a/v3/lints/cabf_br/lint_fqdn_contains_non_ldh_label_test.go b/v3/lints/cabf_br/lint_fqdn_contains_non_ldh_label_test.go new file mode 100644 index 000000000..c2c1fa0c3 --- /dev/null +++ b/v3/lints/cabf_br/lint_fqdn_contains_non_ldh_label_test.go @@ -0,0 +1,67 @@ +package cabf_br + +/* + * ZLint Copyright 2021 Regents of the University of Michigan + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +import ( + "testing" + + "github.com/zmap/zlint/v3/lint" + "github.com/zmap/zlint/v3/test" +) + +func TestFQDNContainsNonLDHLabel(t *testing.T) { + testCases := []struct { + InputFilename string + ExpectedResult lint.LintStatus + }{ + { + InputFilename: `dnsNameValidWildcard.pem`, + ExpectedResult: lint.Pass, + }, + { + InputFilename: `dnsNameLabel63CharactersValid.pem`, + ExpectedResult: lint.Pass, + }, + { + InputFilename: `dnsNameNonLDHEmptyLabel.pem`, + ExpectedResult: lint.Error, + }, + { + InputFilename: `dnsNameNonLDHInvalidCharacter.pem`, + ExpectedResult: lint.Error, + }, + { + InputFilename: `dnsNameNonLDHTooLongLabel.pem`, + ExpectedResult: lint.Error, + }, + { + InputFilename: `dnsNameNonLDHStartsWithHyphen.pem`, + ExpectedResult: lint.Error, + }, + { + InputFilename: `dnsNameNonLDHEndsWithHyphen.pem`, + ExpectedResult: lint.Error, + }, + } + + for _, tc := range testCases { + t.Run(tc.InputFilename, func(t *testing.T) { + result := test.TestLint("e_fqdn_contains_non_ldh_label", tc.InputFilename) + if result.Status != tc.ExpectedResult { + t.Errorf("expected result %v was %v", tc.ExpectedResult, result.Status) + } + }) + } +} diff --git a/v3/testdata/dnsNameLabel63CharactersValid.pem b/v3/testdata/dnsNameLabel63CharactersValid.pem new file mode 100644 index 000000000..768e96370 --- /dev/null +++ b/v3/testdata/dnsNameLabel63CharactersValid.pem @@ -0,0 +1,39 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 6b:cb:65:70:26:e5:f6:09:0c:d7:a9:c8:e9:48:46:69:fd:74:1a:01 + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN = Bar + Validity + Not Before: Oct 1 00:00:00 2021 GMT + Not After : Oct 1 00:00:00 2022 GMT + Subject: CN = Foo + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (512 bit) + Modulus: + 00:b9:31:63:12:27:72:6a:07:63:76:6c:4f:34:66: + a5:52:38:43:ce:26:7d:7a:e8:f5:0a:64:76:fb:55: + 48:bd:9a:b9:79:73:5a:3c:1e:ab:56:0d:b4:71:bb: + b9:8e:4a:da:b2:42:87:09:23:a2:53:9c:43:89:88: + 85:df:b2:31:91 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Alternative Name: + DNS:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com + Signature Algorithm: sha256WithRSAEncryption + 64:ab:4a:09:71:fc:81:ff:5b:15:81:91:cc:fb:93:aa:80:75: + b7:d1:45:6a:b9:47:f5:b3:1a:5d:55:87:1b:75:44:ac:36:23: + 23:bd:01:9e:fc:e4:a9:85:6f:c3:b7:72:67:18:0d:be:23:37: + 17:19:9b:1d:aa:36:d8:7a:c0:95 +-----BEGIN CERTIFICATE----- +MIIBcjCCARygAwIBAgIUa8tlcCbl9gkM16nI6UhGaf10GgEwDQYJKoZIhvcNAQEL +BQAwDjEMMAoGA1UEAwwDQmFyMB4XDTIxMTAwMTAwMDAwMFoXDTIyMTAwMTAwMDAw +MFowDjEMMAoGA1UEAwwDRm9vMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALkxYxIn +cmoHY3ZsTzRmpVI4Q84mfXro9QpkdvtVSL2auXlzWjweq1YNtHG7uY5K2rJChwkj +olOcQ4mIhd+yMZECAwEAAaNSMFAwTgYDVR0RBEcwRYJDYWFhYWFhYWFhYWFhYWFh +YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFh +LmNvbTANBgkqhkiG9w0BAQsFAANBAGSrSglx/IH/WxWBkcz7k6qAdbfRRWq5R/Wz +Gl1Vhxt1RKw2IyO9AZ785KmFb8O3cmcYDb4jNxcZmx2qNth6wJU= +-----END CERTIFICATE----- diff --git a/v3/testdata/dnsNameLabelNonLDHTooLong.pem b/v3/testdata/dnsNameLabelNonLDHTooLong.pem new file mode 100644 index 000000000..7a47a74b2 --- /dev/null +++ b/v3/testdata/dnsNameLabelNonLDHTooLong.pem @@ -0,0 +1,39 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 5f:3d:5f:d4:f0:e1:e9:a0:ea:ad:1d:fc:82:16:7b:62:d8:30:d8:2e + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN = Bar + Validity + Not Before: Oct 1 00:00:00 2021 GMT + Not After : Oct 1 00:00:00 2022 GMT + Subject: CN = Foo + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (512 bit) + Modulus: + 00:d1:e6:16:3c:ab:5c:36:4c:69:82:0b:9a:89:0c: + 96:4d:fb:72:9b:40:e9:da:22:d8:2b:c7:cf:2b:4c: + 02:10:75:55:98:f7:4e:86:24:ec:4f:3b:36:65:76: + 96:ae:f6:ef:44:34:78:5b:58:47:10:66:13:c0:4e: + 9e:8f:9f:2a:1b + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Alternative Name: + DNS:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com + Signature Algorithm: sha256WithRSAEncryption + 9a:ef:35:9d:89:3a:05:5c:77:9d:75:d0:dd:53:b2:ad:fc:ff: + 87:32:75:9b:67:9c:9f:9b:3e:bb:51:06:fe:16:6f:b3:13:6b: + 95:fc:e2:a7:7c:61:b0:84:78:45:16:8b:cf:cf:3d:9f:ab:f9: + ef:30:fe:6f:94:31:3b:40:57:b4 +-----BEGIN CERTIFICATE----- +MIIBczCCAR2gAwIBAgIUXz1f1PDh6aDqrR38ghZ7Ytgw2C4wDQYJKoZIhvcNAQEL +BQAwDjEMMAoGA1UEAwwDQmFyMB4XDTIxMTAwMTAwMDAwMFoXDTIyMTAwMTAwMDAw +MFowDjEMMAoGA1UEAwwDRm9vMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANHmFjyr +XDZMaYILmokMlk37cptA6doi2CvHzytMAhB1VZj3ToYk7E87NmV2lq7270Q0eFtY +RxBmE8BOno+fKhsCAwEAAaNTMFEwTwYDVR0RBEgwRoJEYWFhYWFhYWFhYWFhYWFh +YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFh +YS5jb20wDQYJKoZIhvcNAQELBQADQQCa7zWdiToFXHedddDdU7Kt/P+HMnWbZ5yf +mz67UQb+Fm+zE2uV/OKnfGGwhHhFFovPzz2fq/nvMP5vlDE7QFe0 +-----END CERTIFICATE----- diff --git a/v3/testdata/dnsNameNonLDHEmptyLabel.pem b/v3/testdata/dnsNameNonLDHEmptyLabel.pem new file mode 100644 index 000000000..88114f1b0 --- /dev/null +++ b/v3/testdata/dnsNameNonLDHEmptyLabel.pem @@ -0,0 +1,38 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 7e:e0:6a:57:82:68:21:c9:93:df:69:f4:27:de:54:85:9a:79:83:0f + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN = Bar + Validity + Not Before: Oct 1 00:00:00 2021 GMT + Not After : Oct 1 00:00:00 2022 GMT + Subject: CN = Foo + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (512 bit) + Modulus: + 00:e7:50:b2:fe:25:9c:dc:57:f5:d6:76:2f:89:84: + d1:90:20:bc:8f:61:4e:0d:9d:26:a5:e6:22:36:78: + 35:39:51:d1:dd:6b:98:f9:64:aa:85:43:71:3b:5d: + 49:48:96:e3:00:fa:d8:0f:ed:91:48:6b:4f:1d:78: + ef:51:36:8a:2f + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Alternative Name: + DNS:.com + Signature Algorithm: sha256WithRSAEncryption + 00:cd:f5:76:d9:a3:9b:5c:72:26:e4:d1:02:bb:b9:b8:51:aa: + 58:05:5e:18:87:26:9c:03:f6:4c:02:fd:86:c6:31:64:d1:1b: + 8c:97:75:81:ec:5b:95:13:d8:47:e1:ea:52:0b:4b:de:b6:df: + 70:7d:2b:9b:72:59:4c:2e:4e:3d +-----BEGIN CERTIFICATE----- +MIIBMjCB3aADAgECAhR+4GpXgmghyZPfafQn3lSFmnmDDzANBgkqhkiG9w0BAQsF +ADAOMQwwCgYDVQQDDANCYXIwHhcNMjExMDAxMDAwMDAwWhcNMjIxMDAxMDAwMDAw +WjAOMQwwCgYDVQQDDANGb28wXDANBgkqhkiG9w0BAQEFAANLADBIAkEA51Cy/iWc +3Ff11nYviYTRkCC8j2FODZ0mpeYiNng1OVHR3WuY+WSqhUNxO11JSJbjAPrYD+2R +SGtPHXjvUTaKLwIDAQABoxMwETAPBgNVHREECDAGggQuY29tMA0GCSqGSIb3DQEB +CwUAA0EAAM31dtmjm1xyJuTRAru5uFGqWAVeGIcmnAP2TAL9hsYxZNEbjJd1gexb +lRPYR+HqUgtL3rbfcH0rm3JZTC5OPQ== +-----END CERTIFICATE----- diff --git a/v3/testdata/dnsNameNonLDHEndsWithHyphen.pem b/v3/testdata/dnsNameNonLDHEndsWithHyphen.pem new file mode 100644 index 000000000..0c2b57c59 --- /dev/null +++ b/v3/testdata/dnsNameNonLDHEndsWithHyphen.pem @@ -0,0 +1,38 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 6c:26:dd:73:80:0b:e9:56:6e:31:2f:26:f1:94:e1:ad:43:9e:d7:51 + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN = Bar + Validity + Not Before: Oct 1 00:00:00 2021 GMT + Not After : Oct 1 00:00:00 2022 GMT + Subject: CN = Foo + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (512 bit) + Modulus: + 00:c4:a6:5e:de:8b:82:ac:d2:d9:3c:dd:f7:1f:1c: + 2d:fd:75:11:45:9d:75:f9:4d:53:29:30:ce:e1:7a: + be:24:47:ff:4d:9f:ad:b3:ae:50:a4:1b:f5:a0:1a: + 75:30:66:a5:ce:73:cd:27:ea:02:46:f0:e6:e8:c3: + 21:86:1c:c9:a1 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Alternative Name: + DNS:foo.bar-.com + Signature Algorithm: sha256WithRSAEncryption + 83:2f:3d:e5:1b:a0:65:60:23:69:a9:24:cd:d6:33:1e:05:14: + 4b:e4:94:3e:25:c7:c3:71:eb:b5:73:7f:8e:66:21:33:8a:fb: + 0f:a9:67:9a:fc:bb:c7:25:80:f9:c8:40:8f:be:41:a3:18:2b: + 83:54:85:f4:1a:dc:eb:98:e2:03 +-----BEGIN CERTIFICATE----- +MIIBOjCB5aADAgECAhRsJt1zgAvpVm4xLybxlOGtQ57XUTANBgkqhkiG9w0BAQsF +ADAOMQwwCgYDVQQDDANCYXIwHhcNMjExMDAxMDAwMDAwWhcNMjIxMDAxMDAwMDAw +WjAOMQwwCgYDVQQDDANGb28wXDANBgkqhkiG9w0BAQEFAANLADBIAkEAxKZe3ouC +rNLZPN33Hxwt/XURRZ11+U1TKTDO4Xq+JEf/TZ+ts65QpBv1oBp1MGalznPNJ+oC +RvDm6MMhhhzJoQIDAQABoxswGTAXBgNVHREEEDAOggxmb28uYmFyLS5jb20wDQYJ +KoZIhvcNAQELBQADQQCDLz3lG6BlYCNpqSTN1jMeBRRL5JQ+JcfDceu1c3+OZiEz +ivsPqWea/LvHJYD5yECPvkGjGCuDVIX0GtzrmOID +-----END CERTIFICATE----- diff --git a/v3/testdata/dnsNameNonLDHInvalidCharacter.pem b/v3/testdata/dnsNameNonLDHInvalidCharacter.pem new file mode 100644 index 000000000..525da1438 --- /dev/null +++ b/v3/testdata/dnsNameNonLDHInvalidCharacter.pem @@ -0,0 +1,38 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 03:1a:c1:48:f4:ec:d4:6b:bd:7e:5d:a7:b4:0e:72:e9:9c:ec:c2:3f + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN = Bar + Validity + Not Before: Oct 1 00:00:00 2021 GMT + Not After : Oct 1 00:00:00 2022 GMT + Subject: CN = Foo + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (512 bit) + Modulus: + 00:a6:cc:90:af:c9:5f:16:aa:02:88:51:dd:db:f1: + 50:d2:df:be:b6:e4:4a:a7:f1:2b:71:f5:49:35:8a: + a8:d8:c8:c3:1f:26:fc:ff:e8:8a:d4:51:a1:ff:c7: + 4c:5c:d0:71:41:fc:83:ed:dd:a6:75:23:b1:0f:c2: + 50:d0:e4:66:fb + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Alternative Name: + DNS:hell,o.com + Signature Algorithm: sha256WithRSAEncryption + 79:6e:00:62:8e:6c:75:2b:b2:3e:4c:05:39:0e:2b:a4:42:c4: + 23:fb:6d:de:da:1e:4e:3f:00:c7:7b:c7:e7:37:22:77:20:c0: + 68:df:c3:ef:f6:1d:a7:a6:29:29:0c:ce:a7:6d:6c:91:73:54: + b8:ed:08:3e:26:42:54:6a:11:12 +-----BEGIN CERTIFICATE----- +MIIBODCB46ADAgECAhQDGsFI9OzUa71+Xae0DnLpnOzCPzANBgkqhkiG9w0BAQsF +ADAOMQwwCgYDVQQDDANCYXIwHhcNMjExMDAxMDAwMDAwWhcNMjIxMDAxMDAwMDAw +WjAOMQwwCgYDVQQDDANGb28wXDANBgkqhkiG9w0BAQEFAANLADBIAkEApsyQr8lf +FqoCiFHd2/FQ0t++tuRKp/ErcfVJNYqo2MjDHyb8/+iK1FGh/8dMXNBxQfyD7d2m +dSOxD8JQ0ORm+wIDAQABoxkwFzAVBgNVHREEDjAMggpoZWxsLG8uY29tMA0GCSqG +SIb3DQEBCwUAA0EAeW4AYo5sdSuyPkwFOQ4rpELEI/tt3toeTj8Ax3vH5zcidyDA +aN/D7/Ydp6YpKQzOp21skXNUuO0IPiZCVGoREg== +-----END CERTIFICATE----- diff --git a/v3/testdata/dnsNameNonLDHStartsWithHyphen.pem b/v3/testdata/dnsNameNonLDHStartsWithHyphen.pem new file mode 100644 index 000000000..42fbbcd91 --- /dev/null +++ b/v3/testdata/dnsNameNonLDHStartsWithHyphen.pem @@ -0,0 +1,38 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 69:e2:af:b9:e3:8e:e4:33:85:95:a8:d1:b6:49:88:c1:ad:97:76:d7 + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN = Bar + Validity + Not Before: Oct 1 00:00:00 2021 GMT + Not After : Oct 1 00:00:00 2022 GMT + Subject: CN = Foo + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (512 bit) + Modulus: + 00:b7:c7:06:78:11:e4:a0:41:3d:fb:c4:31:de:a6: + 86:68:32:2b:08:04:e8:de:66:98:c5:6b:7f:13:ec: + 84:68:3d:55:40:7c:4f:42:c0:21:96:81:c6:9e:f2: + 0f:37:99:d5:37:5f:ba:9a:24:93:b1:8f:bf:01:e3: + 3e:f9:81:6f:51 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Alternative Name: + DNS:foo.-bar.com + Signature Algorithm: sha256WithRSAEncryption + 67:cf:58:2d:2f:66:86:e4:39:d8:b8:9f:3c:e5:f9:c3:8e:5d: + b9:20:0d:a6:72:63:1e:e9:f4:c6:bc:51:d5:15:8e:5f:c3:cf: + 25:63:c6:22:92:f9:19:d6:a6:37:ce:99:67:c2:a6:a5:86:5b: + 4e:db:7b:ad:fc:64:31:2c:b2:b4 +-----BEGIN CERTIFICATE----- +MIIBOjCB5aADAgECAhRp4q+5447kM4WVqNG2SYjBrZd21zANBgkqhkiG9w0BAQsF +ADAOMQwwCgYDVQQDDANCYXIwHhcNMjExMDAxMDAwMDAwWhcNMjIxMDAxMDAwMDAw +WjAOMQwwCgYDVQQDDANGb28wXDANBgkqhkiG9w0BAQEFAANLADBIAkEAt8cGeBHk +oEE9+8Qx3qaGaDIrCATo3maYxWt/E+yEaD1VQHxPQsAhloHGnvIPN5nVN1+6miST +sY+/AeM++YFvUQIDAQABoxswGTAXBgNVHREEEDAOggxmb28uLWJhci5jb20wDQYJ +KoZIhvcNAQELBQADQQBnz1gtL2aG5DnYuJ885fnDjl25IA2mcmMe6fTGvFHVFY5f +w88lY8YikvkZ1qY3zplnwqalhltO23ut/GQxLLK0 +-----END CERTIFICATE----- diff --git a/v3/testdata/dnsNameNonLDHTooLongLabel.pem b/v3/testdata/dnsNameNonLDHTooLongLabel.pem new file mode 100644 index 000000000..84c9ba9f4 --- /dev/null +++ b/v3/testdata/dnsNameNonLDHTooLongLabel.pem @@ -0,0 +1,39 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 36:dc:36:f4:ac:5b:ae:2a:86:55:f6:8c:5c:29:b4:f3:d3:a6:52:76 + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN = Bar + Validity + Not Before: Oct 1 00:00:00 2021 GMT + Not After : Oct 1 00:00:00 2022 GMT + Subject: CN = Foo + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (512 bit) + Modulus: + 00:cd:08:60:77:5a:4a:0f:b8:b2:eb:93:8e:cc:3e: + fa:d9:b1:0d:e3:8b:ca:67:49:19:f8:89:85:27:5c: + 6e:6b:cf:b8:08:0b:e6:c2:ab:e5:4b:9f:db:6e:8a: + 24:b5:b4:b0:55:70:9e:48:b0:74:22:39:a4:c5:80: + d1:e4:05:7d:d5 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Alternative Name: + DNS:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com + Signature Algorithm: sha256WithRSAEncryption + 1a:73:65:6d:77:ed:60:7f:d3:f6:f6:9b:e3:d1:ca:55:de:c9: + 98:7e:93:20:d2:42:37:32:c8:f7:eb:1f:95:fd:f2:79:5e:ee: + bf:b8:25:19:15:31:c4:00:ae:36:3f:60:54:45:b2:36:ea:28: + 14:54:04:5e:a8:6f:46:0f:7e:f8 +-----BEGIN CERTIFICATE----- +MIIBczCCAR2gAwIBAgIUNtw29KxbriqGVfaMXCm089OmUnYwDQYJKoZIhvcNAQEL +BQAwDjEMMAoGA1UEAwwDQmFyMB4XDTIxMTAwMTAwMDAwMFoXDTIyMTAwMTAwMDAw +MFowDjEMMAoGA1UEAwwDRm9vMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAM0IYHda +Sg+4suuTjsw++tmxDeOLymdJGfiJhSdcbmvPuAgL5sKr5Uuf226KJLW0sFVwnkiw +dCI5pMWA0eQFfdUCAwEAAaNTMFEwTwYDVR0RBEgwRoJEYWFhYWFhYWFhYWFhYWFh +YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFh +YS5jb20wDQYJKoZIhvcNAQELBQADQQAac2Vtd+1gf9P29pvj0cpV3smYfpMg0kI3 +Msj36x+V/fJ5Xu6/uCUZFTHEAK42P2BURbI26igUVAReqG9GD374 +-----END CERTIFICATE----- diff --git a/v3/testdata/dnsNameValidWildcard.pem b/v3/testdata/dnsNameValidWildcard.pem new file mode 100644 index 000000000..2fc959652 --- /dev/null +++ b/v3/testdata/dnsNameValidWildcard.pem @@ -0,0 +1,38 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 03:44:14:59:55:55:32:20:50:a6:98:61:26:21:d9:7d:61:3c:ef:63 + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN = Bar + Validity + Not Before: Oct 1 00:00:00 2021 GMT + Not After : Oct 1 00:00:00 2022 GMT + Subject: CN = Foo + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (512 bit) + Modulus: + 00:b3:fc:8c:9c:66:bd:cc:05:8d:74:91:6d:c3:07: + ec:f5:47:54:35:31:be:cf:36:0f:d7:22:92:5e:f8: + 68:bd:64:73:7e:53:90:9a:81:8a:f2:fc:ba:f7:f5: + 57:27:7d:70:58:64:c9:3f:4c:3e:11:00:0c:01:a2: + 29:a4:69:16:83 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Alternative Name: + DNS:*.foo.com + Signature Algorithm: sha256WithRSAEncryption + 18:0b:2c:b6:96:5d:68:e8:77:ce:ba:18:56:2b:52:26:54:9e: + 9f:6d:90:2a:4f:2d:15:08:63:e1:71:70:8a:91:1b:05:ee:2c: + 66:89:b3:2a:6c:df:a3:6d:fe:37:39:e7:a8:77:60:70:f6:5c: + 8d:23:d4:85:4c:cb:91:39:0b:99 +-----BEGIN CERTIFICATE----- +MIIBNzCB4qADAgECAhQDRBRZVVUyIFCmmGEmIdl9YTzvYzANBgkqhkiG9w0BAQsF +ADAOMQwwCgYDVQQDDANCYXIwHhcNMjExMDAxMDAwMDAwWhcNMjIxMDAxMDAwMDAw +WjAOMQwwCgYDVQQDDANGb28wXDANBgkqhkiG9w0BAQEFAANLADBIAkEAs/yMnGa9 +zAWNdJFtwwfs9UdUNTG+zzYP1yKSXvhovWRzflOQmoGK8vy69/VXJ31wWGTJP0w+ +EQAMAaIppGkWgwIDAQABoxgwFjAUBgNVHREEDTALggkqLmZvby5jb20wDQYJKoZI +hvcNAQELBQADQQAYCyy2ll1o6HfOuhhWK1ImVJ6fbZAqTy0VCGPhcXCKkRsF7ixm +ibMqbN+jbf43Oeeod2Bw9lyNI9SFTMuROQuZ +-----END CERTIFICATE----- diff --git a/v3/util/fqdn.go b/v3/util/fqdn.go index 705104912..ea7d74968 100644 --- a/v3/util/fqdn.go +++ b/v3/util/fqdn.go @@ -117,3 +117,15 @@ func CommonNameIsIP(cert *x509.Certificate) bool { return true } } + +func AllLabelsSatisfyPredicate(dns string, labelPredicate func(string) bool) bool { + labels := strings.Split(dns, ".") + + for _, label := range labels { + if !labelPredicate(label) { + return false + } + } + + return true +} diff --git a/v3/util/fqdn_test.go b/v3/util/fqdn_test.go index a3779c9d6..dbce94771 100644 --- a/v3/util/fqdn_test.go +++ b/v3/util/fqdn_test.go @@ -1012,3 +1012,25 @@ func TestGetHostWithUserinfoWithPortWithAbsolutePathWithQueryWithFragment(t *tes ) } } + +func IsLabelFoo(label string) bool { + return label == "foo" +} + +func TestAllLabelsSatisfyPredicate(t *testing.T) { + input := map[string]bool{ + "foo": true, + "foo.foo": true, + "": false, + ".foo": false, + "foo.": false, + ".foo.": false, + } + + for input, want := range input { + got := AllLabelsSatisfyPredicate(input, IsLabelFoo) + if got != want { + t.Errorf("got %v want %v for input '%s'", got, want, input) + } + } +}