rsa: add a structure for the padding
The rsa signature use a padding algorithm. By default, we use the
padding pkcs-1.5. In order to add some new padding algorithm, we
add a padding framework to manage several padding algorithm.
The choice of the padding is done in the file .its.
Signed-off-by: Philippe Reynes <philippe.reynes@softathome.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
diff --git a/common/image-fit.c b/common/image-fit.c
index 8d39a24..ac901e1 100644
--- a/common/image-fit.c
+++ b/common/image-fit.c
@@ -165,6 +165,7 @@
uint8_t *value;
int value_len;
char *algo;
+ const char *padding;
int required;
int ret, i;
@@ -184,6 +185,10 @@
printf(" (required)");
printf("\n");
+ padding = fdt_getprop(fit, noffset, "padding", NULL);
+ if (padding)
+ printf("%s %s padding: %s\n", p, type, padding);
+
ret = fit_image_hash_get_value(fit, noffset, &value,
&value_len);
printf("%s %s value: ", p, type);
diff --git a/common/image-sig.c b/common/image-sig.c
index 5d860e1..3d8281f 100644
--- a/common/image-sig.c
+++ b/common/image-sig.c
@@ -71,6 +71,13 @@
};
+struct padding_algo padding_algos[] = {
+ {
+ .name = "pkcs-1.5",
+ .verify = padding_pkcs_15_verify,
+ },
+};
+
struct checksum_algo *image_get_checksum_algo(const char *full_name)
{
int i;
@@ -106,6 +113,21 @@
return NULL;
}
+struct padding_algo *image_get_padding_algo(const char *name)
+{
+ int i;
+
+ if (!name)
+ return NULL;
+
+ for (i = 0; i < ARRAY_SIZE(padding_algos); i++) {
+ if (!strcmp(padding_algos[i].name, name))
+ return &padding_algos[i];
+ }
+
+ return NULL;
+}
+
/**
* fit_region_make_list() - Make a list of image regions
*
@@ -155,6 +177,7 @@
char **err_msgp)
{
char *algo_name;
+ const char *padding_name;
if (fdt_totalsize(fit) > CONFIG_FIT_SIGNATURE_MAX_SIZE) {
*err_msgp = "Total size too large";
@@ -165,6 +188,11 @@
*err_msgp = "Can't get hash algo property";
return -1;
}
+
+ padding_name = fdt_getprop(fit, noffset, "padding", NULL);
+ if (!padding_name)
+ padding_name = RSA_DEFAULT_PADDING_NAME;
+
memset(info, '\0', sizeof(*info));
info->keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL);
info->fit = (void *)fit;
@@ -172,6 +200,7 @@
info->name = algo_name;
info->checksum = image_get_checksum_algo(algo_name);
info->crypto = image_get_crypto_algo(algo_name);
+ info->padding = image_get_padding_algo(padding_name);
info->fdt_blob = gd_fdt_blob();
info->required_keynode = required_keynode;
printf("%s:%s", algo_name, info->keyname);
diff --git a/include/image.h b/include/image.h
index f67502e..e75d176 100644
--- a/include/image.h
+++ b/include/image.h
@@ -1101,6 +1101,7 @@
int node_offset; /* Offset of signature node */
const char *name; /* Algorithm name */
struct checksum_algo *checksum; /* Checksum algorithm information */
+ struct padding_algo *padding; /* Padding algorithm information */
struct crypto_algo *crypto; /* Crypto algorithm information */
const void *fdt_blob; /* FDT containing public keys */
int required_keynode; /* Node offset of key to use: -1=any */
@@ -1186,6 +1187,13 @@
uint8_t *sig, uint sig_len);
};
+struct padding_algo {
+ const char *name;
+ int (*verify)(struct image_sign_info *info,
+ uint8_t *pad, int pad_len,
+ const uint8_t *hash, int hash_len);
+};
+
/**
* image_get_checksum_algo() - Look up a checksum algorithm
*
@@ -1203,6 +1211,14 @@
struct crypto_algo *image_get_crypto_algo(const char *full_name);
/**
+ * image_get_padding_algo() - Look up a padding algorithm
+ *
+ * @param name Name of padding algorithm
+ * @return pointer to algorithm information, or NULL if not found
+ */
+struct padding_algo *image_get_padding_algo(const char *name);
+
+/**
* fit_image_verify_required_sigs() - Verify signatures marked as 'required'
*
* @fit: FIT to check
diff --git a/include/u-boot/rsa.h b/include/u-boot/rsa.h
index 68bcb14..16b4c4c 100644
--- a/include/u-boot/rsa.h
+++ b/include/u-boot/rsa.h
@@ -97,6 +97,10 @@
int rsa_verify(struct image_sign_info *info,
const struct image_region region[], int region_count,
uint8_t *sig, uint sig_len);
+
+int padding_pkcs_15_verify(struct image_sign_info *info,
+ uint8_t *msg, int msg_len,
+ const uint8_t *hash, int hash_len);
#else
static inline int rsa_verify(struct image_sign_info *info,
const struct image_region region[], int region_count,
@@ -104,8 +108,17 @@
{
return -ENXIO;
}
+
+static inline int padding_pkcs_15_verify(struct image_sign_info *info,
+ uint8_t *msg, int msg_len,
+ const uint8_t *hash, int hash_len)
+{
+ return -ENXIO;
+}
#endif
+#define RSA_DEFAULT_PADDING_NAME "pkcs-1.5"
+
#define RSA2048_BYTES (2048 / 8)
#define RSA4096_BYTES (4096 / 8)
diff --git a/lib/rsa/rsa-sign.c b/lib/rsa/rsa-sign.c
index 78e348e..6aa0e2a 100644
--- a/lib/rsa/rsa-sign.c
+++ b/lib/rsa/rsa-sign.c
@@ -387,11 +387,13 @@
}
}
-static int rsa_sign_with_key(RSA *rsa, struct checksum_algo *checksum_algo,
+static int rsa_sign_with_key(RSA *rsa, struct padding_algo *padding_algo,
+ struct checksum_algo *checksum_algo,
const struct image_region region[], int region_count,
uint8_t **sigp, uint *sig_size)
{
EVP_PKEY *key;
+ EVP_PKEY_CTX *ckey;
EVP_MD_CTX *context;
int ret = 0;
size_t size;
@@ -422,7 +424,14 @@
goto err_create;
}
EVP_MD_CTX_init(context);
- if (EVP_DigestSignInit(context, NULL,
+
+ ckey = EVP_PKEY_CTX_new(key, NULL);
+ if (!ckey) {
+ ret = rsa_err("EVP key context creation failed");
+ goto err_create;
+ }
+
+ if (EVP_DigestSignInit(context, &ckey,
checksum_algo->calculate_sign(),
NULL, key) <= 0) {
ret = rsa_err("Signer setup failed");
@@ -488,7 +497,7 @@
ret = rsa_get_priv_key(info->keydir, info->keyname, e, &rsa);
if (ret)
goto err_priv;
- ret = rsa_sign_with_key(rsa, info->checksum, region,
+ ret = rsa_sign_with_key(rsa, info->padding, info->checksum, region,
region_count, sigp, sig_len);
if (ret)
goto err_sign;
diff --git a/lib/rsa/rsa-verify.c b/lib/rsa/rsa-verify.c
index bc83354..279a9ba 100644
--- a/lib/rsa/rsa-verify.c
+++ b/lib/rsa/rsa-verify.c
@@ -57,31 +57,57 @@
return ret;
}
+int padding_pkcs_15_verify(struct image_sign_info *info,
+ uint8_t *msg, int msg_len,
+ const uint8_t *hash, int hash_len)
+{
+ struct checksum_algo *checksum = info->checksum;
+ int ret, pad_len = msg_len - checksum->checksum_len;
+
+ /* Check pkcs1.5 padding bytes. */
+ ret = rsa_verify_padding(msg, pad_len, checksum);
+ if (ret) {
+ debug("In RSAVerify(): Padding check failed!\n");
+ return -EINVAL;
+ }
+
+ /* Check hash. */
+ if (memcmp((uint8_t *)msg + pad_len, hash, msg_len - pad_len)) {
+ debug("In RSAVerify(): Hash check failed!\n");
+ return -EACCES;
+ }
+
+ return 0;
+}
+
/**
* rsa_verify_key() - Verify a signature against some data using RSA Key
*
* Verify a RSA PKCS1.5 signature against an expected hash using
* the RSA Key properties in prop structure.
*
+ * @info: Specifies key and FIT information
* @prop: Specifies key
* @sig: Signature
* @sig_len: Number of bytes in signature
* @hash: Pointer to the expected hash
* @key_len: Number of bytes in rsa key
- * @algo: Checksum algo structure having information on DER encoding etc.
* @return 0 if verified, -ve on error
*/
-static int rsa_verify_key(struct key_prop *prop, const uint8_t *sig,
+static int rsa_verify_key(struct image_sign_info *info,
+ struct key_prop *prop, const uint8_t *sig,
const uint32_t sig_len, const uint8_t *hash,
- const uint32_t key_len, struct checksum_algo *algo)
+ const uint32_t key_len)
{
- int pad_len;
int ret;
#if !defined(USE_HOSTCC)
struct udevice *mod_exp_dev;
#endif
+ struct checksum_algo *checksum = info->checksum;
+ struct padding_algo *padding = info->padding;
+ int hash_len = checksum->checksum_len;
- if (!prop || !sig || !hash || !algo)
+ if (!prop || !sig || !hash || !checksum)
return -EIO;
if (sig_len != (prop->num_bits / 8)) {
@@ -89,7 +115,7 @@
return -EINVAL;
}
- debug("Checksum algorithm: %s", algo->name);
+ debug("Checksum algorithm: %s", checksum->name);
/* Sanity check for stack size */
if (sig_len > RSA_MAX_SIG_BITS / 8) {
@@ -116,19 +142,10 @@
return ret;
}
- pad_len = key_len - algo->checksum_len;
-
- /* Check pkcs1.5 padding bytes. */
- ret = rsa_verify_padding(buf, pad_len, algo);
+ ret = padding->verify(info, buf, key_len, hash, hash_len);
if (ret) {
- debug("In RSAVerify(): Padding check failed!\n");
- return -EINVAL;
- }
-
- /* Check hash. */
- if (memcmp((uint8_t *)buf + pad_len, hash, sig_len - pad_len)) {
- debug("In RSAVerify(): Hash check failed!\n");
- return -EACCES;
+ debug("In RSAVerify(): padding check failed!\n");
+ return ret;
}
return 0;
@@ -182,8 +199,8 @@
return -EFAULT;
}
- ret = rsa_verify_key(&prop, sig, sig_len, hash,
- info->crypto->key_len, info->checksum);
+ ret = rsa_verify_key(info, &prop, sig, sig_len, hash,
+ info->crypto->key_len);
return ret;
}
diff --git a/tools/image-host.c b/tools/image-host.c
index 09e4f47..88b3295 100644
--- a/tools/image-host.c
+++ b/tools/image-host.c
@@ -157,6 +157,7 @@
{
const char *node_name;
char *algo_name;
+ const char *padding_name;
node_name = fit_get_name(fit, noffset, NULL);
if (fit_image_hash_get_algo(fit, noffset, &algo_name)) {
@@ -165,6 +166,8 @@
return -1;
}
+ padding_name = fdt_getprop(fit, noffset, "padding", NULL);
+
memset(info, '\0', sizeof(*info));
info->keydir = keydir;
info->keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL);
@@ -173,6 +176,7 @@
info->name = strdup(algo_name);
info->checksum = image_get_checksum_algo(algo_name);
info->crypto = image_get_crypto_algo(algo_name);
+ info->padding = image_get_padding_algo(padding_name);
info->require_keys = require_keys;
info->engine_id = engine_id;
if (!info->checksum || !info->crypto) {