[PATCH 00/11] Support encrypted images

293 views
Skip to first unread message

Stefano Babic

unread,
Aug 10, 2016, 3:48:24 AM8/10/16
to swup...@googlegroups.com, Stefano Babic
The series adds support for encrypted images. The encryption
is set at the image level, allowing to combine encrypted
and not encrypted images in the same compound image .swu

The only supported algorythm is AES-256. The symmetric
key must be stored in a protected file (accessible to SWUpdate)
that is read by SWUpdate at the start up.


Stefano Babic (11):
Added decryption functions
Add encrypted attribute
Synchronize external parser
Replace copyfile function for handlers with easier copyimage
copyfile: add parameter to decrypt image
copyfile: let the function reantrant
copyfile: add a callback to write the image
util.c: add function to load symmetric key
Load symmetric key for decryption
copyfile: add image decryption
Support for encrypted scripts

Kconfig | 6 ++
Makefile.flags | 5 ++
core/cpio_utils.c | 125 ++++++++++++++++++++++++++++++++++++------
core/handler.c | 3 +-
core/swupdate.c | 33 +++++++++++
core/util.c | 71 +++++++++++++++++++++++-
corelib/Makefile | 1 +
corelib/installer.c | 3 +-
corelib/stream_interface.c | 6 +-
corelib/swupdate_decrypt.c | 96 ++++++++++++++++++++++++++++++++
corelib/verify_signature.c | 21 +++----
doc/source/sw-description.rst | 5 ++
handlers/archive_handler.c | 6 +-
handlers/flash_handler.c | 4 +-
handlers/raw_handler.c | 12 +---
handlers/ubivol_handler.c | 13 ++---
handlers/uboot_handler.c | 4 +-
include/sslapi.h | 45 ++++++++++++++-
include/swupdate.h | 1 +
include/util.h | 17 +++++-
parser/parse_external.c | 24 +++++++-
parser/parser.c | 4 ++
22 files changed, 435 insertions(+), 70 deletions(-)
create mode 100644 corelib/swupdate_decrypt.c

--
2.7.4

Stefano Babic

unread,
Aug 10, 2016, 3:48:25 AM8/10/16
to swup...@googlegroups.com, Stefano Babic
Functions as preparation to support encrypted
images.

Signed-off-by: Stefano Babic <sba...@denx.de>
---
Makefile.flags | 5 +++
corelib/Makefile | 1 +
corelib/swupdate_decrypt.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++
corelib/verify_signature.c | 21 +++++-----
include/sslapi.h | 45 +++++++++++++++++++++-
5 files changed, 155 insertions(+), 13 deletions(-)
create mode 100644 corelib/swupdate_decrypt.c

diff --git a/Makefile.flags b/Makefile.flags
index 72e3327..e058d22 100644
--- a/Makefile.flags
+++ b/Makefile.flags
@@ -126,6 +126,11 @@ ifneq ($(CONFIG_SIGNED_IMAGES),)
LDLIBS += crypto ssl
endif

