Skip to content
This repository was archived by the owner on Apr 22, 2025. It is now read-only.

Commit f80259c

Browse files
author
Saad Karim
committed
[FAB-9373] Add SDK support for Certificate API
Added support to be able to query certificates from the fabric CA server. Change-Id: I716c58da4eeb8bee7beeeab7ca5f39e786f32493 Signed-off-by: Saad Karim <skarim@us.ibm.com>
1 parent edd54f8 commit f80259c

File tree

10 files changed

+666
-20
lines changed

10 files changed

+666
-20
lines changed

src/main/java/org/hyperledger/fabric/sdk/helper/Utils.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,14 @@
2525
import java.nio.file.Path;
2626
import java.nio.file.Paths;
2727
import java.security.SecureRandom;
28+
import java.text.SimpleDateFormat;
2829
import java.time.Instant;
2930
import java.util.Collection;
3031
import java.util.Comparator;
32+
import java.util.Date;
3133
import java.util.List;
3234
import java.util.Properties;
35+
import java.util.TimeZone;
3336
import java.util.UUID;
3437
import java.util.regex.Matcher;
3538
import java.util.regex.Pattern;
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
package org.hyperledger.fabric_ca.sdk;
2+
3+
import java.util.Date;
4+
import java.util.HashMap;
5+
import java.util.Map;
6+
7+
import org.hyperledger.fabric_ca.sdk.exception.InvalidArgumentException;
8+
import org.hyperledger.fabric_ca.sdk.helper.Util;
9+
10+
/**
11+
* Request to the Fabric CA server to get certificates
12+
* based on filter parameters
13+
*/
14+
public class HFCACertificateRequest {
15+
16+
private final Map<String, String> queryParms = new HashMap<>();
17+
18+
/**
19+
* Get certificate request from Fabric CA server
20+
*/
21+
HFCACertificateRequest() {
22+
}
23+
24+
/**
25+
* Get certificates for this enrollment ID
26+
*
27+
* @param enrollmentID Enrollment ID associated with the certificate(s)
28+
*/
29+
public void setEnrollmentID(String enrollmentID) {
30+
queryParms.put("id", enrollmentID);
31+
}
32+
33+
/**
34+
* Get certificates for this serial number
35+
*
36+
* @param serial Serial Number of the certificate
37+
*/
38+
public void setSerial(String serial) {
39+
queryParms.put("serial", serial);
40+
}
41+
42+
/**
43+
* Get certificates for this aki
44+
*
45+
* @param aki AKI of the certificate(s)
46+
*/
47+
public void setAki(String aki) {
48+
queryParms.put("aki", aki);
49+
}
50+
51+
/**
52+
* Get certificates that have been revoked after this date
53+
*
54+
* @param revokedStart Revoked after date
55+
* @throws InvalidArgumentException Date can't be null
56+
*/
57+
public void setRevokedStart(Date revokedStart) throws InvalidArgumentException {
58+
if (revokedStart == null) {
59+
throw new InvalidArgumentException("Date can't be null");
60+
}
61+
queryParms.put("revoked_start", Util.dateToString(revokedStart));
62+
}
63+
64+
/**
65+
* Get certificates that have been revoked before this date
66+
*
67+
* @param revokedEnd Revoked before date
68+
* @throws InvalidArgumentException Date can't be null
69+
*/
70+
public void setRevokedEnd(Date revokedEnd) throws InvalidArgumentException {
71+
if (revokedEnd == null) {
72+
throw new InvalidArgumentException("Date can't be null");
73+
}
74+
queryParms.put("revoked_end", Util.dateToString(revokedEnd));
75+
}
76+
77+
/**
78+
* Get certificates that have expired after this date
79+
*
80+
* @param expiredStart Expired after date
81+
* @throws InvalidArgumentException Date can't be null
82+
*/
83+
public void setExpiredStart(Date expiredStart) throws InvalidArgumentException {
84+
if (expiredStart == null) {
85+
throw new InvalidArgumentException("Date can't be null");
86+
}
87+
queryParms.put("expired_start", Util.dateToString(expiredStart));
88+
}
89+
90+
/**
91+
* Get certificates that have expired before this date
92+
*
93+
* @param expiredEnd Expired end date
94+
* @throws InvalidArgumentException Date can't be null
95+
*/
96+
public void setExpiredEnd(Date expiredEnd) throws InvalidArgumentException {
97+
if (expiredEnd == null) {
98+
throw new InvalidArgumentException("Date can't be null");
99+
}
100+
queryParms.put("expired_end", Util.dateToString(expiredEnd));
101+
}
102+
103+
/**
104+
* Get certificates that include/exclude expired certificates
105+
*
106+
* @param expired Boolean indicating if expired certificates should be excluded
107+
*/
108+
public void setExpired(boolean expired) {
109+
if (expired) {
110+
queryParms.put("notexpired", "false");
111+
} else {
112+
queryParms.put("notexpired", "true");
113+
}
114+
}
115+
116+
/**
117+
* Get certificates that include/exclude revoked certificates
118+
*
119+
* @param revoked Boolean indicating if revoked certificates should excluded
120+
*/
121+
public void setRevoked(boolean revoked) {
122+
if (revoked) {
123+
queryParms.put("notrevoked", "false");
124+
} else {
125+
queryParms.put("notrevoked", "true");
126+
}
127+
}
128+
129+
/**
130+
* Get all the filter parameters for this certificate request
131+
*
132+
* @return A map of filters that will be used as query parameters in GET request
133+
*/
134+
public Map<String, String> getQueryParameters() {
135+
return this.queryParms;
136+
}
137+
138+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package org.hyperledger.fabric_ca.sdk;
2+
3+
import java.util.Collection;
4+
5+
/**
6+
* The response from a certificate API request, contains the status code of the
7+
* request and certificates that were retrieved
8+
*/
9+
public class HFCACertificateResponse {
10+
private final int statusCode;
11+
private final Collection<HFCACredential> certs;
12+
13+
/**
14+
* Contains the response from the server with status code and credentials requested
15+
*
16+
* @param statusCode Status code of the HTTP request
17+
* @param certs The certificates return from the GET request
18+
*/
19+
HFCACertificateResponse(int statusCode, Collection<HFCACredential> certs) {
20+
this.statusCode = statusCode;
21+
this.certs = certs;
22+
}
23+
24+
/**
25+
* Returns the status code of the request
26+
*
27+
* @return HTTP status code
28+
*/
29+
public int getStatusCode() {
30+
return statusCode;
31+
}
32+
33+
/**
34+
* Returns the certificates that were retrieved from the GET certificate request
35+
*
36+
* @return Certificates
37+
*/
38+
public Collection<HFCACredential> getCerts() {
39+
return certs;
40+
}
41+
}

src/main/java/org/hyperledger/fabric_ca/sdk/HFCAClient.java

Lines changed: 62 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,13 @@
3838
import java.security.cert.CertificateException;
3939
import java.security.cert.CertificateFactory;
4040
import java.security.cert.X509Certificate;
41-
import java.text.SimpleDateFormat;
4241
import java.util.ArrayList;
4342
import java.util.Base64;
4443
import java.util.Collection;
4544
import java.util.Date;
4645
import java.util.Map;
4746
import java.util.Map.Entry;
4847
import java.util.Properties;
49-
import java.util.TimeZone;
5048

5149
import javax.json.Json;
5250
import javax.json.JsonArray;
@@ -104,13 +102,15 @@
104102
import org.hyperledger.fabric_ca.sdk.exception.AffiliationException;
105103
import org.hyperledger.fabric_ca.sdk.exception.EnrollmentException;
106104
import org.hyperledger.fabric_ca.sdk.exception.GenerateCRLException;
105+
import org.hyperledger.fabric_ca.sdk.exception.HFCACertificateException;
107106
import org.hyperledger.fabric_ca.sdk.exception.HTTPException;
108107
import org.hyperledger.fabric_ca.sdk.exception.IdentityException;
109108
import org.hyperledger.fabric_ca.sdk.exception.InfoException;
110109
import org.hyperledger.fabric_ca.sdk.exception.InvalidArgumentException;
111110
import org.hyperledger.fabric_ca.sdk.exception.RegistrationException;
112111
import org.hyperledger.fabric_ca.sdk.exception.RevocationException;
113112
import org.hyperledger.fabric_ca.sdk.helper.Config;
113+
import org.hyperledger.fabric_ca.sdk.helper.Util;
114114

115115
import static java.lang.String.format;
116116
import static java.nio.charset.StandardCharsets.UTF_8;
@@ -189,6 +189,7 @@ public class HFCAClient {
189189
private static final String HFCA_REVOKE = HFCA_CONTEXT_ROOT + "revoke";
190190
private static final String HFCA_INFO = HFCA_CONTEXT_ROOT + "cainfo";
191191
private static final String HFCA_GENCRL = HFCA_CONTEXT_ROOT + "gencrl";
192+
private static final String HFCA_CERTIFICATE = HFCAClient.HFCA_CONTEXT_ROOT + "certificates";
192193

193194
private final String url;
194195
private final boolean isSSL;
@@ -912,16 +913,16 @@ public String generateCRL(User registrar, Date revokedBefore, Date revokedAfter,
912913
//---------------------------------------
913914
JsonObjectBuilder factory = Json.createObjectBuilder();
914915
if (revokedBefore != null) {
915-
factory.add("revokedBefore", toJson(revokedBefore));
916+
factory.add("revokedBefore", Util.dateToString(revokedBefore));
916917
}
917918
if (revokedAfter != null) {
918-
factory.add("revokedAfter", toJson(revokedAfter));
919+
factory.add("revokedAfter", Util.dateToString(revokedAfter));
919920
}
920921
if (expireBefore != null) {
921-
factory.add("expireBefore", toJson(expireBefore));
922+
factory.add("expireBefore", Util.dateToString(expireBefore));
922923
}
923924
if (expireAfter != null) {
924-
factory.add("expireAfter", toJson(expireAfter));
925+
factory.add("expireAfter", Util.dateToString(expireAfter));
925926
}
926927
if (caName != null) {
927928
factory.add(HFCAClient.FABRIC_CA_REQPROP, caName);
@@ -1055,14 +1056,55 @@ public HFCAAffiliation getHFCAAffiliations(User registrar) throws AffiliationExc
10551056

10561057
}
10571058

1058-
private String toJson(Date date) {
1059-
final TimeZone utc = TimeZone.getTimeZone("UTC");
1059+
/**
1060+
* @return HFCACertificateRequest object
1061+
*/
1062+
public HFCACertificateRequest newHFCACertificateRequest() {
1063+
return new HFCACertificateRequest();
1064+
}
10601065

1061-
SimpleDateFormat tformat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
1062-
tformat.setTimeZone(utc);
1063-
return tformat.format(date);
1066+
/**
1067+
* Gets all certificates that the registrar is allowed to see and based on filter parameters that
1068+
* are part of the certificate request.
1069+
*
1070+
* @param registrar The identity of the registrar (i.e. who is performing the registration).
1071+
* @param req The certificate request that contains filter parameters
1072+
* @return HFCACertificateResponse object
1073+
* @throws HFCACertificateException Failed to process get certificate request
1074+
*/
1075+
public HFCACertificateResponse getHFCACertificates(User registrar, HFCACertificateRequest req) throws HFCACertificateException {
1076+
try {
1077+
logger.debug(format("certificate url: %s, registrar: %s", HFCA_CERTIFICATE, registrar.getName()));
1078+
1079+
JsonObject result = httpGet(HFCA_CERTIFICATE, registrar, req.getQueryParameters());
1080+
1081+
int statusCode = result.getInt("statusCode");
1082+
Collection<HFCACredential> certs = new ArrayList<>();
1083+
if (statusCode < 400) {
1084+
JsonArray certificates = result.getJsonArray("certs");
1085+
if (certificates != null && !certificates.isEmpty()) {
1086+
for (int i = 0; i < certificates.size(); i++) {
1087+
String certPEM = certificates.getJsonObject(i).getString("PEM");
1088+
certs.add(new HFCAX509Certificate(certPEM));
1089+
}
1090+
}
1091+
logger.debug(format("certificate url: %s, registrar: %s done.", HFCA_CERTIFICATE, registrar));
1092+
}
1093+
return new HFCACertificateResponse(statusCode, certs);
1094+
} catch (HTTPException e) {
1095+
String msg = format("[Code: %d] - Error while getting certificates from url '%s': %s", e.getStatusCode(), HFCA_CERTIFICATE, e.getMessage());
1096+
HFCACertificateException certificateException = new HFCACertificateException(msg, e);
1097+
logger.error(msg);
1098+
throw certificateException;
1099+
} catch (Exception e) {
1100+
String msg = format("Error while getting certificates from url '%s': %s", HFCA_CERTIFICATE, e.getMessage());
1101+
HFCACertificateException certificateException = new HFCACertificateException(msg, e);
1102+
logger.error(msg);
1103+
throw certificateException;
1104+
}
10641105
}
10651106

1107+
10661108
/**
10671109
* Http Post Request.
10681110
*
@@ -1167,8 +1209,12 @@ JsonObject httpPost(String url, String body, User registrar) throws Exception {
11671209
}
11681210

11691211
JsonObject httpGet(String url, User registrar) throws Exception {
1212+
return httpGet(url, registrar, null);
1213+
}
1214+
1215+
JsonObject httpGet(String url, User registrar, Map<String, String> queryMap) throws Exception {
11701216
String authHTTPCert = getHTTPAuthCertificate(registrar.getEnrollment(), "");
1171-
url = getURL(url);
1217+
url = getURL(url, queryMap);
11721218
HttpGet httpGet = new HttpGet(url);
11731219
httpGet.setConfig(getRequestConfig());
11741220
logger.debug(format("httpGet %s, authHTTPCert: %s", url, authHTTPCert));
@@ -1438,13 +1484,7 @@ public Socket createSocket() throws IOException {
14381484
}
14391485

14401486
String getURL(String endpoint) throws URISyntaxException, MalformedURLException, InvalidArgumentException {
1441-
setUpSSL();
1442-
String url = this.url + endpoint;
1443-
URIBuilder uri = new URIBuilder(url);
1444-
if (caName != null) {
1445-
uri.addParameter("ca", caName);
1446-
}
1447-
return uri.build().toURL().toString();
1487+
return getURL(endpoint, null);
14481488
}
14491489

14501490
String getURL(String endpoint, Map<String, String> queryMap) throws URISyntaxException, MalformedURLException, InvalidArgumentException {
@@ -1456,7 +1496,9 @@ String getURL(String endpoint, Map<String, String> queryMap) throws URISyntaxExc
14561496
}
14571497
if (queryMap != null) {
14581498
for (Map.Entry<String, String> param : queryMap.entrySet()) {
1459-
uri.addParameter(param.getKey(), param.getValue());
1499+
if (!Utils.isNullOrEmpty(param.getValue())) {
1500+
uri.addParameter(param.getKey(), param.getValue());
1501+
}
14601502
}
14611503
}
14621504
return uri.build().toURL().toString();
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package org.hyperledger.fabric_ca.sdk;
2+
3+
/**
4+
* Credentials supported by Fabric CA
5+
*/
6+
public abstract class HFCACredential {
7+
}

0 commit comments

Comments
 (0)