Allow SSH keys on multiple accounts
Update validation and duplicate checks to scope key uniqueness per account, and clarify the console error message. Document cross-account key assignment and authentication testing.
This commit is contained in:
@@ -48,10 +48,12 @@ Verify all of the following fail without changing the account generation or key
|
|||||||
|
|
||||||
- Unsupported RSA, certificate, or unknown key types.
|
- Unsupported RSA, certificate, or unknown key types.
|
||||||
- Truncated/invalid Base64, mismatched outer and embedded types, trailing blob data, malformed Ed25519 lengths, and an invalid/off-curve ECDSA point.
|
- Truncated/invalid Base64, mismatched outer and embedded types, trailing blob data, malformed Ed25519 lengths, and an invalid/off-curve ECDSA point.
|
||||||
- Adding the same key again to the same account or assigning it to a different account.
|
- Adding the same key again to the same account.
|
||||||
- Adding a fourth key to an account that already has three.
|
- Adding a fourth key to an account that already has three.
|
||||||
- Deleting an empty/out-of-range slot.
|
- Deleting an empty/out-of-range slot.
|
||||||
|
|
||||||
|
Assign the same public key to a second account and confirm it is accepted, receives an independent slot, and authenticates as the username selected by the SSH client.
|
||||||
|
|
||||||
Then exercise `user key delete <username> <index> --force` and `user key clear <username> --force`, reboot, and confirm the exact remaining fingerprints persist. Phase 8A stores these keys but does not yet accept SSH key login.
|
Then exercise `user key delete <username> <index> --force` and `user key clear <username> --force`, reboot, and confirm the exact remaining fingerprints persist. Phase 8A stores these keys but does not yet accept SSH key login.
|
||||||
|
|
||||||
### 5. Legacy credential rotation boundary and reboot reconciliation
|
### 5. Legacy credential rotation boundary and reboot reconciliation
|
||||||
|
|||||||
+1
-1
@@ -357,7 +357,7 @@ static int add_key(const char *username)
|
|||||||
secure_wipe(line, sizeof(line));
|
secure_wipe(line, sizeof(line));
|
||||||
if (error != ESP_OK) {
|
if (error != ESP_OK) {
|
||||||
if (error == USER_DATABASE_ERR_DUPLICATE_SSH_KEY) {
|
if (error == USER_DATABASE_ERR_DUPLICATE_SSH_KEY) {
|
||||||
printf("Could not add SSH key: that public key is already assigned to an account.\n");
|
printf("Could not add SSH key: that public key is already assigned to this account.\n");
|
||||||
} else if (error == ESP_ERR_NO_MEM) {
|
} else if (error == ESP_ERR_NO_MEM) {
|
||||||
printf("Could not add SSH key: the account already has %u keys.\n",
|
printf("Could not add SSH key: the account already has %u keys.\n",
|
||||||
USER_DATABASE_MAX_SSH_KEYS_PER_USER);
|
USER_DATABASE_MAX_SSH_KEYS_PER_USER);
|
||||||
|
|||||||
+8
-23
@@ -387,17 +387,11 @@ static esp_err_t validate_database(const stored_database_t *database)
|
|||||||
sizeof(key->blob) - key->blob_length)) {
|
sizeof(key->blob) - key->blob_length)) {
|
||||||
return ESP_ERR_INVALID_RESPONSE;
|
return ESP_ERR_INVALID_RESPONSE;
|
||||||
}
|
}
|
||||||
for (size_t prior_user = 0U; prior_user <= index; ++prior_user) {
|
for (size_t prior_key = 0U; prior_key < key_index; ++prior_key) {
|
||||||
size_t prior_key_limit = prior_user == index
|
if (stored_keys_equal(key, &user->keys[prior_key])) {
|
||||||
? key_index
|
|
||||||
: USER_DATABASE_MAX_SSH_KEYS_PER_USER;
|
|
||||||
for (size_t prior_key = 0U; prior_key < prior_key_limit; ++prior_key) {
|
|
||||||
if (stored_keys_equal(key,
|
|
||||||
&database->users[prior_user].keys[prior_key])) {
|
|
||||||
return ESP_ERR_INVALID_RESPONSE;
|
return ESP_ERR_INVALID_RESPONSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
uint8_t fingerprint[USER_DATABASE_SHA256_LENGTH];
|
uint8_t fingerprint[USER_DATABASE_SHA256_LENGTH];
|
||||||
if (mbedtls_sha256(key->blob, key->blob_length, fingerprint, 0) != 0 ||
|
if (mbedtls_sha256(key->blob, key->blob_length, fingerprint, 0) != 0 ||
|
||||||
!constant_time_equal(fingerprint, key->fingerprint,
|
!constant_time_equal(fingerprint, key->fingerprint,
|
||||||
@@ -1157,21 +1151,16 @@ esp_err_t user_database_add_ssh_key(
|
|||||||
if (error == ESP_OK) {
|
if (error == ESP_OK) {
|
||||||
stored_user_t *user = &s_candidate.users[user_index];
|
stored_user_t *user = &s_candidate.users[user_index];
|
||||||
int free_index = -1;
|
int free_index = -1;
|
||||||
for (size_t candidate_user_index = 0U;
|
|
||||||
candidate_user_index < USER_DATABASE_MAX_USERS; ++candidate_user_index) {
|
|
||||||
stored_user_t *candidate_user =
|
|
||||||
&s_candidate.users[candidate_user_index];
|
|
||||||
if (candidate_user->active == 0U) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
for (size_t index = 0U;
|
for (size_t index = 0U;
|
||||||
index < USER_DATABASE_MAX_SSH_KEYS_PER_USER; ++index) {
|
index < USER_DATABASE_MAX_SSH_KEYS_PER_USER; ++index) {
|
||||||
stored_key_t *key = &candidate_user->keys[index];
|
stored_key_t *key = &user->keys[index];
|
||||||
if (candidate_user_index == (size_t)user_index &&
|
if (key->active == 0U) {
|
||||||
key->active == 0U && free_index < 0) {
|
if (free_index < 0) {
|
||||||
free_index = (int)index;
|
free_index = (int)index;
|
||||||
}
|
}
|
||||||
if (key->active != 0U && key->type_length == key_type_length &&
|
continue;
|
||||||
|
}
|
||||||
|
if (key->type_length == key_type_length &&
|
||||||
key->blob_length == key_blob_length &&
|
key->blob_length == key_blob_length &&
|
||||||
memcmp(key->type, key_type, key_type_length) == 0 &&
|
memcmp(key->type, key_type, key_type_length) == 0 &&
|
||||||
constant_time_equal(key->blob, key_blob, key_blob_length)) {
|
constant_time_equal(key->blob, key_blob, key_blob_length)) {
|
||||||
@@ -1179,10 +1168,6 @@ esp_err_t user_database_add_ssh_key(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (error != ESP_OK) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (error == ESP_OK && free_index < 0) {
|
if (error == ESP_OK && free_index < 0) {
|
||||||
error = ESP_ERR_NO_MEM;
|
error = ESP_ERR_NO_MEM;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user