• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  PSA AEAD entry points
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_CRYPTO_C)
12 
13 #include "psa_crypto_aead.h"
14 #include "psa_crypto_core.h"
15 #include "psa_crypto_cipher.h"
16 
17 #include "mbedtls/ccm.h"
18 #include "mbedtls/chachapoly.h"
19 #include "mbedtls/cipher.h"
20 #include "mbedtls/gcm.h"
21 
22 typedef struct {
23     psa_algorithm_t core_alg;
24     uint8_t tag_length;
25     union {
26         unsigned dummy; /* Make the union non-empty even with no supported algorithms. */
27 #if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
28         mbedtls_ccm_context ccm;
29 #endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
30 #if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
31         mbedtls_gcm_context gcm;
32 #endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
33 #if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
34         mbedtls_chachapoly_context chachapoly;
35 #endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
36     } ctx;
37 } aead_operation_t;
38 
39 #define AEAD_OPERATION_INIT { 0, 0, { 0 } }
40 
psa_aead_abort_internal(aead_operation_t * operation)41 static void psa_aead_abort_internal(aead_operation_t *operation)
42 {
43     switch (operation->core_alg) {
44 #if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
45         case PSA_ALG_CCM:
46             mbedtls_ccm_free(&operation->ctx.ccm);
47             break;
48 #endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
49 #if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
50         case PSA_ALG_GCM:
51             mbedtls_gcm_free(&operation->ctx.gcm);
52             break;
53 #endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
54 #if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
55         case PSA_ALG_CHACHA20_POLY1305:
56             mbedtls_chachapoly_free(&operation->ctx.chachapoly);
57             break;
58 #endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
59     }
60 }
61 
psa_aead_setup(aead_operation_t * operation,const psa_key_attributes_t * attributes,const uint8_t * key_buffer,psa_algorithm_t alg)62 static psa_status_t psa_aead_setup(
63     aead_operation_t *operation,
64     const psa_key_attributes_t *attributes,
65     const uint8_t *key_buffer,
66     psa_algorithm_t alg)
67 {
68     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
69     size_t key_bits;
70     const mbedtls_cipher_info_t *cipher_info;
71     mbedtls_cipher_id_t cipher_id;
72     size_t full_tag_length = 0;
73 
74     key_bits = attributes->core.bits;
75 
76     cipher_info = mbedtls_cipher_info_from_psa(alg,
77                                                attributes->core.type, key_bits,
78                                                &cipher_id);
79     if (cipher_info == NULL) {
80         return PSA_ERROR_NOT_SUPPORTED;
81     }
82 
83     switch (PSA_ALG_AEAD_WITH_SHORTENED_TAG(alg, 0)) {
84 #if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
85         case PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, 0):
86             operation->core_alg = PSA_ALG_CCM;
87             full_tag_length = 16;
88             /* CCM allows the following tag lengths: 4, 6, 8, 10, 12, 14, 16.
89              * The call to mbedtls_ccm_encrypt_and_tag or
90              * mbedtls_ccm_auth_decrypt will validate the tag length. */
91             if (PSA_BLOCK_CIPHER_BLOCK_LENGTH(attributes->core.type) != 16) {
92                 return PSA_ERROR_INVALID_ARGUMENT;
93             }
94 
95             mbedtls_ccm_init(&operation->ctx.ccm);
96             status = mbedtls_to_psa_error(
97                 mbedtls_ccm_setkey(&operation->ctx.ccm, cipher_id,
98                                    key_buffer, (unsigned int) key_bits));
99             if (status != PSA_SUCCESS) {
100                 return status;
101             }
102             break;
103 #endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
104 
105 #if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
106         case PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_GCM, 0):
107             operation->core_alg = PSA_ALG_GCM;
108             full_tag_length = 16;
109             /* GCM allows the following tag lengths: 4, 8, 12, 13, 14, 15, 16.
110              * The call to mbedtls_gcm_crypt_and_tag or
111              * mbedtls_gcm_auth_decrypt will validate the tag length. */
112             if (PSA_BLOCK_CIPHER_BLOCK_LENGTH(attributes->core.type) != 16) {
113                 return PSA_ERROR_INVALID_ARGUMENT;
114             }
115 
116             mbedtls_gcm_init(&operation->ctx.gcm);
117             status = mbedtls_to_psa_error(
118                 mbedtls_gcm_setkey(&operation->ctx.gcm, cipher_id,
119                                    key_buffer, (unsigned int) key_bits));
120             if (status != PSA_SUCCESS) {
121                 return status;
122             }
123             break;
124 #endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
125 
126 #if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
127         case PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CHACHA20_POLY1305, 0):
128             operation->core_alg = PSA_ALG_CHACHA20_POLY1305;
129             full_tag_length = 16;
130             /* We only support the default tag length. */
131             if (alg != PSA_ALG_CHACHA20_POLY1305) {
132                 return PSA_ERROR_NOT_SUPPORTED;
133             }
134 
135             mbedtls_chachapoly_init(&operation->ctx.chachapoly);
136             status = mbedtls_to_psa_error(
137                 mbedtls_chachapoly_setkey(&operation->ctx.chachapoly,
138                                           key_buffer));
139             if (status != PSA_SUCCESS) {
140                 return status;
141             }
142             break;
143 #endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
144 
145         default:
146             (void) status;
147             (void) key_buffer;
148             return PSA_ERROR_NOT_SUPPORTED;
149     }
150 
151     if (PSA_AEAD_TAG_LENGTH(attributes->core.type,
152                             key_bits, alg)
153         > full_tag_length) {
154         return PSA_ERROR_INVALID_ARGUMENT;
155     }
156 
157     operation->tag_length = PSA_AEAD_TAG_LENGTH(attributes->core.type,
158                                                 key_bits,
159                                                 alg);
160 
161     return PSA_SUCCESS;
162 }
163 
mbedtls_psa_aead_encrypt(const psa_key_attributes_t * attributes,const uint8_t * key_buffer,size_t key_buffer_size,psa_algorithm_t alg,const uint8_t * nonce,size_t nonce_length,const uint8_t * additional_data,size_t additional_data_length,const uint8_t * plaintext,size_t plaintext_length,uint8_t * ciphertext,size_t ciphertext_size,size_t * ciphertext_length)164 psa_status_t mbedtls_psa_aead_encrypt(
165     const psa_key_attributes_t *attributes,
166     const uint8_t *key_buffer, size_t key_buffer_size,
167     psa_algorithm_t alg,
168     const uint8_t *nonce, size_t nonce_length,
169     const uint8_t *additional_data, size_t additional_data_length,
170     const uint8_t *plaintext, size_t plaintext_length,
171     uint8_t *ciphertext, size_t ciphertext_size, size_t *ciphertext_length)
172 {
173     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
174     aead_operation_t operation = AEAD_OPERATION_INIT;
175     uint8_t *tag;
176     (void) key_buffer_size;
177 
178     status = psa_aead_setup(&operation, attributes, key_buffer, alg);
179     if (status != PSA_SUCCESS) {
180         goto exit;
181     }
182 
183     /* For all currently supported modes, the tag is at the end of the
184      * ciphertext. */
185     if (ciphertext_size < (plaintext_length + operation.tag_length)) {
186         status = PSA_ERROR_BUFFER_TOO_SMALL;
187         goto exit;
188     }
189     tag = ciphertext + plaintext_length;
190 
191 #if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
192     if (operation.core_alg == PSA_ALG_CCM) {
193         status = mbedtls_to_psa_error(
194             mbedtls_ccm_encrypt_and_tag(&operation.ctx.ccm,
195                                         plaintext_length,
196                                         nonce, nonce_length,
197                                         additional_data,
198                                         additional_data_length,
199                                         plaintext, ciphertext,
200                                         tag, operation.tag_length));
201     } else
202 #endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
203 #if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
204     if (operation.core_alg == PSA_ALG_GCM) {
205         status = mbedtls_to_psa_error(
206             mbedtls_gcm_crypt_and_tag(&operation.ctx.gcm,
207                                       MBEDTLS_GCM_ENCRYPT,
208                                       plaintext_length,
209                                       nonce, nonce_length,
210                                       additional_data, additional_data_length,
211                                       plaintext, ciphertext,
212                                       operation.tag_length, tag));
213     } else
214 #endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
215 #if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
216     if (operation.core_alg == PSA_ALG_CHACHA20_POLY1305) {
217         if (nonce_length != 12) {
218             if (nonce_length == 8) {
219                 status = PSA_ERROR_NOT_SUPPORTED;
220             } else {
221                 status = PSA_ERROR_INVALID_ARGUMENT;
222             }
223             goto exit;
224         }
225 
226         if (operation.tag_length != 16) {
227             status = PSA_ERROR_NOT_SUPPORTED;
228             goto exit;
229         }
230         status = mbedtls_to_psa_error(
231             mbedtls_chachapoly_encrypt_and_tag(&operation.ctx.chachapoly,
232                                                plaintext_length,
233                                                nonce,
234                                                additional_data,
235                                                additional_data_length,
236                                                plaintext,
237                                                ciphertext,
238                                                tag));
239     } else
240 #endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
241     {
242         (void) tag;
243         (void) nonce;
244         (void) nonce_length;
245         (void) additional_data;
246         (void) additional_data_length;
247         (void) plaintext;
248         return PSA_ERROR_NOT_SUPPORTED;
249     }
250 
251     if (status == PSA_SUCCESS) {
252         *ciphertext_length = plaintext_length + operation.tag_length;
253     }
254 
255 exit:
256     psa_aead_abort_internal(&operation);
257 
258     return status;
259 }
260 
261 /* Locate the tag in a ciphertext buffer containing the encrypted data
262  * followed by the tag. Return the length of the part preceding the tag in
263  * *plaintext_length. This is the size of the plaintext in modes where
264  * the encrypted data has the same size as the plaintext, such as
265  * CCM and GCM. */
psa_aead_unpadded_locate_tag(size_t tag_length,const uint8_t * ciphertext,size_t ciphertext_length,size_t plaintext_size,const uint8_t ** p_tag)266 static psa_status_t psa_aead_unpadded_locate_tag(size_t tag_length,
267                                                  const uint8_t *ciphertext,
268                                                  size_t ciphertext_length,
269                                                  size_t plaintext_size,
270                                                  const uint8_t **p_tag)
271 {
272     size_t payload_length;
273     if (tag_length > ciphertext_length) {
274         return PSA_ERROR_INVALID_ARGUMENT;
275     }
276     payload_length = ciphertext_length - tag_length;
277     if (payload_length > plaintext_size) {
278         return PSA_ERROR_BUFFER_TOO_SMALL;
279     }
280     *p_tag = ciphertext + payload_length;
281     return PSA_SUCCESS;
282 }
283 
mbedtls_psa_aead_decrypt(const psa_key_attributes_t * attributes,const uint8_t * key_buffer,size_t key_buffer_size,psa_algorithm_t alg,const uint8_t * nonce,size_t nonce_length,const uint8_t * additional_data,size_t additional_data_length,const uint8_t * ciphertext,size_t ciphertext_length,uint8_t * plaintext,size_t plaintext_size,size_t * plaintext_length)284 psa_status_t mbedtls_psa_aead_decrypt(
285     const psa_key_attributes_t *attributes,
286     const uint8_t *key_buffer, size_t key_buffer_size,
287     psa_algorithm_t alg,
288     const uint8_t *nonce, size_t nonce_length,
289     const uint8_t *additional_data, size_t additional_data_length,
290     const uint8_t *ciphertext, size_t ciphertext_length,
291     uint8_t *plaintext, size_t plaintext_size, size_t *plaintext_length)
292 {
293     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
294     aead_operation_t operation = AEAD_OPERATION_INIT;
295     const uint8_t *tag = NULL;
296     (void) key_buffer_size;
297 
298     status = psa_aead_setup(&operation, attributes, key_buffer, alg);
299     if (status != PSA_SUCCESS) {
300         goto exit;
301     }
302 
303     status = psa_aead_unpadded_locate_tag(operation.tag_length,
304                                           ciphertext, ciphertext_length,
305                                           plaintext_size, &tag);
306     if (status != PSA_SUCCESS) {
307         goto exit;
308     }
309 
310 #if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
311     if (operation.core_alg == PSA_ALG_CCM) {
312         status = mbedtls_to_psa_error(
313             mbedtls_ccm_auth_decrypt(&operation.ctx.ccm,
314                                      ciphertext_length - operation.tag_length,
315                                      nonce, nonce_length,
316                                      additional_data,
317                                      additional_data_length,
318                                      ciphertext, plaintext,
319                                      tag, operation.tag_length));
320     } else
321 #endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
322 #if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
323     if (operation.core_alg == PSA_ALG_GCM) {
324         status = mbedtls_to_psa_error(
325             mbedtls_gcm_auth_decrypt(&operation.ctx.gcm,
326                                      ciphertext_length - operation.tag_length,
327                                      nonce, nonce_length,
328                                      additional_data,
329                                      additional_data_length,
330                                      tag, operation.tag_length,
331                                      ciphertext, plaintext));
332     } else
333 #endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
334 #if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
335     if (operation.core_alg == PSA_ALG_CHACHA20_POLY1305) {
336         if (nonce_length != 12) {
337             if (nonce_length == 8) {
338                 status = PSA_ERROR_NOT_SUPPORTED;
339             } else {
340                 status = PSA_ERROR_INVALID_ARGUMENT;
341             }
342             goto exit;
343         }
344 
345         if (operation.tag_length != 16) {
346             status = PSA_ERROR_NOT_SUPPORTED;
347             goto exit;
348         }
349         status = mbedtls_to_psa_error(
350             mbedtls_chachapoly_auth_decrypt(&operation.ctx.chachapoly,
351                                             ciphertext_length - operation.tag_length,
352                                             nonce,
353                                             additional_data,
354                                             additional_data_length,
355                                             tag,
356                                             ciphertext,
357                                             plaintext));
358     } else
359 #endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
360     {
361         (void) nonce;
362         (void) nonce_length;
363         (void) additional_data;
364         (void) additional_data_length;
365         (void) plaintext;
366         return PSA_ERROR_NOT_SUPPORTED;
367     }
368 
369     if (status == PSA_SUCCESS) {
370         *plaintext_length = ciphertext_length - operation.tag_length;
371     }
372 
373 exit:
374     psa_aead_abort_internal(&operation);
375 
376     if (status == PSA_SUCCESS) {
377         *plaintext_length = ciphertext_length - operation.tag_length;
378     }
379     return status;
380 }
381 
382 #endif /* MBEDTLS_PSA_CRYPTO_C */
383