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:
parent
dd3e5619cb
commit
c32a22c20b
5 changed files with 792 additions and 108 deletions
|
@ -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()
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
329
lib/tls/mbedtls/lws-genrsa.c
Normal file
329
lib/tls/mbedtls/lws-genrsa.c
Normal 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;
|
||||
}
|
269
lib/tls/openssl/lws-genrsa.c
Normal file
269
lib/tls/openssl/lws-genrsa.c
Normal 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;
|
||||
}
|
|
@ -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:
|
||||
|
|
Loading…
Add table
Reference in a new issue