mirror of
https://github.com/polhenarejos/pico-fido.git
synced 2026-08-24 05:23:27 +01:00
Add FIDO object authorization context with operation-scoped evidence
Invalidate authorization epochs on PIN/UV token and session changes, with host tests Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
This commit is contained in:
@@ -112,6 +112,7 @@ endif()
|
||||
|
||||
list(APPEND SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/fido/fido.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/fido/object_authorization.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/fido/object_provider.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/fido/files.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/fido/cmd_register.c
|
||||
@@ -226,6 +227,19 @@ if(NOT ESP_PLATFORM)
|
||||
endif()
|
||||
target_link_libraries(fido_object_provider_test PRIVATE mbedtls)
|
||||
add_test(NAME fido_object_provider_test COMMAND fido_object_provider_test)
|
||||
|
||||
add_executable(fido_object_authorization_test
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/fido/object_authorization.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/tests/fido_object_authorization_test.c
|
||||
)
|
||||
target_include_directories(fido_object_authorization_test PRIVATE ${INCLUDES})
|
||||
if(MSVC)
|
||||
target_compile_options(fido_object_authorization_test PRIVATE /W4 /WX)
|
||||
else()
|
||||
target_compile_options(fido_object_authorization_test PRIVATE -Wall -Wextra -Werror)
|
||||
endif()
|
||||
target_link_libraries(fido_object_authorization_test PRIVATE mbedtls)
|
||||
add_test(NAME fido_object_authorization_test COMMAND fido_object_authorization_test)
|
||||
else()
|
||||
target_link_libraries(
|
||||
pico_fido
|
||||
|
||||
+1
-1
Submodule pico-keys-sdk updated: 5e2c0336d1...5f4032fdfa
@@ -33,6 +33,7 @@
|
||||
#include "random.h"
|
||||
#include "crypto_utils.h"
|
||||
#include "apdu.h"
|
||||
#include "object_authorization.h"
|
||||
|
||||
uint32_t usage_timer = 0, initial_usage_time_limit = 0;
|
||||
uint32_t max_usage_time_period = 600 * 1000;
|
||||
@@ -74,28 +75,34 @@ static int beginUsingPinUvAuthToken(bool userIsPresent) {
|
||||
initial_usage_time_limit = board_millis();
|
||||
usage_timer = board_millis();
|
||||
paut.in_use = true;
|
||||
fido_object_authorization_session_invalidate();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void clearUserPresentFlag(void) {
|
||||
if (paut.in_use == true) {
|
||||
if (paut.in_use == true && paut.user_present) {
|
||||
paut.user_present = false;
|
||||
fido_object_authorization_session_invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
void clearUserVerifiedFlag(void) {
|
||||
if (paut.in_use == true) {
|
||||
if (paut.in_use == true && paut.user_verified) {
|
||||
paut.user_verified = false;
|
||||
fido_object_authorization_session_invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
void clearPinUvAuthTokenPermissionsExceptLbw(void) {
|
||||
if (paut.in_use == true) {
|
||||
if (paut.in_use == true && paut.permissions != CTAP_PERMISSION_LBW) {
|
||||
paut.permissions = CTAP_PERMISSION_LBW;
|
||||
fido_object_authorization_session_invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
static void stopUsingPinUvAuthToken(void) {
|
||||
bool token_active = paut.in_use || paut.permissions != 0 || paut.has_rp_id || paut.user_present || paut.user_verified;
|
||||
|
||||
paut.permissions = 0;
|
||||
usage_timer = 0;
|
||||
paut.in_use = false;
|
||||
@@ -104,6 +111,9 @@ static void stopUsingPinUvAuthToken(void) {
|
||||
initial_usage_time_limit = 0;
|
||||
paut.user_present = paut.user_verified = false;
|
||||
user_present_time_limit = 0;
|
||||
if (token_active) {
|
||||
fido_object_authorization_session_invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
bool getUserPresentFlagValue(void) {
|
||||
@@ -195,6 +205,7 @@ int resetPinUvAuthToken(void) {
|
||||
paut.permissions = 0;
|
||||
paut.data = file_get_data(ef_authtoken);
|
||||
paut.len = file_get_size(ef_authtoken);
|
||||
fido_object_authorization_session_invalidate();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -204,6 +215,7 @@ int resetPersistentPinUvAuthToken(void) {
|
||||
ppaut.permissions = 0;
|
||||
ppaut.data = file_get_data(ef_pauthtoken);
|
||||
ppaut.len = file_get_size(ef_pauthtoken);
|
||||
fido_object_authorization_session_invalidate();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#endif
|
||||
#include <math.h>
|
||||
#include "management.h"
|
||||
#include "object_authorization.h"
|
||||
#include "hid/ctap_hid.h"
|
||||
#include "ctap2_cbor.h"
|
||||
#include "credential.h"
|
||||
@@ -102,6 +103,7 @@ INITIALIZER ( fido_ctor ) {
|
||||
}
|
||||
|
||||
static int fido_unload(void) {
|
||||
fido_object_authorization_session_invalidate();
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
|
||||
@@ -505,6 +507,7 @@ void scan_all(void) {
|
||||
|
||||
extern bool needs_power_cycle;
|
||||
void init_fido(void) {
|
||||
fido_object_authorization_session_invalidate();
|
||||
scan_all();
|
||||
credential_migrate_rp_secure();
|
||||
#ifdef ENABLE_OTP_APP
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* This file is part of the Pico FIDO distribution (https://github.com/polhenarejos/pico-fido).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* 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
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "picokeys.h"
|
||||
#include "object_authorization.h"
|
||||
#include "object_provider.h"
|
||||
|
||||
static uint32_t fido_object_session_epoch = 1;
|
||||
|
||||
void fido_object_authorization_session_invalidate(void) {
|
||||
fido_object_session_epoch++;
|
||||
if (fido_object_session_epoch == 0) {
|
||||
fido_object_session_epoch = 1;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t fido_object_authorization_session_epoch(void) {
|
||||
return fido_object_session_epoch;
|
||||
}
|
||||
|
||||
int fido_object_authorization_context_build(const fido_object_authorization_evidence_t *evidence, bool internal_firmware, file_object_authorization_context_t *context) {
|
||||
if (!context) {
|
||||
return PICOKEYS_ERR_NULL_PARAM;
|
||||
}
|
||||
|
||||
uint32_t facts = FILE_OBJECT_FACT_OWNING_APPLICATION | FILE_OBJECT_FACT_SESSION_BOUND;
|
||||
if (internal_firmware) {
|
||||
facts |= FILE_OBJECT_FACT_INTERNAL_FIRMWARE;
|
||||
}
|
||||
else if (evidence) {
|
||||
if (evidence->user_presence) {
|
||||
facts |= FILE_OBJECT_FACT_USER_PRESENCE;
|
||||
}
|
||||
if (evidence->user_verification) {
|
||||
facts |= FILE_OBJECT_FACT_USER_VERIFICATION;
|
||||
}
|
||||
if (evidence->pin_uv_auth) {
|
||||
facts |= FILE_OBJECT_FACT_APP_PIN | FILE_OBJECT_FACT_USER_VERIFICATION;
|
||||
}
|
||||
}
|
||||
|
||||
context->facts = facts;
|
||||
context->session_epoch = fido_object_session_epoch;
|
||||
context->facts_epoch = fido_object_session_epoch;
|
||||
context->caller_namespace = FIDO_OBJECT_NAMESPACE;
|
||||
return PICOKEYS_OK;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* This file is part of the Pico FIDO distribution (https://github.com/polhenarejos/pico-fido).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* 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
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _OBJECT_AUTHORIZATION_H_
|
||||
#define _OBJECT_AUTHORIZATION_H_
|
||||
|
||||
#include "object_policy.h"
|
||||
|
||||
typedef struct fido_object_authorization_evidence {
|
||||
bool user_presence;
|
||||
bool user_verification;
|
||||
bool pin_uv_auth;
|
||||
} fido_object_authorization_evidence_t;
|
||||
|
||||
// Evidence must represent checks completed for the current CTAP operation, including token permission and RP binding.
|
||||
int fido_object_authorization_context_build(const fido_object_authorization_evidence_t *evidence, bool internal_firmware, file_object_authorization_context_t *context);
|
||||
void fido_object_authorization_session_invalidate(void);
|
||||
uint32_t fido_object_authorization_session_epoch(void);
|
||||
|
||||
#endif // _OBJECT_AUTHORIZATION_H_
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* This file is part of the Pico FIDO distribution (https://github.com/polhenarejos/pico-fido).
|
||||
* Copyright (c) 2022 Pol Henarejos.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* 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
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "picokeys.h"
|
||||
#include "object_authorization.h"
|
||||
#include "object_provider.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static void test_unauthenticated_context(void) {
|
||||
file_object_authorization_context_t context;
|
||||
|
||||
assert(fido_object_authorization_context_build(NULL, false, &context) == PICOKEYS_OK);
|
||||
assert(context.caller_namespace == FIDO_OBJECT_NAMESPACE);
|
||||
assert(context.session_epoch != 0);
|
||||
assert(context.facts_epoch == context.session_epoch);
|
||||
assert(context.facts == (FILE_OBJECT_FACT_OWNING_APPLICATION | FILE_OBJECT_FACT_SESSION_BOUND));
|
||||
}
|
||||
|
||||
static void test_operation_evidence(void) {
|
||||
fido_object_authorization_evidence_t evidence = {
|
||||
.user_presence = true,
|
||||
.user_verification = true,
|
||||
.pin_uv_auth = false
|
||||
};
|
||||
file_object_authorization_context_t context;
|
||||
|
||||
assert(fido_object_authorization_context_build(&evidence, false, &context) == PICOKEYS_OK);
|
||||
assert((context.facts & FILE_OBJECT_FACT_USER_PRESENCE) != 0);
|
||||
assert((context.facts & FILE_OBJECT_FACT_USER_VERIFICATION) != 0);
|
||||
assert((context.facts & FILE_OBJECT_FACT_APP_PIN) == 0);
|
||||
}
|
||||
|
||||
static void test_pin_uv_auth_context(void) {
|
||||
fido_object_authorization_evidence_t evidence = {
|
||||
.user_presence = false,
|
||||
.user_verification = false,
|
||||
.pin_uv_auth = true
|
||||
};
|
||||
file_object_authorization_context_t context;
|
||||
|
||||
assert(fido_object_authorization_context_build(&evidence, false, &context) == PICOKEYS_OK);
|
||||
assert((context.facts & FILE_OBJECT_FACT_APP_PIN) != 0);
|
||||
assert((context.facts & FILE_OBJECT_FACT_USER_VERIFICATION) != 0);
|
||||
assert((context.facts & FILE_OBJECT_FACT_USER_PRESENCE) == 0);
|
||||
}
|
||||
|
||||
static void test_internal_context(void) {
|
||||
fido_object_authorization_evidence_t evidence = {
|
||||
.user_presence = true,
|
||||
.user_verification = true,
|
||||
.pin_uv_auth = true
|
||||
};
|
||||
file_object_authorization_context_t context;
|
||||
|
||||
assert(fido_object_authorization_context_build(&evidence, true, &context) == PICOKEYS_OK);
|
||||
assert(context.facts == (FILE_OBJECT_FACT_OWNING_APPLICATION | FILE_OBJECT_FACT_SESSION_BOUND | FILE_OBJECT_FACT_INTERNAL_FIRMWARE));
|
||||
}
|
||||
|
||||
static void test_epoch_invalidation(void) {
|
||||
file_object_authorization_context_t before;
|
||||
file_object_authorization_context_t after;
|
||||
|
||||
assert(fido_object_authorization_context_build(NULL, false, &before) == PICOKEYS_OK);
|
||||
assert(fido_object_authorization_session_epoch() == before.session_epoch);
|
||||
fido_object_authorization_session_invalidate();
|
||||
assert(fido_object_authorization_context_build(NULL, false, &after) == PICOKEYS_OK);
|
||||
assert(after.session_epoch != before.session_epoch);
|
||||
assert(fido_object_authorization_session_epoch() == after.session_epoch);
|
||||
assert(after.facts_epoch == after.session_epoch);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
test_unauthenticated_context();
|
||||
test_operation_evidence();
|
||||
test_pin_uv_auth_context();
|
||||
test_internal_context();
|
||||
test_epoch_invalidation();
|
||||
assert(fido_object_authorization_context_build(NULL, false, NULL) == PICOKEYS_ERR_NULL_PARAM);
|
||||
puts("fido_object_authorization_test: OK");
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user