1 /* kcapi_ecc.c
2 *
3 * Copyright (C) 2006-2020 wolfSSL Inc.
4 *
5 * This file is part of wolfSSL.
6 *
7 * wolfSSL is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * wolfSSL is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
20 */
21
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <wolfssl/wolfcrypt/settings.h>
28
29 #if defined(WOLFSSL_KCAPI_ECC)
30
31 #include <wolfssl/wolfcrypt/error-crypt.h>
32 #include <wolfssl/wolfcrypt/logging.h>
33 #include <wolfssl/wolfcrypt/port/kcapi/wc_kcapi.h>
34 #include <wolfssl/wolfcrypt/port/kcapi/kcapi_ecc.h>
35 #include <wolfssl/wolfcrypt/ecc.h>
36
37 #ifndef ECC_CURVE_NIST_P384
38 #define ECC_CURVE_NIST_P384 3
39 #endif
40 #ifndef ECC_CURVE_NIST_P521
41 #define ECC_CURVE_NIST_P521 4
42 #endif
43
44 #define ECDSA_KEY_VERSION 1
45
46 static const char WC_NAME_ECDH[] = "ecdh";
47 #if defined(HAVE_ECC_SIGN) || defined(HAVE_ECC_VERIFY)
48 static const char WC_NAME_ECDSA[] = "ecdsa";
49 #endif
50
KcapiEcc_Free(ecc_key * key)51 void KcapiEcc_Free(ecc_key* key)
52 {
53 if (key->handle != NULL) {
54 kcapi_kpp_destroy(key->handle);
55 key->handle = NULL;
56 }
57 }
58
KcapiEcc_CurveId(int curve_id,word32 * kcapiCurveId)59 static int KcapiEcc_CurveId(int curve_id, word32* kcapiCurveId)
60 {
61 int ret = 0;
62
63 switch (curve_id) {
64 case ECC_SECP256R1:
65 *kcapiCurveId = ECC_CURVE_NIST_P256;
66 break;
67 case ECC_SECP384R1:
68 *kcapiCurveId = ECC_CURVE_NIST_P384;
69 break;
70 case ECC_SECP521R1:
71 *kcapiCurveId = ECC_CURVE_NIST_P521;
72 break;
73 default:
74 ret = BAD_FUNC_ARG;
75 break;
76 }
77
78 return ret;
79 }
80
KcapiEcc_MakeKey(ecc_key * key,int keysize,int curve_id)81 int KcapiEcc_MakeKey(ecc_key* key, int keysize, int curve_id)
82 {
83 int ret = 0;
84 word32 kcapiCurveId;
85
86 if (curve_id == ECC_CURVE_DEF) {
87 switch (keysize) {
88 case 32:
89 curve_id = ECC_SECP256R1;
90 break;
91 case 48:
92 curve_id = ECC_SECP384R1;
93 break;
94 case 66:
95 curve_id = ECC_SECP521R1;
96 break;
97 default:
98 ret = BAD_FUNC_ARG;
99 break;
100 }
101 }
102 if (ret == 0) {
103 ret = KcapiEcc_CurveId(curve_id, &kcapiCurveId);
104 }
105
106 if (key->handle != NULL) {
107 kcapi_kpp_destroy(key->handle);
108 key->handle = NULL;
109 }
110 if (ret == 0) {
111 ret = kcapi_kpp_init(&key->handle, WC_NAME_ECDH, 0);
112 if (ret != 0) {
113 WOLFSSL_MSG("KcapiEcc_MakeKey: Failed to initialize");
114 }
115 }
116 if (ret == 0) {
117 ret = kcapi_kpp_ecdh_setcurve(key->handle, kcapiCurveId);
118 }
119 if (ret == 0) {
120 ret = kcapi_kpp_keygen(key->handle, key->pubkey_raw,
121 sizeof(key->pubkey_raw), KCAPI_ACCESS_HEURISTIC);
122 }
123 if (ret >= 0) {
124 ret = mp_read_unsigned_bin(key->pubkey.x, key->pubkey_raw, ret / 2);
125 }
126 if (ret == 0) {
127 ret = mp_read_unsigned_bin(key->pubkey.y, key->pubkey_raw + ret / 2,
128 ret / 2);
129 }
130 if ((ret != 0) && (key->handle != NULL)) {
131 kcapi_kpp_destroy(key->handle);
132 key->handle = NULL;
133 }
134
135 return ret;
136 }
137
138 #ifdef HAVE_ECC_DHE
KcapiEcc_SharedSecret(ecc_key * private_key,ecc_key * public_key,byte * out,word32 * outlen)139 int KcapiEcc_SharedSecret(ecc_key* private_key, ecc_key* public_key, byte* out,
140 word32* outlen)
141 {
142 int ret;
143
144 ret = kcapi_kpp_ssgen(private_key->handle, public_key->pubkey_raw,
145 public_key->dp->size * 2, out, *outlen,
146 KCAPI_ACCESS_HEURISTIC);
147 if (ret >= 0) {
148 *outlen = ret;
149 ret = 0;
150 }
151
152 return ret;
153 }
154 #endif
155
156 #ifdef HAVE_ECC_SIGN
KcapiEcc_SetPrivKey(ecc_key * key)157 static int KcapiEcc_SetPrivKey(ecc_key* key)
158 {
159 int ret;
160 unsigned char priv[KCAPI_PARAM_SZ + MAX_ECC_BYTES];
161 word32 keySz = key->dp->size;
162 word32 kcapiCurveId;
163
164 ret = KcapiEcc_CurveId(key->dp->id, &kcapiCurveId);
165 if (ret == MP_OKAY) {
166 priv[0] = ECDSA_KEY_VERSION;
167 priv[1] = kcapiCurveId;
168 ret = wc_export_int(&key->k, priv + 2, &keySz, keySz,
169 WC_TYPE_UNSIGNED_BIN);
170 }
171 if (ret == MP_OKAY) {
172 ret = kcapi_akcipher_setkey(key->handle, priv, KCAPI_PARAM_SZ + keySz);
173 }
174
175 return ret;
176 }
177
KcapiEcc_Sign(ecc_key * key,const byte * hash,word32 hashLen,byte * sig,word32 * sigLen)178 int KcapiEcc_Sign(ecc_key* key, const byte* hash, word32 hashLen, byte* sig,
179 word32* sigLen)
180 {
181 int ret = 0;
182 unsigned char* buf_aligned = NULL;
183 unsigned char* hash_aligned = NULL;
184 unsigned char* sig_aligned = NULL;
185 size_t pageSz = (size_t)sysconf(_SC_PAGESIZE);
186
187 if (key->handle == NULL) {
188 ret = kcapi_akcipher_init(&key->handle, WC_NAME_ECDSA, 0);
189 if (ret != 0) {
190 WOLFSSL_MSG("KcapiEcc_Sign: Failed to initialize");
191 }
192 if (ret == 0) {
193 ret = KcapiEcc_SetPrivKey(key);
194 }
195 }
196 if (ret == 0) {
197 if (((size_t)sig % pageSz != 0) || ((size_t)hash % pageSz != 0)) {
198 ret = posix_memalign((void*)&buf_aligned, pageSz, pageSz * 2);
199 if (ret < 0) {
200 ret = MEMORY_E;
201 }
202 }
203 }
204 if (ret == 0) {
205 sig_aligned = ((size_t)sig % pageSz == 0) ? sig : buf_aligned;
206 if ((size_t)hash % pageSz == 0) {
207 hash_aligned = (unsigned char*)hash;
208 }
209 else {
210 hash_aligned = buf_aligned + pageSz;
211 XMEMCPY(hash_aligned, hash, hashLen);
212 }
213 ret = kcapi_akcipher_sign(key->handle, hash_aligned, hashLen,
214 sig_aligned, *sigLen,
215 KCAPI_ACCESS_HEURISTIC);
216 if (ret >= 0) {
217 *sigLen = ret;
218 ret = 0;
219 if (sig_aligned != sig) {
220 XMEMCPY(sig, sig_aligned, ret);
221 }
222 }
223 }
224 /* Using free as this is in an environment that will have it
225 * available along with posix_memalign. */
226 if (buf_aligned != NULL) {
227 free(buf_aligned);
228 }
229
230 return ret;
231 }
232 #endif
233
234
235 #ifdef HAVE_ECC_VERIFY
KcapiEcc_SetPubKey(ecc_key * key)236 int KcapiEcc_SetPubKey(ecc_key* key)
237 {
238 int ret;
239 int len = KCAPI_PARAM_SZ + key->dp->size * 2;
240 word32 kcapiCurveId;
241
242 ret = KcapiEcc_CurveId(key->dp->id, &kcapiCurveId);
243 if (ret == MP_OKAY) {
244 key->pubkey_raw[0] = ECDSA_KEY_VERSION;
245 key->pubkey_raw[1] = kcapiCurveId;
246
247 ret = kcapi_akcipher_setpubkey(key->handle, key->pubkey_raw, len);
248 }
249
250 return ret;
251 }
252
KcapiEcc_Verify(ecc_key * key,const byte * hash,word32 hashLen,byte * sig,word32 sigLen)253 int KcapiEcc_Verify(ecc_key* key, const byte* hash, word32 hashLen, byte* sig,
254 word32 sigLen)
255 {
256 int ret = 0;
257 unsigned char* sigHash_aligned = NULL;
258 size_t pageSz = (size_t)sysconf(_SC_PAGESIZE);
259
260 if (key->handle == NULL) {
261 ret = kcapi_akcipher_init(&key->handle, WC_NAME_ECDSA, 0);
262 if (ret != 0) {
263 WOLFSSL_MSG("KcapiEcc_Verify: Failed to initialize");
264 }
265 }
266 if (ret == 0) {
267 ret = KcapiEcc_SetPubKey(key);
268 }
269
270 if (ret == 0) {
271 ret = posix_memalign((void*)&sigHash_aligned, pageSz, sigLen + hashLen);
272 if (ret < 0) {
273 ret = MEMORY_E;
274 }
275 }
276 if (ret == 0) {
277 XMEMCPY(sigHash_aligned, sig, sigLen);
278 XMEMCPY(sigHash_aligned + sigLen, hash, hashLen);
279
280 ret = kcapi_akcipher_verify(key->handle, sigHash_aligned,
281 sigLen + hashLen, NULL, hashLen, KCAPI_ACCESS_HEURISTIC);
282 if (ret >= 0) {
283 ret = 0;
284 }
285 }
286
287 /* Using free as this is in an environment that will have it
288 * available along with posix_memalign. */
289 if (sigHash_aligned != NULL) {
290 free(sigHash_aligned);
291 }
292 return ret;
293 }
294 #endif
295
296 #endif /* WOLFSSL_KCAPI_ECC */
297
298