Add SSH host identity rotation controls
This commit is contained in:
@@ -40,6 +40,19 @@ static bool s_initialized, s_running, s_transitioning, s_cleanup_pending, s_desi
|
||||
static uint32_t s_management_generation, s_requested_sequence, s_completed_sequence;
|
||||
static int s_command_result;
|
||||
static bool owner_stalled, owner_fail;
|
||||
static uint32_t identity_generation = 3, identity_token;
|
||||
static unsigned replacements;
|
||||
static bool persist_fail;
|
||||
static esp_err_t ssh_security_reserve_identity(uint32_t generation, bool reset, uint32_t *token) {
|
||||
(void)reset; assert(mutex_storage && !depth); *token = 0;
|
||||
if (identity_token || (generation && generation != identity_generation)) return ESP_ERR_INVALID_STATE;
|
||||
*token = identity_token = 1; return ESP_OK;
|
||||
}
|
||||
static esp_err_t ssh_security_replace_reserved(uint32_t token) {
|
||||
assert(token == identity_token && mutex_storage && !depth && !s_running && !s_cleanup_pending);
|
||||
++replacements; if (persist_fail) return ESP_FAIL; ++identity_generation; return ESP_OK;
|
||||
}
|
||||
static void ssh_security_release_identity(uint32_t token) { if (token) { assert(identity_token == token && mutex_storage && !depth); identity_token = 0; } }
|
||||
static int s_lock;
|
||||
#define taskENTER_CRITICAL(p) do { (void)(p); assert(depth++ == 0); } while(0)
|
||||
#define taskEXIT_CRITICAL(p) do { (void)(p); assert(--depth == 0); } while(0)
|
||||
@@ -71,6 +84,24 @@ static void reset(void) {
|
||||
}
|
||||
}
|
||||
int main(void) {
|
||||
reset(); bool committed = true;
|
||||
assert(ssh_transport_replace_identity(6,3,false,&committed)==ESP_ERR_INVALID_STATE && !committed && !notifications && !replacements);
|
||||
assert(ssh_transport_replace_identity(7,2,false,&committed)==ESP_ERR_INVALID_STATE && !notifications && !replacements);
|
||||
identity_token=1; assert(ssh_transport_replace_identity(7,3,false,&committed)==ESP_ERR_INVALID_STATE && !notifications); identity_token=0;
|
||||
mutex_storage=1; assert(ssh_transport_replace_identity(7,3,false,&committed)==ESP_ERR_TIMEOUT && !notifications); mutex_storage=0;
|
||||
owner_fail=true; assert(ssh_transport_replace_identity(7,3,false,&committed)==ESP_FAIL && !committed && !replacements && notifications==1 && s_cleanup_pending && !identity_token);
|
||||
assert(ssh_transport_start()==ESP_ERR_INVALID_STATE && notifications==1);
|
||||
reset(); owner_stalled=true;
|
||||
assert(ssh_transport_replace_identity(7,3,false,&committed)==ESP_ERR_TIMEOUT && !committed && !replacements && notifications==1 && s_transitioning && !identity_token);
|
||||
reset(); persist_fail=true;
|
||||
assert(ssh_transport_replace_identity(7,3,false,&committed)==ESP_FAIL && !committed && replacements==1 && notifications==2 && s_running && identity_generation==3);
|
||||
reset(); persist_fail=false;
|
||||
assert(ssh_transport_replace_identity(7,3,false,&committed)==ESP_OK && committed && s_running && identity_generation==4 && notifications==2);
|
||||
assert(ssh_transport_replace_identity(7,3,false,&committed)==ESP_ERR_INVALID_STATE && !committed && notifications==2);
|
||||
reset(); s_running=false;
|
||||
assert(ssh_transport_replace_identity(7,4,false,&committed)==ESP_OK && committed && !s_running && !notifications);
|
||||
assert(ssh_transport_replace_host_key(true)==ESP_OK && s_running && notifications==1);
|
||||
puts("PASS SSH combined generation/service-owner admission, competing reservation, failed-stop no mutation/start, timeout retention, persistence recovery, replay fence and stopped/reset semantics");
|
||||
reset(); ssh_transport_management_snapshot_t v;
|
||||
assert(ssh_transport_get_management_snapshot(NULL) == ESP_ERR_INVALID_ARG);
|
||||
assert(ssh_transport_get_management_snapshot(&v) == ESP_OK && v.generation == 7 && v.running && !v.transitioning);
|
||||
@@ -128,7 +159,7 @@ int main(void) {
|
||||
puts("PASS SSH admitted timeout is not cancellation; failed cleanup and saturated versions preserve CLI recovery");
|
||||
}
|
||||
'''
|
||||
names = ('next_generation', 'make_session_id', 'consume_external_close', 'find_free_slot', 'request_running_locked', 'request_running', 'ssh_transport_start', 'ssh_transport_stop', 'ssh_transport_get_management_snapshot', 'ssh_transport_manage_current')
|
||||
names = ('next_generation', 'make_session_id', 'consume_external_close', 'find_free_slot', 'request_running_locked', 'request_running', 'ssh_transport_start', 'ssh_transport_stop', 'ssh_transport_replace_identity', 'ssh_transport_replace_host_key', 'ssh_transport_get_management_snapshot', 'ssh_transport_manage_current')
|
||||
# Guard the accept path, which is not executed with the socket double here.
|
||||
assert 'uint32_t generation = slot->generation + 1U;' in function('accept_connections')
|
||||
assert 'next_generation(slot->generation)' not in source
|
||||
|
||||
Reference in New Issue
Block a user