blob: e92dac512bfc78adfcbdc4e481aeddd43485baa8 [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 */
538 if( input_length != operation->ad_remaining )
539 {
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. */
559 if( !operation->lengths_set || operation->ad_started )
560 {
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;
572 }
573 else
574 {
575 return ( PSA_ERROR_INSUFFICIENT_MEMORY );
576 }
577 }
578 else
579#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
580#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
581 if( operation->alg == PSA_ALG_CHACHA20_POLY1305 )
582 {
583 status = mbedtls_to_psa_error( mbedtls_chachapoly_update_aad( &operation->ctx.chachapoly,
584 input,
585 input_length ) );
586 }
587 else
588#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
589 {
590 (void) input;
591 (void) input_length;
592
593 return ( PSA_ERROR_NOT_SUPPORTED );
594 }
595
596 if( status == PSA_SUCCESS )
597 {
598 operation->ad_started = 1;
599 }
600
601 return ( status );
602}
603
604/* Encrypt or decrypt a message fragment in an active multipart AEAD
605 * operation.*/
606psa_status_t mbedtls_psa_aead_update( psa_aead_operation_t *operation,
607 const uint8_t *input,
608 size_t input_length,
609 uint8_t *output,
610 size_t output_size,
611 size_t *output_length )
612{
613 size_t update_output_size;
614 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
615
Paul Elliottadb8b162021-04-20 16:06:57 +0100616 update_output_size = PSA_AEAD_UPDATE_OUTPUT_SIZE(operation->key_type,
617 operation->alg, input_length);
618
619 if(update_output_size > output_size )
620 {
621 return ( PSA_ERROR_BUFFER_TOO_SMALL );
622 }
623
624 if( operation->lengths_set)
625 {
626 /* Additional data length was supplied, but not all the additional
627 data was supplied.*/
628 if( operation->ad_remaining != 0 )
629 {
630 return ( PSA_ERROR_INVALID_ARGUMENT );
631 }
632
633 /* Too much data provided. */
634 if( operation->body_remaining < input_length )
635 {
636 return ( PSA_ERROR_INVALID_ARGUMENT );
637 }
638
639 operation->body_remaining -= input_length;
640 }
641
642#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
643 if( operation->alg == PSA_ALG_GCM )
644 {
645 /* For the time being set the requirement that all of the body data
646 * must be passed in in one update, rather than deal with the complexity
647 * of non block size aligned updates. This will be fixed in 3.0 when
648 we can change the signature of the GCM multipart functions */
649 if( !operation->lengths_set || operation->body_remaining != 0 )
650 {
651 return( PSA_ERROR_BAD_STATE );
652 }
653
654 if( operation->ad_started )
655 {
656 return( PSA_ERROR_BAD_STATE );
657 }
658
659 status = mbedtls_to_psa_error( mbedtls_gcm_update( &operation->ctx.gcm,
660 input_length,
661 input,
662 output ) );
663 }
664 else
665#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
666#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
667 if( operation->alg == PSA_ALG_CCM )
668 {
669 /* CCM dooes not support multipart yet, so all the input has to be
670 passed in in one go. Store the data for the final step.*/
671 if( operation->ad_started )
672 {
673 return( PSA_ERROR_BAD_STATE );
674 }
675
676 /* Save the additional data for later, this will be passed in
677 when we have the body. */
678 operation->data_buffer = ( uint8_t * ) mbedtls_calloc(1, input_length );
679
680 if( operation->data_buffer )
681 {
682 memcpy( operation->data_buffer, input, input_length );
683 operation->data_length = input_length;
684 }
685 else
686 {
687 return ( PSA_ERROR_INSUFFICIENT_MEMORY );
688 }
689
690 }
691 else
692#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
693#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
694 if( operation->alg == PSA_ALG_CHACHA20_POLY1305 )
695 {
696 status = mbedtls_to_psa_error( mbedtls_chachapoly_update( &operation->ctx.chachapoly,
697 input_length,
698 input,
699 output ) );
700 }
701 else
702#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
703 {
704 (void) input;
705 (void) input_length;
706
707 return ( PSA_ERROR_NOT_SUPPORTED );
708 }
709
710 if( status == PSA_SUCCESS )
711 {
712 *output_length = update_output_size;
713 operation->body_started = 1;
714 }
715
716 return( status );
717}
718
719/* Common checks for both mbedtls_psa_aead_finish() and
720 mbedtls_psa_aead_verify() */
721static psa_status_t mbedtls_psa_aead_finish_checks( psa_aead_operation_t *operation,
722 size_t output_size,
723 size_t tag_size,
724 size_t *finish_output_size,
725 size_t *output_tag_length )
726{
Paul Elliottadb8b162021-04-20 16:06:57 +0100727 if( operation->lengths_set )
728 {
729 if( operation->ad_remaining != 0 || operation->body_remaining != 0 )
730 {
731 return( PSA_ERROR_BAD_STATE );
732 }
733 }
734
735 *output_tag_length = operation->tag_length;
736
737 if( tag_size < *output_tag_length)
738 {
739 return ( PSA_ERROR_BUFFER_TOO_SMALL );
740 }
741
742 if( operation->is_encrypt )
743 {
744 *finish_output_size = PSA_AEAD_FINISH_OUTPUT_SIZE(operation->key_type,
745 operation->alg);
746 }
747 else
748 {
749 *finish_output_size = PSA_AEAD_VERIFY_OUTPUT_SIZE(operation->key_type,
750 operation->alg);
751 }
752
753 if( output_size < *finish_output_size )
754 {
755 return ( PSA_ERROR_BUFFER_TOO_SMALL );
756 }
757
758 return ( PSA_SUCCESS );
759
760}
761
762/* Finish encrypting a message in a multipart AEAD operation. */
763psa_status_t mbedtls_psa_aead_finish( psa_aead_operation_t *operation,
764 uint8_t *ciphertext,
765 size_t ciphertext_size,
766 size_t *ciphertext_length,
767 uint8_t *tag,
768 size_t tag_size,
769 size_t *tag_length )
770{
771 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
772 size_t output_tag_length;
773 size_t finish_output_size;
774
775 status = mbedtls_psa_aead_finish_checks( operation, ciphertext_size, tag_size, &finish_output_size,
776 &output_tag_length);
777
778 if( status != PSA_SUCCESS )
779 {
780 return status;
781 }
782
783#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
784 if( operation->alg == PSA_ALG_GCM )
785 {
786 /* We will need to do final GCM pass in here when multipart is done. */
787 status = mbedtls_to_psa_error( mbedtls_gcm_finish( &operation->ctx.gcm,
788 tag,
789 tag_size ) );
790 }
791 else
792#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
793#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
794 if( operation->alg == PSA_ALG_CCM )
795 {
796 if( !operation->ad_buffer || !operation->data_buffer )
797 {
798 return( PSA_ERROR_BAD_STATE );
799 }
800
801 /* Perform oneshot CCM encryption with data already stored, as
802 CCM does not support multipart yet.*/
803 status = mbedtls_to_psa_error( mbedtls_ccm_encrypt_and_tag( &operation->ctx.ccm,
804 operation->data_length,
805 operation->nonce,
806 operation->nonce_length,
807 operation->ad_buffer,
808 operation->ad_length,
809 operation->data_buffer,
810 ciphertext,
811 tag, tag_size ) );
812
813 /* Even if the above operation fails, we no longer need the data */
814 mbedtls_free(operation->ad_buffer);
815 operation->ad_buffer = NULL;
816 operation->ad_length = 0;
817
818 mbedtls_free(operation->data_buffer);
819 operation->data_buffer = NULL;
820 operation->data_length = 0;
821 }
822 else
823#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
824#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
825 if( operation->alg == PSA_ALG_CHACHA20_POLY1305 )
826 {
827 status = mbedtls_to_psa_error( mbedtls_chachapoly_finish( &operation->ctx.chachapoly,
828 tag ) );
829 }
830 else
831#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
832 {
833 ( void ) ciphertext;
834 ( void ) ciphertext_size;
835 ( void ) ciphertext_length;
836 ( void ) tag;
837 ( void ) tag_size;
838 ( void ) tag_length;
839
840 return ( PSA_ERROR_NOT_SUPPORTED );
841 }
842
843 if( status == PSA_SUCCESS )
844 {
845 *ciphertext_length = finish_output_size;
846 *tag_length = output_tag_length;
847 }
848
849 mbedtls_psa_aead_abort(operation);
850
851 return ( status );
852}
853
854/* Finish authenticating and decrypting a message in a multipart AEAD
855 * operation.*/
856psa_status_t mbedtls_psa_aead_verify( psa_aead_operation_t *operation,
857 uint8_t *plaintext,
858 size_t plaintext_size,
859 size_t *plaintext_length,
860 const uint8_t *tag,
861 size_t tag_length )
862{
863 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
864 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
865
866 size_t finish_output_size;
867 size_t output_tag_length;
868
869 int do_tag_check = 1;
870 uint8_t check_tag[16];
871
872 status = mbedtls_psa_aead_finish_checks( operation, plaintext_size, tag_length, &finish_output_size,
873 &output_tag_length);
874
875 if( status != PSA_SUCCESS )
876 {
877 return status;
878 }
879
880#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
881 if( operation->alg == PSA_ALG_GCM )
882 {
883 /* Call finish to get the tag for comparison */
884 status = mbedtls_to_psa_error( mbedtls_gcm_finish( &operation->ctx.gcm,
885 check_tag,
886 16 ) );
887 }
888 else
889#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
890#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
891 if( operation->alg == PSA_ALG_CCM )
892 {
893 if( !operation->ad_buffer || !operation->data_buffer )
894 {
895 return( PSA_ERROR_BAD_STATE );
896 }
897
898 /* Perform oneshot CCM decryption with data already stored, as
899 CCM does not support multipart yet.*/
900
901 ret = mbedtls_ccm_auth_decrypt( &operation->ctx.ccm, operation->data_length,
902 operation->nonce, operation->nonce_length,
903 operation->ad_buffer, operation->ad_length,
904 operation->data_buffer, plaintext,
905 tag, tag_length );
906
907 if( ret == MBEDTLS_ERR_CCM_AUTH_FAILED )
908 {
909 status = PSA_ERROR_INVALID_SIGNATURE;
910 }
911 else
912 {
913 status = mbedtls_to_psa_error( ret );
914 do_tag_check = 0;
915 }
916
917 /* Even if the above operation fails, we no longer need the data */
918 mbedtls_free(operation->ad_buffer);
919 operation->ad_buffer = NULL;
920 operation->ad_length = 0;
921
922 mbedtls_free(operation->data_buffer);
923 operation->data_buffer = NULL;
924 operation->data_length = 0;
925 }
926 else
927#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
928#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
929 if( operation->alg == PSA_ALG_CHACHA20_POLY1305 )
930 {
931 // call finish to get the tag for comparison.
932 status = mbedtls_to_psa_error( mbedtls_chachapoly_finish( &operation->ctx.chachapoly,
933 check_tag ) );
934 }
935 else
936#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
937 {
938 ( void ) plaintext;
939 ( void ) plaintext_size;
940 ( void ) plaintext_length;
941 ( void ) tag;
942 ( void ) tag_length;
943
944 return ( PSA_ERROR_NOT_SUPPORTED );
945 }
946
947 if( status == PSA_SUCCESS )
948 {
949 if( do_tag_check && safer_memcmp(tag, check_tag, tag_length) != 0 )
950 {
Paul Elliott811d8d42021-04-22 11:31:14 +0100951 status = PSA_ERROR_INVALID_SIGNATURE;
Paul Elliottadb8b162021-04-20 16:06:57 +0100952 }
953 }
954
955 mbedtls_psa_aead_abort(operation);
956
957 return ( status );
958}
959
960/* Abort an AEAD operation */
961psa_status_t mbedtls_psa_aead_abort( psa_aead_operation_t *operation )
962{
Paul Elliott811d8d42021-04-22 11:31:14 +0100963 switch( operation->alg )
Paul Elliottadb8b162021-04-20 16:06:57 +0100964 {
Paul Elliott811d8d42021-04-22 11:31:14 +0100965#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
966 case PSA_ALG_CCM:
Paul Elliottadb8b162021-04-20 16:06:57 +0100967 mbedtls_ccm_free( &operation->ctx.ccm );
968 break;
969#endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
970#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
971 case PSA_ALG_GCM:
972 mbedtls_gcm_free( &operation->ctx.gcm );
973 break;
974#endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
975#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
Paul Elliott811d8d42021-04-22 11:31:14 +0100976 case PSA_ALG_CHACHA20_POLY1305:
977 mbedtls_chachapoly_free( &operation->ctx.chachapoly );
978 break;
Paul Elliottadb8b162021-04-20 16:06:57 +0100979#endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
980 }
981
982 return( PSA_SUCCESS );
983}
984
Ronald Cron7ceee8d2021-03-17 16:55:43 +0100985#endif /* MBEDTLS_PSA_CRYPTO_C */
986