def _get_valid_inf(): txt = """[Version] Class=Firmware ClassGuid={f2e7dd72-6468-4e36-b6f1-6488f42c1b52} DriverVer=04/18/2015,2.0.3 [Firmware_CopyFiles] firmware.bin [Firmware_AddReg] HKR,,FirmwareId,,{2082b5e0-7a64-478a-b1b2-e3404fab6dad} HKR,,FirmwareVersion,%REG_DWORD%,0x0000000 HKR,,FirmwareFilename,,firmware.bin [Strings] Provider = "Hughski" MfgName = "Hughski Limited" FirmwareDesc = "ColorHug2 Firmware" DiskName = "Firmware for the ColorHug2 Colorimeter" """ return CabFile(txt.encode('utf-8'))
def _get_alternate_metainfo(): txt = """<?xml version="1.0" encoding="UTF-8"?> <!-- Copyright 2019 Richard Hughes <*****@*****.**> --> <component type="firmware"> <id>com.hughski.ColorHug.firmware</id> <name>ColorHug</name> <summary>Firmware for the ColorHug</summary> <description><p>Updating the firmware improves performance.</p></description> <provides> <firmware type="flashed">84f40464-9272-4ef7-9399-cd95f12da696</firmware> </provides> <url type="homepage">http://www.hughski.com/</url> <metadata_license>CC0-1.0</metadata_license> <project_license>proprietary</project_license> <developer_name>Hughski Limited</developer_name> <releases> <release version="1.2.3" date="2019-07-02"> <description><p>This stable release fixes bugs</p></description> </release> </releases> </component> """ return CabFile(txt.encode('utf-8'))
def _sign_fw(fw): # load the .cab file download_dir = app.config['DOWNLOAD_DIR'] fn = os.path.join(download_dir, fw.filename) try: with open(fn, 'rb') as f: cabarchive = CabArchive(f.read()) except IOError as e: raise NotImplementedError('cannot read %s: %s' % (fn, str(e))) # create Jcat file jcatfile = JcatFile() # sign each component in the archive print('Signing: %s' % fn) for md in fw.mds: try: # create Jcat item with SHA1 and SHA256 checksum blob cabfile = cabarchive[md.filename_contents] jcatitem = jcatfile.get_item(md.filename_contents) jcatitem.add_blob(JcatBlobSha1(cabfile.buf)) jcatitem.add_blob(JcatBlobSha256(cabfile.buf)) # sign using plugins for blob in ploader.archive_sign(cabfile.buf): # add GPG only to archive for backwards compat with older fwupd if blob.kind == JcatBlobKind.GPG: fn_blob = md.filename_contents + '.' + blob.filename_ext cabarchive[fn_blob] = CabFile(blob.data) # add to Jcat file too jcatitem.add_blob(blob) except KeyError as _: raise NotImplementedError('no {} firmware found'.format( md.filename_contents)) # rewrite the metainfo.xml file to reflect latest changes and sign it for md in fw.mds: # write new metainfo.xml file component = _generate_metadata_mds([md], metainfo=True) blob_xml = b'<?xml version="1.0" encoding="UTF-8"?>\n' + \ ET.tostring(component, encoding='UTF-8', xml_declaration=False, pretty_print=True) _show_diff(cabarchive[md.filename_xml].buf, blob_xml) cabarchive[md.filename_xml].buf = blob_xml # sign it jcatitem = jcatfile.get_item(md.filename_xml) jcatitem.add_blob(JcatBlobSha1(blob_xml)) jcatitem.add_blob(JcatBlobSha256(blob_xml)) for blob in ploader.archive_sign(blob_xml): jcatitem.add_blob(blob) # write jcat file if jcatfile.items: cabarchive['firmware.jcat'] = CabFile(jcatfile.save()) # overwrite old file cab_data = cabarchive.save() with open(fn, 'wb') as f: f.write(cab_data) # inform the plugin loader ploader.file_modified(fn) # update the download size for md in fw.mds: md.release_download_size = len(cab_data) # update the database fw.checksum_signed_sha1 = hashlib.sha1(cab_data).hexdigest() fw.checksum_signed_sha256 = hashlib.sha256(cab_data).hexdigest() fw.signed_timestamp = datetime.datetime.utcnow() db.session.commit()
def test_cabfile_length(self): self.assertEqual(len(CabFile(b'foofoofoofoofoofoofoofoo')), 24)
def test_create(self): # create new archive arc = CabArchive() arc.set_id = 0x0622 # first example cff = CabFile() cff.buf = (b"#include <stdio.h>\r\n\r\nvoid main(void)\r\n" b'{\r\n printf("Hello, world!\\n");\r\n}\r\n') cff.date = datetime.date(1997, 3, 12) cff.time = datetime.time(11, 13, 52) cff.is_arch = True arc["hello.c"] = cff # second example cff = CabFile() cff.buf = (b"#include <stdio.h>\r\n\r\nvoid main(void)\r\n" b'{\r\n printf("Welcome!\\n");\r\n}\r\n\r\n') cff.date = datetime.date(1997, 3, 12) cff.time = datetime.time(11, 15, 14) cff.is_arch = True arc["welcome.c"] = cff # verify data = arc.save(False) with open("/tmp/test.cab", "wb") as f: f.write(data) expected = ( b"\x4D\x53\x43\x46\x00\x00\x00\x00\xFD\x00\x00\x00\x00\x00\x00\x00" b"\x2C\x00\x00\x00\x00\x00\x00\x00\x03\x01\x01\x00\x02\x00\x00\x00" b"\x22\x06\x00\x00\x5E\x00\x00\x00\x01\x00\x00\x00\x4D\x00\x00\x00" b"\x00\x00\x00\x00\x00\x00\x6C\x22\xBA\x59\x20\x00\x68\x65\x6C\x6C" b"\x6F\x2E\x63\x00\x4A\x00\x00\x00\x4D\x00\x00\x00\x00\x00\x6C\x22" b"\xE7\x59\x20\x00\x77\x65\x6C\x63\x6F\x6D\x65\x2E\x63\x00\xBD\x5A" b"\xA6\x30\x97\x00\x97\x00\x23\x69\x6E\x63\x6C\x75\x64\x65\x20\x3C" b"\x73\x74\x64\x69\x6F\x2E\x68\x3E\x0D\x0A\x0D\x0A\x76\x6F\x69\x64" b"\x20\x6D\x61\x69\x6E\x28\x76\x6F\x69\x64\x29\x0D\x0A\x7B\x0D\x0A" b"\x20\x20\x20\x20\x70\x72\x69\x6E\x74\x66\x28\x22\x48\x65\x6C\x6C" b"\x6F\x2C\x20\x77\x6F\x72\x6C\x64\x21\x5C\x6E\x22\x29\x3B\x0D\x0A" b"\x7D\x0D\x0A\x23\x69\x6E\x63\x6C\x75\x64\x65\x20\x3C\x73\x74\x64" b"\x69\x6F\x2E\x68\x3E\x0D\x0A\x0D\x0A\x76\x6F\x69\x64\x20\x6D\x61" b"\x69\x6E\x28\x76\x6F\x69\x64\x29\x0D\x0A\x7B\x0D\x0A\x20\x20\x20" b"\x20\x70\x72\x69\x6E\x74\x66\x28\x22\x57\x65\x6C\x63\x6F\x6D\x65" b"\x21\x5C\x6E\x22\x29\x3B\x0D\x0A\x7D\x0D\x0A\x0D\x0A") _check_range(bytearray(data), bytearray(expected)) # use cabextract to test validity try: self.assertEqual( subprocess.call(["cabextract", "--test", "/tmp/test.cab"]), 0) except FileNotFoundError as _: pass # check we can parse what we just created arc = CabArchive() with open("/tmp/test.cab", "rb") as f: arc.parse(f.read()) # add an extra file arc["test.inf"] = CabFile(b"$CHICAGO$") # save with compression with open("/tmp/test.cab", "wb") as f: f.write(arc.save(True)) # use cabextract to test validity try: self.assertEqual( subprocess.call(["cabextract", "--test", "/tmp/test.cab"]), 0) except FileNotFoundError as _: pass
def _get_valid_firmware(): return CabFile('fubar'.ljust(1024).encode('utf-8'))