All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/12] Verified boot implementation based on FIT
@ 2013-06-13 22:09 ` Simon Glass
  0 siblings, 0 replies; 27+ messages in thread
From: Simon Glass @ 2013-06-13 22:09 UTC (permalink / raw)
  To: U-Boot Mailing List
  Cc: Joel A Fernandes, Will Drewry, Wolfgang Denk, Marek Vasut,
	Joe Hershberger, u-boot-review-hpIqsD4AKlfQT0dZR+AlfA,
	Bill Richardson, Devicetree Discuss, Randall Spangler, Tom Rini,
	Vadim Bendebury, Andreas Bäck, Kees Cook

This series implemented a verified boot system based around FIT images
as discussed on the U-Boot mailing list, including on this thread:

http://permalink.gmane.org/gmane.comp.boot-loaders.u-boot/147830

RSA is used to implement the encryption. Images are signed by mkimage
using private keys created by the user. Public keys are written into
U-Boot control FDT (CONFIG_OF_CONTROL) for access by bootm etc. at
run-time. The control FDT must be stored in a secure place where it
cannot be changed after manufacture. Some notes are provided in the
documentaion on how this can be achieved. The implementation is fairly
efficient and fits nicely into U-Boot. FIT plus RSA adds around 18KB
to SPL size which is manageable on modern SoCs.

When images are loaded, they are verified with the public keys.

It is important to have a test framework for this series. For this, sandbox
is used, and a script is provided which signs images and gets sandbox to
load them using a script, to check that all is well.

Rollback prevention has been added in a separate TPM patch. This ensures
that an attacker cannot boot your system with an old image that has been
compromised. Support for this is not built into bootm, but instead must
be scripted in U-Boot. It is possible that a standard scheme for this could
be devised by adding version number tags to the signing procedure. However
scripts do provide more flexibility. See the 'tpm' command for more
information.

Two patches affect libfdt and have material which is not yet upstream in
that project:

   image: Add support for signing of FIT configurations
   libfdt: Add fdt_find_regions()

If these are not desired, then the rest of the series can stand alone,
just without the configuration-signing feature.

This series requires the 'trace' series since it sits on top of the bootm
refactor there.

This series is available at:

http://git.denx.de/u-boot-x86.git

in the branch 'vboot'.

Changes in v3:
- Fix 'compile' typo
- Rebase to master
- Use new fdt_first/next_subnode()

Changes in v2:
- Add sanity checks on key sizes in RSA (improves security)
- Adjust how signing enable works in image.h
- Adjust mkimage help to separate out signing options
- Avoid using malloc in RSA routines (for smaller SPL code size)
- Build signing support unconditionally in mkimage
- Fix FDT error handling in fit_image_write_sig()
- Fix checkpatch checks about parenthesis alignment
- Fix checkpatch warnings about split strings
- Fix spelling of multiply in rsa-verify.c
- Only build RSA support into mkimage if CONFIG_RSA is defined
- Rebase on previous patches
- Require CONFIG_FIT_SIGNATURE in image.h for mkimage to support signing
- Support RSA library version without ERR_remove_thread_state()
- Tweak tools/Makefile to make image signing optional
- Update README to fix typos
- Update README to fix typos and clarify some points
- Use U-Boot's -c option instead of hard-coding a boot script
- Use stack instead of calloc() within U-Boot's signature verification code
- gd->fdt_blob is now available on all archs (generic board landed)

Simon Glass (12):
  image: Add signing infrastructure
  image: Support signing of images
  image: Add RSA support for image signing
  mkimage: Add -k option to specify key directory
  mkimage: Add -K to write public keys to an FDT blob
  mkimage: Add -F option to modify an existing .fit file
  mkimage: Add -c option to specify a comment for key signing
  mkimage: Add -r option to specify keys that must be verified
  libfdt: Add fdt_find_regions()
  image: Add support for signing of FIT configurations
  sandbox: config: Enable FIT signatures with RSA
  Add verified boot information and test

 Makefile                         |   1 +
 README                           |  15 ++
 common/Makefile                  |   1 +
 common/image-fit.c               |  83 ++++--
 common/image-sig.c               | 422 +++++++++++++++++++++++++++++++
 config.mk                        |   1 +
 doc/mkimage.1                    |  73 +++++-
 doc/uImage.FIT/sign-configs.its  |  45 ++++
 doc/uImage.FIT/sign-images.its   |  42 ++++
 doc/uImage.FIT/signature.txt     | 382 ++++++++++++++++++++++++++++
 doc/uImage.FIT/verified-boot.txt | 104 ++++++++
 include/configs/sandbox.h        |   2 +
 include/image.h                  | 165 +++++++++++-
 include/libfdt.h                 |  64 +++++
 include/rsa.h                    | 108 ++++++++
 lib/libfdt/fdt_wip.c             | 129 ++++++++++
 lib/rsa/Makefile                 |  48 ++++
 lib/rsa/rsa-sign.c               | 460 ++++++++++++++++++++++++++++++++++
 lib/rsa/rsa-verify.c             | 385 ++++++++++++++++++++++++++++
 test/vboot/.gitignore            |   3 +
 test/vboot/sandbox-kernel.dts    |   7 +
 test/vboot/sandbox-u-boot.dts    |   7 +
 test/vboot/sign-configs.its      |  45 ++++
 test/vboot/sign-images.its       |  42 ++++
 test/vboot/vboot_test.sh         | 126 ++++++++++
 tools/Makefile                   |  19 +-
 tools/fit_image.c                |  44 +++-
 tools/image-host.c               | 527 ++++++++++++++++++++++++++++++++++++++-
 tools/mkimage.c                  |  36 ++-
 tools/mkimage.h                  |   4 +
 30 files changed, 3333 insertions(+), 57 deletions(-)
 create mode 100644 common/image-sig.c
 create mode 100644 doc/uImage.FIT/sign-configs.its
 create mode 100644 doc/uImage.FIT/sign-images.its
 create mode 100644 doc/uImage.FIT/signature.txt
 create mode 100644 doc/uImage.FIT/verified-boot.txt
 create mode 100644 include/rsa.h
 create mode 100644 lib/rsa/Makefile
 create mode 100644 lib/rsa/rsa-sign.c
 create mode 100644 lib/rsa/rsa-verify.c
 create mode 100644 test/vboot/.gitignore
 create mode 100644 test/vboot/sandbox-kernel.dts
 create mode 100644 test/vboot/sandbox-u-boot.dts
 create mode 100644 test/vboot/sign-configs.its
 create mode 100644 test/vboot/sign-images.its
 create mode 100755 test/vboot/vboot_test.sh

-- 
1.8.3

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [U-Boot] [PATCH v3 0/12] Verified boot implementation based on FIT
@ 2013-06-13 22:09 ` Simon Glass
  0 siblings, 0 replies; 27+ messages in thread
From: Simon Glass @ 2013-06-13 22:09 UTC (permalink / raw)
  To: u-boot

This series implemented a verified boot system based around FIT images
as discussed on the U-Boot mailing list, including on this thread:

http://permalink.gmane.org/gmane.comp.boot-loaders.u-boot/147830

RSA is used to implement the encryption. Images are signed by mkimage
using private keys created by the user. Public keys are written into
U-Boot control FDT (CONFIG_OF_CONTROL) for access by bootm etc. at
run-time. The control FDT must be stored in a secure place where it
cannot be changed after manufacture. Some notes are provided in the
documentaion on how this can be achieved. The implementation is fairly
efficient and fits nicely into U-Boot. FIT plus RSA adds around 18KB
to SPL size which is manageable on modern SoCs.

When images are loaded, they are verified with the public keys.

It is important to have a test framework for this series. For this, sandbox
is used, and a script is provided which signs images and gets sandbox to
load them using a script, to check that all is well.

Rollback prevention has been added in a separate TPM patch. This ensures
that an attacker cannot boot your system with an old image that has been
compromised. Support for this is not built into bootm, but instead must
be scripted in U-Boot. It is possible that a standard scheme for this could
be devised by adding version number tags to the signing procedure. However
scripts do provide more flexibility. See the 'tpm' command for more
information.

Two patches affect libfdt and have material which is not yet upstream in
that project:

   image: Add support for signing of FIT configurations
   libfdt: Add fdt_find_regions()

If these are not desired, then the rest of the series can stand alone,
just without the configuration-signing feature.

This series requires the 'trace' series since it sits on top of the bootm
refactor there.

This series is available at:

http://git.denx.de/u-boot-x86.git

in the branch 'vboot'.

Changes in v3:
- Fix 'compile' typo
- Rebase to master
- Use new fdt_first/next_subnode()

Changes in v2:
- Add sanity checks on key sizes in RSA (improves security)
- Adjust how signing enable works in image.h
- Adjust mkimage help to separate out signing options
- Avoid using malloc in RSA routines (for smaller SPL code size)
- Build signing support unconditionally in mkimage
- Fix FDT error handling in fit_image_write_sig()
- Fix checkpatch checks about parenthesis alignment
- Fix checkpatch warnings about split strings
- Fix spelling of multiply in rsa-verify.c
- Only build RSA support into mkimage if CONFIG_RSA is defined
- Rebase on previous patches
- Require CONFIG_FIT_SIGNATURE in image.h for mkimage to support signing
- Support RSA library version without ERR_remove_thread_state()
- Tweak tools/Makefile to make image signing optional
- Update README to fix typos
- Update README to fix typos and clarify some points
- Use U-Boot's -c option instead of hard-coding a boot script
- Use stack instead of calloc() within U-Boot's signature verification code
- gd->fdt_blob is now available on all archs (generic board landed)

Simon Glass (12):
  image: Add signing infrastructure
  image: Support signing of images
  image: Add RSA support for image signing
  mkimage: Add -k option to specify key directory
  mkimage: Add -K to write public keys to an FDT blob
  mkimage: Add -F option to modify an existing .fit file
  mkimage: Add -c option to specify a comment for key signing
  mkimage: Add -r option to specify keys that must be verified
  libfdt: Add fdt_find_regions()
  image: Add support for signing of FIT configurations
  sandbox: config: Enable FIT signatures with RSA
  Add verified boot information and test

 Makefile                         |   1 +
 README                           |  15 ++
 common/Makefile                  |   1 +
 common/image-fit.c               |  83 ++++--
 common/image-sig.c               | 422 +++++++++++++++++++++++++++++++
 config.mk                        |   1 +
 doc/mkimage.1                    |  73 +++++-
 doc/uImage.FIT/sign-configs.its  |  45 ++++
 doc/uImage.FIT/sign-images.its   |  42 ++++
 doc/uImage.FIT/signature.txt     | 382 ++++++++++++++++++++++++++++
 doc/uImage.FIT/verified-boot.txt | 104 ++++++++
 include/configs/sandbox.h        |   2 +
 include/image.h                  | 165 +++++++++++-
 include/libfdt.h                 |  64 +++++
 include/rsa.h                    | 108 ++++++++
 lib/libfdt/fdt_wip.c             | 129 ++++++++++
 lib/rsa/Makefile                 |  48 ++++
 lib/rsa/rsa-sign.c               | 460 ++++++++++++++++++++++++++++++++++
 lib/rsa/rsa-verify.c             | 385 ++++++++++++++++++++++++++++
 test/vboot/.gitignore            |   3 +
 test/vboot/sandbox-kernel.dts    |   7 +
 test/vboot/sandbox-u-boot.dts    |   7 +
 test/vboot/sign-configs.its      |  45 ++++
 test/vboot/sign-images.its       |  42 ++++
 test/vboot/vboot_test.sh         | 126 ++++++++++
 tools/Makefile                   |  19 +-
 tools/fit_image.c                |  44 +++-
 tools/image-host.c               | 527 ++++++++++++++++++++++++++++++++++++++-
 tools/mkimage.c                  |  36 ++-
 tools/mkimage.h                  |   4 +
 30 files changed, 3333 insertions(+), 57 deletions(-)
 create mode 100644 common/image-sig.c
 create mode 100644 doc/uImage.FIT/sign-configs.its
 create mode 100644 doc/uImage.FIT/sign-images.its
 create mode 100644 doc/uImage.FIT/signature.txt
 create mode 100644 doc/uImage.FIT/verified-boot.txt
 create mode 100644 include/rsa.h
 create mode 100644 lib/rsa/Makefile
 create mode 100644 lib/rsa/rsa-sign.c
 create mode 100644 lib/rsa/rsa-verify.c
 create mode 100644 test/vboot/.gitignore
 create mode 100644 test/vboot/sandbox-kernel.dts
 create mode 100644 test/vboot/sandbox-u-boot.dts
 create mode 100644 test/vboot/sign-configs.its
 create mode 100644 test/vboot/sign-images.its
 create mode 100755 test/vboot/vboot_test.sh

-- 
1.8.3

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [U-Boot] [PATCH v3 01/12] image: Add signing infrastructure
  2013-06-13 22:09 ` [U-Boot] " Simon Glass
  (?)
@ 2013-06-13 22:10 ` Simon Glass
  -1 siblings, 0 replies; 27+ messages in thread
From: Simon Glass @ 2013-06-13 22:10 UTC (permalink / raw)
  To: u-boot

Add a structure to describe an algorithm which can sign and (later) verify
images.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
Changes in v3: None
Changes in v2:
- Adjust how signing enable works in image.h
- Rebase on previous patches
- Tweak tools/Makefile to make image signing optional
- Update README to fix typos and clarify some points
- gd->fdt_blob is now available on all archs (generic board landed)

 README                       |   5 +
 common/Makefile              |   1 +
 common/image-sig.c           |  42 +++++++++
 doc/uImage.FIT/signature.txt | 216 +++++++++++++++++++++++++++++++++++++++++++
 include/image.h              |  90 +++++++++++++++++-
 tools/Makefile               |   6 ++
 6 files changed, 358 insertions(+), 2 deletions(-)
 create mode 100644 common/image-sig.c
 create mode 100644 doc/uImage.FIT/signature.txt

diff --git a/README b/README
index 33bda8c..3e586c3 100644
--- a/README
+++ b/README
@@ -2781,6 +2781,11 @@ FIT uImage format:
 		most specific compatibility entry of U-Boot's fdt's root node.
 		The order of entries in the configuration's fdt is ignored.
 
+		CONFIG_FIT_SIGNATURE
+		This option enables signature verification of FIT uImages,
+		using a hash signed and verified using RSA. See
+		doc/uImage.FIT/signature.txt for more details.
+
 - Standalone program support:
 		CONFIG_STANDALONE_LOAD_ADDR
 
diff --git a/common/Makefile b/common/Makefile
index d40fb1f..84ae279 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -235,6 +235,7 @@ COBJS-y += dlmalloc.o
 COBJS-y += image.o
 COBJS-$(CONFIG_OF_LIBFDT) += image-fdt.o
 COBJS-$(CONFIG_FIT) += image-fit.o
+COBJS-$(CONFIG_FIT_SIGNATURE) += image-sig.o
 COBJS-y += memsize.o
 COBJS-y += stdio.o
 
diff --git a/common/image-sig.c b/common/image-sig.c
new file mode 100644
index 0000000..841c662
--- /dev/null
+++ b/common/image-sig.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2013, Google Inc.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifdef USE_HOSTCC
+#include "mkimage.h"
+#include <time.h>
+#else
+#include <common.h>
+#endif /* !USE_HOSTCC*/
+#include <errno.h>
+#include <image.h>
+
+struct image_sig_algo image_sig_algos[] = {
+};
+
+struct image_sig_algo *image_get_sig_algo(const char *name)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(image_sig_algos); i++) {
+		if (!strcmp(image_sig_algos[i].name, name))
+			return &image_sig_algos[i];
+	}
+
+	return NULL;
+}
diff --git a/doc/uImage.FIT/signature.txt b/doc/uImage.FIT/signature.txt
new file mode 100644
index 0000000..0d145e0
--- /dev/null
+++ b/doc/uImage.FIT/signature.txt
@@ -0,0 +1,216 @@
+U-Boot FIT Signature Verification
+=================================
+
+Introduction
+------------
+FIT supports hashing of images so that these hashes can be checked on
+loading. This protects against corruption of the image. However it does not
+prevent the substitution of one image for another.
+
+The signature feature allows the hash to be signed with a private key such
+that it can be verified using a public key later. Provided that the private
+key is kept secret and the public key is stored in a non-volatile place,
+any image can be verified in this way.
+
+See verified-boot.txt for more general information on verified boot.
+
+
+Concepts
+--------
+Some familiarity with public key cryptography is assumed in this section.
+
+The procedure for signing is as follows:
+
+   - hash an image in the FIT
+   - sign the hash with a private key to produce a signature
+   - store the resulting signature in the FIT
+
+The procedure for verification is:
+
+   - read the FIT
+   - obtain the public key
+   - extract the signature from the FIT
+   - hash the image from the FIT
+   - verify (with the public key) that the extracted signature matches the
+       hash
+
+The signing is generally performed by mkimage, as part of making a firmware
+image for the device. The verification is normally done in U-Boot on the
+device.
+
+
+Algorithms
+----------
+In principle any suitable algorithm can be used to sign and verify a hash.
+At present only one class of algorithms is supported: SHA1 hashing with RSA.
+This works by hashing the image to produce a 20-byte hash.
+
+While it is acceptable to bring in large cryptographic libraries such as
+openssl on the host side (e.g. mkimage), it is not desirable for U-Boot.
+For the run-time verification side, it is important to keep code and data
+size as small as possible.
+
+For this reason the RSA image verification uses pre-processed public keys
+which can be used with a very small amount of code - just some extraction
+of data from the FDT and exponentiation mod n. Code size impact is a little
+under 5KB on Tegra Seaboard, for example.
+
+It is relatively straightforward to add new algorithms if required. If
+another RSA variant is needed, then it can be added to the table in
+image-sig.c. If another algorithm is needed (such as DSA) then it can be
+placed alongside rsa.c, and its functions added to the table in image-sig.c
+also.
+
+
+Creating an RSA key and certificate
+-----------------------------------
+To create a new public key, size 2048 bits:
+
+$ openssl genrsa -F4 -out keys/dev.key 2048
+
+To create a certificate for this:
+
+$ openssl req -batch -new -x509 -key keys/dev.key -out keys/dev.crt
+
+If you like you can look at the public key also:
+
+$ openssl rsa -in keys/dev.key -pubout
+
+
+Device Tree Bindings
+--------------------
+The following properties are required in the FIT's signature node(s) to
+allow thes signer to operate. These should be added to the .its file.
+Signature nodes sit at the same level as hash nodes and are called
+signature at 1, signature@2, etc.
+
+- algo: Algorithm name (e.g. "sha1,rs2048")
+
+- key-name-hint: Name of key to use for signing. The keys will normally be in
+a single directory (parameter -k to mkimage). For a given key <name>, its
+private key is stored in <name>.key and the certificate is stored in
+<name>.crt.
+
+When the image is signed, the following properties are added (mandatory):
+
+- value: The signature data (e.g. 256 bytes for 2048-bit RSA)
+
+When the image is signed, the following properties are optional:
+
+- timestamp: Time when image was signed (standard Unix time_t format)
+
+- signer-name: Name of the signer (e.g. "mkimage")
+
+- signer-version: Version string of the signer (e.g. "2013.01")
+
+- comment: Additional information about the signer or image
+
+
+Example: See sign-images.its for an example image tree source file.
+
+
+Public Key Storage
+------------------
+In order to verify an image that has been signed with a public key we need to
+have a trusted public key. This cannot be stored in the signed image, since
+it would be easy to alter. For this implementation we choose to store the
+public key in U-Boot's control FDT (using CONFIG_OF_CONTROL).
+
+Public keys should be stored as sub-nodes in a /signature node. Required
+properties are:
+
+- algo: Algorithm name (e.g. "sha1,rs2048")
+
+Optional properties are:
+
+- key-name-hint: Name of key used for signing. This is only a hint since it
+is possible for the name to be changed. Verification can proceed by checking
+all available signing keys until one matches.
+
+- required: If present this indicates that the key must be verified for the
+image / configuration to be considered valid. Only required keys are
+normally verified by the FIT image booting algorithm. Valid values are
+"image" to force verification of all images, and "conf" to force verfication
+of the selected configuration (which then relies on hashes in the images to
+verify those).
+
+Each signing algorithm has its own additional properties.
+
+For RSA the following are mandatory:
+
+- rsa,num-bits: Number of key bits (e.g. 2048)
+- rsa,modulus: Modulus (N) as a big-endian multi-word integer
+- rsa,r-squared: (2^num-bits)^2 as a big-endian multi-word integer
+- rsa,n0-inverse: -1 / modulus[0] mod 2^32
+
+
+Verification
+------------
+FITs are verified when loaded. After the configuration is selected a list
+of required images is produced. If there are 'required' public keys, then
+each image must be verified against those keys. This means that every image
+that might be used by the target needs to be signed with 'required' keys.
+
+This happens automatically as part of a bootm command when FITs are used.
+
+
+Enabling FIT Verification
+-------------------------
+In addition to the options to enable FIT itself, the following CONFIGs must
+be enabled:
+
+CONFIG_FIT_SIGNATURE - enable signing and verfication in FITs
+CONFIG_RSA - enable RSA algorithm for signing
+
+
+Testing
+-------
+An easy way to test signing and verfication is to use the test script
+provided in test/vboot/vboot_test.sh. This uses sandbox (a special version
+of U-Boot which runs under Linux) to show the operation of a 'bootm'
+command loading and verifying images.
+
+A sample run is show below:
+
+$ make O=sandbox sandbox_config
+$ make O=sandbox
+$ O=sandbox ./test/vboot/vboot_test.sh
+Simple Verified Boot Test
+=========================
+
+Please see doc/uImage.FIT/verified-boot.txt for more information
+
+Build keys
+Build FIT with signed images
+Test Verified Boot Run: unsigned signatures:: OK
+Sign images
+Test Verified Boot Run: signed images: OK
+Build FIT with signed configuration
+Test Verified Boot Run: unsigned config: OK
+Sign images
+Test Verified Boot Run: signed config: OK
+
+Test passed
+
+
+Future Work
+-----------
+- Roll-back protection using a TPM is done using the tpm command. This can
+be scripted, but we might consider a default way of doing this, built into
+bootm.
+
+
+Possible Future Work
+--------------------
+- Add support for other RSA/SHA variants, such as rsa4096,sha512.
+- Other algorithms besides RSA
+- More sandbox tests for failure modes
+- Passwords for keys/certificates
+- Perhaps implement OAEP
+- Enhance bootm to permit scripted signature verification (so that a script
+can verify an image but not actually boot it)
+
+
+Simon Glass
+sjg at chromium.org
+1-1-13
diff --git a/include/image.h b/include/image.h
index 4415bcf..3f61682 100644
--- a/include/image.h
+++ b/include/image.h
@@ -46,6 +46,9 @@ struct lmb;
 #define CONFIG_OF_LIBFDT	1
 #define CONFIG_FIT_VERBOSE	1 /* enable fit_format_{error,warning}() */
 
+/* Support FIT image signing on host */
+#define CONFIG_FIT_SIGNATURE
+
 #define IMAGE_ENABLE_IGNORE	0
 #define IMAGE_INDENT_STRING	""
 
@@ -670,11 +673,12 @@ int image_setup_linux(bootm_headers_t *images);
 #define FIT_IMAGES_PATH		"/images"
 #define FIT_CONFS_PATH		"/configurations"
 
-/* hash node */
+/* hash/signature node */
 #define FIT_HASH_NODENAME	"hash"
 #define FIT_ALGO_PROP		"algo"
 #define FIT_VALUE_PROP		"value"
 #define FIT_IGNORE_PROP		"uboot-ignore"
+#define FIT_SIG_NODENAME	"signature"
 
 /* image node */
 #define FIT_DATA_PROP		"data"
@@ -804,15 +808,19 @@ int calculate_hash(const void *data, int data_len, const char *algo,
 			uint8_t *value, int *value_len);
 
 /*
- * At present we only support verification on the device
+ * At present we only support signing on the host, and verification on the
+ * device
  */
 #if defined(CONFIG_FIT_SIGNATURE)
 # ifdef USE_HOSTCC
+#  define IMAGE_ENABLE_SIGN	1
 #  define IMAGE_ENABLE_VERIFY	0
 #else
+#  define IMAGE_ENABLE_SIGN	0
 #  define IMAGE_ENABLE_VERIFY	1
 # endif
 #else
+# define IMAGE_ENABLE_SIGN	0
 # define IMAGE_ENABLE_VERIFY	0
 #endif
 
