Skip to content
This repository has been archived by the owner on Sep 6, 2022. It is now read-only.

Commit

Permalink
feat: harden encoding/decoding functions against panics
Browse files Browse the repository at this point in the history
Part of libp2p/go-libp2p#1389

These kinds of functions:

1. Handle user input.
2. Often have out-of-bounds, null pointer, etc bugs.
3. Have completely isolated logic where local panics are unlikely to
   cause memory corruption elsewhere.
  • Loading branch information
Stebalien committed Apr 14, 2022
1 parent 2a28e1d commit 5b6861e
Show file tree
Hide file tree
Showing 9 changed files with 187 additions and 29 deletions.
54 changes: 47 additions & 7 deletions crypto/ecdsa.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"crypto/x509"
"encoding/asn1"
"errors"
"fmt"
"io"
"math/big"

Expand Down Expand Up @@ -73,17 +74,33 @@ func ECDSAPublicKeyFromPubKey(pub ecdsa.PublicKey) (PubKey, error) {
}

// MarshalECDSAPrivateKey returns x509 bytes from a private key
func MarshalECDSAPrivateKey(ePriv ECDSAPrivateKey) ([]byte, error) {
func MarshalECDSAPrivateKey(ePriv ECDSAPrivateKey) (res []byte, err error) {
defer func() {
if rerr := recover(); rerr != nil {
err = fmt.Errorf("panic in ECDSA private-key marshal: %s", rerr)
}
}()
return x509.MarshalECPrivateKey(ePriv.priv)
}

// MarshalECDSAPublicKey returns x509 bytes from a public key
func MarshalECDSAPublicKey(ePub ECDSAPublicKey) ([]byte, error) {
func MarshalECDSAPublicKey(ePub ECDSAPublicKey) (res []byte, err error) {
defer func() {
if rerr := recover(); rerr != nil {
err = fmt.Errorf("panic in ECDSA public-key marshal: %s", rerr)
}
}()
return x509.MarshalPKIXPublicKey(ePub.pub)
}

// UnmarshalECDSAPrivateKey returns a private key from x509 bytes
func UnmarshalECDSAPrivateKey(data []byte) (PrivKey, error) {
func UnmarshalECDSAPrivateKey(data []byte) (res PrivKey, err error) {
defer func() {
if rerr := recover(); rerr != nil {
err = fmt.Errorf("panic in ECDSA private-key unmarshal: %s", rerr)
}
}()

priv, err := x509.ParseECPrivateKey(data)
if err != nil {
return nil, err
Expand All @@ -93,7 +110,13 @@ func UnmarshalECDSAPrivateKey(data []byte) (PrivKey, error) {
}

// UnmarshalECDSAPublicKey returns the public key from x509 bytes
func UnmarshalECDSAPublicKey(data []byte) (PubKey, error) {
func UnmarshalECDSAPublicKey(data []byte) (key PubKey, err error) {
defer func() {
if rerr := recover(); rerr != nil {
err = fmt.Errorf("panic in ECDSA public-key unmarshal: %s", rerr)
}
}()

pubIfc, err := x509.ParsePKIXPublicKey(data)
if err != nil {
return nil, err
Expand All @@ -113,7 +136,12 @@ func (ePriv *ECDSAPrivateKey) Type() pb.KeyType {
}

// Raw returns x509 bytes from a private key
func (ePriv *ECDSAPrivateKey) Raw() ([]byte, error) {
func (ePriv *ECDSAPrivateKey) Raw() (res []byte, err error) {
defer func() {
if rerr := recover(); rerr != nil {
err = fmt.Errorf("panic in ECDSA private-key marshal: %s", rerr)
}
}()
return x509.MarshalECPrivateKey(ePriv.priv)
}

Expand All @@ -123,7 +151,12 @@ func (ePriv *ECDSAPrivateKey) Equals(o Key) bool {
}

// Sign returns the signature of the input data
func (ePriv *ECDSAPrivateKey) Sign(data []byte) ([]byte, error) {
func (ePriv *ECDSAPrivateKey) Sign(data []byte) (sig []byte, err error) {
defer func() {
if rerr := recover(); rerr != nil {
err = fmt.Errorf("panic in ECDSA signing: %s", rerr)
}
}()
hash := sha256.Sum256(data)
r, s, err := ecdsa.Sign(rand.Reader, ePriv.priv, hash[:])
if err != nil {
Expand Down Expand Up @@ -157,7 +190,14 @@ func (ePub *ECDSAPublicKey) Equals(o Key) bool {
}

// Verify compares data to a signature
func (ePub *ECDSAPublicKey) Verify(data, sigBytes []byte) (bool, error) {
func (ePub *ECDSAPublicKey) Verify(data, sigBytes []byte) (success bool, err error) {
defer func() {
if rerr := recover(); rerr != nil {
err = fmt.Errorf("panic in ECDSA signature verification: %s", rerr)
success = false
}
}()

sig := new(ECDSASig)
if _, err := asn1.Unmarshal(sigBytes, sig); err != nil {
return false, err
Expand Down
15 changes: 13 additions & 2 deletions crypto/ed25519.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,12 @@ func (k *Ed25519PrivateKey) GetPublic() PubKey {
}

// Sign returns a signature from an input message.
func (k *Ed25519PrivateKey) Sign(msg []byte) ([]byte, error) {
func (k *Ed25519PrivateKey) Sign(msg []byte) (res []byte, err error) {
defer func() {
if rerr := recover(); rerr != nil {
err = fmt.Errorf("panic in ed25519 signing: %s", rerr)
}
}()
return ed25519.Sign(k.k, msg), nil
}

Expand All @@ -99,7 +104,13 @@ func (k *Ed25519PublicKey) Equals(o Key) bool {
}

// Verify checks a signature agains the input data.
func (k *Ed25519PublicKey) Verify(data []byte, sig []byte) (bool, error) {
func (k *Ed25519PublicKey) Verify(data []byte, sig []byte) (success bool, err error) {
defer func() {
if rerr := recover(); rerr != nil {
err = fmt.Errorf("panic in ed25519 signature verification: %s", rerr)
success = false
}
}()
return ed25519.Verify(k.k, data, sig), nil
}

Expand Down
17 changes: 16 additions & 1 deletion crypto/key_openssl.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,18 @@ import (
)

// KeyPairFromStdKey wraps standard library (and secp256k1) private keys in libp2p/go-libp2p-core/crypto keys
func KeyPairFromStdKey(priv crypto.PrivateKey) (PrivKey, PubKey, error) {
func KeyPairFromStdKey(priv crypto.PrivateKey) (priv PrivKey, pub PubKey, err error) {
if priv == nil {
return nil, nil, ErrNilPrivateKey
}

switch p := priv.(type) {
case *rsa.PrivateKey:
defer func() {
if rerr := recover(); rerr != nil {
err = fmt.Errorf("panic in x509 private key marshaling: %s", rerr)
}
}()
pk, err := openssl.LoadPrivateKeyFromDER(x509.MarshalPKCS1PrivateKey(p))
if err != nil {
return nil, nil, err
Expand Down Expand Up @@ -54,6 +59,11 @@ func PrivKeyToStdKey(priv PrivKey) (crypto.PrivateKey, error) {
}
switch p := priv.(type) {
case *opensslPrivateKey:
defer func() {
if rerr := recover(); rerr != nil {
err = fmt.Errorf("panic in x509 private key parsing: %s", rerr)
}
}()
raw, err := p.Raw()
if err != nil {
return nil, err
Expand All @@ -78,6 +88,11 @@ func PubKeyToStdKey(pub PubKey) (crypto.PublicKey, error) {

switch p := pub.(type) {
case *opensslPublicKey:
defer func() {
if rerr := recover(); rerr != nil {
err = fmt.Errorf("panic in x509 public key parsing: %s", rerr)
}
}()
raw, err := p.Raw()
if err != nil {
return nil, err
Expand Down
46 changes: 39 additions & 7 deletions crypto/rsa_go.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"crypto/rsa"
"crypto/x509"
"errors"
"fmt"
"io"

pb "github.com/libp2p/go-libp2p-core/crypto/pb"
Expand Down Expand Up @@ -42,9 +43,15 @@ func GenerateRSAKeyPair(bits int, src io.Reader) (PrivKey, PubKey, error) {
}

// Verify compares a signature against input data
func (pk *RsaPublicKey) Verify(data, sig []byte) (bool, error) {
func (pk *RsaPublicKey) Verify(data, sig []byte) (success bool, err error) {
defer func() {
if rerr := recover(); rerr != nil {
err = fmt.Errorf("panic in RSA signature verification: %s", rerr)
success = false
}
}()
hashed := sha256.Sum256(data)
err := rsa.VerifyPKCS1v15(&pk.k, crypto.SHA256, hashed[:], sig)
err = rsa.VerifyPKCS1v15(&pk.k, crypto.SHA256, hashed[:], sig)
if err != nil {
return false, err
}
Expand All @@ -55,7 +62,12 @@ func (pk *RsaPublicKey) Type() pb.KeyType {
return pb.KeyType_RSA
}

func (pk *RsaPublicKey) Raw() ([]byte, error) {
func (pk *RsaPublicKey) Raw() (res []byte, err error) {
defer func() {
if rerr := recover(); rerr != nil {
err = fmt.Errorf("panic in RSA public key marshaling: %s", rerr)
}
}()
return x509.MarshalPKIXPublicKey(&pk.k)
}

Expand All @@ -71,7 +83,12 @@ func (pk *RsaPublicKey) Equals(k Key) bool {
}

// Sign returns a signature of the input data
func (sk *RsaPrivateKey) Sign(message []byte) ([]byte, error) {
func (sk *RsaPrivateKey) Sign(message []byte) (sig []byte, err error) {
defer func() {
if rerr := recover(); rerr != nil {
err = fmt.Errorf("panic in RSA signing: %s", rerr)
}
}()
hashed := sha256.Sum256(message)
return rsa.SignPKCS1v15(rand.Reader, &sk.sk, crypto.SHA256, hashed[:])
}
Expand All @@ -85,7 +102,12 @@ func (sk *RsaPrivateKey) Type() pb.KeyType {
return pb.KeyType_RSA
}

func (sk *RsaPrivateKey) Raw() ([]byte, error) {
func (sk *RsaPrivateKey) Raw() (res []byte, err error) {
defer func() {
if rerr := recover(); rerr != nil {
err = fmt.Errorf("panic in RSA private key marshaling: %s", rerr)
}
}()
b := x509.MarshalPKCS1PrivateKey(&sk.sk)
return b, nil
}
Expand All @@ -106,7 +128,12 @@ func (sk *RsaPrivateKey) Equals(k Key) bool {
}

// UnmarshalRsaPrivateKey returns a private key from the input x509 bytes
func UnmarshalRsaPrivateKey(b []byte) (PrivKey, error) {
func UnmarshalRsaPrivateKey(b []byte) (key PrivKey, err error) {
defer func() {
if rerr := recover(); rerr != nil {
err = fmt.Errorf("panic in RSA private key unmarshaling: %s", rerr)
}
}()
sk, err := x509.ParsePKCS1PrivateKey(b)
if err != nil {
return nil, err
Expand All @@ -118,7 +145,12 @@ func UnmarshalRsaPrivateKey(b []byte) (PrivKey, error) {
}

// UnmarshalRsaPublicKey returns a public key from the input x509 bytes
func UnmarshalRsaPublicKey(b []byte) (PubKey, error) {
func UnmarshalRsaPublicKey(b []byte) (key PubKey, err error) {
defer func() {
if rerr := recover(); rerr != nil {
err = fmt.Errorf("panic in RSA public key unmarshaling: %s", rerr)
}
}()
pub, err := x509.ParsePKIXPublicKey(b)
if err != nil {
return nil, err
Expand Down
36 changes: 31 additions & 5 deletions crypto/secp256k1.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,27 @@ func GenerateSecp256k1Key(src io.Reader) (PrivKey, PubKey, error) {
}

// UnmarshalSecp256k1PrivateKey returns a private key from bytes
func UnmarshalSecp256k1PrivateKey(data []byte) (PrivKey, error) {
func UnmarshalSecp256k1PrivateKey(data []byte) (k PrivKey, err error) {
if len(data) != btcec.PrivKeyBytesLen {
return nil, fmt.Errorf("expected secp256k1 data size to be %d", btcec.PrivKeyBytesLen)
}
defer func() {
if rerr := recover(); rerr != nil {
err = fmt.Errorf("panic in secp256k1 private key unmarshal: %s", rerr)
}
}()

privk, _ := btcec.PrivKeyFromBytes(btcec.S256(), data)
return (*Secp256k1PrivateKey)(privk), nil
}

// UnmarshalSecp256k1PublicKey returns a public key from bytes
func UnmarshalSecp256k1PublicKey(data []byte) (PubKey, error) {
func UnmarshalSecp256k1PublicKey(data []byte) (_k PubKey, err error) {
defer func() {
if rerr := recover(); rerr != nil {
err = fmt.Errorf("panic in secp256k1 public key unmarshal: %s", rerr)
}
}()
k, err := btcec.ParsePubKey(data, btcec.S256())
if err != nil {
return nil, err
Expand Down Expand Up @@ -68,7 +78,12 @@ func (k *Secp256k1PrivateKey) Equals(o Key) bool {
}

// Sign returns a signature from input data
func (k *Secp256k1PrivateKey) Sign(data []byte) ([]byte, error) {
func (k *Secp256k1PrivateKey) Sign(data []byte) (_sig []byte, err error) {
defer func() {
if rerr := recover(); rerr != nil {
err = fmt.Errorf("panic in secp256k1 signing: %s", rerr)
}
}()
hash := sha256.Sum256(data)
sig, err := (*btcec.PrivateKey)(k).Sign(hash[:])
if err != nil {
Expand All @@ -89,7 +104,12 @@ func (k *Secp256k1PublicKey) Type() pb.KeyType {
}

// Raw returns the bytes of the key
func (k *Secp256k1PublicKey) Raw() ([]byte, error) {
func (k *Secp256k1PublicKey) Raw() (res []byte, err error) {
defer func() {
if rerr := recover(); rerr != nil {
err = fmt.Errorf("panic in secp256k1 public key marshaling: %s", rerr)
}
}()
return (*btcec.PublicKey)(k).SerializeCompressed(), nil
}

Expand All @@ -104,7 +124,13 @@ func (k *Secp256k1PublicKey) Equals(o Key) bool {
}

// Verify compares a signature against the input data
func (k *Secp256k1PublicKey) Verify(data []byte, sigStr []byte) (bool, error) {
func (k *Secp256k1PublicKey) Verify(data []byte, sigStr []byte) (success bool, err error) {
defer func() {
if rerr := recover(); rerr != nil {
err = fmt.Errorf("panic in secp256k1 signature verification: %s", rerr)
success = false
}
}()
sig, err := btcec.ParseDERSignature(sigStr, btcec.S256())
if err != nil {
return false, err
Expand Down
15 changes: 13 additions & 2 deletions peer/addrinfo_serde.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package peer

import (
"encoding/json"
"fmt"

ma "github.com/multiformats/go-multiaddr"
)
Expand All @@ -12,7 +13,12 @@ type addrInfoJson struct {
Addrs []string
}

func (pi AddrInfo) MarshalJSON() ([]byte, error) {
func (pi AddrInfo) MarshalJSON() (res []byte, err error) {
defer func() {
if rerr := recover(); rerr != nil {
err = fmt.Errorf("panic when marshaling addr info: %w", err)
}
}()
addrs := make([]string, len(pi.Addrs))
for i, addr := range pi.Addrs {
addrs[i] = addr.String()
Expand All @@ -23,7 +29,12 @@ func (pi AddrInfo) MarshalJSON() ([]byte, error) {
})
}

func (pi *AddrInfo) UnmarshalJSON(b []byte) error {
func (pi *AddrInfo) UnmarshalJSON(b []byte) (err error) {
defer func() {
if rerr := recover(); rerr != nil {
err = fmt.Errorf("panic when unmarshaling addr info: %w", err)
}
}()
var data addrInfoJson
if err := json.Unmarshal(b, &data); err != nil {
return err
Expand Down
Loading

0 comments on commit 5b6861e

Please sign in to comment.