From 275f6f80772a114558982d09cdddfdfc338d5de6 Mon Sep 17 00:00:00 2001 From: George Arama <50641385+gearama@users.noreply.github.com> Date: Fri, 13 Jan 2023 11:00:46 -0800 Subject: [PATCH] Okp (#4239) * first pass * part2 * part3 * part 5 * pre PR * updated tests * fix test * clangs * updated changelog --- sdk/keyvault/assets.json | 2 +- .../azure-security-keyvault-keys/CHANGELOG.md | 2 + .../cryptography_client_options.hpp | 5 +- .../inc/azure/keyvault/keys/key_client.hpp | 17 +++++ .../azure/keyvault/keys/key_client_models.hpp | 26 ++++++- .../keyvault/keys/key_client_options.hpp | 76 ++++++++++++++++++- .../src/key_client.cpp | 21 +++++ .../src/key_curve_name.cpp | 2 + .../src/key_request_parameters.cpp | 20 +++-- .../src/key_type.cpp | 2 + .../src/keyvault_protocol.cpp | 2 +- .../src/private/key_constants.hpp | 3 + .../src/private/key_request_parameters.hpp | 9 +++ .../test/ut/key_client_create_test_live.cpp | 48 ++++++++++++ .../test/ut/key_client_test.cpp | 2 +- 15 files changed, 222 insertions(+), 15 deletions(-) diff --git a/sdk/keyvault/assets.json b/sdk/keyvault/assets.json index 9377449c7..cbe416b73 100644 --- a/sdk/keyvault/assets.json +++ b/sdk/keyvault/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "cpp", "TagPrefix": "cpp/keyvault", - "Tag": "cpp/keyvault_ea82152bd3" + "Tag": "cpp/keyvault_fd91dfe00e" } diff --git a/sdk/keyvault/azure-security-keyvault-keys/CHANGELOG.md b/sdk/keyvault/azure-security-keyvault-keys/CHANGELOG.md index e5fb3a3b2..4b06b5883 100644 --- a/sdk/keyvault/azure-security-keyvault-keys/CHANGELOG.md +++ b/sdk/keyvault/azure-security-keyvault-keys/CHANGELOG.md @@ -4,6 +4,8 @@ ### Features Added +- Support for OKP keys. + ### Breaking Changes ### Bugs Fixed diff --git a/sdk/keyvault/azure-security-keyvault-keys/inc/azure/keyvault/keys/cryptography/cryptography_client_options.hpp b/sdk/keyvault/azure-security-keyvault-keys/inc/azure/keyvault/keys/cryptography/cryptography_client_options.hpp index 5adfc81ce..70cefe2c0 100644 --- a/sdk/keyvault/azure-security-keyvault-keys/inc/azure/keyvault/keys/cryptography/cryptography_client_options.hpp +++ b/sdk/keyvault/azure-security-keyvault-keys/inc/azure/keyvault/keys/cryptography/cryptography_client_options.hpp @@ -39,6 +39,9 @@ namespace Azure { * @brief Construct a new Key Client Options object. * */ - CryptographyClientOptions() : Azure::Core::_internal::ClientOptions() { Version = "7.3"; } + CryptographyClientOptions() : Azure::Core::_internal::ClientOptions() + { + Version = "7.4-preview.1"; + } }; }}}}} // namespace Azure::Security::KeyVault::Keys::Cryptography diff --git a/sdk/keyvault/azure-security-keyvault-keys/inc/azure/keyvault/keys/key_client.hpp b/sdk/keyvault/azure-security-keyvault-keys/inc/azure/keyvault/keys/key_client.hpp index 4371ddd6b..738cc3f36 100644 --- a/sdk/keyvault/azure-security-keyvault-keys/inc/azure/keyvault/keys/key_client.hpp +++ b/sdk/keyvault/azure-security-keyvault-keys/inc/azure/keyvault/keys/key_client.hpp @@ -173,6 +173,23 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Keys { CreateOctKeyOptions const& octKeyOptions, Azure::Core::Context const& context = Azure::Core::Context()) const; + /** + * @brief Creates and stores a new OKP key in Key Vault. + * + * @remark If the named key already exists, Azure Key Vault creates a new version of the + * key. + * + * @remark This operation requires the keys/create permission. + * + * @param okpKeyOptions The key options object containing information about the OKP key + * being created. + * @param context A #Azure::Core::Context controlling the request lifetime. + * @return The Key wrapped in the Response. + */ + Azure::Response CreateOkpKey( + CreateOkpKeyOptions const& okpKeyOptions, + Azure::Core::Context const& context = Azure::Core::Context()) const; + /** * @brief Get a single page with the properties of all keys in the specified vault. You can * use the returned #KeyProperties.Name in subsequent calls to #GetKey. diff --git a/sdk/keyvault/azure-security-keyvault-keys/inc/azure/keyvault/keys/key_client_models.hpp b/sdk/keyvault/azure-security-keyvault-keys/inc/azure/keyvault/keys/key_client_models.hpp index 6688e64a0..4ac09f32a 100644 --- a/sdk/keyvault/azure-security-keyvault-keys/inc/azure/keyvault/keys/key_client_models.hpp +++ b/sdk/keyvault/azure-security-keyvault-keys/inc/azure/keyvault/keys/key_client_models.hpp @@ -214,6 +214,18 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Keys { * */ AZ_SECURITY_KEYVAULT_KEYS_DLLEXPORT static const KeyVaultKeyType OctHsm; + + /** + * @brief An OKP cryptographic algorithm. + * + */ + AZ_SECURITY_KEYVAULT_KEYS_DLLEXPORT static const KeyVaultKeyType Okp; + + /** + * @brief An OKP cryptographic algorithm backed by a Hardware Security Module (HSM). + * + */ + AZ_SECURITY_KEYVAULT_KEYS_DLLEXPORT static const KeyVaultKeyType OkpHsm; }; /** @@ -297,6 +309,16 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Keys { * */ AZ_SECURITY_KEYVAULT_KEYS_DLLEXPORT static const KeyCurveName P521; + + /** + * @brief Gets the Ed25519 Edwards curve. + * + * @remark For more information, see + * Curve + * types. + * + */ + AZ_SECURITY_KEYVAULT_KEYS_DLLEXPORT static const KeyCurveName Ed25519; }; /** @@ -400,14 +422,14 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Keys { /// The RSA secret prime. std::vector Q; - /// The RSA private exponent or EC private key. + /// The RSA private exponent or EC private key, or OKP private key. std::vector D; /// Gets the symmetric key. std::vector K; /// Gets the protected key used with "Bring Your Own Key". std::vector T; - /// Gets the X coordinate of the elliptic curve point. + /// Gets the X coordinate of the elliptic curve point, or OKP public key. std::vector X; /// Gets the Y coordinate for the elliptic curve point. std::vector Y; diff --git a/sdk/keyvault/azure-security-keyvault-keys/inc/azure/keyvault/keys/key_client_options.hpp b/sdk/keyvault/azure-security-keyvault-keys/inc/azure/keyvault/keys/key_client_options.hpp index 8912beddc..85e4c9725 100644 --- a/sdk/keyvault/azure-security-keyvault-keys/inc/azure/keyvault/keys/key_client_options.hpp +++ b/sdk/keyvault/azure-security-keyvault-keys/inc/azure/keyvault/keys/key_client_options.hpp @@ -53,7 +53,7 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Keys { * @brief Service Version used. * */ - const std::string ApiVersion{"7.3"}; + const std::string ApiVersion{"7.4-preview.1"}; }; /** @@ -326,6 +326,80 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Keys { bool GetHardwareProtected() const { return m_hardwareProtected; } }; + /** + * @brief The properties needed to create an OKP key. + * + */ + class CreateOkpKeyOptions final : public CreateKeyOptions { + private: + std::string m_name; + bool m_hardwareProtected; + KeyVaultKeyType m_keyType; + + public: + /** + * @brief Gets or sets the key size in bits, such as 2048, 3072, or 4096. + * + * @remark If null, the service default is used. + * + */ + Azure::Nullable KeySize; + + /** + * @brief Gets or sets the elliptic curve name. + * + * @remark See #KeyCurveName for possible values. + * + * @remark If null, the service default is used. + * + */ + Azure::Nullable CurveName; + + /** + * @brief Create a OKP Key Options object. + * + * @param name Name of the key to create. + * @param hardwareProtected `true` to create hardware-protected key in a hardware security + * module (HSM). The default is false to create a software key. + */ + explicit CreateOkpKeyOptions(std::string const& name, bool hardwareProtected = false) + : m_hardwareProtected(hardwareProtected) + { + if (name.empty()) + { + throw std::invalid_argument("The name can't be empty"); + } + m_name = name; + if (hardwareProtected) + { + m_keyType = KeyVaultKeyType::OkpHsm; + } + else + { + m_keyType = KeyVaultKeyType::Okp; + } + } + + /** + * @brief Gets the name of the key to create. + * + */ + std::string const& GetName() const { return m_name; } + + /** + * @brief Gets the key type to create, including Okp and OkpHsm. + * + */ + KeyVaultKeyType GetKeyType() const { return m_keyType; } + + /** + * @brief Gets a value indicating whether to create a hardware-protected key in a hardware + * security module (HSM). + * + */ + bool GetHardwareProtected() const { return m_hardwareProtected; } + }; + /** * @brief A key resource and its properties. * diff --git a/sdk/keyvault/azure-security-keyvault-keys/src/key_client.cpp b/sdk/keyvault/azure-security-keyvault-keys/src/key_client.cpp index fda932f13..f32c87d36 100644 --- a/sdk/keyvault/azure-security-keyvault-keys/src/key_client.cpp +++ b/sdk/keyvault/azure-security-keyvault-keys/src/key_client.cpp @@ -167,6 +167,27 @@ Azure::Response KeyClient::CreateRsaKey( return Azure::Response(std::move(value), std::move(rawResponse)); } +Azure::Response KeyClient::CreateOkpKey( + CreateOkpKeyOptions const& okpKeyOptions, + Azure::Core::Context const& context) const +{ + // Payload for the request + std::string const& keyName = okpKeyOptions.GetName(); + std::string payload = _detail ::KeyRequestParameters(okpKeyOptions).Serialize(); + Azure::Core::IO::MemoryBodyStream payloadStream( + reinterpret_cast(payload.data()), payload.size()); + + // Request and settings + auto request + = CreateRequest(HttpMethod::Post, {_detail::KeysPath, keyName, CreateValue}, &payloadStream); + request.SetHeader(HttpShared::ContentType, HttpShared::ApplicationJson); + + // Send and parse respone + auto rawResponse = SendRequest(request, context); + auto value = _detail::KeyVaultKeySerializer::KeyVaultKeyDeserialize(keyName, *rawResponse); + return Azure::Response(std::move(value), std::move(rawResponse)); +} + Azure::Response KeyClient::CreateOctKey( CreateOctKeyOptions const& octKeyOptions, Azure::Core::Context const& context) const diff --git a/sdk/keyvault/azure-security-keyvault-keys/src/key_curve_name.cpp b/sdk/keyvault/azure-security-keyvault-keys/src/key_curve_name.cpp index 296c82c17..a2b419590 100644 --- a/sdk/keyvault/azure-security-keyvault-keys/src/key_curve_name.cpp +++ b/sdk/keyvault/azure-security-keyvault-keys/src/key_curve_name.cpp @@ -14,4 +14,6 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Keys { const KeyCurveName KeyCurveName::P521(_detail::P521Value); + const KeyCurveName KeyCurveName::Ed25519(_detail::Ed25519Value); + }}}} // namespace Azure::Security::KeyVault::Keys diff --git a/sdk/keyvault/azure-security-keyvault-keys/src/key_request_parameters.cpp b/sdk/keyvault/azure-security-keyvault-keys/src/key_request_parameters.cpp index df8f8d15e..e047cb0ed 100644 --- a/sdk/keyvault/azure-security-keyvault-keys/src/key_request_parameters.cpp +++ b/sdk/keyvault/azure-security-keyvault-keys/src/key_request_parameters.cpp @@ -24,15 +24,12 @@ std::string KeyRequestParameters::Serialize() const return type.ToString(); }); + json attributes; // attributes - JsonOptional::SetFromNullable( - m_options.Enabled, payload[_detail::AttributesPropertyName], _detail::EnabledPropertyName); + JsonOptional::SetFromNullable(m_options.Enabled, attributes, _detail::EnabledPropertyName); // exportable attribute - JsonOptional::SetFromNullable( - m_options.Exportable, - payload[_detail::AttributesPropertyName], - _detail::ExportablePropertyName); + JsonOptional::SetFromNullable(m_options.Exportable, attributes, _detail::ExportablePropertyName); /* Optional */ // key_size @@ -46,16 +43,23 @@ std::string KeyRequestParameters::Serialize() const // attributes JsonOptional::SetFromNullable( m_options.ExpiresOn, - payload[_detail::AttributesPropertyName], + attributes, _detail::ExpPropertyName, PosixTimeConverter::DateTimeToPosixTime); JsonOptional::SetFromNullable( m_options.NotBefore, - payload[_detail::AttributesPropertyName], + attributes, _detail::NbfPropertyName, PosixTimeConverter::DateTimeToPosixTime); + // in order to avoid creating the "attributes":null json field. + // The service deserializer on HSM really does not like that + if (!attributes.empty()) + { + payload[_detail::AttributesPropertyName] = attributes; + } + // tags for (auto tag : m_options.Tags) { diff --git a/sdk/keyvault/azure-security-keyvault-keys/src/key_type.cpp b/sdk/keyvault/azure-security-keyvault-keys/src/key_type.cpp index a847a5e4b..3a4331ead 100644 --- a/sdk/keyvault/azure-security-keyvault-keys/src/key_type.cpp +++ b/sdk/keyvault/azure-security-keyvault-keys/src/key_type.cpp @@ -14,3 +14,5 @@ const KeyVaultKeyType KeyVaultKeyType::Rsa(_detail::RsaValue); const KeyVaultKeyType KeyVaultKeyType::RsaHsm(_detail::RsaHsmValue); const KeyVaultKeyType KeyVaultKeyType::Oct(_detail::OctValue); const KeyVaultKeyType KeyVaultKeyType::OctHsm(_detail::OctHsmValue); +const KeyVaultKeyType KeyVaultKeyType::Okp(_detail::OkpValue); +const KeyVaultKeyType KeyVaultKeyType::OkpHsm(_detail::OkpHsmValue); diff --git a/sdk/keyvault/azure-security-keyvault-keys/src/keyvault_protocol.cpp b/sdk/keyvault/azure-security-keyvault-keys/src/keyvault_protocol.cpp index 9e0c4ca06..4fb1c673b 100644 --- a/sdk/keyvault/azure-security-keyvault-keys/src/keyvault_protocol.cpp +++ b/sdk/keyvault/azure-security-keyvault-keys/src/keyvault_protocol.cpp @@ -19,9 +19,9 @@ std::unique_ptr _detail::KeyVaultKeysCommonReque { auto response = pipeline.Send(request, context); auto responseCode = response->GetStatusCode(); + switch (responseCode) { - // 200, 2001, 202, 204 are accepted responses case Azure::Core::Http::HttpStatusCode::Ok: case Azure::Core::Http::HttpStatusCode::Created: diff --git a/sdk/keyvault/azure-security-keyvault-keys/src/private/key_constants.hpp b/sdk/keyvault/azure-security-keyvault-keys/src/private/key_constants.hpp index a40ecce22..53f942454 100644 --- a/sdk/keyvault/azure-security-keyvault-keys/src/private/key_constants.hpp +++ b/sdk/keyvault/azure-security-keyvault-keys/src/private/key_constants.hpp @@ -60,6 +60,8 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Keys { nam constexpr static const char RsaHsmValue[] = "RSA-HSM"; constexpr static const char OctValue[] = "oct"; constexpr static const char OctHsmValue[] = "oct-HSM"; + constexpr static const char OkpValue[] = "OKP"; + constexpr static const char OkpHsmValue[] = "OKP-HSM"; /***************** Deleted Key *****************/ constexpr static const char RecoveryIdPropertyName[] = "recoveryId"; @@ -71,6 +73,7 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Keys { nam constexpr static const char P256KValue[] = "P-256K"; constexpr static const char P384Value[] = "P-384"; constexpr static const char P521Value[] = "P-521"; + constexpr static const char Ed25519Value[] = "Ed25519"; constexpr static const char P256OidValue[] = "1.2.840.10045.3.1.7"; constexpr static const char P256KOidValue[] = "1.3.132.0.10"; diff --git a/sdk/keyvault/azure-security-keyvault-keys/src/private/key_request_parameters.hpp b/sdk/keyvault/azure-security-keyvault-keys/src/private/key_request_parameters.hpp index e23536243..da8c3e5e6 100644 --- a/sdk/keyvault/azure-security-keyvault-keys/src/private/key_request_parameters.hpp +++ b/sdk/keyvault/azure-security-keyvault-keys/src/private/key_request_parameters.hpp @@ -104,6 +104,15 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Keys { nam } } + explicit KeyRequestParameters(CreateOkpKeyOptions const& okpKey) + : KeyRequestParameters(okpKey.GetKeyType(), okpKey) + { + if (okpKey.CurveName.HasValue()) + { + Curve = okpKey.CurveName.Value(); + } + } + std::string Serialize() const override; }; }}}}} // namespace Azure::Security::KeyVault::Keys::_detail diff --git a/sdk/keyvault/azure-security-keyvault-keys/test/ut/key_client_create_test_live.cpp b/sdk/keyvault/azure-security-keyvault-keys/test/ut/key_client_create_test_live.cpp index 5cb035b1b..f67ad1f55 100644 --- a/sdk/keyvault/azure-security-keyvault-keys/test/ut/key_client_create_test_live.cpp +++ b/sdk/keyvault/azure-security-keyvault-keys/test/ut/key_client_create_test_live.cpp @@ -130,6 +130,54 @@ TEST_F(KeyVaultKeyClient, CreateEcKey) } } +/********************************* Create key overloads *********************************/ +TEST_F(KeyVaultKeyClient, CreateOkpKey) +{ + auto const keyName = GetTestName(); + // This client requires an HSM client + CreateHsmClient(); + auto const& client = GetClientForTest(keyName); + + { + auto okpKey = Azure::Security::KeyVault::Keys::CreateOkpKeyOptions(keyName); + auto keyResponse = client.CreateOkpKey(okpKey); + CheckValidResponse(keyResponse); + auto keyVaultKey = keyResponse.Value; + EXPECT_EQ(keyVaultKey.Name(), keyName); + } + { + // Now get the key + auto keyResponse = client.GetKey(keyName); + CheckValidResponse(keyResponse); + auto keyVaultKey = keyResponse.Value; + EXPECT_EQ(keyVaultKey.Name(), keyName); + } +} + +TEST_F(KeyVaultKeyClient, CreateOkpHSMKey) +{ + auto const keyName = GetTestName(); + // This client requires an HSM client + CreateHsmClient(); + auto const& client = GetClientForTest(keyName); + + { + auto okpKey = Azure::Security::KeyVault::Keys::CreateOkpKeyOptions(keyName, true); + auto keyResponse = client.CreateOkpKey(okpKey); + CheckValidResponse(keyResponse); + auto keyVaultKey = keyResponse.Value; + EXPECT_EQ(keyVaultKey.Name(), keyName); + EXPECT_EQ(keyVaultKey.GetKeyType(), KeyVaultKeyType::OkpHsm); + EXPECT_EQ(keyVaultKey.Key.CurveName.Value(), KeyCurveName::Ed25519); + } + { + // Now get the key + auto keyResponse = client.GetKey(keyName); + CheckValidResponse(keyResponse); + auto keyVaultKey = keyResponse.Value; + EXPECT_EQ(keyVaultKey.Name(), keyName); + } +} TEST_F(KeyVaultKeyClient, CreateEcKeyWithCurve) { auto const keyName = GetTestName(); diff --git a/sdk/keyvault/azure-security-keyvault-keys/test/ut/key_client_test.cpp b/sdk/keyvault/azure-security-keyvault-keys/test/ut/key_client_test.cpp index 5b924c9f9..b2920fc9b 100644 --- a/sdk/keyvault/azure-security-keyvault-keys/test/ut/key_client_test.cpp +++ b/sdk/keyvault/azure-security-keyvault-keys/test/ut/key_client_test.cpp @@ -35,7 +35,7 @@ TEST(KeyVaultKeyClientUnitTest, ServiceVersion) // 7.3 EXPECT_NO_THROW(auto options = KeyClientOptions(); KeyClient keyClient("http://account.vault.azure.net", credential, options); - EXPECT_EQ(options.ApiVersion, "7.3");); + EXPECT_EQ(options.ApiVersion, "7.4-preview.1");); } TEST(KeyVaultKeyClientUnitTest, GetUrl)