mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-10 23:24:38 +00:00
efi_loader: image_loader: add digest-based verification for signed image
In case that a type of certificate in "db" or "dbx" is EFI_CERT_X509_SHA256_GUID, it is actually not a certificate which contains a public key for RSA decryption, but a digest of image to be loaded. If the value matches to a value calculated from a given binary image, it is granted for loading. With this patch, common digest check code, which used to be used for unsigned image verification, will be extracted from efi_signature_verify_with_sigdb() into efi_signature_lookup_digest(), and extra step for digest check will be added to efi_image_authenticate(). Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
This commit is contained in:
parent
11bafb2596
commit
7926dfb579
3 changed files with 102 additions and 78 deletions
|
@ -765,6 +765,8 @@ struct efi_signature_store {
|
|||
struct x509_certificate;
|
||||
struct pkcs7_message;
|
||||
|
||||
bool efi_signature_lookup_digest(struct efi_image_regions *regs,
|
||||
struct efi_signature_store *db);
|
||||
bool efi_signature_verify_one(struct efi_image_regions *regs,
|
||||
struct pkcs7_message *msg,
|
||||
struct efi_signature_store *db);
|
||||
|
|
|
@ -448,16 +448,16 @@ static bool efi_image_unsigned_authenticate(struct efi_image_regions *regs)
|
|||
}
|
||||
|
||||
/* try black-list first */
|
||||
if (efi_signature_verify_one(regs, NULL, dbx)) {
|
||||
EFI_PRINT("Image is not signed and rejected by \"dbx\"\n");
|
||||
if (efi_signature_lookup_digest(regs, dbx)) {
|
||||
EFI_PRINT("Image is not signed and its digest found in \"dbx\"\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* try white-list */
|
||||
if (efi_signature_verify_one(regs, NULL, db))
|
||||
if (efi_signature_lookup_digest(regs, db))
|
||||
ret = true;
|
||||
else
|
||||
EFI_PRINT("Image is not signed and not found in \"db\" or \"dbx\"\n");
|
||||
EFI_PRINT("Image is not signed and its digest not found in \"db\" or \"dbx\"\n");
|
||||
|
||||
out:
|
||||
efi_sigstore_free(db);
|
||||
|
@ -605,6 +605,25 @@ static bool efi_image_authenticate(void *efi, size_t efi_size)
|
|||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE:
|
||||
* UEFI specification defines two signature types possible
|
||||
* in signature database:
|
||||
* a. x509 certificate, where a signature in image is
|
||||
* a message digest encrypted by RSA public key
|
||||
* (EFI_CERT_X509_GUID)
|
||||
* b. bare hash value of message digest
|
||||
* (EFI_CERT_SHAxxx_GUID)
|
||||
*
|
||||
* efi_signature_verify() handles case (a), while
|
||||
* efi_signature_lookup_digest() handles case (b).
|
||||
*
|
||||
* There is a third type:
|
||||
* c. message digest of a certificate
|
||||
* (EFI_CERT_X509_SHAAxxx_GUID)
|
||||
* This type of signature is used only in revocation list
|
||||
* (dbx) and handled as part of efi_signatgure_verify().
|
||||
*/
|
||||
/* try black-list first */
|
||||
if (efi_signature_verify_one(regs, msg, dbx)) {
|
||||
EFI_PRINT("Signature was rejected by \"dbx\"\n");
|
||||
|
@ -616,11 +635,22 @@ static bool efi_image_authenticate(void *efi, size_t efi_size)
|
|||
goto err;
|
||||
}
|
||||
|
||||
/* try white-list */
|
||||
if (!efi_signature_verify_with_sigdb(regs, msg, db, dbx)) {
|
||||
EFI_PRINT("Signature was not verified by \"db\"\n");
|
||||
if (efi_signature_lookup_digest(regs, dbx)) {
|
||||
EFI_PRINT("Image's digest was found in \"dbx\"\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* try white-list */
|
||||
if (efi_signature_verify_with_sigdb(regs, msg, db, dbx))
|
||||
continue;
|
||||
|
||||
debug("Signature was not verified by \"db\"\n");
|
||||
|
||||
if (efi_signature_lookup_digest(regs, db))
|
||||
continue;
|
||||
|
||||
debug("Image's digest was not found in \"db\" or \"dbx\"\n");
|
||||
goto err;
|
||||
}
|
||||
ret = true;
|
||||
|
||||
|
|
|
@ -197,6 +197,68 @@ out:
|
|||
return verified;
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_signature_lookup_digest - search for an image's digest in sigdb
|
||||
* @regs: List of regions to be authenticated
|
||||
* @db: Signature database for trusted certificates
|
||||
*
|
||||
* A message digest of image pointed to by @regs is calculated and
|
||||
* its hash value is compared to entries in signature database pointed
|
||||
* to by @db.
|
||||
*
|
||||
* Return: true if found, false if not
|
||||
*/
|
||||
bool efi_signature_lookup_digest(struct efi_image_regions *regs,
|
||||
struct efi_signature_store *db)
|
||||
{
|
||||
struct efi_signature_store *siglist;
|
||||
struct efi_sig_data *sig_data;
|
||||
void *hash = NULL;
|
||||
size_t size = 0;
|
||||
bool found = false;
|
||||
|
||||
EFI_PRINT("%s: Enter, %p, %p\n", __func__, regs, db);
|
||||
|
||||
if (!regs || !db || !db->sig_data_list)
|
||||
goto out;
|
||||
|
||||
for (siglist = db; siglist; siglist = siglist->next) {
|
||||
/* TODO: support other hash algorithms */
|
||||
if (guidcmp(&siglist->sig_type, &efi_guid_sha256)) {
|
||||
EFI_PRINT("Digest algorithm is not supported: %pUl\n",
|
||||
&siglist->sig_type);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!efi_hash_regions(regs->reg, regs->num, &hash, &size)) {
|
||||
EFI_PRINT("Digesting an image failed\n");
|
||||
break;
|
||||
}
|
||||
|
||||
for (sig_data = siglist->sig_data_list; sig_data;
|
||||
sig_data = sig_data->next) {
|
||||
#ifdef DEBUG
|
||||
EFI_PRINT("Msg digest in database:\n");
|
||||
print_hex_dump(" ", DUMP_PREFIX_OFFSET, 16, 1,
|
||||
sig_data->data, sig_data->size, false);
|
||||
#endif
|
||||
if (sig_data->size == size &&
|
||||
!memcmp(sig_data->data, hash, size)) {
|
||||
found = true;
|
||||
free(hash);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
free(hash);
|
||||
hash = NULL;
|
||||
}
|
||||
|
||||
out:
|
||||
EFI_PRINT("%s: Exit, found: %d\n", __func__, found);
|
||||
return found;
|
||||
}
|
||||
|
||||
/**
|
||||
* efi_signature_verify_with_list - verify a signature with signature list
|
||||
* @regs: List of regions to be authenticated
|
||||
|
@ -226,46 +288,6 @@ bool efi_signature_verify_with_list(struct efi_image_regions *regs,
|
|||
EFI_PRINT("%s: Enter, %p, %p, %p, %p\n", __func__,
|
||||
regs, signed_info, siglist, valid_cert);
|
||||
|
||||
if (!signed_info) {
|
||||
void *hash = NULL;
|
||||
size_t size;
|
||||
|
||||
EFI_PRINT("%s: unsigned image\n", __func__);
|
||||
/*
|
||||
* verify based on calculated hash value
|
||||
* TODO: support other hash algorithms
|
||||
*/
|
||||
if (guidcmp(&siglist->sig_type, &efi_guid_sha256)) {
|
||||
EFI_PRINT("Digest algorithm is not supported: %pUl\n",
|
||||
&siglist->sig_type);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!efi_hash_regions(regs->reg, regs->num, &hash, &size)) {
|
||||
EFI_PRINT("Digesting unsigned image failed\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* go through the list */
|
||||
for (sig_data = siglist->sig_data_list; sig_data;
|
||||
sig_data = sig_data->next) {
|
||||
#ifdef DEBUG
|
||||
EFI_PRINT("Msg digest in database:\n");
|
||||
print_hex_dump(" ", DUMP_PREFIX_OFFSET, 16, 1,
|
||||
sig_data->data, sig_data->size, false);
|
||||
#endif
|
||||
if ((sig_data->size == size) &&
|
||||
!memcmp(sig_data->data, hash, size)) {
|
||||
verified = true;
|
||||
free(hash);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
free(hash);
|
||||
goto out;
|
||||
}
|
||||
|
||||
EFI_PRINT("%s: signed image\n", __func__);
|
||||
if (guidcmp(&siglist->sig_type, &efi_guid_cert_x509)) {
|
||||
EFI_PRINT("Signature type is not supported: %pUl\n",
|
||||
&siglist->sig_type);
|
||||
|
@ -412,19 +434,6 @@ bool efi_signature_verify_one(struct efi_image_regions *regs,
|
|||
if (!db->sig_data_list)
|
||||
goto out;
|
||||
|
||||
/* for unsigned image */
|
||||
if (!msg) {
|
||||
EFI_PRINT("%s: Verify unsigned image with db\n", __func__);
|
||||
for (siglist = db; siglist; siglist = siglist->next)
|
||||
if (efi_signature_verify_with_list(regs, NULL, NULL,
|
||||
siglist, &cert)) {
|
||||
verified = true;
|
||||
break;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* for signed image or variable */
|
||||
EFI_PRINT("%s: Verify signed image with db\n", __func__);
|
||||
for (sinfo = msg->signed_infos; sinfo; sinfo = sinfo->next) {
|
||||
EFI_PRINT("Signed Info: digest algo: %s, pkey algo: %s\n",
|
||||
|
@ -468,26 +477,9 @@ bool efi_signature_verify_with_sigdb(struct efi_image_regions *regs,
|
|||
|
||||
EFI_PRINT("%s: Enter, %p, %p, %p, %p\n", __func__, regs, msg, db, dbx);
|
||||
|
||||
if (!db)
|
||||
if (!regs || !msg || !db || !db->sig_data_list)
|
||||
goto out;
|
||||
|
||||
if (!db->sig_data_list)
|
||||
goto out;
|
||||
|
||||
/* for unsigned image */
|
||||
if (!msg) {
|
||||
EFI_PRINT("%s: Verify unsigned image with db\n", __func__);
|
||||
for (siglist = db; siglist; siglist = siglist->next)
|
||||
if (efi_signature_verify_with_list(regs, NULL, NULL,
|
||||
siglist, &cert)) {
|
||||
verified = true;
|
||||
break;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* for signed image or variable */
|
||||
EFI_PRINT("%s: Verify signed image with db\n", __func__);
|
||||
for (info = msg->signed_infos; info; info = info->next) {
|
||||
EFI_PRINT("Signed Info: digest algo: %s, pkey algo: %s\n",
|
||||
info->sig->hash_algo, info->sig->pkey_algo);
|
||||
|
|
Loading…
Reference in a new issue