Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
e5f6d16
begin implementing basic quarantine/local trust store
d-shapiro Jul 24, 2018
f9a7075
bugfix
d-shapiro Jul 24, 2018
dba39c4
work on making certificate verification more correct
d-shapiro Jul 25, 2018
e9a00cf
check CRLs when verifying a cert; add action that generates a CSR
d-shapiro Jul 25, 2018
2bd9840
add code that generates a self-signed certificate (without keytool)
d-shapiro Jul 26, 2018
3195766
Refactor to not require bouncycastle, add actions for importing certs
d-shapiro Jul 27, 2018
ce3ebbe
change certificate name to contain timestamp instead of hashcode
d-shapiro Jul 27, 2018
86fe455
fix bugs, add more keytool actions
d-shapiro Jul 30, 2018
ca18d0a
begin implementing basic quarantine/local trust store
d-shapiro Jul 24, 2018
74176d9
bugfix
d-shapiro Jul 24, 2018
9b4ea1d
work on making certificate verification more correct
d-shapiro Jul 25, 2018
6d077e6
check CRLs when verifying a cert; add action that generates a CSR
d-shapiro Jul 25, 2018
cf5b5b4
add code that generates a self-signed certificate (without keytool)
d-shapiro Jul 26, 2018
7035b29
Refactor to not require bouncycastle, add actions for importing certs
d-shapiro Jul 27, 2018
7b90523
change certificate name to contain timestamp instead of hashcode
d-shapiro Jul 27, 2018
69f7295
fix bugs, add more keytool actions
d-shapiro Jul 30, 2018
902d241
Merge branch 'daniel-certs' of https://github.com/iot-dsa-v2/sdk-dsli…
d-shapiro Jul 31, 2018
54066f3
add option to enable or disable hostname verification
d-shapiro Aug 7, 2018
9b4fe02
Merge pull request #62 from iot-dsa-v2/develop
d-shapiro Aug 8, 2018
529101d
only configure WebSocket hostname verifier for wss urls
d-shapiro Aug 9, 2018
9936ace
implement hostname whitelist and blacklist
d-shapiro Aug 11, 2018
1f911da
implement removal of hostname from whitelist via enum option
d-shapiro Aug 13, 2018
67b28b6
cleanup
d-shapiro Aug 14, 2018
3e4833c
remove commented-out imports
d-shapiro Aug 28, 2018
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
1 change: 1 addition & 0 deletions dslink-core/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/bin/
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
package org.iot.dsa.dslink.websocket;

import com.acuity.iot.dsa.dslink.sys.cert.SysCertManager;
import com.acuity.iot.dsa.dslink.transport.BufferedBinaryTransport;
import com.acuity.iot.dsa.dslink.transport.DSTransport;
import java.io.IOException;
import java.net.URI;
import java.nio.ByteBuffer;
import javax.websocket.*;
import org.glassfish.tyrus.client.ClientManager;
import org.glassfish.tyrus.client.ClientProperties;
import org.glassfish.tyrus.client.SslContextConfigurator;
import org.glassfish.tyrus.client.SslEngineConfigurator;
import org.iot.dsa.util.DSException;

