1a8e1175bSopenharmony_ci# Mbed TLS PSA keystore format stability testing strategy
2a8e1175bSopenharmony_ci
3a8e1175bSopenharmony_ci## Introduction
4a8e1175bSopenharmony_ci
5a8e1175bSopenharmony_ciThe PSA crypto subsystem includes a persistent key store. It is possible to create a persistent key and read it back later. This must work even if Mbed TLS has been upgraded in the meantime (except for deliberate breaks in the backward compatibility of the storage).
6a8e1175bSopenharmony_ci
7a8e1175bSopenharmony_ciThe goal of this document is to define a test strategy for the key store that not only validates that it's possible to load a key that was saved with the version of Mbed TLS under test, but also that it's possible to load a key that was saved with previous versions of Mbed TLS.
8a8e1175bSopenharmony_ci
9a8e1175bSopenharmony_ciInteroperability is not a goal: PSA crypto implementations are not intended to have compatible storage formats. Downgrading is not required to work.
10a8e1175bSopenharmony_ci
11a8e1175bSopenharmony_ci## General approach
12a8e1175bSopenharmony_ci
13a8e1175bSopenharmony_ci### Limitations of a direct approach
14a8e1175bSopenharmony_ci
15a8e1175bSopenharmony_ciThe goal of storage format stability testing is: as a user of Mbed TLS, I want to store a key under version V and read it back under version W, with W ≥ V.
16a8e1175bSopenharmony_ci
17a8e1175bSopenharmony_ciDoing the testing this way would be difficult because we'd need to have version V of Mbed TLS available when testing version W.
18a8e1175bSopenharmony_ci
19a8e1175bSopenharmony_ciAn alternative, semi-direct approach consists of generating test data under version V, and reading it back under version W. Done naively, this would require keeping a large amount of test data (full test coverage multiplied by the number of versions that we want to preserve backward compatibility with).
20a8e1175bSopenharmony_ci
21a8e1175bSopenharmony_ci### Save-and-compare approach
22a8e1175bSopenharmony_ci
23a8e1175bSopenharmony_ciImporting and saving a key is deterministic. Therefore we can ensure the stability of the storage format by creating test cases under a version V of Mbed TLS, where the test case parameters include both the parameters to pass to key creation and the expected state of the storage after the key is created. The test case creates a key as indicated by the parameters, then compares the actual state of the storage with the expected state.
24a8e1175bSopenharmony_ci
25a8e1175bSopenharmony_ciIn addition, the test case also loads the key and checks that it has the expected data and metadata. Import-and-save testing and load-and-check testing can be split into separate test functions with the same payloads.
26a8e1175bSopenharmony_ci
27a8e1175bSopenharmony_ciIf the test passes with version V, this means that the test data is consistent with what the implementation does. When the test later runs under version W ≥ V, it creates and reads back a storage state which is known to be identical to the state that V would have produced. Thus, this approach validates that W can read storage states created by V.
28a8e1175bSopenharmony_ci
29a8e1175bSopenharmony_ciNote that it is the combination of import-and-save passing on version V and load-and-check passing on version W with the same data that proves that version W can read back what version V wrote. From the perspective of a particular version of the library, the import-and-save tests guarantee forward compatibility while the load-and-check tests guarantee backward compatibility.
30a8e1175bSopenharmony_ci
31a8e1175bSopenharmony_ciUse a similar approach for files other than keys where possible and relevant.
32a8e1175bSopenharmony_ci
33a8e1175bSopenharmony_ci### Keeping up with storage format evolution
34a8e1175bSopenharmony_ci
35a8e1175bSopenharmony_ciTest cases should normally not be removed from the code base: if something has worked before, it should keep working in future versions, so we should keep testing it.
36a8e1175bSopenharmony_ci
37a8e1175bSopenharmony_ciThis cannot be enforced solely by looking at a single version of Mbed TLS, since there would be no indication that more test cases used to exist. It can only be enforced through review of library changes. The review is be assisted by a tool that compares the old and the new version, which is implemented in `scripts/abi_check.py`. This tool fails the CI if load-and-check test case disappears (changed test cases are raised as false positives).
38a8e1175bSopenharmony_ci
39a8e1175bSopenharmony_ciIf the way certain keys are stored changes, and we don't deliberately decide to stop supporting old keys (which should only be done by retiring a version of the storage format), then we should keep the corresponding test cases in load-only mode: create a file with the expected content, load it and check the data that it contains.
40a8e1175bSopenharmony_ci
41a8e1175bSopenharmony_ci## Storage architecture overview
42a8e1175bSopenharmony_ci
43a8e1175bSopenharmony_ciThe PSA subsystem provides storage on top of the PSA trusted storage interface. The state of the storage is a mapping from file identifier (a 64-bit number) to file content (a byte array). These files include:
44a8e1175bSopenharmony_ci
45a8e1175bSopenharmony_ci* [Key files](#key-storage) (files containing one key's metadata and, except for some secure element keys, key material).
46a8e1175bSopenharmony_ci* The [random generator injected seed or state file](#random-generator-state) (`PSA_CRYPTO_ITS_RANDOM_SEED_UID`).
47a8e1175bSopenharmony_ci* [Storage transaction file](#storage-transaction-resumption).
48a8e1175bSopenharmony_ci* [Driver state files](#driver-state-files).
49a8e1175bSopenharmony_ci
50a8e1175bSopenharmony_ciFor a more detailed description, refer to the [Mbed TLS storage specification](../mbed-crypto-storage-specification.md).
51a8e1175bSopenharmony_ci
52a8e1175bSopenharmony_ciIn addition, Mbed TLS includes an implementation of the PSA trusted storage interface on top of C stdio. This document addresses the test strategy for [PSA ITS over file](#psa-its-over-file) in a separate section below.
53a8e1175bSopenharmony_ci
54a8e1175bSopenharmony_ci## Key storage testing
55a8e1175bSopenharmony_ci
56a8e1175bSopenharmony_ciThis section describes the desired test cases for keys created with the current storage format version. When the storage format changes, if backward compatibility is desired, old test data should be kept as described under [“Keeping up with storage format evolution”](#keeping-up-with-storage-format-evolution).
57a8e1175bSopenharmony_ci
58a8e1175bSopenharmony_ci### Keystore layout
59a8e1175bSopenharmony_ci
60a8e1175bSopenharmony_ciObjective: test that the key file name corresponds to the key identifier.
61a8e1175bSopenharmony_ci
62a8e1175bSopenharmony_ciMethod: Create a key with a given identifier (using `psa_import_key`) and verify that a file with the expected name is created, and no other. Repeat for different identifiers.
63a8e1175bSopenharmony_ci
64a8e1175bSopenharmony_ci### General key format
65a8e1175bSopenharmony_ci
66a8e1175bSopenharmony_ciObjective: test the format of the key file: which field goes where and how big it is.
67a8e1175bSopenharmony_ci
68a8e1175bSopenharmony_ciMethod: Create a key with certain metadata with `psa_import_key`. Read the file content and validate that it has the expected layout, deduced from the storage specification. Repeat with different metadata. Ensure that there are test cases covering all fields.
69a8e1175bSopenharmony_ci
70a8e1175bSopenharmony_ci### Enumeration of test cases for keys
71a8e1175bSopenharmony_ci
72a8e1175bSopenharmony_ciObjective: ensure that the coverage is sufficient to have assurance that all keys are stored correctly. This requires a sufficient selection of key types, sizes, policies, etc.
73a8e1175bSopenharmony_ci
74a8e1175bSopenharmony_ciIn particular, the tests must validate that each `PSA_xxx` constant that is stored in a key is covered by at least one test case:
75a8e1175bSopenharmony_ci
76a8e1175bSopenharmony_ci* Lifetimes: `PSA_KEY_LIFETIME_xxx`, `PSA_KEY_PERSISTENCE_xxx`, `PSA_KEY_LOCATION_xxx`.
77a8e1175bSopenharmony_ci* Usage flags: `PSA_KEY_USAGE_xxx`.
78a8e1175bSopenharmony_ci* Algorithms in policies: `PSA_ALG_xxx`.
79a8e1175bSopenharmony_ci* Key types: `PSA_KEY_TYPE_xxx`, `PSA_ECC_FAMILY_xxx`, `PSA_DH_FAMILY_xxx`.
80a8e1175bSopenharmony_ci
81a8e1175bSopenharmony_ciIn addition, the coverage of key material must ensure that any variation in key representation is detected. See [“Considerations on key material representations”](#Considerations-on-key-material-representations) for considerations regarding key types.
82a8e1175bSopenharmony_ci
83a8e1175bSopenharmony_ciMethod: Each test case creates a key with `psa_import_key`, purges it from memory, then reads it back and exercises it.
84a8e1175bSopenharmony_ci
85a8e1175bSopenharmony_ciGenerate test cases automatically based on an enumeration of available constants and some knowledge of what attributes (sizes, algorithms, …) and content to use for keys of a certain type.
86a8e1175bSopenharmony_ci
87a8e1175bSopenharmony_ci### Testing with alternative lifetime values
88a8e1175bSopenharmony_ci
89a8e1175bSopenharmony_ciObjective: have test coverage for lifetimes other than the default persistent lifetime (`PSA_KEY_LIFETIME_PERSISTENT`).
90a8e1175bSopenharmony_ci
91a8e1175bSopenharmony_ciMethod:
92a8e1175bSopenharmony_ci
93a8e1175bSopenharmony_ci* For alternative locations: have tests conditional on the presence of a driver for that location.
94a8e1175bSopenharmony_ci* For alternative persistence levels: have load-and-check tests for supported persistence levels. We may also want to have negative tests ensuring that keys with a not-supported persistence level are not accidentally created.
95a8e1175bSopenharmony_ci
96a8e1175bSopenharmony_ci### Considerations on key material representations
97a8e1175bSopenharmony_ci
98a8e1175bSopenharmony_ciThe risks of incompatibilities in key representations depends on the key type and on the presence of drivers. Compatibility of and with drivers is currently out of scope of this document.
99a8e1175bSopenharmony_ci
100a8e1175bSopenharmony_ciSome types only have one plausible representation. Others admit alternative plausible representations (different encodings, or non-canonical representations).
101a8e1175bSopenharmony_ciHere are some areas to watch for, with an identified risk of incompatibilities.
102a8e1175bSopenharmony_ci
103a8e1175bSopenharmony_ci* HMAC keys longer than the block size: pre-hashed or not?
104a8e1175bSopenharmony_ci* DES keys: was parity enforced?
105a8e1175bSopenharmony_ci* RSA keys: can invalid DER encodings (e.g. leading zeros, ignored sign bit) have been stored?
106a8e1175bSopenharmony_ci* RSA private keys: can invalid CRT parameters have been stored?
107a8e1175bSopenharmony_ci* Montgomery private keys: were they stored in masked form?
108a8e1175bSopenharmony_ci
109a8e1175bSopenharmony_ci## Random generator state
110a8e1175bSopenharmony_ci
111a8e1175bSopenharmony_ciTODO
112a8e1175bSopenharmony_ci
113a8e1175bSopenharmony_ci## Driver state files
114a8e1175bSopenharmony_ci
115a8e1175bSopenharmony_ciNot yet implemented.
116a8e1175bSopenharmony_ci
117a8e1175bSopenharmony_ciTODO
118a8e1175bSopenharmony_ci
119a8e1175bSopenharmony_ci## Storage transaction resumption
120a8e1175bSopenharmony_ci
121a8e1175bSopenharmony_ciOnly relevant for secure element support. Not yet fully implemented.
122a8e1175bSopenharmony_ci
123a8e1175bSopenharmony_ciTODO
124a8e1175bSopenharmony_ci
125a8e1175bSopenharmony_ci## PSA ITS over file
126a8e1175bSopenharmony_ci
127a8e1175bSopenharmony_ciTODO
128