Move OCSP/PKI interop test to PKI engine (#20273)
This prevents SDK from having a circular import on the main Vault package. Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
This commit is contained in:
parent
879844d300
commit
f0279b0d31
|
@ -14,9 +14,14 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/vault/api"
|
||||||
|
vaulthttp "github.com/hashicorp/vault/http"
|
||||||
|
vaultocsp "github.com/hashicorp/vault/sdk/helper/ocsp"
|
||||||
"github.com/hashicorp/vault/sdk/helper/testhelpers/schema"
|
"github.com/hashicorp/vault/sdk/helper/testhelpers/schema"
|
||||||
|
|
||||||
"github.com/hashicorp/vault/sdk/logical"
|
"github.com/hashicorp/vault/sdk/logical"
|
||||||
|
"github.com/hashicorp/vault/vault"
|
||||||
|
|
||||||
|
"github.com/hashicorp/go-hclog"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -469,6 +474,169 @@ func TestIntegration_AutoIssuer(t *testing.T) {
|
||||||
require.Equal(t, issuerIdOneReimported, resp.Data["default"])
|
require.Equal(t, issuerIdOneReimported, resp.Data["default"])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIntegrationOCSPClientWithPKI(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()
|
||||||
|
cores := cluster.Cores
|
||||||
|
vault.TestWaitActive(t, cores[0].Core)
|
||||||
|
client := cores[0].Client
|
||||||
|
|
||||||
|
err := client.Sys().Mount("pki", &api.MountInput{
|
||||||
|
Type: "pki",
|
||||||
|
Config: api.MountConfigInput{
|
||||||
|
DefaultLeaseTTL: "16h",
|
||||||
|
MaxLeaseTTL: "32h",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
resp, err := client.Logical().Write("pki/root/generate/internal", map[string]interface{}{
|
||||||
|
"ttl": "40h",
|
||||||
|
"common_name": "Root R1",
|
||||||
|
"key_type": "ec",
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, resp)
|
||||||
|
require.NotNil(t, resp.Data)
|
||||||
|
require.NotEmpty(t, resp.Data["issuer_id"])
|
||||||
|
rootIssuerId := resp.Data["issuer_id"].(string)
|
||||||
|
|
||||||
|
// Set URLs pointing to the issuer.
|
||||||
|
_, err = client.Logical().Write("pki/config/cluster", map[string]interface{}{
|
||||||
|
"path": client.Address() + "/v1/pki",
|
||||||
|
"aia_path": client.Address() + "/v1/pki",
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = client.Logical().Write("pki/config/urls", map[string]interface{}{
|
||||||
|
"enable_templating": true,
|
||||||
|
"crl_distribution_points": "{{cluster_aia_path}}/issuer/{{issuer_id}}/crl/der",
|
||||||
|
"issuing_certificates": "{{cluster_aia_path}}/issuer/{{issuer_id}}/der",
|
||||||
|
"ocsp_servers": "{{cluster_aia_path}}/ocsp",
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Build an intermediate CA
|
||||||
|
resp, err = client.Logical().Write("pki/intermediate/generate/internal", map[string]interface{}{
|
||||||
|
"common_name": "Int X1",
|
||||||
|
"key_type": "ec",
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, resp)
|
||||||
|
require.NotNil(t, resp.Data)
|
||||||
|
require.NotEmpty(t, resp.Data["csr"])
|
||||||
|
intermediateCSR := resp.Data["csr"].(string)
|
||||||
|
|
||||||
|
resp, err = client.Logical().Write("pki/root/sign-intermediate", map[string]interface{}{
|
||||||
|
"csr": intermediateCSR,
|
||||||
|
"ttl": "20h",
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, resp)
|
||||||
|
require.NotNil(t, resp.Data)
|
||||||
|
require.NotEmpty(t, resp.Data["certificate"])
|
||||||
|
intermediateCert := resp.Data["certificate"]
|
||||||
|
|
||||||
|
resp, err = client.Logical().Write("pki/intermediate/set-signed", map[string]interface{}{
|
||||||
|
"certificate": intermediateCert,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, resp)
|
||||||
|
require.NotNil(t, resp.Data)
|
||||||
|
require.NotEmpty(t, resp.Data["imported_issuers"])
|
||||||
|
rawImportedIssuers := resp.Data["imported_issuers"].([]interface{})
|
||||||
|
require.Equal(t, len(rawImportedIssuers), 1)
|
||||||
|
importedIssuer := rawImportedIssuers[0].(string)
|
||||||
|
require.NotEmpty(t, importedIssuer)
|
||||||
|
|
||||||
|
// Set intermediate as default.
|
||||||
|
_, err = client.Logical().Write("pki/config/issuers", map[string]interface{}{
|
||||||
|
"default": importedIssuer,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Setup roles for root, intermediate.
|
||||||
|
_, err = client.Logical().Write("pki/roles/example-root", map[string]interface{}{
|
||||||
|
"allowed_domains": "example.com",
|
||||||
|
"allow_subdomains": "true",
|
||||||
|
"max_ttl": "1h",
|
||||||
|
"key_type": "ec",
|
||||||
|
"issuer_ref": rootIssuerId,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = client.Logical().Write("pki/roles/example-int", map[string]interface{}{
|
||||||
|
"allowed_domains": "example.com",
|
||||||
|
"allow_subdomains": "true",
|
||||||
|
"max_ttl": "1h",
|
||||||
|
"key_type": "ec",
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Issue certs and validate them against OCSP.
|
||||||
|
for _, path := range []string{"pki/issue/example-int", "pki/issue/example-root"} {
|
||||||
|
t.Logf("Validating against path: %v", path)
|
||||||
|
resp, err = client.Logical().Write(path, map[string]interface{}{
|
||||||
|
"common_name": "test.example.com",
|
||||||
|
"ttl": "5m",
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, resp)
|
||||||
|
require.NotNil(t, resp.Data)
|
||||||
|
require.NotEmpty(t, resp.Data["certificate"])
|
||||||
|
require.NotEmpty(t, resp.Data["issuing_ca"])
|
||||||
|
require.NotEmpty(t, resp.Data["serial_number"])
|
||||||
|
|
||||||
|
certPEM := resp.Data["certificate"].(string)
|
||||||
|
certBlock, _ := pem.Decode([]byte(certPEM))
|
||||||
|
require.NotNil(t, certBlock)
|
||||||
|
cert, err := x509.ParseCertificate(certBlock.Bytes)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, cert)
|
||||||
|
|
||||||
|
issuerPEM := resp.Data["issuing_ca"].(string)
|
||||||
|
issuerBlock, _ := pem.Decode([]byte(issuerPEM))
|
||||||
|
require.NotNil(t, issuerBlock)
|
||||||
|
issuer, err := x509.ParseCertificate(issuerBlock.Bytes)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, issuer)
|
||||||
|
|
||||||
|
serialNumber := resp.Data["serial_number"].(string)
|
||||||
|
|
||||||
|
testLogger := hclog.New(hclog.DefaultOptions)
|
||||||
|
|
||||||
|
conf := &vaultocsp.VerifyConfig{
|
||||||
|
OcspFailureMode: vaultocsp.FailOpenFalse,
|
||||||
|
ExtraCas: []*x509.Certificate{cluster.CACert},
|
||||||
|
}
|
||||||
|
ocspClient := vaultocsp.New(func() hclog.Logger {
|
||||||
|
return testLogger
|
||||||
|
}, 10)
|
||||||
|
|
||||||
|
err = ocspClient.VerifyLeafCertificate(context.Background(), cert, issuer, conf)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = client.Logical().Write("pki/revoke", map[string]interface{}{
|
||||||
|
"serial_number": serialNumber,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
err = ocspClient.VerifyLeafCertificate(context.Background(), cert, issuer, conf)
|
||||||
|
require.Error(t, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func genTestRootCa(t *testing.T, b *backend, s logical.Storage) (issuerID, keyID) {
|
func genTestRootCa(t *testing.T, b *backend, s logical.Storage) (issuerID, keyID) {
|
||||||
return genTestRootCaWithIssuerName(t, b, s, "")
|
return genTestRootCaWithIssuerName(t, b, s, "")
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"crypto"
|
"crypto"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/pem"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
@ -19,16 +18,9 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/hashicorp/vault/api"
|
|
||||||
"github.com/hashicorp/vault/builtin/logical/pki"
|
|
||||||
vaulthttp "github.com/hashicorp/vault/http"
|
|
||||||
"github.com/hashicorp/vault/sdk/logical"
|
|
||||||
"github.com/hashicorp/vault/vault"
|
|
||||||
|
|
||||||
"github.com/hashicorp/go-hclog"
|
"github.com/hashicorp/go-hclog"
|
||||||
"github.com/hashicorp/go-retryablehttp"
|
"github.com/hashicorp/go-retryablehttp"
|
||||||
lru "github.com/hashicorp/golang-lru"
|
lru "github.com/hashicorp/golang-lru"
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
"golang.org/x/crypto/ocsp"
|
"golang.org/x/crypto/ocsp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -432,165 +424,6 @@ func TestCanEarlyExitForOCSP(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWithVaultPKI(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
coreConfig := &vault.CoreConfig{
|
|
||||||
LogicalBackends: map[string]logical.Factory{
|
|
||||||
"pki": pki.Factory,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
cluster := vault.NewTestCluster(t, coreConfig, &vault.TestClusterOptions{
|
|
||||||
HandlerFunc: vaulthttp.Handler,
|
|
||||||
})
|
|
||||||
|
|
||||||
cluster.Start()
|
|
||||||
defer cluster.Cleanup()
|
|
||||||
cores := cluster.Cores
|
|
||||||
vault.TestWaitActive(t, cores[0].Core)
|
|
||||||
client := cores[0].Client
|
|
||||||
|
|
||||||
err := client.Sys().Mount("pki", &api.MountInput{
|
|
||||||
Type: "pki",
|
|
||||||
Config: api.MountConfigInput{
|
|
||||||
DefaultLeaseTTL: "16h",
|
|
||||||
MaxLeaseTTL: "32h",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
resp, err := client.Logical().Write("pki/root/generate/internal", map[string]interface{}{
|
|
||||||
"ttl": "40h",
|
|
||||||
"common_name": "Root R1",
|
|
||||||
"key_type": "ec",
|
|
||||||
})
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.NotNil(t, resp)
|
|
||||||
require.NotNil(t, resp.Data)
|
|
||||||
require.NotEmpty(t, resp.Data["issuer_id"])
|
|
||||||
rootIssuerId := resp.Data["issuer_id"].(string)
|
|
||||||
|
|
||||||
// Set URLs pointing to the issuer.
|
|
||||||
_, err = client.Logical().Write("pki/config/cluster", map[string]interface{}{
|
|
||||||
"path": client.Address() + "/v1/pki",
|
|
||||||
"aia_path": client.Address() + "/v1/pki",
|
|
||||||
})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
_, err = client.Logical().Write("pki/config/urls", map[string]interface{}{
|
|
||||||
"enable_templating": true,
|
|
||||||
"crl_distribution_points": "{{cluster_aia_path}}/issuer/{{issuer_id}}/crl/der",
|
|
||||||
"issuing_certificates": "{{cluster_aia_path}}/issuer/{{issuer_id}}/der",
|
|
||||||
"ocsp_servers": "{{cluster_aia_path}}/ocsp",
|
|
||||||
})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// Build an intermediate CA
|
|
||||||
resp, err = client.Logical().Write("pki/intermediate/generate/internal", map[string]interface{}{
|
|
||||||
"common_name": "Int X1",
|
|
||||||
"key_type": "ec",
|
|
||||||
})
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.NotNil(t, resp)
|
|
||||||
require.NotNil(t, resp.Data)
|
|
||||||
require.NotEmpty(t, resp.Data["csr"])
|
|
||||||
intermediateCSR := resp.Data["csr"].(string)
|
|
||||||
|
|
||||||
resp, err = client.Logical().Write("pki/root/sign-intermediate", map[string]interface{}{
|
|
||||||
"csr": intermediateCSR,
|
|
||||||
"ttl": "20h",
|
|
||||||
})
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.NotNil(t, resp)
|
|
||||||
require.NotNil(t, resp.Data)
|
|
||||||
require.NotEmpty(t, resp.Data["certificate"])
|
|
||||||
intermediateCert := resp.Data["certificate"]
|
|
||||||
|
|
||||||
resp, err = client.Logical().Write("pki/intermediate/set-signed", map[string]interface{}{
|
|
||||||
"certificate": intermediateCert,
|
|
||||||
})
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.NotNil(t, resp)
|
|
||||||
require.NotNil(t, resp.Data)
|
|
||||||
require.NotEmpty(t, resp.Data["imported_issuers"])
|
|
||||||
rawImportedIssuers := resp.Data["imported_issuers"].([]interface{})
|
|
||||||
require.Equal(t, len(rawImportedIssuers), 1)
|
|
||||||
importedIssuer := rawImportedIssuers[0].(string)
|
|
||||||
require.NotEmpty(t, importedIssuer)
|
|
||||||
|
|
||||||
// Set intermediate as default.
|
|
||||||
_, err = client.Logical().Write("pki/config/issuers", map[string]interface{}{
|
|
||||||
"default": importedIssuer,
|
|
||||||
})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// Setup roles for root, intermediate.
|
|
||||||
_, err = client.Logical().Write("pki/roles/example-root", map[string]interface{}{
|
|
||||||
"allowed_domains": "example.com",
|
|
||||||
"allow_subdomains": "true",
|
|
||||||
"max_ttl": "1h",
|
|
||||||
"key_type": "ec",
|
|
||||||
"issuer_ref": rootIssuerId,
|
|
||||||
})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
_, err = client.Logical().Write("pki/roles/example-int", map[string]interface{}{
|
|
||||||
"allowed_domains": "example.com",
|
|
||||||
"allow_subdomains": "true",
|
|
||||||
"max_ttl": "1h",
|
|
||||||
"key_type": "ec",
|
|
||||||
})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// Issue certs and validate them against OCSP.
|
|
||||||
for _, path := range []string{"pki/issue/example-int", "pki/issue/example-root"} {
|
|
||||||
t.Logf("Validating against path: %v", path)
|
|
||||||
resp, err = client.Logical().Write(path, map[string]interface{}{
|
|
||||||
"common_name": "test.example.com",
|
|
||||||
"ttl": "5m",
|
|
||||||
})
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.NotNil(t, resp)
|
|
||||||
require.NotNil(t, resp.Data)
|
|
||||||
require.NotEmpty(t, resp.Data["certificate"])
|
|
||||||
require.NotEmpty(t, resp.Data["issuing_ca"])
|
|
||||||
require.NotEmpty(t, resp.Data["serial_number"])
|
|
||||||
|
|
||||||
certPEM := resp.Data["certificate"].(string)
|
|
||||||
certBlock, _ := pem.Decode([]byte(certPEM))
|
|
||||||
require.NotNil(t, certBlock)
|
|
||||||
cert, err := x509.ParseCertificate(certBlock.Bytes)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.NotNil(t, cert)
|
|
||||||
|
|
||||||
issuerPEM := resp.Data["issuing_ca"].(string)
|
|
||||||
issuerBlock, _ := pem.Decode([]byte(issuerPEM))
|
|
||||||
require.NotNil(t, issuerBlock)
|
|
||||||
issuer, err := x509.ParseCertificate(issuerBlock.Bytes)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.NotNil(t, issuer)
|
|
||||||
|
|
||||||
serialNumber := resp.Data["serial_number"].(string)
|
|
||||||
|
|
||||||
conf := &VerifyConfig{
|
|
||||||
OcspFailureMode: FailOpenFalse,
|
|
||||||
ExtraCas: []*x509.Certificate{cluster.CACert},
|
|
||||||
}
|
|
||||||
ocspClient := New(testLogFactory, 10)
|
|
||||||
|
|
||||||
err = ocspClient.VerifyLeafCertificate(context.Background(), cert, issuer, conf)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
_, err = client.Logical().Write("pki/revoke", map[string]interface{}{
|
|
||||||
"serial_number": serialNumber,
|
|
||||||
})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
err = ocspClient.VerifyLeafCertificate(context.Background(), cert, issuer, conf)
|
|
||||||
require.Error(t, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var testLogger = hclog.New(hclog.DefaultOptions)
|
var testLogger = hclog.New(hclog.DefaultOptions)
|
||||||
|
|
||||||
func testLogFactory() hclog.Logger {
|
func testLogFactory() hclog.Logger {
|
||||||
|
|
Loading…
Reference in New Issue