github.com/yacovm/fabric@v2.0.0-alpha.0.20191128145320-c5d4087dc723+incompatible/msp/identities.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package msp
     8  
     9  import (
    10  	"crypto"
    11  	"crypto/rand"
    12  	"crypto/x509"
    13  	"encoding/hex"
    14  	"encoding/pem"
    15  	"sync"
    16  	"time"
    17  
    18  	"github.com/golang/protobuf/proto"
    19  	"github.com/hyperledger/fabric-protos-go/msp"
    20  	"github.com/hyperledger/fabric/bccsp"
    21  	"github.com/hyperledger/fabric/common/flogging"
    22  	"github.com/pkg/errors"
    23  	"go.uber.org/zap/zapcore"
    24  )
    25  
    26  var mspIdentityLogger = flogging.MustGetLogger("msp.identity")
    27  
    28  type identity struct {
    29  	// id contains the identifier (MSPID and identity identifier) for this instance
    30  	id *IdentityIdentifier
    31  
    32  	// cert contains the x.509 certificate that signs the public key of this instance
    33  	cert *x509.Certificate
    34  
    35  	// this is the public key of this instance
    36  	pk bccsp.Key
    37  
    38  	// reference to the MSP that "owns" this identity
    39  	msp *bccspmsp
    40  
    41  	// validationMutex is used to synchronise memory operation
    42  	// over validated and validationErr
    43  	validationMutex sync.Mutex
    44  
    45  	// validated is true when the validateIdentity function
    46  	// has been called on this instance
    47  	validated bool
    48  
    49  	// validationErr contains the validation error for this
    50  	// instance. It can be read if validated is true
    51  	validationErr error
    52  }
    53  
    54  func newIdentity(cert *x509.Certificate, pk bccsp.Key, msp *bccspmsp) (Identity, error) {
    55  	if mspIdentityLogger.IsEnabledFor(zapcore.DebugLevel) {
    56  		mspIdentityLogger.Debugf("Creating identity instance for cert %s", certToPEM(cert))
    57  	}
    58  
    59  	// Sanitize first the certificate
    60  	cert, err := msp.sanitizeCert(cert)
    61  	if err != nil {
    62  		return nil, err
    63  	}
    64  
    65  	// Compute identity identifier
    66  
    67  	// Use the hash of the identity's certificate as id in the IdentityIdentifier
    68  	hashOpt, err := bccsp.GetHashOpt(msp.cryptoConfig.IdentityIdentifierHashFunction)
    69  	if err != nil {
    70  		return nil, errors.WithMessage(err, "failed getting hash function options")
    71  	}
    72  
    73  	digest, err := msp.bccsp.Hash(cert.Raw, hashOpt)
    74  	if err != nil {
    75  		return nil, errors.WithMessage(err, "failed hashing raw certificate to compute the id of the IdentityIdentifier")
    76  	}
    77  
    78  	id := &IdentityIdentifier{
    79  		Mspid: msp.name,
    80  		Id:    hex.EncodeToString(digest)}
    81  
    82  	return &identity{id: id, cert: cert, pk: pk, msp: msp}, nil
    83  }
    84  
    85  // ExpiresAt returns the time at which the Identity expires.
    86  func (id *identity) ExpiresAt() time.Time {
    87  	return id.cert.NotAfter
    88  }
    89  
    90  // SatisfiesPrincipal returns nil if this instance matches the supplied principal or an error otherwise
    91  func (id *identity) SatisfiesPrincipal(principal *msp.MSPPrincipal) error {
    92  	return id.msp.SatisfiesPrincipal(id, principal)
    93  }
    94  
    95  // GetIdentifier returns the identifier (MSPID/IDID) for this instance
    96  func (id *identity) GetIdentifier() *IdentityIdentifier {
    97  	return id.id
    98  }
    99  
   100  // GetMSPIdentifier returns the MSP identifier for this instance
   101  func (id *identity) GetMSPIdentifier() string {
   102  	return id.id.Mspid
   103  }
   104  
   105  // Validate returns nil if this instance is a valid identity or an error otherwise
   106  func (id *identity) Validate() error {
   107  	return id.msp.Validate(id)
   108  }
   109  
   110  // GetOrganizationalUnits returns the OU for this instance
   111  func (id *identity) GetOrganizationalUnits() []*OUIdentifier {
   112  	if id.cert == nil {
   113  		return nil
   114  	}
   115  
   116  	cid, err := id.msp.getCertificationChainIdentifier(id)
   117  	if err != nil {
   118  		mspIdentityLogger.Errorf("Failed getting certification chain identifier for [%v]: [%+v]", id, err)
   119  
   120  		return nil
   121  	}
   122  
   123  	res := []*OUIdentifier{}
   124  	for _, unit := range id.cert.Subject.OrganizationalUnit {
   125  		res = append(res, &OUIdentifier{
   126  			OrganizationalUnitIdentifier: unit,
   127  			CertifiersIdentifier:         cid,
   128  		})
   129  	}
   130  
   131  	return res
   132  }
   133  
   134  // Anonymous returns true if this identity provides anonymity
   135  func (id *identity) Anonymous() bool {
   136  	return false
   137  }
   138  
   139  // NewSerializedIdentity returns a serialized identity
   140  // having as content the passed mspID and x509 certificate in PEM format.
   141  // This method does not check the validity of certificate nor
   142  // any consistency of the mspID with it.
   143  func NewSerializedIdentity(mspID string, certPEM []byte) ([]byte, error) {
   144  	// We serialize identities by prepending the MSPID
   145  	// and appending the x509 cert in PEM format
   146  	sId := &msp.SerializedIdentity{Mspid: mspID, IdBytes: certPEM}
   147  	raw, err := proto.Marshal(sId)
   148  	if err != nil {
   149  		return nil, errors.Wrapf(err, "failed serializing identity [%s][%X]", mspID, certPEM)
   150  	}
   151  	return raw, nil
   152  }
   153  
   154  // Verify checks against a signature and a message
   155  // to determine whether this identity produced the
   156  // signature; it returns nil if so or an error otherwise
   157  func (id *identity) Verify(msg []byte, sig []byte) error {
   158  	// mspIdentityLogger.Infof("Verifying signature")
   159  
   160  	// Compute Hash
   161  	hashOpt, err := id.getHashOpt(id.msp.cryptoConfig.SignatureHashFamily)
   162  	if err != nil {
   163  		return errors.WithMessage(err, "failed getting hash function options")
   164  	}
   165  
   166  	digest, err := id.msp.bccsp.Hash(msg, hashOpt)
   167  	if err != nil {
   168  		return errors.WithMessage(err, "failed computing digest")
   169  	}
   170  
   171  	if mspIdentityLogger.IsEnabledFor(zapcore.DebugLevel) {
   172  		mspIdentityLogger.Debugf("Verify: digest = %s", hex.Dump(digest))
   173  		mspIdentityLogger.Debugf("Verify: sig = %s", hex.Dump(sig))
   174  	}
   175  
   176  	valid, err := id.msp.bccsp.Verify(id.pk, sig, digest, nil)
   177  	if err != nil {
   178  		return errors.WithMessage(err, "could not determine the validity of the signature")
   179  	} else if !valid {
   180  		return errors.New("The signature is invalid")
   181  	}
   182  
   183  	return nil
   184  }
   185  
   186  // Serialize returns a byte array representation of this identity
   187  func (id *identity) Serialize() ([]byte, error) {
   188  	// mspIdentityLogger.Infof("Serializing identity %s", id.id)
   189  
   190  	pb := &pem.Block{Bytes: id.cert.Raw, Type: "CERTIFICATE"}
   191  	pemBytes := pem.EncodeToMemory(pb)
   192  	if pemBytes == nil {
   193  		return nil, errors.New("encoding of identity failed")
   194  	}
   195  
   196  	// We serialize identities by prepending the MSPID and appending the ASN.1 DER content of the cert
   197  	sId := &msp.SerializedIdentity{Mspid: id.id.Mspid, IdBytes: pemBytes}
   198  	idBytes, err := proto.Marshal(sId)
   199  	if err != nil {
   200  		return nil, errors.Wrapf(err, "could not marshal a SerializedIdentity structure for identity %s", id.id)
   201  	}
   202  
   203  	return idBytes, nil
   204  }
   205  
   206  func (id *identity) getHashOpt(hashFamily string) (bccsp.HashOpts, error) {
   207  	switch hashFamily {
   208  	case bccsp.SHA2:
   209  		return bccsp.GetHashOpt(bccsp.SHA256)
   210  	case bccsp.SHA3:
   211  		return bccsp.GetHashOpt(bccsp.SHA3_256)
   212  	}
   213  	return nil, errors.Errorf("hash familiy not recognized [%s]", hashFamily)
   214  }
   215  
   216  type signingidentity struct {
   217  	// we embed everything from a base identity
   218  	identity
   219  
   220  	// signer corresponds to the object that can produce signatures from this identity
   221  	signer crypto.Signer
   222  }
   223  
   224  func newSigningIdentity(cert *x509.Certificate, pk bccsp.Key, signer crypto.Signer, msp *bccspmsp) (SigningIdentity, error) {
   225  	//mspIdentityLogger.Infof("Creating signing identity instance for ID %s", id)
   226  	mspId, err := newIdentity(cert, pk, msp)
   227  	if err != nil {
   228  		return nil, err
   229  	}
   230  	return &signingidentity{
   231  		identity: identity{
   232  			id:   mspId.(*identity).id,
   233  			cert: mspId.(*identity).cert,
   234  			msp:  mspId.(*identity).msp,
   235  			pk:   mspId.(*identity).pk,
   236  		},
   237  		signer: signer,
   238  	}, nil
   239  }
   240  
   241  // Sign produces a signature over msg, signed by this instance
   242  func (id *signingidentity) Sign(msg []byte) ([]byte, error) {
   243  	//mspIdentityLogger.Infof("Signing message")
   244  
   245  	// Compute Hash
   246  	hashOpt, err := id.getHashOpt(id.msp.cryptoConfig.SignatureHashFamily)
   247  	if err != nil {
   248  		return nil, errors.WithMessage(err, "failed getting hash function options")
   249  	}
   250  
   251  	digest, err := id.msp.bccsp.Hash(msg, hashOpt)
   252  	if err != nil {
   253  		return nil, errors.WithMessage(err, "failed computing digest")
   254  	}
   255  
   256  	if len(msg) < 32 {
   257  		mspIdentityLogger.Debugf("Sign: plaintext: %X \n", msg)
   258  	} else {
   259  		mspIdentityLogger.Debugf("Sign: plaintext: %X...%X \n", msg[0:16], msg[len(msg)-16:])
   260  	}
   261  	mspIdentityLogger.Debugf("Sign: digest: %X \n", digest)
   262  
   263  	// Sign
   264  	return id.signer.Sign(rand.Reader, digest, nil)
   265  }
   266  
   267  // GetPublicVersion returns the public version of this identity,
   268  // namely, the one that is only able to verify messages and not sign them
   269  func (id *signingidentity) GetPublicVersion() Identity {
   270  	return &id.identity
   271  }