| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407 |
- /*
- * 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_genrsa provides an RSA 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.
- */
- void
- lws_genrsa_destroy_elements(struct lws_gencrypto_keyelem *el)
- {
- lws_gencrypto_destroy_elements(el, LWS_GENCRYPTO_RSA_KEYEL_COUNT);
- }
- static int mode_map_crypt[] = { RSA_PKCS1_PADDING, RSA_PKCS1_OAEP_PADDING },
- mode_map_sig[] = { RSA_PKCS1_PADDING, RSA_PKCS1_PSS_PADDING };
- static int
- rsa_pkey_wrap(struct lws_genrsa_ctx *ctx, RSA *rsa)
- {
- EVP_PKEY *pkey;
- /* we have the RSA object filled up... wrap in a PKEY */
- pkey = EVP_PKEY_new();
- if (!pkey)
- return 1;
- /* bind the PKEY to the RSA key we just prepared */
- if (EVP_PKEY_assign_RSA(pkey, rsa) != 1) {
- lwsl_err("%s: EVP_PKEY_assign_RSA_KEY failed\n", __func__);
- goto bail;
- }
- /* pepare our PKEY_CTX with the PKEY */
- ctx->ctx = EVP_PKEY_CTX_new(pkey, NULL);
- EVP_PKEY_free(pkey);
- pkey = NULL;
- if (!ctx->ctx)
- goto bail;
- return 0;
- bail:
- if (pkey)
- EVP_PKEY_free(pkey);
- return 1;
- }
- int
- lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_gencrypto_keyelem *el,
- struct lws_context *context, enum enum_genrsa_mode mode,
- enum lws_genhash_types oaep_hashid)
- {
- int n;
- memset(ctx, 0, sizeof(*ctx));
- ctx->context = context;
- ctx->mode = mode;
- /* Step 1:
- *
- * convert the MPI for e and n to OpenSSL BIGNUMs
- */
- for (n = 0; n < 5; n++) {
- ctx->bn[n] = BN_bin2bn(el[n].buf, el[n].len, NULL);
- if (!ctx->bn[n]) {
- lwsl_notice("mpi load failed\n");
- goto bail;
- }
- }
- /* Step 2:
- *
- * assemble the OpenSSL RSA from the BIGNUMs
- */
- ctx->rsa = RSA_new();
- if (!ctx->rsa) {
- lwsl_notice("Failed to create RSA\n");
- goto bail;
- }
- #if defined(LWS_HAVE_RSA_SET0_KEY)
- if (RSA_set0_key(ctx->rsa, ctx->bn[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[LWS_GENCRYPTO_RSA_KEYEL_P],
- ctx->bn[LWS_GENCRYPTO_RSA_KEYEL_Q]);
- #else
- 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))
- return 0;
- bail:
- for (n = 0; n < 5; n++)
- if (ctx->bn[n]) {
- BN_clear_free(ctx->bn[n]);
- ctx->bn[n] = NULL;
- }
- if (ctx->rsa) {
- RSA_free(ctx->rsa);
- ctx->rsa = NULL;
- }
- return 1;
- }
- int
- lws_genrsa_new_keypair(struct lws_context *context, struct lws_genrsa_ctx *ctx,
- enum enum_genrsa_mode mode, struct lws_gencrypto_keyelem *el,
- int bits)
- {
- BIGNUM *bn;
- int n;
- memset(ctx, 0, sizeof(*ctx));
- ctx->context = context;
- ctx->mode = mode;
- ctx->rsa = RSA_new();
- if (!ctx->rsa) {
- lwsl_notice("Failed to create RSA\n");
- return -1;
- }
- bn = BN_new();
- if (!bn)
- goto cleanup_1;
- if (BN_set_word(bn, RSA_F4) != 1) {
- BN_free(bn);
- goto cleanup_1;
- }
- n = RSA_generate_key_ex(ctx->rsa, bits, bn, NULL);
- BN_clear_free(bn);
- if (n != 1)
- goto cleanup_1;
- #if defined(LWS_HAVE_RSA_SET0_KEY)
- {
- const BIGNUM *mpi[5];
- RSA_get0_key(ctx->rsa, &mpi[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->e, ctx->rsa->n, ctx->rsa->d,
- ctx->rsa->p, ctx->rsa->q, };
- #endif
- for (n = 0; n < 5; n++)
- if (BN_num_bytes(mpi[n])) {
- el[n].buf = lws_malloc(
- BN_num_bytes(mpi[n]), "genrsakey");
- if (!el[n].buf)
- goto cleanup;
- el[n].len = BN_num_bytes(mpi[n]);
- BN_bn2bin(mpi[n], el[n].buf);
- }
- }
- if (!rsa_pkey_wrap(ctx, ctx->rsa))
- return 0;
- cleanup:
- for (n = 0; n < LWS_GENCRYPTO_RSA_KEYEL_COUNT; n++)
- if (el[n].buf)
- lws_free_set_NULL(el[n].buf);
- cleanup_1:
- RSA_free(ctx->rsa);
- ctx->rsa = NULL;
- return -1;
- }
- /*
- * in_len must be less than RSA_size(rsa) - 11 for the PKCS #1 v1.5
- * based padding modes
- */
- int
- lws_genrsa_public_encrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in,
- size_t in_len, uint8_t *out)
- {
- int n = RSA_public_encrypt((int)in_len, in, out, ctx->rsa,
- mode_map_crypt[ctx->mode]);
- if (n < 0) {
- lwsl_err("%s: RSA_public_encrypt failed\n", __func__);
- lws_tls_err_describe_clear();
- return -1;
- }
- return n;
- }
- int
- lws_genrsa_private_encrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in,
- size_t in_len, uint8_t *out)
- {
- int n = RSA_private_encrypt((int)in_len, in, out, ctx->rsa,
- mode_map_crypt[ctx->mode]);
- if (n < 0) {
- lwsl_err("%s: RSA_private_encrypt failed\n", __func__);
- lws_tls_err_describe_clear();
- return -1;
- }
- return n;
- }
- 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)
- {
- int n = RSA_public_decrypt((int)in_len, in, out, ctx->rsa,
- mode_map_crypt[ctx->mode]);
- if (n < 0) {
- lwsl_err("%s: RSA_public_decrypt failed\n", __func__);
- return -1;
- }
- return n;
- }
- int
- lws_genrsa_private_decrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in,
- size_t in_len, uint8_t *out, size_t out_max)
- {
- int n = RSA_private_decrypt((int)in_len, in, out, ctx->rsa,
- mode_map_crypt[ctx->mode]);
- if (n < 0) {
- lwsl_err("%s: RSA_private_decrypt failed\n", __func__);
- lws_tls_err_describe_clear();
- return -1;
- }
- return n;
- }
- int
- 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_gencrypto_openssl_hash_to_NID(hash_type),
- h = (int)lws_genhash_size(hash_type);
- const EVP_MD *md = NULL;
- if (n < 0)
- return -1;
- switch(ctx->mode) {
- case LGRSAM_PKCS1_1_5:
- n = RSA_verify(n, in, h, (uint8_t *)sig, (int)sig_len, ctx->rsa);
- break;
- case LGRSAM_PKCS1_OAEP_PSS:
- md = lws_gencrypto_openssl_hash_to_EVP_MD(hash_type);
- if (!md)
- return -1;
- #if defined(LWS_HAVE_RSA_verify_pss_mgf1)
- n = RSA_verify_pss_mgf1(ctx->rsa, in, h, md, NULL, -1,
- (uint8_t *)sig,
- #else
- n = RSA_verify_PKCS1_PSS(ctx->rsa, in, md, (uint8_t *)sig,
- #endif
- (int)sig_len);
- break;
- default:
- return -1;
- }
- if (n != 1) {
- lwsl_notice("%s: fail\n", __func__);
- lws_tls_err_describe_clear();
- return -1;
- }
- return 0;
- }
- int
- 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_gencrypto_openssl_hash_to_NID(hash_type),
- h = (int)lws_genhash_size(hash_type);
- unsigned int used = 0;
- EVP_MD_CTX *mdctx = NULL;
- const EVP_MD *md = NULL;
- if (n < 0)
- return -1;
- switch(ctx->mode) {
- case LGRSAM_PKCS1_1_5:
- if (RSA_sign(n, in, h, sig, &used, ctx->rsa) != 1) {
- lwsl_err("%s: RSA_sign failed\n", __func__);
- goto bail;
- }
- break;
- case LGRSAM_PKCS1_OAEP_PSS:
- md = lws_gencrypto_openssl_hash_to_EVP_MD(hash_type);
- if (!md)
- return -1;
- if (EVP_PKEY_CTX_set_rsa_padding(ctx->ctx,
- mode_map_sig[ctx->mode]) != 1) {
- lwsl_err("%s: set_rsa_padding failed\n", __func__);
- goto bail;
- }
- 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);
- used = (int)sig_len;
- break;
- default:
- return -1;
- }
- return used;
- bail:
- if (mdctx)
- EVP_MD_CTX_free(mdctx);
- return -1;
- }
- void
- lws_genrsa_destroy(struct lws_genrsa_ctx *ctx)
- {
- if (!ctx->ctx)
- return;
- EVP_PKEY_CTX_free(ctx->ctx);
- ctx->ctx = NULL;
- ctx->rsa = NULL;
- }
|