{"schema":"libjg2-1",
"vpath":"/git/",
"avatar":"/git/avatar/",
"alang":"",
"gen_ut":1747291576,
"reponame":"libwebsockets",
"desc":"libwebsockets lightweight C networking library",
"owner": { "name": "Andy Green", "email": "andy@warmcat.com", "md5": "c50933ca2aa61e0fe2c43d46bb6b59cb" },"url":"https://libwebsockets.org/repo/libwebsockets",
"f":3,
"items": [
{"schema":"libjg2-1",
"cid":"0544ea2f217ed3d898118efb0a715535",
"commit": {"type":"commit",
"time": 1545864331,
"time_ofs": 480,
"oid_tree": { "oid": "78f8ebdc94f1a7f2a7114cc778532a08cbfed634", "alias": []},
"oid":{ "oid": "440dacc9928eedfc6806832f114e8ecd97210362", "alias": []},
"msg": "JOSE: refactor and prepare for JWE",
"sig_commit": { "git_time": { "time": 1545864331, "offset": 480 }, "name": "Andy Green", "email": "andy@warmcat.com", "md5": "c50933ca2aa61e0fe2c43d46bb6b59cb" },
"sig_author": { "git_time": { "time": 1543278968, "offset": 480 }, "name": "Andy Green", "email": "andy@warmcat.com", "md5": "c50933ca2aa61e0fe2c43d46bb6b59cb" }},
"body": "JOSE: refactor and prepare for JWE\n\nUntil now the JOSE pieces only had enough support for ACME.\nThis patch improves the JWK parsing to prepare for more\ncomplete support and for adding JWE, genaes and genec in\nlater patches."
,
"diff": "diff --git a/CMakeLists.txt b/CMakeLists.txt\nindex e44fee8..7de8765 100644\n--- a/CMakeLists.txt\n+++ b/CMakeLists.txt\n@@ -106,8 +106,10 @@ option(LWS_WITH_NO_LOGS \u0022Disable all logging from being compiled in\u0022 OFF)\n option(LWS_AVOID_SIGPIPE_IGN \u0022Android 7+ reportedly needs this\u0022 OFF)\n option(LWS_WITH_STATS \u0022Keep statistics of lws internal operations\u0022 OFF)\n option(LWS_WITH_JWS \u0022JSON Web Signature (RFC7515) API\u0022 OFF)\n+option(LWS_WITH_JWE \u0022JSON Web Encryption (RFC7516) API\u0022 OFF)\n option(LWS_WITH_GENHASH \u0022Enable support for Generic Hash (SHA1 + SHA2 with api independent of TLS backend)\u0022 OFF)\n option(LWS_WITH_GENRSA \u0022Enable support for Generic RSA (RSA with api independent of TLS backend)\u0022 OFF)\n+option(LWS_WITH_GENEC \u0022Enable support for Generic EC (EC with api independent of TLS backend)\u0022 OFF)\n option(LWS_WITH_SELFTESTS \u0022Selftests run at context creation\u0022 OFF)\n option(LWS_WITH_GCOV \u0022Build with gcc gcov coverage instrumentation\u0022 OFF)\n option(LWS_WITH_EXPORT_LWSTARGETS \u0022Export libwebsockets CMake targets. Disable if they conflict with an outer cmake project.\u0022 ON)\n@@ -156,6 +158,9 @@ if(LWS_WITH_DISTRO_RECOMMENDED)\n \tset(LWS_WITH_LEJP_CONF 1)\n \tset(LWS_WITH_PLUGINS 1)\n \tset(LWS_ROLE_RAW_PROXY 1)\n+\tset(LWS_WITH_GENHASH 1)\n+\tset(LWS_WITH_GENRSA 1)\n+\tset(LWS_WITH_GENEC 1)\n endif()\n \n # do you care about this? Then send me a patch where it disables it on travis\n@@ -295,10 +300,15 @@ if (LWS_WITH_ACME)\n set (LWS_WITH_JWS 1)\n endif()\n \n+if (LWS_WITH_JWE)\n+ set(LWS_WITH_JWS 1)\n+endif()\n+\n if (LWS_WITH_JWS)\n set(LWS_WITH_LEJP 1)\n set(LWS_WITH_GENHASH 1)\n set(LWS_WITH_GENRSA 1)\n+ set(LWS_WITH_GENEC 1)\n endif()\n \n if (LWS_WITH_PLUGINS AND NOT LWS_WITH_LIBUV)\n@@ -1021,6 +1031,11 @@ if (LWS_WITH_SSL)\n \t\t\t\t\tlib/tls/mbedtls/lws-genrsa.c\n \t\t\t\t)\n \t\t\tendif()\n+\t\t\tif (LWS_WITH_GENEC)\n+\t\t\t\tlist(APPEND SOURCES\n+\t\t\t\t\tlib/tls/mbedtls/lws-genec.c\n+\t\t\t\t)\n+\t\t\tendif()\n \t\telse()\n \t\t\tlist(APPEND SOURCES\n \t\t\t\tlib/tls/openssl/ssl.c\n@@ -1035,6 +1050,11 @@ if (LWS_WITH_SSL)\n \t\t\t\t\tlib/tls/openssl/lws-genrsa.c\n \t\t\t\t)\n \t\t\tendif()\n+\t\t\tif (LWS_WITH_GENEC)\n+\t\t\t\tlist(APPEND SOURCES\n+\t\t\t\t\tlib/tls/openssl/lws-genec.c\n+\t\t\t\t)\n+\t\t\tendif()\n \t\tendif()\n \t\t\n \tif (NOT LWS_WITHOUT_SERVER)\n@@ -1191,8 +1211,14 @@ endif()\n \n if (LWS_WITH_JWS)\n \tlist(APPEND SOURCES\n-\t\tlib/misc/jws/jwk.c\n-\t\tlib/misc/jws/jws.c)\n+\t\tlib/jose/jwk/jwk.c\n+\t\tlib/jose/jws/jose.c\n+\t\tlib/jose/jws/jws.c)\n+endif()\n+\n+if (LWS_WITH_JWE)\n+\tlist(APPEND SOURCES\n+\t\tlib/jose/jwe/jwe.c)\n endif()\n \n # Add helper files for Windows.\ndiff --git a/READMEs/README.crypto-apis.md b/READMEs/README.crypto-apis.md\nnew file mode 100644\nindex 0000000..193c801\n--- /dev/null\n+++ b/READMEs/README.crypto-apis.md\n@@ -0,0 +1,40 @@\n+# Lws Crypto Apis\n+\n+## Overview\n+\n+\n+\n+Lws provides a \u0022generic\u0022 crypto layer on top of both OpenSSL and\n+compatible tls library, and mbedtls. Using this layer, your code\n+can work without any changes on both types of tls library crypto\n+backends... it's as simple as rebuilding lws with `-DLWS_WITH_MBEDTLS\u003d0`\n+or `\u003d1` at cmake.\n+\n+The generic layer can be used directly (as in, eg, the sshd plugin),\n+or via another layer on top, which processes JOSE JSON objects using\n+JWS (JSON Web Signatures), JWK (JSON Web Keys), and JWE (JSON Web\n+Encryption).\n+\n+## Using the generic layer\n+\n+All the necessary includes are part of `libwebsockets.h`.\n+\n+|api|cmake|header|Functionality|\n+|---|---|---|---|\n+|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|\n+|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|\n+\n+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)\n+\n+## Using the JOSE layer\n+\n+All the necessary includes are part of `libwebsockets.h`.\n+\n+|api|cmake|header|Functionality|\n+|---|---|---|---|\n+|JOSE|`LWS_WITH_JWS`|[./include/libwebsockets/jose.h](https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/lws-jose.h)|Provides signature and verifcation services for RFC7515 JOSE JSON|\n+|JWS|`LWS_WITH_JWS`|[./include/libwebsockets/jws.h](https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/lws-jws.h)|Provides signature and verifcation services for RFC7515 JWS JSON|\n+|JWK|`LWS_WITH_JWS`|[./include/libwebsockets/jwk.h](https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/lws-jwk.h)|Provides signature and verifcation services for RFC7517 JWK JSON, both \u0022keys\u0022 arrays and singletons|\n+\n+Unit tests for these apis, which serve as usage examples, can be found in [./minimal-examples/api-tests/api-test-jose](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/api-tests/api-test-jose)\n+\ndiff --git a/cmake/lws_config.h.in b/cmake/lws_config.h.in\nindex 41c06af..ee2f4f8 100644\n--- a/cmake/lws_config.h.in\n+++ b/cmake/lws_config.h.in\n@@ -75,6 +75,7 @@\n #cmakedefine LWS_WITH_HTTP_PROXY\n #cmakedefine LWS_WITH_HTTP_STREAM_COMPRESSION\n #cmakedefine LWS_WITH_IPV6\n+#cmakedefine LWS_WITH_JWE\n #cmakedefine LWS_WITH_JWS\n #cmakedefine LWS_WITH_LEJP\n #cmakedefine LWS_WITH_LIBEV\ndiff --git a/doc-assets/lws-crypto-overview.svg b/doc-assets/lws-crypto-overview.svg\nnew file mode 100644\nindex 0000000..559c8c4\n--- /dev/null\n+++ b/doc-assets/lws-crypto-overview.svg\n@@ -0,0 +1,43 @@\n+\u003c?xml version\u003d\u00221.0\u0022 encoding\u003d\u0022UTF-8\u0022?\u003e\n+\u003csvg width\u003d\u0022200.21mm\u0022 height\u003d\u0022105.23mm\u0022 version\u003d\u00221.1\u0022 viewBox\u003d\u00220 0 200.21263 105.22723\u0022 xmlns\u003d\u0022http://www.w3.org/2000/svg\u0022\u003e\n+\t\u003cdefs\u003e\n+\t\t\u003cfilter id\u003d\u0022a\u0022 x\u003d\u0022-.036673\u0022 y\u003d\u0022-.074724\u0022 width\u003d\u00221.0733\u0022 height\u003d\u00221.1494\u0022 color-interpolation-filters\u003d\u0022sRGB\u0022\u003e\n+\t\t\t\u003cfeGaussianBlur stdDeviation\u003d\u00222.8502899\u0022/\u003e\n+\t\t\u003c/filter\u003e\n+\t\u003c/defs\u003e\n+\t\u003cg transform\u003d\u0022translate(651.2 344.5)\u0022\u003e\n+\t\t\u003cg fill-opacity\u003d\u0022.99606\u0022\u003e\n+\t\t\t\u003crect x\u003d\u0022-644.35\u0022 y\u003d\u0022-337.66\u0022 width\u003d\u0022186.53\u0022 height\u003d\u002291.546\u0022 filter\u003d\u0022url(#a)\u0022/\u003e\n+\t\t\t\u003crect x\u003d\u0022-645.81\u0022 y\u003d\u0022-339.25\u0022 width\u003d\u0022186.53\u0022 height\u003d\u002291.546\u0022 fill\u003d\u0022#fff\u0022/\u003e\n+\t\t\t\u003crect x\u003d\u0022-633.9\u0022 y\u003d\u0022-327.61\u0022 width\u003d\u0022105.3\u0022 height\u003d\u002241.275\u0022 fill\u003d\u0022#f6ffd5\u0022 stroke\u003d\u0022#e9ddaf\u0022 stroke-dasharray\u003d\u00222.33000003, 2.33000003\u0022 stroke-linejoin\u003d\u0022round\u0022 stroke-width\u003d\u00221.165\u0022/\u003e\n+\t\t\u003c/g\u003e\n+\t\t\u003cg fill-opacity\u003d\u0022.99606\u0022\u003e\n+\t\t\t\u003crect x\u003d\u0022-583.53\u0022 y\u003d\u0022-312\u0022 width\u003d\u00225.4256\u0022 height\u003d\u00229.5415\u0022/\u003e\n+\t\t\t\u003crect x\u003d\u0022-554.9\u0022 y\u003d\u0022-292.8\u0022 width\u003d\u00225.4256\u0022 height\u003d\u002213.996\u0022/\u003e\n+\t\t\t\u003crect x\u003d\u0022-610.37\u0022 y\u003d\u0022-292.94\u0022 width\u003d\u00225.4256\u0022 height\u003d\u002213.996\u0022/\u003e\n+\t\t\u003c/g\u003e\n+\t\t\u003cg fill-opacity\u003d\u0022.99606\u0022\u003e\n+\t\t\t\u003crect x\u003d\u0022-632.82\u0022 y\u003d\u0022-279.84\u0022 width\u003d\u002248.643\u0022 height\u003d\u002224.322\u0022 fill\u003d\u0022#8a0\u0022/\u003e\n+\t\t\t\u003crect x\u003d\u0022-576.51\u0022 y\u003d\u0022-280.03\u0022 width\u003d\u002248.643\u0022 height\u003d\u002224.322\u0022 fill\u003d\u0022#a80\u0022/\u003e\n+\t\t\t\u003crect x\u003d\u0022-628.51\u0022 y\u003d\u0022-303.48\u0022 width\u003d\u002294.328\u0022 height\u003d\u002212.348\u0022 fill\u003d\u0022#008000\u0022/\u003e\n+\t\t\t\u003crect x\u003d\u0022-628.26\u0022 y\u003d\u0022-323.5\u0022 width\u003d\u002294.063\u0022 height\u003d\u002212.348\u0022 fill\u003d\u0022#00aad4\u0022/\u003e\n+\t\t\u003c/g\u003e\n+\t\t\u003cg fill\u003d\u0022#000000\u0022 font-family\u003d\u0022'Open Sans'\u0022 letter-spacing\u003d\u00220px\u0022 text-anchor\u003d\u0022middle\u0022 word-spacing\u003d\u00220px\u0022\u003e\n+\t\t\t\u003ctext x\u003d\u0022-608.50153\u0022 y\u003d\u0022-268.05179\u0022 dominant-baseline\u003d\u0022auto\u0022 font-size\u003d\u00227.7611px\u0022 stroke-width\u003d\u0022.26458\u0022 text-align\u003d\u0022center\u0022 style\u003d\u0022font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;line-height:1.25;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal\u0022 xml:space\u003d\u0022preserve\u0022\u003e\u003ctspan x\u003d\u0022-608.50153\u0022 y\u003d\u0022-268.05179\u0022 stroke-width\u003d\u0022.26458\u0022\u003eOpenSSL\u003c/tspan\u003e\u003c/text\u003e\n+\t\t\t\u003ctext x\u003d\u0022-552.70789\u0022 y\u003d\u0022-264.67337\u0022 dominant-baseline\u003d\u0022auto\u0022 font-size\u003d\u00227.7611px\u0022 stroke-width\u003d\u0022.26458\u0022 text-align\u003d\u0022center\u0022 style\u003d\u0022font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;line-height:1.25;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal\u0022 xml:space\u003d\u0022preserve\u0022\u003e\u003ctspan x\u003d\u0022-552.70789\u0022 y\u003d\u0022-264.67337\u0022 stroke-width\u003d\u0022.26458\u0022\u003embedTLS\u003c/tspan\u003e\u003c/text\u003e\n+\t\t\t\u003ctext x\u003d\u0022-608.09796\u0022 y\u003d\u0022-261.13004\u0022 dominant-baseline\u003d\u0022auto\u0022 font-size\u003d\u00224.8053px\u0022 stroke-width\u003d\u0022.16382\u0022 text-align\u003d\u0022center\u0022 style\u003d\u0022font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;line-height:1.25;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal\u0022 xml:space\u003d\u0022preserve\u0022\u003e\u003ctspan x\u003d\u0022-608.09796\u0022 y\u003d\u0022-261.13004\u0022 stroke-width\u003d\u0022.16382\u0022\u003eand derivitives\u003c/tspan\u003e\u003c/text\u003e\n+\t\t\u003c/g\u003e\n+\t\t\u003ctext x\u003d\u0022-580.06641\u0022 y\u003d\u0022-296.07693\u0022 dominant-baseline\u003d\u0022auto\u0022 fill\u003d\u0022#ffffff\u0022 font-family\u003d\u0022'Open Sans'\u0022 font-size\u003d\u00225.936px\u0022 letter-spacing\u003d\u00220px\u0022 stroke-width\u003d\u0022.20236\u0022 text-align\u003d\u0022center\u0022 text-anchor\u003d\u0022middle\u0022 word-spacing\u003d\u00220px\u0022 style\u003d\u0022font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;line-height:1.25;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal\u0022 xml:space\u003d\u0022preserve\u0022\u003e\u003ctspan x\u003d\u0022-580.06641\u0022 y\u003d\u0022-296.07693\u0022 fill\u003d\u0022#ffffff\u0022 stroke-width\u003d\u0022.20236\u0022\u003egenhash, genrsa, genaes, genec\u003c/tspan\u003e\u003c/text\u003e\n+\t\t\u003ctext x\u003d\u0022-581.93494\u0022 y\u003d\u0022-314.70865\u0022 dominant-baseline\u003d\u0022auto\u0022 fill\u003d\u0022#ffffff\u0022 font-family\u003d\u0022'Open Sans'\u0022 font-size\u003d\u00227.7611px\u0022 letter-spacing\u003d\u00220px\u0022 stroke-width\u003d\u0022.26458\u0022 text-align\u003d\u0022center\u0022 text-anchor\u003d\u0022middle\u0022 word-spacing\u003d\u00220px\u0022 style\u003d\u0022font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;line-height:1.25;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal\u0022 xml:space\u003d\u0022preserve\u0022\u003e\u003ctspan x\u003d\u0022-581.93494\u0022 y\u003d\u0022-314.70865\u0022 fill\u003d\u0022#ffffff\u0022 stroke-width\u003d\u0022.26458\u0022\u003eJOSE, JWS, JWK, JWE\u003c/tspan\u003e\u003c/text\u003e\n+\t\t\u003cg fill\u003d\u0022#000000\u0022 font-family\u003d\u0022'Open Sans'\u0022 font-size\u003d\u00224.3141px\u0022 letter-spacing\u003d\u00220px\u0022 stroke-width\u003d\u0022.14707\u0022 text-anchor\u003d\u0022middle\u0022 word-spacing\u003d\u00220px\u0022\u003e\n+\t\t\t\u003ctext x\u003d\u0022-493.83551\u0022 y\u003d\u0022-274.2438\u0022 dominant-baseline\u003d\u0022auto\u0022 text-align\u003d\u0022center\u0022 style\u003d\u0022font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;line-height:1.25;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal\u0022 xml:space\u003d\u0022preserve\u0022\u003e\u003ctspan x\u003d\u0022-493.83551\u0022 y\u003d\u0022-274.2438\u0022\u003eTLS-library-specific\u003c/tspan\u003e\u003ctspan x\u003d\u0022-493.83551\u0022 y\u003d\u0022-268.8512\u0022\u003eand cipher-specific\u003c/tspan\u003e\u003ctspan x\u003d\u0022-493.83551\u0022 y\u003d\u0022-263.45856\u0022\u003ekeys using EVP\u003c/tspan\u003e\u003ctspan x\u003d\u0022-493.83551\u0022 y\u003d\u0022-258.06595\u0022\u003eor bignum\u003c/tspan\u003e\u003c/text\u003e\n+\t\t\t\u003ctext x\u003d\u0022-493.41776\u0022 y\u003d\u0022-301.00821\u0022 dominant-baseline\u003d\u0022auto\u0022 text-align\u003d\u0022center\u0022 style\u003d\u0022font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;line-height:1.25;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal\u0022 xml:space\u003d\u0022preserve\u0022\u003e\u003ctspan x\u003d\u0022-493.41776\u0022 y\u003d\u0022-301.00821\u0022\u003eTLS library-independent\u003c/tspan\u003e\u003ctspan x\u003d\u0022-493.41776\u0022 y\u003d\u0022-295.6156\u0022\u003emetadata +\u003c/tspan\u003e\u003ctspan x\u003d\u0022-493.41776\u0022 y\u003d\u0022-290.22296\u0022\u003ebinary key elements\u003c/tspan\u003e\u003c/text\u003e\n+\t\t\t\u003ctext x\u003d\u0022-493.22754\u0022 y\u003d\u0022-319.46451\u0022 dominant-baseline\u003d\u0022auto\u0022 text-align\u003d\u0022center\u0022 style\u003d\u0022font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;line-height:1.25;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal\u0022 xml:space\u003d\u0022preserve\u0022\u003e\u003ctspan x\u003d\u0022-493.22754\u0022 y\u003d\u0022-319.46451\u0022\u003eJWK JSON key\u003c/tspan\u003e\u003ctspan x\u003d\u0022-493.22754\u0022 y\u003d\u0022-314.0719\u0022\u003ecreation and parsing\u003c/tspan\u003e\u003c/text\u003e\n+\t\t\u003c/g\u003e\n+\t\t\u003cg\u003e\n+\t\t\t\u003cpath d\u003d\u0022m-492.48-306.99-1.2324 1.0579-1.247-0.9926 0.57189-0.052 0.0645-4.34h-0.66758l1.374-1.2497 1.2493 1.3264-0.66727 0.053 0.0298 4.1963z\u0022 fill\u003d\u0022#0b2822\u0022/\u003e\n+\t\t\t\u003cpath d\u003d\u0022m-492.34-280.9-1.2324 1.0579-1.247-0.9926 0.57189-0.052 0.0645-4.34h-0.66758l1.374-1.2497 1.2493 1.3264-0.66727 0.053 0.0298 4.1963z\u0022 fill\u003d\u0022#0b2822\u0022/\u003e\n+\t\t\t\u003ctext x\u003d\u0022-618.2807\u0022 y\u003d\u0022-330.22464\u0022 dominant-baseline\u003d\u0022auto\u0022 fill\u003d\u0022#000000\u0022 font-family\u003d\u0022'Open Sans'\u0022 font-size\u003d\u00225.0105px\u0022 letter-spacing\u003d\u00220px\u0022 stroke-width\u003d\u0022.17081\u0022 text-align\u003d\u0022center\u0022 text-anchor\u003d\u0022middle\u0022 word-spacing\u003d\u00220px\u0022 style\u003d\u0022font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;line-height:1.25;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal\u0022 xml:space\u003d\u0022preserve\u0022\u003e\u003ctspan x\u003d\u0022-618.2807\u0022 y\u003d\u0022-330.22464\u0022 stroke-width\u003d\u0022.17081\u0022\u003elibwebsockets\u003c/tspan\u003e\u003c/text\u003e\n+\t\t\u003c/g\u003e\n+\t\u003c/g\u003e\n+\u003c/svg\u003e\ndiff --git a/include/libwebsockets.h b/include/libwebsockets.h\nindex 7cc5c28..831904f 100644\n--- a/include/libwebsockets.h\n+++ b/include/libwebsockets.h\n@@ -422,9 +422,11 @@ struct lws;\n #endif\n \n #include \u003clibwebsockets/lws-genhash.h\u003e\n-#include \u003clibwebsockets/lws-genrsa.h\u003e\n #include \u003clibwebsockets/lws-jwk.h\u003e\n+#include \u003clibwebsockets/lws-jose.h\u003e\n #include \u003clibwebsockets/lws-jws.h\u003e\n+#include \u003clibwebsockets/lws-genrsa.h\u003e\n+#include \u003clibwebsockets/lws-genec.h\u003e\n \n #endif\n \ndiff --git a/include/libwebsockets/lws-genec.h b/include/libwebsockets/lws-genec.h\nnew file mode 100644\nindex 0000000..38bd9c8\n--- /dev/null\n+++ b/include/libwebsockets/lws-genec.h\n@@ -0,0 +1,34 @@\n+/*\n+ * libwebsockets - Generic Elliptic Curve Encryption\n+ *\n+ * Copyright (C) 2010-2018 Andy Green \u003candy@warmcat.com\u003e\n+ *\n+ * This library is free software; you can redistribute it and/or\n+ * modify it under the terms of the GNU Lesser General Public\n+ * License as published by the Free Software Foundation:\n+ * version 2.1 of the License.\n+ *\n+ * This library is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ * Lesser General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU Lesser General Public\n+ * License along with this library; if not, write to the Free Software\n+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n+ * MA 02110-1301 USA\n+ *\n+ * included from libwebsockets.h\n+ */\n+\n+/* include/libwebsockets/lws-jwk.h must be included before this */\n+\n+struct lws_genec_ctx {\n+#if defined(LWS_WITH_MBEDTLS)\n+\tmbedtls_rsa_context *ctx;\n+#else\n+\tBIGNUM *bn[LWS_COUNT_EC_KEY_ELEMENTS];\n+\tRSA *rsa;\n+#endif\n+};\n+\ndiff --git a/include/libwebsockets/lws-genrsa.h b/include/libwebsockets/lws-genrsa.h\nindex 3e427e2..f9a204b 100644\n--- a/include/libwebsockets/lws-genrsa.h\n+++ b/include/libwebsockets/lws-genrsa.h\n@@ -32,44 +32,23 @@\n */\n ///@{\n \n-enum enum_jwk_tok {\n-\tJWK_KEY_E,\n-\tJWK_KEY_N,\n-\tJWK_KEY_D,\n-\tJWK_KEY_P,\n-\tJWK_KEY_Q,\n-\tJWK_KEY_DP,\n-\tJWK_KEY_DQ,\n-\tJWK_KEY_QI,\n-\tJWK_KTY, /* also serves as count of real elements */\n-\tJWK_KEY,\n-};\n-\n-#define LWS_COUNT_RSA_ELEMENTS JWK_KTY\n+/* include/libwebsockets/lws-jwk.h must be included before this */\n \n struct lws_genrsa_ctx {\n #if defined(LWS_WITH_MBEDTLS)\n \tmbedtls_rsa_context *ctx;\n #else\n-\tBIGNUM *bn[LWS_COUNT_RSA_ELEMENTS];\n+\tBIGNUM *bn[LWS_COUNT_RSA_KEY_ELEMENTS];\n \tRSA *rsa;\n #endif\n-};\n-\n-struct lws_genrsa_element {\n-\tuint8_t *buf;\n-\tuint16_t len;\n-};\n-\n-struct lws_genrsa_elements {\n-\tstruct lws_genrsa_element e[LWS_COUNT_RSA_ELEMENTS];\n+\tstruct lws_context *context;\n };\n \n /** lws_jwk_destroy_genrsa_elements() - Free allocations in genrsa_elements\n *\n- * \u005cparam el: your struct lws_genrsa_elements\n+ * \u005cparam el: your struct lws_jwk_elements\n *\n- * This is a helper for user code making use of struct lws_genrsa_elements\n+ * This is a helper for user code making use of struct lws_jwk_elements\n * where the elements are allocated on the heap, it frees any non-NULL\n * buf element and sets the buf to NULL.\n *\n@@ -77,7 +56,7 @@ struct lws_genrsa_elements {\n * creation and destruction themselves.\n */\n LWS_VISIBLE LWS_EXTERN void\n-lws_jwk_destroy_genrsa_elements(struct lws_genrsa_elements *el);\n+lws_jwk_destroy_genrsa_elements(struct lws_jwk_elements *el);\n \n /** lws_genrsa_public_decrypt_create() - Create RSA public decrypt context\n *\n@@ -92,7 +71,8 @@ lws_jwk_destroy_genrsa_elements(struct lws_genrsa_elements *el);\n * This and related APIs operate identically with OpenSSL or mbedTLS backends.\n */\n LWS_VISIBLE LWS_EXTERN int\n-lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_genrsa_elements *el);\n+lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_jwk_elements *el,\n+\t\t struct lws_context *context);\n \n /** lws_genrsa_new_keypair() - Create new RSA keypair\n *\n@@ -110,7 +90,24 @@ lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_genrsa_elements *el);\n */\n LWS_VISIBLE LWS_EXTERN int\n lws_genrsa_new_keypair(struct lws_context *context, struct lws_genrsa_ctx *ctx,\n-\t\t struct lws_genrsa_elements *el, int bits);\n+\t\t struct lws_jwk_elements *el, int bits);\n+\n+/** lws_genrsa_public_encrypt() - Perform RSA public encryption\n+ *\n+ * \u005cparam ctx: your struct lws_genrsa_ctx\n+ * \u005cparam in: plaintext input\n+ * \u005cparam in_len: length of plaintext input\n+ * \u005cparam out: encrypted output\n+ *\n+ * Performs PKCS1 v1.5 Encryption\n+ *\n+ * Returns \u003c0 for error, or length of decrypted data.\n+ *\n+ * This and related APIs operate identically with OpenSSL or mbedTLS backends.\n+ */\n+LWS_VISIBLE LWS_EXTERN int\n+lws_genrsa_public_encrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in,\n+\t\t\t size_t in_len, uint8_t *out);\n \n /** lws_genrsa_public_decrypt() - Perform RSA public decryption\n *\n@@ -120,7 +117,7 @@ lws_genrsa_new_keypair(struct lws_context *context, struct lws_genrsa_ctx *ctx,\n * \u005cparam out: decrypted output\n * \u005cparam out_max: size of output buffer\n *\n- * Performs the decryption.\n+ * Performs PKCS1 v1.5 Decryption\n *\n * Returns \u003c0 for error, or length of decrypted data.\n *\ndiff --git a/include/libwebsockets/lws-jose.h b/include/libwebsockets/lws-jose.h\nnew file mode 100644\nindex 0000000..a46af79\n--- /dev/null\n+++ b/include/libwebsockets/lws-jose.h\n@@ -0,0 +1,71 @@\n+/*\n+ * libwebsockets - small server side websockets and web server implementation\n+ *\n+ * Copyright (C) 2010-2018 Andy Green \u003candy@warmcat.com\u003e\n+ *\n+ * This library is free software; you can redistribute it and/or\n+ * modify it under the terms of the GNU Lesser General Public\n+ * License as published by the Free Software Foundation:\n+ * version 2.1 of the License.\n+ *\n+ * This library is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ * Lesser General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU Lesser General Public\n+ * License along with this library; if not, write to the Free Software\n+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n+ * MA 02110-1301 USA\n+ *\n+ * included from libwebsockets.h\n+ */\n+\n+enum lws_jws_jose_hdr_indexes {\n+\tLJJHI_ALG,\t/* REQUIRED */\n+\tLJJHI_JKU,\t/* Optional: string */\n+\tLJJHI_JWK,\t/* Optional: jwk JSON object: public key: */\n+\tLJJHI_KID,\t/* Optional: string */\n+\tLJJHI_X5U,\t/* Optional: string: url of public key cert / chain */\n+\tLJJHI_X5C,\t/* Optional: base64 (NOT -url): actual cert */\n+\tLJJHI_X5T,\t/* Optional: base64url: SHA-1 of actual cert */\n+\tLJJHI_X5T_S256, /* Optional: base64url: SHA-256 of actual cert */\n+\tLJJHI_TYP,\t/* Optional: string: media type */\n+\tLJJHI_CTY,\t/* Optional: string: content media type */\n+\tLJJHI_CRIT,\t/* Optional for send, REQUIRED: array of strings:\n+\t\t\t * mustn't contain standardized strings or null set */\n+\n+\tLJJHI_ENC,\t/* JWE only: Optional: string */\n+\tLJJHI_ZIP,\t/* JWE only: Optional: string (\u0022DEF\u0022 \u003d deflate) */\n+\n+\tLJJHI_EPK,\t/* Additional arg for JWE ECDH: ephemeral public key */\n+\tLJJHI_APU,\t/* Additional arg for JWE ECDH: base64url */\n+\tLJJHI_APV,\t/* Additional arg for JWE ECDH: base64url */\n+\tLJJHI_IV,\t/* Additional arg for JWE AES: base64url */\n+\tLJJHI_TAG,\t/* Additional arg for JWE AES: base64url */\n+\tLJJHI_P2S,\t/* Additional arg for JWE PBES2: base64url: salt */\n+\tLJJHI_P2C,\t/* Additional arg for JWE PBES2: integer: count */\n+\n+\tLWS_COUNT_JOSE_HDR_ELEMENTS\n+};\n+\n+struct lws_jose {\n+\t/* jose header elements */\n+\tstruct lws_jwk_elements e[LWS_COUNT_JOSE_HDR_ELEMENTS];\n+};\n+\n+enum lws_jws_algtype {\n+\tLWS_JWK_ENCTYPE_NONE,\n+\tLWS_JWK_ENCTYPE_RSASSA,\n+\tLWS_JWK_ENCTYPE_EC\n+};\n+\n+struct cb_hdr_s {\n+\tenum lws_genhash_types hash_type;\n+\tenum lws_genhmac_types hmac_type;\n+\tchar alg[24]; /* for jwe, the JWA enc alg name, eg \u0022ECDH-ES\u0022 */\n+\tchar curve[16];\n+\tenum lws_jws_algtype algtype; /* for jws, the signing cipher */\n+\n+\tchar is_jwe;\n+};\ndiff --git a/include/libwebsockets/lws-jwe.h b/include/libwebsockets/lws-jwe.h\nnew file mode 100644\nindex 0000000..d5227c9\n--- /dev/null\n+++ b/include/libwebsockets/lws-jwe.h\n@@ -0,0 +1,22 @@\n+/*\n+ * libwebsockets - JSON Web Encryption\n+ *\n+ * Copyright (C) 2010-2018 Andy Green \u003candy@warmcat.com\u003e\n+ *\n+ * This library is free software; you can redistribute it and/or\n+ * modify it under the terms of the GNU Lesser General Public\n+ * License as published by the Free Software Foundation:\n+ * version 2.1 of the License.\n+ *\n+ * This library is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ * Lesser General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU Lesser General Public\n+ * License along with this library; if not, write to the Free Software\n+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n+ * MA 02110-1301 USA\n+ *\n+ * included from libwebsockets.h\n+ */\ndiff --git a/include/libwebsockets/lws-jwk.h b/include/libwebsockets/lws-jwk.h\nindex 2e2eabd..d4c8468 100644\n--- a/include/libwebsockets/lws-jwk.h\n+++ b/include/libwebsockets/lws-jwk.h\n@@ -25,35 +25,113 @@\n /*! \u005cdefgroup jwk JSON Web Keys\n * ## JSON Web Keys API\n *\n- * Lws provides an API to parse JSON Web Keys into a struct lws_genrsa_elements.\n+ * Lws provides an API to parse JSON Web Keys into a struct lws_jwk_elements.\n *\n * \u0022oct\u0022 and \u0022RSA\u0022 type keys are supported. For \u0022oct\u0022 keys, they are held in\n- * the \u0022e\u0022 member of the struct lws_genrsa_elements.\n+ * the \u0022e\u0022 member of the struct lws_jwk_elements.\n *\n * Keys elements are allocated on the heap. You must destroy the allocations\n- * in the struct lws_genrsa_elements by calling\n+ * in the struct lws_jwk_elements by calling\n * lws_jwk_destroy_genrsa_elements() when you are finished with it.\n */\n ///@{\n \n+enum lws_jwk_kyt {\n+\tLWS_JWK_KYT_UNKNOWN,\n+\tLWS_JWK_KYT_OCT,\n+\tLWS_JWK_KYT_RSA,\n+\tLWS_JWK_KYT_EC\n+};\n+\n+/*\n+ * Keytypes where the same element name is reused must all agree to put the\n+ * same-named element at the same e[] index. It's because we may not know the\n+ * keytype until the end.\n+ */\n+\n+enum enum_jwk_oct_tok {\n+\tJWK_OCT_KEYEL_K,\n+\n+\tLWS_COUNT_OCT_KEY_ELEMENTS\n+};\n+\n+enum enum_jwk_rsa_tok {\n+\tJWK_RSA_KEYEL_E,\n+\tJWK_RSA_KEYEL_N,\n+\tJWK_RSA_KEYEL_D, /* note... same offset as EC D */\n+\tJWK_RSA_KEYEL_P,\n+\tJWK_RSA_KEYEL_Q,\n+\tJWK_RSA_KEYEL_DP,\n+\tJWK_RSA_KEYEL_DQ,\n+\tJWK_RSA_KEYEL_QI,\n+\n+\tLWS_COUNT_RSA_KEY_ELEMENTS\n+};\n+\n+enum enum_jwk_ec_tok {\n+\tJWK_EC_KEYEL_CRV,\n+\tJWK_EC_KEYEL_X,\n+\tJWK_EC_KEYEL_D, /* note... same offset as RSA D */\n+\tJWK_EC_KEYEL_Y,\n+\n+\tLWS_COUNT_EC_KEY_ELEMENTS\n+};\n+\n+enum enum_jwk_meta_tok {\n+\tJWK_META_KTY,\n+\tJWK_META_KID,\n+\tJWK_META_USE,\n+\tJWK_META_KEY_OPS,\n+\tJWK_META_X5C,\n+\tJWK_META_ALG,\n+\n+\tLWS_COUNT_JWK_ELEMENTS\n+};\n+\n+/* largest number of key elements for any algorithm */\n+#define LWS_COUNT_ALG_KEY_ELEMENTS_MAX LWS_COUNT_RSA_KEY_ELEMENTS\n+\n+struct lws_jwk_elements {\n+\tuint8_t *buf;\n+\tuint16_t len;\n+};\n+\n struct lws_jwk {\n-\tchar keytype[5];\t\t/**\u003c \u0022oct\u0022 or \u0022RSA\u0022 */\n-\tstruct lws_genrsa_elements el;\t/**\u003c OCTet key is in el.e */\n+\t/* key data elements */\n+\tstruct lws_jwk_elements e[LWS_COUNT_ALG_KEY_ELEMENTS_MAX];\n+\t/* generic meta key elements, like KID */\n+\tstruct lws_jwk_elements meta[LWS_COUNT_JWK_ELEMENTS];\n+\tint kty;\t\t\t/**\u003c one of LWS_JWK_ */\n };\n \n+typedef int (*lws_jwk_key_import_callback)(struct lws_jwk *s, void *user);\n+\n /** lws_jwk_import() - Create a JSON Web key from the textual representation\n *\n * \u005cparam s: the JWK object to create\n+ * \u005cparam cb: callback for each jwk-processed key, or NULL if importing a single\n+ *\t key with no parent \u0022keys\u0022 JSON\n+ * \u005cparam user: pointer to be passed to the callback, otherwise ignored by lws.\n+ *\t\tNULL if importing a single key with no parent \u0022keys\u0022 JSON\n * \u005cparam in: a single JWK JSON stanza in utf-8\n * \u005cparam len: the length of the JWK JSON stanza in bytes\n *\n * Creates an lws_jwk struct filled with data from the JSON representation.\n- * \u0022oct\u0022 and \u0022rsa\u0022 key types are supported.\n *\n- * For \u0022oct\u0022 type keys, it is loaded into el.e.\n+ * There are two ways to use this... with some protocols a single jwk is\n+ * delivered with no parent \u0022keys\u0022: [] array. If you call this with cb and\n+ * user as NULL, then the input will be interpreted like that and the results\n+ * placed in s.\n+ *\n+ * The second case is that you are dealing with a \u0022keys\u0022:[] array with one or\n+ * more keys in it. In this case, the function iterates through the keys using\n+ * s as a temporary jwk, and calls the user-provided callback for each key in\n+ * turn while it return 0 (nonzero return from the callback terminates the\n+ * iteration through any further keys).\n */\n LWS_VISIBLE LWS_EXTERN int\n-lws_jwk_import(struct lws_jwk *s, const char *in, size_t len);\n+lws_jwk_import(struct lws_jwk *s, lws_jwk_key_import_callback cb, void *user,\n+\t const char *in, size_t len);\n \n /** lws_jwk_destroy() - Destroy a JSON Web key\n *\n@@ -84,9 +162,21 @@ lws_jwk_export(struct lws_jwk *s, int _private, char *p, size_t len);\n * \u005cparam filename: filename to load from\n *\n * Returns 0 for OK or -1 for failure\n+ *\n+ * There are two ways to use this... with some protocols a single jwk is\n+ * delivered with no parent \u0022keys\u0022: [] array. If you call this with cb and\n+ * user as NULL, then the input will be interpreted like that and the results\n+ * placed in s.\n+ *\n+ * The second case is that you are dealing with a \u0022keys\u0022:[] array with one or\n+ * more keys in it. In this case, the function iterates through the keys using\n+ * s as a temporary jwk, and calls the user-provided callback for each key in\n+ * turn while it return 0 (nonzero return from the callback terminates the\n+ * iteration through any further keys, leaving the last one in s).\n */\n LWS_VISIBLE int\n-lws_jwk_load(struct lws_jwk *s, const char *filename);\n+lws_jwk_load(struct lws_jwk *s, const char *filename,\n+\t lws_jwk_key_import_callback cb, void *user);\n \n /** lws_jwk_save() - Export a JSON Web key to a file\n *\ndiff --git a/include/libwebsockets/lws-jws.h b/include/libwebsockets/lws-jws.h\nindex 7112fc3..3485146 100644\n--- a/include/libwebsockets/lws-jws.h\n+++ b/include/libwebsockets/lws-jws.h\n@@ -34,7 +34,8 @@\n ///@{\n \n LWS_VISIBLE LWS_EXTERN int\n-lws_jws_confirm_sig(const char *in, size_t len, struct lws_jwk *jwk);\n+lws_jws_confirm_sig(const char *in, size_t len, struct lws_jwk *jwk,\n+\t\t struct lws_context *context);\n \n /**\n * lws_jws_sign_from_b64() - add b64 sig to b64 hdr + payload\n@@ -47,6 +48,7 @@ lws_jws_confirm_sig(const char *in, size_t len, struct lws_jwk *jwk);\n * \u005cparam sig_len: max bytes we can write at b64_sig\n * \u005cparam hash_type: one of LWS_GENHASH_TYPE_SHA[256|384|512]\n * \u005cparam jwk: the struct lws_jwk containing the signing key\n+ * \u005cparam context: the lws context (used to get random)\n *\n * This adds a b64-coded JWS signature of the b64-encoded protected header\n * and b64-encoded payload, at \u005cp b64_sig. The signature will be as large\n@@ -62,7 +64,8 @@ lws_jws_confirm_sig(const char *in, size_t len, struct lws_jwk *jwk);\n LWS_VISIBLE LWS_EXTERN int\n lws_jws_sign_from_b64(const char *b64_hdr, size_t hdr_len, const char *b64_pay,\n \t\t size_t pay_len, char *b64_sig, size_t sig_len,\n-\t\t enum lws_genhash_types hash_type, struct lws_jwk *jwk);\n+\t\t enum lws_genhash_types hash_type, struct lws_jwk *jwk,\n+\t\t struct lws_context *context);\n \n /**\n * lws_jws_create_packet() - add b64 sig to b64 hdr + payload\n@@ -73,6 +76,7 @@ lws_jws_sign_from_b64(const char *b64_hdr, size_t hdr_len, const char *b64_pay,\n * \u005cparam nonce: Nonse string to include in protected header\n * \u005cparam out: buffer to take signed packet\n * \u005cparam out_len: size of \u005cp out buffer\n+ * \u005cparam conext: lws_context to get random from\n *\n * This creates a \u0022flattened\u0022 JWS packet from the jwk and the plaintext\n * payload, and signs it. The packet is written into \u005cp out.\n@@ -84,7 +88,8 @@ lws_jws_sign_from_b64(const char *b64_hdr, size_t hdr_len, const char *b64_pay,\n */\n LWS_VISIBLE LWS_EXTERN int\n lws_jws_create_packet(struct lws_jwk *jwk, const char *payload, size_t len,\n-\t\t const char *nonce, char *out, size_t out_len);\n+\t\t const char *nonce, char *out, size_t out_len,\n+\t\t struct lws_context *context);\n \n /**\n * lws_jws_base64_enc() - encode input data into b64url data\n@@ -98,4 +103,21 @@ lws_jws_create_packet(struct lws_jwk *jwk, const char *payload, size_t len,\n */\n LWS_VISIBLE LWS_EXTERN int\n lws_jws_base64_enc(const char *in, size_t in_len, char *out, size_t out_max);\n+\n+/**\n+ * lws_jws_encode_section() - encode input data into b64url data, prepending . if not first\n+ *\n+ * \u005cparam in: the incoming plaintext\n+ * \u005cparam in_len: the length of the incoming plaintext in bytes\n+ * \u005cparam first: nonzero if the first section\n+ * \u005cparam out: the buffer to store the b64url encoded data to\n+ * \u005cparam out_max: the length of \u005cp out in bytes\n+ *\n+ * Returns either -1 if problems, or the number of bytes written to \u005cp out.\n+ * If the section is not the first one, '.' is prepended.\n+ */\n+\n+LWS_VISIBLE LWS_EXTERN int\n+lws_jws_encode_section(const char *in, size_t in_len, int first, char **p,\n+\t\t char *end);\n ///@}\ndiff --git a/lib/README.md b/lib/README.md\nindex d6475b8..2c0c900 100644\n--- a/lib/README.md\n+++ b/lib/README.md\n@@ -6,6 +6,7 @@ Path|Sources\n ---|---\n lib/core|Core lws code related to generic fd and wsi servicing and management\n lib/event-libs|Code containing optional event-lib specific adaptations\n+lib/jose|JOSE / JWS / JWK / JWE implementations\n lib/misc|Code for various mostly optional miscellaneous features\n lib/plat|Platform-specific adaptation code\n lib/roles|Code for specific optional wsi roles, eg, http/1, h2, ws, raw, etc\ndiff --git a/lib/core/context.c b/lib/core/context.c\nindex 9749447..e36e942 100644\n--- a/lib/core/context.c\n+++ b/lib/core/context.c\n@@ -1273,10 +1273,6 @@ lws_create_context(const struct lws_context_creation_info *info)\n \t/* expedite post-context init (eg, protocols) */\n \tlws_cancel_service(context);\n \n-#if defined(LWS_WITH_SELFTESTS)\n-\tlws_jws_selftest();\n-#endif\n-\n \treturn context;\n \n bail:\ndiff --git a/lib/core/private.h b/lib/core/private.h\nindex 9a8dc86..43aa14a 100644\n--- a/lib/core/private.h\n+++ b/lib/core/private.h\n@@ -1337,7 +1337,7 @@ int\n lws_tls_check_cert_lifetime(struct lws_vhost *vhost);\n \n int lws_jws_selftest(void);\n-\n+int lws_jwe_selftest(void);\n \n #ifndef LWS_NO_CLIENT\n LWS_EXTERN int lws_client_socket_service(struct lws *wsi,\ndiff --git a/lib/jose/README.md b/lib/jose/README.md\nnew file mode 100644\nindex 0000000..cf7284f\n--- /dev/null\n+++ b/lib/jose/README.md\n@@ -0,0 +1,51 @@\n+# JOSE support\n+\n+JOSE is a set of web standards aimed at encapsulating crypto\n+operations flexibly inside JSON objects.\n+\n+Lws provides lightweight apis to performs operations on JWK, JWS and JWE\n+independent of the tls backend in use. The JSON parsing is handled by the lws\n+lejp stream parser.\n+\n+|Part|RFC|Function|\n+|---|---|---|\n+|JWS|[RFC7515](https://tools.ietf.org/html/rfc7515)|JSON Web Signatures|\n+|JWE|[RFC7516](https://tools.ietf.org/html/rfc7516)|JSON Web Encryption|\n+|JWK|[RFC7517](https://tools.ietf.org/html/rfc7517)|JSON Web Keys|\n+|JWA|[RFC7518](https://tools.ietf.org/html/rfc7518)|JSON Web Algorithms|\n+\n+JWA is a set of recommendations for which combinations of algorithms\n+are deemed desirable and secure, which implies what must be done for\n+useful implementations of JWS, JWE and JWK.\n+\n+## Supported algorithms\n+\n+Symmetric ciphers are not currently supported... symmetric keys and HMAC\n+are supported though.\n+\n+For the required and recommended asymmetric algorithms, support currently\n+looks like this\n+\n+|JWK kty|JWA|lws|\n+|---|---|---|\n+|EC|Recommended+|no|\n+|RSA|Required|yes|\n+|oct|Required|yes|\n+\n+|JWE alg|JWA|lws|\n+|---|---|---|\n+|RSA1_5|Recommended-|yes (no JWE yet but lws_genrsa supports)|\n+|RSA-OAEP|Recommended+|no|\n+|ECDH-ES|Recommended+|no|\n+\n+|JWS alg|JWA|lws|\n+|---|---|---|\n+|HS256|Required|yes|\n+|RS256|Recommended+|yes|\n+|ES256|Recommended|no|\n+\n+## API tests\n+\n+See `./minimal-examples/api-tests/api-test-jose/` for example test code.\n+The tests are built and confirmed during CI.\n+\ndiff --git a/lib/jose/jwe/jwe.c b/lib/jose/jwe/jwe.c\nnew file mode 100644\nindex 0000000..cc7c9c8\n--- /dev/null\n+++ b/lib/jose/jwe/jwe.c\n@@ -0,0 +1,27 @@\n+/*\n+ * libwebsockets - JSON Web Encryption support\n+ *\n+ * Copyright (C) 2018 Andy Green \u003candy@warmcat.com\u003e\n+ *\n+ * This library is free software; you can redistribute it and/or\n+ * modify it under the terms of the GNU Lesser General Public\n+ * License as published by the Free Software Foundation:\n+ * version 2.1 of the License.\n+ *\n+ * This library is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ * Lesser General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU Lesser General Public\n+ * License along with this library; if not, write to the Free Software\n+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n+ * MA 02110-1301 USA\n+ *\n+ *\n+ * This supports RFC7516 JSON Web Encryption\n+ *\n+ *\n+ */\n+#include \u0022core/private.h\u0022\n+\ndiff --git a/lib/jose/jwk/jwk.c b/lib/jose/jwk/jwk.c\nnew file mode 100644\nindex 0000000..a216697\n--- /dev/null\n+++ b/lib/jose/jwk/jwk.c\n@@ -0,0 +1,497 @@\n+/*\n+ * libwebsockets - JSON Web Key support\n+ *\n+ * Copyright (C) 2017 - 2018 Andy Green \u003candy@warmcat.com\u003e\n+ *\n+ * This library is free software; you can redistribute it and/or\n+ * modify it under the terms of the GNU Lesser General Public\n+ * License as published by the Free Software Foundation:\n+ * version 2.1 of the License.\n+ *\n+ * This library is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ * Lesser General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU Lesser General Public\n+ * License along with this library; if not, write to the Free Software\n+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n+ * MA 02110-1301 USA\n+ */\n+\n+#include \u0022core/private.h\u0022\n+\n+#include \u003cfcntl.h\u003e\n+#include \u003cunistd.h\u003e\n+\n+static const char * const kyt_names[] \u003d {\n+\t\u0022unknown\u0022,\t/* LWS_JWK_KYT_UNKNOWN */\n+\t\u0022oct\u0022,\t\t/* LWS_JWK_KYT_OCT */\n+\t\u0022RSA\u0022,\t\t/* LWS_JWK_KYT_RSA */\n+\t\u0022EC\u0022\t\t/* LWS_JWK_KYT_EC */\n+};\n+\n+/*\n+ * These are the entire legal token set for names in jwk.\n+ *\n+ * The first version is used to parse a detached single jwk that don't have any\n+ * parent JSON context. The second version is used to parse full jwk objects\n+ * that has a \u0022keys\u0022: [ ] array containing the keys.\n+ */\n+\n+static const char * const jwk_tok[] \u003d {\n+\t\u0022keys[]\u0022,\t\t\t/* dummy */\n+\t\u0022e\u0022, \u0022n\u0022, \u0022d\u0022, \u0022p\u0022, \u0022q\u0022, \u0022dp\u0022, \u0022dq\u0022, \u0022qi\u0022, /* RSA */\n+\t\u0022kty\u0022,\t\t\t\t/* generic */\n+\t\u0022k\u0022,\t\t\t\t/* symmetric oct key data */\n+\t\u0022crv\u0022, \u0022x\u0022, \u0022y\u0022,\t\t/* EC (also \u0022D\u0022) */\n+\t\u0022kid\u0022,\t\t\t\t/* generic */\n+\t\u0022use\u0022\t\t\t\t/* mutually exclusive with \u0022key_ops\u0022 */,\n+\t\u0022key_ops\u0022\t\t\t/* mutually exclusive with \u0022use\u0022 */,\n+\t\u0022x5c\u0022,\t\t\t\t/* generic */\n+\t\u0022alg\u0022\t\t\t\t/* generic */\n+}, * const jwk_outer_tok[] \u003d {\n+\t\u0022keys[]\u0022,\n+\t\u0022keys[].e\u0022, \u0022keys[].n\u0022, \u0022keys[].d\u0022, \u0022keys[].p\u0022, \u0022keys[].q\u0022, \u0022keys[].dp\u0022,\n+\t\u0022keys[].dq\u0022, \u0022keys[].qi\u0022,\n+\n+\t\u0022keys[].kty\u0022, \u0022keys[].k\u0022,\t\t/* generic */\n+\t\u0022keys[].crv\u0022, \u0022keys[].x\u0022, \u0022keys[].y\u0022,\t/* EC (also \u0022D\u0022) */\n+\t\u0022keys[].kid\u0022, \u0022keys[].use\u0022\t/* mutually exclusive with \u0022key_ops\u0022 */,\n+\t\u0022keys[].key_ops\u0022,\t\t/* mutually exclusive with \u0022use\u0022 */\n+\t\u0022keys[].x5c\u0022, \u0022keys[].alg\u0022\n+};\n+\n+/* information about each token declared above */\n+\n+#define FLAG_META\t(1 \u003c\u003c 12)\n+#define FLAG_RSA\t(1 \u003c\u003c 13)\n+#define FLAG_EC\t\t(1 \u003c\u003c 14)\n+#define FLAG_OCT\t(1 \u003c\u003c 15)\n+\n+unsigned short tok_map[] \u003d {\n+\tFLAG_RSA | FLAG_EC | FLAG_OCT | FLAG_META | 0, /* padding */\n+\tFLAG_RSA |\t\t\t\t JWK_RSA_KEYEL_E,\n+\tFLAG_RSA |\t\t\t\t JWK_RSA_KEYEL_N,\n+\tFLAG_RSA | FLAG_EC |\t\t\t JWK_RSA_KEYEL_D,\n+\tFLAG_RSA |\t\t\t\t JWK_RSA_KEYEL_P,\n+\tFLAG_RSA |\t\t\t\t JWK_RSA_KEYEL_Q,\n+\tFLAG_RSA |\t\t\t\t JWK_RSA_KEYEL_DP,\n+\tFLAG_RSA |\t\t\t\t JWK_RSA_KEYEL_DQ,\n+\tFLAG_RSA |\t\t\t\t JWK_RSA_KEYEL_QI,\n+\n+\tFLAG_RSA | FLAG_EC | FLAG_OCT | FLAG_META | JWK_META_KTY,\n+\t\t\t FLAG_OCT |\t\t JWK_OCT_KEYEL_K,\n+\n+\t\t FLAG_EC |\t\t\t JWK_EC_KEYEL_CRV,\n+\t\t FLAG_EC |\t\t\t JWK_EC_KEYEL_X,\n+\t\t FLAG_EC |\t\t\t JWK_EC_KEYEL_Y,\n+\n+\tFLAG_RSA | FLAG_EC | FLAG_OCT | FLAG_META | JWK_META_KID,\n+\tFLAG_RSA | FLAG_EC | FLAG_OCT | FLAG_META | JWK_META_USE,\n+\n+\tFLAG_RSA | FLAG_EC | FLAG_OCT | FLAG_META | JWK_META_KEY_OPS,\n+\tFLAG_RSA | FLAG_EC | FLAG_OCT | FLAG_META | JWK_META_X5C,\n+\tFLAG_RSA | FLAG_EC | FLAG_OCT | FLAG_META | JWK_META_ALG,\n+};\n+\n+struct cb_lws_jwk {\n+\tstruct lws_jwk *s;\n+\tchar *b64;\n+\tlws_jwk_key_import_callback per_key_cb;\n+\tvoid *user;\n+\tint b64max;\n+\tint pos;\n+\tunsigned short possible;\n+};\n+\n+static int\n+_lws_jwk_set_element_jwk(struct lws_jwk_elements *e, char *in, int len)\n+{\n+\te-\u003ebuf \u003d lws_malloc(len + 1, \u0022jwk\u0022);\n+\tif (!e-\u003ebuf)\n+\t\treturn -1;\n+\n+\tmemcpy(e-\u003ebuf, in, len);\n+\te-\u003ebuf[len] \u003d '\u005c0';\n+\te-\u003elen \u003d len;\n+\n+\treturn 0;\n+}\n+\n+static int\n+_lws_jwk_set_element_jwk_b64(struct lws_jwk_elements *e, char *in, int len)\n+{\n+\tint dec_size \u003d ((len * 3) / 4) + 4, n;\n+\n+\te-\u003ebuf \u003d lws_malloc(dec_size, \u0022jwk\u0022);\n+\tif (!e-\u003ebuf)\n+\t\treturn -1;\n+\n+\tn \u003d lws_b64_decode_string_len(in, len, (char *)e-\u003ebuf, dec_size - 1);\n+\tif (n \u003c 0)\n+\t\treturn -1;\n+\te-\u003elen \u003d n;\n+\n+\treturn 0;\n+}\n+\n+void\n+lws_jwk_destroy_elements(struct lws_jwk_elements *el, int m)\n+{\n+\tint n;\n+\n+\tfor (n \u003d 0; n \u003c m; n++)\n+\t\tif (el[n].buf)\n+\t\t\tlws_free_set_NULL(el[n].buf);\n+}\n+\n+LWS_VISIBLE void\n+lws_jwk_destroy(struct lws_jwk *s)\n+{\n+\tlws_jwk_destroy_elements(s-\u003ee, LWS_ARRAY_SIZE(s-\u003ee));\n+\tlws_jwk_destroy_elements(s-\u003emeta, LWS_ARRAY_SIZE(s-\u003emeta));\n+}\n+\n+static signed char\n+cb_jwk(struct lejp_ctx *ctx, char reason)\n+{\n+\tstruct cb_lws_jwk *cbs \u003d (struct cb_lws_jwk *)ctx-\u003euser;\n+\tstruct lws_jwk *s \u003d cbs-\u003es;\n+\tint idx, poss;\n+\n+\tif (reason \u003d\u003d LEJPCB_VAL_STR_START)\n+\t\tcbs-\u003epos \u003d 0;\n+\n+\tif (reason \u003d\u003d LEJPCB_OBJECT_START \u0026\u0026 ctx-\u003epath_match \u003d\u003d 0 + 1)\n+\t\t/*\n+\t\t * new keys[] member is starting\n+\t\t *\n+\t\t * Until we see some JSON names, it could be anything...\n+\t\t * there is no requirement for kty to be given first and eg,\n+\t\t * ACME specifies the keys must be ordered in lexographic\n+\t\t * order - where kty is not first.\n+\t\t */\n+\t\tcbs-\u003epossible \u003d FLAG_RSA | FLAG_EC | FLAG_OCT;\n+\n+\tif (reason \u003d\u003d LEJPCB_OBJECT_END \u0026\u0026 ctx-\u003epath_match \u003d\u003d 0 + 1) {\n+\t\t/* we completed parsing a key */\n+\t\tif (cbs-\u003eper_key_cb \u0026\u0026 cbs-\u003epossible) {\n+\t\t\tif (cbs-\u003eper_key_cb(cbs-\u003es, cbs-\u003euser)) {\n+\n+\t\t\t\tlwsl_notice(\u0022%s: user cb halts import\u005cn\u0022, __func__);\n+\n+\t\t\t\treturn -2;\n+\t\t\t}\n+\n+\t\t\t/* clear it down */\n+\t\t\tlws_jwk_destroy(cbs-\u003es);\n+\t\t\tcbs-\u003epossible \u003d 0;\n+\t\t}\n+\t}\n+\n+\tif (!(reason \u0026 LEJP_FLAG_CB_IS_VALUE) || !ctx-\u003epath_match)\n+\t\treturn 0;\n+\n+\tif (ctx-\u003epath_match \u003d\u003d 0 + 1)\n+\t\treturn 0;\n+\n+\tidx \u003d tok_map[ctx-\u003epath_match - 1];\n+\n+\tswitch (idx) {\n+\t/* note: kty is not necessarily first... we have to keep track of\n+\t * what could match given which element names have already been\n+\t * seen. Once kty comes, we confirm it's still possible (ie, it's\n+\t * not trying to tell us that it's RSA when we saw a \u0022crv\u0022\n+\t * already) and then reduce the possibilities to just the one that\n+\t * kty told. */\n+\tcase FLAG_RSA | FLAG_EC | FLAG_OCT | FLAG_META | JWK_META_KTY:\n+\n+\t\tif (!strcmp(ctx-\u003ebuf, \u0022oct\u0022)) {\n+\t\t\tif (!(cbs-\u003epossible \u0026 FLAG_OCT))\n+\t\t\t\tgoto elements_mismatch;\n+\t\t\ts-\u003ekty \u003d LWS_JWK_KYT_OCT;\n+\t\t\tcbs-\u003epossible \u003d FLAG_OCT;\n+\t\t\tbreak;\n+\t\t}\n+\t\tif (!strcmp(ctx-\u003ebuf, \u0022RSA\u0022)) {\n+\t\t\tif (!(cbs-\u003epossible \u0026 FLAG_RSA))\n+\t\t\t\tgoto elements_mismatch;\n+\t\t\ts-\u003ekty \u003d LWS_JWK_KYT_RSA;\n+\t\t\tcbs-\u003epossible \u003d FLAG_RSA;\n+\t\t\tbreak;\n+\t\t}\n+\t\tif (!strcmp(ctx-\u003ebuf, \u0022EC\u0022)) {\n+\t\t\tif (!(cbs-\u003epossible \u0026 FLAG_EC))\n+\t\t\t\tgoto elements_mismatch;\n+\t\t\ts-\u003ekty \u003d LWS_JWK_KYT_EC;\n+\t\t\tcbs-\u003epossible \u003d FLAG_EC;\n+\t\t\tbreak;\n+\t\t}\n+\t\tlwsl_err(\u0022%s: Unknown KTY '%s'\u005cn\u0022, __func__, ctx-\u003ebuf);\n+\t\treturn -1;\n+\n+\tdefault:\n+\n+\t\tif (cbs-\u003epos + ctx-\u003enpos \u003e\u003d cbs-\u003eb64max)\n+\t\t\tgoto bail;\n+\n+\t\tmemcpy(cbs-\u003eb64 + cbs-\u003epos, ctx-\u003ebuf, ctx-\u003enpos);\n+\t\tcbs-\u003epos +\u003d ctx-\u003enpos;\n+\n+\t\tif (reason \u003d\u003d LEJPCB_VAL_STR_CHUNK)\n+\t\t\treturn 0;\n+\n+\t\t/* chunking has been collated */\n+\n+\t\tposs \u003d idx \u0026 (FLAG_RSA | FLAG_EC | FLAG_OCT);\n+\t\tcbs-\u003epossible \u0026\u003d poss;\n+\t\tif (!cbs-\u003epossible)\n+\t\t\tgoto elements_mismatch;\n+\n+\t\tif (idx \u0026 FLAG_META) {\n+\t\t\tif (_lws_jwk_set_element_jwk(\u0026s-\u003emeta[idx \u0026 0x7f],\n+\t\t\t\t\t\t cbs-\u003eb64, cbs-\u003epos) \u003c 0)\n+\t\t\t\tgoto bail;\n+\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\t/* key data... do the base64 decode then */\n+\n+\t\tif (_lws_jwk_set_element_jwk_b64(\u0026s-\u003ee[idx \u0026 0x7f],\n+\t\t\t\t\t\t cbs-\u003eb64, cbs-\u003epos) \u003c 0)\n+\t\t\tgoto bail;\n+\n+\t\tbreak;\n+\t}\n+\n+\treturn 0;\n+\n+elements_mismatch:\n+\tlwsl_err(\u0022%s: jwk elements mismatch\u005cn\u0022, __func__);\n+\n+bail:\n+\tlwsl_err(\u0022%s: element failed\u005cn\u0022, __func__);\n+\n+\treturn -1;\n+}\n+\n+LWS_VISIBLE int\n+lws_jwk_import(struct lws_jwk *s, lws_jwk_key_import_callback cb, void *user,\n+\t const char *in, size_t len)\n+{\n+\tstruct lejp_ctx jctx;\n+\tstruct cb_lws_jwk cbs;\n+\tconst int b64max \u003d (((8192 / 8) * 4) / 3) + 1; /* enough for 8K key */\n+\tconst char * const *tok \u003d jwk_outer_tok;\n+\tchar b64[b64max];\n+\tint m;\n+\n+\tmemset(s, 0, sizeof(*s));\n+\tcbs.s \u003d s;\n+\tcbs.b64 \u003d b64;\n+\tcbs.b64max \u003d b64max;\n+\tcbs.pos \u003d 0;\n+\tcbs.per_key_cb \u003d cb;\n+\tcbs.user \u003d user;\n+\tcbs.possible \u003d FLAG_RSA | FLAG_EC | FLAG_OCT;\n+\n+\tif (cb \u003d\u003d NULL)\n+\t\ttok \u003d jwk_tok;\n+\n+\tlejp_construct(\u0026jctx, cb_jwk, \u0026cbs, tok, LWS_ARRAY_SIZE(jwk_tok));\n+\tm \u003d (int)(signed char)lejp_parse(\u0026jctx, (uint8_t *)in, len);\n+\tlejp_destruct(\u0026jctx);\n+\n+\tif (m \u003c 0) {\n+\t\tlwsl_notice(\u0022%s: parse got %d\u005cn\u0022, __func__, m);\n+\n+\t\treturn -1;\n+\t}\n+\n+\tif (s-\u003ekty \u003d\u003d LWS_JWK_KYT_UNKNOWN) {\n+\t\tlwsl_notice(\u0022%s: missing or unknown kyt\u005cn\u0022, __func__);\n+\t\treturn -1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE int\n+lws_jwk_export(struct lws_jwk *s, int private, char *p, size_t len)\n+{\n+\tchar *start \u003d p, *end \u003d \u0026p[len - 1];\n+\tint n, limit \u003d LWS_COUNT_JWK_ELEMENTS;\n+\n+\t/* RFC7638 lexicographic order requires\n+\t * RSA: e -\u003e kty -\u003e n\n+\t * oct: k -\u003e kty\n+\t */\n+\n+\tp +\u003d lws_snprintf(p, end - p, \u0022{\u0022);\n+\n+\tswitch (s-\u003ekty) {\n+\n+\tcase LWS_JWK_KYT_OCT:\n+\t\tif (!s-\u003ee[JWK_OCT_KEYEL_K].buf)\n+\t\t\treturn -1;\n+\n+\t\tp +\u003d lws_snprintf(p, end - p, \u0022\u005c\u0022k\u005c\u0022:\u005c\u0022\u0022);\n+\t\tn \u003d lws_jws_base64_enc((const char *)s-\u003ee[JWK_OCT_KEYEL_K].buf,\n+\t\t\t\ts-\u003ee[JWK_OCT_KEYEL_K].len, p, end - p - 4);\n+\t\tif (n \u003c 0) {\n+\t\t\tlwsl_notice(\u0022%s: enc failed\u005cn\u0022, __func__);\n+\t\t\treturn -1;\n+\t\t}\n+\t\tp +\u003d n;\n+\n+\t\tp +\u003d lws_snprintf(p, end - p, \u0022\u005c\u0022,\u005c\u0022kty\u005c\u0022:\u005c\u0022%s\u005c\u0022}\u0022,\n+\t\t\t\t kyt_names[s-\u003ekty]);\n+\n+\t\treturn p - start;\n+\n+\tcase LWS_JWK_KYT_RSA:\n+\t\tif (!s-\u003ee[JWK_RSA_KEYEL_E].buf ||\n+\t\t !s-\u003ee[JWK_RSA_KEYEL_N].buf ||\n+\t\t (private \u0026\u0026 (!s-\u003ee[JWK_RSA_KEYEL_D].buf ||\n+\t\t\t\t !s-\u003ee[JWK_RSA_KEYEL_P].buf ||\n+\t\t\t\t !s-\u003ee[JWK_RSA_KEYEL_Q].buf))\n+\t\t) {\n+\t\t\tlwsl_notice(\u0022%s: not enough elements filled\u005cn\u0022,\n+\t\t\t\t __func__);\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tif (!private)\n+\t\t\tlimit \u003d JWK_RSA_KEYEL_N + 1;\n+\n+\t\tfor (n \u003d 0; n \u003c limit; n++) {\n+\t\t\tint m;\n+\n+\t\t\tif (!s-\u003ee[n].buf)\n+\t\t\t\tcontinue;\n+\t\t\tlwsl_info(\u0022%d: len %d\u005cn\u0022, n, s-\u003ee[n].len);\n+\n+\t\t\tif (n)\n+\t\t\t\tp +\u003d lws_snprintf(p, end - p, \u0022,\u0022);\n+\t\t\tp +\u003d lws_snprintf(p, end - p, \u0022\u005c\u0022%s\u005c\u0022:\u005c\u0022\u0022, jwk_tok[n]);\n+\t\t\tm \u003d lws_jws_base64_enc((const char *)s-\u003ee[n].buf,\n+\t\t\t\t\t\t s-\u003ee[n].len, p,\n+\t\t\t\t\t\t end - p - 4);\n+\t\t\tif (m \u003c 0) {\n+\t\t\t\tlwsl_notice(\u0022%s: enc fail inlen %d outlen %d\u005cn\u0022,\n+\t\t\t\t\t\t__func__, (int)s-\u003ee[n].len,\n+\t\t\t\t\t\tlws_ptr_diff(end, p) - 4);\n+\t\t\t\treturn -1;\n+\t\t\t}\n+\t\t\tp +\u003d m;\n+\t\t\t*p++ \u003d '\u005c\u0022';\n+\n+\t\t\tif (!n) /* RFC7638 lexicographic order */\n+\t\t\t\tp +\u003d lws_snprintf(p, end - p, \u0022,\u005c\u0022kty\u005c\u0022:\u005c\u0022%s\u005c\u0022\u0022,\n+\t\t\t\t\t\t kyt_names[s-\u003ekty]);\n+\t\t}\n+\n+\t\tp +\u003d lws_snprintf(p, end - p, \u0022}\u0022);\n+\n+\t\treturn p - start;\n+\n+\tcase LWS_JWK_KYT_EC:\n+\t\treturn p - start;\n+\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\n+\tlwsl_err(\u0022%s: unknown key type %d\u005cn\u0022, __func__, s-\u003ekty);\n+\n+\treturn -1;\n+}\n+\n+LWS_VISIBLE int\n+lws_jwk_rfc7638_fingerprint(struct lws_jwk *s, char *digest32)\n+{\n+\tstruct lws_genhash_ctx hash_ctx;\n+\tint tmpsize \u003d 2536, n;\n+\tchar *tmp;\n+\n+\ttmp \u003d lws_malloc(tmpsize, \u0022rfc7638 tmp\u0022);\n+\n+\tn \u003d lws_jwk_export(s, 0, tmp, tmpsize);\n+\tif (n \u003c 0)\n+\t\tgoto bail;\n+\n+\tif (lws_genhash_init(\u0026hash_ctx, LWS_GENHASH_TYPE_SHA256))\n+\t\tgoto bail;\n+\n+\tif (lws_genhash_update(\u0026hash_ctx, tmp, n)) {\n+\t\tlws_genhash_destroy(\u0026hash_ctx, NULL);\n+\n+\t\tgoto bail;\n+\t}\n+\tlws_free(tmp);\n+\n+\tif (lws_genhash_destroy(\u0026hash_ctx, digest32))\n+\t\treturn -1;\n+\n+\treturn 0;\n+\n+bail:\n+\tlws_free(tmp);\n+\n+\treturn -1;\n+}\n+\n+LWS_VISIBLE int\n+lws_jwk_load(struct lws_jwk *s, const char *filename,\n+\t lws_jwk_key_import_callback cb, void *user)\n+{\n+\tint buflen \u003d 4096;\n+\tchar *buf \u003d lws_malloc(buflen, \u0022jwk-load\u0022);\n+\tint n;\n+\n+\tif (!buf)\n+\t\treturn -1;\n+\n+\tn \u003d lws_plat_read_file(filename, buf, buflen);\n+\tif (n \u003c 0)\n+\t\tgoto bail;\n+\n+\tn \u003d lws_jwk_import(s, cb, user, buf, n);\n+\tlws_free(buf);\n+\n+\treturn n;\n+bail:\n+\tlws_free(buf);\n+\n+\treturn -1;\n+}\n+\n+LWS_VISIBLE int\n+lws_jwk_save(struct lws_jwk *s, const char *filename)\n+{\n+\tint buflen \u003d 4096;\n+\tchar *buf \u003d lws_malloc(buflen, \u0022jwk-save\u0022);\n+\tint n, m;\n+\n+\tif (!buf)\n+\t\treturn -1;\n+\n+\tn \u003d lws_jwk_export(s, 1, buf, buflen);\n+\tif (n \u003c 0)\n+\t\tgoto bail;\n+\n+\tm \u003d lws_plat_write_file(filename, buf, n);\n+\n+\tlws_free(buf);\n+\tif (m)\n+\t\treturn -1;\n+\n+\treturn 0;\n+\n+bail:\n+\tlws_free(buf);\n+\n+\treturn -1;\n+}\ndiff --git a/lib/jose/jws/jose.c b/lib/jose/jws/jose.c\nnew file mode 100644\nindex 0000000..6abb965\n--- /dev/null\n+++ b/lib/jose/jws/jose.c\n@@ -0,0 +1,254 @@\n+/*\n+ * libwebsockets - JSON Web Signature support\n+ *\n+ * Copyright (C) 2017 - 2018 Andy Green \u003candy@warmcat.com\u003e\n+ *\n+ * This library is free software; you can redistribute it and/or\n+ * modify it under the terms of the GNU Lesser General Public\n+ * License as published by the Free Software Foundation:\n+ * version 2.1 of the License.\n+ *\n+ * This library is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ * Lesser General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU Lesser General Public\n+ * License along with this library; if not, write to the Free Software\n+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n+ * MA 02110-1301 USA\n+ *\n+ * JOSE is actually specified as part of JWS RFC7515. JWE references RFC7515\n+ * to specify its JOSE JSON object. So it lives in ./lib/jose/jws/jose.c.\n+ */\n+\n+#include \u0022core/private.h\u0022\n+\n+#include \u003cstdint.h\u003e\n+\n+static const char * const jws_jose[] \u003d {\n+\t\u0022alg\u0022, /* REQUIRED */\n+\t\u0022jku\u0022,\n+\t\u0022jwk\u0022,\n+\t\u0022kid\u0022,\n+\t\u0022x5u\u0022,\n+\t\u0022x5c\u0022,\n+\t\u0022x5t\u0022,\n+\t\u0022x5t#S256\u0022,\n+\t\u0022typ\u0022,\n+\t\u0022cty\u0022,\n+\t\u0022crit\u0022,\n+\n+\t/* valid for JWE only below here */\n+\n+\t\u0022enc\u0022,\n+\t\u0022zip\u0022, /* (\u0022DEF\u0022 \u003d deflate) */\n+\n+\t\u0022epk\u0022, /* valid for JWE ECDH only */\n+\t\u0022apu\u0022, /* valid for JWE ECDH only */\n+\t\u0022apv\u0022, /* valid for JWE ECDH only */\n+\t\u0022iv\u0022, /* valid for JWE AES only */\n+\t\u0022tag\u0022, /* valid for JWE AES only */\n+\t\u0022p2s\u0022, /* valid for JWE PBES2 only */\n+\t\u0022p2c\u0022 /* valid for JWE PBES2 only */\n+};\n+\n+static signed char\n+lws_jws_jose_cb(struct lejp_ctx *ctx, char reason)\n+{\n+\tstruct cb_hdr_s *s \u003d (struct cb_hdr_s *)ctx-\u003euser;\n+\n+\tif (!(reason \u0026 LEJP_FLAG_CB_IS_VALUE) || !ctx-\u003epath_match)\n+\t\treturn 0;\n+\n+\tswitch (ctx-\u003epath_match - 1) {\n+\n+\t/* strings */\n+\n+\tcase LJJHI_ALG: /* REQUIRED */\n+\n+\t\tlws_strncpy(s-\u003ealg, ctx-\u003ebuf, sizeof(s-\u003ealg));\n+\n+\t\tif (s-\u003eis_jwe) {\n+\n+\t\t\tlwsl_err(\u0022%s: JWE alg\u005cn\u0022, __func__);\n+\n+\t\t\t/* interpret as for JWE... just store the string */\n+\n+\t\t\treturn 0;\n+\t\t}\n+\n+\t\t/* interpret as for JWS */\n+\n+\t\tif (!strcmp(ctx-\u003ebuf, \u0022HS256\u0022)) {\n+\t\t\ts-\u003ehmac_type \u003d LWS_GENHMAC_TYPE_SHA256;\n+\t\t\ts-\u003ealgtype \u003d LWS_JWK_ENCTYPE_NONE;\n+\t\t\tbreak;\n+\t\t}\n+\t\tif (!strcmp(ctx-\u003ebuf, \u0022HS384\u0022)) {\n+\t\t\ts-\u003ehmac_type \u003d LWS_GENHMAC_TYPE_SHA384;\n+\t\t\ts-\u003ealgtype \u003d LWS_JWK_ENCTYPE_NONE;\n+\t\t\tbreak;\n+\t\t}\n+\t\tif (!strcmp(ctx-\u003ebuf, \u0022HS512\u0022)) {\n+\t\t\ts-\u003ehmac_type \u003d LWS_GENHMAC_TYPE_SHA512;\n+\t\t\ts-\u003ealgtype \u003d LWS_JWK_ENCTYPE_NONE;\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tif (!strcmp(ctx-\u003ebuf, \u0022RS256\u0022)) {\n+\t\t\ts-\u003ehash_type \u003d LWS_GENHASH_TYPE_SHA256;\n+\t\t\ts-\u003ealgtype \u003d LWS_JWK_ENCTYPE_RSASSA;\n+\t\t\tbreak;\n+\t\t}\n+\t\tif (!strcmp(ctx-\u003ebuf, \u0022RS384\u0022)) {\n+\t\t\ts-\u003ehash_type \u003d LWS_GENHASH_TYPE_SHA384;\n+\t\t\ts-\u003ealgtype \u003d LWS_JWK_ENCTYPE_RSASSA;\n+\t\t\tbreak;\n+\t\t}\n+\t\tif (!strcmp(ctx-\u003ebuf, \u0022RS512\u0022)) {\n+\t\t\ts-\u003ehash_type \u003d LWS_GENHASH_TYPE_SHA512;\n+\t\t\ts-\u003ealgtype \u003d LWS_JWK_ENCTYPE_RSASSA;\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tif (!strcmp(ctx-\u003ebuf, \u0022ES256\u0022)) {\n+\t\t\ts-\u003ehash_type \u003d LWS_GENHASH_TYPE_SHA256;\n+\t\t\ts-\u003ealgtype \u003d LWS_JWK_ENCTYPE_EC;\n+\t\t\tstrncpy(s-\u003ecurve, \u0022P-256\u0022, sizeof(s-\u003ecurve));\n+\t\t\tbreak;\n+\t\t}\n+\t\tif (!strcmp(ctx-\u003ebuf, \u0022ES384\u0022)) {\n+\t\t\ts-\u003ehash_type \u003d LWS_GENHASH_TYPE_SHA384;\n+\t\t\ts-\u003ealgtype \u003d LWS_JWK_ENCTYPE_EC;\n+\t\t\tstrncpy(s-\u003ecurve, \u0022P-384\u0022, sizeof(s-\u003ecurve));\n+\t\t\tbreak;\n+\t\t}\n+\t\tif (!strcmp(ctx-\u003ebuf, \u0022ES512\u0022)) {\n+\t\t\ts-\u003ehash_type \u003d LWS_GENHASH_TYPE_SHA512;\n+\t\t\ts-\u003ealgtype \u003d LWS_JWK_ENCTYPE_EC;\n+\t\t\tstrncpy(s-\u003ecurve, \u0022P-521\u0022, sizeof(s-\u003ecurve));\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\treturn -1;\n+\n+\tcase LJJHI_TYP: /* Optional: string: media type */\n+\t\tif (strcmp(ctx-\u003ebuf, \u0022JWT\u0022))\n+\t\t\treturn -1;\n+\t\tbreak;\n+\n+\tcase LJJHI_JKU:\t/* Optional: string */\n+\tcase LJJHI_KID:\t/* Optional: string */\n+\tcase LJJHI_X5U:\t/* Optional: string: url of public key cert / chain */\n+\tcase LJJHI_CTY:\t/* Optional: string: content media type */\n+\n+\t/* base64 */\n+\n+\tcase LJJHI_X5C:\t/* Optional: base64 (NOT -url): actual cert */\n+\n+\t/* base64-url */\n+\n+\tcase LJJHI_X5T:\t/* Optional: base64url: SHA-1 of actual cert */\n+\tcase LJJHI_X5T_S256: /* Optional: base64url: SHA-256 of actual cert */\n+\n+\t/* array of strings */\n+\n+\tcase LJJHI_CRIT: /* Optional for send, REQUIRED: array of strings:\n+\t\t\t * mustn't contain standardized strings or null set */\n+\t\tbreak;\n+\n+\t/* jwk child */\n+\n+\tcase LJJHI_JWK:\t/* Optional: jwk JSON object: public key: */\n+\n+\t/* past here, JWE only */\n+\n+\tcase LJJHI_ENC:\t/* JWE only: Optional: string */\n+\t\tif (!s-\u003eis_jwe)\n+\t\t\treturn -1;\n+\t\tbreak;\n+\n+\tcase LJJHI_ZIP:\t/* JWE only: Optional: string (\u0022DEF\u0022 \u003d deflate) */\n+\t\tif (!s-\u003eis_jwe)\n+\t\t\treturn -1;\n+\t\tbreak;\n+\n+\tcase LJJHI_EPK:\t/* Additional arg for JWE ECDH */\n+\t\tif (!s-\u003eis_jwe)\n+\t\t\treturn -1;\n+\t\tbreak;\n+\n+\tcase LJJHI_APU:\t/* Additional arg for JWE ECDH */\n+\t\tif (!s-\u003eis_jwe)\n+\t\t\treturn -1;\n+\t\tbreak;\n+\n+\tcase LJJHI_APV:\t/* Additional arg for JWE ECDH */\n+\t\tif (!s-\u003eis_jwe)\n+\t\t\treturn -1;\n+\t\tbreak;\n+\n+\tcase LJJHI_IV: /* Additional arg for JWE AES */\n+\t\tif (!s-\u003eis_jwe)\n+\t\t\treturn -1;\n+\t\tbreak;\n+\n+\tcase LJJHI_TAG:\t/* Additional arg for JWE AES */\n+\t\tif (!s-\u003eis_jwe)\n+\t\t\treturn -1;\n+\t\tbreak;\n+\n+\tcase LJJHI_P2S:\t/* Additional arg for JWE PBES2 */\n+\t\tif (!s-\u003eis_jwe)\n+\t\t\treturn -1;\n+\t\tbreak;\n+\tcase LJJHI_P2C:\t/* Additional arg for JWE PBES2 */\n+\t\tif (!s-\u003eis_jwe)\n+\t\t\treturn -1;\n+\t\tbreak;\n+\n+\t/* ignore what we don't understand */\n+\n+\tdefault:\n+\t\treturn 0;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int\n+lws_jose_parse(struct cb_hdr_s *args, uint8_t *buf, int n, int is_jwe)\n+{\n+\tstruct lejp_ctx jctx;\n+\tint m;\n+\n+\targs-\u003ealg[0] \u003d '\u005c0';\n+\targs-\u003ecurve[0] \u003d '\u005c0';\n+\targs-\u003ealgtype \u003d -1;\n+\targs-\u003eis_jwe \u003d is_jwe;\n+\n+\tlejp_construct(\u0026jctx, lws_jws_jose_cb, args, jws_jose,\n+\t\t LWS_ARRAY_SIZE(jws_jose));\n+\n+\tm \u003d (int)(signed char)lejp_parse(\u0026jctx, (uint8_t *)buf, n);\n+\tlejp_destruct(\u0026jctx);\n+\tif (m \u003c 0) {\n+\t\tlwsl_notice(\u0022parse got %d: alg %s\u005cn\u0022, m, args-\u003ealg);\n+\t\treturn -1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int\n+lws_jws_parse_jose(struct cb_hdr_s *args, uint8_t *buf, int n)\n+{\n+\treturn lws_jose_parse(args, buf, n, 0);\n+}\n+\n+int\n+lws_jwe_parse_jose(struct cb_hdr_s *args, uint8_t *buf, int n)\n+{\n+\treturn lws_jose_parse(args, buf, n, 1);\n+}\ndiff --git a/lib/jose/jws/jws.c b/lib/jose/jws/jws.c\nnew file mode 100644\nindex 0000000..2065512\n--- /dev/null\n+++ b/lib/jose/jws/jws.c\n@@ -0,0 +1,367 @@\n+/*\n+ * libwebsockets - JSON Web Signature support\n+ *\n+ * Copyright (C) 2017 - 2018 Andy Green \u003candy@warmcat.com\u003e\n+ *\n+ * This library is free software; you can redistribute it and/or\n+ * modify it under the terms of the GNU Lesser General Public\n+ * License as published by the Free Software Foundation:\n+ * version 2.1 of the License.\n+ *\n+ * This library is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ * Lesser General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU Lesser General Public\n+ * License along with this library; if not, write to the Free Software\n+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n+ * MA 02110-1301 USA\n+ */\n+\n+#include \u0022core/private.h\u0022\n+#include \u0022private.h\u0022\n+\n+LWS_VISIBLE int\n+lws_jws_base64_enc(const char *in, size_t in_len, char *out, size_t out_max)\n+{\n+\tint n;\n+\n+\tn \u003d lws_b64_encode_string_url(in, in_len, out, out_max - 1);\n+\tif (n \u003c 0)\n+\t\treturn n; /* too large for output buffer */\n+\n+\t/* trim the terminal \u003d */\n+\twhile (n \u0026\u0026 out[n - 1] \u003d\u003d '\u003d')\n+\t\tn--;\n+\n+\tout[n] \u003d '\u005c0';\n+\n+\treturn n;\n+}\n+\n+LWS_VISIBLE int\n+lws_jws_encode_section(const char *in, size_t in_len, int first, char **p,\n+\t\t char *end)\n+{\n+\tint n, len \u003d (end - *p) - 1;\n+\tchar *p_entry \u003d *p;\n+\n+\tif (len \u003c 3)\n+\t\treturn -1;\n+\n+\tif (!first)\n+\t\t*(*p)++ \u003d '.';\n+\n+\tn \u003d lws_jws_base64_enc(in, in_len, *p, len - 1);\n+\tif (n \u003c 0)\n+\t\treturn -1;\n+\n+\t*p +\u003d n;\n+\n+\treturn (*p) - p_entry;\n+}\n+\n+static int\n+lws_jws_find_sig(const char *in, size_t len)\n+{\n+\tconst char *p \u003d in + len - 1;\n+\n+\twhile (len--)\n+\t\tif (*p \u003d\u003d '.')\n+\t\t\treturn (p + 1) - in;\n+\t\telse\n+\t\t\tp--;\n+\n+\tlwsl_notice(\u0022%s failed\u005cn\u0022, __func__);\n+\treturn -1;\n+}\n+\n+LWS_VISIBLE int\n+lws_jws_confirm_sig(const char *in, size_t len, struct lws_jwk *jwk,\n+\t\t struct lws_context *context)\n+{\n+\tint sig_pos \u003d lws_jws_find_sig(in, len), pos \u003d 0, n, m, h_len;\n+\tuint8_t digest[LWS_GENHASH_LARGEST];\n+\tstruct lws_genhash_ctx hash_ctx;\n+\tstruct lws_genrsa_ctx rsactx;\n+\tstruct lws_genhmac_ctx ctx;\n+\tstruct cb_hdr_s args;\n+\tchar buf[2048];\n+\n+\t/* 1) there has to be a signature */\n+\n+\tif (sig_pos \u003c 0)\n+\t\treturn -1;\n+\n+\t/* 2) find length of first, hdr, block */\n+\n+\twhile (pos \u003c (int)len \u0026\u0026 in[pos] !\u003d '.')\n+\t\tpos++;\n+\tif (pos \u003d\u003d (int)len)\n+\t\treturn -1;\n+\n+\t/* 3) Decode the header block */\n+\n+\tn \u003d lws_b64_decode_string_len(in, pos, buf, sizeof(buf) - 1);\n+\tif (n \u003c 0)\n+\t\treturn -1;\n+\n+\t/* 4) Require either:\n+\t * typ: JWT (if present) and alg: HS256/384/512\n+\t * typ: JWT (if present) and alg: RS256/384/512\n+\t * typ: JWT (if present) and alg: ES256/384/512\n+\t */\n+\n+\tm \u003d lws_jws_parse_jose(\u0026args, (unsigned char *)buf, n);\n+\tif (m \u003c 0) {\n+\t\tlwsl_notice(\u0022parse got %d: alg %s\u005cn\u0022, m, args.alg);\n+\t\treturn -1;\n+\t}\n+\n+\t/* 5) decode the B64URL signature part into buf / m */\n+\n+\tm \u003d lws_b64_decode_string_len(in + sig_pos, len - sig_pos,\n+\t\t\t\t buf, sizeof(buf) - 1);\n+\n+\tswitch (args.algtype) {\n+\tcase LWS_JWK_ENCTYPE_RSASSA:\n+\n+\t\t/* RSASSA-PKCS1-v1_5 using SHA-256/384/512 */\n+\n+\t\t/* 6(RSA): compute the hash of the payload into \u0022digest\u0022 */\n+\n+\t\tif (lws_genhash_init(\u0026hash_ctx, args.hash_type))\n+\t\t\treturn -1;\n+\n+\t\tif (lws_genhash_update(\u0026hash_ctx, (uint8_t *)in, sig_pos - 1)) {\n+\t\t\tlws_genhash_destroy(\u0026hash_ctx, NULL);\n+\n+\t\t\treturn -1;\n+\t\t}\n+\t\tif (lws_genhash_destroy(\u0026hash_ctx, digest))\n+\t\t\treturn -1;\n+\n+\t\th_len \u003d lws_genhash_size(args.hash_type);\n+\n+\t\tif (lws_genrsa_create(\u0026rsactx, jwk-\u003ee, context)) {\n+\t\t\tlwsl_notice(\u0022%s: lws_genrsa_public_decrypt_create\u005cn\u0022,\n+\t\t\t\t __func__);\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tn \u003d lws_genrsa_public_verify(\u0026rsactx, digest, args.hash_type,\n+\t\t\t\t\t (uint8_t *)buf, m);\n+\n+\t\tlws_genrsa_destroy(\u0026rsactx);\n+\t\tif (n \u003c 0) {\n+\t\t\tlwsl_notice(\u0022decrypt fail\u005cn\u0022);\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tbreak;\n+\n+\tcase LWS_JWK_ENCTYPE_NONE:\n+\n+\t\t/* SHA256/384/512 HMAC */\n+\n+\t\th_len \u003d lws_genhmac_size(args.hmac_type);\n+\t\tif (m \u003c 0 || m !\u003d h_len)\n+\t\t\treturn -1;\n+\n+\t\t/* 6) compute HMAC over payload */\n+\n+\t\tif (lws_genhmac_init(\u0026ctx, args.hmac_type,\n+\t\t\t\t jwk-\u003ee[JWK_RSA_KEYEL_E].buf,\n+\t\t\t\t jwk-\u003ee[JWK_RSA_KEYEL_E].len))\n+\t\t\treturn -1;\n+\n+\t\tif (lws_genhmac_update(\u0026ctx, (uint8_t *)in, sig_pos - 1)) {\n+\t\t\tlws_genhmac_destroy(\u0026ctx, NULL);\n+\n+\t\t\treturn -1;\n+\t\t}\n+\t\tif (lws_genhmac_destroy(\u0026ctx, digest))\n+\t\t\treturn -1;\n+\n+\t\t/* 7) Compare the computed and decoded hashes */\n+\n+\t\tif (memcmp(digest, buf, h_len)) {\n+\t\t\tlwsl_notice(\u0022digest mismatch\u005cn\u0022);\n+\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tbreak;\n+\n+\tcase LWS_JWK_ENCTYPE_EC:\n+\n+\t\tlwsl_err(\u0022%s: EC not supported yet\u005cn\u0022, __func__);\n+\t\treturn -1;\n+\n+\tdefault:\n+\t\tlwsl_err(\u0022%s: unknown alg from jose\u005cn\u0022, __func__);\n+\t\treturn -1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+LWS_VISIBLE int\n+lws_jws_sign_from_b64(const char *b64_hdr, size_t hdr_len, const char *b64_pay,\n+\t\t size_t pay_len, char *b64_sig, size_t sig_len,\n+\t\t enum lws_genhash_types hash_type, struct lws_jwk *jwk,\n+\t\t struct lws_context *context)\n+{\n+\tuint8_t digest[LWS_GENHASH_LARGEST];\n+\tstruct lws_genhash_ctx hash_ctx;\n+\tstruct lws_genrsa_ctx rsactx;\n+\tuint8_t *buf;\n+\tint n;\n+\n+\tif (lws_genhash_init(\u0026hash_ctx, hash_type))\n+\t\treturn -1;\n+\n+\tif (b64_hdr) {\n+\t\tif (lws_genhash_update(\u0026hash_ctx, (uint8_t *)b64_hdr, hdr_len))\n+\t\t\tgoto hash_fail;\n+\t\tif (lws_genhash_update(\u0026hash_ctx, (uint8_t *)\u0022.\u0022, 1))\n+\t\t\tgoto hash_fail;\n+\t}\n+\tif (lws_genhash_update(\u0026hash_ctx, (uint8_t *)b64_pay, pay_len))\n+\t\tgoto hash_fail;\n+\n+\tif (lws_genhash_destroy(\u0026hash_ctx, digest))\n+\t\treturn -1;\n+\n+\tif (jwk-\u003ekty \u003d\u003d LWS_JWK_KYT_RSA) {\n+\t\tif (lws_genrsa_create(\u0026rsactx, jwk-\u003ee, context)) {\n+\t\t\tlwsl_notice(\u0022%s: lws_genrsa_public_decrypt_create\u005cn\u0022,\n+\t\t\t\t __func__);\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tn \u003d jwk-\u003ee[JWK_RSA_KEYEL_N].len;\n+\t\tbuf \u003d lws_malloc(n, \u0022jws sign\u0022);\n+\t\tif (!buf)\n+\t\t\treturn -1;\n+\n+\t\tn \u003d lws_genrsa_public_sign(\u0026rsactx, digest, hash_type, buf, n);\n+\t\tlws_genrsa_destroy(\u0026rsactx);\n+\t\tif (n \u003c 0) {\n+\t\t\tlws_free(buf);\n+\n+\t\t\treturn -1;\n+\t\t}\n+\n+\t\tn \u003d lws_jws_base64_enc((char *)buf, n, b64_sig, sig_len);\n+\t\tlws_free(buf);\n+\n+\t\treturn n;\n+\t}\n+\n+\tif (jwk-\u003ekty \u003d\u003d LWS_JWK_KYT_OCT)\n+\t\treturn lws_jws_base64_enc((char *)digest,\n+\t\t\t\t\t lws_genhash_size(hash_type),\n+\t\t\t\t\t b64_sig, sig_len);\n+\n+\t/* unknown key type */\n+\n+\treturn -1;\n+\n+hash_fail:\n+\tlws_genhash_destroy(\u0026hash_ctx, NULL);\n+\treturn -1;\n+}\n+\n+LWS_VISIBLE int\n+lws_jws_create_packet(struct lws_jwk *jwk, const char *payload, size_t len,\n+\t\t const char *nonce, char *out, size_t out_len,\n+\t\t struct lws_context *context)\n+{\n+\tchar *buf, *start, *p, *end, *p1, *end1, *b64_hdr, *b64_pay;\n+\tint n, b64_hdr_len, b64_pay_len;\n+\n+\t/*\n+\t * This buffer is local to the function, the actual output\n+\t * is prepared into vhd-\u003ebuf. Only the plaintext protected header\n+\t * (which contains the public key, 512 bytes for 4096b) goes in\n+\t * here temporarily.\n+\t */\n+\tn \u003d LWS_PRE + 2048;\n+\tbuf \u003d malloc(n);\n+\tif (!buf) {\n+\t\tlwsl_notice(\u0022%s: malloc %d failed\u005cn\u0022, __func__, n);\n+\t\treturn -1;\n+\t}\n+\n+\tp \u003d start \u003d buf + LWS_PRE;\n+\tend \u003d buf + n - LWS_PRE - 1;\n+\n+\t/*\n+\t * temporary JWS protected header plaintext\n+\t */\n+\n+\tp +\u003d lws_snprintf(p, end - p, \u0022{\u005c\u0022alg\u005c\u0022:\u005c\u0022RS256\u005c\u0022,\u005c\u0022jwk\u005c\u0022:\u0022);\n+\tn \u003d lws_jwk_export(jwk, 0, p, end - p);\n+\tif (n \u003c 0) {\n+\t\tlwsl_notice(\u0022failed to export jwk\u005cn\u0022);\n+\n+\t\tgoto bail;\n+\t}\n+\tp +\u003d n;\n+\tp +\u003d lws_snprintf(p, end - p, \u0022,\u005c\u0022nonce\u005c\u0022:\u005c\u0022%s\u005c\u0022}\u0022, nonce);\n+\n+\t/*\n+\t * prepare the signed outer JSON with all the parts in\n+\t */\n+\n+\tp1 \u003d out;\n+\tend1 \u003d out + out_len - 1;\n+\n+\tp1 +\u003d lws_snprintf(p1, end1 - p1, \u0022{\u005c\u0022protected\u005c\u0022:\u005c\u0022\u0022);\n+\tb64_hdr \u003d p1;\n+\tn \u003d lws_jws_base64_enc(start, p - start, p1, end1 - p1);\n+\tif (n \u003c 0) {\n+\t\tlwsl_notice(\u0022%s: failed to encode protected\u005cn\u0022, __func__);\n+\t\tgoto bail;\n+\t}\n+\tb64_hdr_len \u003d n;\n+\tp1 +\u003d n;\n+\n+\tp1 +\u003d lws_snprintf(p1, end1 - p1, \u0022\u005c\u0022,\u005c\u0022payload\u005c\u0022:\u005c\u0022\u0022);\n+\tb64_pay \u003d p1;\n+\tn \u003d lws_jws_base64_enc(payload, len, p1, end1 - p1);\n+\tif (n \u003c 0) {\n+\t\tlwsl_notice(\u0022%s: failed to encode payload\u005cn\u0022, __func__);\n+\t\tgoto bail;\n+\t}\n+\tb64_pay_len \u003d n;\n+\n+\tp1 +\u003d n;\n+\tp1 +\u003d lws_snprintf(p1, end1 - p1, \u0022\u005c\u0022,\u005c\u0022signature\u005c\u0022:\u005c\u0022\u0022);\n+\n+\t/*\n+\t * taking the b64 protected header and the b64 payload, sign them\n+\t * and place the signature into the packet\n+\t */\n+\tn \u003d lws_jws_sign_from_b64(b64_hdr, b64_hdr_len, b64_pay, b64_pay_len,\n+\t\t\t\t p1, end1 - p1, LWS_GENHASH_TYPE_SHA256, jwk,\n+\t\t\t\t context);\n+\tif (n \u003c 0) {\n+\t\tlwsl_notice(\u0022sig gen failed\u005cn\u0022);\n+\n+\t\tgoto bail;\n+\t}\n+\tp1 +\u003d n;\n+\tp1 +\u003d lws_snprintf(p1, end1 - p1, \u0022\u005c\u0022}\u0022);\n+\n+\tfree(buf);\n+\n+\treturn p1 - out;\n+\n+bail:\n+\tfree(buf);\n+\n+\treturn -1;\n+}\ndiff --git a/lib/jose/jws/private.h b/lib/jose/jws/private.h\nnew file mode 100644\nindex 0000000..b5d39f2\n--- /dev/null\n+++ b/lib/jose/jws/private.h\n@@ -0,0 +1,29 @@\n+/*\n+ * libwebsockets - JSON Web Signature support\n+ *\n+ * Copyright (C) 2018 Andy Green \u003candy@warmcat.com\u003e\n+ *\n+ * This library is free software; you can redistribute it and/or\n+ * modify it under the terms of the GNU Lesser General Public\n+ * License as published by the Free Software Foundation:\n+ * version 2.1 of the License.\n+ *\n+ * This library is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ * Lesser General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU Lesser General Public\n+ * License along with this library; if not, write to the Free Software\n+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n+ * MA 02110-1301 USA\n+ *\n+ * JOSE is actually specified as part of JWS RFC7515. JWE references RFC7515\n+ * to specify its JOSE JSON object. So it lives in ./lib/jose/jws/jose.c.\n+ */\n+\n+int\n+lws_jws_parse_jose(struct cb_hdr_s *args, uint8_t *buf, int n);\n+\n+int\n+lws_jwe_parse_jose(struct cb_hdr_s *args, uint8_t *buf, int n);\ndiff --git a/lib/jose/private.h b/lib/jose/private.h\nnew file mode 100644\nindex 0000000..d39f712\n--- /dev/null\n+++ b/lib/jose/private.h\n@@ -0,0 +1,23 @@\n+/*\n+ * libwebsockets - jose private header\n+ *\n+ * Copyright (C) 2018 Andy Green \u003candy@warmcat.com\u003e\n+ *\n+ * This library is free software; you can redistribute it and/or\n+ * modify it under the terms of the GNU Lesser General Public\n+ * License as published by the Free Software Foundation:\n+ * version 2.1 of the License.\n+ *\n+ * This library is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ * Lesser General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU Lesser General Public\n+ * License along with this library; if not, write to the Free Software\n+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n+ * MA 02110-1301 USA\n+ */\n+\n+void\n+lws_jwk_destroy_elements(struct lws_jwk_elements *el, int m);\ndiff --git a/lib/misc/jws/jwk.c b/lib/misc/jws/jwk.c\ndeleted file mode 100644\nindex fca8346..0000000\n--- a/lib/misc/jws/jwk.c\n+++ /dev/null\n@@ -1,325 +0,0 @@\n-/*\n- * libwebsockets - JSON Web Key support\n- *\n- * Copyright (C) 2017 Andy Green \u003candy@warmcat.com\u003e\n- *\n- * This library is free software; you can redistribute it and/or\n- * modify it under the terms of the GNU Lesser General Public\n- * License as published by the Free Software Foundation:\n- * version 2.1 of the License.\n- *\n- * This library is distributed in the hope that it will be useful,\n- * but WITHOUT ANY WARRANTY; without even the implied warranty of\n- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n- * Lesser General Public License for more details.\n- *\n- * You should have received a copy of the GNU Lesser General Public\n- * License along with this library; if not, write to the Free Software\n- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n- * MA 02110-1301 USA\n- */\n-\n-#include \u0022core/private.h\u0022\n-\n-#include \u003cfcntl.h\u003e\n-#include \u003cunistd.h\u003e\n-\n-static const char * const jwk_tok[] \u003d {\n-\t\u0022e\u0022, \u0022n\u0022, \u0022d\u0022, \u0022p\u0022, \u0022q\u0022, \u0022dp\u0022, \u0022dq\u0022, \u0022qi\u0022, \u0022kty\u0022, \u0022k\u0022,\n-};\n-\n-static int\n-_lws_jwk_set_element(struct lws_genrsa_element *e, char *in, int len)\n-{\n-\tint dec_size \u003d ((len * 3) / 4) + 4, n;\n-\n-\te-\u003ebuf \u003d lws_malloc(dec_size, \u0022jwk\u0022);\n-\tif (!e-\u003ebuf)\n-\t\treturn -1;\n-\n-\tn \u003d lws_b64_decode_string_len(in, len, (char *)e-\u003ebuf, dec_size - 1);\n-\tif (n \u003c 0)\n-\t\treturn -1;\n-\te-\u003elen \u003d n;\n-\n-\treturn 0;\n-}\n-\n-struct cb_lws_jwk {\n-\tstruct lws_jwk *s;\n-\tchar *b64;\n-\tint b64max;\n-\tint pos;\n-};\n-\n-static signed char\n-cb_jwk(struct lejp_ctx *ctx, char reason)\n-{\n-\tstruct cb_lws_jwk *cbs \u003d (struct cb_lws_jwk *)ctx-\u003euser;\n-\tstruct lws_jwk *s \u003d cbs-\u003es;\n-\tint idx;\n-\n-\tif (reason \u003d\u003d LEJPCB_VAL_STR_START)\n-\t\tcbs-\u003epos \u003d 0;\n-\n-\tif (!(reason \u0026 LEJP_FLAG_CB_IS_VALUE) || !ctx-\u003epath_match)\n-\t\treturn 0;\n-\n-\tswitch (ctx-\u003epath_match - 1) {\n-\tcase JWK_KTY:\n-\t\tlws_strncpy(s-\u003ekeytype, ctx-\u003ebuf, sizeof(s-\u003ekeytype));\n-\t\tif (!strcmp(ctx-\u003ebuf, \u0022oct\u0022)) {\n-\t\t\tbreak;\n-\t\t}\n-\t\tif (!strcmp(ctx-\u003ebuf, \u0022RSA\u0022)) {\n-\t\t\tbreak;\n-\t\t}\n-\t\treturn -1;\n-\n-\tcase JWK_KEY:\n-//\t\tif (strcmp(s-\u003ekeytype, \u0022oct\u0022))\n-//\t\t\treturn -1;\n-\t\tidx \u003d JWK_KEY_E;\n-\t\tgoto read_element1;\n-\n-\tcase JWK_KEY_N:\n-\tcase JWK_KEY_E:\n-\tcase JWK_KEY_D:\n-\tcase JWK_KEY_P:\n-\tcase JWK_KEY_Q:\n-\tcase JWK_KEY_DP:\n-\tcase JWK_KEY_DQ:\n-\tcase JWK_KEY_QI:\n-\t\tidx \u003d ctx-\u003epath_match - 1;\n-\t\tgoto read_element;\n-\t}\n-\n-\treturn 0;\n-\n-read_element:\n-/* kty is no longer first in lex order */\n-//\tif (strcmp(s-\u003ekeytype, \u0022RSA\u0022))\n-//\t\treturn -1;\n-\n-read_element1:\n-\n-\tif (cbs-\u003epos + ctx-\u003enpos \u003e\u003d cbs-\u003eb64max)\n-\t\treturn -1;\n-\n-\tmemcpy(cbs-\u003eb64 + cbs-\u003epos, ctx-\u003ebuf, ctx-\u003enpos);\n-\tcbs-\u003epos +\u003d ctx-\u003enpos;\n-\n-\tif (reason \u003d\u003d LEJPCB_VAL_STR_CHUNK)\n-\t\treturn 0;\n-\n-\tif (_lws_jwk_set_element(\u0026s-\u003eel.e[idx], cbs-\u003eb64, cbs-\u003epos) \u003c 0) {\n-\t\tlws_jwk_destroy_genrsa_elements(\u0026s-\u003eel);\n-\n-\t\treturn -1;\n-\t}\n-\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE int\n-lws_jwk_import(struct lws_jwk *s, const char *in, size_t len)\n-{\n-\tstruct lejp_ctx jctx;\n-\tstruct cb_lws_jwk cbs;\n-\tconst int b64max \u003d (((8192 / 8) * 4) / 3) + 1; /* enough for 8K key */\n-\tchar b64[b64max];\n-\tint m;\n-\n-\tmemset(s, 0, sizeof(*s));\n-\tcbs.s \u003d s;\n-\tcbs.b64 \u003d b64;\n-\tcbs.b64max \u003d b64max;\n-\tcbs.pos \u003d 0;\n-\tlejp_construct(\u0026jctx, cb_jwk, \u0026cbs, jwk_tok, LWS_ARRAY_SIZE(jwk_tok));\n-\tm \u003d (int)(signed char)lejp_parse(\u0026jctx, (uint8_t *)in, len);\n-\tlejp_destruct(\u0026jctx);\n-\n-\tif (m \u003c 0) {\n-\t\tlwsl_notice(\u0022%s: parse got %d\u005cn\u0022, __func__, m);\n-\n-\t\treturn -1;\n-\t}\n-\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE void\n-lws_jwk_destroy(struct lws_jwk *s)\n-{\n-\tlws_jwk_destroy_genrsa_elements(\u0026s-\u003eel);\n-}\n-\n-LWS_VISIBLE int\n-lws_jwk_export(struct lws_jwk *s, int private, char *p, size_t len)\n-{\n-\tchar *start \u003d p, *end \u003d \u0026p[len - 1];\n-\tint n, limit \u003d LWS_COUNT_RSA_ELEMENTS;\n-\n-\t/* RFC7638 lexicographic order requires\n-\t * RSA: e -\u003e kty -\u003e n\n-\t * oct: k -\u003e kty\n-\t */\n-\n-\tp +\u003d lws_snprintf(p, end - p, \u0022{\u0022);\n-\n-\tif (!strcmp(s-\u003ekeytype, \u0022oct\u0022)) {\n-\t\tif (!s-\u003eel.e[JWK_KEY_E].buf)\n-\t\t\treturn -1;\n-\n-\t\tp +\u003d lws_snprintf(p, end - p, \u0022\u005c\u0022k\u005c\u0022:\u005c\u0022\u0022);\n-\t\tn \u003d lws_jws_base64_enc((const char *)s-\u003eel.e[JWK_KEY_E].buf,\n-\t\t\t\t\t s-\u003eel.e[JWK_KEY_E].len, p,\n-\t\t\t\t\t end - p - 4);\n-\t\tif (n \u003c 0) {\n-\t\t\tlwsl_notice(\u0022%s: enc failed\u005cn\u0022, __func__);\n-\t\t\treturn -1;\n-\t\t}\n-\t\tp +\u003d n;\n-\n-\t\tp +\u003d lws_snprintf(p, end - p, \u0022\u005c\u0022,\u005c\u0022kty\u005c\u0022:\u005c\u0022%s\u005c\u0022}\u0022, s-\u003ekeytype);\n-\n-\t\treturn p - start;\n-\t}\n-\n-\tif (!strcmp(s-\u003ekeytype, \u0022RSA\u0022)) {\n-\t\tif (!s-\u003eel.e[JWK_KEY_E].buf ||\n-\t\t !s-\u003eel.e[JWK_KEY_N].buf ||\n-\t\t (private \u0026\u0026 (!s-\u003eel.e[JWK_KEY_D].buf ||\n-\t\t\t\t !s-\u003eel.e[JWK_KEY_P].buf ||\n-\t\t\t\t !s-\u003eel.e[JWK_KEY_Q].buf))\n-\t\t) {\n-\t\t\tlwsl_notice(\u0022%s: not enough elements filled\u005cn\u0022,\n-\t\t\t\t __func__);\n-\t\t\treturn -1;\n-\t\t}\n-\n-\t\tif (!private)\n-\t\t\tlimit \u003d JWK_KEY_N + 1;\n-\n-\t\tfor (n \u003d 0; n \u003c limit; n++) {\n-\t\t\tint m;\n-\n-\t\t\tif (!s-\u003eel.e[n].buf)\n-\t\t\t\tcontinue;\n-\t\t\tlwsl_info(\u0022%d: len %d\u005cn\u0022, n, s-\u003eel.e[n].len);\n-\n-\t\t\tif (n)\n-\t\t\t\tp +\u003d lws_snprintf(p, end - p, \u0022,\u0022);\n-\t\t\tp +\u003d lws_snprintf(p, end - p, \u0022\u005c\u0022%s\u005c\u0022:\u005c\u0022\u0022, jwk_tok[n]);\n-\t\t\tm \u003d lws_jws_base64_enc((const char *)s-\u003eel.e[n].buf,\n-\t\t\t\t\t\t s-\u003eel.e[n].len, p,\n-\t\t\t\t\t\t end - p - 4);\n-\t\t\tif (m \u003c 0) {\n-\t\t\t\tlwsl_notice(\u0022%s: enc fail inlen %d outlen %d\u005cn\u0022,\n-\t\t\t\t\t\t__func__, (int)s-\u003eel.e[n].len,\n-\t\t\t\t\t\tlws_ptr_diff(end, p) - 4);\n-\t\t\t\treturn -1;\n-\t\t\t}\n-\t\t\tp +\u003d m;\n-\t\t\t*p++ \u003d '\u005c\u0022';\n-\n-\t\t\tif (!n) /* RFC7638 lexicographic order */\n-\t\t\t\tp +\u003d lws_snprintf(p, end - p, \u0022,\u005c\u0022kty\u005c\u0022:\u005c\u0022%s\u005c\u0022\u0022,\n-\t\t\t\t\t\t s-\u003ekeytype);\n-\t\t}\n-\n-\t\tp +\u003d lws_snprintf(p, end - p, \u0022}\u0022);\n-\n-\t\treturn p - start;\n-\t}\n-\n-\tlwsl_err(\u0022%s: unknown key type %s\u005cn\u0022, __func__, s-\u003ekeytype);\n-\n-\treturn -1;\n-}\n-\n-LWS_VISIBLE int\n-lws_jwk_rfc7638_fingerprint(struct lws_jwk *s, char *digest32)\n-{\n-\tstruct lws_genhash_ctx hash_ctx;\n-\tint tmpsize \u003d 2536, n;\n-\tchar *tmp;\n-\n-\ttmp \u003d lws_malloc(tmpsize, \u0022rfc7638 tmp\u0022);\n-\n-\tn \u003d lws_jwk_export(s, 0, tmp, tmpsize);\n-\tif (n \u003c 0)\n-\t\tgoto bail;\n-\n-\tif (lws_genhash_init(\u0026hash_ctx, LWS_GENHASH_TYPE_SHA256))\n-\t\tgoto bail;\n-\n-\tif (lws_genhash_update(\u0026hash_ctx, tmp, n)) {\n-\t\tlws_genhash_destroy(\u0026hash_ctx, NULL);\n-\n-\t\tgoto bail;\n-\t}\n-\tlws_free(tmp);\n-\n-\tif (lws_genhash_destroy(\u0026hash_ctx, digest32))\n-\t\treturn -1;\n-\n-\treturn 0;\n-\n-bail:\n-\tlws_free(tmp);\n-\n-\treturn -1;\n-}\n-\n-LWS_VISIBLE int\n-lws_jwk_load(struct lws_jwk *s, const char *filename)\n-{\n-\tint buflen \u003d 4096;\n-\tchar *buf \u003d lws_malloc(buflen, \u0022jwk-load\u0022);\n-\tint n;\n-\n-\tif (!buf)\n-\t\treturn -1;\n-\n-\tn \u003d lws_plat_read_file(filename, buf, buflen);\n-\tif (n \u003c 0)\n-\t\tgoto bail;\n-\n-\tn \u003d lws_jwk_import(s, buf, n);\n-\tlws_free(buf);\n-\n-\treturn n;\n-bail:\n-\tlws_free(buf);\n-\n-\treturn -1;\n-}\n-\n-LWS_VISIBLE int\n-lws_jwk_save(struct lws_jwk *s, const char *filename)\n-{\n-\tint buflen \u003d 4096;\n-\tchar *buf \u003d lws_malloc(buflen, \u0022jwk-save\u0022);\n-\tint n, m;\n-\n-\tif (!buf)\n-\t\treturn -1;\n-\n-\tn \u003d lws_jwk_export(s, 1, buf, buflen);\n-\tif (n \u003c 0)\n-\t\tgoto bail;\n-\n-\tm \u003d lws_plat_write_file(filename, buf, n);\n-\n-\tlws_free(buf);\n-\tif (m)\n-\t\treturn -1;\n-\n-\treturn 0;\n-\n-bail:\n-\tlws_free(buf);\n-\n-\treturn -1;\n-}\ndiff --git a/lib/misc/jws/jws.c b/lib/misc/jws/jws.c\ndeleted file mode 100644\nindex ae68dc8..0000000\n--- a/lib/misc/jws/jws.c\n+++ /dev/null\n@@ -1,642 +0,0 @@\n-/*\n- * libwebsockets - JSON Web Signature support\n- *\n- * Copyright (C) 2017 Andy Green \u003candy@warmcat.com\u003e\n- *\n- * This library is free software; you can redistribute it and/or\n- * modify it under the terms of the GNU Lesser General Public\n- * License as published by the Free Software Foundation:\n- * version 2.1 of the License.\n- *\n- * This library is distributed in the hope that it will be useful,\n- * but WITHOUT ANY WARRANTY; without even the implied warranty of\n- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n- * Lesser General Public License for more details.\n- *\n- * You should have received a copy of the GNU Lesser General Public\n- * License along with this library; if not, write to the Free Software\n- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,\n- * MA 02110-1301 USA\n- */\n-\n-#include \u0022core/private.h\u0022\n-\n-/*\n- * JSON Web Signature is defined in RFC7515\n- *\n- * https://tools.ietf.org/html/rfc7515\n- *\n- * It's basically a way to wrap some JSON with a JSON \u0022header\u0022 describing the\n- * crypto, and a signature, all in a BASE64 wrapper with elided terminating '\u003d'.\n- *\n- * The signature stays with the content, it serves a different purpose than eg\n- * a TLS tunnel to transfer it.\n- *\n- * RFC7518 (JSON Web Algorithms) says for the \u0022alg\u0022 names\n- *\n- * | HS256 | HMAC using SHA-256 | Required |\n- * | HS384 | HMAC using SHA-384 | Optional |\n- * | HS512 | HMAC using SHA-512 | Optional |\n- * | RS256 | RSASSA-PKCS1-v1_5 using | Recommended |\n- * | RS384 | RSASSA-PKCS1-v1_5 using | Optional |\n- * | | SHA-384 | |\n- * | RS512 | RSASSA-PKCS1-v1_5 using | Optional |\n- * | | SHA-512 | |\n- * | ES256 | ECDSA using P-256 and SHA-256 | Recommended+ |\n- * | ES384 | ECDSA using P-384 and SHA-384 | Optional |\n- * | ES512 | ECDSA using P-521 and SHA-512 | Optional |\n- *\n- * Boulder (FOSS ACME provider) supports RS256, ES256, ES384 and ES512\n- * currently. The \u0022Recommended+\u0022 just means it is recommended but will likely\n- * be \u0022very recommended\u0022 soon.\n- *\n- * We support HS256/384/512 for symmetric crypto, but the choice for the\n- * asymmetric crypto isn't as easy to make.\n- *\n- * Normally you'd choose the EC option but these are defined to use the\n- * \u0022NIST curves\u0022 (RFC7518 3.4) which are believed to be insecure.\n- *\n- * https://safecurves.cr.yp.to/\n- *\n- * For that reason we implement RS256/384/512 for asymmetric.\n- */\n-\n-#if defined(LWS_WITH_SELFTESTS)\n-static const char\n-\t *test1\t\u003d \u0022{\u005c\u0022typ\u005c\u0022:\u005c\u0022JWT\u005c\u0022,\u005cr\u005cn \u005c\u0022alg\u005c\u0022:\u005c\u0022HS256\u005c\u0022}\u0022,\n-\t *test1_enc\t\u003d \u0022eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9\u0022,\n-\t *test2\t\u003d \u0022{\u005c\u0022iss\u005c\u0022:\u005c\u0022joe\u005c\u0022,\u005cr\u005cn \u005c\u0022exp\u005c\u0022:1300819380,\u005cr\u005cn\u0022\n-\t\t\t \u0022 \u005c\u0022http://example.com/is_root\u005c\u0022:true}\u0022,\n-\t *test2_enc\t\u003d \u0022eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQ\u0022\n-\t\t\t \u0022ogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ\u0022,\n-\t *key_jwk\t\u003d \u0022{\u005c\u0022kty\u005c\u0022:\u005c\u0022oct\u005c\u0022,\u005cr\u005cn\u0022\n-\t\t\t \u0022 \u005c\u0022k\u005c\u0022:\u005c\u0022AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQ\u0022\n-\t\t\t \u0022Lr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow\u005c\u0022}\u0022,\n-\t *hash_enc\t\u003d \u0022dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk\u0022,\n-\t /* the key from worked example in RFC7515 A-1, as a JWK */\n-\t *rfc7515_rsa_key \u003d\n-\t\u0022{\u005c\u0022kty\u005c\u0022:\u005c\u0022RSA\u005c\u0022,\u0022\n-\t\u0022 \u005c\u0022n\u005c\u0022:\u005c\u0022ofgWCuLjybRlzo0tZWJjNiuSfb4p4fAkd_wWJcyQoTbji9k0l8W26mPddx\u0022\n-\t \u0022HmfHQp-Vaw-4qPCJrcS2mJPMEzP1Pt0Bm4d4QlL-yRT-SFd2lZS-pCgNMs\u0022\n-\t \u0022D1W_YpRPEwOWvG6b32690r2jZ47soMZo9wGzjb_7OMg0LOL-bSf63kpaSH\u0022\n-\t \u0022SXndS5z5rexMdbBYUsLA9e-KXBdQOS-UTo7WTBEMa2R2CapHg665xsmtdV\u0022\n-\t \u0022MTBQY4uDZlxvb3qCo5ZwKh9kG4LT6_I5IhlJH7aGhyxXFvUK-DWNmoudF8\u0022\n-\t \u0022NAco9_h9iaGNj8q2ethFkMLs91kzk2PAcDTW9gb54h4FRWyuXpoQ\u005c\u0022,\u0022\n-\t\u0022\u005c\u0022e\u005c\u0022:\u005c\u0022AQAB\u005c\u0022,\u0022\n-\t\u0022\u005c\u0022d\u005c\u0022:\u005c\u0022Eq5xpGnNCivDflJsRQBXHx1hdR1k6Ulwe2JZD50LpXyWPEAeP88vLNO97I\u0022\n-\t \u0022jlA7_GQ5sLKMgvfTeXZx9SE-7YwVol2NXOoAJe46sui395IW_GO-pWJ1O0\u0022\n-\t \u0022BkTGoVEn2bKVRUCgu-GjBVaYLU6f3l9kJfFNS3E0QbVdxzubSu3Mkqzjkn\u0022\n-\t \u0022439X0M_V51gfpRLI9JYanrC4D4qAdGcopV_0ZHHzQlBjudU2QvXt4ehNYT\u0022\n-\t \u0022CBr6XCLQUShb1juUO1ZdiYoFaFQT5Tw8bGUl_x_jTj3ccPDVZFD9pIuhLh\u0022\n-\t \u0022BOneufuBiB4cS98l2SR_RQyGWSeWjnczT0QU91p1DhOVRuOopznQ\u005c\u0022,\u0022\n-\t\u0022\u005c\u0022p\u005c\u0022:\u005c\u00224BzEEOtIpmVdVEZNCqS7baC4crd0pqnRH_5IB3jw3bcxGn6QLvnEtfdUdi\u0022\n-\t \u0022YrqBdss1l58BQ3KhooKeQTa9AB0Hw_Py5PJdTJNPY8cQn7ouZ2KKDcmnPG\u0022\n-\t \u0022BY5t7yLc1QlQ5xHdwW1VhvKn-nXqhJTBgIPgtldC-KDV5z-y2XDwGUc\u005c\u0022,\u0022\n-\t\u0022\u005c\u0022q\u005c\u0022:\u005c\u0022uQPEfgmVtjL0Uyyx88GZFF1fOunH3-7cepKmtH4pxhtCoHqpWmT8YAmZxa\u0022\n-\t \u0022ewHgHAjLYsp1ZSe7zFYHj7C6ul7TjeLQeZD_YwD66t62wDmpe_HlB-TnBA\u0022\n-\t \u0022-njbglfIsRLtXlnDzQkv5dTltRJ11BKBBypeeF6689rjcJIDEz9RWdc\u005c\u0022,\u0022\n-\t\u0022\u005c\u0022dp\u005c\u0022:\u005c\u0022BwKfV3Akq5_MFZDFZCnW-wzl-CCo83WoZvnLQwCTeDv8uzluRSnm71I3Q\u0022\n-\t \u0022CLdhrqE2e9YkxvuxdBfpT_PI7Yz-FOKnu1R6HsJeDCjn12Sk3vmAktV2zb\u0022\n-\t \u002234MCdy7cpdTh_YVr7tss2u6vneTwrA86rZtu5Mbr1C1XsmvkxHQAdYo0\u005c\u0022,\u0022\n-\t\u0022\u005c\u0022dq\u005c\u0022:\u005c\u0022h_96-mK1R_7glhsum81dZxjTnYynPbZpHziZjeeHcXYsXaaMwkOlODsWa\u0022\n-\t \u00227I9xXDoRwbKgB719rrmI2oKr6N3Do9U0ajaHF-NKJnwgjMd2w9cjz3_-ky\u0022\n-\t \u0022NlxAr2v4IKhGNpmM5iIgOS1VZnOZ68m6_pbLBSp3nssTdlqvd0tIiTHU\u005c\u0022,\u0022\n-\t\u0022\u005c\u0022qi\u005c\u0022:\u005c\u0022IYd7DHOhrWvxkwPQsRM2tOgrjbcrfvtQJipd-DlcxyVuuM9sQLdgjVk2o\u0022\n-\t \u0022y26F0EmpScGLq2MowX7fhd_QJQ3ydy5cY7YIBi87w93IKLEdfnbJtoOPLU\u0022\n-\t \u0022W0ITrJReOgo1cq9SbsxYawBgfp_gh6A5603k2-ZQwVK0JKSHuLFkuQ3U\u005c\u0022\u0022\n-\t\u0022}\u0022,\n-\t *rfc7515_rsa_a1 \u003d /* the signed worked example in RFC7515 A-1 */\n-\t \u0022eyJhbGciOiJSUzI1NiJ9\u0022\n-\t \u0022.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt\u0022\n-\t \u0022cGxlLmNvbS9pc19yb290Ijp0cnVlfQ\u0022\n-\t \u0022.cC4hiUPoj9Eetdgtv3hF80EGrhuB__dzERat0XF9g2VtQgr9PJbu3XOiZj5RZmh7\u0022\n-\t \u0022AAuHIm4Bh-0Qc_lF5YKt_O8W2Fp5jujGbds9uJdbF9CUAr7t1dnZcAcQjbKBYNX4\u0022\n-\t \u0022BAynRFdiuB--f_nZLgrnbyTyWzO75vRK5h6xBArLIARNPvkSjtQBMHlb1L07Qe7K\u0022\n-\t \u00220GarZRmB_eSN9383LcOLn6_dO--xi12jzDwusC-eOkHWEsqtFZESc6BfI7noOPqv\u0022\n-\t \u0022hJ1phCnvWh6IeYI2w9QOYEUipUTI8np6LbgGY9Fs98rqVt5AXLIhWkWywlVmtVrB\u0022\n-\t \u0022p0igcN_IoypGlUPQGe77Rw\u0022;\n-#endif\n-\n-LWS_VISIBLE int\n-lws_jws_base64_enc(const char *in, size_t in_len, char *out, size_t out_max)\n-{\n-\tint n;\n-\n-\tn \u003d lws_b64_encode_string_url(in, in_len, out, out_max - 1);\n-\tif (n \u003c 0)\n-\t\treturn n; /* too large for output buffer */\n-\n-\t/* trim the terminal \u003d */\n-\twhile (n \u0026\u0026 out[n - 1] \u003d\u003d '\u003d')\n-\t\tn--;\n-\n-\tout[n] \u003d '\u005c0';\n-\n-\treturn n;\n-}\n-\n-LWS_VISIBLE int\n-lws_jws_encode_section(const char *in, size_t in_len, int first, char **p,\n-\t\t char *end)\n-{\n-\tint n, len \u003d (end - *p) - 1;\n-\tchar *p_entry \u003d *p;\n-\n-\tif (len \u003c 3)\n-\t\treturn -1;\n-\n-\tif (!first)\n-\t\t*(*p)++ \u003d '.';\n-\n-\tn \u003d lws_jws_base64_enc(in, in_len, *p, len - 1);\n-\tif (n \u003c 0)\n-\t\treturn -1;\n-\n-\t*p +\u003d n;\n-\n-\treturn (*p) - p_entry;\n-}\n-\n-static int\n-lws_jws_find_sig(const char *in, size_t len)\n-{\n-\tconst char *p \u003d in + len - 1;\n-\n-\twhile (len--)\n-\t\tif (*p \u003d\u003d '.')\n-\t\t\treturn (p + 1) - in;\n-\t\telse\n-\t\t\tp--;\n-\n-\tlwsl_notice(\u0022%s failed\u005cn\u0022, __func__);\n-\treturn -1;\n-}\n-\n-\n-static const char * const jhdr_tok[] \u003d {\n-\t\u0022typ\u0022,\n-\t\u0022alg\u0022,\n-};\n-enum enum_jhdr_tok {\n-\tJHP_TYP,\n-\tJHP_ALG\n-};\n-struct cb_hdr_s {\n-\tenum lws_genhash_types hash_type;\n-\tenum lws_genhmac_types hmac_type;\n-\tchar alg[10];\n-\tint is_rsa:1;\n-};\n-\n-static signed char\n-cb_hdr(struct lejp_ctx *ctx, char reason)\n-{\n-\tstruct cb_hdr_s *s \u003d (struct cb_hdr_s *)ctx-\u003euser;\n-\n-\tif (!(reason \u0026 LEJP_FLAG_CB_IS_VALUE) || !ctx-\u003epath_match)\n-\t\treturn 0;\n-\n-\tswitch (ctx-\u003epath_match - 1) {\n-\tcase JHP_TYP: /* it is optional */\n-\t\tif (strcmp(ctx-\u003ebuf, \u0022JWT\u0022))\n-\t\t\treturn -1;\n-\t\tbreak;\n-\tcase JHP_ALG:\n-\t\tlws_strncpy(s-\u003ealg, ctx-\u003ebuf, sizeof(s-\u003ealg));\n-\t\tif (!strcmp(ctx-\u003ebuf, \u0022HS256\u0022)) {\n-\t\t\ts-\u003ehmac_type \u003d LWS_GENHMAC_TYPE_SHA256;\n-\t\t\tbreak;\n-\t\t}\n-\t\tif (!strcmp(ctx-\u003ebuf, \u0022HS384\u0022)) {\n-\t\t\ts-\u003ehmac_type \u003d LWS_GENHMAC_TYPE_SHA384;\n-\t\t\tbreak;\n-\t\t}\n-\t\tif (!strcmp(ctx-\u003ebuf, \u0022HS512\u0022)) {\n-\t\t\ts-\u003ehmac_type \u003d LWS_GENHMAC_TYPE_SHA512;\n-\t\t\tbreak;\n-\t\t}\n-\t\tif (!strcmp(ctx-\u003ebuf, \u0022RS256\u0022)) {\n-\t\t\ts-\u003ehash_type \u003d LWS_GENHASH_TYPE_SHA256;\n-\t\t\ts-\u003eis_rsa \u003d 1;\n-\t\t\tbreak;\n-\t\t}\n-\t\tif (!strcmp(ctx-\u003ebuf, \u0022RS384\u0022)) {\n-\t\t\ts-\u003ehash_type \u003d LWS_GENHASH_TYPE_SHA384;\n-\t\t\ts-\u003eis_rsa \u003d 1;\n-\t\t\tbreak;\n-\t\t}\n-\t\tif (!strcmp(ctx-\u003ebuf, \u0022RS512\u0022)) {\n-\t\t\ts-\u003ehash_type \u003d LWS_GENHASH_TYPE_SHA512;\n-\t\t\ts-\u003eis_rsa \u003d 1;\n-\t\t\tbreak;\n-\t\t}\n-\t\treturn -1;\n-\t}\n-\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE int\n-lws_jws_confirm_sig(const char *in, size_t len, struct lws_jwk *jwk)\n-{\n-\tint sig_pos \u003d lws_jws_find_sig(in, len), pos \u003d 0, n, m, h_len;\n-\tuint8_t digest[LWS_GENHASH_LARGEST];\n-\tstruct lws_genhash_ctx hash_ctx;\n-\tstruct lws_genrsa_ctx rsactx;\n-\tstruct lws_genhmac_ctx ctx;\n-\tstruct cb_hdr_s args;\n-\tstruct lejp_ctx jctx;\n-\tchar buf[2048];\n-\n-\t/* 1) there has to be a signature */\n-\n-\tif (sig_pos \u003c 0)\n-\t\treturn -1;\n-\n-\t/* 2) find length of first, hdr, block */\n-\n-\twhile (pos \u003c (int)len \u0026\u0026 in[pos] !\u003d '.')\n-\t\tpos++;\n-\tif (pos \u003d\u003d (int)len)\n-\t\treturn -1;\n-\n-\t/* 3) Decode the header block */\n-\n-\tn \u003d lws_b64_decode_string_len(in, pos, buf, sizeof(buf) - 1);\n-\tif (n \u003c 0)\n-\t\treturn -1;\n-\n-\t/* 4) Require either:\n-\t * typ: JWT (if present) and alg: HS256/384/512\n-\t * typ: JWT (if present) and alg: RS256/384/512\n-\t */\n-\n-\targs.alg[0] \u003d '\u005c0';\n-\targs.is_rsa \u003d 0;\n-\tlejp_construct(\u0026jctx, cb_hdr, \u0026args, jhdr_tok, LWS_ARRAY_SIZE(jhdr_tok));\n-\tm \u003d (int)(signed char)lejp_parse(\u0026jctx, (uint8_t *)buf, n);\n-\tlejp_destruct(\u0026jctx);\n-\tif (m \u003c 0) {\n-\t\tlwsl_notice(\u0022parse got %d: alg %s\u005cn\u0022, m, args.alg);\n-\t\treturn -1;\n-\t}\n-\n-\t/* 5) decode the B64URL signature part into buf / m */\n-\n-\tm \u003d lws_b64_decode_string_len(in + sig_pos, len - sig_pos,\n-\t\t\t\t buf, sizeof(buf) - 1);\n-\n-\tif (args.is_rsa) {\n-\n-\t\t/* RSASSA-PKCS1-v1_5 using SHA-256/384/512 */\n-\n-\t\t/* 6(RSA): compute the hash of the payload into \u0022digest\u0022 */\n-\n-\t\tif (lws_genhash_init(\u0026hash_ctx, args.hash_type))\n-\t\t\treturn -1;\n-\n-\t\tif (lws_genhash_update(\u0026hash_ctx, (uint8_t *)in, sig_pos - 1)) {\n-\t\t\tlws_genhash_destroy(\u0026hash_ctx, NULL);\n-\n-\t\t\treturn -1;\n-\t\t}\n-\t\tif (lws_genhash_destroy(\u0026hash_ctx, digest))\n-\t\t\treturn -1;\n-\n-\t\th_len \u003d lws_genhash_size(args.hash_type);\n-\n-\t\tif (lws_genrsa_create(\u0026rsactx, \u0026jwk-\u003eel)) {\n-\t\t\tlwsl_notice(\u0022%s: lws_genrsa_public_decrypt_create\u005cn\u0022,\n-\t\t\t\t __func__);\n-\t\t\treturn -1;\n-\t\t}\n-\n-\t\tn \u003d lws_genrsa_public_verify(\u0026rsactx, digest, args.hash_type,\n-\t\t\t\t\t (uint8_t *)buf, m);\n-\n-\t\tlws_genrsa_destroy(\u0026rsactx);\n-\t\tif (n \u003c 0) {\n-\t\t\tlwsl_notice(\u0022decrypt fail\u005cn\u0022);\n-\t\t\treturn -1;\n-\t\t}\n-\n-\t\treturn 0;\n-\t}\n-\n-\t/* SHA256/384/512 HMAC */\n-\n-\th_len \u003d lws_genhmac_size(args.hmac_type);\n-\tif (m \u003c 0 || m !\u003d h_len)\n-\t\treturn -1;\n-\n-\t/* 6) compute HMAC over payload */\n-\n-\tif (lws_genhmac_init(\u0026ctx, args.hmac_type, jwk-\u003eel.e[JWK_KEY_E].buf,\n-\t\t\t jwk-\u003eel.e[JWK_KEY_E].len))\n-\t\treturn -1;\n-\n-\tif (lws_genhmac_update(\u0026ctx, (uint8_t *)in, sig_pos - 1)) {\n-\t\tlws_genhmac_destroy(\u0026ctx, NULL);\n-\n-\t\treturn -1;\n-\t}\n-\tif (lws_genhmac_destroy(\u0026ctx, digest))\n-\t\treturn -1;\n-\n-\t/* 7) Compare the computed and decoded hashes */\n-\n-\tif (memcmp(digest, buf, h_len)) {\n-\t\tlwsl_notice(\u0022digest mismatch\u005cn\u0022);\n-\n-\t\treturn -1;\n-\t}\n-\n-\treturn 0;\n-}\n-\n-LWS_VISIBLE int\n-lws_jws_sign_from_b64(const char *b64_hdr, size_t hdr_len, const char *b64_pay,\n-\t\t size_t pay_len, char *b64_sig, size_t sig_len,\n-\t\t enum lws_genhash_types hash_type, struct lws_jwk *jwk)\n-{\n-\tuint8_t digest[LWS_GENHASH_LARGEST];\n-\tstruct lws_genhash_ctx hash_ctx;\n-\tstruct lws_genrsa_ctx rsactx;\n-\tuint8_t *buf;\n-\tint n;\n-\n-\tif (lws_genhash_init(\u0026hash_ctx, hash_type))\n-\t\treturn -1;\n-\n-\tif (b64_hdr) {\n-\t\tif (lws_genhash_update(\u0026hash_ctx, (uint8_t *)b64_hdr, hdr_len))\n-\t\t\tgoto hash_fail;\n-\t\tif (lws_genhash_update(\u0026hash_ctx, (uint8_t *)\u0022.\u0022, 1))\n-\t\t\tgoto hash_fail;\n-\t}\n-\tif (lws_genhash_update(\u0026hash_ctx, (uint8_t *)b64_pay, pay_len))\n-\t\tgoto hash_fail;\n-\n-\tif (lws_genhash_destroy(\u0026hash_ctx, digest))\n-\t\treturn -1;\n-\n-\tif (!strcmp(jwk-\u003ekeytype, \u0022RSA\u0022)) {\n-\t\tif (lws_genrsa_create(\u0026rsactx, \u0026jwk-\u003eel)) {\n-\t\t\tlwsl_notice(\u0022%s: lws_genrsa_public_decrypt_create\u005cn\u0022,\n-\t\t\t\t __func__);\n-\t\t\treturn -1;\n-\t\t}\n-\n-\t\tn \u003d jwk-\u003eel.e[JWK_KEY_N].len;\n-\t\tbuf \u003d lws_malloc(n, \u0022jws sign\u0022);\n-\t\tif (!buf)\n-\t\t\treturn -1;\n-\n-\t\tn \u003d lws_genrsa_public_sign(\u0026rsactx, digest, hash_type, buf, n);\n-\t\tlws_genrsa_destroy(\u0026rsactx);\n-\t\tif (n \u003c 0) {\n-\t\t\tlws_free(buf);\n-\n-\t\t\treturn -1;\n-\t\t}\n-\n-\t\tn \u003d lws_jws_base64_enc((char *)buf, n, b64_sig, sig_len);\n-\t\tlws_free(buf);\n-\n-\t\treturn n;\n-\t}\n-\n-\tif (!strcmp(jwk-\u003ekeytype, \u0022oct\u0022))\n-\t\treturn lws_jws_base64_enc((char *)digest,\n-\t\t\t\t\t lws_genhash_size(hash_type),\n-\t\t\t\t\t b64_sig, sig_len);\n-\n-\t/* unknown key type */\n-\n-\treturn -1;\n-\n-hash_fail:\n-\tlws_genhash_destroy(\u0026hash_ctx, NULL);\n-\treturn -1;\n-}\n-\n-LWS_VISIBLE int\n-lws_jws_create_packet(struct lws_jwk *jwk, const char *payload, size_t len,\n-\t\t const char *nonce, char *out, size_t out_len)\n-{\n-\tchar *buf, *start, *p, *end, *p1, *end1, *b64_hdr, *b64_pay;\n-\tint n, b64_hdr_len, b64_pay_len;\n-\n-\t/*\n-\t * This buffer is local to the function, the actual output\n-\t * is prepared into vhd-\u003ebuf. Only the plaintext protected header\n-\t * (which contains the public key, 512 bytes for 4096b) goes in\n-\t * here temporarily.\n-\t */\n-\tn \u003d LWS_PRE + 2048;\n-\tbuf \u003d malloc(n);\n-\tif (!buf) {\n-\t\tlwsl_notice(\u0022%s: malloc %d failed\u005cn\u0022, __func__, n);\n-\t\treturn -1;\n-\t}\n-\n-\tp \u003d start \u003d buf + LWS_PRE;\n-\tend \u003d buf + n - LWS_PRE - 1;\n-\n-\t/*\n-\t * temporary JWS protected header plaintext\n-\t */\n-\n-\tp +\u003d lws_snprintf(p, end - p, \u0022{\u005c\u0022alg\u005c\u0022:\u005c\u0022RS256\u005c\u0022,\u005c\u0022jwk\u005c\u0022:\u0022);\n-\tn \u003d lws_jwk_export(jwk, 0, p, end - p);\n-\tif (n \u003c 0) {\n-\t\tlwsl_notice(\u0022failed to export jwk\u005cn\u0022);\n-\n-\t\tgoto bail;\n-\t}\n-\tp +\u003d n;\n-\tp +\u003d lws_snprintf(p, end - p, \u0022,\u005c\u0022nonce\u005c\u0022:\u005c\u0022%s\u005c\u0022}\u0022, nonce);\n-\n-\t/*\n-\t * prepare the signed outer JSON with all the parts in\n-\t */\n-\n-\tp1 \u003d out;\n-\tend1 \u003d out + out_len - 1;\n-\n-\tp1 +\u003d lws_snprintf(p1, end1 - p1, \u0022{\u005c\u0022protected\u005c\u0022:\u005c\u0022\u0022);\n-\tb64_hdr \u003d p1;\n-\tn \u003d lws_jws_base64_enc(start, p - start, p1, end1 - p1);\n-\tif (n \u003c 0) {\n-\t\tlwsl_notice(\u0022%s: failed to encode protected\u005cn\u0022, __func__);\n-\t\tgoto bail;\n-\t}\n-\tb64_hdr_len \u003d n;\n-\tp1 +\u003d n;\n-\n-\tp1 +\u003d lws_snprintf(p1, end1 - p1, \u0022\u005c\u0022,\u005c\u0022payload\u005c\u0022:\u005c\u0022\u0022);\n-\tb64_pay \u003d p1;\n-\tn \u003d lws_jws_base64_enc(payload, len, p1, end1 - p1);\n-\tif (n \u003c 0) {\n-\t\tlwsl_notice(\u0022%s: failed to encode payload\u005cn\u0022, __func__);\n-\t\tgoto bail;\n-\t}\n-\tb64_pay_len \u003d n;\n-\n-\tp1 +\u003d n;\n-\tp1 +\u003d lws_snprintf(p1, end1 - p1, \u0022\u005c\u0022,\u005c\u0022signature\u005c\u0022:\u005c\u0022\u0022);\n-\n-\t/*\n-\t * taking the b64 protected header and the b64 payload, sign them\n-\t * and place the signature into the packet\n-\t */\n-\tn \u003d lws_jws_sign_from_b64(b64_hdr, b64_hdr_len, b64_pay, b64_pay_len,\n-\t\t\t\t p1, end1 - p1, LWS_GENHASH_TYPE_SHA256, jwk);\n-\tif (n \u003c 0) {\n-\t\tlwsl_notice(\u0022sig gen failed\u005cn\u0022);\n-\n-\t\tgoto bail;\n-\t}\n-\tp1 +\u003d n;\n-\tp1 +\u003d lws_snprintf(p1, end1 - p1, \u0022\u005c\u0022}\u0022);\n-\n-\tfree(buf);\n-\n-\treturn p1 - out;\n-\n-bail:\n-\tfree(buf);\n-\n-\treturn -1;\n-}\n-\n-\n-#if defined(LWS_WITH_SELFTESTS)\n-/*\n- * These are the inputs and outputs from the worked example in RFC7515\n- * Appendix A.1.\n- *\n- * 1) has a fixed header + payload, and a fixed SHA256 HMAC key, and must give\n- * a fixed BASE64URL result.\n- *\n- * 2) has a fixed header + payload and is signed with a key given in JWK format\n- */\n-int\n-lws_jws_selftest(void)\n-{\n-\tstruct lws_genhmac_ctx ctx;\n-\tstruct lws_jwk jwk;\n-\tchar buf[2048], *p \u003d buf, *end \u003d buf + sizeof(buf) - 1, *enc_ptr, *p1;\n-\tuint8_t digest[LWS_GENHASH_LARGEST];\n-\tint n;\n-\n-\t/* Test 1: SHA256 on RFC7515 worked example */\n-\n-\t/* 1.1: decode the JWK oct key */\n-\n-\tif (lws_jwk_import(\u0026jwk, key_jwk, strlen(key_jwk)) \u003c 0) {\n-\t\tlwsl_notice(\u0022Failed to decode JWK test key\u005cn\u0022);\n-\t\treturn -1;\n-\t}\n-\n-\t/* 1.2: create JWS known hdr + known payload */\n-\n-\tn \u003d lws_jws_encode_section(test1, strlen(test1), 1, \u0026p, end);\n-\tif (n \u003c 0)\n-\t\tgoto bail;\n-\tif (strcmp(buf, test1_enc))\n-\t\tgoto bail;\n-\n-\tenc_ptr \u003d p + 1; /* + 1 skips the . */\n-\tn \u003d lws_jws_encode_section(test2, strlen(test2), 0, \u0026p, end);\n-\tif (n \u003c 0)\n-\t\tgoto bail;\n-\tif (strcmp(enc_ptr, test2_enc))\n-\t\tgoto bail;\n-\n-\t/* 1.3: use HMAC SHA-256 with known key on the hdr . payload */\n-\n-\tif (lws_genhmac_init(\u0026ctx, LWS_GENHMAC_TYPE_SHA256,\n-\t\t\t jwk.el.e[JWK_KEY_E].buf, jwk.el.e[JWK_KEY_E].len))\n-\t\tgoto bail;\n-\tif (lws_genhmac_update(\u0026ctx, (uint8_t *)buf, p - buf))\n-\t\tgoto bail_destroy_hmac;\n-\tlws_genhmac_destroy(\u0026ctx, digest);\n-\n-\t/* 1.4: append a base64 encode of the computed HMAC digest */\n-\n-\tenc_ptr \u003d p + 1; /* + 1 skips the . */\n-\tn \u003d lws_jws_encode_section((const char *)digest, 32, 0, \u0026p, end);\n-\tif (n \u003c 0)\n-\t\tgoto bail;\n-\tif (strcmp(enc_ptr, hash_enc)) /* check against known B64URL hash */\n-\t\tgoto bail;\n-\n-\t/* 1.5: Check we can agree the signature matches the payload */\n-\n-\tif (lws_jws_confirm_sig(buf, p - buf, \u0026jwk) \u003c 0) {\n-\t\tlwsl_notice(\u0022confirm sig failed\u005cn\u0022);\n-\t\tgoto bail;\n-\t}\n-\n-\tlws_jwk_destroy(\u0026jwk); /* finished with the key from the first test */\n-\n-\t/* Test 2: RSA256 on RFC7515 worked example */\n-\n-\t/* 2.1: turn the known JWK key for the RSA test into a lws_jwk */\n-\n-\tif (lws_jwk_import(\u0026jwk, rfc7515_rsa_key, strlen(rfc7515_rsa_key))) {\n-\t\tlwsl_notice(\u0022Failed to read JWK key\u005cn\u0022);\n-\t\tgoto bail2;\n-\t}\n-\n-\t/* 2.2: check the signature on the test packet from RFC7515 A-1 */\n-\n-\tif (lws_jws_confirm_sig(rfc7515_rsa_a1, strlen(rfc7515_rsa_a1),\n-\t\t\t\t\u0026jwk) \u003c 0) {\n-\t\tlwsl_notice(\u0022confirm rsa sig failed\u005cn\u0022);\n-\t\tgoto bail;\n-\t}\n-\n-\t/* 2.3: generate our own signature for a copy of the test packet */\n-\n-\tmemcpy(buf, rfc7515_rsa_a1, strlen(rfc7515_rsa_a1));\n-\n-\t/* set p to second . */\n-\tp \u003d strchr(buf + 1, '.');\n-\tp1 \u003d strchr(p + 1, '.');\n-\n-\tn \u003d lws_jws_sign_from_b64(buf, p - buf, p + 1, p1 - (p + 1),\n-\t\t\t\t p1 + 1, sizeof(buf) - (p1 - buf) - 1,\n-\t\t\t\t LWS_GENHASH_TYPE_SHA256, \u0026jwk);\n-\tif (n \u003c 0)\n-\t\tgoto bail;\n-\n-\tputs(buf);\n-\n-\t/* 2.4: confirm our signature can be verified */\n-\n-\tif (lws_jws_confirm_sig(buf, (p1 + 1 + n) - buf, \u0026jwk) \u003c 0) {\n-\t\tlwsl_notice(\u0022confirm rsa sig 2 failed\u005cn\u0022);\n-\t\tgoto bail;\n-\t}\n-\n-\tlws_jwk_destroy(\u0026jwk);\n-\n-\t/* end */\n-\n-\tlwsl_notice(\u0022%s: selftest OK\u005cn\u0022, __func__);\n-\n-\treturn 0;\n-\n-bail_destroy_hmac:\n-\tlws_genhmac_destroy(\u0026ctx, NULL);\n-\n-bail:\n-\tlws_jwk_destroy(\u0026jwk);\n-bail2:\n-\tlwsl_err(\u0022%s: selftest failed ++++++++++++++++++++\u005cn\u0022, __func__);\n-\n-\treturn 1;\n-}\n-#endif\ndiff --git a/lib/tls/mbedtls/lws-genec.c b/lib/tls/mbedtls/lws-genec.c\nnew file mode 100644\nindex 0000000..e69de29\n--- /dev/null\n+++ b/lib/tls/mbedtls/lws-genec.c\ndiff --git a/lib/tls/mbedtls/lws-genrsa.c b/lib/tls/mbedtls/lws-genrsa.c\nindex 99b2e75..937ed69 100644\n--- a/lib/tls/mbedtls/lws-genrsa.c\n+++ b/lib/tls/mbedtls/lws-genrsa.c\n@@ -1,7 +1,7 @@\n /*\n * libwebsockets - generic RSA api hiding the backend\n *\n- * Copyright (C) 2017 Andy Green \u003candy@warmcat.com\u003e\n+ * Copyright (C) 2017 - 2018 Andy Green \u003candy@warmcat.com\u003e\n *\n * This library is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n@@ -22,40 +22,39 @@\n * same whether you are using openssl or mbedtls hash functions underneath.\n */\n #include \u0022core/private.h\u0022\n+#include \u0022../../jose/private.h\u0022\n \n LWS_VISIBLE void\n-lws_jwk_destroy_genrsa_elements(struct lws_genrsa_elements *el)\n+lws_jwk_destroy_genrsa_elements(struct lws_jwk_elements *el)\n {\n-\tint n;\n-\n-\tfor (n \u003d 0; n \u003c LWS_COUNT_RSA_ELEMENTS; n++)\n-\t\tif (el-\u003ee[n].buf)\n-\t\t\tlws_free_set_NULL(el-\u003ee[n].buf);\n+\tlws_jwk_destroy_elements(el, LWS_COUNT_RSA_KEY_ELEMENTS);\n }\n \n LWS_VISIBLE int\n-lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_genrsa_elements *el)\n+lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_jwk_elements *el,\n+\t\t struct lws_context *context)\n {\n \tmemset(ctx, 0, sizeof(*ctx));\n \tctx-\u003ectx \u003d lws_zalloc(sizeof(*ctx-\u003ectx), \u0022genrsa\u0022);\n \tif (!ctx-\u003ectx)\n \t\treturn 1;\n \n+\tctx-\u003econtext \u003d context;\n \tmbedtls_rsa_init(ctx-\u003ectx, MBEDTLS_RSA_PKCS_V15, 0);\n \n \t{\n \t\tint n;\n \n-\t\tmbedtls_mpi *mpi[LWS_COUNT_RSA_ELEMENTS] \u003d {\n+\t\tmbedtls_mpi *mpi[LWS_COUNT_RSA_KEY_ELEMENTS] \u003d {\n \t\t\t\u0026ctx-\u003ectx-\u003eE, \u0026ctx-\u003ectx-\u003eN, \u0026ctx-\u003ectx-\u003eD, \u0026ctx-\u003ectx-\u003eP,\n \t\t\t\u0026ctx-\u003ectx-\u003eQ, \u0026ctx-\u003ectx-\u003eDP, \u0026ctx-\u003ectx-\u003eDQ,\n \t\t\t\u0026ctx-\u003ectx-\u003eQP,\n \t\t};\n \n-\t\tfor (n \u003d 0; n \u003c LWS_COUNT_RSA_ELEMENTS; n++)\n-\t\t\tif (el-\u003ee[n].buf \u0026\u0026\n-\t\t\t mbedtls_mpi_read_binary(mpi[n], el-\u003ee[n].buf,\n-\t\t\t\t\t \t el-\u003ee[n].len)) {\n+\t\tfor (n \u003d 0; n \u003c LWS_COUNT_RSA_KEY_ELEMENTS; n++)\n+\t\t\tif (el[n].buf \u0026\u0026\n+\t\t\t mbedtls_mpi_read_binary(mpi[n], el[n].buf,\n+\t\t\t\t\t \t el[n].len)) {\n \t\t\t\tlwsl_notice(\u0022mpi load failed\u005cn\u0022);\n \t\t\t\tlws_free_set_NULL(ctx-\u003ectx);\n \n@@ -63,7 +62,7 @@ lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_genrsa_elements *el)\n \t\t\t}\n \t}\n \n-\tctx-\u003ectx-\u003elen \u003d el-\u003ee[JWK_KEY_N].len;\n+\tctx-\u003ectx-\u003elen \u003d el[JWK_RSA_KEYEL_N].len;\n \n \treturn 0;\n }\n@@ -79,7 +78,7 @@ _rngf(void *context, unsigned char *buf, size_t len)\n \n LWS_VISIBLE int\n lws_genrsa_new_keypair(struct lws_context *context, struct lws_genrsa_ctx *ctx,\n-\t\t struct lws_genrsa_elements *el, int bits)\n+\t\t struct lws_jwk_elements *el, int bits)\n {\n \tint n;\n \n@@ -97,30 +96,30 @@ lws_genrsa_new_keypair(struct lws_context *context, struct lws_genrsa_ctx *ctx,\n \t}\n \n \t{\n-\t\tmbedtls_mpi *mpi[LWS_COUNT_RSA_ELEMENTS] \u003d {\n+\t\tmbedtls_mpi *mpi[LWS_COUNT_RSA_KEY_ELEMENTS] \u003d {\n \t\t\t\u0026ctx-\u003ectx-\u003eE, \u0026ctx-\u003ectx-\u003eN, \u0026ctx-\u003ectx-\u003eD, \u0026ctx-\u003ectx-\u003eP,\n \t\t\t\u0026ctx-\u003ectx-\u003eQ, \u0026ctx-\u003ectx-\u003eDP, \u0026ctx-\u003ectx-\u003eDQ,\n \t\t\t\u0026ctx-\u003ectx-\u003eQP,\n \t\t};\n \n-\t\tfor (n \u003d 0; n \u003c LWS_COUNT_RSA_ELEMENTS; n++)\n+\t\tfor (n \u003d 0; n \u003c LWS_COUNT_RSA_KEY_ELEMENTS; n++)\n \t\t\tif (mbedtls_mpi_size(mpi[n])) {\n-\t\t\t\tel-\u003ee[n].buf \u003d lws_malloc(\n+\t\t\t\tel[n].buf \u003d lws_malloc(\n \t\t\t\t\tmbedtls_mpi_size(mpi[n]), \u0022genrsakey\u0022);\n-\t\t\t\tif (!el-\u003ee[n].buf)\n+\t\t\t\tif (!el[n].buf)\n \t\t\t\t\tgoto cleanup;\n-\t\t\t\tel-\u003ee[n].len \u003d mbedtls_mpi_size(mpi[n]);\n-\t\t\t\tmbedtls_mpi_write_binary(mpi[n], el-\u003ee[n].buf,\n-\t\t\t\t\t\t\t el-\u003ee[n].len);\n+\t\t\t\tel[n].len \u003d mbedtls_mpi_size(mpi[n]);\n+\t\t\t\tmbedtls_mpi_write_binary(mpi[n], el[n].buf,\n+\t\t\t\t\t\t\t el[n].len);\n \t\t\t}\n \t}\n \n \treturn 0;\n \n cleanup:\n-\tfor (n \u003d 0; n \u003c LWS_COUNT_RSA_ELEMENTS; n++)\n-\t\tif (el-\u003ee[n].buf)\n-\t\t\tlws_free_set_NULL(el-\u003ee[n].buf);\n+\tfor (n \u003d 0; n \u003c LWS_COUNT_JWK_ELEMENTS; n++)\n+\t\tif (el[n].buf)\n+\t\t\tlws_free_set_NULL(el[n].buf);\n cleanup_1:\n \tlws_free(ctx-\u003ectx);\n \n@@ -153,12 +152,14 @@ lws_genrsa_public_encrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in,\n {\n \tint n;\n \n-\tctx-\u003ectx-\u003elen \u003d in_len;\n-\tn \u003d mbedtls_rsa_rsaes_pkcs1_v15_encrypt(ctx-\u003ectx, NULL, NULL,\n+\t//ctx-\u003ectx-\u003elen \u003d in_len; // ???\n+\tctx-\u003ectx-\u003epadding \u003d MBEDTLS_RSA_PKCS_V15;\n+\tn \u003d mbedtls_rsa_rsaes_pkcs1_v15_encrypt(ctx-\u003ectx, _rngf, ctx-\u003econtext,\n \t\t\t\t\t\tMBEDTLS_RSA_PRIVATE,\n \t\t\t\t\t\tin_len, in, out);\n \tif (n) {\n-\t\tlwsl_notice(\u0022%s: -0x%x\u005cn\u0022, __func__, -n);\n+\t\tlwsl_notice(\u0022%s: -0x%x: in_len: %d\u005cn\u0022, __func__, -n,\n+\t\t\t\t(int)in_len);\n \n \t\treturn -1;\n \t}\n@@ -245,7 +246,7 @@ lws_genrsa_render_pkey_asn1(struct lws_genrsa_ctx *ctx, int _private,\n \t\t\t uint8_t *pkey_asn1, size_t pkey_asn1_len)\n {\n \tuint8_t *p \u003d pkey_asn1, *totlen, *end \u003d pkey_asn1 + pkey_asn1_len - 1;\n-\tmbedtls_mpi *mpi[LWS_COUNT_RSA_ELEMENTS] \u003d {\n+\tmbedtls_mpi *mpi[LWS_COUNT_RSA_KEY_ELEMENTS] \u003d {\n \t\t\u0026ctx-\u003ectx-\u003eN, \u0026ctx-\u003ectx-\u003eE, \u0026ctx-\u003ectx-\u003eD, \u0026ctx-\u003ectx-\u003eP,\n \t\t\u0026ctx-\u003ectx-\u003eQ, \u0026ctx-\u003ectx-\u003eDP, \u0026ctx-\u003ectx-\u003eDQ,\n \t\t\u0026ctx-\u003ectx-\u003eQP,\n@@ -277,7 +278,7 @@ lws_genrsa_render_pkey_asn1(struct lws_genrsa_ctx *ctx, int _private,\n \t*p++ \u003d 0x01;\n \t*p++ \u003d 0x00;\n \n-\tfor (n \u003d 0; n \u003c LWS_COUNT_RSA_ELEMENTS; n++) {\n+\tfor (n \u003d 0; n \u003c LWS_COUNT_RSA_KEY_ELEMENTS; n++) {\n \t\tint m \u003d mbedtls_mpi_size(mpi[n]);\n \t\tuint8_t *elen;\n \ndiff --git a/lib/tls/mbedtls/mbedtls-server.c b/lib/tls/mbedtls/mbedtls-server.c\nindex df6ddf2..78e3084 100644\n--- a/lib/tls/mbedtls/mbedtls-server.c\n+++ b/lib/tls/mbedtls/mbedtls-server.c\n@@ -453,7 +453,7 @@ lws_tls_acme_sni_cert_create(struct lws_vhost *vhost, const char *san_a,\n \tint buflen \u003d 0x560;\n \tuint8_t *buf \u003d lws_malloc(buflen, \u0022tmp cert buf\u0022), *p \u003d buf, *pkey_asn1;\n \tstruct lws_genrsa_ctx ctx;\n-\tstruct lws_genrsa_elements el;\n+\tstruct lws_jwk_elements el;\n \tuint8_t digest[32];\n \tstruct lws_genhash_ctx hash_ctx;\n \tint pkey_asn1_len \u003d 3 * 1024;\n@@ -498,8 +498,8 @@ lws_tls_acme_sni_cert_create(struct lws_vhost *vhost, const char *san_a,\n \t/* we need to drop 1 + (keybits / 8) bytes of n in here, 00 + key */\n \n \t*p++ \u003d 0x00;\n-\tmemcpy(p, el.e[JWK_KEY_N].buf, el.e[JWK_KEY_N].len);\n-\tp +\u003d el.e[JWK_KEY_N].len;\n+\tmemcpy(p, el.e[JWK_RSA_KEYEL_N].buf, el.e[JWK_RSA_KEYEL_N].len);\n+\tp +\u003d el.e[JWK_RSA_KEYEL_N].len;\n \n \tmemcpy(p, ss_cert_san_leadin, sizeof(ss_cert_san_leadin));\n \tp +\u003d sizeof(ss_cert_san_leadin);\ndiff --git a/lib/tls/openssl/lws-genec.c b/lib/tls/openssl/lws-genec.c\nnew file mode 100644\nindex 0000000..e69de29\n--- /dev/null\n+++ b/lib/tls/openssl/lws-genec.c\ndiff --git a/lib/tls/openssl/lws-genrsa.c b/lib/tls/openssl/lws-genrsa.c\nindex a136327..8bb52bf 100644\n--- a/lib/tls/openssl/lws-genrsa.c\n+++ b/lib/tls/openssl/lws-genrsa.c\n@@ -22,31 +22,31 @@\n * same whether you are using openssl or mbedtls hash functions underneath.\n */\n #include \u0022core/private.h\u0022\n+#include \u0022../../jose/private.h\u0022\n \n LWS_VISIBLE void\n-lws_jwk_destroy_genrsa_elements(struct lws_genrsa_elements *el)\n+lws_jwk_destroy_genrsa_elements(struct lws_jwk_elements *el)\n {\n-\tint n;\n-\n-\tfor (n \u003d 0; n \u003c LWS_COUNT_RSA_ELEMENTS; n++)\n-\t\tif (el-\u003ee[n].buf)\n-\t\t\tlws_free_set_NULL(el-\u003ee[n].buf);\n+\tlws_jwk_destroy_elements(el, LWS_COUNT_RSA_KEY_ELEMENTS);\n }\n \n LWS_VISIBLE int\n-lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_genrsa_elements *el)\n+lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_jwk_elements *el,\n+\t\t struct lws_context *context)\n {\n \tint n;\n \n \tmemset(ctx, 0, sizeof(*ctx));\n \n+\tctx-\u003econtext \u003d context;\n+\n \t/* Step 1:\n \t *\n \t * convert the MPI for e and n to OpenSSL BIGNUMs\n \t */\n \n \tfor (n \u003d 0; n \u003c 5; n++) {\n-\t\tctx-\u003ebn[n] \u003d BN_bin2bn(el-\u003ee[n].buf, el-\u003ee[n].len, NULL);\n+\t\tctx-\u003ebn[n] \u003d BN_bin2bn(el[n].buf, el[n].len, NULL);\n \t\tif (!ctx-\u003ebn[n]) {\n \t\t\tlwsl_notice(\u0022mpi load failed\u005cn\u0022);\n \t\t\tgoto bail;\n@@ -65,18 +65,20 @@ lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_genrsa_elements *el)\n \t}\n \n #if defined(LWS_HAVE_RSA_SET0_KEY)\n-\tif (RSA_set0_key(ctx-\u003ersa, ctx-\u003ebn[JWK_KEY_N], ctx-\u003ebn[JWK_KEY_E],\n-\t\t\t ctx-\u003ebn[JWK_KEY_D]) !\u003d 1) {\n+\tif (RSA_set0_key(ctx-\u003ersa, ctx-\u003ebn[JWK_RSA_KEYEL_N],\n+\t\t\t ctx-\u003ebn[JWK_RSA_KEYEL_E],\n+\t\t\t ctx-\u003ebn[JWK_RSA_KEYEL_D]) !\u003d 1) {\n \t\tlwsl_notice(\u0022RSA_set0_key failed\u005cn\u0022);\n \t\tgoto bail;\n \t}\n-\tRSA_set0_factors(ctx-\u003ersa, ctx-\u003ebn[JWK_KEY_P], ctx-\u003ebn[JWK_KEY_Q]);\n+\tRSA_set0_factors(ctx-\u003ersa, ctx-\u003ebn[JWK_RSA_KEYEL_P],\n+\t\t\t\t ctx-\u003ebn[JWK_RSA_KEYEL_Q]);\n #else\n-\tctx-\u003ersa-\u003ee \u003d ctx-\u003ebn[JWK_KEY_E];\n-\tctx-\u003ersa-\u003en \u003d ctx-\u003ebn[JWK_KEY_N];\n-\tctx-\u003ersa-\u003ed \u003d ctx-\u003ebn[JWK_KEY_D];\n-\tctx-\u003ersa-\u003ep \u003d ctx-\u003ebn[JWK_KEY_P];\n-\tctx-\u003ersa-\u003eq \u003d ctx-\u003ebn[JWK_KEY_Q];\n+\tctx-\u003ersa-\u003ee \u003d ctx-\u003ebn[JWK_RSA_KEYEL_E];\n+\tctx-\u003ersa-\u003en \u003d ctx-\u003ebn[JWK_RSA_KEYEL_N];\n+\tctx-\u003ersa-\u003ed \u003d ctx-\u003ebn[JWK_RSA_KEYEL_D];\n+\tctx-\u003ersa-\u003ep \u003d ctx-\u003ebn[JWK_RSA_KEYEL_P];\n+\tctx-\u003ersa-\u003eq \u003d ctx-\u003ebn[JWK_RSA_KEYEL_Q];\n #endif\n \n \treturn 0;\n@@ -98,7 +100,7 @@ bail:\n \n LWS_VISIBLE int\n lws_genrsa_new_keypair(struct lws_context *context, struct lws_genrsa_ctx *ctx,\n-\t\t struct lws_genrsa_elements *el, int bits)\n+\t\t struct lws_jwk_elements *el, int bits)\n {\n \tBIGNUM *bn;\n \tint n;\n@@ -128,9 +130,10 @@ lws_genrsa_new_keypair(struct lws_context *context, struct lws_genrsa_ctx *ctx,\n \t{\n \t\tconst BIGNUM *mpi[5];\n \n-\t\tRSA_get0_key(ctx-\u003ersa, \u0026mpi[JWK_KEY_N], \u0026mpi[JWK_KEY_E],\n-\t\t\t \u0026mpi[JWK_KEY_D]);\n-\t\tRSA_get0_factors(ctx-\u003ersa, \u0026mpi[JWK_KEY_P], \u0026mpi[JWK_KEY_Q]);\n+\t\tRSA_get0_key(ctx-\u003ersa, \u0026mpi[JWK_RSA_KEYEL_N],\n+\t\t\t \u0026mpi[JWK_RSA_KEYEL_E], \u0026mpi[JWK_RSA_KEYEL_D]);\n+\t\tRSA_get0_factors(ctx-\u003ersa, \u0026mpi[JWK_RSA_KEYEL_P],\n+\t\t\t\t \u0026mpi[JWK_RSA_KEYEL_Q]);\n #else\n \t{\n \t\tBIGNUM *mpi[5] \u003d {\n@@ -140,41 +143,66 @@ lws_genrsa_new_keypair(struct lws_context *context, struct lws_genrsa_ctx *ctx,\n #endif\n \t\tfor (n \u003d 0; n \u003c 5; n++)\n \t\t\tif (BN_num_bytes(mpi[n])) {\n-\t\t\t\tel-\u003ee[n].buf \u003d lws_malloc(\n+\t\t\t\tel[n].buf \u003d lws_malloc(\n \t\t\t\t\tBN_num_bytes(mpi[n]), \u0022genrsakey\u0022);\n-\t\t\t\tif (!el-\u003ee[n].buf)\n+\t\t\t\tif (!el[n].buf)\n \t\t\t\t\tgoto cleanup;\n-\t\t\t\tel-\u003ee[n].len \u003d BN_num_bytes(mpi[n]);\n-\t\t\t\tBN_bn2bin(mpi[n], el-\u003ee[n].buf);\n+\t\t\t\tel[n].len \u003d BN_num_bytes(mpi[n]);\n+\t\t\t\tBN_bn2bin(mpi[n], el[n].buf);\n \t\t\t}\n \t}\n \n \treturn 0;\n \n cleanup:\n-\tfor (n \u003d 0; n \u003c LWS_COUNT_RSA_ELEMENTS; n++)\n-\t\tif (el-\u003ee[n].buf)\n-\t\t\tlws_free_set_NULL(el-\u003ee[n].buf);\n+\tfor (n \u003d 0; n \u003c LWS_COUNT_RSA_KEY_ELEMENTS; n++)\n+\t\tif (el[n].buf)\n+\t\t\tlws_free_set_NULL(el[n].buf);\n cleanup_1:\n \tRSA_free(ctx-\u003ersa);\n \n \treturn -1;\n }\n \n+/*\n+ * flen must be less than RSA_size(rsa) - 11 for the PKCS #1 v1.5\n+ * based padding modes\n+ */\n+\n+LWS_VISIBLE int\n+lws_genrsa_public_encrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in,\n+\t\t\t size_t in_len, uint8_t *out)\n+{\n+\tint m;\n+\n+\tm \u003d RSA_public_encrypt((int)in_len, in, out, ctx-\u003ersa,\n+\t\t\t RSA_PKCS1_PADDING);\n+\n+\t/* the bignums are also freed by freeing the RSA */\n+\tRSA_free(ctx-\u003ersa);\n+\tctx-\u003ersa \u003d NULL;\n+\n+\tif (m !\u003d -1)\n+\t\treturn m;\n+\n+\treturn -1;\n+}\n+\n LWS_VISIBLE int\n lws_genrsa_public_decrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in,\n \t\t\t size_t in_len, uint8_t *out, size_t out_max)\n {\n-\tuint32_t m;\n+\tint m;\n \n-\tm \u003d RSA_public_decrypt((int)in_len, in, out, ctx-\u003ersa, RSA_PKCS1_PADDING);\n+\tm \u003d RSA_public_decrypt((int)in_len, in, out, ctx-\u003ersa,\n+\t\t\t RSA_PKCS1_PADDING);\n \n \t/* the bignums are also freed by freeing the RSA */\n \tRSA_free(ctx-\u003ersa);\n \tctx-\u003ersa \u003d NULL;\n \n-\tif (m !\u003d (uint32_t)-1)\n-\t\treturn (int)m;\n+\tif (m !\u003d -1)\n+\t\treturn m;\n \n \treturn -1;\n }\ndiff --git a/minimal-examples/api-tests/api-test-jose/CMakeLists.txt b/minimal-examples/api-tests/api-test-jose/CMakeLists.txt\nnew file mode 100644\nindex 0000000..49207b7\n--- /dev/null\n+++ b/minimal-examples/api-tests/api-test-jose/CMakeLists.txt\n@@ -0,0 +1,73 @@\n+cmake_minimum_required(VERSION 2.8)\n+include(CheckCSourceCompiles)\n+\n+set(SAMP lws-api-test-jose)\n+set(SRCS main.c jwk.c jws.c jwe.c)\n+\n+# If we are being built as part of lws, confirm current build config supports\n+# reqconfig, else skip building ourselves.\n+#\n+# If we are being built externally, confirm installed lws was configured to\n+# support reqconfig, else error out with a helpful message about the problem.\n+#\n+MACRO(require_lws_config reqconfig _val result)\n+\n+\tif (DEFINED ${reqconfig})\n+\tif (${reqconfig})\n+\t\tset (rq 1)\n+\telse()\n+\t\tset (rq 0)\n+\tendif()\n+\telse()\n+\t\tset(rq 0)\n+\tendif()\n+\n+\tif (${_val} EQUAL ${rq})\n+\t\tset(SAME 1)\n+\telse()\n+\t\tset(SAME 0)\n+\tendif()\n+\n+\tif (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})\n+\t\tif (${_val})\n+\t\t\tmessage(\u0022${SAMP}: skipping as lws being built without ${reqconfig}\u0022)\n+\t\telse()\n+\t\t\tmessage(\u0022${SAMP}: skipping as lws built with ${reqconfig}\u0022)\n+\t\tendif()\n+\t\tset(${result} 0)\n+\telse()\n+\t\tif (LWS_WITH_MINIMAL_EXAMPLES)\n+\t\t\tset(MET ${SAME})\n+\t\telse()\n+\t\t\tCHECK_C_SOURCE_COMPILES(\u0022#include \u003clibwebsockets.h\u003e\u005cnint main(void) {\u005cn#if defined(${reqconfig})\u005cn return 0;\u005cn#else\u005cn fail;\u005cn#endif\u005cn return 0;\u005cn}\u005cn\u0022 HAS_${reqconfig})\n+\t\t\tif (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})\n+\t\t\t\tset(HAS_${reqconfig} 0)\n+\t\t\telse()\n+\t\t\t\tset(HAS_${reqconfig} 1)\n+\t\t\tendif()\n+\t\t\tif ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))\n+\t\t\t\tset(MET 1)\n+\t\t\telse()\n+\t\t\t\tset(MET 0)\n+\t\t\tendif()\n+\t\tendif()\n+\t\tif (NOT MET)\n+\t\t\tif (${_val})\n+\t\t\t\tmessage(FATAL_ERROR \u0022This project requires lws must have been configured with ${reqconfig}\u0022)\n+\t\t\telse()\n+\t\t\t\tmessage(FATAL_ERROR \u0022Lws configuration of ${reqconfig} is incompatible with this project\u0022)\n+\t\t\tendif()\n+\t\tendif()\n+\tendif()\n+ENDMACRO()\n+\n+\n+\n+\tadd_executable(${SAMP} ${SRCS})\n+\n+\tif (websockets_shared)\n+\t\ttarget_link_libraries(${SAMP} websockets_shared)\n+\t\tadd_dependencies(${SAMP} websockets_shared)\n+\telse()\n+\t\ttarget_link_libraries(${SAMP} websockets)\n+\tendif()\ndiff --git a/minimal-examples/api-tests/api-test-jose/README.md b/minimal-examples/api-tests/api-test-jose/README.md\nnew file mode 100644\nindex 0000000..74034c7\n--- /dev/null\n+++ b/minimal-examples/api-tests/api-test-jose/README.md\n@@ -0,0 +1,22 @@\n+# lws api test lwsac\n+\n+Demonstrates how to use and performs selftests for lwsac\n+\n+## build\n+\n+```\n+ $ cmake . \u0026\u0026 make\n+```\n+\n+## usage\n+\n+Commandline option|Meaning\n+---|---\n+-d \u003cloglevel\u003e|Debug verbosity in decimal, eg, -d15\n+\n+```\n+ $ ./lws-api-test-lwsac\n+[2018/10/09 09:14:17:4834] USER: LWS API selftest: lwsac\n+[2018/10/09 09:14:17:4835] USER: Completed: PASS\n+```\n+\ndiff --git a/minimal-examples/api-tests/api-test-jose/jwe.c b/minimal-examples/api-tests/api-test-jose/jwe.c\nnew file mode 100644\nindex 0000000..77637e3\n--- /dev/null\n+++ b/minimal-examples/api-tests/api-test-jose/jwe.c\n@@ -0,0 +1,332 @@\n+/*\n+ * lws-api-test-jose - RFC7516 jwe tests\n+ *\n+ * Copyright (C) 2018 Andy Green \u003candy@warmcat.com\u003e\n+ *\n+ * This file is made available under the Creative Commons CC0 1.0\n+ * Universal Public Domain Dedication.\n+ */\n+\n+#include \u003clibwebsockets.h\u003e\n+\n+\n+/* A.2. Example JWE using RSAES-PKCS1-v1_5 and AES_128_CBC_HMAC_SHA_256 */\n+\n+/* \u0022Live long and prosper.\u0022 */\n+static\n+uint8_t\n+\n+#if 0\n+lws_jwe_ex_a2_plaintext[] \u003d {\n+\t76, 105, 118, 101, 32, 108, 111, 110,\n+\t103, 32, 97, 110, 100, 32, 112, 114,\n+\t111, 115, 112, 101, 114, 46\n+},\n+#endif\n+*lws_jwe_ex_a2_jose_hdr \u003d (uint8_t *)\n+\t\u0022{\u005c\u0022alg\u005c\u0022:\u005c\u0022RSA1_5\u005c\u0022,\u005c\u0022enc\u005c\u0022:\u005c\u0022A128CBC-HS256\u005c\u0022}\u0022,\n+\n+*lws_jwe_ex_a2_jose_hdr_b64utf8 \u003d (unsigned char *)\n+\t\u0022eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0\u0022,\n+\n+lws_jwe_ex_a2_cek[] \u003d {\n+\t 4, 211, 31, 197, 84, 157, 252, 254,\n+\t 11, 100, 157, 250, 63, 170, 106, 206,\n+\t107, 124, 212, 45, 111, 107, 9, 219,\n+\t200, 177, 0, 240, 143, 156, 44, 207\n+},\n+\n+*lws_jwe_ex_a2_jwk_json \u003d (uint8_t *)\n+\u0022{\u0022\n+ \u0022\u005c\u0022kty\u005c\u0022:\u005c\u0022RSA\u005c\u0022,\u0022\n+ \u0022\u005c\u0022n\u005c\u0022:\u005c\u0022sXchDaQebHnPiGvyDOAT4saGEUetSyo9MKLOoWFsueri23bOdgWp4Dy1Wl\u0022\n+\t \u0022UzewbgBHod5pcM9H95GQRV3JDXboIRROSBigeC5yjU1hGzHHyXss8UDpre\u0022\n+\t \u0022cbAYxknTcQkhslANGRUZmdTOQ5qTRsLAt6BTYuyvVRdhS8exSZEy_c4gs_\u0022\n+\t \u00227svlJJQ4H9_NxsiIoLwAEk7-Q3UXERGYw_75IDrGA84-lA_-Ct4eTlXHBI\u0022\n+\t \u0022Y2EaV7t7LjJaynVJCpkv4LKjTTAumiGUIuQhrNhZLuF_RJLqHpM2kgWFLU\u0022\n+\t \u00227-VTdL1VbC2tejvcI2BlMkEpk1BzBZI0KQB0GaDWFLN-aEAw3vRw\u005c\u0022,\u0022\n+ \u0022\u005c\u0022e\u005c\u0022:\u005c\u0022AQAB\u005c\u0022,\u0022\n+ \u0022\u005c\u0022d\u005c\u0022:\u005c\u0022VFCWOqXr8nvZNyaaJLXdnNPXZKRaWCjkU5Q2egQQpTBMwhprMzWzpR8Sxq\u0022\n+\t \u00221OPThh_J6MUD8Z35wky9b8eEO0pwNS8xlh1lOFRRBoNqDIKVOku0aZb-ry\u0022\n+\t \u0022nq8cxjDTLZQ6Fz7jSjR1Klop-YKaUHc9GsEofQqYruPhzSA-QgajZGPbE_\u0022\n+\t \u00220ZaVDJHfyd7UUBUKunFMScbflYAAOYJqVIVwaYR5zWEEceUjNnTNo_CVSj\u0022\n+\t \u0022-VvXLO5VZfCUAVLgW4dpf1SrtZjSt34YLsRarSb127reG_DUwg9Ch-Kyvj\u0022\n+\t \u0022T1SkHgUWRVGcyly7uvVGRSDwsXypdrNinPA4jlhoNdizK2zF2CWQ\u005c\u0022,\u0022\n+ \u0022\u005c\u0022p\u005c\u0022:\u005c\u00229gY2w6I6S6L0juEKsbeDAwpd9WMfgqFoeA9vEyEUuk4kLwBKcoe1x4HG68\u0022\n+\t \u0022ik918hdDSE9vDQSccA3xXHOAFOPJ8R9EeIAbTi1VwBYnbTp87X-xcPWlEP\u0022\n+\t \u0022krdoUKW60tgs1aNd_Nnc9LEVVPMS390zbFxt8TN_biaBgelNgbC95sM\u005c\u0022,\u0022\n+ \u0022\u005c\u0022q\u005c\u0022:\u005c\u0022uKlCKvKv_ZJMVcdIs5vVSU_6cPtYI1ljWytExV_skstvRSNi9r66jdd9-y\u0022\n+\t \u0022BhVfuG4shsp2j7rGnIio901RBeHo6TPKWVVykPu1iYhQXw1jIABfw-MVsN\u0022\n+\t \u0022-3bQ76WLdt2SDxsHs7q7zPyUyHXmps7ycZ5c72wGkUwNOjYelmkiNS0\u005c\u0022,\u0022\n+ \u0022\u005c\u0022dp\u005c\u0022:\u005c\u0022w0kZbV63cVRvVX6yk3C8cMxo2qCM4Y8nsq1lmMSYhG4EcL6FWbX5h9yuv\u0022\n+\t \u0022ngs4iLEFk6eALoUS4vIWEwcL4txw9LsWH_zKI-hwoReoP77cOdSL4AVcra\u0022\n+\t \u0022Hawlkpyd2TWjE5evgbhWtOxnZee3cXJBkAi64Ik6jZxbvk-RR3pEhnCs\u005c\u0022,\u0022\n+ \u0022\u005c\u0022dq\u005c\u0022:\u005c\u0022o_8V14SezckO6CNLKs_btPdFiO9_kC1DsuUTd2LAfIIVeMZ7jn1Gus_Ff\u0022\n+\t \u00227B7IVx3p5KuBGOVF8L-qifLb6nQnLysgHDh132NDioZkhH7mI7hPG-PYE_\u0022\n+\t \u0022odApKdnqECHWw0J-F0JWnUd6D2B_1TvF9mXA2Qx-iGYn8OVV1Bsmp6qU\u005c\u0022,\u0022\n+ \u0022\u005c\u0022qi\u005c\u0022:\u005c\u0022eNho5yRBEBxhGBtQRww9QirZsB66TrfFReG_CcteI1aCneT0ELGhYlRlC\u0022\n+\t \u0022tUkTRclIfuEPmNsNDPbLoLqqCVznFbvdB7x-Tl-m0l_eFTj2KiqwGqE9PZ\u0022\n+\t \u0022B9nNTwMVvH3VRRSLWACvPnSiwP8N5Usy-WRXS-V7TbpxIhvepTfE0NNo\u005c\u0022\u0022\n+\u0022}\u0022,\n+\n+lws_jwe_ex_a2_jwk_enc_key[] \u003d {\n+\t 80, 104, 72, 58, 11, 130, 236, 139,\n+\t 132, 189, 255, 205, 61, 86, 151, 176,\n+\t 99, 40, 44, 233, 176, 189, 205, 70,\n+\t 202, 169, 72, 40, 226, 181, 156, 223,\n+\t 120, 156, 115, 232, 150, 209, 145, 133,\n+\t 104, 112, 237, 156, 116, 250, 65, 102,\n+\t 212, 210, 103, 240, 177, 61, 93, 40,\n+\t 71, 231, 223, 226, 240, 157, 15, 31,\n+\t 150, 89, 200, 215, 198, 203, 108, 70,\n+\t 117, 66, 212, 238, 193, 205, 23, 161,\n+\t 169, 218, 243, 203, 128, 214, 127, 253,\n+\t 215, 139, 43, 17, 135, 103, 179, 220,\n+\t 28, 2, 212, 206, 131, 158, 128, 66,\n+\t 62, 240, 78, 186, 141, 125, 132, 227,\n+\t 60, 137, 43, 31, 152, 199, 54, 72,\n+\t 34, 212, 115, 11, 152, 101, 70, 42,\n+\t 219, 233, 142, 66, 151, 250, 126, 146,\n+\t 141, 216, 190, 73, 50, 177, 146, 5,\n+\t 52, 247, 28, 197, 21, 59, 170, 247,\n+\t 181, 89, 131, 241, 169, 182, 246, 99,\n+\t 15, 36, 102, 166, 182, 172, 197, 136,\n+\t 230, 120, 60, 58, 219, 243, 149, 94,\n+\t 222, 150, 154, 194, 110, 227, 225, 112,\n+\t 39, 89, 233, 112, 207, 211, 241, 124,\n+\t 174, 69, 221, 179, 107, 196, 225, 127,\n+\t 167, 112, 226, 12, 242, 16, 24, 28,\n+\t 120, 182, 244, 213, 244, 153, 194, 162,\n+\t 69, 160, 244, 248, 63, 165, 141, 4,\n+\t 207, 249, 193, 79, 131, 0, 169, 233,\n+\t 127, 167, 101, 151, 125, 56, 112, 111,\n+\t 248, 29, 232, 90, 29, 147, 110, 169,\n+\t 146, 114, 165, 204, 71, 136, 41, 252\n+}\n+#if 0\n+,\n+*lws_jwe_ex_a2_jwk_enc_key_b64 \u003d (uint8_t *)\n+\t\u0022UGhIOguC7IuEvf_NPVaXsGMoLOmwvc1GyqlIKOK1nN94nHPoltGRhWhw7Zx0-kFm\u0022\n+\t\u00221NJn8LE9XShH59_i8J0PH5ZZyNfGy2xGdULU7sHNF6Gp2vPLgNZ__deLKxGHZ7Pc\u0022\n+\t\u0022HALUzoOegEI-8E66jX2E4zyJKx-YxzZIItRzC5hlRirb6Y5Cl_p-ko3YvkkysZIF\u0022\n+\t\u0022NPccxRU7qve1WYPxqbb2Yw8kZqa2rMWI5ng8OtvzlV7elprCbuPhcCdZ6XDP0_F8\u0022\n+\t\u0022rkXds2vE4X-ncOIM8hAYHHi29NX0mcKiRaD0-D-ljQTP-cFPgwCp6X-nZZd9OHBv\u0022\n+\t\u0022-B3oWh2TbqmScqXMR4gp_A\u0022,\n+\n+lws_jwe_ex_a2_iv[] \u003d {\n+\t 3, 22, 60, 12, 43, 67, 104, 105,\n+\t108, 108, 105, 99, 111, 116, 104, 101\n+},\n+\n+*lws_jwe_ex_a2_iv_b64 \u003d (uint8_t *)\n+\t\u0022AxY8DCtDaGlsbGljb3RoZQ\u0022,\n+\n+lws_jwe_ex_a2_aad[] \u003d {\n+\t101, 121, 74, 104, 98, 71, 99, 105,\n+\t 79, 105, 74, 83, 85, 48, 69, 120,\n+\t 88, 122, 85, 105, 76, 67, 74, 108,\n+\t 98, 109, 77, 105, 79, 105, 74, 66,\n+\t 77, 84, 73, 52, 81, 48, 74, 68,\n+\t 76, 85, 104, 84, 77, 106, 85, 50,\n+\t 73, 110, 48\n+},\n+\n+lws_jwe_ex_a2_ciphertext[] \u003d {\n+\t 40, 57, 83, 181, 119, 33, 133, 148,\n+\t198, 185, 243, 24, 152, 230, 6, 75,\n+\t129, 223, 127, 19, 210, 82, 183, 230,\n+\t168, 33, 215, 104, 143, 112, 56, 102\n+},\n+\n+*lws_jwe_ex_a2_ciphertext_b64 \u003d (uint8_t *)\n+\t\u0022KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY\u0022,\n+\n+lws_jwe_ex_a2_authtag[] \u003d {\n+\t246, 17, 244, 190, 4, 95, 98, 3,\n+\t231, 0, 115, 157, 242, 203, 100, 191\n+},\n+\n+*lws_jwe_ex_a2_authtag_b64 \u003d (uint8_t *)\n+\t\u00229hH0vgRfYgPnAHOd8stkvw\u0022,\n+\n+*lws_jwe_ex_a2_aggregated \u003d (uint8_t *)\n+\t\u0022eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.\u0022\n+\t\u0022UGhIOguC7IuEvf_NPVaXsGMoLOmwvc1GyqlIKOK1nN94nHPoltGRhWhw7Zx0-kFm\u0022\n+\t\u00221NJn8LE9XShH59_i8J0PH5ZZyNfGy2xGdULU7sHNF6Gp2vPLgNZ__deLKxGHZ7Pc\u0022\n+\t\u0022HALUzoOegEI-8E66jX2E4zyJKx-YxzZIItRzC5hlRirb6Y5Cl_p-ko3YvkkysZIF\u0022\n+\t\u0022NPccxRU7qve1WYPxqbb2Yw8kZqa2rMWI5ng8OtvzlV7elprCbuPhcCdZ6XDP0_F8\u0022\n+\t\u0022rkXds2vE4X-ncOIM8hAYHHi29NX0mcKiRaD0-D-ljQTP-cFPgwCp6X-nZZd9OHBv\u0022\n+\t\u0022-B3oWh2TbqmScqXMR4gp_A.\u0022\n+\t\u0022AxY8DCtDaGlsbGljb3RoZQ.\u0022\n+\t\u0022KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY.\u0022\n+\t\u00229hH0vgRfYgPnAHOd8stkvw\u0022\n+#endif\n+;\n+\n+/*\n+ * These are the inputs and outputs from the worked example in RFC7515\n+ * Appendix A.1.\n+ *\n+ * 1) has a fixed header + payload, and a fixed SHA256 HMAC key, and must give\n+ * a fixed BASE64URL result.\n+ *\n+ * 2) has a fixed header + payload and is signed with a key given in JWK format\n+ */\n+int\n+test_jwe(struct lws_context *context)\n+{\n+\tstruct lws_genrsa_ctx rsactx;\n+\tstruct lws_jwk jwk;\n+\tuint8_t enc_cek[sizeof(lws_jwe_ex_a2_jwk_enc_key) + 2048];\n+\tchar buf[2048], *p \u003d buf, *end \u003d buf + sizeof(buf) - 1;\n+\tint n;\n+\n+\t/* Test 1: A.2 */\n+\n+\t/* Decode the JWK JSON key */\n+\n+\tif (lws_jwk_import(\u0026jwk, NULL, NULL, (char *)lws_jwe_ex_a2_jwk_json,\n+\t\t\t strlen((char *)lws_jwe_ex_a2_jwk_json)) \u003c 0) {\n+\t\tlwsl_notice(\u0022Failed to decode JWK test key\u005cn\u0022);\n+\t\treturn -1;\n+\t}\n+\n+\tif (jwk.kty !\u003d LWS_JWK_KYT_RSA) {\n+\t\tlwsl_err(\u0022%s: unexpected kty %d\u005cn\u0022, __func__, jwk.kty);\n+\n+\t\treturn -1;\n+\t}\n+\n+\t/* A.2.1: encode JOSE header and confirm matches official string */\n+\n+\tn \u003d lws_jws_encode_section((char *)lws_jwe_ex_a2_jose_hdr,\n+\t\t\t\t strlen((char *)lws_jwe_ex_a2_jose_hdr), 1,\n+\t\t\t\t \u0026p, end);\n+\tif (n \u003c 0)\n+\t\tgoto bail;\n+\tif (strcmp(buf, (char *)lws_jwe_ex_a2_jose_hdr_b64utf8))\n+\t\tgoto bail;\n+\n+\t/* A.2.3: Encrypt the CEK with the recipient's public key using the\n+\t * RSAES-PKCS1-v1_5 algorithm to produce the JWE Encrypted Key.\n+\t */\n+\n+\tif (lws_genrsa_create(\u0026rsactx, jwk.e, context)) {\n+\t\tlwsl_notice(\u0022%s: lws_genrsa_public_decrypt_create\u005cn\u0022,\n+\t\t\t __func__);\n+\t\tgoto bail;\n+\t}\n+\n+\tmemset(enc_cek, 0, sizeof(enc_cek));\n+\n+\tn \u003d lws_genrsa_public_encrypt(\u0026rsactx, lws_jwe_ex_a2_cek,\n+\t\t\t\t sizeof(lws_jwe_ex_a2_cek), enc_cek);\n+\tlws_genrsa_destroy(\u0026rsactx);\n+\tif (n \u003c 0) {\n+\t\tlwsl_err(\u0022%s: encrypt cek fail\u005cn\u0022, __func__);\n+\t\tgoto bail;\n+\t}\n+#if 0\n+\tif (memcmp(enc_cek, lws_jwe_ex_a2_jwk_enc_key, sizeof(enc_cek))) {\n+\t\tlwsl_err(\u0022%s: encrypt cek wrong output\u005cn\u0022, __func__);\n+\t\tlwsl_hexdump_notice(enc_cek, sizeof(enc_cek));\n+\t\tlwsl_hexdump_notice(lws_jwe_ex_a2_jwk_enc_key,\n+\t\t\t\t sizeof(lws_jwe_ex_a2_jwk_enc_key));\n+\t\tgoto bail;\n+\t}\n+\n+\n+\tenc_ptr \u003d p + 1; /* + 1 skips the . */\n+\tn \u003d lws_jws_encode_section(test2, strlen(test2), 0, \u0026p, end);\n+\tif (n \u003c 0)\n+\t\tgoto bail;\n+\tif (strcmp(enc_ptr, test2_enc))\n+\t\tgoto bail;\n+\n+\t/* 1.3: use HMAC SHA-256 with known key on the hdr . payload */\n+\n+\tif (lws_genhmac_init(\u0026ctx, LWS_GENHMAC_TYPE_SHA256,\n+\t\t\t jwk.el.e[JWK_RSA_KEYEL_E].buf,\n+\t\t\t jwk.el.e[JWK_RSA_KEYEL_E].len))\n+\t\tgoto bail;\n+\tif (lws_genhmac_update(\u0026ctx, (uint8_t *)buf, p - buf))\n+\t\tgoto bail_destroy_hmac;\n+\tlws_genhmac_destroy(\u0026ctx, digest);\n+\n+\t/* 1.4: append a base64 encode of the computed HMAC digest */\n+\n+\tenc_ptr \u003d p + 1; /* + 1 skips the . */\n+\tn \u003d lws_jws_encode_section((const char *)digest, 32, 0, \u0026p, end);\n+\tif (n \u003c 0)\n+\t\tgoto bail;\n+\tif (strcmp(enc_ptr, hash_enc)) /* check against known B64URL hash */\n+\t\tgoto bail;\n+\n+\t/* 1.5: Check we can agree the signature matches the payload */\n+\n+\tif (lws_jws_confirm_sig(buf, p - buf, \u0026jwk) \u003c 0) {\n+\t\tlwsl_notice(\u0022confirm sig failed\u005cn\u0022);\n+\t\tgoto bail;\n+\t}\n+\n+\tlws_jwk_destroy(\u0026jwk); /* finished with the key from the first test */\n+\n+\t/* Test 2: RSA256 on RFC7515 worked example */\n+\n+\t/* 2.1: turn the known JWK key for the RSA test into a lws_jwk */\n+\n+\tif (lws_jwk_import(\u0026jwk, rfc7515_rsa_key, strlen(rfc7515_rsa_key))) {\n+\t\tlwsl_notice(\u0022Failed to read JWK key\u005cn\u0022);\n+\t\tgoto bail2;\n+\t}\n+\n+\t/* 2.2: check the signature on the test packet from RFC7515 A-1 */\n+\n+\tif (lws_jws_confirm_sig(rfc7515_rsa_a1, strlen(rfc7515_rsa_a1),\n+\t\t\t\t\u0026jwk) \u003c 0) {\n+\t\tlwsl_notice(\u0022confirm rsa sig failed\u005cn\u0022);\n+\t\tgoto bail;\n+\t}\n+\n+\t/* 2.3: generate our own signature for a copy of the test packet */\n+\n+\tmemcpy(buf, rfc7515_rsa_a1, strlen(rfc7515_rsa_a1));\n+\n+\t/* set p to second . */\n+\tp \u003d strchr(buf + 1, '.');\n+\tp1 \u003d strchr(p + 1, '.');\n+\n+\tn \u003d lws_jws_sign_from_b64(buf, p - buf, p + 1, p1 - (p + 1),\n+\t\t\t\t p1 + 1, sizeof(buf) - (p1 - buf) - 1,\n+\t\t\t\t LWS_GENHASH_TYPE_SHA256, \u0026jwk);\n+\tif (n \u003c 0)\n+\t\tgoto bail;\n+\n+\tputs(buf);\n+\n+\t/* 2.4: confirm our signature can be verified */\n+\n+\tif (lws_jws_confirm_sig(buf, (p1 + 1 + n) - buf, \u0026jwk) \u003c 0) {\n+\t\tlwsl_notice(\u0022confirm rsa sig 2 failed\u005cn\u0022);\n+\t\tgoto bail;\n+\t}\n+#endif\n+\tlws_jwk_destroy(\u0026jwk);\n+\n+\t/* end */\n+\n+\tlwsl_notice(\u0022%s: selftest OK\u005cn\u0022, __func__);\n+\n+\treturn 0;\n+#if 0\n+bail_destroy_hmac:\n+\tlws_genhmac_destroy(\u0026ctx, NULL);\n+#endif\n+bail:\n+\tlws_jwk_destroy(\u0026jwk);\n+//bail2:\n+\tlwsl_err(\u0022%s: selftest failed ++++++++++++++++++++\u005cn\u0022, __func__);\n+\n+\treturn 1;\n+\n+}\ndiff --git a/minimal-examples/api-tests/api-test-jose/jwk.c b/minimal-examples/api-tests/api-test-jose/jwk.c\nnew file mode 100644\nindex 0000000..b4fb95a\n--- /dev/null\n+++ b/minimal-examples/api-tests/api-test-jose/jwk.c\n@@ -0,0 +1,350 @@\n+/*\n+ * lws-api-test-jose - RFC7517 jwk tests\n+ *\n+ * Copyright (C) 2018 Andy Green \u003candy@warmcat.com\u003e\n+ *\n+ * This file is made available under the Creative Commons CC0 1.0\n+ * Universal Public Domain Dedication.\n+ */\n+\n+#include \u003clibwebsockets.h\u003e\n+\n+static\n+uint8_t *lws_jwe_ex_a1_jwk_json \u003d (uint8_t *) /* EC + RSA public keys */\n+\t\u0022{\u005c\u0022keys\u005c\u0022:\u0022\n+\t \u0022[\u0022\n+\t \u0022{\u005c\u0022kty\u005c\u0022:\u005c\u0022EC\u005c\u0022,\u0022\n+\t \u0022\u005c\u0022crv\u005c\u0022:\u005c\u0022P-256\u005c\u0022,\u0022\n+\t \u0022\u005c\u0022x\u005c\u0022:\u005c\u0022MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4\u005c\u0022,\u0022\n+\t \u0022\u005c\u0022y\u005c\u0022:\u005c\u00224Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM\u005c\u0022,\u0022\n+\t \u0022\u005c\u0022use\u005c\u0022:\u005c\u0022enc\u005c\u0022,\u0022\n+\t \u0022\u005c\u0022kid\u005c\u0022:\u005c\u00221\u005c\u0022},\u0022\n+\n+\t \u0022{\u005c\u0022kty\u005c\u0022:\u005c\u0022RSA\u005c\u0022,\u0022\n+\t \u0022\u005c\u0022n\u005c\u0022: \u005c\u00220vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx\u0022\n+\t\u00224cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMs\u0022\n+\t\u0022tn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2\u0022\n+\t\u0022QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbI\u0022\n+\t\u0022SD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqb\u0022\n+\t\u0022w0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw\u005c\u0022,\u0022\n+\t \u0022\u005c\u0022e\u005c\u0022:\u005c\u0022AQAB\u005c\u0022,\u0022\n+\t \u0022\u005c\u0022alg\u005c\u0022:\u005c\u0022RS256\u005c\u0022,\u0022\n+\t \u0022\u005c\u0022kid\u005c\u0022:\u005c\u00222011-04-29\u005c\u0022}\u0022\n+\t \u0022]\u0022\n+\t\u0022}\u0022,\n+\n+*lws_jwe_ex_a2_jwk_json \u003d (uint8_t *) /* EC + RSA private keys */\n+\t\u0022{\u005c\u0022keys\u005c\u0022:\u0022\n+\t \u0022[\u0022\n+\t\t\u0022{\u005c\u0022kty\u005c\u0022:\u005c\u0022EC\u005c\u0022,\u0022\n+\t\t\u0022\u005c\u0022crv\u005c\u0022:\u005c\u0022P-256\u005c\u0022,\u0022\n+\t\t\u0022\u005c\u0022x\u005c\u0022:\u005c\u0022MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4\u005c\u0022,\u0022\n+\t\t\u0022\u005c\u0022y\u005c\u0022:\u005c\u00224Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM\u005c\u0022,\u0022\n+\t\t\u0022\u005c\u0022d\u005c\u0022:\u005c\u0022870MB6gfuTJ4HtUnUvYMyJpr5eUZNP4Bk43bVdj3eAE\u005c\u0022,\u0022\n+\t\t\u0022\u005c\u0022use\u005c\u0022:\u005c\u0022enc\u005c\u0022,\u0022\n+\t\t\u0022\u005c\u0022kid\u005c\u0022:\u005c\u00221\u005c\u0022},\u0022\n+\n+\t\t\u0022{\u005c\u0022kty\u005c\u0022:\u005c\u0022RSA\u005c\u0022,\u0022\n+\t\t \u0022\u005c\u0022n\u005c\u0022:\u005c\u00220vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4\u0022\n+\t \u0022cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMst\u0022\n+\t \u0022n64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2Q\u0022\n+\t \u0022vzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbIS\u0022\n+\t \u0022D08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw\u0022\n+\t \u00220Ls1jF44-csFCur-kEgU8awapJzKnqDKgw\u005c\u0022,\u0022\n+\t\t \u0022\u005c\u0022e\u005c\u0022:\u005c\u0022AQAB\u005c\u0022,\u0022\n+\t\t \u0022\u005c\u0022d\u005c\u0022:\u005c\u0022X4cTteJY_gn4FYPsXB8rdXix5vwsg1FLN5E3EaG6RJoVH-HLLKD9\u0022\n+\t \u0022M7dx5oo7GURknchnrRweUkC7hT5fJLM0WbFAKNLWY2vv7B6NqXSzUvxT0_YSfqij\u0022\n+\t \u0022wp3RTzlBaCxWp4doFk5N2o8Gy_nHNKroADIkJ46pRUohsXywbReAdYaMwFs9tv8d\u0022\n+\t \u0022_cPVY3i07a3t8MN6TNwm0dSawm9v47UiCl3Sk5ZiG7xojPLu4sbg1U2jx4IBTNBz\u0022\n+\t \u0022nbJSzFHK66jT8bgkuqsk0GjskDJk19Z4qwjwbsnn4j2WBii3RL-Us2lGVkY8fkFz\u0022\n+\t \u0022me1z0HbIkfz0Y6mqnOYtqc0X4jfcKoAC8Q\u005c\u0022,\u0022\n+\t\t\u0022\u005c\u0022p\u005c\u0022:\u005c\u002283i-7IvMGXoMXCskv73TKr8637FiO7Z27zv8oj6pbWUQyLPQBQxtPV\u0022\n+\t \u0022nwD20R-60eTDmD2ujnMt5PoqMrm8RfmNhVWDtjjMmCMjOpSXicFHj7XOuVIYQyqV\u0022\n+\t \u0022WlWEh6dN36GVZYk93N8Bc9vY41xy8B9RzzOGVQzXvNEvn7O0nVbfs\u005c\u0022,\u0022\n+\t\t\u0022\u005c\u0022q\u005c\u0022:\u005c\u00223dfOR9cuYq-0S-mkFLzgItgMEfFzB2q3hWehMuG0oCuqnb3vobLyum\u0022\n+\t \u0022qjVZQO1dIrdwgTnCdpYzBcOfW5r370AFXjiWft_NGEiovonizhKpo9VVS78TzFgx\u0022\n+\t \u0022kIdrecRezsZ-1kYd_s1qDbxtkDEgfAITAG9LUnADun4vIcb6yelxk\u005c\u0022,\u0022\n+\t\t\u0022\u005c\u0022dp\u005c\u0022:\u005c\u0022G4sPXkc6Ya9y8oJW9_ILj4xuppu0lzi_H7VTkS8xj5SdX3coE0oim\u0022\n+\t \u0022YwxIi2emTAue0UOa5dpgFGyBJ4c8tQ2VF402XRugKDTP8akYhFo5tAA77Qe_Nmtu\u0022\n+\t \u0022YZc3C3m3I24G2GvR5sSDxUyAN2zq8Lfn9EUms6rY3Ob8YeiKkTiBj0\u005c\u0022,\u0022\n+\t\t\u0022\u005c\u0022dq\u005c\u0022:\u005c\u0022s9lAH9fggBsoFR8Oac2R_E2gw282rT2kGOAhvIllETE1efrA6huUU\u0022\n+\t \u0022vMfBcMpn8lqeW6vzznYY5SSQF7pMdC_agI3nG8Ibp1BUb0JUiraRNqUfLhcQb_d9\u0022\n+\t \u0022GF4Dh7e74WbRsobRonujTYN1xCaP6TO61jvWrX-L18txXw494Q_cgk\u005c\u0022,\u0022\n+\t\t\u0022\u005c\u0022qi\u005c\u0022:\u005c\u0022GyM_p6JrXySiz1toFgKbWV-JdI3jQ4ypu9rbMWx3rQJBfmt0FoYzg\u0022\n+\t \u0022UIZEVFEcOqwemRN81zoDAaa-Bk0KWNGDjJHZDdDmFhW3AN7lI-puxk_mHZGJ11rx\u0022\n+\t \u0022yR8O55XLSe3SPmRfKwZI6yU24ZxvQKFYItdldUKGzO6Ia6zTKhAVRU\u005c\u0022,\u0022\n+\t\t\u0022\u005c\u0022alg\u005c\u0022:\u005c\u0022RS256\u005c\u0022,\u0022\n+\t\t\u0022\u005c\u0022kid\u005c\u0022:\u005c\u00222011-04-29\u005c\u0022}\u0022\n+\t \u0022]\u0022\n+\t \u0022}\u0022,\n+*lws_jwe_ex_a3_jwk_json \u003d (uint8_t *) /* oct symmetric keys */\n+\t \u0022{\u005c\u0022keys\u005c\u0022:\u0022\n+\t \u0022[\u0022\n+\t \u0022{\u005c\u0022kty\u005c\u0022:\u005c\u0022oct\u005c\u0022,\u0022\n+\t \u0022\u005c\u0022alg\u005c\u0022:\u005c\u0022A128KW\u005c\u0022,\u0022\n+\t \u0022\u005c\u0022k\u005c\u0022:\u005c\u0022GawgguFyGrWKav7AX4VKUg\u005c\u0022},\u0022\n+\n+\t \u0022{\u005c\u0022kty\u005c\u0022:\u005c\u0022oct\u005c\u0022,\u0022\n+\t \u0022\u005c\u0022k\u005c\u0022:\u005c\u0022AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75\u0022\n+\t\t\t\u0022aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow\u005c\u0022,\u0022\n+\t \u0022\u005c\u0022kid\u005c\u0022:\u005c\u0022HMAC key used in JWS spec Appendix A.1 example\u005c\u0022}\u0022\n+\t \u0022]\u0022\n+\t \u0022}\u0022,\n+\n+*lws_jwe_ex_b_jwk_json \u003d (uint8_t *) /* x5c example (no parent JSON) */\n+\t \u0022{\u005c\u0022kty\u005c\u0022:\u005c\u0022RSA\u005c\u0022,\u0022\n+\t \u0022\u005c\u0022use\u005c\u0022:\u005c\u0022sig\u005c\u0022,\u0022\n+\t \u0022\u005c\u0022kid\u005c\u0022:\u005c\u00221b94c\u005c\u0022,\u0022\n+\t \u0022\u005c\u0022n\u005c\u0022:\u005c\u0022vrjOfz9Ccdgx5nQudyhdoR17V-IubWMeOZCwX_jj0hgAsz2J_pqYW08\u0022\n+\t \u0022PLbK_PdiVGKPrqzmDIsLI7sA25VEnHU1uCLNwBuUiCO11_-7dYbsr4iJmG0Q\u0022\n+\t \u0022u2j8DsVyT1azpJC_NG84Ty5KKthuCaPod7iI7w0LK9orSMhBEwwZDCxTWq4a\u0022\n+\t \u0022YWAchc8t-emd9qOvWtVMDC2BXksRngh6X5bUYLy6AyHKvj-nUy1wgzjYQDwH\u0022\n+\t \u0022MTplCoLtU-o-8SNnZ1tmRoGE9uJkBLdh5gFENabWnU5m1ZqZPdwS-qo-meMv\u0022\n+\t \u0022VfJb6jJVWRpl2SUtCnYG2C32qvbWbjZ_jBPD5eunqsIo1vQ\u005c\u0022,\u0022\n+\t \u0022\u005c\u0022e\u005c\u0022:\u005c\u0022AQAB\u005c\u0022,\u0022\n+\t \u0022\u005c\u0022x5c\u005c\u0022:\u0022\n+\t \u0022[\u005c\u0022MIIDQjCCAiqgAwIBAgIGATz/FuLiMA0GCSqGSIb3DQEBBQUAMGIxCzAJB\u0022\n+\t \u0022gNVBAYTAlVTMQswCQYDVQQIEwJDTzEPMA0GA1UEBxMGRGVudmVyMRwwGgYD\u0022\n+\t \u0022VQQKExNQaW5nIElkZW50aXR5IENvcnAuMRcwFQYDVQQDEw5CcmlhbiBDYW1\u0022\n+\t \u0022wYmVsbDAeFw0xMzAyMjEyMzI5MTVaFw0xODA4MTQyMjI5MTVaMGIxCzAJBg\u0022\n+\t \u0022NVBAYTAlVTMQswCQYDVQQIEwJDTzEPMA0GA1UEBxMGRGVudmVyMRwwGgYDV\u0022\n+\t \u0022QQKExNQaW5nIElkZW50aXR5IENvcnAuMRcwFQYDVQQDEw5CcmlhbiBDYW1w\u0022\n+\t \u0022YmVsbDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL64zn8/QnH\u0022\n+\t \u0022YMeZ0LncoXaEde1fiLm1jHjmQsF/449IYALM9if6amFtPDy2yvz3YlRij66\u0022\n+\t \u0022s5gyLCyO7ANuVRJx1NbgizcAblIgjtdf/u3WG7K+IiZhtELto/A7Fck9Ws6\u0022\n+\t \u0022SQvzRvOE8uSirYbgmj6He4iO8NCyvaK0jIQRMMGQwsU1quGmFgHIXPLfnpn\u0022\n+\t \u0022fajr1rVTAwtgV5LEZ4Iel+W1GC8ugMhyr4/p1MtcIM42EA8BzE6ZQqC7VPq\u0022\n+\t \u0022PvEjZ2dbZkaBhPbiZAS3YeYBRDWm1p1OZtWamT3cEvqqPpnjL1XyW+oyVVk\u0022\n+\t \u0022aZdklLQp2Btgt9qr21m42f4wTw+Xrp6rCKNb0CAwEAATANBgkqhkiG9w0BA\u0022\n+\t \u0022QUFAAOCAQEAh8zGlfSlcI0o3rYDPBB07aXNswb4ECNIKG0CETTUxmXl9KUL\u0022\n+\t \u0022+9gGlqCz5iWLOgWsnrcKcY0vXPG9J1r9AqBNTqNgHq2G03X09266X5CpOe1\u0022\n+\t \u0022zFo+Owb1zxtp3PehFdfQJ610CDLEaS9V9Rqp17hCyybEpOGVwe8fnk+fbEL\u0022\n+\t \u00222Bo3UPGrpsHzUoaGpDftmWssZkhpBJKVMJyf/RuP2SmmaIzmnw9JiSlYhzo\u0022\n+\t \u00224tpzd5rFXhjRbg4zW9C+2qok+2+qDM1iJ684gPHMIY8aLWrdgQTxkumGmTq\u0022\n+\t \u0022gawR+N5MDtdPTEQ0XfIBc2cJEUyMTY5MPvACWpkA6SdS4xSvdXK3IVfOWA\u003d\u003d\u005c\u0022]\u0022\n+\t \u0022}\u0022,\n+*lws_jwe_ex_c1_jwk_json \u003d (uint8_t *) /* RSA enc private key (no parent JSON) */\n+\t \u0022{\u0022\n+\t \u0022\u005c\u0022kty\u005c\u0022:\u005c\u0022RSA\u005c\u0022,\u0022\n+\t \u0022\u005c\u0022kid\u005c\u0022:\u005c\u0022juliet@capulet.lit\u005c\u0022,\u0022\n+\t \u0022\u005c\u0022use\u005c\u0022:\u005c\u0022enc\u005c\u0022,\u0022\n+\t \u0022\u005c\u0022n\u005c\u0022:\u005c\u0022t6Q8PWSi1dkJj9hTP8hNYFlvadM7DflW9mWepOJhJ66w7nyoK1gPNqFMSQRy\u0022\n+\t \u0022O125Gp-TEkodhWr0iujjHVx7BcV0llS4w5ACGgPrcAd6ZcSR0-Iqom-QFcNP\u0022\n+\t \u00228Sjg086MwoqQU_LYywlAGZ21WSdS_PERyGFiNnj3QQlO8Yns5jCtLCRwLHL0\u0022\n+\t \u0022Pb1fEv45AuRIuUfVcPySBWYnDyGxvjYGDSM-AqWS9zIQ2ZilgT-GqUmipg0X\u0022\n+\t \u0022OC0Cc20rgLe2ymLHjpHciCKVAbY5-L32-lSeZO-Os6U15_aXrk9Gw8cPUaX1\u0022\n+\t \u0022_I8sLGuSiVdt3C_Fn2PZ3Z8i744FPFGGcG1qs2Wz-Q\u005c\u0022,\u0022\n+\t \u0022\u005c\u0022e\u005c\u0022:\u005c\u0022AQAB\u005c\u0022,\u0022\n+\t \u0022\u005c\u0022d\u005c\u0022:\u005c\u0022GRtbIQmhOZtyszfgKdg4u_N-R_mZGU_9k7JQ_jn1DnfTuMdSNprTeaSTyWfS\u0022\n+\t \u0022NkuaAwnOEbIQVy1IQbWVV25NY3ybc_IhUJtfri7bAXYEReWaCl3hdlPKXy9U\u0022\n+\t \u0022vqPYGR0kIXTQRqns-dVJ7jahlI7LyckrpTmrM8dWBo4_PMaenNnPiQgO0xnu\u0022\n+\t \u0022ToxutRZJfJvG4Ox4ka3GORQd9CsCZ2vsUDmsXOfUENOyMqADC6p1M3h33tsu\u0022\n+\t \u0022rY15k9qMSpG9OX_IJAXmxzAh_tWiZOwk2K4yxH9tS3Lq1yX8C1EWmeRDkK2a\u0022\n+\t \u0022hecG85-oLKQt5VEpWHKmjOi_gJSdSgqcN96X52esAQ\u005c\u0022,\u0022\n+\t \u0022\u005c\u0022p\u005c\u0022:\u005c\u00222rnSOV4hKSN8sS4CgcQHFbs08XboFDqKum3sc4h3GRxrTmQdl1ZK9uw-PIHf\u0022\n+\t \u0022QP0FkxXVrx-WE-ZEbrqivH_2iCLUS7wAl6XvARt1KkIaUxPPSYB9yk31s0Q8\u0022\n+\t \u0022UK96E3_OrADAYtAJs-M3JxCLfNgqh56HDnETTQhH3rCT5T3yJws\u005c\u0022,\u0022\n+\t \u0022\u005c\u0022q\u005c\u0022:\u005c\u00221u_RiFDP7LBYh3N4GXLT9OpSKYP0uQZyiaZwBtOCBNJgQxaj10RWjsZu0c6I\u0022\n+\t \u0022edis4S7B_coSKB0Kj9PaPaBzg-IySRvvcQuPamQu66riMhjVtG6TlV8CLCYK\u0022\n+\t \u0022rYl52ziqK0E_ym2QnkwsUX7eYTB7LbAHRK9GqocDE5B0f808I4s\u005c\u0022,\u0022\n+\t \u0022\u005c\u0022dp\u005c\u0022:\u005c\u0022KkMTWqBUefVwZ2_Dbj1pPQqyHSHjj90L5x_MOzqYAJMcLMZtbUtwKqvVDq3\u0022\n+\t \u0022tbEo3ZIcohbDtt6SbfmWzggabpQxNxuBpoOOf_a_HgMXK_lhqigI4y_kqS1w\u0022\n+\t \u0022Y52IwjUn5rgRrJ-yYo1h41KR-vz2pYhEAeYrhttWtxVqLCRViD6c\u005c\u0022,\u0022\n+\t \u0022\u005c\u0022dq\u005c\u0022:\u005c\u0022AvfS0-gRxvn0bwJoMSnFxYcK1WnuEjQFluMGfwGitQBWtfZ1Er7t1xDkbN9\u0022\n+\t \u0022GQTB9yqpDoYaN06H7CFtrkxhJIBQaj6nkF5KKS3TQtQ5qCzkOkmxIe3KRbBy\u0022\n+\t \u0022mXxkb5qwUpX5ELD5xFc6FeiafWYY63TmmEAu_lRFCOJ3xDea-ots\u005c\u0022,\u0022\n+\t \u0022\u005c\u0022qi\u005c\u0022:\u005c\u0022lSQi-w9CpyUReMErP1RsBLk7wNtOvs5EQpPqmuMvqW57NBUczScEoPwmUqq\u0022\n+\t \u0022abu9V0-Py4dQ57_bapoKRu1R90bvuFnU63SHWEFglZQvJDMeAvmj4sm-Fp0o\u0022\n+\t \u0022Yu_neotgQ0hzbI5gry7ajdYy9-2lNx_76aBZoOUu9HCJ-UsfSOI8\u005c\u0022\u0022\n+\t \u0022}\u0022 /*,\n+lws_jwe_ex_c1_plaintext[] \u003d {\n+\t123, 34, 107, 116, 121, 34, 58, 34, 82, 83, 65, 34, 44, 34, 107,\n+\t105, 100, 34, 58, 34, 106, 117, 108, 105, 101, 116, 64, 99, 97, 112,\n+\t117, 108, 101, 116, 46, 108, 105, 116, 34, 44, 34, 117, 115, 101, 34,\n+\t58, 34, 101, 110, 99, 34, 44, 34, 110, 34, 58, 34, 116, 54, 81, 56,\n+\t80, 87, 83, 105, 49, 100, 107, 74, 106, 57, 104, 84, 80, 56, 104, 78,\n+\t89, 70, 108, 118, 97, 100, 77, 55, 68, 102, 108, 87, 57, 109, 87,\n+\t101, 112, 79, 74, 104, 74, 54, 54, 119, 55, 110, 121, 111, 75, 49,\n+\t103, 80, 78, 113, 70, 77, 83, 81, 82, 121, 79, 49, 50, 53, 71, 112,\n+\t45, 84, 69, 107, 111, 100, 104, 87, 114, 48, 105, 117, 106, 106, 72,\n+\t86, 120, 55, 66, 99, 86, 48, 108, 108, 83, 52, 119, 53, 65, 67, 71,\n+\t103, 80, 114, 99, 65, 100, 54, 90, 99, 83, 82, 48, 45, 73, 113, 111,\n+\t109, 45, 81, 70, 99, 78, 80, 56, 83, 106, 103, 48, 56, 54, 77, 119,\n+\t111, 113, 81, 85, 95, 76, 89, 121, 119, 108, 65, 71, 90, 50, 49, 87,\n+\t83, 100, 83, 95, 80, 69, 82, 121, 71, 70, 105, 78, 110, 106, 51, 81,\n+\t81, 108, 79, 56, 89, 110, 115, 53, 106, 67, 116, 76, 67, 82, 119, 76,\n+\t72, 76, 48, 80, 98, 49, 102, 69, 118, 52, 53, 65, 117, 82, 73, 117,\n+\t85, 102, 86, 99, 80, 121, 83, 66, 87, 89, 110, 68, 121, 71, 120, 118,\n+\t106, 89, 71, 68, 83, 77, 45, 65, 113, 87, 83, 57, 122, 73, 81, 50,\n+\t90, 105, 108, 103, 84, 45, 71, 113, 85, 109, 105, 112, 103, 48, 88,\n+\t79, 67, 48, 67, 99, 50, 48, 114, 103, 76, 101, 50, 121, 109, 76, 72,\n+\t106, 112, 72, 99, 105, 67, 75, 86, 65, 98, 89, 53, 45, 76, 51, 50,\n+\t45, 108, 83, 101, 90, 79, 45, 79, 115, 54, 85, 49, 53, 95, 97, 88,\n+\t114, 107, 57, 71, 119, 56, 99, 80, 85, 97, 88, 49, 95, 73, 56, 115,\n+\t76, 71, 117, 83, 105, 86, 100, 116, 51, 67, 95, 70, 110, 50, 80, 90,\n+\t51, 90, 56, 105, 55, 52, 52, 70, 80, 70, 71, 71, 99, 71, 49, 113,\n+\t115, 50, 87, 122, 45, 81, 34, 44, 34, 101, 34, 58, 34, 65, 81, 65,\n+\t66, 34, 44, 34, 100, 34, 58, 34, 71, 82, 116, 98, 73, 81, 109, 104,\n+\t79, 90, 116, 121, 115, 122, 102, 103, 75, 100, 103, 52, 117, 95, 78,\n+\t45, 82, 95, 109, 90, 71, 85, 95, 57, 107, 55, 74, 81, 95, 106, 110,\n+\t49, 68, 110, 102, 84, 117, 77, 100, 83, 78, 112, 114, 84, 101, 97,\n+\t83, 84, 121, 87, 102, 83, 78, 107, 117, 97, 65, 119, 110, 79, 69, 98,\n+\t73, 81, 86, 121, 49, 73, 81, 98, 87, 86, 86, 50, 53, 78, 89, 51, 121,\n+\t98, 99, 95, 73, 104, 85, 74, 116, 102, 114, 105, 55, 98, 65, 88, 89,\n+\t69, 82, 101, 87, 97, 67, 108, 51, 104, 100, 108, 80, 75, 88, 121, 57,\n+\t85, 118, 113, 80, 89, 71, 82, 48, 107, 73, 88, 84, 81, 82, 113, 110,\n+\t115, 45, 100, 86, 74, 55, 106, 97, 104, 108, 73, 55, 76, 121, 99,\n+\t107, 114, 112, 84, 109, 114, 77, 56, 100, 87, 66, 111, 52, 95, 80,\n+\t77, 97, 101, 110, 78, 110, 80, 105, 81, 103, 79, 48, 120, 110, 117,\n+\t84, 111, 120, 117, 116, 82, 90, 74, 102, 74, 118, 71, 52, 79, 120,\n+\t52, 107, 97, 51, 71, 79, 82, 81, 100, 57, 67, 115, 67, 90, 50, 118,\n+\t115, 85, 68, 109, 115, 88, 79, 102, 85, 69, 78, 79, 121, 77, 113, 65,\n+\t68, 67, 54, 112, 49, 77, 51, 104, 51, 51, 116, 115, 117, 114, 89, 49,\n+\t53, 107, 57, 113, 77, 83, 112, 71, 57, 79, 88, 95, 73, 74, 65, 88,\n+\t109, 120, 122, 65, 104, 95, 116, 87, 105, 90, 79, 119, 107, 50, 75,\n+\t52, 121, 120, 72, 57, 116, 83, 51, 76, 113, 49, 121, 88, 56, 67, 49,\n+\t69, 87, 109, 101, 82, 68, 107, 75, 50, 97, 104, 101, 99, 71, 56, 53,\n+\t45, 111, 76, 75, 81, 116, 53, 86, 69, 112, 87, 72, 75, 109, 106, 79,\n+\t105, 95, 103, 74, 83, 100, 83, 103, 113, 99, 78, 57, 54, 88, 53, 50,\n+\t101, 115, 65, 81, 34, 44, 34, 112, 34, 58, 34, 50, 114, 110, 83, 79,\n+\t86, 52, 104, 75, 83, 78, 56, 115, 83, 52, 67, 103, 99, 81, 72, 70,\n+\t98, 115, 48, 56, 88, 98, 111, 70, 68, 113, 75, 117, 109, 51, 115, 99,\n+\t52, 104, 51, 71, 82, 120, 114, 84, 109, 81, 100, 108, 49, 90, 75, 57,\n+\t117, 119, 45, 80, 73, 72, 102, 81, 80, 48, 70, 107, 120, 88, 86, 114,\n+\t120, 45, 87, 69, 45, 90, 69, 98, 114, 113, 105, 118, 72, 95, 50, 105,\n+\t67, 76, 85, 83, 55, 119, 65, 108, 54, 88, 118, 65, 82, 116, 49, 75,\n+\t107, 73, 97, 85, 120, 80, 80, 83, 89, 66, 57, 121, 107, 51, 49, 115,\n+\t48, 81, 56, 85, 75, 57, 54, 69, 51, 95, 79, 114, 65, 68, 65, 89, 116,\n+\t65, 74, 115, 45, 77, 51, 74, 120, 67, 76, 102, 78, 103, 113, 104, 53,\n+\t54, 72, 68, 110, 69, 84, 84, 81, 104, 72, 51, 114, 67, 84, 53, 84,\n+\t51, 121, 74, 119, 115, 34, 44, 34, 113, 34, 58, 34, 49, 117, 95, 82,\n+\t105, 70, 68, 80, 55, 76, 66, 89, 104, 51, 78, 52, 71, 88, 76, 84, 57,\n+\t79, 112, 83, 75, 89, 80, 48, 117, 81, 90, 121, 105, 97, 90, 119, 66,\n+\t116, 79, 67, 66, 78, 74, 103, 81, 120, 97, 106, 49, 48, 82, 87, 106,\n+\t115, 90, 117, 48, 99, 54, 73, 101, 100, 105, 115, 52, 83, 55, 66, 95,\n+\t99, 111, 83, 75, 66, 48, 75, 106, 57, 80, 97, 80, 97, 66, 122, 103,\n+\t45, 73, 121, 83, 82, 118, 118, 99, 81, 117, 80, 97, 109, 81, 117, 54,\n+\t54, 114, 105, 77, 104, 106, 86, 116, 71, 54, 84, 108, 86, 56, 67, 76,\n+\t67, 89, 75, 114, 89, 108, 53, 50, 122, 105, 113, 75, 48, 69, 95, 121,\n+\t109, 50, 81, 110, 107, 119, 115, 85, 88, 55, 101, 89, 84, 66, 55, 76,\n+\t98, 65, 72, 82, 75, 57, 71, 113, 111, 99, 68, 69, 53, 66, 48, 102,\n+\t56, 48, 56, 73, 52, 115, 34, 44, 34, 100, 112, 34, 58, 34, 75, 107,\n+\t77, 84, 87, 113, 66, 85, 101, 102, 86, 119, 90, 50, 95, 68, 98, 106,\n+\t49, 112, 80, 81, 113, 121, 72, 83, 72, 106, 106, 57, 48, 76, 53, 120,\n+\t95, 77, 79, 122, 113, 89, 65, 74, 77, 99, 76, 77, 90, 116, 98, 85,\n+\t116, 119, 75, 113, 118, 86, 68, 113, 51, 116, 98, 69, 111, 51, 90,\n+\t73, 99, 111, 104, 98, 68, 116, 116, 54, 83, 98, 102, 109, 87, 122,\n+\t103, 103, 97, 98, 112, 81, 120, 78, 120, 117, 66, 112, 111, 79, 79,\n+\t102, 95, 97, 95, 72, 103, 77, 88, 75, 95, 108, 104, 113, 105, 103,\n+\t73, 52, 121, 95, 107, 113, 83, 49, 119, 89, 53, 50, 73, 119, 106, 85,\n+\t110, 53, 114, 103, 82, 114, 74, 45, 121, 89, 111, 49, 104, 52, 49,\n+\t75, 82, 45, 118, 122, 50, 112, 89, 104, 69, 65, 101, 89, 114, 104,\n+\t116, 116, 87, 116, 120, 86, 113, 76, 67, 82, 86, 105, 68, 54, 99, 34,\n+\t44, 34, 100, 113, 34, 58, 34, 65, 118, 102, 83, 48, 45, 103, 82, 120,\n+\t118, 110, 48, 98, 119, 74, 111, 77, 83, 110, 70, 120, 89, 99, 75, 49,\n+\t87, 110, 117, 69, 106, 81, 70, 108, 117, 77, 71, 102, 119, 71, 105,\n+\t116, 81, 66, 87, 116, 102, 90, 49, 69, 114, 55, 116, 49, 120, 68,\n+\t107, 98, 78, 57, 71, 81, 84, 66, 57, 121, 113, 112, 68, 111, 89, 97,\n+\t78, 48, 54, 72, 55, 67, 70, 116, 114, 107, 120, 104, 74, 73, 66, 81,\n+\t97, 106, 54, 110, 107, 70, 53, 75, 75, 83, 51, 84, 81, 116, 81, 53,\n+\t113, 67, 122, 107, 79, 107, 109, 120, 73, 101, 51, 75, 82, 98, 66,\n+\t121, 109, 88, 120, 107, 98, 53, 113, 119, 85, 112, 88, 53, 69, 76,\n+\t68, 53, 120, 70, 99, 54, 70, 101, 105, 97, 102, 87, 89, 89, 54, 51,\n+\t84, 109, 109, 69, 65, 117, 95, 108, 82, 70, 67, 79, 74, 51, 120, 68,\n+\t101, 97, 45, 111, 116, 115, 34, 44, 34, 113, 105, 34, 58, 34, 108,\n+\t83, 81, 105, 45, 119, 57, 67, 112, 121, 85, 82, 101, 77, 69, 114, 80,\n+\t49, 82, 115, 66, 76, 107, 55, 119, 78, 116, 79, 118, 115, 53, 69, 81,\n+\t112, 80, 113, 109, 117, 77, 118, 113, 87, 53, 55, 78, 66, 85, 99,\n+\t122, 83, 99, 69, 111, 80, 119, 109, 85, 113, 113, 97, 98, 117, 57,\n+\t86, 48, 45, 80, 121, 52, 100, 81, 53, 55, 95, 98, 97, 112, 111, 75,\n+\t82, 117, 49, 82, 57, 48, 98, 118, 117, 70, 110, 85, 54, 51, 83, 72,\n+\t87, 69, 70, 103, 108, 90, 81, 118, 74, 68, 77, 101, 65, 118, 109,\n+\t106, 52, 115, 109, 45, 70, 112, 48, 111, 89, 117, 95, 110, 101, 111,\n+\t116, 103, 81, 48, 104, 122, 98, 73, 53, 103, 114, 121, 55, 97, 106,\n+\t100, 89, 121, 57, 45, 50, 108, 78, 120, 95, 55, 54, 97, 66, 90, 111,\n+\t79, 85, 117, 57, 72, 67, 74, 45, 85, 115, 102, 83, 79, 73, 56, 34,\n+\t125 } */\n+;\n+\n+static int\n+key_import_callback(struct lws_jwk *s, void *user)\n+{\n+\tlwsl_notice(\u0022%s: key type %d\u005cn\u0022, __func__, s-\u003ekty);\n+\n+\treturn 0;\n+}\n+\n+\n+int\n+test_jwk(struct lws_context *context)\n+{\n+\tstruct lws_jwk jwk;\n+\n+\t/* Test 1: A.1: Example public keys */\n+\n+\tif (lws_jwk_import(\u0026jwk, key_import_callback, NULL,\n+\t\t\t (char *)lws_jwe_ex_a1_jwk_json,\n+\t\t\t strlen((char *)lws_jwe_ex_a1_jwk_json)) \u003c 0) {\n+\t\tlwsl_notice(\u0022Failed to decode JWK test key\u005cn\u0022);\n+\t\tgoto bail1;\n+\t}\n+\n+\tlws_jwk_destroy(\u0026jwk);\n+\n+\t/* Test 1: A.2: Example private keys */\n+\n+\tif (lws_jwk_import(\u0026jwk, key_import_callback, NULL,\n+\t\t\t (char *)lws_jwe_ex_a2_jwk_json,\n+\t\t\t strlen((char *)lws_jwe_ex_a2_jwk_json)) \u003c 0) {\n+\t\tlwsl_notice(\u0022Failed at A.2\u005cn\u0022);\n+\t\tgoto bail1;\n+\t}\n+\n+\tlws_jwk_destroy(\u0026jwk);\n+\n+\t/* Test 1: A.3: Example symmetric keys */\n+\n+\tif (lws_jwk_import(\u0026jwk, key_import_callback, NULL,\n+\t\t\t (char *)lws_jwe_ex_a3_jwk_json,\n+\t\t\t strlen((char *)lws_jwe_ex_a3_jwk_json)) \u003c 0) {\n+\t\tlwsl_notice(\u0022Failed at A.3\u005cn\u0022);\n+\t\tgoto bail1;\n+\t}\n+\n+\tlws_jwk_destroy(\u0026jwk);\n+\n+\t/* Test 1: B: Example x509 cert chain (no parent JSON) */\n+\n+\tif (lws_jwk_import(\u0026jwk, NULL, NULL, (char *)lws_jwe_ex_b_jwk_json,\n+\t\t\t strlen((char *)lws_jwe_ex_b_jwk_json)) \u003c 0) {\n+\t\tlwsl_notice(\u0022Failed at B\u005cn\u0022);\n+\t\tgoto bail1;\n+\t}\n+\n+\tlws_jwk_destroy(\u0026jwk);\n+\n+\t/* Test 1: C.1: Example private key (no parent JSON) */\n+\n+\tif (lws_jwk_import(\u0026jwk, NULL, NULL,\n+\t\t\t (char *)lws_jwe_ex_c1_jwk_json,\n+\t\t\t strlen((char *)lws_jwe_ex_c1_jwk_json)) \u003c 0) {\n+\t\tlwsl_notice(\u0022Failed at B\u005cn\u0022);\n+\t\tgoto bail1;\n+\t}\n+\n+\tlws_jwk_destroy(\u0026jwk);\n+\n+\t/* end */\n+\n+\tlwsl_notice(\u0022%s: selftest OK\u005cn\u0022, __func__);\n+\n+\treturn 0;\n+\n+//bail:\n+//\tlws_jwk_destroy(\u0026jwk);\n+bail1:\n+\tlwsl_err(\u0022%s: selftest failed ++++++++++++++++++++\u005cn\u0022, __func__);\n+\n+\treturn 1;\n+\n+}\ndiff --git a/minimal-examples/api-tests/api-test-jose/jws.c b/minimal-examples/api-tests/api-test-jose/jws.c\nnew file mode 100644\nindex 0000000..d82b0ca\n--- /dev/null\n+++ b/minimal-examples/api-tests/api-test-jose/jws.c\n@@ -0,0 +1,248 @@\n+/*\n+ * lws-api-test-jose - RFC7515 jws tests\n+ *\n+ * Copyright (C) 2018 Andy Green \u003candy@warmcat.com\u003e\n+ *\n+ * This file is made available under the Creative Commons CC0 1.0\n+ * Universal Public Domain Dedication.\n+ */\n+\n+#include \u003clibwebsockets.h\u003e\n+\n+/*\n+ * JSON Web Signature is defined in RFC7515\n+ *\n+ * https://tools.ietf.org/html/rfc7515\n+ *\n+ * It's basically a way to wrap some JSON with a JSON \u0022header\u0022 describing the\n+ * crypto, and a signature, all in a BASE64 wrapper with elided terminating '\u003d'.\n+ *\n+ * The signature stays with the content, it serves a different purpose than eg\n+ * a TLS tunnel to transfer it.\n+ *\n+ * RFC7518 (JSON Web Algorithms) says for the \u0022alg\u0022 names\n+ *\n+ * | HS256 | HMAC using SHA-256 | Required |\n+ * | HS384 | HMAC using SHA-384 | Optional |\n+ * | HS512 | HMAC using SHA-512 | Optional |\n+ * | RS256 | RSASSA-PKCS1-v1_5 using | Recommended |\n+ * | RS384 | RSASSA-PKCS1-v1_5 using | Optional |\n+ * | | SHA-384 | |\n+ * | RS512 | RSASSA-PKCS1-v1_5 using | Optional |\n+ * | | SHA-512 | |\n+ * | ES256 | ECDSA using P-256 and SHA-256 | Recommended+ |\n+ * | ES384 | ECDSA using P-384 and SHA-384 | Optional |\n+ * | ES512 | ECDSA using P-521 and SHA-512 | Optional |\n+ *\n+ * Boulder (FOSS ACME provider) supports RS256, ES256, ES384 and ES512\n+ * currently. The \u0022Recommended+\u0022 just means it is recommended but will likely\n+ * be \u0022very recommended\u0022 soon.\n+ *\n+ * We support HS256/384/512 for symmetric crypto, but the choice for the\n+ * asymmetric crypto isn't as easy to make.\n+ *\n+ * Normally you'd choose the EC option but these are defined to use the\n+ * \u0022NIST curves\u0022 (RFC7518 3.4) which are believed to be insecure.\n+ *\n+ * https://safecurves.cr.yp.to/\n+ *\n+ * For that reason we implement RS256/384/512 for asymmetric.\n+ */\n+\n+static const char\n+\t *test1\t\u003d \u0022{\u005c\u0022typ\u005c\u0022:\u005c\u0022JWT\u005c\u0022,\u005cr\u005cn \u005c\u0022alg\u005c\u0022:\u005c\u0022HS256\u005c\u0022}\u0022,\n+\t *test1_enc\t\u003d \u0022eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9\u0022,\n+\t *test2\t\u003d \u0022{\u005c\u0022iss\u005c\u0022:\u005c\u0022joe\u005c\u0022,\u005cr\u005cn \u005c\u0022exp\u005c\u0022:1300819380,\u005cr\u005cn\u0022\n+\t\t\t \u0022 \u005c\u0022http://example.com/is_root\u005c\u0022:true}\u0022,\n+\t *test2_enc\t\u003d \u0022eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQ\u0022\n+\t\t\t \u0022ogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ\u0022,\n+\t *key_jwk\t\u003d \u0022{\u005c\u0022kty\u005c\u0022:\u005c\u0022oct\u005c\u0022,\u005cr\u005cn\u0022\n+\t\t\t \u0022 \u005c\u0022k\u005c\u0022:\u005c\u0022AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQ\u0022\n+\t\t\t \u0022Lr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow\u005c\u0022}\u0022,\n+\t *hash_enc\t\u003d \u0022dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk\u0022,\n+\t /* the key from worked example in RFC7515 A-1, as a JWK */\n+\t *rfc7515_rsa_key \u003d\n+\t\u0022{\u005c\u0022kty\u005c\u0022:\u005c\u0022RSA\u005c\u0022,\u0022\n+\t\u0022 \u005c\u0022n\u005c\u0022:\u005c\u0022ofgWCuLjybRlzo0tZWJjNiuSfb4p4fAkd_wWJcyQoTbji9k0l8W26mPddx\u0022\n+\t\t \u0022HmfHQp-Vaw-4qPCJrcS2mJPMEzP1Pt0Bm4d4QlL-yRT-SFd2lZS-pCgNMs\u0022\n+\t\t \u0022D1W_YpRPEwOWvG6b32690r2jZ47soMZo9wGzjb_7OMg0LOL-bSf63kpaSH\u0022\n+\t\t \u0022SXndS5z5rexMdbBYUsLA9e-KXBdQOS-UTo7WTBEMa2R2CapHg665xsmtdV\u0022\n+\t\t \u0022MTBQY4uDZlxvb3qCo5ZwKh9kG4LT6_I5IhlJH7aGhyxXFvUK-DWNmoudF8\u0022\n+\t\t \u0022NAco9_h9iaGNj8q2ethFkMLs91kzk2PAcDTW9gb54h4FRWyuXpoQ\u005c\u0022,\u0022\n+\t\u0022\u005c\u0022e\u005c\u0022:\u005c\u0022AQAB\u005c\u0022,\u0022\n+\t\u0022\u005c\u0022d\u005c\u0022:\u005c\u0022Eq5xpGnNCivDflJsRQBXHx1hdR1k6Ulwe2JZD50LpXyWPEAeP88vLNO97I\u0022\n+\t\t\u0022jlA7_GQ5sLKMgvfTeXZx9SE-7YwVol2NXOoAJe46sui395IW_GO-pWJ1O0\u0022\n+\t\t\u0022BkTGoVEn2bKVRUCgu-GjBVaYLU6f3l9kJfFNS3E0QbVdxzubSu3Mkqzjkn\u0022\n+\t\t\u0022439X0M_V51gfpRLI9JYanrC4D4qAdGcopV_0ZHHzQlBjudU2QvXt4ehNYT\u0022\n+\t\t\u0022CBr6XCLQUShb1juUO1ZdiYoFaFQT5Tw8bGUl_x_jTj3ccPDVZFD9pIuhLh\u0022\n+\t\t\u0022BOneufuBiB4cS98l2SR_RQyGWSeWjnczT0QU91p1DhOVRuOopznQ\u005c\u0022,\u0022\n+\t\u0022\u005c\u0022p\u005c\u0022:\u005c\u00224BzEEOtIpmVdVEZNCqS7baC4crd0pqnRH_5IB3jw3bcxGn6QLvnEtfdUdi\u0022\n+\t\t\u0022YrqBdss1l58BQ3KhooKeQTa9AB0Hw_Py5PJdTJNPY8cQn7ouZ2KKDcmnPG\u0022\n+\t\t\u0022BY5t7yLc1QlQ5xHdwW1VhvKn-nXqhJTBgIPgtldC-KDV5z-y2XDwGUc\u005c\u0022,\u0022\n+\t\u0022\u005c\u0022q\u005c\u0022:\u005c\u0022uQPEfgmVtjL0Uyyx88GZFF1fOunH3-7cepKmtH4pxhtCoHqpWmT8YAmZxa\u0022\n+\t\t\u0022ewHgHAjLYsp1ZSe7zFYHj7C6ul7TjeLQeZD_YwD66t62wDmpe_HlB-TnBA\u0022\n+\t\t\u0022-njbglfIsRLtXlnDzQkv5dTltRJ11BKBBypeeF6689rjcJIDEz9RWdc\u005c\u0022,\u0022\n+\t\u0022\u005c\u0022dp\u005c\u0022:\u005c\u0022BwKfV3Akq5_MFZDFZCnW-wzl-CCo83WoZvnLQwCTeDv8uzluRSnm71I3Q\u0022\n+\t\t\u0022CLdhrqE2e9YkxvuxdBfpT_PI7Yz-FOKnu1R6HsJeDCjn12Sk3vmAktV2zb\u0022\n+\t\t\u002234MCdy7cpdTh_YVr7tss2u6vneTwrA86rZtu5Mbr1C1XsmvkxHQAdYo0\u005c\u0022,\u0022\n+\t\u0022\u005c\u0022dq\u005c\u0022:\u005c\u0022h_96-mK1R_7glhsum81dZxjTnYynPbZpHziZjeeHcXYsXaaMwkOlODsWa\u0022\n+\t\t\u00227I9xXDoRwbKgB719rrmI2oKr6N3Do9U0ajaHF-NKJnwgjMd2w9cjz3_-ky\u0022\n+\t\t\u0022NlxAr2v4IKhGNpmM5iIgOS1VZnOZ68m6_pbLBSp3nssTdlqvd0tIiTHU\u005c\u0022,\u0022\n+\t\u0022\u005c\u0022qi\u005c\u0022:\u005c\u0022IYd7DHOhrWvxkwPQsRM2tOgrjbcrfvtQJipd-DlcxyVuuM9sQLdgjVk2o\u0022\n+\t\t\u0022y26F0EmpScGLq2MowX7fhd_QJQ3ydy5cY7YIBi87w93IKLEdfnbJtoOPLU\u0022\n+\t\t\u0022W0ITrJReOgo1cq9SbsxYawBgfp_gh6A5603k2-ZQwVK0JKSHuLFkuQ3U\u005c\u0022\u0022\n+\t\u0022}\u0022,\n+\t *rfc7515_rsa_a1 \u003d /* the signed worked example in RFC7515 A-1 */\n+\t \u0022eyJhbGciOiJSUzI1NiJ9\u0022\n+\t \u0022.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt\u0022\n+\t \u0022cGxlLmNvbS9pc19yb290Ijp0cnVlfQ\u0022\n+\t \u0022.cC4hiUPoj9Eetdgtv3hF80EGrhuB__dzERat0XF9g2VtQgr9PJbu3XOiZj5RZmh7\u0022\n+\t \u0022AAuHIm4Bh-0Qc_lF5YKt_O8W2Fp5jujGbds9uJdbF9CUAr7t1dnZcAcQjbKBYNX4\u0022\n+\t \u0022BAynRFdiuB--f_nZLgrnbyTyWzO75vRK5h6xBArLIARNPvkSjtQBMHlb1L07Qe7K\u0022\n+\t \u00220GarZRmB_eSN9383LcOLn6_dO--xi12jzDwusC-eOkHWEsqtFZESc6BfI7noOPqv\u0022\n+\t \u0022hJ1phCnvWh6IeYI2w9QOYEUipUTI8np6LbgGY9Fs98rqVt5AXLIhWkWywlVmtVrB\u0022\n+\t \u0022p0igcN_IoypGlUPQGe77Rw\u0022;\n+\n+/*\n+ * These are the inputs and outputs from the worked example in RFC7515\n+ * Appendix A.1.\n+ *\n+ * 1) has a fixed header + payload, and a fixed SHA256 HMAC key, and must give\n+ * a fixed BASE64URL result.\n+ *\n+ * 2) has a fixed header + payload and is signed with a key given in JWK format\n+ */\n+int\n+test_jws(struct lws_context *context)\n+{\n+\tstruct lws_genhmac_ctx ctx;\n+\tstruct lws_jwk jwk;\n+\tchar buf[2048], *p \u003d buf, *end \u003d buf + sizeof(buf) - 1, *enc_ptr, *p1;\n+\tuint8_t digest[LWS_GENHASH_LARGEST];\n+\tint n;\n+\n+\t/* Test 1: SHA256 on RFC7515 worked example */\n+\n+\t/* 1.1: decode the JWK oct key */\n+\n+\tif (lws_jwk_import(\u0026jwk, NULL, NULL, key_jwk, strlen(key_jwk)) \u003c 0) {\n+\t\tlwsl_notice(\u0022Failed to decode JWK test key\u005cn\u0022);\n+\t\treturn -1;\n+\t}\n+\tif (jwk.kty !\u003d LWS_JWK_KYT_OCT) {\n+\t\tlwsl_err(\u0022%s: unexpected kty %d\u005cn\u0022, __func__, jwk.kty);\n+\n+\t\treturn -1;\n+\t}\n+\n+\t/* 1.2: create JWS known hdr + known payload */\n+\n+\tn \u003d lws_jws_encode_section(test1, strlen(test1), 1, \u0026p, end);\n+\tif (n \u003c 0)\n+\t\tgoto bail;\n+\tif (strcmp(buf, test1_enc))\n+\t\tgoto bail;\n+\n+\tenc_ptr \u003d p + 1; /* + 1 skips the . */\n+\tn \u003d lws_jws_encode_section(test2, strlen(test2), 0, \u0026p, end);\n+\tif (n \u003c 0)\n+\t\tgoto bail;\n+\tif (strcmp(enc_ptr, test2_enc))\n+\t\tgoto bail;\n+\n+\t/* 1.3: use HMAC SHA-256 with known key on the hdr . payload */\n+\n+\tif (lws_genhmac_init(\u0026ctx, LWS_GENHMAC_TYPE_SHA256,\n+\t\t\t jwk.e[JWK_OCT_KEYEL_K].buf,\n+\t\t\t jwk.e[JWK_OCT_KEYEL_K].len))\n+\t\tgoto bail;\n+\tif (lws_genhmac_update(\u0026ctx, (uint8_t *)buf, p - buf))\n+\t\tgoto bail_destroy_hmac;\n+\tlws_genhmac_destroy(\u0026ctx, digest);\n+\n+\t/* 1.4: append a base64 encode of the computed HMAC digest */\n+\n+\tenc_ptr \u003d p + 1; /* + 1 skips the . */\n+\tn \u003d lws_jws_encode_section((const char *)digest, 32, 0, \u0026p, end);\n+\tif (n \u003c 0)\n+\t\tgoto bail;\n+\tif (strcmp(enc_ptr, hash_enc)) { /* check against known B64URL hash */\n+\t\tlwsl_err(\u0022%s: b64 enc of computed HMAC mismatches '%s' '%s'\u005cn\u0022,\n+\t\t\t __func__, enc_ptr, hash_enc);\n+\t\tgoto bail;\n+\t}\n+\n+\t/* 1.5: Check we can agree the signature matches the payload */\n+\n+\tif (lws_jws_confirm_sig(buf, p - buf, \u0026jwk, context) \u003c 0) {\n+\t\tlwsl_notice(\u0022confirm sig failed\u005cn\u0022);\n+\t\tgoto bail;\n+\t}\n+\n+\tlws_jwk_destroy(\u0026jwk); /* finished with the key from the first test */\n+\n+\t/* Test 2: RSA256 on RFC7515 worked example */\n+\n+\t/* 2.1: turn the known JWK key for the RSA test into a lws_jwk */\n+\n+\tif (lws_jwk_import(\u0026jwk, NULL, NULL,\n+\t\t\t rfc7515_rsa_key, strlen(rfc7515_rsa_key))) {\n+\t\tlwsl_notice(\u0022%s: 2.2: Failed to read JWK key\u005cn\u0022, __func__);\n+\t\tgoto bail2;\n+\t}\n+\n+\tif (jwk.kty !\u003d LWS_JWK_KYT_RSA) {\n+\t\tlwsl_err(\u0022%s: 2.2: kty: %d instead of RSA\u005cn\u0022, __func__, jwk.kty);\n+\t}\n+\n+\t/* 2.2: check the signature on the test packet from RFC7515 A-1 */\n+\n+\tif (lws_jws_confirm_sig(rfc7515_rsa_a1, strlen(rfc7515_rsa_a1),\n+\t\t\t\t\u0026jwk, context) \u003c 0) {\n+\t\tlwsl_notice(\u0022%s: 2.2: confirm rsa sig failed\u005cn\u0022, __func__);\n+\t\tgoto bail;\n+\t}\n+\n+\t/* 2.3: generate our own signature for a copy of the test packet */\n+\n+\tmemcpy(buf, rfc7515_rsa_a1, strlen(rfc7515_rsa_a1));\n+\n+\t/* set p to second . */\n+\tp \u003d strchr(buf + 1, '.');\n+\tp1 \u003d strchr(p + 1, '.');\n+\n+\tn \u003d lws_jws_sign_from_b64(buf, p - buf, p + 1, p1 - (p + 1),\n+\t\t\t\t p1 + 1, sizeof(buf) - (p1 - buf) - 1,\n+\t\t\t\t LWS_GENHASH_TYPE_SHA256, \u0026jwk, context);\n+\tif (n \u003c 0) {\n+\t\tlwsl_err(\u0022%s: failed signing test packet\u005cn\u0022, __func__);\n+\t\tgoto bail;\n+\t}\n+\n+\t// puts(buf);\n+\n+\t/* 2.4: confirm our signature can be verified */\n+\n+\tif (lws_jws_confirm_sig(buf, (p1 + 1 + n) - buf, \u0026jwk, context) \u003c 0) {\n+\t\tlwsl_notice(\u0022confirm rsa sig 2 failed\u005cn\u0022);\n+\t\tgoto bail;\n+\t}\n+\n+\tlws_jwk_destroy(\u0026jwk);\n+\n+\t/* end */\n+\n+\tlwsl_notice(\u0022%s: selftest OK\u005cn\u0022, __func__);\n+\n+\treturn 0;\n+\n+bail_destroy_hmac:\n+\tlws_genhmac_destroy(\u0026ctx, NULL);\n+\n+bail:\n+\tlws_jwk_destroy(\u0026jwk);\n+bail2:\n+\tlwsl_err(\u0022%s: selftest failed ++++++++++++++++++++\u005cn\u0022, __func__);\n+\n+\treturn 1;\n+}\ndiff --git a/minimal-examples/api-tests/api-test-jose/main.c b/minimal-examples/api-tests/api-test-jose/main.c\nnew file mode 100644\nindex 0000000..3a5b27b\n--- /dev/null\n+++ b/minimal-examples/api-tests/api-test-jose/main.c\n@@ -0,0 +1,51 @@\n+/*\n+ * lws-api-test-jose\n+ *\n+ * Copyright (C) 2018 Andy Green \u003candy@warmcat.com\u003e\n+ *\n+ * This file is made available under the Creative Commons CC0 1.0\n+ * Universal Public Domain Dedication.\n+ */\n+\n+#include \u003clibwebsockets.h\u003e\n+\n+int\n+test_jwk(struct lws_context *context);\n+int\n+test_jws(struct lws_context *context);\n+int\n+test_jwe(struct lws_context *context);\n+\n+int main(int argc, const char **argv)\n+{\n+\tstruct lws_context_creation_info info;\n+\tstruct lws_context *context;\n+\tconst char *p;\n+\tint result \u003d 0, logs \u003d LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;\n+\n+\tif ((p \u003d lws_cmdline_option(argc, argv, \u0022-d\u0022)))\n+\t\tlogs \u003d atoi(p);\n+\n+\tlws_set_log_level(logs, NULL);\n+\tlwsl_user(\u0022LWS JOSE api tests\u005cn\u0022);\n+\n+\tmemset(\u0026info, 0, sizeof info); /* otherwise uninitialized garbage */\n+\tinfo.port \u003d CONTEXT_PORT_NO_LISTEN;\n+\tinfo.options \u003d 0;\n+\n+\tcontext \u003d lws_create_context(\u0026info);\n+\tif (!context) {\n+\t\tlwsl_err(\u0022lws init failed\u005cn\u0022);\n+\t\treturn 1;\n+\t}\n+\n+\tresult |\u003d test_jwk(context);\n+\tresult |\u003d test_jws(context);\n+\tresult |\u003d test_jwe(context);\n+\n+\tlwsl_user(\u0022Completed: %s\u005cn\u0022, result ? \u0022FAIL\u0022 : \u0022PASS\u0022);\n+\n+\tlws_context_destroy(context);\n+\n+\treturn result;\n+}\ndiff --git a/minimal-examples/api-tests/api-test-jose/selftest.sh b/minimal-examples/api-tests/api-test-jose/selftest.sh\nnew file mode 100755\nindex 0000000..16d1e2e\n--- /dev/null\n+++ b/minimal-examples/api-tests/api-test-jose/selftest.sh\n@@ -0,0 +1,24 @@\n+#!/bin/bash\n+#\n+# $1: path to minimal example binaries...\n+# if lws is built with -DLWS_WITH_MINIMAL_EXAMPLES\u003d1\n+# that will be ./bin from your build dir\n+#\n+# $2: path for logs and results. The results will go\n+# in a subdir named after the directory this script\n+# is in\n+#\n+# $3: offset for test index count\n+#\n+# $4: total test count\n+#\n+# $5: path to ./minimal-examples dir in lws\n+#\n+# Test return code 0: OK, 254: timed out, other: error indication\n+\n+. $5/selftests-library.sh\n+\n+COUNT_TESTS\u003d1\n+\n+dotest $1 $2 apiselftest\n+exit $FAILS\ndiff --git a/plugins/acme-client/protocol_lws_acme_client.c b/plugins/acme-client/protocol_lws_acme_client.c\nindex c10b411..c30056c 100644\n--- a/plugins/acme-client/protocol_lws_acme_client.c\n+++ b/plugins/acme-client/protocol_lws_acme_client.c\n@@ -435,13 +435,14 @@ lws_acme_load_create_auth_keys(struct per_vhost_data__lws_acme_client *vhd,\n {\n \tint n;\n \n-\tif (!lws_jwk_load(\u0026vhd-\u003ejwk, vhd-\u003epvop[LWS_TLS_SET_AUTH_PATH]))\n+\tif (!lws_jwk_load(\u0026vhd-\u003ejwk, vhd-\u003epvop[LWS_TLS_SET_AUTH_PATH],\n+\t\t\t NULL, NULL))\n \t\treturn 0;\n \n-\tstrcpy(vhd-\u003ejwk.keytype, \u0022RSA\u0022);\n+\tvhd-\u003ejwk.kty \u003d LWS_JWK_KYT_RSA;\n \tlwsl_notice(\u0022Generating ACME %d-bit keypair... \u0022\n \t\t \u0022will take a little while\u005cn\u0022, bits);\n-\tn \u003d lws_genrsa_new_keypair(vhd-\u003econtext, \u0026vhd-\u003ersactx, \u0026vhd-\u003ejwk.el,\n+\tn \u003d lws_genrsa_new_keypair(vhd-\u003econtext, \u0026vhd-\u003ersactx, vhd-\u003ejwk.e,\n \t\t\t\t bits);\n \tif (n) {\n \t\tlwsl_notice(\u0022failed to create keypair\u005cn\u0022);\n@@ -786,7 +787,8 @@ pkt_add_hdrs:\n \t\t\t\t\t\t\tac-\u003ereplay_nonce,\n \t\t\t\t\t\t\t\u0026ac-\u003ebuf[LWS_PRE],\n \t\t\t\t\t\t\tsizeof(ac-\u003ebuf) -\n-\t\t\t\t\t\t\t\t LWS_PRE);\n+\t\t\t\t\t\t\t\t LWS_PRE,\n+\t\t\t\t\t\t\tlws_get_context(wsi));\n \t\t\tif (ac-\u003elen \u003c 0) {\n \t\t\t\tac-\u003elen \u003d 0;\n \t\t\t\tlwsl_notice(\u0022lws_jws_create_packet failed\u005cn\u0022);\ndiff --git a/plugins/ssh-base/sshd.c b/plugins/ssh-base/sshd.c\nindex 980e4eb..baa79e8 100644\n--- a/plugins/ssh-base/sshd.c\n+++ b/plugins/ssh-base/sshd.c\n@@ -548,7 +548,7 @@ lws_ssh_exec_finish(void *finish_handle, int retcode)\n static int\n lws_ssh_parse_plaintext(struct per_session_data__sshd *pss, uint8_t *p, size_t len)\n {\n-\tstruct lws_genrsa_elements el;\n+\tstruct lws_jwk_elements e[LWS_COUNT_RSA_KEY_ELEMENTS];\n \tstruct lws_genrsa_ctx ctx;\n \tstruct lws_ssh_channel *ch;\n \tstruct lws_subprotocol_scp *scp;\n@@ -1247,19 +1247,19 @@ again:\n \t\t\t * the E and N factors\n \t\t\t */\n \n-\t\t\tmemset(\u0026el, 0, sizeof(el));\n+\t\t\tmemset(e, 0, sizeof(e));\n \t\t\tpp \u003d pss-\u003eua-\u003epubkey;\n \t\t\tm \u003d lws_g32(\u0026pp);\n \t\t\tpp +\u003d m;\n \t\t\tm \u003d lws_g32(\u0026pp);\n-\t\t\tel.e[JWK_KEY_E].buf \u003d pp;\n-\t\t\tel.e[JWK_KEY_E].len \u003d m;\n+\t\t\te[JWK_RSA_KEYEL_E].buf \u003d pp;\n+\t\t\te[JWK_RSA_KEYEL_E].len \u003d m;\n \t\t\tpp +\u003d m;\n \t\t\tm \u003d lws_g32(\u0026pp);\n-\t\t\tel.e[JWK_KEY_N].buf \u003d pp;\n-\t\t\tel.e[JWK_KEY_N].len \u003d m;\n+\t\t\te[JWK_RSA_KEYEL_N].buf \u003d pp;\n+\t\t\te[JWK_RSA_KEYEL_N].len \u003d m;\n \n-\t\t\tif (lws_genrsa_create(\u0026ctx, \u0026el))\n+\t\t\tif (lws_genrsa_create(\u0026ctx, e, pss-\u003evhd-\u003econtext))\n \t\t\t\tgoto ua_fail;\n \n \t\t\t/*\ndiff --git a/scripts/libwebsockets.spec b/scripts/libwebsockets.spec\nindex 84790b1..dd90a4f 100644\n--- a/scripts/libwebsockets.spec\n+++ b/scripts/libwebsockets.spec\n@@ -110,6 +110,7 @@ rm -rf $RPM_BUILD_ROOT\n \u0022/usr/include/libwebsockets/lws-genhash.h\u0022\n \u0022/usr/include/libwebsockets/lws-genrsa.h\u0022\n \u0022/usr/include/libwebsockets/lws-http.h\u0022\n+\u0022/usr/include/libwebsockets/lws-jose.h\u0022\n \u0022/usr/include/libwebsockets/lws-jwk.h\u0022\n \u0022/usr/include/libwebsockets/lws-jws.h\u0022\n \u0022/usr/include/libwebsockets/lws-lejp.h\u0022\n","s":{"c":1747291576,"u": 40215}}
],"g": 1395881,"chitpc": 0,"ehitpc": 0,"indexed":0
,
"ab": 0, "si": 0, "db":0, "di":0, "sat":0, "lfc": "0000"}