Exemplo n.º 1
0
def digest(blob, comment, bootargs, initramfs, kernel, seckey, password=None):
    with tempfile.NamedTemporaryFile() as temp:
        esmd_create_digest(temp.name, bootargs, initramfs, kernel)
        blob_contents = file_read(temp.name)
        fdt = libfdt.Fdt(blob_contents)
        attach_digests(blob, temp.name, comment, 'digests-fdt', seckey,
                       password)
Exemplo n.º 2
0
    def __init__(self, fname):
        self._fname = fname
        self._cached_offsets = False
        self.phandle_to_node = {}
        if self._fname:
            self._fname = fdt_util.EnsureCompiled(self._fname)

            with open(self._fname) as fd:
                self._fdt_obj = libfdt.Fdt(fd.read())
Exemplo n.º 3
0
    def __init__(self, fname):
        self._fname = fname
        self._cached_offsets = False
        if self._fname:
            self._fname = fdt_util.EnsureCompiled(self._fname)

            with open(self._fname) as fd:
                self._fdt = bytearray(fd.read())
                self._fdt_obj = libfdt.Fdt(self._fdt)
Exemplo n.º 4
0
def _ReadFdt(fname):
    """Read a device tree file into an Fdt object, ready for use

    Args:
        fname: Filename to read from

    Returns:
        Fdt bytearray suitable for passing to libfdt functions
    """
    return libfdt.Fdt(open(fname).read())
Exemplo n.º 5
0
    def FromData(data):
        """Create a new Fdt object from the given data

        Args:
            data: Device-tree data blob

        Returns:
            Fdt object containing the data
        """
        fdt = Fdt(None)
        fdt._fdt_obj = libfdt.Fdt(bytearray(data))
        return fdt
Exemplo n.º 6
0
    def FromData(data, name=''):
        """Create a new Fdt object from the given data

        Args:
            data: Device-tree data blob
            name: Helpful name for this Fdt for the user

        Returns:
            Fdt object containing the data
        """
        fdt = Fdt(None)
        fdt._fdt_obj = libfdt.Fdt(bytes(data))
        fdt.name = name
        return fdt
Exemplo n.º 7
0
def esm_detach(args):
    blob_contents = file_read(args.blob)
    fdt = libfdt.Fdt(blob_contents)
    validate_esm(fdt, args.blob)

    # Find and delete the attachment.
    file_path = '/file/' + args.file
    file_offset = fdt.path_offset(file_path, QUIET_NOTFOUND)
    if file_offset == -libfdt.NOTFOUND:
        err(1, '{}: not attached', args.file)
    dbg1('{}: deleting node', file_path)
    fdt.del_node(file_offset)

    # Write out the updated blob.
    fdt.pack()
    if not dryrun:
        file_atomic_replace(args.blob, fdt.as_bytearray())
Exemplo n.º 8
0
def attach(blob, file, comment, name, seckey, password=None):
    blob_contents = file_read(blob)
    fdt = libfdt.Fdt(blob_contents)
    validate_esm(fdt, blob)

    file_fdt = file_fdt_get(fdt, create=True)

    # Load the attachment.
    file_contents = file_read(file)

    # Make room for the attachment, its comment, and other properties.
    file_fdt.resize(file_fdt.totalsize() + len(comment))
    file_fdt.resize(file_fdt.totalsize() + len(file_contents) + EIGHT_KB)

    # Check that the attachment name is acceptable.
    if name == '':
        node_name = os.path.basename(file)
    else:
        node_name = name
    if not node_name_is_valid(node_name):
        err(1, '{}: file name is invalid: {}', file, node_name)

    # Create a subnode in /file for the attachment.
    parent_offset = file_fdt.path_offset('/files')
    file_offset = file_fdt.add_subnode(parent_offset, node_name)
    file_fdt.setprop_str(file_offset, 'algorithm', 'AES256-GCM')

    if '\n' in comment:
        err(1, 'comment cannot contain a newline')
    file_fdt.setprop_str(file_offset, 'untrusted-comment', comment)

    # Encrypt and store the attachment in the subnode.
    symkey = extract_symkey(fdt, seckey, password)
    aes_cipher = AES.new(symkey, AES.MODE_GCM)
    ciphertext, mac = aes_cipher.encrypt_and_digest(file_contents)
    file_fdt.setprop(file_offset, 'ciphertext', ciphertext)
    file_fdt.setprop(file_offset, 'iv', aes_cipher.nonce)
    file_fdt.setprop(file_offset, 'mac', mac)

    # Update files-fdt
    file_fdt_put(fdt, file_fdt)

    # Write out the updated blob.
    fdt.pack()
    if not dryrun:
        file_atomic_replace(blob, fdt.as_bytearray())
