From dde366dc86e255859d2457915a9f66cbb73836aa Mon Sep 17 00:00:00 2001 From: Luis Sanchez Date: Mon, 6 Apr 2026 16:11:46 -0400 Subject: [PATCH] Replace installer TLS utility functions with Go stdlib Replace usage of github.com/openshift/installer/pkg/asset/tls utility functions (PemToPrivateKey, PemToCertificate, PrivateKeyToPem, CertToPem, PublicKeyToPem) with Go standard library equivalents. This reduces coupling to the installer's internal crypto utilities, which are being deprecated upstream in favor of library-go/pkg/crypto. The new local helpers support both RSA and ECDSA key types, aligning with the upstream direction. Installer asset types (RootCA, BoundSASigningKey, CertCfg, GenerateSignedCertificate) are retained as they are fundamental to the wrapper's graph-based architecture. --- pkg/installer/aroboundsasigningkey.go | 13 ++++-- pkg/installer/custominstallconfig_test.go | 3 +- pkg/installer/pemutils.go | 56 +++++++++++++++++++++++ pkg/installer/regenerate_mcs_certs.go | 29 ++++++------ 4 files changed, 82 insertions(+), 19 deletions(-) create mode 100644 pkg/installer/pemutils.go 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