diff --git a/kpconfig.go b/kpconfig.go index f9303e2..4748fbc 100644 --- a/kpconfig.go +++ b/kpconfig.go @@ -2,6 +2,7 @@ package testcerts import ( "errors" + "math/big" "net" ) @@ -22,6 +23,12 @@ type KeyPairConfig struct { // IPAddresses is a list of IP addresses to include in the certificate // as Subject Alternative Names. IPAddresses []string + + // SerialNumber is the serial number to use for the certificate. + SerialNumber *big.Int + + // CommonName is the Common Name to use for the certificate. + CommonName string } // Validate validates the KeyPairConfig ensuring that it is not empty and that diff --git a/testcerts.go b/testcerts.go index 2d62373..855e4f1 100644 --- a/testcerts.go +++ b/testcerts.go @@ -158,14 +158,21 @@ func (ca *CertificateAuthority) NewKeyPairFromConfig(config KeyPairConfig) (*Key return nil, err } + // If a serial number is provided, use it, otherwise use 42 + serialNumber := config.SerialNumber + if serialNumber == nil { + serialNumber = big.NewInt(42) + } + // Create a Certificate kp := &KeyPair{cert: &x509.Certificate{ Subject: pkix.Name{ Organization: []string{"Never Use this Certificate in Production Inc."}, + CommonName: config.CommonName, }, DNSNames: config.Domains, IPAddresses: ips, - SerialNumber: big.NewInt(42), + SerialNumber: serialNumber, NotBefore: time.Now().Add(-1 * time.Hour), NotAfter: time.Now().Add(2 * time.Hour), ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, diff --git a/testcerts_test.go b/testcerts_test.go index 9d1e462..c097850 100644 --- a/testcerts_test.go +++ b/testcerts_test.go @@ -4,6 +4,7 @@ import ( "crypto/tls" "crypto/x509" "fmt" + "math/big" "net/http" "os" "path/filepath" @@ -273,6 +274,22 @@ func TestKeyPairConfig(t *testing.T) { }, err: ErrInvalidIP, }, + { + name: "Happy Path - Serial Number provided", + cfg: KeyPairConfig{ + Domains: []string{"example.com"}, + SerialNumber: big.NewInt(123), + }, + err: nil, + }, + { + name: "Happy Path - Common Name provided", + cfg: KeyPairConfig{ + Domains: []string{"example.com"}, + CommonName: "Example Common Name", + }, + err: nil, + }, } for _, c := range tc { @@ -290,6 +307,34 @@ func TestKeyPairConfig(t *testing.T) { } }) } + + t.Run("Serial Number is correct in Key Pair", func(t *testing.T) { + certs, err := NewCA().NewKeyPairFromConfig(KeyPairConfig{ + Domains: []string{"example.com"}, + SerialNumber: big.NewInt(123), + }) + if err != nil { + t.Fatalf("KeyPair Generation Failed expected nil got %v", err) + } + + if certs.cert.SerialNumber.Cmp(big.NewInt(123)) != 0 { + t.Fatalf("Unexpected Serial Number expected 123 got %v", certs.cert.SerialNumber) + } + }) + + t.Run("Common Name is correct in Key Pair", func(t *testing.T) { + certs, err := NewCA().NewKeyPairFromConfig(KeyPairConfig{ + Domains: []string{"example.com"}, + CommonName: "Example Common Name", + }) + if err != nil { + t.Fatalf("KeyPair Generation Failed expected nil got %v", err) + } + + if certs.cert.Subject.CommonName != "Example Common Name" { + t.Fatalf("Unexpected Common Name expected 'Example Common Name' got %v", certs.cert.Subject.CommonName) + } + }) } type FullFlowTestCase struct { @@ -327,6 +372,17 @@ func TestFullFlow(t *testing.T) { }, kpErr: nil, }, + { + name: "Localhost IP, Domain, Serial Number, and Common Name", + listenAddr: "0.0.0.0", + kpCfg: KeyPairConfig{ + IPAddresses: []string{"127.0.0.1", "::1"}, + Domains: []string{"localhost"}, + SerialNumber: big.NewInt(123), + CommonName: "Example Common Name", + }, + kpErr: nil, + }, } for _, c := range tc {