@@ -354,6 +354,41 @@ static int PasswordCallback(char *buf, int size, int rwflag, void *u) {
354
354
return 0 ;
355
355
}
356
356
357
+ // Loads OpenSSL engine by engine id and returns it. The loaded engine
358
+ // gets a reference so remember the corresponding call to ENGINE_free.
359
+ // In case of error the appropriate js exception is scheduled
360
+ // and nullptr is returned.
361
+ #ifndef OPENSSL_NO_ENGINE
362
+ static ENGINE* LoadEngineById (const char * engine_id, char (*errmsg)[1024]) {
363
+ MarkPopErrorOnReturn mark_pop_error_on_return;
364
+
365
+ ENGINE* engine = ENGINE_by_id (engine_id);
366
+
367
+ if (engine == nullptr ) {
368
+ // Engine not found, try loading dynamically.
369
+ engine = ENGINE_by_id (" dynamic" );
370
+ if (engine != nullptr ) {
371
+ if (!ENGINE_ctrl_cmd_string (engine, " SO_PATH" , engine_id, 0 ) ||
372
+ !ENGINE_ctrl_cmd_string (engine, " LOAD" , nullptr , 0 )) {
373
+ ENGINE_free (engine);
374
+ engine = nullptr ;
375
+ }
376
+ }
377
+ }
378
+
379
+ if (engine == nullptr ) {
380
+ int err = ERR_get_error ();
381
+ if (err != 0 ) {
382
+ ERR_error_string_n (err, *errmsg, sizeof (*errmsg));
383
+ } else {
384
+ snprintf (*errmsg, sizeof (*errmsg),
385
+ " Engine \" %s\" was not found" , engine_id);
386
+ }
387
+ }
388
+
389
+ return engine;
390
+ }
391
+ #endif // !OPENSSL_NO_ENGINE
357
392
358
393
// This callback is used to avoid the default passphrase callback in OpenSSL
359
394
// which will typically prompt for the passphrase. The prompting is designed
@@ -498,6 +533,10 @@ void SecureContext::Initialize(Environment* env, Local<Object> target) {
498
533
SecureContext::SetSessionTimeout);
499
534
env->SetProtoMethod (t, " close" , SecureContext::Close);
500
535
env->SetProtoMethod (t, " loadPKCS12" , SecureContext::LoadPKCS12);
536
+ #ifndef OPENSSL_NO_ENGINE
537
+ env->SetProtoMethod (t, " setClientCertEngine" ,
538
+ SecureContext::SetClientCertEngine);
539
+ #endif // !OPENSSL_NO_ENGINE
501
540
env->SetProtoMethod (t, " getTicketKeys" , SecureContext::GetTicketKeys);
502
541
env->SetProtoMethod (t, " setTicketKeys" , SecureContext::SetTicketKeys);
503
542
env->SetProtoMethod (t, " setFreeListLength" , SecureContext::SetFreeListLength);
@@ -1295,6 +1334,46 @@ void SecureContext::LoadPKCS12(const FunctionCallbackInfo<Value>& args) {
1295
1334
}
1296
1335
1297
1336
1337
+ #ifndef OPENSSL_NO_ENGINE
1338
+ void SecureContext::SetClientCertEngine (
1339
+ const FunctionCallbackInfo<Value>& args) {
1340
+ Environment* env = Environment::GetCurrent (args);
1341
+ CHECK_EQ (args.Length (), 1 );
1342
+ CHECK (args[0 ]->IsString ());
1343
+
1344
+ SecureContext* sc = Unwrap<SecureContext>(args.This ());
1345
+
1346
+ MarkPopErrorOnReturn mark_pop_error_on_return;
1347
+
1348
+ // SSL_CTX_set_client_cert_engine does not itself support multiple
1349
+ // calls by cleaning up before overwriting the client_cert_engine
1350
+ // internal context variable.
1351
+ // Instead of trying to fix up this problem we in turn also do not
1352
+ // support multiple calls to SetClientCertEngine.
1353
+ if (sc->client_cert_engine_provided_ ) {
1354
+ return env->ThrowError (
1355
+ " Multiple calls to SetClientCertEngine are not allowed" );
1356
+ }
1357
+
1358
+ const node::Utf8Value engine_id (env->isolate (), args[0 ]);
1359
+ char errmsg[1024 ];
1360
+ ENGINE* engine = LoadEngineById (*engine_id, &errmsg);
1361
+
1362
+ if (engine == nullptr ) {
1363
+ return env->ThrowError (errmsg);
1364
+ }
1365
+
1366
+ int r = SSL_CTX_set_client_cert_engine (sc->ctx_ , engine);
1367
+ // Free reference (SSL_CTX_set_client_cert_engine took it via ENGINE_init).
1368
+ ENGINE_free (engine);
1369
+ if (r == 0 ) {
1370
+ return ThrowCryptoError (env, ERR_get_error ());
1371
+ }
1372
+ sc->client_cert_engine_provided_ = true ;
1373
+ }
1374
+ #endif // !OPENSSL_NO_ENGINE
1375
+
1376
+
1298
1377
void SecureContext::GetTicketKeys (const FunctionCallbackInfo<Value>& args) {
1299
1378
#if !defined(OPENSSL_NO_TLSEXT) && defined(SSL_CTX_get_tlsext_ticket_keys)
1300
1379
@@ -6093,20 +6172,10 @@ void SetEngine(const FunctionCallbackInfo<Value>& args) {
6093
6172
6094
6173
ClearErrorOnReturn clear_error_on_return;
6095
6174
6175
+ // Load engine.
6096
6176
const node::Utf8Value engine_id (env->isolate (), args[0 ]);
6097
- ENGINE* engine = ENGINE_by_id (*engine_id);
6098
-
6099
- // Engine not found, try loading dynamically
6100
- if (engine == nullptr ) {
6101
- engine = ENGINE_by_id (" dynamic" );
6102
- if (engine != nullptr ) {
6103
- if (!ENGINE_ctrl_cmd_string (engine, " SO_PATH" , *engine_id, 0 ) ||
6104
- !ENGINE_ctrl_cmd_string (engine, " LOAD" , nullptr , 0 )) {
6105
- ENGINE_free (engine);
6106
- engine = nullptr ;
6107
- }
6108
- }
6109
- }
6177
+ char errmsg[1024 ];
6178
+ ENGINE* engine = LoadEngineById (*engine_id, &errmsg);
6110
6179
6111
6180
if (engine == nullptr ) {
6112
6181
int err = ERR_get_error ();
0 commit comments