def _sigul_detached_sign_data(contents, config, key):

    # check is valid
    if not config:
        raise PluginError('No config file set')
    if not key:
        raise PluginError('No signing key set')

    # write firmware to temp file
    src = tempfile.NamedTemporaryFile(mode='wb',
                                      prefix='sigul_',
                                      suffix=".bin",
                                      dir=None,
                                      delete=True)
    src.write(contents)
    src.flush()

    # get asc file from temp file
    dst = tempfile.NamedTemporaryFile(mode='wb',
                                      prefix='sigul_',
                                      suffix=".asc",
                                      dir=None,
                                      delete=True)

    # sign
    argv = [
        'sigul', '--batch', '--config-file', config, 'sign-data', '--output',
        dst.name, key, src.name
    ]
    ps = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    if ps.wait() != 0:
        raise PluginError('Failed to sign: %s' % ps.stderr.read())

    # read back the temp file
    return open(dst.name, 'r').read()
Example #2
0
    def file_modified(self, fn):

        # is the file in the whitelist
        fns = self.get_setting('cdn_purge_files', required=True)
        basename = os.path.basename(fn)
        if not _basename_matches_globs(basename, fns.split(',')):
            print('%s not in %s' % (basename, fns))
            return

        # purge
        url = self.get_setting('cdn_purge_uri', required=True) + basename
        headers = {}
        accesskey = self.get_setting('cdn_purge_accesskey')
        if accesskey:
            headers['AccessKey'] = accesskey
        r = requests.request(self.get_setting('cdn_purge_method',
                                              required=True),
                             url,
                             headers=headers)
        if r.text:
            try:
                response = json.loads(r.text)
                if response['status'] != 'ok':
                    raise PluginError('Failed to purge metadata on CDN: ' +
                                      r.text)
            except ValueError as e:
                # BunnyCDN doesn't sent a JSON blob
                raise PluginError('Failed to purge metadata on CDN: %s: %s' %
                                  (r.text, str(e)))
Example #3
0
    def run_test_on_md(self, test, md):

        # sanity check
        if not md.blob:
            return

        # build the remote name
        remote_path = '/' + md.fw.vendor.group_id + '/' + str(
            md.component_id) + '/' + md.filename_contents

        # upload the file
        try:
            headers = {}
            headers['X-Apikey'] = self.get_setting('virustotal_api_key',
                                                   required=True)
            headers['User-Agent'] = self.get_setting('virustotal_user_agent',
                                                     required=True)
            files = {'file': ('filepath', md.blob, 'application/octet-stream')}
            args = {'path': remote_path}
            r = requests.post(self.get_setting('virustotal_uri',
                                               required=True),
                              files=files,
                              data=args,
                              headers=headers)
            if r.status_code != 200:
                test.add_fail('Failed to upload', r.text)
                return
        except IOError as e:
            raise PluginError(e)
Example #4
0
    def _sign_blob(self, contents):

        # write firmware to temp file
        src = tempfile.NamedTemporaryFile(mode='wb',
                                          prefix='pkcs7_',
                                          suffix=".bin",
                                          dir=None,
                                          delete=True)
        src.write(contents)
        src.flush()

        # get p7b file from temp file
        dst = tempfile.NamedTemporaryFile(mode='wb',
                                          prefix='pkcs7_',
                                          suffix=".p7b",
                                          dir=None,
                                          delete=True)

        # sign
        argv = [
            'certtool', '--p7-detached-sign', '--p7-time', '--load-privkey',
            self.get_setting('sign_pkcs7_privkey',
                             required=True), '--load-certificate',
            self.get_setting('sign_pkcs7_certificate', required=True),
            '--infile', src.name, '--outfile', dst.name
        ]
        ps = subprocess.Popen(argv,
                              stdout=subprocess.PIPE,
                              stderr=subprocess.PIPE)
        if ps.wait() != 0:
            raise PluginError('Failed to sign: %s' % ps.stderr.read())

        # read back the temp file
        with open(dst.name, 'rb') as f:
            return f.read()
Example #5
0
    def _get_shards_for_blob(self, blob):

        # write blob to temp file
        cwd = tempfile.TemporaryDirectory(prefix='lvfs')
        src = tempfile.NamedTemporaryFile(mode='wb',
                                          prefix='lvfs_',
                                          suffix=".bin",
                                          dir=cwd.name,
                                          delete=False)
        src.write(blob)
        src.flush()

        # run chipsec
        cmd = self.get_setting('chipsec_binary', required=True)
        argv = [cmd, '--no_driver', 'uefi', 'decode', src.name]
        ps = subprocess.Popen(argv,
                              stdout=subprocess.PIPE,
                              stderr=subprocess.PIPE,
                              cwd=cwd.name)
        if ps.wait() != 0:
            raise PluginError('Failed to decode file: %s' % ps.stderr.read())

        # look for shards
        outdir = src.name + '.dir'
        files = glob.glob(outdir + '/FV/**/*.efi', recursive=True)
        files.extend(glob.glob(outdir + '/FV/**/*.pe32', recursive=True))
        return self._convert_files_to_shards(files)
