• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  PSA ITS simulator over stdio files.
3  */
4 /*
5  *  Copyright The Mbed TLS Contributors
6  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
7  */
8 
9 #include "common.h"
10 
11 #if defined(MBEDTLS_PSA_ITS_FILE_C)
12 
13 #include "mbedtls/platform.h"
14 
15 #if defined(_WIN32)
16 #include <windows.h>
17 #endif
18 
19 #include "psa_crypto_its.h"
20 
21 #include <limits.h>
22 #include <stdint.h>
23 #include <stdio.h>
24 #include <string.h>
25 
26 #if !defined(PSA_ITS_STORAGE_PREFIX)
27 #define PSA_ITS_STORAGE_PREFIX ""
28 #endif
29 
30 #define PSA_ITS_STORAGE_FILENAME_PATTERN "%08x%08x"
31 #define PSA_ITS_STORAGE_SUFFIX ".psa_its"
32 #define PSA_ITS_STORAGE_FILENAME_LENGTH         \
33     (sizeof(PSA_ITS_STORAGE_PREFIX) - 1 +    /*prefix without terminating 0*/ \
34      16 +  /*UID (64-bit number in hex)*/                               \
35      sizeof(PSA_ITS_STORAGE_SUFFIX) - 1 +    /*suffix without terminating 0*/ \
36      1 /*terminating null byte*/)
37 #define PSA_ITS_STORAGE_TEMP \
38     PSA_ITS_STORAGE_PREFIX "tempfile" PSA_ITS_STORAGE_SUFFIX
39 
40 /* The maximum value of psa_storage_info_t.size */
41 #define PSA_ITS_MAX_SIZE 0xffffffff
42 
43 #define PSA_ITS_MAGIC_STRING "PSA\0ITS\0"
44 #define PSA_ITS_MAGIC_LENGTH 8
45 
46 /* As rename fails on Windows if the new filepath already exists,
47  * use MoveFileExA with the MOVEFILE_REPLACE_EXISTING flag instead.
48  * Returns 0 on success, nonzero on failure. */
49 #if defined(_WIN32)
50 #define rename_replace_existing(oldpath, newpath) \
51     (!MoveFileExA(oldpath, newpath, MOVEFILE_REPLACE_EXISTING))
52 #else
53 #define rename_replace_existing(oldpath, newpath) rename(oldpath, newpath)
54 #endif
55 
56 typedef struct {
57     uint8_t magic[PSA_ITS_MAGIC_LENGTH];
58     uint8_t size[sizeof(uint32_t)];
59     uint8_t flags[sizeof(psa_storage_create_flags_t)];
60 } psa_its_file_header_t;
61 
psa_its_fill_filename(psa_storage_uid_t uid,char * filename)62 static void psa_its_fill_filename(psa_storage_uid_t uid, char *filename)
63 {
64     /* Break up the UID into two 32-bit pieces so as not to rely on
65      * long long support in snprintf. */
66     mbedtls_snprintf(filename, PSA_ITS_STORAGE_FILENAME_LENGTH,
67                      "%s" PSA_ITS_STORAGE_FILENAME_PATTERN "%s",
68                      PSA_ITS_STORAGE_PREFIX,
69                      (unsigned) (uid >> 32),
70                      (unsigned) (uid & 0xffffffff),
71                      PSA_ITS_STORAGE_SUFFIX);
72 }
73 
psa_its_read_file(psa_storage_uid_t uid,struct psa_storage_info_t * p_info,FILE ** p_stream)74 static psa_status_t psa_its_read_file(psa_storage_uid_t uid,
75                                       struct psa_storage_info_t *p_info,
76                                       FILE **p_stream)
77 {
78     char filename[PSA_ITS_STORAGE_FILENAME_LENGTH];
79     psa_its_file_header_t header;
80     size_t n;
81 
82     *p_stream = NULL;
83     psa_its_fill_filename(uid, filename);
84     *p_stream = fopen(filename, "rb");
85     if (*p_stream == NULL) {
86         return PSA_ERROR_DOES_NOT_EXIST;
87     }
88 
89     n = fread(&header, 1, sizeof(header), *p_stream);
90     if (n != sizeof(header)) {
91         return PSA_ERROR_DATA_CORRUPT;
92     }
93     if (memcmp(header.magic, PSA_ITS_MAGIC_STRING,
94                PSA_ITS_MAGIC_LENGTH) != 0) {
95         return PSA_ERROR_DATA_CORRUPT;
96     }
97 
98     p_info->size = (header.size[0] |
99                     header.size[1] << 8 |
100                     header.size[2] << 16 |
101                     header.size[3] << 24);
102     p_info->flags = (header.flags[0] |
103                      header.flags[1] << 8 |
104                      header.flags[2] << 16 |
105                      header.flags[3] << 24);
106     return PSA_SUCCESS;
107 }
108 
psa_its_get_info(psa_storage_uid_t uid,struct psa_storage_info_t * p_info)109 psa_status_t psa_its_get_info(psa_storage_uid_t uid,
110                               struct psa_storage_info_t *p_info)
111 {
112     psa_status_t status;
113     FILE *stream = NULL;
114     status = psa_its_read_file(uid, p_info, &stream);
115     if (stream != NULL) {
116         fclose(stream);
117     }
118     return status;
119 }
120 
psa_its_get(psa_storage_uid_t uid,uint32_t data_offset,uint32_t data_length,void * p_data,size_t * p_data_length)121 psa_status_t psa_its_get(psa_storage_uid_t uid,
122                          uint32_t data_offset,
123                          uint32_t data_length,
124                          void *p_data,
125                          size_t *p_data_length)
126 {
127     psa_status_t status;
128     FILE *stream = NULL;
129     size_t n;
130     struct psa_storage_info_t info;
131 
132     status = psa_its_read_file(uid, &info, &stream);
133     if (status != PSA_SUCCESS) {
134         goto exit;
135     }
136     status = PSA_ERROR_INVALID_ARGUMENT;
137     if (data_offset + data_length < data_offset) {
138         goto exit;
139     }
140 #if SIZE_MAX < 0xffffffff
141     if (data_offset + data_length > SIZE_MAX) {
142         goto exit;
143     }
144 #endif
145     if (data_offset + data_length > info.size) {
146         goto exit;
147     }
148 
149     status = PSA_ERROR_STORAGE_FAILURE;
150 #if LONG_MAX < 0xffffffff
151     while (data_offset > LONG_MAX) {
152         if (fseek(stream, LONG_MAX, SEEK_CUR) != 0) {
153             goto exit;
154         }
155         data_offset -= LONG_MAX;
156     }
157 #endif
158     if (fseek(stream, data_offset, SEEK_CUR) != 0) {
159         goto exit;
160     }
161     n = fread(p_data, 1, data_length, stream);
162     if (n != data_length) {
163         goto exit;
164     }
165     status = PSA_SUCCESS;
166     if (p_data_length != NULL) {
167         *p_data_length = n;
168     }
169 
170 exit:
171     if (stream != NULL) {
172         fclose(stream);
173     }
174     return status;
175 }
176 
psa_its_set(psa_storage_uid_t uid,uint32_t data_length,const void * p_data,psa_storage_create_flags_t create_flags)177 psa_status_t psa_its_set(psa_storage_uid_t uid,
178                          uint32_t data_length,
179                          const void *p_data,
180                          psa_storage_create_flags_t create_flags)
181 {
182     if (uid == 0) {
183         return PSA_ERROR_INVALID_HANDLE;
184     }
185 
186     psa_status_t status = PSA_ERROR_STORAGE_FAILURE;
187     char filename[PSA_ITS_STORAGE_FILENAME_LENGTH];
188     FILE *stream = NULL;
189     psa_its_file_header_t header;
190     size_t n;
191 
192     memcpy(header.magic, PSA_ITS_MAGIC_STRING, PSA_ITS_MAGIC_LENGTH);
193     MBEDTLS_PUT_UINT32_LE(data_length, header.size, 0);
194     MBEDTLS_PUT_UINT32_LE(create_flags, header.flags, 0);
195 
196     psa_its_fill_filename(uid, filename);
197     stream = fopen(PSA_ITS_STORAGE_TEMP, "wb");
198     if (stream == NULL) {
199         goto exit;
200     }
201 
202     status = PSA_ERROR_INSUFFICIENT_STORAGE;
203     n = fwrite(&header, 1, sizeof(header), stream);
204     if (n != sizeof(header)) {
205         goto exit;
206     }
207     if (data_length != 0) {
208         n = fwrite(p_data, 1, data_length, stream);
209         if (n != data_length) {
210             goto exit;
211         }
212     }
213     status = PSA_SUCCESS;
214 
215 exit:
216     if (stream != NULL) {
217         int ret = fclose(stream);
218         if (status == PSA_SUCCESS && ret != 0) {
219             status = PSA_ERROR_INSUFFICIENT_STORAGE;
220         }
221     }
222     if (status == PSA_SUCCESS) {
223         if (rename_replace_existing(PSA_ITS_STORAGE_TEMP, filename) != 0) {
224             status = PSA_ERROR_STORAGE_FAILURE;
225         }
226     }
227     /* The temporary file may still exist, but only in failure cases where
228      * we're already reporting an error. So there's nothing we can do on
229      * failure. If the function succeeded, and in some error cases, the
230      * temporary file doesn't exist and so remove() is expected to fail.
231      * Thus we just ignore the return status of remove(). */
232     (void) remove(PSA_ITS_STORAGE_TEMP);
233     return status;
234 }
235 
psa_its_remove(psa_storage_uid_t uid)236 psa_status_t psa_its_remove(psa_storage_uid_t uid)
237 {
238     char filename[PSA_ITS_STORAGE_FILENAME_LENGTH];
239     FILE *stream;
240     psa_its_fill_filename(uid, filename);
241     stream = fopen(filename, "rb");
242     if (stream == NULL) {
243         return PSA_ERROR_DOES_NOT_EXIST;
244     }
245     fclose(stream);
246     if (remove(filename) != 0) {
247         return PSA_ERROR_STORAGE_FAILURE;
248     }
249     return PSA_SUCCESS;
250 }
251 
252 #endif /* MBEDTLS_PSA_ITS_FILE_C */
253