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

genec: generic ECDH crypto layer

!!! WIP

This implements the "genec" layer wrapping mbedtls + openssl
ECDH support.

API tests are added for the parts that are implemented so far.

Stuff related to ec at all, like keys, are prefixed lws_genec_.
Stuff specific to ECDH are prefixed lws_genecdh_.
This commit is contained in:
Andy Green 2018-12-05 13:11:03 +08:00
parent 47e14ba34b
commit a3dcc95471
51 changed files with 2748 additions and 664 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -421,14 +421,17 @@ struct lws;
#include <mbedtls/sha512.h>
#endif
#include <libwebsockets/lws-gencrypto.h>
#include <libwebsockets/lws-genhash.h>
#include <libwebsockets/lws-jwk.h>
#include <libwebsockets/lws-jose.h>
#include <libwebsockets/lws-jws.h>
#include <libwebsockets/lws-genrsa.h>
#include <libwebsockets/lws-genaes.h>
#include <libwebsockets/lws-genec.h>
#include <libwebsockets/lws-jose.h>
#include <libwebsockets/lws-jwk.h>
#include <libwebsockets/lws-jws.h>
#include <libwebsockets/lws-jwe.h>
#endif
#ifdef __cplusplus

View file

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

View file

@ -0,0 +1,94 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2018 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
*
* 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;
};

View file

@ -1,7 +1,7 @@
/*
* libwebsockets - Generic Elliptic Curve Encryption
*
* Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
* Copyright (C) 2010 - 2018 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
@ -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);

View file

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

View file

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

View file

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

View file

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

View file

@ -1,7 +1,7 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
* Copyright (C) 2010 - 2018 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
@ -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);
///@}

View file

@ -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);
/**

View file

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

View file

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

View file

@ -25,10 +25,10 @@
#include <unistd.h>
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:

View file

@ -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);
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,308 @@
/*
* libwebsockets - generic crypto hiding the backend - common parts
*
* Copyright (C) 2017 - 2018 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
*/
#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;
}

View file

@ -0,0 +1,73 @@
/*
* libwebsockets - generic EC api hiding the backend - common parts
*
* Copyright (C) 2017 - 2018 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_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;
}

View file

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

View file

@ -0,0 +1,59 @@
/*
* libwebsockets - generic crypto api hiding the backend
*
* Copyright (C) 2017 - 2018 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-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;
}

View file

@ -0,0 +1,526 @@
/*
* libwebsockets - generic EC api hiding the backend - mbedtls implementation
*
* Copyright (C) 2017 - 2018 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_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

View file

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

View file

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

View file

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

View file

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

28
lib/tls/mbedtls/private.h Normal file
View file

@ -0,0 +1,28 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2018 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
*
* 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);

View file

@ -23,7 +23,7 @@
#include <mbedtls/oid.h>
void
lws_ssl_elaborate_error(void)
lws_tls_err_describe(void)
{
}

View file

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

View file

@ -0,0 +1,75 @@
/*
* libwebsockets - generic crypto api hiding the backend
*
* Copyright (C) 2017 - 2018 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-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;
}

View file

@ -0,0 +1,431 @@
/*
* libwebsockets - generic EC api hiding the backend - openssl implementation
*
* Copyright (C) 2017 - 2018 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_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;
}

View file

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

View file

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

View file

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

28
lib/tls/openssl/private.h Normal file
View file

@ -0,0 +1,28 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2018 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
*
* 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);

View file

@ -61,6 +61,8 @@
#include <mbedtls/gcm.h>
#include <mbedtls/x509_crt.h>
#include <mbedtls/x509_csr.h>
#include <mbedtls/ecp.h>
#include <mbedtls/ecdsa.h>
#include "tls/mbedtls/wrapper/include/openssl/ssl.h" /* wrapper !!!! */
#else
#include <openssl/ssl.h>
@ -74,6 +76,9 @@
#ifdef LWS_HAVE_OPENSSL_ECDH_H
#include <openssl/ecdh.h>
#endif
#if !defined(LWS_HAVE_EVP_MD_CTX_free)
#define EVP_MD_CTX_free EVP_MD_CTX_destroy
#endif
#include <openssl/x509v3.h>
#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

View file

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

View file

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

View file

@ -0,0 +1,132 @@
/*
* lws-api-test-gencrypto - lws-genec
*
* Copyright (C) 2018 Andy Green <andy@warmcat.com>
*
* This file is made available under the Creative Commons CC0 1.0
* Universal Public Domain Dedication.
*/
#include <libwebsockets.h>
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;
}

View file

@ -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");

View file

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

View file

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

View file

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

View file

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