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

lws-genrsa: add resuable backend-independent rsa decrypt in tls/ and migrate sshd to it

This commit is contained in:
Andy Green 2017-10-19 11:21:27 +08:00
parent dd3e5619cb
commit c32a22c20b
5 changed files with 792 additions and 108 deletions

View file

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

View file

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

View file

@ -0,0 +1,329 @@
/*
* libwebsockets - generic RSA api hiding the backend
*
* Copyright (C) 2017 Andy Green <andy@warmcat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation:
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* lws_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;
}

View file

@ -0,0 +1,269 @@
/*
* libwebsockets - generic RSA api hiding the backend
*
* Copyright (C) 2017 Andy Green <andy@warmcat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation:
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* lws_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;
}

View file

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