blob: c204ff4948d838e72e16535bdfd27bca41e9ee3d [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
23#if defined(MBEDTLS_PSA_CRYPTO_C)
24
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +020025# include "psa_crypto_aead.h"
26# include "psa_crypto_core.h"
Ronald Cron46f91782021-03-17 08:16:34 +010027
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +020028# include "mbedtls/ccm.h"
29# include "mbedtls/chachapoly.h"
30# include "mbedtls/cipher.h"
31# include "mbedtls/gcm.h"
Ronald Cron46f91782021-03-17 08:16:34 +010032
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +020033typedef struct {
34 union {
35 unsigned dummy; /* Make the union non-empty even with no supported
36 algorithms. */
37# if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
Ronald Cron46f91782021-03-17 08:16:34 +010038 mbedtls_ccm_context ccm;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +020039# endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
40# if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
Ronald Cron46f91782021-03-17 08:16:34 +010041 mbedtls_gcm_context gcm;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +020042# endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
43# if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
Ronald Cron46f91782021-03-17 08:16:34 +010044 mbedtls_chachapoly_context chachapoly;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +020045# endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
Ronald Cron46f91782021-03-17 08:16:34 +010046 } ctx;
47 psa_algorithm_t core_alg;
Ronald Cron46f91782021-03-17 08:16:34 +010048 uint8_t tag_length;
49} aead_operation_t;
50
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +020051# define AEAD_OPERATION_INIT \
52 { \
53 { 0 }, 0, 0 \
54 }
Ronald Cron46f91782021-03-17 08:16:34 +010055
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +020056static void psa_aead_abort_internal(aead_operation_t *operation)
Ronald Cron46f91782021-03-17 08:16:34 +010057{
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +020058 switch (operation->core_alg) {
59# if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
Ronald Cron46f91782021-03-17 08:16:34 +010060 case PSA_ALG_CCM:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +020061 mbedtls_ccm_free(&operation->ctx.ccm);
Ronald Cron46f91782021-03-17 08:16:34 +010062 break;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +020063# endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
64# if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
Ronald Cron46f91782021-03-17 08:16:34 +010065 case PSA_ALG_GCM:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +020066 mbedtls_gcm_free(&operation->ctx.gcm);
Ronald Cron46f91782021-03-17 08:16:34 +010067 break;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +020068# endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
69# if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
Ronald Cronb9349a62021-03-26 13:32:29 +010070 case PSA_ALG_CHACHA20_POLY1305:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +020071 mbedtls_chachapoly_free(&operation->ctx.chachapoly);
Ronald Cronb9349a62021-03-26 13:32:29 +010072 break;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +020073# endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
Ronald Cron46f91782021-03-17 08:16:34 +010074 }
75}
76
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +020077static psa_status_t psa_aead_setup(aead_operation_t *operation,
78 const psa_key_attributes_t *attributes,
79 const uint8_t *key_buffer,
80 psa_algorithm_t alg)
Ronald Cron46f91782021-03-17 08:16:34 +010081{
82 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
83 size_t key_bits;
Ronald Cronecbc0682021-03-26 13:25:17 +010084 const mbedtls_cipher_info_t *cipher_info;
Ronald Cron46f91782021-03-17 08:16:34 +010085 mbedtls_cipher_id_t cipher_id;
Ronald Cronecbc0682021-03-26 13:25:17 +010086 size_t full_tag_length = 0;
Ronald Cron46f91782021-03-17 08:16:34 +010087
88 key_bits = attributes->core.bits;
89
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +020090 cipher_info = mbedtls_cipher_info_from_psa(alg, attributes->core.type,
91 key_bits, &cipher_id);
92 if (cipher_info == NULL)
93 return PSA_ERROR_NOT_SUPPORTED;
Ronald Cron46f91782021-03-17 08:16:34 +010094
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +020095 switch (PSA_ALG_AEAD_WITH_SHORTENED_TAG(alg, 0)) {
96# if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
97 case PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, 0):
Ronald Cron46f91782021-03-17 08:16:34 +010098 operation->core_alg = PSA_ALG_CCM;
Ronald Cronecbc0682021-03-26 13:25:17 +010099 full_tag_length = 16;
Ronald Cron46f91782021-03-17 08:16:34 +0100100 /* CCM allows the following tag lengths: 4, 6, 8, 10, 12, 14, 16.
101 * The call to mbedtls_ccm_encrypt_and_tag or
102 * mbedtls_ccm_auth_decrypt will validate the tag length. */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200103 if (PSA_BLOCK_CIPHER_BLOCK_LENGTH(attributes->core.type) != 16)
104 return PSA_ERROR_INVALID_ARGUMENT;
Ronald Cron46f91782021-03-17 08:16:34 +0100105
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200106 mbedtls_ccm_init(&operation->ctx.ccm);
Ronald Cron46f91782021-03-17 08:16:34 +0100107 status = mbedtls_to_psa_error(
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200108 mbedtls_ccm_setkey(&operation->ctx.ccm, cipher_id, key_buffer,
109 (unsigned int)key_bits));
110 if (status != PSA_SUCCESS)
111 return status;
Ronald Cron46f91782021-03-17 08:16:34 +0100112 break;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200113# endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
Ronald Cron46f91782021-03-17 08:16:34 +0100114
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200115# if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
116 case PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_GCM, 0):
Ronald Cron46f91782021-03-17 08:16:34 +0100117 operation->core_alg = PSA_ALG_GCM;
Ronald Cronecbc0682021-03-26 13:25:17 +0100118 full_tag_length = 16;
Ronald Cron46f91782021-03-17 08:16:34 +0100119 /* GCM allows the following tag lengths: 4, 8, 12, 13, 14, 15, 16.
120 * The call to mbedtls_gcm_crypt_and_tag or
121 * mbedtls_gcm_auth_decrypt will validate the tag length. */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200122 if (PSA_BLOCK_CIPHER_BLOCK_LENGTH(attributes->core.type) != 16)
123 return PSA_ERROR_INVALID_ARGUMENT;
Ronald Cron46f91782021-03-17 08:16:34 +0100124
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200125 mbedtls_gcm_init(&operation->ctx.gcm);
Ronald Cron46f91782021-03-17 08:16:34 +0100126 status = mbedtls_to_psa_error(
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200127 mbedtls_gcm_setkey(&operation->ctx.gcm, cipher_id, key_buffer,
128 (unsigned int)key_bits));
129 if (status != PSA_SUCCESS)
130 return status;
Ronald Cron46f91782021-03-17 08:16:34 +0100131 break;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200132# endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
Ronald Cron46f91782021-03-17 08:16:34 +0100133
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200134# if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
135 case PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CHACHA20_POLY1305, 0):
Ronald Cron46f91782021-03-17 08:16:34 +0100136 operation->core_alg = PSA_ALG_CHACHA20_POLY1305;
Ronald Cronecbc0682021-03-26 13:25:17 +0100137 full_tag_length = 16;
Ronald Cron46f91782021-03-17 08:16:34 +0100138 /* We only support the default tag length. */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200139 if (alg != PSA_ALG_CHACHA20_POLY1305)
140 return PSA_ERROR_NOT_SUPPORTED;
Ronald Cron46f91782021-03-17 08:16:34 +0100141
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200142 mbedtls_chachapoly_init(&operation->ctx.chachapoly);
143 status = mbedtls_to_psa_error(mbedtls_chachapoly_setkey(
144 &operation->ctx.chachapoly, key_buffer));
145 if (status != PSA_SUCCESS)
146 return status;
Ronald Cron46f91782021-03-17 08:16:34 +0100147 break;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200148# endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
Ronald Cron46f91782021-03-17 08:16:34 +0100149
150 default:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200151 return PSA_ERROR_NOT_SUPPORTED;
Ronald Cron46f91782021-03-17 08:16:34 +0100152 }
153
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200154 if (PSA_AEAD_TAG_LENGTH(attributes->core.type, key_bits, alg) >
155 full_tag_length)
156 return PSA_ERROR_INVALID_ARGUMENT;
Ronald Cron46f91782021-03-17 08:16:34 +0100157
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200158 operation->tag_length =
159 PSA_AEAD_TAG_LENGTH(attributes->core.type, key_bits, alg);
Ronald Cron46f91782021-03-17 08:16:34 +0100160
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200161 return PSA_SUCCESS;
Ronald Cron46f91782021-03-17 08:16:34 +0100162}
163
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200164psa_status_t mbedtls_psa_aead_encrypt(const psa_key_attributes_t *attributes,
165 const uint8_t *key_buffer,
166 size_t key_buffer_size,
167 psa_algorithm_t alg,
168 const uint8_t *nonce,
169 size_t nonce_length,
170 const uint8_t *additional_data,
171 size_t additional_data_length,
172 const uint8_t *plaintext,
173 size_t plaintext_length,
174 uint8_t *ciphertext,
175 size_t ciphertext_size,
176 size_t *ciphertext_length)
Ronald Cron46f91782021-03-17 08:16:34 +0100177{
178 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
179 aead_operation_t operation = AEAD_OPERATION_INIT;
180 uint8_t *tag;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200181 (void)key_buffer_size;
Ronald Cron46f91782021-03-17 08:16:34 +0100182
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200183 status = psa_aead_setup(&operation, attributes, key_buffer, alg);
184 if (status != PSA_SUCCESS)
Ronald Cron46f91782021-03-17 08:16:34 +0100185 goto exit;
186
187 /* For all currently supported modes, the tag is at the end of the
188 * ciphertext. */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200189 if (ciphertext_size < (plaintext_length + operation.tag_length)) {
Ronald Cron46f91782021-03-17 08:16:34 +0100190 status = PSA_ERROR_BUFFER_TOO_SMALL;
191 goto exit;
192 }
193 tag = ciphertext + plaintext_length;
194
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200195# if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
196 if (operation.core_alg == PSA_ALG_CCM) {
197 status = mbedtls_to_psa_error(mbedtls_ccm_encrypt_and_tag(
198 &operation.ctx.ccm, plaintext_length, nonce, nonce_length,
199 additional_data, additional_data_length, plaintext, ciphertext, tag,
200 operation.tag_length));
201 } else
202# endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
203# if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
204 if (operation.core_alg == PSA_ALG_GCM) {
205 status = mbedtls_to_psa_error(mbedtls_gcm_crypt_and_tag(
206 &operation.ctx.gcm, MBEDTLS_GCM_ENCRYPT, plaintext_length, nonce,
207 nonce_length, additional_data, additional_data_length, plaintext,
208 ciphertext, operation.tag_length, tag));
209 } else
210# endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
211# if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
212 if (operation.core_alg == PSA_ALG_CHACHA20_POLY1305) {
213 if (nonce_length != 12 || operation.tag_length != 16) {
Ronald Cron46f91782021-03-17 08:16:34 +0100214 status = PSA_ERROR_NOT_SUPPORTED;
215 goto exit;
216 }
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200217 status = mbedtls_to_psa_error(mbedtls_chachapoly_encrypt_and_tag(
218 &operation.ctx.chachapoly, plaintext_length, nonce, additional_data,
219 additional_data_length, plaintext, ciphertext, tag));
220 } else
221# endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
Ronald Cron46f91782021-03-17 08:16:34 +0100222 {
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200223 (void)tag;
224 return PSA_ERROR_NOT_SUPPORTED;
Ronald Cron46f91782021-03-17 08:16:34 +0100225 }
226
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200227 if (status == PSA_SUCCESS)
Ronald Cron46f91782021-03-17 08:16:34 +0100228 *ciphertext_length = plaintext_length + operation.tag_length;
229
230exit:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200231 psa_aead_abort_internal(&operation);
Ronald Cron46f91782021-03-17 08:16:34 +0100232
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200233 return status;
Ronald Cron46f91782021-03-17 08:16:34 +0100234}
235
236/* Locate the tag in a ciphertext buffer containing the encrypted data
237 * followed by the tag. Return the length of the part preceding the tag in
238 * *plaintext_length. This is the size of the plaintext in modes where
239 * the encrypted data has the same size as the plaintext, such as
240 * CCM and GCM. */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200241static psa_status_t psa_aead_unpadded_locate_tag(size_t tag_length,
242 const uint8_t *ciphertext,
243 size_t ciphertext_length,
244 size_t plaintext_size,
245 const uint8_t **p_tag)
Ronald Cron46f91782021-03-17 08:16:34 +0100246{
247 size_t payload_length;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200248 if (tag_length > ciphertext_length)
249 return PSA_ERROR_INVALID_ARGUMENT;
Ronald Cron46f91782021-03-17 08:16:34 +0100250 payload_length = ciphertext_length - tag_length;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200251 if (payload_length > plaintext_size)
252 return PSA_ERROR_BUFFER_TOO_SMALL;
Ronald Cron46f91782021-03-17 08:16:34 +0100253 *p_tag = ciphertext + payload_length;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200254 return PSA_SUCCESS;
Ronald Cron46f91782021-03-17 08:16:34 +0100255}
256
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200257psa_status_t mbedtls_psa_aead_decrypt(const psa_key_attributes_t *attributes,
258 const uint8_t *key_buffer,
259 size_t key_buffer_size,
260 psa_algorithm_t alg,
261 const uint8_t *nonce,
262 size_t nonce_length,
263 const uint8_t *additional_data,
264 size_t additional_data_length,
265 const uint8_t *ciphertext,
266 size_t ciphertext_length,
267 uint8_t *plaintext,
268 size_t plaintext_size,
269 size_t *plaintext_length)
Ronald Cron46f91782021-03-17 08:16:34 +0100270{
271 psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
272 aead_operation_t operation = AEAD_OPERATION_INIT;
273 const uint8_t *tag = NULL;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200274 (void)key_buffer_size;
Ronald Cron46f91782021-03-17 08:16:34 +0100275
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200276 status = psa_aead_setup(&operation, attributes, key_buffer, alg);
277 if (status != PSA_SUCCESS)
Ronald Cron46f91782021-03-17 08:16:34 +0100278 goto exit;
279
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200280 status = psa_aead_unpadded_locate_tag(operation.tag_length, ciphertext,
281 ciphertext_length, plaintext_size,
282 &tag);
283 if (status != PSA_SUCCESS)
Ronald Cron46f91782021-03-17 08:16:34 +0100284 goto exit;
285
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200286# if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
287 if (operation.core_alg == PSA_ALG_CCM) {
288 status = mbedtls_to_psa_error(mbedtls_ccm_auth_decrypt(
289 &operation.ctx.ccm, ciphertext_length - operation.tag_length, nonce,
290 nonce_length, additional_data, additional_data_length, ciphertext,
291 plaintext, tag, operation.tag_length));
292 } else
293# endif /* MBEDTLS_PSA_BUILTIN_ALG_CCM */
294# if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
295 if (operation.core_alg == PSA_ALG_GCM) {
296 status = mbedtls_to_psa_error(mbedtls_gcm_auth_decrypt(
297 &operation.ctx.gcm, ciphertext_length - operation.tag_length, nonce,
298 nonce_length, additional_data, additional_data_length, tag,
299 operation.tag_length, ciphertext, plaintext));
300 } else
301# endif /* MBEDTLS_PSA_BUILTIN_ALG_GCM */
302# if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
303 if (operation.core_alg == PSA_ALG_CHACHA20_POLY1305) {
304 if (nonce_length != 12 || operation.tag_length != 16) {
Ronald Cron46f91782021-03-17 08:16:34 +0100305 status = PSA_ERROR_NOT_SUPPORTED;
306 goto exit;
307 }
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200308 status = mbedtls_to_psa_error(mbedtls_chachapoly_auth_decrypt(
309 &operation.ctx.chachapoly, ciphertext_length - operation.tag_length,
310 nonce, additional_data, additional_data_length, tag, ciphertext,
311 plaintext));
312 } else
313# endif /* MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305 */
Ronald Cron46f91782021-03-17 08:16:34 +0100314 {
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200315 return PSA_ERROR_NOT_SUPPORTED;
Ronald Cron46f91782021-03-17 08:16:34 +0100316 }
317
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200318 if (status == PSA_SUCCESS)
Ronald Cron46f91782021-03-17 08:16:34 +0100319 *plaintext_length = ciphertext_length - operation.tag_length;
320
321exit:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200322 psa_aead_abort_internal(&operation);
Ronald Cron46f91782021-03-17 08:16:34 +0100323
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200324 if (status == PSA_SUCCESS)
Ronald Cron46f91782021-03-17 08:16:34 +0100325 *plaintext_length = ciphertext_length - operation.tag_length;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200326 return status;
Ronald Cron46f91782021-03-17 08:16:34 +0100327}
Ronald Cron7ceee8d2021-03-17 16:55:43 +0100328
329#endif /* MBEDTLS_PSA_CRYPTO_C */