コード例 #1
0
def get_verifier(context, img_signature_certificate_uuid,
                 img_signature_hash_method, img_signature,
                 img_signature_key_type):
    """Instantiate signature properties and use them to create a verifier.

    :param context: the user context for authentication
    :param img_signature_certificate_uuid:
           uuid of signing certificate stored in key manager
    :param img_signature_hash_method:
           string denoting hash method used to compute signature
    :param img_signature: string of base64 encoding of signature
    :param img_signature_key_type:
           string denoting type of keypair used to compute signature
    :returns: instance of
       cryptography.hazmat.primitives.asymmetric.AsymmetricVerificationContext
    :raises: SignatureVerificationError if we fail to build the verifier
    """
    image_meta_props = {'img_signature_uuid': img_signature_certificate_uuid,
                        'img_signature_hash_method': img_signature_hash_method,
                        'img_signature': img_signature,
                        'img_signature_key_type': img_signature_key_type}
    for key in image_meta_props.keys():
        if image_meta_props[key] is None:
            raise exception.SignatureVerificationError(
                reason=_('Required image properties for signature verification'
                         ' do not exist. Cannot verify signature. Missing'
                         ' property: %s') % key)

    signature = get_signature(img_signature)
    hash_method = get_hash_method(img_signature_hash_method)
    signature_key_type = SignatureKeyType.lookup(img_signature_key_type)
    public_key = get_public_key(context,
                                img_signature_certificate_uuid,
                                signature_key_type)

    # create the verifier based on the signature key type
    verifier = signature_key_type.create_verifier(signature,
                                                  hash_method,
                                                  public_key)
    if verifier:
        return verifier
    else:
        # Error creating the verifier
        raise exception.SignatureVerificationError(
            reason=_('Error occurred while creating the verifier'))
コード例 #2
0
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: 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 ManagedObjectNotFoundError as e:
        raise exception.SignatureVerificationError(
            reason=_('Certificate not found with ID: %s')
            % signature_certificate_uuid)
    except KeyManagerError 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(
            reason=_('Unable to retrieve certificate with ID: %s')
            % signature_certificate_uuid)

    if cert.format not in CERTIFICATE_FORMATS:
        raise exception.SignatureVerificationError(
            reason=_('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())

    return certificate
コード例 #3
0
    def update(self, certificate):
        """Process the certificate to be verified.

        Raises an exception if the certificate is invalid. Stores it
        otherwise.

        :param certificate: the cryptography certificate to be verified
        :raises: SignatureVerificationError if the certificate is not of the
                 right type or if it is outside its valid date range.
        """
        if not isinstance(certificate, x509.Certificate):
            raise exception.SignatureVerificationError(
                "The certificate must be an x509.Certificate object.")

        if self._enforce_valid_dates:
            if not is_within_valid_dates(certificate):
                raise exception.SignatureVerificationError(
                    "The certificate is outside its valid date range.")

        self._signed_certificate = certificate
コード例 #4
0
    def lookup(cls, name):
        """Look up the signature key type.

        :param name: the name of the signature key type
        :returns: the SignatureKeyType object
        :raises: SignatureVerificationError if signature key type is invalid
        """
        if name not in cls.REGISTERED_TYPES:
            raise exception.SignatureVerificationError(
                reason=_('Invalid signature key type: %s') % name)
        return cls.REGISTERED_TYPES[name]
コード例 #5
0
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
    :returns: 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(
            reason=_('Invalid signature hash method: %s') % hash_method_name)

    return HASH_METHODS[hash_method_name]
コード例 #6
0
    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)
        extra_props = self.image.extra_properties
        if (signature_utils.should_create_verifier(extra_props)):
            # NOTE(bpoulos): if creating verifier fails, exception will be
            # raised
            img_signature = extra_props[signature_utils.SIGNATURE]
            hash_method = extra_props[signature_utils.HASH_METHOD]
            key_type = extra_props[signature_utils.KEY_TYPE]
            cert_uuid = extra_props[signature_utils.CERT_UUID]
            verifier = signature_utils.get_verifier(
                context=self.context,
                img_signature_certificate_uuid=cert_uuid,
                img_signature_hash_method=hash_method,
                img_signature=img_signature,
                img_signature_key_type=key_type)
        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)

        # 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:
                self.store_api.delete_from_backend(location,
                                                   context=self.context)
                raise cursive_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'
コード例 #7
0
 def test_raises_when_all_stores_must_succeed(self, mock_import):
     img_repo = mock.MagicMock()
     image_import = import_flow._ImportToStore(TASK_ID1, TASK_TYPE,
                                               img_repo, "http://url",
                                               IMAGE_ID1, "store1", True,
                                               True)
     image = self.img_factory.new_image(image_id=UUID1)
     img_repo.get.return_value = image
     mock_import.set_image_data.side_effect = \
         cursive_exception.SignatureVerificationError(
             "Signature verification failed")
     self.assertRaises(cursive_exception.SignatureVerificationError,
                       image_import.execute)
