| Message ID | BE0P281MB000219D82F0D0B68B1E1A8CE8C822@BE0P281MB0002.DEUP281.PROD.OUTLOOK.COM |
|---|---|
| State | New |
| Headers | show |
| Series | core: accept 128 and 192 bit per-image aes-key | expand |
Hi Raimar, On 9/23/26 11:15, 'Raimar Sandner' via swupdate wrote: > copyfile() passes the size of the destination buffer to ascii_to_bin > which only converts when the hex string has exactly twice that length. > The buffer is AES_256_KEY_LEN, so a per-image "aes-key" in > sw-description is rejected with "Invalid image aes-key" for every key > that is not 256 bit, although the line below already computes keylen > from the string. The global key file has always accepted all three > lengths, so the two ways of supplying a key disagree. > > Derive the length from the string, accept it only if it is one of the > three AES key lengths, and convert exactly that many bytes. > This was to implicitly force to use the strongest key length, and officially only AES-256 is supported. Probably not clear in doc, but see source/swupdate-ipc-interface.rst. Are there any reason to allow weaker length ? Anyway, if this becomes supported, docs must be adjusted as well, and also be sure that IPC is working, int swupdate_set_aes(char *key, char *ivt). Best regards, Stefano > Signed-off-by: Lukas Knöpfle <lukas.knoepfle@sick.de> > Co-developed-by: Raimar Sandner <raimar.sandner@sick.de> > Signed-off-by: Raimar Sandner <raimar.sandner@sick.de> > --- > core/cpio_utils.c | 8 ++++++-- > include/util.h | 7 +++++++ > 2 files changed, 13 insertions(+), 2 deletions(-) > > diff --git a/core/cpio_utils.c b/core/cpio_utils.c > index 9faa8019..4802c390 100644 > --- a/core/cpio_utils.c > +++ b/core/cpio_utils.c > @@ -706,12 +706,16 @@ int copyfile(struct swupdate_copy *args) > ivt = get_aes_ivt(); > > if (args->imgaes && strlen(args->imgaes)) { > - if (!is_hex_str(args->imgaes) || ascii_to_bin(aesbuf, sizeof(aesbuf), args->imgaes)) { > + size_t imgkeylen = strlen(args->imgaes) / 2; > + > + if (!is_valid_aes_keylen(imgkeylen) || > + !is_hex_str(args->imgaes) || > + ascii_to_bin(aesbuf, imgkeylen, args->imgaes)) { > ERROR("Invalid image aes-key"); > return -EINVAL; > } > aes_key = aesbuf; > - keylen = strlen(args->imgaes) / 2; > + keylen = imgkeylen; > } else { > /* > * Only fall back to the default decryption key if the requested cipher matches. > diff --git a/include/util.h b/include/util.h > index 7007d357..4255a126 100644 > --- a/include/util.h > +++ b/include/util.h > @@ -34,6 +34,13 @@ > #define AES_192_KEY_LEN 24 > #define AES_256_KEY_LEN 32 > > +static inline bool is_valid_aes_keylen(size_t keylen) > +{ > + return keylen == AES_128_KEY_LEN || > + keylen == AES_192_KEY_LEN || > + keylen == AES_256_KEY_LEN; > +} > + > #define HWID_REGEXP_PREFIX "#RE:" > > #define BOOTVAR_TRANSACTION "recovery_status"
copyfile() passes the size of the destination buffer to ascii_to_bin which only converts when the hex string has exactly twice that length. The buffer is AES_256_KEY_LEN, so a per-image "aes-key" in sw-description is rejected with "Invalid image aes-key" for every key that is not 256 bit, although the line below already computes keylen from the string. The global key file has always accepted all three lengths, so the two ways of supplying a key disagree. Derive the length from the string, accept it only if it is one of the three AES key lengths, and convert exactly that many bytes. This patch brings the per-image aes-key handling in line with the documentation (sw-description.rst) and the global key file. Note that the IPC interface intentionally only accepts 256 bit keys, as documented in swupdate-ipc-interface.rst. The patch makes sure this limitation is still correctly enforced. Signed-off-by: Lukas Knöpfle <lukas.knoepfle@sick.de> Co-developed-by: Raimar Sandner <raimar.sandner@sick.de> Signed-off-by: Raimar Sandner <raimar.sandner@sick.de> --- v2: revised commit message clarifying the IPC vs aes-key behavior, also fix the overly permissive length check in swupdate_set_aes of network_ipc-if.c core/cpio_utils.c | 8 ++++++-- include/util.h | 7 +++++++ ipc/network_ipc-if.c | 2 +- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/core/cpio_utils.c b/core/cpio_utils.c index ff417d7e..e3aed763 100644 --- a/core/cpio_utils.c +++ b/core/cpio_utils.c @@ -697,12 +697,16 @@ int copyfile(struct swupdate_copy *args) ivt = get_aes_ivt(); if (args->imgaes && strlen(args->imgaes)) { - if (!is_hex_str(args->imgaes) || ascii_to_bin(aesbuf, sizeof(aesbuf), args->imgaes)) { + size_t imgkeylen = strlen(args->imgaes) / 2; + + if (!is_valid_aes_keylen(imgkeylen) || + !is_hex_str(args->imgaes) || + ascii_to_bin(aesbuf, imgkeylen, args->imgaes)) { ERROR("Invalid image aes-key"); return -EINVAL; } aes_key = aesbuf; - keylen = strlen(args->imgaes) / 2; + keylen = imgkeylen; } else { /* * Only fall back to the default decryption key if the requested cipher matches. diff --git a/include/util.h b/include/util.h index 7007d357..4255a126 100644 --- a/include/util.h +++ b/include/util.h @@ -34,6 +34,13 @@ #define AES_192_KEY_LEN 24 #define AES_256_KEY_LEN 32 +static inline bool is_valid_aes_keylen(size_t keylen) +{ + return keylen == AES_128_KEY_LEN || + keylen == AES_192_KEY_LEN || + keylen == AES_256_KEY_LEN; +} + #define HWID_REGEXP_PREFIX "#RE:" #define BOOTVAR_TRANSACTION "recovery_status" diff --git a/ipc/network_ipc-if.c b/ipc/network_ipc-if.c index 7c209ad4..1b43e560 100644 --- a/ipc/network_ipc-if.c +++ b/ipc/network_ipc-if.c @@ -336,7 +336,7 @@ int swupdate_set_aes(char *key, char *ivt) if (!key || !ivt) return -EINVAL; - if (strlen(key) != 64 && strlen(ivt) != 32) + if (strlen(key) != 64 || strlen(ivt) != 32) return -EINVAL; memset(&msg, 0, sizeof(msg)); -- 2.43.0
Dear Stefano,
> Are there any reason to allow weaker length ?
Not for us. If you don't see any need for the smaller key sizes (e.g., low-end
hardware) then only supporting AES256 is totally fine. As of today, however,
there is a discrepancy between using the global key file (which supports the
smaller keys) and the per-image keys. To avoid misunderstandings, this is
probably worth a comment in encrypted_images.rst. This file claims "you may use
other key lengths as well" unconditionally. Also sw-description.rst documents
16, 24 or 32 characters as valid hex-string lengths for the aes-key parameter
in the manifest.
The issue came up when implementing the AEAD (AES-GCM) support and testing it
with per-image keys. We didn't realize the limitation on per-image keys was
intentional, our motivation was to submit this as independent "bug fix" before
the AEAD implementation patches land.
Applying the revised patch I just sent would bring the implementation in line
with the sw-description documentation, and the IPC limitation to only support
256-bit is now correctly checked in network_ipc-if.c, consistent with the
documentation in swupdate-ipc-interface.rst. Not applying this patch and
keeping the behavior as is also works for us.
Either way, here is a quick update on the status of AEAD encryption for
SWUpdate: the student project is feature-complete with solid test coverage. A
short list of blockers remains, which we're closing before the patches go out.
There is still some polishing left to do on the documentation, and we will
conduct a full internal review before sending the patches.
Unfortunately Lukas now has other priorities in his curriculum, and a change in
my availability means I'll be out of office for the next four months. I'm still
fully committed to finishing the project with an upstream contribution, but the
patches will arrive no earlier than February 2027.
Thanks for your support so far!
Raimar
Mit freundlichen Grüßen / Best regards
i.A. Dr. Raimar Sandner
Expert in Industrial Cybersecurity | Autonomous Perception
diff --git a/core/cpio_utils.c b/core/cpio_utils.c index 9faa8019..4802c390 100644 --- a/core/cpio_utils.c +++ b/core/cpio_utils.c @@ -706,12 +706,16 @@ int copyfile(struct swupdate_copy *args) ivt = get_aes_ivt(); if (args->imgaes && strlen(args->imgaes)) { - if (!is_hex_str(args->imgaes) || ascii_to_bin(aesbuf, sizeof(aesbuf), args->imgaes)) { + size_t imgkeylen = strlen(args->imgaes) / 2; + + if (!is_valid_aes_keylen(imgkeylen) || + !is_hex_str(args->imgaes) || + ascii_to_bin(aesbuf, imgkeylen, args->imgaes)) { ERROR("Invalid image aes-key"); return -EINVAL; } aes_key = aesbuf; - keylen = strlen(args->imgaes) / 2; + keylen = imgkeylen; } else { /* * Only fall back to the default decryption key if the requested cipher matches. diff --git a/include/util.h b/include/util.h index 7007d357..4255a126 100644 --- a/include/util.h +++ b/include/util.h @@ -34,6 +34,13 @@ #define AES_192_KEY_LEN 24 #define AES_256_KEY_LEN 32 +static inline bool is_valid_aes_keylen(size_t keylen) +{ + return keylen == AES_128_KEY_LEN || + keylen == AES_192_KEY_LEN || + keylen == AES_256_KEY_LEN; +} + #define HWID_REGEXP_PREFIX "#RE:" #define BOOTVAR_TRANSACTION "recovery_status"