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