diff --git a/CMakeLists.txt b/CMakeLists.txt index 45c7b7d8..0bb79357 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -693,15 +693,17 @@ endif() if (LWS_WITH_SSL) list(APPEND SOURCES - lib/tls/tls.c - lib/misc/lws-genhash.c) + lib/tls/tls.c) if (LWS_WITH_MBEDTLS) list(APPEND SOURCES - lib/tls/mbedtls/ssl.c) + lib/tls/mbedtls/ssl.c + lib/tls/mbedtls/lws-genhash.c) else() list(APPEND SOURCES - lib/tls/openssl/ssl.c) + lib/tls/openssl/ssl.c + lib/tls/openssl/lws-genhash.c + ) endif() if (NOT LWS_WITHOUT_SERVER) diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h index 103d99ce..39cb6011 100644 --- a/lib/libwebsockets.h +++ b/lib/libwebsockets.h @@ -1469,9 +1469,20 @@ lws_callback_function(struct lws *wsi, enum lws_callback_reasons reason, #include #endif -#define LWS_GENHASH_TYPE_SHA1 0 -#define LWS_GENHASH_TYPE_SHA256 1 -#define LWS_GENHASH_TYPE_SHA512 2 +enum lws_genhash_types { + LWS_GENHASH_TYPE_SHA1, + LWS_GENHASH_TYPE_SHA256, + LWS_GENHASH_TYPE_SHA384, + LWS_GENHASH_TYPE_SHA512, +}; + +enum lws_genhmac_types { + LWS_GENHMAC_TYPE_SHA256, + LWS_GENHMAC_TYPE_SHA384, + LWS_GENHMAC_TYPE_SHA512, +}; + +#define LWS_GENHASH_LARGEST 64 struct lws_genhash_ctx { uint8_t type; @@ -1479,7 +1490,8 @@ struct lws_genhash_ctx { union { mbedtls_sha1_context sha1; mbedtls_sha256_context sha256; - mbedtls_sha512_context sha512; + mbedtls_sha512_context sha512; /* 384 also uses this */ + const mbedtls_md_info_t *hmac; } u; #else const EVP_MD *evp_type; @@ -1487,6 +1499,17 @@ struct lws_genhash_ctx { #endif }; +struct lws_genhmac_ctx { + uint8_t type; +#if defined(LWS_WITH_MBEDTLS) + const mbedtls_md_info_t *hmac; + mbedtls_md_context_t ctx; +#else + const EVP_MD *evp_type; + EVP_MD_CTX *ctx; +#endif +}; + /** lws_genhash_size() - get hash size in bytes * * \param type: one of LWS_GENHASH_TYPE_... @@ -1494,7 +1517,16 @@ struct lws_genhash_ctx { * Returns number of bytes in this type of hash */ LWS_VISIBLE LWS_EXTERN size_t LWS_WARN_UNUSED_RESULT -lws_genhash_size(int type); +lws_genhash_size(enum lws_genhash_types type); + +/** lws_genhmac_size() - get hash size in bytes + * + * \param type: one of LWS_GENHASH_TYPE_... + * + * Returns number of bytes in this type of hmac + */ +LWS_VISIBLE LWS_EXTERN size_t LWS_WARN_UNUSED_RESULT +lws_genhmac_size(enum lws_genhmac_types type); /** lws_genhash_init() - prepare your struct lws_genhash_ctx for use * @@ -1504,7 +1536,7 @@ lws_genhash_size(int type); * Initializes the hash context for the type you requested */ LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT -lws_genhash_init(struct lws_genhash_ctx *ctx, int type); +lws_genhash_init(struct lws_genhash_ctx *ctx, enum lws_genhash_types type); /** lws_genhash_update() - digest len bytes of the buffer starting at in * @@ -1531,6 +1563,49 @@ lws_genhash_update(struct lws_genhash_ctx *ctx, const void *in, size_t len); LWS_VISIBLE LWS_EXTERN int lws_genhash_destroy(struct lws_genhash_ctx *ctx, void *result); +/** lws_genhmac_init() - prepare your struct lws_genhmac_ctx for use + * + * \param ctx: your struct lws_genhmac_ctx + * \param type: one of LWS_GENHMAC_TYPE_... + * \param key: pointer to the start of the HMAC key + * \param key_len: length of the HMAC key + * + * Initializes the hash context for the type you requested + * + * If the return is nonzero, it failed and there is nothing needing to be + * destroyed. + */ +int +lws_genhmac_init(struct lws_genhmac_ctx *ctx, enum lws_genhmac_types type, + const uint8_t *key, size_t key_len); + +/** lws_genhmac_update() - digest len bytes of the buffer starting at in + * + * \param ctx: your struct lws_genhmac_ctx + * \param in: start of the bytes to digest + * \param len: count of bytes to digest + * + * Updates the state of your hash context to reflect digesting len bytes from in + * + * If the return is nonzero, it failed and needs destroying. + */ +int +lws_genhmac_update(struct lws_genhmac_ctx *ctx, const void *in, size_t len); + +/** lws_genhmac_destroy() - copy out the result digest and destroy the ctx + * + * \param ctx: your struct lws_genhmac_ctx + * \param result: NULL, or where to copy the result hash + * + * Finalizes the hash and copies out the digest. Destroys any allocations such + * that ctx can safely go out of scope after calling this. + * + * NULL result is supported so that you can destroy the ctx cleanly on error + * conditions, where there is no valid result. + */ +int +lws_genhmac_destroy(struct lws_genhmac_ctx *ctx, void *result); + #endif ///@} diff --git a/lib/misc/lws-genhash.c b/lib/tls/mbedtls/lws-genhash.c similarity index 54% rename from lib/misc/lws-genhash.c rename to lib/tls/mbedtls/lws-genhash.c index 26bdb318..55a4a128 100644 --- a/lib/misc/lws-genhash.c +++ b/lib/tls/mbedtls/lws-genhash.c @@ -1,5 +1,5 @@ /* - * libwebsockets - small server side websockets and web server implementation + * libwebsockets - generic hash and HMAC api hiding the backend * * Copyright (C) 2017 Andy Green * @@ -18,19 +18,21 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA * - * lws_genhash provides a hash abstraction api in lws that works the same - * whether you are using openssl or mbedtls hash functions underneath. + * lws_genhash provides a hash / hmac abstraction api in lws that works the + * same whether you are using openssl or mbedtls hash functions underneath. */ #include "libwebsockets.h" size_t -lws_genhash_size(int type) +lws_genhash_size(enum lws_genhash_types type) { switch(type) { case LWS_GENHASH_TYPE_SHA1: return 20; case LWS_GENHASH_TYPE_SHA256: return 32; + case LWS_GENHASH_TYPE_SHA384: + return 48; case LWS_GENHASH_TYPE_SHA512: return 64; } @@ -39,11 +41,10 @@ lws_genhash_size(int type) } int -lws_genhash_init(struct lws_genhash_ctx *ctx, int type) +lws_genhash_init(struct lws_genhash_ctx *ctx, enum lws_genhash_types type) { ctx->type = type; -#if defined(LWS_WITH_MBEDTLS) switch (ctx->type) { case LWS_GENHASH_TYPE_SHA1: mbedtls_sha1_init(&ctx->u.sha1); @@ -53,6 +54,10 @@ lws_genhash_init(struct lws_genhash_ctx *ctx, int type) mbedtls_sha256_init(&ctx->u.sha256); mbedtls_sha256_starts(&ctx->u.sha256, 0); break; + case LWS_GENHASH_TYPE_SHA384: + mbedtls_sha512_init(&ctx->u.sha512); + mbedtls_sha512_starts(&ctx->u.sha512, 1 /* is384 */); + break; case LWS_GENHASH_TYPE_SHA512: mbedtls_sha512_init(&ctx->u.sha512); mbedtls_sha512_starts(&ctx->u.sha512, 0); @@ -60,39 +65,13 @@ lws_genhash_init(struct lws_genhash_ctx *ctx, int type) default: return 1; } -#else - ctx->mdctx = EVP_MD_CTX_create(); - if (!ctx->mdctx) - return 1; - switch (ctx->type) { - case LWS_GENHASH_TYPE_SHA1: - ctx->evp_type = EVP_sha1(); - break; - case LWS_GENHASH_TYPE_SHA256: - ctx->evp_type = EVP_sha256(); - break; - case LWS_GENHASH_TYPE_SHA512: - ctx->evp_type = EVP_sha512(); - break; - default: - return 1; - } - - if (EVP_DigestInit_ex(ctx->mdctx, ctx->evp_type, NULL) != 1) { - EVP_MD_CTX_destroy(ctx->mdctx); - - return 1; - } - -#endif return 0; } int lws_genhash_update(struct lws_genhash_ctx *ctx, const void *in, size_t len) { -#if defined(LWS_WITH_MBEDTLS) switch (ctx->type) { case LWS_GENHASH_TYPE_SHA1: mbedtls_sha1_update(&ctx->u.sha1, in, len); @@ -100,13 +79,13 @@ lws_genhash_update(struct lws_genhash_ctx *ctx, const void *in, size_t len) case LWS_GENHASH_TYPE_SHA256: mbedtls_sha256_update(&ctx->u.sha256, in, len); break; + case LWS_GENHASH_TYPE_SHA384: + mbedtls_sha512_update(&ctx->u.sha512, in, len); + break; case LWS_GENHASH_TYPE_SHA512: mbedtls_sha512_update(&ctx->u.sha512, in, len); break; } -#else - return EVP_DigestUpdate(ctx->mdctx, in, len) != 1; -#endif return 0; } @@ -114,7 +93,6 @@ lws_genhash_update(struct lws_genhash_ctx *ctx, const void *in, size_t len) int lws_genhash_destroy(struct lws_genhash_ctx *ctx, void *result) { -#if defined(LWS_WITH_MBEDTLS) switch (ctx->type) { case LWS_GENHASH_TYPE_SHA1: mbedtls_sha1_finish(&ctx->u.sha1, result); @@ -124,6 +102,10 @@ lws_genhash_destroy(struct lws_genhash_ctx *ctx, void *result) mbedtls_sha256_finish(&ctx->u.sha256, result); mbedtls_sha256_free(&ctx->u.sha256); break; + case LWS_GENHASH_TYPE_SHA384: + mbedtls_sha512_finish(&ctx->u.sha512, result); + mbedtls_sha512_free(&ctx->u.sha512); + break; case LWS_GENHASH_TYPE_SHA512: mbedtls_sha512_finish(&ctx->u.sha512, result); mbedtls_sha512_free(&ctx->u.sha512); @@ -131,19 +113,83 @@ lws_genhash_destroy(struct lws_genhash_ctx *ctx, void *result) } return 0; -#else - unsigned int len; - int ret = 0; - - if (result) - ret = EVP_DigestFinal_ex(ctx->mdctx, result, &len) != 1; - - (void)len; - - EVP_MD_CTX_destroy(ctx->mdctx); - - return ret; -#endif } +size_t +lws_genhmac_size(enum lws_genhmac_types type) +{ + switch(type) { + case LWS_GENHMAC_TYPE_SHA256: + return 32; + case LWS_GENHMAC_TYPE_SHA384: + return 48; + case LWS_GENHMAC_TYPE_SHA512: + return 64; + } + return 0; +} + +int +lws_genhmac_init(struct lws_genhmac_ctx *ctx, enum lws_genhmac_types type, + const uint8_t *key, size_t key_len) +{ + int t; + + ctx->type = type; + + switch (type) { + case LWS_GENHMAC_TYPE_SHA256: + t = MBEDTLS_MD_SHA256; + break; + case LWS_GENHMAC_TYPE_SHA384: + t = MBEDTLS_MD_SHA384; + break; + case LWS_GENHMAC_TYPE_SHA512: + t = MBEDTLS_MD_SHA512; + break; + default: + return -1; + } + + ctx->hmac = mbedtls_md_info_from_type(t); + if (!ctx->hmac) + return -1; + + if (mbedtls_md_init_ctx(&ctx->ctx, ctx->hmac)) + return -1; + + if (mbedtls_md_hmac_starts(&ctx->ctx, key, key_len)) { + mbedtls_md_free(&ctx->ctx); + ctx->hmac = NULL; + + return -1; + } + + return 0; +} + +int +lws_genhmac_update(struct lws_genhmac_ctx *ctx, const void *in, size_t len) +{ + if (mbedtls_md_hmac_update(&ctx->ctx, in, len)) + return -1; + + return 0; +} + +int +lws_genhmac_destroy(struct lws_genhmac_ctx *ctx, void *result) +{ + int n = 0; + + if (result) + n = mbedtls_md_hmac_finish(&ctx->ctx, result); + + mbedtls_md_free(&ctx->ctx); + ctx->hmac = NULL; + if (n) + return -1; + + return 0; +} diff --git a/lib/tls/openssl/lws-genhash.c b/lib/tls/openssl/lws-genhash.c new file mode 100644 index 00000000..df2ce46c --- /dev/null +++ b/lib/tls/openssl/lws-genhash.c @@ -0,0 +1,179 @@ +/* + * libwebsockets - generic hash and HMAC api hiding the backend + * + * Copyright (C) 2017 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_genhash provides a hash / hmac abstraction api in lws that works the + * same whether you are using openssl or mbedtls hash functions underneath. + */ +#include "libwebsockets.h" + +size_t +lws_genhash_size(enum lws_genhash_types type) +{ + switch(type) { + case LWS_GENHASH_TYPE_SHA1: + return 20; + case LWS_GENHASH_TYPE_SHA256: + return 32; + case LWS_GENHASH_TYPE_SHA384: + return 48; + case LWS_GENHASH_TYPE_SHA512: + return 64; + } + + return 0; +} + +int +lws_genhash_init(struct lws_genhash_ctx *ctx, enum lws_genhash_types type) +{ + ctx->type = type; + ctx->mdctx = EVP_MD_CTX_create(); + if (!ctx->mdctx) + return 1; + + switch (ctx->type) { + case LWS_GENHASH_TYPE_SHA1: + ctx->evp_type = EVP_sha1(); + break; + case LWS_GENHASH_TYPE_SHA256: + ctx->evp_type = EVP_sha256(); + break; + case LWS_GENHASH_TYPE_SHA384: + ctx->evp_type = EVP_sha384(); + break; + case LWS_GENHASH_TYPE_SHA512: + ctx->evp_type = EVP_sha512(); + break; + default: + return 1; + } + + if (EVP_DigestInit_ex(ctx->mdctx, ctx->evp_type, NULL) != 1) { + EVP_MD_CTX_destroy(ctx->mdctx); + + return 1; + } + + return 0; +} + +int +lws_genhash_update(struct lws_genhash_ctx *ctx, const void *in, size_t len) +{ + return EVP_DigestUpdate(ctx->mdctx, in, len) != 1; +} + +int +lws_genhash_destroy(struct lws_genhash_ctx *ctx, void *result) +{ + unsigned int len; + int ret = 0; + + if (result) + ret = EVP_DigestFinal_ex(ctx->mdctx, result, &len) != 1; + + (void)len; + + EVP_MD_CTX_destroy(ctx->mdctx); + + return ret; +} + +size_t +lws_genhmac_size(enum lws_genhmac_types type) +{ + switch(type) { + case LWS_GENHMAC_TYPE_SHA256: + return 32; + case LWS_GENHMAC_TYPE_SHA384: + return 48; + case LWS_GENHMAC_TYPE_SHA512: + return 64; + } + + return 0; +} + +int +lws_genhmac_init(struct lws_genhmac_ctx *ctx, enum lws_genhmac_types type, + const uint8_t *key, size_t key_len) +{ + const char *ts; + const EVP_MD *md; + EVP_PKEY *pkey; + + ctx->type = type; + + switch (type) { + case LWS_GENHMAC_TYPE_SHA256: + ts = "SHA256"; + break; + case LWS_GENHMAC_TYPE_SHA384: + ts = "SHA384"; + break; + case LWS_GENHMAC_TYPE_SHA512: + ts = "SHA512"; + break; + default: + return -1; + } + + ctx->ctx = EVP_MD_CTX_create(); + if (!ctx->ctx) + return -1; + + md = EVP_get_digestbyname(ts); + if (!md) + return -1; + + if (EVP_DigestInit_ex(ctx->ctx, md, NULL) != 1) + return -1; + + pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, key, key_len); + + if (EVP_DigestSignInit(ctx->ctx, NULL, md, NULL, pkey) != 1) + return -1; + + EVP_PKEY_free(pkey); + + return 0; +} + +int +lws_genhmac_update(struct lws_genhmac_ctx *ctx, const void *in, size_t len) +{ + if (EVP_DigestSignUpdate(ctx->ctx, in, len) != 1) + return -1; + + return 0; +} + +int +lws_genhmac_destroy(struct lws_genhmac_ctx *ctx, void *result) +{ + size_t size = lws_genhmac_size(ctx->type); + int n = EVP_DigestSignFinal(ctx->ctx, result, &size); + + EVP_MD_CTX_destroy(ctx->ctx); + if (n != 1) + return -1; + + return 0; +}