/**
Expand Down Expand Up @@ -97,7 +101,13 @@ public DSTransport open() {
}
client.setDefaultMaxBinaryMessageBufferSize(64 * 1024);
client.setDefaultMaxTextMessageBufferSize(64 * 1024);
client.connectToServer(this, new URI(getConnectionUrl()));
URI connUri = new URI(getConnectionUrl());
if ("wss".equalsIgnoreCase(connUri.getScheme())) {
SslEngineConfigurator sslEngineConfigurator = new SslEngineConfigurator(new SslContextConfigurator());
sslEngineConfigurator.setHostnameVerifier(SysCertManager.getInstance().getHostnameVerifier());
client.getProperties().put(ClientProperties.SSL_ENGINE_CONFIGURATOR, sslEngineConfigurator);
}
client.connectToServer(this, connUri);
debug(debug() ? "Transport open" : null);
} catch (Exception x) {
DSException.throwRuntime(x);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.acuity.iot.dsa.dslink.io.DSCharBuffer;
import com.acuity.iot.dsa.dslink.io.DSIoException;
import com.acuity.iot.dsa.dslink.sys.cert.SysCertManager;
import com.acuity.iot.dsa.dslink.transport.DSTextTransport;
import com.acuity.iot.dsa.dslink.transport.DSTransport;
import java.io.IOException;
Expand All @@ -18,6 +19,9 @@
import javax.websocket.RemoteEndpoint;
import javax.websocket.Session;
import org.glassfish.tyrus.client.ClientManager;
import org.glassfish.tyrus.client.ClientProperties;
import org.glassfish.tyrus.client.SslContextConfigurator;
import org.glassfish.tyrus.client.SslEngineConfigurator;
import org.iot.dsa.util.DSException;

/**
Expand Down Expand Up @@ -149,7 +153,13 @@ public DSTransport open() {
}
client.setDefaultMaxBinaryMessageBufferSize(64 * 1024);
client.setDefaultMaxTextMessageBufferSize(64 * 1024);
client.connectToServer(this, new URI(getConnectionUrl()));
URI connUri = new URI(getConnectionUrl());
if ("wss".equalsIgnoreCase(connUri.getScheme())) {
SslEngineConfigurator sslEngineConfigurator = new SslEngineConfigurator(new SslContextConfigurator());
sslEngineConfigurator.setHostnameVerifier(SysCertManager.getInstance().getHostnameVerifier());
client.getProperties().put(ClientProperties.SSL_ENGINE_CONFIGURATOR, sslEngineConfigurator);
}
client.connectToServer(this, connUri);
} catch (Exception x) {
DSException.throwRuntime(x);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
import org.iot.dsa.node.action.DSAction;
import org.iot.dsa.time.DSTime;

/**
* @author Daniel Shapiro
* @author Aaron Hansen
*/
public class SysBackupService extends DSNode implements Runnable {

static final String ENABLED = "Enabled";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
package com.acuity.iot.dsa.dslink.sys.cert;

import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Provider;
import java.security.Security;
import java.security.cert.CertificateException;
import java.security.cert.PKIXCertPathBuilderResult;
import java.security.cert.TrustAnchor;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.net.ssl.*;

/**
* Adds support for self signed SSL. If anonymous is not allowed
* falls back to the default Java trust manager.
*
* @author Aaron Hansen
* @author Daniel Shapiro
*/
public class AnonymousTrustFactory extends TrustManagerFactorySpi {

Expand Down Expand Up @@ -114,8 +122,13 @@ public void checkClientTrusted(X509Certificate[] chain, String authType)
return;
}
if (defaultX509Mgr != null) {
defaultX509Mgr.checkClientTrusted(chain, authType);
try {
defaultX509Mgr.checkClientTrusted(chain, authType);
return;
} catch (CertificateException e) {
}
}
checkLocally(chain, authType);
}

@Override
Expand All @@ -125,7 +138,43 @@ public void checkServerTrusted(X509Certificate[] chain, String authType)
return;
}
if (defaultX509Mgr != null) {
defaultX509Mgr.checkServerTrusted(chain, authType);
try {
defaultX509Mgr.checkServerTrusted(chain, authType);
return;
} catch (CertificateException e) {
}
}
checkLocally(chain, authType);
}

