diff options
author | Andreas Steffen <andreas.steffen@strongswan.org> | 2016-11-14 12:37:23 +0100 |
---|---|---|
committer | Tobias Brunner <tobias@strongswan.org> | 2016-12-14 11:15:47 +0100 |
commit | 35bc60cc68ea8adf21504a422d7ec4e0c5aed353 (patch) | |
tree | e0ae0448d10d9087ac4286277af43d02c6c2050b /src/libstrongswan | |
parent | 564a19967477adb60e018609d3ab76c554705f08 (diff) | |
download | strongswan-35bc60cc68ea8adf21504a422d7ec4e0c5aed353.tar.bz2 strongswan-35bc60cc68ea8adf21504a422d7ec4e0c5aed353.tar.xz |
Added support of EdDSA signatures
Diffstat (limited to 'src/libstrongswan')
23 files changed, 857 insertions, 35 deletions
diff --git a/src/libstrongswan/asn1/asn1.c b/src/libstrongswan/asn1/asn1.c index 2ee414abf..5ce840325 100644 --- a/src/libstrongswan/asn1/asn1.c +++ b/src/libstrongswan/asn1/asn1.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2006 Martin Will - * Copyright (C) 2000-2008 Andreas Steffen + * Copyright (C) 2000-2016 Andreas Steffen * * Hochschule fuer Technik Rapperswil * @@ -47,6 +47,8 @@ chunk_t asn1_algorithmIdentifier(int oid) case OID_ECDSA_WITH_SHA256: case OID_ECDSA_WITH_SHA384: case OID_ECDSA_WITH_SHA512: + case OID_ED25519: + case OID_ED448: parameters = chunk_empty; break; default: diff --git a/src/libstrongswan/asn1/oid.txt b/src/libstrongswan/asn1/oid.txt index 761a38ab6..a0c2aada3 100644 --- a/src/libstrongswan/asn1/oid.txt +++ b/src/libstrongswan/asn1/oid.txt @@ -382,6 +382,9 @@ 0x0C "brainpoolP384t1" 0x0D "brainpoolP512r1" 0x0E "brainpoolP512t1" + 0x65 "Thawte" + 0x70 "id-Ed25519" OID_ED25519 + 0x71 "id-Ed448" OID_ED448 0x81 "" 0x04 "Certicom" 0x00 "curve" diff --git a/src/libstrongswan/credentials/builder.c b/src/libstrongswan/credentials/builder.c index ddb64ef88..243dfd7cf 100644 --- a/src/libstrongswan/credentials/builder.c +++ b/src/libstrongswan/credentials/builder.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2008 Martin Willi - * Hochschule fuer Technik Rapperswil + * Copyright (C) 2016 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -70,5 +71,6 @@ ENUM(builder_part_names, BUILD_FROM_FILE, BUILD_END, "BUILD_SAFE_PRIMES", "BUILD_SHARES", "BUILD_THRESHOLD", + "BUILD_EDDSA_PRIV_ASN1_DER", "BUILD_END", ); diff --git a/src/libstrongswan/credentials/builder.h b/src/libstrongswan/credentials/builder.h index 627e0934d..7d1139348 100644 --- a/src/libstrongswan/credentials/builder.h +++ b/src/libstrongswan/credentials/builder.h @@ -1,6 +1,7 @@ /* * Copyright (C) 2008 Martin Willi - * Hochschule fuer Technik Rapperswil + * Copyright (C) 2016 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -151,6 +152,8 @@ enum builder_part_t { BUILD_SHARES, /** minimum number of participating private key shares */ BUILD_THRESHOLD, + /** DER encoded ASN.1 EdDSA private key */ + BUILD_EDDSA_PRIV_ASN1_DER, /** end of variable argument builder list */ BUILD_END, }; diff --git a/src/libstrongswan/credentials/cred_encoding.h b/src/libstrongswan/credentials/cred_encoding.h index b4d1f4c3c..0b6536430 100644 --- a/src/libstrongswan/credentials/cred_encoding.h +++ b/src/libstrongswan/credentials/cred_encoding.h @@ -144,6 +144,10 @@ enum cred_encoding_part_t { CRED_PART_PKCS10_ASN1_DER, /** a PGP encoded certificate */ CRED_PART_PGP_CERT, + /** a DER encoded EdDSA public key */ + CRED_PART_EDDSA_PUB_ASN1_DER, + /** a DER encoded EdDSA private key */ + CRED_PART_EDDSA_PRIV_ASN1_DER, /** a DER encoded BLISS public key */ CRED_PART_BLISS_PUB_ASN1_DER, /** a DER encoded BLISS private key */ diff --git a/src/libstrongswan/credentials/keys/public_key.c b/src/libstrongswan/credentials/keys/public_key.c index 03f93b1d3..2c76ad680 100644 --- a/src/libstrongswan/credentials/keys/public_key.c +++ b/src/libstrongswan/credentials/keys/public_key.c @@ -24,6 +24,8 @@ ENUM(key_type_names, KEY_ANY, KEY_BLISS, "RSA", "ECDSA", "DSA", + "ED25519", + "ED448", "BLISS" ); @@ -48,6 +50,8 @@ ENUM(signature_scheme_names, SIGN_UNKNOWN, SIGN_BLISS_WITH_SHA3_512, "ECDSA-256", "ECDSA-384", "ECDSA-521", + "ED25519", + "ED448", "BLISS_WITH_SHA2_256", "BLISS_WITH_SHA2_384", "BLISS_WITH_SHA2_512", @@ -151,6 +155,10 @@ signature_scheme_t signature_scheme_from_oid(int oid) return SIGN_ECDSA_WITH_SHA384_DER; case OID_ECDSA_WITH_SHA512: return SIGN_ECDSA_WITH_SHA512_DER; + case OID_ED25519: + return SIGN_ED25519; + case OID_ED448: + return SIGN_ED448; case OID_BLISS_PUBLICKEY: case OID_BLISS_WITH_SHA2_512: return SIGN_BLISS_WITH_SHA2_512; @@ -210,6 +218,10 @@ int signature_scheme_to_oid(signature_scheme_t scheme) return OID_ECDSA_WITH_SHA384; case SIGN_ECDSA_WITH_SHA512_DER: return OID_ECDSA_WITH_SHA512; + case SIGN_ED25519: + return OID_ED25519; + case SIGN_ED448: + return OID_ED448; case SIGN_BLISS_WITH_SHA2_256: return OID_BLISS_WITH_SHA2_256; case SIGN_BLISS_WITH_SHA2_384: @@ -236,15 +248,17 @@ static struct { key_type_t type; int max_keysize; } scheme_map[] = { - { SIGN_RSA_EMSA_PKCS1_SHA2_256, KEY_RSA, 3072 }, - { SIGN_RSA_EMSA_PKCS1_SHA2_384, KEY_RSA, 7680 }, - { SIGN_RSA_EMSA_PKCS1_SHA2_512, KEY_RSA, 0 }, - { SIGN_ECDSA_WITH_SHA256_DER, KEY_ECDSA, 256 }, - { SIGN_ECDSA_WITH_SHA384_DER, KEY_ECDSA, 384 }, - { SIGN_ECDSA_WITH_SHA512_DER, KEY_ECDSA, 0 }, - { SIGN_BLISS_WITH_SHA2_256, KEY_BLISS, 128 }, - { SIGN_BLISS_WITH_SHA2_384, KEY_BLISS, 192 }, - { SIGN_BLISS_WITH_SHA2_512, KEY_BLISS, 0 } + { SIGN_RSA_EMSA_PKCS1_SHA2_256, KEY_RSA, 3072 }, + { SIGN_RSA_EMSA_PKCS1_SHA2_384, KEY_RSA, 7680 }, + { SIGN_RSA_EMSA_PKCS1_SHA2_512, KEY_RSA, 0 }, + { SIGN_ECDSA_WITH_SHA256_DER, KEY_ECDSA, 256 }, + { SIGN_ECDSA_WITH_SHA384_DER, KEY_ECDSA, 384 }, + { SIGN_ECDSA_WITH_SHA512_DER, KEY_ECDSA, 0 }, + { SIGN_ED25519, KEY_ED25519, 0 }, + { SIGN_ED448, KEY_ED448, 0 }, + { SIGN_BLISS_WITH_SHA2_256, KEY_BLISS, 128 }, + { SIGN_BLISS_WITH_SHA2_384, KEY_BLISS, 192 }, + { SIGN_BLISS_WITH_SHA2_512, KEY_BLISS, 0 } }; /** @@ -323,6 +337,10 @@ key_type_t key_type_from_signature_scheme(signature_scheme_t scheme) case SIGN_ECDSA_384: case SIGN_ECDSA_521: return KEY_ECDSA; + case SIGN_ED25519: + return KEY_ED25519; + case SIGN_ED448: + return KEY_ED448; case SIGN_BLISS_WITH_SHA2_256: case SIGN_BLISS_WITH_SHA2_384: case SIGN_BLISS_WITH_SHA2_512: diff --git a/src/libstrongswan/credentials/keys/public_key.h b/src/libstrongswan/credentials/keys/public_key.h index 236128234..a8958fd98 100644 --- a/src/libstrongswan/credentials/keys/public_key.h +++ b/src/libstrongswan/credentials/keys/public_key.h @@ -37,16 +37,19 @@ typedef enum encryption_scheme_t encryption_scheme_t; */ enum key_type_t { /** key type wildcard */ - KEY_ANY = 0, + KEY_ANY = 0, /** RSA crypto system as in PKCS#1 */ - KEY_RSA = 1, + KEY_RSA = 1, /** ECDSA as in ANSI X9.62 */ - KEY_ECDSA = 2, + KEY_ECDSA = 2, /** DSA */ - KEY_DSA = 3, + KEY_DSA = 3, + /** Ed25519 PureEdDSA instance as in draft-irtf-cfrg-eddsa */ + KEY_ED25519 = 4, + /** Ed448 PureEdDSA instance as in draft-irtf-cfrg-eddsa */ + KEY_ED448 = 5, /** BLISS */ - KEY_BLISS = 4, - /** ElGamal, ... */ + KEY_BLISS = 6, }; /** @@ -102,6 +105,10 @@ enum signature_scheme_t { SIGN_ECDSA_384, /** ECDSA on the P-521 curve with SHA-512 as in RFC 4754 */ SIGN_ECDSA_521, + /** PureEdDSA on Curve25519 as in draft-ietf-curdle-pkix */ + SIGN_ED25519, + /** PureEdDSA on Curve448 as in draft-ietf-curdle-pkix */ + SIGN_ED448, /** BLISS with SHA-2_256 */ SIGN_BLISS_WITH_SHA2_256, /** BLISS with SHA-2_384 */ diff --git a/src/libstrongswan/crypto/hashers/hasher.c b/src/libstrongswan/crypto/hashers/hasher.c index d136799d7..aab18ecf1 100644 --- a/src/libstrongswan/crypto/hashers/hasher.c +++ b/src/libstrongswan/crypto/hashers/hasher.c @@ -20,7 +20,8 @@ #include <asn1/oid.h> -ENUM_BEGIN(hash_algorithm_names, HASH_SHA1, HASH_SHA512, +ENUM_BEGIN(hash_algorithm_names, HASH_IDENTITY, HASH_SHA512, + "HASH_IDENTITY", "HASH_SHA1", "HASH_SHA256", "HASH_SHA384", @@ -37,7 +38,8 @@ ENUM_NEXT(hash_algorithm_names, HASH_UNKNOWN, HASH_SHA3_512, HASH_SHA512, "HASH_SHA3_512"); ENUM_END(hash_algorithm_names, HASH_SHA3_512); -ENUM_BEGIN(hash_algorithm_short_names, HASH_SHA1, HASH_SHA512, +ENUM_BEGIN(hash_algorithm_short_names, HASH_IDENTITY, HASH_SHA512, + "identity", "sha1", "sha256", "sha384", @@ -94,6 +96,9 @@ hash_algorithm_t hasher_algorithm_from_oid(int oid) case OID_SHA3_512: case OID_RSASSA_PKCS1V15_WITH_SHA3_512: return HASH_SHA3_512; + case OID_ED25519: + case OID_ED448: + return HASH_IDENTITY; default: return HASH_UNKNOWN; } @@ -267,6 +272,7 @@ integrity_algorithm_t hasher_algorithm_to_integrity(hash_algorithm_t alg, case HASH_SHA3_256: case HASH_SHA3_384: case HASH_SHA3_512: + case HASH_IDENTITY: case HASH_UNKNOWN: break; } @@ -280,6 +286,7 @@ bool hasher_algorithm_for_ikev2(hash_algorithm_t alg) { switch (alg) { + case HASH_IDENTITY: case HASH_SHA1: case HASH_SHA256: case HASH_SHA384: @@ -396,6 +403,22 @@ int hasher_signature_algorithm_to_oid(hash_algorithm_t alg, key_type_t key) default: return OID_UNKNOWN; } + case KEY_ED25519: + switch (alg) + { + case HASH_IDENTITY: + return OID_ED25519; + default: + return OID_UNKNOWN; + } + case KEY_ED448: + switch (alg) + { + case HASH_IDENTITY: + return OID_ED448; + default: + return OID_UNKNOWN; + } case KEY_BLISS: switch (alg) { @@ -430,6 +453,9 @@ hash_algorithm_t hasher_from_signature_scheme(signature_scheme_t scheme) case SIGN_RSA_EMSA_PKCS1_NULL: case SIGN_ECDSA_WITH_NULL: break; + case SIGN_ED25519: + case SIGN_ED448: + return HASH_IDENTITY; case SIGN_RSA_EMSA_PKCS1_MD5: return HASH_MD5; case SIGN_RSA_EMSA_PKCS1_SHA1: diff --git a/src/libstrongswan/crypto/hashers/hasher.h b/src/libstrongswan/crypto/hashers/hasher.h index 2d28b207d..8cd9b1346 100644 --- a/src/libstrongswan/crypto/hashers/hasher.h +++ b/src/libstrongswan/crypto/hashers/hasher.h @@ -1,8 +1,9 @@ /* + * Copyright (C) 2016 Andreas Steffen * Copyright (C) 2012-2015 Tobias Brunner * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -35,6 +36,7 @@ typedef struct hasher_t hasher_t; * Hash algorithms as defined for IKEv2 by RFC 7427 */ enum hash_algorithm_t { + HASH_IDENTITY = 0, HASH_SHA1 = 1, HASH_SHA256 = 2, HASH_SHA384 = 3, diff --git a/src/libstrongswan/plugins/curve25519/Makefile.am b/src/libstrongswan/plugins/curve25519/Makefile.am index e97a61c2c..d5d260bdd 100644 --- a/src/libstrongswan/plugins/curve25519/Makefile.am +++ b/src/libstrongswan/plugins/curve25519/Makefile.am @@ -14,6 +14,8 @@ libstrongswan_curve25519_la_SOURCES = \ curve25519_dh.h curve25519_dh.c \ curve25519_drv.h curve25519_drv.c \ curve25519_drv_portable.h curve25519_drv_portable.c \ + curve25519_private_key.h curve25519_private_key.c \ + curve25519_public_key.h curve25519_public_key.c \ curve25519_plugin.h curve25519_plugin.c libstrongswan_curve25519_la_LDFLAGS = -module -avoid-version diff --git a/src/libstrongswan/plugins/curve25519/curve25519_drv.h b/src/libstrongswan/plugins/curve25519/curve25519_drv.h index c172580bc..bdf0c4c29 100644 --- a/src/libstrongswan/plugins/curve25519/curve25519_drv.h +++ b/src/libstrongswan/plugins/curve25519/curve25519_drv.h @@ -15,7 +15,7 @@ /** * @defgroup curve25519_drv curve25519_drv - * @{ @ingroup curve25519 + * @{ @ingroup curve25519_p */ #ifndef CURVE25519_DRV_H_ diff --git a/src/libstrongswan/plugins/curve25519/curve25519_drv_portable.h b/src/libstrongswan/plugins/curve25519/curve25519_drv_portable.h index 45ad1d904..f0de0bd1c 100644 --- a/src/libstrongswan/plugins/curve25519/curve25519_drv_portable.h +++ b/src/libstrongswan/plugins/curve25519/curve25519_drv_portable.h @@ -15,7 +15,7 @@ /** * @defgroup curve25519_drv_portable curve25519_drv_portable - * @{ @ingroup curve25519 + * @{ @ingroup curve25519_p */ #include "curve25519_drv.h" diff --git a/src/libstrongswan/plugins/curve25519/curve25519_plugin.c b/src/libstrongswan/plugins/curve25519/curve25519_plugin.c index 06c540a82..0b1e59e97 100644 --- a/src/libstrongswan/plugins/curve25519/curve25519_plugin.c +++ b/src/libstrongswan/plugins/curve25519/curve25519_plugin.c @@ -2,6 +2,9 @@ * Copyright (C) 2014 Martin Willi * Copyright (C) 2014 revosec AG * + * Copyright (C) 2016 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your @@ -15,6 +18,8 @@ #include "curve25519_plugin.h" #include "curve25519_dh.h" +#include "curve25519_private_key.h" +#include "curve25519_public_key.h" #include <library.h> @@ -41,9 +46,25 @@ METHOD(plugin_t, get_features, int, private_curve25519_plugin_t *this, plugin_feature_t *features[]) { static plugin_feature_t f[] = { + /* X25519 DH group */ PLUGIN_REGISTER(DH, curve25519_dh_create), PLUGIN_PROVIDE(DH, CURVE_25519), PLUGIN_DEPENDS(RNG, RNG_STRONG), + /* Ed25519 private/public keys */ + PLUGIN_REGISTER(PRIVKEY, curve25519_private_key_load, TRUE), + PLUGIN_PROVIDE(PRIVKEY, KEY_ED25519), + PLUGIN_REGISTER(PRIVKEY_GEN, curve25519_private_key_gen, FALSE), + PLUGIN_PROVIDE(PRIVKEY_GEN, KEY_ED25519), + PLUGIN_DEPENDS(RNG, RNG_TRUE), + PLUGIN_DEPENDS(HASHER, HASH_SHA512), + PLUGIN_REGISTER(PUBKEY, curve25519_public_key_load, TRUE), + PLUGIN_PROVIDE(PUBKEY, KEY_ED25519), + /* Ed25519 signature scheme, private */ + PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_ED25519), + PLUGIN_DEPENDS(HASHER, HASH_SHA512), + /* Ed25519 signature verification scheme, public */ + PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_ED25519), + PLUGIN_DEPENDS(HASHER, HASH_SHA512), }; *features = f; return countof(f); diff --git a/src/libstrongswan/plugins/curve25519/curve25519_private_key.c b/src/libstrongswan/plugins/curve25519/curve25519_private_key.c new file mode 100644 index 000000000..05216226d --- /dev/null +++ b/src/libstrongswan/plugins/curve25519/curve25519_private_key.c @@ -0,0 +1,287 @@ +/* + * Copyright (C) 2016 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "curve25519_private_key.h" +#include "curve25519_public_key.h" + +#include <asn1/asn1.h> +#include <asn1/oid.h> + +#define _GNU_SOURCE +#include <stdlib.h> + +typedef struct private_curve25519_private_key_t private_curve25519_private_key_t; + +/** + * Private data of a curve25519_private_key_t object. + */ +struct private_curve25519_private_key_t { + /** + * Public interface for this signer. + */ + curve25519_private_key_t public; + + /** + * Ed25519 private key + */ + chunk_t key; + + /** + * Ed25519 public key + */ + chunk_t pubkey; + + /** + * Reference count + */ + refcount_t ref; +}; + +METHOD(private_key_t, get_type, key_type_t, + private_curve25519_private_key_t *this) +{ + return KEY_ED25519; +} + +METHOD(private_key_t, sign, bool, + private_curve25519_private_key_t *this, signature_scheme_t scheme, + chunk_t data, chunk_t *signature) +{ + if (scheme != SIGN_ED25519) + { + DBG1(DBG_LIB, "signature scheme %N not supported by Ed25519", + signature_scheme_names, scheme); + return FALSE; + } + return FALSE; +} + +METHOD(private_key_t, decrypt, bool, + private_curve25519_private_key_t *this, encryption_scheme_t scheme, + chunk_t crypto, chunk_t *plain) +{ + DBG1(DBG_LIB, "encryption scheme %N not supported", encryption_scheme_names, + scheme); + return FALSE; +} + +METHOD(private_key_t, get_keysize, int, + private_curve25519_private_key_t *this) +{ + return 8 * ED25519_KEY_LEN; +} + +METHOD(private_key_t, get_public_key, public_key_t*, + private_curve25519_private_key_t *this) +{ + public_key_t *public; + chunk_t pubkey; + + pubkey = curve25519_public_key_info_encode(this->pubkey); + public = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ED25519, + BUILD_BLOB_ASN1_DER, pubkey, BUILD_END); + free(pubkey.ptr); + + return public; +} + +METHOD(private_key_t, get_encoding, bool, + private_curve25519_private_key_t *this, cred_encoding_type_t type, + chunk_t *encoding) +{ + switch (type) + { + case PRIVKEY_ASN1_DER: + case PRIVKEY_PEM: + { + bool success = TRUE; + + *encoding = asn1_wrap(ASN1_SEQUENCE, "cms", + ASN1_INTEGER_0, + asn1_algorithmIdentifier(OID_ED25519), + asn1_wrap(ASN1_OCTET_STRING, "s", + asn1_simple_object(ASN1_OCTET_STRING, this->key) + ) + ); + if (type == PRIVKEY_PEM) + { + chunk_t asn1_encoding = *encoding; + + success = lib->encoding->encode(lib->encoding, PRIVKEY_PEM, + NULL, encoding, CRED_PART_EDDSA_PRIV_ASN1_DER, + asn1_encoding, CRED_PART_END); + chunk_clear(&asn1_encoding); + } + return success; + } + default: + return FALSE; + } +} + +METHOD(private_key_t, get_fingerprint, bool, + private_curve25519_private_key_t *this, cred_encoding_type_t type, + chunk_t *fp) +{ + bool success; + + if (lib->encoding->get_cache(lib->encoding, type, this, fp)) + { + return TRUE; + } + success = curve25519_public_key_fingerprint(this->pubkey, type, fp); + if (success) + { + lib->encoding->cache(lib->encoding, type, this, *fp); + } + return success; +} + +METHOD(private_key_t, get_ref, private_key_t*, + private_curve25519_private_key_t *this) +{ + ref_get(&this->ref); + return &this->public.key; +} + +METHOD(private_key_t, destroy, void, + private_curve25519_private_key_t *this) +{ + if (ref_put(&this->ref)) + { + lib->encoding->clear_cache(lib->encoding, this); + chunk_clear(&this->key); + chunk_free(&this->pubkey); + free(this); + } +} + +/** + * Internal generic constructor + */ +static private_curve25519_private_key_t *curve25519_private_key_create(chunk_t key) +{ + private_curve25519_private_key_t *this; + uint8_t buf[HASH_SIZE_SHA512]; + hasher_t *hasher; + + /* derive public key */ + hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA512); + if (!hasher || !hasher->get_hash(hasher, key, buf)) + { + return NULL; + } + buf[ 0] &= 0xf8; + buf[31] &= 0x7f; + buf[31] |= 0x40; + + INIT(this, + .public = { + .key = { + .get_type = _get_type, + .sign = _sign, + .decrypt = _decrypt, + .get_keysize = _get_keysize, + .get_public_key = _get_public_key, + .equals = private_key_equals, + .belongs_to = private_key_belongs_to, + .get_fingerprint = _get_fingerprint, + .has_fingerprint = private_key_has_fingerprint, + .get_encoding = _get_encoding, + .get_ref = _get_ref, + .destroy = _destroy, + }, + }, + .key = key, + .pubkey = chunk_clone(chunk_create(buf, ED25519_KEY_LEN)), + .ref = 1, + ); + + return this; +} + +/** + * See header. + */ +curve25519_private_key_t *curve25519_private_key_gen(key_type_t type, + va_list args) +{ + private_curve25519_private_key_t *this; + chunk_t key; + rng_t *rng; + + while (TRUE) + { + switch (va_arg(args, builder_part_t)) + { + case BUILD_KEY_SIZE: + /* key_size argument is not needed */ + va_arg(args, u_int); + continue; + case BUILD_END: + break; + default: + return NULL; + } + break; + } + + /* generate 256 bit true random private key */ + rng = lib->crypto->create_rng(lib->crypto, RNG_TRUE); + if (!rng || !rng->allocate_bytes(rng, ED25519_KEY_LEN, &key)) + { + DESTROY_IF(rng); + return NULL; + } + rng->destroy(rng); + + this = curve25519_private_key_create(key); + + return this ? &this->public : NULL; +} + +/** + * See header. + */ +curve25519_private_key_t *curve25519_private_key_load(key_type_t type, + va_list args) +{ + private_curve25519_private_key_t *this; + chunk_t key = chunk_empty; + + while (TRUE) + { + switch (va_arg(args, builder_part_t)) + { + case BUILD_EDDSA_PRIV_ASN1_DER: + key = va_arg(args, chunk_t); + continue; + case BUILD_END: + break; + default: + return NULL; + } + break; + } + + if (!asn1_parse_simple_object(&key, ASN1_OCTET_STRING, 0, "EdPrivateKey") || + key.len != ED25519_KEY_LEN) + { + return NULL; + } + this = curve25519_private_key_create(chunk_clone(key)); + + return this ? &this->public : NULL; +} diff --git a/src/libstrongswan/plugins/curve25519/curve25519_private_key.h b/src/libstrongswan/plugins/curve25519/curve25519_private_key.h new file mode 100644 index 000000000..26f474ffb --- /dev/null +++ b/src/libstrongswan/plugins/curve25519/curve25519_private_key.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2016 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup curve25519_private_key curve25519_private_key + * @{ @ingroup curve25519_p + */ + +#ifndef CURVE25519_PRIVATE_KEY_H_ +#define CURVE25519_PRIVATE_KEY_H_ + +#include <credentials/builder.h> +#include <credentials/keys/private_key.h> + +typedef struct curve25519_private_key_t curve25519_private_key_t; + +/** + * Private_key_t implementation of Ed25519 signature algorithm. + */ +struct curve25519_private_key_t { + + /** + * Implements private_key_t interface + */ + private_key_t key; +}; + +/** + * Generate an Ed25519 private key. + * + * @param type type of the key, must be KEY_ED25519 + * @param args builder_part_t argument list + * @return generated key, NULL on failure + */ +curve25519_private_key_t *curve25519_private_key_gen(key_type_t type, + va_list args); + +/** + * Load an Ed25519 private key. + * + * @param type type of the key, must be KEY_ED25519 + * @param args builder_part_t argument list + * @return loaded key, NULL on failure + */ +curve25519_private_key_t *curve25519_private_key_load(key_type_t type, + va_list args); + +#endif /** CURVE25519_PRIVATE_KEY_H_ @}*/ diff --git a/src/libstrongswan/plugins/curve25519/curve25519_public_key.c b/src/libstrongswan/plugins/curve25519/curve25519_public_key.c new file mode 100644 index 000000000..56efe3a0f --- /dev/null +++ b/src/libstrongswan/plugins/curve25519/curve25519_public_key.c @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2016 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "curve25519_public_key.h" + +#include <asn1/asn1.h> +#include <asn1/asn1_parser.h> +#include <asn1/oid.h> + +typedef struct private_curve25519_public_key_t private_curve25519_public_key_t; + +/** + * Private data structure with signing context. + */ +struct private_curve25519_public_key_t { + /** + * Public interface for this signer. + */ + curve25519_public_key_t public; + + /** + * Ed25519 public key + */ + chunk_t pubkey; + + /** + * Reference counter + */ + refcount_t ref; +}; + +METHOD(public_key_t, get_type, key_type_t, + private_curve25519_public_key_t *this) +{ + return KEY_ED25519; +} + + +METHOD(public_key_t, verify, bool, + private_curve25519_public_key_t *this, signature_scheme_t scheme, + chunk_t data, chunk_t signature) +{ + if (scheme != SIGN_ED25519) + { + DBG1(DBG_LIB, "signature scheme %N not supported by Ed25519", + signature_scheme_names, scheme); + return FALSE; + } + /* TODO Implement signature verification */ + + return FALSE; +} + + +METHOD(public_key_t, encrypt_, bool, + private_curve25519_public_key_t *this, encryption_scheme_t scheme, + chunk_t plain, chunk_t *crypto) +{ + DBG1(DBG_LIB, "encryption scheme %N not supported", encryption_scheme_names, + scheme); + return FALSE; +} + +METHOD(public_key_t, get_keysize, int, + private_curve25519_public_key_t *this) +{ + return 8 * ED25519_KEY_LEN; +} + +METHOD(public_key_t, get_encoding, bool, + private_curve25519_public_key_t *this, cred_encoding_type_t type, + chunk_t *encoding) +{ + bool success = TRUE; + + *encoding = curve25519_public_key_info_encode(this->pubkey); + + if (type != PUBKEY_SPKI_ASN1_DER) + { + chunk_t asn1_encoding = *encoding; + + success = lib->encoding->encode(lib->encoding, type, + NULL, encoding, CRED_PART_EDDSA_PUB_ASN1_DER, + asn1_encoding, CRED_PART_END); + chunk_clear(&asn1_encoding); + } + return success; +} + +METHOD(public_key_t, get_fingerprint, bool, + private_curve25519_public_key_t *this, cred_encoding_type_t type, + chunk_t *fp) +{ + bool success; + + if (lib->encoding->get_cache(lib->encoding, type, this, fp)) + { + return TRUE; + } + success = curve25519_public_key_fingerprint(this->pubkey, type, fp); + if (success) + { + lib->encoding->cache(lib->encoding, type, this, *fp); + } + return success; +} + +METHOD(public_key_t, get_ref, public_key_t*, + private_curve25519_public_key_t *this) +{ + ref_get(&this->ref); + return &this->public.key; +} + +METHOD(public_key_t, destroy, void, + private_curve25519_public_key_t *this) +{ + if (ref_put(&this->ref)) + { + lib->encoding->clear_cache(lib->encoding, this); + free(this->pubkey.ptr); + free(this); + } +} + +/** + * ASN.1 definition of an Ed25519 public key + */ +static const asn1Object_t pubkeyObjects[] = { + { 0, "subjectPublicKeyInfo",ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "algorithm", ASN1_EOC, ASN1_RAW }, /* 1 */ + { 1, "subjectPublicKey", ASN1_BIT_STRING, ASN1_BODY }, /* 2 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } +}; + +#define ED25519_SUBJECT_PUBLIC_KEY_ALGORITHM 1 +#define ED25519_SUBJECT_PUBLIC_KEY 2 + +/** + * See header. + */ +curve25519_public_key_t *curve25519_public_key_load(key_type_t type, + va_list args) +{ + private_curve25519_public_key_t *this; + chunk_t blob = chunk_empty, object; + asn1_parser_t *parser; + bool success = FALSE; + int objectID, oid; + + while (TRUE) + { + switch (va_arg(args, builder_part_t)) + { + case BUILD_BLOB_ASN1_DER: + blob = va_arg(args, chunk_t); + continue; + case BUILD_END: + break; + default: + return NULL; + } + break; + } + + INIT(this, + .public = { + .key = { + .get_type = _get_type, + .verify = _verify, + .encrypt = _encrypt_, + .equals = public_key_equals, + .get_keysize = _get_keysize, + .get_fingerprint = _get_fingerprint, + .has_fingerprint = public_key_has_fingerprint, + .get_encoding = _get_encoding, + .get_ref = _get_ref, + .destroy = _destroy, + }, + }, + .ref = 1, + ); + + parser = asn1_parser_create(pubkeyObjects, blob); + + while (parser->iterate(parser, &objectID, &object)) + { + switch (objectID) + { + case ED25519_SUBJECT_PUBLIC_KEY_ALGORITHM: + { + oid = asn1_parse_algorithmIdentifier(object, + parser->get_level(parser) + 1, NULL); + if (oid != OID_ED25519) + { + goto end; + } + break; + } + case ED25519_SUBJECT_PUBLIC_KEY: + { + /* encoded as an ASN1 BIT STRING */ + if (object.len != 1 + ED25519_KEY_LEN) + { + goto end; + } + this->pubkey = chunk_clone(chunk_skip(object, 1)); + break; + } + } + } + success = parser->success(parser); + +end: + parser->destroy(parser); + if (!success) + { + destroy(this); + return NULL; + } + return &this->public; +} + +/** + * See header. + */ +chunk_t curve25519_public_key_info_encode(chunk_t pubkey) +{ + return asn1_wrap(ASN1_SEQUENCE, "mm", + asn1_wrap(ASN1_SEQUENCE, "m", + asn1_build_known_oid(OID_ED25519)), + asn1_bitstring("c", pubkey)); +} + +/** + * See header. + */ +bool curve25519_public_key_fingerprint(chunk_t pubkey, + cred_encoding_type_t type, chunk_t *fp) +{ + hasher_t *hasher; + chunk_t key; + + switch (type) + { + case KEYID_PUBKEY_SHA1: + key = chunk_clone(pubkey); + break; + case KEYID_PUBKEY_INFO_SHA1: + key = curve25519_public_key_info_encode(pubkey); + break; + default: + return FALSE; + } + + hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); + if (!hasher || !hasher->allocate_hash(hasher, key, fp)) + { + DBG1(DBG_LIB, "SHA1 hash algorithm not supported, " + "fingerprinting failed"); + DESTROY_IF(hasher); + free(key.ptr); + return FALSE; + } + hasher->destroy(hasher); + free(key.ptr); + return TRUE; +} diff --git a/src/libstrongswan/plugins/curve25519/curve25519_public_key.h b/src/libstrongswan/plugins/curve25519/curve25519_public_key.h new file mode 100644 index 000000000..5f6ae175a --- /dev/null +++ b/src/libstrongswan/plugins/curve25519/curve25519_public_key.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2016 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup curve25519_public_key curve25519_public_key + * @{ @ingroup curve25519_p + */ + +#ifndef CURVE25519_PUBLIC_KEY_H_ +#define CURVE25519_PUBLIC_KEY_H_ + +#include <credentials/builder.h> +#include <credentials/cred_encoding.h> +#include <credentials/keys/public_key.h> + +typedef struct curve25519_public_key_t curve25519_public_key_t; + +#define ED25519_KEY_LEN 32 + +/** + * public_key_t implementation of Ed25519 signature algorithm + */ +struct curve25519_public_key_t { + + /** + * Implements the public_key_t interface + */ + public_key_t key; +}; + +/** + * Load an Ed25519 public key. + * + * @param type type of the key, must be KEY_ED25519 + * @param args builder_part_t argument list + * @return loaded key, NULL on failure + */ +curve25519_public_key_t *curve25519_public_key_load(key_type_t type, + va_list args); + +/* The following functions are shared with the curve25519_private_key class */ + +/** + * Encode a Ed25519 subjectPublicKeyInfo record in ASN.1 DER format + * + * @param pubkey Ed25519 public key + * @result ASN.1 encoded subjectPublicKeyInfo record + */ +chunk_t curve25519_public_key_info_encode(chunk_t pubkey); + +/** + * Generate a Ed25519 public key fingerprint + * + * @param pubkey Ed25519 public key + * @param type type of fingerprint to be generated + * @param fp generated fingerprint (must be freed by caller) + * @result TRUE if generation was successful + */ +bool curve25519_public_key_fingerprint(chunk_t pubkey, + cred_encoding_type_t type, chunk_t *fp); + +#endif /** CURVE25519_PUBLIC_KEY_H_ @}*/ diff --git a/src/libstrongswan/plugins/pem/pem_encoder.c b/src/libstrongswan/plugins/pem/pem_encoder.c index 35ea3e885..76b0b7b40 100644 --- a/src/libstrongswan/plugins/pem/pem_encoder.c +++ b/src/libstrongswan/plugins/pem/pem_encoder.c @@ -1,6 +1,6 @@ /* - * Copyright (C) 2010 Andreas Steffen - * Hochschule fuer Technik Rapperswil + * Copyright (C) 2010-2016 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -37,7 +37,11 @@ bool pem_encoder_encode(cred_encoding_type_t type, chunk_t *encoding, if (cred_encoding_args(args, CRED_PART_RSA_PUB_ASN1_DER, &asn1, CRED_PART_END) || cred_encoding_args(args, CRED_PART_ECDSA_PUB_ASN1_DER, - &asn1, CRED_PART_END)) + &asn1, CRED_PART_END) || + cred_encoding_args(args, CRED_PART_EDDSA_PUB_ASN1_DER, + &asn1, CRED_PART_END) || + cred_encoding_args(args, CRED_PART_BLISS_PUB_ASN1_DER, + &asn1, CRED_PART_END)) { break; } @@ -53,11 +57,6 @@ bool pem_encoder_encode(cred_encoding_type_t type, chunk_t *encoding, break; } } - if (cred_encoding_args(args, CRED_PART_BLISS_PUB_ASN1_DER, - &asn1, CRED_PART_END)) - { - break; - } return FALSE; case PRIVKEY_PEM: label ="RSA PRIVATE KEY"; @@ -97,6 +96,12 @@ bool pem_encoder_encode(cred_encoding_type_t type, chunk_t *encoding, label ="BLISS PRIVATE KEY"; break; } + if (cred_encoding_args(args, CRED_PART_EDDSA_PRIV_ASN1_DER, + &asn1, CRED_PART_END)) + { + label ="PRIVATE KEY"; + break; + } return FALSE; case CERT_PEM: if (cred_encoding_args(args, CRED_PART_X509_ASN1_DER, diff --git a/src/libstrongswan/plugins/pem/pem_plugin.c b/src/libstrongswan/plugins/pem/pem_plugin.c index d5bcbb617..662b0fe8e 100644 --- a/src/libstrongswan/plugins/pem/pem_plugin.c +++ b/src/libstrongswan/plugins/pem/pem_plugin.c @@ -63,6 +63,9 @@ METHOD(plugin_t, get_features, int, PLUGIN_REGISTER(PRIVKEY, pem_private_key_load, FALSE), PLUGIN_PROVIDE(PRIVKEY, KEY_BLISS), PLUGIN_DEPENDS(PRIVKEY, KEY_BLISS), + PLUGIN_REGISTER(PRIVKEY, pem_private_key_load, FALSE), + PLUGIN_PROVIDE(PRIVKEY, KEY_ED25519), + PLUGIN_DEPENDS(PRIVKEY, KEY_ED25519), /* public key PEM decoding */ PLUGIN_REGISTER(PUBKEY, pem_public_key_load, FALSE), @@ -79,6 +82,10 @@ METHOD(plugin_t, get_features, int, PLUGIN_DEPENDS(PUBKEY, KEY_DSA), PLUGIN_REGISTER(PUBKEY, pem_public_key_load, FALSE), PLUGIN_PROVIDE(PUBKEY, KEY_BLISS), + PLUGIN_DEPENDS(PUBKEY, KEY_BLISS), + PLUGIN_REGISTER(PUBKEY, pem_public_key_load, FALSE), + PLUGIN_PROVIDE(PUBKEY, KEY_ED25519), + PLUGIN_DEPENDS(PUBKEY, KEY_ED25519), /* certificate PEM decoding */ PLUGIN_REGISTER(CERT_DECODE, pem_certificate_load, FALSE), diff --git a/src/libstrongswan/plugins/pkcs1/pkcs1_builder.c b/src/libstrongswan/plugins/pkcs1/pkcs1_builder.c index 766832d39..97e0633e7 100644 --- a/src/libstrongswan/plugins/pkcs1/pkcs1_builder.c +++ b/src/libstrongswan/plugins/pkcs1/pkcs1_builder.c @@ -75,6 +75,13 @@ static public_key_t *parse_public_key(chunk_t blob) KEY_BLISS, BUILD_BLOB_ASN1_DER, blob, BUILD_END); goto end; } + else if (oid == OID_ED25519) + { + /* Need the whole subjectPublicKeyInfo for Ed25519 public keys */ + key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, + KEY_ED25519, BUILD_BLOB_ASN1_DER, blob, BUILD_END); + goto end; + } else { /* key type not supported */ diff --git a/src/libstrongswan/plugins/pkcs1/pkcs1_plugin.c b/src/libstrongswan/plugins/pkcs1/pkcs1_plugin.c index ec1bdf565..b8877404d 100644 --- a/src/libstrongswan/plugins/pkcs1/pkcs1_plugin.c +++ b/src/libstrongswan/plugins/pkcs1/pkcs1_plugin.c @@ -52,6 +52,9 @@ METHOD(plugin_t, get_features, int, PLUGIN_PROVIDE(PUBKEY, KEY_ANY), PLUGIN_SDEPEND(PUBKEY, KEY_RSA), PLUGIN_SDEPEND(PUBKEY, KEY_ECDSA), + PLUGIN_SDEPEND(PUBKEY, KEY_ED25519), + PLUGIN_SDEPEND(PUBKEY, KEY_ED448), + PLUGIN_SDEPEND(PUBKEY, KEY_BLISS), PLUGIN_SDEPEND(PUBKEY, KEY_DSA), PLUGIN_REGISTER(PUBKEY, pkcs1_public_key_load, FALSE), PLUGIN_PROVIDE(PUBKEY, KEY_RSA), diff --git a/src/libstrongswan/plugins/pkcs8/pkcs8_builder.c b/src/libstrongswan/plugins/pkcs8/pkcs8_builder.c index e93a8361c..beb8866f8 100644 --- a/src/libstrongswan/plugins/pkcs8/pkcs8_builder.c +++ b/src/libstrongswan/plugins/pkcs8/pkcs8_builder.c @@ -47,6 +47,7 @@ static private_key_t *parse_private_key(chunk_t blob) int objectID; private_key_t *key = NULL; key_type_t type = KEY_ANY; + builder_part_t part = BUILD_BLOB_ASN1_DER; parser = asn1_parser_create(pkinfoObjects, blob); parser->set_flags(parser, FALSE, TRUE); @@ -68,6 +69,14 @@ static private_key_t *parse_private_key(chunk_t blob) case OID_EC_PUBLICKEY: type = KEY_ECDSA; break; + case OID_ED25519: + type = KEY_ED25519; + part = BUILD_EDDSA_PRIV_ASN1_DER; + break; + case OID_ED448: + type = KEY_ED448; + part = BUILD_EDDSA_PRIV_ASN1_DER; + break; default: /* key type not supported */ goto end; @@ -81,14 +90,12 @@ static private_key_t *parse_private_key(chunk_t blob) { key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type, BUILD_BLOB_ALGID_PARAMS, - params, BUILD_BLOB_ASN1_DER, - object, BUILD_END); + params, part, object, BUILD_END); } else { key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, - type, BUILD_BLOB_ASN1_DER, object, - BUILD_END); + type, part, object, BUILD_END); } DBG2(DBG_ASN, "-- < --"); break; diff --git a/src/libstrongswan/plugins/pkcs8/pkcs8_plugin.c b/src/libstrongswan/plugins/pkcs8/pkcs8_plugin.c index 129fbb045..fcd8f119e 100644 --- a/src/libstrongswan/plugins/pkcs8/pkcs8_plugin.c +++ b/src/libstrongswan/plugins/pkcs8/pkcs8_plugin.c @@ -46,6 +46,8 @@ METHOD(plugin_t, get_features, int, PLUGIN_PROVIDE(PRIVKEY, KEY_ANY), PLUGIN_PROVIDE(PRIVKEY, KEY_RSA), PLUGIN_PROVIDE(PRIVKEY, KEY_ECDSA), + PLUGIN_PROVIDE(PRIVKEY, KEY_ED25519), + PLUGIN_PROVIDE(PRIVKEY, KEY_ED448), }; *features = f; return countof(f); |