|
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