Commit 440a00ba authored by Gari Singh's avatar Gari Singh Committed by Gerrit Code Review
Browse files

Merge "[FAB-8921] include idemix revocation data in conf"

parents 15df8233 4ad504a0
......@@ -7,6 +7,8 @@ SPDX-License-Identifier: Apache-2.0
package idemixca
import (
"crypto/ecdsa"
"github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric-amcl/amcl/FP256BN"
"github.com/hyperledger/fabric/idemix"
......@@ -37,15 +39,10 @@ func GenerateIssuerKey() ([]byte, []byte, error) {
return key.ISk, ipkSerialized, err
}
// GenerateMSPConfig creates a new MSP config.
// If the new MSP config contains a signer then
// it generates a fresh user secret and issues a credential
// with four attributes (described above)
// using the CA's key pair from the file.
// If the new MSP config does not contain a signer
// (meaning it is used only for verification)
// then only a public key of the CA (issuer) is added to the MSP config (besides the name).
func GenerateSignerConfig(isAdmin bool, ouString string, enrollmentId string, revocationHandle int, key *idemix.IssuerKey) ([]byte, error) {
// GenerateSignerConfig creates a new signer config.
// It generates a fresh user secret and issues a credential
// with four attributes (described above) using the CA's key pair.
func GenerateSignerConfig(isAdmin bool, ouString string, enrollmentId string, revocationHandle int, key *idemix.IssuerKey, revKey *ecdsa.PrivateKey) ([]byte, error) {
attrs := make([]*FP256BN.BIG, 4)
if ouString == "" {
......@@ -84,12 +81,24 @@ func GenerateSignerConfig(isAdmin bool, ouString string, enrollmentId string, re
return nil, errors.WithMessage(err, "failed to marshal credential")
}
// NOTE currently, idemixca creates CRI's with "ALG_NO_REVOCATION"
cri, err := idemix.CreateCRI(revKey, []*FP256BN.BIG{FP256BN.NewBIGint(revocationHandle)}, 0, idemix.ALG_NO_REVOCATION, rng)
if err != nil {
return nil, err
}
criBytes, err := proto.Marshal(cri)
if err != nil {
return nil, errors.WithMessage(err, "failed to marshal CRI")
}
signer := &m.IdemixMSPSignerConfig{
credBytes,
idemix.BigToBytes(sk),
ouString,
isAdmin,
enrollmentId,
criBytes,
}
return proto.Marshal(signer)
}
......@@ -12,6 +12,8 @@ import (
"path/filepath"
"testing"
"crypto/elliptic"
"github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric/idemix"
m "github.com/hyperledger/fabric/msp"
......@@ -28,21 +30,24 @@ func TestIdemixCa(t *testing.T) {
isk, ipkBytes, err := GenerateIssuerKey()
assert.NoError(t, err)
revocationkey, err := idemix.GenerateLongTermRevocationKey()
assert.NoError(t, err)
ipk := &idemix.IssuerPublicKey{}
err = proto.Unmarshal(ipkBytes, ipk)
assert.NoError(t, err)
writeVerifierToFile(ipkBytes)
writeVerifierToFile(ipkBytes, elliptic.Marshal(elliptic.P384(), revocationkey.X, revocationkey.Y))
key := &idemix.IssuerKey{isk, ipk}
conf, err := GenerateSignerConfig(false, "OU1", "enrollmentid1", 1, key)
conf, err := GenerateSignerConfig(false, "OU1", "enrollmentid1", 1, key, revocationkey)
assert.NoError(t, err)
cleanupSigner()
assert.NoError(t, writeSignerToFile(conf))
assert.NoError(t, setupMSP())
conf, err = GenerateSignerConfig(true, "OU1", "enrollmentid2", 1234, key)
conf, err = GenerateSignerConfig(true, "OU1", "enrollmentid2", 1234, key, revocationkey)
assert.NoError(t, err)
cleanupSigner()
assert.NoError(t, writeSignerToFile(conf))
......@@ -52,10 +57,10 @@ func TestIdemixCa(t *testing.T) {
cleanupVerifier()
assert.Error(t, setupMSP())
_, err = GenerateSignerConfig(true, "", "enrollmentid", 1, key)
_, err = GenerateSignerConfig(true, "", "enrollmentid", 1, key, revocationkey)
assert.EqualError(t, err, "the OU attribute value is empty")
_, err = GenerateSignerConfig(true, "OU1", "", 1, key)
_, err = GenerateSignerConfig(true, "OU1", "", 1, key, revocationkey)
assert.EqualError(t, err, "the enrollment id value is empty")
}
......@@ -76,12 +81,17 @@ func cleanupVerifier() {
os.RemoveAll(filepath.Join(testDir, m.IdemixConfigDirMsp))
}
func writeVerifierToFile(ipkBytes []byte) error {
func writeVerifierToFile(ipkBytes []byte, revpkBytes []byte) error {
err := os.Mkdir(filepath.Join(testDir, m.IdemixConfigDirMsp), os.ModePerm)
if err != nil {
return err
}
return ioutil.WriteFile(filepath.Join(testDir, m.IdemixConfigDirMsp, m.IdemixConfigFileIssuerPublicKey), ipkBytes, 0644)
err = ioutil.WriteFile(filepath.Join(testDir, m.IdemixConfigDirMsp, m.IdemixConfigFileIssuerPublicKey), ipkBytes, 0644)
if err != nil {
return err
}
return ioutil.WriteFile(filepath.Join(testDir, m.IdemixConfigDirMsp, m.IdemixConfigFileRevocationPublicKey), revpkBytes, 0644)
}
func writeSignerToFile(signerBytes []byte) error {
......@@ -102,5 +112,9 @@ func setupMSP() error {
}
mspConfig, err := m.GetIdemixMspConfig(testDir, "TestName")
if err != nil {
return err
}
return msp.Setup(mspConfig)
}
......@@ -12,11 +12,16 @@ package main
// the Identity Mixer MSP
import (
"crypto/x509"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"crypto/elliptic"
"crypto/ecdsa"
"github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric/common/tools/idemixgen/idemixca"
"github.com/hyperledger/fabric/idemix"
......@@ -29,6 +34,7 @@ import (
const (
IdemixDirIssuer = "ca"
IdemixConfigIssuerSecretKey = "IssuerSecretKey"
IdemixConfigRevocationKey = "RevocationKey"
)
// command line flags
......@@ -54,6 +60,12 @@ func main() {
isk, ipk, err := idemixca.GenerateIssuerKey()
handleError(err)
revocationKey, err := idemix.GenerateLongTermRevocationKey()
handleError(err)
revocationKeyBytes, err := x509.MarshalECPrivateKey(revocationKey)
handleError(err)
revocationPkBytes := elliptic.Marshal(elliptic.P384(), revocationKey.X, revocationKey.Y)
// Prevent overwriting the existing key
path := filepath.Join(IdemixDirIssuer)
checkDirectoryNotExists(path, fmt.Sprintf("Directory %s already exists", path))
......@@ -65,11 +77,13 @@ func main() {
handleError(os.Mkdir(IdemixDirIssuer, 0770))
handleError(os.Mkdir(msp.IdemixConfigDirMsp, 0770))
writeFile(filepath.Join(IdemixDirIssuer, IdemixConfigIssuerSecretKey), isk)
writeFile(filepath.Join(IdemixDirIssuer, IdemixConfigRevocationKey), revocationKeyBytes)
writeFile(filepath.Join(IdemixDirIssuer, msp.IdemixConfigFileIssuerPublicKey), ipk)
writeFile(filepath.Join(msp.IdemixConfigDirMsp, msp.IdemixConfigFileRevocationPublicKey), revocationPkBytes)
writeFile(filepath.Join(msp.IdemixConfigDirMsp, msp.IdemixConfigFileIssuerPublicKey), ipk)
case genSignerConfig.FullCommand():
config, err := idemixca.GenerateSignerConfig(*genCredIsAdmin, *genCredOU, *genCredEnrollmentId, *genCredRevocationHandle, readIssuerKey())
config, err := idemixca.GenerateSignerConfig(*genCredIsAdmin, *genCredOU, *genCredEnrollmentId, *genCredRevocationHandle, readIssuerKey(), readRevocationKey())
handleError(err)
path := msp.IdemixConfigDirUser
......@@ -112,6 +126,18 @@ func readIssuerKey() *idemix.IssuerKey {
return key
}
func readRevocationKey() *ecdsa.PrivateKey {
path := filepath.Join(IdemixDirIssuer, IdemixConfigRevocationKey)
keyBytes, err := ioutil.ReadFile(path)
if err != nil {
handleError(errors.Wrapf(err, "failed to open revocation secret key file: %s", path))
}
key, err := x509.ParseECPrivateKey(keyBytes)
handleError(err)
return key
}
// checkDirectoryNotExists checks whether a directory with the given path already exists and exits if this is the case
func checkDirectoryNotExists(path string, errorMessage string) {
_, err := os.Stat(path)
......
......@@ -39,6 +39,8 @@ func GenerateLongTermRevocationKey() (*ecdsa.PrivateKey, error) {
// CreateCRI creates the Credential Revocation Information for a certain time period (epoch).
// Users can use the CRI to prove that they are not revoked.
// Note that when not using revocation (i.e., alg = ALG_NO_REVOCATION), the entered unrevokedHandles are not used,
// and the resulting CRI can be used by any signer.
func CreateCRI(key *ecdsa.PrivateKey, unrevokedHandles []*FP256BN.BIG, epoch int, alg RevocationAlgorithm, rng *amcl.RAND) (*CredentialRevocationInformation, error) {
if key == nil || rng == nil {
return nil, errors.Errorf("CreateCRI received nil input")
......
......@@ -358,10 +358,11 @@ func getMspConfig(dir string, ID string, sigid *msp.SigningIdentityInfo) (*msp.M
}
const (
IdemixConfigDirMsp = "msp"
IdemixConfigDirUser = "user"
IdemixConfigFileIssuerPublicKey = "IssuerPublicKey"
IdemixConfigFileSigner = "SignerConfig"
IdemixConfigDirMsp = "msp"
IdemixConfigDirUser = "user"
IdemixConfigFileIssuerPublicKey = "IssuerPublicKey"
IdemixConfigFileRevocationPublicKey = "RevocationPublicKey"
IdemixConfigFileSigner = "SignerConfig"
)
// GetIdemixMspConfig returns the configuration for the Idemix MSP
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment