2015-05-15 16:13:05 +00:00
package pki
import (
2018-01-19 06:44:44 +00:00
"context"
2017-11-06 17:05:07 +00:00
"crypto"
2016-02-19 23:50:51 +00:00
"crypto/ecdsa"
2021-10-05 15:28:49 +00:00
"crypto/ed25519"
2016-02-18 22:55:47 +00:00
"crypto/rsa"
2015-05-15 16:13:05 +00:00
"crypto/x509"
"crypto/x509/pkix"
2015-11-18 15:16:09 +00:00
"encoding/asn1"
2017-11-06 17:05:07 +00:00
"encoding/base64"
2015-09-30 01:48:31 +00:00
"encoding/pem"
2015-05-15 16:13:05 +00:00
"fmt"
2021-09-15 16:59:12 +00:00
"io"
2015-05-15 16:13:05 +00:00
"net"
2018-06-15 19:32:25 +00:00
"net/url"
2015-05-15 16:13:05 +00:00
"regexp"
2019-12-11 15:16:44 +00:00
"strconv"
2015-05-15 16:13:05 +00:00
"strings"
"time"
2021-07-16 00:17:31 +00:00
"github.com/hashicorp/go-secure-stdlib/strutil"
2019-04-13 07:44:06 +00:00
"github.com/hashicorp/vault/sdk/framework"
2019-04-12 21:54:35 +00:00
"github.com/hashicorp/vault/sdk/helper/certutil"
"github.com/hashicorp/vault/sdk/helper/errutil"
"github.com/hashicorp/vault/sdk/logical"
2019-05-09 15:43:11 +00:00
"github.com/ryanuber/go-glob"
2019-12-11 15:16:44 +00:00
"golang.org/x/crypto/cryptobyte"
cbbasn1 "golang.org/x/crypto/cryptobyte/asn1"
2018-02-10 15:07:10 +00:00
"golang.org/x/net/idna"
2015-05-15 16:13:05 +00:00
)
2019-05-09 15:43:11 +00:00
type inputBundle struct {
role * roleEntry
req * logical . Request
apiData * framework . FieldData
2016-09-28 00:50:17 +00:00
}
2015-11-18 15:16:09 +00:00
var (
Add role parameter to restrict issuance of wildcard certificates (#14238)
* Add new AllowWildcardCertificate field to PKI role
This field allows the PKI role to control whether or not issuance of
wildcard certificates are allowed. We default (both on migration and
new role creation) to the less secure true value for backwards
compatibility with existing Vault versions.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Refactor sanitizedName to reducedName
Per comment, this variable name was confusing during the reproduction
and subsequent fix of the earlier vulnerability and associated bug
report. Because the common name isn't necessarily _sanitized_ in any way
(and indeed must be considered in relation to other parts or the whole),
but portions of the entire name are removed, reducedName appears to make
the most sense.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Enforce AllowWildcardCertificates during issuance
This commit adds the bulk of correctly validating wildcard certificate
Common Names during issuance according to RFC 6125 Section 6.4.3
semantics. As part of this, support for RFC 2818-conforming wildcard
certificates (wherein there are almost no restrictions on issuance) has
been removed.
Note that this flag does take precedence over AllowAnyName, giving a
little more safety in wildcard issuance in this case.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Update test cases to conform with RFC 6125
Test cases 19, 70+71, and 83+84 didn't conform with the RFC 6125, and so
should've been rejected under strict conformance. For 70+71 and 83+84,
we previously conditioned around the value of AllowSubdomains (allowing
issuance when true), but they likely should've been rejected either way.
Additionally, update the notes about globs matching wildcard
certificates to notate this is indeed the case.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Check AllowWildcardCertifciates in issuance tests
This allows for regression tests to cover the new
AllowWildcardCertificate conditional. We add additional test cases
ensuring that wildcard issuance is properly forbidden in all relevant
scenarios, while allowing the existing test cases to validate that
wildcard status doesn't affect non-wildcard certificates.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add Wildcard allowance during signing operations
When using sign-verbatim, sign-intermediate, or getting certificate
generation parameters, set AllowWildcardCertificates to mirror existing
policies.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add changelog entry
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
2022-02-24 13:41:56 +00:00
// labelRegex is a single label from a valid domain name and was extracted
// from hostnameRegex below for use in leftWildLabelRegex, without any
// label separators (`.`).
labelRegex = ` ([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9]) `
2018-02-10 15:07:10 +00:00
// 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.
Add role parameter to restrict issuance of wildcard certificates (#14238)
* Add new AllowWildcardCertificate field to PKI role
This field allows the PKI role to control whether or not issuance of
wildcard certificates are allowed. We default (both on migration and
new role creation) to the less secure true value for backwards
compatibility with existing Vault versions.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Refactor sanitizedName to reducedName
Per comment, this variable name was confusing during the reproduction
and subsequent fix of the earlier vulnerability and associated bug
report. Because the common name isn't necessarily _sanitized_ in any way
(and indeed must be considered in relation to other parts or the whole),
but portions of the entire name are removed, reducedName appears to make
the most sense.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Enforce AllowWildcardCertificates during issuance
This commit adds the bulk of correctly validating wildcard certificate
Common Names during issuance according to RFC 6125 Section 6.4.3
semantics. As part of this, support for RFC 2818-conforming wildcard
certificates (wherein there are almost no restrictions on issuance) has
been removed.
Note that this flag does take precedence over AllowAnyName, giving a
little more safety in wildcard issuance in this case.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Update test cases to conform with RFC 6125
Test cases 19, 70+71, and 83+84 didn't conform with the RFC 6125, and so
should've been rejected under strict conformance. For 70+71 and 83+84,
we previously conditioned around the value of AllowSubdomains (allowing
issuance when true), but they likely should've been rejected either way.
Additionally, update the notes about globs matching wildcard
certificates to notate this is indeed the case.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Check AllowWildcardCertifciates in issuance tests
This allows for regression tests to cover the new
AllowWildcardCertificate conditional. We add additional test cases
ensuring that wildcard issuance is properly forbidden in all relevant
scenarios, while allowing the existing test cases to validate that
wildcard status doesn't affect non-wildcard certificates.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add Wildcard allowance during signing operations
When using sign-verbatim, sign-intermediate, or getting certificate
generation parameters, set AllowWildcardCertificates to mirror existing
policies.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add changelog entry
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
2022-02-24 13:41:56 +00:00
hostnameRegex = regexp . MustCompile ( ` ^(\*\.)?( ` + labelRegex + ` \.)* ` + labelRegex + ` \.?$ ` )
// Left Wildcard Label Regex is equivalent to a single domain label
// component from hostnameRegex above, but with additional wildcard
// characters added. There are four possibilities here:
//
// 1. Entire label is a wildcard,
// 2. Wildcard exists at the start,
// 3. Wildcard exists at the end,
// 4. Wildcard exists in the middle.
allWildRegex = ` \* `
startWildRegex = ` \* ` + labelRegex
endWildRegex = labelRegex + ` \* `
middleWildRegex = labelRegex + ` \* ` + labelRegex
leftWildLabelRegex = regexp . MustCompile ( ` ^( ` + allWildRegex + ` | ` + startWildRegex + ` | ` + endWildRegex + ` | ` + middleWildRegex + ` )$ ` )
// OIDs for X.509 certificate extensions used below.
2019-12-11 15:16:44 +00:00
oidExtensionBasicConstraints = [ ] int { 2 , 5 , 29 , 19 }
oidExtensionSubjectAltName = [ ] int { 2 , 5 , 29 , 17 }
2015-11-18 15:16:09 +00:00
)
func oidInExtensions ( oid asn1 . ObjectIdentifier , extensions [ ] pkix . Extension ) bool {
for _ , e := range extensions {
if e . Id . Equal ( oid ) {
return true
}
}
return false
}
2015-11-16 16:42:06 +00:00
2015-11-16 21:32:49 +00:00
func getFormat ( data * framework . FieldData ) string {
format := data . Get ( "format" ) . ( string )
switch format {
case "pem" :
case "der" :
2016-02-01 18:19:41 +00:00
case "pem_bundle" :
2015-11-16 21:32:49 +00:00
default :
format = ""
}
return format
}
2015-06-19 16:48:18 +00:00
// Fetches the CA info. Unlike other certificates, the CA info is stored
// in the backend as a CertBundle, because we are storing its private key
2022-01-27 04:06:25 +00:00
func fetchCAInfo ( ctx context . Context , b * backend , req * logical . Request ) ( * certutil . CAInfoBundle , error ) {
2018-01-19 06:44:44 +00:00
bundleEntry , err := req . Storage . Get ( ctx , "config/ca_bundle" )
2015-05-15 16:13:05 +00:00
if err != nil {
2016-07-28 19:19:27 +00:00
return nil , errutil . InternalError { Err : fmt . Sprintf ( "unable to fetch local CA certificate/key: %v" , err ) }
2015-05-15 16:13:05 +00:00
}
2015-06-19 16:48:18 +00:00
if bundleEntry == nil {
2016-07-28 19:19:27 +00:00
return nil , errutil . UserError { Err : "backend must be configured with a CA certificate/key" }
2015-05-15 16:13:05 +00:00
}
2015-06-19 16:48:18 +00:00
var bundle certutil . CertBundle
if err := bundleEntry . DecodeJSON ( & bundle ) ; err != nil {
2016-07-28 19:19:27 +00:00
return nil , errutil . InternalError { Err : fmt . Sprintf ( "unable to decode local CA certificate/key: %v" , err ) }
2015-05-15 16:13:05 +00:00
}
2022-01-27 04:06:25 +00:00
parsedBundle , err := parseCABundle ( ctx , b , req , & bundle )
2015-05-15 16:13:05 +00:00
if err != nil {
2016-07-28 19:19:27 +00:00
return nil , errutil . InternalError { Err : err . Error ( ) }
2015-05-15 16:13:05 +00:00
}
2015-06-19 16:48:18 +00:00
if parsedBundle . Certificate == nil {
2016-07-28 19:19:27 +00:00
return nil , errutil . InternalError { Err : "stored CA information not able to be parsed" }
2015-05-15 16:13:05 +00:00
}
2022-03-23 19:19:56 +00:00
caInfo := & certutil . CAInfoBundle { ParsedCertBundle : * parsedBundle , URLs : nil }
2015-10-09 17:45:17 +00:00
2018-01-19 06:44:44 +00:00
entries , err := getURLs ( ctx , req )
2015-10-09 17:45:17 +00:00
if err != nil {
2016-07-28 19:19:27 +00:00
return nil , errutil . InternalError { Err : fmt . Sprintf ( "unable to fetch URL information: %v" , err ) }
2015-10-09 17:45:17 +00:00
}
2015-10-14 01:13:40 +00:00
if entries == nil {
2019-05-09 15:43:11 +00:00
entries = & certutil . URLEntries {
2015-10-14 18:48:51 +00:00
IssuingCertificates : [ ] string { } ,
CRLDistributionPoints : [ ] string { } ,
OCSPServers : [ ] string { } ,
2015-10-14 01:13:40 +00:00
}
2015-10-09 17:45:17 +00:00
}
2015-10-14 01:13:40 +00:00
caInfo . URLs = entries
2015-10-09 17:45:17 +00:00
return caInfo , nil
2015-05-15 16:13:05 +00:00
}
2015-06-19 16:48:18 +00:00
// Allows fetching certificates from the backend; it handles the slightly
// separate pathing for CA, CRL, and revoked certificates.
2018-01-19 06:44:44 +00:00
func fetchCertBySerial ( ctx context . Context , req * logical . Request , prefix , serial string ) ( * logical . StorageEntry , error ) {
2017-05-03 18:58:22 +00:00
var path , legacyPath string
2017-04-06 21:00:50 +00:00
var err error
var certEntry * logical . StorageEntry
2015-06-19 16:48:18 +00:00
2017-05-03 14:12:58 +00:00
hyphenSerial := normalizeSerial ( serial )
2017-05-02 18:11:57 +00:00
colonSerial := strings . Replace ( strings . ToLower ( serial ) , "-" , ":" , - 1 )
2015-06-19 16:48:18 +00:00
2015-05-15 16:13:05 +00:00
switch {
2016-03-07 15:57:38 +00:00
// Revoked goes first as otherwise ca/crl get hardcoded paths which fail if
// we actually want revocation info
case strings . HasPrefix ( prefix , "revoked/" ) :
2017-05-03 18:58:22 +00:00
legacyPath = "revoked/" + colonSerial
2017-05-02 18:11:57 +00:00
path = "revoked/" + hyphenSerial
2015-05-15 16:13:05 +00:00
case serial == "ca" :
path = "ca"
case serial == "crl" :
path = "crl"
default :
2017-05-03 18:58:22 +00:00
legacyPath = "certs/" + colonSerial
2017-05-02 18:11:57 +00:00
path = "certs/" + hyphenSerial
2015-05-15 16:13:05 +00:00
}
2018-01-19 06:44:44 +00:00
certEntry , err = req . Storage . Get ( ctx , path )
2016-02-22 15:36:26 +00:00
if err != nil {
2016-07-28 19:19:27 +00:00
return nil , errutil . InternalError { Err : fmt . Sprintf ( "error fetching certificate %s: %s" , serial , err ) }
2016-02-22 15:36:26 +00:00
}
2017-04-06 21:00:50 +00:00
if certEntry != nil {
if certEntry . Value == nil || len ( certEntry . Value ) == 0 {
return nil , errutil . InternalError { Err : fmt . Sprintf ( "returned certificate bytes for serial %s were empty" , serial ) }
}
return certEntry , nil
}
2017-05-03 20:13:54 +00:00
// If legacyPath is unset, it's going to be a CA or CRL; return immediately
2017-05-03 18:58:22 +00:00
if legacyPath == "" {
2016-02-22 15:36:26 +00:00
return nil , nil
2015-05-15 16:13:05 +00:00
}
2019-01-09 02:08:21 +00:00
// Retrieve the old-style path. We disregard errors here because they
// always manifest on windows, and thus the initial check for a revoked
// cert fails would return an error when the cert isn't revoked, preventing
// the happy path from working.
certEntry , _ = req . Storage . Get ( ctx , legacyPath )
2016-02-22 15:36:26 +00:00
if certEntry == nil {
return nil , nil
2015-05-15 16:13:05 +00:00
}
2015-06-19 16:48:18 +00:00
if certEntry . Value == nil || len ( certEntry . Value ) == 0 {
2016-07-28 19:19:27 +00:00
return nil , errutil . InternalError { Err : fmt . Sprintf ( "returned certificate bytes for serial %s were empty" , serial ) }
2015-05-15 16:13:05 +00:00
}
2017-04-27 21:09:59 +00:00
// Update old-style paths to new-style paths
2017-05-03 18:58:22 +00:00
certEntry . Key = path
2018-01-19 06:44:44 +00:00
if err = req . Storage . Put ( ctx , certEntry ) ; err != nil {
2017-04-06 21:00:50 +00:00
return nil , errutil . InternalError { Err : fmt . Sprintf ( "error saving certificate with serial %s to new location" , serial ) }
}
2018-01-19 06:44:44 +00:00
if err = req . Storage . Delete ( ctx , legacyPath ) ; err != nil {
2017-04-06 21:00:50 +00:00
return nil , errutil . InternalError { Err : fmt . Sprintf ( "error deleting certificate with serial %s from old location" , serial ) }
}
2015-06-19 16:48:18 +00:00
return certEntry , nil
2015-05-15 16:13:05 +00:00
}
2021-12-15 15:18:28 +00:00
// Given a URI SAN, verify that it is allowed.
func validateURISAN ( b * backend , data * inputBundle , uri string ) bool {
valid := false
for _ , allowed := range data . role . AllowedURISANs {
if data . role . AllowedURISANsTemplate {
isTemplate , _ := framework . ValidateIdentityTemplate ( allowed )
if isTemplate && data . req . EntityID != "" {
tmpAllowed , err := framework . PopulateIdentityTemplate ( allowed , data . req . EntityID , b . System ( ) )
if err != nil {
continue
}
allowed = tmpAllowed
}
}
validURI := glob . Glob ( allowed , uri )
if validURI {
valid = true
break
}
}
return valid
}
2015-06-19 16:48:18 +00:00
// Given a set of requested names for a certificate, verifies that all of them
// match the various toggles set in the role for controlling issuance.
// If one does not pass, it is returned in the string argument.
2020-07-08 16:52:25 +00:00
func validateNames ( b * backend , data * inputBundle , names [ ] string ) string {
2015-10-02 18:27:30 +00:00
for _ , name := range names {
Add role parameter to restrict issuance of wildcard certificates (#14238)
* Add new AllowWildcardCertificate field to PKI role
This field allows the PKI role to control whether or not issuance of
wildcard certificates are allowed. We default (both on migration and
new role creation) to the less secure true value for backwards
compatibility with existing Vault versions.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Refactor sanitizedName to reducedName
Per comment, this variable name was confusing during the reproduction
and subsequent fix of the earlier vulnerability and associated bug
report. Because the common name isn't necessarily _sanitized_ in any way
(and indeed must be considered in relation to other parts or the whole),
but portions of the entire name are removed, reducedName appears to make
the most sense.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Enforce AllowWildcardCertificates during issuance
This commit adds the bulk of correctly validating wildcard certificate
Common Names during issuance according to RFC 6125 Section 6.4.3
semantics. As part of this, support for RFC 2818-conforming wildcard
certificates (wherein there are almost no restrictions on issuance) has
been removed.
Note that this flag does take precedence over AllowAnyName, giving a
little more safety in wildcard issuance in this case.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Update test cases to conform with RFC 6125
Test cases 19, 70+71, and 83+84 didn't conform with the RFC 6125, and so
should've been rejected under strict conformance. For 70+71 and 83+84,
we previously conditioned around the value of AllowSubdomains (allowing
issuance when true), but they likely should've been rejected either way.
Additionally, update the notes about globs matching wildcard
certificates to notate this is indeed the case.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Check AllowWildcardCertifciates in issuance tests
This allows for regression tests to cover the new
AllowWildcardCertificate conditional. We add additional test cases
ensuring that wildcard issuance is properly forbidden in all relevant
scenarios, while allowing the existing test cases to validate that
wildcard status doesn't affect non-wildcard certificates.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add Wildcard allowance during signing operations
When using sign-verbatim, sign-intermediate, or getting certificate
generation parameters, set AllowWildcardCertificates to mirror existing
policies.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add changelog entry
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
2022-02-24 13:41:56 +00:00
// Previously, reducedName was called sanitizedName but this made
// little sense under the previous interpretation of wildcards,
// leading to two bugs in this implementation. We presently call it
// "reduced" to indicate that it is still untrusted input (potentially
// different from the bare Common Name entry we're validating), it
// might have been modified such as by the removal of wildcard labels
// or the email prefix.
reducedName := name
emailDomain := reducedName
wildcardLabel := ""
2015-10-02 18:27:30 +00:00
isEmail := false
2015-05-15 16:13:05 +00:00
isWildcard := false
2015-11-23 19:15:32 +00:00
// If it has an @, assume it is an email address and separate out the
// user from the hostname portion so that we can act on the hostname.
// Note that this matches behavior from the alt_names parameter. If it
// ends up being problematic for users, I guess that could be separated
// into dns_names and email_names in the future to be explicit, but I
// don't think this is likely.
Add role parameter to restrict issuance of wildcard certificates (#14238)
* Add new AllowWildcardCertificate field to PKI role
This field allows the PKI role to control whether or not issuance of
wildcard certificates are allowed. We default (both on migration and
new role creation) to the less secure true value for backwards
compatibility with existing Vault versions.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Refactor sanitizedName to reducedName
Per comment, this variable name was confusing during the reproduction
and subsequent fix of the earlier vulnerability and associated bug
report. Because the common name isn't necessarily _sanitized_ in any way
(and indeed must be considered in relation to other parts or the whole),
but portions of the entire name are removed, reducedName appears to make
the most sense.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Enforce AllowWildcardCertificates during issuance
This commit adds the bulk of correctly validating wildcard certificate
Common Names during issuance according to RFC 6125 Section 6.4.3
semantics. As part of this, support for RFC 2818-conforming wildcard
certificates (wherein there are almost no restrictions on issuance) has
been removed.
Note that this flag does take precedence over AllowAnyName, giving a
little more safety in wildcard issuance in this case.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Update test cases to conform with RFC 6125
Test cases 19, 70+71, and 83+84 didn't conform with the RFC 6125, and so
should've been rejected under strict conformance. For 70+71 and 83+84,
we previously conditioned around the value of AllowSubdomains (allowing
issuance when true), but they likely should've been rejected either way.
Additionally, update the notes about globs matching wildcard
certificates to notate this is indeed the case.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Check AllowWildcardCertifciates in issuance tests
This allows for regression tests to cover the new
AllowWildcardCertificate conditional. We add additional test cases
ensuring that wildcard issuance is properly forbidden in all relevant
scenarios, while allowing the existing test cases to validate that
wildcard status doesn't affect non-wildcard certificates.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add Wildcard allowance during signing operations
When using sign-verbatim, sign-intermediate, or getting certificate
generation parameters, set AllowWildcardCertificates to mirror existing
policies.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add changelog entry
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
2022-02-24 13:41:56 +00:00
if strings . Contains ( reducedName , "@" ) {
splitEmail := strings . Split ( reducedName , "@" )
2015-10-02 18:27:30 +00:00
if len ( splitEmail ) != 2 {
2017-03-16 15:41:00 +00:00
return name
2015-10-02 18:27:30 +00:00
}
Add role parameter to restrict issuance of wildcard certificates (#14238)
* Add new AllowWildcardCertificate field to PKI role
This field allows the PKI role to control whether or not issuance of
wildcard certificates are allowed. We default (both on migration and
new role creation) to the less secure true value for backwards
compatibility with existing Vault versions.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Refactor sanitizedName to reducedName
Per comment, this variable name was confusing during the reproduction
and subsequent fix of the earlier vulnerability and associated bug
report. Because the common name isn't necessarily _sanitized_ in any way
(and indeed must be considered in relation to other parts or the whole),
but portions of the entire name are removed, reducedName appears to make
the most sense.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Enforce AllowWildcardCertificates during issuance
This commit adds the bulk of correctly validating wildcard certificate
Common Names during issuance according to RFC 6125 Section 6.4.3
semantics. As part of this, support for RFC 2818-conforming wildcard
certificates (wherein there are almost no restrictions on issuance) has
been removed.
Note that this flag does take precedence over AllowAnyName, giving a
little more safety in wildcard issuance in this case.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Update test cases to conform with RFC 6125
Test cases 19, 70+71, and 83+84 didn't conform with the RFC 6125, and so
should've been rejected under strict conformance. For 70+71 and 83+84,
we previously conditioned around the value of AllowSubdomains (allowing
issuance when true), but they likely should've been rejected either way.
Additionally, update the notes about globs matching wildcard
certificates to notate this is indeed the case.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Check AllowWildcardCertifciates in issuance tests
This allows for regression tests to cover the new
AllowWildcardCertificate conditional. We add additional test cases
ensuring that wildcard issuance is properly forbidden in all relevant
scenarios, while allowing the existing test cases to validate that
wildcard status doesn't affect non-wildcard certificates.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add Wildcard allowance during signing operations
When using sign-verbatim, sign-intermediate, or getting certificate
generation parameters, set AllowWildcardCertificates to mirror existing
policies.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add changelog entry
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
2022-02-24 13:41:56 +00:00
reducedName = splitEmail [ 1 ]
2015-10-02 19:47:45 +00:00
emailDomain = splitEmail [ 1 ]
2015-10-02 18:27:30 +00:00
isEmail = true
}
2015-11-23 19:15:32 +00:00
Add role parameter to restrict issuance of wildcard certificates (#14238)
* Add new AllowWildcardCertificate field to PKI role
This field allows the PKI role to control whether or not issuance of
wildcard certificates are allowed. We default (both on migration and
new role creation) to the less secure true value for backwards
compatibility with existing Vault versions.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Refactor sanitizedName to reducedName
Per comment, this variable name was confusing during the reproduction
and subsequent fix of the earlier vulnerability and associated bug
report. Because the common name isn't necessarily _sanitized_ in any way
(and indeed must be considered in relation to other parts or the whole),
but portions of the entire name are removed, reducedName appears to make
the most sense.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Enforce AllowWildcardCertificates during issuance
This commit adds the bulk of correctly validating wildcard certificate
Common Names during issuance according to RFC 6125 Section 6.4.3
semantics. As part of this, support for RFC 2818-conforming wildcard
certificates (wherein there are almost no restrictions on issuance) has
been removed.
Note that this flag does take precedence over AllowAnyName, giving a
little more safety in wildcard issuance in this case.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Update test cases to conform with RFC 6125
Test cases 19, 70+71, and 83+84 didn't conform with the RFC 6125, and so
should've been rejected under strict conformance. For 70+71 and 83+84,
we previously conditioned around the value of AllowSubdomains (allowing
issuance when true), but they likely should've been rejected either way.
Additionally, update the notes about globs matching wildcard
certificates to notate this is indeed the case.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Check AllowWildcardCertifciates in issuance tests
This allows for regression tests to cover the new
AllowWildcardCertificate conditional. We add additional test cases
ensuring that wildcard issuance is properly forbidden in all relevant
scenarios, while allowing the existing test cases to validate that
wildcard status doesn't affect non-wildcard certificates.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add Wildcard allowance during signing operations
When using sign-verbatim, sign-intermediate, or getting certificate
generation parameters, set AllowWildcardCertificates to mirror existing
policies.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add changelog entry
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
2022-02-24 13:41:56 +00:00
// Per RFC 6125 Section 6.4.3, and explicitly contradicting the earlier
// RFC 2818 which no modern client will validate against, there are two
// main types of wildcards, each with a single wildcard specifier (`*`,
// functionally different from the `*` used as a glob from the
// AllowGlobDomains parsing path) in the left-most label:
//
// 1. Entire label is a single wildcard character (most common and
// well-supported),
// 2. Part of the label contains a single wildcard character (e.g. per
/// RFC 6125: baz*.example.net, *baz.example.net, or b*z.example.net).
//
// We permit issuance of both but not the older RFC 2818 style under
// the new AllowWildcardCertificates option. However, anything with a
// glob character is technically a wildcard.
if strings . Contains ( reducedName , "*" ) {
// Regardless of later rejections below, this common name contains
// a wildcard character and is thus technically a wildcard name.
2015-05-15 16:13:05 +00:00
isWildcard = true
Add role parameter to restrict issuance of wildcard certificates (#14238)
* Add new AllowWildcardCertificate field to PKI role
This field allows the PKI role to control whether or not issuance of
wildcard certificates are allowed. We default (both on migration and
new role creation) to the less secure true value for backwards
compatibility with existing Vault versions.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Refactor sanitizedName to reducedName
Per comment, this variable name was confusing during the reproduction
and subsequent fix of the earlier vulnerability and associated bug
report. Because the common name isn't necessarily _sanitized_ in any way
(and indeed must be considered in relation to other parts or the whole),
but portions of the entire name are removed, reducedName appears to make
the most sense.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Enforce AllowWildcardCertificates during issuance
This commit adds the bulk of correctly validating wildcard certificate
Common Names during issuance according to RFC 6125 Section 6.4.3
semantics. As part of this, support for RFC 2818-conforming wildcard
certificates (wherein there are almost no restrictions on issuance) has
been removed.
Note that this flag does take precedence over AllowAnyName, giving a
little more safety in wildcard issuance in this case.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Update test cases to conform with RFC 6125
Test cases 19, 70+71, and 83+84 didn't conform with the RFC 6125, and so
should've been rejected under strict conformance. For 70+71 and 83+84,
we previously conditioned around the value of AllowSubdomains (allowing
issuance when true), but they likely should've been rejected either way.
Additionally, update the notes about globs matching wildcard
certificates to notate this is indeed the case.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Check AllowWildcardCertifciates in issuance tests
This allows for regression tests to cover the new
AllowWildcardCertificate conditional. We add additional test cases
ensuring that wildcard issuance is properly forbidden in all relevant
scenarios, while allowing the existing test cases to validate that
wildcard status doesn't affect non-wildcard certificates.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add Wildcard allowance during signing operations
When using sign-verbatim, sign-intermediate, or getting certificate
generation parameters, set AllowWildcardCertificates to mirror existing
policies.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add changelog entry
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
2022-02-24 13:41:56 +00:00
// Additionally, if AllowWildcardCertificates is explicitly
// forbidden, it takes precedence over AllowAnyName, thus we should
// reject the name now.
//
// We expect the role to have been correctly migrated but guard for
// safety.
if data . role . AllowWildcardCertificates != nil && ! * data . role . AllowWildcardCertificates {
return name
}
if strings . Count ( reducedName , "*" ) > 1 {
// As mentioned above, only one wildcard character is permitted
// under RFC 6125 semantics.
return name
}
// Split the Common Name into two parts: a left-most label and the
// remaining segments (if present).
splitLabels := strings . SplitN ( reducedName , "." , 2 )
if len ( splitLabels ) != 2 {
// We've been given a single-part domain name that consists
// entirely of a wildcard. This is a little tricky to handle,
// but EnforceHostnames validates both the wildcard-containing
// label and the reduced name, but _only_ the latter if it is
// non-empty. This allows us to still validate the only label
// component matches hostname expectations still.
wildcardLabel = splitLabels [ 0 ]
reducedName = ""
} else {
// We have a (at least) two label domain name. But before we can
// update our names, we need to validate the wildcard ended up
// in the segment we expected it to. While this is (kinda)
// validated under EnforceHostnames's leftWildLabelRegex, we
// still need to validate it in the non-enforced mode.
//
// By validated assumption above, we know there's strictly one
// wildcard in this domain so we only need to check the wildcard
// label or the reduced name (as one is equivalent to the other).
// Because we later assume reducedName _lacks_ wildcard segments,
// we validate that.
wildcardLabel = splitLabels [ 0 ]
reducedName = splitLabels [ 1 ]
if strings . Contains ( reducedName , "*" ) {
return name
}
}
2015-05-15 16:13:05 +00:00
}
2015-08-20 21:33:37 +00:00
2015-11-23 19:15:32 +00:00
// Email addresses using wildcard domain names do not make sense
Add role parameter to restrict issuance of wildcard certificates (#14238)
* Add new AllowWildcardCertificate field to PKI role
This field allows the PKI role to control whether or not issuance of
wildcard certificates are allowed. We default (both on migration and
new role creation) to the less secure true value for backwards
compatibility with existing Vault versions.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Refactor sanitizedName to reducedName
Per comment, this variable name was confusing during the reproduction
and subsequent fix of the earlier vulnerability and associated bug
report. Because the common name isn't necessarily _sanitized_ in any way
(and indeed must be considered in relation to other parts or the whole),
but portions of the entire name are removed, reducedName appears to make
the most sense.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Enforce AllowWildcardCertificates during issuance
This commit adds the bulk of correctly validating wildcard certificate
Common Names during issuance according to RFC 6125 Section 6.4.3
semantics. As part of this, support for RFC 2818-conforming wildcard
certificates (wherein there are almost no restrictions on issuance) has
been removed.
Note that this flag does take precedence over AllowAnyName, giving a
little more safety in wildcard issuance in this case.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Update test cases to conform with RFC 6125
Test cases 19, 70+71, and 83+84 didn't conform with the RFC 6125, and so
should've been rejected under strict conformance. For 70+71 and 83+84,
we previously conditioned around the value of AllowSubdomains (allowing
issuance when true), but they likely should've been rejected either way.
Additionally, update the notes about globs matching wildcard
certificates to notate this is indeed the case.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Check AllowWildcardCertifciates in issuance tests
This allows for regression tests to cover the new
AllowWildcardCertificate conditional. We add additional test cases
ensuring that wildcard issuance is properly forbidden in all relevant
scenarios, while allowing the existing test cases to validate that
wildcard status doesn't affect non-wildcard certificates.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add Wildcard allowance during signing operations
When using sign-verbatim, sign-intermediate, or getting certificate
generation parameters, set AllowWildcardCertificates to mirror existing
policies.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add changelog entry
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
2022-02-24 13:41:56 +00:00
// in a Common Name field.
2015-11-23 19:15:32 +00:00
if isEmail && isWildcard {
2017-03-16 15:41:00 +00:00
return name
2015-11-23 19:15:32 +00:00
}
// AllowAnyName is checked after this because EnforceHostnames still
Add role parameter to restrict issuance of wildcard certificates (#14238)
* Add new AllowWildcardCertificate field to PKI role
This field allows the PKI role to control whether or not issuance of
wildcard certificates are allowed. We default (both on migration and
new role creation) to the less secure true value for backwards
compatibility with existing Vault versions.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Refactor sanitizedName to reducedName
Per comment, this variable name was confusing during the reproduction
and subsequent fix of the earlier vulnerability and associated bug
report. Because the common name isn't necessarily _sanitized_ in any way
(and indeed must be considered in relation to other parts or the whole),
but portions of the entire name are removed, reducedName appears to make
the most sense.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Enforce AllowWildcardCertificates during issuance
This commit adds the bulk of correctly validating wildcard certificate
Common Names during issuance according to RFC 6125 Section 6.4.3
semantics. As part of this, support for RFC 2818-conforming wildcard
certificates (wherein there are almost no restrictions on issuance) has
been removed.
Note that this flag does take precedence over AllowAnyName, giving a
little more safety in wildcard issuance in this case.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Update test cases to conform with RFC 6125
Test cases 19, 70+71, and 83+84 didn't conform with the RFC 6125, and so
should've been rejected under strict conformance. For 70+71 and 83+84,
we previously conditioned around the value of AllowSubdomains (allowing
issuance when true), but they likely should've been rejected either way.
Additionally, update the notes about globs matching wildcard
certificates to notate this is indeed the case.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Check AllowWildcardCertifciates in issuance tests
This allows for regression tests to cover the new
AllowWildcardCertificate conditional. We add additional test cases
ensuring that wildcard issuance is properly forbidden in all relevant
scenarios, while allowing the existing test cases to validate that
wildcard status doesn't affect non-wildcard certificates.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add Wildcard allowance during signing operations
When using sign-verbatim, sign-intermediate, or getting certificate
generation parameters, set AllowWildcardCertificates to mirror existing
policies.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add changelog entry
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
2022-02-24 13:41:56 +00:00
// applies when allowing any name. Also, we check the reduced name to
2015-11-23 19:15:32 +00:00
// ensure that we are not either checking a full email address or a
// wildcard prefix.
2018-02-16 22:19:34 +00:00
if data . role . EnforceHostnames {
Add role parameter to restrict issuance of wildcard certificates (#14238)
* Add new AllowWildcardCertificate field to PKI role
This field allows the PKI role to control whether or not issuance of
wildcard certificates are allowed. We default (both on migration and
new role creation) to the less secure true value for backwards
compatibility with existing Vault versions.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Refactor sanitizedName to reducedName
Per comment, this variable name was confusing during the reproduction
and subsequent fix of the earlier vulnerability and associated bug
report. Because the common name isn't necessarily _sanitized_ in any way
(and indeed must be considered in relation to other parts or the whole),
but portions of the entire name are removed, reducedName appears to make
the most sense.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Enforce AllowWildcardCertificates during issuance
This commit adds the bulk of correctly validating wildcard certificate
Common Names during issuance according to RFC 6125 Section 6.4.3
semantics. As part of this, support for RFC 2818-conforming wildcard
certificates (wherein there are almost no restrictions on issuance) has
been removed.
Note that this flag does take precedence over AllowAnyName, giving a
little more safety in wildcard issuance in this case.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Update test cases to conform with RFC 6125
Test cases 19, 70+71, and 83+84 didn't conform with the RFC 6125, and so
should've been rejected under strict conformance. For 70+71 and 83+84,
we previously conditioned around the value of AllowSubdomains (allowing
issuance when true), but they likely should've been rejected either way.
Additionally, update the notes about globs matching wildcard
certificates to notate this is indeed the case.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Check AllowWildcardCertifciates in issuance tests
This allows for regression tests to cover the new
AllowWildcardCertificate conditional. We add additional test cases
ensuring that wildcard issuance is properly forbidden in all relevant
scenarios, while allowing the existing test cases to validate that
wildcard status doesn't affect non-wildcard certificates.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add Wildcard allowance during signing operations
When using sign-verbatim, sign-intermediate, or getting certificate
generation parameters, set AllowWildcardCertificates to mirror existing
policies.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add changelog entry
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
2022-02-24 13:41:56 +00:00
if reducedName != "" {
// See note above about splitLabels having only one segment
// and setting reducedName to the empty string.
p := idna . New (
idna . StrictDomainName ( true ) ,
idna . VerifyDNSLength ( true ) ,
)
converted , err := p . ToASCII ( reducedName )
if err != nil {
return name
}
if ! hostnameRegex . MatchString ( converted ) {
return name
}
2018-02-10 15:07:10 +00:00
}
Add role parameter to restrict issuance of wildcard certificates (#14238)
* Add new AllowWildcardCertificate field to PKI role
This field allows the PKI role to control whether or not issuance of
wildcard certificates are allowed. We default (both on migration and
new role creation) to the less secure true value for backwards
compatibility with existing Vault versions.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Refactor sanitizedName to reducedName
Per comment, this variable name was confusing during the reproduction
and subsequent fix of the earlier vulnerability and associated bug
report. Because the common name isn't necessarily _sanitized_ in any way
(and indeed must be considered in relation to other parts or the whole),
but portions of the entire name are removed, reducedName appears to make
the most sense.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Enforce AllowWildcardCertificates during issuance
This commit adds the bulk of correctly validating wildcard certificate
Common Names during issuance according to RFC 6125 Section 6.4.3
semantics. As part of this, support for RFC 2818-conforming wildcard
certificates (wherein there are almost no restrictions on issuance) has
been removed.
Note that this flag does take precedence over AllowAnyName, giving a
little more safety in wildcard issuance in this case.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Update test cases to conform with RFC 6125
Test cases 19, 70+71, and 83+84 didn't conform with the RFC 6125, and so
should've been rejected under strict conformance. For 70+71 and 83+84,
we previously conditioned around the value of AllowSubdomains (allowing
issuance when true), but they likely should've been rejected either way.
Additionally, update the notes about globs matching wildcard
certificates to notate this is indeed the case.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Check AllowWildcardCertifciates in issuance tests
This allows for regression tests to cover the new
AllowWildcardCertificate conditional. We add additional test cases
ensuring that wildcard issuance is properly forbidden in all relevant
scenarios, while allowing the existing test cases to validate that
wildcard status doesn't affect non-wildcard certificates.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add Wildcard allowance during signing operations
When using sign-verbatim, sign-intermediate, or getting certificate
generation parameters, set AllowWildcardCertificates to mirror existing
policies.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add changelog entry
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
2022-02-24 13:41:56 +00:00
// When a wildcard is specified, we additionally need to validate
// the label with the wildcard is correctly formed.
if isWildcard && ! leftWildLabelRegex . MatchString ( wildcardLabel ) {
2017-03-16 15:41:00 +00:00
return name
2015-08-20 21:33:37 +00:00
}
2015-10-14 15:26:56 +00:00
}
Add role parameter to restrict issuance of wildcard certificates (#14238)
* Add new AllowWildcardCertificate field to PKI role
This field allows the PKI role to control whether or not issuance of
wildcard certificates are allowed. We default (both on migration and
new role creation) to the less secure true value for backwards
compatibility with existing Vault versions.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Refactor sanitizedName to reducedName
Per comment, this variable name was confusing during the reproduction
and subsequent fix of the earlier vulnerability and associated bug
report. Because the common name isn't necessarily _sanitized_ in any way
(and indeed must be considered in relation to other parts or the whole),
but portions of the entire name are removed, reducedName appears to make
the most sense.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Enforce AllowWildcardCertificates during issuance
This commit adds the bulk of correctly validating wildcard certificate
Common Names during issuance according to RFC 6125 Section 6.4.3
semantics. As part of this, support for RFC 2818-conforming wildcard
certificates (wherein there are almost no restrictions on issuance) has
been removed.
Note that this flag does take precedence over AllowAnyName, giving a
little more safety in wildcard issuance in this case.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Update test cases to conform with RFC 6125
Test cases 19, 70+71, and 83+84 didn't conform with the RFC 6125, and so
should've been rejected under strict conformance. For 70+71 and 83+84,
we previously conditioned around the value of AllowSubdomains (allowing
issuance when true), but they likely should've been rejected either way.
Additionally, update the notes about globs matching wildcard
certificates to notate this is indeed the case.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Check AllowWildcardCertifciates in issuance tests
This allows for regression tests to cover the new
AllowWildcardCertificate conditional. We add additional test cases
ensuring that wildcard issuance is properly forbidden in all relevant
scenarios, while allowing the existing test cases to validate that
wildcard status doesn't affect non-wildcard certificates.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add Wildcard allowance during signing operations
When using sign-verbatim, sign-intermediate, or getting certificate
generation parameters, set AllowWildcardCertificates to mirror existing
policies.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add changelog entry
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
2022-02-24 13:41:56 +00:00
// Self-explanatory, but validations from EnforceHostnames and
// AllowWildcardCertificates take precedence.
2018-02-16 22:19:34 +00:00
if data . role . AllowAnyName {
2015-10-14 15:26:56 +00:00
continue
2015-05-15 16:13:05 +00:00
}
2015-08-20 21:33:37 +00:00
2015-11-23 19:15:32 +00:00
// The following blocks all work the same basic way:
// 1) If a role allows a certain class of base (localhost, token
2015-12-01 04:49:11 +00:00
// display name, role-configured domains), perform further tests
2015-11-23 19:15:32 +00:00
//
2021-03-10 05:28:27 +00:00
// 2) If there is a perfect match on either the sanitized name or it's an
2015-11-23 19:15:32 +00:00
// email address with a perfect match on the hostname portion, allow it
//
// 3) If subdomains are allowed, we check based on the sanitized name;
// note that if not a wildcard, will be equivalent to the email domain
// for email checks, and we already checked above for both a wildcard
// and email address being present in the same name
// 3a) First we check for a non-wildcard subdomain, as in <name>.<base>
// 3b) Then we check if it's a wildcard and the base domain is a match
//
// Variances are noted in-line
2018-02-16 22:19:34 +00:00
if data . role . AllowLocalhost {
Add role parameter to restrict issuance of wildcard certificates (#14238)
* Add new AllowWildcardCertificate field to PKI role
This field allows the PKI role to control whether or not issuance of
wildcard certificates are allowed. We default (both on migration and
new role creation) to the less secure true value for backwards
compatibility with existing Vault versions.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Refactor sanitizedName to reducedName
Per comment, this variable name was confusing during the reproduction
and subsequent fix of the earlier vulnerability and associated bug
report. Because the common name isn't necessarily _sanitized_ in any way
(and indeed must be considered in relation to other parts or the whole),
but portions of the entire name are removed, reducedName appears to make
the most sense.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Enforce AllowWildcardCertificates during issuance
This commit adds the bulk of correctly validating wildcard certificate
Common Names during issuance according to RFC 6125 Section 6.4.3
semantics. As part of this, support for RFC 2818-conforming wildcard
certificates (wherein there are almost no restrictions on issuance) has
been removed.
Note that this flag does take precedence over AllowAnyName, giving a
little more safety in wildcard issuance in this case.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Update test cases to conform with RFC 6125
Test cases 19, 70+71, and 83+84 didn't conform with the RFC 6125, and so
should've been rejected under strict conformance. For 70+71 and 83+84,
we previously conditioned around the value of AllowSubdomains (allowing
issuance when true), but they likely should've been rejected either way.
Additionally, update the notes about globs matching wildcard
certificates to notate this is indeed the case.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Check AllowWildcardCertifciates in issuance tests
This allows for regression tests to cover the new
AllowWildcardCertificate conditional. We add additional test cases
ensuring that wildcard issuance is properly forbidden in all relevant
scenarios, while allowing the existing test cases to validate that
wildcard status doesn't affect non-wildcard certificates.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add Wildcard allowance during signing operations
When using sign-verbatim, sign-intermediate, or getting certificate
generation parameters, set AllowWildcardCertificates to mirror existing
policies.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add changelog entry
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
2022-02-24 13:41:56 +00:00
if reducedName == "localhost" ||
reducedName == "localdomain" ||
2015-11-23 19:15:32 +00:00
( isEmail && emailDomain == "localhost" ) ||
( isEmail && emailDomain == "localdomain" ) {
2015-10-02 19:47:45 +00:00
continue
}
2018-02-16 22:19:34 +00:00
if data . role . AllowSubdomains {
2015-11-23 19:15:32 +00:00
// It is possible, if unlikely, to have a subdomain of "localhost"
Add role parameter to restrict issuance of wildcard certificates (#14238)
* Add new AllowWildcardCertificate field to PKI role
This field allows the PKI role to control whether or not issuance of
wildcard certificates are allowed. We default (both on migration and
new role creation) to the less secure true value for backwards
compatibility with existing Vault versions.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Refactor sanitizedName to reducedName
Per comment, this variable name was confusing during the reproduction
and subsequent fix of the earlier vulnerability and associated bug
report. Because the common name isn't necessarily _sanitized_ in any way
(and indeed must be considered in relation to other parts or the whole),
but portions of the entire name are removed, reducedName appears to make
the most sense.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Enforce AllowWildcardCertificates during issuance
This commit adds the bulk of correctly validating wildcard certificate
Common Names during issuance according to RFC 6125 Section 6.4.3
semantics. As part of this, support for RFC 2818-conforming wildcard
certificates (wherein there are almost no restrictions on issuance) has
been removed.
Note that this flag does take precedence over AllowAnyName, giving a
little more safety in wildcard issuance in this case.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Update test cases to conform with RFC 6125
Test cases 19, 70+71, and 83+84 didn't conform with the RFC 6125, and so
should've been rejected under strict conformance. For 70+71 and 83+84,
we previously conditioned around the value of AllowSubdomains (allowing
issuance when true), but they likely should've been rejected either way.
Additionally, update the notes about globs matching wildcard
certificates to notate this is indeed the case.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Check AllowWildcardCertifciates in issuance tests
This allows for regression tests to cover the new
AllowWildcardCertificate conditional. We add additional test cases
ensuring that wildcard issuance is properly forbidden in all relevant
scenarios, while allowing the existing test cases to validate that
wildcard status doesn't affect non-wildcard certificates.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add Wildcard allowance during signing operations
When using sign-verbatim, sign-intermediate, or getting certificate
generation parameters, set AllowWildcardCertificates to mirror existing
policies.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add changelog entry
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
2022-02-24 13:41:56 +00:00
if strings . HasSuffix ( reducedName , ".localhost" ) ||
( isWildcard && reducedName == "localhost" ) {
2015-11-23 19:15:32 +00:00
continue
2015-10-02 19:47:45 +00:00
}
2015-11-23 19:15:32 +00:00
// A subdomain of "localdomain" is also not entirely uncommon
Add role parameter to restrict issuance of wildcard certificates (#14238)
* Add new AllowWildcardCertificate field to PKI role
This field allows the PKI role to control whether or not issuance of
wildcard certificates are allowed. We default (both on migration and
new role creation) to the less secure true value for backwards
compatibility with existing Vault versions.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Refactor sanitizedName to reducedName
Per comment, this variable name was confusing during the reproduction
and subsequent fix of the earlier vulnerability and associated bug
report. Because the common name isn't necessarily _sanitized_ in any way
(and indeed must be considered in relation to other parts or the whole),
but portions of the entire name are removed, reducedName appears to make
the most sense.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Enforce AllowWildcardCertificates during issuance
This commit adds the bulk of correctly validating wildcard certificate
Common Names during issuance according to RFC 6125 Section 6.4.3
semantics. As part of this, support for RFC 2818-conforming wildcard
certificates (wherein there are almost no restrictions on issuance) has
been removed.
Note that this flag does take precedence over AllowAnyName, giving a
little more safety in wildcard issuance in this case.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Update test cases to conform with RFC 6125
Test cases 19, 70+71, and 83+84 didn't conform with the RFC 6125, and so
should've been rejected under strict conformance. For 70+71 and 83+84,
we previously conditioned around the value of AllowSubdomains (allowing
issuance when true), but they likely should've been rejected either way.
Additionally, update the notes about globs matching wildcard
certificates to notate this is indeed the case.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Check AllowWildcardCertifciates in issuance tests
This allows for regression tests to cover the new
AllowWildcardCertificate conditional. We add additional test cases
ensuring that wildcard issuance is properly forbidden in all relevant
scenarios, while allowing the existing test cases to validate that
wildcard status doesn't affect non-wildcard certificates.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add Wildcard allowance during signing operations
When using sign-verbatim, sign-intermediate, or getting certificate
generation parameters, set AllowWildcardCertificates to mirror existing
policies.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add changelog entry
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
2022-02-24 13:41:56 +00:00
if strings . HasSuffix ( reducedName , ".localdomain" ) ||
( isWildcard && reducedName == "localdomain" ) {
2015-10-02 19:47:45 +00:00
continue
}
}
}
2018-02-16 22:19:34 +00:00
if data . role . AllowTokenDisplayName {
if name == data . req . DisplayName {
2015-05-15 16:13:05 +00:00
continue
}
2018-02-16 22:19:34 +00:00
if data . role . AllowSubdomains {
2015-11-23 19:15:32 +00:00
if isEmail {
// If it's an email address, we need to parse the token
// display name in order to do a proper comparison of the
// subdomain
2018-02-16 22:19:34 +00:00
if strings . Contains ( data . req . DisplayName , "@" ) {
splitDisplay := strings . Split ( data . req . DisplayName , "@" )
2015-11-23 19:15:32 +00:00
if len ( splitDisplay ) == 2 {
// Compare the sanitized name against the hostname
2018-03-20 18:54:10 +00:00
// portion of the email address in the broken
2015-11-23 19:15:32 +00:00
// display name
Add role parameter to restrict issuance of wildcard certificates (#14238)
* Add new AllowWildcardCertificate field to PKI role
This field allows the PKI role to control whether or not issuance of
wildcard certificates are allowed. We default (both on migration and
new role creation) to the less secure true value for backwards
compatibility with existing Vault versions.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Refactor sanitizedName to reducedName
Per comment, this variable name was confusing during the reproduction
and subsequent fix of the earlier vulnerability and associated bug
report. Because the common name isn't necessarily _sanitized_ in any way
(and indeed must be considered in relation to other parts or the whole),
but portions of the entire name are removed, reducedName appears to make
the most sense.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Enforce AllowWildcardCertificates during issuance
This commit adds the bulk of correctly validating wildcard certificate
Common Names during issuance according to RFC 6125 Section 6.4.3
semantics. As part of this, support for RFC 2818-conforming wildcard
certificates (wherein there are almost no restrictions on issuance) has
been removed.
Note that this flag does take precedence over AllowAnyName, giving a
little more safety in wildcard issuance in this case.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Update test cases to conform with RFC 6125
Test cases 19, 70+71, and 83+84 didn't conform with the RFC 6125, and so
should've been rejected under strict conformance. For 70+71 and 83+84,
we previously conditioned around the value of AllowSubdomains (allowing
issuance when true), but they likely should've been rejected either way.
Additionally, update the notes about globs matching wildcard
certificates to notate this is indeed the case.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Check AllowWildcardCertifciates in issuance tests
This allows for regression tests to cover the new
AllowWildcardCertificate conditional. We add additional test cases
ensuring that wildcard issuance is properly forbidden in all relevant
scenarios, while allowing the existing test cases to validate that
wildcard status doesn't affect non-wildcard certificates.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add Wildcard allowance during signing operations
When using sign-verbatim, sign-intermediate, or getting certificate
generation parameters, set AllowWildcardCertificates to mirror existing
policies.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add changelog entry
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
2022-02-24 13:41:56 +00:00
if strings . HasSuffix ( reducedName , "." + splitDisplay [ 1 ] ) {
2015-11-23 19:15:32 +00:00
continue
}
}
2015-10-02 18:27:30 +00:00
}
}
Add role parameter to restrict issuance of wildcard certificates (#14238)
* Add new AllowWildcardCertificate field to PKI role
This field allows the PKI role to control whether or not issuance of
wildcard certificates are allowed. We default (both on migration and
new role creation) to the less secure true value for backwards
compatibility with existing Vault versions.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Refactor sanitizedName to reducedName
Per comment, this variable name was confusing during the reproduction
and subsequent fix of the earlier vulnerability and associated bug
report. Because the common name isn't necessarily _sanitized_ in any way
(and indeed must be considered in relation to other parts or the whole),
but portions of the entire name are removed, reducedName appears to make
the most sense.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Enforce AllowWildcardCertificates during issuance
This commit adds the bulk of correctly validating wildcard certificate
Common Names during issuance according to RFC 6125 Section 6.4.3
semantics. As part of this, support for RFC 2818-conforming wildcard
certificates (wherein there are almost no restrictions on issuance) has
been removed.
Note that this flag does take precedence over AllowAnyName, giving a
little more safety in wildcard issuance in this case.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Update test cases to conform with RFC 6125
Test cases 19, 70+71, and 83+84 didn't conform with the RFC 6125, and so
should've been rejected under strict conformance. For 70+71 and 83+84,
we previously conditioned around the value of AllowSubdomains (allowing
issuance when true), but they likely should've been rejected either way.
Additionally, update the notes about globs matching wildcard
certificates to notate this is indeed the case.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Check AllowWildcardCertifciates in issuance tests
This allows for regression tests to cover the new
AllowWildcardCertificate conditional. We add additional test cases
ensuring that wildcard issuance is properly forbidden in all relevant
scenarios, while allowing the existing test cases to validate that
wildcard status doesn't affect non-wildcard certificates.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add Wildcard allowance during signing operations
When using sign-verbatim, sign-intermediate, or getting certificate
generation parameters, set AllowWildcardCertificates to mirror existing
policies.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add changelog entry
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
2022-02-24 13:41:56 +00:00
if strings . HasSuffix ( reducedName , "." + data . req . DisplayName ) ||
( isWildcard && reducedName == data . req . DisplayName ) {
2015-05-15 16:13:05 +00:00
continue
}
}
}
2018-02-16 22:19:34 +00:00
if len ( data . role . AllowedDomains ) > 0 {
2015-12-01 04:49:11 +00:00
valid := false
2018-02-16 22:19:34 +00:00
for _ , currDomain := range data . role . AllowedDomains {
2015-12-01 04:49:11 +00:00
// If there is, say, a trailing comma, ignore it
if currDomain == "" {
2015-05-15 16:13:05 +00:00
continue
}
2015-12-01 04:49:11 +00:00
2020-07-08 16:52:25 +00:00
if data . role . AllowedDomainsTemplate {
2020-08-17 18:37:00 +00:00
isTemplate , _ := framework . ValidateIdentityTemplate ( currDomain )
if isTemplate && data . req . EntityID != "" {
2020-07-08 16:52:25 +00:00
tmpCurrDomain , err := framework . PopulateIdentityTemplate ( currDomain , data . req . EntityID , b . System ( ) )
if err != nil {
continue
}
currDomain = tmpCurrDomain
}
}
2015-12-01 04:49:11 +00:00
// First, allow an exact match of the base domain if that role flag
// is enabled
2018-02-16 22:19:34 +00:00
if data . role . AllowBareDomains &&
Fix broken interactions between glob_domains and wildcards (#14235)
* Allow issuance of wildcard via glob match
From Vault v1.8.0 onwards, we would incorrectly disallow issuance of a
wildcard certificate when allow_glob_domain was enabled with a
multi-part glob domain in allowed_domains (such as *.*.foo) when
attempting to issue a wildcard for a subdomain (such as *.bar.foo).
This fixes that by reverting an errant change in the case insensitivity
patch. Here, when validating against a very powerful glob construct, we
leave the wildcard prefix (*.) from the raw common_name element, to
allow multi-part globs to match wildcard entries.
It is important to note that "sanitizedName" is an incorrect variable
naming here. Wildcard parsing (per RFC 6125 which supercedes RFC 2818)
must be in the left-most segment of the domain, but we lack validation
to ensure no internal wildcards exist. Additionally per item 3 of
section 6.4.3 of RFC 6125, wildcards MAY be internal to a domain
segment, in which case sanitizedName again leaves the wildcard in place.
Resolves: #13530
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Remove duplicate email address check
As pointed out by Steven Clark (author of the removed conditional in
70012cd865b3dcdab376dba0c0e0abc88c48f508), this is duplicate from the
now-reintroduced comparison against name (versus the erroneous
sanitizedName at the time of his commit).
This is a reversion of the changes to builtin/logical/pki/cert_util.go,
but keeping the additional valuable test cases.
Co-authored-by: Steven Clark <steven.clark@hashicorp.com>
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add multi-dimensional PKI role issuance tests
This commit introduces multi-dimensional testing of PKI secrets engine's
role-based certificate issuance with the intent of preventing future
regressions.
Here, dimensions of testing include:
- AllowedDomains to decide which domains are approved for issuance,
- AllowBareDomains to decide if raw entries of AllowedDomains are
permitted,
- AllowGlobDomains to decide if glob patterns in AllowedDomains are
parsed,
- AllowSubdomains to decide if subdomains of AllowedDomains are
permitted,
- AllowLocalhost to decide if localhost identifiers are permitted, and
- CommonName of the certificate to request.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add changelog entry
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
Co-authored-by: Steven Clark <steven.clark@hashicorp.com>
2022-02-23 21:44:09 +00:00
( strings . EqualFold ( name , currDomain ) ||
( isEmail && strings . EqualFold ( emailDomain , currDomain ) ) ) {
2015-12-01 04:49:11 +00:00
valid = true
break
}
2018-02-16 22:19:34 +00:00
if data . role . AllowSubdomains {
Add role parameter to restrict issuance of wildcard certificates (#14238)
* Add new AllowWildcardCertificate field to PKI role
This field allows the PKI role to control whether or not issuance of
wildcard certificates are allowed. We default (both on migration and
new role creation) to the less secure true value for backwards
compatibility with existing Vault versions.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Refactor sanitizedName to reducedName
Per comment, this variable name was confusing during the reproduction
and subsequent fix of the earlier vulnerability and associated bug
report. Because the common name isn't necessarily _sanitized_ in any way
(and indeed must be considered in relation to other parts or the whole),
but portions of the entire name are removed, reducedName appears to make
the most sense.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Enforce AllowWildcardCertificates during issuance
This commit adds the bulk of correctly validating wildcard certificate
Common Names during issuance according to RFC 6125 Section 6.4.3
semantics. As part of this, support for RFC 2818-conforming wildcard
certificates (wherein there are almost no restrictions on issuance) has
been removed.
Note that this flag does take precedence over AllowAnyName, giving a
little more safety in wildcard issuance in this case.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Update test cases to conform with RFC 6125
Test cases 19, 70+71, and 83+84 didn't conform with the RFC 6125, and so
should've been rejected under strict conformance. For 70+71 and 83+84,
we previously conditioned around the value of AllowSubdomains (allowing
issuance when true), but they likely should've been rejected either way.
Additionally, update the notes about globs matching wildcard
certificates to notate this is indeed the case.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Check AllowWildcardCertifciates in issuance tests
This allows for regression tests to cover the new
AllowWildcardCertificate conditional. We add additional test cases
ensuring that wildcard issuance is properly forbidden in all relevant
scenarios, while allowing the existing test cases to validate that
wildcard status doesn't affect non-wildcard certificates.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add Wildcard allowance during signing operations
When using sign-verbatim, sign-intermediate, or getting certificate
generation parameters, set AllowWildcardCertificates to mirror existing
policies.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add changelog entry
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
2022-02-24 13:41:56 +00:00
if strings . HasSuffix ( reducedName , "." + currDomain ) ||
( isWildcard && strings . EqualFold ( reducedName , currDomain ) ) {
2015-12-01 04:49:11 +00:00
valid = true
break
}
}
2017-05-01 14:40:18 +00:00
2018-02-16 22:19:34 +00:00
if data . role . AllowGlobDomains &&
2017-05-01 14:40:18 +00:00
strings . Contains ( currDomain , "*" ) &&
Fix broken interactions between glob_domains and wildcards (#14235)
* Allow issuance of wildcard via glob match
From Vault v1.8.0 onwards, we would incorrectly disallow issuance of a
wildcard certificate when allow_glob_domain was enabled with a
multi-part glob domain in allowed_domains (such as *.*.foo) when
attempting to issue a wildcard for a subdomain (such as *.bar.foo).
This fixes that by reverting an errant change in the case insensitivity
patch. Here, when validating against a very powerful glob construct, we
leave the wildcard prefix (*.) from the raw common_name element, to
allow multi-part globs to match wildcard entries.
It is important to note that "sanitizedName" is an incorrect variable
naming here. Wildcard parsing (per RFC 6125 which supercedes RFC 2818)
must be in the left-most segment of the domain, but we lack validation
to ensure no internal wildcards exist. Additionally per item 3 of
section 6.4.3 of RFC 6125, wildcards MAY be internal to a domain
segment, in which case sanitizedName again leaves the wildcard in place.
Resolves: #13530
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Remove duplicate email address check
As pointed out by Steven Clark (author of the removed conditional in
70012cd865b3dcdab376dba0c0e0abc88c48f508), this is duplicate from the
now-reintroduced comparison against name (versus the erroneous
sanitizedName at the time of his commit).
This is a reversion of the changes to builtin/logical/pki/cert_util.go,
but keeping the additional valuable test cases.
Co-authored-by: Steven Clark <steven.clark@hashicorp.com>
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add multi-dimensional PKI role issuance tests
This commit introduces multi-dimensional testing of PKI secrets engine's
role-based certificate issuance with the intent of preventing future
regressions.
Here, dimensions of testing include:
- AllowedDomains to decide which domains are approved for issuance,
- AllowBareDomains to decide if raw entries of AllowedDomains are
permitted,
- AllowGlobDomains to decide if glob patterns in AllowedDomains are
parsed,
- AllowSubdomains to decide if subdomains of AllowedDomains are
permitted,
- AllowLocalhost to decide if localhost identifiers are permitted, and
- CommonName of the certificate to request.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add changelog entry
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
Co-authored-by: Steven Clark <steven.clark@hashicorp.com>
2022-02-23 21:44:09 +00:00
glob . Glob ( currDomain , name ) {
2017-05-01 14:40:18 +00:00
valid = true
break
}
2015-12-01 04:49:11 +00:00
}
2020-07-08 16:52:25 +00:00
2015-12-01 04:49:11 +00:00
if valid {
continue
2015-05-15 16:13:05 +00:00
}
}
2017-03-16 15:41:00 +00:00
return name
2015-05-15 16:13:05 +00:00
}
2017-03-16 15:41:00 +00:00
return ""
2015-05-15 16:13:05 +00:00
}
2018-02-16 22:19:34 +00:00
// validateOtherSANs checks if the values requested are allowed. If an OID
// isn't allowed, it will be returned as the first string. If a value isn't
// allowed, it will be returned as the second string. Empty strings + error
// means everything is okay.
2019-05-09 15:43:11 +00:00
func validateOtherSANs ( data * inputBundle , requested map [ string ] [ ] string ) ( string , string , error ) {
2019-12-11 15:16:44 +00:00
if len ( data . role . AllowedOtherSANs ) == 1 && data . role . AllowedOtherSANs [ 0 ] == "*" {
// Anything is allowed
return "" , "" , nil
2018-10-08 13:51:43 +00:00
}
2019-12-11 15:16:44 +00:00
2018-02-16 22:19:34 +00:00
allowed , err := parseOtherSANs ( data . role . AllowedOtherSANs )
if err != nil {
2021-04-22 15:20:59 +00:00
return "" , "" , fmt . Errorf ( "error parsing role's allowed SANs: %w" , err )
2018-02-16 22:19:34 +00:00
}
for oid , names := range requested {
for _ , name := range names {
allowedNames , ok := allowed [ oid ]
if ! ok {
return oid , "" , nil
}
valid := false
for _ , allowedName := range allowedNames {
if glob . Glob ( allowedName , name ) {
valid = true
break
}
}
if ! valid {
return oid , name , nil
}
}
}
return "" , "" , nil
}
func parseOtherSANs ( others [ ] string ) ( map [ string ] [ ] string , error ) {
result := map [ string ] [ ] string { }
for _ , other := range others {
splitOther := strings . SplitN ( other , ";" , 2 )
if len ( splitOther ) != 2 {
return nil , fmt . Errorf ( "expected a semicolon in other SAN %q" , other )
}
splitType := strings . SplitN ( splitOther [ 1 ] , ":" , 2 )
if len ( splitType ) != 2 {
return nil , fmt . Errorf ( "expected a colon in other SAN %q" , other )
}
2018-10-08 13:51:43 +00:00
switch {
case strings . EqualFold ( splitType [ 0 ] , "utf8" ) :
case strings . EqualFold ( splitType [ 0 ] , "utf-8" ) :
default :
2018-02-16 22:19:34 +00:00
return nil , fmt . Errorf ( "only utf8 other SANs are supported; found non-supported type in other SAN %q" , other )
}
result [ splitOther [ 0 ] ] = append ( result [ splitOther [ 0 ] ] , splitType [ 1 ] )
}
return result , nil
}
2019-05-09 15:43:11 +00:00
func validateSerialNumber ( data * inputBundle , serialNumber string ) string {
2018-06-05 03:18:39 +00:00
valid := false
if len ( data . role . AllowedSerialNumbers ) > 0 {
for _ , currSerialNumber := range data . role . AllowedSerialNumbers {
if currSerialNumber == "" {
continue
}
if ( strings . Contains ( currSerialNumber , "*" ) &&
glob . Glob ( currSerialNumber , serialNumber ) ) ||
currSerialNumber == serialNumber {
valid = true
break
}
}
}
if ! valid {
return serialNumber
} else {
return ""
}
}
2018-01-19 06:44:44 +00:00
func generateCert ( ctx context . Context ,
b * backend ,
2019-05-09 15:43:11 +00:00
input * inputBundle ,
caSign * certutil . CAInfoBundle ,
2021-09-15 16:59:12 +00:00
isCA bool ,
2022-01-27 18:06:34 +00:00
randomSource io . Reader ) ( * certutil . ParsedCertBundle , error ,
) {
2019-05-09 15:43:11 +00:00
if input . role == nil {
2018-02-16 22:19:34 +00:00
return nil , errutil . InternalError { Err : "no role found in data bundle" }
}
2019-05-09 15:43:11 +00:00
if input . role . KeyType == "rsa" && input . role . KeyBits < 2048 {
2016-07-28 19:19:27 +00:00
return nil , errutil . UserError { Err : "RSA keys < 2048 bits are unsafe and not supported" }
2016-02-18 22:55:47 +00:00
}
2019-05-09 15:43:11 +00:00
data , err := generateCreationBundle ( b , input , caSign , nil )
2015-08-29 13:03:02 +00:00
if err != nil {
return nil , err
}
2019-05-09 15:43:11 +00:00
if data . Params == nil {
2018-03-20 18:54:10 +00:00
return nil , errutil . InternalError { Err : "nil parameters received from parameter bundle generation" }
2018-02-16 22:19:34 +00:00
}
2015-08-29 13:03:02 +00:00
2015-10-09 17:45:17 +00:00
if isCA {
2019-05-09 15:43:11 +00:00
data . Params . IsCA = isCA
data . Params . PermittedDNSDomains = input . apiData . Get ( "permitted_dns_domains" ) . ( [ ] string )
2017-08-15 20:10:36 +00:00
2019-05-09 15:43:11 +00:00
if data . SigningBundle == nil {
2015-11-16 16:42:06 +00:00
// Generating a self-signed root certificate
2019-05-09 15:43:11 +00:00
entries , err := getURLs ( ctx , input . req )
2015-11-16 16:42:06 +00:00
if err != nil {
2016-07-28 19:19:27 +00:00
return nil , errutil . InternalError { Err : fmt . Sprintf ( "unable to fetch URL information: %v" , err ) }
2015-11-16 16:42:06 +00:00
}
if entries == nil {
2019-05-09 15:43:11 +00:00
entries = & certutil . URLEntries {
2015-11-16 16:42:06 +00:00
IssuingCertificates : [ ] string { } ,
CRLDistributionPoints : [ ] string { } ,
OCSPServers : [ ] string { } ,
}
}
2019-05-09 15:43:11 +00:00
data . Params . URLs = entries
2015-11-16 16:42:06 +00:00
2019-05-09 15:43:11 +00:00
if input . role . MaxPathLength == nil {
data . Params . MaxPathLength = - 1
2015-11-16 16:42:06 +00:00
} else {
2019-05-09 15:43:11 +00:00
data . Params . MaxPathLength = * input . role . MaxPathLength
2015-11-16 16:42:06 +00:00
}
}
2015-10-09 17:45:17 +00:00
}
2022-01-27 04:06:25 +00:00
parsedBundle , err := generateCABundle ( ctx , b , input , data , randomSource )
2015-08-29 13:03:02 +00:00
if err != nil {
return nil , err
}
return parsedBundle , nil
}
2015-10-02 15:55:30 +00:00
// N.B.: This is only meant to be used for generating intermediate CAs.
// It skips some sanity checks.
2022-01-27 04:06:25 +00:00
func generateIntermediateCSR ( ctx context . Context , b * backend , input * inputBundle , randomSource io . Reader ) ( * certutil . ParsedCSRBundle , error ) {
2019-05-09 15:43:11 +00:00
creation , err := generateCreationBundle ( b , input , nil , nil )
2015-11-12 16:24:32 +00:00
if err != nil {
return nil , err
2015-08-29 13:03:02 +00:00
}
2019-05-09 15:43:11 +00:00
if creation . Params == nil {
2018-03-20 18:54:10 +00:00
return nil , errutil . InternalError { Err : "nil parameters received from parameter bundle generation" }
2018-02-16 22:19:34 +00:00
}
2015-08-29 13:03:02 +00:00
2019-05-09 15:43:11 +00:00
addBasicConstraints := input . apiData != nil && input . apiData . Get ( "add_basic_constraints" ) . ( bool )
2022-01-27 04:06:25 +00:00
parsedBundle , err := generateCSRBundle ( ctx , b , input , creation , addBasicConstraints , randomSource )
2015-08-29 13:03:02 +00:00
if err != nil {
return nil , err
}
return parsedBundle , nil
}
func signCert ( b * backend ,
2019-05-09 15:43:11 +00:00
data * inputBundle ,
caSign * certutil . CAInfoBundle ,
2015-10-09 17:45:17 +00:00
isCA bool ,
2022-01-27 18:06:34 +00:00
useCSRValues bool ) ( * certutil . ParsedCertBundle , error ,
) {
2018-02-16 22:19:34 +00:00
if data . role == nil {
return nil , errutil . InternalError { Err : "no role found in data bundle" }
}
2015-08-29 13:03:02 +00:00
2018-02-16 22:19:34 +00:00
csrString := data . apiData . Get ( "csr" ) . ( string )
2015-09-30 01:48:31 +00:00
if csrString == "" {
2016-07-28 19:19:27 +00:00
return nil , errutil . UserError { Err : fmt . Sprintf ( "\"csr\" is empty" ) }
2015-09-30 01:48:31 +00:00
}
pemBytes := [ ] byte ( csrString )
pemBlock , pemBytes := pem . Decode ( pemBytes )
if pemBlock == nil {
2016-07-28 19:19:27 +00:00
return nil , errutil . UserError { Err : "csr contains no data" }
2015-09-30 01:48:31 +00:00
}
csr , err := x509 . ParseCertificateRequest ( pemBlock . Bytes )
if err != nil {
2017-04-28 12:30:24 +00:00
return nil , errutil . UserError { Err : fmt . Sprintf ( "certificate request could not be parsed: %v" , err ) }
2015-09-30 01:48:31 +00:00
}
Fix handling of default zero SignatureBits value with Any key type in PKI Secrets Engine (#14875)
* Correctly handle minimums, default SignatureBits
When using KeyType = "any" on a role (whether explicitly or implicitly
via a sign-verbatim like operation), we need to update the value of
SignatureBits from its new value 0 to a per-key-type default value. This
will allow sign operations on these paths to function correctly, having
the correctly inferred default signature bit length.
Additionally, this allows the computed default value for key type to be
used for minimum size validation in the RSA/ECDSA paths. We additionally
enforce the 2048-minimum in this case as well.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Fix defaults and validation of "any" KeyType
When certutil is given the placeholder any keytype, it attempts to
validate and update the default zero value. However, in lacking a
default value for SignatureBits, it cannot update the value from the
zero value, thus causing validation to fail.
Add more awareness to the placeholder "any" value to certutil.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add role-based regression tests for key bits
This adds regression tests for Key Type, Key Bits, and Signature Bits
parameters on the role. We test several values, including the "any"
value to ensure it correctly restricts key sizes.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add sign-verbatim test for key type
This ensures that we test sign-verbatim against a variety of key types.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add changelog entry
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
Co-authored-by: Steven Clark <steven.clark@hashicorp.com>
2022-04-04 19:26:54 +00:00
// This switch validates that the CSR key type matches the role and sets
// the value in the actualKeyType/actualKeyBits values.
actualKeyType := ""
actualKeyBits := 0
2018-02-16 22:19:34 +00:00
switch data . role . KeyType {
2016-02-19 23:50:51 +00:00
case "rsa" :
// Verify that the key matches the role type
if csr . PublicKeyAlgorithm != x509 . RSA {
2016-07-28 19:19:27 +00:00
return nil , errutil . UserError { Err : fmt . Sprintf (
2016-02-19 23:50:51 +00:00
"role requires keys of type %s" ,
2018-02-16 22:19:34 +00:00
data . role . KeyType ) }
2016-02-19 23:50:51 +00:00
}
Fix handling of default zero SignatureBits value with Any key type in PKI Secrets Engine (#14875)
* Correctly handle minimums, default SignatureBits
When using KeyType = "any" on a role (whether explicitly or implicitly
via a sign-verbatim like operation), we need to update the value of
SignatureBits from its new value 0 to a per-key-type default value. This
will allow sign operations on these paths to function correctly, having
the correctly inferred default signature bit length.
Additionally, this allows the computed default value for key type to be
used for minimum size validation in the RSA/ECDSA paths. We additionally
enforce the 2048-minimum in this case as well.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Fix defaults and validation of "any" KeyType
When certutil is given the placeholder any keytype, it attempts to
validate and update the default zero value. However, in lacking a
default value for SignatureBits, it cannot update the value from the
zero value, thus causing validation to fail.
Add more awareness to the placeholder "any" value to certutil.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add role-based regression tests for key bits
This adds regression tests for Key Type, Key Bits, and Signature Bits
parameters on the role. We test several values, including the "any"
value to ensure it correctly restricts key sizes.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add sign-verbatim test for key type
This ensures that we test sign-verbatim against a variety of key types.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add changelog entry
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
Co-authored-by: Steven Clark <steven.clark@hashicorp.com>
2022-04-04 19:26:54 +00:00
2016-02-19 23:50:51 +00:00
pubKey , ok := csr . PublicKey . ( * rsa . PublicKey )
if ! ok {
2016-07-28 19:19:27 +00:00
return nil , errutil . UserError { Err : "could not parse CSR's public key" }
2016-02-19 23:50:51 +00:00
}
Fix handling of default zero SignatureBits value with Any key type in PKI Secrets Engine (#14875)
* Correctly handle minimums, default SignatureBits
When using KeyType = "any" on a role (whether explicitly or implicitly
via a sign-verbatim like operation), we need to update the value of
SignatureBits from its new value 0 to a per-key-type default value. This
will allow sign operations on these paths to function correctly, having
the correctly inferred default signature bit length.
Additionally, this allows the computed default value for key type to be
used for minimum size validation in the RSA/ECDSA paths. We additionally
enforce the 2048-minimum in this case as well.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Fix defaults and validation of "any" KeyType
When certutil is given the placeholder any keytype, it attempts to
validate and update the default zero value. However, in lacking a
default value for SignatureBits, it cannot update the value from the
zero value, thus causing validation to fail.
Add more awareness to the placeholder "any" value to certutil.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add role-based regression tests for key bits
This adds regression tests for Key Type, Key Bits, and Signature Bits
parameters on the role. We test several values, including the "any"
value to ensure it correctly restricts key sizes.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add sign-verbatim test for key type
This ensures that we test sign-verbatim against a variety of key types.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add changelog entry
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
Co-authored-by: Steven Clark <steven.clark@hashicorp.com>
2022-04-04 19:26:54 +00:00
actualKeyType = "rsa"
actualKeyBits = pubKey . N . BitLen ( )
2016-02-19 23:50:51 +00:00
case "ec" :
// Verify that the key matches the role type
if csr . PublicKeyAlgorithm != x509 . ECDSA {
2016-07-28 19:19:27 +00:00
return nil , errutil . UserError { Err : fmt . Sprintf (
2016-02-19 23:50:51 +00:00
"role requires keys of type %s" ,
2018-02-16 22:19:34 +00:00
data . role . KeyType ) }
2016-02-19 23:50:51 +00:00
}
pubKey , ok := csr . PublicKey . ( * ecdsa . PublicKey )
if ! ok {
2016-07-28 19:19:27 +00:00
return nil , errutil . UserError { Err : "could not parse CSR's public key" }
2016-02-19 23:50:51 +00:00
}
Fix handling of default zero SignatureBits value with Any key type in PKI Secrets Engine (#14875)
* Correctly handle minimums, default SignatureBits
When using KeyType = "any" on a role (whether explicitly or implicitly
via a sign-verbatim like operation), we need to update the value of
SignatureBits from its new value 0 to a per-key-type default value. This
will allow sign operations on these paths to function correctly, having
the correctly inferred default signature bit length.
Additionally, this allows the computed default value for key type to be
used for minimum size validation in the RSA/ECDSA paths. We additionally
enforce the 2048-minimum in this case as well.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Fix defaults and validation of "any" KeyType
When certutil is given the placeholder any keytype, it attempts to
validate and update the default zero value. However, in lacking a
default value for SignatureBits, it cannot update the value from the
zero value, thus causing validation to fail.
Add more awareness to the placeholder "any" value to certutil.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add role-based regression tests for key bits
This adds regression tests for Key Type, Key Bits, and Signature Bits
parameters on the role. We test several values, including the "any"
value to ensure it correctly restricts key sizes.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add sign-verbatim test for key type
This ensures that we test sign-verbatim against a variety of key types.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add changelog entry
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
Co-authored-by: Steven Clark <steven.clark@hashicorp.com>
2022-04-04 19:26:54 +00:00
actualKeyType = "ec"
actualKeyBits = pubKey . Params ( ) . BitSize
2021-10-05 15:28:49 +00:00
case "ed25519" :
// Verify that the key matches the role type
2022-03-23 19:19:56 +00:00
if csr . PublicKeyAlgorithm != x509 . Ed25519 {
2021-10-05 15:28:49 +00:00
return nil , errutil . UserError { Err : fmt . Sprintf (
"role requires keys of type %s" ,
data . role . KeyType ) }
}
Fix handling of default zero SignatureBits value with Any key type in PKI Secrets Engine (#14875)
* Correctly handle minimums, default SignatureBits
When using KeyType = "any" on a role (whether explicitly or implicitly
via a sign-verbatim like operation), we need to update the value of
SignatureBits from its new value 0 to a per-key-type default value. This
will allow sign operations on these paths to function correctly, having
the correctly inferred default signature bit length.
Additionally, this allows the computed default value for key type to be
used for minimum size validation in the RSA/ECDSA paths. We additionally
enforce the 2048-minimum in this case as well.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Fix defaults and validation of "any" KeyType
When certutil is given the placeholder any keytype, it attempts to
validate and update the default zero value. However, in lacking a
default value for SignatureBits, it cannot update the value from the
zero value, thus causing validation to fail.
Add more awareness to the placeholder "any" value to certutil.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add role-based regression tests for key bits
This adds regression tests for Key Type, Key Bits, and Signature Bits
parameters on the role. We test several values, including the "any"
value to ensure it correctly restricts key sizes.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add sign-verbatim test for key type
This ensures that we test sign-verbatim against a variety of key types.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add changelog entry
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
Co-authored-by: Steven Clark <steven.clark@hashicorp.com>
2022-04-04 19:26:54 +00:00
2021-10-05 15:28:49 +00:00
_ , ok := csr . PublicKey . ( ed25519 . PublicKey )
if ! ok {
return nil , errutil . UserError { Err : "could not parse CSR's public key" }
}
Fix handling of default zero SignatureBits value with Any key type in PKI Secrets Engine (#14875)
* Correctly handle minimums, default SignatureBits
When using KeyType = "any" on a role (whether explicitly or implicitly
via a sign-verbatim like operation), we need to update the value of
SignatureBits from its new value 0 to a per-key-type default value. This
will allow sign operations on these paths to function correctly, having
the correctly inferred default signature bit length.
Additionally, this allows the computed default value for key type to be
used for minimum size validation in the RSA/ECDSA paths. We additionally
enforce the 2048-minimum in this case as well.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Fix defaults and validation of "any" KeyType
When certutil is given the placeholder any keytype, it attempts to
validate and update the default zero value. However, in lacking a
default value for SignatureBits, it cannot update the value from the
zero value, thus causing validation to fail.
Add more awareness to the placeholder "any" value to certutil.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add role-based regression tests for key bits
This adds regression tests for Key Type, Key Bits, and Signature Bits
parameters on the role. We test several values, including the "any"
value to ensure it correctly restricts key sizes.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add sign-verbatim test for key type
This ensures that we test sign-verbatim against a variety of key types.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add changelog entry
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
Co-authored-by: Steven Clark <steven.clark@hashicorp.com>
2022-04-04 19:26:54 +00:00
actualKeyType = "ed25519"
actualKeyBits = 0
2016-02-19 23:50:51 +00:00
case "any" :
Fix handling of default zero SignatureBits value with Any key type in PKI Secrets Engine (#14875)
* Correctly handle minimums, default SignatureBits
When using KeyType = "any" on a role (whether explicitly or implicitly
via a sign-verbatim like operation), we need to update the value of
SignatureBits from its new value 0 to a per-key-type default value. This
will allow sign operations on these paths to function correctly, having
the correctly inferred default signature bit length.
Additionally, this allows the computed default value for key type to be
used for minimum size validation in the RSA/ECDSA paths. We additionally
enforce the 2048-minimum in this case as well.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Fix defaults and validation of "any" KeyType
When certutil is given the placeholder any keytype, it attempts to
validate and update the default zero value. However, in lacking a
default value for SignatureBits, it cannot update the value from the
zero value, thus causing validation to fail.
Add more awareness to the placeholder "any" value to certutil.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add role-based regression tests for key bits
This adds regression tests for Key Type, Key Bits, and Signature Bits
parameters on the role. We test several values, including the "any"
value to ensure it correctly restricts key sizes.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add sign-verbatim test for key type
This ensures that we test sign-verbatim against a variety of key types.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add changelog entry
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
Co-authored-by: Steven Clark <steven.clark@hashicorp.com>
2022-04-04 19:26:54 +00:00
// We need to compute the actual key type and key bits, to correctly
// validate minimums and SignatureBits below.
switch csr . PublicKeyAlgorithm {
case x509 . RSA :
pubKey , ok := csr . PublicKey . ( * rsa . PublicKey )
if ! ok {
return nil , errutil . UserError { Err : "could not parse CSR's public key" }
}
if pubKey . N . BitLen ( ) < 2048 {
return nil , errutil . UserError { Err : "RSA keys < 2048 bits are unsafe and not supported" }
}
actualKeyType = "rsa"
actualKeyBits = pubKey . N . BitLen ( )
case x509 . ECDSA :
pubKey , ok := csr . PublicKey . ( * ecdsa . PublicKey )
if ! ok {
return nil , errutil . UserError { Err : "could not parse CSR's public key" }
}
actualKeyType = "ec"
actualKeyBits = pubKey . Params ( ) . BitSize
case x509 . Ed25519 :
_ , ok := csr . PublicKey . ( ed25519 . PublicKey )
if ! ok {
return nil , errutil . UserError { Err : "could not parse CSR's public key" }
}
actualKeyType = "ed25519"
actualKeyBits = 0
default :
return nil , errutil . UserError { Err : "Unknown key type in CSR: " + csr . PublicKeyAlgorithm . String ( ) }
2016-02-19 23:50:51 +00:00
}
Fix handling of default zero SignatureBits value with Any key type in PKI Secrets Engine (#14875)
* Correctly handle minimums, default SignatureBits
When using KeyType = "any" on a role (whether explicitly or implicitly
via a sign-verbatim like operation), we need to update the value of
SignatureBits from its new value 0 to a per-key-type default value. This
will allow sign operations on these paths to function correctly, having
the correctly inferred default signature bit length.
Additionally, this allows the computed default value for key type to be
used for minimum size validation in the RSA/ECDSA paths. We additionally
enforce the 2048-minimum in this case as well.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Fix defaults and validation of "any" KeyType
When certutil is given the placeholder any keytype, it attempts to
validate and update the default zero value. However, in lacking a
default value for SignatureBits, it cannot update the value from the
zero value, thus causing validation to fail.
Add more awareness to the placeholder "any" value to certutil.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add role-based regression tests for key bits
This adds regression tests for Key Type, Key Bits, and Signature Bits
parameters on the role. We test several values, including the "any"
value to ensure it correctly restricts key sizes.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add sign-verbatim test for key type
This ensures that we test sign-verbatim against a variety of key types.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add changelog entry
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
Co-authored-by: Steven Clark <steven.clark@hashicorp.com>
2022-04-04 19:26:54 +00:00
default :
return nil , errutil . InternalError { Err : fmt . Sprintf ( "unsupported key type value: %s" , data . role . KeyType ) }
}
2016-02-19 23:50:51 +00:00
Fix handling of default zero SignatureBits value with Any key type in PKI Secrets Engine (#14875)
* Correctly handle minimums, default SignatureBits
When using KeyType = "any" on a role (whether explicitly or implicitly
via a sign-verbatim like operation), we need to update the value of
SignatureBits from its new value 0 to a per-key-type default value. This
will allow sign operations on these paths to function correctly, having
the correctly inferred default signature bit length.
Additionally, this allows the computed default value for key type to be
used for minimum size validation in the RSA/ECDSA paths. We additionally
enforce the 2048-minimum in this case as well.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Fix defaults and validation of "any" KeyType
When certutil is given the placeholder any keytype, it attempts to
validate and update the default zero value. However, in lacking a
default value for SignatureBits, it cannot update the value from the
zero value, thus causing validation to fail.
Add more awareness to the placeholder "any" value to certutil.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add role-based regression tests for key bits
This adds regression tests for Key Type, Key Bits, and Signature Bits
parameters on the role. We test several values, including the "any"
value to ensure it correctly restricts key sizes.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add sign-verbatim test for key type
This ensures that we test sign-verbatim against a variety of key types.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add changelog entry
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
Co-authored-by: Steven Clark <steven.clark@hashicorp.com>
2022-04-04 19:26:54 +00:00
// Before validating key lengths, update our KeyBits/SignatureBits based
// on the actual CSR key type.
if data . role . KeyType == "any" {
// We update the value of KeyBits and SignatureBits here (from the
// role), using the specified key type. This allows us to convert
// the default value (0) for SignatureBits and KeyBits to a
// meaningful value. In the event KeyBits takes a zero value, we also
// update that to a new value.
//
// This is mandatory because on some roles, with KeyType any, we'll
// set a default SignatureBits to 0, but this will need to be updated
// in order to behave correctly during signing.
roleBitsWasZero := data . role . KeyBits == 0
if data . role . KeyBits , data . role . SignatureBits , err = certutil . ValidateDefaultOrValueKeyTypeSignatureLength ( actualKeyType , data . role . KeyBits , data . role . SignatureBits ) ; err != nil {
return nil , errutil . InternalError { Err : fmt . Sprintf ( "unknown internal error updating default values: %v" , err ) }
2016-02-18 22:55:47 +00:00
}
Fix handling of default zero SignatureBits value with Any key type in PKI Secrets Engine (#14875)
* Correctly handle minimums, default SignatureBits
When using KeyType = "any" on a role (whether explicitly or implicitly
via a sign-verbatim like operation), we need to update the value of
SignatureBits from its new value 0 to a per-key-type default value. This
will allow sign operations on these paths to function correctly, having
the correctly inferred default signature bit length.
Additionally, this allows the computed default value for key type to be
used for minimum size validation in the RSA/ECDSA paths. We additionally
enforce the 2048-minimum in this case as well.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Fix defaults and validation of "any" KeyType
When certutil is given the placeholder any keytype, it attempts to
validate and update the default zero value. However, in lacking a
default value for SignatureBits, it cannot update the value from the
zero value, thus causing validation to fail.
Add more awareness to the placeholder "any" value to certutil.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add role-based regression tests for key bits
This adds regression tests for Key Type, Key Bits, and Signature Bits
parameters on the role. We test several values, including the "any"
value to ensure it correctly restricts key sizes.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add sign-verbatim test for key type
This ensures that we test sign-verbatim against a variety of key types.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add changelog entry
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
Co-authored-by: Steven Clark <steven.clark@hashicorp.com>
2022-04-04 19:26:54 +00:00
// We're using the KeyBits field as a minimum value, and P-224 is safe
// and a previously allowed value. However, the above call defaults
// to P-256 as that's a saner default than P-224 (w.r.t. generation).
// So, override our fake Role value if it was previously zero.
if actualKeyType == "ec" && roleBitsWasZero {
data . role . KeyBits = 224
2016-02-18 22:55:47 +00:00
}
Fix handling of default zero SignatureBits value with Any key type in PKI Secrets Engine (#14875)
* Correctly handle minimums, default SignatureBits
When using KeyType = "any" on a role (whether explicitly or implicitly
via a sign-verbatim like operation), we need to update the value of
SignatureBits from its new value 0 to a per-key-type default value. This
will allow sign operations on these paths to function correctly, having
the correctly inferred default signature bit length.
Additionally, this allows the computed default value for key type to be
used for minimum size validation in the RSA/ECDSA paths. We additionally
enforce the 2048-minimum in this case as well.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Fix defaults and validation of "any" KeyType
When certutil is given the placeholder any keytype, it attempts to
validate and update the default zero value. However, in lacking a
default value for SignatureBits, it cannot update the value from the
zero value, thus causing validation to fail.
Add more awareness to the placeholder "any" value to certutil.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add role-based regression tests for key bits
This adds regression tests for Key Type, Key Bits, and Signature Bits
parameters on the role. We test several values, including the "any"
value to ensure it correctly restricts key sizes.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add sign-verbatim test for key type
This ensures that we test sign-verbatim against a variety of key types.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add changelog entry
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
Co-authored-by: Steven Clark <steven.clark@hashicorp.com>
2022-04-04 19:26:54 +00:00
}
2016-02-19 23:50:51 +00:00
Fix handling of default zero SignatureBits value with Any key type in PKI Secrets Engine (#14875)
* Correctly handle minimums, default SignatureBits
When using KeyType = "any" on a role (whether explicitly or implicitly
via a sign-verbatim like operation), we need to update the value of
SignatureBits from its new value 0 to a per-key-type default value. This
will allow sign operations on these paths to function correctly, having
the correctly inferred default signature bit length.
Additionally, this allows the computed default value for key type to be
used for minimum size validation in the RSA/ECDSA paths. We additionally
enforce the 2048-minimum in this case as well.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Fix defaults and validation of "any" KeyType
When certutil is given the placeholder any keytype, it attempts to
validate and update the default zero value. However, in lacking a
default value for SignatureBits, it cannot update the value from the
zero value, thus causing validation to fail.
Add more awareness to the placeholder "any" value to certutil.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add role-based regression tests for key bits
This adds regression tests for Key Type, Key Bits, and Signature Bits
parameters on the role. We test several values, including the "any"
value to ensure it correctly restricts key sizes.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add sign-verbatim test for key type
This ensures that we test sign-verbatim against a variety of key types.
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
* Add changelog entry
Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
Co-authored-by: Steven Clark <steven.clark@hashicorp.com>
2022-04-04 19:26:54 +00:00
// At this point, data.role.KeyBits and data.role.SignatureBits should both
// be non-zero, for RSA and ECDSA keys. Validate the actualKeyBits based on
// the role's values. If the KeyType was any, and KeyBits was set to 0,
// KeyBits should be updated to 2048 unless some other value was chosen
// explicitly.
//
// This validation needs to occur regardless of the role's key type, so
// that we always validate both RSA and ECDSA key sizes.
if actualKeyType == "rsa" {
if actualKeyBits < data . role . KeyBits {
return nil , errutil . UserError { Err : fmt . Sprintf (
"role requires a minimum of a %d-bit key, but CSR's key is %d bits" ,
data . role . KeyBits , actualKeyBits ) }
}
if actualKeyBits < 2048 {
return nil , errutil . UserError { Err : fmt . Sprintf (
"Vault requires a minimum of a 2048-bit key, but CSR's key is %d bits" ,
actualKeyBits ) }
}
} else if actualKeyType == "ec" {
if actualKeyBits < data . role . KeyBits {
return nil , errutil . UserError { Err : fmt . Sprintf (
"role requires a minimum of a %d-bit key, but CSR's key is %d bits" ,
data . role . KeyBits ,
actualKeyBits ) }
}
2016-02-18 22:55:47 +00:00
}
2019-05-09 15:43:11 +00:00
creation , err := generateCreationBundle ( b , data , caSign , csr )
2015-08-29 13:03:02 +00:00
if err != nil {
return nil , err
}
2019-05-09 15:43:11 +00:00
if creation . Params == nil {
2018-03-20 18:54:10 +00:00
return nil , errutil . InternalError { Err : "nil parameters received from parameter bundle generation" }
2018-02-16 22:19:34 +00:00
}
2015-08-29 13:03:02 +00:00
2019-05-09 15:43:11 +00:00
creation . Params . IsCA = isCA
creation . Params . UseCSRValues = useCSRValues
2015-10-09 17:45:17 +00:00
2017-08-15 20:10:36 +00:00
if isCA {
2019-05-09 15:43:11 +00:00
creation . Params . PermittedDNSDomains = data . apiData . Get ( "permitted_dns_domains" ) . ( [ ] string )
2017-08-15 20:10:36 +00:00
}
2019-05-09 15:43:11 +00:00
parsedBundle , err := certutil . SignCertificate ( creation )
2015-08-29 13:03:02 +00:00
if err != nil {
return nil , err
}
return parsedBundle , nil
}
2019-12-11 15:16:44 +00:00
// otherNameRaw describes a name related to a certificate which is not in one
// of the standard name formats. RFC 5280, 4.2.1.6:
// OtherName ::= SEQUENCE {
// type-id OBJECT IDENTIFIER,
// value [0] EXPLICIT ANY DEFINED BY type-id }
type otherNameRaw struct {
TypeID asn1 . ObjectIdentifier
Value asn1 . RawValue
}
type otherNameUtf8 struct {
oid string
value string
}
// ExtractUTF8String returns the UTF8 string contained in the Value, or an error
// if none is present.
func ( oraw * otherNameRaw ) extractUTF8String ( ) ( * otherNameUtf8 , error ) {
svalue := cryptobyte . String ( oraw . Value . Bytes )
var outTag cbbasn1 . Tag
var val cryptobyte . String
read := svalue . ReadAnyASN1 ( & val , & outTag )
if read && outTag == asn1 . TagUTF8String {
return & otherNameUtf8 { oid : oraw . TypeID . String ( ) , value : string ( val ) } , nil
}
return nil , fmt . Errorf ( "no UTF-8 string found in OtherName" )
}
func ( o otherNameUtf8 ) String ( ) string {
return fmt . Sprintf ( "%s;%s:%s" , o . oid , "UTF-8" , o . value )
}
func getOtherSANsFromX509Extensions ( exts [ ] pkix . Extension ) ( [ ] otherNameUtf8 , error ) {
var ret [ ] otherNameUtf8
for _ , ext := range exts {
if ! ext . Id . Equal ( oidExtensionSubjectAltName ) {
continue
}
err := forEachSAN ( ext . Value , func ( tag int , data [ ] byte ) error {
if tag != 0 {
return nil
}
var other otherNameRaw
_ , err := asn1 . UnmarshalWithParams ( data , & other , "tag:0" )
if err != nil {
2021-04-22 15:20:59 +00:00
return fmt . Errorf ( "could not parse requested other SAN: %w" , err )
2019-12-11 15:16:44 +00:00
}
val , err := other . extractUTF8String ( )
if err != nil {
return err
}
ret = append ( ret , * val )
return nil
} )
if err != nil {
return nil , err
}
}
return ret , nil
}
func forEachSAN ( extension [ ] byte , callback func ( tag int , data [ ] byte ) error ) error {
// RFC 5280, 4.2.1.6
// SubjectAltName ::= GeneralNames
//
// GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
//
// GeneralName ::= CHOICE {
// otherName [0] OtherName,
// rfc822Name [1] IA5String,
// dNSName [2] IA5String,
// x400Address [3] ORAddress,
// directoryName [4] Name,
// ediPartyName [5] EDIPartyName,
// uniformResourceIdentifier [6] IA5String,
// iPAddress [7] OCTET STRING,
// registeredID [8] OBJECT IDENTIFIER }
var seq asn1 . RawValue
rest , err := asn1 . Unmarshal ( extension , & seq )
if err != nil {
return err
} else if len ( rest ) != 0 {
return fmt . Errorf ( "x509: trailing data after X.509 extension" )
}
if ! seq . IsCompound || seq . Tag != 16 || seq . Class != 0 {
return asn1 . StructuralError { Msg : "bad SAN sequence" }
}
rest = seq . Bytes
for len ( rest ) > 0 {
var v asn1 . RawValue
rest , err = asn1 . Unmarshal ( rest , & v )
if err != nil {
return err
}
if err := callback ( v . Tag , v . FullBytes ) ; err != nil {
return err
}
}
return nil
}
2015-11-19 21:51:27 +00:00
// generateCreationBundle is a shared function that reads parameters supplied
2019-05-09 15:43:11 +00:00
// from the various endpoints and generates a CreationParameters with the
2015-11-19 21:51:27 +00:00
// parameters that can be used to issue or sign
2019-05-09 15:43:11 +00:00
func generateCreationBundle ( b * backend , data * inputBundle , caSign * certutil . CAInfoBundle , csr * x509 . CertificateRequest ) ( * certutil . CreationBundle , error ) {
2017-03-16 15:41:00 +00:00
// Read in names -- CN, DNS and email addresses
2015-11-16 15:10:03 +00:00
var cn string
2018-06-05 03:18:39 +00:00
var ridSerialNumber string
2017-03-16 15:41:00 +00:00
dnsNames := [ ] string { }
emailAddresses := [ ] string { }
2015-11-19 21:51:27 +00:00
{
2019-05-09 15:43:11 +00:00
if csr != nil && data . role . UseCSRCommonName {
cn = csr . Subject . CommonName
2015-11-16 15:10:03 +00:00
}
if cn == "" {
2018-02-16 22:19:34 +00:00
cn = data . apiData . Get ( "common_name" ) . ( string )
if cn == "" && data . role . RequireCN {
2019-05-09 15:43:11 +00:00
return nil , errutil . UserError { Err : ` the common_name field is required, or must be provided in a CSR with "use_csr_common_name" set to true, unless "require_cn" is set to false ` }
2015-11-19 21:51:27 +00:00
}
2015-10-09 17:45:17 +00:00
}
2017-02-16 06:04:29 +00:00
2018-06-05 03:18:39 +00:00
ridSerialNumber = data . apiData . Get ( "serial_number" ) . ( string )
// only take serial number from CSR if one was not supplied via API
2019-05-09 15:43:11 +00:00
if ridSerialNumber == "" && csr != nil {
ridSerialNumber = csr . Subject . SerialNumber
2018-06-05 03:18:39 +00:00
}
2019-05-09 15:43:11 +00:00
if csr != nil && data . role . UseCSRSANs {
dnsNames = csr . DNSNames
emailAddresses = csr . EmailAddresses
2017-03-15 18:38:18 +00:00
}
2018-02-16 22:19:34 +00:00
if cn != "" && ! data . apiData . Get ( "exclude_cn_from_sans" ) . ( bool ) {
2016-03-17 20:28:40 +00:00
if strings . Contains ( cn , "@" ) {
// Note: emails are not disallowed if the role's email protection
// flag is false, because they may well be included for
// informational purposes; it is up to the verifying party to
// ensure that email addresses in a subject alternate name can be
// used for the purpose for which they are presented
emailAddresses = append ( emailAddresses , cn )
} else {
2018-02-10 15:07:10 +00:00
// 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 {
2019-05-09 15:43:11 +00:00
return nil , errutil . UserError { Err : err . Error ( ) }
2018-02-10 15:07:10 +00:00
}
if hostnameRegex . MatchString ( converted ) {
dnsNames = append ( dnsNames , converted )
2018-02-09 18:42:19 +00:00
}
2016-03-17 20:28:40 +00:00
}
2015-11-19 21:51:27 +00:00
}
2017-03-15 18:38:18 +00:00
2019-05-09 15:43:11 +00:00
if csr == nil || ! data . role . UseCSRSANs {
2018-02-16 22:19:34 +00:00
cnAltRaw , ok := data . apiData . GetOk ( "alt_names" )
2017-03-15 18:38:18 +00:00
if ok {
2021-03-10 05:28:27 +00:00
cnAlt := strutil . ParseDedupAndSortStrings ( cnAltRaw . ( string ) , "," )
2017-03-16 15:41:00 +00:00
for _ , v := range cnAlt {
if strings . Contains ( v , "@" ) {
emailAddresses = append ( emailAddresses , v )
} else {
2018-02-10 15:07:10 +00:00
// 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 {
2019-05-09 15:43:11 +00:00
return nil , errutil . UserError { Err : err . Error ( ) }
2018-02-10 15:07:10 +00:00
}
if hostnameRegex . MatchString ( converted ) {
dnsNames = append ( dnsNames , converted )
2018-02-09 18:42:19 +00:00
}
2015-11-19 21:51:27 +00:00
}
2015-10-02 18:27:30 +00:00
}
2015-09-29 23:13:54 +00:00
}
2015-08-29 13:03:02 +00:00
}
2015-11-19 21:51:27 +00:00
2017-03-16 15:41:00 +00:00
// Check the CN. This ensures that the CN is checked even if it's
// excluded from SANs.
2018-02-09 18:42:19 +00:00
if cn != "" {
2020-07-08 16:52:25 +00:00
badName := validateNames ( b , data , [ ] string { cn } )
2018-02-09 18:42:19 +00:00
if len ( badName ) != 0 {
2019-05-09 15:43:11 +00:00
return nil , errutil . UserError { Err : fmt . Sprintf (
2018-02-09 18:42:19 +00:00
"common name %s not allowed by this role" , badName ) }
}
2017-03-16 15:41:00 +00:00
}
2018-06-05 03:18:39 +00:00
if ridSerialNumber != "" {
badName := validateSerialNumber ( data , ridSerialNumber )
if len ( badName ) != 0 {
2019-05-09 15:43:11 +00:00
return nil , errutil . UserError { Err : fmt . Sprintf (
2018-06-05 03:18:39 +00:00
"serial_number %s not allowed by this role" , badName ) }
}
}
2015-11-19 21:51:27 +00:00
// Check for bad email and/or DNS names
2020-07-08 16:52:25 +00:00
badName := validateNames ( b , data , dnsNames )
2015-11-19 21:51:27 +00:00
if len ( badName ) != 0 {
2019-05-09 15:43:11 +00:00
return nil , errutil . UserError { Err : fmt . Sprintf (
2017-03-16 15:41:00 +00:00
"subject alternate name %s not allowed by this role" , badName ) }
2015-11-19 21:51:27 +00:00
}
2020-07-08 16:52:25 +00:00
badName = validateNames ( b , data , emailAddresses )
2015-11-19 21:51:27 +00:00
if len ( badName ) != 0 {
2019-05-09 15:43:11 +00:00
return nil , errutil . UserError { Err : fmt . Sprintf (
2017-03-16 15:41:00 +00:00
"email address %s not allowed by this role" , badName ) }
2015-11-19 21:51:27 +00:00
}
2015-08-29 13:03:02 +00:00
}
2019-12-11 15:16:44 +00:00
// otherSANsInput has the same format as the other_sans HTTP param in the
// Vault PKI API: it is a list of strings of the form <oid>;<type>:<value>
// where <type> must be UTF8/UTF-8.
var otherSANsInput [ ] string
// otherSANs is the output of parseOtherSANs(otherSANsInput): its keys are
// the <oid> value, its values are of the form [<type>, <value>]
2018-02-16 22:19:34 +00:00
var otherSANs map [ string ] [ ] string
if sans := data . apiData . Get ( "other_sans" ) . ( [ ] string ) ; len ( sans ) > 0 {
2019-12-11 15:16:44 +00:00
otherSANsInput = sans
}
if data . role . UseCSRSANs && csr != nil && len ( csr . Extensions ) > 0 {
others , err := getOtherSANsFromX509Extensions ( csr . Extensions )
if err != nil {
2021-04-22 15:20:59 +00:00
return nil , errutil . UserError { Err : fmt . Errorf ( "could not parse requested other SAN: %w" , err ) . Error ( ) }
2019-12-11 15:16:44 +00:00
}
for _ , other := range others {
otherSANsInput = append ( otherSANsInput , other . String ( ) )
}
}
if len ( otherSANsInput ) > 0 {
requested , err := parseOtherSANs ( otherSANsInput )
2018-02-16 22:19:34 +00:00
if err != nil {
2021-04-22 15:20:59 +00:00
return nil , errutil . UserError { Err : fmt . Errorf ( "could not parse requested other SAN: %w" , err ) . Error ( ) }
2018-02-16 22:19:34 +00:00
}
badOID , badName , err := validateOtherSANs ( data , requested )
switch {
case err != nil :
2019-05-09 15:43:11 +00:00
return nil , errutil . UserError { Err : err . Error ( ) }
2018-02-16 22:19:34 +00:00
case len ( badName ) > 0 :
2019-05-09 15:43:11 +00:00
return nil , errutil . UserError { Err : fmt . Sprintf (
2018-02-16 22:19:34 +00:00
"other SAN %s not allowed for OID %s by this role" , badName , badOID ) }
case len ( badOID ) > 0 :
2019-05-09 15:43:11 +00:00
return nil , errutil . UserError { Err : fmt . Sprintf (
2018-02-16 22:19:34 +00:00
"other SAN OID %s not allowed by this role" , badOID ) }
default :
otherSANs = requested
}
}
2015-11-19 21:51:27 +00:00
// Get and verify any IP SANs
2015-10-02 18:27:30 +00:00
ipAddresses := [ ] net . IP { }
2015-11-19 21:51:27 +00:00
{
2019-05-09 15:43:11 +00:00
if csr != nil && data . role . UseCSRSANs {
if len ( csr . IPAddresses ) > 0 {
2018-02-16 22:19:34 +00:00
if ! data . role . AllowIPSANs {
2019-05-09 15:43:11 +00:00
return nil , errutil . UserError { Err : fmt . Sprintf (
2017-04-13 17:40:31 +00:00
"IP Subject Alternative Names are not allowed in this role, but was provided some via CSR" ) }
}
2019-05-09 15:43:11 +00:00
ipAddresses = csr . IPAddresses
2017-03-15 18:38:18 +00:00
}
} else {
2018-06-15 19:32:25 +00:00
ipAlt := data . apiData . Get ( "ip_sans" ) . ( [ ] string )
if len ( ipAlt ) > 0 {
if ! data . role . AllowIPSANs {
2019-05-09 15:43:11 +00:00
return nil , errutil . UserError { Err : fmt . Sprintf (
2018-06-15 19:32:25 +00:00
"IP Subject Alternative Names are not allowed in this role, but was provided %s" , ipAlt ) }
}
for _ , v := range ipAlt {
parsedIP := net . ParseIP ( v )
if parsedIP == nil {
2019-05-09 15:43:11 +00:00
return nil , errutil . UserError { Err : fmt . Sprintf (
2018-06-15 19:32:25 +00:00
"the value '%s' is not a valid IP address" , v ) }
}
ipAddresses = append ( ipAddresses , parsedIP )
}
}
}
}
URIs := [ ] * url . URL { }
{
2019-05-09 15:43:11 +00:00
if csr != nil && data . role . UseCSRSANs {
if len ( csr . URIs ) > 0 {
2018-06-15 19:32:25 +00:00
if len ( data . role . AllowedURISANs ) == 0 {
2021-04-08 16:43:39 +00:00
return nil , errutil . UserError {
Err : fmt . Sprintf (
"URI Subject Alternative Names are not allowed in this role, but were provided via CSR" ) ,
2017-03-15 18:38:18 +00:00
}
2018-06-15 19:32:25 +00:00
}
// validate uri sans
2019-05-09 15:43:11 +00:00
for _ , uri := range csr . URIs {
2021-12-15 15:18:28 +00:00
valid := validateURISAN ( b , data , uri . String ( ) )
2018-06-15 19:32:25 +00:00
if ! valid {
2021-04-08 16:43:39 +00:00
return nil , errutil . UserError {
Err : fmt . Sprintf (
"URI Subject Alternative Names were provided via CSR which are not valid for this role" ) ,
2018-06-15 19:32:25 +00:00
}
}
URIs = append ( URIs , uri )
}
}
} else {
uriAlt := data . apiData . Get ( "uri_sans" ) . ( [ ] string )
if len ( uriAlt ) > 0 {
if len ( data . role . AllowedURISANs ) == 0 {
2021-04-08 16:43:39 +00:00
return nil , errutil . UserError {
Err : fmt . Sprintf (
"URI Subject Alternative Names are not allowed in this role, but were provided via the API" ) ,
2018-06-15 19:32:25 +00:00
}
}
for _ , uri := range uriAlt {
2021-12-15 15:18:28 +00:00
valid := validateURISAN ( b , data , uri )
2018-06-15 19:32:25 +00:00
if ! valid {
2021-04-08 16:43:39 +00:00
return nil , errutil . UserError {
Err : fmt . Sprintf (
"URI Subject Alternative Names were provided via the API which are not valid for this role" ) ,
2018-06-15 19:32:25 +00:00
}
}
parsedURI , err := url . Parse ( uri )
if parsedURI == nil || err != nil {
2021-04-08 16:43:39 +00:00
return nil , errutil . UserError {
Err : fmt . Sprintf (
"the provided URI Subject Alternative Name '%s' is not a valid URI" , uri ) ,
2018-06-15 19:32:25 +00:00
}
}
URIs = append ( URIs , parsedURI )
2015-09-29 23:13:54 +00:00
}
2015-08-29 13:03:02 +00:00
}
}
}
2019-05-02 21:31:29 +00:00
// Most of these could also be RemoveDuplicateStable, or even
// leave duplicates in, but OU is the one most likely to be duplicated.
2018-02-16 22:19:34 +00:00
subject := pkix . Name {
2018-02-18 02:01:36 +00:00
CommonName : cn ,
2018-06-05 03:18:39 +00:00
SerialNumber : ridSerialNumber ,
2021-04-02 15:33:24 +00:00
Country : strutil . RemoveDuplicatesStable ( data . role . Country , false ) ,
Organization : strutil . RemoveDuplicatesStable ( data . role . Organization , false ) ,
2019-05-02 21:31:29 +00:00
OrganizationalUnit : strutil . RemoveDuplicatesStable ( data . role . OU , false ) ,
2021-04-02 15:33:24 +00:00
Locality : strutil . RemoveDuplicatesStable ( data . role . Locality , false ) ,
Province : strutil . RemoveDuplicatesStable ( data . role . Province , false ) ,
StreetAddress : strutil . RemoveDuplicatesStable ( data . role . StreetAddress , false ) ,
PostalCode : strutil . RemoveDuplicatesStable ( data . role . PostalCode , false ) ,
2018-02-16 22:19:34 +00:00
}
2017-03-16 15:41:00 +00:00
2017-09-15 02:49:04 +00:00
// Get the TTL and verify it against the max allowed
2015-08-29 13:03:02 +00:00
var ttl time . Duration
var maxTTL time . Duration
2017-08-15 20:10:36 +00:00
var notAfter time . Time
2021-11-11 00:09:06 +00:00
var err error
2015-11-19 21:51:27 +00:00
{
2018-02-16 22:19:34 +00:00
ttl = time . Duration ( data . apiData . Get ( "ttl" ) . ( int ) ) * time . Second
2021-11-11 00:09:06 +00:00
notAfterAlt := data . role . NotAfter
if notAfterAlt == "" {
notAfterAltRaw , ok := data . apiData . GetOk ( "not_after" )
if ok {
notAfterAlt = notAfterAltRaw . ( string )
}
}
if ttl > 0 && notAfterAlt != "" {
return nil , errutil . UserError {
Err : fmt . Sprintf (
"Either ttl or not_after should be provided. Both should not be provided in the same request." ) ,
}
}
2015-08-29 13:03:02 +00:00
2018-05-09 14:29:54 +00:00
if ttl == 0 && data . role . TTL > 0 {
ttl = data . role . TTL
2018-03-20 01:01:41 +00:00
}
2018-05-09 14:29:54 +00:00
if data . role . MaxTTL > 0 {
maxTTL = data . role . MaxTTL
2015-11-19 21:51:27 +00:00
}
2015-10-03 01:02:16 +00:00
2017-08-31 19:46:13 +00:00
if ttl == 0 {
ttl = b . System ( ) . DefaultLeaseTTL ( )
}
if maxTTL == 0 {
maxTTL = b . System ( ) . MaxLeaseTTL ( )
}
2015-11-19 21:51:27 +00:00
if ttl > maxTTL {
2017-08-31 19:46:13 +00:00
ttl = maxTTL
2015-11-19 21:51:27 +00:00
}
2015-10-02 18:27:30 +00:00
2021-11-11 00:09:06 +00:00
if notAfterAlt != "" {
notAfter , err = time . Parse ( time . RFC3339 , notAfterAlt )
if err != nil {
return nil , errutil . UserError { Err : err . Error ( ) }
}
} else {
notAfter = time . Now ( ) . Add ( ttl )
}
2015-11-19 21:51:27 +00:00
// If it's not self-signed, verify that the issued certificate won't be
// valid past the lifetime of the CA certificate
2019-05-09 15:43:11 +00:00
if caSign != nil &&
notAfter . After ( caSign . Certificate . NotAfter ) && ! data . role . AllowExpirationPastCA {
2015-08-29 13:03:02 +00:00
2019-05-09 15:43:11 +00:00
return nil , errutil . UserError { Err : fmt . Sprintf (
"cannot satisfy request, as TTL would result in notAfter %s that is beyond the expiration of the CA certificate at %s" , notAfter . Format ( time . RFC3339Nano ) , caSign . Certificate . NotAfter . Format ( time . RFC3339Nano ) ) }
}
}
creation := & certutil . CreationBundle {
Params : & certutil . CreationParameters {
Subject : subject ,
2019-10-28 16:31:56 +00:00
DNSNames : strutil . RemoveDuplicates ( dnsNames , false ) ,
EmailAddresses : strutil . RemoveDuplicates ( emailAddresses , false ) ,
2019-05-09 15:43:11 +00:00
IPAddresses : ipAddresses ,
URIs : URIs ,
OtherSANs : otherSANs ,
KeyType : data . role . KeyType ,
KeyBits : data . role . KeyBits ,
2021-09-10 21:39:05 +00:00
SignatureBits : data . role . SignatureBits ,
2019-05-09 15:43:11 +00:00
NotAfter : notAfter ,
KeyUsage : x509 . KeyUsage ( parseKeyUsages ( data . role . KeyUsage ) ) ,
ExtKeyUsage : parseExtKeyUsages ( data . role ) ,
ExtKeyUsageOIDs : data . role . ExtKeyUsageOIDs ,
PolicyIdentifiers : data . role . PolicyIdentifiers ,
BasicConstraintsValidForNonCA : data . role . BasicConstraintsValidForNonCA ,
NotBeforeDuration : data . role . NotBeforeDuration ,
} ,
SigningBundle : caSign ,
CSR : csr ,
2015-08-29 13:03:02 +00:00
}
2015-11-19 21:51:27 +00:00
// Don't deal with URLs or max path length if it's self-signed, as these
// normally come from the signing bundle
2019-05-09 15:43:11 +00:00
if caSign == nil {
return creation , nil
2015-11-16 16:42:06 +00:00
}
2015-10-14 19:53:57 +00:00
2015-11-19 21:51:27 +00:00
// This will have been read in from the getURLs function
2019-05-09 15:43:11 +00:00
creation . Params . URLs = caSign . URLs
2015-11-19 21:51:27 +00:00
// If the max path length in the role is not nil, it was specified at
// generation time with the max_path_length parameter; otherwise derive it
// from the signing certificate
2018-02-16 22:19:34 +00:00
if data . role . MaxPathLength != nil {
2019-05-09 15:43:11 +00:00
creation . Params . MaxPathLength = * data . role . MaxPathLength
2015-11-16 16:42:06 +00:00
} else {
switch {
2019-05-09 15:43:11 +00:00
case caSign . Certificate . MaxPathLen < 0 :
creation . Params . MaxPathLength = - 1
case caSign . Certificate . MaxPathLen == 0 &&
caSign . Certificate . MaxPathLenZero :
2015-11-16 16:42:06 +00:00
// The signing function will ensure that we do not issue a CA cert
2019-05-09 15:43:11 +00:00
creation . Params . MaxPathLength = 0
2015-11-16 16:42:06 +00:00
default :
// If this takes it to zero, we handle this case later if
// necessary
2019-05-09 15:43:11 +00:00
creation . Params . MaxPathLength = caSign . Certificate . MaxPathLen - 1
2015-10-14 19:53:57 +00:00
}
2015-10-14 01:13:40 +00:00
}
2019-05-09 15:43:11 +00:00
return creation , nil
2015-05-15 16:13:05 +00:00
}
2017-08-15 20:10:36 +00:00
2017-11-06 17:05:07 +00:00
func convertRespToPKCS8 ( resp * logical . Response ) error {
privRaw , ok := resp . Data [ "private_key" ]
if ! ok {
return nil
}
priv , ok := privRaw . ( string )
if ! ok {
return fmt . Errorf ( "error converting response to pkcs8: could not parse original value as string" )
}
privKeyTypeRaw , ok := resp . Data [ "private_key_type" ]
if ! ok {
return fmt . Errorf ( "error converting response to pkcs8: %q not found in response" , "private_key_type" )
}
privKeyType , ok := privKeyTypeRaw . ( certutil . PrivateKeyType )
if ! ok {
return fmt . Errorf ( "error converting response to pkcs8: could not parse original type value as string" )
}
var keyData [ ] byte
var pemUsed bool
var err error
var signer crypto . Signer
block , _ := pem . Decode ( [ ] byte ( priv ) )
if block == nil {
keyData , err = base64 . StdEncoding . DecodeString ( priv )
if err != nil {
2021-04-22 15:20:59 +00:00
return fmt . Errorf ( "error converting response to pkcs8: error decoding original value: %w" , err )
2017-11-06 17:05:07 +00:00
}
} else {
keyData = block . Bytes
pemUsed = true
}
switch privKeyType {
case certutil . RSAPrivateKey :
signer , err = x509 . ParsePKCS1PrivateKey ( keyData )
case certutil . ECPrivateKey :
signer , err = x509 . ParseECPrivateKey ( keyData )
2021-11-24 19:24:06 +00:00
case certutil . Ed25519PrivateKey :
k , err := x509 . ParsePKCS8PrivateKey ( keyData )
if err != nil {
return fmt . Errorf ( "error converting response to pkcs8: error parsing previous key: %w" , err )
}
signer = k . ( crypto . Signer )
2017-11-06 17:05:07 +00:00
default :
return fmt . Errorf ( "unknown private key type %q" , privKeyType )
}
if err != nil {
2021-04-22 15:20:59 +00:00
return fmt . Errorf ( "error converting response to pkcs8: error parsing previous key: %w" , err )
2017-11-06 17:05:07 +00:00
}
2018-03-29 19:32:16 +00:00
keyData , err = x509 . MarshalPKCS8PrivateKey ( signer )
2017-11-06 17:05:07 +00:00
if err != nil {
2021-04-22 15:20:59 +00:00
return fmt . Errorf ( "error converting response to pkcs8: error marshaling pkcs8 key: %w" , err )
2017-11-06 17:05:07 +00:00
}
if pemUsed {
block . Type = "PRIVATE KEY"
block . Bytes = keyData
2018-03-18 20:00:51 +00:00
resp . Data [ "private_key" ] = strings . TrimSpace ( string ( pem . EncodeToMemory ( block ) ) )
2017-11-06 17:05:07 +00:00
} else {
resp . Data [ "private_key" ] = base64 . StdEncoding . EncodeToString ( keyData )
}
return nil
}
2019-12-11 15:16:44 +00:00
func handleOtherCSRSANs ( in * x509 . CertificateRequest , sans map [ string ] [ ] string ) error {
certTemplate := & x509 . Certificate {
DNSNames : in . DNSNames ,
IPAddresses : in . IPAddresses ,
EmailAddresses : in . EmailAddresses ,
URIs : in . URIs ,
}
if err := handleOtherSANs ( certTemplate , sans ) ; err != nil {
return err
}
if len ( certTemplate . ExtraExtensions ) > 0 {
for _ , v := range certTemplate . ExtraExtensions {
in . ExtraExtensions = append ( in . ExtraExtensions , v )
}
}
return nil
}
func handleOtherSANs ( in * x509 . Certificate , sans map [ string ] [ ] string ) error {
// If other SANs is empty we return which causes normal Go stdlib parsing
// of the other SAN types
if len ( sans ) == 0 {
return nil
}
var rawValues [ ] asn1 . RawValue
// We need to generate an IMPLICIT sequence for compatibility with OpenSSL
// -- it's an open question what the default for RFC 5280 actually is, see
// https://github.com/openssl/openssl/issues/5091 -- so we have to use
// cryptobyte because using the asn1 package's marshaling always produces
// an EXPLICIT sequence. Note that asn1 is way too magical according to
// agl, and cryptobyte is modeled after the CBB/CBS bits that agl put into
// boringssl.
for oid , vals := range sans {
for _ , val := range vals {
var b cryptobyte . Builder
oidStr , err := stringToOid ( oid )
if err != nil {
return err
}
b . AddASN1ObjectIdentifier ( oidStr )
b . AddASN1 ( cbbasn1 . Tag ( 0 ) . ContextSpecific ( ) . Constructed ( ) , func ( b * cryptobyte . Builder ) {
b . AddASN1 ( cbbasn1 . UTF8String , func ( b * cryptobyte . Builder ) {
b . AddBytes ( [ ] byte ( val ) )
} )
} )
m , err := b . Bytes ( )
if err != nil {
return err
}
rawValues = append ( rawValues , asn1 . RawValue { Tag : 0 , Class : 2 , IsCompound : true , Bytes : m } )
}
}
// If other SANs is empty we return which causes normal Go stdlib parsing
// of the other SAN types
if len ( rawValues ) == 0 {
return nil
}
// Append any existing SANs, sans marshalling
rawValues = append ( rawValues , marshalSANs ( in . DNSNames , in . EmailAddresses , in . IPAddresses , in . URIs ) ... )
// Marshal and add to ExtraExtensions
ext := pkix . Extension {
// This is the defined OID for subjectAltName
Id : asn1 . ObjectIdentifier ( oidExtensionSubjectAltName ) ,
}
var err error
ext . Value , err = asn1 . Marshal ( rawValues )
if err != nil {
return err
}
in . ExtraExtensions = append ( in . ExtraExtensions , ext )
return nil
}
// Note: Taken from the Go source code since it's not public, and used in the
// modified function below (which also uses these consts upstream)
const (
nameTypeOther = 0
nameTypeEmail = 1
nameTypeDNS = 2
nameTypeURI = 6
nameTypeIP = 7
)
// Note: Taken from the Go source code since it's not public, plus changed to not marshal
// marshalSANs marshals a list of addresses into a the contents of an X.509
// SubjectAlternativeName extension.
func marshalSANs ( dnsNames , emailAddresses [ ] string , ipAddresses [ ] net . IP , uris [ ] * url . URL ) [ ] asn1 . RawValue {
var rawValues [ ] asn1 . RawValue
for _ , name := range dnsNames {
rawValues = append ( rawValues , asn1 . RawValue { Tag : nameTypeDNS , Class : 2 , Bytes : [ ] byte ( name ) } )
}
for _ , email := range emailAddresses {
rawValues = append ( rawValues , asn1 . RawValue { Tag : nameTypeEmail , Class : 2 , Bytes : [ ] byte ( email ) } )
}
for _ , rawIP := range ipAddresses {
// If possible, we always want to encode IPv4 addresses in 4 bytes.
ip := rawIP . To4 ( )
if ip == nil {
ip = rawIP
}
rawValues = append ( rawValues , asn1 . RawValue { Tag : nameTypeIP , Class : 2 , Bytes : ip } )
}
for _ , uri := range uris {
rawValues = append ( rawValues , asn1 . RawValue { Tag : nameTypeURI , Class : 2 , Bytes : [ ] byte ( uri . String ( ) ) } )
}
return rawValues
}
func stringToOid ( in string ) ( asn1 . ObjectIdentifier , error ) {
split := strings . Split ( in , "." )
ret := make ( asn1 . ObjectIdentifier , 0 , len ( split ) )
for _ , v := range split {
i , err := strconv . Atoi ( v )
if err != nil {
return nil , err
}
ret = append ( ret , i )
}
2022-03-23 19:19:56 +00:00
return ret , nil
2019-12-11 15:16:44 +00:00
}