diff mbox series

[meta,05/12] class: add function that signs and returns hash of artifact

Message ID 20220405071005.3855186-6-sbabic@denx.de
State Changes Requested
Headers show
Series Support to call functions inside sw-description | expand

Commit Message

Stefano Babic April 5, 2022, 7:09 a.m. UTC
This adds swupdate_sign_ec521_sha512 - it can be used to report and store the
hash after signing an artifact. Used to verify the integrity of a
component by the device during boot. This function signs a file with
secp521r1.

There are a lot of ways to sign, and they can be easily added later. The
rule is to add a function with the name swupdate_sign_<signing
algotithm>, and if the function needs OE variables, they should be
created with the name rule SWUPDATE_<algotithm>_<varname>.

Signed-off-by: Stefano Babic <sbabic@denx.de>
---
 classes/swupdate-lib.bbclass | 73 ++++++++++++++++++++++++++++++++++++
 1 file changed, 73 insertions(+)
diff mbox series

Patch

diff --git a/classes/swupdate-lib.bbclass b/classes/swupdate-lib.bbclass
index e69de29..4347b83 100644
--- a/classes/swupdate-lib.bbclass
+++ b/classes/swupdate-lib.bbclass
@@ -0,0 +1,73 @@ 
+DEPENDS += "python3-magic-native zstd-native"
+
+def swupdate_encrypt_file(f, out, key, ivt):
+    import subprocess
+    encargs = ["openssl", "enc", "-aes-256-cbc", "-in", f, "-out", out]
+    encargs += ["-K", key, "-iv", ivt, "-nosalt"]
+    subprocess.run(encargs, check=True)
+
+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'].rstrip('\n')
+    iv = data['iv'].rstrip('\n')
+
+    return key,iv
+
+def swupdate_get_sha256(d, 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_sign_file(d, s, filename):
+    import subprocess
+    import magic
+    import base64
+
+    fname = os.path.join(s, filename)
+    mime = magic.Magic(mime=True)
+    ftype = mime.from_file(fname)
+
+    if ftype == 'application/zstd':
+       zcmd = 'zstdcat'
+    elif ftype == 'application/gzip':
+       zcmd = 'zcat'
+    else:
+       zcmd = 'cat'
+
+    privkey = d.getVar('SWUPDATE_SIGN_PRIVATE_KEY')
+
+    dump = subprocess.run([ zcmd, fname ], check=True, capture_output=True)
+
+    signature = subprocess.run([ "openssl", "dgst", "-keyform", "PEM", "-sha256", "-sign", privkey ] + \
+              get_pwd_file_args(d, 'SWUPDATE_SIGN_PASSWORD_FILE'), check=True, capture_output=True, input=dump.stdout)
+
+    hash = base64.b64encode(signature.stdout).decode()
+
+    # SWUpdate accepts attribute with a maximum size of 255. If the hash
+    # exceeds this value, returns sha256 of the generated hash
+    #  
+    if len(hash) > 255:
+       m = hashlib.sha256()
+       m.update(hash)
+       hash = m.hexdigest()
+
+    return hash
+