[Celinux-dev] RFC - Secure Bootloader patch

Stephen Johnson steve at research.panasonic.com
Tue Aug 22 12:57:27 PDT 2006


At OLS last month I demoed a Secure Boot Loader that was based on a
u-boot that had been modified to verify an image signature using a
SHA1 digest and RSA encryption/decryption.  Because I could find the
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.  I'm including the u-boot patch in this message so
that others can look at it for ways to cut the size.  The eventual
goal is to release this patch to the community.

Notes:
 - The u-boot was downloaded from the u-boot git tree on August 1, but
   the patch also applied cleanly with a u-boot version from June.
 - I'm linking against openssl-0.9.8b.  
 - I used crosstool built tool chain based on gcc-3.4.5 and glibc-2.3.6
 - It all was built for an omap5912osk board.
 - The signature is added to the u-boot header by mkimage.
 - 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.  The changes
   there are straight forward to move to another board in that same
   "configs" directory.  These are the only board-specific changes
   required.
 - The patch is applied at the top level of the u-boot source, 
   patch -p1 < /path/to/patch/file

To compile the patched u-boot, the following are needed:

CPATH should be defined to point to wherever the tool chain 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 to 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 and include the
necessary 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 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	= 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);



More information about the Celinux-dev mailing list