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

Add Support of RPK at Client side 2 #546

Closed
wants to merge 2 commits into from
Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,20 @@

import java.io.IOException;
import java.net.InetSocketAddress;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.Collection;

import org.eclipse.californium.core.CoapServer;
import org.eclipse.californium.core.network.CoapEndpoint;
import org.eclipse.californium.core.network.Endpoint;
import org.eclipse.californium.core.network.config.NetworkConfig;
import org.eclipse.californium.elements.auth.RawPublicKeyIdentity;
import org.eclipse.californium.scandium.DTLSConnector;
import org.eclipse.californium.scandium.config.DtlsConnectorConfig;
import org.eclipse.californium.scandium.config.DtlsConnectorConfig.Builder;
import org.eclipse.californium.scandium.dtls.pskstore.StaticPskStore;
import org.eclipse.californium.scandium.dtls.rpkstore.TrustedRpkStore;
import org.eclipse.leshan.SecurityMode;
import org.eclipse.leshan.client.servers.EndpointsManager;
import org.eclipse.leshan.client.servers.Server;
Expand Down Expand Up @@ -76,9 +79,30 @@ public synchronized Identity createEndpoint(ServerInfo serverInfo) {
if (serverInfo.secureMode == SecurityMode.PSK) {
StaticPskStore staticPskStore = new StaticPskStore(serverInfo.pskId, serverInfo.pskKey);
newBuilder.setPskStore(staticPskStore);
} else if (serverInfo.secureMode == SecurityMode.RPK) {
// set identity
newBuilder.setIdentity(serverInfo.privateKey, serverInfo.publicKey);
// set RPK truststore
final PublicKey expectedKey = serverInfo.serverPublicKey;
newBuilder.setRpkTrustStore(new TrustedRpkStore() {
@Override
public boolean isTrusted(RawPublicKeyIdentity id) {
PublicKey receivedKey = id.getKey();
if (receivedKey == null) {
LOG.warn("The server public key is null {}", id);
return false;
}
if (!receivedKey.equals(expectedKey)) {
LOG.debug(
"Server public key received does match with the expected one.\nReceived: {}\nExpected: {}",
receivedKey, expectedKey);
return false;
}
return true;
}
});
}
// TODO add support for RPK and X509

// TODO add support X509
if (endpointFactory != null) {
currentEndpoint = endpointFactory.createSecuredEndpoint(newBuilder.build(), coapConfig, null);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.PrivateKey;
import java.security.PublicKey;

import org.eclipse.leshan.LwM2m;
import org.eclipse.leshan.SecurityMode;
Expand All @@ -31,9 +33,14 @@ public class ServerInfo {
public long serverId;
public URI serverUri;
public SecurityMode secureMode;

public String pskId;
public byte[] pskKey;

public PublicKey publicKey;
public PrivateKey privateKey;
public PublicKey serverPublicKey;

public InetSocketAddress getAddress() {
return getAddress(serverUri);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@

import java.net.URI;
import java.net.URISyntaxException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Map;

import org.eclipse.leshan.SecurityMode;
Expand Down Expand Up @@ -64,11 +71,14 @@ public static ServersInfo getInfo(Map<Integer, LwM2mObjectEnabler> objectEnabler
else
info.serverId = 0;
info.serverUri = new URI((String) security.getResource(SEC_SERVER_URI).getValue());
info.secureMode = SecurityMode
.fromCode((long) security.getResource(SEC_SECURITY_MODE).getValue());
info.secureMode = getSecurityMode(security);
if (info.secureMode == SecurityMode.PSK) {
info.pskId = new String((byte[]) security.getResource(SEC_PUBKEY_IDENTITY).getValue());
info.pskKey = (byte[]) security.getResource(SEC_SECRET_KEY).getValue();
info.pskId = getPskIdentity(security);
info.pskKey = getPskKey(security);
} else if (info.secureMode == SecurityMode.RPK) {
info.publicKey = getPublicKey(security);
info.privateKey = getPrivateKey(security);
info.serverPublicKey = getServerPublicKey(security);
}
infos.bootstrap = info;
}
Expand All @@ -77,10 +87,14 @@ public static ServersInfo getInfo(Map<Integer, LwM2mObjectEnabler> objectEnabler
DmServerInfo info = new DmServerInfo();
info.serverUri = new URI((String) security.getResource(SEC_SERVER_URI).getValue());
info.serverId = (long) security.getResource(SEC_SERVER_ID).getValue();
info.secureMode = SecurityMode.fromCode((long) security.getResource(SEC_SECURITY_MODE).getValue());
info.secureMode = getSecurityMode(security);
if (info.secureMode == SecurityMode.PSK) {
info.pskId = new String((byte[]) security.getResource(SEC_PUBKEY_IDENTITY).getValue());
info.pskKey = (byte[]) security.getResource(SEC_SECRET_KEY).getValue();
info.pskId = getPskIdentity(security);
info.pskKey = getPskKey(security);
} else if (info.secureMode == SecurityMode.RPK) {
info.publicKey = getPublicKey(security);
info.privateKey = getPrivateKey(security);
info.serverPublicKey = getServerPublicKey(security);
}
// search corresponding device management server
for (LwM2mObjectInstance server : servers.getInstances().values()) {
Expand Down Expand Up @@ -115,4 +129,62 @@ public static ServerInfo getBootstrapServerInfo(Map<Integer, LwM2mObjectEnabler>

return info.bootstrap;
}

public static SecurityMode getSecurityMode(LwM2mObjectInstance securityInstance) {
return SecurityMode.fromCode((long) securityInstance.getResource(SEC_SECURITY_MODE).getValue());
}

public static String getPskIdentity(LwM2mObjectInstance securityInstance) {
byte[] pubKey = (byte[]) securityInstance.getResource(SEC_PUBKEY_IDENTITY).getValue();
return new String(pubKey);
}

public static byte[] getPskKey(LwM2mObjectInstance securityInstance) {
return (byte[]) securityInstance.getResource(SEC_SECRET_KEY).getValue();
}

private static PublicKey getPublicKey(LwM2mObjectInstance securityInstance) {
byte[] encodedKey = (byte[]) securityInstance.getResource(SEC_PUBKEY_IDENTITY).getValue();
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encodedKey);
String algorithm = "EC";
try {
KeyFactory kf = KeyFactory.getInstance(algorithm);
return kf.generatePublic(keySpec);
} catch (NoSuchAlgorithmException e) {
LOG.debug("Failed to instantiate key factory for algorithm " + algorithm, e);
} catch (InvalidKeySpecException e) {
LOG.debug("Failed to decode RFC7250 public key with algorithm " + algorithm, e);
}
return null;
}

private static PrivateKey getPrivateKey(LwM2mObjectInstance securityInstance) {
byte[] encodedKey = (byte[]) securityInstance.getResource(SEC_SECRET_KEY).getValue();
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedKey);
String algorithm = "EC";
try {
KeyFactory kf = KeyFactory.getInstance(algorithm);
return kf.generatePrivate(keySpec);
} catch (NoSuchAlgorithmException e) {
LOG.warn("Failed to instantiate key factory for algorithm " + algorithm, e);
} catch (InvalidKeySpecException e) {
LOG.warn("Failed to decode RFC5958 private key with algorithm " + algorithm, e);
}
return null;
}

private static PublicKey getServerPublicKey(LwM2mObjectInstance securityInstance) {
byte[] encodedKey = (byte[]) securityInstance.getResource(SEC_SERVER_PUBKEY).getValue();
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encodedKey);
String algorithm = "EC";
try {
KeyFactory kf = KeyFactory.getInstance(algorithm);
return kf.generatePublic(keySpec);
} catch (NoSuchAlgorithmException e) {
LOG.debug("Failed to instantiate key factory for algorithm " + algorithm, e);
} catch (InvalidKeySpecException e) {
LOG.debug("Failed to decode RFC7250 public key with algorithm " + algorithm, e);
}
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,67 +39,66 @@
import org.eclipse.leshan.server.security.BootstrapSecurityStore;
import org.eclipse.leshan.server.security.EditableSecurityStore;
import org.eclipse.leshan.server.security.SecurityInfo;
import org.eclipse.leshan.util.Hex;

/**
* Helper for running a server and executing a client against it.
*
*/
public class BootstrapIntegrationTestHelper extends IntegrationTestHelper {

public static final String GOOD_PSK_ID = "Good_Client_identity";
public static final byte[] GOOD_PSK_KEY = Hex.decodeHex("73656372657450534b".toCharArray());
public static final byte[] BAD_PSK_KEY = Hex.decodeHex("010101010101010101".toCharArray());
public class BootstrapIntegrationTestHelper extends SecureIntegrationTestHelper {

LeshanBootstrapServer bootstrapServer;

public void createBootstrapServer(BootstrapSecurityStore securityStore) {

BootstrapStore bsStore = new BootstrapStore() {
@Override
public BootstrapConfig getBootstrap(String endpoint, Identity deviceIdentity) {

BootstrapConfig bsConfig = new BootstrapConfig();

// security for BS server
ServerSecurity bsSecurity = new ServerSecurity();
bsSecurity.serverId = 1111;
bsSecurity.bootstrapServer = true;
bsSecurity.uri = "coap://" + bootstrapServer.getUnsecuredAddress().getHostString() + ":"
+ bootstrapServer.getUnsecuredAddress().getPort();
bsSecurity.securityMode = SecurityMode.NO_SEC;
bsConfig.security.put(0, bsSecurity);

// security for DM server
ServerSecurity dmSecurity = new ServerSecurity();
dmSecurity.uri = "coap://" + server.getUnsecuredAddress().getHostString() + ":"
+ server.getUnsecuredAddress().getPort();
dmSecurity.serverId = 2222;
dmSecurity.securityMode = SecurityMode.NO_SEC;
bsConfig.security.put(1, dmSecurity);

// DM server
ServerConfig dmConfig = new ServerConfig();
dmConfig.shortId = 2222;
bsConfig.servers.put(0, dmConfig);

return bsConfig;
}
};
public void createBootstrapServer(BootstrapSecurityStore securityStore, BootstrapStore bootstrapStore) {
if (bootstrapStore == null) {
bootstrapStore = new BootstrapStore() {
@Override
public BootstrapConfig getBootstrap(String endpoint, Identity deviceIdentity) {
BootstrapConfig bsConfig = new BootstrapConfig();

// security for BS server
ServerSecurity bsSecurity = new ServerSecurity();
bsSecurity.serverId = 1111;
bsSecurity.bootstrapServer = true;
bsSecurity.uri = "coap://" + bootstrapServer.getUnsecuredAddress().getHostString() + ":"
+ bootstrapServer.getUnsecuredAddress().getPort();
bsSecurity.securityMode = SecurityMode.NO_SEC;
bsConfig.security.put(0, bsSecurity);

// security for DM server
ServerSecurity dmSecurity = new ServerSecurity();
dmSecurity.uri = "coap://" + server.getUnsecuredAddress().getHostString() + ":"
+ server.getUnsecuredAddress().getPort();
dmSecurity.serverId = 2222;
dmSecurity.securityMode = SecurityMode.NO_SEC;
bsConfig.security.put(1, dmSecurity);

// DM server
ServerConfig dmConfig = new ServerConfig();
dmConfig.shortId = 2222;
bsConfig.servers.put(0, dmConfig);

return bsConfig;
}
};
}

if (securityStore == null) {
securityStore = dummyBsSecurityStore();
}

LeshanBootstrapServerBuilder builder = new LeshanBootstrapServerBuilder();
builder.setConfigStore(bsStore);
builder.setConfigStore(bootstrapStore);
builder.setSecurityStore(securityStore);
builder.setLocalAddress(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
builder.setLocalSecureAddress(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));

bootstrapServer = builder.build();
}

public void createBootstrapServer(BootstrapSecurityStore securityStore) {
createBootstrapServer(securityStore, null);
}

@Override
public void createClient() {
// Create Security Object (with bootstrap server only)
Expand Down Expand Up @@ -183,6 +182,81 @@ public List<SecurityInfo> getAllByEndpoint(String endpoint) {
};
}

public BootstrapStore pskBootstrapStore() {
return new BootstrapStore() {

@Override
public BootstrapConfig getBootstrap(String endpoint, Identity deviceIdentity) {

BootstrapConfig bsConfig = new BootstrapConfig();

// security for BS server
ServerSecurity bsSecurity = new ServerSecurity();
bsSecurity.serverId = 1111;
bsSecurity.bootstrapServer = true;
bsSecurity.uri = "coap://" + bootstrapServer.getUnsecuredAddress().getHostString() + ":"
+ bootstrapServer.getUnsecuredAddress().getPort();
bsSecurity.securityMode = SecurityMode.NO_SEC;
bsConfig.security.put(0, bsSecurity);

// security for DM server
ServerSecurity dmSecurity = new ServerSecurity();
dmSecurity.uri = "coaps://" + server.getUnsecuredAddress().getHostString() + ":"
+ server.getSecuredAddress().getPort();
dmSecurity.serverId = 2222;
dmSecurity.securityMode = SecurityMode.PSK;
dmSecurity.publicKeyOrId = GOOD_PSK_ID.getBytes();
dmSecurity.secretKey = GOOD_PSK_KEY;
bsConfig.security.put(1, dmSecurity);

// DM server
ServerConfig dmConfig = new ServerConfig();
dmConfig.shortId = 2222;
bsConfig.servers.put(0, dmConfig);

return bsConfig;
}
};
}

public BootstrapStore rpkBootstrapStore() {
return new BootstrapStore() {

@Override
public BootstrapConfig getBootstrap(String endpoint, Identity deviceIdentity) {

BootstrapConfig bsConfig = new BootstrapConfig();

// security for BS server
ServerSecurity bsSecurity = new ServerSecurity();
bsSecurity.serverId = 1111;
bsSecurity.bootstrapServer = true;
bsSecurity.uri = "coap://" + bootstrapServer.getUnsecuredAddress().getHostString() + ":"
+ bootstrapServer.getUnsecuredAddress().getPort();
bsSecurity.securityMode = SecurityMode.NO_SEC;
bsConfig.security.put(0, bsSecurity);

// security for DM server
ServerSecurity dmSecurity = new ServerSecurity();
dmSecurity.uri = "coaps://" + server.getUnsecuredAddress().getHostString() + ":"
+ server.getSecuredAddress().getPort();
dmSecurity.serverId = 2222;
dmSecurity.securityMode = SecurityMode.RPK;
dmSecurity.publicKeyOrId = clientPublicKey.getEncoded();
dmSecurity.secretKey = clientPrivateKey.getEncoded();
dmSecurity.serverPublicKey = serverPublicKey.getEncoded();
bsConfig.security.put(1, dmSecurity);

// DM server
ServerConfig dmConfig = new ServerConfig();
dmConfig.shortId = 2222;
bsConfig.servers.put(0, dmConfig);

return bsConfig;
}
};
}

@Override
public void dispose() {
super.dispose();
Expand Down
Loading