513 lines
19 KiB
Go
513 lines
19 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
package pki
|
|
|
|
import (
|
|
"crypto/x509"
|
|
"crypto/x509/pkix"
|
|
"encoding/asn1"
|
|
"encoding/base64"
|
|
"fmt"
|
|
"math/big"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/hashicorp/vault/sdk/helper/testhelpers/schema"
|
|
|
|
"github.com/hashicorp/vault/api"
|
|
vaulthttp "github.com/hashicorp/vault/http"
|
|
"github.com/hashicorp/vault/vault"
|
|
|
|
"github.com/hashicorp/vault/sdk/logical"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestResignCrls_ForbidSigningOtherIssuerCRL(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
// Some random CRL from another issuer
|
|
pem1 := "-----BEGIN X509 CRL-----\nMIIBvjCBpwIBATANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDExByb290LWV4YW1w\nbGUuY29tFw0yMjEwMjYyMTI5MzlaFw0yMjEwMjkyMTI5MzlaMCcwJQIUSnVf8wsd\nHjOt9drCYFhWxS9QqGoXDTIyMTAyNjIxMjkzOVqgLzAtMB8GA1UdIwQYMBaAFHki\nZ0XDUQVSajNRGXrg66OaIFlYMAoGA1UdFAQDAgEDMA0GCSqGSIb3DQEBCwUAA4IB\nAQBGIdtqTwemnLZF5AoP+jzvKZ26S3y7qvRIzd7f4A0EawzYmWXSXfwqo4TQ4DG3\nnvT+AaA1zCCOlH/1U+ufN9gSSN0j9ax58brSYMnMskMCqhLKIp0qnvS4jr/gopmF\nv8grbvLHEqNYTu1T7umMLdNQUsWT3Qc+EIjfoKj8xD2FHsZwJ+EMbytwl8Unipjr\nhz4rmcES/65vavfdFpOI6YXfi+UAaHBdkTqmHgg4BdpuXfYtlf+iotFSOkygD5fl\n0D+RVFW9uJv2WfbQ7kRt1X/VcFk/onw0AQqxZRVUzvjoMw+EMcxSq3UKOlXcWDxm\nEFz9rFQQ66L388EP8RD7Dh3X\n-----END X509 CRL-----"
|
|
|
|
b, s := CreateBackendWithStorage(t)
|
|
resp, err := CBWrite(b, s, "root/generate/internal", map[string]interface{}{
|
|
"common_name": "test.com",
|
|
"key_type": "ec",
|
|
})
|
|
requireSuccessNonNilResponse(t, resp, err)
|
|
|
|
resp, err = CBWrite(b, s, "issuer/default/resign-crls", map[string]interface{}{
|
|
"crl_number": "2",
|
|
"next_update": "1h",
|
|
"format": "pem",
|
|
"crls": []string{pem1},
|
|
})
|
|
require.ErrorContains(t, err, "was not signed by requested issuer")
|
|
}
|
|
|
|
func TestResignCrls_NormalCrl(t *testing.T) {
|
|
t.Parallel()
|
|
b1, s1 := CreateBackendWithStorage(t)
|
|
b2, s2 := CreateBackendWithStorage(t)
|
|
|
|
// Setup two backends, with the same key material/certificate with a different leaf in each that is revoked.
|
|
caCert, serial1, serial2, crl1, crl2 := setupResignCrlMounts(t, b1, s1, b2, s2)
|
|
|
|
// Attempt to combine the CRLs
|
|
resp, err := CBWrite(b1, s1, "issuer/default/resign-crls", map[string]interface{}{
|
|
"crl_number": "2",
|
|
"next_update": "1h",
|
|
"format": "pem",
|
|
"crls": []string{crl1, crl2},
|
|
})
|
|
schema.ValidateResponse(t, schema.GetResponseSchema(t, b1.Route("issuer/default/resign-crls"), logical.UpdateOperation), resp, true)
|
|
requireSuccessNonNilResponse(t, resp, err)
|
|
requireFieldsSetInResp(t, resp, "crl")
|
|
pemCrl := resp.Data["crl"].(string)
|
|
combinedCrl, err := decodePemCrl(pemCrl)
|
|
require.NoError(t, err, "failed decoding combined CRL")
|
|
serials := extractSerialsFromCrl(t, combinedCrl)
|
|
|
|
require.Contains(t, serials, serial1)
|
|
require.Contains(t, serials, serial2)
|
|
require.Equal(t, 2, len(serials), "serials contained more serials than expected")
|
|
|
|
require.Equal(t, big.NewInt(int64(2)), combinedCrl.Number)
|
|
require.Equal(t, combinedCrl.ThisUpdate.Add(1*time.Hour), combinedCrl.NextUpdate)
|
|
|
|
extensions := combinedCrl.Extensions
|
|
requireExtensionOid(t, []int{2, 5, 29, 20}, extensions) // CRL Number Extension
|
|
requireExtensionOid(t, []int{2, 5, 29, 35}, extensions) // akidOid
|
|
require.Equal(t, 2, len(extensions))
|
|
|
|
err = combinedCrl.CheckSignatureFrom(caCert)
|
|
require.NoError(t, err, "failed signature check of CRL")
|
|
}
|
|
|
|
func TestResignCrls_EliminateDuplicates(t *testing.T) {
|
|
t.Parallel()
|
|
b1, s1 := CreateBackendWithStorage(t)
|
|
b2, s2 := CreateBackendWithStorage(t)
|
|
|
|
// Setup two backends, with the same key material/certificate with a different leaf in each that is revoked.
|
|
_, serial1, _, crl1, _ := setupResignCrlMounts(t, b1, s1, b2, s2)
|
|
|
|
// Pass in the same CRLs to make sure we do not duplicate entries
|
|
resp, err := CBWrite(b1, s1, "issuer/default/resign-crls", map[string]interface{}{
|
|
"crl_number": "2",
|
|
"next_update": "1h",
|
|
"format": "pem",
|
|
"crls": []string{crl1, crl1},
|
|
})
|
|
requireSuccessNonNilResponse(t, resp, err)
|
|
requireFieldsSetInResp(t, resp, "crl")
|
|
pemCrl := resp.Data["crl"].(string)
|
|
combinedCrl, err := decodePemCrl(pemCrl)
|
|
require.NoError(t, err, "failed decoding combined CRL")
|
|
|
|
// Technically this will die if we have duplicates.
|
|
serials := extractSerialsFromCrl(t, combinedCrl)
|
|
|
|
// We should have no warnings about collisions if they have the same revoked time
|
|
require.Empty(t, resp.Warnings, "expected no warnings in response")
|
|
|
|
require.Contains(t, serials, serial1)
|
|
require.Equal(t, 1, len(serials), "serials contained more serials than expected")
|
|
}
|
|
|
|
func TestResignCrls_ConflictingExpiry(t *testing.T) {
|
|
t.Parallel()
|
|
b1, s1 := CreateBackendWithStorage(t)
|
|
b2, s2 := CreateBackendWithStorage(t)
|
|
|
|
// Setup two backends, with the same key material/certificate with a different leaf in each that is revoked.
|
|
_, serial1, serial2, crl1, _ := setupResignCrlMounts(t, b1, s1, b2, s2)
|
|
|
|
timeAfterMountSetup := time.Now()
|
|
|
|
// Read in serial1 from mount 1
|
|
resp, err := CBRead(b1, s1, "cert/"+serial1)
|
|
requireSuccessNonNilResponse(t, resp, err, "failed reading serial 1's certificate")
|
|
requireFieldsSetInResp(t, resp, "certificate")
|
|
cert1 := resp.Data["certificate"].(string)
|
|
|
|
// Wait until at least we have rolled over to the next second to match sure the generated CRL time
|
|
// on backend 2 for the serial 1 will be different
|
|
for {
|
|
if time.Now().After(timeAfterMountSetup.Add(1 * time.Second)) {
|
|
break
|
|
}
|
|
}
|
|
|
|
// Use BYOC to revoke the same certificate on backend 2 now
|
|
resp, err = CBWrite(b2, s2, "revoke", map[string]interface{}{
|
|
"certificate": cert1,
|
|
})
|
|
requireSuccessNonNilResponse(t, resp, err, "failed revoking serial 1 on backend 2")
|
|
|
|
// Fetch the new CRL from backend2 now
|
|
resp, err = CBRead(b2, s2, "cert/crl")
|
|
requireSuccessNonNilResponse(t, resp, err, "error fetch crl from backend 2")
|
|
requireFieldsSetInResp(t, resp, "certificate")
|
|
crl2 := resp.Data["certificate"].(string)
|
|
|
|
// Attempt to combine the CRLs
|
|
resp, err = CBWrite(b1, s1, "issuer/default/resign-crls", map[string]interface{}{
|
|
"crl_number": "2",
|
|
"next_update": "1h",
|
|
"format": "pem",
|
|
"crls": []string{crl2, crl1}, // Make sure we don't just grab the first colliding entry...
|
|
})
|
|
requireSuccessNonNilResponse(t, resp, err)
|
|
requireFieldsSetInResp(t, resp, "crl")
|
|
pemCrl := resp.Data["crl"].(string)
|
|
combinedCrl, err := decodePemCrl(pemCrl)
|
|
require.NoError(t, err, "failed decoding combined CRL")
|
|
combinedSerials := extractSerialsFromCrl(t, combinedCrl)
|
|
|
|
require.Contains(t, combinedSerials, serial1)
|
|
require.Contains(t, combinedSerials, serial2)
|
|
require.Equal(t, 2, len(combinedSerials), "serials contained more serials than expected")
|
|
|
|
// Make sure we issued a warning about the time collision
|
|
require.NotEmpty(t, resp.Warnings, "expected at least one warning")
|
|
require.Contains(t, resp.Warnings[0], "different revocation times detected")
|
|
|
|
// Make sure we have the initial revocation time from backend 1 within the combined CRL.
|
|
decodedCrl1, err := decodePemCrl(crl1)
|
|
require.NoError(t, err, "failed decoding crl from backend 1")
|
|
serialsFromBackend1 := extractSerialsFromCrl(t, decodedCrl1)
|
|
|
|
require.Equal(t, serialsFromBackend1[serial1], combinedSerials[serial1])
|
|
|
|
// Make sure we have the initial revocation time from backend 1 does not match with backend 2's time
|
|
decodedCrl2, err := decodePemCrl(crl2)
|
|
require.NoError(t, err, "failed decoding crl from backend 2")
|
|
serialsFromBackend2 := extractSerialsFromCrl(t, decodedCrl2)
|
|
|
|
require.NotEqual(t, serialsFromBackend1[serial1], serialsFromBackend2[serial1])
|
|
}
|
|
|
|
func TestResignCrls_DeltaCrl(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
b1, s1 := CreateBackendWithStorage(t)
|
|
b2, s2 := CreateBackendWithStorage(t)
|
|
|
|
// Setup two backends, with the same key material/certificate with a different leaf in each that is revoked.
|
|
caCert, serial1, serial2, crl1, crl2 := setupResignCrlMounts(t, b1, s1, b2, s2)
|
|
|
|
resp, err := CBWrite(b1, s1, "issuer/default/resign-crls", map[string]interface{}{
|
|
"crl_number": "5",
|
|
"delta_crl_base_number": "4",
|
|
"next_update": "12h",
|
|
"format": "pem",
|
|
"crls": []string{crl1, crl2},
|
|
})
|
|
requireSuccessNonNilResponse(t, resp, err)
|
|
requireFieldsSetInResp(t, resp, "crl")
|
|
pemCrl := resp.Data["crl"].(string)
|
|
combinedCrl, err := decodePemCrl(pemCrl)
|
|
require.NoError(t, err, "failed decoding combined CRL")
|
|
serials := extractSerialsFromCrl(t, combinedCrl)
|
|
|
|
require.Contains(t, serials, serial1)
|
|
require.Contains(t, serials, serial2)
|
|
require.Equal(t, 2, len(serials), "serials contained more serials than expected")
|
|
|
|
require.Equal(t, big.NewInt(int64(5)), combinedCrl.Number)
|
|
require.Equal(t, combinedCrl.ThisUpdate.Add(12*time.Hour), combinedCrl.NextUpdate)
|
|
|
|
extensions := combinedCrl.Extensions
|
|
requireExtensionOid(t, []int{2, 5, 29, 27}, extensions) // Delta CRL Extension
|
|
requireExtensionOid(t, []int{2, 5, 29, 20}, extensions) // CRL Number Extension
|
|
requireExtensionOid(t, []int{2, 5, 29, 35}, extensions) // akidOid
|
|
require.Equal(t, 3, len(extensions))
|
|
|
|
err = combinedCrl.CheckSignatureFrom(caCert)
|
|
require.NoError(t, err, "failed signature check of CRL")
|
|
}
|
|
|
|
func TestSignRevocationList(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
coreConfig := &vault.CoreConfig{
|
|
LogicalBackends: map[string]logical.Factory{
|
|
"pki": Factory,
|
|
},
|
|
}
|
|
cluster := vault.NewTestCluster(t, coreConfig, &vault.TestClusterOptions{
|
|
HandlerFunc: vaulthttp.Handler,
|
|
})
|
|
cluster.Start()
|
|
defer cluster.Cleanup()
|
|
client := cluster.Cores[0].Client
|
|
|
|
// Mount PKI, use this form of backend so our request is closer to reality (json parsed)
|
|
err := client.Sys().Mount("pki", &api.MountInput{
|
|
Type: "pki",
|
|
Config: api.MountConfigInput{
|
|
DefaultLeaseTTL: "16h",
|
|
MaxLeaseTTL: "60h",
|
|
},
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
// Generate internal CA.
|
|
resp, err := client.Logical().Write("pki/root/generate/internal", map[string]interface{}{
|
|
"ttl": "40h",
|
|
"common_name": "myvault.com",
|
|
})
|
|
require.NoError(t, err)
|
|
caCert := parseCert(t, resp.Data["certificate"].(string))
|
|
|
|
resp, err = client.Logical().Write("pki/issuer/default/sign-revocation-list", map[string]interface{}{
|
|
"crl_number": "1",
|
|
"next_update": "12h",
|
|
"format": "pem",
|
|
"revoked_certs": []map[string]interface{}{
|
|
{
|
|
"serial_number": "37:60:16:e4:85:d5:96:38:3a:ed:31:06:8d:ed:7a:46:d4:22:63:d8",
|
|
"revocation_time": "1668614976",
|
|
"extensions": []map[string]interface{}{},
|
|
},
|
|
{
|
|
"serial_number": "27:03:89:76:5a:d4:d8:19:48:47:ca:96:db:6f:27:86:31:92:9f:82",
|
|
"revocation_time": "2022-11-16T16:09:36.739592Z",
|
|
},
|
|
{
|
|
"serial_number": "27:03:89:76:5a:d4:d8:19:48:47:ca:96:db:6f:27:86:31:92:9f:81",
|
|
"revocation_time": "2022-10-16T16:09:36.739592Z",
|
|
"extensions": []map[string]interface{}{
|
|
{
|
|
"id": "2.5.29.100",
|
|
"critical": "true",
|
|
"value": "aGVsbG8=", // "hello" base64 encoded
|
|
},
|
|
{
|
|
"id": "2.5.29.101",
|
|
"critical": "false",
|
|
"value": "Ynll", // "bye" base64 encoded
|
|
},
|
|
},
|
|
},
|
|
},
|
|
"extensions": []map[string]interface{}{
|
|
{
|
|
"id": "2.5.29.200",
|
|
"critical": "true",
|
|
"value": "aGVsbG8=", // "hello" base64 encoded
|
|
},
|
|
{
|
|
"id": "2.5.29.201",
|
|
"critical": "false",
|
|
"value": "Ynll", // "bye" base64 encoded
|
|
},
|
|
},
|
|
})
|
|
require.NoError(t, err)
|
|
pemCrl := resp.Data["crl"].(string)
|
|
crl, err := decodePemCrl(pemCrl)
|
|
require.NoError(t, err, "failed decoding CRL")
|
|
serials := extractSerialsFromCrl(t, crl)
|
|
require.Contains(t, serials, "37:60:16:e4:85:d5:96:38:3a:ed:31:06:8d:ed:7a:46:d4:22:63:d8")
|
|
require.Contains(t, serials, "27:03:89:76:5a:d4:d8:19:48:47:ca:96:db:6f:27:86:31:92:9f:82")
|
|
require.Contains(t, serials, "27:03:89:76:5a:d4:d8:19:48:47:ca:96:db:6f:27:86:31:92:9f:81")
|
|
require.Equal(t, 3, len(serials), "expected 3 serials within CRL")
|
|
|
|
// Make sure extensions on serials match what we expect.
|
|
require.Equal(t, 0, len(crl.RevokedCertificates[0].Extensions), "Expected no extensions on 1st serial")
|
|
require.Equal(t, 0, len(crl.RevokedCertificates[1].Extensions), "Expected no extensions on 2nd serial")
|
|
require.Equal(t, 2, len(crl.RevokedCertificates[2].Extensions), "Expected 2 extensions on 3 serial")
|
|
require.Equal(t, "2.5.29.100", crl.RevokedCertificates[2].Extensions[0].Id.String())
|
|
require.True(t, crl.RevokedCertificates[2].Extensions[0].Critical)
|
|
require.Equal(t, []byte("hello"), crl.RevokedCertificates[2].Extensions[0].Value)
|
|
|
|
require.Equal(t, "2.5.29.101", crl.RevokedCertificates[2].Extensions[1].Id.String())
|
|
require.False(t, crl.RevokedCertificates[2].Extensions[1].Critical)
|
|
require.Equal(t, []byte("bye"), crl.RevokedCertificates[2].Extensions[1].Value)
|
|
|
|
// CRL Number and times
|
|
require.Equal(t, big.NewInt(int64(1)), crl.Number)
|
|
require.Equal(t, crl.ThisUpdate.Add(12*time.Hour), crl.NextUpdate)
|
|
|
|
// Verify top level extensions are present
|
|
extensions := crl.Extensions
|
|
requireExtensionOid(t, []int{2, 5, 29, 20}, extensions) // CRL Number Extension
|
|
requireExtensionOid(t, []int{2, 5, 29, 35}, extensions) // akidOid
|
|
requireExtensionOid(t, []int{2, 5, 29, 200}, extensions) // Added value from param
|
|
requireExtensionOid(t, []int{2, 5, 29, 201}, extensions) // Added value from param
|
|
require.Equal(t, 4, len(extensions))
|
|
|
|
// Signature
|
|
err = crl.CheckSignatureFrom(caCert)
|
|
require.NoError(t, err, "failed signature check of CRL")
|
|
}
|
|
|
|
func TestSignRevocationList_NoRevokedCerts(t *testing.T) {
|
|
t.Parallel()
|
|
b, s := CreateBackendWithStorage(t)
|
|
resp, err := CBWrite(b, s, "root/generate/internal", map[string]interface{}{
|
|
"common_name": "test.com",
|
|
})
|
|
requireSuccessNonNilResponse(t, resp, err)
|
|
|
|
resp, err = CBWrite(b, s, "issuer/default/sign-revocation-list", map[string]interface{}{
|
|
"crl_number": "10000",
|
|
"next_update": "12h",
|
|
"format": "pem",
|
|
})
|
|
schema.ValidateResponse(t, schema.GetResponseSchema(t, b.Route("issuer/default/sign-revocation-list"), logical.UpdateOperation), resp, true)
|
|
requireSuccessNonNilResponse(t, resp, err)
|
|
requireFieldsSetInResp(t, resp, "crl")
|
|
pemCrl := resp.Data["crl"].(string)
|
|
crl, err := decodePemCrl(pemCrl)
|
|
require.NoError(t, err, "failed decoding CRL")
|
|
|
|
serials := extractSerialsFromCrl(t, crl)
|
|
require.Equal(t, 0, len(serials), "no serials were expected in CRL")
|
|
|
|
require.Equal(t, big.NewInt(int64(10000)), crl.Number)
|
|
require.Equal(t, crl.ThisUpdate.Add(12*time.Hour), crl.NextUpdate)
|
|
}
|
|
|
|
func TestSignRevocationList_ReservedExtensions(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
reservedOids := []asn1.ObjectIdentifier{
|
|
akOid, deltaCrlOid, crlNumOid,
|
|
}
|
|
// Validate there isn't copy/paste issues with our constants...
|
|
require.Equal(t, asn1.ObjectIdentifier{2, 5, 29, 27}, deltaCrlOid) // Delta CRL Extension
|
|
require.Equal(t, asn1.ObjectIdentifier{2, 5, 29, 20}, crlNumOid) // CRL Number Extension
|
|
require.Equal(t, asn1.ObjectIdentifier{2, 5, 29, 35}, akOid) // akidOid
|
|
|
|
for _, reservedOid := range reservedOids {
|
|
t.Run(reservedOid.String(), func(t *testing.T) {
|
|
b, s := CreateBackendWithStorage(t)
|
|
resp, err := CBWrite(b, s, "root/generate/internal", map[string]interface{}{
|
|
"common_name": "test.com",
|
|
})
|
|
requireSuccessNonNilResponse(t, resp, err)
|
|
|
|
resp, err = CBWrite(b, s, "issuer/default/sign-revocation-list", map[string]interface{}{
|
|
"crl_number": "1",
|
|
"next_update": "12h",
|
|
"format": "pem",
|
|
"extensions": []map[string]interface{}{
|
|
{
|
|
"id": reservedOid.String(),
|
|
"critical": "false",
|
|
"value": base64.StdEncoding.EncodeToString([]byte("hello")),
|
|
},
|
|
},
|
|
})
|
|
|
|
require.ErrorContains(t, err, "is reserved")
|
|
})
|
|
}
|
|
}
|
|
|
|
func setupResignCrlMounts(t *testing.T, b1 *backend, s1 logical.Storage, b2 *backend, s2 logical.Storage) (*x509.Certificate, string, string, string, string) {
|
|
t.Helper()
|
|
|
|
// Setup two mounts with the same CA/key material
|
|
resp, err := CBWrite(b1, s1, "root/generate/exported", map[string]interface{}{
|
|
"common_name": "test.com",
|
|
})
|
|
requireSuccessNonNilResponse(t, resp, err)
|
|
requireFieldsSetInResp(t, resp, "certificate", "private_key")
|
|
pemCaCert := resp.Data["certificate"].(string)
|
|
caCert := parseCert(t, pemCaCert)
|
|
privKey := resp.Data["private_key"].(string)
|
|
|
|
// Import the above key/cert into another mount
|
|
resp, err = CBWrite(b2, s2, "config/ca", map[string]interface{}{
|
|
"pem_bundle": pemCaCert + "\n" + privKey,
|
|
})
|
|
requireSuccessNonNilResponse(t, resp, err, "error setting up CA on backend 2")
|
|
|
|
// Create the same role in both mounts
|
|
resp, err = CBWrite(b1, s1, "roles/test", map[string]interface{}{
|
|
"allowed_domains": "test.com",
|
|
"allow_subdomains": "true",
|
|
"max_ttl": "1h",
|
|
})
|
|
requireSuccessNonNilResponse(t, resp, err, "error setting up pki role on backend 1")
|
|
|
|
resp, err = CBWrite(b2, s2, "roles/test", map[string]interface{}{
|
|
"allowed_domains": "test.com",
|
|
"allow_subdomains": "true",
|
|
"max_ttl": "1h",
|
|
})
|
|
requireSuccessNonNilResponse(t, resp, err, "error setting up pki role on backend 2")
|
|
|
|
// Issue and revoke a cert in backend 1
|
|
resp, err = CBWrite(b1, s1, "issue/test", map[string]interface{}{
|
|
"common_name": "test1.test.com",
|
|
})
|
|
requireSuccessNonNilResponse(t, resp, err, "error issuing cert from backend 1")
|
|
requireFieldsSetInResp(t, resp, "serial_number")
|
|
serial1 := resp.Data["serial_number"].(string)
|
|
|
|
resp, err = CBWrite(b1, s1, "revoke", map[string]interface{}{"serial_number": serial1})
|
|
requireSuccessNonNilResponse(t, resp, err, "error revoking cert from backend 2")
|
|
|
|
// Issue and revoke a cert in backend 2
|
|
resp, err = CBWrite(b2, s2, "issue/test", map[string]interface{}{
|
|
"common_name": "test1.test.com",
|
|
})
|
|
requireSuccessNonNilResponse(t, resp, err, "error issuing cert from backend 2")
|
|
requireFieldsSetInResp(t, resp, "serial_number")
|
|
serial2 := resp.Data["serial_number"].(string)
|
|
|
|
resp, err = CBWrite(b2, s2, "revoke", map[string]interface{}{"serial_number": serial2})
|
|
requireSuccessNonNilResponse(t, resp, err, "error revoking cert from backend 2")
|
|
|
|
// Fetch PEM CRLs from each
|
|
resp, err = CBRead(b1, s1, "cert/crl")
|
|
requireSuccessNonNilResponse(t, resp, err, "error fetch crl from backend 1")
|
|
requireFieldsSetInResp(t, resp, "certificate")
|
|
crl1 := resp.Data["certificate"].(string)
|
|
|
|
resp, err = CBRead(b2, s2, "cert/crl")
|
|
requireSuccessNonNilResponse(t, resp, err, "error fetch crl from backend 2")
|
|
requireFieldsSetInResp(t, resp, "certificate")
|
|
crl2 := resp.Data["certificate"].(string)
|
|
return caCert, serial1, serial2, crl1, crl2
|
|
}
|
|
|
|
func requireExtensionOid(t *testing.T, identifier asn1.ObjectIdentifier, extensions []pkix.Extension, msgAndArgs ...interface{}) {
|
|
t.Helper()
|
|
|
|
found := false
|
|
var oidsInExtensions []string
|
|
for _, extension := range extensions {
|
|
oidsInExtensions = append(oidsInExtensions, extension.Id.String())
|
|
if extension.Id.Equal(identifier) {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !found {
|
|
msg := fmt.Sprintf("Failed to find matching asn oid %s out of %v", identifier.String(), oidsInExtensions)
|
|
require.Fail(t, msg, msgAndArgs)
|
|
}
|
|
}
|
|
|
|
func extractSerialsFromCrl(t *testing.T, crl *x509.RevocationList) map[string]time.Time {
|
|
t.Helper()
|
|
|
|
serials := map[string]time.Time{}
|
|
|
|
for _, revokedCert := range crl.RevokedCertificates {
|
|
serial := serialFromBigInt(revokedCert.SerialNumber)
|
|
if _, exists := serials[serial]; exists {
|
|
t.Fatalf("Serial number %s was duplicated in CRL", serial)
|
|
}
|
|
serials[serial] = revokedCert.RevocationTime
|
|
}
|
|
return serials
|
|
}
|