Exemplo n.º 9
0
def esm_display(args):
    blob_contents = file_read(args.blob)
    fdt = libfdt.Fdt(blob_contents)
    validate_esm(fdt, args.blob)

    dbg1('reading lockboxes')

    # Find the offset to each lockbox and note its number.
    parent_offset = fdt.path_offset('/lockboxes')
    lockbox_offset = fdt.first_subnode(parent_offset)
    offset_by_number = dict()
    while lockbox_offset >= 0:
        lockbox_name = fdt.get_name(lockbox_offset)
        lockbox_num = -1
        if lockbox_name == 'origin-lockbox':
            lockbox_num = 0
        else:
            tokens = lockbox_name.split('-')
            lockbox_num = int(tokens[1])
        offset_by_number[lockbox_num] = lockbox_offset
        lockbox_offset = fdt.next_subnode(lockbox_offset, QUIET_NOTFOUND)

    # Display the hash of the public key and the comment for each lockbox.
    # The origin key's hash is always displayed first.
    for num in sorted(offset_by_number):
        offset = offset_by_number[num]
        comment = fdt.getprop(offset, 'untrusted-comment').as_str()
        fingerprint_offset = fdt.subnode_offset(offset, 'pubkey-fingerprint')
        hash_str = fdt.getprop(fingerprint_offset, 'hash').hex()
        if num == 0:
            prefix = 'origin'
        else:
            prefix = 'recipient'
        print(prefix, hash_str, 'untrusted-comment', comment)

    dbg1('reading attachments')

    # Display the attachment and its comment
    parent_offset = fdt.path_offset('/file')
    file_offset = fdt.first_subnode(parent_offset, QUIET_NOTFOUND)
    while file_offset >= 0:
        comment = fdt.getprop(file_offset, 'untrusted-comment').as_str()
        name = fdt.get_name(file_offset)
        print('file', name, 'untrusted-comment', comment)
        file_offset = fdt.next_subnode(file_offset, QUIET_NOTFOUND)
Exemplo n.º 10
0
def esm_revoke(args):
    header_contents = file_read(args.blob)
    fdt = libfdt.Fdt(header_contents)
    validate_esm(fdt, args.blob)

    # Prepare the pubkey hash.
    pubkey_contents = open(args.pubkey, 'rb').read()
    sha256 = SHA256.new()
    sha256.update(pubkey_contents)
    pubkey_hash = sha256.digest()
    dbg2('{}: SHA256: {}', args.pubkey, pubkey_hash.hex())

    # Find a matching lockbox.
    parent_offset = fdt.path_offset('/lockboxes')
    offset = fdt.first_subnode(parent_offset)
    while offset > 0:
        lockbox_name = fdt.get_name(offset)
        fingerprint_path = '/lockboxes/' + lockbox_name + '/pubkey-fingerprint'
        fingerprint_offset = fdt.path_offset(fingerprint_path)
        lockbox_pubkey_hash = fdt.getprop(fingerprint_offset, 'hash')
        dbg2('{}: SHA256: {}', lockbox_name, lockbox_pubkey_hash.hex())
        if pubkey_hash == lockbox_pubkey_hash:
            break
        offset = fdt.next_subnode(offset, libfdt.QUIET_NOTFOUND)

    # Not found.
    if offset <= 0:
        err(1, '{}: cannot revoke unauthorized key', args.pubkey)

    dbg1('{}: matching hash found', lockbox_name)

    # The origin key is a special case.  We can never revoke it.
    if lockbox_name == "origin-lockbox":
        err(1, '{}: cannot revoke origin key', args.pubkey)

    # Remove the lockbox.
    dbg1('{}: deleting lockbox', lockbox_name)
    fdt.del_node(offset)

    # Write out the updated blob.
    fdt.pack()
    if not dryrun:
        file_atomic_replace(args.blob, fdt.as_bytearray())
