Add cert_create tool support for RSA key sizes

cert_tool is now able to accept a command line option for specifying the
key size. It now supports the following options: 1024, 2048 (default),
3072 and 4096. This is also modifiable by TFA using the build flag
KEY_SIZE.

Change-Id: Ifadecf84ade3763249ee8cc7123a8178f606f0e5
Signed-off-by: Justin Chadwell <justin.chadwell@arm.com>
diff --git a/tools/cert_create/src/main.c b/tools/cert_create/src/main.c
index 0f588cc..44a65eb 100644
--- a/tools/cert_create/src/main.c
+++ b/tools/cert_create/src/main.c
@@ -10,6 +10,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <stdbool.h>
 
 #include <openssl/conf.h>
 #include <openssl/engine.h>
@@ -69,6 +70,7 @@
 /* Global options */
 static int key_alg;
 static int hash_alg;
+static int key_size;
 static int new_keys;
 static int save_keys;
 static int print_cert;
@@ -155,6 +157,18 @@
 	return -1;
 }
 
+static int get_key_size(const char *key_size_str)
+{
+	char *end;
+	long key_size;
+
+	key_size = strtol(key_size_str, &end, 10);
+	if (*end != '\0')
+		return -1;
+
+	return key_size;
+}
+
 static int get_hash_alg(const char *hash_alg_str)
 {
 	int i;
@@ -174,6 +188,7 @@
 	ext_t *ext;
 	key_t *key;
 	int i, j;
+	bool valid_size;
 
 	/* Only save new keys */
 	if (save_keys && !new_keys) {
@@ -181,6 +196,26 @@
 		exit(1);
 	}
 
+	/* Validate key-size */
+	valid_size = false;
+	for (i = 0; i < KEY_SIZE_MAX_NUM; i++) {
+		if (key_size == KEY_SIZES[key_alg][i]) {
+			valid_size = true;
+			break;
+		}
+	}
+	if (!valid_size) {
+		ERROR("'%d' is not a valid key size for '%s'\n",
+				key_size, key_algs_str[key_alg]);
+		NOTICE("Valid sizes are: ");
+		for (i = 0; i < KEY_SIZE_MAX_NUM &&
+				KEY_SIZES[key_alg][i] != 0; i++) {
+			printf("%d ", KEY_SIZES[key_alg][i]);
+		}
+		printf("\n");
+		exit(1);
+	}
+
 	/* Check that all required options have been specified in the
 	 * command line */
 	for (i = 0; i < num_certs; i++) {
@@ -246,6 +281,10 @@
 PKCS#1 v2.1, 'rsa_1_5' - RSA PKCS#1 v1.5, 'ecdsa'"
 	},
 	{
+		{ "key-size", required_argument, NULL, 'b' },
+		"Key size (for supported algorithms)."
+	},
+	{
 		{ "hash-alg", required_argument, NULL, 's' },
 		"Hash algorithm : 'sha256' (default), 'sha384', 'sha512'"
 	},
@@ -286,6 +325,7 @@
 	/* Set default options */
 	key_alg = KEY_ALG_RSA;
 	hash_alg = HASH_ALG_SHA256;
+	key_size = -1;
 
 	/* Add common command line options */
 	for (i = 0; i < NUM_ELEM(common_cmd_opt); i++) {
@@ -315,7 +355,7 @@
 
 	while (1) {
 		/* getopt_long stores the option index here. */
-		c = getopt_long(argc, argv, "a:hknps:", cmd_opt, &opt_idx);
+		c = getopt_long(argc, argv, "a:b:hknps:", cmd_opt, &opt_idx);
 
 		/* Detect the end of the options. */
 		if (c == -1) {
@@ -330,6 +370,13 @@
 				exit(1);
 			}
 			break;
+		case 'b':
+			key_size = get_key_size(optarg);
+			if (key_size <= 0) {
+				ERROR("Invalid key size '%s'\n", optarg);
+				exit(1);
+			}
+			break;
 		case 'h':
 			print_help(argv[0], cmd_opt);
 			exit(0);
@@ -371,6 +418,11 @@
 		}
 	}
 
+	/* Select a reasonable default key-size */
+	if (key_size == -1) {
+		key_size = KEY_SIZES[key_alg][0];
+	}
+
 	/* Check command line arguments */
 	check_cmd_params();
 
@@ -413,7 +465,7 @@
 		if (new_keys) {
 			/* Try to create a new key */
 			NOTICE("Creating new key for '%s'\n", keys[i].desc);
-			if (!key_create(&keys[i], key_alg)) {
+			if (!key_create(&keys[i], key_alg, key_size)) {
 				ERROR("Error creating key '%s'\n", keys[i].desc);
 				exit(1);
 			}