def swupdate_is_hash_needed(s, filename): with open(os.path.join(s, "sw-description"), 'r') as f: for line in f: if line.find("@%s" % (filename)) != -1: return True return False def swupdate_get_sha256(s, filename): import hashlib m = hashlib.sha256() with open(os.path.join(s, filename), 'rb') as f: while True: data = f.read(1024) if not data: break m.update(data) return m.hexdigest() def swupdate_extract_keys(keyfile_path): try: with open(keyfile_path, 'r') as f: lines = f.readlines() except IOError: bb.fatal("Failed to open file with keys %s" % (keyfile)) data = {} for _ in lines: k,v = _.split('=',maxsplit=1) data[k.rstrip()] = v key = data['key'] iv = data['iv'] salt = data['salt'] return key,iv,salt def swupdate_encrypt_file(f, out, key, ivt, salt): import subprocess encargs = ["openssl", "enc", "-aes-256-cbc", "-in", f, "-out", out] encargs += ["-K", key, "-iv", ivt, "-S", salt] cmd = "openssl enc -aes-256-cbc -in '%s' -out '%s' -K '%s' -iv '%s' -S '%s'" % ( f, out, key, ivt, salt) subprocess.run(encargs, check=True) def swupdate_write_sha256(s, filename, hash): write_lines = [] with open(os.path.join(s, "sw-description"), 'r') as f: for line in f: write_lines.append(line.replace("@%s" % (filename), hash)) with open(os.path.join(s, "sw-description"), 'w+') as f: for line in write_lines: f.write(line) def swupdate_expand_bitbake_variables(d, s): write_lines = [] with open(os.path.join(s, "sw-description"), 'r') as f: import re for line in f: found = False while True: m = re.match(r"^(?P.+)@@(?P\w+)@@(?P.+)$", line) if m: bitbake_variable_value = d.getVar(m.group('bitbake_variable_name'), True) if bitbake_variable_value is None: bitbake_variable_value = "" bb.warn("BitBake variable %s not set" % (m.group('bitbake_variable_name'))) line = m.group('before_placeholder') + bitbake_variable_value + m.group('after_placeholder') found = True continue else: m = re.match(r"^(?P.+)@@(?P.+)\[(?P.+)\]@@(?P.+)$", line) if m: bitbake_variable_value = (d.getVarFlag(m.group('bitbake_variable_name'), m.group('flag_var_name'), True) or "") if bitbake_variable_value is None: bitbake_variable_value = "" line = m.group('before_placeholder') + bitbake_variable_value + m.group('after_placeholder') continue if found: line = line + "\n" break write_lines.append(line) with open(os.path.join(s, "sw-description"), 'w+') as f: for line in write_lines: f.write(line) def prepare_sw_description(d, s, list_for_cpio): import shutil swupdate_expand_bitbake_variables(d, s) for file in list_for_cpio: if file != 'sw-description' and swupdate_is_hash_needed(s, file): hash = swupdate_get_sha256(s, file) swupdate_write_sha256(s, file, hash) encrypt = d.getVar('SWUPDATE_ENCRYPT_SWDESC', True) if encrypt: bb.note("Encryption of sw-description") shutil.copyfile(os.path.join(s, 'sw-description'), os.path.join(s, 'sw-description.plain')) key,iv,salt = swupdate_extract_keys(d.getVar('SWUPDATE_AES_FILE', True)) swupdate_encrypt_file(os.path.join(s, 'sw-description.plain'), os.path.join(s, 'sw-description'), key, iv, salt) signing = d.getVar('SWUPDATE_SIGNING', True) if signing == "1": bb.warn('SWUPDATE_SIGNING = "1" is deprecated, falling back to "RSA". It is advised to set it to "RSA" if using RSA signing.') signing = "RSA" if signing: if signing == "CUSTOM": sign_tool = d.getVar('SWUPDATE_SIGN_TOOL', True) if sign_tool: ret = os.system(sign_tool) if ret != 0: bb.fatal("Failed to sign with %s" % (sign_tool)) else: bb.fatal("Custom SWUPDATE_SIGN_TOOL is not given") elif signing == "RSA": privkey = d.getVar('SWUPDATE_PRIVATE_KEY', True) if not privkey: bb.fatal("SWUPDATE_PRIVATE_KEY isn't set") if not os.path.exists(privkey): bb.fatal("SWUPDATE_PRIVATE_KEY %s doesn't exist" % (privkey)) passout = d.getVar('SWUPDATE_PASSWORD_FILE', True) if passout: passout = "-passin file:'%s' " % (passout) else: passout = "" signcmd = "openssl dgst -sha256 -sign '%s' %s -out '%s' '%s'" % ( privkey, passout, os.path.join(s, 'sw-description.sig'), os.path.join(s, 'sw-description.plain' if encrypt else 'sw-description')) if os.system(signcmd) != 0: bb.fatal("Failed to sign sw-description with %s" % (privkey)) elif signing == "CMS": cms_cert = d.getVar('SWUPDATE_CMS_CERT', True) if not cms_cert: bb.fatal("SWUPDATE_CMS_CERT is not set") if not os.path.exists(cms_cert): bb.fatal("SWUPDATE_CMS_CERT %s doesn't exist" % (cms_cert)) cms_key = d.getVar('SWUPDATE_CMS_KEY', True) if not cms_key: bb.fatal("SWUPDATE_CMS_KEY isn't set") if not os.path.exists(cms_key): bb.fatal("SWUPDATE_CMS_KEY %s doesn't exist" % (cms_key)) passout = d.getVar('SWUPDATE_PASSWORD_FILE', True) if passout: passout = "-passin file:'%s' " % (passout) else: passout = "" signcmd = "openssl cms -sign -in '%s' -out '%s' -signer '%s' -inkey '%s' %s -outform DER -nosmimecap -binary" % ( os.path.join(s, 'sw-description.plain' if encrypt else 'sw-description'), os.path.join(s, 'sw-description.sig'), cms_cert, cms_key, passout) if os.system(signcmd) != 0: bb.fatal("Failed to sign sw-description with %s" % (privkey)) else: bb.fatal("Unrecognized SWUPDATE_SIGNING mechanism.");