blob: bfa271b5a193b0eeeb4f059bdc7b6ee900dd886b [file] [log] [blame]
Ronald Cron7ceee8d2021-03-17 16:55:43 +01001/*
2 * PSA AEAD entry points
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
Paul Elliottadb8b162021-04-20 16:06:57 +010023
Ronald Cron7ceee8d2021-03-17 16:55:43 +010024#if defined(MBEDTLS_PSA_CRYPTO_C)
25
26#include "psa_crypto_aead.h"
Ronald Cron46f91782021-03-17 08:16:34 +010027#include "psa_crypto_core.h"
28
Paul Elliottadb8b162021-04-20 16:06:57 +010029#include <string.h>
30#include "mbedtls/platform.h"
31#if !defined(MBEDTLS_PLATFORM_C)
32#define mbedtls_calloc calloc
33#define mbedtls_free free
34#endif
35
Ronald Cron46f91782021-03-17 08:16:34 +010036#include "mbedtls/ccm.h"
37#include "mbedtls/chachapoly.h"
38#include "mbedtls/cipher.h"
39#include "mbedtls/gcm.h"
Paul Elliottadb8b162021-04-20 16:06:57 +010040#include "mbedtls/error.h"
Ronald Cron46f91782021-03-17 08:16:34 +010041
Paul Elliottadb8b162021-04-20 16:06:57 +010042/* Constant-time buffer comparison. This is duplication of code from
43 * psa_crypto.c, but has nowhere private I can put it for the minute. Really
44 belongs in the constant time module, when that gets implemented */
45static inline int safer_memcmp( const uint8_t *a, const uint8_t *b, size_t n )
Ronald Cron46f91782021-03-17 08:16:34 +010046{
Paul Elliottadb8b162021-04-20 16:06:57 +010047 size_t i;
48 unsigned char diff = 0;
49
50 for( i = 0; i < n; i++ )
51 diff |= a[i] ^ b[i];
52
53 return( diff );
Ronald Cron46f91782021-03-17 08:16:34 +010054}
55
Paul Elliottadb8b162021-04-20 16:06:57 +010056
Ronald Cron46f91782021-03-17 08:16:34 +010057static psa_status_t psa_aead_setup(
Paul Elliott07a30c42021-04-20 14:13:23 +010058 psa_aead_operation_t *operation,
Ronald Cron46f91782021-03-17 08:16:34 +010059 const psa_key_attributes_t *attributes,
60 const uint8_t *key_buffer,
61 psa_algorithm_t alg )
62{
63 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
64 size_t key_bits;
Ronald Cronecbc0682021-03-26 13:25:17 +010065 const mbedtls_cipher_info_t *cipher_info;
Ronald Cron46f91782021-03-17 08:16:34 +010066 mbedtls_cipher_id_t cipher_id;
Ronald Cronecbc0682021-03-26 13:25:17 +010067 size_t full_tag_length = 0;
Ronald Cron46f91782021-03-17 08:16:34 +010068
Paul Elliottadb8b162021-04-20 16:06:57 +010069 if( operation->key_set || operation->nonce_set ||
70 operation->ad_started || operation->body_started )
71 {
72 return( PSA_ERROR_BAD_STATE );
73 }
74
Ronald Cron46f91782021-03-17 08:16:34 +010075 key_bits = attributes->core.bits;
76
Ronald Cronecbc0682021-03-26 13:25:17 +010077 cipher_info = mbedtls_cipher_info_from_psa( alg,
78 attributes->core.type, key_bits,
79 &cipher_id );
80 if( cipher_info == NULL )
Ronald Cron46f91782021-03-17 08:16:34 +010081 return( PSA_ERROR_NOT_SUPPORTED );
82
83 switch( PSA_ALG_AEAD_WITH_SHORTENED_TAG( alg, 0 ) )
84 {
85#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
86 case PSA_ALG_AEAD_WITH_SHORTENED_TAG( PSA_ALG_CCM, 0 ):
Paul Elliott07a30c42021-04-20 14:13:23 +010087 operation->alg = PSA_ALG_CCM;
Ronald Cronecbc0682021-03-26 13:25:17 +010088 full_tag_length = 16;
Ronald Cron46f91782021-03-17 08:16:34 +010089 /* CCM allows the following tag lengths: 4, 6, 8, 10, 12, 14, 16.
90 * The call to mbedtls_ccm_encrypt_and_tag or
91 * mbedtls_ccm_auth_decrypt will validate the tag length. */
92 if( PSA_BLOCK_CIPHER_BLOCK_LENGTH( attributes->core.type ) != 16 )
93 return( PSA_ERROR_INVALID_ARGUMENT );
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 break;
102#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
103
104#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
105 case PSA_ALG_AEAD_WITH_SHORTENED_TAG( PSA_ALG_GCM, 0 ):
Paul Elliott07a30c42021-04-20 14:13:23 +0100106 operation->alg = PSA_ALG_GCM;
Ronald Cronecbc0682021-03-26 13:25:17 +0100107 full_tag_length = 16;
Ronald Cron46f91782021-03-17 08:16:34 +0100108 /* GCM allows the following tag lengths: 4, 8, 12, 13, 14, 15, 16.
109 * The call to mbedtls_gcm_crypt_and_tag or
110 * mbedtls_gcm_auth_decrypt will validate the tag length. */
111 if( PSA_BLOCK_CIPHER_BLOCK_LENGTH( attributes->core.type ) != 16 )
112 return( PSA_ERROR_INVALID_ARGUMENT );
113
114 mbedtls_gcm_init( &operation->ctx.gcm );
115 status = mbedtls_to_psa_error(
116 mbedtls_gcm_setkey( &operation->ctx.gcm, cipher_id,
117 key_buffer, (unsigned int) key_bits ) );
118 if( status != PSA_SUCCESS )
119 return( status );
120 break;
121#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
122
123#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
124 case PSA_ALG_AEAD_WITH_SHORTENED_TAG( PSA_ALG_CHACHA20_POLY1305, 0 ):
Paul Elliott07a30c42021-04-20 14:13:23 +0100125 operation->alg = PSA_ALG_CHACHA20_POLY1305;
Ronald Cronecbc0682021-03-26 13:25:17 +0100126 full_tag_length = 16;
Ronald Cron46f91782021-03-17 08:16:34 +0100127 /* We only support the default tag length. */
128 if( alg != PSA_ALG_CHACHA20_POLY1305 )
129 return( PSA_ERROR_NOT_SUPPORTED );
130
131 mbedtls_chachapoly_init( &operation->ctx.chachapoly );
132 status = mbedtls_to_psa_error(
133 mbedtls_chachapoly_setkey( &operation->ctx.chachapoly,
134 key_buffer ) );
135 if( status != PSA_SUCCESS )
136 return( status );
137 break;
138#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
139
140 default:
141 return( PSA_ERROR_NOT_SUPPORTED );
142 }
143
Bence Szépkútiec174e22021-03-19 18:46:15 +0100144 if( PSA_AEAD_TAG_LENGTH( attributes->core.type,
145 key_bits, alg )
146 > full_tag_length )
Ronald Cron46f91782021-03-17 08:16:34 +0100147 return( PSA_ERROR_INVALID_ARGUMENT );
148
Bence Szépkútiec174e22021-03-19 18:46:15 +0100149 operation->tag_length = PSA_AEAD_TAG_LENGTH( attributes->core.type,
150 key_bits,
151 alg );
Ronald Cron46f91782021-03-17 08:16:34 +0100152
Paul Elliottadb8b162021-04-20 16:06:57 +0100153 operation->key_set = 1;
154
Ronald Cron46f91782021-03-17 08:16:34 +0100155 return( PSA_SUCCESS );
156}
157
158psa_status_t mbedtls_psa_aead_encrypt(
159 const psa_key_attributes_t *attributes,
160 const uint8_t *key_buffer, size_t key_buffer_size,
161 psa_algorithm_t alg,
162 const uint8_t *nonce, size_t nonce_length,
163 const uint8_t *additional_data, size_t additional_data_length,
164 const uint8_t *plaintext, size_t plaintext_length,
165 uint8_t *ciphertext, size_t ciphertext_size, size_t *ciphertext_length )
166{
167 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
Paul Elliott07a30c42021-04-20 14:13:23 +0100168 psa_aead_operation_t operation = PSA_AEAD_OPERATION_INIT;
Ronald Cron46f91782021-03-17 08:16:34 +0100169 uint8_t *tag;
170 (void) key_buffer_size;
171
172 status = psa_aead_setup( &operation, attributes, key_buffer, alg );
173 if( status != PSA_SUCCESS )
174 goto exit;
175
176 /* For all currently supported modes, the tag is at the end of the
177 * ciphertext. */
178 if( ciphertext_size < ( plaintext_length + operation.tag_length ) )
179 {
180 status = PSA_ERROR_BUFFER_TOO_SMALL;
181 goto exit;
182 }
183 tag = ciphertext + plaintext_length;
184
Ronald Cron46f91782021-03-17 08:16:34 +0100185#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
Paul Elliott07a30c42021-04-20 14:13:23 +0100186 if( operation.alg == PSA_ALG_CCM )
Ronald Cron46f91782021-03-17 08:16:34 +0100187 {
188 status = mbedtls_to_psa_error(
189 mbedtls_ccm_encrypt_and_tag( &operation.ctx.ccm,
190 plaintext_length,
191 nonce, nonce_length,
192 additional_data,
193 additional_data_length,
194 plaintext, ciphertext,
195 tag, operation.tag_length ) );
196 }
197 else
198#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
Ronald Cron810eb162021-04-06 09:01:39 +0200199#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
Paul Elliott07a30c42021-04-20 14:13:23 +0100200 if( operation.alg == PSA_ALG_GCM )
Ronald Cron810eb162021-04-06 09:01:39 +0200201 {
202 status = mbedtls_to_psa_error(
203 mbedtls_gcm_crypt_and_tag( &operation.ctx.gcm,
204 MBEDTLS_GCM_ENCRYPT,
205 plaintext_length,
206 nonce, nonce_length,
207 additional_data, additional_data_length,
208 plaintext, ciphertext,
209 operation.tag_length, tag ) );
210 }
211 else
212#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
Ronald Cron46f91782021-03-17 08:16:34 +0100213#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
Paul Elliott07a30c42021-04-20 14:13:23 +0100214 if( operation.alg == PSA_ALG_CHACHA20_POLY1305 )
Ronald Cron46f91782021-03-17 08:16:34 +0100215 {
216 if( nonce_length != 12 || operation.tag_length != 16 )
217 {
218 status = PSA_ERROR_NOT_SUPPORTED;
219 goto exit;
220 }
221 status = mbedtls_to_psa_error(
222 mbedtls_chachapoly_encrypt_and_tag( &operation.ctx.chachapoly,
223 plaintext_length,
224 nonce,
225 additional_data,
226 additional_data_length,
227 plaintext,
228 ciphertext,
229 tag ) );
230 }
231 else
232#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
233 {
234 (void) tag;
235 return( PSA_ERROR_NOT_SUPPORTED );
236 }
237
238 if( status == PSA_SUCCESS )
239 *ciphertext_length = plaintext_length + operation.tag_length;
240
241exit:
Paul Elliottadb8b162021-04-20 16:06:57 +0100242 mbedtls_psa_aead_abort( &operation );
Ronald Cron46f91782021-03-17 08:16:34 +0100243
244 return( status );
245}
246
247/* Locate the tag in a ciphertext buffer containing the encrypted data
248 * followed by the tag. Return the length of the part preceding the tag in
249 * *plaintext_length. This is the size of the plaintext in modes where
250 * the encrypted data has the same size as the plaintext, such as
251 * CCM and GCM. */
252static psa_status_t psa_aead_unpadded_locate_tag( size_t tag_length,
253 const uint8_t *ciphertext,
254 size_t ciphertext_length,
255 size_t plaintext_size,
256 const uint8_t **p_tag )
257{
258 size_t payload_length;
259 if( tag_length > ciphertext_length )
260 return( PSA_ERROR_INVALID_ARGUMENT );
261 payload_length = ciphertext_length - tag_length;
262 if( payload_length > plaintext_size )
263 return( PSA_ERROR_BUFFER_TOO_SMALL );
264 *p_tag = ciphertext + payload_length;
265 return( PSA_SUCCESS );
266}
267
268psa_status_t mbedtls_psa_aead_decrypt(
269 const psa_key_attributes_t *attributes,
270 const uint8_t *key_buffer, size_t key_buffer_size,
271 psa_algorithm_t alg,
272 const uint8_t *nonce, size_t nonce_length,
273 const uint8_t *additional_data, size_t additional_data_length,
274 const uint8_t *ciphertext, size_t ciphertext_length,
275 uint8_t *plaintext, size_t plaintext_size, size_t *plaintext_length )
276{
277 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
Paul Elliott07a30c42021-04-20 14:13:23 +0100278 psa_aead_operation_t operation = PSA_AEAD_OPERATION_INIT;
Ronald Cron46f91782021-03-17 08:16:34 +0100279 const uint8_t *tag = NULL;
280 (void) key_buffer_size;
281
282 status = psa_aead_setup( &operation, attributes, key_buffer, alg );
283 if( status != PSA_SUCCESS )
284 goto exit;
285
286 status = psa_aead_unpadded_locate_tag( operation.tag_length,
287 ciphertext, ciphertext_length,
288 plaintext_size, &tag );
289 if( status != PSA_SUCCESS )
290 goto exit;
291
Ronald Cron46f91782021-03-17 08:16:34 +0100292#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
Paul Elliott07a30c42021-04-20 14:13:23 +0100293 if( operation.alg == PSA_ALG_CCM )
Ronald Cron46f91782021-03-17 08:16:34 +0100294 {
295 status = mbedtls_to_psa_error(
296 mbedtls_ccm_auth_decrypt( &operation.ctx.ccm,
297 ciphertext_length - operation.tag_length,
298 nonce, nonce_length,
299 additional_data,
300 additional_data_length,
301 ciphertext, plaintext,
302 tag, operation.tag_length ) );
303 }
304 else
305#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
Ronald Cron810eb162021-04-06 09:01:39 +0200306#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
Paul Elliott07a30c42021-04-20 14:13:23 +0100307 if( operation.alg == PSA_ALG_GCM )
Ronald Cron810eb162021-04-06 09:01:39 +0200308 {
309 status = mbedtls_to_psa_error(
310 mbedtls_gcm_auth_decrypt( &operation.ctx.gcm,
311 ciphertext_length - operation.tag_length,
312 nonce, nonce_length,
313 additional_data,
314 additional_data_length,
315 tag, operation.tag_length,
316 ciphertext, plaintext ) );
317 }
318 else
319#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
Ronald Cron46f91782021-03-17 08:16:34 +0100320#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
Paul Elliott07a30c42021-04-20 14:13:23 +0100321 if( operation.alg == PSA_ALG_CHACHA20_POLY1305 )
Ronald Cron46f91782021-03-17 08:16:34 +0100322 {
323 if( nonce_length != 12 || operation.tag_length != 16 )
324 {
325 status = PSA_ERROR_NOT_SUPPORTED;
326 goto exit;
327 }
328 status = mbedtls_to_psa_error(
329 mbedtls_chachapoly_auth_decrypt( &operation.ctx.chachapoly,
330 ciphertext_length - operation.tag_length,
331 nonce,
332 additional_data,
333 additional_data_length,
334 tag,
335 ciphertext,
336 plaintext ) );
337 }
338 else
339#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
340 {
341 return( PSA_ERROR_NOT_SUPPORTED );
342 }
343
344 if( status == PSA_SUCCESS )
345 *plaintext_length = ciphertext_length - operation.tag_length;
346
347exit:
Paul Elliottadb8b162021-04-20 16:06:57 +0100348 mbedtls_psa_aead_abort( &operation );
Ronald Cron46f91782021-03-17 08:16:34 +0100349
350 if( status == PSA_SUCCESS )
351 *plaintext_length = ciphertext_length - operation.tag_length;
352 return( status );
353}
Ronald Cron7ceee8d2021-03-17 16:55:43 +0100354
Paul Elliottadb8b162021-04-20 16:06:57 +0100355/* Set the key and algorithm for a multipart authenticated encryption
356 * operation. */
357psa_status_t mbedtls_psa_aead_encrypt_setup( psa_aead_operation_t *operation,
358 const psa_key_attributes_t *attributes,
359 const uint8_t *key_buffer, size_t key_buffer_size,
360 psa_algorithm_t alg )
361{
362 psa_status_t status;
363
364 (void) key_buffer_size;
365
366 status = psa_aead_setup( operation, attributes, key_buffer, alg );
367
368 if( status == PSA_SUCCESS )
369 {
370 operation->is_encrypt = 1;
371 }
372
373 return ( status );
374}
375
376/* Set the key and algorithm for a multipart authenticated decryption
377 * operation. */
378psa_status_t mbedtls_psa_aead_decrypt_setup( psa_aead_operation_t *operation,
379 const psa_key_attributes_t *attributes,
380 const uint8_t *key_buffer, size_t key_buffer_size,
381 psa_algorithm_t alg )
382{
383 psa_status_t status;
384
385 (void) key_buffer_size;
386
387 status = psa_aead_setup( operation, attributes, key_buffer, alg );
388
389 if( status == PSA_SUCCESS )
390 {
391 operation->is_encrypt = 0;
392 }
393
394 return ( status );
395}
396
Paul Elliottadb8b162021-04-20 16:06:57 +0100397/* Set a nonce for the multipart AEAD operation*/
398psa_status_t mbedtls_psa_aead_set_nonce( psa_aead_operation_t *operation,
399 const uint8_t *nonce,
400 size_t nonce_length )
401{
402 psa_status_t status;
403
Paul Elliottadb8b162021-04-20 16:06:57 +0100404 #if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
405 if( operation->alg == PSA_ALG_GCM )
406 {
407 /* GCM sets nonce once additional data has been supplied */
408 memcpy(operation->nonce, nonce, nonce_length);
409
410 /* We know that nonce size cannot exceed the uint8_t size */
411 operation->nonce_length = ( uint8_t ) nonce_length;
412 status = PSA_SUCCESS;
413 }
414 else
415#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
416#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
417 if( operation->alg == PSA_ALG_CCM )
418 {
419 /* Multipart CCM not supported as yet, so CCM is basically operating
420 in oneshot mode. Store the nonce as we need this later */
421 memcpy(operation->nonce, nonce, nonce_length);
422
423 /* We know that nonce size cannot exceed the uint8_t size */
424 operation->nonce_length = ( uint8_t ) nonce_length;
425 status = PSA_SUCCESS;
426 }
427 else
428#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
429#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
430 if( operation->alg == PSA_ALG_CHACHA20_POLY1305 )
431 {
432 if( nonce_length != 12 && nonce_length != 8)
433 {
434 return( PSA_ERROR_INVALID_ARGUMENT );
435 }
436
437 status = mbedtls_to_psa_error(mbedtls_chachapoly_starts( &operation->ctx.chachapoly,
438 nonce,
439 operation->is_encrypt ?
440 MBEDTLS_CHACHAPOLY_ENCRYPT :
441 MBEDTLS_CHACHAPOLY_DECRYPT ) );
442 }
443 else
444#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
445 {
446 ( void ) nonce;
447 ( void ) nonce_length;
448
449 return ( PSA_ERROR_NOT_SUPPORTED );
450 }
451
452 if( status == PSA_SUCCESS )
453 {
454 operation->nonce_set = 1;
455 }
456
457 return( status );
458}
459 /* Declare the lengths of the message and additional data for AEAD. */
460psa_status_t mbedtls_psa_aead_set_lengths( psa_aead_operation_t *operation,
461 size_t ad_length,
462 size_t plaintext_length )
463{
464
Paul Elliottadb8b162021-04-20 16:06:57 +0100465#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
466 if( operation->alg == PSA_ALG_GCM )
467 {
468#if SIZE_MAX > UINT32_MAX
469 if( ( (uint64_t) ad_length ) >> 61 != 0 ||
470 ( (uint64_t) plaintext_length ) > 0xFFFFFFFE0ull )
471 {
472 return ( PSA_ERROR_INVALID_ARGUMENT );
473 }
474#endif
475 }
476 else
477#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
478#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
479 if( operation->alg == PSA_ALG_CCM )
480 {
481 if( ad_length > 0xFF00 )
482 {
483 return ( PSA_ERROR_INVALID_ARGUMENT );
484 }
485 }
486 else
487#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
488#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
489 if( operation->alg == PSA_ALG_CHACHA20_POLY1305 )
490 {
491 /* No length restrictions for ChaChaPoly. */
492 }
493 else
494#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
495 {
496 ( void ) ad_length;
497 ( void ) plaintext_length;
498
499 return ( PSA_ERROR_NOT_SUPPORTED );
500 }
501
502 operation->ad_remaining = ad_length;
503 operation->body_remaining = plaintext_length;
504 operation->lengths_set = 1;
505
506 return ( PSA_SUCCESS );
507}
508
509/* Pass additional data to an active multipart AEAD operation. */
510psa_status_t mbedtls_psa_aead_update_ad( psa_aead_operation_t *operation,
511 const uint8_t *input,
512 size_t input_length )
513{
514 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
515
Paul Elliottadb8b162021-04-20 16:06:57 +0100516 if( operation->lengths_set )
517 {
518 if ( operation->ad_remaining < input_length )
519 {
520 return( PSA_ERROR_INVALID_ARGUMENT );
521 }
522
523 operation->ad_remaining -= input_length;
524 }
525
526#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
527 if( operation->alg == PSA_ALG_GCM )
528 {
529 if( !operation->lengths_set || operation->ad_started )
530 {
531 return( PSA_ERROR_BAD_STATE );
532 }
533
534 /* GCM currently requires all the additional data to be passed in in
535 * one contigious buffer, so until that is re-done, we have to enforce
536 * this, as we cannot allocate a buffer to collate multiple calls into.
537 */
Paul Elliott72c10082021-04-23 19:02:16 +0100538 if( operation->ad_remaining != 0 )
Paul Elliottadb8b162021-04-20 16:06:57 +0100539 {
540 return ( PSA_ERROR_INVALID_ARGUMENT );
541 }
542
543 status = mbedtls_to_psa_error( mbedtls_gcm_starts( &operation->ctx.gcm,
544 operation->is_encrypt ?
545 MBEDTLS_GCM_ENCRYPT : MBEDTLS_GCM_DECRYPT,
546 operation->nonce,
547 operation->nonce_length,
548 input,
549 input_length ) );
550
551 }
552 else
553#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
554#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
555 if( operation->alg == PSA_ALG_CCM )
556 {
557 /* CCM requires all additional data to be passed in in one go at the
558 minute, as we are basically operating in oneshot mode. */
Paul Elliott72c10082021-04-23 19:02:16 +0100559 if( operation->ad_started )
Paul Elliottadb8b162021-04-20 16:06:57 +0100560 {
561 return( PSA_ERROR_BAD_STATE );
562 }
563
564 /* Save the additional data for later, this will be passed in
565 when we have the body. */
566 operation->ad_buffer = ( uint8_t * ) mbedtls_calloc(1, input_length );
567
568 if( operation->ad_buffer )
569 {
570 memcpy( operation->ad_buffer, input, input_length );
571 operation->ad_length = input_length;
Paul Elliott72c10082021-04-23 19:02:16 +0100572 status = PSA_SUCCESS;
Paul Elliottadb8b162021-04-20 16:06:57 +0100573 }
574 else
575 {
576 return ( PSA_ERROR_INSUFFICIENT_MEMORY );
577 }
578 }
579 else
580#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
581#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
582 if( operation->alg == PSA_ALG_CHACHA20_POLY1305 )
583 {
584 status = mbedtls_to_psa_error( mbedtls_chachapoly_update_aad( &operation->ctx.chachapoly,
585 input,
586 input_length ) );
587 }
588 else
589#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
590 {
591 (void) input;
592 (void) input_length;
593
594 return ( PSA_ERROR_NOT_SUPPORTED );
595 }
596
597 if( status == PSA_SUCCESS )
598 {
599 operation->ad_started = 1;
600 }
601
602 return ( status );
603}
604
605/* Encrypt or decrypt a message fragment in an active multipart AEAD
606 * operation.*/
607psa_status_t mbedtls_psa_aead_update( psa_aead_operation_t *operation,
608 const uint8_t *input,
609 size_t input_length,
610 uint8_t *output,
611 size_t output_size,
612 size_t *output_length )
613{
614 size_t update_output_size;
615 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
Paul Elliottfd3ca242021-04-25 18:10:42 +0100616 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Elliottadb8b162021-04-20 16:06:57 +0100617
Paul Elliottfd3ca242021-04-25 18:10:42 +0100618 update_output_size = input_length;
Paul Elliottadb8b162021-04-20 16:06:57 +0100619
Paul Elliott72c10082021-04-23 19:02:16 +0100620 if( PSA_AEAD_UPDATE_OUTPUT_SIZE( operation->key_type, operation->alg,
621 input_length ) > output_size )
Paul Elliottadb8b162021-04-20 16:06:57 +0100622 {
623 return ( PSA_ERROR_BUFFER_TOO_SMALL );
624 }
625
626 if( operation->lengths_set)
627 {
628 /* Additional data length was supplied, but not all the additional
629 data was supplied.*/
630 if( operation->ad_remaining != 0 )
631 {
632 return ( PSA_ERROR_INVALID_ARGUMENT );
633 }
634
635 /* Too much data provided. */
636 if( operation->body_remaining < input_length )
637 {
638 return ( PSA_ERROR_INVALID_ARGUMENT );
639 }
640
641 operation->body_remaining -= input_length;
642 }
643
644#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
645 if( operation->alg == PSA_ALG_GCM )
646 {
647 /* For the time being set the requirement that all of the body data
648 * must be passed in in one update, rather than deal with the complexity
649 * of non block size aligned updates. This will be fixed in 3.0 when
650 we can change the signature of the GCM multipart functions */
651 if( !operation->lengths_set || operation->body_remaining != 0 )
652 {
653 return( PSA_ERROR_BAD_STATE );
654 }
655
Paul Elliott72c10082021-04-23 19:02:16 +0100656 if( !operation->ad_started )
Paul Elliottadb8b162021-04-20 16:06:57 +0100657 {
658 return( PSA_ERROR_BAD_STATE );
659 }
660
661 status = mbedtls_to_psa_error( mbedtls_gcm_update( &operation->ctx.gcm,
662 input_length,
663 input,
664 output ) );
665 }
666 else
667#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
668#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
669 if( operation->alg == PSA_ALG_CCM )
670 {
671 /* CCM dooes not support multipart yet, so all the input has to be
Paul Elliottfd3ca242021-04-25 18:10:42 +0100672 passed in in one go. */
Paul Elliott72c10082021-04-23 19:02:16 +0100673 if( operation->body_started )
Paul Elliottadb8b162021-04-20 16:06:57 +0100674 {
675 return( PSA_ERROR_BAD_STATE );
676 }
677
Paul Elliottfd3ca242021-04-25 18:10:42 +0100678 /* Need to store tag for Finish() / Verify() */
679 operation->tag_buffer = ( uint8_t * ) mbedtls_calloc(1, operation->tag_length );
Paul Elliottadb8b162021-04-20 16:06:57 +0100680
Paul Elliottfd3ca242021-04-25 18:10:42 +0100681 if( operation->tag_buffer )
Paul Elliottadb8b162021-04-20 16:06:57 +0100682 {
Paul Elliottfd3ca242021-04-25 18:10:42 +0100683
684 if( operation->is_encrypt )
685 {
686 /* Perform oneshot CCM encryption with additional data already
687 stored, as CCM does not support multipart yet.*/
688 status = mbedtls_to_psa_error( mbedtls_ccm_encrypt_and_tag( &operation->ctx.ccm,
689 input_length,
690 operation->nonce,
691 operation->nonce_length,
692 operation->ad_buffer,
693 operation->ad_length,
694 input,
695 output,
696 operation->tag_buffer,
697 operation->tag_length ) );
698
699 /* Even if the above operation fails, we no longer need the
700 additional data.*/
701 mbedtls_free(operation->ad_buffer);
702 operation->ad_buffer = NULL;
703 operation->ad_length = 0;
704 }
705 else
706 {
707 /* Need to back up the body data so we can do this again
708 later.*/
709 operation->body_buffer = ( uint8_t * ) mbedtls_calloc(1, input_length );
710
711 if( operation->body_buffer )
712 {
713 memcpy( operation->body_buffer, input, input_length );
714 operation->body_length = input_length;
715
716 /* this will fail, as the tag is clearly false, but will write the
717 decrypted data to the output buffer. */
718 ret = mbedtls_ccm_auth_decrypt( &operation->ctx.ccm, input_length,
719 operation->nonce, operation->nonce_length,
720 operation->ad_buffer, operation->ad_length,
721 input, output,
722 operation->tag_buffer,
723 operation->tag_length );
724
725 if( ret == MBEDTLS_ERR_CCM_AUTH_FAILED )
726 {
727 status = PSA_SUCCESS;
728 }
729 else
730 {
731 status = mbedtls_to_psa_error( ret );
732 }
733 }
734 else
735 {
736 status = PSA_ERROR_INSUFFICIENT_MEMORY;
737 }
738 }
Paul Elliottadb8b162021-04-20 16:06:57 +0100739 }
740 else
741 {
Paul Elliottfd3ca242021-04-25 18:10:42 +0100742 status = PSA_ERROR_INSUFFICIENT_MEMORY;
Paul Elliottadb8b162021-04-20 16:06:57 +0100743 }
Paul Elliottadb8b162021-04-20 16:06:57 +0100744 }
745 else
746#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
747#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
748 if( operation->alg == PSA_ALG_CHACHA20_POLY1305 )
749 {
750 status = mbedtls_to_psa_error( mbedtls_chachapoly_update( &operation->ctx.chachapoly,
751 input_length,
752 input,
753 output ) );
754 }
755 else
756#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
757 {
758 (void) input;
759 (void) input_length;
760
761 return ( PSA_ERROR_NOT_SUPPORTED );
762 }
763
764 if( status == PSA_SUCCESS )
765 {
766 *output_length = update_output_size;
767 operation->body_started = 1;
768 }
769
770 return( status );
771}
772
773/* Common checks for both mbedtls_psa_aead_finish() and
774 mbedtls_psa_aead_verify() */
775static psa_status_t mbedtls_psa_aead_finish_checks( psa_aead_operation_t *operation,
776 size_t output_size,
Paul Elliottfd3ca242021-04-25 18:10:42 +0100777 size_t tag_size )
Paul Elliottadb8b162021-04-20 16:06:57 +0100778{
Paul Elliottfd3ca242021-04-25 18:10:42 +0100779 size_t finish_output_size;
780
Paul Elliottadb8b162021-04-20 16:06:57 +0100781 if( operation->lengths_set )
782 {
783 if( operation->ad_remaining != 0 || operation->body_remaining != 0 )
784 {
785 return( PSA_ERROR_BAD_STATE );
786 }
787 }
788
Paul Elliottfd3ca242021-04-25 18:10:42 +0100789 if( tag_size < operation->tag_length )
Paul Elliottadb8b162021-04-20 16:06:57 +0100790 {
791 return ( PSA_ERROR_BUFFER_TOO_SMALL );
792 }
793
Paul Elliottfd3ca242021-04-25 18:10:42 +0100794 if( operation->is_encrypt )
Paul Elliottadb8b162021-04-20 16:06:57 +0100795 {
Paul Elliottfd3ca242021-04-25 18:10:42 +0100796 finish_output_size = PSA_AEAD_FINISH_OUTPUT_SIZE( operation->key_type,
797 operation->alg );
Paul Elliottadb8b162021-04-20 16:06:57 +0100798 }
799 else
800 {
Paul Elliottfd3ca242021-04-25 18:10:42 +0100801 finish_output_size = PSA_AEAD_VERIFY_OUTPUT_SIZE( operation->key_type,
Paul Elliott72c10082021-04-23 19:02:16 +0100802 operation->alg );
Paul Elliottadb8b162021-04-20 16:06:57 +0100803 }
804
Paul Elliottfd3ca242021-04-25 18:10:42 +0100805 if( output_size < finish_output_size )
Paul Elliottadb8b162021-04-20 16:06:57 +0100806 {
807 return ( PSA_ERROR_BUFFER_TOO_SMALL );
808 }
809
810 return ( PSA_SUCCESS );
Paul Elliottadb8b162021-04-20 16:06:57 +0100811}
812
813/* Finish encrypting a message in a multipart AEAD operation. */
814psa_status_t mbedtls_psa_aead_finish( psa_aead_operation_t *operation,
815 uint8_t *ciphertext,
816 size_t ciphertext_size,
817 size_t *ciphertext_length,
818 uint8_t *tag,
819 size_t tag_size,
820 size_t *tag_length )
821{
822 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
Paul Elliottfd3ca242021-04-25 18:10:42 +0100823 size_t finish_output_size = 0;
Paul Elliottadb8b162021-04-20 16:06:57 +0100824
Paul Elliottfd3ca242021-04-25 18:10:42 +0100825 status = mbedtls_psa_aead_finish_checks( operation, ciphertext_size, tag_size );
Paul Elliottadb8b162021-04-20 16:06:57 +0100826
827 if( status != PSA_SUCCESS )
828 {
829 return status;
830 }
831
832#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
833 if( operation->alg == PSA_ALG_GCM )
834 {
835 /* We will need to do final GCM pass in here when multipart is done. */
836 status = mbedtls_to_psa_error( mbedtls_gcm_finish( &operation->ctx.gcm,
837 tag,
838 tag_size ) );
839 }
840 else
841#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
842#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
843 if( operation->alg == PSA_ALG_CCM )
844 {
Paul Elliottfd3ca242021-04-25 18:10:42 +0100845 /* Copy the previously generated tag into place */
846 memcpy( tag, operation->tag_buffer, operation->tag_length );
Paul Elliottadb8b162021-04-20 16:06:57 +0100847
Paul Elliottfd3ca242021-04-25 18:10:42 +0100848 mbedtls_free(operation->tag_buffer);
849 operation->tag_buffer = NULL;
Paul Elliottadb8b162021-04-20 16:06:57 +0100850
Paul Elliottfd3ca242021-04-25 18:10:42 +0100851 status = PSA_SUCCESS;
Paul Elliottadb8b162021-04-20 16:06:57 +0100852 }
853 else
854#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
855#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
856 if( operation->alg == PSA_ALG_CHACHA20_POLY1305 )
857 {
858 status = mbedtls_to_psa_error( mbedtls_chachapoly_finish( &operation->ctx.chachapoly,
859 tag ) );
860 }
861 else
862#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
863 {
864 ( void ) ciphertext;
865 ( void ) ciphertext_size;
866 ( void ) ciphertext_length;
867 ( void ) tag;
868 ( void ) tag_size;
869 ( void ) tag_length;
870
871 return ( PSA_ERROR_NOT_SUPPORTED );
872 }
873
874 if( status == PSA_SUCCESS )
875 {
876 *ciphertext_length = finish_output_size;
Paul Elliottfd3ca242021-04-25 18:10:42 +0100877 *tag_length = operation->tag_length;
Paul Elliottadb8b162021-04-20 16:06:57 +0100878 }
879
880 mbedtls_psa_aead_abort(operation);
881
882 return ( status );
883}
884
885/* Finish authenticating and decrypting a message in a multipart AEAD
886 * operation.*/
887psa_status_t mbedtls_psa_aead_verify( psa_aead_operation_t *operation,
888 uint8_t *plaintext,
889 size_t plaintext_size,
890 size_t *plaintext_length,
891 const uint8_t *tag,
892 size_t tag_length )
893{
894 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
895 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
896
Paul Elliottfd3ca242021-04-25 18:10:42 +0100897 uint8_t * temp_buffer;
898 size_t temp_buffer_size;
899
900 size_t finish_output_size = 0;
Paul Elliottadb8b162021-04-20 16:06:57 +0100901
902 int do_tag_check = 1;
903 uint8_t check_tag[16];
904
Paul Elliottfd3ca242021-04-25 18:10:42 +0100905 status = mbedtls_psa_aead_finish_checks( operation, plaintext_size, tag_length );
Paul Elliottadb8b162021-04-20 16:06:57 +0100906
907 if( status != PSA_SUCCESS )
908 {
909 return status;
910 }
911
912#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
913 if( operation->alg == PSA_ALG_GCM )
914 {
915 /* Call finish to get the tag for comparison */
916 status = mbedtls_to_psa_error( mbedtls_gcm_finish( &operation->ctx.gcm,
917 check_tag,
Paul Elliottfd3ca242021-04-25 18:10:42 +0100918 operation->tag_length ) );
Paul Elliottadb8b162021-04-20 16:06:57 +0100919 }
920 else
921#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
922#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
923 if( operation->alg == PSA_ALG_CCM )
924 {
Paul Elliottfd3ca242021-04-25 18:10:42 +0100925 if( !operation->ad_buffer || !operation->body_buffer )
Paul Elliottadb8b162021-04-20 16:06:57 +0100926 {
927 return( PSA_ERROR_BAD_STATE );
928 }
929
Paul Elliottfd3ca242021-04-25 18:10:42 +0100930 /* Perform oneshot CCM decryption *again*, as its the
931 * only way to get the tag, but this time throw away the
932 results, as verify cannot write that much data. */
933 temp_buffer_size = PSA_AEAD_UPDATE_OUTPUT_SIZE( operation->key_type,
934 operation->alg, operation->body_length );
Paul Elliottadb8b162021-04-20 16:06:57 +0100935
Paul Elliottfd3ca242021-04-25 18:10:42 +0100936 temp_buffer = ( uint8_t * ) mbedtls_calloc(1, temp_buffer_size );
Paul Elliottadb8b162021-04-20 16:06:57 +0100937
Paul Elliottfd3ca242021-04-25 18:10:42 +0100938 if( temp_buffer )
Paul Elliottadb8b162021-04-20 16:06:57 +0100939 {
Paul Elliottfd3ca242021-04-25 18:10:42 +0100940 ret = mbedtls_ccm_auth_decrypt( &operation->ctx.ccm, operation->body_length,
941 operation->nonce, operation->nonce_length,
942 operation->ad_buffer, operation->ad_length,
943 operation->body_buffer, temp_buffer,
944 tag, tag_length );
945
946 if( ret == MBEDTLS_ERR_CCM_AUTH_FAILED )
947 {
948 status = PSA_ERROR_INVALID_SIGNATURE;
949 }
950 else
951 {
952 status = mbedtls_to_psa_error( ret );
953 do_tag_check = 0;
954 }
Paul Elliottadb8b162021-04-20 16:06:57 +0100955 }
956 else
957 {
Paul Elliottfd3ca242021-04-25 18:10:42 +0100958 status = PSA_ERROR_INSUFFICIENT_MEMORY;
Paul Elliottadb8b162021-04-20 16:06:57 +0100959 }
960
961 /* Even if the above operation fails, we no longer need the data */
Paul Elliottfd3ca242021-04-25 18:10:42 +0100962 mbedtls_free(temp_buffer);
Paul Elliottadb8b162021-04-20 16:06:57 +0100963
Paul Elliottfd3ca242021-04-25 18:10:42 +0100964 mbedtls_free(operation->body_buffer);
965 operation->body_buffer = NULL;
966 operation->body_length = 0;
967
968 mbedtls_free(operation->tag_buffer);
969 operation->tag_buffer = NULL;
Paul Elliottadb8b162021-04-20 16:06:57 +0100970 }
971 else
972#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
973#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
974 if( operation->alg == PSA_ALG_CHACHA20_POLY1305 )
975 {
976 // call finish to get the tag for comparison.
977 status = mbedtls_to_psa_error( mbedtls_chachapoly_finish( &operation->ctx.chachapoly,
978 check_tag ) );
Paul Elliottfd3ca242021-04-25 18:10:42 +0100979
Paul Elliottadb8b162021-04-20 16:06:57 +0100980 }
981 else
982#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
983 {
984 ( void ) plaintext;
985 ( void ) plaintext_size;
986 ( void ) plaintext_length;
987 ( void ) tag;
988 ( void ) tag_length;
989
990 return ( PSA_ERROR_NOT_SUPPORTED );
991 }
992
993 if( status == PSA_SUCCESS )
994 {
Paul Elliott72c10082021-04-23 19:02:16 +0100995 *plaintext_length = finish_output_size;
996
Paul Elliottadb8b162021-04-20 16:06:57 +0100997 if( do_tag_check && safer_memcmp(tag, check_tag, tag_length) != 0 )
998 {
Paul Elliott811d8d42021-04-22 11:31:14 +0100999 status = PSA_ERROR_INVALID_SIGNATURE;
Paul Elliottadb8b162021-04-20 16:06:57 +01001000 }
1001 }
1002
1003 mbedtls_psa_aead_abort(operation);
1004
1005 return ( status );
1006}
1007
1008/* Abort an AEAD operation */
1009psa_status_t mbedtls_psa_aead_abort( psa_aead_operation_t *operation )
1010{
Paul Elliott811d8d42021-04-22 11:31:14 +01001011 switch( operation->alg )
Paul Elliottadb8b162021-04-20 16:06:57 +01001012 {
Paul Elliott811d8d42021-04-22 11:31:14 +01001013#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
1014 case PSA_ALG_CCM:
Paul Elliottadb8b162021-04-20 16:06:57 +01001015 mbedtls_ccm_free( &operation->ctx.ccm );
1016 break;
1017#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
1018#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
1019 case PSA_ALG_GCM:
1020 mbedtls_gcm_free( &operation->ctx.gcm );
1021 break;
1022#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
1023#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
Paul Elliott811d8d42021-04-22 11:31:14 +01001024 case PSA_ALG_CHACHA20_POLY1305:
1025 mbedtls_chachapoly_free( &operation->ctx.chachapoly );
1026 break;
Paul Elliottadb8b162021-04-20 16:06:57 +01001027#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
1028 }
1029
Paul Elliottfd3ca242021-04-25 18:10:42 +01001030 mbedtls_free(operation->ad_buffer);
1031 operation->ad_buffer = NULL;
1032 operation->ad_length = 0;
1033
1034 mbedtls_free(operation->body_buffer);
1035 operation->body_buffer = NULL;
1036 operation->body_length = 0;
1037
1038 mbedtls_free(operation->tag_buffer);
1039 operation->tag_buffer = NULL;
1040
Paul Elliottadb8b162021-04-20 16:06:57 +01001041 return( PSA_SUCCESS );
1042}
1043
Ronald Cron7ceee8d2021-03-17 16:55:43 +01001044#endif /* MBEDTLS_PSA_CRYPTO_C */
1045