diff options
| -rw-r--r-- | include/variables.h | 16 | ||||
| -rw-r--r-- | lib/variables.c | 81 | ||||
| -rw-r--r-- | mok.c | 56 |
3 files changed, 106 insertions, 47 deletions
diff --git a/include/variables.h b/include/variables.h index 31cfcb65..493f433f 100644 --- a/include/variables.h +++ b/include/variables.h @@ -64,12 +64,20 @@ EFI_STATUS variable_enroll_hash(const CHAR16 * const var, EFI_GUID owner, UINT8 hash[SHA256_DIGEST_SIZE]); EFI_STATUS -variable_create_esl(const uint8_t *cert, const size_t cert_len, - const EFI_GUID *type, const EFI_GUID *owner, +variable_create_esl(const EFI_SIGNATURE_DATA *first_sig, const size_t howmany, + const EFI_GUID *type, const UINT32 sig_size, uint8_t **out, size_t *outlen); EFI_STATUS -fill_esl(const uint8_t *data, const size_t data_len, - const EFI_GUID *type, const EFI_GUID *owner, +variable_create_esl_with_one_signature(const uint8_t* data, const size_t data_len, + const EFI_GUID *type, const EFI_GUID *owner, + uint8_t **out, size_t *outlen); +EFI_STATUS +fill_esl(const EFI_SIGNATURE_DATA *first_sig, const size_t howmany, + const EFI_GUID *type, const UINT32 sig_size, uint8_t *out, size_t *outlen); +EFI_STATUS +fill_esl_with_one_signature(const uint8_t *data, const uint32_t data_len, + const EFI_GUID *type, const EFI_GUID *owner, + uint8_t *out, size_t *outlen); #endif /* SHIM_VARIABLES_H */ diff --git a/lib/variables.c b/lib/variables.c index 9f5b2b57..53a5d14a 100644 --- a/lib/variables.c +++ b/lib/variables.c @@ -13,18 +13,24 @@ #include "shim.h" EFI_STATUS -fill_esl(const uint8_t *data, const size_t data_len, - const EFI_GUID *type, const EFI_GUID *owner, +fill_esl(const EFI_SIGNATURE_DATA *first_sig, const size_t howmany, + const EFI_GUID *type, const UINT32 sig_size, uint8_t *out, size_t *outlen) { EFI_SIGNATURE_LIST *sl; EFI_SIGNATURE_DATA *sd; size_t needed = 0; + size_t data_len = howmany * sig_size; - if (!data || !data_len || !type || !outlen) + dprint(L"fill_esl: data=%p, data_len=%lu", first_sig, data_len); + + if ((out && !first_sig) || !howmany || !type || !sig_size || !outlen) + return EFI_INVALID_PARAMETER; + + if (howmany > (UINT32_MAX - sizeof(EFI_SIGNATURE_LIST)) / sig_size) return EFI_INVALID_PARAMETER; - needed = sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_GUID) + data_len; + needed = sizeof(EFI_SIGNATURE_LIST) + data_len; if (!out || *outlen < needed) { *outlen = needed; return EFI_BUFFER_TOO_SMALL; @@ -35,27 +41,70 @@ fill_esl(const uint8_t *data, const size_t data_len, sl->SignatureHeaderSize = 0; sl->SignatureType = *type; - sl->SignatureSize = sizeof(EFI_GUID) + data_len; + sl->SignatureSize = sig_size; sl->SignatureListSize = needed; sd = (EFI_SIGNATURE_DATA *)(out + sizeof(EFI_SIGNATURE_LIST)); - if (owner) - sd->SignatureOwner = *owner; - - CopyMem(sd->SignatureData, data, data_len); + CopyMem(sd, first_sig, data_len); return EFI_SUCCESS; } EFI_STATUS -variable_create_esl(const uint8_t *data, const size_t data_len, - const EFI_GUID *type, const EFI_GUID *owner, +fill_esl_with_one_signature(const uint8_t *data, const uint32_t data_len, + const EFI_GUID *type, const EFI_GUID *owner, + uint8_t *out, size_t *outlen) +{ + EFI_STATUS efi_status; + EFI_SIGNATURE_DATA *sd = NULL; + UINT32 sig_size = sizeof(EFI_SIGNATURE_DATA) - 1 + data_len; + + if (data_len > UINT32_MAX - sizeof(EFI_SIGNATURE_DATA) + 1) + return EFI_INVALID_PARAMETER; + + if (out) { + sd = AllocateZeroPool(sig_size); + if (owner) + CopyMem(sd, owner, sizeof(EFI_GUID)); + CopyMem(sd->SignatureData, data, data_len); + } + + efi_status = fill_esl(sd, 1, type, sig_size, out, outlen); + + if (out) + FreePool(sd); + return efi_status; +} + +EFI_STATUS +variable_create_esl(const EFI_SIGNATURE_DATA *first_sig, const size_t howmany, + const EFI_GUID *type, const UINT32 sig_size, uint8_t **out, size_t *outlen) { EFI_STATUS efi_status; *outlen = 0; - efi_status = fill_esl(data, data_len, type, owner, NULL, outlen); + efi_status = fill_esl(first_sig, howmany, type, sig_size, NULL, outlen); + if (efi_status != EFI_BUFFER_TOO_SMALL) + return efi_status; + + *out = AllocateZeroPool(*outlen); + if (!*out) + return EFI_OUT_OF_RESOURCES; + + return fill_esl(first_sig, howmany, type, sig_size, *out, outlen); +} + +EFI_STATUS +variable_create_esl_with_one_signature(const uint8_t* data, const size_t data_len, + const EFI_GUID *type, const EFI_GUID *owner, + uint8_t **out, size_t *outlen) +{ + EFI_STATUS efi_status; + + *outlen = 0; + efi_status = fill_esl_with_one_signature(data, data_len, type, owner, + NULL, outlen); if (efi_status != EFI_BUFFER_TOO_SMALL) return efi_status; @@ -63,7 +112,8 @@ variable_create_esl(const uint8_t *data, const size_t data_len, if (!*out) return EFI_OUT_OF_RESOURCES; - return fill_esl(data, data_len, type, owner, *out, outlen); + return fill_esl_with_one_signature(data, data_len, type, owner, *out, + outlen); } EFI_STATUS @@ -153,8 +203,9 @@ SetSecureVariable(const CHAR16 * const var, UINT8 *Data, UINTN len, if (createtimebased) { size_t ds; - efi_status = variable_create_esl(Data, len, &X509_GUID, NULL, - (uint8_t **)&Cert, &ds); + efi_status = variable_create_esl_with_one_signature( + Data, len, &X509_GUID, NULL, + (uint8_t **)&Cert, &ds); if (EFI_ERROR(efi_status)) { console_print(L"Failed to create %s certificate %d\n", var, efi_status); @@ -303,8 +303,8 @@ mirror_one_esl(CHAR16 *name, EFI_GUID *guid, UINT32 attrs, UINTN *newsz, SIZE_T maxsz) { EFI_STATUS efi_status; - SIZE_T howmany, varsz = 0, esdsz; - UINT8 *var, *data; + SIZE_T howmany, varsz = 0; + UINT8 *var; howmany = MIN((maxsz - sizeof(*esl)) / esl->SignatureSize, (esl->SignatureListSize - sizeof(*esl)) / esl->SignatureSize); @@ -316,8 +316,6 @@ mirror_one_esl(CHAR16 *name, EFI_GUID *guid, UINT32 attrs, * We always assume esl->SignatureHeaderSize is 0 (and so far, * that's true as per UEFI 2.8) */ - esdsz = howmany * esl->SignatureSize; - data = (UINT8 *)esd; dprint(L"Trying to add %lx signatures to \"%s\" of size %lx\n", howmany, name, esl->SignatureSize); @@ -327,10 +325,9 @@ mirror_one_esl(CHAR16 *name, EFI_GUID *guid, UINT32 attrs, * * Compensate here. */ - efi_status = variable_create_esl(data + sizeof(EFI_GUID), - esdsz - sizeof(EFI_GUID), + efi_status = variable_create_esl(esd, howmany, &esl->SignatureType, - &esd->SignatureOwner, + esl->SignatureSize, &var, &varsz); if (EFI_ERROR(efi_status) || !var || !varsz) { LogError(L"Couldn't allocate %lu bytes for mok variable \"%s\": %r\n", @@ -349,7 +346,7 @@ mirror_one_esl(CHAR16 *name, EFI_GUID *guid, UINT32 attrs, return efi_status; } - *newsz = esdsz; + *newsz = howmany * esl->SignatureSize; return efi_status; } @@ -507,7 +504,7 @@ mirror_mok_db(CHAR16 *name, CHAR8 *name8, EFI_GUID *guid, UINT32 attrs, UINT8 *var; UINTN varsz; - efi_status = variable_create_esl( + efi_status = variable_create_esl_with_one_signature( null_sha256, sizeof(null_sha256), &EFI_CERT_SHA256_GUID, &SHIM_LOCK_GUID, &var, &varsz); @@ -592,10 +589,12 @@ mirror_one_mok_variable(struct mok_state_variable *v, FullDataSize, FullData); break; case VENDOR_ADDEND_X509: - efi_status = fill_esl(*v->addend, *v->addend_size, - &EFI_CERT_TYPE_X509_GUID, - &SHIM_LOCK_GUID, - NULL, &addend_esl_sz); + efi_status = fill_esl_with_one_signature(*v->addend, + *v->addend_size, + &EFI_CERT_TYPE_X509_GUID, + &SHIM_LOCK_GUID, + NULL, + &addend_esl_sz); if (efi_status != EFI_BUFFER_TOO_SMALL) { perror(L"Could not add built-in cert to %s: %r\n", v->name, efi_status); @@ -616,11 +615,11 @@ mirror_one_mok_variable(struct mok_state_variable *v, * then the build cert if it's there */ if (should_mirror_build_cert(v)) { - efi_status = fill_esl(*v->build_cert, - *v->build_cert_size, - &EFI_CERT_TYPE_X509_GUID, - &SHIM_LOCK_GUID, - NULL, &build_cert_esl_sz); + efi_status = fill_esl_with_one_signature(*v->build_cert, + *v->build_cert_size, + &EFI_CERT_TYPE_X509_GUID, + &SHIM_LOCK_GUID, + NULL, &build_cert_esl_sz); if (efi_status != EFI_BUFFER_TOO_SMALL) { perror(L"Could not add built-in cert to %s: %r\n", v->name, efi_status); @@ -703,10 +702,11 @@ mirror_one_mok_variable(struct mok_state_variable *v, FullDataSize, FullData, p, p-(uintptr_t)FullData); break; case VENDOR_ADDEND_X509: - efi_status = fill_esl(*v->addend, *v->addend_size, - &EFI_CERT_TYPE_X509_GUID, - &SHIM_LOCK_GUID, - p, &addend_esl_sz); + efi_status = fill_esl_with_one_signature(*v->addend, + *v->addend_size, + &EFI_CERT_TYPE_X509_GUID, + &SHIM_LOCK_GUID, + p, &addend_esl_sz); if (EFI_ERROR(efi_status)) { perror(L"Could not add built-in cert to %s: %r\n", v->name, efi_status); @@ -729,11 +729,11 @@ mirror_one_mok_variable(struct mok_state_variable *v, dprint(L"FullDataSize:%lu FullData:0x%llx p:0x%llx pos:%lld\n", FullDataSize, FullData, p, p-(uintptr_t)FullData); if (should_mirror_build_cert(v)) { - efi_status = fill_esl(*v->build_cert, - *v->build_cert_size, - &EFI_CERT_TYPE_X509_GUID, - &SHIM_LOCK_GUID, - p, &build_cert_esl_sz); + efi_status = fill_esl_with_one_signature(*v->build_cert, + *v->build_cert_size, + &EFI_CERT_TYPE_X509_GUID, + &SHIM_LOCK_GUID, + p, &build_cert_esl_sz); if (EFI_ERROR(efi_status)) { perror(L"Could not add built-in cert to %s: %r\n", v->name, efi_status); @@ -765,7 +765,7 @@ mirror_one_mok_variable(struct mok_state_variable *v, * need a dummy entry */ if ((v->flags & MOK_MIRROR_KEYDB) && FullDataSize == 0) { - efi_status = variable_create_esl( + efi_status = variable_create_esl_with_one_signature( null_sha256, sizeof(null_sha256), &EFI_CERT_SHA256_GUID, &SHIM_LOCK_GUID, &FullData, &FullDataSize); |
