From 56b48a49076e8c106c0418919212848b63e0797b Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Fri, 9 Feb 2018 16:28:33 -0500 Subject: [PATCH 1/7] Various PKI updates: * Update hostname regex in cert util to handle wildcard * Convert a DNS name, if needed, to IDN equivalent before adding to DNS SANs (wildcard handled separately since it is not a valid part of an IDNA conversion) * Change SAN DNS value in tests to be host names since Go 1.10 will be more strict about this --- builtin/logical/pki/backend_test.go | 52 ++++++++++++----------------- builtin/logical/pki/cert_util.go | 39 ++++++++++++++++++---- 2 files changed, 55 insertions(+), 36 deletions(-) diff --git a/builtin/logical/pki/backend_test.go b/builtin/logical/pki/backend_test.go index f6dc61b73aa8..e8907b4299d5 100644 --- a/builtin/logical/pki/backend_test.go +++ b/builtin/logical/pki/backend_test.go @@ -33,6 +33,7 @@ import ( logicaltest "github.com/hashicorp/vault/logical/testing" "github.com/hashicorp/vault/vault" "github.com/mitchellh/mapstructure" + "golang.org/x/net/idna" ) var ( @@ -153,8 +154,6 @@ func TestBackend_RSAKey(t *testing.T) { Steps: []logicaltest.TestStep{}, } - stepCount = len(testCase.Steps) - intdata := map[string]interface{}{} reqdata := map[string]interface{}{} testCase.Steps = append(testCase.Steps, generateCATestingSteps(t, rsaCACert, rsaCAKey, ecCACert, intdata, reqdata)...) @@ -183,8 +182,6 @@ func TestBackend_ECKey(t *testing.T) { Steps: []logicaltest.TestStep{}, } - stepCount = len(testCase.Steps) - intdata := map[string]interface{}{} reqdata := map[string]interface{}{} testCase.Steps = append(testCase.Steps, generateCATestingSteps(t, ecCACert, ecCAKey, rsaCACert, intdata, reqdata)...) @@ -211,8 +208,6 @@ func TestBackend_CSRValues(t *testing.T) { Steps: []logicaltest.TestStep{}, } - stepCount = len(testCase.Steps) - intdata := map[string]interface{}{} reqdata := map[string]interface{}{} testCase.Steps = append(testCase.Steps, generateCSRSteps(t, ecCACert, ecCAKey, intdata, reqdata)...) @@ -239,8 +234,6 @@ func TestBackend_URLsCRUD(t *testing.T) { Steps: []logicaltest.TestStep{}, } - stepCount = len(testCase.Steps) - intdata := map[string]interface{}{} reqdata := map[string]interface{}{} testCase.Steps = append(testCase.Steps, generateURLSteps(t, ecCACert, ecCAKey, intdata, reqdata)...) @@ -278,12 +271,10 @@ func TestBackend_RSARoles(t *testing.T) { }, } - stepCount = len(testCase.Steps) - testCase.Steps = append(testCase.Steps, generateRoleSteps(t, false)...) if len(os.Getenv("VAULT_VERBOSE_PKITESTS")) > 0 { for i, v := range testCase.Steps { - fmt.Printf("Step %d:\n%+v\n\n", i+stepCount, v) + fmt.Printf("Step %d:\n%+v\n\n", i+1, v) } } @@ -320,12 +311,10 @@ func TestBackend_RSARoles_CSR(t *testing.T) { }, } - stepCount = len(testCase.Steps) - testCase.Steps = append(testCase.Steps, generateRoleSteps(t, true)...) if len(os.Getenv("VAULT_VERBOSE_PKITESTS")) > 0 { for i, v := range testCase.Steps { - fmt.Printf("Step %d:\n%+v\n\n", i+stepCount, v) + fmt.Printf("Step %d:\n%+v\n\n", i+1, v) } } @@ -362,12 +351,10 @@ func TestBackend_ECRoles(t *testing.T) { }, } - stepCount = len(testCase.Steps) - testCase.Steps = append(testCase.Steps, generateRoleSteps(t, false)...) if len(os.Getenv("VAULT_VERBOSE_PKITESTS")) > 0 { for i, v := range testCase.Steps { - fmt.Printf("Step %d:\n%+v\n\n", i+stepCount, v) + fmt.Printf("Step %d:\n%+v\n\n", i+1, v) } } @@ -404,12 +391,10 @@ func TestBackend_ECRoles_CSR(t *testing.T) { }, } - stepCount = len(testCase.Steps) - testCase.Steps = append(testCase.Steps, generateRoleSteps(t, true)...) if len(os.Getenv("VAULT_VERBOSE_PKITESTS")) > 0 { for i, v := range testCase.Steps { - fmt.Printf("Step %d:\n%+v\n\n", i+stepCount, v) + fmt.Printf("Step %d:\n%+v\n\n", i+1, v) } } @@ -588,7 +573,7 @@ func generateURLSteps(t *testing.T, caCert, caKey string, intdata, reqdata map[s Operation: logical.UpdateOperation, Path: "root/sign-intermediate", Data: map[string]interface{}{ - "common_name": "Intermediate Cert", + "common_name": "intermediate.cert.com", "csr": string(csrPem1024), "format": "der", }, @@ -609,7 +594,7 @@ func generateURLSteps(t *testing.T, caCert, caKey string, intdata, reqdata map[s Operation: logical.UpdateOperation, Path: "root/sign-intermediate", Data: map[string]interface{}{ - "common_name": "Intermediate Cert", + "common_name": "intermediate.cert.com", "csr": string(csrPem2048), "format": "der", }, @@ -638,8 +623,8 @@ func generateURLSteps(t *testing.T, caCert, caKey string, intdata, reqdata map[s return fmt.Errorf("expected\n%#v\ngot\n%#v\n", expected.CRLDistributionPoints, cert.CRLDistributionPoints) case !reflect.DeepEqual(expected.OCSPServers, cert.OCSPServer): return fmt.Errorf("expected\n%#v\ngot\n%#v\n", expected.OCSPServers, cert.OCSPServer) - case !reflect.DeepEqual([]string{"Intermediate Cert"}, cert.DNSNames): - return fmt.Errorf("expected\n%#v\ngot\n%#v\n", []string{"Intermediate Cert"}, cert.DNSNames) + case !reflect.DeepEqual([]string{"intermediate.cert.com"}, cert.DNSNames): + return fmt.Errorf("expected\n%#v\ngot\n%#v\n", []string{"intermediate.cert.com"}, cert.DNSNames) } return nil @@ -651,7 +636,7 @@ func generateURLSteps(t *testing.T, caCert, caKey string, intdata, reqdata map[s Operation: logical.UpdateOperation, Path: "root/sign-intermediate", Data: map[string]interface{}{ - "common_name": "Intermediate Cert", + "common_name": "intermediate.cert.com", "csr": string(csrPem2048), "format": "der", "exclude_cn_from_sans": true, @@ -991,7 +976,7 @@ func generateCATestingSteps(t *testing.T, caCert, caKey, otherCaCert string, int Operation: logical.UpdateOperation, Path: "intermediate/generate/exported", Data: map[string]interface{}{ - "common_name": "Intermediate Cert", + "common_name": "intermediate.cert.com", }, Check: func(resp *logical.Response) error { intdata["intermediatecsr"] = resp.Data["csr"].(string) @@ -1009,7 +994,7 @@ func generateCATestingSteps(t *testing.T, caCert, caKey, otherCaCert string, int delete(reqdata, "pem_bundle") delete(reqdata, "ttl") reqdata["csr"] = intdata["intermediatecsr"].(string) - reqdata["common_name"] = "Intermediate Cert" + reqdata["common_name"] = "intermediate.cert.com" reqdata["ttl"] = "10s" return nil }, @@ -1144,7 +1129,7 @@ func generateCATestingSteps(t *testing.T, caCert, caKey, otherCaCert string, int "format": "der", "key_type": "ec", "key_bits": 384, - "common_name": "Intermediate Cert", + "common_name": "intermediate.cert.com", }, Check: func(resp *logical.Response) error { csrBytes, _ := base64.StdEncoding.DecodeString(resp.Data["csr"].(string)) @@ -1171,7 +1156,7 @@ func generateCATestingSteps(t *testing.T, caCert, caKey, otherCaCert string, int delete(reqdata, "pem_bundle") delete(reqdata, "ttl") reqdata["csr"] = intdata["intermediatecsr"].(string) - reqdata["common_name"] = "Intermediate Cert" + reqdata["common_name"] = "intermediate.cert.com" reqdata["ttl"] = "10s" return nil }, @@ -1646,7 +1631,14 @@ func generateRoleSteps(t *testing.T, useCSRs bool) []logicaltest.TestStep { retName = cert.EmailAddresses[0] } if retName != name { - return fmt.Errorf("Error: returned certificate has a DNS SAN of %s but %s was requested", retName, name) + // Check IDNA + converted, err := idna.Lookup.ToUnicode(retName) + if err != nil { + t.Fatal(err) + } + if converted != name { + return fmt.Errorf("Error: returned certificate has a DNS SAN of %s (from idna: %s) but %s was requested", retName, converted, name) + } } return nil } diff --git a/builtin/logical/pki/cert_util.go b/builtin/logical/pki/cert_util.go index bbdff2f3aec7..4a3843e8a0f6 100644 --- a/builtin/logical/pki/cert_util.go +++ b/builtin/logical/pki/cert_util.go @@ -27,6 +27,7 @@ import ( "github.com/hashicorp/vault/logical" "github.com/hashicorp/vault/logical/framework" "github.com/ryanuber/go-glob" + "golang.org/x/net/idna" ) type certExtKeyUsage int @@ -91,7 +92,7 @@ func (b *caInfoBundle) GetCAChain() []*certutil.CertBlock { } var ( - hostnameRegex = regexp.MustCompile(`^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$`) + hostnameRegex = regexp.MustCompile(`^(\*\.)?(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]{0,61}[A-Za-z0-9])$`) oidExtensionBasicConstraints = []int{2, 5, 29, 19} ) @@ -642,9 +643,22 @@ func generateCreationBundle(b *backend, // used for the purpose for which they are presented emailAddresses = append(emailAddresses, cn) } else { - // Only add to dnsNames if it's actually a DNS name - if hostnameRegex.MatchString(cn) { - dnsNames = append(dnsNames, cn) + // Only add to dnsNames if it's actually a DNS name but convert idn first + wildcard := false + lcn := cn + if strings.HasPrefix(cn, "*.") { + wildcard = true + lcn = strings.TrimPrefix(cn, "*.") + } + converted, err := idna.Lookup.ToASCII(lcn) + if err != nil { + return nil, errutil.UserError{Err: err.Error()} + } + if hostnameRegex.MatchString(converted) { + if wildcard { + converted = "*." + converted + } + dnsNames = append(dnsNames, converted) } } } @@ -657,8 +671,21 @@ func generateCreationBundle(b *backend, if strings.Contains(v, "@") { emailAddresses = append(emailAddresses, v) } else { - if hostnameRegex.MatchString(v) { - dnsNames = append(dnsNames, v) + // Only add to dnsNames if it's actually a DNS name but convert idn first + wildcard := false + if strings.HasPrefix(v, "*.") { + wildcard = true + v = strings.TrimPrefix(v, "*.") + } + converted, err := idna.Lookup.ToASCII(v) + if err != nil { + return nil, errutil.UserError{Err: err.Error()} + } + if hostnameRegex.MatchString(converted) { + if wildcard { + converted = "*." + converted + } + dnsNames = append(dnsNames, converted) } } } From 48d2cd9875bb8f83f5c56678266d731164e878b8 Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Fri, 9 Feb 2018 16:45:17 -0500 Subject: [PATCH 2/7] Vendor deps --- builtin/logical/pki/cert_util.go | 2 +- vendor/vendor.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/builtin/logical/pki/cert_util.go b/builtin/logical/pki/cert_util.go index 4a3843e8a0f6..ca64a967e330 100644 --- a/builtin/logical/pki/cert_util.go +++ b/builtin/logical/pki/cert_util.go @@ -92,7 +92,7 @@ func (b *caInfoBundle) GetCAChain() []*certutil.CertBlock { } var ( - hostnameRegex = regexp.MustCompile(`^(\*\.)?(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]{0,61}[A-Za-z0-9])$`) + hostnameRegex = regexp.MustCompile(`^(\*\.)?(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$`) oidExtensionBasicConstraints = []int{2, 5, 29, 19} ) diff --git a/vendor/vendor.json b/vendor/vendor.json index 26b22b74d904..db66169493bf 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -1647,8 +1647,8 @@ { "checksumSHA1": "RcrB7tgYS/GMW4QrwVdMOTNqIU8=", "path": "golang.org/x/net/idna", - "revision": "0ed95abb35c445290478a5348a7b38bb154135fd", - "revisionTime": "2018-01-24T06:08:02Z" + "revision": "f5dfe339be1d06f81b22525fe34671ee7d2c8904", + "revisionTime": "2018-02-04T03:50:36Z" }, { "checksumSHA1": "5JWn/wMC+EWNDKI/AYE4JifQF54=", From 2a19b7fd032b2ee732cfa75d58c142f681fbcaf7 Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Fri, 9 Feb 2018 16:58:59 -0500 Subject: [PATCH 3/7] Simplify the idna logic a bit --- builtin/logical/pki/backend_test.go | 6 ++++- builtin/logical/pki/cert_util.go | 35 ++++++++++++----------------- 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/builtin/logical/pki/backend_test.go b/builtin/logical/pki/backend_test.go index e8907b4299d5..402dc1d8f3d6 100644 --- a/builtin/logical/pki/backend_test.go +++ b/builtin/logical/pki/backend_test.go @@ -1632,7 +1632,11 @@ func generateRoleSteps(t *testing.T, useCSRs bool) []logicaltest.TestStep { } if retName != name { // Check IDNA - converted, err := idna.Lookup.ToUnicode(retName) + p := idna.New( + idna.StrictDomainName(true), + idna.VerifyDNSLength(true), + ) + converted, err := p.ToUnicode(retName) if err != nil { t.Fatal(err) } diff --git a/builtin/logical/pki/cert_util.go b/builtin/logical/pki/cert_util.go index ca64a967e330..32b48093341f 100644 --- a/builtin/logical/pki/cert_util.go +++ b/builtin/logical/pki/cert_util.go @@ -643,21 +643,17 @@ func generateCreationBundle(b *backend, // used for the purpose for which they are presented emailAddresses = append(emailAddresses, cn) } else { - // Only add to dnsNames if it's actually a DNS name but convert idn first - wildcard := false - lcn := cn - if strings.HasPrefix(cn, "*.") { - wildcard = true - lcn = strings.TrimPrefix(cn, "*.") - } - converted, err := idna.Lookup.ToASCII(lcn) + // Only add to dnsNames if it's actually a DNS name but convert + // idn first + p := idna.New( + idna.StrictDomainName(true), + idna.VerifyDNSLength(true), + ) + converted, err := p.ToASCII(cn) if err != nil { return nil, errutil.UserError{Err: err.Error()} } if hostnameRegex.MatchString(converted) { - if wildcard { - converted = "*." + converted - } dnsNames = append(dnsNames, converted) } } @@ -671,20 +667,17 @@ func generateCreationBundle(b *backend, if strings.Contains(v, "@") { emailAddresses = append(emailAddresses, v) } else { - // Only add to dnsNames if it's actually a DNS name but convert idn first - wildcard := false - if strings.HasPrefix(v, "*.") { - wildcard = true - v = strings.TrimPrefix(v, "*.") - } - converted, err := idna.Lookup.ToASCII(v) + // Only add to dnsNames if it's actually a DNS name but + // convert idn first + p := idna.New( + idna.StrictDomainName(true), + idna.VerifyDNSLength(true), + ) + converted, err := p.ToASCII(v) if err != nil { return nil, errutil.UserError{Err: err.Error()} } if hostnameRegex.MatchString(converted) { - if wildcard { - converted = "*." + converted - } dnsNames = append(dnsNames, converted) } } From d2452aa0d826f7215cc413a46af311896c71d0ee Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Fri, 9 Feb 2018 17:07:53 -0500 Subject: [PATCH 4/7] Remove hostname regex --- builtin/logical/pki/cert_util.go | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/builtin/logical/pki/cert_util.go b/builtin/logical/pki/cert_util.go index 32b48093341f..9ce6fd4dfe64 100644 --- a/builtin/logical/pki/cert_util.go +++ b/builtin/logical/pki/cert_util.go @@ -15,7 +15,6 @@ import ( "encoding/pem" "fmt" "net" - "regexp" "strings" "time" @@ -92,7 +91,6 @@ func (b *caInfoBundle) GetCAChain() []*certutil.CertBlock { } var ( - hostnameRegex = regexp.MustCompile(`^(\*\.)?(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$`) oidExtensionBasicConstraints = []int{2, 5, 29, 19} ) @@ -298,7 +296,12 @@ func validateNames(req *logical.Request, names []string, role *roleEntry) string // ensure that we are not either checking a full email address or a // wildcard prefix. if role.EnforceHostnames { - if !hostnameRegex.MatchString(sanitizedName) { + p := idna.New( + idna.StrictDomainName(true), + idna.VerifyDNSLength(true), + ) + converted, err := p.ToASCII(sanitizedName) + if err != nil { return name } } @@ -650,10 +653,7 @@ func generateCreationBundle(b *backend, idna.VerifyDNSLength(true), ) converted, err := p.ToASCII(cn) - if err != nil { - return nil, errutil.UserError{Err: err.Error()} - } - if hostnameRegex.MatchString(converted) { + if err == nil { dnsNames = append(dnsNames, converted) } } @@ -674,10 +674,7 @@ func generateCreationBundle(b *backend, idna.VerifyDNSLength(true), ) converted, err := p.ToASCII(v) - if err != nil { - return nil, errutil.UserError{Err: err.Error()} - } - if hostnameRegex.MatchString(converted) { + if err == nil { dnsNames = append(dnsNames, converted) } } From ffba3a416fa489f9172a459ded1a6fffbb883bff Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Fri, 9 Feb 2018 17:08:29 -0500 Subject: [PATCH 5/7] Fix build --- builtin/logical/pki/cert_util.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/logical/pki/cert_util.go b/builtin/logical/pki/cert_util.go index 9ce6fd4dfe64..bd353ce5743f 100644 --- a/builtin/logical/pki/cert_util.go +++ b/builtin/logical/pki/cert_util.go @@ -300,7 +300,7 @@ func validateNames(req *logical.Request, names []string, role *roleEntry) string idna.StrictDomainName(true), idna.VerifyDNSLength(true), ) - converted, err := p.ToASCII(sanitizedName) + _, err := p.ToASCII(sanitizedName) if err != nil { return name } From 873e321fc05684cfa3e27486715b430355ce885c Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Fri, 9 Feb 2018 17:40:38 -0500 Subject: [PATCH 6/7] Change nonhostname test to IDN test --- builtin/logical/pki/backend_test.go | 4 ++-- builtin/logical/pki/cert_util.go | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/builtin/logical/pki/backend_test.go b/builtin/logical/pki/backend_test.go index 402dc1d8f3d6..0684ee5555fa 100644 --- a/builtin/logical/pki/backend_test.go +++ b/builtin/logical/pki/backend_test.go @@ -1658,7 +1658,7 @@ func generateRoleSteps(t *testing.T, useCSRs bool) []logicaltest.TestStep { SubSubdomain bool `structs:"foo.bar.example.com"` SubSubdomainWildcard bool `structs:"*.bar.example.com"` GlobDomain bool `structs:"fooexample.com"` - NonHostname bool `structs:"daɪˈɛrɨsɨs"` + IDN bool `structs:"daɪˈɛrɨsɨs"` AnyHost bool `structs:"porkslap.beer"` } @@ -1872,10 +1872,10 @@ func generateRoleSteps(t *testing.T, useCSRs bool) []logicaltest.TestStep { roleVals.AllowAnyName = true roleVals.EnforceHostnames = true commonNames.AnyHost = true + commonNames.IDN = true addCnTests() roleVals.EnforceHostnames = false - commonNames.NonHostname = true addCnTests() // Ensure that we end up with acceptable key sizes since they won't be diff --git a/builtin/logical/pki/cert_util.go b/builtin/logical/pki/cert_util.go index bd353ce5743f..5924be581699 100644 --- a/builtin/logical/pki/cert_util.go +++ b/builtin/logical/pki/cert_util.go @@ -417,7 +417,6 @@ func validateNames(req *logical.Request, names []string, role *roleEntry) string } } - //panic(fmt.Sprintf("\nName is %s\nRole is\n%#v\n", name, role)) return name } From c327d24ecc4fed1f9263652dec055e289e318722 Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Sat, 10 Feb 2018 10:00:40 -0500 Subject: [PATCH 7/7] Re-add hostname regex. IDNA's strict domain name checking appears to only take effect when it actually produces new output so it can't be relied upon to ensure that only DNS-compatible names get through. --- builtin/logical/pki/cert_util.go | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/builtin/logical/pki/cert_util.go b/builtin/logical/pki/cert_util.go index 5924be581699..a02a4c229231 100644 --- a/builtin/logical/pki/cert_util.go +++ b/builtin/logical/pki/cert_util.go @@ -15,6 +15,7 @@ import ( "encoding/pem" "fmt" "net" + "regexp" "strings" "time" @@ -91,6 +92,11 @@ func (b *caInfoBundle) GetCAChain() []*certutil.CertBlock { } var ( + // A note on hostnameRegex: although we set the StrictDomainName option + // when doing the idna conversion, this appears to only affect output, not + // input, so it will allow e.g. host^123.example.com straight through. So + // we still need to use this to check the output. + hostnameRegex = regexp.MustCompile(`^(\*\.)?(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$`) oidExtensionBasicConstraints = []int{2, 5, 29, 19} ) @@ -300,10 +306,13 @@ func validateNames(req *logical.Request, names []string, role *roleEntry) string idna.StrictDomainName(true), idna.VerifyDNSLength(true), ) - _, err := p.ToASCII(sanitizedName) + converted, err := p.ToASCII(sanitizedName) if err != nil { return name } + if !hostnameRegex.MatchString(converted) { + return name + } } // Self-explanatory @@ -652,7 +661,10 @@ func generateCreationBundle(b *backend, idna.VerifyDNSLength(true), ) converted, err := p.ToASCII(cn) - if err == nil { + if err != nil { + return nil, errutil.UserError{Err: err.Error()} + } + if hostnameRegex.MatchString(converted) { dnsNames = append(dnsNames, converted) } } @@ -673,7 +685,10 @@ func generateCreationBundle(b *backend, idna.VerifyDNSLength(true), ) converted, err := p.ToASCII(v) - if err == nil { + if err != nil { + return nil, errutil.UserError{Err: err.Error()} + } + if hostnameRegex.MatchString(converted) { dnsNames = append(dnsNames, converted) } }