Add SSH host identity rotation controls
This commit is contained in:
+54
-33
@@ -707,6 +707,11 @@ static esp_err_t create_listener(void)
|
||||
|
||||
static esp_err_t start_runtime(void)
|
||||
{
|
||||
/* Never overwrite an orphaned context/listener or sessions after failed stop. */
|
||||
if (s_context != NULL || s_listen_fd >= 0) return ESP_ERR_INVALID_STATE;
|
||||
for (size_t index = 0U; index < SSH_TRANSPORT_MAX_SESSIONS; ++index) {
|
||||
if (s_slots[index].state != SSH_TRANSPORT_SESSION_FREE) return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
esp_err_t error = create_context();
|
||||
if (error == ESP_OK) {
|
||||
error = create_listener();
|
||||
@@ -752,7 +757,7 @@ static esp_err_t stop_runtime(void)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (s_context != NULL) {
|
||||
if (all_free && s_context != NULL) {
|
||||
wolfSSH_CTX_free(s_context);
|
||||
s_context = NULL;
|
||||
}
|
||||
@@ -1393,10 +1398,18 @@ static void process_slots(void)
|
||||
}
|
||||
if (all_free) {
|
||||
taskENTER_CRITICAL(&s_lock);
|
||||
if (!s_running) {
|
||||
s_cleanup_pending = false;
|
||||
}
|
||||
bool stopped = !s_running;
|
||||
taskEXIT_CRITICAL(&s_lock);
|
||||
/* The owner alone retires the retained context, before reopening admission. */
|
||||
if (stopped) {
|
||||
if (s_context != NULL) {
|
||||
wolfSSH_CTX_free(s_context);
|
||||
s_context = NULL;
|
||||
}
|
||||
taskENTER_CRITICAL(&s_lock);
|
||||
s_cleanup_pending = false;
|
||||
taskEXIT_CRITICAL(&s_lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1563,46 +1576,54 @@ esp_err_t ssh_transport_stop(void)
|
||||
return request_running(false);
|
||||
}
|
||||
|
||||
esp_err_t ssh_transport_replace_host_key(bool reset)
|
||||
esp_err_t ssh_transport_replace_identity(uint32_t service_generation,
|
||||
uint32_t identity_generation,
|
||||
bool reset, bool *committed)
|
||||
{
|
||||
if (s_command_mutex == NULL) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
xSemaphoreTake(s_command_mutex, portMAX_DELAY);
|
||||
if (!committed || (!!service_generation != !!identity_generation) ||
|
||||
(reset && service_generation) || service_generation == UINT32_MAX ||
|
||||
identity_generation == UINT32_MAX) return ESP_ERR_INVALID_ARG;
|
||||
*committed = false;
|
||||
if (!s_command_mutex) return ESP_ERR_INVALID_STATE;
|
||||
if (xSemaphoreTake(s_command_mutex, 0U) != pdTRUE) return ESP_ERR_TIMEOUT;
|
||||
|
||||
bool was_running;
|
||||
bool cleanup_pending;
|
||||
taskENTER_CRITICAL(&s_lock);
|
||||
if (!s_initialized || s_transitioning) {
|
||||
taskEXIT_CRITICAL(&s_lock);
|
||||
xSemaphoreGive(s_command_mutex);
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
was_running = s_running;
|
||||
cleanup_pending = s_cleanup_pending;
|
||||
bool valid = s_initialized && !s_transitioning &&
|
||||
(!service_generation || (!s_cleanup_pending && service_generation == s_management_generation));
|
||||
bool was_running = s_running, cleanup_pending = s_cleanup_pending;
|
||||
taskEXIT_CRITICAL(&s_lock);
|
||||
|
||||
esp_err_t error = ESP_OK;
|
||||
if (was_running || cleanup_pending) {
|
||||
error = request_running_locked(false);
|
||||
}
|
||||
uint32_t token = 0;
|
||||
esp_err_t error = valid ? ssh_security_reserve_identity(identity_generation, reset, &token)
|
||||
: ESP_ERR_INVALID_STATE;
|
||||
if (error == ESP_OK) {
|
||||
error = reset ? ssh_security_reset() : ssh_security_rotate();
|
||||
}
|
||||
if (error != ESP_OK) {
|
||||
if (was_running) {
|
||||
(void)request_running_locked(true);
|
||||
taskENTER_CRITICAL(&s_lock);
|
||||
if (s_management_generation != UINT32_MAX) ++s_management_generation;
|
||||
taskEXIT_CRITICAL(&s_lock);
|
||||
/* Keep the service mutex and identity reservation through stop/replace/start.
|
||||
* Failed stop must never mutate identity or attempt another start. */
|
||||
if (was_running || cleanup_pending) error = request_running_locked(false);
|
||||
if (error == ESP_OK) {
|
||||
error = ssh_security_replace_reserved(token);
|
||||
*committed = error == ESP_OK;
|
||||
if (error != ESP_OK && was_running) {
|
||||
/* Stop succeeded: restore service using unchanged committed material. */
|
||||
(void)request_running_locked(true);
|
||||
} else if (error == ESP_OK && (was_running || reset)) {
|
||||
error = request_running_locked(true);
|
||||
}
|
||||
}
|
||||
xSemaphoreGive(s_command_mutex);
|
||||
return error;
|
||||
}
|
||||
if (was_running || reset) {
|
||||
error = request_running_locked(true);
|
||||
}
|
||||
ssh_security_release_identity(token);
|
||||
xSemaphoreGive(s_command_mutex);
|
||||
return error;
|
||||
}
|
||||
|
||||
esp_err_t ssh_transport_replace_host_key(bool reset)
|
||||
{
|
||||
bool committed;
|
||||
return ssh_transport_replace_identity(0, 0, reset, &committed);
|
||||
}
|
||||
|
||||
esp_err_t ssh_transport_get_snapshot(ssh_transport_snapshot_t *snapshot)
|
||||
{
|
||||
if (snapshot == NULL) {
|
||||
|
||||
Reference in New Issue
Block a user