github.com/defanghe/fabric@v2.1.1+incompatible/internal/cryptogen/csp/csp.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  package csp
     7  
     8  import (
     9  	"crypto"
    10  	"crypto/ecdsa"
    11  	"crypto/elliptic"
    12  	"crypto/rand"
    13  	"crypto/x509"
    14  	"encoding/asn1"
    15  	"encoding/pem"
    16  	"io"
    17  	"io/ioutil"
    18  	"math/big"
    19  	"os"
    20  	"path/filepath"
    21  	"strings"
    22  
    23  	"github.com/pkg/errors"
    24  )
    25  
    26  // LoadPrivateKey loads a private key from a file in keystorePath.  It looks
    27  // for a file ending in "_sk" and expects a PEM-encoded PKCS8 EC private key.
    28  func LoadPrivateKey(keystorePath string) (*ecdsa.PrivateKey, error) {
    29  	var priv *ecdsa.PrivateKey
    30  
    31  	walkFunc := func(path string, info os.FileInfo, pathErr error) error {
    32  
    33  		if !strings.HasSuffix(path, "_sk") {
    34  			return nil
    35  		}
    36  
    37  		rawKey, err := ioutil.ReadFile(path)
    38  		if err != nil {
    39  			return err
    40  		}
    41  
    42  		priv, err = parsePrivateKeyPEM(rawKey)
    43  		if err != nil {
    44  			return errors.WithMessage(err, path)
    45  		}
    46  
    47  		return nil
    48  	}
    49  
    50  	err := filepath.Walk(keystorePath, walkFunc)
    51  	if err != nil {
    52  		return nil, err
    53  	}
    54  
    55  	return priv, err
    56  }
    57  
    58  func parsePrivateKeyPEM(rawKey []byte) (*ecdsa.PrivateKey, error) {
    59  	block, _ := pem.Decode(rawKey)
    60  	if block == nil {
    61  		return nil, errors.New("bytes are not PEM encoded")
    62  	}
    63  
    64  	key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
    65  	if err != nil {
    66  		return nil, errors.WithMessage(err, "pem bytes are not PKCS8 encoded ")
    67  	}
    68  
    69  	priv, ok := key.(*ecdsa.PrivateKey)
    70  	if !ok {
    71  		return nil, errors.New("pem bytes do not contain an EC private key")
    72  	}
    73  	return priv, nil
    74  }
    75  
    76  // GeneratePrivateKey creates an EC private key using a P-256 curve and stores
    77  // it in keystorePath.
    78  func GeneratePrivateKey(keystorePath string) (*ecdsa.PrivateKey, error) {
    79  
    80  	priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
    81  	if err != nil {
    82  		return nil, errors.WithMessage(err, "failed to generate private key")
    83  	}
    84  
    85  	pkcs8Encoded, err := x509.MarshalPKCS8PrivateKey(priv)
    86  	if err != nil {
    87  		return nil, errors.WithMessage(err, "failed to marshal private key")
    88  	}
    89  
    90  	pemEncoded := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: pkcs8Encoded})
    91  
    92  	keyFile := filepath.Join(keystorePath, "priv_sk")
    93  	err = ioutil.WriteFile(keyFile, pemEncoded, 0600)
    94  	if err != nil {
    95  		return nil, errors.WithMessagef(err, "failed to save private key to file %s", keyFile)
    96  	}
    97  
    98  	return priv, err
    99  }
   100  
   101  /**
   102  ECDSA signer implements the crypto.Signer interface for ECDSA keys.  The
   103  Sign method ensures signatures are created with Low S values since Fabric
   104  normalizes all signatures to Low S.
   105  See https://github.com/bitcoin/bips/blob/master/bip-0146.mediawiki#low_s
   106  for more detail.
   107  */
   108  type ECDSASigner struct {
   109  	PrivateKey *ecdsa.PrivateKey
   110  }
   111  
   112  // Public returns the ecdsa.PublicKey associated with PrivateKey.
   113  func (e *ECDSASigner) Public() crypto.PublicKey {
   114  	return &e.PrivateKey.PublicKey
   115  }
   116  
   117  // Sign signs the digest and ensures that signatures use the Low S value.
   118  func (e *ECDSASigner) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
   119  	r, s, err := ecdsa.Sign(rand, e.PrivateKey, digest)
   120  	if err != nil {
   121  		return nil, err
   122  	}
   123  
   124  	// ensure Low S signatures
   125  	sig := toLowS(
   126  		e.PrivateKey.PublicKey,
   127  		ECDSASignature{
   128  			R: r,
   129  			S: s,
   130  		},
   131  	)
   132  
   133  	// return marshaled aignature
   134  	return asn1.Marshal(sig)
   135  }
   136  
   137  /**
   138  When using ECDSA, both (r,s) and (r, -s mod n) are valid signatures.  In order
   139  to protect against signature malleability attacks, Fabric normalizes all
   140  signatures to a canonical form where s is at most half the order of the curve.
   141  In order to make signatures compliant with what Fabric expects, toLowS creates
   142  signatures in this canonical form.
   143  */
   144  func toLowS(key ecdsa.PublicKey, sig ECDSASignature) ECDSASignature {
   145  	// calculate half order of the curve
   146  	halfOrder := new(big.Int).Div(key.Curve.Params().N, big.NewInt(2))
   147  	// check if s is greater than half order of curve
   148  	if sig.S.Cmp(halfOrder) == 1 {
   149  		// Set s to N - s so that s will be less than or equal to half order
   150  		sig.S.Sub(key.Params().N, sig.S)
   151  	}
   152  	return sig
   153  }
   154  
   155  type ECDSASignature struct {
   156  	R, S *big.Int
   157  }