docs/trustmanager/x509filestore_test.go

430 lines
12 KiB
Go

package trustmanager
import (
"crypto/x509"
"encoding/pem"
"io/ioutil"
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
)
func TestNewX509FileStore(t *testing.T) {
tempDir, err := ioutil.TempDir("", "cert-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tempDir)
store, err := NewX509FileStore(tempDir)
if err != nil {
t.Fatalf("failed to create a new X509FileStore: %v", store)
}
}
// NewX509FileStore loads any existing certs from the directory, and does
// not overwrite any of the.
func TestNewX509FileStoreLoadsExistingCerts(t *testing.T) {
tempDir, err := ioutil.TempDir("", "cert-test")
assert.NoError(t, err)
defer os.RemoveAll(tempDir)
certBytes, err := ioutil.ReadFile("../fixtures/root-ca.crt")
assert.NoError(t, err)
out, err := os.Create(filepath.Join(tempDir, "root-ca.crt"))
assert.NoError(t, err)
// to distinguish it from the canonical format
distinguishingBytes := []byte{'\n', '\n', '\n', '\n', '\n', '\n'}
nBytes, err := out.Write(distinguishingBytes)
assert.NoError(t, err)
assert.Len(t, distinguishingBytes, nBytes)
nBytes, err = out.Write(certBytes)
assert.NoError(t, err)
assert.Len(t, certBytes, nBytes)
err = out.Close()
assert.NoError(t, err)
store, err := NewX509FileStore(tempDir)
assert.NoError(t, err)
expectedCert, err := LoadCertFromFile("../fixtures/root-ca.crt")
assert.NoError(t, err)
assert.Equal(t, []*x509.Certificate{expectedCert}, store.GetCertificates())
outBytes, err := ioutil.ReadFile(filepath.Join(tempDir, "root-ca.crt"))
assert.NoError(t, err)
assert.Equal(t, distinguishingBytes, outBytes[:6], "original file overwritten")
assert.Equal(t, certBytes, outBytes[6:], "original file overwritten")
}
func TestAddCertX509FileStore(t *testing.T) {
// Read certificate from file
b, err := ioutil.ReadFile("../fixtures/root-ca.crt")
if err != nil {
t.Fatalf("couldn't load fixture: %v", err)
}
// Decode PEM block
var block *pem.Block
block, _ = pem.Decode(b)
// Load X509 Certificate
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
t.Fatalf("couldn't parse certificate: %v", err)
}
tempDir, err := ioutil.TempDir("", "cert-test")
if err != nil {
t.Fatal(err)
}
// Create a Store and add the certificate to it
store, _ := NewX509FileStore(tempDir)
err = store.AddCert(cert)
if err != nil {
t.Fatalf("failed to load certificate: %v", err)
}
// Retrieve all the certificates
certs := store.GetCertificates()
// Check to see if certificate is present and total number of certs is correct
numCerts := len(certs)
if numCerts != 1 {
t.Fatalf("unexpected number of certificates in store: %d", numCerts)
}
if certs[0] != cert {
t.Fatalf("expected certificates to be the same")
}
}
func TestAddCertFromFileX509FileStore(t *testing.T) {
tempDir, err := ioutil.TempDir("", "cert-test")
assert.NoError(t, err, "failed to create temporary directory")
store, err := NewX509FileStore(tempDir)
assert.NoError(t, err, "failed to load x509 filestore")
err = store.AddCertFromFile("../fixtures/root-ca.crt")
assert.NoError(t, err, "failed to add certificate from file")
assert.Len(t, store.GetCertificates(), 1)
// Now load the x509 filestore with the same path and expect the same result
newStore, err := NewX509FileStore(tempDir)
assert.NoError(t, err, "failed to load x509 filestore")
assert.Len(t, newStore.GetCertificates(), 1)
// Test that adding the same certificate returns an error
err = newStore.AddCert(newStore.GetCertificates()[0])
if assert.Error(t, err, "expected error when adding certificate twice") {
assert.Equal(t, err, &ErrCertExists{})
}
}
// TestNewX509FileStoreEmpty verifies the behavior of the Empty function
func TestNewX509FileStoreEmpty(t *testing.T) {
tempDir, err := ioutil.TempDir("", "cert-test")
assert.NoError(t, err)
defer os.RemoveAll(tempDir)
store, err := NewX509FileStore(tempDir)
assert.NoError(t, err)
assert.True(t, store.Empty())
err = store.AddCertFromFile("../fixtures/root-ca.crt")
assert.NoError(t, err)
assert.False(t, store.Empty())
}
func TestAddCertFromPEMX509FileStore(t *testing.T) {
b, err := ioutil.ReadFile("../fixtures/root-ca.crt")
if err != nil {
t.Fatalf("couldn't load fixture: %v", err)
}
tempDir, err := ioutil.TempDir("", "cert-test")
if err != nil {
t.Fatal(err)
}
store, _ := NewX509FileStore(tempDir)
err = store.AddCertFromPEM(b)
if err != nil {
t.Fatalf("failed to load certificate from PEM: %v", err)
}
numCerts := len(store.GetCertificates())
if numCerts != 1 {
t.Fatalf("unexpected number of certificates in store: %d", numCerts)
}
}
func TestRemoveCertX509FileStore(t *testing.T) {
b, err := ioutil.ReadFile("../fixtures/root-ca.crt")
if err != nil {
t.Fatalf("couldn't load fixture: %v", err)
}
var block *pem.Block
block, _ = pem.Decode(b)
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
t.Fatalf("couldn't parse certificate: %v", err)
}
tempDir, err := ioutil.TempDir("", "cert-test")
if err != nil {
t.Fatal(err)
}
store, _ := NewX509FileStore(tempDir)
err = store.AddCert(cert)
if err != nil {
t.Fatalf("failed to load certificate: %v", err)
}
// Number of certificates should be 1 since we added the cert
numCerts := len(store.GetCertificates())
if numCerts != 1 {
t.Fatalf("unexpected number of certificates in store: %d", numCerts)
}
// Remove the cert from the store
err = store.RemoveCert(cert)
if err != nil {
t.Fatalf("failed to remove certificate: %v", err)
}
// Number of certificates should be 0 since we added and removed the cert
numCerts = len(store.GetCertificates())
if numCerts != 0 {
t.Fatalf("unexpected number of certificates in store: %d", numCerts)
}
}
func TestRemoveAllX509FileStore(t *testing.T) {
tempDir, err := ioutil.TempDir("", "cert-test")
if err != nil {
t.Fatal(err)
}
// Add three certificates to store
store, _ := NewX509FileStore(tempDir)
certFiles := [3]string{"../fixtures/root-ca.crt",
"../fixtures/intermediate-ca.crt",
"../fixtures/secure.example.com.crt"}
for _, file := range certFiles {
b, err := ioutil.ReadFile(file)
if err != nil {
t.Fatalf("couldn't load fixture: %v", err)
}
var block *pem.Block
block, _ = pem.Decode(b)
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
t.Fatalf("couldn't parse certificate: %v", err)
}
err = store.AddCert(cert)
if err != nil {
t.Fatalf("failed to load certificate: %v", err)
}
}
// Number of certificates should be 3 since we added the cert
numCerts := len(store.GetCertificates())
if numCerts != 3 {
t.Fatalf("unexpected number of certificates in store: %d", numCerts)
}
// Remove the cert from the store
err = store.RemoveAll()
if err != nil {
t.Fatalf("failed to remove all certificates: %v", err)
}
// Number of certificates should be 0 since we added and removed the cert
numCerts = len(store.GetCertificates())
if numCerts != 0 {
t.Fatalf("unexpected number of certificates in store: %d", numCerts)
}
}
func TestInexistentGetCertificateByKeyIDX509FileStore(t *testing.T) {
tempDir, err := ioutil.TempDir("", "cert-test")
if err != nil {
t.Fatal(err)
}
store, _ := NewX509FileStore(tempDir)
err = store.AddCertFromFile("../fixtures/root-ca.crt")
if err != nil {
t.Fatalf("failed to load certificate from file: %v", err)
}
_, err = store.GetCertificateByCertID("4d06afd30b8bed131d2a84c97d00b37f422021598bfae34285ce98e77b708b5a")
if err == nil {
t.Fatalf("no error returned for inexistent certificate")
}
}
func TestGetCertificateByKeyIDX509FileStore(t *testing.T) {
b, err := ioutil.ReadFile("../fixtures/root-ca.crt")
if err != nil {
t.Fatalf("couldn't load fixture: %v", err)
}
var block *pem.Block
block, _ = pem.Decode(b)
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
t.Fatalf("couldn't parse certificate: %v", err)
}
tempDir, err := ioutil.TempDir("", "cert-test")
if err != nil {
t.Fatal(err)
}
store, _ := NewX509FileStore(tempDir)
err = store.AddCert(cert)
if err != nil {
t.Fatalf("failed to load certificate from PEM: %v", err)
}
keyID, err := FingerprintCert(cert)
if err != nil {
t.Fatalf("failed to fingerprint the certificate: %v", err)
}
// Tries to retrieve cert by Subject Key IDs
_, err = store.GetCertificateByCertID(keyID)
if err != nil {
t.Fatalf("expected certificate in store: %s", keyID)
}
}
func TestGetVerifyOpsErrorsWithoutCertsX509FileStore(t *testing.T) {
tempDir, err := ioutil.TempDir("", "cert-test")
if err != nil {
t.Fatal(err)
}
// Create empty Store
store, _ := NewX509FileStore(tempDir)
// Try to get VerifyOptions without certs added
_, err = store.GetVerifyOptions("example.com")
if err == nil {
t.Fatalf("expecting an error when getting empty VerifyOptions")
}
}
func TestVerifyLeafCertFromIntermediateX509FileStore(t *testing.T) {
tempDir, err := ioutil.TempDir("", "cert-test")
if err != nil {
t.Fatal(err)
}
// Create a store and add a root
store, _ := NewX509FileStore(tempDir)
err = store.AddCertFromFile("../fixtures/intermediate-ca.crt")
if err != nil {
t.Fatalf("failed to load certificate from file: %v", err)
}
// Get the VerifyOptions from our Store
opts, err := store.GetVerifyOptions("secure.example.com")
// Get leaf certificate
b, err := ioutil.ReadFile("../fixtures/secure.example.com.crt")
if err != nil {
t.Fatalf("couldn't load fixture: %v", err)
}
var block *pem.Block
block, _ = pem.Decode(b)
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
t.Fatalf("couldn't parse certificate: %v", err)
}
// Try to find a valid chain for cert
_, err = cert.Verify(opts)
if err != nil {
t.Fatalf("couldn't find a valid chain for this certificate: %v", err)
}
}
func TestVerifyIntermediateFromRootX509FileStore(t *testing.T) {
tempDir, err := ioutil.TempDir("", "cert-test")
if err != nil {
t.Fatal(err)
}
// Create a store and add a root
store, _ := NewX509FileStore(tempDir)
err = store.AddCertFromFile("../fixtures/root-ca.crt")
if err != nil {
t.Fatalf("failed to load certificate from file: %v", err)
}
// Get the VerifyOptions from our Store
opts, err := store.GetVerifyOptions("Notary Testing CA")
// Get leaf certificate
b, err := ioutil.ReadFile("../fixtures/intermediate-ca.crt")
if err != nil {
t.Fatalf("couldn't load fixture: %v", err)
}
var block *pem.Block
block, _ = pem.Decode(b)
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
t.Fatalf("couldn't parse certificate: %v", err)
}
// Try to find a valid chain for cert
_, err = cert.Verify(opts)
if err != nil {
t.Fatalf("couldn't find a valid chain for this certificate: %v", err)
}
}
func TestNewX509FilteredFileStore(t *testing.T) {
tempDir, err := ioutil.TempDir("", "cert-test")
if err != nil {
t.Fatal(err)
}
store, err := NewX509FilteredFileStore(tempDir, func(cert *x509.Certificate) bool {
return cert.IsCA
})
if err != nil {
t.Fatalf("failed to create new X509FilteredFileStore: %v", err)
}
// AddCert should succeed because this is a CA being added
err = store.AddCertFromFile("../fixtures/root-ca.crt")
if err != nil {
t.Fatalf("failed to load certificate from file: %v", err)
}
numCerts := len(store.GetCertificates())
if numCerts != 1 {
t.Fatalf("unexpected number of certificates in store: %d", numCerts)
}
// AddCert should fail because this is a leaf cert being added
err = store.AddCertFromFile("../fixtures/secure.example.com.crt")
if err == nil {
t.Fatalf("was expecting non-CA certificate to be rejected")
}
}
func TestGetCertificatePoolX509FileStore(t *testing.T) {
tempDir, err := ioutil.TempDir("", "cert-test")
if err != nil {
t.Fatal(err)
}
// Create a store and add a root
store, _ := NewX509FileStore(tempDir)
err = store.AddCertFromFile("../fixtures/root-ca.crt")
if err != nil {
t.Fatalf("failed to load certificate from file: %v", err)
}
pool := store.GetCertificatePool()
numCerts := len(pool.Subjects())
if numCerts != 1 {
t.Fatalf("unexpected number of certificates in pool: %d", numCerts)
}
}