@@ -828,6 +836,84 @@ int calculate_hash(const void *data, int data_len, const char *algo,
 #define IMAGE_ENABLE_BEST_MATCH	0
 #endif
 
+/* Information passed to the signing routines */
+struct image_sign_info {
+	const char *keydir;		/* Directory conaining keys */
+	const char *keyname;		/* Name of key to use */
+	void *fit;			/* Pointer to FIT blob */
+	int node_offset;		/* Offset of signature node */
+	struct image_sig_algo *algo;	/* Algorithm information */
+	const void *fdt_blob;		/* FDT containing public keys */
+	int required_keynode;		/* Node offset of key to use: -1=any */
+	const char *require_keys;	/* Value for 'required' property */
+};
+
+/* A part of an image, used for hashing */
+struct image_region {
+	const void *data;
+	int size;
+};
+
+struct image_sig_algo {
+	const char *name;		/* Name of algorithm */
+
+	/**
+	 * sign() - calculate and return signature for given input data
+	 *
+	 * @info:	Specifies key and FIT information
+	 * @data:	Pointer to the input data
+	 * @data_len:	Data length
+	 * @sigp:	Set to an allocated buffer holding the signature
+	 * @sig_len:	Set to length of the calculated hash
+	 *
+	 * This computes input data signature according to selected algorithm.
+	 * Resulting signature value is placed in an allocated buffer, the
+	 * pointer is returned as *sigp. The length of the calculated
+	 * signature is returned via the sig_len pointer argument. The caller
+	 * should free *sigp.
+	 *
+	 * @return: 0, on success, -ve on error
+	 */
+	int (*sign)(struct image_sign_info *info,
+		    const struct image_region region[],
+		    int region_count, uint8_t **sigp, uint *sig_len);
+
+	/**
+	 * add_verify_data() - Add verification information to FDT
+	 *
+	 * Add public key information to the FDT node, suitable for
+	 * verification at run-time. The information added depends on the
+	 * algorithm being used.
+	 *
+	 * @info:	Specifies key and FIT information
+	 * @keydest:	Destination FDT blob for public key data
+	 * @return: 0, on success, -ve on error
+	 */
+	int (*add_verify_data)(struct image_sign_info *info, void *keydest);
+
+	/**
+	 * verify() - Verify a signature against some data
+	 *
+	 * @info:	Specifies key and FIT information
+	 * @data:	Pointer to the input data
+	 * @data_len:	Data length
+	 * @sig:	Signature
+	 * @sig_len:	Number of bytes in signature
+	 * @return 0 if verified, -ve on error
+	 */
+	int (*verify)(struct image_sign_info *info,
+		      const struct image_region region[], int region_count,
+		      uint8_t *sig, uint sig_len);
+};
+
+/**
+ * image_get_sig_algo() - Look up a signature algortihm
+ *
+ * @param name		Name of algorithm
+ * @return pointer to algorithm information, or NULL if not found
+ */
+struct image_sig_algo *image_get_sig_algo(const char *name);
+
 static inline int fit_image_check_target_arch(const void *fdt, int node)
 {
 	return fit_image_check_arch(fdt, node, IH_ARCH_DEFAULT);
diff --git a/tools/Makefile b/tools/Makefile
index 569dc77..38fd934 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -80,6 +80,7 @@ BIN_FILES-y += proftool(SFX)
 EXT_OBJ_FILES-$(CONFIG_BUILD_ENVCRC) += common/env_embedded.o
 EXT_OBJ_FILES-y += common/image.o
 EXT_OBJ_FILES-$(CONFIG_FIT) += common/image-fit.o
+EXT_OBJ_FILES-y += common/image-sig.o
 EXT_OBJ_FILES-y += lib/crc32.o
 EXT_OBJ_FILES-y += lib/md5.o
 EXT_OBJ_FILES-y += lib/sha1.o
@@ -161,6 +162,10 @@ HOSTSRCS += $(addprefix $(SRCTREE)/lib/libfdt/,$(LIBFDT_OBJ_FILES-y:.o=.c))
 BINS	:= $(addprefix $(obj),$(sort $(BIN_FILES-y)))
 LIBFDT_OBJS	:= $(addprefix $(obj),$(LIBFDT_OBJ_FILES-y))
 
+# We cannot check CONFIG_FIT_SIGNATURE here since it is not set on the host
+FIT_SIG_OBJ_FILES	:= image-sig.o
+FIT_SIG_OBJS		:= $(addprefix $(obj),$(FIT_SIG_OBJ_FILES))
+
 HOSTOBJS := $(addprefix $(obj),$(OBJ_FILES-y))
 NOPEDOBJS := $(addprefix $(obj),$(NOPED_OBJ_FILES-y))
 
@@ -220,6 +225,7 @@ $(obj)mkimage$(SFX):	$(obj)aisimage.o \
 			$(obj)image-fit.o \
 			$(obj)image.o \
 			$(obj)image-host.o \
+			$(FIT_SIG_OBJS) \
 			$(obj)imximage.o \
 			$(obj)kwbimage.o \
 			$(obj)pblimage.o \
-- 
1.8.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [U-Boot] [PATCH v3 02/12] image: Support signing of images
  2013-06-13 22:09 ` [U-Boot] " Simon Glass
  (?)
  (?)
@ 2013-06-13 22:10 ` Simon Glass
  -1 siblings, 0 replies; 27+ messages in thread
From: Simon Glass @ 2013-06-13 22:10 UTC (permalink / raw)
  To: u-boot

Add support for signing images using a new signature node. The process
is handled by fdt_add_verification_data() which now takes parameters to
provide the keys and related information.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
Changes in v3:
- Use new fdt_first/next_subnode()

Changes in v2:
- Adjust how signing enable works in image.h
- Fix FDT error handling in fit_image_write_sig()
- Fix checkpatch checks about parenthesis alignment
- Fix checkpatch warnings about split strings
- Require CONFIG_FIT_SIGNATURE in image.h for mkimage to support signing

 common/image-fit.c             |  83 +++++++++++++-----
 common/image-sig.c             | 144 +++++++++++++++++++++++++++++++
 doc/uImage.FIT/sign-images.its |  42 ++++++++++
 include/image.h                |  59 ++++++++++++-
 tools/fit_image.c              |   2 +-
 tools/image-host.c             | 186 ++++++++++++++++++++++++++++++++++++++---
 6 files changed, 478 insertions(+), 38 deletions(-)
 create mode 100644 doc/uImage.FIT/sign-images.its

diff --git a/common/image-fit.c b/common/image-fit.c
index 7bf82d3..06426ad 100644
--- a/common/image-fit.c
+++ b/common/image-fit.c
@@ -234,42 +234,45 @@ void fit_print_contents(const void *fit)
  * @fit: pointer to the FIT format image header
  * @noffset: offset of the hash node
  * @p: pointer to prefix string
+ * @type: Type of information to print ("hash" or "sign")
  *
  * fit_image_print_data() lists properies for the processed hash node
  *
+ * This function avoid using puts() since it prints a newline on the host
+ * but does not in U-Boot.
+ *
  * returns:
  *     no returned results
  */
-static void fit_image_print_data(const void *fit, int noffset, const char *p)
+static void fit_image_print_data(const void *fit, int noffset, const char *p,
+				 const char *type)
 {
-	char *algo;
+	const char *keyname;
 	uint8_t *value;
 	int value_len;
-	int i, ret;
-
-	/*
-	 * Check subnode name, must be equal to "hash".
-	 * Multiple hash nodes require unique unit node
-	 * names, e.g. hash at 1, hash at 2, etc.
-	 */
-	if (strncmp(fit_get_name(fit, noffset, NULL),
-		    FIT_HASH_NODENAME,
-		    strlen(FIT_HASH_NODENAME)) != 0)
-		return;
+	char *algo;
+	int required;
+	int ret, i;
 
-	debug("%s  Hash node:    '%s'\n", p,
+	debug("%s  %s node:    '%s'\n", p, type,
 	      fit_get_name(fit, noffset, NULL));
-
-	printf("%s  Hash algo:    ", p);
+	printf("%s  %s algo:    ", p, type);
 	if (fit_image_hash_get_algo(fit, noffset, &algo)) {
 		printf("invalid/unsupported\n");
 		return;
 	}
-	printf("%s\n", algo);
+	printf("%s", algo);
+	keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL);
+	required = fdt_getprop(fit, noffset, "required", NULL) != NULL;
+	if (keyname)
+		printf(":%s", keyname);
+	if (required)
+		printf(" (required)");
+	printf("\n");
 
 	ret = fit_image_hash_get_value(fit, noffset, &value,
 					&value_len);
-	printf("%s  Hash value:   ", p);
+	printf("%s  %s value:   ", p, type);
 	if (ret) {
 		printf("unavailable\n");
 	} else {
@@ -278,7 +281,18 @@ static void fit_image_print_data(const void *fit, int noffset, const char *p)
 		printf("\n");
 	}
 
-	debug("%s  Hash len:     %d\n", p, value_len);
+	debug("%s  %s len:     %d\n", p, type, value_len);
+
+	/* Signatures have a time stamp */
+	if (IMAGE_ENABLE_TIMESTAMP && keyname) {
+		time_t timestamp;
+
+		printf("%s  Timestamp:    ", p);
+		if (fit_get_timestamp(fit, noffset, &timestamp))
+			printf("unavailable\n");
+		else
+			genimg_print_time(timestamp);
+	}
 }
 
 /**
@@ -303,8 +317,12 @@ static void fit_image_print_verification_data(const void *fit, int noffset,
 	 * names, e.g. hash at 1, hash at 2, signature at 1, signature at 2, etc.
 	 */
 	name = fit_get_name(fit, noffset, NULL);
-	if (!strncmp(name, FIT_HASH_NODENAME, strlen(FIT_HASH_NODENAME)))
-		fit_image_print_data(fit, noffset, p);
+	if (!strncmp(name, FIT_HASH_NODENAME, strlen(FIT_HASH_NODENAME))) {
+		fit_image_print_data(fit, noffset, p, "Hash");
+	} else if (!strncmp(name, FIT_SIG_NODENAME,
+				strlen(FIT_SIG_NODENAME))) {
+		fit_image_print_data(fit, noffset, p, "Sign");
+	}
 }
 
 /**
@@ -944,13 +962,23 @@ int fit_image_verify(const void *fit, int image_noffset)
 {
 	const void	*data;
 	size_t		size;
-	int		noffset;
+	int		noffset = 0;
 	char		*err_msg = "";
+	int verify_all = 1;
+	int ret;
 
 	/* Get image data and data length */
 	if (fit_image_get_data(fit, image_noffset, &data, &size)) {
 		err_msg = "Can't get image data/size";
-		return 0;
+		goto error;
+	}
+
+	/* Verify all required signatures */
+	if (IMAGE_ENABLE_VERIFY &&
+	    fit_image_verify_required_sigs(fit, image_noffset, data, size,
+					   gd_fdt_blob(), &verify_all)) {
+		err_msg = "Unable to verify required signature";
+		goto error;
 	}
 
 	/* Process all hash subnodes of the component image node */
@@ -970,6 +998,15 @@ int fit_image_verify(const void *fit, int image_noffset)
 						 &err_msg))
 				goto error;
 			puts("+ ");
+		} else if (IMAGE_ENABLE_VERIFY && verify_all &&
+				!strncmp(name, FIT_SIG_NODENAME,
+					strlen(FIT_SIG_NODENAME))) {
+			ret = fit_image_check_sig(fit, noffset, data,
+							size, -1, &err_msg);
+			if (ret)
+				puts("- ");
+			else
+				puts("+ ");
 		}
 	}
 
diff --git a/common/image-sig.c b/common/image-sig.c
index 841c662..9b222da 100644
--- a/common/image-sig.c
+++ b/common/image-sig.c
@@ -22,6 +22,8 @@
 #include <time.h>
 #else
 #include <common.h>
+#include <malloc.h>
+DECLARE_GLOBAL_DATA_PTR;
 #endif /* !USE_HOSTCC*/
 #include <errno.h>
 #include <image.h>
@@ -40,3 +42,145 @@ struct image_sig_algo *image_get_sig_algo(const char *name)
 
 	return NULL;
 }
