github.com/anjalikarhana/fabric@v2.1.1+incompatible/idemix/revocation_authority.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package idemix 8 9 import ( 10 "crypto/ecdsa" 11 "crypto/elliptic" 12 "crypto/rand" 13 "crypto/sha256" 14 "encoding/asn1" 15 "math/big" 16 17 "github.com/golang/protobuf/proto" 18 "github.com/hyperledger/fabric-amcl/amcl" 19 "github.com/hyperledger/fabric-amcl/amcl/FP256BN" 20 "github.com/pkg/errors" 21 ) 22 23 type RevocationAlgorithm int32 24 25 const ( 26 ALG_NO_REVOCATION RevocationAlgorithm = iota 27 ) 28 29 var ProofBytes = map[RevocationAlgorithm]int{ 30 ALG_NO_REVOCATION: 0, 31 } 32 33 // GenerateLongTermRevocationKey generates a long term signing key that will be used for revocation 34 func GenerateLongTermRevocationKey() (*ecdsa.PrivateKey, error) { 35 return ecdsa.GenerateKey(elliptic.P384(), rand.Reader) 36 } 37 38 // CreateCRI creates the Credential Revocation Information for a certain time period (epoch). 39 // Users can use the CRI to prove that they are not revoked. 40 // Note that when not using revocation (i.e., alg = ALG_NO_REVOCATION), the entered unrevokedHandles are not used, 41 // and the resulting CRI can be used by any signer. 42 func CreateCRI(key *ecdsa.PrivateKey, unrevokedHandles []*FP256BN.BIG, epoch int, alg RevocationAlgorithm, rng *amcl.RAND) (*CredentialRevocationInformation, error) { 43 if key == nil || rng == nil { 44 return nil, errors.Errorf("CreateCRI received nil input") 45 } 46 cri := &CredentialRevocationInformation{} 47 cri.RevocationAlg = int32(alg) 48 cri.Epoch = int64(epoch) 49 50 if alg == ALG_NO_REVOCATION { 51 // put a dummy PK in the proto 52 cri.EpochPk = Ecp2ToProto(GenG2) 53 } else { 54 // create epoch key 55 _, epochPk := WBBKeyGen(rng) 56 cri.EpochPk = Ecp2ToProto(epochPk) 57 } 58 59 // sign epoch + epoch key with long term key 60 bytesToSign, err := proto.Marshal(cri) 61 if err != nil { 62 return nil, errors.Wrap(err, "failed to marshal CRI") 63 } 64 65 digest := sha256.Sum256(bytesToSign) 66 67 cri.EpochPkSig, err = key.Sign(rand.Reader, digest[:], nil) 68 if err != nil { 69 return nil, err 70 } 71 72 if alg == ALG_NO_REVOCATION { 73 return cri, nil 74 } else { 75 return nil, errors.Errorf("the specified revocation algorithm is not supported.") 76 } 77 } 78 79 // VerifyEpochPK verifies that the revocation PK for a certain epoch is valid, 80 // by checking that it was signed with the long term revocation key. 81 // Note that even if we use no revocation (i.e., alg = ALG_NO_REVOCATION), we need 82 // to verify the signature to make sure the issuer indeed signed that no revocation 83 // is used in this epoch. 84 func VerifyEpochPK(pk *ecdsa.PublicKey, epochPK *ECP2, epochPkSig []byte, epoch int, alg RevocationAlgorithm) error { 85 if pk == nil || epochPK == nil { 86 return errors.Errorf("EpochPK invalid: received nil input") 87 } 88 cri := &CredentialRevocationInformation{} 89 cri.RevocationAlg = int32(alg) 90 cri.EpochPk = epochPK 91 cri.Epoch = int64(epoch) 92 bytesToSign, err := proto.Marshal(cri) 93 if err != nil { 94 return err 95 } 96 digest := sha256.Sum256(bytesToSign) 97 98 var sig struct{ R, S *big.Int } 99 if _, err := asn1.Unmarshal(epochPkSig, &sig); err != nil { 100 return errors.Wrap(err, "failed unmashalling signature") 101 } 102 103 if !ecdsa.Verify(pk, digest[:], sig.R, sig.S) { 104 return errors.Errorf("EpochPKSig invalid") 105 } 106 107 return nil 108 }