diff mbox

[U-Boot,v3,03/12] image: Add RSA support for image signing

Message ID 1371161411-2834-4-git-send-email-sjg@chromium.org
State Accepted
Delegated to: Tom Rini
Headers show

Commit Message

Simon Glass June 13, 2013, 10:10 p.m. UTC
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

Comments

Masahiro Yamada June 27, 2013, 4:08 a.m. UTC | #1
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
Simon Glass June 27, 2013, 6:44 a.m. UTC | #2
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
>
>
Tom Rini June 27, 2013, 12:50 p.m. UTC | #3
-----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@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-----
Simon Glass June 27, 2013, 3:45 p.m. UTC | #4
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@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
Tom Rini June 27, 2013, 3:48 p.m. UTC | #5
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@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.
Simon Glass June 27, 2013, 5:04 p.m. UTC | #6
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@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
diff mbox

Patch

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@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@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 at 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),)
 	@: