From ddb94d4e27cbf4b09e81fedecf58826c304e303f Mon Sep 17 00:00:00 2001 From: Andy Green Date: Tue, 4 Dec 2018 08:03:58 +0800 Subject: [PATCH] genaes: generic AES layer independent of tls library Although RSA can be used directly for signing / JWS on large chunks of data since it's only operating on the hash, when JWE support arrives, which allows bulk encryption, it's going to be mandatory to support secondary AES ciphers to use on the bulk data. This adds generic support for all AES modes that OpenSSL and mbedTLS have in common, works on both mbedTLS and OpenSSL the same, and adds unit tests for each mode in api-test-gencrypto, to run in CI. --- .travis.yml | 2 +- CMakeLists.txt | 11 + README.md | 6 + READMEs/README.crypto-apis.md | 34 + ...shd-base.md => README.plugin-sshd-base.md} | 0 cmake/lws_config.h.in | 3 + include/libwebsockets.h | 1 + include/libwebsockets/lws-genaes.h | 161 ++++ include/libwebsockets/lws-jwk.h | 8 +- include/libwebsockets/lws-misc.h | 3 + lib/core/libwebsockets.c | 9 + lib/jose/jwk/jwk.c | 2 +- lib/tls/mbedtls/lws-genaes.c | 242 ++++++ lib/tls/mbedtls/lws-genrsa.c | 9 +- lib/tls/openssl/lws-genaes.c | 313 +++++++ lib/tls/openssl/lws-genrsa.c | 9 +- lib/tls/private.h | 5 + .../api-test-gencrypto/CMakeLists.txt | 78 ++ .../api-tests/api-test-gencrypto/README.md | 26 + .../api-tests/api-test-gencrypto/lws-genaes.c | 788 ++++++++++++++++++ .../api-tests/api-test-gencrypto/main.c | 45 + .../api-tests/api-test-gencrypto/selftest.sh | 24 + .../api-tests/api-test-jose/CMakeLists.txt | 6 + plugins/ssh-base/crypto/chacha.c | 6 +- plugins/ssh-base/include/lws-ssh.h | 3 - plugins/ssh-base/kex-25519.c | 2 +- plugins/ssh-base/sshd.c | 16 +- 27 files changed, 1783 insertions(+), 29 deletions(-) rename READMEs/{README-plugin-sshd-base.md => README.plugin-sshd-base.md} (100%) create mode 100644 include/libwebsockets/lws-genaes.h create mode 100644 lib/tls/mbedtls/lws-genaes.c create mode 100644 lib/tls/openssl/lws-genaes.c create mode 100644 minimal-examples/api-tests/api-test-gencrypto/CMakeLists.txt create mode 100644 minimal-examples/api-tests/api-test-gencrypto/README.md create mode 100644 minimal-examples/api-tests/api-test-gencrypto/lws-genaes.c create mode 100644 minimal-examples/api-tests/api-test-gencrypto/main.c create mode 100755 minimal-examples/api-tests/api-test-gencrypto/selftest.sh diff --git a/.travis.yml b/.travis.yml index c2186067f..ed642a5cb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ env: global: - secure: "KhAdQ9ja+LBObWNQTYO7Df5J4DyOih6S+eerDMu8UPSO+CoWV2pWoQzbOfocjyOscGOwC+2PrrHDNZyGfqkCLDXg1BxynXPCFerHC1yc2IajvKpGXmAAygNIvp4KACDfGv/dkXrViqIzr/CdcNaU4vIMHSVb5xkeLi0W1dPnQOI=" matrix: - - LWS_METHOD=lwsws CMAKE_ARGS="-DLWS_WITH_LWSWS=ON -DLWS_WITHOUT_EXTENSIONS=0 -DLWS_WITH_HTTP2=1 -DLWS_WITH_ACME=1 -DLWS_WITH_MINIMAL_EXAMPLES=1 -DCMAKE_BUILD_TYPE=DEBUG -DLWS_ROLE_DBUS=1 -DLWS_DBUS_INCLUDE2=/usr/lib/x86_64-linux-gnu/dbus-1.0/include/" + - LWS_METHOD=lwsws CMAKE_ARGS="-DLWS_WITH_LWSWS=ON -DLWS_WITHOUT_EXTENSIONS=0 -DLWS_WITH_HTTP2=1 -DLWS_WITH_ACME=1 -DLWS_WITH_MINIMAL_EXAMPLES=1 -DCMAKE_BUILD_TYPE=DEBUG -DLWS_ROLE_DBUS=1 -DLWS_DBUS_INCLUDE2=/usr/lib/x86_64-linux-gnu/dbus-1.0/include/ -DLWS_WITH_JWS=1 -DLWS_WITH_GENRSA=1 -DLWS_WITH_GENHASH=1 -DLWS_WITH_GENAES=1" - LWS_METHOD=lwsws2 CMAKE_ARGS="-DLWS_WITH_LWSWS=ON -DLWS_WITHOUT_EXTENSIONS=0 -DLWS_WITH_HTTP2=1 -DLWS_WITH_ACME=1 -DLWS_WITH_MINIMAL_EXAMPLES=1 -DCMAKE_BUILD_TYPE=DEBUG -DLWS_ROLE_DBUS=1 -DLWS_DBUS_INCLUDE2=/usr/lib/x86_64-linux-gnu/dbus-1.0/include/" - LWS_METHOD=default CMAKE_ARGS="-DLWS_WITH_MINIMAL_EXAMPLES=1" - LWS_METHOD=mbedtls CMAKE_ARGS="-DLWS_WITH_MBEDTLS=1 -DLWS_WITH_HTTP2=1 -DLWS_WITH_LWSWS=1 -DLWS_WITH_MINIMAL_EXAMPLES=1 -DCMAKE_BUILD_TYPE=DEBUG" diff --git a/CMakeLists.txt b/CMakeLists.txt index 7de8765df..2c932866b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -109,6 +109,7 @@ option(LWS_WITH_JWS "JSON Web Signature (RFC7515) API" OFF) option(LWS_WITH_JWE "JSON Web Encryption (RFC7516) API" OFF) option(LWS_WITH_GENHASH "Enable support for Generic Hash (SHA1 + SHA2 with api independent of TLS backend)" OFF) option(LWS_WITH_GENRSA "Enable support for Generic RSA (RSA with api independent of TLS backend)" OFF) +option(LWS_WITH_GENAES "Enable support for Generic AES (AES with api independent of TLS backend)" OFF) option(LWS_WITH_GENEC "Enable support for Generic EC (EC with api independent of TLS backend)" OFF) option(LWS_WITH_SELFTESTS "Selftests run at context creation" OFF) option(LWS_WITH_GCOV "Build with gcc gcov coverage instrumentation" OFF) @@ -1031,6 +1032,11 @@ if (LWS_WITH_SSL) lib/tls/mbedtls/lws-genrsa.c ) endif() + if (LWS_WITH_GENAES) + list(APPEND SOURCES + lib/tls/mbedtls/lws-genaes.c + ) + endif() if (LWS_WITH_GENEC) list(APPEND SOURCES lib/tls/mbedtls/lws-genec.c @@ -1050,6 +1056,11 @@ if (LWS_WITH_SSL) lib/tls/openssl/lws-genrsa.c ) endif() + if (LWS_WITH_GENAES) + list(APPEND SOURCES + lib/tls/openssl/lws-genaes.c + ) + endif() if (LWS_WITH_GENEC) list(APPEND SOURCES lib/tls/openssl/lws-genec.c diff --git a/README.md b/README.md index 2ae78a8d7..d1c64b76c 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,12 @@ News ## New features on master + - **lws-genaes Generic AES crypto** - thin api layer works identically with both mbedtls and openssl + backends. Supports CBC, CFB128, CFB8, CTR, ECB, OFB, XTS and GCM variants. Unit tests in CI. + [genaes api](https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/lws-genaes.h), + [api test](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/api-tests/api-test-gencrypto), + CMake config: `-DLWS_WITH_GENAES=1` + - **http fallback support** - you can specify a role and protocol to apply if non-http or non-tls packets arrive at an http(s) listen port. For example, you can specify that the new `raw proxy` role + protocol should be used, to proxy your sshd port over :443 or :80. Without affecting diff --git a/READMEs/README.crypto-apis.md b/READMEs/README.crypto-apis.md index 193c801f6..e82a6980a 100644 --- a/READMEs/README.crypto-apis.md +++ b/READMEs/README.crypto-apis.md @@ -23,9 +23,27 @@ All the necessary includes are part of `libwebsockets.h`. |---|---|---|---| |genhash|`LWS_WITH_GENHASH`|[./include/libwebsockets/lws-genhash.h](https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/lws-genhash.h)|Provides SHA1 + SHA2 hashes and hmac| |genrsa|`LWS_WITH_GENRSA`|[./include/libwebsockets/lws-genrsa.h](https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/lws-genrsa.h)|Provides RSA encryption, decryption, signing, verification, key generation and creation| +|genaes|`LWS_WITH_GENAES`|[./include/libwebsockets/lws-genaes.h](https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/lws-genaes.h)|Provides AES in all common variants for encryption and decryption| Unit tests for these apis, which serve as usage examples, can be found in [./minimal-examples/api-tests/api-test-gencrypto](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/api-tests/api-test-gencrypto) +### Keys in the generic layer + +The necessary types and defines are brought in by `libwebsockets.h`. + +Keys are represented only by an array of `struct lws_jwk_elements`... the +length of the array is defined by the cipher... it's one of + +|key elements count|definition| +|---|---| +|`LWS_COUNT_OCT_KEY_ELEMENTS`|1| +|`LWS_COUNT_RSA_KEY_ELEMENTS`|8| +|`LWS_COUNT_EC_KEY_ELEMENTS`|4| +|`LWS_COUNT_AES_KEY_ELEMENTS`|1| + +`struct lws_jwk_elements` is a simple pointer / length combination used to +store arbitrary octets that make up the key element's binary representation. + ## Using the JOSE layer All the necessary includes are part of `libwebsockets.h`. @@ -38,3 +56,19 @@ All the necessary includes are part of `libwebsockets.h`. Unit tests for these apis, which serve as usage examples, can be found in [./minimal-examples/api-tests/api-test-jose](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/api-tests/api-test-jose) +### Keys in the JOSE layer + +Keys in the JOSE layer use a `struct lws_jwk`, this contains two arrays of +`struct lws_jwk_elements` sized for the worst case (currently RSA). One +array contains the key elements as described for the generic case, and the +other contains various key metadata taken from JWK JSON. + +|metadata index|function| +|---|---| +|`JWK_META_KTY`|Key type, eg, "EC"| +|`JWK_META_KID`|Arbitrary ID string| +|`JWK_META_USE`|What the public key may be used to validate, "enc" or "sig"| +|`JWK_META_KEY_OPS`|Which operations the key is authorized for, eg, "encrypt"| +|`JWK_META_X5C`|Optional X.509 cert version of the key| +|`JWK_META_ALG`|Optional overall crypto algorithm the key is intended for use with| + diff --git a/READMEs/README-plugin-sshd-base.md b/READMEs/README.plugin-sshd-base.md similarity index 100% rename from READMEs/README-plugin-sshd-base.md rename to READMEs/README.plugin-sshd-base.md diff --git a/cmake/lws_config.h.in b/cmake/lws_config.h.in index ee2f4f800..a0ae900dd 100644 --- a/cmake/lws_config.h.in +++ b/cmake/lws_config.h.in @@ -70,6 +70,9 @@ #cmakedefine LWS_WITH_CGI #cmakedefine LWS_WITH_ESP32 #cmakedefine LWS_WITH_FTS +#cmakedefine LWS_WITH_GENRSA +#cmakedefine LWS_WITH_GENHASH +#cmakedefine LWS_WITH_GENAES #cmakedefine LWS_WITH_HTTP2 #cmakedefine LWS_WITH_HTTP_BROTLI #cmakedefine LWS_WITH_HTTP_PROXY diff --git a/include/libwebsockets.h b/include/libwebsockets.h index 831904f3a..0052bcbd9 100644 --- a/include/libwebsockets.h +++ b/include/libwebsockets.h @@ -426,6 +426,7 @@ struct lws; #include #include #include +#include #include #endif diff --git a/include/libwebsockets/lws-genaes.h b/include/libwebsockets/lws-genaes.h new file mode 100644 index 000000000..5ea734eb7 --- /dev/null +++ b/include/libwebsockets/lws-genaes.h @@ -0,0 +1,161 @@ +/* + * libwebsockets - small server side websockets and web server implementation + * + * Copyright (C) 2010 - 2018 Andy Green + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * included from libwebsockets.h + */ + +/*! \defgroup generic AES + * ## Generic AES related functions + * + * Lws provides generic AES functions that abstract the ones + * provided by whatever tls library you are linking against. + * + * It lets you use the same code if you build against mbedtls or OpenSSL + * for example. + */ +///@{ + +#if defined(LWS_WITH_MBEDTLS) +#include +#include +#endif + +enum enum_aes_modes { + LWS_GAESM_CBC, + LWS_GAESM_CFB128, + LWS_GAESM_CFB8, + LWS_GAESM_CTR, + LWS_GAESM_ECB, + LWS_GAESM_OFB, + LWS_GAESM_XTS, /* care... requires double-length key */ + LWS_GAESM_GCM, +}; + +enum enum_aes_operation { + LWS_GAESO_ENC, + LWS_GAESO_DEC +}; + +/* include/libwebsockets/lws-jwk.h must be included before this */ + +#define LWS_AES_BLOCKSIZE 128 + +struct lws_genaes_ctx { +#if defined(LWS_WITH_MBEDTLS) + union { + mbedtls_aes_context ctx; +#if defined(MBEDTLS_CIPHER_MODE_XTS) + mbedtls_aes_xts_context ctx_xts; +#endif + mbedtls_gcm_context ctx_gcm; + } u; +#else + EVP_CIPHER_CTX *ctx; + const EVP_CIPHER *cipher; + ENGINE *engine; + char init; +#endif + unsigned char tag[16]; + struct lws_jwk_elements *k; + enum enum_aes_operation op; + enum enum_aes_modes mode; + int taglen; + char underway; +}; + +/** lws_genaes_create() - Create RSA public decrypt context + * + * \param ctx: your struct lws_genaes_ctx + * \param op: LWS_GAESO_ENC or LWS_GAESO_DEC + * \param mode: one of LWS_GAESM_ + * \param el: struct prepared with key element data + * \param padding: 0 = no padding, 1 = padding + * \param engine: if openssl engine used, pass the pointer here + * + * Creates an RSA context with a public key associated with it, formed from + * the key elements in \p el. + * + * Returns 0 for OK or nonzero for error. + * + * This and related APIs operate identically with OpenSSL or mbedTLS backends. + */ +LWS_VISIBLE LWS_EXTERN int +lws_genaes_create(struct lws_genaes_ctx *ctx, enum enum_aes_operation op, + enum enum_aes_modes mode, struct lws_jwk_elements *el, + int padding, void *engine); + +/** lws_genaes_destroy() - Destroy genaes AES context + * + * \param ctx: your struct lws_genaes_ctx + * \param tag: NULL, or, GCM-only: buffer to receive tag + * \param tlen: 0, or, GCM-only: length of tag buffer + * + * Destroys any allocations related to \p ctx. + * + * For GCM only, up to tlen bytes of tag buffer will be set on exit. + * + * This and related APIs operate identically with OpenSSL or mbedTLS backends. + */ +LWS_VISIBLE LWS_EXTERN int +lws_genaes_destroy(struct lws_genaes_ctx *ctx, unsigned char *tag, size_t tlen); + +/** lws_genaes_crypt() - Encrypt or decrypt + * + * \param ctx: your struct lws_genaes_ctx + * \param op: LWS_GAESO_ENC or LWS_GAESO_DEC + * \param iv_or_nonce_ctr_or_data_unit_16: NULL, iv, nonce_ctr16, or data_unit16 + * \param stream_block_16: pointer to 16-byte stream block for CTR mode only + * \param nc_or_iv_off: NULL or pointer to nc, or iv_off + * \param in: input plaintext or ciphertext + * \param len: length of input (which is always length of output) + * \param out: output plaintext or ciphertext + * + * Encrypts or decrypts using the AES mode set when the ctx was created. + * The last three arguments have different meanings depending on the mode: + * + * CBC CFB128 CFB8 CTR ECB OFB XTS + * iv_or_nonce_ctr_or_data_unit_16 : iv iv iv nonce NULL iv dataunt + * stream_block_16 : NULL NULL NULL stream NULL NULL NULL + * nc_or_iv_off : NULL iv_off NULL nc_off NULL iv_off NULL + * + * For GCM: + * + * iv_or_nonce_ctr_or_data_unit_16 : iv + * stream_block_16 : pointer to tag + * nc_or_iv_off : set pointed-to size_t to iv length + * in : first call: additional data, subsequently + * : input data + * len : first call: add data length, subsequently + * : input / output length + * + * The length of the optional arg is always 16 if used, regardless of the mode. + * + * Returns 0 for OK or nonzero for error. + * + * This and related APIs operate identically with OpenSSL or mbedTLS backends. + */ +LWS_VISIBLE LWS_EXTERN int +lws_genaes_crypt(struct lws_genaes_ctx *ctx, const uint8_t *in, size_t len, + uint8_t *out, + uint8_t *iv_or_nonce_ctr_or_data_unit_16, + uint8_t *stream_block_16, + size_t *nc_or_iv_off, int taglen); + +///@} diff --git a/include/libwebsockets/lws-jwk.h b/include/libwebsockets/lws-jwk.h index d4c846844..5dd0e777b 100644 --- a/include/libwebsockets/lws-jwk.h +++ b/include/libwebsockets/lws-jwk.h @@ -71,12 +71,18 @@ enum enum_jwk_rsa_tok { enum enum_jwk_ec_tok { JWK_EC_KEYEL_CRV, JWK_EC_KEYEL_X, - JWK_EC_KEYEL_D, /* note... same offset as RSA D */ + JWK_EC_KEYEL_D = JWK_RSA_KEYEL_D, /* note... same offset as RSA D */ JWK_EC_KEYEL_Y, LWS_COUNT_EC_KEY_ELEMENTS }; +enum enum_jwk_aes_tok { + JWK_EC_KEYEL_K = JWK_OCT_KEYEL_K, + + LWS_COUNT_AES_KEY_ELEMENTS +}; + enum enum_jwk_meta_tok { JWK_META_KTY, JWK_META_KID, diff --git a/include/libwebsockets/lws-misc.h b/include/libwebsockets/lws-misc.h index d84415c28..6bb446193 100644 --- a/include/libwebsockets/lws-misc.h +++ b/include/libwebsockets/lws-misc.h @@ -715,6 +715,9 @@ LWS_VISIBLE LWS_EXTERN SSL* lws_get_ssl(struct lws *wsi); #endif +LWS_VISIBLE LWS_EXTERN void +lws_explicit_bzero(void *p, size_t len); + /** \defgroup smtp SMTP related functions * ##SMTP related functions * \ingroup lwsapi diff --git a/lib/core/libwebsockets.c b/lib/core/libwebsockets.c index 35218a385..91dc77a43 100644 --- a/lib/core/libwebsockets.c +++ b/lib/core/libwebsockets.c @@ -1437,6 +1437,15 @@ lws_get_network_wsi(struct lws *wsi) return wsi; } +LWS_VISIBLE void +lws_explicit_bzero(void *p, size_t len) +{ + volatile uint8_t *vp = p; + + while (len--) + *vp++ = 0; +} + LWS_VISIBLE int LWS_WARN_UNUSED_RESULT lws_raw_transaction_completed(struct lws *wsi) diff --git a/lib/jose/jwk/jwk.c b/lib/jose/jwk/jwk.c index a216697f7..ee051366c 100644 --- a/lib/jose/jwk/jwk.c +++ b/lib/jose/jwk/jwk.c @@ -43,7 +43,7 @@ static const char * const jwk_tok[] = { "keys[]", /* dummy */ "e", "n", "d", "p", "q", "dp", "dq", "qi", /* RSA */ "kty", /* generic */ - "k", /* symmetric oct key data */ + "k", /* symmetric key data */ "crv", "x", "y", /* EC (also "D") */ "kid", /* generic */ "use" /* mutually exclusive with "key_ops" */, diff --git a/lib/tls/mbedtls/lws-genaes.c b/lib/tls/mbedtls/lws-genaes.c new file mode 100644 index 000000000..392e685b4 --- /dev/null +++ b/lib/tls/mbedtls/lws-genaes.c @@ -0,0 +1,242 @@ +/* + * libwebsockets - generic AES api hiding the backend + * + * Copyright (C) 2017 - 2018 Andy Green + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * lws_genaes provides an abstraction api for AES in lws that works the + * same whether you are using openssl or mbedtls hash functions underneath. + */ +#include "core/private.h" +#include "../../jose/private.h" + +static int operation_map[] = { MBEDTLS_AES_ENCRYPT, MBEDTLS_AES_DECRYPT }; + +LWS_VISIBLE int +lws_genaes_create(struct lws_genaes_ctx *ctx, enum enum_aes_operation op, + enum enum_aes_modes mode, struct lws_jwk_elements *el, + int padding, void *engine) +{ + int n; + + ctx->mode = mode; + ctx->k = el; + ctx->op = operation_map[op]; + ctx->underway = 0; + + switch (ctx->mode) { + case LWS_GAESM_XTS: + mbedtls_aes_xts_init(&ctx->u.ctx_xts); + break; + case LWS_GAESM_GCM: + mbedtls_gcm_init(&ctx->u.ctx_gcm); + n = mbedtls_gcm_setkey(&ctx->u.ctx_gcm, MBEDTLS_CIPHER_ID_AES, + ctx->k->buf, ctx->k->len * 8); + if (n) { + lwsl_notice("%s: mbedtls_gcm_setkey: -0x%x\n", + __func__, -n); + return n; + } + return n; + default: + mbedtls_aes_init(&ctx->u.ctx); + break; + } + + switch (op) { + case LWS_GAESO_ENC: + if (ctx->mode == LWS_GAESM_XTS) +#if defined(MBEDTLS_CIPHER_MODE_XTS) + n = mbedtls_aes_xts_setkey_enc(&ctx->u.ctx_xts, + ctx->k->buf, + ctx->k->len * 8); +#else + return -1; +#endif + else + n = mbedtls_aes_setkey_enc(&ctx->u.ctx, ctx->k->buf, + ctx->k->len * 8); + break; + case LWS_GAESO_DEC: + switch (ctx->mode) { + case LWS_GAESM_XTS: +#if defined(MBEDTLS_CIPHER_MODE_XTS) + n = mbedtls_aes_xts_setkey_dec(&ctx->u.ctx_xts, + ctx->k->buf, + ctx->k->len * 8); + break; +#else + return -1; +#endif + + case LWS_GAESM_CFB128: + case LWS_GAESM_CFB8: + case LWS_GAESM_CTR: + case LWS_GAESM_OFB: + n = mbedtls_aes_setkey_enc(&ctx->u.ctx, ctx->k->buf, + ctx->k->len * 8); + break; + default: + n = mbedtls_aes_setkey_dec(&ctx->u.ctx, ctx->k->buf, + ctx->k->len * 8); + break; + } + break; + } + + if (n) + lwsl_notice("%s: setting key: -0x%x\n", __func__, -n); + + return n; +} + +LWS_VISIBLE int +lws_genaes_destroy(struct lws_genaes_ctx *ctx, unsigned char *tag, size_t tlen) +{ + int n; + + if (ctx->mode == LWS_GAESM_GCM) { + if (tag) { + n = mbedtls_gcm_finish(&ctx->u.ctx_gcm, tag, tlen); + if (n) + lwsl_notice("%s: mbedtls_gcm_finish: -0x%x\n", + __func__, -n); + else + if (memcmp(ctx->tag, tag, ctx->taglen)) { + lwsl_err("%s: lws_genaes_crypt tag " + "mismatch (bad first)\n", + __func__); + lwsl_hexdump_notice(tag, tlen); + lwsl_hexdump_notice(ctx->tag, ctx->taglen); + n = -1; + } + } + mbedtls_gcm_free(&ctx->u.ctx_gcm); + return n; + } + if (ctx->mode == LWS_GAESM_XTS) +#if defined(MBEDTLS_CIPHER_MODE_XTS) + mbedtls_aes_xts_free(&ctx->u.ctx_xts); +#else + return -1; +#endif + else + mbedtls_aes_free(&ctx->u.ctx); + + return 0; +} + +LWS_VISIBLE int +lws_genaes_crypt(struct lws_genaes_ctx *ctx, const uint8_t *in, size_t len, + uint8_t *out, uint8_t *iv_or_nonce_ctr_or_data_unit_16, + uint8_t *stream_block_16, size_t *nc_or_iv_off, int taglen) +{ + uint8_t iv[16], sb[16]; + int n; + + switch (ctx->mode) { + case LWS_GAESM_CBC: + memcpy(iv, iv_or_nonce_ctr_or_data_unit_16, 16); + n = mbedtls_aes_crypt_cbc(&ctx->u.ctx, ctx->op, len, iv, + in, out); + break; + + case LWS_GAESM_CFB128: + memcpy(iv, iv_or_nonce_ctr_or_data_unit_16, 16); + n = mbedtls_aes_crypt_cfb128(&ctx->u.ctx, ctx->op, len, + nc_or_iv_off, iv, in, out); + break; + + case LWS_GAESM_CFB8: + memcpy(iv, iv_or_nonce_ctr_or_data_unit_16, 16); + n = mbedtls_aes_crypt_cfb8(&ctx->u.ctx, ctx->op, len, iv, + in, out); + break; + + case LWS_GAESM_CTR: + memcpy(iv, iv_or_nonce_ctr_or_data_unit_16, 16); + memcpy(sb, stream_block_16, 16); + n = mbedtls_aes_crypt_ctr(&ctx->u.ctx, len, nc_or_iv_off, + iv, sb, in, out); + memcpy(iv_or_nonce_ctr_or_data_unit_16, iv, 16); + memcpy(stream_block_16, sb, 16); + break; + + case LWS_GAESM_ECB: + n = mbedtls_aes_crypt_ecb(&ctx->u.ctx, ctx->op, in, out); + break; + + case LWS_GAESM_OFB: + memcpy(iv, iv_or_nonce_ctr_or_data_unit_16, 16); + n = mbedtls_aes_crypt_ofb(&ctx->u.ctx, len, nc_or_iv_off, iv, + in, out); + break; + + case LWS_GAESM_XTS: +#if defined(MBEDTLS_CIPHER_MODE_XTS) + memcpy(iv, iv_or_nonce_ctr_or_data_unit_16, 16); + n = mbedtls_aes_crypt_xts(&ctx->u.ctx_xts, ctx->op, len, iv, + in, out); + break; +#else + return -1; +#endif + case LWS_GAESM_GCM: + if (!ctx->underway) { + ctx->underway = 1; + + memcpy(ctx->tag, stream_block_16, taglen); + ctx->taglen = taglen; + + /* + * iv: iv_or_nonce_ctr_or_data_unit_16 + * iv_len: *nc_or_iv_off + * stream_block_16: pointer to tag + * additional data: in + * additional data len: len + */ + + n = mbedtls_gcm_starts(&ctx->u.ctx_gcm, ctx->op, + iv_or_nonce_ctr_or_data_unit_16, + *nc_or_iv_off, in, len); + if (n) { + lwsl_notice("%s: mbedtls_gcm_starts: -0x%x\n", + __func__, -n); + + return -1; + } + break; + } + + n = mbedtls_gcm_update(&ctx->u.ctx_gcm, len, in, out); + if (n) { + lwsl_notice("%s: mbedtls_gcm_update: -0x%x\n", + __func__, -n); + + return -1; + } + break; + } + + if (n) { + lwsl_notice("%s: enc: -0x%x, len %d\n", __func__, -n, (int)len); + + return -1; + } + + return 0; +} diff --git a/lib/tls/mbedtls/lws-genrsa.c b/lib/tls/mbedtls/lws-genrsa.c index 937ed6927..ebf36798d 100644 --- a/lib/tls/mbedtls/lws-genrsa.c +++ b/lib/tls/mbedtls/lws-genrsa.c @@ -18,16 +18,19 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA * - * lws_genhash provides a hash / hmac abstraction api in lws that works the + * lws_genrsa provides an RSA abstraction api in lws that works the * same whether you are using openssl or mbedtls hash functions underneath. */ #include "core/private.h" -#include "../../jose/private.h" LWS_VISIBLE void lws_jwk_destroy_genrsa_elements(struct lws_jwk_elements *el) { - lws_jwk_destroy_elements(el, LWS_COUNT_RSA_KEY_ELEMENTS); + int n; + + for (n = 0; n < LWS_COUNT_RSA_KEY_ELEMENTS; n++) + if (el[n].buf) + lws_free_set_NULL(el[n].buf); } LWS_VISIBLE int diff --git a/lib/tls/openssl/lws-genaes.c b/lib/tls/openssl/lws-genaes.c new file mode 100644 index 000000000..47c87b051 --- /dev/null +++ b/lib/tls/openssl/lws-genaes.c @@ -0,0 +1,313 @@ +/* + * libwebsockets - generic AES api hiding the backend + * + * Copyright (C) 2017 - 2018 Andy Green + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * lws_genaes provides an AES abstraction api in lws that works the + * same whether you are using openssl or mbedtls hash functions underneath. + */ +#include "core/private.h" +#include "../../jose/private.h" + +/* + * Care: many openssl apis return 1 for success. These are translated to the + * lws convention of 0 for success. + */ + +LWS_VISIBLE int +lws_genaes_create(struct lws_genaes_ctx *ctx, enum enum_aes_operation op, + enum enum_aes_modes mode, struct lws_jwk_elements *el, + int padding, void *engine) +{ + int n; + + ctx->ctx = EVP_CIPHER_CTX_new(); + if (!ctx->ctx) + return -1; + + ctx->mode = mode; + ctx->k = el; + ctx->engine = engine; + ctx->init = 0; + ctx->op = op; + + switch (ctx->k->len) { + case 128 / 8: + switch (mode) { + case LWS_GAESM_CBC: + ctx->cipher = EVP_aes_128_cbc(); + break; + case LWS_GAESM_CFB128: + ctx->cipher = EVP_aes_128_cfb128(); + break; + case LWS_GAESM_CFB8: + ctx->cipher = EVP_aes_128_cfb8(); + break; + case LWS_GAESM_CTR: + ctx->cipher = EVP_aes_128_ctr(); + break; + case LWS_GAESM_ECB: + ctx->cipher = EVP_aes_128_ecb(); + break; + case LWS_GAESM_OFB: + ctx->cipher = EVP_aes_128_ofb(); + break; + case LWS_GAESM_XTS: + lwsl_err("%s: AES XTS requires double-length key\n", + __func__); + break; + case LWS_GAESM_GCM: + ctx->cipher = EVP_aes_128_gcm(); + break; + default: + return -1; + } + break; + + case 192 / 8: + switch (mode) { + case LWS_GAESM_CBC: + ctx->cipher = EVP_aes_192_cbc(); + break; + case LWS_GAESM_CFB128: + ctx->cipher = EVP_aes_192_cfb128(); + break; + case LWS_GAESM_CFB8: + ctx->cipher = EVP_aes_192_cfb8(); + break; + case LWS_GAESM_CTR: + ctx->cipher = EVP_aes_192_ctr(); + break; + case LWS_GAESM_ECB: + ctx->cipher = EVP_aes_192_ecb(); + break; + case LWS_GAESM_OFB: + ctx->cipher = EVP_aes_192_ofb(); + break; + case LWS_GAESM_XTS: + lwsl_err("%s: AES XTS 192 invalid\n", __func__); + return -1; + case LWS_GAESM_GCM: + ctx->cipher = EVP_aes_192_gcm(); + break; + default: + return -1; + } + break; + + case 256 / 8: + switch (mode) { + case LWS_GAESM_CBC: + ctx->cipher = EVP_aes_256_cbc(); + break; + case LWS_GAESM_CFB128: + ctx->cipher = EVP_aes_256_cfb128(); + break; + case LWS_GAESM_CFB8: + ctx->cipher = EVP_aes_256_cfb8(); + break; + case LWS_GAESM_CTR: + ctx->cipher = EVP_aes_256_ctr(); + break; + case LWS_GAESM_ECB: + ctx->cipher = EVP_aes_256_ecb(); + break; + case LWS_GAESM_OFB: + ctx->cipher = EVP_aes_256_ofb(); + break; + case LWS_GAESM_XTS: + ctx->cipher = EVP_aes_128_xts(); + break; + case LWS_GAESM_GCM: + ctx->cipher = EVP_aes_256_gcm(); + break; + default: + return -1; + } + break; + + case 512 / 8: + switch (mode) { + case LWS_GAESM_XTS: + ctx->cipher = EVP_aes_256_xts(); + break; + default: + return -1; + } + break; + + default: + lwsl_err("%s: unsupported AES size %d bits\n", __func__, + ctx->k->len * 8); + return -1; + } + + switch (ctx->op) { + case LWS_GAESO_ENC: + n = EVP_EncryptInit_ex(ctx->ctx, ctx->cipher, ctx->engine, + NULL, NULL); + EVP_CIPHER_CTX_set_padding(ctx->ctx, padding); + break; + case LWS_GAESO_DEC: + n = EVP_DecryptInit_ex(ctx->ctx, ctx->cipher, ctx->engine, + NULL, NULL); + EVP_CIPHER_CTX_set_padding(ctx->ctx, padding); + break; + } + if (!n) { + lwsl_err("%s: cipher init failed (cipher %p)\n", __func__, + ctx->cipher); + + return -1; + } + + return 0; +} + +LWS_VISIBLE int +lws_genaes_destroy(struct lws_genaes_ctx *ctx, unsigned char *tag, size_t tlen) +{ + int outl = 0, n = 0; + uint8_t buf[256]; + + if (!ctx->ctx) + return 0; + + if (ctx->init) { + switch (ctx->op) { + case LWS_GAESO_ENC: + + if (EVP_EncryptFinal_ex(ctx->ctx, buf, &outl) != 1) { + lwsl_err("%s: enc final failed\n", __func__); + n = -1; + } + if (ctx->mode == LWS_GAESM_GCM) { + memset(tag, 0, tlen); + if (EVP_CIPHER_CTX_ctrl(ctx->ctx, + EVP_CTRL_GCM_GET_TAG, + ctx->taglen, tag) != 1) { + lwsl_err("get tag ctrl failed\n"); + lws_tls_err_describe(); + n = 1; + } else + if (memcmp(tag, ctx->tag, ctx->taglen)) { + lwsl_err("%s: tag mismatch " + "(bad first)\n", __func__); + lws_tls_err_describe(); + lwsl_hexdump_notice(tag, tlen); + lwsl_hexdump_notice(ctx->tag, ctx->taglen); + n = -1; + } + } + break; + case LWS_GAESO_DEC: + if (EVP_DecryptFinal_ex(ctx->ctx, buf, &outl) != 1) { + lwsl_err("%s: dec final failed\n", __func__); + lws_tls_err_describe(); + n = -1; + } + break; + } + if (outl) + lwsl_debug("%s: final len %d\n", __func__, outl); + } + + ctx->k = NULL; + EVP_CIPHER_CTX_free(ctx->ctx); + ctx->ctx = NULL; + + return n; +} + +LWS_VISIBLE int +lws_genaes_crypt(struct lws_genaes_ctx *ctx, + const uint8_t *in, size_t len, uint8_t *out, + uint8_t *iv_or_nonce_ctr_or_data_unit_16, + uint8_t *stream_block_16, size_t *nc_or_iv_off, int taglen) +{ + int n, outl, olen; + + if (!ctx->init) { + + EVP_CIPHER_CTX_set_key_length(ctx->ctx, ctx->k->len); + + if (ctx->mode == LWS_GAESM_GCM) { + EVP_CIPHER_CTX_ctrl(ctx->ctx, EVP_CTRL_GCM_SET_IVLEN, + *nc_or_iv_off, NULL); + memcpy(ctx->tag, stream_block_16, taglen); + ctx->taglen = taglen; + } + + switch (ctx->op) { + case LWS_GAESO_ENC: + n = EVP_EncryptInit_ex(ctx->ctx, NULL, NULL, + ctx->k->buf, + iv_or_nonce_ctr_or_data_unit_16); + break; + case LWS_GAESO_DEC: + if (ctx->mode == LWS_GAESM_GCM) + EVP_CIPHER_CTX_ctrl(ctx->ctx, + EVP_CTRL_CCM_SET_TAG, + ctx->taglen, ctx->tag); + n = EVP_DecryptInit_ex(ctx->ctx, NULL, NULL, + ctx->k->buf, + iv_or_nonce_ctr_or_data_unit_16); + break; + } + + if (!n) { + lwsl_err("%s: init failed (cipher %p)\n", + __func__, ctx->cipher); + + return -1; + } + ctx->init = 1; + if (ctx->mode == LWS_GAESM_GCM) { + /* AAD */ + if (len) + if (EVP_EncryptUpdate(ctx->ctx, NULL, &olen, + in, len) != 1) { + lwsl_err("%s: set aad failed\n", + __func__); + + return -1; + } + + return 0; + } + } + + switch (ctx->op) { + case LWS_GAESO_ENC: + n = EVP_EncryptUpdate(ctx->ctx, out, &outl, in, len); + break; + case LWS_GAESO_DEC: + n = EVP_DecryptUpdate(ctx->ctx, out, &outl, in, len); + break; + } + + // lwsl_notice("discarding outl %d\n", (int)outl); + + if (!n) { + lwsl_notice("%s: update failed\n", __func__); + + return -1; + } + + return 0; +} diff --git a/lib/tls/openssl/lws-genrsa.c b/lib/tls/openssl/lws-genrsa.c index 8bb52bf0b..ce9c94776 100644 --- a/lib/tls/openssl/lws-genrsa.c +++ b/lib/tls/openssl/lws-genrsa.c @@ -18,16 +18,19 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA * - * lws_genhash provides a hash / hmac abstraction api in lws that works the + * lws_genrsa provides an RSA abstraction api in lws that works the * same whether you are using openssl or mbedtls hash functions underneath. */ #include "core/private.h" -#include "../../jose/private.h" LWS_VISIBLE void lws_jwk_destroy_genrsa_elements(struct lws_jwk_elements *el) { - lws_jwk_destroy_elements(el, LWS_COUNT_RSA_KEY_ELEMENTS); + int n; + + for (n = 0; n < LWS_COUNT_RSA_KEY_ELEMENTS; n++) + if (el[n].buf) + lws_free_set_NULL(el[n].buf); } LWS_VISIBLE int diff --git a/lib/tls/private.h b/lib/tls/private.h index ad01bfd4f..b9536be09 100644 --- a/lib/tls/private.h +++ b/lib/tls/private.h @@ -50,11 +50,15 @@ #undef MBEDTLS_CONFIG_FILE #define MBEDTLS_CONFIG_FILE #include + #include + #include #include #include "tls/mbedtls/wrapper/include/openssl/ssl.h" /* wrapper !!!! */ #else /* not esp32 */ #if defined(LWS_WITH_MBEDTLS) #include + #include + #include #include #include #include "tls/mbedtls/wrapper/include/openssl/ssl.h" /* wrapper !!!! */ @@ -66,6 +70,7 @@ #include #include #include + #include #ifdef LWS_HAVE_OPENSSL_ECDH_H #include #endif diff --git a/minimal-examples/api-tests/api-test-gencrypto/CMakeLists.txt b/minimal-examples/api-tests/api-test-gencrypto/CMakeLists.txt new file mode 100644 index 000000000..a36a5cda8 --- /dev/null +++ b/minimal-examples/api-tests/api-test-gencrypto/CMakeLists.txt @@ -0,0 +1,78 @@ +cmake_minimum_required(VERSION 2.8) +include(CheckCSourceCompiles) + +set(SAMP lws-api-test-gencrypto) +set(SRCS main.c lws-genaes.c) + +# If we are being built as part of lws, confirm current build config supports +# reqconfig, else skip building ourselves. +# +# If we are being built externally, confirm installed lws was configured to +# support reqconfig, else error out with a helpful message about the problem. +# +MACRO(require_lws_config reqconfig _val result) + + if (DEFINED ${reqconfig}) + if (${reqconfig}) + set (rq 1) + else() + set (rq 0) + endif() + else() + set(rq 0) + endif() + + if (${_val} EQUAL ${rq}) + set(SAME 1) + else() + set(SAME 0) + endif() + + if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME}) + if (${_val}) + message("${SAMP}: skipping as lws being built without ${reqconfig}") + else() + message("${SAMP}: skipping as lws built with ${reqconfig}") + endif() + set(${result} 0) + else() + if (LWS_WITH_MINIMAL_EXAMPLES) + set(MET ${SAME}) + else() + CHECK_C_SOURCE_COMPILES("#include \nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig}) + if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig}) + set(HAS_${reqconfig} 0) + else() + set(HAS_${reqconfig} 1) + endif() + if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val})) + set(MET 1) + else() + set(MET 0) + endif() + endif() + if (NOT MET) + if (${_val}) + message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}") + else() + message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project") + endif() + endif() + endif() +ENDMACRO() + +set(requirements 1) +require_lws_config(LWS_WITH_GENAES 1 requirements) + +if (requirements) + + add_executable(${SAMP} ${SRCS}) + + if (websockets_shared) + target_link_libraries(${SAMP} websockets_shared) + add_dependencies(${SAMP} websockets_shared) + else() + target_link_libraries(${SAMP} websockets) + endif() +endif() + diff --git a/minimal-examples/api-tests/api-test-gencrypto/README.md b/minimal-examples/api-tests/api-test-gencrypto/README.md new file mode 100644 index 000000000..ab8ff0bea --- /dev/null +++ b/minimal-examples/api-tests/api-test-gencrypto/README.md @@ -0,0 +1,26 @@ +# lws api test gencrypto + +Demonstrates how to use and performs selftests for Generic Crypto, +which works the same whether the tls backend is OpenSSL or mbedTLS + +## build + +``` + $ cmake . && make +``` + +## usage + +Commandline option|Meaning +---|--- +-d |Debug verbosity in decimal, eg, -d15 + +``` + $ ./lws-api-test-gencrypto +[2018/12/05 08:30:27:1342] USER: LWS gencrypto apis tests +[2018/12/05 08:30:27:1343] NOTICE: Creating Vhost 'default' (serving disabled), 1 protocols, IPv6 off +[2018/12/05 08:30:27:1343] NOTICE: created client ssl context for default +[2018/12/05 08:30:27:1344] NOTICE: test_genaes: selftest OK +[2018/12/05 08:30:27:1344] USER: Completed: PASS +``` + diff --git a/minimal-examples/api-tests/api-test-gencrypto/lws-genaes.c b/minimal-examples/api-tests/api-test-gencrypto/lws-genaes.c new file mode 100644 index 000000000..634912518 --- /dev/null +++ b/minimal-examples/api-tests/api-test-gencrypto/lws-genaes.c @@ -0,0 +1,788 @@ +/* + * lws-api-test-gencrypto - lws-genaes + * + * Copyright (C) 2018 Andy Green + * + * This file is made available under the Creative Commons CC0 1.0 + * Universal Public Domain Dedication. + */ + +#include + +static const uint8_t + /* + * produced with (plaintext.txt contains "test plaintext\0\0") + * + * openssl enc -aes256 \ + * -K "0123456789abcdeffedcba98765432100123456789abcdeffedcba9876543210" \ + * -iv "0123456789abcdeffedcba9876543210" + * -in plaintext.txt -out out.enc + * + */ + *cbc256 = (uint8_t *)"test plaintext\0\0", + cbc256_enc[] = { + 0x2b, 0x5d, 0xb2, 0xa8, 0x5a, 0x5a, 0xf4, 0x2e, + 0xf7, 0xf9, 0xc5, 0x3c, 0x73, 0xef, 0x40, 0x88, + }, cbc256_iv[] = { + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, + }, cbc256_key[] = { + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, + } +; + +static int +test_genaes_cbc(void) +{ + struct lws_genaes_ctx ctx; + struct lws_jwk_elements e; + uint8_t res[32], res1[32]; + + /* + * As part of a jwk, these are allocated. But here we just use one as + * a wrapper on a static binary key. + */ + e.buf = (uint8_t *)cbc256_key; + e.len = sizeof(cbc256_key); + + if (lws_genaes_create(&ctx, LWS_GAESO_ENC, LWS_GAESM_CBC, &e, 0, NULL)) { + lwsl_err("%s: lws_genaes_create failed\n", __func__); + return 1; + } + + if (lws_genaes_crypt(&ctx, cbc256, 16, res, (uint8_t *)cbc256_iv, + NULL, NULL, 0)) { + lwsl_err("%s: lws_genaes_crypt failed\n", __func__); + goto bail; + } + + if (lws_genaes_destroy(&ctx, NULL, 0)) { + lwsl_err("%s: lws_genaes_destroy enc failed\n", __func__); + return -1; + } + + if (memcmp(cbc256_enc, res, 16)) { + lwsl_err("%s: lws_genaes_crypt encoding mismatch\n", __func__); + lwsl_hexdump_notice(res, 16); + return -1; + } + + + if (lws_genaes_create(&ctx, LWS_GAESO_DEC, LWS_GAESM_CBC, &e, 0, NULL)) { + lwsl_err("%s: lws_genaes_create dec failed\n", __func__); + return -1; + } + + if (lws_genaes_crypt(&ctx, res, 16, res1, (uint8_t *)cbc256_iv, + NULL, NULL, 0)) { + lwsl_err("%s: lws_genaes_crypt dec failed\n", __func__); + goto bail; + } + + if (lws_genaes_destroy(&ctx, NULL, 0)) { + lwsl_err("%s: lws_genaes_destroy dec failed\n", __func__); + lwsl_hexdump_notice(res1, 16); + return -1; + } + + if (memcmp(cbc256, res1, 16)) { + lwsl_err("%s: lws_genaes_crypt decoding mismatch\n", __func__); + lwsl_hexdump_notice(res, 16); + return -1; + } + + return 0; + +bail: + lws_genaes_destroy(&ctx, NULL, 0); + + return -1; +} + +static const uint8_t +/* + * produced with (plaintext.txt contains "test plaintext\0\0") + * + * openssl enc -aes-128-cfb \ + * -K "0123456789abcdeffedcba9876543210" \ + * -iv "0123456789abcdeffedcba9876543210" + * -in plaintext.txt -out out.enc + * + */ +*cfb128 = (uint8_t *)"test plaintext\0\0", +cfb128_enc[] = { + 0xd2, 0x11, 0x86, 0xd7, 0xa9, 0x55, 0x59, 0x04, + 0x4f, 0x63, 0x7c, 0xb9, 0xc6, 0xa1, 0xc9, 0x71 +}, cfb128_iv[] = { + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, +}, cfb128_key[] = { + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, +}; + +static int +test_genaes_cfb128(void) +{ + struct lws_genaes_ctx ctx; + struct lws_jwk_elements e; + uint8_t res[32], res1[32]; + size_t iv_off = 0; + + e.buf = (uint8_t *)cfb128_key; + e.len = sizeof(cfb128_key); + + if (lws_genaes_create(&ctx, LWS_GAESO_ENC, LWS_GAESM_CFB128, &e, 0, NULL)) { + lwsl_err("%s: lws_genaes_create failed\n", __func__); + return 1; + } + + if (lws_genaes_crypt(&ctx, cfb128, 16, res, (uint8_t *)cfb128_iv, + NULL, &iv_off, 0)) { + lwsl_err("%s: lws_genaes_crypt failed\n", __func__); + goto bail; + } + + if (lws_genaes_destroy(&ctx, NULL, 0)) { + lwsl_err("%s: lws_genaes_destroy failed\n", __func__); + return -1; + } + + if (memcmp(cfb128_enc, res, 16)) { + lwsl_err("%s: lws_genaes_crypt encoding mismatch\n", __func__); + lwsl_hexdump_notice(res, 16); + return -1; + } + + iv_off = 0; + + if (lws_genaes_create(&ctx, LWS_GAESO_DEC, LWS_GAESM_CFB128, &e, 0, NULL)) { + lwsl_err("%s: lws_genaes_create dec failed\n", __func__); + return -1; + } + + if (lws_genaes_crypt(&ctx, res, 16, res1, (uint8_t *)cfb128_iv, + NULL, &iv_off, 0)) { + lwsl_err("%s: lws_genaes_crypt dec failed\n", __func__); + goto bail; + } + + if (lws_genaes_destroy(&ctx, NULL, 0)) { + lwsl_err("%s: lws_genaes_destroy failed\n", __func__); + return -1; + } + + if (memcmp(cfb128, res1, 16)) { + lwsl_err("%s: lws_genaes_crypt decoding mismatch\n", __func__); + lwsl_hexdump_notice(res1, 16); + return -1; + } + + return 0; + +bail: + lws_genaes_destroy(&ctx, NULL, 0); + + return -1; +} + +static const uint8_t +/* + * produced with (plaintext.txt contains "test plaintext\0\0") + * + * openssl enc -aes-128-cfb8 \ + * -K "0123456789abcdeffedcba9876543210" \ + * -iv "0123456789abcdeffedcba9876543210" + * -in plaintext.txt -out out.enc + * + */ +*cfb8 = (uint8_t *)"test plaintext\0\0", +cfb8_enc[] = { + 0xd2, 0x91, 0x06, 0x2d, 0x1b, 0x1e, 0x9b, 0x39, + 0xa6, 0x65, 0x8e, 0xbe, 0x68, 0x32, 0x3d, 0xab +}, cfb8_iv[] = { + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, +}, cfb8_key[] = { + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, +}; + +static int +test_genaes_cfb8(void) +{ + struct lws_genaes_ctx ctx; + struct lws_jwk_elements e; + uint8_t res[32], res1[32]; + + e.buf = (uint8_t *)cfb8_key; + e.len = sizeof(cfb8_key); + + if (lws_genaes_create(&ctx, LWS_GAESO_ENC, LWS_GAESM_CFB8, &e, 0, NULL)) { + lwsl_err("%s: lws_genaes_create failed\n", __func__); + return 1; + } + + if (lws_genaes_crypt(&ctx, cfb8, 16, res, (uint8_t *)cfb8_iv, + NULL, NULL, 0)) { + lwsl_err("%s: lws_genaes_crypt failed\n", __func__); + goto bail; + } + + if (lws_genaes_destroy(&ctx, NULL, 0)) { + lwsl_err("%s: lws_genaes_destroy failed\n", __func__); + return -1; + } + + if (memcmp(cfb8_enc, res, 16)) { + lwsl_err("%s: lws_genaes_crypt encoding mismatch\n", __func__); + lwsl_hexdump_notice(res, 16); + return -1; + } + + if (lws_genaes_create(&ctx, LWS_GAESO_DEC, LWS_GAESM_CFB8, &e, 0, NULL)) { + lwsl_err("%s: lws_genaes_create dec failed\n", __func__); + return -1; + } + + if (lws_genaes_crypt(&ctx, res, 16, res1, (uint8_t *)cfb8_iv, + NULL, NULL, 0)) { + lwsl_err("%s: lws_genaes_crypt dec failed\n", __func__); + goto bail; + } + + if (lws_genaes_destroy(&ctx, NULL, 0)) { + lwsl_err("%s: lws_genaes_destroy failed\n", __func__); + return -1; + } + + if (memcmp(cfb8, res1, 16)) { + lwsl_err("%s: lws_genaes_crypt decoding mismatch\n", __func__); + lwsl_hexdump_notice(res1, 16); + return -1; + } + + return 0; + +bail: + lws_genaes_destroy(&ctx, NULL, 0); + + return -1; +} + +static const uint8_t +/* + * produced with (plaintext.txt contains "test plaintext\0\0") + * + * openssl enc -aes-128-ctr \ + * -K "0123456789abcdeffedcba9876543210" \ + * -iv "0123456789abcdeffedcba9876543210" + * -in plaintext.txt -out out.enc + * + */ +*ctr = (uint8_t *)"test plaintext\0\0", +ctr_enc[] = { + 0xd2, 0x11, 0x86, 0xd7, 0xa9, 0x55, 0x59, 0x04, + 0x4f, 0x63, 0x7c, 0xb9, 0xc6, 0xa1, 0xc9, 0x71 +}, ctr_iv[] = { + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, +}, ctr_key[] = { + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, +}; + +static int +test_genaes_ctr(void) +{ + uint8_t nonce_counter[16], sb[16]; + struct lws_genaes_ctx ctx; + struct lws_jwk_elements e; + uint8_t res[32], res1[32]; + size_t nc_off = 0; + + e.buf = (uint8_t *)ctr_key; + e.len = sizeof(ctr_key); + + memset(sb, 0, sizeof(nonce_counter)); + memcpy(nonce_counter, ctr_iv, sizeof(ctr_iv)); + + if (lws_genaes_create(&ctx, LWS_GAESO_ENC, LWS_GAESM_CTR, &e, 0, NULL)) { + lwsl_err("%s: lws_genaes_create failed\n", __func__); + return 1; + } + + if (lws_genaes_crypt(&ctx, ctr, 16, res, nonce_counter, sb, &nc_off, 0)) { + lwsl_err("%s: lws_genaes_crypt failed\n", __func__); + goto bail; + } + + if (lws_genaes_destroy(&ctx, NULL, 0)) { + lwsl_err("%s: lws_genaes_destroy failed\n", __func__); + return -1; + } + + if (memcmp(ctr_enc, res, 16)) { + lwsl_err("%s: lws_genaes_crypt encoding mismatch\n", __func__); + lwsl_hexdump_notice(res, 16); + return -1; + } + + nc_off = 0; + memset(sb , 0, sizeof(nonce_counter)); + memcpy(nonce_counter, ctr_iv, sizeof(ctr_iv)); + + if (lws_genaes_create(&ctx, LWS_GAESO_DEC, LWS_GAESM_CTR, &e, 0, NULL)) { + lwsl_err("%s: lws_genaes_create dec failed\n", __func__); + return -1; + } + + if (lws_genaes_crypt(&ctx, res, 16, res1, nonce_counter, sb, &nc_off, 0)) { + lwsl_err("%s: lws_genaes_crypt dec failed\n", __func__); + goto bail; + } + + if (lws_genaes_destroy(&ctx, NULL, 0)) { + lwsl_err("%s: lws_genaes_destroy failed\n", __func__); + return -1; + } + + if (memcmp(ctr, res1, 16)) { + lwsl_err("%s: lws_genaes_crypt decoding mismatch\n", __func__); + lwsl_hexdump_notice(res1, 16); + return -1; + } + + lws_explicit_bzero(sb, sizeof(sb)); + + return 0; + +bail: + lws_genaes_destroy(&ctx, NULL, 0); + + return -1; +} + +static const uint8_t +/* + * produced with (plaintext.txt contains "test plaintext\0\0") + * + * openssl enc -aes-128-ecb \ + * -K "0123456789abcdeffedcba9876543210" \ + * -in plaintext.txt -out out.enc + * + */ +*ecb = (uint8_t *)"test plaintext\0\0", +ecb_enc[] = { + 0xf3, 0xe5, 0x6c, 0x80, 0x3a, 0xf1, 0xc4, 0xa0, + 0x7e, 0xdf, 0x86, 0x0f, 0x6d, 0xca, 0x5d, 0x36, + 0x17, 0x22, 0x37, 0x42, 0x47, 0x41, 0x67, 0x7d, + 0x99, 0x25, 0x02, 0x6b, 0x6b, 0x8f, 0x9c, 0x7f +}, ecb_key[] = { + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, +}; + +static int +test_genaes_ecb(void) +{ + struct lws_genaes_ctx ctx; + struct lws_jwk_elements e; + uint8_t res[32], res1[32]; + + /* + * As part of a jwk, these are allocated. But here we just use one as + * a wrapper on a static binary key. + */ + e.buf = (uint8_t *)ecb_key; + e.len = sizeof(ecb_key); + + if (lws_genaes_create(&ctx, LWS_GAESO_ENC, LWS_GAESM_ECB, &e, 0, NULL)) { + lwsl_err("%s: lws_genaes_create failed\n", __func__); + return 1; + } + + if (lws_genaes_crypt(&ctx, ecb, 16, res, NULL, NULL, NULL, 0)) { + lwsl_err("%s: lws_genaes_crypt failed\n", __func__); + goto bail; + } + + if (lws_genaes_destroy(&ctx, NULL, 0)) { + lwsl_err("%s: lws_genaes_destroy failed\n", __func__); + return -1; + } + + if (memcmp(ecb_enc, res, 16)) { + lwsl_err("%s: lws_genaes_crypt encoding mismatch\n", __func__); + lwsl_hexdump_notice(res, 16); + return -1; + } + + if (lws_genaes_create(&ctx, LWS_GAESO_DEC, LWS_GAESM_ECB, &e, 0, NULL)) { + lwsl_err("%s: lws_genaes_create dec failed\n", __func__); + return -1; + } + + if (lws_genaes_crypt(&ctx, res, 16, res1, NULL, NULL, NULL, 0)) { + lwsl_err("%s: lws_genaes_crypt dec failed\n", __func__); + goto bail; + } + + if (lws_genaes_destroy(&ctx, NULL, 0)) { + lwsl_err("%s: lws_genaes_destroy failed\n", __func__); + return -1; + } + + if (memcmp(ecb, res1, 16)) { + lwsl_err("%s: lws_genaes_crypt decoding mismatch\n", __func__); + lwsl_hexdump_notice(res, 16); + return -1; + } + + return 0; + +bail: + lws_genaes_destroy(&ctx, NULL, 0); + + return -1; +} + +static const uint8_t + /* + * produced with (plaintext.txt contains "test plaintext\0\0") + * + * openssl enc -aes-128-ofb \ + * -K "0123456789abcdeffedcba98765432100123456789abcdeffedcba9876543210" \ + * -iv "0123456789abcdeffedcba9876543210" + * -in plaintext.txt -out out.enc + * + */ + *ofb = (uint8_t *)"test plaintext\0\0", + ofb_enc[] = { + /* !!! ugh... openssl app produces this... */ + // 0xd2, 0x11, 0x86, 0xd7, 0xa9, 0x55, 0x59, 0x04, + // 0x4f, 0x63, 0x7c, 0xb9, 0xc6, 0xa1, 0xc9, 0x71, + /* but both OpenSSL and mbedTLS produce this */ + 0x11, 0x33, 0x6D, 0xFC, 0x88, 0x4C, 0x28, 0xBA, + 0xD0, 0xF2, 0x6C, 0xBC, 0xDE, 0x4A, 0x56, 0x20 + }, ofb_iv[] = { + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, + }, ofb_key[] = { + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, + } +; + +static int +test_genaes_ofb(void) +{ + struct lws_genaes_ctx ctx; + struct lws_jwk_elements e; + uint8_t res[32], res1[32]; + size_t iv_off = 0; + + e.buf = (uint8_t *)ofb_key; + e.len = sizeof(ofb_key); + + if (lws_genaes_create(&ctx, LWS_GAESO_ENC, LWS_GAESM_OFB, &e, 0, NULL)) { + lwsl_err("%s: lws_genaes_create failed\n", __func__); + return 1; + } + + if (lws_genaes_crypt(&ctx, ofb, 16, res, (uint8_t *)ofb_iv, NULL, + &iv_off, 0)) { + lwsl_err("%s: lws_genaes_crypt failed\n", __func__); + goto bail; + } + + if (lws_genaes_destroy(&ctx, NULL, 0)) { + lwsl_err("%s: lws_genaes_destroy failed\n", __func__); + return -1; + } + + if (memcmp(ofb_enc, res, 16)) { + lwsl_err("%s: lws_genaes_crypt encoding mismatch\n", __func__); + lwsl_hexdump_notice(res, 16); + return -1; + } + + iv_off = 0; + + if (lws_genaes_create(&ctx, LWS_GAESO_DEC, LWS_GAESM_OFB, &e, 0, NULL)) { + lwsl_err("%s: lws_genaes_create dec failed\n", __func__); + return -1; + } + + if (lws_genaes_crypt(&ctx, res, 16, res1, (uint8_t *)ofb_iv, NULL, + &iv_off, 0)) { + lwsl_err("%s: lws_genaes_crypt dec failed\n", __func__); + goto bail; + } + + if (lws_genaes_destroy(&ctx, NULL, 0)) { + lwsl_err("%s: lws_genaes_destroy failed\n", __func__); + return -1; + } + + if (memcmp(ofb, res1, 16)) { + lwsl_err("%s: lws_genaes_crypt decoding mismatch\n", __func__); + lwsl_hexdump_notice(res, 16); + return -1; + } + + return 0; + +bail: + lws_genaes_destroy(&ctx, NULL, 0); + + return -1; +} + +static const uint8_t + /* + * Fedora openssl tool doesn't support xts... this data produced + * by testing on mbedtls + OpenSSL and getting the same result + * + * NOTICE that xts requires a double-length key... + */ + *xts = (uint8_t *)"test plaintext\0\0", + xts_enc[] = { + 0xA9, 0x26, 0xFD, 0x68, 0x1E, 0x6A, 0x80, 0xCA, + 0x18, 0xD5, 0xEB, 0x08, 0x23, 0xF1, 0x90, 0x15 + }, xts_key[] = { + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, + } +; + +static int +test_genaes_xts(void) +{ + struct lws_genaes_ctx ctx; + struct lws_jwk_elements e; + uint8_t res[32], res1[32], data_unit[16]; + + memset(data_unit, 0, sizeof(data_unit)); + + e.buf = (uint8_t *)xts_key; + e.len = sizeof(xts_key); + + if (lws_genaes_create(&ctx, LWS_GAESO_ENC, LWS_GAESM_XTS, &e, 0, NULL)) { + lwsl_err("%s: lws_genaes_create failed\n", __func__); + return 1; + } + + if (lws_genaes_crypt(&ctx, xts, 16, res, data_unit, NULL, NULL, 0)) { + lwsl_err("%s: lws_genaes_crypt failed\n", __func__); + goto bail; + } + + if (lws_genaes_destroy(&ctx, NULL, 0)) { + lwsl_err("%s: lws_genaes_destroy failed\n", __func__); + return -1; + } + + if (memcmp(xts_enc, res, 16)) { + lwsl_err("%s: lws_genaes_crypt encoding mismatch\n", __func__); + lwsl_hexdump_notice(res, 16); + return -1; + } + + if (lws_genaes_create(&ctx, LWS_GAESO_DEC, LWS_GAESM_XTS, &e, 0, NULL)) { + lwsl_err("%s: lws_genaes_create dec failed\n", __func__); + return -1; + } + + if (lws_genaes_crypt(&ctx, res, 16, res1, data_unit, NULL, NULL, 0)) { + lwsl_err("%s: lws_genaes_crypt dec failed\n", __func__); + goto bail; + } + + if (lws_genaes_destroy(&ctx, NULL, 0)) { + lwsl_err("%s: lws_genaes_destroy failed\n", __func__); + return -1; + } + + if (memcmp(xts, res1, 16)) { + lwsl_err("%s: lws_genaes_crypt decoding mismatch\n", __func__); + lwsl_hexdump_notice(res, 16); + return -1; + } + + return 0; + +bail: + lws_genaes_destroy(&ctx, NULL, 0); + + return -1; +} + +static const uint8_t + /* + * https://csrc.nist.gov/CSRC/media/Projects/ + * Cryptographic-Algorithm-Validation-Program/ + * documents/mac/gcmtestvectors.zip + */ + + gcm_ct[] = { + 0xf7, 0x26, 0x44, 0x13, 0xa8, 0x4c, 0x0e, 0x7c, + 0xd5, 0x36, 0x86, 0x7e, 0xb9, 0xf2, 0x17, 0x36 + }, gcm_iv[] = { + 0x99, 0xaa, 0x3e, 0x68, 0xed, 0x81, 0x73, 0xa0, + 0xee, 0xd0, 0x66, 0x84 + }, gcm_key[] = { + 0xee, 0xbc, 0x1f, 0x57, 0x48, 0x7f, 0x51, 0x92, + 0x1c, 0x04, 0x65, 0x66, 0x5f, 0x8a, 0xe6, 0xd1, + 0x65, 0x8b, 0xb2, 0x6d, 0xe6, 0xf8, 0xa0, 0x69, + 0xa3, 0x52, 0x02, 0x93, 0xa5, 0x72, 0x07, 0x8f + }, gcm_pt[] = { + 0xf5, 0x6e, 0x87, 0x05, 0x5b, 0xc3, 0x2d, 0x0e, + 0xeb, 0x31, 0xb2, 0xea, 0xcc, 0x2b, 0xf2, 0xa5 + }, gcm_aad[] = { + 0x4d, 0x23, 0xc3, 0xce, 0xc3, 0x34, 0xb4, 0x9b, + 0xdb, 0x37, 0x0c, 0x43, 0x7f, 0xec, 0x78, 0xde + }, gcm_tag[] = { + 0x67, 0xba, 0x05, 0x10, 0x26, 0x2a, 0xe4, 0x87, + 0xd7, 0x37, 0xee, 0x62, 0x98, 0xf7, 0x7e, 0x0c + }; + +static int +test_genaes_gcm(void) +{ + uint8_t res[sizeof(gcm_ct)], tag[sizeof(gcm_tag)]; + struct lws_genaes_ctx ctx; + struct lws_jwk_elements e; + size_t iv_off = 0; + + e.buf = (uint8_t *)gcm_key; + e.len = sizeof(gcm_key); + + /* Encrypt */ + + if (lws_genaes_create(&ctx, LWS_GAESO_ENC, LWS_GAESM_GCM, &e, 0, NULL)) { + lwsl_err("%s: lws_genaes_create failed\n", __func__); + return 1; + } + + /* first we set the iv and aad */ + + iv_off = sizeof(gcm_iv); + if (lws_genaes_crypt(&ctx, gcm_aad, sizeof(gcm_aad), NULL, + (uint8_t *)gcm_iv, (uint8_t *)gcm_tag, + &iv_off, sizeof(gcm_tag))) { + lwsl_err("%s: lws_genaes_crypt 1 failed\n", __func__); + goto bail; + } + + if (lws_genaes_crypt(&ctx, gcm_pt, sizeof(gcm_pt), res, + NULL, NULL, NULL, 0)) { + lwsl_err("%s: lws_genaes_crypt 2 failed\n", __func__); + goto bail; + } + + if (lws_genaes_destroy(&ctx, tag, sizeof(tag))) { + lwsl_err("%s: lws_genaes_destroy enc failed\n", __func__); + return -1; + } + + if (memcmp(gcm_ct, res, sizeof(gcm_ct))) { + lwsl_err("%s: lws_genaes_crypt encoding mismatch\n", __func__); + lwsl_hexdump_notice(res, sizeof(gcm_ct)); + return -1; + } + + + /* Decrypt */ + + if (lws_genaes_create(&ctx, LWS_GAESO_DEC, LWS_GAESM_GCM, &e, 0, NULL)) { + lwsl_err("%s: lws_genaes_create failed\n", __func__); + return 1; + } + + iv_off = sizeof(gcm_iv); /* initial call sets iv + aad + tag */ + if (lws_genaes_crypt(&ctx, gcm_aad, sizeof(gcm_aad), NULL, + (uint8_t *)gcm_iv, (uint8_t *)gcm_tag, + &iv_off, sizeof(gcm_tag))) { + lwsl_err("%s: lws_genaes_crypt 1 failed\n", __func__); + goto bail; + } + + if (lws_genaes_crypt(&ctx, gcm_ct, sizeof(gcm_ct), res, + NULL, NULL, NULL, 0)) { + lwsl_err("%s: lws_genaes_crypt 2 failed\n", __func__); + goto bail; + } + + if (lws_genaes_destroy(&ctx, tag, sizeof(tag))) { + lwsl_err("%s: lws_genaes_destroy dec failed\n", __func__); + return -1; + } + + if (memcmp(gcm_pt, res, sizeof(gcm_pt))) { + lwsl_err("%s: lws_genaes_crypt decoding mismatch\n", __func__); + lwsl_hexdump_notice(res, sizeof(gcm_ct)); + return -1; + } + + return 0; + +bail: + lws_genaes_destroy(&ctx, NULL, 0); + + return -1; +} + +int +test_genaes(struct lws_context *context) +{ + + if (test_genaes_cbc()) + goto bail; + + if (test_genaes_cfb128()) + goto bail; + + if (test_genaes_cfb8()) + goto bail; + + if (test_genaes_ctr()) + goto bail; + + if (test_genaes_ecb()) + goto bail; + + if (test_genaes_ofb()) + goto bail; + +#if defined(MBEDTLS_CONFIG_H) && !defined(MBEDTLS_CIPHER_MODE_XTS) +#else + if (test_genaes_xts()) + goto bail; +#endif + + if (test_genaes_gcm()) + goto bail; + + /* end */ + + lwsl_notice("%s: selftest OK\n", __func__); + + return 0; + +bail: + lwsl_err("%s: selftest failed ++++++++++++++++++++\n", __func__); + + return 1; +} diff --git a/minimal-examples/api-tests/api-test-gencrypto/main.c b/minimal-examples/api-tests/api-test-gencrypto/main.c new file mode 100644 index 000000000..7bdcdf532 --- /dev/null +++ b/minimal-examples/api-tests/api-test-gencrypto/main.c @@ -0,0 +1,45 @@ +/* + * lws-api-test-gencrypto + * + * Copyright (C) 2018 Andy Green + * + * This file is made available under the Creative Commons CC0 1.0 + * Universal Public Domain Dedication. + */ + +#include + +int +test_genaes(struct lws_context *context); + +int main(int argc, const char **argv) +{ + struct lws_context_creation_info info; + struct lws_context *context; + const char *p; + int result = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE; + + if ((p = lws_cmdline_option(argc, argv, "-d"))) + logs = atoi(p); + + lws_set_log_level(logs, NULL); + lwsl_user("LWS gencrypto apis tests\n"); + + memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ + info.port = CONTEXT_PORT_NO_LISTEN; + info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; + + context = lws_create_context(&info); + if (!context) { + lwsl_err("lws init failed\n"); + return 1; + } + + result |= test_genaes(context); + + lwsl_user("Completed: %s\n", result ? "FAIL" : "PASS"); + + lws_context_destroy(context); + + return result; +} diff --git a/minimal-examples/api-tests/api-test-gencrypto/selftest.sh b/minimal-examples/api-tests/api-test-gencrypto/selftest.sh new file mode 100755 index 000000000..16d1e2e8e --- /dev/null +++ b/minimal-examples/api-tests/api-test-gencrypto/selftest.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# +# $1: path to minimal example binaries... +# if lws is built with -DLWS_WITH_MINIMAL_EXAMPLES=1 +# that will be ./bin from your build dir +# +# $2: path for logs and results. The results will go +# in a subdir named after the directory this script +# is in +# +# $3: offset for test index count +# +# $4: total test count +# +# $5: path to ./minimal-examples dir in lws +# +# Test return code 0: OK, 254: timed out, other: error indication + +. $5/selftests-library.sh + +COUNT_TESTS=1 + +dotest $1 $2 apiselftest +exit $FAILS diff --git a/minimal-examples/api-tests/api-test-jose/CMakeLists.txt b/minimal-examples/api-tests/api-test-jose/CMakeLists.txt index 49207b7b2..3f6f768e9 100644 --- a/minimal-examples/api-tests/api-test-jose/CMakeLists.txt +++ b/minimal-examples/api-tests/api-test-jose/CMakeLists.txt @@ -61,7 +61,12 @@ MACRO(require_lws_config reqconfig _val result) endif() ENDMACRO() +set(requirements 1) +require_lws_config(LWS_WITH_JWK 1 requirements) +require_lws_config(LWS_WITH_JWS 1 requirements) +require_lws_config(LWS_WITH_JWE 1 requirements) +if (requirements) add_executable(${SAMP} ${SRCS}) @@ -71,3 +76,4 @@ ENDMACRO() else() target_link_libraries(${SAMP} websockets) endif() +endif() diff --git a/plugins/ssh-base/crypto/chacha.c b/plugins/ssh-base/crypto/chacha.c index 5c9bb696c..694de2565 100644 --- a/plugins/ssh-base/crypto/chacha.c +++ b/plugins/ssh-base/crypto/chacha.c @@ -345,9 +345,9 @@ chachapoly_crypt(struct lws_ssh_keys *keys, u_int seqnr, u_char *dest, } r = 0; out: - explicit_bzero(expected_tag, sizeof(expected_tag)); - explicit_bzero(seqbuf, sizeof(seqbuf)); - explicit_bzero(poly_key, sizeof(poly_key)); + lws_explicit_bzero(expected_tag, sizeof(expected_tag)); + lws_explicit_bzero(seqbuf, sizeof(seqbuf)); + lws_explicit_bzero(poly_key, sizeof(poly_key)); return r; } diff --git a/plugins/ssh-base/include/lws-ssh.h b/plugins/ssh-base/include/lws-ssh.h index 4ffb17eae..10de9ff15 100644 --- a/plugins/ssh-base/include/lws-ssh.h +++ b/plugins/ssh-base/include/lws-ssh.h @@ -559,9 +559,6 @@ lws_g32(uint8_t **p); extern uint32_t lws_p32(uint8_t *p, uint32_t v); -extern void -explicit_bzero(void *p, size_t len); - extern int lws_timingsafe_bcmp(const void *a, const void *b, uint32_t len); diff --git a/plugins/ssh-base/kex-25519.c b/plugins/ssh-base/kex-25519.c index f4ee5acb0..2fd3aa4ce 100644 --- a/plugins/ssh-base/kex-25519.c +++ b/plugins/ssh-base/kex-25519.c @@ -534,7 +534,7 @@ kex_ecdh(struct per_session_data__sshd *pss, uint8_t *reply, uint32_t *plen) kbi, kbi_len, temp, 'B' + (c * 2), pss->session_id); } - explicit_bzero(temp, sizeof(temp)); + lws_explicit_bzero(temp, sizeof(temp)); return 0; diff --git a/plugins/ssh-base/sshd.c b/plugins/ssh-base/sshd.c index baa79e80e..7706b2960 100644 --- a/plugins/ssh-base/sshd.c +++ b/plugins/ssh-base/sshd.c @@ -86,16 +86,6 @@ lws_buf(uint8_t **p, void *s, uint32_t len) return 0; } - -void -explicit_bzero(void *p, size_t len) -{ - volatile uint8_t *vp = p; - - while (len--) - *vp++ = 0; -} - int lws_timingsafe_bcmp(const void *a, const void *b, uint32_t len) { @@ -402,7 +392,7 @@ lws_kex_destroy(struct per_session_data__sshd *pss) pss->kex->I_S = NULL; } - explicit_bzero(pss->kex, sizeof(*pss->kex)); + lws_explicit_bzero(pss->kex, sizeof(*pss->kex)); free(pss->kex); pss->kex = NULL; } @@ -436,11 +426,11 @@ lws_ua_destroy(struct per_session_data__sshd *pss) if (pss->ua->pubkey) ssh_free(pss->ua->pubkey); if (pss->ua->sig) { - explicit_bzero(pss->ua->sig, pss->ua->sig_len); + lws_explicit_bzero(pss->ua->sig, pss->ua->sig_len); ssh_free(pss->ua->sig); } - explicit_bzero(pss->ua, sizeof(*pss->ua)); + lws_explicit_bzero(pss->ua, sizeof(*pss->ua)); free(pss->ua); pss->ua = NULL; }