open-vault/sdk/helper/certutil/certutil_test.go
Alexander Scheel 412603befd
Fix RevocationSigAlg provisioning in GCP (#17449)
* Fix RevocationSigAlg provisioning in GCP

GCP restricts keys to a certain type of signature, including hash
algorithm, so we must provision our RevocationSigAlg from the root
itself unconditionally in order for GCP to work.

This does change the default, but only for newly created certificates.

Additionally, we clarify that CRL building is not fatal to the import
process.

Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>

* Add inverse mapping for SignatureAlgorithm

By default we'd use .String() on x509.SignatureAlgorithm, but this
doesn't round-trip. Switch to a custom map that is round-trippable
and matches the constant name as there is no other way to get this info
presently.

Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>

* Add test to ensure root creation sets rev_sig_alg

Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>

* Test round-tripping of SigAlgoNames, InvSigAlgoNames

Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>

* Fix failing Default Update test

Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>

Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
2022-10-06 17:50:49 -04:00

980 lines
28 KiB
Go

package certutil
import (
"bytes"
"crypto"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/json"
"encoding/pem"
"fmt"
"math/big"
mathrand "math/rand"
"reflect"
"strings"
"sync"
"testing"
"time"
"github.com/fatih/structs"
)
// Tests converting back and forth between a CertBundle and a ParsedCertBundle.
//
// Also tests the GetSubjKeyID, GetHexFormatted, and
// ParsedCertBundle.getSigner functions.
func TestCertBundleConversion(t *testing.T) {
cbuts := []*CertBundle{
refreshRSACertBundle(),
refreshRSACertBundleWithChain(),
refreshRSA8CertBundle(),
refreshRSA8CertBundleWithChain(),
refreshECCertBundle(),
refreshECCertBundleWithChain(),
refreshEC8CertBundle(),
refreshEC8CertBundleWithChain(),
refreshEd255198CertBundle(),
refreshEd255198CertBundleWithChain(),
}
for i, cbut := range cbuts {
pcbut, err := cbut.ToParsedCertBundle()
if err != nil {
t.Logf("Error occurred with bundle %d in test array (index %d).\n", i+1, i)
t.Errorf("Error converting to parsed cert bundle: %s", err)
continue
}
err = compareCertBundleToParsedCertBundle(cbut, pcbut)
if err != nil {
t.Logf("Error occurred with bundle %d in test array (index %d).\n", i+1, i)
t.Errorf(err.Error())
}
cbut, err := pcbut.ToCertBundle()
if err != nil {
t.Fatalf("Error converting to cert bundle: %s", err)
}
err = compareCertBundleToParsedCertBundle(cbut, pcbut)
if err != nil {
t.Fatalf(err.Error())
}
}
}
func BenchmarkCertBundleParsing(b *testing.B) {
for i := 0; i < b.N; i++ {
cbuts := []*CertBundle{
refreshRSACertBundle(),
refreshRSACertBundleWithChain(),
refreshRSA8CertBundle(),
refreshRSA8CertBundleWithChain(),
refreshECCertBundle(),
refreshECCertBundleWithChain(),
refreshEC8CertBundle(),
refreshEC8CertBundleWithChain(),
refreshEd255198CertBundle(),
refreshEd255198CertBundleWithChain(),
}
for i, cbut := range cbuts {
pcbut, err := cbut.ToParsedCertBundle()
if err != nil {
b.Logf("Error occurred with bundle %d in test array (index %d).\n", i+1, i)
b.Errorf("Error converting to parsed cert bundle: %s", err)
continue
}
cbut, err = pcbut.ToCertBundle()
if err != nil {
b.Fatalf("Error converting to cert bundle: %s", err)
}
}
}
}
func TestCertBundleParsing(t *testing.T) {
cbuts := []*CertBundle{
refreshRSACertBundle(),
refreshRSACertBundleWithChain(),
refreshRSA8CertBundle(),
refreshRSA8CertBundleWithChain(),
refreshECCertBundle(),
refreshECCertBundleWithChain(),
refreshEC8CertBundle(),
refreshEC8CertBundleWithChain(),
refreshEd255198CertBundle(),
refreshEd255198CertBundleWithChain(),
}
for i, cbut := range cbuts {
jsonString, err := json.Marshal(cbut)
if err != nil {
t.Logf("Error occurred with bundle %d in test array (index %d).\n", i+1, i)
t.Fatalf("Error marshaling testing certbundle to JSON: %s", err)
}
pcbut, err := ParsePKIJSON(jsonString)
if err != nil {
t.Logf("Error occurred with bundle %d in test array (index %d).\n", i+1, i)
t.Fatalf("Error during JSON bundle handling: %s", err)
}
err = compareCertBundleToParsedCertBundle(cbut, pcbut)
if err != nil {
t.Logf("Error occurred with bundle %d in test array (index %d).\n", i+1, i)
t.Fatalf(err.Error())
}
dataMap := structs.New(cbut).Map()
pcbut, err = ParsePKIMap(dataMap)
if err != nil {
t.Logf("Error occurred with bundle %d in test array (index %d).\n", i+1, i)
t.Fatalf("Error during JSON bundle handling: %s", err)
}
err = compareCertBundleToParsedCertBundle(cbut, pcbut)
if err != nil {
t.Logf("Error occurred with bundle %d in test array (index %d).\n", i+1, i)
t.Fatalf(err.Error())
}
pcbut, err = ParsePEMBundle(cbut.ToPEMBundle())
if err != nil {
t.Logf("Error occurred with bundle %d in test array (index %d).\n", i+1, i)
t.Fatalf("Error during JSON bundle handling: %s", err)
}
err = compareCertBundleToParsedCertBundle(cbut, pcbut)
if err != nil {
t.Logf("Error occurred with bundle %d in test array (index %d).\n", i+1, i)
t.Fatalf(err.Error())
}
}
}
func compareCertBundleToParsedCertBundle(cbut *CertBundle, pcbut *ParsedCertBundle) error {
if cbut == nil {
return fmt.Errorf("got nil bundle")
}
if pcbut == nil {
return fmt.Errorf("got nil parsed bundle")
}
switch {
case pcbut.Certificate == nil:
return fmt.Errorf("parsed bundle has nil certificate")
case pcbut.PrivateKey == nil:
return fmt.Errorf("parsed bundle has nil private key")
}
switch cbut.PrivateKey {
case privRSAKeyPem:
if pcbut.PrivateKeyType != RSAPrivateKey {
return fmt.Errorf("parsed bundle has wrong private key type: %v, should be 'rsa' (%v)", pcbut.PrivateKeyType, RSAPrivateKey)
}
case privRSA8KeyPem:
if pcbut.PrivateKeyType != RSAPrivateKey {
return fmt.Errorf("parsed bundle has wrong pkcs8 private key type: %v, should be 'rsa' (%v)", pcbut.PrivateKeyType, RSAPrivateKey)
}
case privECKeyPem:
if pcbut.PrivateKeyType != ECPrivateKey {
return fmt.Errorf("parsed bundle has wrong private key type: %v, should be 'ec' (%v)", pcbut.PrivateKeyType, ECPrivateKey)
}
case privEC8KeyPem:
if pcbut.PrivateKeyType != ECPrivateKey {
return fmt.Errorf("parsed bundle has wrong pkcs8 private key type: %v, should be 'ec' (%v)", pcbut.PrivateKeyType, ECPrivateKey)
}
case privEd255198KeyPem:
if pcbut.PrivateKeyType != Ed25519PrivateKey {
return fmt.Errorf("parsed bundle has wrong pkcs8 private key type: %v, should be 'ed25519' (%v)", pcbut.PrivateKeyType, ECPrivateKey)
}
default:
return fmt.Errorf("parsed bundle has unknown private key type")
}
subjKeyID, err := GetSubjKeyID(pcbut.PrivateKey)
if err != nil {
return fmt.Errorf("error when getting subject key id: %s", err)
}
if bytes.Compare(subjKeyID, pcbut.Certificate.SubjectKeyId) != 0 {
return fmt.Errorf("parsed bundle private key does not match subject key id\nGot\n%#v\nExpected\n%#v\nCert\n%#v", subjKeyID, pcbut.Certificate.SubjectKeyId, *pcbut.Certificate)
}
switch {
case len(pcbut.CAChain) > 0 && len(cbut.CAChain) == 0:
return fmt.Errorf("parsed bundle ca chain has certs when cert bundle does not")
case len(pcbut.CAChain) == 0 && len(cbut.CAChain) > 0:
return fmt.Errorf("cert bundle ca chain has certs when parsed cert bundle does not")
}
cb, err := pcbut.ToCertBundle()
if err != nil {
return fmt.Errorf("thrown error during parsed bundle conversion: %s\n\nInput was: %#v", err, *pcbut)
}
switch {
case len(cb.Certificate) == 0:
return fmt.Errorf("bundle has nil certificate")
case len(cb.PrivateKey) == 0:
return fmt.Errorf("bundle has nil private key")
case len(cb.CAChain[0]) == 0:
return fmt.Errorf("bundle has nil issuing CA")
}
switch pcbut.PrivateKeyType {
case RSAPrivateKey:
if cb.PrivateKey != privRSAKeyPem && cb.PrivateKey != privRSA8KeyPem {
return fmt.Errorf("bundle private key does not match")
}
case ECPrivateKey:
if cb.PrivateKey != privECKeyPem && cb.PrivateKey != privEC8KeyPem {
return fmt.Errorf("bundle private key does not match")
}
case Ed25519PrivateKey:
if cb.PrivateKey != privEd255198KeyPem {
return fmt.Errorf("bundle private key does not match")
}
default:
return fmt.Errorf("certBundle has unknown private key type")
}
if cb.SerialNumber != GetHexFormatted(pcbut.Certificate.SerialNumber.Bytes(), ":") {
return fmt.Errorf("bundle serial number does not match")
}
switch {
case len(pcbut.CAChain) > 0 && len(cb.CAChain) == 0:
return fmt.Errorf("parsed bundle ca chain has certs when cert bundle does not")
case len(pcbut.CAChain) == 0 && len(cb.CAChain) > 0:
return fmt.Errorf("cert bundle ca chain has certs when parsed cert bundle does not")
case !reflect.DeepEqual(cbut.CAChain, cb.CAChain):
return fmt.Errorf("cert bundle ca chain does not match: %#v\n\n%#v", cbut.CAChain, cb.CAChain)
}
return nil
}
func TestCSRBundleConversion(t *testing.T) {
csrbuts := []*CSRBundle{
refreshRSACSRBundle(),
refreshECCSRBundle(),
refreshEd25519CSRBundle(),
}
for _, csrbut := range csrbuts {
pcsrbut, err := csrbut.ToParsedCSRBundle()
if err != nil {
t.Fatalf("Error converting to parsed CSR bundle: %v", err)
}
err = compareCSRBundleToParsedCSRBundle(csrbut, pcsrbut)
if err != nil {
t.Fatalf(err.Error())
}
csrbut, err = pcsrbut.ToCSRBundle()
if err != nil {
t.Fatalf("Error converting to CSR bundle: %v", err)
}
err = compareCSRBundleToParsedCSRBundle(csrbut, pcsrbut)
if err != nil {
t.Fatalf(err.Error())
}
}
}
func compareCSRBundleToParsedCSRBundle(csrbut *CSRBundle, pcsrbut *ParsedCSRBundle) error {
if csrbut == nil {
return fmt.Errorf("got nil bundle")
}
if pcsrbut == nil {
return fmt.Errorf("got nil parsed bundle")
}
switch {
case pcsrbut.CSR == nil:
return fmt.Errorf("parsed bundle has nil csr")
case pcsrbut.PrivateKey == nil:
return fmt.Errorf("parsed bundle has nil private key")
}
switch csrbut.PrivateKey {
case privRSAKeyPem:
if pcsrbut.PrivateKeyType != RSAPrivateKey {
return fmt.Errorf("parsed bundle has wrong private key type")
}
case privECKeyPem:
if pcsrbut.PrivateKeyType != ECPrivateKey {
return fmt.Errorf("parsed bundle has wrong private key type")
}
case privEd255198KeyPem:
if pcsrbut.PrivateKeyType != Ed25519PrivateKey {
return fmt.Errorf("parsed bundle has wrong private key type")
}
default:
return fmt.Errorf("parsed bundle has unknown private key type")
}
csrb, err := pcsrbut.ToCSRBundle()
if err != nil {
return fmt.Errorf("Thrown error during parsed bundle conversion: %s\n\nInput was: %#v", err, *pcsrbut)
}
switch {
case len(csrb.CSR) == 0:
return fmt.Errorf("bundle has nil certificate")
case len(csrb.PrivateKey) == 0:
return fmt.Errorf("bundle has nil private key")
}
switch csrb.PrivateKeyType {
case "rsa":
if pcsrbut.PrivateKeyType != RSAPrivateKey {
return fmt.Errorf("bundle has wrong private key type")
}
if csrb.PrivateKey != privRSAKeyPem {
return fmt.Errorf("bundle rsa private key does not match\nGot\n%#v\nExpected\n%#v", csrb.PrivateKey, privRSAKeyPem)
}
case "ec":
if pcsrbut.PrivateKeyType != ECPrivateKey {
return fmt.Errorf("bundle has wrong private key type")
}
if csrb.PrivateKey != privECKeyPem {
return fmt.Errorf("bundle ec private key does not match")
}
case "ed25519":
if pcsrbut.PrivateKeyType != Ed25519PrivateKey {
return fmt.Errorf("bundle has wrong private key type")
}
if csrb.PrivateKey != privEd255198KeyPem {
return fmt.Errorf("bundle ed25519 private key does not match")
}
default:
return fmt.Errorf("bundle has unknown private key type")
}
return nil
}
func TestTLSConfig(t *testing.T) {
cbut := refreshRSACertBundle()
pcbut, err := cbut.ToParsedCertBundle()
if err != nil {
t.Fatalf("Error getting parsed cert bundle: %s", err)
}
usages := []TLSUsage{
TLSUnknown,
TLSClient,
TLSServer,
TLSClient | TLSServer,
}
for _, usage := range usages {
tlsConfig, err := pcbut.GetTLSConfig(usage)
if err != nil {
t.Fatalf("Error getting tls config: %s", err)
}
if tlsConfig == nil {
t.Fatalf("Got nil tls.Config")
}
if len(tlsConfig.Certificates) != 1 {
t.Fatalf("Unexpected length in config.Certificates")
}
// Length should be 2, since we passed in a CA
if len(tlsConfig.Certificates[0].Certificate) != 2 {
t.Fatalf("Did not find both certificates in config.Certificates.Certificate")
}
if tlsConfig.Certificates[0].Leaf != pcbut.Certificate {
t.Fatalf("Leaf certificate does not match parsed bundle's certificate")
}
if tlsConfig.Certificates[0].PrivateKey != pcbut.PrivateKey {
t.Fatalf("Config's private key does not match parsed bundle's private key")
}
switch usage {
case TLSServer | TLSClient:
if len(tlsConfig.ClientCAs.Subjects()) != 1 || bytes.Compare(tlsConfig.ClientCAs.Subjects()[0], pcbut.CAChain[0].Certificate.RawSubject) != 0 {
t.Fatalf("CA certificate not in client cert pool as expected")
}
if len(tlsConfig.RootCAs.Subjects()) != 1 || bytes.Compare(tlsConfig.RootCAs.Subjects()[0], pcbut.CAChain[0].Certificate.RawSubject) != 0 {
t.Fatalf("CA certificate not in root cert pool as expected")
}
case TLSServer:
if len(tlsConfig.ClientCAs.Subjects()) != 1 || bytes.Compare(tlsConfig.ClientCAs.Subjects()[0], pcbut.CAChain[0].Certificate.RawSubject) != 0 {
t.Fatalf("CA certificate not in client cert pool as expected")
}
if tlsConfig.RootCAs != nil {
t.Fatalf("Found root pools in config object when not expected")
}
case TLSClient:
if len(tlsConfig.RootCAs.Subjects()) != 1 || bytes.Compare(tlsConfig.RootCAs.Subjects()[0], pcbut.CAChain[0].Certificate.RawSubject) != 0 {
t.Fatalf("CA certificate not in root cert pool as expected")
}
if tlsConfig.ClientCAs != nil {
t.Fatalf("Found root pools in config object when not expected")
}
default:
if tlsConfig.RootCAs != nil || tlsConfig.ClientCAs != nil {
t.Fatalf("Found root pools in config object when not expected")
}
}
}
}
func TestNewCertPool(t *testing.T) {
caExample := `-----BEGIN CERTIFICATE-----
MIIC5zCCAc+gAwIBAgIBATANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQDEwptaW5p
a3ViZUNBMB4XDTE5MTIxMDIzMDUxOVoXDTI5MTIwODIzMDUxOVowFTETMBEGA1UE
AxMKbWluaWt1YmVDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANFi
/RIdMHd865X6JygTb9riX01DA3QnR+RoXDXNnj8D3LziLG2n8ItXMJvWbU3sxxyy
nX9HxJ0SIeexj1cYzdQBtJDjO1/PeuKc4CZ7zCukCAtHz8mC7BDPOU7F7pggpcQ0
/t/pa2m22hmCu8aDF9WlUYHtJpYATnI/A5vz/VFLR9daxmkl59Qo3oHITj7vAzSx
/75r9cibpQyJ+FhiHOZHQWYY2JYw2g4v5hm5hg5SFM9yFcZ75ISI9ebyFFIl9iBY
zAk9jqv1mXvLr0Q39AVwMTamvGuap1oocjM9NIhQvaFL/DNqF1ouDQjCf5u2imLc
TraO1/2KO8fqwOZCOrMCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgKkMB0GA1UdJQQW
MBQGCCsGAQUFBwMCBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3
DQEBCwUAA4IBAQBtVZCwCPqUUUpIClAlE9nc2fo2bTs9gsjXRmqdQ5oaSomSLE93
aJWYFuAhxPXtlApbLYZfW2m1sM3mTVQN60y0uE4e1jdSN1ErYQ9slJdYDAMaEmOh
iSexj+Nd1scUiMHV9lf3ps5J8sYeCpwZX3sPmw7lqZojTS12pANBDcigsaj5RRyN
9GyP3WkSQUsTpWlDb9Fd+KNdkCVw7nClIpBPA2KW4BQKw/rNSvOFD61mbzc89lo0
Q9IFGQFFF8jO18lbyWqnRBGXcS4/G7jQ3S7C121d14YLUeAYOM7pJykI1g4CLx9y
vitin0L6nprauWkKO38XgM4T75qKZpqtiOcT
-----END CERTIFICATE-----
`
if _, err := NewCertPool(bytes.NewReader([]byte(caExample))); err != nil {
t.Fatal(err)
}
}
func TestGetPublicKeySize(t *testing.T) {
rsa, err := rsa.GenerateKey(rand.Reader, 3072)
if err != nil {
t.Fatal(err)
}
if GetPublicKeySize(&rsa.PublicKey) != 3072 {
t.Fatal("unexpected rsa key size")
}
ecdsa, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
if err != nil {
t.Fatal(err)
}
if GetPublicKeySize(&ecdsa.PublicKey) != 384 {
t.Fatal("unexpected ecdsa key size")
}
ed25519, _, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
t.Fatal(err)
}
if GetPublicKeySize(ed25519) != 256 {
t.Fatal("unexpected ed25519 key size")
}
// Skipping DSA as too slow
}
func refreshRSA8CertBundle() *CertBundle {
initTest.Do(setCerts)
return &CertBundle{
Certificate: certRSAPem,
PrivateKey: privRSA8KeyPem,
CAChain: []string{issuingCaChainPem[0]},
}
}
func refreshRSA8CertBundleWithChain() *CertBundle {
initTest.Do(setCerts)
ret := refreshRSA8CertBundle()
ret.CAChain = issuingCaChainPem
return ret
}
func refreshRSACertBundle() *CertBundle {
initTest.Do(setCerts)
return &CertBundle{
Certificate: certRSAPem,
CAChain: []string{issuingCaChainPem[0]},
PrivateKey: privRSAKeyPem,
}
}
func refreshRSACertBundleWithChain() *CertBundle {
initTest.Do(setCerts)
ret := refreshRSACertBundle()
ret.CAChain = issuingCaChainPem
return ret
}
func refreshECCertBundle() *CertBundle {
initTest.Do(setCerts)
return &CertBundle{
Certificate: certECPem,
CAChain: []string{issuingCaChainPem[0]},
PrivateKey: privECKeyPem,
}
}
func refreshECCertBundleWithChain() *CertBundle {
initTest.Do(setCerts)
ret := refreshECCertBundle()
ret.CAChain = issuingCaChainPem
return ret
}
func refreshEd255198CertBundle() *CertBundle {
initTest.Do(setCerts)
return &CertBundle{
Certificate: certEd25519Pem,
PrivateKey: privEd255198KeyPem,
CAChain: []string{issuingCaChainPem[0]},
}
}
func refreshEd255198CertBundleWithChain() *CertBundle {
initTest.Do(setCerts)
ret := refreshEd255198CertBundle()
ret.CAChain = issuingCaChainPem
return ret
}
func refreshEd25519CSRBundle() *CSRBundle {
initTest.Do(setCerts)
return &CSRBundle{
CSR: csrEd25519Pem,
PrivateKey: privEd255198KeyPem,
}
}
func refreshRSACSRBundle() *CSRBundle {
initTest.Do(setCerts)
return &CSRBundle{
CSR: csrRSAPem,
PrivateKey: privRSAKeyPem,
}
}
func refreshECCSRBundle() *CSRBundle {
initTest.Do(setCerts)
return &CSRBundle{
CSR: csrECPem,
PrivateKey: privECKeyPem,
}
}
func refreshEC8CertBundle() *CertBundle {
initTest.Do(setCerts)
return &CertBundle{
Certificate: certECPem,
PrivateKey: privEC8KeyPem,
CAChain: []string{issuingCaChainPem[0]},
}
}
func refreshEC8CertBundleWithChain() *CertBundle {
initTest.Do(setCerts)
ret := refreshEC8CertBundle()
ret.CAChain = issuingCaChainPem
return ret
}
func setCerts() {
caKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
panic(err)
}
subjKeyID, err := GetSubjKeyID(caKey)
if err != nil {
panic(err)
}
caCertTemplate := &x509.Certificate{
Subject: pkix.Name{
CommonName: "root.localhost",
},
SubjectKeyId: subjKeyID,
DNSNames: []string{"root.localhost"},
KeyUsage: x509.KeyUsage(x509.KeyUsageCertSign | x509.KeyUsageCRLSign),
SerialNumber: big.NewInt(mathrand.Int63()),
NotBefore: time.Now().Add(-30 * time.Second),
NotAfter: time.Now().Add(262980 * time.Hour),
BasicConstraintsValid: true,
IsCA: true,
}
caBytes, err := x509.CreateCertificate(rand.Reader, caCertTemplate, caCertTemplate, caKey.Public(), caKey)
if err != nil {
panic(err)
}
caCert, err := x509.ParseCertificate(caBytes)
if err != nil {
panic(err)
}
caCertPEMBlock := &pem.Block{
Type: "CERTIFICATE",
Bytes: caBytes,
}
caCertPEM := strings.TrimSpace(string(pem.EncodeToMemory(caCertPEMBlock)))
intKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
panic(err)
}
subjKeyID, err = GetSubjKeyID(intKey)
if err != nil {
panic(err)
}
intCertTemplate := &x509.Certificate{
Subject: pkix.Name{
CommonName: "int.localhost",
},
SubjectKeyId: subjKeyID,
DNSNames: []string{"int.localhost"},
KeyUsage: x509.KeyUsage(x509.KeyUsageCertSign | x509.KeyUsageCRLSign),
SerialNumber: big.NewInt(mathrand.Int63()),
NotBefore: time.Now().Add(-30 * time.Second),
NotAfter: time.Now().Add(262980 * time.Hour),
BasicConstraintsValid: true,
IsCA: true,
}
intBytes, err := x509.CreateCertificate(rand.Reader, intCertTemplate, caCert, intKey.Public(), caKey)
if err != nil {
panic(err)
}
intCert, err := x509.ParseCertificate(intBytes)
if err != nil {
panic(err)
}
intCertPEMBlock := &pem.Block{
Type: "CERTIFICATE",
Bytes: intBytes,
}
intCertPEM := strings.TrimSpace(string(pem.EncodeToMemory(intCertPEMBlock)))
// EC generation
{
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
panic(err)
}
subjKeyID, err := GetSubjKeyID(key)
if err != nil {
panic(err)
}
certTemplate := &x509.Certificate{
Subject: pkix.Name{
CommonName: "localhost",
},
SubjectKeyId: subjKeyID,
DNSNames: []string{"localhost"},
ExtKeyUsage: []x509.ExtKeyUsage{
x509.ExtKeyUsageServerAuth,
x509.ExtKeyUsageClientAuth,
},
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment | x509.KeyUsageKeyAgreement,
SerialNumber: big.NewInt(mathrand.Int63()),
NotBefore: time.Now().Add(-30 * time.Second),
NotAfter: time.Now().Add(262980 * time.Hour),
}
csrTemplate := &x509.CertificateRequest{
Subject: pkix.Name{
CommonName: "localhost",
},
DNSNames: []string{"localhost"},
}
csrBytes, err := x509.CreateCertificateRequest(rand.Reader, csrTemplate, key)
if err != nil {
panic(err)
}
csrPEMBlock := &pem.Block{
Type: "CERTIFICATE REQUEST",
Bytes: csrBytes,
}
csrECPem = strings.TrimSpace(string(pem.EncodeToMemory(csrPEMBlock)))
certBytes, err := x509.CreateCertificate(rand.Reader, certTemplate, intCert, key.Public(), intKey)
if err != nil {
panic(err)
}
certPEMBlock := &pem.Block{
Type: "CERTIFICATE",
Bytes: certBytes,
}
certECPem = strings.TrimSpace(string(pem.EncodeToMemory(certPEMBlock)))
marshaledKey, err := x509.MarshalECPrivateKey(key)
if err != nil {
panic(err)
}
keyPEMBlock := &pem.Block{
Type: "EC PRIVATE KEY",
Bytes: marshaledKey,
}
privECKeyPem = strings.TrimSpace(string(pem.EncodeToMemory(keyPEMBlock)))
marshaledKey, err = x509.MarshalPKCS8PrivateKey(key)
if err != nil {
panic(err)
}
keyPEMBlock = &pem.Block{
Type: "PRIVATE KEY",
Bytes: marshaledKey,
}
privEC8KeyPem = strings.TrimSpace(string(pem.EncodeToMemory(keyPEMBlock)))
}
// RSA generation
{
key, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
panic(err)
}
subjKeyID, err := GetSubjKeyID(key)
if err != nil {
panic(err)
}
certTemplate := &x509.Certificate{
Subject: pkix.Name{
CommonName: "localhost",
},
SubjectKeyId: subjKeyID,
DNSNames: []string{"localhost"},
ExtKeyUsage: []x509.ExtKeyUsage{
x509.ExtKeyUsageServerAuth,
x509.ExtKeyUsageClientAuth,
},
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment | x509.KeyUsageKeyAgreement,
SerialNumber: big.NewInt(mathrand.Int63()),
NotBefore: time.Now().Add(-30 * time.Second),
NotAfter: time.Now().Add(262980 * time.Hour),
}
csrTemplate := &x509.CertificateRequest{
Subject: pkix.Name{
CommonName: "localhost",
},
DNSNames: []string{"localhost"},
}
csrBytes, err := x509.CreateCertificateRequest(rand.Reader, csrTemplate, key)
if err != nil {
panic(err)
}
csrPEMBlock := &pem.Block{
Type: "CERTIFICATE REQUEST",
Bytes: csrBytes,
}
csrRSAPem = strings.TrimSpace(string(pem.EncodeToMemory(csrPEMBlock)))
certBytes, err := x509.CreateCertificate(rand.Reader, certTemplate, intCert, key.Public(), intKey)
if err != nil {
panic(err)
}
certPEMBlock := &pem.Block{
Type: "CERTIFICATE",
Bytes: certBytes,
}
certRSAPem = strings.TrimSpace(string(pem.EncodeToMemory(certPEMBlock)))
marshaledKey := x509.MarshalPKCS1PrivateKey(key)
keyPEMBlock := &pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: marshaledKey,
}
privRSAKeyPem = strings.TrimSpace(string(pem.EncodeToMemory(keyPEMBlock)))
marshaledKey, err = x509.MarshalPKCS8PrivateKey(key)
if err != nil {
panic(err)
}
keyPEMBlock = &pem.Block{
Type: "PRIVATE KEY",
Bytes: marshaledKey,
}
privRSA8KeyPem = strings.TrimSpace(string(pem.EncodeToMemory(keyPEMBlock)))
}
// Ed25519 generation
{
pubkey, privkey, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
panic(err)
}
subjKeyID, err := GetSubjKeyID(privkey)
if err != nil {
panic(err)
}
certTemplate := &x509.Certificate{
Subject: pkix.Name{
CommonName: "localhost",
},
SubjectKeyId: subjKeyID,
DNSNames: []string{"localhost"},
ExtKeyUsage: []x509.ExtKeyUsage{
x509.ExtKeyUsageServerAuth,
x509.ExtKeyUsageClientAuth,
},
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment | x509.KeyUsageKeyAgreement,
SerialNumber: big.NewInt(mathrand.Int63()),
NotBefore: time.Now().Add(-30 * time.Second),
NotAfter: time.Now().Add(262980 * time.Hour),
}
csrTemplate := &x509.CertificateRequest{
Subject: pkix.Name{
CommonName: "localhost",
},
DNSNames: []string{"localhost"},
}
csrBytes, err := x509.CreateCertificateRequest(rand.Reader, csrTemplate, privkey)
if err != nil {
panic(err)
}
csrPEMBlock := &pem.Block{
Type: "CERTIFICATE REQUEST",
Bytes: csrBytes,
}
csrEd25519Pem = strings.TrimSpace(string(pem.EncodeToMemory(csrPEMBlock)))
certBytes, err := x509.CreateCertificate(rand.Reader, certTemplate, intCert, pubkey, intKey)
if err != nil {
panic(err)
}
certPEMBlock := &pem.Block{
Type: "CERTIFICATE",
Bytes: certBytes,
}
certEd25519Pem = strings.TrimSpace(string(pem.EncodeToMemory(certPEMBlock)))
marshaledKey, err := x509.MarshalPKCS8PrivateKey(privkey)
if err != nil {
panic(err)
}
keyPEMBlock := &pem.Block{
Type: "PRIVATE KEY",
Bytes: marshaledKey,
}
privEd255198KeyPem = strings.TrimSpace(string(pem.EncodeToMemory(keyPEMBlock)))
}
issuingCaChainPem = []string{intCertPEM, caCertPEM}
}
func TestComparePublicKeysAndType(t *testing.T) {
rsa1 := genRsaKey(t).Public()
rsa2 := genRsaKey(t).Public()
eddsa1 := genEdDSA(t).Public()
eddsa2 := genEdDSA(t).Public()
ed25519_1, _ := genEd25519Key(t)
ed25519_2, _ := genEd25519Key(t)
type args struct {
key1Iface crypto.PublicKey
key2Iface crypto.PublicKey
}
tests := []struct {
name string
args args
want bool
wantErr bool
}{
{name: "RSA_Equal", args: args{key1Iface: rsa1, key2Iface: rsa1}, want: true, wantErr: false},
{name: "RSA_NotEqual", args: args{key1Iface: rsa1, key2Iface: rsa2}, want: false, wantErr: false},
{name: "EDDSA_Equal", args: args{key1Iface: eddsa1, key2Iface: eddsa1}, want: true, wantErr: false},
{name: "EDDSA_NotEqual", args: args{key1Iface: eddsa1, key2Iface: eddsa2}, want: false, wantErr: false},
{name: "ED25519_Equal", args: args{key1Iface: ed25519_1, key2Iface: ed25519_1}, want: true, wantErr: false},
{name: "ED25519_NotEqual", args: args{key1Iface: ed25519_1, key2Iface: ed25519_2}, want: false, wantErr: false},
{name: "Mismatched_RSA", args: args{key1Iface: rsa1, key2Iface: ed25519_2}, want: false, wantErr: false},
{name: "Mismatched_EDDSA", args: args{key1Iface: ed25519_1, key2Iface: rsa1}, want: false, wantErr: false},
{name: "Mismatched_ED25519", args: args{key1Iface: ed25519_1, key2Iface: rsa1}, want: false, wantErr: false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := ComparePublicKeysAndType(tt.args.key1Iface, tt.args.key2Iface)
if (err != nil) != tt.wantErr {
t.Errorf("ComparePublicKeysAndType() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("ComparePublicKeysAndType() got = %v, want %v", got, tt.want)
}
})
}
}
func TestNotAfterValues(t *testing.T) {
if ErrNotAfterBehavior != 0 {
t.Fatalf("Expected ErrNotAfterBehavior=%v to have value 0", ErrNotAfterBehavior)
}
if TruncateNotAfterBehavior != 1 {
t.Fatalf("Expected TruncateNotAfterBehavior=%v to have value 1", TruncateNotAfterBehavior)
}
if PermitNotAfterBehavior != 2 {
t.Fatalf("Expected PermitNotAfterBehavior=%v to have value 2", PermitNotAfterBehavior)
}
}
func TestSignatureAlgorithmRoundTripping(t *testing.T) {
for leftName, value := range SignatureAlgorithmNames {
if leftName == "pureed25519" && value == x509.PureEd25519 {
continue
}
rightName, present := InvSignatureAlgorithmNames[value]
if !present {
t.Fatalf("%v=%v is present in SignatureAlgorithmNames but not in InvSignatureAlgorithmNames", leftName, value)
}
if strings.ToLower(rightName) != leftName {
t.Fatalf("%v=%v is present in SignatureAlgorithmNames but inverse for %v has different name: %v", leftName, value, value, rightName)
}
}
for leftValue, name := range InvSignatureAlgorithmNames {
rightValue, present := SignatureAlgorithmNames[strings.ToLower(name)]
if !present {
t.Fatalf("%v=%v is present in InvSignatureAlgorithmNames but not in SignatureAlgorithmNames", leftValue, name)
}
if rightValue != leftValue {
t.Fatalf("%v=%v is present in InvSignatureAlgorithmNames but forwards for %v has different value: %v", leftValue, name, name, rightValue)
}
}
}
func genRsaKey(t *testing.T) *rsa.PrivateKey {
key, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
t.Fatal(err)
}
return key
}
func genEdDSA(t *testing.T) *ecdsa.PrivateKey {
key, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
if err != nil {
t.Fatal(err)
}
return key
}
func genEd25519Key(t *testing.T) (ed25519.PublicKey, ed25519.PrivateKey) {
key, priv, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
t.Fatal(err)
}
return key, priv
}
var (
initTest sync.Once
privRSA8KeyPem string
privRSAKeyPem string
csrRSAPem string
certRSAPem string
privEd255198KeyPem string
csrEd25519Pem string
certEd25519Pem string
privECKeyPem string
csrECPem string
privEC8KeyPem string
certECPem string
issuingCaChainPem []string
)