コード例 #8
0
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: SignatureVerificationError if the signature data is malformatted
    """
    try:
        signature = base64.decode_as_bytes(signature_data)
    except (TypeError, binascii.Error):
        raise exception.SignatureVerificationError(
            reason=_('The signature data was not properly '
                     'encoded using base64'))

    return signature
コード例 #9
0
 def test_doesnt_raise_when_not_all_stores_must_succeed(self, mock_import):
     img_repo = mock.MagicMock()
     image_import = import_flow._ImportToStore(TASK_ID1, TASK_TYPE,
                                               img_repo, "http://url",
                                               IMAGE_ID1, "store1", False,
                                               True)
     image = self.img_factory.new_image(image_id=UUID1)
     img_repo.get.return_value = image
     mock_import.set_image_data.side_effect = \
         cursive_exception.SignatureVerificationError(
             "Signature verification failed")
     try:
         image_import.execute()
         self.assertEqual(image.extra_properties['os_glance_failed_import'],
                          "store1")
     except cursive_exception.SignatureVerificationError:
         self.fail("Exception shouldn't be raised")
コード例 #10
0
 def test_raises_when_all_stores_must_succeed(self, mock_import):
     img_repo = mock.MagicMock()
     task_repo = mock.MagicMock()
     wrapper = import_flow.ImportActionWrapper(img_repo, IMAGE_ID1,
                                               TASK_ID1)
     image_import = import_flow._ImportToStore(TASK_ID1, TASK_TYPE,
                                               task_repo, wrapper,
                                               "http://url", "store1", True,
                                               True)
     extra_properties = {'os_glance_import_task': TASK_ID1}
     image = self.img_factory.new_image(image_id=UUID1,
                                        extra_properties=extra_properties)
     img_repo.get.return_value = image
     mock_import.set_image_data.side_effect = \
         cursive_exception.SignatureVerificationError(
             "Signature verification failed")
     self.assertRaises(cursive_exception.SignatureVerificationError,
                       image_import.execute)
コード例 #11
0
    def load_certificate(self, cert_name):
        # Load the raw certificate file data.
        path = os.path.join(self.cert_path, cert_name)
        with open(path, 'rb') as cert_file:
            data = cert_file.read()

        # Convert the raw certificate data into a certificate object, first
        # as a PEM-encoded certificate and, if that fails, then as a
        # DER-encoded certificate. If both fail, the certificate cannot be
        # loaded.
        try:
            return x509.load_pem_x509_certificate(data, default_backend())
        except Exception:
            try:
                return x509.load_der_x509_certificate(data, default_backend())
            except Exception:
                raise exception.SignatureVerificationError(
                    "Failed to load certificate: %s" % path
                )
コード例 #12
0
    def _verify_signature(self, verifier, location, loc_meta):
        """
        Verify signature of uploaded data.

        :param verifier: for signature verification
        """
        # NOTE(bpoulos): if verification fails, exception will be raised
        if verifier is not None:
            try:
                verifier.verify()
                msg = _LI("Successfully verified signature for image %s")
                LOG.info(msg, self.image.image_id)
            except crypto_exception.InvalidSignature:
                if CONF.enabled_backends:
                    self.store_api.delete(location,
                                          loc_meta.get('store'),
                                          context=self.context)
                else:
                    self.store_api.delete_from_backend(location,
                                                       context=self.context)
                raise cursive_exception.SignatureVerificationError(
                    _('Signature verification failed'))
コード例 #13
0
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: 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(
            reason=_('Invalid public key type for signature key type: %s')
            % signature_key_type.name)

    return public_key
コード例 #14
0
    def verify(self):
        """Locate the certificate's signing certificate and verify it.

        Locate the certificate's signing certificate in the context
        certificate cache, using both subject/issuer name matching and
        signature verification. If the certificate is self-signed, verify that
        it is also located in the context's certificate cache. Construct the
        certificate chain from certificates in the context certificate cache.
        Verify that the signing certificate can have a sufficient number of
        child certificates to support the chain.

        :raises: SignatureVerificationError if certificate validation fails
                 for any reason, including mismatched signatures or a failure
                 to find the required signing certificate.
        """
        signed_certificate = self._signed_certificate
        certificate_chain = [('base', signed_certificate)]

        # Build the certificate chain.
        while True:
            signing_certificate_tuple = None

            # Search for the signing certificate
            for certificate_tuple in self._signing_certificates:
                _, candidate = certificate_tuple
                if is_issuer(candidate, signed_certificate):
                    signing_certificate_tuple = certificate_tuple
                    break

            # If a valid signing certificate is found, prepare to find the
            # next link in the certificate chain. Otherwise, raise an error.
            if signing_certificate_tuple:
                # If the certificate is self-signed, the root of the
                # certificate chain has been found. Otherwise, repeat the
                # verification process using the newly found signing
                # certificate.
                if signed_certificate == signing_certificate_tuple[1]:
                    break
                else:
                    certificate_chain.insert(0, signing_certificate_tuple)
                    signed_certificate = signing_certificate_tuple[1]
            else:
                uuid = certificate_chain[0][0]
                raise exception.SignatureVerificationError(
                    "Certificate chain building failed. Could not locate the "
                    "signing certificate for %s in the set of trusted "
                    "certificates." % "the base certificate" if uuid ==
                    'base' else "certificate '%s'" % uuid)

        if self._enforce_path_length:
            # Verify that each certificate's path length constraint allows
            # for it to support the rest of the certificate chain.
            for i in range(len(certificate_chain)):
                certificate = certificate_chain[i][1]

                # No need to check the last certificate in the chain.
                if certificate == certificate_chain[-1][1]:
                    break

                try:
                    constraints = certificate.extensions.get_extension_for_oid(
                        x509.oid.ExtensionOID.BASIC_CONSTRAINTS).value
                except x509.extensions.ExtensionNotFound:
                    raise exception.SignatureVerificationError(
                        "Certificate validation failed. The signing "
                        "certificate '%s' does not have a basic constraints "
                        "extension." % certificate_chain[i][0])

                # Path length only applies to non-self-issued intermediate
                # certificates. Do not include the current or end certificates
                # when computing path length.
                chain_length = len(certificate_chain[i:])
                chain_length = (chain_length - 2) if chain_length > 2 else 0
                if constraints.path_length < chain_length:
                    raise exception.SignatureVerificationError(
                        "Certificate validation failed. The signing "
                        "certificate '%s' is not configured to support "
                        "certificate chains of sufficient "
                        "length." % certificate_chain[i][0])