| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664 |
- /*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010 - 2019 Andy Green <[email protected]>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- *
- * lws_genec provides an EC abstraction api in lws that works the
- * same whether you are using openssl or mbedtls crypto functions underneath.
- */
- #include "private-lib-core.h"
- #include "private-lib-tls-openssl.h"
- /*
- * Care: many openssl apis return 1 for success. These are translated to the
- * lws convention of 0 for success.
- */
- #if !defined(LWS_HAVE_ECDSA_SIG_set0)
- static void
- ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
- {
- if (pr != NULL)
- *pr = sig->r;
- if (ps != NULL)
- *ps = sig->s;
- }
- static int
- ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
- {
- if (r == NULL || s == NULL)
- return 0;
- BN_clear_free(sig->r);
- BN_clear_free(sig->s);
- sig->r = r;
- sig->s = s;
- return 1;
- }
- #endif
- #if !defined(LWS_HAVE_BN_bn2binpad)
- int BN_bn2binpad(const BIGNUM *a, unsigned char *to, int tolen)
- {
- int i;
- BN_ULONG l;
- bn_check_top(a);
- i = BN_num_bytes(a);
- /* Add leading zeroes if necessary */
- if (tolen > i) {
- memset(to, 0, tolen - i);
- to += tolen - i;
- }
- while (i--) {
- l = a->d[i / BN_BYTES];
- *(to++) = (unsigned char)(l >> (8 * (i % BN_BYTES))) & 0xff;
- }
- return tolen;
- }
- #endif
- const struct lws_ec_curves lws_ec_curves[4] = {
- /*
- * 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_clear();
- goto bail;
- }
- if (el[LWS_GENCRYPTO_EC_KEYEL_D].len) {
- 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_clear_free(bn_d);
- if (n != 1) {
- lwsl_err("%s: EC_KEY_set_private_key fail\n", __func__);
- goto bail;
- }
- }
- /* explicitly confirm the key pieces are consistent */
- if (EC_KEY_check_key(ec) != 1) {
- lwsl_err("%s: EC_KEY_set_private_key fail\n", __func__);
- goto bail;
- }
- n = EVP_PKEY_assign_EC_KEY(pkey, ec);
- if (n != 1) {
- lwsl_err("%s: EVP_PKEY_set1_EC_KEY failed\n", __func__);
- return -1;
- }
- return 0;
- bail1:
- BN_free(bn_x);
- bail:
- EC_KEY_free(ec);
- return -1;
- }
- static int
- lws_genec_keypair_import(struct lws_genec_ctx *ctx,
- 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 &&
- 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;
- ctx->has_private = !!el[LWS_GENCRYPTO_EC_KEYEL_D].len;
- 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;
- }
- 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[0] = NULL;
- ctx->ctx[1] = NULL;
- ctx->curve_table = curve_table;
- ctx->genec_alg = LEGENEC_ECDH;
- return 0;
- }
- 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[0] = NULL;
- ctx->ctx[1] = NULL;
- ctx->curve_table = curve_table;
- ctx->genec_alg = LEGENEC_ECDSA;
- return 0;
- }
- 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, ctx->curve_table, &ctx->ctx[side], el);
- }
- 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, ctx->curve_table, &ctx->ctx[0], el);
- }
- static void
- lws_genec_keypair_destroy(EVP_PKEY_CTX **pctx)
- {
- if (!*pctx)
- return;
- // lwsl_err("%p\n", EVP_PKEY_get1_EC_KEY(EVP_PKEY_CTX_get0_pkey(*pctx)));
- // EC_KEY_free(EVP_PKEY_get1_EC_KEY(EVP_PKEY_CTX_get0_pkey(*pctx)));
- EVP_PKEY_CTX_free(*pctx);
- *pctx = NULL;
- }
- void
- lws_genec_destroy(struct lws_genec_ctx *ctx)
- {
- if (ctx->ctx[0])
- lws_genec_keypair_destroy(&ctx->ctx[0]);
- if (ctx->ctx[1])
- lws_genec_keypair_destroy(&ctx->ctx[1]);
- }
- 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;
- 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) {
- lwsl_err("%s: unknown nid %d\n", __func__, curve->tls_lib_nid);
- return -23;
- }
- if (EC_KEY_generate_key(ec) != 1) {
- lwsl_err("%s: EC_KEY_generate_key failed\n", __func__);
- 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[side] = EVP_PKEY_CTX_new(pkey, NULL);
- if (!ctx->ctx[side]) {
- 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) {
- lwsl_err("%s: EC_KEY_get0_public_key failed\n", __func__);
- goto bail1;
- }
- bn[0] = BN_new();
- bn[1] = (BIGNUM *)EC_KEY_get0_private_key(ec);
- bn[2] = BN_new();
- #if defined(LWS_HAVE_EC_POINT_get_affine_coordinates)
- if (EC_POINT_get_affine_coordinates(EC_KEY_get0_group(ec),
- #else
- if (EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(ec),
- #endif
- 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 = (uint32_t)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) {
- lwsl_err("%s: OOM\n", __func__);
- 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_bn2binpad(bn[n - 1], el[n].buf, el[n].len);
- if ((uint32_t)m != el[n].len)
- goto bail2;
- }
- ctx->has_private = 1;
- ret = 0;
- bail2:
- BN_clear_free(bn[0]);
- BN_clear_free(bn[2]);
- bail1:
- EVP_PKEY_free(pkey);
- bail:
- EC_KEY_free(ec);
- return ret;
- }
- 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);
- }
- 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);
- }
- #if 0
- 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;
- }
- #endif
- int
- lws_genecdsa_hash_sign_jws(struct lws_genec_ctx *ctx, const uint8_t *in,
- enum lws_genhash_types hash_type, int keybits,
- uint8_t *sig, size_t sig_len)
- {
- int ret = -1, n, keybytes = lws_gencrypto_bits_to_bytes(keybits);
- const BIGNUM *r = NULL, *s = NULL;
- ECDSA_SIG *ecdsasig;
- EC_KEY *eckey;
- if (ctx->genec_alg != LEGENEC_ECDSA) {
- lwsl_notice("%s: ctx alg %d\n", __func__, ctx->genec_alg);
- return -1;
- }
- if (!ctx->has_private)
- return -1;
- if ((int)sig_len < keybytes * 2) {
- lwsl_notice("%s: sig buff %d < %d\n", __func__,
- (int)sig_len, keybytes * 2);
- return -1;
- }
- eckey = EVP_PKEY_get1_EC_KEY(EVP_PKEY_CTX_get0_pkey(ctx->ctx[0]));
- /*
- * The ECDSA P-256 SHA-256 digital signature is generated as follows:
- *
- * 1. Generate a digital signature of the JWS Signing Input using ECDSA
- * P-256 SHA-256 with the desired private key. The output will be
- * the pair (R, S), where R and S are 256-bit unsigned integers.
- *
- * 2. Turn R and S into octet sequences in big-endian order, with each
- * array being be 32 octets long. The octet sequence
- * representations MUST NOT be shortened to omit any leading zero
- * octets contained in the values.
- *
- * 3. Concatenate the two octet sequences in the order R and then S.
- * (Note that many ECDSA implementations will directly produce this
- * concatenation as their output.)
- *
- * 4. The resulting 64-octet sequence is the JWS Signature value.
- */
- ecdsasig = ECDSA_do_sign(in, (int)lws_genhash_size(hash_type), eckey);
- EC_KEY_free(eckey);
- if (!ecdsasig) {
- lwsl_notice("%s: ECDSA_do_sign fail\n", __func__);
- goto bail;
- }
- ECDSA_SIG_get0(ecdsasig, &r, &s);
- /*
- * in the 521-bit case, we have to pad the last byte as it only
- * generates 65 bytes
- */
- n = BN_bn2binpad(r, sig, keybytes);
- if (n != keybytes) {
- lwsl_notice("%s: bignum r fail %d %d\n", __func__, n, keybytes);
- goto bail;
- }
- n = BN_bn2binpad(s, sig + keybytes, keybytes);
- if (n != keybytes) {
- lwsl_notice("%s: bignum s fail %d %d\n", __func__, n, keybytes);
- goto bail;
- }
- ret = 0;
- bail:
- if (ecdsasig)
- ECDSA_SIG_free(ecdsasig);
- return ret;
- }
- /* in is the JWS Signing Input hash */
- int
- lws_genecdsa_hash_sig_verify_jws(struct lws_genec_ctx *ctx, const uint8_t *in,
- enum lws_genhash_types hash_type, int keybits,
- const uint8_t *sig, size_t sig_len)
- {
- int ret = -1, n, keybytes = lws_gencrypto_bits_to_bytes(keybits),
- hlen = (int)lws_genhash_size(hash_type);
- ECDSA_SIG *ecsig = ECDSA_SIG_new();
- BIGNUM *r = NULL, *s = NULL;
- EC_KEY *eckey;
- if (!ecsig)
- return -1;
- if (ctx->genec_alg != LEGENEC_ECDSA)
- goto bail;
- if ((int)sig_len != keybytes * 2) {
- lwsl_err("%s: sig buf too small %d vs %d\n", __func__,
- (int)sig_len, keybytes * 2);
- goto bail;
- }
- /*
- * 1. The JWS Signature value MUST be a 64-octet sequence. If it is
- * not a 64-octet sequence, the validation has failed.
- *
- * 2. Split the 64-octet sequence into two 32-octet sequences. The
- * first octet sequence represents R and the second S. The values R
- * and S are represented as octet sequences using the Integer-to-
- * OctetString Conversion defined in Section 2.3.7 of SEC1 [SEC1]
- * (in big-endian octet order).
- *
- * 3. Submit the JWS Signing Input, R, S, and the public key (x, y) to
- * the ECDSA P-256 SHA-256 validator.
- */
- r = BN_bin2bn(sig, keybytes, NULL);
- if (!r) {
- lwsl_err("%s: BN_bin2bn (r) fail\n", __func__);
- goto bail;
- }
- s = BN_bin2bn(sig + keybytes, keybytes, NULL);
- if (!s) {
- lwsl_err("%s: BN_bin2bn (s) fail\n", __func__);
- goto bail1;
- }
- if (ECDSA_SIG_set0(ecsig, r, s) != 1) {
- lwsl_err("%s: ECDSA_SIG_set0 fail\n", __func__);
- goto bail1;
- }
- eckey = EVP_PKEY_get1_EC_KEY(EVP_PKEY_CTX_get0_pkey(ctx->ctx[0]));
- n = ECDSA_do_verify(in, hlen, ecsig, eckey);
- EC_KEY_free(eckey);
- if (n != 1) {
- lwsl_err("%s: ECDSA_do_verify fail\n", __func__);
- lws_tls_err_describe_clear();
- goto bail;
- }
- ret = 0;
- goto bail;
- bail1:
- if (r)
- BN_free(r);
- if (s)
- BN_free(s);
- bail:
- ECDSA_SIG_free(ecsig);
- return ret;
- }
- int
- lws_genecdh_compute_shared_secret(struct lws_genec_ctx *ctx, uint8_t *ss,
- int *ss_len)
- {
- int len, ret = -1;
- EC_KEY *eckey[2];
- if (!ctx->ctx[LDHS_OURS] || !ctx->ctx[LDHS_THEIRS]) {
- lwsl_err("%s: both sides must be set up\n", __func__);
- return -1;
- }
- eckey[LDHS_OURS] = EVP_PKEY_get1_EC_KEY(
- EVP_PKEY_CTX_get0_pkey(ctx->ctx[LDHS_OURS]));
- eckey[LDHS_THEIRS] = EVP_PKEY_get1_EC_KEY(
- EVP_PKEY_CTX_get0_pkey(ctx->ctx[LDHS_THEIRS]));
- len = (EC_GROUP_get_degree(EC_KEY_get0_group(eckey[LDHS_OURS])) + 7) / 8;
- if (len <= *ss_len) {
- *ss_len = ECDH_compute_key(ss, len,
- EC_KEY_get0_public_key(eckey[LDHS_THEIRS]),
- eckey[LDHS_OURS], NULL);
- ret = -(*ss_len < 0);
- }
- EC_KEY_free(eckey[LDHS_OURS]);
- EC_KEY_free(eckey[LDHS_THEIRS]);
- return ret;
- }
|