Skip to content

Commit

Permalink
#1203: Add Oscore SecurityInfo support to Server and BS Server demo
Browse files Browse the repository at this point in the history
  • Loading branch information
sbernard31 committed Apr 28, 2022
1 parent 915f1c5 commit cdfb550
Show file tree
Hide file tree
Showing 18 changed files with 389 additions and 117 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,11 @@ public static LeshanBootstrapServer createBsLeshanServer(LeshanBsServerDemoCLI c
builder.setConfigStore(bsConfigStore);
builder.setSecurityStore(new BootstrapSecurityStoreAdapter(securityStore));

// TODO OSCORE Temporary cli option to deactivate OSCORE
if (!cli.main.disableOscore) {
builder.setEnableOscore(true);
}

return builder.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ public static class BootstrapServerGeneralSection extends GeneralSection {
"Set the filename for the configuration.", //
"Default: ${DEFAULT-VALUE}" })
public String configFilename;

@Option(names = { "-no", "--disable-oscore" },
description = { //
"Disable experimental OSCORE feature." })
public Boolean disableOscore = false;
}

/* ********************************** DTLS Section ******************************** */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,9 @@ export default {
}
// apply endpoint to security
res.security.endpoint = res.endpoint
if (res.security) {
res.security.endpoint = res.endpoint;
}
return res;
},
Expand Down
46 changes: 7 additions & 39 deletions leshan-bsserver-demo/webapp/src/components/wizard/SecurityStep.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,12 @@
a demo.
</p>
</v-card-text>
<v-form
ref="form"
:value="valid"
@input="$emit('update:valid', !useDTLS || $event)"
>
<v-switch
class="pl-5"
v-model="useDTLS"
@change="updateUseDTLS($event)"
label="Using (D)TLS"
></v-switch>
<v-form ref="form" :value="valid" @input="$emit('update:valid', $event)">
<security-info-input
v-show="useDTLS"
:mode="internalSecurityInfo.tls.mode"
:details="internalSecurityInfo.tls.details"
@update:mode="updateMode($event)"
@update:details="updateDetails($event)"
:tls.sync="internalSecurityInfo.tls"
:oscore.sync="internalSecurityInfo.oscore"
@update:tls="$emit('input', internalSecurityInfo)"
@update:oscore="$emit('input', internalSecurityInfo)"
/>
</v-form>
</v-card>
Expand All @@ -53,40 +42,19 @@ export default {
},
data() {
return {
useDTLS: false,
internalSecurityInfo: { tls: { mode: "psk", details: {} } },
internalSecurityInfo: {},
};
},
watch: {
value(v) {
if (!v) {
this.useDTLS = false;
this.internalSecurityInfo = { tls: { mode: "psk", details: {} } };
this.internalSecurityInfo = {};
} else {
this.useDTLS = true;
this.internalSecurityInfo = v;
}
},
},
methods: {
updateUseDTLS(useDTLS) {
if (useDTLS) {
this.$emit("input", this.internalSecurityInfo);
this.resetValidation();
this.$emit("update:valid", false);
} else {
this.$emit("input", null);
this.$emit("update:valid", true);
}
},
updateMode(mode) {
this.internalSecurityInfo.tls.mode = mode;
this.$emit("input", this.internalSecurityInfo);
},
updateDetails(details) {
this.internalSecurityInfo.tls.details = details;
this.$emit("input", this.internalSecurityInfo);
},
resetValidation() {
this.$refs.form.resetValidation();
},
Expand Down
2 changes: 2 additions & 0 deletions leshan-bsserver-demo/webapp/src/plugins/icons.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
mdiKeyPlus,
mdiLeadPencil,
mdiLockOpenRemove,
mdiLockOutline,
mdiMagnify,
mdiPlay,
mdiServerSecurity,
Expand Down Expand Up @@ -66,6 +67,7 @@ const _icons = {
mdiKeyPlus,
mdiLeadPencil,
mdiLockOpenRemove,
mdiLockOutline,
mdiMagnify,
mdiPlay,
mdiServerSecurity,
Expand Down
2 changes: 1 addition & 1 deletion leshan-bsserver-demo/webapp/src/views/Bootstrap.vue
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ export default {
},
onAdd(config) {
if (config.security) {
if (config.security && (config.security.tls || config.security.oscore)) {
// if we have security we try to add security first
this.axios.put("api/security/clients/", config.security).then(() => {
this.addConfig(config);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.security.GeneralSecurityException;
import java.security.PublicKey;

import org.eclipse.leshan.core.oscore.OscoreSetting;
import org.eclipse.leshan.core.util.Hex;
import org.eclipse.leshan.core.util.SecurityUtil;
import org.eclipse.leshan.server.security.SecurityInfo;
Expand Down Expand Up @@ -49,8 +50,9 @@ public SecurityInfo deserialize(JsonParser p, DeserializationContext ctxt) throw
}

// handle dtls
JsonNode oTls = node.get("tls");
if (node.has("tls")) {
JsonNode oTls = node.get("tls");

if (oTls.getNodeType() != JsonNodeType.OBJECT) {
throw new JsonParseException(p, "tls field should be a json object");
}
Expand Down Expand Up @@ -103,6 +105,54 @@ public SecurityInfo deserialize(JsonParser p, DeserializationContext ctxt) throw
throw new JsonParseException(p, "Invalid security info content");
}
}
// Handle Oscore
else if (node.has("oscore")) {
JsonNode oOscore = node.get("oscore");
if (oOscore.getNodeType() != JsonNodeType.OBJECT) {
throw new JsonParseException(p, "oscore field should be a json object");
}
// get Recipient ID
byte[] rid;
if (oOscore.has("rid")) {
rid = Hex.decodeHex(oOscore.get("rid").asText().toCharArray());
} else {
throw new JsonParseException(p, "Missing 'rid' field (Recipient ID)");
}

// get Sender ID
byte[] sid;
if (oOscore.has("sid")) {
sid = Hex.decodeHex(oOscore.get("sid").asText().toCharArray());
} else {
throw new JsonParseException(p, "Missing 'sid' field (Sender ID)");
}

// get Master secret
byte[] msec;
if (oOscore.has("msec")) {
msec = Hex.decodeHex(oOscore.get("msec").asText().toCharArray());
} else {
throw new JsonParseException(p, "Missing 'msec' field (Master Secret)");
}

// TODO OSCORE add support for msalt, aead and hkdf

// get Master salt
// byte[] msalt;
// if (oOscore.has("msalt")) {
// msalt = Hex.decodeHex(oOscore.get("msalt").asText().toCharArray());
// } else {
// msalt = new byte[0];
// }

// TODO OSCORE use dedicated enum / class for algorithm
// waiting use default value :
// master salf : empty string
// aead : AES_CCM_16_64_128("AES-CCM-16-64-128", 10, 128, 64),
// hkdf : HKDF_HMAC_SHA_256("HKDF-SHA-256", -10, 256, 0),

return SecurityInfo.newOscoreInfo(endpoint, new OscoreSetting(sid, rid, msec, 10, -10, null));
}
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,20 @@ public void serialize(SecurityInfo securityInfo, JsonGenerator gen, SerializerPr
oTls.put("mode", "x509");
}
}
if (securityInfo.useOSCORE()) {
// handle OSCORE case :
ObjectNode oOscore = JsonNodeFactory.instance.objectNode();
oSecInfo.set("oscore", oOscore);
oOscore.put("rid", Hex.encodeHexString(securityInfo.getOscoreSetting().getRecipientId()));
oOscore.put("sid", Hex.encodeHexString(securityInfo.getOscoreSetting().getSenderId()));
oOscore.put("msec", Hex.encodeHexString(securityInfo.getOscoreSetting().getMasterSecret()));
// TODO OSCORE it should be possible to use an empty byte array for Master salf. (currently it failed)
if (securityInfo.getOscoreSetting().getMasterSalt() != null) {
oOscore.put("msalt", Hex.encodeHexString(securityInfo.getOscoreSetting().getMasterSalt()));
}
oOscore.put("aead", securityInfo.getOscoreSetting().getAeadAlgorithm().getValue());
oOscore.put("hkdf", securityInfo.getOscoreSetting().getHkdfAlgorithm().getValue());
}
gen.writeTree(oSecInfo);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,11 @@ protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws Se
} catch (JsonParseException e) {
LOG.warn("Could not parse request body", e);
resp.setStatus(HttpServletResponse.SC_BAD_REQUEST);
resp.getWriter().append("Invalid request body").flush();
resp.getWriter().append("Invalid request body");
if (e.getMessage() != null) {
resp.getWriter().append(": ").append(e.getMessage());
}
resp.getWriter().flush();
} catch (RuntimeException e) {
LOG.warn("unexpected error for request " + req.getPathInfo(), e);
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
Expand Down Expand Up @@ -176,8 +180,7 @@ protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws
resp.setStatus(HttpServletResponse.SC_OK);
} else {
resp.setContentType("application/json");
resp.getOutputStream()
.write("{\"message\":\"not_found\"}".getBytes(StandardCharsets.UTF_8));
resp.getOutputStream().write("{\"message\":\"not_found\"}".getBytes(StandardCharsets.UTF_8));
resp.setStatus(HttpServletResponse.SC_OK);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<!-----------------------------------------------------------------------------
* Copyright (c) 2021 Sierra Wireless and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v20.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.html.
----------------------------------------------------------------------------->
<template>
<div>
<!-- Sender ID field -->
<v-textarea
filled
label="Sender ID"
rows="2"
v-model="oscore.sid"
:rules="[
(v) => !!v || 'Sender ID is required',
(v) => /^[0-9a-fA-F]+$/.test(v) || 'Hexadecimal format is expected',
]"
@input="$emit('input', oscore)"
hint="Hexadecimal format"
spellcheck="false"
></v-textarea>
<!-- Master Secret field -->
<v-textarea
filled
label="Master Secret"
rows="2"
v-model="oscore.msec"
:rules="[
(v) => !!v || 'Master Secret is required',
(v) => /^[0-9a-fA-F]+$/.test(v) || 'Hexadecimal format is expected',
]"
@input="$emit('input', oscore)"
hint="Hexadecimal format"
spellcheck="false"
></v-textarea>
<!-- Recipient ID field -->
<v-textarea
filled
label="Recipient ID"
rows="2"
v-model="oscore.rid"
:rules="[
(v) => !!v || 'Recipient ID is required',
(v) => /^[0-9a-fA-F]+$/.test(v) || 'Hexadecimal format is expected',
]"
@input="$emit('input', oscore)"
hint="Hexadecimal format"
spellcheck="false"
></v-textarea>
</div>
</template>
<script>
export default {
props: { value: Object },
data() {
return {
oscore: this.value,
};
},
watch: {
value(v) {
this.oscore = v;
},
},
};
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,17 @@
* http://www.eclipse.org/org/documents/edl-v10.html.
----------------------------------------------------------------------------->
<template>
<div v-if="securityInfo && securityInfo.tls">
<v-chip small>
<div v-if="securityInfo && (securityInfo.tls || securityInfo.oscore)">
<v-chip small v-if="securityInfo.tls">
<v-icon left small>
{{ modeIcon }}
</v-icon>
{{ securityInfo.tls.mode }}
</v-chip>
<v-chip small v-if="securityInfo.oscore">
<v-icon left small> {{$icons.mdiLockOutline}} </v-icon>
oscore
</v-chip>
</div>
<div v-else>
<v-chip small>
Expand Down
Loading

0 comments on commit cdfb550

Please sign in to comment.