Skip to content
Closed
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
17 changes: 15 additions & 2 deletions util/tls/tls.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,11 @@ func publicKey(priv interface{}) interface{} {
func pemBlockForKey(priv interface{}) *pem.Block {
switch k := priv.(type) {
case *rsa.PrivateKey:
// In Go 1.24+, MarshalPKCS1PrivateKey calls Precompute() which can panic
// if the key is invalid. Validate the key first.
if k == nil || k.Validate() != nil {
return nil
}
return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)}
case *ecdsa.PrivateKey:
b, err := x509.MarshalECPrivateKey(k)
Expand Down Expand Up @@ -298,7 +303,11 @@ func generatePEM(opts CertOptions) ([]byte, []byte, error) {
return nil, nil, err
}
certpem := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certBytes})
keypem := pem.EncodeToMemory(pemBlockForKey(privateKey))
keyBlock := pemBlockForKey(privateKey)
if keyBlock == nil {
return nil, nil, errors.New("failed to encode private key")
}
keypem := pem.EncodeToMemory(keyBlock)
return certpem, keypem, nil
}

Expand All @@ -321,7 +330,11 @@ func EncodeX509KeyPair(cert tls.Certificate) ([]byte, []byte) {
for _, certtmp := range cert.Certificate {
certpem = append(certpem, pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certtmp})...)
}
keypem := pem.EncodeToMemory(pemBlockForKey(cert.PrivateKey))
keyBlock := pemBlockForKey(cert.PrivateKey)
if keyBlock == nil {
return certpem, []byte{}
}
keypem := pem.EncodeToMemory(keyBlock)
return certpem, keypem
}

Expand Down
73 changes: 73 additions & 0 deletions util/tls/tls_test.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package tls

import (
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
"math/big"
"os"
"strings"
"testing"
Expand Down Expand Up @@ -452,3 +454,74 @@ func TestLoadX509CertPool(t *testing.T) {
require.Nil(t, p)
})
}

func TestEncodeX509KeyPair_InvalidRSAKey(t *testing.T) {
t.Run("Nil RSA private key", func(t *testing.T) {
cert := tls.Certificate{
Certificate: [][]byte{{0x30, 0x82}}, // minimal DER certificate bytes
PrivateKey: (*rsa.PrivateKey)(nil),
}
certPEM, keyPEM := EncodeX509KeyPair(cert)
assert.NotEmpty(t, certPEM)
assert.Empty(t, keyPEM)
})

t.Run("RSA private key that fails validation", func(t *testing.T) {
// Create an RSA key with invalid parameters that will fail Validate()
invalidKey := &rsa.PrivateKey{
PublicKey: rsa.PublicKey{
N: big.NewInt(1), // Too small modulus, will fail validation
E: 65537,
},
D: big.NewInt(1), // Invalid private exponent
}
cert := tls.Certificate{
Certificate: [][]byte{{0x30, 0x82}}, // minimal DER certificate bytes
PrivateKey: invalidKey,
}
certPEM, keyPEM := EncodeX509KeyPair(cert)
assert.NotEmpty(t, certPEM)
assert.Empty(t, keyPEM)
})

t.Run("RSA private key with inconsistent parameters", func(t *testing.T) {
invalidKey := &rsa.PrivateKey{
PublicKey: rsa.PublicKey{
N: big.NewInt(35),
E: 65537,
},
D: big.NewInt(99999),
}
cert := tls.Certificate{
Certificate: [][]byte{{0x30, 0x82}}, // minimal DER certificate bytes
PrivateKey: invalidKey,
}
certPEM, keyPEM := EncodeX509KeyPair(cert)
assert.NotEmpty(t, certPEM)
assert.Empty(t, keyPEM)
})

t.Run("Unsupported private key type", func(t *testing.T) {
// Use a type that's not *rsa.PrivateKey or *ecdsa.PrivateKey
cert := tls.Certificate{
Certificate: [][]byte{{0x30, 0x82}}, // minimal DER certificate bytes
PrivateKey: "not a private key", // Unsupported type
}
certPEM, keyPEM := EncodeX509KeyPair(cert)
assert.NotEmpty(t, certPEM)
assert.Empty(t, keyPEM)
})

t.Run("Valid RSA private key should work", func(t *testing.T) {
// Generate a valid RSA key for testing
opts := CertOptions{Hosts: []string{"localhost"}, Organization: "Test"}
validCert, err := GenerateX509KeyPair(opts)
require.NoError(t, err)

certPEM, keyPEM := EncodeX509KeyPair(*validCert)
assert.NotEmpty(t, certPEM)
assert.NotEmpty(t, keyPEM)
assert.Contains(t, string(keyPEM), "-----BEGIN RSA PRIVATE KEY-----")
assert.Contains(t, string(keyPEM), "-----END RSA PRIVATE KEY-----")
})
}
Loading