Jwk deserialize (#2087)

* Remove to_json for jsonWebKey

* parse N

* Deserialize JWK for EC and OCT

* change log

* format

* fix live tests
This commit is contained in:
Victor Vazquez 2021-04-14 11:41:05 -07:00 committed by GitHub
parent c297b63b9b
commit 1ea5afa961
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 207 additions and 88 deletions

View File

@ -99,31 +99,44 @@ namespace Azure { namespace Core { namespace Json { namespace _internal {
destination = decorator(jsonKey[key].get<T>());
}
}
template <class T>
static inline void SetFromIfPredicate(
T const& source,
std::function<bool(T const&)> predicate,
Azure::Core::Json::_internal::json& jsonKey,
std::string const& keyName,
std::function<std::string(T const&)> decorator)
{
if (predicate(source))
{
jsonKey[keyName] = decorator(source);
}
}
template <class T, class R>
static inline void SetFromNullable(
Azure::Nullable<T> const& source,
Azure::Core::Json::_internal::json& jsonKey,
std::string const& keyName,
std::function<R(T const&)> factory)
{
if (source)
{
jsonKey[keyName] = factory(source.Value());
}
}
template <class T>
static inline void SetFromNullable(
Azure::Nullable<T> const& source,
Azure::Core::Json::_internal::json& jsonKey,
std::string const& keyName)
{
if (source)
{
jsonKey[keyName] = source.Value();
}
}
};
template <class T, class R>
static inline void SetFromNullable(
Azure::Nullable<T> const& source,
Azure::Core::Json::_internal::json& jsonKey,
std::string const& keyName,
std::function<R(T const&)> factory)
{
if (source)
{
jsonKey[keyName] = factory(source.Value());
}
}
template <class T>
static inline void SetFromNullable(
Azure::Nullable<T> const& source,
Azure::Core::Json::_internal::json& jsonKey,
std::string const& keyName)
{
if (source)
{
jsonKey[keyName] = source.Value();
}
}
}}}} // namespace Azure::Core::Json::_internal

View File

@ -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)

View File

@ -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

View File

@ -92,11 +92,17 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Keys {
/// The RSA private exponent or EC private key.
std::vector<uint8_t> D;
/// Gets the symmetric key.
std::vector<uint8_t> K;
/// Gets the protected key used with "Bring Your Own Key".
std::vector<uint8_t> T;
/// Gets the X coordinate of the elliptic curve point.
std::vector<uint8_t> X;
/// Gets the Y coordinate for the elliptic curve point.
std::vector<uint8_t> Y;
private:
std::vector<KeyOperation> 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

View File

@ -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<Azure::DateTime, uint64_t>(
JsonOptional::SetFromNullable<Azure::DateTime, uint64_t>(
importKeyOptions.Properties.CreatedOn,
payload[_detail::AttributesPropertyName],
_detail::CreatedPropertyName,
UnixTimeConverter::DatetimeToUnixTime);
SetFromNullable(
JsonOptional::SetFromNullable(
importKeyOptions.Properties.Enabled,
payload[_detail::AttributesPropertyName],
_detail::EnabledPropertyName);
SetFromNullable<Azure::DateTime, uint64_t>(
JsonOptional::SetFromNullable<Azure::DateTime, uint64_t>(
importKeyOptions.Properties.ExpiresOn,
payload[_detail::AttributesPropertyName],
_detail::ExpPropertyName,
UnixTimeConverter::DatetimeToUnixTime);
SetFromNullable<Azure::DateTime, uint64_t>(
JsonOptional::SetFromNullable<Azure::DateTime, uint64_t>(
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<Azure::DateTime, uint64_t>(
JsonOptional::SetFromNullable<Azure::DateTime, uint64_t>(
importKeyOptions.Properties.UpdatedOn,
payload[_detail::AttributesPropertyName],
_detail::UpdatedPropertyName,

View File

@ -1,28 +1,128 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
#include <azure/core/internal/json/json_optional.hpp>
#include <azure/keyvault/common/internal/base64url.hpp>
#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 <map>
#include <string>
#include <vector>
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<KeyOperation>& keyOperations,
std::vector<std::string> 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<uint8_t>& destBytes)
{
JsonOptional::SetIfExists<std::string, std::vector<uint8_t>>(
destBytes, jsonKey, keyName, [](std::string const& value) {
return Base64Url::Base64UrlDecode(value);
});
}
static inline void WriteJsonIfVectorHasData(
std::vector<uint8_t> const& srcVector,
Azure::Core::Json::_internal::json& jsonKey,
std::string const& keyName)
{
JsonOptional::SetFromIfPredicate<std::vector<uint8_t> const&>(
srcVector,
[](std::vector<uint8_t> 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<KeyCurveName, std::string>(
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<std::string>>();
std::vector<KeyOperation> keyOperations;
ParseStringOperationsToKeyOperations(keyOperations, keyOperationVector);
srcKey.SetKeyOperations(keyOperations);
}
srcKey.Id = jsonKey[_detail::KeyIdPropertyName].get<std::string>();
srcKey.KeyType
= KeyType::KeyTypeFromString(jsonKey[_detail::KeyTypePropertyName].get<std::string>());
JsonOptional::SetIfExists<std::string, KeyCurveName>(
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);
}
}

View File

@ -20,13 +20,13 @@ std::string KeyRequestParameters::Serialize() const
Azure::Core::Json::_internal::json payload;
// kty
SetFromNullable<JsonWebKeyType, std::string>(
JsonOptional::SetFromNullable<JsonWebKeyType, std::string>(
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<Azure::DateTime, uint64_t>(
JsonOptional::SetFromNullable<Azure::DateTime, uint64_t>(
m_options.ExpiresOn,
payload[_detail::AttributesPropertyName],
_detail::ExpPropertyName,
UnixTimeConverter::DatetimeToUnixTime);
SetFromNullable<Azure::DateTime, uint64_t>(
JsonOptional::SetFromNullable<Azure::DateTime, uint64_t>(
m_options.NotBefore,
payload[_detail::AttributesPropertyName],
_detail::NbfPropertyName,

View File

@ -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<KeyOperation>& keyOperations,
std::vector<std::string> 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<std::string>>();
std::vector<KeyOperation> keyOperations;
ParseStringOperationsToKeyOperations(keyOperations, keyOperationVector);
key.Key.SetKeyOperations(keyOperations);
}
key.Key.Id = jsonKey[_detail::KeyIdPropertyName].get<std::string>();
key.Key.KeyType
= KeyType::KeyTypeFromString(jsonKey[_detail::KeyTypePropertyName].get<std::string>());
JsonOptional::SetIfExists<std::string, KeyCurveName>(
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);

View File

@ -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)

View File

@ -8,6 +8,7 @@
#include "gtest/gtest.h"
#include <azure/keyvault/common/internal/base64url.hpp>
#include <azure/keyvault/common/keyvault_exception.hpp>
#include <azure/keyvault/key_vault.hpp>
#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