Skip to content

Commit 168efc4

Browse files
committed
Merge pull request #1071
2 parents d3a0983 + 08bac1e commit 168efc4

10 files changed

+361
-19
lines changed

phongo_compat.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,14 @@
169169
Z_ARRVAL_P(__z) = __arr; \
170170
Z_TYPE_P(__z) = IS_ARRAY; \
171171
} while (0);
172+
#define ZVAL_DUP(z, v) \
173+
do { \
174+
zval* _z = (z); \
175+
const zval* _v = (v); \
176+
*_z = *_v; \
177+
INIT_PZVAL(_z); \
178+
zval_copy_ctor(_z); \
179+
} while (0);
172180
#define phongo_free_object_arg void
173181
#define phongo_zpp_char_len int
174182
#define ZEND_HASH_APPLY_PROTECTION(ht) 1

php_phongo.c

Lines changed: 218 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2511,6 +2511,66 @@ int php_phongo_set_monitoring_callbacks(mongoc_client_t* client)
25112511
return retval;
25122512
}
25132513

2514+
static zval* php_phongo_manager_prepare_manager_for_hash(zval* driverOptions, bool* free TSRMLS_DC)
2515+
{
2516+
php_phongo_manager_t* manager;
2517+
zval* autoEncryptionOpts = NULL;
2518+
zval* keyVaultClient = NULL;
2519+
zval* driverOptionsClone = NULL;
2520+
zval* autoEncryptionOptsClone = NULL;
2521+
#if PHP_VERSION_ID >= 70000
2522+
zval stackAutoEncryptionOptsClone;
2523+
#endif
2524+
2525+
*free = false;
2526+
2527+
if (!driverOptions) {
2528+
return NULL;
2529+
}
2530+
2531+
if (!php_array_existsc(driverOptions, "autoEncryption")) {
2532+
goto ref;
2533+
}
2534+
2535+
autoEncryptionOpts = php_array_fetchc(driverOptions, "autoEncryption");
2536+
if (Z_TYPE_P(autoEncryptionOpts) != IS_ARRAY) {
2537+
goto ref;
2538+
}
2539+
2540+
if (!php_array_existsc(autoEncryptionOpts, "keyVaultClient")) {
2541+
goto ref;
2542+
}
2543+
2544+
keyVaultClient = php_array_fetchc(autoEncryptionOpts, "keyVaultClient");
2545+
if (Z_TYPE_P(keyVaultClient) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(keyVaultClient), php_phongo_manager_ce TSRMLS_CC)) {
2546+
goto ref;
2547+
}
2548+
2549+
*free = true;
2550+
2551+
manager = Z_MANAGER_OBJ_P(keyVaultClient);
2552+
2553+
#if PHP_VERSION_ID >= 70000
2554+
driverOptionsClone = ecalloc(sizeof(zval), 1);
2555+
autoEncryptionOptsClone = &stackAutoEncryptionOptsClone;
2556+
#else
2557+
ALLOC_INIT_ZVAL(driverOptionsClone);
2558+
MAKE_STD_ZVAL(autoEncryptionOptsClone);
2559+
#endif
2560+
2561+
ZVAL_DUP(autoEncryptionOptsClone, autoEncryptionOpts);
2562+
ADD_ASSOC_STRINGL(autoEncryptionOptsClone, "keyVaultClient", manager->client_hash, manager->client_hash_len);
2563+
2564+
ZVAL_DUP(driverOptionsClone, driverOptions);
2565+
ADD_ASSOC_ZVAL_EX(driverOptionsClone, "autoEncryption", autoEncryptionOptsClone);
2566+
2567+
return driverOptionsClone;
2568+
2569+
ref:
2570+
Z_ADDREF_P(driverOptions);
2571+
return driverOptions;
2572+
}
2573+
25142574
/* Creates a hash for a client by concatenating the URI string with serialized
25152575
* options arrays. On success, a persistent string is returned (i.e. pefree()
25162576
* should be used to free it) and hash_len will be set to the string's length.
@@ -2520,6 +2580,8 @@ static char* php_phongo_manager_make_client_hash(const char* uri_string, zval* o
25202580
char* hash = NULL;
25212581
smart_str var_buf = { 0 };
25222582
php_serialize_data_t var_hash;
2583+
zval* serializable_driver_options = NULL;
2584+
bool free_driver_options = false;
25232585

25242586
#if PHP_VERSION_ID >= 70000
25252587
zval args;
@@ -2536,8 +2598,8 @@ static char* php_phongo_manager_make_client_hash(const char* uri_string, zval* o
25362598
}
25372599

25382600
if (driverOptions) {
2539-
ADD_ASSOC_ZVAL_EX(&args, "driverOptions", driverOptions);
2540-
Z_ADDREF_P(driverOptions);
2601+
serializable_driver_options = php_phongo_manager_prepare_manager_for_hash(driverOptions, &free_driver_options TSRMLS_CC);
2602+
ADD_ASSOC_ZVAL_EX(&args, "driverOptions", serializable_driver_options);
25412603
} else {
25422604
ADD_ASSOC_NULL_EX(&args, "driverOptions");
25432605
}
@@ -2548,10 +2610,15 @@ static char* php_phongo_manager_make_client_hash(const char* uri_string, zval* o
25482610

25492611
if (!EG(exception)) {
25502612
*hash_len = ZSTR_LEN(var_buf.s);
2551-
hash = pestrndup(ZSTR_VAL(var_buf.s), *hash_len, 1);
2613+
hash = estrndup(ZSTR_VAL(var_buf.s), *hash_len);
25522614
}
25532615

25542616
zval_ptr_dtor(&args);
2617+
2618+
if (free_driver_options) {
2619+
efree(serializable_driver_options);
2620+
}
2621+
25552622
#else
25562623
zval* args;
25572624

@@ -2568,8 +2635,8 @@ static char* php_phongo_manager_make_client_hash(const char* uri_string, zval* o
25682635
}
25692636

25702637
if (driverOptions) {
2571-
ADD_ASSOC_ZVAL_EX(args, "driverOptions", driverOptions);
2572-
Z_ADDREF_P(driverOptions);
2638+
serializable_driver_options = php_phongo_manager_prepare_manager_for_hash(driverOptions, &free_driver_options TSRMLS_CC);
2639+
ADD_ASSOC_ZVAL_EX(args, "driverOptions", serializable_driver_options);
25732640
} else {
25742641
ADD_ASSOC_NULL_EX(args, "driverOptions");
25752642
}
@@ -2580,7 +2647,7 @@ static char* php_phongo_manager_make_client_hash(const char* uri_string, zval* o
25802647

25812648
if (!EG(exception)) {
25822649
*hash_len = var_buf.len;
2583-
hash = pestrndup(var_buf.c, *hash_len, 1);
2650+
hash = estrndup(var_buf.c, *hash_len);
25842651
}
25852652

25862653
zval_ptr_dtor(&args);
@@ -2653,23 +2720,156 @@ static mongoc_client_t* php_phongo_find_client(const char* hash, size_t hash_len
26532720
return NULL;
26542721
}
26552722

2723+
#ifdef MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION
2724+
static bool phongo_manager_set_auto_encryption_opts(php_phongo_manager_t* manager, zval* driverOptions TSRMLS_DC) /* {{{ */
2725+
{
2726+
zval* zAutoEncryptionOpts;
2727+
bson_error_t error = { 0 };
2728+
mongoc_auto_encryption_opts_t* auto_encryption_opts = NULL;
2729+
bool retval = false;
2730+
2731+
if (!driverOptions || !php_array_existsc(driverOptions, "autoEncryption")) {
2732+
return true;
2733+
}
2734+
2735+
zAutoEncryptionOpts = php_array_fetch(driverOptions, "autoEncryption");
2736+
2737+
if (Z_TYPE_P(zAutoEncryptionOpts) != IS_ARRAY) {
2738+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Expected \"autoEncryption\" driver option to be array, %s given", PHONGO_ZVAL_CLASS_OR_TYPE_NAME_P(zAutoEncryptionOpts));
2739+
return false;
2740+
}
2741+
2742+
auto_encryption_opts = mongoc_auto_encryption_opts_new();
2743+
2744+
if (php_array_existsc(zAutoEncryptionOpts, "keyVaultClient")) {
2745+
zval* key_vault_client = php_array_fetch(zAutoEncryptionOpts, "keyVaultClient");
2746+
2747+
if (Z_TYPE_P(key_vault_client) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(key_vault_client), php_phongo_manager_ce TSRMLS_CC)) {
2748+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Expected \"keyVaultClient\" encryption option to be %s, %s given", ZSTR_VAL(php_phongo_manager_ce->name), PHONGO_ZVAL_CLASS_OR_TYPE_NAME_P(key_vault_client));
2749+
goto cleanup;
2750+
}
2751+
2752+
mongoc_auto_encryption_opts_set_keyvault_client(auto_encryption_opts, Z_MANAGER_OBJ_P(key_vault_client)->client);
2753+
}
2754+
2755+
if (php_array_existsc(zAutoEncryptionOpts, "keyVaultNamespace")) {
2756+
char* key_vault_ns;
2757+
char* db_name;
2758+
char* coll_name;
2759+
int plen;
2760+
zend_bool pfree;
2761+
2762+
key_vault_ns = php_array_fetch_string(zAutoEncryptionOpts, "keyVaultNamespace", &plen, &pfree);
2763+
2764+
if (!phongo_split_namespace(key_vault_ns, &db_name, &coll_name)) {
2765+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Expected \"keyVaultNamespace\" encryption option to contain a full collection name");
2766+
2767+
if (pfree) {
2768+
str_efree(key_vault_ns);
2769+
}
2770+
2771+
goto cleanup;
2772+
}
2773+
2774+
mongoc_auto_encryption_opts_set_keyvault_namespace(auto_encryption_opts, db_name, coll_name);
2775+
2776+
efree(db_name);
2777+
efree(coll_name);
2778+
2779+
if (pfree) {
2780+
str_efree(key_vault_ns);
2781+
}
2782+
}
2783+
2784+
if (php_array_existsc(zAutoEncryptionOpts, "kmsProviders")) {
2785+
zval* kms_providers = php_array_fetch(zAutoEncryptionOpts, "kmsProviders");
2786+
bson_t bson_providers = BSON_INITIALIZER;
2787+
2788+
php_phongo_zval_to_bson(kms_providers, PHONGO_BSON_NONE, &bson_providers, NULL TSRMLS_CC);
2789+
if (EG(exception)) {
2790+
goto cleanup;
2791+
}
2792+
2793+
mongoc_auto_encryption_opts_set_kms_providers(auto_encryption_opts, &bson_providers);
2794+
2795+
bson_destroy(&bson_providers);
2796+
}
2797+
2798+
if (php_array_existsc(zAutoEncryptionOpts, "schemaMap")) {
2799+
zval* schema_map = php_array_fetch(zAutoEncryptionOpts, "schemaMap");
2800+
bson_t bson_map = BSON_INITIALIZER;
2801+
2802+
php_phongo_zval_to_bson(schema_map, PHONGO_BSON_NONE, &bson_map, NULL TSRMLS_CC);
2803+
if (EG(exception)) {
2804+
goto cleanup;
2805+
}
2806+
2807+
mongoc_auto_encryption_opts_set_schema_map(auto_encryption_opts, &bson_map);
2808+
2809+
bson_destroy(&bson_map);
2810+
}
2811+
2812+
if (php_array_existsc(zAutoEncryptionOpts, "bypassAutoEncryption")) {
2813+
zend_bool bypass_auto_encryption = php_array_fetch_bool(zAutoEncryptionOpts, "bypassAutoEncryption");
2814+
2815+
mongoc_auto_encryption_opts_set_bypass_auto_encryption(auto_encryption_opts, bypass_auto_encryption);
2816+
}
2817+
2818+
if (php_array_existsc(zAutoEncryptionOpts, "extraOptions")) {
2819+
zval* extra_options = php_array_fetch(zAutoEncryptionOpts, "extraOptions");
2820+
bson_t bson_options = BSON_INITIALIZER;
2821+
2822+
php_phongo_zval_to_bson(extra_options, PHONGO_BSON_NONE, &bson_options, NULL TSRMLS_CC);
2823+
if (EG(exception)) {
2824+
goto cleanup;
2825+
}
2826+
2827+
mongoc_auto_encryption_opts_set_extra(auto_encryption_opts, &bson_options);
2828+
2829+
bson_destroy(&bson_options);
2830+
}
2831+
2832+
if (!mongoc_client_enable_auto_encryption(manager->client, auto_encryption_opts, &error)) {
2833+
phongo_throw_exception_from_bson_error_t(&error TSRMLS_CC);
2834+
goto cleanup;
2835+
}
2836+
2837+
retval = true;
2838+
2839+
cleanup:
2840+
mongoc_auto_encryption_opts_destroy(auto_encryption_opts);
2841+
return retval;
2842+
}
2843+
/* }}} */
2844+
#else /* MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION */
2845+
static bool phongo_manager_set_auto_encryption_opts(php_phongo_manager_t* manager, zval* driverOptions TSRMLS_DC) /* {{{ */
2846+
{
2847+
if (!driverOptions || !php_array_existsc(driverOptions, "autoEncryption")) {
2848+
return true;
2849+
}
2850+
2851+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Cannot enable automatic field-level encryption. Please recompile with support for libmongocrypt using the with-mongodb-client-side-encryption configure switch.");
2852+
2853+
return false;
2854+
}
2855+
/* }}} */
2856+
#endif
2857+
26562858
void phongo_manager_init(php_phongo_manager_t* manager, const char* uri_string, zval* options, zval* driverOptions TSRMLS_DC) /* {{{ */
26572859
{
2658-
char* hash = NULL;
2659-
size_t hash_len = 0;
26602860
bson_t bson_options = BSON_INITIALIZER;
26612861
mongoc_uri_t* uri = NULL;
26622862
#ifdef MONGOC_ENABLE_SSL
26632863
mongoc_ssl_opt_t* ssl_opt = NULL;
26642864
#endif
26652865

2666-
if (!(hash = php_phongo_manager_make_client_hash(uri_string, options, driverOptions, &hash_len TSRMLS_CC))) {
2866+
if (!(manager->client_hash = php_phongo_manager_make_client_hash(uri_string, options, driverOptions, &manager->client_hash_len TSRMLS_CC))) {
26672867
/* Exception should already have been thrown and there is nothing to free */
26682868
return;
26692869
}
26702870

2671-
if ((manager->client = php_phongo_find_client(hash, hash_len TSRMLS_CC))) {
2672-
MONGOC_DEBUG("Found client for hash: %s\n", hash);
2871+
if ((manager->client = php_phongo_find_client(manager->client_hash, manager->client_hash_len TSRMLS_CC))) {
2872+
MONGOC_DEBUG("Found client for hash: %s\n", manager->client_hash);
26732873
goto cleanup;
26742874
}
26752875

@@ -2733,14 +2933,15 @@ void phongo_manager_init(php_phongo_manager_t* manager, const char* uri_string,
27332933
}
27342934
#endif
27352935

2736-
MONGOC_DEBUG("Created client hash: %s\n", hash);
2737-
php_phongo_persist_client(hash, hash_len, manager->client TSRMLS_CC);
2738-
2739-
cleanup:
2740-
if (hash) {
2741-
pefree(hash, 1);
2936+
if (!phongo_manager_set_auto_encryption_opts(manager, driverOptions TSRMLS_CC)) {
2937+
/* Exception should already have been thrown */
2938+
goto cleanup;
27422939
}
27432940

2941+
MONGOC_DEBUG("Created client hash: %s\n", manager->client_hash);
2942+
php_phongo_persist_client(manager->client_hash, manager->client_hash_len, manager->client TSRMLS_CC);
2943+
2944+
cleanup:
27442945
bson_destroy(&bson_options);
27452946

27462947
if (uri) {

php_phongo_structs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ typedef struct {
8080
PHONGO_ZEND_OBJECT_PRE
8181
mongoc_client_t* client;
8282
int created_by_pid;
83+
char* client_hash;
84+
size_t client_hash_len;
8385
PHONGO_ZEND_OBJECT_POST
8486
} php_phongo_manager_t;
8587

src/LIBMONGOCRYPT_VERSION_CURRENT

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.0.1-dev+20191220git5ff8a05d97
1+
1.0.1-dev+20200108gitb6cab3967e

src/MongoDB/Manager.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -866,6 +866,10 @@ static void php_phongo_manager_free_object(phongo_free_object_arg* object TSRMLS
866866
intern->client = NULL;
867867
}
868868

869+
if (intern->client_hash) {
870+
efree(intern->client_hash);
871+
}
872+
869873
#if PHP_VERSION_ID < 70000
870874
efree(intern);
871875
#endif
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
--TEST--
2+
MongoDB\Driver\Manager::__construct(): auto encryption options
3+
--SKIPIF--
4+
<?php require __DIR__ . "/../utils/basic-skipif.inc"; ?>
5+
<?php skip_if_not_libmongocrypt(); ?>
6+
--FILE--
7+
<?php
8+
9+
$baseOptions = [
10+
'keyVaultNamespace' => 'admin.dataKeys',
11+
'kmsProviders' => ['aws' => (object) ['accessKeyId' => 'abc', 'secretAccessKey' => 'def']]
12+
];
13+
14+
$tests = [
15+
[],
16+
['keyVaultClient' => new MongoDB\Driver\Manager()],
17+
['schemaMap' => [
18+
'default.default' => [
19+
'properties' => [
20+
'encrypted_objectId' => [
21+
'encrypt' => [
22+
'keyId' => [
23+
[
24+
'$binary' => [
25+
'base64' => 'AAAAAAAAAAAAAAAAAAAAAA==',
26+
'subType' => '04',
27+
],
28+
],
29+
],
30+
'bsonType' => 'objectId',
31+
'algorithm' => 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic',
32+
],
33+
],
34+
],
35+
'bsonType' => 'object',
36+
],
37+
]],
38+
['bypassAutoEncryption' => true],
39+
['extraOptions' => ['mongocryptdBypassSpawn' => true]],
40+
];
41+
42+
foreach ($tests as $autoEncryptionOptions) {
43+
$manager = new MongoDB\Driver\Manager(null, [], ['autoEncryption' => $autoEncryptionOptions + $baseOptions]);
44+
}
45+
46+
?>
47+
===DONE===
48+
<?php exit(0); ?>
49+
--EXPECT--
50+
===DONE===

0 commit comments

Comments
 (0)