From bc78d22d0f0db58b8a340ebf7d36ea2a217bfeac Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 11 Aug 2020 18:20:50 +0200 Subject: cmd/efidebug: missing initialization of load_options Variable load_options must be initialized to NULL to avoid a segmentation fault when freeing the memory this variable points to. Signed-off-by: Heinrich Schuchardt --- cmd/efidebug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/efidebug.c b/cmd/efidebug.c index d00d4247dc..9874838b00 100644 --- a/cmd/efidebug.c +++ b/cmd/efidebug.c @@ -1126,7 +1126,7 @@ static int do_efi_test_bootmgr(struct cmd_tbl *cmdtp, int flag, efi_uintn_t exit_data_size = 0; u16 *exit_data = NULL; efi_status_t ret; - void *load_options; + void *load_options = NULL; ret = efi_bootmgr_load(&image, &load_options); printf("efi_bootmgr_load() returned: %ld\n", ret & ~EFI_ERROR_MASK); -- cgit From 0658bb29b026a6af434b9e0cdeced5d25bdd206f Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Wed, 12 Aug 2020 09:37:50 +0900 Subject: efi_loader: variable: keep temporary buffer during the authentication This is a bug fix; Setting an authenticated variable may fail due to a memory corruption in the authentication. A temporary buffer will, if needed, be allocated to parse a variable's authentication data, and some portion of buffer, specifically signer's certificates, will be referenced by efi_signature_verify(). So the buffer should be kept valid until the authentication process is finished. Signed-off-by: AKASHI Takahiro Tested-by: Heinrich Schuchardt --- lib/efi_loader/efi_variable.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c index e509d6dbf0..0c06931135 100644 --- a/lib/efi_loader/efi_variable.c +++ b/lib/efi_loader/efi_variable.c @@ -37,16 +37,21 @@ static u8 pkcs7_hdr[] = { * efi_variable_parse_signature - parse a signature in variable * @buf: Pointer to variable's value * @buflen: Length of @buf + * @tmpbuf: Pointer to temporary buffer * * Parse a signature embedded in variable's value and instantiate * a pkcs7_message structure. Since pkcs7_parse_message() accepts only * pkcs7's signedData, some header needed be prepended for correctly * parsing authentication data, particularly for variable's. + * A temporary buffer will be allocated if needed, and it should be + * kept valid during the authentication because some data in the buffer + * will be referenced by efi_signature_verify(). * * Return: Pointer to pkcs7_message structure on success, NULL on error */ static struct pkcs7_message *efi_variable_parse_signature(const void *buf, - size_t buflen) + size_t buflen, + u8 **tmpbuf) { u8 *ebuf; size_t ebuflen, len; @@ -59,7 +64,9 @@ static struct pkcs7_message *efi_variable_parse_signature(const void *buf, if (buflen > sizeof(pkcs7_hdr) && !memcmp(&((u8 *)buf)[4], &pkcs7_hdr[4], 11)) { msg = pkcs7_parse_message(buf, buflen); - goto out; + if (IS_ERR(msg)) + return NULL; + return msg; } /* @@ -94,12 +101,12 @@ static struct pkcs7_message *efi_variable_parse_signature(const void *buf, msg = pkcs7_parse_message(ebuf, ebuflen); - free(ebuf); - -out: - if (IS_ERR(msg)) + if (IS_ERR(msg)) { + free(ebuf); return NULL; + } + *tmpbuf = ebuf; return msg; } @@ -136,6 +143,7 @@ static efi_status_t efi_variable_authenticate(u16 *variable, struct efi_time timestamp; struct rtc_time tm; u64 new_time; + u8 *ebuf; enum efi_auth_var_type var_type; efi_status_t ret; @@ -143,6 +151,7 @@ static efi_status_t efi_variable_authenticate(u16 *variable, truststore = NULL; truststore2 = NULL; regs = NULL; + ebuf = NULL; ret = EFI_SECURITY_VIOLATION; if (*data_size < sizeof(struct efi_variable_authentication_2)) @@ -204,9 +213,12 @@ static efi_status_t efi_variable_authenticate(u16 *variable, /* variable's signature list */ if (auth->auth_info.hdr.dwLength < sizeof(auth->auth_info)) goto err; + + /* ebuf should be kept valid during the authentication */ var_sig = efi_variable_parse_signature(auth->auth_info.cert_data, auth->auth_info.hdr.dwLength - - sizeof(auth->auth_info)); + - sizeof(auth->auth_info), + &ebuf); if (!var_sig) { EFI_PRINT("Parsing variable's signature failed\n"); goto err; @@ -262,6 +274,7 @@ err: efi_sigstore_free(truststore); efi_sigstore_free(truststore2); pkcs7_free_message(var_sig); + free(ebuf); free(regs); return ret; -- cgit From 1115edd8462b047f83fcca4abcf89b68f2d87041 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Tue, 21 Jul 2020 19:35:22 +0900 Subject: efi_loader: signature: rework for intermediate certificates support In this commit, efi_signature_verify(with_sigdb) will be re-implemented using pcks7_verify_one() in order to support certificates chain, where the signer's certificate will be signed by an intermediate CA (certificate authority) and the latter's certificate will also be signed by another CA and so on. What we need to do here is to search for certificates in a signature, build up a chain of certificates and verify one by one. pkcs7_verify_one() handles most of these steps except the last one. pkcs7_verify_one() returns, if succeeded, the last certificate to verify, which can be either a self-signed one or one that should be signed by one of certificates in "db". Re-worked efi_signature_verify() will take care of this step. Signed-off-by: AKASHI Takahiro --- include/efi_loader.h | 8 +- lib/efi_loader/Kconfig | 1 + lib/efi_loader/efi_image_loader.c | 2 +- lib/efi_loader/efi_signature.c | 385 ++++++++++++++++++-------------------- lib/efi_loader/efi_variable.c | 5 +- 5 files changed, 188 insertions(+), 213 deletions(-) diff --git a/include/efi_loader.h b/include/efi_loader.h index 7f0ab1be56..b941b5e994 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -776,10 +776,10 @@ bool efi_signature_lookup_digest(struct efi_image_regions *regs, bool efi_signature_verify_one(struct efi_image_regions *regs, struct pkcs7_message *msg, struct efi_signature_store *db); -bool efi_signature_verify_with_sigdb(struct efi_image_regions *regs, - struct pkcs7_message *msg, - struct efi_signature_store *db, - struct efi_signature_store *dbx); +bool efi_signature_verify(struct efi_image_regions *regs, + struct pkcs7_message *msg, + struct efi_signature_store *db, + struct efi_signature_store *dbx); bool efi_signature_check_signers(struct pkcs7_message *msg, struct efi_signature_store *dbx); diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index 6017ffe9a6..bad1a29ba8 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -205,6 +205,7 @@ config EFI_SECURE_BOOT select ASYMMETRIC_PUBLIC_KEY_SUBTYPE select X509_CERTIFICATE_PARSER select PKCS7_MESSAGE_PARSER + select PKCS7_VERIFY default n help Select this option to enable EFI secure boot support. diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c index fef0bb870c..832bce9394 100644 --- a/lib/efi_loader/efi_image_loader.c +++ b/lib/efi_loader/efi_image_loader.c @@ -641,7 +641,7 @@ static bool efi_image_authenticate(void *efi, size_t efi_size) } /* try white-list */ - if (efi_signature_verify_with_sigdb(regs, msg, db, dbx)) + if (efi_signature_verify(regs, msg, db, dbx)) continue; debug("Signature was not verified by \"db\"\n"); diff --git a/lib/efi_loader/efi_signature.c b/lib/efi_loader/efi_signature.c index fc0314e6d4..f60c0e1f79 100644 --- a/lib/efi_loader/efi_signature.c +++ b/lib/efi_loader/efi_signature.c @@ -10,7 +10,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -60,143 +62,6 @@ static bool efi_hash_regions(struct image_region *regs, int count, return true; } -/** - * efi_hash_msg_content - calculate a hash value of contentInfo - * @msg: Signature - * @hash: Pointer to a pointer to buffer holding a hash value - * @size: Size of buffer to be returned - * - * Calculate a sha256 value of contentInfo in @msg and return a value in @hash. - * - * Return: true on success, false on error - */ -static bool efi_hash_msg_content(struct pkcs7_message *msg, void **hash, - size_t *size) -{ - struct image_region regtmp; - - regtmp.data = msg->data; - regtmp.size = msg->data_len; - - return efi_hash_regions(®tmp, 1, hash, size); -} - -/** - * efi_signature_verify - verify a signature with a certificate - * @regs: List of regions to be authenticated - * @signed_info: Pointer to PKCS7's signed_info - * @cert: x509 certificate - * - * Signature pointed to by @signed_info against image pointed to by @regs - * is verified by a certificate pointed to by @cert. - * @signed_info holds a signature, including a message digest which is to be - * compared with a hash value calculated from @regs. - * - * Return: true if signature is verified, false if not - */ -static bool efi_signature_verify(struct efi_image_regions *regs, - struct pkcs7_message *msg, - struct pkcs7_signed_info *ps_info, - struct x509_certificate *cert) -{ - struct image_sign_info info; - struct image_region regtmp[2]; - void *hash; - size_t size; - char c; - bool verified; - - EFI_PRINT("%s: Enter, %p, %p, %p(issuer: %s, subject: %s)\n", __func__, - regs, ps_info, cert, cert->issuer, cert->subject); - - verified = false; - - memset(&info, '\0', sizeof(info)); - info.padding = image_get_padding_algo("pkcs-1.5"); - /* - * Note: image_get_[checksum|crypto]_algo takes an string - * argument like "," - * TODO: support other hash algorithms - */ - if (!strcmp(ps_info->sig->hash_algo, "sha1")) { - info.checksum = image_get_checksum_algo("sha1,rsa2048"); - info.name = "sha1,rsa2048"; - } else if (!strcmp(ps_info->sig->hash_algo, "sha256")) { - info.checksum = image_get_checksum_algo("sha256,rsa2048"); - info.name = "sha256,rsa2048"; - } else { - EFI_PRINT("unknown msg digest algo: %s\n", - ps_info->sig->hash_algo); - goto out; - } - info.crypto = image_get_crypto_algo(info.name); - - info.key = cert->pub->key; - info.keylen = cert->pub->keylen; - - /* verify signature */ - EFI_PRINT("%s: crypto: %s, signature len:%x\n", __func__, - info.name, ps_info->sig->s_size); - if (ps_info->aa_set & (1UL << sinfo_has_message_digest)) { - EFI_PRINT("%s: RSA verify authentication attribute\n", - __func__); - /* - * NOTE: This path will be executed only for - * PE image authentication - */ - - /* check if hash matches digest first */ - EFI_PRINT("checking msg digest first, len:0x%x\n", - ps_info->msgdigest_len); - -#ifdef DEBUG - EFI_PRINT("hash in database:\n"); - print_hex_dump(" ", DUMP_PREFIX_OFFSET, 16, 1, - ps_info->msgdigest, ps_info->msgdigest_len, - false); -#endif - /* against contentInfo first */ - hash = NULL; - if ((msg->data && efi_hash_msg_content(msg, &hash, &size)) || - /* for signed image */ - efi_hash_regions(regs->reg, regs->num, &hash, &size)) { - /* for authenticated variable */ - if (ps_info->msgdigest_len != size || - memcmp(hash, ps_info->msgdigest, size)) { - EFI_PRINT("Digest doesn't match\n"); - free(hash); - goto out; - } - - free(hash); - } else { - EFI_PRINT("Digesting image failed\n"); - goto out; - } - - /* against digest */ - c = 0x31; - regtmp[0].data = &c; - regtmp[0].size = 1; - regtmp[1].data = ps_info->authattrs; - regtmp[1].size = ps_info->authattrs_len; - - if (!rsa_verify(&info, regtmp, 2, - ps_info->sig->s, ps_info->sig->s_size)) - verified = true; - } else { - EFI_PRINT("%s: RSA verify content data\n", __func__); - /* against all data */ - if (!rsa_verify(&info, regs->reg, regs->num, - ps_info->sig->s, ps_info->sig->s_size)) - verified = true; - } - -out: - EFI_PRINT("%s: Exit, verified: %d\n", __func__, verified); - return verified; -} - /** * efi_signature_lookup_digest - search for an image's digest in sigdb * @regs: List of regions to be authenticated @@ -260,61 +125,127 @@ out: } /** - * efi_signature_verify_with_list - verify a signature with signature list - * @regs: List of regions to be authenticated - * @msg: Signature - * @signed_info: Pointer to PKCS7's signed_info - * @siglist: Signature list for certificates - * @valid_cert: x509 certificate that verifies this signature + * efi_lookup_certificate - find a certificate within db + * @msg: Signature + * @db: Signature database * - * Signature pointed to by @signed_info against image pointed to by @regs - * is verified by signature list pointed to by @siglist. - * Signature database is a simple concatenation of one or more - * signature list(s). + * Search signature database pointed to by @db and find a certificate + * pointed to by @cert. * - * Return: true if signature is verified, false if not + * Return: true if found, false otherwise. */ -static -bool efi_signature_verify_with_list(struct efi_image_regions *regs, - struct pkcs7_message *msg, - struct pkcs7_signed_info *signed_info, - struct efi_signature_store *siglist, - struct x509_certificate **valid_cert) +static bool efi_lookup_certificate(struct x509_certificate *cert, + struct efi_signature_store *db) { - struct x509_certificate *cert; + struct efi_signature_store *siglist; struct efi_sig_data *sig_data; - bool verified = false; + struct image_region reg[1]; + void *hash = NULL, *hash_tmp = NULL; + size_t size = 0; + bool found = false; - EFI_PRINT("%s: Enter, %p, %p, %p, %p\n", __func__, - regs, signed_info, siglist, valid_cert); + EFI_PRINT("%s: Enter, %p, %p\n", __func__, cert, db); - if (guidcmp(&siglist->sig_type, &efi_guid_cert_x509)) { - EFI_PRINT("Signature type is not supported: %pUl\n", - &siglist->sig_type); + if (!cert || !db || !db->sig_data_list) goto out; - } - /* go through the list */ - for (sig_data = siglist->sig_data_list; sig_data; - sig_data = sig_data->next) { - /* TODO: support owner check based on policy */ + /* + * TODO: identify a certificate using sha256 digest + * Is there any better way? + */ + /* calculate hash of TBSCertificate */ + reg[0].data = cert->tbs; + reg[0].size = cert->tbs_size; + if (!efi_hash_regions(reg, 1, &hash, &size)) + goto out; - cert = x509_cert_parse(sig_data->data, sig_data->size); - if (IS_ERR(cert)) { - EFI_PRINT("Parsing x509 certificate failed\n"); - goto out; + EFI_PRINT("%s: searching for %s\n", __func__, cert->subject); + for (siglist = db; siglist; siglist = siglist->next) { + /* only with x509 certificate */ + if (guidcmp(&siglist->sig_type, &efi_guid_cert_x509)) + continue; + + for (sig_data = siglist->sig_data_list; sig_data; + sig_data = sig_data->next) { + struct x509_certificate *cert_tmp; + + cert_tmp = x509_cert_parse(sig_data->data, + sig_data->size); + if (IS_ERR_OR_NULL(cert_tmp)) + continue; + + reg[0].data = cert_tmp->tbs; + reg[0].size = cert_tmp->tbs_size; + if (!efi_hash_regions(reg, 1, &hash_tmp, NULL)) + goto out; + + x509_free_certificate(cert_tmp); + + if (!memcmp(hash, hash_tmp, size)) { + found = true; + goto out; + } } + } +out: + free(hash); + free(hash_tmp); - verified = efi_signature_verify(regs, msg, signed_info, cert); + EFI_PRINT("%s: Exit, found: %d\n", __func__, found); + return found; +} - if (verified) { - if (valid_cert) - *valid_cert = cert; - else - x509_free_certificate(cert); - break; +/** + * efi_verify_certificate - verify certificate's signature with database + * @signer: Certificate + * @db: Signature database + * @root: Certificate to verify @signer + * + * Determine if certificate pointed to by @signer may be verified + * by one of certificates in signature database pointed to by @db. + * + * Return: true if certificate is verified, false otherwise. + */ +static bool efi_verify_certificate(struct x509_certificate *signer, + struct efi_signature_store *db, + struct x509_certificate **root) +{ + struct efi_signature_store *siglist; + struct efi_sig_data *sig_data; + struct x509_certificate *cert; + bool verified = false; + int ret; + + EFI_PRINT("%s: Enter, %p, %p\n", __func__, signer, db); + + if (!signer || !db || !db->sig_data_list) + goto out; + + for (siglist = db; siglist; siglist = siglist->next) { + /* only with x509 certificate */ + if (guidcmp(&siglist->sig_type, &efi_guid_cert_x509)) + continue; + + for (sig_data = siglist->sig_data_list; sig_data; + sig_data = sig_data->next) { + cert = x509_cert_parse(sig_data->data, sig_data->size); + if (IS_ERR_OR_NULL(cert)) { + EFI_PRINT("Cannot parse x509 certificate\n"); + continue; + } + + ret = public_key_verify_signature(cert->pub, + signer->sig); + if (!ret) { + verified = true; + if (root) + *root = cert; + else + x509_free_certificate(cert); + goto out; + } + x509_free_certificate(cert); } - x509_free_certificate(cert); } out: @@ -422,9 +353,9 @@ bool efi_signature_verify_one(struct efi_image_regions *regs, struct efi_signature_store *db) { struct pkcs7_signed_info *sinfo; - struct efi_signature_store *siglist; - struct x509_certificate *cert; + struct x509_certificate *signer; bool verified = false; + int ret; EFI_PRINT("%s: Enter, %p, %p, %p\n", __func__, regs, msg, db); @@ -439,13 +370,29 @@ bool efi_signature_verify_one(struct efi_image_regions *regs, EFI_PRINT("Signed Info: digest algo: %s, pkey algo: %s\n", sinfo->sig->hash_algo, sinfo->sig->pkey_algo); - for (siglist = db; siglist; siglist = siglist->next) - if (efi_signature_verify_with_list(regs, msg, sinfo, - siglist, &cert)) { + EFI_PRINT("Verifying certificate chain\n"); + signer = NULL; + ret = pkcs7_verify_one(msg, sinfo, &signer); + if (ret == -ENOPKG) + continue; + + if (ret < 0 || !signer) + goto out; + + if (sinfo->blacklisted) + continue; + + EFI_PRINT("Verifying last certificate in chain\n"); + if (signer->self_signed) { + if (efi_lookup_certificate(signer, db)) { verified = true; goto out; } - EFI_PRINT("Valid certificate not in \"db\"\n"); + } else if (efi_verify_certificate(signer, db, NULL)) { + verified = true; + goto out; + } + EFI_PRINT("Valid certificate not in db\n"); } out: @@ -453,8 +400,8 @@ out: return verified; } -/** - * efi_signature_verify_with_sigdb - verify signatures with db and dbx +/* + * efi_signature_verify - verify signatures with db and dbx * @regs: List of regions to be authenticated * @msg: Signature * @db: Signature database for trusted certificates @@ -465,43 +412,71 @@ out: * * Return: true if verification for all signatures passed, false otherwise */ -bool efi_signature_verify_with_sigdb(struct efi_image_regions *regs, - struct pkcs7_message *msg, - struct efi_signature_store *db, - struct efi_signature_store *dbx) +bool efi_signature_verify(struct efi_image_regions *regs, + struct pkcs7_message *msg, + struct efi_signature_store *db, + struct efi_signature_store *dbx) { - struct pkcs7_signed_info *info; - struct efi_signature_store *siglist; - struct x509_certificate *cert; + struct pkcs7_signed_info *sinfo; + struct x509_certificate *signer, *root; bool verified = false; + int ret; EFI_PRINT("%s: Enter, %p, %p, %p, %p\n", __func__, regs, msg, db, dbx); if (!regs || !msg || !db || !db->sig_data_list) goto out; - for (info = msg->signed_infos; info; info = info->next) { + for (sinfo = msg->signed_infos; sinfo; sinfo = sinfo->next) { EFI_PRINT("Signed Info: digest algo: %s, pkey algo: %s\n", - info->sig->hash_algo, info->sig->pkey_algo); + sinfo->sig->hash_algo, sinfo->sig->pkey_algo); - for (siglist = db; siglist; siglist = siglist->next) { - if (efi_signature_verify_with_list(regs, msg, info, - siglist, &cert)) - break; - } - if (!siglist) { - EFI_PRINT("Valid certificate not in \"db\"\n"); + /* + * only for authenticated variable. + * + * If this function is called for image, + * hash calculation will be done in + * pkcs7_verify_one(). + */ + if (!msg->data && + !efi_hash_regions(regs->reg, regs->num, + (void **)&sinfo->sig->digest, NULL)) { + EFI_PRINT("Digesting an image failed\n"); goto out; } - if (!dbx || efi_signature_check_revocation(info, cert, dbx)) + EFI_PRINT("Verifying certificate chain\n"); + signer = NULL; + ret = pkcs7_verify_one(msg, sinfo, &signer); + if (ret == -ENOPKG) continue; - EFI_PRINT("Certificate in \"dbx\"\n"); + if (ret < 0 || !signer) + goto out; + + if (sinfo->blacklisted) + goto out; + + EFI_PRINT("Verifying last certificate in chain\n"); + if (signer->self_signed) { + if (efi_lookup_certificate(signer, db)) + if (efi_signature_check_revocation(sinfo, + signer, dbx)) + continue; + } else if (efi_verify_certificate(signer, db, &root)) { + bool check; + + check = efi_signature_check_revocation(sinfo, root, + dbx); + x509_free_certificate(root); + if (check) + continue; + } + + EFI_PRINT("Certificate chain didn't reach trusted CA\n"); goto out; } verified = true; - out: EFI_PRINT("%s: Exit, verified: %d\n", __func__, verified); return verified; diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c index 0c06931135..282d542a09 100644 --- a/lib/efi_loader/efi_variable.c +++ b/lib/efi_loader/efi_variable.c @@ -253,12 +253,11 @@ static efi_status_t efi_variable_authenticate(u16 *variable, } /* verify signature */ - if (efi_signature_verify_with_sigdb(regs, var_sig, truststore, NULL)) { + if (efi_signature_verify(regs, var_sig, truststore, NULL)) { EFI_PRINT("Verified\n"); } else { if (truststore2 && - efi_signature_verify_with_sigdb(regs, var_sig, - truststore2, NULL)) { + efi_signature_verify(regs, var_sig, truststore2, NULL)) { EFI_PRINT("Verified\n"); } else { EFI_PRINT("Verifying variable's signature failed\n"); -- cgit From 57be8cdce35189ea063ebadb9338ef510289116f Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Tue, 21 Jul 2020 19:35:23 +0900 Subject: test/py: efi_secboot: small rework for adding a new test It won't be very useful to customize HELLO_PATH and EFI_SECBOOT_IMAGE_NAME under the current code base. So just remove them. Signed-off-by: AKASHI Takahiro --- test/py/tests/test_efi_secboot/conftest.py | 10 +++------- test/py/tests/test_efi_secboot/defs.py | 6 ------ 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/test/py/tests/test_efi_secboot/conftest.py b/test/py/tests/test_efi_secboot/conftest.py index c0943b6250..70a0b91836 100644 --- a/test/py/tests/test_efi_secboot/conftest.py +++ b/test/py/tests/test_efi_secboot/conftest.py @@ -25,13 +25,8 @@ def efi_boot_env(request, u_boot_config): Return: A path to disk image to be used for testing """ - global HELLO_PATH - image_path = u_boot_config.persistent_data_dir - image_path = image_path + '/' + EFI_SECBOOT_IMAGE_NAME - - if HELLO_PATH == '': - HELLO_PATH = u_boot_config.build_dir + '/lib/efi_loader/helloworld.efi' + image_path = image_path + '/test_efi_secboot.img' try: mnt_point = u_boot_config.build_dir + '/mnt_efisecure' @@ -98,7 +93,8 @@ def efi_boot_env(request, u_boot_config): shell=True) # Copy image - check_call('cp %s %s' % (HELLO_PATH, mnt_point), shell=True) + check_call('cp %s/lib/efi_loader/helloworld.efi %s' % + (u_boot_config.build_dir, mnt_point), shell=True) # Sign image check_call('cd %s; sbsign --key db.key --cert db.crt helloworld.efi' diff --git a/test/py/tests/test_efi_secboot/defs.py b/test/py/tests/test_efi_secboot/defs.py index ba6b9f391e..14891fcd3a 100644 --- a/test/py/tests/test_efi_secboot/defs.py +++ b/test/py/tests/test_efi_secboot/defs.py @@ -1,14 +1,8 @@ # SPDX-License-Identifier: GPL-2.0+ -# Disk image name -EFI_SECBOOT_IMAGE_NAME = 'test_efi_secboot.img' - # Owner guid GUID = '11111111-2222-3333-4444-123456789abc' # v1.5.1 or earlier of efitools has a bug in sha256 calculation, and # you need build a newer version on your own. EFITOOLS_PATH = '' - -# Hello World application for sandbox -HELLO_PATH = '' -- cgit From e1174c566a61c863db1b782935269acba00e9281 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Tue, 21 Jul 2020 19:35:24 +0900 Subject: test/py: efi_secboot: add test for intermediate certificates In this test case, an image may have a signature with additional intermediate certificates. A chain of trust will be followed and all the certificates in the middle of chain must be verified before loading. Signed-off-by: AKASHI Takahiro --- test/py/tests/test_efi_secboot/conftest.py | 116 ++++++++++++++++++ test/py/tests/test_efi_secboot/defs.py | 6 + test/py/tests/test_efi_secboot/openssl.cnf | 48 ++++++++ .../py/tests/test_efi_secboot/test_signed_intca.py | 135 +++++++++++++++++++++ 4 files changed, 305 insertions(+) create mode 100644 test/py/tests/test_efi_secboot/openssl.cnf create mode 100644 test/py/tests/test_efi_secboot/test_signed_intca.py diff --git a/test/py/tests/test_efi_secboot/conftest.py b/test/py/tests/test_efi_secboot/conftest.py index 70a0b91836..bf27d995b1 100644 --- a/test/py/tests/test_efi_secboot/conftest.py +++ b/test/py/tests/test_efi_secboot/conftest.py @@ -124,3 +124,119 @@ def efi_boot_env(request, u_boot_config): yield image_path finally: call('rm -f %s' % image_path, shell=True) + +# +# Fixture for UEFI secure boot test of intermediate certificates +# + + +@pytest.fixture(scope='session') +def efi_boot_env_intca(request, u_boot_config): + """Set up a file system to be used in UEFI secure boot test + of intermediate certificates. + + Args: + request: Pytest request object. + u_boot_config: U-boot configuration. + + Return: + A path to disk image to be used for testing + """ + image_path = u_boot_config.persistent_data_dir + image_path = image_path + '/test_efi_secboot_intca.img' + + try: + mnt_point = u_boot_config.persistent_data_dir + '/mnt_efi_secboot_intca' + check_call('rm -rf {}'.format(mnt_point), shell=True) + check_call('mkdir -p {}'.format(mnt_point), shell=True) + + # Create signature database + # PK + check_call('cd %s; openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_PK/ -keyout PK.key -out PK.crt -nodes -days 365' + % mnt_point, shell=True) + check_call('cd %s; %scert-to-efi-sig-list -g %s PK.crt PK.esl; %ssign-efi-sig-list -c PK.crt -k PK.key PK PK.esl PK.auth' + % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH), + shell=True) + # KEK + check_call('cd %s; openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_KEK/ -keyout KEK.key -out KEK.crt -nodes -days 365' + % mnt_point, shell=True) + check_call('cd %s; %scert-to-efi-sig-list -g %s KEK.crt KEK.esl; %ssign-efi-sig-list -c PK.crt -k PK.key KEK KEK.esl KEK.auth' + % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH), + shell=True) + + # We will have three-tier hierarchy of certificates: + # TestRoot: Root CA (self-signed) + # TestSub: Intermediate CA (signed by Root CA) + # TestCert: User certificate (signed by Intermediate CA, and used + # for signing an image) + # + # NOTE: + # I consulted the following EDK2 document for certificate options: + # BaseTools/Source/Python/Pkcs7Sign/Readme.md + # Please not use them as they are in product system. They are + # for test purpose only. + + # TestRoot + check_call('cp %s/test/py/tests/test_efi_secboot/openssl.cnf %s' + % (u_boot_config.source_dir, mnt_point), shell=True) + check_call('cd %s; export OPENSSL_CONF=./openssl.cnf; openssl genrsa -out TestRoot.key 2048; openssl req -extensions v3_ca -new -x509 -days 365 -key TestRoot.key -out TestRoot.crt -subj "/CN=TEST_root/"; touch index.txt; touch index.txt.attr' + % mnt_point, shell=True) + # TestSub + check_call('cd %s; touch serial.new; export OPENSSL_CONF=./openssl.cnf; openssl genrsa -out TestSub.key 2048; openssl req -new -key TestSub.key -out TestSub.csr -subj "/CN=TEST_sub/"; openssl ca -in TestSub.csr -out TestSub.crt -extensions v3_int_ca -days 365 -batch -rand_serial -cert TestRoot.crt -keyfile TestRoot.key' + % mnt_point, shell=True) + # TestCert + check_call('cd %s; touch serial.new; export OPENSSL_CONF=./openssl.cnf; openssl genrsa -out TestCert.key 2048; openssl req -new -key TestCert.key -out TestCert.csr -subj "/CN=TEST_cert/"; openssl ca -in TestCert.csr -out TestCert.crt -extensions usr_cert -days 365 -batch -rand_serial -cert TestSub.crt -keyfile TestSub.key' + % mnt_point, shell=True) + # db + # for TestCert + check_call('cd %s; %scert-to-efi-sig-list -g %s TestCert.crt TestCert.esl; %ssign-efi-sig-list -c KEK.crt -k KEK.key db TestCert.esl db_a.auth' + % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH), + shell=True) + # for TestSub + check_call('cd %s; %scert-to-efi-sig-list -g %s TestSub.crt TestSub.esl; %ssign-efi-sig-list -t "2020-07-16" -c KEK.crt -k KEK.key db TestSub.esl db_b.auth' + % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH), + shell=True) + # for TestRoot + check_call('cd %s; %scert-to-efi-sig-list -g %s TestRoot.crt TestRoot.esl; %ssign-efi-sig-list -t "2020-07-17" -c KEK.crt -k KEK.key db TestRoot.esl db_c.auth' + % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH), + shell=True) + ## dbx (hash of certificate with revocation time) + # for TestCert + check_call('cd %s; %scert-to-efi-hash-list -g %s -t "2020-07-20" -s 256 TestCert.crt TestCert.crl; %ssign-efi-sig-list -c KEK.crt -k KEK.key dbx TestCert.crl dbx_a.auth' + % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH), + shell=True) + # for TestSub + check_call('cd %s; %scert-to-efi-hash-list -g %s -t "2020-07-21" -s 256 TestSub.crt TestSub.crl; %ssign-efi-sig-list -t "2020-07-18" -c KEK.crt -k KEK.key dbx TestSub.crl dbx_b.auth' + % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH), + shell=True) + # for TestRoot + check_call('cd %s; %scert-to-efi-hash-list -g %s -t "2020-07-22" -s 256 TestRoot.crt TestRoot.crl; %ssign-efi-sig-list -t "2020-07-19" -c KEK.crt -k KEK.key dbx TestRoot.crl dbx_c.auth' + % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH), + shell=True) + + # Sign image + # additional intermediate certificates may be included + # in SignedData + + check_call('cp %s/lib/efi_loader/helloworld.efi %s' % + (u_boot_config.build_dir, mnt_point), shell=True) + # signed by TestCert + check_call('cd %s; %ssbsign --key TestCert.key --cert TestCert.crt --out helloworld.efi.signed_a helloworld.efi' + % (mnt_point, SBSIGN_PATH), shell=True) + # signed by TestCert with TestSub in signature + check_call('cd %s; %ssbsign --key TestCert.key --cert TestCert.crt --addcert TestSub.crt --out helloworld.efi.signed_ab helloworld.efi' + % (mnt_point, SBSIGN_PATH), shell=True) + # signed by TestCert with TestSub and TestRoot in signature + check_call('cd %s; cat TestSub.crt TestRoot.crt > TestSubRoot.crt; %ssbsign --key TestCert.key --cert TestCert.crt --addcert TestSubRoot.crt --out helloworld.efi.signed_abc helloworld.efi' + % (mnt_point, SBSIGN_PATH), shell=True) + + check_call('virt-make-fs --partition=gpt --size=+1M --type=vfat {} {}'.format(mnt_point, image_path), shell=True) + check_call('rm -rf {}'.format(mnt_point), shell=True) + + except CalledProcessError as e: + pytest.skip('Setup failed: %s' % e.cmd) + return + else: + yield image_path + finally: + call('rm -f %s' % image_path, shell=True) diff --git a/test/py/tests/test_efi_secboot/defs.py b/test/py/tests/test_efi_secboot/defs.py index 14891fcd3a..b7a2a11851 100644 --- a/test/py/tests/test_efi_secboot/defs.py +++ b/test/py/tests/test_efi_secboot/defs.py @@ -5,4 +5,10 @@ GUID = '11111111-2222-3333-4444-123456789abc' # v1.5.1 or earlier of efitools has a bug in sha256 calculation, and # you need build a newer version on your own. +# The path must terminate with '/'. EFITOOLS_PATH = '' + +# "--addcert" option of sbsign must be available, otherwise +# you need build a newer version on your own. +# The path must terminate with '/'. +SBSIGN_PATH = '' diff --git a/test/py/tests/test_efi_secboot/openssl.cnf b/test/py/tests/test_efi_secboot/openssl.cnf new file mode 100644 index 0000000000..f684f1df7e --- /dev/null +++ b/test/py/tests/test_efi_secboot/openssl.cnf @@ -0,0 +1,48 @@ +[ ca ] +default_ca = CA_default + +[ CA_default ] +new_certs_dir = . +database = ./index.txt +serial = ./serial +default_md = sha256 +policy = policy_min + +[ req ] +distinguished_name = def_distinguished_name + +[def_distinguished_name] + +# Extensions +# -addext " ... = ..." +# +[ v3_ca ] + # Extensions for a typical Root CA. + basicConstraints = critical,CA:TRUE + keyUsage = critical, digitalSignature, cRLSign, keyCertSign + subjectKeyIdentifier = hash + authorityKeyIdentifier = keyid:always,issuer + +[ v3_int_ca ] + # Extensions for a typical intermediate CA. + basicConstraints = critical, CA:TRUE + keyUsage = critical, digitalSignature, cRLSign, keyCertSign + subjectKeyIdentifier = hash + authorityKeyIdentifier = keyid:always,issuer + +[ usr_cert ] + # Extensions for user end certificates. + basicConstraints = CA:FALSE + keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment + extendedKeyUsage = clientAuth, emailProtection + subjectKeyIdentifier = hash + authorityKeyIdentifier = keyid,issuer + +[ policy_min ] + countryName = optional + stateOrProvinceName = optional + localityName = optional + organizationName = optional + organizationalUnitName = optional + commonName = supplied + emailAddress = optional diff --git a/test/py/tests/test_efi_secboot/test_signed_intca.py b/test/py/tests/test_efi_secboot/test_signed_intca.py new file mode 100644 index 0000000000..1e5f4d04b3 --- /dev/null +++ b/test/py/tests/test_efi_secboot/test_signed_intca.py @@ -0,0 +1,135 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (c) 2020, Linaro Limited +# Author: AKASHI Takahiro +# +# U-Boot UEFI: Image Authentication Test (signature with certificates chain) + +""" +This test verifies image authentication for a signed image which is signed +by user certificate and contains additional intermediate certificates in its +signature. +""" + +import pytest + + +@pytest.mark.boardspec('sandbox') +@pytest.mark.buildconfigspec('efi_secure_boot') +@pytest.mark.buildconfigspec('cmd_efidebug') +@pytest.mark.buildconfigspec('cmd_fat') +@pytest.mark.buildconfigspec('cmd_nvedit_efi') +@pytest.mark.slow +class TestEfiSignedImageIntca(object): + def test_efi_signed_image_intca1(self, u_boot_console, efi_boot_env_intca): + """ + Test Case 1 - authenticated by root CA in db + """ + u_boot_console.restart_uboot() + disk_img = efi_boot_env_intca + with u_boot_console.log.section('Test Case 1a'): + # Test Case 1a, with no Int CA and not authenticated by root CA + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % disk_img, + 'fatload host 0:1 4000000 db_c.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize db', + 'fatload host 0:1 4000000 KEK.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize KEK', + 'fatload host 0:1 4000000 PK.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize PK']) + assert 'Failed to set EFI variable' not in ''.join(output) + + output = u_boot_console.run_command_list([ + 'efidebug boot add 1 HELLO_a host 0:1 /helloworld.efi.signed_a ""', + 'efidebug boot next 1', + 'efidebug test bootmgr']) + assert '\'HELLO_a\' failed' in ''.join(output) + assert 'efi_start_image() returned: 26' in ''.join(output) + + with u_boot_console.log.section('Test Case 1b'): + # Test Case 1b, signed and authenticated by root CA + output = u_boot_console.run_command_list([ + 'efidebug boot add 2 HELLO_ab host 0:1 /helloworld.efi.signed_ab ""', + 'efidebug boot next 2', + 'bootefi bootmgr']) + assert 'Hello, world!' in ''.join(output) + + def test_efi_signed_image_intca2(self, u_boot_console, efi_boot_env_intca): + """ + Test Case 2 - authenticated by root CA in db + """ + u_boot_console.restart_uboot() + disk_img = efi_boot_env_intca + with u_boot_console.log.section('Test Case 2a'): + # Test Case 2a, unsigned and not authenticated by root CA + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % disk_img, + 'fatload host 0:1 4000000 KEK.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize KEK', + 'fatload host 0:1 4000000 PK.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize PK']) + assert 'Failed to set EFI variable' not in ''.join(output) + + output = u_boot_console.run_command_list([ + 'efidebug boot add 1 HELLO_abc host 0:1 /helloworld.efi.signed_abc ""', + 'efidebug boot next 1', + 'efidebug test bootmgr']) + assert '\'HELLO_abc\' failed' in ''.join(output) + assert 'efi_start_image() returned: 26' in ''.join(output) + + with u_boot_console.log.section('Test Case 2b'): + # Test Case 2b, signed and authenticated by root CA + output = u_boot_console.run_command_list([ + 'fatload host 0:1 4000000 db_b.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize db', + 'efidebug boot next 1', + 'efidebug test bootmgr']) + assert '\'HELLO_abc\' failed' in ''.join(output) + assert 'efi_start_image() returned: 26' in ''.join(output) + + with u_boot_console.log.section('Test Case 2c'): + # Test Case 2c, signed and authenticated by root CA + output = u_boot_console.run_command_list([ + 'fatload host 0:1 4000000 db_c.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize db', + 'efidebug boot next 1', + 'efidebug test bootmgr']) + assert 'Hello, world!' in ''.join(output) + + def test_efi_signed_image_intca3(self, u_boot_console, efi_boot_env_intca): + """ + Test Case 3 - revoked by dbx + """ + u_boot_console.restart_uboot() + disk_img = efi_boot_env_intca + with u_boot_console.log.section('Test Case 3a'): + # Test Case 3a, revoked by int CA in dbx + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % disk_img, + 'fatload host 0:1 4000000 dbx_b.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize dbx', + 'fatload host 0:1 4000000 db_c.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize db', + 'fatload host 0:1 4000000 KEK.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize KEK', + 'fatload host 0:1 4000000 PK.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize PK']) + assert 'Failed to set EFI variable' not in ''.join(output) + + output = u_boot_console.run_command_list([ + 'efidebug boot add 1 HELLO_abc host 0:1 /helloworld.efi.signed_abc ""', + 'efidebug boot next 1', + 'efidebug test bootmgr']) + assert 'Hello, world!' in ''.join(output) + # Or, + # assert '\'HELLO_abc\' failed' in ''.join(output) + # assert 'efi_start_image() returned: 26' in ''.join(output) + + with u_boot_console.log.section('Test Case 3b'): + # Test Case 3b, revoked by root CA in dbx + output = u_boot_console.run_command_list([ + 'fatload host 0:1 4000000 dbx_c.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize dbx', + 'efidebug boot next 1', + 'efidebug test bootmgr']) + assert '\'HELLO_abc\' failed' in ''.join(output) + assert 'efi_start_image() returned: 26' in ''.join(output) -- cgit From f68a6d583578799ec2011476ebd1e10590c6eb3c Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Thu, 13 Aug 2020 17:05:29 +0900 Subject: efi_loader: variable: fix secure state initialization Under the new file-based variable implementation, the secure state is always and falsely set to 0 (hence, the secure boot gets disabled) after the reboot even if PK (and other signature database) has already been enrolled in the previous boot. This is because the secure state is set up *before* loading non-volatile variables' values from saved data. This patch fixes the order of variable initialization and secure state initialization. Signed-off-by: AKASHI Takahiro Fixes: 5f7dcf079de8 ("efi_loader: UEFI variable persistence") --- lib/efi_loader/efi_variable.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c index 282d542a09..a10b9caa8b 100644 --- a/lib/efi_loader/efi_variable.c +++ b/lib/efi_loader/efi_variable.c @@ -508,10 +508,6 @@ efi_status_t efi_init_variables(void) if (ret != EFI_SUCCESS) return ret; - ret = efi_init_secure_state(); - if (ret != EFI_SUCCESS) - return ret; - if (IS_ENABLED(CONFIG_EFI_VARIABLES_PRESEED)) { ret = efi_var_restore((struct efi_var_file *) __efi_var_file_begin); @@ -519,5 +515,9 @@ efi_status_t efi_init_variables(void) log_err("Invalid EFI variable seed\n"); } - return efi_var_from_file(); + ret = efi_var_from_file(); + if (ret != EFI_SUCCESS) + return ret; + + return efi_init_secure_state(); } -- cgit From 52956e535e65c852b1f95d2ca5044cb7c4fc6bbe Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Fri, 14 Aug 2020 14:39:23 +0900 Subject: efi_loader: signature: correct a behavior against multiple signatures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Under the current implementation, all the signatures, if any, in a signed image must be verified before loading it. Meanwhile, UEFI specification v2.8b section 32.5.3.3 says, Multiple signatures are allowed to exist in the binary’s certificate table (as per PE/COFF Section “Attribute Certificate Table”). Only one hash or signature is required to be present in db in order to pass validation, so long as neither the SHA-256 hash of the binary nor any present signature is reflected in dbx. This patch makes the semantics of signature verification compliant with the specification mentioned above. Signed-off-by: AKASHI Takahiro Reported-by: Heinrich Schuchardt --- include/efi_loader.h | 9 +++-- lib/efi_loader/efi_image_loader.c | 33 ++++++++--------- lib/efi_loader/efi_signature.c | 76 ++++----------------------------------- 3 files changed, 30 insertions(+), 88 deletions(-) diff --git a/include/efi_loader.h b/include/efi_loader.h index b941b5e994..50a17a33ca 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -773,13 +773,16 @@ 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); bool efi_signature_verify(struct efi_image_regions *regs, struct pkcs7_message *msg, struct efi_signature_store *db, struct efi_signature_store *dbx); +static inline bool efi_signature_verify_one(struct efi_image_regions *regs, + struct pkcs7_message *msg, + struct efi_signature_store *db) +{ + return efi_signature_verify(regs, msg, db, NULL); +} bool efi_signature_check_signers(struct pkcs7_message *msg, struct efi_signature_store *dbx); diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c index 832bce9394..eea42cc204 100644 --- a/lib/efi_loader/efi_image_loader.c +++ b/lib/efi_loader/efi_image_loader.c @@ -546,6 +546,11 @@ static bool efi_image_authenticate(void *efi, size_t efi_size) goto err; } + if (efi_signature_lookup_digest(regs, dbx)) { + EFI_PRINT("Image's digest was found in \"dbx\"\n"); + goto err; + } + /* * go through WIN_CERTIFICATE list * NOTE: @@ -553,10 +558,9 @@ static bool efi_image_authenticate(void *efi, size_t efi_size) * in PE header, or as pkcs7 SignerInfo's in SignedData. * So the verification policy here is: * - Success if, at least, one of signatures is verified - * - unless - * any of signatures is rejected explicitly, or - * none of digest algorithms are supported + * - unless signature is rejected explicitly with its digest. */ + for (wincert = wincerts, wincerts_end = (u8 *)wincerts + wincerts_len; (u8 *)wincert < wincerts_end; wincert = (WIN_CERTIFICATE *) @@ -627,32 +631,29 @@ static bool efi_image_authenticate(void *efi, size_t efi_size) /* try black-list first */ if (efi_signature_verify_one(regs, msg, dbx)) { EFI_PRINT("Signature was rejected by \"dbx\"\n"); - goto err; + continue; } if (!efi_signature_check_signers(msg, dbx)) { EFI_PRINT("Signer(s) in \"dbx\"\n"); - goto err; - } - - if (efi_signature_lookup_digest(regs, dbx)) { - EFI_PRINT("Image's digest was found in \"dbx\"\n"); - goto err; + continue; } /* try white-list */ - if (efi_signature_verify(regs, msg, db, dbx)) - continue; + if (efi_signature_verify(regs, msg, db, dbx)) { + ret = true; + break; + } debug("Signature was not verified by \"db\"\n"); - if (efi_signature_lookup_digest(regs, db)) - continue; + if (efi_signature_lookup_digest(regs, db)) { + ret = true; + break; + } debug("Image's digest was not found in \"db\" or \"dbx\"\n"); - goto err; } - ret = true; err: efi_sigstore_free(db); diff --git a/lib/efi_loader/efi_signature.c b/lib/efi_loader/efi_signature.c index f60c0e1f79..79dee27421 100644 --- a/lib/efi_loader/efi_signature.c +++ b/lib/efi_loader/efi_signature.c @@ -174,6 +174,8 @@ static bool efi_lookup_certificate(struct x509_certificate *cert, if (IS_ERR_OR_NULL(cert_tmp)) continue; + EFI_PRINT("%s: against %s\n", __func__, + cert_tmp->subject); reg[0].data = cert_tmp->tbs; reg[0].size = cert_tmp->tbs_size; if (!efi_hash_regions(reg, 1, &hash_tmp, NULL)) @@ -266,7 +268,7 @@ out: * protocol at this time and any image will be unconditionally revoked * when this match occurs. * - * Return: true if check passed, false otherwise. + * Return: true if check passed (not found), false otherwise. */ static bool efi_signature_check_revocation(struct pkcs7_signed_info *sinfo, struct x509_certificate *cert, @@ -336,70 +338,6 @@ out: return !revoked; } -/** - * efi_signature_verify_one - verify signatures with database - * @regs: List of regions to be authenticated - * @msg: Signature - * @db: Signature database - * - * All the signature pointed to by @msg against image pointed to by @regs - * will be verified by signature database pointed to by @db. - * - * Return: true if verification for one of signatures passed, false - * otherwise - */ -bool efi_signature_verify_one(struct efi_image_regions *regs, - struct pkcs7_message *msg, - struct efi_signature_store *db) -{ - struct pkcs7_signed_info *sinfo; - struct x509_certificate *signer; - bool verified = false; - int ret; - - EFI_PRINT("%s: Enter, %p, %p, %p\n", __func__, regs, msg, db); - - if (!db) - goto out; - - if (!db->sig_data_list) - goto out; - - 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", - sinfo->sig->hash_algo, sinfo->sig->pkey_algo); - - EFI_PRINT("Verifying certificate chain\n"); - signer = NULL; - ret = pkcs7_verify_one(msg, sinfo, &signer); - if (ret == -ENOPKG) - continue; - - if (ret < 0 || !signer) - goto out; - - if (sinfo->blacklisted) - continue; - - EFI_PRINT("Verifying last certificate in chain\n"); - if (signer->self_signed) { - if (efi_lookup_certificate(signer, db)) { - verified = true; - goto out; - } - } else if (efi_verify_certificate(signer, db, NULL)) { - verified = true; - goto out; - } - EFI_PRINT("Valid certificate not in db\n"); - } - -out: - EFI_PRINT("%s: Exit, verified: %d\n", __func__, verified); - return verified; -} - /* * efi_signature_verify - verify signatures with db and dbx * @regs: List of regions to be authenticated @@ -462,7 +400,7 @@ bool efi_signature_verify(struct efi_image_regions *regs, if (efi_lookup_certificate(signer, db)) if (efi_signature_check_revocation(sinfo, signer, dbx)) - continue; + break; } else if (efi_verify_certificate(signer, db, &root)) { bool check; @@ -470,13 +408,13 @@ bool efi_signature_verify(struct efi_image_regions *regs, dbx); x509_free_certificate(root); if (check) - continue; + break; } EFI_PRINT("Certificate chain didn't reach trusted CA\n"); - goto out; } - verified = true; + if (sinfo) + verified = true; out: EFI_PRINT("%s: Exit, verified: %d\n", __func__, verified); return verified; -- cgit From 0274e50e057e1969876c9d1ef6e2a530688cf5ee Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Fri, 14 Aug 2020 14:39:24 +0900 Subject: test/py: efi_secboot: modify 'multiple signatures' test case The test case 5 in test_signed (multiple signatures) must be modified and aligned with the change introduced in the previous commit ("efi_loader: signature: correct a behavior against multiple signatures"). Signed-off-by: AKASHI Takahiro --- test/py/tests/test_efi_secboot/conftest.py | 5 +---- test/py/tests/test_efi_secboot/test_signed.py | 26 ++++++++++++++++++-------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/test/py/tests/test_efi_secboot/conftest.py b/test/py/tests/test_efi_secboot/conftest.py index bf27d995b1..69a498ca00 100644 --- a/test/py/tests/test_efi_secboot/conftest.py +++ b/test/py/tests/test_efi_secboot/conftest.py @@ -70,9 +70,6 @@ def efi_boot_env(request, u_boot_config): check_call('cd %s; %scert-to-efi-sig-list -g %s db1.crt db1.esl; %ssign-efi-sig-list -t "2020-04-05" -c KEK.crt -k KEK.key db db1.esl db1.auth' % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH), shell=True) - # db1-update - check_call('cd %s; %ssign-efi-sig-list -t "2020-04-06" -a -c KEK.crt -k KEK.key db db1.esl db1-update.auth' - % (mnt_point, EFITOOLS_PATH), shell=True) # dbx (TEST_dbx certificate) check_call('cd %s; openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_dbx/ -keyout dbx.key -out dbx.crt -nodes -days 365' % mnt_point, shell=True) @@ -84,7 +81,7 @@ def efi_boot_env(request, u_boot_config): % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH), shell=True) # dbx_hash1 (digest of TEST_db1 certificate) - check_call('cd %s; %scert-to-efi-hash-list -g %s -t 0 -s 256 db1.crt dbx_hash1.crl; %ssign-efi-sig-list -t "2020-04-05" -c KEK.crt -k KEK.key dbx dbx_hash1.crl dbx_hash1.auth' + check_call('cd %s; %scert-to-efi-hash-list -g %s -t 0 -s 256 db1.crt dbx_hash1.crl; %ssign-efi-sig-list -t "2020-04-06" -c KEK.crt -k KEK.key dbx dbx_hash1.crl dbx_hash1.auth' % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH), shell=True) # dbx_db (with TEST_db certificate) diff --git a/test/py/tests/test_efi_secboot/test_signed.py b/test/py/tests/test_efi_secboot/test_signed.py index 7531bbac6a..1443ba7b62 100644 --- a/test/py/tests/test_efi_secboot/test_signed.py +++ b/test/py/tests/test_efi_secboot/test_signed.py @@ -157,7 +157,8 @@ class TestEfiSignedImage(object): u_boot_console.restart_uboot() disk_img = efi_boot_env with u_boot_console.log.section('Test Case 5a'): - # Test Case 5a, rejected if any of signatures is not verified + # Test Case 5a, authenticated even if only one of signatures + # is verified output = u_boot_console.run_command_list([ 'host bind 0 %s' % disk_img, 'fatload host 0:1 4000000 db.auth', @@ -171,8 +172,7 @@ class TestEfiSignedImage(object): 'efidebug boot add 1 HELLO host 0:1 /helloworld.efi.signed_2sigs ""', 'efidebug boot next 1', 'efidebug test bootmgr']) - assert '\'HELLO\' failed' in ''.join(output) - assert 'efi_start_image() returned: 26' in ''.join(output) + assert 'Hello, world!' in ''.join(output) with u_boot_console.log.section('Test Case 5b'): # Test Case 5b, authenticated if both signatures are verified @@ -181,19 +181,29 @@ class TestEfiSignedImage(object): 'setenv -e -nv -bs -rt -at -a -i 4000000,$filesize db']) assert 'Failed to set EFI variable' not in ''.join(output) output = u_boot_console.run_command_list([ - 'efidebug boot add 1 HELLO host 0:1 /helloworld.efi.signed_2sigs ""', 'efidebug boot next 1', - 'bootefi bootmgr']) + 'efidebug test bootmgr']) assert 'Hello, world!' in ''.join(output) with u_boot_console.log.section('Test Case 5c'): - # Test Case 5c, rejected if any of signatures is revoked + # Test Case 5c, not rejected if one of signatures (digest of + # certificate) is revoked output = u_boot_console.run_command_list([ - 'fatload host 0:1 4000000 dbx_hash1.auth', + 'fatload host 0:1 4000000 dbx_hash.auth', 'setenv -e -nv -bs -rt -at -i 4000000,$filesize dbx']) assert 'Failed to set EFI variable' not in ''.join(output) output = u_boot_console.run_command_list([ - 'efidebug boot add 1 HELLO host 0:1 /helloworld.efi.signed_2sigs ""', + 'efidebug boot next 1', + 'efidebug test bootmgr']) + assert 'Hello, world!' in ''.join(output) + + with u_boot_console.log.section('Test Case 5d'): + # Test Case 5d, rejected if both of signatures are revoked + output = u_boot_console.run_command_list([ + 'fatload host 0:1 4000000 dbx_hash1.auth', + 'setenv -e -nv -bs -rt -at -a -i 4000000,$filesize dbx']) + assert 'Failed to set EFI variable' not in ''.join(output) + output = u_boot_console.run_command_list([ 'efidebug boot next 1', 'efidebug test bootmgr']) assert '\'HELLO\' failed' in ''.join(output) -- cgit From a4bda5ebab8246004caaca2e17bc865d265bf57a Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 29 Jul 2020 12:49:24 +0200 Subject: riscv: load addresses for Sipeed MAIX Define default load addresses and the device tree name for the Sipeed MAIX. Signed-off-by: Heinrich Schuchardt --- include/configs/sipeed-maix.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/configs/sipeed-maix.h b/include/configs/sipeed-maix.h index a46473fc78..36ff522e4b 100644 --- a/include/configs/sipeed-maix.h +++ b/include/configs/sipeed-maix.h @@ -21,4 +21,13 @@ /* For early init */ #define K210_SYSCTL_BASE 0x50440000 +#ifndef CONFIG_EXTRA_ENV_SETTINGS +#define CONFIG_EXTRA_ENV_SETTINGS \ + "loadaddr=0x80060000\0" \ + "fdt_addr_r=0x80028000\0" \ + "scriptaddr=0x80020000\0" \ + "kernel_addr_r=0x80060000\0" \ + "fdtfile=kendryte/" CONFIG_DEFAULT_DEVICE_TREE ".dtb\0" +#endif + #endif /* CONFIGS_SIPEED_MAIX_H */ -- cgit