Exemplo n.º 11
0
def MicroblazeConfig(dtbfile, out):
    fdt = libfdt.Fdt(open(dtbfile, mode='rb').read())

    cpu = -1
    while (True):
        cpu = cpu + 1
        try:
            node = fdt.path_offset('/cpus/cpu@%d' % cpu)

            try:
                prop = fdt.getprop(node, 'compatible')

                prop_val = prop[:-1].decode('utf-8').split('\x00')

                microblaze = False
                for val in prop_val:
                    if "microblaze" in val:
                        microblaze = True
                        break

                if not microblaze:
                    continue

                # Construct TUNE_FEATURE here
                TUNE_FEATURES = processProperties(fdt, node)

                out.write('AVAILTUNES += "microblaze-cpu%s"\n' % (cpu))
                out.write('TUNE_FEATURES_tune-microblaze-cpu%s = "%s"\n' %
                          (cpu, ' '.join(TUNE_FEATURES)))
                out.write(
                    'PACKAGE_EXTRA_ARCHS_tune-microblaze-cpu%s = "${TUNE_PKGARCH}"\n'
                    % (cpu))

            except Exception as e:
                sys.stderr.write("Exception looking at properties: %s\n" % e)

                continue

        except Exception as e:
            # CPUs SHOULD be consecutive w/o gaps, so no more to search
            break
Exemplo n.º 12
0
def file_fdt_get(fdt, create=False):

    file_fdt = None
    file_path = '/file'
    file_offset = fdt.path_offset(file_path, QUIET_NOTFOUND)

    if file_offset == -libfdt.NOTFOUND:
        err(1, f'{file_path} not found')

    files_prop = fdt.getprop(file_offset, 'files-fdt', QUIET_NOTFOUND)
    if files_prop == -libfdt.NOTFOUND:
        # New File FDT with a "compatible" property.
        file_fdt = libfdt.Fdt.create_empty_tree(EIGHT_KB)
        file_fdt.setprop_str(0, 'compatible', 'ibm,esm-file')
        file_fdt.add_subnode(0, 'files')
        file_fdt.pack()
        fdt.resize(file_fdt.totalsize() + EIGHT_KB)
        fdt.setprop(file_offset, 'files-fdt', bytes(file_fdt.as_bytearray()))
    else:
        file_fdt = libfdt.Fdt(files_prop)

    return file_fdt
Exemplo n.º 13
0
def esm_extract(args):
    blob_contents = file_read(args.blob)
    fdt = libfdt.Fdt(blob_contents)
    validate_esm(fdt, args.blob)

    # Find the attachment.
    file_path = '/file/' + args.file
    file_offset = fdt.path_offset(file_path, QUIET_NOTFOUND)
    if file_offset == -libfdt.NOTFOUND:
        err(1, '{}: not attached', args.file)

    # We only do AES256-GCM.
    algorithm = fdt.getprop(file_offset, 'algorithm').as_str()
    if algorithm != 'AES256-GCM':
        err(1, 'unsupported algorithm: {}', algorithm)

    # Grab the needed properties.
    ciphertext = fdt.getprop(file_offset, 'ciphertext')
    iv = fdt.getprop(file_offset, 'iv')
    mac = fdt.getprop(file_offset, 'mac')

    # Prepare our symmetric cipher.
    symkey = extract_symkey(fdt, args.seckey)
    aes_cipher = AES.new(symkey, AES.MODE_GCM, nonce=iv)

    # Decrypt and verify everything.
    plaintext = aes_cipher.decrypt(ciphertext)
    try:
        aes_cipher.verify(mac)
    except ValueError as e:
        err(1, '{}: cannot decrypt: wrong key or attachment corrupted',
            args.file)

    # Write the attached file's contents to the standard output.
    if not dryrun:
        print(plaintext.decode('ASCII'), end='')
