1 |
|
|
#include "crypto/crypto_dsa.h" |
2 |
|
|
#include "crypto/crypto_keys.h" |
3 |
|
|
#include "crypto/crypto_util.h" |
4 |
|
|
#include "async_wrap-inl.h" |
5 |
|
|
#include "env-inl.h" |
6 |
|
|
#include "memory_tracker-inl.h" |
7 |
|
|
#include "threadpoolwork-inl.h" |
8 |
|
|
#include "v8.h" |
9 |
|
|
|
10 |
|
|
#include <openssl/bn.h> |
11 |
|
|
#include <openssl/dsa.h> |
12 |
|
|
|
13 |
|
|
#include <cstdio> |
14 |
|
|
|
15 |
|
|
namespace node { |
16 |
|
|
|
17 |
|
|
using v8::FunctionCallbackInfo; |
18 |
|
|
using v8::Int32; |
19 |
|
|
using v8::Just; |
20 |
|
|
using v8::Local; |
21 |
|
|
using v8::Maybe; |
22 |
|
|
using v8::Nothing; |
23 |
|
|
using v8::Number; |
24 |
|
|
using v8::Object; |
25 |
|
|
using v8::String; |
26 |
|
|
using v8::Uint32; |
27 |
|
|
using v8::Value; |
28 |
|
|
|
29 |
|
|
namespace crypto { |
30 |
|
2 |
EVPKeyCtxPointer DsaKeyGenTraits::Setup(DsaKeyPairGenConfig* params) { |
31 |
|
4 |
EVPKeyCtxPointer param_ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_DSA, nullptr)); |
32 |
|
2 |
EVP_PKEY* raw_params = nullptr; |
33 |
|
|
|
34 |
✓✗✗✓
|
6 |
if (!param_ctx || |
35 |
✓✗✗✓
|
4 |
EVP_PKEY_paramgen_init(param_ctx.get()) <= 0 || |
36 |
|
2 |
EVP_PKEY_CTX_set_dsa_paramgen_bits( |
37 |
|
|
param_ctx.get(), |
38 |
|
|
params->params.modulus_bits) <= 0) { |
39 |
|
|
return EVPKeyCtxPointer(); |
40 |
|
|
} |
41 |
|
|
|
42 |
✓✓ |
2 |
if (params->params.divisor_bits != -1) { |
43 |
✗✓ |
1 |
if (EVP_PKEY_CTX_ctrl( |
44 |
|
|
param_ctx.get(), |
45 |
|
|
EVP_PKEY_DSA, |
46 |
|
|
EVP_PKEY_OP_PARAMGEN, |
47 |
|
|
EVP_PKEY_CTRL_DSA_PARAMGEN_Q_BITS, |
48 |
|
|
params->params.divisor_bits, |
49 |
|
|
nullptr) <= 0) { |
50 |
|
|
return EVPKeyCtxPointer(); |
51 |
|
|
} |
52 |
|
|
} |
53 |
|
|
|
54 |
✗✓ |
2 |
if (EVP_PKEY_paramgen(param_ctx.get(), &raw_params) <= 0) |
55 |
|
|
return EVPKeyCtxPointer(); |
56 |
|
|
|
57 |
|
4 |
EVPKeyPointer key_params(raw_params); |
58 |
|
4 |
EVPKeyCtxPointer key_ctx(EVP_PKEY_CTX_new(key_params.get(), nullptr)); |
59 |
|
|
|
60 |
✓✗✗✓ ✗✓ |
2 |
if (!key_ctx || EVP_PKEY_keygen_init(key_ctx.get()) <= 0) |
61 |
|
|
return EVPKeyCtxPointer(); |
62 |
|
|
|
63 |
|
2 |
return key_ctx; |
64 |
|
|
} |
65 |
|
|
|
66 |
|
|
// Input arguments for DsaKeyPairGenJob |
67 |
|
|
// 1. CryptoJobMode |
68 |
|
|
// 2. Modulus Bits |
69 |
|
|
// 3. Divisor Bits |
70 |
|
|
// 4. Public Format |
71 |
|
|
// 5. Public Type |
72 |
|
|
// 6. Private Format |
73 |
|
|
// 7. Private Type |
74 |
|
|
// 8. Cipher |
75 |
|
|
// 9. Passphrase |
76 |
|
2 |
Maybe<bool> DsaKeyGenTraits::AdditionalConfig( |
77 |
|
|
CryptoJobMode mode, |
78 |
|
|
const FunctionCallbackInfo<Value>& args, |
79 |
|
|
unsigned int* offset, |
80 |
|
|
DsaKeyPairGenConfig* params) { |
81 |
|
2 |
Environment* env = Environment::GetCurrent(args); |
82 |
✗✓ |
6 |
CHECK(args[*offset]->IsUint32()); // modulus bits |
83 |
✗✓ |
6 |
CHECK(args[*offset + 1]->IsInt32()); // divisor bits |
84 |
|
|
|
85 |
|
8 |
params->params.modulus_bits = args[*offset].As<Uint32>()->Value(); |
86 |
|
8 |
params->params.divisor_bits = args[*offset + 1].As<Int32>()->Value(); |
87 |
✗✓ |
2 |
if (params->params.divisor_bits < -1) { |
88 |
|
|
char msg[1024]; |
89 |
|
|
snprintf(msg, sizeof(msg), "invalid value for divisor_bits"); |
90 |
|
|
THROW_ERR_OUT_OF_RANGE(env, msg); |
91 |
|
|
return Nothing<bool>(); |
92 |
|
|
} |
93 |
|
|
|
94 |
|
2 |
*offset += 2; |
95 |
|
|
|
96 |
|
2 |
return Just(true); |
97 |
|
|
} |
98 |
|
|
|
99 |
|
8 |
Maybe<bool> DSAKeyExportTraits::AdditionalConfig( |
100 |
|
|
const FunctionCallbackInfo<Value>& args, |
101 |
|
|
unsigned int offset, |
102 |
|
|
DSAKeyExportConfig* params) { |
103 |
|
8 |
return Just(true); |
104 |
|
|
} |
105 |
|
|
|
106 |
|
8 |
WebCryptoKeyExportStatus DSAKeyExportTraits::DoExport( |
107 |
|
|
std::shared_ptr<KeyObjectData> key_data, |
108 |
|
|
WebCryptoKeyFormat format, |
109 |
|
|
const DSAKeyExportConfig& params, |
110 |
|
|
ByteSource* out) { |
111 |
✗✓ |
8 |
CHECK_NE(key_data->GetKeyType(), kKeyTypeSecret); |
112 |
|
|
|
113 |
✗✓✓✗
|
8 |
switch (format) { |
114 |
|
|
case kWebCryptoKeyFormatRaw: |
115 |
|
|
// Not supported for RSA keys of either type |
116 |
|
|
return WebCryptoKeyExportStatus::FAILED; |
117 |
|
|
case kWebCryptoKeyFormatPKCS8: |
118 |
✗✓ |
4 |
if (key_data->GetKeyType() != kKeyTypePrivate) |
119 |
|
|
return WebCryptoKeyExportStatus::INVALID_KEY_TYPE; |
120 |
|
4 |
return PKEY_PKCS8_Export(key_data.get(), out); |
121 |
|
|
case kWebCryptoKeyFormatSPKI: |
122 |
✗✓ |
4 |
if (key_data->GetKeyType() != kKeyTypePublic) |
123 |
|
|
return WebCryptoKeyExportStatus::INVALID_KEY_TYPE; |
124 |
|
4 |
return PKEY_SPKI_Export(key_data.get(), out); |
125 |
|
|
default: |
126 |
|
|
UNREACHABLE(); |
127 |
|
|
} |
128 |
|
|
} |
129 |
|
|
|
130 |
|
8 |
Maybe<bool> ExportJWKDsaKey( |
131 |
|
|
Environment* env, |
132 |
|
|
std::shared_ptr<KeyObjectData> key, |
133 |
|
|
Local<Object> target) { |
134 |
|
16 |
ManagedEVPPKey pkey = key->GetAsymmetricKey(); |
135 |
✗✓ |
8 |
CHECK_EQ(EVP_PKEY_id(pkey.get()), EVP_PKEY_DSA); |
136 |
|
|
|
137 |
|
8 |
DSA* dsa = EVP_PKEY_get0_DSA(pkey.get()); |
138 |
✗✓ |
8 |
CHECK_NOT_NULL(dsa); |
139 |
|
|
|
140 |
|
|
const BIGNUM* y; |
141 |
|
|
const BIGNUM* x; |
142 |
|
|
const BIGNUM* p; |
143 |
|
|
const BIGNUM* q; |
144 |
|
|
const BIGNUM* g; |
145 |
|
|
|
146 |
|
8 |
DSA_get0_key(dsa, &y, &x); |
147 |
|
8 |
DSA_get0_pqg(dsa, &p, &q, &g); |
148 |
|
|
|
149 |
✗✓ |
24 |
if (target->Set( |
150 |
|
|
env->context(), |
151 |
|
|
env->jwk_kty_string(), |
152 |
|
40 |
env->jwk_dsa_string()).IsNothing()) { |
153 |
|
|
return Nothing<bool>(); |
154 |
|
|
} |
155 |
|
|
|
156 |
✓✗✗✓
|
40 |
if (SetEncodedValue(env, target, env->jwk_y_string(), y).IsNothing() || |
157 |
✓✗ |
32 |
SetEncodedValue(env, target, env->jwk_p_string(), p).IsNothing() || |
158 |
✓✗✗✓
|
40 |
SetEncodedValue(env, target, env->jwk_q_string(), q).IsNothing() || |
159 |
|
24 |
SetEncodedValue(env, target, env->jwk_g_string(), g).IsNothing()) { |
160 |
|
|
return Nothing<bool>(); |
161 |
|
|
} |
162 |
|
|
|
163 |
✓✓✗✓ ✗✓ |
20 |
if (key->GetKeyType() == kKeyTypePrivate && |
164 |
|
16 |
SetEncodedValue(env, target, env->jwk_x_string(), x).IsNothing()) { |
165 |
|
|
return Nothing<bool>(); |
166 |
|
|
} |
167 |
|
|
|
168 |
|
8 |
return Just(true); |
169 |
|
|
} |
170 |
|
|
|
171 |
|
16 |
std::shared_ptr<KeyObjectData> ImportJWKDsaKey( |
172 |
|
|
Environment* env, |
173 |
|
|
Local<Object> jwk, |
174 |
|
|
const FunctionCallbackInfo<Value>& args, |
175 |
|
|
unsigned int offset) { |
176 |
|
|
Local<Value> y_value; |
177 |
|
|
Local<Value> p_value; |
178 |
|
|
Local<Value> q_value; |
179 |
|
|
Local<Value> g_value; |
180 |
|
|
Local<Value> x_value; |
181 |
|
|
|
182 |
✓✗✗✓
|
112 |
if (!jwk->Get(env->context(), env->jwk_y_string()).ToLocal(&y_value) || |
183 |
✓✗ |
96 |
!jwk->Get(env->context(), env->jwk_p_string()).ToLocal(&p_value) || |
184 |
✓✗ |
96 |
!jwk->Get(env->context(), env->jwk_q_string()).ToLocal(&q_value) || |
185 |
✓✗✗✓
|
112 |
!jwk->Get(env->context(), env->jwk_g_string()).ToLocal(&g_value) || |
186 |
|
80 |
!jwk->Get(env->context(), env->jwk_x_string()).ToLocal(&x_value)) { |
187 |
|
|
return std::shared_ptr<KeyObjectData>(); |
188 |
|
|
} |
189 |
|
|
|
190 |
✓✗✗✓
|
64 |
if (!y_value->IsString() || |
191 |
✓✗ |
48 |
!p_value->IsString() || |
192 |
✓✗ |
48 |
!q_value->IsString() || |
193 |
✓✗✓✓
|
64 |
!q_value->IsString() || |
194 |
✗✓ |
48 |
(!x_value->IsUndefined() && !x_value->IsString())) { |
195 |
|
|
THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JSK DSA key"); |
196 |
|
|
return std::shared_ptr<KeyObjectData>(); |
197 |
|
|
} |
198 |
|
|
|
199 |
✓✓ |
32 |
KeyType type = x_value->IsString() ? kKeyTypePrivate : kKeyTypePublic; |
200 |
|
|
|
201 |
|
32 |
DsaPointer dsa(DSA_new()); |
202 |
|
|
|
203 |
|
32 |
ByteSource y = ByteSource::FromEncodedString(env, y_value.As<String>()); |
204 |
|
32 |
ByteSource p = ByteSource::FromEncodedString(env, p_value.As<String>()); |
205 |
|
32 |
ByteSource q = ByteSource::FromEncodedString(env, q_value.As<String>()); |
206 |
|
32 |
ByteSource g = ByteSource::FromEncodedString(env, g_value.As<String>()); |
207 |
|
|
|
208 |
✓✗✗✓ ✓✗✗✓
|
96 |
if (!DSA_set0_key(dsa.get(), y.ToBN().release(), nullptr) || |
209 |
|
48 |
!DSA_set0_pqg(dsa.get(), |
210 |
✓✗ |
32 |
p.ToBN().release(), |
211 |
✓✗ |
32 |
q.ToBN().release(), |
212 |
✓✗ |
32 |
g.ToBN().release())) { |
213 |
|
|
THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JSK DSA key"); |
214 |
|
|
return std::shared_ptr<KeyObjectData>(); |
215 |
|
|
} |
216 |
|
|
|
217 |
✓✓ |
16 |
if (type == kKeyTypePrivate) { |
218 |
|
16 |
ByteSource x = ByteSource::FromEncodedString(env, x_value.As<String>()); |
219 |
✗✓ |
8 |
if (!DSA_set0_key(dsa.get(), nullptr, x.ToBN().release())) { |
220 |
|
|
THROW_ERR_CRYPTO_INVALID_JWK(env, "Invalid JSK DSA key"); |
221 |
|
|
return std::shared_ptr<KeyObjectData>(); |
222 |
|
|
} |
223 |
|
|
} |
224 |
|
|
|
225 |
|
32 |
EVPKeyPointer pkey(EVP_PKEY_new()); |
226 |
✗✓ |
16 |
CHECK_EQ(EVP_PKEY_set1_DSA(pkey.get(), dsa.get()), 1); |
227 |
|
|
|
228 |
|
16 |
return KeyObjectData::CreateAsymmetric(type, ManagedEVPPKey(std::move(pkey))); |
229 |
|
|
} |
230 |
|
|
|
231 |
|
56 |
Maybe<bool> GetDsaKeyDetail( |
232 |
|
|
Environment* env, |
233 |
|
|
std::shared_ptr<KeyObjectData> key, |
234 |
|
|
Local<Object> target) { |
235 |
|
|
const BIGNUM* p; // Modulus length |
236 |
|
|
const BIGNUM* q; // Divisor length |
237 |
|
|
|
238 |
|
112 |
ManagedEVPPKey pkey = key->GetAsymmetricKey(); |
239 |
|
56 |
int type = EVP_PKEY_id(pkey.get()); |
240 |
✗✓ |
56 |
CHECK(type == EVP_PKEY_DSA); |
241 |
|
|
|
242 |
|
56 |
DSA* dsa = EVP_PKEY_get0_DSA(pkey.get()); |
243 |
✗✓ |
56 |
CHECK_NOT_NULL(dsa); |
244 |
|
|
|
245 |
|
56 |
DSA_get0_pqg(dsa, &p, &q, nullptr); |
246 |
|
|
|
247 |
|
56 |
size_t modulus_length = BN_num_bytes(p) * CHAR_BIT; |
248 |
|
56 |
size_t divisor_length = BN_num_bytes(q) * CHAR_BIT; |
249 |
|
|
|
250 |
✗✓ |
224 |
if (target->Set( |
251 |
|
|
env->context(), |
252 |
|
|
env->modulus_length_string(), |
253 |
✓✗✗✓
|
392 |
Number::New(env->isolate(), modulus_length)).IsNothing() || |
254 |
|
112 |
target->Set( |
255 |
|
|
env->context(), |
256 |
|
|
env->divisor_length_string(), |
257 |
|
336 |
Number::New(env->isolate(), divisor_length)).IsNothing()) { |
258 |
|
|
return Nothing<bool>(); |
259 |
|
|
} |
260 |
|
|
|
261 |
|
56 |
return Just(true); |
262 |
|
|
} |
263 |
|
|
|
264 |
|
|
namespace DSAAlg { |
265 |
|
654 |
void Initialize(Environment* env, Local<Object> target) { |
266 |
|
654 |
DsaKeyPairGenJob::Initialize(env, target); |
267 |
|
654 |
DSAKeyExportJob::Initialize(env, target); |
268 |
|
654 |
} |
269 |
|
|
} // namespace DSAAlg |
270 |
|
|
} // namespace crypto |
271 |
✓✗✓✗
|
14034 |
} // namespace node |
272 |
|
|
|