1a8e1175bSopenharmony_ci/*
2a8e1175bSopenharmony_ci *  Driver entry points for p256-m
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 "mbedtls/platform.h"
10a8e1175bSopenharmony_ci#include "p256-m_driver_entrypoints.h"
11a8e1175bSopenharmony_ci#include "p256-m/p256-m.h"
12a8e1175bSopenharmony_ci#include "psa/crypto.h"
13a8e1175bSopenharmony_ci#include <stddef.h>
14a8e1175bSopenharmony_ci#include <string.h>
15a8e1175bSopenharmony_ci#include "psa_crypto_driver_wrappers_no_static.h"
16a8e1175bSopenharmony_ci
17a8e1175bSopenharmony_ci#if defined(MBEDTLS_PSA_P256M_DRIVER_ENABLED)
18a8e1175bSopenharmony_ci
19a8e1175bSopenharmony_ci/* INFORMATION ON PSA KEY EXPORT FORMATS:
20a8e1175bSopenharmony_ci *
21a8e1175bSopenharmony_ci * PSA exports SECP256R1 keys in two formats:
22a8e1175bSopenharmony_ci * 1. Keypair format: 32 byte string which is just the private key (public key
23a8e1175bSopenharmony_ci *                    can be calculated from the private key)
24a8e1175bSopenharmony_ci * 2. Public Key format: A leading byte 0x04 (indicating uncompressed format),
25a8e1175bSopenharmony_ci *                       followed by the 64 byte public key. This results in a
26a8e1175bSopenharmony_ci *                       total of 65 bytes.
27a8e1175bSopenharmony_ci *
28a8e1175bSopenharmony_ci * p256-m's internal format for private keys matches PSA. Its format for public
29a8e1175bSopenharmony_ci * keys is only 64 bytes: the same as PSA but without the leading byte (0x04).
30a8e1175bSopenharmony_ci * Hence, when passing public keys from PSA to p256-m, the leading byte is
31a8e1175bSopenharmony_ci * removed.
32a8e1175bSopenharmony_ci *
33a8e1175bSopenharmony_ci * Shared secret and signature have the same format between PSA and p256-m.
34a8e1175bSopenharmony_ci */
35a8e1175bSopenharmony_ci#define PSA_PUBKEY_SIZE         65
36a8e1175bSopenharmony_ci#define PSA_PUBKEY_HEADER_BYTE  0x04
37a8e1175bSopenharmony_ci#define P256_PUBKEY_SIZE        64
38a8e1175bSopenharmony_ci#define PRIVKEY_SIZE            32
39a8e1175bSopenharmony_ci#define SHARED_SECRET_SIZE      32
40a8e1175bSopenharmony_ci#define SIGNATURE_SIZE          64
41a8e1175bSopenharmony_ci
42a8e1175bSopenharmony_ci#define CURVE_BITS              256
43a8e1175bSopenharmony_ci
44a8e1175bSopenharmony_ci/* Convert between p256-m and PSA error codes */
45a8e1175bSopenharmony_cistatic psa_status_t p256_to_psa_error(int ret)
46a8e1175bSopenharmony_ci{
47a8e1175bSopenharmony_ci    switch (ret) {
48a8e1175bSopenharmony_ci        case P256_SUCCESS:
49a8e1175bSopenharmony_ci            return PSA_SUCCESS;
50a8e1175bSopenharmony_ci        case P256_INVALID_PUBKEY:
51a8e1175bSopenharmony_ci        case P256_INVALID_PRIVKEY:
52a8e1175bSopenharmony_ci            return PSA_ERROR_INVALID_ARGUMENT;
53a8e1175bSopenharmony_ci        case P256_INVALID_SIGNATURE:
54a8e1175bSopenharmony_ci            return PSA_ERROR_INVALID_SIGNATURE;
55a8e1175bSopenharmony_ci        case P256_RANDOM_FAILED:
56a8e1175bSopenharmony_ci        default:
57a8e1175bSopenharmony_ci            return PSA_ERROR_GENERIC_ERROR;
58a8e1175bSopenharmony_ci    }
59a8e1175bSopenharmony_ci}
60a8e1175bSopenharmony_ci
61a8e1175bSopenharmony_cipsa_status_t p256_transparent_import_key(const psa_key_attributes_t *attributes,
62a8e1175bSopenharmony_ci                             const uint8_t *data,
63a8e1175bSopenharmony_ci                             size_t data_length,
64a8e1175bSopenharmony_ci                             uint8_t *key_buffer,
65a8e1175bSopenharmony_ci                             size_t key_buffer_size,
66a8e1175bSopenharmony_ci                             size_t *key_buffer_length,
67a8e1175bSopenharmony_ci                             size_t *bits)
68a8e1175bSopenharmony_ci{
69a8e1175bSopenharmony_ci    /* Check the key size */
70a8e1175bSopenharmony_ci    if (*bits != 0 && *bits != CURVE_BITS) {
71a8e1175bSopenharmony_ci        return PSA_ERROR_NOT_SUPPORTED;
72a8e1175bSopenharmony_ci    }
73a8e1175bSopenharmony_ci
74a8e1175bSopenharmony_ci    /* Validate the key (and its type and size) */
75a8e1175bSopenharmony_ci    psa_key_type_t type = psa_get_key_type(attributes);
76a8e1175bSopenharmony_ci    if (type == PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1)) {
77a8e1175bSopenharmony_ci        if (data_length != PSA_PUBKEY_SIZE) {
78a8e1175bSopenharmony_ci            return *bits == 0 ? PSA_ERROR_NOT_SUPPORTED : PSA_ERROR_INVALID_ARGUMENT;
79a8e1175bSopenharmony_ci        }
80a8e1175bSopenharmony_ci        /* See INFORMATION ON PSA KEY EXPORT FORMATS near top of file */
81a8e1175bSopenharmony_ci        if (p256_validate_pubkey(data + 1) != P256_SUCCESS) {
82a8e1175bSopenharmony_ci            return PSA_ERROR_INVALID_ARGUMENT;
83a8e1175bSopenharmony_ci        }
84a8e1175bSopenharmony_ci    } else if (type == PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)) {
85a8e1175bSopenharmony_ci        if (data_length != PRIVKEY_SIZE) {
86a8e1175bSopenharmony_ci            return *bits == 0 ? PSA_ERROR_NOT_SUPPORTED : PSA_ERROR_INVALID_ARGUMENT;
87a8e1175bSopenharmony_ci        }
88a8e1175bSopenharmony_ci        if (p256_validate_privkey(data) != P256_SUCCESS) {
89a8e1175bSopenharmony_ci            return PSA_ERROR_INVALID_ARGUMENT;
90a8e1175bSopenharmony_ci        }
91a8e1175bSopenharmony_ci    } else {
92a8e1175bSopenharmony_ci        return PSA_ERROR_NOT_SUPPORTED;
93a8e1175bSopenharmony_ci    }
94a8e1175bSopenharmony_ci    *bits = CURVE_BITS;
95a8e1175bSopenharmony_ci
96a8e1175bSopenharmony_ci    /* We only support the export format for input, so just copy. */
97a8e1175bSopenharmony_ci    if (key_buffer_size < data_length) {
98a8e1175bSopenharmony_ci        return PSA_ERROR_BUFFER_TOO_SMALL;
99a8e1175bSopenharmony_ci    }
100a8e1175bSopenharmony_ci    memcpy(key_buffer, data, data_length);
101a8e1175bSopenharmony_ci    *key_buffer_length = data_length;
102a8e1175bSopenharmony_ci
103a8e1175bSopenharmony_ci    return PSA_SUCCESS;
104a8e1175bSopenharmony_ci}
105a8e1175bSopenharmony_ci
106a8e1175bSopenharmony_cipsa_status_t p256_transparent_export_public_key(const psa_key_attributes_t *attributes,
107a8e1175bSopenharmony_ci                                    const uint8_t *key_buffer,
108a8e1175bSopenharmony_ci                                    size_t key_buffer_size,
109a8e1175bSopenharmony_ci                                    uint8_t *data,
110a8e1175bSopenharmony_ci                                    size_t data_size,
111a8e1175bSopenharmony_ci                                    size_t *data_length)
112a8e1175bSopenharmony_ci{
113a8e1175bSopenharmony_ci    /* Is this the right curve? */
114a8e1175bSopenharmony_ci    size_t bits = psa_get_key_bits(attributes);
115a8e1175bSopenharmony_ci    psa_key_type_t type = psa_get_key_type(attributes);
116a8e1175bSopenharmony_ci    if (bits != CURVE_BITS || type != PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)) {
117a8e1175bSopenharmony_ci        return PSA_ERROR_NOT_SUPPORTED;
118a8e1175bSopenharmony_ci    }
119a8e1175bSopenharmony_ci
120a8e1175bSopenharmony_ci    /* Validate sizes, as p256-m expects fixed-size buffers */
121a8e1175bSopenharmony_ci    if (key_buffer_size != PRIVKEY_SIZE) {
122a8e1175bSopenharmony_ci        return PSA_ERROR_INVALID_ARGUMENT;
123a8e1175bSopenharmony_ci    }
124a8e1175bSopenharmony_ci    if (data_size < PSA_PUBKEY_SIZE) {
125a8e1175bSopenharmony_ci        return PSA_ERROR_BUFFER_TOO_SMALL;
126a8e1175bSopenharmony_ci    }
127a8e1175bSopenharmony_ci
128a8e1175bSopenharmony_ci    /* See INFORMATION ON PSA KEY EXPORT FORMATS near top of file */
129a8e1175bSopenharmony_ci    data[0] = PSA_PUBKEY_HEADER_BYTE;
130a8e1175bSopenharmony_ci    int ret = p256_public_from_private(data + 1, key_buffer);
131a8e1175bSopenharmony_ci    if (ret == P256_SUCCESS) {
132a8e1175bSopenharmony_ci        *data_length = PSA_PUBKEY_SIZE;
133a8e1175bSopenharmony_ci    }
134a8e1175bSopenharmony_ci
135a8e1175bSopenharmony_ci    return p256_to_psa_error(ret);
136a8e1175bSopenharmony_ci}
137a8e1175bSopenharmony_ci
138a8e1175bSopenharmony_cipsa_status_t p256_transparent_generate_key(
139a8e1175bSopenharmony_ci    const psa_key_attributes_t *attributes,
140a8e1175bSopenharmony_ci    uint8_t *key_buffer,
141a8e1175bSopenharmony_ci    size_t key_buffer_size,
142a8e1175bSopenharmony_ci    size_t *key_buffer_length)
143a8e1175bSopenharmony_ci{
144a8e1175bSopenharmony_ci    /* We don't use this argument, but the specification mandates the signature
145a8e1175bSopenharmony_ci     * of driver entry-points. (void) used to avoid compiler warning. */
146a8e1175bSopenharmony_ci    (void) attributes;
147a8e1175bSopenharmony_ci
148a8e1175bSopenharmony_ci    /* Validate sizes, as p256-m expects fixed-size buffers */
149a8e1175bSopenharmony_ci    if (key_buffer_size != PRIVKEY_SIZE) {
150a8e1175bSopenharmony_ci        return PSA_ERROR_BUFFER_TOO_SMALL;
151a8e1175bSopenharmony_ci    }
152a8e1175bSopenharmony_ci
153a8e1175bSopenharmony_ci    /*
154a8e1175bSopenharmony_ci     *  p256-m's keypair generation function outputs both public and private
155a8e1175bSopenharmony_ci     *  keys. Allocate a buffer to which the public key will be written. The
156a8e1175bSopenharmony_ci     *  private key will be written to key_buffer, which is passed to this
157a8e1175bSopenharmony_ci     *  function as an argument. */
158a8e1175bSopenharmony_ci    uint8_t public_key_buffer[P256_PUBKEY_SIZE];
159a8e1175bSopenharmony_ci
160a8e1175bSopenharmony_ci    int ret = p256_gen_keypair(key_buffer, public_key_buffer);
161a8e1175bSopenharmony_ci    if (ret == P256_SUCCESS) {
162a8e1175bSopenharmony_ci        *key_buffer_length = PRIVKEY_SIZE;
163a8e1175bSopenharmony_ci    }
164a8e1175bSopenharmony_ci
165a8e1175bSopenharmony_ci    return p256_to_psa_error(ret);
166a8e1175bSopenharmony_ci}
167a8e1175bSopenharmony_ci
168a8e1175bSopenharmony_cipsa_status_t p256_transparent_key_agreement(
169a8e1175bSopenharmony_ci    const psa_key_attributes_t *attributes,
170a8e1175bSopenharmony_ci    const uint8_t *key_buffer,
171a8e1175bSopenharmony_ci    size_t key_buffer_size,
172a8e1175bSopenharmony_ci    psa_algorithm_t alg,
173a8e1175bSopenharmony_ci    const uint8_t *peer_key,
174a8e1175bSopenharmony_ci    size_t peer_key_length,
175a8e1175bSopenharmony_ci    uint8_t *shared_secret,
176a8e1175bSopenharmony_ci    size_t shared_secret_size,
177a8e1175bSopenharmony_ci    size_t *shared_secret_length)
178a8e1175bSopenharmony_ci{
179a8e1175bSopenharmony_ci    /* We don't use these arguments, but the specification mandates the
180a8e1175bSopenharmony_ci     * sginature of driver entry-points. (void) used to avoid compiler
181a8e1175bSopenharmony_ci     * warning. */
182a8e1175bSopenharmony_ci    (void) attributes;
183a8e1175bSopenharmony_ci    (void) alg;
184a8e1175bSopenharmony_ci
185a8e1175bSopenharmony_ci    /* Validate sizes, as p256-m expects fixed-size buffers */
186a8e1175bSopenharmony_ci    if (key_buffer_size != PRIVKEY_SIZE || peer_key_length != PSA_PUBKEY_SIZE) {
187a8e1175bSopenharmony_ci        return PSA_ERROR_INVALID_ARGUMENT;
188a8e1175bSopenharmony_ci    }
189a8e1175bSopenharmony_ci    if (shared_secret_size < SHARED_SECRET_SIZE) {
190a8e1175bSopenharmony_ci        return PSA_ERROR_BUFFER_TOO_SMALL;
191a8e1175bSopenharmony_ci    }
192a8e1175bSopenharmony_ci
193a8e1175bSopenharmony_ci    /* See INFORMATION ON PSA KEY EXPORT FORMATS near top of file */
194a8e1175bSopenharmony_ci    const uint8_t *peer_key_p256m = peer_key + 1;
195a8e1175bSopenharmony_ci    int ret = p256_ecdh_shared_secret(shared_secret, key_buffer, peer_key_p256m);
196a8e1175bSopenharmony_ci    if (ret == P256_SUCCESS) {
197a8e1175bSopenharmony_ci        *shared_secret_length = SHARED_SECRET_SIZE;
198a8e1175bSopenharmony_ci    }
199a8e1175bSopenharmony_ci
200a8e1175bSopenharmony_ci    return p256_to_psa_error(ret);
201a8e1175bSopenharmony_ci}
202a8e1175bSopenharmony_ci
203a8e1175bSopenharmony_cipsa_status_t p256_transparent_sign_hash(
204a8e1175bSopenharmony_ci    const psa_key_attributes_t *attributes,
205a8e1175bSopenharmony_ci    const uint8_t *key_buffer,
206a8e1175bSopenharmony_ci    size_t key_buffer_size,
207a8e1175bSopenharmony_ci    psa_algorithm_t alg,
208a8e1175bSopenharmony_ci    const uint8_t *hash,
209a8e1175bSopenharmony_ci    size_t hash_length,
210a8e1175bSopenharmony_ci    uint8_t *signature,
211a8e1175bSopenharmony_ci    size_t signature_size,
212a8e1175bSopenharmony_ci    size_t *signature_length)
213a8e1175bSopenharmony_ci{
214a8e1175bSopenharmony_ci    /* We don't use these arguments, but the specification mandates the
215a8e1175bSopenharmony_ci     * sginature of driver entry-points. (void) used to avoid compiler
216a8e1175bSopenharmony_ci     * warning. */
217a8e1175bSopenharmony_ci    (void) attributes;
218a8e1175bSopenharmony_ci    (void) alg;
219a8e1175bSopenharmony_ci
220a8e1175bSopenharmony_ci    /* Validate sizes, as p256-m expects fixed-size buffers */
221a8e1175bSopenharmony_ci    if (key_buffer_size != PRIVKEY_SIZE) {
222a8e1175bSopenharmony_ci        return PSA_ERROR_INVALID_ARGUMENT;
223a8e1175bSopenharmony_ci    }
224a8e1175bSopenharmony_ci    if (signature_size < SIGNATURE_SIZE) {
225a8e1175bSopenharmony_ci        return PSA_ERROR_BUFFER_TOO_SMALL;
226a8e1175bSopenharmony_ci    }
227a8e1175bSopenharmony_ci
228a8e1175bSopenharmony_ci    int ret = p256_ecdsa_sign(signature, key_buffer, hash, hash_length);
229a8e1175bSopenharmony_ci    if (ret == P256_SUCCESS) {
230a8e1175bSopenharmony_ci        *signature_length = SIGNATURE_SIZE;
231a8e1175bSopenharmony_ci    }
232a8e1175bSopenharmony_ci
233a8e1175bSopenharmony_ci    return p256_to_psa_error(ret);
234a8e1175bSopenharmony_ci}
235a8e1175bSopenharmony_ci
236a8e1175bSopenharmony_ci/*  This function expects the key buffer to contain a PSA public key,
237a8e1175bSopenharmony_ci *  as exported by psa_export_public_key() */
238a8e1175bSopenharmony_cistatic psa_status_t p256_verify_hash_with_public_key(
239a8e1175bSopenharmony_ci    const uint8_t *key_buffer,
240a8e1175bSopenharmony_ci    size_t key_buffer_size,
241a8e1175bSopenharmony_ci    const uint8_t *hash,
242a8e1175bSopenharmony_ci    size_t hash_length,
243a8e1175bSopenharmony_ci    const uint8_t *signature,
244a8e1175bSopenharmony_ci    size_t signature_length)
245a8e1175bSopenharmony_ci{
246a8e1175bSopenharmony_ci    /* Validate sizes, as p256-m expects fixed-size buffers */
247a8e1175bSopenharmony_ci    if (key_buffer_size != PSA_PUBKEY_SIZE || *key_buffer != PSA_PUBKEY_HEADER_BYTE) {
248a8e1175bSopenharmony_ci        return PSA_ERROR_INVALID_ARGUMENT;
249a8e1175bSopenharmony_ci    }
250a8e1175bSopenharmony_ci    if (signature_length != SIGNATURE_SIZE) {
251a8e1175bSopenharmony_ci        return PSA_ERROR_INVALID_SIGNATURE;
252a8e1175bSopenharmony_ci    }
253a8e1175bSopenharmony_ci
254a8e1175bSopenharmony_ci    /* See INFORMATION ON PSA KEY EXPORT FORMATS near top of file */
255a8e1175bSopenharmony_ci    const uint8_t *public_key_p256m = key_buffer + 1;
256a8e1175bSopenharmony_ci    int ret = p256_ecdsa_verify(signature, public_key_p256m, hash, hash_length);
257a8e1175bSopenharmony_ci
258a8e1175bSopenharmony_ci    return p256_to_psa_error(ret);
259a8e1175bSopenharmony_ci}
260a8e1175bSopenharmony_ci
261a8e1175bSopenharmony_cipsa_status_t p256_transparent_verify_hash(
262a8e1175bSopenharmony_ci    const psa_key_attributes_t *attributes,
263a8e1175bSopenharmony_ci    const uint8_t *key_buffer,
264a8e1175bSopenharmony_ci    size_t key_buffer_size,
265a8e1175bSopenharmony_ci    psa_algorithm_t alg,
266a8e1175bSopenharmony_ci    const uint8_t *hash,
267a8e1175bSopenharmony_ci    size_t hash_length,
268a8e1175bSopenharmony_ci    const uint8_t *signature,
269a8e1175bSopenharmony_ci    size_t signature_length)
270a8e1175bSopenharmony_ci{
271a8e1175bSopenharmony_ci    /* We don't use this argument, but the specification mandates the signature
272a8e1175bSopenharmony_ci     * of driver entry-points. (void) used to avoid compiler warning. */
273a8e1175bSopenharmony_ci    (void) alg;
274a8e1175bSopenharmony_ci
275a8e1175bSopenharmony_ci    psa_status_t status;
276a8e1175bSopenharmony_ci    uint8_t public_key_buffer[PSA_PUBKEY_SIZE];
277a8e1175bSopenharmony_ci    size_t public_key_buffer_size = PSA_PUBKEY_SIZE;
278a8e1175bSopenharmony_ci
279a8e1175bSopenharmony_ci    size_t public_key_length = PSA_PUBKEY_SIZE;
280a8e1175bSopenharmony_ci    /* As p256-m doesn't require dynamic allocation, we want to avoid it in
281a8e1175bSopenharmony_ci     * the entrypoint functions as well. psa_driver_wrapper_export_public_key()
282a8e1175bSopenharmony_ci     * requires size_t*, so we use a pointer to a stack variable. */
283a8e1175bSopenharmony_ci    size_t *public_key_length_ptr = &public_key_length;
284a8e1175bSopenharmony_ci
285a8e1175bSopenharmony_ci    /* The contents of key_buffer may either be the 32 byte private key
286a8e1175bSopenharmony_ci     * (keypair format), or 0x04 followed by the 64 byte public key (public
287a8e1175bSopenharmony_ci     * key format). To ensure the key is in the latter format, the public key
288a8e1175bSopenharmony_ci     * is exported. */
289a8e1175bSopenharmony_ci    status = psa_driver_wrapper_export_public_key(
290a8e1175bSopenharmony_ci        attributes,
291a8e1175bSopenharmony_ci        key_buffer,
292a8e1175bSopenharmony_ci        key_buffer_size,
293a8e1175bSopenharmony_ci        public_key_buffer,
294a8e1175bSopenharmony_ci        public_key_buffer_size,
295a8e1175bSopenharmony_ci        public_key_length_ptr);
296a8e1175bSopenharmony_ci    if (status != PSA_SUCCESS) {
297a8e1175bSopenharmony_ci        goto exit;
298a8e1175bSopenharmony_ci    }
299a8e1175bSopenharmony_ci
300a8e1175bSopenharmony_ci    status = p256_verify_hash_with_public_key(
301a8e1175bSopenharmony_ci        public_key_buffer,
302a8e1175bSopenharmony_ci        public_key_buffer_size,
303a8e1175bSopenharmony_ci        hash,
304a8e1175bSopenharmony_ci        hash_length,
305a8e1175bSopenharmony_ci        signature,
306a8e1175bSopenharmony_ci        signature_length);
307a8e1175bSopenharmony_ci
308a8e1175bSopenharmony_ciexit:
309a8e1175bSopenharmony_ci    return status;
310a8e1175bSopenharmony_ci}
311a8e1175bSopenharmony_ci
312a8e1175bSopenharmony_ci#endif /* MBEDTLS_PSA_P256M_DRIVER_ENABLED */
313