diff --git a/.travis.yml b/.travis.yml index 98804f2c6..7e70df553 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,7 +38,7 @@ env: matrix: include: - env: TEST=sonarcloud - if: type = push + if: type = push AND env(SONAR_TOKEN) IS present git: depth: false addons: @@ -78,22 +78,13 @@ matrix: - env: TEST=printf-builtin LEAK_DETECTIVE=yes - env: TEST=printf-builtin LEAK_DETECTIVE=yes compiler: clang + # the crypto plugins are build-tested with clang via "all" above - env: TEST=botan - - env: TEST=botan - compiler: clang - env: TEST=botan LEAK_DETECTIVE=yes - - env: TEST=botan LEAK_DETECTIVE=yes - compiler: clang - env: TEST=openssl - - env: TEST=openssl - compiler: clang - env: TEST=openssl LEAK_DETECTIVE=yes - - env: TEST=openssl LEAK_DETECTIVE=yes - compiler: clang + - env: TEST=openssl-1.0 + - env: TEST=openssl-1.0 LEAK_DETECTIVE=yes - env: TEST=gcrypt - - env: TEST=gcrypt - compiler: clang - env: TEST=gcrypt LEAK_DETECTIVE=yes - - env: TEST=gcrypt LEAK_DETECTIVE=yes - compiler: clang - env: TEST=apidoc diff --git a/scripts/dh_speed.c b/scripts/dh_speed.c index f2f98d7af..235772faf 100644 --- a/scripts/dh_speed.c +++ b/scripts/dh_speed.c @@ -47,6 +47,7 @@ struct { {"ecp192", ECP_192_BIT}, {"ecp224", ECP_224_BIT}, {"curve25519", CURVE_25519}, + {"curve448", CURVE_448}, }; static void start_timing(struct timespec *start) diff --git a/scripts/test.sh b/scripts/test.sh index 1998f2178..fbf76b5f0 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -11,6 +11,8 @@ build_botan() return fi + echo "$ build_botan()" + # if the leak detective is enabled we have to disable threading support # (used for std::async) as that causes invalid frees somehow, the # locking allocator causes a static leak via the first function that @@ -43,7 +45,9 @@ build_tss2() return fi - # the default version of libgcrypt in Ubuntu 14.04 is too old + echo "$ build_tss2()" + + # the default version of libgcrypt in Ubuntu 16.04 is too old sudo apt-get update -qq && \ sudo apt-get install -qq libgcrypt20-dev && curl -L $TSS2_SRC | tar xz -C $TRAVIS_BUILD_DIR/.. && @@ -55,6 +59,42 @@ build_tss2() cd - } +build_openssl() +{ + SSL_REV=1.1.1a + SSL_PKG=openssl-$SSL_REV + SSL_DIR=$TRAVIS_BUILD_DIR/../$SSL_PKG + SSL_SRC=https://www.openssl.org/source/$SSL_PKG.tar.gz + SSL_INS=/usr/local/ssl + SSL_OPT="shared no-tls no-dtls no-ssl3 no-zlib no-comp no-idea no-psk no-srp + no-stdio no-tests enable-rfc3779 enable-ec_nistp_64_gcc_128" + + if test -d "$SSL_DIR"; then + return + fi + + echo "$ build_openssl()" + + curl -L $SSL_SRC | tar xz -C $TRAVIS_BUILD_DIR/.. && + cd $SSL_DIR && + ./config --prefix=$SSL_INS --openssldir=$SSL_INS $SSL_OPT && + make -j4 >/dev/null && + sudo make install_sw >/dev/null && + echo $SSL_INS/lib | sudo tee /etc/ld.so.conf.d/openssl-$SSL_REV.conf >/dev/null && + sudo ldconfig || exit $? + cd - +} + +use_custom_openssl() +{ + CFLAGS="$CFLAGS -I/usr/local/ssl/include" + LDFLAGS="$LDFLAGS -L/usr/local/ssl/lib" + export LDFLAGS + if test "$1" = "deps"; then + build_openssl + fi +} + if test -z $TRAVIS_BUILD_DIR; then TRAVIS_BUILD_DIR=$PWD fi @@ -72,9 +112,13 @@ default) # should be the default, but lets make sure CONFIG="--with-printf-hooks=glibc" ;; -openssl) - CONFIG="--disable-defaults --enable-pki --enable-openssl" +openssl*) + CONFIG="--disable-defaults --enable-pki --enable-openssl --enable-pem" DEPS="libssl-dev" + if test "$TEST" != "openssl-1.0"; then + DEPS="" + use_custom_openssl $1 + fi ;; gcrypt) CONFIG="--disable-defaults --enable-pki --enable-gcrypt --enable-pkcs1" @@ -119,6 +163,7 @@ all|coverage|sonarcloud) build_botan build_tss2 fi + use_custom_openssl $1 ;; win*) CONFIG="--disable-defaults --enable-svc --enable-ikev2 diff --git a/src/libstrongswan/plugins/curve25519/curve25519_public_key.c b/src/libstrongswan/plugins/curve25519/curve25519_public_key.c index 6eb80a119..dfc1df4d0 100644 --- a/src/libstrongswan/plugins/curve25519/curve25519_public_key.c +++ b/src/libstrongswan/plugins/curve25519/curve25519_public_key.c @@ -49,6 +49,13 @@ METHOD(public_key_t, get_type, key_type_t, return KEY_ED25519; } +/* L = 2^252+27742317777372353535851937790883648493 in little-endian form */ +static chunk_t curve25519_order = chunk_from_chars( + 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, + 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10); + METHOD(public_key_t, verify, bool, private_curve25519_public_key_t *this, signature_scheme_t scheme, void *params, chunk_t data, chunk_t signature) @@ -94,6 +101,20 @@ METHOD(public_key_t, verify, bool, { return FALSE; } + /* make sure 0 <= s < L, as per RFC 8032, section 5.1.7 to prevent signature + * malleability. Due to the three-bit check above (forces s < 2^253) there + * is not that much room, but adding L once works with most signatures */ + for (i = 31; ; i--) + { + if (sig[i+32] < curve25519_order.ptr[i]) + { + break; + } + else if (sig[i+32] > curve25519_order.ptr[i] || i == 0) + { + return FALSE; + } + } hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA512); if (!hasher) diff --git a/src/libstrongswan/plugins/openssl/Makefile.am b/src/libstrongswan/plugins/openssl/Makefile.am index 9287f788a..d484092e7 100644 --- a/src/libstrongswan/plugins/openssl/Makefile.am +++ b/src/libstrongswan/plugins/openssl/Makefile.am @@ -29,7 +29,10 @@ libstrongswan_openssl_la_SOURCES = \ openssl_pkcs12.c openssl_pkcs12.h \ openssl_rng.c openssl_rng.h \ openssl_hmac.c openssl_hmac.h \ - openssl_gcm.c openssl_gcm.h + openssl_gcm.c openssl_gcm.h \ + openssl_x_diffie_hellman.c openssl_x_diffie_hellman.h \ + openssl_ed_private_key.c openssl_ed_private_key.h \ + openssl_ed_public_key.c openssl_ed_public_key.h libstrongswan_openssl_la_LDFLAGS = -module -avoid-version libstrongswan_openssl_la_LIBADD = $(OPENSSL_LIB) diff --git a/src/libstrongswan/plugins/openssl/openssl_ed_private_key.c b/src/libstrongswan/plugins/openssl/openssl_ed_private_key.c new file mode 100644 index 000000000..b5bc9b868 --- /dev/null +++ b/src/libstrongswan/plugins/openssl/openssl_ed_private_key.c @@ -0,0 +1,356 @@ +/* + * Copyright (C) 2018 Tobias Brunner + * 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 . + * + * 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 + +#if OPENSSL_VERSION_NUMBER >= 0x1010100fL && !defined(OPENSSL_NO_EC) + +#include "openssl_ed_private_key.h" + +#include + +typedef struct private_private_key_t private_private_key_t; + +/** + * Private data + */ +struct private_private_key_t { + + /** + * Public interface + */ + private_key_t public; + + /** + * Key object + */ + EVP_PKEY *key; + + /** + * Key type + */ + key_type_t type; + + /** + * TRUE if the key is from an OpenSSL ENGINE and might not be readable + */ + bool engine; + + /** + * reference count + */ + refcount_t ref; +}; + +/** + * We can't include asn1.h, declare function prototype directly + */ +int asn1_unwrap(chunk_t*, chunk_t*); + +/* from ed public key */ +int openssl_ed_key_type(key_type_t type); +int openssl_ed_keysize(key_type_t type); +bool openssl_ed_fingerprint(EVP_PKEY *key, cred_encoding_type_t type, chunk_t *fp); + +METHOD(private_key_t, sign, bool, + private_private_key_t *this, signature_scheme_t scheme, + void *params, chunk_t data, chunk_t *signature) +{ + EVP_MD_CTX *ctx; + bool success = FALSE; + + if ((this->type == KEY_ED25519 && scheme != SIGN_ED25519) || + (this->type == KEY_ED448 && scheme != SIGN_ED448)) + { + DBG1(DBG_LIB, "signature scheme %N not supported by %N key", + signature_scheme_names, scheme, key_type_names, this->type); + return FALSE; + } + + ctx = EVP_MD_CTX_new(); + if (!ctx || + EVP_DigestSignInit(ctx, NULL, NULL, NULL, this->key) <= 0) + { + goto error; + } + + if (EVP_DigestSign(ctx, NULL, &signature->len, data.ptr, data.len) <= 0) + { + goto error; + } + + *signature = chunk_alloc(signature->len); + + if (EVP_DigestSign(ctx, signature->ptr, &signature->len, + data.ptr, data.len) <= 0) + { + goto error; + } + + success = TRUE; + +error: + EVP_MD_CTX_free(ctx); + return success; +} + +METHOD(private_key_t, decrypt, bool, + private_private_key_t *this, encryption_scheme_t scheme, + chunk_t crypto, chunk_t *plain) +{ + DBG1(DBG_LIB, "EdDSA private key decryption not implemented"); + return FALSE; +} + +METHOD(private_key_t, get_keysize, int, + private_private_key_t *this) +{ + return openssl_ed_keysize(this->type); +} + +METHOD(private_key_t, get_type, key_type_t, + private_private_key_t *this) +{ + return this->type; +} + +METHOD(private_key_t, get_public_key, public_key_t*, + private_private_key_t *this) +{ + public_key_t *public; + chunk_t key; + + if (!EVP_PKEY_get_raw_public_key(this->key, NULL, &key.len)) + { + return FALSE; + } + key = chunk_alloca(key.len); + if (!EVP_PKEY_get_raw_public_key(this->key, key.ptr, &key.len)) + { + return FALSE; + } + public = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, this->type, + BUILD_EDDSA_PUB, key, BUILD_END); + return public; +} + +METHOD(private_key_t, get_fingerprint, bool, + private_private_key_t *this, cred_encoding_type_t type, + chunk_t *fingerprint) +{ + return openssl_ed_fingerprint(this->key, type, fingerprint); +} + +METHOD(private_key_t, get_encoding, bool, + private_private_key_t *this, cred_encoding_type_t type, chunk_t *encoding) +{ + u_char *p; + + if (this->engine) + { + return FALSE; + } + + switch (type) + { + case PRIVKEY_ASN1_DER: + case PRIVKEY_PEM: + { + bool success = TRUE; + + *encoding = chunk_alloc(i2d_PrivateKey(this->key, NULL)); + p = encoding->ptr; + i2d_PrivateKey(this->key, &p); + + 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_ref, private_key_t*, + private_private_key_t *this) +{ + ref_get(&this->ref); + return &this->public; +} + +METHOD(private_key_t, destroy, void, + private_private_key_t *this) +{ + if (ref_put(&this->ref)) + { + lib->encoding->clear_cache(lib->encoding, this->key); + EVP_PKEY_free(this->key); + free(this); + } +} + +/** + * Internal generic constructor + */ +static private_private_key_t *create_internal(key_type_t type, EVP_PKEY *key) +{ + private_private_key_t *this; + + INIT(this, + .public = { + .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, + }, + .type = type, + .key = key, + .ref = 1, + ); + + return this; +} + +/* + * Described in header + */ +private_key_t *openssl_ed_private_key_create(EVP_PKEY *key, bool engine) +{ + private_private_key_t *this; + key_type_t type; + + switch (EVP_PKEY_base_id(key)) + { + case EVP_PKEY_X25519: + type = KEY_ED25519; + break; + case EVP_PKEY_X448: + type = KEY_ED448; + break; + default: + EVP_PKEY_free(key); + return NULL; + } + + this = create_internal(type, key); + this->engine = engine; + return &this->public; +} + +/* + * Described in header + */ +private_key_t *openssl_ed_private_key_gen(key_type_t type, va_list args) +{ + private_private_key_t *this; + EVP_PKEY_CTX *ctx; + EVP_PKEY *key = NULL; + + while (TRUE) + { + switch (va_arg(args, builder_part_t)) + { + case BUILD_KEY_SIZE: + /* just ignore the key size */ + va_arg(args, u_int); + continue; + case BUILD_END: + break; + default: + return NULL; + } + break; + } + + ctx = EVP_PKEY_CTX_new_id(openssl_ed_key_type(type), NULL); + if (!ctx || + EVP_PKEY_keygen_init(ctx) <= 0 || + EVP_PKEY_keygen(ctx, &key) <= 0) + { + DBG1(DBG_LIB, "generating %N key failed", key_type_names, type); + EVP_PKEY_CTX_free(ctx); + return NULL; + } + EVP_PKEY_CTX_free(ctx); + + this = create_internal(type, key); + return &this->public; +} + +/* + * Described in header + */ +private_key_t *openssl_ed_private_key_load(key_type_t type, va_list args) +{ + private_private_key_t *this; + chunk_t blob = chunk_empty, priv = chunk_empty; + EVP_PKEY *key = NULL; + + while (TRUE) + { + switch (va_arg(args, builder_part_t)) + { + case BUILD_BLOB_ASN1_DER: + blob = va_arg(args, chunk_t); + continue; + case BUILD_EDDSA_PRIV_ASN1_DER: + priv = va_arg(args, chunk_t); + continue; + case BUILD_END: + break; + default: + return NULL; + } + break; + } + + if (priv.len) + { + /* unwrap octet string */ + if (asn1_unwrap(&priv, &priv) == 0x04 && priv.len) + { + key = EVP_PKEY_new_raw_private_key(openssl_ed_key_type(type), NULL, + priv.ptr, priv.len); + } + } + else if (blob.len) + { + key = d2i_PrivateKey(openssl_ed_key_type(type), NULL, + (const u_char**)&blob.ptr, blob.len); + } + if (!key) + { + return NULL; + } + this = create_internal(type, key); + return &this->public; +} + +#endif /* OPENSSL_NO_ECDSA */ diff --git a/src/libstrongswan/plugins/openssl/openssl_ed_private_key.h b/src/libstrongswan/plugins/openssl/openssl_ed_private_key.h new file mode 100644 index 000000000..ce9071348 --- /dev/null +++ b/src/libstrongswan/plugins/openssl/openssl_ed_private_key.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2018 Tobias Brunner + * 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 . + * + * 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 openssl_ed_private_key openssl_ed_private_key + * @{ @ingroup openssl_p + */ + +#ifndef OPENSSL_ED_PRIVATE_KEY_H_ +#define OPENSSL_ED_PRIVATE_KEY_H_ + +#include + +#include +#include + +/** + * Generate an EdDSA private key using OpenSSL. + * + * @param type type of the key, must be KEY_ED25519 or KEY_ED448 + * @param args builder_part_t argument list + * @return generated key, NULL on failure + */ +private_key_t *openssl_ed_private_key_gen(key_type_t type, va_list args); + +/** + * Load an EdDSA private key using OpenSSL. + * + * Accepts a BUILD_BLOB_ASN1_DER argument. + * + * @param type type of the key, must be KEY_ED25519 or KEY_ED448 + * @param args builder_part_t argument list + * @return loaded key, NULL on failure + */ +private_key_t *openssl_ed_private_key_load(key_type_t type, va_list args); + +/** + * Wrap an EVP_PKEY object of type EVP_PKEY_ED25519/448 + * + * @param key EVP_PKEY object (adopted) + * @param engine whether the key was loaded via an engine + * @return loaded key, NULL on failure + */ +private_key_t *openssl_ed_private_key_create(EVP_PKEY *key, bool engine); + +#endif /** OPENSSL_ED_PRIVATE_KEY_H_ @}*/ diff --git a/src/libstrongswan/plugins/openssl/openssl_ed_public_key.c b/src/libstrongswan/plugins/openssl/openssl_ed_public_key.c new file mode 100644 index 000000000..2daddc57e --- /dev/null +++ b/src/libstrongswan/plugins/openssl/openssl_ed_public_key.c @@ -0,0 +1,304 @@ +/* + * Copyright (C) 2018 Tobias Brunner + * 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 . + * + * 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 + +#if OPENSSL_VERSION_NUMBER >= 0x1010100fL && !defined(OPENSSL_NO_EC) + +#include + +#include "openssl_ed_public_key.h" + +#include + +typedef struct private_public_key_t private_public_key_t; + +/** + * Private data + */ +struct private_public_key_t { + + /** + * Public interface + */ + public_key_t public; + + /** + * Key object + */ + EVP_PKEY *key; + + /** + * Key type + */ + key_type_t type; + + /** + * Reference counter + */ + refcount_t ref; +}; + +/** + * Map a key type to an EVP key type + */ +int openssl_ed_key_type(key_type_t type) +{ + switch (type) + { + case KEY_ED25519: + return EVP_PKEY_ED25519; + case KEY_ED448: + return EVP_PKEY_ED448; + default: + return 0; + } +} + +/** + * Map a key type to a key size + */ +int openssl_ed_keysize(key_type_t type) +{ + switch (type) + { + case KEY_ED25519: + return 32 * 8; + case KEY_ED448: + return 57 * 8; + default: + return 0; + } +} + +METHOD(public_key_t, get_type, key_type_t, + private_public_key_t *this) +{ + return this->type; +} + +METHOD(public_key_t, verify, bool, + private_public_key_t *this, signature_scheme_t scheme, + void *params, chunk_t data, chunk_t signature) +{ + EVP_MD_CTX *ctx; + + if ((this->type == KEY_ED25519 && scheme != SIGN_ED25519) || + (this->type == KEY_ED448 && scheme != SIGN_ED448)) + { + DBG1(DBG_LIB, "signature scheme %N not supported by %N key", + signature_scheme_names, scheme, key_type_names, this->type); + return FALSE; + } + + ctx = EVP_MD_CTX_new(); + if (!ctx || + EVP_DigestVerifyInit(ctx, NULL, NULL, NULL, this->key) <= 0 || + EVP_DigestVerify(ctx, signature.ptr, signature.len, + data.ptr, data.len) <= 0) + { + EVP_MD_CTX_free(ctx); + return FALSE; + } + EVP_MD_CTX_free(ctx); + return TRUE; +} + +METHOD(public_key_t, encrypt, bool, + private_public_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(public_key_t, get_keysize, int, + private_public_key_t *this) +{ + return openssl_ed_keysize(this->type); +} + +/** + * Calculate fingerprint from an EdDSA key, also used in ed private key. + */ +bool openssl_ed_fingerprint(EVP_PKEY *key, cred_encoding_type_t type, + chunk_t *fp) +{ + hasher_t *hasher; + chunk_t blob; + u_char *p; + + if (lib->encoding->get_cache(lib->encoding, type, key, fp)) + { + return TRUE; + } + switch (type) + { + case KEYID_PUBKEY_SHA1: + if (!EVP_PKEY_get_raw_public_key(key, NULL, &blob.len)) + { + return FALSE; + } + blob = chunk_alloca(blob.len); + if (!EVP_PKEY_get_raw_public_key(key, blob.ptr, &blob.len)) + { + return FALSE; + } + break; + case KEYID_PUBKEY_INFO_SHA1: + blob = chunk_alloca(i2d_PUBKEY(key, NULL)); + p = blob.ptr; + i2d_PUBKEY(key, &p); + break; + default: + return FALSE; + } + hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); + if (!hasher || !hasher->allocate_hash(hasher, blob, fp)) + { + DBG1(DBG_LIB, "SHA1 not supported, fingerprinting failed"); + DESTROY_IF(hasher); + return FALSE; + } + hasher->destroy(hasher); + lib->encoding->cache(lib->encoding, type, key, *fp); + return TRUE; +} + +METHOD(public_key_t, get_fingerprint, bool, + private_public_key_t *this, cred_encoding_type_t type, chunk_t *fingerprint) +{ + return openssl_ed_fingerprint(this->key, type, fingerprint); +} + +METHOD(public_key_t, get_encoding, bool, + private_public_key_t *this, cred_encoding_type_t type, chunk_t *encoding) +{ + bool success = TRUE; + u_char *p; + + *encoding = chunk_alloc(i2d_PUBKEY(this->key, NULL)); + p = encoding->ptr; + i2d_PUBKEY(this->key, &p); + + 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_ref, public_key_t*, + private_public_key_t *this) +{ + ref_get(&this->ref); + return &this->public; +} + +METHOD(public_key_t, destroy, void, + private_public_key_t *this) +{ + if (ref_put(&this->ref)) + { + lib->encoding->clear_cache(lib->encoding, this->key); + EVP_PKEY_free(this->key); + free(this); + } +} + +/** + * Generic private constructor + */ +static private_public_key_t *create_empty(key_type_t type) +{ + private_public_key_t *this; + + INIT(this, + .public = { + .get_type = _get_type, + .verify = _verify, + .encrypt = _encrypt, + .get_keysize = _get_keysize, + .equals = public_key_equals, + .get_fingerprint = _get_fingerprint, + .has_fingerprint = public_key_has_fingerprint, + .get_encoding = _get_encoding, + .get_ref = _get_ref, + .destroy = _destroy, + }, + .type = type, + .ref = 1, + ); + + return this; +} + +/* + * Described in header + */ +public_key_t *openssl_ed_public_key_load(key_type_t type, va_list args) +{ + private_public_key_t *this; + chunk_t blob = chunk_empty, pub = chunk_empty; + EVP_PKEY *key = NULL; + + while (TRUE) + { + switch (va_arg(args, builder_part_t)) + { + case BUILD_BLOB_ASN1_DER: + blob = va_arg(args, chunk_t); + continue; + case BUILD_EDDSA_PUB: + pub = va_arg(args, chunk_t); + continue; + case BUILD_END: + break; + default: + return NULL; + } + break; + } + + if (pub.len) + { + key = EVP_PKEY_new_raw_public_key(openssl_ed_key_type(type), NULL, + pub.ptr, pub.len); + } + else if (blob.len) + { + key = d2i_PUBKEY(NULL, (const u_char**)&blob.ptr, blob.len); + if (key && EVP_PKEY_base_id(key) != openssl_ed_key_type(type)) + { + EVP_PKEY_free(key); + return NULL; + } + } + if (!key) + { + return NULL; + } + this = create_empty(type); + this->key = key; + return &this->public; +} + +#endif /* OPENSSL_VERSION_NUMBER */ diff --git a/src/libstrongswan/plugins/openssl/openssl_ed_public_key.h b/src/libstrongswan/plugins/openssl/openssl_ed_public_key.h new file mode 100644 index 000000000..c4e1ba3ed --- /dev/null +++ b/src/libstrongswan/plugins/openssl/openssl_ed_public_key.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2018 Tobias Brunner + * 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 . + * + * 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 openssl_ed_public_key openssl_ed_public_key + * @{ @ingroup openssl_p + */ + +#ifndef OPENSSL_ED_PUBLIC_KEY_H_ +#define OPENSSL_ED_PUBLIC_KEY_H_ + +#include +#include + +/** + * Load an EdDSA public key using OpenSSL. + * + * Accepts a BUILD_BLOB_ASN1_DER argument. + * + * @param type type of the key, must be KEY_ED25519 or KEY_ED448 + * @param args builder_part_t argument list + * @return loaded key, NULL on failure + */ +public_key_t *openssl_ed_public_key_load(key_type_t type, va_list args); + +#endif /** OPENSSL_ED_PUBLIC_KEY_H_ @}*/ diff --git a/src/libstrongswan/plugins/openssl/openssl_plugin.c b/src/libstrongswan/plugins/openssl/openssl_plugin.c index b0db9325f..c5f1c5b14 100644 --- a/src/libstrongswan/plugins/openssl/openssl_plugin.c +++ b/src/libstrongswan/plugins/openssl/openssl_plugin.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2016 Tobias Brunner + * Copyright (C) 2008-2018 Tobias Brunner * Copyright (C) 2008 Martin Willi * HSR Hochschule fuer Technik Rapperswil * @@ -47,6 +47,9 @@ #include "openssl_rng.h" #include "openssl_hmac.h" #include "openssl_gcm.h" +#include "openssl_x_diffie_hellman.h" +#include "openssl_ed_public_key.h" +#include "openssl_ed_private_key.h" #ifndef FIPS_MODE #define FIPS_MODE 0 @@ -307,6 +310,11 @@ static private_key_t *openssl_private_key_load(key_type_t type, va_list args) case EVP_PKEY_EC: return openssl_ec_private_key_create(key, FALSE); #endif +#if OPENSSL_VERSION_NUMBER >= 0x1010100fL && !defined(OPENSSL_NO_EC) + case EVP_PKEY_ED25519: + case EVP_PKEY_ED448: + return openssl_ed_private_key_create(key, FALSE); +#endif /* OPENSSL_VERSION_NUMBER */ default: EVP_PKEY_free(key); break; @@ -454,6 +462,11 @@ static private_key_t *openssl_private_key_connect(key_type_t type, case EVP_PKEY_EC: return openssl_ec_private_key_create(key, TRUE); #endif +#if OPENSSL_VERSION_NUMBER >= 0x1010100fL && !defined(OPENSSL_NO_EC) + case EVP_PKEY_ED25519: + case EVP_PKEY_ED448: + return openssl_ed_private_key_create(key, TRUE); +#endif /* OPENSSL_VERSION_NUMBER */ default: EVP_PKEY_free(key); break; @@ -594,7 +607,7 @@ METHOD(plugin_t, get_features, int, PLUGIN_PROVIDE(DH, ECP_384_BP), PLUGIN_PROVIDE(DH, ECP_512_BP), PLUGIN_PROVIDE(DH, ECP_224_BP), -#endif +#endif /* OPENSSL_NO_ECDH */ #ifndef OPENSSL_NO_DH /* MODP DH groups */ PLUGIN_REGISTER(DH, openssl_diffie_hellman_create), @@ -699,6 +712,30 @@ METHOD(plugin_t, get_features, int, PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_ECDSA_521), #endif #endif /* OPENSSL_NO_ECDSA */ +#if OPENSSL_VERSION_NUMBER >= 0x1010100fL && !defined(OPENSSL_NO_EC) + PLUGIN_REGISTER(DH, openssl_x_diffie_hellman_create), + /* available since 1.1.0a, but we require 1.1.1 features */ + PLUGIN_PROVIDE(DH, CURVE_25519), + /* available since 1.1.1 */ + PLUGIN_PROVIDE(DH, CURVE_448), + /* EdDSA private/public key loading */ + PLUGIN_REGISTER(PUBKEY, openssl_ed_public_key_load, TRUE), + PLUGIN_PROVIDE(PUBKEY, KEY_ED25519), + PLUGIN_PROVIDE(PUBKEY, KEY_ED448), + PLUGIN_REGISTER(PRIVKEY, openssl_ed_private_key_load, TRUE), + PLUGIN_PROVIDE(PRIVKEY, KEY_ED25519), + PLUGIN_PROVIDE(PRIVKEY, KEY_ED448), + PLUGIN_REGISTER(PRIVKEY_GEN, openssl_ed_private_key_gen, FALSE), + PLUGIN_PROVIDE(PRIVKEY_GEN, KEY_ED25519), + PLUGIN_PROVIDE(PRIVKEY_GEN, KEY_ED448), + PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_ED25519), + PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_ED448), + PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_ED25519), + PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_ED448), + /* register a pro forma identity hasher, never instantiated */ + PLUGIN_REGISTER(HASHER, return_null), + PLUGIN_PROVIDE(HASHER, HASH_IDENTITY), +#endif /* OPENSSL_VERSION_NUMBER && !OPENSSL_NO_EC */ /* generic key loader */ PLUGIN_REGISTER(PRIVKEY, openssl_private_key_load, TRUE), PLUGIN_PROVIDE(PRIVKEY, KEY_ANY), diff --git a/src/libstrongswan/plugins/openssl/openssl_rng.c b/src/libstrongswan/plugins/openssl/openssl_rng.c index a25b6b4b6..9514ca916 100644 --- a/src/libstrongswan/plugins/openssl/openssl_rng.c +++ b/src/libstrongswan/plugins/openssl/openssl_rng.c @@ -1,4 +1,7 @@ /* + * Copyright (C) 2012-2018 Tobias Brunner + * HSR Hochschule fuer Technik Rapperswil + * * Copyright (C) 2012 Aleksandr Grinberg * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -24,7 +27,6 @@ #include #include -#include #include "openssl_rng.h" @@ -49,6 +51,13 @@ struct private_openssl_rng_t { METHOD(rng_t, get_bytes, bool, private_openssl_rng_t *this, size_t bytes, uint8_t *buffer) { +#if OPENSSL_VERSION_NUMBER >= 0x1010100fL + if (this->quality > RNG_WEAK) + { /* use a separate DRBG for data we wan't to keep private, compared + * to e.g. nonces */ + return RAND_priv_bytes((char*)buffer, bytes) == 1; + } +#endif return RAND_bytes((char*)buffer, bytes) == 1; } diff --git a/src/libstrongswan/plugins/openssl/openssl_x_diffie_hellman.c b/src/libstrongswan/plugins/openssl/openssl_x_diffie_hellman.c new file mode 100644 index 000000000..37943f5bf --- /dev/null +++ b/src/libstrongswan/plugins/openssl/openssl_x_diffie_hellman.c @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2018 Tobias Brunner + * 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 . + * + * 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 + +/* basic support for X25519 was added with 1.1.0a, but we require features (e.g. + * to load the keys) that were only added with 1.1.1 */ +#if OPENSSL_VERSION_NUMBER >= 0x1010100fL && !defined(OPENSSL_NO_ECDH) + +#include "openssl_x_diffie_hellman.h" + +#include + +typedef struct private_diffie_hellman_t private_diffie_hellman_t; + +/** + * Private data + */ +struct private_diffie_hellman_t { + /** + * Public interface. + */ + diffie_hellman_t public; + + /** + * Diffie Hellman group number. + */ + diffie_hellman_group_t group; + + /** + * Private (public) key + */ + EVP_PKEY *key; + + /** + * Shared secret + */ + chunk_t shared_secret; + + /** + * True if shared secret is computed + */ + bool computed; +}; + +/** + * Map a DH group to a key type + */ +static int map_key_type(diffie_hellman_group_t group) +{ + switch (group) + { + case CURVE_25519: + return EVP_PKEY_X25519; + case CURVE_448: + return EVP_PKEY_X448; + default: + return 0; + } +} + +/** + * Compute the shared secret + */ +static bool compute_shared_key(private_diffie_hellman_t *this, EVP_PKEY *pub, + chunk_t *shared_secret) +{ + EVP_PKEY_CTX *ctx; + bool success = FALSE; + + ctx = EVP_PKEY_CTX_new(this->key, NULL); + if (!ctx) + { + return FALSE; + } + + if (EVP_PKEY_derive_init(ctx) <= 0) + { + goto error; + } + + if (EVP_PKEY_derive_set_peer(ctx, pub) <= 0) + { + goto error; + } + + if (EVP_PKEY_derive(ctx, NULL, &shared_secret->len) <= 0) + { + goto error; + } + + *shared_secret = chunk_alloc(shared_secret->len); + + if (EVP_PKEY_derive(ctx, shared_secret->ptr, &shared_secret->len) <= 0) + { + goto error; + } + + success = TRUE; + +error: + EVP_PKEY_CTX_free(ctx); + return success; +} + +METHOD(diffie_hellman_t, set_other_public_value, bool, + private_diffie_hellman_t *this, chunk_t value) +{ + EVP_PKEY *pub; + + if (!diffie_hellman_verify_value(this->group, value)) + { + return FALSE; + } + + pub = EVP_PKEY_new_raw_public_key(map_key_type(this->group), NULL, + value.ptr, value.len); + if (!pub) + { + DBG1(DBG_LIB, "%N public value is malformed", + diffie_hellman_group_names, this->group); + return FALSE; + } + + chunk_clear(&this->shared_secret); + + if (!compute_shared_key(this, pub, &this->shared_secret)) + { + DBG1(DBG_LIB, "%N shared secret computation failed", + diffie_hellman_group_names, this->group); + EVP_PKEY_free(pub); + return FALSE; + } + this->computed = TRUE; + EVP_PKEY_free(pub); + return TRUE; +} + +METHOD(diffie_hellman_t, get_my_public_value, bool, + private_diffie_hellman_t *this, chunk_t *value) +{ + size_t len; + + if (!EVP_PKEY_get_raw_public_key(this->key, NULL, &len)) + { + return FALSE; + } + + *value = chunk_alloc(len); + + if (!EVP_PKEY_get_raw_public_key(this->key, value->ptr, &value->len)) + { + chunk_free(value); + return FALSE; + } + return TRUE; +} + +METHOD(diffie_hellman_t, set_private_value, bool, + private_diffie_hellman_t *this, chunk_t value) +{ + EVP_PKEY_free(this->key); + this->key = EVP_PKEY_new_raw_private_key(map_key_type(this->group), NULL, + value.ptr, value.len); + if (!this->key) + { + return FALSE; + } + return TRUE; +} + +METHOD(diffie_hellman_t, get_shared_secret, bool, + private_diffie_hellman_t *this, chunk_t *secret) +{ + if (!this->computed) + { + return FALSE; + } + *secret = chunk_clone(this->shared_secret); + return TRUE; +} + +METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t, + private_diffie_hellman_t *this) +{ + return this->group; +} + +METHOD(diffie_hellman_t, destroy, void, + private_diffie_hellman_t *this) +{ + EVP_PKEY_free(this->key); + chunk_clear(&this->shared_secret); + free(this); +} + +/* + * Described in header + */ +diffie_hellman_t *openssl_x_diffie_hellman_create(diffie_hellman_group_t group) +{ + private_diffie_hellman_t *this; + EVP_PKEY_CTX *ctx = NULL; + EVP_PKEY *key = NULL; + + switch (group) + { + case CURVE_25519: + ctx = EVP_PKEY_CTX_new_id(NID_X25519, NULL); + break; + case CURVE_448: + ctx = EVP_PKEY_CTX_new_id(NID_X448, NULL); + break; + default: + break; + } + + if (!ctx || + EVP_PKEY_keygen_init(ctx) <= 0 || + EVP_PKEY_keygen(ctx, &key) <= 0) + { + DBG1(DBG_LIB, "generating key for %N failed", + diffie_hellman_group_names, group); + EVP_PKEY_CTX_free(ctx); + return NULL; + } + EVP_PKEY_CTX_free(ctx); + + INIT(this, + .public = { + .get_shared_secret = _get_shared_secret, + .set_other_public_value = _set_other_public_value, + .get_my_public_value = _get_my_public_value, + .set_private_value = _set_private_value, + .get_dh_group = _get_dh_group, + .destroy = _destroy, + }, + .group = group, + .key = key, + ); + return &this->public; +} + +#endif /* OPENSSL_NO_ECDH */ diff --git a/src/libstrongswan/plugins/openssl/openssl_x_diffie_hellman.h b/src/libstrongswan/plugins/openssl/openssl_x_diffie_hellman.h new file mode 100644 index 000000000..e28f38d15 --- /dev/null +++ b/src/libstrongswan/plugins/openssl/openssl_x_diffie_hellman.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2018 Tobias Brunner + * 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 . + * + * 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. + */ + +/** + * Implementation of the X25519/X448 Diffie-Hellman algorithm using OpenSSL. + * + * @defgroup openssl_x_diffie_hellman openssl_x_diffie_hellman + * @{ @ingroup openssl_p + */ + +#ifndef OPENSSL_X_DIFFIE_HELLMAN_H_ +#define OPENSSL_X_DIFFIE_HELLMAN_H_ + +#include + +/** + * Creates a new diffie_hellman_t object. + * + * @param group Diffie Hellman group number to use + * @return object, NULL if not supported + */ +diffie_hellman_t *openssl_x_diffie_hellman_create(diffie_hellman_group_t group); + +#endif /** OPENSSL_X_DIFFIE_HELLMAN_H_ @}*/ + diff --git a/src/libstrongswan/plugins/test_vectors/Makefile.am b/src/libstrongswan/plugins/test_vectors/Makefile.am index c4d9f2fc5..3d34cf7c9 100644 --- a/src/libstrongswan/plugins/test_vectors/Makefile.am +++ b/src/libstrongswan/plugins/test_vectors/Makefile.am @@ -49,6 +49,7 @@ libstrongswan_test_vectors_la_SOURCES = \ test_vectors/ecp.c \ test_vectors/ecpbp.c \ test_vectors/curve25519.c \ + test_vectors/curve448.c \ test_vectors/rng.c libstrongswan_test_vectors_la_LDFLAGS = -module -avoid-version diff --git a/src/libstrongswan/plugins/test_vectors/test_vectors.h b/src/libstrongswan/plugins/test_vectors/test_vectors.h index ded93ac90..7c8ac0c6e 100644 --- a/src/libstrongswan/plugins/test_vectors/test_vectors.h +++ b/src/libstrongswan/plugins/test_vectors/test_vectors.h @@ -306,3 +306,4 @@ TEST_VECTOR_DH(ecp384bp) TEST_VECTOR_DH(ecp512bp) TEST_VECTOR_DH(curve25519_1) TEST_VECTOR_DH(curve25519_2) +TEST_VECTOR_DH(curve448_1) diff --git a/src/libstrongswan/plugins/test_vectors/test_vectors/curve25519.c b/src/libstrongswan/plugins/test_vectors/test_vectors/curve25519.c index 676fcfc5a..23c024a37 100644 --- a/src/libstrongswan/plugins/test_vectors/test_vectors/curve25519.c +++ b/src/libstrongswan/plugins/test_vectors/test_vectors/curve25519.c @@ -16,7 +16,7 @@ #include /** - * From RFC 8037 + * From RFC 7748 */ dh_test_vector_t curve25519_1 = { .group = CURVE_25519, .priv_len = 32, .pub_len = 32, .shared_len = 32, diff --git a/src/libstrongswan/plugins/test_vectors/test_vectors/curve448.c b/src/libstrongswan/plugins/test_vectors/test_vectors/curve448.c new file mode 100644 index 000000000..fccbb808a --- /dev/null +++ b/src/libstrongswan/plugins/test_vectors/test_vectors/curve448.c @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2018 Tobias Brunner + * 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 Licenseor (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be usefulbut + * 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 + +/** + * From RFC 7748 + */ +dh_test_vector_t curve448_1 = { + .group = CURVE_448, .priv_len = 56, .pub_len = 56, .shared_len = 56, + .priv_a = "\x9a\x8f\x49\x25\xd1\x51\x9f\x57\x75\xcf\x46\xb0\x4b\x58\x00\xd4" + "\xee\x9e\xe8\xba\xe8\xbc\x55\x65\xd4\x98\xc2\x8d\xd9\xc9\xba\xf5" + "\x74\xa9\x41\x97\x44\x89\x73\x91\x00\x63\x82\xa6\xf1\x27\xab\x1d" + "\x9a\xc2\xd8\xc0\xa5\x98\x72\x6b", + .priv_b = "\x1c\x30\x6a\x7a\xc2\xa0\xe2\xe0\x99\x0b\x29\x44\x70\xcb\xa3\x39" + "\xe6\x45\x37\x72\xb0\x75\x81\x1d\x8f\xad\x0d\x1d\x69\x27\xc1\x20" + "\xbb\x5e\xe8\x97\x2b\x0d\x3e\x21\x37\x4c\x9c\x92\x1b\x09\xd1\xb0" + "\x36\x6f\x10\xb6\x51\x73\x99\x2d", + .pub_a = "\x9b\x08\xf7\xcc\x31\xb7\xe3\xe6\x7d\x22\xd5\xae\xa1\x21\x07\x4a" + "\x27\x3b\xd2\xb8\x3d\xe0\x9c\x63\xfa\xa7\x3d\x2c\x22\xc5\xd9\xbb" + "\xc8\x36\x64\x72\x41\xd9\x53\xd4\x0c\x5b\x12\xda\x88\x12\x0d\x53" + "\x17\x7f\x80\xe5\x32\xc4\x1f\xa0", + .pub_b = "\x3e\xb7\xa8\x29\xb0\xcd\x20\xf5\xbc\xfc\x0b\x59\x9b\x6f\xec\xcf" + "\x6d\xa4\x62\x71\x07\xbd\xb0\xd4\xf3\x45\xb4\x30\x27\xd8\xb9\x72" + "\xfc\x3e\x34\xfb\x42\x32\xa1\x3c\xa7\x06\xdc\xb5\x7a\xec\x3d\xae" + "\x07\xbd\xc1\xc6\x7b\xf3\x36\x09", + .shared = "\x07\xff\xf4\x18\x1a\xc6\xcc\x95\xec\x1c\x16\xa9\x4a\x0f\x74\xd1" + "\x2d\xa2\x32\xce\x40\xa7\x75\x52\x28\x1d\x28\x2b\xb6\x0c\x0b\x56" + "\xfd\x24\x64\xc3\x35\x54\x39\x36\x52\x1c\x24\x40\x30\x85\xd5\x9a" + "\x44\x9a\x50\x37\x51\x4a\x87\x9d", +}; diff --git a/src/libstrongswan/tests/Makefile.am b/src/libstrongswan/tests/Makefile.am index 5737e7a17..d4cac5a3b 100644 --- a/src/libstrongswan/tests/Makefile.am +++ b/src/libstrongswan/tests/Makefile.am @@ -58,6 +58,7 @@ libstrongswan_tests_SOURCES = tests.h tests.c \ suites/test_mgf1.c \ suites/test_ntru.c \ suites/test_ed25519.c \ + suites/test_ed448.c \ suites/test_signature_params.c libstrongswan_tests_CFLAGS = \ diff --git a/src/libstrongswan/tests/suites/test_ed25519.c b/src/libstrongswan/tests/suites/test_ed25519.c index 86cbb1bc0..c52b90885 100644 --- a/src/libstrongswan/tests/suites/test_ed25519.c +++ b/src/libstrongswan/tests/suites/test_ed25519.c @@ -24,10 +24,12 @@ struct sig_test_t { chunk_t pubkey; chunk_t msg; chunk_t sig; + chunk_t fp_pk; + chunk_t fp_spki; }; /** - * Ed25519 Test Vectors from draft-irtf-cfrg-eddsa + * Ed25519 Test Vectors from RFC 8032 */ static sig_test_t sig_tests[] = { /* Test 1 */ @@ -51,7 +53,13 @@ static sig_test_t sig_tests[] = { 0x01, 0x55, 0x5f, 0xb8, 0x82, 0x15, 0x90, 0xa3, 0x3b, 0xac, 0xc6, 0x1e, 0x39, 0x70, 0x1c, 0xf9, 0xb4, 0x6b, 0xd2, 0x5b, 0xf5, 0xf0, 0x59, 0x5b, 0xbe, 0x24, 0x65, 0x51, 0x41, 0x43, - 0x8e, 0x7a, 0x10, 0x0b) + 0x8e, 0x7a, 0x10, 0x0b), + chunk_from_chars( + 0x5b, 0x27, 0xaa, 0x55, 0x89, 0x17, 0x97, 0x70, 0xe4, 0x75, + 0x75, 0xb1, 0x62, 0xa1, 0xde, 0xd9, 0x7b, 0x8b, 0xfc, 0x6d), + chunk_from_chars( + 0xa5, 0x66, 0xbe, 0x19, 0x84, 0x01, 0x73, 0x41, 0x3a, 0x61, + 0x04, 0x83, 0x50, 0xef, 0xf2, 0x3e, 0x8f, 0xe2, 0x22, 0x66), }, /* Test 2 */ { chunk_from_chars( @@ -75,7 +83,13 @@ static sig_test_t sig_tests[] = { 0x69, 0xda, 0x08, 0x5a, 0xc1, 0xe4, 0x3e, 0x15, 0x99, 0x6e, 0x45, 0x8f, 0x36, 0x13, 0xd0, 0xf1, 0x1d, 0x8c, 0x38, 0x7b, 0x2e, 0xae, 0xb4, 0x30, 0x2a, 0xee, 0xb0, 0x0d, 0x29, 0x16, - 0x12, 0xbb, 0x0c, 0x00) + 0x12, 0xbb, 0x0c, 0x00), + chunk_from_chars( + 0x13, 0xf7, 0x72, 0x66, 0x9e, 0x15, 0x2a, 0xe6, 0xa6, 0x2a, + 0x60, 0xa3, 0x48, 0x8a, 0x6f, 0x29, 0x7d, 0x06, 0x13, 0xdd), + chunk_from_chars( + 0xbd, 0xae, 0x41, 0xeb, 0x5d, 0xbf, 0x88, 0xb9, 0xdf, 0x18, + 0xda, 0xbb, 0x2d, 0xee, 0xa9, 0x1a, 0x4e, 0x03, 0x38, 0xe4), }, /* Test 3 */ { chunk_from_chars( @@ -99,7 +113,13 @@ static sig_test_t sig_tests[] = { 0xc3, 0xac, 0x18, 0xff, 0x9b, 0x53, 0x8d, 0x16, 0xf2, 0x90, 0xae, 0x67, 0xf7, 0x60, 0x98, 0x4d, 0xc6, 0x59, 0x4a, 0x7c, 0x15, 0xe9, 0x71, 0x6e, 0xd2, 0x8d, 0xc0, 0x27, 0xbe, 0xce, - 0xea, 0x1e, 0xc4, 0x0a) + 0xea, 0x1e, 0xc4, 0x0a), + chunk_from_chars( + 0x88, 0xc7, 0x64, 0xc8, 0xbe, 0x44, 0x37, 0x4a, 0x7d, 0x2f, + 0x5d, 0x84, 0x72, 0x1f, 0x8e, 0x32, 0x5e, 0x5b, 0xd6, 0x4c), + chunk_from_chars( + 0xad, 0x01, 0x30, 0xb1, 0x2b, 0x48, 0x62, 0x9b, 0xb9, 0xad, + 0xea, 0x92, 0x1f, 0xfe, 0xd2, 0x9a, 0x42, 0xf0, 0xad, 0xe6), }, /* Test 1024 */ { chunk_from_chars( @@ -235,7 +255,13 @@ static sig_test_t sig_tests[] = { 0xc3, 0x50, 0xaa, 0x53, 0x71, 0xb1, 0x50, 0x8f, 0x9f, 0x45, 0x28, 0xec, 0xea, 0x23, 0xc4, 0x36, 0xd9, 0x4b, 0x5e, 0x8f, 0xcd, 0x4f, 0x68, 0x1e, 0x30, 0xa6, 0xac, 0x00, 0xa9, 0x70, - 0x4a, 0x18, 0x8a, 0x03) + 0x4a, 0x18, 0x8a, 0x03), + chunk_from_chars( + 0x11, 0x2d, 0xb3, 0x08, 0x97, 0x6e, 0x38, 0x8f, 0x5f, 0x5e, + 0xb0, 0xae, 0x8f, 0x5f, 0x59, 0x1d, 0xff, 0x74, 0xf4, 0x44), + chunk_from_chars( + 0xcb, 0x36, 0xcc, 0x6a, 0x82, 0x2c, 0x49, 0x40, 0xfb, 0x08, + 0x04, 0xf6, 0x3a, 0x4f, 0x20, 0x2b, 0xe5, 0x73, 0x43, 0x2f), }, /* Test SHA(abc) */ { chunk_from_chars( @@ -265,7 +291,13 @@ static sig_test_t sig_tests[] = { 0xb5, 0x89, 0x09, 0x35, 0x1f, 0xc9, 0xac, 0x90, 0xb3, 0xec, 0xfd, 0xfb, 0xc7, 0xc6, 0x64, 0x31, 0xe0, 0x30, 0x3d, 0xca, 0x17, 0x9c, 0x13, 0x8a, 0xc1, 0x7a, 0xd9, 0xbe, 0xf1, 0x17, - 0x73, 0x31, 0xa7, 0x04) + 0x73, 0x31, 0xa7, 0x04), + chunk_from_chars( + 0x26, 0x4c, 0xa5, 0x7f, 0x89, 0x6d, 0x64, 0x81, 0xd1, 0x87, + 0xe9, 0x89, 0x47, 0x29, 0x5a, 0xfe, 0xe3, 0x6d, 0x82, 0x44), + chunk_from_chars( + 0x27, 0x88, 0xfc, 0x14, 0xb1, 0xcd, 0xd0, 0x24, 0xd5, 0x9d, + 0x31, 0x65, 0x59, 0x63, 0x69, 0xcf, 0xaf, 0x50, 0x10, 0xe7), } }; @@ -273,24 +305,34 @@ START_TEST(test_ed25519_sign) { private_key_t *key; public_key_t *pubkey, *public; - chunk_t sig, encoding; + chunk_t sig, encoding, fp; /* load private key */ key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ED25519, BUILD_BLOB_ASN1_DER, sig_tests[_i].key, BUILD_END); ck_assert(key != NULL); ck_assert(key->get_encoding(key, PRIVKEY_ASN1_DER, &encoding)); - ck_assert(chunk_equals(encoding, sig_tests[_i].key)); + ck_assert_chunk_eq(encoding, sig_tests[_i].key); chunk_free(&encoding); + ck_assert(key->get_fingerprint(key, KEYID_PUBKEY_SHA1, &fp)); + ck_assert_chunk_eq(sig_tests[_i].fp_pk, fp); + ck_assert(key->get_fingerprint(key, KEYID_PUBKEY_INFO_SHA1, &fp)); + ck_assert_chunk_eq(sig_tests[_i].fp_spki, fp); + /* load public key */ pubkey = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ED25519, BUILD_BLOB_ASN1_DER, sig_tests[_i].pubkey, BUILD_END); ck_assert(pubkey != NULL); ck_assert(pubkey->get_encoding(pubkey, PUBKEY_SPKI_ASN1_DER, &encoding)); - ck_assert(chunk_equals(encoding, sig_tests[_i].pubkey)); + ck_assert_chunk_eq(encoding, sig_tests[_i].pubkey); chunk_free(&encoding); + ck_assert(pubkey->get_fingerprint(pubkey, KEYID_PUBKEY_SHA1, &fp)); + ck_assert_chunk_eq(sig_tests[_i].fp_pk, fp); + ck_assert(pubkey->get_fingerprint(pubkey, KEYID_PUBKEY_INFO_SHA1, &fp)); + ck_assert_chunk_eq(sig_tests[_i].fp_spki, fp); + /* compare public keys */ public = key->get_public_key(key); ck_assert(public != NULL); @@ -299,7 +341,7 @@ START_TEST(test_ed25519_sign) /* sign */ ck_assert(key->sign(key, SIGN_ED25519, NULL, sig_tests[_i].msg, &sig)); ck_assert(sig.len == 64); - ck_assert(chunk_equals(sig, sig_tests[_i].sig)); + ck_assert_chunk_eq(sig, sig_tests[_i].sig); /* verify */ ck_assert(pubkey->verify(pubkey, SIGN_ED25519, NULL, sig_tests[_i].msg, @@ -364,7 +406,7 @@ START_TEST(test_ed25519_gen) ck_assert(pubkey->get_fingerprint(pubkey, KEYID_PUBKEY_SHA1, &fp_pub)); ck_assert(pubkey->get_fingerprint(pubkey, KEYID_PUBKEY_SHA1, &fp_pub)); ck_assert(fp_pub.ptr != NULL); - ck_assert(chunk_equals(fp_pub, fp_priv)); + ck_assert_chunk_eq(fp_pub, fp_priv); /* clone public key */ pubkey2 = pubkey->get_ref(pubkey); @@ -429,6 +471,16 @@ static chunk_t zero_pk = chunk_from_chars( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); +/* sig_tests[0].sig with s+L */ +static chunk_t malleable_sig = chunk_from_chars( + 0xe5, 0x56, 0x43, 0x00, 0xc3, 0x60, 0xac, 0x72, 0x90, 0x86, + 0xe2, 0xcc, 0x80, 0x6e, 0x82, 0x8a, 0x84, 0x87, 0x7f, 0x1e, + 0xb8, 0xe5, 0xd9, 0x74, 0xd8, 0x73, 0xe0, 0x65, 0x22, 0x49, + 0x01, 0x55, 0x4c, 0x8c, 0x78, 0x72, 0xaa, 0x06, 0x4e, 0x04, + 0x9d, 0xbb, 0x30, 0x13, 0xfb, 0xf2, 0x93, 0x80, 0xd2, 0x5b, + 0xf5, 0xf0, 0x59, 0x5b, 0xbe, 0x24, 0x65, 0x51, 0x41, 0x43, + 0x8e, 0x7a, 0x10, 0x1b); + START_TEST(test_ed25519_fail) { private_key_t *key; @@ -479,6 +531,16 @@ START_TEST(test_ed25519_fail) ck_assert(!pubkey->verify(pubkey, SIGN_ED25519, NULL, chunk_empty, chunk_empty)); + /* RFC 8032, section 5.1.7 requires that 0 <= s < L to prevent signature + * malleability. Only a warning because Botan and OpenSSL are both + * vulnerable to this. */ + if (pubkey->verify(pubkey, SIGN_ED25519, NULL, sig_tests[0].msg, + malleable_sig)) + { + warn("Ed25519 signature verification is vulnerable to malleable " + "signatures"); + } + /* malformed signature */ sig = chunk_create(sig1, 64); memcpy(sig1, sig_tests[0].sig.ptr, 64); diff --git a/src/libstrongswan/tests/suites/test_ed448.c b/src/libstrongswan/tests/suites/test_ed448.c new file mode 100644 index 000000000..288da19a0 --- /dev/null +++ b/src/libstrongswan/tests/suites/test_ed448.c @@ -0,0 +1,654 @@ +/* + * Copyright (C) 2018 Tobias Brunner + * 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 . + * + * 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 "test_suite.h" + +#include + +typedef struct sig_test_t sig_test_t; + +struct sig_test_t { + chunk_t key; + chunk_t pubkey; + chunk_t msg; + chunk_t sig; + chunk_t fp_pk; + chunk_t fp_spki; +}; + +/** + * Ed448 Test Vectors from RFC 8032 + */ +static sig_test_t sig_tests[] = { + /* Blank */ + { chunk_from_chars( + 0x30,0x47,0x02,0x01,0x00,0x30,0x05,0x06,0x03,0x2b,0x65,0x71,0x04,0x3b,0x04,0x39, + 0x6c,0x82,0xa5,0x62,0xcb,0x80,0x8d,0x10,0xd6,0x32,0xbe,0x89,0xc8,0x51,0x3e,0xbf, + 0x6c,0x92,0x9f,0x34,0xdd,0xfa,0x8c,0x9f,0x63,0xc9,0x96,0x0e,0xf6,0xe3,0x48,0xa3, + 0x52,0x8c,0x8a,0x3f,0xcc,0x2f,0x04,0x4e,0x39,0xa3,0xfc,0x5b,0x94,0x49,0x2f,0x8f, + 0x03,0x2e,0x75,0x49,0xa2,0x00,0x98,0xf9,0x5b), + chunk_from_chars( + 0x30,0x43,0x30,0x05,0x06,0x03,0x2b,0x65,0x71,0x03,0x3a,0x00,0x5f,0xd7,0x44,0x9b, + 0x59,0xb4,0x61,0xfd,0x2c,0xe7,0x87,0xec,0x61,0x6a,0xd4,0x6a,0x1d,0xa1,0x34,0x24, + 0x85,0xa7,0x0e,0x1f,0x8a,0x0e,0xa7,0x5d,0x80,0xe9,0x67,0x78,0xed,0xf1,0x24,0x76, + 0x9b,0x46,0xc7,0x06,0x1b,0xd6,0x78,0x3d,0xf1,0xe5,0x0f,0x6c,0xd1,0xfa,0x1a,0xbe, + 0xaf,0xe8,0x25,0x61,0x80), + { NULL, 0 }, + chunk_from_chars( + 0x53,0x3a,0x37,0xf6,0xbb,0xe4,0x57,0x25,0x1f,0x02,0x3c,0x0d,0x88,0xf9,0x76,0xae, + 0x2d,0xfb,0x50,0x4a,0x84,0x3e,0x34,0xd2,0x07,0x4f,0xd8,0x23,0xd4,0x1a,0x59,0x1f, + 0x2b,0x23,0x3f,0x03,0x4f,0x62,0x82,0x81,0xf2,0xfd,0x7a,0x22,0xdd,0xd4,0x7d,0x78, + 0x28,0xc5,0x9b,0xd0,0xa2,0x1b,0xfd,0x39,0x80,0xff,0x0d,0x20,0x28,0xd4,0xb1,0x8a, + 0x9d,0xf6,0x3e,0x00,0x6c,0x5d,0x1c,0x2d,0x34,0x5b,0x92,0x5d,0x8d,0xc0,0x0b,0x41, + 0x04,0x85,0x2d,0xb9,0x9a,0xc5,0xc7,0xcd,0xda,0x85,0x30,0xa1,0x13,0xa0,0xf4,0xdb, + 0xb6,0x11,0x49,0xf0,0x5a,0x73,0x63,0x26,0x8c,0x71,0xd9,0x58,0x08,0xff,0x2e,0x65, + 0x26,0x00), + chunk_from_chars( + 0x6d,0xe0,0x8a,0x72,0x35,0x1e,0xf1,0xad,0xeb,0xca,0x2c,0xd7,0xf1,0xfd,0xa6,0x91, + 0x54,0xad,0xfa,0x4f), + chunk_from_chars( + 0x1b,0x7a,0x47,0x56,0x91,0xb8,0x41,0x33,0x0d,0x2e,0x4d,0xa5,0xe6,0x13,0xb9,0x89, + 0xda,0xce,0xc5,0x8e), + }, + /* 1 octet */ + { chunk_from_chars( + 0x30,0x47,0x02,0x01,0x00,0x30,0x05,0x06,0x03,0x2b,0x65,0x71,0x04,0x3b,0x04,0x39, + 0xc4,0xea,0xb0,0x5d,0x35,0x70,0x07,0xc6,0x32,0xf3,0xdb,0xb4,0x84,0x89,0x92,0x4d, + 0x55,0x2b,0x08,0xfe,0x0c,0x35,0x3a,0x0d,0x4a,0x1f,0x00,0xac,0xda,0x2c,0x46,0x3a, + 0xfb,0xea,0x67,0xc5,0xe8,0xd2,0x87,0x7c,0x5e,0x3b,0xc3,0x97,0xa6,0x59,0x94,0x9e, + 0xf8,0x02,0x1e,0x95,0x4e,0x0a,0x12,0x27,0x4e), + chunk_from_chars( + 0x30,0x43,0x30,0x05,0x06,0x03,0x2b,0x65,0x71,0x03,0x3a,0x00,0x43,0xba,0x28,0xf4, + 0x30,0xcd,0xff,0x45,0x6a,0xe5,0x31,0x54,0x5f,0x7e,0xcd,0x0a,0xc8,0x34,0xa5,0x5d, + 0x93,0x58,0xc0,0x37,0x2b,0xfa,0x0c,0x6c,0x67,0x98,0xc0,0x86,0x6a,0xea,0x01,0xeb, + 0x00,0x74,0x28,0x02,0xb8,0x43,0x8e,0xa4,0xcb,0x82,0x16,0x9c,0x23,0x51,0x60,0x62, + 0x7b,0x4c,0x3a,0x94,0x80), + chunk_from_chars( + 0x03), + chunk_from_chars( + 0x26,0xb8,0xf9,0x17,0x27,0xbd,0x62,0x89,0x7a,0xf1,0x5e,0x41,0xeb,0x43,0xc3,0x77, + 0xef,0xb9,0xc6,0x10,0xd4,0x8f,0x23,0x35,0xcb,0x0b,0xd0,0x08,0x78,0x10,0xf4,0x35, + 0x25,0x41,0xb1,0x43,0xc4,0xb9,0x81,0xb7,0xe1,0x8f,0x62,0xde,0x8c,0xcd,0xf6,0x33, + 0xfc,0x1b,0xf0,0x37,0xab,0x7c,0xd7,0x79,0x80,0x5e,0x0d,0xbc,0xc0,0xaa,0xe1,0xcb, + 0xce,0xe1,0xaf,0xb2,0xe0,0x27,0xdf,0x36,0xbc,0x04,0xdc,0xec,0xbf,0x15,0x43,0x36, + 0xc1,0x9f,0x0a,0xf7,0xe0,0xa6,0x47,0x29,0x05,0xe7,0x99,0xf1,0x95,0x3d,0x2a,0x0f, + 0xf3,0x34,0x8a,0xb2,0x1a,0xa4,0xad,0xaf,0xd1,0xd2,0x34,0x44,0x1c,0xf8,0x07,0xc0, + 0x3a,0x00), + chunk_from_chars( + 0x74,0xa7,0x4b,0x23,0x69,0x98,0x17,0x46,0x1f,0xca,0xcf,0x84,0xf7,0xc6,0x3e,0x05, + 0x2a,0x1b,0xf9,0xb8), + chunk_from_chars( + 0xf6,0x76,0xf7,0x63,0x82,0x2b,0x53,0x5c,0x61,0x9c,0xfa,0x4a,0x59,0x7d,0xdd,0xae, + 0x13,0x34,0xf0,0xb1), + }, + /* 11 octets */ + { chunk_from_chars( + 0x30,0x47,0x02,0x01,0x00,0x30,0x05,0x06,0x03,0x2b,0x65,0x71,0x04,0x3b,0x04,0x39, + 0xcd,0x23,0xd2,0x4f,0x71,0x42,0x74,0xe7,0x44,0x34,0x32,0x37,0xb9,0x32,0x90,0xf5, + 0x11,0xf6,0x42,0x5f,0x98,0xe6,0x44,0x59,0xff,0x20,0x3e,0x89,0x85,0x08,0x3f,0xfd, + 0xf6,0x05,0x00,0x55,0x3a,0xbc,0x0e,0x05,0xcd,0x02,0x18,0x4b,0xdb,0x89,0xc4,0xcc, + 0xd6,0x7e,0x18,0x79,0x51,0x26,0x7e,0xb3,0x28), + chunk_from_chars( + 0x30,0x43,0x30,0x05,0x06,0x03,0x2b,0x65,0x71,0x03,0x3a,0x00,0xdc,0xea,0x9e,0x78, + 0xf3,0x5a,0x1b,0xf3,0x49,0x9a,0x83,0x1b,0x10,0xb8,0x6c,0x90,0xaa,0xc0,0x1c,0xd8, + 0x4b,0x67,0xa0,0x10,0x9b,0x55,0xa3,0x6e,0x93,0x28,0xb1,0xe3,0x65,0xfc,0xe1,0x61, + 0xd7,0x1c,0xe7,0x13,0x1a,0x54,0x3e,0xa4,0xcb,0x5f,0x7e,0x9f,0x1d,0x8b,0x00,0x69, + 0x64,0x47,0x00,0x14,0x00), + chunk_from_chars( + 0x0c,0x3e,0x54,0x40,0x74,0xec,0x63,0xb0,0x26,0x5e,0x0c), + chunk_from_chars( + 0x1f,0x0a,0x88,0x88,0xce,0x25,0xe8,0xd4,0x58,0xa2,0x11,0x30,0x87,0x9b,0x84,0x0a, + 0x90,0x89,0xd9,0x99,0xaa,0xba,0x03,0x9e,0xaf,0x3e,0x3a,0xfa,0x09,0x0a,0x09,0xd3, + 0x89,0xdb,0xa8,0x2c,0x4f,0xf2,0xae,0x8a,0xc5,0xcd,0xfb,0x7c,0x55,0xe9,0x4d,0x5d, + 0x96,0x1a,0x29,0xfe,0x01,0x09,0x94,0x1e,0x00,0xb8,0xdb,0xde,0xea,0x6d,0x3b,0x05, + 0x10,0x68,0xdf,0x72,0x54,0xc0,0xcd,0xc1,0x29,0xcb,0xe6,0x2d,0xb2,0xdc,0x95,0x7d, + 0xbb,0x47,0xb5,0x1f,0xd3,0xf2,0x13,0xfb,0x86,0x98,0xf0,0x64,0x77,0x42,0x50,0xa5, + 0x02,0x89,0x61,0xc9,0xbf,0x8f,0xfd,0x97,0x3f,0xe5,0xd5,0xc2,0x06,0x49,0x2b,0x14, + 0x0e,0x00), + chunk_from_chars( + 0x3b,0x56,0x55,0xa4,0xce,0x4c,0xec,0x67,0x77,0x9c,0x9f,0xeb,0xfe,0x6f,0x38,0xba, + 0x88,0xc2,0x25,0x10), + chunk_from_chars( + 0x71,0xcb,0xf2,0xb7,0x1b,0x3b,0x77,0xcb,0xd6,0x41,0x05,0x02,0x72,0x31,0xa6,0x91, + 0x27,0x3f,0xe5,0x51), + }, + /* 12 octets */ + { chunk_from_chars( + 0x30,0x47,0x02,0x01,0x00,0x30,0x05,0x06,0x03,0x2b,0x65,0x71,0x04,0x3b,0x04,0x39, + 0x25,0x8c,0xdd,0x4a,0xda,0x32,0xed,0x9c,0x9f,0xf5,0x4e,0x63,0x75,0x6a,0xe5,0x82, + 0xfb,0x8f,0xab,0x2a,0xc7,0x21,0xf2,0xc8,0xe6,0x76,0xa7,0x27,0x68,0x51,0x3d,0x93, + 0x9f,0x63,0xdd,0xdb,0x55,0x60,0x91,0x33,0xf2,0x9a,0xdf,0x86,0xec,0x99,0x29,0xdc, + 0xcb,0x52,0xc1,0xc5,0xfd,0x2f,0xf7,0xe2,0x1b), + chunk_from_chars( + 0x30,0x43,0x30,0x05,0x06,0x03,0x2b,0x65,0x71,0x03,0x3a,0x00,0x3b,0xa1,0x6d,0xa0, + 0xc6,0xf2,0xcc,0x1f,0x30,0x18,0x77,0x40,0x75,0x6f,0x5e,0x79,0x8d,0x6b,0xc5,0xfc, + 0x01,0x5d,0x7c,0x63,0xcc,0x95,0x10,0xee,0x3f,0xd4,0x4a,0xdc,0x24,0xd8,0xe9,0x68, + 0xb6,0xe4,0x6e,0x6f,0x94,0xd1,0x9b,0x94,0x53,0x61,0x72,0x6b,0xd7,0x5e,0x14,0x9e, + 0xf0,0x98,0x17,0xf5,0x80), + chunk_from_chars( + 0x64,0xa6,0x5f,0x3c,0xde,0xdc,0xdd,0x66,0x81,0x1e,0x29,0x15), + chunk_from_chars( + 0x7e,0xee,0xab,0x7c,0x4e,0x50,0xfb,0x79,0x9b,0x41,0x8e,0xe5,0xe3,0x19,0x7f,0xf6, + 0xbf,0x15,0xd4,0x3a,0x14,0xc3,0x43,0x89,0xb5,0x9d,0xd1,0xa7,0xb1,0xb8,0x5b,0x4a, + 0xe9,0x04,0x38,0xac,0xa6,0x34,0xbe,0xa4,0x5e,0x3a,0x26,0x95,0xf1,0x27,0x0f,0x07, + 0xfd,0xcd,0xf7,0xc6,0x2b,0x8e,0xfe,0xaf,0x00,0xb4,0x5c,0x2c,0x96,0xba,0x45,0x7e, + 0xb1,0xa8,0xbf,0x07,0x5a,0x3d,0xb2,0x8e,0x5c,0x24,0xf6,0xb9,0x23,0xed,0x4a,0xd7, + 0x47,0xc3,0xc9,0xe0,0x3c,0x70,0x79,0xef,0xb8,0x7c,0xb1,0x10,0xd3,0xa9,0x98,0x61, + 0xe7,0x20,0x03,0xcb,0xae,0x6d,0x6b,0x8b,0x82,0x7e,0x4e,0x6c,0x14,0x30,0x64,0xff, + 0x3c,0x00), + chunk_from_chars( + 0x56,0x8e,0xad,0x67,0xa7,0x83,0x78,0xfe,0x8f,0xaf,0xa7,0x87,0x2e,0xc8,0x95,0xa0, + 0xde,0x05,0x37,0x4c), + chunk_from_chars( + 0xed,0x1b,0xe5,0xa1,0x97,0x23,0x59,0x4d,0x86,0x6b,0x6b,0xef,0xfb,0x81,0xe4,0x8e, + 0xf7,0x42,0xe0,0x81), + }, + /* 13 octets */ + { chunk_from_chars( + 0x30,0x47,0x02,0x01,0x00,0x30,0x05,0x06,0x03,0x2b,0x65,0x71,0x04,0x3b,0x04,0x39, + 0x7e,0xf4,0xe8,0x45,0x44,0x23,0x67,0x52,0xfb,0xb5,0x6b,0x8f,0x31,0xa2,0x3a,0x10, + 0xe4,0x28,0x14,0xf5,0xf5,0x5c,0xa0,0x37,0xcd,0xcc,0x11,0xc6,0x4c,0x9a,0x3b,0x29, + 0x49,0xc1,0xbb,0x60,0x70,0x03,0x14,0x61,0x17,0x32,0xa6,0xc2,0xfe,0xa9,0x8e,0xeb, + 0xc0,0x26,0x6a,0x11,0xa9,0x39,0x70,0x10,0x0e), + chunk_from_chars( + 0x30,0x43,0x30,0x05,0x06,0x03,0x2b,0x65,0x71,0x03,0x3a,0x00,0xb3,0xda,0x07,0x9b, + 0x0a,0xa4,0x93,0xa5,0x77,0x20,0x29,0xf0,0x46,0x7b,0xae,0xbe,0xe5,0xa8,0x11,0x2d, + 0x9d,0x3a,0x22,0x53,0x23,0x61,0xda,0x29,0x4f,0x7b,0xb3,0x81,0x5c,0x5d,0xc5,0x9e, + 0x17,0x6b,0x4d,0x9f,0x38,0x1c,0xa0,0x93,0x8e,0x13,0xc6,0xc0,0x7b,0x17,0x4b,0xe6, + 0x5d,0xfa,0x57,0x8e,0x80), + chunk_from_chars( + 0x64,0xa6,0x5f,0x3c,0xde,0xdc,0xdd,0x66,0x81,0x1e,0x29,0x15,0xe7), + chunk_from_chars( + 0x6a,0x12,0x06,0x6f,0x55,0x33,0x1b,0x6c,0x22,0xac,0xd5,0xd5,0xbf,0xc5,0xd7,0x12, + 0x28,0xfb,0xda,0x80,0xae,0x8d,0xec,0x26,0xbd,0xd3,0x06,0x74,0x3c,0x50,0x27,0xcb, + 0x48,0x90,0x81,0x0c,0x16,0x2c,0x02,0x74,0x68,0x67,0x5e,0xcf,0x64,0x5a,0x83,0x17, + 0x6c,0x0d,0x73,0x23,0xa2,0xcc,0xde,0x2d,0x80,0xef,0xe5,0xa1,0x26,0x8e,0x8a,0xca, + 0x1d,0x6f,0xbc,0x19,0x4d,0x3f,0x77,0xc4,0x49,0x86,0xeb,0x4a,0xb4,0x17,0x79,0x19, + 0xad,0x8b,0xec,0x33,0xeb,0x47,0xbb,0xb5,0xfc,0x6e,0x28,0x19,0x6f,0xd1,0xca,0xf5, + 0x6b,0x4e,0x7e,0x0b,0xa5,0x51,0x92,0x34,0xd0,0x47,0x15,0x5a,0xc7,0x27,0xa1,0x05, + 0x31,0x00), + chunk_from_chars( + 0x6e,0xb1,0xb6,0x33,0x76,0xa8,0x0f,0x84,0x26,0x23,0xfb,0xaa,0x9e,0xaa,0x1d,0x8d, + 0x6d,0xa5,0x75,0x4e), + chunk_from_chars( + 0xfa,0x2f,0xeb,0xff,0x13,0xc0,0xee,0xd0,0x3b,0xc6,0xf2,0x7d,0xb8,0x61,0xe5,0x9d, + 0x16,0x53,0xb1,0x11), + }, + /* 64 octets */ + { chunk_from_chars( + 0x30,0x47,0x02,0x01,0x00,0x30,0x05,0x06,0x03,0x2b,0x65,0x71,0x04,0x3b,0x04,0x39, + 0xd6,0x5d,0xf3,0x41,0xad,0x13,0xe0,0x08,0x56,0x76,0x88,0xba,0xed,0xda,0x8e,0x9d, + 0xcd,0xc1,0x7d,0xc0,0x24,0x97,0x4e,0xa5,0xb4,0x22,0x7b,0x65,0x30,0xe3,0x39,0xbf, + 0xf2,0x1f,0x99,0xe6,0x8c,0xa6,0x96,0x8f,0x3c,0xca,0x6d,0xfe,0x0f,0xb9,0xf4,0xfa, + 0xb4,0xfa,0x13,0x5d,0x55,0x42,0xea,0x3f,0x01), + chunk_from_chars( + 0x30,0x43,0x30,0x05,0x06,0x03,0x2b,0x65,0x71,0x03,0x3a,0x00,0xdf,0x97,0x05,0xf5, + 0x8e,0xdb,0xab,0x80,0x2c,0x7f,0x83,0x63,0xcf,0xe5,0x56,0x0a,0xb1,0xc6,0x13,0x2c, + 0x20,0xa9,0xf1,0xdd,0x16,0x34,0x83,0xa2,0x6f,0x8a,0xc5,0x3a,0x39,0xd6,0x80,0x8b, + 0xf4,0xa1,0xdf,0xbd,0x26,0x1b,0x09,0x9b,0xb0,0x3b,0x3f,0xb5,0x09,0x06,0xcb,0x28, + 0xbd,0x8a,0x08,0x1f,0x00), + chunk_from_chars( + 0xbd,0x0f,0x6a,0x37,0x47,0xcd,0x56,0x1b,0xdd,0xdf,0x46,0x40,0xa3,0x32,0x46,0x1a, + 0x4a,0x30,0xa1,0x2a,0x43,0x4c,0xd0,0xbf,0x40,0xd7,0x66,0xd9,0xc6,0xd4,0x58,0xe5, + 0x51,0x22,0x04,0xa3,0x0c,0x17,0xd1,0xf5,0x0b,0x50,0x79,0x63,0x1f,0x64,0xeb,0x31, + 0x12,0x18,0x2d,0xa3,0x00,0x58,0x35,0x46,0x11,0x13,0x71,0x8d,0x1a,0x5e,0xf9,0x44), + chunk_from_chars( + 0x55,0x4b,0xc2,0x48,0x08,0x60,0xb4,0x9e,0xab,0x85,0x32,0xd2,0xa5,0x33,0xb7,0xd5, + 0x78,0xef,0x47,0x3e,0xeb,0x58,0xc9,0x8b,0xb2,0xd0,0xe1,0xce,0x48,0x8a,0x98,0xb1, + 0x8d,0xfd,0xe9,0xb9,0xb9,0x07,0x75,0xe6,0x7f,0x47,0xd4,0xa1,0xc3,0x48,0x20,0x58, + 0xef,0xc9,0xf4,0x0d,0x2c,0xa0,0x33,0xa0,0x80,0x1b,0x63,0xd4,0x5b,0x3b,0x72,0x2e, + 0xf5,0x52,0xba,0xd3,0xb4,0xcc,0xb6,0x67,0xda,0x35,0x01,0x92,0xb6,0x1c,0x50,0x8c, + 0xf7,0xb6,0xb5,0xad,0xad,0xc2,0xc8,0xd9,0xa4,0x46,0xef,0x00,0x3f,0xb0,0x5c,0xba, + 0x5f,0x30,0xe8,0x8e,0x36,0xec,0x27,0x03,0xb3,0x49,0xca,0x22,0x9c,0x26,0x70,0x83, + 0x39,0x00), + chunk_from_chars( + 0x2b,0xb0,0xd4,0x29,0xb8,0x51,0x3f,0xb5,0x9d,0x07,0xd0,0xb0,0x1f,0x4a,0x39,0x25, + 0x33,0xae,0x3e,0x64), + chunk_from_chars( + 0x79,0xbb,0x37,0xe4,0x2a,0xf9,0x58,0xb7,0xa4,0x58,0x18,0x88,0x4b,0x82,0x8f,0xfb, + 0x9c,0x74,0xce,0x9d), + }, + /* 256 octets */ + { chunk_from_chars( + 0x30,0x47,0x02,0x01,0x00,0x30,0x05,0x06,0x03,0x2b,0x65,0x71,0x04,0x3b,0x04,0x39, + 0x2e,0xc5,0xfe,0x3c,0x17,0x04,0x5a,0xbd,0xb1,0x36,0xa5,0xe6,0xa9,0x13,0xe3,0x2a, + 0xb7,0x5a,0xe6,0x8b,0x53,0xd2,0xfc,0x14,0x9b,0x77,0xe5,0x04,0x13,0x2d,0x37,0x56, + 0x9b,0x7e,0x76,0x6b,0xa7,0x4a,0x19,0xbd,0x61,0x62,0x34,0x3a,0x21,0xc8,0x59,0x0a, + 0xa9,0xce,0xbc,0xa9,0x01,0x4c,0x63,0x6d,0xf5), + chunk_from_chars( + 0x30,0x43,0x30,0x05,0x06,0x03,0x2b,0x65,0x71,0x03,0x3a,0x00,0x79,0x75,0x6f,0x01, + 0x4d,0xcf,0xe2,0x07,0x9f,0x5d,0xd9,0xe7,0x18,0xbe,0x41,0x71,0xe2,0xef,0x24,0x86, + 0xa0,0x8f,0x25,0x18,0x6f,0x6b,0xff,0x43,0xa9,0x93,0x6b,0x9b,0xfe,0x12,0x40,0x2b, + 0x08,0xae,0x65,0x79,0x8a,0x3d,0x81,0xe2,0x2e,0x9e,0xc8,0x0e,0x76,0x90,0x86,0x2e, + 0xf3,0xd4,0xed,0x3a,0x00), + chunk_from_chars( + 0x15,0x77,0x75,0x32,0xb0,0xbd,0xd0,0xd1,0x38,0x9f,0x63,0x6c,0x5f,0x6b,0x9b,0xa7, + 0x34,0xc9,0x0a,0xf5,0x72,0x87,0x7e,0x2d,0x27,0x2d,0xd0,0x78,0xaa,0x1e,0x56,0x7c, + 0xfa,0x80,0xe1,0x29,0x28,0xbb,0x54,0x23,0x30,0xe8,0x40,0x9f,0x31,0x74,0x50,0x41, + 0x07,0xec,0xd5,0xef,0xac,0x61,0xae,0x75,0x04,0xda,0xbe,0x2a,0x60,0x2e,0xde,0x89, + 0xe5,0xcc,0xa6,0x25,0x7a,0x7c,0x77,0xe2,0x7a,0x70,0x2b,0x3a,0xe3,0x9f,0xc7,0x69, + 0xfc,0x54,0xf2,0x39,0x5a,0xe6,0xa1,0x17,0x8c,0xab,0x47,0x38,0xe5,0x43,0x07,0x2f, + 0xc1,0xc1,0x77,0xfe,0x71,0xe9,0x2e,0x25,0xbf,0x03,0xe4,0xec,0xb7,0x2f,0x47,0xb6, + 0x4d,0x04,0x65,0xaa,0xea,0x4c,0x7f,0xad,0x37,0x25,0x36,0xc8,0xba,0x51,0x6a,0x60, + 0x39,0xc3,0xc2,0xa3,0x9f,0x0e,0x4d,0x83,0x2b,0xe4,0x32,0xdf,0xa9,0xa7,0x06,0xa6, + 0xe5,0xc7,0xe1,0x9f,0x39,0x79,0x64,0xca,0x42,0x58,0x00,0x2f,0x7c,0x05,0x41,0xb5, + 0x90,0x31,0x6d,0xbc,0x56,0x22,0xb6,0xb2,0xa6,0xfe,0x7a,0x4a,0xbf,0xfd,0x96,0x10, + 0x5e,0xca,0x76,0xea,0x7b,0x98,0x81,0x6a,0xf0,0x74,0x8c,0x10,0xdf,0x04,0x8c,0xe0, + 0x12,0xd9,0x01,0x01,0x5a,0x51,0xf1,0x89,0xf3,0x88,0x81,0x45,0xc0,0x36,0x50,0xaa, + 0x23,0xce,0x89,0x4c,0x3b,0xd8,0x89,0xe0,0x30,0xd5,0x65,0x07,0x1c,0x59,0xf4,0x09, + 0xa9,0x98,0x1b,0x51,0x87,0x8f,0xd6,0xfc,0x11,0x06,0x24,0xdc,0xbc,0xde,0x0b,0xf7, + 0xa6,0x9c,0xcc,0xe3,0x8f,0xab,0xdf,0x86,0xf3,0xbe,0xf6,0x04,0x48,0x19,0xde,0x11), + chunk_from_chars( + 0xc6,0x50,0xdd,0xbb,0x06,0x01,0xc1,0x9c,0xa1,0x14,0x39,0xe1,0x64,0x0d,0xd9,0x31, + 0xf4,0x3c,0x51,0x8e,0xa5,0xbe,0xa7,0x0d,0x3d,0xcd,0xe5,0xf4,0x19,0x1f,0xe5,0x3f, + 0x00,0xcf,0x96,0x65,0x46,0xb7,0x2b,0xcc,0x7d,0x58,0xbe,0x2b,0x9b,0xad,0xef,0x28, + 0x74,0x39,0x54,0xe3,0xa4,0x4a,0x23,0xf8,0x80,0xe8,0xd4,0xf1,0xcf,0xce,0x2d,0x7a, + 0x61,0x45,0x2d,0x26,0xda,0x05,0x89,0x6f,0x0a,0x50,0xda,0x66,0xa2,0x39,0xa8,0xa1, + 0x88,0xb6,0xd8,0x25,0xb3,0x30,0x5a,0xd7,0x7b,0x73,0xfb,0xac,0x08,0x36,0xec,0xc6, + 0x09,0x87,0xfd,0x08,0x52,0x7c,0x1a,0x8e,0x80,0xd5,0x82,0x3e,0x65,0xca,0xfe,0x2a, + 0x3d,0x00), + chunk_from_chars( + 0xfc,0x02,0xc5,0x25,0x74,0x09,0x8f,0xbb,0xaf,0x8c,0xad,0x02,0x14,0x9d,0xef,0x0d, + 0x94,0xb7,0x96,0x5f), + chunk_from_chars( + 0x63,0x03,0x8e,0x1f,0xcc,0x69,0x1e,0x2f,0x9d,0xb3,0x57,0x0f,0xad,0xbc,0x01,0x35, + 0x63,0xdb,0x06,0xba), + }, + /* 1023 octets */ + { chunk_from_chars( + 0x30,0x47,0x02,0x01,0x00,0x30,0x05,0x06,0x03,0x2b,0x65,0x71,0x04,0x3b,0x04,0x39, + 0x87,0x2d,0x09,0x37,0x80,0xf5,0xd3,0x73,0x0d,0xf7,0xc2,0x12,0x66,0x4b,0x37,0xb8, + 0xa0,0xf2,0x4f,0x56,0x81,0x0d,0xaa,0x83,0x82,0xcd,0x4f,0xa3,0xf7,0x76,0x34,0xec, + 0x44,0xdc,0x54,0xf1,0xc2,0xed,0x9b,0xea,0x86,0xfa,0xfb,0x76,0x32,0xd8,0xbe,0x19, + 0x9e,0xa1,0x65,0xf5,0xad,0x55,0xdd,0x9c,0xe8), + chunk_from_chars( + 0x30,0x43,0x30,0x05,0x06,0x03,0x2b,0x65,0x71,0x03,0x3a,0x00,0xa8,0x1b,0x2e,0x8a, + 0x70,0xa5,0xac,0x94,0xff,0xdb,0xcc,0x9b,0xad,0xfc,0x3f,0xeb,0x08,0x01,0xf2,0x58, + 0x57,0x8b,0xb1,0x14,0xad,0x44,0xec,0xe1,0xec,0x0e,0x79,0x9d,0xa0,0x8e,0xff,0xb8, + 0x1c,0x5d,0x68,0x5c,0x0c,0x56,0xf6,0x4e,0xec,0xae,0xf8,0xcd,0xf1,0x1c,0xc3,0x87, + 0x37,0x83,0x8c,0xf4,0x00), + chunk_from_chars( + 0x6d,0xdf,0x80,0x2e,0x1a,0xae,0x49,0x86,0x93,0x5f,0x7f,0x98,0x1b,0xa3,0xf0,0x35, + 0x1d,0x62,0x73,0xc0,0xa0,0xc2,0x2c,0x9c,0x0e,0x83,0x39,0x16,0x8e,0x67,0x54,0x12, + 0xa3,0xde,0xbf,0xaf,0x43,0x5e,0xd6,0x51,0x55,0x80,0x07,0xdb,0x43,0x84,0xb6,0x50, + 0xfc,0xc0,0x7e,0x3b,0x58,0x6a,0x27,0xa4,0xf7,0xa0,0x0a,0xc8,0xa6,0xfe,0xc2,0xcd, + 0x86,0xae,0x4b,0xf1,0x57,0x0c,0x41,0xe6,0xa4,0x0c,0x93,0x1d,0xb2,0x7b,0x2f,0xaa, + 0x15,0xa8,0xce,0xdd,0x52,0xcf,0xf7,0x36,0x2c,0x4e,0x6e,0x23,0xda,0xec,0x0f,0xbc, + 0x3a,0x79,0xb6,0x80,0x6e,0x31,0x6e,0xfc,0xc7,0xb6,0x81,0x19,0xbf,0x46,0xbc,0x76, + 0xa2,0x60,0x67,0xa5,0x3f,0x29,0x6d,0xaf,0xdb,0xdc,0x11,0xc7,0x7f,0x77,0x77,0xe9, + 0x72,0x66,0x0c,0xf4,0xb6,0xa9,0xb3,0x69,0xa6,0x66,0x5f,0x02,0xe0,0xcc,0x9b,0x6e, + 0xdf,0xad,0x13,0x6b,0x4f,0xab,0xe7,0x23,0xd2,0x81,0x3d,0xb3,0x13,0x6c,0xfd,0xe9, + 0xb6,0xd0,0x44,0x32,0x2f,0xee,0x29,0x47,0x95,0x2e,0x03,0x1b,0x73,0xab,0x5c,0x60, + 0x33,0x49,0xb3,0x07,0xbd,0xc2,0x7b,0xc6,0xcb,0x8b,0x8b,0xbd,0x7b,0xd3,0x23,0x21, + 0x9b,0x80,0x33,0xa5,0x81,0xb5,0x9e,0xad,0xeb,0xb0,0x9b,0x3c,0x4f,0x3d,0x22,0x77, + 0xd4,0xf0,0x34,0x36,0x24,0xac,0xc8,0x17,0x80,0x47,0x28,0xb2,0x5a,0xb7,0x97,0x17, + 0x2b,0x4c,0x5c,0x21,0xa2,0x2f,0x9c,0x78,0x39,0xd6,0x43,0x00,0x23,0x2e,0xb6,0x6e, + 0x53,0xf3,0x1c,0x72,0x3f,0xa3,0x7f,0xe3,0x87,0xc7,0xd3,0xe5,0x0b,0xdf,0x98,0x13, + 0xa3,0x0e,0x5b,0xb1,0x2c,0xf4,0xcd,0x93,0x0c,0x40,0xcf,0xb4,0xe1,0xfc,0x62,0x25, + 0x92,0xa4,0x95,0x88,0x79,0x44,0x94,0xd5,0x6d,0x24,0xea,0x4b,0x40,0xc8,0x9f,0xc0, + 0x59,0x6c,0xc9,0xeb,0xb9,0x61,0xc8,0xcb,0x10,0xad,0xde,0x97,0x6a,0x5d,0x60,0x2b, + 0x1c,0x3f,0x85,0xb9,0xb9,0xa0,0x01,0xed,0x3c,0x6a,0x4d,0x3b,0x14,0x37,0xf5,0x20, + 0x96,0xcd,0x19,0x56,0xd0,0x42,0xa5,0x97,0xd5,0x61,0xa5,0x96,0xec,0xd3,0xd1,0x73, + 0x5a,0x8d,0x57,0x0e,0xa0,0xec,0x27,0x22,0x5a,0x2c,0x4a,0xaf,0xf2,0x63,0x06,0xd1, + 0x52,0x6c,0x1a,0xf3,0xca,0x6d,0x9c,0xf5,0xa2,0xc9,0x8f,0x47,0xe1,0xc4,0x6d,0xb9, + 0xa3,0x32,0x34,0xcf,0xd4,0xd8,0x1f,0x2c,0x98,0x53,0x8a,0x09,0xeb,0xe7,0x69,0x98, + 0xd0,0xd8,0xfd,0x25,0x99,0x7c,0x7d,0x25,0x5c,0x6d,0x66,0xec,0xe6,0xfa,0x56,0xf1, + 0x11,0x44,0x95,0x0f,0x02,0x77,0x95,0xe6,0x53,0x00,0x8f,0x4b,0xd7,0xca,0x2d,0xee, + 0x85,0xd8,0xe9,0x0f,0x3d,0xc3,0x15,0x13,0x0c,0xe2,0xa0,0x03,0x75,0xa3,0x18,0xc7, + 0xc3,0xd9,0x7b,0xe2,0xc8,0xce,0x5b,0x6d,0xb4,0x1a,0x62,0x54,0xff,0x26,0x4f,0xa6, + 0x15,0x5b,0xae,0xe3,0xb0,0x77,0x3c,0x0f,0x49,0x7c,0x57,0x3f,0x19,0xbb,0x4f,0x42, + 0x40,0x28,0x1f,0x0b,0x1f,0x4f,0x7b,0xe8,0x57,0xa4,0xe5,0x9d,0x41,0x6c,0x06,0xb4, + 0xc5,0x0f,0xa0,0x9e,0x18,0x10,0xdd,0xc6,0xb1,0x46,0x7b,0xae,0xac,0x5a,0x36,0x68, + 0xd1,0x1b,0x6e,0xca,0xa9,0x01,0x44,0x00,0x16,0xf3,0x89,0xf8,0x0a,0xcc,0x4d,0xb9, + 0x77,0x02,0x5e,0x7f,0x59,0x24,0x38,0x8c,0x7e,0x34,0x0a,0x73,0x2e,0x55,0x44,0x40, + 0xe7,0x65,0x70,0xf8,0xdd,0x71,0xb7,0xd6,0x40,0xb3,0x45,0x0d,0x1f,0xd5,0xf0,0x41, + 0x0a,0x18,0xf9,0xa3,0x49,0x4f,0x70,0x7c,0x71,0x7b,0x79,0xb4,0xbf,0x75,0xc9,0x84, + 0x00,0xb0,0x96,0xb2,0x16,0x53,0xb5,0xd2,0x17,0xcf,0x35,0x65,0xc9,0x59,0x74,0x56, + 0xf7,0x07,0x03,0x49,0x7a,0x07,0x87,0x63,0x82,0x9b,0xc0,0x1b,0xb1,0xcb,0xc8,0xfa, + 0x04,0xea,0xdc,0x9a,0x6e,0x3f,0x66,0x99,0x58,0x7a,0x9e,0x75,0xc9,0x4e,0x5b,0xab, + 0x00,0x36,0xe0,0xb2,0xe7,0x11,0x39,0x2c,0xff,0x00,0x47,0xd0,0xd6,0xb0,0x5b,0xd2, + 0xa5,0x88,0xbc,0x10,0x97,0x18,0x95,0x42,0x59,0xf1,0xd8,0x66,0x78,0xa5,0x79,0xa3, + 0x12,0x0f,0x19,0xcf,0xb2,0x96,0x3f,0x17,0x7a,0xeb,0x70,0xf2,0xd4,0x84,0x48,0x26, + 0x26,0x2e,0x51,0xb8,0x02,0x71,0x27,0x20,0x68,0xef,0x5b,0x38,0x56,0xfa,0x85,0x35, + 0xaa,0x2a,0x88,0xb2,0xd4,0x1f,0x2a,0x0e,0x2f,0xda,0x76,0x24,0xc2,0x85,0x02,0x72, + 0xac,0x4a,0x2f,0x56,0x1f,0x8f,0x2f,0x7a,0x31,0x8b,0xfd,0x5c,0xaf,0x96,0x96,0x14, + 0x9e,0x4a,0xc8,0x24,0xad,0x34,0x60,0x53,0x8f,0xdc,0x25,0x42,0x1b,0xee,0xc2,0xcc, + 0x68,0x18,0x16,0x2d,0x06,0xbb,0xed,0x0c,0x40,0xa3,0x87,0x19,0x23,0x49,0xdb,0x67, + 0xa1,0x18,0xba,0xda,0x6c,0xd5,0xab,0x01,0x40,0xee,0x27,0x32,0x04,0xf6,0x28,0xaa, + 0xd1,0xc1,0x35,0xf7,0x70,0x27,0x9a,0x65,0x1e,0x24,0xd8,0xc1,0x4d,0x75,0xa6,0x05, + 0x9d,0x76,0xb9,0x6a,0x6f,0xd8,0x57,0xde,0xf5,0xe0,0xb3,0x54,0xb2,0x7a,0xb9,0x37, + 0xa5,0x81,0x5d,0x16,0xb5,0xfa,0xe4,0x07,0xff,0x18,0x22,0x2c,0x6d,0x1e,0xd2,0x63, + 0xbe,0x68,0xc9,0x5f,0x32,0xd9,0x08,0xbd,0x89,0x5c,0xd7,0x62,0x07,0xae,0x72,0x64, + 0x87,0x56,0x7f,0x9a,0x67,0xda,0xd7,0x9a,0xbe,0xc3,0x16,0xf6,0x83,0xb1,0x7f,0x2d, + 0x02,0xbf,0x07,0xe0,0xac,0x8b,0x5b,0xc6,0x16,0x2c,0xf9,0x46,0x97,0xb3,0xc2,0x7c, + 0xd1,0xfe,0xa4,0x9b,0x27,0xf2,0x3b,0xa2,0x90,0x18,0x71,0x96,0x25,0x06,0x52,0x0c, + 0x39,0x2d,0xa8,0xb6,0xad,0x0d,0x99,0xf7,0x01,0x3f,0xbc,0x06,0xc2,0xc1,0x7a,0x56, + 0x95,0x00,0xc8,0xa7,0x69,0x64,0x81,0xc1,0xcd,0x33,0xe9,0xb1,0x4e,0x40,0xb8,0x2e, + 0x79,0xa5,0xf5,0xdb,0x82,0x57,0x1b,0xa9,0x7b,0xae,0x3a,0xd3,0xe0,0x47,0x95,0x15, + 0xbb,0x0e,0x2b,0x0f,0x3b,0xfc,0xd1,0xfd,0x33,0x03,0x4e,0xfc,0x62,0x45,0xed,0xdd, + 0x7e,0xe2,0x08,0x6d,0xda,0xe2,0x60,0x0d,0x8c,0xa7,0x3e,0x21,0x4e,0x8c,0x2b,0x0b, + 0xdb,0x2b,0x04,0x7c,0x6a,0x46,0x4a,0x56,0x2e,0xd7,0x7b,0x73,0xd2,0xd8,0x41,0xc4, + 0xb3,0x49,0x73,0x55,0x12,0x57,0x71,0x3b,0x75,0x36,0x32,0xef,0xba,0x34,0x81,0x69, + 0xab,0xc9,0x0a,0x68,0xf4,0x26,0x11,0xa4,0x01,0x26,0xd7,0xcb,0x21,0xb5,0x86,0x95, + 0x56,0x81,0x86,0xf7,0xe5,0x69,0xd2,0xff,0x0f,0x9e,0x74,0x5d,0x04,0x87,0xdd,0x2e, + 0xb9,0x97,0xca,0xfc,0x5a,0xbf,0x9d,0xd1,0x02,0xe6,0x2f,0xf6,0x6c,0xba,0x87), + chunk_from_chars( + 0xe3,0x01,0x34,0x5a,0x41,0xa3,0x9a,0x4d,0x72,0xff,0xf8,0xdf,0x69,0xc9,0x80,0x75, + 0xa0,0xcc,0x08,0x2b,0x80,0x2f,0xc9,0xb2,0xb6,0xbc,0x50,0x3f,0x92,0x6b,0x65,0xbd, + 0xdf,0x7f,0x4c,0x8f,0x1c,0xb4,0x9f,0x63,0x96,0xaf,0xc8,0xa7,0x0a,0xbe,0x6d,0x8a, + 0xef,0x0d,0xb4,0x78,0xd4,0xc6,0xb2,0x97,0x00,0x76,0xc6,0xa0,0x48,0x4f,0xe7,0x6d, + 0x76,0xb3,0xa9,0x76,0x25,0xd7,0x9f,0x1c,0xe2,0x40,0xe7,0xc5,0x76,0x75,0x0d,0x29, + 0x55,0x28,0x28,0x6f,0x71,0x9b,0x41,0x3d,0xe9,0xad,0xa3,0xe8,0xeb,0x78,0xed,0x57, + 0x36,0x03,0xce,0x30,0xd8,0xbb,0x76,0x17,0x85,0xdc,0x30,0xdb,0xc3,0x20,0x86,0x9e, + 0x1a,0x00), + chunk_from_chars( + 0x89,0x30,0xb4,0x62,0xe0,0x28,0x45,0xf1,0x37,0xc0,0x0e,0x47,0xfe,0x64,0x3d,0x07, + 0x02,0x7b,0x66,0xec), + chunk_from_chars( + 0xc1,0x6c,0x19,0x0e,0x3e,0xe9,0x2c,0x5e,0xd0,0x35,0x19,0x93,0x77,0x2c,0xd6,0x38, + 0xf0,0xbc,0xe1,0x62), + }, +}; + +START_TEST(test_ed448_sign) +{ + private_key_t *key; + public_key_t *pubkey, *public; + chunk_t sig, encoding, fp; + + /* load private key */ + key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ED448, + BUILD_BLOB_ASN1_DER, sig_tests[_i].key, BUILD_END); + ck_assert(key != NULL); + ck_assert(key->get_encoding(key, PRIVKEY_ASN1_DER, &encoding)); + ck_assert_chunk_eq(encoding, sig_tests[_i].key); + chunk_free(&encoding); + + ck_assert(key->get_fingerprint(key, KEYID_PUBKEY_SHA1, &fp)); + ck_assert_chunk_eq(sig_tests[_i].fp_pk, fp); + ck_assert(key->get_fingerprint(key, KEYID_PUBKEY_INFO_SHA1, &fp)); + ck_assert_chunk_eq(sig_tests[_i].fp_spki, fp); + + /* load public key */ + pubkey = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ED448, + BUILD_BLOB_ASN1_DER, sig_tests[_i].pubkey, BUILD_END); + ck_assert(pubkey != NULL); + ck_assert(pubkey->get_encoding(pubkey, PUBKEY_SPKI_ASN1_DER, &encoding)); + ck_assert_chunk_eq(encoding, sig_tests[_i].pubkey); + chunk_free(&encoding); + + ck_assert(pubkey->get_fingerprint(pubkey, KEYID_PUBKEY_SHA1, &fp)); + ck_assert_chunk_eq(sig_tests[_i].fp_pk, fp); + ck_assert(pubkey->get_fingerprint(pubkey, KEYID_PUBKEY_INFO_SHA1, &fp)); + ck_assert_chunk_eq(sig_tests[_i].fp_spki, fp); + + /* compare public keys */ + public = key->get_public_key(key); + ck_assert(public != NULL); + ck_assert(public->equals(public, pubkey)); + + /* sign */ + ck_assert(key->sign(key, SIGN_ED448, NULL, sig_tests[_i].msg, &sig)); + ck_assert_chunk_eq(sig, sig_tests[_i].sig); + + /* verify */ + ck_assert(pubkey->verify(pubkey, SIGN_ED448, NULL, sig_tests[_i].msg, + sig_tests[_i].sig)); + + /* cleanup */ + key->destroy(key); + pubkey->destroy(pubkey); + public->destroy(public); + chunk_free(&sig); +} +END_TEST + +START_TEST(test_ed448_gen) +{ + private_key_t *key, *key2; + public_key_t *pubkey, *pubkey2; + chunk_t msg = chunk_from_str("Ed448"), sig, encoding, fp_priv, fp_pub; + + /* generate private key */ + key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ED448, + BUILD_KEY_SIZE, 456, BUILD_END); + ck_assert(key != NULL); + ck_assert(key->get_type(key) == KEY_ED448); + ck_assert(key->get_keysize(key) == 456); + ck_assert(!key->get_encoding(key, PRIVKEY_PGP, &encoding)); + ck_assert(key->get_encoding(key, PRIVKEY_PEM, &encoding)); + ck_assert(encoding.ptr != NULL); + ck_assert(strstr(encoding.ptr, "PRIVATE KEY")); + chunk_free(&encoding); + + /* clone private key */ + key2 = key->get_ref(key); + ck_assert(key2); + key2->destroy(key2); + + /* decryption not supported */ + ck_assert(!key->decrypt(key, ENCRYPT_UNKNOWN, msg, NULL)); + + /* wrong signature scheme */ + ck_assert(!key->sign(key, SIGN_ED25519, NULL, msg, &sig)); + + /* correct signature scheme*/ + ck_assert(key->sign(key, SIGN_ED448, NULL, msg, &sig)); + + /* export public key */ + pubkey = key->get_public_key(key); + ck_assert(pubkey != NULL); + ck_assert(pubkey->get_type(pubkey) == KEY_ED448); + ck_assert(pubkey->get_keysize(pubkey) == 456); + ck_assert(pubkey->get_encoding(pubkey, PUBKEY_PEM, &encoding)); + ck_assert(encoding.ptr != NULL); + ck_assert(strstr(encoding.ptr, "PUBLIC KEY")); + chunk_free(&encoding); + + /* generate and compare public and private key fingerprints */ + ck_assert(!key->get_fingerprint(key, KEYID_PGPV4, &fp_priv)); + ck_assert(key->get_fingerprint(key, KEYID_PUBKEY_SHA1, &fp_priv)); + ck_assert(key->get_fingerprint(key, KEYID_PUBKEY_SHA1, &fp_priv)); + ck_assert(fp_priv.ptr != NULL); + ck_assert(!pubkey->get_fingerprint(pubkey, KEYID_PGPV4, &fp_pub)); + ck_assert(pubkey->get_fingerprint(pubkey, KEYID_PUBKEY_SHA1, &fp_pub)); + ck_assert(pubkey->get_fingerprint(pubkey, KEYID_PUBKEY_SHA1, &fp_pub)); + ck_assert(fp_pub.ptr != NULL); + ck_assert_chunk_eq(fp_pub, fp_priv); + + /* clone public key */ + pubkey2 = pubkey->get_ref(pubkey); + ck_assert(pubkey2 != NULL); + pubkey2->destroy(pubkey2); + + /* encryption not supported */ + ck_assert(!pubkey->encrypt(pubkey, ENCRYPT_UNKNOWN, msg, NULL)); + + /* verify with wrong signature scheme */ + ck_assert(!pubkey->verify(pubkey, SIGN_ED25519, NULL, msg, sig)); + + /* verify with correct signature scheme */ + ck_assert(pubkey->verify(pubkey, SIGN_ED448, NULL, msg, sig)); + + /* cleanup */ + key->destroy(key); + pubkey->destroy(pubkey); + chunk_free(&sig); +} +END_TEST + +START_TEST(test_ed448_speed) +{ + private_key_t *key; + public_key_t *pubkey; + chunk_t msg = chunk_from_str("Hello Ed448"), sig; + int i, count = 500; + +#ifdef HAVE_CLOCK_GETTIME + struct timespec start, stop; + clock_gettime(CLOCK_THREAD_CPUTIME_ID, &start); +#endif + + for (i = 0; i < count; i++) + { + key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ED448, + BUILD_KEY_SIZE, 456, BUILD_END); + ck_assert(key != NULL); + ck_assert(key->sign(key, SIGN_ED448, NULL, msg, &sig)); + pubkey = key->get_public_key(key); + ck_assert(pubkey != NULL); + ck_assert(pubkey->verify(pubkey, SIGN_ED448, NULL, msg, sig)); + key->destroy(key); + pubkey->destroy(pubkey); + chunk_free(&sig); + } + +#ifdef HAVE_CLOCK_GETTIME + clock_gettime(CLOCK_THREAD_CPUTIME_ID, &stop); + DBG0(DBG_LIB, "%d Ed448 keys and signatures in %d ms\n", count, + (stop.tv_nsec - start.tv_nsec) / 1000000 + + (stop.tv_sec - start.tv_sec) * 1000); +#endif +} +END_TEST + +static chunk_t zero_pk = chunk_from_chars( + 0x30,0x43,0x30,0x05,0x06,0x03,0x2b,0x65,0x71,0x03,0x3a,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00); + +/* sig_tests[0].sig with s+L, note that only the 9 most significant bits are 0 */ +static chunk_t malleable_sig = chunk_from_chars( + 0x53,0x3a,0x37,0xf6,0xbb,0xe4,0x57,0x25,0x1f,0x02,0x3c,0x0d,0x88,0xf9,0x76,0xae, + 0x2d,0xfb,0x50,0x4a,0x84,0x3e,0x34,0xd2,0x07,0x4f,0xd8,0x23,0xd4,0x1a,0x59,0x1f, + 0x2b,0x23,0x3f,0x03,0x4f,0x62,0x82,0x81,0xf2,0xfd,0x7a,0x22,0xdd,0xd4,0x7d,0x78, + 0x28,0xc5,0x9b,0xd0,0xa2,0x1b,0xfd,0x39,0x80,0xf2,0x52,0x78,0xd3,0x66,0x74,0x03, + 0xc1,0x4b,0xce,0xc5,0xf9,0xcf,0xde,0x99,0x55,0xeb,0xc8,0x33,0x3c,0x0a,0xe7,0x8f, + 0xc8,0x6e,0x51,0x83,0x17,0xc5,0xc7,0xcd,0xda,0x85,0x30,0xa1,0x13,0xa0,0xf4,0xdb, + 0xb6,0x11,0x49,0xf0,0x5a,0x73,0x63,0x26,0x8c,0x71,0xd9,0x58,0x08,0xff,0x2e,0x65, + 0x66,0x00); + +START_TEST(test_ed448_fail) +{ + private_key_t *key; + public_key_t *pubkey; + chunk_t blob, sig; + uint8_t sig1[114]; + + /* Invalid private key format */ + key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ED448, + BUILD_BLOB_ASN1_DER, chunk_empty, BUILD_END); + ck_assert(key == NULL); + + key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ED448, + BUILD_EDDSA_PRIV_ASN1_DER, chunk_empty, BUILD_END); + ck_assert(key == NULL); + + blob = chunk_from_chars(0x04, 0x01, 0x9d); + key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ED448, + BUILD_EDDSA_PRIV_ASN1_DER, blob, BUILD_END); + ck_assert(key == NULL); + + /* Invalid public key format */ + pubkey = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ED448, + BUILD_BLOB_ASN1_DER, chunk_empty, BUILD_END); + ck_assert(pubkey == NULL); + + blob = chunk_from_chars(0x30, 0x0b, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, + 0x71, 0x03, 0x02, 0x00, 0xd7); + pubkey = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ED448, + BUILD_BLOB_ASN1_DER, blob, BUILD_END); + ck_assert(pubkey == NULL); + + blob = chunk_from_chars(0x30, 0x0b, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x00, + 0x71, 0x03, 0x02, 0x00, 0xd7); + pubkey = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ED448, + BUILD_BLOB_ASN1_DER, blob, BUILD_END); + ck_assert(pubkey == NULL); + + pubkey = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ED448, + BUILD_KEY_SIZE, 456, BUILD_BLOB_ASN1_DER, blob, BUILD_END); + ck_assert(pubkey == NULL); + + /* Invalid signature format */ + pubkey = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ED448, + BUILD_BLOB_ASN1_DER, sig_tests[0].pubkey, BUILD_END); + ck_assert(pubkey != NULL); + + ck_assert(!pubkey->verify(pubkey, SIGN_ED448, NULL, chunk_empty, + chunk_empty)); + + /* RFC 8032, section 5.2.7 requires that 0 <= s < L to prevent signature + * malleability. Only a warning because OpenSSL is vulnerable to this. */ + if (pubkey->verify(pubkey, SIGN_ED448, NULL, sig_tests[0].msg, + malleable_sig)) + { + warn("Ed448 signature verification is vulnerable to malleable " + "signatures"); + } + + /* malformed signature */ + sig = chunk_from_thing(sig1); + memcpy(sig1, sig_tests[0].sig.ptr, sig_tests[0].sig.len); + sig1[113] |= 0xFF; + ck_assert(!pubkey->verify(pubkey, SIGN_ED448, NULL, sig_tests[0].msg, + sig)); + + /* wrong signature */ + memcpy(sig1, sig_tests[0].sig.ptr, sig_tests[0].sig.len); + sig1[0] = 0xe4; + ck_assert(!pubkey->verify(pubkey, SIGN_ED448, NULL, sig_tests[0].msg, + sig)); + + /* detect all-zeroes public key */ + pubkey->destroy(pubkey); + pubkey = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ED448, + BUILD_BLOB_ASN1_DER, zero_pk, BUILD_END); + ck_assert(pubkey != NULL); + ck_assert(!pubkey->verify(pubkey, SIGN_ED448, NULL, sig_tests[0].msg, + sig)); + pubkey->destroy(pubkey); +} +END_TEST + +Suite *ed448_suite_create() +{ + Suite *s; + TCase *tc; + + s = suite_create("ed448"); + + tc = tcase_create("ed448_sign"); + tcase_add_loop_test(tc, test_ed448_sign, 0, countof(sig_tests)); + suite_add_tcase(s, tc); + + tc = tcase_create("ed448_gen"); + tcase_add_test(tc, test_ed448_gen); + suite_add_tcase(s, tc); + + tc = tcase_create("ed448_fail"); + tcase_add_test(tc, test_ed448_fail); + suite_add_tcase(s, tc); + + tc = tcase_create("ed448_speed"); + test_case_set_timeout(tc, 10); + tcase_add_test(tc, test_ed448_speed); + suite_add_tcase(s, tc); + + return s; +} diff --git a/src/libstrongswan/tests/tests.h b/src/libstrongswan/tests/tests.h index 9fc38d480..26ff161a4 100644 --- a/src/libstrongswan/tests/tests.h +++ b/src/libstrongswan/tests/tests.h @@ -52,5 +52,6 @@ TEST_SUITE_DEPEND(mgf1_sha256_suite_create, XOF, XOF_MGF1_SHA256) TEST_SUITE_DEPEND(ntru_suite_create, DH, NTRU_112_BIT) TEST_SUITE_DEPEND(fetch_http_suite_create, FETCHER, "http://") TEST_SUITE_DEPEND(ed25519_suite_create, PRIVKEY_GEN, KEY_ED25519) +TEST_SUITE_DEPEND(ed448_suite_create, PRIVKEY_GEN, KEY_ED448) TEST_SUITE(signature_params_suite_create) diff --git a/src/libstrongswan/utils/leak_detective.c b/src/libstrongswan/utils/leak_detective.c index 07f33c83d..63b7453f3 100644 --- a/src/libstrongswan/utils/leak_detective.c +++ b/src/libstrongswan/utils/leak_detective.c @@ -587,6 +587,11 @@ static char *whitelist[] = { "OPENSSL_load_builtin_modules", "CONF_modules_load_file", "CONF_module_add", + "RAND_DRBG_bytes", + "RAND_DRBG_generate", + "RAND_DRBG_get0_master", + "RAND_DRBG_get0_private", + "RAND_DRBG_get0_public", /* OpenSSL libssl */ "SSL_COMP_get_compression_methods", /* NSPR */