mirror of https://github.com/docker/docs.git
430 lines
12 KiB
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)
|
|
}
|
|
}
|