Skip to content

Commit

Permalink
[FAB-6843] Adding IdemixUser
Browse files Browse the repository at this point in the history
This change-set does the following:
- It introduces an Idemix implementation of the
User interface called IdemixUser.
- An IdemixUserStore class have been added
to load instances of IdemixUser.
- Support tests

Change-Id: I9b8c4f2aacb132e6cb0b74c0ea3ccbeb61ef63be
Signed-off-by: Angelo De Caro <adc@zurich.ibm.com>
Signed-off-by: Manu Drijvers (mdr@zurich.ibm.com)
  • Loading branch information
adecaro authored and Saad Karim committed Sep 4, 2018
1 parent 5721b15 commit 3a600c2
Show file tree
Hide file tree
Showing 15 changed files with 310 additions and 54 deletions.
1 change: 0 additions & 1 deletion src/main/java/org/hyperledger/fabric/sdk/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

import org.hyperledger.fabric.sdk.exception.InvalidArgumentException;
import org.hyperledger.fabric.sdk.helper.Utils;
import org.hyperledger.fabric.sdk.identity.SigningIdentity;

import static java.lang.String.format;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,77 @@

import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;

import org.apache.milagro.amcl.FP256BN.BIG;
import org.hyperledger.fabric.protos.idemix.Idemix.CredentialRevocationInformation;
import org.hyperledger.fabric.sdk.Enrollment;
import org.hyperledger.fabric.sdk.idemix.IdemixCredential;
import org.hyperledger.fabric.sdk.idemix.IdemixIssuerPublicKey;

