Пример #1
0
def signed_unpack(data, hmac_data, hmac_keys):
    """Unpack data and check that it was signed with hmac_key.

    :param data: json string that was singed_packed.
    :param hmac_data: hmac data that was generated from json by hmac_key on
                      user side
    :param hmac_keys: server side hmac_keys, one of these should be the same
                      as user used to sign with

    :returns: None in case of something wrong, Object in case of everything OK.
    """
    # NOTE(boris-42): For security reason, if there is no hmac_data or
    #                 hmac_keys we don't trust data => return None.
    if not (hmac_keys and hmac_data):
        return None
    hmac_data = hmac_data.strip()
    if not hmac_data:
        return None
    for hmac_key in hmac_keys:
        try:
            user_hmac_data = generate_hmac(data, hmac_key)
        except Exception:  # nosec
            pass
        else:
            if secretutils.constant_time_compare(hmac_data, user_hmac_data):
                try:
                    contents = json.loads(
                        binary_decode(base64.urlsafe_b64decode(data)))
                    contents["hmac_key"] = hmac_key
                    return contents
                except Exception:
                    return None
    return None
Пример #2
0
def signed_unpack(data, hmac_data, hmac_keys):
    """Unpack data and check that it was signed with hmac_key.

    :param data: json string that was singed_packed.
    :param hmac_data: hmac data that was generated from json by hmac_key on
                      user side
    :param hmac_keys: server side hmac_keys, one of these should be the same
                      as user used to sign with

    :returns: None in case of something wrong, Object in case of everything OK.
    """
    # NOTE(boris-42): For security reason, if there is no hmac_data or
    #                 hmac_keys we don't trust data => return None.
    if not (hmac_keys and hmac_data):
        return None
    hmac_data = hmac_data.strip()
    if not hmac_data:
        return None
    for hmac_key in hmac_keys:
        try:
            user_hmac_data = generate_hmac(data, hmac_key)
        except Exception:  # nosec
            pass
        else:
            if secretutils.constant_time_compare(hmac_data, user_hmac_data):
                try:
                    contents = json.loads(
                        binary_decode(base64.urlsafe_b64decode(data)))
                    contents["hmac_key"] = hmac_key
                    return contents
                except Exception:
                    return None
    return None
Пример #3
0
def unprotect_data(keys, signed_data):
    """De-serialize data given a dict of keys.

    Given keys and cached string data, verifies the signature, decrypts if
    necessary, and returns the original serialized data.

    """
    # cache backends return None when no data is found. We don't mind
    # that this particular special value is unsigned.
    if signed_data is None:
        return None

    # First we calculate the signature
    provided_mac = signed_data[:DIGEST_LENGTH_B64]
    calculated_mac = sign_data(
        keys['MAC'],
        signed_data[DIGEST_LENGTH_B64:])

    # Then verify that it matches the provided value
    if not secretutils.constant_time_compare(provided_mac, calculated_mac):
        raise InvalidMacError(_('Invalid MAC; data appears to be corrupted.'))

    data = base64.b64decode(signed_data[DIGEST_LENGTH_B64:])

    # then if necessary decrypt the data
    if keys['strategy'] == b'ENCRYPT':
        data = decrypt_data(keys['ENCRYPTION'], data)

    return data
Пример #4
0
    def _validate_shared_secret(self, requestor_id, signature, requestor_address):
        expected_signature = hmac.new(
            CONF.neutron.metadata_proxy_shared_secret, requestor_id, hashlib.sha256
        ).hexdigest()

        if not secutils.constant_time_compare(expected_signature, signature):
            if requestor_id:
                LOG.warning(
                    _LW(
                        "X-Instance-ID-Signature: %(signature)s does "
                        "not match the expected value: "
                        "%(expected_signature)s for id: "
                        "%(requestor_id)s. Request From: "
                        "%(requestor_address)s"
                    ),
                    {
                        "signature": signature,
                        "expected_signature": expected_signature,
                        "requestor_id": requestor_id,
                        "requestor_address": requestor_address,
                    },
                )

            msg = _("Invalid proxy request signature.")
            raise webob.exc.HTTPForbidden(explanation=msg)