+
+static int fit_image_setup_verify(struct image_sign_info *info,
+		const void *fit, int noffset, int required_keynode,
+		char **err_msgp)
+{
+	char *algo_name;
+
+	if (fit_image_hash_get_algo(fit, noffset, &algo_name)) {
+		*err_msgp = "Can't get hash algo property";
+		return -1;
+	}
+	memset(info, '\0', sizeof(*info));
+	info->keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL);
+	info->fit = (void *)fit;
+	info->node_offset = noffset;
+	info->algo = image_get_sig_algo(algo_name);
+	info->fdt_blob = gd_fdt_blob();
+	info->required_keynode = required_keynode;
+	printf("%s:%s", algo_name, info->keyname);
+
+	if (!info->algo) {
+		*err_msgp = "Unknown signature algorithm";
+		return -1;
+	}
+
+	return 0;
+}
+
+int fit_image_check_sig(const void *fit, int noffset, const void *data,
+		size_t size, int required_keynode, char **err_msgp)
+{
+	struct image_sign_info info;
+	struct image_region region;
+	uint8_t *fit_value;
+	int fit_value_len;
+
+	*err_msgp = NULL;
+	if (fit_image_setup_verify(&info, fit, noffset, required_keynode,
+				   err_msgp))
+		return -1;
+
+	if (fit_image_hash_get_value(fit, noffset, &fit_value,
+				     &fit_value_len)) {
+		*err_msgp = "Can't get hash value property";
+		return -1;
+	}
+
+	region.data = data;
+	region.size = size;
+
+	if (info.algo->verify(&info, &region, 1, fit_value, fit_value_len)) {
+		*err_msgp = "Verification failed";
+		return -1;
+	}
+
+	return 0;
+}
+
+static int fit_image_verify_sig(const void *fit, int image_noffset,
+		const char *data, size_t size, const void *sig_blob,
+		int sig_offset)
+{
+	int noffset;
+	char *err_msg = "";
+	int verified = 0;
+	int ret;
+
+	/* Process all hash subnodes of the component image node */
+	for (noffset = fdt_first_subnode(fit, image_noffset);
+	     noffset >= 0;
+	     noffset = fdt_next_subnode(fit, noffset)) {
+		const char *name = fit_get_name(fit, noffset, NULL);
+
+		if (!strncmp(name, FIT_SIG_NODENAME,
+			     strlen(FIT_SIG_NODENAME))) {
+			ret = fit_image_check_sig(fit, noffset, data,
+							size, -1, &err_msg);
+			if (ret) {
+				puts("- ");
+			} else {
+				puts("+ ");
+				verified = 1;
+				break;
+			}
+		}
+	}
+
+	if (noffset == -FDT_ERR_TRUNCATED || noffset == -FDT_ERR_BADSTRUCTURE) {
+		err_msg = "Corrupted or truncated tree";
+		goto error;
+	}
+
+	return verified ? 0 : -EPERM;
+
+error:
+	printf(" error!\n%s for '%s' hash node in '%s' image node\n",
+	       err_msg, fit_get_name(fit, noffset, NULL),
+	       fit_get_name(fit, image_noffset, NULL));
+	return -1;
+}
+
+int fit_image_verify_required_sigs(const void *fit, int image_noffset,
+		const char *data, size_t size, const void *sig_blob,
+		int *no_sigsp)
+{
+	int verify_count = 0;
+	int noffset;
+	int sig_node;
+
+	/* Work out what we need to verify */
+	*no_sigsp = 1;
+	sig_node = fdt_subnode_offset(sig_blob, 0, FIT_SIG_NODENAME);
+	if (sig_node < 0) {
+		debug("%s: No signature node found: %s\n", __func__,
+		      fdt_strerror(sig_node));
+		return 0;
+	}
+
+	for (noffset = fdt_first_subnode(sig_blob, sig_node);
+	     noffset >= 0;
+	     noffset = fdt_next_subnode(sig_blob, noffset)) {
+		const char *required;
+		int ret;
+
+		required = fdt_getprop(sig_blob, noffset, "required", NULL);
+		if (!required || strcmp(required, "image"))
+			continue;
+		ret = fit_image_verify_sig(fit, image_noffset, data, size,
+					sig_blob, noffset);
+		if (ret) {
+			printf("Failed to verify required signature '%s'\n",
+			       fit_get_name(sig_blob, noffset, NULL));
+			return ret;
+		}
+		verify_count++;
+	}
+
+	if (verify_count)
+		*no_sigsp = 0;
+
+	return 0;
+}
diff --git a/doc/uImage.FIT/sign-images.its b/doc/uImage.FIT/sign-images.its
new file mode 100644
index 0000000..f69326a
--- /dev/null
+++ b/doc/uImage.FIT/sign-images.its
@@ -0,0 +1,42 @@
+/dts-v1/;
+
+/ {
+	description = "Chrome OS kernel image with one or more FDT blobs";
+	#address-cells = <1>;
+
+	images {
+		kernel at 1 {
+			data = /incbin/("test-kernel.bin");
+			type = "kernel_noload";
+			arch = "sandbox";
+			os = "linux";
+			compression = "none";
+			load = <0x4>;
+			entry = <0x8>;
+			kernel-version = <1>;
+			signature at 1 {
+				algo = "sha1,rsa2048";
+				key-name-hint = "dev";
+			};
+		};
+		fdt at 1 {
+			description = "snow";
+			data = /incbin/("sandbox-kernel.dtb");
+			type = "flat_dt";
+			arch = "sandbox";
+			compression = "none";
+			fdt-version = <1>;
+			signature at 1 {
+				algo = "sha1,rsa2048";
+				key-name-hint = "dev";
+			};
+		};
+	};
+	configurations {
+		default = "conf at 1";
+		conf at 1 {
+			kernel = "kernel at 1";
+			fdt = "fdt at 1";
+		};
+	};
+};
diff --git a/include/image.h b/include/image.h
index 3f61682..da7b9a0 100644
--- a/include/image.h
+++ b/include/image.h
@@ -766,12 +766,26 @@ int fit_image_hash_get_value(const void *fit, int noffset, uint8_t **value,
 int fit_set_timestamp(void *fit, int noffset, time_t timestamp);
 
 /**
- * fit_add_verification_data() - Calculate and add hashes to FIT
+ * fit_add_verification_data() - add verification data to FIT image nodes
  *
- * @fit:	Fit image to process
- * @return 0 if ok, <0 for error
+ * @keydir:	Directory containing keys
+ * @kwydest:	FDT blob to write public key information to
+ * @fit:	Pointer to the FIT format image header
+ * @comment:	Comment to add to signature nodes
+ * @require_keys: Mark all keys as 'required'
+ *
+ * Adds hash values for all component images in the FIT blob.
+ * Hashes are calculated for all component images which have hash subnodes
+ * with algorithm property set to one of the supported hash algorithms.
+ *
+ * Also add signatures if signature nodes are present.
+ *
+ * returns
+ *     0, on success
+ *     libfdt error code, on failure
  */
-int fit_add_verification_data(void *fit);
+int fit_add_verification_data(const char *keydir, void *keydest, void *fit,
+			      const char *comment, int require_keys);
 
 int fit_image_verify(const void *fit, int noffset);
 int fit_config_verify(const void *fit, int conf_noffset);
@@ -914,6 +928,43 @@ struct image_sig_algo {
  */
 struct image_sig_algo *image_get_sig_algo(const char *name);
 
+/**
+ * fit_image_verify_required_sigs() - Verify signatures marked as 'required'
+ *
+ * @fit:		FIT to check
+ * @image_noffset:	Offset of image node to check
+ * @data:		Image data to check
+ * @size:		Size of image data
+ * @sig_blob:		FDT containing public keys
+ * @no_sigsp:		Returns 1 if no signatures were required, and
+ *			therefore nothing was checked. The caller may wish
+ *			to fall back to other mechanisms, or refuse to
+ *			boot.
+ * @return 0 if all verified ok, <0 on error
+ */
+int fit_image_verify_required_sigs(const void *fit, int image_noffset,
+		const char *data, size_t size, const void *sig_blob,
+		int *no_sigsp);
+
+/**
+ * fit_image_check_sig() - Check a single image signature node
+ *
+ * @fit:		FIT to check
+ * @noffset:		Offset of signature node to check
+ * @data:		Image data to check
+ * @size:		Size of image data
+ * @required_keynode:	Offset in the control FDT of the required key node,
+ *			if any. If this is given, then the image wil not
+ *			pass verification unless that key is used. If this is
+ *			-1 then any signature will do.
+ * @err_msgp:		In the event of an error, this will be pointed to a
+ *			help error string to display to the user.
+ * @return 0 if all verified ok, <0 on error
+ */
+int fit_image_check_sig(const void *fit, int noffset, const void *data,
+		size_t size, int required_keynode, char **err_msgp);
+
+
 static inline int fit_image_check_target_arch(const void *fdt, int node)
 {
 	return fit_image_check_arch(fdt, node, IH_ARCH_DEFAULT);
diff --git a/tools/fit_image.c b/tools/fit_image.c
index cc123dd..ef6ef44 100644
--- a/tools/fit_image.c
+++ b/tools/fit_image.c
@@ -137,7 +137,7 @@ static int fit_handle_file (struct mkimage_params *params)
 		goto err_mmap;
 
 	/* set hashes for images in the blob */
-	if (fit_add_verification_data(ptr)) {
+	if (fit_add_verification_data(NULL, NULL, ptr, NULL, 0)) {
 		fprintf (stderr, "%s Can't add hashes to FIT blob",
 				params->cmdname);
 		goto err_add_hashes;
diff --git a/tools/image-host.c b/tools/image-host.c
index d944d0f..7aebc29 100644
--- a/tools/image-host.c
+++ b/tools/image-host.c
@@ -26,12 +26,8 @@
  */
 
 #include "mkimage.h"
-#include <bootstage.h>
 #include <image.h>
-#include <sha1.h>
-#include <time.h>
-#include <u-boot/crc.h>
-#include <u-boot/md5.h>
+#include <version.h>
 
 /**
  * fit_set_hash_value - set hash value in requested has node
@@ -108,9 +104,165 @@ static int fit_image_process_hash(void *fit, const char *image_name,
 }
 
 /**
- * fit_image_add_verification_data() - calculate/set hash data for image node
+ * fit_image_write_sig() - write the signature to a FIT
  *
- * This adds hash values for a component image node.
+ * This writes the signature and signer data to the FIT.
+ *
+ * @fit: pointer to the FIT format image header
+ * @noffset: hash node offset
+ * @value: signature value to be set
+ * @value_len: signature value length
+ * @comment: Text comment to write (NULL for none)
+ *
+ * returns
+ *     0, on success
+ *     -FDT_ERR_..., on failure
+ */
+static int fit_image_write_sig(void *fit, int noffset, uint8_t *value,
+		int value_len, const char *comment, const char *region_prop,
+		int region_proplen)
+{
+	int string_size;
+	int ret;
+
+	/*
+	 * Get the current string size, before we update the FIT and add
+	 * more
+	 */
+	string_size = fdt_size_dt_strings(fit);
+
+	ret = fdt_setprop(fit, noffset, FIT_VALUE_PROP, value, value_len);
+	if (!ret) {
+		ret = fdt_setprop_string(fit, noffset, "signer-name",
+					 "mkimage");
+	}
+	if (!ret) {
+		ret = fdt_setprop_string(fit, noffset, "signer-version",
+				  PLAIN_VERSION);
+	}
+	if (comment && !ret)
+		ret = fdt_setprop_string(fit, noffset, "comment", comment);
+	if (!ret)
+		ret = fit_set_timestamp(fit, noffset, time(NULL));
+	if (region_prop && !ret) {
+		uint32_t strdata[2];
+
+		ret = fdt_setprop(fit, noffset, "hashed-nodes",
+				   region_prop, region_proplen);
+		strdata[0] = 0;
+		strdata[1] = cpu_to_fdt32(string_size);
+		if (!ret) {
+			ret = fdt_setprop(fit, noffset, "hashed-strings",
+					  strdata, sizeof(strdata));
+		}
+	}
+
+	return ret;
+}
+
+static int fit_image_setup_sig(struct image_sign_info *info,
+		const char *keydir, void *fit, const char *image_name,
+		int noffset, const char *require_keys)
+{
+	const char *node_name;
+	char *algo_name;
+
+	node_name = fit_get_name(fit, noffset, NULL);
+	if (fit_image_hash_get_algo(fit, noffset, &algo_name)) {
+		printf("Can't get algo property for '%s' signature node in '%s' image node\n",
+		       node_name, image_name);
+		return -1;
+	}
+
+	memset(info, '\0', sizeof(*info));
+	info->keydir = keydir;
+	info->keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL);
+	info->fit = fit;
+	info->node_offset = noffset;
+	info->algo = image_get_sig_algo(algo_name);
+	info->require_keys = require_keys;
+	if (!info->algo) {
+		printf("Unsupported signature algorithm (%s) for '%s' signature node in '%s' image node\n",
+		       algo_name, node_name, image_name);
+		return -1;
+	}
+
+	return 0;
+}
+
+/**
+ * fit_image_process_sig- Process a single subnode of the images/ node
+ *
+ * Check each subnode and process accordingly. For signature nodes we
+ * generate a signed hash of the supplised data and store it in the node.
+ *
+ * @keydir:	Directory containing keys to use for signing
+ * @keydest:	Destination FDT blob to write public keys into
+ * @fit:	pointer to the FIT format image header
+ * @image_name:	name of image being processes (used to display errors)
+ * @noffset:	subnode offset
+ * @data:	data to process
+ * @size:	size of data in bytes
+ * @comment:	Comment to add to signature nodes
+ * @require_keys: Mark all keys as 'required'
+ * @return 0 if ok, -1 on error
+ */
+static int fit_image_process_sig(const char *keydir, void *keydest,
+		void *fit, const char *image_name,
+		int noffset, const void *data, size_t size,
+		const char *comment, int require_keys)
+{
+	struct image_sign_info info;
+	struct image_region region;
+	const char *node_name;
+	uint8_t *value;
+	uint value_len;
+	int ret;
+
+	if (fit_image_setup_sig(&info, keydir, fit, image_name, noffset,
+				require_keys ? "image" : NULL))
+		return -1;
+
+	node_name = fit_get_name(fit, noffset, NULL);
+	region.data = data;
+	region.size = size;
+	ret = info.algo->sign(&info, &region, 1, &value, &value_len);
+	if (ret) {
+		printf("Failed to sign '%s' signature node in '%s' image node: %d\n",
+		       node_name, image_name, ret);
+
+		/* We allow keys to be missing */
+		if (ret == -ENOENT)
+			return 0;
+		return -1;
+	}
+
+	ret = fit_image_write_sig(fit, noffset, value, value_len, comment,
+			NULL, 0);
+	if (ret) {
+		printf("Can't write signature for '%s' signature node in '%s' image node: %s\n",
+		       node_name, image_name, fdt_strerror(ret));
+		return -1;
+	}
+	free(value);
+
+	/* Get keyname again, as FDT has changed and invalidated our pointer */
+	info.keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL);
+
+	/* Write the public key into the supplied FDT file */
+	if (keydest && info.algo->add_verify_data(&info, keydest)) {
+		printf("Failed to add verification data for '%s' signature node in '%s' image node\n",
+		       node_name, image_name);
+		return -1;
+	}
+
+	return 0;
+}
+
+/**
+ * fit_image_add_verification_data() - calculate/set verig. data for image node
+ *
+ * This adds hash and signature values for an component image node.
  *
  * All existing hash subnodes are checked, if algorithm property is set to
  * one of the supported hash algorithms, hash value is computed and
@@ -133,11 +285,17 @@ static int fit_image_process_hash(void *fit, const char *image_name,
  *
  * For signature details, please see doc/uImage.FIT/signature.txt
  *
+ * @keydir	Directory containing *.key and *.crt files (or NULL)
+ * @keydest	FDT Blob to write public keys into (NULL if none)
  * @fit:	Pointer to the FIT format image header
  * @image_noffset: Requested component image node
+ * @comment:	Comment to add to signature nodes
+ * @require_keys: Mark all keys as 'required'
  * @return: 0 on success, <0 on failure
  */
-int fit_image_add_verification_data(void *fit, int image_noffset)
+int fit_image_add_verification_data(const char *keydir, void *keydest,
+		void *fit, int image_noffset, const char *comment,
+		int require_keys)
 {
 	const char *image_name;
 	const void *data;
@@ -169,6 +327,12 @@ int fit_image_add_verification_data(void *fit, int image_noffset)
 			     strlen(FIT_HASH_NODENAME))) {
 			ret = fit_image_process_hash(fit, image_name, noffset,
 						data, size);
+		} else if (IMAGE_ENABLE_SIGN && keydir &&
+			   !strncmp(node_name, FIT_SIG_NODENAME,
+				strlen(FIT_SIG_NODENAME))) {
+			ret = fit_image_process_sig(keydir, keydest,
+				fit, image_name, noffset, data, size,
+				comment, require_keys);
 		}
 		if (ret)
 			return -1;
@@ -177,7 +341,8 @@ int fit_image_add_verification_data(void *fit, int image_noffset)
 	return 0;
 }
 
-int fit_add_verification_data(void *fit)
+int fit_add_verification_data(const char *keydir, void *keydest, void *fit,
+			      const char *comment, int require_keys)
 {
 	int images_noffset;
 	int noffset;
@@ -199,7 +364,8 @@ int fit_add_verification_data(void *fit)
 		 * Direct child node of the images parent node,
 		 * i.e. component image node.
 		 */
-		ret = fit_image_add_verification_data(fit, noffset);
+		ret = fit_image_add_verification_data(keydir, keydest,
+				fit, noffset, comment, require_keys);
 		if (ret)
 			return ret;
 	}
-- 
1.8.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [U-Boot] [PATCH v3 03/12] image: Add RSA support for image signing
  2013-06-13 22:09 ` [U-Boot] " Simon Glass
                   ` (2 preceding siblings ...)
  (?)
@ 2013-06-13 22:10 ` Simon Glass
  2013-06-27  4:08   ` Masahiro Yamada
  -1 siblings, 1 reply; 27+ messages in thread
From: Simon Glass @ 2013-06-13 22:10 UTC (permalink / raw)
  To: u-boot

RSA provides a public key encryption facility which is ideal for image
signing and verification.

Images are signed using a private key by mkimage. Then at run-time, the
images are verified using a private key.

This implementation uses openssl for the host part (mkimage). To avoid
bringing large libraries into the U-Boot binary, the RSA public key
is encoded using a simple numeric representation in the device tree.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
Changes in v3: None
Changes in v2:
- Add sanity checks on key sizes in RSA (improves security)
- Avoid using malloc in RSA routines (for smaller SPL code size)
- Build signing support unconditionally in mkimage
- Fix checkpatch checks about parenthesis alignment
- Fix spelling of multiply in rsa-verify.c
- Only build RSA support into mkimage if CONFIG_RSA is defined
- Support RSA library version without ERR_remove_thread_state()

 Makefile             |   1 +
 README               |  10 ++
 common/image-sig.c   |   7 +
 config.mk            |   1 +
 include/rsa.h        | 108 ++++++++++++
 lib/rsa/Makefile     |  48 ++++++
 lib/rsa/rsa-sign.c   | 460 +++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/rsa/rsa-verify.c | 385 ++++++++++++++++++++++++++++++++++++++++++
 tools/Makefile       |  13 +-
 9 files changed, 1031 insertions(+), 2 deletions(-)
 create mode 100644 include/rsa.h
 create mode 100644 lib/rsa/Makefile
 create mode 100644 lib/rsa/rsa-sign.c
 create mode 100644 lib/rsa/rsa-verify.c

diff --git a/Makefile b/Makefile
index eb751f4..90f2bb9 100644
--- a/Makefile
+++ b/Makefile
@@ -247,6 +247,7 @@ OBJS := $(addprefix $(obj),$(OBJS))
 HAVE_VENDOR_COMMON_LIB = $(if $(wildcard board/$(VENDOR)/common/Makefile),y,n)
 
 LIBS-y += lib/libgeneric.o
+LIBS-y += lib/rsa/librsa.o
 LIBS-y += lib/lzma/liblzma.o
 LIBS-y += lib/lzo/liblzo.o
 LIBS-y += lib/zlib/libz.o
diff --git a/README b/README
index 3e586c3..f91e431 100644
--- a/README
+++ b/README
@@ -2557,6 +2557,16 @@ CBFS (Coreboot Filesystem) support
 		Note: There is also a sha1sum command, which should perhaps
 		be deprecated in favour of 'hash sha1'.
 
+- Signing support:
+		CONFIG_RSA
+
+		This enables the RSA algorithm used for FIT image verification
+		in U-Boot. See doc/uImage/signature for more information.
+
+		The signing part is build into mkimage regardless of this
+		option.
+
+
 - Show boot progress:
 		CONFIG_SHOW_BOOT_PROGRESS
 
diff --git a/common/image-sig.c b/common/image-sig.c
index 9b222da..9928bfc 100644
--- a/common/image-sig.c
+++ b/common/image-sig.c
@@ -27,8 +27,15 @@ DECLARE_GLOBAL_DATA_PTR;
 #endif /* !USE_HOSTCC*/
 #include <errno.h>
 #include <image.h>
+#include <rsa.h>
 
 struct image_sig_algo image_sig_algos[] = {
+	{
+		"sha1,rsa2048",
+		rsa_sign,
+		rsa_add_verify_data,
+		rsa_verify,
+	}
 };
 
 struct image_sig_algo *image_get_sig_algo(const char *name)
diff --git a/config.mk b/config.mk
index 9003268..a5e26e3 100644
--- a/config.mk
+++ b/config.mk
@@ -96,6 +96,7 @@ HOSTCFLAGS	+= $(call os_x_before, 10, 4, "-traditional-cpp")
 HOSTLDFLAGS	+= $(call os_x_before, 10, 5, "-multiply_defined suppress")
 else
 HOSTCC		= gcc
+HOSTLIBS	+= -lssl -lcrypto
 endif
 
 ifeq ($(HOSTOS),cygwin)
diff --git a/include/rsa.h b/include/rsa.h
new file mode 100644
index 0000000..a5dd676
--- /dev/null
+++ b/include/rsa.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2013, Google Inc.
+ *
+ * (C) Copyright 2008 Semihalf
+ *
+ * (C) Copyright 2000-2006
+ * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef _RSA_H
+#define _RSA_H
+
+#include <errno.h>
+#include <image.h>
+
+#if IMAGE_ENABLE_SIGN
+/**
+ * sign() - calculate and return signature for given input data
+ *
+ * @info:	Specifies key and FIT information
+ * @data:	Pointer to the input data
+ * @data_len:	Data length
+ * @sigp:	Set to an allocated buffer holding the signature
+ * @sig_len:	Set to length of the calculated hash
+ *
+ * This computes input data signature according to selected algorithm.
+ * Resulting signature value is placed in an allocated buffer, the
+ * pointer is returned as *sigp. The length of the calculated
+ * signature is returned via the sig_len pointer argument. The caller
+ * should free *sigp.
+ *
+ * @return: 0, on success, -ve on error
+ */
+int rsa_sign(struct image_sign_info *info,
+	     const struct image_region region[],
+	     int region_count, uint8_t **sigp, uint *sig_len);
+
+/**
+ * add_verify_data() - Add verification information to FDT
+ *
+ * Add public key information to the FDT node, suitable for
+ * verification at run-time. The information added depends on the
+ * algorithm being used.
+ *
+ * @info:	Specifies key and FIT information
+ * @keydest:	Destination FDT blob for public key data
+ * @return: 0, on success, -ve on error
+*/
+int rsa_add_verify_data(struct image_sign_info *info, void *keydest);
+#else
+static inline int rsa_sign(struct image_sign_info *info,
+		const struct image_region region[], int region_count,
+		uint8_t **sigp, uint *sig_len)
+{
+	return -ENXIO;
+}
+
+static inline int rsa_add_verify_data(struct image_sign_info *info,
+				      void *keydest)
+{
+	return -ENXIO;
+}
+#endif
+
+#if IMAGE_ENABLE_VERIFY
+/**
+ * rsa_verify() - Verify a signature against some data
+ *
+ * Verify a RSA PKCS1.5 signature against an expected hash.
+ *
+ * @info:	Specifies key and FIT information
+ * @data:	Pointer to the input data
+ * @data_len:	Data length
+ * @sig:	Signature
+ * @sig_len:	Number of bytes in signature
+ * @return 0 if verified, -ve on error
+ */
+int rsa_verify(struct image_sign_info *info,
+	       const struct image_region region[], int region_count,
+	       uint8_t *sig, uint sig_len);
+#else
+static inline int rsa_verify(struct image_sign_info *info,
+		const struct image_region region[], int region_count,
+		uint8_t *sig, uint sig_len)
+{
+	return -ENXIO;
+}
+#endif
+
+#endif
diff --git a/lib/rsa/Makefile b/lib/rsa/Makefile
new file mode 100644
index 0000000..9eb3e40
--- /dev/null
+++ b/lib/rsa/Makefile
@@ -0,0 +1,48 @@
+#
+# Copyright (c) 2013, Google Inc.
+#
+# (C) Copyright 2000-2007
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)librsa.o
+
+ifdef CONFIG_FIT_SIGNATURE
+COBJS-$(CONFIG_RSA) += rsa-verify.o
+endif
+
+COBJS	:= $(sort $(COBJS-y))
+SRCS	:= $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS))
+
+$(LIB):	$(obj).depend $(OBJS)
+	$(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/lib/rsa/rsa-sign.c b/lib/rsa/rsa-sign.c
new file mode 100644
index 0000000..a75ae24
--- /dev/null
+++ b/lib/rsa/rsa-sign.c
@@ -0,0 +1,460 @@
+/*
+ * Copyright (c) 2013, Google Inc.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include "mkimage.h"
+#include <stdio.h>
+#include <string.h>
+#include <error.h>
+#include <image.h>
+#include <time.h>
+#include <openssl/rsa.h>
+#include <openssl/pem.h>
+#include <openssl/err.h>
+#include <openssl/ssl.h>
+#include <openssl/evp.h>
+
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+#define HAVE_ERR_REMOVE_THREAD_STATE
+#endif
+
+static int rsa_err(const char *msg)
+{
+	unsigned long sslErr = ERR_get_error();
+
+	fprintf(stderr, "%s", msg);
+	fprintf(stderr, ": %s\n",
+		ERR_error_string(sslErr, 0));
+
+	return -1;
+}
+
+/**
+ * rsa_get_pub_key() - read a public key from a .crt file
+ *
+ * @keydir:	Directory containins the key
+ * @name	Name of key file (will have a .crt extension)
+ * @rsap	Returns RSA object, or NULL on failure
+ * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL)
+ */
+static int rsa_get_pub_key(const char *keydir, const char *name, RSA **rsap)
+{
+	char path[1024];
+	EVP_PKEY *key;
+	X509 *cert;
+	RSA *rsa;
+	FILE *f;
+	int ret;
+
+	*rsap = NULL;
+	snprintf(path, sizeof(path), "%s/%s.crt", keydir, name);
+	f = fopen(path, "r");
+	if (!f) {
+		fprintf(stderr, "Couldn't open RSA certificate: '%s': %s\n",
+			path, strerror(errno));
+		return -EACCES;
+	}
+
+	/* Read the certificate */
+	cert = NULL;
+	if (!PEM_read_X509(f, &cert, NULL, NULL)) {
+		rsa_err("Couldn't read certificate");
+		ret = -EINVAL;
+		goto err_cert;
+	}
+
+	/* Get the public key from the certificate. */
+	key = X509_get_pubkey(cert);
+	if (!key) {
+		rsa_err("Couldn't read public key\n");
+		ret = -EINVAL;
+		goto err_pubkey;
+	}
+
+	/* Convert to a RSA_style key. */
+	rsa = EVP_PKEY_get1_RSA(key);
+	if (!rsa) {
+		rsa_err("Couldn't convert to a RSA style key");
+		goto err_rsa;
+	}
+	fclose(f);
+	EVP_PKEY_free(key);
+	X509_free(cert);
+	*rsap = rsa;
+
+	return 0;
+
+err_rsa:
+	EVP_PKEY_free(key);
+err_pubkey:
+	X509_free(cert);
+err_cert:
+	fclose(f);
+	return ret;
+}
+
+/**
+ * rsa_get_priv_key() - read a private key from a .key file
+ *
+ * @keydir:	Directory containins the key
+ * @name	Name of key file (will have a .key extension)
+ * @rsap	Returns RSA object, or NULL on failure
+ * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL)
+ */
+static int rsa_get_priv_key(const char *keydir, const char *name, RSA **rsap)
+{
+	char path[1024];
+	RSA *rsa;
+	FILE *f;
+
+	*rsap = NULL;
+	snprintf(path, sizeof(path), "%s/%s.key", keydir, name);
+	f = fopen(path, "r");
+	if (!f) {
+		fprintf(stderr, "Couldn't open RSA private key: '%s': %s\n",
+			path, strerror(errno));
+		return -ENOENT;
+	}
+
+	rsa = PEM_read_RSAPrivateKey(f, 0, NULL, path);
+	if (!rsa) {
+		rsa_err("Failure reading private key");
+		fclose(f);
+		return -EPROTO;
+	}
+	fclose(f);
+	*rsap = rsa;
+
+	return 0;
+}
+
+static int rsa_init(void)
+{
+	int ret;
+
+	ret = SSL_library_init();
+	if (!ret) {
+		fprintf(stderr, "Failure to init SSL library\n");
+		return -1;
+	}
+	SSL_load_error_strings();
+
+	OpenSSL_add_all_algorithms();
+	OpenSSL_add_all_digests();
+	OpenSSL_add_all_ciphers();
+
+	return 0;
+}
+
+static void rsa_remove(void)
+{
+	CRYPTO_cleanup_all_ex_data();
+	ERR_free_strings();
+#ifdef HAVE_ERR_REMOVE_THREAD_STATE
+	ERR_remove_thread_state(NULL);
+#else
+	ERR_remove_state(0);
+#endif
+	EVP_cleanup();
+}
+
+static int rsa_sign_with_key(RSA *rsa, const struct image_region region[],
+		int region_count, uint8_t **sigp, uint *sig_size)
+{
+	EVP_PKEY *key;
+	EVP_MD_CTX *context;
+	int size, ret = 0;
+	uint8_t *sig;
+	int i;
+
+	key = EVP_PKEY_new();
+	if (!key)
+		return rsa_err("EVP_PKEY object creation failed");
+
+	if (!EVP_PKEY_set1_RSA(key, rsa)) {
+		ret = rsa_err("EVP key setup failed");
+		goto err_set;
+	}
+
+	size = EVP_PKEY_size(key);
+	sig = malloc(size);
+	if (!sig) {
+		fprintf(stderr, "Out of memory for signature (%d bytes)\n",
+			size);
+		ret = -ENOMEM;
+		goto err_alloc;
+	}
+
+	context = EVP_MD_CTX_create();
+	if (!context) {
+		ret = rsa_err("EVP context creation failed");
+		goto err_create;
+	}
+	EVP_MD_CTX_init(context);
+	if (!EVP_SignInit(context, EVP_sha1())) {
+		ret = rsa_err("Signer setup failed");
+		goto err_sign;
+	}
+
+	for (i = 0; i < region_count; i++) {
+		if (!EVP_SignUpdate(context, region[i].data, region[i].size)) {
+			ret = rsa_err("Signing data failed");
+			goto err_sign;
+		}
+	}
+
+	if (!EVP_SignFinal(context, sig, sig_size, key)) {
+		ret = rsa_err("Could not obtain signature");
+		goto err_sign;
+	}
+	EVP_MD_CTX_cleanup(context);
+	EVP_MD_CTX_destroy(context);
+	EVP_PKEY_free(key);
+
+	debug("Got signature: %d bytes, expected %d\n", *sig_size, size);
+	*sigp = sig;
+	*sig_size = size;
+
+	return 0;
+
+err_sign:
+	EVP_MD_CTX_destroy(context);
+err_create:
+	free(sig);
+err_alloc:
+err_set:
+	EVP_PKEY_free(key);
+	return ret;
+}
+
+int rsa_sign(struct image_sign_info *info,
+	     const struct image_region region[], int region_count,
+	     uint8_t **sigp, uint *sig_len)
+{
+	RSA *rsa;
+	int ret;
+
+	ret = rsa_init();
+	if (ret)
+		return ret;
+
+	ret = rsa_get_priv_key(info->keydir, info->keyname, &rsa);
+	if (ret)
+		goto err_priv;
+	ret = rsa_sign_with_key(rsa, region, region_count, sigp, sig_len);
+	if (ret)
+		goto err_sign;
+
+	RSA_free(rsa);
+	rsa_remove();
+
+	return ret;
+
+err_sign:
+	RSA_free(rsa);
+err_priv:
+	rsa_remove();
+	return ret;
+}
+
+/*
+ * rsa_get_params(): - Get the important parameters of an RSA public key
+ */
+int rsa_get_params(RSA *key, uint32_t *n0_invp, BIGNUM **modulusp,
+		   BIGNUM **r_squaredp)
+{
+	BIGNUM *big1, *big2, *big32, *big2_32;
+	BIGNUM *n, *r, *r_squared, *tmp;
+	BN_CTX *bn_ctx = BN_CTX_new();
+	int ret = 0;
+
+	/* Initialize BIGNUMs */
+	big1 = BN_new();
+	big2 = BN_new();
+	big32 = BN_new();
+	r = BN_new();
+	r_squared = BN_new();
+	tmp = BN_new();
+	big2_32 = BN_new();
+	n = BN_new();
+	if (!big1 || !big2 || !big32 || !r || !r_squared || !tmp || !big2_32 ||
+	    !n) {
+		fprintf(stderr, "Out of memory (bignum)\n");
+		return -ENOMEM;
+	}
+
+	if (!BN_copy(n, key->n) || !BN_set_word(big1, 1L) ||
+	    !BN_set_word(big2, 2L) || !BN_set_word(big32, 32L))
+		ret = -1;
+
+	/* big2_32 = 2^32 */
+	if (!BN_exp(big2_32, big2, big32, bn_ctx))
+		ret = -1;
+
+	/* Calculate n0_inv = -1 / n[0] mod 2^32 */
+	if (!BN_mod_inverse(tmp, n, big2_32, bn_ctx) ||
+	    !BN_sub(tmp, big2_32, tmp))
+		ret = -1;
+	*n0_invp = BN_get_word(tmp);
+
+	/* Calculate R = 2^(# of key bits) */
+	if (!BN_set_word(tmp, BN_num_bits(n)) ||
+	    !BN_exp(r, big2, tmp, bn_ctx))
+		ret = -1;
+
+	/* Calculate r_squared = R^2 mod n */
+	if (!BN_copy(r_squared, r) ||
+	    !BN_mul(tmp, r_squared, r, bn_ctx) ||
+	    !BN_mod(r_squared, tmp, n, bn_ctx))
+		ret = -1;
+
+	*modulusp = n;
+	*r_squaredp = r_squared;
+
+	BN_free(big1);
+	BN_free(big2);
+	BN_free(big32);
+	BN_free(r);
+	BN_free(tmp);
+	BN_free(big2_32);
+	if (ret) {
+		fprintf(stderr, "Bignum operations failed\n");
+		return -ENOMEM;
+	}
+
+	return ret;
+}
+
+static int fdt_add_bignum(void *blob, int noffset, const char *prop_name,
+			  BIGNUM *num, int num_bits)
+{
+	int nwords = num_bits / 32;
+	int size;
+	uint32_t *buf, *ptr;
+	BIGNUM *tmp, *big2, *big32, *big2_32;
+	BN_CTX *ctx;
+	int ret;
+
+	tmp = BN_new();
+	big2 = BN_new();
+	big32 = BN_new();
+	big2_32 = BN_new();
+	if (!tmp || !big2 || !big32 || !big2_32) {
+		fprintf(stderr, "Out of memory (bignum)\n");
+		return -ENOMEM;
+	}
+	ctx = BN_CTX_new();
+	if (!tmp) {
+		fprintf(stderr, "Out of memory (bignum context)\n");
+		return -ENOMEM;
+	}
+	BN_set_word(big2, 2L);
+	BN_set_word(big32, 32L);
+	BN_exp(big2_32, big2, big32, ctx); /* B = 2^32 */
+
+	size = nwords * sizeof(uint32_t);
+	buf = malloc(size);
+	if (!buf) {
+		fprintf(stderr, "Out of memory (%d bytes)\n", size);
+		return -ENOMEM;
+	}
+
+	/* Write out modulus as big endian array of integers */
+	for (ptr = buf + nwords - 1; ptr >= buf; ptr--) {
+		BN_mod(tmp, num, big2_32, ctx); /* n = N mod B */
+		*ptr = cpu_to_fdt32(BN_get_word(tmp));
+		BN_rshift(num, num, 32); /*  N = N/B */
+	}
+
+	ret = fdt_setprop(blob, noffset, prop_name, buf, size);
+	if (ret) {
+		fprintf(stderr, "Failed to write public key to FIT\n");
+		return -ENOSPC;
+	}
+	free(buf);
+	BN_free(tmp);
+	BN_free(big2);
+	BN_free(big32);
+	BN_free(big2_32);
+
+	return ret;
+}
+
+int rsa_add_verify_data(struct image_sign_info *info, void *keydest)
+{
+	BIGNUM *modulus, *r_squared;
+	uint32_t n0_inv;
+	int parent, node;
+	char name[100];
+	int ret;
+	int bits;
+	RSA *rsa;
+
+	debug("%s: Getting verification data\n", __func__);
+	ret = rsa_get_pub_key(info->keydir, info->keyname, &rsa);
+	if (ret)
+		return ret;
+	ret = rsa_get_params(rsa, &n0_inv, &modulus, &r_squared);
+	if (ret)
+		return ret;
+	bits = BN_num_bits(modulus);
+	parent = fdt_subnode_offset(keydest, 0, FIT_SIG_NODENAME);
+	if (parent == -FDT_ERR_NOTFOUND) {
+		parent = fdt_add_subnode(keydest, 0, FIT_SIG_NODENAME);
+		if (parent < 0) {
+			fprintf(stderr, "Couldn't create signature node: %s\n",
+				fdt_strerror(parent));
+			return -EINVAL;
+		}
+	}
+
+	/* Either create or overwrite the named key node */
+	snprintf(name, sizeof(name), "key-%s", info->keyname);
+	node = fdt_subnode_offset(keydest, parent, name);
+	if (node == -FDT_ERR_NOTFOUND) {
+		node = fdt_add_subnode(keydest, parent, name);
+		if (node < 0) {
+			fprintf(stderr, "Could not create key subnode: %s\n",
+				fdt_strerror(node));
+			return -EINVAL;
+		}
+	} else if (node < 0) {
+		fprintf(stderr, "Cannot select keys parent: %s\n",
+			fdt_strerror(node));
+		return -ENOSPC;
+	}
+
+	ret = fdt_setprop_string(keydest, node, "key-name-hint",
+				 info->keyname);
+	ret |= fdt_setprop_u32(keydest, node, "rsa,num-bits", bits);
+	ret |= fdt_setprop_u32(keydest, node, "rsa,n0-inverse", n0_inv);
+	ret |= fdt_add_bignum(keydest, node, "rsa,modulus", modulus, bits);
+	ret |= fdt_add_bignum(keydest, node, "rsa,r-squared", r_squared, bits);
+	ret |= fdt_setprop_string(keydest, node, FIT_ALGO_PROP,
+				  info->algo->name);
+	if (info->require_keys) {
+		fdt_setprop_string(keydest, node, "required",
+				   info->require_keys);
+	}
+	BN_free(modulus);
+	BN_free(r_squared);
+	if (ret)
+		return -EIO;
+
+	return 0;
+}
diff --git a/lib/rsa/rsa-verify.c b/lib/rsa/rsa-verify.c
new file mode 100644
index 0000000..6a02689
--- /dev/null
+++ b/lib/rsa/rsa-verify.c
@@ -0,0 +1,385 @@
+/*
+ * Copyright (c) 2013, Google Inc.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <fdtdec.h>
+#include <rsa.h>
+#include <sha1.h>
+#include <asm/byteorder.h>
+#include <asm/errno.h>
+#include <asm/unaligned.h>
+
+/**
+ * struct rsa_public_key - holder for a public key
+ *
+ * An RSA public key consists of a modulus (typically called N), the inverse
+ * and R^2, where R is 2^(# key bits).
+ */
+struct rsa_public_key {
+	uint len;		/* Length of modulus[] in number of uint32_t */
+	uint32_t n0inv;		/* -1 / modulus[0] mod 2^32 */
+	uint32_t *modulus;	/* modulus as little endian array */
+	uint32_t *rr;		/* R^2 as little endian array */
+};
+
+#define UINT64_MULT32(v, multby)  (((uint64_t)(v)) * ((uint32_t)(multby)))
+
+#define RSA2048_BYTES	(2048 / 8)
+
+/* This is the minimum/maximum key size we support, in bits */
+#define RSA_MIN_KEY_BITS	2048
+#define RSA_MAX_KEY_BITS	2048
+
+/* This is the maximum signature length that we support, in bits */
+#define RSA_MAX_SIG_BITS	2048
+
+static const uint8_t padding_sha1_rsa2048[RSA2048_BYTES - SHA1_SUM_LEN] = {
+	0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0x00, 0x30, 0x21, 0x30,
+	0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a,
+	0x05, 0x00, 0x04, 0x14
+};
+
+/**
+ * subtract_modulus() - subtract modulus from the given value
+ *
+ * @key:	Key containing modulus to subtract
+ * @num:	Number to subtract modulus from, as little endian word array
+ */
+static void subtract_modulus(const struct rsa_public_key *key, uint32_t num[])
+{
+	int64_t acc = 0;
+	uint i;
+
+	for (i = 0; i < key->len; i++) {
+		acc += (uint64_t)num[i] - key->modulus[i];
+		num[i] = (uint32_t)acc;
+		acc >>= 32;
+	}
+}
+
+/**
+ * greater_equal_modulus() - check if a value is >= modulus
+ *
+ * @key:	Key containing modulus to check
+ * @num:	Number to check against modulus, as little endian word array
+ * @return 0 if num < modulus, 1 if num >= modulus
+ */
+static int greater_equal_modulus(const struct rsa_public_key *key,
+				 uint32_t num[])
+{
+	uint32_t i;
+
+	for (i = key->len - 1; i >= 0; i--) {
+		if (num[i] < key->modulus[i])
+			return 0;
+		if (num[i] > key->modulus[i])
+			return 1;
+	}
+
+	return 1;  /* equal */
+}
+
+/**
+ * montgomery_mul_add_step() - Perform montgomery multiply-add step
+ *
+ * Operation: montgomery result[] += a * b[] / n0inv % modulus
+ *
+ * @key:	RSA key
+ * @result:	Place to put result, as little endian word array
+ * @a:		Multiplier
+ * @b:		Multiplicand, as little endian word array
+ */
+static void montgomery_mul_add_step(const struct rsa_public_key *key,
+		uint32_t result[], const uint32_t a, const uint32_t b[])
+{
+	uint64_t acc_a, acc_b;
+	uint32_t d0;
+	uint i;
+
+	acc_a = (uint64_t)a * b[0] + result[0];
+	d0 = (uint32_t)acc_a * key->n0inv;
+	acc_b = (uint64_t)d0 * key->modulus[0] + (uint32_t)acc_a;
+	for (i = 1; i < key->len; i++) {
+		acc_a = (acc_a >> 32) + (uint64_t)a * b[i] + result[i];
+		acc_b = (acc_b >> 32) + (uint64_t)d0 * key->modulus[i] +
+				(uint32_t)acc_a;
+		result[i - 1] = (uint32_t)acc_b;
+	}
+
+	acc_a = (acc_a >> 32) + (acc_b >> 32);
+
+	result[i - 1] = (uint32_t)acc_a;
+
+	if (acc_a >> 32)
+		subtract_modulus(key, result);
+}
+
+/**
+ * montgomery_mul() - Perform montgomery mutitply
+ *
+ * Operation: montgomery result[] = a[] * b[] / n0inv % modulus
+ *
+ * @key:	RSA key
+ * @result:	Place to put result, as little endian word array
+ * @a:		Multiplier, as little endian word array
+ * @b:		Multiplicand, as little endian word array
+ */
+static void montgomery_mul(const struct rsa_public_key *key,
+		uint32_t result[], uint32_t a[], const uint32_t b[])
+{
+	uint i;
+
+	for (i = 0; i < key->len; ++i)
+		result[i] = 0;
+	for (i = 0; i < key->len; ++i)
+		montgomery_mul_add_step(key, result, a[i], b);
+}
+
+/**
+ * pow_mod() - in-place public exponentiation
+ *
+ * @key:	RSA key
+ * @inout:	Big-endian word array containing value and result
+ */
+static int pow_mod(const struct rsa_public_key *key, uint32_t *inout)
+{
+	uint32_t *result, *ptr;
+	uint i;
+
+	/* Sanity check for stack size - key->len is in 32-bit words */
+	if (key->len > RSA_MAX_KEY_BITS / 32) {
+		debug("RSA key words %u exceeds maximum %d\n", key->len,
+		      RSA_MAX_KEY_BITS / 32);
+		return -EINVAL;
+	}
+
+	uint32_t val[key->len], acc[key->len], tmp[key->len];
+	result = tmp;  /* Re-use location. */
+
+	/* Convert from big endian byte array to little endian word array. */
+	for (i = 0, ptr = inout + key->len - 1; i < key->len; i++, ptr--)
+		val[i] = get_unaligned_be32(ptr);
+
+	montgomery_mul(key, acc, val, key->rr);  /* axx = a * RR / R mod M */
+	for (i = 0; i < 16; i += 2) {
+		montgomery_mul(key, tmp, acc, acc); /* tmp = acc^2 / R mod M */
+		montgomery_mul(key, acc, tmp, tmp); /* acc = tmp^2 / R mod M */
+	}
+	montgomery_mul(key, result, acc, val);  /* result = XX * a / R mod M */
+
+	/* Make sure result < mod; result is@most 1x mod too large. */
+	if (greater_equal_modulus(key, result))
+		subtract_modulus(key, result);
+
+	/* Convert to bigendian byte array */
+	for (i = key->len - 1, ptr = inout; (int)i >= 0; i--, ptr++)
+		put_unaligned_be32(result[i], ptr);
+
+	return 0;
+}
+
+static int rsa_verify_key(const struct rsa_public_key *key, const uint8_t *sig,
+		const uint32_t sig_len, const uint8_t *hash)
+{
+	const uint8_t *padding;
+	int pad_len;
+	int ret;
+
+	if (!key || !sig || !hash)
+		return -EIO;
+
+	if (sig_len != (key->len * sizeof(uint32_t))) {
+		debug("Signature is of incorrect length %d\n", sig_len);
+		return -EINVAL;
+	}
+
+	/* Sanity check for stack size */
+	if (sig_len > RSA_MAX_SIG_BITS / 8) {
+		debug("Signature length %u exceeds maximum %d\n", sig_len,
+		      RSA_MAX_SIG_BITS / 8);
+		return -EINVAL;
+	}
+
+	uint32_t buf[sig_len / sizeof(uint32_t)];
+
+	memcpy(buf, sig, sig_len);
+
+	ret = pow_mod(key, buf);
+	if (ret)
+		return ret;
+
+	/* Determine padding to use depending on the signature type. */
+	padding = padding_sha1_rsa2048;
+	pad_len = RSA2048_BYTES - SHA1_SUM_LEN;
+
+	/* Check pkcs1.5 padding bytes. */
+	if (memcmp(buf, padding, pad_len)) {
+		debug("In RSAVerify(): Padding check failed!\n");
+		return -EINVAL;
+	}
+
+	/* Check hash. */
+	if (memcmp((uint8_t *)buf + pad_len, hash, sig_len - pad_len)) {
+		debug("In RSAVerify(): Hash check failed!\n");
+		return -EACCES;
+	}
+
+	return 0;
+}
+
+static void rsa_convert_big_endian(uint32_t *dst, const uint32_t *src, int len)
+{
+	int i;
+
+	for (i = 0; i < len; i++)
+		dst[i] = fdt32_to_cpu(src[len - 1 - i]);
+}
+
+static int rsa_verify_with_keynode(struct image_sign_info *info,
+		const void *hash, uint8_t *sig, uint sig_len, int node)
+{
+	const void *blob = info->fdt_blob;
+	struct rsa_public_key key;
+	const void *modulus, *rr;
+	int ret;
+
+	if (node < 0) {
+		debug("%s: Skipping invalid node", __func__);
+		return -EBADF;
+	}
+	if (!fdt_getprop(blob, node, "rsa,n0-inverse", NULL)) {
+		debug("%s: Missing rsa,n0-inverse", __func__);
+		return -EFAULT;
+	}
+	key.len = fdtdec_get_int(blob, node, "rsa,num-bits", 0);
+	key.n0inv = fdtdec_get_int(blob, node, "rsa,n0-inverse", 0);
+	modulus = fdt_getprop(blob, node, "rsa,modulus", NULL);
+	rr = fdt_getprop(blob, node, "rsa,r-squared", NULL);
+	if (!key.len || !modulus || !rr) {
+		debug("%s: Missing RSA key info", __func__);
+		return -EFAULT;
+	}
+
+	/* Sanity check for stack size */
+	if (key.len > RSA_MAX_KEY_BITS || key.len < RSA_MIN_KEY_BITS) {
+		debug("RSA key bits %u outside allowed range %d..%d\n",
+		      key.len, RSA_MIN_KEY_BITS, RSA_MAX_KEY_BITS);
+		return -EFAULT;
+	}
+	key.len /= sizeof(uint32_t) * 8;
+	uint32_t key1[key.len], key2[key.len];
+
+	key.modulus = key1;
+	key.rr = key2;
+	rsa_convert_big_endian(key.modulus, modulus, key.len);
+	rsa_convert_big_endian(key.rr, rr, key.len);
+	if (!key.modulus || !key.rr) {
+		debug("%s: Out of memory", __func__);
+		return -ENOMEM;
+	}
+
+	debug("key length %d\n", key.len);
+	ret = rsa_verify_key(&key, sig, sig_len, hash);
+	if (ret) {
+		printf("%s: RSA failed to verify: %d\n", __func__, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+int rsa_verify(struct image_sign_info *info,
+	       const struct image_region region[], int region_count,
+	       uint8_t *sig, uint sig_len)
+{
+	const void *blob = info->fdt_blob;
+	uint8_t hash[SHA1_SUM_LEN];
+	int ndepth, noffset;
+	int sig_node, node;
+	char name[100];
+	sha1_context ctx;
+	int ret, i;
+
+	sig_node = fdt_subnode_offset(blob, 0, FIT_SIG_NODENAME);
+	if (sig_node < 0) {
+		debug("%s: No signature node found\n", __func__);
+		return -ENOENT;
+	}
+
+	sha1_starts(&ctx);
+	for (i = 0; i < region_count; i++)
+		sha1_update(&ctx, region[i].data, region[i].size);
+	sha1_finish(&ctx, hash);
+
+	/* See if we must use a particular key */
+	if (info->required_keynode != -1) {
+		ret = rsa_verify_with_keynode(info, hash, sig, sig_len,
+			info->required_keynode);
+		if (!ret)
+			return ret;
+	}
+
+	/* Look for a key that matches our hint */
+	snprintf(name, sizeof(name), "key-%s", info->keyname);
+	node = fdt_subnode_offset(blob, sig_node, name);
+	ret = rsa_verify_with_keynode(info, hash, sig, sig_len, node);
+	if (!ret)
+		return ret;
+
+	/* No luck, so try each of the keys in turn */
+	for (ndepth = 0, noffset = fdt_next_node(info->fit, sig_node, &ndepth);
+			(noffset >= 0) && (ndepth > 0);
+			noffset = fdt_next_node(info->fit, noffset, &ndepth)) {
+		if (ndepth == 1 && noffset != node) {
+			ret = rsa_verify_with_keynode(info, hash, sig, sig_len,
+						      noffset);
+			if (!ret)
+				break;
+		}
+	}
+
+	return ret;
+}
diff --git a/tools/Makefile b/tools/Makefile
index 38fd934..b589cae 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -125,6 +125,9 @@ LIBFDT_OBJ_FILES-y += fdt_rw.o
 LIBFDT_OBJ_FILES-y += fdt_strerror.o
 LIBFDT_OBJ_FILES-y += fdt_wip.o
 
+# RSA objects
+RSA_OBJ_FILES-y += rsa-sign.o
+
 # Generated LCD/video logo
 LOGO_H = $(OBJTREE)/include/bmp_logo.h
 LOGO_DATA_H = $(OBJTREE)/include/bmp_logo_data.h
@@ -159,8 +162,10 @@ endif
 HOSTSRCS += $(addprefix $(SRCTREE)/,$(EXT_OBJ_FILES-y:.o=.c))
 HOSTSRCS += $(addprefix $(SRCTREE)/tools/,$(OBJ_FILES-y:.o=.c))
 HOSTSRCS += $(addprefix $(SRCTREE)/lib/libfdt/,$(LIBFDT_OBJ_FILES-y:.o=.c))
+HOSTSRCS += $(addprefix $(SRCTREE)/lib/rsa/,$(RSA_OBJ_FILES-y:.o=.c))
 BINS	:= $(addprefix $(obj),$(sort $(BIN_FILES-y)))
 LIBFDT_OBJS	:= $(addprefix $(obj),$(LIBFDT_OBJ_FILES-y))
+RSA_OBJS	:= $(addprefix $(obj),$(RSA_OBJ_FILES-y))
 
 # We cannot check CONFIG_FIT_SIGNATURE here since it is not set on the host
 FIT_SIG_OBJ_FILES	:= image-sig.o
@@ -235,8 +240,9 @@ $(obj)mkimage$(SFX):	$(obj)aisimage.o \
 			$(obj)omapimage.o \
 			$(obj)sha1.o \
 			$(obj)ublimage.o \
-			$(LIBFDT_OBJS)
-	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+			$(LIBFDT_OBJS) \
+			$(RSA_OBJS)
+	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^ $(HOSTLIBS)
 	$(HOSTSTRIP) $@
 
 $(obj)mk$(BOARD)spl$(SFX):	$(obj)mkexynosspl.o
@@ -272,6 +278,9 @@ $(obj)%.o: $(SRCTREE)/lib/%.c
 $(obj)%.o: $(SRCTREE)/lib/libfdt/%.c
 	$(HOSTCC) -g $(HOSTCFLAGS_NOPED) -c -o $@ $<
 
+$(obj)%.o: $(SRCTREE)/lib/rsa/%.c
+	$(HOSTCC) -g $(HOSTCFLAGS_NOPED) -c -o $@ $<
+
 subdirs:
 ifeq ($(TOOLSUBDIRS),)
 	@:
-- 
1.8.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [U-Boot] [PATCH v3 04/12] mkimage: Add -k option to specify key directory
  2013-06-13 22:09 ` [U-Boot] " Simon Glass
                   ` (3 preceding siblings ...)
  (?)
@ 2013-06-13 22:10 ` Simon Glass
  -1 siblings, 0 replies; 27+ messages in thread
From: Simon Glass @ 2013-06-13 22:10 UTC (permalink / raw)
  To: u-boot

Keys required for signing images will be in a specific directory. Add a
-k option to specify that directory.

Also update the mkimage man page with this information and a clearer list
of available commands.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Marek Vasut <marex@denx.de> (v1)
---
Changes in v3: None
Changes in v2:
- Adjust mkimage help to separate out signing options
- Fix checkpatch warnings about split strings

 doc/mkimage.1     | 25 ++++++++++++++++++++++---
 tools/fit_image.c |  2 +-
 tools/mkimage.c   | 15 ++++++++++++++-
 tools/mkimage.h   |  1 +
 4 files changed, 38 insertions(+), 5 deletions(-)

diff --git a/doc/mkimage.1 b/doc/mkimage.1
index 39652c8..6740fb1 100644
--- a/doc/mkimage.1
+++ b/doc/mkimage.1
@@ -4,7 +4,14 @@
 mkimage \- Generate image for U-Boot
 .SH SYNOPSIS
 .B mkimage
-.RB [\fIoptions\fP]
+.RB "\-l [" "uimage file name" "]"
+
+.B mkimage
+.RB [\fIoptions\fP] " \-f [" "image tree source file" "]" " [" "uimage file name" "]"
+
+.B mkimage
+.RB [\fIoptions\fP] " (legacy mode)"
+
 .SH "DESCRIPTION"
 The
 .B mkimage
@@ -26,7 +33,8 @@ etc.
 The new
 .I FIT (Flattened Image Tree) format
 allows for more flexibility in handling images of various types and also
-enhances integrity protection of images with stronger checksums.
+enhances integrity protection of images with stronger checksums. It also
+supports verified boot.
 
 .SH "OPTIONS"
 
@@ -67,6 +75,10 @@ Set load address with a hex number.
 Set entry point with a hex number.
 
 .TP
+.BI "\-l"
+List the contents of an image.
+
+.TP
 .BI "\-n [" "image name" "]"
 Set image name to 'image name'.
 
@@ -91,6 +103,12 @@ create the image.
 Image tree source file that describes the structure and contents of the
 FIT image.
 
+.TP
+.BI "\-k [" "key_directory" "]"
+Specifies the directory containing keys to use for signing. This directory
+should contain a private key file <name>.key for use with signing and a
+certificate <name>.crt (containing the public key) for use with verification.
+
 .SH EXAMPLES
 
 List image information:
@@ -115,4 +133,5 @@ http://www.denx.de/wiki/U-Boot/WebHome
 .PP
 .SH AUTHOR
 This manual page was written by Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
-and Wolfgang Denk <wd@denx.de>
+and Wolfgang Denk <wd@denx.de>. It was updated for image signing by
+Simon Glass <sjg@chromium.org>.
diff --git a/tools/fit_image.c b/tools/fit_image.c
index ef6ef44..339e0f8 100644
--- a/tools/fit_image.c
+++ b/tools/fit_image.c
@@ -137,7 +137,7 @@ static int fit_handle_file (struct mkimage_params *params)
 		goto err_mmap;
 
 	/* set hashes for images in the blob */
-	if (fit_add_verification_data(NULL, NULL, ptr, NULL, 0)) {
+	if (fit_add_verification_data(params->keydir, NULL, ptr, NULL, 0)) {
 		fprintf (stderr, "%s Can't add hashes to FIT blob",
 				params->cmdname);
 		goto err_add_hashes;
diff --git a/tools/mkimage.c b/tools/mkimage.c
index e43b09f..def7df2 100644
--- a/tools/mkimage.c
+++ b/tools/mkimage.c
@@ -248,6 +248,11 @@ main (int argc, char **argv)
 				params.datafile = *++argv;
 				params.fflag = 1;
 				goto NXTARG;
+			case 'k':
+				if (--argc <= 0)
+					usage();
+				params.keydir = *++argv;
+				goto NXTARG;
 			case 'n':
 				if (--argc <= 0)
 					usage ();
@@ -623,8 +628,16 @@ usage ()
 			 "          -d ==> use image data from 'datafile'\n"
 			 "          -x ==> set XIP (execute in place)\n",
 		params.cmdname);
-	fprintf (stderr, "       %s [-D dtc_options] -f fit-image.its fit-image\n",
+	fprintf(stderr, "       %s [-D dtc_options] -f fit-image.its fit-image\n",
 		params.cmdname);
+	fprintf(stderr, "          -D => set options for device tree compiler\n"
+			"          -f => input filename for FIT source\n");
+#ifdef CONFIG_FIT_SIGNATURE
+	fprintf(stderr, "Signing / verified boot options: [-k keydir]\n"
+			"          -k => set directory containing private keys\n");
+#else
+	fprintf(stderr, "Signing / verified boot not supported (CONFIG_FIT_SIGNATURE undefined)\n");
+#endif
 	fprintf (stderr, "       %s -V ==> print version information and exit\n",
 		params.cmdname);
 
diff --git a/tools/mkimage.h b/tools/mkimage.h
index 03c6c8f..059e124 100644
--- a/tools/mkimage.h
+++ b/tools/mkimage.h
@@ -87,6 +87,7 @@ struct mkimage_params {
 	char *datafile;
 	char *imagefile;
 	char *cmdname;
+	const char *keydir;	/* Directory holding private keys */
 };
 
 /*
-- 
1.8.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [U-Boot] [PATCH v3 05/12] mkimage: Add -K to write public keys to an FDT blob
  2013-06-13 22:09 ` [U-Boot] " Simon Glass
                   ` (4 preceding siblings ...)
  (?)
@ 2013-06-13 22:10 ` Simon Glass
  -1 siblings, 0 replies; 27+ messages in thread
From: Simon Glass @ 2013-06-13 22:10 UTC (permalink / raw)
  To: u-boot

FIT image verification requires public keys. Add a convenient option to
mkimage to write the public keys to an FDT blob when it uses then for
signing an image. This allows us to use:

   mkimage -f test.its -K dest.dtb -k keys test.fit

and have the signatures written to test.fit and the corresponding public
keys written to dest.dtb. Then dest.dtb can be used as the control FDT
for U-Boot (CONFIG_OF_CONTROL), thus providing U-Boot with access to the
public keys it needs.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Marek Vasut <marex@denx.de>
---
Changes in v3: None
Changes in v2:
- Adjust mkimage help to separate out signing options
- Rebase on previous patches

 doc/mkimage.1     | 16 ++++++++++++++++
 tools/fit_image.c | 21 +++++++++++++++++++--
 tools/mkimage.c   | 10 ++++++++--
 tools/mkimage.h   |  1 +
 4 files changed, 44 insertions(+), 4 deletions(-)

diff --git a/doc/mkimage.1 b/doc/mkimage.1
index 6740fb1..8185ff5 100644
--- a/doc/mkimage.1
+++ b/doc/mkimage.1
@@ -109,6 +109,14 @@ Specifies the directory containing keys to use for signing. This directory
 should contain a private key file <name>.key for use with signing and a
 certificate <name>.crt (containing the public key) for use with verification.
 
+.TP
+.BI "\-K [" "key_destination" "]"
+Specifies a compiled device tree binary file (typically .dtb) to write
+public key information into. When a private key is used to sign an image,
+the corresponding public key is written into this file for for run-time
+verification. Typically the file here is the device tree binary used by
+CONFIG_OF_CONTROL in U-Boot.
+
 .SH EXAMPLES
 
 List image information:
@@ -127,6 +135,14 @@ Create FIT image with compressed PowerPC Linux kernel:
 .nf
 .B mkimage -f kernel.its kernel.itb
 .fi
+.P
+Create FIT image with compressed kernel and sign it with keys in the
+/public/signing-keys directory. Add corresponding public keys into u-boot.dtb,
+skipping those for which keys cannot be found. Also add a comment.
+.nf
+.B mkimage -f kernel.its -k /public/signing-keys -K u-boot.dtb \\\\
+-c "Kernel 3.8 image for production devices" kernel.itb
+.fi
 
 .SH HOMEPAGE
 http://www.denx.de/wiki/U-Boot/WebHome
diff --git a/tools/fit_image.c b/tools/fit_image.c
index 339e0f8..b17fa2d 100644
--- a/tools/fit_image.c
+++ b/tools/fit_image.c
@@ -105,9 +105,11 @@ static int fit_handle_file (struct mkimage_params *params)
 {
 	char tmpfile[MKIMAGE_MAX_TMPFILE_LEN];
 	char cmd[MKIMAGE_MAX_DTC_CMDLINE_LEN];
-	int tfd;
+	int tfd, destfd = 0;
+	void *dest_blob = NULL;
 	struct stat sbuf;
 	void *ptr;
+	off_t destfd_size = 0;
 
 	/* Flattened Image Tree (FIT) format  handling */
 	debug ("FIT format handling\n");
@@ -132,12 +134,20 @@ static int fit_handle_file (struct mkimage_params *params)
 		goto err_system;
 	}
 
+	if (params->keydest) {
+		destfd = mmap_fdt(params, params->keydest, &dest_blob, &sbuf);
+		if (destfd < 0)
+			goto err_keydest;
+		destfd_size = sbuf.st_size;
+	}
+
 	tfd = mmap_fdt(params, tmpfile, &ptr, &sbuf);
 	if (tfd < 0)
 		goto err_mmap;
 
 	/* set hashes for images in the blob */
-	if (fit_add_verification_data(params->keydir, NULL, ptr, NULL, 0)) {
+	if (fit_add_verification_data(params->keydir, dest_blob, ptr,
+				      NULL, 0)) {
 		fprintf (stderr, "%s Can't add hashes to FIT blob",
 				params->cmdname);
 		goto err_add_hashes;
@@ -153,6 +163,10 @@ static int fit_handle_file (struct mkimage_params *params)
 
 	munmap ((void *)ptr, sbuf.st_size);
 	close (tfd);
+	if (dest_blob) {
+		munmap(dest_blob, destfd_size);
+		close(destfd);
+	}
 
 	if (rename (tmpfile, params->imagefile) == -1) {
 		fprintf (stderr, "%s: Can't rename %s to %s: %s\n",
@@ -168,6 +182,9 @@ err_add_timestamp:
 err_add_hashes:
 	munmap(ptr, sbuf.st_size);
 err_mmap:
+	if (dest_blob)
+		munmap(dest_blob, destfd_size);
+err_keydest:
 err_system:
 	unlink(tmpfile);
 	return -1;
diff --git a/tools/mkimage.c b/tools/mkimage.c
index def7df2..3760392 100644
--- a/tools/mkimage.c
+++ b/tools/mkimage.c
@@ -253,6 +253,11 @@ main (int argc, char **argv)
 					usage();
 				params.keydir = *++argv;
 				goto NXTARG;
+			case 'K':
+				if (--argc <= 0)
+					usage();
+				params.keydest = *++argv;
+				goto NXTARG;
 			case 'n':
 				if (--argc <= 0)
 					usage ();
@@ -633,8 +638,9 @@ usage ()
 	fprintf(stderr, "          -D => set options for device tree compiler\n"
 			"          -f => input filename for FIT source\n");
 #ifdef CONFIG_FIT_SIGNATURE
-	fprintf(stderr, "Signing / verified boot options: [-k keydir]\n"
-			"          -k => set directory containing private keys\n");
+	fprintf(stderr, "Signing / verified boot options: [-k keydir] [-K dtb]\n"
+			"          -k => set directory containing private keys\n"
+			"          -K => write public keys to this .dtb file\n");
 #else
 	fprintf(stderr, "Signing / verified boot not supported (CONFIG_FIT_SIGNATURE undefined)\n");
 #endif
diff --git a/tools/mkimage.h b/tools/mkimage.h
index 059e124..63b9b4f 100644
--- a/tools/mkimage.h
+++ b/tools/mkimage.h
@@ -88,6 +88,7 @@ struct mkimage_params {
 	char *imagefile;
 	char *cmdname;
 	const char *keydir;	/* Directory holding private keys */
+	const char *keydest;	/* Destination .dtb for public key */
 };
 
 /*
-- 
1.8.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [U-Boot] [PATCH v3 06/12] mkimage: Add -F option to modify an existing .fit file
  2013-06-13 22:09 ` [U-Boot] " Simon Glass
                   ` (5 preceding siblings ...)
  (?)
@ 2013-06-13 22:10 ` Simon Glass
  -1 siblings, 0 replies; 27+ messages in thread
From: Simon Glass @ 2013-06-13 22:10 UTC (permalink / raw)
  To: u-boot

When signing images it is sometimes necessary to sign with different keys
at different times, or make the signer entirely separate from the FIT
creation to avoid needing the private keys to be publicly available in
the system.

Add a -F option so that key signing can be a separate step, and possibly
done multiple times as different keys are avaiable.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Marek Vasut <marex@denx.de>
---
Changes in v3: None
Changes in v2:
- Adjust mkimage help to separate out signing options
- Fix checkpatch checks about parenthesis alignment
- Rebase on previous patches

 doc/mkimage.1     | 20 ++++++++++++++++++++
 tools/fit_image.c | 18 ++++++++++++------
 tools/mkimage.c   |  9 ++++++---
 3 files changed, 38 insertions(+), 9 deletions(-)

diff --git a/doc/mkimage.1 b/doc/mkimage.1
index 8185ff5..f9c733a 100644
--- a/doc/mkimage.1
+++ b/doc/mkimage.1
@@ -10,6 +10,9 @@ mkimage \- Generate image for U-Boot
 .RB [\fIoptions\fP] " \-f [" "image tree source file" "]" " [" "uimage file name" "]"
 
 .B mkimage
+.RB [\fIoptions\fP] " \-F [" "uimage file name" "]"
+
+.B mkimage
 .RB [\fIoptions\fP] " (legacy mode)"
 
 .SH "DESCRIPTION"
@@ -104,6 +107,13 @@ Image tree source file that describes the structure and contents of the
 FIT image.
 
 .TP
+.BI "\-F"
+Indicates that an existing FIT image should be modified. No dtc
+compilation is performed and the -f flag should not be given.
+This can be used to sign images with additional keys after initial image
+creation.
+
+.TP
 .BI "\-k [" "key_directory" "]"
 Specifies the directory containing keys to use for signing. This directory
 should contain a private key file <name>.key for use with signing and a
@@ -144,6 +154,16 @@ skipping those for which keys cannot be found. Also add a comment.
 -c "Kernel 3.8 image for production devices" kernel.itb
 .fi
 
+.P
+Update an existing FIT image, signing it with additional keys.
+Add corresponding public keys into u-boot.dtb. This will resign all images
+with keys that are available in the new directory. Images that request signing
+with unavailable keys are skipped.
+.nf
+.B mkimage -F -k /secret/signing-keys -K u-boot.dtb \\\\
+-c "Kernel 3.8 image for production devices" kernel.itb
+.fi
+
 .SH HOMEPAGE
 http://www.denx.de/wiki/U-Boot/WebHome
 .PP
diff --git a/tools/fit_image.c b/tools/fit_image.c
index b17fa2d..645e93c 100644
--- a/tools/fit_image.c
+++ b/tools/fit_image.c
@@ -124,10 +124,16 @@ static int fit_handle_file (struct mkimage_params *params)
 	}
 	sprintf (tmpfile, "%s%s", params->imagefile, MKIMAGE_TMPFILE_SUFFIX);
 
-	/* dtc -I dts -O dtb -p 500 datafile > tmpfile */
-	sprintf (cmd, "%s %s %s > %s",
-		MKIMAGE_DTC, params->dtc, params->datafile, tmpfile);
-	debug ("Trying to execute \"%s\"\n", cmd);
+	/* We either compile the source file, or use the existing FIT image */
+	if (params->datafile) {
+		/* dtc -I dts -O dtb -p 500 datafile > tmpfile */
+		snprintf(cmd, sizeof(cmd), "%s %s %s > %s",
+			 MKIMAGE_DTC, params->dtc, params->datafile, tmpfile);
+		debug("Trying to execute \"%s\"\n", cmd);
+	} else {
+		snprintf(cmd, sizeof(cmd), "cp %s %s",
+			 params->imagefile, tmpfile);
+	}
 	if (system (cmd) == -1) {
 		fprintf (stderr, "%s: system(%s) failed: %s\n",
 				params->cmdname, cmd, strerror(errno));
@@ -153,8 +159,8 @@ static int fit_handle_file (struct mkimage_params *params)
 		goto err_add_hashes;
 	}
 
-	/* add a timestamp at offset 0 i.e., root  */
-	if (fit_set_timestamp (ptr, 0, sbuf.st_mtime)) {
+	/* for first image creation, add a timestamp at offset 0 i.e., root  */
+	if (params->datafile && fit_set_timestamp(ptr, 0, sbuf.st_mtime)) {
 		fprintf (stderr, "%s: Can't add image timestamp\n",
 				params->cmdname);
 		goto err_add_timestamp;
diff --git a/tools/mkimage.c b/tools/mkimage.c
index 3760392..e2b82d0 100644
--- a/tools/mkimage.c
+++ b/tools/mkimage.c
@@ -240,12 +240,14 @@ main (int argc, char **argv)
 			case 'f':
 				if (--argc <= 0)
 					usage ();
+				params.datafile = *++argv;
+				/* no break */
+			case 'F':
 				/*
 				 * The flattened image tree (FIT) format
 				 * requires a flattened device tree image type
 				 */
 				params.type = IH_TYPE_FLATDT;
-				params.datafile = *++argv;
 				params.fflag = 1;
 				goto NXTARG;
 			case 'k':
@@ -633,14 +635,15 @@ usage ()
 			 "          -d ==> use image data from 'datafile'\n"
 			 "          -x ==> set XIP (execute in place)\n",
 		params.cmdname);
-	fprintf(stderr, "       %s [-D dtc_options] -f fit-image.its fit-image\n",
+	fprintf(stderr, "       %s [-D dtc_options] [-f fit-image.its|-F] fit-image\n",
 		params.cmdname);
 	fprintf(stderr, "          -D => set options for device tree compiler\n"
 			"          -f => input filename for FIT source\n");
 #ifdef CONFIG_FIT_SIGNATURE
 	fprintf(stderr, "Signing / verified boot options: [-k keydir] [-K dtb]\n"
 			"          -k => set directory containing private keys\n"
-			"          -K => write public keys to this .dtb file\n");
+			"          -K => write public keys to this .dtb file\n"
+			"          -F => re-sign existing FIT image\n");
 #else
 	fprintf(stderr, "Signing / verified boot not supported (CONFIG_FIT_SIGNATURE undefined)\n");
 #endif
-- 
1.8.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [U-Boot] [PATCH v3 07/12] mkimage: Add -c option to specify a comment for key signing
  2013-06-13 22:09 ` [U-Boot] " Simon Glass
                   ` (6 preceding siblings ...)
  (?)
@ 2013-06-13 22:10 ` Simon Glass
  -1 siblings, 0 replies; 27+ messages in thread
From: Simon Glass @ 2013-06-13 22:10 UTC (permalink / raw)
  To: u-boot

When signing an image, it is useful to add some details about which tool
or person is authorising the signing. Add a comment field which can take
care of miscellaneous requirements.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Marek Vasut <marex@denx.de>
---
Changes in v3: None
Changes in v2:
- Adjust mkimage help to separate out signing options
- Rebase on previous patches

 doc/mkimage.1     | 6 ++++++
 tools/fit_image.c | 4 ++--
 tools/mkimage.c   | 8 +++++++-
 tools/mkimage.h   | 1 +
 4 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/doc/mkimage.1 b/doc/mkimage.1
index f9c733a..b67a351 100644
--- a/doc/mkimage.1
+++ b/doc/mkimage.1
@@ -97,6 +97,12 @@ Set XIP (execute in place) flag.
 .B Create FIT image:
 
 .TP
+.BI "\-c [" "comment" "]"
+Specifies a comment to be added when signing. This is typically a useful
+message which describes how the image was signed or some other useful
+information.
+
+.TP
 .BI "\-D [" "dtc options" "]"
 Provide special options to the device tree compiler that is used to
 create the image.
diff --git a/tools/fit_image.c b/tools/fit_image.c
index 645e93c..d48f571 100644
--- a/tools/fit_image.c
+++ b/tools/fit_image.c
@@ -153,9 +153,9 @@ static int fit_handle_file (struct mkimage_params *params)
 
 	/* set hashes for images in the blob */
 	if (fit_add_verification_data(params->keydir, dest_blob, ptr,
-				      NULL, 0)) {
+				      params->comment, 0)) {
 		fprintf (stderr, "%s Can't add hashes to FIT blob",
-				params->cmdname);
+			 params->cmdname);
 		goto err_add_hashes;
 	}
 
diff --git a/tools/mkimage.c b/tools/mkimage.c
index e2b82d0..b3b45a4 100644
--- a/tools/mkimage.c
+++ b/tools/mkimage.c
@@ -183,6 +183,11 @@ main (int argc, char **argv)
 					genimg_get_arch_id (*++argv)) < 0)
 					usage ();
 				goto NXTARG;
+			case 'c':
+				if (--argc <= 0)
+					usage();
+				params.comment = *++argv;
+				goto NXTARG;
 			case 'C':
 				if ((--argc <= 0) ||
 					(params.comp =
@@ -640,9 +645,10 @@ usage ()
 	fprintf(stderr, "          -D => set options for device tree compiler\n"
 			"          -f => input filename for FIT source\n");
 #ifdef CONFIG_FIT_SIGNATURE
-	fprintf(stderr, "Signing / verified boot options: [-k keydir] [-K dtb]\n"
+	fprintf(stderr, "Signing / verified boot options: [-k keydir] [-K dtb] [ -c <comment>]\n"
 			"          -k => set directory containing private keys\n"
 			"          -K => write public keys to this .dtb file\n"
+			"          -c => add comment in signature node\n"
 			"          -F => re-sign existing FIT image\n");
 #else
 	fprintf(stderr, "Signing / verified boot not supported (CONFIG_FIT_SIGNATURE undefined)\n");
diff --git a/tools/mkimage.h b/tools/mkimage.h
index 63b9b4f..ab8baf8 100644
--- a/tools/mkimage.h
+++ b/tools/mkimage.h
@@ -89,6 +89,7 @@ struct mkimage_params {
 	char *cmdname;
 	const char *keydir;	/* Directory holding private keys */
 	const char *keydest;	/* Destination .dtb for public key */
+	const char *comment;	/* Comment to add to signature node */
 };
 
 /*
-- 
1.8.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [U-Boot] [PATCH v3 08/12] mkimage: Add -r option to specify keys that must be verified
  2013-06-13 22:09 ` [U-Boot] " Simon Glass
                   ` (7 preceding siblings ...)
  (?)
@ 2013-06-13 22:10 ` Simon Glass
  -1 siblings, 0 replies; 27+ messages in thread
From: Simon Glass @ 2013-06-13 22:10 UTC (permalink / raw)
  To: u-boot

Normally, multiple public keys can be provided and U-Boot is not
required to use all of them for verification. This is because some
images may not be signed, or may be optionally signed.

But we still need a mechanism to determine when a key must be used.
This feature cannot be implemented in the FIT itself, since anyone
could change it to mark a key as optional. The requirement for
key verification must go in with the public keys, in a place that
is protected from modification.

Add a -r option which tells mkimage to mark all keys that it uses
for signing as 'required'.

If some keys are optional and some are required, run mkimage several
times (perhaps with different key directories if some keys are very
secret) using the -F flag to update an existing FIT.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Marek Vasut <marex@denx.de>
---
Changes in v3: None
Changes in v2:
- Adjust mkimage help to separate out signing options
- Rebase on previous patches

 doc/mkimage.1     | 6 ++++++
 tools/fit_image.c | 9 +++++----
 tools/mkimage.c   | 8 ++++++--
 tools/mkimage.h   | 1 +
 4 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/doc/mkimage.1 b/doc/mkimage.1
index b67a351..14374da 100644
--- a/doc/mkimage.1
+++ b/doc/mkimage.1
@@ -133,6 +133,12 @@ the corresponding public key is written into this file for for run-time
 verification. Typically the file here is the device tree binary used by
 CONFIG_OF_CONTROL in U-Boot.
 
+.TP
+.BI "\-r
+Specifies that keys used to sign the FIT are required. This means that they
+must be verified for the image to boot. Without this option, the verification
+will be optional (useful for testing but not for release).
+
 .SH EXAMPLES
 
 List image information:
diff --git a/tools/fit_image.c b/tools/fit_image.c
index d48f571..281c2bd 100644
--- a/tools/fit_image.c
+++ b/tools/fit_image.c
@@ -152,10 +152,11 @@ static int fit_handle_file (struct mkimage_params *params)
 		goto err_mmap;
 
 	/* set hashes for images in the blob */
-	if (fit_add_verification_data(params->keydir, dest_blob, ptr,
-				      params->comment, 0)) {
-		fprintf (stderr, "%s Can't add hashes to FIT blob",
-			 params->cmdname);
+	if (fit_add_verification_data(params->keydir,
+				      dest_blob, ptr, params->comment,
+				      params->require_keys)) {
+		fprintf(stderr, "%s Can't add hashes to FIT blob\n",
+			params->cmdname);
 		goto err_add_hashes;
 	}
 
diff --git a/tools/mkimage.c b/tools/mkimage.c
index b3b45a4..d312844 100644
--- a/tools/mkimage.c
+++ b/tools/mkimage.c
@@ -270,6 +270,9 @@ main (int argc, char **argv)
 					usage ();
 				params.imagename = *++argv;
 				goto NXTARG;
+			case 'r':
+				params.require_keys = 1;
+				break;
 			case 'R':
 				if (--argc <= 0)
 					usage();
@@ -645,11 +648,12 @@ usage ()
 	fprintf(stderr, "          -D => set options for device tree compiler\n"
 			"          -f => input filename for FIT source\n");
 #ifdef CONFIG_FIT_SIGNATURE
-	fprintf(stderr, "Signing / verified boot options: [-k keydir] [-K dtb] [ -c <comment>]\n"
+	fprintf(stderr, "Signing / verified boot options: [-k keydir] [-K dtb] [ -c <comment>] [-r]\n"
 			"          -k => set directory containing private keys\n"
 			"          -K => write public keys to this .dtb file\n"
 			"          -c => add comment in signature node\n"
-			"          -F => re-sign existing FIT image\n");
+			"          -F => re-sign existing FIT image\n"
+			"          -r => mark keys used as 'required' in dtb\n");
 #else
 	fprintf(stderr, "Signing / verified boot not supported (CONFIG_FIT_SIGNATURE undefined)\n");
 #endif
diff --git a/tools/mkimage.h b/tools/mkimage.h
index ab8baf8..1d9984e 100644
--- a/tools/mkimage.h
+++ b/tools/mkimage.h
@@ -90,6 +90,7 @@ struct mkimage_params {
 	const char *keydir;	/* Directory holding private keys */
 	const char *keydest;	/* Destination .dtb for public key */
 	const char *comment;	/* Comment to add to signature node */
+	int require_keys;	/* 1 to mark signing keys as 'required' */
 };
 
 /*
-- 
1.8.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v3 09/12] libfdt: Add fdt_find_regions()
  2013-06-13 22:09 ` [U-Boot] " Simon Glass
@ 2013-06-13 22:10     ` Simon Glass
  -1 siblings, 0 replies; 27+ messages in thread
From: Simon Glass @ 2013-06-13 22:10 UTC (permalink / raw)
  To: U-Boot Mailing List
  Cc: Joel A Fernandes, Will Drewry, Wolfgang Denk, Devicetree Discuss,
	u-boot-review-hpIqsD4AKlfQT0dZR+AlfA, Bill Richardson,
	Randall Spangler, Tom Rini, Vadim Bendebury, Andreas Bäck,
	Kees Cook

Add a function to find regions in device tree given a list of nodes to
include and properties to exclude.

See the header file for full documentation.

Signed-off-by: Simon Glass <sjg-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
---
Changes in v3: None
Changes in v2:
- Fix checkpatch checks about parenthesis alignment

 include/libfdt.h     |  64 +++++++++++++++++++++++++
 lib/libfdt/fdt_wip.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 193 insertions(+)

diff --git a/include/libfdt.h b/include/libfdt.h
index c5ec2ac..765d84f 100644
--- a/include/libfdt.h
+++ b/include/libfdt.h
@@ -1511,4 +1511,68 @@ int fdt_del_node(void *fdt, int nodeoffset);
 
 const char *fdt_strerror(int errval);
 
+struct fdt_region {
+	int offset;
+	int size;
+};
+
+/**
+ * fdt_find_regions() - find regions in device tree
+ *
+ * Given a list of nodes to include and properties to exclude, find
+ * the regions of the device tree which describe those included parts.
+ *
+ * The intent is to get a list of regions which will be invariant provided
+ * those parts are invariant. For example, if you request a list of regions
+ * for all nodes but exclude the property "data", then you will get the
+ * same region contents regardless of any change to "data" properties.
+ *
+ * This function can be used to produce a byte-stream to send to a hashing
+ * function to verify that critical parts of the FDT have not changed.
+ *
+ * Nodes which are given in 'inc' are included in the region list, as
+ * are the names of the immediate subnodes nodes (but not the properties
+ * or subnodes of those subnodes).
+ *
+ * For eaxample "/" means to include the root node, all root properties
+ * and the FDT_BEGIN_NODE and FDT_END_NODE of all subnodes of /. The latter
+ * ensures that we capture the names of the subnodes. In a hashing situation
+ * it prevents the root node from changing at all Any change to non-excluded
+ * properties, names of subnodes or number of subnodes would be detected.
+ *
+ * When used with FITs this provides the ability to hash and sign parts of
+ * the FIT based on different configurations in the FIT. Then it is
+ * impossible to change anything about that configuration (include images
+ * attached to the configuration), but it may be possible to add new
+ * configurations, new images or new signatures within the existing
+ * framework.
+ *
+ * Adding new properties to a device tree may result in the string table
+ * being extended (if the new property names are different from those
+ * already added). This function can optionally include a region for
+ * the string table so that this can be part of the hash too.
+ *
+ * The device tree header is not included in the list.
+ *
+ * @fdt:	Device tree to check
+ * @inc:	List of node paths to included
+ * @inc_count:	Number of node paths in list
+ * @exc_prop:	List of properties names to exclude
+ * @exc_prop_count:	Number of properties in exclude list
+ * @region:	Returns list of regions
+ * @max_region:	Maximum length of region list
+ * @path:	Pointer to a temporary string for the function to use for
+ *		building path names
+ * @path_len:	Length of path, must be large enough to hold the longest
+ *		path in the tree
+ * @add_string_tab:	1 to add a region for the string table
+ * @return number of regions in list. If this is >max_regions then the
+ * region array was exhausted. You should increase max_regions and try
+ * the call again.
+ */
+int fdt_find_regions(const void *fdt, char * const inc[], int inc_count,
+		     char * const exc_prop[], int exc_prop_count,
+		     struct fdt_region region[], int max_regions,
+		     char *path, int path_len, int add_string_tab);
+
 #endif /* _LIBFDT_H */
diff --git a/lib/libfdt/fdt_wip.c b/lib/libfdt/fdt_wip.c
index 63e67b7..b9e3c4a 100644
--- a/lib/libfdt/fdt_wip.c
+++ b/lib/libfdt/fdt_wip.c
@@ -120,3 +120,132 @@ int fdt_nop_node(void *fdt, int nodeoffset)
 			endoffset - nodeoffset);
 	return 0;
 }
+
+#define FDT_MAX_DEPTH	32
+
+static int str_in_list(const char *str, char * const list[], int count)
+{
+	int i;
+
+	for (i = 0; i < count; i++)
+		if (!strcmp(list[i], str))
+			return 1;
+
+	return 0;
+}
+
+int fdt_find_regions(const void *fdt, char * const inc[], int inc_count,
+		     char * const exc_prop[], int exc_prop_count,
+		     struct fdt_region region[], int max_regions,
+		     char *path, int path_len, int add_string_tab)
+{
+	int stack[FDT_MAX_DEPTH];
+	char *end;
+	int nextoffset = 0;
+	uint32_t tag;
+	int count = 0;
+	int start = -1;
+	int depth = -1;
+	int want = 0;
+	int base = fdt_off_dt_struct(fdt);
+
+	end = path;
+	*end = '\0';
+	do {
+		const struct fdt_property *prop;
+		const char *name;
+		const char *str;
+		int include = 0;
+		int stop_at = 0;
+		int offset;
+		int len;
+
+		offset = nextoffset;
+		tag = fdt_next_tag(fdt, offset, &nextoffset);
+		stop_at = nextoffset;
+
+		switch (tag) {
+		case FDT_PROP:
+			include = want >= 2;
+			stop_at = offset;
+			prop = fdt_get_property_by_offset(fdt, offset, NULL);
+			str = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
+			if (str_in_list(str, exc_prop, exc_prop_count))
+				include = 0;
+			break;
+
+		case FDT_NOP:
+			include = want >= 2;
+			stop_at = offset;
+			break;
+
+		case FDT_BEGIN_NODE:
+			depth++;
+			if (depth == FDT_MAX_DEPTH)
+				return -FDT_ERR_BADSTRUCTURE;
+			name = fdt_get_name(fdt, offset, &len);
+			if (end - path + 2 + len >= path_len)
+				return -FDT_ERR_NOSPACE;
+			if (end != path + 1)
+				*end++ = '/';
+			strcpy(end, name);
+			end += len;
+			stack[depth] = want;
+			if (want == 1)
+				stop_at = offset;
+			if (str_in_list(path, inc, inc_count))
+				want = 2;
+			else if (want)
+				want--;
+			else
+				stop_at = offset;
+			include = want;
+			break;
+
+		case FDT_END_NODE:
+			include = want;
+			want = stack[depth--];
+			while (end > path && *--end != '/')
+				;
+			*end = '\0';
+			break;
+
+		case FDT_END:
+			include = 1;
+			break;
+		}
+
+		if (include && start == -1) {
+			/* Should we merge with previous? */
+			if (count && count <= max_regions &&
+			    offset == region[count - 1].offset +
+					region[count - 1].size - base)
+				start = region[--count].offset - base;
+			else
+				start = offset;
+		}
+
+		if (!include && start != -1) {
+			if (count < max_regions) {
+				region[count].offset = base + start;
+				region[count].size = stop_at - start;
+			}
+			count++;
+			start = -1;
+		}
+	} while (tag != FDT_END);
+
+	if (nextoffset != fdt_size_dt_struct(fdt))
+		return -FDT_ERR_BADLAYOUT;
+
+	/* Add a region for the END tag and the string table */
+	if (count < max_regions) {
+		region[count].offset = base + start;
+		region[count].size = nextoffset - start;
+		if (add_string_tab)
+			region[count].size += fdt_size_dt_strings(fdt);
+	}
+	count++;
+
+	return count;
+}
-- 
1.8.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [U-Boot] [PATCH v3 09/12] libfdt: Add fdt_find_regions()
@ 2013-06-13 22:10     ` Simon Glass
  0 siblings, 0 replies; 27+ messages in thread
From: Simon Glass @ 2013-06-13 22:10 UTC (permalink / raw)
  To: u-boot

Add a function to find regions in device tree given a list of nodes to
include and properties to exclude.

See the header file for full documentation.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
Changes in v3: None
Changes in v2:
- Fix checkpatch checks about parenthesis alignment

 include/libfdt.h     |  64 +++++++++++++++++++++++++
 lib/libfdt/fdt_wip.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 193 insertions(+)

diff --git a/include/libfdt.h b/include/libfdt.h
index c5ec2ac..765d84f 100644
--- a/include/libfdt.h
+++ b/include/libfdt.h
@@ -1511,4 +1511,68 @@ int fdt_del_node(void *fdt, int nodeoffset);
 
 const char *fdt_strerror(int errval);
 
+struct fdt_region {
+	int offset;
+	int size;
+};
+
+/**
+ * fdt_find_regions() - find regions in device tree
+ *
+ * Given a list of nodes to include and properties to exclude, find
+ * the regions of the device tree which describe those included parts.
+ *
+ * The intent is to get a list of regions which will be invariant provided
+ * those parts are invariant. For example, if you request a list of regions
+ * for all nodes but exclude the property "data", then you will get the
+ * same region contents regardless of any change to "data" properties.
+ *
+ * This function can be used to produce a byte-stream to send to a hashing
+ * function to verify that critical parts of the FDT have not changed.
+ *
+ * Nodes which are given in 'inc' are included in the region list, as
+ * are the names of the immediate subnodes nodes (but not the properties
+ * or subnodes of those subnodes).
+ *
+ * For eaxample "/" means to include the root node, all root properties
+ * and the FDT_BEGIN_NODE and FDT_END_NODE of all subnodes of /. The latter
+ * ensures that we capture the names of the subnodes. In a hashing situation
+ * it prevents the root node from changing at all Any change to non-excluded
+ * properties, names of subnodes or number of subnodes would be detected.
+ *
+ * When used with FITs this provides the ability to hash and sign parts of
+ * the FIT based on different configurations in the FIT. Then it is
+ * impossible to change anything about that configuration (include images
+ * attached to the configuration), but it may be possible to add new
+ * configurations, new images or new signatures within the existing
+ * framework.
+ *
+ * Adding new properties to a device tree may result in the string table
+ * being extended (if the new property names are different from those
+ * already added). This function can optionally include a region for
+ * the string table so that this can be part of the hash too.
+ *
+ * The device tree header is not included in the list.
+ *
+ * @fdt:	Device tree to check
+ * @inc:	List of node paths to included
+ * @inc_count:	Number of node paths in list
+ * @exc_prop:	List of properties names to exclude
+ * @exc_prop_count:	Number of properties in exclude list
+ * @region:	Returns list of regions
+ * @max_region:	Maximum length of region list
+ * @path:	Pointer to a temporary string for the function to use for
+ *		building path names
+ * @path_len:	Length of path, must be large enough to hold the longest
+ *		path in the tree
+ * @add_string_tab:	1 to add a region for the string table
+ * @return number of regions in list. If this is >max_regions then the
+ * region array was exhausted. You should increase max_regions and try
+ * the call again.
+ */
+int fdt_find_regions(const void *fdt, char * const inc[], int inc_count,
+		     char * const exc_prop[], int exc_prop_count,
+		     struct fdt_region region[], int max_regions,
+		     char *path, int path_len, int add_string_tab);
+
 #endif /* _LIBFDT_H */
diff --git a/lib/libfdt/fdt_wip.c b/lib/libfdt/fdt_wip.c
index 63e67b7..b9e3c4a 100644
--- a/lib/libfdt/fdt_wip.c
+++ b/lib/libfdt/fdt_wip.c
@@ -120,3 +120,132 @@ int fdt_nop_node(void *fdt, int nodeoffset)
 			endoffset - nodeoffset);
 	return 0;
 }
+
+#define FDT_MAX_DEPTH	32
+
+static int str_in_list(const char *str, char * const list[], int count)
+{
+	int i;
+
+	for (i = 0; i < count; i++)
+		if (!strcmp(list[i], str))
+			return 1;
+
+	return 0;
+}
+
+int fdt_find_regions(const void *fdt, char * const inc[], int inc_count,
+		     char * const exc_prop[], int exc_prop_count,
+		     struct fdt_region region[], int max_regions,
+		     char *path, int path_len, int add_string_tab)
+{
+	int stack[FDT_MAX_DEPTH];
+	char *end;
+	int nextoffset = 0;
+	uint32_t tag;
+	int count = 0;
+	int start = -1;
+	int depth = -1;
+	int want = 0;
+	int base = fdt_off_dt_struct(fdt);
+
+	end = path;
+	*end = '\0';
+	do {
+		const struct fdt_property *prop;
+		const char *name;
+		const char *str;
+		int include = 0;
+		int stop_at = 0;
+		int offset;
+		int len;
+
+		offset = nextoffset;
+		tag = fdt_next_tag(fdt, offset, &nextoffset);
+		stop_at = nextoffset;
+
+		switch (tag) {
+		case FDT_PROP:
+			include = want >= 2;
+			stop_at = offset;
+			prop = fdt_get_property_by_offset(fdt, offset, NULL);
+			str = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
+			if (str_in_list(str, exc_prop, exc_prop_count))
+				include = 0;
+			break;
+
+		case FDT_NOP:
+			include = want >= 2;
+			stop_at = offset;
+			break;
+
+		case FDT_BEGIN_NODE:
+			depth++;
+			if (depth == FDT_MAX_DEPTH)
+				return -FDT_ERR_BADSTRUCTURE;
+			name = fdt_get_name(fdt, offset, &len);
+			if (end - path + 2 + len >= path_len)
+				return -FDT_ERR_NOSPACE;
+			if (end != path + 1)
+				*end++ = '/';
+			strcpy(end, name);
+			end += len;
+			stack[depth] = want;
+			if (want == 1)
+				stop_at = offset;
+			if (str_in_list(path, inc, inc_count))
+				want = 2;
+			else if (want)
+				want--;
+			else
+				stop_at = offset;
+			include = want;
+			break;
+
+		case FDT_END_NODE:
+			include = want;
+			want = stack[depth--];
+			while (end > path && *--end != '/')
+				;
+			*end = '\0';
+			break;
+
+		case FDT_END:
+			include = 1;
+			break;
+		}
+
+		if (include && start == -1) {
+			/* Should we merge with previous? */
+			if (count && count <= max_regions &&
+			    offset == region[count - 1].offset +
+					region[count - 1].size - base)
+				start = region[--count].offset - base;
+			else
+				start = offset;
+		}
+
+		if (!include && start != -1) {
+			if (count < max_regions) {
+				region[count].offset = base + start;
+				region[count].size = stop_at - start;
+			}
+			count++;
+			start = -1;
+		}
+	} while (tag != FDT_END);
+
+	if (nextoffset != fdt_size_dt_struct(fdt))
+		return -FDT_ERR_BADLAYOUT;
+
+	/* Add a region for the END tag and the string table */
+	if (count < max_regions) {
+		region[count].offset = base + start;
+		region[count].size = nextoffset - start;
+		if (add_string_tab)
+			region[count].size += fdt_size_dt_strings(fdt);
+	}
+	count++;
+
+	return count;
+}
-- 
1.8.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [U-Boot] [PATCH v3 10/12] image: Add support for signing of FIT configurations
  2013-06-13 22:09 ` [U-Boot] " Simon Glass
                   ` (9 preceding siblings ...)
  (?)
@ 2013-06-13 22:10 ` Simon Glass
  -1 siblings, 0 replies; 27+ messages in thread
From: Simon Glass @ 2013-06-13 22:10 UTC (permalink / raw)
  To: u-boot

While signing images is useful, it does not provide complete protection
against several types of attack. For example, it it possible to create a
FIT with the same signed images, but with the configuration changed such
that a different one is selected (mix and match attack). It is also possible
to substitute a signed image from an older FIT version into a newer FIT
(roll-back attack).

Add support for signing of FIT configurations using the libfdt's region
support.

Please see doc/uImage.FIT/signature.txt for more information.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
Changes in v3:
- Use new fdt_first/next_subnode()

Changes in v2:
- Fix checkpatch checks about parenthesis alignment
- Fix checkpatch warnings about split strings
- Require CONFIG_FIT_SIGNATURE in image.h for mkimage to support signing
- Update README to fix typos and clarify some points
- Use stack instead of calloc() within U-Boot's signature verification code

 common/image-sig.c              | 231 ++++++++++++++++++++++++++-
 doc/uImage.FIT/sign-configs.its |  45 ++++++
 doc/uImage.FIT/signature.txt    | 168 +++++++++++++++++++-
 include/image.h                 |  16 ++
 tools/image-host.c              | 341 +++++++++++++++++++++++++++++++++++++++-
 5 files changed, 798 insertions(+), 3 deletions(-)
 create mode 100644 doc/uImage.FIT/sign-configs.its

diff --git a/common/image-sig.c b/common/image-sig.c
index 9928bfc..5d907cf 100644
--- a/common/image-sig.c
+++ b/common/image-sig.c
@@ -25,10 +25,11 @@
 #include <malloc.h>
 DECLARE_GLOBAL_DATA_PTR;
 #endif /* !USE_HOSTCC*/
-#include <errno.h>
 #include <image.h>
 #include <rsa.h>
 
+#define IMAGE_MAX_HASHED_NODES		100
+
 struct image_sig_algo image_sig_algos[] = {
 	{
 		"sha1,rsa2048",
@@ -50,6 +51,50 @@ struct image_sig_algo *image_get_sig_algo(const char *name)
 	return NULL;
 }
 
+/**
+ * fit_region_make_list() - Make a list of image regions
+ *
+ * Given a list of fdt_regions, create a list of image_regions. This is a
+ * simple conversion routine since the FDT and image code use different
+ * structures.
+ *
+ * @fit: FIT image
+ * @fdt_regions: Pointer to FDT regions
+ * @count: Number of FDT regions
+ * @region: Pointer to image regions, which must hold @count records. If
+ * region is NULL, then (except for an SPL build) the array will be
+ * allocated.
+ * @return: Pointer to image regions
+ */
+struct image_region *fit_region_make_list(const void *fit,
+		struct fdt_region *fdt_regions, int count,
+		struct image_region *region)
+{
+	int i;
+
+	debug("Hash regions:\n");
+	debug("%10s %10s\n", "Offset", "Size");
+
+	/*
+	 * Use malloc() except in SPL (to save code size). In SPL the caller
+	 * must allocate the array.
+	 */
+#ifndef CONFIG_SPL_BUILD
+	if (!region)
+		region = calloc(sizeof(*region), count);
+#endif
+	if (!region)
+		return NULL;
+	for (i = 0; i < count; i++) {
+		debug("%10x %10x\n", fdt_regions[i].offset,
+		      fdt_regions[i].size);
+		region[i].data = fit + fdt_regions[i].offset;
+		region[i].size = fdt_regions[i].size;
+	}
+
+	return region;
+}
+
 static int fit_image_setup_verify(struct image_sign_info *info,
 		const void *fit, int noffset, int required_keynode,
 		char **err_msgp)
@@ -191,3 +236,187 @@ int fit_image_verify_required_sigs(const void *fit, int image_noffset,
 
 	return 0;
 }
+
+int fit_config_check_sig(const void *fit, int noffset, int required_keynode,
+			 char **err_msgp)
+{
+	char * const exc_prop[] = {"data"};
+	const char *prop, *end, *name;
+	struct image_sign_info info;
+	const uint32_t *strings;
+	uint8_t *fit_value;
+	int fit_value_len;
+	int max_regions;
+	int i, prop_len;
+	char path[200];
+	int count;
+
+	debug("%s: fdt=%p, conf='%s', sig='%s'\n", __func__, gd_fdt_blob(),
+	      fit_get_name(fit, noffset, NULL),
+	      fit_get_name(gd_fdt_blob(), required_keynode, NULL));
+	*err_msgp = NULL;
+	if (fit_image_setup_verify(&info, fit, noffset, required_keynode,
+				   err_msgp))
+		return -1;
+
+	if (fit_image_hash_get_value(fit, noffset, &fit_value,
+				     &fit_value_len)) {
+		*err_msgp = "Can't get hash value property";
+		return -1;
+	}
+
+	/* Count the number of strings in the property */
+	prop = fdt_getprop(fit, noffset, "hashed-nodes", &prop_len);
+	end = prop ? prop + prop_len : prop;
+	for (name = prop, count = 0; name < end; name++)
+		if (!*name)
+			count++;
+	if (!count) {
+		*err_msgp = "Can't get hashed-nodes property";
+		return -1;
+	}
+
+	/* Add a sanity check here since we are using the stack */
+	if (count > IMAGE_MAX_HASHED_NODES) {
+		*err_msgp = "Number of hashed nodes exceeds maximum";
+		return -1;
+	}
+
+	/* Create a list of node names from those strings */
+	char *node_inc[count];
+
+	debug("Hash nodes (%d):\n", count);
+	for (name = prop, i = 0; name < end; name += strlen(name) + 1, i++) {
+		debug("   '%s'\n", name);
+		node_inc[i] = (char *)name;
+	}
+
+	/*
+	 * Each node can generate one region for each sub-node. Allow for
+	 * 7 sub-nodes (hash at 1, signature@1, etc.) and some extra.
+	 */
+	max_regions = 20 + count * 7;
+	struct fdt_region fdt_regions[max_regions];
+
+	/* Get a list of regions to hash */
+	count = fdt_find_regions(fit, node_inc, count,
+			exc_prop, ARRAY_SIZE(exc_prop),
+			fdt_regions, max_regions - 1,
+			path, sizeof(path), 0);
+	if (count < 0) {
+		*err_msgp = "Failed to hash configuration";
+		return -1;
+	}
+	if (count == 0) {
+		*err_msgp = "No data to hash";
+		return -1;
+	}
+	if (count >= max_regions - 1) {
+		*err_msgp = "Too many hash regions";
+		return -1;
+	}
+
+	/* Add the strings */
+	strings = fdt_getprop(fit, noffset, "hashed-strings", NULL);
+	if (strings) {
+		fdt_regions[count].offset = fdt_off_dt_strings(fit) +
+				fdt32_to_cpu(strings[0]);
+		fdt_regions[count].size = fdt32_to_cpu(strings[1]);
+		count++;
+	}
+
+	/* Allocate the region list on the stack */
+	struct image_region region[count];
+
+	fit_region_make_list(fit, fdt_regions, count, region);
+	if (info.algo->verify(&info, region, count, fit_value,
+			      fit_value_len)) {
+		*err_msgp = "Verification failed";
+		return -1;
+	}
+
+	return 0;
+}
+
+static int fit_config_verify_sig(const void *fit, int conf_noffset,
+		const void *sig_blob, int sig_offset)
+{
+	int noffset;
+	char *err_msg = "";
+	int verified = 0;
+	int ret;
+
+	/* Process all hash subnodes of the component conf node */
+	for (noffset = fdt_first_subnode(fit, conf_noffset);
+	     noffset >= 0;
+	     noffset = fdt_next_subnode(fit, noffset)) {
+		const char *name = fit_get_name(fit, noffset, NULL);
+
+		if (!strncmp(name, FIT_SIG_NODENAME,
+			     strlen(FIT_SIG_NODENAME))) {
+			ret = fit_config_check_sig(fit, noffset, sig_offset,
+						   &err_msg);
+			if (ret) {
+				puts("- ");
+			} else {
+				puts("+ ");
+				verified = 1;
+				break;
+			}
+		}
+	}
+
+	if (noffset == -FDT_ERR_TRUNCATED || noffset == -FDT_ERR_BADSTRUCTURE) {
+		err_msg = "Corrupted or truncated tree";
+		goto error;
+	}
+
+	return verified ? 0 : -EPERM;
+
+error:
+	printf(" error!\n%s for '%s' hash node in '%s' config node\n",
+	       err_msg, fit_get_name(fit, noffset, NULL),
+	       fit_get_name(fit, conf_noffset, NULL));
+	return -1;
+}
+
+int fit_config_verify_required_sigs(const void *fit, int conf_noffset,
+		const void *sig_blob)
+{
+	int noffset;
+	int sig_node;
+
+	/* Work out what we need to verify */
+	sig_node = fdt_subnode_offset(sig_blob, 0, FIT_SIG_NODENAME);
+	if (sig_node < 0) {
+		debug("%s: No signature node found: %s\n", __func__,
+		      fdt_strerror(sig_node));
+		return 0;
+	}
+
+	for (noffset = fdt_first_subnode(sig_blob, sig_node);
+	     noffset >= 0;
+	     noffset = fdt_next_subnode(sig_blob, noffset)) {
+		const char *required;
+		int ret;
+
+		required = fdt_getprop(sig_blob, noffset, "required", NULL);
+		if (!required || strcmp(required, "conf"))
+			continue;
+		ret = fit_config_verify_sig(fit, conf_noffset, sig_blob,
+					    noffset);
+		if (ret) {
+			printf("Failed to verify required signature '%s'\n",
+			       fit_get_name(sig_blob, noffset, NULL));
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+int fit_config_verify(const void *fit, int conf_noffset)
+{
+	return !fit_config_verify_required_sigs(fit, conf_noffset,
+						gd_fdt_blob());
+}
diff --git a/doc/uImage.FIT/sign-configs.its b/doc/uImage.FIT/sign-configs.its
new file mode 100644
index 0000000..3c17f04
--- /dev/null
+++ b/doc/uImage.FIT/sign-configs.its
@@ -0,0 +1,45 @@
+/dts-v1/;
+
+/ {
+	description = "Chrome OS kernel image with one or more FDT blobs";
+	#address-cells = <1>;
+
+	images {
+		kernel at 1 {
+			data = /incbin/("test-kernel.bin");
+			type = "kernel_noload";
+			arch = "sandbox";
+			os = "linux";
+			compression = "lzo";
+			load = <0x4>;
+			entry = <0x8>;
+			kernel-version = <1>;
+			hash at 1 {
+				algo = "sha1";
+			};
+		};
+		fdt at 1 {
+			description = "snow";
+			data = /incbin/("sandbox-kernel.dtb");
+			type = "flat_dt";
+			arch = "sandbox";
+			compression = "none";
+			fdt-version = <1>;
+			hash at 1 {
+				algo = "sha1";
+			};
+		};
+	};
+	configurations {
+		default = "conf at 1";
+		conf at 1 {
+			kernel = "kernel at 1";
+			fdt = "fdt at 1";
+			signature at 1 {
+				algo = "sha1,rsa2048";
+				key-name-hint = "dev";
+				sign-images = "fdt", "kernel";
+			};
+		};
+	};
+};
diff --git a/doc/uImage.FIT/signature.txt b/doc/uImage.FIT/signature.txt
index 0d145e0..bc9f3fa 100644
--- a/doc/uImage.FIT/signature.txt
+++ b/doc/uImage.FIT/signature.txt
@@ -105,8 +105,27 @@ When the image is signed, the following properties are optional:
 
 - comment: Additional information about the signer or image
 
+For config bindings (see Signed Configurations below), the following
+additional properties are optional:
 
-Example: See sign-images.its for an example image tree source file.
+- sign-images: A list of images to sign, each being a property of the conf
+node that contains then. The default is "kernel,fdt" which means that these
+two images will be looked up in the config and signed if present.
+
+For config bindings, these properties are added by the signer:
+
+- hashed-nodes: A list of nodes which were hashed by the signer. Each is
+	a string - the full path to node. A typical value might be:
+
+	hashed-nodes = "/", "/configurations/conf at 1", "/images/kernel at 1",
+		"/images/kernel at 1/hash at 1", "/images/fdt at 1",
+		"/images/fdt at 1/hash at 1";
+
+- hashed-strings: The start and size of the string region of the FIT that
+	was hashed
+
+Example: See sign-images.its for an example image tree source file and
+sign-configs.its for config signing.
 
 
 Public Key Storage
@@ -144,6 +163,153 @@ For RSA the following are mandatory:
 - rsa,n0-inverse: -1 / modulus[0] mod 2^32
 
 
+Signed Configurations
+---------------------
+While signing images is useful, it does not provide complete protection
+against several types of attack. For example, it it possible to create a
+FIT with the same signed images, but with the configuration changed such
+that a different one is selected (mix and match attack). It is also possible
+to substitute a signed image from an older FIT version into a newer FIT
+(roll-back attack).
+
+As an example, consider this FIT:
+
+/ {
+	images {
+		kernel at 1 {
+			data = <data for kernel1>
+			signature at 1 {
+				algo = "sha1,rsa2048";
+				value = <...kernel signature 1...>
+			};
+		};
+		kernel at 2 {
+			data = <data for kernel2>
+			signature at 1 {
+				algo = "sha1,rsa2048";
+				value = <...kernel signature 2...>
+			};
+		};
+		fdt at 1 {
+			data = <data for fdt1>;
+			signature at 1 {
+				algo = "sha1,rsa2048";
+				vaue = <...fdt signature 1...>
+			};
+		};
+		fdt at 2 {
+			data = <data for fdt2>;
+			signature at 1 {
+				algo = "sha1,rsa2048";
+				vaue = <...fdt signature 2...>
+			};
+		};
+	};
+	configurations {
+		default = "conf at 1";
+		conf at 1 {
+			kernel = "kernel at 1";
+			fdt = "fdt at 1";
+		};
+		conf at 1 {
+			kernel = "kernel at 2";
+			fdt = "fdt at 2";
+		};
+	};
+};
+
+Since both kernels are signed it is easy for an attacker to add a new
+configuration 3 with kernel 1 and fdt 2:
+
+	configurations {
+		default = "conf at 1";
+		conf at 1 {
+			kernel = "kernel at 1";
+			fdt = "fdt at 1";
+		};
+		conf at 1 {
+			kernel = "kernel at 2";
+			fdt = "fdt at 2";
+		};
+		conf at 3 {
+			kernel = "kernel at 1";
+			fdt = "fdt at 2";
+		};
+	};
+
+With signed images, nothing protects against this. Whether it gains an
+advantage for the attacker is debatable, but it is not secure.
+
+To solved this problem, we support signed configurations. In this case it
+is the configurations that are signed, not the image. Each image has its
+own hash, and we include the hash in the configuration signature.
+
+So the above example is adjusted to look like this:
+
+/ {
+	images {
+		kernel at 1 {
+			data = <data for kernel1>
+			hash at 1 {
+				algo = "sha1";
+				value = <...kernel hash 1...>
+			};
+		};
+		kernel at 2 {
+			data = <data for kernel2>
+			hash at 1 {
+				algo = "sha1";
+				value = <...kernel hash 2...>
+			};
+		};
+		fdt at 1 {
+			data = <data for fdt1>;
+			hash at 1 {
+				algo = "sha1";
+				value = <...fdt hash 1...>
+			};
+		};
+		fdt at 2 {
+			data = <data for fdt2>;
+			hash at 1 {
+				algo = "sha1";
+				value = <...fdt hash 2...>
+			};
+		};
+	};
+	configurations {
+		default = "conf at 1";
+		conf at 1 {
+			kernel = "kernel at 1";
+			fdt = "fdt at 1";
+			signature at 1 {
+				algo = "sha1,rsa2048";
+				value = <...conf 1 signature...>;
+			};
+		};
+		conf at 2 {
+			kernel = "kernel at 2";
+			fdt = "fdt at 2";
+			signature at 1 {
+				algo = "sha1,rsa2048";
+				value = <...conf 1 signature...>;
+			};
+		};
+	};
+};
+
+
+You can see that we have added hashes for all images (since they are no
+longer signed), and a signature to each configuration. In the above example,
+mkimage will sign configurations/conf at 1, the kernel and fdt that are
+pointed to by the configuration (/images/kernel at 1, /images/kernel at 1/hash at 1,
+/images/fdt at 1, /images/fdt at 1/hash at 1) and the root structure of the image
+(so that it isn't possible to add or remove root nodes). The signature is
+written into /configurations/conf at 1/signature at 1/value. It can easily be
+verified later even if the FIT has been signed with other keys in the
+meantime.
+
+
 Verification
 ------------
 FITs are verified when loaded. After the configuration is selected a list
diff --git a/include/image.h b/include/image.h
index da7b9a0..2614918 100644
--- a/include/image.h
+++ b/include/image.h
@@ -964,6 +964,22 @@ int fit_image_verify_required_sigs(const void *fit, int image_noffset,
 int fit_image_check_sig(const void *fit, int noffset, const void *data,
 		size_t size, int required_keynode, char **err_msgp);
 
+/**
+ * fit_region_make_list() - Make a list of regions to hash
+ *
+ * Given a list of FIT regions (offset, size) provided by libfdt, create
+ * a list of regions (void *, size) for use by the signature creationg
+ * and verification code.
+ *
+ * @fit:		FIT image to process
+ * @fdt_regions:	Regions as returned by libfdt
+ * @count:		Number of regions returned by libfdt
+ * @region:		Place to put list of regions (NULL to allocate it)
+ * @return pointer to list of regions, or NULL if out of memory
+ */
+struct image_region *fit_region_make_list(const void *fit,
+		struct fdt_region *fdt_regions, int count,
+		struct image_region *region);
 
 static inline int fit_image_check_target_arch(const void *fdt, int node)
 {
diff --git a/tools/image-host.c b/tools/image-host.c
index 7aebc29..932384b 100644
--- a/tools/image-host.c
+++ b/tools/image-host.c
@@ -341,10 +341,326 @@ int fit_image_add_verification_data(const char *keydir, void *keydest,
 	return 0;
 }
 
+struct strlist {
+	int count;
+	char **strings;
+};
+
+static void strlist_init(struct strlist *list)
+{
+	memset(list, '\0', sizeof(*list));
+}
+
+static void strlist_free(struct strlist *list)
+{
+	int i;
+
+	for (i = 0; i < list->count; i++)
+		free(list->strings[i]);
+	free(list->strings);
+}
+
+static int strlist_add(struct strlist *list, const char *str)
+{
+	char *dup;
+
+	dup = strdup(str);
+	list->strings = realloc(list->strings,
+				(list->count + 1) * sizeof(char *));
+	if (!list || !str)
+		return -1;
+	list->strings[list->count++] = dup;
+
+	return 0;
+}
+
+static const char *fit_config_get_image_list(void *fit, int noffset,
+		int *lenp, int *allow_missingp)
+{
+	static const char default_list[] = FIT_KERNEL_PROP "\0"
+			FIT_FDT_PROP;
+	const char *prop;
+
+	/* If there is an "image" property, use that */
+	prop = fdt_getprop(fit, noffset, "sign-images", lenp);
+	if (prop) {
+		*allow_missingp = 0;
+		return *lenp ? prop : NULL;
+	}
+
+	/* Default image list */
+	*allow_missingp = 1;
+	*lenp = sizeof(default_list);
+
+	return default_list;
+}
+
+static int fit_config_get_hash_list(void *fit, int conf_noffset,
+				    int sig_offset, struct strlist *node_inc)
+{
+	int allow_missing;
+	const char *prop, *iname, *end;
+	const char *conf_name, *sig_name;
+	char name[200], path[200];
+	int image_count;
+	int ret, len;
+
+	conf_name = fit_get_name(fit, conf_noffset, NULL);
+	sig_name = fit_get_name(fit, sig_offset, NULL);
+
+	/*
+	 * Build a list of nodes we need to hash. We always need the root
+	 * node and the configuration.
+	 */
+	strlist_init(node_inc);
+	snprintf(name, sizeof(name), "%s/%s", FIT_CONFS_PATH, conf_name);
+	if (strlist_add(node_inc, "/") ||
+	    strlist_add(node_inc, name))
+		goto err_mem;
+
+	/* Get a list of images that we intend to sign */
+	prop = fit_config_get_image_list(fit, conf_noffset, &len,
+					&allow_missing);
+	if (!prop)
+		return 0;
+
+	/* Locate the images */
+	end = prop + len;
+	image_count = 0;
+	for (iname = prop; iname < end; iname += strlen(iname) + 1) {
+		int noffset;
+		int image_noffset;
+		int hash_count;
+
+		image_noffset = fit_conf_get_prop_node(fit, conf_noffset,
+						       iname);
+		if (image_noffset < 0) {
+			printf("Failed to find image '%s' in  configuration '%s/%s'\n",
+			       iname, conf_name, sig_name);
+			if (allow_missing)
+				continue;
+
+			return -ENOENT;
+		}
+
+		ret = fdt_get_path(fit, image_noffset, path, sizeof(path));
+		if (ret < 0)
+			goto err_path;
+		if (strlist_add(node_inc, path))
+			goto err_mem;
+
+		snprintf(name, sizeof(name), "%s/%s", FIT_CONFS_PATH,
+			 conf_name);
+
+		/* Add all this image's hashes */
+		hash_count = 0;
+		for (noffset = fdt_first_subnode(fit, image_noffset);
+		     noffset >= 0;
+		     noffset = fdt_next_subnode(fit, noffset)) {
+			const char *name = fit_get_name(fit, noffset, NULL);
+
+			if (strncmp(name, FIT_HASH_NODENAME,
+				    strlen(FIT_HASH_NODENAME)))
+				continue;
+			ret = fdt_get_path(fit, noffset, path, sizeof(path));
+			if (ret < 0)
+				goto err_path;
+			if (strlist_add(node_inc, path))
+				goto err_mem;
+			hash_count++;
+		}
+
+		if (!hash_count) {
+			printf("Failed to find any hash nodes in configuration '%s/%s' image '%s' - without these it is not possible to verify this image\n",
+			       conf_name, sig_name, iname);
+			return -ENOMSG;
+		}
+
+		image_count++;
+	}
+
+	if (!image_count) {
+		printf("Failed to find any images for configuration '%s/%s'\n",
+		       conf_name, sig_name);
+		return -ENOMSG;
+	}
+
+	return 0;
+
+err_mem:
+	printf("Out of memory processing configuration '%s/%s'\n", conf_name,
+	       sig_name);
+	return -ENOMEM;
+
+err_path:
+	printf("Failed to get path for image '%s' in configuration '%s/%s': %s\n",
+	       iname, conf_name, sig_name, fdt_strerror(ret));
+	return -ENOENT;
+}
+
+static int fit_config_get_data(void *fit, int conf_noffset, int noffset,
+		struct image_region **regionp, int *region_countp,
+		char **region_propp, int *region_proplen)
+{
+	char * const exc_prop[] = {"data"};
+	struct strlist node_inc;
+	struct image_region *region;
+	struct fdt_region fdt_regions[100];
+	const char *conf_name, *sig_name;
+	char path[200];
+	int count, i;
+	char *region_prop;
+	int ret, len;
+
+	conf_name = fit_get_name(fit, conf_noffset, NULL);
+	sig_name = fit_get_name(fit, conf_noffset, NULL);
+	debug("%s: conf='%s', sig='%s'\n", __func__, conf_name, sig_name);
+
+	/* Get a list of nodes we want to hash */
+	ret = fit_config_get_hash_list(fit, conf_noffset, noffset, &node_inc);
+	if (ret)
+		return ret;
+
+	/* Get a list of regions to hash */
+	count = fdt_find_regions(fit, node_inc.strings, node_inc.count,
+			exc_prop, ARRAY_SIZE(exc_prop),
+			fdt_regions, ARRAY_SIZE(fdt_regions),
+			path, sizeof(path), 1);
+	if (count < 0) {
+		printf("Failed to hash configuration '%s/%s': %s\n", conf_name,
+		       sig_name, fdt_strerror(ret));
+		return -EIO;
+	}
+	if (count == 0) {
+		printf("No data to hash for configuration '%s/%s': %s\n",
+		       conf_name, sig_name, fdt_strerror(ret));
+		return -EINVAL;
+	}
+
+	/* Build our list of data blocks */
+	region = fit_region_make_list(fit, fdt_regions, count, NULL);
+	if (!region) {
+		printf("Out of memory hashing configuration '%s/%s'\n",
+		       conf_name, sig_name);
+		return -ENOMEM;
+	}
+
+	/* Create a list of all hashed properties */
+	debug("Hash nodes:\n");
+	for (i = len = 0; i < node_inc.count; i++) {
+		debug("   %s\n", node_inc.strings[i]);
+		len += strlen(node_inc.strings[i]) + 1;
+	}
+	region_prop = malloc(len);
+	if (!region_prop) {
+		printf("Out of memory setting up regions for configuration '%s/%s'\n",
+		       conf_name, sig_name);
+		return -ENOMEM;
+	}
+	for (i = len = 0; i < node_inc.count;
+	     len += strlen(node_inc.strings[i]) + 1, i++)
+		strcpy(region_prop + len, node_inc.strings[i]);
+	strlist_free(&node_inc);
+
+	*region_countp = count;
+	*regionp = region;
+	*region_propp = region_prop;
+	*region_proplen = len;
+
+	return 0;
+}
+
+static int fit_config_process_sig(const char *keydir, void *keydest,
+		void *fit, const char *conf_name, int conf_noffset,
+		int noffset, const char *comment, int require_keys)
+{
+	struct image_sign_info info;
+	const char *node_name;
+	struct image_region *region;
+	char *region_prop;
+	int region_proplen;
+	int region_count;
+	uint8_t *value;
+	uint value_len;
+	int ret;
+
+	node_name = fit_get_name(fit, noffset, NULL);
+	if (fit_config_get_data(fit, conf_noffset, noffset, &region,
+				&region_count, &region_prop, &region_proplen))
+		return -1;
+
+	if (fit_image_setup_sig(&info, keydir, fit, conf_name, noffset,
+				require_keys ? "conf" : NULL))
+		return -1;
+
+	ret = info.algo->sign(&info, region, region_count, &value, &value_len);
+	free(region);
+	if (ret) {
+		printf("Failed to sign '%s' signature node in '%s' conf node\n",
+		       node_name, conf_name);
+
+		/* We allow keys to be missing */
+		if (ret == -ENOENT)
+			return 0;
+		return -1;
+	}
+
+	if (fit_image_write_sig(fit, noffset, value, value_len, comment,
+				region_prop, region_proplen)) {
+		printf("Can't write signature for '%s' signature node in '%s' conf node\n",
+		       node_name, conf_name);
+		return -1;
+	}
+	free(value);
+	free(region_prop);
+
+	/* Get keyname again, as FDT has changed and invalidated our pointer */
+	info.keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL);
+
+	/* Write the public key into the supplied FDT file */
+	if (keydest && info.algo->add_verify_data(&info, keydest)) {
+		printf("Failed to add verification data for '%s' signature node in '%s' image node\n",
+		       node_name, conf_name);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int fit_config_add_verification_data(const char *keydir, void *keydest,
+		void *fit, int conf_noffset, const char *comment,
+		int require_keys)
+{
+	const char *conf_name;
+	int noffset;
+
+	conf_name = fit_get_name(fit, conf_noffset, NULL);
+
+	/* Process all hash subnodes of the configuration node */
+	for (noffset = fdt_first_subnode(fit, conf_noffset);
+	     noffset >= 0;
+	     noffset = fdt_next_subnode(fit, noffset)) {
+		const char *node_name;
+		int ret = 0;
+
+		node_name = fit_get_name(fit, noffset, NULL);
+		if (!strncmp(node_name, FIT_SIG_NODENAME,
+			     strlen(FIT_SIG_NODENAME))) {
+			ret = fit_config_process_sig(keydir, keydest,
+				fit, conf_name, conf_noffset, noffset, comment,
+				require_keys);
+		}
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
 int fit_add_verification_data(const char *keydir, void *keydest, void *fit,
 			      const char *comment, int require_keys)
 {
-	int images_noffset;
+	int images_noffset, confs_noffset;
 	int noffset;
 	int ret;
 
@@ -370,5 +686,28 @@ int fit_add_verification_data(const char *keydir, void *keydest, void *fit,
 			return ret;
 	}
 
+	/* If there are no keys, we can't sign configurations */
+	if (!IMAGE_ENABLE_SIGN || !keydir)
+		return 0;
+
+	/* Find configurations parent node offset */
+	confs_noffset = fdt_path_offset(fit, FIT_CONFS_PATH);
+	if (confs_noffset < 0) {
+		printf("Can't find images parent node '%s' (%s)\n",
+		       FIT_IMAGES_PATH, fdt_strerror(confs_noffset));
+		return -ENOENT;
+	}
+
+	/* Process its subnodes, print out component images details */
+	for (noffset = fdt_first_subnode(fit, confs_noffset);
+	     noffset >= 0;
+	     noffset = fdt_next_subnode(fit, noffset)) {
+		ret = fit_config_add_verification_data(keydir, keydest,
+						       fit, noffset, comment,
+						       require_keys);
+		if (ret)
+			return ret;
+	}
+
 	return 0;
 }
-- 
1.8.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [U-Boot] [PATCH v3 11/12] sandbox: config: Enable FIT signatures with RSA
  2013-06-13 22:09 ` [U-Boot] " Simon Glass
                   ` (10 preceding siblings ...)
  (?)
@ 2013-06-13 22:10 ` Simon Glass
  -1 siblings, 0 replies; 27+ messages in thread
From: Simon Glass @ 2013-06-13 22:10 UTC (permalink / raw)
  To: u-boot

We want to sign and verify images using sandbox, so enable these options.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
Changes in v3: None
Changes in v2: None

 include/configs/sandbox.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h
index d704329..98dd083 100644
--- a/include/configs/sandbox.h
+++ b/include/configs/sandbox.h
@@ -43,6 +43,8 @@
 #define CONFIG_OF_LIBFDT
 #define CONFIG_LMB
 #define CONFIG_FIT
+#define CONFIG_FIT_SIGNATURE
+#define CONFIG_RSA
 #define CONFIG_CMD_FDT
 
 #define CONFIG_FS_FAT
-- 
1.8.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [U-Boot] [PATCH v3 12/12] Add verified boot information and test
  2013-06-13 22:09 ` [U-Boot] " Simon Glass
                   ` (11 preceding siblings ...)
  (?)
@ 2013-06-13 22:10 ` Simon Glass
  2013-06-13 22:33   ` Simon Glass
  -1 siblings, 1 reply; 27+ messages in thread
From: Simon Glass @ 2013-06-13 22:10 UTC (permalink / raw)
  To: u-boot

Add a description of how to implement verified boot using signed FIT images,
and a simple test which verifies operation on sandbox.

The test signs a FIT image and verifies it, then signs a FIT configuration
and verifies it. Then it corrupts the signature to check that this is
detected.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
Changes in v3:
- Fix 'compile' typo
- Rebase to master

Changes in v2:
- Update README to fix typos
- Use U-Boot's -c option instead of hard-coding a boot script

 doc/uImage.FIT/verified-boot.txt | 104 ++++++++++++++++++++++++++++++++
 test/vboot/.gitignore            |   3 +
 test/vboot/sandbox-kernel.dts    |   7 +++
 test/vboot/sandbox-u-boot.dts    |   7 +++
 test/vboot/sign-configs.its      |  45 ++++++++++++++
 test/vboot/sign-images.its       |  42 +++++++++++++
 test/vboot/vboot_test.sh         | 126 +++++++++++++++++++++++++++++++++++++++
 7 files changed, 334 insertions(+)
 create mode 100644 doc/uImage.FIT/verified-boot.txt
 create mode 100644 test/vboot/.gitignore
 create mode 100644 test/vboot/sandbox-kernel.dts
 create mode 100644 test/vboot/sandbox-u-boot.dts
 create mode 100644 test/vboot/sign-configs.its
 create mode 100644 test/vboot/sign-images.its
 create mode 100755 test/vboot/vboot_test.sh

diff --git a/doc/uImage.FIT/verified-boot.txt b/doc/uImage.FIT/verified-boot.txt
new file mode 100644
index 0000000..3c83fbc
--- /dev/null
+++ b/doc/uImage.FIT/verified-boot.txt
@@ -0,0 +1,104 @@
+U-Boot Verified Boot
+====================
+
+Introduction
+------------
+Verified boot here means the verification of all software loaded into a
+machine during the boot process to ensure that it is authorised and correct
+for that machine.
+
+Verified boot extends from the moment of system reset to as far as you wish
+into the boot process. An example might be loading U-Boot from read-only
+memory, then loading a signed kernel, then using the kernel's dm-verity
+driver to mount a signed root filesystem.
+
+A key point is that it is possible to field-upgrade the software on machines
+which use verified boot. Since the machine will only run software that has
+been correctly signed, it is safe to read software from an updatable medium.
+It is also possible to add a secondary signed firmware image, in read-write
+memory, so that firmware can easily be upgraded in a secure manner.
+
+
+Signing
+-------
+Verified boot uses cryptographic algorithms to 'sign' software images.
+Images are signed using a private key known only to the signer, but can
+be verified using a public key. As its name suggests the public key can be
+made available without risk to the verification process. The private and
+public keys are mathematically related. For more information on how this
+works look up "public key cryptography" and "RSA" (a particular algorithm).
+
+The signing and verification process looks something like this:
+
+
+      Signing                                      Verification
+      =======                                      ============
+
+ +--------------+                   *
+ | RSA key pair |                   *             +---------------+
+ | .key  .crt   |                   *             | Public key in |
+ +--------------+       +------> public key ----->| trusted place |
+       |                |           *             +---------------+
+       |                |           *                    |
+       v                |           *                    v
+   +---------+          |           *              +--------------+
+   |         |----------+           *              |              |
+   | signer  |                      *              |    U-Boot    |
+   |         |----------+           *              |  signature   |--> yes/no
+   +---------+          |           *              | verification |
+      ^                 |           *              |              |
+      |                 |           *              +--------------+
+      |                 |           *                    ^
+ +----------+           |           *                    |
+ | Software |           +----> signed image -------------+
+ |  image   |                       *
+ +----------+                       *
+
+
+The signature algorithm relies only on the public key to do its work. Using
+this key it checks the signature that it finds in the image. If it verifies
+then we know that the image is OK.
+
+The public key from the signer allows us to verify and therefore trust
+software from updatable memory.
+
+It is critical that the public key be secure and cannot be tampered with.
+It can be stored in read-only memory, or perhaps protected by other on-chip
+crypto provided by some modern SOCs. If the public key can ben changed, then
+the verification is worthless.
+
+
+Chaining Images
+---------------
+The above method works for a signer providing images to a run-time U-Boot.
+It is also possible to extend this scheme to a second level, like this:
+
+1. Master private key is used by the signer to sign a first-stage image.
+2. Master public key is placed in read-only memory.
+2. Secondary private key is created and used to sign second-stage images.
+3. Secondary public key is placed in first stage images
+4. We use the master public key to verify the first-stage image. We then
+use the secondary public key in the first-stage image to verify the second-
+state image.
+5. This chaining process can go on indefinitely. It is recommended to use a
+different key at each stage, so that a compromise in one place will not
+affect the whole change.
+
+
+Flattened Image Tree (FIT)
+--------------------------
+The FIT format is alreay widely used in U-Boot. It is a flattened device
+tree (FDT) in a particular format, with images contained within. FITs
+include hashes to verify images, so it is relatively straightforward to
+add signatures as well.
+
+The public key can be stored in U-Boot's CONFIG_OF_CONTROL device tree in
+a standard place. Then when a FIT it loaded it can be verified using that
+public key. Multiple keys and multiple signatures are supported.
+
+See signature.txt for more information.
+
+
+Simon Glass
+sjg at chromium.org
+1-1-13
diff --git a/test/vboot/.gitignore b/test/vboot/.gitignore
new file mode 100644
index 0000000..4631242
--- /dev/null
+++ b/test/vboot/.gitignore
@@ -0,0 +1,3 @@
+/*.dtb
+/test.fit
+/dev-keys
diff --git a/test/vboot/sandbox-kernel.dts b/test/vboot/sandbox-kernel.dts
new file mode 100644
index 0000000..a1e853c
--- /dev/null
+++ b/test/vboot/sandbox-kernel.dts
@@ -0,0 +1,7 @@
+/dts-v1/;
+
+/ {
+	model = "Sandbox Verified Boot Test";
+	compatible = "sandbox";
+
+};
diff --git a/test/vboot/sandbox-u-boot.dts b/test/vboot/sandbox-u-boot.dts
new file mode 100644
index 0000000..a1e853c
--- /dev/null
+++ b/test/vboot/sandbox-u-boot.dts
@@ -0,0 +1,7 @@
+/dts-v1/;
+
+/ {
+	model = "Sandbox Verified Boot Test";
+	compatible = "sandbox";
+
+};
diff --git a/test/vboot/sign-configs.its b/test/vboot/sign-configs.its
new file mode 100644
index 0000000..db2ed79
--- /dev/null
+++ b/test/vboot/sign-configs.its
@@ -0,0 +1,45 @@
+/dts-v1/;
+
+/ {
+	description = "Chrome OS kernel image with one or more FDT blobs";
+	#address-cells = <1>;
+
+	images {
+		kernel at 1 {
+			data = /incbin/("test-kernel.bin");
+			type = "kernel_noload";
+			arch = "sandbox";
+			os = "linux";
+			compression = "none";
+			load = <0x4>;
+			entry = <0x8>;
+			kernel-version = <1>;
+			hash at 1 {
+				algo = "sha1";
+			};
+		};
+		fdt at 1 {
+			description = "snow";
+			data = /incbin/("sandbox-kernel.dtb");
+			type = "flat_dt";
+			arch = "sandbox";
+			compression = "none";
+			fdt-version = <1>;
+			hash at 1 {
+				algo = "sha1";
+			};
+		};
+	};
+	configurations {
+		default = "conf at 1";
+		conf at 1 {
+			kernel = "kernel at 1";
+			fdt = "fdt at 1";
+			signature at 1 {
+				algo = "sha1,rsa2048";
+				key-name-hint = "dev";
+				sign-images = "fdt", "kernel";
+			};
+		};
+	};
+};
diff --git a/test/vboot/sign-images.its b/test/vboot/sign-images.its
new file mode 100644
index 0000000..f69326a
--- /dev/null
+++ b/test/vboot/sign-images.its
@@ -0,0 +1,42 @@
+/dts-v1/;
+
+/ {
+	description = "Chrome OS kernel image with one or more FDT blobs";
+	#address-cells = <1>;
+
+	images {
+		kernel at 1 {
+			data = /incbin/("test-kernel.bin");
+			type = "kernel_noload";
+			arch = "sandbox";
+			os = "linux";
+			compression = "none";
+			load = <0x4>;
+			entry = <0x8>;
+			kernel-version = <1>;
+			signature at 1 {
+				algo = "sha1,rsa2048";
+				key-name-hint = "dev";
+			};
+		};
+		fdt at 1 {
+			description = "snow";
+			data = /incbin/("sandbox-kernel.dtb");
+			type = "flat_dt";
+			arch = "sandbox";
+			compression = "none";
+			fdt-version = <1>;
+			signature at 1 {
+				algo = "sha1,rsa2048";
+				key-name-hint = "dev";
+			};
+		};
+	};
+	configurations {
+		default = "conf at 1";
+		conf at 1 {
+			kernel = "kernel at 1";
+			fdt = "fdt at 1";
+		};
+	};
+};
diff --git a/test/vboot/vboot_test.sh b/test/vboot/vboot_test.sh
new file mode 100755
index 0000000..c3cfade
--- /dev/null
+++ b/test/vboot/vboot_test.sh
@@ -0,0 +1,126 @@
+#!/bin/sh
+#
+# Copyright (c) 2013, Google Inc.
+#
+# Simple Verified Boot Test Script
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+
+set -e
+
+# Run U-Boot and report the result
+# Args:
+#	$1:	Test message
+run_uboot() {
+	echo -n "Test Verified Boot Run: $1: "
+	${uboot} -d sandbox-u-boot.dtb >${tmp} -c '
+sb load host 0 100 test.fit;
+fdt addr 100;
+bootm 100;
+reset'
+	if ! grep -q "$2" ${tmp}; then
+		echo
+		echo "Verified boot key check failed, output follows:"
+		cat ${tmp}
+		false
+	else
+		echo "OK"
+	fi
+}
+
+echo "Simple Verified Boot Test"
+echo "========================="
+echo
+echo "Please see doc/uImage.FIT/verified-boot.txt for more information"
+echo
+
+err=0
+tmp=/tmp/vboot_test.$$
+
+dir=$(dirname $0)
+
+if [ -z ${O} ]; then
+	O=.
+fi
+O=$(readlink -f ${O})
+
+dtc="-I dts -O dtb -p 2000"
+uboot="${O}/u-boot"
+mkimage="${O}/tools/mkimage"
+keys="${dir}/dev-keys"
+echo ${mkimage} -D "${dtc}"
+
+echo "Build keys"
+mkdir -p ${keys}
+
+# Create an RSA key pair
+openssl genrsa -F4 -out ${keys}/dev.key 2048 2>/dev/null
+
+# Create a certificate containing the public key
+openssl req -batch -new -x509 -key ${keys}/dev.key -out ${keys}/dev.crt
+
+pushd ${dir} >/dev/null
+
+# Compile our device tree files for kernel and U-Boot (CONFIG_OF_CONTROL)
+dtc -p 0x1000 sandbox-kernel.dts -O dtb -o sandbox-kernel.dtb
+dtc -p 0x1000 sandbox-u-boot.dts -O dtb -o sandbox-u-boot.dtb
+
+# Create a number kernel image with zeroes
+head -c 5000 /dev/zero >test-kernel.bin
+
+# Build the FIT, but don't sign anything yet
+echo Build FIT with signed images
+${mkimage} -D "${dtc}" -f sign-images.its test.fit >${tmp}
+
+run_uboot "unsigned signatures:" "dev-"
+
+# Sign images with our dev keys
+echo Sign images
+${mkimage} -D "${dtc}" -F -k dev-keys -K sandbox-u-boot.dtb -r test.fit >${tmp}
+
+run_uboot "signed images" "dev+"
+
+
+# Create a fresh .dtb without the public keys
+dtc -p 0x1000 sandbox-u-boot.dts -O dtb -o sandbox-u-boot.dtb
+
+echo Build FIT with signed configuration
+${mkimage} -D "${dtc}" -f sign-configs.its test.fit >${tmp}
+
+run_uboot "unsigned config" "sha1+ OK"
+
+# Sign images with our dev keys
+echo Sign images
+${mkimage} -D "${dtc}" -F -k dev-keys -K sandbox-u-boot.dtb -r test.fit >${tmp}
+
+run_uboot "signed config" "dev+"
+
+# Increment the first byte of the signature, which should cause failure
+sig=$(fdtget -t bx test.fit /configurations/conf at 1/signature at 1 value)
+newbyte=$(printf %x $((0x${sig:0:2} + 1)))
+sig="${newbyte} ${sig:2}"
+fdtput -t bx test.fit /configurations/conf at 1/signature at 1 value ${sig}
+
+run_uboot "signed config with bad hash" "Bad Data Hash"
+
+popd >/dev/null
+
+echo
+if ${ok}; then
+	echo "Test passed"
+else
+	echo "Test failed"
+fi
-- 
1.8.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [U-Boot] [PATCH v3 12/12] Add verified boot information and test
  2013-06-13 22:10 ` [U-Boot] [PATCH v3 12/12] Add verified boot information and test Simon Glass
@ 2013-06-13 22:33   ` Simon Glass
  2013-06-20 16:07     ` Tom Rini
  0 siblings, 1 reply; 27+ messages in thread
From: Simon Glass @ 2013-06-13 22:33 UTC (permalink / raw)
  To: u-boot

Hi Tom,

On Thu, Jun 13, 2013 at 3:10 PM, Simon Glass <sjg@chromium.org> wrote:

> Add a description of how to implement verified boot using signed FIT
> images,
> and a simple test which verifies operation on sandbox.
>
> The test signs a FIT image and verifies it, then signs a FIT configuration
> and verifies it. Then it corrupts the signature to check that this is
> detected.
>
> Signed-off-by: Simon Glass <sjg@chromium.org>
>

If it helps, here are the results of my build for this series (and the
trace one). No new failures but you can see quite a few problems with
Xscale.

 ./tools/buildman/buildman -b us-vboot9c -s
Summary of 35 commits for 1124 boards (32 threads, 1 job per thread)
01: pci: introduce CONFIG_PCI_INDIRECT_BRIDGE option
  blackfin: +   bf561-acvilon cm-bf561 blackstamp br4 bct-brettl2 cm-bf527
dnp5370 bf506f-ezkit ip04 bf527-sdp bf609-ezkit bf537-stamp bf527-ezkit-v2
cm-bf537e tcm-bf518 cm-bf537u bf527-ezkit bf537-pnav cm-bf533 pr1
bf533-ezkit ibf-dsp561 bf537-srv1 cm-bf548 bf537-minotaur bf538f-ezkit
bf548-ezkit bf525-ucr2 blackvme tcm-bf537 bf533-stamp bf518f-ezbrd
bf527-ad7160-eval bf526-ezbrd bf561-ezkit
      m68k: +   M54455EVB_a66 M5329AFEE M5249EVB idmr M5208EVBE M5475FFE
M54451EVB astro_mcf5373l M54418TWR_serial_rmii M54455EVB_intel M5282EVB
M54455EVB_i66 M5475GFE M5253DEMO M54455EVB_stm33 M5485BFE M5485DFE
M5329BFEE M52277EVB M5475EFE M5475CFE M5485AFE M53017EVB M5475AFE M5485HFE
M5235EVB M5253EVBE M54418TWR_nand_mii M54418TWR_nand_rmii_lowfreq TASREG
cobra5272 M5475BFE M5475DFE M5275EVB M52277EVB_stmicro eb_cpu5282
eb_cpu5282_internal M54451EVB_stmicro M5271EVB M5485GFE M5485EFE M5485FFE
M54418TWR M5235EVB_Flash32 M5373EVB M54418TWR_nand_rmii
M54418TWR_serial_mii M5485CFE M54455EVB M5272C3
   powerpc: +   MVBLM7 MVSMR lcd4_lwmon5
        sh: +   rsk7269 rsk7264 sh7757lcr sh7752evb rsk7203
microblaze: +   microblaze-generic
  openrisc: +   openrisc-generic
       arm: +   palmtc zipitz2 VCMA9 lubbock zynq_dcc vpac270_nor_128
colibri_pxa270 kzm9g zynq xaeniax polaris pxa255_idp vpac270_ond_256
vpac270_nor_256 smdk2410 h2200 balloon3 palmld trizepsiv
     nds32: +   adp-ag101p adp-ag102 adp-ag101
02: pci: Convert extern inline functions to static inline
03: x86: Correct missing local variable in bootm
04: Fix missing return in do_mem_loop()
05: Show stdout on error in fit-test
06: bootstage: Correct printf types
07: Add function to print a number with grouped digits
08: Add trace library
09: Add a trace command
10: Support tracing in config.mk when enabled
11: Add trace support to generic board
12: Add proftool to decode profile data
13: sandbox: Support trace feature
14: Add a simple test for sandbox trace
15: Clarify bootm OS arguments
16: Refactor the bootm command to reduce code duplication
17: Add a 'fake' go command to the bootm command
18: arm: Implement the 'fake' go command
19: exynos: Avoid function instrumentation for microsecond timer
20: exynos: config: Add tracing options
21: x86: Support tracing function
22: x86: config: Add tracing options
23: wip
24: image: Add signing infrastructure
25: image: Support signing of images
26: image: Add RSA support for image signing
27: mkimage: Add -k option to specify key directory
28: mkimage: Add -K to write public keys to an FDT blob
29: mkimage: Add -F option to modify an existing .fit file
30: mkimage: Add -c option to specify a comment for key signing
31: mkimage: Add -r option to specify keys that must be verified
32: libfdt: Add fdt_find_regions()
33: image: Add support for signing of FIT configurations
34: sandbox: config: Enable FIT signatures with RSA
35: Add verified boot information and test

Regards,
Simon

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [U-Boot] [PATCH v3 12/12] Add verified boot information and test
  2013-06-13 22:33   ` Simon Glass
@ 2013-06-20 16:07     ` Tom Rini
  2013-06-20 16:18       ` Simon Glass
  2013-06-20 20:55       ` Simon Glass
  0 siblings, 2 replies; 27+ messages in thread
From: Tom Rini @ 2013-06-20 16:07 UTC (permalink / raw)
  To: u-boot

On Thu, Jun 13, 2013 at 03:33:19PM -0700, Simon Glass wrote:
> Hi Tom,
> 
> On Thu, Jun 13, 2013 at 3:10 PM, Simon Glass <sjg@chromium.org> wrote:
> 
> > Add a description of how to implement verified boot using signed FIT
> > images,
> > and a simple test which verifies operation on sandbox.
> >
> > The test signs a FIT image and verifies it, then signs a FIT configuration
> > and verifies it. Then it corrupts the signature to check that this is
> > detected.
> >
> > Signed-off-by: Simon Glass <sjg@chromium.org>
> >
> 
> If it helps, here are the results of my build for this series (and the
> trace one). No new failures but you can see quite a few problems with
> Xscale.

I _think_ Xscale is toolchain choice related.  My question is, for
arches which use --gc-sections, what is the size change from before to
after, when not opting in on this?

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20130620/72b50def/attachment.pgp>

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [U-Boot] [PATCH v3 12/12] Add verified boot information and test
  2013-06-20 16:07     ` Tom Rini
@ 2013-06-20 16:18       ` Simon Glass
  2013-06-20 20:55       ` Simon Glass
  1 sibling, 0 replies; 27+ messages in thread
From: Simon Glass @ 2013-06-20 16:18 UTC (permalink / raw)
  To: u-boot

Hi Tom,

On Thu, Jun 20, 2013 at 9:07 AM, Tom Rini <trini@ti.com> wrote:

> On Thu, Jun 13, 2013 at 03:33:19PM -0700, Simon Glass wrote:
> > Hi Tom,
> >
> > On Thu, Jun 13, 2013 at 3:10 PM, Simon Glass <sjg@chromium.org> wrote:
> >
> > > Add a description of how to implement verified boot using signed FIT
> > > images,
> > > and a simple test which verifies operation on sandbox.
> > >
> > > The test signs a FIT image and verifies it, then signs a FIT
> configuration
> > > and verifies it. Then it corrupts the signature to check that this is
> > > detected.
> > >
> > > Signed-off-by: Simon Glass <sjg@chromium.org>
> > >
> >
> > If it helps, here are the results of my build for this series (and the
> > trace one). No new failures but you can see quite a few problems with
> > Xscale.
>
> I _think_ Xscale is toolchain choice related.  My question is, for
> arches which use --gc-sections, what is the size change from before to
> after, when not opting in on this?
>

Yes I think you are right. Unfortunately I don't have that build now, but I
will redo it and check.

Regards,
Simon


>
> --
> Tom
>

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [U-Boot] [PATCH v3 12/12] Add verified boot information and test
  2013-06-20 16:07     ` Tom Rini
  2013-06-20 16:18       ` Simon Glass
@ 2013-06-20 20:55       ` Simon Glass
  1 sibling, 0 replies; 27+ messages in thread
From: Simon Glass @ 2013-06-20 20:55 UTC (permalink / raw)
  To: u-boot

Hi Tom,

On Thu, Jun 20, 2013 at 9:07 AM, Tom Rini <trini@ti.com> wrote:

> On Thu, Jun 13, 2013 at 03:33:19PM -0700, Simon Glass wrote:
> > Hi Tom,
> >
> > On Thu, Jun 13, 2013 at 3:10 PM, Simon Glass <sjg@chromium.org> wrote:
> >
> > > Add a description of how to implement verified boot using signed FIT
> > > images,
> > > and a simple test which verifies operation on sandbox.
> > >
> > > The test signs a FIT image and verifies it, then signs a FIT
> configuration
> > > and verifies it. Then it corrupts the signature to check that this is
> > > detected.
> > >
> > > Signed-off-by: Simon Glass <sjg@chromium.org>
> > >
> >
> > If it helps, here are the results of my build for this series (and the
> > trace one). No new failures but you can see quite a few problems with
> > Xscale.
>
> I _think_ Xscale is toolchain choice related.  My question is, for
> arches which use --gc-sections, what is the size change from before to
> after, when not opting in on this?
>

Including both trace and verified boot series, the size drops a little for
ARM and powerpc:

$ ./tools/buildman/buildman -b us-vboot9d  -sS arm powerpc --step 0
Summary of 2 commits for 955 boards (32 threads, 1 job per thread)
01: Merge branch 'master' of git://www.denx.de/git/u-boot-mmc
       arm: +   palmtc zipitz2 VCMA9 lubbock vpac270_nor_128 colibri_pxa270
kzm9g zynq_dcc zynq xaeniax polaris pxa255_idp vpac270_ond_256
vpac270_nor_256 smdk2410 balloon3 palmld trizepsiv h2200
   powerpc: +   MVBLM7 MVSMR lcd4_lwmon5
36: wip
       arm: (for 290/314 boards)  all -142.6  bss +4.5  data +27.1  rodata
-20.4  spl/u-boot-spl:all +1.9  spl/u-boot-spl:bss +0.0
 spl/u-boot-spl:rodata +1.9  text -153.8
   powerpc: (for 639/641 boards)  all -190.2  bss +0.0  data +25.6  rodata
-12.2  spl/u-boot-spl:all +0.2  spl/u-boot-spl:rodata +0.2  text -203.6

(the wip commit is just a patman change). You can see the text size drops
by 100-200 bytes. This is all due to the bootm refactor which removed
duplicated code.

If you are interested you can see this in the detail view. Commit 16
removes quite a bit of code. Commit 25 adds up to 80 bytes of text.

$ ./tools/buildman/buildman -b us-vboot9d  -sS arm powerpc
Summary of 36 commits for 955 boards (32 threads, 1 job per thread)
01: Merge branch 'master' of git://www.denx.de/git/u-boot-mmc
       arm: +   palmtc zipitz2 VCMA9 lubbock vpac270_nor_128 colibri_pxa270
kzm9g zynq_dcc zynq xaeniax polaris pxa255_idp vpac270_ond_256
vpac270_nor_256 smdk2410 balloon3 palmld trizepsiv h2200
   powerpc: +   MVBLM7 MVSMR lcd4_lwmon5
02: pci: Convert extern inline functions to static inline
03: x86: Correct missing local variable in bootm
04: Fix missing return in do_mem_loop()
05: Show stdout on error in fit-test
06: bootstage: Correct printf types
07: Add function to print a number with grouped digits
       arm: (for 290/314 boards)  all +6.0  bss -1.2  data +0.0  rodata
+7.2  spl/u-boot-spl:all +1.8  spl/u-boot-spl:bss -0.1
 spl/u-boot-spl:rodata +1.9
   powerpc: (for 639/641 boards)  all +7.8  bss -0.0  rodata +4.8
 spl/u-boot-spl:all +0.1  spl/u-boot-spl:rodata +0.1  text +3.0
08: Add trace library
       arm: (for 290/314 boards)  all +0.1  bss -0.0  data +0.1
 spl/u-boot-spl:all +0.1  spl/u-boot-spl:bss +0.1
   powerpc: (for 639/641 boards)  all +0.0  bss +0.0
09: Add a trace command
10: Support tracing in config.mk when enabled
11: Add trace support to generic board
       arm: (for 290/314 boards)  all +2.7  bss -0.4  data +0.6  text +2.5
12: Add proftool to decode profile data
13: sandbox: Support trace feature
14: Add a simple test for sandbox trace
15: Clarify bootm OS arguments
       arm: (for 290/314 boards)  all +13.0  bss +1.1  text +12.0
   powerpc: (for 639/641 boards)  all +15.4  text +15.4
16: Refactor the bootm command to reduce code duplication
       arm: (for 290/314 boards)  all -352.1  bss +2.1  rodata -69.0  text
-285.2
   powerpc: (for 639/641 boards)  all -345.4  rodata -44.2  text -301.2
17: Add a 'fake' go command to the bootm command
       arm: (for 290/314 boards)  all +55.1  bss +0.1  data +26.2  rodata
+5.0  text +23.8
   powerpc: (for 639/641 boards)  all +42.5  data +25.6  rodata +3.2  text
+13.7
18: arm: Implement the 'fake' go command
       arm: (for 290/314 boards)  all +89.4  bss +4.5  rodata +25.0  text
+59.9
19: exynos: Avoid function instrumentation for microsecond timer
20: exynos: config: Add tracing options
       arm: (for 290/314 boards)  all +25.0  bss -0.1  data +0.2  rodata
+6.9  text +18.0
   powerpc: (for 639/641 boards)  all -0.0  text -0.0
21: x86: Support tracing function
   powerpc: (for 639/641 boards)  all +0.0  text +0.0
22: x86: config: Add tracing options
       arm: (for 290/314 boards)  all -0.9  bss -0.7  rodata -0.1
   powerpc: (for 639/641 boards)  all -0.4  rodata -0.4
23: wip
       arm: (for 290/314 boards)  all +0.9  bss +0.7  rodata +0.1
   powerpc: (for 639/641 boards)  all +0.4  rodata +0.4
24: image: Add signing infrastructure
       arm: (for 290/314 boards)  all -0.3  bss -0.4  data +0.1
25: image: Support signing of images
       arm: (for 290/314 boards)  all +18.9  bss -0.6  data -0.0  rodata
+4.5  text +15.1
   powerpc: (for 639/641 boards)  all +89.4  rodata +23.9
 spl/u-boot-spl:all +0.1  spl/u-boot-spl:rodata +0.1  text +65.5
26: image: Add RSA support for image signing
   powerpc: (for 639/641 boards)  all +0.0  rodata +0.0
27: mkimage: Add -k option to specify key directory
   powerpc: (for 639/641 boards)  all +0.0  text +0.0
28: mkimage: Add -K to write public keys to an FDT blob
29: mkimage: Add -F option to modify an existing .fit file
   powerpc: (for 639/641 boards)  all -0.0  rodata -0.0  text -0.0
30: mkimage: Add -c option to specify a comment for key signing
   powerpc: (for 639/641 boards)  all -0.0  rodata -0.0  text +0.0
31: mkimage: Add -r option to specify keys that must be verified
   powerpc: (for 639/641 boards)  all +0.0  rodata +0.0
32: libfdt: Add fdt_find_regions()
       arm: (for 290/314 boards)  all -0.4  bss -0.4  data +0.0
33: image: Add support for signing of FIT configurations
       arm: (for 290/314 boards)  all +0.0  bss +0.1  data -0.0
34: sandbox: config: Enable FIT signatures with RSA
35: Add verified boot information and test
36: wip

Regards,
Simon

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [U-Boot] [PATCH v3 0/12] Verified boot implementation based on FIT
  2013-06-13 22:09 ` [U-Boot] " Simon Glass
@ 2013-06-26 20:24     ` Tom Rini
  -1 siblings, 0 replies; 27+ messages in thread
From: Tom Rini @ 2013-06-26 20:24 UTC (permalink / raw)
  To: Simon Glass
  Cc: Joel A Fernandes, Will Drewry,
	u-boot-review-hpIqsD4AKlfQT0dZR+AlfA, U-Boot Mailing List,
	Devicetree Discuss, Bill Richardson, Joe Hershberger,
	Randall Spangler, Vadim Bendebury, Andreas B??ck, Kees Cook


[-- Attachment #1.1: Type: text/plain, Size: 6411 bytes --]

On Thu, Jun 13, 2013 at 03:09:59PM -0700, Simon Glass wrote:

> This series implemented a verified boot system based around FIT images
> as discussed on the U-Boot mailing list, including on this thread:
> 
> http://permalink.gmane.org/gmane.comp.boot-loaders.u-boot/147830
> 
> RSA is used to implement the encryption. Images are signed by mkimage
> using private keys created by the user. Public keys are written into
> U-Boot control FDT (CONFIG_OF_CONTROL) for access by bootm etc. at
> run-time. The control FDT must be stored in a secure place where it
> cannot be changed after manufacture. Some notes are provided in the
> documentaion on how this can be achieved. The implementation is fairly
> efficient and fits nicely into U-Boot. FIT plus RSA adds around 18KB
> to SPL size which is manageable on modern SoCs.
> 
> When images are loaded, they are verified with the public keys.
> 
> It is important to have a test framework for this series. For this, sandbox
> is used, and a script is provided which signs images and gets sandbox to
> load them using a script, to check that all is well.
> 
> Rollback prevention has been added in a separate TPM patch. This ensures
> that an attacker cannot boot your system with an old image that has been
> compromised. Support for this is not built into bootm, but instead must
> be scripted in U-Boot. It is possible that a standard scheme for this could
> be devised by adding version number tags to the signing procedure. However
> scripts do provide more flexibility. See the 'tpm' command for more
> information.
> 
> Two patches affect libfdt and have material which is not yet upstream in
> that project:
> 
>    image: Add support for signing of FIT configurations
>    libfdt: Add fdt_find_regions()
> 
> If these are not desired, then the rest of the series can stand alone,
> just without the configuration-signing feature.
> 
> This series requires the 'trace' series since it sits on top of the bootm
> refactor there.
> 
> This series is available at:
> 
> http://git.denx.de/u-boot-x86.git
> 
> in the branch 'vboot'.
> 
> Changes in v3:
> - Fix 'compile' typo
> - Rebase to master
> - Use new fdt_first/next_subnode()
> 
> Changes in v2:
> - Add sanity checks on key sizes in RSA (improves security)
> - Adjust how signing enable works in image.h
> - Adjust mkimage help to separate out signing options
> - Avoid using malloc in RSA routines (for smaller SPL code size)
> - Build signing support unconditionally in mkimage
> - Fix FDT error handling in fit_image_write_sig()
> - Fix checkpatch checks about parenthesis alignment
> - Fix checkpatch warnings about split strings
> - Fix spelling of multiply in rsa-verify.c
> - Only build RSA support into mkimage if CONFIG_RSA is defined
> - Rebase on previous patches
> - Require CONFIG_FIT_SIGNATURE in image.h for mkimage to support signing
> - Support RSA library version without ERR_remove_thread_state()
> - Tweak tools/Makefile to make image signing optional
> - Update README to fix typos
> - Update README to fix typos and clarify some points
> - Use U-Boot's -c option instead of hard-coding a boot script
> - Use stack instead of calloc() within U-Boot's signature verification code
> - gd->fdt_blob is now available on all archs (generic board landed)
> 
> Simon Glass (12):
>   image: Add signing infrastructure
>   image: Support signing of images
>   image: Add RSA support for image signing
>   mkimage: Add -k option to specify key directory
>   mkimage: Add -K to write public keys to an FDT blob
>   mkimage: Add -F option to modify an existing .fit file
>   mkimage: Add -c option to specify a comment for key signing
>   mkimage: Add -r option to specify keys that must be verified
>   libfdt: Add fdt_find_regions()
>   image: Add support for signing of FIT configurations
>   sandbox: config: Enable FIT signatures with RSA
>   Add verified boot information and test
> 
>  Makefile                         |   1 +
>  README                           |  15 ++
>  common/Makefile                  |   1 +
>  common/image-fit.c               |  83 ++++--
>  common/image-sig.c               | 422 +++++++++++++++++++++++++++++++
>  config.mk                        |   1 +
>  doc/mkimage.1                    |  73 +++++-
>  doc/uImage.FIT/sign-configs.its  |  45 ++++
>  doc/uImage.FIT/sign-images.its   |  42 ++++
>  doc/uImage.FIT/signature.txt     | 382 ++++++++++++++++++++++++++++
>  doc/uImage.FIT/verified-boot.txt | 104 ++++++++
>  include/configs/sandbox.h        |   2 +
>  include/image.h                  | 165 +++++++++++-
>  include/libfdt.h                 |  64 +++++
>  include/rsa.h                    | 108 ++++++++
>  lib/libfdt/fdt_wip.c             | 129 ++++++++++
>  lib/rsa/Makefile                 |  48 ++++
>  lib/rsa/rsa-sign.c               | 460 ++++++++++++++++++++++++++++++++++
>  lib/rsa/rsa-verify.c             | 385 ++++++++++++++++++++++++++++
>  test/vboot/.gitignore            |   3 +
>  test/vboot/sandbox-kernel.dts    |   7 +
>  test/vboot/sandbox-u-boot.dts    |   7 +
>  test/vboot/sign-configs.its      |  45 ++++
>  test/vboot/sign-images.its       |  42 ++++
>  test/vboot/vboot_test.sh         | 126 ++++++++++
>  tools/Makefile                   |  19 +-
>  tools/fit_image.c                |  44 +++-
>  tools/image-host.c               | 527 ++++++++++++++++++++++++++++++++++++++-
>  tools/mkimage.c                  |  36 ++-
>  tools/mkimage.h                  |   4 +
>  30 files changed, 3333 insertions(+), 57 deletions(-)
>  create mode 100644 common/image-sig.c
>  create mode 100644 doc/uImage.FIT/sign-configs.its
>  create mode 100644 doc/uImage.FIT/sign-images.its
>  create mode 100644 doc/uImage.FIT/signature.txt
>  create mode 100644 doc/uImage.FIT/verified-boot.txt
>  create mode 100644 include/rsa.h
>  create mode 100644 lib/rsa/Makefile
>  create mode 100644 lib/rsa/rsa-sign.c
>  create mode 100644 lib/rsa/rsa-verify.c
>  create mode 100644 test/vboot/.gitignore
>  create mode 100644 test/vboot/sandbox-kernel.dts
>  create mode 100644 test/vboot/sandbox-u-boot.dts
>  create mode 100644 test/vboot/sign-configs.its
>  create mode 100644 test/vboot/sign-images.its
>  create mode 100755 test/vboot/vboot_test.sh

Applied to u-boot/master, thanks!

-- 
Tom

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

[-- Attachment #2: Type: text/plain, Size: 192 bytes --]

_______________________________________________
devicetree-discuss mailing list
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org
https://lists.ozlabs.org/listinfo/devicetree-discuss

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [U-Boot] [PATCH v3 0/12] Verified boot implementation based on FIT
@ 2013-06-26 20:24     ` Tom Rini
  0 siblings, 0 replies; 27+ messages in thread
From: Tom Rini @ 2013-06-26 20:24 UTC (permalink / raw)
  To: u-boot

On Thu, Jun 13, 2013 at 03:09:59PM -0700, Simon Glass wrote:

> This series implemented a verified boot system based around FIT images
> as discussed on the U-Boot mailing list, including on this thread:
> 
> http://permalink.gmane.org/gmane.comp.boot-loaders.u-boot/147830
> 
> RSA is used to implement the encryption. Images are signed by mkimage
> using private keys created by the user. Public keys are written into
> U-Boot control FDT (CONFIG_OF_CONTROL) for access by bootm etc. at
> run-time. The control FDT must be stored in a secure place where it
> cannot be changed after manufacture. Some notes are provided in the
> documentaion on how this can be achieved. The implementation is fairly
> efficient and fits nicely into U-Boot. FIT plus RSA adds around 18KB
> to SPL size which is manageable on modern SoCs.
> 
> When images are loaded, they are verified with the public keys.
> 
> It is important to have a test framework for this series. For this, sandbox
> is used, and a script is provided which signs images and gets sandbox to
> load them using a script, to check that all is well.
> 
> Rollback prevention has been added in a separate TPM patch. This ensures
> that an attacker cannot boot your system with an old image that has been
> compromised. Support for this is not built into bootm, but instead must
> be scripted in U-Boot. It is possible that a standard scheme for this could
> be devised by adding version number tags to the signing procedure. However
> scripts do provide more flexibility. See the 'tpm' command for more
> information.
> 
> Two patches affect libfdt and have material which is not yet upstream in
> that project:
> 
>    image: Add support for signing of FIT configurations
>    libfdt: Add fdt_find_regions()
> 
> If these are not desired, then the rest of the series can stand alone,
> just without the configuration-signing feature.
> 
> This series requires the 'trace' series since it sits on top of the bootm
> refactor there.
> 
> This series is available at:
> 
> http://git.denx.de/u-boot-x86.git
> 
> in the branch 'vboot'.
> 
> Changes in v3:
> - Fix 'compile' typo
> - Rebase to master
> - Use new fdt_first/next_subnode()
> 
> Changes in v2:
> - Add sanity checks on key sizes in RSA (improves security)
> - Adjust how signing enable works in image.h
> - Adjust mkimage help to separate out signing options
> - Avoid using malloc in RSA routines (for smaller SPL code size)
> - Build signing support unconditionally in mkimage
> - Fix FDT error handling in fit_image_write_sig()
> - Fix checkpatch checks about parenthesis alignment
> - Fix checkpatch warnings about split strings
> - Fix spelling of multiply in rsa-verify.c
> - Only build RSA support into mkimage if CONFIG_RSA is defined
> - Rebase on previous patches
> - Require CONFIG_FIT_SIGNATURE in image.h for mkimage to support signing
> - Support RSA library version without ERR_remove_thread_state()
> - Tweak tools/Makefile to make image signing optional
> - Update README to fix typos
> - Update README to fix typos and clarify some points
> - Use U-Boot's -c option instead of hard-coding a boot script
> - Use stack instead of calloc() within U-Boot's signature verification code
> - gd->fdt_blob is now available on all archs (generic board landed)
> 
> Simon Glass (12):
>   image: Add signing infrastructure
>   image: Support signing of images
>   image: Add RSA support for image signing
>   mkimage: Add -k option to specify key directory
>   mkimage: Add -K to write public keys to an FDT blob
>   mkimage: Add -F option to modify an existing .fit file
>   mkimage: Add -c option to specify a comment for key signing
>   mkimage: Add -r option to specify keys that must be verified
>   libfdt: Add fdt_find_regions()
>   image: Add support for signing of FIT configurations
>   sandbox: config: Enable FIT signatures with RSA
>   Add verified boot information and test
> 
>  Makefile                         |   1 +
>  README                           |  15 ++
>  common/Makefile                  |   1 +
>  common/image-fit.c               |  83 ++++--
>  common/image-sig.c               | 422 +++++++++++++++++++++++++++++++
>  config.mk                        |   1 +
>  doc/mkimage.1                    |  73 +++++-
>  doc/uImage.FIT/sign-configs.its  |  45 ++++
>  doc/uImage.FIT/sign-images.its   |  42 ++++
>  doc/uImage.FIT/signature.txt     | 382 ++++++++++++++++++++++++++++
>  doc/uImage.FIT/verified-boot.txt | 104 ++++++++
>  include/configs/sandbox.h        |   2 +
>  include/image.h                  | 165 +++++++++++-
>  include/libfdt.h                 |  64 +++++
>  include/rsa.h                    | 108 ++++++++
>  lib/libfdt/fdt_wip.c             | 129 ++++++++++
>  lib/rsa/Makefile                 |  48 ++++
>  lib/rsa/rsa-sign.c               | 460 ++++++++++++++++++++++++++++++++++
>  lib/rsa/rsa-verify.c             | 385 ++++++++++++++++++++++++++++
>  test/vboot/.gitignore            |   3 +
>  test/vboot/sandbox-kernel.dts    |   7 +
>  test/vboot/sandbox-u-boot.dts    |   7 +
>  test/vboot/sign-configs.its      |  45 ++++
>  test/vboot/sign-images.its       |  42 ++++
>  test/vboot/vboot_test.sh         | 126 ++++++++++
>  tools/Makefile                   |  19 +-
>  tools/fit_image.c                |  44 +++-
>  tools/image-host.c               | 527 ++++++++++++++++++++++++++++++++++++++-
>  tools/mkimage.c                  |  36 ++-
>  tools/mkimage.h                  |   4 +
>  30 files changed, 3333 insertions(+), 57 deletions(-)
>  create mode 100644 common/image-sig.c
>  create mode 100644 doc/uImage.FIT/sign-configs.its
>  create mode 100644 doc/uImage.FIT/sign-images.its
>  create mode 100644 doc/uImage.FIT/signature.txt
>  create mode 100644 doc/uImage.FIT/verified-boot.txt
>  create mode 100644 include/rsa.h
>  create mode 100644 lib/rsa/Makefile
>  create mode 100644 lib/rsa/rsa-sign.c
>  create mode 100644 lib/rsa/rsa-verify.c
>  create mode 100644 test/vboot/.gitignore
>  create mode 100644 test/vboot/sandbox-kernel.dts
>  create mode 100644 test/vboot/sandbox-u-boot.dts
>  create mode 100644 test/vboot/sign-configs.its
>  create mode 100644 test/vboot/sign-images.its
>  create mode 100755 test/vboot/vboot_test.sh

Applied to u-boot/master, thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20130626/a15a5544/attachment.pgp>

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [U-Boot] [PATCH v3 03/12] image: Add RSA support for image signing
  2013-06-13 22:10 ` [U-Boot] [PATCH v3 03/12] image: Add RSA support for image signing Simon Glass
@ 2013-06-27  4:08   ` Masahiro Yamada
  2013-06-27  6:44     ` Simon Glass
  0 siblings, 1 reply; 27+ messages in thread
From: Masahiro Yamada @ 2013-06-27  4:08 UTC (permalink / raw)
  To: u-boot

Hello, Simon.


When compiling the master branch,
I got an error while a tools/mkimage build. 


u-boot/lib/rsa/rsa-sign.c:26:25: fatal error: openssl/rsa.h: No such
file or directory


I think this erorr is caused by commit 19c402a.


I searched and installed the necessary package and
I could resolve this error.

$ apt-file search openssl/rsa.h
libssl-dev: /usr/include/openssl/rsa.h
$ sudo apt-get install libssl-dev


Let me ask a question.

Going forward do we always need the openssl development package
for creating mkimage tool?
Or is it possible to disable RSA feature by some CONFIG option?


Best Regards
Masahiro Yamada

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [U-Boot] [PATCH v3 03/12] image: Add RSA support for image signing
  2013-06-27  4:08   ` Masahiro Yamada
@ 2013-06-27  6:44     ` Simon Glass
  2013-06-27 12:50       ` Tom Rini
  0 siblings, 1 reply; 27+ messages in thread
From: Simon Glass @ 2013-06-27  6:44 UTC (permalink / raw)
  To: u-boot

Hi Masahiro,

On Wed, Jun 26, 2013 at 9:08 PM, Masahiro Yamada
<yamada.m@jp.panasonic.com>wrote:

> Hello, Simon.
>
>
> When compiling the master branch,
> I got an error while a tools/mkimage build.
>
>
> u-boot/lib/rsa/rsa-sign.c:26:25: fatal error: openssl/rsa.h: No such
> file or directory
>
>
> I think this erorr is caused by commit 19c402a.
>
>
> I searched and installed the necessary package and
> I could resolve this error.
>
> $ apt-file search openssl/rsa.h
> libssl-dev: /usr/include/openssl/rsa.h
> $ sudo apt-get install libssl-dev
>
>
> Let me ask a question.
>
> Going forward do we always need the openssl development package
> for creating mkimage tool?
> Or is it possible to disable RSA feature by some CONFIG option?
>

This is to support verified boot using FIT. Yes it would be possible to
make it an option. I had it that way for a while, but then I worried that
it would create two versions of mkimage, one of which is incapable of
signing images. That means that mkimage would need to be built for a board
with verified boot enabled in order to get full functionality.

Perhaps another way would be to check for the header and (if not present),
silently build without signing support?

Regards,
Simon


>
>
> Best Regards
> Masahiro Yamada
>
>

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [U-Boot] [PATCH v3 03/12] image: Add RSA support for image signing
  2013-06-27  6:44     ` Simon Glass
@ 2013-06-27 12:50       ` Tom Rini
  2013-06-27 15:45         ` Simon Glass
  0 siblings, 1 reply; 27+ messages in thread
From: Tom Rini @ 2013-06-27 12:50 UTC (permalink / raw)
  To: u-boot

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 06/27/2013 02:44 AM, Simon Glass wrote:
> Hi Masahiro,
> 
> On Wed, Jun 26, 2013 at 9:08 PM, Masahiro Yamada 
> <yamada.m at jp.panasonic.com <mailto:yamada.m@jp.panasonic.com>> 
> wrote:
> 
> Hello, Simon.
> 
> 
> When compiling the master branch, I got an error while a 
> tools/mkimage build.
> 
> 
> u-boot/lib/rsa/rsa-sign.c:26:25: fatal error: openssl/rsa.h: No 
> such file or directory
> 
> 
> I think this erorr is caused by commit 19c402a.
> 
> 
> I searched and installed the necessary package and I could resolve 
> this error.
> 
> $ apt-file search openssl/rsa.h libssl-dev: 
> /usr/include/openssl/rsa.h $ sudo apt-get install libssl-dev
> 
> 
> Let me ask a question.
> 
> Going forward do we always need the openssl development package
> for creating mkimage tool? Or is it possible to disable RSA feature
> by some CONFIG option?
> 
> 
> This is to support verified boot using FIT. Yes it would be 
> possible to make it an option. I had it that way for a while, but 
> then I worried that it would create two versions of mkimage, one
> of which is incapable of signing images. That means that mkimage
> would need to be built for a board with verified boot enabled in
> order to get full functionality.
> 
> Perhaps another way would be to check for the header and (if not 
> present), silently build without signing support?

Hurk, dang it.. Yes, I think we need to build and go with an error
message on attempted use.  Skimming the code, we can't rely on
CONFIG_FIT_SIGNATURE being inherited from the config, on the host
side, yes?

- -- 
Tom
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/

iQIcBAEBAgAGBQJRzDUoAAoJENk4IS6UOR1WOF8P/in1joGCy0NcOJ3g3PKRRi5Y
eUgwTbOaQ3x82dJ3820YEkxSpaJIxiw+l0cvbWVH9TR6wO/7EiVjNLmFwauhuVBU
BAf9ghleHjd3T6utxEzDk0z9O2E9f8aliSQ1d31oK1NrM/IvhW06udv6V0shFRCN
i3uD4bkWPgv+qChZ+94ma4rc3SDz393lG2dwn0L9TZ/Kv3qOaoEr1qTDSS2fRXqg
2Yd1vFD3mT9ZEMQwfteoThuXWZfyWFYfh9wsUjwjHonJNauwKkZgWFHnZpYCv6tJ
TQEOH7pVpO7RAMFw/7f/tXdk/U2Qnmq/GH0Gy/p9E7UYb4IqXNGrXBOjhEGizH+c
gA4bAxjooHoVayUf/m3m6g5WUd1uv6cKhcS5WppmaduPdPncB8wPKxksT/ti1NKi
4yDdFLsudPvO+0R94MT+5dgV4Album8aoICmSgzxRy+3x9lGGxEGHeCleDtwnLTR
dQEnmUEweKvwL1MNJZ6TBtqekbf/hKVbgn4EqEi0fb4CLKCVFOGT3YSu8oWDaZEQ
q0C08/hn6lNgbGqTQL83I0lahp2HiPjHZMvUVVcE0lzOIowkTLLxvsZLfLhlCdXv
LxG26Pi0rG/CU8BnYQ/W00X4HPi20UDOt9nLyINq63ctKLWKMMA3B7IkcpBGbT2U
dA8uceK04MStQdxiB3kh
=wI1Q
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [U-Boot] [PATCH v3 03/12] image: Add RSA support for image signing
  2013-06-27 12:50       ` Tom Rini
@ 2013-06-27 15:45         ` Simon Glass
  2013-06-27 15:48           ` Tom Rini
  0 siblings, 1 reply; 27+ messages in thread
From: Simon Glass @ 2013-06-27 15:45 UTC (permalink / raw)
  To: u-boot

Hi Tom,

On Thu, Jun 27, 2013 at 5:50 AM, Tom Rini <trini@ti.com> wrote:

> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> On 06/27/2013 02:44 AM, Simon Glass wrote:
> > Hi Masahiro,
> >
> > On Wed, Jun 26, 2013 at 9:08 PM, Masahiro Yamada
> > <yamada.m at jp.panasonic.com <mailto:yamada.m@jp.panasonic.com>>
> > wrote:
> >
> > Hello, Simon.
> >
> >
> > When compiling the master branch, I got an error while a
> > tools/mkimage build.
> >
> >
> > u-boot/lib/rsa/rsa-sign.c:26:25: fatal error: openssl/rsa.h: No
> > such file or directory
> >
> >
> > I think this erorr is caused by commit 19c402a.
> >
> >
> > I searched and installed the necessary package and I could resolve
> > this error.
> >
> > $ apt-file search openssl/rsa.h libssl-dev:
> > /usr/include/openssl/rsa.h $ sudo apt-get install libssl-dev
> >
> >
> > Let me ask a question.
> >
> > Going forward do we always need the openssl development package
> > for creating mkimage tool? Or is it possible to disable RSA feature
> > by some CONFIG option?
> >
> >
> > This is to support verified boot using FIT. Yes it would be
> > possible to make it an option. I had it that way for a while, but
> > then I worried that it would create two versions of mkimage, one
> > of which is incapable of signing images. That means that mkimage
> > would need to be built for a board with verified boot enabled in
> > order to get full functionality.
> >
> > Perhaps another way would be to check for the header and (if not
> > present), silently build without signing support?
>
> Hurk, dang it.. Yes, I think we need to build and go with an error
> message on attempted use.  Skimming the code, we can't rely on
> CONFIG_FIT_SIGNATURE being inherited from the config, on the host
> side, yes?
>

Yes I can make this check CONFIG_FIT_SIGNATURE - as mentioned I had it that
way originally but worred about creating different versions of mkimage.

There is actually code there for this which we can use:

#ifdef CONFIG_FIT_SIGNATURE
fprintf(stderr, "Signing / verified boot options: [-k keydir] [-K dtb] [ -c
<comment>] [-r]\n"
"          -k => set directory containing private keys\n"
"          -K => write public keys to this .dtb file\n"
"          -c => add comment in signature node\n"
"          -F => re-sign existing FIT image\n"
"          -r => mark keys used as 'required' in dtb\n");
#else
fprintf(stderr, "Signing / verified boot not supported
(CONFIG_FIT_SIGNATURE undefined)\n");
#endif

Let me know if this is the preferred option and I will prepare a patch.

Regards,
Simon

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [U-Boot] [PATCH v3 03/12] image: Add RSA support for image signing
  2013-06-27 15:45         ` Simon Glass
@ 2013-06-27 15:48           ` Tom Rini
  2013-06-27 17:04             ` Simon Glass
  0 siblings, 1 reply; 27+ messages in thread
From: Tom Rini @ 2013-06-27 15:48 UTC (permalink / raw)
  To: u-boot

On Thu, Jun 27, 2013 at 08:45:34AM -0700, Simon Glass wrote:
> Hi Tom,
> 
> On Thu, Jun 27, 2013 at 5:50 AM, Tom Rini <trini@ti.com> wrote:
> 
> > -----BEGIN PGP SIGNED MESSAGE-----
> > Hash: SHA1
> >
> > On 06/27/2013 02:44 AM, Simon Glass wrote:
> > > Hi Masahiro,
> > >
> > > On Wed, Jun 26, 2013 at 9:08 PM, Masahiro Yamada
> > > <yamada.m at jp.panasonic.com <mailto:yamada.m@jp.panasonic.com>>
> > > wrote:
> > >
> > > Hello, Simon.
> > >
> > >
> > > When compiling the master branch, I got an error while a
> > > tools/mkimage build.
> > >
> > >
> > > u-boot/lib/rsa/rsa-sign.c:26:25: fatal error: openssl/rsa.h: No
> > > such file or directory
> > >
> > >
> > > I think this erorr is caused by commit 19c402a.
> > >
> > >
> > > I searched and installed the necessary package and I could resolve
> > > this error.
> > >
> > > $ apt-file search openssl/rsa.h libssl-dev:
> > > /usr/include/openssl/rsa.h $ sudo apt-get install libssl-dev
> > >
> > >
> > > Let me ask a question.
> > >
> > > Going forward do we always need the openssl development package
> > > for creating mkimage tool? Or is it possible to disable RSA feature
> > > by some CONFIG option?
> > >
> > >
> > > This is to support verified boot using FIT. Yes it would be
> > > possible to make it an option. I had it that way for a while, but
> > > then I worried that it would create two versions of mkimage, one
> > > of which is incapable of signing images. That means that mkimage
> > > would need to be built for a board with verified boot enabled in
> > > order to get full functionality.
> > >
> > > Perhaps another way would be to check for the header and (if not
> > > present), silently build without signing support?
> >
> > Hurk, dang it.. Yes, I think we need to build and go with an error
> > message on attempted use.  Skimming the code, we can't rely on
> > CONFIG_FIT_SIGNATURE being inherited from the config, on the host
> > side, yes?
> >
> 
> Yes I can make this check CONFIG_FIT_SIGNATURE - as mentioned I had it that
> way originally but worred about creating different versions of mkimage.
> 
> There is actually code there for this which we can use:
> 
> #ifdef CONFIG_FIT_SIGNATURE
> fprintf(stderr, "Signing / verified boot options: [-k keydir] [-K dtb] [ -c
> <comment>] [-r]\n"
> "          -k => set directory containing private keys\n"
> "          -K => write public keys to this .dtb file\n"
> "          -c => add comment in signature node\n"
> "          -F => re-sign existing FIT image\n"
> "          -r => mark keys used as 'required' in dtb\n");
> #else
> fprintf(stderr, "Signing / verified boot not supported
> (CONFIG_FIT_SIGNATURE undefined)\n");
> #endif
> 
> Let me know if this is the preferred option and I will prepare a patch.

The Makefile fragments I saw implied we couldn't use this approach on
the host.  But if we can, lets.

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20130627/b1dfbf7f/attachment.pgp>

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [U-Boot] [PATCH v3 03/12] image: Add RSA support for image signing
  2013-06-27 15:48           ` Tom Rini
@ 2013-06-27 17:04             ` Simon Glass
  0 siblings, 0 replies; 27+ messages in thread
From: Simon Glass @ 2013-06-27 17:04 UTC (permalink / raw)
  To: u-boot

Hi Tom,

On Thu, Jun 27, 2013 at 8:48 AM, Tom Rini <trini@ti.com> wrote:

> On Thu, Jun 27, 2013 at 08:45:34AM -0700, Simon Glass wrote:
> > Hi Tom,
> >
> > On Thu, Jun 27, 2013 at 5:50 AM, Tom Rini <trini@ti.com> wrote:
> >
> > > -----BEGIN PGP SIGNED MESSAGE-----
> > > Hash: SHA1
> > >
> > > On 06/27/2013 02:44 AM, Simon Glass wrote:
> > > > Hi Masahiro,
> > > >
> > > > On Wed, Jun 26, 2013 at 9:08 PM, Masahiro Yamada
> > > > <yamada.m at jp.panasonic.com <mailto:yamada.m@jp.panasonic.com>>
> > > > wrote:
> > > >
> > > > Hello, Simon.
> > > >
> > > >
> > > > When compiling the master branch, I got an error while a
> > > > tools/mkimage build.
> > > >
> > > >
> > > > u-boot/lib/rsa/rsa-sign.c:26:25: fatal error: openssl/rsa.h: No
> > > > such file or directory
> > > >
> > > >
> > > > I think this erorr is caused by commit 19c402a.
> > > >
> > > >
> > > > I searched and installed the necessary package and I could resolve
> > > > this error.
> > > >
> > > > $ apt-file search openssl/rsa.h libssl-dev:
> > > > /usr/include/openssl/rsa.h $ sudo apt-get install libssl-dev
> > > >
> > > >
> > > > Let me ask a question.
> > > >
> > > > Going forward do we always need the openssl development package
> > > > for creating mkimage tool? Or is it possible to disable RSA feature
> > > > by some CONFIG option?
> > > >
> > > >
> > > > This is to support verified boot using FIT. Yes it would be
> > > > possible to make it an option. I had it that way for a while, but
> > > > then I worried that it would create two versions of mkimage, one
> > > > of which is incapable of signing images. That means that mkimage
> > > > would need to be built for a board with verified boot enabled in
> > > > order to get full functionality.
> > > >
> > > > Perhaps another way would be to check for the header and (if not
> > > > present), silently build without signing support?
> > >
> > > Hurk, dang it.. Yes, I think we need to build and go with an error
> > > message on attempted use.  Skimming the code, we can't rely on
> > > CONFIG_FIT_SIGNATURE being inherited from the config, on the host
> > > side, yes?
> > >
> >
> > Yes I can make this check CONFIG_FIT_SIGNATURE - as mentioned I had it
> that
> > way originally but worred about creating different versions of mkimage.
> >
> > There is actually code there for this which we can use:
> >
> > #ifdef CONFIG_FIT_SIGNATURE
> > fprintf(stderr, "Signing / verified boot options: [-k keydir] [-K dtb] [
> -c
> > <comment>] [-r]\n"
> > "          -k => set directory containing private keys\n"
> > "          -K => write public keys to this .dtb file\n"
> > "          -c => add comment in signature node\n"
> > "          -F => re-sign existing FIT image\n"
> > "          -r => mark keys used as 'required' in dtb\n");
> > #else
> > fprintf(stderr, "Signing / verified boot not supported
> > (CONFIG_FIT_SIGNATURE undefined)\n");
> > #endif
> >
> > Let me know if this is the preferred option and I will prepare a patch.
>
> The Makefile fragments I saw implied we couldn't use this approach on
> the host.  But if we can, lets.
>

That still seems to work OK. Will send a patch.

Regards,
Simon

^ permalink raw reply	[flat|nested] 27+ messages in thread

end of thread, other threads:[~2013-06-27 17:04 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-06-13 22:09 [PATCH v3 0/12] Verified boot implementation based on FIT Simon Glass
2013-06-13 22:09 ` [U-Boot] " Simon Glass
2013-06-13 22:10 ` [U-Boot] [PATCH v3 01/12] image: Add signing infrastructure Simon Glass
2013-06-13 22:10 ` [U-Boot] [PATCH v3 02/12] image: Support signing of images Simon Glass
2013-06-13 22:10 ` [U-Boot] [PATCH v3 03/12] image: Add RSA support for image signing Simon Glass
2013-06-27  4:08   ` Masahiro Yamada
2013-06-27  6:44     ` Simon Glass
2013-06-27 12:50       ` Tom Rini
2013-06-27 15:45         ` Simon Glass
2013-06-27 15:48           ` Tom Rini
2013-06-27 17:04             ` Simon Glass
2013-06-13 22:10 ` [U-Boot] [PATCH v3 04/12] mkimage: Add -k option to specify key directory Simon Glass
2013-06-13 22:10 ` [U-Boot] [PATCH v3 05/12] mkimage: Add -K to write public keys to an FDT blob Simon Glass
2013-06-13 22:10 ` [U-Boot] [PATCH v3 06/12] mkimage: Add -F option to modify an existing .fit file Simon Glass
2013-06-13 22:10 ` [U-Boot] [PATCH v3 07/12] mkimage: Add -c option to specify a comment for key signing Simon Glass
2013-06-13 22:10 ` [U-Boot] [PATCH v3 08/12] mkimage: Add -r option to specify keys that must be verified Simon Glass
     [not found] ` <1371161411-2834-1-git-send-email-sjg-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
2013-06-13 22:10   ` [PATCH v3 09/12] libfdt: Add fdt_find_regions() Simon Glass
2013-06-13 22:10     ` [U-Boot] " Simon Glass
2013-06-26 20:24   ` [U-Boot] [PATCH v3 0/12] Verified boot implementation based on FIT Tom Rini
2013-06-26 20:24     ` Tom Rini
2013-06-13 22:10 ` [U-Boot] [PATCH v3 10/12] image: Add support for signing of FIT configurations Simon Glass
2013-06-13 22:10 ` [U-Boot] [PATCH v3 11/12] sandbox: config: Enable FIT signatures with RSA Simon Glass
2013-06-13 22:10 ` [U-Boot] [PATCH v3 12/12] Add verified boot information and test Simon Glass
2013-06-13 22:33   ` Simon Glass
2013-06-20 16:07     ` Tom Rini
2013-06-20 16:18       ` Simon Glass
2013-06-20 20:55       ` Simon Glass

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.