mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-10 07:04:28 +00:00
image: Add signing infrastructure
Add a structure to describe an algorithm which can sign and (later) verify images. Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
parent
b5f3193734
commit
3e569a6b1e
6 changed files with 358 additions and 2 deletions
5
README
5
README
|
@ -2805,6 +2805,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
|
||||
|
||||
|
|
|
@ -243,6 +243,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
|
||||
|
||||
|
|
42
common/image-sig.c
Normal file
42
common/image-sig.c
Normal file
|
@ -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;
|
||||
}
|
216
doc/uImage.FIT/signature.txt
Normal file
216
doc/uImage.FIT/signature.txt
Normal file
|
@ -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@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@chromium.org
|
||||
1-1-13
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
@ -154,6 +155,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))
|
||||
|
||||
|
@ -213,6 +218,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 \
|
||||
|
|
Loading…
Reference in a new issue