| /* | 
 |  *  PSA AEAD entry points | 
 |  */ | 
 | /* | 
 |  *  Copyright The Mbed TLS Contributors | 
 |  *  SPDX-License-Identifier: Apache-2.0 | 
 |  * | 
 |  *  Licensed under the Apache License, Version 2.0 (the "License"); you may | 
 |  *  not use this file except in compliance with the License. | 
 |  *  You may obtain a copy of the License at | 
 |  * | 
 |  *  http://www.apache.org/licenses/LICENSE-2.0 | 
 |  * | 
 |  *  Unless required by applicable law or agreed to in writing, software | 
 |  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | 
 |  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 |  *  See the License for the specific language governing permissions and | 
 |  *  limitations under the License. | 
 |  */ | 
 |  | 
 | #include "common.h" | 
 |  | 
 | #if defined(MBEDTLS_PSA_CRYPTO_C) | 
 |  | 
 | #include "psa_crypto_aead.h" | 
 | #include "psa_crypto_core.h" | 
 | #include "psa_crypto_cipher.h" | 
 |  | 
 | #include <string.h> | 
 | #include "mbedtls/platform.h" | 
 |  | 
 | #include "mbedtls/ccm.h" | 
 | #include "mbedtls/chachapoly.h" | 
 | #include "mbedtls/cipher.h" | 
 | #include "mbedtls/gcm.h" | 
 | #include "mbedtls/error.h" | 
 |  | 
 | static psa_status_t psa_aead_setup( | 
 |     mbedtls_psa_aead_operation_t *operation, | 
 |     const psa_key_attributes_t *attributes, | 
 |     const uint8_t *key_buffer, | 
 |     size_t key_buffer_size, | 
 |     psa_algorithm_t alg) | 
 | { | 
 |     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; | 
 |     size_t key_bits; | 
 |     const mbedtls_cipher_info_t *cipher_info; | 
 |     mbedtls_cipher_id_t cipher_id; | 
 |  | 
 |     (void) key_buffer_size; | 
 |  | 
 |     key_bits = attributes->core.bits; | 
 |  | 
 |     cipher_info = mbedtls_cipher_info_from_psa(alg, | 
 |                                                attributes->core.type, key_bits, | 
 |                                                &cipher_id); | 
 |     if (cipher_info == NULL) { | 
 |         return PSA_ERROR_NOT_SUPPORTED; | 
 |     } | 
 |  | 
 |     switch (PSA_ALG_AEAD_WITH_SHORTENED_TAG(alg, 0)) { | 
 | #if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM) | 
 |         case PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, 0): | 
 |             operation->alg = PSA_ALG_CCM; | 
 |             /* CCM allows the following tag lengths: 4, 6, 8, 10, 12, 14, 16. | 
 |              * The call to mbedtls_ccm_encrypt_and_tag or | 
 |              * mbedtls_ccm_auth_decrypt will validate the tag length. */ | 
 |             if (PSA_BLOCK_CIPHER_BLOCK_LENGTH(attributes->core.type) != 16) { | 
 |                 return PSA_ERROR_INVALID_ARGUMENT; | 
 |             } | 
 |  | 
 |             mbedtls_ccm_init(&operation->ctx.ccm); | 
 |             status = mbedtls_to_psa_error( | 
 |                 mbedtls_ccm_setkey(&operation->ctx.ccm, cipher_id, | 
 |                                    key_buffer, (unsigned int) key_bits)); | 
 |             if (status != PSA_SUCCESS) { | 
 |                 return status; | 
 |             } | 
 |             break; | 
 | #endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */ | 
 |  | 
 | #if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM) | 
 |         case PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_GCM, 0): | 
 |             operation->alg = PSA_ALG_GCM; | 
 |             /* GCM allows the following tag lengths: 4, 8, 12, 13, 14, 15, 16. | 
 |              * The call to mbedtls_gcm_crypt_and_tag or | 
 |              * mbedtls_gcm_auth_decrypt will validate the tag length. */ | 
 |             if (PSA_BLOCK_CIPHER_BLOCK_LENGTH(attributes->core.type) != 16) { | 
 |                 return PSA_ERROR_INVALID_ARGUMENT; | 
 |             } | 
 |  | 
 |             mbedtls_gcm_init(&operation->ctx.gcm); | 
 |             status = mbedtls_to_psa_error( | 
 |                 mbedtls_gcm_setkey(&operation->ctx.gcm, cipher_id, | 
 |                                    key_buffer, (unsigned int) key_bits)); | 
 |             if (status != PSA_SUCCESS) { | 
 |                 return status; | 
 |             } | 
 |             break; | 
 | #endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */ | 
 |  | 
 | #if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305) | 
 |         case PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CHACHA20_POLY1305, 0): | 
 |             operation->alg = PSA_ALG_CHACHA20_POLY1305; | 
 |             /* We only support the default tag length. */ | 
 |             if (alg != PSA_ALG_CHACHA20_POLY1305) { | 
 |                 return PSA_ERROR_NOT_SUPPORTED; | 
 |             } | 
 |  | 
 |             mbedtls_chachapoly_init(&operation->ctx.chachapoly); | 
 |             status = mbedtls_to_psa_error( | 
 |                 mbedtls_chachapoly_setkey(&operation->ctx.chachapoly, | 
 |                                           key_buffer)); | 
 |             if (status != PSA_SUCCESS) { | 
 |                 return status; | 
 |             } | 
 |             break; | 
 | #endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */ | 
 |  | 
 |         default: | 
 |             (void) status; | 
 |             (void) key_buffer; | 
 |             return PSA_ERROR_NOT_SUPPORTED; | 
 |     } | 
 |  | 
 |     operation->key_type = psa_get_key_type(attributes); | 
 |  | 
 |     operation->tag_length = PSA_ALG_AEAD_GET_TAG_LENGTH(alg); | 
 |  | 
 |     return PSA_SUCCESS; | 
 | } | 
 |  | 
 | psa_status_t 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) | 
 | { | 
 |     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; | 
 |     mbedtls_psa_aead_operation_t operation = MBEDTLS_PSA_AEAD_OPERATION_INIT; | 
 |     uint8_t *tag; | 
 |  | 
 |     status = psa_aead_setup(&operation, attributes, key_buffer, | 
 |                             key_buffer_size, alg); | 
 |  | 
 |     if (status != PSA_SUCCESS) { | 
 |         goto exit; | 
 |     } | 
 |  | 
 |     /* For all currently supported modes, the tag is at the end of the | 
 |      * ciphertext. */ | 
 |     if (ciphertext_size < (plaintext_length + operation.tag_length)) { | 
 |         status = PSA_ERROR_BUFFER_TOO_SMALL; | 
 |         goto exit; | 
 |     } | 
 |     tag = ciphertext + plaintext_length; | 
 |  | 
 | #if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM) | 
 |     if (operation.alg == PSA_ALG_CCM) { | 
 |         status = mbedtls_to_psa_error( | 
 |             mbedtls_ccm_encrypt_and_tag(&operation.ctx.ccm, | 
 |                                         plaintext_length, | 
 |                                         nonce, nonce_length, | 
 |                                         additional_data, | 
 |                                         additional_data_length, | 
 |                                         plaintext, ciphertext, | 
 |                                         tag, operation.tag_length)); | 
 |     } else | 
 | #endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */ | 
 | #if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM) | 
 |     if (operation.alg == PSA_ALG_GCM) { | 
 |         status = mbedtls_to_psa_error( | 
 |             mbedtls_gcm_crypt_and_tag(&operation.ctx.gcm, | 
 |                                       MBEDTLS_GCM_ENCRYPT, | 
 |                                       plaintext_length, | 
 |                                       nonce, nonce_length, | 
 |                                       additional_data, additional_data_length, | 
 |                                       plaintext, ciphertext, | 
 |                                       operation.tag_length, tag)); | 
 |     } else | 
 | #endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */ | 
 | #if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305) | 
 |     if (operation.alg == PSA_ALG_CHACHA20_POLY1305) { | 
 |         if (operation.tag_length != 16) { | 
 |             status = PSA_ERROR_NOT_SUPPORTED; | 
 |             goto exit; | 
 |         } | 
 |         status = mbedtls_to_psa_error( | 
 |             mbedtls_chachapoly_encrypt_and_tag(&operation.ctx.chachapoly, | 
 |                                                plaintext_length, | 
 |                                                nonce, | 
 |                                                additional_data, | 
 |                                                additional_data_length, | 
 |                                                plaintext, | 
 |                                                ciphertext, | 
 |                                                tag)); | 
 |     } else | 
 | #endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */ | 
 |     { | 
 |         (void) tag; | 
 |         (void) nonce; | 
 |         (void) nonce_length; | 
 |         (void) additional_data; | 
 |         (void) additional_data_length; | 
 |         (void) plaintext; | 
 |         return PSA_ERROR_NOT_SUPPORTED; | 
 |     } | 
 |  | 
 |     if (status == PSA_SUCCESS) { | 
 |         *ciphertext_length = plaintext_length + operation.tag_length; | 
 |     } | 
 |  | 
 | exit: | 
 |     mbedtls_psa_aead_abort(&operation); | 
 |  | 
 |     return status; | 
 | } | 
 |  | 
 | /* Locate the tag in a ciphertext buffer containing the encrypted data | 
 |  * followed by the tag. Return the length of the part preceding the tag in | 
 |  * *plaintext_length. This is the size of the plaintext in modes where | 
 |  * the encrypted data has the same size as the plaintext, such as | 
 |  * CCM and GCM. */ | 
 | static psa_status_t 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) | 
 | { | 
 |     size_t payload_length; | 
 |     if (tag_length > ciphertext_length) { | 
 |         return PSA_ERROR_INVALID_ARGUMENT; | 
 |     } | 
 |     payload_length = ciphertext_length - tag_length; | 
 |     if (payload_length > plaintext_size) { | 
 |         return PSA_ERROR_BUFFER_TOO_SMALL; | 
 |     } | 
 |     *p_tag = ciphertext + payload_length; | 
 |     return PSA_SUCCESS; | 
 | } | 
 |  | 
 | psa_status_t 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) | 
 | { | 
 |     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; | 
 |     mbedtls_psa_aead_operation_t operation = MBEDTLS_PSA_AEAD_OPERATION_INIT; | 
 |     const uint8_t *tag = NULL; | 
 |  | 
 |     status = psa_aead_setup(&operation, attributes, key_buffer, | 
 |                             key_buffer_size, alg); | 
 |  | 
 |     if (status != PSA_SUCCESS) { | 
 |         goto exit; | 
 |     } | 
 |  | 
 |     status = psa_aead_unpadded_locate_tag(operation.tag_length, | 
 |                                           ciphertext, ciphertext_length, | 
 |                                           plaintext_size, &tag); | 
 |     if (status != PSA_SUCCESS) { | 
 |         goto exit; | 
 |     } | 
 |  | 
 | #if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM) | 
 |     if (operation.alg == PSA_ALG_CCM) { | 
 |         status = mbedtls_to_psa_error( | 
 |             mbedtls_ccm_auth_decrypt(&operation.ctx.ccm, | 
 |                                      ciphertext_length - operation.tag_length, | 
 |                                      nonce, nonce_length, | 
 |                                      additional_data, | 
 |                                      additional_data_length, | 
 |                                      ciphertext, plaintext, | 
 |                                      tag, operation.tag_length)); | 
 |     } else | 
 | #endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */ | 
 | #if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM) | 
 |     if (operation.alg == PSA_ALG_GCM) { | 
 |         status = mbedtls_to_psa_error( | 
 |             mbedtls_gcm_auth_decrypt(&operation.ctx.gcm, | 
 |                                      ciphertext_length - operation.tag_length, | 
 |                                      nonce, nonce_length, | 
 |                                      additional_data, | 
 |                                      additional_data_length, | 
 |                                      tag, operation.tag_length, | 
 |                                      ciphertext, plaintext)); | 
 |     } else | 
 | #endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */ | 
 | #if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305) | 
 |     if (operation.alg == PSA_ALG_CHACHA20_POLY1305) { | 
 |         if (operation.tag_length != 16) { | 
 |             status = PSA_ERROR_NOT_SUPPORTED; | 
 |             goto exit; | 
 |         } | 
 |         status = mbedtls_to_psa_error( | 
 |             mbedtls_chachapoly_auth_decrypt(&operation.ctx.chachapoly, | 
 |                                             ciphertext_length - operation.tag_length, | 
 |                                             nonce, | 
 |                                             additional_data, | 
 |                                             additional_data_length, | 
 |                                             tag, | 
 |                                             ciphertext, | 
 |                                             plaintext)); | 
 |     } else | 
 | #endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */ | 
 |     { | 
 |         (void) nonce; | 
 |         (void) nonce_length; | 
 |         (void) additional_data; | 
 |         (void) additional_data_length; | 
 |         (void) plaintext; | 
 |         return PSA_ERROR_NOT_SUPPORTED; | 
 |     } | 
 |  | 
 |     if (status == PSA_SUCCESS) { | 
 |         *plaintext_length = ciphertext_length - operation.tag_length; | 
 |     } | 
 |  | 
 | exit: | 
 |     mbedtls_psa_aead_abort(&operation); | 
 |  | 
 |     if (status == PSA_SUCCESS) { | 
 |         *plaintext_length = ciphertext_length - operation.tag_length; | 
 |     } | 
 |     return status; | 
 | } | 
 |  | 
 | /* Set the key and algorithm for a multipart authenticated encryption | 
 |  * operation. */ | 
 | psa_status_t mbedtls_psa_aead_encrypt_setup( | 
 |     mbedtls_psa_aead_operation_t *operation, | 
 |     const psa_key_attributes_t *attributes, | 
 |     const uint8_t *key_buffer, | 
 |     size_t key_buffer_size, | 
 |     psa_algorithm_t alg) | 
 | { | 
 |     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; | 
 |  | 
 |     status = psa_aead_setup(operation, attributes, key_buffer, | 
 |                             key_buffer_size, alg); | 
 |  | 
 |     if (status == PSA_SUCCESS) { | 
 |         operation->is_encrypt = 1; | 
 |     } | 
 |  | 
 |     return status; | 
 | } | 
 |  | 
 | /* Set the key and algorithm for a multipart authenticated decryption | 
 |  * operation. */ | 
 | psa_status_t mbedtls_psa_aead_decrypt_setup( | 
 |     mbedtls_psa_aead_operation_t *operation, | 
 |     const psa_key_attributes_t *attributes, | 
 |     const uint8_t *key_buffer, | 
 |     size_t key_buffer_size, | 
 |     psa_algorithm_t alg) | 
 | { | 
 |     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; | 
 |  | 
 |     status = psa_aead_setup(operation, attributes, key_buffer, | 
 |                             key_buffer_size, alg); | 
 |  | 
 |     if (status == PSA_SUCCESS) { | 
 |         operation->is_encrypt = 0; | 
 |     } | 
 |  | 
 |     return status; | 
 | } | 
 |  | 
 | /* Set a nonce for the multipart AEAD operation*/ | 
 | psa_status_t mbedtls_psa_aead_set_nonce( | 
 |     mbedtls_psa_aead_operation_t *operation, | 
 |     const uint8_t *nonce, | 
 |     size_t nonce_length) | 
 | { | 
 |     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; | 
 |  | 
 | #if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM) | 
 |     if (operation->alg == PSA_ALG_GCM) { | 
 |         status = mbedtls_to_psa_error( | 
 |             mbedtls_gcm_starts(&operation->ctx.gcm, | 
 |                                operation->is_encrypt ? | 
 |                                MBEDTLS_GCM_ENCRYPT : MBEDTLS_GCM_DECRYPT, | 
 |                                nonce, | 
 |                                nonce_length)); | 
 |     } else | 
 | #endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */ | 
 | #if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM) | 
 |     if (operation->alg == PSA_ALG_CCM) { | 
 |         status = mbedtls_to_psa_error( | 
 |             mbedtls_ccm_starts(&operation->ctx.ccm, | 
 |                                operation->is_encrypt ? | 
 |                                MBEDTLS_CCM_ENCRYPT : MBEDTLS_CCM_DECRYPT, | 
 |                                nonce, | 
 |                                nonce_length)); | 
 |     } else | 
 | #endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */ | 
 | #if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305) | 
 |     if (operation->alg == PSA_ALG_CHACHA20_POLY1305) { | 
 |         /* Note - ChaChaPoly allows an 8 byte nonce, but we would have to | 
 |          * allocate a buffer in the operation, copy the nonce to it and pad | 
 |          * it, so for now check the nonce is 12 bytes, as | 
 |          * mbedtls_chachapoly_starts() assumes it can read 12 bytes from the | 
 |          * passed in buffer. */ | 
 |         if (nonce_length != 12) { | 
 |             return PSA_ERROR_INVALID_ARGUMENT; | 
 |         } | 
 |  | 
 |         status = mbedtls_to_psa_error( | 
 |             mbedtls_chachapoly_starts(&operation->ctx.chachapoly, | 
 |                                       nonce, | 
 |                                       operation->is_encrypt ? | 
 |                                       MBEDTLS_CHACHAPOLY_ENCRYPT : | 
 |                                       MBEDTLS_CHACHAPOLY_DECRYPT)); | 
 |     } else | 
 | #endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */ | 
 |     { | 
 |         (void) operation; | 
 |         (void) nonce; | 
 |         (void) nonce_length; | 
 |  | 
 |         return PSA_ERROR_NOT_SUPPORTED; | 
 |     } | 
 |  | 
 |     return status; | 
 | } | 
 |  | 
 | /* Declare the lengths of the message and additional data for AEAD. */ | 
 | psa_status_t mbedtls_psa_aead_set_lengths( | 
 |     mbedtls_psa_aead_operation_t *operation, | 
 |     size_t ad_length, | 
 |     size_t plaintext_length) | 
 | { | 
 | #if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM) | 
 |     if (operation->alg == PSA_ALG_CCM) { | 
 |         return mbedtls_to_psa_error( | 
 |             mbedtls_ccm_set_lengths(&operation->ctx.ccm, | 
 |                                     ad_length, | 
 |                                     plaintext_length, | 
 |                                     operation->tag_length)); | 
 |  | 
 |     } | 
 | #else /* MBEDTLS_PSA_BUILTIN_ALG_CCM */ | 
 |     (void) operation; | 
 |     (void) ad_length; | 
 |     (void) plaintext_length; | 
 | #endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */ | 
 |  | 
 |     return PSA_SUCCESS; | 
 | } | 
 |  | 
 | /* Pass additional data to an active multipart AEAD operation. */ | 
 | psa_status_t mbedtls_psa_aead_update_ad( | 
 |     mbedtls_psa_aead_operation_t *operation, | 
 |     const uint8_t *input, | 
 |     size_t input_length) | 
 | { | 
 |     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; | 
 |  | 
 | #if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM) | 
 |     if (operation->alg == PSA_ALG_GCM) { | 
 |         status = mbedtls_to_psa_error( | 
 |             mbedtls_gcm_update_ad(&operation->ctx.gcm, input, input_length)); | 
 |     } else | 
 | #endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */ | 
 | #if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM) | 
 |     if (operation->alg == PSA_ALG_CCM) { | 
 |         status = mbedtls_to_psa_error( | 
 |             mbedtls_ccm_update_ad(&operation->ctx.ccm, input, input_length)); | 
 |     } else | 
 | #endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */ | 
 | #if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305) | 
 |     if (operation->alg == PSA_ALG_CHACHA20_POLY1305) { | 
 |         status = mbedtls_to_psa_error( | 
 |             mbedtls_chachapoly_update_aad(&operation->ctx.chachapoly, | 
 |                                           input, | 
 |                                           input_length)); | 
 |     } else | 
 | #endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */ | 
 |     { | 
 |         (void) operation; | 
 |         (void) input; | 
 |         (void) input_length; | 
 |  | 
 |         return PSA_ERROR_NOT_SUPPORTED; | 
 |     } | 
 |  | 
 |     return status; | 
 | } | 
 |  | 
 | /* Encrypt or decrypt a message fragment in an active multipart AEAD | 
 |  * operation.*/ | 
 | psa_status_t mbedtls_psa_aead_update( | 
 |     mbedtls_psa_aead_operation_t *operation, | 
 |     const uint8_t *input, | 
 |     size_t input_length, | 
 |     uint8_t *output, | 
 |     size_t output_size, | 
 |     size_t *output_length) | 
 | { | 
 |     size_t update_output_length; | 
 |     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; | 
 |  | 
 |     update_output_length = input_length; | 
 |  | 
 | #if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM) | 
 |     if (operation->alg == PSA_ALG_GCM) { | 
 |         status =  mbedtls_to_psa_error( | 
 |             mbedtls_gcm_update(&operation->ctx.gcm, | 
 |                                input, input_length, | 
 |                                output, output_size, | 
 |                                &update_output_length)); | 
 |     } else | 
 | #endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */ | 
 | #if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM) | 
 |     if (operation->alg == PSA_ALG_CCM) { | 
 |         if (output_size < input_length) { | 
 |             return PSA_ERROR_BUFFER_TOO_SMALL; | 
 |         } | 
 |  | 
 |         status = mbedtls_to_psa_error( | 
 |             mbedtls_ccm_update(&operation->ctx.ccm, | 
 |                                input, input_length, | 
 |                                output, output_size, | 
 |                                &update_output_length)); | 
 |     } else | 
 | #endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */ | 
 | #if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305) | 
 |     if (operation->alg == PSA_ALG_CHACHA20_POLY1305) { | 
 |         if (output_size < input_length) { | 
 |             return PSA_ERROR_BUFFER_TOO_SMALL; | 
 |         } | 
 |  | 
 |         status = mbedtls_to_psa_error( | 
 |             mbedtls_chachapoly_update(&operation->ctx.chachapoly, | 
 |                                       input_length, | 
 |                                       input, | 
 |                                       output)); | 
 |     } else | 
 | #endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */ | 
 |     { | 
 |         (void) operation; | 
 |         (void) input; | 
 |         (void) output; | 
 |         (void) output_size; | 
 |  | 
 |         return PSA_ERROR_NOT_SUPPORTED; | 
 |     } | 
 |  | 
 |     if (status == PSA_SUCCESS) { | 
 |         *output_length = update_output_length; | 
 |     } | 
 |  | 
 |     return status; | 
 | } | 
 |  | 
 | /* Finish encrypting a message in a multipart AEAD operation. */ | 
 | psa_status_t mbedtls_psa_aead_finish( | 
 |     mbedtls_psa_aead_operation_t *operation, | 
 |     uint8_t *ciphertext, | 
 |     size_t ciphertext_size, | 
 |     size_t *ciphertext_length, | 
 |     uint8_t *tag, | 
 |     size_t tag_size, | 
 |     size_t *tag_length) | 
 | { | 
 |     psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED; | 
 |     size_t finish_output_size = 0; | 
 |  | 
 |     if (tag_size < operation->tag_length) { | 
 |         return PSA_ERROR_BUFFER_TOO_SMALL; | 
 |     } | 
 |  | 
 | #if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM) | 
 |     if (operation->alg == PSA_ALG_GCM) { | 
 |         status =  mbedtls_to_psa_error( | 
 |             mbedtls_gcm_finish(&operation->ctx.gcm, | 
 |                                ciphertext, ciphertext_size, ciphertext_length, | 
 |                                tag, operation->tag_length)); | 
 |     } else | 
 | #endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */ | 
 | #if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM) | 
 |     if (operation->alg == PSA_ALG_CCM) { | 
 |         /* tag must be big enough to store a tag of size passed into set | 
 |          * lengths. */ | 
 |         if (tag_size < operation->tag_length) { | 
 |             return PSA_ERROR_BUFFER_TOO_SMALL; | 
 |         } | 
 |  | 
 |         status = mbedtls_to_psa_error( | 
 |             mbedtls_ccm_finish(&operation->ctx.ccm, | 
 |                                tag, operation->tag_length)); | 
 |     } else | 
 | #endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */ | 
 | #if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305) | 
 |     if (operation->alg == PSA_ALG_CHACHA20_POLY1305) { | 
 |         /* Belt and braces. Although the above tag_size check should have | 
 |          * already done this, if we later start supporting smaller tag sizes | 
 |          * for chachapoly, then passing a tag buffer smaller than 16 into here | 
 |          * could cause a buffer overflow, so better safe than sorry. */ | 
 |         if (tag_size < 16) { | 
 |             return PSA_ERROR_BUFFER_TOO_SMALL; | 
 |         } | 
 |  | 
 |         status = mbedtls_to_psa_error( | 
 |             mbedtls_chachapoly_finish(&operation->ctx.chachapoly, | 
 |                                       tag)); | 
 |     } else | 
 | #endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */ | 
 |     { | 
 |         (void) ciphertext; | 
 |         (void) ciphertext_size; | 
 |         (void) ciphertext_length; | 
 |         (void) tag; | 
 |         (void) tag_size; | 
 |         (void) tag_length; | 
 |  | 
 |         return PSA_ERROR_NOT_SUPPORTED; | 
 |     } | 
 |  | 
 |     if (status == PSA_SUCCESS) { | 
 |         /* This will be zero for all supported algorithms currently, but left | 
 |          * here for future support. */ | 
 |         *ciphertext_length = finish_output_size; | 
 |         *tag_length = operation->tag_length; | 
 |     } | 
 |  | 
 |     return status; | 
 | } | 
 |  | 
 | /* Abort an AEAD operation */ | 
 | psa_status_t mbedtls_psa_aead_abort( | 
 |     mbedtls_psa_aead_operation_t *operation) | 
 | { | 
 |     switch (operation->alg) { | 
 | #if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM) | 
 |         case PSA_ALG_CCM: | 
 |             mbedtls_ccm_free(&operation->ctx.ccm); | 
 |             break; | 
 | #endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */ | 
 | #if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM) | 
 |         case PSA_ALG_GCM: | 
 |             mbedtls_gcm_free(&operation->ctx.gcm); | 
 |             break; | 
 | #endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */ | 
 | #if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305) | 
 |         case PSA_ALG_CHACHA20_POLY1305: | 
 |             mbedtls_chachapoly_free(&operation->ctx.chachapoly); | 
 |             break; | 
 | #endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */ | 
 |     } | 
 |  | 
 |     operation->is_encrypt = 0; | 
 |  | 
 |     return PSA_SUCCESS; | 
 | } | 
 |  | 
 | #endif /* MBEDTLS_PSA_CRYPTO_C */ |