[U-Boot-Users] Secure Bootloader patch

This message contains a patch to add RSA signature validation to U-Boot. I previously sent a similar e-mail to the CELinux-dev mailing list for comments where I received the following:
1. I shouldn't be using OpenSSL (due to licensing concerns), 2. alternate RSA libraries are GNU TLS and MatrixSSL, and 3. the U-Boot mailing list might be a more appropriate place
The patch modifies u-boot to verify an image signature created with a SHA1 digest and RSA encryption/decryption. Because I found the necessary information fairly easily about SHA1 and RSA from the OpenSSL package, that's what I used. Hence, the modified u-boot ran quite quickly, but was rather large. The eventual goal is to release this patch to the community.
I'm looking for additional comments, especially about other encryption libraries that would be better to use, and whether or not something like this is seen as useful.
Notes: - I'm linking against openssl-0.9.8b. - I used crosstool based on gcc-3.4.5 and glibc-2.3.6 for the tool chain. - It all was built for an omap5912osk board. - The signature is added to the u-boot header by a modified mkimage (patch is included). - The signature is verified in cmd_bootm.c. - In u-boot/include/configs/omap5912osk.h there is a CONFIG_SIGNATURE that turns on/off the signature checking and creating.
To compile the modified u-boot the following were needed:
CPATH should be defined to point to where ever crosstool has it's generic include files, e.g. export CPATH="/opt/crosstool/gcc-3.4.5-glibc-2.3.6/arm-softfloat-linux-gnu/arm-softfloat-linux-gnu/include"
CRYPTO_INC needs to point at the openssl include files, e.g. export CRYPTO_INC="-I/home/steve/src/SecureBoot/openssl-0.9.8b/include"
CRYPTO_LIBS needs to point the the openssl libraries, e.g. export CRYPTO_LIBS="-L /home/steve/src/SecureBoot/openssl-0.9.8b -lssl -lcrypto -lm -lc"
If anyone has any problems or even better, suggestions, don't hesitate to let me know.
Best regards, Steve
=========================================
diff -Naur u-boot.orig/common/cmd_bootm.c u-boot/common/cmd_bootm.c --- u-boot.orig/common/cmd_bootm.c 2006-05-10 11:43:20.000000000 -0400 +++ u-boot/common/cmd_bootm.c 2006-06-12 10:35:57.000000000 -0400 @@ -79,6 +79,12 @@ # define CHUNKSZ (64 * 1024) #endif
+#ifdef CONFIG_SIGNATURE +extern int verify_signature (const unsigned char *signature, + const unsigned char *buf, + unsigned int len); +#endif /* CONFIG_SIGNATURE */ + int gunzip (void *, int, unsigned char *, unsigned long *);
static void *zalloc(void *, unsigned, unsigned); @@ -238,6 +244,19 @@ } puts ("OK\n"); } + +#ifdef CONFIG_SIGNATURE + puts (" Verifying Signature ... "); + if (verify_signature(hdr->ih_sign, + (const unsigned char *)data, + len) == 0) { + puts("Invalid image signature\n"); + SHOW_BOOT_PROGRESS(-3); + return 1; + } + puts ("OK\n"); +#endif /* CONFIG_SIGNATURE */ + SHOW_BOOT_PROGRESS (4);
len_ptr = (ulong *)data; diff -Naur u-boot.orig/config.mk u-boot/config.mk --- u-boot.orig/config.mk 2006-05-10 11:43:20.000000000 -0400 +++ u-boot/config.mk 2006-06-08 09:41:17.000000000 -0400 @@ -126,7 +126,7 @@ -D__KERNEL__ -DTEXT_BASE=$(TEXT_BASE) \ -I$(TOPDIR)/include \ -fno-builtin -ffreestanding -nostdinc -isystem \ - $(gccincdir) -pipe $(PLATFORM_CPPFLAGS) + $(gccincdir) -pipe $(PLATFORM_CPPFLAGS) $(CRYPTO_INC)
ifdef BUILD_TAG CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes \ diff -Naur u-boot.orig/include/configs/omap5912osk.h u-boot/include/configs/omap5912osk.h --- u-boot.orig/include/configs/omap5912osk.h 2006-05-10 11:43:20.000000000 -0400 +++ u-boot/include/configs/omap5912osk.h 2006-06-08 15:34:00.000000000 -0400 @@ -38,6 +38,8 @@ #define CONFIG_DISPLAY_CPUINFO 1 /* display cpu info (and speed) */ #define CONFIG_DISPLAY_BOARDINFO 1 /* display board info */
+#define CONFIG_SIGNATURE 1 + /* input clock of PLL */ /* the OMAP5912 OSK has 12MHz input clock */ #define CONFIG_SYS_CLK_FREQ 12000000 @@ -112,7 +122,11 @@ */ #define CFG_LONGHELP /* undef to save memory */ #define CFG_PROMPT "OMAP5912 OSK # " /* Monitor Command Prompt */ +#ifdef CONFIG_SIGNATURE +#define CFG_CBSIZE 512 /* Console I/O Buffer Size */ +#else #define CFG_CBSIZE 256 /* Console I/O Buffer Size */ +#endif /* Print Buffer Size */ #define CFG_PBSIZE (CFG_CBSIZE+sizeof(CFG_PROMPT)+16) #define CFG_MAXARGS 16 /* max number of command args */ @@ -183,9 +197,9 @@ */ #define CFG_ENV_IS_IN_FLASH 1 /* addr of environment */ -#define CFG_ENV_ADDR (CFG_FLASH_BASE + 0x020000) +#define CFG_ENV_ADDR (CFG_FLASH_BASE + 0x0E0000)
#define CFG_ENV_SIZE 0x20000 /* Total Size of Environment Sector */ -#define CFG_ENV_OFFSET 0x20000 /* environment starts here */ +#define CFG_ENV_OFFSET 0xE0000 /* environment starts here */
#endif /* __CONFIG_H */ diff -Naur u-boot.orig/include/image.h u-boot/include/image.h --- u-boot.orig/include/image.h 2006-05-10 11:43:20.000000000 -0400 +++ u-boot/include/image.h 2006-06-08 09:09:09.000000000 -0400 @@ -134,6 +134,9 @@
#define IH_MAGIC 0x27051956 /* Image Magic Number */ #define IH_NMLEN 32 /* Image Name Length */ +#ifdef CONFIG_SIGNATURE +#define IH_SIGN 256 /* Image Signature Length */ +#endif /* CONFIG_SIGNATURE */
/* * all data in network byte order (aka natural aka bigendian) @@ -152,6 +155,9 @@ uint8_t ih_type; /* Image Type */ uint8_t ih_comp; /* Compression Type */ uint8_t ih_name[IH_NMLEN]; /* Image Name */ +#ifdef CONFIG_SIGNATURE + uint8_t ih_sign[IH_SIGN]; /* Image Signature */ +#endif /* CONFIG_SIGNATURE */ } image_header_t;
diff -Naur u-boot.orig/lib_crypto/Makefile u-boot/lib_crypto/Makefile --- u-boot.orig/lib_crypto/Makefile 1969-12-31 19:00:00.000000000 -0500 +++ u-boot/lib_crypto/Makefile 2006-06-08 10:17:56.000000000 -0400 @@ -0,0 +1,40 @@ +# +# (C) Copyright 2000-2002 +# Wolfgang Denk, DENX Software Engineering, wd@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 = libcrypto.a + +OBJS = signature.o + +$(LIB): .depend $(OBJS) + $(AR) crv $@ $(OBJS) + +######################################################################### + +.depend: Makefile $(OBJS:.o=.c) + $(CC) -M $(CFLAGS) $(CRYPTO_INC) $(OBJS:.o=.c) > $@ + +sinclude .depend + +######################################################################### diff -Naur u-boot.orig/lib_crypto/signature.c u-boot/lib_crypto/signature.c --- u-boot.orig/lib_crypto/signature.c 1969-12-31 19:00:00.000000000 -0500 +++ u-boot/lib_crypto/signature.c 2006-06-12 10:41:51.000000000 -0400 @@ -0,0 +1,121 @@ +#include <stdio.h> + +#include <openssl/ssl.h> +#include <openssl/rsa.h> +#include <openssl/err.h> +#include <openssl/pem.h> +#include <openssl/sha.h> +#include <openssl/bio.h> + +#define IH_SIGN 256 + +unsigned char key_string[] = "-----BEGIN PUBLIC KEY-----\n\ +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6IgnrRN+ER3GG/ZNDQk/\n\ +JByf09bYPgHfERJdHUb8p+6wM7cb7RvoxyVyaFQFA7RKErr6kvzjIKz/tyDnKKzK\n\ +0kAE0vE5prSUDxhoExM9YBAAjc6TAQ0kKjerIwZx5iT9vYV7YSpG5U7Sycw2NrjP\n\ +dMS2X8v1pHZSSgQAYPs3zGlC+oyMebd7vpsFKihc2vr2J0PXdD1Owh8gEIiZjm5o\n\ +eXL93BGFUVMZa040YUvTn9627eEg6hJJqmRZ4Myx90585J/2Jmhztv2U2t2Rl2T9\n\ +mentqOvFO0QhhadniRgDzhsLM6wbpwOqlRROcVGnkqmFckLKlLWqYbzoZOJs4xO3\n\ +oQIDAQAB\n\ +-----END PUBLIC KEY-----\n"; + + +void SSL_load_error_strings(void); + +static void err_msg(void); +static RSA *load_key(void) ; +static RSA *get_public_key(char *key_string); + +/* + ========================================================================= +*/ + +static void +err_msg(void) +{ + char err_buff[1024]; + unsigned long err; + + SSL_load_error_strings(); + + while ((err = ERR_get_error())) { + ERR_error_string_n(err, err_buff, sizeof(err_buff)); + fprintf(stderr, "%s\n", err_buff); + } + + ERR_free_strings(); +} + + +int +verify_signature(const unsigned char *signature, + const unsigned char *buf, + unsigned int len) +{ + RSA *public_key; + unsigned char digest[SHA_DIGEST_LENGTH]; + int res; + int i; + + /* Do SHA1 encryption of buffer */ + (void)SHA1(buf, len, digest); + + /* Load public key */ + if ((public_key = load_key()) == NULL) { + return 0; + } + + /* verify digest */ + res = RSA_verify(NID_sha1, + digest, SHA_DIGEST_LENGTH, + signature, IH_SIGN, + public_key); + + /* Clean up */ + RSA_free(public_key); + + return res; +} + + +static RSA * +load_key(void) +{ + RSA *key; + char *key_string; + + key = get_public_key(key_string); + + return key; +} + + +static RSA * +get_public_key(char *key_string) +{ + RSA *key; + int res; + BIO *bp; + + /* Load public key from string */ + bp = BIO_new_mem_buf(key_string, -1); + if (bp == NULL) { + err_msg(); + return NULL; + } + + /* Convert string to internal key */ + key = PEM_read_bio_RSA_PUBKEY(bp, NULL, NULL, NULL); + if (key == NULL) { + err_msg(); + return NULL; + } + + res = BIO_free(bp); + if (res == 0) { + err_msg(); + return NULL; + } + + return key; +} diff -Naur u-boot.orig/Makefile u-boot/Makefile --- u-boot.orig/Makefile 2006-05-10 11:43:20.000000000 -0400 +++ u-boot/Makefile 2006-06-08 08:55:24.000000000 -0400 @@ -120,6 +120,7 @@ endif
LIBS = lib_generic/libgeneric.a +LIBS += lib_crypto/libcrypto.a LIBS += board/$(BOARDDIR)/lib$(BOARD).a LIBS += cpu/$(CPU)/lib$(CPU).a ifdef SOC @@ -144,7 +145,6 @@ # Add GCC lib PLATFORM_LIBS += -L $(shell dirname `$(CC) $(CFLAGS) -print-libgcc-file-name`) -lgcc
- # The "tools" are needed early, so put this first # Don't include stuff already done in $(LIBS) SUBDIRS = tools \ @@ -182,7 +182,7 @@ u-boot: depend version $(SUBDIRS) $(OBJS) $(LIBS) $(LDSCRIPT) UNDEF_SYM=`$(OBJDUMP) -x $(LIBS) |sed -n -e 's/.*(__u_boot_cmd_.*)/-u\1/p'|sort|uniq`;\ $(LD) $(LDFLAGS) $$UNDEF_SYM $(OBJS) \ - --start-group $(LIBS) --end-group $(PLATFORM_LIBS) \ + --start-group $(LIBS) --end-group $(CRYPTO_LIBS) $(PLATFORM_LIBS) \ -Map u-boot.map -o u-boot
$(LIBS): @@ -206,14 +206,14 @@
tags: ctags -w `find $(SUBDIRS) include \ - lib_generic board/$(BOARDDIR) cpu/$(CPU) lib_$(ARCH) \ + lib_generic lib_crypto board/$(BOARDDIR) cpu/$(CPU) lib_$(ARCH) \ fs/cramfs fs/fat fs/fdos fs/jffs2 \ net disk rtc dtt drivers drivers/sk98lin common \ ( -name CVS -prune ) -o ( -name '*.[ch]' -print )`
etags: etags -a `find $(SUBDIRS) include \ - lib_generic board/$(BOARDDIR) cpu/$(CPU) lib_$(ARCH) \ + lib_generic lib_crypto board/$(BOARDDIR) cpu/$(CPU) lib_$(ARCH) \ fs/cramfs fs/fat fs/fdos fs/jffs2 \ net disk rtc dtt drivers drivers/sk98lin common \ ( -name CVS -prune ) -o ( -name '*.[ch]' -print )` diff -Naur u-boot.orig/tools/Makefile u-boot/tools/Makefile --- u-boot.orig/tools/Makefile 2006-05-10 11:43:20.000000000 -0400 +++ u-boot/tools/Makefile 2006-06-08 08:56:16.000000000 -0400 @@ -23,7 +23,7 @@
BINS = img2srec$(SFX) mkimage$(SFX) envcrc$(SFX) gen_eth_addr$(SFX) bmp_logo$(SFX)
-OBJS = environment.o img2srec.o mkimage.o crc32.o envcrc.o gen_eth_addr.o bmp_logo.o +OBJS = environment.o img2srec.o mkimage.o crc32.o envcrc.o gen_eth_addr.o bmp_logo.o make_sign.o
ifeq ($(ARCH),mips) BINS += inca-swap-bytes$(SFX) @@ -125,8 +125,8 @@ $(CC) $(CFLAGS) $(HOST_LDFLAGS) -o $@ $^ $(STRIP) $@
-mkimage$(SFX): mkimage.o crc32.o - $(CC) $(CFLAGS) $(HOST_LDFLAGS) -o $@ $^ +mkimage$(SFX): mkimage.o crc32.o make_sign.o + $(CC) $(CFLAGS) $(HOST_LDFLAGS) -o $@ $^ -lssl $(STRIP) $@
ncb$(SFX): ncb.o @@ -155,6 +155,9 @@ crc32.o: crc32.c $(CC) -g $(CFLAGS) -c $<
+make_sign.o: make_sign.c + $(CC) -g $(CFLAGS) -c $< + mkimage.o: mkimage.c $(CC) -g $(CFLAGS) -c $<
diff -Naur u-boot.orig/tools/make_sign.c u-boot/tools/make_sign.c --- u-boot.orig/tools/make_sign.c 1969-12-31 19:00:00.000000000 -0500 +++ u-boot/tools/make_sign.c 2006-06-08 08:56:37.000000000 -0400 @@ -0,0 +1,202 @@ +#include <fcntl.h> +/* #include <stdio.h> */ +#include <string.h> +/* #include <sys/types.h> */ +#include <sys/stat.h> +#include <unistd.h> + +/* #include <asm/types.h> */ +/* #include <image.h> */ + +#include <openssl/ssl.h> +#include <openssl/rsa.h> +#include <openssl/err.h> +#include <openssl/pem.h> +#include <openssl/sha.h> + +#define PRIVATE_KEY "/etc/ssl/uboot" + + +void SSL_load_error_strings(void); + +static RSA *load_key(void) ; +static char *get_key_file_name(void); +static FILE *open_key_file(char *filename); +static RSA *get_private_key(FILE * fp); +static size_t sign_digest(const unsigned char *digest, + RSA * private_key, + unsigned char *signature); + +/* + ========================================================================= +*/ + +static void +err_msg(void) +{ + char err_buff[1024]; + unsigned long err; + + SSL_load_error_strings(); + + while ((err = ERR_get_error())) { + ERR_error_string_n(err, err_buff, sizeof(err_buff)); + fprintf(stderr, "%s\n", err_buff); + } + + ERR_free_strings(); +} + + +size_t +get_signature(const unsigned char *buf, + unsigned int len, + unsigned char *signature) +{ + RSA *private_key; + unsigned char digest[SHA_DIGEST_LENGTH]; + size_t sign_len; + + /* Do SHA1 encryption of buffer */ + (void)SHA1(buf, len, digest); + + /* Load private key */ + if ((private_key = load_key()) == NULL) { + return 0; + } + + /* Sign digest */ + sign_len = sign_digest(digest, private_key, signature); + + /* Clean up */ + RSA_free(private_key); + + return sign_len; +} + + +static RSA * +load_key(void) +{ + RSA *key; + char *key_name; + FILE *fp; + int res; + + key_name = get_key_file_name(); + if (key_name == NULL) { + return NULL; + } + + fp = open_key_file(key_name); + if (fp == NULL) { + free(key_name); + return NULL; + } + + free(key_name); + + key = get_private_key(fp); + + if (key == NULL) { + return NULL; + } + + res = fclose(fp); + if (res) { + fprintf(stderr, "Can't close file: %s\n", strerror(errno)); + RSA_free(key); + key = NULL; + } + + return key; +} + + +static char * +get_key_file_name(void) +{ + char *file_name = NULL; + + file_name = malloc(strlen(PRIVATE_KEY)); + strncpy(file_name, PRIVATE_KEY, strlen(PRIVATE_KEY)); + + return file_name; +} + + +static FILE * +open_key_file(char *file_name) +{ + FILE *fp; + int fd; + struct stat st; + + /* Open key and check size of file */ + fd = open(file_name, O_RDONLY); + if (fstat(fd, &st) < 0 ) { + fprintf(stderr, "fstat for key file %s failed: %s\n", + file_name, strerror(errno)); + return NULL; + } + + if (st.st_size > 1 * 1024 * 1024) { + fprintf(stderr, "key file %s is too large\n", file_name); + return NULL; + } + + fp = fdopen(fd, "r"); + if (fp == NULL) { + fprintf(stderr, "Can't fdopen file: %s\n", strerror(errno)); + return NULL; + } + + return fp; +} + + +static RSA * +get_private_key( FILE *fp) +{ + RSA *key; + int res; + + /* Load private key */ + key = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL); + res = RSA_check_key(key); + if (res == 0) { + RSA_free(key); + key = NULL; + } + + if (key == NULL) { + err_msg(); + } + + return key; +} + + +/* Do SHA1 encryption of buffer. Result is in digest*/ +static size_t +sign_digest(const unsigned char *digest, + RSA * private_key, + unsigned char *signature) +{ + size_t sign_len; + int res; + + /* Allocate space for signature */ + sign_len = RSA_size(private_key); + + /* Sign digest */ + res = RSA_sign(NID_sha1, digest, SHA_DIGEST_LENGTH, + signature, &sign_len, private_key); + if (res == 0) { + err_msg(); + sign_len = 0; + } + + return sign_len; +} + diff -Naur u-boot.orig/tools/mkimage.c u-boot/tools/mkimage.c --- u-boot.orig/tools/mkimage.c 2006-05-10 11:43:20.000000000 -0400 +++ u-boot/tools/mkimage.c 2006-06-08 08:56:30.000000000 -0400 @@ -70,6 +70,13 @@
extern unsigned long crc32 (unsigned long crc, const char *buf, unsigned int len);
+#ifdef CONFIG_SIGNATURE +extern size_t get_signature (const char *buf, + unsigned int len, + unsigned char *signature); +#endif /* CONFIG_SIGNATURE */ + + typedef struct table_entry { int val; /* as defined in image.h */ char *sname; /* short (input) name */ @@ -155,7 +162,6 @@ static int get_os (char *); static int get_type(char *);
- char *datafile; char *imagefile;
@@ -182,6 +188,10 @@ struct stat sbuf; unsigned char *ptr; char *name = ""; +#ifdef CONFIG_SIGNATURE + unsigned char signature[IH_SIGN]; + size_t sign_len; +#endif /* CONFIG_SIGNATURES */
cmdname = *argv;
@@ -362,6 +372,15 @@ cmdname, imagefile); exit (EXIT_FAILURE); } + +#ifdef CONFIG_SIGNATURE + sign_len = get_signature(data, len, signature); + if (memcmp(signature, hdr->ih_sign, sign_len)) { + fprintf (stderr, + "*** Warning: "%s" has invalid signature!\n", + imagefile); + } +#endif /* CONFIG_SIGNATURE */
/* for multi-file images we need the data part, too */ print_header ((image_header_t *)ptr); @@ -485,6 +504,18 @@
strncpy((char *)hdr->ih_name, name, IH_NMLEN);
+#ifdef CONFIG_SIGNATURE + sign_len = get_signature((const char *)(ptr + sizeof(image_header_t)), + sbuf.st_size - sizeof(image_header_t), + signature); + if (sign_len == 0) { + fprintf(stderr, "Error getting signature\n"); + exit (EXIT_FAILURE); + } + + memcpy((char *)hdr->ih_sign, signature, sign_len); +#endif /* CONFIG_SIGNATURE */ + checksum = crc32(0,(const char *)hdr,sizeof(image_header_t));
hdr->ih_hcrc = htonl(checksum);

