github.com/tw-bc-group/fabric-ca-gm@v0.0.0-20201218004200-3b690512bd5a/lib/server/idemix/revocationkey.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 "encoding/pem" 12 "github.com/Hyperledger-TWGC/tjfoc-gm/sm2" 13 x509GM "github.com/Hyperledger-TWGC/tjfoc-gm/x509" 14 "io/ioutil" 15 16 "github.com/cloudflare/cfssl/log" 17 "github.com/pkg/errors" 18 "github.com/tw-bc-group/fabric-ca-gm/util" 19 ) 20 21 // RevocationKey represents issuer revocation public and private key 22 type RevocationKey interface { 23 // Load loads this revocation key from the disk 24 Load() error 25 // Store stores this revocation key to the disk 26 Store() error 27 // GetKey returns *sm2.PrivateKey that represents revocation public and private key pair 28 GetKey() *sm2.PrivateKey 29 // SetKey sets revocation public and private key 30 SetKey(key *sm2.PrivateKey) 31 // SetNewKey creates new revocation public and private key pair and sets them in this object 32 SetNewKey() error 33 } 34 35 // caIdemixRevocationKey implements RevocationKey interface 36 type caIdemixRevocationKey struct { 37 pubKeyFile string 38 privateKeyFile string 39 key *sm2.PrivateKey 40 idemixLib Lib 41 } 42 43 // NewRevocationKey returns an instance of an object that implements RevocationKey interface 44 func NewRevocationKey(pubKeyFile, privateKeyFile string, lib Lib) RevocationKey { 45 return &caIdemixRevocationKey{ 46 pubKeyFile: pubKeyFile, 47 privateKeyFile: privateKeyFile, 48 idemixLib: lib, 49 } 50 } 51 52 // Load loads the Issuer revocation public and private key from the location specified 53 // by pubKeyFile and privateKeyFile attributes, respectively 54 func (rk *caIdemixRevocationKey) Load() error { 55 pubKeyBytes, err := ioutil.ReadFile(rk.pubKeyFile) 56 if err != nil { 57 return errors.Wrapf(err, "Failed to read revocation public key from %s", rk.pubKeyFile) 58 } 59 if len(pubKeyBytes) == 0 { 60 return errors.New("Revocation public key file is empty") 61 } 62 privKey, err := ioutil.ReadFile(rk.privateKeyFile) 63 if err != nil { 64 return errors.Wrapf(err, "Failed to read revocation private key from %s", rk.privateKeyFile) 65 } 66 if len(privKey) == 0 { 67 return errors.New("Revocation private key file is empty") 68 } 69 pk, pubKey, err := DecodeKeys(privKey, pubKeyBytes) 70 if err != nil { 71 return errors.WithMessage(err, "Failed to decode revocation key") 72 } 73 pk.PublicKey = *pubKey 74 rk.key = pk 75 return nil 76 } 77 78 // Store stores the CA's Idemix public and private key to the location 79 // specified by pubKeyFile and secretKeyFile attributes, respectively 80 func (rk *caIdemixRevocationKey) Store() error { 81 pk := rk.GetKey() 82 if pk == nil { 83 return errors.New("Revocation key is not set") 84 } 85 pkBytes, pubKeyBytes, err := EncodeKeys(pk, &pk.PublicKey) 86 if err != nil { 87 return errors.WithMessage(err, "Failed to encode revocation public key") 88 } 89 err = util.WriteFile(rk.privateKeyFile, []byte(pkBytes), 0644) 90 if err != nil { 91 log.Errorf("Failed to store revocation private key: %s", err.Error()) 92 return errors.Wrapf(err, "Failed to store revocation private key at %s", rk.privateKeyFile) 93 } 94 95 err = util.WriteFile(rk.pubKeyFile, []byte(pubKeyBytes), 0644) 96 if err != nil { 97 log.Errorf("Failed to store revocation public key: %s", err.Error()) 98 return errors.Wrapf(err, "Failed to store revocation public key at %s", rk.pubKeyFile) 99 } 100 101 log.Infof("The revocation key was successfully stored. The public key is at: %s, private key is at: %s", 102 rk.pubKeyFile, rk.privateKeyFile) 103 return nil 104 } 105 106 // GetKey returns revocation key 107 func (rk *caIdemixRevocationKey) GetKey() *sm2.PrivateKey { 108 return rk.key 109 } 110 111 // SetKey sets revocation key 112 func (rk *caIdemixRevocationKey) SetKey(key *sm2.PrivateKey) { 113 rk.key = key 114 } 115 116 // SetNewKey creates new revocation key and sets it in this object 117 func (rk *caIdemixRevocationKey) SetNewKey() (err error) { 118 rk.key, err = rk.idemixLib.GenerateLongTermRevocationKey() 119 return err 120 } 121 122 // EncodeKeys encodes ECDSA key pair to PEM encoding 123 func EncodeKeys(privateKey *sm2.PrivateKey, publicKey *sm2.PublicKey) ([]byte, []byte, error) { 124 encodedPK, err := x509GM.MarshalSm2UnecryptedPrivateKey(privateKey) 125 if err != nil { 126 return nil, nil, errors.Wrap(err, "Failed to encode ECDSA private key") 127 } 128 pemEncodedPK := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: encodedPK}) 129 130 encodedPubKey, err := x509GM.MarshalPKIXPublicKey(publicKey) 131 if err != nil { 132 return nil, nil, errors.Wrap(err, "Failed to encode ECDSA public key") 133 } 134 pemEncodedPubKey := pem.EncodeToMemory(&pem.Block{Type: "PUBLIC KEY", Bytes: encodedPubKey}) 135 return pemEncodedPK, pemEncodedPubKey, nil 136 } 137 138 // DecodeKeys decodes ECDSA key pair that are pem encoded 139 func DecodeKeys(pemEncodedPK, pemEncodedPubKey []byte) (*sm2.PrivateKey, *sm2.PublicKey, error) { 140 block, _ := pem.Decode(pemEncodedPK) 141 if block == nil { 142 return nil, nil, errors.New("Failed to decode ECDSA private key") 143 } 144 pk, err := x509GM.ParsePKCS8UnecryptedPrivateKey(block.Bytes) 145 if err != nil { 146 return nil, nil, errors.Wrap(err, "Failed to parse ECDSA private key bytes") 147 } 148 blockPub, _ := pem.Decode(pemEncodedPubKey) 149 if blockPub == nil { 150 return nil, nil, errors.New("Failed to decode ECDSA public key") 151 } 152 key, err := x509GM.ParsePKIXPublicKey(blockPub.Bytes) 153 if err != nil { 154 return nil, nil, errors.Wrap(err, "Failed to parse ECDSA public key bytes") 155 } 156 ecdsaPubKey := key.(*ecdsa.PublicKey) 157 publicKey := &sm2.PublicKey{ 158 X: ecdsaPubKey.X, 159 Y: ecdsaPubKey.Y, 160 Curve: ecdsaPubKey.Curve, 161 } 162 return pk, publicKey, nil 163 }