Commit ccbf890e authored by Juan Castillo's avatar Juan Castillo
Browse files

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
parent dff93c86
......@@ -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 ${NON_TRUSTED_WORLD_KEY}, --non-trusted-world-key ${NON_TRUSTED_WORLD_KEY}))
$(eval CRT_ARGS += --trusted-key-cert ${TRUSTED_KEY_CERT})
$(eval CRT_ARGS += $(if ${KEY_ALG}, --key-alg ${KEY_ALG}))
endif
# Check Trusted Board Boot options
......
......@@ -33,6 +33,7 @@ PLAT := none
V := 0
DEBUG := 0
BINARY := ${PROJECT}
OPENSSL_DIR := /usr
OBJECTS := src/cert.o \
src/ext.o \
......@@ -69,8 +70,8 @@ endif
# Make soft links and include from local directory otherwise wrong headers
# could get pulled in from firmware tree.
INC_DIR := -I ./include -I ${PLAT_INCLUDE}
LIB_DIR :=
INC_DIR := -I ./include -I ${PLAT_INCLUDE} -I ${OPENSSL_DIR}/include
LIB_DIR := -L ${OPENSSL_DIR}/lib
LIB := -lssl -lcrypto
CC := gcc
......
......@@ -35,6 +35,21 @@
#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
* required to sign the certificates.
......@@ -50,8 +65,8 @@ typedef struct key_s {
EVP_PKEY *key; /* Key container */
} key_t;
int key_new(key_t *key);
int key_load(key_t *key);
int key_create(key_t *key, int type);
int key_load(key_t *key, unsigned int *err_code);
int key_store(key_t *key);
#endif /* KEY_H_ */
......@@ -46,41 +46,81 @@
#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 */
k = EVP_PKEY_new();
if (k == NULL) {
key->key = EVP_PKEY_new();
if (key->key == NULL) {
return 0;
}
/* Generate a new RSA key */
rsa = RSA_generate_key(RSA_KEY_BITS, RSA_F4, NULL, NULL);
if (EVP_PKEY_assign_RSA(k, rsa)) {
key->key = k;
return 1;
} else {
printf("Cannot assign RSA key\n");
return 1;
}
int key_create(key_t *key, int type)
{
RSA *rsa = NULL;
EC_KEY *ec = NULL;
/* Create OpenSSL key container */
if (!key_new(key)) {
goto err;
}
if (k)
EVP_PKEY_free(k);
switch (type) {
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;
}
int key_load(key_t *key)
int key_load(key_t *key, unsigned int *err_code)
{
FILE *fp = NULL;
EVP_PKEY *k = NULL;
/* Create key pair container */
k = EVP_PKEY_new();
if (k == NULL) {
/* Create OpenSSL key container */
if (!key_new(key)) {
*err_code = KEY_ERR_MALLOC;
return 0;
}
......@@ -88,24 +128,24 @@ int key_load(key_t *key)
/* Load key from file */
fp = fopen(key->fn, "r");
if (fp) {
k = PEM_read_PrivateKey(fp, &k, NULL, NULL);
k = PEM_read_PrivateKey(fp, &key->key, NULL, NULL);
fclose(fp);
if (k) {
key->key = k;
*err_code = KEY_ERR_NONE;
return 1;
} 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 {
ERROR("Cannot open file %s\n", key->fn);
WARN("Cannot open file %s\n", key->fn);
*err_code = KEY_ERR_OPEN;
}
} 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;
}
......
......@@ -80,6 +80,7 @@
#define VAL_DAYS 7300
#define ID_TO_BIT_MASK(id) (1 << id)
#define NVCOUNTER_VALUE 0
#define NUM_ELEM(x) ((sizeof(x)) / (sizeof(x[0])))
/* Files */
enum {
......@@ -112,6 +113,7 @@ enum {
};
/* Global options */
static int key_alg;
static int new_keys;
static int save_keys;
static int print_cert;
......@@ -138,6 +140,11 @@ static char *strdup(const char *str)
return dup;
}
static const char *key_algs_str[] = {
[KEY_ALG_RSA] = "rsa",
[KEY_ALG_ECDSA] = "ecdsa"
};
/* Command line options */
static const struct option long_opt[] = {
/* Binary images */
......@@ -166,6 +173,7 @@ static const struct option long_opt[] = {
{"bl32-key", required_argument, 0, BL32_KEY_ID},
{"bl33-key", required_argument, 0, BL33_KEY_ID},
/* Common options */
{"key-alg", required_argument, 0, 'a'},
{"help", no_argument, 0, 'h'},
{"save-keys", no_argument, 0, 'k'},
{"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("\n");
printf("-a Key algorithm: rsa (default), ecdsa\n");
printf("-h Print help and exit\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");
......@@ -198,8 +207,27 @@ static void print_help(const char *cmd)
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)
{
/* 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 */
if (certs[BL2_CERT].bin == NULL) {
ERROR("BL2 image not specified\n");
......@@ -276,15 +304,19 @@ int main(int argc, char *argv[])
FILE *file = NULL;
int i, tz_nvctr_nid, ntz_nvctr_nid, hash_nid, pk_nid;
int c, opt_idx = 0;
unsigned int err_code;
unsigned char md[SHA256_DIGEST_LENGTH];
const EVP_MD *md_info;
NOTICE("CoT Generation Tool: %s\n", build_msg);
NOTICE("Target platform: %s\n", platform_msg);
/* Set default options */
key_alg = KEY_ALG_RSA;
while (1) {
/* 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. */
if (c == -1) {
......@@ -292,6 +324,13 @@ int main(int argc, char *argv[])
}
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':
print_help(argv[0]);
break;
......@@ -399,19 +438,41 @@ int main(int argc, char *argv[])
CHECK_OID(ntz_nvctr_nid, NTZ_FW_NVCOUNTER_OID);
/* Load private keys from files (or generate new ones) */
if (new_keys) {
for (i = 0 ; i < NUM_KEYS ; i++) {
if (!key_new(&keys[i])) {
ERROR("Error creating %s\n", keys[i].desc);
exit(1);
}
for (i = 0 ; i < NUM_KEYS ; i++) {
/* First try to load the key from disk */
if (key_load(&keys[i], &err_code)) {
/* Key loaded successfully */
continue;
}
} else {
for (i = 0 ; i < NUM_KEYS ; i++) {
if (!key_load(&keys[i])) {
ERROR("Error loading %s\n", keys[i].desc);
/* Key not loaded. Check the error code */
if (err_code == KEY_ERR_MALLOC) {
/* 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);
}
} 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);
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment