aboutsummaryrefslogtreecommitdiffstats
path: root/tests/hazmat/primitives/test_arc4.py
blob: 33f7ff09441b594ef5af5887b5f0e7fa4cb3d12c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from __future__ import absolute_import, division, print_function

import binascii
import os

import pytest

from cryptography.hazmat.primitives.ciphers import algorithms

from .utils import generate_stream_encryption_test
from ...utils import load_nist_vectors


@pytest.mark.supported(
    only_if=lambda backend: backend.cipher_supported(
        algorithms.ARC4("\x00" * 16), None
    ),
    skip_message="Does not support ARC4",
)
@pytest.mark.cipher
class TestARC4(object):
    test_rfc = generate_stream_encryption_test(
        load_nist_vectors,
        os.path.join("ciphers", "ARC4"),
        [
            "rfc-6229-40.txt",
            "rfc-6229-56.txt",
            "rfc-6229-64.txt",
            "rfc-6229-80.txt",
            "rfc-6229-128.txt",
            "rfc-6229-192.txt",
            "rfc-6229-256.txt",
        ],
        lambda key, **kwargs: algorithms.ARC4(binascii.unhexlify(key)),
    )
n351' href='#n351'>351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466
/*
 * mmconfig-shared.c - Low-level direct PCI config space access via
 *                     MMCONFIG - common code between i386 and x86-64.
 *
 * This code does:
 * - known chipset handling
 * - ACPI decoding and validation
 *
 * Per-architecture code takes care of the mappings and accesses
 * themselves.
 *
 * Author: Allen Kay <allen.m.kay@intel.com> -  adapted to xen from Linux
 */

#include <xen/config.h>
#include <xen/init.h>
#include <xen/mm.h>
#include <xen/acpi.h>
#include <xen/xmalloc.h>
#include <xen/pci.h>
#include <xen/pci_regs.h>
#include <asm/e820.h>
#include <asm/msr.h>
#include <asm/msr-index.h>

#include "mmconfig.h"

static int __initdata known_bridge;
unsigned int pci_probe = PCI_PROBE_CONF1 | PCI_PROBE_MMCONF;

static void __init parse_mmcfg(char *s)
{
    char *ss;

    do {
        ss = strchr(s, ',');
        if ( ss )
            *ss = '\0';

        if ( !parse_bool(s) )
            pci_probe &= ~PCI_PROBE_MMCONF;
        else if ( !strcmp(s, "amd_fam10") || !strcmp(s, "amd-fam10") )
            pci_probe |= PCI_CHECK_ENABLE_AMD_MMCONF;

        s = ss + 1;
    } while ( ss );
}
custom_param("mmcfg", parse_mmcfg);

static const char __init *pci_mmcfg_e7520(void)
{
    u32 win;
    win = pci_conf_read16(0, 0, 0, 0xce);

    win = win & 0xf000;
    if(win == 0x0000 || win == 0xf000)
        pci_mmcfg_config_num = 0;
    else {
        pci_mmcfg_config_num = 1;
        pci_mmcfg_config = xmalloc(struct acpi_mcfg_allocation);
        if (!pci_mmcfg_config)
            return NULL;
        memset(pci_mmcfg_config, 0, sizeof(pci_mmcfg_config[0]));
        pci_mmcfg_config[0].address = win << 16;
        pci_mmcfg_config[0].pci_segment = 0;
        pci_mmcfg_config[0].start_bus_number = 0;
        pci_mmcfg_config[0].end_bus_number = 255;
    }

    return "Intel Corporation E7520 Memory Controller Hub";
}

