@@ -178,6 +178,8 @@ public function testDataKeyAndDoubleEncryption(string $providerName, $masterKey)
178
178
'keyVaultNamespace ' => 'keyvault.datakeys ' ,
179
179
'kmsProviders ' => [
180
180
'aws ' => Context::getAWSCredentials (),
181
+ 'azure ' => Context::getAzureCredentials (),
182
+ 'gcp ' => Context::getGCPCredentials (),
181
183
'local ' => ['key ' => new Binary (base64_decode (self ::LOCAL_MASTERKEY ), 0 )],
182
184
],
183
185
];
@@ -268,6 +270,22 @@ public static function dataKeyProvider()
268
270
'key ' => 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0 ' ,
269
271
],
270
272
],
273
+ 'azure ' => [
274
+ 'providerName ' => 'azure ' ,
275
+ 'masterKey ' => [
276
+ 'keyVaultEndpoint ' => 'key-vault-csfle.vault.azure.net ' ,
277
+ 'keyName ' => 'key-name-csfle ' ,
278
+ ],
279
+ ],
280
+ 'gcp ' => [
281
+ 'providerName ' => 'gcp ' ,
282
+ 'masterKey ' => [
283
+ 'projectId ' => 'devprod-drivers ' ,
284
+ 'location ' => 'global ' ,
285
+ 'keyRing ' => 'key-ring-csfle ' ,
286
+ 'keyName ' => 'key-name-csfle ' ,
287
+ ],
288
+ ],
271
289
];
272
290
}
273
291
@@ -505,12 +523,16 @@ public function testCorpus($schemaMap = true)
505
523
$ client ->selectCollection ('keyvault ' , 'datakeys ' )->insertMany ([
506
524
$ this ->decodeJson (file_get_contents (__DIR__ . '/client-side-encryption/corpus/corpus-key-local.json ' )),
507
525
$ this ->decodeJson (file_get_contents (__DIR__ . '/client-side-encryption/corpus/corpus-key-aws.json ' )),
526
+ $ this ->decodeJson (file_get_contents (__DIR__ . '/client-side-encryption/corpus/corpus-key-azure.json ' )),
527
+ $ this ->decodeJson (file_get_contents (__DIR__ . '/client-side-encryption/corpus/corpus-key-gcp.json ' )),
508
528
]);
509
529
510
530
$ encryptionOpts = [
511
531
'keyVaultNamespace ' => 'keyvault.datakeys ' ,
512
532
'kmsProviders ' => [
513
533
'aws ' => Context::getAWSCredentials (),
534
+ 'azure ' => Context::getAzureCredentials (),
535
+ 'gcp ' => Context::getGCPCredentials (),
514
536
'local ' => ['key ' => new Binary (base64_decode (self ::LOCAL_MASTERKEY ), 0 )],
515
537
],
516
538
];
@@ -535,19 +557,55 @@ public function testCorpus($schemaMap = true)
535
557
switch ($ fieldName ) {
536
558
case '_id ' :
537
559
case 'altname_aws ' :
560
+ case 'altname_azure ' :
561
+ case 'altname_gcp ' :
538
562
case 'altname_local ' :
539
563
$ corpusCopied [$ fieldName ] = $ data ;
540
564
break ;
541
565
542
566
default :
543
- $ corpusCopied [$ fieldName ] = $ this ->prepareCorpusData ($ data , $ clientEncryption );
567
+ $ corpusCopied [$ fieldName ] = $ this ->prepareCorpusData ($ fieldName , $ data , $ clientEncryption );
544
568
}
545
569
}
546
570
547
571
$ collection ->insertOne ($ corpusCopied );
548
572
$ corpusDecrypted = $ collection ->findOne (['_id ' => 'client_side_encryption_corpus ' ]);
549
573
550
574
$ this ->assertDocumentsMatch ($ corpus , $ corpusDecrypted );
575
+
576
+ $ corpusEncryptedExpected = (array ) $ this ->decodeJson (file_get_contents (__DIR__ . '/client-side-encryption/corpus/corpus-encrypted.json ' ));
577
+ $ corpusEncryptedActual = $ client ->selectCollection ('db ' , 'coll ' )->findOne (['_id ' => 'client_side_encryption_corpus ' ], ['typeMap ' => ['root ' => 'array ' , 'document ' => stdClass::class, 'array ' => 'array ' ]]);
578
+
579
+ foreach ($ corpusEncryptedExpected as $ fieldName => $ expectedData ) {
580
+ switch ($ fieldName ) {
581
+ case '_id ' :
582
+ case 'altname_aws ' :
583
+ case 'altname_azure ' :
584
+ case 'altname_gcp ' :
585
+ case 'altname_local ' :
586
+ continue 2 ;
587
+ }
588
+
589
+ $ actualData = $ corpusEncryptedActual [$ fieldName ];
590
+
591
+ if ($ expectedData ->algo === 'det ' ) {
592
+ $ this ->assertEquals ($ expectedData ->value , $ actualData ->value , 'Value for field ' . $ fieldName . ' does not match expected value. ' );
593
+ }
594
+
595
+ if ($ expectedData ->allowed ) {
596
+ if ($ expectedData ->algo === 'rand ' ) {
597
+ $ this ->assertNotEquals ($ expectedData ->value , $ actualData ->value , 'Value for field ' . $ fieldName . ' does not differ from expected value. ' );
598
+ }
599
+
600
+ $ this ->assertEquals (
601
+ $ clientEncryption ->decrypt ($ expectedData ->value ),
602
+ $ clientEncryption ->decrypt ($ actualData ->value ),
603
+ 'Decrypted value for field ' . $ fieldName . ' does not match. '
604
+ );
605
+ } else {
606
+ $ this ->assertEquals ($ corpus [$ fieldName ]->value , $ actualData ->value , 'Value for field ' . $ fieldName . ' does not match original value. ' );
607
+ }
608
+ }
551
609
}
552
610
553
611
/**
@@ -582,6 +640,14 @@ public function testCustomEndpoint(Closure $test)
582
640
public static function customEndpointProvider ()
583
641
{
584
642
$ awsMasterKey = ['region ' => 'us-east-1 ' , 'key ' => 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0 ' ];
643
+ $ azureMasterKey = ['keyVaultEndpoint ' => 'key-vault-csfle.vault.azure.net ' , 'keyName ' => 'key-name-csfle ' ];
644
+ $ gcpMasterKey = [
645
+ 'projectId ' => 'devprod-drivers ' ,
646
+ 'location ' => 'global ' ,
647
+ 'keyRing ' => 'key-ring-csfle ' ,
648
+ 'keyName ' => 'key-name-csfle ' ,
649
+ 'endpoint ' => 'cloudkms.googleapis.com:443 ' ,
650
+ ];
585
651
586
652
return [
587
653
'Test 1 ' => [
@@ -625,6 +691,38 @@ static function (self $test, ClientEncryption $clientEncryption, ClientEncryptio
625
691
$ clientEncryption ->createDataKey ('aws ' , ['masterKey ' => $ awsMasterKey + ['endpoint ' => 'example.com ' ]]);
626
692
},
627
693
],
694
+ 'Test 7 ' => [
695
+ static function (self $ test , ClientEncryption $ clientEncryption , ClientEncryption $ clientEncryptionInvalid ) use ($ azureMasterKey ) {
696
+ $ keyId = $ clientEncryption ->createDataKey ('azure ' , ['masterKey ' => $ azureMasterKey ]);
697
+ $ encrypted = $ clientEncryption ->encrypt ('test ' , ['algorithm ' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC , 'keyId ' => $ keyId ]);
698
+ $ test ->assertSame ('test ' , $ clientEncryption ->decrypt ($ encrypted ));
699
+
700
+ $ test ->expectException (RuntimeException::class);
701
+ $ test ->expectExceptionMessageMatches ('#parse error# ' );
702
+ $ clientEncryptionInvalid ->createDataKey ('azure ' , ['masterKey ' => $ azureMasterKey ]);
703
+ },
704
+ ],
705
+ 'Test 8 ' => [
706
+ static function (self $ test , ClientEncryption $ clientEncryption , ClientEncryption $ clientEncryptionInvalid ) use ($ gcpMasterKey ) {
707
+ $ keyId = $ clientEncryption ->createDataKey ('gcp ' , ['masterKey ' => $ gcpMasterKey ]);
708
+ $ encrypted = $ clientEncryption ->encrypt ('test ' , ['algorithm ' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC , 'keyId ' => $ keyId ]);
709
+ $ test ->assertSame ('test ' , $ clientEncryption ->decrypt ($ encrypted ));
710
+
711
+ $ test ->expectException (RuntimeException::class);
712
+ $ test ->expectExceptionMessageMatches ('#parse error# ' );
713
+ $ clientEncryptionInvalid ->createDataKey ('gcp ' , ['masterKey ' => $ gcpMasterKey ]);
714
+ },
715
+ ],
716
+ 'Test 9 ' => [
717
+ static function (self $ test , ClientEncryption $ clientEncryption , ClientEncryption $ clientEncryptionInvalid ) use ($ gcpMasterKey ) {
718
+ $ masterKey = $ gcpMasterKey ;
719
+ $ masterKey ['endpoint ' ] = 'example.com:443 ' ;
720
+
721
+ $ test ->expectException (RuntimeException::class);
722
+ $ test ->expectExceptionMessageMatches ('#Invalid KMS response# ' );
723
+ $ clientEncryption ->createDataKey ('gcp ' , ['masterKey ' => $ masterKey ]);
724
+ },
725
+ ],
628
726
];
629
727
}
630
728
@@ -719,28 +817,54 @@ private function createTestCollection($jsonSchema)
719
817
$ operation ->execute ($ this ->getPrimaryServer ());
720
818
}
721
819
722
- private function encryptCorpusValue (stdClass $ data , ClientEncryption $ clientEncryption )
820
+ private function encryptCorpusValue (string $ fieldName , stdClass $ data , ClientEncryption $ clientEncryption )
723
821
{
724
822
$ encryptionOptions = [
725
823
'algorithm ' => $ data ->algo === 'rand ' ? ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_RANDOM : ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC ,
726
824
];
727
825
826
+ switch ($ data ->kms ) {
827
+ case 'local ' :
828
+ $ keyId = 'LOCALAAAAAAAAAAAAAAAAA== ' ;
829
+ $ keyAltName = 'local ' ;
830
+ break ;
831
+ case 'aws ' :
832
+ $ keyId = 'AWSAAAAAAAAAAAAAAAAAAA== ' ;
833
+ $ keyAltName = 'aws ' ;
834
+ break ;
835
+ case 'azure ' :
836
+ $ keyId = 'AZUREAAAAAAAAAAAAAAAAA== ' ;
837
+ $ keyAltName = 'azure ' ;
838
+ break ;
839
+ case 'gcp ' :
840
+ $ keyId = 'GCPAAAAAAAAAAAAAAAAAAA== ' ;
841
+ $ keyAltName = 'gcp ' ;
842
+ break ;
843
+
844
+ default :
845
+ throw new UnexpectedValueException ('Unexpected KMS "%s" ' , $ data ->kms );
846
+ }
847
+
728
848
switch ($ data ->identifier ) {
729
849
case 'id ' :
730
- $ keyId = $ data ->kms === 'local ' ? 'LOCALAAAAAAAAAAAAAAAAA== ' : 'AWSAAAAAAAAAAAAAAAAAAA== ' ;
731
850
$ encryptionOptions ['keyId ' ] = new Binary (base64_decode ($ keyId ), 4 );
732
851
break ;
733
852
734
853
case 'altname ' :
735
- $ encryptionOptions ['keyAltName ' ] = $ data -> kms === ' local ' ? ' local ' : ' aws ' ;
854
+ $ encryptionOptions ['keyAltName ' ] = $ keyAltName ;
736
855
break ;
737
856
738
857
default :
739
858
throw new UnexpectedValueException ('Unexpected value "%s" for identifier ' , $ data ->identifier );
740
859
}
741
860
742
861
if ($ data ->allowed ) {
743
- $ encrypted = $ clientEncryption ->encrypt ($ this ->craftInt64 ($ data ), $ encryptionOptions );
862
+ try {
863
+ $ encrypted = $ clientEncryption ->encrypt ($ this ->craftInt64 ($ data ), $ encryptionOptions );
864
+ } catch (EncryptionException $ e ) {
865
+ $ this ->fail ('Could not encrypt value for field ' . $ fieldName . ': ' . $ e ->getMessage ());
866
+ }
867
+
744
868
$ this ->assertEquals ($ data ->value , $ clientEncryption ->decrypt ($ encrypted ));
745
869
746
870
return $ encrypted ;
@@ -769,7 +893,7 @@ private function insertKeyVaultData(array $keyVaultData = null)
769
893
return ;
770
894
}
771
895
772
- private function prepareCorpusData (stdClass $ data , ClientEncryption $ clientEncryption )
896
+ private function prepareCorpusData (string $ fieldName , stdClass $ data , ClientEncryption $ clientEncryption )
773
897
{
774
898
if ($ data ->method === 'auto ' ) {
775
899
$ data ->value = $ this ->craftInt64 ($ data );
@@ -778,7 +902,7 @@ private function prepareCorpusData(stdClass $data, ClientEncryption $clientEncry
778
902
}
779
903
780
904
$ returnData = clone $ data ;
781
- $ returnData ->value = $ this ->encryptCorpusValue ($ data , $ clientEncryption );
905
+ $ returnData ->value = $ this ->encryptCorpusValue ($ fieldName , $ data , $ clientEncryption );
782
906
783
907
return $ data ->allowed ? $ returnData : $ data ;
784
908
}
0 commit comments