mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-11-04 04:28:08 +00:00 
			
		
		
		
	* Mark deprecated plugins as deprecated * Add redaction capability to database plugins * Add x509 client auth * Update vendored files * Add integration test for x509 client auth * Remove redaction logic pending further discussion * Update vendored files * Minor updates from code review * Updated docs with x509 client auth * Roles are required * Disable x509 test because it doesn't work in CircleCI * Add timeouts for container lifetime
		
			
				
	
	
		
			243 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			243 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package mongodb
 | 
						|
 | 
						|
import (
 | 
						|
	"bytes"
 | 
						|
	"crypto"
 | 
						|
	"crypto/rand"
 | 
						|
	"crypto/rsa"
 | 
						|
	"crypto/sha1"
 | 
						|
	"crypto/tls"
 | 
						|
	"crypto/x509"
 | 
						|
	"crypto/x509/pkix"
 | 
						|
	"encoding/pem"
 | 
						|
	"io/ioutil"
 | 
						|
	"math/big"
 | 
						|
	"os"
 | 
						|
	"strings"
 | 
						|
	"testing"
 | 
						|
	"time"
 | 
						|
)
 | 
						|
 | 
						|
type certBuilder struct {
 | 
						|
	tmpl       *x509.Certificate
 | 
						|
	parentTmpl *x509.Certificate
 | 
						|
 | 
						|
	selfSign  bool
 | 
						|
	parentKey *rsa.PrivateKey
 | 
						|
 | 
						|
	isCA bool
 | 
						|
}
 | 
						|
 | 
						|
type certOpt func(*certBuilder) error
 | 
						|
 | 
						|
