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 __FBSDID("$FreeBSD$"); 29 30 #include <stand.h> 31 #include <string.h> 32 33 #include <efi.h> 34 #include <efilib.h> 35 #include <Guid/ImageAuthentication.h> 36 37 #define NEED_BRSSL_H 38 #include "../libsecureboot-priv.h" 39 #include <brssl.h> 40 41 static EFI_GUID ImageSecurityDatabaseGUID = EFI_IMAGE_SECURITY_DATABASE_GUID; 42 43 static EFI_GUID efiCertX509GUID = EFI_CERT_X509_GUID; 44 static EFI_GUID efiCertX509Sha256GUID = EFI_CERT_X509_SHA256_GUID; 45 static EFI_GUID efiCertX509Sha384GUID = EFI_CERT_X509_SHA384_GUID; 46 static EFI_GUID efiCertX509Sha5122UID = EFI_CERT_X509_SHA512_GUID; 47 48 /* 49 * Check if Secure Boot is enabled in firmware. 50 * We evaluate two variables - Secure Boot and Setup Mode. 51 * Secure Boot is enforced only if the first one equals 1 and the other 0. 52 */ 53 int 54 efi_secure_boot_enabled(void) 55 { 56 UINT8 SecureBoot; 57 UINT8 SetupMode; 58 size_t length; 59 EFI_STATUS status; 60 61 length = sizeof(SecureBoot); 62 status = efi_global_getenv("SecureBoot", &SecureBoot, &length); 63 if (status != EFI_SUCCESS) { 64 if (status == EFI_NOT_FOUND) 65 return (0); 66 67 printf("Failed to read \"SecureBoot\" variable\n"); 68 return (-efi_status_to_errno(status)); 69 } 70 71 length = sizeof(SetupMode); 72 status = efi_global_getenv("SetupMode", &SetupMode, &length); 73 if (status != EFI_SUCCESS) 74 SetupMode = 0; 75 76 printf(" SecureBoot: %d, SetupMode: %d\n", SecureBoot, SetupMode); 77 78 return (SecureBoot == 1 && SetupMode == 0); 79 } 80 81 /* 82 * Iterate through UEFI variable and extract X509 certificates from it. 83 * The EFI_* structures and related guids are defined in UEFI standard. 84 */ 85 static br_x509_certificate* 86 efi_get_certs(const char *name, size_t *count) 87 { 88 br_x509_certificate *certs; 89 UINT8 *database; 90 EFI_SIGNATURE_LIST *list; 91 EFI_SIGNATURE_DATA *entry; 92 size_t db_size; 93 ssize_t cert_count; 94 EFI_STATUS status; 95 96 database = NULL; 97 certs = NULL; 98 db_size = 0; 99 cert_count = 0; 100 101 /* 102 * Read variable length and allocate memory for it 103 */ 104 status = efi_getenv(&ImageSecurityDatabaseGUID, name, database, &db_size); 105 if (status != EFI_BUFFER_TOO_SMALL) 106 return (NULL); 107 108 database = malloc(db_size); 109 if (database == NULL) 110 return (NULL); 111 112 status = efi_getenv(&ImageSecurityDatabaseGUID, name, database, &db_size); 113 if (status != EFI_SUCCESS) 114 goto fail; 115 116 for (list = (EFI_SIGNATURE_LIST*) database; 117 db_size >= list->SignatureListSize && db_size > 0; 118 db_size -= list->SignatureListSize, 119 list = (EFI_SIGNATURE_LIST*) 120 ((UINT8*)list + list->SignatureListSize)) { 121 122 /* We are only interested in entries containing X509 certs. */ 123 if (memcmp(&efiCertX509GUID, 124 &list->SignatureType, 125 sizeof(EFI_GUID)) != 0) { 126 continue; 127 } 128 129 entry = (EFI_SIGNATURE_DATA*) 130 ((UINT8*)list + 131 sizeof(EFI_SIGNATURE_LIST) + 132 list->SignatureHeaderSize); 133 134 certs = realloc(certs, 135 (cert_count + 1) * sizeof(br_x509_certificate)); 136 if (certs == NULL) { 137 cert_count = 0; 138 goto fail; 139 } 140 141 certs[cert_count].data_len = list->SignatureSize - sizeof(EFI_GUID); 142 certs[cert_count].data = malloc(certs[cert_count].data_len); 143 if (certs[cert_count].data == NULL) 144 goto fail; 145 146 memcpy(certs[cert_count].data, 147 entry->SignatureData, 148 certs[cert_count].data_len); 149 150 cert_count++; 151 } 152 153 *count = cert_count; 154 155 xfree(database); 156 return (certs); 157 158 fail: 159 free_certificates(certs, cert_count); 160 xfree(database); 161 return (NULL); 162 163 } 164 165 /* 166 * Extract digests from UEFI "dbx" variable. 167 * UEFI standard specifies three types of digest - sha256, sha386, sha512. 168 */ 169 hash_data* 170 efi_get_forbidden_digests(size_t *count) 171 { 172 UINT8 *database; 173 hash_data *digests; 174 EFI_SIGNATURE_LIST *list; 175 EFI_SIGNATURE_DATA *entry; 176 size_t db_size, header_size, hash_size; 177 int digest_count, entry_count; 178 EFI_STATUS status; 179 180 db_size = 0; 181 digest_count = 0; 182 database = NULL; 183 digests = NULL; 184 185 status = efi_getenv(&ImageSecurityDatabaseGUID, "dbx", database, &db_size); 186 if (status != EFI_BUFFER_TOO_SMALL) 187 return (NULL); 188 189 database = malloc(db_size); 190 if (database == NULL) 191 return (NULL); 192 193 status = efi_getenv(&ImageSecurityDatabaseGUID, "dbx", database, &db_size); 194 if (status != EFI_SUCCESS) 195 goto fail; 196 197 198 for (list = (EFI_SIGNATURE_LIST*) database; 199 db_size >= list->SignatureListSize && db_size > 0; 200 db_size -= list->SignatureListSize, 201 list = (EFI_SIGNATURE_LIST*) 202 ((UINT8*)list + list->SignatureListSize)) { 203 204 /* We are only interested in entries that contain digests. */ 205 if (memcmp(&efiCertX509Sha256GUID, &list->SignatureType, 206 sizeof(EFI_GUID)) == 0) { 207 hash_size = br_sha256_SIZE; 208 } else if (memcmp(&efiCertX509Sha384GUID, &list->SignatureType, 209 sizeof(EFI_GUID)) == 0) { 210 hash_size = br_sha384_SIZE; 211 } else if (memcmp(&efiCertX509Sha5122UID, &list->SignatureType, 212 sizeof(EFI_GUID)) == 0) { 213 hash_size = br_sha512_SIZE; 214 } else { 215 continue; 216 } 217 218 /* 219 * A single entry can have multiple digests 220 * of the same type for some reason. 221 */ 222 header_size = sizeof(EFI_SIGNATURE_LIST) + list->SignatureHeaderSize; 223 224 /* Calculate the number of entries basing on structure size */ 225 entry_count = list->SignatureListSize - header_size; 226 entry_count /= list->SignatureSize; 227 entry = (EFI_SIGNATURE_DATA*)((UINT8*)list + header_size); 228 while (entry_count-- > 0) { 229 digests = realloc(digests, 230 (digest_count + 1) * sizeof(hash_data)); 231 if (digests == NULL) { 232 digest_count = 0; 233 goto fail; 234 } 235 236 digests[digest_count].data = malloc(hash_size); 237 if (digests[digest_count].data == NULL) 238 goto fail; 239 240 memcpy(digests[digest_count].data, 241 entry->SignatureData, 242 hash_size); 243 digests[digest_count].hash_size = hash_size; 244 245 entry = (EFI_SIGNATURE_DATA*)(entry + list->SignatureSize); 246 digest_count++; 247 } 248 } 249 xfree(database); 250 if (count != NULL) 251 *count = digest_count; 252 253 return (digests); 254 255 fail: 256 while (digest_count--) 257 xfree(digests[digest_count].data); 258 259 xfree(database); 260 xfree(digests); 261 return (NULL); 262 } 263 264 /* Copy x509 certificates from db */ 265 br_x509_certificate* 266 efi_get_trusted_certs(size_t *count) 267 { 268 return (efi_get_certs("db", count)); 269 } 270 271 /* Copy forbidden certificates from dbx */ 272 br_x509_certificate* 273 efi_get_forbidden_certs(size_t *count) 274 { 275 return (efi_get_certs("dbx", count)); 276 } 277