1
0
Fork 0
mirror of https://github.com/warmcat/libwebsockets.git synced 2025-03-09 00:00:04 +01:00

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.
This commit is contained in:
Andy Green 2018-12-04 08:03:58 +08:00
parent 440dacc992
commit ddb94d4e27
27 changed files with 1783 additions and 29 deletions

View file

@ -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"

View file

@ -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

View file

@ -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

View file

@ -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|

View file

@ -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

View file

@ -426,6 +426,7 @@ struct lws;
#include <libwebsockets/lws-jose.h>
#include <libwebsockets/lws-jws.h>
#include <libwebsockets/lws-genrsa.h>
#include <libwebsockets/lws-genaes.h>
#include <libwebsockets/lws-genec.h>
#endif

View file

@ -0,0 +1,161 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
*
* 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 <mbedtls/aes.h>
#include <mbedtls/gcm.h>
#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);
///@}

View file

@ -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,

View file

@ -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

View file

@ -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)

View file

@ -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" */,

View file

@ -0,0 +1,242 @@
/*
* libwebsockets - generic AES api hiding the backend
*
* Copyright (C) 2017 - 2018 Andy Green <andy@warmcat.com>
*
* 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;
}

View file

@ -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

View file

@ -0,0 +1,313 @@
/*
* libwebsockets - generic AES api hiding the backend
*
* Copyright (C) 2017 - 2018 Andy Green <andy@warmcat.com>
*
* 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;
}

View file

@ -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

View file

@ -50,11 +50,15 @@
#undef MBEDTLS_CONFIG_FILE
#define MBEDTLS_CONFIG_FILE <mbedtls/esp_config.h>
#include <mbedtls/ssl.h>
#include <mbedtls/aes.h>
#include <mbedtls/gcm.h>
#include <mbedtls/x509_crt.h>
#include "tls/mbedtls/wrapper/include/openssl/ssl.h" /* wrapper !!!! */
#else /* not esp32 */
#if defined(LWS_WITH_MBEDTLS)
#include <mbedtls/ssl.h>
#include <mbedtls/aes.h>
#include <mbedtls/gcm.h>
#include <mbedtls/x509_crt.h>
#include <mbedtls/x509_csr.h>
#include "tls/mbedtls/wrapper/include/openssl/ssl.h" /* wrapper !!!! */
@ -66,6 +70,7 @@
#include <openssl/sha.h>
#include <openssl/rsa.h>
#include <openssl/bn.h>
#include <openssl/aes.h>
#ifdef LWS_HAVE_OPENSSL_ECDH_H
#include <openssl/ecdh.h>
#endif

View file

@ -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 <libwebsockets.h>\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()

View file

@ -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 <loglevel>|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
```

View file

@ -0,0 +1,788 @@
/*
* lws-api-test-gencrypto - lws-genaes
*
* Copyright (C) 2018 Andy Green <andy@warmcat.com>
*
* This file is made available under the Creative Commons CC0 1.0
* Universal Public Domain Dedication.
*/
#include <libwebsockets.h>
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;
}

View file

@ -0,0 +1,45 @@
/*
* lws-api-test-gencrypto
*
* Copyright (C) 2018 Andy Green <andy@warmcat.com>
*
* This file is made available under the Creative Commons CC0 1.0
* Universal Public Domain Dedication.
*/
#include <libwebsockets.h>
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;
}

View file

@ -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

View file

@ -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()

View file

@ -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;
}

View file

@ -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);

View file

@ -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;

View file

@ -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;
}