|
1 | 1 | #include "KeyObjectData.hpp" |
| 2 | +#include "Utils.hpp" |
| 3 | +#include <optional> |
2 | 4 |
|
3 | 5 | namespace margelo { |
4 | 6 |
|
| 7 | +using namespace margelo::nitro::crypto; |
| 8 | + |
| 9 | +ncrypto::EVPKeyPointer::PrivateKeyEncodingConfig GetPrivateKeyEncodingConfig( |
| 10 | + KFormatType format, |
| 11 | + KeyEncoding type) { |
| 12 | +auto pk_format = static_cast<ncrypto::EVPKeyPointer::PKFormatType>(format); |
| 13 | +auto pk_type = static_cast<ncrypto::EVPKeyPointer::PKEncodingType>(type); |
| 14 | + |
| 15 | +auto config = ncrypto::EVPKeyPointer::PrivateKeyEncodingConfig(false, pk_format, pk_type); |
| 16 | +return config; |
| 17 | +} |
| 18 | + |
| 19 | +KeyObjectData TryParsePrivateKey(std::shared_ptr<ArrayBuffer> key, std::optional<KFormatType> format, |
| 20 | + std::optional<KeyEncoding> type, |
| 21 | + const std::optional<std::shared_ptr<ArrayBuffer>>& passphrase) { |
| 22 | + auto config = GetPrivateKeyEncodingConfig(format.value(), type.value()); |
| 23 | + auto buffer = ncrypto::Buffer<const unsigned char>{key->data(), key->size()}; |
| 24 | + auto res = ncrypto::EVPKeyPointer::TryParsePrivateKey(config, buffer); |
| 25 | + if (res) { |
| 26 | + return KeyObjectData::CreateAsymmetric(KeyType::PRIVATE, |
| 27 | + std::move(res.value)); |
| 28 | + } |
| 29 | + |
| 30 | + if (res.error.value() == ncrypto::EVPKeyPointer::PKParseError::NEED_PASSPHRASE) { |
| 31 | + throw std::runtime_error("Passphrase required for encrypted key"); |
| 32 | + } else { |
| 33 | + throw std::runtime_error("Failed to read private key"); |
| 34 | + } |
| 35 | +} |
| 36 | + |
5 | 37 | KeyObjectData::KeyObjectData(std::nullptr_t) |
6 | 38 | : key_type_(KeyType::SECRET) {} |
7 | 39 |
|
@@ -55,41 +87,38 @@ KeyObjectData KeyObjectData::GetPublicOrPrivateKey(std::shared_ptr<ArrayBuffer> |
55 | 87 | if (format.has_value() && format.value() == KFormatType::PEM) { |
56 | 88 | // For PEM, we can easily determine whether it is a public or private key |
57 | 89 | // by looking for the respective PEM tags. |
58 | | - auto res = EVPKeyPointer::TryParsePublicKeyPEM(key); |
| 90 | + auto config = GetPrivateKeyEncodingConfig(format.value(), type.value()); |
| 91 | + auto buffer = ncrypto::Buffer<const unsigned char>{key->data(), key->size()}; |
| 92 | + auto res = ncrypto::EVPKeyPointer::TryParsePublicKeyPEM(buffer); |
59 | 93 | if (res) { |
60 | 94 | return CreateAsymmetric(KeyType::PUBLIC, std::move(res.value)); |
61 | 95 | } |
62 | 96 |
|
63 | | - if (res.error.value() == EVPKeyPointer::PKParseError::NOT_RECOGNIZED) { |
64 | | - return TryParsePrivateKey(key, format, type, passphrase); |
| 97 | + if (res.error.has_value() && res.error.value() == ncrypto::EVPKeyPointer::PKParseError::NOT_RECOGNIZED) { |
| 98 | + if (passphrase.has_value()) { |
| 99 | + auto& passphrase_ptr = passphrase.value(); |
| 100 | + config.passphrase = std::make_optional(ncrypto::DataPointer(passphrase_ptr->data(), passphrase_ptr->size())); |
| 101 | + } |
| 102 | + |
| 103 | + auto private_res = ncrypto::EVPKeyPointer::TryParsePrivateKey(config, buffer); |
| 104 | + if (private_res) { |
| 105 | + return CreateAsymmetric(KeyType::PRIVATE, std::move(private_res.value)); |
| 106 | + } |
| 107 | + // TODO: Handle private key parsing errors |
65 | 108 | } |
66 | 109 | throw std::runtime_error("Failed to read asymmetric key"); |
67 | 110 | } |
| 111 | + |
| 112 | + throw std::runtime_error("Unsupported key format for GetPublicOrPrivateKey. Only PEM is supported."); |
68 | 113 | } |
69 | 114 |
|
70 | 115 | KeyObjectData KeyObjectData::GetPrivateKey(std::shared_ptr<ArrayBuffer> key, std::optional<KFormatType> format, |
71 | 116 | std::optional<KeyEncoding> type, |
72 | 117 | const std::optional<std::shared_ptr<ArrayBuffer>>& passphrase, |
73 | 118 | bool isPublic) { |
74 | | - throw std::runtime_error("Not yet implemented"); |
75 | | -} |
76 | | - |
77 | | -KeyObjectData TryParsePrivateKey(std::shared_ptr<ArrayBuffer> key, std::optional<KFormatType> format, |
78 | | - std::optional<KeyEncoding> type, |
79 | | - const std::optional<std::shared_ptr<ArrayBuffer>>& passphrase) { |
80 | | - auto res = EVPKeyPointer::TryParsePrivateKey(config, buffer); |
81 | | - if (res) { |
82 | | - return KeyObjectData::CreateAsymmetric(KeyType::kKeyTypePrivate, |
83 | | - std::move(res.value)); |
84 | | - } |
85 | | - |
86 | | - if (res.error.value() == EVPKeyPointer::PKParseError::NEED_PASSPHRASE) { |
87 | | - THROW_ERR_MISSING_PASSPHRASE(env, "Passphrase required for encrypted key"); |
88 | | - } else { |
89 | | - ThrowCryptoError( |
90 | | - env, res.openssl_error.value_or(0), "Failed to read private key"); |
91 | | - } |
92 | | - return {}; |
| 119 | + // TODO: Node's KeyObjectData::GetPrivateKeyFromJs checks for key "IsString" or "IsAnyBufferSource" |
| 120 | + // We have converted key to an ArrayBuffer - not sure if that's correct |
| 121 | + return TryParsePrivateKey(key, format, type, passphrase); |
93 | 122 | } |
94 | 123 |
|
95 | 124 | } // namespace margelo |
0 commit comments