diff --git a/pkg/pki/x509/x509.go b/pkg/pki/x509/x509.go index 6b5e30270..aefff8af6 100644 --- a/pkg/pki/x509/x509.go +++ b/pkg/pki/x509/x509.go @@ -106,8 +106,9 @@ func NewPublicKey(r io.Reader) (*PublicKey, error) { if err != nil { return nil, err } + trimmedRawPub := bytes.TrimSpace(rawPub) - block, rest := pem.Decode(rawPub) + block, rest := pem.Decode(trimmedRawPub) if block == nil { return nil, errors.New("invalid public key: failure decoding PEM") } @@ -115,7 +116,7 @@ func NewPublicKey(r io.Reader) (*PublicKey, error) { // Handle certificate chain, concatenated PEM-encoded certificates if len(rest) > 0 { // Support up to 10 certificates in a chain, to avoid parsing extremely long chains - certs, err := cryptoutils.UnmarshalCertificatesFromPEMLimited(rawPub, 10) + certs, err := cryptoutils.UnmarshalCertificatesFromPEMLimited(trimmedRawPub, 10) if err != nil { return nil, err } diff --git a/pkg/pki/x509/x509_test.go b/pkg/pki/x509/x509_test.go index 459c514ef..ae580acd6 100644 --- a/pkg/pki/x509/x509_test.go +++ b/pkg/pki/x509/x509_test.go @@ -62,10 +62,11 @@ pPZrHZ1cFykidZoURKoYXfkohJ+U/USYy8Sd8b4DMd5xDRZCnlDM0h37 // Extracted from above with: // openssl ec -in ec_private.pem -pubout -const pub = `-----BEGIN PUBLIC KEY----- +const pubStr = `-----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEx+ikqUxXurlxZltajRBV2ju31j32 baT2ax2dXBcpInWaFESqGF35KISflP1EmMvEnfG+AzHecQ0WQp5QzNId+w== ------END PUBLIC KEY-----` +-----END PUBLIC KEY----- +` // Generated with: // openssl genpkey -algorithm ED25519 -out edprivate.pem @@ -79,6 +80,13 @@ const ed25519Pub = `-----BEGIN PUBLIC KEY----- MCowBQYDK2VwAyEAizWek2gKgMM+bad4rVJ5nc9NsbNOba0A0BNfzOgklRs= -----END PUBLIC KEY-----` +const pubWithTrailingNewLine = `-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEx+ikqUxXurlxZltajRBV2ju31j32 +baT2ax2dXBcpInWaFESqGF35KISflP1EmMvEnfG+AzHecQ0WQp5QzNId+w== +-----END PUBLIC KEY----- + +` + func signData(t *testing.T, b []byte, pkey string) []byte { priv, err := cryptoutils.UnmarshalPEMToPrivateKey([]byte(pkey), cryptoutils.SkipPassword) @@ -111,7 +119,7 @@ func TestSignature_Verify(t *testing.T) { { name: "ec", priv: priv, - pub: pub, + pub: pubStr, }, { name: "ed25519", @@ -167,7 +175,7 @@ func TestSignature_VerifyFail(t *testing.T) { { name: "ec", priv: priv, - pub: pub, + pub: pubStr, }, { name: "ed25519", @@ -303,4 +311,18 @@ func TestPublicKeyWithCertChain(t *testing.T) { if err == nil || !strings.Contains(err.Error(), "too many certificates specified in PEM block") { t.Fatalf("expected error with long certificate chain, got %v", err) } + + // Verify public key with extra trailing newline is parsed OK + key, err := NewPublicKey(strings.NewReader(pubWithTrailingNewLine)) + if err != nil { + t.Fatalf("unexpected error parsing public key with extra trailing newline: %v", err) + } + canonicalKeyBytes, err := key.CanonicalValue() + if err != nil { + t.Fatalf("unexpected error canonicalizing public key with extra trailing newline: %v", err) + } + + if !bytes.Equal([]byte(pubStr), canonicalKeyBytes) { + t.Fatalf("expected canonical value to match original without extra trailing new line") + } }