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