mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-09 05:49:09 -07:00
Merge branch 'ofw_dev' into dev
This commit is contained in:
@@ -13,7 +13,7 @@ App(
|
||||
"!plugins",
|
||||
"!nfc_cli.c",
|
||||
],
|
||||
fap_libs=["assets"],
|
||||
fap_libs=["assets", "mbedtls"],
|
||||
fap_icon="icon.png",
|
||||
fap_category="NFC",
|
||||
)
|
||||
|
||||
@@ -29,7 +29,9 @@ static NfcCommand nfc_scene_read_poller_callback_st25tb(NfcGenericEvent event, v
|
||||
NfcApp* instance = context;
|
||||
const St25tbPollerEvent* st25tb_event = event.event_data;
|
||||
|
||||
if(st25tb_event->type == St25tbPollerEventTypeReady) {
|
||||
if(st25tb_event->type == St25tbPollerEventTypeRequestMode) {
|
||||
st25tb_event->data->mode_request.mode = St25tbPollerModeRead;
|
||||
} else if(st25tb_event->type == St25tbPollerEventTypeSuccess) {
|
||||
nfc_device_set_data(
|
||||
instance->nfc_device, NfcProtocolSt25tb, nfc_poller_get_data(instance->poller));
|
||||
view_dispatcher_send_custom_event(instance->view_dispatcher, NfcCustomEventPollerSuccess);
|
||||
|
||||
@@ -7,7 +7,7 @@ App(
|
||||
icon="A_U2F_14",
|
||||
order=80,
|
||||
resources="resources",
|
||||
fap_libs=["assets"],
|
||||
fap_libs=["assets", "mbedtls"],
|
||||
fap_category="USB",
|
||||
fap_icon="icon.png",
|
||||
)
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
/*
|
||||
* hmac.c - HMAC
|
||||
*
|
||||
* Copyright (C) 2017 Sergei Glushchenko
|
||||
* Author: Sergei Glushchenko <gl.sergei@gmail.com>
|
||||
*
|
||||
* This file is a part of U2F firmware for STM32
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As additional permission under GNU GPL version 3 section 7, you may
|
||||
* distribute non-source form of the Program without the copy of the
|
||||
* GNU GPL normally required by section 4, provided you inform the
|
||||
* recipients of GNU GPL by a written offer.
|
||||
*
|
||||
*/
|
||||
#include <stdint.h>
|
||||
|
||||
#include "sha256.h"
|
||||
#include "hmac_sha256.h"
|
||||
|
||||
static void _hmac_sha256_init(const hmac_context* ctx) {
|
||||
hmac_sha256_context* context = (hmac_sha256_context*)ctx;
|
||||
sha256_start(&context->sha_ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
_hmac_sha256_update(const hmac_context* ctx, const uint8_t* message, unsigned message_size) {
|
||||
hmac_sha256_context* context = (hmac_sha256_context*)ctx;
|
||||
sha256_update(&context->sha_ctx, message, message_size);
|
||||
}
|
||||
|
||||
static void _hmac_sha256_finish(const hmac_context* ctx, uint8_t* hash_result) {
|
||||
hmac_sha256_context* context = (hmac_sha256_context*)ctx;
|
||||
sha256_finish(&context->sha_ctx, hash_result);
|
||||
}
|
||||
|
||||
/* Compute an HMAC using K as a key (as in RFC 6979). Note that K is always
|
||||
the same size as the hash result size. */
|
||||
static void hmac_init(const hmac_context* ctx, const uint8_t* K) {
|
||||
uint8_t* pad = ctx->tmp + 2 * ctx->result_size;
|
||||
unsigned i;
|
||||
for(i = 0; i < ctx->result_size; ++i) pad[i] = K[i] ^ 0x36;
|
||||
for(; i < ctx->block_size; ++i) pad[i] = 0x36;
|
||||
|
||||
ctx->init_hash(ctx);
|
||||
ctx->update_hash(ctx, pad, ctx->block_size);
|
||||
}
|
||||
|
||||
static void hmac_update(const hmac_context* ctx, const uint8_t* message, unsigned message_size) {
|
||||
ctx->update_hash(ctx, message, message_size);
|
||||
}
|
||||
|
||||
static void hmac_finish(const hmac_context* ctx, const uint8_t* K, uint8_t* result) {
|
||||
uint8_t* pad = ctx->tmp + 2 * ctx->result_size;
|
||||
unsigned i;
|
||||
for(i = 0; i < ctx->result_size; ++i) pad[i] = K[i] ^ 0x5c;
|
||||
for(; i < ctx->block_size; ++i) pad[i] = 0x5c;
|
||||
|
||||
ctx->finish_hash(ctx, result);
|
||||
|
||||
ctx->init_hash(ctx);
|
||||
ctx->update_hash(ctx, pad, ctx->block_size);
|
||||
ctx->update_hash(ctx, result, ctx->result_size);
|
||||
ctx->finish_hash(ctx, result);
|
||||
}
|
||||
|
||||
void hmac_sha256_init(hmac_sha256_context* ctx, const uint8_t* K) {
|
||||
ctx->hmac_ctx.init_hash = _hmac_sha256_init;
|
||||
ctx->hmac_ctx.update_hash = _hmac_sha256_update;
|
||||
ctx->hmac_ctx.finish_hash = _hmac_sha256_finish;
|
||||
ctx->hmac_ctx.block_size = 64;
|
||||
ctx->hmac_ctx.result_size = 32;
|
||||
ctx->hmac_ctx.tmp = ctx->tmp;
|
||||
hmac_init(&ctx->hmac_ctx, K);
|
||||
}
|
||||
|
||||
void hmac_sha256_update(
|
||||
const hmac_sha256_context* ctx,
|
||||
const uint8_t* message,
|
||||
unsigned message_size) {
|
||||
hmac_update(&ctx->hmac_ctx, message, message_size);
|
||||
}
|
||||
|
||||
void hmac_sha256_finish(const hmac_sha256_context* ctx, const uint8_t* K, uint8_t* hash_result) {
|
||||
hmac_finish(&ctx->hmac_ctx, K, hash_result);
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "sha256.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct hmac_context {
|
||||
void (*init_hash)(const struct hmac_context* context);
|
||||
void (*update_hash)(
|
||||
const struct hmac_context* context,
|
||||
const uint8_t* message,
|
||||
unsigned message_size);
|
||||
void (*finish_hash)(const struct hmac_context* context, uint8_t* hash_result);
|
||||
unsigned block_size; /* Hash function block size in bytes, eg 64 for SHA-256. */
|
||||
unsigned result_size; /* Hash function result size in bytes, eg 32 for SHA-256. */
|
||||
uint8_t* tmp; /* Must point to a buffer of at least (2 * result_size + block_size) bytes. */
|
||||
} hmac_context;
|
||||
|
||||
typedef struct hmac_sha256_context {
|
||||
hmac_context hmac_ctx;
|
||||
sha256_context sha_ctx;
|
||||
uint8_t tmp[32 * 2 + 64];
|
||||
} hmac_sha256_context;
|
||||
|
||||
void hmac_sha256_init(hmac_sha256_context* ctx, const uint8_t* K);
|
||||
|
||||
void hmac_sha256_update(
|
||||
const hmac_sha256_context* ctx,
|
||||
const uint8_t* message,
|
||||
unsigned message_size);
|
||||
|
||||
void hmac_sha256_finish(const hmac_sha256_context* ctx, const uint8_t* K, uint8_t* hash_result);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,18 +1,22 @@
|
||||
#include <furi.h>
|
||||
#include "u2f.h"
|
||||
#include "u2f_hid.h"
|
||||
#include "u2f_data.h"
|
||||
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <furi_hal_random.h>
|
||||
#include <littlefs/lfs_util.h> // for lfs_tobe32
|
||||
|
||||
#include "toolbox/sha256.h"
|
||||
#include "hmac_sha256.h"
|
||||
#include "micro-ecc/uECC.h"
|
||||
#include <mbedtls/sha256.h>
|
||||
#include <mbedtls/md.h>
|
||||
#include <mbedtls/ecdsa.h>
|
||||
#include <mbedtls/error.h>
|
||||
|
||||
#define TAG "U2f"
|
||||
#define WORKER_TAG TAG "Worker"
|
||||
|
||||
#define MCHECK(expr) furi_check((expr) == 0)
|
||||
|
||||
#define U2F_CMD_REGISTER 0x01
|
||||
#define U2F_CMD_AUTHENTICATE 0x02
|
||||
#define U2F_CMD_VERSION 0x03
|
||||
@@ -25,16 +29,26 @@ typedef enum {
|
||||
0x08, // "dont-enforce-user-presence-and-sign" - send auth response even if user is missing
|
||||
} U2fAuthMode;
|
||||
|
||||
#define U2F_HASH_SIZE 32
|
||||
#define U2F_NONCE_SIZE 32
|
||||
#define U2F_CHALLENGE_SIZE 32
|
||||
#define U2F_APP_ID_SIZE 32
|
||||
|
||||
#define U2F_EC_KEY_SIZE 32
|
||||
#define U2F_EC_BIGNUM_SIZE 32
|
||||
#define U2F_EC_POINT_SIZE 65
|
||||
|
||||
typedef struct {
|
||||
uint8_t format;
|
||||
uint8_t xy[64];
|
||||
} __attribute__((packed)) U2fPubKey;
|
||||
} FURI_PACKED U2fPubKey;
|
||||
_Static_assert(sizeof(U2fPubKey) == U2F_EC_POINT_SIZE, "U2fPubKey size mismatch");
|
||||
|
||||
typedef struct {
|
||||
uint8_t len;
|
||||
uint8_t hash[32];
|
||||
uint8_t nonce[32];
|
||||
} __attribute__((packed)) U2fKeyHandle;
|
||||
uint8_t hash[U2F_HASH_SIZE];
|
||||
uint8_t nonce[U2F_NONCE_SIZE];
|
||||
} FURI_PACKED U2fKeyHandle;
|
||||
|
||||
typedef struct {
|
||||
uint8_t cla;
|
||||
@@ -42,16 +56,16 @@ typedef struct {
|
||||
uint8_t p1;
|
||||
uint8_t p2;
|
||||
uint8_t len[3];
|
||||
uint8_t challenge[32];
|
||||
uint8_t app_id[32];
|
||||
} __attribute__((packed)) U2fRegisterReq;
|
||||
uint8_t challenge[U2F_CHALLENGE_SIZE];
|
||||
uint8_t app_id[U2F_APP_ID_SIZE];
|
||||
} FURI_PACKED U2fRegisterReq;
|
||||
|
||||
typedef struct {
|
||||
uint8_t reserved;
|
||||
U2fPubKey pub_key;
|
||||
U2fKeyHandle key_handle;
|
||||
uint8_t cert[];
|
||||
} __attribute__((packed)) U2fRegisterResp;
|
||||
} FURI_PACKED U2fRegisterResp;
|
||||
|
||||
typedef struct {
|
||||
uint8_t cla;
|
||||
@@ -59,16 +73,16 @@ typedef struct {
|
||||
uint8_t p1;
|
||||
uint8_t p2;
|
||||
uint8_t len[3];
|
||||
uint8_t challenge[32];
|
||||
uint8_t app_id[32];
|
||||
uint8_t challenge[U2F_CHALLENGE_SIZE];
|
||||
uint8_t app_id[U2F_APP_ID_SIZE];
|
||||
U2fKeyHandle key_handle;
|
||||
} __attribute__((packed)) U2fAuthReq;
|
||||
} FURI_PACKED U2fAuthReq;
|
||||
|
||||
typedef struct {
|
||||
uint8_t user_present;
|
||||
uint32_t counter;
|
||||
uint8_t signature[];
|
||||
} __attribute__((packed)) U2fAuthResp;
|
||||
} FURI_PACKED U2fAuthResp;
|
||||
|
||||
static const uint8_t ver_str[] = {"U2F_V2"};
|
||||
|
||||
@@ -78,19 +92,20 @@ static const uint8_t state_user_missing[] = {0x69, 0x85};
|
||||
static const uint8_t state_wrong_data[] = {0x6A, 0x80};
|
||||
|
||||
struct U2fData {
|
||||
uint8_t device_key[32];
|
||||
uint8_t cert_key[32];
|
||||
uint8_t device_key[U2F_EC_KEY_SIZE];
|
||||
uint8_t cert_key[U2F_EC_KEY_SIZE];
|
||||
uint32_t counter;
|
||||
const struct uECC_Curve_t* p_curve;
|
||||
bool ready;
|
||||
bool user_present;
|
||||
U2fEvtCallback callback;
|
||||
void* context;
|
||||
mbedtls_ecp_group group;
|
||||
};
|
||||
|
||||
static int u2f_uecc_random(uint8_t* dest, unsigned size) {
|
||||
static int u2f_uecc_random_cb(void* context, uint8_t* dest, unsigned size) {
|
||||
UNUSED(context);
|
||||
furi_hal_random_fill_buf(dest, size);
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
U2fData* u2f_alloc() {
|
||||
@@ -99,6 +114,7 @@ U2fData* u2f_alloc() {
|
||||
|
||||
void u2f_free(U2fData* U2F) {
|
||||
furi_assert(U2F);
|
||||
mbedtls_ecp_group_free(&U2F->group);
|
||||
free(U2F);
|
||||
}
|
||||
|
||||
@@ -129,8 +145,8 @@ bool u2f_init(U2fData* U2F) {
|
||||
}
|
||||
}
|
||||
|
||||
U2F->p_curve = uECC_secp256r1();
|
||||
uECC_set_rng(u2f_uecc_random);
|
||||
mbedtls_ecp_group_init(&U2F->group);
|
||||
mbedtls_ecp_group_load(&U2F->group, MBEDTLS_ECP_DP_SECP256R1);
|
||||
|
||||
U2F->ready = true;
|
||||
return true;
|
||||
@@ -171,21 +187,63 @@ static uint8_t u2f_der_encode_signature(uint8_t* der, uint8_t* sig) {
|
||||
der[0] = 0x30;
|
||||
|
||||
uint8_t len = 2;
|
||||
len += u2f_der_encode_int(der + len, sig, 32);
|
||||
len += u2f_der_encode_int(der + len, sig + 32, 32);
|
||||
len += u2f_der_encode_int(der + len, sig, U2F_HASH_SIZE);
|
||||
len += u2f_der_encode_int(der + len, sig + U2F_HASH_SIZE, U2F_HASH_SIZE);
|
||||
|
||||
der[1] = len - 2;
|
||||
return len;
|
||||
}
|
||||
|
||||
static void
|
||||
u2f_ecc_sign(mbedtls_ecp_group* grp, const uint8_t* key, uint8_t* hash, uint8_t* signature) {
|
||||
mbedtls_mpi r, s, d;
|
||||
|
||||
mbedtls_mpi_init(&r);
|
||||
mbedtls_mpi_init(&s);
|
||||
mbedtls_mpi_init(&d);
|
||||
|
||||
MCHECK(mbedtls_mpi_read_binary(&d, key, U2F_EC_KEY_SIZE));
|
||||
MCHECK(mbedtls_ecdsa_sign(grp, &r, &s, &d, hash, U2F_HASH_SIZE, u2f_uecc_random_cb, NULL));
|
||||
MCHECK(mbedtls_mpi_write_binary(&r, signature, U2F_EC_BIGNUM_SIZE));
|
||||
MCHECK(mbedtls_mpi_write_binary(&s, signature + U2F_EC_BIGNUM_SIZE, U2F_EC_BIGNUM_SIZE));
|
||||
|
||||
mbedtls_mpi_free(&r);
|
||||
mbedtls_mpi_free(&s);
|
||||
mbedtls_mpi_free(&d);
|
||||
}
|
||||
|
||||
static void u2f_ecc_compute_public_key(
|
||||
mbedtls_ecp_group* grp,
|
||||
const uint8_t* private_key,
|
||||
U2fPubKey* public_key) {
|
||||
mbedtls_ecp_point Q;
|
||||
mbedtls_mpi d;
|
||||
size_t olen;
|
||||
|
||||
mbedtls_ecp_point_init(&Q);
|
||||
mbedtls_mpi_init(&d);
|
||||
|
||||
MCHECK(mbedtls_mpi_read_binary(&d, private_key, U2F_EC_KEY_SIZE));
|
||||
MCHECK(mbedtls_ecp_mul(grp, &Q, &d, &grp->G, u2f_uecc_random_cb, NULL));
|
||||
MCHECK(mbedtls_ecp_check_privkey(grp, &d));
|
||||
|
||||
MCHECK(mbedtls_ecp_point_write_binary(
|
||||
grp, &Q, MBEDTLS_ECP_PF_UNCOMPRESSED, &olen, (unsigned char*)public_key, sizeof(U2fPubKey)));
|
||||
|
||||
mbedtls_ecp_point_free(&Q);
|
||||
mbedtls_mpi_free(&d);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////
|
||||
|
||||
static uint16_t u2f_register(U2fData* U2F, uint8_t* buf) {
|
||||
U2fRegisterReq* req = (U2fRegisterReq*)buf;
|
||||
U2fRegisterResp* resp = (U2fRegisterResp*)buf;
|
||||
U2fKeyHandle handle;
|
||||
uint8_t private[32];
|
||||
uint8_t private[U2F_EC_KEY_SIZE];
|
||||
U2fPubKey pub_key;
|
||||
uint8_t hash[32];
|
||||
uint8_t signature[64];
|
||||
uint8_t hash[U2F_HASH_SIZE];
|
||||
uint8_t signature[U2F_EC_BIGNUM_SIZE * 2];
|
||||
|
||||
if(u2f_data_check(false) == false) {
|
||||
U2F->ready = false;
|
||||
@@ -201,40 +259,54 @@ static uint16_t u2f_register(U2fData* U2F, uint8_t* buf) {
|
||||
}
|
||||
U2F->user_present = false;
|
||||
|
||||
hmac_sha256_context hmac_ctx;
|
||||
sha256_context sha_ctx;
|
||||
handle.len = U2F_HASH_SIZE * 2;
|
||||
|
||||
handle.len = 32 * 2;
|
||||
// Generate random nonce
|
||||
furi_hal_random_fill_buf(handle.nonce, 32);
|
||||
|
||||
// Generate private key
|
||||
hmac_sha256_init(&hmac_ctx, U2F->device_key);
|
||||
hmac_sha256_update(&hmac_ctx, req->app_id, 32);
|
||||
hmac_sha256_update(&hmac_ctx, handle.nonce, 32);
|
||||
hmac_sha256_finish(&hmac_ctx, U2F->device_key, private);
|
||||
{
|
||||
mbedtls_md_context_t hmac_ctx;
|
||||
mbedtls_md_init(&hmac_ctx);
|
||||
MCHECK(mbedtls_md_setup(&hmac_ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1));
|
||||
MCHECK(mbedtls_md_hmac_starts(&hmac_ctx, U2F->device_key, sizeof(U2F->device_key)));
|
||||
|
||||
// Generate private key handle
|
||||
hmac_sha256_init(&hmac_ctx, U2F->device_key);
|
||||
hmac_sha256_update(&hmac_ctx, private, 32);
|
||||
hmac_sha256_update(&hmac_ctx, req->app_id, 32);
|
||||
hmac_sha256_finish(&hmac_ctx, U2F->device_key, handle.hash);
|
||||
// Generate private key
|
||||
MCHECK(mbedtls_md_hmac_update(&hmac_ctx, req->app_id, sizeof(req->app_id)));
|
||||
MCHECK(mbedtls_md_hmac_update(&hmac_ctx, handle.nonce, sizeof(handle.nonce)));
|
||||
MCHECK(mbedtls_md_hmac_finish(&hmac_ctx, private));
|
||||
|
||||
MCHECK(mbedtls_md_hmac_reset(&hmac_ctx));
|
||||
|
||||
// Generate private key handle
|
||||
MCHECK(mbedtls_md_hmac_update(&hmac_ctx, private, sizeof(private)));
|
||||
MCHECK(mbedtls_md_hmac_update(&hmac_ctx, req->app_id, sizeof(req->app_id)));
|
||||
MCHECK(mbedtls_md_hmac_finish(&hmac_ctx, handle.hash));
|
||||
}
|
||||
|
||||
// Generate public key
|
||||
pub_key.format = 0x04; // Uncompressed point
|
||||
uECC_compute_public_key(private, pub_key.xy, U2F->p_curve);
|
||||
u2f_ecc_compute_public_key(&U2F->group, private, &pub_key);
|
||||
|
||||
// Generate signature
|
||||
uint8_t reserved_byte = 0;
|
||||
sha256_start(&sha_ctx);
|
||||
sha256_update(&sha_ctx, &reserved_byte, 1);
|
||||
sha256_update(&sha_ctx, req->app_id, 32);
|
||||
sha256_update(&sha_ctx, req->challenge, 32);
|
||||
sha256_update(&sha_ctx, handle.hash, handle.len);
|
||||
sha256_update(&sha_ctx, (uint8_t*)&pub_key, 65);
|
||||
sha256_finish(&sha_ctx, hash);
|
||||
{
|
||||
uint8_t reserved_byte = 0;
|
||||
|
||||
uECC_sign(U2F->cert_key, hash, 32, signature, U2F->p_curve);
|
||||
mbedtls_sha256_context sha_ctx;
|
||||
|
||||
mbedtls_sha256_init(&sha_ctx);
|
||||
mbedtls_sha256_starts(&sha_ctx, 0);
|
||||
|
||||
mbedtls_sha256_update(&sha_ctx, &reserved_byte, 1);
|
||||
mbedtls_sha256_update(&sha_ctx, req->app_id, sizeof(req->app_id));
|
||||
mbedtls_sha256_update(&sha_ctx, req->challenge, sizeof(req->challenge));
|
||||
mbedtls_sha256_update(&sha_ctx, handle.hash, handle.len);
|
||||
mbedtls_sha256_update(&sha_ctx, (uint8_t*)&pub_key, sizeof(U2fPubKey));
|
||||
|
||||
mbedtls_sha256_finish(&sha_ctx, hash);
|
||||
mbedtls_sha256_free(&sha_ctx);
|
||||
}
|
||||
|
||||
// Sign hash
|
||||
u2f_ecc_sign(&U2F->group, U2F->cert_key, hash, signature);
|
||||
|
||||
// Encode response message
|
||||
resp->reserved = 0x05;
|
||||
@@ -250,13 +322,11 @@ static uint16_t u2f_register(U2fData* U2F, uint8_t* buf) {
|
||||
static uint16_t u2f_authenticate(U2fData* U2F, uint8_t* buf) {
|
||||
U2fAuthReq* req = (U2fAuthReq*)buf;
|
||||
U2fAuthResp* resp = (U2fAuthResp*)buf;
|
||||
uint8_t priv_key[32];
|
||||
uint8_t priv_key[U2F_EC_KEY_SIZE];
|
||||
uint8_t mac_control[32];
|
||||
hmac_sha256_context hmac_ctx;
|
||||
sha256_context sha_ctx;
|
||||
uint8_t flags = 0;
|
||||
uint8_t hash[32];
|
||||
uint8_t signature[64];
|
||||
uint8_t hash[U2F_HASH_SIZE];
|
||||
uint8_t signature[U2F_HASH_SIZE * 2];
|
||||
uint32_t be_u2f_counter;
|
||||
|
||||
if(u2f_data_check(false) == false) {
|
||||
@@ -281,26 +351,42 @@ static uint16_t u2f_authenticate(U2fData* U2F, uint8_t* buf) {
|
||||
be_u2f_counter = lfs_tobe32(U2F->counter + 1);
|
||||
|
||||
// Generate hash
|
||||
sha256_start(&sha_ctx);
|
||||
sha256_update(&sha_ctx, req->app_id, 32);
|
||||
sha256_update(&sha_ctx, &flags, 1);
|
||||
sha256_update(&sha_ctx, (uint8_t*)&(be_u2f_counter), 4);
|
||||
sha256_update(&sha_ctx, req->challenge, 32);
|
||||
sha256_finish(&sha_ctx, hash);
|
||||
{
|
||||
mbedtls_sha256_context sha_ctx;
|
||||
|
||||
// Recover private key
|
||||
hmac_sha256_init(&hmac_ctx, U2F->device_key);
|
||||
hmac_sha256_update(&hmac_ctx, req->app_id, 32);
|
||||
hmac_sha256_update(&hmac_ctx, req->key_handle.nonce, 32);
|
||||
hmac_sha256_finish(&hmac_ctx, U2F->device_key, priv_key);
|
||||
mbedtls_sha256_init(&sha_ctx);
|
||||
mbedtls_sha256_starts(&sha_ctx, 0);
|
||||
|
||||
// Generate and verify private key handle
|
||||
hmac_sha256_init(&hmac_ctx, U2F->device_key);
|
||||
hmac_sha256_update(&hmac_ctx, priv_key, 32);
|
||||
hmac_sha256_update(&hmac_ctx, req->app_id, 32);
|
||||
hmac_sha256_finish(&hmac_ctx, U2F->device_key, mac_control);
|
||||
mbedtls_sha256_update(&sha_ctx, req->app_id, sizeof(req->app_id));
|
||||
mbedtls_sha256_update(&sha_ctx, &flags, 1);
|
||||
mbedtls_sha256_update(&sha_ctx, (uint8_t*)&(be_u2f_counter), sizeof(be_u2f_counter));
|
||||
mbedtls_sha256_update(&sha_ctx, req->challenge, sizeof(req->challenge));
|
||||
|
||||
if(memcmp(req->key_handle.hash, mac_control, 32) != 0) {
|
||||
mbedtls_sha256_finish(&sha_ctx, hash);
|
||||
mbedtls_sha256_free(&sha_ctx);
|
||||
}
|
||||
|
||||
{
|
||||
mbedtls_md_context_t hmac_ctx;
|
||||
mbedtls_md_init(&hmac_ctx);
|
||||
MCHECK(mbedtls_md_setup(&hmac_ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1));
|
||||
MCHECK(mbedtls_md_hmac_starts(&hmac_ctx, U2F->device_key, sizeof(U2F->device_key)));
|
||||
|
||||
// Recover private key
|
||||
MCHECK(mbedtls_md_hmac_update(&hmac_ctx, req->app_id, sizeof(req->app_id)));
|
||||
MCHECK(mbedtls_md_hmac_update(
|
||||
&hmac_ctx, req->key_handle.nonce, sizeof(req->key_handle.nonce)));
|
||||
MCHECK(mbedtls_md_hmac_finish(&hmac_ctx, priv_key));
|
||||
|
||||
MCHECK(mbedtls_md_hmac_reset(&hmac_ctx));
|
||||
|
||||
// Generate and verify private key handle
|
||||
MCHECK(mbedtls_md_hmac_update(&hmac_ctx, priv_key, sizeof(priv_key)));
|
||||
MCHECK(mbedtls_md_hmac_update(&hmac_ctx, req->app_id, sizeof(req->app_id)));
|
||||
MCHECK(mbedtls_md_hmac_finish(&hmac_ctx, mac_control));
|
||||
}
|
||||
|
||||
if(memcmp(req->key_handle.hash, mac_control, sizeof(mac_control)) != 0) {
|
||||
FURI_LOG_W(TAG, "Wrong handle!");
|
||||
memcpy(&buf[0], state_wrong_data, 2);
|
||||
return 2;
|
||||
@@ -311,7 +397,8 @@ static uint16_t u2f_authenticate(U2fData* U2F, uint8_t* buf) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
uECC_sign(priv_key, hash, 32, signature, U2F->p_curve);
|
||||
// Sign hash
|
||||
u2f_ecc_sign(&U2F->group, priv_key, hash, signature);
|
||||
|
||||
resp->user_present = flags;
|
||||
resp->counter = be_u2f_counter;
|
||||
|
||||
@@ -37,7 +37,7 @@ typedef struct {
|
||||
uint32_t counter;
|
||||
uint8_t random_salt[24];
|
||||
uint32_t control;
|
||||
} __attribute__((packed)) U2fCounterData;
|
||||
} FURI_PACKED U2fCounterData;
|
||||
|
||||
bool u2f_data_check(bool cert_only) {
|
||||
bool state = false;
|
||||
|
||||
Reference in New Issue
Block a user