TBB: add ECDSA support to the certificate generation tool

This patch extends the 'cert_create' tool to support ECDSA keys
to sign the certificates. The '--key-alg' command line option
can be used to specify the key algorithm when invoking the tool.
Available options are:

    * 'rsa': create RSA-2048 keys (default option)
    * 'ecdsa': create ECDSA-SECP256R1 keys

The TF Makefile has been updated to allow the platform to specify
the key algorithm by declaring the 'KEY_ALG' variable in the
platform makefile.

The behaviour regarding key management has changed. After applying
this patch, the tool will try first to open the keys from disk. If
one key does not exist or no key is specified, and the command line
option to create keys has been specified, new keys will be created.
Otherwise an error will be generated and the tool will exit. This
way, the user may specify certain keys while the tool will create
the remaining ones. This feature is useful for testing purposes
and CI infrastructures.

The OpenSSL directory may be specified using the build option
'OPENSSL_DIR' when building the certificate generation tool.
Default is '/usr'.

Change-Id: I98bcc2bfab28dd7179f17f1177ea7a65698df4e7
This commit is contained in:
Juan Castillo 2015-06-01 16:34:23 +01:00
parent dff93c8675
commit ccbf890e5e
5 changed files with 161 additions and 43 deletions

View File

@ -337,6 +337,7 @@ ifneq (${GENERATE_COT},0)
$(eval CRT_ARGS += $(if ${TRUSTED_WORLD_KEY}, --trusted-world-key ${TRUSTED_WORLD_KEY})) $(eval CRT_ARGS += $(if ${TRUSTED_WORLD_KEY}, --trusted-world-key ${TRUSTED_WORLD_KEY}))
$(eval CRT_ARGS += $(if ${NON_TRUSTED_WORLD_KEY}, --non-trusted-world-key ${NON_TRUSTED_WORLD_KEY})) $(eval CRT_ARGS += $(if ${NON_TRUSTED_WORLD_KEY}, --non-trusted-world-key ${NON_TRUSTED_WORLD_KEY}))
$(eval CRT_ARGS += --trusted-key-cert ${TRUSTED_KEY_CERT}) $(eval CRT_ARGS += --trusted-key-cert ${TRUSTED_KEY_CERT})
$(eval CRT_ARGS += $(if ${KEY_ALG}, --key-alg ${KEY_ALG}))
endif endif
# Check Trusted Board Boot options # Check Trusted Board Boot options

View File

@ -33,6 +33,7 @@ PLAT := none
V := 0 V := 0
DEBUG := 0 DEBUG := 0
BINARY := ${PROJECT} BINARY := ${PROJECT}
OPENSSL_DIR := /usr
OBJECTS := src/cert.o \ OBJECTS := src/cert.o \
src/ext.o \ src/ext.o \
@ -69,8 +70,8 @@ endif
# Make soft links and include from local directory otherwise wrong headers # Make soft links and include from local directory otherwise wrong headers
# could get pulled in from firmware tree. # could get pulled in from firmware tree.
INC_DIR := -I ./include -I ${PLAT_INCLUDE} INC_DIR := -I ./include -I ${PLAT_INCLUDE} -I ${OPENSSL_DIR}/include
LIB_DIR := LIB_DIR := -L ${OPENSSL_DIR}/lib
LIB := -lssl -lcrypto LIB := -lssl -lcrypto
CC := gcc CC := gcc

View File

@ -35,6 +35,21 @@
#define RSA_KEY_BITS 2048 #define RSA_KEY_BITS 2048
/* Error codes */
enum {
KEY_ERR_NONE,
KEY_ERR_MALLOC,
KEY_ERR_FILENAME,
KEY_ERR_OPEN,
KEY_ERR_LOAD
};
/* Supported key algorithms */
enum {
KEY_ALG_RSA,
KEY_ALG_ECDSA
};
/* /*
* This structure contains the relevant information to create the keys * This structure contains the relevant information to create the keys
* required to sign the certificates. * required to sign the certificates.
@ -50,8 +65,8 @@ typedef struct key_s {
EVP_PKEY *key; /* Key container */ EVP_PKEY *key; /* Key container */
} key_t; } key_t;
int key_new(key_t *key); int key_create(key_t *key, int type);
int key_load(key_t *key); int key_load(key_t *key, unsigned int *err_code);
int key_store(key_t *key); int key_store(key_t *key);
#endif /* KEY_H_ */ #endif /* KEY_H_ */

View File

