Add base64url routines.

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
This commit is contained in:
Pol Henarejos
2026-04-21 17:09:51 +02:00
parent 11a8923148
commit 9ab9d96af5
5 changed files with 80 additions and 6 deletions

View File

@@ -22,6 +22,7 @@
#include "mbedtls/aes.h"
#include "mbedtls/hkdf.h"
#include "mbedtls/gcm.h"
#include "mbedtls/base64.h"
#include "crypto_utils.h"
#include "otp.h"
#include "random.h"
@@ -308,3 +309,52 @@ uint32_t crc32c(const uint8_t *buf, size_t len) {
}
return ~crc;
}
int base64url_encode(unsigned char *dst, size_t dlen, size_t *olen, const unsigned char *src, size_t slen) {
int rc = mbedtls_base64_encode(dst, dlen, olen, src, slen);
if (rc != 0) {
return rc;
}
for (size_t i = 0; i < *olen; i++) {
if (dst[i] == '+') {
dst[i] = '-';
}
else if (dst[i] == '/') {
dst[i] = '_';
}
}
uint8_t *p = dst + *olen - 1;
while (*p == '=') {
*p-- = '\0';
(*olen)--;
}
return 0;
}
int base64url_decode(unsigned char *dst, size_t dlen, size_t *olen, const unsigned char *src, size_t slen) {
// First convert from base64url to standard base64
unsigned char *b64_src = (unsigned char *)malloc(slen + 2); // +2 for padding if needed
if (b64_src == NULL) {
return PICOKEYS_ERR_MEMORY_FATAL;
}
for (size_t i = 0; i < slen; i++) {
if (src[i] == '-') {
b64_src[i] = '+';
}
else if (src[i] == '_') {
b64_src[i] = '/';
}
else {
b64_src[i] = src[i];
}
}
size_t padding = (4 - (slen % 4)) % 4;
for (size_t i = 0; i < padding; i++) {
b64_src[slen + i] = '=';
}
size_t b64_len = slen + padding;
int rc = mbedtls_base64_decode(dst, dlen, olen, b64_src, b64_len);
free(b64_src);
return rc;
}

View File

@@ -66,6 +66,8 @@ extern int aes_encrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *d
extern int aes_decrypt_cfb_256(const uint8_t *key, const uint8_t *iv, uint8_t *data, uint16_t len);
extern mbedtls_ecp_group_id ec_get_curve_from_prime(const uint8_t *prime, size_t prime_len);
extern uint32_t crc32c(const uint8_t *buf, size_t len);
extern int base64url_encode(unsigned char *dst, size_t dlen, size_t *olen, const unsigned char *src, size_t slen);
extern int base64url_decode(unsigned char *dst, size_t dlen, size_t *olen, const unsigned char *src, size_t slen);
#define PIN_KDF_SIZE(x) (12 + (x) + 16)

View File

