Skip to content

Commit 52027bd

Browse files
committed
p2p: store private keys as PKCS#8 ASN.1 DER PEM
1 parent 81edd96 commit 52027bd

File tree

1 file changed

+42
-3
lines changed

1 file changed

+42
-3
lines changed

network/p2p/peerID.go

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@
1919
package p2p
2020

2121
import (
22+
"crypto/ed25519"
2223
"crypto/rand"
24+
"crypto/x509"
25+
"encoding/pem"
2326
"fmt"
2427
"os"
2528
"path"
@@ -34,7 +37,7 @@ import (
3437

3538
// DefaultPrivKeyPath is the default path inside the node's root directory at which the private key
3639
// for p2p identity is found and persisted to when a new one is generated.
37-
const DefaultPrivKeyPath = "peerIDPrivKey.pem"
40+
const DefaultPrivKeyPath = "peerIDPrivKey.key"
3841

3942
// PeerID is a string representation of a peer's public key, primarily used to avoid importing libp2p into packages that shouldn't need it
4043
type PeerID string
@@ -84,15 +87,31 @@ func PeerIDFromPublicKey(pubKey crypto.PubKey) (PeerID, error) {
8487
return PeerID(peerID), nil
8588
}
8689

90+
// pemBlockType is the type of PEM block used for private keys
91+
const pemBlockType = "PRIVATE KEY"
92+
8793
// loadPrivateKeyFromFile attempts to read raw privKey bytes from path
8894
// It only supports Ed25519 keys.
8995
func loadPrivateKeyFromFile(path string) (crypto.PrivKey, error) {
9096
bytes, err := os.ReadFile(path)
9197
if err != nil {
9298
return nil, err
9399
}
100+
p, _ := pem.Decode(bytes)
101+
if p == nil || p.Type != pemBlockType {
102+
return nil, fmt.Errorf("failed to PEM decode private key at %s", path)
103+
}
104+
105+
ak, err := x509.ParsePKCS8PrivateKey(p.Bytes)
106+
if err != nil {
107+
return nil, err
108+
}
109+
sk, ok := ak.(ed25519.PrivateKey)
110+
if !ok {
111+
return nil, fmt.Errorf("unsupported private key type: %T, expecting ed25519", ak)
112+
}
94113
// We only support Ed25519 keys
95-
return crypto.UnmarshalEd25519PrivateKey(bytes)
114+
return crypto.UnmarshalEd25519PrivateKey(sk)
96115
}
97116

98117
// writePrivateKeyToFile attempts to write raw privKey bytes to path
@@ -101,7 +120,27 @@ func writePrivateKeyToFile(path string, privKey crypto.PrivKey) error {
101120
if err != nil {
102121
return err
103122
}
104-
return os.WriteFile(path, bytes, 0600)
123+
if len(bytes) != ed25519.PrivateKeySize {
124+
return fmt.Errorf("incompatible ed25519 private key length: %d", len(bytes))
125+
}
126+
key := ed25519.PrivateKey(bytes)
127+
derBytes, err := x509.MarshalPKCS8PrivateKey(key)
128+
if err != nil {
129+
return err
130+
}
131+
132+
p := pem.Block{
133+
Type: pemBlockType,
134+
Bytes: derBytes,
135+
}
136+
137+
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
138+
if err != nil {
139+
return err
140+
}
141+
defer f.Close()
142+
143+
return pem.Encode(f, &p)
105144
}
106145

107146
// generatePrivKey creates a new Ed25519 key

0 commit comments

Comments
 (0)