@ -46,41 +46,81 @@
#define MAX_FILENAME_LEN 1024 #define MAX_FILENAME_LEN 1024
/* /*
* Create a new key * Create a new key container
*/ */
int key_new(key_t *key) static int key_new(key_t *key)
{ {
RSA *rsa = NULL;
EVP_PKEY *k = NULL;
/* Create key pair container */ /* Create key pair container */
k = EVP_PKEY_new(); key->key = EVP_PKEY_new();
if (k == NULL) { if (key->key == NULL) {
return 0; return 0;
} }
/* Generate a new RSA key */ return 1;
rsa = RSA_generate_key(RSA_KEY_BITS, RSA_F4, NULL, NULL); }
if (EVP_PKEY_assign_RSA(k, rsa)) {
key->key = k; int key_create(key_t *key, int type)
return 1; {
} else { RSA *rsa = NULL;
printf("Cannot assign RSA key\n"); EC_KEY *ec = NULL;
/* Create OpenSSL key container */
if (!key_new(key)) {
goto err;
} }
if (k) switch (type) {
EVP_PKEY_free(k); case KEY_ALG_RSA:
/* Generate a new RSA key */
rsa = RSA_generate_key(RSA_KEY_BITS, RSA_F4, NULL, NULL);
if (rsa == NULL) {
printf("Cannot create RSA key\n");
goto err;
}
if (!EVP_PKEY_assign_RSA(key->key, rsa)) {
printf("Cannot assign RSA key\n");
goto err;
}
break;
case KEY_ALG_ECDSA:
/* Generate a new ECDSA key */
ec = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
if (ec == NULL) {
printf("Cannot create EC key\n");
goto err;
}
if (!EC_KEY_generate_key(ec)) {
printf("Cannot generate EC key\n");
goto err;
}
EC_KEY_set_flags(ec, EC_PKEY_NO_PARAMETERS);
EC_KEY_set_asn1_flag(ec, OPENSSL_EC_NAMED_CURVE);
if (!EVP_PKEY_assign_EC_KEY(key->key, ec)) {
printf("Cannot assign EC key\n");
goto err;
}
break;
default:
goto err;
}
return 1;
err:
RSA_free(rsa);
EC_KEY_free(ec);
return 0; return 0;
} }
int key_load(key_t *key) int key_load(key_t *key, unsigned int *err_code)
{ {
FILE *fp = NULL; FILE *fp = NULL;
EVP_PKEY *k = NULL; EVP_PKEY *k = NULL;
/* Create key pair container */ /* Create OpenSSL key container */
k = EVP_PKEY_new(); if (!key_new(key)) {
if (k == NULL) { *err_code = KEY_ERR_MALLOC;
return 0; return 0;
} }
@ -88,24 +128,24 @@ int key_load(key_t *key)
/* Load key from file */ /* Load key from file */
fp = fopen(key->fn, "r"); fp = fopen(key->fn, "r");
if (fp) { if (fp) {
k = PEM_read_PrivateKey(fp, &k, NULL, NULL); k = PEM_read_PrivateKey(fp, &key->key, NULL, NULL);
fclose(fp); fclose(fp);
if (k) { if (k) {
key->key = k; *err_code = KEY_ERR_NONE;
return 1; return 1;
} else { } else {
ERROR("Cannot read key from %s\n", key->fn); ERROR("Cannot load key from %s\n", key->fn);
*err_code = KEY_ERR_LOAD;
} }
} else { } else {
ERROR("Cannot open file %s\n", key->fn); WARN("Cannot open file %s\n", key->fn);
*err_code = KEY_ERR_OPEN;
} }
} else { } else {
ERROR("Key filename not specified\n"); WARN("Key filename not specified\n");
*err_code = KEY_ERR_FILENAME;
} }
if (k)
EVP_PKEY_free(k);
return 0; return 0;
} }

View File

