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