| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522 |
- /*
- * 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-mbedtls.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;
- /*
- * d (the private part) may be missing, otherwise it and everything
- * else must match the expected bignum size
- */
- 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 -23;
- mbedtls_ecp_keypair_init(&kp);
- if (mbedtls_ecp_group_load(&kp.grp, curve->tls_lib_nid))
- goto bail1;
- ctx->has_private = !!el[LWS_GENCRYPTO_EC_KEYEL_D].len;
- /* d (the private key) is directly an mpi */
- if (ctx->has_private &&
- 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;
- mbedtls_mpi_lset(&kp.Q.Z, 1);
- switch (ctx->genec_alg) {
- case LEGENEC_ECDH:
- if (mbedtls_ecdh_get_params(ctx->u.ctx_ecdh, &kp,
- (mbedtls_ecdh_side)side))
- goto bail1;
- /* verify the key is consistent with the claimed curve */
- if (ctx->has_private &&
- mbedtls_ecp_check_privkey(&ctx->u.ctx_ecdh->grp,
- &ctx->u.ctx_ecdh->d))
- goto bail1;
- if (mbedtls_ecp_check_pubkey(&ctx->u.ctx_ecdh->grp,
- &ctx->u.ctx_ecdh->Q))
- goto bail1;
- break;
- case LEGENEC_ECDSA:
- if (mbedtls_ecdsa_from_keypair(ctx->u.ctx_ecdsa, &kp))
- goto bail1;
- /* verify the key is consistent with the claimed curve */
- if (ctx->has_private &&
- mbedtls_ecp_check_privkey(&ctx->u.ctx_ecdsa->grp,
- &ctx->u.ctx_ecdsa->d))
- goto bail1;
- if (mbedtls_ecp_check_pubkey(&ctx->u.ctx_ecdsa->grp,
- &ctx->u.ctx_ecdsa->Q))
- goto bail1;
- break;
- default:
- goto bail1;
- }
- ret = 0;
- bail1:
- mbedtls_ecp_keypair_free(&kp);
- return ret;
- }
- 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;
- }
- 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_ecdsa = lws_zalloc(sizeof(*ctx->u.ctx_ecdsa), "genecdsa");
- if (!ctx->u.ctx_ecdsa)
- return 1;
- mbedtls_ecdsa_init(ctx->u.ctx_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, 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, 0, el);
- }
- 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;
- }
- }
- 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,
- (mbedtls_ecdh_side)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;
- }
- 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, el[n].len)) {
- lwsl_err("%s: mbedtls_mpi_write_binary failed\n", __func__);
- 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;
- }
- 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 n, keybytes = lws_gencrypto_bits_to_bytes(keybits);
- size_t hlen = lws_genhash_size(hash_type);
- mbedtls_mpi mpi_r, mpi_s;
- size_t slen = sig_len;
- if (ctx->genec_alg != LEGENEC_ECDSA)
- return -1;
- /*
- * 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.
- */
- mbedtls_mpi_init(&mpi_r);
- mbedtls_mpi_init(&mpi_s);
- n = mbedtls_ecdsa_sign(&ctx->u.ctx_ecdsa->grp, &mpi_r, &mpi_s,
- &ctx->u.ctx_ecdsa->d, in, hlen,
- lws_gencrypto_mbedtls_rngf, ctx->context);
- if (n) {
- lwsl_err("%s: mbedtls_ecdsa_sign failed: -0x%x\n",
- __func__, -n);
- goto bail2;
- }
- if (mbedtls_mpi_write_binary(&mpi_r, sig, keybytes))
- goto bail2;
- mbedtls_mpi_free(&mpi_r);
- if (mbedtls_mpi_write_binary(&mpi_s, sig + keybytes, keybytes))
- goto bail1;
- mbedtls_mpi_free(&mpi_s);
- return (int)slen;
- bail2:
- mbedtls_mpi_free(&mpi_r);
- bail1:
- mbedtls_mpi_free(&mpi_s);
- return -3;
- }
- 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 n, keybytes = lws_gencrypto_bits_to_bytes(keybits);
- size_t hlen = lws_genhash_size(hash_type);
- mbedtls_mpi mpi_r, mpi_s;
- if (ctx->genec_alg != LEGENEC_ECDSA)
- return -1;
- if ((int)sig_len != keybytes * 2)
- return -1;
- /*
- * 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.
- */
- mbedtls_mpi_init(&mpi_r);
- mbedtls_mpi_init(&mpi_s);
- if (mbedtls_mpi_read_binary(&mpi_r, sig, keybytes))
- return -1;
- if (mbedtls_mpi_read_binary(&mpi_s, sig + keybytes, keybytes))
- goto bail1;
- n = mbedtls_ecdsa_verify(&ctx->u.ctx_ecdsa->grp, in, hlen,
- &ctx->u.ctx_ecdsa->Q, &mpi_r, &mpi_s);
- mbedtls_mpi_free(&mpi_s);
- mbedtls_mpi_free(&mpi_r);
- if (n) {
- lwsl_err("%s: mbedtls_ecdsa_verify failed: -0x%x\n",
- __func__, -n);
- goto bail;
- }
- return 0;
- bail1:
- mbedtls_mpi_free(&mpi_r);
- bail:
- return -3;
- }
- int
- lws_genecdh_compute_shared_secret(struct lws_genec_ctx *ctx, uint8_t *ss,
- int *ss_len)
- {
- int n;
- size_t st;
- if (mbedtls_ecp_check_pubkey(&ctx->u.ctx_ecdh->grp, &ctx->u.ctx_ecdh->Q) ||
- mbedtls_ecp_check_pubkey(&ctx->u.ctx_ecdh->grp, &ctx->u.ctx_ecdh->Qp)) {
- lwsl_err("%s: both sides must be set up\n", __func__);
- return -1;
- }
- n = mbedtls_ecdh_calc_secret(ctx->u.ctx_ecdh, &st, ss, *ss_len,
- lws_gencrypto_mbedtls_rngf, ctx->context);
- if (n)
- return -1;
- *ss_len = (int)st;
- return 0;
- }
|