Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions internal/egress/certs.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package egress

import (
"container/list"
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
Expand All @@ -21,7 +22,7 @@ import (

type CertificateAuthority struct {
cert *x509.Certificate
privateKey any
privateKey crypto.Signer
fingerprint string
}

Expand All @@ -46,14 +47,31 @@ func LoadCertificateAuthority(certPath string, keyPath string) (*CertificateAuth
if keyBlock == nil {
return nil, fmt.Errorf("decode egress ca key: missing PEM block")
}
key, err := x509.ParsePKCS8PrivateKey(keyBlock.Bytes)
key, err := parsePrivateKey(keyBlock.Bytes)
if err != nil {
return nil, fmt.Errorf("parse egress ca key: %w", err)
}
fingerprintBytes := sha256.Sum256(cert.Raw)
return &CertificateAuthority{cert: cert, privateKey: key, fingerprint: hex.EncodeToString(fingerprintBytes[:])}, nil
}

func parsePrivateKey(der []byte) (crypto.Signer, error) {
if key, err := x509.ParsePKCS8PrivateKey(der); err == nil {
signer, ok := key.(crypto.Signer)
if !ok {
return nil, fmt.Errorf("PKCS#8 private key type %T does not implement crypto.Signer", key)
}
return signer, nil
}
if key, err := x509.ParseECPrivateKey(der); err == nil {
return key, nil
}
if key, err := x509.ParsePKCS1PrivateKey(der); err == nil {
return key, nil
}
return nil, fmt.Errorf("unsupported private key format")
}

type LeafCertificateCache struct {
ca *CertificateAuthority
clock Clock
Expand Down
21 changes: 21 additions & 0 deletions internal/egress/egress_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -801,6 +801,27 @@ func headerSecret(name string, secretID string, scheme egressv1.HeaderAuthScheme
return &egressv1.EgressRuleHeader{Name: name, Scheme: scheme, Credential: &egressv1.EgressRuleHeader_SecretId{SecretId: secretID}}
}

func TestLoadCertificateAuthorityAcceptsECPrivateKey(t *testing.T) {
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
t.Fatalf("generate ca key: %v", err)
}
template := &x509.Certificate{SerialNumber: big.NewInt(1), Subject: pkix.Name{CommonName: "test ca"}, NotBefore: time.Now().Add(-time.Minute), NotAfter: time.Now().Add(time.Hour), IsCA: true, KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageDigitalSignature, BasicConstraintsValid: true}
der, err := x509.CreateCertificate(rand.Reader, template, template, key.Public(), key)
if err != nil {
t.Fatalf("create ca cert: %v", err)
}
keyBytes, err := x509.MarshalECPrivateKey(key)
if err != nil {
t.Fatalf("marshal ca key: %v", err)
}
certFile := tempPEM(t, "CERTIFICATE", der)
keyFile := tempPEM(t, "EC PRIVATE KEY", keyBytes)
if _, err := LoadCertificateAuthority(certFile, keyFile); err != nil {
t.Fatalf("LoadCertificateAuthority: %v", err)
}
}

func testCA(t *testing.T) *CertificateAuthority {
t.Helper()
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
Expand Down
Loading