Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow client TLS certificate and key to be specified in connection profile (backport #261) #262

Merged
merged 1 commit into from
Feb 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 16 additions & 16 deletions src/main/java/org/hyperledger/fabric/sdk/Channel.java
Original file line number Diff line number Diff line change
Expand Up @@ -1627,25 +1627,25 @@ public Orderer addOrderer(SDOrdererAdditionInfo sdOrdererAdditionInfo) throws In

String protocol = (String) findClientProp(config, "protocol", mspid, endpoint, sdOrdererAdditionInfo.isTLS() ? "grpcs:" : "grpc:");

String clientCertFile = (String) findClientProp(config, "clientCertFile", mspid, endpoint, null);
String clientCertFile = (String) findClientProp(config, NetworkConfig.CLIENT_CERT_FILE, mspid, endpoint, null);

if (null != clientCertFile) {
properties.put("clientCertFile", clientCertFile);
properties.put(NetworkConfig.CLIENT_CERT_FILE, clientCertFile);
}

String clientKeyFile = (String) findClientProp(config, "clientKeyFile", mspid, endpoint, null);
String clientKeyFile = (String) findClientProp(config, NetworkConfig.CLIENT_KEY_FILE, mspid, endpoint, null);
if (null != clientKeyFile) {
properties.put("clientKeyFile", clientKeyFile);
properties.put(NetworkConfig.CLIENT_KEY_FILE, clientKeyFile);
}

byte[] clientCertBytes = (byte[]) findClientProp(config, "clientCertBytes", mspid, endpoint, null);
byte[] clientCertBytes = (byte[]) findClientProp(config, NetworkConfig.CLIENT_CERT_BYTES, mspid, endpoint, null);
if (null != clientCertBytes) {
properties.put("clientCertBytes", clientCertBytes);
properties.put(NetworkConfig.CLIENT_CERT_BYTES, clientCertBytes);
}

byte[] clientKeyBytes = (byte[]) findClientProp(config, "clientKeyBytes", mspid, endpoint, null);
byte[] clientKeyBytes = (byte[]) findClientProp(config, NetworkConfig.CLIENT_KEY_BYTES, mspid, endpoint, null);
if (null != clientKeyBytes) {
properties.put("clientKeyBytes", clientKeyBytes);
properties.put(NetworkConfig.CLIENT_KEY_BYTES, clientKeyBytes);
}

String hostnameOverride = (String) findClientProp(config, "hostnameOverride", mspid, endpoint, null);
Expand Down Expand Up @@ -1693,23 +1693,23 @@ public Peer addPeer(SDPeerAdditionInfo sdPeerAddition) throws InvalidArgumentExc

}

String clientCertFile = (String) findClientProp(config, "clientCertFile", mspid, endpoint, null);
String clientCertFile = (String) findClientProp(config, NetworkConfig.CLIENT_CERT_FILE, mspid, endpoint, null);

byte[] clientCertBytes = (byte[]) findClientProp(config, "clientCertBytes", mspid, endpoint, null);
byte[] clientCertBytes = (byte[]) findClientProp(config, NetworkConfig.CLIENT_CERT_BYTES, mspid, endpoint, null);
if (null != clientCertBytes) {
properties.put("clientCertBytes", clientCertBytes);
properties.put(NetworkConfig.CLIENT_CERT_BYTES, clientCertBytes);
} else if (null != clientCertFile) {
properties.put("clientCertFile", clientCertFile);
properties.put(NetworkConfig.CLIENT_CERT_FILE, clientCertFile);
}

properties.put(Peer.PEER_ORGANIZATION_MSPID_PROPERTY, sdPeerAddition.getMspId());

