def _determine_generation_type(algorithm): """Determines the type based on algorithm.""" if not algorithm: raise sstore.SecretAlgorithmNotSupportedException(algorithm) symmetric_algs = crypto.PluginSupportTypes.SYMMETRIC_ALGORITHMS asymmetric_algs = crypto.PluginSupportTypes.ASYMMETRIC_ALGORITHMS if algorithm.lower() in symmetric_algs: return crypto.PluginSupportTypes.SYMMETRIC_KEY_GENERATION elif algorithm.lower() in asymmetric_algs: return crypto.PluginSupportTypes.ASYMMETRIC_KEY_GENERATION else: raise sstore.SecretAlgorithmNotSupportedException(algorithm)
def generate_asymmetric_key(self, key_spec): """Generate an asymmetric key pair. Creates KMIP attribute objects based on the given KeySpec to send to the server. The KMIP Secret Store currently does not support protecting the private key with a passphrase. :param key_spec: KeySpec with asymmetric algorithm and bit_length :returns: AsymmetricKeyMetadataDTO with the key UUIDs :raises: SecretGeneralException, SecretAlgorithmNotSupportedException KMIPSecretStoreActionNotSupported """ LOG.debug("Starting asymmetric key generation with KMIP plugin") if not self.generate_supports(key_spec): raise ss.SecretAlgorithmNotSupportedException(key_spec.alg) if key_spec.alg.lower() not in ss.KeyAlgorithm.ASYMMETRIC_ALGORITHMS: raise ss.SecretAlgorithmNotSupportedException(key_spec.alg) if key_spec.passphrase: raise KMIPSecretStoreActionNotSupported( u._('KMIP plugin does not currently support protecting the ' 'private key with a passphrase')) algorithm = self._get_kmip_algorithm(key_spec.alg.lower()) length = key_spec.bit_length try: with self.client: LOG.debug("Opened connection to KMIP client for " "asymmetric secret generation") public_uuid, private_uuid = self.client.create_key_pair( algorithm, length) LOG.debug("SUCCESS: Asymmetric key pair generated with " "public key uuid: %(public_uuid)s and " "private key uuid: %(private_uuid)s" % { 'public_uuid': public_uuid, 'private_uuid': private_uuid }) private_key_metadata = {KMIPSecretStore.KEY_UUID: private_uuid} public_key_metadata = {KMIPSecretStore.KEY_UUID: public_uuid} passphrase_metadata = None return ss.AsymmetricKeyMetadataDTO(private_key_metadata, public_key_metadata, passphrase_metadata) except Exception as e: LOG.exception(u._LE("Error opening or writing to client")) raise ss.SecretGeneralException(e)
def store_secret(self, secret_dto): """Stores a secret To store a secret in KMIP, the attributes must be known. :param secret_dto: SecretDTO of the secret to be stored :returns: Dictionary holding the key_uuid assigned by KMIP :raises: SecretGeneralException, SecretAlgorithmNotSupportedException """ LOG.debug("Starting secret storage with KMIP plugin") if not self.store_secret_supports(secret_dto.key_spec): raise ss.SecretAlgorithmNotSupportedException( secret_dto.key_spec.alg) secret_type = secret_dto.type object_type, key_format_type = (self._map_type_ss_to_kmip(secret_type)) if object_type is None: raise KMIPSecretStoreError( u._('Secret object type {object_type} is ' 'not supported').format(object_type=object_type)) secret = self._get_kmip_secret(secret_dto) try: with self.client: LOG.debug("Opened connection to KMIP client") uuid = self.client.register(secret) LOG.debug("SUCCESS: Key stored with uuid: %s", uuid) return {KMIPSecretStore.KEY_UUID: uuid} except Exception as e: LOG.exception(u._LE("Error opening or writing to client")) raise ss.SecretGeneralException(str(e))
def generate_symmetric_key(self, key_spec): """Generate a symmetric key. Creates KMIP attribute objects based on the given KeySpec to send to the server. :param key_spec: KeySpec with symmetric algorithm and bit_length :returns: dictionary holding key_id returned by server :raises: SecretGeneralException, SecretAlgorithmNotSupportedException """ LOG.debug("Starting symmetric key generation with KMIP plugin") if not self.generate_supports(key_spec): raise ss.SecretAlgorithmNotSupportedException(key_spec.alg) if key_spec.alg.lower() not in ss.KeyAlgorithm.SYMMETRIC_ALGORITHMS: raise KMIPSecretStoreError( u._("An unsupported algorithm {algorithm} was passed to the " "'generate_symmetric_key' method").format( algorithm=key_spec.alg)) algorithm = self._get_kmip_algorithm(key_spec.alg) try: with self.client: LOG.debug("Opened connection to KMIP client for secret " + "generation") uuid = self.client.create(algorithm, key_spec.bit_length) LOG.debug("SUCCESS: Symmetric key generated with " "uuid: %s", uuid) return {KMIPSecretStore.KEY_UUID: uuid} except Exception as e: LOG.exception(u._LE("Error opening or writing to client")) raise ss.SecretGeneralException(str(e))
def generate_asymmetric_key(self, key_spec): if not self.generate_supports(key_spec): raise ss.SecretAlgorithmNotSupportedException( key_spec.alg) if key_spec.passphrase: raise ss.GeneratePassphraseNotSupportedException() try: private_id, public_id = self.key_manager.create_key_pair( self.context, key_spec.alg, key_spec.bit_length ) private_key_metadata = self._meta_dict( private_id, key_spec.bit_length, key_spec.alg ) public_key_metadata = self._meta_dict( public_id, key_spec.bit_length, key_spec.alg ) return ss.AsymmetricKeyMetadataDTO( private_key_metadata, public_key_metadata, None ) except Exception as e: LOG.exception("Error generating asymmetric key: {}".format( six.text_type(e))) raise ss.SecretGeneralException(e)
def generate_symmetric_key(self, key_spec, context): """Generate a symmetric key. :param key_spec: KeySpec that contains details on the type of key to generate :param context: StoreCryptoContext for secret :returns: a dictionary that contains metadata about the key """ # Find HSM-style 'crypto' plugin. plugin_type = _determine_generation_type(key_spec.alg) if crypto.PluginSupportTypes.SYMMETRIC_KEY_GENERATION != plugin_type: raise sstore.SecretAlgorithmNotSupportedException(key_spec.alg) generating_plugin = manager.get_manager().get_plugin_store_generate( plugin_type, key_spec.alg, key_spec.bit_length, key_spec.mode) # Find or create a key encryption key metadata. kek_datum_model, kek_meta_dto = _find_or_create_kek_objects( generating_plugin, context.project_model) # Create an encrypted datum instance and add the created cypher text. generate_dto = crypto.GenerateDTO(key_spec.alg, key_spec.bit_length, key_spec.mode, None) # Create the encrypted meta. response_dto = generating_plugin.generate_symmetric( generate_dto, kek_meta_dto, context.project_model.external_id) # Convert binary data into a text-based format. _store_secret_and_datum(context, context.secret_model, kek_datum_model, response_dto) return None
def generate_symmetric_key(self, key_spec): """Generate a symmetric key. Creates KMIP attribute objects based on the given KeySpec to send to the server. :param key_spec: KeySpec with symmetric algorithm and bit_length :returns: dictionary holding key_id returned by server :raises: SecretGeneralException, SecretAlgorithmNotSupportedException """ LOG.debug("Starting symmetric key generation with KMIP plugin") if not self.generate_supports(key_spec): raise ss.SecretAlgorithmNotSupportedException(key_spec.alg) if key_spec.alg.lower() not in ss.KeyAlgorithm.SYMMETRIC_ALGORITHMS: raise KMIPSecretStoreError( u._("An unsupported algorithm {algorithm} was passed to the " "'generate_symmetric_key' method").format( algorithm=key_spec.alg)) object_type = enums.ObjectType.SYMMETRIC_KEY algorithm = self._create_cryptographic_algorithm_attribute( key_spec.alg) usage_mask = self._create_usage_mask_attribute(object_type) length = self._create_cryptographic_length_attribute( key_spec.bit_length) attribute_list = [algorithm, usage_mask, length] template_attribute = TemplateAttribute(attributes=attribute_list) try: self.client.open() LOG.debug("Opened connection to KMIP client for secret " + "generation") result = self.client.create(object_type=object_type, template_attribute=template_attribute, credential=self.credential) except Exception as e: LOG.exception(u._LE("Error opening or writing to client")) raise ss.SecretGeneralException(str(e)) else: if result.result_status.enum == enums.ResultStatus.SUCCESS: LOG.debug("SUCCESS: Symmetric key generated with " "uuid: %s", result.uuid.value) return {KMIPSecretStore.KEY_UUID: result.uuid.value} else: self._raise_secret_general_exception(result) finally: self.client.close() LOG.debug("Closed connection to KMIP client for secret " + "generation")
def generate_asymmetric_key(self, key_spec, context): """Generates an asymmetric key. Returns a AsymmetricKeyMetadataDTO object containing metadata(s) for asymmetric key components. The metadata can be used to retrieve individual components of asymmetric key pair. """ plugin_type = _determine_generation_type(key_spec.alg) if crypto.PluginSupportTypes.ASYMMETRIC_KEY_GENERATION != plugin_type: raise sstore.SecretAlgorithmNotSupportedException(key_spec.alg) generating_plugin = manager.get_manager().get_plugin_store_generate( plugin_type, key_spec.alg, key_spec.bit_length, project_id=context.project_model.id) # Find or create a key encryption key metadata. kek_datum_model, kek_meta_dto = _find_or_create_kek_objects( generating_plugin, context.project_model) generate_dto = crypto.GenerateDTO(key_spec.alg, key_spec.bit_length, None, key_spec.passphrase) # Create the encrypted meta. private_key_dto, public_key_dto, passwd_dto = ( generating_plugin.generate_asymmetric( generate_dto, kek_meta_dto, context.project_model.external_id ) ) _store_secret_and_datum( context, context.private_secret_model, kek_datum_model, private_key_dto) _store_secret_and_datum( context, context.public_secret_model, kek_datum_model, public_key_dto) if key_spec.passphrase and passwd_dto: _store_secret_and_datum( context, context.passphrase_secret_model, kek_datum_model, passwd_dto) return sstore.AsymmetricKeyMetadataDTO()
def store_secret(self, secret_dto): if not self.store_secret_supports(secret_dto.key_spec): raise ss.SecretAlgorithmNotSupportedException( secret_dto.key_spec.alg) try: secret_ref = self.key_manager.store( self.context, opaque_data.OpaqueData(secret_dto.secret) ) return {CastellanSecretStore.KEY_ID: secret_ref} except Exception as e: LOG.exception("Error storing secret: {}".format( six.text_type(e))) raise ss.SecretGeneralException(e)
def generate_symmetric_key(self, key_spec): if not self.generate_supports(key_spec): raise ss.SecretAlgorithmNotSupportedException( key_spec.alg) try: secret_ref = self.key_manager.create_key( self.context, key_spec.alg, key_spec.bit_length ) return {CastellanSecretStore.KEY_ID: secret_ref} except Exception as e: LOG.exception("Error generating symmetric key: {}".format( six.text_type(e))) raise ss.SecretGeneralException(e)
def store_secret(self, secret_dto): if not self.store_secret_supports(secret_dto.key_spec): raise ss.SecretAlgorithmNotSupportedException( secret_dto.key_spec.alg) plaintext = base64.b64decode(secret_dto.secret) try: secret_id = self.key_manager.store( self.context, opaque_data.OpaqueData(plaintext) ) return self._meta_dict(secret_id) except Exception as e: LOG.exception("Error storing secret: {}".format( six.text_type(e))) raise ss.SecretGeneralException(e)
def store_secret(self, secret_dto): """Stores a secret To store a secret in KMIP, the attributes must be known. :param secret_dto: SecretDTO of the secret to be stored :returns: Dictionary holding the key_uuid assigned by KMIP :raises: SecretGeneralException, SecretAlgorithmNotSupportedException """ LOG.debug("Starting secret storage with KMIP plugin") if not self.store_secret_supports(secret_dto.key_spec): raise ss.SecretAlgorithmNotSupportedException( secret_dto.key_spec.alg) secret_type = secret_dto.type object_type, key_format_type = (self._map_type_ss_to_kmip(secret_type)) if object_type is None: raise KMIPSecretStoreError( u._('Secret object type {object_type} is ' 'not supported').format(object_type=object_type)) usage_mask = self._create_usage_mask_attribute(object_type) attribute_list = [usage_mask] template_attribute = TemplateAttribute(attributes=attribute_list) secret = self._get_kmip_secret(secret_dto) try: self.client.open() LOG.debug("Opened connection to KMIP client for secret storage") result = self.client.register( object_type=object_type, template_attribute=template_attribute, secret=secret, credential=self.credential) except Exception as e: LOG.exception(u._LE("Error opening or writing to client")) raise ss.SecretGeneralException(str(e)) else: if result.result_status.enum == enums.ResultStatus.SUCCESS: LOG.debug("SUCCESS: Key stored with uuid: %s", result.uuid.value) return {KMIPSecretStore.KEY_UUID: result.uuid.value} else: self._raise_secret_general_exception(result) finally: self.client.close() LOG.debug("Closed connection to KMIP client for secret storage")
def generate_asymmetric_key(self, key_spec): if not self.generate_supports(key_spec): raise ss.SecretAlgorithmNotSupportedException( key_spec.alg) if key_spec.passphrase: raise ss.GeneratePassphraseNotSupportedException() try: private_ref, public_ref = self.key_manager.create_key_pair( self.context, key_spec.alg, key_spec.bit_length ) private_key_metadata = { CastellanSecretStore.ALG: key_spec.alg, CastellanSecretStore.BIT_LENGTH: key_spec.bit_length, CastellanSecretStore.KEY_ID: private_ref } public_key_metadata = { CastellanSecretStore.ALG: key_spec.alg, CastellanSecretStore.BIT_LENGTH: key_spec.bit_length, CastellanSecretStore.KEY_ID: public_ref } return ss.AsymmetricKeyMetadataDTO( private_key_metadata, public_key_metadata, None ) except Exception as e: LOG.exception("Error generating asymmetric key: {}".format( six.text_type(e))) raise ss.SecretGeneralException(e)
def get_secret(self, secret_type, secret_metadata): """Retrieve a secret from the KRA The secret_metadata is simply the dict returned by a store_secret() or get_secret() call. We will extract the key_id from this dict. Note: There are two ways to retrieve secrets from the KRA. The first method calls retrieve_key without a wrapping key. This relies on the KRA client to generate a wrapping key (and wrap it with the KRA transport cert), and is completely transparent to the Barbican server. What is returned to the caller is the unencrypted secret. The second way is to provide a wrapping key that would be generated on the barbican client. That way only the client will be able to unwrap the secret. This wrapping key is provided in the secret_metadata by Barbican core. Format/Type of the secret returned in the SecretDTO object. ----------------------------------------------------------- The type of the secret returned is always dependent on the way it is stored using the store_secret method. In case of strings - like passphrase/PEM strings, the return will be a string. In case of binary data - the return will be the actual binary data. In case of retrieving an asymmetric key that is generated using the dogtag plugin, then the binary representation of, the asymmetric key in PEM format, is returned """ key_id = secret_metadata[DogtagKRAPlugin.KEY_ID] key_spec = sstore.KeySpec( alg=secret_metadata.get(DogtagKRAPlugin.ALG, None), bit_length=secret_metadata.get(DogtagKRAPlugin.BIT_LENGTH, None), mode=secret_metadata.get(DogtagKRAPlugin.SECRET_MODE, None), passphrase=None) generated = secret_metadata.get(DogtagKRAPlugin.GENERATED, False) passphrase = self._get_passphrase_for_a_private_key( secret_type, secret_metadata, key_spec) recovered_key = None twsk = DogtagKRAPlugin._get_trans_wrapped_session_key( secret_type, secret_metadata) if DogtagKRAPlugin.CONVERT_TO_PEM in secret_metadata: # Case for returning the asymmetric keys generated in KRA. # Asymmetric keys generated in KRA are not generated in PEM format. # This marker DogtagKRAPlugin.CONVERT_TO_PEM is set in the # secret_metadata for asymmetric keys generated in KRA to # help convert the returned private/public keys to PEM format and # eventually return the binary data of the keys in PEM format. if secret_type == sstore.SecretType.PUBLIC: # Public key should be retrieved using the get_key_info method # as it is treated as an attribute of the asymmetric key pair # stored in the KRA database. if key_spec.alg is None: raise sstore.SecretAlgorithmNotSupportedException('None') key_info = self.keyclient.get_key_info(key_id) if key_spec.alg.upper() == key.KeyClient.RSA_ALGORITHM: recovered_key = (RSA.importKey( key_info.public_key).publickey().exportKey('PEM') ).encode('utf-8') elif key_spec.alg.upper() == key.KeyClient.DSA_ALGORITHM: pub_seq = asn1.DerSequence() pub_seq[:] = key_info.public_key recovered_key = (("%s\n%s%s" % (DogtagKRAPlugin.DSA_PUBLIC_KEY_HEADER, pub_seq.encode().encode("base64"), DogtagKRAPlugin.DSA_PUBLIC_KEY_FOOTER) ).encode('utf-8')) else: raise sstore.SecretAlgorithmNotSupportedException( key_spec.alg.upper()) elif secret_type == sstore.SecretType.PRIVATE: key_data = self.keyclient.retrieve_key(key_id) if key_spec.alg.upper() == key.KeyClient.RSA_ALGORITHM: recovered_key = ((RSA.importKey(key_data.data).exportKey( 'PEM', passphrase, 8)).encode('utf-8')) elif key_spec.alg.upper() == key.KeyClient.DSA_ALGORITHM: pub_seq = asn1.DerSequence() pub_seq[:] = key_data.data recovered_key = (("%s\n%s%s" % (DogtagKRAPlugin.DSA_PRIVATE_KEY_HEADER, pub_seq.encode().encode("base64"), DogtagKRAPlugin.DSA_PRIVATE_KEY_FOOTER) ).encode('utf-8')) else: raise sstore.SecretAlgorithmNotSupportedException( key_spec.alg.upper()) else: # TODO(alee-3) send transport key as well when dogtag client API # changes in case the transport key has changed. key_data = self.keyclient.retrieve_key(key_id, twsk) if twsk: # The data returned is a byte array. recovered_key = key_data.encrypted_data else: recovered_key = key_data.data # TODO(alee) remove final field when content_type is removed # from secret_dto if generated: recovered_key = base64.b64encode(recovered_key) ret = sstore.SecretDTO(type=secret_type, secret=recovered_key, key_spec=key_spec, content_type=None, transport_key=None) return ret
def generate_asymmetric_key(self, key_spec): """Generate an asymmetric key pair. Creates KMIP attribute objects based on the given KeySpec to send to the server. The KMIP Secret Store currently does not support protecting the private key with a passphrase. :param key_spec: KeySpec with asymmetric algorithm and bit_length :returns: AsymmetricKeyMetadataDTO with the key UUIDs :raises: SecretGeneralException, SecretAlgorithmNotSupportedException """ LOG.debug("Starting asymmetric key generation with KMIP plugin") if not self.generate_supports(key_spec): raise ss.SecretAlgorithmNotSupportedException(key_spec.alg) if key_spec.alg.lower() not in ss.KeyAlgorithm.ASYMMETRIC_ALGORITHMS: raise KMIPSecretStoreError( u._("An unsupported algorithm {algorithm} was passed to " "the 'generate_asymmetric_key' method").format( algorithm=key_spec.alg)) if key_spec.passphrase: raise KMIPSecretStoreError( u._('KMIP plugin does not currently support protecting the ' 'private key with a passphrase')) algorithm = self._create_cryptographic_algorithm_attribute( key_spec.alg) length = self._create_cryptographic_length_attribute( key_spec.bit_length) attributes = [algorithm, length] common = CommonTemplateAttribute(attributes=attributes) try: self.client.open() LOG.debug("Opened connection to KMIP client for asymmetric " + "secret generation") result = self.client.create_key_pair( common_template_attribute=common, credential=self.credential) except Exception as e: LOG.exception(u._LE("Error opening or writing to client")) raise ss.SecretGeneralException(str(e)) else: if result.result_status.enum == enums.ResultStatus.SUCCESS: LOG.debug( "SUCCESS: Asymmetric key pair generated with " "public key uuid: %s and private key uuid: %s", result.public_key_uuid.value, result.private_key_uuid.value) private_key_metadata = { KMIPSecretStore.KEY_UUID: result.private_key_uuid.value } public_key_metadata = { KMIPSecretStore.KEY_UUID: result.public_key_uuid.value } passphrase_metadata = None return ss.AsymmetricKeyMetadataDTO(private_key_metadata, public_key_metadata, passphrase_metadata) else: self._raise_secret_general_exception(result) finally: self.client.close() LOG.debug("Closed connection to KMIP client for asymmetric " "secret generation")
def store_secret(self, secret_dto): """Stores a secret To store a secret in KMIP, the attributes must be known. :param secret_dto: SecretDTO of the secret to be stored :returns: Dictionary holding the key_uuid assigned by KMIP :raises: SecretGeneralException, SecretAlgorithmNotSupportedException """ LOG.debug("Starting secret storage with KMIP plugin") if not self.store_secret_supports(secret_dto.key_spec): raise ss.SecretAlgorithmNotSupportedException( secret_dto.key_spec.alg) object_type = self._map_type_ss_to_kmip(secret_dto.type) algorithm_value = self._map_algorithm_ss_to_kmip( secret_dto.key_spec.alg) usage_mask = self._create_usage_mask_attribute() attribute_list = [usage_mask] template_attribute = kmip_objects.TemplateAttribute( attributes=attribute_list) secret_features = { 'key_format_type': enums.KeyFormatType.RAW, 'key_value': { 'bytes': self._convert_base64_to_byte_array(secret_dto.secret) }, 'cryptographic_algorithm': algorithm_value, 'cryptographic_length': secret_dto.key_spec.bit_length } secret = secrets.SecretFactory().create_secret(object_type, secret_features) LOG.debug("Created secret object to be stored: %s, %s, %s", secret_features.get('key_format_type'), secret_features.get('cryptographic_algorithm'), secret_features.get('cryptographic_length')) try: self.client.open() LOG.debug("Opened connection to KMIP client for secret storage") result = self.client.register(object_type, template_attribute, secret, self.credential) except Exception as e: LOG.exception(u._LE("Error opening or writing to client")) raise ss.SecretGeneralException(str(e)) else: if result.result_status.enum == enums.ResultStatus.SUCCESS: LOG.debug("SUCCESS: Key stored with uuid: %s", result.uuid.value) return {KMIPSecretStore.KEY_UUID: result.uuid.value} else: self._raise_secret_general_exception(result) finally: self.client.close() LOG.debug("Closed connection to KMIP client for secret storage")