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:
parent
47e14ba34b
commit
a3dcc95471
51 changed files with 2748 additions and 664 deletions
|
@ -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"
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
94
include/libwebsockets/lws-gencrypto.h
Normal file
94
include/libwebsockets/lws-gencrypto.h
Normal 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;
|
||||
};
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
///@}
|
||||
|
|
|
@ -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);
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
308
lib/tls/lws-gencrypto-common.c
Normal file
308
lib/tls/lws-gencrypto-common.c
Normal 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;
|
||||
}
|
73
lib/tls/lws-genec-common.c
Normal file
73
lib/tls/lws-genec-common.c
Normal 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;
|
||||
}
|
|
@ -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;
|
||||
|
|
59
lib/tls/mbedtls/lws-gencrypto.c
Normal file
59
lib/tls/mbedtls/lws-gencrypto.c
Normal 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;
|
||||
}
|
|
@ -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
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
28
lib/tls/mbedtls/private.h
Normal 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);
|
|
@ -23,7 +23,7 @@
|
|||
#include <mbedtls/oid.h>
|
||||
|
||||
void
|
||||
lws_ssl_elaborate_error(void)
|
||||
lws_tls_err_describe(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
75
lib/tls/openssl/lws-gencrypto.c
Normal file
75
lib/tls/openssl/lws-gencrypto.c
Normal 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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
28
lib/tls/openssl/private.h
Normal 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);
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
132
minimal-examples/api-tests/api-test-gencrypto/lws-genec.c
Normal file
132
minimal-examples/api-tests/api-test-gencrypto/lws-genec.c
Normal 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;
|
||||
}
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
Loading…
Add table
Reference in a new issue