From a88b46113c28466cceeed03862d37bf3a3fbd700 Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Mon, 6 May 2024 12:33:19 +0200 Subject: [PATCH] Add authentication for system_restore_post This patch fixes the API spec to add authentication to the POST /system/restore endpoint. Fixes: https://github.com/Nitrokey/nethsm-sdk-rs/issues/15 --- .openapi-generator/FILES | 4 ++++ CHANGELOG.md | 5 +++++ docs/AkPub.md | 12 ++++++++++++ docs/DefaultApi.md | 6 +++--- docs/Pcr.md | 12 ++++++++++++ docs/SystemInfo.md | 4 ++-- nethsm-api.yaml | 40 ++++++++++++++++++++++++++++++--------- src/apis/default_api.rs | 9 +++++++-- src/models/ak_pub.rs | 26 +++++++++++++++++++++++++ src/models/mod.rs | 4 ++++ src/models/pcr.rs | 26 +++++++++++++++++++++++++ src/models/system_info.rs | 12 ++++++------ tests/basic.rs | 18 ++++++++++++++++-- 13 files changed, 154 insertions(+), 24 deletions(-) create mode 100644 docs/AkPub.md create mode 100644 docs/Pcr.md create mode 100644 src/models/ak_pub.rs create mode 100644 src/models/pcr.rs diff --git a/.openapi-generator/FILES b/.openapi-generator/FILES index 748fc6b..64cc307 100644 --- a/.openapi-generator/FILES +++ b/.openapi-generator/FILES @@ -1,3 +1,4 @@ +docs/AkPub.md docs/BackupPassphraseConfig.md docs/CreateResourceId.md docs/DecryptData.md @@ -20,6 +21,7 @@ docs/KeyType.md docs/LogLevel.md docs/LoggingConfig.md docs/NetworkConfig.md +docs/Pcr.md docs/PrivateKey.md docs/PrivateKeyPemArguments.md docs/ProvisionRequestData.md @@ -49,6 +51,7 @@ src/apis/configuration.rs src/apis/default_api.rs src/apis/mod.rs src/lib.rs +src/models/ak_pub.rs src/models/backup_passphrase_config.rs src/models/create_resource_id.rs src/models/decrypt_data.rs @@ -71,6 +74,7 @@ src/models/log_level.rs src/models/logging_config.rs src/models/mod.rs src/models/network_config.rs +src/models/pcr.rs src/models/private_key.rs src/models/private_key_pem_arguments.rs src/models/provision_request_data.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index f1c779e..5c9b961 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ - Return `Error::ResponseError` instead of `Error::Transport` for API errors ([#21](https://github.com/Nitrokey/nethsm-sdk-rs/issues/21)) - Fix multipart requests, namely `system_restore_post` ([#20](https://github.com/Nitrokey/nethsm-sdk-rs/issues/20)) +- Add authentication for `system_restore_post` ([#15](https://github.com/Nitrokey/nethsm-sdk-rs/issues/15)) + +### Changes + +- Add `AkPub` and `Pcr` schemas [All Changes](https://github.com/Nitrokey/nethsm-sdk-rs/compare/v1.0.1...HEAD) diff --git a/docs/AkPub.md b/docs/AkPub.md new file mode 100644 index 0000000..9b030c1 --- /dev/null +++ b/docs/AkPub.md @@ -0,0 +1,12 @@ +# AkPub + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**p256** | Option<**String**> | | [optional] +**p384** | Option<**String**> | | [optional] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/DefaultApi.md b/docs/DefaultApi.md index 43ec4e2..011fc8a 100644 --- a/docs/DefaultApi.md +++ b/docs/DefaultApi.md @@ -502,7 +502,7 @@ Name | Type | Description | Required | Notes > health_alive_get() -Retrieve wether NetHSM is alive (powered up). This corresponds to the state *Locked* or *Unprovisioned*. +Retrieve whether NetHSM is fully started but not ready to take traffic. This corresponds to the state *Locked* or *Unprovisioned*. ### Parameters @@ -529,7 +529,7 @@ No authorization required > health_ready_get() -Retrieve wether NetHSM is alive and ready to take traffic. This corresponds to the state *Operational*. +Retrieve whether NetHSM is in state *Operational* and thus ready to take traffic. ### Parameters @@ -1390,7 +1390,7 @@ Name | Type | Description | Required | Notes ### Authorization -No authorization required +[basic](../README.md#basic) ### HTTP request headers diff --git a/docs/Pcr.md b/docs/Pcr.md new file mode 100644 index 0000000..c8bd443 --- /dev/null +++ b/docs/Pcr.md @@ -0,0 +1,12 @@ +# Pcr + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**param_0** | Option<**String**> | | [optional] +**param_2** | Option<**String**> | | [optional] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/docs/SystemInfo.md b/docs/SystemInfo.md index 1b1ef3d..426bf50 100644 --- a/docs/SystemInfo.md +++ b/docs/SystemInfo.md @@ -9,8 +9,8 @@ Name | Type | Description | Notes **firmware_version** | **String** | | **hardware_version** | **String** | | **device_id** | **String** | | -**ak_pub** | [**serde_json::Value**](.md) | | -**pcr** | [**serde_json::Value**](.md) | | +**ak_pub** | [**crate::models::AkPub**](AkPub.md) | | +**pcr** | [**crate::models::Pcr**](Pcr.md) | | [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/nethsm-api.yaml b/nethsm-api.yaml index de6496e..67ac828 100644 --- a/nethsm-api.yaml +++ b/nethsm-api.yaml @@ -37,13 +37,13 @@ paths: get: responses: "200": - description: Yes, it is alive. + description: NetHSM is fully started and in state *Locked* or *Unprovisioned*. "406": description: Content type in Accept header not supported. "412": - description: Not locked or unprovisioned (in operational state). + description: NetHSM is not in state *Locked* or *Unprovisioned*. description: | - Retrieve wether NetHSM is alive (powered up). + Retrieve whether NetHSM is fully started but not ready to take traffic. This corresponds to the state *Locked* or *Unprovisioned*. x-annotation-role: - Public @@ -54,14 +54,13 @@ paths: get: responses: "200": - description: Yes, it is alive and ready. + description: NetHSM is in state *Operational*. "406": description: Content type in Accept header not supported. "412": - description: Not alive and ready (not in operational state). + description: NetHSM is not in state *Operational*. description: | - Retrieve wether NetHSM is alive and ready to take traffic. - This corresponds to the state *Operational*. + Retrieve whether NetHSM is in state *Operational* and thus ready to take traffic. x-annotation-role: - Public x-annotation-state: @@ -1839,6 +1838,9 @@ paths: multipart/form-data: schema: $ref: "#/components/schemas/RestoreRequest" + security: + - {} # for complete restore + - basic: [] # for partial restore x-annotation-role: - Public x-annotation-state: @@ -1846,6 +1848,26 @@ paths: - Operational components: schemas: + AkPub: + example: + P256: MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEup7z8QYvkzkBuLryG1SgVQjlPhSFW3PzYn1l3uLNd+pSBxX0OBpslcbnmPFr5wSs/iP46+H8MFlEAYUkYv6uuQ== + P384: MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEfQiurLvEmjsAmumRtIqu70HKehRo8A/nVrqQGiR8Rcr+SUujwgtQByORX5BoRtv4sZNJW4FyLGqvXCIF9IV1puob2+9Qq5oEjz4x4malLbFdyXDmQK8o2NpvcbgOr215 + type: object + properties: + P256: + type: string + P384: + type: string + Pcr: + example: + 0: 0f6064779fba55b102a6ecc20498c2020deaf2aebef23716ec293b25873647f8 + 2: 2b0d25a4a92b4df5205742954243db9d306a4c3277a6b6958bcbaf3d47def26f + type: object + properties: + 0: + type: string + 2: + type: string Passphrase: minLength: 10 type: string @@ -2478,9 +2500,9 @@ components: deviceId: type: string akPub: - type: object + $ref: "#/components/schemas/AkPub" pcr: - type: object + $ref: "#/components/schemas/Pcr" required: - softwareVersion - softwareBuild diff --git a/src/apis/default_api.rs b/src/apis/default_api.rs index 2136b75..607aa17 100644 --- a/src/apis/default_api.rs +++ b/src/apis/default_api.rs @@ -1681,7 +1681,7 @@ pub fn config_unlock_passphrase_put( } } -/// Retrieve wether NetHSM is alive (powered up). This corresponds to the state *Locked* or *Unprovisioned*. +/// Retrieve whether NetHSM is fully started but not ready to take traffic. This corresponds to the state *Locked* or *Unprovisioned*. pub fn health_alive_get( configuration: &configuration::Configuration, @@ -1734,7 +1734,7 @@ pub fn health_alive_get( } } -/// Retrieve wether NetHSM is alive and ready to take traffic. This corresponds to the state *Operational*. +/// Retrieve whether NetHSM is in state *Operational* and thus ready to take traffic. pub fn health_ready_get( configuration: &configuration::Configuration, @@ -3590,6 +3590,11 @@ pub fn system_restore_post( if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { local_var_req_builder = local_var_req_builder.set("user-agent", local_var_user_agent); } + if let Some(ref local_var_auth_conf) = local_var_configuration.basic_auth { + let value = super::basic_auth(local_var_auth_conf); + + local_var_req_builder = local_var_req_builder.set("authorization", &value); + }; let mut local_var_multipart = ::multipart::client::lazy::Multipart::new(); diff --git a/src/models/ak_pub.rs b/src/models/ak_pub.rs new file mode 100644 index 0000000..ff97176 --- /dev/null +++ b/src/models/ak_pub.rs @@ -0,0 +1,26 @@ +/* + * NetHSM + * + * All endpoints expect exactly the specified JSON. Additional properties will cause a Bad Request Error (400). All HTTP errors contain a JSON structure with an explanation of type string. All [base64](https://tools.ietf.org/html/rfc4648#section-4) encoded values are Big Endian. + * + * The version of the OpenAPI document: v1 + * Contact: Nitrokey + * Generated by: https://openapi-generator.tech + */ + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct AkPub { + #[serde(rename = "P256", skip_serializing_if = "Option::is_none")] + pub p256: Option, + #[serde(rename = "P384", skip_serializing_if = "Option::is_none")] + pub p384: Option, +} + +impl AkPub { + pub fn new() -> AkPub { + AkPub { + p256: None, + p384: None, + } + } +} diff --git a/src/models/mod.rs b/src/models/mod.rs index 9459eac..ec0112c 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -1,3 +1,5 @@ +pub mod ak_pub; +pub use self::ak_pub::AkPub; pub mod backup_passphrase_config; pub use self::backup_passphrase_config::BackupPassphraseConfig; pub mod create_resource_id; @@ -40,6 +42,8 @@ pub mod logging_config; pub use self::logging_config::LoggingConfig; pub mod network_config; pub use self::network_config::NetworkConfig; +pub mod pcr; +pub use self::pcr::Pcr; pub mod private_key; pub use self::private_key::PrivateKey; pub mod private_key_pem_arguments; diff --git a/src/models/pcr.rs b/src/models/pcr.rs new file mode 100644 index 0000000..5259a01 --- /dev/null +++ b/src/models/pcr.rs @@ -0,0 +1,26 @@ +/* + * NetHSM + * + * All endpoints expect exactly the specified JSON. Additional properties will cause a Bad Request Error (400). All HTTP errors contain a JSON structure with an explanation of type string. All [base64](https://tools.ietf.org/html/rfc4648#section-4) encoded values are Big Endian. + * + * The version of the OpenAPI document: v1 + * Contact: Nitrokey + * Generated by: https://openapi-generator.tech + */ + +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] +pub struct Pcr { + #[serde(rename = "0", skip_serializing_if = "Option::is_none")] + pub param_0: Option, + #[serde(rename = "2", skip_serializing_if = "Option::is_none")] + pub param_2: Option, +} + +impl Pcr { + pub fn new() -> Pcr { + Pcr { + param_0: None, + param_2: None, + } + } +} diff --git a/src/models/system_info.rs b/src/models/system_info.rs index e774c95..9ec2ca7 100644 --- a/src/models/system_info.rs +++ b/src/models/system_info.rs @@ -21,9 +21,9 @@ pub struct SystemInfo { #[serde(rename = "deviceId")] pub device_id: String, #[serde(rename = "akPub")] - pub ak_pub: serde_json::Value, + pub ak_pub: Box, #[serde(rename = "pcr")] - pub pcr: serde_json::Value, + pub pcr: Box, } impl SystemInfo { @@ -33,8 +33,8 @@ impl SystemInfo { firmware_version: String, hardware_version: String, device_id: String, - ak_pub: serde_json::Value, - pcr: serde_json::Value, + ak_pub: crate::models::AkPub, + pcr: crate::models::Pcr, ) -> SystemInfo { SystemInfo { software_version, @@ -42,8 +42,8 @@ impl SystemInfo { firmware_version, hardware_version, device_id, - ak_pub, - pcr, + ak_pub: Box::new(ak_pub), + pcr: Box::new(pcr), } } } diff --git a/tests/basic.rs b/tests/basic.rs index 296ef98..20c25ab 100644 --- a/tests/basic.rs +++ b/tests/basic.rs @@ -41,8 +41,9 @@ async fn test_error() { }) .await } + #[tokio::test] -async fn test_restore_unprovisioned() { +async fn test_restore() { let admin_passphrase = "adminadmin"; let backup_passphrase = "backupbackup"; let unlock_passphrase = "unlockunlock"; @@ -67,7 +68,7 @@ async fn test_restore_unprovisioned() { .unwrap() .entity .id; - let keys = BTreeSet::from([key_id]); + let keys = BTreeSet::from([key_id.clone()]); assert_eq!(list_keys(&config), keys); @@ -88,6 +89,19 @@ async fn test_restore_unprovisioned() { let backup = default_api::system_backup_post(&config).unwrap().entity; + config.basic_auth = Some(("admin".to_owned(), Some(admin_passphrase.to_owned()))); + + default_api::keys_key_id_delete(&config, &key_id).unwrap(); + assert_eq!(list_keys(&config), BTreeSet::default()); + + let request = RestoreRequestArguments { + backup_passphrase: Some(backup_passphrase.to_owned()), + system_time: Some(Utc::now().to_rfc3339()), + }; + default_api::system_restore_post(&config, Some(request), Some(backup.clone())).unwrap(); + + assert_eq!(list_keys(&config), keys); + (keys, backup) }) .await;