Example #6
0
    def _get_shards_for_blob(self, blob):

        # write blob to temp file
        cwd = tempfile.TemporaryDirectory(prefix='lvfs')
        src = tempfile.NamedTemporaryFile(mode='wb',
                                          prefix='lvfs_',
                                          suffix=".bin",
                                          dir=cwd.name,
                                          delete=False)
        src.write(blob)
        src.flush()

        # run chipsec
        cmd = self.get_setting('chipsec_binary', required=True)
        try:
            # pylint: disable=unexpected-keyword-arg
            subprocess.check_output(
                [cmd, '--no_driver', 'uefi', 'decode', src.name],
                stderr=subprocess.PIPE,
                cwd=cwd.name)
        except subprocess.CalledProcessError as e:
            raise PluginError('Failed to decode file: {}'.format(e.output))

        # look for shards
        outdir = src.name + '.dir'
        files = glob.glob(outdir + '/FV/**/*.efi', recursive=True)
        files.extend(glob.glob(outdir + '/FV/**/*.pe32', recursive=True))
        return self._convert_files_to_shards(files)
    def _get_shards_for_blob(self, blob):

        # write blob to temp file
        cwd = tempfile.TemporaryDirectory(prefix='lvfs')
        src = tempfile.NamedTemporaryFile(mode='wb',
                                          prefix='lvfs_',
                                          suffix=".bin",
                                          dir=cwd.name,
                                          delete=False)
        src.write(blob)
        src.flush()

        # run UEFIExtract
        cmd = self.get_setting('uefi_extract_binary', required=True)
        try:
            # pylint: disable=unexpected-keyword-arg
            subprocess.check_output([cmd, src.name],
                                    stderr=subprocess.PIPE,
                                    cwd=cwd.name)
        except subprocess.CalledProcessError as e:
            raise PluginError('Failed to decode file') from e

        # look for shards
        files = glob.glob(src.name + '.dump' + '/**/info.txt', recursive=True)
        return self._convert_files_to_shards(files)
Example #8
0
 def verify(self, data):
     """ Verify that the data was signed by something we trust """
     gpg = gnupg.GPG(gnupghome=self._homedir, gpgbinary='gpg2')
     gpg.encoding = 'utf-8'
     ver = gpg.verify(data)
     if not ver.valid:
         raise PluginError('Firmware was signed with an unknown private key')
     return True
Example #9
0
    def __init__(self, key_uid=None, homedir='/tmp'):
        """ Set defaults """

        # check exists
        if not os.path.exists(homedir):
            try:
                os.mkdir(homedir)
            except OSError as e:
                raise PluginError(e)

        # find correct key ID for the UID
        self._keyid = None
        gpg = gnupg.GPG(gnupghome=homedir, gpgbinary='gpg2')
        gpg.encoding = 'utf-8'
        for privkey in gpg.list_keys(True):
            for uid in privkey['uids']:
                if uid.find(key_uid) != -1:
                    self._keyid = privkey['keyid']
        if not self._keyid:
            raise PluginError('No imported private key for %s' % key_uid)
        self._homedir = homedir
Example #10
0
    def oauth_get_data(self):

        # get response success
        try:
            oauth_response = remote_app.authorized_response()
        except OAuthException as e:
            raise PluginError(str(e))
        if oauth_response is None:
            raise PluginError('Access Denied' + str(request))

        # check response for correct GUID
        if str(session['auth_azure_state']) != str(request.args['state']):
            raise PluginError('State has been messed with, end authentication')

        # save the access token -- treat as a password
        session['auth_azure_token'] = (oauth_response['access_token'], '')

        # get the profile ID
        resp = remote_app.get('me')
        if not resp:
            raise PluginError('No suitable profile response')
        if not resp.data:
            raise PluginError('No suitable profile data')
        return resp.data
Example #11
0
    def archive_finalize(self, cabarchive, metadata):

        # does the readme file already exist?
        filename = self.get_setting('info_readme_filename', required=True)
        if filename in cabarchive:
            return

        # read in the file and do substititons
        try:
            with open(self.get_setting('info_readme_template', required=True),
                      'rb') as f:
                template = f.read().decode('utf-8')
        except IOError as e:
            raise PluginError(e)
        for key in metadata:
            template = template.replace(key, metadata[key])

        # add it to the archive
        cabarchive[filename] = CabFile(template.encode('utf-8'))