Пример #5
0
def login(ra_name, user, secret):
    """Validates a user supplied user/password against an expected value.

       The expected value is pulled from the pecan config. Note that this
       value is currently stored in the clear inside that config, so we
       are assuming that the config is protected using file perms, etc.

       This function provides some resistance to timing attacks, but
       information on the expected user/password lengths can still be
       leaked. It may also be possible to use a timing attack to see
       which input failed validation. See comments below for details.

       :param ra_name: name of the registration authority
       :param user: The user supplied username (unicode or string)
       :param secret: The user supplied password (unicode or string)
       :return: None on failure or an AuthDetails object on success
    """
    auth_conf = jsonloader.authentication_for_registration_authority(ra_name)

    # convert input to strings
    user = str(user)
    secret = str(secret)

    # expected values
    try:
        expected_user = str(auth_conf['user'])
        expected_secret = str(auth_conf['secret'])
    except (KeyError, TypeError):
        logger.warning("auth conf missing static user or secret")
        return None

    # This technique is used to provide a constant time string compare
    # between the user input and the expected values.
    valid_user = util.constant_time_compare(user, expected_user)
    valid_secret = util.constant_time_compare(secret, expected_secret)

    # This if statement results in a potential timing attack where the
    # statement could return more quickly if valid_secret=False. We
    # do not see an obvious solution to this problem, but also believe
    # that leaking which input was valid isn't as big of a concern.
    if valid_user and valid_secret:
        return results.AuthDetails(username=expected_user, groups=[])

    logger.info("failed static auth for user {}".format(user))
Пример #6
0
def unwrap_envelope(envelope, key):
    payload = envelope[:-hash_len]
    expected_hmc = envelope[-hash_len:]
    calculated_hmc = get_hmac(payload, key)
    if not secretutils.constant_time_compare(expected_hmc, calculated_hmc):
        LOG.warning(_LW('calculated hmac: %(s1)s not equal to msg hmac: '
                    '%(s2)s dropping packet'), {'s1': to_hex(calculated_hmc),
                                                's2': to_hex(expected_hmc)})
        fmt = 'calculated hmac: {0} not equal to msg hmac: {1} dropping packet'
        raise exceptions.InvalidHMACException(fmt.format(
            to_hex(calculated_hmc), to_hex(expected_hmc)))
    obj = decode_obj(payload)
    return obj
Пример #7
0
def unwrap_envelope(envelope, key):
    payload = envelope[:-hash_len]
    expected_hmc = envelope[-hash_len:]
    calculated_hmc = get_hmac(payload, key)
    if not secretutils.constant_time_compare(expected_hmc, calculated_hmc):
        LOG.warn(
            _LW('calculated hmac: %(s1)s not equal to msg hmac: '
                '%(s2)s dropping packet'), {
                    's1': to_hex(calculated_hmc),
                    's2': to_hex(expected_hmc)
                })
        fmt = 'calculated hmac: {0} not equal to msg hmac: {1} dropping packet'
        raise exceptions.InvalidHMACException(
            fmt.format(to_hex(calculated_hmc), to_hex(expected_hmc)))
    obj = decode_obj(payload)
    return obj
Пример #8
0
def get_payload(envelope, key, hex=True):
    len = hex_hash_len if hex else hash_len
    payload = envelope[:-len]
    expected_hmc = envelope[-len:]
    calculated_hmc = get_hmac(payload, key, hex=hex)
    if not secretutils.constant_time_compare(expected_hmc, calculated_hmc):
        LOG.warning(
            'calculated hmac(hex=%(hex)s): %(s1)s not equal to msg hmac: '
            '%(s2)s dropping packet', {
                'hex': hex,
                's1': to_hex(calculated_hmc),
                's2': to_hex(expected_hmc)
            })
        fmt = 'calculated hmac: {0} not equal to msg hmac: {1} dropping packet'
        raise exceptions.InvalidHMACException(
            fmt.format(to_hex(calculated_hmc), to_hex(expected_hmc)))
    obj = decode_obj(payload)
    return obj
