56
56
#include <openssl/ssl.h>
57
57
#include <openssl/pkcs12.h>
58
58
#include <openssl/cms.h>
59
+ #include <openssl/engine.h>
59
60
60
61
/* Common */
61
62
#include <time.h>
@@ -515,7 +516,6 @@ struct php_x509_request { /* {{{ */
515
516
static X509 * php_openssl_x509_from_param (zend_object * cert_obj , zend_string * cert_str );
516
517
static X509 * php_openssl_x509_from_zval (zval * val , bool * free_cert );
517
518
static X509_REQ * php_openssl_csr_from_param (zend_object * csr_obj , zend_string * csr_str );
518
- static EVP_PKEY * php_openssl_pkey_from_zval (zval * val , int public_key , char * passphrase , size_t passphrase_len );
519
519
520
520
static int php_openssl_is_private_key (EVP_PKEY * pkey );
521
521
static X509_STORE * php_openssl_setup_verify (zval * calist );
@@ -933,6 +933,46 @@ static void php_openssl_dispose_config(struct php_x509_request * req) /* {{{ */
933
933
}
934
934
/* }}} */
935
935
936
+ static ENGINE * php_openssl_make_pkcs11_engine (const bool warn ) /* {{{ */
937
+ {
938
+ char * verbose = NULL ;
939
+ ENGINE * engine ;
940
+
941
+ engine = ENGINE_by_id ("pkcs11" );
942
+ if (engine == NULL ) {
943
+ if (warn ) {
944
+ php_error_docref (NULL , E_WARNING , "Cannot load PKCS11 engine" );
945
+ }
946
+ php_openssl_store_errors ();
947
+ return NULL ;
948
+ }
949
+ verbose = getenv ("OPENSSL_ENGINE_VERBOSE" );
950
+ if (verbose ) {
951
+ if (!ENGINE_ctrl_cmd_string (engine , "VERBOSE" , NULL , 0 )) {
952
+ ENGINE_free (engine );
953
+ php_openssl_store_errors ();
954
+ return NULL ;
955
+ }
956
+ } else {
957
+ if (!ENGINE_ctrl_cmd_string (engine , "QUIET" , NULL , 0 )) {
958
+ ENGINE_free (engine );
959
+ php_openssl_store_errors ();
960
+ return NULL ;
961
+ }
962
+ }
963
+ if (!ENGINE_init (engine )) {
964
+ if (warn ) {
965
+ php_error_docref (NULL , E_WARNING , "Cannot init PKCS11 engine" );
966
+ }
967
+ php_openssl_store_errors ();
968
+ return NULL ;
969
+ }
970
+ ENGINE_free (engine );
971
+
972
+ return engine ;
973
+ }
974
+ /* }}} */
975
+
936
976
#if defined(PHP_WIN32 ) || PHP_OPENSSL_API_VERSION >= 0x10100
937
977
#define PHP_OPENSSL_RAND_ADD_TIME () ((void) 0)
938
978
#else
@@ -1384,9 +1424,9 @@ PHP_FUNCTION(openssl_get_cert_locations)
1384
1424
}
1385
1425
/* }}} */
1386
1426
1387
- static X509 * php_openssl_x509_from_str (zend_string * cert_str ) {
1427
+ X509 * php_openssl_x509_from_str (zend_string * cert_str ) {
1388
1428
X509 * cert = NULL ;
1389
- BIO * in ;
1429
+ BIO * in = NULL ;
1390
1430
1391
1431
if (ZSTR_LEN (cert_str ) > 7 && memcmp (ZSTR_VAL (cert_str ), "file://" , sizeof ("file://" ) - 1 ) == 0 ) {
1392
1432
if (php_openssl_open_base_dir_chk (ZSTR_VAL (cert_str ) + (sizeof ("file://" ) - 1 ))) {
@@ -1399,6 +1439,32 @@ static X509 *php_openssl_x509_from_str(zend_string *cert_str) {
1399
1439
return NULL ;
1400
1440
}
1401
1441
cert = PEM_read_bio_X509 (in , NULL , NULL , NULL );
1442
+ } else if (ZSTR_LEN (cert_str ) > 7 && memcmp (ZSTR_VAL (cert_str ), "pkcs11:" , sizeof ("pkcs11:" ) - 1 ) == 0 ) {
1443
+ ENGINE * engine = php_openssl_make_pkcs11_engine (true);
1444
+ struct {
1445
+ const char * s_slot_cert_id ;
1446
+ X509 * cert ;
1447
+ } parms = {
1448
+ .s_slot_cert_id = ZSTR_VAL (cert_str ),
1449
+ .cert = NULL ,
1450
+ };
1451
+ int force_login = 0 ;
1452
+
1453
+ if (!engine ) {
1454
+ return NULL ;
1455
+ }
1456
+
1457
+ if (!ENGINE_ctrl_cmd (engine , "LOAD_CERT_CTRL" , 0 , & parms , NULL , force_login )) {
1458
+ ENGINE_finish (engine );
1459
+ php_openssl_store_errors ();
1460
+ return NULL ;
1461
+ }
1462
+ ENGINE_finish (engine );
1463
+ if (parms .cert == NULL ) {
1464
+ php_openssl_store_errors ();
1465
+ return NULL ;
1466
+ }
1467
+ cert = parms .cert ;
1402
1468
} else {
1403
1469
in = BIO_new_mem_buf (ZSTR_VAL (cert_str ), (int ) ZSTR_LEN (cert_str ));
1404
1470
if (in == NULL ) {
@@ -3477,7 +3543,7 @@ static int php_openssl_pem_password_cb(char *buf, int size, int rwflag, void *us
3477
3543
}
3478
3544
/* }}} */
3479
3545
3480
- static EVP_PKEY * php_openssl_pkey_from_zval (zval * val , int public_key , char * passphrase , size_t passphrase_len )
3546
+ EVP_PKEY * php_openssl_pkey_from_zval (zval * val , int public_key , char * passphrase , size_t passphrase_len )
3481
3547
{
3482
3548
EVP_PKEY * key = NULL ;
3483
3549
X509 * cert = NULL ;
@@ -3549,6 +3615,8 @@ static EVP_PKEY *php_openssl_pkey_from_zval(zval *val, int public_key, char *pas
3549
3615
} else if (Z_TYPE_P (val ) == IS_OBJECT && Z_OBJCE_P (val ) == php_openssl_certificate_ce ) {
3550
3616
cert = php_openssl_certificate_from_obj (Z_OBJ_P (val ))-> x509 ;
3551
3617
} else {
3618
+ ENGINE * engine = NULL ;
3619
+
3552
3620
/* force it to be a string and check if it refers to a file */
3553
3621
/* passing non string values leaks, object uses toString, it returns NULL
3554
3622
* See bug38255.phpt
@@ -3566,13 +3634,27 @@ static EVP_PKEY *php_openssl_pkey_from_zval(zval *val, int public_key, char *pas
3566
3634
TMP_CLEAN ;
3567
3635
}
3568
3636
}
3637
+ if (Z_STRLEN_P (val ) > 7 && memcmp (Z_STRVAL_P (val ), "pkcs11:" , sizeof ("pkcs11:" ) - 1 ) == 0 ) {
3638
+ engine = php_openssl_make_pkcs11_engine (true);
3639
+ if (engine == NULL ) {
3640
+ TMP_CLEAN ;
3641
+ }
3642
+ }
3569
3643
/* it's an X509 file/cert of some kind, and we need to extract the data from that */
3570
3644
if (public_key ) {
3571
- cert = php_openssl_x509_from_str (Z_STR_P (val ));
3645
+ if (engine ) {
3646
+ key = ENGINE_load_public_key (engine , Z_STRVAL_P (val ), NULL , NULL );
3647
+ ENGINE_finish (engine );
3648
+ engine = NULL ;
3649
+ }
3650
+ /* val could be a certificate (file, pkcs11:, etc., let's try to extract the key) */
3651
+ if (!key ) {
3652
+ cert = php_openssl_x509_from_str (Z_STR_P (val ));
3653
+ }
3572
3654
3573
3655
if (cert ) {
3574
3656
free_cert = 1 ;
3575
- } else {
3657
+ } else if (! key ) {
3576
3658
/* not a X509 certificate, try to retrieve public key */
3577
3659
BIO * in ;
3578
3660
if (filename ) {
@@ -3589,26 +3671,32 @@ static EVP_PKEY *php_openssl_pkey_from_zval(zval *val, int public_key, char *pas
3589
3671
}
3590
3672
} else {
3591
3673
/* we want the private key */
3592
- BIO * in ;
3593
-
3594
- if ( filename ) {
3595
- in = BIO_new_file ( filename , PHP_OPENSSL_BIO_MODE_R ( PKCS7_BINARY )) ;
3674
+ if ( engine ) {
3675
+ key = ENGINE_load_private_key ( engine , Z_STRVAL_P ( val ), NULL , NULL );
3676
+ ENGINE_finish ( engine );
3677
+ engine = NULL ;
3596
3678
} else {
3597
- in = BIO_new_mem_buf (Z_STRVAL_P (val ), (int )Z_STRLEN_P (val ));
3598
- }
3679
+ BIO * in ;
3599
3680
3600
- if (in == NULL ) {
3601
- TMP_CLEAN ;
3602
- }
3603
- if (passphrase == NULL ) {
3604
- key = PEM_read_bio_PrivateKey (in , NULL , NULL , NULL );
3605
- } else {
3606
- struct php_openssl_pem_password password ;
3607
- password .key = passphrase ;
3608
- password .len = passphrase_len ;
3609
- key = PEM_read_bio_PrivateKey (in , NULL , php_openssl_pem_password_cb , & password );
3681
+ if (filename ) {
3682
+ in = BIO_new_file (filename , PHP_OPENSSL_BIO_MODE_R (PKCS7_BINARY ));
3683
+ } else {
3684
+ in = BIO_new_mem_buf (Z_STRVAL_P (val ), (int )Z_STRLEN_P (val ));
3685
+ }
3686
+
3687
+ if (in == NULL ) {
3688
+ TMP_CLEAN ;
3689
+ }
3690
+ if (passphrase == NULL ) {
3691
+ key = PEM_read_bio_PrivateKey (in , NULL , NULL , NULL );
3692
+ } else {
3693
+ struct php_openssl_pem_password password ;
3694
+ password .key = passphrase ;
3695
+ password .len = passphrase_len ;
3696
+ key = PEM_read_bio_PrivateKey (in , NULL , php_openssl_pem_password_cb , & password );
3697
+ }
3698
+ BIO_free (in );
3610
3699
}
3611
- BIO_free (in );
3612
3700
}
3613
3701
}
3614
3702
0 commit comments