net: lwm2m: Senml Opaque BASE64URL support and fix padding
LwM2M specification is only mentioning BASE64 encoding but SenML-JSON specification is talking about BASE64URL encoding. This change is silently accepting both formats and automatically pads the data if padding is dropped. Signed-off-by: Juha Heiskanen <juha.heiskanen@nordicsemi.no>
This commit is contained in:
parent
52be3030aa
commit
164680d696
1 changed files with 133 additions and 37 deletions
|
@ -45,6 +45,9 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME);
|
|||
#define OBJECT_SEPARATOR(f) ((f & WRITER_OUTPUT_VALUE) ? "," : "")
|
||||
|
||||
#define TOKEN_BUF_LEN 64
|
||||
#define BASE64_OUTPUT_MIN_LENGTH 4
|
||||
#define BASE64_MODULO_LENGTH(x) (x % BASE64_OUTPUT_MIN_LENGTH)
|
||||
#define BASE64_BYTES_TO_MODULO(x) (BASE64_OUTPUT_MIN_LENGTH - x)
|
||||
|
||||
struct json_out_formatter_data {
|
||||
/* flags */
|
||||
|
@ -875,12 +878,71 @@ static int get_bool(struct lwm2m_input_context *in, bool *value)
|
|||
return fd->value_len;
|
||||
}
|
||||
|
||||
static void base64_url_safe_decode(uint8_t *data_buf, size_t buf_len)
|
||||
{
|
||||
uint8_t *ptr = data_buf;
|
||||
|
||||
for (size_t i = 0; i < buf_len; i++) {
|
||||
if (*ptr == '-') {
|
||||
/* replace '-' with "+" */
|
||||
*ptr = '+';
|
||||
} else if (*ptr == '_') {
|
||||
/* replace '_' with "/" */
|
||||
*ptr = '/';
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
static int store_padded_modulo(uint16_t *padded_length, uint8_t *padded_buf, uint8_t *data_tail,
|
||||
uint16_t data_length)
|
||||
{
|
||||
uint16_t padded_len = BASE64_MODULO_LENGTH(data_length);
|
||||
|
||||
if (data_length < padded_len) {
|
||||
return -ENODATA;
|
||||
}
|
||||
*padded_length = padded_len;
|
||||
|
||||
if (padded_len) {
|
||||
uint8_t *tail_ptr;
|
||||
|
||||
tail_ptr = data_tail - padded_len;
|
||||
memcpy(padded_buf, tail_ptr, padded_len);
|
||||
for (size_t i = padded_len; i < BASE64_OUTPUT_MIN_LENGTH; i++) {
|
||||
padded_buf[i] = '=';
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int store_modulo_data(struct lwm2m_senml_json_context *block_ctx, uint8_t *data_ptr,
|
||||
uint16_t data_length)
|
||||
{
|
||||
block_ctx->base64_buf_len = BASE64_MODULO_LENGTH(data_length);
|
||||
if (data_length < block_ctx->base64_buf_len) {
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
if (block_ctx->base64_buf_len) {
|
||||
uint8_t *data_tail_ptr;
|
||||
|
||||
data_tail_ptr = data_ptr + (data_length - block_ctx->base64_buf_len);
|
||||
memcpy(block_ctx->base64_mod_buf, data_tail_ptr, block_ctx->base64_buf_len);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_opaque(struct lwm2m_input_context *in, uint8_t *value, size_t buflen,
|
||||
struct lwm2m_opaque_context *opaque, bool *last_block)
|
||||
{
|
||||
struct json_in_formatter_data *fd;
|
||||
struct lwm2m_senml_json_context *block_ctx;
|
||||
int in_len;
|
||||
int in_len, ret;
|
||||
uint8_t module_buf[BASE64_OUTPUT_MIN_LENGTH];
|
||||
uint16_t padded_length = 0;
|
||||
uint8_t padded_buf[BASE64_OUTPUT_MIN_LENGTH];
|
||||
size_t buffer_base64_length;
|
||||
|
||||
block_ctx = seml_json_context_get(in->block_ctx);
|
||||
|
||||
|
@ -891,55 +953,57 @@ static int get_opaque(struct lwm2m_input_context *in, uint8_t *value, size_t buf
|
|||
|
||||
uint8_t *data_ptr = in->in_cpkt->data + fd->value_offset;
|
||||
|
||||
/* Decode from url safe to normal */
|
||||
base64_url_safe_decode(data_ptr, fd->value_len);
|
||||
|
||||
if (opaque->remaining == 0) {
|
||||
size_t original_size = fd->value_len;
|
||||
size_t base64_length;
|
||||
|
||||
if (block_ctx) {
|
||||
if (block_ctx->base64_buf_len) {
|
||||
uint8_t module_buf[4];
|
||||
size_t buffer_module_length = 4 - block_ctx->base64_buf_len;
|
||||
size_t b_to_module;
|
||||
|
||||
if (fd->value_len < buffer_module_length) {
|
||||
b_to_module = BASE64_BYTES_TO_MODULO(block_ctx->base64_buf_len);
|
||||
|
||||
if (fd->value_len < b_to_module) {
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
fd->value_len -= buffer_module_length;
|
||||
fd->value_len -= b_to_module;
|
||||
memcpy(module_buf, block_ctx->base64_mod_buf,
|
||||
block_ctx->base64_buf_len);
|
||||
memcpy(module_buf + block_ctx->base64_buf_len, data_ptr,
|
||||
buffer_module_length);
|
||||
b_to_module);
|
||||
|
||||
size_t buffer_base64_length;
|
||||
|
||||
if (base64_decode(module_buf, 4, &buffer_base64_length, module_buf,
|
||||
4) < 0) {
|
||||
if (base64_decode(module_buf, BASE64_OUTPUT_MIN_LENGTH,
|
||||
&buffer_base64_length, module_buf,
|
||||
BASE64_OUTPUT_MIN_LENGTH) < 0) {
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
block_ctx->base64_buf_len = 0;
|
||||
if (in->block_ctx->last_block) {
|
||||
ret = store_padded_modulo(&padded_length, padded_buf,
|
||||
data_ptr + original_size,
|
||||
fd->value_len);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
fd->value_len -= padded_length;
|
||||
|
||||
if (!in->block_ctx->last_block) {
|
||||
block_ctx->base64_buf_len = (fd->value_len % 4);
|
||||
if (fd->value_len < block_ctx->base64_buf_len) {
|
||||
return -ENODATA;
|
||||
} else {
|
||||
ret = store_modulo_data(block_ctx, data_ptr,
|
||||
fd->value_len);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (block_ctx->base64_buf_len) {
|
||||
uint8_t *data_tail_ptr;
|
||||
|
||||
data_tail_ptr =
|
||||
data_ptr + (original_size -
|
||||
block_ctx->base64_buf_len);
|
||||
memcpy(block_ctx->base64_mod_buf, data_tail_ptr,
|
||||
block_ctx->base64_buf_len);
|
||||
fd->value_len -= block_ctx->base64_buf_len;
|
||||
}
|
||||
fd->value_len -= block_ctx->base64_buf_len;
|
||||
}
|
||||
|
||||
/* Decode rest of data and do memmove */
|
||||
if (base64_decode(data_ptr, original_size, &base64_length,
|
||||
data_ptr + buffer_module_length,
|
||||
fd->value_len) < 0) {
|
||||
data_ptr + b_to_module, fd->value_len) < 0) {
|
||||
return -ENODATA;
|
||||
}
|
||||
fd->value_len = base64_length;
|
||||
|
@ -948,18 +1012,22 @@ static int get_opaque(struct lwm2m_input_context *in, uint8_t *value, size_t buf
|
|||
memcpy(data_ptr, module_buf, buffer_base64_length);
|
||||
fd->value_len += buffer_base64_length;
|
||||
} else {
|
||||
block_ctx->base64_buf_len = (fd->value_len % 4);
|
||||
if (fd->value_len < block_ctx->base64_buf_len) {
|
||||
return -ENODATA;
|
||||
}
|
||||
if (in->block_ctx->last_block) {
|
||||
ret = store_padded_modulo(&padded_length, padded_buf,
|
||||
data_ptr + original_size,
|
||||
original_size);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
fd->value_len -= padded_length;
|
||||
|
||||
if (block_ctx->base64_buf_len) {
|
||||
uint8_t *data_tail_ptr =
|
||||
data_ptr +
|
||||
(original_size - block_ctx->base64_buf_len);
|
||||
} else {
|
||||
ret = store_modulo_data(block_ctx, data_ptr,
|
||||
fd->value_len);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
memcpy(block_ctx->base64_mod_buf, data_tail_ptr,
|
||||
block_ctx->base64_buf_len);
|
||||
fd->value_len -= block_ctx->base64_buf_len;
|
||||
}
|
||||
|
||||
|
@ -969,14 +1037,42 @@ static int get_opaque(struct lwm2m_input_context *in, uint8_t *value, size_t buf
|
|||
}
|
||||
fd->value_len = base64_length;
|
||||
}
|
||||
|
||||
if (padded_length) {
|
||||
if (base64_decode(padded_buf, BASE64_OUTPUT_MIN_LENGTH,
|
||||
&buffer_base64_length, padded_buf,
|
||||
BASE64_OUTPUT_MIN_LENGTH) < 0) {
|
||||
return -ENODATA;
|
||||
}
|
||||
/* Add padded tail */
|
||||
memcpy(data_ptr + fd->value_len, padded_buf, buffer_base64_length);
|
||||
fd->value_len += buffer_base64_length;
|
||||
}
|
||||
/* Set zero because total length is unknown */
|
||||
opaque->len = 0;
|
||||
} else {
|
||||
ret = store_padded_modulo(&padded_length, padded_buf,
|
||||
data_ptr + original_size, original_size);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (base64_decode(data_ptr, fd->value_len, &base64_length, data_ptr,
|
||||
fd->value_len) < 0) {
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
fd->value_len = base64_length;
|
||||
if (padded_length) {
|
||||
if (base64_decode(padded_buf, BASE64_OUTPUT_MIN_LENGTH,
|
||||
&buffer_base64_length, padded_buf,
|
||||
BASE64_OUTPUT_MIN_LENGTH) < 0) {
|
||||
return -ENODATA;
|
||||
}
|
||||
/* Add padded tail */
|
||||
memcpy(data_ptr + fd->value_len, padded_buf, buffer_base64_length);
|
||||
fd->value_len += buffer_base64_length;
|
||||
}
|
||||
opaque->len = fd->value_len;
|
||||
}
|
||||
opaque->remaining = fd->value_len;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue