提交 55fca74a 编写于 作者: T Tom Rini

Merge branch '2020-10-12-assorted-encryption-changes'

- Fix verified boot on BE targets
- Add support for multiple required keys in verified boots
- Add support for Initialization Vectors in AES keys in FIT images
- Assorted fixes in the RSA code
...@@ -94,9 +94,11 @@ static int fit_image_setup_decrypt(struct image_cipher_info *info, ...@@ -94,9 +94,11 @@ static int fit_image_setup_decrypt(struct image_cipher_info *info,
return -1; return -1;
} }
info->iv = fdt_getprop(fit, cipher_noffset, "iv", NULL);
info->ivname = fdt_getprop(fit, cipher_noffset, "iv-name-hint", NULL); info->ivname = fdt_getprop(fit, cipher_noffset, "iv-name-hint", NULL);
if (!info->ivname) {
printf("Can't get IV name\n"); if (!info->iv && !info->ivname) {
printf("Can't get IV or IV name\n");
return -1; return -1;
} }
...@@ -120,8 +122,12 @@ static int fit_image_setup_decrypt(struct image_cipher_info *info, ...@@ -120,8 +122,12 @@ static int fit_image_setup_decrypt(struct image_cipher_info *info,
* Search the cipher node in the u-boot fdt * Search the cipher node in the u-boot fdt
* the path should be: /cipher/key-<algo>-<key>-<iv> * the path should be: /cipher/key-<algo>-<key>-<iv>
*/ */
snprintf(node_path, sizeof(node_path), "/%s/key-%s-%s-%s", if (info->ivname)
FIT_CIPHER_NODENAME, algo_name, info->keyname, info->ivname); snprintf(node_path, sizeof(node_path), "/%s/key-%s-%s-%s",
FIT_CIPHER_NODENAME, algo_name, info->keyname, info->ivname);
else
snprintf(node_path, sizeof(node_path), "/%s/key-%s-%s",
FIT_CIPHER_NODENAME, algo_name, info->keyname);
noffset = fdt_path_offset(fdt, node_path); noffset = fdt_path_offset(fdt, node_path);
if (noffset < 0) { if (noffset < 0) {
...@@ -137,10 +143,12 @@ static int fit_image_setup_decrypt(struct image_cipher_info *info, ...@@ -137,10 +143,12 @@ static int fit_image_setup_decrypt(struct image_cipher_info *info,
} }
/* read iv */ /* read iv */
info->iv = fdt_getprop(fdt, noffset, "iv", NULL);
if (!info->iv) { if (!info->iv) {
printf("Can't get IV in cipher node '%s'\n", node_path); info->iv = fdt_getprop(fdt, noffset, "iv", NULL);
return -1; if (!info->iv) {
printf("Can't get IV in cipher node '%s'\n", node_path);
return -1;
}
} }
return 0; return 0;
......
...@@ -416,6 +416,10 @@ int fit_config_verify_required_sigs(const void *fit, int conf_noffset, ...@@ -416,6 +416,10 @@ int fit_config_verify_required_sigs(const void *fit, int conf_noffset,
{ {
int noffset; int noffset;
int sig_node; int sig_node;
int verified = 0;
int reqd_sigs = 0;
bool reqd_policy_all = true;
const char *reqd_mode;
/* Work out what we need to verify */ /* Work out what we need to verify */
sig_node = fdt_subnode_offset(sig_blob, 0, FIT_SIG_NODENAME); sig_node = fdt_subnode_offset(sig_blob, 0, FIT_SIG_NODENAME);
...@@ -425,6 +429,14 @@ int fit_config_verify_required_sigs(const void *fit, int conf_noffset, ...@@ -425,6 +429,14 @@ int fit_config_verify_required_sigs(const void *fit, int conf_noffset,
return 0; return 0;
} }
/* Get required-mode policy property from DTB */
reqd_mode = fdt_getprop(sig_blob, sig_node, "required-mode", NULL);
if (reqd_mode && !strcmp(reqd_mode, "any"))
reqd_policy_all = false;
debug("%s: required-mode policy set to '%s'\n", __func__,
reqd_policy_all ? "all" : "any");
fdt_for_each_subnode(noffset, sig_blob, sig_node) { fdt_for_each_subnode(noffset, sig_blob, sig_node) {
const char *required; const char *required;
int ret; int ret;
...@@ -433,15 +445,29 @@ int fit_config_verify_required_sigs(const void *fit, int conf_noffset, ...@@ -433,15 +445,29 @@ int fit_config_verify_required_sigs(const void *fit, int conf_noffset,
NULL); NULL);
if (!required || strcmp(required, "conf")) if (!required || strcmp(required, "conf"))
continue; continue;
reqd_sigs++;
ret = fit_config_verify_sig(fit, conf_noffset, sig_blob, ret = fit_config_verify_sig(fit, conf_noffset, sig_blob,
noffset); noffset);
if (ret) { if (ret) {
printf("Failed to verify required signature '%s'\n", if (reqd_policy_all) {
fit_get_name(sig_blob, noffset, NULL)); printf("Failed to verify required signature '%s'\n",
return ret; fit_get_name(sig_blob, noffset, NULL));
return ret;
}
} else {
verified++;
if (!reqd_policy_all)
break;
} }
} }
if (reqd_sigs && !verified) {
printf("Failed to verify 'any' of the required signature(s)\n");
return -EPERM;
}
return 0; return 0;
} }
......
...@@ -386,6 +386,20 @@ that might be used by the target needs to be signed with 'required' keys. ...@@ -386,6 +386,20 @@ that might be used by the target needs to be signed with 'required' keys.
This happens automatically as part of a bootm command when FITs are used. This happens automatically as part of a bootm command when FITs are used.
For Signed Configurations, the default verification behavior can be changed by
the following optional property in /signature node in U-Boot's control FDT.
- required-mode: Valid values are "any" to allow verified boot to succeed if
the selected configuration is signed by any of the 'required' keys, and "all"
to allow verified boot to succeed if the selected configuration is signed by
all of the 'required' keys.
This property can be added to a binary device tree using fdtput as shown in
below examples::
fdtput -t s control.dtb /signature required-mode any
fdtput -t s control.dtb /signature required-mode all
Enabling FIT Verification Enabling FIT Verification
------------------------- -------------------------
......
...@@ -1463,7 +1463,7 @@ struct cipher_algo { ...@@ -1463,7 +1463,7 @@ struct cipher_algo {
unsigned char **cipher, int *cipher_len); unsigned char **cipher, int *cipher_len);
int (*add_cipher_data)(struct image_cipher_info *info, int (*add_cipher_data)(struct image_cipher_info *info,
void *keydest); void *keydest, void *fit, int node_noffset);
int (*decrypt)(struct image_cipher_info *info, int (*decrypt)(struct image_cipher_info *info,
const void *cipher, size_t cipher_len, const void *cipher, size_t cipher_len,
......
...@@ -13,7 +13,8 @@ ...@@ -13,7 +13,8 @@
int image_aes_encrypt(struct image_cipher_info *info, int image_aes_encrypt(struct image_cipher_info *info,
const unsigned char *data, int size, const unsigned char *data, int size,
unsigned char **cipher, int *cipher_len); unsigned char **cipher, int *cipher_len);
int image_aes_add_cipher_data(struct image_cipher_info *info, void *keydest); int image_aes_add_cipher_data(struct image_cipher_info *info, void *keydest,
void *fit, int node_noffset);
#else #else
int image_aes_encrypt(struct image_cipher_info *info, int image_aes_encrypt(struct image_cipher_info *info,
const unsigned char *data, int size, const unsigned char *data, int size,
...@@ -22,7 +23,8 @@ int image_aes_encrypt(struct image_cipher_info *info, ...@@ -22,7 +23,8 @@ int image_aes_encrypt(struct image_cipher_info *info,
return -ENXIO; return -ENXIO;
} }
int image_aes_add_cipher_data(struct image_cipher_info *info, void *keydest) int image_aes_add_cipher_data(struct image_cipher_info *info, void *keydest,
void *fit, int node_noffset)
{ {
return -ENXIO; return -ENXIO;
} }
......
...@@ -74,7 +74,8 @@ int image_aes_encrypt(struct image_cipher_info *info, ...@@ -74,7 +74,8 @@ int image_aes_encrypt(struct image_cipher_info *info,
return ret; return ret;
} }
int image_aes_add_cipher_data(struct image_cipher_info *info, void *keydest) int image_aes_add_cipher_data(struct image_cipher_info *info, void *keydest,
void *fit, int node_noffset)
{ {
int parent, node; int parent, node;
char name[128]; char name[128];
...@@ -97,8 +98,13 @@ int image_aes_add_cipher_data(struct image_cipher_info *info, void *keydest) ...@@ -97,8 +98,13 @@ int image_aes_add_cipher_data(struct image_cipher_info *info, void *keydest)
goto done; goto done;
/* Either create or overwrite the named key node */ /* Either create or overwrite the named key node */
snprintf(name, sizeof(name), "key-%s-%s-%s", if (info->ivname)
info->name, info->keyname, info->ivname); snprintf(name, sizeof(name), "key-%s-%s-%s",
info->name, info->keyname, info->ivname);
else
snprintf(name, sizeof(name), "key-%s-%s",
info->name, info->keyname);
node = fdt_subnode_offset(keydest, parent, name); node = fdt_subnode_offset(keydest, parent, name);
if (node == -FDT_ERR_NOTFOUND) { if (node == -FDT_ERR_NOTFOUND) {
node = fdt_add_subnode(keydest, parent, name); node = fdt_add_subnode(keydest, parent, name);
...@@ -116,9 +122,17 @@ int image_aes_add_cipher_data(struct image_cipher_info *info, void *keydest) ...@@ -116,9 +122,17 @@ int image_aes_add_cipher_data(struct image_cipher_info *info, void *keydest)
ret = node; ret = node;
} }
if (!ret) if (ret)
goto done;
if (info->ivname)
/* Store the IV in the u-boot device tree */
ret = fdt_setprop(keydest, node, "iv", ret = fdt_setprop(keydest, node, "iv",
info->iv, info->cipher->iv_len); info->iv, info->cipher->iv_len);
else
/* Store the IV in the FIT image */
ret = fdt_setprop(fit, node_noffset, "iv",
info->iv, info->cipher->iv_len);
if (!ret) if (!ret)
ret = fdt_setprop(keydest, node, "key", ret = fdt_setprop(keydest, node, "key",
......
...@@ -324,8 +324,7 @@ int hsearch_r(struct env_entry item, enum env_action action, ...@@ -324,8 +324,7 @@ int hsearch_r(struct env_entry item, enum env_action action,
*/ */
unsigned hval2; unsigned hval2;
if (htab->table[idx].used == USED_DELETED if (htab->table[idx].used == USED_DELETED)
&& !first_deleted)
first_deleted = idx; first_deleted = idx;
ret = _compare_and_overwrite_entry(item, action, retval, htab, ret = _compare_and_overwrite_entry(item, action, retval, htab,
......
...@@ -25,6 +25,14 @@ ...@@ -25,6 +25,14 @@
#define get_unaligned_be32(a) fdt32_to_cpu(*(uint32_t *)a) #define get_unaligned_be32(a) fdt32_to_cpu(*(uint32_t *)a)
#define put_unaligned_be32(a, b) (*(uint32_t *)(b) = cpu_to_fdt32(a)) #define put_unaligned_be32(a, b) (*(uint32_t *)(b) = cpu_to_fdt32(a))
static inline uint64_t fdt64_to_cpup(const void *p)
{
fdt64_t w;
memcpy(&w, p, sizeof(w));
return fdt64_to_cpu(w);
}
/* Default public exponent for backward compatibility */ /* Default public exponent for backward compatibility */
#define RSA_DEFAULT_PUBEXP 65537 #define RSA_DEFAULT_PUBEXP 65537
...@@ -263,8 +271,7 @@ int rsa_mod_exp_sw(const uint8_t *sig, uint32_t sig_len, ...@@ -263,8 +271,7 @@ int rsa_mod_exp_sw(const uint8_t *sig, uint32_t sig_len,
if (!prop->public_exponent) if (!prop->public_exponent)
key.exponent = RSA_DEFAULT_PUBEXP; key.exponent = RSA_DEFAULT_PUBEXP;
else else
rsa_convert_big_endian((uint32_t *)&key.exponent, key.exponent = fdt64_to_cpup(prop->public_exponent);
prop->public_exponent, 2);
if (!key.len || !prop->modulus || !prop->rr) { if (!key.len || !prop->modulus || !prop->rr) {
debug("%s: Missing RSA key info", __func__); debug("%s: Missing RSA key info", __func__);
......
...@@ -439,12 +439,17 @@ static int rsa_verify_with_keynode(struct image_sign_info *info, ...@@ -439,12 +439,17 @@ static int rsa_verify_with_keynode(struct image_sign_info *info,
struct key_prop prop; struct key_prop prop;
int length; int length;
int ret = 0; int ret = 0;
const char *algo;
if (node < 0) { if (node < 0) {
debug("%s: Skipping invalid node", __func__); debug("%s: Skipping invalid node", __func__);
return -EBADF; return -EBADF;
} }
algo = fdt_getprop(blob, node, "algo", NULL);
if (strcmp(info->name, algo))
return -EFAULT;
prop.num_bits = fdtdec_get_int(blob, node, "rsa,num-bits", 0); prop.num_bits = fdtdec_get_int(blob, node, "rsa,num-bits", 0);
prop.n0inv = fdtdec_get_int(blob, node, "rsa,n0-inverse", 0); prop.n0inv = fdtdec_get_int(blob, node, "rsa,n0-inverse", 0);
...@@ -540,7 +545,7 @@ int rsa_verify(struct image_sign_info *info, ...@@ -540,7 +545,7 @@ int rsa_verify(struct image_sign_info *info,
{ {
/* Reserve memory for maximum checksum-length */ /* Reserve memory for maximum checksum-length */
uint8_t hash[info->crypto->key_len]; uint8_t hash[info->crypto->key_len];
int ret = -EACCES; int ret;
/* /*
* Verify that the checksum-length does not exceed the * Verify that the checksum-length does not exceed the
......
...@@ -126,6 +126,23 @@ def test_vboot(u_boot_console, sha_algo, padding, sign_options, required): ...@@ -126,6 +126,23 @@ def test_vboot(u_boot_console, sha_algo, padding, sign_options, required):
cons.log.action('%s: Sign images' % sha_algo) cons.log.action('%s: Sign images' % sha_algo)
util.run_and_log(cons, args) util.run_and_log(cons, args)
def sign_fit_norequire(sha_algo, options):
"""Sign the FIT
Signs the FIT and writes the signature into it. It also writes the
public key into the dtb. It does not mark key as 'required' in dtb.
Args:
sha_algo: Either 'sha1' or 'sha256', to select the algorithm to
use.
options: Options to provide to mkimage.
"""
args = [mkimage, '-F', '-k', tmpdir, '-K', dtb, fit]
if options:
args += options.split(' ')
cons.log.action('%s: Sign images' % sha_algo)
util.run_and_log(cons, args)
def replace_fit_totalsize(size): def replace_fit_totalsize(size):
"""Replace FIT header's totalsize with something greater. """Replace FIT header's totalsize with something greater.
...@@ -279,15 +296,40 @@ def test_vboot(u_boot_console, sha_algo, padding, sign_options, required): ...@@ -279,15 +296,40 @@ def test_vboot(u_boot_console, sha_algo, padding, sign_options, required):
# Build the FIT with dev key (keys NOT required). This adds the # Build the FIT with dev key (keys NOT required). This adds the
# signature into sandbox-u-boot.dtb, NOT marked 'required'. # signature into sandbox-u-boot.dtb, NOT marked 'required'.
make_fit('sign-configs-%s%s.its' % (sha_algo, padding)) make_fit('sign-configs-%s%s.its' % (sha_algo, padding))
sign_fit(sha_algo, sign_options) sign_fit_norequire(sha_algo, sign_options)
# So now sandbox-u-boot.dtb two signatures, for the prod and dev keys. # So now sandbox-u-boot.dtb two signatures, for the prod and dev keys.
# Only the prod key is set as 'required'. But FIT we just built has # Only the prod key is set as 'required'. But FIT we just built has
# a dev signature only (sign_fit() overwrites the FIT). # a dev signature only (sign_fit_norequire() overwrites the FIT).
# Try to boot the FIT with dev key. This FIT should not be accepted by # Try to boot the FIT with dev key. This FIT should not be accepted by
# U-Boot because the prod key is required. # U-Boot because the prod key is required.
run_bootm(sha_algo, 'required key', '', False) run_bootm(sha_algo, 'required key', '', False)
# Build the FIT with dev key (keys required) and sign it. This puts the
# signature into sandbox-u-boot.dtb, marked 'required'.
make_fit('sign-configs-%s%s.its' % (sha_algo, padding))
sign_fit(sha_algo, sign_options)
# Set the required-mode policy to "any".
# So now sandbox-u-boot.dtb two signatures, for the prod and dev keys.
# Both the dev and prod key are set as 'required'. But FIT we just built has
# a dev signature only (sign_fit() overwrites the FIT).
# Try to boot the FIT with dev key. This FIT should be accepted by
# U-Boot because the dev key is required and policy is "any" required key.
util.run_and_log(cons, 'fdtput -t s %s /signature required-mode any' %
(dtb))
run_bootm(sha_algo, 'multi required key', 'dev+', True)
# Set the required-mode policy to "all".
# So now sandbox-u-boot.dtb two signatures, for the prod and dev keys.
# Both the dev and prod key are set as 'required'. But FIT we just built has
# a dev signature only (sign_fit() overwrites the FIT).
# Try to boot the FIT with dev key. This FIT should not be accepted by
# U-Boot because the prod key is required and policy is "all" required key
util.run_and_log(cons, 'fdtput -t s %s /signature required-mode all' %
(dtb))
run_bootm(sha_algo, 'multi required key', '', False)
cons = u_boot_console cons = u_boot_console
tmpdir = cons.config.result_dir + '/' tmpdir = cons.config.result_dir + '/'
datadir = cons.config.source_dir + '/test/py/tests/vboot/' datadir = cons.config.source_dir + '/test/py/tests/vboot/'
......
...@@ -320,6 +320,36 @@ err: ...@@ -320,6 +320,36 @@ err:
return ret; return ret;
} }
static int get_random_data(void *data, int size)
{
unsigned char *tmp = data;
struct timespec date;
int i, ret = 0;
if (!tmp) {
printf("%s: pointer data is NULL\n", __func__);
ret = -1;
goto out;
}
ret = clock_gettime(CLOCK_MONOTONIC, &date);
if (ret < 0) {
printf("%s: clock_gettime has failed (err=%d, str=%s)\n",
__func__, ret, strerror(ret));
goto out;
}
srand(date.tv_nsec);
for (i = 0; i < size; i++) {
*tmp = rand() & 0xff;
tmp++;
}
out:
return ret;
}
static int fit_image_setup_cipher(struct image_cipher_info *info, static int fit_image_setup_cipher(struct image_cipher_info *info,
const char *keydir, void *fit, const char *keydir, void *fit,
const char *image_name, int image_noffset, const char *image_name, int image_noffset,
...@@ -345,13 +375,13 @@ static int fit_image_setup_cipher(struct image_cipher_info *info, ...@@ -345,13 +375,13 @@ static int fit_image_setup_cipher(struct image_cipher_info *info,
goto out; goto out;
} }
/* Read the IV name */ /*
* Read the IV name
*
* If this property is not provided then mkimage will generate
* a random IV and store it in the FIT image
*/
info->ivname = fdt_getprop(fit, noffset, "iv-name-hint", NULL); info->ivname = fdt_getprop(fit, noffset, "iv-name-hint", NULL);
if (!info->ivname) {
printf("Can't get iv name for cipher in image '%s'\n",
image_name);
goto out;
}
info->fit = fit; info->fit = fit;
info->node_noffset = noffset; info->node_noffset = noffset;
...@@ -377,17 +407,23 @@ static int fit_image_setup_cipher(struct image_cipher_info *info, ...@@ -377,17 +407,23 @@ static int fit_image_setup_cipher(struct image_cipher_info *info,
if (ret < 0) if (ret < 0)
goto out; goto out;
/* Read the IV in the file */
snprintf(filename, sizeof(filename), "%s/%s%s",
info->keydir, info->ivname, ".bin");
info->iv = malloc(info->cipher->iv_len); info->iv = malloc(info->cipher->iv_len);
if (!info->iv) { if (!info->iv) {
printf("Can't allocate memory for iv\n"); printf("Can't allocate memory for iv\n");
ret = -1; ret = -1;
goto out; goto out;
} }
ret = fit_image_read_data(filename, (unsigned char *)info->iv,
info->cipher->iv_len); if (info->ivname) {
/* Read the IV in the file */
snprintf(filename, sizeof(filename), "%s/%s%s",
info->keydir, info->ivname, ".bin");
ret = fit_image_read_data(filename, (unsigned char *)info->iv,
info->cipher->iv_len);
} else {
/* Generate an ramdom IV */
ret = get_random_data((void *)info->iv, info->cipher->iv_len);
}
out: out:
return ret; return ret;
...@@ -453,9 +489,10 @@ fit_image_process_cipher(const char *keydir, void *keydest, void *fit, ...@@ -453,9 +489,10 @@ fit_image_process_cipher(const char *keydir, void *keydest, void *fit,
* Write the public key into the supplied FDT file; this might fail * Write the public key into the supplied FDT file; this might fail
* several times, since we try signing with successively increasing * several times, since we try signing with successively increasing
* size values * size values
* And, if needed, write the iv in the FIT file
*/ */
if (keydest) { if (keydest) {
ret = info.cipher->add_cipher_data(&info, keydest); ret = info.cipher->add_cipher_data(&info, keydest, fit, node_noffset);
if (ret) { if (ret) {
printf("Failed to add verification data for cipher '%s' in image '%s'\n", printf("Failed to add verification data for cipher '%s' in image '%s'\n",
info.keyname, image_name); info.keyname, image_name);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册