Hi Stephen; I'am not an expert on crypto but It seems that it's really a good job. This was critical a security requirement for a bootloader. Thanks for sharing this to community. Emre --- Stephen Johnson steve@research.panasonic.com wrote:
This message contains a patch to add RSA signature validation to U-Boot. I previously sent a similar e-mail to the CELinux-dev mailing list for comments where I received the following:
- I shouldn't be using OpenSSL (due to licensing
concerns), 2. alternate RSA libraries are GNU TLS and MatrixSSL, and 3. the U-Boot mailing list might be a more appropriate place
The patch modifies u-boot to verify an image signature created with a SHA1 digest and RSA encryption/decryption. Because I found the necessary information fairly easily about SHA1 and RSA from the OpenSSL package, that's what I used. Hence, the modified u-boot ran quite quickly, but was rather large. The eventual goal is to release this patch to the community.
I'm looking for additional comments, especially about other encryption libraries that would be better to use, and whether or not something like this is seen as useful.
Notes:
- I'm linking against openssl-0.9.8b.
- I used crosstool based on gcc-3.4.5 and
glibc-2.3.6 for the tool chain.
- It all was built for an omap5912osk board.
- The signature is added to the u-boot header by a
modified mkimage (patch is included).
- The signature is verified in cmd_bootm.c.
- In u-boot/include/configs/omap5912osk.h there is
a CONFIG_SIGNATURE that turns on/off the signature checking and creating.
To compile the modified u-boot the following were needed:
CPATH should be defined to point to where ever crosstool has it's generic include files, e.g. export
CPATH="/opt/crosstool/gcc-3.4.5-glibc-2.3.6/arm-softfloat-linux-gnu/arm-softfloat-linux-gnu/include"
CRYPTO_INC needs to point at the openssl include files, e.g. export
CRYPTO_INC="-I/home/steve/src/SecureBoot/openssl-0.9.8b/include"
CRYPTO_LIBS needs to point the the openssl libraries, e.g. export CRYPTO_LIBS="-L /home/steve/src/SecureBoot/openssl-0.9.8b -lssl -lcrypto -lm -lc"
If anyone has any problems or even better, suggestions, don't hesitate to let me know.
Best regards, Steve
=========================================
diff -Naur u-boot.orig/common/cmd_bootm.c u-boot/common/cmd_bootm.c --- u-boot.orig/common/cmd_bootm.c 2006-05-10 11:43:20.000000000 -0400 +++ u-boot/common/cmd_bootm.c 2006-06-12 10:35:57.000000000 -0400 @@ -79,6 +79,12 @@ # define CHUNKSZ (64 * 1024) #endif
+#ifdef CONFIG_SIGNATURE +extern int verify_signature (const unsigned char *signature,
const unsigned char
*buf,
unsigned int len);
+#endif /* CONFIG_SIGNATURE */
int gunzip (void *, int, unsigned char *, unsigned long *);
static void *zalloc(void *, unsigned, unsigned); @@ -238,6 +244,19 @@ } puts ("OK\n"); }
+#ifdef CONFIG_SIGNATURE
- puts (" Verifying Signature ... ");
- if (verify_signature(hdr->ih_sign,
(const unsigned char *)data,
len) == 0) {
puts("Invalid image signature\n");
SHOW_BOOT_PROGRESS(-3);
return 1;
}
puts ("OK\n");
+#endif /* CONFIG_SIGNATURE */
SHOW_BOOT_PROGRESS (4);
len_ptr = (ulong *)data;
diff -Naur u-boot.orig/config.mk u-boot/config.mk --- u-boot.orig/config.mk 2006-05-10 11:43:20.000000000 -0400 +++ u-boot/config.mk 2006-06-08 09:41:17.000000000 -0400 @@ -126,7 +126,7 @@ -D__KERNEL__ -DTEXT_BASE=$(TEXT_BASE) \ -I$(TOPDIR)/include \ -fno-builtin -ffreestanding -nostdinc -isystem \
- $(gccincdir) -pipe $(PLATFORM_CPPFLAGS)
- $(gccincdir) -pipe $(PLATFORM_CPPFLAGS)
$(CRYPTO_INC)
ifdef BUILD_TAG CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes \ diff -Naur u-boot.orig/include/configs/omap5912osk.h u-boot/include/configs/omap5912osk.h --- u-boot.orig/include/configs/omap5912osk.h 2006-05-10 11:43:20.000000000 -0400 +++ u-boot/include/configs/omap5912osk.h 2006-06-08 15:34:00.000000000 -0400 @@ -38,6 +38,8 @@ #define CONFIG_DISPLAY_CPUINFO 1 /* display cpu info (and speed) */ #define CONFIG_DISPLAY_BOARDINFO 1 /* display board info */
+#define CONFIG_SIGNATURE 1
/* input clock of PLL */ /* the OMAP5912 OSK has 12MHz input clock */ #define CONFIG_SYS_CLK_FREQ 12000000 @@ -112,7 +122,11 @@ */ #define CFG_LONGHELP /* undef to save memory */ #define CFG_PROMPT "OMAP5912 OSK # " /* Monitor Command Prompt */ +#ifdef CONFIG_SIGNATURE +#define CFG_CBSIZE 512 /* Console I/O Buffer Size */ +#else #define CFG_CBSIZE 256 /* Console I/O Buffer Size */ +#endif /* Print Buffer Size */ #define CFG_PBSIZE (CFG_CBSIZE+sizeof(CFG_PROMPT)+16) #define CFG_MAXARGS 16 /* max number of command args */ @@ -183,9 +197,9 @@ */ #define CFG_ENV_IS_IN_FLASH 1 /* addr of environment */ -#define CFG_ENV_ADDR (CFG_FLASH_BASE + 0x020000) +#define CFG_ENV_ADDR (CFG_FLASH_BASE + 0x0E0000)
#define CFG_ENV_SIZE 0x20000 /* Total Size of Environment Sector */ -#define CFG_ENV_OFFSET 0x20000 /* environment starts here */ +#define CFG_ENV_OFFSET 0xE0000 /* environment starts here */
#endif /* __CONFIG_H */ diff -Naur u-boot.orig/include/image.h u-boot/include/image.h --- u-boot.orig/include/image.h 2006-05-10 11:43:20.000000000 -0400 +++ u-boot/include/image.h 2006-06-08 09:09:09.000000000 -0400 @@ -134,6 +134,9 @@
#define IH_MAGIC 0x27051956 /* Image Magic Number */ #define IH_NMLEN 32 /* Image Name Length */ +#ifdef CONFIG_SIGNATURE +#define IH_SIGN 256 /* Image Signature Length */ +#endif /* CONFIG_SIGNATURE */
/*
- all data in network byte order (aka natural aka
bigendian) @@ -152,6 +155,9 @@
=== message truncated ===
___________________________________________________________ All new Yahoo! Mail "The new Interface is stunning in its simplicity and ease of use." - PC Magazine http://uk.docs.yahoo.com/nowyoucan.html

Dear Stephen,
On Wed, Sep 13, 2006 at 03:49:43PM -0400, Stephen Johnson wrote:
This message contains a patch to add RSA signature validation to U-Boot. I previously sent a similar e-mail to the CELinux-dev mailing list for comments where I received the following:
- I shouldn't be using OpenSSL (due to licensing concerns),
- alternate RSA libraries are GNU TLS and MatrixSSL, and
- the U-Boot mailing list might be a more appropriate place
The patch modifies u-boot to verify an image signature created with a SHA1 digest and RSA encryption/decryption. Because I found the necessary information fairly easily about SHA1 and RSA from the OpenSSL package, that's what I used. Hence, the modified u-boot ran quite quickly, but was rather large.
Size is not surprising, surprising is that it was possible to do at all.
The eventual goal is to release this patch to the community.
I'm looking for additional comments, especially about other encryption libraries that would be better to use, and whether or not something like this is seen as useful.
Notes:
- I'm linking against openssl-0.9.8b.
- I used crosstool based on gcc-3.4.5 and glibc-2.3.6 for the tool chain.
- It all was built for an omap5912osk board.
- The signature is added to the u-boot header by a modified mkimage (patch is included).
- The signature is verified in cmd_bootm.c.
- In u-boot/include/configs/omap5912osk.h there is a CONFIG_SIGNATURE that turns on/off the signature checking and creating.
To compile the modified u-boot the following were needed:
CPATH should be defined to point to where ever crosstool has it's generic include files, e.g. export CPATH="/opt/crosstool/gcc-3.4.5-glibc-2.3.6/arm-softfloat-linux-gnu/arm-softfloat-linux-gnu/include"
Why do you need this? Compiler knows where to find its includes.
CRYPTO_INC needs to point at the openssl include files, e.g. export CRYPTO_INC="-I/home/steve/src/SecureBoot/openssl-0.9.8b/include"
CRYPTO_LIBS needs to point the the openssl libraries, e.g. export CRYPTO_LIBS="-L /home/steve/src/SecureBoot/openssl-0.9.8b -lssl -lcrypto -lm -lc"
Oops, see below [*]
If anyone has any problems or even better, suggestions, don't hesitate to let me know.
Best regards, Steve
=========================================
diff -Naur u-boot.orig/common/cmd_bootm.c u-boot/common/cmd_bootm.c --- u-boot.orig/common/cmd_bootm.c 2006-05-10 11:43:20.000000000 -0400 +++ u-boot/common/cmd_bootm.c 2006-06-12 10:35:57.000000000 -0400 @@ -79,6 +79,12 @@ # define CHUNKSZ (64 * 1024) #endif
+#ifdef CONFIG_SIGNATURE +extern int verify_signature (const unsigned char *signature,
const unsigned char *buf,
unsigned int len);
+#endif /* CONFIG_SIGNATURE */
int gunzip (void *, int, unsigned char *, unsigned long *);
static void *zalloc(void *, unsigned, unsigned); @@ -238,6 +244,19 @@ } puts ("OK\n"); }
+#ifdef CONFIG_SIGNATURE
- puts (" Verifying Signature ... ");
- if (verify_signature(hdr->ih_sign,
(const unsigned char *)data,
len) == 0) {
puts("Invalid image signature\n");
SHOW_BOOT_PROGRESS(-3);
return 1;
}
puts ("OK\n");
+#endif /* CONFIG_SIGNATURE */
SHOW_BOOT_PROGRESS (4);
len_ptr = (ulong *)data;
diff -Naur u-boot.orig/config.mk u-boot/config.mk --- u-boot.orig/config.mk 2006-05-10 11:43:20.000000000 -0400 +++ u-boot/config.mk 2006-06-08 09:41:17.000000000 -0400 @@ -126,7 +126,7 @@ -D__KERNEL__ -DTEXT_BASE=$(TEXT_BASE) \ -I$(TOPDIR)/include \ -fno-builtin -ffreestanding -nostdinc -isystem \
- $(gccincdir) -pipe $(PLATFORM_CPPFLAGS)
- $(gccincdir) -pipe $(PLATFORM_CPPFLAGS) $(CRYPTO_INC)
[*] You are adding path to opessl includes to crosscompiler... Uh, I have bad feelings...
ifdef BUILD_TAG CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes \ diff -Naur u-boot.orig/include/configs/omap5912osk.h u-boot/include/configs/omap5912osk.h --- u-boot.orig/include/configs/omap5912osk.h 2006-05-10 11:43:20.000000000 -0400 +++ u-boot/include/configs/omap5912osk.h 2006-06-08 15:34:00.000000000 -0400 @@ -38,6 +38,8 @@ #define CONFIG_DISPLAY_CPUINFO 1 /* display cpu info (and speed) */ #define CONFIG_DISPLAY_BOARDINFO 1 /* display board info */
+#define CONFIG_SIGNATURE 1
/* input clock of PLL */ /* the OMAP5912 OSK has 12MHz input clock */ #define CONFIG_SYS_CLK_FREQ 12000000 @@ -112,7 +122,11 @@ */ #define CFG_LONGHELP /* undef to save memory */ #define CFG_PROMPT "OMAP5912 OSK # " /* Monitor Command Prompt */ +#ifdef CONFIG_SIGNATURE +#define CFG_CBSIZE 512 /* Console I/O Buffer Size */ +#else #define CFG_CBSIZE 256 /* Console I/O Buffer Size */ +#endif /* Print Buffer Size */ #define CFG_PBSIZE (CFG_CBSIZE+sizeof(CFG_PROMPT)+16) #define CFG_MAXARGS 16 /* max number of command args */ @@ -183,9 +197,9 @@ */ #define CFG_ENV_IS_IN_FLASH 1 /* addr of environment */ -#define CFG_ENV_ADDR (CFG_FLASH_BASE + 0x020000) +#define CFG_ENV_ADDR (CFG_FLASH_BASE + 0x0E0000)
#define CFG_ENV_SIZE 0x20000 /* Total Size of Environment Sector */ -#define CFG_ENV_OFFSET 0x20000 /* environment starts here */ +#define CFG_ENV_OFFSET 0xE0000 /* environment starts here */
#endif /* __CONFIG_H */ diff -Naur u-boot.orig/include/image.h u-boot/include/image.h --- u-boot.orig/include/image.h 2006-05-10 11:43:20.000000000 -0400 +++ u-boot/include/image.h 2006-06-08 09:09:09.000000000 -0400 @@ -134,6 +134,9 @@
#define IH_MAGIC 0x27051956 /* Image Magic Number */ #define IH_NMLEN 32 /* Image Name Length */ +#ifdef CONFIG_SIGNATURE +#define IH_SIGN 256 /* Image Signature Length */ +#endif /* CONFIG_SIGNATURE */
/*
- all data in network byte order (aka natural aka bigendian)
@@ -152,6 +155,9 @@ uint8_t ih_type; /* Image Type */ uint8_t ih_comp; /* Compression Type */ uint8_t ih_name[IH_NMLEN]; /* Image Name */ +#ifdef CONFIG_SIGNATURE
- uint8_t ih_sign[IH_SIGN]; /* Image Signature */
+#endif /* CONFIG_SIGNATURE */ } image_header_t;
diff -Naur u-boot.orig/lib_crypto/Makefile u-boot/lib_crypto/Makefile --- u-boot.orig/lib_crypto/Makefile 1969-12-31 19:00:00.000000000 -0500 +++ u-boot/lib_crypto/Makefile 2006-06-08 10:17:56.000000000 -0400 @@ -0,0 +1,40 @@ +# +# (C) Copyright 2000-2002 +# Wolfgang Denk, DENX Software Engineering, wd@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 = libcrypto.a
+OBJS = signature.o
+$(LIB): .depend $(OBJS)
- $(AR) crv $@ $(OBJS)
+#########################################################################
+.depend: Makefile $(OBJS:.o=.c)
$(CC) -M $(CFLAGS) $(CRYPTO_INC) $(OBJS:.o=.c) > $@
+sinclude .depend
+######################################################################### diff -Naur u-boot.orig/lib_crypto/signature.c u-boot/lib_crypto/signature.c --- u-boot.orig/lib_crypto/signature.c 1969-12-31 19:00:00.000000000 -0500 +++ u-boot/lib_crypto/signature.c 2006-06-12 10:41:51.000000000 -0400 @@ -0,0 +1,121 @@ +#include <stdio.h>
+#include <openssl/ssl.h> +#include <openssl/rsa.h> +#include <openssl/err.h> +#include <openssl/pem.h> +#include <openssl/sha.h> +#include <openssl/bio.h>
+#define IH_SIGN 256
+unsigned char key_string[] = "-----BEGIN PUBLIC KEY-----\n\ +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6IgnrRN+ER3GG/ZNDQk/\n\ +JByf09bYPgHfERJdHUb8p+6wM7cb7RvoxyVyaFQFA7RKErr6kvzjIKz/tyDnKKzK\n\ +0kAE0vE5prSUDxhoExM9YBAAjc6TAQ0kKjerIwZx5iT9vYV7YSpG5U7Sycw2NrjP\n\ +dMS2X8v1pHZSSgQAYPs3zGlC+oyMebd7vpsFKihc2vr2J0PXdD1Owh8gEIiZjm5o\n\ +eXL93BGFUVMZa040YUvTn9627eEg6hJJqmRZ4Myx90585J/2Jmhztv2U2t2Rl2T9\n\ +mentqOvFO0QhhadniRgDzhsLM6wbpwOqlRROcVGnkqmFckLKlLWqYbzoZOJs4xO3\n\ +oQIDAQAB\n\ +-----END PUBLIC KEY-----\n";
You want public key to be board specific, don't you?
+void SSL_load_error_strings(void);
+static void err_msg(void); +static RSA *load_key(void) ; +static RSA *get_public_key(char *key_string);
+/*
- =========================================================================
+*/
+static void +err_msg(void) +{
- char err_buff[1024];
- unsigned long err;
- SSL_load_error_strings();
- while ((err = ERR_get_error())) {
ERR_error_string_n(err, err_buff, sizeof(err_buff));
fprintf(stderr, "%s\n", err_buff);
- }
- ERR_free_strings();
+}
+int +verify_signature(const unsigned char *signature,
const unsigned char *buf,
unsigned int len)
+{
- RSA *public_key;
- unsigned char digest[SHA_DIGEST_LENGTH];
- int res;
- int i;
- /* Do SHA1 encryption of buffer */
- (void)SHA1(buf, len, digest);
Oh, here bad feeling came true. It seems you are indeed using SHA1 function from crypto/sha/sha1_one.c (openssl library).
- /* Load public key */
- if ((public_key = load_key()) == NULL) {
return 0;
- }
- /* verify digest */
- res = RSA_verify(NID_sha1,
digest, SHA_DIGEST_LENGTH,
signature, IH_SIGN,
public_key);
- /* Clean up */
- RSA_free(public_key);
- return res;
+}
[snip]
Well, I have admit it is a bit surprising that openssl can be compiled as standalone library and linked with U-Boot :-)
Although I'd like to see support for something like this in U-Boot, this is not way to go. Please see, how hush (busybox shell - common/hush.c) or nand support (drivers/nand) were integrated. Just take all necesary routines you need and make them fit into U-Boot tree. Remove all bloat, but make future updates from original source easy.
Best regards, ladis
participants (3)
-
emre kara
-
Ladislav Michl
-
Stephen Johnson