diff --git a/CMakeLists.txt b/CMakeLists.txt index 0bb79357..a5680fdf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -693,16 +693,20 @@ endif() if (LWS_WITH_SSL) list(APPEND SOURCES - lib/tls/tls.c) + lib/tls/tls.c + ) if (LWS_WITH_MBEDTLS) list(APPEND SOURCES lib/tls/mbedtls/ssl.c - lib/tls/mbedtls/lws-genhash.c) + lib/tls/mbedtls/lws-genhash.c + lib/tls/mbedtls/lws-genrsa.c + ) else() list(APPEND SOURCES lib/tls/openssl/ssl.c lib/tls/openssl/lws-genhash.c + lib/tls/openssl/lws-genrsa.c ) endif() diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h index 39cb6011..2cc48246 100644 --- a/lib/libwebsockets.h +++ b/lib/libwebsockets.h @@ -1605,10 +1605,177 @@ lws_genhmac_update(struct lws_genhmac_ctx *ctx, const void *in, size_t len); */ int lws_genhmac_destroy(struct lws_genhmac_ctx *ctx, void *result); +///@} +/*! \defgroup generic RSA + * ## Generic RSA related functions + * + * Lws provides generic RSA functions that abstract the ones + * provided by whatever OpenSSL library you are linking against. + * + * It lets you use the same code if you build against mbedtls or OpenSSL + * for example. + */ +///@{ + +enum enum_jwk_tok { + JWK_KEY_E, + JWK_KEY_N, + JWK_KEY_D, + JWK_KEY_P, + JWK_KEY_Q, + JWK_KEY_DP, + JWK_KEY_DQ, + JWK_KEY_QI, + JWK_KTY, /* also serves as count of real elements */ + JWK_KEY, +}; + +#define LWS_COUNT_RSA_ELEMENTS JWK_KTY + +struct lws_genrsa_ctx { +#if defined(LWS_WITH_MBEDTLS) + mbedtls_rsa_context *ctx; +#else + BIGNUM *bn[LWS_COUNT_RSA_ELEMENTS]; + RSA *rsa; +#endif +}; + +struct lws_genrsa_element { + uint8_t *buf; + uint16_t len; +}; + +struct lws_genrsa_elements { + struct lws_genrsa_element e[LWS_COUNT_RSA_ELEMENTS]; +}; + +/** lws_jwk_destroy_genrsa_elements() - Free allocations in genrsa_elements + * + * \param el: your struct lws_genrsa_elements + * + * This is a helper for user code making use of struct lws_genrsa_elements + * where the elements are allocated on the heap, it frees any non-NULL + * buf element and sets the buf to NULL. + * + * NB: lws_genrsa_public_... apis do not need this as they take care of the key + * creation and destruction themselves. + */ +LWS_VISIBLE LWS_EXTERN void +lws_jwk_destroy_genrsa_elements(struct lws_genrsa_elements *el); + +/** lws_genrsa_public_decrypt_create() - Create RSA public decrypt context + * + * \param ctx: your struct lws_genrsa_ctx + * \param el: struct prepared with key element data + * + * Creates an RSA context with a public key associated with it, formed from + * the key elements in \p el. + * + * Returns 0 for OK or nonzero for error. + * + * This and related APIs operate identically with OpenSSL or mbedTLS backends. + */ +LWS_VISIBLE LWS_EXTERN int +lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_genrsa_elements *el); + +/** lws_genrsa_new_keypair() - Create new RSA keypair + * + * \param context: your struct lws_context (may be used for RNG) + * \param ctx: your struct lws_genrsa_ctx + * \param el: struct to get the new key element data allocated into it + * \param bits: key size, eg, 4096 + * + * Creates a new RSA context and generates a new keypair into it, with \p bits + * bits. + * + * Returns 0 for OK or nonzero for error. + * + * This and related APIs operate identically with OpenSSL or mbedTLS backends. + */ +LWS_VISIBLE LWS_EXTERN int +lws_genrsa_new_keypair(struct lws_context *context, struct lws_genrsa_ctx *ctx, + struct lws_genrsa_elements *el, int bits); + +/** lws_genrsa_public_decrypt() - Perform RSA public decryption + * + * \param ctx: your struct lws_genrsa_ctx + * \param in: encrypted input + * \param in_len: length of encrypted input + * \param out: decrypted output + * \param out_max: size of output buffer + * + * Performs the decryption. + * + * Returns <0 for error, or length of decrypted data. + * + * This and related APIs operate identically with OpenSSL or mbedTLS backends. + */ +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 + * + * \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 + * + * Returns <0 for error, or 0 if signature matches the payload + key. + * + * 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_public_sign() - Create RSA signature + * + * \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 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_public_decrypt_destroy() - Destroy RSA public decrypt context + * + * \param ctx: your struct lws_genrsa_ctx + * + * Destroys any allocations related to \p ctx. + * + * This and related APIs operate identically with OpenSSL or mbedTLS backends. + */ +LWS_VISIBLE LWS_EXTERN void +lws_genrsa_destroy(struct lws_genrsa_ctx *ctx); + +/** lws_genrsa_render_pkey_asn1() - Exports public or private key to ASN1/DER + * + * \param ctx: your struct lws_genrsa_ctx + * \param _private: 0 = public part only, 1 = all parts of the key + * \param pkey_asn1: pointer to buffer to take the ASN1 + * \param pkey_asn1_len: max size of the pkey_asn1_len + * + * Returns length of pkey_asn1 written, or -1 for error. + */ +LWS_VISIBLE LWS_EXTERN int +lws_genrsa_render_pkey_asn1(struct lws_genrsa_ctx *ctx, int _private, + uint8_t *pkey_asn1, size_t pkey_asn1_len); +///@} #endif -///@} /*! \defgroup extensions Extension related functions * ##Extension releated functions diff --git a/lib/tls/mbedtls/lws-genrsa.c b/lib/tls/mbedtls/lws-genrsa.c new file mode 100644 index 00000000..ba5f6d58 --- /dev/null +++ b/lib/tls/mbedtls/lws-genrsa.c @@ -0,0 +1,329 @@ +/* + * libwebsockets - generic RSA api hiding the backend + * + * Copyright (C) 2017 Andy Green + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * lws_genhash provides a hash / hmac abstraction api in lws that works the + * same whether you are using openssl or mbedtls hash functions underneath. + */ +#include "private-libwebsockets.h" + +LWS_VISIBLE void +lws_jwk_destroy_genrsa_elements(struct lws_genrsa_elements *el) +{ + int n; + + for (n = 0; n < LWS_COUNT_RSA_ELEMENTS; n++) + if (el->e[n].buf) + lws_free_set_NULL(el->e[n].buf); +} + +LWS_VISIBLE int +lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_genrsa_elements *el) +{ + int n; + + memset(ctx, 0, sizeof(*ctx)); + ctx->ctx = lws_zalloc(sizeof(*ctx->ctx), "genrsa"); + if (!ctx->ctx) + return 1; + + mbedtls_rsa_init(ctx->ctx, MBEDTLS_RSA_PKCS_V15, 0); + + { + mbedtls_mpi *mpi[LWS_COUNT_RSA_ELEMENTS] = { + &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_ELEMENTS; n++) + if (el->e[n].buf && + mbedtls_mpi_read_binary(mpi[n], el->e[n].buf, + el->e[n].len)) { + lwsl_notice("mpi load failed\n"); + lws_free_set_NULL(ctx->ctx); + + return -1; + } + } + + ctx->ctx->len = el->e[JWK_KEY_N].len; + + return 0; +} + +static int +_rngf(void *context, unsigned char *buf, size_t len) +{ + if ((size_t)lws_get_random(context, buf, len) == len) + return 0; + + return -1; +} + +LWS_VISIBLE int +lws_genrsa_new_keypair(struct lws_context *context, struct lws_genrsa_ctx *ctx, + struct lws_genrsa_elements *el, int bits) +{ + int n; + + memset(ctx, 0, sizeof(*ctx)); + ctx->ctx = lws_zalloc(sizeof(*ctx->ctx), "genrsa"); + if (!ctx->ctx) + return -1; + + mbedtls_rsa_init(ctx->ctx, MBEDTLS_RSA_PKCS_V15, 0); + + n = mbedtls_rsa_gen_key(ctx->ctx, _rngf, context, bits, 65537); + if (n) { + lwsl_err("mbedtls_rsa_gen_key failed 0x%x\n", -n); + goto cleanup_1; + } + + { + mbedtls_mpi *mpi[LWS_COUNT_RSA_ELEMENTS] = { + &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_ELEMENTS; n++) + if (mbedtls_mpi_size(mpi[n])) { + el->e[n].buf = lws_malloc( + mbedtls_mpi_size(mpi[n]), "genrsakey"); + if (!el->e[n].buf) + goto cleanup; + el->e[n].len = mbedtls_mpi_size(mpi[n]); + mbedtls_mpi_write_binary(mpi[n], el->e[n].buf, + el->e[n].len); + } + } + + return 0; + +cleanup: + for (n = 0; n < LWS_COUNT_RSA_ELEMENTS; n++) + if (el->e[n].buf) + lws_free_set_NULL(el->e[n].buf); +cleanup_1: + lws_free(ctx->ctx); + + return -1; +} + +LWS_VISIBLE 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) +{ + 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_genrsa_public_encrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in, + size_t in_len, uint8_t *out) +{ + int n; + + ctx->ctx->len = in_len; + n = mbedtls_rsa_rsaes_pkcs1_v15_encrypt(ctx->ctx, NULL, NULL, + MBEDTLS_RSA_PRIVATE, + in_len, in, out); + if (n) { + lwsl_notice("%s: -0x%x\n", __func__, -n); + + return -1; + } + + 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, + 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); + + if (h < 0) + return -1; + + n = mbedtls_rsa_rsassa_pkcs1_v15_verify(ctx->ctx, NULL, NULL, + MBEDTLS_RSA_PUBLIC, + h, 0, in, sig); + if (n < 0) { + lwsl_notice("%s: -0x%x\n", __func__, -n); + + return -1; + } + + return n; +} + +LWS_VISIBLE 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) +{ + int n, h = lws_genrsa_genrsa_hash_to_mbed_hash(hash_type); + + if (h < 0) + return -1; + + /* + * The "sig" buffer must be as large as the size of ctx->N + * (eg. 128 bytes if RSA-1024 is used). + */ + if (sig_len < ctx->ctx->len) + return -1; + + n = mbedtls_rsa_rsassa_pkcs1_v15_sign(ctx->ctx, NULL, NULL, + MBEDTLS_RSA_PRIVATE, h, 0, in, + sig); + if (n < 0) { + lwsl_notice("%s: -0x%x\n", __func__, -n); + + return -1; + } + + return ctx->ctx->len; +} + +LWS_VISIBLE int +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_ELEMENTS] = { + &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_COUNT_RSA_ELEMENTS; 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; +} + +LWS_VISIBLE void +lws_genrsa_destroy(struct lws_genrsa_ctx *ctx) +{ + if (!ctx->ctx) + return; + mbedtls_rsa_free(ctx->ctx); + lws_free(ctx->ctx); + ctx->ctx = NULL; +} diff --git a/lib/tls/openssl/lws-genrsa.c b/lib/tls/openssl/lws-genrsa.c new file mode 100644 index 00000000..6bdcde48 --- /dev/null +++ b/lib/tls/openssl/lws-genrsa.c @@ -0,0 +1,269 @@ +/* + * libwebsockets - generic RSA api hiding the backend + * + * Copyright (C) 2017 Andy Green + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * lws_genhash provides a hash / hmac abstraction api in lws that works the + * same whether you are using openssl or mbedtls hash functions underneath. + */ +#include "private-libwebsockets.h" + +LWS_VISIBLE void +lws_jwk_destroy_genrsa_elements(struct lws_genrsa_elements *el) +{ + int n; + + for (n = 0; n < LWS_COUNT_RSA_ELEMENTS; n++) + if (el->e[n].buf) + lws_free_set_NULL(el->e[n].buf); +} + +LWS_VISIBLE int +lws_genrsa_create(struct lws_genrsa_ctx *ctx, + struct lws_genrsa_elements *el) +{ + int n; + + memset(ctx, 0, sizeof(*ctx)); + + /* Step 1: + * + * convert the MPI for e and n to OpenSSL BIGNUMs + */ + + for (n = 0; n < 5; n++) { + ctx->bn[n] = BN_bin2bn(el->e[n].buf, el->e[n].len, NULL); + if (!ctx->bn[n]) { + lwsl_notice("mpi load failed\n"); + goto bail; + } + } + + /* Step 2: + * + * assemble the OpenSSL RSA from the BIGNUMs + */ + + ctx->rsa = RSA_new(); + if (!ctx->rsa) { + lwsl_notice("Failed to create RSA\n"); + goto bail; + } + +#if defined(LWS_HAVE_RSA_SET0_KEY) + if (RSA_set0_key(ctx->rsa, ctx->bn[JWK_KEY_N], ctx->bn[JWK_KEY_E], + ctx->bn[JWK_KEY_D]) != 1) { + lwsl_notice("RSA_set0_key failed\n"); + goto bail; + } + RSA_set0_factors(ctx->rsa, ctx->bn[JWK_KEY_P], ctx->bn[JWK_KEY_Q]); +#else + ctx->rsa->e = ctx->bn[JWK_KEY_E]; + ctx->rsa->n = ctx->bn[JWK_KEY_N]; + ctx->rsa->d = ctx->bn[JWK_KEY_D]; + ctx->rsa->p = ctx->bn[JWK_KEY_P]; + ctx->rsa->q = ctx->bn[JWK_KEY_Q]; +#endif + + return 0; + +bail: + for (n = 0; n < 5; n++) + if (ctx->bn[n]) { + BN_free(ctx->bn[n]); + ctx->bn[n] = NULL; + } + + if (ctx->rsa) { + RSA_free(ctx->rsa); + ctx->rsa = NULL; + } + + return 1; +} + +LWS_VISIBLE int +lws_genrsa_new_keypair(struct lws_context *context, struct lws_genrsa_ctx *ctx, + struct lws_genrsa_elements *el, int bits) +{ + BIGNUM *bn; + int n; + + memset(ctx, 0, sizeof(*ctx)); + + ctx->rsa = RSA_new(); + if (!ctx->rsa) { + lwsl_notice("Failed to create RSA\n"); + return -1; + } + + bn = BN_new(); + if (!bn) + goto cleanup_1; + if (BN_set_word(bn, RSA_F4) != 1) { + BN_free(bn); + goto cleanup_1; + } + + n = RSA_generate_key_ex(ctx->rsa, bits, bn, NULL); + BN_free(bn); + if (n != 1) + goto cleanup_1; + +#if defined(LWS_HAVE_RSA_SET0_KEY) + { + const BIGNUM *mpi[5]; + + RSA_get0_key(ctx->rsa, &mpi[JWK_KEY_N], &mpi[JWK_KEY_E], &mpi[JWK_KEY_D]); + RSA_get0_factors(ctx->rsa, &mpi[JWK_KEY_P], &mpi[JWK_KEY_Q]); +#else + { + BIGNUM *mpi[5] = { + ctx->rsa->n, ctx->rsa->e, ctx->rsa->d, + ctx->rsa->p, ctx->rsa->q, + }; +#endif + for (n = 0; n < 5; n++) + if (BN_num_bytes(mpi[n])) { + el->e[n].buf = lws_malloc( + BN_num_bytes(mpi[n]), "genrsakey"); + if (!el->e[n].buf) + goto cleanup; + el->e[n].len = BN_num_bytes(mpi[n]); + BN_bn2bin(mpi[n], el->e[n].buf); + } + } + + return 0; + +cleanup: + for (n = 0; n < LWS_COUNT_RSA_ELEMENTS; n++) + if (el->e[n].buf) + lws_free_set_NULL(el->e[n].buf); +cleanup_1: + RSA_free(ctx->rsa); + + return -1; +} + +LWS_VISIBLE 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) +{ + uint32_t m; + + m = RSA_public_decrypt(in_len, in, out, ctx->rsa, RSA_PKCS1_PADDING); + + /* the bignums are also freed by freeing the RSA */ + RSA_free(ctx->rsa); + ctx->rsa = NULL; + + if (m != (uint32_t)-1) + return (int)m; + + return -1; +} + +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; +} + +LWS_VISIBLE 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) +{ + int n = lws_genrsa_genrsa_hash_to_NID(hash_type), + h = lws_genhash_size(hash_type); + + if (n < 0) + return -1; + + n = RSA_verify(n, in, h, (uint8_t *)sig, sig_len, ctx->rsa); + if (n != 1) { + lwsl_notice("%s: -0x%x\n", __func__, -n); + + return -1; + } + + return 0; +} + +LWS_VISIBLE 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) +{ + int n = lws_genrsa_genrsa_hash_to_NID(hash_type), + h = lws_genhash_size(hash_type); + unsigned int used = 0; + + if (n < 0) + return -1; + + n = RSA_sign(n, in, h, sig, &used, ctx->rsa); + if (n != 1) { + lwsl_notice("%s: -0x%x\n", __func__, -n); + + return -1; + } + + return used; +} + +LWS_VISIBLE void +lws_genrsa_destroy(struct lws_genrsa_ctx *ctx) +{ + if (!ctx->rsa) + return; + +#if defined(LWS_HAVE_RSA_SET0_KEY) + if (RSA_set0_key(ctx->rsa, NULL, NULL, NULL) != 1) + lwsl_notice("RSA_set0_key failed\n"); + RSA_set0_factors(ctx->rsa, NULL, NULL); + +#else + ctx->rsa->e = NULL; + ctx->rsa->n = NULL; + ctx->rsa->d = NULL; + ctx->rsa->p = NULL; + ctx->rsa->q = NULL; +#endif + + RSA_free(ctx->rsa); + ctx->rsa = NULL; +} diff --git a/plugins/ssh-base/sshd.c b/plugins/ssh-base/sshd.c index da4d4009..a419cfef 100644 --- a/plugins/ssh-base/sshd.c +++ b/plugins/ssh-base/sshd.c @@ -524,16 +524,11 @@ ssh_destroy_channel(struct per_session_data__sshd *pss, static int lws_ssh_parse_plaintext(struct per_session_data__sshd *pss, uint8_t *p, size_t len) { -#if defined(LWS_WITH_MBEDTLS) - mbedtls_rsa_context *ctx; -#else - BIGNUM *bn_e = NULL, *bn_n = NULL; - RSA *rsa = NULL; -#endif + struct lws_genrsa_elements el; + struct lws_genrsa_ctx ctx; struct lws_ssh_channel *ch; struct lws_subprotocol_scp *scp; uint8_t *pp, *ps, hash[64], *otmp; - size_t olen; uint32_t m; int n; @@ -1223,76 +1218,22 @@ again: * Prepare the RSA decryption context: load in * the E and N factors */ -#if defined(LWS_WITH_MBEDTLS) - ctx = sshd_zalloc(sizeof(*ctx)); - if (!ctx) - goto ua_fail; - mbedtls_rsa_init(ctx, MBEDTLS_RSA_PKCS_V15, 0); + memset(&el, 0, sizeof(el)); pp = pss->ua->pubkey; m = lws_g32(&pp); pp += m; m = lws_g32(&pp); - if (mbedtls_mpi_read_binary(&ctx->E, pp, m)) - lwsl_notice("mpi load E failed\n"); + el.e[JWK_KEY_E].buf = pp; + el.e[JWK_KEY_E].len = m; pp += m; m = lws_g32(&pp); + el.e[JWK_KEY_N].buf = pp; + el.e[JWK_KEY_N].len = m; - m = mbedtls_mpi_read_binary(&ctx->N, pp, m); - if (m) - lwsl_notice("mpi load N failed %d\n", m); -#else - /* Step 1: - * - * convert the MPI for e and n to OpenSSL BIGNUMs - */ - - pp = pss->ua->pubkey; - m = lws_g32(&pp); - pp += m; - m = lws_g32(&pp); - pp -= 4; - bn_e = BN_mpi2bn(pp, m + 4, NULL); - if (!bn_e) { - lwsl_notice("mpi load E failed\n"); + if (lws_genrsa_create(&ctx, &el)) goto ua_fail; - } - pp += m + 4; - m = lws_g32(&pp); - pp -= 4; - bn_n = BN_mpi2bn(pp, m + 4, NULL); - if (!bn_n) { - lwsl_notice("mpi load N failed %d\n", m); - BN_free(bn_e); - bn_e = NULL; - goto ua_fail; - } - /* Step 2: - * - * assemble the OpenSSL RSA from the BIGNUMs - */ - - rsa = RSA_new(); - if (!rsa) { - lwsl_notice("Failed to create RSA\n"); - BN_free(bn_e); - BN_free(bn_n); - goto ua_fail; - } -#if defined(LWS_HAVE_RSA_SET0_KEY) - if (RSA_set0_key(rsa, bn_n, bn_e, NULL) != 1) { - lwsl_notice("RSA_set0_key failed\n"); - BN_free(bn_e); - BN_free(bn_n); - goto ua_fail; - } - -#else - rsa->e = bn_e; - rsa->n = bn_n; -#endif -#endif /* * point to the encrypted signature payload we * were sent @@ -1301,39 +1242,21 @@ again: m = lws_g32(&pp); pp += m; m = lws_g32(&pp); -#if defined(LWS_WITH_MBEDTLS) - ctx->len = m; -#endif /* - * decrypt it, resulting in an error or some - * ASN1 including the decrypted signature + * decrypt it, resulting in an error, or some ASN1 + * including the decrypted signature */ - otmp = sshd_zalloc(m); if (!otmp) /* ua_fail1 frees bn_e, bn_n and rsa */ goto ua_fail1; -#if defined(LWS_WITH_MBEDTLS) - m = mbedtls_rsa_rsaes_pkcs1_v15_decrypt(ctx, - NULL, NULL, MBEDTLS_RSA_PUBLIC, - &olen, pp, otmp, m); -#else - olen = 0; - m = RSA_public_decrypt((int)m, pp, otmp, rsa, - RSA_PKCS1_PADDING); - if (m != (uint32_t)-1) { - olen = m; - m = 0; - } - /* the bignums are also freed by freeing the RSA */ - RSA_free(rsa); -#endif - if (!m) { + + n = lws_genrsa_public_decrypt(&ctx, pp, m, otmp, m); + if (n > 0) { /* the decrypted sig is in ASN1 format */ m = 0; - - while (m < olen) { + while ((int)m < n) { /* sig payload */ if (otmp[m] == 0x04 && otmp[m + 1] == lws_genhash_size( @@ -1350,17 +1273,15 @@ again: /* otherwise skip payloads */ m += otmp[m + 1] + 2; } - } else - lwsl_notice("decrypt failed\n"); -#if defined(LWS_WITH_MBEDTLS) - mbedtls_rsa_free(ctx); - free(ctx); -#endif + } + free(otmp); + lws_genrsa_destroy(&ctx); + /* * if no good, m is nonzero and inform peer */ - if (m) { + if (n <= 0) { lwsl_notice("hash sig verify fail: %d\n", m); goto ua_fail; } @@ -1878,13 +1799,7 @@ ch_fail: break; ua_fail1: -#if defined(LWS_WITH_MBEDTLS) - mbedtls_rsa_free(ctx); - free(ctx); -#else - /* also frees the bignums */ - RSA_free(rsa); -#endif + lws_genrsa_destroy(&ctx); ua_fail: write_task(pss, NULL, SSH_WT_UA_FAILURE); ua_fail_silently: