Commit 9af0527c authored by Olaf Bergmann's avatar Olaf Bergmann

UTF8-encode psk_identity for transfer

RFC 7925 recommends that DTLS implementations should treat the
contents of psk_identity as opaque data whereas TLS originally
defined this as UTF8 encoded data and check for correct encoding.
To support implementations that treat psk_identity as UTF8, this
change encodes access tickets in UTF8 for transfer and decodes
upon receipt. For encrypted data, the average growth for this
encoding would be 25 % as in average half of the input bytes would
be greater than 127 and thus required an additional byte for
UTF8-encoding.
parent 56314ff5
......@@ -48,7 +48,8 @@ libdcaf_a_SOURCES = \
src/dcaf_mem.c \
src/dcaf_optlist.c \
src/dcaf_prng.c \
src/dcaf_transaction.c
src/dcaf_transaction.c \
src/dcaf_utf8.c
## Public header files and their installation location.
libdcaf_includedir = $(includedir)/dcaf/
......@@ -71,6 +72,7 @@ libdcaf_include_HEADERS = \
$(top_srcdir)/include/dcaf/dcaf_prng.h \
$(top_srcdir)/include/dcaf/dcaf_transaction.h \
$(top_srcdir)/include/dcaf/dcaf_address.h \
$(top_srcdir)/include/dcaf/dcaf_utf8.h \
$(top_builddir)/include/dcaf/dcaf.h
## Include autogen.sh in distribution but do not install it.
......
/*
* dcaf_base64.h -- UTF-8 encoder/decoder for DCAF
*
* Copyright (C) 2020 Olaf Bergmann <bergmann@tzi.org>
*
* This file is part of the DCAF library libdcaf. Please see README
* for terms of use.
*/
#ifndef DCAF_UTF8_H
#define DCAF_UTF8_H 1
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
/**
* UTF8-encodes @p srclen bytes from @p src into the buffer @p
* dst. @p *dstlen specifies the size of @p dst and is overwritten
* with the number of bytes written. In case of error, the value of @p
* *dstlen is undefined. This function only encodes 8-bit values, i.e.,
* code points between 0 and 255.
*
* @param dst The destination buffer to hold the base64-encoded input.
* @param dstlen A pointer that is updated with the number of bytes
* that have actually been written. The initial value of
* of @p *dstlen must denote the maximum size of @p dst.
* @param src The source to be encoded.
* @param srclen The size of @p src in bytes.
*
* @return True if @p src successfully has been encoded, false otherwise.
* In case of an error, the value written to @p *dstlen is undefined.
*/
bool uint8_to_utf8(char *dst, size_t *dstlen, const uint8_t *src, size_t srclen);
/**
* UTF8-decodes @p srclen bytes from @p src into the buffer @p dst.
* @p *dstlen specifies the size of @p dst and is overwritten with the
* number of bytes written. In case of error, the value of @p *dstlen
* is undefined. This function only decodes multibyte sequences that
* lead to a single byte result, i.e., a code point between 0 and 255.
* Input bytes larger than 195 hence will result in an error.
*
* @param dst The destination buffer to hold the decoded data.
* @param dstlen A pointer that is updated with the number of bytes
* that have actually been written. The initial value of
* of @p *dstlen must denote the maximum size of @p dst.
* @param src The source to be Base64-decoded.
* @param srclen The size of @p src in bytes.
*
* @return True if @p src successfully has been decoded, false otherwise.
* In case of an error, the value written to @p *dstlen is undefined.
*/
bool utf8_to_uint8(uint8_t *dst, size_t *dstlen, const char *src, size_t srclen);
#endif /* DCAF_UTF8_H */
......@@ -13,32 +13,9 @@
#include <stdint.h>
#include <stdio.h>
#define DCAF_BASE64ENCODE_PSKIDENTITY 1
#define DCAF_UTF8ENCODE_PSKIDENTITY 1
#define DCAF_MAX_PSK_IDENTITY 256
#define DCAF_CBOR_MAJOR_TYPE_BASE64 34
static size_t encode_tag(int type, uint8_t *buf) {
/* TODO: handle multiple bytes other than 24..255 */
buf[0] = (6 << 5) + 24;
buf[1] = type;
return 2;
}
static int64_t decode_tag(const uint8_t *data, size_t datalen) {
if (datalen > 0 && (data[0] >> 5) == 6) { /* found tag */
uint8_t val = data[0] & 0x1f;
/* TODO: handle multiple bytes other than 24..65535 */
if (val < 24)
return val;
else if (val == 24)
return datalen > 1 ? data[1] : -1;
else if (val == 25)
return datalen > 2 ? ((data[1] << 8) + data[2]) : -1;
}
return -1;
}
#ifdef RIOT_VERSION
#include "libcoap_init.h"
#ifdef MODULE_PRNG
......@@ -52,6 +29,10 @@ static int64_t decode_tag(const uint8_t *data, size_t datalen) {
#include "dcaf/utlist.h"
#include "dcaf/dcaf_cbor.h"
#if DCAF_UTF8ENCODE_PSKIDENTITY
#include "dcaf/dcaf_utf8.h"
#endif
#include "dcaf/aif.h"
#include "dcaf/cwt.h"
......@@ -336,19 +317,18 @@ handle_ticket_transfer(dcaf_context_t *dcaf_context,
ctx = dcaf_get_coap_context(dcaf_context);
assert(ctx);
#ifdef DCAF_BASE64ENCODE_PSKIDENTITY
#if DCAF_UTF8ENCODE_PSKIDENTITY
/* write tag 34 (base64-encoded) */
encode_tag(DCAF_CBOR_MAJOR_TYPE_BASE64, identity);
identity_len = sizeof(identity) - 2;
if (!dcaf_base64_encode(identity + 2, &identity_len, ticket_face->v.bytes, ticket_face->length)) {
dcaf_log(DCAF_LOG_WARNING, "Cannot Base64-encode ticket face. Sending raw.");
identity_len = sizeof(identity);
if (!uint8_to_utf8((char *)identity, &identity_len, ticket_face->v.bytes, ticket_face->length)) {
dcaf_log(DCAF_LOG_WARNING, "Cannot encode ticket face. Sending raw.");
identity_len = ticket_face->length;
memcpy(identity, ticket_face->v.bytes, identity_len);
}
#else /* !DCAF_BASE64ENCODE_PSKIDENTITY */
#else /* !DCAF_UTF8ENCODE_PSKIDENTITY */
identity_len = ticket_face->length;
memcpy(identity, ticket_face->v.bytes, identity_len);
#endif /* !DCAF_BASE64ENCODE_PSKIDENTITY */
#endif /* !DCAF_UTF8ENCODE_PSKIDENTITY */
#if !defined(LIBCOAP_VERSION) || (LIBCOAP_VERSION < 4003000U)
session = coap_new_client_session_psk(ctx, NULL,
......@@ -363,8 +343,6 @@ handle_ticket_transfer(dcaf_context_t *dcaf_context,
COAP_SET_STR(&setup_data.psk_info.identity, identity_len, identity);
COAP_SET_STR(&setup_data.psk_info.key, cinfo->key->length, cinfo->key->data);
dcaf_log(DCAF_LOG_INFO, "Set key to:\n");
dcaf_debug_hexdump(setup_data.psk_info.key.s, setup_data.psk_info.key.length);
session = coap_new_client_session_psk2(ctx, NULL,
&t->state.future->remote,
......@@ -1017,21 +995,16 @@ dcaf_get_server_psk(const coap_session_t *session,
const uint8_t *identity, size_t identity_len,
uint8_t *psk, size_t max_psk_len) {
dcaf_ticket_t *t = NULL;
#ifdef DCAF_BASE64ENCODE_PSKIDENTITY
#if DCAF_UTF8ENCODE_PSKIDENTITY
static uint8_t identity_buf[DCAF_MAX_PSK_IDENTITY];
if (decode_tag(identity, identity_len) == DCAF_CBOR_MAJOR_TYPE_BASE64) {
size_t identity_buflen = sizeof(identity_buf);
if (!dcaf_base64_decode(identity_buf, &identity_buflen, identity + 2, identity_len - 2)) {
dcaf_log(DCAF_LOG_WARNING, "Cannot Base64-decode ticket face. Parsing raw data.\n");
} else {
identity = identity_buf;
identity_len = identity_buflen;
}
size_t identity_buflen = sizeof(identity_buf);
if (!utf8_to_uint8(identity_buf, &identity_buflen, (const char *)identity, identity_len)) {
dcaf_log(DCAF_LOG_WARNING, "Cannot decode ticket face. Parsing raw data.\n");
} else {
identity = identity_buf;
identity_len = identity_buflen;
}
#endif /* DCAF_BASE64ENCODE_PSKIDENTITY */
dcaf_log(DCAF_LOG_DEBUG, "Trying to parse ticket:\n");
dcaf_debug_hexdump(identity, identity_len);
#endif /* DCAF_UTF8ENCODE_PSKIDENTITY */
if (dcaf_parse_ticket_face(session, identity, identity_len, &t) == DCAF_OK){
/* got a new ticket; just store it and continue */
dcaf_add_ticket(t);
......
/*
* dcaf_base64.c -- UTF-8 encoder/decoder for DCAF
*
* Copyright (C) 2020 Olaf Bergmann <bergmann@tzi.org>
*
* This file is part of the DCAF library libdcaf. Please see README
* for terms of use.
*/
#include "dcaf/dcaf_utf8.h"
#define CHECK_PTR(Current, End, Count) \
if ((End) < ((Current) + (Count))) { goto finish; }
bool uint8_to_utf8(char *dst, size_t *dstlen,
const uint8_t *src, size_t srclen) {
char *p = dst;
bool ok = false;
while (srclen-- && (p < dst + *dstlen)) {
uint8_t c = *src++;
if (c <= 127)
*p++ = c;
else {
CHECK_PTR(p, dst + *dstlen, 2);
*p++ = 0xc0 + (c >> 6);
*p++ = 0x80 + (c & 0x3f);
}
}
*dstlen = p - dst;
ok = true;
finish:
return ok;
}
bool utf8_to_uint8(uint8_t *dst, size_t *dstlen,
const char *src, size_t srclen) {
uint8_t *p = dst;
bool ok = false;
while (srclen-- && (p < dst + *dstlen)) {
unsigned char c = *src++;
if (c <= 127)
*p++ = c;
else if (c <= 195) { /* only up to 8 bits supported */
CHECK_PTR(src, src + srclen, 1);
*p = (c << 6);
c = *src++;
if ((c >> 6) != 2) /* is the next byte valid UTF-8? */
goto finish;
*p += (c & 0x3f);
p++;
srclen--;
} else { /* wide characters are not supported */
goto finish;
}
}
*dstlen = p - dst;
ok = true;
finish:
return ok;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment