diff options
author | Andy Green <andy@warmcat.com> | 2018-12-05 13:11:03 +0800 |
---|---|---|
committer | Andy Green <andy@warmcat.com> | 2018-12-27 06:45:31 +0800 |
commit | a3dcc95471c34c9a819ee1327ac03a74d1fb4f78 (patch) | |
tree | d8e337f52d7a87f5171eb3a03f103c26a530edc3 /minimal-examples/api-tests | |
parent | 47e14ba34bc845d81b6387a902c1fa37a0c685bc (diff) | |
download | libwebsockets-a3dcc95471c34c9a819ee1327ac03a74d1fb4f78.tar.gz |
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_.
Diffstat (limited to 'minimal-examples/api-tests')
6 files changed, 206 insertions, 51 deletions
diff --git a/minimal-examples/api-tests/api-test-gencrypto/CMakeLists.txt b/minimal-examples/api-tests/api-test-gencrypto/CMakeLists.txt index a36a5cda..0679f88a 100644 --- a/minimal-examples/api-tests/api-test-gencrypto/CMakeLists.txt +++ b/minimal-examples/api-tests/api-test-gencrypto/CMakeLists.txt @@ -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) diff --git a/minimal-examples/api-tests/api-test-gencrypto/lws-genaes.c b/minimal-examples/api-tests/api-test-gencrypto/lws-genaes.c index 63491251..b14e08e5 100644 --- a/minimal-examples/api-tests/api-test-gencrypto/lws-genaes.c +++ b/minimal-examples/api-tests/api-test-gencrypto/lws-genaes.c @@ -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; diff --git a/minimal-examples/api-tests/api-test-gencrypto/lws-genec.c b/minimal-examples/api-tests/api-test-gencrypto/lws-genec.c new file mode 100644 index 00000000..d640650d --- /dev/null +++ b/minimal-examples/api-tests/api-test-gencrypto/lws-genec.c @@ -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; +} diff --git a/minimal-examples/api-tests/api-test-gencrypto/main.c b/minimal-examples/api-tests/api-test-gencrypto/main.c index 7bdcdf53..fd808c69 100644 --- a/minimal-examples/api-tests/api-test-gencrypto/main.c +++ b/minimal-examples/api-tests/api-test-gencrypto/main.c @@ -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"); diff --git a/minimal-examples/api-tests/api-test-jose/jwe.c b/minimal-examples/api-tests/api-test-jose/jwe.c index cb88492c..27b8b9b3 100644 --- a/minimal-examples/api-tests/api-test-jose/jwe.c +++ b/minimal-examples/api-tests/api-test-jose/jwe.c @@ -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; diff --git a/minimal-examples/api-tests/api-test-jose/jws.c b/minimal-examples/api-tests/api-test-jose/jws.c index d82b0ca7..d66978e8 100644 --- a/minimal-examples/api-tests/api-test-jose/jws.c +++ b/minimal-examples/api-tests/api-test-jose/jws.c @@ -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) { - struct lws_genhmac_ctx ctx; - struct lws_jwk jwk; 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; 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; |