static const char __init *pci_mmcfg_intel_945(void)
{
    u32 pciexbar, mask = 0, len = 0;

    pci_mmcfg_config_num = 1;

        pciexbar = pci_conf_read32(0, 0, 0, 0x48);

    /* Enable bit */
    if (!(pciexbar & 1))
        pci_mmcfg_config_num = 0;

    /* Size bits */
    switch ((pciexbar >> 1) & 3) {
    case 0:
        mask = 0xf0000000U;
        len  = 0x10000000U;
        break;
    case 1:
        mask = 0xf8000000U;
        len  = 0x08000000U;
        break;
    case 2:
        mask = 0xfc000000U;
        len  = 0x04000000U;
        break;
    default:
        pci_mmcfg_config_num = 0;
    }

    /* Errata #2, things break when not aligned on a 256Mb boundary */
    /* Can only happen in 64M/128M mode */

    if ((pciexbar & mask) & 0x0fffffffU)
        pci_mmcfg_config_num = 0;

    /* Don't hit the APIC registers and their friends */
    if ((pciexbar & mask) >= 0xf0000000U)
        pci_mmcfg_config_num = 0;

    if (pci_mmcfg_config_num) {
        pci_mmcfg_config = xmalloc(struct acpi_mcfg_allocation);
        if (!pci_mmcfg_config)
            return NULL;
        memset(pci_mmcfg_config, 0, sizeof(pci_mmcfg_config[0]));
        pci_mmcfg_config[0].address = pciexbar & mask;
        pci_mmcfg_config[0].pci_segment = 0;
        pci_mmcfg_config[0].start_bus_number = 0;
        pci_mmcfg_config[0].end_bus_number = (len >> 20) - 1;
    }

    return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub";
}

static const char __init *pci_mmcfg_amd_fam10h(void)
{
    uint32_t address;
    uint64_t base, msr_content;
    int i;
    unsigned segnbits = 0, busnbits;

    if (!(pci_probe & PCI_CHECK_ENABLE_AMD_MMCONF))
        return NULL;

    address = MSR_FAM10H_MMIO_CONF_BASE;
    if (rdmsr_safe(address, msr_content))
        return NULL;

    /* mmconfig is not enable */
    if (!(msr_content & FAM10H_MMIO_CONF_ENABLE))
        return NULL;

    base = msr_content &
        (FAM10H_MMIO_CONF_BASE_MASK<<FAM10H_MMIO_CONF_BASE_SHIFT);

    busnbits = (msr_content >> FAM10H_MMIO_CONF_BUSRANGE_SHIFT) &
                FAM10H_MMIO_CONF_BUSRANGE_MASK;

    /*
     * only handle bus 0 ?
     * need to skip it
     */
    if (!busnbits)
        return NULL;

    if (busnbits > 8) {
        segnbits = busnbits - 8;
        busnbits = 8;
    }

    pci_mmcfg_config_num = (1 << segnbits);
    pci_mmcfg_config = xmalloc_array(struct acpi_mcfg_allocation,
                                     pci_mmcfg_config_num);
    if (!pci_mmcfg_config)
        return NULL;

    for (i = 0; i < (1 << segnbits); i++) {
        pci_mmcfg_config[i].address = base + ((unsigned long)i << 28);
        pci_mmcfg_config[i].pci_segment = i;
        pci_mmcfg_config[i].start_bus_number = 0;
        pci_mmcfg_config[i].end_bus_number = (1 << busnbits) - 1;
    }

    return "AMD Family 10h NB";
}