Пример #9
0
    def _validate_shared_secret(self, requestor_id, signature,
                                requestor_address):
        expected_signature = hmac.new(
            CONF.neutron.metadata_proxy_shared_secret,
            requestor_id, hashlib.sha256).hexdigest()

        if not secutils.constant_time_compare(expected_signature, signature):
            if requestor_id:
                LOG.warning(_LW('X-Instance-ID-Signature: %(signature)s does '
                                'not match the expected value: '
                                '%(expected_signature)s for id: '
                                '%(requestor_id)s. Request From: '
                                '%(requestor_address)s'),
                            {'signature': signature,
                             'expected_signature': expected_signature,
                             'requestor_id': requestor_id,
                             'requestor_address': requestor_address})

            msg = _('Invalid proxy request signature.')
            raise webob.exc.HTTPForbidden(explanation=msg)
Пример #10
0
def verify_signature(message, secret):
    """Check the signature in the message.

    Message is verified against the value computed from the rest of the
    contents.
    """
    if not secret:
        return True

    old_sig = message.get('message_signature', '')
    new_sig = compute_signature(message, secret)

    if isinstance(old_sig, str):
        try:
            old_sig = old_sig.encode('ascii')
        except UnicodeDecodeError:
            return False
    new_sig = new_sig.encode('ascii')

    return secretutils.constant_time_compare(new_sig, old_sig)
Пример #11
0
 def _validate_shared_secret(self, requestor_id, signature,
                             requestor_address):
     expected_signature = hmac.new(
         encodeutils.to_utf8(CONF.neutron.metadata_proxy_shared_secret),
         encodeutils.to_utf8(requestor_id),
         hashlib.sha256).hexdigest()
     if (not signature or
         not secutils.constant_time_compare(expected_signature, signature)):
         if requestor_id:
             LOG.warning('X-Instance-ID-Signature: %(signature)s does '
                         'not match the expected value: '
                         '%(expected_signature)s for id: '
                         '%(requestor_id)s. Request From: '
                         '%(requestor_address)s',
                         {'signature': signature,
                          'expected_signature': expected_signature,
                          'requestor_id': requestor_id,
                          'requestor_address': requestor_address})
         msg = _('Invalid proxy request signature.')
         raise webob.exc.HTTPForbidden(explanation=msg)
Пример #12
0
def get_payload(envelope, key, hex=True):
    len = hex_hash_len if hex else hash_len
    payload = envelope[:-len]
    expected_hmc = envelope[-len:]
    calculated_hmc = get_hmac(payload, key, hex=hex)
    if not secretutils.constant_time_compare(expected_hmc, calculated_hmc):
        LOG.warning(
            'calculated hmac(hex=%(hex)s): %(s1)s not equal to msg hmac: '
            '%(s2)s dropping packet',
            {
                'hex': hex,
                's1': to_hex(calculated_hmc),
                's2': to_hex(expected_hmc)
            }
        )
        fmt = 'calculated hmac: {0} not equal to msg hmac: {1} dropping packet'
        raise exceptions.InvalidHMACException(fmt.format(
            to_hex(calculated_hmc), to_hex(expected_hmc)))
    obj = decode_obj(payload)
    return obj
Пример #13
0
def verify_signature(message, secret):
    """Check the signature in the message.

    Message is verified against the value computed from the rest of the
    contents.
    """
    if not secret:
        return True

    old_sig = message.get('message_signature', '')
    new_sig = compute_signature(message, secret)

    if isinstance(old_sig, six.text_type):
        try:
            old_sig = old_sig.encode('ascii')
        except UnicodeDecodeError:
            return False
    if six.PY3:
        new_sig = new_sig.encode('ascii')

    return secretutils.constant_time_compare(new_sig, old_sig)
Пример #14
0
from oslo_utils import secretutils

print(secretutils.constant_time_compare('a', 'a'))
print(secretutils.constant_time_compare('a', 'b'))
print(secretutils.constant_time_compare('a', 'ab'))

print(secretutils.constant_time_compare(b'a', b'a'))
print(secretutils.constant_time_compare(b'a', b'b'))
print(secretutils.constant_time_compare(b'a', b'ab'))