2 * Copyright (C) 2018 Tobias Brunner
3 * HSR Hochschule fuer Technik Rapperswil
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 #include <openssl/evp.h>
18 #if OPENSSL_VERSION_NUMBER >= 0x1010100fL && !defined(OPENSSL_NO_EC)
20 #include "openssl_ed_private_key.h"
22 #include <utils/debug.h>
24 typedef struct private_private_key_t private_private_key_t
;
29 struct private_private_key_t
{
47 * TRUE if the key is from an OpenSSL ENGINE and might not be readable
58 * We can't include asn1.h, declare function prototype directly
60 int asn1_unwrap(chunk_t
*, chunk_t
*);
62 /* from ed public key */
63 int openssl_ed_key_type(key_type_t type
);
64 int openssl_ed_keysize(key_type_t type
);
65 bool openssl_ed_fingerprint(EVP_PKEY
*key
, cred_encoding_type_t type
, chunk_t
*fp
);
67 METHOD(private_key_t
, sign
, bool,
68 private_private_key_t
*this, signature_scheme_t scheme
,
69 void *params
, chunk_t data
, chunk_t
*signature
)
74 if ((this->type
== KEY_ED25519
&& scheme
!= SIGN_ED25519
) ||
75 (this->type
== KEY_ED448
&& scheme
!= SIGN_ED448
))
77 DBG1(DBG_LIB
, "signature scheme %N not supported by %N key",
78 signature_scheme_names
, scheme
, key_type_names
, this->type
);
82 ctx
= EVP_MD_CTX_new();
84 EVP_DigestSignInit(ctx
, NULL
, NULL
, NULL
, this->key
) <= 0)
89 if (EVP_DigestSign(ctx
, NULL
, &signature
->len
, data
.ptr
, data
.len
) <= 0)
94 *signature
= chunk_alloc(signature
->len
);
96 if (EVP_DigestSign(ctx
, signature
->ptr
, &signature
->len
,
97 data
.ptr
, data
.len
) <= 0)
105 EVP_MD_CTX_free(ctx
);
109 METHOD(private_key_t
, decrypt
, bool,
110 private_private_key_t
*this, encryption_scheme_t scheme
,
111 void *params
, chunk_t crypto
, chunk_t
*plain
)
113 DBG1(DBG_LIB
, "EdDSA private key decryption not implemented");
117 METHOD(private_key_t
, get_keysize
, int,
118 private_private_key_t
*this)
120 return openssl_ed_keysize(this->type
);
123 METHOD(private_key_t
, get_type
, key_type_t
,
124 private_private_key_t
*this)
129 METHOD(private_key_t
, get_public_key
, public_key_t
*,
130 private_private_key_t
*this)
132 public_key_t
*public;
135 if (!EVP_PKEY_get_raw_public_key(this->key
, NULL
, &key
.len
))
139 key
= chunk_alloca(key
.len
);
140 if (!EVP_PKEY_get_raw_public_key(this->key
, key
.ptr
, &key
.len
))
144 public = lib
->creds
->create(lib
->creds
, CRED_PUBLIC_KEY
, this->type
,
145 BUILD_EDDSA_PUB
, key
, BUILD_END
);
149 METHOD(private_key_t
, get_fingerprint
, bool,
150 private_private_key_t
*this, cred_encoding_type_t type
,
151 chunk_t
*fingerprint
)
153 return openssl_ed_fingerprint(this->key
, type
, fingerprint
);
156 METHOD(private_key_t
, get_encoding
, bool,
157 private_private_key_t
*this, cred_encoding_type_t type
, chunk_t
*encoding
)
168 case PRIVKEY_ASN1_DER
:
173 *encoding
= chunk_alloc(i2d_PrivateKey(this->key
, NULL
));
175 i2d_PrivateKey(this->key
, &p
);
177 if (type
== PRIVKEY_PEM
)
179 chunk_t asn1_encoding
= *encoding
;
181 success
= lib
->encoding
->encode(lib
->encoding
, PRIVKEY_PEM
,
182 NULL
, encoding
, CRED_PART_EDDSA_PRIV_ASN1_DER
,
183 asn1_encoding
, CRED_PART_END
);
184 chunk_clear(&asn1_encoding
);
193 METHOD(private_key_t
, get_ref
, private_key_t
*,
194 private_private_key_t
*this)
197 return &this->public;
200 METHOD(private_key_t
, destroy
, void,
201 private_private_key_t
*this)
203 if (ref_put(&this->ref
))
205 lib
->encoding
->clear_cache(lib
->encoding
, this->key
);
206 EVP_PKEY_free(this->key
);
212 * Internal generic constructor
214 static private_private_key_t
*create_internal(key_type_t type
, EVP_PKEY
*key
)
216 private_private_key_t
*this;
220 .get_type
= _get_type
,
223 .get_keysize
= _get_keysize
,
224 .get_public_key
= _get_public_key
,
225 .equals
= private_key_equals
,
226 .belongs_to
= private_key_belongs_to
,
227 .get_fingerprint
= _get_fingerprint
,
228 .has_fingerprint
= private_key_has_fingerprint
,
229 .get_encoding
= _get_encoding
,
242 * Described in header
244 private_key_t
*openssl_ed_private_key_create(EVP_PKEY
*key
, bool engine
)
246 private_private_key_t
*this;
249 switch (EVP_PKEY_base_id(key
))
251 case EVP_PKEY_ED25519
:
262 this = create_internal(type
, key
);
263 this->engine
= engine
;
264 return &this->public;
268 * Described in header
270 private_key_t
*openssl_ed_private_key_gen(key_type_t type
, va_list args
)
272 private_private_key_t
*this;
274 EVP_PKEY
*key
= NULL
;
278 switch (va_arg(args
, builder_part_t
))
281 /* just ignore the key size */
292 ctx
= EVP_PKEY_CTX_new_id(openssl_ed_key_type(type
), NULL
);
294 EVP_PKEY_keygen_init(ctx
) <= 0 ||
295 EVP_PKEY_keygen(ctx
, &key
) <= 0)
297 DBG1(DBG_LIB
, "generating %N key failed", key_type_names
, type
);
298 EVP_PKEY_CTX_free(ctx
);
301 EVP_PKEY_CTX_free(ctx
);
303 this = create_internal(type
, key
);
304 return &this->public;
308 * Described in header
310 private_key_t
*openssl_ed_private_key_load(key_type_t type
, va_list args
)
312 private_private_key_t
*this;
313 chunk_t blob
= chunk_empty
, priv
= chunk_empty
;
314 EVP_PKEY
*key
= NULL
;
318 switch (va_arg(args
, builder_part_t
))
320 case BUILD_BLOB_ASN1_DER
:
321 blob
= va_arg(args
, chunk_t
);
323 case BUILD_EDDSA_PRIV_ASN1_DER
:
324 priv
= va_arg(args
, chunk_t
);
336 /* unwrap octet string */
337 if (asn1_unwrap(&priv
, &priv
) == 0x04 && priv
.len
)
339 key
= EVP_PKEY_new_raw_private_key(openssl_ed_key_type(type
), NULL
,
345 key
= d2i_PrivateKey(openssl_ed_key_type(type
), NULL
,
346 (const u_char
**)&blob
.ptr
, blob
.len
);
352 this = create_internal(type
, key
);
353 return &this->public;
356 #endif /* OPENSSL_NO_ECDSA */