+# signed images require openssl (digest)
+ifneq ($(CONFIG_ENCRYPTED_IMAGES),)
+LDLIBS += crypto ssl
+endif
+
# mongoose / webserver
ifneq ($(CONFIG_WEBSERVER),)
ifneq ($(CONFIG_MONGOOSESSL),)
diff --git a/corelib/Makefile b/corelib/Makefile
index f39b92c..db36419 100644
--- a/corelib/Makefile
+++ b/corelib/Makefile
@@ -6,3 +6,4 @@ lib-$(CONFIG_DOWNLOAD) += downloader.o
lib-$(CONFIG_MTD) += mtd-interface.o
lib-$(CONFIG_LUA) += lua_interface.o
lib-$(CONFIG_SIGNED_IMAGES) += verify_signature.o
+lib-$(CONFIG_ENCRYPTED_IMAGES) += swupdate_decrypt.o
diff --git a/corelib/swupdate_decrypt.c b/corelib/swupdate_decrypt.c
new file mode 100644
index 0000000..027ddbe
--- /dev/null
+++ b/corelib/swupdate_decrypt.c
@@ -0,0 +1,96 @@
+/*
+ * (C) Copyright 2016
+ * Stefano Babic, DENX Software Engineering, sba...@denx.de.
+ *
+ * Code mostly taken from openssl examples
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include "swupdate.h"
+#include "sslapi.h"
+#include "util.h"
+
+struct swupdate_digest *swupdate_DECRYPT_init(unsigned char *key, unsigned char *iv)
+{
+ struct swupdate_digest *dec;
+ int ret;
+
+ dec = calloc(1, sizeof(*dec));
+ if (!dec) {
+ return NULL;
+ }
+
+ EVP_CIPHER_CTX_init(&dec->ctxdec);
+
+ /*
+ * Check openSSL documentation for return errors
+ */
+ ret = EVP_DecryptInit_ex(&dec->ctxdec, EVP_aes_256_cbc(), NULL, key, iv);
+ if (ret != 1) {
+ ERROR("Decrypt Engine not initialized, error 0x%lx\n", ERR_get_error());
+ free(dec);
+ return NULL;
+ }
+#if 0
+ if(!EVP_DecryptInit_ex(&dec->ctxdec, NULL, NULL, NULL, NULL)){
+ ERROR("ERROR in EVP_DecryptInit_ex, 0x%lx\n", ERR_get_error());
+ free(dec);
+ return NULL;
+ }
+#endif
+
+ return dec;
+}
+
+int swupdate_DECRYPT_update(struct swupdate_digest *dgst, unsigned char *buf,
+ int *outlen, unsigned char *cryptbuf, int inlen)
+{
+ if (EVP_DecryptUpdate(&dgst->ctxdec, buf, outlen, cryptbuf, inlen) != 1) {
+ ERROR("Decryption error 0x%lx\n", ERR_get_error());
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+int swupdate_DECRYPT_final(struct swupdate_digest *dgst, unsigned char *buf,
+ int *outlen)
+{
+ if (!dgst)
+ return -EINVAL;
+
+ if (EVP_DecryptFinal_ex(&dgst->ctxdec, buf, outlen) != 1) {
+ ERROR("Decryption error 0x%s\n",
+ ERR_reason_error_string(ERR_get_error()));
+ return -EFAULT;
+ }
+
+ return 0;
+
+}
+
+void swupdate_DECRYPT_cleanup(struct swupdate_digest *dgst)
+{
+ if (dgst) {
+ EVP_CIPHER_CTX_cleanup(&dgst->ctxdec);
+ free(dgst);
+ dgst = NULL;
+ }
+}
diff --git a/corelib/verify_signature.c b/corelib/verify_signature.c
index a05cf40..4936c3b 100644
--- a/corelib/verify_signature.c
+++ b/corelib/verify_signature.c
@@ -158,6 +158,15 @@ int swupdate_HASH_final(struct swupdate_digest *dgst, unsigned char *md_value,

}

+void swupdate_HASH_cleanup(struct swupdate_digest *dgst)
+{
+ if (dgst) {
+ EVP_MD_CTX_destroy(dgst->ctx);
+ free(dgst);
+ dgst = NULL;
+ }
+}
+
int swupdate_verify_file(struct swupdate_digest *dgst, const char *sigfile,
const char *file)
{
@@ -271,9 +280,6 @@ int swupdate_dgst_init(struct swupdate_cfg *sw, const char *keyfile)
return -EBUSY;
}

- CRYPTO_malloc_init();
- OpenSSL_add_all_algorithms();
-
dgst = calloc(1, sizeof(*dgst));
if (!dgst) {
ret = -ENOMEM;
@@ -310,12 +316,3 @@ dgst_init_error:

return ret;
}
-
-void swupdate_HASH_cleanup(struct swupdate_digest *dgst)
-{
- if (dgst) {
- EVP_MD_CTX_destroy(dgst->ctx);
- free(dgst);
- dgst = NULL;
- }
-}
diff --git a/include/sslapi.h b/include/sslapi.h
index 807223e..ee86485 100644
--- a/include/sslapi.h
+++ b/include/sslapi.h
@@ -20,7 +20,11 @@
#ifndef _SWUPDATE_SSL_H
#define _SWUPDATE_SSL_H

-#ifdef CONFIG_SIGNED_IMAGES
+/*
+ * openSSL is not mandatory
+ * Let compile when openSSL is not activated
+ */
+#if defined(CONFIG_SIGNED_IMAGES) || defined(CONFIG_ENCRYPTED_IMAGES)

#include <openssl/bio.h>
#include <openssl/objects.h>
@@ -30,12 +34,31 @@
#include <openssl/pem.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
+#include <openssl/aes.h>

struct swupdate_digest {
EVP_PKEY *pkey;
EVP_MD_CTX *ctx;
+ EVP_CIPHER_CTX ctxdec;
};

+/*
+ * This just initialize globally the openSSL
+ * library
+ * It must be called just once
+ */
+#define swupdate_crypto_init() { \
+ do { \
+ CRYPTO_malloc_init(); \
+ OpenSSL_add_all_algorithms(); \
+ } while (0); \
+}
+#else
+#define swupdate_crypto_init()
+#define AES_BLOCK_SIZE 16
+#endif
+
+#if defined(CONFIG_SIGNED_IMAGES)
int swupdate_dgst_init(struct swupdate_cfg *sw, const char *keyfile);
struct swupdate_digest *swupdate_HASH_init(void);
int swupdate_HASH_update(struct swupdate_digest *dgst, unsigned char *buf,
@@ -46,6 +69,8 @@ void swupdate_HASH_cleanup(struct swupdate_digest *dgst);
int swupdate_verify_file(struct swupdate_digest *dgst, const char *sigfile,
const char *file);
int swupdate_HASH_compare(unsigned char *hash1, unsigned char *hash2);
+
+
#else
#define swupdate_dgst_init(sw, keyfile) ( 0 )
#define swupdate_HASH_init(p) ( NULL )
@@ -56,5 +81,23 @@ int swupdate_HASH_compare(unsigned char *hash1, unsigned char *hash2);
#define swupdate_HASH_compare(hash1,hash2) (0)
#endif

+#ifdef CONFIG_ENCRYPTED_IMAGES
+struct swupdate_digest *swupdate_DECRYPT_init(unsigned char *key, unsigned char *iv);
+int swupdate_DECRYPT_update(struct swupdate_digest *dgst, unsigned char *buf,
+ int *outlen, unsigned char *cryptbuf, int inlen);
+int swupdate_DECRYPT_final(struct swupdate_digest *dgst, unsigned char *buf,
+ int *outlen);
+void swupdate_DECRYPT_cleanup(struct swupdate_digest *dgst);
+#else
+/*
+ * Note: macro for swupdate_DECRYPT_init is
+ * just to avoid compiler warnings
+ */
+#define swupdate_DECRYPT_init(key, iv) (((key != NULL) | (ivt != NULL)) ? NULL : NULL)
+#define swupdate_DECRYPT_update(p, buf, len, cbuf, inlen) (-1)
+#define swupdate_DECRYPT_final(p, buf, len) (-1)
+#define swupdate_DECRYPT_cleanup(p)
+#endif
+
#endif

--
2.7.4

Stefano Babic

unread,
Aug 10, 2016, 3:48:26 AM8/10/16
to swup...@googlegroups.com, Stefano Babic
Synchronize attribute between parsers.

Signed-off-by: Stefano Babic <sba...@denx.de>
---
parser/parse_external.c | 24 +++++++++++++++++++++++-
1 file changed, 23 insertions(+), 1 deletion(-)

diff --git a/parser/parse_external.c b/parser/parse_external.c
index 605d10a..7c5cce2 100644
--- a/parser/parse_external.c
+++ b/parser/parse_external.c
@@ -47,20 +47,34 @@ static void sw_append_stream(struct img_type *img, const char *key,
if (!strcmp(key, "type"))
strncpy(img->type, value,
sizeof(img->type));
- if (!strcmp(key, "name")) {
+ if (!strcmp(key, "filename")) {
strncpy(img->fname, value,
sizeof(img->fname));
img->required = 1;
}
+ if (!strcmp(key, "name")) {
+ strncpy(img->id.name, value,
+ sizeof(img->id.name));
+ }
+ if (!strcmp(key, "version")) {
+ strncpy(img->id.version, value,
+ sizeof(img->id.version));
+ }
if (!strcmp(key, "mtdname") || !strcmp(key, "dest"))
strncpy(img->path, value,
sizeof(img->path));
+ if (!strcmp(key, "filesystem"))
+ strncpy(img->filesystem, value,
+ sizeof(img->filesystem));
if (!strcmp(key, "volume"))
strncpy(img->volname, value,
sizeof(img->volname));
if (!strcmp(key, "device_id"))
strncpy(img->device, value,
sizeof(img->device));
+ if (!strcmp(key, "device"))
+ strncpy(img->device, value,
+ sizeof(img->device));
if (!strcmp(key, "script"))
img->is_script = 1;
if (!strcmp(key, "path"))
@@ -68,6 +82,14 @@ static void sw_append_stream(struct img_type *img, const char *key,
sizeof(img->path));
if (!strcmp(key, "sha256"))
ascii_to_hash(img->sha256, value);
+ if (!strcmp(key, "encrypted"))
+ img->is_encrypted = 1;
+ if (!strcmp(key, "compressed"))
+ img->compressed = 1;
+ if (!strcmp(key, "installed-directly"))
+ img->install_directly = 1;
+ if (!strcmp(key, "install-if-different"))
+ img->id.install_if_different = 1;
}

int parse_external(struct swupdate_cfg *software, const char *filename)
--
2.7.4

Stefano Babic

unread,
Aug 10, 2016, 3:48:27 AM8/10/16
to swup...@googlegroups.com, Stefano Babic
To support encrypted image, add an "encrypted"
attribute. This simply signals that the image was
encrypted and must be decrypted before installing.

Hash is computed on the encrypted image if
SIGNED_IMAGE is set.

Signed-off-by: Stefano Babic <sba...@denx.de>
---
doc/source/sw-description.rst | 5 +++++
include/swupdate.h | 1 +
parser/parser.c | 4 ++++
3 files changed, 10 insertions(+)

diff --git a/doc/source/sw-description.rst b/doc/source/sw-description.rst
index 7d2f540..ec28fac 100644
--- a/doc/source/sw-description.rst
+++ b/doc/source/sw-description.rst
@@ -609,3 +609,8 @@ There are 4 main sections inside sw-description:
| different | | files | if set, name and version are |
| | | | compared with the entries in |
+-------------+----------+------------+---------------------------------------+
+| encrypted | boolean | images | flag |
+| | | files | if set, file is encrypted |
+| | | scripts | and must be decrypted before |
+| | | | installing. |
++-------------+----------+------------+---------------------------------------+
diff --git a/include/swupdate.h b/include/swupdate.h
index 2c8c537..784f39d 100644
--- a/include/swupdate.h
+++ b/include/swupdate.h
@@ -71,6 +71,7 @@ struct img_type {
int required;
int provided;
int compressed;
+ int is_encrypted;
int install_directly;
int is_script;
int is_partitioner;
diff --git a/parser/parser.c b/parser/parser.c
index efeb1b6..1cdedaf 100644
--- a/parser/parser.c
+++ b/parser/parser.c
@@ -527,6 +527,8 @@ static void parse_scripts(parsertype p, void *cfg, struct swupdate_cfg *swcfg)
GET_FIELD_STRING(p, elem, "type", script->type);
get_hash_value(p, elem, script->sha256);

+ get_field(p, elem, "encrypted", &script->is_encrypted);
+
/* Scripts as default call the LUA interpreter */
if (!strlen(script->type)) {
strcpy(script->type, "lua");
@@ -634,6 +636,7 @@ static void parse_images(parsertype p, void *cfg, struct swupdate_cfg *swcfg)
get_field(p, elem, "compressed", &image->compressed);
get_field(p, elem, "installed-directly", &image->install_directly);
get_field(p, elem, "install-if-different", &image->id.install_if_different);
+ get_field(p, elem, "encrypted", &image->is_encrypted);

TRACE("Found %sImage %s %s: %s in %s : %s for handler %s%s %s\n",
image->compressed ? "compressed " : "",
@@ -699,6 +702,7 @@ static void parse_files(parsertype p, void *cfg, struct swupdate_cfg *swcfg)
get_field(p, elem, "compressed", &file->compressed);
get_field(p, elem, "installed-directly", &file->install_directly);
get_field(p, elem, "install-if-different", &file->id.install_if_different);
+ get_field(p, elem, "encrypted", &file->is_encrypted);
TRACE("Found %sFile %s %s: %s --> %s (%s) %s\n",
file->compressed ? "compressed " : "",
file->id.name,
--
2.7.4

Stefano Babic

unread,
Aug 10, 2016, 3:48:28 AM8/10/16
to swup...@googlegroups.com, Stefano Babic
copyfile() takes care of a lot of parameters. Handlers
do not need all of them and the interface for the handler
appears confuse.

Simplify the interface for the handler introducing a simpler
copyimage(int , struct img_type *) function. All parameters
for extracting a copying a single image can be derived
from the img_type struct.

Signed-off-by: Stefano Babic <sba...@denx.de>
---
core/cpio_utils.c | 12 ++++++++++++
handlers/archive_handler.c | 6 +-----
handlers/flash_handler.c | 4 +---
handlers/raw_handler.c | 12 +++---------
handlers/ubivol_handler.c | 13 +++++--------
handlers/uboot_handler.c | 4 +---
include/util.h | 1 +
7 files changed, 24 insertions(+), 28 deletions(-)

diff --git a/core/cpio_utils.c b/core/cpio_utils.c
index df120ce..4781e04 100644
--- a/core/cpio_utils.c
+++ b/core/cpio_utils.c
@@ -213,6 +213,18 @@ int copyfile(int fdin, int fdout, int nbytes, unsigned long *offs,
return 0;
}

+int copyimage(int fdout, struct img_type *img)
+{
+ return copyfile(img->fdin,
+ fdout,
+ img->size,
+ (unsigned long *)&img->offset,
+ 0, /* no skip */
+ img->compressed,
+ &img->checksum,
+ img->sha256);
+}
+
int extract_cpio_header(int fd, struct filehdr *fhdr, unsigned long *offset)
{
unsigned char buf[256];
diff --git a/handlers/archive_handler.c b/handlers/archive_handler.c
index 9ce79f2..4a57ed1 100644
--- a/handlers/archive_handler.c
+++ b/handlers/archive_handler.c
@@ -148,8 +148,6 @@ static int install_archive_image(struct img_type *img,
char path[255];
int fdout;
int ret = 0;
- uint32_t checksum = 0;
- unsigned long offset;
char pwd[256];
struct extract_data tf;
pthread_attr_t attr;
@@ -210,9 +208,7 @@ static int install_archive_image(struct img_type *img,

fdout = open(FIFO, O_WRONLY);

- offset = img->offset;
- ret = copyfile(img->fdin, fdout, img->size, &offset, 0,
- img->compressed, &checksum, img->sha256);
+ ret = copyimage(fdout, img);
if (ret< 0) {
ERROR("Error copying extracted file\n");
return -EFAULT;
diff --git a/handlers/flash_handler.c b/handlers/flash_handler.c
index 7fe5e64..3365dcc 100644
--- a/handlers/flash_handler.c
+++ b/handlers/flash_handler.c
@@ -636,8 +636,6 @@ static int flash_write_nor(int mtdnum, struct img_type *img)
int fdout;
char mtd_device[LINESIZE];
int ret;
- uint32_t checksum;
- long unsigned int dummy = 0;
struct flash_description *flash = get_flash_info();

if (!mtd_dev_present(flash->libmtd, mtdnum)) {
@@ -651,7 +649,7 @@ static int flash_write_nor(int mtdnum, struct img_type *img)
return -1;
}

- ret = copyfile(img->fdin, fdout, img->size, &dummy, 0, 0, &checksum, img->sha256);
+ ret = copyimage(fdout, img);

/* tell 'nbytes == 0' (EOF) from 'nbytes < 0' (read error) */
if (ret < 0) {
diff --git a/handlers/raw_handler.c b/handlers/raw_handler.c
index c436225..0c885b0 100644
--- a/handlers/raw_handler.c
+++ b/handlers/raw_handler.c
@@ -41,8 +41,6 @@ static int install_raw_image(struct img_type *img,
{
int ret;
int fdout;
- unsigned long offset = 0;
- uint32_t checksum;

fdout = open(img->device, O_RDWR);
if (fdout < 0) {
@@ -51,8 +49,8 @@ static int install_raw_image(struct img_type *img,
return -1;
}

- ret = copyfile(img->fdin, fdout, img->size, &offset, 0, img->compressed,
- &checksum, img->sha256);
+ ret = copyimage(fdout, img);
+
close(fdout);
return ret;
}
@@ -63,8 +61,6 @@ static int install_raw_file(struct img_type *img,
char path[255];
int fdout;
int ret = 0;
- uint32_t checksum = 0;
- unsigned long offset = 0;
int use_mount = (strlen(img->device) && strlen(img->filesystem)) ? 1 : 0;

if (strlen(img->path) == 0) {
@@ -89,9 +85,7 @@ static int install_raw_file(struct img_type *img,
TRACE("Installing file %s on %s\n",
img->fname, path);
fdout = openfileoutput(path);
- offset = img->offset;
- ret = copyfile(img->fdin, fdout, img->size, &offset, 0,
- img->compressed, &checksum, img->sha256);
+ ret = copyimage(fdout, img);
if (ret< 0) {
ERROR("Error copying extracted file\n");
}
diff --git a/handlers/ubivol_handler.c b/handlers/ubivol_handler.c
index 77db1a9..0d7788c 100644
--- a/handlers/ubivol_handler.c
+++ b/handlers/ubivol_handler.c
@@ -46,15 +46,13 @@ static struct ubi_part *search_volume(const char *str, struct ubilist *list)
return NULL;
}

-static int update_volume(libubi_t libubi, int fdsw, struct img_type *img,
+static int update_volume(libubi_t libubi, struct img_type *img,
struct ubi_vol_info *vol)
{
long long bytes;
int fdout;
char node[64];
int err;
- unsigned long offset = 0;
- uint32_t checksum = 0;
char sbuf[128];

bytes = img->size;
@@ -104,10 +102,9 @@ static int update_volume(libubi_t libubi, int fdsw, struct img_type *img,
img->fname, node, img->volname);
notify(RUN, RECOVERY_NO_ERROR, sbuf);

- TRACE("Updating UBI : %s %lld %lu\n",
- img->fname, img->size, offset);
- if (copyfile(fdsw, fdout, img->size, (unsigned long *)&img->offset, 0,
- img->compressed, &checksum, img->sha256) < 0) {
+ TRACE("Updating UBI : %s %lld\n",
+ img->fname, img->size);
+ if (copyimage(fdout, img) < 0) {
ERROR("Error copying extracted file");
err = -1;
}
@@ -140,7 +137,7 @@ static int install_ubivol_image(struct img_type *img,
img->volname);
return -1;
}
- ret = update_volume(flash->libubi, img->fdin, img,
+ ret = update_volume(flash->libubi, img,
&ubivol->vol_info);
return ret;

diff --git a/handlers/uboot_handler.c b/handlers/uboot_handler.c
index 4bdb6a5..2d51113 100644
--- a/handlers/uboot_handler.c
+++ b/handlers/uboot_handler.c
@@ -37,8 +37,6 @@ static int install_uboot_environment(struct img_type *img,
{
int ret;
int fdout;
- uint32_t checksum = 0;
- unsigned long dummy;
char buf[64];

char filename[64];
@@ -52,7 +50,7 @@ static int install_uboot_environment(struct img_type *img,
* U-Boot environment is set inside sw-description
* there is no hash but sw-description was already verified
*/
- ret = copyfile(img->fdin, fdout, img->size, &dummy, 0, 0, &checksum, NULL);
+ ret = copyimage(fdout, img);
close(fdout);
}

diff --git a/include/util.h b/include/util.h
index abba6be..e71f6e8 100644
--- a/include/util.h
+++ b/include/util.h
@@ -128,6 +128,7 @@ int fw_set_one_env(const char *name, const char *value);
int openfile(const char *filename);
int copyfile(int fdin, int fdout, int nbytes, unsigned long *offs,
int skip_file, int compressed, uint32_t *checksum, unsigned char *hash);
+int copyimage(int fdout, struct img_type *img);
off_t extract_sw_description(int fd, const char *descfile, off_t start);
off_t extract_next_file(int fd, int fdout, off_t start, int compressed,
unsigned char *hash);
--
2.7.4

Stefano Babic

unread,
Aug 10, 2016, 3:48:29 AM8/10/16
to swup...@googlegroups.com, Stefano Babic
Prepare image decryption allowing to have
an additional parametr to copyfile() to signal
if the image was encrypted.

Signed-off-by: Stefano Babic <sba...@denx.de>
---
core/cpio_utils.c | 16 +++++++++++-----
corelib/stream_interface.c | 6 +++---
include/util.h | 3 ++-
3 files changed, 16 insertions(+), 9 deletions(-)

diff --git a/core/cpio_utils.c b/core/cpio_utils.c
index 4781e04..88ddfca 100644
--- a/core/cpio_utils.c
+++ b/core/cpio_utils.c
@@ -120,7 +120,7 @@ static int copy_write(int fd, const void *buf, int len)

int copyfile(int fdin, int fdout, int nbytes, unsigned long *offs,
int skip_file, int __attribute__ ((__unused__)) compressed,
- uint32_t *checksum, unsigned char *hash)
+ uint32_t *checksum, unsigned char *hash, int encrypted)
{
unsigned long size;
unsigned long filesize = nbytes;
@@ -145,6 +145,11 @@ int copyfile(int fdin, int fdout, int nbytes, unsigned long *offs,

#ifdef CONFIG_GUNZIP
if (compressed) {
+ if (encrypted) {
+ ERROR("encrypted zip images are not yet supported -- aborting\n");
+ return -EINVAL;
+ }
+
ret = decompress_image(fdin, offs, nbytes, fdout, checksum, dgst);
if (ret < 0) {
ERROR("gunzip failure %d (errno %d) -- aborting\n", ret, errno);
@@ -222,7 +227,8 @@ int copyimage(int fdout, struct img_type *img)
0, /* no skip */
img->compressed,
&img->checksum,
- img->sha256);
+ img->sha256,
+ img->is_encrypted);
}

int extract_cpio_header(int fd, struct filehdr *fhdr, unsigned long *offset)
@@ -284,7 +290,7 @@ off_t extract_sw_description(int fd, const char *descfile, off_t start)
ERROR("CPIO file corrupted : %s\n", strerror(errno));
return -1;
}
- if (copyfile(fd, fdout, fdh.size, &offset, 0, 0, &checksum, NULL) < 0) {
+ if (copyfile(fd, fdout, fdh.size, &offset, 0, 0, &checksum, NULL, 0) < 0) {
ERROR("%s corrupted or not valid\n", descfile);
return -1;
}
@@ -345,7 +351,7 @@ off_t extract_next_file(int fd, int fdout, off_t start, int compressed,

if (lseek(fd, offset, SEEK_SET) < 0)
ERROR("CPIO file corrupted : %s\n", strerror(errno));
- if (copyfile(fd, fdout, fdh.size, &offset, 0, compressed, &checksum, hash) < 0) {
+ if (copyfile(fd, fdout, fdh.size, &offset, 0, compressed, &checksum, hash, 0) < 0) {
ERROR("Error copying extracted file\n");
}

@@ -394,7 +400,7 @@ int cpio_scan(int fd, struct swupdate_cfg *cfg, off_t start)
* use copyfile for checksum verification, as we skip file
* we do not have to provide fdout
*/
- if (copyfile(fd, 0, fdh.size, &offset, 1, 0, &checksum, NULL) != 0) {
+ if (copyfile(fd, 0, fdh.size, &offset, 1, 0, &checksum, NULL, 0) != 0) {
ERROR("invalid archive\n");
return -1;
}
diff --git a/corelib/stream_interface.c b/corelib/stream_interface.c
index 41dd605..7f7bd25 100644
--- a/corelib/stream_interface.c
+++ b/corelib/stream_interface.c
@@ -104,7 +104,7 @@ static int extract_file_to_tmp(int fd, const char *fname, unsigned long *poffs)
if (fdout < 0)
return -1;

- if (copyfile(fd, fdout, fdh.size, poffs, 0, 0, &checksum, NULL) < 0) {
+ if (copyfile(fd, fdout, fdh.size, poffs, 0, 0, &checksum, NULL, 0) < 0) {
return -1;
}
if (checksum != (uint32_t)fdh.chksum) {
@@ -206,7 +206,7 @@ static int extract_files(int fd, struct swupdate_cfg *software)
fdout = openfileoutput(img->extract_file);
if (fdout < 0)
return -1;
- if (copyfile(fd, fdout, fdh.size, &offset, 0, 0, &checksum, img->sha256) < 0) {
+ if (copyfile(fd, fdout, fdh.size, &offset, 0, 0, &checksum, img->sha256, 0) < 0) {
return -1;
}
if (checksum != (unsigned long)fdh.chksum) {
@@ -218,7 +218,7 @@ static int extract_files(int fd, struct swupdate_cfg *software)
break;

case SKIP_FILE:
- if (copyfile(fd, fdout, fdh.size, &offset, skip, 0, &checksum, NULL) < 0) {
+ if (copyfile(fd, fdout, fdh.size, &offset, skip, 0, &checksum, NULL, 0) < 0) {
return -1;
}
if (checksum != (unsigned long)fdh.chksum) {
diff --git a/include/util.h b/include/util.h
index e71f6e8..ad38329 100644
--- a/include/util.h
+++ b/include/util.h
@@ -127,7 +127,8 @@ int decompress_image(int infile, unsigned long *offs, int nbytes,
int fw_set_one_env(const char *name, const char *value);
int openfile(const char *filename);
int copyfile(int fdin, int fdout, int nbytes, unsigned long *offs,
- int skip_file, int compressed, uint32_t *checksum, unsigned char *hash);
+ int skip_file, int compressed, uint32_t *checksum,
+ unsigned char *hash, int encrypted);
int copyimage(int fdout, struct img_type *img);
off_t extract_sw_description(int fd, const char *descfile, off_t start);
off_t extract_next_file(int fd, int fdout, off_t start, int compressed,
--
2.7.4

Stefano Babic

unread,
Aug 10, 2016, 3:48:29 AM8/10/16
to swup...@googlegroups.com, Stefano Babic
Use dynamic alloacted buffer instead of static to
allow calling the function from multiple threads.
This can be useful in future.

Signed-off-by: Stefano Babic <sba...@denx.de>
---
core/cpio_utils.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/core/cpio_utils.c b/core/cpio_utils.c
index 88ddfca..20b7e04 100644
--- a/core/cpio_utils.c
+++ b/core/cpio_utils.c
@@ -43,8 +43,6 @@

#define NPAD_BYTES(o) ((4 - (o % 4)) % 4)

-static unsigned char in[BUFF_SIZE];
-
static int get_cpiohdr(unsigned char *buf, long *size, long *namesize, long *chksum)
{
struct new_ascii_header *cpiohdr;
@@ -123,6 +121,7 @@ int copyfile(int fdin, int fdout, int nbytes, unsigned long *offs,
uint32_t *checksum, unsigned char *hash, int encrypted)
{
unsigned long size;
+ unsigned char *in;
unsigned long filesize = nbytes;
unsigned int percent, prevpercent = 0;
int ret;
@@ -142,17 +141,22 @@ int copyfile(int fdin, int fdout, int nbytes, unsigned long *offs,
if (checksum)
*checksum = 0;

+ in = (unsigned char *)malloc(BUFF_SIZE);
+ if (!in)
+ return -ENOMEM;

#ifdef CONFIG_GUNZIP
if (compressed) {
if (encrypted) {
ERROR("encrypted zip images are not yet supported -- aborting\n");
+ free(in);
return -EINVAL;
}

ret = decompress_image(fdin, offs, nbytes, fdout, checksum, dgst);
if (ret < 0) {
ERROR("gunzip failure %d (errno %d) -- aborting\n", ret, errno);
+ free(in);
return ret;
}
}
@@ -164,6 +168,7 @@ int copyfile(int fdin, int fdout, int nbytes, unsigned long *offs,

if ((ret = fill_buffer(fdin, in, size, offs, checksum, dgst) < 0)) {
close(fdout);
+ free(in);
return ret;
}

@@ -179,6 +184,7 @@ int copyfile(int fdin, int fdout, int nbytes, unsigned long *offs,
*/
if (copy_write(fdout, in, size) < 0) {
close(fdout);
+ free(in);
return -ENOSPC;
}

@@ -209,12 +215,15 @@ int copyfile(int fdin, int fdout, int nbytes, unsigned long *offs,

ERROR("HASH mismatch : %s <--> %s",
hashstring, newhashstring);
+ free(in);
return -EFAULT;
}
}

fill_buffer(fdin, in, NPAD_BYTES(*offs), offs, checksum, NULL);

+ free(in);
+
return 0;
}

--
2.7.4

Stefano Babic

unread,
Aug 10, 2016, 3:48:32 AM8/10/16
to swup...@googlegroups.com, Stefano Babic
Some handlers can need to write theiselves
the image instead of implicitely call the write()
function from copyfile / copyimage. Add a callback
to copyimage(), and adjust all handlers to the new
interface.

Signed-off-by: Stefano Babic <sba...@denx.de>
---
core/cpio_utils.c | 18 +++++++++++-------
corelib/stream_interface.c | 6 +++---
handlers/archive_handler.c | 2 +-
handlers/flash_handler.c | 2 +-
handlers/raw_handler.c | 4 ++--
handlers/ubivol_handler.c | 2 +-
handlers/uboot_handler.c | 2 +-
include/util.h | 9 +++++++--
8 files changed, 27 insertions(+), 18 deletions(-)

diff --git a/core/cpio_utils.c b/core/cpio_utils.c
index 20b7e04..b987656 100644
--- a/core/cpio_utils.c
+++ b/core/cpio_utils.c
@@ -118,7 +118,7 @@ static int copy_write(int fd, const void *buf, int len)

int copyfile(int fdin, int fdout, int nbytes, unsigned long *offs,
int skip_file, int __attribute__ ((__unused__)) compressed,
- uint32_t *checksum, unsigned char *hash, int encrypted)
+ uint32_t *checksum, unsigned char *hash, int encrypted, writeimage callback)
{
unsigned long size;
unsigned char *in;
@@ -132,6 +132,9 @@ int copyfile(int fdin, int fdout, int nbytes, unsigned long *offs,
*/
unsigned int md_len = 0;

+ if (!callback)
+ callback = copy_write;
+
if (IsValidHash(hash)) {
dgst = swupdate_HASH_init();
if (!dgst)
@@ -182,7 +185,7 @@ int copyfile(int fdin, int fdout, int nbytes, unsigned long *offs,
* results corrupted. This lets the cleanup routine
* to remove it
*/
- if (copy_write(fdout, in, size) < 0) {
+ if (callback(fdout, in, size) < 0) {
close(fdout);
free(in);
return -ENOSPC;
@@ -227,7 +230,7 @@ int copyfile(int fdin, int fdout, int nbytes, unsigned long *offs,
return 0;
}

-int copyimage(int fdout, struct img_type *img)
+int copyimage(int fdout, struct img_type *img, writeimage callback)
{
return copyfile(img->fdin,
fdout,
@@ -237,7 +240,8 @@ int copyimage(int fdout, struct img_type *img)
img->compressed,
&img->checksum,
img->sha256,
- img->is_encrypted);
+ img->is_encrypted,
+ callback);
}

int extract_cpio_header(int fd, struct filehdr *fhdr, unsigned long *offset)
@@ -299,7 +303,7 @@ off_t extract_sw_description(int fd, const char *descfile, off_t start)
ERROR("CPIO file corrupted : %s\n", strerror(errno));
return -1;
}
- if (copyfile(fd, fdout, fdh.size, &offset, 0, 0, &checksum, NULL, 0) < 0) {
+ if (copyfile(fd, fdout, fdh.size, &offset, 0, 0, &checksum, NULL, 0, NULL) < 0) {
ERROR("%s corrupted or not valid\n", descfile);
return -1;
}
@@ -360,7 +364,7 @@ off_t extract_next_file(int fd, int fdout, off_t start, int compressed,

if (lseek(fd, offset, SEEK_SET) < 0)
ERROR("CPIO file corrupted : %s\n", strerror(errno));
- if (copyfile(fd, fdout, fdh.size, &offset, 0, compressed, &checksum, hash, 0) < 0) {
+ if (copyfile(fd, fdout, fdh.size, &offset, 0, compressed, &checksum, hash, 0, NULL) < 0) {
ERROR("Error copying extracted file\n");
}

@@ -409,7 +413,7 @@ int cpio_scan(int fd, struct swupdate_cfg *cfg, off_t start)
* use copyfile for checksum verification, as we skip file
* we do not have to provide fdout
*/
- if (copyfile(fd, 0, fdh.size, &offset, 1, 0, &checksum, NULL, 0) != 0) {
+ if (copyfile(fd, 0, fdh.size, &offset, 1, 0, &checksum, NULL, 0, NULL) != 0) {
ERROR("invalid archive\n");
return -1;
}
diff --git a/corelib/stream_interface.c b/corelib/stream_interface.c
index 7f7bd25..bed76d0 100644
--- a/corelib/stream_interface.c
+++ b/corelib/stream_interface.c
@@ -104,7 +104,7 @@ static int extract_file_to_tmp(int fd, const char *fname, unsigned long *poffs)
if (fdout < 0)
return -1;

- if (copyfile(fd, fdout, fdh.size, poffs, 0, 0, &checksum, NULL, 0) < 0) {
+ if (copyfile(fd, fdout, fdh.size, poffs, 0, 0, &checksum, NULL, 0, NULL) < 0) {
return -1;
}
if (checksum != (uint32_t)fdh.chksum) {
@@ -206,7 +206,7 @@ static int extract_files(int fd, struct swupdate_cfg *software)
fdout = openfileoutput(img->extract_file);
if (fdout < 0)
return -1;
- if (copyfile(fd, fdout, fdh.size, &offset, 0, 0, &checksum, img->sha256, 0) < 0) {
+ if (copyfile(fd, fdout, fdh.size, &offset, 0, 0, &checksum, img->sha256, 0, NULL) < 0) {
return -1;
}
if (checksum != (unsigned long)fdh.chksum) {
@@ -218,7 +218,7 @@ static int extract_files(int fd, struct swupdate_cfg *software)
break;

case SKIP_FILE:
- if (copyfile(fd, fdout, fdh.size, &offset, skip, 0, &checksum, NULL, 0) < 0) {
+ if (copyfile(fd, fdout, fdh.size, &offset, skip, 0, &checksum, NULL, 0, NULL) < 0) {
return -1;
}
if (checksum != (unsigned long)fdh.chksum) {
diff --git a/handlers/archive_handler.c b/handlers/archive_handler.c
index 4a57ed1..bf1a9e4 100644
--- a/handlers/archive_handler.c
+++ b/handlers/archive_handler.c
@@ -208,7 +208,7 @@ static int install_archive_image(struct img_type *img,

fdout = open(FIFO, O_WRONLY);

- ret = copyimage(fdout, img);
+ ret = copyimage(fdout, img, NULL);
if (ret< 0) {
ERROR("Error copying extracted file\n");
return -EFAULT;
diff --git a/handlers/flash_handler.c b/handlers/flash_handler.c
index 3365dcc..1fdab01 100644
--- a/handlers/flash_handler.c
+++ b/handlers/flash_handler.c
@@ -649,7 +649,7 @@ static int flash_write_nor(int mtdnum, struct img_type *img)
return -1;
}

- ret = copyimage(fdout, img);
+ ret = copyimage(fdout, img, NULL);

/* tell 'nbytes == 0' (EOF) from 'nbytes < 0' (read error) */
if (ret < 0) {
diff --git a/handlers/raw_handler.c b/handlers/raw_handler.c
index 0c885b0..0346a27 100644
--- a/handlers/raw_handler.c
+++ b/handlers/raw_handler.c
@@ -49,7 +49,7 @@ static int install_raw_image(struct img_type *img,
return -1;
}

- ret = copyimage(fdout, img);
+ ret = copyimage(fdout, img, NULL);

close(fdout);
return ret;
@@ -85,7 +85,7 @@ static int install_raw_file(struct img_type *img,
TRACE("Installing file %s on %s\n",
img->fname, path);
fdout = openfileoutput(path);
- ret = copyimage(fdout, img);
+ ret = copyimage(fdout, img, NULL);
if (ret< 0) {
ERROR("Error copying extracted file\n");
}
diff --git a/handlers/ubivol_handler.c b/handlers/ubivol_handler.c
index 0d7788c..c741b99 100644
--- a/handlers/ubivol_handler.c
+++ b/handlers/ubivol_handler.c
@@ -104,7 +104,7 @@ static int update_volume(libubi_t libubi, struct img_type *img,

TRACE("Updating UBI : %s %lld\n",
img->fname, img->size);
- if (copyimage(fdout, img) < 0) {
+ if (copyimage(fdout, img, NULL) < 0) {
ERROR("Error copying extracted file");
err = -1;
}
diff --git a/handlers/uboot_handler.c b/handlers/uboot_handler.c
index 2d51113..b6e3d21 100644
--- a/handlers/uboot_handler.c
+++ b/handlers/uboot_handler.c
@@ -50,7 +50,7 @@ static int install_uboot_environment(struct img_type *img,
* U-Boot environment is set inside sw-description
* there is no hash but sw-description was already verified
*/
- ret = copyimage(fdout, img);
+ ret = copyimage(fdout, img, NULL);
close(fdout);
}

diff --git a/include/util.h b/include/util.h
index ad38329..e82d4c1 100644
--- a/include/util.h
+++ b/include/util.h
@@ -120,6 +120,11 @@ int gpio_direction_output(int gpio_number, int value);
int gpio_set_value(int gpio_number, int value);
int gpio_get_value(int gpio_number);

+/*
+ * Function to extract / copy images
+ */
+typedef int (*writeimage) (int fd, const void *buf, int len);
+
int fill_buffer(int fd, unsigned char *buf, int nbytes, unsigned long *offs,
uint32_t *checksum, void *dgst);
int decompress_image(int infile, unsigned long *offs, int nbytes,
@@ -128,8 +133,8 @@ int fw_set_one_env(const char *name, const char *value);
int openfile(const char *filename);
int copyfile(int fdin, int fdout, int nbytes, unsigned long *offs,
int skip_file, int compressed, uint32_t *checksum,
- unsigned char *hash, int encrypted);
-int copyimage(int fdout, struct img_type *img);
+ unsigned char *hash, int encrypted, writeimage callback);
+int copyimage(int fdout, struct img_type *img, writeimage callback);
off_t extract_sw_description(int fd, const char *descfile, off_t start);
off_t extract_next_file(int fd, int fdout, off_t start, int compressed,

Stefano Babic

unread,
Aug 10, 2016, 3:48:33 AM8/10/16
to swup...@googlegroups.com, Stefano Babic
Signed-off-by: Stefano Babic <sba...@denx.de>
---
core/util.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
include/util.h | 6 ++++++
2 files changed, 66 insertions(+)

diff --git a/core/util.c b/core/util.c
index 30805ca..fb478b5 100644
--- a/core/util.c
+++ b/core/util.c
@@ -31,6 +31,13 @@
#include "fw_env.h"
#include "generated/autoconf.h"

+struct decryption_key {
+ unsigned char key[32];
+ unsigned char ivt[16];
+};
+
+static struct decryption_key *aes_key = NULL;
+
/*
* Replacement for fw_setenv() for calling inside
* the library
@@ -398,3 +405,56 @@ int count_elem_list(struct imglist *list)

return count;
}
+
+int load_decryption_key(char *fname)
+{
+ FILE *fp;
+ char *b1, *b2;
+ int ret;
+
+ fp = fopen(fname, "r");
+ if (!fp)
+ return -EBADF;
+
+ ret = fscanf(fp, "%ms %ms", &b1, &b2);
+ fclose(fp);
+
+ if (aes_key)
+ free(aes_key);
+
+ aes_key = (struct decryption_key *)calloc(1, sizeof(*aes_key));
+ if (!aes_key)
+ return -ENOMEM;
+
+ if (ret != 2) {
+ fprintf(stderr, "File with decryption key is in the format <key> <ivt>\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Key is for aes_256, it must be 256 bit
+ * and IVT is 128 bit
+ */
+ if ((strlen(b1) != 32) || (strlen(b2) != 16)) {
+ fprintf(stderr, "Keys are of invalid length: Key %d instead of 32, IVT %d instead of 16\n",
+ (int)strlen(b1), (int)strlen(b2));
+ return -EINVAL;
+ }
+
+ memcpy(aes_key->key, b1, 32);
+ memcpy(aes_key->ivt, b2, 16);
+
+ return 0;
+}
+
+unsigned char *get_aes_key(void) {
+ if (!aes_key)
+ return NULL;
+ return aes_key->key;
+}
+
+unsigned char *get_aes_ivt(void) {
+ if (!aes_key)
+ return NULL;
+ return aes_key->ivt;
+}
diff --git a/include/util.h b/include/util.h
index e82d4c1..64fd56f 100644
--- a/include/util.h
+++ b/include/util.h
@@ -152,4 +152,10 @@ int get_hw_revision(struct hw_type *hw);
void get_sw_versions(struct swupdate_cfg *sw);
int check_hw_compatibility(struct swupdate_cfg *cfg);
int count_elem_list(struct imglist *list);
+
+/* Decryption key functions */
+int load_decryption_key(char *fname);
+unsigned char *get_aes_key(void);
+unsigned char *get_aes_ivt(void);
+
#endif
--
2.7.4

Stefano Babic

unread,
Aug 10, 2016, 3:48:34 AM8/10/16
to swup...@googlegroups.com, Stefano Babic
Load AES key for decryption from a file
if CONFIG_ENCRYPTED_IMAGES is set.

Signed-off-by: Stefano Babic <sba...@denx.de>
---
Kconfig | 6 ++++++
core/swupdate.c | 33 +++++++++++++++++++++++++++++++++
core/util.c | 23 ++++++++++++++---------
3 files changed, 53 insertions(+), 9 deletions(-)

diff --git a/Kconfig b/Kconfig
index 83bb51d..2a6be6e 100644
--- a/Kconfig
+++ b/Kconfig
@@ -270,6 +270,12 @@ config SIGNED_IMAGES
comment "Image verification (signed images) needs libssl"
depends on !HAVE_LIBSSL

+config ENCRYPTED_IMAGES
+ bool "Images can be encrypted with a symmetric key"
+ depends on HAVE_LIBSSL
+comment "Image verification (signed images) needs libssl"
+ depends on !HAVE_LIBSSL
+
config SURICATTA
bool "Enable Suricatta Daemon Mode"
default n
diff --git a/core/swupdate.c b/core/swupdate.c
index 47666c6..4da7eac 100644
--- a/core/swupdate.c
+++ b/core/swupdate.c
@@ -85,6 +85,9 @@ static struct option long_options[] = {
#ifdef CONFIG_SIGNED_IMAGES
{"key", required_argument, NULL, 'k'},
#endif
+#ifdef CONFIG_ENCRYPTED_IMAGES
+ {"key-aes", required_argument, NULL, 'K'},
+#endif
#ifdef CONFIG_MTD
{"blacklist", required_argument, NULL, 'b'},
#endif
@@ -132,6 +135,10 @@ static void usage(char *programname)
#ifdef CONFIG_SIGNED_IMAGES
" -k, --key <public key file> : file with public key to verify images\n"
#endif
+#ifdef CONFIG_ENCRYPTED_IMAGES
+ " -K, --key-aes <key file> : the file contains the symmetric key to be used\n"
+ " to decrypt images\n"
+#endif
" -s, --server : run as daemon waiting from\n"
" IPC interface.\n"
" -v, --verbose : be verbose, set maximum loglevel\n"
@@ -386,9 +393,11 @@ int main(int argc, char **argv)
int c;
char fname[MAX_IMAGE_FNAME];
char pubkeyfname[MAX_IMAGE_FNAME];
+ char aeskeyfname[MAX_IMAGE_FNAME];
const char *software_select = NULL;
int opt_i = 0;
int opt_k = 0;
+ int opt_K = 0;
int opt_e = 0;
int opt_s = 0;
int opt_u = 0;
@@ -440,6 +449,9 @@ int main(int argc, char **argv)
strcat(main_options, "k:");
public_key_mandatory = 1;
#endif
+#ifdef CONFIG_ENCRYPTED_IMAGES
+ strcat(main_options, "K:");
+#endif

memset(fname, 0, sizeof(fname));

@@ -477,6 +489,13 @@ int main(int argc, char **argv)
optarg, sizeof(pubkeyfname));
opt_k = 1;
break;
+#ifdef CONFIG_ENCRYPTED_IMAGES
+ case 'K':
+ strncpy(aeskeyfname,
+ optarg, sizeof(aeskeyfname));
+ opt_K = 1;
+ break;
+#endif
case 'e':
software_select = optarg;
opt_e = 1;
@@ -536,6 +555,8 @@ int main(int argc, char **argv)
exit(1);
}

+ swupdate_crypto_init();
+
if (opt_k) {
if (swupdate_dgst_init(&swcfg, pubkeyfname)) {
fprintf(stderr,
@@ -544,6 +565,18 @@ int main(int argc, char **argv)
}
}

+ /*
+ * If a aes key is passed, load it to allow
+ * to decrypt images
+ */
+ if (opt_K) {
+ if (load_decryption_key(aeskeyfname)) {
+ fprintf(stderr,
+ "Key file does not contain a valid AES key\n");
+ exit(1);
+ }
+ }
+
if (lua_handlers_init())
printf("Custom handlers not found, no error, skipping...\n\n");

diff --git a/core/util.c b/core/util.c
index fb478b5..edea1eb 100644
--- a/core/util.c
+++ b/core/util.c
@@ -348,13 +348,15 @@ from_ascii (char const *where, size_t digs, unsigned logbase)
* Convert a hash as hexa string into a sequence of bytes
* hash must be a an array of 32 bytes as specified by SHA256
*/
-int ascii_to_hash(unsigned char *hash, const char *s)
+static int ascii_to_bin(unsigned char *hash, const char *s, int len)
{
int i;
unsigned int val;

- if (strlen(s) == 64) {
- for (i = 0; i < 64; i+= 2) {
+ if (len % 2)
+ return -EINVAL;
+ if (strlen(s) == len) {
+ for (i = 0; i < len; i+= 2) {
val = from_ascii(&s[i], 2, LG_16);
hash[i / 2] = val;
}
@@ -364,6 +366,11 @@ int ascii_to_hash(unsigned char *hash, const char *s)
return 0;
}

+int ascii_to_hash(unsigned char *hash, const char *s)
+{
+ return ascii_to_bin(hash, s, 64);
+}
+
void hash_to_ascii(const unsigned char *hash, char *str)
{
int i;
@@ -435,15 +442,13 @@ int load_decryption_key(char *fname)
* Key is for aes_256, it must be 256 bit
* and IVT is 128 bit
*/
- if ((strlen(b1) != 32) || (strlen(b2) != 16)) {
- fprintf(stderr, "Keys are of invalid length: Key %d instead of 32, IVT %d instead of 16\n",
- (int)strlen(b1), (int)strlen(b2));
+ ret = ascii_to_bin(aes_key->key, b1, 64) | ascii_to_bin(aes_key->ivt, b2, 32);
+
+ if (ret) {
+ fprintf(stderr, "Keys are invalid\n");
return -EINVAL;
}

- memcpy(aes_key->key, b1, 32);
- memcpy(aes_key->ivt, b2, 16);
-
return 0;
}

--
2.7.4

Stefano Babic

unread,
Aug 10, 2016, 3:48:34 AM8/10/16
to swup...@googlegroups.com, Stefano Babic
Decrypt images with symmetric key if
configured via sw-description.

Signed-off-by: Stefano Babic <sba...@denx.de>
---
core/cpio_utils.c | 104 ++++++++++++++++++++++++++++++++++++++++++------------
1 file changed, 81 insertions(+), 23 deletions(-)

diff --git a/core/cpio_utils.c b/core/cpio_utils.c
index b987656..5d3341c 100644
--- a/core/cpio_utils.c
+++ b/core/cpio_utils.c
@@ -14,7 +14,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc.
+ * Foundation, Inc.
*/

#include <stdio.h>
@@ -121,16 +121,21 @@ int copyfile(int fdin, int fdout, int nbytes, unsigned long *offs,
uint32_t *checksum, unsigned char *hash, int encrypted, writeimage callback)
{
unsigned long size;
- unsigned char *in;
+ unsigned char *in = NULL, *inbuf;
+ unsigned char *decbuf = NULL;
unsigned long filesize = nbytes;
unsigned int percent, prevpercent = 0;
- int ret;
+ int ret = 0;
void *dgst = NULL; /* use a private context for HASH */
+ void *dcrypt = NULL; /* use a private context for decryption */
+ int len;
unsigned char md_value[64]; /*
* Maximum hash is 64 bytes for SHA512
* and we use sha256 in swupdate
*/
unsigned int md_len = 0;
+ unsigned char *aes_key;
+ unsigned char *ivt;

if (!callback)
callback = copy_write;
@@ -144,23 +149,41 @@ int copyfile(int fdin, int fdout, int nbytes, unsigned long *offs,
if (checksum)
*checksum = 0;

+ /*
+ * Simultaneous compression and decryption of images
+ * is not (yet ?) supported
+ */
+ if (compressed && encrypted) {
+ ERROR("encrypted zip images are not yet supported -- aborting\n");
+ return -EINVAL;
+ }
+
in = (unsigned char *)malloc(BUFF_SIZE);
if (!in)
return -ENOMEM;

-#ifdef CONFIG_GUNZIP
- if (compressed) {
- if (encrypted) {
- ERROR("encrypted zip images are not yet supported -- aborting\n");
- free(in);
- return -EINVAL;
+ if (encrypted) {
+ decbuf = (unsigned char *)calloc(1, BUFF_SIZE + AES_BLOCK_SIZE);
+ if (!decbuf) {
+ ret = -ENOMEM;
+ goto copyfile_exit;
}

+ aes_key = get_aes_key();
+ ivt = get_aes_ivt();
+ dcrypt = swupdate_DECRYPT_init(aes_key, ivt);
+ if (!dcrypt) {
+ ret = -EFAULT;
+ goto copyfile_exit;
+ }
+ }
+
+#ifdef CONFIG_GUNZIP
+ if (compressed) {
ret = decompress_image(fdin, offs, nbytes, fdout, checksum, dgst);
if (ret < 0) {
ERROR("gunzip failure %d (errno %d) -- aborting\n", ret, errno);
- free(in);
- return ret;
+ goto copyfile_exit;
}
}
else {
@@ -170,25 +193,33 @@ int copyfile(int fdin, int fdout, int nbytes, unsigned long *offs,
size = (nbytes < BUFF_SIZE ? nbytes : BUFF_SIZE);

if ((ret = fill_buffer(fdin, in, size, offs, checksum, dgst) < 0)) {
- close(fdout);
- free(in);
- return ret;
+ goto copyfile_exit;
}

nbytes -= size;
if (skip_file)
continue;

+ inbuf = in;
+ len = size;
+
+ if (encrypted) {
+ ret = swupdate_DECRYPT_update(dcrypt, decbuf,
+ &len, in, size);
+ if (ret < 0)
+ goto copyfile_exit;
+ inbuf = decbuf;
+ }
+
/*
* If there is no enough place,
* returns an error and close the output file that
* results corrupted. This lets the cleanup routine
* to remove it
*/
- if (callback(fdout, in, size) < 0) {
- close(fdout);
- free(in);
- return -ENOSPC;
+ if (callback(fdout, inbuf, len) < 0) {
+ ret =-ENOSPC;
+ goto copyfile_exit;
}

percent = (unsigned int)(((double)(filesize - nbytes)) * 100 / filesize);
@@ -201,9 +232,24 @@ int copyfile(int fdin, int fdout, int nbytes, unsigned long *offs,
#ifdef CONFIG_GUNZIP
}
#endif
+
+ /*
+ * Finalise the decryption. Further plaintext bytes may be written at
+ * this stage.
+ */
+ if (encrypted) {
+ ret = swupdate_DECRYPT_final(dcrypt, decbuf, &len);
+ if (ret < 0)
+ goto copyfile_exit;
+ if (callback(fdout, decbuf, len) < 0) {
+ ret =-ENOSPC;
+ goto copyfile_exit;
+ }
+ }
+
+
if (IsValidHash(hash)) {
swupdate_HASH_final(dgst, md_value, &md_len);
- swupdate_HASH_cleanup(dgst);

/*
* Now check if the computed hash is equal
@@ -218,16 +264,28 @@ int copyfile(int fdin, int fdout, int nbytes, unsigned long *offs,

ERROR("HASH mismatch : %s <--> %s",
hashstring, newhashstring);
- free(in);
- return -EFAULT;
+ ret = -EFAULT;
+ goto copyfile_exit;
}
}

fill_buffer(fdin, in, NPAD_BYTES(*offs), offs, checksum, NULL);

- free(in);
+ ret = 0;

- return 0;
+copyfile_exit:
+ if (in)
+ free(in);
+ if (dcrypt)
+ swupdate_DECRYPT_cleanup(dcrypt);
+ if (decbuf)
+ free(decbuf);
+ if (dgst)
+ swupdate_HASH_cleanup(dgst);
+
+ close(fdout);
+
+ return ret;
}

int copyimage(int fdout, struct img_type *img, writeimage callback)
--
2.7.4

Stefano Babic

unread,
Aug 10, 2016, 3:48:36 AM8/10/16
to swup...@googlegroups.com, Stefano Babic
Scripts are always extracted to TMPDIR before
execution. Allow to have encrypted scripts in
swu image. Scripts must be then decrypted when
copied into TMPDIR before execution.

Signed-off-by: Stefano Babic <sba...@denx.de>
---
core/cpio_utils.c | 4 ++--
core/handler.c | 3 ++-
corelib/installer.c | 3 ++-
include/util.h | 2 +-
4 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/core/cpio_utils.c b/core/cpio_utils.c
index 5d3341c..87ad2b5 100644
--- a/core/cpio_utils.c
+++ b/core/cpio_utils.c
@@ -404,7 +404,7 @@ int extract_img_from_cpio(int fd, unsigned long offset, struct filehdr *fdh)
}

off_t extract_next_file(int fd, int fdout, off_t start, int compressed,
- unsigned char *hash)
+ int encrypted, unsigned char *hash)
{
struct filehdr fdh;
uint32_t checksum = 0;
@@ -422,7 +422,7 @@ off_t extract_next_file(int fd, int fdout, off_t start, int compressed,

if (lseek(fd, offset, SEEK_SET) < 0)
ERROR("CPIO file corrupted : %s\n", strerror(errno));
- if (copyfile(fd, fdout, fdh.size, &offset, 0, compressed, &checksum, hash, 0, NULL) < 0) {
+ if (copyfile(fd, fdout, fdh.size, &offset, 0, compressed, &checksum, hash, encrypted, NULL) < 0) {
ERROR("Error copying extracted file\n");
}

diff --git a/core/handler.c b/core/handler.c
index 99ae3c9..58924cf 100644
--- a/core/handler.c
+++ b/core/handler.c
@@ -72,7 +72,8 @@ static int l_handler_wrapper(struct img_type *img, void *data) {
snprintf(img->extract_file, sizeof(img->extract_file), "%s%s",
TMPDIR, img->fname);
fdout = openfileoutput(img->extract_file);
- res = extract_next_file(img->fdin, fdout, img->offset, 0, img->sha256);
+ res = extract_next_file(img->fdin, fdout, img->offset, 0,
+ img->is_encrypted, img->sha256);
}

l_func_ref = *((int*)data);
diff --git a/corelib/installer.c b/corelib/installer.c
index 0badac4..aa00b68 100644
--- a/corelib/installer.c
+++ b/corelib/installer.c
@@ -156,7 +156,8 @@ static int extract_script(int fd, struct imglist *head, const char *dest)
dest, script->fname);

fdout = openfileoutput(script->extract_file);
- extract_next_file(fd, fdout, script->offset, 0, script->sha256);
+ extract_next_file(fd, fdout, script->offset, 0,
+ script->is_encrypted, script->sha256);
close(fdout);
}
return 0;
diff --git a/include/util.h b/include/util.h
index 64fd56f..dccd6e5 100644
--- a/include/util.h
+++ b/include/util.h
@@ -137,7 +137,7 @@ int copyfile(int fdin, int fdout, int nbytes, unsigned long *offs,
int copyimage(int fdout, struct img_type *img, writeimage callback);
off_t extract_sw_description(int fd, const char *descfile, off_t start);
off_t extract_next_file(int fd, int fdout, off_t start, int compressed,
- unsigned char *hash);
+ int encrypted, unsigned char *hash);
int openfileoutput(const char *filename);

int register_notifier(notifier client);
--
2.7.4

Jeroen Hofstee

unread,
Aug 10, 2016, 4:08:39 AM8/10/16
to swup...@googlegroups.com
Hello Stefano,


On 10-08-16 09:48, Stefano Babic wrote:
> The series adds support for encrypted images. The encryption
> is set at the image level, allowing to combine encrypted
> and not encrypted images in the same compound image .swu
>
> The only supported algorythm is AES-256. The symmetric
> key must be stored in a protected file (accessible to SWUpdate)
> that is read by SWUpdate at the start up.

Out of curiosity, what are you trying to achieve with this / what kind
of device
do you have in mind this is useful for?

Assuming you want to prevent someone stealing the image, decrypting it
during
installation wouldn't help a lot for devices I know. You just solder the
nand / emmc
etc of the board and connect it to some other device and dd it. I agree
that it is
a bit annoying to have to do that, but no more then that.

Having a encrypted rootfs etc seems to be a far better option, as copy
protection.
(but likely not for performance...)

Regards,
Jeroen

Stefano Babic

unread,
Aug 10, 2016, 4:28:24 AM8/10/16
to Jeroen Hofstee, swup...@googlegroups.com
Hi Jeroen,

On 10/08/2016 10:08, Jeroen Hofstee wrote:
> Hello Stefano,
>
>
> On 10-08-16 09:48, Stefano Babic wrote:
>> The series adds support for encrypted images. The encryption
>> is set at the image level, allowing to combine encrypted
>> and not encrypted images in the same compound image .swu
>> The only supported algorythm is AES-256. The symmetric
>> key must be stored in a protected file (accessible to SWUpdate)
>> that is read by SWUpdate at the start up.
>
> Out of curiosity, what are you trying to achieve with this / what kind
> of device
> do you have in mind this is useful for?
>

Just avoid that images are extracted without buying the hardware. You
need the hardware to extract them.

> Assuming you want to prevent someone stealing the image, decrypting it
> during
> installation wouldn't help a lot for devices I know.

Of course. If you have full control of the device, you are also able to
get the keys.

> You just solder the
> nand / emmc
> etc of the board and connect it to some other device and dd it. I agree
> that it is
> a bit annoying to have to do that, but no more then that.

Right - however, this is out of scope. Goal is to make life harder, for
example in the way you have described.

>
> Having a encrypted rootfs etc seems to be a far better option, as copy
> protection.

Agree with you, accomplished by putting the keys in some removable
storage and without storing into the device.

> (but likely not for performance...)

I guess that for some SOCs with hardware crypto device, performance will
remain acceptable. But I have not yet tested myself such as solution.

Best regards,
Stefano


--
=====================================================================
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-53 Fax: +49-8142-66989-80 Email: sba...@denx.de
=====================================================================

Jeroen Hofstee

unread,
Aug 10, 2016, 3:25:32 PM8/10/16
to Stefano Babic, swup...@googlegroups.com
Hello Stefano,

On 10-08-16 10:28, Stefano Babic wrote:
> On 10/08/2016 10:08, Jeroen Hofstee wrote:
>> On 10-08-16 09:48, Stefano Babic wrote:
>>> The series adds support for encrypted images. The encryption
>>> is set at the image level, allowing to combine encrypted
>>> and not encrypted images in the same compound image .swu
>>> The only supported algorythm is AES-256. The symmetric
>>> key must be stored in a protected file (accessible to SWUpdate)
>>> that is read by SWUpdate at the start up.
>> Out of curiosity, what are you trying to achieve with this / what kind
>> of device
>> do you have in mind this is useful for?
>>
> Just avoid that images are extracted without buying the hardware. You
> need the hardware to extract them.

good, so it has at least a valid use case. Not really a common one I
guess, but I
can e.g. imagine it could be useful if you trust all users of the device
and ship
to a controlled group...

[...]

>
>> You just solder the
>> nand / emmc
>> etc of the board and connect it to some other device and dd it. I agree
>> that it is
>> a bit annoying to have to do that, but no more then that.
> Right - however, this is out of scope. Goal is to make life harder, for
> example in the way you have described.

I have never done this, but for someone doing this regularly I
guesstimate it
takes 20 minutes or so, to remove the chip, clean it and put it in
pogo-pin mount.
But yes, it is a bit harder then downloading a file from a webserver ;)

>
>> Having a encrypted rootfs etc seems to be a far better option, as copy
>> protection.
> Agree with you, accomplished by putting the keys in some removable
> storage and without storing into the device.

I don't really understand this. But yes, you should store the key in a
safe place,
not copy it to external RAM, not load it in the same location in RAM etc
etc.
But given that you exclude having physical access, such things don't matter
for this patch-set and are fine.

>
>> (but likely not for performance...)
> I guess that for some SOCs with hardware crypto device, performance will
> remain acceptable. But I have not yet tested myself such as solution.

I never tried that either... just speculating it is slower..

Regards,
Jeroen
Reply all
Reply to author
Forward
0 new messages