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 // EVP_PKEY_CTX_set_dsa_paramgen_q_bits was added in OpenSSL 1.1.1e.
16 #if OPENSSL_VERSION_NUMBER < 0x1010105fL
17 #define EVP_PKEY_CTX_set_dsa_paramgen_q_bits(ctx, qbits) \
18 EVP_PKEY_CTX_ctrl((ctx), \
19 EVP_PKEY_DSA, \
20 EVP_PKEY_OP_PARAMGEN, \
21 EVP_PKEY_CTRL_DSA_PARAMGEN_Q_BITS, \
22 (qbits), \
23 nullptr)
24 #endif
25
26 namespace node {
27
28 using v8::FunctionCallbackInfo;
29 using v8::Int32;
30 using v8::Just;
31 using v8::Local;
32 using v8::Maybe;
33 using v8::Nothing;
34 using v8::Number;
35 using v8::Object;
36 using v8::Uint32;
37 using v8::Value;
38
39 namespace crypto {
Setup(DsaKeyPairGenConfig * params)40 EVPKeyCtxPointer DsaKeyGenTraits::Setup(DsaKeyPairGenConfig* params) {
41 EVPKeyCtxPointer param_ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_DSA, nullptr));
42 EVP_PKEY* raw_params = nullptr;
43
44 if (!param_ctx ||
45 EVP_PKEY_paramgen_init(param_ctx.get()) <= 0 ||
46 EVP_PKEY_CTX_set_dsa_paramgen_bits(
47 param_ctx.get(),
48 params->params.modulus_bits) <= 0) {
49 return EVPKeyCtxPointer();
50 }
51
52 if (params->params.divisor_bits != -1) {
53 if (EVP_PKEY_CTX_set_dsa_paramgen_q_bits(
54 param_ctx.get(), params->params.divisor_bits) <= 0) {
55 return EVPKeyCtxPointer();
56 }
57 }
58
59 if (EVP_PKEY_paramgen(param_ctx.get(), &raw_params) <= 0)
60 return EVPKeyCtxPointer();
61
62 EVPKeyPointer key_params(raw_params);
63 EVPKeyCtxPointer key_ctx(EVP_PKEY_CTX_new(key_params.get(), nullptr));
64
65 if (!key_ctx || EVP_PKEY_keygen_init(key_ctx.get()) <= 0)
66 return EVPKeyCtxPointer();
67
68 return key_ctx;
69 }
70
71 // Input arguments for DsaKeyPairGenJob
72 // 1. CryptoJobMode
73 // 2. Modulus Bits
74 // 3. Divisor Bits
75 // 4. Public Format
76 // 5. Public Type
77 // 6. Private Format
78 // 7. Private Type
79 // 8. Cipher
80 // 9. Passphrase
AdditionalConfig(CryptoJobMode mode,const FunctionCallbackInfo<Value> & args,unsigned int * offset,DsaKeyPairGenConfig * params)81 Maybe<bool> DsaKeyGenTraits::AdditionalConfig(
82 CryptoJobMode mode,
83 const FunctionCallbackInfo<Value>& args,
84 unsigned int* offset,
85 DsaKeyPairGenConfig* params) {
86 CHECK(args[*offset]->IsUint32()); // modulus bits
87 CHECK(args[*offset + 1]->IsInt32()); // divisor bits
88
89 params->params.modulus_bits = args[*offset].As<Uint32>()->Value();
90 params->params.divisor_bits = args[*offset + 1].As<Int32>()->Value();
91 CHECK_GE(params->params.divisor_bits, -1);
92
93 *offset += 2;
94
95 return Just(true);
96 }
97
AdditionalConfig(const FunctionCallbackInfo<Value> & args,unsigned int offset,DSAKeyExportConfig * params)98 Maybe<bool> DSAKeyExportTraits::AdditionalConfig(
99 const FunctionCallbackInfo<Value>& args,
100 unsigned int offset,
101 DSAKeyExportConfig* params) {
102 return Just(true);
103 }
104
DoExport(std::shared_ptr<KeyObjectData> key_data,WebCryptoKeyFormat format,const DSAKeyExportConfig & params,ByteSource * out)105 WebCryptoKeyExportStatus DSAKeyExportTraits::DoExport(
106 std::shared_ptr<KeyObjectData> key_data,
107 WebCryptoKeyFormat format,
108 const DSAKeyExportConfig& params,
109 ByteSource* out) {
110 CHECK_NE(key_data->GetKeyType(), kKeyTypeSecret);
111
112 switch (format) {
113 case kWebCryptoKeyFormatRaw:
114 // Not supported for RSA keys of either type
115 return WebCryptoKeyExportStatus::FAILED;
116 case kWebCryptoKeyFormatPKCS8:
117 if (key_data->GetKeyType() != kKeyTypePrivate)
118 return WebCryptoKeyExportStatus::INVALID_KEY_TYPE;
119 return PKEY_PKCS8_Export(key_data.get(), out);
120 case kWebCryptoKeyFormatSPKI:
121 if (key_data->GetKeyType() != kKeyTypePublic)
122 return WebCryptoKeyExportStatus::INVALID_KEY_TYPE;
123 return PKEY_SPKI_Export(key_data.get(), out);
124 default:
125 UNREACHABLE();
126 }
127 }
128
GetDsaKeyDetail(Environment * env,std::shared_ptr<KeyObjectData> key,Local<Object> target)129 Maybe<bool> GetDsaKeyDetail(
130 Environment* env,
131 std::shared_ptr<KeyObjectData> key,
132 Local<Object> target) {
133 const BIGNUM* p; // Modulus length
134 const BIGNUM* q; // Divisor length
135
136 ManagedEVPPKey m_pkey = key->GetAsymmetricKey();
137 Mutex::ScopedLock lock(*m_pkey.mutex());
138 int type = EVP_PKEY_id(m_pkey.get());
139 CHECK(type == EVP_PKEY_DSA);
140
141 const DSA* dsa = EVP_PKEY_get0_DSA(m_pkey.get());
142 CHECK_NOT_NULL(dsa);
143
144 DSA_get0_pqg(dsa, &p, &q, nullptr);
145
146 size_t modulus_length = BN_num_bits(p);
147 size_t divisor_length = BN_num_bits(q);
148
149 if (target
150 ->Set(
151 env->context(),
152 env->modulus_length_string(),
153 Number::New(env->isolate(), static_cast<double>(modulus_length)))
154 .IsNothing() ||
155 target
156 ->Set(
157 env->context(),
158 env->divisor_length_string(),
159 Number::New(env->isolate(), static_cast<double>(divisor_length)))
160 .IsNothing()) {
161 return Nothing<bool>();
162 }
163
164 return Just(true);
165 }
166
167 namespace DSAAlg {
Initialize(Environment * env,Local<Object> target)168 void Initialize(Environment* env, Local<Object> target) {
169 DsaKeyPairGenJob::Initialize(env, target);
170 DSAKeyExportJob::Initialize(env, target);
171 }
172
RegisterExternalReferences(ExternalReferenceRegistry * registry)173 void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
174 DsaKeyPairGenJob::RegisterExternalReferences(registry);
175 DSAKeyExportJob::RegisterExternalReferences(registry);
176 }
177 } // namespace DSAAlg
178 } // namespace crypto
179 } // namespace node
180