Skip to content

Commit e65a933

Browse files
committed
PHPC-1499: Implement ClientEncryption::createDataKey
1 parent 4923bdd commit e65a933

File tree

5 files changed

+260
-0
lines changed

5 files changed

+260
-0
lines changed

php_phongo.c

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2947,6 +2947,163 @@ void phongo_clientencryption_init(php_phongo_clientencryption_t* clientencryptio
29472947
mongoc_client_encryption_opts_destroy(opts);
29482948
}
29492949
} /* }}} */
2950+
2951+
static mongoc_client_encryption_datakey_opts_t* phongo_clientencryption_datakey_opts_from_zval(zval* options TSRMLS_DC) /* {{{ */
2952+
{
2953+
mongoc_client_encryption_datakey_opts_t* opts;
2954+
2955+
opts = mongoc_client_encryption_datakey_opts_new();
2956+
2957+
if (!options || Z_TYPE_P(options) != IS_ARRAY) {
2958+
return opts;
2959+
}
2960+
2961+
if (php_array_existsc(options, "keyAltNames")) {
2962+
zval* zkeyaltnames = php_array_fetchc(options, "keyAltNames");
2963+
HashTable* ht_data;
2964+
uint32_t keyaltnames_count;
2965+
char** keyaltnames;
2966+
uint32_t i = 0;
2967+
uint32_t j = 0;
2968+
bool failed = false;
2969+
2970+
if (!zkeyaltnames || Z_TYPE_P(zkeyaltnames) != IS_ARRAY) {
2971+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Expected keyAltNames to be array, %s given", PHONGO_ZVAL_CLASS_OR_TYPE_NAME_P(zkeyaltnames));
2972+
goto cleanup;
2973+
}
2974+
2975+
ht_data = HASH_OF(zkeyaltnames);
2976+
keyaltnames_count = ht_data ? zend_hash_num_elements(ht_data) : 0;
2977+
keyaltnames = ecalloc(keyaltnames_count, sizeof(char*));
2978+
2979+
#if PHP_VERSION_ID >= 70000
2980+
{
2981+
zend_string* string_key = NULL;
2982+
zend_ulong num_key = 0;
2983+
zval* keyaltname;
2984+
2985+
ZEND_HASH_FOREACH_KEY_VAL(ht_data, num_key, string_key, keyaltname)
2986+
{
2987+
if (i >= keyaltnames_count) {
2988+
phongo_throw_exception(PHONGO_ERROR_LOGIC TSRMLS_CC, "Iterating over too many keyAltNames. Please file a bug report");
2989+
failed = true;
2990+
break;
2991+
}
2992+
2993+
if (Z_TYPE_P(keyaltname) != IS_STRING) {
2994+
if (string_key) {
2995+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Expected keyAltName with index \"%s\" to be string, %s given", ZSTR_VAL(string_key), PHONGO_ZVAL_CLASS_OR_TYPE_NAME_P(keyaltname));
2996+
} else {
2997+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Expected keyAltName with index \"%lu\" to be string, %s given", num_key, PHONGO_ZVAL_CLASS_OR_TYPE_NAME_P(keyaltname));
2998+
}
2999+
3000+
failed = true;
3001+
break;
3002+
}
3003+
3004+
keyaltnames[i] = estrdup(Z_STRVAL_P(keyaltname));
3005+
i++;
3006+
}
3007+
ZEND_HASH_FOREACH_END();
3008+
}
3009+
#else
3010+
{
3011+
HashPosition pos;
3012+
char* string_key = NULL;
3013+
uint string_key_len = 0;
3014+
ulong num_key = 0;
3015+
zval** keyaltname;
3016+
3017+
for (
3018+
zend_hash_internal_pointer_reset_ex(ht_data, &pos);
3019+
zend_hash_get_current_data_ex(ht_data, (void**) &keyaltname, &pos) == SUCCESS;
3020+
zend_hash_move_forward_ex(ht_data, &pos)) {
3021+
3022+
if (i == keyaltnames_count) {
3023+
phongo_throw_exception(PHONGO_ERROR_LOGIC TSRMLS_CC, "Iterating over too many keyAltNames. Please file a bug report");
3024+
failed = true;
3025+
break;
3026+
}
3027+
3028+
if (Z_TYPE_PP(keyaltname) != IS_STRING) {
3029+
if (zend_hash_get_current_key_ex(ht_data, &string_key, &string_key_len, &num_key, 0, &pos) == HASH_KEY_IS_STRING) {
3030+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Expected keyAltName with index \"%s\" to be string, %s given", string_key, PHONGO_ZVAL_CLASS_OR_TYPE_NAME_P(*keyaltname));
3031+
} else {
3032+
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "Expected keyAltName with index \"%lu\" to be string, %s given", num_key, PHONGO_ZVAL_CLASS_OR_TYPE_NAME_P(*keyaltname));
3033+
}
3034+
3035+
failed = true;
3036+
break;
3037+
}
3038+
3039+
keyaltnames[i] = estrdup(Z_STRVAL_PP(keyaltname));
3040+
i++;
3041+
}
3042+
}
3043+
#endif
3044+
3045+
if (!failed) {
3046+
mongoc_client_encryption_datakey_opts_set_keyaltnames(opts, keyaltnames, keyaltnames_count);
3047+
}
3048+
3049+
for (j = 0; j < i; j++) {
3050+
efree(keyaltnames[j]);
3051+
}
3052+
efree(keyaltnames);
3053+
3054+
if (failed) {
3055+
goto cleanup;
3056+
}
3057+
}
3058+
3059+
if (php_array_existsc(options, "masterKey")) {
3060+
bson_t masterkey = BSON_INITIALIZER;
3061+
3062+
php_phongo_zval_to_bson(php_array_fetchc(options, "masterKey"), PHONGO_BSON_NONE, &masterkey, NULL TSRMLS_CC);
3063+
if (EG(exception)) {
3064+
goto cleanup;
3065+
}
3066+
3067+
mongoc_client_encryption_datakey_opts_set_masterkey(opts, &masterkey);
3068+
}
3069+
3070+
return opts;
3071+
3072+
cleanup:
3073+
if (opts) {
3074+
mongoc_client_encryption_datakey_opts_destroy(opts);
3075+
}
3076+
3077+
return NULL;
3078+
} /* }}} */
3079+
3080+
void phongo_clientencryption_create_datakey(php_phongo_clientencryption_t* clientencryption, zval* return_value, char* kms_provider, zval* options TSRMLS_DC) /* {{{ */
3081+
{
3082+
mongoc_client_encryption_datakey_opts_t* opts;
3083+
bson_value_t keyid;
3084+
bson_error_t error = { 0 };
3085+
3086+
opts = phongo_clientencryption_datakey_opts_from_zval(options TSRMLS_CC);
3087+
if (!opts) {
3088+
/* Exception already thrown */
3089+
goto cleanup;
3090+
}
3091+
3092+
if (!mongoc_client_encryption_create_datakey(clientencryption->client_encryption, kms_provider, opts, &keyid, &error)) {
3093+
phongo_throw_exception_from_bson_error_t(&error TSRMLS_CC);
3094+
goto cleanup;
3095+
}
3096+
3097+
if (!php_phongo_bson_value_to_zval(&keyid, return_value)) {
3098+
/* Exception already thrown */
3099+
goto cleanup;
3100+
}
3101+
3102+
cleanup:
3103+
if (opts) {
3104+
mongoc_client_encryption_datakey_opts_destroy(opts);
3105+
}
3106+
} /* }}} */
29503107
#else /* MONGOC_ENABLE_CLIENT_SIDE_ENCRYPTION */
29513108
static void phongo_throw_exception_no_cse(php_phongo_error_domain_t domain, const char* message TSRMLS_DC) /* {{{ */
29523109
{
@@ -2971,6 +3128,12 @@ void phongo_clientencryption_init(php_phongo_clientencryption_t* clientencryptio
29713128
phongo_throw_exception_no_cse(PHONGO_ERROR_RUNTIME, "Cannot configure clientEncryption object." TSRMLS_CC);
29723129
}
29733130
/* }}} */
3131+
3132+
void phongo_clientencryption_create_datakey(php_phongo_clientencryption_t* clientencryption, zval* return_value, char* kms_provider, zval* options TSRMLS_DC) /* {{{ */
3133+
{
3134+
phongo_throw_exception_no_cse(PHONGO_ERROR_RUNTIME, "Cannot create encryption key." TSRMLS_CC);
3135+
}
3136+
/* }}} */
29743137
#endif
29753138

29763139
void phongo_manager_init(php_phongo_manager_t* manager, const char* uri_string, zval* options, zval* driverOptions TSRMLS_DC) /* {{{ */

php_phongo.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,8 @@ int php_phongo_set_monitoring_callbacks(mongoc_client_t* client);
167167

168168
bool php_phongo_parse_int64(int64_t* retval, const char* data, phongo_zpp_char_len data_len);
169169

170+
void phongo_clientencryption_create_datakey(php_phongo_clientencryption_t* clientencryption, zval* return_value, char* kms_provider, zval* options TSRMLS_DC);
171+
170172
zend_bool phongo_writeerror_init(zval* return_value, bson_t* bson TSRMLS_DC);
171173
zend_bool phongo_writeconcernerror_init(zval* return_value, bson_t* bson TSRMLS_DC);
172174

src/MongoDB/ClientEncryption.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,40 @@
2626

2727
zend_class_entry* php_phongo_clientencryption_ce;
2828

29+
/* {{{ proto MongoDB\BSON\Binary MongoDB\Driver\ClientEncryption::createDataKey(string $kmsProvider[, array $options])
30+
Creates a new key document and inserts into the key vault collection. */
31+
static PHP_METHOD(ClientEncryption, createDataKey)
32+
{
33+
char* kms_provider = NULL;
34+
phongo_zpp_char_len kms_provider_len = 0;
35+
zval* options = NULL;
36+
zend_error_handling error_handling;
37+
php_phongo_clientencryption_t* intern;
38+
39+
intern = Z_CLIENTENCRYPTION_OBJ_P(getThis());
40+
zend_replace_error_handling(EH_THROW, phongo_exception_from_phongo_domain(PHONGO_ERROR_INVALID_ARGUMENT), &error_handling TSRMLS_CC);
41+
42+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|a!", &kms_provider, &kms_provider_len, &options) == FAILURE) {
43+
zend_restore_error_handling(&error_handling TSRMLS_CC);
44+
return;
45+
}
46+
47+
zend_restore_error_handling(&error_handling TSRMLS_CC);
48+
49+
phongo_clientencryption_create_datakey(intern, return_value, kms_provider, options TSRMLS_CC);
50+
} /* }}} */
51+
52+
ZEND_BEGIN_ARG_INFO_EX(ai_ClientEncryption_createDataKey, 0, 0, 1)
53+
ZEND_ARG_INFO(0, kmsProvider)
54+
ZEND_ARG_ARRAY_INFO(0, options, 1)
55+
ZEND_END_ARG_INFO()
56+
2957
ZEND_BEGIN_ARG_INFO_EX(ai_ClientEncryption_void, 0, 0, 0)
3058
ZEND_END_ARG_INFO()
3159

