diff --git a/builtin/logical/pki/cert_util.go b/builtin/logical/pki/cert_util.go index 6992e04872..c6503cfe97 100644 --- a/builtin/logical/pki/cert_util.go +++ b/builtin/logical/pki/cert_util.go @@ -563,10 +563,8 @@ func generateCreationBundle(b *backend, // Get the common name var cn string { - if csr != nil { - if role.UseCSRCommonName { - cn = csr.Subject.CommonName - } + if csr != nil && role.UseCSRCommonName { + cn = csr.Subject.CommonName } if cn == "" { cn = data.Get("common_name").(string) @@ -596,6 +594,11 @@ func generateCreationBundle(b *backend, dnsNames := []string{} emailAddresses := []string{} { + if csr != nil && role.UseCSRSANs { + dnsNames = csr.DNSNames + emailAddresses = csr.EmailAddresses + } + if !data.Get("exclude_cn_from_sans").(bool) { if strings.Contains(cn, "@") { // Note: emails are not disallowed if the role's email protection @@ -608,15 +611,18 @@ func generateCreationBundle(b *backend, dnsNames = append(dnsNames, cn) } } - cnAltInt, ok := data.GetOk("alt_names") - if ok { - cnAlt := cnAltInt.(string) - if len(cnAlt) != 0 { - for _, v := range strings.Split(cnAlt, ",") { - if strings.Contains(v, "@") { - emailAddresses = append(emailAddresses, v) - } else { - dnsNames = append(dnsNames, v) + + if csr == nil || !role.UseCSRSANs { + cnAltInt, ok := data.GetOk("alt_names") + if ok { + cnAlt := cnAltInt.(string) + if len(cnAlt) != 0 { + for _, v := range strings.Split(cnAlt, ",") { + if strings.Contains(v, "@") { + emailAddresses = append(emailAddresses, v) + } else { + dnsNames = append(dnsNames, v) + } } } } @@ -646,21 +652,29 @@ func generateCreationBundle(b *backend, ipAddresses := []net.IP{} var ipAltInt interface{} { - ipAltInt, ok = data.GetOk("ip_sans") - if ok { - ipAlt := ipAltInt.(string) - if len(ipAlt) != 0 { - if !role.AllowIPSANs { - return nil, errutil.UserError{Err: fmt.Sprintf( - "IP Subject Alternative Names are not allowed in this role, but was provided %s", ipAlt)} - } - for _, v := range strings.Split(ipAlt, ",") { - parsedIP := net.ParseIP(v) - if parsedIP == nil { + if csr != nil && role.UseCSRSANs { + if !role.AllowIPSANs { + return nil, errutil.UserError{Err: fmt.Sprintf( + "IP Subject Alternative Names are not allowed in this role, but was provided some via CSR")} + } + ipAddresses = csr.IPAddresses + } else { + ipAltInt, ok = data.GetOk("ip_sans") + if ok { + ipAlt := ipAltInt.(string) + if len(ipAlt) != 0 { + if !role.AllowIPSANs { return nil, errutil.UserError{Err: fmt.Sprintf( - "the value '%s' is not a valid IP address", v)} + "IP Subject Alternative Names are not allowed in this role, but was provided %s", ipAlt)} + } + for _, v := range strings.Split(ipAlt, ",") { + parsedIP := net.ParseIP(v) + if parsedIP == nil { + return nil, errutil.UserError{Err: fmt.Sprintf( + "the value '%s' is not a valid IP address", v)} + } + ipAddresses = append(ipAddresses, parsedIP) } - ipAddresses = append(ipAddresses, parsedIP) } } } diff --git a/builtin/logical/pki/path_issue_sign.go b/builtin/logical/pki/path_issue_sign.go index fc96997f25..803ef7f385 100644 --- a/builtin/logical/pki/path_issue_sign.go +++ b/builtin/logical/pki/path_issue_sign.go @@ -125,6 +125,7 @@ func (b *backend) pathSignVerbatim( EnforceHostnames: false, KeyType: "any", UseCSRCommonName: true, + UseCSRSANs: true, } return b.pathIssueSignCert(req, data, role, true, true) diff --git a/builtin/logical/pki/path_roles.go b/builtin/logical/pki/path_roles.go index 656cc92b03..0eadc6ff29 100644 --- a/builtin/logical/pki/path_roles.go +++ b/builtin/logical/pki/path_roles.go @@ -169,6 +169,14 @@ does *not* include any requested Subject Alternative Names. Defaults to true.`, }, + "use_csr_sans": &framework.FieldSchema{ + Type: framework.TypeBool, + Default: true, + Description: `If set, when used with a signing profile, +the SANs in the CSR will be used. This does *not* +include the Common Name (cn). Defaults to true.`, + }, + "ou": &framework.FieldSchema{ Type: framework.TypeString, Default: "", @@ -371,6 +379,7 @@ func (b *backend) pathRoleCreate( KeyType: data.Get("key_type").(string), KeyBits: data.Get("key_bits").(int), UseCSRCommonName: data.Get("use_csr_common_name").(bool), + UseCSRSANs: data.Get("use_csr_sans").(bool), KeyUsage: data.Get("key_usage").(string), OU: data.Get("ou").(string), Organization: data.Get("organization").(string), @@ -487,6 +496,7 @@ type roleEntry struct { CodeSigningFlag bool `json:"code_signing_flag" structs:"code_signing_flag" mapstructure:"code_signing_flag"` EmailProtectionFlag bool `json:"email_protection_flag" structs:"email_protection_flag" mapstructure:"email_protection_flag"` UseCSRCommonName bool `json:"use_csr_common_name" structs:"use_csr_common_name" mapstructure:"use_csr_common_name"` + UseCSRSANs bool `json:"use_csr_sans" structs:"use_csr_sans" mapstructure:"use_csr_sans"` KeyType string `json:"key_type" structs:"key_type" mapstructure:"key_type"` KeyBits int `json:"key_bits" structs:"key_bits" mapstructure:"key_bits"` MaxPathLength *int `json:",omitempty" structs:"max_path_length,omitempty" mapstructure:"max_path_length"` diff --git a/website/source/docs/secrets/pki/index.html.md b/website/source/docs/secrets/pki/index.html.md index 87d5a89aef..bc1f0a2d40 100644 --- a/website/source/docs/secrets/pki/index.html.md +++ b/website/source/docs/secrets/pki/index.html.md @@ -1221,7 +1221,24 @@ subpath for interactive help output. optional If set, when used with the CSR signing endpoint, the common name in the CSR will be used instead of taken from the JSON data. This does `not` - include any requested SANs in the CSR. Defaults to `false`. + include any requested SANs in the CSR; use `use_csr_sans` for that. + Defaults to `true`. + +
  • + use_csr_sans + optional + If set, when used with the CSR signing endpoint, the subject alternate + names in the CSR will be used instead of taken from the JSON data. This + does `not` include the common name in the CSR; use + `use_csr_common_name` for that. Defaults to `true`. +
  • +
  • + allow_token_displayname + optional + If set, the display name of the token used when requesting a + certificate will be considered to be a valid host name by the role. + Normal verification behavior applies with respect to subdomains and + wildcards.
  • ou