diff options
Diffstat (limited to 'tools/image-host.c')
| -rw-r--r-- | tools/image-host.c | 152 | 
1 files changed, 151 insertions, 1 deletions
| diff --git a/tools/image-host.c b/tools/image-host.c index e6de34fa059..a9b86902763 100644 --- a/tools/image-host.c +++ b/tools/image-host.c @@ -19,6 +19,11 @@  #include <openssl/evp.h>  #endif +#if CONFIG_IS_ENABLED(IMAGE_PRE_LOAD) +#include <openssl/rsa.h> +#include <openssl/err.h> +#endif +  /**   * fit_set_hash_value - set hash value in requested has node   * @fit: pointer to the FIT format image header @@ -729,11 +734,20 @@ static int strlist_add(struct strlist *list, const char *str)  {  	char *dup; +	if (!list || !str) +		return -1; +  	dup = strdup(str); +	if(!dup) +		return -1; +  	list->strings = realloc(list->strings,  				(list->count + 1) * sizeof(char *)); -	if (!list || !str) +	if (!list->strings) { +		free(dup);  		return -1; +	} +  	list->strings[list->count++] = dup;  	return 0; @@ -1401,3 +1415,139 @@ int fit_check_sign(const void *fit, const void *key,  	return ret;  }  #endif + +#if CONFIG_IS_ENABLED(IMAGE_PRE_LOAD) +/** + * rsa_verify_openssl() - Verify a signature against some data with openssl API + * + * Verify a RSA PKCS1.5/PSS signature against an expected hash. + * + * @info:		Specifies the key and algorithms + * @region:		Pointer to the input data + * @region_count:	Number of region + * @sig:		Signature + * @sig_len:		Number of bytes in the signature + * Return: 0 if verified, -ve on error + */ +int rsa_verify_openssl(struct image_sign_info *info, +		       const struct image_region region[], int region_count, +		       uint8_t *sig, uint sig_len) +{ +	EVP_PKEY *pkey = NULL; +	EVP_PKEY_CTX *ckey = NULL; +	EVP_MD_CTX *ctx = NULL; +	int pad; +	int size; +	int i; +	int ret = 0; + +	if (!info) { +		fprintf(stderr, "No info provided\n"); +		ret = -EINVAL; +		goto out; +	} + +	if (!info->key) { +		fprintf(stderr, "No key provided\n"); +		ret = -EINVAL; +		goto out; +	} + +	if (!info->checksum) { +		fprintf(stderr, "No checksum information\n"); +		ret = -EINVAL; +		goto out; +	} + +	if (!info->padding) { +		fprintf(stderr, "No padding information\n"); +		ret = -EINVAL; +		goto out; +	} + +	if (region_count < 1) { +		fprintf(stderr, "Invalid value for region_count: %d\n", region_count); +		ret = -EINVAL; +		goto out; +	} + +	pkey = (EVP_PKEY *)info->key; + +	ckey = EVP_PKEY_CTX_new(pkey, NULL); +	if (!ckey) { +		ret = -ENOMEM; +		fprintf(stderr, "EVK key context setup failed: %s\n", +			ERR_error_string(ERR_get_error(), NULL)); +		goto out; +	} + +	size = EVP_PKEY_size(pkey); +	if (size > sig_len) { +		fprintf(stderr, "Invalid signature size (%d bytes)\n", +			size); +		ret = -EINVAL; +		goto out; +	} + +	ctx = EVP_MD_CTX_new(); +	if (!ctx) { +		ret = -ENOMEM; +		fprintf(stderr, "EVP context creation failed: %s\n", +			ERR_error_string(ERR_get_error(), NULL)); +		goto out; +	} +	EVP_MD_CTX_init(ctx); + +	if (EVP_DigestVerifyInit(ctx, &ckey, +				 EVP_get_digestbyname(info->checksum->name), +				 NULL, pkey) <= 0) { +		ret = -EINVAL; +		fprintf(stderr, "Verifier setup failed: %s\n", +			ERR_error_string(ERR_get_error(), NULL)); +		goto out; +	} + +	if (!strcmp(info->padding->name, "pkcs-1.5")) { +		pad = RSA_PKCS1_PADDING; +	} else if (!strcmp(info->padding->name, "pss")) { +		pad = RSA_PKCS1_PSS_PADDING; +	} else { +		ret = -ENOMSG; +		fprintf(stderr, "Unsupported padding: %s\n", +			info->padding->name); +		goto out; +	} + +	if (EVP_PKEY_CTX_set_rsa_padding(ckey, pad) <= 0) { +		ret = -EINVAL; +		fprintf(stderr, "padding setup has failed: %s\n", +			ERR_error_string(ERR_get_error(), NULL)); +		goto out; +	} + +	for (i=0 ; i < region_count ; ++i) { +		if (EVP_DigestVerifyUpdate(ctx, region[i].data, +					   region[i].size) <= 0) { +			ret = -EINVAL; +			fprintf(stderr, "Hashing data failed: %s\n", +				ERR_error_string(ERR_get_error(), NULL)); +			goto out; +		} +	} + +	if (EVP_DigestVerifyFinal(ctx, sig, sig_len) <= 0) { +		ret = -EINVAL; +		fprintf(stderr, "Verifying digest failed: %s\n", +			ERR_error_string(ERR_get_error(), NULL)); +		goto out; +	} +out: +	if (ctx) +		EVP_MD_CTX_free(ctx); + +	if (ret) +		fprintf(stderr, "Failed to verify signature\n"); + +	return ret; +} +#endif | 