func commonName(cn string) certOpt {
 | 
						|
	return func(builder *certBuilder) error {
 | 
						|
		builder.tmpl.Subject.CommonName = cn
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func parent(parent certificate) certOpt {
 | 
						|
	return func(builder *certBuilder) error {
 | 
						|
		builder.parentKey = parent.privKey.privKey
 | 
						|
		builder.parentTmpl = parent.template
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func isCA(isCA bool) certOpt {
 | 
						|
	return func(builder *certBuilder) error {
 | 
						|
		builder.isCA = isCA
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func selfSign() certOpt {
 | 
						|
	return func(builder *certBuilder) error {
 | 
						|
		builder.selfSign = true
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func dns(dns ...string) certOpt {
 | 
						|
	return func(builder *certBuilder) error {
 | 
						|
		builder.tmpl.DNSNames = dns
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func newCert(t *testing.T, opts ...certOpt) (cert certificate) {
 | 
						|
	t.Helper()
 | 
						|
 | 
						|
	builder := certBuilder{
 | 
						|
		tmpl: &x509.Certificate{
 | 
						|
			SerialNumber: makeSerial(t),
 | 
						|
			Subject: pkix.Name{
 | 
						|
				CommonName: makeCommonName(),
 | 
						|
			},
 | 
						|
			NotBefore: time.Now().Add(-1 * time.Hour),
 | 
						|
			NotAfter:  time.Now().Add(1 * time.Hour),
 | 
						|
			IsCA:      false,
 | 
						|
			KeyUsage: x509.KeyUsageDigitalSignature |
 | 
						|
				x509.KeyUsageKeyEncipherment |
 | 
						|
				x509.KeyUsageKeyAgreement,
 | 
						|
			ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
 | 
						|
			BasicConstraintsValid: true,
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	for _, opt := range opts {
 | 
						|
		err := opt(&builder)
 | 
						|
		if err != nil {
 | 
						|
			t.Fatalf("Failed to set up certificate builder: %s", err)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	key := newPrivateKey(t)
 | 
						|
 | 
						|
	builder.tmpl.SubjectKeyId = getSubjKeyID(t, key.privKey)
 | 
						|
 | 
						|
	tmpl := builder.tmpl
 | 
						|
	parent := builder.parentTmpl
 | 
						|
	publicKey := key.privKey.Public()
 | 
						|
	signingKey := builder.parentKey
 | 
						|
 | 
						|
	if builder.selfSign {
 | 
						|
		parent = tmpl
 | 
						|
		signingKey = key.privKey
 | 
						|
	}
 | 
						|
 | 
						|
	if builder.isCA {
 | 
						|
		tmpl.IsCA = true
 | 
						|
		tmpl.KeyUsage = x509.KeyUsageCertSign | x509.KeyUsageCRLSign
 | 
						|
		tmpl.ExtKeyUsage = nil
 | 
						|
	} else {
 | 
						|
		tmpl.KeyUsage = x509.KeyUsageDigitalSignature |
 | 
						|
			x509.KeyUsageKeyEncipherment |
 | 
						|
			x509.KeyUsageKeyAgreement
 | 
						|
		tmpl.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}
 | 
						|
	}
 | 
						|
 | 
						|
	certBytes, err := x509.CreateCertificate(rand.Reader, tmpl, parent, publicKey, signingKey)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("Unable to generate certificate: %s", err)
 | 
						|
	}
 | 
						|
	certPem := pem.EncodeToMemory(&pem.Block{
 | 
						|
		Type:  "CERTIFICATE",
 | 
						|
		Bytes: certBytes,
 | 
						|
	})
 | 
						|
 | 
						|
	tlsCert, err := tls.X509KeyPair(certPem, key.pem)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("Unable to parse X509 key pair: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	return certificate{
 | 
						|
		template: tmpl,
 | 
						|
		privKey:  key,
 | 
						|
		tlsCert:  tlsCert,
 | 
						|
		rawCert:  certBytes,
 | 
						|
		pem:      certPem,
 | 
						|
		isCA:     builder.isCA,
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// ////////////////////////////////////////////////////////////////////////////
 | 
						|
// Private Key
 | 
						|
// ////////////////////////////////////////////////////////////////////////////
 | 
						|
type keyWrapper struct {
 | 
						|
	privKey *rsa.PrivateKey
 | 
						|
	pem     []byte
 | 
						|
}
 | 
						|
 | 
						|
func newPrivateKey(t *testing.T) (key keyWrapper) {
 | 
						|
	t.Helper()
 | 
						|
 | 
						|
	privKey, err := rsa.GenerateKey(rand.Reader, 2048)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("Unable to generate key for cert: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	privKeyPem := pem.EncodeToMemory(
 | 
						|
		&pem.Block{
 | 
						|
			Type:  "RSA PRIVATE KEY",
 | 
						|
			Bytes: x509.MarshalPKCS1PrivateKey(privKey),
 | 
						|
		},
 | 
						|
	)
 | 
						|
 | 
						|
	key = keyWrapper{
 | 
						|
		privKey: privKey,
 | 
						|
		pem:     privKeyPem,
 | 
						|
	}
 | 
						|
 | 
						|
	return key
 | 
						|
}
 | 
						|
 | 
						|
// ////////////////////////////////////////////////////////////////////////////
 | 
						|
// Certificate
 | 
						|
// ////////////////////////////////////////////////////////////////////////////
 | 
						|
type certificate struct {
 | 
						|
	privKey  keyWrapper
 | 
						|
	template *x509.Certificate
 | 
						|
	tlsCert  tls.Certificate
 | 
						|
	rawCert  []byte
 | 
						|
	pem      []byte
 | 
						|
	isCA     bool
 | 
						|
}
 | 
						|
 | 
						|
func (cert certificate) CombinedPEM() []byte {
 | 
						|
	if cert.isCA {
 | 
						|
		return cert.pem
 | 
						|
	}
 | 
						|
	return bytes.Join([][]byte{cert.privKey.pem, cert.pem}, []byte{'\n'})
 | 
						|
}
 | 
						|
 | 
						|
// ////////////////////////////////////////////////////////////////////////////
 | 
						|
// Writing to file
 | 
						|
// ////////////////////////////////////////////////////////////////////////////
 | 
						|
func writeFile(t *testing.T, filename string, data []byte, perms os.FileMode) {
 | 
						|
	t.Helper()
 | 
						|
 | 
						|
	err := ioutil.WriteFile(filename, data, perms)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("Unable to write to file [%s]: %s", filename, err)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// ////////////////////////////////////////////////////////////////////////////
 | 
						|
// Helpers
 | 
						|
// ////////////////////////////////////////////////////////////////////////////
 | 
						|
func makeSerial(t *testing.T) *big.Int {
 | 
						|
	t.Helper()
 | 
						|
 | 
						|
	v := &big.Int{}
 | 
						|
	serialNumberLimit := v.Lsh(big.NewInt(1), 128)
 | 
						|
	serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("Unable to generate serial number: %s", err)
 | 
						|
	}
 | 
						|
	return serialNumber
 | 
						|
}
 | 
						|
 | 
						|
// Pulled from sdk/helper/certutil & slightly modified for test usage
 | 
						|
func getSubjKeyID(t *testing.T, privateKey crypto.Signer) []byte {
 | 
						|
	t.Helper()
 | 
						|
 | 
						|
	if privateKey == nil {
 | 
						|
		t.Fatalf("passed-in private key is nil")
 | 
						|
	}
 | 
						|
 | 
						|
	marshaledKey, err := x509.MarshalPKIXPublicKey(privateKey.Public())
 | 
						|
	if err != nil {
 | 
						|
		t.Fatalf("error marshalling public key: %s", err)
 | 
						|
	}
 | 
						|
 | 
						|
	subjKeyID := sha1.Sum(marshaledKey)
 | 
						|
 | 
						|
	return subjKeyID[:]
 | 
						|
}
 | 
						|
 | 
						|
func makeCommonName() (cn string) {
 | 
						|
	return strings.ReplaceAll(time.Now().Format("20060102T150405.000"), ".", "")
 | 
						|
}
 |