@@ -6,6 +6,7 @@ const log = new DummyRequestLogger();
66const { makeRequest } = require ( '../raw-node/utils/makeRequest' ) ;
77const helpers = require ( './helpers' ) ;
88const scenarios = require ( './scenarios' ) ;
9+ const kms = require ( '../../../lib/kms/wrapper' ) ;
910
1011// copy part of aws-node-sdk/test/object/encryptionHeaders.js and add more tests
1112
@@ -505,3 +506,164 @@ describe('ensure MPU use good SSE', () => {
505506 ) ;
506507 } ) ;
507508} ) ;
509+
510+ describe . only ( 'KMS error' , ( ) => {
511+ const destroyKmsKey = promisify ( kms . destroyBucketKey ) ;
512+ const sseConfig = { algo : 'aws:kms' , masterKeyId : true }
513+ const Bucket = 'bkt-kms-err' ;
514+ const Key = 'obj' ;
515+ const body = 'content' ;
516+
517+ let masterKeyId , masterKeyArn ;
518+ let anotherKeyInfo ;
519+
520+ let expectedErr , expectedMsg ;
521+
522+ const expectedKMIP = {
523+ code : / K M S \. N o t F o u n d E x c e p t i o n / ,
524+ msg : ( action , keyId ) => new RegExp ( `^KMS \\(KMIP\\) error for ${ action } on ${ keyId } \\..*` ) ,
525+ } ;
526+ // localkms container returns a different error message when the key is pending deletion
527+ // as we decrypt without passing the keyId, so we need to handle it separately
528+ const localKms = 'The ciphertext refers to a customer master key that does not exist, ' +
529+ 'does not exist in this region, or you are not allowed to access\\.' ;
530+ const expectedAWS = {
531+ code : / K M S \. K M S I n v a l i d S t a t e E x c e p t i o n | K M S \. A c c e s s D e n i e d E x c e p t i o n / ,
532+ msg : ( _ , keyId ) => new RegExp ( `${ keyId } is pending deletion\\.|${ localKms } ` ) ,
533+ } ;
534+
535+ if ( helpers . config . backends . kms === 'kmip' ) {
536+ ( { code : expectedErr , msg : expectedMsg } = expectedKMIP ) ;
537+ } else if ( helpers . config . backends . kms === 'aws' ) {
538+ ( { code : expectedErr , msg : expectedMsg } = expectedAWS ) ;
539+ } else {
540+ throw new Error ( `Unsupported KMS backend: ${ helpers . config . backends . kms } ` ) ;
541+ }
542+
543+ function assertKmsError ( action , keyId ) {
544+ return err => {
545+ assert . match ( err . name , expectedErr ) ;
546+ assert . match ( err . message , expectedMsg ( action , keyId ) ) ;
547+ return true ;
548+ } ;
549+ }
550+
551+
552+ before ( async ( ) => {
553+ void await helpers . s3 . createBucket ( { Bucket } ) . promise ( ) ;
554+ await helpers . s3 . putObject ( {
555+ ...helpers . putObjParams ( Bucket , 'plaintext' , { } , null ) ,
556+ Body : body ,
557+ } ) . promise ( ) ;
558+
559+ ( { masterKeyId, masterKeyArn } = await helpers . createKmsKey ( log ) ) ;
560+ await helpers . putEncryptedObject ( Bucket , Key , sseConfig , masterKeyArn , body ) ;
561+ // ensure we can decrypt and read the object
562+ const obj = await helpers . s3 . getObject ( { Bucket, Key } ) . promise ( ) ;
563+ assert . strictEqual ( obj . Body . toString ( ) , body ) ;
564+ void await destroyKmsKey ( masterKeyArn , log ) ;
565+ } ) ;
566+
567+ after ( async ( ) => {
568+ void await helpers . cleanup ( Bucket ) ;
569+ if ( masterKeyArn ) {
570+ try {
571+ void await destroyKmsKey ( masterKeyArn , log ) ;
572+ } catch ( e ) { void e ; }
573+ [ masterKeyArn , masterKeyId ] = [ null , null ] ;
574+ }
575+ } ) ;
576+
577+ afterEach ( async ( ) => {
578+ if ( anotherKeyInfo ) {
579+ try {
580+ void await destroyKmsKey ( anotherKeyInfo . masterKeyArn , log ) ;
581+ } catch ( e ) { void e ; }
582+ anotherKeyInfo = null ;
583+ }
584+ } ) ;
585+
586+ it ( 'putObject should fail with kms error' , async ( ) => {
587+ await assert . rejects ( helpers . putEncryptedObject ( Bucket , 'fail' , sseConfig , masterKeyArn , body ) ,
588+ assertKmsError ( 'Encrypt' , masterKeyId ) ) ;
589+ } ) ;
590+
591+ it ( 'getObject should fail with kms error' , async ( ) => {
592+ await assert . rejects ( helpers . s3 . getObject ( { Bucket, Key } ) . promise ( ) ,
593+ assertKmsError ( 'Decrypt' , masterKeyId ) ) ;
594+ } ) ;
595+
596+ it ( 'copyObject should fail with kms error when getting from source' , async ( ) => {
597+ await assert . rejects ( helpers . s3 . copyObject (
598+ { Bucket, Key : 'copy' , CopySource : `${ Bucket } /${ Key } ` } ) . promise ( ) ,
599+ assertKmsError ( 'Decrypt' , masterKeyId )
600+ ) ;
601+ } ) ;
602+
603+ it ( 'copyObject should fail with kms error when putting to destination' , async ( ) => {
604+ await assert . rejects ( helpers . s3 . copyObject (
605+ {
606+ Bucket,
607+ Key : 'copyencrypted' ,
608+ CopySource : `${ Bucket } /plaintext` ,
609+ ServerSideEncryption : 'aws:kms' ,
610+ SSEKMSKeyId : masterKeyArn ,
611+ }
612+ ) . promise ( ) ,
613+ assertKmsError ( 'Encrypt' , masterKeyId ) ) ;
614+ } ) ;
615+
616+ it ( 'createMPU should fail with kms error' , async ( ) => {
617+ const mpuKey = 'mpuKeyEncryptedFail' ;
618+ await assert . rejects ( helpers . s3 . createMultipartUpload (
619+ helpers . putObjParams ( Bucket , mpuKey , sseConfig , masterKeyArn ) ) . promise ( ) ,
620+ assertKmsError ( 'Encrypt' , masterKeyId ) ) ;
621+ } ) ;
622+
623+ it ( 'mpu uploadPartCopy should fail with kms error when getting from source' , async ( ) => {
624+ const mpuKey = 'mpuKey' ;
625+ const mpu = await helpers . s3 . createMultipartUpload (
626+ helpers . putObjParams ( Bucket , mpuKey , { } , null ) ) . promise ( ) ;
627+ await assert . rejects ( helpers . s3 . uploadPartCopy (
628+ {
629+ UploadId : mpu . UploadId ,
630+ Bucket,
631+ Key : mpuKey ,
632+ PartNumber : 1 ,
633+ CopySource : `${ Bucket } /${ Key } ` ,
634+ }
635+ ) . promise ( ) ,
636+ assertKmsError ( 'Decrypt' , masterKeyId ) ) ;
637+ } ) ;
638+
639+ it ( 'mpu uploadPart & copy should fail with kms error when putting to destination' , async ( ) => {
640+ const mpuKey = 'mpuKeyEncrypted' ;
641+ anotherKeyInfo = await helpers . createKmsKey ( log ) ;
642+
643+ const mpu = await helpers . s3 . createMultipartUpload (
644+ helpers . putObjParams ( Bucket , mpuKey , sseConfig , anotherKeyInfo . masterKeyArn ) ) . promise ( ) ;
645+
646+ void await destroyKmsKey ( anotherKeyInfo . masterKeyArn , log ) ;
647+ await assert . rejects ( helpers . s3 . uploadPart (
648+ {
649+ UploadId : mpu . UploadId ,
650+ Bucket,
651+ Key : mpuKey ,
652+ PartNumber : 1 ,
653+ Body : body ,
654+ }
655+ ) . promise ( ) ,
656+ assertKmsError ( 'Encrypt' , anotherKeyInfo . masterKeyId ) ) ;
657+
658+ await assert . rejects ( helpers . s3 . uploadPartCopy (
659+ {
660+ UploadId : mpu . UploadId ,
661+ Bucket,
662+ Key : mpuKey ,
663+ PartNumber : 1 ,
664+ CopySource : `${ Bucket } /plaintext` ,
665+ }
666+ ) . promise ( ) ,
667+ assertKmsError ( 'Encrypt' , anotherKeyInfo . masterKeyId ) ) ;
668+ } ) ;
669+ } ) ;
0 commit comments