byte[] clientKeyBytes = (byte[]) findClientProp(config, "clientKeyBytes", mspid, endpoint, null);
String clientKeyFile = (String) findClientProp(config, "clientKeyFile", mspid, endpoint, null);
byte[] clientKeyBytes = (byte[]) findClientProp(config, NetworkConfig.CLIENT_KEY_BYTES, mspid, endpoint, null);
String clientKeyFile = (String) findClientProp(config, NetworkConfig.CLIENT_KEY_FILE, mspid, endpoint, null);
if (null != clientKeyBytes) {
properties.put("clientKeyBytes", clientKeyBytes);
properties.put(NetworkConfig.CLIENT_KEY_BYTES, clientKeyBytes);
} else if (null != clientKeyFile) {
properties.put("clientKeyFile", clientKeyFile);
properties.put(NetworkConfig.CLIENT_KEY_FILE, clientKeyFile);
}

String hostnameOverride = (String) findClientProp(config, "hostnameOverride", mspid, endpoint, null);
Expand Down
53 changes: 27 additions & 26 deletions src/main/java/org/hyperledger/fabric/sdk/Endpoint.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
import static org.hyperledger.fabric.sdk.helper.Utils.parseGrpcUrl;

class Endpoint {

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

private static final String SSLPROVIDER = Config.getConfig().getDefaultSSLProvider();
Expand Down Expand Up @@ -172,28 +173,28 @@ class Endpoint {
}
// check for mutual TLS - both clientKey and clientCert must be present
byte[] ckb = null, ccb = null;
if (properties.containsKey("clientKeyFile") && properties.containsKey("clientKeyBytes")) {
if (properties.containsKey(NetworkConfig.CLIENT_KEY_FILE) && properties.containsKey(NetworkConfig.CLIENT_KEY_BYTES)) {
throw new RuntimeException("Properties \"clientKeyFile\" and \"clientKeyBytes\" must cannot both be set");
} else if (properties.containsKey("clientCertFile") && properties.containsKey("clientCertBytes")) {
} else if (properties.containsKey(NetworkConfig.CLIENT_CERT_FILE) && properties.containsKey(NetworkConfig.CLIENT_CERT_BYTES)) {
throw new RuntimeException("Properties \"clientCertFile\" and \"clientCertBytes\" must cannot both be set");
} else if (properties.containsKey("clientKeyFile") || properties.containsKey("clientCertFile")) {
if ((properties.getProperty("clientKeyFile") != null) && (properties.getProperty("clientCertFile") != null)) {
} else if (properties.containsKey(NetworkConfig.CLIENT_KEY_FILE) || properties.containsKey(NetworkConfig.CLIENT_CERT_FILE)) {
if ((properties.getProperty(NetworkConfig.CLIENT_KEY_FILE) != null) && (properties.getProperty(NetworkConfig.CLIENT_CERT_FILE) != null)) {
try {
logger.trace(format("Endpoint %s reading clientKeyFile: %s", url, properties.getProperty("clientKeyFile")));
ckb = Files.readAllBytes(Paths.get(properties.getProperty("clientKeyFile")));
logger.trace(format("Endpoint %s reading clientCertFile: %s", url, properties.getProperty("clientCertFile")));
ccb = Files.readAllBytes(Paths.get(properties.getProperty("clientCertFile")));
logger.trace(format("Endpoint %s reading clientKeyFile: %s", url, properties.getProperty(NetworkConfig.CLIENT_KEY_FILE)));
ckb = Files.readAllBytes(Paths.get(properties.getProperty(NetworkConfig.CLIENT_KEY_FILE)));
logger.trace(format("Endpoint %s reading clientCertFile: %s", url, properties.getProperty(NetworkConfig.CLIENT_CERT_FILE)));
ccb = Files.readAllBytes(Paths.get(properties.getProperty(NetworkConfig.CLIENT_CERT_FILE)));
} catch (IOException e) {
throw new RuntimeException("Failed to parse TLS client key and/or cert", e);
}
} else {
throw new RuntimeException("Properties \"clientKeyFile\" and \"clientCertFile\" must both be set or both be null");
throw new RuntimeException(String.format("Properties \"%s\" and \"%s\" must both be set or both be null", NetworkConfig.CLIENT_KEY_FILE, NetworkConfig.CLIENT_CERT_FILE));
}
} else if (properties.containsKey("clientKeyBytes") || properties.containsKey("clientCertBytes")) {
ckb = (byte[]) properties.get("clientKeyBytes");
ccb = (byte[]) properties.get("clientCertBytes");
} else if (properties.containsKey(NetworkConfig.CLIENT_KEY_BYTES) || properties.containsKey(NetworkConfig.CLIENT_CERT_BYTES)) {
ckb = (byte[]) properties.get(NetworkConfig.CLIENT_KEY_BYTES);
ccb = (byte[]) properties.get(NetworkConfig.CLIENT_CERT_BYTES);
if ((ckb == null) || (ccb == null)) {
throw new RuntimeException("Properties \"clientKeyBytes\" and \"clientCertBytes\" must both be set or both be null");
throw new RuntimeException(String.format("Properties \"%s\" and \"%s\" must both be set or both be null", NetworkConfig.CLIENT_KEY_BYTES, NetworkConfig.CLIENT_CERT_BYTES));
}
}

Expand Down Expand Up @@ -400,28 +401,28 @@ AbstractMap.SimpleImmutableEntry<PrivateKey, X509Certificate[]> getClientTLSProp

// check for mutual TLS - both clientKey and clientCert must be present
byte[] ckb = null, ccb = null;
if (properties.containsKey("clientKeyFile") && properties.containsKey("clientKeyBytes")) {
if (properties.containsKey(NetworkConfig.CLIENT_KEY_FILE) && properties.containsKey(NetworkConfig.CLIENT_KEY_BYTES)) {
throw new RuntimeException("Properties \"clientKeyFile\" and \"clientKeyBytes\" must cannot both be set");
} else if (properties.containsKey("clientCertFile") && properties.containsKey("clientCertBytes")) {
} else if (properties.containsKey(NetworkConfig.CLIENT_CERT_FILE) && properties.containsKey(NetworkConfig.CLIENT_CERT_BYTES)) {
throw new RuntimeException("Properties \"clientCertFile\" and \"clientCertBytes\" must cannot both be set");
} else if (properties.containsKey("clientKeyFile") || properties.containsKey("clientCertFile")) {
if ((properties.getProperty("clientKeyFile") != null) && (properties.getProperty("clientCertFile") != null)) {
} else if (properties.containsKey(NetworkConfig.CLIENT_KEY_FILE) || properties.containsKey(NetworkConfig.CLIENT_CERT_FILE)) {
if ((properties.getProperty(NetworkConfig.CLIENT_KEY_FILE) != null) && (properties.getProperty(NetworkConfig.CLIENT_CERT_FILE) != null)) {
try {
logger.trace(format("Endpoint %s reading clientKeyFile: %s", url, new File(properties.getProperty("clientKeyFile")).getAbsolutePath()));
ckb = Files.readAllBytes(Paths.get(properties.getProperty("clientKeyFile")));
logger.trace(format("Endpoint %s reading clientCertFile: %s", url, new File(properties.getProperty("clientCertFile")).getAbsolutePath()));
ccb = Files.readAllBytes(Paths.get(properties.getProperty("clientCertFile")));
logger.trace(format("Endpoint %s reading clientKeyFile: %s", url, new File(properties.getProperty(NetworkConfig.CLIENT_KEY_FILE)).getAbsolutePath()));
ckb = Files.readAllBytes(Paths.get(properties.getProperty(NetworkConfig.CLIENT_KEY_FILE)));
logger.trace(format("Endpoint %s reading clientCertFile: %s", url, new File(properties.getProperty(NetworkConfig.CLIENT_CERT_FILE)).getAbsolutePath()));
ccb = Files.readAllBytes(Paths.get(properties.getProperty(NetworkConfig.CLIENT_CERT_FILE)));
} catch (IOException e) {
throw new RuntimeException("Failed to parse TLS client key and/or cert", e);
}
} else {
throw new RuntimeException("Properties \"clientKeyFile\" and \"clientCertFile\" must both be set or both be null");
throw new RuntimeException(String.format("Properties \"%s\" and \"%s\" must both be set or both be null", NetworkConfig.CLIENT_KEY_FILE, NetworkConfig.CLIENT_CERT_FILE));
}
} else if (properties.containsKey("clientKeyBytes") || properties.containsKey("clientCertBytes")) {
ckb = (byte[]) properties.get("clientKeyBytes");
ccb = (byte[]) properties.get("clientCertBytes");
} else if (properties.containsKey(NetworkConfig.CLIENT_KEY_BYTES) || properties.containsKey(NetworkConfig.CLIENT_CERT_BYTES)) {
ckb = (byte[]) properties.get(NetworkConfig.CLIENT_KEY_BYTES);
ccb = (byte[]) properties.get(NetworkConfig.CLIENT_CERT_BYTES);
if ((ckb == null) || (ccb == null)) {
throw new RuntimeException("Properties \"clientKeyBytes\" and \"clientCertBytes\" must both be set or both be null");
throw new RuntimeException(String.format("Properties \"%s\" and \"%s\" must both be set or both be null", NetworkConfig.CLIENT_KEY_BYTES, NetworkConfig.CLIENT_CERT_BYTES));
}
}

Expand Down
16 changes: 12 additions & 4 deletions src/main/java/org/hyperledger/fabric/sdk/NetworkConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,14 @@
*/

public class NetworkConfig {
public static final String CLIENT_CERT_BYTES = "clientCertBytes";

public static final String CLIENT_KEY_BYTES = "clientKeyBytes";

public static final String CLIENT_CERT_FILE = "clientCertFile";

public static final String CLIENT_KEY_FILE = "clientKeyFile";

private static final String URL_PROP_NAME = "url";

private final JsonObject jsonConfig;
Expand Down Expand Up @@ -843,22 +851,22 @@ private void getTLSCerts(JsonObject jsonOrderer, Properties props) {
String certfile = getJsonValueAsString(jsonTlsClientCerts.get("certfile"));

if (keyfile != null) {
props.put("tlsClientKeyFile", keyfile);
props.put(CLIENT_KEY_FILE, keyfile);
}

if (certfile != null) {
props.put("tlsClientCertFile", certfile);
props.put(CLIENT_CERT_FILE, certfile);
}

String keyBytes = getJsonValueAsString(jsonTlsClientCerts.get("keyPem"));
String certBytes = getJsonValueAsString(jsonTlsClientCerts.get("certPem"));

if (keyBytes != null) {
props.put("tlsClientKeyBytes", keyBytes.getBytes());
props.put(CLIENT_KEY_BYTES, keyBytes.getBytes());
}

if (certBytes != null) {
props.put("tlsClientCertBytes", certBytes.getBytes());
props.put(CLIENT_CERT_BYTES, certBytes.getBytes());
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/main/java/org/hyperledger/fabric_ca/sdk/HFCAClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -1617,17 +1617,17 @@ private void setUpSSL() throws InvalidArgumentException {
}
}

String tlsClientKeyFile = properties.getProperty("tlsClientKeyFile");
String tlsClientCertFile = properties.getProperty("tlsClientCertFile");
String tlsClientKeyFile = properties.getProperty(NetworkConfig.CLIENT_KEY_FILE);
String tlsClientCertFile = properties.getProperty(NetworkConfig.CLIENT_CERT_FILE);

byte[] tlsClientKeyAsBytes = (byte[]) properties.get("tlsClientKeyBytes");
byte[] tlsClientKeyAsBytes = (byte[]) properties.get(NetworkConfig.CLIENT_KEY_BYTES);
if (tlsClientKeyFile != null && tlsClientKeyAsBytes != null) {
logger.warn("SSL CA client key is specified as bytes and as a file path. Using client key specified as bytes.");
}
if (tlsClientKeyFile != null && tlsClientKeyAsBytes == null) {
tlsClientKeyAsBytes = Files.readAllBytes(Paths.get(tlsClientKeyFile));
}
byte[] tlsClientCertAsBytes = (byte[]) properties.get("tlsClientCertBytes");
byte[] tlsClientCertAsBytes = (byte[]) properties.get(NetworkConfig.CLIENT_CERT_BYTES);
if (tlsClientCertFile != null && tlsClientCertAsBytes != null) {
logger.warn("SSL CA client cert is specified as bytes and as a file path. Using client cert specified as bytes.");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
{
"name": "global-trade-network",
"x-type": "hlfv1",
"description": "The network to be in if you want to stay in the global trade business",
"version": "1.0.0",
"client": {
"organization": "Org1",
"credentialStore": {
"path": "/tmp/hfc-kvs",
"cryptoStore": {
"path": "/tmp/hfc-cvs"
},
"wallet": "wallet-name"
}
},
"channels": {
"mychannel": {
"orderers": [
"orderer.example.com"
],
"peers": {
"peer0.org1.example.com": {
"endorsingPeer": true,
"chaincodeQuery": true,
"ledgerQuery": true,
"eventSource": true

},
"peer1.org1.example.com": {
"endorsingPeer": true,
"chaincodeQuery": true,
"ledgerQuery": true,
"eventSource": true
}
},
"chaincodes": [
"example02:v1",
"marbles:1.0"
]
}
},
"organizations": {
"Org1": {
"mspid": "Org1MSP",
"peers": [
"peer0.org1.example.com",
"peer1.org1.example.com"
],
"certificateAuthorities": [
"ca-org1"
],
"adminPrivateKey": {
"pem": "-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQghnA7rdgbZi/wndusiXjyf0KgE6OKZjQ+5INjwelRAC6hRANCAASb3u+hY+U/FZvhYDN6d08HJ1v56UJUyz/n2NHyJgTg6kC05AaJMeGIinEF0JeJtRDNVQGzoQJQYjnzUTS9FvGh\n-----END PRIVATE KEY-----"
},
"signedCert": {
"path": "src/test/fixture/sdkintegration/e2e-2Orgs/v1.3/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/signcerts/Admin@org1.example.com-cert.pem"
}
}
},
"orderers": {
"orderer.example.com": {
"url": "grpcs://localhost:7050",
"grpcOptions": {
"ssl-target-name-override": "orderer.example.com",
"grpc-max-send-message-length": 15
},
"tlsCACerts": {
"pem": "-----BEGIN CERTIFICATE----- <etc>"
}
}
},
"peers": {
"peer0.org1.example.com": {
"url": "grpcs://localhost:7051",
"grpcOptions": {
"ssl-target-name-override": "peer0.org1.example.com",
"grpc.http2.keepalive_time": 15
},
"tlsCACerts": {
"path": "src/test/fixture/sdkintegration/e2e-2Orgs/v1.3/crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.crt",
"client": {
"certfile": "./tls/sign.pem",
"keyfile": "./tls/key.pem"
}
}
},
"peer1.org1.example.com": {
"url": "grpcs://localhost:7051",
"grpcOptions": {
"ssl-target-name-override": "peer1.org1.example.com",
"grpc.http2.keepalive_time": 15
},
"tlsCACerts": {
"path": "src/test/fixture/sdkintegration/e2e-2Orgs/v1.3/crypto-config/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls/server.crt",
"client": {
"certPem": "-----BEGIN CERTIFICATE----- <etc>",
"keyPem": "-----BEGIN PRIVATE KEY----- <etc>"
}
}
}
},"certificateAuthorities": {
"ca-org1": {
"url": "https://localhost:7054",
"httpOptions": {
"verify": true
},
"tlsCACerts": {
"path": "peerOrganizations/org1.example.com/ca/org1.example.com-cert.pem",
"pem": "-----BEGIN CERTIFICATE----- <etc>"
},
"registrar": [
{
"enrollId": "admin",
"enrollSecret": "adminpw"
}
],
"caName": "caNameHere"
}
}
}
5 changes: 5 additions & 0 deletions src/test/fixture/testPems/client.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEILaiKBtmV7pPCel9NBp74A6jJWHc/Vobug5AyMkncB3ToAoGCCqGSM49
AwEHoUQDQgAEJT+fZ/nl8t38QY6VmddSvjB9HMITio6JUFZhDJ3qoAqCVAfKi6EI
sH+zLZuZA/324j3iHRYkNFUqkNA9wU91qw==
-----END EC PRIVATE KEY-----
Loading