/src/mbedtls/library/pk_ecc.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * ECC setters for PK. |
3 | | * |
4 | | * Copyright The Mbed TLS Contributors |
5 | | * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later |
6 | | */ |
7 | | |
8 | | #include "common.h" |
9 | | |
10 | | #include "mbedtls/pk.h" |
11 | | #include "mbedtls/error.h" |
12 | | #include "mbedtls/ecp.h" |
13 | | #include "pk_internal.h" |
14 | | |
15 | | #if defined(MBEDTLS_PK_C) && defined(MBEDTLS_PK_HAVE_ECC_KEYS) |
16 | | |
17 | | int mbedtls_pk_ecc_set_group(mbedtls_pk_context *pk, mbedtls_ecp_group_id grp_id) |
18 | 0 | { |
19 | | #if defined(MBEDTLS_PK_USE_PSA_EC_DATA) |
20 | | size_t ec_bits; |
21 | | psa_ecc_family_t ec_family = mbedtls_ecc_group_to_psa(grp_id, &ec_bits); |
22 | | |
23 | | /* group may already be initialized; if so, make sure IDs match */ |
24 | | if ((pk->ec_family != 0 && pk->ec_family != ec_family) || |
25 | | (pk->ec_bits != 0 && pk->ec_bits != ec_bits)) { |
26 | | return MBEDTLS_ERR_PK_KEY_INVALID_FORMAT; |
27 | | } |
28 | | |
29 | | /* set group */ |
30 | | pk->ec_family = ec_family; |
31 | | pk->ec_bits = ec_bits; |
32 | | |
33 | | return 0; |
34 | | #else /* MBEDTLS_PK_USE_PSA_EC_DATA */ |
35 | 0 | mbedtls_ecp_keypair *ecp = mbedtls_pk_ec_rw(*pk); |
36 | | |
37 | | /* grp may already be initialized; if so, make sure IDs match */ |
38 | 0 | if (mbedtls_pk_ec_ro(*pk)->grp.id != MBEDTLS_ECP_DP_NONE && |
39 | 0 | mbedtls_pk_ec_ro(*pk)->grp.id != grp_id) { |
40 | 0 | return MBEDTLS_ERR_PK_KEY_INVALID_FORMAT; |
41 | 0 | } |
42 | | |
43 | | /* set group */ |
44 | 0 | return mbedtls_ecp_group_load(&(ecp->grp), grp_id); |
45 | 0 | #endif /* MBEDTLS_PK_USE_PSA_EC_DATA */ |
46 | 0 | } |
47 | | |
48 | | int mbedtls_pk_ecc_set_key(mbedtls_pk_context *pk, unsigned char *key, size_t key_len) |
49 | 0 | { |
50 | | #if defined(MBEDTLS_PK_USE_PSA_EC_DATA) |
51 | | psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; |
52 | | psa_key_usage_t flags; |
53 | | psa_status_t status; |
54 | | |
55 | | psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(pk->ec_family)); |
56 | | if (pk->ec_family == PSA_ECC_FAMILY_MONTGOMERY) { |
57 | | /* Do not set algorithm here because Montgomery keys cannot do ECDSA and |
58 | | * the PK module cannot do ECDH. When the key will be used in TLS for |
59 | | * ECDH, it will be exported and then re-imported with proper flags |
60 | | * and algorithm. */ |
61 | | flags = PSA_KEY_USAGE_EXPORT; |
62 | | } else { |
63 | | psa_set_key_algorithm(&attributes, |
64 | | MBEDTLS_PK_PSA_ALG_ECDSA_MAYBE_DET(PSA_ALG_ANY_HASH)); |
65 | | flags = PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_SIGN_MESSAGE | |
66 | | PSA_KEY_USAGE_EXPORT; |
67 | | } |
68 | | psa_set_key_usage_flags(&attributes, flags); |
69 | | |
70 | | status = psa_import_key(&attributes, key, key_len, &pk->priv_id); |
71 | | return psa_pk_status_to_mbedtls(status); |
72 | | |
73 | | #else /* MBEDTLS_PK_USE_PSA_EC_DATA */ |
74 | |
|
75 | 0 | mbedtls_ecp_keypair *eck = mbedtls_pk_ec_rw(*pk); |
76 | 0 | int ret = mbedtls_ecp_read_key(eck->grp.id, eck, key, key_len); |
77 | 0 | if (ret != 0) { |
78 | 0 | return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret); |
79 | 0 | } |
80 | 0 | return 0; |
81 | 0 | #endif /* MBEDTLS_PK_USE_PSA_EC_DATA */ |
82 | 0 | } |
83 | | |
84 | | int mbedtls_pk_ecc_set_pubkey_from_prv(mbedtls_pk_context *pk, |
85 | | const unsigned char *prv, size_t prv_len, |
86 | | int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) |
87 | 0 | { |
88 | | #if defined(MBEDTLS_PK_USE_PSA_EC_DATA) |
89 | | |
90 | | (void) f_rng; |
91 | | (void) p_rng; |
92 | | (void) prv; |
93 | | (void) prv_len; |
94 | | psa_status_t status; |
95 | | |
96 | | status = psa_export_public_key(pk->priv_id, pk->pub_raw, sizeof(pk->pub_raw), |
97 | | &pk->pub_raw_len); |
98 | | return psa_pk_status_to_mbedtls(status); |
99 | | |
100 | | #elif defined(MBEDTLS_USE_PSA_CRYPTO) /* && !MBEDTLS_PK_USE_PSA_EC_DATA */ |
101 | |
|
102 | 0 | (void) f_rng; |
103 | 0 | (void) p_rng; |
104 | 0 | psa_status_t status; |
105 | |
|
106 | 0 | mbedtls_ecp_keypair *eck = (mbedtls_ecp_keypair *) pk->pk_ctx; |
107 | 0 | size_t curve_bits; |
108 | 0 | psa_ecc_family_t curve = mbedtls_ecc_group_to_psa(eck->grp.id, &curve_bits); |
109 | | |
110 | | /* Import private key into PSA, from serialized input */ |
111 | 0 | mbedtls_svc_key_id_t key_id = MBEDTLS_SVC_KEY_ID_INIT; |
112 | 0 | psa_key_attributes_t key_attr = PSA_KEY_ATTRIBUTES_INIT; |
113 | 0 | psa_set_key_type(&key_attr, PSA_KEY_TYPE_ECC_KEY_PAIR(curve)); |
114 | 0 | psa_set_key_usage_flags(&key_attr, PSA_KEY_USAGE_EXPORT); |
115 | 0 | status = psa_import_key(&key_attr, prv, prv_len, &key_id); |
116 | 0 | if (status != PSA_SUCCESS) { |
117 | 0 | return psa_pk_status_to_mbedtls(status); |
118 | 0 | } |
119 | | |
120 | | /* Export public key from PSA */ |
121 | 0 | unsigned char pub[MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH]; |
122 | 0 | size_t pub_len; |
123 | 0 | status = psa_export_public_key(key_id, pub, sizeof(pub), &pub_len); |
124 | 0 | psa_status_t destruction_status = psa_destroy_key(key_id); |
125 | 0 | if (status != PSA_SUCCESS) { |
126 | 0 | return psa_pk_status_to_mbedtls(status); |
127 | 0 | } else if (destruction_status != PSA_SUCCESS) { |
128 | 0 | return psa_pk_status_to_mbedtls(destruction_status); |
129 | 0 | } |
130 | | |
131 | | /* Load serialized public key into ecp_keypair structure */ |
132 | 0 | return mbedtls_ecp_point_read_binary(&eck->grp, &eck->Q, pub, pub_len); |
133 | |
|
134 | | #else /* MBEDTLS_USE_PSA_CRYPTO */ |
135 | | |
136 | | (void) prv; |
137 | | (void) prv_len; |
138 | | |
139 | | mbedtls_ecp_keypair *eck = (mbedtls_ecp_keypair *) pk->pk_ctx; |
140 | | return mbedtls_ecp_mul(&eck->grp, &eck->Q, &eck->d, &eck->grp.G, f_rng, p_rng); |
141 | | |
142 | | #endif /* MBEDTLS_USE_PSA_CRYPTO */ |
143 | 0 | } |
144 | | |
145 | | #if defined(MBEDTLS_PK_USE_PSA_EC_DATA) |
146 | | /* |
147 | | * Set the public key: fallback using ECP_LIGHT in the USE_PSA_EC_DATA case. |
148 | | * |
149 | | * Normally, when MBEDTLS_PK_USE_PSA_EC_DATA is enabled, we only use PSA |
150 | | * functions to handle keys. However, currently psa_import_key() does not |
151 | | * support compressed points. In case that support was explicitly requested, |
152 | | * this fallback uses ECP functions to get the job done. This is the reason |
153 | | * why MBEDTLS_PK_PARSE_EC_COMPRESSED auto-enables MBEDTLS_ECP_LIGHT. |
154 | | * |
155 | | * [in/out] pk: in: must have the group set, see mbedtls_pk_ecc_set_group(). |
156 | | * out: will have the public key set. |
157 | | * [in] pub, pub_len: the public key as an ECPoint, |
158 | | * in any format supported by ECP. |
159 | | * |
160 | | * Return: |
161 | | * - 0 on success; |
162 | | * - MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if the format is potentially valid |
163 | | * but not supported; |
164 | | * - another error code otherwise. |
165 | | */ |
166 | | static int pk_ecc_set_pubkey_psa_ecp_fallback(mbedtls_pk_context *pk, |
167 | | const unsigned char *pub, |
168 | | size_t pub_len) |
169 | | { |
170 | | #if !defined(MBEDTLS_PK_PARSE_EC_COMPRESSED) |
171 | | (void) pk; |
172 | | (void) pub; |
173 | | (void) pub_len; |
174 | | return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; |
175 | | #else /* MBEDTLS_PK_PARSE_EC_COMPRESSED */ |
176 | | mbedtls_ecp_keypair ecp_key; |
177 | | mbedtls_ecp_group_id ecp_group_id; |
178 | | int ret; |
179 | | |
180 | | ecp_group_id = mbedtls_ecc_group_from_psa(pk->ec_family, pk->ec_bits); |
181 | | |
182 | | mbedtls_ecp_keypair_init(&ecp_key); |
183 | | ret = mbedtls_ecp_group_load(&(ecp_key.grp), ecp_group_id); |
184 | | if (ret != 0) { |
185 | | goto exit; |
186 | | } |
187 | | ret = mbedtls_ecp_point_read_binary(&(ecp_key.grp), &ecp_key.Q, |
188 | | pub, pub_len); |
189 | | if (ret != 0) { |
190 | | goto exit; |
191 | | } |
192 | | ret = mbedtls_ecp_point_write_binary(&(ecp_key.grp), &ecp_key.Q, |
193 | | MBEDTLS_ECP_PF_UNCOMPRESSED, |
194 | | &pk->pub_raw_len, pk->pub_raw, |
195 | | sizeof(pk->pub_raw)); |
196 | | |
197 | | exit: |
198 | | mbedtls_ecp_keypair_free(&ecp_key); |
199 | | return ret; |
200 | | #endif /* MBEDTLS_PK_PARSE_EC_COMPRESSED */ |
201 | | } |
202 | | #endif /* MBEDTLS_PK_USE_PSA_EC_DATA */ |
203 | | |
204 | | int mbedtls_pk_ecc_set_pubkey(mbedtls_pk_context *pk, const unsigned char *pub, size_t pub_len) |
205 | 0 | { |
206 | | #if defined(MBEDTLS_PK_USE_PSA_EC_DATA) |
207 | | |
208 | | /* Load the key */ |
209 | | if (!PSA_ECC_FAMILY_IS_WEIERSTRASS(pk->ec_family) || *pub == 0x04) { |
210 | | /* Format directly supported by PSA: |
211 | | * - non-Weierstrass curves that only have one format; |
212 | | * - uncompressed format for Weierstrass curves. */ |
213 | | if (pub_len > sizeof(pk->pub_raw)) { |
214 | | return MBEDTLS_ERR_PK_BUFFER_TOO_SMALL; |
215 | | } |
216 | | memcpy(pk->pub_raw, pub, pub_len); |
217 | | pk->pub_raw_len = pub_len; |
218 | | } else { |
219 | | /* Other format, try the fallback */ |
220 | | int ret = pk_ecc_set_pubkey_psa_ecp_fallback(pk, pub, pub_len); |
221 | | if (ret != 0) { |
222 | | return ret; |
223 | | } |
224 | | } |
225 | | |
226 | | /* Validate the key by trying to import it */ |
227 | | mbedtls_svc_key_id_t key_id = MBEDTLS_SVC_KEY_ID_INIT; |
228 | | psa_key_attributes_t key_attrs = PSA_KEY_ATTRIBUTES_INIT; |
229 | | |
230 | | psa_set_key_usage_flags(&key_attrs, 0); |
231 | | psa_set_key_type(&key_attrs, PSA_KEY_TYPE_ECC_PUBLIC_KEY(pk->ec_family)); |
232 | | psa_set_key_bits(&key_attrs, pk->ec_bits); |
233 | | |
234 | | if ((psa_import_key(&key_attrs, pk->pub_raw, pk->pub_raw_len, |
235 | | &key_id) != PSA_SUCCESS) || |
236 | | (psa_destroy_key(key_id) != PSA_SUCCESS)) { |
237 | | return MBEDTLS_ERR_PK_INVALID_PUBKEY; |
238 | | } |
239 | | |
240 | | return 0; |
241 | | |
242 | | #else /* MBEDTLS_PK_USE_PSA_EC_DATA */ |
243 | |
|
244 | 0 | int ret; |
245 | 0 | mbedtls_ecp_keypair *ec_key = (mbedtls_ecp_keypair *) pk->pk_ctx; |
246 | 0 | ret = mbedtls_ecp_point_read_binary(&ec_key->grp, &ec_key->Q, pub, pub_len); |
247 | 0 | if (ret != 0) { |
248 | 0 | return ret; |
249 | 0 | } |
250 | 0 | return mbedtls_ecp_check_pubkey(&ec_key->grp, &ec_key->Q); |
251 | |
|
252 | 0 | #endif /* MBEDTLS_PK_USE_PSA_EC_DATA */ |
253 | 0 | } |
254 | | |
255 | | #endif /* MBEDTLS_PK_C && MBEDTLS_PK_HAVE_ECC_KEYS */ |