def stored_key_side_effect(self, *args, **kwargs): if args[0] == 'PRIVATE': return secret_store.SecretDTO(secret_store.SecretType.PRIVATE, self.private_key_value, None, 'application/octet-string', None) elif args[0] == 'PASSPHRASE': return secret_store.SecretDTO(secret_store.SecretType.PASSPHRASE, self.passphrase_value, None, 'application/octet-string', None) elif args[0] == 'PUBLIC': return secret_store.SecretDTO(secret_store.SecretType.PUBLIC, self.public_key_value, None, 'application/octet-string', None) else: return None
def get_secret(self, secret_metadata, context): """Retrieve a secret. :param secret_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 = crypto.KEKMetaDTO(datum_model.kek_meta_project) # Convert from text-based storage format to binary. encrypted = base64.b64decode(datum_model.cypher_text) decrypt_dto = crypto.DecryptDTO(encrypted) # Decrypt the secret. secret = decrypting_plugin.decrypt(decrypt_dto, kek_meta_dto, datum_model.kek_meta_extended, context.project_model.external_id) key_spec = sstore.KeySpec(alg=context.secret_model.algorithm, bit_length=context.secret_model.bit_length, mode=context.secret_model.mode) return sstore.SecretDTO(sstore.SecretType.SYMMETRIC, secret, key_spec, datum_model.content_type)
def get_certificate_dto(): spec = secret_store.KeySpec(secret_store.KeyAlgorithm.RSA, 2048) return secret_store.SecretDTO(secret_store.SecretType.CERTIFICATE, base64.b64encode( keys.get_certificate_pem()), spec, 'application/pkix-cert')
def get_public_dto(): spec = secret_store.KeySpec(secret_store.KeyAlgorithm.RSA, 2048) return secret_store.SecretDTO(secret_store.SecretType.PUBLIC, base64.b64encode( keys.get_public_key_pem()), spec, 'application/octet-stream')
def get_private_dto(): spec = secret_store.KeySpec(secret_store.KeyAlgorithm.RSA, 2048) return secret_store.SecretDTO(secret_store.SecretType.PRIVATE, base64.b64encode( keys.get_private_key_pem()), spec, 'application/pkcs8')
def test_store_passphrase_secret_assert_called(self): key_spec = secret_store.KeySpec(None, None, None) passphrase = "supersecretpassphrase" secret_dto = secret_store.SecretDTO(secret_store.SecretType.PASSPHRASE, base64.b64encode(passphrase), key_spec, 'content_type', transport_key=None) self.secret_store.store_secret(secret_dto) self.secret_store.client.proxy.register.assert_called_once_with( enums.ObjectType.SECRET_DATA, mock.ANY, mock.ANY) proxy = self.secret_store.client.proxy register_call_args, _ = proxy.register.call_args actual_secret = register_call_args[2] self.assertEqual( None, actual_secret.key_block.cryptographic_length) self.assertEqual( None, actual_secret.key_block.cryptographic_algorithm) self.assertEqual( passphrase, actual_secret.key_block.key_value.key_material.value)
def test_store_asymmetric_key_secret_assert_called(self, barbican_type, barbican_key, kmip_type, kmip_key, pkcs1_only): key_spec = secret_store.KeySpec(secret_store.KeyAlgorithm.RSA, 2048) secret_dto = secret_store.SecretDTO(barbican_type, base64.b64encode(barbican_key), key_spec, 'content_type') self.secret_store.pkcs1_only = pkcs1_only self.secret_store.store_secret(secret_dto) self.secret_store.client.proxy.register.assert_called_once_with( kmip_type, mock.ANY, mock.ANY) proxy = self.secret_store.client.proxy register_call_args, _ = proxy.register.call_args actual_secret = register_call_args[2] self.assertEqual( 2048, actual_secret.key_block.cryptographic_length.value) self.assertEqual( attr.CryptographicAlgorithm(enums.CryptographicAlgorithm.RSA), actual_secret.key_block.cryptographic_algorithm) self.assertEqual( kmip_key, actual_secret.key_block.key_value.key_material.value)
def test_store_asymmetric_key_secret_assert_called(self, barbican_type, barbican_key, kmip_type, kmip_key, pkcs1_only): key_spec = secret_store.KeySpec(secret_store.KeyAlgorithm.RSA, 2048) secret_value = base64.b64encode(barbican_key) secret_dto = secret_store.SecretDTO(barbican_type, secret_value, key_spec, 'content_type') self.secret_store.pkcs1_only = pkcs1_only self.secret_store.store_secret(secret_dto) secret_value = base64.b64decode(secret_value) if not pkcs1_only: secret_value = translations.convert_pem_to_der( secret_value, barbican_type) if kmip_type == enums.ObjectType.PUBLIC_KEY: if pkcs1_only: secret_value = kss.get_public_key_der_pkcs1(secret_value) secret = objects.PublicKey(enums.CryptographicAlgorithm.RSA, 2048, secret_value, enums.KeyFormatType.X_509) else: if pkcs1_only: secret_value = kss.get_private_key_der_pkcs1(secret_value) secret = objects.PrivateKey(enums.CryptographicAlgorithm.RSA, 2048, secret_value, enums.KeyFormatType.PKCS_8) self.secret_store.client.register.assert_called_once_with(secret)
def test_store_symmetric_secret_assert_called(self): key_spec = secret_store.KeySpec(secret_store.KeyAlgorithm.AES, 128, 'mode') sym_key = utils.get_symmetric_key() secret_dto = secret_store.SecretDTO(secret_store.SecretType.SYMMETRIC, sym_key, key_spec, 'content_type', transport_key=None) self.secret_store.store_secret(secret_dto) self.secret_store.client.proxy.register.assert_called_once_with( enums.ObjectType.SYMMETRIC_KEY, mock.ANY, mock.ANY) register_mock = self.secret_store.client.proxy.register register_call_args, _ = register_mock.call_args actual_secret = register_call_args[2] self.assertEqual( 128, actual_secret.key_block.cryptographic_length.value) self.assertEqual( attr.CryptographicAlgorithm(enums.CryptographicAlgorithm.AES), actual_secret.key_block.cryptographic_algorithm) self.assertEqual( base64.b64decode(sym_key), actual_secret.key_block.key_value.key_material.value)
def setUp(self): super(TestSecretStoreBase, self).setUp() self.patchers = [] # List of patchers utilized in this test class. self.project_id = '12345' self.content_type = 'application/octet-stream' self.content_encoding = 'base64' self.secret = base64.b64encode(b'secret') self.decrypted_secret = b'decrypted_secret' self.cypher_text = b'cypher_text' self.kek_meta_extended = 'kek-meta-extended' self.spec_aes = secret_store.KeySpec('AES', 64, 'CBC') self.spec_rsa = secret_store.KeySpec('RSA', 1024, passphrase='changeit') self.project_model = mock.MagicMock() self.project_model.id = 'project-model-id' self.project_model.external_id = self.project_id self.secret_dto = secret_store.SecretDTO( secret_store.SecretType.OPAQUE, self.secret, secret_store.KeySpec(), self.content_type) self.response_dto = base.ResponseDTO( self.cypher_text, kek_meta_extended=self.kek_meta_extended) self.private_key_dto = base.ResponseDTO(self.cypher_text) self.public_key_dto = base.ResponseDTO(self.cypher_text) self.passphrase_dto = base.ResponseDTO(self.cypher_text) self.kek_meta_project_model = models.KEKDatum() self.kek_meta_project_model.plugin_name = 'plugin-name' self.kek_meta_project_model.kek_label = 'kek-meta-label' self.kek_meta_project_model.algorithm = 'kek-meta-algo' self.kek_meta_project_model.bit_length = 1024 self.kek_meta_project_model.mode = 'kek=meta-mode' self.kek_meta_project_model.plugin_meta = 'kek-meta-plugin-meta' self.encrypted_datum_model = models.EncryptedDatum() self.encrypted_datum_model.kek_meta_project = ( self.kek_meta_project_model) self.encrypted_datum_model.cypher_text = base64.b64encode( b'cypher_text') self.encrypted_datum_model.content_type = 'content_type' self.encrypted_datum_model.kek_meta_extended = 'extended_meta' self.secret_model = models.Secret({ 'algorithm': 'myalg', 'bit_length': 1024, 'mode': 'mymode' }) self.secret_model.id = 'secret-model-id' self.secret_model.encrypted_data = [self.encrypted_datum_model] self.context = store_crypto.StoreCryptoContext( secret_model=self.secret_model, project_model=self.project_model, content_type=self.content_type)
def test_store_certificate_secret_return_value(self): key_spec = secret_store.KeySpec(secret_store.KeyAlgorithm.RSA, 2048) secret_dto = secret_store.SecretDTO( secret_store.SecretType.CERTIFICATE, base64.b64encode(keys.get_certificate_pem()), key_spec, 'content_type') return_value = self.secret_store.store_secret(secret_dto) expected = {kss.KMIPSecretStore.KEY_UUID: 'uuid'} self.assertEqual(expected, return_value)
def test_store_secret_with_tkey_id(self): payload = 'data wrapped in PKIArchiveOptions object' key_spec = mock.MagicMock() content_type = mock.MagicMock() transport_key = mock.MagicMock() secret_dto = sstore.SecretDTO(sstore.SecretType.SYMMETRIC, payload, key_spec, content_type, transport_key) self.plugin.store_secret(secret_dto) self.keyclient_mock.archive_pki_options.assert_called_once_with( mock.ANY, "passPhrase", payload, key_algorithm=None, key_size=None)
def test_store_secret(self): payload = 'encrypt me!!' key_spec = mock.MagicMock() content_type = mock.MagicMock() transport_key = None secret_dto = sstore.SecretDTO(sstore.SecretType.SYMMETRIC, payload, key_spec, content_type, transport_key) self.plugin.store_secret(secret_dto) self.keyclient_mock.archive_key.assert_called_once_with( mock.ANY, "passPhrase", payload, key_algorithm=None, key_size=None)
def test_store_secret_valid_algorithm_invalid_bit_length(self): key_spec = secret_store.KeySpec(secret_store.KeyAlgorithm.AES, 56, 'mode') secret_dto = secret_store.SecretDTO(secret_store.SecretType.SYMMETRIC, "AAAA", key_spec, 'content_type', transport_key=None) self.assertRaises(secret_store.SecretAlgorithmNotSupportedException, self.secret_store.store_secret, secret_dto)
def store_secret(unencrypted_raw, content_type_raw, content_encoding, secret_model, project_model, transport_key_needed=False, transport_key_id=None): """Store a provided secret into secure backend.""" if _secret_already_has_stored_data(secret_model): raise ValueError('Secret already has encrypted data stored for it.') # Create a KeySpec to find a plugin that will support storing the secret key_spec = secret_store.KeySpec(alg=secret_model.algorithm, bit_length=secret_model.bit_length, mode=secret_model.mode) # If there is no secret data to store, then just create Secret entity and # leave. A subsequent call to this method should provide both the Secret # entity created here *and* the secret data to store into it. if not unencrypted_raw: key_model = _get_transport_key_model(key_spec, transport_key_needed, project_id=project_model.id) _save_secret_in_repo(secret_model, project_model) return secret_model, key_model plugin_name, transport_key = _get_plugin_name_and_transport_key( transport_key_id) unencrypted, content_type = tr.normalize_before_encryption( unencrypted_raw, content_type_raw, content_encoding, secret_model.secret_type, enforce_text_only=True) plugin_manager = secret_store.get_manager() store_plugin = plugin_manager.get_plugin_store(key_spec=key_spec, plugin_name=plugin_name, project_id=project_model.id) secret_dto = secret_store.SecretDTO(type=secret_model.secret_type, secret=unencrypted, key_spec=key_spec, content_type=content_type, transport_key=transport_key) secret_metadata = _store_secret_using_plugin(store_plugin, secret_dto, secret_model, project_model) _save_secret_in_repo(secret_model, project_model) _save_secret_metadata_in_repo(secret_model, secret_metadata, store_plugin, content_type) return secret_model, None
def test_store_secret_raises_exception(self): payload = 'encrypt me!!' key_spec = mock.MagicMock() content_type = mock.MagicMock() transport_key = None secret_dto = ss.SecretDTO(ss.SecretType.SYMMETRIC, payload, key_spec, content_type, transport_key) self.plugin.key_manager.store.side_effect = exception.Forbidden() self.assertRaises(ss.SecretGeneralException, self.plugin.store_secret, secret_dto)
def test_store_secret_assert_called(self): key_spec = secret_store.KeySpec(secret_store.KeyAlgorithm.AES, 128, 'mode') secret_dto = secret_store.SecretDTO(secret_store.SecretType.SYMMETRIC, "AAAA", key_spec, 'content_type', transport_key=None) self.secret_store.store_secret(secret_dto) self.kmipclient_mock.register.assert_called_once_with( enums.ObjectType.SYMMETRIC_KEY, mock.ANY, mock.ANY, self.credential)
def test_store_passphrase_secret_assert_called(self): key_spec = secret_store.KeySpec(None, None, None) passphrase = base64.b64encode(b"supersecretpassphrase") secret_dto = secret_store.SecretDTO(secret_store.SecretType.PASSPHRASE, passphrase, key_spec, 'content_type', transport_key=None) self.secret_store.store_secret(secret_dto) self.secret_store.client.register.assert_called_once_with( objects.SecretData(base64.b64decode(passphrase), enums.SecretDataType.PASSWORD))
def test_store_passphrase_secret_return_value(self): key_spec = secret_store.KeySpec(None, None, None) passphrase = b"supersecretpassphrase" secret_dto = secret_store.SecretDTO(secret_store.SecretType.PASSPHRASE, base64.b64encode(passphrase), key_spec, 'content_type', transport_key=None) return_value = self.secret_store.store_secret(secret_dto) expected = {kss.KMIPSecretStore.KEY_UUID: 'uuid'} self.assertEqual(expected, return_value)
def test_store_secret_return_value(self): key_spec = secret_store.KeySpec(secret_store.KeyAlgorithm.AES, 128, 'mode') secret_dto = secret_store.SecretDTO(secret_store.SecretType.SYMMETRIC, "AAAA", key_spec, 'content_type', transport_key=None) return_value = self.secret_store.store_secret(secret_dto) expected = {kss.KMIPSecretStore.KEY_UUID: 'uuid'} self.assertEqual(0, cmp(expected, return_value))
def test_store_asymmetric_key_secret_return_value(self, barbican_type, barbican_key, pkcs1_only): key_spec = secret_store.KeySpec(secret_store.KeyAlgorithm.RSA, 2048) secret_dto = secret_store.SecretDTO(barbican_type, base64.b64encode(barbican_key), key_spec, 'content_type') self.secret_store.pkcs1_only = pkcs1_only return_value = self.secret_store.store_secret(secret_dto) expected = {kss.KMIPSecretStore.KEY_UUID: 'uuid'} self.assertEqual(expected, return_value)
def test_store_opaque_secret_return_value(self): key_spec = secret_store.KeySpec(None, None, None) opaque = b'\x00\x01\x02\x03\x04\x05\x06\x07' secret_dto = secret_store.SecretDTO(secret_store.SecretType.OPAQUE, base64.b64encode(opaque), key_spec, 'content_type', transport_key=None) return_value = self.secret_store.store_secret(secret_dto) expected = {kss.KMIPSecretStore.KEY_UUID: 'uuid'} self.assertEqual(expected, return_value)
def test_store_opaque_secret_assert_called(self): key_spec = secret_store.KeySpec(None, None, None) opaque = base64.b64encode(b'\x00\x01\x02\x03\x04\x05\x06\x07') secret_dto = secret_store.SecretDTO(secret_store.SecretType.OPAQUE, opaque, key_spec, 'content_type', transport_key=None) self.secret_store.store_secret(secret_dto) self.secret_store.client.register.assert_called_once_with( objects.OpaqueObject(base64.b64decode(opaque), enums.OpaqueDataType.NONE))
def get_secret(self, secret_type, secret_metadata): secret_ref = secret_metadata[CastellanSecretStore.KEY_ID] try: secret = self.key_manager.get( self.context, secret_ref) return ss.SecretDTO(secret_type, secret.get_encoded(), ss.KeySpec(), secret_metadata['content_type']) except Exception as e: LOG.exception("Error retrieving secret {}: {}".format( secret_ref, six.text_type(e))) raise ss.SecretGeneralException(e)
def test_store_certificate_secret_assert_called(self, algorithm, bit_length): key_spec = secret_store.KeySpec(algorithm, bit_length) certificate_value = base64.b64encode(keys.get_certificate_pem()) secret_dto = secret_store.SecretDTO( secret_store.SecretType.CERTIFICATE, certificate_value, key_spec, 'content_type') self.secret_store.store_secret(secret_dto) self.secret_store.client.register.assert_called_once_with( objects.X509Certificate( translations.convert_pem_to_der( base64.b64decode(certificate_value), secret_store.SecretType.CERTIFICATE)))
def test_store_secret_error_opening_connection(self): self.secret_store.client.open = mock.Mock(side_effect=socket.error) key_spec = secret_store.KeySpec(secret_store.KeyAlgorithm.AES, 128, 'mode') secret_dto = secret_store.SecretDTO(secret_store.SecretType.SYMMETRIC, "AAAA", key_spec, 'content_type', transport_key=None) self.assertRaises(secret_store.SecretGeneralException, self.secret_store.store_secret, secret_dto)
def test_store_secret_error_opening_connection(self): self.secret_store.client.open.side_effect = Exception key_spec = secret_store.KeySpec(secret_store.KeyAlgorithm.AES, 128, 'mode') secret_dto = secret_store.SecretDTO(secret_store.SecretType.SYMMETRIC, utils.get_symmetric_key(), key_spec, 'content_type', transport_key=None) self.assertRaises(secret_store.SecretGeneralException, self.secret_store.store_secret, secret_dto)
def test_store_symmetric_secret_assert_called(self): key_spec = secret_store.KeySpec(secret_store.KeyAlgorithm.AES, 128, 'mode') sym_key = utils.get_symmetric_key() secret_dto = secret_store.SecretDTO(secret_store.SecretType.SYMMETRIC, sym_key, key_spec, 'content_type', transport_key=None) self.secret_store.store_secret(secret_dto) self.secret_store.client.register.assert_called_once_with( objects.SymmetricKey(enums.CryptographicAlgorithm.AES, 128, base64.b64decode(utils.get_symmetric_key())))
def test_store_secret(self): payload = 'encrypt me!!' key_spec = mock.MagicMock() content_type = mock.MagicMock() transport_key = None secret_dto = ss.SecretDTO(ss.SecretType.SYMMETRIC, payload, key_spec, content_type, transport_key) response = self.plugin.store_secret(secret_dto) data = opaque_data.OpaqueData(secret_dto.secret) self.plugin.key_manager.store.assert_called_once_with(mock.ANY, data) expected_response = {css.CastellanSecretStore.KEY_ID: key_ref1} self.assertEqual(response, expected_response)
def _get_barbican_secret(self, result, secret_type): object_type = result.object_type.value if object_type == enums.ObjectType.CERTIFICATE.value: certificate = result.secret secret_value = certificate.certificate_value.value key_spec = ss.KeySpec() elif object_type == enums.ObjectType.OPAQUE_DATA.value: opaque_secret = result.secret secret_value = opaque_secret.opaque_data_value.value key_spec = ss.KeySpec() elif (object_type == enums.ObjectType.SYMMETRIC_KEY.value or object_type == enums.ObjectType.PRIVATE_KEY.value or object_type == enums.ObjectType.PUBLIC_KEY.value or object_type == enums.ObjectType.SECRET_DATA.value): secret_block = result.secret.key_block key_value_type = type(secret_block.key_value.key_material) if (key_value_type == KeyMaterialStruct or key_value_type == KeyMaterial): secret_value = secret_block.key_value.key_material.value else: msg = u._( "Unknown key value type received from KMIP " "server, expected {key_value_struct} or " "{key_value_string}, received: {key_value_type}").format( key_value_struct=KeyValue, key_value_string=KeyMaterial, key_value_type=key_value_type) LOG.exception(msg) raise ss.SecretGeneralException(msg) if secret_block.cryptographic_algorithm: secret_alg = self._map_algorithm_kmip_to_ss( secret_block.cryptographic_algorithm.value) else: secret_alg = None if secret_block.cryptographic_length: secret_bit_length = secret_block.cryptographic_length.value else: secret_bit_length = None key_spec = ss.KeySpec(secret_alg, secret_bit_length), secret_value = self._denormalize_secret(secret_value, secret_type) secret_dto = ss.SecretDTO(secret_type, secret_value, key_spec, content_type=None, transport_key=None) return secret_dto