github.com/aavshr/aws-sdk-go@v1.41.3/service/s3/s3crypto/kms_key_handler.go (about)

     1  package s3crypto
     2  
     3  import (
     4  	"github.com/aavshr/aws-sdk-go/aws"
     5  	"github.com/aavshr/aws-sdk-go/aws/awserr"
     6  	"github.com/aavshr/aws-sdk-go/service/kms"
     7  	"github.com/aavshr/aws-sdk-go/service/kms/kmsiface"
     8  )
     9  
    10  const (
    11  	// KMSWrap is a constant used during decryption to build a KMS key handler.
    12  	KMSWrap = "kms"
    13  )
    14  
    15  // kmsKeyHandler will make calls to KMS to get the masterkey
    16  type kmsKeyHandler struct {
    17  	kms   kmsiface.KMSAPI
    18  	cmkID *string
    19  
    20  	// useProvidedCMK is toggled when using `kms` key wrapper with V2 client
    21  	useProvidedCMK bool
    22  
    23  	CipherData
    24  }
    25  
    26  // NewKMSKeyGenerator builds a new KMS key provider using the customer key ID and material
    27  // description.
    28  //
    29  // Example:
    30  //	sess := session.Must(session.NewSession())
    31  //	cmkID := "arn to key"
    32  //	matdesc := s3crypto.MaterialDescription{}
    33  //	handler := s3crypto.NewKMSKeyGenerator(kms.New(sess), cmkID)
    34  //
    35  // deprecated: This feature is in maintenance mode, no new updates will be released. Please see https://docs.aws.amazon.com/general/latest/gr/aws_sdk_cryptography.html for more information.
    36  func NewKMSKeyGenerator(kmsClient kmsiface.KMSAPI, cmkID string) CipherDataGenerator {
    37  	return NewKMSKeyGeneratorWithMatDesc(kmsClient, cmkID, MaterialDescription{})
    38  }
    39  
    40  func newKMSKeyHandler(client kmsiface.KMSAPI, cmkID string, matdesc MaterialDescription) *kmsKeyHandler {
    41  	// These values are read only making them thread safe
    42  	kp := &kmsKeyHandler{
    43  		kms:   client,
    44  		cmkID: &cmkID,
    45  	}
    46  
    47  	if matdesc == nil {
    48  		matdesc = MaterialDescription{}
    49  	}
    50  
    51  	matdesc["kms_cmk_id"] = &cmkID
    52  
    53  	kp.CipherData.WrapAlgorithm = KMSWrap
    54  	kp.CipherData.MaterialDescription = matdesc
    55  
    56  	return kp
    57  }
    58  
    59  // NewKMSKeyGeneratorWithMatDesc builds a new KMS key provider using the customer key ID and material
    60  // description.
    61  //
    62  // Example:
    63  //	sess := session.Must(session.NewSession())
    64  //	cmkID := "arn to key"
    65  //	matdesc := s3crypto.MaterialDescription{}
    66  //	handler := s3crypto.NewKMSKeyGeneratorWithMatDesc(kms.New(sess), cmkID, matdesc)
    67  //
    68  // deprecated: This feature is in maintenance mode, no new updates will be released. Please see https://docs.aws.amazon.com/general/latest/gr/aws_sdk_cryptography.html for more information.
    69  func NewKMSKeyGeneratorWithMatDesc(kmsClient kmsiface.KMSAPI, cmkID string, matdesc MaterialDescription) CipherDataGenerator {
    70  	return newKMSKeyHandler(kmsClient, cmkID, matdesc)
    71  }
    72  
    73  // NewKMSWrapEntry builds returns a new KMS key provider and its decrypt handler.
    74  //
    75  // Example:
    76  //	sess := session.Must(session.NewSession())
    77  //	customKMSClient := kms.New(sess)
    78  //	decryptHandler := s3crypto.NewKMSWrapEntry(customKMSClient)
    79  //
    80  //	svc := s3crypto.NewDecryptionClient(sess, func(svc *s3crypto.DecryptionClient) {
    81  //		svc.WrapRegistry[s3crypto.KMSWrap] = decryptHandler
    82  //	}))
    83  //
    84  // deprecated: This feature is in maintenance mode, no new updates will be released. Please see https://docs.aws.amazon.com/general/latest/gr/aws_sdk_cryptography.html for more information.
    85  func NewKMSWrapEntry(kmsClient kmsiface.KMSAPI) WrapEntry {
    86  	kp := newKMSWrapEntry(kmsClient)
    87  	return kp.decryptHandler
    88  }
    89  
    90  // RegisterKMSWrapWithCMK registers the `kms` wrapping algorithm to the given WrapRegistry. The wrapper will be
    91  // configured to call KMS Decrypt with the provided CMK.
    92  //
    93  // Example:
    94  //	sess := session.Must(session.NewSession())
    95  //	cr := s3crypto.NewCryptoRegistry()
    96  //	if err := s3crypto.RegisterKMSWrapWithCMK(cr, kms.New(sess), "cmkId"); err != nil {
    97  //		panic(err) // handle error
    98  //	}
    99  //
   100  // deprecated: This feature is in maintenance mode, no new updates will be released. Please see https://docs.aws.amazon.com/general/latest/gr/aws_sdk_cryptography.html for more information.
   101  func RegisterKMSWrapWithCMK(registry *CryptoRegistry, client kmsiface.KMSAPI, cmkID string) error {
   102  	if registry == nil {
   103  		return errNilCryptoRegistry
   104  	}
   105  	return registry.AddWrap(KMSWrap, newKMSWrapEntryWithCMK(client, cmkID))
   106  }
   107  
   108  // RegisterKMSWrapWithAnyCMK registers the `kms` wrapping algorithm to the given WrapRegistry. The wrapper will be
   109  // configured to call KMS Decrypt without providing a CMK.
   110  //
   111  // Example:
   112  //	sess := session.Must(session.NewSession())
   113  //	cr := s3crypto.NewCryptoRegistry()
   114  //	if err := s3crypto.RegisterKMSWrapWithAnyCMK(cr, kms.New(sess)); err != nil {
   115  //		panic(err) // handle error
   116  //	}
   117  //
   118  // deprecated: This feature is in maintenance mode, no new updates will be released. Please see https://docs.aws.amazon.com/general/latest/gr/aws_sdk_cryptography.html for more information.
   119  func RegisterKMSWrapWithAnyCMK(registry *CryptoRegistry, client kmsiface.KMSAPI) error {
   120  	if registry == nil {
   121  		return errNilCryptoRegistry
   122  	}
   123  	return registry.AddWrap(KMSWrap, NewKMSWrapEntry(client))
   124  }
   125  
   126  // newKMSWrapEntryWithCMK builds returns a new KMS key provider and its decrypt handler. The wrap entry will be configured
   127  // to only attempt to decrypt the data key using the provided CMK.
   128  func newKMSWrapEntryWithCMK(kmsClient kmsiface.KMSAPI, cmkID string) WrapEntry {
   129  	kp := newKMSWrapEntry(kmsClient)
   130  	kp.useProvidedCMK = true
   131  	kp.cmkID = &cmkID
   132  	return kp.decryptHandler
   133  }
   134  
   135  func newKMSWrapEntry(kmsClient kmsiface.KMSAPI) *kmsKeyHandler {
   136  	// These values are read only making them thread safe
   137  	kp := &kmsKeyHandler{
   138  		kms: kmsClient,
   139  	}
   140  
   141  	return kp
   142  }
   143  
   144  // decryptHandler initializes a KMS keyprovider with a material description. This
   145  // is used with Decrypting kms content, due to the cmkID being in the material description.
   146  func (kp kmsKeyHandler) decryptHandler(env Envelope) (CipherDataDecrypter, error) {
   147  	m := MaterialDescription{}
   148  	err := m.decodeDescription([]byte(env.MatDesc))
   149  	if err != nil {
   150  		return nil, err
   151  	}
   152  
   153  	_, ok := m["kms_cmk_id"]
   154  	if !ok {
   155  		return nil, awserr.New("MissingCMKIDError", "Material description is missing CMK ID", nil)
   156  	}
   157  
   158  	kp.CipherData.MaterialDescription = m
   159  	kp.WrapAlgorithm = KMSWrap
   160  
   161  	return &kp, nil
   162  }
   163  
   164  // DecryptKey makes a call to KMS to decrypt the key.
   165  func (kp *kmsKeyHandler) DecryptKey(key []byte) ([]byte, error) {
   166  	return kp.DecryptKeyWithContext(aws.BackgroundContext(), key)
   167  }
   168  
   169  // DecryptKeyWithContext makes a call to KMS to decrypt the key with request context.
   170  func (kp *kmsKeyHandler) DecryptKeyWithContext(ctx aws.Context, key []byte) ([]byte, error) {
   171  	in := &kms.DecryptInput{
   172  		EncryptionContext: kp.MaterialDescription,
   173  		CiphertextBlob:    key,
   174  		GrantTokens:       []*string{},
   175  	}
   176  
   177  	// useProvidedCMK will be true if a constructor was used with the new V2 client
   178  	if kp.useProvidedCMK {
   179  		in.KeyId = kp.cmkID
   180  	}
   181  
   182  	out, err := kp.kms.DecryptWithContext(ctx, in)
   183  	if err != nil {
   184  		return nil, err
   185  	}
   186  	return out.Plaintext, nil
   187  }
   188  
   189  // GenerateCipherData makes a call to KMS to generate a data key, Upon making
   190  // the call, it also sets the encrypted key.
   191  func (kp *kmsKeyHandler) GenerateCipherData(keySize, ivSize int) (CipherData, error) {
   192  	return kp.GenerateCipherDataWithContext(aws.BackgroundContext(), keySize, ivSize)
   193  }
   194  
   195  // GenerateCipherDataWithContext makes a call to KMS to generate a data key,
   196  // Upon making the call, it also sets the encrypted key.
   197  func (kp *kmsKeyHandler) GenerateCipherDataWithContext(ctx aws.Context, keySize, ivSize int) (CipherData, error) {
   198  	cd := kp.CipherData.Clone()
   199  
   200  	out, err := kp.kms.GenerateDataKeyWithContext(ctx,
   201  		&kms.GenerateDataKeyInput{
   202  			EncryptionContext: cd.MaterialDescription,
   203  			KeyId:             kp.cmkID,
   204  			KeySpec:           aws.String("AES_256"),
   205  		})
   206  	if err != nil {
   207  		return CipherData{}, err
   208  	}
   209  
   210  	iv, err := generateBytes(ivSize)
   211  	if err != nil {
   212  		return CipherData{}, err
   213  	}
   214  
   215  	cd.Key = out.Plaintext
   216  	cd.IV = iv
   217  	cd.EncryptedKey = out.CiphertextBlob
   218  
   219  	return cd, nil
   220  }
   221  
   222  func (kp kmsKeyHandler) isAWSFixture() bool {
   223  	return true
   224  }
   225  
   226  var (
   227  	_ CipherDataGenerator            = (*kmsKeyHandler)(nil)
   228  	_ CipherDataGeneratorWithContext = (*kmsKeyHandler)(nil)
   229  	_ CipherDataDecrypter            = (*kmsKeyHandler)(nil)
   230  	_ CipherDataDecrypterWithContext = (*kmsKeyHandler)(nil)
   231  	_ awsFixture                     = (*kmsKeyHandler)(nil)
   232  )