static const char __init *pci_mmcfg_nvidia_mcp55(void)
{
    static bool_t __initdata mcp55_checked;
    int bus, i;

    static const u32 extcfg_regnum      = 0x90;
    static const u32 extcfg_enable_mask = 1<<31;
    static const u32 extcfg_start_mask  = 0xff<<16;
    static const int extcfg_start_shift = 16;
    static const u32 extcfg_size_mask   = 0x3<<28;
    static const int extcfg_size_shift  = 28;
    static const int extcfg_sizebus[]   = {0xff, 0x7f, 0x3f, 0x1f};
    static const u32 extcfg_base_mask[] = {0x7ff8, 0x7ffc, 0x7ffe, 0x7fff};
    static const int extcfg_base_lshift = 25;

    /* check if amd fam10h already took over */
    if (!acpi_disabled || pci_mmcfg_config_num || mcp55_checked)
        return NULL;

    mcp55_checked = 1;
    for (i = bus = 0; bus < 256; bus++) {
        u32 l, extcfg;
        u16 vendor, device;

        l = pci_conf_read32(bus, 0, 0, 0);
        vendor = l & 0xffff;
        device = (l >> 16) & 0xffff;

        if (PCI_VENDOR_ID_NVIDIA != vendor || 0x0369 != device)
            continue;

        extcfg = pci_conf_read32(bus, 0, 0, extcfg_regnum);

        if (extcfg & extcfg_enable_mask)
            i++;
    }

    if (!i)
        return NULL;

    pci_mmcfg_config_num = i;
    pci_mmcfg_config = xmalloc_array(struct acpi_mcfg_allocation,
                                     pci_mmcfg_config_num);

    for (i = bus = 0; bus < 256; bus++) {
        u64 base;
        u32 l, extcfg;
        u16 vendor, device;
        int size_index;

        l = pci_conf_read32(bus, 0, 0, 0);
        vendor = l & 0xffff;
        device = (l >> 16) & 0xffff;

        if (PCI_VENDOR_ID_NVIDIA != vendor || 0x0369 != device)
            continue;

        extcfg = pci_conf_read32(bus, 0, 0, extcfg_regnum);

        if (!(extcfg & extcfg_enable_mask))
            continue;

        if (i >= pci_mmcfg_config_num)
            break;

        size_index = (extcfg & extcfg_size_mask) >> extcfg_size_shift;
        base = extcfg & extcfg_base_mask[size_index];
        /* base could be > 4G */
        pci_mmcfg_config[i].address = base << extcfg_base_lshift;
        pci_mmcfg_config[i].pci_segment = 0;
        pci_mmcfg_config[i].start_bus_number =
            (extcfg & extcfg_start_mask) >> extcfg_start_shift;
        pci_mmcfg_config[i].end_bus_number =
            pci_mmcfg_config[i].start_bus_number + extcfg_sizebus[size_index];
        i++;
    }

    if (bus == 256)
        return "nVidia MCP55";

    pci_mmcfg_config_num = 0;
    xfree(pci_mmcfg_config);
    pci_mmcfg_config = NULL;

    return NULL;
}

struct pci_mmcfg_hostbridge_probe {
    u32 bus;
    u32 devfn;
    u32 vendor;
    u32 device;
    const char *(*probe)(void);
};

static struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initdata = {
    { 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID_INTEL,
      PCI_DEVICE_ID_INTEL_E7520_MCH, pci_mmcfg_e7520 },
    { 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID_INTEL,
      PCI_DEVICE_ID_INTEL_82945G_HB, pci_mmcfg_intel_945 },
    { 0, PCI_DEVFN(0x18, 0), PCI_VENDOR_ID_AMD,
      0x1200, pci_mmcfg_amd_fam10h },
    { 0xff, PCI_DEVFN(0, 0), PCI_VENDOR_ID_AMD,
      0x1200, pci_mmcfg_amd_fam10h },
    { 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID_NVIDIA,
      0x0369, pci_mmcfg_nvidia_mcp55 },
};

static int __init pci_mmcfg_check_hostbridge(void)
{
    u32 l;
    u32 bus, devfn;
    u16 vendor, device;
    int i;
    const char *name;

    pci_mmcfg_config_num = 0;
    pci_mmcfg_config = NULL;
    name = NULL;

    for (i = 0; !name && i < ARRAY_SIZE(pci_mmcfg_probes); i++) {
        bus =  pci_mmcfg_probes[i].bus;
        devfn = pci_mmcfg_probes[i].devfn;
        l = pci_conf_read32(bus, PCI_SLOT(devfn), PCI_FUNC(devfn), 0);
        vendor = l & 0xffff;
        device = (l >> 16) & 0xffff;

        if (pci_mmcfg_probes[i].vendor == vendor &&
            pci_mmcfg_probes[i].device == device)
            name = pci_mmcfg_probes[i].probe();
    }

    if (name) {
        printk(KERN_INFO "PCI: Found %s %s MMCONFIG support.\n",
            name, pci_mmcfg_config_num ? "with" : "without");
    }

    return name != NULL;
}

typedef int (*check_reserved_t)(u64 start, u64 end, unsigned type);

