Skip to content

Commit 8405cd9

Browse files
authored
0.35.0
Certificate Service
2 parents 8f7c18d + b77ff71 commit 8405cd9

File tree

20 files changed

+903
-49
lines changed

20 files changed

+903
-49
lines changed

.gitignore

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,30 @@
11
# Tooling
22
**.classpath
33
**.idea
4+
**.iml
45
**.metadata
56
**.project
67
**.settings
7-
**eclipseBin
8+
**/eclipseBin
89

910
# Build artifacts
11+
.gradle
1012
**.class
11-
**.iml
12-
**build
13-
**classes
14-
**libJar
15-
**out
16-
**target
17-
**/.gradle
18-
**javadoc
19-
**repository
13+
**/build
14+
**/classes
15+
**/libJar
16+
**/out
17+
**/target
2018

2119
# Misc
2220
**.bak
23-
**.old
2421
**.log
22+
**.old
2523
**.DS_Store
2624

2725
# Runtime files
2826
**.jks
2927
**.key
30-
**db
3128
**nodes.json
3229
**nodes*.zip
3330
**test.json

build.gradle

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ subprojects {
44
apply plugin: 'maven'
55

66
group 'org.iot-dsa'
7-
version '0.34.0'
7+
version '0.35.0'
88

99
sourceCompatibility = 1.6
1010
targetCompatibility = 1.6
@@ -25,6 +25,6 @@ subprojects {
2525
}
2626
}
2727

