github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/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/osdi23p228/fabric/bccsp" 22 "github.com/osdi23p228/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 pb := &pem.Block{Bytes: id.cert.Raw, Type: "CERTIFICATE"} 201 pemBytes := pem.EncodeToMemory(pb) 202 if pemBytes == nil { 203 return nil, errors.New("encoding of identity failed") 204 } 205 206 // We serialize identities by prepending the MSPID and appending the ASN.1 DER content of the cert 207 sId := &msp.SerializedIdentity{Mspid: id.id.Mspid, IdBytes: pemBytes} 208 idBytes, err := proto.Marshal(sId) 209 if err != nil { 210 return nil, errors.Wrapf(err, "could not marshal a SerializedIdentity structure for identity %s", id.id) 211 } 212 213 return idBytes, nil 214 } 215 216 func (id *identity) getHashOpt(hashFamily string) (bccsp.HashOpts, error) { 217 switch hashFamily { 218 case bccsp.SHA2: 219 return bccsp.GetHashOpt(bccsp.SHA256) 220 case bccsp.SHA3: 221 return bccsp.GetHashOpt(bccsp.SHA3_256) 222 } 223 return nil, errors.Errorf("hash familiy not recognized [%s]", hashFamily) 224 } 225 226 type signingidentity struct { 227 // we embed everything from a base identity 228 identity 229 230 // signer corresponds to the object that can produce signatures from this identity 231 signer crypto.Signer 232 } 233 234 func newSigningIdentity(cert *x509.Certificate, pk bccsp.Key, signer crypto.Signer, msp *bccspmsp) (SigningIdentity, error) { 235 //mspIdentityLogger.Infof("Creating signing identity instance for ID %s", id) 236 mspId, err := newIdentity(cert, pk, msp) 237 if err != nil { 238 return nil, err 239 } 240 return &signingidentity{ 241 identity: identity{ 242 id: mspId.(*identity).id, 243 cert: mspId.(*identity).cert, 244 msp: mspId.(*identity).msp, 245 pk: mspId.(*identity).pk, 246 }, 247 signer: signer, 248 }, nil 249 } 250 251 // Sign produces a signature over msg, signed by this instance 252 func (id *signingidentity) Sign(msg []byte) ([]byte, error) { 253 //mspIdentityLogger.Infof("Signing message") 254 255 // Compute Hash 256 hashOpt, err := id.getHashOpt(id.msp.cryptoConfig.SignatureHashFamily) 257 if err != nil { 258 return nil, errors.WithMessage(err, "failed getting hash function options") 259 } 260 261 digest, err := id.msp.bccsp.Hash(msg, hashOpt) 262 if err != nil { 263 return nil, errors.WithMessage(err, "failed computing digest") 264 } 265 266 if len(msg) < 32 { 267 mspIdentityLogger.Debugf("Sign: plaintext: %X \n", msg) 268 } else { 269 mspIdentityLogger.Debugf("Sign: plaintext: %X...%X \n", msg[0:16], msg[len(msg)-16:]) 270 } 271 mspIdentityLogger.Debugf("Sign: digest: %X \n", digest) 272 273 // Sign 274 return id.signer.Sign(rand.Reader, digest, nil) 275 } 276 277 // GetPublicVersion returns the public version of this identity, 278 // namely, the one that is only able to verify messages and not sign them 279 func (id *signingidentity) GetPublicVersion() Identity { 280 return &id.identity 281 }