-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Perform validation when issuing or signing certificates.
- Loading branch information
Showing
6 changed files
with
190 additions
and
71 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -364,7 +364,7 @@ func TestParseCertificate(t *testing.T) { | |
"other_sans": "1.3.6.1.4.1.311.20.2.3;utf8:[email protected]", | ||
"ttl": "2h", | ||
"max_path_length": 2, | ||
"permitted_dns_domains": ".example.com,.www.example.com", | ||
"permitted_dns_domains": "example.com,.example.com,.www.example.com", | ||
"ou": "unit1, unit2", | ||
"organization": "org1, org2", | ||
"country": "US, CA", | ||
|
@@ -409,7 +409,7 @@ func TestParseCertificate(t *testing.T) { | |
UsePSS: true, | ||
ForceAppendCaChain: false, | ||
UseCSRValues: false, | ||
PermittedDNSDomains: []string{".example.com", ".www.example.com"}, | ||
PermittedDNSDomains: []string{"example.com", ".example.com", ".www.example.com"}, | ||
URLs: nil, | ||
MaxPathLength: 2, | ||
NotBeforeDuration: 45 * time.Second, | ||
|
@@ -433,7 +433,7 @@ func TestParseCertificate(t *testing.T) { | |
"serial_number": "", | ||
"ttl": "2h0m45s", | ||
"max_path_length": 2, | ||
"permitted_dns_domains": ".example.com,.www.example.com", | ||
"permitted_dns_domains": "example.com,.example.com,.www.example.com", | ||
"use_pss": true, | ||
"key_type": "rsa", | ||
"key_bits": 2048, | ||
|
@@ -532,49 +532,50 @@ func TestParseCertificate(t *testing.T) { | |
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
b, s := CreateBackendWithStorage(t) | ||
|
||
var cert *x509.Certificate | ||
issueTime := time.Now() | ||
if tt.wantParams.IsCA { | ||
resp, err := CBWrite(b, s, "root/generate/internal", tt.data) | ||
require.NoError(t, err) | ||
require.NotNil(t, resp) | ||
|
||
certData := resp.Data["certificate"].(string) | ||
cert, err = parsing.ParseCertificateFromString(certData) | ||
require.NoError(t, err) | ||
require.NotNil(t, cert) | ||
} else { | ||
// use the "simple CA" data to create the internal CA | ||
caData := tests[1].data | ||
caData["ttl"] = "3h" | ||
resp, err := CBWrite(b, s, "root/generate/internal", caData) | ||
require.NoError(t, err) | ||
require.NotNil(t, resp) | ||
|
||
// create a role | ||
resp, err = CBWrite(b, s, "roles/test", tt.roleData) | ||
require.NoError(t, err) | ||
require.NotNil(t, resp) | ||
|
||
// create the cert | ||
resp, err = CBWrite(b, s, "issue/test", tt.data) | ||
require.NoError(t, err) | ||
require.NotNil(t, resp) | ||
|
||
certData := resp.Data["certificate"].(string) | ||
cert, err = parsing.ParseCertificateFromString(certData) | ||
require.NoError(t, err) | ||
require.NotNil(t, cert) | ||
} | ||
|
||
b, s := CreateBackendWithStorage(t) | ||
|
||
var cert *x509.Certificate | ||
issueTime := time.Now() | ||
if tt.wantParams.IsCA { | ||
resp, err := CBWrite(b, s, "root/generate/internal", tt.data) | ||
require.NoError(t, err) | ||
require.NotNil(t, resp) | ||
|
||
certData := resp.Data["certificate"].(string) | ||
cert, err = parsing.ParseCertificateFromString(certData) | ||
require.NoError(t, err) | ||
require.NotNil(t, cert) | ||
} else { | ||
// use the "simple CA" data to create the internal CA | ||
caData := tests[1].data | ||
caData["ttl"] = "3h" | ||
resp, err := CBWrite(b, s, "root/generate/internal", caData) | ||
require.NoError(t, err) | ||
require.NotNil(t, resp) | ||
|
||
// create a role | ||
resp, err = CBWrite(b, s, "roles/test", tt.roleData) | ||
require.NoError(t, err) | ||
require.NotNil(t, resp) | ||
|
||
// create the cert | ||
resp, err = CBWrite(b, s, "issue/test", tt.data) | ||
require.NoError(t, err) | ||
require.NotNil(t, resp) | ||
|
||
certData := resp.Data["certificate"].(string) | ||
cert, err = parsing.ParseCertificateFromString(certData) | ||
require.NoError(t, err) | ||
require.NotNil(t, cert) | ||
} | ||
|
||
t.Run(tt.name+" parameters", func(t *testing.T) { | ||
testParseCertificateToCreationParameters(t, issueTime, tt, cert) | ||
}) | ||
t.Run(tt.name+" fields", func(t *testing.T) { | ||
testParseCertificateToFields(t, issueTime, tt, cert) | ||
t.Run(tt.name+" parameters", func(t *testing.T) { | ||
testParseCertificateToCreationParameters(t, issueTime, tt, cert) | ||
}) | ||
t.Run(tt.name+" fields", func(t *testing.T) { | ||
testParseCertificateToFields(t, issueTime, tt, cert) | ||
}) | ||
}) | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
// Copyright (c) HashiCorp, Inc. | ||
// SPDX-License-Identifier: BUSL-1.1 | ||
|
||
package issuing | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
ctx509 "github.com/google/certificate-transparency-go/x509" | ||
"github.com/hashicorp/vault/sdk/framework" | ||
"github.com/hashicorp/vault/sdk/helper/certutil" | ||
"github.com/hashicorp/vault/sdk/logical" | ||
"time" | ||
) | ||
|
||
func VerifyCertificate(ctx context.Context, storage logical.Storage, issuerId IssuerID, parsedBundle *certutil.ParsedCertBundle, data *framework.FieldData) error { | ||
certChainPool := ctx509.NewCertPool() | ||
for _, certificate := range parsedBundle.CAChain { | ||
cert, err := convertCertificate(certificate.Bytes) | ||
if err != nil { | ||
return err | ||
} | ||
certChainPool.AddCert(cert) | ||
} | ||
|
||
// Validation Code, assuming we need to validate the entire chain of constraints | ||
|
||
// Note that we use github.com/google/certificate-transparency-go/x509 to perform certificate verification, | ||
// since that library provides options to disable checks that the standard library does not. | ||
|
||
options := ctx509.VerifyOptions{ | ||
Intermediates: nil, // We aren't verifying the chain here, this would do more work | ||
Roots: certChainPool, | ||
CurrentTime: time.Time{}, | ||
KeyUsages: nil, | ||
MaxConstraintComparisions: 0, // This means infinite | ||
DisableTimeChecks: true, | ||
DisableEKUChecks: true, | ||
DisableCriticalExtensionChecks: false, | ||
DisableNameChecks: false, | ||
DisablePathLenChecks: false, | ||
DisableNameConstraintChecks: false, | ||
} | ||
|
||
if err := entSetCertVerifyOptions(ctx, storage, issuerId, &options); err != nil { | ||
return err | ||
} | ||
|
||
certificate, err := convertCertificate(parsedBundle.CertificateBytes) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
_, err = certificate.Verify(options) | ||
return err | ||
} | ||
|
||
func convertCertificate(certBytes []byte) (*ctx509.Certificate, error) { | ||
ret, err := ctx509.ParseCertificate(certBytes) | ||
if err != nil { | ||
return nil, fmt.Errorf("cannot convert certificate for validation: %w", err) | ||
} | ||
return ret, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// Copyright (c) HashiCorp, Inc. | ||
// SPDX-License-Identifier: BUSL-1.1 | ||
|
||
//go:build !enterprise | ||
|
||
package issuing | ||
|
||
import ( | ||
ctx509 "github.com/google/certificate-transparency-go/x509" | ||
"github.com/hashicorp/vault/sdk/logical" | ||
) | ||
|
||
//go:generate go run github.com/hashicorp/vault/tools/stubmaker | ||
|
||
func entSetCertVerifyOptions(ctx context.Context, storage logical.Storage, issuerId IssuerID, options *ctx509.VerifyOptions) error { | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.