28-
task wrapper(type: Wrapper) {
29-
gradleVersion = '4.9'
28+
wrapper {
29+
gradleVersion = '4.10'
3030
}

dslink-v2-websocket/src/main/java/org/iot/dsa/dslink/websocket/WsBinaryTransport.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
package org.iot.dsa.dslink.websocket;
22

3+
import com.acuity.iot.dsa.dslink.sys.cert.SysCertManager;
34
import com.acuity.iot.dsa.dslink.transport.BufferedBinaryTransport;
45
import com.acuity.iot.dsa.dslink.transport.DSTransport;
56
import java.io.IOException;
67
import java.net.URI;
78
import java.nio.ByteBuffer;
89
import javax.websocket.*;
910
import org.glassfish.tyrus.client.ClientManager;
11+
import org.glassfish.tyrus.client.ClientProperties;
12+
import org.glassfish.tyrus.client.SslContextConfigurator;
13+
import org.glassfish.tyrus.client.SslEngineConfigurator;
1014
import org.iot.dsa.util.DSException;
1115

1216
/**
@@ -97,7 +101,13 @@ public DSTransport open() {
97101
}
98102
client.setDefaultMaxBinaryMessageBufferSize(64 * 1024);
99103
client.setDefaultMaxTextMessageBufferSize(64 * 1024);
100-
client.connectToServer(this, new URI(getConnectionUrl()));
104+
URI connUri = new URI(getConnectionUrl());
105+
if ("wss".equalsIgnoreCase(connUri.getScheme())) {
106+
SslEngineConfigurator sslEngineConfigurator = new SslEngineConfigurator(new SslContextConfigurator());
107+
sslEngineConfigurator.setHostnameVerifier(SysCertManager.getInstance().getHostnameVerifier());
108+
client.getProperties().put(ClientProperties.SSL_ENGINE_CONFIGURATOR, sslEngineConfigurator);
109+
}
110+
client.connectToServer(this, connUri);
101111
debug(debug() ? "Transport open" : null);
102112
} catch (Exception x) {
103113
DSException.throwRuntime(x);

dslink-v2-websocket/src/main/java/org/iot/dsa/dslink/websocket/WsTextTransport.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.acuity.iot.dsa.dslink.io.DSCharBuffer;
44
import com.acuity.iot.dsa.dslink.io.DSIoException;
5+
import com.acuity.iot.dsa.dslink.sys.cert.SysCertManager;
56
import com.acuity.iot.dsa.dslink.transport.DSTextTransport;
67
import com.acuity.iot.dsa.dslink.transport.DSTransport;
78
import java.io.IOException;
@@ -18,6 +19,9 @@
1819
import javax.websocket.RemoteEndpoint;
1920
import javax.websocket.Session;
2021
import org.glassfish.tyrus.client.ClientManager;
22+
import org.glassfish.tyrus.client.ClientProperties;
23+
import org.glassfish.tyrus.client.SslContextConfigurator;
24+
import org.glassfish.tyrus.client.SslEngineConfigurator;
2125
import org.iot.dsa.util.DSException;
2226

2327
/**
@@ -149,7 +153,13 @@ public DSTransport open() {
149153
}
150154
client.setDefaultMaxBinaryMessageBufferSize(64 * 1024);
151155
client.setDefaultMaxTextMessageBufferSize(64 * 1024);
152-
client.connectToServer(this, new URI(getConnectionUrl()));
156+
URI connUri = new URI(getConnectionUrl());
157+
if ("wss".equalsIgnoreCase(connUri.getScheme())) {
158+
SslEngineConfigurator sslEngineConfigurator = new SslEngineConfigurator(new SslContextConfigurator());
159+
sslEngineConfigurator.setHostnameVerifier(SysCertManager.getInstance().getHostnameVerifier());
160+
client.getProperties().put(ClientProperties.SSL_ENGINE_CONFIGURATOR, sslEngineConfigurator);
161+
}
162+
client.connectToServer(this, connUri);
153163
} catch (Exception x) {
154164
DSException.throwRuntime(x);
155165
}

dslink-v2/src/main/java/com/acuity/iot/dsa/dslink/protocol/v1/DS1LinkConnection.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,11 @@ public DSIWriter getWriter() {
6868
}
6969

7070
public void updateSalt(String salt) {
71-
connectionInit.updateSalt(salt);
71+
if ((salt == null) || salt.equals("1234")) {
72+
connectionInit = null;
73+
} else {
74+
connectionInit.updateSalt(salt);
75+
}
7276
}
7377

7478
///////////////////////////////////////////////////////////////////////////
@@ -152,6 +156,7 @@ protected void onConnect() {
152156
connOk();
153157
} catch (Exception x) {
154158
connDown(DSException.makeMessage(x));
159+
connectionInit = null;
155160
}
156161
}
157162

dslink-v2/src/main/java/com/acuity/iot/dsa/dslink/sys/backup/SysBackupService.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@
2525
import org.iot.dsa.node.action.DSAction;
2626
import org.iot.dsa.time.DSTime;
2727

28+
/**
29+
* @author Daniel Shapiro
30+
* @author Aaron Hansen
31+
*/
2832
public class SysBackupService extends DSNode implements Runnable {
2933

3034
static final String ENABLED = "Enabled";

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

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,27 @@
11
package com.acuity.iot.dsa.dslink.sys.cert;
22

33
import java.security.KeyStore;
4+
import java.security.NoSuchAlgorithmException;
5+
import java.security.NoSuchProviderException;
46
import java.security.Provider;
57
import java.security.Security;
68
import java.security.cert.CertificateException;
9+
import java.security.cert.PKIXCertPathBuilderResult;
10+
import java.security.cert.TrustAnchor;
711
import java.security.cert.X509Certificate;
812
import java.util.Arrays;
13+
import java.util.Collections;
14+
import java.util.HashSet;
915
import java.util.List;
16+
import java.util.Set;
1017
import javax.net.ssl.*;
1118

1219
/**
1320
* Adds support for self signed SSL. If anonymous is not allowed
1421
* falls back to the default Java trust manager.
1522
*
1623
* @author Aaron Hansen
24+
* @author Daniel Shapiro
1725
*/
1826
public class AnonymousTrustFactory extends TrustManagerFactorySpi {
1927

@@ -114,8 +122,13 @@ public void checkClientTrusted(X509Certificate[] chain, String authType)
114122
return;
115123
}
116124
if (defaultX509Mgr != null) {
117-
defaultX509Mgr.checkClientTrusted(chain, authType);
125+
try {
126+
defaultX509Mgr.checkClientTrusted(chain, authType);
127+
return;
128+
} catch (CertificateException e) {
129+
}
118130
}
131+
checkLocally(chain, authType);
119132
}
120133

121134
@Override
@@ -125,7 +138,43 @@ public void checkServerTrusted(X509Certificate[] chain, String authType)
125138
return;
126139
}
127140
if (defaultX509Mgr != null) {
128-
defaultX509Mgr.checkServerTrusted(chain, authType);
141+
try {
142+
defaultX509Mgr.checkServerTrusted(chain, authType);
143+
return;
144+
} catch (CertificateException e) {
145+
}
146+
}
147+
checkLocally(chain, authType);
148+
}
149+
150+
private void checkLocally(X509Certificate[] chain, String authType) throws CertificateException {
151+
Set<X509Certificate> chainAsSet = new HashSet<X509Certificate>();
152+
Collections.addAll(chainAsSet, chain);
153+
X509Certificate anchorCert;
154+
try {
155+
if (CertificateVerifier.isSelfSigned(chain[0])) {
156+
anchorCert = chain[0];
157+
} else {
158+
PKIXCertPathBuilderResult result = CertificateVerifier.verifyCertificate(chain[0], chainAsSet);
159+
TrustAnchor anchor = result.getTrustAnchor();
160+
anchorCert = anchor.getTrustedCert();
161+
}
162+
163+
if (anchorCert == null) {
164+
throw new CertificateException();
165+
}
166+
167+
if (!certManager.isInTrustStore(anchorCert)) {
168+
certManager.addToQuarantine(anchorCert);
169+
throw new CertificateException();
170+
}
171+
172+
} catch (CertificateVerificationException e1) {
173+
throw new CertificateException();
174+
} catch (NoSuchAlgorithmException e) {
175+
throw new CertificateException();
176+
} catch (NoSuchProviderException e) {
177+
throw new CertificateException();
129178
}
130179
}
131180

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package com.acuity.iot.dsa.dslink.sys.cert;
2+
3+
import java.security.cert.CertificateEncodingException;
4+
import java.security.cert.X509Certificate;
5+
import java.util.Base64;
6+
import java.util.Base64.Encoder;
7+
import org.iot.dsa.node.DSIObject;
8+
import org.iot.dsa.node.DSNode;
9+
import org.iot.dsa.time.DSTime;
10+
11+
/**
12+
* @author Daniel Shapiro
13+
*/
14+
public class CertCollection extends DSNode {
15+
16+
public void addCertificate(X509Certificate cert) throws CertificateEncodingException {
17+
String name = certToName(cert);
18+
addCertificate(name, encodeCertificate(cert));
19+
}
20+
21+
public void addCertificate(String name, String cert) {
22+
put(name, new CertNode().updateValue(cert));
23+
}
24+
25+
public boolean containsCertificate(X509Certificate cert) {
26+
DSIObject obj = get(certToName(cert));
27+
String certStr;
28+
try {
29+
certStr = encodeCertificate(cert);
30+
} catch (CertificateEncodingException e) {
31+
warn(e);
32+
return false;
33+
}
34+
return obj != null && obj instanceof CertNode && certStr.equals(((CertNode) obj).toElement().toString());
35+
}
36+
37+
public static String certToName(X509Certificate cert) {
38+
return DSTime.encodeForFiles(DSTime.getCalendar(System.currentTimeMillis()), new StringBuilder(cert.getIssuerX500Principal().getName())).toString();
39+
}
40+
41+
public static String encodeCertificate(X509Certificate cert) throws CertificateEncodingException {
42+
Encoder encoder = Base64.getEncoder();
43+
return encoder.encodeToString(cert.getEncoded());
44+
}
45+
46+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package com.acuity.iot.dsa.dslink.sys.cert;
2+
3+
import org.iot.dsa.node.DSInfo;
4+
import org.iot.dsa.node.DSString;
5+
import org.iot.dsa.node.DSValueNode;
6+
import org.iot.dsa.node.action.ActionInvocation;
7+
import org.iot.dsa.node.action.ActionResult;
8+
import org.iot.dsa.node.action.DSAction;
9+
10+
/**
11+
* @author Daniel Shapiro
12+
*/
13+
public class CertNode extends DSValueNode {
14+
15+
private static final String VALUE = "value";
16+
private static final String ALLOW = "Allow";
17+
private static final String REMOVE = "Remove";
18+
19+
private DSInfo value = getInfo(VALUE);
20+
private DSInfo allow = getInfo(ALLOW);
21+
private DSInfo remove = getInfo(REMOVE);
22+
23+
private SysCertManager certManager;
24+
25+
@Override
26+
protected void declareDefaults() {
27+
super.declareDefaults();
28+
declareDefault(VALUE, DSString.valueOf("")).setHidden(true).setReadOnly(true);
29+
declareDefault(ALLOW, DSAction.DEFAULT);
30+
declareDefault(REMOVE, DSAction.DEFAULT);
31+
}
32+
33+
public CertNode updateValue(String newVal) {
34+
put(VALUE, newVal);
35+
return this;
36+
}
37+
38+
@Override
39+
public DSInfo getValueChild() {
40+
return value;
41+
}
42+
43+
@Override
44+
public ActionResult onInvoke(DSInfo action, ActionInvocation invocation) {
45+
if (action == remove) {
46+
remove();
47+
} else if (action == allow) {
48+
allow();
49+
} else {
50+
super.onInvoke(action, invocation);
51+
}
52+
return null;
53+
}
54+
55+
private void remove() {
56+
getParent().remove(getInfo());
57+
}
58+
59+
private void allow() {
60+
getCertManager().allow(getInfo());
61+
}
62+
63+
public SysCertManager getCertManager() {
64+
if (certManager == null) {
65+
certManager = (SysCertManager) getAncestor(SysCertManager.class);
66+
}
67+
return certManager;
68+
}
69+
70+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.acuity.iot.dsa.dslink.sys.cert;
2+
3+
/**
4+
* This class wraps an exception that could be thrown during
5+
* the certificate verification process.
6+
*
7+
* @author Svetlin Nakov
8+
*/
9+
public class CertificateVerificationException extends Exception {
10+
private static final long serialVersionUID = 1L;
11+
12+
public CertificateVerificationException(String message, Throwable cause) {
13+
super(message, cause);
14+
}
15+
16+
public CertificateVerificationException(String message) {
17+
super(message);
18+
}
19+
}

0 commit comments

Comments
 (0)