1a8e1175bSopenharmony_ci/*
2a8e1175bSopenharmony_ci *  PSA ECP layer on top of Mbed TLS crypto
3a8e1175bSopenharmony_ci */
4a8e1175bSopenharmony_ci/*
5a8e1175bSopenharmony_ci *  Copyright The Mbed TLS Contributors
6a8e1175bSopenharmony_ci *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
7a8e1175bSopenharmony_ci */
8a8e1175bSopenharmony_ci
9a8e1175bSopenharmony_ci#include "common.h"
10a8e1175bSopenharmony_ci
11a8e1175bSopenharmony_ci#if defined(MBEDTLS_PSA_CRYPTO_C)
12a8e1175bSopenharmony_ci
13a8e1175bSopenharmony_ci#include <psa/crypto.h>
14a8e1175bSopenharmony_ci#include "psa_crypto_core.h"
15a8e1175bSopenharmony_ci#include "psa_crypto_ecp.h"
16a8e1175bSopenharmony_ci#include "psa_crypto_random_impl.h"
17a8e1175bSopenharmony_ci#include "mbedtls/psa_util.h"
18a8e1175bSopenharmony_ci
19a8e1175bSopenharmony_ci#include <stdlib.h>
20a8e1175bSopenharmony_ci#include <string.h>
21a8e1175bSopenharmony_ci#include "mbedtls/platform.h"
22a8e1175bSopenharmony_ci
23a8e1175bSopenharmony_ci#include <mbedtls/ecdsa.h>
24a8e1175bSopenharmony_ci#include <mbedtls/ecdh.h>
25a8e1175bSopenharmony_ci#include <mbedtls/ecp.h>
26a8e1175bSopenharmony_ci#include <mbedtls/error.h>
27a8e1175bSopenharmony_ci
28a8e1175bSopenharmony_ci#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_BASIC) || \
29a8e1175bSopenharmony_ci    defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_IMPORT) || \
30a8e1175bSopenharmony_ci    defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_EXPORT) || \
31a8e1175bSopenharmony_ci    defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY) || \
32a8e1175bSopenharmony_ci    defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \
33a8e1175bSopenharmony_ci    defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) || \
34a8e1175bSopenharmony_ci    defined(MBEDTLS_PSA_BUILTIN_ALG_ECDH)
35a8e1175bSopenharmony_ci/* Helper function to verify if the provided EC's family and key bit size are valid.
36a8e1175bSopenharmony_ci *
37a8e1175bSopenharmony_ci * Note: "bits" parameter is used both as input and output and it might be updated
38a8e1175bSopenharmony_ci *       in case provided input value is not multiple of 8 ("sloppy" bits).
39a8e1175bSopenharmony_ci */
40a8e1175bSopenharmony_cistatic int check_ecc_parameters(psa_ecc_family_t family, size_t *bits)
41a8e1175bSopenharmony_ci{
42a8e1175bSopenharmony_ci    switch (family) {
43a8e1175bSopenharmony_ci        case PSA_ECC_FAMILY_SECP_R1:
44a8e1175bSopenharmony_ci            switch (*bits) {
45a8e1175bSopenharmony_ci                case 192:
46a8e1175bSopenharmony_ci                case 224:
47a8e1175bSopenharmony_ci                case 256:
48a8e1175bSopenharmony_ci                case 384:
49a8e1175bSopenharmony_ci                case 521:
50a8e1175bSopenharmony_ci                    return PSA_SUCCESS;
51a8e1175bSopenharmony_ci                case 528:
52a8e1175bSopenharmony_ci                    *bits = 521;
53a8e1175bSopenharmony_ci                    return PSA_SUCCESS;
54a8e1175bSopenharmony_ci            }
55a8e1175bSopenharmony_ci            break;
56a8e1175bSopenharmony_ci
57a8e1175bSopenharmony_ci        case PSA_ECC_FAMILY_BRAINPOOL_P_R1:
58a8e1175bSopenharmony_ci            switch (*bits) {
59a8e1175bSopenharmony_ci                case 256:
60a8e1175bSopenharmony_ci                case 384:
61a8e1175bSopenharmony_ci                case 512:
62a8e1175bSopenharmony_ci                    return PSA_SUCCESS;
63a8e1175bSopenharmony_ci            }
64a8e1175bSopenharmony_ci            break;
65a8e1175bSopenharmony_ci
66a8e1175bSopenharmony_ci        case PSA_ECC_FAMILY_MONTGOMERY:
67a8e1175bSopenharmony_ci            switch (*bits) {
68a8e1175bSopenharmony_ci                case 448:
69a8e1175bSopenharmony_ci                case 255:
70a8e1175bSopenharmony_ci                    return PSA_SUCCESS;
71a8e1175bSopenharmony_ci                case 256:
72a8e1175bSopenharmony_ci                    *bits = 255;
73a8e1175bSopenharmony_ci                    return PSA_SUCCESS;
74a8e1175bSopenharmony_ci            }
75a8e1175bSopenharmony_ci            break;
76a8e1175bSopenharmony_ci
77a8e1175bSopenharmony_ci        case PSA_ECC_FAMILY_SECP_K1:
78a8e1175bSopenharmony_ci            switch (*bits) {
79a8e1175bSopenharmony_ci                case 192:
80a8e1175bSopenharmony_ci                /* secp224k1 is not and will not be supported in PSA (#3541). */
81a8e1175bSopenharmony_ci                case 256:
82a8e1175bSopenharmony_ci                    return PSA_SUCCESS;
83a8e1175bSopenharmony_ci            }
84a8e1175bSopenharmony_ci            break;
85a8e1175bSopenharmony_ci    }
86a8e1175bSopenharmony_ci
87a8e1175bSopenharmony_ci    return PSA_ERROR_INVALID_ARGUMENT;
88a8e1175bSopenharmony_ci}
89a8e1175bSopenharmony_ci
90a8e1175bSopenharmony_cipsa_status_t mbedtls_psa_ecp_load_representation(
91a8e1175bSopenharmony_ci    psa_key_type_t type, size_t curve_bits,
92a8e1175bSopenharmony_ci    const uint8_t *data, size_t data_length,
93a8e1175bSopenharmony_ci    mbedtls_ecp_keypair **p_ecp)
94a8e1175bSopenharmony_ci{
95a8e1175bSopenharmony_ci    mbedtls_ecp_group_id grp_id = MBEDTLS_ECP_DP_NONE;
96a8e1175bSopenharmony_ci    psa_status_t status;
97a8e1175bSopenharmony_ci    mbedtls_ecp_keypair *ecp = NULL;
98a8e1175bSopenharmony_ci    size_t curve_bytes = data_length;
99a8e1175bSopenharmony_ci    int explicit_bits = (curve_bits != 0);
100a8e1175bSopenharmony_ci
101a8e1175bSopenharmony_ci    if (PSA_KEY_TYPE_IS_PUBLIC_KEY(type) &&
102a8e1175bSopenharmony_ci        PSA_KEY_TYPE_ECC_GET_FAMILY(type) != PSA_ECC_FAMILY_MONTGOMERY) {
103a8e1175bSopenharmony_ci        /* A Weierstrass public key is represented as:
104a8e1175bSopenharmony_ci         * - The byte 0x04;
105a8e1175bSopenharmony_ci         * - `x_P` as a `ceiling(m/8)`-byte string, big-endian;
106a8e1175bSopenharmony_ci         * - `y_P` as a `ceiling(m/8)`-byte string, big-endian.
107a8e1175bSopenharmony_ci         * So its data length is 2m+1 where m is the curve size in bits.
108a8e1175bSopenharmony_ci         */
109a8e1175bSopenharmony_ci        if ((data_length & 1) == 0) {
110a8e1175bSopenharmony_ci            return PSA_ERROR_INVALID_ARGUMENT;
111a8e1175bSopenharmony_ci        }
112a8e1175bSopenharmony_ci        curve_bytes = data_length / 2;
113a8e1175bSopenharmony_ci
114a8e1175bSopenharmony_ci        /* Montgomery public keys are represented in compressed format, meaning
115a8e1175bSopenharmony_ci         * their curve_bytes is equal to the amount of input. */
116a8e1175bSopenharmony_ci
117a8e1175bSopenharmony_ci        /* Private keys are represented in uncompressed private random integer
118a8e1175bSopenharmony_ci         * format, meaning their curve_bytes is equal to the amount of input. */
119a8e1175bSopenharmony_ci    }
120a8e1175bSopenharmony_ci
121a8e1175bSopenharmony_ci    if (explicit_bits) {
122a8e1175bSopenharmony_ci        /* With an explicit bit-size, the data must have the matching length. */
123a8e1175bSopenharmony_ci        if (curve_bytes != PSA_BITS_TO_BYTES(curve_bits)) {
124a8e1175bSopenharmony_ci            return PSA_ERROR_INVALID_ARGUMENT;
125a8e1175bSopenharmony_ci        }
126a8e1175bSopenharmony_ci    } else {
127a8e1175bSopenharmony_ci        /* We need to infer the bit-size from the data. Since the only
128a8e1175bSopenharmony_ci         * information we have is the length in bytes, the value of curve_bits
129a8e1175bSopenharmony_ci         * at this stage is rounded up to the nearest multiple of 8. */
130a8e1175bSopenharmony_ci        curve_bits = PSA_BYTES_TO_BITS(curve_bytes);
131a8e1175bSopenharmony_ci    }
132a8e1175bSopenharmony_ci
133a8e1175bSopenharmony_ci    /* Allocate and initialize a key representation. */
134a8e1175bSopenharmony_ci    ecp = mbedtls_calloc(1, sizeof(mbedtls_ecp_keypair));
135a8e1175bSopenharmony_ci    if (ecp == NULL) {
136a8e1175bSopenharmony_ci        return PSA_ERROR_INSUFFICIENT_MEMORY;
137a8e1175bSopenharmony_ci    }
138a8e1175bSopenharmony_ci    mbedtls_ecp_keypair_init(ecp);
139a8e1175bSopenharmony_ci
140a8e1175bSopenharmony_ci    status = check_ecc_parameters(PSA_KEY_TYPE_ECC_GET_FAMILY(type), &curve_bits);
141a8e1175bSopenharmony_ci    if (status != PSA_SUCCESS) {
142a8e1175bSopenharmony_ci        goto exit;
143a8e1175bSopenharmony_ci    }
144a8e1175bSopenharmony_ci
145a8e1175bSopenharmony_ci    /* Load the group. */
146a8e1175bSopenharmony_ci    grp_id = mbedtls_ecc_group_from_psa(PSA_KEY_TYPE_ECC_GET_FAMILY(type),
147a8e1175bSopenharmony_ci                                        curve_bits);
148a8e1175bSopenharmony_ci    if (grp_id == MBEDTLS_ECP_DP_NONE) {
149a8e1175bSopenharmony_ci        status = PSA_ERROR_NOT_SUPPORTED;
150a8e1175bSopenharmony_ci        goto exit;
151a8e1175bSopenharmony_ci    }
152a8e1175bSopenharmony_ci
153a8e1175bSopenharmony_ci    status = mbedtls_to_psa_error(
154a8e1175bSopenharmony_ci        mbedtls_ecp_group_load(&ecp->grp, grp_id));
155a8e1175bSopenharmony_ci    if (status != PSA_SUCCESS) {
156a8e1175bSopenharmony_ci        goto exit;
157a8e1175bSopenharmony_ci    }
158a8e1175bSopenharmony_ci
159a8e1175bSopenharmony_ci    /* Load the key material. */
160a8e1175bSopenharmony_ci    if (PSA_KEY_TYPE_IS_PUBLIC_KEY(type)) {
161a8e1175bSopenharmony_ci        /* Load the public value. */
162a8e1175bSopenharmony_ci        status = mbedtls_to_psa_error(
163a8e1175bSopenharmony_ci            mbedtls_ecp_point_read_binary(&ecp->grp, &ecp->Q,
164a8e1175bSopenharmony_ci                                          data,
165a8e1175bSopenharmony_ci                                          data_length));
166a8e1175bSopenharmony_ci        if (status != PSA_SUCCESS) {
167a8e1175bSopenharmony_ci            goto exit;
168a8e1175bSopenharmony_ci        }
169a8e1175bSopenharmony_ci
170a8e1175bSopenharmony_ci        /* Check that the point is on the curve. */
171a8e1175bSopenharmony_ci        status = mbedtls_to_psa_error(
172a8e1175bSopenharmony_ci            mbedtls_ecp_check_pubkey(&ecp->grp, &ecp->Q));
173a8e1175bSopenharmony_ci        if (status != PSA_SUCCESS) {
174a8e1175bSopenharmony_ci            goto exit;
175a8e1175bSopenharmony_ci        }
176a8e1175bSopenharmony_ci    } else {
177a8e1175bSopenharmony_ci        /* Load and validate the secret value. */
178a8e1175bSopenharmony_ci        status = mbedtls_to_psa_error(
179a8e1175bSopenharmony_ci            mbedtls_ecp_read_key(ecp->grp.id,
180a8e1175bSopenharmony_ci                                 ecp,
181a8e1175bSopenharmony_ci                                 data,
182a8e1175bSopenharmony_ci                                 data_length));
183a8e1175bSopenharmony_ci        if (status != PSA_SUCCESS) {
184a8e1175bSopenharmony_ci            goto exit;
185a8e1175bSopenharmony_ci        }
186a8e1175bSopenharmony_ci    }
187a8e1175bSopenharmony_ci
188a8e1175bSopenharmony_ci    *p_ecp = ecp;
189a8e1175bSopenharmony_ciexit:
190a8e1175bSopenharmony_ci    if (status != PSA_SUCCESS) {
191a8e1175bSopenharmony_ci        mbedtls_ecp_keypair_free(ecp);
192a8e1175bSopenharmony_ci        mbedtls_free(ecp);
193a8e1175bSopenharmony_ci    }
194a8e1175bSopenharmony_ci
195a8e1175bSopenharmony_ci    return status;
196a8e1175bSopenharmony_ci}
197a8e1175bSopenharmony_ci#endif /* defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_BASIC) ||
198a8e1175bSopenharmony_ci        * defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_IMPORT) ||
199a8e1175bSopenharmony_ci        * defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_EXPORT) ||
200a8e1175bSopenharmony_ci        * defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY) ||
201a8e1175bSopenharmony_ci        * defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) ||
202a8e1175bSopenharmony_ci        * defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) ||
203a8e1175bSopenharmony_ci        * defined(MBEDTLS_PSA_BUILTIN_ALG_ECDH) */
204a8e1175bSopenharmony_ci
205a8e1175bSopenharmony_ci#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_IMPORT) || \
206a8e1175bSopenharmony_ci    defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_EXPORT) || \
207a8e1175bSopenharmony_ci    defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY)
208a8e1175bSopenharmony_ci
209a8e1175bSopenharmony_cipsa_status_t mbedtls_psa_ecp_import_key(
210a8e1175bSopenharmony_ci    const psa_key_attributes_t *attributes,
211a8e1175bSopenharmony_ci    const uint8_t *data, size_t data_length,
212a8e1175bSopenharmony_ci    uint8_t *key_buffer, size_t key_buffer_size,
213a8e1175bSopenharmony_ci    size_t *key_buffer_length, size_t *bits)
214a8e1175bSopenharmony_ci{
215a8e1175bSopenharmony_ci    psa_status_t status;
216a8e1175bSopenharmony_ci    mbedtls_ecp_keypair *ecp = NULL;
217a8e1175bSopenharmony_ci
218a8e1175bSopenharmony_ci    /* Parse input */
219a8e1175bSopenharmony_ci    status = mbedtls_psa_ecp_load_representation(attributes->type,
220a8e1175bSopenharmony_ci                                                 attributes->bits,
221a8e1175bSopenharmony_ci                                                 data,
222a8e1175bSopenharmony_ci                                                 data_length,
223a8e1175bSopenharmony_ci                                                 &ecp);
224a8e1175bSopenharmony_ci    if (status != PSA_SUCCESS) {
225a8e1175bSopenharmony_ci        goto exit;
226a8e1175bSopenharmony_ci    }
227a8e1175bSopenharmony_ci
228a8e1175bSopenharmony_ci    if (PSA_KEY_TYPE_ECC_GET_FAMILY(attributes->type) ==
229a8e1175bSopenharmony_ci        PSA_ECC_FAMILY_MONTGOMERY) {
230a8e1175bSopenharmony_ci        *bits = ecp->grp.nbits + 1;
231a8e1175bSopenharmony_ci    } else {
232a8e1175bSopenharmony_ci        *bits = ecp->grp.nbits;
233a8e1175bSopenharmony_ci    }
234a8e1175bSopenharmony_ci
235a8e1175bSopenharmony_ci    /* Re-export the data to PSA export format. There is currently no support
236a8e1175bSopenharmony_ci     * for other input formats then the export format, so this is a 1-1
237a8e1175bSopenharmony_ci     * copy operation. */
238a8e1175bSopenharmony_ci    status = mbedtls_psa_ecp_export_key(attributes->type,
239a8e1175bSopenharmony_ci                                        ecp,
240a8e1175bSopenharmony_ci                                        key_buffer,
241a8e1175bSopenharmony_ci                                        key_buffer_size,
242a8e1175bSopenharmony_ci                                        key_buffer_length);
243a8e1175bSopenharmony_ciexit:
244a8e1175bSopenharmony_ci    /* Always free the PK object (will also free contained ECP context) */
245a8e1175bSopenharmony_ci    mbedtls_ecp_keypair_free(ecp);
246a8e1175bSopenharmony_ci    mbedtls_free(ecp);
247a8e1175bSopenharmony_ci
248a8e1175bSopenharmony_ci    return status;
249a8e1175bSopenharmony_ci}
250a8e1175bSopenharmony_ci
251a8e1175bSopenharmony_cipsa_status_t mbedtls_psa_ecp_export_key(psa_key_type_t type,
252a8e1175bSopenharmony_ci                                        mbedtls_ecp_keypair *ecp,
253a8e1175bSopenharmony_ci                                        uint8_t *data,
254a8e1175bSopenharmony_ci                                        size_t data_size,
255a8e1175bSopenharmony_ci                                        size_t *data_length)
256a8e1175bSopenharmony_ci{
257a8e1175bSopenharmony_ci    psa_status_t status;
258a8e1175bSopenharmony_ci
259a8e1175bSopenharmony_ci    if (PSA_KEY_TYPE_IS_PUBLIC_KEY(type)) {
260a8e1175bSopenharmony_ci        /* Check whether the public part is loaded */
261a8e1175bSopenharmony_ci        if (mbedtls_ecp_is_zero(&ecp->Q)) {
262a8e1175bSopenharmony_ci            /* Calculate the public key */
263a8e1175bSopenharmony_ci            status = mbedtls_to_psa_error(
264a8e1175bSopenharmony_ci                mbedtls_ecp_mul(&ecp->grp, &ecp->Q, &ecp->d, &ecp->grp.G,
265a8e1175bSopenharmony_ci                                mbedtls_psa_get_random,
266a8e1175bSopenharmony_ci                                MBEDTLS_PSA_RANDOM_STATE));
267a8e1175bSopenharmony_ci            if (status != PSA_SUCCESS) {
268a8e1175bSopenharmony_ci                return status;
269a8e1175bSopenharmony_ci            }
270a8e1175bSopenharmony_ci        }
271a8e1175bSopenharmony_ci
272a8e1175bSopenharmony_ci        status = mbedtls_to_psa_error(
273a8e1175bSopenharmony_ci            mbedtls_ecp_point_write_binary(&ecp->grp, &ecp->Q,
274a8e1175bSopenharmony_ci                                           MBEDTLS_ECP_PF_UNCOMPRESSED,
275a8e1175bSopenharmony_ci                                           data_length,
276a8e1175bSopenharmony_ci                                           data,
277a8e1175bSopenharmony_ci                                           data_size));
278a8e1175bSopenharmony_ci        if (status != PSA_SUCCESS) {
279a8e1175bSopenharmony_ci            memset(data, 0, data_size);
280a8e1175bSopenharmony_ci        }
281a8e1175bSopenharmony_ci
282a8e1175bSopenharmony_ci        return status;
283a8e1175bSopenharmony_ci    } else {
284a8e1175bSopenharmony_ci        status = mbedtls_to_psa_error(
285a8e1175bSopenharmony_ci            mbedtls_ecp_write_key_ext(ecp, data_length, data, data_size));
286a8e1175bSopenharmony_ci        return status;
287a8e1175bSopenharmony_ci    }
288a8e1175bSopenharmony_ci}
289a8e1175bSopenharmony_ci
290a8e1175bSopenharmony_cipsa_status_t mbedtls_psa_ecp_export_public_key(
291a8e1175bSopenharmony_ci    const psa_key_attributes_t *attributes,
292a8e1175bSopenharmony_ci    const uint8_t *key_buffer, size_t key_buffer_size,
293a8e1175bSopenharmony_ci    uint8_t *data, size_t data_size, size_t *data_length)
294a8e1175bSopenharmony_ci{
295a8e1175bSopenharmony_ci    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
296a8e1175bSopenharmony_ci    mbedtls_ecp_keypair *ecp = NULL;
297a8e1175bSopenharmony_ci
298a8e1175bSopenharmony_ci    status = mbedtls_psa_ecp_load_representation(
299a8e1175bSopenharmony_ci        attributes->type, attributes->bits,
300a8e1175bSopenharmony_ci        key_buffer, key_buffer_size, &ecp);
301a8e1175bSopenharmony_ci    if (status != PSA_SUCCESS) {
302a8e1175bSopenharmony_ci        return status;
303a8e1175bSopenharmony_ci    }
304a8e1175bSopenharmony_ci
305a8e1175bSopenharmony_ci    status = mbedtls_psa_ecp_export_key(
306a8e1175bSopenharmony_ci        PSA_KEY_TYPE_ECC_PUBLIC_KEY(
307a8e1175bSopenharmony_ci            PSA_KEY_TYPE_ECC_GET_FAMILY(attributes->type)),
308a8e1175bSopenharmony_ci        ecp, data, data_size, data_length);
309a8e1175bSopenharmony_ci
310a8e1175bSopenharmony_ci    mbedtls_ecp_keypair_free(ecp);
311a8e1175bSopenharmony_ci    mbedtls_free(ecp);
312a8e1175bSopenharmony_ci
313a8e1175bSopenharmony_ci    return status;
314a8e1175bSopenharmony_ci}
315a8e1175bSopenharmony_ci#endif /* defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_IMPORT) ||
316a8e1175bSopenharmony_ci        * defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_EXPORT) ||
317a8e1175bSopenharmony_ci        * defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_PUBLIC_KEY) */
318a8e1175bSopenharmony_ci
319a8e1175bSopenharmony_ci#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_GENERATE)
320a8e1175bSopenharmony_cipsa_status_t mbedtls_psa_ecp_generate_key(
321a8e1175bSopenharmony_ci    const psa_key_attributes_t *attributes,
322a8e1175bSopenharmony_ci    uint8_t *key_buffer, size_t key_buffer_size, size_t *key_buffer_length)
323a8e1175bSopenharmony_ci{
324a8e1175bSopenharmony_ci    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
325a8e1175bSopenharmony_ci    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
326a8e1175bSopenharmony_ci
327a8e1175bSopenharmony_ci    psa_ecc_family_t curve = PSA_KEY_TYPE_ECC_GET_FAMILY(
328a8e1175bSopenharmony_ci        attributes->type);
329a8e1175bSopenharmony_ci    mbedtls_ecp_group_id grp_id =
330a8e1175bSopenharmony_ci        mbedtls_ecc_group_from_psa(curve, attributes->bits);
331a8e1175bSopenharmony_ci
332a8e1175bSopenharmony_ci    const mbedtls_ecp_curve_info *curve_info =
333a8e1175bSopenharmony_ci        mbedtls_ecp_curve_info_from_grp_id(grp_id);
334a8e1175bSopenharmony_ci    mbedtls_ecp_keypair ecp;
335a8e1175bSopenharmony_ci
336a8e1175bSopenharmony_ci    if (grp_id == MBEDTLS_ECP_DP_NONE || curve_info == NULL) {
337a8e1175bSopenharmony_ci        return PSA_ERROR_NOT_SUPPORTED;
338a8e1175bSopenharmony_ci    }
339a8e1175bSopenharmony_ci
340a8e1175bSopenharmony_ci    mbedtls_ecp_keypair_init(&ecp);
341a8e1175bSopenharmony_ci    ret = mbedtls_ecp_gen_key(grp_id, &ecp,
342a8e1175bSopenharmony_ci                              mbedtls_psa_get_random,
343a8e1175bSopenharmony_ci                              MBEDTLS_PSA_RANDOM_STATE);
344a8e1175bSopenharmony_ci    if (ret != 0) {
345a8e1175bSopenharmony_ci        mbedtls_ecp_keypair_free(&ecp);
346a8e1175bSopenharmony_ci        return mbedtls_to_psa_error(ret);
347a8e1175bSopenharmony_ci    }
348a8e1175bSopenharmony_ci
349a8e1175bSopenharmony_ci    status = mbedtls_to_psa_error(
350a8e1175bSopenharmony_ci        mbedtls_ecp_write_key_ext(&ecp, key_buffer_length,
351a8e1175bSopenharmony_ci                                  key_buffer, key_buffer_size));
352a8e1175bSopenharmony_ci
353a8e1175bSopenharmony_ci    mbedtls_ecp_keypair_free(&ecp);
354a8e1175bSopenharmony_ci
355a8e1175bSopenharmony_ci    return status;
356a8e1175bSopenharmony_ci}
357a8e1175bSopenharmony_ci#endif /* MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR_GENERATE */
358a8e1175bSopenharmony_ci
359a8e1175bSopenharmony_ci/****************************************************************/
360a8e1175bSopenharmony_ci/* ECDSA sign/verify */
361a8e1175bSopenharmony_ci/****************************************************************/
362a8e1175bSopenharmony_ci
363a8e1175bSopenharmony_ci#if defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \
364a8e1175bSopenharmony_ci    defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA)
365a8e1175bSopenharmony_cipsa_status_t mbedtls_psa_ecdsa_sign_hash(
366a8e1175bSopenharmony_ci    const psa_key_attributes_t *attributes,
367a8e1175bSopenharmony_ci    const uint8_t *key_buffer, size_t key_buffer_size,
368a8e1175bSopenharmony_ci    psa_algorithm_t alg, const uint8_t *hash, size_t hash_length,
369a8e1175bSopenharmony_ci    uint8_t *signature, size_t signature_size, size_t *signature_length)
370a8e1175bSopenharmony_ci{
371a8e1175bSopenharmony_ci    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
372a8e1175bSopenharmony_ci    mbedtls_ecp_keypair *ecp = NULL;
373a8e1175bSopenharmony_ci    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
374a8e1175bSopenharmony_ci    size_t curve_bytes;
375a8e1175bSopenharmony_ci    mbedtls_mpi r, s;
376a8e1175bSopenharmony_ci
377a8e1175bSopenharmony_ci    status = mbedtls_psa_ecp_load_representation(attributes->type,
378a8e1175bSopenharmony_ci                                                 attributes->bits,
379a8e1175bSopenharmony_ci                                                 key_buffer,
380a8e1175bSopenharmony_ci                                                 key_buffer_size,
381a8e1175bSopenharmony_ci                                                 &ecp);
382a8e1175bSopenharmony_ci    if (status != PSA_SUCCESS) {
383a8e1175bSopenharmony_ci        return status;
384a8e1175bSopenharmony_ci    }
385a8e1175bSopenharmony_ci
386a8e1175bSopenharmony_ci    curve_bytes = PSA_BITS_TO_BYTES(ecp->grp.pbits);
387a8e1175bSopenharmony_ci    mbedtls_mpi_init(&r);
388a8e1175bSopenharmony_ci    mbedtls_mpi_init(&s);
389a8e1175bSopenharmony_ci
390a8e1175bSopenharmony_ci    if (signature_size < 2 * curve_bytes) {
391a8e1175bSopenharmony_ci        ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
392a8e1175bSopenharmony_ci        goto cleanup;
393a8e1175bSopenharmony_ci    }
394a8e1175bSopenharmony_ci
395a8e1175bSopenharmony_ci    if (PSA_ALG_ECDSA_IS_DETERMINISTIC(alg)) {
396a8e1175bSopenharmony_ci#if defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA)
397a8e1175bSopenharmony_ci        psa_algorithm_t hash_alg = PSA_ALG_SIGN_GET_HASH(alg);
398a8e1175bSopenharmony_ci        mbedtls_md_type_t md_alg = mbedtls_md_type_from_psa_alg(hash_alg);
399a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mbedtls_ecdsa_sign_det_ext(
400a8e1175bSopenharmony_ci                            &ecp->grp, &r, &s,
401a8e1175bSopenharmony_ci                            &ecp->d, hash,
402a8e1175bSopenharmony_ci                            hash_length, md_alg,
403a8e1175bSopenharmony_ci                            mbedtls_psa_get_random,
404a8e1175bSopenharmony_ci                            MBEDTLS_PSA_RANDOM_STATE));
405a8e1175bSopenharmony_ci#else
406a8e1175bSopenharmony_ci        ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
407a8e1175bSopenharmony_ci        goto cleanup;
408a8e1175bSopenharmony_ci#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) */
409a8e1175bSopenharmony_ci    } else {
410a8e1175bSopenharmony_ci        (void) alg;
411a8e1175bSopenharmony_ci        MBEDTLS_MPI_CHK(mbedtls_ecdsa_sign(&ecp->grp, &r, &s, &ecp->d,
412a8e1175bSopenharmony_ci                                           hash, hash_length,
413a8e1175bSopenharmony_ci                                           mbedtls_psa_get_random,
414a8e1175bSopenharmony_ci                                           MBEDTLS_PSA_RANDOM_STATE));
415a8e1175bSopenharmony_ci    }
416a8e1175bSopenharmony_ci
417a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&r,
418a8e1175bSopenharmony_ci                                             signature,
419a8e1175bSopenharmony_ci                                             curve_bytes));
420a8e1175bSopenharmony_ci    MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&s,
421a8e1175bSopenharmony_ci                                             signature + curve_bytes,
422a8e1175bSopenharmony_ci                                             curve_bytes));
423a8e1175bSopenharmony_cicleanup:
424a8e1175bSopenharmony_ci    mbedtls_mpi_free(&r);
425a8e1175bSopenharmony_ci    mbedtls_mpi_free(&s);
426a8e1175bSopenharmony_ci    if (ret == 0) {
427a8e1175bSopenharmony_ci        *signature_length = 2 * curve_bytes;
428a8e1175bSopenharmony_ci    }
429a8e1175bSopenharmony_ci
430a8e1175bSopenharmony_ci    mbedtls_ecp_keypair_free(ecp);
431a8e1175bSopenharmony_ci    mbedtls_free(ecp);
432a8e1175bSopenharmony_ci
433a8e1175bSopenharmony_ci    return mbedtls_to_psa_error(ret);
434a8e1175bSopenharmony_ci}
435a8e1175bSopenharmony_ci
436a8e1175bSopenharmony_cipsa_status_t mbedtls_psa_ecp_load_public_part(mbedtls_ecp_keypair *ecp)
437a8e1175bSopenharmony_ci{
438a8e1175bSopenharmony_ci    int ret = 0;
439a8e1175bSopenharmony_ci
440a8e1175bSopenharmony_ci    /* Check whether the public part is loaded. If not, load it. */
441a8e1175bSopenharmony_ci    if (mbedtls_ecp_is_zero(&ecp->Q)) {
442a8e1175bSopenharmony_ci        ret = mbedtls_ecp_mul(&ecp->grp, &ecp->Q,
443a8e1175bSopenharmony_ci                              &ecp->d, &ecp->grp.G,
444a8e1175bSopenharmony_ci                              mbedtls_psa_get_random,
445a8e1175bSopenharmony_ci                              MBEDTLS_PSA_RANDOM_STATE);
446a8e1175bSopenharmony_ci    }
447a8e1175bSopenharmony_ci
448a8e1175bSopenharmony_ci    return mbedtls_to_psa_error(ret);
449a8e1175bSopenharmony_ci}
450a8e1175bSopenharmony_ci
451a8e1175bSopenharmony_cipsa_status_t mbedtls_psa_ecdsa_verify_hash(
452a8e1175bSopenharmony_ci    const psa_key_attributes_t *attributes,
453a8e1175bSopenharmony_ci    const uint8_t *key_buffer, size_t key_buffer_size,
454a8e1175bSopenharmony_ci    psa_algorithm_t alg, const uint8_t *hash, size_t hash_length,
455a8e1175bSopenharmony_ci    const uint8_t *signature, size_t signature_length)
456a8e1175bSopenharmony_ci{
457a8e1175bSopenharmony_ci    psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
458a8e1175bSopenharmony_ci    mbedtls_ecp_keypair *ecp = NULL;
459a8e1175bSopenharmony_ci    size_t curve_bytes;
460a8e1175bSopenharmony_ci    mbedtls_mpi r, s;
461a8e1175bSopenharmony_ci
462a8e1175bSopenharmony_ci    (void) alg;
463a8e1175bSopenharmony_ci
464a8e1175bSopenharmony_ci    status = mbedtls_psa_ecp_load_representation(attributes->type,
465a8e1175bSopenharmony_ci                                                 attributes->bits,
466a8e1175bSopenharmony_ci                                                 key_buffer,
467a8e1175bSopenharmony_ci                                                 key_buffer_size,
468a8e1175bSopenharmony_ci                                                 &ecp);
469a8e1175bSopenharmony_ci    if (status != PSA_SUCCESS) {
470a8e1175bSopenharmony_ci        return status;
471a8e1175bSopenharmony_ci    }
472a8e1175bSopenharmony_ci
473a8e1175bSopenharmony_ci    curve_bytes = PSA_BITS_TO_BYTES(ecp->grp.pbits);
474a8e1175bSopenharmony_ci    mbedtls_mpi_init(&r);
475a8e1175bSopenharmony_ci    mbedtls_mpi_init(&s);
476a8e1175bSopenharmony_ci
477a8e1175bSopenharmony_ci    if (signature_length != 2 * curve_bytes) {
478a8e1175bSopenharmony_ci        status = PSA_ERROR_INVALID_SIGNATURE;
479a8e1175bSopenharmony_ci        goto cleanup;
480a8e1175bSopenharmony_ci    }
481a8e1175bSopenharmony_ci
482a8e1175bSopenharmony_ci    status = mbedtls_to_psa_error(mbedtls_mpi_read_binary(&r,
483a8e1175bSopenharmony_ci                                                          signature,
484a8e1175bSopenharmony_ci                                                          curve_bytes));
485a8e1175bSopenharmony_ci    if (status != PSA_SUCCESS) {
486a8e1175bSopenharmony_ci        goto cleanup;
487a8e1175bSopenharmony_ci    }
488a8e1175bSopenharmony_ci
489a8e1175bSopenharmony_ci    status = mbedtls_to_psa_error(mbedtls_mpi_read_binary(&s,
490a8e1175bSopenharmony_ci                                                          signature + curve_bytes,
491a8e1175bSopenharmony_ci                                                          curve_bytes));
492a8e1175bSopenharmony_ci    if (status != PSA_SUCCESS) {
493a8e1175bSopenharmony_ci        goto cleanup;
494a8e1175bSopenharmony_ci    }
495a8e1175bSopenharmony_ci
496a8e1175bSopenharmony_ci    status = mbedtls_psa_ecp_load_public_part(ecp);
497a8e1175bSopenharmony_ci    if (status != PSA_SUCCESS) {
498a8e1175bSopenharmony_ci        goto cleanup;
499a8e1175bSopenharmony_ci    }
500a8e1175bSopenharmony_ci
501a8e1175bSopenharmony_ci    status = mbedtls_to_psa_error(mbedtls_ecdsa_verify(&ecp->grp, hash,
502a8e1175bSopenharmony_ci                                                       hash_length, &ecp->Q,
503a8e1175bSopenharmony_ci                                                       &r, &s));
504a8e1175bSopenharmony_cicleanup:
505a8e1175bSopenharmony_ci    mbedtls_mpi_free(&r);
506a8e1175bSopenharmony_ci    mbedtls_mpi_free(&s);
507a8e1175bSopenharmony_ci    mbedtls_ecp_keypair_free(ecp);
508a8e1175bSopenharmony_ci    mbedtls_free(ecp);
509a8e1175bSopenharmony_ci
510a8e1175bSopenharmony_ci    return status;
511a8e1175bSopenharmony_ci}
512a8e1175bSopenharmony_ci
513a8e1175bSopenharmony_ci#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_ECDSA) || \
514a8e1175bSopenharmony_ci        * defined(MBEDTLS_PSA_BUILTIN_ALG_DETERMINISTIC_ECDSA) */
515a8e1175bSopenharmony_ci
516a8e1175bSopenharmony_ci/****************************************************************/
517a8e1175bSopenharmony_ci/* ECDH Key Agreement */
518a8e1175bSopenharmony_ci/****************************************************************/
519a8e1175bSopenharmony_ci
520a8e1175bSopenharmony_ci#if defined(MBEDTLS_PSA_BUILTIN_ALG_ECDH)
521a8e1175bSopenharmony_cipsa_status_t mbedtls_psa_key_agreement_ecdh(
522a8e1175bSopenharmony_ci    const psa_key_attributes_t *attributes,
523a8e1175bSopenharmony_ci    const uint8_t *key_buffer, size_t key_buffer_size,
524a8e1175bSopenharmony_ci    psa_algorithm_t alg, const uint8_t *peer_key, size_t peer_key_length,
525a8e1175bSopenharmony_ci    uint8_t *shared_secret, size_t shared_secret_size,
526a8e1175bSopenharmony_ci    size_t *shared_secret_length)
527a8e1175bSopenharmony_ci{
528a8e1175bSopenharmony_ci    psa_status_t status;
529a8e1175bSopenharmony_ci    if (!PSA_KEY_TYPE_IS_ECC_KEY_PAIR(attributes->type) ||
530a8e1175bSopenharmony_ci        !PSA_ALG_IS_ECDH(alg)) {
531a8e1175bSopenharmony_ci        return PSA_ERROR_INVALID_ARGUMENT;
532a8e1175bSopenharmony_ci    }
533a8e1175bSopenharmony_ci    mbedtls_ecp_keypair *ecp = NULL;
534a8e1175bSopenharmony_ci    status = mbedtls_psa_ecp_load_representation(
535a8e1175bSopenharmony_ci        attributes->type,
536a8e1175bSopenharmony_ci        attributes->bits,
537a8e1175bSopenharmony_ci        key_buffer,
538a8e1175bSopenharmony_ci        key_buffer_size,
539a8e1175bSopenharmony_ci        &ecp);
540a8e1175bSopenharmony_ci    if (status != PSA_SUCCESS) {
541a8e1175bSopenharmony_ci        return status;
542a8e1175bSopenharmony_ci    }
543a8e1175bSopenharmony_ci    mbedtls_ecp_keypair *their_key = NULL;
544a8e1175bSopenharmony_ci    mbedtls_ecdh_context ecdh;
545a8e1175bSopenharmony_ci    size_t bits = 0;
546a8e1175bSopenharmony_ci    psa_ecc_family_t curve = mbedtls_ecc_group_to_psa(ecp->grp.id, &bits);
547a8e1175bSopenharmony_ci    mbedtls_ecdh_init(&ecdh);
548a8e1175bSopenharmony_ci
549a8e1175bSopenharmony_ci    status = mbedtls_psa_ecp_load_representation(
550a8e1175bSopenharmony_ci        PSA_KEY_TYPE_ECC_PUBLIC_KEY(curve),
551a8e1175bSopenharmony_ci        bits,
552a8e1175bSopenharmony_ci        peer_key,
553a8e1175bSopenharmony_ci        peer_key_length,
554a8e1175bSopenharmony_ci        &their_key);
555a8e1175bSopenharmony_ci    if (status != PSA_SUCCESS) {
556a8e1175bSopenharmony_ci        goto exit;
557a8e1175bSopenharmony_ci    }
558a8e1175bSopenharmony_ci
559a8e1175bSopenharmony_ci    status = mbedtls_to_psa_error(
560a8e1175bSopenharmony_ci        mbedtls_ecdh_get_params(&ecdh, their_key, MBEDTLS_ECDH_THEIRS));
561a8e1175bSopenharmony_ci    if (status != PSA_SUCCESS) {
562a8e1175bSopenharmony_ci        goto exit;
563a8e1175bSopenharmony_ci    }
564a8e1175bSopenharmony_ci    status = mbedtls_to_psa_error(
565a8e1175bSopenharmony_ci        mbedtls_ecdh_get_params(&ecdh, ecp, MBEDTLS_ECDH_OURS));
566a8e1175bSopenharmony_ci    if (status != PSA_SUCCESS) {
567a8e1175bSopenharmony_ci        goto exit;
568a8e1175bSopenharmony_ci    }
569a8e1175bSopenharmony_ci
570a8e1175bSopenharmony_ci    status = mbedtls_to_psa_error(
571a8e1175bSopenharmony_ci        mbedtls_ecdh_calc_secret(&ecdh,
572a8e1175bSopenharmony_ci                                 shared_secret_length,
573a8e1175bSopenharmony_ci                                 shared_secret, shared_secret_size,
574a8e1175bSopenharmony_ci                                 mbedtls_psa_get_random,
575a8e1175bSopenharmony_ci                                 MBEDTLS_PSA_RANDOM_STATE));
576a8e1175bSopenharmony_ci    if (status != PSA_SUCCESS) {
577a8e1175bSopenharmony_ci        goto exit;
578a8e1175bSopenharmony_ci    }
579a8e1175bSopenharmony_ci    if (PSA_BITS_TO_BYTES(bits) != *shared_secret_length) {
580a8e1175bSopenharmony_ci        status = PSA_ERROR_CORRUPTION_DETECTED;
581a8e1175bSopenharmony_ci    }
582a8e1175bSopenharmony_ciexit:
583a8e1175bSopenharmony_ci    if (status != PSA_SUCCESS) {
584a8e1175bSopenharmony_ci        mbedtls_platform_zeroize(shared_secret, shared_secret_size);
585a8e1175bSopenharmony_ci    }
586a8e1175bSopenharmony_ci    mbedtls_ecdh_free(&ecdh);
587a8e1175bSopenharmony_ci    mbedtls_ecp_keypair_free(their_key);
588a8e1175bSopenharmony_ci    mbedtls_free(their_key);
589a8e1175bSopenharmony_ci    mbedtls_ecp_keypair_free(ecp);
590a8e1175bSopenharmony_ci    mbedtls_free(ecp);
591a8e1175bSopenharmony_ci    return status;
592a8e1175bSopenharmony_ci}
593a8e1175bSopenharmony_ci#endif /* MBEDTLS_PSA_BUILTIN_ALG_ECDH */
594a8e1175bSopenharmony_ci
595a8e1175bSopenharmony_ci
596a8e1175bSopenharmony_ci#endif /* MBEDTLS_PSA_CRYPTO_C */
597