Skip to content

Commit 7ba4131

Browse files
authored
0.40.0
- Keytool actions now return any output from the corresponding keytool command as an Action Result - Changing Cert File, Cert File Type, or Cert File Pass will now update the corresponding System property - At startup, invoke keytool -help to check whether keytool is available. If it isn't, hide the keytool actions - Added a default dslink.jks keystore file to resources - If keystore cannot be found or generated, copy the default keystore from resources into the working directory
2 parents af4bc38 + 90ea2bf commit 7ba4131

File tree

5 files changed

+132
-39
lines changed

5 files changed

+132
-39
lines changed

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
**.DS_Store
2424

2525
# Runtime files
26-
**.jks
2726
**.key
2827
**nodes.json
2928
**nodes*.zip

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ subprojects {
55
apply plugin: 'maven'
66

77
group 'org.iot-dsa'
8-
version '0.39.0'
8+
version '0.40.0'
99

1010
sourceCompatibility = 1.6
1111
targetCompatibility = 1.6

dslink-v2/src/main/java/com/acuity/iot/dsa/dslink/sys/cert/KeyToolUtil.java

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import java.io.InputStreamReader;
77
import java.nio.file.Files;
88
import java.nio.file.Paths;
9-
109
import org.iot.dsa.logging.DSLogger;
1110
import org.iot.dsa.time.DSTime;
1211

@@ -40,7 +39,7 @@ private String executeCommand(String[] cmd) {
4039
}
4140
}
4241

