swupdate-lib.bbclass 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. # Copyright (C) 2015-2022 Stefano Babic
  2. #
  3. # SPDX-License-Identifier: GPLv3
  4. DEPENDS += "python3-magic-native zstd-native"
  5. def swupdate_encrypt_file(f, out, key, ivt):
  6. import subprocess
  7. encargs = ["openssl", "enc", "-aes-256-cbc", "-in", f, "-out", out]
  8. encargs += ["-K", key, "-iv", ivt, "-nosalt"]
  9. subprocess.run(encargs, check=True)
  10. def swupdate_extract_keys(keyfile_path):
  11. try:
  12. with open(keyfile_path, 'r') as f:
  13. lines = f.readlines()
  14. except IOError:
  15. bb.fatal("Failed to open file with keys %s" % (keyfile_path))
  16. data = {}
  17. for _ in lines:
  18. k,v = _.split('=',maxsplit=1)
  19. data[k.rstrip()] = v
  20. key = data['key'].rstrip('\n')
  21. iv = data['iv'].rstrip('\n')
  22. return key,iv
  23. def swupdate_get_sha256(d, s, filename):
  24. import hashlib
  25. m = hashlib.sha256()
  26. with open(os.path.join(s, filename), 'rb') as f:
  27. while True:
  28. data = f.read(1024)
  29. if not data:
  30. break
  31. m.update(data)
  32. return m.hexdigest()
  33. def swupdate_get_IV(d, s, filename):
  34. # By default preserve original behavior: use IV from SWUPDATE_AES_FILE.
  35. key,iv = swupdate_extract_keys(d.getVar('SWUPDATE_AES_FILE', True))
  36. return iv
  37. def swupdate_get_unique_IV(d, s, filename):
  38. # New behavior: use unique random IV for each filename.
  39. from secrets import token_hex
  40. iv = d.getVarFlag("SWUPDATE_IV", filename, True)
  41. if not iv:
  42. iv = token_hex(16)
  43. d.setVarFlag("SWUPDATE_IV", filename, iv)
  44. return iv
  45. def swupdate_get_size(d, s, filename):
  46. import os
  47. fname = os.path.join(s, filename)
  48. fsize = os.path.getsize(fname)
  49. return str(fsize)
  50. def swupdate_sign_file(d, s, filename):
  51. import subprocess
  52. import magic
  53. import base64
  54. fname = os.path.join(s, filename)
  55. mime = magic.Magic(mime=True)
  56. ftype = mime.from_file(fname)
  57. if ftype == 'application/zstd':
  58. zcmd = 'zstdcat'
  59. elif ftype == 'application/gzip':
  60. zcmd = 'zcat'
  61. else:
  62. zcmd = 'cat'
  63. privkey = d.getVar('SWUPDATE_SIGN_PRIVATE_KEY')
  64. dump = subprocess.run([ zcmd, fname ], check=True, capture_output=True)
  65. signature = subprocess.run([ "openssl", "dgst", "-keyform", "PEM", "-sha256", "-sign", privkey ] + \
  66. get_pwd_file_args(d, 'SWUPDATE_SIGN_PASSWORD_FILE'), check=True, capture_output=True, input=dump.stdout)
  67. hash = base64.b64encode(signature.stdout).decode()
  68. # SWUpdate accepts attribute with a maximum size of 255. If the hash
  69. # exceeds this value, returns sha256 of the generated hash
  70. #
  71. if len(hash) > 255:
  72. m = hashlib.sha256()
  73. m.update(hash)
  74. hash = m.hexdigest()
  75. return hash
  76. def swupdate_get_pkgvar(d, s, parms):
  77. import re
  78. import oe.packagedata
  79. def get_package_name(group):
  80. package = None
  81. pkgvar = group.split('@')
  82. package = pkgvar[0]
  83. if len(pkgvar) > 1:
  84. varname = pkgvar[1]
  85. else:
  86. varname = 'PV'
  87. return (package, varname)
  88. if parms is None:
  89. return "undefined"
  90. group = parms
  91. (package, key) = get_package_name(group)
  92. bb.debug(2, "Package %s defined %s" %(package, key))
  93. pkg_info = os.path.join(d.getVar('PKGDATA_DIR'), 'runtime-reverse', package)
  94. pkgdata = oe.packagedata.read_pkgdatafile(pkg_info)
  95. if not key in pkgdata.keys():
  96. bb.warn("\"%s\" not set for package %s - using \"1.0\"" % (key, package))
  97. version = "1.0"
  98. else:
  99. version = pkgdata[key].split('+')[0]
  100. return version