mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-11-01 19:17:58 +00:00
Add tests for usage-based restrictions of issuers (#15411)
* Restructure leaf issuance test Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com> * Add usage-based testing of issuing leaves, CRLs Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
This commit is contained in:
@@ -432,15 +432,34 @@ func (c CBValidateChain) Run(t testing.TB, b *backend, s logical.Storage, knownK
|
||||
type CBUpdateIssuer struct {
|
||||
Name string
|
||||
CAChain []string
|
||||
Usage string
|
||||
}
|
||||
|
||||
func (c CBUpdateIssuer) Run(t testing.TB, b *backend, s logical.Storage, knownKeys map[string]string, knownCerts map[string]string) {
|
||||
url := "issuer/" + c.Name
|
||||
data := make(map[string]interface{})
|
||||
data["issuer_name"] = c.Name
|
||||
data["manual_chain"] = c.CAChain
|
||||
|
||||
_, err := CBWrite(b, s, url, data)
|
||||
resp, err := CBRead(b, s, url)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to read issuer (%v): %v", c.Name, err)
|
||||
}
|
||||
|
||||
if len(c.CAChain) == 1 && c.CAChain[0] == "existing" {
|
||||
data["manual_chain"] = resp.Data["manual_chain"]
|
||||
} else {
|
||||
data["manual_chain"] = c.CAChain
|
||||
}
|
||||
|
||||
if c.Usage == "existing" {
|
||||
data["usage"] = resp.Data["usage"]
|
||||
} else if len(c.Usage) == 0 {
|
||||
data["usage"] = "read-only,issuing-certificates,crl-signing"
|
||||
} else {
|
||||
data["usage"] = c.Usage
|
||||
}
|
||||
|
||||
_, err = CBWrite(b, s, url, data)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to update issuer (%v): %v / body: %v", c.Name, err, data)
|
||||
}
|
||||
@@ -452,11 +471,7 @@ type CBIssueLeaf struct {
|
||||
Role string
|
||||
}
|
||||
|
||||
func (c CBIssueLeaf) Run(t testing.TB, b *backend, s logical.Storage, knownKeys map[string]string, knownCerts map[string]string) {
|
||||
if len(c.Role) == 0 {
|
||||
c.Role = "testing"
|
||||
}
|
||||
|
||||
func (c CBIssueLeaf) IssueLeaf(t testing.TB, b *backend, s logical.Storage, knownKeys map[string]string, knownCerts map[string]string, errorMessage string) *logical.Response {
|
||||
// Write a role
|
||||
url := "roles/" + c.Role
|
||||
data := make(map[string]interface{})
|
||||
@@ -476,13 +491,20 @@ func (c CBIssueLeaf) Run(t testing.TB, b *backend, s logical.Storage, knownKeys
|
||||
|
||||
resp, err := CBWrite(b, s, url, data)
|
||||
if err != nil {
|
||||
if len(errorMessage) >= 0 {
|
||||
if !strings.Contains(err.Error(), errorMessage) {
|
||||
t.Fatalf("failed to issue cert (%v via %v): %v / body: %v\nExpected error message: %v", c.Issuer, c.Role, err, data, errorMessage)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
t.Fatalf("failed to issue cert (%v via %v): %v / body: %v", c.Issuer, c.Role, err, data)
|
||||
}
|
||||
if resp == nil {
|
||||
t.Fatalf("failed to issue cert (%v via %v): nil response / body: %v", c.Issuer, c.Role, data)
|
||||
}
|
||||
|
||||
api_serial := resp.Data["serial_number"].(string)
|
||||
raw_cert := resp.Data["certificate"].(string)
|
||||
cert := ToCertificate(t, raw_cert)
|
||||
raw_issuer := resp.Data["issuing_ca"].(string)
|
||||
@@ -497,11 +519,21 @@ func (c CBIssueLeaf) Run(t testing.TB, b *backend, s logical.Storage, knownKeys
|
||||
t.Fatalf("failed to verify signature on issued certificate from %v: %v\n[%v]\n[%v]\n", c.Issuer, err, raw_cert, raw_issuer)
|
||||
}
|
||||
|
||||
return resp
|
||||
}
|
||||
|
||||
func (c CBIssueLeaf) RevokeLeaf(t testing.TB, b *backend, s logical.Storage, knownKeys map[string]string, knownCerts map[string]string, issueResponse *logical.Response, hasCRL bool, isDefault bool) {
|
||||
api_serial := issueResponse.Data["serial_number"].(string)
|
||||
raw_cert := issueResponse.Data["certificate"].(string)
|
||||
cert := ToCertificate(t, raw_cert)
|
||||
raw_issuer := issueResponse.Data["issuing_ca"].(string)
|
||||
issuer := ToCertificate(t, raw_issuer)
|
||||
|
||||
// Revoke the certificate.
|
||||
url = "revoke"
|
||||
data = make(map[string]interface{})
|
||||
url := "revoke"
|
||||
data := make(map[string]interface{})
|
||||
data["serial_number"] = api_serial
|
||||
resp, err = CBWrite(b, s, url, data)
|
||||
resp, err := CBWrite(b, s, url, data)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to revoke issued certificate (%v) under role %v / issuer %v: %v", api_serial, c.Role, c.Issuer, err)
|
||||
}
|
||||
@@ -512,6 +544,15 @@ func (c CBIssueLeaf) Run(t testing.TB, b *backend, s logical.Storage, knownKeys
|
||||
t.Fatalf("failed to revoke issued certificate (%v) under role %v / issuer %v: expected response parameter revocation_time was missing from response:\n%v", api_serial, c.Role, c.Issuer, resp.Data)
|
||||
}
|
||||
|
||||
if !hasCRL && isDefault {
|
||||
// Nothing further we can test here. We could re-enable CRL building
|
||||
// and check that it works, but that seems like a stretch. Other
|
||||
// issuers might be functionally the same as this issuer (and thus
|
||||
// this CRL will still be issued), but that requires more work to
|
||||
// check and verify.
|
||||
return
|
||||
}
|
||||
|
||||
// Verify it is on this issuer's CRL.
|
||||
url = "issuer/" + c.Issuer + "/crl"
|
||||
resp, err = CBRead(b, s, url)
|
||||
@@ -525,14 +566,36 @@ func (c CBIssueLeaf) Run(t testing.TB, b *backend, s logical.Storage, knownKeys
|
||||
raw_crl := resp.Data["crl"].(string)
|
||||
crl := ToCRL(t, raw_crl, issuer)
|
||||
|
||||
foundCert := false
|
||||
for _, revoked := range crl.TBSCertList.RevokedCertificates {
|
||||
// t.Logf("[%v] revoked serial number: %v -- vs -- %v", index, revoked.SerialNumber, cert.SerialNumber)
|
||||
if revoked.SerialNumber.Cmp(cert.SerialNumber) == 0 {
|
||||
// t.Logf("found revoked cert at index: %v", index)
|
||||
foundCert = true
|
||||
break
|
||||
foundCert := requireSerialNumberInCRL(nil, crl.TBSCertList, api_serial)
|
||||
if !foundCert {
|
||||
if !hasCRL && !isDefault {
|
||||
// Update the issuer we expect to find this on.
|
||||
resp, err := CBRead(b, s, "config/issuers")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to read default issuer config: %v", err)
|
||||
}
|
||||
if resp == nil {
|
||||
t.Fatalf("failed to read default issuer config: nil response")
|
||||
}
|
||||
defaultID := resp.Data["default"].(issuerID).String()
|
||||
c.Issuer = defaultID
|
||||
issuer = nil
|
||||
}
|
||||
|
||||
// Verify it is on the default issuer's CRL.
|
||||
url = "issuer/" + c.Issuer + "/crl"
|
||||
resp, err = CBRead(b, s, url)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to fetch CRL for issuer %v: %v", c.Issuer, err)
|
||||
}
|
||||
if resp == nil {
|
||||
t.Fatalf("failed to fetch CRL for issuer %v: nil response", c.Issuer)
|
||||
}
|
||||
|
||||
raw_crl = resp.Data["crl"].(string)
|
||||
crl = ToCRL(t, raw_crl, issuer)
|
||||
|
||||
foundCert = requireSerialNumberInCRL(nil, crl.TBSCertList, api_serial)
|
||||
}
|
||||
|
||||
if !foundCert {
|
||||
@@ -564,6 +627,55 @@ func (c CBIssueLeaf) Run(t testing.TB, b *backend, s logical.Storage, knownKeys
|
||||
}
|
||||
}
|
||||
|
||||
func (c CBIssueLeaf) Run(t testing.TB, b *backend, s logical.Storage, knownKeys map[string]string, knownCerts map[string]string) {
|
||||
if len(c.Role) == 0 {
|
||||
c.Role = "testing"
|
||||
}
|
||||
|
||||
resp, err := CBRead(b, s, "config/issuers")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to read default issuer config: %v", err)
|
||||
}
|
||||
if resp == nil {
|
||||
t.Fatalf("failed to read default issuer config: nil response")
|
||||
}
|
||||
defaultID := resp.Data["default"].(issuerID).String()
|
||||
|
||||
resp, err = CBRead(b, s, "issuer/"+c.Issuer)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to read issuer %v: %v", c.Issuer, err)
|
||||
}
|
||||
if resp == nil {
|
||||
t.Fatalf("failed to read issuer %v: nil response", c.Issuer)
|
||||
}
|
||||
ourID := resp.Data["issuer_id"].(issuerID).String()
|
||||
areDefault := ourID == defaultID
|
||||
|
||||
for _, usage := range []string{"read-only", "crl-signing", "issuing-certificates", "issuing-certificates,crl-signing"} {
|
||||
ui := CBUpdateIssuer{
|
||||
Name: c.Issuer,
|
||||
CAChain: []string{"existing"},
|
||||
Usage: usage,
|
||||
}
|
||||
ui.Run(t, b, s, knownKeys, knownCerts)
|
||||
|
||||
ilError := "requested usage issuing-certificates for issuer"
|
||||
hasIssuing := strings.Contains(usage, "issuing-certificates")
|
||||
if hasIssuing {
|
||||
ilError = ""
|
||||
}
|
||||
|
||||
hasCRL := strings.Contains(usage, "crl-signing")
|
||||
|
||||
resp := c.IssueLeaf(t, b, s, knownKeys, knownCerts, ilError)
|
||||
if resp == nil && !hasIssuing {
|
||||
continue
|
||||
}
|
||||
|
||||
c.RevokeLeaf(t, b, s, knownKeys, knownCerts, resp, hasCRL, areDefault)
|
||||
}
|
||||
}
|
||||
|
||||
// Stable ordering
|
||||
func ensureStableOrderingOfChains(t testing.TB, b *backend, s logical.Storage, knownKeys map[string]string, knownCerts map[string]string) {
|
||||
// Start by fetching all chains
|
||||
|
||||
@@ -159,17 +159,21 @@ func parseCrlPemBytes(t *testing.T, crlPem []byte) pkix.TBSCertificateList {
|
||||
return certList.TBSCertList
|
||||
}
|
||||
|
||||
func requireSerialNumberInCRL(t *testing.T, revokeList pkix.TBSCertificateList, serialNum string) {
|
||||
func requireSerialNumberInCRL(t *testing.T, revokeList pkix.TBSCertificateList, serialNum string) bool {
|
||||
serialsInList := make([]string, 0, len(revokeList.RevokedCertificates))
|
||||
for _, revokeEntry := range revokeList.RevokedCertificates {
|
||||
formattedSerial := certutil.GetHexFormatted(revokeEntry.SerialNumber.Bytes(), ":")
|
||||
serialsInList = append(serialsInList, formattedSerial)
|
||||
if formattedSerial == serialNum {
|
||||
return
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
t.Fatalf("the serial number %s, was not found in the CRL list containing: %v", serialNum, serialsInList)
|
||||
if t != nil {
|
||||
t.Fatalf("the serial number %s, was not found in the CRL list containing: %v", serialNum, serialsInList)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func getParsedCrl(t *testing.T, client *api.Client, mountPoint string) *pkix.CertificateList {
|
||||
|
||||
Reference in New Issue
Block a user