public class IdemixEnrollment implements Enrollment {


protected final IdemixIssuerPublicKey ipk;
protected final PublicKey revocationPk;
protected final String mspId;
protected final BIG sk;
protected final IdemixCredential cred;
protected final CredentialRevocationInformation cri;
protected final String ou;
protected final boolean role;

private KeyPair key;
private String cert;

public IdemixEnrollment(KeyPair signingKeyPair, String signedPem) {
this.key = signingKeyPair;
this.cert = signedPem;
public IdemixEnrollment(IdemixIssuerPublicKey ipk, PublicKey revocationPk, String mspId, BIG sk, IdemixCredential cred, CredentialRevocationInformation cri, String ou, boolean role) {
this.ipk = ipk;
this.revocationPk = revocationPk;
this.mspId = mspId;
this.sk = sk;
this.cred = cred;
this.cri = cri;
this.ou = ou;
this.role = role;
}

public PrivateKey getKey() {
return key.getPrivate();
return null;
}

public String getCert() {
return cert;
return null;
}

public IdemixIssuerPublicKey getIpk() {
return this.ipk;
}

public PublicKey getRevocationPk() {
return this.revocationPk;
}

public String getMspId() {
return this.mspId;
}

public BIG getSk() {
return this.sk;
}

public IdemixCredential getCred() {
return this.cred;
}

public CredentialRevocationInformation getCri() {
return this.cri;
}

public String getOu() {
return this.ou;
}

public boolean getRole() {
return this.role;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public class IdemixIdentity implements Identity {
// MSP identifier
private final String mspId;

// Issuer public key hash
private final byte[] ipkHash;

// Idemix Pseudonym
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ public class IdemixSigningIdentity implements SigningIdentity {

private static final Log logger = LogFactory.getLog(IdemixSigningIdentity.class);

public IdemixSigningIdentity(IdemixEnrollment enrollment) throws CryptoException, InvalidArgumentException {
this(enrollment.ipk, enrollment.revocationPk, enrollment.mspId, enrollment.sk, enrollment.cred,
enrollment.cri, enrollment.ou, enrollment.role);
}

/**
* Create new Idemix Signing Identity with a fresh pseudonym
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.hyperledger.fabric.sdk.identity;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hyperledger.fabric.sdk.Enrollment;
import org.hyperledger.fabric.sdk.User;
import org.hyperledger.fabric.sdk.security.CryptoSuite;
Expand All @@ -12,11 +14,19 @@ private IdentityFactory() {
public static SigningIdentity getSigningIdentity(CryptoSuite cryptoSuite, User user) {
Enrollment enrollment = user.getEnrollment();

if (enrollment instanceof X509Enrollment) {
return new X509SigningIdentity(cryptoSuite, user);
try {
if (enrollment instanceof X509Enrollment) {
return new X509SigningIdentity(cryptoSuite, user);
}

if (enrollment instanceof IdemixEnrollment) {
return new IdemixSigningIdentity((IdemixEnrollment) enrollment);
}
} catch (Exception e) {
throw new IllegalStateException(e.getMessage(), e);
}

throw new IllegalStateException("Invalid enrollment. Expected X509Enrollment. " + enrollment);
throw new IllegalStateException("Invalid enrollment. Expected either X509Enrollment or IdemixEnrollment." + enrollment);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@

public class X509Enrollment implements Enrollment, Serializable {

private PrivateKey key;
private String cert;
private final PrivateKey key;
private final String cert;

public X509Enrollment(KeyPair signingKeyPair, String signedPem) {
key = signingKeyPair.getPrivate();
this.key = signingKeyPair.getPrivate();
this.cert = signedPem;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

public class X509Identity implements Identity {

protected User user;
protected final User user;

public X509Identity(User user) {
if (user == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

public class X509SigningIdentity extends X509Identity implements SigningIdentity {

private CryptoSuite cryptoSuite;
private final CryptoSuite cryptoSuite;

public X509SigningIdentity(CryptoSuite cryptoSuite, User user) {
super(user);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,9 +232,7 @@ public ByteString[] signByteStrings(User[] users, ByteString... bs) throws Crypt
}

public TransactionContext retryTransactionSameContext() {

return new TransactionContext(channel, user, cryptoPrimitives);

}

public Identities.SerializedIdentity getSerializedIdentity() {
Expand Down
87 changes: 87 additions & 0 deletions src/main/java/org/hyperledger/fabric/sdk/user/IdemixUser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package org.hyperledger.fabric.sdk.user;

import java.security.PublicKey;
import java.util.Set;

import org.apache.milagro.amcl.FP256BN.BIG;
import org.hyperledger.fabric.protos.idemix.Idemix;
import org.hyperledger.fabric.sdk.Enrollment;
import org.hyperledger.fabric.sdk.User;
import org.hyperledger.fabric.sdk.exception.CryptoException;
import org.hyperledger.fabric.sdk.exception.InvalidArgumentException;
import org.hyperledger.fabric.sdk.idemix.IdemixCredential;
import org.hyperledger.fabric.sdk.idemix.IdemixIssuerPublicKey;
import org.hyperledger.fabric.sdk.identity.IdemixEnrollment;
import org.hyperledger.fabric.sdk.identity.IdemixSigningIdentity;
import org.hyperledger.fabric.sdk.identity.SigningIdentity;

public class IdemixUser implements User {

protected final String name;
protected final String mspId;
protected final IdemixEnrollment enrollment;

public IdemixUser(String name, String mspId, IdemixEnrollment enrollment) {
this.name = name;
this.mspId = mspId;
this.enrollment = enrollment;
}

@Override
public String getName() {
return this.name;
}

@Override
public Set<String> getRoles() {
return null;
}

@Override
public String getAccount() {
return null;
}

@Override
public String getAffiliation() {
return null;
}

@Override
public Enrollment getEnrollment() {
return this.enrollment;
}

@Override
public String getMspId() {
return this.mspId;
}

public IdemixIssuerPublicKey getIpk() {
return this.enrollment.getIpk();
}

public IdemixCredential getIdemixCredential() {
return this.enrollment.getCred();
}

public Idemix.CredentialRevocationInformation getCri() {
return this.enrollment.getCri();
}

public BIG getSk() {
return this.enrollment.getSk();
}

public PublicKey getRevocationPk() {
return this.enrollment.getRevocationPk();
}

public String getOu() {
return this.enrollment.getOu();
}

public boolean getRole() {
return this.enrollment.getRole();
}
}
103 changes: 103 additions & 0 deletions src/main/java/org/hyperledger/fabric/sdk/user/IdemixUserStore.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package org.hyperledger.fabric.sdk.user;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;

import com.google.protobuf.InvalidProtocolBufferException;
import org.apache.milagro.amcl.FP256BN.BIG;
import org.hyperledger.fabric.protos.idemix.Idemix;
import org.hyperledger.fabric.protos.msp.MspConfig;
import org.hyperledger.fabric.sdk.User;
import org.hyperledger.fabric.sdk.exception.CryptoException;
import org.hyperledger.fabric.sdk.idemix.IdemixCredential;
import org.hyperledger.fabric.sdk.idemix.IdemixIssuerPublicKey;
import org.hyperledger.fabric.sdk.identity.IdemixEnrollment;

public class IdemixUserStore {

private static final String USER_PATH = "user";
private static final String VERIFIER_PATH = "msp";
private static final String IPK_CONFIG = "IssuerPublicKey";
private static final String REVOCATION_PUBLIC_KEY = "RevocationPublicKey";


protected final String storePath;
protected final String mspId;
protected final IdemixIssuerPublicKey ipk;

public IdemixUserStore(String storePath, String mspId) throws CryptoException {
this.storePath = storePath;
this.mspId = mspId;
Idemix.IssuerPublicKey ipkProto = readIdemixIssuerPublicKey(Paths.get(mspId, VERIFIER_PATH + IPK_CONFIG).toString());
this.ipk = new IdemixIssuerPublicKey(ipkProto);
if (!this.ipk.check()) {
throw new CryptoException("Failed verifying issuer public key.");
}
}

public User getUser(String id) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
MspConfig.IdemixMSPSignerConfig signerConfig = readIdemixMSPConfig(Paths.get(this.mspId, USER_PATH + id).toString());
PublicKey revocationPk = readIdemixRevocationPublicKey(this.mspId);
BIG sk = BIG.fromBytes(signerConfig.getSk().toByteArray());
IdemixCredential cred = new IdemixCredential(Idemix.Credential.parseFrom(signerConfig.getCred()));
Idemix.CredentialRevocationInformation cri = Idemix.CredentialRevocationInformation.parseFrom(signerConfig.getCredentialRevocationInformation());

IdemixEnrollment enrollment = new IdemixEnrollment(this.ipk, revocationPk, this.mspId, sk, cred, cri, signerConfig.getOrganizationalUnitIdentifier(), signerConfig.getIsAdmin());
return new IdemixUser(id, this.mspId, enrollment);
}

/**
* Helper function: parse Idemix MSP Signer config (is part of the MSPConfig proto) from path
*
* @param id
* @return IdemixMSPSignerConfig proto
*/
protected MspConfig.IdemixMSPSignerConfig readIdemixMSPConfig(String id) throws IOException {
Path path = Paths.get(this.storePath + id);
return MspConfig.IdemixMSPSignerConfig.parseFrom(Files.readAllBytes(path));
}

/**
* Parse Idemix issuer public key from the config file
*
* @param id
* @return Idemix IssuerPublicKey proto
*/
protected Idemix.IssuerPublicKey readIdemixIssuerPublicKey(String id) {
Path path = Paths.get(this.storePath + id);
byte[] data = null;
try {
data = Files.readAllBytes(path);
} catch (IOException e) {
e.printStackTrace();
}

Idemix.IssuerPublicKey ipk = null;

try {
ipk = Idemix.IssuerPublicKey.parseFrom(data);
} catch (InvalidProtocolBufferException e) {
e.printStackTrace();
}

return ipk;
}

/**
* Parse Idemix long-term revocation public key
*
* @param id
* @return idemix long-term revocation public key
*/
protected PublicKey readIdemixRevocationPublicKey(String id) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
Path path = Paths.get(this.mspId, VERIFIER_PATH + id);
return KeyFactory.getInstance("EC").generatePublic(new X509EncodedKeySpec(Files.readAllBytes(path)));
}
}
Loading

0 comments on commit 3a600c2

Please sign in to comment.