diff --git a/pkg/installer/aroboundsasigningkey.go b/pkg/installer/aroboundsasigningkey.go index 48e640fb6..66a238579 100644 --- a/pkg/installer/aroboundsasigningkey.go +++ b/pkg/installer/aroboundsasigningkey.go @@ -4,6 +4,7 @@ package installer // Licensed under the Apache License 2.0. import ( + "crypto" "os" "path/filepath" @@ -43,12 +44,16 @@ func (sk *AROBoundSASigningKey) Load(f asset.FileFetcher) (bool, error) { return false, err } - rsaKey, err := tls.PemToPrivateKey(keyFile.Data) + privateKey, err := pemToPrivateKey(keyFile.Data) if err != nil { - logrus.Debugf("Failed to load rsa.PrivateKey from file: %s", err) - return false, errors.Wrap(err, "failed to load rsa.PrivateKey from the file") + logrus.Debugf("Failed to load private key from file: %s", err) + return false, errors.Wrap(err, "failed to load private key from the file") } - pubData, err := tls.PublicKeyToPem(&rsaKey.PublicKey) + signer, ok := privateKey.(crypto.Signer) + if !ok { + return false, errors.New("private key does not implement crypto.Signer") + } + pubData, err := publicKeyToPem(signer.Public()) if err != nil { return false, errors.Wrap(err, "failed to extract public key from the key") } diff --git a/pkg/installer/custominstallconfig_test.go b/pkg/installer/custominstallconfig_test.go index 4e61820f7..6a44a9d5f 100644 --- a/pkg/installer/custominstallconfig_test.go +++ b/pkg/installer/custominstallconfig_test.go @@ -33,7 +33,6 @@ import ( icazure "github.com/openshift/installer/pkg/asset/installconfig/azure" "github.com/openshift/installer/pkg/asset/installconfig/azure/mock" "github.com/openshift/installer/pkg/asset/releaseimage" - "github.com/openshift/installer/pkg/asset/tls" "github.com/openshift/installer/pkg/ipnet" "github.com/openshift/installer/pkg/types" azuretypes "github.com/openshift/installer/pkg/types/azure" @@ -471,7 +470,7 @@ func verifyUpdateMCSCertKey(t *testing.T, bootstrap *bootstrap.Bootstrap) { } rawCert = decodedCert assert.NotNil(t, rawCert) - cert, err = tls.PemToCertificate(decodedCert) + cert, err = pemToCertificate(decodedCert) if err != nil { t.Fatal(err) } diff --git a/pkg/installer/pemutils.go b/pkg/installer/pemutils.go new file mode 100644 index 000000000..12a071b64 --- /dev/null +++ b/pkg/installer/pemutils.go @@ -0,0 +1,56 @@ +package installer + +// Copyright (c) Microsoft Corporation. +// Licensed under the Apache License 2.0. + +import ( + "crypto" + "crypto/ecdsa" + "crypto/rsa" + "crypto/x509" + "encoding/pem" + "fmt" +) + +func pemToPrivateKey(data []byte) (crypto.PrivateKey, error) { + block, _ := pem.Decode(data) + if block == nil { + return nil, fmt.Errorf("could not find a PEM block in the private key") + } + + switch block.Type { + case "RSA PRIVATE KEY": + return x509.ParsePKCS1PrivateKey(block.Bytes) + case "EC PRIVATE KEY": + return x509.ParseECPrivateKey(block.Bytes) + case "PRIVATE KEY": + key, err := x509.ParsePKCS8PrivateKey(block.Bytes) + if err != nil { + return nil, err + } + switch key.(type) { + case *rsa.PrivateKey, *ecdsa.PrivateKey: + return key, nil + default: + return nil, fmt.Errorf("unsupported PKCS#8 key type: %T", key) + } + default: + return nil, fmt.Errorf("unsupported PEM block type: %s", block.Type) + } +} + +func pemToCertificate(data []byte) (*x509.Certificate, error) { + block, _ := pem.Decode(data) + if block == nil { + return nil, fmt.Errorf("could not find a PEM block in the certificate") + } + return x509.ParseCertificate(block.Bytes) +} + +func publicKeyToPem(pub crypto.PublicKey) ([]byte, error) { + keyBytes, err := x509.MarshalPKIXPublicKey(pub) + if err != nil { + return nil, fmt.Errorf("failed to marshal public key: %w", err) + } + return pem.EncodeToMemory(&pem.Block{Type: "PUBLIC KEY", Bytes: keyBytes}), nil +} diff --git a/pkg/installer/regenerate_mcs_certs.go b/pkg/installer/regenerate_mcs_certs.go index 6c7ff2b0f..63c8fbd4e 100644 --- a/pkg/installer/regenerate_mcs_certs.go +++ b/pkg/installer/regenerate_mcs_certs.go @@ -9,6 +9,7 @@ import ( "crypto/x509" "crypto/x509/pkix" "encoding/base64" + "encoding/pem" "fmt" "net" "strings" @@ -39,40 +40,42 @@ const ( header = "data:text/plain;charset=utf-8;base64," ) -// RegenerateSignedCertKey regenerates a cert/key pair signed by the specified parent CA. +// regenerateSignedCertKey regenerates a cert/key pair signed by the specified parent CA. // It does not write the cert/key pair to an asset file. func regenerateSignedCertKey( cfg *tls.CertCfg, parentCA tls.CertKeyInterface, appendParent tls.AppendParentChoice, ) ([]byte, []byte, error) { - var key *rsa.PrivateKey - var crt *x509.Certificate - var err error - - caKey, err := tls.PemToPrivateKey(parentCA.Key()) + caKeyRaw, err := pemToPrivateKey(parentCA.Key()) if err != nil { - logrus.Debugf("Failed to parse RSA private key: %s", err) - return nil, nil, errors.Wrap(err, "failed to parse rsa private key") + logrus.Debugf("Failed to parse private key: %s", err) + return nil, nil, errors.Wrap(err, "failed to parse private key") + } + + caKey, ok := caKeyRaw.(*rsa.PrivateKey) + if !ok { + return nil, nil, fmt.Errorf("expected RSA private key, got %T", caKeyRaw) } - caCert, err := tls.PemToCertificate(parentCA.Cert()) + caCert, err := pemToCertificate(parentCA.Cert()) if err != nil { logrus.Debugf("Failed to parse x509 certificate: %s", err) return nil, nil, errors.Wrap(err, "failed to parse x509 certificate") } - key, crt, err = tls.GenerateSignedCertificate(caKey, caCert, cfg) + key, crt, err := tls.GenerateSignedCertificate(caKey, caCert, cfg) if err != nil { logrus.Debugf("Failed to generate signed cert/key pair: %s", err) return nil, nil, errors.Wrap(err, "failed to generate signed cert/key pair") } - keyRaw := tls.PrivateKeyToPem(key) - certRaw := tls.CertToPem(crt) + keyRaw := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)}) + certRaw := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: crt.Raw}) if appendParent { - certRaw = bytes.Join([][]byte{certRaw, tls.CertToPem(caCert)}, []byte("\n")) + caCertRaw := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: caCert.Raw}) + certRaw = bytes.Join([][]byte{certRaw, caCertRaw}, []byte("\n")) } return keyRaw, certRaw, nil