]>
Commit | Line | Data |
---|---|---|
c92eade8 | 1 | /* |
142b5e79 | 2 | * Copyright (C) 2020 Tobias Brunner |
142b5e79 | 3 | * |
c92eade8 SP |
4 | * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc. |
5 | * | |
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
7 | * of this software and associated documentation files (the "Software"), to deal | |
8 | * in the Software without restriction, including without limitation the rights | |
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
10 | * copies of the Software, and to permit persons to whom the Software is | |
11 | * furnished to do so, subject to the following conditions: | |
12 | * | |
13 | * The above copyright notice and this permission notice shall be included in | |
14 | * all copies or substantial portions of the Software. | |
15 | * | |
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
22 | * THE SOFTWARE. | |
23 | */ | |
24 | ||
25 | #include "wolfssl_common.h" | |
26 | ||
142b5e79 | 27 | #if defined(HAVE_ED25519) || defined(HAVE_ED448) |
c92eade8 SP |
28 | |
29 | #include "wolfssl_ed_private_key.h" | |
30 | ||
31 | #include <utils/debug.h> | |
32 | ||
d3329ee5 | 33 | #include <wolfssl/wolfcrypt/asn.h> |
c92eade8 SP |
34 | |
35 | typedef struct private_private_key_t private_private_key_t; | |
36 | ||
37 | /** | |
38 | * Private data | |
39 | */ | |
40 | struct private_private_key_t { | |
41 | ||
42 | /** | |
43 | * Public interface | |
44 | */ | |
45 | private_key_t public; | |
46 | ||
47 | /** | |
48 | * Key object | |
49 | */ | |
142b5e79 TB |
50 | wolfssl_ed_key key; |
51 | ||
52 | /** | |
53 | * Key type | |
54 | */ | |
55 | key_type_t type; | |
c92eade8 SP |
56 | |
57 | /** | |
d3329ee5 | 58 | * Reference count |
c92eade8 SP |
59 | */ |
60 | refcount_t ref; | |
61 | }; | |
62 | ||
c92eade8 | 63 | /* from ed public key */ |
142b5e79 TB |
64 | int wolfssl_ed_keysize(key_type_t type); |
65 | bool wolfssl_ed_create(wolfssl_ed_key *key, key_type_t type); | |
66 | void wolfssl_ed_destroy(wolfssl_ed_key *key, key_type_t type); | |
67 | bool wolfssl_ed_public_key(wolfssl_ed_key *key, key_type_t type, chunk_t *raw); | |
68 | bool wolfssl_ed_fingerprint(wolfssl_ed_key *key, key_type_t key_type, | |
69 | cred_encoding_type_t type, chunk_t *fp); | |
c92eade8 SP |
70 | |
71 | METHOD(private_key_t, sign, bool, | |
72 | private_private_key_t *this, signature_scheme_t scheme, | |
73 | void *params, chunk_t data, chunk_t *signature) | |
74 | { | |
75 | word32 len; | |
c92eade8 | 76 | byte dummy[1]; |
142b5e79 | 77 | int ret = -1; |
c92eade8 | 78 | |
142b5e79 TB |
79 | if ((this->type == KEY_ED25519 && scheme != SIGN_ED25519) || |
80 | (this->type == KEY_ED448 && scheme != SIGN_ED448)) | |
c92eade8 SP |
81 | { |
82 | DBG1(DBG_LIB, "signature scheme %N not supported by %N key", | |
142b5e79 | 83 | signature_scheme_names, scheme, key_type_names, this->type); |
c92eade8 SP |
84 | return FALSE; |
85 | } | |
86 | ||
d3329ee5 | 87 | if (!data.ptr && !data.len) |
c92eade8 SP |
88 | { |
89 | data.ptr = dummy; | |
90 | } | |
91 | ||
142b5e79 TB |
92 | if (this->type == KEY_ED25519) |
93 | { | |
94 | #ifdef HAVE_ED25519 | |
95 | len = ED25519_SIG_SIZE; | |
96 | *signature = chunk_alloc(len); | |
97 | ret = wc_ed25519_sign_msg(data.ptr, data.len, signature->ptr, &len, | |
98 | &this->key.ed25519); | |
99 | #endif | |
100 | } | |
101 | else if (this->type == KEY_ED448) | |
102 | { | |
103 | #ifdef HAVE_ED448 | |
104 | len = ED448_SIG_SIZE; | |
105 | *signature = chunk_alloc(len); | |
106 | ret = wc_ed448_sign_msg(data.ptr, data.len, signature->ptr, &len, | |
107 | &this->key.ed448, NULL, 0); | |
108 | #endif | |
109 | } | |
c92eade8 SP |
110 | return ret == 0; |
111 | } | |
112 | ||
113 | METHOD(private_key_t, decrypt, bool, | |
114 | private_private_key_t *this, encryption_scheme_t scheme, | |
4abb29f6 | 115 | void *params, chunk_t crypto, chunk_t *plain) |
c92eade8 SP |
116 | { |
117 | DBG1(DBG_LIB, "EdDSA private key decryption not implemented"); | |
118 | return FALSE; | |
119 | } | |
120 | ||
121 | METHOD(private_key_t, get_keysize, int, | |
122 | private_private_key_t *this) | |
123 | { | |
142b5e79 | 124 | return wolfssl_ed_keysize(this->type); |
c92eade8 SP |
125 | } |
126 | ||
127 | METHOD(private_key_t, get_type, key_type_t, | |
128 | private_private_key_t *this) | |
129 | { | |
142b5e79 | 130 | return this->type; |
c92eade8 SP |
131 | } |
132 | ||
133 | METHOD(private_key_t, get_public_key, public_key_t*, | |
134 | private_private_key_t *this) | |
135 | { | |
136 | public_key_t *public; | |
137 | chunk_t key; | |
c92eade8 | 138 | |
142b5e79 | 139 | if (!wolfssl_ed_public_key(&this->key, this->type, &key)) |
c92eade8 | 140 | { |
c92eade8 SP |
141 | return NULL; |
142 | } | |
142b5e79 | 143 | public = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, this->type, |
c92eade8 | 144 | BUILD_EDDSA_PUB, key, BUILD_END); |
142b5e79 | 145 | chunk_free(&key); |
c92eade8 SP |
146 | return public; |
147 | } | |
148 | ||
149 | METHOD(private_key_t, get_fingerprint, bool, | |
150 | private_private_key_t *this, cred_encoding_type_t type, | |
151 | chunk_t *fingerprint) | |
152 | { | |
142b5e79 | 153 | return wolfssl_ed_fingerprint(&this->key, this->type, type, fingerprint); |
c92eade8 SP |
154 | } |
155 | ||
156 | METHOD(private_key_t, get_encoding, bool, | |
157 | private_private_key_t *this, cred_encoding_type_t type, chunk_t *encoding) | |
158 | { | |
142b5e79 | 159 | int ret = -1; |
c92eade8 SP |
160 | |
161 | switch (type) | |
162 | { | |
163 | case PRIVKEY_ASN1_DER: | |
164 | case PRIVKEY_PEM: | |
165 | { | |
166 | bool success = TRUE; | |
167 | ||
d3329ee5 | 168 | /* +4 is for the two octet strings */ |
142b5e79 TB |
169 | *encoding = chunk_empty; |
170 | if (this->type == KEY_ED25519) | |
171 | { | |
172 | #ifdef HAVE_ED25519 | |
173 | *encoding = chunk_alloc(ED25519_PRV_KEY_SIZE + 2 * MAX_SEQ_SZ + | |
174 | MAX_VERSION_SZ + MAX_ALGO_SZ + 4); | |
175 | ret = wc_Ed25519PrivateKeyToDer(&this->key.ed25519, | |
176 | encoding->ptr, encoding->len); | |
177 | #endif | |
178 | } | |
179 | else if (this->type == KEY_ED448) | |
180 | { | |
181 | #ifdef HAVE_ED448 | |
182 | *encoding = chunk_alloc(ED448_PRV_KEY_SIZE + 2 * MAX_SEQ_SZ + | |
183 | MAX_VERSION_SZ + MAX_ALGO_SZ + 4); | |
184 | ret = wc_Ed448PrivateKeyToDer(&this->key.ed448, encoding->ptr, | |
185 | encoding->len); | |
186 | #endif | |
187 | } | |
c92eade8 SP |
188 | if (ret < 0) |
189 | { | |
190 | chunk_free(encoding); | |
191 | return FALSE; | |
192 | } | |
193 | encoding->len = ret; | |
194 | ||
195 | if (type == PRIVKEY_PEM) | |
196 | { | |
197 | chunk_t asn1_encoding = *encoding; | |
198 | ||
199 | success = lib->encoding->encode(lib->encoding, PRIVKEY_PEM, | |
200 | NULL, encoding, CRED_PART_EDDSA_PRIV_ASN1_DER, | |
201 | asn1_encoding, CRED_PART_END); | |
202 | chunk_clear(&asn1_encoding); | |
203 | } | |
204 | return success; | |
205 | } | |
206 | default: | |
207 | return FALSE; | |
208 | } | |
209 | } | |
210 | ||
211 | METHOD(private_key_t, get_ref, private_key_t*, | |
212 | private_private_key_t *this) | |
213 | { | |
214 | ref_get(&this->ref); | |
215 | return &this->public; | |
216 | } | |
217 | ||
218 | METHOD(private_key_t, destroy, void, | |
219 | private_private_key_t *this) | |
220 | { | |
221 | if (ref_put(&this->ref)) | |
222 | { | |
223 | lib->encoding->clear_cache(lib->encoding, &this->key); | |
142b5e79 | 224 | wolfssl_ed_destroy(&this->key, this->type); |
c92eade8 SP |
225 | free(this); |
226 | } | |
227 | } | |
228 | ||
229 | /** | |
230 | * Internal generic constructor | |
231 | */ | |
142b5e79 | 232 | static private_private_key_t *create_internal(key_type_t type) |
c92eade8 SP |
233 | { |
234 | private_private_key_t *this; | |
235 | ||
236 | INIT(this, | |
237 | .public = { | |
238 | .get_type = _get_type, | |
239 | .sign = _sign, | |
240 | .decrypt = _decrypt, | |
241 | .get_keysize = _get_keysize, | |
242 | .get_public_key = _get_public_key, | |
243 | .equals = private_key_equals, | |
244 | .belongs_to = private_key_belongs_to, | |
245 | .get_fingerprint = _get_fingerprint, | |
246 | .has_fingerprint = private_key_has_fingerprint, | |
247 | .get_encoding = _get_encoding, | |
248 | .get_ref = _get_ref, | |
249 | .destroy = _destroy, | |
250 | }, | |
142b5e79 | 251 | .type = type, |
c92eade8 SP |
252 | .ref = 1, |
253 | ); | |
254 | ||
142b5e79 | 255 | if (!wolfssl_ed_create(&this->key, type)) |
c92eade8 SP |
256 | { |
257 | free(this); | |
258 | this = NULL; | |
259 | } | |
260 | return this; | |
261 | } | |
262 | ||
263 | /* | |
264 | * Described in header | |
265 | */ | |
266 | private_key_t *wolfssl_ed_private_key_gen(key_type_t type, va_list args) | |
267 | { | |
268 | private_private_key_t *this; | |
269 | WC_RNG rng; | |
142b5e79 | 270 | int ret = -1; |
c92eade8 | 271 | |
c92eade8 SP |
272 | while (TRUE) |
273 | { | |
274 | switch (va_arg(args, builder_part_t)) | |
275 | { | |
276 | case BUILD_KEY_SIZE: | |
277 | /* just ignore the key size */ | |
278 | va_arg(args, u_int); | |
279 | continue; | |
280 | case BUILD_END: | |
281 | break; | |
282 | default: | |
283 | return NULL; | |
284 | } | |
285 | break; | |
286 | } | |
287 | ||
142b5e79 | 288 | this = create_internal(type); |
d3329ee5 | 289 | if (!this) |
c92eade8 | 290 | { |
d3329ee5 | 291 | return NULL; |
c92eade8 | 292 | } |
d3329ee5 TB |
293 | |
294 | if (wc_InitRng(&rng) != 0) | |
c92eade8 | 295 | { |
d3329ee5 TB |
296 | DBG1(DBG_LIB, "initializing random failed"); |
297 | destroy(this); | |
c92eade8 SP |
298 | return NULL; |
299 | } | |
142b5e79 TB |
300 | |
301 | if (type == KEY_ED25519) | |
302 | { | |
303 | #ifdef HAVE_ED25519 | |
304 | ret = wc_ed25519_make_key(&rng, ED25519_KEY_SIZE, &this->key.ed25519); | |
305 | #endif | |
306 | } | |
307 | else if (type == KEY_ED448) | |
308 | { | |
309 | #ifdef HAVE_ED448 | |
310 | ret = wc_ed448_make_key(&rng, ED448_KEY_SIZE, &this->key.ed448); | |
311 | #endif | |
312 | } | |
c92eade8 | 313 | wc_FreeRng(&rng); |
d3329ee5 | 314 | |
c92eade8 SP |
315 | if (ret < 0) |
316 | { | |
317 | DBG1(DBG_LIB, "generating %N key failed", key_type_names, type); | |
318 | destroy(this); | |
319 | return NULL; | |
320 | } | |
c92eade8 SP |
321 | return &this->public; |
322 | } | |
323 | ||
d3329ee5 TB |
324 | /** |
325 | * Fix the internal state if only the private key is set | |
326 | */ | |
327 | static int set_public_key(private_private_key_t *this) | |
328 | { | |
329 | int ret = 0; | |
330 | ||
142b5e79 | 331 | if (this->type == KEY_ED25519) |
d3329ee5 | 332 | { |
142b5e79 TB |
333 | #ifdef HAVE_ED25519 |
334 | if (!this->key.ed25519.pubKeySet) | |
d3329ee5 | 335 | { |
142b5e79 TB |
336 | ret = wc_ed25519_make_public(&this->key.ed25519, |
337 | this->key.ed25519.p, ED25519_PUB_KEY_SIZE); | |
338 | if (ret == 0) | |
339 | { | |
340 | /* put public key after private key in the same buffer */ | |
341 | memmove(this->key.ed25519.k + ED25519_KEY_SIZE, | |
342 | this->key.ed25519.p, ED25519_PUB_KEY_SIZE); | |
343 | this->key.ed25519.pubKeySet = 1; | |
344 | } | |
345 | } | |
346 | #endif | |
347 | } | |
348 | else if (this->type == KEY_ED448) | |
349 | { | |
350 | #ifdef HAVE_ED448 | |
351 | if (!this->key.ed448.pubKeySet) | |
352 | { | |
353 | ret = wc_ed448_make_public(&this->key.ed448, this->key.ed448.p, | |
354 | ED448_PUB_KEY_SIZE); | |
355 | if (ret == 0) | |
356 | { | |
357 | /* put public key after private key in the same buffer */ | |
358 | memmove(this->key.ed448.k + ED448_KEY_SIZE, | |
359 | this->key.ed448.p, ED448_PUB_KEY_SIZE); | |
360 | this->key.ed448.pubKeySet = 1; | |
361 | } | |
d3329ee5 | 362 | } |
142b5e79 | 363 | #endif |
d3329ee5 TB |
364 | } |
365 | return ret; | |
366 | } | |
367 | ||
c92eade8 SP |
368 | /* |
369 | * Described in header | |
370 | */ | |
371 | private_key_t *wolfssl_ed_private_key_load(key_type_t type, va_list args) | |
372 | { | |
373 | private_private_key_t *this; | |
374 | chunk_t blob = chunk_empty, priv = chunk_empty; | |
375 | int idx; | |
376 | int ret = -1; | |
377 | ||
378 | while (TRUE) | |
379 | { | |
380 | switch (va_arg(args, builder_part_t)) | |
381 | { | |
382 | case BUILD_BLOB_ASN1_DER: | |
383 | blob = va_arg(args, chunk_t); | |
384 | continue; | |
385 | case BUILD_EDDSA_PRIV_ASN1_DER: | |
386 | priv = va_arg(args, chunk_t); | |
387 | continue; | |
388 | case BUILD_END: | |
389 | break; | |
390 | default: | |
391 | return NULL; | |
392 | } | |
393 | break; | |
394 | } | |
142b5e79 | 395 | this = create_internal(type); |
d3329ee5 | 396 | if (!this) |
c92eade8 SP |
397 | { |
398 | return NULL; | |
399 | } | |
400 | ||
142b5e79 | 401 | if (type == KEY_ED25519) |
c92eade8 | 402 | { |
142b5e79 TB |
403 | #ifdef HAVE_ED25519 |
404 | if (priv.len) | |
405 | { /* check for ASN.1 wrapped key (Octet String == 0x04) */ | |
406 | if (priv.len == ED25519_KEY_SIZE + 2 && | |
407 | priv.ptr[0] == 0x04 && priv.ptr[1] == ED25519_KEY_SIZE) | |
408 | { | |
409 | priv = chunk_skip(priv, 2); | |
410 | } | |
411 | ret = wc_ed25519_import_private_only(priv.ptr, priv.len, | |
412 | &this->key.ed25519); | |
413 | } | |
414 | else if (blob.len) | |
c92eade8 | 415 | { |
142b5e79 TB |
416 | idx = 0; |
417 | ret = wc_Ed25519PrivateKeyDecode(blob.ptr, &idx, &this->key.ed25519, | |
418 | blob.len); | |
c92eade8 | 419 | } |
142b5e79 | 420 | #endif |
c92eade8 | 421 | } |
142b5e79 | 422 | else if (type == KEY_ED448) |
c92eade8 | 423 | { |
142b5e79 TB |
424 | #ifdef HAVE_ED448 |
425 | if (priv.len) | |
426 | { /* check for ASN.1 wrapped key (Octet String == 0x04) */ | |
427 | if (priv.len == ED448_KEY_SIZE + 2 && | |
428 | priv.ptr[0] == 0x04 && priv.ptr[1] == ED448_KEY_SIZE) | |
429 | { | |
430 | priv = chunk_skip(priv, 2); | |
431 | } | |
432 | ret = wc_ed448_import_private_only(priv.ptr, priv.len, | |
433 | &this->key.ed448); | |
434 | } | |
435 | else if (blob.len) | |
436 | { | |
437 | idx = 0; | |
438 | ret = wc_Ed448PrivateKeyDecode(blob.ptr, &idx, &this->key.ed448, | |
439 | blob.len); | |
440 | } | |
441 | #endif | |
c92eade8 | 442 | } |
142b5e79 | 443 | |
d3329ee5 TB |
444 | if (ret == 0) |
445 | { | |
446 | ret = set_public_key(this); | |
447 | } | |
c92eade8 SP |
448 | if (ret != 0) |
449 | { | |
450 | destroy(this); | |
451 | return NULL; | |
452 | } | |
453 | return &this->public; | |
454 | } | |
455 | ||
456 | #endif /* HAVE_ED25519 */ |