def _get_mocked_kek_meta_dto(self): # For SimpleCryptoPlugin, per-project KEKs are stored in # kek_meta_dto.plugin_meta. SimpleCryptoPlugin does a get-or-create # on the plugin_meta field, so plugin_meta should be None initially. kek_meta_dto = plugin.KEKMetaDTO(mock.MagicMock()) kek_meta_dto.plugin_meta = None return self.plugin.bind_kek_metadata(kek_meta_dto)
def test_bind_kek_metadata_with_existing_key(self): kek_datum = models.KEKDatum() dto = plugin_import.KEKMetaDTO(kek_datum) dto.plugin_meta = '{}' dto = self.plugin.bind_kek_metadata(dto) self.assertEqual(0, self.pkcs11.generate_key.call_count) self.assertEqual(0, self.pkcs11.wrap_key.call_count) self.assertEqual(0, self.pkcs11.compute_hmac.call_count)
def test_bind_kek_metadata_without_existing_key(self): kek_datum = models.KEKDatum() dto = plugin_import.KEKMetaDTO(kek_datum) dto = self.plugin.bind_kek_metadata(dto) self.assertEqual('AES', dto.algorithm) self.assertEqual(256, dto.bit_length) self.assertEqual('CBC', dto.mode) self.assertEqual(2, self.pkcs11.get_key_handle.call_count) self.assertEqual(1, self.pkcs11.generate_key.call_count) self.assertEqual(1, self.pkcs11.wrap_key.call_count) self.assertEqual(1, self.pkcs11.compute_hmac.call_count)
def test_bind_operation(self): kek_meta_dto = base.KEKMetaDTO(self.kek_meta_project_model) self.kek_meta_project_model.bind_completed = False store_crypto._indicate_bind_completed(kek_meta_dto, self.kek_meta_project_model) self.assertTrue(self.kek_meta_project_model.bind_completed) self.assertEqual(self.kek_meta_project_model.algorithm, kek_meta_dto.algorithm) self.assertEqual(self.kek_meta_project_model.bit_length, kek_meta_dto.bit_length) self.assertEqual(self.kek_meta_project_model.mode, kek_meta_dto.mode) self.assertEqual(self.kek_meta_project_model.plugin_meta, kek_meta_dto.plugin_meta)
def get_secret(self, secret_type, metadata, context): """Retrieve a secret. :param secret_type: secret type :param metadata: secret metadata :param context: StoreCryptoContext for secret :returns: SecretDTO that contains secret """ if (not context.secret_model or not context.secret_model.encrypted_data): raise sstore.SecretNotFoundException() # TODO(john-wood-w) Need to revisit 1 to many datum relationship. datum_model = context.secret_model.encrypted_data[0] # Find HSM-style 'crypto' plugin. decrypting_plugin = manager.get_manager().get_plugin_retrieve( datum_model.kek_meta_project.plugin_name) # wrap the KEKDatum instance in our DTO kek_meta_dto = base.KEKMetaDTO(datum_model.kek_meta_project) # Convert from text-based storage format to binary. encrypted = base64.b64decode(datum_model.cypher_text) decrypt_dto = base.DecryptDTO(encrypted) # Decrypt the secret. secret = decrypting_plugin.decrypt(decrypt_dto, kek_meta_dto, datum_model.kek_meta_extended, context.project_model.external_id) secret = base64.b64encode(secret) key_spec = sstore.KeySpec(alg=context.secret_model.algorithm, bit_length=context.secret_model.bit_length, mode=context.secret_model.mode) return sstore.SecretDTO(secret_type, secret, key_spec, datum_model.content_type)
def _find_or_create_kek_objects(plugin_inst, project_model): kek_repo = repositories.get_kek_datum_repository() # Find or create a key encryption key. full_plugin_name = utils.generate_fullname_for(plugin_inst) kek_datum_model = kek_repo.find_or_create_kek_datum( project_model, full_plugin_name) # Bind to the plugin's key management. # TODO(jwood): Does this need to be in a critical section? Should the # bind operation just be declared idempotent in the plugin contract? kek_meta_dto = base.KEKMetaDTO(kek_datum_model) if not kek_datum_model.bind_completed: kek_meta_dto = plugin_inst.bind_kek_metadata(kek_meta_dto) # By contract, enforce that plugins return a # (typically modified) DTO. if kek_meta_dto is None: raise base.CryptoKEKBindingException(full_plugin_name) _indicate_bind_completed(kek_meta_dto, kek_datum_model) kek_repo.save(kek_datum_model) return kek_datum_model, kek_meta_dto