diff --git a/sdk/core/azure-core/inc/azure/core/internal/json/json_optional.hpp b/sdk/core/azure-core/inc/azure/core/internal/json/json_optional.hpp index d1b44e413..dd847a573 100644 --- a/sdk/core/azure-core/inc/azure/core/internal/json/json_optional.hpp +++ b/sdk/core/azure-core/inc/azure/core/internal/json/json_optional.hpp @@ -99,31 +99,44 @@ namespace Azure { namespace Core { namespace Json { namespace _internal { destination = decorator(jsonKey[key].get()); } } + + template + static inline void SetFromIfPredicate( + T const& source, + std::function predicate, + Azure::Core::Json::_internal::json& jsonKey, + std::string const& keyName, + std::function decorator) + { + if (predicate(source)) + { + jsonKey[keyName] = decorator(source); + } + } + + template + static inline void SetFromNullable( + Azure::Nullable const& source, + Azure::Core::Json::_internal::json& jsonKey, + std::string const& keyName, + std::function factory) + { + if (source) + { + jsonKey[keyName] = factory(source.Value()); + } + } + + template + static inline void SetFromNullable( + Azure::Nullable const& source, + Azure::Core::Json::_internal::json& jsonKey, + std::string const& keyName) + { + if (source) + { + jsonKey[keyName] = source.Value(); + } + } }; - - template - static inline void SetFromNullable( - Azure::Nullable const& source, - Azure::Core::Json::_internal::json& jsonKey, - std::string const& keyName, - std::function factory) - { - if (source) - { - jsonKey[keyName] = factory(source.Value()); - } - } - - template - static inline void SetFromNullable( - Azure::Nullable const& source, - Azure::Core::Json::_internal::json& jsonKey, - std::string const& keyName) - { - if (source) - { - jsonKey[keyName] = source.Value(); - } - } - }}}} // namespace Azure::Core::Json::_internal diff --git a/sdk/keyvault/azure-security-keyvault-keys/CHANGELOG.md b/sdk/keyvault/azure-security-keyvault-keys/CHANGELOG.md index 75f5809fe..be452c3cb 100644 --- a/sdk/keyvault/azure-security-keyvault-keys/CHANGELOG.md +++ b/sdk/keyvault/azure-security-keyvault-keys/CHANGELOG.md @@ -2,6 +2,13 @@ ## 4.0.0-beta.2 (Unreleased) +### New Features + +- Added support for importing and deserializing EC and OCT keys. + +### Breaking Changes + +- Removed `Azure::Security::KeyVault::Keys::JsonWebKey::to_json`. ## 4.0.0-beta.1 (2021-04-07) diff --git a/sdk/keyvault/azure-security-keyvault-keys/inc/azure/keyvault/keys/details/key_serializers.hpp b/sdk/keyvault/azure-security-keyvault-keys/inc/azure/keyvault/keys/details/key_serializers.hpp index 02e17e562..057e5851c 100644 --- a/sdk/keyvault/azure-security-keyvault-keys/inc/azure/keyvault/keys/details/key_serializers.hpp +++ b/sdk/keyvault/azure-security-keyvault-keys/inc/azure/keyvault/keys/details/key_serializers.hpp @@ -105,4 +105,16 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Keys { nam Azure::Core::Http::RawResponse const& rawResponse); }; + /**************** JWK ************/ + struct JsonWebKeySerializer + { + static void JsonWebKeySerialize( + JsonWebKey const& jwk, + Azure::Core::Json::_internal::json& destJson); + + static void JsonWebDeserialize( + JsonWebKey& srcKey, + Azure::Core::Json::_internal::json const& jsonParser); + }; + }}}}} // namespace Azure::Security::KeyVault::Keys::_detail diff --git a/sdk/keyvault/azure-security-keyvault-keys/inc/azure/keyvault/keys/json_web_key.hpp b/sdk/keyvault/azure-security-keyvault-keys/inc/azure/keyvault/keys/json_web_key.hpp index 25a217fec..2a4ab6d6f 100644 --- a/sdk/keyvault/azure-security-keyvault-keys/inc/azure/keyvault/keys/json_web_key.hpp +++ b/sdk/keyvault/azure-security-keyvault-keys/inc/azure/keyvault/keys/json_web_key.hpp @@ -92,11 +92,17 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Keys { /// The RSA private exponent or EC 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. + std::vector X; + /// Gets the Y coordinate for the elliptic curve point. + std::vector Y; + private: std::vector m_keyOps; }; - // Define the serialization of a JsonWebKey - void to_json(Azure::Core::Json::_internal::json& j, JsonWebKey const& p); - }}}} // namespace Azure::Security::KeyVault::Keys diff --git a/sdk/keyvault/azure-security-keyvault-keys/src/import_key_options.cpp b/sdk/keyvault/azure-security-keyvault-keys/src/import_key_options.cpp index 6cba2bfb6..d1ca14086 100644 --- a/sdk/keyvault/azure-security-keyvault-keys/src/import_key_options.cpp +++ b/sdk/keyvault/azure-security-keyvault-keys/src/import_key_options.cpp @@ -24,39 +24,41 @@ Azure::Security::KeyVault::Keys::_detail::ImportKeyOptionsSerializer::ImportKeyO Azure::Core::Json::_internal::json payload; // key - payload[_detail::KeyPropertyName] = importKeyOptions.Key; + JsonWebKeySerializer::JsonWebKeySerialize( + importKeyOptions.Key, payload[_detail::KeyPropertyName]); // hsm - SetFromNullable(importKeyOptions.HardwareProtected, payload, _detail::HsmPropertyName); + JsonOptional::SetFromNullable( + importKeyOptions.HardwareProtected, payload, _detail::HsmPropertyName); // attributes - SetFromNullable( + JsonOptional::SetFromNullable( importKeyOptions.Properties.CreatedOn, payload[_detail::AttributesPropertyName], _detail::CreatedPropertyName, UnixTimeConverter::DatetimeToUnixTime); - SetFromNullable( + JsonOptional::SetFromNullable( importKeyOptions.Properties.Enabled, payload[_detail::AttributesPropertyName], _detail::EnabledPropertyName); - SetFromNullable( + JsonOptional::SetFromNullable( importKeyOptions.Properties.ExpiresOn, payload[_detail::AttributesPropertyName], _detail::ExpPropertyName, UnixTimeConverter::DatetimeToUnixTime); - SetFromNullable( + JsonOptional::SetFromNullable( importKeyOptions.Properties.NotBefore, payload[_detail::AttributesPropertyName], _detail::NbfPropertyName, UnixTimeConverter::DatetimeToUnixTime); - SetFromNullable( + JsonOptional::SetFromNullable( importKeyOptions.Properties.RecoverableDays, payload[_detail::AttributesPropertyName], _detail::RecoverableDaysPropertyName); payload[_detail::RecoveryLevelPropertyName] = importKeyOptions.Properties.RecoveryLevel; - SetFromNullable( + JsonOptional::SetFromNullable( importKeyOptions.Properties.UpdatedOn, payload[_detail::AttributesPropertyName], _detail::UpdatedPropertyName, diff --git a/sdk/keyvault/azure-security-keyvault-keys/src/json_web_key.cpp b/sdk/keyvault/azure-security-keyvault-keys/src/json_web_key.cpp index 5b744f28c..91fa2df40 100644 --- a/sdk/keyvault/azure-security-keyvault-keys/src/json_web_key.cpp +++ b/sdk/keyvault/azure-security-keyvault-keys/src/json_web_key.cpp @@ -1,28 +1,128 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // SPDX-License-Identifier: MIT +#include #include #include "azure/keyvault/keys/details/key_constants.hpp" +#include "azure/keyvault/keys/details/key_serializers.hpp" #include "azure/keyvault/keys/json_web_key.hpp" +#include "azure/keyvault/keys/key_curve_name.hpp" +#include #include +#include using namespace Azure::Security::KeyVault::Keys; using namespace Azure::Core::Json::_internal; using namespace Azure::Security::KeyVault::_internal; -void Azure::Security::KeyVault::Keys::to_json( - Azure::Core::Json::_internal::json& j, - JsonWebKey const& p) +namespace { +void ParseStringOperationsToKeyOperations( + std::vector& keyOperations, + std::vector const& stringOperations) { - j[_detail::KeyTypePropertyName] = KeyType::KeyTypeToString(p.KeyType); - j[_detail::NPropertyName] = Base64Url::Base64UrlEncode(p.N); - j[_detail::EPropertyName] = Base64Url::Base64UrlEncode(p.E); - j[_detail::DPropertyName] = Base64Url::Base64UrlEncode(p.D); - j[_detail::DPPropertyName] = Base64Url::Base64UrlEncode(p.DP); - j[_detail::DQPropertyName] = Base64Url::Base64UrlEncode(p.DQ); - j[_detail::QIPropertyName] = Base64Url::Base64UrlEncode(p.QI); - j[_detail::PPropertyName] = Base64Url::Base64UrlEncode(p.P); - j[_detail::QPropertyName] = Base64Url::Base64UrlEncode(p.Q); + for (std::string const& operation : stringOperations) + { + keyOperations.emplace_back(KeyOperation(operation)); + } +} + +static inline void AssignBytesIfExists( + Azure::Core::Json::_internal::json const& jsonKey, + std::string const& keyName, + std::vector& destBytes) +{ + JsonOptional::SetIfExists>( + destBytes, jsonKey, keyName, [](std::string const& value) { + return Base64Url::Base64UrlDecode(value); + }); +} + +static inline void WriteJsonIfVectorHasData( + std::vector const& srcVector, + Azure::Core::Json::_internal::json& jsonKey, + std::string const& keyName) +{ + JsonOptional::SetFromIfPredicate const&>( + srcVector, + [](std::vector const& value) { return value.size() > 0; }, + jsonKey, + keyName, + Base64Url::Base64UrlEncode); +} +} // namespace + +void Azure::Security::KeyVault::Keys::_detail::JsonWebKeySerializer::JsonWebKeySerialize( + JsonWebKey const& jwk, + Azure::Core::Json::_internal::json& destJson) +{ + // kty + destJson[_detail::KeyTypePropertyName] = KeyType::KeyTypeToString(jwk.KeyType); + + // ops + for (KeyOperation op : jwk.KeyOperations()) + { + destJson[_detail::KeyOpsPropertyName].push_back(op.ToString()); + } + + // curve name + JsonOptional::SetFromNullable( + jwk.CurveName, destJson, _detail::CurveNamePropertyName, [](KeyCurveName const& value) { + return value.ToString(); + }); + + // fields + WriteJsonIfVectorHasData(jwk.N, destJson, _detail::NPropertyName); + WriteJsonIfVectorHasData(jwk.E, destJson, _detail::EPropertyName); + WriteJsonIfVectorHasData(jwk.D, destJson, _detail::DPropertyName); + WriteJsonIfVectorHasData(jwk.DP, destJson, _detail::DPPropertyName); + WriteJsonIfVectorHasData(jwk.DQ, destJson, _detail::DQPropertyName); + WriteJsonIfVectorHasData(jwk.QI, destJson, _detail::QIPropertyName); + WriteJsonIfVectorHasData(jwk.P, destJson, _detail::PPropertyName); + WriteJsonIfVectorHasData(jwk.Q, destJson, _detail::QPropertyName); + WriteJsonIfVectorHasData(jwk.X, destJson, _detail::XPropertyName); + WriteJsonIfVectorHasData(jwk.Y, destJson, _detail::YPropertyName); + WriteJsonIfVectorHasData(jwk.K, destJson, _detail::KPropertyName); + WriteJsonIfVectorHasData(jwk.T, destJson, _detail::TPropertyName); +} + +void Azure::Security::KeyVault::Keys::_detail::JsonWebKeySerializer::JsonWebDeserialize( + JsonWebKey& srcKey, + Azure::Core::Json::_internal::json const& jsonParser) +{ + // "Key" + if (jsonParser.contains(_detail::KeyPropertyName)) + { + auto const& jsonKey = jsonParser[_detail ::KeyPropertyName]; + { + // key_ops + auto keyOperationVector + = jsonKey[_detail::KeyOpsPropertyName].get>(); + std::vector keyOperations; + ParseStringOperationsToKeyOperations(keyOperations, keyOperationVector); + srcKey.SetKeyOperations(keyOperations); + } + srcKey.Id = jsonKey[_detail::KeyIdPropertyName].get(); + srcKey.KeyType + = KeyType::KeyTypeFromString(jsonKey[_detail::KeyTypePropertyName].get()); + + JsonOptional::SetIfExists( + srcKey.CurveName, jsonKey, _detail::CurveNamePropertyName, [](std::string const& keyName) { + return KeyCurveName(keyName); + }); + + AssignBytesIfExists(jsonKey, _detail::NPropertyName, srcKey.N); + AssignBytesIfExists(jsonKey, _detail::EPropertyName, srcKey.E); + AssignBytesIfExists(jsonKey, _detail::DPPropertyName, srcKey.DP); + AssignBytesIfExists(jsonKey, _detail::DQPropertyName, srcKey.DQ); + AssignBytesIfExists(jsonKey, _detail::QIPropertyName, srcKey.QI); + AssignBytesIfExists(jsonKey, _detail::PPropertyName, srcKey.P); + AssignBytesIfExists(jsonKey, _detail::QPropertyName, srcKey.Q); + AssignBytesIfExists(jsonKey, _detail::DPropertyName, srcKey.D); + AssignBytesIfExists(jsonKey, _detail::KPropertyName, srcKey.K); + AssignBytesIfExists(jsonKey, _detail::TPropertyName, srcKey.T); + AssignBytesIfExists(jsonKey, _detail::XPropertyName, srcKey.X); + AssignBytesIfExists(jsonKey, _detail::YPropertyName, srcKey.Y); + } } 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 a5f466ec0..56d9f0d4b 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 @@ -20,13 +20,13 @@ std::string KeyRequestParameters::Serialize() const Azure::Core::Json::_internal::json payload; // kty - SetFromNullable( + JsonOptional::SetFromNullable( m_keyType, payload, _detail::KeyTypePropertyName, [](JsonWebKeyType type) { return KeyType::KeyTypeToString(type); }); // attributes - SetFromNullable( + JsonOptional::SetFromNullable( m_options.Enabled, payload[_detail::AttributesPropertyName], _detail::EnabledPropertyName); /* Optional */ @@ -39,13 +39,13 @@ std::string KeyRequestParameters::Serialize() const } // attributes - SetFromNullable( + JsonOptional::SetFromNullable( m_options.ExpiresOn, payload[_detail::AttributesPropertyName], _detail::ExpPropertyName, UnixTimeConverter::DatetimeToUnixTime); - SetFromNullable( + JsonOptional::SetFromNullable( m_options.NotBefore, payload[_detail::AttributesPropertyName], _detail::NbfPropertyName, diff --git a/sdk/keyvault/azure-security-keyvault-keys/src/key_vault_key.cpp b/sdk/keyvault/azure-security-keyvault-keys/src/key_vault_key.cpp index ab0a300f8..76bbed219 100644 --- a/sdk/keyvault/azure-security-keyvault-keys/src/key_vault_key.cpp +++ b/sdk/keyvault/azure-security-keyvault-keys/src/key_vault_key.cpp @@ -10,25 +10,12 @@ #include "azure/keyvault/keys/details/key_constants.hpp" #include "azure/keyvault/keys/details/key_serializers.hpp" -#include "azure/keyvault/keys/key_curve_name.hpp" #include "azure/keyvault/keys/key_vault_key.hpp" using namespace Azure::Security::KeyVault::Keys; using namespace Azure::Core::Json::_internal; using Azure::Security::KeyVault::_internal::UnixTimeConverter; -namespace { -void ParseStringOperationsToKeyOperations( - std::vector& keyOperations, - std::vector const& stringOperations) -{ - for (std::string const& operation : stringOperations) - { - keyOperations.emplace_back(KeyOperation(operation)); - } -} -} // namespace - KeyVaultKey _detail::KeyVaultKeySerializer::KeyVaultKeyDeserialize( std::string const& name, Azure::Core::Http::RawResponse const& rawResponse) @@ -59,27 +46,8 @@ void _detail::KeyVaultKeySerializer::KeyVaultKeyDeserialize( KeyVaultKey& key, Azure::Core::Json::_internal::json const& jsonParser) { - // "Key" - if (jsonParser.contains(_detail::KeyPropertyName)) - { - auto const& jsonKey = jsonParser[_detail::KeyPropertyName]; - { - // key_ops - auto keyOperationVector - = jsonKey[_detail::KeyOpsPropertyName].get>(); - std::vector keyOperations; - ParseStringOperationsToKeyOperations(keyOperations, keyOperationVector); - key.Key.SetKeyOperations(keyOperations); - } - key.Key.Id = jsonKey[_detail::KeyIdPropertyName].get(); - key.Key.KeyType - = KeyType::KeyTypeFromString(jsonKey[_detail::KeyTypePropertyName].get()); - - JsonOptional::SetIfExists( - key.Key.CurveName, jsonKey, _detail::CurveNamePropertyName, [](std::string const& keyName) { - return KeyCurveName(keyName); - }); - } + // Deserialize jwk + _detail::JsonWebKeySerializer::JsonWebDeserialize(key.Key, jsonParser); // Parse URL for the vaultUri, keyVersion _detail::KeyVaultKeySerializer::ParseKeyUrl(key.Properties, key.Key.Id); diff --git a/sdk/keyvault/azure-security-keyvault-keys/test/ut/CMakeLists.txt b/sdk/keyvault/azure-security-keyvault-keys/test/ut/CMakeLists.txt index c4e9c2728..3c1424765 100644 --- a/sdk/keyvault/azure-security-keyvault-keys/test/ut/CMakeLists.txt +++ b/sdk/keyvault/azure-security-keyvault-keys/test/ut/CMakeLists.txt @@ -48,7 +48,8 @@ add_executable ( ) if (MSVC) - target_compile_options(azure-security-keyvault-keys-test-live PUBLIC /wd6326 /wd26495 /wd26812) + # warning C4389: '==': signed/unsigned mismatch + target_compile_options(azure-security-keyvault-keys-test-live PUBLIC /wd6326 /wd26495 /wd26812 /wd4389) endif() target_link_libraries(azure-security-keyvault-keys-test-live PRIVATE azure-security-keyvault-keys azure-identity gtest gmock) diff --git a/sdk/keyvault/azure-security-keyvault-keys/test/ut/key_client_import_test_live.cpp b/sdk/keyvault/azure-security-keyvault-keys/test/ut/key_client_import_test_live.cpp index b1886b733..8dd2d43f2 100644 --- a/sdk/keyvault/azure-security-keyvault-keys/test/ut/key_client_import_test_live.cpp +++ b/sdk/keyvault/azure-security-keyvault-keys/test/ut/key_client_import_test_live.cpp @@ -8,6 +8,7 @@ #include "gtest/gtest.h" #include +#include #include #include "key_client_base_test.hpp" @@ -55,8 +56,17 @@ TEST_F(KeyVaultClientTest, ImportKey) "Uyf9s52ywLylhcVE3jfbjOgEozlSwKyhqfXkLpMLWHqOKj9fcfYd4PWKPOgpzWsqjA6fJbBUM" "Yo0CU2G9cWCtVodO7sBJVSIZunWrAlBc"); std::string keyName(GetUniqueName()); + key.CurveName = KeyCurveName::P521(); + key.SetKeyOperations({KeyOperation::Sign()}); + auto response = keyClient.ImportKey(keyName, key); CheckValidResponse(response); + auto const& returnedkey = response.Value; + EXPECT_EQ(key.N, returnedkey.Key.N); + EXPECT_EQ(key.E, returnedkey.Key.E); + EXPECT_EQ(key.CurveName.Value().ToString(), returnedkey.Key.CurveName.Value().ToString()); + EXPECT_EQ(returnedkey.KeyOperations().size(), 1); + EXPECT_EQ(returnedkey.KeyOperations()[0].ToString(), KeyOperation::Sign().ToString()); { // delete + purge