Implement SSH authorized key management
This commit is contained in:
+96
-10
@@ -1091,6 +1091,44 @@ static bool target_matches_locked(const uint8_t *username, size_t length,
|
||||
s_database.users[index].auth_generation == expected->auth_generation;
|
||||
}
|
||||
|
||||
esp_err_t user_database_get_account_keys(const user_database_account_t *expected,
|
||||
user_database_user_snapshot_t *snapshot)
|
||||
{
|
||||
if (!snapshot) return ESP_ERR_INVALID_ARG;
|
||||
memset(snapshot, 0, sizeof(*snapshot));
|
||||
if (!expected) return ESP_ERR_INVALID_ARG;
|
||||
size_t length = strnlen(expected->username, sizeof(expected->username));
|
||||
if (!user_database_username_valid((const uint8_t *)expected->username, length))
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
if (!s_initialized || !s_mutex) return ESP_ERR_INVALID_STATE;
|
||||
if (xSemaphoreTake(s_mutex, 0U) != pdTRUE) return ESP_ERR_TIMEOUT;
|
||||
esp_err_t error = ESP_ERR_NOT_FOUND;
|
||||
if (target_matches_locked((const uint8_t *)expected->username, length, expected)) {
|
||||
const stored_user_t *user = &s_database.users[find_user(&s_database,
|
||||
(const uint8_t *)expected->username, length)];
|
||||
snapshot->active = true;
|
||||
snapshot->user_id = user->user_id;
|
||||
snapshot->auth_generation = user->auth_generation;
|
||||
snapshot->role = (user_role_t)user->role;
|
||||
snapshot->username_length = length;
|
||||
memcpy(snapshot->username, user->username, length);
|
||||
snapshot->public_key_count = user->key_count;
|
||||
for (size_t i = 0; i < USER_DATABASE_MAX_SSH_KEYS_PER_USER; ++i) {
|
||||
const stored_key_t *key = &user->keys[i];
|
||||
if (!key->active) continue;
|
||||
user_database_key_snapshot_t *out = &snapshot->public_keys[i];
|
||||
out->active = true;
|
||||
out->index = (uint8_t)i;
|
||||
out->key_type_length = key->type_length;
|
||||
memcpy(out->key_type, key->type, key->type_length);
|
||||
memcpy(out->sha256_fingerprint, key->fingerprint, sizeof(out->sha256_fingerprint));
|
||||
}
|
||||
error = ESP_OK;
|
||||
}
|
||||
xSemaphoreGive(s_mutex);
|
||||
return error;
|
||||
}
|
||||
|
||||
static esp_err_t delete_user(const uint8_t *username, size_t username_length,
|
||||
const user_database_account_t *expected)
|
||||
{
|
||||
@@ -1245,11 +1283,11 @@ esp_err_t user_database_generate_password(
|
||||
return error;
|
||||
}
|
||||
|
||||
esp_err_t user_database_add_ssh_key(
|
||||
static esp_err_t add_ssh_key(
|
||||
const uint8_t *username, size_t username_length,
|
||||
const uint8_t *key_type, size_t key_type_length,
|
||||
const uint8_t *key_blob, size_t key_blob_length,
|
||||
uint8_t *key_index)
|
||||
uint8_t *key_index, const user_database_account_t *expected)
|
||||
{
|
||||
if (!s_initialized || s_mutex == NULL || key_index == NULL ||
|
||||
!user_database_key_valid(key_type, key_type_length, key_blob, key_blob_length)) {
|
||||
@@ -1257,7 +1295,8 @@ esp_err_t user_database_add_ssh_key(
|
||||
}
|
||||
xSemaphoreTake(s_mutex, portMAX_DELAY);
|
||||
int user_index;
|
||||
esp_err_t error = mutate_user_begin(username, username_length, &user_index);
|
||||
esp_err_t error = target_matches_locked(username, username_length, expected)
|
||||
? mutate_user_begin(username, username_length, &user_index) : ESP_ERR_NOT_FOUND;
|
||||
if (error == ESP_OK) {
|
||||
stored_user_t *user = &s_candidate->users[user_index];
|
||||
int free_index = -1;
|
||||
@@ -1308,9 +1347,9 @@ esp_err_t user_database_add_ssh_key(
|
||||
return error;
|
||||
}
|
||||
|
||||
esp_err_t user_database_remove_ssh_key(const uint8_t *username,
|
||||
size_t username_length,
|
||||
uint8_t key_index)
|
||||
static esp_err_t remove_ssh_key(const uint8_t *username,
|
||||
size_t username_length, uint8_t key_index,
|
||||
const user_database_account_t *expected)
|
||||
{
|
||||
if (!s_initialized || s_mutex == NULL ||
|
||||
key_index >= USER_DATABASE_MAX_SSH_KEYS_PER_USER) {
|
||||
@@ -1318,7 +1357,8 @@ esp_err_t user_database_remove_ssh_key(const uint8_t *username,
|
||||
}
|
||||
xSemaphoreTake(s_mutex, portMAX_DELAY);
|
||||
int user_index;
|
||||
esp_err_t error = mutate_user_begin(username, username_length, &user_index);
|
||||
esp_err_t error = target_matches_locked(username, username_length, expected)
|
||||
? mutate_user_begin(username, username_length, &user_index) : ESP_ERR_NOT_FOUND;
|
||||
if (error == ESP_OK) {
|
||||
stored_user_t *user = &s_candidate->users[user_index];
|
||||
if (user->keys[key_index].active == 0U) {
|
||||
@@ -1339,15 +1379,17 @@ esp_err_t user_database_remove_ssh_key(const uint8_t *username,
|
||||
return error;
|
||||
}
|
||||
|
||||
esp_err_t user_database_clear_ssh_keys(const uint8_t *username,
|
||||
size_t username_length)
|
||||
static esp_err_t clear_ssh_keys(const uint8_t *username,
|
||||
size_t username_length,
|
||||
const user_database_account_t *expected)
|
||||
{
|
||||
if (!s_initialized || s_mutex == NULL) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
xSemaphoreTake(s_mutex, portMAX_DELAY);
|
||||
int user_index;
|
||||
esp_err_t error = mutate_user_begin(username, username_length, &user_index);
|
||||
esp_err_t error = target_matches_locked(username, username_length, expected)
|
||||
? mutate_user_begin(username, username_length, &user_index) : ESP_ERR_NOT_FOUND;
|
||||
if (error == ESP_OK) {
|
||||
stored_user_t *user = &s_candidate->users[user_index];
|
||||
if (user->key_count == 0U) {
|
||||
@@ -1367,3 +1409,47 @@ esp_err_t user_database_clear_ssh_keys(const uint8_t *username,
|
||||
xSemaphoreGive(s_mutex);
|
||||
return error;
|
||||
}
|
||||
|
||||
esp_err_t user_database_add_ssh_key(const uint8_t *username, size_t length,
|
||||
const uint8_t *type, size_t type_length, const uint8_t *blob, size_t blob_length,
|
||||
uint8_t *index)
|
||||
{
|
||||
return add_ssh_key(username, length, type, type_length, blob, blob_length, index, NULL);
|
||||
}
|
||||
|
||||
esp_err_t user_database_remove_ssh_key(const uint8_t *username, size_t length, uint8_t index)
|
||||
{
|
||||
return remove_ssh_key(username, length, index, NULL);
|
||||
}
|
||||
|
||||
esp_err_t user_database_clear_ssh_keys(const uint8_t *username, size_t length)
|
||||
{
|
||||
return clear_ssh_keys(username, length, NULL);
|
||||
}
|
||||
|
||||
static bool key_target_valid(const user_database_account_t *expected)
|
||||
{
|
||||
return expected && user_database_username_valid((const uint8_t *)expected->username,
|
||||
strnlen(expected->username, sizeof(expected->username)));
|
||||
}
|
||||
|
||||
esp_err_t user_database_add_ssh_key_current(const user_database_account_t *expected,
|
||||
const uint8_t *type, size_t type_length, const uint8_t *blob, size_t blob_length,
|
||||
uint8_t *index)
|
||||
{
|
||||
if (!key_target_valid(expected)) return ESP_ERR_INVALID_ARG;
|
||||
return add_ssh_key((const uint8_t *)expected->username, strlen(expected->username),
|
||||
type, type_length, blob, blob_length, index, expected);
|
||||
}
|
||||
|
||||
esp_err_t user_database_remove_ssh_key_current(const user_database_account_t *expected, uint8_t index)
|
||||
{
|
||||
if (!key_target_valid(expected)) return ESP_ERR_INVALID_ARG;
|
||||
return remove_ssh_key((const uint8_t *)expected->username, strlen(expected->username), index, expected);
|
||||
}
|
||||
|
||||
esp_err_t user_database_clear_ssh_keys_current(const user_database_account_t *expected)
|
||||
{
|
||||
if (!key_target_valid(expected)) return ESP_ERR_INVALID_ARG;
|
||||
return clear_ssh_keys((const uint8_t *)expected->username, strlen(expected->username), expected);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user