1 /*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "trusty_secure_deletion_secret_storage.h"
18
19 #include <inttypes.h>
20
21 #include <array>
22 #include <optional>
23 #include <vector>
24
25 #include <lib/storage/storage.h>
26 #include <uapi/err.h>
27
28 #include <keymaster/logger.h>
29 #include <keymaster/random_source.h>
30
31 namespace keymaster {
32
33 namespace {
34
35 // Maximum number of attempts to perform a secure storage transaction to read or
36 // delete a secure deletion secret. Because the storageproxy may be restarted
37 // while this code is running, it may be necessary to retry. But because it's
38 // unclear exactly what error codes may be returned when the proxy is shut down,
39 // we conservatively retry all unexpected errors. To avoid an infinite loop, we
40 // set a limit on the number of retries (though hitting the limit and returning
41 // an error will likely break the boot anyway). Ideally, we should never need
42 // more than one retry. We allow three.
43 constexpr size_t kMaxTries = 3;
44
45 // Name of the file to store secrets. The "_1" suffix is to allow for new file
46 // formats/versions in the future.
47 constexpr char kSecureDeletionSecretFileName[] = "SecureDeletionSecrets_1";
48
49 // Each secret is 16 bytes.
50 constexpr storage_off_t kSecretSize = 16;
51
52 // The factory reset secret is composed of two secrets, so 32 bytes, and it's
53 // stored at offset 0.
54 constexpr storage_off_t kFactoryResetSecretSize = kSecretSize * 2;
55 constexpr storage_off_t kFactoryResetSecretPos = 0;
56 constexpr storage_off_t kFirstSecureDeletionSecretPos =
57 kFactoryResetSecretPos + kFactoryResetSecretSize;
58
59 // We read secrets in blocks of 32, so 512 bytes.
60 constexpr storage_off_t kBlockSize = kSecretSize * 32;
61
62 // Limit file size to 16 KiB (except for key upgrades, see
63 // kMaxSecretFileSizeForUpgrades).
64 constexpr storage_off_t kMaxSecretFileSize = kBlockSize * 32;
65
66 // This is a higher file size limit, with the space above kMaxSecretFileSize
67 // usable only for key IDs that need to be written as part of a key upgrade.
68 // This is to reduce the probability that keys are degraded as a result of
69 // upgrading.
70 constexpr storage_off_t kMaxSecretFileSizeForUpgrades =
71 kMaxSecretFileSize + 8 * kBlockSize;
72
73 // We set a bit in the first byte of each slot to indicate that the slot is in
74 // use. This reduces the maximum entropy of each slot to 127 bits.
75 constexpr uint8_t kInUseFlag = 0x80;
76
77 /**
78 * StorageFile represents a secure storage file, and provides operations on it.
79 * Use StorageSession::OpenFile to create a StorageFile.
80 */
81 class StorageFile {
82 public:
83 StorageFile(const StorageFile&) = delete;
84 StorageFile& operator=(const StorageFile&) = delete;
85
StorageFile(StorageFile && rhs)86 StorageFile(StorageFile&& rhs)
87 : fileHandle_(std::move(rhs.fileHandle_)),
88 fileSize_(rhs.fileSize_) {
89 rhs.fileHandle_ = std::nullopt;
90 rhs.fileSize_ = 0;
91 }
92
~StorageFile()93 ~StorageFile() { CloseFile(); }
94
95 /**
96 * Close the file.
97 *
98 * Note that normally it's not necessary to call this, because the dtor
99 * will.
100 */
CloseFile()101 void CloseFile() {
102 if (!fileHandle_) {
103 return;
104 }
105
106 LOG_D("Closing file handle %" PRIu64, *fileHandle_);
107 storage_close_file(*fileHandle_);
108 fileHandle_ = std::nullopt;
109 }
110
111 /**
112 * Return size of file.
113 */
size() const114 storage_off_t size() const { return fileSize_; }
115
116 /**
117 * Reads a block of bytes from the file. On error returns std::nullopt.
118 */
ReadBlock(storage_off_t readPos,storage_off_t bytesToRead) const119 std::optional<Buffer> ReadBlock(storage_off_t readPos,
120 storage_off_t bytesToRead) const {
121 if (!fileHandle_) {
122 return std::nullopt;
123 }
124
125 Buffer buf(bytesToRead);
126 if (buf.buffer_size() < bytesToRead) {
127 LOG_E("Error memory allocation failed trying to allocate ReadBlock buffer.");
128 return std::nullopt;
129 }
130
131 ssize_t bytesRead = storage_read(
132 *fileHandle_, readPos, buf.peek_write(), buf.available_write());
133 if (bytesRead < 0) {
134 LOG_E("Error %zd reading file", bytesRead);
135 return std::nullopt;
136 } else if (static_cast<size_t>(bytesRead) < bytesToRead) {
137 LOG_E("Error attempt to read %" PRIu64
138 " bytes returned only %zd bytes",
139 bytesToRead, bytesRead);
140 return std::nullopt;
141 }
142
143 if (!buf.advance_write(bytesRead)) {
144 LOG_E("Failed to update buffer write position. Code error.");
145 return std::nullopt;
146 }
147 return buf;
148 }
149
150 /**
151 * Write a block of bytes from `data` of size `size` to storage at offset
152 * `pos`. Will not extend the file.
153 *
154 * Returns false if the write would go past the end of the file, or if an
155 * error occurs (all errors are logged).
156 */
WriteBlock(storage_off_t pos,const uint8_t * data,size_t size) const157 bool WriteBlock(storage_off_t pos, const uint8_t* data, size_t size) const {
158 if (!fileHandle_) {
159 LOG_E("Attempt to write to invalid file handle");
160 return false;
161 }
162
163 storage_off_t end;
164 if (__builtin_add_overflow(pos, size, &end) || end > fileSize_) {
165 LOG_E("Attempt to write past EOF");
166 return false;
167 }
168
169 ssize_t bytesWritten =
170 storage_write(*fileHandle_, pos, data, size, 0 /* opflags */);
171 if (bytesWritten < 0) {
172 LOG_E("Error %zd writing rollback record at offset %" PRIu64,
173 bytesWritten, pos);
174 return false;
175 } else if (static_cast<size_t>(bytesWritten) < size) {
176 LOG_E("Wrote %zd of %zu bytes", bytesWritten, size);
177 return false;
178 }
179
180 return true;
181 }
182
183 /**
184 * Resize the file to `newSize` bytes.
185 *
186 * Returns error code from uapi/err.h. Errors are logged.
187 */
Resize(storage_off_t newSize)188 int Resize(storage_off_t newSize) {
189 if (!fileHandle_) {
190 LOG_E("Attempt to resize invalid file handle");
191 return ERR_NOT_VALID;
192 }
193
194 int rc = storage_set_file_size(*fileHandle_, newSize, 0 /* opflags */);
195 if (rc) {
196 LOG_E("Error %d resizing file from %" PRIu64 " to %" PRIu64, rc,
197 fileSize_, newSize);
198 return rc;
199 }
200
201 fileSize_ = newSize;
202 return NO_ERROR;
203 }
204
205 private:
206 friend class StorageSession;
207
StorageFile(file_handle_t fileHandle,storage_off_t fileSize)208 StorageFile(file_handle_t fileHandle, storage_off_t fileSize)
209 : fileHandle_(fileHandle), fileSize_(fileSize) {}
210
211 std::optional<file_handle_t> fileHandle_;
212 storage_off_t fileSize_;
213 };
214
215 /**
216 * StorageSession represents a secure storage session, and provides methods to
217 * manipulate files within the session, and to finalize a storage transaction.
218 */
219 class StorageSession {
220 public:
221 // Error codes used by DeleteFile.
222 enum class Error : uint32_t {
223 OK = 0,
224 NOT_FOUND = 1,
225 UNKNOWN = 2,
226 };
227
228 StorageSession(const StorageSession&) = delete;
StorageSession(StorageSession && rhs)229 StorageSession(StorageSession&& rhs) : session_(rhs.session_) {
230 rhs.session_ = STORAGE_INVALID_SESSION;
231 }
~StorageSession()232 ~StorageSession() {
233 if (session_ != STORAGE_INVALID_SESSION) {
234 LOG_D("Closing storage session %" PRIu32, session_);
235 storage_close_session(session_);
236 }
237 }
238
239 /**
240 * Creates a session, connected to the specified port.
241 *
242 * There is a possibility that the port has not been created when this
243 * method is called. In this case its behavior is determined by the
244 * `waitForPort` argument:
245 *
246 * - if true, the method will block until the port is available and the
247 * connection is completed.
248 *
249 * - if false, the method will return std::nullopt immediately.
250 *
251 * If the port exists, this method will block until the connection is
252 * completed.
253 */
CreateSession(bool waitForPort=true,const char * port=STORAGE_CLIENT_TP_PORT)254 static std::optional<StorageSession> CreateSession(
255 bool waitForPort = true,
256 const char* port = STORAGE_CLIENT_TP_PORT) {
257 LOG_D("Opening storage session on port %s (wait: %s)", port,
258 waitForPort ? "true" : "false");
259 // We use connect rather than storage_open_session because the latter
260 // always waits for the port.
261 long rc = connect(port, waitForPort ? IPC_CONNECT_WAIT_FOR_PORT : 0);
262 if (rc < 0) {
263 LOG_E("Error %ld opening storage session on port %s.", rc, port);
264 return std::nullopt;
265 }
266 storage_session_t session = static_cast<storage_session_t>(rc);
267 LOG_D("Opened storage session %" PRIu32, session);
268 return StorageSession(session);
269 }
270
271 /**
272 * Open a file. Returns std::nullopt on failure (after logging error code).
273 */
OpenFile(const char * fileName,uint32_t flags=STORAGE_FILE_OPEN_CREATE) const274 std::optional<StorageFile> OpenFile(
275 const char* fileName,
276 uint32_t flags = STORAGE_FILE_OPEN_CREATE) const {
277 file_handle_t fileHandle;
278 int err = storage_open_file(session_, &fileHandle, fileName, flags,
279 0 /* opflags */);
280 if (err) {
281 LOG_E("Error %d opening file %s", err, fileName);
282 return std::nullopt;
283 }
284 LOG_D("Opened file %s with handle %" PRIu64, fileName, fileHandle);
285
286 storage_off_t fileSize;
287 err = storage_get_file_size(fileHandle, &fileSize);
288 if (err) {
289 LOG_E("Error %d reading size of file %s", err, fileName);
290 storage_close_file(fileHandle);
291 return std::nullopt;
292 }
293 return StorageFile(fileHandle, fileSize);
294 }
295
296 /**
297 * Delete a file.
298 *
299 * Returns Error::OK on success, Error::NOT_FOUND, if the file did not
300 * exist, Error::UNKNOWN in any other case.
301 */
DeleteFile(const char * fileName) const302 Error DeleteFile(const char* fileName) const {
303 int rc = storage_delete_file(session_, fileName, 0 /* opflags */);
304 if (rc < 0) {
305 LOG_E("Error (%d) deleting file %s", rc, fileName);
306 if (rc == ERR_NOT_FOUND) {
307 return Error::NOT_FOUND;
308 } else {
309 return Error::UNKNOWN;
310 }
311 }
312 return Error::OK;
313 }
314
315 /**
316 * Ends current transaction (any uncommitted changes in this session),
317 * either committing or aborting (rolling back) the changes, as specified by
318 * `commit`.
319 *
320 * Note failing to commit the transaction will result in it being lost.
321 *
322 * Returns true on success, false on failure.
323 */
EndTransaction(bool commit)324 bool EndTransaction(bool commit) {
325 int rc = storage_end_transaction(session_, commit);
326 if (rc < 0) {
327 LOG_E("Error (%d) committing transaction", rc);
328 return false;
329 }
330 return true;
331 }
332
333 private:
StorageSession(storage_session_t session)334 StorageSession(storage_session_t session) : session_(session) {}
335
336 storage_session_t session_;
337 };
338
339 /**
340 * Zeros each secret from position `begin` to position `end`.
341 */
zero_entries(const StorageFile & file,storage_off_t begin,storage_off_t end)342 bool zero_entries(const StorageFile& file,
343 storage_off_t begin,
344 storage_off_t end) {
345 if (begin % kSecretSize != 0) {
346 LOG_S("zero_entries called with invalid offset %" PRIu64, begin);
347 return false;
348 }
349
350 for (storage_off_t pos = begin; pos < end; pos += kSecretSize) {
351 uint8_t zero_buf[kSecretSize] = {0x00, 0x00, 0x00, 0x00, //
352 0x00, 0x00, 0x00, 0x00, //
353 0x00, 0x00, 0x00, 0x00, //
354 0x00, 0x00, 0x00, 0x00};
355 if (!file.WriteBlock(pos, zero_buf, sizeof(zero_buf))) {
356 LOG_E("Failed to zero secret at offset %" PRIu64, pos);
357 return false;
358 }
359 }
360
361 return true;
362 }
363
364 /**
365 * Finds an empty slot in file. Returns empty on error, 0 on failure to
366 * find an empty slot and a valid (>0) slot number otherwise.
367 */
find_empty_slot(const StorageFile & file,bool isUpgrade)368 std::optional<uint32_t /* keySlot */> find_empty_slot(const StorageFile& file,
369 bool isUpgrade) {
370 storage_off_t end =
371 std::min(file.size(), isUpgrade ? kMaxSecretFileSizeForUpgrades
372 : kMaxSecretFileSize);
373
374 uint32_t retval = 0;
375 for (storage_off_t filePos = 0; filePos < end; filePos += kBlockSize) {
376 std::optional<Buffer> block = file.ReadBlock(filePos, kBlockSize);
377 if (!block) {
378 LOG_E("Failed to read block of secrets");
379 return std::nullopt;
380 }
381
382 size_t blockPos =
383 filePos == kFactoryResetSecretPos ? kFactoryResetSecretSize : 0;
384 for (; blockPos < block->available_read(); blockPos += kSecretSize) {
385 uint8_t first_byte = *(block->begin() + blockPos);
386 if ((first_byte & kInUseFlag) == 0 && retval == 0) {
387 static_assert(kBlockSize % kSecretSize == 0 &&
388 kFactoryResetSecretSize % kSecretSize == 0);
389 retval = static_cast<uint32_t>((filePos + blockPos) /
390 kSecretSize);
391 }
392 }
393 }
394
395 return retval;
396 }
397
398 // Helper class that calls the provided function (probably a lambda) on
399 // destruction if not disarmed.
400 template <typename F>
401 class OnExit {
402 public:
OnExit(F f)403 OnExit(F f) : f_(f) {}
~OnExit()404 ~OnExit() {
405 if (!disarmed_) {
406 f_();
407 }
408 }
409
disarm()410 void disarm() { disarmed_ = true; }
411
412 private:
413 F f_;
414 bool disarmed_ = false;
415 };
416
417 } // namespace
418
LoadOrCreateFactoryResetSecret(bool wait_for_port) const419 bool TrustySecureDeletionSecretStorage::LoadOrCreateFactoryResetSecret(
420 bool wait_for_port) const {
421 if (factory_reset_secret_) {
422 // Already read.
423 return true;
424 }
425
426 LOG_D("Trying to open a session to read factory reset secret");
427 std::optional<StorageSession> session =
428 StorageSession::CreateSession(wait_for_port);
429 if (!session) {
430 return false;
431 }
432
433 LOG_D("Trying to open secure secrets file");
434 std::optional<StorageFile> file =
435 session->OpenFile(kSecureDeletionSecretFileName);
436 if (!file) {
437 // This shouldn't be possible, unless maybe the session just went away?
438 LOG_E("Can't open secure secrets file.");
439 return false;
440 }
441
442 if (file->size() > 0) {
443 LOG_D("Opened non-empty secure secrets file.");
444 std::optional<Buffer> block = file->ReadBlock(kFactoryResetSecretPos,
445 kFactoryResetSecretSize);
446 if (!block) {
447 LOG_E("Failed to read factory reset secret");
448 return false;
449 }
450
451 LOG_D("Read factory-reset secret, size %zu", block->available_read());
452 factory_reset_secret_ = std::move(block);
453 return true;
454 }
455
456 // The file was just created. Need to create the factory reset secret.
457 LOG_I("Created new secure secrets file, size %" PRIu64, file->size());
458 if (file->Resize(kBlockSize) != NO_ERROR) {
459 LOG_E("Failed to grow new file from 0 to %" PRIu64 " bytes",
460 kBlockSize);
461 return false;
462 }
463 LOG_D("Resized secure secrets file to size %" PRIu64, file->size());
464
465 static_assert(kBlockSize >= kFactoryResetSecretSize);
466 Buffer buf(kFactoryResetSecretSize);
467 keymaster_error_t error =
468 random_.GenerateRandom(buf.peek_write(), buf.available_write());
469 if (error != KM_ERROR_OK || !buf.advance_write(kFactoryResetSecretSize)) {
470 LOG_E("Failed to generate %" PRIu64
471 " random bytes for factory reset secret",
472 kFactoryResetSecretSize);
473 return false;
474 }
475
476 if (!file->WriteBlock(kFactoryResetSecretPos, buf.peek_read(),
477 buf.available_read())) {
478 LOG_E("Failed to write factory reset secret");
479 return false;
480 }
481 LOG_D("Wrote new factory reset secret.");
482
483 if (!zero_entries(*file, kFirstSecureDeletionSecretPos /* begin */,
484 kBlockSize /* end */)) {
485 LOG_E("Failed to zero secure deletion secret entries in first block");
486 return false;
487 }
488 LOG_D("Zeroed secrets.");
489
490 if (!session->EndTransaction(true /* commit */)) {
491 LOG_E("Failed to commit transaction creating secure secrets file");
492 return false;
493 }
494 LOG_D("Committed new secrets file.");
495
496 LOG_I("Got factory reset secret of size %zu", buf.buffer_size());
497 factory_reset_secret_ = std::move(buf);
498 return true;
499 }
500
501 std::optional<SecureDeletionData>
CreateDataForNewKey(bool secure_deletion,bool is_upgrade) const502 TrustySecureDeletionSecretStorage::CreateDataForNewKey(bool secure_deletion,
503 bool is_upgrade) const {
504 if (!LoadOrCreateFactoryResetSecret(false /* wait_for_port */) ||
505 !factory_reset_secret_) {
506 // Unable to get factory reset secret from secure storage.
507 LOG_I("Unable to get factory reset secret");
508 return std::nullopt;
509 }
510
511 SecureDeletionData retval;
512 retval.factory_reset_secret.Reinitialize(*factory_reset_secret_);
513
514 if (!secure_deletion) {
515 LOG_D("Secure deletion not requested.");
516 return retval;
517 }
518
519 retval.secure_deletion_secret.reserve(kSecretSize);
520 if (retval.secure_deletion_secret.buffer_size() == 0) {
521 return std::nullopt;
522 }
523
524 keymaster_error_t error = random_.GenerateRandom(
525 retval.secure_deletion_secret.peek_write(),
526 retval.secure_deletion_secret.available_write());
527 if (error != KM_ERROR_OK) {
528 // Ths really shouldn't be possible. Perhaps we should abort()?
529 LOG_E("Failed to create secure deletion secret");
530 return std::nullopt;
531 }
532 retval.secure_deletion_secret.peek_write()[0] |= kInUseFlag;
533 retval.secure_deletion_secret.advance_write(
534 retval.secure_deletion_secret.available_write());
535
536 auto sds_cleanup = OnExit([&]() { retval.secure_deletion_secret.Clear(); });
537
538 std::optional<StorageSession> session =
539 StorageSession::CreateSession(); // Will block
540
541 if (!session) {
542 LOG_E("Failed to open session in CreateDateForNewKey");
543 return retval;
544 }
545 LOG_D("Opened session to store secure deletion secret.");
546
547 std::optional<StorageFile> file =
548 session->OpenFile(kSecureDeletionSecretFileName);
549 if (!file) {
550 LOG_E("Failed to open file in CreateDateForNewKey");
551 return retval;
552 }
553 LOG_D("Opened file to store secure deletion secret.");
554
555 std::optional<uint32_t> keySlot = find_empty_slot(*file, is_upgrade);
556 if (!keySlot) {
557 LOG_E("Error while searching for key slot");
558 return retval;
559 }
560
561 if (*keySlot == 0) {
562 bool can_resize =
563 file->size() < kMaxSecretFileSize ||
564 (is_upgrade && file->size() < kMaxSecretFileSizeForUpgrades);
565
566 if (!can_resize) {
567 LOG_E("Didn't find a slot and can't grow the file larger than %" PRIu64,
568 file->size());
569 return retval;
570 }
571
572 storage_off_t old_size = file->size();
573 LOG_D("Attempting to resize file from %" PRIu64 " to %" PRIu64,
574 file->size(), file->size() + kBlockSize);
575 int rc = file->Resize(old_size + kBlockSize);
576 if (rc != NO_ERROR) {
577 LOG_E("Failed (%d) to grow file to make room for a key slot", rc);
578 return retval;
579 }
580 LOG_D("Resized file to %" PRIu64, file->size());
581
582 if (!zero_entries(*file, old_size, file->size())) {
583 LOG_E("Error zeroing space in extended file");
584 return retval;
585 }
586
587 keySlot = old_size / kSecretSize;
588 }
589
590 LOG_D("Writing new deletion secret to key slot %u", *keySlot);
591 if (!file->WriteBlock(*keySlot * kSecretSize,
592 retval.secure_deletion_secret.peek_read(),
593 retval.secure_deletion_secret.available_read())) {
594 LOG_E("Failed to write new deletion secret to key slot %u", *keySlot);
595 return retval;
596 }
597
598 if (!session->EndTransaction(true /* commit */)) {
599 LOG_E("Failed to commit transaction writing new deletion secret to slot %u",
600 *keySlot);
601 return retval;
602 }
603 LOG_D("Committed new secret.");
604
605 sds_cleanup.disarm(); // Secure deletion secret written; no need to wipe.
606 retval.key_slot = *keySlot;
607 return retval;
608 }
609
GetDataForKey(const uint32_t key_slot) const610 SecureDeletionData TrustySecureDeletionSecretStorage::GetDataForKey(
611 const uint32_t key_slot) const {
612 for (size_t tries = 0; tries < kMaxTries && !factory_reset_secret_;
613 ++tries) {
614 LoadOrCreateFactoryResetSecret(true /* waitForPort */);
615 }
616 if (!factory_reset_secret_) {
617 return SecureDeletionData{};
618 }
619
620 SecureDeletionData retval;
621 retval.key_slot = key_slot;
622 retval.factory_reset_secret.Reinitialize(*factory_reset_secret_);
623
624 bool secureDeletionSecretRequested = (key_slot != 0);
625 if (!secureDeletionSecretRequested) {
626 LOG_D("Secure deletion not requested.");
627 return retval;
628 }
629
630 LOG_D("Need to read secure deletion secret from slot %u", retval.key_slot);
631
632 for (size_t tries = 0; tries < kMaxTries; ++tries) {
633 std::optional<StorageSession> session =
634 StorageSession::CreateSession(); // Will block
635 if (!session) {
636 LOG_E("Failed to open session to get secure deletion data.");
637 continue;
638 }
639
640 std::optional<StorageFile> file =
641 session->OpenFile(kSecureDeletionSecretFileName);
642 if (!file) {
643 LOG_E("Failed to open file to get secure deletion data.");
644 continue;
645 }
646
647 storage_off_t keySlotBegin = retval.key_slot * kSecretSize;
648 storage_off_t keySlotEnd = keySlotBegin + kSecretSize;
649 if (keySlotEnd > file->size()) {
650 LOG_E("Invalid key slot %u would read past end of file of size %" PRIu64,
651 retval.key_slot, file->size());
652 return retval; // Empty secure_deletion_secret, key decryption will
653 // fail.
654 }
655
656 std::optional<Buffer> secret =
657 file->ReadBlock(retval.key_slot * kSecretSize, kSecretSize);
658 if (!secret) {
659 LOG_E("Failed to read secret from slot %u", retval.key_slot);
660 continue;
661 }
662
663 LOG_D("Read secure deletion secret, size: %zu",
664 secret->available_read());
665 retval.secure_deletion_secret = std::move(*secret);
666 break;
667 }
668
669 return retval;
670 }
671
DeleteKey(uint32_t key_slot) const672 void TrustySecureDeletionSecretStorage::DeleteKey(uint32_t key_slot) const {
673 if (key_slot == 0) {
674 LOG_D("key_slot == 0, nothing to delete");
675 return;
676 }
677
678 for (;;) {
679 std::optional<StorageSession> session =
680 StorageSession::CreateSession(); // Will block
681 if (!session) {
682 LOG_E("Failed to open session to retrieve secure deletion data.");
683 continue;
684 }
685
686 std::optional<StorageFile> file =
687 session->OpenFile(kSecureDeletionSecretFileName);
688 if (!file) {
689 LOG_E("Failed to open file to retrieve secure deletion data.");
690 continue;
691 }
692
693 storage_off_t key_slot_begin = key_slot * kSecretSize;
694 storage_off_t key_slot_end = key_slot_begin + kSecretSize;
695 if (key_slot_begin <
696 kFactoryResetSecretPos + kFactoryResetSecretSize //
697 || key_slot_end > file->size()) {
698 LOG_E("Attempted to delete invalid key slot %u", key_slot);
699 return;
700 }
701
702 if (!zero_entries(*file, key_slot_begin, key_slot_end)) {
703 continue;
704 }
705 LOG_D("Deleted secure key slot %u, zeroing %" PRIu64 " to %" PRIu64,
706 key_slot, key_slot_begin, key_slot_end);
707
708 if (!session->EndTransaction(true /* commit */)) {
709 LOG_E("Failed to commit transaction deleting key at slot %u",
710 key_slot);
711 continue;
712 }
713 LOG_D("Committed deletion");
714
715 return;
716 }
717 }
718
DeleteAllKeys() const719 void TrustySecureDeletionSecretStorage::DeleteAllKeys() const {
720 for (;;) {
721 std::optional<StorageSession> session =
722 StorageSession::CreateSession(); // Will block
723 if (!session) {
724 LOG_E("Failed to open session to delete secrets file.");
725 continue;
726 }
727 LOG_D("Opened session to delete secrets file.");
728
729 auto error = session->DeleteFile(kSecureDeletionSecretFileName);
730 if (error == StorageSession::Error::OK) {
731 LOG_D("Deleted secrets file");
732
733 if (!session->EndTransaction(true /* commit */)) {
734 LOG_E("Failed to commit deletion of secrets file.");
735 }
736 LOG_D("Committed deletion of secrets file.");
737 } else if (error == StorageSession::Error::NOT_FOUND) {
738 // File does not exist, may as well abandon the session.
739 LOG_D("No secrets file existed.");
740 } else {
741 // Assuming transient error. Log and retry.
742 LOG_E("Failed to delete secrets file");
743 continue;
744 }
745
746 // Success
747 factory_reset_secret_ = {};
748 return;
749 }
750 }
751
752 } // namespace keymaster
753