From 61e0eda70c6095253b5711877fc92ee6c2c72ef3 Mon Sep 17 00:00:00 2001 From: Nicholas Jackson Date: Fri, 25 May 2018 16:34:46 +0200 Subject: [PATCH] Breakout parameters for x.509 certificate login (#4463) --- builtin/credential/cert/backend_test.go | 209 ++++++++++++++---- builtin/credential/cert/path_certs.go | 61 ++++- builtin/credential/cert/path_login.go | 80 +++++++ .../cert/test-fixtures/root/rootcacert.srl | 2 +- .../cert/test-fixtures/root/rootcawdns.cnf | 17 ++ .../cert/test-fixtures/root/rootcawdns.csr | 27 +++ .../test-fixtures/root/rootcawdnscert.pem | 23 ++ .../cert/test-fixtures/root/rootcawdnskey.pem | 52 +++++ .../cert/test-fixtures/root/rootcawemail.cnf | 17 ++ .../cert/test-fixtures/root/rootcawemail.csr | 27 +++ .../test-fixtures/root/rootcawemailcert.pem | 23 ++ .../test-fixtures/root/rootcawemailkey.pem | 52 +++++ .../cert/test-fixtures/root/rootcawext.cnf | 5 - .../cert/test-fixtures/root/rootcawuri.cnf | 18 ++ .../cert/test-fixtures/root/rootcawuri.csr | 17 ++ .../test-fixtures/root/rootcawuricert.pem | 18 ++ .../cert/test-fixtures/root/rootcawurikey.pem | 28 +++ website/source/api/auth/cert/index.html.md | 23 ++ 18 files changed, 646 insertions(+), 53 deletions(-) create mode 100644 builtin/credential/cert/test-fixtures/root/rootcawdns.cnf create mode 100644 builtin/credential/cert/test-fixtures/root/rootcawdns.csr create mode 100644 builtin/credential/cert/test-fixtures/root/rootcawdnscert.pem create mode 100644 builtin/credential/cert/test-fixtures/root/rootcawdnskey.pem create mode 100644 builtin/credential/cert/test-fixtures/root/rootcawemail.cnf create mode 100644 builtin/credential/cert/test-fixtures/root/rootcawemail.csr create mode 100644 builtin/credential/cert/test-fixtures/root/rootcawemailcert.pem create mode 100644 builtin/credential/cert/test-fixtures/root/rootcawemailkey.pem create mode 100644 builtin/credential/cert/test-fixtures/root/rootcawuri.cnf create mode 100644 builtin/credential/cert/test-fixtures/root/rootcawuri.csr create mode 100644 builtin/credential/cert/test-fixtures/root/rootcawuricert.pem create mode 100644 builtin/credential/cert/test-fixtures/root/rootcawurikey.pem diff --git a/builtin/credential/cert/backend_test.go b/builtin/credential/cert/backend_test.go index 8942e736697d..8b62ec075420 100644 --- a/builtin/credential/cert/backend_test.go +++ b/builtin/credential/cert/backend_test.go @@ -843,9 +843,9 @@ func TestBackend_CertWrites(t *testing.T) { tc := logicaltest.TestCase{ Backend: testFactory(t), Steps: []logicaltest.TestStep{ - testAccStepCert(t, "aaa", ca1, "foo", "", "", false), - testAccStepCert(t, "bbb", ca2, "foo", "", "", false), - testAccStepCert(t, "ccc", ca3, "foo", "", "", true), + testAccStepCert(t, "aaa", ca1, "foo", allowed{}, false), + testAccStepCert(t, "bbb", ca2, "foo", allowed{}, false), + testAccStepCert(t, "ccc", ca3, "foo", allowed{}, true), }, } tc.Steps = append(tc.Steps, testAccStepListCerts(t, []string{"aaa", "bbb"})...) @@ -866,7 +866,7 @@ func TestBackend_basic_CA(t *testing.T) { logicaltest.Test(t, logicaltest.TestCase{ Backend: testFactory(t), Steps: []logicaltest.TestStep{ - testAccStepCert(t, "web", ca, "foo", "", "", false), + testAccStepCert(t, "web", ca, "foo", allowed{}, false), testAccStepLogin(t, connState), testAccStepCertLease(t, "web", ca, "foo"), testAccStepCertTTL(t, "web", ca, "foo"), @@ -875,9 +875,9 @@ func TestBackend_basic_CA(t *testing.T) { testAccStepLogin(t, connState), testAccStepCertNoLease(t, "web", ca, "foo"), testAccStepLoginDefaultLease(t, connState), - testAccStepCert(t, "web", ca, "foo", "*.example.com", "", false), + testAccStepCert(t, "web", ca, "foo", allowed{names: "*.example.com"}, false), testAccStepLogin(t, connState), - testAccStepCert(t, "web", ca, "foo", "*.invalid.com", "", false), + testAccStepCert(t, "web", ca, "foo", allowed{names: "*.invalid.com"}, false), testAccStepLoginInvalid(t, connState), }, }) @@ -926,20 +926,45 @@ func TestBackend_basic_singleCert(t *testing.T) { logicaltest.Test(t, logicaltest.TestCase{ Backend: testFactory(t), Steps: []logicaltest.TestStep{ - testAccStepCert(t, "web", ca, "foo", "", "", false), + testAccStepCert(t, "web", ca, "foo", allowed{}, false), testAccStepLogin(t, connState), - testAccStepCert(t, "web", ca, "foo", "example.com", "", false), + testAccStepCert(t, "web", ca, "foo", allowed{names: "example.com"}, false), testAccStepLogin(t, connState), - testAccStepCert(t, "web", ca, "foo", "invalid", "", false), + testAccStepCert(t, "web", ca, "foo", allowed{names: "invalid"}, false), testAccStepLoginInvalid(t, connState), - testAccStepCert(t, "web", ca, "foo", "", "1.2.3.4:invalid", false), + testAccStepCert(t, "web", ca, "foo", allowed{ext: "1.2.3.4:invalid"}, false), testAccStepLoginInvalid(t, connState), }, }) } -// Test a self-signed client with custom extensions (root CA) that is trusted -func TestBackend_extensions_singleCert(t *testing.T) { +func TestBackend_common_name_singleCert(t *testing.T) { + connState, err := testConnState("test-fixtures/root/rootcacert.pem", + "test-fixtures/root/rootcakey.pem", "test-fixtures/root/rootcacert.pem") + if err != nil { + t.Fatalf("error testing connection state: %v", err) + } + ca, err := ioutil.ReadFile("test-fixtures/root/rootcacert.pem") + if err != nil { + t.Fatalf("err: %v", err) + } + logicaltest.Test(t, logicaltest.TestCase{ + Backend: testFactory(t), + Steps: []logicaltest.TestStep{ + testAccStepCert(t, "web", ca, "foo", allowed{}, false), + testAccStepLogin(t, connState), + testAccStepCert(t, "web", ca, "foo", allowed{common_names: "example.com"}, false), + testAccStepLogin(t, connState), + testAccStepCert(t, "web", ca, "foo", allowed{common_names: "invalid"}, false), + testAccStepLoginInvalid(t, connState), + testAccStepCert(t, "web", ca, "foo", allowed{ext: "1.2.3.4:invalid"}, false), + testAccStepLoginInvalid(t, connState), + }, + }) +} + +// Test a self-signed client with custom ext (root CA) that is trusted +func TestBackend_ext_singleCert(t *testing.T) { connState, err := testConnState( "test-fixtures/root/rootcawextcert.pem", "test-fixtures/root/rootcawextkey.pem", @@ -955,39 +980,132 @@ func TestBackend_extensions_singleCert(t *testing.T) { logicaltest.Test(t, logicaltest.TestCase{ Backend: testFactory(t), Steps: []logicaltest.TestStep{ - testAccStepCert(t, "web", ca, "foo", "", "2.1.1.1:A UTF8String Extension", false), + testAccStepCert(t, "web", ca, "foo", allowed{ext: "2.1.1.1:A UTF8String Extension"}, false), testAccStepLogin(t, connState), - testAccStepCert(t, "web", ca, "foo", "", "2.1.1.1:*,2.1.1.2:A UTF8*", false), + testAccStepCert(t, "web", ca, "foo", allowed{ext: "2.1.1.1:*,2.1.1.2:A UTF8*"}, false), testAccStepLogin(t, connState), - testAccStepCert(t, "web", ca, "foo", "", "1.2.3.45:*", false), + testAccStepCert(t, "web", ca, "foo", allowed{ext: "1.2.3.45:*"}, false), + testAccStepLoginInvalid(t, connState), + testAccStepCert(t, "web", ca, "foo", allowed{ext: "2.1.1.1:The Wrong Value"}, false), testAccStepLoginInvalid(t, connState), - testAccStepCert(t, "web", ca, "foo", "", "2.1.1.1:The Wrong Value", false), + testAccStepCert(t, "web", ca, "foo", allowed{ext: "2.1.1.1:*,2.1.1.2:The Wrong Value"}, false), testAccStepLoginInvalid(t, connState), - testAccStepCert(t, "web", ca, "foo", "", "2.1.1.1:*,2.1.1.2:The Wrong Value", false), + testAccStepCert(t, "web", ca, "foo", allowed{ext: "2.1.1.1:"}, false), testAccStepLoginInvalid(t, connState), - testAccStepCert(t, "web", ca, "foo", "", "2.1.1.1:", false), + testAccStepCert(t, "web", ca, "foo", allowed{ext: "2.1.1.1:,2.1.1.2:*"}, false), testAccStepLoginInvalid(t, connState), - testAccStepCert(t, "web", ca, "foo", "", "2.1.1.1:,2.1.1.2:*", false), + testAccStepCert(t, "web", ca, "foo", allowed{names: "example.com", ext: "2.1.1.1:A UTF8String Extension"}, false), + testAccStepLogin(t, connState), + testAccStepCert(t, "web", ca, "foo", allowed{names: "example.com", ext: "2.1.1.1:*,2.1.1.2:A UTF8*"}, false), + testAccStepLogin(t, connState), + testAccStepCert(t, "web", ca, "foo", allowed{names: "example.com", ext: "1.2.3.45:*"}, false), testAccStepLoginInvalid(t, connState), - testAccStepCert(t, "web", ca, "foo", "example.com", "2.1.1.1:A UTF8String Extension", false), + testAccStepCert(t, "web", ca, "foo", allowed{names: "example.com", ext: "2.1.1.1:The Wrong Value"}, false), + testAccStepLoginInvalid(t, connState), + testAccStepCert(t, "web", ca, "foo", allowed{names: "example.com", ext: "2.1.1.1:*,2.1.1.2:The Wrong Value"}, false), + testAccStepLoginInvalid(t, connState), + testAccStepCert(t, "web", ca, "foo", allowed{names: "invalid", ext: "2.1.1.1:A UTF8String Extension"}, false), + testAccStepLoginInvalid(t, connState), + testAccStepCert(t, "web", ca, "foo", allowed{names: "invalid", ext: "2.1.1.1:*,2.1.1.2:A UTF8*"}, false), + testAccStepLoginInvalid(t, connState), + testAccStepCert(t, "web", ca, "foo", allowed{names: "invalid", ext: "1.2.3.45:*"}, false), + testAccStepLoginInvalid(t, connState), + testAccStepCert(t, "web", ca, "foo", allowed{names: "invalid", ext: "2.1.1.1:The Wrong Value"}, false), + testAccStepLoginInvalid(t, connState), + testAccStepCert(t, "web", ca, "foo", allowed{names: "invalid", ext: "2.1.1.1:*,2.1.1.2:The Wrong Value"}, false), + testAccStepLoginInvalid(t, connState), + }, + }) +} + +// Test a self-signed client with URI alt names (root CA) that is trusted +func TestBackend_dns_singleCert(t *testing.T) { + connState, err := testConnState( + "test-fixtures/root/rootcawdnscert.pem", + "test-fixtures/root/rootcawdnskey.pem", + "test-fixtures/root/rootcacert.pem", + ) + if err != nil { + t.Fatalf("error testing connection state: %v", err) + } + ca, err := ioutil.ReadFile("test-fixtures/root/rootcacert.pem") + if err != nil { + t.Fatalf("err: %v", err) + } + logicaltest.Test(t, logicaltest.TestCase{ + Backend: testFactory(t), + Steps: []logicaltest.TestStep{ + testAccStepCert(t, "web", ca, "foo", allowed{dns: "example.com"}, false), testAccStepLogin(t, connState), - testAccStepCert(t, "web", ca, "foo", "example.com", "2.1.1.1:*,2.1.1.2:A UTF8*", false), + testAccStepCert(t, "web", ca, "foo", allowed{dns: "*ample.com"}, false), testAccStepLogin(t, connState), - testAccStepCert(t, "web", ca, "foo", "example.com", "1.2.3.45:*", false), + testAccStepCert(t, "web", ca, "foo", allowed{dns: "notincert.com"}, false), testAccStepLoginInvalid(t, connState), - testAccStepCert(t, "web", ca, "foo", "example.com", "2.1.1.1:The Wrong Value", false), + testAccStepCert(t, "web", ca, "foo", allowed{dns: "abc"}, false), testAccStepLoginInvalid(t, connState), - testAccStepCert(t, "web", ca, "foo", "example.com", "2.1.1.1:*,2.1.1.2:The Wrong Value", false), + testAccStepCert(t, "web", ca, "foo", allowed{dns: "*.example.com"}, false), testAccStepLoginInvalid(t, connState), - testAccStepCert(t, "web", ca, "foo", "invalid", "2.1.1.1:A UTF8String Extension", false), + }, + }) +} + +// Test a self-signed client with URI alt names (root CA) that is trusted +func TestBackend_email_singleCert(t *testing.T) { + connState, err := testConnState( + "test-fixtures/root/rootcawemailcert.pem", + "test-fixtures/root/rootcawemailkey.pem", + "test-fixtures/root/rootcacert.pem", + ) + if err != nil { + t.Fatalf("error testing connection state: %v", err) + } + ca, err := ioutil.ReadFile("test-fixtures/root/rootcacert.pem") + if err != nil { + t.Fatalf("err: %v", err) + } + logicaltest.Test(t, logicaltest.TestCase{ + Backend: testFactory(t), + Steps: []logicaltest.TestStep{ + testAccStepCert(t, "web", ca, "foo", allowed{emails: "valid@example.com"}, false), + testAccStepLogin(t, connState), + testAccStepCert(t, "web", ca, "foo", allowed{emails: "*@example.com"}, false), + testAccStepLogin(t, connState), + testAccStepCert(t, "web", ca, "foo", allowed{emails: "invalid@notincert.com"}, false), testAccStepLoginInvalid(t, connState), - testAccStepCert(t, "web", ca, "foo", "invalid", "2.1.1.1:*,2.1.1.2:A UTF8*", false), + testAccStepCert(t, "web", ca, "foo", allowed{emails: "abc"}, false), testAccStepLoginInvalid(t, connState), - testAccStepCert(t, "web", ca, "foo", "invalid", "1.2.3.45:*", false), + testAccStepCert(t, "web", ca, "foo", allowed{emails: "*.example.com"}, false), testAccStepLoginInvalid(t, connState), - testAccStepCert(t, "web", ca, "foo", "invalid", "2.1.1.1:The Wrong Value", false), + }, + }) +} + +// Test a self-signed client with URI alt names (root CA) that is trusted +func TestBackend_uri_singleCert(t *testing.T) { + connState, err := testConnState( + "test-fixtures/root/rootcawuricert.pem", + "test-fixtures/root/rootcawurikey.pem", + "test-fixtures/root/rootcacert.pem", + ) + if err != nil { + t.Fatalf("error testing connection state: %v", err) + } + ca, err := ioutil.ReadFile("test-fixtures/root/rootcacert.pem") + if err != nil { + t.Fatalf("err: %v", err) + } + logicaltest.Test(t, logicaltest.TestCase{ + Backend: testFactory(t), + Steps: []logicaltest.TestStep{ + testAccStepCert(t, "web", ca, "foo", allowed{uris: "spiffe://example.com/*"}, false), + testAccStepLogin(t, connState), + testAccStepCert(t, "web", ca, "foo", allowed{uris: "spiffe://example.com/host"}, false), + testAccStepLogin(t, connState), + testAccStepCert(t, "web", ca, "foo", allowed{uris: "spiffe://example.com/invalid"}, false), testAccStepLoginInvalid(t, connState), - testAccStepCert(t, "web", ca, "foo", "invalid", "2.1.1.1:*,2.1.1.2:The Wrong Value", false), + testAccStepCert(t, "web", ca, "foo", allowed{uris: "abc"}, false), + testAccStepLoginInvalid(t, connState), + testAccStepCert(t, "web", ca, "foo", allowed{uris: "http://www.google.com"}, false), testAccStepLoginInvalid(t, connState), }, }) @@ -1007,9 +1125,9 @@ func TestBackend_mixed_constraints(t *testing.T) { logicaltest.Test(t, logicaltest.TestCase{ Backend: testFactory(t), Steps: []logicaltest.TestStep{ - testAccStepCert(t, "1unconstrained", ca, "foo", "", "", false), - testAccStepCert(t, "2matching", ca, "foo", "*.example.com,whatever", "", false), - testAccStepCert(t, "3invalid", ca, "foo", "invalid", "", false), + testAccStepCert(t, "1unconstrained", ca, "foo", allowed{}, false), + testAccStepCert(t, "2matching", ca, "foo", allowed{names: "*.example.com,whatever"}, false), + testAccStepCert(t, "3invalid", ca, "foo", allowed{names: "invalid"}, false), testAccStepLogin(t, connState), // Assumes CertEntries are processed in alphabetical order (due to store.List), so we only match 2matching if 1unconstrained doesn't match testAccStepLoginWithName(t, connState, "2matching"), @@ -1314,19 +1432,32 @@ func testAccStepListCerts( } } +type allowed struct { + names string // allowed names in the certificate, looks at common, name, dns, email [depricated] + common_names string // allowed common names in the certificate + dns string // allowed dns names in the SAN extension of the certificate + emails string // allowed email names in SAN extension of the certificate + uris string // allowed uris in SAN extension of the certificate + ext string // required extensions in the certificate +} + func testAccStepCert( - t *testing.T, name string, cert []byte, policies string, allowedNames string, requiredExtensions string, expectError bool) logicaltest.TestStep { + t *testing.T, name string, cert []byte, policies string, testData allowed, expectError bool) logicaltest.TestStep { return logicaltest.TestStep{ Operation: logical.UpdateOperation, Path: "certs/" + name, ErrorOk: expectError, Data: map[string]interface{}{ - "certificate": string(cert), - "policies": policies, - "display_name": name, - "allowed_names": allowedNames, - "required_extensions": requiredExtensions, - "lease": 1000, + "certificate": string(cert), + "policies": policies, + "display_name": name, + "allowed_names": testData.names, + "allowed_common_names": testData.common_names, + "allowed_dns_sans": testData.dns, + "allowed_email_sans": testData.emails, + "allowed_uri_sans": testData.uris, + "required_extensions": testData.ext, + "lease": 1000, }, Check: func(resp *logical.Response) error { if resp == nil && expectError { diff --git a/builtin/credential/cert/path_certs.go b/builtin/credential/cert/path_certs.go index 96c93ac56277..384cd47fd65a 100644 --- a/builtin/credential/cert/path_certs.go +++ b/builtin/credential/cert/path_certs.go @@ -45,7 +45,33 @@ Must be x509 PEM encoded.`, "allowed_names": &framework.FieldSchema{ Type: framework.TypeCommaStringSlice, Description: `A comma-separated list of names. -At least one must exist in either the Common Name or SANs. Supports globbing.`, +At least one must exist in either the Common Name or SANs. Supports globbing. +This parameter is deprecated, please use allowed_common_names, allowed_dns_sans, +allowed_email_sans, allowed_uri_sans.`, + }, + + "allowed_common_names": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: `A comma-separated list of names. +At least one must exist in the Common Name. Supports globbing.`, + }, + + "allowed_dns_sans": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: `A comma-separated list of DNS names. +At least one must exist in the SANs. Supports globbing.`, + }, + + "allowed_email_sans": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: `A comma-separated list of Email Addresses. +At least one must exist in the SANs. Supports globbing.`, + }, + + "allowed_uri_sans": &framework.FieldSchema{ + Type: framework.TypeCommaStringSlice, + Description: `A comma-separated list of URIs. +At least one must exist in the SANs. Supports globbing.`, }, "required_extensions": &framework.FieldSchema{ @@ -77,12 +103,14 @@ seconds. Defaults to system/backend default TTL.`, Description: `TTL for tokens issued by this backend. Defaults to system/backend default TTL time.`, }, + "max_ttl": &framework.FieldSchema{ Type: framework.TypeDurationSecond, Description: `Duration in either an integer number of seconds (3600) or an integer time unit (60m) after which the issued token can no longer be renewed.`, }, + "period": &framework.FieldSchema{ Type: framework.TypeDurationSecond, Description: `If set, indicates that the token generated using this role @@ -151,13 +179,18 @@ func (b *backend) pathCertRead(ctx context.Context, req *logical.Request, d *fra return &logical.Response{ Data: map[string]interface{}{ - "certificate": cert.Certificate, - "display_name": cert.DisplayName, - "policies": cert.Policies, - "ttl": cert.TTL / time.Second, - "max_ttl": cert.MaxTTL / time.Second, - "period": cert.Period / time.Second, - "allowed_names": cert.AllowedNames, + "certificate": cert.Certificate, + "display_name": cert.DisplayName, + "policies": cert.Policies, + "ttl": cert.TTL / time.Second, + "max_ttl": cert.MaxTTL / time.Second, + "period": cert.Period / time.Second, + "allowed_names": cert.AllowedNames, + "allowed_common_names": cert.AllowedCommonNames, + "allowed_dns_sans": cert.AllowedDNSSANs, + "allowed_email_sans": cert.AllowedEmailSANs, + "allowed_uri_sans": cert.AllowedURISANs, + "required_extensions": cert.RequiredExtensions, }, }, nil } @@ -168,6 +201,10 @@ func (b *backend) pathCertWrite(ctx context.Context, req *logical.Request, d *fr displayName := d.Get("display_name").(string) policies := policyutil.ParsePolicies(d.Get("policies")) allowedNames := d.Get("allowed_names").([]string) + allowedCommonNames := d.Get("allowed_common_names").([]string) + allowedDNSSANs := d.Get("allowed_dns_sans").([]string) + allowedEmailSANs := d.Get("allowed_email_sans").([]string) + allowedURISANs := d.Get("allowed_uri_sans").([]string) requiredExtensions := d.Get("required_extensions").([]string) var resp logical.Response @@ -246,6 +283,10 @@ func (b *backend) pathCertWrite(ctx context.Context, req *logical.Request, d *fr DisplayName: displayName, Policies: policies, AllowedNames: allowedNames, + AllowedCommonNames: allowedCommonNames, + AllowedDNSSANs: allowedDNSSANs, + AllowedEmailSANs: allowedEmailSANs, + AllowedURISANs: allowedURISANs, RequiredExtensions: requiredExtensions, TTL: ttl, MaxTTL: maxTTL, @@ -278,6 +319,10 @@ type CertEntry struct { MaxTTL time.Duration Period time.Duration AllowedNames []string + AllowedCommonNames []string + AllowedDNSSANs []string + AllowedEmailSANs []string + AllowedURISANs []string RequiredExtensions []string BoundCIDRs []*sockaddr.SockAddrMarshaler } diff --git a/builtin/credential/cert/path_login.go b/builtin/credential/cert/path_login.go index cf1c6c68f48e..a5a3d00d9207 100644 --- a/builtin/credential/cert/path_login.go +++ b/builtin/credential/cert/path_login.go @@ -103,6 +103,7 @@ func (b *backend) pathLogin(ctx context.Context, req *logical.Request, data *fra Renewable: true, TTL: matched.Entry.TTL, MaxTTL: matched.Entry.MaxTTL, + Period: matched.Entry.Period, }, Alias: &logical.Alias{ Name: clientCerts[0].Subject.CommonName, @@ -253,6 +254,10 @@ func (b *backend) verifyCredentials(ctx context.Context, req *logical.Request, d func (b *backend) matchesConstraints(clientCert *x509.Certificate, trustedChain []*x509.Certificate, config *ParsedCert) bool { return !b.checkForChainInCRLs(trustedChain) && b.matchesNames(clientCert, config) && + b.matchesCommonName(clientCert, config) && + b.matchesDNSSANs(clientCert, config) && + b.matchesEmailSANs(clientCert, config) && + b.matchesURISANs(clientCert, config) && b.matchesCertificateExtensions(clientCert, config) } @@ -280,7 +285,82 @@ func (b *backend) matchesNames(clientCert *x509.Certificate, config *ParsedCert) return true } } + + } + return false +} + +// matchesCommonName verifies that the certificate matches at least one configured +// allowed common name +func (b *backend) matchesCommonName(clientCert *x509.Certificate, config *ParsedCert) bool { + // Default behavior (no names) is to allow all names + if len(config.Entry.AllowedCommonNames) == 0 { + return true } + // At least one pattern must match at least one name if any patterns are specified + for _, allowedCommonName := range config.Entry.AllowedCommonNames { + if glob.Glob(allowedCommonName, clientCert.Subject.CommonName) { + return true + } + } + + return false +} + +// matchesDNSSANs verifies that the certificate matches at least one configured +// allowed dns entry in the subject alternate name extension +func (b *backend) matchesDNSSANs(clientCert *x509.Certificate, config *ParsedCert) bool { + // Default behavior (no names) is to allow all names + if len(config.Entry.AllowedDNSSANs) == 0 { + return true + } + // At least one pattern must match at least one name if any patterns are specified + for _, allowedDNS := range config.Entry.AllowedDNSSANs { + for _, name := range clientCert.DNSNames { + if glob.Glob(allowedDNS, name) { + return true + } + } + } + + return false +} + +// matchesEmailSANs verifies that the certificate matches at least one configured +// allowed email in the subject alternate name extension +func (b *backend) matchesEmailSANs(clientCert *x509.Certificate, config *ParsedCert) bool { + // Default behavior (no names) is to allow all names + if len(config.Entry.AllowedEmailSANs) == 0 { + return true + } + // At least one pattern must match at least one name if any patterns are specified + for _, allowedEmail := range config.Entry.AllowedEmailSANs { + for _, email := range clientCert.EmailAddresses { + if glob.Glob(allowedEmail, email) { + return true + } + } + } + + return false +} + +// matchesURISANs verifies that the certificate matches at least one configured +// allowed uri in the subject alternate name extension +func (b *backend) matchesURISANs(clientCert *x509.Certificate, config *ParsedCert) bool { + // Default behavior (no names) is to allow all names + if len(config.Entry.AllowedURISANs) == 0 { + return true + } + // At least one pattern must match at least one name if any patterns are specified + for _, allowedURI := range config.Entry.AllowedURISANs { + for _, name := range clientCert.URIs { + if glob.Glob(allowedURI, name.String()) { + return true + } + } + } + return false } diff --git a/builtin/credential/cert/test-fixtures/root/rootcacert.srl b/builtin/credential/cert/test-fixtures/root/rootcacert.srl index 219a6be4b13b..1c85d6318e03 100644 --- a/builtin/credential/cert/test-fixtures/root/rootcacert.srl +++ b/builtin/credential/cert/test-fixtures/root/rootcacert.srl @@ -1 +1 @@ -92223EAFBBEE17A3 +92223EAFBBEE17AF diff --git a/builtin/credential/cert/test-fixtures/root/rootcawdns.cnf b/builtin/credential/cert/test-fixtures/root/rootcawdns.cnf new file mode 100644 index 000000000000..3c576a95c50e --- /dev/null +++ b/builtin/credential/cert/test-fixtures/root/rootcawdns.cnf @@ -0,0 +1,17 @@ +[ req ] +default_bits = 2048 +encrypt_key = no +prompt = no +default_md = sha256 +req_extensions = req_v3 +distinguished_name = dn + +[ dn ] +CN = example.com + +[ req_v3 ] +subjectAltName = @alt_names + +[ alt_names ] +IP.1 = 127.0.0.1 +DNS.1 = example.com diff --git a/builtin/credential/cert/test-fixtures/root/rootcawdns.csr b/builtin/credential/cert/test-fixtures/root/rootcawdns.csr new file mode 100644 index 000000000000..b56d3231404d --- /dev/null +++ b/builtin/credential/cert/test-fixtures/root/rootcawdns.csr @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIEijCCAnICAQAwFjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wggIiMA0GCSqGSIb3 +DQEBAQUAA4ICDwAwggIKAoICAQDUJ6s97BFxR295bCjpwQ85Vo8DnBFa/awNH107 +QFn/zw0ZDdJMLtEBc/bw7pTYw5ulKbiZDFrmzPEY+QZlo+t1TeWgPRJg0CbYNukS +aNv0vKXjDXYwbrCyOvZucy8hte6IKjZfH+kAsgbbUxfD75BCKsxMxbVHkg0W9Ma2 +pnZj/kpvQE5lkMj5mDvtWdfCRsVg4zL6jhRHkPZ6fOkF3mrfTbQu3oyOcbKLEE/G +t3QRKw3uv0vMDmhg62ZPvD1k70UMjUV2MVqEPZuWY7/bbW8OsfzMyBOGY9LLp7QS +krxWYRj6SPUR4f1bZq7pRbqOfS0okq/XDLf1k6Na5cT6iNdyjEVdSJl7vR7kSreX +8hkwK46Oup8v/vJLu/cRDCpAas0gJJkJDPt5114V0/Xww7EFxs5GijXP8i5RLlgK +/nRscbK+fgjQOnQ5cp0pcP8HAriy2vil7E0fQvMvt5QTyINEYgiYaCIT9WGRC8Xo +WcoUGI2vyrGy6RU6A3/TKeBLtikaSPjFKa1dFTAHfrUkTBpfqc+sbiJ334Bvucg5 +WyS8oAC5Vf++iMnETSdzx1k0/QARVLD38PO8wPaPU1M2XaSA+RHTB9SGFc4VTauT +B167NLlmgJHYuhp+KM1RTy1TEoDlJh2qKj21BLcR1GJ0KgDze6Vpf9xdRTdqMpo2 +h20wdQIDAQABoC8wLQYJKoZIhvcNAQkOMSAwHjAcBgNVHREEFTAThwR/AAABggtl +eGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAgEAGtds+2IUVKzw9bi130mBbb9K +CrXw2NXSp+LJwneIEy0bjAaNr7zCGQsj7q57qFwjc7vLTtGRheP5myrAOq00lp8J +1sGZSETS/y4yeITLZSYWVq2dtF/hY9I+X3uOoibdsQgzYqhBcUr4oTDapf1ZEs0i +wA2J5IcasfaBpWFc9wRN79BBACLGyCbX6VwUISrGe3Hgzkeqtg97cU62ecQsgXiZ +LdQgERvC0wSfAmI4lGulXi1oYYSRxXQ8pEKEAMeJrJVQfvhdbS/o4Bdf3Yj6ibtD +tFSdKLcdRCfMQBEHNpSh665LfBbwU55Fh89tBdGmf6uqsimUY6AxNncnLsc1Kq6F +oINXix3GsBNmCahDeHdGOlNjw0Lpl0m6bnu6LXSDwwuNWAEdDfEmxR+5T/GkGxcG +TTWPwEkpnCe4VmGl9Y10uPSvqneNsdNWjDVK4BeW4VSf9Lp1Zeme1dYFvpyzow+r +4ogpvMPf5vy5I/0HCEf1KlaPyhs8ZGK6YBGaeEDYSaysAWJfYm8eiqwUuKYj/FUe +G3KkaFpOGsQHFNRtG8GukV3r2AK97HFHKNfygZ2xvk5isXz2ZsNX1/J0+GGjalJl +cWBBEiXFM94XJHE9rACsL2UKn8cWCh9lHNLlePOkQuoNY9CUd63xx4Hg97XWP3+U +DhpG7CADsKcPJfbMgrk= +-----END CERTIFICATE REQUEST----- diff --git a/builtin/credential/cert/test-fixtures/root/rootcawdnscert.pem b/builtin/credential/cert/test-fixtures/root/rootcawdnscert.pem new file mode 100644 index 000000000000..2ce633e3a452 --- /dev/null +++ b/builtin/credential/cert/test-fixtures/root/rootcawdnscert.pem @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIIDzzCCAregAwIBAgIJAJIiPq+77herMA0GCSqGSIb3DQEBBQUAMBYxFDASBgNV +BAMTC2V4YW1wbGUuY29tMB4XDTE4MDQyNjEyMDEzMFoXDTE5MDQyNjEyMDEzMFow +FjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw +ggIKAoICAQDUJ6s97BFxR295bCjpwQ85Vo8DnBFa/awNH107QFn/zw0ZDdJMLtEB +c/bw7pTYw5ulKbiZDFrmzPEY+QZlo+t1TeWgPRJg0CbYNukSaNv0vKXjDXYwbrCy +OvZucy8hte6IKjZfH+kAsgbbUxfD75BCKsxMxbVHkg0W9Ma2pnZj/kpvQE5lkMj5 +mDvtWdfCRsVg4zL6jhRHkPZ6fOkF3mrfTbQu3oyOcbKLEE/Gt3QRKw3uv0vMDmhg +62ZPvD1k70UMjUV2MVqEPZuWY7/bbW8OsfzMyBOGY9LLp7QSkrxWYRj6SPUR4f1b +Zq7pRbqOfS0okq/XDLf1k6Na5cT6iNdyjEVdSJl7vR7kSreX8hkwK46Oup8v/vJL +u/cRDCpAas0gJJkJDPt5114V0/Xww7EFxs5GijXP8i5RLlgK/nRscbK+fgjQOnQ5 +cp0pcP8HAriy2vil7E0fQvMvt5QTyINEYgiYaCIT9WGRC8XoWcoUGI2vyrGy6RU6 +A3/TKeBLtikaSPjFKa1dFTAHfrUkTBpfqc+sbiJ334Bvucg5WyS8oAC5Vf++iMnE +TSdzx1k0/QARVLD38PO8wPaPU1M2XaSA+RHTB9SGFc4VTauTB167NLlmgJHYuhp+ +KM1RTy1TEoDlJh2qKj21BLcR1GJ0KgDze6Vpf9xdRTdqMpo2h20wdQIDAQABoyAw +HjAcBgNVHREEFTAThwR/AAABggtleGFtcGxlLmNvbTANBgkqhkiG9w0BAQUFAAOC +AQEA2JswcCYtHvOm2QmSEVeFcCeVNkzr35FXATamJv0oMMjjUFix78MW03EW6vJa +E52e3pBvRdy+k2fuq/RtHIUKzB6jNbv0Vds26Dq+pmGeoaQZOW94/Wht7f9pZgBi +IRPBg9oACtyNAuDsCOdetOyvyoU29sjUOUoQZbEXF+FK4lRJrEmZUJHbp/BOD58V +mQRtjTMjQlZZropqBQmooMRYU0qgWHaIjyoQpu2MgEj3+/1b1IX6SCfRuit0auh/ +YI3/cCtyAG/DpZ6zfyXuyY+iN+l8B6t0nXyV3g8JgBWYPGJv1hgVIgnnqlwuL517 +mEAT5RnHCNJQNuzS1dwfuBrX3w== +-----END CERTIFICATE----- diff --git a/builtin/credential/cert/test-fixtures/root/rootcawdnskey.pem b/builtin/credential/cert/test-fixtures/root/rootcawdnskey.pem new file mode 100644 index 000000000000..15db567e0378 --- /dev/null +++ b/builtin/credential/cert/test-fixtures/root/rootcawdnskey.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +VQpWjPdILMpiVrB/9NsENTNv2DUvc+o= +-----END PRIVATE KEY----- diff --git a/builtin/credential/cert/test-fixtures/root/rootcawemail.cnf b/builtin/credential/cert/test-fixtures/root/rootcawemail.cnf new file mode 100644 index 000000000000..f679fb987900 --- /dev/null +++ b/builtin/credential/cert/test-fixtures/root/rootcawemail.cnf @@ -0,0 +1,17 @@ +[ req ] +default_bits = 2048 +encrypt_key = no +prompt = no +default_md = sha256 +distinguished_name = dn +req_extensions = req_v3 + +[ req_v3 ] +subjectAltName = @alt_names + +[ dn ] +CN = example.com + +[ alt_names ] +IP.1 = 127.0.0.1 +email = valid@example.com diff --git a/builtin/credential/cert/test-fixtures/root/rootcawemail.csr b/builtin/credential/cert/test-fixtures/root/rootcawemail.csr new file mode 100644 index 000000000000..44b191495f46 --- /dev/null +++ b/builtin/credential/cert/test-fixtures/root/rootcawemail.csr @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIEkDCCAngCAQAwFjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wggIiMA0GCSqGSIb3 +DQEBAQUAA4ICDwAwggIKAoICAQDO7stcdJQwUtVeJriwpAswDAirO827peSlgdxs +fW8X9M2hE9ihvESEILb7TRMRiFlDyQYg1BxKMrJ0DZmixFi8RvUCZbH6TFOUMsk+ +w1FhpzjuqAqxNQ51s7u30sfruJg7XN3YJLEPelom62wvzhvLXJFLQZlQCDrMx+PC +ofWs4IA7jR8JaXZjIGdkEU0GgRPy8zKPUe3dUBHi2UR4eKT4cRCn4IwCrFx4BQjV +AxNKNDGpe+fTVOzII/UX+FppDdGZZ4g0y3E1mQUEKkff4dKCK7vhlGJR9D+5v/V0 +/stwP72aXczijuVtnXXyli+oj24NaijoqQluNCD3MvV/INovLL2Tyk54H3/GvpU1 ++sJbpE2+UPh+Rh8DNkT6RPRguymJO8MSsdLt/qvVD8BlZ7I9V3XZlDKosCRTUyxf +jjFpa+VzB3nt7uFtIXZ9HNGhQIpOULvkFGizWV+tS8PpGdTFVzDjyWg0HUKWn8g8 +IiWR9S40h6mHjVuTuxA9tlO69PuTjGK7MlAvFTDaPC8seau1LUiqtQ+prnSLI0h1 +6GfI9W2G7BKKVPloErODhLcsOcwRcmaJVW+yBda3te8+cMBIvtQYKAYSCtg8qXws +xyfPLo4GChbGGRbRCuM3mB1lG1qHEivJ0vynsgolp0t8jaXSFVBVgYj+C6Vd9/hl +ieUcOwIDAQABoDUwMwYJKoZIhvcNAQkOMSYwJDAiBgNVHREEGzAZhwR/AAABgRF2 +YWxpZEBleGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAgEAe1u3wYMMKaZ3d5Wz +jKH971CF3sl+KYl+oV0ekD8dbYe+szERgajn6Y5IYVxxi5o9UgeAWqnyHCiqsW8T +MQdUwMa67Ym/pHKSVoBlGePAKHqock0+iSsVBMcPpU9RkxdSW2aVtdb0DGfyB952 +t3dSb0LaITu30fe8p7lxrL0DKESbwd4N2XQE1F5Vf+1OodvpJinn4Wqzn45hqRf0 +imxrCgVjT5VtR+NRzKCK3Msmh+cJGpR3zgXwGKqgHLWzhvSoQwRWYE3apMK5xLk7 +N1sWVxEKK5+L/CDaMNGQFx5lPiCN3bUudCq4uSZcPLO5AuDpSeLKnknBrWA6HcbB +WvnwtKmHeVe2qogPViKGuwE16rnPlp9hysPl2ckmtqEsXRagIAh5fMI3OoRbZmVV +jfJm21U4YkUWuMKet3EU1StT6T8T6O7QEFA4w4s5+m3dsjDZ9iTuK9/dCs1xnIke +4uJYmh3YrNl8IjMffJuWxA+/de3JO1UljC2EAFxa5KAc24+qyeWwky4tMv72gTOp +6q3k2wnsrK5B1errRV37OLgxtoh1I3Rgp+0B77SOK/PpD/JJazJG5O9bBJOvHJc0 +STW9Td2CzgC2lKGfvkX6UYgVy/9HDq7/EKXP/G2f3kRik2NPUhGcnAH9nyL9SvpP ++T4CZ+FumDj5DulARk6arSq+uy4= +-----END CERTIFICATE REQUEST----- diff --git a/builtin/credential/cert/test-fixtures/root/rootcawemailcert.pem b/builtin/credential/cert/test-fixtures/root/rootcawemailcert.pem new file mode 100644 index 000000000000..f774a71827b8 --- /dev/null +++ b/builtin/credential/cert/test-fixtures/root/rootcawemailcert.pem @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIID1TCCAr2gAwIBAgIJAJIiPq+77hevMA0GCSqGSIb3DQEBBQUAMBYxFDASBgNV +BAMTC2V4YW1wbGUuY29tMB4XDTE4MDQyNjEyMjE1MloXDTE5MDQyNjEyMjE1Mlow +FjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw +ggIKAoICAQDO7stcdJQwUtVeJriwpAswDAirO827peSlgdxsfW8X9M2hE9ihvESE +ILb7TRMRiFlDyQYg1BxKMrJ0DZmixFi8RvUCZbH6TFOUMsk+w1FhpzjuqAqxNQ51 +s7u30sfruJg7XN3YJLEPelom62wvzhvLXJFLQZlQCDrMx+PCofWs4IA7jR8JaXZj +IGdkEU0GgRPy8zKPUe3dUBHi2UR4eKT4cRCn4IwCrFx4BQjVAxNKNDGpe+fTVOzI +I/UX+FppDdGZZ4g0y3E1mQUEKkff4dKCK7vhlGJR9D+5v/V0/stwP72aXczijuVt +nXXyli+oj24NaijoqQluNCD3MvV/INovLL2Tyk54H3/GvpU1+sJbpE2+UPh+Rh8D +NkT6RPRguymJO8MSsdLt/qvVD8BlZ7I9V3XZlDKosCRTUyxfjjFpa+VzB3nt7uFt +IXZ9HNGhQIpOULvkFGizWV+tS8PpGdTFVzDjyWg0HUKWn8g8IiWR9S40h6mHjVuT +uxA9tlO69PuTjGK7MlAvFTDaPC8seau1LUiqtQ+prnSLI0h16GfI9W2G7BKKVPlo +ErODhLcsOcwRcmaJVW+yBda3te8+cMBIvtQYKAYSCtg8qXwsxyfPLo4GChbGGRbR +CuM3mB1lG1qHEivJ0vynsgolp0t8jaXSFVBVgYj+C6Vd9/hlieUcOwIDAQABoyYw +JDAiBgNVHREEGzAZhwR/AAABgRF2YWxpZEBleGFtcGxlLmNvbTANBgkqhkiG9w0B +AQUFAAOCAQEAp2T99t93hxPyCDaqfTF0lsdzIgxZ5GkSzYTYQ2pekLfMDUUy4WFQ +AppdnSJSpm6b+xWO2DkO8UAgOdSEORf/Qpfm+UpHaEYZlQiWQ0zNmIQgBoh6indU +bEZKeL6aAOfIshPNfmqjFt+DpEClrQvCHJggG/rB77Ujj6hPY2+8h4JjbjeX7Pe9 +oUEx9LpZ5Qpo6PK5vB537PP7Q2qp2PIr29DLz1VeLCbqUnV+j7qT0T3hhqurnpTA +QUiRZI0etgeP/B5lw/S4AWijq+R6RasdPAS4UNHsYK+PSGiqdhW/bJvSx5UBXQbk +DuY2A4kdv60H5Aw45/F6enH2Fg1kg7PlQA== +-----END CERTIFICATE----- diff --git a/builtin/credential/cert/test-fixtures/root/rootcawemailkey.pem b/builtin/credential/cert/test-fixtures/root/rootcawemailkey.pem new file mode 100644 index 000000000000..13b1657829c9 --- /dev/null +++ b/builtin/credential/cert/test-fixtures/root/rootcawemailkey.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJRAIBADANBgkqhkiG9w0BAQEFAASCCS4wggkqAgEAAoICAQDO7stcdJQwUtVe +JriwpAswDAirO827peSlgdxsfW8X9M2hE9ihvESEILb7TRMRiFlDyQYg1BxKMrJ0 +DZmixFi8RvUCZbH6TFOUMsk+w1FhpzjuqAqxNQ51s7u30sfruJg7XN3YJLEPelom +62wvzhvLXJFLQZlQCDrMx+PCofWs4IA7jR8JaXZjIGdkEU0GgRPy8zKPUe3dUBHi +2UR4eKT4cRCn4IwCrFx4BQjVAxNKNDGpe+fTVOzII/UX+FppDdGZZ4g0y3E1mQUE +Kkff4dKCK7vhlGJR9D+5v/V0/stwP72aXczijuVtnXXyli+oj24NaijoqQluNCD3 +MvV/INovLL2Tyk54H3/GvpU1+sJbpE2+UPh+Rh8DNkT6RPRguymJO8MSsdLt/qvV +D8BlZ7I9V3XZlDKosCRTUyxfjjFpa+VzB3nt7uFtIXZ9HNGhQIpOULvkFGizWV+t +S8PpGdTFVzDjyWg0HUKWn8g8IiWR9S40h6mHjVuTuxA9tlO69PuTjGK7MlAvFTDa +PC8seau1LUiqtQ+prnSLI0h16GfI9W2G7BKKVPloErODhLcsOcwRcmaJVW+yBda3 +te8+cMBIvtQYKAYSCtg8qXwsxyfPLo4GChbGGRbRCuM3mB1lG1qHEivJ0vynsgol +p0t8jaXSFVBVgYj+C6Vd9/hlieUcOwIDAQABAoICAQDFitqh6TxqITlFBwv6vK9d +b696371XrFdo1F57RwcdxHnkklCUnWh/BcgIgJx6eUJV3nq2LibPgjQva6hF5NCc +89QDNNfBjMmgyRaqjsSKx5sm4U5Lus2R+UFzi4mEcpUI3m99XhGVKAUV8Fo4DLcl +3LlrMTVNXH3dbdj0va4NGcfwkZiWYJI+sPliYs24LtK/dADJJro/MqfQef7OTsWV +0kHHMSoXhzlC7fNvfd8VUFw0Ym99pC3iJclc155feWyk2FwDok7xjqFmR4KTrD1M +PLm/7+ooOFX5WdHVnULSZlb3HSJxCV7l1JJ7QXo/nKS/s59X875n8OWjdoc7lD4T +Xw/K9CzJCyhJ/HDhTAea1+MNTig4a6wjdSim6vasig/Gkot6jjS2lhnZae8ZhYxP +GUx4JcPthHppgHt8s6Jb2PHuqNVRmVB0x41c5mmXOnJcSqOX0XhbSbeS1TUV8BiC +HMaa+agt7RpQOb5uxpb+Hath/88tsjDXI0ZHNAG43ndkHxSQQ9P/q/m5uaLwuJyo +Yb06yUy/g7ceXpJFjGsjO+33DmamvligqOswgg+oazMFo8S9ZUJw6sSXhM/XiHla +JOj+Vatfj0ViVcaGlO2kWughuCT5thn92bgC9V2VnJhbaSzSaQlRphlbuSYJEYj0 +S1uIbwPzTrcBQuekwY50YQKCAQEA/vve5K/nAnw4KLSrKwwCp9trYSm8C5czv2jV +tn6vQtckQMrw/hubX7TcTTgTuGboGdHMwZMFJBKpx6AlRHCR5IBw8fR1z+58c+2V +VJgllc23eKwCcBMKoe6LmsiUXOWmc7MuHc+qQS+9OemO93nNafsSwFCkucBFQs/3 +Yx7J3zNvMOuy+dq3jrxO0xl2jBF0pcmJF/czrvbMCD7tvDntgqvpAnybgrwm2cu3 +Q5F6i+E5w6VDhCprQL/aK95iT7cPmfdGxsUCdfNzDGIJFHZp2Hrar1TsOP6ESsDl +Q/Oz9oO1vMy7MymJjWFoVELBlCBxDEgubyM1f8cE1tQ6UAqFSwKCAQEAz8HnKWPe +NWZtqdAzSmY+3ZxSe1BbukOo4XtCV8LfRHGazKpXMTqsO9l7ynK7ifXv3b3GHTr+ +ck2Af/vyiVx6f7Ty2dmBotFQDzg0HfKD2skAPyH8cHpA8TUeL3yMOR3XQU5/pOnG +tn84n7KWpAyZXh8gzMnmzWjMlb9pUlkKcATUj0gb8iSa9PV0zBwMKYKY0ngznJT2 +CgE1vhy59rpuUVMrQ8i5iW9jbqYVrqID+ta2DWgcLsEXft7jKfupnRHF0Dvc650p ++Lkxv0YgKjUg5sYc2QJbIiBxXaW0cTRrw/KfOe4kvdG5RMF60Six+W1DIW2l+qi3 +irnDRvRm1N6e0QKCAQEA86d5MaxJIl3TSEqEeikK7J3GuV0pHSZKQ7EI70+VaFiv +gt6qdReqXEU2cu+QIJjtV6bcc2lq8zKGXITSt9ieAO0fgIWqgpyQ/jJcjS6qU8D1 +fnFYDwKTGXQaoTjkVPT6HvtsqP4E4i+dMZbWj/MrcAeEvpMRJZLuXE7gRi5ol0nO +CcBhEVKILvQQmrZtSqFvhvDTeTw2fg3FoGeJw2DTbheaHE84RzBGK774C7Abm0kI +asUkhEoInSH3eA4UgbobRXQ+hLhDhrSxDncr2ArjUALtr7eF11yWy9wR+OIK6Rio +9JXqmJQrphcbm9ECq+poPGVJQdgySjzCigrZAh1biwKCAQBiBnFVXCOaOov/lZa9 +weRjl8BrIo1FI2tpiEjTM8U4fAm4C588QRzG2GTKLrxB6eKVU1dIr28i62J4AJ59 +JT8/RldXZoL+GZiWtcQRZT3FWxVctGJxh51gsdleOnvG70eDLtCXNR5nOTu0TgU5 +viAXAsTtG05lGM9+0GOXUR/VntHUEQfuhkr+zVmgfJNYeqA0njZr6PT134BGBTPR +MEGg6Yb+YpT4PbBCouaUESmjju8zAC5b+Qtm9y9jvbRXwez9xWEFYpBNJMROJX5D +q/GsMUmnMq9hOMGEmAy9ZSh7udxa7vwy++NYh5m1Wmgu8di8ywmHbVe8gs2aivKB ++dAhAoIBAQC7nSuRSmRGeKJCAqikMFPVdFdLaTnEw4i/fcyYsPa+o2hTWXyLll8K +lwSnBxe+BCvdeQ8cWzg3rPaIBVzUjDecZjdwjcHnhlHvgHjEvFX339rvpD7J2HIb +DaVqvtPniCFdNK4Jyvd3JMtNq34SIHFAcmB9358JuKsOwCmk8CpMAqKPVsKj7m6H +ETISh/K8aI2vZxVZ4WN4FsQTCqmtQDXFSGpZF5EZSpMJIB3ZZLt2jyyDW2DaZ+1T +yuVl9jU56fTtacQROQY7cvrwznX0lFpmniwl0Aj0wln/svFAqKo1+RujqApw5iYn +ssH1dH2tESx6RpMMyLYihjHVDC/ULUVu +-----END PRIVATE KEY----- diff --git a/builtin/credential/cert/test-fixtures/root/rootcawext.cnf b/builtin/credential/cert/test-fixtures/root/rootcawext.cnf index 524efd2e4013..77e8258e1048 100644 --- a/builtin/credential/cert/test-fixtures/root/rootcawext.cnf +++ b/builtin/credential/cert/test-fixtures/root/rootcawext.cnf @@ -10,12 +10,7 @@ distinguished_name = dn CN = example.com [ req_v3 ] -subjectAltName = @alt_names 2.1.1.1=ASN1:UTF8String:A UTF8String Extension 2.1.1.2=ASN1:UTF8:A UTF8 Extension 2.1.1.3=ASN1:IA5:An IA5 Extension 2.1.1.4=ASN1:VISIBLE:A Visible Extension - -[ alt_names ] -DNS.1 = example.com -IP.1 = 127.0.0.1 diff --git a/builtin/credential/cert/test-fixtures/root/rootcawuri.cnf b/builtin/credential/cert/test-fixtures/root/rootcawuri.cnf new file mode 100644 index 000000000000..bb15540ca7e4 --- /dev/null +++ b/builtin/credential/cert/test-fixtures/root/rootcawuri.cnf @@ -0,0 +1,18 @@ +[ req ] +default_bits = 2048 +encrypt_key = no +prompt = no +default_md = sha256 +req_extensions = req_v3 +distinguished_name = dn + +[ dn ] +CN = example.com + +[ req_v3 ] +subjectAltName = @alt_names + +[ alt_names ] +DNS.1 = example.com +IP.1 = 127.0.0.1 +URI.1 = spiffe://example.com/host diff --git a/builtin/credential/cert/test-fixtures/root/rootcawuri.csr b/builtin/credential/cert/test-fixtures/root/rootcawuri.csr new file mode 100644 index 000000000000..0ababe1ce027 --- /dev/null +++ b/builtin/credential/cert/test-fixtures/root/rootcawuri.csr @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIICpTCCAY0CAQAwFjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQDEtoz6THzA8RFNJ+wu40Pa30Inyprv3xRGYA71 +0T3yLrWUA0xaS8i7HHXDaEVmtHi7I+dFRqGwCgtDLY3sXN1C1t/U6V6xhhQ1hRW7 +PJhbGfsfi8uBx83amWiSMlmEBYPryQzPS+8mmRErBi6EdmgbdGWV5IcovMddDxE1 +Npc1vwmTxDUOe6mRSa8UkaR9nwFl8LTz9clIkGlOJLHWD2oX15PVr7SKYco+MrIh +HLKkYMgATFJ05EKLyRxO/lQWD6ibUYJuGhFeNyjk34swl3uoWQBGndxcs2BQP4OL +EfnsoXVDrHwjZ1FWSu/Bf6TfKvwo5It1IZLnm+cCTqxCnaLRAgMBAAGgSjBIBgkq +hkiG9w0BCQ4xOzA5MDcGA1UdEQQwMC6CC2V4YW1wbGUuY29thwR/AAABhhlzcGlm +ZmU6Ly9leGFtcGxlLmNvbS9ob3N0MA0GCSqGSIb3DQEBCwUAA4IBAQBw2y7bPrLk +B7DrZRvO/s8yj/Mi2iS/q3KEACEUxHTXH9GrqnQJ1n00WjaEu5JgXW8F08738nj/ +QhO5IM9ZMBtFyt9/GguZzGWnGUGUvtfM/ps/qzF6lAnjxYnFfqJeDWhg4SQsW6ZW +eFZ3S1kx0iQjy+Y7oWZNObbgDhszdJa6swN1WJBB8BZuiDJYXMBzfWdR6aZStJ0Z +lUHyaQbILXRc+meuDY7KeILJhldlE8oU/NENO1w1WXcsseXg8790pPYg+uR/uXg0 +0iWPtqgjO+55eAvkZ5nY0N/kABV1oaCB8bVs6/2HPqquPX6c+xkcUI/HY8SJgWzk +AHCG7VIB4W94 +-----END CERTIFICATE REQUEST----- diff --git a/builtin/credential/cert/test-fixtures/root/rootcawuricert.pem b/builtin/credential/cert/test-fixtures/root/rootcawuricert.pem new file mode 100644 index 000000000000..171f4de004ea --- /dev/null +++ b/builtin/credential/cert/test-fixtures/root/rootcawuricert.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC6jCCAdKgAwIBAgIJAJIiPq+77hekMA0GCSqGSIb3DQEBBQUAMBYxFDASBgNV +BAMTC2V4YW1wbGUuY29tMB4XDTE4MDMzMTE2MTE0NVoXDTE5MDMzMTE2MTE0NVow +FjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQDEtoz6THzA8RFNJ+wu40Pa30Inyprv3xRGYA710T3yLrWUA0xaS8i7 +HHXDaEVmtHi7I+dFRqGwCgtDLY3sXN1C1t/U6V6xhhQ1hRW7PJhbGfsfi8uBx83a +mWiSMlmEBYPryQzPS+8mmRErBi6EdmgbdGWV5IcovMddDxE1Npc1vwmTxDUOe6mR +Sa8UkaR9nwFl8LTz9clIkGlOJLHWD2oX15PVr7SKYco+MrIhHLKkYMgATFJ05EKL +yRxO/lQWD6ibUYJuGhFeNyjk34swl3uoWQBGndxcs2BQP4OLEfnsoXVDrHwjZ1FW +Su/Bf6TfKvwo5It1IZLnm+cCTqxCnaLRAgMBAAGjOzA5MDcGA1UdEQQwMC6CC2V4 +YW1wbGUuY29thwR/AAABhhlzcGlmZmU6Ly9leGFtcGxlLmNvbS9ob3N0MA0GCSqG +SIb3DQEBBQUAA4IBAQDhR59hSpL4k4wbK3bA17YoNwFBsDpDcoU2iB9NDUTj+j+T +Rgumt+VHtgxuGRDFPQ+0D2hmJJHNCHKulgeDKVLtY/c5dCEsk8epLQwoCd/pQsNR +Lj102g83rCrU0pfTFjAUoecmHBFt7GDxVyWDsJgGItMatPQuWyZXTzO8JdhCfpMP +m7z65VYZjIPgevpSR5NVJDU8u2jRCkRQBFqOXotJS6EObu4P8aly4YhwiMf1B0L8 +60XHbBksOQSZOky37uFhaab78bAu5nd2kN1K4qSObTJshCZAwRYk0XdCjDrMcZRJ +Fp+yygib+K8e7o71Co0zUdSU0yxOKGsWvjz1BUVl +-----END CERTIFICATE----- diff --git a/builtin/credential/cert/test-fixtures/root/rootcawurikey.pem b/builtin/credential/cert/test-fixtures/root/rootcawurikey.pem new file mode 100644 index 000000000000..81ac978291d7 --- /dev/null +++ b/builtin/credential/cert/test-fixtures/root/rootcawurikey.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDEtoz6THzA8RFN +J+wu40Pa30Inyprv3xRGYA710T3yLrWUA0xaS8i7HHXDaEVmtHi7I+dFRqGwCgtD +LY3sXN1C1t/U6V6xhhQ1hRW7PJhbGfsfi8uBx83amWiSMlmEBYPryQzPS+8mmREr +Bi6EdmgbdGWV5IcovMddDxE1Npc1vwmTxDUOe6mRSa8UkaR9nwFl8LTz9clIkGlO +JLHWD2oX15PVr7SKYco+MrIhHLKkYMgATFJ05EKLyRxO/lQWD6ibUYJuGhFeNyjk +34swl3uoWQBGndxcs2BQP4OLEfnsoXVDrHwjZ1FWSu/Bf6TfKvwo5It1IZLnm+cC +TqxCnaLRAgMBAAECggEAYLdYbR/6HmroFMVSLGN000H9ps7IirNlpoxIDrhH+rDY +eeN9QNAN62E8zUyRAsQsr+YhKUBm8sSdcPQO2W13JAu9lVMAScwgV4gNfTd3uSL3 +AzWaYz63iYjvjyHOPUjw6Za6A5nUBWgwtrSdXmdRHF6IK8Bma7MVWj20OjOS+MsM +ScXk+yMTzpQYZ+AhP6rgcccn6djtk+Mqrpa7yW5cTDkQ0+/MF0KR7tYUbakRSimI +Ph6e+zFt4infOWP5fDr0oSpMXA2chh0INTtxbltnJzvaaPF8LSzyihWTZszABc84 +Ckgrvmt5DViYbmfKHk0csS/xF/wdygfkkJHML8l/IQKBgQD9CMaDgfpM78uH8Kgm +Ja/ANu4Te5zO/n5E96PHdvCN+m7pCMgYuXuKgXDADgD1O6MItzDnEpkubluffARf +1eJyw9ner0tTAs8bZgtKdLQvaghq5Afk1+m8XDTskJsVLVGrozvJLuabPqnZrkRH +AxLdZjiAh6z2csFVYTQnMQSfhQKBgQDHBMjapcDx9y/jUq/yoFvwkdT3THQO9JgK +XC5NOHGVhyT3695wpqi/ANA4b8P9MmAzcUkT8a3jcqV87OIQmK3Y1oGvjHQCKS60 +OYE9TadpxwW2uzxS5T7YegXf5L3uHinoWHlLklN+Q9pvJStw4QrDzhd8rtcZA+FN +KBmjzYdJ3QKBgQDYutl97qi7mXEVgPYlpoYA94u4OFq5mZYB8LLhuGiW03iINbNe +KhE9M12lwtjjNC+S2YYThgSaln/3/LuqcoLBlitY54B3G6LVbvQg1BE5w3JuS97P +Dnjvk3LpZXrQCr83altdGMUBGA1XnEJzKJjR9ipTPOLTPLuIK/gF0aCKGQKBgQCm +ZFitfZGge4M9Mt/KIcpciwCcNf5+ln8bglBv3XYRhykgYsLaOmyxLLPpy3/4DAsk +V1263//7PtofZUnoiE4pEcbhh7NiLx5OLhngsDD9Hhmn2kkoIWR2xyZsN6mYEP4G +tRnMVi2aTo6tCE2WlYBTjtZSNze9QWI4CQPO0MKAvQKBgQCzpJAJXl04zQv9S5uW +pH3xShmd0Zjv9tNyOVNqWUeg47IFzNC2w/6FqYkhd9C4DCAibzPx7WkVjYAR+ivY +NQv1usVhV3maJX5rw+C4Zck8kAmiqMbLacUVdy/5E2Mbk7xqjAvu+qrMFdSk/2GR +raR1xOEvE0cKWIwr8c8wIva4wA== +-----END PRIVATE KEY----- diff --git a/website/source/api/auth/cert/index.html.md b/website/source/api/auth/cert/index.html.md index a3d2f505f283..a189997b894a 100644 --- a/website/source/api/auth/cert/index.html.md +++ b/website/source/api/auth/cert/index.html.md @@ -34,6 +34,29 @@ Sets a CA cert and associated parameters in a role name. (https://github.com/ryanuber/go-glob/blob/master/README.md#example). Value is a comma-separated list of patterns. Authentication requires at least one Name matching at least one pattern. If not set, defaults to allowing all names. + Note: This parameter is deprecated please use individual parameters + allowed_common_names, allowed_dns_sans, allowed_email_sans, allowed_uri_sans, + required_extensions +- `allowed_common_names` `(string: "")` - Constrain the Common Names in + the client certificate with a [globbed pattern] + (https://github.com/ryanuber/go-glob/blob/master/README.md#example). Value is + a comma-separated list of patterns. Authentication requires at least one Name + matching at least one pattern. If not set, defaults to allowing all names. +- `allowed_dns_sans` `(string: "")` - Constrain the Alternative Names in + the client certificate with a [globbed pattern] + (https://github.com/ryanuber/go-glob/blob/master/README.md#example). Value is + a comma-separated list of patterns. Authentication requires at least one DNS + matching at least one pattern. If not set, defaults to allowing all dns. +- `allowed_email_sans` `(string: "")` - Constrain the Alternative Names in + the client certificate with a [globbed pattern] + (https://github.com/ryanuber/go-glob/blob/master/README.md#example). Value is + a comma-separated list of patterns. Authentication requires at least one Email + matching at least one pattern. If not set, defaults to allowing all emails. +- `allowed_uri_sans` `(string: "")` - Constrain the Alternative Names in + the client certificate with a [globbed pattern] + (https://github.com/ryanuber/go-glob/blob/master/README.md#example). Value is + a comma-separated list of URI patterns. Authentication requires at least one URI + matching at least one pattern. If not set, defaults to allowing all URIs. - `required_extensions` `(string: "" or array:[])` - Require specific Custom Extension OIDs to exist and match the pattern. Value is a comma separated string or array of `oid:value`. Expects the extension value to be some type