github.com/hellobchain/third_party@v0.0.0-20230331131523-deb0478a2e52/hyperledger/fabric-config/configtx/signer.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package configtx
     8  
     9  import (
    10  	"crypto"
    11  	"crypto/rand"
    12  	"encoding/asn1"
    13  	"encoding/pem"
    14  	"fmt"
    15  	"github.com/hellobchain/newcryptosm"
    16  	"github.com/hellobchain/newcryptosm/ecdsa"
    17  	"github.com/hellobchain/newcryptosm/x509"
    18  	"io"
    19  	"math/big"
    20  
    21  	"github.com/golang/protobuf/proto"
    22  	cb "github.com/hyperledger/fabric-protos-go/common"
    23  	mb "github.com/hyperledger/fabric-protos-go/msp"
    24  )
    25  
    26  // SigningIdentity is an MSP Identity that can be used to sign configuration
    27  // updates.
    28  type SigningIdentity struct {
    29  	Certificate *x509.Certificate
    30  	PrivateKey  crypto.PrivateKey
    31  	MSPID       string
    32  }
    33  
    34  type ecdsaSignature struct {
    35  	R, S *big.Int
    36  }
    37  
    38  // Public returns the public key associated with this signing
    39  // identity's certificate.
    40  func (s *SigningIdentity) Public() crypto.PublicKey {
    41  	return s.Certificate.PublicKey
    42  }
    43  
    44  // Sign performs ECDSA sign with this signing identity's private key on the
    45  // given message hashed using SHA-256. It ensures signatures are created with
    46  // Low S values since Fabric normalizes all signatures to Low S.
    47  // See https://github.com/bitcoin/bips/blob/master/bip-0146.mediawiki#low_s
    48  // for more detail.
    49  func (s *SigningIdentity) Sign(reader io.Reader, msg []byte, opts crypto.SignerOpts) (signature []byte, err error) {
    50  	switch pk := s.PrivateKey.(type) {
    51  	case *ecdsa.PrivateKey:
    52  		hasher := newcryptosm.SHA256.New()
    53  		if ecdsa.IsSM2(pk.Params()) {
    54  			hasher = newcryptosm.SM3.New()
    55  		}
    56  		hasher.Write(msg)
    57  		digest := hasher.Sum(nil)
    58  
    59  		rr, ss, err := ecdsa.Sign(reader, pk, digest)
    60  		if err != nil {
    61  			return nil, err
    62  		}
    63  
    64  		// ensure Low S signatures
    65  		sig := toLowS(
    66  			pk.PublicKey,
    67  			ecdsaSignature{
    68  				R: rr,
    69  				S: ss,
    70  			},
    71  		)
    72  
    73  		return asn1.Marshal(sig)
    74  	default:
    75  		return nil, fmt.Errorf("signing with private key of type %T not supported", pk)
    76  	}
    77  }
    78  
    79  // toLows normalizes all signatures to a canonical form where s is at most
    80  // half the order of the curve. By doing so, it compliant with what Fabric
    81  // expected as well as protect against signature malleability attacks.
    82  func toLowS(key ecdsa.PublicKey, sig ecdsaSignature) ecdsaSignature {
    83  	if ecdsa.IsSM2(key.Params()) {
    84  		return sig
    85  	}
    86  
    87  	// calculate half order of the curve
    88  	halfOrder := new(big.Int).Div(key.Curve.Params().N, big.NewInt(2))
    89  	// check if s is greater than half order of curve
    90  	if sig.S.Cmp(halfOrder) == 1 {
    91  		// Set s to N - s so that s will be less than or equal to half order
    92  		sig.S.Sub(key.Params().N, sig.S)
    93  	}
    94  
    95  	return sig
    96  }
    97  
    98  // CreateConfigSignature creates a config signature for the the given configuration
    99  // update using the specified signing identity.
   100  func (s *SigningIdentity) CreateConfigSignature(marshaledUpdate []byte) (*cb.ConfigSignature, error) {
   101  	signatureHeader, err := s.signatureHeader()
   102  	if err != nil {
   103  		return nil, fmt.Errorf("creating signature header: %v", err)
   104  	}
   105  
   106  	header, err := proto.Marshal(signatureHeader)
   107  	if err != nil {
   108  		return nil, fmt.Errorf("marshaling signature header: %v", err)
   109  	}
   110  
   111  	configSignature := &cb.ConfigSignature{
   112  		SignatureHeader: header,
   113  	}
   114  
   115  	configSignature.Signature, err = s.Sign(
   116  		rand.Reader,
   117  		concatenateBytes(configSignature.SignatureHeader, marshaledUpdate),
   118  		nil,
   119  	)
   120  	if err != nil {
   121  		return nil, fmt.Errorf("signing config update: %v", err)
   122  	}
   123  
   124  	return configSignature, nil
   125  }
   126  
   127  // SignEnvelope signs an envelope using the SigningIdentity.
   128  func (s *SigningIdentity) SignEnvelope(e *cb.Envelope) error {
   129  	signatureHeader, err := s.signatureHeader()
   130  	if err != nil {
   131  		return fmt.Errorf("creating signature header: %v", err)
   132  	}
   133  
   134  	sHeader, err := proto.Marshal(signatureHeader)
   135  	if err != nil {
   136  		return fmt.Errorf("marshaling signature header: %v", err)
   137  	}
   138  
   139  	payload := &cb.Payload{}
   140  	err = proto.Unmarshal(e.Payload, payload)
   141  	if err != nil {
   142  		return fmt.Errorf("unmarshaling envelope payload: %v", err)
   143  	}
   144  	payload.Header.SignatureHeader = sHeader
   145  
   146  	payloadBytes, err := proto.Marshal(payload)
   147  	if err != nil {
   148  		return fmt.Errorf("marshaling payload: %v", err)
   149  	}
   150  
   151  	sig, err := s.Sign(rand.Reader, payloadBytes, nil)
   152  	if err != nil {
   153  		return fmt.Errorf("signing envelope payload: %v", err)
   154  	}
   155  
   156  	e.Payload = payloadBytes
   157  	e.Signature = sig
   158  
   159  	return nil
   160  }
   161  
   162  func (s *SigningIdentity) signatureHeader() (*cb.SignatureHeader, error) {
   163  	pemBytes := pem.EncodeToMemory(&pem.Block{
   164  		Type:  "CERTIFICATE",
   165  		Bytes: s.Certificate.Raw,
   166  	})
   167  
   168  	idBytes, err := proto.Marshal(&mb.SerializedIdentity{
   169  		Mspid:   s.MSPID,
   170  		IdBytes: pemBytes,
   171  	})
   172  	if err != nil {
   173  		return nil, fmt.Errorf("marshaling serialized identity: %v", err)
   174  	}
   175  
   176  	nonce, err := newNonce()
   177  	if err != nil {
   178  		return nil, err
   179  	}
   180  
   181  	return &cb.SignatureHeader{
   182  		Creator: idBytes,
   183  		Nonce:   nonce,
   184  	}, nil
   185  }
   186  
   187  // newNonce generates a 24-byte nonce using the crypto/rand package.
   188  func newNonce() ([]byte, error) {
   189  	nonce := make([]byte, 24)
   190  
   191  	_, err := rand.Read(nonce)
   192  	if err != nil {
   193  		return nil, fmt.Errorf("failed to get random bytes: %v", err)
   194  	}
   195  
   196  	return nonce, nil
   197  }