Skip to content
Open
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
10 changes: 9 additions & 1 deletion lib/ocrypto/ec_key_pair.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,15 @@ func ECPrivateKeyFromPem(privateECKeyInPem []byte) (*ecdh.PrivateKey, error) {
}

priv, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
switch {
case err == nil:
case strings.Contains(err.Error(), "use ParseECPrivateKey instead"):
// Check if it's in SEC1 / RFC 5915 encoding using the same pattern as `asym_decryption.go`: `FromPrivatePEMWithSalt`
priv, err = x509.ParseECPrivateKey(block.Bytes)
if err != nil {
return nil, fmt.Errorf("ec x509.ParseECPrivateKey failed: %w", err)
}
default:
return nil, fmt.Errorf("ec x509.ParsePKCS8PrivateKey failed: %w", err)
}

Expand Down
55 changes: 55 additions & 0 deletions lib/ocrypto/ec_key_pair_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
package ocrypto

import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/pem"
"testing"

"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -68,6 +74,55 @@ func TestECKeyPair(t *testing.T) {
}
}

func TestECPrivateKeyFromPem(t *testing.T) {
curves := []struct {
name string
curve elliptic.Curve
}{
{"P-256", elliptic.P256()},
{"P-384", elliptic.P384()},
{"P-521", elliptic.P521()},
}

for _, tc := range curves {
ecdsaKey, err := ecdsa.GenerateKey(tc.curve, rand.Reader)
require.NoError(t, err, "fail on ecdsa.GenerateKey for %s", tc.name)

// PKCS8 encoding ("BEGIN PRIVATE KEY"), e.g. `openssl genpkey`
pkcs8Bytes, err := x509.MarshalPKCS8PrivateKey(ecdsaKey)
require.NoError(t, err, "fail on x509.MarshalPKCS8PrivateKey for %s", tc.name)
pkcs8Pem := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: pkcs8Bytes})

// SEC1 / RFC 5915 encoding ("BEGIN EC PRIVATE KEY"), e.g. `openssl ecparam -genkey`
sec1Bytes, err := x509.MarshalECPrivateKey(ecdsaKey)
require.NoError(t, err, "fail on x509.MarshalECPrivateKey for %s", tc.name)
sec1Pem := pem.EncodeToMemory(&pem.Block{Type: "EC PRIVATE KEY", Bytes: sec1Bytes})

fromPKCS8, err := ECPrivateKeyFromPem(pkcs8Pem)
require.NoError(t, err, "fail on ECPrivateKeyFromPem with PKCS8 encoding for %s", tc.name)

fromSEC1, err := ECPrivateKeyFromPem(sec1Pem)
require.NoError(t, err, "fail on ECPrivateKeyFromPem with SEC1 encoding for %s", tc.name)

// Both encodings of the same key must yield the same ECDH key
require.True(t, fromPKCS8.Equal(fromSEC1),
"PKCS8 and SEC1 decodings of the same %s key differ", tc.name)
}

// Not PEM at all
_, err := ECPrivateKeyFromPem([]byte("not a pem"))
require.Error(t, err, "non-PEM input must be rejected")

// Valid PKCS8, but not an EC key
rsaKey, err := rsa.GenerateKey(rand.Reader, 2048)
require.NoError(t, err, "fail on rsa.GenerateKey")
rsaBytes, err := x509.MarshalPKCS8PrivateKey(rsaKey)
require.NoError(t, err, "fail on x509.MarshalPKCS8PrivateKey for RSA")
rsaPem := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: rsaBytes})
_, err = ECPrivateKeyFromPem(rsaPem)
require.Error(t, err, "non-EC PKCS8 key must be rejected")
}

func TestECRewrapKeyGenerate(t *testing.T) {
kasECKeyPair, err := NewECKeyPair(ECCModeSecp256r1)
require.NoError(t, err, "fail on NewECKeyPair")
Expand Down
Loading