@@ -361,6 +361,41 @@ static int PasswordCallback(char *buf, int size, int rwflag, void *u) {
361
361
return 0 ;
362
362
}
363
363
364
+ // Loads OpenSSL engine by engine id and returns it. The loaded engine
365
+ // gets a reference so remember the corresponding call to ENGINE_free.
366
+ // In case of error the appropriate js exception is scheduled
367
+ // and nullptr is returned.
368
+ #ifndef OPENSSL_NO_ENGINE
369
+ static ENGINE* LoadEngineById (const char * engine_id, char (*errmsg)[1024]) {
370
+ MarkPopErrorOnReturn mark_pop_error_on_return;
371
+
372
+ ENGINE* engine = ENGINE_by_id (engine_id);
373
+
374
+ if (engine == nullptr ) {
375
+ // Engine not found, try loading dynamically.
376
+ engine = ENGINE_by_id (" dynamic" );
377
+ if (engine != nullptr ) {
378
+ if (!ENGINE_ctrl_cmd_string (engine, " SO_PATH" , engine_id, 0 ) ||
379
+ !ENGINE_ctrl_cmd_string (engine, " LOAD" , nullptr , 0 )) {
380
+ ENGINE_free (engine);
381
+ engine = nullptr ;
382
+ }
383
+ }
384
+ }
385
+
386
+ if (engine == nullptr ) {
387
+ int err = ERR_get_error ();
388
+ if (err != 0 ) {
389
+ ERR_error_string_n (err, *errmsg, sizeof (*errmsg));
390
+ } else {
391
+ snprintf (*errmsg, sizeof (*errmsg),
392
+ " Engine \" %s\" was not found" , engine_id);
393
+ }
394
+ }
395
+
396
+ return engine;
397
+ }
398
+ #endif // !OPENSSL_NO_ENGINE
364
399
365
400
// This callback is used to avoid the default passphrase callback in OpenSSL
366
401
// which will typically prompt for the passphrase. The prompting is designed
@@ -505,6 +540,10 @@ void SecureContext::Initialize(Environment* env, Local<Object> target) {
505
540
SecureContext::SetSessionTimeout);
506
541
env->SetProtoMethod (t, " close" , SecureContext::Close);
507
542
env->SetProtoMethod (t, " loadPKCS12" , SecureContext::LoadPKCS12);
543
+ #ifndef OPENSSL_NO_ENGINE
544
+ env->SetProtoMethod (t, " setClientCertEngine" ,
545
+ SecureContext::SetClientCertEngine);
546
+ #endif // !OPENSSL_NO_ENGINE
508
547
env->SetProtoMethod (t, " getTicketKeys" , SecureContext::GetTicketKeys);
509
548
env->SetProtoMethod (t, " setTicketKeys" , SecureContext::SetTicketKeys);
510
549
env->SetProtoMethod (t, " setFreeListLength" , SecureContext::SetFreeListLength);
@@ -1302,6 +1341,46 @@ void SecureContext::LoadPKCS12(const FunctionCallbackInfo<Value>& args) {
1302
1341
}
1303
1342
1304
1343
1344
+ #ifndef OPENSSL_NO_ENGINE
1345
+ void SecureContext::SetClientCertEngine (
1346
+ const FunctionCallbackInfo<Value>& args) {
1347
+ Environment* env = Environment::GetCurrent (args);
1348
+ CHECK_EQ (args.Length (), 1 );
1349
+ CHECK (args[0 ]->IsString ());
1350
+
1351
+ SecureContext* sc = Unwrap<SecureContext>(args.This ());
1352
+
1353
+ MarkPopErrorOnReturn mark_pop_error_on_return;
1354
+
1355
+ // SSL_CTX_set_client_cert_engine does not itself support multiple
1356
+ // calls by cleaning up before overwriting the client_cert_engine
1357
+ // internal context variable.
1358
+ // Instead of trying to fix up this problem we in turn also do not
1359
+ // support multiple calls to SetClientCertEngine.
1360
+ if (sc->client_cert_engine_provided_ ) {
1361
+ return env->ThrowError (
1362
+ " Multiple calls to SetClientCertEngine are not allowed" );
1363
+ }
1364
+
1365
+ const node::Utf8Value engine_id (env->isolate (), args[0 ]);
1366
+ char errmsg[1024 ];
1367
+ ENGINE* engine = LoadEngineById (*engine_id, &errmsg);
1368
+
1369
+ if (engine == nullptr ) {
1370
+ return env->ThrowError (errmsg);
1371
+ }
1372
+
1373
+ int r = SSL_CTX_set_client_cert_engine (sc->ctx_ , engine);
1374
+ // Free reference (SSL_CTX_set_client_cert_engine took it via ENGINE_init).
1375
+ ENGINE_free (engine);
1376
+ if (r == 0 ) {
1377
+ return ThrowCryptoError (env, ERR_get_error ());
1378
+ }
1379
+ sc->client_cert_engine_provided_ = true ;
1380
+ }
1381
+ #endif // !OPENSSL_NO_ENGINE
1382
+
1383
+
1305
1384
void SecureContext::GetTicketKeys (const FunctionCallbackInfo<Value>& args) {
1306
1385
#if !defined(OPENSSL_NO_TLSEXT) && defined(SSL_CTX_get_tlsext_ticket_keys)
1307
1386
@@ -6124,20 +6203,10 @@ void SetEngine(const FunctionCallbackInfo<Value>& args) {
6124
6203
6125
6204
ClearErrorOnReturn clear_error_on_return;
6126
6205
6206
+ // Load engine.
6127
6207
const node::Utf8Value engine_id (env->isolate (), args[0 ]);
6128
- ENGINE* engine = ENGINE_by_id (*engine_id);
6129
-
6130
- // Engine not found, try loading dynamically
6131
- if (engine == nullptr ) {
6132
- engine = ENGINE_by_id (" dynamic" );
6133
- if (engine != nullptr ) {
6134
- if (!ENGINE_ctrl_cmd_string (engine, " SO_PATH" , *engine_id, 0 ) ||
6135
- !ENGINE_ctrl_cmd_string (engine, " LOAD" , nullptr , 0 )) {
6136
- ENGINE_free (engine);
6137
- engine = nullptr ;
6138
- }
6139
- }
6140
- }
6208
+ char errmsg[1024 ];
6209
+ ENGINE* engine = LoadEngineById (*engine_id, &errmsg);
6141
6210
6142
6211
if (engine == nullptr ) {
6143
6212
int err = ERR_get_error ();
0 commit comments