private void checkLocally(X509Certificate[] chain, String authType) throws CertificateException {
Set<X509Certificate> chainAsSet = new HashSet<X509Certificate>();
Collections.addAll(chainAsSet, chain);
X509Certificate anchorCert;
try {
if (CertificateVerifier.isSelfSigned(chain[0])) {
anchorCert = chain[0];
} else {
PKIXCertPathBuilderResult result = CertificateVerifier.verifyCertificate(chain[0], chainAsSet);
TrustAnchor anchor = result.getTrustAnchor();
anchorCert = anchor.getTrustedCert();
}

if (anchorCert == null) {
throw new CertificateException();
}

if (!certManager.isInTrustStore(anchorCert)) {
certManager.addToQuarantine(anchorCert);
throw new CertificateException();
}

} catch (CertificateVerificationException e1) {
throw new CertificateException();
} catch (NoSuchAlgorithmException e) {
throw new CertificateException();
} catch (NoSuchProviderException e) {
throw new CertificateException();
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.acuity.iot.dsa.dslink.sys.cert;

import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.util.Base64;
import java.util.Base64.Encoder;
import org.iot.dsa.node.DSIObject;
import org.iot.dsa.node.DSNode;
import org.iot.dsa.time.DSTime;

/**
* @author Daniel Shapiro
*/
public class CertCollection extends DSNode {

public void addCertificate(X509Certificate cert) throws CertificateEncodingException {
String name = certToName(cert);
addCertificate(name, encodeCertificate(cert));
}

public void addCertificate(String name, String cert) {
put(name, new CertNode().updateValue(cert));
}

public boolean containsCertificate(X509Certificate cert) {
DSIObject obj = get(certToName(cert));
String certStr;
try {
certStr = encodeCertificate(cert);
} catch (CertificateEncodingException e) {
warn(e);
return false;
}
return obj != null && obj instanceof CertNode && certStr.equals(((CertNode) obj).toElement().toString());
}

public static String certToName(X509Certificate cert) {
return DSTime.encodeForFiles(DSTime.getCalendar(System.currentTimeMillis()), new StringBuilder(cert.getIssuerX500Principal().getName())).toString();
}

public static String encodeCertificate(X509Certificate cert) throws CertificateEncodingException {
Encoder encoder = Base64.getEncoder();
return encoder.encodeToString(cert.getEncoded());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package com.acuity.iot.dsa.dslink.sys.cert;

import org.iot.dsa.node.DSInfo;
import org.iot.dsa.node.DSString;
import org.iot.dsa.node.DSValueNode;
import org.iot.dsa.node.action.ActionInvocation;
import org.iot.dsa.node.action.ActionResult;
import org.iot.dsa.node.action.DSAction;

/**
* @author Daniel Shapiro
*/
public class CertNode extends DSValueNode {

private static final String VALUE = "value";
private static final String ALLOW = "Allow";
private static final String REMOVE = "Remove";

private DSInfo value = getInfo(VALUE);
private DSInfo allow = getInfo(ALLOW);
private DSInfo remove = getInfo(REMOVE);

private SysCertManager certManager;

@Override
protected void declareDefaults() {
super.declareDefaults();
declareDefault(VALUE, DSString.valueOf("")).setHidden(true).setReadOnly(true);
declareDefault(ALLOW, DSAction.DEFAULT);
declareDefault(REMOVE, DSAction.DEFAULT);
}

public CertNode updateValue(String newVal) {
put(VALUE, newVal);
return this;
}

@Override
public DSInfo getValueChild() {
return value;
}

@Override
public ActionResult onInvoke(DSInfo action, ActionInvocation invocation) {
if (action == remove) {
remove();
} else if (action == allow) {
allow();
} else {
super.onInvoke(action, invocation);
}
return null;
}

private void remove() {
getParent().remove(getInfo());
}

private void allow() {
getCertManager().allow(getInfo());
}

public SysCertManager getCertManager() {
if (certManager == null) {
certManager = (SysCertManager) getAncestor(SysCertManager.class);
}
return certManager;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.acuity.iot.dsa.dslink.sys.cert;

/**
* This class wraps an exception that could be thrown during
* the certificate verification process.
*
* @author Svetlin Nakov
*/
public class CertificateVerificationException extends Exception {
private static final long serialVersionUID = 1L;

public CertificateVerificationException(String message, Throwable cause) {
super(message, cause);
}

public CertificateVerificationException(String message) {
super(message);
}
}
Loading