43-
public static void generateSelfSigned(String keystore, String password) {
42+
public static String generateSelfSigned(String keystore, String password) {
4443
String[] cmd = new String[]{
4544
"keytool",
4645
"-genkey",
@@ -50,12 +49,12 @@ public static void generateSelfSigned(String keystore, String password) {
5049
"-alias", "dsa",
5150
"-keyalg", "RSA",
5251
"-validity", "18000",
53-
"-dname", "\"CN=dslink-java-v2, O=DSA, C=US\""
52+
"-dname", "CN=dslink-java-v2, O=DSA, C=US"
5453
};
55-
inst.executeCommand(cmd);
54+
return inst.executeCommand(cmd);
5655
}
5756

58-
public static String generateCSR(String keystore, String password) throws IOException {
57+
public static String[] generateCSR(String keystore, String password) throws IOException {
5958
String filename = "dsa.csr";
6059
String[] cmd = new String[]{
6160
"keytool",
@@ -68,11 +67,12 @@ public static String generateCSR(String keystore, String password) throws IOExce
6867
"-dname", "\"CN=dslink-java-v2, O=DSA, C=US\"",
6968
"-file", filename
7069
};
71-
inst.executeCommand(cmd);
72-
return new String(Files.readAllBytes(Paths.get(filename)));
70+
String result = inst.executeCommand(cmd);
71+
String csr = new String(Files.readAllBytes(Paths.get(filename)));
72+
return new String[] {result, csr};
7373
}
7474

75-
public static void importCACert(String keystore, String certStr, String alias, String password) throws IOException {
75+
public static String importCACert(String keystore, String certStr, String alias, String password) throws IOException {
7676
String filename = DSTime.encodeForFiles(DSTime.getCalendar(System.currentTimeMillis()), new StringBuilder("tempCACert")).toString();
7777
Files.write(Paths.get(filename), certStr.getBytes());
7878
String[] cmd = new String[]{
@@ -84,12 +84,13 @@ public static void importCACert(String keystore, String certStr, String alias, S
8484
"-alias", alias,
8585
"-file", filename
8686
};
87-
inst.executeCommand(cmd);
87+
String result = inst.executeCommand(cmd);
8888

8989
new File(filename).delete();
90+
return result;
9091
}
9192

92-
public static void importPrimaryCert(String keystore, String certStr, String password) throws IOException {
93+
public static String importPrimaryCert(String keystore, String certStr, String password) throws IOException {
9394
String filename = DSTime.encodeForFiles(DSTime.getCalendar(System.currentTimeMillis()), new StringBuilder("tempCert")).toString();
9495
Files.write(Paths.get(filename), certStr.getBytes());
9596
String[] cmd = new String[]{
@@ -101,9 +102,10 @@ public static void importPrimaryCert(String keystore, String certStr, String pas
101102
"-alias", "dsa",
102103
"-file", filename
103104
};
104-
inst.executeCommand(cmd);
105+
String result = inst.executeCommand(cmd);
105106

106107
new File(filename).delete();
108+
return result;
107109
}
108110

109111
public static String getEntry(String keystore, String password) {
@@ -118,15 +120,23 @@ public static String getEntry(String keystore, String password) {
118120
return inst.executeCommand(cmd);
119121
}
120122

121-
public static void deleteEntry(String keystore, String password) {
123+
public static String deleteEntry(String keystore, String password) {
122124
String[] cmd = new String[]{
123125
"keytool",
124126
"-delete",
125127
"-keystore", keystore,
126128
"-storepass", password,
127129
"-alias", "dsa",
128130
};
129-
inst.executeCommand(cmd);
131+
return inst.executeCommand(cmd);
132+
}
133+
134+
public static String help() {
135+
String[] cmd = new String[] {
136+
"keytool",
137+
"-help"
138+
};
139+
return inst.executeCommand(cmd);
130140
}
131141

132142
}

dslink-v2/src/main/java/com/acuity/iot/dsa/dslink/sys/cert/SysCertService.java

Lines changed: 108 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
import com.acuity.iot.dsa.dslink.sys.cert.HostnameWhitelist.WhitelistValue;
44
import java.io.File;
5+
import java.io.FileOutputStream;
56
import java.io.IOException;
7+
import java.io.InputStream;
68
import java.security.cert.CertificateEncodingException;
79
import java.security.cert.X509Certificate;
810
import javax.net.ssl.HostnameVerifier;
@@ -50,6 +52,7 @@ public class SysCertService extends DSNode {
5052
private static final String GENERATE_SELF_SIGNED = "Generate Self-Signed Certificate";
5153
private static final String DELETE_KS_ENTRY = "Delete Keystore Entry";
5254
private static final String GET_KS_ENTRY = "Get Keystore Entry";
55+
private static final String DEFAULT_CERTFILE = "dslink.jks";
5356

5457
// Fields
5558
// ------
@@ -60,6 +63,12 @@ public class SysCertService extends DSNode {
6063
private DSInfo keystorePath = getInfo(CERTFILE);
6164
private DSInfo keystorePass = getInfo(CERTFILE_PASS);
6265
private DSInfo keystoreType = getInfo(CERTFILE_TYPE);
66+
private DSInfo generateCsr = getInfo(GENERATE_CSR);
67+
private DSInfo importCaCert = getInfo(IMPORT_CA_CERT);
68+
private DSInfo importPrimaryCert = getInfo(IMPORT_PRIMARY_CERT);
69+
private DSInfo generateSSCert = getInfo(GENERATE_SELF_SIGNED);
70+
private DSInfo getKSEntry = getInfo(GET_KS_ENTRY);
71+
private DSInfo deleteKSEntry = getInfo(DELETE_KS_ENTRY);
6372
private CertCollection localTruststore;
6473
private CertCollection quarantine;
6574
private HostnameWhitelist whitelist;
@@ -128,7 +137,7 @@ public void declareDefaults() {
128137
declareDefault(ALLOW_SERVERS, DSBool.TRUE);
129138
declareDefault(VERIFY_HOSTNAMES, DSBool.TRUE);
130139
declareDefault(HOSTNAME_WHITELIST, new HostnameWhitelist());
131-
declareDefault(CERTFILE, DSString.valueOf("dslink.jks"));
140+
declareDefault(CERTFILE, DSString.valueOf(DEFAULT_CERTFILE));
132141
declareDefault(CERTFILE_TYPE, DSString.valueOf("JKS"));
133142
declareDefault(CERTFILE_PASS, DSPasswordAes128.valueOf("dsarocks"));
134143
declareDefault(LOCAL_TRUSTSTORE, new CertCollection());
@@ -153,17 +162,23 @@ public void prepareParameter(DSInfo info, DSMap parameter) {
153162

154163
@Override
155164
public ActionResult invoke(DSInfo info, ActionInvocation invocation) {
156-
String csr = ((SysCertService) info.getParent()).generateCSR();
157-
return csr != null ? new DSActionValues(info.getAction())
158-
.addResult(DSString.valueOf(csr)) : null;
165+
String[] results = ((SysCertService) info.getParent()).generateCSR();
166+
if (results != null && results.length > 1) {
167+
return new DSActionValues(info.getAction())
168+
.addResult(DSString.valueOf(results[0]))
169+
.addResult(DSString.valueOf(results[1]));
170+
} else {
171+
return null;
172+
}
159173
}
160174
};
161175
act.setResultType(ResultType.VALUES);
176+
act.addValueResult("Result", DSValueType.STRING);
162177
act.addValueResult("CSR", DSValueType.STRING).setEditor("textarea");
163178
return act;
164179
}
165180

166-
private String generateCSR() {
181+
private String[] generateCSR() {
167182
try {
168183
return KeyToolUtil.generateCSR(getKeystorePath(), getCertFilePass());
169184
} catch (IOException e) {
@@ -182,22 +197,25 @@ public void prepareParameter(DSInfo info, DSMap parameter) {
182197
@Override
183198
public ActionResult invoke(DSInfo info, ActionInvocation invocation) {
184199
DSMap parameters = invocation.getParameters();
185-
((SysCertService) info.getParent()).importCACert(parameters);
186-
return null;
200+
String result = ((SysCertService) info.getParent()).importCACert(parameters);
201+
return new DSActionValues(info.getAction()).addResult(DSString.valueOf(result));
187202
}
188203
};
189204
act.addParameter("Alias", DSValueType.STRING, null);
190205
act.addParameter("Certificate", DSValueType.STRING, null).setEditor("textarea");
206+
act.setResultType(ResultType.VALUES);
207+
act.addValueResult("Result", DSValueType.STRING);
191208
return act;
192209
}
193210

194-
private void importCACert(DSMap parameters) {
211+
private String importCACert(DSMap parameters) {
195212
String alias = parameters.getString("Alias");
196213
String certStr = parameters.getString("Certificate");
197214
try {
198-
KeyToolUtil.importCACert(getKeystorePath(), certStr, alias, getCertFilePass());
215+
return KeyToolUtil.importCACert(getKeystorePath(), certStr, alias, getCertFilePass());
199216
} catch (IOException e) {
200217
DSException.throwRuntime(e);
218+
return null;
201219
}
202220
}
203221

@@ -211,20 +229,23 @@ public void prepareParameter(DSInfo info, DSMap parameter) {
211229
@Override
212230
public ActionResult invoke(DSInfo info, ActionInvocation invocation) {
213231
DSMap parameters = invocation.getParameters();
214-
((SysCertService) info.getParent()).importPrimaryCert(parameters);
215-
return null;
232+
String result = ((SysCertService) info.getParent()).importPrimaryCert(parameters);
233+
return new DSActionValues(info.getAction()).addResult(DSString.valueOf(result));
216234
}
217235
};
218236
act.addParameter("Certificate", DSValueType.STRING, null).setEditor("textarea");
237+
act.setResultType(ResultType.VALUES);
238+
act.addValueResult("Result", DSValueType.STRING);
219239
return act;
220240
}
221241

222-
private void importPrimaryCert(DSMap parameters) {
242+
private String importPrimaryCert(DSMap parameters) {
223243
String certStr = parameters.getString("Certificate");
224244
try {
225-
KeyToolUtil.importPrimaryCert(getKeystorePath(), certStr, getCertFilePass());
245+
return KeyToolUtil.importPrimaryCert(getKeystorePath(), certStr, getCertFilePass());
226246
} catch (IOException e) {
227247
DSException.throwRuntime(e);
248+
return null;
228249
}
229250
}
230251

@@ -237,10 +258,12 @@ public void prepareParameter(DSInfo info, DSMap parameter) {
237258

238259
@Override
239260
public ActionResult invoke(DSInfo info, ActionInvocation invocation) {
240-
((SysCertService) info.getParent()).keytoolGenkey();
241-
return null;
261+
String result = ((SysCertService) info.getParent()).keytoolGenkey();
262+
return new DSActionValues(info.getAction()).addResult(DSString.valueOf(result));
242263
}
243264
};
265+
act.setResultType(ResultType.VALUES);
266+
act.addValueResult("Result", DSValueType.STRING);
244267
return act;
245268
}
246269

@@ -275,15 +298,17 @@ public void prepareParameter(DSInfo info, DSMap parameter) {
275298

276299
@Override
277300
public ActionResult invoke(DSInfo info, ActionInvocation invocation) {
278-
((SysCertService) info.getParent()).deleteKSEntry();
279-
return null;
301+
String result = ((SysCertService) info.getParent()).deleteKSEntry();
302+
return new DSActionValues(info.getAction()).addResult(DSString.valueOf(result));
280303
}
281304
};
305+
act.setResultType(ResultType.VALUES);
306+
act.addValueResult("Result", DSValueType.STRING);
282307
return act;
283308
}
284309

285-
private void deleteKSEntry() {
286-
KeyToolUtil.deleteEntry(getKeystorePath(), getCertFilePass());
310+
private String deleteKSEntry() {
311+
return KeyToolUtil.deleteEntry(getKeystorePath(), getCertFilePass());
287312
}
288313

289314
private String getCertFilePass() {
@@ -298,19 +323,66 @@ private String getKeystorePath() {
298323
/**
299324
* Executes the java keytool to generate a new self signed cert.
300325
*/
301-
private void keytoolGenkey() {
302-
KeyToolUtil.generateSelfSigned(getKeystorePath(), getCertFilePass());
326+
private String keytoolGenkey() {
327+
return KeyToolUtil.generateSelfSigned(getKeystorePath(), getCertFilePass());
328+
}
329+
330+
private boolean isKeytoolAvailable() {
331+
String result = KeyToolUtil.help();
332+
return result != null && !result.isEmpty();
303333
}
304334

305335
@Override
306336
public void onStarted() {
307337
inst = this;
308338
AnonymousTrustFactory.init(this);
309-
String keystore = this.keystorePath.getElement().toString();
339+
String keystore = getKeystorePath();
310340
File f = new File(keystore);
311-
if (!f.exists()) {
312-
keytoolGenkey();
341+
if (isKeytoolAvailable()) {
342+
if (!f.exists()) {
343+
keytoolGenkey();
344+
}
345+
} else {
346+
info("Keytool not available. Disabling keytool functionality and attempting to use existing keystore");
347+
if (!f.exists()) {
348+
InputStream inpStream = null;
349+
FileOutputStream outStream = null;
350+
try {
351+
inpStream = SysCertService.class.getResourceAsStream(DEFAULT_CERTFILE);
352+
if (inpStream != null) {
353+
int readBytes;
354+
byte[] buffer = new byte[4096];
355+
outStream = new FileOutputStream(f);
356+
while ((readBytes = inpStream.read(buffer)) > 0) {
357+
outStream.write(buffer, 0, readBytes);
358+
}
359+
}
360+
} catch (Exception e) {
361+
debug("", e);
362+
} finally {
363+
try {
364+
if (inpStream != null) {
365+
inpStream.close();
366+
}
367+
if (outStream != null) {
368+
outStream.close();
369+
}
370+
} catch (Exception e) {
371+
debug("", e);
372+
}
373+
}
374+
if (!f.exists()) {
375+
error("Existing keystore not found and new one could not be generated");
376+
}
377+
}
378+
generateCsr.setHidden(true);
379+
importCaCert.setHidden(true);
380+
importPrimaryCert.setHidden(true);
381+
generateSSCert.setHidden(true);
382+
getKSEntry.setHidden(true);
383+
deleteKSEntry.setHidden(true);
313384
}
385+
314386
try {
315387
System.setProperty("javax.net.ssl.keyStore", keystore);
316388
System.setProperty("javax.net.ssl.keyStoreType",
@@ -321,6 +393,18 @@ public void onStarted() {
321393
}
322394
HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);
323395
}
396+
397+
@Override
398+
protected void onChildChanged(DSInfo info) {
399+
if (info == keystorePath) {
400+
System.setProperty("javax.net.ssl.keyStore", getKeystorePath());
401+
} else if (info == keystoreType) {
402+
System.setProperty("javax.net.ssl.keyStoreType",
403+
keystoreType.getElement().toString());
404+
} else if (info == keystorePass) {
405+
System.setProperty("javax.net.ssl.keyStorePassword", getCertFilePass());
406+
}
407+
}
324408

325409
public boolean isInTrustStore(X509Certificate cert) {
326410
return getLocalTruststore().containsCertificate(cert);
Binary file not shown.

0 commit comments

Comments
 (0)