@@ -20,6 +20,7 @@
#include "rest.h"
#include <strings.h>
#include "random.h"
#include "crypto_utils.h"
#define REST_MAX_SESSIONS 4
@@ -34,6 +35,11 @@ rest_session_t *rest_session_create(const rest_session_role_t role, rest_session
random_fill_buffer(rest_sessions[i].id, sizeof(rest_sessions[i].id));
rest_sessions[i].created_at = board_millis();
rest_sessions[i].last_activity_timestamp = rest_sessions[i].created_at;
size_t olen = 0;
if (base64url_encode(rest_sessions[i].id_str, sizeof(rest_sessions[i].id_str), &olen, (const unsigned char *)rest_sessions[i].id, sizeof(rest_sessions[i].id)) != 0) {
memset(&rest_sessions[i], 0, sizeof(rest_session_t));
return NULL;
}
return &rest_sessions[i];
}
}
@@ -54,6 +60,20 @@ rest_session_t *rest_session_get(const uint8_t *id, size_t id_len) {
return NULL;
}
rest_session_t *rest_session_get_by_id_str(const char *id_str) {
if (id_str == NULL || strlen(id_str) != 22) {
return NULL;
}
for (int i = 0; i < REST_MAX_SESSIONS; i++) {
if (rest_sessions[i].status != REST_SESSION_UNKNOWN && rest_sessions[i].status != REST_SESSION_EXPIRED && rest_sessions[i].status != REST_SESSION_TERMINATED) {
if (strcmp((const char *)rest_sessions[i].id_str, id_str) == 0) {
return &rest_sessions[i];
}
}
}
return NULL;
}
int rest_session_terminate(const uint8_t *id, size_t id_len) {
rest_session_t *session = rest_session_get(id, id_len);
if (session == NULL) {

View File

@@ -25,6 +25,7 @@
#include <stdint.h>
#include <time.h>
#include "cJSON.h"
#include "mbedtls/base64.h"
#define REST_MAX_REQUEST_SIZE 1024
#define REST_MAX_METHOD_SIZE 8
@@ -85,9 +86,9 @@ typedef struct {
} rest_route_t;
typedef enum {
REST_SESSION_NONE = 0,
REST_SESSION_USER = 0x1,
REST_SESSION_ADMIN = 0x2
REST_SESSION_ROLE_NONE = 0,
REST_SESSION_ROLE_USER = 0x1,
REST_SESSION_ROLE_ADMIN = 0x2
} rest_session_role_t;
typedef enum {
@@ -102,6 +103,7 @@ typedef enum {
typedef struct {
uint8_t id[16];
uint8_t id_str[25];
time_t last_activity_timestamp;
time_t created_at;
uint32_t last_seq;
@@ -120,6 +122,7 @@ const rest_route_t *rest_get_routes(size_t *count);
extern rest_session_t *rest_session_create(const rest_session_role_t role, rest_session_status_t status);
extern rest_session_t *rest_session_get(const uint8_t *id, size_t id_len);
extern rest_session_t *rest_session_get_by_id_str(const char *id_str);
extern int rest_session_terminate(const uint8_t *id, size_t id_len);
extern int rest_session_update_activity(const uint8_t *id, size_t id_len);
extern int rest_session_set_status(const uint8_t *id, size_t id_len, rest_session_status_t status);

View File

@@ -24,7 +24,6 @@
#include <ctype.h>
#include <strings.h>
#include "mbedtls/base64.h"
#include "mbedtls/md.h"
#include "mbedtls/hkdf.h"
#include "crypto_utils.h"
@@ -615,7 +614,7 @@ static int rest_verify_request_signature(const rest_request_t *request, const re
if (md_info == NULL) {
return PICOKEYS_ERR_MEMORY_FATAL;
}
if (mbedtls_base64_decode(hmac_x, sizeof(hmac_x), &olen, (const unsigned char *)request->headers[REST_HEADER_X_SIGNATURE], strlen(request->headers[REST_HEADER_X_SIGNATURE])) != 0) {
if (base64url_decode(hmac_x, sizeof(hmac_x), &olen, (const unsigned char *)request->headers[REST_HEADER_X_SIGNATURE], strlen(request->headers[REST_HEADER_X_SIGNATURE])) != 0) {
return PICOKEYS_EXEC_ERROR;
}
mbedtls_md_init(&ctx);
@@ -707,7 +706,7 @@ void rest_handle_request(rest_conn_t *conn) {
send_json_error(conn, 401, "authentication_required");
return;
}
rest_session_t *session = rest_session_get((const uint8_t *)request->headers[REST_HEADER_X_SESSION_ID], strlen(request->headers[REST_HEADER_X_SESSION_ID]));
rest_session_t *session = rest_session_get_by_id_str(request->headers[REST_HEADER_X_SESSION_ID]);
if (!session) {
send_json_error(conn, 401, "authentication_required");
return;