Exemplo n.º 14
0
def authorize(blob, pubkey, comment, seckey, password=None):
    blob_contents = file_read(blob)
    fdt = libfdt.Fdt(blob_contents)
    validate_esm(fdt, blob)

    # Prepare the pubkey hash.
    pubkey_contents = file_read(pubkey)
    sha256 = SHA256.new()
    sha256.update(pubkey_contents)
    pubkey_hash = sha256.digest()
    dbg2('{}: SHA256: {}', pubkey, pubkey_hash.hex())

    # Find the largest lockbox number.
    parent_offset = fdt.path_offset('/lockboxes')
    offset = fdt.first_subnode(parent_offset)
    max_lockbox_num = -1
    while offset > 0:
        lockbox_name = fdt.get_name(offset)
        fingerprint_offset = fdt.subnode_offset(offset, 'pubkey-fingerprint')
        lockbox_pubkey_hash = fdt.getprop(fingerprint_offset, 'hash')
        dbg2('{}: SHA256: {}', lockbox_name, lockbox_pubkey_hash.hex())
        if pubkey_hash == lockbox_pubkey_hash:
            break
        lockbox_num = -1
        if lockbox_name == 'origin-lockbox':
            lockbox_num = 0
        else:
            tokens = lockbox_name.split('-')
            lockbox_num = int(tokens[1])
        max_lockbox_num = max(max_lockbox_num, lockbox_num)
        offset = fdt.next_subnode(offset, libfdt.QUIET_NOTFOUND)

    # If the key is already authorized there's nothing more to do.
    if offset > 0:
        err(1, '{}: already authorized', pubkey)

    # Need more room for new lockbox.
    fdt.resize(fdt.totalsize() + len(comment) + EIGHT_KB)

    # Create a new lockbox and add the comment, if any.
    lockbox_name = "lockbox-{}".format(max_lockbox_num + 1)
    dbg1('{}: making new lockbox', lockbox_name)
    lockbox_offset = fdt.add_subnode(parent_offset, lockbox_name)

    if '\n' in comment:
        err(1, 'comment cannot contain a newline')
    fdt.setprop_str(lockbox_offset, "untrusted-comment", comment)

    # Add the pubkey fingerprint.
    fingerprint_offset = fdt.add_subnode(lockbox_offset, 'pubkey-fingerprint')
    fdt.setprop_str(fingerprint_offset, 'algorithm', 'SHA256')
    fdt.setprop(fingerprint_offset, 'hash', pubkey_hash)

    # Prepare the public key cipher.
    try:
        rsa_pubkey = RSA.importKey(pubkey_contents)
    except ValueError as e:
        err(1, '{}: {}', pubkey, *e.args)
    rsa_cipher = PKCS1_OAEP.new(rsa_pubkey, hashAlgo=SHA256)

    # Add the encrypted symkey.
    symkey = extract_symkey(fdt, seckey, password)
    encrypted_symkey = rsa_cipher.encrypt(symkey)
    fdt.setprop(lockbox_offset, 'encrypted-symkey', encrypted_symkey)

    # Write out the updated blob.
    fdt.pack()
    if not dryrun:
        file_atomic_replace(blob, fdt.as_bytearray())
Exemplo n.º 15
0
 def testBadFdt(self):
     """Check that a filename provided accidentally is not accepted"""
     with self.assertRaises(FdtException) as e:
         fdt = libfdt.Fdt('a string')
     self.assertEquals(e.exception.err, -libfdt.BADMAGIC)