@ -80,6 +80,7 @@
#define VAL_DAYS 7300 #define VAL_DAYS 7300
#define ID_TO_BIT_MASK(id) (1 << id) #define ID_TO_BIT_MASK(id) (1 << id)
#define NVCOUNTER_VALUE 0 #define NVCOUNTER_VALUE 0
#define NUM_ELEM(x) ((sizeof(x)) / (sizeof(x[0])))
/* Files */ /* Files */
enum { enum {
@ -112,6 +113,7 @@ enum {
}; };
/* Global options */ /* Global options */
static int key_alg;
static int new_keys; static int new_keys;
static int save_keys; static int save_keys;
static int print_cert; static int print_cert;
@ -138,6 +140,11 @@ static char *strdup(const char *str)
return dup; return dup;
} }
static const char *key_algs_str[] = {
[KEY_ALG_RSA] = "rsa",
[KEY_ALG_ECDSA] = "ecdsa"
};
/* Command line options */ /* Command line options */
static const struct option long_opt[] = { static const struct option long_opt[] = {
/* Binary images */ /* Binary images */
@ -166,6 +173,7 @@ static const struct option long_opt[] = {
{"bl32-key", required_argument, 0, BL32_KEY_ID}, {"bl32-key", required_argument, 0, BL32_KEY_ID},
{"bl33-key", required_argument, 0, BL33_KEY_ID}, {"bl33-key", required_argument, 0, BL33_KEY_ID},
/* Common options */ /* Common options */
{"key-alg", required_argument, 0, 'a'},
{"help", no_argument, 0, 'h'}, {"help", no_argument, 0, 'h'},
{"save-keys", no_argument, 0, 'k'}, {"save-keys", no_argument, 0, 'k'},
{"new-chain", no_argument, 0, 'n'}, {"new-chain", no_argument, 0, 'n'},
@ -189,6 +197,7 @@ static void print_help(const char *cmd)
printf(" --%s <file> \\\n", long_opt[i].name); printf(" --%s <file> \\\n", long_opt[i].name);
} }
printf("\n"); printf("\n");
printf("-a Key algorithm: rsa (default), ecdsa\n");
printf("-h Print help and exit\n"); printf("-h Print help and exit\n");
printf("-k Save key pairs into files. Filenames must be provided\n"); printf("-k Save key pairs into files. Filenames must be provided\n");
printf("-n Generate new key pairs if no key files are provided\n"); printf("-n Generate new key pairs if no key files are provided\n");
@ -198,8 +207,27 @@ static void print_help(const char *cmd)
exit(0); exit(0);
} }
static int get_key_alg(const char *key_alg_str)
{
int i;
for (i = 0 ; i < NUM_ELEM(key_algs_str) ; i++) {
if (0 == strcmp(key_alg_str, key_algs_str[i])) {
return i;
}
}
return -1;
}
static void check_cmd_params(void) static void check_cmd_params(void)
{ {
/* Only save new keys */
if (save_keys && !new_keys) {
ERROR("Only new keys can be saved to disk\n");
exit(1);
}
/* BL2, BL31 and BL33 are mandatory */ /* BL2, BL31 and BL33 are mandatory */
if (certs[BL2_CERT].bin == NULL) { if (certs[BL2_CERT].bin == NULL) {
ERROR("BL2 image not specified\n"); ERROR("BL2 image not specified\n");
@ -276,15 +304,19 @@ int main(int argc, char *argv[])
FILE *file = NULL; FILE *file = NULL;
int i, tz_nvctr_nid, ntz_nvctr_nid, hash_nid, pk_nid; int i, tz_nvctr_nid, ntz_nvctr_nid, hash_nid, pk_nid;
int c, opt_idx = 0; int c, opt_idx = 0;
unsigned int err_code;
unsigned char md[SHA256_DIGEST_LENGTH]; unsigned char md[SHA256_DIGEST_LENGTH];
const EVP_MD *md_info; const EVP_MD *md_info;
NOTICE("CoT Generation Tool: %s\n", build_msg); NOTICE("CoT Generation Tool: %s\n", build_msg);
NOTICE("Target platform: %s\n", platform_msg); NOTICE("Target platform: %s\n", platform_msg);
/* Set default options */
key_alg = KEY_ALG_RSA;
while (1) { while (1) {
/* getopt_long stores the option index here. */ /* getopt_long stores the option index here. */
c = getopt_long(argc, argv, "hknp", long_opt, &opt_idx); c = getopt_long(argc, argv, "ahknp", long_opt, &opt_idx);
/* Detect the end of the options. */ /* Detect the end of the options. */
if (c == -1) { if (c == -1) {
@ -292,6 +324,13 @@ int main(int argc, char *argv[])
} }
switch (c) { switch (c) {
case 'a':
key_alg = get_key_alg(optarg);
if (key_alg < 0) {
ERROR("Invalid key algorithm '%s'\n", optarg);
exit(1);
}
break;
case 'h': case 'h':
print_help(argv[0]); print_help(argv[0]);
break; break;
@ -399,19 +438,41 @@ int main(int argc, char *argv[])
CHECK_OID(ntz_nvctr_nid, NTZ_FW_NVCOUNTER_OID); CHECK_OID(ntz_nvctr_nid, NTZ_FW_NVCOUNTER_OID);
/* Load private keys from files (or generate new ones) */ /* Load private keys from files (or generate new ones) */
if (new_keys) { for (i = 0 ; i < NUM_KEYS ; i++) {
for (i = 0 ; i < NUM_KEYS ; i++) { /* First try to load the key from disk */
if (!key_new(&keys[i])) { if (key_load(&keys[i], &err_code)) {
ERROR("Error creating %s\n", keys[i].desc); /* Key loaded successfully */
exit(1); continue;
}
} }
} else {
for (i = 0 ; i < NUM_KEYS ; i++) { /* Key not loaded. Check the error code */
if (!key_load(&keys[i])) { if (err_code == KEY_ERR_MALLOC) {
ERROR("Error loading %s\n", keys[i].desc); /* Cannot allocate memory. Abort. */
ERROR("Malloc error while loading '%s'\n", keys[i].fn);
exit(1);
} else if (err_code == KEY_ERR_LOAD) {
/* File exists, but it does not contain a valid private
* key. Abort. */
ERROR("Error loading '%s'\n", keys[i].fn);
exit(1);
}
/* File does not exist, could not be opened or no filename was
* given */
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)) {
ERROR("Error creating key '%s'\n", keys[i].desc);
exit(1); exit(1);
} }
} else {
if (err_code == KEY_ERR_OPEN) {
ERROR("Error opening '%s'\n", keys[i].fn);
} else {
ERROR("Key '%s' not specified\n", keys[i].desc);
}
exit(1);
} }
} }