Skip to content

Commit 76c0447

Browse files
committed
Handle binaries with multiple signatures.
This adds support for multiple signatures. It first tries validating the binary by hash, first against our dbx lists, then against our db lists. If it isn't allowed or rejected at that step, it continues to the normal routine of checking all the signatures. At this point it does *not* reject a binary just because a signature is by a cert on a dbx list, though that will override any db list that certificate is listed on. If at any point any assertion about the binary or signature list being well-formed fails, the binary is immediately rejected, though we do allow skipping over signatures which have an unsupported sig->Hdr.wCertificateType. Signed-off-by: Peter Jones <pjones@redhat.com> Upstream: pr#210
1 parent dd3a5d7 commit 76c0447

File tree

1 file changed

+197
-88
lines changed

1 file changed

+197
-88
lines changed

shim.c

Lines changed: 197 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -690,7 +690,7 @@ static EFI_STATUS check_whitelist (WIN_CERTIFICATE_EFI_PKCS *cert,
690690
}
691691

692692
update_verification_method(VERIFIED_BY_NOTHING);
693-
return EFI_SECURITY_VIOLATION;
693+
return EFI_NOT_FOUND;
694694
}
695695

696696
/*
@@ -1004,129 +1004,238 @@ static EFI_STATUS generate_hash (char *data, unsigned int datasize_in,
10041004
return efi_status;
10051005
}
10061006

1007+
static EFI_STATUS
1008+
verify_one_signature(WIN_CERTIFICATE_EFI_PKCS *sig,
1009+
UINT8 *sha256hash, UINT8 *sha1hash)
1010+
{
1011+
EFI_STATUS efi_status;
1012+
1013+
/*
1014+
* Ensure that the binary isn't blacklisted
1015+
*/
1016+
drain_openssl_errors();
1017+
efi_status = check_blacklist(sig, sha256hash, sha1hash);
1018+
if (EFI_ERROR(efi_status)) {
1019+
perror(L"Binary is blacklisted: %r\n", efi_status);
1020+
PrintErrors();
1021+
ClearErrors();
1022+
crypterr(efi_status);
1023+
return efi_status;
1024+
}
1025+
1026+
/*
1027+
* Check whether the binary is whitelisted in any of the firmware
1028+
* databases
1029+
*/
1030+
drain_openssl_errors();
1031+
efi_status = check_whitelist(sig, sha256hash, sha1hash);
1032+
if (EFI_ERROR(efi_status)) {
1033+
if (efi_status != EFI_NOT_FOUND) {
1034+
dprint(L"check_whitelist(): %r\n", efi_status);
1035+
PrintErrors();
1036+
ClearErrors();
1037+
crypterr(efi_status);
1038+
}
1039+
} else {
1040+
drain_openssl_errors();
1041+
return efi_status;
1042+
}
1043+
1044+
efi_status = EFI_NOT_FOUND;
1045+
#if defined(ENABLE_SHIM_CERT)
1046+
/*
1047+
* Check against the shim build key
1048+
*/
1049+
drain_openssl_errors();
1050+
if (build_cert && build_cert_size) {
1051+
dprint("verifying against shim cert\n");
1052+
}
1053+
if (build_cert && build_cert_size &&
1054+
AuthenticodeVerify(sig->CertData,
1055+
sig->Hdr.dwLength - sizeof(sig->Hdr),
1056+
build_cert, build_cert_size, sha256hash,
1057+
SHA256_DIGEST_SIZE)) {
1058+
dprint(L"AuthenticodeVerify(shim_cert) succeeded\n");
1059+
update_verification_method(VERIFIED_BY_CERT);
1060+
tpm_measure_variable(L"Shim", SHIM_LOCK_GUID,
1061+
build_cert_size, build_cert);
1062+
efi_status = EFI_SUCCESS;
1063+
drain_openssl_errors();
1064+
return efi_status;
1065+
} else {
1066+
dprint(L"AuthenticodeVerify(shim_cert) failed\n");
1067+
PrintErrors();
1068+
ClearErrors();
1069+
crypterr(EFI_NOT_FOUND);
1070+
}
1071+
#endif /* defined(ENABLE_SHIM_CERT) */
1072+
1073+
#if defined(VENDOR_CERT_FILE)
1074+
/*
1075+
* And finally, check against shim's built-in key
1076+
*/
1077+
drain_openssl_errors();
1078+
if (vendor_cert_size) {
1079+
dprint("verifying against vendor_cert\n");
1080+
}
1081+
if (vendor_cert_size &&
1082+
AuthenticodeVerify(sig->CertData,
1083+
sig->Hdr.dwLength - sizeof(sig->Hdr),
1084+
vendor_cert, vendor_cert_size,
1085+
sha256hash, SHA256_DIGEST_SIZE)) {
1086+
dprint(L"AuthenticodeVerify(vendor_cert) succeeded\n");
1087+
update_verification_method(VERIFIED_BY_CERT);
1088+
tpm_measure_variable(L"Shim", SHIM_LOCK_GUID,
1089+
vendor_cert_size, vendor_cert);
1090+
efi_status = EFI_SUCCESS;
1091+
drain_openssl_errors();
1092+
return efi_status;
1093+
} else {
1094+
dprint(L"AuthenticodeVerify(vendor_cert) failed\n");
1095+
PrintErrors();
1096+
ClearErrors();
1097+
crypterr(EFI_NOT_FOUND);
1098+
}
1099+
#endif /* defined(VENDOR_CERT_FILE) */
1100+
1101+
return efi_status;
1102+
}
1103+
10071104
/*
10081105
* Check that the signature is valid and matches the binary
10091106
*/
10101107
static EFI_STATUS verify_buffer (char *data, int datasize,
10111108
PE_COFF_LOADER_IMAGE_CONTEXT *context,
10121109
UINT8 *sha256hash, UINT8 *sha1hash)
10131110
{
1014-
EFI_STATUS efi_status = EFI_SECURITY_VIOLATION;
1015-
WIN_CERTIFICATE_EFI_PKCS *cert = NULL;
1016-
unsigned int size = datasize;
1111+
EFI_STATUS ret_efi_status;
1112+
size_t size = datasize;
1113+
size_t offset = 0;
1114+
unsigned int i = 0;
10171115

10181116
if (datasize < 0)
10191117
return EFI_INVALID_PARAMETER;
10201118

1021-
if (context->SecDir->Size != 0) {
1022-
if (context->SecDir->Size >= size) {
1023-
perror(L"Certificate Database size is too large\n");
1024-
return EFI_INVALID_PARAMETER;
1025-
}
1026-
1027-
cert = ImageAddress (data, size,
1028-
context->SecDir->VirtualAddress);
1029-
1030-
if (!cert) {
1031-
perror(L"Certificate located outside the image\n");
1032-
return EFI_INVALID_PARAMETER;
1033-
}
1034-
1035-
if (cert->Hdr.dwLength > context->SecDir->Size) {
1036-
perror(L"Certificate list size is inconsistent with PE headers");
1037-
return EFI_INVALID_PARAMETER;
1038-
}
1039-
1040-
if (cert->Hdr.wCertificateType !=
1041-
WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
1042-
perror(L"Unsupported certificate type %x\n",
1043-
cert->Hdr.wCertificateType);
1044-
return EFI_UNSUPPORTED;
1045-
}
1046-
}
1047-
10481119
/*
10491120
* Clear OpenSSL's error log, because we get some DSO unimplemented
10501121
* errors during its intialization, and we don't want those to look
10511122
* like they're the reason for validation failures.
10521123
*/
10531124
drain_openssl_errors();
10541125

1055-
efi_status = generate_hash(data, datasize, context, sha256hash, sha1hash);
1056-
if (EFI_ERROR(efi_status)) {
1057-
LogError(L"generate_hash: %r\n", efi_status);
1058-
return efi_status;
1126+
ret_efi_status = generate_hash(data, datasize, context, sha256hash, sha1hash);
1127+
if (EFI_ERROR(ret_efi_status)) {
1128+
dprint(L"generate_hash: %r\n", ret_efi_status);
1129+
PrintErrors();
1130+
ClearErrors();
1131+
crypterr(ret_efi_status);
1132+
return ret_efi_status;
10591133
}
10601134

10611135
/*
1062-
* Ensure that the binary isn't blacklisted
1136+
* Ensure that the binary isn't blacklisted by hash
10631137
*/
1064-
efi_status = check_blacklist(cert, sha256hash, sha1hash);
1065-
if (EFI_ERROR(efi_status)) {
1138+
drain_openssl_errors();
1139+
ret_efi_status = check_blacklist(NULL, sha256hash, sha1hash);
1140+
if (EFI_ERROR(ret_efi_status)) {
10661141
perror(L"Binary is blacklisted\n");
1067-
LogError(L"Binary is blacklisted: %r\n", efi_status);
1068-
return efi_status;
1142+
dprint(L"Binary is blacklisted: %r\n", ret_efi_status);
1143+
PrintErrors();
1144+
ClearErrors();
1145+
crypterr(ret_efi_status);
1146+
return ret_efi_status;
10691147
}
10701148

10711149
/*
1072-
* Check whether the binary is whitelisted in any of the firmware
1073-
* databases
1150+
* Check whether the binary is whitelisted by hash in any of the
1151+
* firmware databases
10741152
*/
1075-
efi_status = check_whitelist(cert, sha256hash, sha1hash);
1076-
if (EFI_ERROR(efi_status)) {
1077-
LogError(L"check_whitelist(): %r\n", efi_status);
1153+
drain_openssl_errors();
1154+
ret_efi_status = check_whitelist(NULL, sha256hash, sha1hash);
1155+
if (EFI_ERROR(ret_efi_status)) {
1156+
dprint(L"check_whitelist: %r\n", ret_efi_status);
1157+
if (ret_efi_status != EFI_NOT_FOUND) {
1158+
PrintErrors();
1159+
ClearErrors();
1160+
crypterr(ret_efi_status);
1161+
return ret_efi_status;
1162+
}
10781163
} else {
10791164
drain_openssl_errors();
1080-
return efi_status;
1165+
return ret_efi_status;
10811166
}
10821167

1083-
if (cert) {
1084-
#if defined(ENABLE_SHIM_CERT)
1085-
/*
1086-
* Check against the shim build key
1087-
*/
1088-
if (sizeof(shim_cert) &&
1089-
AuthenticodeVerify(cert->CertData,
1090-
cert->Hdr.dwLength - sizeof(cert->Hdr),
1091-
shim_cert, sizeof(shim_cert), sha256hash,
1092-
SHA256_DIGEST_SIZE)) {
1093-
update_verification_method(VERIFIED_BY_CERT);
1094-
tpm_measure_variable(L"Shim", SHIM_LOCK_GUID,
1095-
sizeof(shim_cert), shim_cert);
1096-
efi_status = EFI_SUCCESS;
1097-
drain_openssl_errors();
1098-
return efi_status;
1099-
} else {
1100-
LogError(L"AuthenticodeVerify(shim_cert) failed\n");
1168+
if (context->SecDir->Size == 0) {
1169+
dprint(L"No signatures found\n");
1170+
return EFI_SECURITY_VIOLATION;
1171+
}
1172+
1173+
if (context->SecDir->Size >= size) {
1174+
perror(L"Certificate Database size is too large\n");
1175+
return EFI_INVALID_PARAMETER;
1176+
}
1177+
1178+
ret_efi_status = EFI_NOT_FOUND;
1179+
do {
1180+
WIN_CERTIFICATE_EFI_PKCS *sig = NULL;
1181+
size_t sz;
1182+
1183+
sig = ImageAddress(data, size,
1184+
context->SecDir->VirtualAddress + offset);
1185+
if (!sig)
1186+
break;
1187+
1188+
sz = offset + offsetof(WIN_CERTIFICATE_EFI_PKCS, Hdr.dwLength)
1189+
+ sizeof(sig->Hdr.dwLength);
1190+
if (sz > context->SecDir->Size) {
1191+
perror(L"Certificate size is too large for secruity database");
1192+
return EFI_INVALID_PARAMETER;
11011193
}
1102-
#endif /* defined(ENABLE_SHIM_CERT) */
11031194

1104-
#if defined(VENDOR_CERT_FILE)
1105-
/*
1106-
* And finally, check against shim's built-in key
1107-
*/
1108-
if (vendor_authorized_size &&
1109-
AuthenticodeVerify(cert->CertData,
1110-
cert->Hdr.dwLength - sizeof(cert->Hdr),
1111-
vendor_authorized, vendor_authorized_size,
1112-
sha256hash, SHA256_DIGEST_SIZE)) {
1113-
update_verification_method(VERIFIED_BY_CERT);
1114-
tpm_measure_variable(L"Shim", SHIM_LOCK_GUID,
1115-
vendor_authorized_size, vendor_authorized);
1116-
efi_status = EFI_SUCCESS;
1117-
drain_openssl_errors();
1118-
return efi_status;
1195+
sz = sig->Hdr.dwLength;
1196+
if (sz > context->SecDir->Size - offset) {
1197+
perror(L"Certificate size is too large for secruity database");
1198+
return EFI_INVALID_PARAMETER;
1199+
}
1200+
1201+
if (sz < sizeof(sig->Hdr)) {
1202+
perror(L"Certificate size is too small for certificate data");
1203+
return EFI_INVALID_PARAMETER;
1204+
}
1205+
1206+
if (sig->Hdr.wCertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
1207+
EFI_STATUS efi_status;
1208+
1209+
dprint(L"Attempting to verify signature %d:\n", i++);
1210+
1211+
efi_status = verify_one_signature(sig, sha256hash, sha1hash);
1212+
1213+
/*
1214+
* If we didn't get EFI_SECURITY_VIOLATION from
1215+
* checking the hashes above, then any dbx entries are
1216+
* for a certificate, not this individual binary.
1217+
*
1218+
* So don't clobber successes with security violation
1219+
* here; that just means it isn't a success.
1220+
*/
1221+
if (ret_efi_status != EFI_SUCCESS)
1222+
ret_efi_status = efi_status;
11191223
} else {
1120-
LogError(L"AuthenticodeVerify(vendor_authorized) failed\n");
1224+
perror(L"Unsupported certificate type %x\n",
1225+
sig->Hdr.wCertificateType);
11211226
}
1122-
#endif /* defined(VENDOR_CERT_FILE) */
1123-
}
1227+
offset = ALIGN_VALUE(offset + sz, 8);
1228+
} while (offset < context->SecDir->Size);
11241229

1125-
LogError(L"Binary is not whitelisted\n");
1126-
crypterr(EFI_SECURITY_VIOLATION);
1127-
PrintErrors();
1128-
efi_status = EFI_SECURITY_VIOLATION;
1129-
return efi_status;
1230+
if (ret_efi_status != EFI_SUCCESS) {
1231+
dprint(L"Binary is not whitelisted\n");
1232+
PrintErrors();
1233+
ClearErrors();
1234+
crypterr(EFI_SECURITY_VIOLATION);
1235+
ret_efi_status = EFI_SECURITY_VIOLATION;
1236+
}
1237+
drain_openssl_errors();
1238+
return ret_efi_status;
11301239
}
11311240

11321241
/*

0 commit comments

Comments
 (0)