From 708e734ff714e0baabc5ea2a6722d3c974a51dde Mon Sep 17 00:00:00 2001 From: rikard-sics Date: Thu, 12 Sep 2019 11:56:32 +0200 Subject: [PATCH 01/18] Generate OSCORE object and use it for endpoint creation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Code to implement the points listed here: https://github.com/eclipse/leshan/pull/718#issuecomment-521316754 The OSCORE object is generated and filled in the Leshan client demo. It will then be used to create a ServerInfo object using the ServersInfoExtractor. Next the ServerInfo is used in the CaliforniumEndpointsManager to generate endpoints towards servers that OSCORE should be used with. See also issue regarding OSCORE client integration: https://github.com/eclipse/leshan/issues/726 Signed-off-by: Rikard Höglund --- .../impl/CaliforniumEndpointsManager.java | 49 ++++- leshan-client-core/pom.xml | 7 + .../eclipse/leshan/client/object/Oscore.java | 176 +++++++++++++----- .../leshan/client/object/Security.java | 9 + .../leshan/client/servers/ServerInfo.java | 11 ++ .../client/servers/ServersInfoExtractor.java | 72 +++++++ leshan-client-demo/pom.xml | 3 +- .../leshan/client/demo/LeshanClientDemo.java | 40 +--- leshan-core-cf/pom.xml | 7 + .../core/californium/EndpointFactory.java | 4 + .../main/java/org/eclipse/leshan/LwM2mId.java | 11 ++ .../java/org/eclipse/leshan/SecurityMode.java | 3 +- .../leshan/core/model/ObjectLoader.java | 4 +- .../resources/models/LWM2M_OSCORE-V1_0.xml | 128 +++++++++++++ .../tests/SecureIntegrationTestHelper.java | 11 ++ 15 files changed, 443 insertions(+), 92 deletions(-) create mode 100644 leshan-core/src/main/resources/models/LWM2M_OSCORE-V1_0.xml diff --git a/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/impl/CaliforniumEndpointsManager.java b/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/impl/CaliforniumEndpointsManager.java index 622e797524..e4f57825ee 100644 --- a/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/impl/CaliforniumEndpointsManager.java +++ b/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/impl/CaliforniumEndpointsManager.java @@ -12,11 +12,16 @@ * * Contributors: * Sierra Wireless - initial API and implementation + * Rikard Höglund (RISE SICS) - Additions to support OSCORE *******************************************************************************/ package org.eclipse.leshan.client.californium.impl; import java.io.IOException; +import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.UnknownHostException; import java.security.PublicKey; import java.security.cert.Certificate; import java.security.cert.X509Certificate; @@ -29,6 +34,9 @@ import org.eclipse.californium.core.network.config.NetworkConfig; import org.eclipse.californium.elements.Connector; import org.eclipse.californium.elements.auth.RawPublicKeyIdentity; +import org.eclipse.californium.oscore.HashMapCtxDB; +import org.eclipse.californium.oscore.OSCoreCtx; +import org.eclipse.californium.oscore.OSException; import org.eclipse.californium.scandium.DTLSConnector; import org.eclipse.californium.scandium.config.DtlsConnectorConfig.Builder; import org.eclipse.californium.scandium.dtls.AlertMessage; @@ -113,6 +121,31 @@ public boolean isTrusted(RawPublicKeyIdentity id) { } }); serverIdentity = Identity.rpk(serverInfo.getAddress(), expectedKey); + } else if (serverInfo.secureMode == SecurityMode.OSCORE) { + System.out.println("Adding OSCORE CTX " + serverInfo.getFullUri().toASCIIString()); + HashMapCtxDB db = HashMapCtxDB.getInstance(); //TODO: Do not use singleton here but give it to endpoint builder (for Cf-M16) + try { + OSCoreCtx ctx = new OSCoreCtx(serverInfo.masterSecret, true, serverInfo.aeadAlgorithm, serverInfo.senderId, serverInfo.recipientId, serverInfo.hkdfAlgorithm, 32, serverInfo.masterSalt, serverInfo.idContext); + db.addContext(serverInfo.getFullUri().toASCIIString(), ctx); + + // Also add the context by the IP of the server since requests may use that + String serverIP = InetAddress.getByName(serverInfo.getFullUri().getHost()).getHostAddress(); + db.addContext("coap://" + serverIP, ctx); + + } catch (OSException | UnknownHostException e) { + LOG.error("Failed to generate OSCORE context information"); + return null; + } + + if (endpointFactory != null) { + currentEndpoint = endpointFactory.createOSCoreEndpoint(localAddress, coapConfig, null, db); + } else { + CoapEndpoint.Builder builder = new CoapEndpoint.Builder(); + builder.setInetSocketAddress(localAddress); + builder.setNetworkConfig(coapConfig); + currentEndpoint = builder.build(); + } + serverIdentity = Identity.unsecure(serverInfo.getAddress()); //TODO: FIX? } else if (serverInfo.secureMode == SecurityMode.X509) { // set identity newBuilder.setIdentity(serverInfo.privateKey, new Certificate[] { serverInfo.clientCertificate }); @@ -153,13 +186,15 @@ public X509Certificate[] getAcceptedIssuers() { } else { throw new RuntimeException("Unable to create connector : unsupported security mode"); } - if (endpointFactory != null) { - currentEndpoint = endpointFactory.createSecuredEndpoint(newBuilder.build(), coapConfig, null); - } else { - CoapEndpoint.Builder builder = new CoapEndpoint.Builder(); - builder.setConnector(new DTLSConnector(newBuilder.build())); - builder.setNetworkConfig(coapConfig); - currentEndpoint = builder.build(); + if (currentEndpoint == null) { + if (endpointFactory != null) { + currentEndpoint = endpointFactory.createSecuredEndpoint(newBuilder.build(), coapConfig, null); + } else { + CoapEndpoint.Builder builder = new CoapEndpoint.Builder(); + builder.setConnector(new DTLSConnector(newBuilder.build())); + builder.setNetworkConfig(coapConfig); + currentEndpoint = builder.build(); + } } } else { if (endpointFactory != null) { diff --git a/leshan-client-core/pom.xml b/leshan-client-core/pom.xml index 6f68310e58..d717d34427 100644 --- a/leshan-client-core/pom.xml +++ b/leshan-client-core/pom.xml @@ -15,6 +15,7 @@ Contributors: Sierra Wireless - initial API and implementation Zebra Technologies - initial API and implementation Eurotech - initial API and implementation + Rikard Höglund (RISE SICS) - Additions to support OSCORE --> @@ -34,6 +35,12 @@ Contributors: org.eclipse.leshan leshan-core + + + org.eclipse.californium + cf-oscore + ${californium.version} + diff --git a/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Oscore.java b/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Oscore.java index bd583fa63e..32c7d9e92b 100644 --- a/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Oscore.java +++ b/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Oscore.java @@ -12,14 +12,26 @@ * * Contributors: * Sierra Wireless - initial API and implementation - * Rikard Höglund (RISE SICS) + * Rikard Höglund (RISE SICS) - Additions to support OSCORE * *******************************************************************************/ package org.eclipse.leshan.client.object; +import static org.eclipse.leshan.LwM2mId.OSCORE_Master_Secret; +import static org.eclipse.leshan.LwM2mId.OSCORE_Sender_ID; +import static org.eclipse.leshan.LwM2mId.OSCORE_Recipient_ID; +import static org.eclipse.leshan.LwM2mId.OSCORE_AEAD_Algorithm; +import static org.eclipse.leshan.LwM2mId.OSCORE_HMAC_Algorithm; +import static org.eclipse.leshan.LwM2mId.OSCORE_Master_Salt; + +import java.util.Arrays; +import java.util.List; + import org.eclipse.leshan.client.request.ServerIdentity; import org.eclipse.leshan.client.resource.BaseInstanceEnabler; import org.eclipse.leshan.client.resource.LwM2mInstanceEnabler; +import org.eclipse.leshan.core.model.ObjectModel; +import org.eclipse.leshan.core.model.ResourceModel.Type; import org.eclipse.leshan.core.node.LwM2mResource; import org.eclipse.leshan.core.response.ReadResponse; import org.eclipse.leshan.core.response.WriteResponse; @@ -32,78 +44,140 @@ public class Oscore extends BaseInstanceEnabler { private static final Logger LOG = LoggerFactory.getLogger(Security.class); + + private final static List supportedResources = Arrays.asList(OSCORE_Master_Secret, + OSCORE_Sender_ID, OSCORE_Recipient_ID, OSCORE_AEAD_Algorithm, OSCORE_HMAC_Algorithm, + OSCORE_Master_Salt); - private byte[] masterSecret; + private String masterSecret; private String senderId; private String recipientId; private int aeadAlgorithm; - private int hmacAlgorithm; + private int hkdfAlgorithm; + private String masterSalt; + private String idContext; public Oscore() { } - public Oscore(byte[] masterSecret, String senderId, String recipientId, int aeadAlgorithm, int hmacAlgorithm) { - super(); - this.masterSecret = masterSecret.clone(); + /** + * Returns a new OSCORE instance. + */ + public static Oscore set(String masterSecret, String senderId, String recipientId, int aeadAlgorithm, int hkdfAlgorithm, String masterSalt) { + return new Oscore(masterSecret, senderId, recipientId, aeadAlgorithm, hkdfAlgorithm, masterSalt); + } + + /** + * Returns a new OSCORE instance (less parameters and using default values). + */ + public static Oscore set(String masterSecret, String senderId, String recipientId) { + int defaultAeadAlgorithm = 10; //AES_CCM_16_64_128 + int defaultHmacAlgorithm = -10; //HKDF_HMAC_SHA_256 + + return new Oscore(masterSecret, senderId, recipientId, defaultAeadAlgorithm, defaultHmacAlgorithm, ""); + } + + + public Oscore(String masterSecret, String senderId, String recipientId, int aeadAlgorithm, int hkdfAlgorithm, String masterSalt) { + this.masterSecret = masterSecret; this.senderId = senderId; this.recipientId = recipientId; this.aeadAlgorithm = aeadAlgorithm; - this.hmacAlgorithm = hmacAlgorithm; + this.hkdfAlgorithm = hkdfAlgorithm; + this.masterSalt = masterSalt; + this.idContext = ""; } @Override public WriteResponse write(ServerIdentity identity, int resourceId, LwM2mResource value) { LOG.debug("Write on resource {}: {}", resourceId, value); - // extend - return WriteResponse.notFound(); - } - - @Override - public ReadResponse read(ServerIdentity identity, int resourceid) { - LOG.debug("Read on resource {}", resourceid); - // extend - return ReadResponse.notFound(); - } - - public byte[] getMasterSecret() { - return masterSecret; - } - public void setMasterSecret(byte[] masterSecret) { - this.masterSecret = masterSecret; - } + // restricted to BS server? + + switch (resourceId) { + + case OSCORE_Master_Secret: + if (value.getType() != Type.STRING) { + return WriteResponse.badRequest("invalid type"); + } + masterSecret = (String) value.getValue(); + return WriteResponse.success(); + + case OSCORE_Sender_ID: + if (value.getType() != Type.STRING) { + return WriteResponse.badRequest("invalid type"); + } + senderId = (String) value.getValue(); + return WriteResponse.success(); + + case OSCORE_Recipient_ID: + if (value.getType() != Type.STRING) { + return WriteResponse.badRequest("invalid type"); + } + recipientId = (String) value.getValue(); + return WriteResponse.success(); + + case OSCORE_AEAD_Algorithm: + if (value.getType() != Type.INTEGER) { + return WriteResponse.badRequest("invalid type"); + } + aeadAlgorithm = ((Long) value.getValue()).intValue(); + return WriteResponse.success(); + + case OSCORE_HMAC_Algorithm: + if (value.getType() != Type.INTEGER) { + return WriteResponse.badRequest("invalid type"); + } + hkdfAlgorithm = ((Long) value.getValue()).intValue(); + return WriteResponse.success(); + + case OSCORE_Master_Salt: + if (value.getType() != Type.STRING) { + return WriteResponse.badRequest("invalid type"); + } + masterSalt = (String) value.getValue(); + return WriteResponse.success(); + + + default: + return super.write(identity, resourceId, value); + } - public String getSenderId() { - return senderId; } - public void setSenderId(String senderId) { - this.senderId = senderId; - } - - public String getRecipientId() { - return recipientId; - } - - public void setRecipientId(String recipientId) { - this.recipientId = recipientId; - } - - public int getAeadAlgorithm() { - return aeadAlgorithm; - } - - public void setAeadAlgorithm(int aeadAlgorithm) { - this.aeadAlgorithm = aeadAlgorithm; - } - - public int getHmacAlgorithm() { - return hmacAlgorithm; + @Override + public ReadResponse read(ServerIdentity identity, int resourceid) { + // only accessible for internal read? + + switch (resourceid) { + + case OSCORE_Master_Secret: + return ReadResponse.success(resourceid, masterSecret); + + case OSCORE_Sender_ID: + return ReadResponse.success(resourceid, senderId); + + case OSCORE_Recipient_ID: + return ReadResponse.success(resourceid, recipientId); + + case OSCORE_AEAD_Algorithm: + return ReadResponse.success(resourceid, aeadAlgorithm); + + case OSCORE_HMAC_Algorithm: + return ReadResponse.success(resourceid, hkdfAlgorithm); + + case OSCORE_Master_Salt: + return ReadResponse.success(resourceid, masterSalt); + + default: + return super.read(identity, resourceid); + } } - public void setHmacAlgorithm(int hmacAlgorithm) { - this.hmacAlgorithm = hmacAlgorithm; + @Override + public List getAvailableResourceIds(ObjectModel model) { + return supportedResources; } - + } diff --git a/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Security.java b/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Security.java index 82f1a5c1f0..e1f33c0172 100644 --- a/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Security.java +++ b/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Security.java @@ -12,6 +12,7 @@ * * Contributors: * Sierra Wireless - initial API and implementation + * Rikard Höglund (RISE SICS) - Additions to support OSCORE *******************************************************************************/ package org.eclipse.leshan.client.object; @@ -108,6 +109,14 @@ public static Security noSec(String serverUri, int shortServerId) { return new Security(serverUri, false, SecurityMode.NO_SEC.code, new byte[0], new byte[0], new byte[0], shortServerId); } + + /** + * Returns a new security instance (OSCORE) for a device management server. + */ + public static Security secOSCore(String serverUri, int shortServerId) { + return new Security(serverUri, false, SecurityMode.OSCORE.code, new byte[0], new byte[0], new byte[0], + shortServerId); + } /** * Returns a new security instance (PSK) for a device management server. diff --git a/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServerInfo.java b/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServerInfo.java index 98846ac9f9..a9dd9f54d3 100644 --- a/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServerInfo.java +++ b/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServerInfo.java @@ -12,6 +12,7 @@ * * Contributors: * Sierra Wireless - initial API and implementation + * Rikard Höglund (RISE SICS) - Additions to support OSCORE *******************************************************************************/ package org.eclipse.leshan.client.servers; @@ -22,6 +23,7 @@ import java.security.PublicKey; import java.security.cert.Certificate; +import org.eclipse.californium.cose.AlgorithmID; import org.eclipse.leshan.LwM2m; import org.eclipse.leshan.SecurityMode; import org.slf4j.Logger; @@ -45,6 +47,15 @@ public class ServerInfo { public Certificate serverCertificate; public PrivateKey privateKey; + + //OSCORE parameters + public byte[] masterSecret; + public byte[] senderId; + public byte[] recipientId; + public AlgorithmID aeadAlgorithm; + public AlgorithmID hkdfAlgorithm; + public byte[] masterSalt; + public byte[] idContext; public InetSocketAddress getAddress() { return getAddress(serverUri); diff --git a/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServersInfoExtractor.java b/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServersInfoExtractor.java index 0f8cb47040..9104ce7593 100644 --- a/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServersInfoExtractor.java +++ b/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServersInfoExtractor.java @@ -13,6 +13,7 @@ * Contributors: * Sierra Wireless - initial API and implementation * Achim Kraus (Bosch Software Innovations GmbH) - use ServerIdentity.SYSTEM + * Rikard Höglund (RISE SICS) - Additions to support OSCORE *******************************************************************************/ package org.eclipse.leshan.client.servers; @@ -35,6 +36,10 @@ import java.security.spec.X509EncodedKeySpec; import java.util.Map; +import org.eclipse.californium.core.Utils; +import org.eclipse.californium.cose.AlgorithmID; +import org.eclipse.californium.cose.CoseException; +import org.eclipse.californium.elements.util.StringUtil; import org.eclipse.leshan.LwM2mId; import org.eclipse.leshan.SecurityMode; import org.eclipse.leshan.client.request.ServerIdentity; @@ -46,9 +51,12 @@ import org.eclipse.leshan.core.request.BindingMode; import org.eclipse.leshan.core.request.ReadRequest; import org.eclipse.leshan.core.response.ReadResponse; +import org.eclipse.leshan.util.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.upokecenter.cbor.CBORObject; + /** * Extract from LwM2m tree servers information like server uri, security mode, ... */ @@ -58,6 +66,7 @@ public class ServersInfoExtractor { public static ServersInfo getInfo(Map objectEnablers) { LwM2mObjectEnabler securityEnabler = objectEnablers.get(SECURITY); LwM2mObjectEnabler serverEnabler = objectEnablers.get(SERVER); + LwM2mObjectEnabler oscoreEnabler = objectEnablers.get(OSCORE); if (securityEnabler == null || serverEnabler == null) return null; @@ -65,6 +74,7 @@ public static ServersInfo getInfo(Map objectEnabler ServersInfo infos = new ServersInfo(); LwM2mObject securities = (LwM2mObject) securityEnabler.read(SYSTEM, new ReadRequest(SECURITY)).getContent(); LwM2mObject servers = (LwM2mObject) serverEnabler.read(SYSTEM, new ReadRequest(SERVER)).getContent(); + LwM2mObject oscores = (LwM2mObject) oscoreEnabler.read(SYSTEM, new ReadRequest(OSCORE)).getContent(); for (LwM2mObjectInstance security : securities.getInstances().values()) { try { @@ -112,6 +122,16 @@ public static ServersInfo getInfo(Map objectEnabler info.clientCertificate = getClientCertificate(security); info.serverCertificate = getServerCertificate(security); info.privateKey = getPrivateKey(security); + } else if (info.secureMode == SecurityMode.OSCORE) { + //FIXME: Need proper way to find correct oscore instance corresponding to this security instance + LwM2mObjectInstance oscoreInstance = (LwM2mObjectInstance)oscores.getInstances().values().toArray()[0]; + info.masterSecret = getMasterSecret(oscoreInstance); + info.senderId = getSenderId(oscoreInstance); + info.recipientId = getRecipientId(oscoreInstance); + info.aeadAlgorithm = getAeadAlgorithm(oscoreInstance); + info.hkdfAlgorithm = getHkdfAlgorithm(oscoreInstance); + info.masterSalt = getMasterSalt(oscoreInstance); + info.idContext = getIdContext(oscoreInstance); } // search corresponding device management server for (LwM2mObjectInstance server : servers.getInstances().values()) { @@ -240,4 +260,56 @@ public static boolean isBootstrapServer(LwM2mInstanceEnabler instance) { LwM2mResource isBootstrap = (LwM2mResource) response.getContent(); return (Boolean) isBootstrap.getValue(); } + + //OSCORE related methods below + + public static byte[] getMasterSecret(LwM2mObjectInstance oscoreInstance) { + return StringUtil.hex2ByteArray((String)oscoreInstance.getResource(OSCORE_Master_Secret).getValue()); + } + + public static byte[] getSenderId(LwM2mObjectInstance oscoreInstance) { + return StringUtil.hex2ByteArray((String)oscoreInstance.getResource(OSCORE_Sender_ID).getValue()); + } + + public static byte[] getRecipientId(LwM2mObjectInstance oscoreInstance) { + return StringUtil.hex2ByteArray((String)oscoreInstance.getResource(OSCORE_Recipient_ID).getValue()); + } + + public static AlgorithmID getAeadAlgorithm(LwM2mObjectInstance oscoreInstance) { + AlgorithmID aeadAlg = null; + + try { + aeadAlg = AlgorithmID.FromCBOR(CBORObject.FromObject((Long)oscoreInstance.getResource(OSCORE_AEAD_Algorithm).getValue())); + } catch (CoseException e) { + LOG.error("Failed to decode OSCORE AEAD algorithm"); + } + + return aeadAlg; + } + + public static AlgorithmID getHkdfAlgorithm(LwM2mObjectInstance oscoreInstance) { + AlgorithmID hkdfAlg = null; + + try { + hkdfAlg = AlgorithmID.FromCBOR(CBORObject.FromObject((Long)oscoreInstance.getResource(OSCORE_HMAC_Algorithm).getValue())); + } catch (CoseException e) { + LOG.error("Failed to decode OSCORE HMAC algorithm"); + } + + return hkdfAlg; + } + + public static byte[] getMasterSalt(LwM2mObjectInstance oscoreInstance) { + String value = (String)oscoreInstance.getResource(OSCORE_Master_Salt).getValue(); + + if(value.equals("")) { + return null; + } else { + return StringUtil.hex2ByteArray(value); + } + } + + public static byte[] getIdContext(LwM2mObjectInstance oscoreInstance) { + return null; + } } diff --git a/leshan-client-demo/pom.xml b/leshan-client-demo/pom.xml index 8523a584ae..4337dff792 100644 --- a/leshan-client-demo/pom.xml +++ b/leshan-client-demo/pom.xml @@ -13,6 +13,7 @@ and the Eclipse Distribution License is available at Contributors: Zebra Technologies - initial API and implementation + Rikard Höglund (RISE SICS) - Additions to support OSCORE --> @@ -40,7 +41,7 @@ Contributors: org.eclipse.californium cf-oscore ${californium.version} - + diff --git a/leshan-client-demo/src/main/java/org/eclipse/leshan/client/demo/LeshanClientDemo.java b/leshan-client-demo/src/main/java/org/eclipse/leshan/client/demo/LeshanClientDemo.java index 342049da5a..0f9d24b5f6 100644 --- a/leshan-client-demo/src/main/java/org/eclipse/leshan/client/demo/LeshanClientDemo.java +++ b/leshan-client-demo/src/main/java/org/eclipse/leshan/client/demo/LeshanClientDemo.java @@ -14,6 +14,7 @@ * Zebra Technologies - initial API and implementation * Sierra Wireless, - initial API and implementation * Bosch Software Innovations GmbH, - initial API and implementation + * Rikard Höglund (RISE SICS) - Additions to support OSCORE *******************************************************************************/ package org.eclipse.leshan.client.demo; @@ -49,6 +50,7 @@ import org.eclipse.leshan.LwM2m; import org.eclipse.leshan.client.californium.LeshanClient; import org.eclipse.leshan.client.californium.LeshanClientBuilder; +import org.eclipse.leshan.client.object.Oscore; import org.eclipse.leshan.client.object.Server; import org.eclipse.leshan.client.resource.LwM2mObjectEnabler; import org.eclipse.leshan.client.resource.ObjectsInitializer; @@ -309,47 +311,19 @@ public static void main(final String[] args) { return; } } - // Set up OSCORE Context when using OSCORE + // Set boolean controlling OSCORE usage boolean useOSCore = false; if (cl.hasOption("oscore")) { System.out.println("Using OSCORE"); useOSCore = true; - HashMapCtxDB db = HashMapCtxDB.getInstance(); - AlgorithmID alg = AlgorithmID.AES_CCM_16_64_128; - AlgorithmID kdf = AlgorithmID.HKDF_HMAC_SHA_256; - - byte[] master_secret = { 0x11, 0x22, 0x33, 0x44 }; - byte[] sid = new byte[] { (byte) 0xAA }; - byte[] rid = new byte[] { (byte) 0xBB }; - - // Add the OSCORE context associated to the URI of the server - OSCoreCtx ctx = null; - try { - ctx = new OSCoreCtx(master_secret, true, alg, sid, rid, kdf, 32, null, null); - db.addContext(serverURI, ctx); - } catch (OSException e) { - System.err.println("Failed to generate OSCORE Context"); - e.printStackTrace(); - } - - // Also add the context by the IP of the server since requests may use that - String serverIP = null; - try { - serverIP = InetAddress.getByName(new URI(serverURI).getHost()).getHostAddress(); - db.addContext("coap://" + serverIP, ctx); - } catch (UnknownHostException | URISyntaxException | OSException e) { - System.err.println("Failed to find Server IP"); - e.printStackTrace(); - } - OSCoreCoapStackFactory.useAsDefault(); } try { createAndStartClient(endpoint, localAddress, localPort, cl.hasOption("b"), serverURI, pskIdentity, pskKey, clientPrivateKey, clientPublicKey, serverPublicKey, clientCertificate, serverCertificate, latitude, - longitude, scaleFactor); + longitude, scaleFactor, useOSCore); } catch (Exception e) { System.err.println("Unable to create and start client ..."); e.printStackTrace(); @@ -360,7 +334,7 @@ public static void main(final String[] args) { public static void createAndStartClient(String endpoint, String localAddress, int localPort, boolean needBootstrap, String serverURI, byte[] pskIdentity, byte[] pskKey, PrivateKey clientPrivateKey, PublicKey clientPublicKey, PublicKey serverPublicKey, X509Certificate clientCertificate, X509Certificate serverCertificate, - Float latitude, Float longitude, float scaleFactor) throws CertificateEncodingException { + Float latitude, Float longitude, float scaleFactor, boolean useOSCore) throws CertificateEncodingException { locationInstance = new MyLocation(latitude, longitude, scaleFactor); @@ -398,6 +372,10 @@ public static void createAndStartClient(String endpoint, String localAddress, in initializer.setInstancesForObject(SECURITY, x509(serverURI, 123, clientCertificate.getEncoded(), clientPrivateKey.getEncoded(), serverCertificate.getEncoded())); initializer.setInstancesForObject(SERVER, new Server(123, 30, BindingMode.U, false)); + } else if (useOSCore) { + initializer.setInstancesForObject(SECURITY, secOSCore(serverURI, 123)); + initializer.setInstancesForObject(OSCORE, Oscore.set("11223344", "AA", "BB")); //Hardcoded values + initializer.setInstancesForObject(SERVER, new Server(123, 30, BindingMode.U, false)); } else { initializer.setInstancesForObject(SECURITY, noSec(serverURI, 123)); initializer.setInstancesForObject(SERVER, new Server(123, 30, BindingMode.U, false)); diff --git a/leshan-core-cf/pom.xml b/leshan-core-cf/pom.xml index ed54de5e57..8dc6bfed25 100644 --- a/leshan-core-cf/pom.xml +++ b/leshan-core-cf/pom.xml @@ -13,6 +13,7 @@ and the Eclipse Distribution License is available at Contributors: Sierra Wireless - initial API and implementation + Rikard Höglund (RISE SICS) - Additions to support OSCORE --> @@ -40,6 +41,12 @@ Contributors: org.eclipse.californium scandium + + + org.eclipse.californium + cf-oscore + ${californium.version} + diff --git a/leshan-core-cf/src/main/java/org/eclipse/leshan/core/californium/EndpointFactory.java b/leshan-core-cf/src/main/java/org/eclipse/leshan/core/californium/EndpointFactory.java index 3d5b67fec2..883709d1fc 100644 --- a/leshan-core-cf/src/main/java/org/eclipse/leshan/core/californium/EndpointFactory.java +++ b/leshan-core-cf/src/main/java/org/eclipse/leshan/core/californium/EndpointFactory.java @@ -12,6 +12,7 @@ * * Contributors: * Sierra Wireless - initial API and implementation + * Rikard Höglund (RISE SICS) - Additions to support OSCORE *******************************************************************************/ package org.eclipse.leshan.core.californium; @@ -20,6 +21,7 @@ import org.eclipse.californium.core.network.CoapEndpoint; import org.eclipse.californium.core.network.config.NetworkConfig; import org.eclipse.californium.core.observe.ObservationStore; +import org.eclipse.californium.oscore.HashMapCtxDB; import org.eclipse.californium.scandium.config.DtlsConnectorConfig; /** @@ -28,6 +30,8 @@ public interface EndpointFactory { CoapEndpoint createUnsecuredEndpoint(InetSocketAddress address, NetworkConfig coapConfig, ObservationStore store); + + CoapEndpoint createOSCoreEndpoint(InetSocketAddress address, NetworkConfig coapConfig, ObservationStore store, HashMapCtxDB db); CoapEndpoint createSecuredEndpoint(DtlsConnectorConfig dtlsConfig, NetworkConfig coapConfig, ObservationStore store); diff --git a/leshan-core/src/main/java/org/eclipse/leshan/LwM2mId.java b/leshan-core/src/main/java/org/eclipse/leshan/LwM2mId.java index 6b24cb9059..9d9ca8356f 100644 --- a/leshan-core/src/main/java/org/eclipse/leshan/LwM2mId.java +++ b/leshan-core/src/main/java/org/eclipse/leshan/LwM2mId.java @@ -12,6 +12,7 @@ * * Contributors: * Sierra Wireless - initial API and implementation + * Rikard Höglund (RISE SICS) - Additions to support OSCORE *******************************************************************************/ package org.eclipse.leshan; @@ -31,6 +32,7 @@ public interface LwM2mId { public static final int LOCATION = 6; public static final int CONNECTIVITY_STATISTICS = 7; public static final int SOFTWARE_MANAGEMENT = 9; + public static final int OSCORE = 21; /* SECURITY RESOURCES */ @@ -41,6 +43,15 @@ public interface LwM2mId { public static final int SEC_SERVER_PUBKEY = 4; public static final int SEC_SECRET_KEY = 5; public static final int SEC_SERVER_ID = 10; + + /* OSCORE RESOURCES */ + + public static final int OSCORE_Master_Secret = 0; + public static final int OSCORE_Sender_ID = 1; + public static final int OSCORE_Recipient_ID = 2; + public static final int OSCORE_AEAD_Algorithm = 3; + public static final int OSCORE_HMAC_Algorithm = 4; + public static final int OSCORE_Master_Salt = 5; /* SERVER RESOURCES */ diff --git a/leshan-core/src/main/java/org/eclipse/leshan/SecurityMode.java b/leshan-core/src/main/java/org/eclipse/leshan/SecurityMode.java index 26b1aa04ad..01d8d73d6e 100644 --- a/leshan-core/src/main/java/org/eclipse/leshan/SecurityMode.java +++ b/leshan-core/src/main/java/org/eclipse/leshan/SecurityMode.java @@ -12,6 +12,7 @@ * * Contributors: * Sierra Wireless - initial API and implementation + * Rikard Höglund (RISE SICS) - Additions to support OSCORE *******************************************************************************/ package org.eclipse.leshan; @@ -19,7 +20,7 @@ * The different DTLS security modes */ public enum SecurityMode { - PSK(0), RPK(1), X509(2), NO_SEC(3); + PSK(0), RPK(1), X509(2), NO_SEC(3), OSCORE(4); public final int code; diff --git a/leshan-core/src/main/java/org/eclipse/leshan/core/model/ObjectLoader.java b/leshan-core/src/main/java/org/eclipse/leshan/core/model/ObjectLoader.java index 51de4db6d3..0ca77059f7 100644 --- a/leshan-core/src/main/java/org/eclipse/leshan/core/model/ObjectLoader.java +++ b/leshan-core/src/main/java/org/eclipse/leshan/core/model/ObjectLoader.java @@ -12,6 +12,7 @@ * * Contributors: * Sierra Wireless - initial API and implementation + * Rikard Höglund (RISE SICS) - Additions to support OSCORE *******************************************************************************/ package org.eclipse.leshan.core.model; @@ -40,7 +41,8 @@ public class ObjectLoader { private static final String[] ddfpaths = new String[] { "LWM2M_Security-v1_0.xml", "LWM2M_Server-v1_0.xml", "LWM2M_Access_Control-v1_0.xml", "LWM2M_Device-v1_0.xml", "LWM2M_Connectivity_Monitoring-v1_0.xml", "LWM2M_Firmware_Update-v1_0.xml", - "LWM2M_Location-v1_0.xml", "LWM2M_Connectivity_Statistics-v1_0.xml" }; + "LWM2M_Location-v1_0.xml", "LWM2M_Connectivity_Statistics-v1_0.xml", + "LWM2M_OSCORE-V1_0.xml" }; /** * Load the default LWM2M objects diff --git a/leshan-core/src/main/resources/models/LWM2M_OSCORE-V1_0.xml b/leshan-core/src/main/resources/models/LWM2M_OSCORE-V1_0.xml new file mode 100644 index 0000000000..15a210da12 --- /dev/null +++ b/leshan-core/src/main/resources/models/LWM2M_OSCORE-V1_0.xml @@ -0,0 +1,128 @@ + + + + + + + LWM2M OSCORE + + 21 + urn:oma:lwm2m:oma:211.1 + 1.0Multiple + Optional + + OSCORE Master Secret + + Single + Mandatory + String + + + + + OSCORE Sender ID + + Single + Mandatory + String + + + + + OSCORE Recipient ID + + Single + Mandatory + String + + + + + OSCORE AEAD Algorithm + + Single + Optional + Integer + + + + + OSCORE HMAC Algorithm + + Single + Optional + Integer + + + + + OSCORE Master Salt + + Single + Optional + String + + + + + + + diff --git a/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/SecureIntegrationTestHelper.java b/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/SecureIntegrationTestHelper.java index 174cfc0501..1ca01ee866 100644 --- a/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/SecureIntegrationTestHelper.java +++ b/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/SecureIntegrationTestHelper.java @@ -12,6 +12,7 @@ * * Contributors: * Zebra Technologies - initial API and implementation + * Rikard Höglund (RISE SICS) - Additions to support OSCORE *******************************************************************************/ package org.eclipse.leshan.integration.tests; @@ -42,6 +43,7 @@ import org.eclipse.californium.core.network.CoapEndpoint; import org.eclipse.californium.core.network.config.NetworkConfig; import org.eclipse.californium.core.observe.ObservationStore; +import org.eclipse.californium.oscore.HashMapCtxDB; import org.eclipse.californium.scandium.DTLSConnector; import org.eclipse.californium.scandium.config.DtlsConnectorConfig; import org.eclipse.californium.scandium.config.DtlsConnectorConfig.Builder; @@ -228,6 +230,15 @@ public CoapEndpoint createSecuredEndpoint(DtlsConnectorConfig dtlsConfig, Networ builder.setNetworkConfig(coapConfig); return builder.build(); } + + @Override + public CoapEndpoint createOSCoreEndpoint(InetSocketAddress address, NetworkConfig coapConfig, + ObservationStore store, HashMapCtxDB db) { + CoapEndpoint.Builder builder = new CoapEndpoint.Builder(); + builder.setInetSocketAddress(address); + builder.setNetworkConfig(coapConfig); + return builder.build(); + } }); // create client; From 8fc7bfcdb67d219f712c5f2a1536a2d4c692e860 Mon Sep 17 00:00:00 2001 From: rikard-sics Date: Tue, 17 Sep 2019 16:38:11 +0200 Subject: [PATCH 02/18] Removed Californium dependencies from leshan-client-core MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rikard Höglund --- .../impl/CaliforniumEndpointsManager.java | 21 +++++- leshan-client-core/pom.xml | 6 -- .../leshan/client/servers/ServerInfo.java | 5 +- .../client/servers/ServersInfoExtractor.java | 75 +++++++++++-------- 4 files changed, 67 insertions(+), 40 deletions(-) diff --git a/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/impl/CaliforniumEndpointsManager.java b/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/impl/CaliforniumEndpointsManager.java index e4f57825ee..2334782886 100644 --- a/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/impl/CaliforniumEndpointsManager.java +++ b/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/impl/CaliforniumEndpointsManager.java @@ -32,6 +32,8 @@ 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.cose.AlgorithmID; +import org.eclipse.californium.cose.CoseException; import org.eclipse.californium.elements.Connector; import org.eclipse.californium.elements.auth.RawPublicKeyIdentity; import org.eclipse.californium.oscore.HashMapCtxDB; @@ -58,6 +60,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.upokecenter.cbor.CBORObject; + public class CaliforniumEndpointsManager implements EndpointsManager { private static final Logger LOG = LoggerFactory.getLogger(CaliforniumEndpointsManager.class); @@ -124,8 +128,23 @@ public boolean isTrusted(RawPublicKeyIdentity id) { } else if (serverInfo.secureMode == SecurityMode.OSCORE) { System.out.println("Adding OSCORE CTX " + serverInfo.getFullUri().toASCIIString()); HashMapCtxDB db = HashMapCtxDB.getInstance(); //TODO: Do not use singleton here but give it to endpoint builder (for Cf-M16) + + AlgorithmID hkdfAlg = null; try { - OSCoreCtx ctx = new OSCoreCtx(serverInfo.masterSecret, true, serverInfo.aeadAlgorithm, serverInfo.senderId, serverInfo.recipientId, serverInfo.hkdfAlgorithm, 32, serverInfo.masterSalt, serverInfo.idContext); + hkdfAlg = AlgorithmID.FromCBOR(CBORObject.FromObject(serverInfo.hkdfAlgorithm)); + } catch (CoseException e) { + LOG.error("Failed to decode OSCORE HMAC algorithm"); + } + + AlgorithmID aeadAlg = null; + try { + aeadAlg = AlgorithmID.FromCBOR(CBORObject.FromObject(serverInfo.aeadAlgorithm)); + } catch (CoseException e) { + LOG.error("Failed to decode OSCORE AEAD algorithm"); + } + + try { + OSCoreCtx ctx = new OSCoreCtx(serverInfo.masterSecret, true, aeadAlg, serverInfo.senderId, serverInfo.recipientId, hkdfAlg, 32, serverInfo.masterSalt, serverInfo.idContext); db.addContext(serverInfo.getFullUri().toASCIIString(), ctx); // Also add the context by the IP of the server since requests may use that diff --git a/leshan-client-core/pom.xml b/leshan-client-core/pom.xml index d717d34427..18419da1d6 100644 --- a/leshan-client-core/pom.xml +++ b/leshan-client-core/pom.xml @@ -35,12 +35,6 @@ Contributors: org.eclipse.leshan leshan-core - - - org.eclipse.californium - cf-oscore - ${californium.version} - diff --git a/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServerInfo.java b/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServerInfo.java index a9dd9f54d3..072db9d3af 100644 --- a/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServerInfo.java +++ b/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServerInfo.java @@ -23,7 +23,6 @@ import java.security.PublicKey; import java.security.cert.Certificate; -import org.eclipse.californium.cose.AlgorithmID; import org.eclipse.leshan.LwM2m; import org.eclipse.leshan.SecurityMode; import org.slf4j.Logger; @@ -52,8 +51,8 @@ public class ServerInfo { public byte[] masterSecret; public byte[] senderId; public byte[] recipientId; - public AlgorithmID aeadAlgorithm; - public AlgorithmID hkdfAlgorithm; + public long aeadAlgorithm; + public long hkdfAlgorithm; public byte[] masterSalt; public byte[] idContext; diff --git a/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServersInfoExtractor.java b/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServersInfoExtractor.java index 9104ce7593..ecb80b9391 100644 --- a/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServersInfoExtractor.java +++ b/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServersInfoExtractor.java @@ -36,10 +36,6 @@ import java.security.spec.X509EncodedKeySpec; import java.util.Map; -import org.eclipse.californium.core.Utils; -import org.eclipse.californium.cose.AlgorithmID; -import org.eclipse.californium.cose.CoseException; -import org.eclipse.californium.elements.util.StringUtil; import org.eclipse.leshan.LwM2mId; import org.eclipse.leshan.SecurityMode; import org.eclipse.leshan.client.request.ServerIdentity; @@ -55,8 +51,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.upokecenter.cbor.CBORObject; - /** * Extract from LwM2m tree servers information like server uri, security mode, ... */ @@ -264,39 +258,23 @@ public static boolean isBootstrapServer(LwM2mInstanceEnabler instance) { //OSCORE related methods below public static byte[] getMasterSecret(LwM2mObjectInstance oscoreInstance) { - return StringUtil.hex2ByteArray((String)oscoreInstance.getResource(OSCORE_Master_Secret).getValue()); + return hex2ByteArray((String)oscoreInstance.getResource(OSCORE_Master_Secret).getValue()); } public static byte[] getSenderId(LwM2mObjectInstance oscoreInstance) { - return StringUtil.hex2ByteArray((String)oscoreInstance.getResource(OSCORE_Sender_ID).getValue()); + return hex2ByteArray((String)oscoreInstance.getResource(OSCORE_Sender_ID).getValue()); } public static byte[] getRecipientId(LwM2mObjectInstance oscoreInstance) { - return StringUtil.hex2ByteArray((String)oscoreInstance.getResource(OSCORE_Recipient_ID).getValue()); + return hex2ByteArray((String)oscoreInstance.getResource(OSCORE_Recipient_ID).getValue()); } - public static AlgorithmID getAeadAlgorithm(LwM2mObjectInstance oscoreInstance) { - AlgorithmID aeadAlg = null; - - try { - aeadAlg = AlgorithmID.FromCBOR(CBORObject.FromObject((Long)oscoreInstance.getResource(OSCORE_AEAD_Algorithm).getValue())); - } catch (CoseException e) { - LOG.error("Failed to decode OSCORE AEAD algorithm"); - } - - return aeadAlg; + public static long getAeadAlgorithm(LwM2mObjectInstance oscoreInstance) { + return (long)oscoreInstance.getResource(OSCORE_AEAD_Algorithm).getValue(); } - public static AlgorithmID getHkdfAlgorithm(LwM2mObjectInstance oscoreInstance) { - AlgorithmID hkdfAlg = null; - - try { - hkdfAlg = AlgorithmID.FromCBOR(CBORObject.FromObject((Long)oscoreInstance.getResource(OSCORE_HMAC_Algorithm).getValue())); - } catch (CoseException e) { - LOG.error("Failed to decode OSCORE HMAC algorithm"); - } - - return hkdfAlg; + public static long getHkdfAlgorithm(LwM2mObjectInstance oscoreInstance) { + return (long)oscoreInstance.getResource(OSCORE_HMAC_Algorithm).getValue(); } public static byte[] getMasterSalt(LwM2mObjectInstance oscoreInstance) { @@ -305,11 +283,48 @@ public static byte[] getMasterSalt(LwM2mObjectInstance oscoreInstance) { if(value.equals("")) { return null; } else { - return StringUtil.hex2ByteArray(value); + return hex2ByteArray(value); } } public static byte[] getIdContext(LwM2mObjectInstance oscoreInstance) { return null; } + + /** + * Convert hexadecimal String into decoded byte array. + * From Californium StringUtil.java + * + * @param hex hexadecimal string. e.g. "4130010A" + * @return byte array with decoded hexadecimal input parameter. + * @throws IllegalArgumentException if the parameter length is odd or + * contains non hexadecimal characters. + * @see #byteArray2Hex(byte[]) + */ + public static byte[] hex2ByteArray(String hex) { + if (hex == null) { + return null; + } + int length = hex.length(); + if ((1 & length) != 0) { + throw new IllegalArgumentException("'" + hex + "' has odd length!"); + } + length /= 2; + byte[] result = new byte[length]; + for (int indexDest = 0, indexSrc = 0; indexDest < length; ++indexDest) { + int digit = Character.digit(hex.charAt(indexSrc), 16); + if (digit < 0) { + throw new IllegalArgumentException("'" + hex + "' digit " + indexSrc + " is not hexadecimal!"); + } + result[indexDest] = (byte) (digit << 4); + ++indexSrc; + digit = Character.digit(hex.charAt(indexSrc), 16); + if (digit < 0) { + throw new IllegalArgumentException("'" + hex + "' digit " + indexSrc + " is not hexadecimal!"); + } + result[indexDest] |= (byte) digit; + ++indexSrc; + } + return result; + } } From dc37bd9c5a597cb41ca91238edbfe76665b72c76 Mon Sep 17 00:00:00 2001 From: rikard-sics Date: Tue, 17 Sep 2019 20:48:39 +0200 Subject: [PATCH 03/18] Removed static initializers from Oscore class, instead use constructors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rikard Höglund --- .../eclipse/leshan/client/object/Oscore.java | 29 +++++++++---------- .../leshan/client/demo/LeshanClientDemo.java | 2 +- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Oscore.java b/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Oscore.java index 32c7d9e92b..e5c31dfe8e 100644 --- a/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Oscore.java +++ b/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Oscore.java @@ -62,23 +62,8 @@ public Oscore() { } /** - * Returns a new OSCORE instance. + * Default constructor. */ - public static Oscore set(String masterSecret, String senderId, String recipientId, int aeadAlgorithm, int hkdfAlgorithm, String masterSalt) { - return new Oscore(masterSecret, senderId, recipientId, aeadAlgorithm, hkdfAlgorithm, masterSalt); - } - - /** - * Returns a new OSCORE instance (less parameters and using default values). - */ - public static Oscore set(String masterSecret, String senderId, String recipientId) { - int defaultAeadAlgorithm = 10; //AES_CCM_16_64_128 - int defaultHmacAlgorithm = -10; //HKDF_HMAC_SHA_256 - - return new Oscore(masterSecret, senderId, recipientId, defaultAeadAlgorithm, defaultHmacAlgorithm, ""); - } - - public Oscore(String masterSecret, String senderId, String recipientId, int aeadAlgorithm, int hkdfAlgorithm, String masterSalt) { this.masterSecret = masterSecret; this.senderId = senderId; @@ -88,6 +73,18 @@ public Oscore(String masterSecret, String senderId, String recipientId, int aead this.masterSalt = masterSalt; this.idContext = ""; } + + /** + * Constructor providing some default values. + * + * aeadAlgorithm = 10; //AES_CCM_16_64_128 + * hmacAlgorithm = -10; //HKDF_HMAC_SHA_256 + * masterSalt = ""; + * + */ + public Oscore(String masterSecret, String senderId, String recipientId) { + this(masterSecret, senderId, recipientId, 10, -10, ""); + } @Override public WriteResponse write(ServerIdentity identity, int resourceId, LwM2mResource value) { diff --git a/leshan-client-demo/src/main/java/org/eclipse/leshan/client/demo/LeshanClientDemo.java b/leshan-client-demo/src/main/java/org/eclipse/leshan/client/demo/LeshanClientDemo.java index 0f9d24b5f6..8976284764 100644 --- a/leshan-client-demo/src/main/java/org/eclipse/leshan/client/demo/LeshanClientDemo.java +++ b/leshan-client-demo/src/main/java/org/eclipse/leshan/client/demo/LeshanClientDemo.java @@ -374,7 +374,7 @@ public static void createAndStartClient(String endpoint, String localAddress, in initializer.setInstancesForObject(SERVER, new Server(123, 30, BindingMode.U, false)); } else if (useOSCore) { initializer.setInstancesForObject(SECURITY, secOSCore(serverURI, 123)); - initializer.setInstancesForObject(OSCORE, Oscore.set("11223344", "AA", "BB")); //Hardcoded values + initializer.setInstancesForObject(OSCORE, new Oscore("11223344", "AA", "BB")); //Hardcoded values initializer.setInstancesForObject(SERVER, new Server(123, 30, BindingMode.U, false)); } else { initializer.setInstancesForObject(SECURITY, noSec(serverURI, 123)); From ebc728a69129645fe1347e312c1feb34ee4aae13 Mon Sep 17 00:00:00 2001 From: rikard-sics Date: Tue, 17 Sep 2019 21:08:03 +0200 Subject: [PATCH 04/18] Use hex string manipulation method from Leshan rather than adding new MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rikard Höglund --- .../client/servers/ServersInfoExtractor.java | 50 +++---------------- 1 file changed, 8 insertions(+), 42 deletions(-) diff --git a/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServersInfoExtractor.java b/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServersInfoExtractor.java index ecb80b9391..e432aacfe2 100644 --- a/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServersInfoExtractor.java +++ b/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServersInfoExtractor.java @@ -47,7 +47,7 @@ import org.eclipse.leshan.core.request.BindingMode; import org.eclipse.leshan.core.request.ReadRequest; import org.eclipse.leshan.core.response.ReadResponse; -import org.eclipse.leshan.util.StringUtils; +import org.eclipse.leshan.util.Hex; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -258,15 +258,18 @@ public static boolean isBootstrapServer(LwM2mInstanceEnabler instance) { //OSCORE related methods below public static byte[] getMasterSecret(LwM2mObjectInstance oscoreInstance) { - return hex2ByteArray((String)oscoreInstance.getResource(OSCORE_Master_Secret).getValue()); + String value = (String)oscoreInstance.getResource(OSCORE_Master_Secret).getValue(); + return Hex.decodeHex(value.toCharArray()); } public static byte[] getSenderId(LwM2mObjectInstance oscoreInstance) { - return hex2ByteArray((String)oscoreInstance.getResource(OSCORE_Sender_ID).getValue()); + String value = (String)oscoreInstance.getResource(OSCORE_Sender_ID).getValue(); + return Hex.decodeHex(value.toCharArray()); } public static byte[] getRecipientId(LwM2mObjectInstance oscoreInstance) { - return hex2ByteArray((String)oscoreInstance.getResource(OSCORE_Recipient_ID).getValue()); + String value = (String)oscoreInstance.getResource(OSCORE_Recipient_ID).getValue(); + return Hex.decodeHex(value.toCharArray()); } public static long getAeadAlgorithm(LwM2mObjectInstance oscoreInstance) { @@ -283,48 +286,11 @@ public static byte[] getMasterSalt(LwM2mObjectInstance oscoreInstance) { if(value.equals("")) { return null; } else { - return hex2ByteArray(value); + return Hex.decodeHex(value.toCharArray()); } } public static byte[] getIdContext(LwM2mObjectInstance oscoreInstance) { return null; } - - /** - * Convert hexadecimal String into decoded byte array. - * From Californium StringUtil.java - * - * @param hex hexadecimal string. e.g. "4130010A" - * @return byte array with decoded hexadecimal input parameter. - * @throws IllegalArgumentException if the parameter length is odd or - * contains non hexadecimal characters. - * @see #byteArray2Hex(byte[]) - */ - public static byte[] hex2ByteArray(String hex) { - if (hex == null) { - return null; - } - int length = hex.length(); - if ((1 & length) != 0) { - throw new IllegalArgumentException("'" + hex + "' has odd length!"); - } - length /= 2; - byte[] result = new byte[length]; - for (int indexDest = 0, indexSrc = 0; indexDest < length; ++indexDest) { - int digit = Character.digit(hex.charAt(indexSrc), 16); - if (digit < 0) { - throw new IllegalArgumentException("'" + hex + "' digit " + indexSrc + " is not hexadecimal!"); - } - result[indexDest] = (byte) (digit << 4); - ++indexSrc; - digit = Character.digit(hex.charAt(indexSrc), 16); - if (digit < 0) { - throw new IllegalArgumentException("'" + hex + "' digit " + indexSrc + " is not hexadecimal!"); - } - result[indexDest] |= (byte) digit; - ++indexSrc; - } - return result; - } } From dd58e43e1da396aa35c54a24b898752647c04bdd Mon Sep 17 00:00:00 2001 From: rikard-sics Date: Tue, 17 Sep 2019 21:12:00 +0200 Subject: [PATCH 05/18] Renamed initialization method for OSCORE only in Security object MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rikard Höglund --- .../main/java/org/eclipse/leshan/client/object/Security.java | 4 ++-- .../java/org/eclipse/leshan/client/demo/LeshanClientDemo.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Security.java b/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Security.java index e1f33c0172..20b88494f3 100644 --- a/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Security.java +++ b/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Security.java @@ -111,9 +111,9 @@ public static Security noSec(String serverUri, int shortServerId) { } /** - * Returns a new security instance (OSCORE) for a device management server. + * Returns a new security instance (OSCORE only) for a device management server. */ - public static Security secOSCore(String serverUri, int shortServerId) { + public static Security oscoreOnly(String serverUri, int shortServerId) { return new Security(serverUri, false, SecurityMode.OSCORE.code, new byte[0], new byte[0], new byte[0], shortServerId); } diff --git a/leshan-client-demo/src/main/java/org/eclipse/leshan/client/demo/LeshanClientDemo.java b/leshan-client-demo/src/main/java/org/eclipse/leshan/client/demo/LeshanClientDemo.java index 8976284764..329ce01ff7 100644 --- a/leshan-client-demo/src/main/java/org/eclipse/leshan/client/demo/LeshanClientDemo.java +++ b/leshan-client-demo/src/main/java/org/eclipse/leshan/client/demo/LeshanClientDemo.java @@ -373,7 +373,7 @@ public static void createAndStartClient(String endpoint, String localAddress, in clientPrivateKey.getEncoded(), serverCertificate.getEncoded())); initializer.setInstancesForObject(SERVER, new Server(123, 30, BindingMode.U, false)); } else if (useOSCore) { - initializer.setInstancesForObject(SECURITY, secOSCore(serverURI, 123)); + initializer.setInstancesForObject(SECURITY, oscoreOnly(serverURI, 123)); initializer.setInstancesForObject(OSCORE, new Oscore("11223344", "AA", "BB")); //Hardcoded values initializer.setInstancesForObject(SERVER, new Server(123, 30, BindingMode.U, false)); } else { From ecebdfa09ce8028fa02d0d26c448ce3029069479 Mon Sep 17 00:00:00 2001 From: rikard-sics Date: Wed, 18 Sep 2019 14:13:59 +0200 Subject: [PATCH 06/18] Updated Security object xml and introduced link to OSCORE object MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rikard Höglund --- .../leshan/client/object/Security.java | 42 +- .../client/servers/ServersInfoExtractor.java | 10 +- .../leshan/client/demo/LeshanClientDemo.java | 6 +- .../main/java/org/eclipse/leshan/LwM2mId.java | 1 + .../leshan/core/model/ObjectLoader.java | 2 +- ...ity-v1_0.xml => LWM2M_Security-v1_1_1.xml} | 505 ++++++++++-------- 6 files changed, 323 insertions(+), 243 deletions(-) rename leshan-core/src/main/resources/models/{LWM2M_Security-v1_0.xml => LWM2M_Security-v1_1_1.xml} (50%) diff --git a/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Security.java b/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Security.java index 20b88494f3..fb2cc42e1b 100644 --- a/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Security.java +++ b/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Security.java @@ -28,6 +28,7 @@ import org.eclipse.leshan.core.model.ObjectModel; import org.eclipse.leshan.core.model.ResourceModel.Type; import org.eclipse.leshan.core.node.LwM2mResource; +import org.eclipse.leshan.core.node.ObjectLink; import org.eclipse.leshan.core.response.ExecuteResponse; import org.eclipse.leshan.core.response.ReadResponse; import org.eclipse.leshan.core.response.WriteResponse; @@ -42,7 +43,8 @@ public class Security extends BaseInstanceEnabler { private static final Logger LOG = LoggerFactory.getLogger(Security.class); private final static List supportedResources = Arrays.asList(SEC_SERVER_URI, SEC_BOOTSTRAP, - SEC_SECURITY_MODE, SEC_PUBKEY_IDENTITY, SEC_SERVER_PUBKEY, SEC_SECRET_KEY, SEC_SERVER_ID); + SEC_SECURITY_MODE, SEC_PUBKEY_IDENTITY, SEC_SERVER_PUBKEY, SEC_SECRET_KEY, SEC_SERVER_ID, + SEC_OSCORE_SECURITY_MODE); private String serverUri; /* coaps://host:port */ private boolean bootstrapServer; @@ -53,13 +55,14 @@ public class Security extends BaseInstanceEnabler { private byte[] secretKey; private Integer shortServerId; - + private ObjectLink oscoreSecurityMode; + public Security() { // should only be used at bootstrap time } public Security(String serverUri, boolean bootstrapServer, int securityMode, byte[] publicKeyOrIdentity, - byte[] serverPublicKey, byte[] secretKey, Integer shortServerId) { + byte[] serverPublicKey, byte[] secretKey, Integer shortServerId, ObjectLink oscoreSecurityMode) { this.serverUri = serverUri; this.bootstrapServer = bootstrapServer; this.securityMode = securityMode; @@ -67,13 +70,15 @@ public Security(String serverUri, boolean bootstrapServer, int securityMode, byt this.serverPublicKey = serverPublicKey; this.secretKey = secretKey; this.shortServerId = shortServerId; + this.oscoreSecurityMode = oscoreSecurityMode; } /** * Returns a new security instance (NoSec) for a bootstrap server. */ public static Security noSecBootstap(String serverUri) { - return new Security(serverUri, true, SecurityMode.NO_SEC.code, new byte[0], new byte[0], new byte[0], 0); + return new Security(serverUri, true, SecurityMode.NO_SEC.code, new byte[0], new byte[0], new byte[0], 0, + new ObjectLink()); } /** @@ -81,7 +86,7 @@ public static Security noSecBootstap(String serverUri) { */ public static Security pskBootstrap(String serverUri, byte[] pskIdentity, byte[] privateKey) { return new Security(serverUri, true, SecurityMode.PSK.code, pskIdentity.clone(), new byte[0], - privateKey.clone(), 0); + privateKey.clone(), 0, new ObjectLink()); } /** @@ -90,7 +95,7 @@ public static Security pskBootstrap(String serverUri, byte[] pskIdentity, byte[] public static Security rpkBootstrap(String serverUri, byte[] clientPublicKey, byte[] clientPrivateKey, byte[] serverPublicKey) { return new Security(serverUri, true, SecurityMode.RPK.code, clientPublicKey.clone(), serverPublicKey.clone(), - clientPrivateKey.clone(), 0); + clientPrivateKey.clone(), 0, new ObjectLink()); } /** @@ -99,7 +104,7 @@ public static Security rpkBootstrap(String serverUri, byte[] clientPublicKey, by public static Security x509Bootstrap(String serverUri, byte[] clientCertificate, byte[] clientPrivateKey, byte[] serverPublicKey) { return new Security(serverUri, true, SecurityMode.X509.code, clientCertificate.clone(), serverPublicKey.clone(), - clientPrivateKey.clone(), 0); + clientPrivateKey.clone(), 0, new ObjectLink()); } /** @@ -107,15 +112,15 @@ public static Security x509Bootstrap(String serverUri, byte[] clientCertificate, */ public static Security noSec(String serverUri, int shortServerId) { return new Security(serverUri, false, SecurityMode.NO_SEC.code, new byte[0], new byte[0], new byte[0], - shortServerId); + shortServerId, new ObjectLink()); } /** * Returns a new security instance (OSCORE only) for a device management server. */ - public static Security oscoreOnly(String serverUri, int shortServerId) { + public static Security oscoreOnly(String serverUri, int shortServerId, int oscoreObjectInstanceId) { return new Security(serverUri, false, SecurityMode.OSCORE.code, new byte[0], new byte[0], new byte[0], - shortServerId); + shortServerId, new ObjectLink(OSCORE, oscoreObjectInstanceId)); } /** @@ -123,7 +128,7 @@ public static Security oscoreOnly(String serverUri, int shortServerId) { */ public static Security psk(String serverUri, int shortServerId, byte[] pskIdentity, byte[] privateKey) { return new Security(serverUri, false, SecurityMode.PSK.code, pskIdentity.clone(), new byte[0], - privateKey.clone(), shortServerId); + privateKey.clone(), shortServerId, new ObjectLink()); } /** @@ -132,7 +137,7 @@ public static Security psk(String serverUri, int shortServerId, byte[] pskIdenti public static Security rpk(String serverUri, int shortServerId, byte[] clientPublicKey, byte[] clientPrivateKey, byte[] serverPublicKey) { return new Security(serverUri, false, SecurityMode.RPK.code, clientPublicKey.clone(), serverPublicKey.clone(), - clientPrivateKey.clone(), shortServerId); + clientPrivateKey.clone(), shortServerId, new ObjectLink()); } /** @@ -141,7 +146,7 @@ public static Security rpk(String serverUri, int shortServerId, byte[] clientPub public static Security x509(String serverUri, int shortServerId, byte[] clientCertificate, byte[] clientPrivateKey, byte[] serverPublicKey) { return new Security(serverUri, false, SecurityMode.X509.code, clientCertificate.clone(), - serverPublicKey.clone(), clientPrivateKey.clone(), shortServerId); + serverPublicKey.clone(), clientPrivateKey.clone(), shortServerId, new ObjectLink()); } @Override @@ -197,6 +202,14 @@ public WriteResponse write(ServerIdentity identity, int resourceId, LwM2mResourc } shortServerId = ((Long) value.getValue()).intValue(); return WriteResponse.success(); + + case SEC_OSCORE_SECURITY_MODE: // oscore security mode + if (value.getType() != Type.OBJLNK) { + return WriteResponse.badRequest("invalid type"); + } + oscoreSecurityMode = (ObjectLink) value.getValue(); + return WriteResponse.success(); + default: return super.write(identity, resourceId, value); @@ -229,6 +242,9 @@ public ReadResponse read(ServerIdentity identity, int resourceid) { case SEC_SERVER_ID: // short server id return ReadResponse.success(resourceid, shortServerId); + + case SEC_OSCORE_SECURITY_MODE: //oscore security mode + return ReadResponse.success(resourceid, oscoreSecurityMode); default: return super.read(identity, resourceid); diff --git a/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServersInfoExtractor.java b/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServersInfoExtractor.java index e432aacfe2..0db35cd201 100644 --- a/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServersInfoExtractor.java +++ b/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServersInfoExtractor.java @@ -44,6 +44,7 @@ import org.eclipse.leshan.core.node.LwM2mObject; import org.eclipse.leshan.core.node.LwM2mObjectInstance; import org.eclipse.leshan.core.node.LwM2mResource; +import org.eclipse.leshan.core.node.ObjectLink; import org.eclipse.leshan.core.request.BindingMode; import org.eclipse.leshan.core.request.ReadRequest; import org.eclipse.leshan.core.response.ReadResponse; @@ -68,8 +69,12 @@ public static ServersInfo getInfo(Map objectEnabler ServersInfo infos = new ServersInfo(); LwM2mObject securities = (LwM2mObject) securityEnabler.read(SYSTEM, new ReadRequest(SECURITY)).getContent(); LwM2mObject servers = (LwM2mObject) serverEnabler.read(SYSTEM, new ReadRequest(SERVER)).getContent(); - LwM2mObject oscores = (LwM2mObject) oscoreEnabler.read(SYSTEM, new ReadRequest(OSCORE)).getContent(); - + + LwM2mObject oscores = null; + if(oscoreEnabler != null) { + oscores = (LwM2mObject) oscoreEnabler.read(SYSTEM, new ReadRequest(OSCORE)).getContent(); + } + for (LwM2mObjectInstance security : securities.getInstances().values()) { try { if ((boolean) security.getResource(SEC_BOOTSTRAP).getValue()) { @@ -126,6 +131,7 @@ public static ServersInfo getInfo(Map objectEnabler info.hkdfAlgorithm = getHkdfAlgorithm(oscoreInstance); info.masterSalt = getMasterSalt(oscoreInstance); info.idContext = getIdContext(oscoreInstance); + } // search corresponding device management server for (LwM2mObjectInstance server : servers.getInstances().values()) { diff --git a/leshan-client-demo/src/main/java/org/eclipse/leshan/client/demo/LeshanClientDemo.java b/leshan-client-demo/src/main/java/org/eclipse/leshan/client/demo/LeshanClientDemo.java index 329ce01ff7..c1a0321aec 100644 --- a/leshan-client-demo/src/main/java/org/eclipse/leshan/client/demo/LeshanClientDemo.java +++ b/leshan-client-demo/src/main/java/org/eclipse/leshan/client/demo/LeshanClientDemo.java @@ -373,8 +373,10 @@ public static void createAndStartClient(String endpoint, String localAddress, in clientPrivateKey.getEncoded(), serverCertificate.getEncoded())); initializer.setInstancesForObject(SERVER, new Server(123, 30, BindingMode.U, false)); } else if (useOSCore) { - initializer.setInstancesForObject(SECURITY, oscoreOnly(serverURI, 123)); - initializer.setInstancesForObject(OSCORE, new Oscore("11223344", "AA", "BB")); //Hardcoded values + Oscore oscoreObject = new Oscore("11223344", "AA", "BB"); //Hardcoded values + oscoreObject.setId(12345); + initializer.setInstancesForObject(SECURITY, oscoreOnly(serverURI, 123, oscoreObject.getId())); + initializer.setInstancesForObject(OSCORE, oscoreObject); initializer.setInstancesForObject(SERVER, new Server(123, 30, BindingMode.U, false)); } else { initializer.setInstancesForObject(SECURITY, noSec(serverURI, 123)); diff --git a/leshan-core/src/main/java/org/eclipse/leshan/LwM2mId.java b/leshan-core/src/main/java/org/eclipse/leshan/LwM2mId.java index 9d9ca8356f..661de5386c 100644 --- a/leshan-core/src/main/java/org/eclipse/leshan/LwM2mId.java +++ b/leshan-core/src/main/java/org/eclipse/leshan/LwM2mId.java @@ -43,6 +43,7 @@ public interface LwM2mId { public static final int SEC_SERVER_PUBKEY = 4; public static final int SEC_SECRET_KEY = 5; public static final int SEC_SERVER_ID = 10; + public static final int SEC_OSCORE_SECURITY_MODE = 17; /* OSCORE RESOURCES */ diff --git a/leshan-core/src/main/java/org/eclipse/leshan/core/model/ObjectLoader.java b/leshan-core/src/main/java/org/eclipse/leshan/core/model/ObjectLoader.java index 0ca77059f7..c23712b2d6 100644 --- a/leshan-core/src/main/java/org/eclipse/leshan/core/model/ObjectLoader.java +++ b/leshan-core/src/main/java/org/eclipse/leshan/core/model/ObjectLoader.java @@ -38,7 +38,7 @@ public class ObjectLoader { private static final Logger LOG = LoggerFactory.getLogger(ObjectLoader.class); - private static final String[] ddfpaths = new String[] { "LWM2M_Security-v1_0.xml", "LWM2M_Server-v1_0.xml", + private static final String[] ddfpaths = new String[] { "LWM2M_Security-v1_1_1.xml", "LWM2M_Server-v1_0.xml", "LWM2M_Access_Control-v1_0.xml", "LWM2M_Device-v1_0.xml", "LWM2M_Connectivity_Monitoring-v1_0.xml", "LWM2M_Firmware_Update-v1_0.xml", "LWM2M_Location-v1_0.xml", "LWM2M_Connectivity_Statistics-v1_0.xml", diff --git a/leshan-core/src/main/resources/models/LWM2M_Security-v1_0.xml b/leshan-core/src/main/resources/models/LWM2M_Security-v1_1_1.xml similarity index 50% rename from leshan-core/src/main/resources/models/LWM2M_Security-v1_0.xml rename to leshan-core/src/main/resources/models/LWM2M_Security-v1_1_1.xml index 65cd844ca3..af6376dbfa 100644 --- a/leshan-core/src/main/resources/models/LWM2M_Security-v1_0.xml +++ b/leshan-core/src/main/resources/models/LWM2M_Security-v1_1_1.xml @@ -1,225 +1,280 @@ - - - - - - - LWM2M Security - - 0 - urn:oma:lwm2m:oma:0 - Multiple - Mandatory - - - LWM2M Server URI - - Single - Mandatory - String - 0-255 bytes - - - - - Bootstrap-Server - - Single - Mandatory - Boolean - - - - - - Security Mode - - Single - Mandatory - Integer - 0-4 - - - - - Public Key or Identity - - Single - Mandatory - Opaque - - - - - - Server Public Key - - Single - Mandatory - Opaque - - - - - - Secret Key - - Single - Mandatory - Opaque - - - - - - SMS Security Mode - - Single - Optional - Integer - 0-255 - - - - - SMS Binding Key Parameters - - Single - Optional - Opaque - 6 bytes - - - - - SMS Binding Secret Key(s) - - Single - Optional - Opaque - 16-32-48 bytes - - - - - LwM2M Server SMS Number - - Single - Optional - String - - - - - - Short Server ID - - Single - Optional - Integer - 1-65534 - - - - - Client Hold Off Time - - Single - Optional - Integer - - s - - - - Bootstrap-Server Account Timeout - - Single - Optional - Integer - - s - - - - - - + + + + + LWM2M Security + + 0 + urn:oma:lwm2m:oma:0:1.1 + 1.1 + 1.1 + Multiple + Mandatory + + + LWM2M Server URI + + Single + Mandatory + String + 0..255 bytes + + + + + Bootstrap-Server + + Single + Mandatory + Boolean + + + + + + Security Mode + + Single + Mandatory + Integer + 0..4 + + + + + Public Key or Identity + + Single + Mandatory + Opaque + + + + + + Server Public Key + + Single + Mandatory + Opaque + + + + + + Secret Key + + Single + Mandatory + Opaque + + + + + + SMS Security Mode + + Single + Optional + Integer + 0..255 + + + + + SMS Binding Key Parameters + + Single + Optional + Opaque + 6 + + + + + SMS Binding Secret Key(s) + + Single + Optional + Opaque + 16,32,48 + + + + + LwM2M Server SMS Number + + Single + Optional + String + + + + + + Short Server ID + + Single + Optional + Integer + 1..65534 + + + + + Client Hold Off Time + + Single + Optional + Integer + + s + + + + Bootstrap-Server Account Timeout + + Single + Optional + Integer + + s + + + + Matching Type + + Single + Optional + Unsigned Integer + 0..3 + s + + + + SNI + + Single + Optional + String + + + + + + Certificate Usage + + Single + Optional + Unsigned Integer + 0..3 + s + + + + DTLS/TLS Ciphersuite + + Multiple + Optional + Unsigned Integer + + + + + OSCORE Security Mode + + Single + Optional + Objlnk + + + + + + + + \ No newline at end of file From 3e7db26f5131ad4ef4622ae864e69d5796b3eefa Mon Sep 17 00:00:00 2001 From: rikard-sics Date: Wed, 18 Sep 2019 14:35:51 +0200 Subject: [PATCH 07/18] Use link from Security to find OSCORE object when creating ServerInfo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rikard Höglund --- .../client/servers/ServersInfoExtractor.java | 41 +++++++++++++------ .../leshan/client/demo/LeshanClientDemo.java | 2 +- 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServersInfoExtractor.java b/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServersInfoExtractor.java index 0db35cd201..b656703625 100644 --- a/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServersInfoExtractor.java +++ b/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServersInfoExtractor.java @@ -110,7 +110,34 @@ public static ServersInfo getInfo(Map objectEnabler info.serverUri = new URI((String) security.getResource(SEC_SERVER_URI).getValue()); info.serverId = (long) security.getResource(SEC_SERVER_ID).getValue(); info.secureMode = getSecurityMode(security); - if (info.secureMode == SecurityMode.PSK) { + + // find instance id of the associated oscore object (if any) + ObjectLink oscoreObjectLink = (ObjectLink) security.getResource(SEC_OSCORE_SECURITY_MODE).getValue(); + int oscoreObjectInstanceId = oscoreObjectLink.getObjectInstanceId(); + int oscoreObjectId = oscoreObjectLink.getObjectId(); + boolean useOscore = false; + if(oscoreObjectId == OSCORE) { + useOscore = true; + } + + if(useOscore) { + // search corresponding oscore object + LwM2mObjectInstance oscoreInstance = null; + for (LwM2mObjectInstance oscore : oscores.getInstances().values()) { + if (oscore.getId() == oscoreObjectInstanceId) { + oscoreInstance = oscore; + break; + } + } + + info.masterSecret = getMasterSecret(oscoreInstance); + info.senderId = getSenderId(oscoreInstance); + info.recipientId = getRecipientId(oscoreInstance); + info.aeadAlgorithm = getAeadAlgorithm(oscoreInstance); + info.hkdfAlgorithm = getHkdfAlgorithm(oscoreInstance); + info.masterSalt = getMasterSalt(oscoreInstance); + info.idContext = getIdContext(oscoreInstance); + } else if (info.secureMode == SecurityMode.PSK) { info.pskId = getPskIdentity(security); info.pskKey = getPskKey(security); } else if (info.secureMode == SecurityMode.RPK) { @@ -121,18 +148,8 @@ public static ServersInfo getInfo(Map objectEnabler info.clientCertificate = getClientCertificate(security); info.serverCertificate = getServerCertificate(security); info.privateKey = getPrivateKey(security); - } else if (info.secureMode == SecurityMode.OSCORE) { - //FIXME: Need proper way to find correct oscore instance corresponding to this security instance - LwM2mObjectInstance oscoreInstance = (LwM2mObjectInstance)oscores.getInstances().values().toArray()[0]; - info.masterSecret = getMasterSecret(oscoreInstance); - info.senderId = getSenderId(oscoreInstance); - info.recipientId = getRecipientId(oscoreInstance); - info.aeadAlgorithm = getAeadAlgorithm(oscoreInstance); - info.hkdfAlgorithm = getHkdfAlgorithm(oscoreInstance); - info.masterSalt = getMasterSalt(oscoreInstance); - info.idContext = getIdContext(oscoreInstance); - } + // search corresponding device management server for (LwM2mObjectInstance server : servers.getInstances().values()) { if (info.serverId == (Long) server.getResource(SRV_SERVER_ID).getValue()) { diff --git a/leshan-client-demo/src/main/java/org/eclipse/leshan/client/demo/LeshanClientDemo.java b/leshan-client-demo/src/main/java/org/eclipse/leshan/client/demo/LeshanClientDemo.java index c1a0321aec..23f4fcb792 100644 --- a/leshan-client-demo/src/main/java/org/eclipse/leshan/client/demo/LeshanClientDemo.java +++ b/leshan-client-demo/src/main/java/org/eclipse/leshan/client/demo/LeshanClientDemo.java @@ -374,7 +374,7 @@ public static void createAndStartClient(String endpoint, String localAddress, in initializer.setInstancesForObject(SERVER, new Server(123, 30, BindingMode.U, false)); } else if (useOSCore) { Oscore oscoreObject = new Oscore("11223344", "AA", "BB"); //Hardcoded values - oscoreObject.setId(12345); + oscoreObject.setId(12346); initializer.setInstancesForObject(SECURITY, oscoreOnly(serverURI, 123, oscoreObject.getId())); initializer.setInstancesForObject(OSCORE, oscoreObject); initializer.setInstancesForObject(SERVER, new Server(123, 30, BindingMode.U, false)); From ae73ab25b69513f1b63b8bf4e2c9fbc4ca931a50 Mon Sep 17 00:00:00 2001 From: rikard-sics Date: Wed, 18 Sep 2019 14:41:00 +0200 Subject: [PATCH 08/18] Modified OSCORE object to take an instance id in its constructor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rikard Höglund --- .../java/org/eclipse/leshan/client/object/Oscore.java | 9 +++++---- .../org/eclipse/leshan/client/demo/LeshanClientDemo.java | 3 +-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Oscore.java b/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Oscore.java index e5c31dfe8e..07e0639239 100644 --- a/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Oscore.java +++ b/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Oscore.java @@ -64,8 +64,9 @@ public Oscore() { /** * Default constructor. */ - public Oscore(String masterSecret, String senderId, String recipientId, int aeadAlgorithm, int hkdfAlgorithm, String masterSalt) { - this.masterSecret = masterSecret; + public Oscore(int instanceId, String masterSecret, String senderId, String recipientId, int aeadAlgorithm, int hkdfAlgorithm, String masterSalt) { + this.setId(instanceId); + this.masterSecret = masterSecret; this.senderId = senderId; this.recipientId = recipientId; this.aeadAlgorithm = aeadAlgorithm; @@ -82,8 +83,8 @@ public Oscore(String masterSecret, String senderId, String recipientId, int aead * masterSalt = ""; * */ - public Oscore(String masterSecret, String senderId, String recipientId) { - this(masterSecret, senderId, recipientId, 10, -10, ""); + public Oscore(int instanceId, String masterSecret, String senderId, String recipientId) { + this(instanceId, masterSecret, senderId, recipientId, 10, -10, ""); } @Override diff --git a/leshan-client-demo/src/main/java/org/eclipse/leshan/client/demo/LeshanClientDemo.java b/leshan-client-demo/src/main/java/org/eclipse/leshan/client/demo/LeshanClientDemo.java index 23f4fcb792..b1ebfffc0a 100644 --- a/leshan-client-demo/src/main/java/org/eclipse/leshan/client/demo/LeshanClientDemo.java +++ b/leshan-client-demo/src/main/java/org/eclipse/leshan/client/demo/LeshanClientDemo.java @@ -373,8 +373,7 @@ public static void createAndStartClient(String endpoint, String localAddress, in clientPrivateKey.getEncoded(), serverCertificate.getEncoded())); initializer.setInstancesForObject(SERVER, new Server(123, 30, BindingMode.U, false)); } else if (useOSCore) { - Oscore oscoreObject = new Oscore("11223344", "AA", "BB"); //Hardcoded values - oscoreObject.setId(12346); + Oscore oscoreObject = new Oscore(12345, "11223344", "AA", "BB"); //Hardcoded values initializer.setInstancesForObject(SECURITY, oscoreOnly(serverURI, 123, oscoreObject.getId())); initializer.setInstancesForObject(OSCORE, oscoreObject); initializer.setInstancesForObject(SERVER, new Server(123, 30, BindingMode.U, false)); From 495d5019f750ffee544ce7a66bb27c270e372de7 Mon Sep 17 00:00:00 2001 From: rikard-sics Date: Wed, 18 Sep 2019 14:48:18 +0200 Subject: [PATCH 09/18] Removed OSCORE endpoint create method and added db parameter to others MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rikard Höglund --- .../impl/CaliforniumEndpointsManager.java | 6 +++--- .../leshan/core/californium/EndpointFactory.java | 6 ++---- .../tests/BootstrapIntegrationTestHelper.java | 3 ++- .../tests/SecureIntegrationTestHelper.java | 12 ++---------- .../californium/LeshanBootstrapServerBuilder.java | 4 ++-- .../server/californium/LeshanServerBuilder.java | 4 ++-- 6 files changed, 13 insertions(+), 22 deletions(-) diff --git a/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/impl/CaliforniumEndpointsManager.java b/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/impl/CaliforniumEndpointsManager.java index 2334782886..6a17c332bb 100644 --- a/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/impl/CaliforniumEndpointsManager.java +++ b/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/impl/CaliforniumEndpointsManager.java @@ -157,7 +157,7 @@ public boolean isTrusted(RawPublicKeyIdentity id) { } if (endpointFactory != null) { - currentEndpoint = endpointFactory.createOSCoreEndpoint(localAddress, coapConfig, null, db); + currentEndpoint = endpointFactory.createUnsecuredEndpoint(localAddress, coapConfig, null, db); } else { CoapEndpoint.Builder builder = new CoapEndpoint.Builder(); builder.setInetSocketAddress(localAddress); @@ -207,7 +207,7 @@ public X509Certificate[] getAcceptedIssuers() { } if (currentEndpoint == null) { if (endpointFactory != null) { - currentEndpoint = endpointFactory.createSecuredEndpoint(newBuilder.build(), coapConfig, null); + currentEndpoint = endpointFactory.createSecuredEndpoint(newBuilder.build(), coapConfig, null, null); } else { CoapEndpoint.Builder builder = new CoapEndpoint.Builder(); builder.setConnector(new DTLSConnector(newBuilder.build())); @@ -217,7 +217,7 @@ public X509Certificate[] getAcceptedIssuers() { } } else { if (endpointFactory != null) { - currentEndpoint = endpointFactory.createUnsecuredEndpoint(localAddress, coapConfig, null); + currentEndpoint = endpointFactory.createUnsecuredEndpoint(localAddress, coapConfig, null, null); } else { CoapEndpoint.Builder builder = new CoapEndpoint.Builder(); builder.setInetSocketAddress(localAddress); diff --git a/leshan-core-cf/src/main/java/org/eclipse/leshan/core/californium/EndpointFactory.java b/leshan-core-cf/src/main/java/org/eclipse/leshan/core/californium/EndpointFactory.java index 883709d1fc..dacb5f0ee9 100644 --- a/leshan-core-cf/src/main/java/org/eclipse/leshan/core/californium/EndpointFactory.java +++ b/leshan-core-cf/src/main/java/org/eclipse/leshan/core/californium/EndpointFactory.java @@ -29,10 +29,8 @@ */ public interface EndpointFactory { - CoapEndpoint createUnsecuredEndpoint(InetSocketAddress address, NetworkConfig coapConfig, ObservationStore store); - - CoapEndpoint createOSCoreEndpoint(InetSocketAddress address, NetworkConfig coapConfig, ObservationStore store, HashMapCtxDB db); + CoapEndpoint createUnsecuredEndpoint(InetSocketAddress address, NetworkConfig coapConfig, ObservationStore store, HashMapCtxDB db); CoapEndpoint createSecuredEndpoint(DtlsConnectorConfig dtlsConfig, NetworkConfig coapConfig, - ObservationStore store); + ObservationStore store, HashMapCtxDB db); } diff --git a/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/BootstrapIntegrationTestHelper.java b/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/BootstrapIntegrationTestHelper.java index 3da445eb85..a8af082e8f 100644 --- a/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/BootstrapIntegrationTestHelper.java +++ b/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/BootstrapIntegrationTestHelper.java @@ -44,6 +44,7 @@ import org.eclipse.leshan.client.resource.LwM2mObjectEnabler; import org.eclipse.leshan.client.resource.ObjectsInitializer; import org.eclipse.leshan.client.resource.SimpleInstanceEnabler; +import org.eclipse.leshan.core.node.ObjectLink; import org.eclipse.leshan.core.request.Identity; import org.eclipse.leshan.server.bootstrap.BootstrapConfig; import org.eclipse.leshan.server.bootstrap.BootstrapConfig.ACLConfig; @@ -127,7 +128,7 @@ public void createClient() { // Create Security Object (with bootstrap server only) String bsUrl = "coap://" + bootstrapServer.getUnsecuredAddress().getHostString() + ":" + bootstrapServer.getUnsecuredAddress().getPort(); - Security security = new Security(bsUrl, true, 3, new byte[0], new byte[0], new byte[0], 12345); + Security security = new Security(bsUrl, true, 3, new byte[0], new byte[0], new byte[0], 12345, new ObjectLink()); createClient(security); } diff --git a/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/SecureIntegrationTestHelper.java b/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/SecureIntegrationTestHelper.java index 1ca01ee866..b4978cd441 100644 --- a/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/SecureIntegrationTestHelper.java +++ b/leshan-integration-tests/src/test/java/org/eclipse/leshan/integration/tests/SecureIntegrationTestHelper.java @@ -208,7 +208,7 @@ public void createPSKClient() { @Override public CoapEndpoint createUnsecuredEndpoint(InetSocketAddress address, NetworkConfig coapConfig, - ObservationStore store) { + ObservationStore store, HashMapCtxDB db) { CoapEndpoint.Builder builder = new CoapEndpoint.Builder(); builder.setInetSocketAddress(address); builder.setNetworkConfig(coapConfig); @@ -217,7 +217,7 @@ public CoapEndpoint createUnsecuredEndpoint(InetSocketAddress address, NetworkCo @Override public CoapEndpoint createSecuredEndpoint(DtlsConnectorConfig dtlsConfig, NetworkConfig coapConfig, - ObservationStore store) { + ObservationStore store, HashMapCtxDB db) { CoapEndpoint.Builder builder = new CoapEndpoint.Builder(); Builder dtlsConfigBuilder = new Builder(dtlsConfig); if (dtlsConfig.getPskStore() != null) { @@ -231,14 +231,6 @@ public CoapEndpoint createSecuredEndpoint(DtlsConnectorConfig dtlsConfig, Networ return builder.build(); } - @Override - public CoapEndpoint createOSCoreEndpoint(InetSocketAddress address, NetworkConfig coapConfig, - ObservationStore store, HashMapCtxDB db) { - CoapEndpoint.Builder builder = new CoapEndpoint.Builder(); - builder.setInetSocketAddress(address); - builder.setNetworkConfig(coapConfig); - return builder.build(); - } }); // create client; diff --git a/leshan-server-cf/src/main/java/org/eclipse/leshan/server/californium/LeshanBootstrapServerBuilder.java b/leshan-server-cf/src/main/java/org/eclipse/leshan/server/californium/LeshanBootstrapServerBuilder.java index e170b7a060..025f04437b 100644 --- a/leshan-server-cf/src/main/java/org/eclipse/leshan/server/californium/LeshanBootstrapServerBuilder.java +++ b/leshan-server-cf/src/main/java/org/eclipse/leshan/server/californium/LeshanBootstrapServerBuilder.java @@ -367,7 +367,7 @@ public LeshanBootstrapServer build() { CoapEndpoint unsecuredEndpoint = null; if (!noUnsecuredEndpoint) { if (endpointFactory != null) { - unsecuredEndpoint = endpointFactory.createUnsecuredEndpoint(localAddress, coapConfig, null); + unsecuredEndpoint = endpointFactory.createUnsecuredEndpoint(localAddress, coapConfig, null, null); } else { CoapEndpoint.Builder builder = new CoapEndpoint.Builder(); builder.setInetSocketAddress(localAddress); @@ -379,7 +379,7 @@ public LeshanBootstrapServer build() { CoapEndpoint securedEndpoint = null; if (!noSecuredEndpoint && dtlsConfig != null) { if (endpointFactory != null) { - securedEndpoint = endpointFactory.createSecuredEndpoint(dtlsConfig, coapConfig, null); + securedEndpoint = endpointFactory.createSecuredEndpoint(dtlsConfig, coapConfig, null, null); } else { CoapEndpoint.Builder builder = new CoapEndpoint.Builder(); builder.setConnector(new DTLSConnector(dtlsConfig)); diff --git a/leshan-server-cf/src/main/java/org/eclipse/leshan/server/californium/LeshanServerBuilder.java b/leshan-server-cf/src/main/java/org/eclipse/leshan/server/californium/LeshanServerBuilder.java index 813ef492b4..b1837214bc 100644 --- a/leshan-server-cf/src/main/java/org/eclipse/leshan/server/californium/LeshanServerBuilder.java +++ b/leshan-server-cf/src/main/java/org/eclipse/leshan/server/californium/LeshanServerBuilder.java @@ -484,7 +484,7 @@ public LeshanServer build() { if (!noUnsecuredEndpoint) { if (endpointFactory != null) { unsecuredEndpoint = endpointFactory.createUnsecuredEndpoint(localAddress, coapConfig, - registrationStore); + registrationStore, null); } else { CoapEndpoint.Builder builder = new CoapEndpoint.Builder(); builder.setInetSocketAddress(localAddress); @@ -497,7 +497,7 @@ public LeshanServer build() { CoapEndpoint securedEndpoint = null; if (!noSecuredEndpoint && dtlsConfig != null) { if (endpointFactory != null) { - securedEndpoint = endpointFactory.createSecuredEndpoint(dtlsConfig, coapConfig, registrationStore); + securedEndpoint = endpointFactory.createSecuredEndpoint(dtlsConfig, coapConfig, registrationStore, null); } else { CoapEndpoint.Builder builder = new CoapEndpoint.Builder(); builder.setConnector(new DTLSConnector(dtlsConfig)); From 6617c2124486cd7a83f1d32568cda53dd77d2bbc Mon Sep 17 00:00:00 2001 From: rikard-sics Date: Wed, 18 Sep 2019 15:01:42 +0200 Subject: [PATCH 10/18] Two small fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rikard Höglund --- .../main/java/org/eclipse/leshan/client/object/Oscore.java | 2 +- .../eclipse/leshan/client/servers/ServersInfoExtractor.java | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Oscore.java b/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Oscore.java index 07e0639239..475ab4f133 100644 --- a/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Oscore.java +++ b/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Oscore.java @@ -65,7 +65,7 @@ public Oscore() { * Default constructor. */ public Oscore(int instanceId, String masterSecret, String senderId, String recipientId, int aeadAlgorithm, int hkdfAlgorithm, String masterSalt) { - this.setId(instanceId); + super(instanceId); this.masterSecret = masterSecret; this.senderId = senderId; this.recipientId = recipientId; diff --git a/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServersInfoExtractor.java b/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServersInfoExtractor.java index b656703625..c55eb5761c 100644 --- a/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServersInfoExtractor.java +++ b/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServersInfoExtractor.java @@ -115,10 +115,7 @@ public static ServersInfo getInfo(Map objectEnabler ObjectLink oscoreObjectLink = (ObjectLink) security.getResource(SEC_OSCORE_SECURITY_MODE).getValue(); int oscoreObjectInstanceId = oscoreObjectLink.getObjectInstanceId(); int oscoreObjectId = oscoreObjectLink.getObjectId(); - boolean useOscore = false; - if(oscoreObjectId == OSCORE) { - useOscore = true; - } + boolean useOscore = oscoreObjectId == OSCORE; if(useOscore) { // search corresponding oscore object From a255bd64d5334790597db3d9de6addcf81b78433 Mon Sep 17 00:00:00 2001 From: rikard-sics Date: Wed, 18 Sep 2019 15:08:50 +0200 Subject: [PATCH 11/18] Do not iterate to find OSCORE object in ServersInfoExtractor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rikard Höglund --- .../leshan/client/servers/ServersInfoExtractor.java | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServersInfoExtractor.java b/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServersInfoExtractor.java index c55eb5761c..3b7cb1de2a 100644 --- a/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServersInfoExtractor.java +++ b/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServersInfoExtractor.java @@ -118,14 +118,8 @@ public static ServersInfo getInfo(Map objectEnabler boolean useOscore = oscoreObjectId == OSCORE; if(useOscore) { - // search corresponding oscore object - LwM2mObjectInstance oscoreInstance = null; - for (LwM2mObjectInstance oscore : oscores.getInstances().values()) { - if (oscore.getId() == oscoreObjectInstanceId) { - oscoreInstance = oscore; - break; - } - } + // get corresponding oscore object + LwM2mObjectInstance oscoreInstance = oscores.getInstance(oscoreObjectInstanceId); info.masterSecret = getMasterSecret(oscoreInstance); info.senderId = getSenderId(oscoreInstance); From 3a4e777eb664aa126c9c4bae1eb1effba7eace0e Mon Sep 17 00:00:00 2001 From: rikard-sics Date: Wed, 18 Sep 2019 15:23:31 +0200 Subject: [PATCH 12/18] Removed SecurityMode for OSCORE. Instead use OSCORE Security Mode link MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rikard Höglund --- .../impl/CaliforniumEndpointsManager.java | 62 ++++++++++--------- .../leshan/client/object/Security.java | 2 +- .../leshan/client/servers/ServerInfo.java | 3 +- .../client/servers/ServersInfoExtractor.java | 1 + .../java/org/eclipse/leshan/SecurityMode.java | 2 +- 5 files changed, 37 insertions(+), 33 deletions(-) diff --git a/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/impl/CaliforniumEndpointsManager.java b/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/impl/CaliforniumEndpointsManager.java index 6a17c332bb..f3031f0e1f 100644 --- a/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/impl/CaliforniumEndpointsManager.java +++ b/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/impl/CaliforniumEndpointsManager.java @@ -97,36 +97,9 @@ public synchronized Server createEndpoint(ServerInfo serverInfo) { if (serverInfo.isSecure()) { Builder newBuilder = new Builder(dtlsConfigbuilder.getIncompleteConfig()); - // Support PSK - if (serverInfo.secureMode == SecurityMode.PSK) { - StaticPskStore staticPskStore = new StaticPskStore(serverInfo.pskId, serverInfo.pskKey); - newBuilder.setPskStore(staticPskStore); - serverIdentity = Identity.psk(serverInfo.getAddress(), serverInfo.pskId); - } 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; - } - }); - serverIdentity = Identity.rpk(serverInfo.getAddress(), expectedKey); - } else if (serverInfo.secureMode == SecurityMode.OSCORE) { - System.out.println("Adding OSCORE CTX " + serverInfo.getFullUri().toASCIIString()); + // oscore only mode + if(serverInfo.useOscore) { + System.out.println("Adding OSCORE CTX " + serverInfo.getFullUri().toASCIIString()); HashMapCtxDB db = HashMapCtxDB.getInstance(); //TODO: Do not use singleton here but give it to endpoint builder (for Cf-M16) AlgorithmID hkdfAlg = null; @@ -165,6 +138,35 @@ public boolean isTrusted(RawPublicKeyIdentity id) { currentEndpoint = builder.build(); } serverIdentity = Identity.unsecure(serverInfo.getAddress()); //TODO: FIX? + + } else if (serverInfo.secureMode == SecurityMode.PSK) { + // Support PSK + StaticPskStore staticPskStore = new StaticPskStore(serverInfo.pskId, serverInfo.pskKey); + newBuilder.setPskStore(staticPskStore); + serverIdentity = Identity.psk(serverInfo.getAddress(), serverInfo.pskId); + } 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; + } + }); + serverIdentity = Identity.rpk(serverInfo.getAddress(), expectedKey); } else if (serverInfo.secureMode == SecurityMode.X509) { // set identity newBuilder.setIdentity(serverInfo.privateKey, new Certificate[] { serverInfo.clientCertificate }); diff --git a/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Security.java b/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Security.java index fb2cc42e1b..3c7565e660 100644 --- a/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Security.java +++ b/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Security.java @@ -119,7 +119,7 @@ public static Security noSec(String serverUri, int shortServerId) { * Returns a new security instance (OSCORE only) for a device management server. */ public static Security oscoreOnly(String serverUri, int shortServerId, int oscoreObjectInstanceId) { - return new Security(serverUri, false, SecurityMode.OSCORE.code, new byte[0], new byte[0], new byte[0], + return new Security(serverUri, false, SecurityMode.NO_SEC.code, new byte[0], new byte[0], new byte[0], shortServerId, new ObjectLink(OSCORE, oscoreObjectInstanceId)); } diff --git a/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServerInfo.java b/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServerInfo.java index 072db9d3af..75e9fe51ed 100644 --- a/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServerInfo.java +++ b/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServerInfo.java @@ -48,6 +48,7 @@ public class ServerInfo { public PrivateKey privateKey; //OSCORE parameters + public boolean useOscore; public byte[] masterSecret; public byte[] senderId; public byte[] recipientId; @@ -65,7 +66,7 @@ public URI getFullUri() { } public boolean isSecure() { - return secureMode != SecurityMode.NO_SEC; + return secureMode != SecurityMode.NO_SEC || useOscore == true; } @Override diff --git a/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServersInfoExtractor.java b/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServersInfoExtractor.java index 3b7cb1de2a..c15b88c516 100644 --- a/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServersInfoExtractor.java +++ b/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServersInfoExtractor.java @@ -121,6 +121,7 @@ public static ServersInfo getInfo(Map objectEnabler // get corresponding oscore object LwM2mObjectInstance oscoreInstance = oscores.getInstance(oscoreObjectInstanceId); + info.useOscore = true; info.masterSecret = getMasterSecret(oscoreInstance); info.senderId = getSenderId(oscoreInstance); info.recipientId = getRecipientId(oscoreInstance); diff --git a/leshan-core/src/main/java/org/eclipse/leshan/SecurityMode.java b/leshan-core/src/main/java/org/eclipse/leshan/SecurityMode.java index 01d8d73d6e..9f3deb7851 100644 --- a/leshan-core/src/main/java/org/eclipse/leshan/SecurityMode.java +++ b/leshan-core/src/main/java/org/eclipse/leshan/SecurityMode.java @@ -20,7 +20,7 @@ * The different DTLS security modes */ public enum SecurityMode { - PSK(0), RPK(1), X509(2), NO_SEC(3), OSCORE(4); + PSK(0), RPK(1), X509(2), NO_SEC(3); public final int code; From 401db2bfd59b9481cc5f452a524b7c52bdb84f19 Mon Sep 17 00:00:00 2001 From: rikard-sics Date: Wed, 18 Sep 2019 16:03:25 +0200 Subject: [PATCH 13/18] Set client name as client OSCORE Sender ID MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rikard Höglund --- .../java/org/eclipse/leshan/client/demo/LeshanClientDemo.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/leshan-client-demo/src/main/java/org/eclipse/leshan/client/demo/LeshanClientDemo.java b/leshan-client-demo/src/main/java/org/eclipse/leshan/client/demo/LeshanClientDemo.java index b1ebfffc0a..a7b4c85336 100644 --- a/leshan-client-demo/src/main/java/org/eclipse/leshan/client/demo/LeshanClientDemo.java +++ b/leshan-client-demo/src/main/java/org/eclipse/leshan/client/demo/LeshanClientDemo.java @@ -373,7 +373,8 @@ public static void createAndStartClient(String endpoint, String localAddress, in clientPrivateKey.getEncoded(), serverCertificate.getEncoded())); initializer.setInstancesForObject(SERVER, new Server(123, 30, BindingMode.U, false)); } else if (useOSCore) { - Oscore oscoreObject = new Oscore(12345, "11223344", "AA", "BB"); //Hardcoded values + String clientName = Hex.encodeHexString(endpoint.getBytes()); + Oscore oscoreObject = new Oscore(12345, "11223344", clientName, "BB"); //Partially hardcoded values initializer.setInstancesForObject(SECURITY, oscoreOnly(serverURI, 123, oscoreObject.getId())); initializer.setInstancesForObject(OSCORE, oscoreObject); initializer.setInstancesForObject(SERVER, new Server(123, 30, BindingMode.U, false)); From a83918e1619c160747895ccc6e44731d1d90a6ed Mon Sep 17 00:00:00 2001 From: rikard-sics Date: Wed, 18 Sep 2019 16:53:38 +0200 Subject: [PATCH 14/18] Updated print statement to use LOG instead MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rikard Höglund --- .../client/californium/impl/CaliforniumEndpointsManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/impl/CaliforniumEndpointsManager.java b/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/impl/CaliforniumEndpointsManager.java index f3031f0e1f..4301f907fd 100644 --- a/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/impl/CaliforniumEndpointsManager.java +++ b/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/impl/CaliforniumEndpointsManager.java @@ -99,7 +99,7 @@ public synchronized Server createEndpoint(ServerInfo serverInfo) { // oscore only mode if(serverInfo.useOscore) { - System.out.println("Adding OSCORE CTX " + serverInfo.getFullUri().toASCIIString()); + LOG.info("Adding OSCORE context for " + serverInfo.getFullUri().toASCIIString()); HashMapCtxDB db = HashMapCtxDB.getInstance(); //TODO: Do not use singleton here but give it to endpoint builder (for Cf-M16) AlgorithmID hkdfAlg = null; From 40213f6bfc1fae4dd4c0d51eb3d48d17a1cfbd5a Mon Sep 17 00:00:00 2001 From: rikard-sics Date: Wed, 18 Sep 2019 17:17:14 +0200 Subject: [PATCH 15/18] Fix for clients to register using name configured in server interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rikard Höglund --- .../eclipse/leshan/server/security/SecurityChecker.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/leshan-server-core/src/main/java/org/eclipse/leshan/server/security/SecurityChecker.java b/leshan-server-core/src/main/java/org/eclipse/leshan/server/security/SecurityChecker.java index b5a1635861..6c6b63a637 100644 --- a/leshan-server-core/src/main/java/org/eclipse/leshan/server/security/SecurityChecker.java +++ b/leshan-server-core/src/main/java/org/eclipse/leshan/server/security/SecurityChecker.java @@ -92,7 +92,7 @@ public boolean checkSecurityInfo(String endpoint, Identity clientIdentity, Secur return false; } } else { - if (securityInfo != null) { + if (securityInfo != null && securityInfo.useOSCore == false) { LOG.debug("Client '{}' must connect using DTLS", endpoint); return false; } @@ -177,4 +177,9 @@ protected boolean matchX509Identity(String endpoint, String receivedX509CommonNa } return true; } + + protected boolean checkOscoreIdentity(String endpoint, Identity clientIdentity, SecurityInfo securityInfo) { + //TODO: Add comprehensive checks here + return true; + } } From 17098a79932f4c48aa608b7418edc3119a193be5 Mon Sep 17 00:00:00 2001 From: rikard-sics Date: Wed, 18 Sep 2019 17:24:00 +0200 Subject: [PATCH 16/18] Undid the change to isSecure method in ServerInfo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rikard Höglund --- .../client/californium/impl/CaliforniumEndpointsManager.java | 2 +- .../main/java/org/eclipse/leshan/client/servers/ServerInfo.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/impl/CaliforniumEndpointsManager.java b/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/impl/CaliforniumEndpointsManager.java index 4301f907fd..2114e90a1d 100644 --- a/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/impl/CaliforniumEndpointsManager.java +++ b/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/impl/CaliforniumEndpointsManager.java @@ -94,7 +94,7 @@ public synchronized Server createEndpoint(ServerInfo serverInfo) { // Create new endpoint Identity serverIdentity; - if (serverInfo.isSecure()) { + if (serverInfo.isSecure() || serverInfo.useOscore) { Builder newBuilder = new Builder(dtlsConfigbuilder.getIncompleteConfig()); // oscore only mode diff --git a/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServerInfo.java b/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServerInfo.java index 75e9fe51ed..e4f5554204 100644 --- a/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServerInfo.java +++ b/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServerInfo.java @@ -66,7 +66,7 @@ public URI getFullUri() { } public boolean isSecure() { - return secureMode != SecurityMode.NO_SEC || useOscore == true; + return secureMode != SecurityMode.NO_SEC; } @Override From 7116077e8e6ed4a1a8456b9040333ad01875b146 Mon Sep 17 00:00:00 2001 From: rikard-sics Date: Wed, 18 Sep 2019 17:50:20 +0200 Subject: [PATCH 17/18] Moved creation of OSCORE endpoint to a better place MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rikard Höglund --- .../impl/CaliforniumEndpointsManager.java | 88 +++++++++---------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/impl/CaliforniumEndpointsManager.java b/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/impl/CaliforniumEndpointsManager.java index 2114e90a1d..41eb5fbcb3 100644 --- a/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/impl/CaliforniumEndpointsManager.java +++ b/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/impl/CaliforniumEndpointsManager.java @@ -94,52 +94,10 @@ public synchronized Server createEndpoint(ServerInfo serverInfo) { // Create new endpoint Identity serverIdentity; - if (serverInfo.isSecure() || serverInfo.useOscore) { + if (serverInfo.isSecure()) { Builder newBuilder = new Builder(dtlsConfigbuilder.getIncompleteConfig()); - // oscore only mode - if(serverInfo.useOscore) { - LOG.info("Adding OSCORE context for " + serverInfo.getFullUri().toASCIIString()); - HashMapCtxDB db = HashMapCtxDB.getInstance(); //TODO: Do not use singleton here but give it to endpoint builder (for Cf-M16) - - AlgorithmID hkdfAlg = null; - try { - hkdfAlg = AlgorithmID.FromCBOR(CBORObject.FromObject(serverInfo.hkdfAlgorithm)); - } catch (CoseException e) { - LOG.error("Failed to decode OSCORE HMAC algorithm"); - } - - AlgorithmID aeadAlg = null; - try { - aeadAlg = AlgorithmID.FromCBOR(CBORObject.FromObject(serverInfo.aeadAlgorithm)); - } catch (CoseException e) { - LOG.error("Failed to decode OSCORE AEAD algorithm"); - } - - try { - OSCoreCtx ctx = new OSCoreCtx(serverInfo.masterSecret, true, aeadAlg, serverInfo.senderId, serverInfo.recipientId, hkdfAlg, 32, serverInfo.masterSalt, serverInfo.idContext); - db.addContext(serverInfo.getFullUri().toASCIIString(), ctx); - - // Also add the context by the IP of the server since requests may use that - String serverIP = InetAddress.getByName(serverInfo.getFullUri().getHost()).getHostAddress(); - db.addContext("coap://" + serverIP, ctx); - - } catch (OSException | UnknownHostException e) { - LOG.error("Failed to generate OSCORE context information"); - return null; - } - - if (endpointFactory != null) { - currentEndpoint = endpointFactory.createUnsecuredEndpoint(localAddress, coapConfig, null, db); - } else { - CoapEndpoint.Builder builder = new CoapEndpoint.Builder(); - builder.setInetSocketAddress(localAddress); - builder.setNetworkConfig(coapConfig); - currentEndpoint = builder.build(); - } - serverIdentity = Identity.unsecure(serverInfo.getAddress()); //TODO: FIX? - - } else if (serverInfo.secureMode == SecurityMode.PSK) { + if (serverInfo.secureMode == SecurityMode.PSK) { // Support PSK StaticPskStore staticPskStore = new StaticPskStore(serverInfo.pskId, serverInfo.pskKey); newBuilder.setPskStore(staticPskStore); @@ -217,6 +175,48 @@ public X509Certificate[] getAcceptedIssuers() { currentEndpoint = builder.build(); } } + } else if (serverInfo.useOscore) { + // oscore only mode + LOG.info("Adding OSCORE context for " + serverInfo.getFullUri().toASCIIString()); + HashMapCtxDB db = HashMapCtxDB.getInstance(); //TODO: Do not use singleton here but give it to endpoint builder (for Cf-M16) + + AlgorithmID hkdfAlg = null; + try { + hkdfAlg = AlgorithmID.FromCBOR(CBORObject.FromObject(serverInfo.hkdfAlgorithm)); + } catch (CoseException e) { + LOG.error("Failed to decode OSCORE HMAC algorithm"); + } + + AlgorithmID aeadAlg = null; + try { + aeadAlg = AlgorithmID.FromCBOR(CBORObject.FromObject(serverInfo.aeadAlgorithm)); + } catch (CoseException e) { + LOG.error("Failed to decode OSCORE AEAD algorithm"); + } + + try { + OSCoreCtx ctx = new OSCoreCtx(serverInfo.masterSecret, true, aeadAlg, serverInfo.senderId, serverInfo.recipientId, hkdfAlg, 32, serverInfo.masterSalt, serverInfo.idContext); + db.addContext(serverInfo.getFullUri().toASCIIString(), ctx); + + // Also add the context by the IP of the server since requests may use that + String serverIP = InetAddress.getByName(serverInfo.getFullUri().getHost()).getHostAddress(); + db.addContext("coap://" + serverIP, ctx); + + } catch (OSException | UnknownHostException e) { + LOG.error("Failed to generate OSCORE context information"); + return null; + } + + if (endpointFactory != null) { + currentEndpoint = endpointFactory.createUnsecuredEndpoint(localAddress, coapConfig, null, db); + } else { + CoapEndpoint.Builder builder = new CoapEndpoint.Builder(); + builder.setInetSocketAddress(localAddress); + builder.setNetworkConfig(coapConfig); + currentEndpoint = builder.build(); + } + serverIdentity = Identity.unsecure(serverInfo.getAddress()); //TODO: FIX? + } else { if (endpointFactory != null) { currentEndpoint = endpointFactory.createUnsecuredEndpoint(localAddress, coapConfig, null, null); From 0138768e1b906ad8f81f67389103266832360d66 Mon Sep 17 00:00:00 2001 From: rikard-sics Date: Thu, 19 Sep 2019 08:11:50 +0200 Subject: [PATCH 18/18] Applying Leshan Eclipse formatter to code and small comment fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rikard Höglund --- .../impl/CaliforniumEndpointsManager.java | 28 +++++---- leshan-client-core/pom.xml | 1 - .../eclipse/leshan/client/object/Oscore.java | 41 ++++++------ .../leshan/client/object/Security.java | 12 ++-- .../leshan/client/servers/ServerInfo.java | 2 +- .../client/servers/ServersInfoExtractor.java | 62 +++++++++---------- .../leshan/client/demo/LeshanClientDemo.java | 6 +- .../core/californium/EndpointFactory.java | 7 ++- .../main/java/org/eclipse/leshan/LwM2mId.java | 4 +- .../java/org/eclipse/leshan/SecurityMode.java | 1 - .../leshan/core/model/ObjectLoader.java | 2 +- .../server/security/SecurityChecker.java | 7 ++- 12 files changed, 85 insertions(+), 88 deletions(-) diff --git a/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/impl/CaliforniumEndpointsManager.java b/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/impl/CaliforniumEndpointsManager.java index 41eb5fbcb3..d5c832a1b6 100644 --- a/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/impl/CaliforniumEndpointsManager.java +++ b/leshan-client-cf/src/main/java/org/eclipse/leshan/client/californium/impl/CaliforniumEndpointsManager.java @@ -97,8 +97,8 @@ public synchronized Server createEndpoint(ServerInfo serverInfo) { if (serverInfo.isSecure()) { Builder newBuilder = new Builder(dtlsConfigbuilder.getIncompleteConfig()); + // Support PSK if (serverInfo.secureMode == SecurityMode.PSK) { - // Support PSK StaticPskStore staticPskStore = new StaticPskStore(serverInfo.pskId, serverInfo.pskKey); newBuilder.setPskStore(staticPskStore); serverIdentity = Identity.psk(serverInfo.getAddress(), serverInfo.pskId); @@ -176,32 +176,34 @@ public X509Certificate[] getAcceptedIssuers() { } } } else if (serverInfo.useOscore) { - // oscore only mode - LOG.info("Adding OSCORE context for " + serverInfo.getFullUri().toASCIIString()); - HashMapCtxDB db = HashMapCtxDB.getInstance(); //TODO: Do not use singleton here but give it to endpoint builder (for Cf-M16) + // oscore only mode + LOG.info("Adding OSCORE context for " + serverInfo.getFullUri().toASCIIString()); + HashMapCtxDB db = HashMapCtxDB.getInstance(); // TODO: Do not use singleton here but give it to endpoint + // builder (for Cf-M16) - AlgorithmID hkdfAlg = null; + AlgorithmID hkdfAlg = null; try { hkdfAlg = AlgorithmID.FromCBOR(CBORObject.FromObject(serverInfo.hkdfAlgorithm)); } catch (CoseException e) { LOG.error("Failed to decode OSCORE HMAC algorithm"); } - + AlgorithmID aeadAlg = null; try { aeadAlg = AlgorithmID.FromCBOR(CBORObject.FromObject(serverInfo.aeadAlgorithm)); } catch (CoseException e) { LOG.error("Failed to decode OSCORE AEAD algorithm"); } - - try { - OSCoreCtx ctx = new OSCoreCtx(serverInfo.masterSecret, true, aeadAlg, serverInfo.senderId, serverInfo.recipientId, hkdfAlg, 32, serverInfo.masterSalt, serverInfo.idContext); + + try { + OSCoreCtx ctx = new OSCoreCtx(serverInfo.masterSecret, true, aeadAlg, serverInfo.senderId, + serverInfo.recipientId, hkdfAlg, 32, serverInfo.masterSalt, serverInfo.idContext); db.addContext(serverInfo.getFullUri().toASCIIString(), ctx); - + // Also add the context by the IP of the server since requests may use that - String serverIP = InetAddress.getByName(serverInfo.getFullUri().getHost()).getHostAddress(); + String serverIP = InetAddress.getByName(serverInfo.getFullUri().getHost()).getHostAddress(); db.addContext("coap://" + serverIP, ctx); - + } catch (OSException | UnknownHostException e) { LOG.error("Failed to generate OSCORE context information"); return null; @@ -215,7 +217,7 @@ public X509Certificate[] getAcceptedIssuers() { builder.setNetworkConfig(coapConfig); currentEndpoint = builder.build(); } - serverIdentity = Identity.unsecure(serverInfo.getAddress()); //TODO: FIX? + serverIdentity = Identity.unsecure(serverInfo.getAddress()); // TODO: FIX? } else { if (endpointFactory != null) { diff --git a/leshan-client-core/pom.xml b/leshan-client-core/pom.xml index 18419da1d6..6f68310e58 100644 --- a/leshan-client-core/pom.xml +++ b/leshan-client-core/pom.xml @@ -15,7 +15,6 @@ Contributors: Sierra Wireless - initial API and implementation Zebra Technologies - initial API and implementation Eurotech - initial API and implementation - Rikard Höglund (RISE SICS) - Additions to support OSCORE --> diff --git a/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Oscore.java b/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Oscore.java index 475ab4f133..4e9fdeaed2 100644 --- a/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Oscore.java +++ b/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Oscore.java @@ -44,10 +44,9 @@ public class Oscore extends BaseInstanceEnabler { private static final Logger LOG = LoggerFactory.getLogger(Security.class); - - private final static List supportedResources = Arrays.asList(OSCORE_Master_Secret, - OSCORE_Sender_ID, OSCORE_Recipient_ID, OSCORE_AEAD_Algorithm, OSCORE_HMAC_Algorithm, - OSCORE_Master_Salt); + + private final static List supportedResources = Arrays.asList(OSCORE_Master_Secret, OSCORE_Sender_ID, + OSCORE_Recipient_ID, OSCORE_AEAD_Algorithm, OSCORE_HMAC_Algorithm, OSCORE_Master_Salt); private String masterSecret; private String senderId; @@ -64,9 +63,10 @@ public Oscore() { /** * Default constructor. */ - public Oscore(int instanceId, String masterSecret, String senderId, String recipientId, int aeadAlgorithm, int hkdfAlgorithm, String masterSalt) { + public Oscore(int instanceId, String masterSecret, String senderId, String recipientId, int aeadAlgorithm, + int hkdfAlgorithm, String masterSalt) { super(instanceId); - this.masterSecret = masterSecret; + this.masterSecret = masterSecret; this.senderId = senderId; this.recipientId = recipientId; this.aeadAlgorithm = aeadAlgorithm; @@ -78,9 +78,7 @@ public Oscore(int instanceId, String masterSecret, String senderId, String recip /** * Constructor providing some default values. * - * aeadAlgorithm = 10; //AES_CCM_16_64_128 - * hmacAlgorithm = -10; //HKDF_HMAC_SHA_256 - * masterSalt = ""; + * aeadAlgorithm = 10; //AES_CCM_16_64_128m hmacAlgorithm = -10; //HKDF_HMAC_SHA_256, masterSalt = ""; * */ public Oscore(int instanceId, String masterSecret, String senderId, String recipientId) { @@ -101,35 +99,35 @@ public WriteResponse write(ServerIdentity identity, int resourceId, LwM2mResourc } masterSecret = (String) value.getValue(); return WriteResponse.success(); - + case OSCORE_Sender_ID: if (value.getType() != Type.STRING) { return WriteResponse.badRequest("invalid type"); } senderId = (String) value.getValue(); return WriteResponse.success(); - + case OSCORE_Recipient_ID: if (value.getType() != Type.STRING) { return WriteResponse.badRequest("invalid type"); } recipientId = (String) value.getValue(); return WriteResponse.success(); - + case OSCORE_AEAD_Algorithm: if (value.getType() != Type.INTEGER) { return WriteResponse.badRequest("invalid type"); } aeadAlgorithm = ((Long) value.getValue()).intValue(); return WriteResponse.success(); - + case OSCORE_HMAC_Algorithm: if (value.getType() != Type.INTEGER) { return WriteResponse.badRequest("invalid type"); } hkdfAlgorithm = ((Long) value.getValue()).intValue(); return WriteResponse.success(); - + case OSCORE_Master_Salt: if (value.getType() != Type.STRING) { return WriteResponse.badRequest("invalid type"); @@ -137,7 +135,6 @@ public WriteResponse write(ServerIdentity identity, int resourceId, LwM2mResourc masterSalt = (String) value.getValue(); return WriteResponse.success(); - default: return super.write(identity, resourceId, value); } @@ -149,25 +146,25 @@ public ReadResponse read(ServerIdentity identity, int resourceid) { // only accessible for internal read? switch (resourceid) { - + case OSCORE_Master_Secret: return ReadResponse.success(resourceid, masterSecret); - + case OSCORE_Sender_ID: return ReadResponse.success(resourceid, senderId); - + case OSCORE_Recipient_ID: return ReadResponse.success(resourceid, recipientId); - + case OSCORE_AEAD_Algorithm: return ReadResponse.success(resourceid, aeadAlgorithm); - + case OSCORE_HMAC_Algorithm: return ReadResponse.success(resourceid, hkdfAlgorithm); - + case OSCORE_Master_Salt: return ReadResponse.success(resourceid, masterSalt); - + default: return super.read(identity, resourceid); } diff --git a/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Security.java b/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Security.java index 3c7565e660..9dcaa69f7e 100644 --- a/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Security.java +++ b/leshan-client-core/src/main/java/org/eclipse/leshan/client/object/Security.java @@ -70,7 +70,7 @@ public Security(String serverUri, boolean bootstrapServer, int securityMode, byt this.serverPublicKey = serverPublicKey; this.secretKey = secretKey; this.shortServerId = shortServerId; - this.oscoreSecurityMode = oscoreSecurityMode; + this.oscoreSecurityMode = oscoreSecurityMode; } /** @@ -78,7 +78,7 @@ public Security(String serverUri, boolean bootstrapServer, int securityMode, byt */ public static Security noSecBootstap(String serverUri) { return new Security(serverUri, true, SecurityMode.NO_SEC.code, new byte[0], new byte[0], new byte[0], 0, - new ObjectLink()); + new ObjectLink()); } /** @@ -204,12 +204,12 @@ public WriteResponse write(ServerIdentity identity, int resourceId, LwM2mResourc return WriteResponse.success(); case SEC_OSCORE_SECURITY_MODE: // oscore security mode - if (value.getType() != Type.OBJLNK) { + if (value.getType() != Type.OBJLNK) { return WriteResponse.badRequest("invalid type"); } oscoreSecurityMode = (ObjectLink) value.getValue(); return WriteResponse.success(); - + default: return super.write(identity, resourceId, value); @@ -243,8 +243,8 @@ public ReadResponse read(ServerIdentity identity, int resourceid) { case SEC_SERVER_ID: // short server id return ReadResponse.success(resourceid, shortServerId); - case SEC_OSCORE_SECURITY_MODE: //oscore security mode - return ReadResponse.success(resourceid, oscoreSecurityMode); + case SEC_OSCORE_SECURITY_MODE: // oscore security mode + return ReadResponse.success(resourceid, oscoreSecurityMode); default: return super.read(identity, resourceid); diff --git a/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServerInfo.java b/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServerInfo.java index e4f5554204..d7cc03aec3 100644 --- a/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServerInfo.java +++ b/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServerInfo.java @@ -47,7 +47,7 @@ public class ServerInfo { public PrivateKey privateKey; - //OSCORE parameters + // OSCORE parameters public boolean useOscore; public byte[] masterSecret; public byte[] senderId; diff --git a/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServersInfoExtractor.java b/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServersInfoExtractor.java index c15b88c516..a9e3558726 100644 --- a/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServersInfoExtractor.java +++ b/leshan-client-core/src/main/java/org/eclipse/leshan/client/servers/ServersInfoExtractor.java @@ -69,12 +69,12 @@ public static ServersInfo getInfo(Map objectEnabler ServersInfo infos = new ServersInfo(); LwM2mObject securities = (LwM2mObject) securityEnabler.read(SYSTEM, new ReadRequest(SECURITY)).getContent(); LwM2mObject servers = (LwM2mObject) serverEnabler.read(SYSTEM, new ReadRequest(SERVER)).getContent(); - + LwM2mObject oscores = null; - if(oscoreEnabler != null) { - oscores = (LwM2mObject) oscoreEnabler.read(SYSTEM, new ReadRequest(OSCORE)).getContent(); + if (oscoreEnabler != null) { + oscores = (LwM2mObject) oscoreEnabler.read(SYSTEM, new ReadRequest(OSCORE)).getContent(); } - + for (LwM2mObjectInstance security : securities.getInstances().values()) { try { if ((boolean) security.getResource(SEC_BOOTSTRAP).getValue()) { @@ -112,17 +112,16 @@ public static ServersInfo getInfo(Map objectEnabler info.secureMode = getSecurityMode(security); // find instance id of the associated oscore object (if any) - ObjectLink oscoreObjectLink = (ObjectLink) security.getResource(SEC_OSCORE_SECURITY_MODE).getValue(); - int oscoreObjectInstanceId = oscoreObjectLink.getObjectInstanceId(); - int oscoreObjectId = oscoreObjectLink.getObjectId(); - boolean useOscore = oscoreObjectId == OSCORE; - - if(useOscore) { - // get corresponding oscore object - LwM2mObjectInstance oscoreInstance = oscores.getInstance(oscoreObjectInstanceId); - - info.useOscore = true; - info.masterSecret = getMasterSecret(oscoreInstance); + ObjectLink oscoreObjLink = (ObjectLink) security.getResource(SEC_OSCORE_SECURITY_MODE).getValue(); + int oscoreObjectInstanceId = oscoreObjLink.getObjectInstanceId(); + boolean useOscore = oscoreObjLink.getObjectId() == OSCORE; + + if (useOscore) { + // get corresponding oscore object + LwM2mObjectInstance oscoreInstance = oscores.getInstance(oscoreObjectInstanceId); + + info.useOscore = true; + info.masterSecret = getMasterSecret(oscoreInstance); info.senderId = getSenderId(oscoreInstance); info.recipientId = getRecipientId(oscoreInstance); info.aeadAlgorithm = getAeadAlgorithm(oscoreInstance); @@ -141,7 +140,6 @@ public static ServersInfo getInfo(Map objectEnabler info.serverCertificate = getServerCertificate(security); info.privateKey = getPrivateKey(security); } - // search corresponding device management server for (LwM2mObjectInstance server : servers.getInstances().values()) { if (info.serverId == (Long) server.getResource(SRV_SERVER_ID).getValue()) { @@ -270,41 +268,41 @@ public static boolean isBootstrapServer(LwM2mInstanceEnabler instance) { return (Boolean) isBootstrap.getValue(); } - //OSCORE related methods below - + // OSCORE related methods below + public static byte[] getMasterSecret(LwM2mObjectInstance oscoreInstance) { - String value = (String)oscoreInstance.getResource(OSCORE_Master_Secret).getValue(); + String value = (String) oscoreInstance.getResource(OSCORE_Master_Secret).getValue(); return Hex.decodeHex(value.toCharArray()); } - + public static byte[] getSenderId(LwM2mObjectInstance oscoreInstance) { - String value = (String)oscoreInstance.getResource(OSCORE_Sender_ID).getValue(); + String value = (String) oscoreInstance.getResource(OSCORE_Sender_ID).getValue(); return Hex.decodeHex(value.toCharArray()); } - + public static byte[] getRecipientId(LwM2mObjectInstance oscoreInstance) { - String value = (String)oscoreInstance.getResource(OSCORE_Recipient_ID).getValue(); + String value = (String) oscoreInstance.getResource(OSCORE_Recipient_ID).getValue(); return Hex.decodeHex(value.toCharArray()); } - + public static long getAeadAlgorithm(LwM2mObjectInstance oscoreInstance) { - return (long)oscoreInstance.getResource(OSCORE_AEAD_Algorithm).getValue(); + return (long) oscoreInstance.getResource(OSCORE_AEAD_Algorithm).getValue(); } - + public static long getHkdfAlgorithm(LwM2mObjectInstance oscoreInstance) { - return (long)oscoreInstance.getResource(OSCORE_HMAC_Algorithm).getValue(); + return (long) oscoreInstance.getResource(OSCORE_HMAC_Algorithm).getValue(); } - + public static byte[] getMasterSalt(LwM2mObjectInstance oscoreInstance) { - String value = (String)oscoreInstance.getResource(OSCORE_Master_Salt).getValue(); - - if(value.equals("")) { + String value = (String) oscoreInstance.getResource(OSCORE_Master_Salt).getValue(); + + if (value.equals("")) { return null; } else { return Hex.decodeHex(value.toCharArray()); } } - + public static byte[] getIdContext(LwM2mObjectInstance oscoreInstance) { return null; } diff --git a/leshan-client-demo/src/main/java/org/eclipse/leshan/client/demo/LeshanClientDemo.java b/leshan-client-demo/src/main/java/org/eclipse/leshan/client/demo/LeshanClientDemo.java index a7b4c85336..ec47d7bcfc 100644 --- a/leshan-client-demo/src/main/java/org/eclipse/leshan/client/demo/LeshanClientDemo.java +++ b/leshan-client-demo/src/main/java/org/eclipse/leshan/client/demo/LeshanClientDemo.java @@ -373,9 +373,9 @@ public static void createAndStartClient(String endpoint, String localAddress, in clientPrivateKey.getEncoded(), serverCertificate.getEncoded())); initializer.setInstancesForObject(SERVER, new Server(123, 30, BindingMode.U, false)); } else if (useOSCore) { - String clientName = Hex.encodeHexString(endpoint.getBytes()); - Oscore oscoreObject = new Oscore(12345, "11223344", clientName, "BB"); //Partially hardcoded values - initializer.setInstancesForObject(SECURITY, oscoreOnly(serverURI, 123, oscoreObject.getId())); + String clientName = Hex.encodeHexString(endpoint.getBytes()); + Oscore oscoreObject = new Oscore(12345, "11223344", clientName, "BB"); // Partially hardcoded values + initializer.setInstancesForObject(SECURITY, oscoreOnly(serverURI, 123, oscoreObject.getId())); initializer.setInstancesForObject(OSCORE, oscoreObject); initializer.setInstancesForObject(SERVER, new Server(123, 30, BindingMode.U, false)); } else { diff --git a/leshan-core-cf/src/main/java/org/eclipse/leshan/core/californium/EndpointFactory.java b/leshan-core-cf/src/main/java/org/eclipse/leshan/core/californium/EndpointFactory.java index dacb5f0ee9..a47f649bfa 100644 --- a/leshan-core-cf/src/main/java/org/eclipse/leshan/core/californium/EndpointFactory.java +++ b/leshan-core-cf/src/main/java/org/eclipse/leshan/core/californium/EndpointFactory.java @@ -29,8 +29,9 @@ */ public interface EndpointFactory { - CoapEndpoint createUnsecuredEndpoint(InetSocketAddress address, NetworkConfig coapConfig, ObservationStore store, HashMapCtxDB db); + CoapEndpoint createUnsecuredEndpoint(InetSocketAddress address, NetworkConfig coapConfig, ObservationStore store, + HashMapCtxDB db); - CoapEndpoint createSecuredEndpoint(DtlsConnectorConfig dtlsConfig, NetworkConfig coapConfig, - ObservationStore store, HashMapCtxDB db); + CoapEndpoint createSecuredEndpoint(DtlsConnectorConfig dtlsConfig, NetworkConfig coapConfig, ObservationStore store, + HashMapCtxDB db); } diff --git a/leshan-core/src/main/java/org/eclipse/leshan/LwM2mId.java b/leshan-core/src/main/java/org/eclipse/leshan/LwM2mId.java index 661de5386c..9a860ca994 100644 --- a/leshan-core/src/main/java/org/eclipse/leshan/LwM2mId.java +++ b/leshan-core/src/main/java/org/eclipse/leshan/LwM2mId.java @@ -44,9 +44,9 @@ public interface LwM2mId { public static final int SEC_SECRET_KEY = 5; public static final int SEC_SERVER_ID = 10; public static final int SEC_OSCORE_SECURITY_MODE = 17; - + /* OSCORE RESOURCES */ - + public static final int OSCORE_Master_Secret = 0; public static final int OSCORE_Sender_ID = 1; public static final int OSCORE_Recipient_ID = 2; diff --git a/leshan-core/src/main/java/org/eclipse/leshan/SecurityMode.java b/leshan-core/src/main/java/org/eclipse/leshan/SecurityMode.java index 9f3deb7851..26b1aa04ad 100644 --- a/leshan-core/src/main/java/org/eclipse/leshan/SecurityMode.java +++ b/leshan-core/src/main/java/org/eclipse/leshan/SecurityMode.java @@ -12,7 +12,6 @@ * * Contributors: * Sierra Wireless - initial API and implementation - * Rikard Höglund (RISE SICS) - Additions to support OSCORE *******************************************************************************/ package org.eclipse.leshan; diff --git a/leshan-core/src/main/java/org/eclipse/leshan/core/model/ObjectLoader.java b/leshan-core/src/main/java/org/eclipse/leshan/core/model/ObjectLoader.java index c23712b2d6..44a1523b8b 100644 --- a/leshan-core/src/main/java/org/eclipse/leshan/core/model/ObjectLoader.java +++ b/leshan-core/src/main/java/org/eclipse/leshan/core/model/ObjectLoader.java @@ -41,7 +41,7 @@ public class ObjectLoader { private static final String[] ddfpaths = new String[] { "LWM2M_Security-v1_1_1.xml", "LWM2M_Server-v1_0.xml", "LWM2M_Access_Control-v1_0.xml", "LWM2M_Device-v1_0.xml", "LWM2M_Connectivity_Monitoring-v1_0.xml", "LWM2M_Firmware_Update-v1_0.xml", - "LWM2M_Location-v1_0.xml", "LWM2M_Connectivity_Statistics-v1_0.xml", + "LWM2M_Location-v1_0.xml", "LWM2M_Connectivity_Statistics-v1_0.xml", "LWM2M_OSCORE-V1_0.xml" }; /** diff --git a/leshan-server-core/src/main/java/org/eclipse/leshan/server/security/SecurityChecker.java b/leshan-server-core/src/main/java/org/eclipse/leshan/server/security/SecurityChecker.java index 6c6b63a637..5e84414baf 100644 --- a/leshan-server-core/src/main/java/org/eclipse/leshan/server/security/SecurityChecker.java +++ b/leshan-server-core/src/main/java/org/eclipse/leshan/server/security/SecurityChecker.java @@ -12,6 +12,7 @@ * * Contributors: * Sierra Wireless - initial API and implementation + * Rikard Höglund (RISE SICS) - Additions to support OSCORE *******************************************************************************/ package org.eclipse.leshan.server.security; @@ -92,7 +93,7 @@ public boolean checkSecurityInfo(String endpoint, Identity clientIdentity, Secur return false; } } else { - if (securityInfo != null && securityInfo.useOSCore == false) { + if (securityInfo != null && securityInfo.useOSCore == false) { LOG.debug("Client '{}' must connect using DTLS", endpoint); return false; } @@ -177,9 +178,9 @@ protected boolean matchX509Identity(String endpoint, String receivedX509CommonNa } return true; } - + protected boolean checkOscoreIdentity(String endpoint, Identity clientIdentity, SecurityInfo securityInfo) { - //TODO: Add comprehensive checks here + // TODO: Add comprehensive checks here return true; } }