Skip to content

Commit

Permalink
#1226: Some cleaning about OSCORE (remove TODO and so on)
Browse files Browse the repository at this point in the history
  • Loading branch information
sbernard31 committed Jun 7, 2022
1 parent 379ad5c commit 56669c7
Show file tree
Hide file tree
Showing 52 changed files with 1,101 additions and 530 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@
import org.eclipse.leshan.core.californium.oscore.cf.InMemoryOscoreContextDB;
import org.eclipse.leshan.core.californium.oscore.cf.OscoreParameters;
import org.eclipse.leshan.core.californium.oscore.cf.StaticOscoreStore;
import org.eclipse.leshan.core.oscore.InvalidOscoreSettingException;
import org.eclipse.leshan.core.oscore.OscoreIdentity;
import org.eclipse.leshan.core.oscore.OscoreValidator;
import org.eclipse.leshan.core.request.Identity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -242,28 +244,48 @@ public synchronized ServerIdentity createEndpoint(ServerInfo serverInfo, boolean
currentEndpoint = endpointFactory.createSecuredEndpoint(newBuilder.build(), coapConfig, null, null);
} else if (serverInfo.useOscore) {
// oscore only mode
LOG.info("Adding OSCORE context for " + serverInfo.getFullUri().toASCIIString());
LOG.warn("Experimental OSCORE support is used for {}", serverInfo.getFullUri().toASCIIString());

try {
new OscoreValidator().validateOscoreSetting(serverInfo.oscoreSetting);
} catch (InvalidOscoreSettingException e) {
throw new RuntimeException(String.format("Unable to create endpoint for %s using OSCORE : Invalid %s.",
serverInfo, serverInfo.oscoreSetting), e);
}

AlgorithmID hkdfAlg = null;
try {
hkdfAlg = AlgorithmID.FromCBOR(CBORObject.FromObject(serverInfo.hkdfAlgorithm));
hkdfAlg = AlgorithmID
.FromCBOR(CBORObject.FromObject(serverInfo.oscoreSetting.getHkdfAlgorithm().getValue()));
} catch (CoseException e) {
LOG.error("Failed to decode OSCORE HMAC algorithm");
throw new RuntimeException(String.format(
"Unable to create endpoint for %s using OSCORE : Unable to decode OSCORE HKDF from %s.",
serverInfo, serverInfo.oscoreSetting), e);
}
AlgorithmID aeadAlg = null;
try {
aeadAlg = AlgorithmID.FromCBOR(CBORObject.FromObject(serverInfo.aeadAlgorithm));
aeadAlg = AlgorithmID
.FromCBOR(CBORObject.FromObject(serverInfo.oscoreSetting.getAeadAlgorithm().getValue()));
} catch (CoseException e) {
LOG.error("Failed to decode OSCORE AEAD algorithm");
throw new RuntimeException(String.format(
"Unable to create endpoint for %s using OSCORE : Unable to decode OSCORE AEAD from %s.",
serverInfo, serverInfo.oscoreSetting), e);
}
OscoreParameters oscoreParameters = new OscoreParameters(serverInfo.senderId, serverInfo.recipientId,
serverInfo.masterSecret, aeadAlg, hkdfAlg, serverInfo.masterSalt);

// TODO OSCORE kind of hack because californium doesn't support an empty byte[] array for salt ?
byte[] masterSalt = serverInfo.oscoreSetting.getMasterSalt().length == 0 ? null
: serverInfo.oscoreSetting.getMasterSalt();

OscoreParameters oscoreParameters = new OscoreParameters(serverInfo.oscoreSetting.getSenderId(),
serverInfo.oscoreSetting.getRecipientId(), serverInfo.oscoreSetting.getMasterSecret(), aeadAlg,
hkdfAlg, masterSalt);

currentEndpoint = endpointFactory.createUnsecuredEndpoint(localAddress, coapConfig, null,
new InMemoryOscoreContextDB(new StaticOscoreStore(oscoreParameters)));

// Build server identity for OSCORE
serverIdentity = Identity.oscoreOnly(serverInfo.getAddress(), new OscoreIdentity(serverInfo.recipientId));
serverIdentity = Identity.oscoreOnly(serverInfo.getAddress(),
new OscoreIdentity(serverInfo.oscoreSetting.getRecipientId()));
} else {
currentEndpoint = endpointFactory.createUnsecuredEndpoint(localAddress, coapConfig, null, null);
serverIdentity = Identity.unsecure(serverInfo.getAddress());
Expand All @@ -283,9 +305,7 @@ public synchronized ServerIdentity createEndpoint(ServerInfo serverInfo, boolean
try {
currentEndpoint.start();
LOG.info("New endpoint created for server {} at {}", currentServer.getUri(), currentEndpoint.getUri());
} catch (

IOException e) {
} catch (IOException e) {
throw new RuntimeException("Unable to start endpoint", e);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.eclipse.californium.core.CoapResource;
import org.eclipse.californium.core.coap.CoAP.ResponseCode;
import org.eclipse.californium.core.network.Exchange;
import org.eclipse.californium.core.network.Exchange.Origin;
import org.eclipse.californium.core.server.resources.CoapExchange;
import org.eclipse.leshan.client.engine.RegistrationEngine;
import org.eclipse.leshan.client.servers.ServerIdentity;
Expand Down Expand Up @@ -74,6 +75,7 @@ protected ServerIdentity getServerOrRejectRequest(CoapExchange exchange) {
*/
protected ServerIdentity extractIdentity(CoapExchange exchange) {
return endpointsManager.getServerIdentity(exchange.advanced().getEndpoint(), exchange.getSourceSocketAddress(),
exchange.advanced().getRequest().getSourceContext());
exchange.advanced().getOrigin() == Origin.REMOTE ? exchange.advanced().getRequest().getSourceContext()
: exchange.advanced().getRequest().getDestinationContext());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,26 @@
import org.eclipse.leshan.client.servers.DmServerInfo;
import org.eclipse.leshan.client.servers.ServerInfo;
import org.eclipse.leshan.core.SecurityMode;
import org.eclipse.leshan.core.oscore.InvalidOscoreSettingException;
import org.eclipse.leshan.core.oscore.OscoreValidator;

/**
* A default implementation of {@link BootstrapConsistencyChecker}
*/
public class DefaultBootstrapConsistencyChecker extends BaseBootstrapConsistencyChecker {

private OscoreValidator oscoreValidator = new OscoreValidator();

@Override
protected void checkBootstrapServerInfo(ServerInfo BootstrapServerInfo, List<String> errors) {
checkCertificateIsValid(BootstrapServerInfo, errors);
protected void checkBootstrapServerInfo(ServerInfo bootstrapServerInfo, List<String> errors) {
checkCertificateIsValid(bootstrapServerInfo, errors);
checkOscoreIsValid(bootstrapServerInfo, errors);
}

@Override
protected void checkDeviceMangementServerInfo(DmServerInfo serverInfo, List<String> errors) {
checkCertificateIsValid(serverInfo, errors);

checkOscoreIsValid(serverInfo, errors);
}

private void checkCertificateIsValid(ServerInfo serverInfo, List<String> errors) {
Expand All @@ -49,4 +54,14 @@ private void checkCertificateIsValid(ServerInfo serverInfo, List<String> errors)
}
}
}

private void checkOscoreIsValid(ServerInfo serverInfo, List<String> errors) {
if (serverInfo.useOscore) {
try {
oscoreValidator.validateOscoreSetting(serverInfo.oscoreSetting);
} catch (InvalidOscoreSettingException e) {
errors.add(e.getMessage());
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
* Contributors:
* Zebra Technologies - initial API and implementation
* Michał Wadowski (Orange) - Improved compliance with rfc6690
* Rikard Höglund (RISE SICS) - Additions to support OSCORE
*******************************************************************************/
package org.eclipse.leshan.client.californium.request;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,27 +28,37 @@
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.oscore.AeadAlgorithm;
import org.eclipse.leshan.core.oscore.HkdfAlgorithm;
import org.eclipse.leshan.core.oscore.InvalidOscoreSettingException;
import org.eclipse.leshan.core.oscore.OscoreSetting;
import org.eclipse.leshan.core.oscore.OscoreValidator;
import org.eclipse.leshan.core.response.ReadResponse;
import org.eclipse.leshan.core.response.WriteResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* A simple {@link LwM2mInstanceEnabler} for the OSCORE Security (21) object.
* <p>
* Note it must be used with a minimum 2.0 version of the object because previously String was used instead of byte[]
* for recipientId, SenderId, MasterKey, MasterSalt.
* <p>
* See for more details : https://github.com/OpenMobileAlliance/OMA_LwM2M_for_Developers/issues/521
*/
public class Oscore extends BaseInstanceEnabler {

private static final Logger LOG = LoggerFactory.getLogger(Security.class);

private final static List<Integer> 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<Integer> 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;
private String recipientId;
private int aeadAlgorithm;
private int hkdfAlgorithm;
private String masterSalt;
private byte[] masterSecret;
private byte[] senderId;
private byte[] recipientId;
private AeadAlgorithm aeadAlgorithm;
private HkdfAlgorithm hkdfAlgorithm;
private byte[] masterSalt;

public Oscore() {

Expand All @@ -57,75 +67,77 @@ public Oscore() {
/**
* Default constructor.
*/
public Oscore(int instanceId, String masterSecret, String senderId, String recipientId, int aeadAlgorithm,
int hkdfAlgorithm, String masterSalt) {
public Oscore(int instanceId, OscoreSetting oscoreSetting) {
super(instanceId);
this.masterSecret = masterSecret;
this.senderId = senderId;
this.recipientId = recipientId;
this.aeadAlgorithm = aeadAlgorithm;
this.hkdfAlgorithm = hkdfAlgorithm;
this.masterSalt = masterSalt;
}

/**
* Constructor providing some default values.
*
* aeadAlgorithm = 10; //AES_CCM_16_64_128m hmacAlgorithm = -10; //HKDF_HMAC_SHA_256, masterSalt = "";
*
*/
public Oscore(int instanceId, String masterSecret, String senderId, String recipientId) {
this(instanceId, masterSecret, senderId, recipientId, 10, -10, "");
try {
new OscoreValidator().validateOscoreSetting(oscoreSetting);
} catch (InvalidOscoreSettingException e) {
throw new IllegalArgumentException("Invalid " + oscoreSetting, e);
}
this.masterSecret = oscoreSetting.getMasterSecret();
this.senderId = oscoreSetting.getSenderId();
this.recipientId = oscoreSetting.getRecipientId();
this.aeadAlgorithm = oscoreSetting.getAeadAlgorithm();
this.hkdfAlgorithm = oscoreSetting.getHkdfAlgorithm();
this.masterSalt = oscoreSetting.getMasterSalt();
}

@Override
public WriteResponse write(ServerIdentity identity, boolean replace, int resourceId, LwM2mResource value) {
LOG.debug("Write on resource {}: {}", resourceId, value);

// restricted to BS server?
if (!identity.isSystem())
LOG.debug("Write on resource {}: {}", resourceId, value);

switch (resourceId) {

case OSCORE_Master_Secret:
if (value.getType() != Type.STRING) {
case OSCORE_MASTER_SECRET:
if (value.getType() != Type.OPAQUE) {
return WriteResponse.badRequest("invalid type");
}
masterSecret = (String) value.getValue();
masterSecret = (byte[]) value.getValue();
return WriteResponse.success();

case OSCORE_Sender_ID:
if (value.getType() != Type.STRING) {
case OSCORE_SENDER_ID:
if (value.getType() != Type.OPAQUE) {
return WriteResponse.badRequest("invalid type");
}
senderId = (String) value.getValue();
senderId = (byte[]) value.getValue();
return WriteResponse.success();

case OSCORE_Recipient_ID:
if (value.getType() != Type.STRING) {
case OSCORE_RECIPIENT_ID:
if (value.getType() != Type.OPAQUE) {
return WriteResponse.badRequest("invalid type");
}
recipientId = (String) value.getValue();
recipientId = (byte[]) value.getValue();
return WriteResponse.success();

case OSCORE_AEAD_Algorithm:
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:
Long longValue = (Long) value.getValue();
aeadAlgorithm = AeadAlgorithm.fromValue(longValue);
if (aeadAlgorithm != null) {
return WriteResponse.success();
} else {
return WriteResponse.badRequest("unknown algorithm " + longValue);
}
}
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) {
Long longValue = (Long) value.getValue();
hkdfAlgorithm = HkdfAlgorithm.fromValue(longValue);
if (hkdfAlgorithm != null) {
return WriteResponse.success();
} else {
return WriteResponse.badRequest("unknown algorithm " + longValue);
}
}
case OSCORE_MASTER_SALT:
if (value.getType() != Type.OPAQUE) {
return WriteResponse.badRequest("invalid type");
}
masterSalt = (String) value.getValue();
masterSalt = (byte[]) value.getValue();
return WriteResponse.success();

default:
Expand All @@ -136,27 +148,27 @@ public WriteResponse write(ServerIdentity identity, boolean replace, int resourc

@Override
public ReadResponse read(ServerIdentity identity, int resourceid) {
LOG.debug("Read on resource {}", resourceid);
// only accessible for internal read?
if (!identity.isSystem())
LOG.debug("Read on resource {}", resourceid);

switch (resourceid) {

case OSCORE_Master_Secret:
case OSCORE_MASTER_SECRET:
return ReadResponse.success(resourceid, masterSecret);

case OSCORE_Sender_ID:
case OSCORE_SENDER_ID:
return ReadResponse.success(resourceid, senderId);

case OSCORE_Recipient_ID:
case OSCORE_RECIPIENT_ID:
return ReadResponse.success(resourceid, recipientId);

case OSCORE_AEAD_Algorithm:
return ReadResponse.success(resourceid, aeadAlgorithm);
case OSCORE_AEAD_ALGORITHM:
return ReadResponse.success(resourceid, aeadAlgorithm.getValue());

case OSCORE_HMAC_Algorithm:
return ReadResponse.success(resourceid, hkdfAlgorithm);
case OSCORE_HMAC_ALGORITHM:
return ReadResponse.success(resourceid, hkdfAlgorithm.getValue());

case OSCORE_Master_Salt:
case OSCORE_MASTER_SALT:
return ReadResponse.success(resourceid, masterSalt);

default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@
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.request.argument.Arguments;
import org.eclipse.leshan.core.node.ObjectLink;
import org.eclipse.leshan.core.request.argument.Arguments;
import org.eclipse.leshan.core.response.ExecuteResponse;
import org.eclipse.leshan.core.response.ReadResponse;
import org.eclipse.leshan.core.response.WriteResponse;
Expand Down Expand Up @@ -84,10 +84,9 @@ public Security(String serverUri, boolean bootstrapServer, int securityMode, byt
/**
* Returns a new security instance (OSCORE only) for a bootstrap server.
*/
public static Security oscoreOnlyBootstrap(String serverUri, Integer shortServerId, int oscoreObjectInstanceId) {
return new Security(serverUri, true, SecurityMode.NO_SEC.code, new byte[0], new byte[0], new byte[0],
shortServerId, CertificateUsage.DOMAIN_ISSUER_CERTIFICATE.code,
new ObjectLink(OSCORE, oscoreObjectInstanceId));
public static Security oscoreOnlyBootstrap(String serverUri, int oscoreObjectInstanceId) {
return new Security(serverUri, true, SecurityMode.NO_SEC.code, new byte[0], new byte[0], new byte[0], null,
CertificateUsage.DOMAIN_ISSUER_CERTIFICATE.code, new ObjectLink(OSCORE, oscoreObjectInstanceId));
}

/**
Expand Down
Loading

0 comments on commit 56669c7

Please sign in to comment.