1 /*- 2 * Copyright (c) 2019 Stormshield. 3 * Copyright (c) 2019 Semihalf. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 18 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 23 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 * POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 #include <stand.h> 29 #include <string.h> 30 31 #include <efi.h> 32 #include <efilib.h> 33 #include <Uefi.h> 34 #include <Guid/ImageAuthentication.h> 35 36 #define NEED_BRSSL_H 37 #include "../libsecureboot-priv.h" 38 #include <brssl.h> 39 40 static EFI_GUID ImageSecurityDatabaseGUID = EFI_IMAGE_SECURITY_DATABASE_GUID; 41 42 static EFI_GUID efiCertX509GUID = EFI_CERT_X509_GUID; 43 static EFI_GUID efiCertX509Sha256GUID = EFI_CERT_X509_SHA256_GUID; 44 static EFI_GUID efiCertX509Sha384GUID = EFI_CERT_X509_SHA384_GUID; 45 static EFI_GUID efiCertX509Sha5122UID = EFI_CERT_X509_SHA512_GUID; 46 47 /* 48 * Check if Secure Boot is enabled in firmware. 49 * We evaluate two variables - Secure Boot and Setup Mode. 50 * Secure Boot is enforced only if the first one equals 1 and the other 0. 51 */ 52 int 53 efi_secure_boot_enabled(void) 54 { 55 UINT8 SecureBoot; 56 UINT8 SetupMode; 57 size_t length; 58 EFI_STATUS status; 59 60 length = sizeof(SecureBoot); 61 status = efi_global_getenv("SecureBoot", &SecureBoot, &length); 62 if (status != EFI_SUCCESS) { 63 if (status == EFI_NOT_FOUND) 64 return (0); 65 66 printf("Failed to read \"SecureBoot\" variable\n"); 67 return (-efi_status_to_errno(status)); 68 } 69 70 length = sizeof(SetupMode); 71 status = efi_global_getenv("SetupMode", &SetupMode, &length); 72 if (status != EFI_SUCCESS) 73 SetupMode = 0; 74 75 printf(" SecureBoot: %d, SetupMode: %d\n", SecureBoot, SetupMode); 76 77 return (SecureBoot == 1 && SetupMode == 0); 78 } 79 80 /* 81 * Iterate through UEFI variable and extract X509 certificates from it. 82 * The EFI_* structures and related guids are defined in UEFI standard. 83 */ 84 static br_x509_certificate* 85 efi_get_certs(const char *name, size_t *count) 86 { 87 br_x509_certificate *certs; 88 UINT8 *database; 89 EFI_SIGNATURE_LIST *list; 90 EFI_SIGNATURE_DATA *entry; 91 size_t db_size; 92 ssize_t cert_count; 93 EFI_STATUS status; 94 95 database = NULL; 96 certs = NULL; 97 db_size = 0; 98 cert_count = 0; 99 100 /* 101 * Read variable length and allocate memory for it 102 */ 103 status = efi_getenv(&ImageSecurityDatabaseGUID, name, database, &db_size); 104 if (status != EFI_BUFFER_TOO_SMALL) 105 return (NULL); 106 107 database = malloc(db_size); 108 if (database == NULL) 109 return (NULL); 110 111 status = efi_getenv(&ImageSecurityDatabaseGUID, name, database, &db_size); 112 if (status != EFI_SUCCESS) 113 goto fail; 114 115 for (list = (EFI_SIGNATURE_LIST*) database; 116 db_size >= list->SignatureListSize && db_size > 0; 117 db_size -= list->SignatureListSize, 118 list = (EFI_SIGNATURE_LIST*) 119 ((UINT8*)list + list->SignatureListSize)) { 120 121 /* We are only interested in entries containing X509 certs. */ 122 if (memcmp(&efiCertX509GUID, 123 &list->SignatureType, 124 sizeof(EFI_GUID)) != 0) { 125 continue; 126 } 127 128 entry = (EFI_SIGNATURE_DATA*) 129 ((UINT8*)list + 130 sizeof(EFI_SIGNATURE_LIST) + 131 list->SignatureHeaderSize); 132 133 certs = realloc(certs, 134 (cert_count + 1) * sizeof(br_x509_certificate)); 135 if (certs == NULL) { 136 cert_count = 0; 137 goto fail; 138 } 139 140 certs[cert_count].data_len = list->SignatureSize - sizeof(EFI_GUID); 141 certs[cert_count].data = malloc(certs[cert_count].data_len); 142 if (certs[cert_count].data == NULL) 143 goto fail; 144 145 memcpy(certs[cert_count].data, 146 entry->SignatureData, 147 certs[cert_count].data_len); 148 149 cert_count++; 150 } 151 152 *count = cert_count; 153 154 xfree(database); 155 return (certs); 156 157 fail: 158 free_certificates(certs, cert_count); 159 xfree(database); 160 return (NULL); 161 162 } 163 164 /* 165 * Extract digests from UEFI "dbx" variable. 166 * UEFI standard specifies three types of digest - sha256, sha386, sha512. 167 */ 168 hash_data* 169 efi_get_forbidden_digests(size_t *count) 170 { 171 UINT8 *database; 172 hash_data *digests; 173 EFI_SIGNATURE_LIST *list; 174 EFI_SIGNATURE_DATA *entry; 175 size_t db_size, header_size, hash_size; 176 int digest_count, entry_count; 177 EFI_STATUS status; 178 179 db_size = 0; 180 digest_count = 0; 181 database = NULL; 182 digests = NULL; 183 184 status = efi_getenv(&ImageSecurityDatabaseGUID, "dbx", database, &db_size); 185 if (status != EFI_BUFFER_TOO_SMALL) 186 return (NULL); 187 188 database = malloc(db_size); 189 if (database == NULL) 190 return (NULL); 191 192 status = efi_getenv(&ImageSecurityDatabaseGUID, "dbx", database, &db_size); 193 if (status != EFI_SUCCESS) 194 goto fail; 195 196 197 for (list = (EFI_SIGNATURE_LIST*) database; 198 db_size >= list->SignatureListSize && db_size > 0; 199 db_size -= list->SignatureListSize, 200 list = (EFI_SIGNATURE_LIST*) 201 ((UINT8*)list + list->SignatureListSize)) { 202 203 /* We are only interested in entries that contain digests. */ 204 if (memcmp(&efiCertX509Sha256GUID, &list->SignatureType, 205 sizeof(EFI_GUID)) == 0) { 206 hash_size = br_sha256_SIZE; 207 } else if (memcmp(&efiCertX509Sha384GUID, &list->SignatureType, 208 sizeof(EFI_GUID)) == 0) { 209 hash_size = br_sha384_SIZE; 210 } else if (memcmp(&efiCertX509Sha5122UID, &list->SignatureType, 211 sizeof(EFI_GUID)) == 0) { 212 hash_size = br_sha512_SIZE; 213 } else { 214 continue; 215 } 216 217 /* 218 * A single entry can have multiple digests 219 * of the same type for some reason. 220 */ 221 header_size = sizeof(EFI_SIGNATURE_LIST) + list->SignatureHeaderSize; 222 223 /* Calculate the number of entries basing on structure size */ 224 entry_count = list->SignatureListSize - header_size; 225 entry_count /= list->SignatureSize; 226 entry = (EFI_SIGNATURE_DATA*)((UINT8*)list + header_size); 227 while (entry_count-- > 0) { 228 digests = realloc(digests, 229 (digest_count + 1) * sizeof(hash_data)); 230 if (digests == NULL) { 231 digest_count = 0; 232 goto fail; 233 } 234 235 digests[digest_count].data = malloc(hash_size); 236 if (digests[digest_count].data == NULL) 237 goto fail; 238 239 memcpy(digests[digest_count].data, 240 entry->SignatureData, 241 hash_size); 242 digests[digest_count].hash_size = hash_size; 243 244 entry = (EFI_SIGNATURE_DATA*)(entry + list->SignatureSize); 245 digest_count++; 246 } 247 } 248 xfree(database); 249 if (count != NULL) 250 *count = digest_count; 251 252 return (digests); 253 254 fail: 255 while (digest_count--) 256 xfree(digests[digest_count].data); 257 258 xfree(database); 259 xfree(digests); 260 return (NULL); 261 } 262 263 /* Copy x509 certificates from db */ 264 br_x509_certificate* 265 efi_get_trusted_certs(size_t *count) 266 { 267 return (efi_get_certs("db", count)); 268 } 269 270 /* Copy forbidden certificates from dbx */ 271 br_x509_certificate* 272 efi_get_forbidden_certs(size_t *count) 273 { 274 return (efi_get_certs("dbx", count)); 275 } 276