Boot: Add RSA-3072 support to imgtool script

PSA TBSA-M recommends to use RSA signature for firmware
authentication with at least 3072 bits length key size.

This change is based on:
https://github.com/JuulLabs-OSS/mcuboot/pull/476
authored by Fabio Utzig <utzig@apache.org>

Change-Id: I78fb0c9732aa6942b6fcb46fef5e1965c9dccaa5
Signed-off-by: Tamas Ban <tamas.ban@arm.com>
diff --git a/bl2/ext/mcuboot/scripts/imgtool.py b/bl2/ext/mcuboot/scripts/imgtool.py
index 924fa96..43d7d15 100644
--- a/bl2/ext/mcuboot/scripts/imgtool.py
+++ b/bl2/ext/mcuboot/scripts/imgtool.py
@@ -80,10 +80,14 @@
     return newVersion
 
 def gen_rsa2048(args):
-    keys.RSA2048.generate().export_private(args.key)
+    keys.RSAutil.generate().export_private(args.key)
+
+def gen_rsa3072(args):
+    keys.RSAutil.generate(key_size=3072).export_private(args.key)
 
 keygens = {
-        'rsa-2048': gen_rsa2048, }
+        'rsa-2048': gen_rsa2048,
+        'rsa-3072': gen_rsa3072, }
 
 def do_keygen(args):
     if args.type not in keygens:
diff --git a/bl2/ext/mcuboot/scripts/imgtool_lib/image.py b/bl2/ext/mcuboot/scripts/imgtool_lib/image.py
index bd1bf5d..ff137a5 100644
--- a/bl2/ext/mcuboot/scripts/imgtool_lib/image.py
+++ b/bl2/ext/mcuboot/scripts/imgtool_lib/image.py
@@ -36,6 +36,7 @@
         'KEYHASH': 0x01,
         'SHA256' : 0x10,
         'RSA2048': 0x20,
+        'RSA3072': 0x23,
         'SEC_CNT': 0x50, }
 
 TLV_INFO_SIZE = 4
diff --git a/bl2/ext/mcuboot/scripts/imgtool_lib/keys.py b/bl2/ext/mcuboot/scripts/imgtool_lib/keys.py
index fda3ed6..f17f173 100644
--- a/bl2/ext/mcuboot/scripts/imgtool_lib/keys.py
+++ b/bl2/ext/mcuboot/scripts/imgtool_lib/keys.py
@@ -1,5 +1,5 @@
 # Copyright 2017 Linaro Limited
-# Copyright (c) 2017-2018, Arm Limited.
+# Copyright (c) 2017-2019, Arm Limited.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -25,25 +25,37 @@
 from pyasn1.type import namedtype, univ
 from pyasn1.codec.der.encoder import encode
 
+# Sizes that bootutil will recognize
+RSA_KEY_SIZES = [2048, 3072]
+
 # By default, we use RSA-PSS (PKCS 2.1).  That can be overridden on
 # the command line to support the older (less secure) PKCS1.5
 sign_rsa_pss = True
 
 AUTOGEN_MESSAGE = "/* Autogenerated by imgtool.py, do not edit. */"
 
+class RSAUsageError(Exception):
+    pass
+
 class RSAPublicKey(univ.Sequence):
     componentType = namedtype.NamedTypes(
             namedtype.NamedType('modulus', univ.Integer()),
             namedtype.NamedType('publicExponent', univ.Integer()))
 
-class RSA2048():
+class RSAutil():
     def __init__(self, key):
-        """Construct an RSA2048 key with the given key data"""
+        """Construct an RSA key with the given key data"""
         self.key = key
 
+    def key_size(self):
+        return self.key.n.bit_length()
+
     @staticmethod
-    def generate():
-        return RSA2048(RSA.generate(2048))
+    def generate(key_size=2048):
+        if key_size not in RSA_KEY_SIZES:
+            raise RSAUsageError("Key size {} is not supported by MCUboot"
+                                .format(key_size))
+        return RSAutil(RSA.generate(key_size))
 
     def export_private(self, path):
         with open(path, 'wb') as f:
@@ -71,15 +83,15 @@
     def sig_type(self):
         """Return the type of this signature (as a string)"""
         if sign_rsa_pss:
-            return "PKCS1_PSS_RSA2048_SHA256"
+            return "PKCS1_PSS_RSA{}_SHA256".format(self.key_size())
         else:
-            return "PKCS15_RSA2048_SHA256"
+            return "PKCS15_RSA{}_SHA256".format(self.key_size())
 
     def sig_len(self):
-        return 256
+        return 256 if self.key_size() == 2048 else 384
 
     def sig_tlv(self):
-        return "RSA2048"
+        return "RSA2048" if self.key_size() == 2048 else "RSA3072"
 
     def sign(self, payload):
         converted_payload = bytes(payload)
@@ -97,8 +109,6 @@
         pem = f.read()
     try:
         key = RSA.importKey(pem)
-        if key.n.bit_length() != 2048:
-            raise Exception("Unsupported RSA bit length, only 2048 supported")
-        return RSA2048(key)
+        return RSAutil(key)
     except ValueError:
         raise Exception("Unsupported RSA key file")