mirror of
https://github.com/hashicorp/vault.git
synced 2025-08-22 07:01:09 +02:00
* Do not use static certificates for diagnose tests * Fix operator command tests, move PKI CA creation code into testhelper lib * Fix compilation error from refactoring
225 lines
6.0 KiB
Go
225 lines
6.0 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package pki
|
|
|
|
import (
|
|
"crypto/ecdsa"
|
|
"crypto/elliptic"
|
|
"crypto/rand"
|
|
"crypto/x509"
|
|
"crypto/x509/pkix"
|
|
"encoding/pem"
|
|
"math/big"
|
|
mathrand2 "math/rand/v2"
|
|
"net"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// This file contains helper functions for generating CA hierarchies for testing
|
|
|
|
type LeafWithRoot struct {
|
|
RootCa GeneratedCert
|
|
Leaf GeneratedCert
|
|
CombinedLeafCaFile string
|
|
}
|
|
|
|
type LeafWithIntermediary struct {
|
|
RootCa GeneratedCert
|
|
IntCa GeneratedCert
|
|
Leaf GeneratedCert
|
|
CombinedCaFile string
|
|
}
|
|
|
|
type GeneratedCert struct {
|
|
KeyFile string
|
|
CertFile string
|
|
CertPem *pem.Block
|
|
Cert *x509.Certificate
|
|
Key *ecdsa.PrivateKey
|
|
}
|
|
|
|
// GenerateCertWithIntermediaryRoot generates a leaf certificate signed by an intermediary root CA
|
|
func GenerateCertWithIntermediaryRoot(t testing.TB) LeafWithIntermediary {
|
|
t.Helper()
|
|
tempDir := t.TempDir()
|
|
template := &x509.Certificate{
|
|
Subject: pkix.Name{
|
|
CommonName: "localhost",
|
|
},
|
|
SerialNumber: big.NewInt(mathrand2.Int64()),
|
|
DNSNames: []string{"localhost"},
|
|
IPAddresses: []net.IP{net.ParseIP("127.0.0.1")},
|
|
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
|
|
NotBefore: time.Now().Add(-30 * time.Second),
|
|
NotAfter: time.Now().Add(60 * 24 * time.Hour),
|
|
}
|
|
|
|
ca := GenerateRootCa(t)
|
|
caIntTemplate := &x509.Certificate{
|
|
Subject: pkix.Name{
|
|
CommonName: "Intermediary CA",
|
|
},
|
|
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
|
|
SerialNumber: big.NewInt(mathrand2.Int64()),
|
|
NotBefore: time.Now().Add(-30 * time.Second),
|
|
NotAfter: time.Now().Add(262980 * time.Hour),
|
|
BasicConstraintsValid: true,
|
|
IsCA: true,
|
|
}
|
|
caInt := generateCertAndSign(t, caIntTemplate, ca, tempDir, "int_")
|
|
leafCert := generateCertAndSign(t, template, caInt, tempDir, "leaf_")
|
|
|
|
combinedCasFile := filepath.Join(tempDir, "cas.pem")
|
|
err := os.WriteFile(combinedCasFile, append(pem.EncodeToMemory(caInt.CertPem), pem.EncodeToMemory(ca.CertPem)...), 0o644)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
return LeafWithIntermediary{
|
|
RootCa: ca,
|
|
IntCa: caInt,
|
|
Leaf: leafCert,
|
|
CombinedCaFile: combinedCasFile,
|
|
}
|
|
}
|
|
|
|
// generateCertAndSign generates a certificate and associated key signed by a CA
|
|
func generateCertAndSign(t testing.TB, template *x509.Certificate, ca GeneratedCert, tempDir string, filePrefix string) GeneratedCert {
|
|
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
certBytes, err := x509.CreateCertificate(rand.Reader, template, ca.Cert, key.Public(), ca.Key)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
cert, err := x509.ParseCertificate(certBytes)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
certPEMBlock := &pem.Block{
|
|
Type: "CERTIFICATE",
|
|
Bytes: certBytes,
|
|
}
|
|
certFile := filepath.Join(tempDir, filePrefix+"cert.pem")
|
|
err = os.WriteFile(certFile, pem.EncodeToMemory(certPEMBlock), 0o644)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
marshaledKey, err := x509.MarshalECPrivateKey(key)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
keyPEMBlock := &pem.Block{
|
|
Type: "EC PRIVATE KEY",
|
|
Bytes: marshaledKey,
|
|
}
|
|
keyFile := filepath.Join(tempDir, filePrefix+"key.pem")
|
|
err = os.WriteFile(keyFile, pem.EncodeToMemory(keyPEMBlock), 0o644)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return GeneratedCert{
|
|
KeyFile: keyFile,
|
|
CertFile: certFile,
|
|
CertPem: certPEMBlock,
|
|
Cert: cert,
|
|
Key: key,
|
|
}
|
|
}
|
|
|
|
// GenerateCertWithRoot generates a leaf certificate signed by a root CA
|
|
func GenerateCertWithRoot(t testing.TB) LeafWithRoot {
|
|
t.Helper()
|
|
tempDir := t.TempDir()
|
|
leafTemplate := &x509.Certificate{
|
|
Subject: pkix.Name{
|
|
CommonName: "localhost",
|
|
},
|
|
SerialNumber: big.NewInt(mathrand2.Int64()),
|
|
DNSNames: []string{"localhost"},
|
|
IPAddresses: []net.IP{net.ParseIP("127.0.0.1")},
|
|
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
|
|
NotBefore: time.Now().Add(-30 * time.Second),
|
|
NotAfter: time.Now().Add(60 * 24 * time.Hour),
|
|
}
|
|
|
|
ca := GenerateRootCa(t)
|
|
leafCert := generateCertAndSign(t, leafTemplate, ca, tempDir, "leaf_")
|
|
|
|
combinedCaLeafFile := filepath.Join(tempDir, "leaf-ca.pem")
|
|
err := os.WriteFile(combinedCaLeafFile, append(pem.EncodeToMemory(leafCert.CertPem), pem.EncodeToMemory(ca.CertPem)...), 0o644)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
return LeafWithRoot{
|
|
RootCa: ca,
|
|
Leaf: leafCert,
|
|
CombinedLeafCaFile: combinedCaLeafFile,
|
|
}
|
|
}
|
|
|
|
// GenerateRootCa generates a self-signed root CA certificate and key
|
|
func GenerateRootCa(t testing.TB) GeneratedCert {
|
|
t.Helper()
|
|
tempDir := t.TempDir()
|
|
|
|
caCertTemplate := &x509.Certificate{
|
|
Subject: pkix.Name{
|
|
CommonName: "Root CA",
|
|
},
|
|
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
|
|
SerialNumber: big.NewInt(mathrand2.Int64()),
|
|
NotBefore: time.Now().Add(-30 * time.Second),
|
|
NotAfter: time.Now().Add(262980 * time.Hour),
|
|
BasicConstraintsValid: true,
|
|
IsCA: true,
|
|
}
|
|
caKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
caBytes, err := x509.CreateCertificate(rand.Reader, caCertTemplate, caCertTemplate, caKey.Public(), caKey)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
caCert, err := x509.ParseCertificate(caBytes)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
caCertPEMBlock := &pem.Block{
|
|
Type: "CERTIFICATE",
|
|
Bytes: caBytes,
|
|
}
|
|
caFile := filepath.Join(tempDir, "ca_root_cert.pem")
|
|
err = os.WriteFile(caFile, pem.EncodeToMemory(caCertPEMBlock), 0o644)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
marshaledCAKey, err := x509.MarshalECPrivateKey(caKey)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
caKeyPEMBlock := &pem.Block{
|
|
Type: "EC PRIVATE KEY",
|
|
Bytes: marshaledCAKey,
|
|
}
|
|
caKeyFile := filepath.Join(tempDir, "ca_root_key.pem")
|
|
err = os.WriteFile(caKeyFile, pem.EncodeToMemory(caKeyPEMBlock), 0o644)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return GeneratedCert{
|
|
CertPem: caCertPEMBlock,
|
|
CertFile: caFile,
|
|
KeyFile: caKeyFile,
|
|
Cert: caCert,
|
|
Key: caKey,
|
|
}
|
|
}
|