diff --git a/.travis.yml b/.travis.yml index ed642a5cb..d7fa222e2 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/ -DLWS_WITH_JWS=1 -DLWS_WITH_GENRSA=1 -DLWS_WITH_GENHASH=1 -DLWS_WITH_GENAES=1" + - 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 -DLWS_WITH_GENEC=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 2c932866b..088cb1c26 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -162,6 +162,8 @@ if(LWS_WITH_DISTRO_RECOMMENDED) set(LWS_WITH_GENHASH 1) set(LWS_WITH_GENRSA 1) set(LWS_WITH_GENEC 1) + set(LWS_WITH_JWS 1) + set(LWS_WITH_JWE 1) endif() # do you care about this? Then send me a patch where it disables it on travis @@ -299,6 +301,7 @@ if (LWS_WITH_ACME) set (LWS_WITHOUT_CLIENT 0) set (LWS_WITHOUT_SERVER 0) set (LWS_WITH_JWS 1) + set (LWS_WITH_JWE 1) endif() if (LWS_WITH_JWE) @@ -1039,9 +1042,15 @@ if (LWS_WITH_SSL) endif() if (LWS_WITH_GENEC) list(APPEND SOURCES + lib/tls/lws-genec-common.c lib/tls/mbedtls/lws-genec.c ) endif() + if (LWS_WITH_GENEC OR LWS_WITH_GENRSA) + list(APPEND SOURCES + lib/tls/mbedtls/lws-gencrypto.c + ) + endif() else() list(APPEND SOURCES lib/tls/openssl/ssl.c @@ -1063,9 +1072,15 @@ if (LWS_WITH_SSL) endif() if (LWS_WITH_GENEC) list(APPEND SOURCES + lib/tls/lws-genec-common.c lib/tls/openssl/lws-genec.c ) endif() + if (LWS_WITH_GENEC OR LWS_WITH_GENRSA) + list(APPEND SOURCES + lib/tls/openssl/lws-gencrypto.c + ) + endif() endif() if (NOT LWS_WITHOUT_SERVER) @@ -1232,6 +1247,11 @@ if (LWS_WITH_JWE) lib/jose/jwe/jwe.c) endif() +if (LWS_WITH_JWE OR LWS_WITH_JWS OR LWS_WITH_GENHASH) + list(APPEND SOURCES + lib/tls/lws-gencrypto-common.c) +endif() + # Add helper files for Windows. if (WIN32) set(WIN32_HELPERS_PATH win32port/win32helpers) @@ -1664,6 +1684,7 @@ CHECK_FUNCTION_EXISTS(SSL_set_alpn_protos LWS_HAVE_SSL_set_alpn_protos) CHECK_FUNCTION_EXISTS(SSL_CTX_set_ciphersuites LWS_HAVE_SSL_CTX_set_ciphersuites) if (LWS_WITH_SSL AND NOT LWS_WITH_MBEDTLS) CHECK_SYMBOL_EXISTS(SSL_CTX_get_extra_chain_certs_only openssl/ssl.h LWS_HAVE_SSL_EXTRA_CHAIN_CERTS) +CHECK_FUNCTION_EXISTS(EVP_MD_CTX_free LWS_HAVE_EVP_MD_CTX_free) endif() if (LWS_WITH_MBEDTLS) set(LWS_HAVE_TLS_CLIENT_METHOD 1) diff --git a/README.md b/README.md index 4e438006c..958641f70 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,9 @@ News ## New features on master - - **`lws_genrsa` OAEP + PSS support** - in addition to PKCS#1 1.5 padding, OAEP and PSS are + - **`lws-genec` ECDH + ECDSA** - Work in progress + + - **`lws-genrsa` OAEP + PSS support** - in addition to PKCS#1 1.5 padding, OAEP and PSS are now supported on both mbedtls and openssl backends. - **`lws-genaes` Generic AES crypto** - thin api layer works identically with both mbedtls and openssl diff --git a/READMEs/README.crypto-apis.md b/READMEs/README.crypto-apis.md index e82a6980a..c8a067756 100644 --- a/READMEs/README.crypto-apis.md +++ b/READMEs/README.crypto-apis.md @@ -24,6 +24,8 @@ 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| +|genec|`LWS_WITH_GENEC`|[./include/libwebsockets/lws-genec.h](https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/lws-genec.h)|Provides Elliptic Curve for encryption, decryption, signing, verification, key generation and creation| + 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) diff --git a/cmake/lws_config.h.in b/cmake/lws_config.h.in index a0ae900dd..7c50c29d1 100644 --- a/cmake/lws_config.h.in +++ b/cmake/lws_config.h.in @@ -23,6 +23,7 @@ #cmakedefine LWS_HAS_INTPTR_T #cmakedefine LWS_HAVE__ATOI64 #cmakedefine LWS_HAVE_ATOLL +#cmakedefine LWS_HAVE_EVP_MD_CTX_free #cmakedefine LWS_HAVE_LIBCAP #cmakedefine LWS_HAVE_MALLOC_H #cmakedefine LWS_HAVE_NEW_UV_VERSION_H @@ -73,6 +74,7 @@ #cmakedefine LWS_WITH_GENRSA #cmakedefine LWS_WITH_GENHASH #cmakedefine LWS_WITH_GENAES +#cmakedefine LWS_WITH_GENEC #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 0052bcbd9..78491a76b 100644 --- a/include/libwebsockets.h +++ b/include/libwebsockets.h @@ -421,14 +421,17 @@ struct lws; #include #endif +#include #include -#include -#include -#include #include #include #include +#include +#include +#include +#include + #endif #ifdef __cplusplus diff --git a/include/libwebsockets/lws-genaes.h b/include/libwebsockets/lws-genaes.h index 5ea734eb7..1e7c3cdcd 100644 --- a/include/libwebsockets/lws-genaes.h +++ b/include/libwebsockets/lws-genaes.h @@ -73,7 +73,7 @@ struct lws_genaes_ctx { char init; #endif unsigned char tag[16]; - struct lws_jwk_elements *k; + struct lws_gencrypto_keyelem *k; enum enum_aes_operation op; enum enum_aes_modes mode; int taglen; @@ -98,7 +98,7 @@ struct lws_genaes_ctx { */ 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, + enum enum_aes_modes mode, struct lws_gencrypto_keyelem *el, int padding, void *engine); /** lws_genaes_destroy() - Destroy genaes AES context diff --git a/include/libwebsockets/lws-gencrypto.h b/include/libwebsockets/lws-gencrypto.h new file mode 100644 index 000000000..ab47ca15f --- /dev/null +++ b/include/libwebsockets/lws-gencrypto.h @@ -0,0 +1,94 @@ +/* + * 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 + */ + +/* + * These are gencrypto-level constants... they are used by both JOSE and direct + * gencrypto code. However while JWK relies on these, using gencrypto apis has + * no dependency at all on any JOSE type. + */ + +enum lws_gencrypto_kyt { + LWS_GENCRYPTO_KYT_UNKNOWN, + + LWS_GENCRYPTO_KYT_OCT, + LWS_GENCRYPTO_KYT_RSA, + LWS_GENCRYPTO_KYT_EC +}; + +/* + * Keytypes where the same element name is reused must all agree to put the + * same-named element at the same e[] index. It's because when used with jwk, + * we parse and store in incoming key data, but we may not be informed of the + * definitive keytype until the end. + */ + +enum lws_gencrypto_oct_tok { + LWS_GENCRYPTO_OCT_KEYEL_K, /* note... same offset as AES K */ + + LWS_GENCRYPTO_OCT_KEYEL_COUNT +}; + +enum lws_gencrypto_rsa_tok { + LWS_GENCRYPTO_RSA_KEYEL_E, + LWS_GENCRYPTO_RSA_KEYEL_N, + LWS_GENCRYPTO_RSA_KEYEL_D, /* note... same offset as EC D */ + LWS_GENCRYPTO_RSA_KEYEL_P, + LWS_GENCRYPTO_RSA_KEYEL_Q, + LWS_GENCRYPTO_RSA_KEYEL_DP, + LWS_GENCRYPTO_RSA_KEYEL_DQ, + LWS_GENCRYPTO_RSA_KEYEL_QI, + + LWS_GENCRYPTO_RSA_KEYEL_COUNT +}; + +enum lws_gencrypto_ec_tok { + LWS_GENCRYPTO_EC_KEYEL_CRV, + LWS_GENCRYPTO_EC_KEYEL_X, + /* note... same offset as RSA D */ + LWS_GENCRYPTO_EC_KEYEL_D = LWS_GENCRYPTO_RSA_KEYEL_D, + LWS_GENCRYPTO_EC_KEYEL_Y, + + LWS_GENCRYPTO_EC_KEYEL_COUNT +}; + +enum lws_gencrypto_aes_tok { + /* note... same offset as OCT K */ + LWS_GENCRYPTO_AES_KEYEL_K = LWS_GENCRYPTO_OCT_KEYEL_K, + + LWS_GENCRYPTO_AES_KEYEL_COUNT +}; + +/* largest number of key elements for any algorithm */ +#define LWS_GENCRYPTO_MAX_KEYEL_COUNT LWS_GENCRYPTO_RSA_KEYEL_COUNT + +/* this "stretchy" type holds individual key element data in binary form. + * It's typcially used in an array with the layout mapping the element index to + * the key element meaning defined by the enums above. An array of these of + * length LWS_GENCRYPTO_MAX_KEYEL_COUNT can define key elements for any key + * type. + */ + +struct lws_gencrypto_keyelem { + uint8_t *buf; + uint16_t len; +}; diff --git a/include/libwebsockets/lws-genec.h b/include/libwebsockets/lws-genec.h index 38bd9c851..cd4fb0ac3 100644 --- a/include/libwebsockets/lws-genec.h +++ b/include/libwebsockets/lws-genec.h @@ -1,7 +1,7 @@ /* * libwebsockets - Generic Elliptic Curve Encryption * - * Copyright (C) 2010-2018 Andy Green + * 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 @@ -21,14 +21,177 @@ * included from libwebsockets.h */ -/* include/libwebsockets/lws-jwk.h must be included before this */ +enum enum_genec_alg { + LEGENEC_UNKNOWN, + + LEGENEC_ECDH, + LEGENEC_ECDSA +}; struct lws_genec_ctx { #if defined(LWS_WITH_MBEDTLS) - mbedtls_rsa_context *ctx; + union { + mbedtls_ecdh_context *ctx_ecdh; + mbedtls_ecdsa_context *ctx_ecdsa; + } u; #else - BIGNUM *bn[LWS_COUNT_EC_KEY_ELEMENTS]; - RSA *rsa; + EVP_PKEY_CTX *ctx; + EVP_PKEY_CTX *ctx_peer; #endif + struct lws_context *context; + const struct lws_ec_curves *curve_table; + enum enum_genec_alg genec_alg; }; +#if defined(LWS_WITH_MBEDTLS) +enum enum_lws_dh_side { + LDHS_OURS = MBEDTLS_ECDH_OURS, + LDHS_THEIRS = MBEDTLS_ECDH_THEIRS +}; +#else +enum enum_lws_dh_side { + LDHS_OURS, + LDHS_THEIRS +}; +#endif + +struct lws_ec_curves { + const char *name; + int tls_lib_nid; + short key_bytes; +}; + + +/* ECDH-specific apis */ + +/** lws_genecdh_create() - Create a genecdh + * + * \param ctx: your genec context + * \param context: your lws_context (for RNG access) + * \param curve_table: NULL, enabling P-256, P-384 and P-521, or a replacement + * struct lws_ec_curves array, terminated by an entry with + * .name = NULL, of curves you want to whitelist + * + * Initializes a genecdh + */ +LWS_VISIBLE int +lws_genecdh_create(struct lws_genec_ctx *ctx, struct lws_context *context, + const struct lws_ec_curves *curve_table); + +/** lws_genecdh_set_key() - Apply an EC key to our or theirs side + * + * \param ctx: your genecdh context + * \param el: your key elements + * \param side: LDHS_OURS or LDHS_THEIRS + * + * Applies an EC key to one side or the other of an ECDH ctx + */ +LWS_VISIBLE LWS_EXTERN int +lws_genecdh_set_key(struct lws_genec_ctx *ctx, struct lws_gencrypto_keyelem *el, + enum enum_lws_dh_side side); + +/** lws_genecdh_new_keypair() - Create a genec with a new public / private key + * + * \param ctx: your genec context + * \param side: LDHS_OURS or LDHS_THEIRS + * \param curve_name: an EC curve name, like "P-256" + * \param el: array pf LWS_GENCRYPTO_EC_KEYEL_COUNT key elems to take the new key + * + * Creates a genecdh with a newly minted EC public / private key + */ +LWS_VISIBLE LWS_EXTERN int +lws_genecdh_new_keypair(struct lws_genec_ctx *ctx, enum enum_lws_dh_side side, + const char *curve_name, struct lws_gencrypto_keyelem *el); + + +/* ECDSA-specific apis */ + +/** lws_genecdsa_create() - Create a genecdsa and + * + * \param ctx: your genec context + * \param context: your lws_context (for RNG access) + * \param curve_table: NULL, enabling P-256, P-384 and P-521, or a replacement + * struct lws_ec_curves array, terminated by an entry with + * .name = NULL, of curves you want to whitelist + * + * Initializes a genecdh + */ +LWS_VISIBLE int +lws_genecdsa_create(struct lws_genec_ctx *ctx, struct lws_context *context, + const struct lws_ec_curves *curve_table); + +/** lws_genecdsa_new_keypair() - Create a genecdsa with a new public / private key + * + * \param ctx: your genec context + * \param curve_name: an EC curve name, like "P-256" + * \param el: array pf LWS_GENCRYPTO_EC_KEYEL_COUNT key elements to take the new key + * + * Creates a genecdsa with a newly minted EC public / private key + */ +LWS_VISIBLE LWS_EXTERN int +lws_genecdsa_new_keypair(struct lws_genec_ctx *ctx, const char *curve_name, + struct lws_gencrypto_keyelem *el); + +/** lws_genecdsa_set_key() - Apply an EC key to an ecdsa context + * + * \param ctx: your genecdsa context + * \param el: your key elements + * + * Applies an EC key to an ecdsa context + */ +LWS_VISIBLE LWS_EXTERN int +lws_genecdsa_set_key(struct lws_genec_ctx *ctx, + struct lws_gencrypto_keyelem *el); + +/** lws_genecdsa_hash_sig_verify() - Verifies ECDSA signature on a given hash + * + * \param ctx: your struct lws_genrsa_ctx + * \param in: unencrypted payload (usually a recomputed hash) + * \param hash_type: one of LWS_GENHASH_TYPE_ + * \param sig: pointer to the signature we received with the payload + * \param sig_len: length of the signature we are checking in bytes + * + * This just looks at the signed hash... that's why there's no input length + * parameter, it's decided by the choice of hash. It's up to you to confirm + * separately the actual payload matches the hash that was confirmed by this to + * be validly signed. + * + * Returns <0 for error, or 0 if signature matches the hash + key.. + * + * This and related APIs operate identically with OpenSSL or mbedTLS backends. + */ +LWS_VISIBLE LWS_EXTERN int +lws_genecdsa_hash_sig_verify(struct lws_genec_ctx *ctx, const uint8_t *in, + enum lws_genhash_types hash_type, + const uint8_t *sig, size_t sig_len); + +/** lws_genecdsa_hash_sign() - Creates an ECDSA signature for a hash you provide + * + * \param ctx: your struct lws_genrsa_ctx + * \param in: precomputed hash + * \param hash_type: one of LWS_GENHASH_TYPE_ + * \param sig: pointer to buffer to take signature + * \param sig_len: length of the buffer (must be >= length of key N) + * + * Returns <0 for error, or 0 for success. + * + * This creates an ECDSA signature for a hash you already computed and provide. + * + * This and related APIs operate identically with OpenSSL or mbedTLS backends. + */ +LWS_VISIBLE LWS_EXTERN int +lws_genecdsa_hash_sign(struct lws_genec_ctx *ctx, const uint8_t *in, + enum lws_genhash_types hash_type, uint8_t *sig, + size_t sig_len); + + +/* Apis that apply to both ECDH and ECDSA */ + +LWS_VISIBLE LWS_EXTERN void +lws_genec_destroy(struct lws_genec_ctx *ctx); + +LWS_VISIBLE LWS_EXTERN void +lws_genec_destroy_elements(struct lws_gencrypto_keyelem *el); + +LWS_VISIBLE LWS_EXTERN int +lws_genec_dump(struct lws_gencrypto_keyelem *el); diff --git a/include/libwebsockets/lws-genhash.h b/include/libwebsockets/lws-genhash.h index a2e4f8ab6..af8e31b01 100644 --- a/include/libwebsockets/lws-genhash.h +++ b/include/libwebsockets/lws-genhash.h @@ -25,7 +25,7 @@ * ## Generic Hash related functions * * Lws provides generic hash / digest accessors that abstract the ones - * provided by whatever OpenSSL library you are linking against. + * 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. @@ -33,6 +33,7 @@ ///@{ enum lws_genhash_types { + LWS_GENHASH_TYPE_UNKNOWN, LWS_GENHASH_TYPE_SHA1, LWS_GENHASH_TYPE_SHA256, LWS_GENHASH_TYPE_SHA384, @@ -40,6 +41,7 @@ enum lws_genhash_types { }; enum lws_genhmac_types { + LWS_GENHMAC_TYPE_UNKNOWN, LWS_GENHMAC_TYPE_SHA256, LWS_GENHMAC_TYPE_SHA384, LWS_GENHMAC_TYPE_SHA512, diff --git a/include/libwebsockets/lws-genrsa.h b/include/libwebsockets/lws-genrsa.h index d4f37b550..0f233791d 100644 --- a/include/libwebsockets/lws-genrsa.h +++ b/include/libwebsockets/lws-genrsa.h @@ -45,7 +45,7 @@ struct lws_genrsa_ctx { #if defined(LWS_WITH_MBEDTLS) mbedtls_rsa_context *ctx; #else - BIGNUM *bn[LWS_COUNT_RSA_KEY_ELEMENTS]; + BIGNUM *bn[LWS_GENCRYPTO_RSA_KEYEL_COUNT]; EVP_PKEY_CTX *ctx; RSA *rsa; #endif @@ -53,11 +53,11 @@ struct lws_genrsa_ctx { enum enum_genrsa_mode mode; }; -/** lws_jwk_destroy_genrsa_elements() - Free allocations in genrsa_elements +/** lws_genrsa_destroy_elements() - Free allocations in genrsa_elements * - * \param el: your struct lws_jwk_elements + * \param el: your struct lws_gencrypto_keyelem * - * This is a helper for user code making use of struct lws_jwk_elements + * This is a helper for user code making use of struct lws_gencrypto_keyelem * where the elements are allocated on the heap, it frees any non-NULL * buf element and sets the buf to NULL. * @@ -65,7 +65,7 @@ struct lws_genrsa_ctx { * creation and destruction themselves. */ LWS_VISIBLE LWS_EXTERN void -lws_jwk_destroy_genrsa_elements(struct lws_jwk_elements *el); +lws_genrsa_destroy_elements(struct lws_gencrypto_keyelem *el); /** lws_genrsa_public_decrypt_create() - Create RSA public decrypt context * @@ -85,7 +85,7 @@ lws_jwk_destroy_genrsa_elements(struct lws_jwk_elements *el); * This and related APIs operate identically with OpenSSL or mbedTLS backends. */ LWS_VISIBLE LWS_EXTERN int -lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_jwk_elements *el, +lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_gencrypto_keyelem *el, struct lws_context *context, enum enum_genrsa_mode mode); /** lws_genrsa_new_keypair() - Create new RSA keypair @@ -108,7 +108,7 @@ lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_jwk_elements *el, */ LWS_VISIBLE LWS_EXTERN int lws_genrsa_new_keypair(struct lws_context *context, struct lws_genrsa_ctx *ctx, - enum enum_genrsa_mode mode, struct lws_jwk_elements *el, + enum enum_genrsa_mode mode, struct lws_gencrypto_keyelem *el, int bits); /** lws_genrsa_public_encrypt() - Perform RSA public encryption @@ -146,39 +146,48 @@ LWS_VISIBLE LWS_EXTERN int lws_genrsa_public_decrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in, size_t in_len, uint8_t *out, size_t out_max); -/** lws_genrsa_public_verify() - Perform RSA public verification +/** lws_genrsa_hash_sig_verify() - Verifies RSA signature on a given hash * * \param ctx: your struct lws_genrsa_ctx - * \param in: unencrypted payload (usually a recomputed hash) + * \param in: input to be hashed * \param hash_type: one of LWS_GENHASH_TYPE_ * \param sig: pointer to the signature we received with the payload * \param sig_len: length of the signature we are checking in bytes * * Returns <0 for error, or 0 if signature matches the payload + key. * + * This just looks at a hash... that's why there's no input length + * parameter, it's decided by the choice of hash. It's up to you to confirm + * separately the actual payload matches the hash that was confirmed by this to + * be validly signed. + * * This and related APIs operate identically with OpenSSL or mbedTLS backends. */ LWS_VISIBLE LWS_EXTERN int -lws_genrsa_public_verify(struct lws_genrsa_ctx *ctx, const uint8_t *in, - enum lws_genhash_types hash_type, - const uint8_t *sig, size_t sig_len); +lws_genrsa_hash_sig_verify(struct lws_genrsa_ctx *ctx, const uint8_t *in, + enum lws_genhash_types hash_type, + const uint8_t *sig, size_t sig_len); -/** lws_genrsa_public_sign() - Create RSA signature +/** lws_genrsa_hash_sign() - Creates an ECDSA signature for a hash you provide * * \param ctx: your struct lws_genrsa_ctx - * \param in: precomputed hash + * \param in: input to be hashed and signed * \param hash_type: one of LWS_GENHASH_TYPE_ * \param sig: pointer to buffer to take signature * \param sig_len: length of the buffer (must be >= length of key N) * * Returns <0 for error, or 0 for success. * + * This creates an RSA signature for a hash you already computed and provide. + * You should have created the hash before calling this by iterating over the + * actual payload you need to confirm. + * * This and related APIs operate identically with OpenSSL or mbedTLS backends. */ LWS_VISIBLE LWS_EXTERN int -lws_genrsa_public_sign(struct lws_genrsa_ctx *ctx, const uint8_t *in, - enum lws_genhash_types hash_type, uint8_t *sig, - size_t sig_len); +lws_genrsa_hash_sign(struct lws_genrsa_ctx *ctx, const uint8_t *in, + enum lws_genhash_types hash_type, + uint8_t *sig, size_t sig_len); /** lws_genrsa_public_decrypt_destroy() - Destroy RSA public decrypt context * diff --git a/include/libwebsockets/lws-jose.h b/include/libwebsockets/lws-jose.h index a46af795e..370afeae7 100644 --- a/include/libwebsockets/lws-jose.h +++ b/include/libwebsockets/lws-jose.h @@ -51,21 +51,45 @@ enum lws_jws_jose_hdr_indexes { struct lws_jose { /* jose header elements */ - struct lws_jwk_elements e[LWS_COUNT_JOSE_HDR_ELEMENTS]; + struct lws_gencrypto_keyelem e[LWS_COUNT_JOSE_HDR_ELEMENTS]; }; -enum lws_jws_algtype { - LWS_JWK_ENCTYPE_NONE, - LWS_JWK_ENCTYPE_RSASSA, - LWS_JWK_ENCTYPE_EC +enum lws_jose_algtype { + LWS_JOSE_ENCTYPE_NONE, + + LWS_JOSE_ENCTYPE_RSASSA_PKCS1_1_5, + LWS_JOSE_ENCTYPE_RSASSA_PKCS1_OAEP, + LWS_JOSE_ENCTYPE_RSASSA_PKCS1_PSS, + + LWS_JOSE_ENCTYPE_ECDSA, + + LWS_JOSE_ENCTYPE_AES_CBC, + LWS_JOSE_ENCTYPE_AES_CFB128, + LWS_JOSE_ENCTYPE_AES_CFB8, + LWS_JOSE_ENCTYPE_AES_CTR, + LWS_JOSE_ENCTYPE_AES_ECB, + LWS_JOSE_ENCTYPE_AES_OFB, + LWS_JOSE_ENCTYPE_AES_XTS, /* care... requires double-length key */ + LWS_JOSE_ENCTYPE_AES_GCM, }; -struct cb_hdr_s { +struct lws_jose_jwe_alg { enum lws_genhash_types hash_type; enum lws_genhmac_types hmac_type; - char alg[24]; /* for jwe, the JWA enc alg name, eg "ECDH-ES" */ - char curve[16]; - enum lws_jws_algtype algtype; /* for jws, the signing cipher */ - - char is_jwe; + enum lws_jose_algtype algtype_signing; /* the signing cipher */ + enum lws_jose_algtype algtype_crypto; /* the encryption cipher */ + const char *alg; /* the JWA enc alg name, eg "ES512" */ + const char *curve_name; /* NULL, or, eg, "P-256" */ }; + +LWS_VISIBLE LWS_EXTERN int +lws_gencrypto_jws_alg_to_definition(const char *alg, + const struct lws_jose_jwe_alg **jose); + +LWS_VISIBLE LWS_EXTERN int +lws_gencrypto_jwe_alg_to_definition(const char *alg, + const struct lws_jose_jwe_alg **jose); + +LWS_VISIBLE LWS_EXTERN int +lws_gencrypto_jwe_enc_to_definition(const char *enc, + const struct lws_jose_jwe_alg **jose); diff --git a/include/libwebsockets/lws-jwe.h b/include/libwebsockets/lws-jwe.h index d5227c9fc..1422a27bd 100644 --- a/include/libwebsockets/lws-jwe.h +++ b/include/libwebsockets/lws-jwe.h @@ -20,3 +20,30 @@ * * included from libwebsockets.h */ + +/** + * lws_jwe_create_packet() - add b64 sig to b64 hdr + payload + * + * \param jwk: the struct lws_jwk containing the signing key + * \param algtype: the signing algorithm + * \param hash_type: the hashing algorithm + * \param payload: unencoded payload JSON + * \param len: length of unencoded payload JSON + * \param nonce: Nonse string to include in protected header + * \param out: buffer to take signed packet + * \param out_len: size of \p out buffer + * \param conext: lws_context to get random from + * + * This creates a "flattened" JWS packet from the jwk and the plaintext + * payload, and signs it. The packet is written into \p out. + * + * This does the whole packet assembly and signing, calling through to + * lws_jws_sign_from_b64() as part of the process. + * + * Returns the length written to \p out, or -1. + */ +LWS_VISIBLE LWS_EXTERN int +lws_jwe_create_packet(struct lws_jwk *jwk, + const struct lws_jose_jwe_alg *jose_alg, + const char *payload, size_t len, const char *nonce, + char *out, size_t out_len, struct lws_context *context); diff --git a/include/libwebsockets/lws-jwk.h b/include/libwebsockets/lws-jwk.h index 5dd0e777b..6cf159647 100644 --- a/include/libwebsockets/lws-jwk.h +++ b/include/libwebsockets/lws-jwk.h @@ -1,7 +1,7 @@ /* * libwebsockets - small server side websockets and web server implementation * - * Copyright (C) 2010-2018 Andy Green + * 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 @@ -21,68 +21,20 @@ * included from libwebsockets.h */ - /*! \defgroup jwk JSON Web Keys * ## JSON Web Keys API * - * Lws provides an API to parse JSON Web Keys into a struct lws_jwk_elements. + * Lws provides an API to parse JSON Web Keys into a struct lws_gencrypto_keyelem. * * "oct" and "RSA" type keys are supported. For "oct" keys, they are held in - * the "e" member of the struct lws_jwk_elements. + * the "e" member of the struct lws_gencrypto_keyelem. * * Keys elements are allocated on the heap. You must destroy the allocations - * in the struct lws_jwk_elements by calling - * lws_jwk_destroy_genrsa_elements() when you are finished with it. + * in the struct lws_gencrypto_keyelem by calling + * lws_genrsa_destroy_elements() when you are finished with it. */ ///@{ -enum lws_jwk_kyt { - LWS_JWK_KYT_UNKNOWN, - LWS_JWK_KYT_OCT, - LWS_JWK_KYT_RSA, - LWS_JWK_KYT_EC -}; - -/* - * Keytypes where the same element name is reused must all agree to put the - * same-named element at the same e[] index. It's because we may not know the - * keytype until the end. - */ - -enum enum_jwk_oct_tok { - JWK_OCT_KEYEL_K, - - LWS_COUNT_OCT_KEY_ELEMENTS -}; - -enum enum_jwk_rsa_tok { - JWK_RSA_KEYEL_E, - JWK_RSA_KEYEL_N, - JWK_RSA_KEYEL_D, /* note... same offset as EC D */ - JWK_RSA_KEYEL_P, - JWK_RSA_KEYEL_Q, - JWK_RSA_KEYEL_DP, - JWK_RSA_KEYEL_DQ, - JWK_RSA_KEYEL_QI, - - LWS_COUNT_RSA_KEY_ELEMENTS -}; - -enum enum_jwk_ec_tok { - JWK_EC_KEYEL_CRV, - JWK_EC_KEYEL_X, - 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, @@ -94,19 +46,11 @@ enum enum_jwk_meta_tok { LWS_COUNT_JWK_ELEMENTS }; -/* largest number of key elements for any algorithm */ -#define LWS_COUNT_ALG_KEY_ELEMENTS_MAX LWS_COUNT_RSA_KEY_ELEMENTS - -struct lws_jwk_elements { - uint8_t *buf; - uint16_t len; -}; - struct lws_jwk { /* key data elements */ - struct lws_jwk_elements e[LWS_COUNT_ALG_KEY_ELEMENTS_MAX]; + struct lws_gencrypto_keyelem e[LWS_GENCRYPTO_MAX_KEYEL_COUNT]; /* generic meta key elements, like KID */ - struct lws_jwk_elements meta[LWS_COUNT_JWK_ELEMENTS]; + struct lws_gencrypto_keyelem meta[LWS_COUNT_JWK_ELEMENTS]; int kty; /**< one of LWS_JWK_ */ }; @@ -180,7 +124,7 @@ lws_jwk_export(struct lws_jwk *s, int _private, char *p, size_t len); * turn while it return 0 (nonzero return from the callback terminates the * iteration through any further keys, leaving the last one in s). */ -LWS_VISIBLE int +LWS_VISIBLE LWS_EXTERN int lws_jwk_load(struct lws_jwk *s, const char *filename, lws_jwk_key_import_callback cb, void *user); @@ -191,7 +135,7 @@ lws_jwk_load(struct lws_jwk *s, const char *filename, * * Returns 0 for OK or -1 for failure */ -LWS_VISIBLE int +LWS_VISIBLE LWS_EXTERN int lws_jwk_save(struct lws_jwk *s, const char *filename); /** lws_jwk_rfc7638_fingerprint() - jwk to RFC7638 compliant fingerprint @@ -201,6 +145,9 @@ lws_jwk_save(struct lws_jwk *s, const char *filename); * * Returns 0 for OK or -1 for failure */ -LWS_VISIBLE int +LWS_VISIBLE LWS_EXTERN int lws_jwk_rfc7638_fingerprint(struct lws_jwk *s, char *digest32); + +LWS_VISIBLE LWS_EXTERN int +lws_jwk_dump(struct lws_jwk *s); ///@} diff --git a/include/libwebsockets/lws-jws.h b/include/libwebsockets/lws-jws.h index 3485146d5..f7d0c13a3 100644 --- a/include/libwebsockets/lws-jws.h +++ b/include/libwebsockets/lws-jws.h @@ -64,31 +64,8 @@ lws_jws_confirm_sig(const char *in, size_t len, struct lws_jwk *jwk, LWS_VISIBLE LWS_EXTERN int lws_jws_sign_from_b64(const char *b64_hdr, size_t hdr_len, const char *b64_pay, size_t pay_len, char *b64_sig, size_t sig_len, - enum lws_genhash_types hash_type, struct lws_jwk *jwk, - struct lws_context *context); - -/** - * lws_jws_create_packet() - add b64 sig to b64 hdr + payload - * - * \param jwk: the struct lws_jwk containing the signing key - * \param payload: unencoded payload JSON - * \param len: length of unencoded payload JSON - * \param nonce: Nonse string to include in protected header - * \param out: buffer to take signed packet - * \param out_len: size of \p out buffer - * \param conext: lws_context to get random from - * - * This creates a "flattened" JWS packet from the jwk and the plaintext - * payload, and signs it. The packet is written into \p out. - * - * This does the whole packet assembly and signing, calling through to - * lws_jws_sign_from_b64() as part of the process. - * - * Returns the length written to \p out, or -1. - */ -LWS_VISIBLE LWS_EXTERN int -lws_jws_create_packet(struct lws_jwk *jwk, const char *payload, size_t len, - const char *nonce, char *out, size_t out_len, + const struct lws_jose_jwe_alg *args, + struct lws_jwk *jwk, struct lws_context *context); /** diff --git a/lib/jose/README.md b/lib/jose/README.md index cf7284f39..7473c5b82 100644 --- a/lib/jose/README.md +++ b/lib/jose/README.md @@ -20,8 +20,21 @@ useful implementations of JWS, JWE and JWK. ## Supported algorithms -Symmetric ciphers are not currently supported... symmetric keys and HMAC -are supported though. +### Supported keys + + - All RFC7517 / JWK forms: octet, RSA and EC + + - singleton and keys[] arrays of keys supported + +### Symmetric ciphers + + - All common AES varaiants: CBC, CFB128, CFB8, CTR, EVB, OFB and XTS + +### Asymmetric ciphers + + - RSA + + - EC (P-256, P-384 and P521 JWA curves) For the required and recommended asymmetric algorithms, support currently looks like this diff --git a/lib/jose/jwe/jwe.c b/lib/jose/jwe/jwe.c index cc7c9c82d..ec0510b3b 100644 --- a/lib/jose/jwe/jwe.c +++ b/lib/jose/jwe/jwe.c @@ -25,3 +25,96 @@ */ #include "core/private.h" + +LWS_VISIBLE int +lws_jwe_create_packet(struct lws_jwk *jwk, + const struct lws_jose_jwe_alg *jose_alg, + const char *payload, size_t len, + const char *nonce, char *out, size_t out_len, + struct lws_context *context) +{ + char *buf, *start, *p, *end, *p1, *end1, *b64_hdr, *b64_pay; + int n, b64_hdr_len, b64_pay_len; + + /* + * This buffer is local to the function, the actual output + * is prepared into vhd->buf. Only the plaintext protected header + * (which contains the public key, 512 bytes for 4096b) goes in + * here temporarily. + */ + n = LWS_PRE + 2048; + buf = malloc(n); + if (!buf) { + lwsl_notice("%s: malloc %d failed\n", __func__, n); + return -1; + } + + p = start = buf + LWS_PRE; + end = buf + n - LWS_PRE - 1; + + /* + * temporary JWS protected header plaintext + */ + + p += lws_snprintf(p, end - p, "{\"alg\":\"RS256\",\"jwk\":"); + n = lws_jwk_export(jwk, 0, p, end - p); + if (n < 0) { + lwsl_notice("failed to export jwk\n"); + + goto bail; + } + p += n; + p += lws_snprintf(p, end - p, ",\"nonce\":\"%s\"}", nonce); + + /* + * prepare the signed outer JSON with all the parts in + */ + + p1 = out; + end1 = out + out_len - 1; + + p1 += lws_snprintf(p1, end1 - p1, "{\"protected\":\""); + b64_hdr = p1; + n = lws_jws_base64_enc(start, p - start, p1, end1 - p1); + if (n < 0) { + lwsl_notice("%s: failed to encode protected\n", __func__); + goto bail; + } + b64_hdr_len = n; + p1 += n; + + p1 += lws_snprintf(p1, end1 - p1, "\",\"payload\":\""); + b64_pay = p1; + n = lws_jws_base64_enc(payload, len, p1, end1 - p1); + if (n < 0) { + lwsl_notice("%s: failed to encode payload\n", __func__); + goto bail; + } + b64_pay_len = n; + + p1 += n; + p1 += lws_snprintf(p1, end1 - p1, "\",\"signature\":\""); + + /* + * taking the b64 protected header and the b64 payload, sign them + * and place the signature into the packet + */ + n = lws_jws_sign_from_b64(b64_hdr, b64_hdr_len, b64_pay, b64_pay_len, + p1, end1 - p1, jose_alg, jwk, context); + if (n < 0) { + lwsl_notice("sig gen failed\n"); + + goto bail; + } + p1 += n; + p1 += lws_snprintf(p1, end1 - p1, "\"}"); + + free(buf); + + return p1 - out; + +bail: + free(buf); + + return -1; +} diff --git a/lib/jose/jwk/jwk.c b/lib/jose/jwk/jwk.c index ee051366c..8ef7494ee 100644 --- a/lib/jose/jwk/jwk.c +++ b/lib/jose/jwk/jwk.c @@ -25,10 +25,10 @@ #include static const char * const kyt_names[] = { - "unknown", /* LWS_JWK_KYT_UNKNOWN */ - "oct", /* LWS_JWK_KYT_OCT */ - "RSA", /* LWS_JWK_KYT_RSA */ - "EC" /* LWS_JWK_KYT_EC */ + "unknown", /* LWS_GENCRYPTO_KYT_UNKNOWN */ + "oct", /* LWS_GENCRYPTO_KYT_OCT */ + "RSA", /* LWS_GENCRYPTO_KYT_RSA */ + "EC" /* LWS_GENCRYPTO_KYT_EC */ }; /* @@ -64,37 +64,59 @@ static const char * const jwk_tok[] = { /* information about each token declared above */ -#define FLAG_META (1 << 12) -#define FLAG_RSA (1 << 13) -#define FLAG_EC (1 << 14) -#define FLAG_OCT (1 << 15) +#define F_B64 (1 << 10) +#define F_B64U (1 << 11) +#define F_META (1 << 12) +#define F_RSA (1 << 13) +#define F_EC (1 << 14) +#define F_OCT (1 << 15) unsigned short tok_map[] = { - FLAG_RSA | FLAG_EC | FLAG_OCT | FLAG_META | 0, /* padding */ - FLAG_RSA | JWK_RSA_KEYEL_E, - FLAG_RSA | JWK_RSA_KEYEL_N, - FLAG_RSA | FLAG_EC | JWK_RSA_KEYEL_D, - FLAG_RSA | JWK_RSA_KEYEL_P, - FLAG_RSA | JWK_RSA_KEYEL_Q, - FLAG_RSA | JWK_RSA_KEYEL_DP, - FLAG_RSA | JWK_RSA_KEYEL_DQ, - FLAG_RSA | JWK_RSA_KEYEL_QI, + F_RSA | F_EC | F_OCT | F_META | 0xff, + F_RSA | F_B64U | LWS_GENCRYPTO_RSA_KEYEL_E, + F_RSA | F_B64U | LWS_GENCRYPTO_RSA_KEYEL_N, + F_RSA | F_EC | F_B64U | LWS_GENCRYPTO_RSA_KEYEL_D, + F_RSA | F_B64U | LWS_GENCRYPTO_RSA_KEYEL_P, + F_RSA | F_B64U | LWS_GENCRYPTO_RSA_KEYEL_Q, + F_RSA | F_B64U | LWS_GENCRYPTO_RSA_KEYEL_DP, + F_RSA | F_B64U | LWS_GENCRYPTO_RSA_KEYEL_DQ, + F_RSA | F_B64U | LWS_GENCRYPTO_RSA_KEYEL_QI, - FLAG_RSA | FLAG_EC | FLAG_OCT | FLAG_META | JWK_META_KTY, - FLAG_OCT | JWK_OCT_KEYEL_K, + F_RSA | F_EC | F_OCT | F_META | JWK_META_KTY, + F_OCT | F_B64U | LWS_GENCRYPTO_OCT_KEYEL_K, - FLAG_EC | JWK_EC_KEYEL_CRV, - FLAG_EC | JWK_EC_KEYEL_X, - FLAG_EC | JWK_EC_KEYEL_Y, + F_EC | LWS_GENCRYPTO_EC_KEYEL_CRV, + F_EC | F_B64U | LWS_GENCRYPTO_EC_KEYEL_X, + F_EC | F_B64U | LWS_GENCRYPTO_EC_KEYEL_Y, - FLAG_RSA | FLAG_EC | FLAG_OCT | FLAG_META | JWK_META_KID, - FLAG_RSA | FLAG_EC | FLAG_OCT | FLAG_META | JWK_META_USE, + F_RSA | F_EC | F_OCT | F_META | JWK_META_KID, + F_RSA | F_EC | F_OCT | F_META | JWK_META_USE, - FLAG_RSA | FLAG_EC | FLAG_OCT | FLAG_META | JWK_META_KEY_OPS, - FLAG_RSA | FLAG_EC | FLAG_OCT | FLAG_META | JWK_META_X5C, - FLAG_RSA | FLAG_EC | FLAG_OCT | FLAG_META | JWK_META_ALG, + F_RSA | F_EC | F_OCT | F_META | JWK_META_KEY_OPS, + F_RSA | F_EC | F_OCT | F_META | F_B64 | JWK_META_X5C, + F_RSA | F_EC | F_OCT | F_META | JWK_META_ALG, }; +static const char *meta_names[] = { + "kty", "kid", "use", "key_ops", "x5c", "alg" +}; +static const char meta_b64[] = { 0, 0, 0, 0, 1, 0 }; + +static const char *oct_names[] = { + "k" +}; +static const char oct_b64[] = { 1 }; + +static const char *rsa_names[] = { + "e", "n", "d", "p", "q", "dp", "dq", "qi" +}; +static const char rsa_b64[] = { 1, 1, 1, 1, 1, 1, 1, 1 }; + +static const char *ec_names[] = { + "crv", "x", "d", "y", +}; +static const char ec_b64[] = { 0, 1, 1, 1 }; + struct cb_lws_jwk { struct lws_jwk *s; char *b64; @@ -105,8 +127,62 @@ struct cb_lws_jwk { unsigned short possible; }; +LWS_VISIBLE int +lws_jwk_dump(struct lws_jwk *s) +{ + const char **enames, *b64; + int elems; + int n; + + switch (s->kty) { + default: + case LWS_GENCRYPTO_KYT_UNKNOWN: + lwsl_err("%s: jwk %p: unknown type\n", __func__, s); + + return 1; + case LWS_GENCRYPTO_KYT_OCT: + elems = LWS_GENCRYPTO_OCT_KEYEL_COUNT; + enames = oct_names; + b64 = oct_b64; + break; + case LWS_GENCRYPTO_KYT_RSA: + elems = LWS_GENCRYPTO_RSA_KEYEL_COUNT; + enames = rsa_names; + b64 = rsa_b64; + break; + case LWS_GENCRYPTO_KYT_EC: + elems = LWS_GENCRYPTO_EC_KEYEL_COUNT; + enames = ec_names; + b64 = ec_b64; + break; + } + + lwsl_info("%s: jwk %p\n", __func__, s); + + for (n = 0; n < LWS_COUNT_JWK_ELEMENTS; n++) { + if (s->meta[n].buf && meta_b64[n]) { + lwsl_info(" meta: %s\n", meta_names[n]); + lwsl_hexdump_info(s->meta[n].buf, s->meta[n].len); + } + if (s->meta[n].buf && !meta_b64[n]) + lwsl_info(" meta: %s: '%s'\n", meta_names[n], + s->meta[n].buf); + } + + for (n = 0; n < elems; n++) { + if (s->e[n].buf && b64[n]) { + lwsl_info(" e: %s\n", enames[n]); + lwsl_hexdump_info(s->e[n].buf, s->e[n].len); + } + if (s->e[n].buf && !b64[n]) + lwsl_info(" e: %s: '%s'\n", enames[n], s->e[n].buf); + } + + return 0; +} + static int -_lws_jwk_set_element_jwk(struct lws_jwk_elements *e, char *in, int len) +_lws_jwk_set_element_jwk(struct lws_gencrypto_keyelem *e, char *in, int len) { e->buf = lws_malloc(len + 1, "jwk"); if (!e->buf) @@ -120,7 +196,7 @@ _lws_jwk_set_element_jwk(struct lws_jwk_elements *e, char *in, int len) } static int -_lws_jwk_set_element_jwk_b64(struct lws_jwk_elements *e, char *in, int len) +_lws_jwk_set_element_jwk_b64(struct lws_gencrypto_keyelem *e, char *in, int len) { int dec_size = ((len * 3) / 4) + 4, n; @@ -128,6 +204,27 @@ _lws_jwk_set_element_jwk_b64(struct lws_jwk_elements *e, char *in, int len) if (!e->buf) return -1; + /* same decoder accepts both url or original styles */ + + n = lws_b64_decode_string_len(in, len, (char *)e->buf, dec_size - 1); + if (n < 0) + return -1; + e->len = n; + + return 0; +} + +static int +_lws_jwk_set_element_jwk_b64u(struct lws_gencrypto_keyelem *e, char *in, int len) +{ + int dec_size = ((len * 3) / 4) + 4, n; + + e->buf = lws_malloc(dec_size, "jwk"); + if (!e->buf) + return -1; + + /* same decoder accepts both url or original styles */ + n = lws_b64_decode_string_len(in, len, (char *)e->buf, dec_size - 1); if (n < 0) return -1; @@ -137,7 +234,7 @@ _lws_jwk_set_element_jwk_b64(struct lws_jwk_elements *e, char *in, int len) } void -lws_jwk_destroy_elements(struct lws_jwk_elements *el, int m) +lws_jwk_destroy_elements(struct lws_gencrypto_keyelem *el, int m) { int n; @@ -158,7 +255,7 @@ cb_jwk(struct lejp_ctx *ctx, char reason) { struct cb_lws_jwk *cbs = (struct cb_lws_jwk *)ctx->user; struct lws_jwk *s = cbs->s; - int idx, poss; + unsigned int idx, poss; if (reason == LEJPCB_VAL_STR_START) cbs->pos = 0; @@ -172,14 +269,15 @@ cb_jwk(struct lejp_ctx *ctx, char reason) * ACME specifies the keys must be ordered in lexographic * order - where kty is not first. */ - cbs->possible = FLAG_RSA | FLAG_EC | FLAG_OCT; + cbs->possible = F_RSA | F_EC | F_OCT; if (reason == LEJPCB_OBJECT_END && ctx->path_match == 0 + 1) { /* we completed parsing a key */ if (cbs->per_key_cb && cbs->possible) { if (cbs->per_key_cb(cbs->s, cbs->user)) { - lwsl_notice("%s: user cb halts import\n", __func__); + lwsl_notice("%s: user cb halts import\n", + __func__); return -2; } @@ -197,6 +295,8 @@ cb_jwk(struct lejp_ctx *ctx, char reason) return 0; idx = tok_map[ctx->path_match - 1]; + if ((idx & 0xff) == 0xff) + return 0; switch (idx) { /* note: kty is not necessarily first... we have to keep track of @@ -205,34 +305,34 @@ cb_jwk(struct lejp_ctx *ctx, char reason) * not trying to tell us that it's RSA when we saw a "crv" * already) and then reduce the possibilities to just the one that * kty told. */ - case FLAG_RSA | FLAG_EC | FLAG_OCT | FLAG_META | JWK_META_KTY: + case F_RSA | F_EC | F_OCT | F_META | JWK_META_KTY: if (!strcmp(ctx->buf, "oct")) { - if (!(cbs->possible & FLAG_OCT)) + if (!(cbs->possible & F_OCT)) goto elements_mismatch; - s->kty = LWS_JWK_KYT_OCT; - cbs->possible = FLAG_OCT; - break; + s->kty = LWS_GENCRYPTO_KYT_OCT; + cbs->possible = F_OCT; + goto cont; } if (!strcmp(ctx->buf, "RSA")) { - if (!(cbs->possible & FLAG_RSA)) + if (!(cbs->possible & F_RSA)) goto elements_mismatch; - s->kty = LWS_JWK_KYT_RSA; - cbs->possible = FLAG_RSA; - break; + s->kty = LWS_GENCRYPTO_KYT_RSA; + cbs->possible = F_RSA; + goto cont; } if (!strcmp(ctx->buf, "EC")) { - if (!(cbs->possible & FLAG_EC)) + if (!(cbs->possible & F_EC)) goto elements_mismatch; - s->kty = LWS_JWK_KYT_EC; - cbs->possible = FLAG_EC; - break; + s->kty = LWS_GENCRYPTO_KYT_EC; + cbs->possible = F_EC; + goto cont; } lwsl_err("%s: Unknown KTY '%s'\n", __func__, ctx->buf); return -1; default: - +cont: if (cbs->pos + ctx->npos >= cbs->b64max) goto bail; @@ -244,12 +344,12 @@ cb_jwk(struct lejp_ctx *ctx, char reason) /* chunking has been collated */ - poss = idx & (FLAG_RSA | FLAG_EC | FLAG_OCT); + poss = idx & (F_RSA | F_EC | F_OCT); cbs->possible &= poss; if (!cbs->possible) goto elements_mismatch; - if (idx & FLAG_META) { + if (idx & F_META) { if (_lws_jwk_set_element_jwk(&s->meta[idx & 0x7f], cbs->b64, cbs->pos) < 0) goto bail; @@ -257,12 +357,27 @@ cb_jwk(struct lejp_ctx *ctx, char reason) break; } - /* key data... do the base64 decode then */ + if (idx & F_B64U) { + /* key data... do the base64 decode as needed */ + if (_lws_jwk_set_element_jwk_b64u(&s->e[idx & 0x7f], + cbs->b64, cbs->pos) + < 0) + goto bail; + return 0; + } - if (_lws_jwk_set_element_jwk_b64(&s->e[idx & 0x7f], - cbs->b64, cbs->pos) < 0) - goto bail; + if (idx & F_B64) { + /* cert data... do non-urlcoded base64 decode */ + if (_lws_jwk_set_element_jwk_b64(&s->e[idx & 0x7f], + cbs->b64, cbs->pos) + < 0) + goto bail; + return 0; + } + if (_lws_jwk_set_element_jwk(&s->e[idx & 0x7f], + cbs->b64, cbs->pos) < 0) + goto bail; break; } @@ -295,7 +410,7 @@ lws_jwk_import(struct lws_jwk *s, lws_jwk_key_import_callback cb, void *user, cbs.pos = 0; cbs.per_key_cb = cb; cbs.user = user; - cbs.possible = FLAG_RSA | FLAG_EC | FLAG_OCT; + cbs.possible = F_RSA | F_EC | F_OCT; if (cb == NULL) tok = jwk_tok; @@ -310,7 +425,7 @@ lws_jwk_import(struct lws_jwk *s, lws_jwk_key_import_callback cb, void *user, return -1; } - if (s->kty == LWS_JWK_KYT_UNKNOWN) { + if (s->kty == LWS_GENCRYPTO_KYT_UNKNOWN) { lwsl_notice("%s: missing or unknown kyt\n", __func__); return -1; } @@ -333,13 +448,13 @@ lws_jwk_export(struct lws_jwk *s, int private, char *p, size_t len) switch (s->kty) { - case LWS_JWK_KYT_OCT: - if (!s->e[JWK_OCT_KEYEL_K].buf) + case LWS_GENCRYPTO_KYT_OCT: + if (!s->e[LWS_GENCRYPTO_OCT_KEYEL_K].buf) return -1; p += lws_snprintf(p, end - p, "\"k\":\""); - n = lws_jws_base64_enc((const char *)s->e[JWK_OCT_KEYEL_K].buf, - s->e[JWK_OCT_KEYEL_K].len, p, end - p - 4); + n = lws_jws_base64_enc((const char *)s->e[LWS_GENCRYPTO_OCT_KEYEL_K].buf, + s->e[LWS_GENCRYPTO_OCT_KEYEL_K].len, p, end - p - 4); if (n < 0) { lwsl_notice("%s: enc failed\n", __func__); return -1; @@ -351,12 +466,12 @@ lws_jwk_export(struct lws_jwk *s, int private, char *p, size_t len) return p - start; - case LWS_JWK_KYT_RSA: - if (!s->e[JWK_RSA_KEYEL_E].buf || - !s->e[JWK_RSA_KEYEL_N].buf || - (private && (!s->e[JWK_RSA_KEYEL_D].buf || - !s->e[JWK_RSA_KEYEL_P].buf || - !s->e[JWK_RSA_KEYEL_Q].buf)) + case LWS_GENCRYPTO_KYT_RSA: + if (!s->e[LWS_GENCRYPTO_RSA_KEYEL_E].buf || + !s->e[LWS_GENCRYPTO_RSA_KEYEL_N].buf || + (private && (!s->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf || + !s->e[LWS_GENCRYPTO_RSA_KEYEL_P].buf || + !s->e[LWS_GENCRYPTO_RSA_KEYEL_Q].buf)) ) { lwsl_notice("%s: not enough elements filled\n", __func__); @@ -364,7 +479,7 @@ lws_jwk_export(struct lws_jwk *s, int private, char *p, size_t len) } if (!private) - limit = JWK_RSA_KEYEL_N + 1; + limit = LWS_GENCRYPTO_RSA_KEYEL_N + 1; for (n = 0; n < limit; n++) { int m; @@ -397,7 +512,7 @@ lws_jwk_export(struct lws_jwk *s, int private, char *p, size_t len) return p - start; - case LWS_JWK_KYT_EC: + case LWS_GENCRYPTO_KYT_EC: return p - start; default: diff --git a/lib/jose/jws/jose.c b/lib/jose/jws/jose.c index 6abb96553..a72014325 100644 --- a/lib/jose/jws/jose.c +++ b/lib/jose/jws/jose.c @@ -53,10 +53,16 @@ static const char * const jws_jose[] = { "p2c" /* valid for JWE PBES2 only */ }; +struct jose_cb_args { + const struct lws_jose_jwe_alg **args; + const struct lws_jose_jwe_alg **enc_args; /* null for jws case */ + int is_jwe; +}; + static signed char lws_jws_jose_cb(struct lejp_ctx *ctx, char reason) { - struct cb_hdr_s *s = (struct cb_hdr_s *)ctx->user; + struct jose_cb_args *args = (struct jose_cb_args *)ctx->user; if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match) return 0; @@ -67,71 +73,28 @@ lws_jws_jose_cb(struct lejp_ctx *ctx, char reason) case LJJHI_ALG: /* REQUIRED */ - lws_strncpy(s->alg, ctx->buf, sizeof(s->alg)); + /* + * look up whether we support this alg and point the caller at + * its definition if so + */ - if (s->is_jwe) { + if (!args->is_jwe && + lws_gencrypto_jws_alg_to_definition(ctx->buf, args->args)) { + lwsl_notice("%s: unknown alg '%s'\n", __func__, + ctx->buf); - lwsl_err("%s: JWE alg\n", __func__); - - /* interpret as for JWE... just store the string */ - - return 0; + return -1; } - /* interpret as for JWS */ + if (args->is_jwe && + lws_gencrypto_jwe_alg_to_definition(ctx->buf, args->args)) { + lwsl_notice("%s: unknown alg '%s'\n", __func__, + ctx->buf); - if (!strcmp(ctx->buf, "HS256")) { - s->hmac_type = LWS_GENHMAC_TYPE_SHA256; - s->algtype = LWS_JWK_ENCTYPE_NONE; - break; - } - if (!strcmp(ctx->buf, "HS384")) { - s->hmac_type = LWS_GENHMAC_TYPE_SHA384; - s->algtype = LWS_JWK_ENCTYPE_NONE; - break; - } - if (!strcmp(ctx->buf, "HS512")) { - s->hmac_type = LWS_GENHMAC_TYPE_SHA512; - s->algtype = LWS_JWK_ENCTYPE_NONE; - break; + return -1; } - if (!strcmp(ctx->buf, "RS256")) { - s->hash_type = LWS_GENHASH_TYPE_SHA256; - s->algtype = LWS_JWK_ENCTYPE_RSASSA; - break; - } - if (!strcmp(ctx->buf, "RS384")) { - s->hash_type = LWS_GENHASH_TYPE_SHA384; - s->algtype = LWS_JWK_ENCTYPE_RSASSA; - break; - } - if (!strcmp(ctx->buf, "RS512")) { - s->hash_type = LWS_GENHASH_TYPE_SHA512; - s->algtype = LWS_JWK_ENCTYPE_RSASSA; - break; - } - - if (!strcmp(ctx->buf, "ES256")) { - s->hash_type = LWS_GENHASH_TYPE_SHA256; - s->algtype = LWS_JWK_ENCTYPE_EC; - strncpy(s->curve, "P-256", sizeof(s->curve)); - break; - } - if (!strcmp(ctx->buf, "ES384")) { - s->hash_type = LWS_GENHASH_TYPE_SHA384; - s->algtype = LWS_JWK_ENCTYPE_EC; - strncpy(s->curve, "P-384", sizeof(s->curve)); - break; - } - if (!strcmp(ctx->buf, "ES512")) { - s->hash_type = LWS_GENHASH_TYPE_SHA512; - s->algtype = LWS_JWK_ENCTYPE_EC; - strncpy(s->curve, "P-521", sizeof(s->curve)); - break; - } - - return -1; + return 0; case LJJHI_TYP: /* Optional: string: media type */ if (strcmp(ctx->buf, "JWT")) @@ -165,46 +128,53 @@ lws_jws_jose_cb(struct lejp_ctx *ctx, char reason) /* past here, JWE only */ case LJJHI_ENC: /* JWE only: Optional: string */ - if (!s->is_jwe) + if (!args->is_jwe) return -1; + if (lws_gencrypto_jwe_enc_to_definition(ctx->buf, + args->enc_args)) { + lwsl_notice("%s: unknown enc '%s'\n", __func__, + ctx->buf); + + return -1; + } break; case LJJHI_ZIP: /* JWE only: Optional: string ("DEF" = deflate) */ - if (!s->is_jwe) + if (!args->is_jwe) return -1; break; case LJJHI_EPK: /* Additional arg for JWE ECDH */ - if (!s->is_jwe) + if (!args->is_jwe) return -1; break; case LJJHI_APU: /* Additional arg for JWE ECDH */ - if (!s->is_jwe) + if (!args->is_jwe) return -1; break; case LJJHI_APV: /* Additional arg for JWE ECDH */ - if (!s->is_jwe) + if (!args->is_jwe) return -1; break; case LJJHI_IV: /* Additional arg for JWE AES */ - if (!s->is_jwe) + if (!args->is_jwe) return -1; break; case LJJHI_TAG: /* Additional arg for JWE AES */ - if (!s->is_jwe) + if (!args->is_jwe) return -1; break; case LJJHI_P2S: /* Additional arg for JWE PBES2 */ - if (!s->is_jwe) + if (!args->is_jwe) return -1; break; case LJJHI_P2C: /* Additional arg for JWE PBES2 */ - if (!s->is_jwe) + if (!args->is_jwe) return -1; break; @@ -217,24 +187,27 @@ lws_jws_jose_cb(struct lejp_ctx *ctx, char reason) return 0; } + static int -lws_jose_parse(struct cb_hdr_s *args, uint8_t *buf, int n, int is_jwe) +lws_jose_parse(const struct lws_jose_jwe_alg **_args, + const struct lws_jose_jwe_alg **enc_args, + uint8_t *buf, int n, int is_jwe) { struct lejp_ctx jctx; + struct jose_cb_args args; int m; - args->alg[0] = '\0'; - args->curve[0] = '\0'; - args->algtype = -1; - args->is_jwe = is_jwe; + args.args = _args; + args.enc_args = enc_args; + args.is_jwe = is_jwe; - lejp_construct(&jctx, lws_jws_jose_cb, args, jws_jose, + lejp_construct(&jctx, lws_jws_jose_cb, &args, jws_jose, LWS_ARRAY_SIZE(jws_jose)); m = (int)(signed char)lejp_parse(&jctx, (uint8_t *)buf, n); lejp_destruct(&jctx); if (m < 0) { - lwsl_notice("parse got %d: alg %s\n", m, args->alg); + lwsl_notice("parse got %d\n", m); return -1; } @@ -242,13 +215,16 @@ lws_jose_parse(struct cb_hdr_s *args, uint8_t *buf, int n, int is_jwe) } int -lws_jws_parse_jose(struct cb_hdr_s *args, uint8_t *buf, int n) +lws_jws_parse_jose(const struct lws_jose_jwe_alg **args, + uint8_t *buf, int n) { - return lws_jose_parse(args, buf, n, 0); + return lws_jose_parse(args, NULL, buf, n, 0); } int -lws_jwe_parse_jose(struct cb_hdr_s *args, uint8_t *buf, int n) +lws_jwe_parse_jose(const struct lws_jose_jwe_alg **args, + const struct lws_jose_jwe_alg **enc_args, + uint8_t *buf, int n) { - return lws_jose_parse(args, buf, n, 1); + return lws_jose_parse(args, enc_args, buf, n, 1); } diff --git a/lib/jose/jws/jws.c b/lib/jose/jws/jws.c index 6ff2845c6..dae98fd1c 100644 --- a/lib/jose/jws/jws.c +++ b/lib/jose/jws/jws.c @@ -82,11 +82,13 @@ lws_jws_confirm_sig(const char *in, size_t len, struct lws_jwk *jwk, struct lws_context *context) { int sig_pos = lws_jws_find_sig(in, len), pos = 0, n, m, h_len; + enum enum_genrsa_mode padding = LGRSAM_PKCS1_1_5; uint8_t digest[LWS_GENHASH_LARGEST]; + const struct lws_jose_jwe_alg *args = NULL; struct lws_genhash_ctx hash_ctx; + struct lws_genec_ctx ecdsactx; struct lws_genrsa_ctx rsactx; struct lws_genhmac_ctx ctx; - struct cb_hdr_s args; char buf[2048]; /* 1) there has to be a signature */ @@ -115,7 +117,7 @@ lws_jws_confirm_sig(const char *in, size_t len, struct lws_jwk *jwk, m = lws_jws_parse_jose(&args, (unsigned char *)buf, n); if (m < 0) { - lwsl_notice("parse got %d: alg %s\n", m, args.alg); + lwsl_notice("parse got %d: alg %s\n", m, args->alg); return -1; } @@ -124,14 +126,21 @@ lws_jws_confirm_sig(const char *in, size_t len, struct lws_jwk *jwk, m = lws_b64_decode_string_len(in + sig_pos, len - sig_pos, buf, sizeof(buf) - 1); - switch (args.algtype) { - case LWS_JWK_ENCTYPE_RSASSA: + switch (args->algtype_signing) { + case LWS_JOSE_ENCTYPE_RSASSA_PKCS1_PSS: + case LWS_JOSE_ENCTYPE_RSASSA_PKCS1_OAEP: + padding = LGRSAM_PKCS1_OAEP_PSS; + /* fallthru */ + case LWS_JOSE_ENCTYPE_RSASSA_PKCS1_1_5: - /* RSASSA-PKCS1-v1_5 using SHA-256/384/512 */ + /* RSASSA-PKCS1-v1_5 or OAEP using SHA-256/384/512 */ + + if (jwk->kty != LWS_GENCRYPTO_KYT_RSA) + return -1; /* 6(RSA): compute the hash of the payload into "digest" */ - if (lws_genhash_init(&hash_ctx, args.hash_type)) + if (lws_genhash_init(&hash_ctx, args->hash_type)) return -1; if (lws_genhash_update(&hash_ctx, (uint8_t *)in, sig_pos - 1)) { @@ -142,17 +151,16 @@ lws_jws_confirm_sig(const char *in, size_t len, struct lws_jwk *jwk, if (lws_genhash_destroy(&hash_ctx, digest)) return -1; - h_len = lws_genhash_size(args.hash_type); + h_len = lws_genhash_size(args->hash_type); - if (lws_genrsa_create(&rsactx, jwk->e, context, - LGRSAM_PKCS1_1_5)) { + if (lws_genrsa_create(&rsactx, jwk->e, context, padding)) { lwsl_notice("%s: lws_genrsa_public_decrypt_create\n", __func__); return -1; } - n = lws_genrsa_public_verify(&rsactx, digest, args.hash_type, - (uint8_t *)buf, m); + n = lws_genrsa_hash_sig_verify(&rsactx, digest, args->hash_type, + (uint8_t *)buf, m); lws_genrsa_destroy(&rsactx); if (n < 0) { @@ -162,19 +170,19 @@ lws_jws_confirm_sig(const char *in, size_t len, struct lws_jwk *jwk, break; - case LWS_JWK_ENCTYPE_NONE: + case LWS_JOSE_ENCTYPE_NONE: /* SHA256/384/512 HMAC */ - h_len = lws_genhmac_size(args.hmac_type); + h_len = lws_genhmac_size(args->hmac_type); if (m < 0 || m != h_len) return -1; /* 6) compute HMAC over payload */ - if (lws_genhmac_init(&ctx, args.hmac_type, - jwk->e[JWK_RSA_KEYEL_E].buf, - jwk->e[JWK_RSA_KEYEL_E].len)) + if (lws_genhmac_init(&ctx, args->hmac_type, + jwk->e[LWS_GENCRYPTO_RSA_KEYEL_E].buf, + jwk->e[LWS_GENCRYPTO_RSA_KEYEL_E].len)) return -1; if (lws_genhmac_update(&ctx, (uint8_t *)in, sig_pos - 1)) { @@ -195,10 +203,63 @@ lws_jws_confirm_sig(const char *in, size_t len, struct lws_jwk *jwk, break; - case LWS_JWK_ENCTYPE_EC: + case LWS_JOSE_ENCTYPE_ECDSA: - lwsl_err("%s: EC not supported yet\n", __func__); - return -1; + /* ECDSA using SHA-256/384/512 */ + + /* the key coming in with this makes sense, right? */ + + /* has to be an EC key :-) */ + if (jwk->kty != LWS_GENCRYPTO_KYT_EC) + return -1; + + /* key must state its curve */ + if (!jwk->e[LWS_GENCRYPTO_EC_KEYEL_CRV].buf) + return -1; + + /* key must match the selected alg curve */ + if (strcmp((const char *)jwk->e[LWS_GENCRYPTO_EC_KEYEL_CRV].buf, + args->curve_name)) + return -1; + + /* compute the hash of the payload into "digest" */ + + if (lws_genhash_init(&hash_ctx, args->hash_type)) + return -1; + + if (lws_genhash_update(&hash_ctx, (uint8_t *)in, sig_pos - 1)) { + lws_genhash_destroy(&hash_ctx, NULL); + + return -1; + } + if (lws_genhash_destroy(&hash_ctx, digest)) + return -1; + + h_len = lws_genhash_size(args->hash_type); + + if (lws_genecdsa_create(&ecdsactx, context, NULL)) { + lwsl_notice("%s: lws_genrsa_public_decrypt_create\n", + __func__); + return -1; + } + + if (lws_genecdsa_set_key(&ecdsactx, jwk->e)) { + lws_genec_destroy(&ecdsactx); + lwsl_notice("%s: ec key import fail\n", __func__); + return -1; + } + + n = lws_genecdsa_hash_sig_verify(&ecdsactx, digest, + args->hash_type, + (uint8_t *)buf, m); + + lws_genec_destroy(&ecdsactx); + if (n < 0) { + lwsl_notice("decrypt fail\n"); + return -1; + } + + break; default: lwsl_err("%s: unknown alg from jose\n", __func__); @@ -211,16 +272,19 @@ lws_jws_confirm_sig(const char *in, size_t len, struct lws_jwk *jwk, LWS_VISIBLE int lws_jws_sign_from_b64(const char *b64_hdr, size_t hdr_len, const char *b64_pay, size_t pay_len, char *b64_sig, size_t sig_len, - enum lws_genhash_types hash_type, struct lws_jwk *jwk, + const struct lws_jose_jwe_alg *args, + struct lws_jwk *jwk, struct lws_context *context) { + enum enum_genrsa_mode padding = LGRSAM_PKCS1_1_5; uint8_t digest[LWS_GENHASH_LARGEST]; struct lws_genhash_ctx hash_ctx; + struct lws_genec_ctx ecdsactx; struct lws_genrsa_ctx rsactx; + int n, m; uint8_t *buf; - int n; - if (lws_genhash_init(&hash_ctx, hash_type)) + if (lws_genhash_init(&hash_ctx, args->hash_type)) return -1; if (b64_hdr) { @@ -235,19 +299,28 @@ lws_jws_sign_from_b64(const char *b64_hdr, size_t hdr_len, const char *b64_pay, if (lws_genhash_destroy(&hash_ctx, digest)) return -1; - if (jwk->kty == LWS_JWK_KYT_RSA) { - if (lws_genrsa_create(&rsactx, jwk->e, context, LGRSAM_PKCS1_1_5)) { + switch (args->algtype_signing) { + case LWS_JOSE_ENCTYPE_RSASSA_PKCS1_PSS: + case LWS_JOSE_ENCTYPE_RSASSA_PKCS1_OAEP: + padding = LGRSAM_PKCS1_OAEP_PSS; + /* fallthru */ + case LWS_JOSE_ENCTYPE_RSASSA_PKCS1_1_5: + + if (jwk->kty != LWS_GENCRYPTO_KYT_RSA) + return -1; + + if (lws_genrsa_create(&rsactx, jwk->e, context, padding)) { lwsl_notice("%s: lws_genrsa_public_decrypt_create\n", __func__); return -1; } - n = jwk->e[JWK_RSA_KEYEL_N].len; + n = jwk->e[LWS_GENCRYPTO_RSA_KEYEL_N].len; buf = lws_malloc(n, "jws sign"); if (!buf) return -1; - n = lws_genrsa_public_sign(&rsactx, digest, hash_type, buf, n); + n = lws_genrsa_hash_sign(&rsactx, digest, args->hash_type, buf, n); lws_genrsa_destroy(&rsactx); if (n < 0) { lws_free(buf); @@ -259,12 +332,66 @@ lws_jws_sign_from_b64(const char *b64_hdr, size_t hdr_len, const char *b64_pay, lws_free(buf); return n; - } - if (jwk->kty == LWS_JWK_KYT_OCT) + case LWS_JOSE_ENCTYPE_NONE: return lws_jws_base64_enc((char *)digest, - lws_genhash_size(hash_type), + lws_genhash_size(args->hash_type), b64_sig, sig_len); + case LWS_JOSE_ENCTYPE_ECDSA: + /* ECDSA using SHA-256/384/512 */ + + /* the key coming in with this makes sense, right? */ + + /* has to be an EC key :-) */ + if (jwk->kty != LWS_GENCRYPTO_KYT_EC) + return -1; + + /* key must state its curve */ + if (!jwk->e[LWS_GENCRYPTO_EC_KEYEL_CRV].buf) + return -1; + + /* must have all his pieces for a private key */ + if (!jwk->e[LWS_GENCRYPTO_EC_KEYEL_X].buf || + !jwk->e[LWS_GENCRYPTO_EC_KEYEL_Y].buf || + !jwk->e[LWS_GENCRYPTO_EC_KEYEL_D].buf) + return -1; + + /* key must match the selected alg curve */ + if (strcmp((const char *)jwk->e[LWS_GENCRYPTO_EC_KEYEL_CRV].buf, + args->curve_name)) + return -1; + + if (lws_genecdsa_create(&ecdsactx, context, NULL)) { + lwsl_notice("%s: lws_genrsa_public_decrypt_create\n", + __func__); + return -1; + } + + if (lws_genecdsa_set_key(&ecdsactx, jwk->e)) { + lws_genec_destroy(&ecdsactx); + lwsl_notice("%s: ec key import fail\n", __func__); + return -1; + } + m = jwk->e[LWS_GENCRYPTO_EC_KEYEL_D].len; + buf = lws_malloc(m, "jws sign"); + if (!buf) + return -1; + + n = lws_genecdsa_hash_sign(&ecdsactx, digest, args->hash_type, + (uint8_t *)buf, m); + lws_genec_destroy(&ecdsactx); + if (n < 0) { + lwsl_notice("decrypt fail\n"); + return -1; + } + n = lws_jws_base64_enc((char *)buf, m, b64_sig, sig_len); + lws_free(buf); + + return n; + + default: + break; + } /* unknown key type */ @@ -274,95 +401,3 @@ hash_fail: lws_genhash_destroy(&hash_ctx, NULL); return -1; } - -LWS_VISIBLE int -lws_jws_create_packet(struct lws_jwk *jwk, const char *payload, size_t len, - const char *nonce, char *out, size_t out_len, - struct lws_context *context) -{ - char *buf, *start, *p, *end, *p1, *end1, *b64_hdr, *b64_pay; - int n, b64_hdr_len, b64_pay_len; - - /* - * This buffer is local to the function, the actual output - * is prepared into vhd->buf. Only the plaintext protected header - * (which contains the public key, 512 bytes for 4096b) goes in - * here temporarily. - */ - n = LWS_PRE + 2048; - buf = malloc(n); - if (!buf) { - lwsl_notice("%s: malloc %d failed\n", __func__, n); - return -1; - } - - p = start = buf + LWS_PRE; - end = buf + n - LWS_PRE - 1; - - /* - * temporary JWS protected header plaintext - */ - - p += lws_snprintf(p, end - p, "{\"alg\":\"RS256\",\"jwk\":"); - n = lws_jwk_export(jwk, 0, p, end - p); - if (n < 0) { - lwsl_notice("failed to export jwk\n"); - - goto bail; - } - p += n; - p += lws_snprintf(p, end - p, ",\"nonce\":\"%s\"}", nonce); - - /* - * prepare the signed outer JSON with all the parts in - */ - - p1 = out; - end1 = out + out_len - 1; - - p1 += lws_snprintf(p1, end1 - p1, "{\"protected\":\""); - b64_hdr = p1; - n = lws_jws_base64_enc(start, p - start, p1, end1 - p1); - if (n < 0) { - lwsl_notice("%s: failed to encode protected\n", __func__); - goto bail; - } - b64_hdr_len = n; - p1 += n; - - p1 += lws_snprintf(p1, end1 - p1, "\",\"payload\":\""); - b64_pay = p1; - n = lws_jws_base64_enc(payload, len, p1, end1 - p1); - if (n < 0) { - lwsl_notice("%s: failed to encode payload\n", __func__); - goto bail; - } - b64_pay_len = n; - - p1 += n; - p1 += lws_snprintf(p1, end1 - p1, "\",\"signature\":\""); - - /* - * taking the b64 protected header and the b64 payload, sign them - * and place the signature into the packet - */ - n = lws_jws_sign_from_b64(b64_hdr, b64_hdr_len, b64_pay, b64_pay_len, - p1, end1 - p1, LWS_GENHASH_TYPE_SHA256, jwk, - context); - if (n < 0) { - lwsl_notice("sig gen failed\n"); - - goto bail; - } - p1 += n; - p1 += lws_snprintf(p1, end1 - p1, "\"}"); - - free(buf); - - return p1 - out; - -bail: - free(buf); - - return -1; -} diff --git a/lib/jose/jws/private.h b/lib/jose/jws/private.h index b5d39f219..c229e5a34 100644 --- a/lib/jose/jws/private.h +++ b/lib/jose/jws/private.h @@ -23,7 +23,10 @@ */ int -lws_jws_parse_jose(struct cb_hdr_s *args, uint8_t *buf, int n); +lws_jws_parse_jose(const struct lws_jose_jwe_alg **args, + uint8_t *buf, int n); int -lws_jwe_parse_jose(struct cb_hdr_s *args, uint8_t *buf, int n); +lws_jwe_parse_jose(const struct lws_jose_jwe_alg **args, + const struct lws_jose_jwe_alg **enc_args, + uint8_t *buf, int n); diff --git a/lib/jose/private.h b/lib/jose/private.h index d39f71299..cfa9c62a2 100644 --- a/lib/jose/private.h +++ b/lib/jose/private.h @@ -20,4 +20,4 @@ */ void -lws_jwk_destroy_elements(struct lws_jwk_elements *el, int m); +lws_jwk_destroy_elements(struct lws_gencrypto_keyelem *el, int m); diff --git a/lib/misc/fts/README.md b/lib/misc/fts/README.md index ef53abbf5..fcb225cf3 100644 --- a/lib/misc/fts/README.md +++ b/lib/misc/fts/README.md @@ -134,9 +134,7 @@ Indexing time|123ms Peak alloc|3MiB Serialization time|1ms Trie File size|1.4MiB - -So the peak memory requirement to generate the whole trie in memory for that -first is around 4x the size of the final output file. + Once it's generated, querying the trie file is very inexpensive, even when there are lots of results. diff --git a/lib/misc/fts/trie.c b/lib/misc/fts/trie.c index 8dd93f7a4..1750919a3 100644 --- a/lib/misc/fts/trie.c +++ b/lib/misc/fts/trie.c @@ -160,7 +160,7 @@ struct lws_fts { unsigned char agg[128]; }; -/* since the kernel case allocates >2GB, no point keeping this too low */ +/* since the kernel case allocates >300MB, no point keeping this too low */ #define TRIE_LWSAC_BLOCK_SIZE (1024 * 1024) diff --git a/lib/tls/lws-gencrypto-common.c b/lib/tls/lws-gencrypto-common.c new file mode 100644 index 000000000..4151524ca --- /dev/null +++ b/lib/tls/lws-gencrypto-common.c @@ -0,0 +1,308 @@ +/* + * libwebsockets - generic crypto hiding the backend - common parts + * + * 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 + */ +#include "core/private.h" + +/* + * Signing algorithms + * + * These came from RFC7518 (JSON Web Algorithms) Section 3 + */ + +static const struct lws_jose_jwe_alg lws_gencrypto_jws_alg_map[] = { + { /* optional */ + LWS_GENHASH_TYPE_UNKNOWN, + LWS_GENHMAC_TYPE_SHA256, + LWS_JOSE_ENCTYPE_NONE, + LWS_JOSE_ENCTYPE_NONE, + "none", NULL + }, + { /* required */ + LWS_GENHASH_TYPE_UNKNOWN, + LWS_GENHMAC_TYPE_SHA256, + LWS_JOSE_ENCTYPE_NONE, + LWS_JOSE_ENCTYPE_NONE, + "HS256", NULL + }, + { /* optional */ + LWS_GENHASH_TYPE_UNKNOWN, + LWS_GENHMAC_TYPE_SHA384, + LWS_JOSE_ENCTYPE_NONE, + LWS_JOSE_ENCTYPE_NONE, + "HS384", NULL + }, + { /* optional */ + LWS_GENHASH_TYPE_UNKNOWN, + LWS_GENHMAC_TYPE_SHA512, + LWS_JOSE_ENCTYPE_NONE, + LWS_JOSE_ENCTYPE_NONE, + "HS512", NULL + }, + + { /* recommended */ + LWS_GENHASH_TYPE_SHA256, + LWS_GENHMAC_TYPE_UNKNOWN, + LWS_JOSE_ENCTYPE_RSASSA_PKCS1_1_5, + LWS_JOSE_ENCTYPE_NONE, + "RS256", NULL + }, + { /* optional */ + LWS_GENHASH_TYPE_SHA384, + LWS_GENHMAC_TYPE_UNKNOWN, + LWS_JOSE_ENCTYPE_RSASSA_PKCS1_1_5, + LWS_JOSE_ENCTYPE_NONE, + "RS384", NULL + }, + { /* optional */ + LWS_GENHASH_TYPE_SHA512, + LWS_GENHMAC_TYPE_UNKNOWN, + LWS_JOSE_ENCTYPE_RSASSA_PKCS1_1_5, + LWS_JOSE_ENCTYPE_NONE, + "RS512", NULL + }, + + { /* Recommended+ */ + LWS_GENHASH_TYPE_SHA256, + LWS_GENHMAC_TYPE_UNKNOWN, + LWS_JOSE_ENCTYPE_ECDSA, + LWS_JOSE_ENCTYPE_NONE, + "ES256", "P-256" + }, + { /* optional */ + LWS_GENHASH_TYPE_SHA384, + LWS_GENHMAC_TYPE_UNKNOWN, + LWS_JOSE_ENCTYPE_ECDSA, + LWS_JOSE_ENCTYPE_NONE, + "ES384", "P-384" + }, + { /* optional */ + LWS_GENHASH_TYPE_SHA512, + LWS_GENHMAC_TYPE_UNKNOWN, + LWS_JOSE_ENCTYPE_ECDSA, + LWS_JOSE_ENCTYPE_NONE, + "ES512", "P-521" + }, + + { /* optional */ + LWS_GENHASH_TYPE_SHA256, + LWS_GENHMAC_TYPE_UNKNOWN, + LWS_JOSE_ENCTYPE_RSASSA_PKCS1_PSS, + LWS_JOSE_ENCTYPE_NONE, + "PS256", NULL + }, + { /* optional */ + LWS_GENHASH_TYPE_SHA384, + LWS_GENHMAC_TYPE_UNKNOWN, + LWS_JOSE_ENCTYPE_RSASSA_PKCS1_PSS, + LWS_JOSE_ENCTYPE_NONE, + "PS384", NULL + }, + { /* optional */ + LWS_GENHASH_TYPE_SHA512, + LWS_GENHMAC_TYPE_UNKNOWN, + LWS_JOSE_ENCTYPE_RSASSA_PKCS1_PSS, + LWS_JOSE_ENCTYPE_NONE, + "PS512", NULL + }, +}; + +static const struct lws_jose_jwe_alg lws_gencrypto_jwe_alg_map[] = { + { /* recommended- */ + LWS_GENHASH_TYPE_SHA256, + LWS_GENHMAC_TYPE_UNKNOWN, + LWS_JOSE_ENCTYPE_RSASSA_PKCS1_1_5, + LWS_JOSE_ENCTYPE_NONE, + "RSA1_5", NULL + }, + { /* recommended+ */ + LWS_GENHASH_TYPE_SHA1, + LWS_GENHMAC_TYPE_UNKNOWN, + LWS_JOSE_ENCTYPE_RSASSA_PKCS1_OAEP, + LWS_JOSE_ENCTYPE_NONE, + "RSA-OAEP", NULL + }, + + { /* recommended */ + LWS_GENHASH_TYPE_SHA256, + LWS_GENHMAC_TYPE_UNKNOWN, + LWS_JOSE_ENCTYPE_RSASSA_PKCS1_OAEP, + LWS_JOSE_ENCTYPE_NONE, + "A128KW", NULL + }, + { /* recommended */ + LWS_GENHASH_TYPE_SHA256, + LWS_GENHMAC_TYPE_UNKNOWN, + LWS_JOSE_ENCTYPE_RSASSA_PKCS1_OAEP, + LWS_JOSE_ENCTYPE_NONE, + "A256KW", NULL + }, + + { /* recommended */ + LWS_GENHASH_TYPE_UNKNOWN, + LWS_GENHMAC_TYPE_UNKNOWN, + LWS_JOSE_ENCTYPE_NONE, + LWS_JOSE_ENCTYPE_AES_GCM, + "dir", NULL + }, + + { /* recommended+ */ + LWS_GENHASH_TYPE_SHA256, + LWS_GENHMAC_TYPE_UNKNOWN, + LWS_JOSE_ENCTYPE_RSASSA_PKCS1_OAEP, + LWS_JOSE_ENCTYPE_NONE, + "ECDH-ES", NULL + }, + { /* recommended */ + LWS_GENHASH_TYPE_SHA256, + LWS_GENHMAC_TYPE_UNKNOWN, + LWS_JOSE_ENCTYPE_RSASSA_PKCS1_OAEP, + LWS_JOSE_ENCTYPE_NONE, + "ECDH-ES+A128KW", NULL + }, + { /* recommended */ + LWS_GENHASH_TYPE_SHA256, + LWS_GENHMAC_TYPE_UNKNOWN, + LWS_JOSE_ENCTYPE_RSASSA_PKCS1_OAEP, + LWS_JOSE_ENCTYPE_NONE, + "ECDH-ES+A256KW", NULL + }, + + /* list terminator */ + { 0, 0, 0, 0, NULL, NULL } +}; + + +static const struct lws_jose_jwe_alg lws_gencrypto_jwe_enc_map[] = { + /* + * It uses the HMAC message authentication code [RFC2104] with the + * SHA-256 hash function [SHS] to provide message authentication, with + * the HMAC output truncated to 128 bits, corresponding to the + * HMAC-SHA-256-128 algorithm defined in [RFC4868]. For encryption, it + * uses AES in the CBC mode of operation as defined in Section 6.2 of + * [NIST.800-38A], with PKCS #7 padding and a 128-bit IV value. + * + * The AES_CBC_HMAC_SHA2 parameters specific to AES_128_CBC_HMAC_SHA_256 + * are: + * + * The input key K is 32 octets long. + * ENC_KEY_LEN is 16 octets. + * MAC_KEY_LEN is 16 octets. + * The SHA-256 hash algorithm is used for the HMAC. + * The HMAC-SHA-256 output is truncated to T_LEN=16 octets, by + * stripping off the final 16 octets. + */ + { /* required */ + LWS_GENHASH_TYPE_UNKNOWN, + LWS_GENHMAC_TYPE_SHA256, + LWS_JOSE_ENCTYPE_NONE, + LWS_JOSE_ENCTYPE_AES_CBC, + "A128CBC-HS256", NULL + }, +}; + +LWS_VISIBLE int +lws_gencrypto_jws_alg_to_definition(const char *alg, + const struct lws_jose_jwe_alg **jose) +{ + const struct lws_jose_jwe_alg *a = lws_gencrypto_jws_alg_map; + + while (a->alg) { + if (!strcmp(alg, a->alg)) { + *jose = a; + + return 0; + } + a++; + } + + return 1; +} + +LWS_VISIBLE int +lws_gencrypto_jwe_alg_to_definition(const char *alg, + const struct lws_jose_jwe_alg **jose) +{ + const struct lws_jose_jwe_alg *a = lws_gencrypto_jwe_alg_map; + + while (a->alg) { + if (!strcmp(alg, a->alg)) { + *jose = a; + + return 0; + } + a++; + } + + return 1; +} + +LWS_VISIBLE int +lws_gencrypto_jwe_enc_to_definition(const char *enc, + const struct lws_jose_jwe_alg **jose) +{ + const struct lws_jose_jwe_alg *e = lws_gencrypto_jwe_enc_map; + + while (e->alg) { + if (!strcmp(enc, e->alg)) { + *jose = e; + + return 0; + } + e++; + } + + return 1; +} + +size_t +lws_genhash_size(enum lws_genhash_types type) +{ + switch(type) { + case LWS_GENHASH_TYPE_UNKNOWN: + return 0; + 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; +} + +size_t +lws_genhmac_size(enum lws_genhmac_types type) +{ + switch(type) { + case LWS_GENHMAC_TYPE_UNKNOWN: + return 0; + case LWS_GENHMAC_TYPE_SHA256: + return 32; + case LWS_GENHMAC_TYPE_SHA384: + return 48; + case LWS_GENHMAC_TYPE_SHA512: + return 64; + } + + return 0; +} diff --git a/lib/tls/lws-genec-common.c b/lib/tls/lws-genec-common.c new file mode 100644 index 000000000..f9e7b1220 --- /dev/null +++ b/lib/tls/lws-genec-common.c @@ -0,0 +1,73 @@ +/* + * libwebsockets - generic EC api hiding the backend - common parts + * + * 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_genec provides an EC abstraction api in lws that works the + * same whether you are using openssl or mbedtls crypto functions underneath. + */ +#include "core/private.h" + +const struct lws_ec_curves * +lws_genec_curve(const struct lws_ec_curves *table, const char *name) +{ + const struct lws_ec_curves *c = lws_ec_curves; + + if (table) + c = table; + + while (c->name) { + if (!strcmp(name, c->name)) + return c; + c++; + } + + return NULL; +} + +LWS_VISIBLE void +lws_genec_destroy_elements(struct lws_gencrypto_keyelem *el) +{ + int n; + + for (n = 0; n < LWS_GENCRYPTO_EC_KEYEL_COUNT; n++) + if (el[n].buf) + lws_free_set_NULL(el[n].buf); +} + +static const char *enames[] = { "crv", "x", "d", "y" }; + +LWS_VISIBLE int +lws_genec_dump(struct lws_gencrypto_keyelem *el) +{ + int n; + + lwsl_info(" genec %p: crv: '%s'\n", el, + !!el[LWS_GENCRYPTO_EC_KEYEL_CRV].buf ? + (char *)el[LWS_GENCRYPTO_EC_KEYEL_CRV].buf: "no curve name"); + + for (n = LWS_GENCRYPTO_EC_KEYEL_X; n < LWS_GENCRYPTO_EC_KEYEL_COUNT; + n++) { + lwsl_info(" e: %s\n", enames[n]); + lwsl_hexdump_info(el[n].buf, el[n].len); + } + + lwsl_info("\n"); + + return 0; +} diff --git a/lib/tls/mbedtls/lws-genaes.c b/lib/tls/mbedtls/lws-genaes.c index 392e685b4..8f3d87894 100644 --- a/lib/tls/mbedtls/lws-genaes.c +++ b/lib/tls/mbedtls/lws-genaes.c @@ -28,7 +28,7 @@ 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, + enum enum_aes_modes mode, struct lws_gencrypto_keyelem *el, int padding, void *engine) { int n; diff --git a/lib/tls/mbedtls/lws-gencrypto.c b/lib/tls/mbedtls/lws-gencrypto.c new file mode 100644 index 000000000..8d2619340 --- /dev/null +++ b/lib/tls/mbedtls/lws-gencrypto.c @@ -0,0 +1,59 @@ +/* + * libwebsockets - generic crypto 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-gencrypto openssl-specific common code + */ + +#include "core/private.h" +#include "tls/mbedtls/private.h" + +mbedtls_md_type_t +lws_gencrypto_mbedtls_hash_to_MD_TYPE(enum lws_genhash_types hash_type) +{ + mbedtls_md_type_t h = -1; + + switch (hash_type) { + case LWS_GENHASH_TYPE_SHA1: + h = MBEDTLS_MD_SHA1; + break; + case LWS_GENHASH_TYPE_SHA256: + h = MBEDTLS_MD_SHA256; + break; + case LWS_GENHASH_TYPE_SHA384: + h = MBEDTLS_MD_SHA384; + break; + case LWS_GENHASH_TYPE_SHA512: + h = MBEDTLS_MD_SHA512; + break; + default: + break; + } + + return h; +} + +int +lws_gencrypto_mbedtls_rngf(void *context, unsigned char *buf, size_t len) +{ + if ((size_t)lws_get_random(context, buf, len) == len) + return 0; + + return -1; +} diff --git a/lib/tls/mbedtls/lws-genec.c b/lib/tls/mbedtls/lws-genec.c index e69de29bb..0b97ea852 100644 --- a/lib/tls/mbedtls/lws-genec.c +++ b/lib/tls/mbedtls/lws-genec.c @@ -0,0 +1,526 @@ +/* + * libwebsockets - generic EC api hiding the backend - mbedtls implementation + * + * 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_genec provides an EC abstraction api in lws that works the + * same whether you are using openssl or mbedtls crypto functions underneath. + */ +#include "core/private.h" +#include "tls/mbedtls/private.h" + +const struct lws_ec_curves lws_ec_curves[] = { + /* + * These are the curves we are willing to use by default... + * + * The 3 recommended+ (P-256) and optional curves in RFC7518 7.6 + * + * Specific keys lengths from RFC8422 p20 + */ + { "P-256", MBEDTLS_ECP_DP_SECP256R1, 32 }, + { "P-384", MBEDTLS_ECP_DP_SECP384R1, 48 }, + { "P-521", MBEDTLS_ECP_DP_SECP521R1, 66 }, + + { NULL, 0, 0 } +}; + +static int +lws_genec_keypair_import(struct lws_genec_ctx *ctx, enum enum_lws_dh_side side, + struct lws_gencrypto_keyelem *el) +{ + const struct lws_ec_curves *curve; + mbedtls_ecp_keypair kp; + int ret = -1; + + if (el[LWS_GENCRYPTO_EC_KEYEL_CRV].len < 4) { + lwsl_notice("%s: crv '%s' (%d)\n", __func__, + el[LWS_GENCRYPTO_EC_KEYEL_CRV].buf ? + (char *)el[LWS_GENCRYPTO_EC_KEYEL_CRV].buf : + "null", + el[LWS_GENCRYPTO_EC_KEYEL_CRV].len); + return -21; + } + + curve = lws_genec_curve(ctx->curve_table, + (char *)el[LWS_GENCRYPTO_EC_KEYEL_CRV].buf); + if (!curve) + return -22; + + if (el[LWS_GENCRYPTO_EC_KEYEL_D].len != curve->key_bytes || + el[LWS_GENCRYPTO_EC_KEYEL_X].len != curve->key_bytes || + el[LWS_GENCRYPTO_EC_KEYEL_Y].len != curve->key_bytes) + return -23; + + mbedtls_ecp_keypair_init(&kp); + if (mbedtls_ecp_group_load(&kp.grp, curve->tls_lib_nid)) + goto bail1; + + /* d (the private key) is directly an mpi */ + + if (mbedtls_mpi_read_binary(&kp.d, el[LWS_GENCRYPTO_EC_KEYEL_D].buf, + el[LWS_GENCRYPTO_EC_KEYEL_D].len)) + goto bail1; + + mbedtls_ecp_set_zero(&kp.Q); + + if (mbedtls_mpi_read_binary(&kp.Q.X, el[LWS_GENCRYPTO_EC_KEYEL_X].buf, + el[LWS_GENCRYPTO_EC_KEYEL_X].len)) + goto bail1; + + if (mbedtls_mpi_read_binary(&kp.Q.Y, el[LWS_GENCRYPTO_EC_KEYEL_Y].buf, + el[LWS_GENCRYPTO_EC_KEYEL_Y].len)) + goto bail1; + + switch (ctx->genec_alg) { + case LEGENEC_ECDH: + if (mbedtls_ecdh_get_params(ctx->u.ctx_ecdh, &kp, side)) + goto bail1; + break; + case LEGENEC_ECDSA: + if (mbedtls_ecdsa_from_keypair(ctx->u.ctx_ecdsa, &kp)) + goto bail1; + break; + default: + goto bail1; + } + + ret = 0; + +bail1: + mbedtls_ecp_keypair_free(&kp); + + return ret; +} + +LWS_VISIBLE int +lws_genecdh_create(struct lws_genec_ctx *ctx, struct lws_context *context, + const struct lws_ec_curves *curve_table) +{ + memset(ctx, 0, sizeof(*ctx)); + ctx->context = context; + ctx->curve_table = curve_table; + ctx->genec_alg = LEGENEC_ECDH; + + ctx->u.ctx_ecdh = lws_zalloc(sizeof(*ctx->u.ctx_ecdh), "genecdh"); + if (!ctx->u.ctx_ecdh) + return 1; + + mbedtls_ecdh_init(ctx->u.ctx_ecdh); + + return 0; +} + +LWS_VISIBLE int +lws_genecdsa_create(struct lws_genec_ctx *ctx, struct lws_context *context, + const struct lws_ec_curves *curve_table) +{ + memset(ctx, 0, sizeof(*ctx)); + ctx->context = context; + ctx->curve_table = curve_table; + ctx->genec_alg = LEGENEC_ECDSA; + + ctx->u.ctx_ecdh = lws_zalloc(sizeof(*ctx->u.ctx_ecdh), "genecdh"); + if (!ctx->u.ctx_ecdh) + return 1; + + mbedtls_ecdh_init(ctx->u.ctx_ecdh); + + return 0; +} + + +LWS_VISIBLE int +lws_genecdh_set_key(struct lws_genec_ctx *ctx, struct lws_gencrypto_keyelem *el, + enum enum_lws_dh_side side) +{ + if (ctx->genec_alg != LEGENEC_ECDH) + return -1; + + return lws_genec_keypair_import(ctx, side, el); +} + +LWS_VISIBLE int +lws_genecdsa_set_key(struct lws_genec_ctx *ctx, + struct lws_gencrypto_keyelem *el) +{ + if (ctx->genec_alg != LEGENEC_ECDSA) + return -1; + + return lws_genec_keypair_import(ctx, 0, el); +} + +LWS_VISIBLE void +lws_genec_destroy(struct lws_genec_ctx *ctx) +{ + switch (ctx->genec_alg) { + case LEGENEC_ECDH: + if (ctx->u.ctx_ecdh) { + mbedtls_ecdh_free(ctx->u.ctx_ecdh); + lws_free(ctx->u.ctx_ecdh); + ctx->u.ctx_ecdh = NULL; + } + break; + case LEGENEC_ECDSA: + if (ctx->u.ctx_ecdsa) { + mbedtls_ecdsa_free(ctx->u.ctx_ecdsa); + lws_free(ctx->u.ctx_ecdsa); + ctx->u.ctx_ecdsa = NULL; + } + break; + default: + break; + } +} + +LWS_VISIBLE int +lws_genecdh_new_keypair(struct lws_genec_ctx *ctx, enum enum_lws_dh_side side, + const char *curve_name, + struct lws_gencrypto_keyelem *el) +{ + const struct lws_ec_curves *curve; + mbedtls_ecdsa_context ecdsa; + mbedtls_ecp_keypair *kp; + mbedtls_mpi *mpi[3]; + int n; + + if (ctx->genec_alg != LEGENEC_ECDH) + return -1; + + curve = lws_genec_curve(ctx->curve_table, curve_name); + if (!curve) { + lwsl_err("%s: curve '%s' not supported\n", + __func__, curve_name); + + return -22; + } + + mbedtls_ecdsa_init(&ecdsa); + n = mbedtls_ecdsa_genkey(&ecdsa, curve->tls_lib_nid, lws_gencrypto_mbedtls_rngf, + ctx->context); + if (n) { + lwsl_err("mbedtls_ecdsa_genkey failed 0x%x\n", -n); + goto bail1; + } + + kp = (mbedtls_ecp_keypair *)&ecdsa; + + n = mbedtls_ecdh_get_params(ctx->u.ctx_ecdh, kp, side); + if (n) { + lwsl_err("mbedtls_ecdh_get_params failed 0x%x\n", -n); + goto bail1; + } + + /* + * we need to capture the individual element BIGNUMs into + * lws_gencrypto_keyelem, so they can be serialized, used in jwk etc + */ + + mpi[0] = &kp->Q.X; + mpi[1] = &kp->d; + mpi[2] = &kp->Q.Y; + + el[LWS_GENCRYPTO_EC_KEYEL_CRV].len = strlen(curve_name) + 1; + el[LWS_GENCRYPTO_EC_KEYEL_CRV].buf = + lws_malloc(el[LWS_GENCRYPTO_EC_KEYEL_CRV].len, "ec"); + if (!el[LWS_GENCRYPTO_EC_KEYEL_CRV].buf) + goto bail1; + strcpy((char *)el[LWS_GENCRYPTO_EC_KEYEL_CRV].buf, curve_name); + + for (n = LWS_GENCRYPTO_EC_KEYEL_X; n < LWS_GENCRYPTO_EC_KEYEL_COUNT; n++) { + el[n].len = curve->key_bytes; + el[n].buf = lws_malloc(curve->key_bytes, "ec"); + if (!el[n].buf) + goto bail2; + + if (mbedtls_mpi_write_binary(mpi[n - 1], el[n].buf, + curve->key_bytes)) + goto bail2; + } + + mbedtls_ecdsa_free(&ecdsa); + + return 0; + +bail2: + for (n = 0; n < LWS_GENCRYPTO_EC_KEYEL_COUNT; n++) + if (el[n].buf) + lws_free_set_NULL(el[n].buf); +bail1: + mbedtls_ecdsa_free(&ecdsa); + + lws_free_set_NULL(ctx->u.ctx_ecdh); + + return -1; +} + +LWS_VISIBLE int +lws_genecdsa_new_keypair(struct lws_genec_ctx *ctx, const char *curve_name, + struct lws_gencrypto_keyelem *el) +{ + const struct lws_ec_curves *curve; + mbedtls_ecp_keypair *kp; + mbedtls_mpi *mpi[3]; + int n; + + if (ctx->genec_alg != LEGENEC_ECDSA) + return -1; + + curve = lws_genec_curve(ctx->curve_table, curve_name); + if (!curve) { + lwsl_err("%s: curve '%s' not supported\n", + __func__, curve_name); + + return -22; + } + + mbedtls_ecdsa_init(ctx->u.ctx_ecdsa); + n = mbedtls_ecdsa_genkey(ctx->u.ctx_ecdsa, curve->tls_lib_nid, + lws_gencrypto_mbedtls_rngf, ctx->context); + if (n) { + lwsl_err("mbedtls_ecdsa_genkey failed 0x%x\n", -n); + goto bail1; + } + + /* + * we need to capture the individual element BIGNUMs into + * lws_gencrypto_keyelems, so they can be serialized, used in jwk etc + */ + + kp = (mbedtls_ecp_keypair *)&ctx->u.ctx_ecdsa; + + mpi[0] = &kp->Q.X; + mpi[1] = &kp->d; + mpi[2] = &kp->Q.Y; + + el[LWS_GENCRYPTO_EC_KEYEL_CRV].len = strlen(curve_name) + 1; + el[LWS_GENCRYPTO_EC_KEYEL_CRV].buf = + lws_malloc(el[LWS_GENCRYPTO_EC_KEYEL_CRV].len, "ec"); + if (!el[LWS_GENCRYPTO_EC_KEYEL_CRV].buf) + goto bail1; + strcpy((char *)el[LWS_GENCRYPTO_EC_KEYEL_CRV].buf, curve_name); + + for (n = LWS_GENCRYPTO_EC_KEYEL_X; n < LWS_GENCRYPTO_EC_KEYEL_COUNT; n++) { + el[n].len = curve->key_bytes; + el[n].buf = lws_malloc(curve->key_bytes, "ec"); + if (!el[n].buf) + goto bail2; + + if (mbedtls_mpi_write_binary(mpi[n - 1], el[n].buf, + curve->key_bytes)) + goto bail2; + } + + return 0; + +bail2: + for (n = 0; n < LWS_GENCRYPTO_EC_KEYEL_COUNT; n++) + if (el[n].buf) + lws_free_set_NULL(el[n].buf); +bail1: + + lws_free_set_NULL(ctx->u.ctx_ecdsa); + + return -1; +} + +LWS_VISIBLE LWS_EXTERN int +lws_genecdsa_hash_sign(struct lws_genec_ctx *ctx, const uint8_t *in, + enum lws_genhash_types hash_type, + uint8_t *sig, size_t sig_len) +{ + mbedtls_md_type_t md_type = + lws_gencrypto_mbedtls_hash_to_MD_TYPE(hash_type); + size_t slen = sig_len; + int n; + + if (ctx->genec_alg != LEGENEC_ECDSA) + return -1; + + if (md_type < 0) + return -2; + + + n = mbedtls_ecdsa_write_signature(ctx->u.ctx_ecdsa, md_type, in, + lws_genhash_size(hash_type), sig, + &slen, lws_gencrypto_mbedtls_rngf, + ctx->context); + if (n) { + lwsl_err("%s: mbedtls_ecdsa_write_signature failed: -0x%x\n", + __func__, -n); + + goto bail; + } + + return (int)slen; +bail: + + return -3; +} + +LWS_VISIBLE LWS_EXTERN int +lws_genecdsa_hash_sig_verify(struct lws_genec_ctx *ctx, const uint8_t *in, + enum lws_genhash_types hash_type, + const uint8_t *sig, size_t sig_len) +{ + mbedtls_md_type_t md_type = + lws_gencrypto_mbedtls_hash_to_MD_TYPE(hash_type); + int n; + + if (ctx->genec_alg != LEGENEC_ECDSA) + return -1; + + if (md_type < 0) + return -2; + + n = mbedtls_ecdsa_read_signature(ctx->u.ctx_ecdsa, in, + lws_genhash_size(hash_type), sig, + sig_len); + if (n) { + lwsl_err("%s: mbedtls_ecdsa_write_signature failed: -0x%x\n", + __func__, -n); + + goto bail; + } + + return 0; +bail: + + return -3; +} + +#if 0 +LWS_VISIBLE int +lws_genec_public_decrypt(struct lws_genec_ctx *ctx, const uint8_t *in, + size_t in_len, uint8_t *out, size_t out_max) +{ + size_t olen = 0; + int n; + + ctx->ctx->len = in_len; + n = mbedtls_rsa_rsaes_pkcs1_v15_decrypt(ctx->ctx, NULL, NULL, + MBEDTLS_RSA_PUBLIC, + &olen, in, out, out_max); + if (n) { + lwsl_notice("%s: -0x%x\n", __func__, -n); + + return -1; + } + + return olen; +} + +LWS_VISIBLE int +lws_genec_public_encrypt(struct lws_genec_ctx *ctx, const uint8_t *in, + size_t in_len, uint8_t *out) +{ + int n; + + //ctx->ctx->len = in_len; // ??? + ctx->ctx->padding = MBEDTLS_RSA_PKCS_V15; + n = mbedtls_rsa_rsaes_pkcs1_v15_encrypt(ctx->ctx, _rngf, ctx->context, + MBEDTLS_RSA_PRIVATE, + in_len, in, out); + if (n) { + lwsl_notice("%s: -0x%x: in_len: %d\n", __func__, -n, + (int)in_len); + + return -1; + } + + return 0; +} + + +LWS_VISIBLE int +lws_genec_render_pkey_asn1(struct lws_genec_ctx *ctx, int _private, + uint8_t *pkey_asn1, size_t pkey_asn1_len) +{ + uint8_t *p = pkey_asn1, *totlen, *end = pkey_asn1 + pkey_asn1_len - 1; + mbedtls_mpi *mpi[LWS_GENCRYPTO_RSA_KEYEL_COUNT] = { + &ctx->ctx->N, &ctx->ctx->E, &ctx->ctx->D, &ctx->ctx->P, + &ctx->ctx->Q, &ctx->ctx->DP, &ctx->ctx->DQ, + &ctx->ctx->QP, + }; + int n; + + /* 30 82 - sequence + * 09 29 <-- length(0x0929) less 4 bytes + * 02 01 <- length (1) + * 00 + * 02 82 + * 02 01 <- length (513) N + * ... + * + * 02 03 <- length (3) E + * 01 00 01 + * + * 02 82 + * 02 00 <- length (512) D P Q EXP1 EXP2 COEFF + * + * */ + + *p++ = 0x30; + *p++ = 0x82; + totlen = p; + p += 2; + + *p++ = 0x02; + *p++ = 0x01; + *p++ = 0x00; + + for (n = 0; n < LWS_GENCRYPTO_RSA_KEYEL_COUNT; n++) { + int m = mbedtls_mpi_size(mpi[n]); + uint8_t *elen; + + *p++ = 0x02; + elen = p; + if (m < 0x7f) + *p++ = m; + else { + *p++ = 0x82; + *p++ = m >> 8; + *p++ = m & 0xff; + } + + if (p + m > end) + return -1; + + mbedtls_mpi_write_binary(mpi[n], p, m); + if (p[0] & 0x80) { + p[0] = 0x00; + mbedtls_mpi_write_binary(mpi[n], &p[1], m); + m++; + } + if (m < 0x7f) + *elen = m; + else { + *elen++ = 0x82; + *elen++ = m >> 8; + *elen = m & 0xff; + } + p += m; + } + + n = lws_ptr_diff(p, pkey_asn1); + + *totlen++ = (n - 4) >> 8; + *totlen = (n - 4) & 0xff; + + return n; +} +#endif diff --git a/lib/tls/mbedtls/lws-genhash.c b/lib/tls/mbedtls/lws-genhash.c index ce4ee6e38..01c453212 100644 --- a/lib/tls/mbedtls/lws-genhash.c +++ b/lib/tls/mbedtls/lws-genhash.c @@ -30,23 +30,6 @@ #define MBA(fn) fn #endif -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) { @@ -122,21 +105,6 @@ lws_genhash_destroy(struct lws_genhash_ctx *ctx, void *result) return 0; } -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) diff --git a/lib/tls/mbedtls/lws-genrsa.c b/lib/tls/mbedtls/lws-genrsa.c index 6e1d61ebb..4004777f0 100644 --- a/lib/tls/mbedtls/lws-genrsa.c +++ b/lib/tls/mbedtls/lws-genrsa.c @@ -19,16 +19,17 @@ * MA 02110-1301 USA * * lws_genrsa provides an RSA abstraction api in lws that works the - * same whether you are using openssl or mbedtls hash functions underneath. + * same whether you are using openssl or mbedtls crypto functions underneath. */ #include "core/private.h" +#include "tls/mbedtls/private.h" LWS_VISIBLE void -lws_jwk_destroy_genrsa_elements(struct lws_jwk_elements *el) +lws_genrsa_destroy_elements(struct lws_gencrypto_keyelem *el) { int n; - for (n = 0; n < LWS_COUNT_RSA_KEY_ELEMENTS; n++) + for (n = 0; n < LWS_GENCRYPTO_RSA_KEYEL_COUNT; n++) if (el[n].buf) lws_free_set_NULL(el[n].buf); } @@ -36,7 +37,7 @@ lws_jwk_destroy_genrsa_elements(struct lws_jwk_elements *el) static int mode_map[] = { MBEDTLS_RSA_PKCS_V15, MBEDTLS_RSA_PKCS_V21 }; LWS_VISIBLE int -lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_jwk_elements *el, +lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_gencrypto_keyelem *el, struct lws_context *context, enum enum_genrsa_mode mode) { memset(ctx, 0, sizeof(*ctx)); @@ -55,13 +56,13 @@ lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_jwk_elements *el, { int n; - mbedtls_mpi *mpi[LWS_COUNT_RSA_KEY_ELEMENTS] = { + mbedtls_mpi *mpi[LWS_GENCRYPTO_RSA_KEYEL_COUNT] = { &ctx->ctx->E, &ctx->ctx->N, &ctx->ctx->D, &ctx->ctx->P, &ctx->ctx->Q, &ctx->ctx->DP, &ctx->ctx->DQ, &ctx->ctx->QP, }; - for (n = 0; n < LWS_COUNT_RSA_KEY_ELEMENTS; n++) + for (n = 0; n < LWS_GENCRYPTO_RSA_KEYEL_COUNT; n++) if (el[n].buf && mbedtls_mpi_read_binary(mpi[n], el[n].buf, el[n].len)) { @@ -72,7 +73,7 @@ lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_jwk_elements *el, } } - ctx->ctx->len = el[JWK_RSA_KEYEL_N].len; + ctx->ctx->len = el[LWS_GENCRYPTO_RSA_KEYEL_N].len; return 0; } @@ -88,7 +89,7 @@ _rngf(void *context, unsigned char *buf, size_t len) LWS_VISIBLE int lws_genrsa_new_keypair(struct lws_context *context, struct lws_genrsa_ctx *ctx, - enum enum_genrsa_mode mode, struct lws_jwk_elements *el, + enum enum_genrsa_mode mode, struct lws_gencrypto_keyelem *el, int bits) { int n; @@ -113,13 +114,13 @@ lws_genrsa_new_keypair(struct lws_context *context, struct lws_genrsa_ctx *ctx, } { - mbedtls_mpi *mpi[LWS_COUNT_RSA_KEY_ELEMENTS] = { + mbedtls_mpi *mpi[LWS_GENCRYPTO_RSA_KEYEL_COUNT] = { &ctx->ctx->E, &ctx->ctx->N, &ctx->ctx->D, &ctx->ctx->P, &ctx->ctx->Q, &ctx->ctx->DP, &ctx->ctx->DQ, &ctx->ctx->QP, }; - for (n = 0; n < LWS_COUNT_RSA_KEY_ELEMENTS; n++) + for (n = 0; n < LWS_GENCRYPTO_RSA_KEYEL_COUNT; n++) if (mbedtls_mpi_size(mpi[n])) { el[n].buf = lws_malloc( mbedtls_mpi_size(mpi[n]), "genrsakey"); @@ -134,7 +135,7 @@ lws_genrsa_new_keypair(struct lws_context *context, struct lws_genrsa_ctx *ctx, return 0; cleanup: - for (n = 0; n < LWS_COUNT_RSA_KEY_ELEMENTS; n++) + for (n = 0; n < LWS_GENCRYPTO_RSA_KEYEL_COUNT; n++) if (el[n].buf) lws_free_set_NULL(el[n].buf); cleanup_1: @@ -212,35 +213,12 @@ lws_genrsa_public_encrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in, return 0; } -static int -lws_genrsa_genrsa_hash_to_mbed_hash(enum lws_genhash_types hash_type) -{ - int h = -1; - - switch (hash_type) { - case LWS_GENHASH_TYPE_SHA1: - h = MBEDTLS_MD_SHA1; - break; - case LWS_GENHASH_TYPE_SHA256: - h = MBEDTLS_MD_SHA256; - break; - case LWS_GENHASH_TYPE_SHA384: - h = MBEDTLS_MD_SHA384; - break; - case LWS_GENHASH_TYPE_SHA512: - h = MBEDTLS_MD_SHA512; - break; - } - - return h; -} - LWS_VISIBLE int -lws_genrsa_public_verify(struct lws_genrsa_ctx *ctx, const uint8_t *in, +lws_genrsa_hash_sig_verify(struct lws_genrsa_ctx *ctx, const uint8_t *in, enum lws_genhash_types hash_type, const uint8_t *sig, size_t sig_len) { - int n, h = lws_genrsa_genrsa_hash_to_mbed_hash(hash_type); + int n, h = lws_gencrypto_mbedtls_hash_to_MD_TYPE(hash_type); if (h < 0) return -1; @@ -269,11 +247,11 @@ lws_genrsa_public_verify(struct lws_genrsa_ctx *ctx, const uint8_t *in, } LWS_VISIBLE int -lws_genrsa_public_sign(struct lws_genrsa_ctx *ctx, const uint8_t *in, +lws_genrsa_hash_sign(struct lws_genrsa_ctx *ctx, const uint8_t *in, enum lws_genhash_types hash_type, uint8_t *sig, size_t sig_len) { - int n, h = lws_genrsa_genrsa_hash_to_mbed_hash(hash_type); + int n, h = lws_gencrypto_mbedtls_hash_to_MD_TYPE(hash_type); if (h < 0) return -1; @@ -314,7 +292,7 @@ lws_genrsa_render_pkey_asn1(struct lws_genrsa_ctx *ctx, int _private, uint8_t *pkey_asn1, size_t pkey_asn1_len) { uint8_t *p = pkey_asn1, *totlen, *end = pkey_asn1 + pkey_asn1_len - 1; - mbedtls_mpi *mpi[LWS_COUNT_RSA_KEY_ELEMENTS] = { + mbedtls_mpi *mpi[LWS_GENCRYPTO_RSA_KEYEL_COUNT] = { &ctx->ctx->N, &ctx->ctx->E, &ctx->ctx->D, &ctx->ctx->P, &ctx->ctx->Q, &ctx->ctx->DP, &ctx->ctx->DQ, &ctx->ctx->QP, @@ -346,7 +324,7 @@ lws_genrsa_render_pkey_asn1(struct lws_genrsa_ctx *ctx, int _private, *p++ = 0x01; *p++ = 0x00; - for (n = 0; n < LWS_COUNT_RSA_KEY_ELEMENTS; n++) { + for (n = 0; n < LWS_GENCRYPTO_RSA_KEYEL_COUNT; n++) { int m = mbedtls_mpi_size(mpi[n]); uint8_t *elen; diff --git a/lib/tls/mbedtls/mbedtls-client.c b/lib/tls/mbedtls/mbedtls-client.c index 84270c15b..719885ead 100644 --- a/lib/tls/mbedtls/mbedtls-client.c +++ b/lib/tls/mbedtls/mbedtls-client.c @@ -177,7 +177,7 @@ lws_tls_client_confirm_peer_cert(struct lws *wsi, char *ebuf, int ebuf_len) "server's cert didn't look good, X509_V_ERR = %d: %s\n", n, ERR_error_string(n, sb)); lwsl_info("%s\n", ebuf); - lws_ssl_elaborate_error(); + lws_tls_err_describe(); return -1; } diff --git a/lib/tls/mbedtls/mbedtls-server.c b/lib/tls/mbedtls/mbedtls-server.c index 78e308491..fa0eef99c 100644 --- a/lib/tls/mbedtls/mbedtls-server.c +++ b/lib/tls/mbedtls/mbedtls-server.c @@ -261,7 +261,7 @@ lws_tls_server_new_nonblocking(struct lws *wsi, lws_sockfd_type accept_fd) if (wsi->tls.ssl == NULL) { lwsl_err("SSL_new failed: errno %d\n", errno); - lws_ssl_elaborate_error(); + lws_tls_err_describe(); return 1; } @@ -453,7 +453,7 @@ lws_tls_acme_sni_cert_create(struct lws_vhost *vhost, const char *san_a, int buflen = 0x560; uint8_t *buf = lws_malloc(buflen, "tmp cert buf"), *p = buf, *pkey_asn1; struct lws_genrsa_ctx ctx; - struct lws_jwk_elements el; + struct lws_gencrypto_keyelem el; uint8_t digest[32]; struct lws_genhash_ctx hash_ctx; int pkey_asn1_len = 3 * 1024; @@ -464,7 +464,7 @@ lws_tls_acme_sni_cert_create(struct lws_vhost *vhost, const char *san_a, n = lws_genrsa_new_keypair(vhost->context, &ctx, &el, keybits); if (n < 0) { - lws_jwk_destroy_genrsa_elements(&el); + lws_genrsa_destroy_elements(&el); goto bail1; } @@ -498,8 +498,8 @@ lws_tls_acme_sni_cert_create(struct lws_vhost *vhost, const char *san_a, /* we need to drop 1 + (keybits / 8) bytes of n in here, 00 + key */ *p++ = 0x00; - memcpy(p, el.e[JWK_RSA_KEYEL_N].buf, el.e[JWK_RSA_KEYEL_N].len); - p += el.e[JWK_RSA_KEYEL_N].len; + memcpy(p, el.e[LWS_GENCRYPTO_RSA_KEYEL_N].buf, el.e[LWS_GENCRYPTO_RSA_KEYEL_N].len); + p += el.e[LWS_GENCRYPTO_RSA_KEYEL_N].len; memcpy(p, ss_cert_san_leadin, sizeof(ss_cert_san_leadin)); p += sizeof(ss_cert_san_leadin); @@ -530,7 +530,7 @@ lws_tls_acme_sni_cert_create(struct lws_vhost *vhost, const char *san_a, /* sign the hash */ - n = lws_genrsa_public_sign(&ctx, digest, LWS_GENHASH_TYPE_SHA256, p, + n = lws_genrsa_hash_sign(&ctx, digest, LWS_GENHASH_TYPE_SHA256, p, buflen - lws_ptr_diff(p, buf)); if (n < 0) goto bail2; @@ -568,7 +568,7 @@ lws_tls_acme_sni_cert_create(struct lws_vhost *vhost, const char *san_a, } lws_genrsa_destroy(&ctx); - lws_jwk_destroy_genrsa_elements(&el); + lws_genrsa_destroy_elements(&el); lws_free(buf); @@ -576,7 +576,7 @@ lws_tls_acme_sni_cert_create(struct lws_vhost *vhost, const char *san_a, bail2: lws_genrsa_destroy(&ctx); - lws_jwk_destroy_genrsa_elements(&el); + lws_genrsa_destroy_elements(&el); bail1: lws_free(buf); diff --git a/lib/tls/mbedtls/private.h b/lib/tls/mbedtls/private.h new file mode 100644 index 000000000..8d3d1b524 --- /dev/null +++ b/lib/tls/mbedtls/private.h @@ -0,0 +1,28 @@ +/* + * 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 + * + * gencrypto mbedtls-specific helper declarations + */ + +mbedtls_md_type_t +lws_gencrypto_mbedtls_hash_to_MD_TYPE(enum lws_genhash_types hash_type); + +int +lws_gencrypto_mbedtls_rngf(void *context, unsigned char *buf, size_t len); diff --git a/lib/tls/mbedtls/ssl.c b/lib/tls/mbedtls/ssl.c index b81f88862..82444bbaf 100644 --- a/lib/tls/mbedtls/ssl.c +++ b/lib/tls/mbedtls/ssl.c @@ -23,7 +23,7 @@ #include void -lws_ssl_elaborate_error(void) +lws_tls_err_describe(void) { } diff --git a/lib/tls/openssl/lws-genaes.c b/lib/tls/openssl/lws-genaes.c index 4cb6db4a4..76cf5254e 100644 --- a/lib/tls/openssl/lws-genaes.c +++ b/lib/tls/openssl/lws-genaes.c @@ -31,7 +31,7 @@ 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, + enum enum_aes_modes mode, struct lws_gencrypto_keyelem *el, int padding, void *engine) { int n; diff --git a/lib/tls/openssl/lws-gencrypto.c b/lib/tls/openssl/lws-gencrypto.c new file mode 100644 index 000000000..00c63c810 --- /dev/null +++ b/lib/tls/openssl/lws-gencrypto.c @@ -0,0 +1,75 @@ +/* + * libwebsockets - generic crypto 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-gencrypto openssl-specific common code + */ + +#include "core/private.h" +#include "tls/openssl/private.h" + +int +lws_gencrypto_openssl_hash_to_NID(enum lws_genhash_types hash_type) +{ + int h = -1; + + switch (hash_type) { + case LWS_GENHASH_TYPE_UNKNOWN: + break; + case LWS_GENHASH_TYPE_SHA1: + h = NID_sha1; + break; + case LWS_GENHASH_TYPE_SHA256: + h = NID_sha256; + break; + case LWS_GENHASH_TYPE_SHA384: + h = NID_sha384; + break; + case LWS_GENHASH_TYPE_SHA512: + h = NID_sha512; + break; + } + + return h; +} + +const EVP_MD * +lws_gencrypto_openssl_hash_to_EVP_MD(enum lws_genhash_types hash_type) +{ + const EVP_MD *h = NULL; + + switch (hash_type) { + case LWS_GENHASH_TYPE_UNKNOWN: + break; + case LWS_GENHASH_TYPE_SHA1: + h = EVP_sha1(); + break; + case LWS_GENHASH_TYPE_SHA256: + h = EVP_sha256(); + break; + case LWS_GENHASH_TYPE_SHA384: + h = EVP_sha384(); + break; + case LWS_GENHASH_TYPE_SHA512: + h = EVP_sha512(); + break; + } + + return h; +} diff --git a/lib/tls/openssl/lws-genec.c b/lib/tls/openssl/lws-genec.c index e69de29bb..b8205017a 100644 --- a/lib/tls/openssl/lws-genec.c +++ b/lib/tls/openssl/lws-genec.c @@ -0,0 +1,431 @@ +/* + * libwebsockets - generic EC api hiding the backend - openssl implementation + * + * 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_genec provides an EC abstraction api in lws that works the + * same whether you are using openssl or mbedtls crypto functions underneath. + */ +#include "core/private.h" +#include "tls/openssl/private.h" + +const struct lws_ec_curves lws_ec_curves[] = { + /* + * These are the curves we are willing to use by default... + * + * The 3 recommended+ (P-256) and optional curves in RFC7518 7.6 + * + * Specific keys lengths from RFC8422 p20 + */ + { "P-256", NID_X9_62_prime256v1, 32 }, + { "P-384", NID_secp384r1, 48 }, + { "P-521", NID_secp521r1, 66 }, + + { NULL, 0, 0 } +}; + +static int +lws_genec_eckey_import(int nid, EVP_PKEY *pkey, struct lws_gencrypto_keyelem *el) +{ + EC_KEY *ec = EC_KEY_new_by_curve_name(nid); + BIGNUM *bn_d, *bn_x, *bn_y; + int n; + + if (!ec) + return -1; + + /* + * EC_KEY contains + * + * EC_GROUP * group + * EC_POINT * pub_key + * BIGNUM * priv_key (ie, d) + */ + + bn_x = BN_bin2bn(el[LWS_GENCRYPTO_EC_KEYEL_X].buf, + el[LWS_GENCRYPTO_EC_KEYEL_X].len, NULL); + if (!bn_x) { + lwsl_err("%s: BN_bin2bn (x) fail\n", __func__); + goto bail; + } + bn_y = BN_bin2bn(el[LWS_GENCRYPTO_EC_KEYEL_Y].buf, + el[LWS_GENCRYPTO_EC_KEYEL_Y].len, NULL); + if (!bn_y) { + lwsl_err("%s: BN_bin2bn (y) fail\n", __func__); + goto bail1; + } + + n = EC_KEY_set_public_key_affine_coordinates(ec, bn_x, bn_y); + BN_free(bn_x); + BN_free(bn_y); + if (n != 1) { + lwsl_err("%s: EC_KEY_set_public_key_affine_coordinates fail:\n", + __func__); + lws_tls_err_describe(); + goto bail; + } + + bn_d = BN_bin2bn(el[LWS_GENCRYPTO_EC_KEYEL_D].buf, + el[LWS_GENCRYPTO_EC_KEYEL_D].len, NULL); + if (!bn_d) { + lwsl_err("%s: BN_bin2bn (d) fail\n", __func__); + goto bail; + } + + n = EC_KEY_set_private_key(ec, bn_d); + BN_free(bn_d); + if (n != 1) { + lwsl_err("%s: EC_KEY_set_private_key fail\n", __func__); + goto bail; + } + + if (EVP_PKEY_assign_EC_KEY(pkey, ec) != 1) { + lwsl_err("%s: EVP_PKEY_set1_EC_KEY failed\n", __func__); + goto bail; + } + + return 0; + +bail1: + BN_free(bn_x); +bail: + EC_KEY_free(ec); + + return -1; +} + +static int +lws_genec_keypair_import(const struct lws_ec_curves *curve_table, + EVP_PKEY_CTX **pctx, struct lws_gencrypto_keyelem *el) +{ + EVP_PKEY *pkey = NULL; + const struct lws_ec_curves *curve; + + if (el[LWS_GENCRYPTO_EC_KEYEL_CRV].len < 4) + return -2; + + curve = lws_genec_curve(curve_table, + (char *)el[LWS_GENCRYPTO_EC_KEYEL_CRV].buf); + if (!curve) + return -3; + + if (el[LWS_GENCRYPTO_EC_KEYEL_D].len != curve->key_bytes || + el[LWS_GENCRYPTO_EC_KEYEL_X].len != curve->key_bytes || + el[LWS_GENCRYPTO_EC_KEYEL_Y].len != curve->key_bytes) + return -4; + + pkey = EVP_PKEY_new(); + if (!pkey) + return -7; + + if (lws_genec_eckey_import(curve->tls_lib_nid, pkey, el)) { + lwsl_err("%s: lws_genec_eckey_import fail\n", __func__); + goto bail; + } + + *pctx = EVP_PKEY_CTX_new(pkey, NULL); + EVP_PKEY_free(pkey); + pkey = NULL; + if (!*pctx) + goto bail; + + return 0; + +bail: + if (pkey) + EVP_PKEY_free(pkey); + + if (*pctx) { + EVP_PKEY_CTX_free(*pctx); + *pctx = NULL; + } + + return -9; +} + +LWS_VISIBLE int +lws_genecdh_create(struct lws_genec_ctx *ctx, struct lws_context *context, + const struct lws_ec_curves *curve_table) +{ + ctx->context = context; + ctx->ctx = NULL; + ctx->ctx_peer = NULL; + ctx->curve_table = curve_table; + ctx->genec_alg = LEGENEC_ECDH; + + return 0; +} + +LWS_VISIBLE int +lws_genecdsa_create(struct lws_genec_ctx *ctx, struct lws_context *context, + const struct lws_ec_curves *curve_table) +{ + ctx->context = context; + ctx->ctx = NULL; + ctx->ctx_peer = NULL; + ctx->curve_table = curve_table; + ctx->genec_alg = LEGENEC_ECDSA; + + return 0; +} + +LWS_VISIBLE int +lws_genecdh_set_key(struct lws_genec_ctx *ctx, struct lws_gencrypto_keyelem *el, + enum enum_lws_dh_side side) +{ + if (ctx->genec_alg != LEGENEC_ECDH) + return -1; + + return lws_genec_keypair_import(ctx->curve_table, + side ? &ctx->ctx : &ctx->ctx_peer, el); +} + +LWS_VISIBLE int +lws_genecdsa_set_key(struct lws_genec_ctx *ctx, + struct lws_gencrypto_keyelem *el) +{ + if (ctx->genec_alg != LEGENEC_ECDSA) + return -1; + + return lws_genec_keypair_import(ctx->curve_table, &ctx->ctx, el); +} + +static void +lws_genec_keypair_destroy(EVP_PKEY_CTX **pctx) +{ + if (!*pctx) + return; + EVP_PKEY_CTX_free(*pctx); + *pctx = NULL; +} + +LWS_VISIBLE void +lws_genec_destroy(struct lws_genec_ctx *ctx) +{ + if (ctx->ctx) + lws_genec_keypair_destroy(&ctx->ctx); + if (ctx->ctx_peer) + lws_genec_keypair_destroy(&ctx->ctx_peer); +} + +static int +lws_genec_new_keypair(struct lws_genec_ctx *ctx, enum enum_lws_dh_side side, + const char *curve_name, struct lws_gencrypto_keyelem *el) +{ + const struct lws_ec_curves *curve; + const EC_POINT *pubkey; + EVP_PKEY *pkey = NULL; + int ret = -29, n, m; + BIGNUM *bn[3]; + EC_KEY *ec; + + if (ctx->genec_alg != LEGENEC_ECDH) + return -1; + + curve = lws_genec_curve(ctx->curve_table, curve_name); + if (!curve) { + lwsl_err("%s: curve '%s' not supported\n", + __func__, curve_name); + + return -22; + } + + ec = EC_KEY_new_by_curve_name(curve->tls_lib_nid); + if (!ec) + return -23; + + if (EC_KEY_generate_key(ec) != 1) + goto bail; + + pkey = EVP_PKEY_new(); + if (!pkey) + goto bail; + + if (EVP_PKEY_set1_EC_KEY(pkey, ec) != 1) { + lwsl_err("%s: EVP_PKEY_assign_EC_KEY failed\n", __func__); + goto bail1; + } + + ctx->ctx = EVP_PKEY_CTX_new(pkey, NULL); + if (!ctx->ctx) { + lwsl_err("%s: EVP_PKEY_CTX_new failed\n", __func__); + goto bail1; + } + + /* + * we need to capture the individual element BIGNUMs into + * lws_gencrypto_keyelem, so they can be serialized, used in jwk etc + */ + + pubkey = EC_KEY_get0_public_key(ec); + if (!pubkey) + goto bail1; + + bn[0] = BN_new(); + bn[1] = (BIGNUM *)EC_KEY_get0_private_key(ec); + bn[2] = BN_new(); + + if (EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(ec), + pubkey, bn[0], bn[2], NULL) != 1) { + lwsl_err("%s: EC_POINT_get_affine_coordinates_GFp failed\n", + __func__); + goto bail2; + } + + el[LWS_GENCRYPTO_EC_KEYEL_CRV].len = strlen(curve_name) + 1; + el[LWS_GENCRYPTO_EC_KEYEL_CRV].buf = + lws_malloc(el[LWS_GENCRYPTO_EC_KEYEL_CRV].len, "ec"); + if (!el[LWS_GENCRYPTO_EC_KEYEL_CRV].buf) + goto bail2; + + strcpy((char *)el[LWS_GENCRYPTO_EC_KEYEL_CRV].buf, curve_name); + + for (n = LWS_GENCRYPTO_EC_KEYEL_X; n < LWS_GENCRYPTO_EC_KEYEL_COUNT; + n++) { + el[n].len = curve->key_bytes; + el[n].buf = lws_malloc(curve->key_bytes, "ec"); + if (!el[n].buf) + goto bail2; + + m = BN_bn2bin(bn[n - 1], el[n].buf); + if (m != el[n].len) + goto bail2; + } + + ret = 0; + +bail2: + BN_free(bn[0]); + BN_free(bn[2]); +bail1: + EVP_PKEY_free(pkey); +bail: + EC_KEY_free(ec); + + return ret; +} + +LWS_VISIBLE int +lws_genecdh_new_keypair(struct lws_genec_ctx *ctx, enum enum_lws_dh_side side, + const char *curve_name, + struct lws_gencrypto_keyelem *el) +{ + if (ctx->genec_alg != LEGENEC_ECDH) + return -1; + + return lws_genec_new_keypair(ctx, side, curve_name, el); +} + +LWS_VISIBLE int +lws_genecdsa_new_keypair(struct lws_genec_ctx *ctx, const char *curve_name, + struct lws_gencrypto_keyelem *el) +{ + if (ctx->genec_alg != LEGENEC_ECDSA) + return -1; + + return lws_genec_new_keypair(ctx, LDHS_OURS, curve_name, el); +} + +LWS_VISIBLE LWS_EXTERN int +lws_genecdsa_hash_sign(struct lws_genec_ctx *ctx, const uint8_t *in, + enum lws_genhash_types hash_type, + uint8_t *sig, size_t sig_len) +{ + const EVP_MD *md = lws_gencrypto_openssl_hash_to_EVP_MD(hash_type); + EVP_MD_CTX *mdctx = NULL; + + if (ctx->genec_alg != LEGENEC_ECDSA) + return -1; + + if (!md) + return -1; + + mdctx = EVP_MD_CTX_create(); + if (!mdctx) + goto bail; + + if (EVP_DigestSignInit(mdctx, NULL, md, NULL, + EVP_PKEY_CTX_get0_pkey(ctx->ctx))) { + lwsl_err("%s: EVP_DigestSignInit failed\n", __func__); + + goto bail; + } + if (EVP_DigestSignUpdate(mdctx, in, EVP_MD_size(md))) { + lwsl_err("%s: EVP_DigestSignUpdate failed\n", __func__); + + goto bail; + } + if (EVP_DigestSignFinal(mdctx, sig, &sig_len)) { + lwsl_err("%s: EVP_DigestSignFinal failed\n", __func__); + + goto bail; + } + + EVP_MD_CTX_free(mdctx); + + return (int)sig_len; +bail: + if (mdctx) + EVP_MD_CTX_free(mdctx); + + return -1; +} + +LWS_VISIBLE LWS_EXTERN int +lws_genecdsa_hash_sig_verify(struct lws_genec_ctx *ctx, const uint8_t *in, + enum lws_genhash_types hash_type, + const uint8_t *sig, size_t sig_len) +{ + const EVP_MD *md = lws_gencrypto_openssl_hash_to_EVP_MD(hash_type); + EVP_MD_CTX *mdctx = NULL; + int ret = -1; + + if (ctx->genec_alg != LEGENEC_ECDSA) + return -1; + + if (!md) + return -1; + + mdctx = EVP_MD_CTX_create(); + if (!mdctx) + goto bail; + + if (EVP_DigestVerifyInit(mdctx, NULL, md, NULL, + EVP_PKEY_CTX_get0_pkey(ctx->ctx))) { + lwsl_err("%s: EVP_DigestSignInit failed\n", __func__); + + goto bail; + } + if (EVP_DigestVerifyUpdate(mdctx, in, EVP_MD_size(md))) { + lwsl_err("%s: EVP_DigestSignUpdate failed\n", __func__); + + goto bail; + } + if (EVP_DigestVerifyFinal(mdctx, sig, sig_len)) { + lwsl_err("%s: EVP_DigestSignFinal failed\n", __func__); + + goto bail; + } + + ret = 0; +bail: + if (mdctx) + EVP_MD_CTX_free(mdctx); + + return ret; +} diff --git a/lib/tls/openssl/lws-genhash.c b/lib/tls/openssl/lws-genhash.c index c81aca3d4..c6ca2c5ec 100644 --- a/lib/tls/openssl/lws-genhash.c +++ b/lib/tls/openssl/lws-genhash.c @@ -23,23 +23,6 @@ */ #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) { @@ -96,21 +79,6 @@ lws_genhash_destroy(struct lws_genhash_ctx *ctx, void *result) 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) diff --git a/lib/tls/openssl/lws-genrsa.c b/lib/tls/openssl/lws-genrsa.c index 68b9bd6c8..ca3c2d539 100644 --- a/lib/tls/openssl/lws-genrsa.c +++ b/lib/tls/openssl/lws-genrsa.c @@ -19,16 +19,17 @@ * MA 02110-1301 USA * * lws_genrsa provides an RSA abstraction api in lws that works the - * same whether you are using openssl or mbedtls hash functions underneath. + * same whether you are using openssl or mbedtls crypto functions underneath. */ #include "core/private.h" +#include "tls/openssl/private.h" LWS_VISIBLE void -lws_jwk_destroy_genrsa_elements(struct lws_jwk_elements *el) +lws_genrsa_destroy_elements(struct lws_gencrypto_keyelem *el) { int n; - for (n = 0; n < LWS_COUNT_RSA_KEY_ELEMENTS; n++) + for (n = 0; n < LWS_GENCRYPTO_RSA_KEYEL_COUNT; n++) if (el[n].buf) lws_free_set_NULL(el[n].buf); } @@ -72,7 +73,7 @@ bail: } LWS_VISIBLE int -lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_jwk_elements *el, +lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_gencrypto_keyelem *el, struct lws_context *context, enum enum_genrsa_mode mode) { int n; @@ -106,20 +107,20 @@ lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_jwk_elements *el, } #if defined(LWS_HAVE_RSA_SET0_KEY) - if (RSA_set0_key(ctx->rsa, ctx->bn[JWK_RSA_KEYEL_N], - ctx->bn[JWK_RSA_KEYEL_E], - ctx->bn[JWK_RSA_KEYEL_D]) != 1) { + if (RSA_set0_key(ctx->rsa, ctx->bn[LWS_GENCRYPTO_RSA_KEYEL_N], + ctx->bn[LWS_GENCRYPTO_RSA_KEYEL_E], + ctx->bn[LWS_GENCRYPTO_RSA_KEYEL_D]) != 1) { lwsl_notice("RSA_set0_key failed\n"); goto bail; } - RSA_set0_factors(ctx->rsa, ctx->bn[JWK_RSA_KEYEL_P], - ctx->bn[JWK_RSA_KEYEL_Q]); + RSA_set0_factors(ctx->rsa, ctx->bn[LWS_GENCRYPTO_RSA_KEYEL_P], + ctx->bn[LWS_GENCRYPTO_RSA_KEYEL_Q]); #else - ctx->rsa->e = ctx->bn[JWK_RSA_KEYEL_E]; - ctx->rsa->n = ctx->bn[JWK_RSA_KEYEL_N]; - ctx->rsa->d = ctx->bn[JWK_RSA_KEYEL_D]; - ctx->rsa->p = ctx->bn[JWK_RSA_KEYEL_P]; - ctx->rsa->q = ctx->bn[JWK_RSA_KEYEL_Q]; + ctx->rsa->e = ctx->bn[LWS_GENCRYPTO_RSA_KEYEL_E]; + ctx->rsa->n = ctx->bn[LWS_GENCRYPTO_RSA_KEYEL_N]; + ctx->rsa->d = ctx->bn[LWS_GENCRYPTO_RSA_KEYEL_D]; + ctx->rsa->p = ctx->bn[LWS_GENCRYPTO_RSA_KEYEL_P]; + ctx->rsa->q = ctx->bn[LWS_GENCRYPTO_RSA_KEYEL_Q]; #endif if (!rsa_pkey_wrap(ctx, ctx->rsa)) @@ -142,7 +143,7 @@ bail: LWS_VISIBLE int lws_genrsa_new_keypair(struct lws_context *context, struct lws_genrsa_ctx *ctx, - enum enum_genrsa_mode mode, struct lws_jwk_elements *el, + enum enum_genrsa_mode mode, struct lws_gencrypto_keyelem *el, int bits) { BIGNUM *bn; @@ -175,10 +176,10 @@ lws_genrsa_new_keypair(struct lws_context *context, struct lws_genrsa_ctx *ctx, { const BIGNUM *mpi[5]; - RSA_get0_key(ctx->rsa, &mpi[JWK_RSA_KEYEL_N], - &mpi[JWK_RSA_KEYEL_E], &mpi[JWK_RSA_KEYEL_D]); - RSA_get0_factors(ctx->rsa, &mpi[JWK_RSA_KEYEL_P], - &mpi[JWK_RSA_KEYEL_Q]); + RSA_get0_key(ctx->rsa, &mpi[LWS_GENCRYPTO_RSA_KEYEL_N], + &mpi[LWS_GENCRYPTO_RSA_KEYEL_E], &mpi[LWS_GENCRYPTO_RSA_KEYEL_D]); + RSA_get0_factors(ctx->rsa, &mpi[LWS_GENCRYPTO_RSA_KEYEL_P], + &mpi[LWS_GENCRYPTO_RSA_KEYEL_Q]); #else { BIGNUM *mpi[5] = { ctx->rsa->n, ctx->rsa->e, ctx->rsa->d, @@ -199,7 +200,7 @@ lws_genrsa_new_keypair(struct lws_context *context, struct lws_genrsa_ctx *ctx, return 0; cleanup: - for (n = 0; n < LWS_COUNT_RSA_KEY_ELEMENTS; n++) + for (n = 0; n < LWS_GENCRYPTO_RSA_KEYEL_COUNT; n++) if (el[n].buf) lws_free_set_NULL(el[n].buf); cleanup_1: @@ -241,59 +242,12 @@ lws_genrsa_public_decrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in, return 0; } -static int -lws_genrsa_genrsa_hash_to_NID(enum lws_genhash_types hash_type) -{ - int h = -1; - - switch (hash_type) { - case LWS_GENHASH_TYPE_SHA1: - h = NID_sha1; - break; - case LWS_GENHASH_TYPE_SHA256: - h = NID_sha256; - break; - case LWS_GENHASH_TYPE_SHA384: - h = NID_sha384; - break; - case LWS_GENHASH_TYPE_SHA512: - h = NID_sha512; - break; - } - - return h; -} - -static const EVP_MD * -lws_genrsa_genrsa_hash_to_EVP_MD(enum lws_genhash_types hash_type) -{ - const EVP_MD *h = NULL; - - switch (hash_type) { - case LWS_GENHASH_TYPE_SHA1: - h = EVP_sha1(); - break; - case LWS_GENHASH_TYPE_SHA256: - h = EVP_sha256(); - break; - case LWS_GENHASH_TYPE_SHA384: - h = EVP_sha384(); - break; - case LWS_GENHASH_TYPE_SHA512: - h = EVP_sha512(); - break; - } - - return h; -} - - LWS_VISIBLE int -lws_genrsa_public_verify(struct lws_genrsa_ctx *ctx, const uint8_t *in, +lws_genrsa_hash_sig_verify(struct lws_genrsa_ctx *ctx, const uint8_t *in, enum lws_genhash_types hash_type, const uint8_t *sig, size_t sig_len) { - int n = lws_genrsa_genrsa_hash_to_NID(hash_type), + int n = lws_gencrypto_openssl_hash_to_NID(hash_type), h = (int)lws_genhash_size(hash_type); const EVP_MD *md = NULL; @@ -305,7 +259,7 @@ lws_genrsa_public_verify(struct lws_genrsa_ctx *ctx, const uint8_t *in, n = RSA_verify(n, in, h, (uint8_t *)sig, (int)sig_len, ctx->rsa); break; case LGRSAM_PKCS1_OAEP_PSS: - md = lws_genrsa_genrsa_hash_to_EVP_MD(hash_type); + md = lws_gencrypto_openssl_hash_to_EVP_MD(hash_type); if (!md) return -1; @@ -326,11 +280,11 @@ lws_genrsa_public_verify(struct lws_genrsa_ctx *ctx, const uint8_t *in, } LWS_VISIBLE int -lws_genrsa_public_sign(struct lws_genrsa_ctx *ctx, const uint8_t *in, +lws_genrsa_hash_sign(struct lws_genrsa_ctx *ctx, const uint8_t *in, enum lws_genhash_types hash_type, uint8_t *sig, size_t sig_len) { - int n = lws_genrsa_genrsa_hash_to_NID(hash_type), + int n = lws_gencrypto_openssl_hash_to_NID(hash_type), h = (int)lws_genhash_size(hash_type); unsigned int used = 0; EVP_MD_CTX *mdctx = NULL; @@ -350,7 +304,7 @@ lws_genrsa_public_sign(struct lws_genrsa_ctx *ctx, const uint8_t *in, case LGRSAM_PKCS1_OAEP_PSS: - md = lws_genrsa_genrsa_hash_to_EVP_MD(hash_type); + md = lws_gencrypto_openssl_hash_to_EVP_MD(hash_type); if (!md) return -1; @@ -381,6 +335,8 @@ lws_genrsa_public_sign(struct lws_genrsa_ctx *ctx, const uint8_t *in, goto bail; } + EVP_MD_CTX_free(mdctx); + used = (int)sig_len; break; default: diff --git a/lib/tls/openssl/openssl-client.c b/lib/tls/openssl/openssl-client.c index 884d0317c..62e250b54 100644 --- a/lib/tls/openssl/openssl-client.c +++ b/lib/tls/openssl/openssl-client.c @@ -142,7 +142,7 @@ lws_ssl_client_bio_create(struct lws *wsi) if (!wsi->tls.ssl) { lwsl_err("SSL_new failed: %s\n", ERR_error_string(lws_ssl_get_error(wsi, 0), NULL)); - lws_ssl_elaborate_error(); + lws_tls_err_describe(); return -1; } @@ -338,7 +338,7 @@ lws_tls_client_confirm_peer_cert(struct lws *wsi, char *ebuf, int ebuf_len) "server's cert didn't look good, X509_V_ERR = %d: %s\n", n, ERR_error_string(n, sb)); lwsl_info("%s\n", ebuf); - lws_ssl_elaborate_error(); + lws_tls_err_describe(); return -1; @@ -440,7 +440,7 @@ lws_tls_client_create_vhost_context(struct lws_vhost *vh, "Unable to load SSL Client certs " "file from %s -- client ssl isn't " "going to work\n", ca_filepath); - lws_ssl_elaborate_error(); + lws_tls_err_describe(); } else lwsl_info("loaded ssl_ca_filepath\n"); @@ -453,7 +453,7 @@ lws_tls_client_create_vhost_context(struct lws_vhost *vh, lwsl_err("Unable to load SSL Client certs from " "ssl_ca_mem -- client ssl isn't going to " "work\n"); - lws_ssl_elaborate_error(); + lws_tls_err_describe(); } else { /* it doesn't increment x509_store ref counter */ SSL_CTX_set_cert_store(vh->tls.ssl_client_ctx, @@ -483,7 +483,7 @@ lws_tls_client_create_vhost_context(struct lws_vhost *vh, if (n < 1) { lwsl_err("problem %d getting cert '%s'\n", n, cert_filepath); - lws_ssl_elaborate_error(); + lws_tls_err_describe(); return 1; } lwsl_notice("Loaded client cert %s\n", cert_filepath); @@ -496,7 +496,7 @@ lws_tls_client_create_vhost_context(struct lws_vhost *vh, private_key_filepath, SSL_FILETYPE_PEM) != 1) { lwsl_err("use_PrivateKey_file '%s'\n", private_key_filepath); - lws_ssl_elaborate_error(); + lws_tls_err_describe(); return 1; } lwsl_notice("Loaded client cert private key %s\n", diff --git a/lib/tls/openssl/private.h b/lib/tls/openssl/private.h new file mode 100644 index 000000000..39e9ef6d1 --- /dev/null +++ b/lib/tls/openssl/private.h @@ -0,0 +1,28 @@ +/* + * 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 + * + * gencrypto openssl-specific helper declarations + */ + +int +lws_gencrypto_openssl_hash_to_NID(enum lws_genhash_types hash_type); + +const EVP_MD * +lws_gencrypto_openssl_hash_to_EVP_MD(enum lws_genhash_types hash_type); diff --git a/lib/tls/private.h b/lib/tls/private.h index f9ab7d3b3..6a1cd0012 100644 --- a/lib/tls/private.h +++ b/lib/tls/private.h @@ -61,6 +61,8 @@ #include #include #include + #include + #include #include "tls/mbedtls/wrapper/include/openssl/ssl.h" /* wrapper !!!! */ #else #include @@ -74,6 +76,9 @@ #ifdef LWS_HAVE_OPENSSL_ECDH_H #include #endif + #if !defined(LWS_HAVE_EVP_MD_CTX_free) + #define EVP_MD_CTX_free EVP_MD_CTX_destroy + #endif #include #endif /* not mbedtls */ #if defined(OPENSSL_VERSION_NUMBER) @@ -288,4 +293,18 @@ lws_ssl_info_callback(const lws_tls_conn *ssl, int where, int ret); int lws_tls_fake_POLLIN_for_buffered(struct lws_context_per_thread *pt); + +/* genec */ + +struct lws_gencrypto_keyelem; +struct lws_ec_curves; + +LWS_EXTERN const struct lws_ec_curves lws_ec_curves[]; +const struct lws_ec_curves * +lws_genec_curve(const struct lws_ec_curves *table, const char *name); +LWS_VISIBLE void +lws_genec_destroy_elements(struct lws_gencrypto_keyelem *el); +int +lws_gencrypto_mbedtls_rngf(void *context, unsigned char *buf, size_t len); + #endif diff --git a/minimal-examples/api-tests/api-test-gencrypto/CMakeLists.txt b/minimal-examples/api-tests/api-test-gencrypto/CMakeLists.txt index a36a5cda8..0679f88a5 100644 --- a/minimal-examples/api-tests/api-test-gencrypto/CMakeLists.txt +++ b/minimal-examples/api-tests/api-test-gencrypto/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 2.8) include(CheckCSourceCompiles) set(SAMP lws-api-test-gencrypto) -set(SRCS main.c lws-genaes.c) +set(SRCS main.c lws-genaes.c lws-genec.c) # If we are being built as part of lws, confirm current build config supports # reqconfig, else skip building ourselves. @@ -63,6 +63,7 @@ ENDMACRO() set(requirements 1) require_lws_config(LWS_WITH_GENAES 1 requirements) +require_lws_config(LWS_WITH_GENEC 1 requirements) if (requirements) diff --git a/minimal-examples/api-tests/api-test-gencrypto/lws-genaes.c b/minimal-examples/api-tests/api-test-gencrypto/lws-genaes.c index 634912518..b14e08e59 100644 --- a/minimal-examples/api-tests/api-test-gencrypto/lws-genaes.c +++ b/minimal-examples/api-tests/api-test-gencrypto/lws-genaes.c @@ -38,7 +38,7 @@ static int test_genaes_cbc(void) { struct lws_genaes_ctx ctx; - struct lws_jwk_elements e; + struct lws_gencrypto_keyelem e; uint8_t res[32], res1[32]; /* @@ -128,7 +128,7 @@ static int test_genaes_cfb128(void) { struct lws_genaes_ctx ctx; - struct lws_jwk_elements e; + struct lws_gencrypto_keyelem e; uint8_t res[32], res1[32]; size_t iv_off = 0; @@ -215,7 +215,7 @@ static int test_genaes_cfb8(void) { struct lws_genaes_ctx ctx; - struct lws_jwk_elements e; + struct lws_gencrypto_keyelem e; uint8_t res[32], res1[32]; e.buf = (uint8_t *)cfb8_key; @@ -300,7 +300,7 @@ test_genaes_ctr(void) { uint8_t nonce_counter[16], sb[16]; struct lws_genaes_ctx ctx; - struct lws_jwk_elements e; + struct lws_gencrypto_keyelem e; uint8_t res[32], res1[32]; size_t nc_off = 0; @@ -390,7 +390,7 @@ static int test_genaes_ecb(void) { struct lws_genaes_ctx ctx; - struct lws_jwk_elements e; + struct lws_gencrypto_keyelem e; uint8_t res[32], res1[32]; /* @@ -483,7 +483,7 @@ static int test_genaes_ofb(void) { struct lws_genaes_ctx ctx; - struct lws_jwk_elements e; + struct lws_gencrypto_keyelem e; uint8_t res[32], res1[32]; size_t iv_off = 0; @@ -571,7 +571,7 @@ static int test_genaes_xts(void) { struct lws_genaes_ctx ctx; - struct lws_jwk_elements e; + struct lws_gencrypto_keyelem e; uint8_t res[32], res1[32], data_unit[16]; memset(data_unit, 0, sizeof(data_unit)); @@ -663,7 +663,7 @@ test_genaes_gcm(void) { uint8_t res[sizeof(gcm_ct)], tag[sizeof(gcm_tag)]; struct lws_genaes_ctx ctx; - struct lws_jwk_elements e; + struct lws_gencrypto_keyelem e; size_t iv_off = 0; e.buf = (uint8_t *)gcm_key; diff --git a/minimal-examples/api-tests/api-test-gencrypto/lws-genec.c b/minimal-examples/api-tests/api-test-gencrypto/lws-genec.c new file mode 100644 index 000000000..d640650dd --- /dev/null +++ b/minimal-examples/api-tests/api-test-gencrypto/lws-genec.c @@ -0,0 +1,132 @@ +/* + * lws-api-test-gencrypto - lws-genec + * + * 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 + *jwk_ec1 = (uint8_t *) + "{\"kty\":\"EC\"," + "\"crv\":\"P-256\"," + "\"x\":\"MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4\"," + "\"y\":\"4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM\"," + "\"d\":\"870MB6gfuTJ4HtUnUvYMyJpr5eUZNP4Bk43bVdj3eAE\"," + "\"use\":\"enc\"," + "\"kid\":\"rfc7517-A.2-example private key\"}" +; + +static int +test_genec1(struct lws_context *context) +{ + struct lws_genec_ctx ctx; + struct lws_jwk jwk; + struct lws_gencrypto_keyelem el[LWS_GENCRYPTO_EC_KEYEL_COUNT]; + //uint8_t res[32], res1[32]; + int n; + + memset(el, 0, sizeof(el)); + + if (lws_genecdh_create(&ctx, context, NULL)) + return 1; + + /* let's create a new key */ + + if (lws_genecdh_new_keypair(&ctx, LDHS_OURS, "P-256", el)) { + lwsl_err("%s: lws_genec_new_keypair failed\n", __func__); + return 1; + } + + lws_genec_dump(el); + lws_genec_destroy_elements(el); + + lws_genec_destroy(&ctx); + + if (lws_jwk_import(&jwk, NULL, NULL, (char *)jwk_ec1, + strlen((char *)jwk_ec1)) < 0) { + lwsl_notice("Failed to decode JWK test key\n"); + return 1; + } + + lws_jwk_dump(&jwk); + + if (jwk.kty != LWS_GENCRYPTO_KYT_EC) { + lws_jwk_destroy(&jwk); + lwsl_err("%s: jwk is not an EC key\n", __func__); + return 1; + } + + if (lws_genecdh_create(&ctx, context, NULL)) + return 1; + + n = lws_genecdh_set_key(&ctx, jwk.e, LDHS_OURS); + if (n) { + lws_jwk_destroy(&jwk); + lwsl_err("%s: lws_genec_create failed: %d\n", __func__, n); + return 1; + } +#if 0 + if (lws_genec_crypt(&ctx, cbc256, 16, res, (uint8_t *)cbc256_iv, + NULL, NULL)) { + lwsl_err("%s: lws_genec_crypt failed\n", __func__); + goto bail; + } + + if (memcmp(cbc256_enc, res, 16)) { + lwsl_err("%s: lws_genec_crypt encoding mismatch\n", __func__); + lwsl_hexdump_notice(res, 16); + goto bail; + } + + lws_genec_destroy(&ctx); + + if (lws_genec_create(&ctx, LWS_GAESO_DEC, LWS_GAESM_CBC, &e, NULL)) { + lwsl_err("%s: lws_genec_create dec failed\n", __func__); + return -1; + } + + if (lws_genec_crypt(&ctx, res, 16, res1, (uint8_t *)cbc256_iv, + NULL, NULL)) { + lwsl_err("%s: lws_genec_crypt dec failed\n", __func__); + goto bail; + } + + if (memcmp(cbc256, res1, 16)) { + lwsl_err("%s: lws_genec_crypt decoding mismatch\n", __func__); + lwsl_hexdump_notice(res, 16); + goto bail; + } +#endif + lws_genec_destroy(&ctx); + + lws_jwk_destroy(&jwk); + + return 0; + +//bail: +// lws_genec_destroy(&ctx); + +// return -1; +} + +int +test_genec(struct lws_context *context) +{ + if (test_genec1(context)) + 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 index 7bdcdf532..fd808c69a 100644 --- a/minimal-examples/api-tests/api-test-gencrypto/main.c +++ b/minimal-examples/api-tests/api-test-gencrypto/main.c @@ -11,6 +11,8 @@ int test_genaes(struct lws_context *context); +int +test_genec(struct lws_context *context); int main(int argc, const char **argv) { @@ -36,6 +38,7 @@ int main(int argc, const char **argv) } result |= test_genaes(context); + result |= test_genec(context); lwsl_user("Completed: %s\n", result ? "FAIL" : "PASS"); diff --git a/minimal-examples/api-tests/api-test-jose/jwe.c b/minimal-examples/api-tests/api-test-jose/jwe.c index cb88492c1..27b8b9b3d 100644 --- a/minimal-examples/api-tests/api-test-jose/jwe.c +++ b/minimal-examples/api-tests/api-test-jose/jwe.c @@ -67,8 +67,10 @@ lws_jwe_ex_a2_cek[] = { "\"qi\":\"eNho5yRBEBxhGBtQRww9QirZsB66TrfFReG_CcteI1aCneT0ELGhYlRlC" "tUkTRclIfuEPmNsNDPbLoLqqCVznFbvdB7x-Tl-m0l_eFTj2KiqwGqE9PZ" "B9nNTwMVvH3VRRSLWACvPnSiwP8N5Usy-WRXS-V7TbpxIhvepTfE0NNo\"" -"}", +"}" +#if 0 +, lws_jwe_ex_a2_jwk_enc_key[] = { 80, 104, 72, 58, 11, 130, 236, 139, 132, 189, 255, 205, 61, 86, 151, 176, @@ -103,7 +105,6 @@ lws_jwe_ex_a2_jwk_enc_key[] = { 248, 29, 232, 90, 29, 147, 110, 169, 146, 114, 165, 204, 71, 136, 41, 252 } -#if 0 , *lws_jwe_ex_a2_jwk_enc_key_b64 = (uint8_t *) "UGhIOguC7IuEvf_NPVaXsGMoLOmwvc1GyqlIKOK1nN94nHPoltGRhWhw7Zx0-kFm" @@ -175,9 +176,10 @@ lws_jwe_ex_a2_authtag[] = { int test_jwe(struct lws_context *context) { + //const struct lws_jose_jwe_alg *jose_alg; struct lws_genrsa_ctx rsactx; struct lws_jwk jwk; - uint8_t enc_cek[sizeof(lws_jwe_ex_a2_jwk_enc_key) + 2048]; + uint8_t enc_cek[/* sizeof(lws_jwe_ex_a2_jwk_enc_key) */ 256 + 2048]; char buf[2048], *p = buf, *end = buf + sizeof(buf) - 1; int n; @@ -191,7 +193,7 @@ test_jwe(struct lws_context *context) return -1; } - if (jwk.kty != LWS_JWK_KYT_RSA) { + if (jwk.kty != LWS_GENCRYPTO_KYT_RSA) { lwsl_err("%s: unexpected kty %d\n", __func__, jwk.kty); return -1; @@ -246,8 +248,8 @@ test_jwe(struct lws_context *context) /* 1.3: use HMAC SHA-256 with known key on the hdr . payload */ if (lws_genhmac_init(&ctx, LWS_GENHMAC_TYPE_SHA256, - jwk.el.e[JWK_RSA_KEYEL_E].buf, - jwk.el.e[JWK_RSA_KEYEL_E].len)) + jwk.el.e[LWS_GENCRYPTO_RSA_KEYEL_E].buf, + jwk.el.e[LWS_GENCRYPTO_RSA_KEYEL_E].len)) goto bail; if (lws_genhmac_update(&ctx, (uint8_t *)buf, p - buf)) goto bail_destroy_hmac; @@ -296,9 +298,14 @@ test_jwe(struct lws_context *context) p = strchr(buf + 1, '.'); p1 = strchr(p + 1, '.'); + if (lws_gencrypto_jwe_alg_to_definition("RSA1_5", &jose_alg)) { + lwsl_err("%s: RSA1_5 not supported\n", __func__); + goto bail; + } + n = lws_jws_sign_from_b64(buf, p - buf, p + 1, p1 - (p + 1), p1 + 1, sizeof(buf) - (p1 - buf) - 1, - LWS_GENHASH_TYPE_SHA256, &jwk); + jose_alg, &jwk, context); if (n < 0) goto bail; diff --git a/minimal-examples/api-tests/api-test-jose/jws.c b/minimal-examples/api-tests/api-test-jose/jws.c index d82b0ca78..d66978e8d 100644 --- a/minimal-examples/api-tests/api-test-jose/jws.c +++ b/minimal-examples/api-tests/api-test-jose/jws.c @@ -20,33 +20,6 @@ * The signature stays with the content, it serves a different purpose than eg * a TLS tunnel to transfer it. * - * RFC7518 (JSON Web Algorithms) says for the "alg" names - * - * | HS256 | HMAC using SHA-256 | Required | - * | HS384 | HMAC using SHA-384 | Optional | - * | HS512 | HMAC using SHA-512 | Optional | - * | RS256 | RSASSA-PKCS1-v1_5 using | Recommended | - * | RS384 | RSASSA-PKCS1-v1_5 using | Optional | - * | | SHA-384 | | - * | RS512 | RSASSA-PKCS1-v1_5 using | Optional | - * | | SHA-512 | | - * | ES256 | ECDSA using P-256 and SHA-256 | Recommended+ | - * | ES384 | ECDSA using P-384 and SHA-384 | Optional | - * | ES512 | ECDSA using P-521 and SHA-512 | Optional | - * - * Boulder (FOSS ACME provider) supports RS256, ES256, ES384 and ES512 - * currently. The "Recommended+" just means it is recommended but will likely - * be "very recommended" soon. - * - * We support HS256/384/512 for symmetric crypto, but the choice for the - * asymmetric crypto isn't as easy to make. - * - * Normally you'd choose the EC option but these are defined to use the - * "NIST curves" (RFC7518 3.4) which are believed to be insecure. - * - * https://safecurves.cr.yp.to/ - * - * For that reason we implement RS256/384/512 for asymmetric. */ static const char @@ -101,7 +74,40 @@ static const char "BAynRFdiuB--f_nZLgrnbyTyWzO75vRK5h6xBArLIARNPvkSjtQBMHlb1L07Qe7K" "0GarZRmB_eSN9383LcOLn6_dO--xi12jzDwusC-eOkHWEsqtFZESc6BfI7noOPqv" "hJ1phCnvWh6IeYI2w9QOYEUipUTI8np6LbgGY9Fs98rqVt5AXLIhWkWywlVmtVrB" - "p0igcN_IoypGlUPQGe77Rw"; + "p0igcN_IoypGlUPQGe77Rw" + +#if 0 + , + *rfc7515_ec_a3_jose = "{\"alg\":\"ES256\"}", + /* payload is the same as test2 above */ + *rfc7515_ec_a3_b64_serialization = + "eyJhbGciOiJFUzI1NiJ9" + "." + "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt" + "cGxlLmNvbS9pc19yb290Ijp0cnVlfQ" + "." + "DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSA" + "pmWQxfKTUJqPP3-Kg6NU1Q", + *rfc7515_ec_a3_jwk = + "{" + "\"kty\":\"EC\"," + "\"crv\":\"P-256\"," + "\"x\":\"f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU\"," + "\"y\":\"x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0\"," + "\"d\":\"jpsQnnGQmL-YBIffH1136cspYG6-0iY7X1fCE9-E9LI\"" + "}", + rfc7515_ec_a3_R[] = { + 14, 209, 33, 83, 121, 99, 108, 72, 60, 47, 127, 21, 88, + 7, 212, 2, 163, 178, 40, 3, 58, 249, 124, 126, 23, 129, + 154, 195, 22, 158, 166, 101 + }, + rfc7515_ec_a3_S[] = { + 197, 10, 7, 211, 140, 60, 112, 229, 216, 241, 45, 175, + 8, 74, 84, 128, 166, 101, 144, 197, 242, 147, 80, 154, + 143, 63, 127, 138, 131, 163, 84, 213 + } +#endif +; /* * These are the inputs and outputs from the worked example in RFC7515 @@ -115,10 +121,11 @@ static const char int test_jws(struct lws_context *context) { + char buf[2048], *p = buf, *end = buf + sizeof(buf) - 1, *enc_ptr, *p1; + const struct lws_jose_jwe_alg *jose_alg; + uint8_t digest[LWS_GENHASH_LARGEST]; struct lws_genhmac_ctx ctx; struct lws_jwk jwk; - char buf[2048], *p = buf, *end = buf + sizeof(buf) - 1, *enc_ptr, *p1; - uint8_t digest[LWS_GENHASH_LARGEST]; int n; /* Test 1: SHA256 on RFC7515 worked example */ @@ -129,7 +136,7 @@ test_jws(struct lws_context *context) lwsl_notice("Failed to decode JWK test key\n"); return -1; } - if (jwk.kty != LWS_JWK_KYT_OCT) { + if (jwk.kty != LWS_GENCRYPTO_KYT_OCT) { lwsl_err("%s: unexpected kty %d\n", __func__, jwk.kty); return -1; @@ -153,8 +160,8 @@ test_jws(struct lws_context *context) /* 1.3: use HMAC SHA-256 with known key on the hdr . payload */ if (lws_genhmac_init(&ctx, LWS_GENHMAC_TYPE_SHA256, - jwk.e[JWK_OCT_KEYEL_K].buf, - jwk.e[JWK_OCT_KEYEL_K].len)) + jwk.e[LWS_GENCRYPTO_OCT_KEYEL_K].buf, + jwk.e[LWS_GENCRYPTO_OCT_KEYEL_K].len)) goto bail; if (lws_genhmac_update(&ctx, (uint8_t *)buf, p - buf)) goto bail_destroy_hmac; @@ -191,7 +198,7 @@ test_jws(struct lws_context *context) goto bail2; } - if (jwk.kty != LWS_JWK_KYT_RSA) { + if (jwk.kty != LWS_GENCRYPTO_KYT_RSA) { lwsl_err("%s: 2.2: kty: %d instead of RSA\n", __func__, jwk.kty); } @@ -211,9 +218,14 @@ test_jws(struct lws_context *context) p = strchr(buf + 1, '.'); p1 = strchr(p + 1, '.'); + if (lws_gencrypto_jwe_alg_to_definition("RSA1_5", &jose_alg)) { + lwsl_err("%s: RSA1_5 not supported\n", __func__); + goto bail; + } + n = lws_jws_sign_from_b64(buf, p - buf, p + 1, p1 - (p + 1), p1 + 1, sizeof(buf) - (p1 - buf) - 1, - LWS_GENHASH_TYPE_SHA256, &jwk, context); + jose_alg, &jwk, context); if (n < 0) { lwsl_err("%s: failed signing test packet\n", __func__); goto bail; diff --git a/plugins/acme-client/protocol_lws_acme_client.c b/plugins/acme-client/protocol_lws_acme_client.c index e693d451a..2e4695870 100644 --- a/plugins/acme-client/protocol_lws_acme_client.c +++ b/plugins/acme-client/protocol_lws_acme_client.c @@ -439,7 +439,7 @@ lws_acme_load_create_auth_keys(struct per_vhost_data__lws_acme_client *vhd, NULL, NULL)) return 0; - vhd->jwk.kty = LWS_JWK_KYT_RSA; + vhd->jwk.kty = LWS_GENCRYPTO_KYT_RSA; lwsl_notice("Generating ACME %d-bit keypair... " "will take a little while\n", bits); n = lws_genrsa_new_keypair(vhd->context, &vhd->rsactx, LGRSAM_PKCS1_1_5, @@ -547,12 +547,13 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason, lws_get_protocol(wsi)); char buf[LWS_PRE + 2536], *start = buf + LWS_PRE, *p = start, *end = buf + sizeof(buf) - 1, digest[32], *failreason = NULL; - unsigned char **pp, *pend; - const char *content_type; const struct lws_protocol_vhost_options *pvo; struct lws_acme_cert_aging_args *caa; + const struct lws_jose_jwe_alg *args; struct acme_connection *ac = NULL; struct lws_genhash_ctx hctx; + unsigned char **pp, *pend; + const char *content_type; struct lws *cwsi; int n, m; @@ -782,7 +783,12 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason, puts(start); pkt_add_hdrs: - ac->len = lws_jws_create_packet(&vhd->jwk, + if (lws_gencrypto_jwe_alg_to_definition("RSA1_5", &args)) { + ac->len = 0; + lwsl_notice("%s: no RSA1_5\n", __func__); + goto failed; + } + ac->len = lws_jwe_create_packet(&vhd->jwk, args, start, p - start, ac->replay_nonce, &ac->buf[LWS_PRE], @@ -791,7 +797,7 @@ pkt_add_hdrs: lws_get_context(wsi)); if (ac->len < 0) { ac->len = 0; - lwsl_notice("lws_jws_create_packet failed\n"); + lwsl_notice("lws_jwe_create_packet failed\n"); goto failed; } diff --git a/plugins/ssh-base/sshd.c b/plugins/ssh-base/sshd.c index 21357ef48..68cea380d 100644 --- a/plugins/ssh-base/sshd.c +++ b/plugins/ssh-base/sshd.c @@ -538,7 +538,7 @@ lws_ssh_exec_finish(void *finish_handle, int retcode) static int lws_ssh_parse_plaintext(struct per_session_data__sshd *pss, uint8_t *p, size_t len) { - struct lws_jwk_elements e[LWS_COUNT_RSA_KEY_ELEMENTS]; + struct lws_gencrypto_keyelem e[LWS_GENCRYPTO_RSA_KEYEL_COUNT]; struct lws_genrsa_ctx ctx; struct lws_ssh_channel *ch; struct lws_subprotocol_scp *scp; @@ -1242,12 +1242,12 @@ again: m = lws_g32(&pp); pp += m; m = lws_g32(&pp); - e[JWK_RSA_KEYEL_E].buf = pp; - e[JWK_RSA_KEYEL_E].len = m; + e[LWS_GENCRYPTO_RSA_KEYEL_E].buf = pp; + e[LWS_GENCRYPTO_RSA_KEYEL_E].len = m; pp += m; m = lws_g32(&pp); - e[JWK_RSA_KEYEL_N].buf = pp; - e[JWK_RSA_KEYEL_N].len = m; + e[LWS_GENCRYPTO_RSA_KEYEL_N].buf = pp; + e[LWS_GENCRYPTO_RSA_KEYEL_N].len = m; if (lws_genrsa_create(&ctx, e, pss->vhd->context, LGRSAM_PKCS1_1_5))