• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  PSA MAC layer on top of Mbed TLS software crypto
3  */
4 /*
5  *  Copyright The Mbed TLS Contributors
6  *  SPDX-License-Identifier: Apache-2.0
7  *
8  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
9  *  not use this file except in compliance with the License.
10  *  You may obtain a copy of the License at
11  *
12  *  http://www.apache.org/licenses/LICENSE-2.0
13  *
14  *  Unless required by applicable law or agreed to in writing, software
15  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  *  See the License for the specific language governing permissions and
18  *  limitations under the License.
19  */
20 
21 #include "common.h"
22 
23 #if defined(MBEDTLS_PSA_CRYPTO_C)
24 
25 #include <psa/crypto.h>
26 #include "psa_crypto_core.h"
27 #include "psa_crypto_cipher.h"
28 #include "psa_crypto_mac.h"
29 #include <mbedtls/md.h>
30 
31 #include <mbedtls/error.h>
32 #include <string.h>
33 
34 #if defined(MBEDTLS_PSA_BUILTIN_ALG_HMAC)
psa_hmac_abort_internal(mbedtls_psa_hmac_operation_t * hmac)35 static psa_status_t psa_hmac_abort_internal(
36     mbedtls_psa_hmac_operation_t *hmac)
37 {
38     mbedtls_platform_zeroize(hmac->opad, sizeof(hmac->opad));
39     return psa_hash_abort(&hmac->hash_ctx);
40 }
41 
psa_hmac_setup_internal(mbedtls_psa_hmac_operation_t * hmac,const uint8_t * key,size_t key_length,psa_algorithm_t hash_alg)42 static psa_status_t psa_hmac_setup_internal(
43     mbedtls_psa_hmac_operation_t *hmac,
44     const uint8_t *key,
45     size_t key_length,
46     psa_algorithm_t hash_alg)
47 {
48     uint8_t ipad[PSA_HMAC_MAX_HASH_BLOCK_SIZE];
49     size_t i;
50     size_t hash_size = PSA_HASH_LENGTH(hash_alg);
51     size_t block_size = PSA_HASH_BLOCK_LENGTH(hash_alg);
52     psa_status_t status;
53 
54     hmac->alg = hash_alg;
55 
56     /* Sanity checks on block_size, to guarantee that there won't be a buffer
57      * overflow below. This should never trigger if the hash algorithm
58      * is implemented correctly. */
59     /* The size checks against the ipad and opad buffers cannot be written
60      * `block_size > sizeof( ipad ) || block_size > sizeof( hmac->opad )`
61      * because that triggers -Wlogical-op on GCC 7.3. */
62     if (block_size > sizeof(ipad)) {
63         return PSA_ERROR_NOT_SUPPORTED;
64     }
65     if (block_size > sizeof(hmac->opad)) {
66         return PSA_ERROR_NOT_SUPPORTED;
67     }
68     if (block_size < hash_size) {
69         return PSA_ERROR_NOT_SUPPORTED;
70     }
71 
72     if (key_length > block_size) {
73         status = psa_hash_compute(hash_alg, key, key_length,
74                                   ipad, sizeof(ipad), &key_length);
75         if (status != PSA_SUCCESS) {
76             goto cleanup;
77         }
78     }
79     /* A 0-length key is not commonly used in HMAC when used as a MAC,
80      * but it is permitted. It is common when HMAC is used in HKDF, for
81      * example. Don't call `memcpy` in the 0-length because `key` could be
82      * an invalid pointer which would make the behavior undefined. */
83     else if (key_length != 0) {
84         memcpy(ipad, key, key_length);
85     }
86 
87     /* ipad contains the key followed by garbage. Xor and fill with 0x36
88      * to create the ipad value. */
89     for (i = 0; i < key_length; i++) {
90         ipad[i] ^= 0x36;
91     }
92     memset(ipad + key_length, 0x36, block_size - key_length);
93 
94     /* Copy the key material from ipad to opad, flipping the requisite bits,
95      * and filling the rest of opad with the requisite constant. */
96     for (i = 0; i < key_length; i++) {
97         hmac->opad[i] = ipad[i] ^ 0x36 ^ 0x5C;
98     }
99     memset(hmac->opad + key_length, 0x5C, block_size - key_length);
100 
101     status = psa_hash_setup(&hmac->hash_ctx, hash_alg);
102     if (status != PSA_SUCCESS) {
103         goto cleanup;
104     }
105 
106     status = psa_hash_update(&hmac->hash_ctx, ipad, block_size);
107 
108 cleanup:
109     mbedtls_platform_zeroize(ipad, sizeof(ipad));
110 
111     return status;
112 }
113 
psa_hmac_update_internal(mbedtls_psa_hmac_operation_t * hmac,const uint8_t * data,size_t data_length)114 static psa_status_t psa_hmac_update_internal(
115     mbedtls_psa_hmac_operation_t *hmac,
116     const uint8_t *data,
117     size_t data_length)
118 {
119     return psa_hash_update(&hmac->hash_ctx, data, data_length);
120 }
121 
psa_hmac_finish_internal(mbedtls_psa_hmac_operation_t * hmac,uint8_t * mac,size_t mac_size)122 static psa_status_t psa_hmac_finish_internal(
123     mbedtls_psa_hmac_operation_t *hmac,
124     uint8_t *mac,
125     size_t mac_size)
126 {
127     uint8_t tmp[PSA_HASH_MAX_SIZE];
128     psa_algorithm_t hash_alg = hmac->alg;
129     size_t hash_size = 0;
130     size_t block_size = PSA_HASH_BLOCK_LENGTH(hash_alg);
131     psa_status_t status;
132 
133     status = psa_hash_finish(&hmac->hash_ctx, tmp, sizeof(tmp), &hash_size);
134     if (status != PSA_SUCCESS) {
135         return status;
136     }
137     /* From here on, tmp needs to be wiped. */
138 
139     status = psa_hash_setup(&hmac->hash_ctx, hash_alg);
140     if (status != PSA_SUCCESS) {
141         goto exit;
142     }
143 
144     status = psa_hash_update(&hmac->hash_ctx, hmac->opad, block_size);
145     if (status != PSA_SUCCESS) {
146         goto exit;
147     }
148 
149     status = psa_hash_update(&hmac->hash_ctx, tmp, hash_size);
150     if (status != PSA_SUCCESS) {
151         goto exit;
152     }
153 
154     status = psa_hash_finish(&hmac->hash_ctx, tmp, sizeof(tmp), &hash_size);
155     if (status != PSA_SUCCESS) {
156         goto exit;
157     }
158 
159     memcpy(mac, tmp, mac_size);
160 
161 exit:
162     mbedtls_platform_zeroize(tmp, hash_size);
163     return status;
164 }
165 #endif /* MBEDTLS_PSA_BUILTIN_ALG_HMAC */
166 
167 #if defined(MBEDTLS_PSA_BUILTIN_ALG_CMAC)
cmac_setup(mbedtls_psa_mac_operation_t * operation,const psa_key_attributes_t * attributes,const uint8_t * key_buffer)168 static psa_status_t cmac_setup(mbedtls_psa_mac_operation_t *operation,
169                                const psa_key_attributes_t *attributes,
170                                const uint8_t *key_buffer)
171 {
172     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
173 
174 #if defined(PSA_WANT_KEY_TYPE_DES)
175     /* Mbed TLS CMAC does not accept 3DES with only two keys, nor does it accept
176      * to do CMAC with pure DES, so return NOT_SUPPORTED here. */
177     if (psa_get_key_type(attributes) == PSA_KEY_TYPE_DES &&
178         (psa_get_key_bits(attributes) == 64 ||
179          psa_get_key_bits(attributes) == 128)) {
180         return PSA_ERROR_NOT_SUPPORTED;
181     }
182 #endif
183 
184     const mbedtls_cipher_info_t *cipher_info =
185         mbedtls_cipher_info_from_psa(
186             PSA_ALG_CMAC,
187             psa_get_key_type(attributes),
188             psa_get_key_bits(attributes),
189             NULL);
190 
191     if (cipher_info == NULL) {
192         return PSA_ERROR_NOT_SUPPORTED;
193     }
194 
195     ret = mbedtls_cipher_setup(&operation->ctx.cmac, cipher_info);
196     if (ret != 0) {
197         goto exit;
198     }
199 
200     ret = mbedtls_cipher_cmac_starts(&operation->ctx.cmac,
201                                      key_buffer,
202                                      psa_get_key_bits(attributes));
203 exit:
204     return mbedtls_to_psa_error(ret);
205 }
206 #endif /* MBEDTLS_PSA_BUILTIN_ALG_CMAC */
207 
208 #if defined(MBEDTLS_PSA_BUILTIN_ALG_HMAC) || \
209     defined(MBEDTLS_PSA_BUILTIN_ALG_CMAC)
210 
211 /* Initialize this driver's MAC operation structure. Once this function has been
212  * called, mbedtls_psa_mac_abort can run and will do the right thing. */
mac_init(mbedtls_psa_mac_operation_t * operation,psa_algorithm_t alg)213 static psa_status_t mac_init(
214     mbedtls_psa_mac_operation_t *operation,
215     psa_algorithm_t alg)
216 {
217     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
218 
219     operation->alg = alg;
220 
221 #if defined(MBEDTLS_PSA_BUILTIN_ALG_CMAC)
222     if (PSA_ALG_FULL_LENGTH_MAC(operation->alg) == PSA_ALG_CMAC) {
223         mbedtls_cipher_init(&operation->ctx.cmac);
224         status = PSA_SUCCESS;
225     } else
226 #endif /* MBEDTLS_PSA_BUILTIN_ALG_CMAC */
227 #if defined(MBEDTLS_PSA_BUILTIN_ALG_HMAC)
228     if (PSA_ALG_IS_HMAC(operation->alg)) {
229         /* We'll set up the hash operation later in psa_hmac_setup_internal. */
230         operation->ctx.hmac.alg = 0;
231         status = PSA_SUCCESS;
232     } else
233 #endif /* MBEDTLS_PSA_BUILTIN_ALG_HMAC */
234     {
235         (void) operation;
236         status = PSA_ERROR_NOT_SUPPORTED;
237     }
238 
239     if (status != PSA_SUCCESS) {
240         memset(operation, 0, sizeof(*operation));
241     }
242     return status;
243 }
244 
mbedtls_psa_mac_abort(mbedtls_psa_mac_operation_t * operation)245 psa_status_t mbedtls_psa_mac_abort(mbedtls_psa_mac_operation_t *operation)
246 {
247     if (operation->alg == 0) {
248         /* The object has (apparently) been initialized but it is not
249          * in use. It's ok to call abort on such an object, and there's
250          * nothing to do. */
251         return PSA_SUCCESS;
252     } else
253 #if defined(MBEDTLS_PSA_BUILTIN_ALG_CMAC)
254     if (PSA_ALG_FULL_LENGTH_MAC(operation->alg) == PSA_ALG_CMAC) {
255         mbedtls_cipher_free(&operation->ctx.cmac);
256     } else
257 #endif /* MBEDTLS_PSA_BUILTIN_ALG_CMAC */
258 #if defined(MBEDTLS_PSA_BUILTIN_ALG_HMAC)
259     if (PSA_ALG_IS_HMAC(operation->alg)) {
260         psa_hmac_abort_internal(&operation->ctx.hmac);
261     } else
262 #endif /* MBEDTLS_PSA_BUILTIN_ALG_HMAC */
263     {
264         /* Sanity check (shouldn't happen: operation->alg should
265          * always have been initialized to a valid value). */
266         goto bad_state;
267     }
268 
269     operation->alg = 0;
270 
271     return PSA_SUCCESS;
272 
273 bad_state:
274     /* If abort is called on an uninitialized object, we can't trust
275      * anything. Wipe the object in case it contains confidential data.
276      * This may result in a memory leak if a pointer gets overwritten,
277      * but it's too late to do anything about this. */
278     memset(operation, 0, sizeof(*operation));
279     return PSA_ERROR_BAD_STATE;
280 }
281 
psa_mac_setup(mbedtls_psa_mac_operation_t * operation,const psa_key_attributes_t * attributes,const uint8_t * key_buffer,size_t key_buffer_size,psa_algorithm_t alg)282 static psa_status_t psa_mac_setup(mbedtls_psa_mac_operation_t *operation,
283                                   const psa_key_attributes_t *attributes,
284                                   const uint8_t *key_buffer,
285                                   size_t key_buffer_size,
286                                   psa_algorithm_t alg)
287 {
288     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
289 
290     /* A context must be freshly initialized before it can be set up. */
291     if (operation->alg != 0) {
292         return PSA_ERROR_BAD_STATE;
293     }
294 
295     status = mac_init(operation, alg);
296     if (status != PSA_SUCCESS) {
297         return status;
298     }
299 
300 #if defined(MBEDTLS_PSA_BUILTIN_ALG_CMAC)
301     if (PSA_ALG_FULL_LENGTH_MAC(alg) == PSA_ALG_CMAC) {
302         /* Key buffer size for CMAC is dictated by the key bits set on the
303          * attributes, and previously validated by the core on key import. */
304         (void) key_buffer_size;
305         status = cmac_setup(operation, attributes, key_buffer);
306     } else
307 #endif /* MBEDTLS_PSA_BUILTIN_ALG_CMAC */
308 #if defined(MBEDTLS_PSA_BUILTIN_ALG_HMAC)
309     if (PSA_ALG_IS_HMAC(alg)) {
310         status = psa_hmac_setup_internal(&operation->ctx.hmac,
311                                          key_buffer,
312                                          key_buffer_size,
313                                          PSA_ALG_HMAC_GET_HASH(alg));
314     } else
315 #endif /* MBEDTLS_PSA_BUILTIN_ALG_HMAC */
316     {
317         (void) attributes;
318         (void) key_buffer;
319         (void) key_buffer_size;
320         status = PSA_ERROR_NOT_SUPPORTED;
321     }
322 
323     if (status != PSA_SUCCESS) {
324         mbedtls_psa_mac_abort(operation);
325     }
326 
327     return status;
328 }
329 
mbedtls_psa_mac_sign_setup(mbedtls_psa_mac_operation_t * operation,const psa_key_attributes_t * attributes,const uint8_t * key_buffer,size_t key_buffer_size,psa_algorithm_t alg)330 psa_status_t mbedtls_psa_mac_sign_setup(
331     mbedtls_psa_mac_operation_t *operation,
332     const psa_key_attributes_t *attributes,
333     const uint8_t *key_buffer,
334     size_t key_buffer_size,
335     psa_algorithm_t alg)
336 {
337     return psa_mac_setup(operation, attributes,
338                          key_buffer, key_buffer_size, alg);
339 }
340 
mbedtls_psa_mac_verify_setup(mbedtls_psa_mac_operation_t * operation,const psa_key_attributes_t * attributes,const uint8_t * key_buffer,size_t key_buffer_size,psa_algorithm_t alg)341 psa_status_t mbedtls_psa_mac_verify_setup(
342     mbedtls_psa_mac_operation_t *operation,
343     const psa_key_attributes_t *attributes,
344     const uint8_t *key_buffer,
345     size_t key_buffer_size,
346     psa_algorithm_t alg)
347 {
348     return psa_mac_setup(operation, attributes,
349                          key_buffer, key_buffer_size, alg);
350 }
351 
mbedtls_psa_mac_update(mbedtls_psa_mac_operation_t * operation,const uint8_t * input,size_t input_length)352 psa_status_t mbedtls_psa_mac_update(
353     mbedtls_psa_mac_operation_t *operation,
354     const uint8_t *input,
355     size_t input_length)
356 {
357     if (operation->alg == 0) {
358         return PSA_ERROR_BAD_STATE;
359     }
360 
361 #if defined(MBEDTLS_PSA_BUILTIN_ALG_CMAC)
362     if (PSA_ALG_FULL_LENGTH_MAC(operation->alg) == PSA_ALG_CMAC) {
363         return mbedtls_to_psa_error(
364             mbedtls_cipher_cmac_update(&operation->ctx.cmac,
365                                        input, input_length));
366     } else
367 #endif /* MBEDTLS_PSA_BUILTIN_ALG_CMAC */
368 #if defined(MBEDTLS_PSA_BUILTIN_ALG_HMAC)
369     if (PSA_ALG_IS_HMAC(operation->alg)) {
370         return psa_hmac_update_internal(&operation->ctx.hmac,
371                                         input, input_length);
372     } else
373 #endif /* MBEDTLS_PSA_BUILTIN_ALG_HMAC */
374     {
375         /* This shouldn't happen if `operation` was initialized by
376          * a setup function. */
377         (void) input;
378         (void) input_length;
379         return PSA_ERROR_BAD_STATE;
380     }
381 }
382 
psa_mac_finish_internal(mbedtls_psa_mac_operation_t * operation,uint8_t * mac,size_t mac_size)383 static psa_status_t psa_mac_finish_internal(
384     mbedtls_psa_mac_operation_t *operation,
385     uint8_t *mac, size_t mac_size)
386 {
387 #if defined(MBEDTLS_PSA_BUILTIN_ALG_CMAC)
388     if (PSA_ALG_FULL_LENGTH_MAC(operation->alg) == PSA_ALG_CMAC) {
389         uint8_t tmp[PSA_BLOCK_CIPHER_BLOCK_MAX_SIZE];
390         int ret = mbedtls_cipher_cmac_finish(&operation->ctx.cmac, tmp);
391         if (ret == 0) {
392             memcpy(mac, tmp, mac_size);
393         }
394         mbedtls_platform_zeroize(tmp, sizeof(tmp));
395         return mbedtls_to_psa_error(ret);
396     } else
397 #endif /* MBEDTLS_PSA_BUILTIN_ALG_CMAC */
398 #if defined(MBEDTLS_PSA_BUILTIN_ALG_HMAC)
399     if (PSA_ALG_IS_HMAC(operation->alg)) {
400         return psa_hmac_finish_internal(&operation->ctx.hmac,
401                                         mac, mac_size);
402     } else
403 #endif /* MBEDTLS_PSA_BUILTIN_ALG_HMAC */
404     {
405         /* This shouldn't happen if `operation` was initialized by
406          * a setup function. */
407         (void) operation;
408         (void) mac;
409         (void) mac_size;
410         return PSA_ERROR_BAD_STATE;
411     }
412 }
413 
mbedtls_psa_mac_sign_finish(mbedtls_psa_mac_operation_t * operation,uint8_t * mac,size_t mac_size,size_t * mac_length)414 psa_status_t mbedtls_psa_mac_sign_finish(
415     mbedtls_psa_mac_operation_t *operation,
416     uint8_t *mac,
417     size_t mac_size,
418     size_t *mac_length)
419 {
420     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
421 
422     if (operation->alg == 0) {
423         return PSA_ERROR_BAD_STATE;
424     }
425 
426     status = psa_mac_finish_internal(operation, mac, mac_size);
427     if (status == PSA_SUCCESS) {
428         *mac_length = mac_size;
429     }
430 
431     return status;
432 }
433 
mbedtls_psa_mac_verify_finish(mbedtls_psa_mac_operation_t * operation,const uint8_t * mac,size_t mac_length)434 psa_status_t mbedtls_psa_mac_verify_finish(
435     mbedtls_psa_mac_operation_t *operation,
436     const uint8_t *mac,
437     size_t mac_length)
438 {
439     uint8_t actual_mac[PSA_MAC_MAX_SIZE];
440     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
441 
442     if (operation->alg == 0) {
443         return PSA_ERROR_BAD_STATE;
444     }
445 
446     /* Consistency check: requested MAC length fits our local buffer */
447     if (mac_length > sizeof(actual_mac)) {
448         return PSA_ERROR_INVALID_ARGUMENT;
449     }
450 
451     status = psa_mac_finish_internal(operation, actual_mac, mac_length);
452     if (status != PSA_SUCCESS) {
453         goto cleanup;
454     }
455 
456     if (mbedtls_psa_safer_memcmp(mac, actual_mac, mac_length) != 0) {
457         status = PSA_ERROR_INVALID_SIGNATURE;
458     }
459 
460 cleanup:
461     mbedtls_platform_zeroize(actual_mac, sizeof(actual_mac));
462 
463     return status;
464 }
465 
mbedtls_psa_mac_compute(const psa_key_attributes_t * attributes,const uint8_t * key_buffer,size_t key_buffer_size,psa_algorithm_t alg,const uint8_t * input,size_t input_length,uint8_t * mac,size_t mac_size,size_t * mac_length)466 psa_status_t mbedtls_psa_mac_compute(
467     const psa_key_attributes_t *attributes,
468     const uint8_t *key_buffer,
469     size_t key_buffer_size,
470     psa_algorithm_t alg,
471     const uint8_t *input,
472     size_t input_length,
473     uint8_t *mac,
474     size_t mac_size,
475     size_t *mac_length)
476 {
477     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
478     mbedtls_psa_mac_operation_t operation = MBEDTLS_PSA_MAC_OPERATION_INIT;
479 
480     status = psa_mac_setup(&operation,
481                            attributes, key_buffer, key_buffer_size,
482                            alg);
483     if (status != PSA_SUCCESS) {
484         goto exit;
485     }
486 
487     if (input_length > 0) {
488         status = mbedtls_psa_mac_update(&operation, input, input_length);
489         if (status != PSA_SUCCESS) {
490             goto exit;
491         }
492     }
493 
494     status = psa_mac_finish_internal(&operation, mac, mac_size);
495     if (status == PSA_SUCCESS) {
496         *mac_length = mac_size;
497     }
498 
499 exit:
500     mbedtls_psa_mac_abort(&operation);
501 
502     return status;
503 }
504 
505 #endif /* MBEDTLS_PSA_BUILTIN_ALG_HMAC || MBEDTLS_PSA_BUILTIN_ALG_CMAC */
506 
507 #endif /* MBEDTLS_PSA_CRYPTO_C */
508