Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support ECDSA private keys #667

Merged
merged 2 commits into from
Jan 17, 2025
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
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -229,8 +229,8 @@ metallb:
cat hack/metallb.yaml | sed -E "s|172.19|$$(docker network inspect -f '{{range .IPAM.Config}}{{.Gateway}}{{end}}' kind | sed -E 's|^([0-9]+\.[0-9]+)\..*$$|\1|g')|g" | kubectl apply -f -

cert-manager:
$(HELM) repo add bitnami https://charts.bitnami.com/bitnami
$(HELM) upgrade --install cert-manager bitnami/cert-manager --namespace certmanager-system --create-namespace --set "installCRDs=true"
$(HELM) repo add jetstack https://charts.jetstack.io
$(HELM) upgrade --install cert-manager jetstack/cert-manager --namespace certmanager-system --create-namespace --set "installCRDs=true"
Comment on lines +232 to +233
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QQ: what's wrong with Bitnami's chart?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like they have a broken dependency or something. Either way, bitnami charts tend to have some extra stuff which isn't really needed in most cases (IMO).

https://github.com/clastix/kamaji/actions/runs/12776386026/job/35614933651

Release "cert-manager" does not exist. Installing it now.
index.go:346: skipping loading invalid entry for chart "airflow" "" from /home/runner/.cache/helm/repository/bitnami-index.yaml: validation: chart.metadata.version is required
Error: failed to download "bitnami/cert-manager"


load: kind
$(KIND) load docker-image --name kamaji ${CONTAINER_REPOSITORY}:${VERSION}
Expand Down
27 changes: 19 additions & 8 deletions internal/crypto/crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package crypto

import (
"bytes"
"crypto"
cryptorand "crypto/rand"
"crypto/rsa"
"crypto/x509"
Expand Down Expand Up @@ -36,7 +37,7 @@ func CheckPublicAndPrivateKeyValidity(publicKey []byte, privateKey []byte) (bool
return false, err
}

return checkPublicKeys(privKey.PublicKey, *pubKey), nil
return checkPublicKeys(pubKey, privKey), nil
}

// CheckCertificateSAN checks if the Kubernetes API Server certificate matches the SAN stored in the kubeadm:
Expand Down Expand Up @@ -114,12 +115,21 @@ func ParseCertificateBytes(content []byte) (*x509.Certificate, error) {
}

// ParsePrivateKeyBytes takes the private key bytes returning an RSA private key by parsing it.
func ParsePrivateKeyBytes(content []byte) (*rsa.PrivateKey, error) {
func ParsePrivateKeyBytes(content []byte) (crypto.Signer, error) {
pemContent, _ := pem.Decode(content)
if pemContent == nil {
return nil, fmt.Errorf("no right PEM block")
}

if pemContent.Type == "EC PRIVATE KEY" {
privateKey, err := x509.ParseECPrivateKey(pemContent.Bytes)
if err != nil {
return nil, errors.Wrap(err, "cannot parse EC Private Key")
}

return privateKey, nil
}

privateKey, err := x509.ParsePKCS1PrivateKey(pemContent.Bytes)
if err != nil {
return nil, errors.Wrap(err, "cannot parse PKCS1 Private Key")
Expand Down Expand Up @@ -163,7 +173,7 @@ func IsValidCertificateKeyPairBytes(certificateBytes []byte, privateKeyBytes []b
switch {
case !checkCertificateValidity(*crt):
return false, nil
case !checkPublicKeys(*crt.PublicKey.(*rsa.PublicKey), key.PublicKey): //nolint:forcetypeassert
case !checkPublicKeys(crt.PublicKey, key):
return false, nil
default:
return true, nil
Expand Down Expand Up @@ -196,7 +206,7 @@ func VerifyCertificate(cert, ca []byte, usages ...x509.ExtKeyUsage) (bool, error
return len(chains) > 0, err
}

func generateCertificateKeyPairBytes(template *x509.Certificate, caCert *x509.Certificate, caKey *rsa.PrivateKey) (*bytes.Buffer, *bytes.Buffer, error) {
func generateCertificateKeyPairBytes(template *x509.Certificate, caCert *x509.Certificate, caKey crypto.Signer) (*bytes.Buffer, *bytes.Buffer, error) {
certPrivKey, err := rsa.GenerateKey(cryptorand.Reader, 2048)
if err != nil {
return nil, nil, errors.Wrap(err, "cannot generate an RSA key")
Expand Down Expand Up @@ -236,11 +246,12 @@ func checkCertificateValidity(cert x509.Certificate) bool {
return notAfter && notBefore
}

func checkPublicKeys(a rsa.PublicKey, b rsa.PublicKey) bool {
isN := a.N.Cmp(b.N) == 0
isE := a.E == b.E
func checkPublicKeys(a crypto.PublicKey, b crypto.Signer) bool {
if key, ok := a.(interface{ Equal(k crypto.PublicKey) bool }); ok {
return key.Equal(b.Public())
}

return isN && isE
return false
}

// NewCertificateTemplate returns the template that must be used to generate a certificate,
Expand Down