static int __init is_mmconf_reserved(
    check_reserved_t is_reserved,
    u64 addr, u64 size, int i,
    typeof(pci_mmcfg_config[0]) *cfg, int with_e820)
{
    u64 old_size = size;
    int valid = 0;

    while (!is_reserved(addr, addr + size - 1, E820_RESERVED)) {
        size >>= 1;
        if (size < (16UL<<20))
            break;
    }

    if (size >= (16UL<<20) || size == old_size) {
        printk(KERN_NOTICE
               "PCI: MCFG area at %lx reserved in %s\n",
                addr, with_e820?"E820":"ACPI motherboard resources");
        valid = 1;

        if (old_size != size) {
            /* update end_bus_number */
            cfg->end_bus_number = cfg->start_bus_number + ((size>>20) - 1);
            printk(KERN_NOTICE "PCI: updated MCFG configuration %d: base %lx "
                   "segment %hu buses %u - %u\n",
                   i, (unsigned long)cfg->address, cfg->pci_segment,
                   (unsigned int)cfg->start_bus_number,
                   (unsigned int)cfg->end_bus_number);
        }
    }

    return valid;
}

static void __init pci_mmcfg_reject_broken(void)
{
    typeof(pci_mmcfg_config[0]) *cfg;
    int i;

    if ((pci_mmcfg_config_num == 0) ||
        (pci_mmcfg_config == NULL) ||
        (pci_mmcfg_config[0].address == 0))
        return;

    cfg = &pci_mmcfg_config[0];

    for (i = 0; i < pci_mmcfg_config_num; i++) {
        u64 addr, size;

        cfg = &pci_mmcfg_config[i];
        addr = cfg->start_bus_number;
        addr <<= 20;
        addr += cfg->address;
        size = cfg->end_bus_number + 1 - cfg->start_bus_number;
        size <<= 20;
        printk(KERN_NOTICE "PCI: MCFG configuration %d: base %lx "
               "segment %hu buses %u - %u\n",
               i, (unsigned long)cfg->address, cfg->pci_segment,
               (unsigned int)cfg->start_bus_number,
               (unsigned int)cfg->end_bus_number);

        if (!is_mmconf_reserved(e820_all_mapped, addr, size, i, cfg, 1))
            goto reject;
    }

    return;

reject:
    printk(KERN_INFO "PCI: Not using MMCONFIG.\n");
    pci_mmcfg_arch_free();
    xfree(pci_mmcfg_config);
    pci_mmcfg_config = NULL;
    pci_mmcfg_config_num = 0;
}

void __init acpi_mmcfg_init(void)
{
    /* MMCONFIG disabled */
    if ((pci_probe & PCI_PROBE_MMCONF) == 0)
        return;

    /* MMCONFIG already enabled */
    if (!(pci_probe & PCI_PROBE_MASK & ~PCI_PROBE_MMCONF))
        return;

    /* for late to exit */
    if (known_bridge)
        return;

    if (pci_mmcfg_check_hostbridge())
        known_bridge = 1;

    if (!known_bridge) {
        acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg);
        pci_mmcfg_reject_broken();
    }

    if ((pci_mmcfg_config_num == 0) ||
        (pci_mmcfg_config == NULL) ||
        (pci_mmcfg_config[0].address == 0))
        return;

    if (pci_mmcfg_arch_init()) {
        pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
    }
}

/**
 * pci_find_ext_capability - Find an extended capability
 * @dev: PCI device to query
 * @cap: capability code
 *
 * Returns the address of the requested extended capability structure
 * within the device's PCI configuration space or 0 if the device does
 * not support it.  Possible values for @cap:
 *
 *  %PCI_EXT_CAP_ID_ERR         Advanced Error Reporting
 *  %PCI_EXT_CAP_ID_VC          Virtual Channel
 *  %PCI_EXT_CAP_ID_DSN         Device Serial Number
 *  %PCI_EXT_CAP_ID_PWR         Power Budgeting
 */
int pci_find_ext_capability(int seg, int bus, int devfn, int cap)
{
    u32 header;
    int ttl = 480; /* 3840 bytes, minimum 8 bytes per capability */
    int pos = 0x100;

    header = pci_conf_read32(bus, PCI_SLOT(devfn), PCI_FUNC(devfn), pos);

    /*
     * If we have no capabilities, this is indicated by cap ID,
     * cap version and next pointer all being 0.
     */
    if ( (header == 0) || (header == -1) )
        return 0;

    while ( ttl-- > 0 ) {
        if ( PCI_EXT_CAP_ID(header) == cap )
            return pos;
        pos = PCI_EXT_CAP_NEXT(header);
        if ( pos < 0x100 )
            break;
        header = pci_conf_read32(bus, PCI_SLOT(devfn), PCI_FUNC(devfn), pos);
    }
    return 0;
}