3260
static zend_function_entry php_phongo_clientencryption_me[] = {
3361
/* clang-format off */
62+
PHP_ME(ClientEncryption, createDataKey, ai_ClientEncryption_createDataKey, ZEND_ACC_PUBLIC | ZEND_ACC_FINAL)
3463
ZEND_NAMED_ME(__construct, PHP_FN(MongoDB_disabled___construct), ai_ClientEncryption_void, ZEND_ACC_PRIVATE | ZEND_ACC_FINAL)
3564
ZEND_NAMED_ME(__wakeup, PHP_FN(MongoDB_disabled___wakeup), ai_ClientEncryption_void, ZEND_ACC_PUBLIC | ZEND_ACC_FINAL)
3665
PHP_FE_END
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
--TEST--
2+
MongoDB\Driver\ClientEncryption::createDataKey()
3+
--SKIPIF--
4+
<?php require __DIR__ . "/../utils/basic-skipif.inc"; ?>
5+
<?php skip_if_not_libmongocrypt(); ?>
6+
<?php skip_if_not_live(); ?>
7+
--FILE--
8+
<?php
9+
require_once __DIR__ . "/../utils/basic.inc";
10+
11+
$key = base64_decode('Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk');
12+
13+
$manager = new MongoDB\Driver\Manager(URI);
14+
$clientEncryption = $manager->createClientEncryption(['keyVaultNamespace' => 'default.keys', 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary($key, 0)]]]);
15+
16+
var_dump($clientEncryption->createDataKey('local'));
17+
18+
?>
19+
===DONE===
20+
<?php exit(0); ?>
21+
--EXPECTF--
22+
object(MongoDB\BSON\Binary)#%d (%d) {
23+
["data"]=>
24+
string(16) "%a"
25+
["type"]=>
26+
int(4)
27+
}
28+
===DONE===
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
--TEST--
2+
MongoDB\Driver\ClientEncryption::createDataKey() with invalid keyAltNames
3+
--SKIPIF--
4+
<?php require __DIR__ . "/../utils/basic-skipif.inc"; ?>
5+
<?php skip_if_not_libmongocrypt(); ?>
6+
<?php skip_if_not_live(); ?>
7+
--FILE--
8+
<?php
9+
require_once __DIR__ . "/../utils/basic.inc";
10+
11+
$key = base64_decode('Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk');
12+
13+
$tests = [
14+
['keyAltNames' => 'foo'],
15+
['keyAltNames' => [0 => []]],
16+
['keyAltNames' => ['foo' => []]],
17+
];
18+
19+
$manager = new MongoDB\Driver\Manager(URI);
20+
$clientEncryption = $manager->createClientEncryption(['keyVaultNamespace' => 'default.keys', 'kmsProviders' => ['local' => ['key' => new MongoDB\BSON\Binary($key, 0)]]]);
21+
22+
foreach ($tests as $opts) {
23+
echo throws(function () use ($clientEncryption, $opts) {
24+
$clientEncryption->createDataKey('local', $opts);
25+
}, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n";
26+
}
27+
28+
?>
29+
===DONE===
30+
<?php exit(0); ?>
31+
--EXPECT--
32+
OK: Got MongoDB\Driver\Exception\InvalidArgumentException
33+
Expected keyAltNames to be array, string given
34+
OK: Got MongoDB\Driver\Exception\InvalidArgumentException
35+
Expected keyAltName with index "0" to be string, array given
36+
OK: Got MongoDB\Driver\Exception\InvalidArgumentException
37+
Expected keyAltName with index "foo" to be string, array given
38+
===DONE===

0 commit comments

Comments
 (0)