def verify_signature(context, checksum_hash, image_properties): """Retrieve the image properties and use them to verify the signature. :param context: the user context for authentication :param checksum_hash: the 'checksum' hash of the image data :param image_properties: the key-value properties about the image :returns: True if verification succeeds :raises glance.common.exception.SignatureVerificationError: if verification fails """ if not should_verify_signature(image_properties): raise exception.SignatureVerificationError( _('Required image properties for signature verification do not' ' exist. Cannot verify signature.')) checksum_hash = encodeutils.to_utf8(checksum_hash) signature = get_signature(image_properties[OLD_SIGNATURE]) hash_method = get_hash_method(image_properties[OLD_HASH_METHOD]) signature_key_type = SignatureKeyType.lookup( image_properties[OLD_KEY_TYPE]) public_key = get_public_key(context, image_properties[OLD_CERT_UUID], signature_key_type) # create the verifier based on the signature key type try: verifier = signature_key_type.create_verifier(signature, hash_method, public_key, image_properties) except crypto_exception.UnsupportedAlgorithm as e: msg = (_LE("Unable to create verifier since algorithm is " "unsupported: %(e)s") % { 'e': encodeutils.exception_to_unicode(e) }) LOG.error(msg) raise exception.SignatureVerificationError( _('Unable to verify signature since the algorithm is unsupported ' 'on this system')) if verifier: # Verify the signature verifier.update(checksum_hash) try: verifier.verify() return True except crypto_exception.InvalidSignature: raise exception.SignatureVerificationError( _('Signature verification failed.')) else: # Error creating the verifier raise exception.SignatureVerificationError( _('Error occurred while verifying the signature'))
def get_public_key(context, signature_certificate_uuid, signature_key_type): """Create the public key object from a retrieved certificate. :param context: the user context for authentication :param signature_certificate_uuid: the uuid to use to retrieve the certificate :param signature_key_type: a SignatureKeyType object :returns: the public key cryptography object :raises glance.common.exception.SignatureVerificationError: if public key format is invalid """ certificate = get_certificate(context, signature_certificate_uuid) # Note that this public key could either be # RSAPublicKey, DSAPublicKey, or EllipticCurvePublicKey public_key = certificate.public_key() # Confirm the type is of the type expected based on the signature key type if not isinstance(public_key, signature_key_type.public_key_type): raise exception.SignatureVerificationError( _('Invalid public key type for signature key type: %s') % signature_key_type ) return public_key
def fake_old_verify_signature(context, checksum_hash, image_properties): if (image_properties is not None and 'signature' in image_properties and image_properties['signature'] == 'VALID'): return True else: raise exception.SignatureVerificationError( 'Signature verification failed.')
def get_certificate(context, signature_certificate_uuid): """Create the certificate object from the retrieved certificate data. :param context: the user context for authentication :param signature_certificate_uuid: the uuid to use to retrieve the certificate :returns: the certificate cryptography object :raises glance.common.exception.SignatureVerificationError: if the retrieval fails or the format is invalid """ keymgr_api = key_manager.API() try: # The certificate retrieved here is a castellan certificate object cert = keymgr_api.get(context, signature_certificate_uuid) except Exception as e: # The problem encountered may be backend-specific, since castellan # can use different backends. Rather than importing all possible # backends here, the generic "Exception" is used. msg = (_LE("Unable to retrieve certificate with ID %(id)s: %(e)s") % {'id': signature_certificate_uuid, 'e': encodeutils.exception_to_unicode(e)}) LOG.error(msg) raise exception.SignatureVerificationError( _('Unable to retrieve certificate with ID: %s') % signature_certificate_uuid ) if cert.format not in CERTIFICATE_FORMATS: raise exception.SignatureVerificationError( _('Invalid certificate format: %s') % cert.format ) if cert.format == X_509: # castellan always encodes certificates in DER format cert_data = cert.get_encoded() certificate = x509.load_der_x509_certificate(cert_data, default_backend()) else: raise exception.SignatureVerificationError( _('Certificate format not supported: %s') % cert.format ) # verify the certificate verify_certificate(certificate) return certificate
def get_verifier(context, image_properties): """Retrieve the image properties and use them to create a verifier. :param context: the user context for authentication :param image_properties: the key-value properties about the image :return: instance of cryptography AsymmetricVerificationContext :raises glance.common.exception.SignatureVerificationError: if building the verifier fails """ if not should_create_verifier(image_properties): raise exception.SignatureVerificationError( _('Required image properties for signature verification do not' ' exist. Cannot verify signature.') ) signature = get_signature(image_properties[SIGNATURE]) hash_method = get_hash_method(image_properties[HASH_METHOD]) signature_key_type = SignatureKeyType.lookup( image_properties[KEY_TYPE]) public_key = get_public_key(context, image_properties[CERT_UUID], signature_key_type) # create the verifier based on the signature key type try: verifier = signature_key_type.create_verifier(signature, hash_method, public_key, image_properties) except crypto_exception.UnsupportedAlgorithm as e: msg = (_LE("Unable to create verifier since algorithm is " "unsupported: %(e)s") % {'e': encodeutils.exception_to_unicode(e)}) LOG.error(msg) raise exception.SignatureVerificationError( _('Unable to verify signature since the algorithm is unsupported ' 'on this system') ) if verifier: return verifier else: # Error creating the verifier raise exception.SignatureVerificationError( _('Error occurred while creating the verifier') )
def verify_certificate(certificate): """Verify that the certificate has not expired. :param certificate: the cryptography certificate object :raises glance.common.exception.SignatureVerificationError: if the certificate valid time range does not include now """ # Get now in UTC, since certificate returns times in UTC now = datetime.datetime.utcnow() # Confirm the certificate valid time range includes now if now < certificate.not_valid_before: raise exception.SignatureVerificationError( _('Certificate is not valid before: %s UTC') % certificate.not_valid_before) elif now > certificate.not_valid_after: raise exception.SignatureVerificationError( _('Certificate is not valid after: %s UTC') % certificate.not_valid_after)
def create_verifier_for_pss(signature, hash_method, public_key, image_properties): """Create the verifier to use when the key type is RSA-PSS. :param signature: the decoded signature to use :param hash_method: the hash method to use, as a cryptography object :param public_key: the public key to use, as a cryptography object :param image_properties: the key-value properties about the image :returns: the verifier to use to verify the signature for RSA-PSS :raises glance.common.exception.SignatureVerificationError: if the RSA-PSS specific properties are invalid """ # retrieve other needed properties, or use defaults if not there if MASK_GEN_ALG in image_properties: mask_gen_algorithm = image_properties[MASK_GEN_ALG] if mask_gen_algorithm not in MASK_GEN_ALGORITHMS: raise exception.SignatureVerificationError( _('Invalid mask_gen_algorithm: %s') % mask_gen_algorithm ) mgf = MASK_GEN_ALGORITHMS[mask_gen_algorithm](hash_method) else: # default to MGF1 mgf = padding.MGF1(hash_method) if PSS_SALT_LENGTH in image_properties: pss_salt_length = image_properties[PSS_SALT_LENGTH] try: salt_length = int(pss_salt_length) except ValueError: raise exception.SignatureVerificationError( _('Invalid pss_salt_length: %s') % pss_salt_length ) else: # default to max salt length salt_length = padding.PSS.MAX_LENGTH # return the verifier return public_key.verifier( signature, padding.PSS(mgf=mgf, salt_length=salt_length), hash_method )
def verify_signature(context, checksum_hash, image_properties): """Retrieve the image properties and use them to verify the signature. :param context: the user context for authentication :param checksum_hash: the 'checksum' hash of the image data :param image_properties: the key-value properties about the image :returns: True if verification succeeds :raises: SignatureVerificationError if verification fails """ if not should_verify_signature(image_properties): raise exception.SignatureVerificationError( 'Required image properties for signature verification do not' ' exist. Cannot verify signature.') if isinstance(checksum_hash, six.text_type): checksum_hash = checksum_hash.encode('utf-8') signature = get_signature(image_properties[OLD_SIGNATURE]) hash_method = get_hash_method(image_properties[OLD_HASH_METHOD]) signature_key_type = get_signature_key_type(image_properties[OLD_KEY_TYPE]) public_key = get_public_key(context, image_properties[OLD_CERT_UUID], signature_key_type) # create the verifier based on the signature key type verifier = KEY_TYPE_METHODS[signature_key_type](signature, hash_method, public_key, image_properties) if verifier: # Verify the signature verifier.update(checksum_hash) try: verifier.verify() return True except crypto_exception.InvalidSignature: raise exception.SignatureVerificationError( 'Signature verification failed.') else: # Error creating the verifier raise exception.SignatureVerificationError( 'Error occurred while verifying the signature')
def lookup(cls, name): """Look up the signature key type. :param name: the name of the signature key type :returns: the SignatureKeyType object :raises: glance.common.exception.SignatureVerificationError if signature key type is invalid """ if name not in cls._REGISTERED_TYPES: raise exception.SignatureVerificationError( _('Invalid signature key type: %s') % name) return cls._REGISTERED_TYPES[name]
def get_signature_key_type(signature_key_type): """Verify the signature key type. :param signature_key_type: the key type of the signature :return: the validated signature key type :raises: SignatureVerificationError if the signature key type is invalid """ if signature_key_type not in SIGNATURE_KEY_TYPES: raise exception.SignatureVerificationError( 'Invalid signature key type: %s' % signature_key_type) return signature_key_type
def get_hash_method(hash_method_name): """Verify the hash method name and create the hash method. :param hash_method_name: the name of the hash method to retrieve :return: the hash method, a cryptography object :raises: SignatureVerificationError if the hash method name is invalid """ if hash_method_name not in HASH_METHODS: raise exception.SignatureVerificationError( 'Invalid signature hash method: %s' % hash_method_name) return HASH_METHODS[hash_method_name]
def get_signature(signature_data): """Decode the signature data and returns the signature. :param siganture_data: the base64-encoded signature data :return: the decoded signature :raises: SignatureVerificationError if the signature data is malformatted """ try: signature = base64.b64decode(signature_data) except TypeError: raise exception.SignatureVerificationError( 'The signature data was not properly encoded using base64') return signature
def get_signature(signature_data): """Decode the signature data and returns the signature. :param signature_data: the base64-encoded signature data :returns: the decoded signature :raises glance.common.exception.SignatureVerificationError: if the signature data is malformatted """ try: signature = base64.decode_as_bytes(signature_data) except (TypeError, binascii.Error): raise exception.SignatureVerificationError( _('The signature data was not properly encoded using base64')) return signature
def set_data(self, data, size=None): if size is None: size = 0 # NOTE(markwash): zero -> unknown size # Create the verifier for signature verification (if correct properties # are present) if (signature_utils.should_create_verifier( self.image.extra_properties)): # NOTE(bpoulos): if creating verifier fails, exception will be # raised verifier = signature_utils.get_verifier( self.context, self.image.extra_properties) else: verifier = None location, size, checksum, loc_meta = self.store_api.add_to_backend( CONF, self.image.image_id, utils.LimitingReader(utils.CooperativeReader(data), CONF.image_size_cap), size, context=self.context, verifier=verifier) self._verify_signature_if_needed(checksum) # NOTE(bpoulos): if verification fails, exception will be raised if verifier: try: verifier.verify() LOG.info(_LI("Successfully verified signature for image %s"), self.image.image_id) except crypto_exception.InvalidSignature: raise exception.SignatureVerificationError( _('Signature verification failed')) self.image.locations = [{ 'url': location, 'metadata': loc_meta, 'status': 'active' }] self.image.size = size self.image.checksum = checksum self.image.status = 'active'
def verify_signature(context, checksum_hash, image_properties): """Retrieve the image properties and use them to verify the signature. :param context: the user context for authentication :param checksum_hash: the 'checksum' hash of the image data :param image_properties: the key-value properties about the image :return: True if verification succeeds :raises: SignatureVerificationError if verification fails """ if not should_verify_signature(image_properties): raise exception.SignatureVerificationError( 'Required image properties for signature verification do not' ' exist. Cannot verify signature.') signature = get_signature(image_properties[SIGNATURE]) hash_method = get_hash_method(image_properties[HASH_METHOD]) signature_key_type = get_signature_key_type(image_properties[KEY_TYPE]) public_key = get_public_key(context, image_properties[CERT_UUID], signature_key_type) # Initialize the verifier verifier = None # create the verifier based on the signature key type if signature_key_type == RSA_PSS: # retrieve other needed properties, or use defaults if not there if MASK_GEN_ALG in image_properties: mask_gen_algorithm = image_properties[MASK_GEN_ALG] if mask_gen_algorithm in MASK_GEN_ALGORITHMS: mgf = MASK_GEN_ALGORITHMS[mask_gen_algorithm](hash_method) else: raise exception.SignatureVerificationError( 'Invalid mask_gen_algorithm: %s' % mask_gen_algorithm) else: # default to MGF1 mgf = padding.MGF1(hash_method) if PSS_SALT_LENGTH in image_properties: pss_salt_length = image_properties[PSS_SALT_LENGTH] try: salt_length = int(pss_salt_length) except ValueError: raise exception.SignatureVerificationError( 'Invalid pss_salt_length: %s' % pss_salt_length) else: # default to max salt length salt_length = padding.PSS.MAX_LENGTH # Create the verifier verifier = public_key.verifier( signature, padding.PSS(mgf=mgf, salt_length=salt_length), hash_method) if verifier: # Verify the signature verifier.update(checksum_hash) try: verifier.verify() return True except crypto_exception.InvalidSignature: raise exception.SignatureVerificationError( 'Signature verification failed.') else: # Error creating the verifier raise exception.SignatureVerificationError( 'Error occurred while verifying the signature')