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