Remove Legacy Credential Bootstrap Paths
Decouple user provisioning from HTTPS identity storage while retaining compatible v1 user records and migrating TLS material to the credential-free v2 format. Add focused security regression coverage and update operator documentation.
This commit is contained in:
@@ -6,7 +6,6 @@ static void reset(void)
|
||||
s_candidate=&candidate_storage; s_mutex=(void *)1; s_initialized=true;
|
||||
s_database.version=USER_DATABASE_SCHEMA_VERSION;
|
||||
s_database.size=sizeof(s_database); s_database.generation=1;
|
||||
s_database.admin_bootstrapped=1;
|
||||
fail_stage=0; invalidate_during_derivation=false; derivation_invalidations=0;
|
||||
assert(initialize_user(&s_database.users[0], (const uint8_t *)"admin", 5,
|
||||
USER_ROLE_ADMIN, (const uint8_t *)"test-password", 13)==ESP_OK);
|
||||
@@ -138,8 +137,80 @@ static void typed_password_tests(void)
|
||||
}
|
||||
assert(user_database_generate_password_value(NULL)==ESP_ERR_INVALID_ARG);
|
||||
}
|
||||
static void unload_database(void)
|
||||
{
|
||||
s_initialized=false; s_mutex=NULL; release_candidate();
|
||||
secure_wipe(&s_database,sizeof(s_database));
|
||||
}
|
||||
|
||||
static void storage_tests(void)
|
||||
{
|
||||
reset(); storage_test=true;
|
||||
/* Both historical v1 states load without any account/verifier/ID changes. */
|
||||
for (unsigned admins=0;admins<2;++admins) {
|
||||
reset();
|
||||
s_database.users[0].role=admins ? USER_ROLE_ADMIN : USER_ROLE_USER;
|
||||
recount(&s_database);
|
||||
stored_database_t before=s_database;
|
||||
memcpy(persisted,&before,sizeof(before)); persisted_size=sizeof(before);
|
||||
unload_database();
|
||||
user_database_load_result_t result;
|
||||
assert(user_database_init(&result)==ESP_OK && result==USER_DATABASE_LOAD_STORED);
|
||||
assert(!memcmp(&before,&s_database,sizeof(before)) && !writes && !commits);
|
||||
assert(user_database_recover_empty()==ESP_ERR_INVALID_STATE);
|
||||
if (!admins) {
|
||||
assert(user_database_delete((const uint8_t *)"admin",5)==ESP_OK);
|
||||
assert(s_database.admin_count==0 && s_database.user_count==2);
|
||||
}
|
||||
}
|
||||
for (unsigned kind=0;kind<4;++kind) {
|
||||
reset(); stored_database_t bad=s_database;
|
||||
if (kind==0) ++bad.version;
|
||||
if (kind==1) bad.v1_admin_marker=0;
|
||||
if (kind==2) bad.users[0].user_id=0;
|
||||
memcpy(persisted,&bad,sizeof(bad)); persisted_size=sizeof(bad)-(kind==3);
|
||||
size_t size=persisted_size;
|
||||
unload_database(); user_database_load_result_t result;
|
||||
assert(user_database_init(&result)!=ESP_OK && !s_initialized && !s_mutex);
|
||||
assert(!writes && !commits && persisted_size==size && !memcmp(persisted,&bad,size));
|
||||
web=false; remote=true;
|
||||
assert(run("user recover --force")!=0 && !writes);
|
||||
remote=false;
|
||||
assert(run("user recover")!=0 && !writes);
|
||||
assert(run("user recover --force")==0 && s_initialized);
|
||||
assert(!s_database.user_count && !s_database.admin_count);
|
||||
assert(validate_database(&s_database)==ESP_OK);
|
||||
}
|
||||
reset(); unload_database(); persisted_size=0;
|
||||
user_database_load_result_t result;
|
||||
assert(user_database_init(&result)==ESP_OK && result==USER_DATABASE_LOAD_EMPTY);
|
||||
assert(s_initialized && !s_database.user_count && writes==1 && commits==1);
|
||||
stored_database_t empty=s_database;
|
||||
assert(persisted_size==sizeof(empty) && !memcmp(persisted,&empty,sizeof(empty)));
|
||||
unload_database();
|
||||
assert(user_database_init(&result)==ESP_OK && result==USER_DATABASE_LOAD_STORED);
|
||||
assert(!memcmp(&empty,&s_database,sizeof(empty)) && writes==1 && commits==1);
|
||||
user_database_snapshot_t snapshot;
|
||||
assert(user_database_get_snapshot(&snapshot)==ESP_OK && snapshot.initialized);
|
||||
assert(!snapshot.user_count && !snapshot.admin_count);
|
||||
web=remote=false;
|
||||
assert(run("user bootstrap")!=0 && run("user bootstrap --generate")!=0);
|
||||
assert(run("user recover --force")!=0 && !memcmp(&empty,&s_database,sizeof(empty)));
|
||||
assert(run("user add chief admin")==0 && s_database.admin_count==1);
|
||||
assert(user_database_delete((const uint8_t *)"chief",5)==ESP_ERR_INVALID_STATE);
|
||||
assert(user_database_set_role((const uint8_t *)"chief",5,USER_ROLE_USER)==ESP_ERR_INVALID_STATE);
|
||||
for (unsigned stage=1;stage<=3;++stage) {
|
||||
reset(); unload_database(); persisted_size=0; fail_stage=stage;
|
||||
assert(user_database_init(&result)==ESP_FAIL && !s_initialized && !s_mutex);
|
||||
assert(!persisted_size);
|
||||
assert(user_database_recover_empty()==ESP_FAIL && !s_initialized && !s_mutex);
|
||||
}
|
||||
storage_test=false;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
storage_tests();
|
||||
typed_account_tests();
|
||||
typed_password_tests();
|
||||
const char *supported[]={
|
||||
|
||||
Reference in New Issue
Block a user