2 * Copyright (C) 2020 Tobias Brunner
3 * HSR Hochschule fuer Technik Rapperswil
5 * Copyright (C) 2019 Sean Parkinson, wolfSSL Inc.
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 #include "wolfssl_common.h"
28 #if defined(HAVE_ED25519) || defined(HAVE_ED448)
30 #include "wolfssl_ed_private_key.h"
32 #include <utils/debug.h>
34 #include <wolfssl/wolfcrypt/asn.h>
36 typedef struct private_private_key_t private_private_key_t
;
41 struct private_private_key_t
{
64 /* from ed public key */
65 int wolfssl_ed_keysize(key_type_t type
);
66 bool wolfssl_ed_create(wolfssl_ed_key
*key
, key_type_t type
);
67 void wolfssl_ed_destroy(wolfssl_ed_key
*key
, key_type_t type
);
68 bool wolfssl_ed_public_key(wolfssl_ed_key
*key
, key_type_t type
, chunk_t
*raw
);
69 bool wolfssl_ed_fingerprint(wolfssl_ed_key
*key
, key_type_t key_type
,
70 cred_encoding_type_t type
, chunk_t
*fp
);
72 METHOD(private_key_t
, sign
, bool,
73 private_private_key_t
*this, signature_scheme_t scheme
,
74 void *params
, chunk_t data
, chunk_t
*signature
)
80 if ((this->type
== KEY_ED25519
&& scheme
!= SIGN_ED25519
) ||
81 (this->type
== KEY_ED448
&& scheme
!= SIGN_ED448
))
83 DBG1(DBG_LIB
, "signature scheme %N not supported by %N key",
84 signature_scheme_names
, scheme
, key_type_names
, this->type
);
88 if (!data
.ptr
&& !data
.len
)
93 if (this->type
== KEY_ED25519
)
96 len
= ED25519_SIG_SIZE
;
97 *signature
= chunk_alloc(len
);
98 ret
= wc_ed25519_sign_msg(data
.ptr
, data
.len
, signature
->ptr
, &len
,
102 else if (this->type
== KEY_ED448
)
105 len
= ED448_SIG_SIZE
;
106 *signature
= chunk_alloc(len
);
107 ret
= wc_ed448_sign_msg(data
.ptr
, data
.len
, signature
->ptr
, &len
,
108 &this->key
.ed448
, NULL
, 0);
114 METHOD(private_key_t
, decrypt
, bool,
115 private_private_key_t
*this, encryption_scheme_t scheme
,
116 chunk_t crypto
, chunk_t
*plain
)
118 DBG1(DBG_LIB
, "EdDSA private key decryption not implemented");
122 METHOD(private_key_t
, get_keysize
, int,
123 private_private_key_t
*this)
125 return wolfssl_ed_keysize(this->type
);
128 METHOD(private_key_t
, get_type
, key_type_t
,
129 private_private_key_t
*this)
134 METHOD(private_key_t
, get_public_key
, public_key_t
*,
135 private_private_key_t
*this)
137 public_key_t
*public;
140 if (!wolfssl_ed_public_key(&this->key
, this->type
, &key
))
144 public = lib
->creds
->create(lib
->creds
, CRED_PUBLIC_KEY
, this->type
,
145 BUILD_EDDSA_PUB
, key
, BUILD_END
);
150 METHOD(private_key_t
, get_fingerprint
, bool,
151 private_private_key_t
*this, cred_encoding_type_t type
,
152 chunk_t
*fingerprint
)
154 return wolfssl_ed_fingerprint(&this->key
, this->type
, type
, fingerprint
);
157 METHOD(private_key_t
, get_encoding
, bool,
158 private_private_key_t
*this, cred_encoding_type_t type
, chunk_t
*encoding
)
164 case PRIVKEY_ASN1_DER
:
169 /* +4 is for the two octet strings */
170 *encoding
= chunk_empty
;
171 if (this->type
== KEY_ED25519
)
174 *encoding
= chunk_alloc(ED25519_PRV_KEY_SIZE
+ 2 * MAX_SEQ_SZ
+
175 MAX_VERSION_SZ
+ MAX_ALGO_SZ
+ 4);
176 ret
= wc_Ed25519PrivateKeyToDer(&this->key
.ed25519
,
177 encoding
->ptr
, encoding
->len
);
180 else if (this->type
== KEY_ED448
)
183 *encoding
= chunk_alloc(ED448_PRV_KEY_SIZE
+ 2 * MAX_SEQ_SZ
+
184 MAX_VERSION_SZ
+ MAX_ALGO_SZ
+ 4);
185 ret
= wc_Ed448PrivateKeyToDer(&this->key
.ed448
, encoding
->ptr
,
191 chunk_free(encoding
);
196 if (type
== PRIVKEY_PEM
)
198 chunk_t asn1_encoding
= *encoding
;
200 success
= lib
->encoding
->encode(lib
->encoding
, PRIVKEY_PEM
,
201 NULL
, encoding
, CRED_PART_EDDSA_PRIV_ASN1_DER
,
202 asn1_encoding
, CRED_PART_END
);
203 chunk_clear(&asn1_encoding
);
212 METHOD(private_key_t
, get_ref
, private_key_t
*,
213 private_private_key_t
*this)
216 return &this->public;
219 METHOD(private_key_t
, destroy
, void,
220 private_private_key_t
*this)
222 if (ref_put(&this->ref
))
224 lib
->encoding
->clear_cache(lib
->encoding
, &this->key
);
225 wolfssl_ed_destroy(&this->key
, this->type
);
231 * Internal generic constructor
233 static private_private_key_t
*create_internal(key_type_t type
)
235 private_private_key_t
*this;
239 .get_type
= _get_type
,
242 .get_keysize
= _get_keysize
,
243 .get_public_key
= _get_public_key
,
244 .equals
= private_key_equals
,
245 .belongs_to
= private_key_belongs_to
,
246 .get_fingerprint
= _get_fingerprint
,
247 .has_fingerprint
= private_key_has_fingerprint
,
248 .get_encoding
= _get_encoding
,
256 if (!wolfssl_ed_create(&this->key
, type
))
265 * Described in header
267 private_key_t
*wolfssl_ed_private_key_gen(key_type_t type
, va_list args
)
269 private_private_key_t
*this;
275 switch (va_arg(args
, builder_part_t
))
278 /* just ignore the key size */
289 this = create_internal(type
);
295 if (wc_InitRng(&rng
) != 0)
297 DBG1(DBG_LIB
, "initializing random failed");
302 if (type
== KEY_ED25519
)
305 ret
= wc_ed25519_make_key(&rng
, ED25519_KEY_SIZE
, &this->key
.ed25519
);
308 else if (type
== KEY_ED448
)
311 ret
= wc_ed448_make_key(&rng
, ED448_KEY_SIZE
, &this->key
.ed448
);
318 DBG1(DBG_LIB
, "generating %N key failed", key_type_names
, type
);
322 return &this->public;
326 * Fix the internal state if only the private key is set
328 static int set_public_key(private_private_key_t
*this)
332 if (this->type
== KEY_ED25519
)
335 if (!this->key
.ed25519
.pubKeySet
)
337 ret
= wc_ed25519_make_public(&this->key
.ed25519
,
338 this->key
.ed25519
.p
, ED25519_PUB_KEY_SIZE
);
341 /* put public key after private key in the same buffer */
342 memmove(this->key
.ed25519
.k
+ ED25519_KEY_SIZE
,
343 this->key
.ed25519
.p
, ED25519_PUB_KEY_SIZE
);
344 this->key
.ed25519
.pubKeySet
= 1;
349 else if (this->type
== KEY_ED448
)
352 if (!this->key
.ed448
.pubKeySet
)
354 ret
= wc_ed448_make_public(&this->key
.ed448
, this->key
.ed448
.p
,
358 /* put public key after private key in the same buffer */
359 memmove(this->key
.ed448
.k
+ ED448_KEY_SIZE
,
360 this->key
.ed448
.p
, ED448_PUB_KEY_SIZE
);
361 this->key
.ed448
.pubKeySet
= 1;
370 * Described in header
372 private_key_t
*wolfssl_ed_private_key_load(key_type_t type
, va_list args
)
374 private_private_key_t
*this;
375 chunk_t blob
= chunk_empty
, priv
= chunk_empty
;
381 switch (va_arg(args
, builder_part_t
))
383 case BUILD_BLOB_ASN1_DER
:
384 blob
= va_arg(args
, chunk_t
);
386 case BUILD_EDDSA_PRIV_ASN1_DER
:
387 priv
= va_arg(args
, chunk_t
);
396 this = create_internal(type
);
402 if (type
== KEY_ED25519
)
406 { /* check for ASN.1 wrapped key (Octet String == 0x04) */
407 if (priv
.len
== ED25519_KEY_SIZE
+ 2 &&
408 priv
.ptr
[0] == 0x04 && priv
.ptr
[1] == ED25519_KEY_SIZE
)
410 priv
= chunk_skip(priv
, 2);
412 ret
= wc_ed25519_import_private_only(priv
.ptr
, priv
.len
,
418 ret
= wc_Ed25519PrivateKeyDecode(blob
.ptr
, &idx
, &this->key
.ed25519
,
423 else if (type
== KEY_ED448
)
427 { /* check for ASN.1 wrapped key (Octet String == 0x04) */
428 if (priv
.len
== ED448_KEY_SIZE
+ 2 &&
429 priv
.ptr
[0] == 0x04 && priv
.ptr
[1] == ED448_KEY_SIZE
)
431 priv
= chunk_skip(priv
, 2);
433 ret
= wc_ed448_import_private_only(priv
.ptr
, priv
.len
,
439 ret
= wc_Ed448PrivateKeyDecode(blob
.ptr
, &idx
, &this->key
.ed448
,
447 ret
= set_public_key(this);
454 return &this->public;
457 #endif /* HAVE_ED25519 */