mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-10-29 17:52:32 +00:00
Fix missing permitted_dns_domains parameter when signing certificates (#29436)
* Use PermittedDNSDomains parameter when signing certificates. * Add missing name constraints extension docs for PKI root/generate.
This commit is contained in:
@@ -20,6 +20,7 @@ import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
mathrand "math/rand"
|
||||
"net"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -27,6 +28,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/fatih/structs"
|
||||
"github.com/go-test/deep"
|
||||
"github.com/hashicorp/vault/sdk/helper/cryptoutil"
|
||||
)
|
||||
|
||||
@@ -1107,6 +1109,114 @@ func TestIgnoreCSRSigning(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// TestSignIntermediat_name_constraints verifies that all the name constraints extension fields are
|
||||
// used when signing a certificate.
|
||||
func TestSignCertificate_name_constraints(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
caKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatalf("failed generating ca key: %v", err)
|
||||
}
|
||||
subjKeyID, err := GetSubjKeyID(caKey)
|
||||
if err != nil {
|
||||
t.Fatalf("failed generating ca subject key id: %v", err)
|
||||
}
|
||||
caCertTemplate := &x509.Certificate{
|
||||
Subject: pkix.Name{
|
||||
CommonName: "root.localhost",
|
||||
},
|
||||
SubjectKeyId: subjKeyID,
|
||||
DNSNames: []string{"root.localhost"},
|
||||
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
|
||||
SerialNumber: big.NewInt(mathrand.Int63()),
|
||||
NotBefore: time.Now().Add(-30 * time.Second),
|
||||
NotAfter: time.Now().Add(262980 * time.Hour),
|
||||
BasicConstraintsValid: true,
|
||||
IsCA: true,
|
||||
}
|
||||
caBytes, err := x509.CreateCertificate(rand.Reader, caCertTemplate, caCertTemplate, caKey.Public(), caKey)
|
||||
if err != nil {
|
||||
t.Fatalf("failed creating ca certificate: %v", err)
|
||||
}
|
||||
caCert, err := x509.ParseCertificate(caBytes)
|
||||
if err != nil {
|
||||
t.Fatalf("failed parsing ca certificate: %v", err)
|
||||
}
|
||||
|
||||
signingBundle := &CAInfoBundle{
|
||||
ParsedCertBundle: ParsedCertBundle{
|
||||
PrivateKeyType: ECPrivateKey,
|
||||
PrivateKey: caKey,
|
||||
CertificateBytes: caBytes,
|
||||
Certificate: caCert,
|
||||
CAChain: nil,
|
||||
},
|
||||
URLs: &URLEntries{},
|
||||
}
|
||||
|
||||
key := genEdDSA(t)
|
||||
csr := &x509.CertificateRequest{
|
||||
PublicKeyAlgorithm: x509.ECDSA,
|
||||
PublicKey: key.Public(),
|
||||
Subject: pkix.Name{
|
||||
CommonName: "test.dadgarcorp.com",
|
||||
},
|
||||
}
|
||||
_, ipnet1, err := net.ParseCIDR("1.2.3.4/32")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, ipnet2, err := net.ParseCIDR("1.2.3.4/16")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
params := &CreationParameters{
|
||||
IgnoreCSRSignature: true,
|
||||
URLs: &URLEntries{},
|
||||
NotAfter: time.Now().Add(10000 * time.Hour),
|
||||
PermittedDNSDomains: []string{"example.com", ".example.com"},
|
||||
ExcludedDNSDomains: []string{"bad.example.com"},
|
||||
PermittedIPRanges: []*net.IPNet{ipnet1},
|
||||
ExcludedIPRanges: []*net.IPNet{ipnet2},
|
||||
PermittedEmailAddresses: []string{"one@example.com", "two@example.com"},
|
||||
ExcludedEmailAddresses: []string{"un@example.com", "deux@example.com"},
|
||||
PermittedURIDomains: []string{"domain1", "domain2"},
|
||||
ExcludedURIDomains: []string{"domain3", "domain4"},
|
||||
}
|
||||
data := &CreationBundle{
|
||||
Params: params,
|
||||
SigningBundle: signingBundle,
|
||||
CSR: csr,
|
||||
}
|
||||
|
||||
parsedBundle, err := SignCertificate(data)
|
||||
if err != nil {
|
||||
t.Fatal("should have failed signing csr with ignore csr signature disabled")
|
||||
}
|
||||
|
||||
var failedChecks []error
|
||||
check := func(fieldName string, expected any, actual any) {
|
||||
diff := deep.Equal(expected, actual)
|
||||
if len(diff) > 0 {
|
||||
failedChecks = append(failedChecks, fmt.Errorf("error in field %q: %v", fieldName, diff))
|
||||
}
|
||||
}
|
||||
cert := parsedBundle.Certificate
|
||||
check("PermittedDNSDomains", params.PermittedDNSDomains, cert.PermittedDNSDomains)
|
||||
check("ExcludedDNSDomains", params.ExcludedDNSDomains, cert.ExcludedDNSDomains)
|
||||
check("PermittedIPRanges", params.PermittedIPRanges, cert.PermittedIPRanges)
|
||||
check("ExcludedIPRanges", params.ExcludedIPRanges, cert.ExcludedIPRanges)
|
||||
check("PermittedEmailAddresses", params.PermittedEmailAddresses, cert.PermittedEmailAddresses)
|
||||
check("ExcludedEmailAddresses", params.ExcludedEmailAddresses, cert.ExcludedEmailAddresses)
|
||||
check("PermittedURIDomains", params.PermittedURIDomains, cert.PermittedURIDomains)
|
||||
check("ExcludedURIDomains", params.ExcludedURIDomains, cert.ExcludedURIDomains)
|
||||
|
||||
if err := errors.Join(failedChecks...); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func genRsaKey(t *testing.T) *rsa.PrivateKey {
|
||||
key, err := cryptoutil.GenerateRSAKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
|
||||
@@ -1360,6 +1360,7 @@ func signCertificate(data *CreationBundle, randReader io.Reader) (*ParsedCertBun
|
||||
certTemplate.IsCA = false
|
||||
}
|
||||
|
||||
certTemplate.PermittedDNSDomains = append(certTemplate.PermittedDNSDomains, data.Params.PermittedDNSDomains...)
|
||||
certTemplate.ExcludedDNSDomains = append(certTemplate.ExcludedDNSDomains, data.Params.ExcludedDNSDomains...)
|
||||
certTemplate.PermittedIPRanges = append(certTemplate.PermittedIPRanges, data.Params.PermittedIPRanges...)
|
||||
certTemplate.ExcludedIPRanges = append(certTemplate.ExcludedIPRanges, data.Params.ExcludedIPRanges...)
|
||||
|
||||
@@ -2180,6 +2180,44 @@ use the values set via `config/urls`.
|
||||
[RFC 5280 Section 4.2.1.10 - Name
|
||||
Constraints](https://tools.ietf.org/html/rfc5280#section-4.2.1.10).
|
||||
|
||||
- `excluded_dns_domains` `(string: "")` - A comma separated string (or, string
|
||||
array) containing DNS domains for which certificates are not allowed to be issued
|
||||
or signed by this CA certificate. Supports subdomains via a `.` in front of
|
||||
the domain, as per [RFC 5280 Section 4.2.1.10 - Name
|
||||
Constraints](https://tools.ietf.org/html/rfc5280#section-4.2.1.10)
|
||||
|
||||
- `permitted_ip_ranges` `(string: "")` - A comma separated string (or, string
|
||||
array) containing IP ranges for which certificates are allowed to be issued or
|
||||
signed by this CA certificate. IP ranges must be in the CIDR notation of IP
|
||||
address and prefix length like "192.0.2.0/24" or "2001:db8::/32", as defined
|
||||
in RFC 4632 and RFC 4291.
|
||||
|
||||
- `excluded_ip_ranges` `(string: "")` - A comma separated string (or, string
|
||||
array) containing IP ranges for which certificates are not allowed to be
|
||||
issued or signed by this CA certificate. IP ranges must be in the CIDR
|
||||
notation of IP address and prefix length like "192.0.2.0/24" or
|
||||
"2001:db8::/32", as defined in RFC 4632 and RFC 4291.
|
||||
|
||||
- `permitted_email_addresses` `(string: "")` - A comma separated string (or, string
|
||||
array) containing email addresses for which certificates are allowed to be issued or
|
||||
signed by this CA certificate.
|
||||
|
||||
- `excluded_email_addresses` `(string: "")` - A comma separated string (or,
|
||||
string array) containing email addresses for which certificates are not
|
||||
allowed to be issued or signed by this CA certificate.
|
||||
|
||||
- `permitted_uri_domains` `(string: "")` - A comma separated string (or, string
|
||||
array) containing fully qualified domain names for which certificates are
|
||||
allowed to be issued or signed by this CA certificate. Supports subdomains via
|
||||
a `.` in front of the domain, as per [RFC 5280 Section 4.2.1.10 - Name
|
||||
Constraints](https://tools.ietf.org/html/rfc5280#section-4.2.1.10)
|
||||
|
||||
- `excluded_uri_domains` `(string: "")` - A comma separated string (or, string
|
||||
array) containing fully qualified domain names for which certificates are not
|
||||
allowed to be issued or signed by this CA certificate. Supports subdomains via
|
||||
a `.` in front of the domain, as per [RFC 5280 Section 4.2.1.10 - Name
|
||||
Constraints](https://tools.ietf.org/html/rfc5280#section-4.2.1.10)
|
||||
|
||||
- `ou` `(string: "")` - Specifies the OU (OrganizationalUnit) values in the
|
||||
subject field of the resulting certificate. This is a comma-separated string
|
||||
or JSON array.
|
||||
|
||||
Reference in New Issue
Block a user