Skip to content

Commit

Permalink
FAB-8077 Create client TLS from Fabric CA
Browse files Browse the repository at this point in the history
Change-Id: I68d811a517fb64c46cdb01f7f621277bb0d7627c
Signed-off-by: rickr <cr22rc@gmail.com>
  • Loading branch information
cr22rc committed Feb 9, 2018
1 parent 5c57df4 commit 09776f0
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 13 deletions.
15 changes: 10 additions & 5 deletions src/main/java/org/hyperledger/fabric/sdk/Endpoint.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,17 @@
import io.grpc.netty.NettyChannelBuilder;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslProvider;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bouncycastle.asn1.x500.RDN;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.asn1.x500.style.IETFUtils;
import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;

import org.hyperledger.fabric.sdk.exception.CryptoException;
import org.hyperledger.fabric.sdk.security.CryptoPrimitives;

import static org.hyperledger.fabric.sdk.helper.Utils.parseGrpcUrl;

class Endpoint {
Expand Down Expand Up @@ -146,12 +144,19 @@ class Endpoint {
throw new RuntimeException("Properties \"clientKeyBytes\" and \"clientCertBytes\" must both be set or both be null");
}
}

if ((ckb != null) && (ccb != null)) {
String what = "private key";
try {
logger.trace("client TLS private key bytes size:" + ckb.length);
clientKey = cp.bytesToPrivateKey(ckb);
logger.trace("converted TLS key.");
what = "certificate";
logger.trace("client TLS certificate bytes:" + Hex.encodeHexString(ccb));
clientCert = new X509Certificate[] {(X509Certificate) cp.bytesToCertificate(ccb)};
logger.trace("converted client TLS certificate.");
} catch (CryptoException e) {
throw new RuntimeException("Failed to parse TLS client key and/or certificate", e);
throw new RuntimeException("Failed to parse TLS client " + what, e);
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/test/java/org/hyperledger/fabric/sdk/EndpointTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ public void testNullPropertyClientCertBytes() {
@Test
public void testBadClientKeyFile() {
thrown.expect(RuntimeException.class);
thrown.expectMessage("Failed to parse TLS client key and/or cert");
thrown.expectMessage("Failed to parse TLS client private key");

Properties testprops = new Properties();
testprops.setProperty("trustServerCertificate", "true");
Expand All @@ -211,7 +211,7 @@ public void testBadClientKeyFile() {
@Test
public void testBadClientCertFile() {
thrown.expect(RuntimeException.class);
thrown.expectMessage("Failed to parse TLS client key and/or cert");
thrown.expectMessage("Failed to parse TLS client certificate");

Properties testprops = new Properties();
testprops.setProperty("trustServerCertificate", "true");
Expand Down Expand Up @@ -258,7 +258,7 @@ public void testClientTLSInvalidProperties() {
try {
new Endpoint("grpcs://localhost:594", testprops);
} catch (RuntimeException e) {
Assert.assertEquals("Failed to parse TLS client key and/or certificate", e.getMessage());
Assert.assertEquals("Failed to parse TLS client private key", e.getMessage());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ public class TestConfig {
private static final Properties sdkProperties = new Properties();
private final boolean runningTLS;
private final boolean runningFabricCATLS;

public boolean isRunningFabricTLS() {
return runningFabricTLS;
}

private final boolean runningFabricTLS;
private static final HashMap<String, SampleOrg> sampleOrgs = new HashMap<>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -582,18 +582,33 @@ private Channel reconstructChannel(String name, HFClient client, SampleOrg sampl
} else {
// foo channel do manual reconstruction.

Properties clientTLSProperties = new Properties();

final String clientPEMTLSCertificate = sampleStore.getClientPEMTLSCertificate(sampleOrg);
if (clientPEMTLSCertificate != null) {
clientTLSProperties.put("clientCertBytes", clientPEMTLSCertificate.getBytes(UTF_8));
}
final String clientPEMTLSKey = sampleStore.getClientPEMTLSKey(sampleOrg);

if (clientPEMTLSKey != null) {
clientTLSProperties.put("clientKeyBytes", clientPEMTLSKey.getBytes(UTF_8));
}

newChannel = client.newChannel(name);

for (String ordererName : sampleOrg.getOrdererNames()) {
Properties ordererProperties = (Properties) clientTLSProperties.clone();
ordererProperties.putAll(testConfig.getOrdererProperties(ordererName));
newChannel.addOrderer(client.newOrderer(ordererName, sampleOrg.getOrdererLocation(ordererName),
testConfig.getOrdererProperties(ordererName)));
ordererProperties));
}

boolean everyOther = false;

for (String peerName : sampleOrg.getPeerNames()) {
String peerLocation = sampleOrg.getPeerLocation(peerName);
Properties peerProperties = testConfig.getPeerProperties(peerName);
peerProperties.putAll(clientTLSProperties);
Peer peer = client.newPeer(peerName, peerLocation, peerProperties);
final PeerOptions peerEventingOptions = // we have two peers on one use block on other use filtered
everyOther ?
Expand All @@ -613,8 +628,10 @@ private Channel reconstructChannel(String name, HFClient client, SampleOrg sampl
//Should have two peers with all roles but event source.
assertEquals(2, newChannel.getPeers(PeerRole.NO_EVENT_SOURCE).size());
for (String eventHubName : sampleOrg.getEventHubNames()) {
Properties eventhubProperties = (Properties) clientTLSProperties.clone();
eventhubProperties.putAll(testConfig.getEventHubProperties(eventHubName));
EventHub eventHub = client.newEventHub(eventHubName, sampleOrg.getEventHubLocation(eventHubName),
testConfig.getEventHubProperties(eventHubName));
eventhubProperties);
newChannel.addEventHub(eventHub);
}
} else {
Expand Down Expand Up @@ -710,13 +727,12 @@ private Channel reconstructChannel(String name, HFClient client, SampleOrg sampl
return newChannel;
}


/**
*
*This code test the replay feature of the new peer event services.
* This code test the replay feature of the new peer event services.
* Instead of the default of starting the eventing peer to retrieve the newest block it sets it
* retrieve starting from the start parameter. Also checks with block and filterblock replays.
* Depends on end2end and end2endAndBackagain of have fully run to have the blocks need to work with.
*
* @param client
* @param replayTestChannel
* @param start
Expand Down
51 changes: 51 additions & 0 deletions src/test/java/org/hyperledger/fabric/sdkintegration/End2endIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@

import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.nio.file.Paths;
import java.security.PrivateKey;
import java.util.Arrays;
import java.util.Collection;
import java.util.EnumSet;
Expand All @@ -31,6 +33,7 @@
import java.util.regex.Pattern;

import org.apache.commons.codec.binary.Hex;
import org.bouncycastle.openssl.PEMWriter;
import org.hyperledger.fabric.protos.ledger.rwset.kvrwset.KvRwset;
import org.hyperledger.fabric.sdk.BlockEvent;
import org.hyperledger.fabric.sdk.BlockInfo;
Expand All @@ -40,6 +43,7 @@
import org.hyperledger.fabric.sdk.ChaincodeID;
import org.hyperledger.fabric.sdk.Channel;
import org.hyperledger.fabric.sdk.ChannelConfiguration;
import org.hyperledger.fabric.sdk.Enrollment;
import org.hyperledger.fabric.sdk.EventHub;
import org.hyperledger.fabric.sdk.HFClient;
import org.hyperledger.fabric.sdk.InstallProposalRequest;
Expand All @@ -60,6 +64,7 @@
import org.hyperledger.fabric.sdk.exception.TransactionEventException;
import org.hyperledger.fabric.sdk.security.CryptoSuite;
import org.hyperledger.fabric.sdk.testutils.TestConfig;
import org.hyperledger.fabric_ca.sdk.EnrollmentRequest;
import org.hyperledger.fabric_ca.sdk.HFCAClient;
import org.hyperledger.fabric_ca.sdk.HFCAInfo;
import org.hyperledger.fabric_ca.sdk.RegistrationRequest;
Expand Down Expand Up @@ -156,6 +161,8 @@ public void checkConfig() throws NoSuchFieldException, SecurityException, Illega
}
}

Map<String, Properties> clientTLSProperties = new HashMap<>();

@Test
public void setup() {

Expand Down Expand Up @@ -197,6 +204,26 @@ public void setup() {
final String mspid = sampleOrg.getMSPID();
ca.setCryptoSuite(CryptoSuite.Factory.getCryptoSuite());

if (testConfig.isRunningFabricTLS()) {
//This shows how to get a client TLS certificate from Fabric CA
// we will use one client TLS certificate for orderer peers etc.
final EnrollmentRequest enrollmentRequestTLS = new EnrollmentRequest();
enrollmentRequestTLS.addHost("localhost");
enrollmentRequestTLS.setProfile("tls");
final Enrollment enroll = ca.enroll("admin", "adminpw", enrollmentRequestTLS);
final String tlsCertPEM = enroll.getCert();
final String tlsKeyPEM = getPEMStringFromPrivateKey(enroll.getKey());

final Properties tlsProperties = new Properties();

tlsProperties.put("clientKeyBytes", tlsKeyPEM.getBytes(UTF_8));
tlsProperties.put("clientCertBytes", tlsCertPEM.getBytes(UTF_8));
clientTLSProperties.put(sampleOrg.getName(), tlsProperties);
//Save in samplestore for follow on tests.
sampleStore.storeClientPEMTLCertificate(sampleOrg, tlsCertPEM);
sampleStore.storeClientPEMTLSKey(sampleOrg, tlsKeyPEM);
}

HFCAInfo info = ca.info(); //just check if we connect at all.
assertNotNull(info);
String infoName = info.getCAName();
Expand Down Expand Up @@ -276,6 +303,17 @@ sampleOrgDomainName, format("/users/Admin@%s/msp/keystore", sampleOrgDomainName)

}

static String getPEMStringFromPrivateKey(PrivateKey privateKey) throws IOException {
StringWriter pemStrWriter = new StringWriter();
PEMWriter pemWriter = new PEMWriter(pemStrWriter);

pemWriter.writeObject(privateKey);

pemWriter.close();

return pemStrWriter.toString();
}

//CHECKSTYLE.OFF: Method length is 320 lines (max allowed is 150).
void runChannel(HFClient client, Channel channel, boolean installChaincode, SampleOrg sampleOrg, int delta) {

Expand Down Expand Up @@ -703,6 +741,10 @@ private Channel constructChannel(String name, HFClient client, SampleOrg sampleO
ordererProperties.put("grpc.NettyChannelBuilderOption.keepAliveTimeout", new Object[] {8L, TimeUnit.SECONDS});
ordererProperties.put("grpc.NettyChannelBuilderOption.keepAliveWithoutCalls", new Object[] {true});

if (!clientTLSProperties.isEmpty()) {
ordererProperties.putAll(clientTLSProperties.get(sampleOrg.getName()));
}

orderers.add(client.newOrderer(orderName, sampleOrg.getOrdererLocation(orderName),
ordererProperties));
}
Expand All @@ -727,6 +769,11 @@ private Channel constructChannel(String name, HFClient client, SampleOrg sampleO
if (peerProperties == null) {
peerProperties = new Properties();
}

if (!clientTLSProperties.isEmpty()) {
peerProperties.putAll(clientTLSProperties.get(sampleOrg.getName()));
}

//Example of setting specific options on grpc's NettyChannelBuilder
peerProperties.put("grpc.NettyChannelBuilderOption.maxInboundMessageSize", 9000000);

Expand Down Expand Up @@ -758,6 +805,10 @@ private Channel constructChannel(String name, HFClient client, SampleOrg sampleO
eventHubProperties.put("grpc.NettyChannelBuilderOption.keepAliveTime", new Object[] {5L, TimeUnit.MINUTES});
eventHubProperties.put("grpc.NettyChannelBuilderOption.keepAliveTimeout", new Object[] {8L, TimeUnit.SECONDS});

if (!clientTLSProperties.isEmpty()) {
eventHubProperties.putAll(clientTLSProperties.get(sampleOrg.getName()));
}

EventHub eventHub = client.newEventHub(eventHubName, sampleOrg.getEventHubLocation(eventHubName),
eventHubProperties);
newChannel.addEventHub(eventHub);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -276,4 +276,28 @@ Channel getChannel(HFClient client, String name) throws IOException, ClassNotFou
return ret;
}

public void storeClientPEMTLSKey(SampleOrg sampleOrg, String key) {

setValue("clientPEMTLSKey." + sampleOrg.getName(), key);

}

public String getClientPEMTLSKey(SampleOrg sampleOrg) {

return getValue("clientPEMTLSKey." + sampleOrg.getName());

}

public void storeClientPEMTLCertificate(SampleOrg sampleOrg, String certificate) {

setValue("clientPEMTLSCertificate." + sampleOrg.getName(), certificate);

}

public String getClientPEMTLSCertificate(SampleOrg sampleOrg) {

return getValue("clientPEMTLSCertificate." + sampleOrg.getName());

}

}

0 comments on commit 09776f0

Please sign in to comment.