From eda102e39760b89d94a76a2b58cd052752874c80 Mon Sep 17 00:00:00 2001 From: Andy Green Date: Thu, 13 Dec 2018 20:05:12 +0800 Subject: [PATCH] jwe --- .gitignore | 1 + .travis.yml | 4 +- CMakeLists.txt | 91 +- README.md | 48 +- READMEs/README.crypto-apis.md | 18 +- changelog | 6 + cmake/lws_config.h.in | 11 +- doc-assets/lws-overview.png | Bin 0 -> 519276 bytes doc-assets/lws-overview.svg | 335 --- include/libwebsockets.h | 5 +- include/libwebsockets/lws-genaes.h | 23 +- include/libwebsockets/lws-gencrypto.h | 33 +- include/libwebsockets/lws-genec.h | 26 +- include/libwebsockets/lws-genrsa.h | 72 +- include/libwebsockets/lws-jose.h | 91 +- include/libwebsockets/lws-jwe.h | 94 +- include/libwebsockets/lws-jwk.h | 65 +- include/libwebsockets/lws-jws.h | 325 ++- include/libwebsockets/lws-lejp.h | 4 + include/libwebsockets/lws-misc.h | 16 + lib/core/libwebsockets.c | 20 +- lib/core/output.c | 3 +- lib/jose/README.md | 25 +- lib/jose/jwe/jwe-aeskw.c | 192 ++ lib/jose/jwe/jwe-rsa-aescbc.c | 437 ++++ lib/jose/jwe/jwe-rsa-aesgcm.c | 349 +++ lib/jose/jwe/jwe.c | 439 +++- lib/jose/jwe/private.h | 50 + lib/jose/jwk/jwk.c | 708 ++++-- lib/jose/jws/jose.c | 146 +- lib/jose/jws/jws.c | 626 ++++- lib/jose/jws/private.h | 8 - lib/jose/private.h | 5 + lib/misc/fts/trie-fd.c | 2 +- lib/misc/lejp.c | 12 +- lib/misc/peer-limits.c | 11 +- lib/roles/http/client/client.c | 9 +- lib/roles/http/server/server.c | 22 +- lib/tls/lws-gencrypto-common.c | 491 +++- lib/tls/lws-genec-common.c | 2 + lib/tls/mbedtls/lws-genaes.c | 166 +- lib/tls/mbedtls/lws-gencrypto.c | 6 +- lib/tls/mbedtls/lws-genec.c | 137 +- lib/tls/mbedtls/lws-genhash.c | 6 + lib/tls/mbedtls/lws-genrsa.c | 110 +- lib/tls/mbedtls/mbedtls-server.c | 2 +- lib/tls/openssl/lws-genaes.c | 98 +- lib/tls/openssl/lws-gencrypto.c | 5 + lib/tls/openssl/lws-genec.c | 243 +- lib/tls/openssl/lws-genhash.c | 8 + lib/tls/openssl/lws-genrsa.c | 65 +- lib/tls/openssl/openssl-client.c | 5 + lib/tls/openssl/openssl-server.c | 5 + lib/tls/openssl/ssl.c | 5 + lib/tls/private.h | 5 + minimal-examples/README.md | 1 + minimal-examples/api-tests/README.md | 9 +- .../api-tests/api-test-gencrypto/lws-genaes.c | 40 +- .../api-tests/api-test-gencrypto/lws-genec.c | 6 +- .../api-tests/api-test-jose/jwe.c | 2259 ++++++++++++++--- .../api-tests/api-test-jose/jws.c | 794 ++++-- .../api-tests/api-test-lwsac/main.c | 2 + minimal-examples/crypto/README.md | 5 + .../crypto/minimal-crypto-jwe/CMakeLists.txt | 77 + .../crypto/minimal-crypto-jwe/README.md | 69 + .../minimal-crypto-jwe/key-rsa-4096.private | 1 + .../minimal-crypto-jwe/key-rsa-4096.pub | 1 + .../crypto/minimal-crypto-jwe/main.c | 264 ++ .../crypto/minimal-crypto-jwk/CMakeLists.txt | 77 + .../crypto/minimal-crypto-jwk/README.md | 51 + .../crypto/minimal-crypto-jwk/main.c | 187 ++ .../crypto/minimal-crypto-jws/CMakeLists.txt | 77 + .../crypto/minimal-crypto-jws/README.md | 59 + .../crypto/minimal-crypto-jws/main.c | 185 ++ .../minimal-http-server-smp.c | 6 +- .../acme-client/protocol_lws_acme_client.c | 10 +- plugins/deaddrop/protocol_lws_deaddrop.c | 8 +- plugins/raw-proxy/protocol_lws_raw_proxy.c | 13 +- plugins/ssh-base/sshd.c | 15 +- scripts/autobahn-test-server.sh | 2 +- test-apps/test-sshd.c | 2 +- 81 files changed, 8280 insertions(+), 1631 deletions(-) create mode 100644 doc-assets/lws-overview.png delete mode 100644 doc-assets/lws-overview.svg create mode 100644 lib/jose/jwe/jwe-aeskw.c create mode 100644 lib/jose/jwe/jwe-rsa-aescbc.c create mode 100644 lib/jose/jwe/jwe-rsa-aesgcm.c create mode 100644 lib/jose/jwe/private.h create mode 100644 minimal-examples/crypto/README.md create mode 100644 minimal-examples/crypto/minimal-crypto-jwe/CMakeLists.txt create mode 100644 minimal-examples/crypto/minimal-crypto-jwe/README.md create mode 100644 minimal-examples/crypto/minimal-crypto-jwe/key-rsa-4096.private create mode 100644 minimal-examples/crypto/minimal-crypto-jwe/key-rsa-4096.pub create mode 100644 minimal-examples/crypto/minimal-crypto-jwe/main.c create mode 100644 minimal-examples/crypto/minimal-crypto-jwk/CMakeLists.txt create mode 100644 minimal-examples/crypto/minimal-crypto-jwk/README.md create mode 100644 minimal-examples/crypto/minimal-crypto-jwk/main.c create mode 100644 minimal-examples/crypto/minimal-crypto-jws/CMakeLists.txt create mode 100644 minimal-examples/crypto/minimal-crypto-jws/README.md create mode 100644 minimal-examples/crypto/minimal-crypto-jws/main.c diff --git a/.gitignore b/.gitignore index 19199b1b7..5805b27d4 100644 --- a/.gitignore +++ b/.gitignore @@ -51,3 +51,4 @@ doc /build3/ /cov-int/ /.vs/ +/build-mtls/ diff --git a/.travis.yml b/.travis.yml index d7fa222e2..fb94419c6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,10 +4,10 @@ env: global: - secure: "KhAdQ9ja+LBObWNQTYO7Df5J4DyOih6S+eerDMu8UPSO+CoWV2pWoQzbOfocjyOscGOwC+2PrrHDNZyGfqkCLDXg1BxynXPCFerHC1yc2IajvKpGXmAAygNIvp4KACDfGv/dkXrViqIzr/CdcNaU4vIMHSVb5xkeLi0W1dPnQOI=" matrix: - - LWS_METHOD=lwsws CMAKE_ARGS="-DLWS_WITH_LWSWS=ON -DLWS_WITHOUT_EXTENSIONS=0 -DLWS_WITH_HTTP2=1 -DLWS_WITH_ACME=1 -DLWS_WITH_MINIMAL_EXAMPLES=1 -DCMAKE_BUILD_TYPE=DEBUG -DLWS_ROLE_DBUS=1 -DLWS_DBUS_INCLUDE2=/usr/lib/x86_64-linux-gnu/dbus-1.0/include/ -DLWS_WITH_JWS=1 -DLWS_WITH_GENRSA=1 -DLWS_WITH_GENHASH=1 -DLWS_WITH_GENAES=1 -DLWS_WITH_GENEC=1" + - LWS_METHOD=lwsws CMAKE_ARGS="-DLWS_WITH_LWSWS=ON -DLWS_WITHOUT_EXTENSIONS=0 -DLWS_WITH_HTTP2=1 -DLWS_WITH_ACME=1 -DLWS_WITH_MINIMAL_EXAMPLES=1 -DCMAKE_BUILD_TYPE=DEBUG -DLWS_ROLE_DBUS=1 -DLWS_DBUS_INCLUDE2=/usr/lib/x86_64-linux-gnu/dbus-1.0/include/ -DLWS_WITH_GENCRYPTO=1 -DLWS_WITH_JOSE=1" - LWS_METHOD=lwsws2 CMAKE_ARGS="-DLWS_WITH_LWSWS=ON -DLWS_WITHOUT_EXTENSIONS=0 -DLWS_WITH_HTTP2=1 -DLWS_WITH_ACME=1 -DLWS_WITH_MINIMAL_EXAMPLES=1 -DCMAKE_BUILD_TYPE=DEBUG -DLWS_ROLE_DBUS=1 -DLWS_DBUS_INCLUDE2=/usr/lib/x86_64-linux-gnu/dbus-1.0/include/" - LWS_METHOD=default CMAKE_ARGS="-DLWS_WITH_MINIMAL_EXAMPLES=1" - - LWS_METHOD=mbedtls CMAKE_ARGS="-DLWS_WITH_MBEDTLS=1 -DLWS_WITH_HTTP2=1 -DLWS_WITH_LWSWS=1 -DLWS_WITH_MINIMAL_EXAMPLES=1 -DCMAKE_BUILD_TYPE=DEBUG" + - LWS_METHOD=mbedtls CMAKE_ARGS="-DLWS_WITH_MBEDTLS=1 -DLWS_WITH_HTTP2=1 -DLWS_WITH_LWSWS=1 -DLWS_WITH_MINIMAL_EXAMPLES=1 -DLWS_WITH_JOSE=1 -DCMAKE_BUILD_TYPE=DEBUG" - LWS_METHOD=noserver CMAKE_ARGS="-DLWS_WITHOUT_SERVER=ON -DLWS_WITH_MINIMAL_EXAMPLES=1" - LWS_METHOD=noclient CMAKE_ARGS="-DLWS_WITHOUT_CLIENT=ON -DLWS_WITH_MINIMAL_EXAMPLES=1" - LWS_METHOD=noext CMAKE_ARGS="-DLWS_WITHOUT_EXTENSIONS=ON -DLWS_WITH_MINIMAL_EXAMPLES=1" diff --git a/CMakeLists.txt b/CMakeLists.txt index 088cb1c26..63bc25cc8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -105,12 +105,8 @@ option(LWS_WITH_SMTP "Provide SMTP support" OFF) option(LWS_WITH_NO_LOGS "Disable all logging from being compiled in" OFF) option(LWS_AVOID_SIGPIPE_IGN "Android 7+ reportedly needs this" OFF) option(LWS_WITH_STATS "Keep statistics of lws internal operations" OFF) -option(LWS_WITH_JWS "JSON Web Signature (RFC7515) API" OFF) -option(LWS_WITH_JWE "JSON Web Encryption (RFC7516) API" OFF) -option(LWS_WITH_GENHASH "Enable support for Generic Hash (SHA1 + SHA2 with api independent of TLS backend)" OFF) -option(LWS_WITH_GENRSA "Enable support for Generic RSA (RSA with api independent of TLS backend)" OFF) -option(LWS_WITH_GENAES "Enable support for Generic AES (AES with api independent of TLS backend)" OFF) -option(LWS_WITH_GENEC "Enable support for Generic EC (EC with api independent of TLS backend)" OFF) +option(LWS_WITH_JOSE "JSON Web Signature / Encryption / Keys (RFC7515/6/) API" OFF) +option(LWS_WITH_GENCRYPTO "Enable support for Generic Crypto apis independent of TLS backend" OFF) option(LWS_WITH_SELFTESTS "Selftests run at context creation" OFF) option(LWS_WITH_GCOV "Build with gcc gcov coverage instrumentation" OFF) option(LWS_WITH_EXPORT_LWSTARGETS "Export libwebsockets CMake targets. Disable if they conflict with an outer cmake project." ON) @@ -159,11 +155,8 @@ if(LWS_WITH_DISTRO_RECOMMENDED) set(LWS_WITH_LEJP_CONF 1) set(LWS_WITH_PLUGINS 1) set(LWS_ROLE_RAW_PROXY 1) - set(LWS_WITH_GENHASH 1) - set(LWS_WITH_GENRSA 1) - set(LWS_WITH_GENEC 1) - set(LWS_WITH_JWS 1) - set(LWS_WITH_JWE 1) + set(LWS_WITH_GENCRYPTO 1) + set(LWS_WITH_JOSE 1) endif() # do you care about this? Then send me a patch where it disables it on travis @@ -292,6 +285,11 @@ if (LWS_WITH_LWSWS) set(LWS_ROLE_RAW_PROXY 1) endif() +# sshd plugin +if (LWS_WITH_PLUGINS) + set(LWS_WITH_GENCRYPTO 1) +endif() + if (LWS_ROLE_RAW_PROXY) set (LWS_WITHOUT_CLIENT 0) set (LWS_WITHOUT_SERVER 0) @@ -300,19 +298,12 @@ endif() if (LWS_WITH_ACME) set (LWS_WITHOUT_CLIENT 0) set (LWS_WITHOUT_SERVER 0) - set (LWS_WITH_JWS 1) - set (LWS_WITH_JWE 1) + set (LWS_WITH_JOSE 1) endif() -if (LWS_WITH_JWE) - set(LWS_WITH_JWS 1) -endif() - -if (LWS_WITH_JWS) +if (LWS_WITH_JOSE) set(LWS_WITH_LEJP 1) - set(LWS_WITH_GENHASH 1) - set(LWS_WITH_GENRSA 1) - set(LWS_WITH_GENEC 1) + set(LWS_WITH_GENCRYPTO 1) endif() if (LWS_WITH_PLUGINS AND NOT LWS_WITH_LIBUV) @@ -327,8 +318,7 @@ endif() if (LWS_WITH_PLUGINS OR LWS_WITH_CGI) # sshd plugin - set(LWS_WITH_GENHASH 1) - set(LWS_WITH_GENRSA 1) + set(LWS_WITH_GENCRYPTO 1) endif() if (LWS_WITH_GENERIC_SESSIONS) @@ -1025,29 +1015,13 @@ if (LWS_WITH_SSL) list(APPEND SOURCES lib/tls/mbedtls/ssl.c ) - if (LWS_WITH_GENHASH) + if (LWS_WITH_GENCRYPTO) list(APPEND SOURCES lib/tls/mbedtls/lws-genhash.c - ) - endif() - if (LWS_WITH_GENRSA) - list(APPEND SOURCES lib/tls/mbedtls/lws-genrsa.c - ) - endif() - if (LWS_WITH_GENAES) - list(APPEND SOURCES lib/tls/mbedtls/lws-genaes.c - ) - endif() - if (LWS_WITH_GENEC) - list(APPEND SOURCES lib/tls/lws-genec-common.c lib/tls/mbedtls/lws-genec.c - ) - endif() - if (LWS_WITH_GENEC OR LWS_WITH_GENRSA) - list(APPEND SOURCES lib/tls/mbedtls/lws-gencrypto.c ) endif() @@ -1055,29 +1029,13 @@ if (LWS_WITH_SSL) list(APPEND SOURCES lib/tls/openssl/ssl.c ) - if (LWS_WITH_GENHASH) + if (LWS_WITH_GENCRYPTO) list(APPEND SOURCES lib/tls/openssl/lws-genhash.c - ) - endif() - if (LWS_WITH_GENRSA) - list(APPEND SOURCES lib/tls/openssl/lws-genrsa.c - ) - endif() - if (LWS_WITH_GENAES) - list(APPEND SOURCES lib/tls/openssl/lws-genaes.c - ) - endif() - if (LWS_WITH_GENEC) - list(APPEND SOURCES lib/tls/lws-genec-common.c lib/tls/openssl/lws-genec.c - ) - endif() - if (LWS_WITH_GENEC OR LWS_WITH_GENRSA) - list(APPEND SOURCES lib/tls/openssl/lws-gencrypto.c ) endif() @@ -1235,19 +1193,19 @@ if (LWS_WITH_ZIP_FOPS) endif() endif() -if (LWS_WITH_JWS) +if (LWS_WITH_JOSE) list(APPEND SOURCES lib/jose/jwk/jwk.c lib/jose/jws/jose.c - lib/jose/jws/jws.c) + lib/jose/jws/jws.c + lib/jose/jwe/jwe.c + lib/jose/jwe/jwe-rsa-aescbc.c + lib/jose/jwe/jwe-aeskw.c + lib/jose/jwe/jwe-rsa-aesgcm.c + ) endif() -if (LWS_WITH_JWE) - list(APPEND SOURCES - lib/jose/jwe/jwe.c) -endif() - -if (LWS_WITH_JWE OR LWS_WITH_JWS OR LWS_WITH_GENHASH) +if (LWS_WITH_JOSE OR LWS_WITH_GENCRYPTO) list(APPEND SOURCES lib/tls/lws-gencrypto-common.c) endif() @@ -1685,6 +1643,9 @@ CHECK_FUNCTION_EXISTS(SSL_CTX_set_ciphersuites LWS_HAVE_SSL_CTX_set_ciphersuites if (LWS_WITH_SSL AND NOT LWS_WITH_MBEDTLS) CHECK_SYMBOL_EXISTS(SSL_CTX_get_extra_chain_certs_only openssl/ssl.h LWS_HAVE_SSL_EXTRA_CHAIN_CERTS) CHECK_FUNCTION_EXISTS(EVP_MD_CTX_free LWS_HAVE_EVP_MD_CTX_free) +CHECK_FUNCTION_EXISTS(ECDSA_SIG_set0 LWS_HAVE_ECDSA_SIG_set0) +CHECK_FUNCTION_EXISTS(BN_bn2binpad LWS_HAVE_BN_bn2binpad) +CHECK_FUNCTION_EXISTS(EVP_aes_128_wrap LWS_HAVE_EVP_aes_128_wrap) endif() if (LWS_WITH_MBEDTLS) set(LWS_HAVE_TLS_CLIENT_METHOD 1) diff --git a/README.md b/README.md index 958641f70..0fc8526dd 100644 --- a/README.md +++ b/README.md @@ -11,14 +11,56 @@ cloud serving. [50 minimal examples](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples) for various scenarios, CC0-licensed (public domain) for cut-and-paste, allow you to get started quickly. -![overview](./doc-assets/lws-overview.svg) +![overview](./doc-assets/lws-overview.png) News ---- ## New features on master - - **`lws-genec` ECDH + ECDSA** - Work in progress + - CMake config simplification for crypto: `-DLWS_WITH_GENCRYPTO=1` for all + generic cipher and hash apis built (which work the same on mbedtls and + OpenSSL transparently), and `-DLWS_WITH_JOSE=1` for all JOSE, JWK, JWS + and JWE support built (which use gencrypto and so also work the same + regardless of tls library backend). + + - **`JWE`** - JWE (RFC7516) Work in progress: Working CI tests + +|Key Encryption|Payload authentication + crypt|Enc + Dec Support| +|---|---|---| +|`RSAES-PKCS1-v1.5` 2048b & 4096b|`AES_128_CBC_HMAC_SHA_256`|Enc + Dec| +|`RSAES-PKCS1-v1.5` 2048b|`AES_192_CBC_HMAC_SHA_384`|Enc + Dec| +|`RSAES-PKCS1-v1.5` 2048b|`AES_256_CBC_HMAC_SHA_512`|Enc + Dec| +|`RSAES-OAEP`|`AES_256_GCM`|Enc + Dec| +|`AES128KW`, `AES192KW`, `AES256KW`|`AES_128_CBC_HMAC_SHA_256`|Enc + Dec| +|`AES128KW`, `AES192KW`, `AES256KW`|`AES_192_CBC_HMAC_SHA_384`|Enc + Dec| +|`AES128KW`, `AES192KW`, `AES256KW`|`AES_256_CBC_HMAC_SHA_512`|Enc + Dec| +|`ECDH-ES` P-256|`AES_128_GCM`|Dec| + +All tests pass on both OpenSSL and mbedTLS backends, using keys generated on +both OpenSSL and mbedTLS in the tests. + +A minimal example tool shows how to encrypt and decrypt compact JWE objects +from the commandline for all supported algorithms. + + [jwe api](https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/lws-jwe.h), + [jwe unit tests](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/api-tests/api-test-jose/jwe.c), + [jwe minimal example](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/crypto/minimal-crypto-jwe) + + - **`lws-genec` ECDSA** - JWS-compatible ECDSA is supported on both OpenSSL and mbedtls... Work in progress: ECDH-ES + + - **`JWS`** - JWS (RFC7515) is now supported for none, HS256/384/512, RS256/384/512, and ES256/384/512, on both OpenSSL and mbedtls. There's a minimal example tool that signs and verifies compact + representation JWS from stdin. + [jws api](https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/lws-jws.h), + [jws unit tests](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/api-tests/api-test-jose/jws.c), + [jws minimal example](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/crypto/minimal-crypto-jwe) + + - **`JWK`** - JWK (RFC7517) now supports oct, RSA and EC keys including JSON key + arrays on both OpenSSL and mbedtls. A minimal example tool shows how to create + new JSON JWK keys to specified parameters from the commandline for all supported + ciphers. + + [jwk minimal example](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/crypto/minimal-crypto-jwk) - **`lws-genrsa` OAEP + PSS support** - in addition to PKCS#1 1.5 padding, OAEP and PSS are now supported on both mbedtls and openssl backends. @@ -27,7 +69,7 @@ News backends. Supports CBC, CFB128, CFB8, CTR, ECB, OFB, XTS and GCM variants. Unit tests in CI. [genaes api](https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/lws-genaes.h), [api test](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/api-tests/api-test-gencrypto), - CMake config: `-DLWS_WITH_GENAES=1` + CMake config: `-DLWS_WITH_GENCRYPTO=1` - **http fallback support** - you can specify a role and protocol to apply if non-http or non-tls packets arrive at an http(s) listen port. For example, you can specify that the new `raw proxy` diff --git a/READMEs/README.crypto-apis.md b/READMEs/README.crypto-apis.md index c8a067756..88e4695f5 100644 --- a/READMEs/README.crypto-apis.md +++ b/READMEs/README.crypto-apis.md @@ -15,6 +15,19 @@ or via another layer on top, which processes JOSE JSON objects using JWS (JSON Web Signatures), JWK (JSON Web Keys), and JWE (JSON Web Encryption). +The `JW` apis use the generic apis (`lws_genrsa_`, etc) to get the crypto tasks +done, so anything they can do you can also get done using the generic apis. +The main difference is that with the generic apis, you must instantiate the +correct types and use type-specfic apis. With the `JW` apis, there is only +one interface for all operations, with the details hidden in the api and +controlled by the JSON objects. + +Because of this, the `JW` apis are often preferred because they give you +"crypto agility" cheaply... to change your crypto to another supported algorithm +once it's working, you literally just change your JSON defining the keys and +JWE or JWS algorithm. (It's up to you to define your policy for which +combinations are acceptable by querying the parsed JW structs). + ## Using the generic layer All the necessary includes are part of `libwebsockets.h`. @@ -63,7 +76,7 @@ Unit tests for these apis, which serve as usage examples, can be found in [./min Keys in the JOSE layer use a `struct lws_jwk`, this contains two arrays of `struct lws_jwk_elements` sized for the worst case (currently RSA). One array contains the key elements as described for the generic case, and the -other contains various key metadata taken from JWK JSON. +other contains various nonencrypted key metadata taken from JWK JSON. |metadata index|function| |---|---| @@ -74,3 +87,6 @@ other contains various key metadata taken from JWK JSON. |`JWK_META_X5C`|Optional X.509 cert version of the key| |`JWK_META_ALG`|Optional overall crypto algorithm the key is intended for use with| +`lws_jwk_destroy()` should be called when the jwk is going out of scope... this +takes care to zero down any key element data in the jwk. + diff --git a/changelog b/changelog index 4ce593582..8fd650705 100644 --- a/changelog +++ b/changelog @@ -1,6 +1,12 @@ Changelog --------- + - CHANGE: REMOVED: LWS_WITH_GENRSA, LWS_WITH_GENHASH, LWS_WITH_GENEC, + LWS_WITH_GENAES have all been removed and combined into LWS_WITH_GENCRYPTO + + - CHANGE: REMOVED: LWS_WITH_JWS, LWS_WITH_JWE have been removed and combined + into LWS_WITH_JOSE + v3.1.0 ====== diff --git a/cmake/lws_config.h.in b/cmake/lws_config.h.in index 7c50c29d1..7c6cc5240 100644 --- a/cmake/lws_config.h.in +++ b/cmake/lws_config.h.in @@ -23,7 +23,10 @@ #cmakedefine LWS_HAS_INTPTR_T #cmakedefine LWS_HAVE__ATOI64 #cmakedefine LWS_HAVE_ATOLL +#cmakedefine LWS_HAVE_BN_bn2binpad +#cmakedefine LWS_HAVE_ECDSA_SIG_set0 #cmakedefine LWS_HAVE_EVP_MD_CTX_free +#cmakedefine LWS_HAVE_EVP_aes_128_wrap #cmakedefine LWS_HAVE_LIBCAP #cmakedefine LWS_HAVE_MALLOC_H #cmakedefine LWS_HAVE_NEW_UV_VERSION_H @@ -71,17 +74,13 @@ #cmakedefine LWS_WITH_CGI #cmakedefine LWS_WITH_ESP32 #cmakedefine LWS_WITH_FTS -#cmakedefine LWS_WITH_GENRSA -#cmakedefine LWS_WITH_GENHASH -#cmakedefine LWS_WITH_GENAES -#cmakedefine LWS_WITH_GENEC +#cmakedefine LWS_WITH_GENCRYPTO #cmakedefine LWS_WITH_HTTP2 #cmakedefine LWS_WITH_HTTP_BROTLI #cmakedefine LWS_WITH_HTTP_PROXY #cmakedefine LWS_WITH_HTTP_STREAM_COMPRESSION #cmakedefine LWS_WITH_IPV6 -#cmakedefine LWS_WITH_JWE -#cmakedefine LWS_WITH_JWS +#cmakedefine LWS_WITH_JOSE #cmakedefine LWS_WITH_LEJP #cmakedefine LWS_WITH_LIBEV #cmakedefine LWS_WITH_LIBEVENT diff --git a/doc-assets/lws-overview.png b/doc-assets/lws-overview.png new file mode 100644 index 0000000000000000000000000000000000000000..7355cdfd1ac3d10f02532557a025004cdc31e8e5 GIT binary patch literal 519276 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
    SOnv$!R1aJb++@<6904A?7-(rcbQd188=WSc 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­-B}Tuy;4Ghnqi+oQ zOo4{DYGwArkx@&0X`5SG*iS0*cp6DHIR*8!wc<-0QGLW`J8@`sQps4tD z^_@q<0T@7od=!HjRNxULVTlR$EAH{Mn9C^_=g_LlGSorry0Q`$x-_Va0bfAq;0j{p z#tv=_jBhJ-{NH}G_1=E@lCvR=*8Le8&a9(@F$2YELFjGmCr}0%X>is51$qe~Q?t z|GI?n4M(>t6$#%_Aj94L-xlomV5LK8>$|sL2|gg;*NEhj*$Lm>W<5T_v?KN#A~=qs zcJJ6Rmvb$*a0&Qzs{i~R(?4vrTDLZQVK#gKWB_fnJJQw&acx>w<)V80duM8`)T*(a zXQ`|>KB0;eo~E9@v59gZY+9vr@u8!%5eEM90mLd#?>%J5m!S0M0j{{nSCXAhkixRwb0%goN#J>=?kmGqi0c#t1)8`^)RFnD#3bsm zi9SRp*Gy_1TGC0AQAWchQ|_f0evF{9gyT$(qZ*wRMX>T!n9#%;BcISoi`l!qHp?>p z06lqbJo82fniX&&`awj@VjTt|A2E3K!_;Q}9prar(XGY} zg3guINVu3i;a6FouV!!6ez9A~vc6cm0aXND152fX)0ll1t9?{Ar)kW?&Wi}rp z1akfp==PBvX9!oxhO)<98g!-DMCp#OCk+p9*C!_qkG7zK?$SCsvAM3@q(X`ri;3|8 zO3sU58YKasc4hRtVi-ObB^Bℑ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%0Amv^1&HYX2(!c9I;D6H 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

      Z&eaA>S0gLk^}sUVn&O(N0J@RFGEH`M@1||n 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ⅇ;~3XueZrb2~aG(?8syvtNKFg1SOpBJ`J{43L51E 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%0Dl&~Y?ibT14SdiV8b6AHs=yX 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

      N==calJDk-0NY&ae!vaO2?$gQ*qPh*O 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 Vt4mq?&X@rRJYD@<);T3K0RS$RkO%+( literal 0 HcmV?d00001 diff --git a/doc-assets/lws-overview.svg b/doc-assets/lws-overview.svg deleted file mode 100644 index 7f8e45bcd..000000000 --- a/doc-assets/lws-overview.svg +++ /dev/null @@ -1,335 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - struct lws - - tls - tls ctx - - - - - http1 - - http2 - - - ws - - - - raw - - cgi - - - - - - - - - lws_role - protocol - - - role - - - - - - - - - - struct lws_vhost - struct lws_context - - - - protocol - - - - - - - event loops - - - - - - - - event - uv - poll - ev - - TLS backend - - - - - openSSL - mbedTLS - - - - - - - - - - - - - - - - tcp, udp,unix listensocket(s) - - - - - - - - - - - - - - - tcp, udp,http1,h2, wstls client(s) - - - - - - - - ALPNSNI - ah http headers - - - - - - - event loop - peer trackingbasic auth - logging - - - - - ws ext: pm-def - - - - - - - - ssh - ACME - lws_ringVFSzip_fops - - - - service thread(s) - - - - - - - - diff --git a/include/libwebsockets.h b/include/libwebsockets.h index 78491a76b..e5f234691 100644 --- a/include/libwebsockets.h +++ b/include/libwebsockets.h @@ -367,6 +367,9 @@ typedef unsigned long long lws_filepos_t; typedef long long lws_fileofs_t; typedef uint32_t lws_fop_flags_t; +#define lws_concat_temp(_t, _l) (_t + sizeof(_t) - _l) +#define lws_concat_used(_t, _l) (sizeof(_t) - _l) + /** struct lws_pollargs - argument structure for all external poll related calls * passed in via 'in' */ struct lws_pollargs { @@ -427,8 +430,8 @@ struct lws; #include #include -#include #include +#include #include #include diff --git a/include/libwebsockets/lws-genaes.h b/include/libwebsockets/lws-genaes.h index 1e7c3cdcd..aecb68d31 100644 --- a/include/libwebsockets/lws-genaes.h +++ b/include/libwebsockets/lws-genaes.h @@ -46,6 +46,7 @@ enum enum_aes_modes { LWS_GAESM_OFB, LWS_GAESM_XTS, /* care... requires double-length key */ LWS_GAESM_GCM, + LWS_GAESM_KW, }; enum enum_aes_operation { @@ -53,6 +54,11 @@ enum enum_aes_operation { LWS_GAESO_DEC }; +enum enum_aes_padding { + LWS_GAESP_NO_PADDING, + LWS_GAESP_WITH_PADDING +}; + /* include/libwebsockets/lws-jwk.h must be included before this */ #define LWS_AES_BLOCKSIZE 128 @@ -99,7 +105,7 @@ struct lws_genaes_ctx { LWS_VISIBLE LWS_EXTERN int lws_genaes_create(struct lws_genaes_ctx *ctx, enum enum_aes_operation op, enum enum_aes_modes mode, struct lws_gencrypto_keyelem *el, - int padding, void *engine); + enum enum_aes_padding padding, void *engine); /** lws_genaes_destroy() - Destroy genaes AES context * @@ -119,21 +125,22 @@ lws_genaes_destroy(struct lws_genaes_ctx *ctx, unsigned char *tag, size_t tlen); /** lws_genaes_crypt() - Encrypt or decrypt * * \param ctx: your struct lws_genaes_ctx + * \param in: input plaintext or ciphertext + * \param len: length of input (which is always length of output) + * \param out: output plaintext or ciphertext * \param op: LWS_GAESO_ENC or LWS_GAESO_DEC * \param iv_or_nonce_ctr_or_data_unit_16: NULL, iv, nonce_ctr16, or data_unit16 * \param stream_block_16: pointer to 16-byte stream block for CTR mode only * \param nc_or_iv_off: NULL or pointer to nc, or iv_off - * \param in: input plaintext or ciphertext - * \param len: length of input (which is always length of output) - * \param out: output plaintext or ciphertext + * \param taglen: length of tag * * Encrypts or decrypts using the AES mode set when the ctx was created. * The last three arguments have different meanings depending on the mode: * - * CBC CFB128 CFB8 CTR ECB OFB XTS - * iv_or_nonce_ctr_or_data_unit_16 : iv iv iv nonce NULL iv dataunt - * stream_block_16 : NULL NULL NULL stream NULL NULL NULL - * nc_or_iv_off : NULL iv_off NULL nc_off NULL iv_off NULL + * KW CBC CFB128 CFB8 CTR ECB OFB XTS + * iv_or_nonce_ct.._unit_16 : iv iv iv iv nonce NULL iv dataunt + * stream_block_16 : NULL NULL NULL NULL stream NULL NULL NULL + * nc_or_iv_off : NULL NULL iv_off NULL nc_off NULL iv_off NULL * * For GCM: * diff --git a/include/libwebsockets/lws-gencrypto.h b/include/libwebsockets/lws-gencrypto.h index ab47ca15f..7a0b4d2ad 100644 --- a/include/libwebsockets/lws-gencrypto.h +++ b/include/libwebsockets/lws-gencrypto.h @@ -27,12 +27,12 @@ * no dependency at all on any JOSE type. */ -enum lws_gencrypto_kyt { - LWS_GENCRYPTO_KYT_UNKNOWN, +enum lws_gencrypto_kty { + LWS_GENCRYPTO_KTY_UNKNOWN, - LWS_GENCRYPTO_KYT_OCT, - LWS_GENCRYPTO_KYT_RSA, - LWS_GENCRYPTO_KYT_EC + LWS_GENCRYPTO_KTY_OCT, + LWS_GENCRYPTO_KTY_RSA, + LWS_GENCRYPTO_KTY_EC }; /* @@ -92,3 +92,26 @@ struct lws_gencrypto_keyelem { uint8_t *buf; uint16_t len; }; + + +/** + * lws_gencrypto_bits_to_bytes() - returns rounded up bytes needed for bits + * + * \param bits + * + * Returns the number of bytes needed to store the given number of bits. If + * a byte is partially used, the byte count is rounded up. + */ +LWS_VISIBLE LWS_EXTERN int +lws_gencrypto_bits_to_bytes(int bits); + +/** + * lws_base64_size() - returns estimated size of base64 encoding + * + * \param bytes + * + * Returns a slightly oversize estimate of the size of a base64 encoded version + * of the given amount of unencoded data. + */ +LWS_VISIBLE LWS_EXTERN int +lws_base64_size(int bytes); diff --git a/include/libwebsockets/lws-genec.h b/include/libwebsockets/lws-genec.h index cd4fb0ac3..75e9243ec 100644 --- a/include/libwebsockets/lws-genec.h +++ b/include/libwebsockets/lws-genec.h @@ -143,11 +143,12 @@ LWS_VISIBLE LWS_EXTERN int lws_genecdsa_set_key(struct lws_genec_ctx *ctx, struct lws_gencrypto_keyelem *el); -/** lws_genecdsa_hash_sig_verify() - Verifies ECDSA signature on a given hash +/** lws_genecdsa_hash_sig_verify_jws() - Verifies a JWS ECDSA signature on a given hash * * \param ctx: your struct lws_genrsa_ctx * \param in: unencrypted payload (usually a recomputed hash) * \param hash_type: one of LWS_GENHASH_TYPE_ + * \param keybits: number of bits in the crypto key * \param sig: pointer to the signature we received with the payload * \param sig_len: length of the signature we are checking in bytes * @@ -158,31 +159,38 @@ lws_genecdsa_set_key(struct lws_genec_ctx *ctx, * * Returns <0 for error, or 0 if signature matches the hash + key.. * + * The JWS ECDSA signature verification algorithm differs to generic ECDSA + * signatures and they're not interoperable. + * * This and related APIs operate identically with OpenSSL or mbedTLS backends. */ LWS_VISIBLE LWS_EXTERN int -lws_genecdsa_hash_sig_verify(struct lws_genec_ctx *ctx, const uint8_t *in, - enum lws_genhash_types hash_type, - const uint8_t *sig, size_t sig_len); +lws_genecdsa_hash_sig_verify_jws(struct lws_genec_ctx *ctx, const uint8_t *in, + enum lws_genhash_types hash_type, int keybits, + const uint8_t *sig, size_t sig_len); -/** lws_genecdsa_hash_sign() - Creates an ECDSA signature for a hash you provide +/** lws_genecdsa_hash_sign_jws() - Creates a JWS ECDSA signature for a hash you provide * * \param ctx: your struct lws_genrsa_ctx * \param in: precomputed hash * \param hash_type: one of LWS_GENHASH_TYPE_ + * \param keybits: number of bits in the crypto key * \param sig: pointer to buffer to take signature * \param sig_len: length of the buffer (must be >= length of key N) * * Returns <0 for error, or 0 for success. * - * This creates an ECDSA signature for a hash you already computed and provide. + * This creates a JWS ECDSA signature for a hash you already computed and provide. + * + * The JWS ECDSA signature generation algorithm differs to generic ECDSA + * signatures and they're not interoperable. * * This and related APIs operate identically with OpenSSL or mbedTLS backends. */ LWS_VISIBLE LWS_EXTERN int -lws_genecdsa_hash_sign(struct lws_genec_ctx *ctx, const uint8_t *in, - enum lws_genhash_types hash_type, uint8_t *sig, - size_t sig_len); +lws_genecdsa_hash_sign_jws(struct lws_genec_ctx *ctx, const uint8_t *in, + enum lws_genhash_types hash_type, int keybits, + uint8_t *sig, size_t sig_len); /* Apis that apply to both ECDH and ECDSA */ diff --git a/include/libwebsockets/lws-genrsa.h b/include/libwebsockets/lws-genrsa.h index 0f233791d..243439390 100644 --- a/include/libwebsockets/lws-genrsa.h +++ b/include/libwebsockets/lws-genrsa.h @@ -53,26 +53,14 @@ struct lws_genrsa_ctx { enum enum_genrsa_mode mode; }; -/** lws_genrsa_destroy_elements() - Free allocations in genrsa_elements - * - * \param el: your struct lws_gencrypto_keyelem - * - * This is a helper for user code making use of struct lws_gencrypto_keyelem - * where the elements are allocated on the heap, it frees any non-NULL - * buf element and sets the buf to NULL. - * - * NB: lws_genrsa_public_... apis do not need this as they take care of the key - * creation and destruction themselves. - */ -LWS_VISIBLE LWS_EXTERN void -lws_genrsa_destroy_elements(struct lws_gencrypto_keyelem *el); - /** lws_genrsa_public_decrypt_create() - Create RSA public decrypt context * * \param ctx: your struct lws_genrsa_ctx * \param el: struct prepared with key element data * \param context: lws_context for RNG * \param mode: RSA mode, one of LGRSAM_ constants + * \param oaep_hashid: the lws genhash id for the hash used in MFG1 hash + * used in OAEP mode - normally, SHA1 * * Creates an RSA context with a public key associated with it, formed from * the key elements in \p el. @@ -86,7 +74,22 @@ lws_genrsa_destroy_elements(struct lws_gencrypto_keyelem *el); */ LWS_VISIBLE LWS_EXTERN int lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_gencrypto_keyelem *el, - struct lws_context *context, enum enum_genrsa_mode mode); + struct lws_context *context, enum enum_genrsa_mode mode, + enum lws_genhash_types oaep_hashid); + +/** lws_genrsa_destroy_elements() - Free allocations in genrsa_elements + * + * \param el: your struct lws_gencrypto_keyelem + * + * This is a helper for user code making use of struct lws_gencrypto_keyelem + * where the elements are allocated on the heap, it frees any non-NULL + * buf element and sets the buf to NULL. + * + * NB: lws_genrsa_public_... apis do not need this as they take care of the key + * creation and destruction themselves. + */ +LWS_VISIBLE LWS_EXTERN void +lws_genrsa_destroy_elements(struct lws_gencrypto_keyelem *el); /** lws_genrsa_new_keypair() - Create new RSA keypair * @@ -111,7 +114,7 @@ lws_genrsa_new_keypair(struct lws_context *context, struct lws_genrsa_ctx *ctx, enum enum_genrsa_mode mode, struct lws_gencrypto_keyelem *el, int bits); -/** lws_genrsa_public_encrypt() - Perform RSA public encryption +/** lws_genrsa_public_encrypt() - Perform RSA public key encryption * * \param ctx: your struct lws_genrsa_ctx * \param in: plaintext input @@ -128,7 +131,24 @@ LWS_VISIBLE LWS_EXTERN int lws_genrsa_public_encrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in, size_t in_len, uint8_t *out); -/** lws_genrsa_public_decrypt() - Perform RSA public decryption +/** lws_genrsa_private_encrypt() - Perform RSA private key encryption + * + * \param ctx: your struct lws_genrsa_ctx + * \param in: plaintext input + * \param in_len: length of plaintext input + * \param out: encrypted output + * + * Performs PKCS1 v1.5 Encryption + * + * Returns <0 for error, or length of decrypted data. + * + * This and related APIs operate identically with OpenSSL or mbedTLS backends. + */ +LWS_VISIBLE LWS_EXTERN int +lws_genrsa_private_encrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in, + size_t in_len, uint8_t *out); + +/** lws_genrsa_public_decrypt() - Perform RSA public key decryption * * \param ctx: your struct lws_genrsa_ctx * \param in: encrypted input @@ -146,6 +166,24 @@ LWS_VISIBLE LWS_EXTERN int lws_genrsa_public_decrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in, size_t in_len, uint8_t *out, size_t out_max); +/** lws_genrsa_private_decrypt() - Perform RSA private key decryption + * + * \param ctx: your struct lws_genrsa_ctx + * \param in: encrypted input + * \param in_len: length of encrypted input + * \param out: decrypted output + * \param out_max: size of output buffer + * + * Performs PKCS1 v1.5 Decryption + * + * Returns <0 for error, or length of decrypted data. + * + * This and related APIs operate identically with OpenSSL or mbedTLS backends. + */ +LWS_VISIBLE LWS_EXTERN int +lws_genrsa_private_decrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in, + size_t in_len, uint8_t *out, size_t out_max); + /** lws_genrsa_hash_sig_verify() - Verifies RSA signature on a given hash * * \param ctx: your struct lws_genrsa_ctx diff --git a/include/libwebsockets/lws-jose.h b/include/libwebsockets/lws-jose.h index 370afeae7..d0e6dea94 100644 --- a/include/libwebsockets/lws-jose.h +++ b/include/libwebsockets/lws-jose.h @@ -49,11 +49,6 @@ enum lws_jws_jose_hdr_indexes { LWS_COUNT_JOSE_HDR_ELEMENTS }; -struct lws_jose { - /* jose header elements */ - struct lws_gencrypto_keyelem e[LWS_COUNT_JOSE_HDR_ELEMENTS]; -}; - enum lws_jose_algtype { LWS_JOSE_ENCTYPE_NONE, @@ -62,6 +57,7 @@ enum lws_jose_algtype { LWS_JOSE_ENCTYPE_RSASSA_PKCS1_PSS, LWS_JOSE_ENCTYPE_ECDSA, + LWS_JOSE_ENCTYPE_ECDHES, LWS_JOSE_ENCTYPE_AES_CBC, LWS_JOSE_ENCTYPE_AES_CFB128, @@ -69,10 +65,12 @@ enum lws_jose_algtype { LWS_JOSE_ENCTYPE_AES_CTR, LWS_JOSE_ENCTYPE_AES_ECB, LWS_JOSE_ENCTYPE_AES_OFB, - LWS_JOSE_ENCTYPE_AES_XTS, /* care... requires double-length key */ + LWS_JOSE_ENCTYPE_AES_XTS, /* care: requires double-length key */ LWS_JOSE_ENCTYPE_AES_GCM, }; +/* there's a table of these defined in lws-gencrypto-common.c */ + struct lws_jose_jwe_alg { enum lws_genhash_types hash_type; enum lws_genhmac_types hmac_type; @@ -80,16 +78,97 @@ struct lws_jose_jwe_alg { enum lws_jose_algtype algtype_crypto; /* the encryption cipher */ const char *alg; /* the JWA enc alg name, eg "ES512" */ const char *curve_name; /* NULL, or, eg, "P-256" */ + unsigned short keybits_min, keybits_fixed; + unsigned short ivbits; }; +struct lws_jose { + /* jose header elements */ + struct lws_gencrypto_keyelem e[LWS_COUNT_JOSE_HDR_ELEMENTS]; + struct lws_jwk jwk_ephemeral; + const struct lws_jose_jwe_alg *alg; + const struct lws_jose_jwe_alg *enc_alg; +}; + +/** + * lws_jose_init() - prepare a struct lws_jose for use + * + * \param jose: the jose header struct to prepare + */ +LWS_VISIBLE LWS_EXTERN void +lws_jose_init(struct lws_jose *jose); + +/** + * lws_jose_destroy() - retire a struct lws_jose from use + * + * \param jose: the jose header struct to destroy + */ +LWS_VISIBLE LWS_EXTERN void +lws_jose_destroy(struct lws_jose *jose); + +/** + * lws_gencrypto_jws_alg_to_definition() - look up a jws alg name + * + * \param alg: the jws alg name + * \param jose: pointer to the pointer to the info struct to set on success + * + * Returns 0 if *jose set, else nonzero for failure + */ LWS_VISIBLE LWS_EXTERN int lws_gencrypto_jws_alg_to_definition(const char *alg, const struct lws_jose_jwe_alg **jose); +/** + * lws_gencrypto_jwe_alg_to_definition() - look up a jwe alg name + * + * \param alg: the jwe alg name + * \param jose: pointer to the pointer to the info struct to set on success + * + * Returns 0 if *jose set, else nonzero for failure + */ LWS_VISIBLE LWS_EXTERN int lws_gencrypto_jwe_alg_to_definition(const char *alg, const struct lws_jose_jwe_alg **jose); +/** + * lws_gencrypto_jwe_enc_to_definition() - look up a jwe enc name + * + * \param alg: the jwe enc name + * \param jose: pointer to the pointer to the info struct to set on success + * + * Returns 0 if *jose set, else nonzero for failure + */ LWS_VISIBLE LWS_EXTERN int lws_gencrypto_jwe_enc_to_definition(const char *enc, const struct lws_jose_jwe_alg **jose); + +/** + * lws_jws_parse_jose() - parse a JWS JOSE header + * + * \param jose: the jose struct to set to parsing results + * \param buf: the raw JOSE header + * \param len: the length of the raw JOSE header + * \param temp: parent-owned buffer to "allocate" elements into + * \param temp_len: amount of space available in temp + * + * returns the amount of temp used, or -1 for error + */ +LWS_VISIBLE LWS_EXTERN int +lws_jws_parse_jose(struct lws_jose *jose, + const char *buf, int len, char *temp, int *temp_len); + +/** + * lws_jwe_parse_jose() - parse a JWE JOSE header + * + * \param jose: the jose struct to set to parsing results + * \param buf: the raw JOSE header + * \param len: the length of the raw JOSE header + * \param temp: parent-owned buffer to "allocate" elements into + * \param temp_len: amount of space available in temp + * + * returns the amount of temp used, or -1 for error + */ +LWS_VISIBLE LWS_EXTERN int +lws_jwe_parse_jose(struct lws_jose *jose, + const char *buf, int len, char *temp, int *temp_len); + diff --git a/include/libwebsockets/lws-jwe.h b/include/libwebsockets/lws-jwe.h index 1422a27bd..3e568be8b 100644 --- a/include/libwebsockets/lws-jwe.h +++ b/include/libwebsockets/lws-jwe.h @@ -19,8 +19,27 @@ * MA 02110-1301 USA * * included from libwebsockets.h + * + * JWE Compact Serialization consists of + * + * BASE64URL(UTF8(JWE Protected Header)) || '.' || + * BASE64URL(JWE Encrypted Key) || '.' || + * BASE64URL(JWE Initialization Vector) || '.' || + * BASE64URL(JWE Ciphertext) || '.' || + * BASE64URL(JWE Authentication Tag) */ +#define LWS_JWE_RFC3394_OVERHEAD_BYTES 8 +#define LWS_JWE_AES_IV_BYTES 16 + +#define LWS_JWE_LIMIT_RSA_KEY_BITS 4096 +#define LWS_JWE_LIMIT_AES_KEY_BITS (512 + 64) /* RFC3394 Key Wrap adds 64b */ +#define LWS_JWE_LIMIT_EC_KEY_BITS 528 /* 521 rounded to byte boundary */ +#define LWS_JWE_LIMIT_HASH_BITS (LWS_GENHASH_LARGEST * 8) + +/* the largest key element for any cipher */ +#define LWS_JWE_LIMIT_KEY_ELEMENT_BYTES (LWS_JWE_LIMIT_RSA_KEY_BITS / 8) + /** * lws_jwe_create_packet() - add b64 sig to b64 hdr + payload * @@ -43,7 +62,78 @@ * Returns the length written to \p out, or -1. */ LWS_VISIBLE LWS_EXTERN int -lws_jwe_create_packet(struct lws_jwk *jwk, - const struct lws_jose_jwe_alg *jose_alg, +lws_jwe_create_packet(struct lws_jose *jose, struct lws_jwk *jwk, const char *payload, size_t len, const char *nonce, char *out, size_t out_len, struct lws_context *context); + +LWS_VISIBLE LWS_EXTERN void +lws_jwe_be64(uint64_t c, uint8_t *p8); + +/* + * JWE Compact Serialization consists of + * + * BASE64URL(UTF8(JWE Protected Header)) || '.' || + * BASE64URL(JWE Encrypted Key) || '.' || + * BASE64URL(JWE Initialization Vector) || '.' || + * BASE64URL(JWE Ciphertext) || '.' || + * BASE64URL(JWE Authentication Tag) + */ + +LWS_VISIBLE LWS_EXTERN int +lws_jwe_write_compact(struct lws_jose *jose, struct lws_jws *jws, + char *out, size_t out_len); + + +/** + * lws_jwe_auth_and_decrypt() - confirm and decrypt JWE + * + * \param jose: jose context + * \param jws: jws / jwe context... .map and .map_b64 must be filled already + * + * This is a high level JWE decrypt api that takes a jws with the maps + * already processed, and if the authentication passes, returns the decrypted + * plaintext in jws.map.buf[LJWE_CTXT] and its length in jws.map.len[LJWE_CTXT]. + * + * In the jws, the following fields must have been set by the caller + * + * .context + * .jwk (the key encryption key) + * .map + * .map_b64 + * + * Having the b64 and decoded maps filled externally makes it flexible where + * the data was picked from, eg, from a Complete JWE JSON serialization, a + * flattened one, or a Compact Serialization. + * + * Returns decrypt length, or -1 for failure. + */ +LWS_VISIBLE LWS_EXTERN int +lws_jwe_auth_and_decrypt(struct lws_jose *jose, struct lws_jws *jws); + + + +/* only exposed because we have test vectors that need it */ +LWS_VISIBLE LWS_EXTERN int +lws_jwe_auth_and_decrypt_cbc_hs(struct lws_jose *jose, + struct lws_jws *jws, uint8_t *enc_cek, + uint8_t *aad, int aad_len); + +/* only exposed because we have test vectors that need it */ +LWS_VISIBLE LWS_EXTERN int +lws_jwa_concat_kdf(struct lws_jose *jose, struct lws_jws *jws, int direct, + uint8_t *out, const uint8_t *shared_secret, int sslen); + + +/** + * lws_jwe_encrypt() - perform JWE encryption + * + * \param jose: the JOSE header information (encryption types, etc) + * \param jws: the JWE elements, pointer to jwk etc + * \param temp: parent-owned buffer to "allocate" elements into + * \param temp_len: amount of space available in temp + * + * returns the amount of temp used, or -1 for error + */ +LWS_VISIBLE LWS_EXTERN int +lws_jwe_encrypt(struct lws_jose *jose, struct lws_jws *jws, + char *temp, int *temp_len); diff --git a/include/libwebsockets/lws-jwk.h b/include/libwebsockets/lws-jwk.h index 6cf159647..e2a001ca9 100644 --- a/include/libwebsockets/lws-jwk.h +++ b/include/libwebsockets/lws-jwk.h @@ -52,13 +52,23 @@ struct lws_jwk { /* generic meta key elements, like KID */ struct lws_gencrypto_keyelem meta[LWS_COUNT_JWK_ELEMENTS]; int kty; /**< one of LWS_JWK_ */ + char private_key; /* nonzero = has private key elements */ }; typedef int (*lws_jwk_key_import_callback)(struct lws_jwk *s, void *user); +struct lws_jwk_parse_state { + struct lws_jwk *jwk; + char b64[(((8192 / 8) * 4) / 3) + 1]; /* enough for 8Kb key */ + lws_jwk_key_import_callback per_key_cb; + void *user; + int pos; + unsigned short possible; +}; + /** lws_jwk_import() - Create a JSON Web key from the textual representation * - * \param s: the JWK object to create + * \param jwk: the JWK object to create * \param cb: callback for each jwk-processed key, or NULL if importing a single * key with no parent "keys" JSON * \param user: pointer to be passed to the callback, otherwise ignored by lws. @@ -80,21 +90,21 @@ typedef int (*lws_jwk_key_import_callback)(struct lws_jwk *s, void *user); * iteration through any further keys). */ LWS_VISIBLE LWS_EXTERN int -lws_jwk_import(struct lws_jwk *s, lws_jwk_key_import_callback cb, void *user, +lws_jwk_import(struct lws_jwk *jwk, lws_jwk_key_import_callback cb, void *user, const char *in, size_t len); /** lws_jwk_destroy() - Destroy a JSON Web key * - * \param s: the JWK object to destroy + * \param jwk: the JWK object to destroy * * All allocations in the lws_jwk are destroyed */ LWS_VISIBLE LWS_EXTERN void -lws_jwk_destroy(struct lws_jwk *s); +lws_jwk_destroy(struct lws_jwk *jwk); /** lws_jwk_export() - Export a JSON Web key to a textual representation * - * \param s: the JWK object to export + * \param jwk: the JWK object to export * \param _private: 0 = just export public parts, 1 = export everything * \param p: the buffer to write the exported JWK to * \param len: the length of the buffer \p p in bytes @@ -104,11 +114,11 @@ lws_jwk_destroy(struct lws_jwk *s); * Serializes the content of the JWK into a char buffer. */ LWS_VISIBLE LWS_EXTERN int -lws_jwk_export(struct lws_jwk *s, int _private, char *p, size_t len); +lws_jwk_export(struct lws_jwk *jwk, int _private, char *p, size_t len); /** lws_jwk_load() - Import a JSON Web key from a file * - * \param s: the JWK object to load into + * \param jwk: the JWK object to load into * \param filename: filename to load from * * Returns 0 for OK or -1 for failure @@ -125,29 +135,58 @@ lws_jwk_export(struct lws_jwk *s, int _private, char *p, size_t len); * iteration through any further keys, leaving the last one in s). */ LWS_VISIBLE LWS_EXTERN int -lws_jwk_load(struct lws_jwk *s, const char *filename, +lws_jwk_load(struct lws_jwk *jwk, const char *filename, lws_jwk_key_import_callback cb, void *user); /** lws_jwk_save() - Export a JSON Web key to a file * - * \param s: the JWK object to save from + * \param jwk: the JWK object to save from * \param filename: filename to save to * * Returns 0 for OK or -1 for failure */ LWS_VISIBLE LWS_EXTERN int -lws_jwk_save(struct lws_jwk *s, const char *filename); +lws_jwk_save(struct lws_jwk *jwk, const char *filename); /** lws_jwk_rfc7638_fingerprint() - jwk to RFC7638 compliant fingerprint * - * \param s: the JWK object to fingerprint + * \param jwk: the JWK object to fingerprint * \param digest32: buffer to take 32-byte digest * * Returns 0 for OK or -1 for failure */ LWS_VISIBLE LWS_EXTERN int -lws_jwk_rfc7638_fingerprint(struct lws_jwk *s, char *digest32); +lws_jwk_rfc7638_fingerprint(struct lws_jwk *jwk, char *digest32); + +/** lws_jwk_strdup_meta() - allocate a duplicated string meta element + * + * \param jwk: the JWK object to fingerprint + * \param idx: JWK_META_ element index + * \param in: string to copy + * \param len: length of string to copy + * + * Returns 0 for OK or -1 for failure + */ +LWS_VISIBLE LWS_EXTERN int +lws_jwk_strdup_meta(struct lws_jwk *jwk, enum enum_jwk_meta_tok idx, + const char *in, int len); + LWS_VISIBLE LWS_EXTERN int -lws_jwk_dump(struct lws_jwk *s); +lws_jwk_dump(struct lws_jwk *jwk); + +/** lws_jwk_generate() - create a new key of given type and characteristics + * + * \param context: the struct lws_context used for RNG + * \param jwk: the JWK object to fingerprint + * \param kty: One of the LWS_GENCRYPTO_KTY_ key types + * \param bits: for OCT and RSA keys, the number of bits + * \param curve: for EC keys, the name of the curve + * + * Returns 0 for OK or -1 for failure + */ +LWS_VISIBLE int +lws_jwk_generate(struct lws_context *context, struct lws_jwk *jwk, + enum lws_gencrypto_kty kty, int bits, const char *curve); + ///@} diff --git a/include/libwebsockets/lws-jws.h b/include/libwebsockets/lws-jws.h index f7d0c13a3..9e2db5213 100644 --- a/include/libwebsockets/lws-jws.h +++ b/include/libwebsockets/lws-jws.h @@ -29,26 +29,144 @@ * SHA256/384/512 HMAC, and RSA 256/384/512 are supported. * * The API uses your TLS library crypto, but works exactly the same no matter - * what you TLS backend is. + * what your TLS backend is. */ ///@{ +/* + * The maps are built to work with both JWS (LJWS_) and JWE (LJWE_), and are + * sized to the slightly larger JWE case. + */ + +enum enum_jws_sig_elements { + + /* JWS block namespace */ + LJWS_JOSE, + LJWS_PYLD, + LJWS_SIG, + LJWS_UHDR, + + /* JWE block namespace */ + LJWE_JOSE = 0, + LJWE_EKEY, + LJWE_IV, + LJWE_CTXT, + LJWE_ATAG, + + LWS_JWS_MAX_COMPACT_BLOCKS +}; + +struct lws_jws_compact_map { + const char *buf[LWS_JWS_MAX_COMPACT_BLOCKS]; + uint16_t len[LWS_JWS_MAX_COMPACT_BLOCKS]; +}; + +struct lws_jws { + struct lws_jwk *jwk; /* the struct lws_jwk containing the signing key */ + struct lws_context *context; /* the lws context (used to get random) */ + struct lws_jws_compact_map map, map_b64; +}; + +/* jws EC signatures do not have ASN.1 in them, meaning they're incompatible + * with generic signatures. + */ + +/** + * lws_jws_init() - initialize a jws for use + * + * \param jws: pointer to the jws to initialize + */ +LWS_VISIBLE LWS_EXTERN void +lws_jws_init(struct lws_jws *jws, struct lws_jwk *jwk, + struct lws_context *context); + +/** + * lws_jws_destroy() - scrub a jws + * + * \param jws: pointer to the jws to destroy + * + * Call before the jws goes out of scope. + * + * Elements defined in the jws are zeroed. + */ +LWS_VISIBLE LWS_EXTERN void +lws_jws_destroy(struct lws_jws *jws); + +/** + * lws_jws_sig_confirm_compact() - check signature + * + * \param map: pointers and lengths for each of the unencoded JWS elements + * \param jwk: public key + * \param content: lws_context + * + * Confirms the signature on a JWS. Use if you have non-b64 plain JWS elements + * in a map... it'll make a temp b64 version needed for comparison. See below + * for other variants. + * + * Returns 0 on match. + */ LWS_VISIBLE LWS_EXTERN int -lws_jws_confirm_sig(const char *in, size_t len, struct lws_jwk *jwk, - struct lws_context *context); +lws_jws_sig_confirm_compact(struct lws_jws_compact_map *map, struct lws_jwk *jwk, + struct lws_context *context, + char *temp, int *temp_len); + +LWS_VISIBLE LWS_EXTERN int +lws_jws_sig_confirm_compact_b64_map(struct lws_jws_compact_map *map_b64, + struct lws_jwk *jwk, + struct lws_context *context, + char *temp, int *temp_len); + +/** + * lws_jws_sig_confirm_compact_b64() - check signature on b64 compact JWS + * + * \param in: pointer to b64 jose.payload[.hdr].sig + * \param len: bytes available at \p in + * \param map: map to take decoded non-b64 content + * \param jwk: public key + * \param content: lws_context + * + * Confirms the signature on a JWS. Use if you have you have b64 compact layout + * (jose.payload.hdr.sig) as an aggregated string... it'll make a temp plain + * version needed for comparison. + * + * Returns 0 on match. + */ +LWS_VISIBLE LWS_EXTERN int +lws_jws_sig_confirm_compact_b64(const char *in, size_t len, + struct lws_jws_compact_map *map, + struct lws_jwk *jwk, + struct lws_context *context, + char *temp, int *temp_len); + +/** + * lws_jws_sig_confirm() - check signature on plain + b64 JWS elements + * + * \param map_b64: pointers and lengths for each of the b64-encoded JWS elements + * \param map: pointers and lengths for each of the unencoded JWS elements + * \param jwk: public key + * \param content: lws_context + * + * Confirms the signature on a JWS. Use if you have you already have both b64 + * compact layout (jose.payload.hdr.sig) and decoded JWS elements in maps. + * + * If you had the b64 string and called lws_jws_compact_decode() on it, you + * will end up with both maps, and can use this api version, saving needlessly + * regenerating any temp map. + * + * Returns 0 on match. + */ +LWS_VISIBLE LWS_EXTERN int +lws_jws_sig_confirm(struct lws_jws_compact_map *map_b64, /* b64-encoded */ + struct lws_jws_compact_map *map, /* non-b64 */ + struct lws_jwk *jwk, struct lws_context *context); /** * lws_jws_sign_from_b64() - add b64 sig to b64 hdr + payload * - * \param b64_hdr: protected header encoded in b64, may be NULL - * \param hdr_len: bytes in b64 coding of protected header - * \param b64_pay: payload encoded in b64 - * \param pay_len: bytes in b64 coding of payload - * \param b64_sig: buffer to write the b64 encoded signature into - * \param sig_len: max bytes we can write at b64_sig - * \param hash_type: one of LWS_GENHASH_TYPE_SHA[256|384|512] - * \param jwk: the struct lws_jwk containing the signing key - * \param context: the lws context (used to get random) + * \param jose: jose header information + * \param jws: information to include in the signature + * \param b64_sig: output buffer for b64 signature + * \param sig_len: size of \p b64_sig output buffer * * This adds a b64-coded JWS signature of the b64-encoded protected header * and b64-encoded payload, at \p b64_sig. The signature will be as large @@ -62,11 +180,181 @@ lws_jws_confirm_sig(const char *in, size_t len, struct lws_jwk *jwk, * Returns the length of the encoded signature written to \p b64_sig, or -1. */ LWS_VISIBLE LWS_EXTERN int -lws_jws_sign_from_b64(const char *b64_hdr, size_t hdr_len, const char *b64_pay, - size_t pay_len, char *b64_sig, size_t sig_len, - const struct lws_jose_jwe_alg *args, - struct lws_jwk *jwk, - struct lws_context *context); +lws_jws_sign_from_b64(struct lws_jose *jose, struct lws_jws *jws, char *b64_sig, + size_t sig_len); + +/** + * lws_jws_compact_decode() - converts and maps compact serialization b64 sections + * + * \param in: the incoming compact serialized b64 + * \param len: the length of the incoming compact serialized b64 + * \param map: pointer to the results structure + * \param map_b64: NULL, or pointer to a second results structure taking block + * information about the undecoded b64 + * \param out: buffer to hold decoded results + * \param out_len: size of out in bytes + * + * Returns number of sections (2 if "none", else 3), or -1 if illegal. + * + * map is set to point to the start and hold the length of each decoded block. + * If map_b64 is non-NULL, then it's set with information about the input b64 + * blocks. + */ +LWS_VISIBLE LWS_EXTERN int +lws_jws_compact_decode(const char *in, int len, struct lws_jws_compact_map *map, + struct lws_jws_compact_map *map_b64, char *out, int *out_len); + +LWS_VISIBLE int +lws_jws_compact_encode(struct lws_jws_compact_map *map_b64, /* b64-encoded */ + const struct lws_jws_compact_map *map, /* non-b64 */ + char *buf, int *out_len); + +/** + * lws_jws_write_flattened_json() - create flattened JSON sig + * + * \param jws: information to include in the signature + * \param flattened: output buffer for JSON + * \param len: size of \p flattened output buffer + * + */ +LWS_VISIBLE LWS_EXTERN int +lws_jws_write_flattened_json(struct lws_jws *jws, char *flattened, size_t len); + +/** + * lws_jws_write_compact() - create flattened JSON sig + * + * \param jws: information to include in the signature + * \param compact: output buffer for compact format + * \param len: size of \p flattened output buffer + * + */ +LWS_VISIBLE LWS_EXTERN int +lws_jws_write_compact(struct lws_jws *jws, char *compact, size_t len); + + + +/* + * below apis are not normally needed if dealing with whole JWS... they're + * useful for creating from scratch + */ + + +/** + * lws_jws_dup_element() - allocate space for an element and copy data into it + * + * \param map: map to create the element in + * \param idx: index of element in the map to create + * \param temp: space to allocate in + * \param temp_len: available space at temp + * \param in: data to duplicate into element + * \param in_len: length of data to duplicate + * \param actual_alloc: 0 for same as in_len, else actual allocation size + * + * Copies in_len from in to temp, if temp_len is sufficient. + * + * Returns 0 or -1 if not enough space in temp / temp_len. + * + * Over-allocation can be acheived by setting actual_alloc to the real + * allocation desired... in_len will be copied into it. + * + * *temp_len is reduced by actual_alloc if successful. + */ +LWS_VISIBLE LWS_EXTERN int +lws_jws_dup_element(struct lws_jws_compact_map *map, int idx, + char *temp, int *temp_len, const void *in, size_t in_len, + size_t actual_alloc); + +/** + * lws_jws_randomize_element() - create an element and fill with random + * + * \param context: lws_context used for random + * \param map: map to create the element in + * \param idx: index of element in the map to create + * \param temp: space to allocate in + * \param temp_len: available space at temp + * \param random_len: length of data to fill with random + * \param actual_alloc: 0 for same as random_len, else actual allocation size + * + * Randomize random_len bytes at temp, if temp_len is sufficient. + * + * Returns 0 or -1 if not enough space in temp / temp_len. + * + * Over-allocation can be acheived by setting actual_alloc to the real + * allocation desired... the first random_len will be filled with random. + * + * *temp_len is reduced by actual_alloc if successful. + */ +LWS_VISIBLE LWS_EXTERN int +lws_jws_randomize_element(struct lws_context *context, + struct lws_jws_compact_map *map, + int idx, char *temp, int *temp_len, size_t random_len, + size_t actual_alloc); + +/** + * lws_jws_alloc_element() - create an element and reserve space for content + * + * \param map: map to create the element in + * \param idx: index of element in the map to create + * \param temp: space to allocate in + * \param temp_len: available space at temp + * \param len: logical length of element + * \param actual_alloc: 0 for same as len, else actual allocation size + * + * Allocate len bytes at temp, if temp_len is sufficient. + * + * Returns 0 or -1 if not enough space in temp / temp_len. + * + * Over-allocation can be acheived by setting actual_alloc to the real + * allocation desired... the element logical length will be set to len. + * + * *temp_len is reduced by actual_alloc if successful. + */ +LWS_VISIBLE LWS_EXTERN int +lws_jws_alloc_element(struct lws_jws_compact_map *map, int idx, char *temp, + int *temp_len, size_t len, size_t actual_alloc); + +/** + * lws_jws_encode_b64_element() - create an b64-encoded element + * + * \param map: map to create the element in + * \param idx: index of element in the map to create + * \param temp: space to allocate in + * \param temp_len: available space at temp + * \param in: pointer to unencoded input + * \param in_len: length of unencoded input + * + * Allocate len bytes at temp, if temp_len is sufficient. + * + * Returns 0 or -1 if not enough space in temp / temp_len. + * + * Over-allocation can be acheived by setting actual_alloc to the real + * allocation desired... the element logical length will be set to len. + * + * *temp_len is reduced by actual_alloc if successful. + */ +LWS_VISIBLE LWS_EXTERN int +lws_jws_encode_b64_element(struct lws_jws_compact_map *map, int idx, + char *temp, int *temp_len, const void *in, + size_t in_len); + + +/** + * lws_jws_b64_compact_map() - find block starts and lengths in compact b64 + * + * \param in: pointer to b64 jose.payload[.hdr].sig + * \param len: bytes available at \p in + * \param map: output struct with pointers and lengths for each JWS element + * + * Scans a jose.payload[.hdr].sig b64 string and notes where the blocks start + * and their length into \p map. + * + * Returns number of blocks if OK. May return <0 if malformed. + * May not fill all map entries. + */ + +LWS_VISIBLE LWS_EXTERN int +lws_jws_b64_compact_map(const char *in, int len, struct lws_jws_compact_map *map); + /** * lws_jws_base64_enc() - encode input data into b64url data @@ -82,7 +370,8 @@ LWS_VISIBLE LWS_EXTERN int lws_jws_base64_enc(const char *in, size_t in_len, char *out, size_t out_max); /** - * lws_jws_encode_section() - encode input data into b64url data, prepending . if not first + * lws_jws_encode_section() - encode input data into b64url data, + * prepending . if not first * * \param in: the incoming plaintext * \param in_len: the length of the incoming plaintext in bytes diff --git a/include/libwebsockets/lws-lejp.h b/include/libwebsockets/lws-lejp.h index f3f7e59a6..faa44abcf 100644 --- a/include/libwebsockets/lws-lejp.h +++ b/include/libwebsockets/lws-lejp.h @@ -257,6 +257,10 @@ LWS_VISIBLE LWS_EXTERN void lejp_change_callback(struct lejp_ctx *ctx, signed char (*callback)(struct lejp_ctx *ctx, char reason)); +/* exported for use when reevaluating a path for use with a subcontext */ +LWS_VISIBLE LWS_EXTERN void +lejp_check_path_match(struct lejp_ctx *ctx); + LWS_VISIBLE LWS_EXTERN int lejp_get_wildcard(struct lejp_ctx *ctx, int wildcard, char *dest, int len); //@} diff --git a/include/libwebsockets/lws-misc.h b/include/libwebsockets/lws-misc.h index 6bb446193..9d0729b6b 100644 --- a/include/libwebsockets/lws-misc.h +++ b/include/libwebsockets/lws-misc.h @@ -330,6 +330,22 @@ lws_snprintf(char *str, size_t size, const char *format, ...) LWS_FORMAT(3); LWS_VISIBLE LWS_EXTERN char * lws_strncpy(char *dest, const char *src, size_t size); +/* + * lws_timingsafe_bcmp(): constant time memcmp + * + * \param a: first buffer + * \param b: second buffer + * \param len: count of bytes to compare + * + * Return 0 if the two buffers are the same, else nonzero. + * + * Always compares all of the buffer before returning, so it can't be used as + * a timing oracle. + */ + +LWS_VISIBLE LWS_EXTERN int +lws_timingsafe_bcmp(const void *a, const void *b, uint32_t len); + /** * lws_get_random(): fill a buffer with platform random data * diff --git a/lib/core/libwebsockets.c b/lib/core/libwebsockets.c index 91dc77a43..e9d85ba2e 100644 --- a/lib/core/libwebsockets.c +++ b/lib/core/libwebsockets.c @@ -1064,7 +1064,11 @@ lws_buflist_append_segment(struct lws_buflist **head, const uint8_t *buf, /* append at the tail */ while (*head) { - if (!--sanity || head == &((*head)->next)) { + if (!--sanity) { + lwsl_err("%s: buflist reached sanity limit\n", __func__); + return -1; + } + if (*head == (*head)->next) { lwsl_err("%s: corrupt list points to self\n", __func__); return -1; } @@ -1097,7 +1101,7 @@ lws_buflist_destroy_segment(struct lws_buflist **head) struct lws_buflist *old = *head; assert(*head); - *head = (*head)->next; + *head = old->next; old->next = NULL; lws_free(old); @@ -3142,6 +3146,18 @@ lws_strncpy(char *dest, const char *src, size_t size) return dest; } +int +lws_timingsafe_bcmp(const void *a, const void *b, uint32_t len) +{ + const uint8_t *pa = a, *pb = b; + uint8_t sum = 0; + + while (len--) + sum |= (*pa++ ^ *pb++); + + return sum; +} + typedef enum { LWS_TOKZS_LEADING_WHITESPACE, diff --git a/lib/core/output.c b/lib/core/output.c index e58aa45b2..aef2d7b9d 100644 --- a/lib/core/output.c +++ b/lib/core/output.c @@ -70,7 +70,8 @@ int lws_issue_raw(struct lws *wsi, unsigned char *buf, size_t len) * the buflist... */ - lws_buflist_append_segment(&wsi->buflist_out, buf, len); + if (lws_buflist_append_segment(&wsi->buflist_out, buf, len)) + return -1; buf = NULL; len = 0; diff --git a/lib/jose/README.md b/lib/jose/README.md index 7473c5b82..b9fd5389b 100644 --- a/lib/jose/README.md +++ b/lib/jose/README.md @@ -28,26 +28,33 @@ useful implementations of JWS, JWE and JWK. ### Symmetric ciphers - - All common AES varaiants: CBC, CFB128, CFB8, CTR, EVB, OFB and XTS + - All common AES varaiants: CBC, CFB128, CFB8, CTR, EVB, OFB, KW and XTS ### Asymmetric ciphers - RSA - - EC (P-256, P-384 and P521 JWA curves) + - EC (P-256, P-384 and P-521 JWA curves) + +### Payload auth and crypt + + - AES_128_CBC_HMAC_SHA_256 + - AES_192_CBC_HMAC_SHA_384 + - AES_256_CBC_HMAC_SHA_512 + - AES_128_GCM For the required and recommended asymmetric algorithms, support currently looks like this |JWK kty|JWA|lws| |---|---|---| -|EC|Recommended+|no| +|EC|Recommended+|yes| |RSA|Required|yes| |oct|Required|yes| |JWE alg|JWA|lws| |---|---|---| -|RSA1_5|Recommended-|yes (no JWE yet but lws_genrsa supports)| +|RSA1_5|Recommended-|yes| |RSA-OAEP|Recommended+|no| |ECDH-ES|Recommended+|no| @@ -55,7 +62,15 @@ looks like this |---|---|---| |HS256|Required|yes| |RS256|Recommended+|yes| -|ES256|Recommended|no| +|ES256|Recommended|yes| + +## Minimal Example tools + +[JWK](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/crypto/minimal-crypto-jwk) + +[JWS](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/crypto/minimal-crypto-jws) + +[JWE](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/crypto/minimal-crypto-jwe) ## API tests diff --git a/lib/jose/jwe/jwe-aeskw.c b/lib/jose/jwe/jwe-aeskw.c new file mode 100644 index 000000000..adb0df7ae --- /dev/null +++ b/lib/jose/jwe/jwe-aeskw.c @@ -0,0 +1,192 @@ +/* + * libwebsockets - JSON Web Encryption support + * + * Copyright (C) 2018 Andy Green + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * + * JWE code related to aeskw cbc + * + */ +#include "core/private.h" +#include "jose/jwe/private.h" + + +/* + * RFC3394 Key Wrap uses a 128-bit key, and bloats what it is wrapping by + * one 8-byte block. So, if you had a 32 byte plaintext CEK to wrap, after + * wrapping it becomes a 40 byte wrapped, enciphered, key. + * + * The CEK comes in from and goes out in LJWE_EKEY. So LJWE_EKEY length + * increases by 8 from calling this. + */ + +int +lws_jwe_encrypt_aeskw_cbc_hs(struct lws_jose *jose, struct lws_jws *jws, + char *temp, int *temp_len) +{ + struct lws_genaes_ctx aesctx; + /* we are wrapping a key, so size for the worst case after wrap */ + uint8_t enc_cek[LWS_JWE_LIMIT_KEY_ELEMENT_BYTES + + LWS_JWE_RFC3394_OVERHEAD_BYTES]; + int n, m, hlen = lws_genhmac_size(jose->enc_alg->hmac_type); + + if (jws->jwk->kty != LWS_GENCRYPTO_KTY_OCT) { + lwsl_err("%s: unexpected kty %d\n", __func__, jws->jwk->kty); + + return -1; + } + + jws->map_b64.len[LJWE_JOSE] = ((jws->map.len[LJWE_JOSE] * 4) / 3) + 10; + if (*temp_len < jws->map_b64.len[LJWE_JOSE]) + return -1; + jws->map_b64.buf[LJWE_JOSE] = (char *)temp; + temp += jws->map_b64.len[LJWE_JOSE]; + *temp_len -= jws->map_b64.len[LJWE_JOSE]; + + n = lws_jws_base64_enc(jws->map.buf[LJWE_JOSE], jws->map.len[LJWE_JOSE], + (char *)jws->map_b64.buf[LJWE_JOSE], + jws->map_b64.len[LJWE_JOSE]); + if (n < 0) { + lwsl_notice("%s: failed to encode JOSE hdr\n", __func__); + + return -1; + } + jws->map_b64.len[LJWE_JOSE] = n; + + jws->map.buf[LJWE_ATAG] = (char *)temp; + jws->map.len[LJWE_ATAG] = hlen / 2; + if (*temp_len < jws->map.len[LJWE_ATAG]) + return -1; + temp += hlen / 2; + *temp_len -= hlen / 2; + + jws->map.buf[LJWE_IV] = (char *)temp; + jws->map.len[LJWE_IV] = LWS_JWE_AES_IV_BYTES; + if (*temp_len < jws->map.len[LJWE_IV]) + return -1; + temp += LWS_JWE_AES_IV_BYTES; + *temp_len -= LWS_JWE_AES_IV_BYTES; + + /* 1) Encrypt the payload... */ + + /* the CEK is 256-bit in the example encrypted with a 128-bit key */ + + n = lws_jwe_encrypt_cbc_hs(jose, jws, (uint8_t *)jws->map.buf[LJWE_EKEY], + (uint8_t *)jws->map_b64.buf[LJWE_JOSE], + jws->map_b64.len[LJWE_JOSE]); + if (n < 0) { + lwsl_err("%s: lws_jwe_encrypt_cbc_hs failed\n", __func__); + return -1; + } + + /* 2) Encrypt the JWE Encrypted Key: RFC3394 Key Wrap uses 64 bit blocks + * and 128-bit input key*/ + + if (lws_genaes_create(&aesctx, LWS_GAESO_ENC, LWS_GAESM_KW, + jws->jwk->e, 1, NULL)) { + + lwsl_notice("%s: lws_genaes_create\n", __func__); + return -1; + } + + /* tag size is determined by enc cipher key length */ + + n = lws_genaes_crypt(&aesctx, (uint8_t *)jws->map.buf[LJWE_EKEY], + jws->map.len[LJWE_EKEY], enc_cek, NULL, NULL, NULL, + lws_gencrypto_bits_to_bytes( + jose->enc_alg->keybits_fixed)); + m = lws_genaes_destroy(&aesctx, NULL, 0); + if (n < 0) { + lwsl_err("%s: encrypt cek fail\n", __func__); + return -1; + } + if (m < 0) { + lwsl_err("%s: lws_genaes_destroy fail\n", __func__); + return -1; + } + + jws->map.len[LJWE_EKEY] += LWS_JWE_RFC3394_OVERHEAD_BYTES; + memcpy((uint8_t *)jws->map.buf[LJWE_EKEY], enc_cek, + jws->map.len[LJWE_EKEY]); + + return jws->map.len[LJWE_CTXT]; +} + + +int +lws_jwe_auth_and_decrypt_aeskw_cbc_hs(struct lws_jose *jose, + struct lws_jws *jws) +{ + struct lws_genaes_ctx aesctx; + uint8_t enc_cek[LWS_JWE_LIMIT_KEY_ELEMENT_BYTES + + LWS_JWE_RFC3394_OVERHEAD_BYTES]; + int n, m; + + if (jws->jwk->kty != LWS_GENCRYPTO_KTY_OCT) { + lwsl_err("%s: unexpected kty %d\n", __func__, jws->jwk->kty); + + return -1; + } + + /* the CEK is 256-bit in the example encrypted with a 128-bit key */ + + if (jws->map.len[LJWE_EKEY] > sizeof(enc_cek)) + return -1; + + /* 1) Decrypt the JWE Encrypted Key to get the raw MAC / CEK */ + + if (lws_genaes_create(&aesctx, LWS_GAESO_DEC, LWS_GAESM_KW, + jws->jwk->e, 1, NULL)) { + + lwsl_notice("%s: lws_genaes_create\n", __func__); + return -1; + } + + /* + * Decrypt the CEK into enc_cek + * tag size is determined by enc cipher key length */ + + n = lws_genaes_crypt(&aesctx, (uint8_t *)jws->map.buf[LJWE_EKEY], + jws->map.len[LJWE_EKEY], enc_cek, NULL, NULL, NULL, + lws_gencrypto_bits_to_bytes( + jose->enc_alg->keybits_fixed)); + m = lws_genaes_destroy(&aesctx, NULL, 0); + if (n < 0) { + lwsl_err("%s: decrypt CEK fail\n", __func__); + return -1; + } + if (m < 0) { + lwsl_err("%s: lws_genaes_destroy fail\n", __func__); + return -1; + } + + /* 2) Decrypt the payload */ + + n = lws_jwe_auth_and_decrypt_cbc_hs(jose, jws, enc_cek, + (uint8_t *)jws->map_b64.buf[LJWE_JOSE], + jws->map_b64.len[LJWE_JOSE]); + if (n < 0) { + lwsl_err("%s: lws_jwe_auth_and_decrypt_cbc_hs failed\n", + __func__); + return -1; + } + + return jws->map.len[LJWE_CTXT]; +} + + diff --git a/lib/jose/jwe/jwe-rsa-aescbc.c b/lib/jose/jwe/jwe-rsa-aescbc.c new file mode 100644 index 000000000..dc93b2195 --- /dev/null +++ b/lib/jose/jwe/jwe-rsa-aescbc.c @@ -0,0 +1,437 @@ +/* + * libwebsockets - JSON Web Encryption support + * + * Copyright (C) 2018 Andy Green + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * + * JWE code related to rsa + aescbc + * + */ +#include "core/private.h" +#include "jose/jwe/private.h" + +int +lws_jwe_encrypt_cbc_hs(struct lws_jose *jose, struct lws_jws *jws, + uint8_t *cek, uint8_t *aad, int aad_len) +{ + int n, hlen = lws_genhmac_size(jose->enc_alg->hmac_type); + uint8_t digest[LWS_GENHASH_LARGEST]; + struct lws_gencrypto_keyelem el; + struct lws_genhmac_ctx hmacctx; + struct lws_genaes_ctx aesctx; + uint8_t al[8]; + + /* Caller must have prepared space for the results */ + + if (jws->map.len[LJWE_ATAG] != hlen / 2) { + lwsl_notice("%s: expected tag len %d, got %d\n", __func__, + hlen / 2, jws->map.len[LJWE_ATAG]); + return -1; + } + + if (jws->map.len[LJWE_IV] != 16) { + lwsl_notice("expected iv len %d, got %d\n", 16, + jws->map.len[LJWE_IV]); + return -1; + } + + /* first create the authentication hmac */ + + /* JWA Section 5.2.2.1 + * + * 1. The secondary keys MAC_KEY and ENC_KEY are generated from the + * input key K as follows. Each of these two keys is an octet + * string. + * + * MAC_KEY consists of the initial MAC_KEY_LEN octets of K, in + * order. + * ENC_KEY consists of the final ENC_KEY_LEN octets of K, in + * order. + */ + + /* + * 2. The IV used is a 128-bit value generated randomly or + * pseudorandomly for use in the cipher. + */ + lws_get_random(jws->context, (void *)jws->map.buf[LJWE_IV], 16); + + /* + * 3. The plaintext is CBC encrypted using PKCS #7 padding using + * ENC_KEY as the key and the IV. We denote the ciphertext output + * from this step as E. + */ + + /* second half is the AES ENC_KEY */ + el.buf = (uint8_t *)jws->map.buf[LJWE_EKEY] + (hlen / 2); + el.len = hlen / 2; + + if (lws_genaes_create(&aesctx, LWS_GAESO_ENC, LWS_GAESM_CBC, &el, + LWS_GAESP_NO_PADDING, NULL)) { + lwsl_err("%s: lws_genaes_create failed\n", __func__); + + return -1; + } + + /* + * the plaintext gets delivered to us in LJWE_CTXT, this replaces + * the plaintext there with the same amount of ciphertext + */ + n = lws_genaes_crypt(&aesctx, (uint8_t *)jws->map.buf[LJWE_CTXT], + jws->map.len[LJWE_CTXT], + (uint8_t *)jws->map.buf[LJWE_CTXT], + (uint8_t *)jws->map.buf[LJWE_IV], NULL, NULL, 16); + lws_genaes_destroy(&aesctx, NULL, 0); + if (n) { + lwsl_err("%s: lws_genaes_crypt failed\n", __func__); + return -1; + } + + /* + * 4. The octet string AL is equal to the number of bits in the + * Additional Authenticated Data A expressed as a 64-bit unsigned + * big-endian integer. + */ + lws_jwe_be64(aad_len * 8, al); + + /* first half of the CEK is the MAC key */ + if (lws_genhmac_init(&hmacctx, jose->enc_alg->hmac_type, + (uint8_t *)jws->map.buf[LJWE_EKEY], hlen / 2)) + return -1; + + /* + * 5. A message Authentication Tag T is computed by applying HMAC + * [RFC2104] to the following data, in order: + * + * - the Additional Authenticated Data A, + * - the Initialization Vector IV, + * - the ciphertext E computed in the previous step, and + * - the octet string AL defined above. + * + * The string MAC_KEY is used as the MAC key. We denote the output + * of the MAC computed in this step as M. The first T_LEN octets of + * M are used as T. + */ + + if (lws_genhmac_update(&hmacctx, aad, aad_len) || + lws_genhmac_update(&hmacctx, jws->map.buf[LJWE_IV], + LWS_JWE_AES_IV_BYTES) || + /* since we encrypted it, this is the ciphertext */ + lws_genhmac_update(&hmacctx, (uint8_t *)jws->map.buf[LJWE_CTXT], + jws->map.len[LJWE_CTXT]) || + lws_genhmac_update(&hmacctx, al, 8)) { + lwsl_err("%s: hmac computation failed\n", __func__); + lws_genhmac_destroy(&hmacctx, NULL); + return -1; + } + + if (lws_genhmac_destroy(&hmacctx, digest)) { + lwsl_err("%s: problem destroying hmac\n", __func__); + return -1; + } + + /* create tag */ + memcpy((void *)jws->map.buf[LJWE_ATAG], digest, hlen / 2); + + return jws->map.len[LJWE_CTXT]; +} + +/* + * Requirements on entry: + * + * - jws->map LJWE_JOSE contains the ASCII JOSE header + * - jws->map LJWE_EKEY contains cek of enc_alg hmac length + * - jws->map LJWE_CTXT contains the plaintext + * + * On successful exit: + * + * - jws->map LJWE_ATAG contains the tag + * - jws->map LJWE_IV contains the new random IV that was used + * - jws->map LJWE_EKEY contains the encrypted CEK + * - jws->map LJWE_CTXT contains the ciphertext + * + * Return the amount of temp used, or -1 + */ + +int +lws_jwe_encrypt_rsa_aes_cbc_hs(struct lws_jose *jose, struct lws_jws *jws, + char *temp, int *temp_len) +{ + int n, hlen = lws_genhmac_size(jose->enc_alg->hmac_type), want; + char ekey[LWS_GENHASH_LARGEST]; + struct lws_genrsa_ctx rsactx; + + if (jws->jwk->kty != LWS_GENCRYPTO_KTY_RSA) { + lwsl_err("%s: unexpected kty %d\n", __func__, jws->jwk->kty); + + return -1; + } + + /* + * Reserve space in caller temp for extra JWE elements and b64 version + * of the JOSE hdr needed for computation... notice that the + * unencrypted EKEY coming in is smaller than the RSA-encrypted EKEY + * going out, which is going to be the RSA key size + */ + + want = lws_base64_size(jws->map.len[LJWE_JOSE]) + + jws->jwk->e[LWS_GENCRYPTO_RSA_KEYEL_N].len + + (hlen / 2) + LWS_JWE_AES_IV_BYTES; + if (*temp_len < want) { + lwsl_notice("%s: more temp space needed: want %d, got %d\n", + __func__, want, *temp_len); + return -1; + } + + jws->map_b64.buf[LJWE_JOSE] = (char *)temp; + jws->map_b64.len[LJWE_JOSE] = lws_base64_size(jws->map.len[LJWE_JOSE]); + if (*temp_len < jws->map_b64.len[LJWE_JOSE]) + return -1; + temp += jws->map_b64.len[LJWE_JOSE]; + *temp_len -= jws->map_b64.len[LJWE_JOSE]; + + jws->map.buf[LJWE_ATAG] = (char *)temp; + jws->map.len[LJWE_ATAG] = hlen / 2; + if (*temp_len < jws->map.len[LJWE_ATAG]) + return -1; + temp += hlen / 2; + *temp_len -= hlen / 2; + + jws->map.buf[LJWE_IV] = (char *)temp; + jws->map.len[LJWE_IV] = LWS_JWE_AES_IV_BYTES; + if (*temp_len < jws->map.len[LJWE_IV]) + return -1; + temp += jws->map.len[LJWE_IV]; + *temp_len -= jws->map.len[LJWE_IV]; + + if (*temp_len < jws->jwk->e[LWS_GENCRYPTO_RSA_KEYEL_N].len) + return -1; + + memcpy(temp, jws->map.buf[LJWE_EKEY], jws->map.len[LJWE_EKEY]); + jws->map.buf[LJWE_EKEY] = (char *)temp; + /* + * don't change jws->map.len[LJWE_EKEY]... it has allocation for up to + * jws->jwk->e[LWS_GENCRYPTO_RSA_KEYEL_N].len bytes now and the length + * will be set after the plaintext version is encrypted in-situ + */ + temp += jws->jwk->e[LWS_GENCRYPTO_RSA_KEYEL_N].len; + *temp_len -= jws->jwk->e[LWS_GENCRYPTO_RSA_KEYEL_N].len; + + /* we need a b64u encode of the JOSE header as AAD */ + + n = lws_jws_base64_enc(jws->map.buf[LJWE_JOSE], jws->map.len[LJWE_JOSE], + (char *)jws->map_b64.buf[LJWE_JOSE], + jws->map_b64.len[LJWE_JOSE]); + if (n < 0) { + lwsl_notice("%s: failed to encode JOSE hdr\n", __func__); + + return -1; + } + jws->map_b64.len[LJWE_JOSE] = n; + + /* Encrypt using the raw CEK (treated as MAC KEY | ENC KEY) */ + + n = lws_jwe_encrypt_cbc_hs(jose, jws, + (uint8_t *)jws->map.buf[LJWE_EKEY], + (uint8_t *)jws->map_b64.buf[LJWE_JOSE], + jws->map_b64.len[LJWE_JOSE]); + if (n < 0) { + lwsl_err("%s: lws_jwe_encrypt_cbc_hs failed\n", __func__); + return -1; + } + + if (lws_genrsa_create(&rsactx, jws->jwk->e, jws->context, + !strcmp(jose->alg->alg, "RSA-OAEP") ? + LGRSAM_PKCS1_OAEP_PSS : LGRSAM_PKCS1_1_5, + LWS_GENHASH_TYPE_UNKNOWN)) { + lwsl_notice("%s: lws_genrsa_public_decrypt_create\n", + __func__); + return -1; + } + + /* encrypt the CEK using RSA, mbedtls can't handle both in and out are + * the EKEY, so copy the unencrypted ekey out temporarily */ + + memcpy(ekey, jws->map.buf[LJWE_EKEY], hlen); + + n = lws_genrsa_public_encrypt(&rsactx, (uint8_t *)ekey, hlen, + (uint8_t *)jws->map.buf[LJWE_EKEY]); + lws_genrsa_destroy(&rsactx); + lws_explicit_bzero(ekey, hlen); + if (n < 0) { + lwsl_err("%s: decrypt cek fail\n", __func__); + return -1; + } + jws->map.len[LJWE_EKEY] = n; /* update to encrypted EKEY size */ + + /* + * We end up with IV, ATAG, set, EKEY encrypted and CTXT is ciphertext, + * and b64u version of ATAG in map_b64. + */ + + return 0; +} + +int +lws_jwe_auth_and_decrypt_cbc_hs(struct lws_jose *jose, + struct lws_jws *jws, uint8_t *enc_cek, + uint8_t *aad, int aad_len) +{ + int n, hlen = lws_genhmac_size(jose->enc_alg->hmac_type); + uint8_t digest[LWS_GENHASH_LARGEST]; + struct lws_gencrypto_keyelem el; + struct lws_genhmac_ctx hmacctx; + struct lws_genaes_ctx aesctx; + uint8_t al[8]; + + /* Some sanity checks on what came in */ + + if (jws->map.len[LJWE_ATAG] != hlen / 2) { + lwsl_notice("%s: expected tag len %d, got %d\n", __func__, + hlen / 2, jws->map.len[LJWE_ATAG]); + return -1; + } + + if (jws->map.len[LJWE_IV] != 16) { + lwsl_notice("expected iv len %d, got %d\n", 16, + jws->map.len[LJWE_IV]); + return -1; + } + + /* Prepare to check authentication + * + * AAD is the b64 JOSE header. + * + * The octet string AL, which is the number of bits in AAD expressed as + * a big-endian 64-bit unsigned integer is: + * + * [0, 0, 0, 0, 0, 0, 1, 152] + * + * Concatenate the AAD, the Initialization Vector, the ciphertext, and + * the AL value. + * + */ + + lws_jwe_be64(aad_len * 8, al); + + /* first half of enc_cek is the MAC key */ + if (lws_genhmac_init(&hmacctx, jose->enc_alg->hmac_type, enc_cek, + hlen / 2)) + return -1; + + if (lws_genhmac_update(&hmacctx, aad, aad_len) || + lws_genhmac_update(&hmacctx, (uint8_t *)jws->map.buf[LJWE_IV], + jws->map.len[LJWE_IV]) || + lws_genhmac_update(&hmacctx, (uint8_t *)jws->map.buf[LJWE_CTXT], + jws->map.len[LJWE_CTXT]) || + lws_genhmac_update(&hmacctx, al, 8)) { + lwsl_err("%s: hmac computation failed\n", __func__); + lws_genhmac_destroy(&hmacctx, NULL); + return -1; + } + + if (lws_genhmac_destroy(&hmacctx, digest)) { + lwsl_err("%s: problem destroying hmac\n", __func__); + return -1; + } + + /* first half of digest is the auth tag */ + + if (lws_timingsafe_bcmp(digest, jws->map.buf[LJWE_ATAG], hlen / 2)) { + lwsl_err("%s: auth failed: hmac tag != ATAG\n", __func__); + lwsl_hexdump_notice(jws->map.buf[LJWE_ATAG], hlen / 2); + lwsl_hexdump_notice(digest, 16); + return -1; + } + + /* second half of enc cek is the CEK KEY */ + el.buf = enc_cek + (hlen / 2); + el.len = hlen / 2; + + if (lws_genaes_create(&aesctx, LWS_GAESO_DEC, LWS_GAESM_CBC, + &el, LWS_GAESP_NO_PADDING, NULL)) { + lwsl_err("%s: lws_genaes_create failed\n", __func__); + + return -1; + } + + n = lws_genaes_crypt(&aesctx, (uint8_t *)jws->map.buf[LJWE_CTXT], + jws->map.len[LJWE_CTXT], + (uint8_t *)jws->map.buf[LJWE_CTXT], + (uint8_t *)jws->map.buf[LJWE_IV], NULL, NULL, 16); + n |= lws_genaes_destroy(&aesctx, NULL, 0); + if (n) { + lwsl_err("%s: lws_genaes_crypt failed\n", __func__); + return -1; + } + + return jws->map.len[LJWE_CTXT]; +} + +int +lws_jwe_auth_and_decrypt_rsa_aes_cbc_hs(struct lws_jose *jose, + struct lws_jws *jws) +{ + int n; + struct lws_genrsa_ctx rsactx; + uint8_t enc_cek[512]; + + if (jws->jwk->kty != LWS_GENCRYPTO_KTY_RSA) { + lwsl_err("%s: unexpected kty %d\n", __func__, jws->jwk->kty); + + return -1; + } + + if (jws->map.len[LJWE_EKEY] < 40) { + lwsl_err("%s: EKEY length too short %d\n", __func__, + jws->map.len[LJWE_EKEY]); + + return -1; + } + + /* Decrypt the JWE Encrypted Key to get the raw MAC || CEK */ + + if (lws_genrsa_create(&rsactx, jws->jwk->e, jws->context, + !strcmp(jose->alg->alg, "RSA-OAEP") ? + LGRSAM_PKCS1_OAEP_PSS : LGRSAM_PKCS1_1_5, + LWS_GENHASH_TYPE_UNKNOWN)) { + lwsl_notice("%s: lws_genrsa_public_decrypt_create\n", + __func__); + return -1; + } + + n = lws_genrsa_private_decrypt(&rsactx, + (uint8_t *)jws->map.buf[LJWE_EKEY], + jws->map.len[LJWE_EKEY], enc_cek, + sizeof(enc_cek)); + lws_genrsa_destroy(&rsactx); + if (n < 0) { + lwsl_err("%s: decrypt cek fail: \n", __func__); + return -1; + } + + n = lws_jwe_auth_and_decrypt_cbc_hs(jose, jws, enc_cek, + (uint8_t *)jws->map_b64.buf[LJWE_JOSE], + jws->map_b64.len[LJWE_JOSE]); + if (n < 0) { + lwsl_err("%s: lws_jwe_auth_and_decrypt_cbc_hs failed\n", + __func__); + return -1; + } + + return jws->map.len[LJWE_CTXT]; +} diff --git a/lib/jose/jwe/jwe-rsa-aesgcm.c b/lib/jose/jwe/jwe-rsa-aesgcm.c new file mode 100644 index 000000000..ac865f6fa --- /dev/null +++ b/lib/jose/jwe/jwe-rsa-aesgcm.c @@ -0,0 +1,349 @@ +/* + * libwebsockets - JSON Web Encryption support + * + * Copyright (C) 2018 Andy Green + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * + * JWE code related to aes gcm + * + */ +#include "core/private.h" +#include "jose/jwe/private.h" + +#define LWS_AESGCM_IV 12 +#define LWS_AESGCM_TAG 16 + +/* + * NOTICE this is AESGCM content encryption, it's not AES GCM key wrapping + * + * + * This section defines the specifics of performing authenticated + * encryption with AES in Galois/Counter Mode (GCM) ([AES] and + * [NIST.800-38D]). + * + * The CEK is used as the encryption key. + * + * Use of an IV of size 96 bits is REQUIRED with this algorithm. + * + * The requested size of the Authentication Tag output MUST be 128 bits, + * regardless of the key size. + * + * For decrypt: decrypt the KEK, then decrypt the payload + * + * For encrypt: encrypt the payload, then encrypt the KEK + */ + +/* + * encrypting... enc_cek is unencrypted + */ + +int +lws_jwe_encrypt_gcm(struct lws_jose *jose, struct lws_jws *jws, + uint8_t *enc_cek, uint8_t *aad, int aad_len) +{ + struct lws_gencrypto_keyelem el; + struct lws_genaes_ctx aesctx; + size_t ivs = LWS_AESGCM_IV; + int n; + + /* Some sanity checks on what came in */ + + /* MUST be 128-bit for all sizes */ + if (jws->map.len[LJWE_ATAG] != LWS_AESGCM_TAG) { + lwsl_notice("%s: AESGCM tag size must be 128b, got %d\n", + __func__, jws->map.len[LJWE_ATAG]); + return -1; + } + + if (jws->map.len[LJWE_IV] != LWS_AESGCM_IV) { /* MUST be 96-bit */ + lwsl_notice("%s: AESGCM IV must be 128b, got %d\n", __func__, + jws->map.len[LJWE_IV]); + return -1; + } + + /* EKEY is directly the CEK KEY */ + el.buf = enc_cek; + el.len = jose->enc_alg->keybits_fixed / 8; + + if (lws_genaes_create(&aesctx, LWS_GAESO_ENC, LWS_GAESM_GCM, + &el, LWS_GAESP_NO_PADDING, NULL)) { + lwsl_err("%s: lws_genaes_create failed\n", __func__); + + return -1; + } + + /* aad */ + + n = lws_genaes_crypt(&aesctx, aad, aad_len, NULL, + (uint8_t *)jws->map.buf[LJWE_IV], + (uint8_t *)jws->map.buf[LJWE_ATAG], &ivs, + LWS_AESGCM_TAG); + if (n) { + lwsl_err("%s: lws_genaes_crypt aad failed\n", __func__); + return -1; + } + + /* payload */ + n = lws_genaes_crypt(&aesctx, (uint8_t *)jws->map.buf[LJWE_CTXT], + jws->map.len[LJWE_CTXT], + (uint8_t *)jws->map.buf[LJWE_CTXT], + (uint8_t *)jws->map.buf[LJWE_IV], + NULL, &ivs, + LWS_AESGCM_TAG); + + n |= lws_genaes_destroy(&aesctx, (uint8_t *)jws->map.buf[LJWE_ATAG], + LWS_AESGCM_TAG); + if (n) { + lwsl_err("%s: lws_genaes_crypt failed\n", __func__); + return -1; + } + + return jws->map.len[LJWE_CTXT]; +} + + + +int +lws_jwe_encrypt_rsa_aes_gcm(struct lws_jose *jose, struct lws_jws *jws, + char *temp, int *temp_len) +{ + int n, ret = -1, used = 0; + struct lws_genrsa_ctx rsactx; + uint8_t enc_cek[LWS_JWE_LIMIT_KEY_ELEMENT_BYTES]; + int ekbytes = jose->enc_alg->keybits_fixed / 8; + + if (jws->jwk->kty != LWS_GENCRYPTO_KTY_RSA) { + lwsl_err("%s: unexpected kty %d\n", __func__, jws->jwk->kty); + + return -1; + } + + if (jws->map.len[LJWE_EKEY] < 32) { + lwsl_err("%s: EKEY length too short %d\n", __func__, + jws->map.len[LJWE_EKEY]); + + return -1; + } + + /* create the IV + CEK */ + + jws->map_b64.len[LJWE_JOSE] = lws_base64_size(jws->map.len[LJWE_JOSE]); + + if (*temp_len < LWS_AESGCM_IV + LWS_AESGCM_TAG + ekbytes + + jws->map_b64.len[LJWE_JOSE]) + return -1; + + *temp_len -= LWS_AESGCM_IV + LWS_AESGCM_TAG + + jws->map_b64.len[LJWE_JOSE] + + (jose->enc_alg->keybits_fixed / 8); + + if (lws_get_random(jws->context, temp, LWS_AESGCM_IV) != LWS_AESGCM_IV) + return -1; + jws->map.buf[LJWE_IV] = temp; + jws->map.len[LJWE_IV] = LWS_AESGCM_IV; + temp += LWS_AESGCM_IV; + + jws->map.buf[LJWE_ATAG] = temp; + jws->map.len[LJWE_ATAG] = LWS_AESGCM_TAG; + temp += LWS_AESGCM_TAG; + + /* we create the CEK into EKEY, it'll be cleansed by jws destroy */ + + if (lws_get_random(jws->context, temp, ekbytes) != ekbytes) + return -1; + jws->map.buf[LJWE_EKEY] = temp; + jws->map.len[LJWE_EKEY] = ekbytes; + temp += ekbytes; + + jws->map_b64.buf[LJWE_JOSE] = temp; + temp += jws->map_b64.len[LJWE_JOSE]; + /* we need a b64u encode of the JOSE header as AAD */ + + n = lws_jws_base64_enc(jws->map.buf[LJWE_JOSE], jws->map.len[LJWE_JOSE], + (char *)jws->map_b64.buf[LJWE_JOSE], + jws->map_b64.len[LJWE_JOSE]); + if (n < 0) { + lwsl_notice("%s: failed to encode JOSE hdr\n", __func__); + + return -1; + } + jws->map_b64.len[LJWE_JOSE] = n; + + /* we must cleanse enc_cek */ + used = jws->map.len[LJWE_EKEY]; + memcpy(enc_cek, jws->map.buf[LJWE_EKEY], jws->map.len[LJWE_EKEY]); + + /* encrypt the payload */ + + n = lws_jwe_encrypt_gcm(jose, jws, (uint8_t *)jws->map.buf[LJWE_EKEY], + (uint8_t *)jws->map_b64.buf[LJWE_JOSE], + jws->map_b64.len[LJWE_JOSE]); + if (n < 0) { + lwsl_err("%s: lws_jwe_encrypt_gcm failed\n", + __func__); + goto bail; + } + + /* Encrypt the CEK to make the JWE Encrypted Key */ + + if (lws_genrsa_create(&rsactx, jws->jwk->e, jws->context, + !strcmp(jose->alg->alg, "RSA-OAEP") ? + LGRSAM_PKCS1_OAEP_PSS : LGRSAM_PKCS1_1_5, + LWS_GENHASH_TYPE_SHA1 /* !!! */)) { + lwsl_notice("%s: lws_genrsa_public_decrypt_create\n", + __func__); + goto bail; + } + + n = lws_genrsa_public_encrypt(&rsactx, + (uint8_t *)jws->map.buf[LJWE_EKEY], + jws->map.len[LJWE_EKEY], enc_cek); + lws_genrsa_destroy(&rsactx); + if (n < 0) { + lwsl_err("%s: encrypt cek fail: \n", __func__); + goto bail; + } + jws->map.len[LJWE_EKEY] = n; + + /* overwrite the CEK in EKEY with the encrypted version */ + + memcpy((void *)jws->map.buf[LJWE_EKEY], enc_cek, + jws->map.len[LJWE_EKEY]); + + ret = jws->map.len[LJWE_CTXT]; + +bail: + /* cleanse enc_cek on stack that contained the unencrypted CEK */ + lws_explicit_bzero(enc_cek, used); + + return ret; +} + +int +lws_jwe_auth_and_decrypt_gcm(struct lws_jose *jose, struct lws_jws *jws, + uint8_t *enc_cek, uint8_t *aad, int aad_len) +{ + struct lws_gencrypto_keyelem el; + struct lws_genaes_ctx aesctx; + size_t ivs = LWS_AESGCM_IV; + uint8_t tag[LWS_AESGCM_TAG]; + int n; + + /* Some sanity checks on what came in */ + + /* Tag MUST be 128-bit for all sizes */ + if (jws->map.len[LJWE_ATAG] != LWS_AESGCM_TAG) { + lwsl_notice("%s: AESGCM tag size must be 128b, got %d\n", + __func__, jws->map.len[LJWE_ATAG]); + return -1; + } + + if (jws->map.len[LJWE_IV] != LWS_AESGCM_IV) { /* MUST be 96-bit */ + lwsl_notice("%s: AESGCM IV must be 128b, got %d\n", __func__, + jws->map.len[LJWE_IV]); + return -1; + } + + /* EKEY is directly the CEK KEY */ + el.buf = enc_cek; + el.len = jose->enc_alg->keybits_fixed / 8; + + if (lws_genaes_create(&aesctx, LWS_GAESO_DEC, LWS_GAESM_GCM, + &el, LWS_GAESP_NO_PADDING, NULL)) { + lwsl_err("%s: lws_genaes_create failed\n", __func__); + + return -1; + } + + n = lws_genaes_crypt(&aesctx, aad, aad_len, + NULL, + (uint8_t *)jws->map.buf[LJWE_IV], + (uint8_t *)jws->map.buf[LJWE_ATAG], &ivs, 16); + if (n) { + lwsl_err("%s: lws_genaes_crypt aad failed\n", __func__); + return -1; + } + n = lws_genaes_crypt(&aesctx, (uint8_t *)jws->map.buf[LJWE_CTXT], + jws->map.len[LJWE_CTXT], + (uint8_t *)jws->map.buf[LJWE_CTXT], + (uint8_t *)jws->map.buf[LJWE_IV], + (uint8_t *)jws->map.buf[LJWE_ATAG], &ivs, 16); + + n |= lws_genaes_destroy(&aesctx, tag, sizeof(tag)); + if (n) { + lwsl_err("%s: lws_genaes_crypt failed\n", __func__); + return -1; + } + + return jws->map.len[LJWE_CTXT]; +} + + + +int +lws_jwe_auth_and_decrypt_rsa_aes_gcm(struct lws_jose *jose, struct lws_jws *jws) +{ + int n; + struct lws_genrsa_ctx rsactx; + uint8_t enc_cek[LWS_JWE_LIMIT_KEY_ELEMENT_BYTES]; + + if (jws->jwk->kty != LWS_GENCRYPTO_KTY_RSA) { + lwsl_err("%s: unexpected kty %d\n", __func__, jws->jwk->kty); + + return -1; + } + + if (jws->map.len[LJWE_EKEY] < 32) { + lwsl_err("%s: EKEY length too short %d\n", __func__, + jws->map.len[LJWE_EKEY]); + + return -1; + } + + /* Decrypt the JWE Encrypted Key to get the direct CEK */ + + if (lws_genrsa_create(&rsactx, jws->jwk->e, jws->context, + !strcmp(jose->alg->alg, "RSA-OAEP") ? + LGRSAM_PKCS1_OAEP_PSS : LGRSAM_PKCS1_1_5, + LWS_GENHASH_TYPE_SHA1 /* !!! */)) { + lwsl_notice("%s: lws_genrsa_public_decrypt_create\n", + __func__); + return -1; + } + + n = lws_genrsa_private_decrypt(&rsactx, + (uint8_t *)jws->map.buf[LJWE_EKEY], + jws->map.len[LJWE_EKEY], enc_cek, + sizeof(enc_cek)); + lws_genrsa_destroy(&rsactx); + if (n < 0) { + lwsl_err("%s: decrypt cek fail: \n", __func__); + return -1; + } + + n = lws_jwe_auth_and_decrypt_gcm(jose, jws, enc_cek, + (uint8_t *)jws->map_b64.buf[LJWE_JOSE], + jws->map_b64.len[LJWE_JOSE]); + if (n < 0) { + lwsl_err("%s: lws_jwe_auth_and_decrypt_gcm_hs failed\n", + __func__); + return -1; + } + + return jws->map.len[LJWE_CTXT]; +} diff --git a/lib/jose/jwe/jwe.c b/lib/jose/jwe/jwe.c index ec0510b3b..5cf95a114 100644 --- a/lib/jose/jwe/jwe.c +++ b/lib/jose/jwe/jwe.c @@ -21,24 +21,418 @@ * * This supports RFC7516 JSON Web Encryption * - * */ #include "core/private.h" +#include "jose/jwe/private.h" +#if 0 +static const char * const jwe_complete_tokens[] = { + "protected", + "recipients[].header", + "recipients[].header.alg", + "recipients[].header.kid", + "recipients[].encrypted_key", + "iv", + "ciphertext", + "tag", +}; + +enum enum_jwe_complete_tokens { + LWS_EJCT_PROTECTED, + LWS_EJCT_HEADER, + LWS_EJCT_HEADER_ALG, + LWS_EJCT_HEADER_KID, + LWS_EJCT_RECIP_ENC_KEY, + LWS_EJCT_IV, + LWS_EJCT_CIPHERTEXT, + LWS_EJCT_TAG, +}; + +struct complete_cb_args { + struct lws_jws_compact_map *map; + struct lws_jws_compact_map *map_b64; + char *out; + int out_len; +}; + + +static int +do_map(struct complete_cb_args *args, int index, char *b64, int len) +{ + return 0; +} + +static signed char +lws_jwe_parse_complete_cb(struct lejp_ctx *ctx, char reason) +{ + struct complete_cb_args *args = (struct complete_cb_args *)ctx->user; + + if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match) + return 0; + + switch (ctx->path_match - 1) { + + /* strings */ + + case LWS_EJCT_PROTECTED: + case LWS_EJCT_HEADER: + case LWS_EJCT_HEADER_ALG: + case LWS_EJCT_HEADER_KID: + case LWS_EJCT_RECIP_ENC_KEY: + case LWS_EJCT_IV: + case LWS_EJCT_CIPHERTEXT: + case LWS_EJCT_TAG: + } + + return 0; +} LWS_VISIBLE int -lws_jwe_create_packet(struct lws_jwk *jwk, - const struct lws_jose_jwe_alg *jose_alg, +lws_jws_complete_decode(const char *json_in, int len, + struct lws_jws_compact_map *map, + struct lws_jws_compact_map *map_b64, char *out, + int out_len) +{ + + struct complete_cb_args args; + struct lejp_ctx jctx; + int blocks, n, m = 0; + + if (!map_b64) + map_b64 = map; + + memset(map_b64, 0, sizeof(*map_b64)); + memset(map, 0, sizeof(*map)); + + args.map = map; + args.map_b64 = map_b64; + args.out = out; + args.out_len = out_len; + + lejp_construct(&jctx, lws_jwe_parse_complete_cb, &args, + jwe_complete_tokens, + LWS_ARRAY_SIZE(jwe_complete_tokens)); + + m = (int)(signed char)lejp_parse(&jctx, (uint8_t *)json_in, len); + lejp_destruct(&jctx); +} +#endif + +static uint8_t * +be32(uint32_t i, uint32_t *p32) +{ + uint8_t *p = (uint8_t *)p32; + + *p++ = (i >> 24) & 0xff; + *p++ = (i >> 16) & 0xff; + *p++ = (i >> 8) & 0xff; + *p++ = i & 0xff; + + return (uint8_t *)p32; +} + +/* + * The key derivation process derives the agreed-upon key from the + * shared secret Z established through the ECDH algorithm, per + * Section 6.2.2.2 of [NIST.800-56A]. + * + * out must be prepared to take at least 32 bytes or the encrypted key size, + * whichever is larger. + */ + +int +lws_jwa_concat_kdf(struct lws_jose *jose, struct lws_jws *jws, int direct, + uint8_t *out, const uint8_t *shared_secret, int sslen) +{ + int hlen = lws_genhash_size(LWS_GENHASH_TYPE_SHA256), aidlen; + struct lws_genhash_ctx hash_ctx; + uint32_t ctr = 1, t; + const char *aid; + + /* + * Hash + * + * AlgorithmID || PartyUInfo || PartyVInfo + * {|| SuppPubInfo }{|| SuppPrivInfo } + * + * AlgorithmID + * + * The AlgorithmID value is of the form Datalen || Data, where Data + * is a variable-length string of zero or more octets, and Datalen is + * a fixed-length, big-endian 32-bit counter that indicates the + * length (in octets) of Data. In the Direct Key Agreement case, + * Data is set to the octets of the ASCII representation of the "enc" + * Header Parameter value. In the Key Agreement with Key Wrapping + * case, Data is set to the octets of the ASCII representation of the + * "alg" (algorithm) Header Parameter value. + */ + + aid = direct ? jose->enc_alg->alg : jose->alg->alg; + aidlen = strlen(aid); + + /* + * PartyUInfo (PartyVInfo is the same deal) + * + * The PartyUInfo value is of the form Datalen || Data, where Data is + * a variable-length string of zero or more octets, and Datalen is a + * fixed-length, big-endian 32-bit counter that indicates the length + * (in octets) of Data. If an "apu" (agreement PartyUInfo) Header + * Parameter is present, Data is set to the result of base64url + * decoding the "apu" value and Datalen is set to the number of + * octets in Data. Otherwise, Datalen is set to 0 and Data is set to + * the empty octet sequence + * + * SuppPubInfo + * + * This is set to the keydatalen represented as a 32-bit big-endian + * integer. + * + * keydatalen + * + * This is set to the number of bits in the desired output key. For + * "ECDH-ES", this is length of the key used by the "enc" algorithm. + * For "ECDH-ES+A128KW", "ECDH-ES+A192KW", and "ECDH-ES+A256KW", this + * is 128, 192, and 256, respectively. + * + * Compute Hash i = H(counter || Z || OtherInfo). + * + * We must iteratively hash over key material that's larger than + * one hash output size (256b for SHA-256) + */ + + while (ctr <= (uint32_t)(jose->enc_alg->keybits_fixed / hlen)) { + + /* + * Key derivation is performed using the Concat KDF, as defined + * in Section 5.8.1 of [NIST.800-56A], where the Digest Method + * is SHA-256. + */ + + if (lws_genhash_init(&hash_ctx, LWS_GENHASH_TYPE_SHA256)) + return -1; + + if (/* counter */ + lws_genhash_update(&hash_ctx, be32(ctr++, &t), 4) || + /* Z */ + lws_genhash_update(&hash_ctx, shared_secret, sslen) || + /* other info */ + lws_genhash_update(&hash_ctx, be32(strlen(aid), &t), 4) || + lws_genhash_update(&hash_ctx, aid, aidlen) || + lws_genhash_update(&hash_ctx, + be32(jose->e[LJJHI_APU].len, &t), 4) || + lws_genhash_update(&hash_ctx, jose->e[LJJHI_APU].buf, + jose->e[LJJHI_APU].len) || + lws_genhash_update(&hash_ctx, + be32(jose->e[LJJHI_APV].len, &t), 4) || + lws_genhash_update(&hash_ctx, jose->e[LJJHI_APV].buf, + jose->e[LJJHI_APV].len) || + lws_genhash_update(&hash_ctx, + be32(jose->enc_alg->keybits_fixed, &t), + 4) || + lws_genhash_destroy(&hash_ctx, out)) { + lws_genhash_destroy(&hash_ctx, NULL); + + return -1; + } + + out += hlen; + } + + return 0; +} + +LWS_VISIBLE void +lws_jwe_be64(uint64_t c, uint8_t *p8) +{ + int n; + + for (n = 56; n >= 0; n -= 8) + *p8++ = (uint8_t)((c >> n) & 0xff); +} + +LWS_VISIBLE int +lws_jwe_auth_and_decrypt(struct lws_jose *jose, struct lws_jws *jws) +{ + int valid_aescbc_hmac, valid_aesgcm; + char temp[512]; + int temp_len = sizeof(temp); + + if (lws_jwe_parse_jose(jose, jws->map.buf[LJWS_JOSE], + jws->map.len[LJWS_JOSE], + temp, &temp_len) < 0) { + lwsl_err("%s: JOSE parse failed\n", __func__); + return -1; + } + + valid_aescbc_hmac = jose->enc_alg && + jose->enc_alg->algtype_crypto == LWS_JOSE_ENCTYPE_AES_CBC && + (jose->enc_alg->hmac_type == LWS_GENHMAC_TYPE_SHA256 || + jose->enc_alg->hmac_type == LWS_GENHMAC_TYPE_SHA384 || + jose->enc_alg->hmac_type == LWS_GENHMAC_TYPE_SHA512); + + valid_aesgcm = jose->enc_alg && + jose->enc_alg->algtype_crypto == LWS_JOSE_ENCTYPE_AES_GCM; + + /* RSA + AESCBC */ + + if ((!strcmp(jose->alg->alg, "RSA1_5") || + !strcmp(jose->alg->alg, "RSA-OAEP")) && valid_aescbc_hmac) + return lws_jwe_auth_and_decrypt_rsa_aes_cbc_hs(jose, jws); + + /* RSA + AESGCM */ + + if ((!strcmp(jose->alg->alg, "RSA1_5") || + !strcmp(jose->alg->alg, "RSA-OAEP")) && valid_aesgcm) + return lws_jwe_auth_and_decrypt_rsa_aes_gcm(jose, jws); + + /* AESKW */ + + if ((!strcmp(jose->alg->alg, "A128KW") || + !strcmp(jose->alg->alg, "A192KW") || + !strcmp(jose->alg->alg, "A256KW")) && valid_aescbc_hmac) + return lws_jwe_auth_and_decrypt_aeskw_cbc_hs(jose, jws); + + lwsl_err("%s: unknown cipher alg combo %s / %s\n", __func__, + jose->alg->alg, jose->enc_alg ? + jose->enc_alg->alg : "NULL"); + + return -1; +} +LWS_VISIBLE int +lws_jwe_encrypt(struct lws_jose *jose, struct lws_jws *jws, + char *temp, int *temp_len) +{ + int valid_aescbc_hmac, valid_aesgcm; + + valid_aesgcm = jose->enc_alg && + jose->enc_alg->algtype_crypto == LWS_JOSE_ENCTYPE_AES_GCM; + + if (lws_jwe_parse_jose(jose, jws->map.buf[LJWS_JOSE], + jws->map.len[LJWS_JOSE], temp, temp_len) < 0) { + lwsl_err("%s: JOSE parse failed\n", __func__); + return -1; + } + + valid_aescbc_hmac = jose->enc_alg && + jose->enc_alg->algtype_crypto == LWS_JOSE_ENCTYPE_AES_CBC && + (jose->enc_alg->hmac_type == LWS_GENHMAC_TYPE_SHA256 || + jose->enc_alg->hmac_type == LWS_GENHMAC_TYPE_SHA384 || + jose->enc_alg->hmac_type == LWS_GENHMAC_TYPE_SHA512); + + /* RSA + AESCBC */ + + if ((!strcmp(jose->alg->alg, "RSA1_5") || + !strcmp(jose->alg->alg, "RSA-OAEP")) && valid_aescbc_hmac) + return lws_jwe_encrypt_rsa_aes_cbc_hs(jose, jws, temp, temp_len); + + /* RSA + AESGCM */ + + if ((!strcmp(jose->alg->alg, "RSA1_5") || + !strcmp(jose->alg->alg, "RSA-OAEP")) && valid_aesgcm) + return lws_jwe_encrypt_rsa_aes_gcm(jose, jws, temp, temp_len); + + /* AESKW */ + + if ((!strcmp(jose->alg->alg, "A128KW") || + !strcmp(jose->alg->alg, "A192KW") || + !strcmp(jose->alg->alg, "A256KW")) && valid_aescbc_hmac) + return lws_jwe_encrypt_aeskw_cbc_hs(jose, jws, temp, temp_len); + + lwsl_err("%s: unknown cipher alg combo %s / %s\n", __func__, + jose->alg->alg, jose->enc_alg ? + jose->enc_alg->alg : "NULL"); + + return -1; +} + +/* + * JWE Compact Serialization consists of + * + * BASE64URL(UTF8(JWE Protected Header)) || '.' || + * BASE64URL(JWE Encrypted Key) || '.' || + * BASE64URL(JWE Initialization Vector) || '.' || + * BASE64URL(JWE Ciphertext) || '.' || + * BASE64URL(JWE Authentication Tag) + */ + +LWS_VISIBLE int +lws_jwe_write_compact(struct lws_jose *jose, struct lws_jws *jws, + char *out, size_t out_len) +{ + size_t orig = out_len; + int n; + + n = lws_jws_base64_enc(jws->map.buf[LJWS_JOSE], + jws->map.len[LJWS_JOSE], out, out_len); + if (n < 0 || (int)out_len == n) { + lwsl_info("%s: unable to encode JOSE\n", __func__); + return n; + } + + out += n; + *out++ = '.'; + out_len -= n + 1; + + n = lws_jws_base64_enc(jws->map.buf[LJWE_EKEY], + jws->map.len[LJWE_EKEY], out, out_len); + if (n < 0 || (int)out_len == n) { + lwsl_info("%s: unable to encode EKEY\n", __func__); + return n; + } + + out += n; + *out++ = '.'; + out_len -= n + 1; + n = lws_jws_base64_enc(jws->map.buf[LJWE_IV], + jws->map.len[LJWE_IV], out, out_len); + if (n < 0 || (int)out_len == n) { + lwsl_info("%s: unable to encode IV\n", __func__); + return n; + } + + out += n; + *out++ = '.'; + out_len -= n + 1; + + n = lws_jws_base64_enc(jws->map.buf[LJWE_CTXT], + jws->map.len[LJWE_CTXT], out, out_len); + if (n < 0 || (int)out_len == n) { + lwsl_info("%s: unable to encode CTXT\n", __func__); + return n; + } + + out += n; + *out++ = '.'; + out_len -= n + 1; + n = lws_jws_base64_enc(jws->map.buf[LJWE_ATAG], + jws->map.len[LJWE_ATAG], out, out_len); + if (n < 0 || (int)out_len == n) { + lwsl_info("%s: unable to encode ATAG\n", __func__); + return n; + } + + out += n; + *out++ = '\0'; + out_len -= n; + + return orig - out_len; +} + +LWS_VISIBLE int +lws_jwe_create_packet(struct lws_jose *jose, struct lws_jwk *jwk, const char *payload, size_t len, const char *nonce, char *out, size_t out_len, struct lws_context *context) { - char *buf, *start, *p, *end, *p1, *end1, *b64_hdr, *b64_pay; - int n, b64_hdr_len, b64_pay_len; + char *buf, *start, *p, *end, *p1, *end1; + struct lws_jws jws; + int n; + + lws_jws_init(&jws, jwk, context); /* - * This buffer is local to the function, the actual output - * is prepared into vhd->buf. Only the plaintext protected header + * This buffer is local to the function, the actual output is prepared + * into vhd->buf. Only the plaintext protected header * (which contains the public key, 512 bytes for 4096b) goes in * here temporarily. */ @@ -56,7 +450,11 @@ lws_jwe_create_packet(struct lws_jwk *jwk, * temporary JWS protected header plaintext */ - p += lws_snprintf(p, end - p, "{\"alg\":\"RS256\",\"jwk\":"); + if (!jose->alg || !jose->alg->alg) + goto bail; + + p += lws_snprintf(p, end - p, "{\"alg\":\"%s\",\"jwk\":", + jose->alg->alg); n = lws_jwk_export(jwk, 0, p, end - p); if (n < 0) { lwsl_notice("failed to export jwk\n"); @@ -74,23 +472,33 @@ lws_jwe_create_packet(struct lws_jwk *jwk, end1 = out + out_len - 1; p1 += lws_snprintf(p1, end1 - p1, "{\"protected\":\""); - b64_hdr = p1; + jws.map_b64.buf[LJWS_JOSE] = p1; n = lws_jws_base64_enc(start, p - start, p1, end1 - p1); if (n < 0) { lwsl_notice("%s: failed to encode protected\n", __func__); goto bail; } - b64_hdr_len = n; + jws.map_b64.len[LJWS_JOSE] = n; p1 += n; p1 += lws_snprintf(p1, end1 - p1, "\",\"payload\":\""); - b64_pay = p1; + jws.map_b64.buf[LJWS_PYLD] = p1; n = lws_jws_base64_enc(payload, len, p1, end1 - p1); if (n < 0) { lwsl_notice("%s: failed to encode payload\n", __func__); goto bail; } - b64_pay_len = n; + jws.map_b64.len[LJWS_PYLD] = n; + p1 += n; + + p1 += lws_snprintf(p1, end1 - p1, "\",\"header\":\""); + jws.map_b64.buf[LJWS_UHDR] = p1; + n = lws_jws_base64_enc(payload, len, p1, end1 - p1); + if (n < 0) { + lwsl_notice("%s: failed to encode payload\n", __func__); + goto bail; + } + jws.map_b64.len[LJWS_UHDR] = n; p1 += n; p1 += lws_snprintf(p1, end1 - p1, "\",\"signature\":\""); @@ -99,13 +507,15 @@ lws_jwe_create_packet(struct lws_jwk *jwk, * taking the b64 protected header and the b64 payload, sign them * and place the signature into the packet */ - n = lws_jws_sign_from_b64(b64_hdr, b64_hdr_len, b64_pay, b64_pay_len, - p1, end1 - p1, jose_alg, jwk, context); + n = lws_jws_sign_from_b64(jose, &jws, p1, end1 - p1); if (n < 0) { lwsl_notice("sig gen failed\n"); goto bail; } + jws.map_b64.buf[LJWS_SIG] = p1; + jws.map_b64.len[LJWS_SIG] = n; + p1 += n; p1 += lws_snprintf(p1, end1 - p1, "\"}"); @@ -114,6 +524,7 @@ lws_jwe_create_packet(struct lws_jwk *jwk, return p1 - out; bail: + lws_jws_destroy(&jws); free(buf); return -1; diff --git a/lib/jose/jwe/private.h b/lib/jose/jwe/private.h new file mode 100644 index 000000000..e4f02b267 --- /dev/null +++ b/lib/jose/jwe/private.h @@ -0,0 +1,50 @@ + +/* jwe-rsa-aescbc.c */ + +int +lws_jwe_encrypt_rsa_aes_cbc_hs(struct lws_jose *jose, struct lws_jws *jws, + char *temp, int *temp_len); + +int +lws_jwe_auth_and_decrypt_cbc_hs(struct lws_jose *jose, + struct lws_jws *jws, uint8_t *enc_cek, + uint8_t *aad, int aad_len); + +int +lws_jwe_auth_and_decrypt_rsa_aes_cbc_hs(struct lws_jose *jose, + struct lws_jws *jws); + +int +lws_jwe_encrypt_cbc_hs(struct lws_jose *jose, struct lws_jws *jws, + uint8_t *cek, uint8_t *aad, int aad_len); + + +/* jws-rsa-aesgcm.c */ + +int +lws_jwe_auth_and_decrypt_gcm(struct lws_jose *jose, + struct lws_jws *jws, uint8_t *enc_cek, + uint8_t *aad, int aad_len); + +int +lws_jwe_auth_and_decrypt_rsa_aes_gcm(struct lws_jose *jose, + struct lws_jws *jws); + +int +lws_jwe_encrypt_gcm(struct lws_jose *jose, struct lws_jws *jws, + uint8_t *enc_cek, uint8_t *aad, int aad_len); + +int +lws_jwe_encrypt_rsa_aes_gcm(struct lws_jose *jose, struct lws_jws *jws, + char *temp, int *temp_len); + + +/* jwe-rsa-aeskw.c */ + +int +lws_jwe_encrypt_aeskw_cbc_hs(struct lws_jose *jose, struct lws_jws *jws, + char *temp, int *temp_len); + +int +lws_jwe_auth_and_decrypt_aeskw_cbc_hs(struct lws_jose *jose, + struct lws_jws *jws); diff --git a/lib/jose/jwk/jwk.c b/lib/jose/jwk/jwk.c index 8ef7494ee..879cff121 100644 --- a/lib/jose/jwk/jwk.c +++ b/lib/jose/jwk/jwk.c @@ -20,15 +20,16 @@ */ #include "core/private.h" +#include "jose/private.h" #include #include -static const char * const kyt_names[] = { - "unknown", /* LWS_GENCRYPTO_KYT_UNKNOWN */ - "oct", /* LWS_GENCRYPTO_KYT_OCT */ - "RSA", /* LWS_GENCRYPTO_KYT_RSA */ - "EC" /* LWS_GENCRYPTO_KYT_EC */ +static const char * const kty_names[] = { + "unknown", /* LWS_GENCRYPTO_KTY_UNKNOWN */ + "oct", /* LWS_GENCRYPTO_KTY_OCT */ + "RSA", /* LWS_GENCRYPTO_KTY_RSA */ + "EC" /* LWS_GENCRYPTO_KTY_EC */ }; /* @@ -64,42 +65,84 @@ static const char * const jwk_tok[] = { /* information about each token declared above */ -#define F_B64 (1 << 10) -#define F_B64U (1 << 11) -#define F_META (1 << 12) -#define F_RSA (1 << 13) -#define F_EC (1 << 14) -#define F_OCT (1 << 15) +#define F_M (1 << 9) /* Mandatory for key type */ +#define F_B64 (1 << 10) /* Base64 coded octets */ +#define F_B64U (1 << 11) /* Base64 Url coded octets */ +#define F_META (1 << 12) /* JWK key metainformation */ +#define F_RSA (1 << 13) /* RSA key */ +#define F_EC (1 << 14) /* Elliptic curve key */ +#define F_OCT (1 << 15) /* octet key */ -unsigned short tok_map[] = { +static unsigned short tok_map[] = { F_RSA | F_EC | F_OCT | F_META | 0xff, - F_RSA | F_B64U | LWS_GENCRYPTO_RSA_KEYEL_E, - F_RSA | F_B64U | LWS_GENCRYPTO_RSA_KEYEL_N, - F_RSA | F_EC | F_B64U | LWS_GENCRYPTO_RSA_KEYEL_D, - F_RSA | F_B64U | LWS_GENCRYPTO_RSA_KEYEL_P, - F_RSA | F_B64U | LWS_GENCRYPTO_RSA_KEYEL_Q, - F_RSA | F_B64U | LWS_GENCRYPTO_RSA_KEYEL_DP, - F_RSA | F_B64U | LWS_GENCRYPTO_RSA_KEYEL_DQ, - F_RSA | F_B64U | LWS_GENCRYPTO_RSA_KEYEL_QI, + F_RSA | F_B64U | F_M | LWS_GENCRYPTO_RSA_KEYEL_E, + F_RSA | F_B64U | F_M | LWS_GENCRYPTO_RSA_KEYEL_N, + F_RSA | F_EC | F_B64U | LWS_GENCRYPTO_RSA_KEYEL_D, + F_RSA | F_B64U | LWS_GENCRYPTO_RSA_KEYEL_P, + F_RSA | F_B64U | LWS_GENCRYPTO_RSA_KEYEL_Q, + F_RSA | F_B64U | LWS_GENCRYPTO_RSA_KEYEL_DP, + F_RSA | F_B64U | LWS_GENCRYPTO_RSA_KEYEL_DQ, + F_RSA | F_B64U | LWS_GENCRYPTO_RSA_KEYEL_QI, - F_RSA | F_EC | F_OCT | F_META | JWK_META_KTY, - F_OCT | F_B64U | LWS_GENCRYPTO_OCT_KEYEL_K, + F_RSA | F_EC | F_OCT | F_META | F_M | JWK_META_KTY, + F_OCT | F_B64U | F_M | LWS_GENCRYPTO_OCT_KEYEL_K, - F_EC | LWS_GENCRYPTO_EC_KEYEL_CRV, - F_EC | F_B64U | LWS_GENCRYPTO_EC_KEYEL_X, - F_EC | F_B64U | LWS_GENCRYPTO_EC_KEYEL_Y, + F_EC | F_M | LWS_GENCRYPTO_EC_KEYEL_CRV, + F_EC | F_B64U | F_M | LWS_GENCRYPTO_EC_KEYEL_X, + F_EC | F_B64U | F_M | LWS_GENCRYPTO_EC_KEYEL_Y, - F_RSA | F_EC | F_OCT | F_META | JWK_META_KID, - F_RSA | F_EC | F_OCT | F_META | JWK_META_USE, + F_RSA | F_EC | F_OCT | F_META | JWK_META_KID, + F_RSA | F_EC | F_OCT | F_META | JWK_META_USE, - F_RSA | F_EC | F_OCT | F_META | JWK_META_KEY_OPS, - F_RSA | F_EC | F_OCT | F_META | F_B64 | JWK_META_X5C, - F_RSA | F_EC | F_OCT | F_META | JWK_META_ALG, + F_RSA | F_EC | F_OCT | F_META | JWK_META_KEY_OPS, + F_RSA | F_EC | F_OCT | F_META | F_B64 | JWK_META_X5C, + F_RSA | F_EC | F_OCT | F_META | JWK_META_ALG, }; static const char *meta_names[] = { "kty", "kid", "use", "key_ops", "x5c", "alg" }; + +struct lexico { + const char *name; + int idx; + char meta; +} lexico_ec[] = { + { "alg", JWK_META_ALG, 1 }, + { "crv", LWS_GENCRYPTO_EC_KEYEL_CRV, 0 }, + { "d", LWS_GENCRYPTO_EC_KEYEL_D, 2 | 0 }, + { "key_ops", JWK_META_KEY_OPS, 1 }, + { "kid", JWK_META_KID, 1 }, + { "kty", JWK_META_KTY, 1 }, + { "use", JWK_META_USE, 1 }, + { "x", LWS_GENCRYPTO_EC_KEYEL_X, 0 }, + { "x5c", JWK_META_X5C, 1 }, + { "y", LWS_GENCRYPTO_EC_KEYEL_Y, 0 } +}, lexico_oct[] = { + { "alg", JWK_META_ALG, 1 }, + { "k", LWS_GENCRYPTO_OCT_KEYEL_K, 0 }, + { "key_ops", JWK_META_KEY_OPS, 1 }, + { "kid", JWK_META_KID, 1 }, + { "kty", JWK_META_KTY, 1 }, + { "use", JWK_META_USE, 1 }, + { "x5c", JWK_META_X5C, 1 } +}, lexico_rsa[] = { + { "alg", JWK_META_ALG, 1 }, + { "d", LWS_GENCRYPTO_RSA_KEYEL_D, 2 | 0 }, + { "dp", LWS_GENCRYPTO_RSA_KEYEL_DP, 2 | 0 }, + { "dq", LWS_GENCRYPTO_RSA_KEYEL_DQ, 2 | 0 }, + { "e", LWS_GENCRYPTO_RSA_KEYEL_E, 0 }, + { "key_ops", JWK_META_KEY_OPS, 1 }, + { "kid", JWK_META_KID, 1 }, + { "kty", JWK_META_KTY, 1 }, + { "n", LWS_GENCRYPTO_RSA_KEYEL_N, 0 }, + { "p", LWS_GENCRYPTO_RSA_KEYEL_P, 2 | 0 }, + { "q", LWS_GENCRYPTO_RSA_KEYEL_Q, 2 | 0 }, + { "qi", LWS_GENCRYPTO_RSA_KEYEL_QI, 2 | 0 }, + { "use", JWK_META_USE, 1 }, + { "x5c", JWK_META_X5C, 1 } +}; + static const char meta_b64[] = { 0, 0, 0, 0, 1, 0 }; static const char *oct_names[] = { @@ -117,72 +160,65 @@ static const char *ec_names[] = { }; static const char ec_b64[] = { 0, 1, 1, 1 }; -struct cb_lws_jwk { - struct lws_jwk *s; - char *b64; - lws_jwk_key_import_callback per_key_cb; - void *user; - int b64max; - int pos; - unsigned short possible; -}; - LWS_VISIBLE int -lws_jwk_dump(struct lws_jwk *s) +lws_jwk_dump(struct lws_jwk *jwk) { const char **enames, *b64; int elems; int n; - switch (s->kty) { + (void)enames; + (void)meta_names; + + switch (jwk->kty) { default: - case LWS_GENCRYPTO_KYT_UNKNOWN: - lwsl_err("%s: jwk %p: unknown type\n", __func__, s); + case LWS_GENCRYPTO_KTY_UNKNOWN: + lwsl_err("%s: jwk %p: unknown type\n", __func__, jwk); return 1; - case LWS_GENCRYPTO_KYT_OCT: + case LWS_GENCRYPTO_KTY_OCT: elems = LWS_GENCRYPTO_OCT_KEYEL_COUNT; enames = oct_names; b64 = oct_b64; break; - case LWS_GENCRYPTO_KYT_RSA: + case LWS_GENCRYPTO_KTY_RSA: elems = LWS_GENCRYPTO_RSA_KEYEL_COUNT; enames = rsa_names; b64 = rsa_b64; break; - case LWS_GENCRYPTO_KYT_EC: + case LWS_GENCRYPTO_KTY_EC: elems = LWS_GENCRYPTO_EC_KEYEL_COUNT; enames = ec_names; b64 = ec_b64; break; } - lwsl_info("%s: jwk %p\n", __func__, s); + lwsl_info("%s: jwk %p\n", __func__, jwk); for (n = 0; n < LWS_COUNT_JWK_ELEMENTS; n++) { - if (s->meta[n].buf && meta_b64[n]) { + if (jwk->meta[n].buf && meta_b64[n]) { lwsl_info(" meta: %s\n", meta_names[n]); - lwsl_hexdump_info(s->meta[n].buf, s->meta[n].len); + lwsl_hexdump_info(jwk->meta[n].buf, jwk->meta[n].len); } - if (s->meta[n].buf && !meta_b64[n]) + if (jwk->meta[n].buf && !meta_b64[n]) lwsl_info(" meta: %s: '%s'\n", meta_names[n], - s->meta[n].buf); + jwk->meta[n].buf); } for (n = 0; n < elems; n++) { - if (s->e[n].buf && b64[n]) { + if (jwk->e[n].buf && b64[n]) { lwsl_info(" e: %s\n", enames[n]); - lwsl_hexdump_info(s->e[n].buf, s->e[n].len); + lwsl_hexdump_info(jwk->e[n].buf, jwk->e[n].len); } - if (s->e[n].buf && !b64[n]) - lwsl_info(" e: %s: '%s'\n", enames[n], s->e[n].buf); + if (jwk->e[n].buf && !b64[n]) + lwsl_info(" e: %s: '%s'\n", enames[n], jwk->e[n].buf); } return 0; } static int -_lws_jwk_set_element_jwk(struct lws_gencrypto_keyelem *e, char *in, int len) +_lws_jwk_set_el_jwk(struct lws_gencrypto_keyelem *e, char *in, int len) { e->buf = lws_malloc(len + 1, "jwk"); if (!e->buf) @@ -196,9 +232,9 @@ _lws_jwk_set_element_jwk(struct lws_gencrypto_keyelem *e, char *in, int len) } static int -_lws_jwk_set_element_jwk_b64(struct lws_gencrypto_keyelem *e, char *in, int len) +_lws_jwk_set_el_jwk_b64(struct lws_gencrypto_keyelem *e, char *in, int len) { - int dec_size = ((len * 3) / 4) + 4, n; + int dec_size = lws_base64_size(len), n; e->buf = lws_malloc(dec_size, "jwk"); if (!e->buf) @@ -215,9 +251,9 @@ _lws_jwk_set_element_jwk_b64(struct lws_gencrypto_keyelem *e, char *in, int len) } static int -_lws_jwk_set_element_jwk_b64u(struct lws_gencrypto_keyelem *e, char *in, int len) +_lws_jwk_set_el_jwk_b64u(struct lws_gencrypto_keyelem *e, char *in, int len) { - int dec_size = ((len * 3) / 4) + 4, n; + int dec_size = lws_base64_size(len), n; e->buf = lws_malloc(dec_size, "jwk"); if (!e->buf) @@ -239,26 +275,29 @@ lws_jwk_destroy_elements(struct lws_gencrypto_keyelem *el, int m) int n; for (n = 0; n < m; n++) - if (el[n].buf) + if (el[n].buf) { + /* wipe all key material when it goes out of scope */ + lws_explicit_bzero(el[n].buf, el[n].len); lws_free_set_NULL(el[n].buf); + } } LWS_VISIBLE void -lws_jwk_destroy(struct lws_jwk *s) +lws_jwk_destroy(struct lws_jwk *jwk) { - lws_jwk_destroy_elements(s->e, LWS_ARRAY_SIZE(s->e)); - lws_jwk_destroy_elements(s->meta, LWS_ARRAY_SIZE(s->meta)); + lws_jwk_destroy_elements(jwk->e, LWS_ARRAY_SIZE(jwk->e)); + lws_jwk_destroy_elements(jwk->meta, LWS_ARRAY_SIZE(jwk->meta)); } static signed char cb_jwk(struct lejp_ctx *ctx, char reason) { - struct cb_lws_jwk *cbs = (struct cb_lws_jwk *)ctx->user; - struct lws_jwk *s = cbs->s; - unsigned int idx, poss; + struct lws_jwk_parse_state *jps = (struct lws_jwk_parse_state *)ctx->user; + struct lws_jwk *jwk = jps->jwk; + unsigned int idx, poss, n; if (reason == LEJPCB_VAL_STR_START) - cbs->pos = 0; + jps->pos = 0; if (reason == LEJPCB_OBJECT_START && ctx->path_match == 0 + 1) /* @@ -269,12 +308,12 @@ cb_jwk(struct lejp_ctx *ctx, char reason) * ACME specifies the keys must be ordered in lexographic * order - where kty is not first. */ - cbs->possible = F_RSA | F_EC | F_OCT; + jps->possible = F_RSA | F_EC | F_OCT; if (reason == LEJPCB_OBJECT_END && ctx->path_match == 0 + 1) { /* we completed parsing a key */ - if (cbs->per_key_cb && cbs->possible) { - if (cbs->per_key_cb(cbs->s, cbs->user)) { + if (jps->per_key_cb && jps->possible) { + if (jps->per_key_cb(jps->jwk, jps->user)) { lwsl_notice("%s: user cb halts import\n", __func__); @@ -283,11 +322,99 @@ cb_jwk(struct lejp_ctx *ctx, char reason) } /* clear it down */ - lws_jwk_destroy(cbs->s); - cbs->possible = 0; + lws_jwk_destroy(jps->jwk); + jps->possible = 0; } } + if (reason == LEJPCB_COMPLETE) { + + /* + * Now we saw the whole jwk and know the key type, let'jwk insist + * that as a whole, it must be consistent and complete. + * + * The tracking of ->possible bits from even before we know the + * kty already makes certain we cannot have key element members + * defined that are inconsistent with the key type. + */ + + for (n = 0; n < LWS_ARRAY_SIZE(tok_map); n++) + /* + * All mandataory elements for the key type + * must be present + */ + if ((tok_map[n] & jps->possible) && ( + ((tok_map[n] & (F_M | F_META)) == (F_M | F_META) && + !jwk->meta[tok_map[n] & 0xff].buf) || + ((tok_map[n] & (F_M | F_META)) == F_M && + !jwk->e[tok_map[n] & 0xff].buf))) { + lwsl_notice("%s: missing %s\n", __func__, + jwk_tok[n]); + return -3; + } + + /* + * When the key may be public or public + private, ensure the + * intra-key members related to that are consistent. + * + * Only RSA keys need extra care, since EC keys are already + * confirmed by making CRV, X and Y mandatory and only D + * (the singular private part) optional. For RSA, N and E are + * also already known to be present using mandatory checking. + */ + + /* + * If a private key, it must have all D, P and Q. Public key + * must have none of them. + */ + if (jwk->kty == LWS_GENCRYPTO_KTY_RSA && + !(((!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf) && + (!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_P].buf) && + (!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_Q].buf)) || + (jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf && + jwk->e[LWS_GENCRYPTO_RSA_KEYEL_P].buf && + jwk->e[LWS_GENCRYPTO_RSA_KEYEL_Q].buf)) + ) { + lwsl_notice("%s: RSA requires D, P and Q for private\n", + __func__); + return -3; + } + + /* + * If the precomputed private key terms appear, they must all + * appear together. + */ + if (jwk->kty == LWS_GENCRYPTO_KTY_RSA && + !(((!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_DP].buf) && + (!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_DQ].buf) && + (!jwk->e[LWS_GENCRYPTO_RSA_KEYEL_QI].buf)) || + (jwk->e[LWS_GENCRYPTO_RSA_KEYEL_DP].buf && + jwk->e[LWS_GENCRYPTO_RSA_KEYEL_DQ].buf && + jwk->e[LWS_GENCRYPTO_RSA_KEYEL_QI].buf)) + ) { + lwsl_notice("%s: RSA DP, DQ, QI must all appear " + "or none\n", __func__); + return -3; + } + + /* + * The precomputed private key terms must not appear without + * the private key itself also appearing. + */ + if (jwk->kty == LWS_GENCRYPTO_KTY_RSA && + !jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf && + jwk->e[LWS_GENCRYPTO_RSA_KEYEL_DQ].buf) { + lwsl_notice("%s: RSA DP, DQ, QI can appear only with " + "private key\n", __func__); + return -3; + } + + if ((jwk->kty == LWS_GENCRYPTO_KTY_RSA || + jwk->kty == LWS_GENCRYPTO_KTY_EC) && + jwk->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf) + jwk->private_key = 1; + } + if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match) return 0; @@ -301,43 +428,44 @@ cb_jwk(struct lejp_ctx *ctx, char reason) switch (idx) { /* note: kty is not necessarily first... we have to keep track of * what could match given which element names have already been - * seen. Once kty comes, we confirm it's still possible (ie, it's - * not trying to tell us that it's RSA when we saw a "crv" - * already) and then reduce the possibilities to just the one that + * seen. Once kty comes, we confirm it'jwk still possible (ie, it'jwk + * not trying to tell us that it'jwk RSA now when we saw a "crv" + * earlier) and then reduce the possibilities to just the one that * kty told. */ - case F_RSA | F_EC | F_OCT | F_META | JWK_META_KTY: + case F_RSA | F_EC | F_OCT | F_META | F_M | JWK_META_KTY: - if (!strcmp(ctx->buf, "oct")) { - if (!(cbs->possible & F_OCT)) + if (ctx->npos == 3 && !strncmp(ctx->buf, "oct", 3)) { + if (!(jps->possible & F_OCT)) goto elements_mismatch; - s->kty = LWS_GENCRYPTO_KYT_OCT; - cbs->possible = F_OCT; + jwk->kty = LWS_GENCRYPTO_KTY_OCT; + jps->possible = F_OCT; goto cont; } - if (!strcmp(ctx->buf, "RSA")) { - if (!(cbs->possible & F_RSA)) + if (ctx->npos == 3 && !strncmp(ctx->buf, "RSA", 3)) { + if (!(jps->possible & F_RSA)) goto elements_mismatch; - s->kty = LWS_GENCRYPTO_KYT_RSA; - cbs->possible = F_RSA; + jwk->kty = LWS_GENCRYPTO_KTY_RSA; + jps->possible = F_RSA; goto cont; } - if (!strcmp(ctx->buf, "EC")) { - if (!(cbs->possible & F_EC)) + if (ctx->npos == 2 && !strncmp(ctx->buf, "EC", 2)) { + if (!(jps->possible & F_EC)) goto elements_mismatch; - s->kty = LWS_GENCRYPTO_KYT_EC; - cbs->possible = F_EC; + jwk->kty = LWS_GENCRYPTO_KTY_EC; + jps->possible = F_EC; goto cont; } - lwsl_err("%s: Unknown KTY '%s'\n", __func__, ctx->buf); + lwsl_err("%s: Unknown KTY '%.*s'\n", __func__, ctx->npos, + ctx->buf); return -1; default: cont: - if (cbs->pos + ctx->npos >= cbs->b64max) + if (jps->pos + ctx->npos >= (int)sizeof(jps->b64)) goto bail; - memcpy(cbs->b64 + cbs->pos, ctx->buf, ctx->npos); - cbs->pos += ctx->npos; + memcpy(jps->b64 + jps->pos, ctx->buf, ctx->npos); + jps->pos += ctx->npos; if (reason == LEJPCB_VAL_STR_CHUNK) return 0; @@ -345,13 +473,13 @@ cont: /* chunking has been collated */ poss = idx & (F_RSA | F_EC | F_OCT); - cbs->possible &= poss; - if (!cbs->possible) + jps->possible &= poss; + if (!jps->possible) goto elements_mismatch; if (idx & F_META) { - if (_lws_jwk_set_element_jwk(&s->meta[idx & 0x7f], - cbs->b64, cbs->pos) < 0) + if (_lws_jwk_set_el_jwk(&jwk->meta[idx & 0x7f], + jps->b64, jps->pos) < 0) goto bail; break; @@ -359,24 +487,30 @@ cont: if (idx & F_B64U) { /* key data... do the base64 decode as needed */ - if (_lws_jwk_set_element_jwk_b64u(&s->e[idx & 0x7f], - cbs->b64, cbs->pos) - < 0) + if (_lws_jwk_set_el_jwk_b64u(&jwk->e[idx & 0x7f], + jps->b64, jps->pos) < 0) goto bail; + + if (jwk->e[idx & 0x7f].len > + LWS_JWE_LIMIT_KEY_ELEMENT_BYTES) { + lwsl_notice("%s: oversize keydata\n", __func__); + goto bail; + } + return 0; } if (idx & F_B64) { + /* cert data... do non-urlcoded base64 decode */ - if (_lws_jwk_set_element_jwk_b64(&s->e[idx & 0x7f], - cbs->b64, cbs->pos) - < 0) + if (_lws_jwk_set_el_jwk_b64(&jwk->e[idx & 0x7f], + jps->b64, jps->pos) < 0) goto bail; return 0; } - if (_lws_jwk_set_element_jwk(&s->e[idx & 0x7f], - cbs->b64, cbs->pos) < 0) + if (_lws_jwk_set_el_jwk(&jwk->e[idx & 0x7f], + jps->b64, jps->pos) < 0) goto bail; break; } @@ -392,140 +526,265 @@ bail: return -1; } -LWS_VISIBLE int -lws_jwk_import(struct lws_jwk *s, lws_jwk_key_import_callback cb, void *user, - const char *in, size_t len) +void +lws_jwk_init_jps(struct lejp_ctx *jctx, struct lws_jwk_parse_state *jps, + struct lws_jwk *jwk, lws_jwk_key_import_callback cb, + void *user) { - struct lejp_ctx jctx; - struct cb_lws_jwk cbs; - const int b64max = (((8192 / 8) * 4) / 3) + 1; /* enough for 8K key */ - const char * const *tok = jwk_outer_tok; - char b64[b64max]; - int m; + if (jwk) + memset(jwk, 0, sizeof(*jwk)); - memset(s, 0, sizeof(*s)); - cbs.s = s; - cbs.b64 = b64; - cbs.b64max = b64max; - cbs.pos = 0; - cbs.per_key_cb = cb; - cbs.user = user; - cbs.possible = F_RSA | F_EC | F_OCT; + jps->jwk = jwk; + jps->possible = F_RSA | F_EC | F_OCT; + jps->per_key_cb = cb; + jps->user = user; + jps->pos = 0; - if (cb == NULL) - tok = jwk_tok; + lejp_construct(jctx, cb_jwk, jps, cb ? jwk_outer_tok: jwk_tok, + LWS_ARRAY_SIZE(jwk_tok)); +} - lejp_construct(&jctx, cb_jwk, &cbs, tok, LWS_ARRAY_SIZE(jwk_tok)); - m = (int)(signed char)lejp_parse(&jctx, (uint8_t *)in, len); - lejp_destruct(&jctx); +LWS_VISIBLE int +lws_jwk_generate(struct lws_context *context, struct lws_jwk *jwk, + enum lws_gencrypto_kty kty, int bits, const char *curve) +{ + int n; - if (m < 0) { - lwsl_notice("%s: parse got %d\n", __func__, m); + memset(jwk, 0, sizeof(*jwk)); - return -1; + jwk->kty = kty; + jwk->private_key = 1; + + switch (kty) { + case LWS_GENCRYPTO_KTY_RSA: + { + struct lws_genrsa_ctx ctx; + + lwsl_notice("%s: generating %d bit RSA key\n", __func__, bits); + n = lws_genrsa_new_keypair(context, &ctx, LGRSAM_PKCS1_1_5, + jwk->e, bits); + lws_genrsa_destroy(&ctx); + if (n) { + lwsl_err("%s: problem generating RSA key\n", __func__); + return 1; + } } + break; + case LWS_GENCRYPTO_KTY_OCT: + n = lws_gencrypto_bits_to_bytes(bits); + jwk->e[LWS_GENCRYPTO_OCT_KEYEL_K].buf = lws_malloc(n, "oct"); + jwk->e[LWS_GENCRYPTO_OCT_KEYEL_K].len = n; + if (lws_get_random(context, + jwk->e[LWS_GENCRYPTO_OCT_KEYEL_K].buf, n) != n) { + lwsl_err("%s: problem getting random\n", __func__); + return 1; + } + break; + case LWS_GENCRYPTO_KTY_EC: + { + struct lws_genec_ctx ctx; - if (s->kty == LWS_GENCRYPTO_KYT_UNKNOWN) { - lwsl_notice("%s: missing or unknown kyt\n", __func__); - return -1; + if (!curve) { + lwsl_err("%s: must have a named curve\n", __func__); + + return 1; + } + + if (lws_genecdsa_create(&ctx, context, NULL)) + return 1; + + lwsl_notice("%s: generating ECDSA key on curve %s\n", __func__, + curve); + + n = lws_genecdsa_new_keypair(&ctx, curve, jwk->e); + lws_genec_destroy(&ctx); + if (n) { + lwsl_err("%s: problem generating ECDSA key\n", __func__); + return 1; + } + } + break; + + case LWS_GENCRYPTO_KTY_UNKNOWN: + default: + lwsl_err("%s: unknown kty\n", __func__); + return 1; } return 0; } LWS_VISIBLE int -lws_jwk_export(struct lws_jwk *s, int private, char *p, size_t len) +lws_jwk_import(struct lws_jwk *jwk, lws_jwk_key_import_callback cb, void *user, + const char *in, size_t len) { - char *start = p, *end = &p[len - 1]; - int n, limit = LWS_COUNT_JWK_ELEMENTS; + struct lejp_ctx jctx; + struct lws_jwk_parse_state jps; + int m; - /* RFC7638 lexicographic order requires - * RSA: e -> kty -> n - * oct: k -> kty - */ + lws_jwk_init_jps(&jctx, &jps, jwk, cb, user); - p += lws_snprintf(p, end - p, "{"); + m = (int)(signed char)lejp_parse(&jctx, (uint8_t *)in, len); + lejp_destruct(&jctx); - switch (s->kty) { - - case LWS_GENCRYPTO_KYT_OCT: - if (!s->e[LWS_GENCRYPTO_OCT_KEYEL_K].buf) - return -1; - - p += lws_snprintf(p, end - p, "\"k\":\""); - n = lws_jws_base64_enc((const char *)s->e[LWS_GENCRYPTO_OCT_KEYEL_K].buf, - s->e[LWS_GENCRYPTO_OCT_KEYEL_K].len, p, end - p - 4); - if (n < 0) { - lwsl_notice("%s: enc failed\n", __func__); - return -1; - } - p += n; - - p += lws_snprintf(p, end - p, "\",\"kty\":\"%s\"}", - kyt_names[s->kty]); - - return p - start; - - case LWS_GENCRYPTO_KYT_RSA: - if (!s->e[LWS_GENCRYPTO_RSA_KEYEL_E].buf || - !s->e[LWS_GENCRYPTO_RSA_KEYEL_N].buf || - (private && (!s->e[LWS_GENCRYPTO_RSA_KEYEL_D].buf || - !s->e[LWS_GENCRYPTO_RSA_KEYEL_P].buf || - !s->e[LWS_GENCRYPTO_RSA_KEYEL_Q].buf)) - ) { - lwsl_notice("%s: not enough elements filled\n", - __func__); - return -1; - } - - if (!private) - limit = LWS_GENCRYPTO_RSA_KEYEL_N + 1; - - for (n = 0; n < limit; n++) { - int m; - - if (!s->e[n].buf) - continue; - lwsl_info("%d: len %d\n", n, s->e[n].len); - - if (n) - p += lws_snprintf(p, end - p, ","); - p += lws_snprintf(p, end - p, "\"%s\":\"", jwk_tok[n]); - m = lws_jws_base64_enc((const char *)s->e[n].buf, - s->e[n].len, p, - end - p - 4); - if (m < 0) { - lwsl_notice("%s: enc fail inlen %d outlen %d\n", - __func__, (int)s->e[n].len, - lws_ptr_diff(end, p) - 4); - return -1; - } - p += m; - *p++ = '\"'; - - if (!n) /* RFC7638 lexicographic order */ - p += lws_snprintf(p, end - p, ",\"kty\":\"%s\"", - kyt_names[s->kty]); - } - - p += lws_snprintf(p, end - p, "}"); - - return p - start; - - case LWS_GENCRYPTO_KYT_EC: - return p - start; + if (m < 0) { + lwsl_notice("%s: parse got %d\n", __func__, m); + lws_jwk_destroy(jwk); + return -1; + } + switch (jwk->kty) { + case LWS_GENCRYPTO_KTY_UNKNOWN: + lwsl_notice("%s: missing or unknown kyt\n", __func__); + lws_jwk_destroy(jwk); + return -1; default: break; } - lwsl_err("%s: unknown key type %d\n", __func__, s->kty); + return 0; +} - return -1; + +LWS_VISIBLE int +lws_jwk_export(struct lws_jwk *jwk, int private, char *p, size_t len) +{ + char *start = p, *end = &p[len - 1]; + int n, m, limit, first = 1, asym = 0; + struct lexico *l; + + /* RFC7638 lexicographic order requires + * RSA: e -> kty -> n + * oct: k -> kty + * + * ie, meta and key data elements appear interleaved in name alpha order + */ + + p += lws_snprintf(p, end - p, "{"); + + switch (jwk->kty) { + case LWS_GENCRYPTO_KTY_OCT: + l = lexico_oct; + limit = LWS_ARRAY_SIZE(lexico_oct); + break; + case LWS_GENCRYPTO_KTY_RSA: + l = lexico_rsa; + limit = LWS_ARRAY_SIZE(lexico_rsa); + asym = 1; + break; + case LWS_GENCRYPTO_KTY_EC: + l = lexico_ec; + limit = LWS_ARRAY_SIZE(lexico_ec); + asym = 1; + break; + default: + return -1; + } + + for (n = 0; n < limit; n++) { + const char *q, *q_end; + char tok[12]; + int pos = 0, f = 1; + + if ((l->meta & 1) && (jwk->meta[l->idx].buf || + l->idx == (int)JWK_META_KTY)) { + + switch (l->idx) { + case JWK_META_KTY: + if (!first) + *p++ = ','; + first = 0; + p += lws_snprintf(p, end - p, "\"%s\":\"%s\"", + l->name, kty_names[jwk->kty]); + break; + case JWK_META_KEY_OPS: + if (!first) + *p++ = ','; + first = 0; + q = (const char *)jwk->meta[l->idx].buf; + q_end = q + jwk->meta[l->idx].len; + + p += lws_snprintf(p, end - p, + "\"%s\":[", l->name); + /* + * For the public version, usages that + * require the private part must be + * snipped + */ + + while (q < q_end) { + if (*q != ' ' && pos < (int)sizeof(tok) - 1) { + tok[pos++] = *q++; + if (q != q_end) + continue; + } + tok[pos] = '\0'; + pos = 0; + if (private || !asym || + (strcmp(tok, "sign") && + strcmp(tok, "encrypt"))) { + if (!f) + *p++ = ','; + f = 0; + p += lws_snprintf(p, end - p, + "\"%s\"", tok); + } + q++; + } + + *p++ = ']'; + + break; + + default: + /* both sig and enc require asym private key */ + if (!private && asym && l->idx == (int)JWK_META_USE) + break; + if (!first) + *p++ = ','; + first = 0; + p += lws_snprintf(p, end - p, "\"%s\":\"%.*s\"", + l->name, jwk->meta[l->idx].len, + jwk->meta[l->idx].buf); + break; + } + } + + if ((!(l->meta & 1)) && jwk->e[l->idx].buf && + (private || !(l->meta & 2))) { + if (!first) + *p++ = ','; + first = 0; + + p += lws_snprintf(p, end - p, "\"%s\":\"", l->name); + + if (jwk->kty == LWS_GENCRYPTO_KTY_EC && + l->idx == (int)LWS_GENCRYPTO_EC_KEYEL_CRV) + m = lws_snprintf(p, end - p, "%.*s", + jwk->e[l->idx].len, + (const char *)jwk->e[l->idx].buf); + else + m = lws_jws_base64_enc( + (const char *)jwk->e[l->idx].buf, + jwk->e[l->idx].len, p, end - p - 4); + if (m < 0) { + lwsl_notice("%s: enc failed\n", __func__); + return -1; + } + p += m; + p += lws_snprintf(p, end - p, "\""); + } + + l++; + } + + p += lws_snprintf(p, end - p, "}\n"); + + return p - start; } LWS_VISIBLE int -lws_jwk_rfc7638_fingerprint(struct lws_jwk *s, char *digest32) +lws_jwk_rfc7638_fingerprint(struct lws_jwk *jwk, char *digest32) { struct lws_genhash_ctx hash_ctx; int tmpsize = 2536, n; @@ -533,7 +792,7 @@ lws_jwk_rfc7638_fingerprint(struct lws_jwk *s, char *digest32) tmp = lws_malloc(tmpsize, "rfc7638 tmp"); - n = lws_jwk_export(s, 0, tmp, tmpsize); + n = lws_jwk_export(jwk, 0, tmp, tmpsize); if (n < 0) goto bail; @@ -559,7 +818,20 @@ bail: } LWS_VISIBLE int -lws_jwk_load(struct lws_jwk *s, const char *filename, +lws_jwk_strdup_meta(struct lws_jwk *jwk, enum enum_jwk_meta_tok idx, + const char *in, int len) +{ + jwk->meta[idx].buf = lws_malloc(len, __func__); + if (!jwk->meta[idx].buf) + return 1; + jwk->meta[idx].len = len; + memcpy(jwk->meta[idx].buf, in, len); + + return 0; +} + +LWS_VISIBLE int +lws_jwk_load(struct lws_jwk *jwk, const char *filename, lws_jwk_key_import_callback cb, void *user) { int buflen = 4096; @@ -573,7 +845,7 @@ lws_jwk_load(struct lws_jwk *s, const char *filename, if (n < 0) goto bail; - n = lws_jwk_import(s, cb, user, buf, n); + n = lws_jwk_import(jwk, cb, user, buf, n); lws_free(buf); return n; @@ -584,7 +856,7 @@ bail: } LWS_VISIBLE int -lws_jwk_save(struct lws_jwk *s, const char *filename) +lws_jwk_save(struct lws_jwk *jwk, const char *filename) { int buflen = 4096; char *buf = lws_malloc(buflen, "jwk-save"); @@ -593,7 +865,7 @@ lws_jwk_save(struct lws_jwk *s, const char *filename) if (!buf) return -1; - n = lws_jwk_export(s, 1, buf, buflen); + n = lws_jwk_export(jwk, 1, buf, buflen); if (n < 0) goto bail; diff --git a/lib/jose/jws/jose.c b/lib/jose/jws/jose.c index a72014325..5fb51b71a 100644 --- a/lib/jose/jws/jose.c +++ b/lib/jose/jws/jose.c @@ -23,6 +23,7 @@ */ #include "core/private.h" +#include "jose/private.h" #include @@ -54,8 +55,11 @@ static const char * const jws_jose[] = { }; struct jose_cb_args { - const struct lws_jose_jwe_alg **args; - const struct lws_jose_jwe_alg **enc_args; /* null for jws case */ + struct lws_jose *jose; + struct lejp_ctx jwk_jctx; /* fake lejp context used to parse epk */ + struct lws_jwk_parse_state jps; /* fake jwk parse state */ + char *temp; + int *temp_len; int is_jwe; }; @@ -63,6 +67,28 @@ static signed char lws_jws_jose_cb(struct lejp_ctx *ctx, char reason) { struct jose_cb_args *args = (struct jose_cb_args *)ctx->user; + int n; + + /* + * In JOSE JSON, the element "epk" contains a fully-formed JWK. + * + * For JOSE paths beginning "epk.", we pass them through to a JWK + * LEJP subcontext to parse using the JWK parser directly. + */ + + if (args->is_jwe && !strncmp(ctx->path, "epk.", 4)) { + memcpy(args->jwk_jctx.path, ctx->path + 4, + sizeof(ctx->path) - 4); + memcpy(args->jwk_jctx.buf, ctx->buf, ctx->npos); + args->jwk_jctx.npos = ctx->npos; + + if (!ctx->path_match) + args->jwk_jctx.path_match = 0; + lejp_check_path_match(&args->jwk_jctx); + + if (args->jwk_jctx.path_match) + args->jwk_jctx.callback(&args->jwk_jctx, reason); + } if (!(reason & LEJP_FLAG_CB_IS_VALUE) || !ctx->path_match) return 0; @@ -79,7 +105,8 @@ lws_jws_jose_cb(struct lejp_ctx *ctx, char reason) */ if (!args->is_jwe && - lws_gencrypto_jws_alg_to_definition(ctx->buf, args->args)) { + lws_gencrypto_jws_alg_to_definition(ctx->buf, + &args->jose->alg)) { lwsl_notice("%s: unknown alg '%s'\n", __func__, ctx->buf); @@ -87,8 +114,9 @@ lws_jws_jose_cb(struct lejp_ctx *ctx, char reason) } if (args->is_jwe && - lws_gencrypto_jwe_alg_to_definition(ctx->buf, args->args)) { - lwsl_notice("%s: unknown alg '%s'\n", __func__, + lws_gencrypto_jwe_alg_to_definition(ctx->buf, + &args->jose->alg)) { + lwsl_notice("%s: unknown JWE alg '%s'\n", __func__, ctx->buf); return -1; @@ -127,11 +155,13 @@ lws_jws_jose_cb(struct lejp_ctx *ctx, char reason) /* past here, JWE only */ - case LJJHI_ENC: /* JWE only: Optional: string */ - if (!args->is_jwe) + case LJJHI_ENC: /* JWE only: Mandatory: string */ + if (!args->is_jwe) { + lwsl_info("%s: enc in jws\n", __func__); return -1; + } if (lws_gencrypto_jwe_enc_to_definition(ctx->buf, - args->enc_args)) { + &args->jose->enc_alg)) { lwsl_notice("%s: unknown enc '%s'\n", __func__, ctx->buf); @@ -142,41 +172,45 @@ lws_jws_jose_cb(struct lejp_ctx *ctx, char reason) case LJJHI_ZIP: /* JWE only: Optional: string ("DEF" = deflate) */ if (!args->is_jwe) return -1; - break; + goto append_string; case LJJHI_EPK: /* Additional arg for JWE ECDH */ if (!args->is_jwe) return -1; + /* Ephemeral key... this JSON subsection is actually a JWK */ + lwsl_err("LJJHI_EPK\n"); break; case LJJHI_APU: /* Additional arg for JWE ECDH */ if (!args->is_jwe) return -1; - break; + /* Agreement Party U */ + goto append_string; case LJJHI_APV: /* Additional arg for JWE ECDH */ if (!args->is_jwe) return -1; - break; + /* Agreement Party V */ + goto append_string; case LJJHI_IV: /* Additional arg for JWE AES */ if (!args->is_jwe) return -1; - break; + goto append_string; case LJJHI_TAG: /* Additional arg for JWE AES */ if (!args->is_jwe) return -1; - break; + goto append_string; case LJJHI_P2S: /* Additional arg for JWE PBES2 */ if (!args->is_jwe) return -1; - break; + goto append_string; case LJJHI_P2C: /* Additional arg for JWE PBES2 */ if (!args->is_jwe) return -1; - break; + goto append_string; /* ignore what we don't understand */ @@ -185,21 +219,76 @@ lws_jws_jose_cb(struct lejp_ctx *ctx, char reason) } return 0; + +append_string: + + if (*args->temp_len < ctx->npos) { + lwsl_err("%s: out of parsing space\n", __func__); + return -1; + } + + if (!args->jose->e[ctx->path_match - 1].buf) { + args->jose->e[ctx->path_match - 1].buf = (uint8_t *)args->temp; + args->jose->e[ctx->path_match - 1].len = 0; + } + + memcpy(args->temp, ctx->buf, ctx->npos); + args->temp += ctx->npos; + *args->temp_len -= ctx->npos; + args->jose->e[ctx->path_match - 1].len += ctx->npos; + + if (reason == LEJPCB_VAL_STR_END) { + n = lws_b64_decode_string_len( + (const char *)args->jose->e[ctx->path_match - 1].buf, + args->jose->e[ctx->path_match - 1].len, + (char *)args->jose->e[ctx->path_match - 1].buf, + args->jose->e[ctx->path_match - 1].len + 1); + if (n < 0) { + lwsl_err("%s: b64 decode failed\n", __func__); + return -1; + } + + args->temp -= args->jose->e[ctx->path_match - 1].len - n - 1; + *args->temp_len += + args->jose->e[ctx->path_match - 1].len - n - 1; + + args->jose->e[ctx->path_match - 1].len = n; + } + + return 0; +} + +void +lws_jose_init(struct lws_jose *jose) +{ + memset(jose, 0, sizeof(*jose)); +} + +void +lws_jose_destroy(struct lws_jose *jose) +{ +// lws_gencrypto_destroy_elements(jose->e, LWS_ARRAY_SIZE(jose->e)); + lws_jwk_destroy(&jose->jwk_ephemeral); } static int -lws_jose_parse(const struct lws_jose_jwe_alg **_args, - const struct lws_jose_jwe_alg **enc_args, - uint8_t *buf, int n, int is_jwe) +lws_jose_parse(struct lws_jose *jose, const uint8_t *buf, int n, + char *temp, int *temp_len, int is_jwe) { struct lejp_ctx jctx; struct jose_cb_args args; int m; - args.args = _args; - args.enc_args = enc_args; + if (is_jwe) + /* prepare a context for JOSE epk ephemeral jwk parsing */ + lws_jwk_init_jps(&args.jwk_jctx, &args.jps, + &jose->jwk_ephemeral, NULL, NULL); + args.is_jwe = is_jwe; + args.temp = temp; + args.temp_len = temp_len; + args.jose = jose; lejp_construct(&jctx, lws_jws_jose_cb, &args, jws_jose, LWS_ARRAY_SIZE(jws_jose)); @@ -207,7 +296,7 @@ lws_jose_parse(const struct lws_jose_jwe_alg **_args, m = (int)(signed char)lejp_parse(&jctx, (uint8_t *)buf, n); lejp_destruct(&jctx); if (m < 0) { - lwsl_notice("parse got %d\n", m); + lwsl_notice("%s: parse %.*s returned %d\n", __func__, n, buf, m); return -1; } @@ -215,16 +304,17 @@ lws_jose_parse(const struct lws_jose_jwe_alg **_args, } int -lws_jws_parse_jose(const struct lws_jose_jwe_alg **args, - uint8_t *buf, int n) +lws_jws_parse_jose(struct lws_jose *jose, + const char *buf, int len, char *temp, int *temp_len) { - return lws_jose_parse(args, NULL, buf, n, 0); + return lws_jose_parse(jose, (const uint8_t *)buf, len, + temp, temp_len, 0); } int -lws_jwe_parse_jose(const struct lws_jose_jwe_alg **args, - const struct lws_jose_jwe_alg **enc_args, - uint8_t *buf, int n) +lws_jwe_parse_jose(struct lws_jose *jose, + const char *buf, int len, char *temp, int *temp_len) { - return lws_jose_parse(args, enc_args, buf, n, 1); + return lws_jose_parse(jose, + (const uint8_t *)buf, len, temp, temp_len, 1); } diff --git a/lib/jose/jws/jws.c b/lib/jose/jws/jws.c index dae98fd1c..fd4a4cb27 100644 --- a/lib/jose/jws/jws.c +++ b/lib/jose/jws/jws.c @@ -22,14 +22,129 @@ #include "core/private.h" #include "private.h" +LWS_VISIBLE void +lws_jws_init(struct lws_jws *jws, struct lws_jwk *jwk, + struct lws_context *context) +{ + memset(jws, 0, sizeof(*jws)); + jws->context = context; + jws->jwk = jwk; +} + +static void +lws_jws_compact_map_bzero(struct lws_jws_compact_map *map) +{ + int n; + + /* no need to scrub first jose header element (it can be canned then) */ + + for (n = 1; n < LWS_JWS_MAX_COMPACT_BLOCKS; n++) + if (map->buf[n]) + lws_explicit_bzero((void *)map->buf[n], map->len[n]); +} + +LWS_VISIBLE void +lws_jws_destroy(struct lws_jws *jws) +{ + lws_jws_compact_map_bzero(&jws->map); + jws->jwk = NULL; +} + +LWS_VISIBLE int +lws_jws_dup_element(struct lws_jws_compact_map *map, int idx, + char *temp, int *temp_len, const void *in, size_t in_len, + size_t actual_alloc) +{ + if (!actual_alloc) + actual_alloc = in_len; + + if ((size_t)*temp_len < actual_alloc) + return -1; + + map->len[idx] = in_len; + map->buf[idx] = temp; + + memcpy((void *)map->buf[idx], in, in_len); + *temp_len -= actual_alloc; + + return 0; +} + +LWS_VISIBLE int +lws_jws_encode_b64_element(struct lws_jws_compact_map *map, int idx, + char *temp, int *temp_len, const void *in, + size_t in_len) +{ + int n; + + if (*temp_len < lws_base64_size((int)in_len)) + return -1; + + n = lws_jws_base64_enc(in, in_len, temp, *temp_len); + if (n < 0) + return -1; + + map->len[idx] = n; + map->buf[idx] = temp; + + *temp_len -= n; + + return 0; +} + +LWS_VISIBLE int +lws_jws_randomize_element(struct lws_context *context, + struct lws_jws_compact_map *map, + int idx, char *temp, int *temp_len, size_t random_len, + size_t actual_alloc) +{ + if (!actual_alloc) + actual_alloc = random_len; + + if ((size_t)*temp_len < actual_alloc) + return -1; + + map->len[idx] = random_len; + map->buf[idx] = temp; + + if (lws_get_random(context, temp, random_len) != (int)random_len) { + lwsl_err("Problem getting random\n"); + return -1; + } + + *temp_len -= actual_alloc; + + return 0; +} + +LWS_VISIBLE int +lws_jws_alloc_element(struct lws_jws_compact_map *map, int idx, char *temp, + int *temp_len, size_t len, size_t actual_alloc) +{ + if (!actual_alloc) + actual_alloc = len; + + if ((size_t)*temp_len < actual_alloc) + return -1; + + map->len[idx] = len; + map->buf[idx] = temp; + *temp_len -= actual_alloc; + + return 0; +} + LWS_VISIBLE int lws_jws_base64_enc(const char *in, size_t in_len, char *out, size_t out_max) { int n; n = lws_b64_encode_string_url(in, in_len, out, out_max - 1); - if (n < 0) + if (n < 0) { + lwsl_notice("%s: in len %d too large for %d out buf\n", + __func__, (int)in_len, (int)out_max); return n; /* too large for output buffer */ + } /* trim the terminal = */ while (n && out[n - 1] == '=') @@ -40,6 +155,99 @@ lws_jws_base64_enc(const char *in, size_t in_len, char *out, size_t out_max) return n; } +LWS_VISIBLE int +lws_jws_b64_compact_map(const char *in, int len, struct lws_jws_compact_map *map) +{ + int me = 0; + + memset(map, 0, sizeof(*map)); + + map->buf[me] = (char *)in; + map->len[me] = 0; + + while (len--) { + if (*in++ == '.') { + if (++me == LWS_JWS_MAX_COMPACT_BLOCKS) + return -1; + map->buf[me] = (char *)in; + map->len[me] = 0; + continue; + } + map->len[me]++; + } + + return me + 1; +} + +/* b64 in, map contains decoded elements, if non-NULL, + * map_b64 set to b64 elements + */ + +LWS_VISIBLE int +lws_jws_compact_decode(const char *in, int len, struct lws_jws_compact_map *map, + struct lws_jws_compact_map *map_b64, char *out, + int *out_len) +{ + int blocks, n, m = 0; + + if (!map_b64) + map_b64 = map; + + memset(map_b64, 0, sizeof(*map_b64)); + memset(map, 0, sizeof(*map)); + + blocks = lws_jws_b64_compact_map(in, len, map_b64); + + if (blocks > LWS_JWS_MAX_COMPACT_BLOCKS) + return -1; + + while (m < blocks) { + n = lws_b64_decode_string_len(map_b64->buf[m], + map_b64->len[m], out, *out_len); + if (n < 0) { + lwsl_err("%s: b64 decode failed\n", __func__); + return -1; + } + /* replace the map entry with the decoded content */ + map->buf[m] = out; + map->len[m++] = n; + out += n; + *out_len -= n; + + if (*out_len < 1) + return -1; + } + + return blocks; +} + +static int +lws_jws_compact_decode_map(struct lws_jws_compact_map *map_b64, + struct lws_jws_compact_map *map, char *out, + int *out_len) +{ + int n, m = 0; + + for (n = 0; n < LWS_JWS_MAX_COMPACT_BLOCKS; n++) { + n = lws_b64_decode_string_len(map_b64->buf[m], + map_b64->len[m], out, *out_len); + if (n < 0) { + lwsl_err("%s: b64 decode failed\n", __func__); + return -1; + } + /* replace the map entry with the decoded content */ + map->buf[m] = out; + map->len[m++] = n; + out += n; + *out_len -= n; + + if (*out_len < 1) + return -1; + } + + return 0; +} + LWS_VISIBLE int lws_jws_encode_section(const char *in, size_t in_len, int first, char **p, char *end) @@ -62,71 +270,81 @@ lws_jws_encode_section(const char *in, size_t in_len, int first, char **p, return (*p) - p_entry; } -static int -lws_jws_find_sig(const char *in, size_t len) +LWS_VISIBLE int +lws_jws_compact_encode(struct lws_jws_compact_map *map_b64, /* b64-encoded */ + const struct lws_jws_compact_map *map, /* non-b64 */ + char *buf, int *len) { - const char *p = in + len - 1; + int n, m; - while (len--) - if (*p == '.') - return (p + 1) - in; - else - p--; + for (n = 0; n < LWS_JWS_MAX_COMPACT_BLOCKS; n++) { + if (!map->buf[n]) { + map_b64->buf[n] = NULL; + map_b64->len[n] = 0; + continue; + } + m = lws_jws_base64_enc(map->buf[n], map->len[n], buf, *len); + if (m < 0) + return -1; + buf += m; + *len -= m; + if (*len < 1) + return -1; + } - lwsl_notice("%s failed\n", __func__); - return -1; + return 0; } +/* + * This takes both a base64 -encoded map and a plaintext map. + * + * JWS demands base-64 encoded elements for hash computation and at least for + * the JOSE header and signature, decoded versions too. + */ + LWS_VISIBLE int -lws_jws_confirm_sig(const char *in, size_t len, struct lws_jwk *jwk, - struct lws_context *context) +lws_jws_sig_confirm(struct lws_jws_compact_map *map_b64, /* b64-encoded */ + struct lws_jws_compact_map *map, /* non-b64 */ + struct lws_jwk *jwk, struct lws_context *context) { - int sig_pos = lws_jws_find_sig(in, len), pos = 0, n, m, h_len; enum enum_genrsa_mode padding = LGRSAM_PKCS1_1_5; + char temp[256]; + int n, h_len, b = 3, temp_len = sizeof(temp); uint8_t digest[LWS_GENHASH_LARGEST]; - const struct lws_jose_jwe_alg *args = NULL; struct lws_genhash_ctx hash_ctx; struct lws_genec_ctx ecdsactx; struct lws_genrsa_ctx rsactx; struct lws_genhmac_ctx ctx; - char buf[2048]; + struct lws_jose jose; - /* 1) there has to be a signature */ + lws_jose_init(&jose); - if (sig_pos < 0) - return -1; + /* only valid if no signature or key */ + if (!map_b64->buf[LJWS_SIG] && !map->buf[LJWS_UHDR]) + b = 2; - /* 2) find length of first, hdr, block */ - - while (pos < (int)len && in[pos] != '.') - pos++; - if (pos == (int)len) - return -1; - - /* 3) Decode the header block */ - - n = lws_b64_decode_string_len(in, pos, buf, sizeof(buf) - 1); - if (n < 0) - return -1; - - /* 4) Require either: - * typ: JWT (if present) and alg: HS256/384/512 - * typ: JWT (if present) and alg: RS256/384/512 - * typ: JWT (if present) and alg: ES256/384/512 - */ - - m = lws_jws_parse_jose(&args, (unsigned char *)buf, n); - if (m < 0) { - lwsl_notice("parse got %d: alg %s\n", m, args->alg); + if (lws_jws_parse_jose(&jose, map->buf[LJWS_JOSE], map->len[LJWS_JOSE], + temp, &temp_len) < 0) { + lwsl_notice("%s: parse failed\n", __func__); return -1; } - /* 5) decode the B64URL signature part into buf / m */ + if (!strcmp(jose.alg->alg, "none")) { + /* "none" compact serialization has 2 blocks: jose.payload */ + if (b != 2 || jwk) + return -1; - m = lws_b64_decode_string_len(in + sig_pos, len - sig_pos, - buf, sizeof(buf) - 1); + /* the lack of a key matches the lack of a signature */ + return 0; + } - switch (args->algtype_signing) { + /* all other have 3 blocks: jose.payload.sig */ + if (b != 3 || !jwk) { + lwsl_notice("%s: %d blocks\n", __func__, b); + return -1; + } + + switch (jose.alg->algtype_signing) { case LWS_JOSE_ENCTYPE_RSASSA_PKCS1_PSS: case LWS_JOSE_ENCTYPE_RSASSA_PKCS1_OAEP: padding = LGRSAM_PKCS1_OAEP_PSS; @@ -135,67 +353,87 @@ lws_jws_confirm_sig(const char *in, size_t len, struct lws_jwk *jwk, /* RSASSA-PKCS1-v1_5 or OAEP using SHA-256/384/512 */ - if (jwk->kty != LWS_GENCRYPTO_KYT_RSA) + if (jwk->kty != LWS_GENCRYPTO_KTY_RSA) return -1; /* 6(RSA): compute the hash of the payload into "digest" */ - if (lws_genhash_init(&hash_ctx, args->hash_type)) + if (lws_genhash_init(&hash_ctx, jose.alg->hash_type)) return -1; - if (lws_genhash_update(&hash_ctx, (uint8_t *)in, sig_pos - 1)) { + /* + * JWS Signing Input value: + * + * BASE64URL(UTF8(JWS Protected Header)) || '.' || + * BASE64URL(JWS Payload) + */ + + if (lws_genhash_update(&hash_ctx, map_b64->buf[LJWS_JOSE], + map_b64->len[LJWS_JOSE]) || + lws_genhash_update(&hash_ctx, ".", 1) || + lws_genhash_update(&hash_ctx, map_b64->buf[LJWS_PYLD], + map_b64->len[LJWS_PYLD]) || + lws_genhash_destroy(&hash_ctx, digest)) { lws_genhash_destroy(&hash_ctx, NULL); return -1; } - if (lws_genhash_destroy(&hash_ctx, digest)) - return -1; + h_len = lws_genhash_size(jose.alg->hash_type); - h_len = lws_genhash_size(args->hash_type); - - if (lws_genrsa_create(&rsactx, jwk->e, context, padding)) { + if (lws_genrsa_create(&rsactx, jwk->e, context, padding, + LWS_GENHASH_TYPE_UNKNOWN)) { lwsl_notice("%s: lws_genrsa_public_decrypt_create\n", __func__); return -1; } - n = lws_genrsa_hash_sig_verify(&rsactx, digest, args->hash_type, - (uint8_t *)buf, m); + n = lws_genrsa_hash_sig_verify(&rsactx, digest, + jose.alg->hash_type, + (uint8_t *)map->buf[LJWS_SIG], + map->len[LJWS_SIG]); lws_genrsa_destroy(&rsactx); if (n < 0) { - lwsl_notice("decrypt fail\n"); + lwsl_notice("%s: decrypt fail\n", __func__); return -1; } break; - case LWS_JOSE_ENCTYPE_NONE: + case LWS_JOSE_ENCTYPE_NONE: /* HSxxx */ /* SHA256/384/512 HMAC */ - h_len = lws_genhmac_size(args->hmac_type); - if (m < 0 || m != h_len) - return -1; + h_len = lws_genhmac_size(jose.alg->hmac_type); /* 6) compute HMAC over payload */ - if (lws_genhmac_init(&ctx, args->hmac_type, + if (lws_genhmac_init(&ctx, jose.alg->hmac_type, jwk->e[LWS_GENCRYPTO_RSA_KEYEL_E].buf, jwk->e[LWS_GENCRYPTO_RSA_KEYEL_E].len)) return -1; - if (lws_genhmac_update(&ctx, (uint8_t *)in, sig_pos - 1)) { + /* + * JWS Signing Input value: + * + * BASE64URL(UTF8(JWS Protected Header)) || '.' || + * BASE64URL(JWS Payload) + */ + + if (lws_genhmac_update(&ctx, map_b64->buf[LJWS_JOSE], + map_b64->len[LJWS_JOSE]) || + lws_genhmac_update(&ctx, ".", 1) || + lws_genhmac_update(&ctx, map_b64->buf[LJWS_PYLD], + map_b64->len[LJWS_PYLD]) || + lws_genhmac_destroy(&ctx, digest)) { lws_genhmac_destroy(&ctx, NULL); return -1; } - if (lws_genhmac_destroy(&ctx, digest)) - return -1; /* 7) Compare the computed and decoded hashes */ - if (memcmp(digest, buf, h_len)) { + if (lws_timingsafe_bcmp(digest, map->buf[2], h_len)) { lwsl_notice("digest mismatch\n"); return -1; @@ -207,10 +445,10 @@ lws_jws_confirm_sig(const char *in, size_t len, struct lws_jwk *jwk, /* ECDSA using SHA-256/384/512 */ - /* the key coming in with this makes sense, right? */ + /* Confirm the key coming in with this makes sense */ /* has to be an EC key :-) */ - if (jwk->kty != LWS_GENCRYPTO_KYT_EC) + if (jwk->kty != LWS_GENCRYPTO_KTY_EC) return -1; /* key must state its curve */ @@ -219,23 +457,41 @@ lws_jws_confirm_sig(const char *in, size_t len, struct lws_jwk *jwk, /* key must match the selected alg curve */ if (strcmp((const char *)jwk->e[LWS_GENCRYPTO_EC_KEYEL_CRV].buf, - args->curve_name)) + jose.alg->curve_name)) return -1; - /* compute the hash of the payload into "digest" */ + /* + * JWS Signing Input value: + * + * BASE64URL(UTF8(JWS Protected Header)) || '.' || + * BASE64URL(JWS Payload) + * + * Validating the JWS Signature is a bit different from the + * previous examples. We need to split the 64 member octet + * sequence of the JWS Signature (which is base64url decoded + * from the value encoded in the JWS representation) into two + * 32 octet sequences, the first representing R and the second + * S. We then pass the public key (x, y), the signature (R, S), + * and the JWS Signing Input (which is the initial substring of + * the JWS Compact Serialization representation up until but not + * including the second period character) to an ECDSA signature + * verifier that has been configured to use the P-256 curve with + * the SHA-256 hash function. + */ - if (lws_genhash_init(&hash_ctx, args->hash_type)) - return -1; - - if (lws_genhash_update(&hash_ctx, (uint8_t *)in, sig_pos - 1)) { + if (lws_genhash_init(&hash_ctx, jose.alg->hash_type) || + lws_genhash_update(&hash_ctx, map_b64->buf[LJWS_JOSE], + map_b64->len[LJWS_JOSE]) || + lws_genhash_update(&hash_ctx, ".", 1) || + lws_genhash_update(&hash_ctx, map_b64->buf[LJWS_PYLD], + map_b64->len[LJWS_PYLD]) || + lws_genhash_destroy(&hash_ctx, digest)) { lws_genhash_destroy(&hash_ctx, NULL); return -1; } - if (lws_genhash_destroy(&hash_ctx, digest)) - return -1; - h_len = lws_genhash_size(args->hash_type); + h_len = lws_genhash_size(jose.alg->hash_type); if (lws_genecdsa_create(&ecdsactx, context, NULL)) { lwsl_notice("%s: lws_genrsa_public_decrypt_create\n", @@ -249,13 +505,14 @@ lws_jws_confirm_sig(const char *in, size_t len, struct lws_jwk *jwk, return -1; } - n = lws_genecdsa_hash_sig_verify(&ecdsactx, digest, - args->hash_type, - (uint8_t *)buf, m); - + n = lws_genecdsa_hash_sig_verify_jws(&ecdsactx, digest, + jose.alg->hash_type, + jose.alg->keybits_fixed, + (uint8_t *)map->buf[LJWS_SIG], + map->len[LJWS_SIG]); lws_genec_destroy(&ecdsactx); if (n < 0) { - lwsl_notice("decrypt fail\n"); + lwsl_notice("%s: verify fail\n", __func__); return -1; } @@ -269,60 +526,121 @@ lws_jws_confirm_sig(const char *in, size_t len, struct lws_jwk *jwk, return 0; } +/* it's already a b64 map, we will make a temp plain version */ + LWS_VISIBLE int -lws_jws_sign_from_b64(const char *b64_hdr, size_t hdr_len, const char *b64_pay, - size_t pay_len, char *b64_sig, size_t sig_len, - const struct lws_jose_jwe_alg *args, - struct lws_jwk *jwk, - struct lws_context *context) +lws_jws_sig_confirm_compact_b64_map(struct lws_jws_compact_map *map_b64, + struct lws_jwk *jwk, + struct lws_context *context, + char *temp, int *temp_len) { - enum enum_genrsa_mode padding = LGRSAM_PKCS1_1_5; + struct lws_jws_compact_map map; + int n; + + n = lws_jws_compact_decode_map(map_b64, &map, temp, temp_len); + if (n > 3 || n < 0) + return -1; + + return lws_jws_sig_confirm(map_b64, &map, jwk, context); +} + +/* + * it's already a compact / concatenated b64 string, we will make a temp + * plain version + */ + +LWS_VISIBLE int +lws_jws_sig_confirm_compact_b64(const char *in, size_t len, + struct lws_jws_compact_map *map, + struct lws_jwk *jwk, + struct lws_context *context, + char *temp, int *temp_len) +{ + struct lws_jws_compact_map map_b64; + int n; + + if (lws_jws_b64_compact_map(in, len, &map_b64) < 0) + return -1; + + n = lws_jws_compact_decode(in, len, map, &map_b64, temp, temp_len); + if (n > 3 || n < 0) + return -1; + + return lws_jws_sig_confirm(&map_b64, map, jwk, context); +} + +/* it's already plain, we will make a temp b64 version */ + +LWS_VISIBLE int +lws_jws_sig_confirm_compact(struct lws_jws_compact_map *map, struct lws_jwk *jwk, + struct lws_context *context, char *temp, + int *temp_len) +{ + struct lws_jws_compact_map map_b64; + + if (lws_jws_compact_encode(&map_b64, map, temp, temp_len) < 0) + return -1; + + return lws_jws_sig_confirm(&map_b64, map, jwk, context); +} + + +LWS_VISIBLE int +lws_jws_sign_from_b64(struct lws_jose *jose, struct lws_jws *jws, + char *b64_sig, size_t sig_len) +{ + enum enum_genrsa_mode pad = LGRSAM_PKCS1_1_5; uint8_t digest[LWS_GENHASH_LARGEST]; struct lws_genhash_ctx hash_ctx; struct lws_genec_ctx ecdsactx; struct lws_genrsa_ctx rsactx; - int n, m; uint8_t *buf; + int n, m; + + if (jose->alg->hash_type == LWS_GENHASH_TYPE_UNKNOWN && + jose->alg->hmac_type == LWS_GENHMAC_TYPE_UNKNOWN && + !strcmp(jose->alg->alg, "none")) + return 0; + + if (lws_genhash_init(&hash_ctx, jose->alg->hash_type) || + lws_genhash_update(&hash_ctx, jws->map_b64.buf[LJWS_JOSE], + jws->map_b64.len[LJWS_JOSE]) || + lws_genhash_update(&hash_ctx, ".", 1) || + lws_genhash_update(&hash_ctx, jws->map_b64.buf[LJWS_PYLD], + jws->map_b64.len[LJWS_PYLD]) || + lws_genhash_destroy(&hash_ctx, digest)) { + lws_genhash_destroy(&hash_ctx, NULL); - if (lws_genhash_init(&hash_ctx, args->hash_type)) return -1; - - if (b64_hdr) { - if (lws_genhash_update(&hash_ctx, (uint8_t *)b64_hdr, hdr_len)) - goto hash_fail; - if (lws_genhash_update(&hash_ctx, (uint8_t *)".", 1)) - goto hash_fail; } - if (lws_genhash_update(&hash_ctx, (uint8_t *)b64_pay, pay_len)) - goto hash_fail; - if (lws_genhash_destroy(&hash_ctx, digest)) - return -1; - - switch (args->algtype_signing) { + switch (jose->alg->algtype_signing) { case LWS_JOSE_ENCTYPE_RSASSA_PKCS1_PSS: case LWS_JOSE_ENCTYPE_RSASSA_PKCS1_OAEP: - padding = LGRSAM_PKCS1_OAEP_PSS; + pad = LGRSAM_PKCS1_OAEP_PSS; /* fallthru */ case LWS_JOSE_ENCTYPE_RSASSA_PKCS1_1_5: - if (jwk->kty != LWS_GENCRYPTO_KYT_RSA) + if (jws->jwk->kty != LWS_GENCRYPTO_KTY_RSA) return -1; - if (lws_genrsa_create(&rsactx, jwk->e, context, padding)) { + if (lws_genrsa_create(&rsactx, jws->jwk->e, jws->context, + pad, LWS_GENHASH_TYPE_UNKNOWN)) { lwsl_notice("%s: lws_genrsa_public_decrypt_create\n", __func__); return -1; } - n = jwk->e[LWS_GENCRYPTO_RSA_KEYEL_N].len; - buf = lws_malloc(n, "jws sign"); + n = jws->jwk->e[LWS_GENCRYPTO_RSA_KEYEL_N].len; + buf = lws_malloc(lws_base64_size(n), "jws sign"); if (!buf) return -1; - n = lws_genrsa_hash_sign(&rsactx, digest, args->hash_type, buf, n); + n = lws_genrsa_hash_sign(&rsactx, digest, jose->alg->hash_type, + buf, n); lws_genrsa_destroy(&rsactx); if (n < 0) { + lwsl_err("%s: lws_genrsa_hash_sign failed\n", __func__); lws_free(buf); return -1; @@ -330,12 +648,15 @@ lws_jws_sign_from_b64(const char *b64_hdr, size_t hdr_len, const char *b64_pay, n = lws_jws_base64_enc((char *)buf, n, b64_sig, sig_len); lws_free(buf); + if (n < 0) { + lwsl_err("%s: lws_jws_base64_enc failed\n", __func__); + } return n; case LWS_JOSE_ENCTYPE_NONE: return lws_jws_base64_enc((char *)digest, - lws_genhash_size(args->hash_type), + lws_genhash_size(jose->alg->hash_type), b64_sig, sig_len); case LWS_JOSE_ENCTYPE_ECDSA: /* ECDSA using SHA-256/384/512 */ @@ -343,47 +664,53 @@ lws_jws_sign_from_b64(const char *b64_hdr, size_t hdr_len, const char *b64_pay, /* the key coming in with this makes sense, right? */ /* has to be an EC key :-) */ - if (jwk->kty != LWS_GENCRYPTO_KYT_EC) + if (jws->jwk->kty != LWS_GENCRYPTO_KTY_EC) return -1; /* key must state its curve */ - if (!jwk->e[LWS_GENCRYPTO_EC_KEYEL_CRV].buf) + if (!jws->jwk->e[LWS_GENCRYPTO_EC_KEYEL_CRV].buf) return -1; /* must have all his pieces for a private key */ - if (!jwk->e[LWS_GENCRYPTO_EC_KEYEL_X].buf || - !jwk->e[LWS_GENCRYPTO_EC_KEYEL_Y].buf || - !jwk->e[LWS_GENCRYPTO_EC_KEYEL_D].buf) + if (!jws->jwk->e[LWS_GENCRYPTO_EC_KEYEL_X].buf || + !jws->jwk->e[LWS_GENCRYPTO_EC_KEYEL_Y].buf || + !jws->jwk->e[LWS_GENCRYPTO_EC_KEYEL_D].buf) return -1; /* key must match the selected alg curve */ - if (strcmp((const char *)jwk->e[LWS_GENCRYPTO_EC_KEYEL_CRV].buf, - args->curve_name)) + if (strcmp((const char *) + jws->jwk->e[LWS_GENCRYPTO_EC_KEYEL_CRV].buf, + jose->alg->curve_name)) return -1; - if (lws_genecdsa_create(&ecdsactx, context, NULL)) { + if (lws_genecdsa_create(&ecdsactx, jws->context, NULL)) { lwsl_notice("%s: lws_genrsa_public_decrypt_create\n", __func__); return -1; } - if (lws_genecdsa_set_key(&ecdsactx, jwk->e)) { + if (lws_genecdsa_set_key(&ecdsactx, jws->jwk->e)) { lws_genec_destroy(&ecdsactx); lwsl_notice("%s: ec key import fail\n", __func__); return -1; } - m = jwk->e[LWS_GENCRYPTO_EC_KEYEL_D].len; + m = lws_gencrypto_bits_to_bytes(jose->alg->keybits_fixed) * 2; buf = lws_malloc(m, "jws sign"); if (!buf) return -1; - n = lws_genecdsa_hash_sign(&ecdsactx, digest, args->hash_type, - (uint8_t *)buf, m); + n = lws_genecdsa_hash_sign_jws(&ecdsactx, digest, + jose->alg->hash_type, + jose->alg->keybits_fixed, + (uint8_t *)buf, m); lws_genec_destroy(&ecdsactx); if (n < 0) { - lwsl_notice("decrypt fail\n"); + lws_free(buf); + lwsl_notice("%s: lws_genecdsa_hash_sign_jws fail\n", + __func__); return -1; } + n = lws_jws_base64_enc((char *)buf, m, b64_sig, sig_len); lws_free(buf); @@ -396,8 +723,57 @@ lws_jws_sign_from_b64(const char *b64_hdr, size_t hdr_len, const char *b64_pay, /* unknown key type */ return -1; - -hash_fail: - lws_genhash_destroy(&hash_ctx, NULL); - return -1; +} + +/* + * Flattened JWS JSON: + * + * { + * "payload": "", + * "protected": "", + * "header": , + * "signature": "" + * } + */ + +LWS_VISIBLE int +lws_jws_write_flattened_json(struct lws_jws *jws, char *flattened, size_t len) +{ + size_t n = 0; + + if (len < 1) + return 1; + + n += lws_snprintf(flattened + n, len - n , "{\"payload\": \"%s\",\n", + jws->map_b64.buf[LJWS_PYLD]); + + n += lws_snprintf(flattened + n, len - n , " \"protected\": \"%s\",\n", + jws->map_b64.buf[LJWS_JOSE]); + + if (jws->map_b64.buf[LJWS_UHDR]) + n += lws_snprintf(flattened + n, len - n , " \"header\": %s,\n", + jws->map_b64.buf[LJWS_UHDR]); + + n += lws_snprintf(flattened + n, len - n , " \"signature\": \"%s\"}\n", + jws->map_b64.buf[LJWS_SIG]); + + return (n >= len - 1); +} + +LWS_VISIBLE int +lws_jws_write_compact(struct lws_jws *jws, char *compact, size_t len) +{ + size_t n = 0; + + if (len < 1) + return 1; + + n += lws_snprintf(compact + n, len - n , "%.*s", + jws->map_b64.len[LJWS_JOSE], jws->map_b64.buf[LJWS_JOSE]); + n += lws_snprintf(compact + n, len - n , ".%.*s", + jws->map_b64.len[LJWS_PYLD], jws->map_b64.buf[LJWS_PYLD]); + n += lws_snprintf(compact + n, len - n , ".%.*s", + jws->map_b64.len[LJWS_SIG], jws->map_b64.buf[LJWS_SIG]); + + return n >= len - 1; } diff --git a/lib/jose/jws/private.h b/lib/jose/jws/private.h index c229e5a34..e7113d34a 100644 --- a/lib/jose/jws/private.h +++ b/lib/jose/jws/private.h @@ -22,11 +22,3 @@ * to specify its JOSE JSON object. So it lives in ./lib/jose/jws/jose.c. */ -int -lws_jws_parse_jose(const struct lws_jose_jwe_alg **args, - uint8_t *buf, int n); - -int -lws_jwe_parse_jose(const struct lws_jose_jwe_alg **args, - const struct lws_jose_jwe_alg **enc_args, - uint8_t *buf, int n); diff --git a/lib/jose/private.h b/lib/jose/private.h index cfa9c62a2..2985da385 100644 --- a/lib/jose/private.h +++ b/lib/jose/private.h @@ -21,3 +21,8 @@ void lws_jwk_destroy_elements(struct lws_gencrypto_keyelem *el, int m); + +void +lws_jwk_init_jps(struct lejp_ctx *jctx, struct lws_jwk_parse_state *jps, + struct lws_jwk *jwk, lws_jwk_key_import_callback cb, + void *user); diff --git a/lib/misc/fts/trie-fd.c b/lib/misc/fts/trie-fd.c index 9e9105e93..56289423c 100644 --- a/lib/misc/fts/trie-fd.c +++ b/lib/misc/fts/trie-fd.c @@ -711,10 +711,10 @@ ensure: if (lseek(ofd, fo, SEEK_SET) < 0) continue; - lbuf[sizeof(lbuf) - 1] = '\0'; m = read(ofd, lbuf, sizeof(lbuf) - 1); if (m < 0) continue; + lbuf[sizeof(lbuf) - 1] = '\0'; p = (unsigned char *)strchr((char *)lbuf, '\n'); if (p) diff --git a/lib/misc/lejp.c b/lib/misc/lejp.c index 599a6d37b..677e40aed 100644 --- a/lib/misc/lejp.c +++ b/lib/misc/lejp.c @@ -1,7 +1,7 @@ /* * Lightweight Embedded JSON Parser * - * Copyright (C) 2013-2017 Andy Green + * Copyright (C) 2013-2018 Andy Green * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -107,7 +107,7 @@ lejp_change_callback(struct lejp_ctx *ctx, ctx->callback(ctx, LEJPCB_START); } -static void +void lejp_check_path_match(struct lejp_ctx *ctx) { const char *p, *q; @@ -644,9 +644,11 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len) ret = LEJP_REJECT_CALLBACK; goto reject; } - ctx->callback(ctx, LEJPCB_COMPLETE); - /* done, return unused amount */ - return len; + if (ctx->callback(ctx, LEJPCB_COMPLETE)) + goto reject; + else + /* done, return unused amount */ + return len; } /* pop */ ctx->sp--; diff --git a/lib/misc/peer-limits.c b/lib/misc/peer-limits.c index cc4c07d63..53d9421fe 100644 --- a/lib/misc/peer-limits.c +++ b/lib/misc/peer-limits.c @@ -77,19 +77,20 @@ lws_get_or_create_peer(struct lws_vhost *vhost, lws_sockfd_type sockfd) /* eg, udp doesn't have to have a peer */ return NULL; - if (af == AF_INET) { +#ifdef LWS_WITH_IPV6 + if (af == AF_INET) +#endif + { struct sockaddr_in *s = (struct sockaddr_in *)&addr; q = &s->sin_addr; rlen = sizeof(s->sin_addr); - } else + } #ifdef LWS_WITH_IPV6 - { + else { struct sockaddr_in6 *s = (struct sockaddr_in6 *)&addr; q = &s->sin6_addr; rlen = sizeof(s->sin6_addr); } -#else - return NULL; #endif q8 = q; diff --git a/lib/roles/http/client/client.c b/lib/roles/http/client/client.c index f43b69f51..4015f4e12 100644 --- a/lib/roles/http/client/client.c +++ b/lib/roles/http/client/client.c @@ -127,7 +127,14 @@ lws_client_socket_service(struct lws *wsi, struct lws_pollfd *pollfd, * need to use that in HANDSHAKE2 to understand * which wsi to actually write on */ - lws_client_socket_service(wfound, pollfd, wsi); + if (lws_client_socket_service(wfound, pollfd, wsi) < 0) { + /* closed */ + + lws_vhost_unlock(wsi->vhost); + + return -1; + } + lws_callback_on_writable(wsi); } else lwsl_debug("%s: didn't find anything in txn q in HS2\n", diff --git a/lib/roles/http/server/server.c b/lib/roles/http/server/server.c index 063491bd3..dc5e5ff6d 100644 --- a/lib/roles/http/server/server.c +++ b/lib/roles/http/server/server.c @@ -1654,6 +1654,7 @@ lws_http_to_fallback(struct lws *wsi, unsigned char *obuf, size_t olen) const struct lws_role_ops *role = &role_ops_raw_skt; const struct lws_protocols *p1, *protocol = &wsi->vhost->protocols[wsi->vhost->raw_protocol_index]; + char ipbuf[64]; int n; if (wsi->vhost->listen_accept_role && @@ -1678,9 +1679,14 @@ lws_http_to_fallback(struct lws *wsi, unsigned char *obuf, size_t olen) if (wsi->role_ops->adoption_cb[lwsi_role_server(wsi)]) n = wsi->role_ops->adoption_cb[lwsi_role_server(wsi)]; - lwsl_notice("%s: vh %s, role %s, protocol %s, cb %d, ah %p\n", - __func__, wsi->vhost->name, role->name, protocol->name, n, - wsi->http.ah); + ipbuf[0] = '\0'; +#if !defined(LWS_PLAT_OPTEE) + lws_get_peer_simple(wsi, ipbuf, sizeof(ipbuf)); +#endif + + lwsl_notice("%s: vh %s, peer: %s, role %s, " + "protocol %s, cb %d, ah %p\n", __func__, wsi->vhost->name, + ipbuf, role->name, protocol->name, n, wsi->http.ah); if ((wsi->protocol->callback)(wsi, n, wsi->user_space, NULL, 0)) return 1; @@ -2630,8 +2636,7 @@ all_sent: #else ) #endif - ) - { + ) { lwsi_set_state(wsi, LRS_ESTABLISHED); /* we might be in keepalive, so close it off here */ lws_vfs_file_close(&wsi->http.fop_fd); @@ -2664,7 +2669,12 @@ all_sent: return 1; /* >0 indicates completed */ } - } while (1); //(!lws_send_pipe_choked(wsi)); + /* + * while(1) here causes us to spam the whole file contents into + * a hugely bloated output buffer if it ever can't send the + * whole chunk... + */ + } while (!lws_send_pipe_choked(wsi)); lws_callback_on_writable(wsi); diff --git a/lib/tls/lws-gencrypto-common.c b/lib/tls/lws-gencrypto-common.c index 4151524ca..e77d8497a 100644 --- a/lib/tls/lws-gencrypto-common.c +++ b/lib/tls/lws-gencrypto-common.c @@ -21,176 +21,460 @@ #include "core/private.h" /* - * Signing algorithms - * * These came from RFC7518 (JSON Web Algorithms) Section 3 + * + * Cryptographic Algorithms for Digital Signatures and MACs */ static const struct lws_jose_jwe_alg lws_gencrypto_jws_alg_map[] = { + + /* + * JWSs MAY also be created that do not provide integrity protection. + * Such a JWS is called an Unsecured JWS. An Unsecured JWS uses the + * "alg" value "none" and is formatted identically to other JWSs, but + * MUST use the empty octet sequence as its JWS Signature value. + * Recipients MUST verify that the JWS Signature value is the empty + * octet sequence. + * + * Implementations that support Unsecured JWSs MUST NOT accept such + * objects as valid unless the application specifies that it is + * acceptable for a specific object to not be integrity protected. + * Implementations MUST NOT accept Unsecured JWSs by default. In order + * to mitigate downgrade attacks, applications MUST NOT signal + * acceptance of Unsecured JWSs at a global level, and SHOULD signal + * acceptance on a per-object basis. See Section 8.5 for security + * considerations associated with using this algorithm. + */ { /* optional */ + LWS_GENHASH_TYPE_UNKNOWN, + LWS_GENHMAC_TYPE_UNKNOWN, + LWS_JOSE_ENCTYPE_NONE, + LWS_JOSE_ENCTYPE_NONE, + "none", NULL, 0, 0, 0 + }, + + /* + * HMAC with SHA-2 Functions + * + * The HMAC SHA-256 MAC for a JWS is validated by computing an HMAC + * value per RFC 2104, using SHA-256 as the hash algorithm "H", using + * the received JWS Signing Input as the "text" value, and using the + * shared key. This computed HMAC value is then compared to the result + * of base64url decoding the received encoded JWS Signature value. The + * comparison of the computed HMAC value to the JWS Signature value MUST + * be done in a constant-time manner to thwart timing attacks. + * + * Alternatively, the computed HMAC value can be base64url encoded and + * compared to the received encoded JWS Signature value (also in a + * constant-time manner), as this comparison produces the same result as + * comparing the unencoded values. In either case, if the values match, + * the HMAC has been validated. + */ + + { /* required: HMAC using SHA-256 */ LWS_GENHASH_TYPE_UNKNOWN, LWS_GENHMAC_TYPE_SHA256, LWS_JOSE_ENCTYPE_NONE, LWS_JOSE_ENCTYPE_NONE, - "none", NULL + "HS256", NULL, 0, 0, 0 }, - { /* required */ - LWS_GENHASH_TYPE_UNKNOWN, - LWS_GENHMAC_TYPE_SHA256, - LWS_JOSE_ENCTYPE_NONE, - LWS_JOSE_ENCTYPE_NONE, - "HS256", NULL - }, - { /* optional */ + { /* optional: HMAC using SHA-384 */ LWS_GENHASH_TYPE_UNKNOWN, LWS_GENHMAC_TYPE_SHA384, LWS_JOSE_ENCTYPE_NONE, LWS_JOSE_ENCTYPE_NONE, - "HS384", NULL + "HS384", NULL, 0, 0, 0 }, - { /* optional */ + { /* optional: HMAC using SHA-512 */ LWS_GENHASH_TYPE_UNKNOWN, LWS_GENHMAC_TYPE_SHA512, LWS_JOSE_ENCTYPE_NONE, LWS_JOSE_ENCTYPE_NONE, - "HS512", NULL + "HS512", NULL, 0, 0, 0 }, - { /* recommended */ + /* + * Digital Signature with RSASSA-PKCS1-v1_5 + * + * This section defines the use of the RSASSA-PKCS1-v1_5 digital + * signature algorithm as defined in Section 8.2 of RFC 3447 [RFC3447] + * (commonly known as PKCS #1), using SHA-2 [SHS] hash functions. + * + * A key of size 2048 bits or larger MUST be used with these algorithms. + * + * The RSASSA-PKCS1-v1_5 SHA-256 digital signature is generated as + * follows: generate a digital signature of the JWS Signing Input using + * RSASSA-PKCS1-v1_5-SIGN and the SHA-256 hash function with the desired + * private key. This is the JWS Signature value. + * + * The RSASSA-PKCS1-v1_5 SHA-256 digital signature for a JWS is + * validated as follows: submit the JWS Signing Input, the JWS + * Signature, and the public key corresponding to the private key used + * by the signer to the RSASSA-PKCS1-v1_5-VERIFY algorithm using SHA-256 + * as the hash function. + */ + + { /* recommended: RSASSA-PKCS1-v1_5 using SHA-256 */ LWS_GENHASH_TYPE_SHA256, LWS_GENHMAC_TYPE_UNKNOWN, LWS_JOSE_ENCTYPE_RSASSA_PKCS1_1_5, LWS_JOSE_ENCTYPE_NONE, - "RS256", NULL + "RS256", NULL, 2048, 4096, 0 }, - { /* optional */ + { /* optional: RSASSA-PKCS1-v1_5 using SHA-384 */ LWS_GENHASH_TYPE_SHA384, LWS_GENHMAC_TYPE_UNKNOWN, LWS_JOSE_ENCTYPE_RSASSA_PKCS1_1_5, LWS_JOSE_ENCTYPE_NONE, - "RS384", NULL + "RS384", NULL, 2048, 4096, 0 }, - { /* optional */ + { /* optional: RSASSA-PKCS1-v1_5 using SHA-512 */ LWS_GENHASH_TYPE_SHA512, LWS_GENHMAC_TYPE_UNKNOWN, LWS_JOSE_ENCTYPE_RSASSA_PKCS1_1_5, LWS_JOSE_ENCTYPE_NONE, - "RS512", NULL + "RS512", NULL, 2048, 4096, 0 }, - { /* Recommended+ */ + /* + * Digital Signature with ECDSA + * + * The ECDSA P-256 SHA-256 digital signature is generated as follows: + * + * 1. Generate a digital signature of the JWS Signing Input using ECDSA + * P-256 SHA-256 with the desired private key. The output will be + * the pair (R, S), where R and S are 256-bit unsigned integers. + * 2. Turn R and S into octet sequences in big-endian order, with each + * array being be 32 octets long. The octet sequence + * representations MUST NOT be shortened to omit any leading zero + * octets contained in the values. + * + * 3. Concatenate the two octet sequences in the order R and then S. + * (Note that many ECDSA implementations will directly produce this + * concatenation as their output.) + * + * 4. The resulting 64-octet sequence is the JWS Signature value. + * + * The ECDSA P-256 SHA-256 digital signature for a JWS is validated as + * follows: + * + * 1. The JWS Signature value MUST be a 64-octet sequence. If it is + * not a 64-octet sequence, the validation has failed. + * + * 2. Split the 64-octet sequence into two 32-octet sequences. The + * first octet sequence represents R and the second S. The values R + * and S are represented as octet sequences using the Integer-to- + * OctetString Conversion defined in Section 2.3.7 of SEC1 [SEC1] + * (in big-endian octet order). + * 3. Submit the JWS Signing Input, R, S, and the public key (x, y) to + * the ECDSA P-256 SHA-256 validator. + */ + + { /* Recommended+: ECDSA using P-256 and SHA-256 */ LWS_GENHASH_TYPE_SHA256, LWS_GENHMAC_TYPE_UNKNOWN, LWS_JOSE_ENCTYPE_ECDSA, LWS_JOSE_ENCTYPE_NONE, - "ES256", "P-256" + "ES256", "P-256", 256, 256, 0 }, - { /* optional */ + { /* optional: ECDSA using P-384 and SHA-384 */ LWS_GENHASH_TYPE_SHA384, LWS_GENHMAC_TYPE_UNKNOWN, LWS_JOSE_ENCTYPE_ECDSA, LWS_JOSE_ENCTYPE_NONE, - "ES384", "P-384" + "ES384", "P-384", 384, 384, 0 }, - { /* optional */ + { /* optional: ECDSA using P-521 and SHA-512 */ LWS_GENHASH_TYPE_SHA512, LWS_GENHMAC_TYPE_UNKNOWN, LWS_JOSE_ENCTYPE_ECDSA, LWS_JOSE_ENCTYPE_NONE, - "ES512", "P-521" + "ES512", "P-521", 521, 521, 0 }, +#if 0 + Not yet supported - { /* optional */ + /* + * Digital Signature with RSASSA-PSS + * + * A key of size 2048 bits or larger MUST be used with this algorithm. + * + * The RSASSA-PSS SHA-256 digital signature is generated as follows: + * generate a digital signature of the JWS Signing Input using RSASSA- + * PSS-SIGN, the SHA-256 hash function, and the MGF1 mask generation + * function with SHA-256 with the desired private key. This is the JWS + * Signature value. + * + * The RSASSA-PSS SHA-256 digital signature for a JWS is validated as + * follows: submit the JWS Signing Input, the JWS Signature, and the + * public key corresponding to the private key used by the signer to the + * RSASSA-PSS-VERIFY algorithm using SHA-256 as the hash function and + * using MGF1 as the mask generation function with SHA-256. + * + */ + { /* optional: RSASSA-PSS using SHA-256 and MGF1 with SHA-256 */ LWS_GENHASH_TYPE_SHA256, LWS_GENHMAC_TYPE_UNKNOWN, LWS_JOSE_ENCTYPE_RSASSA_PKCS1_PSS, LWS_JOSE_ENCTYPE_NONE, - "PS256", NULL + "PS256", NULL, 2048, 4096, 0 }, - { /* optional */ + { /* optional: RSASSA-PSS using SHA-384 and MGF1 with SHA-384 */ LWS_GENHASH_TYPE_SHA384, LWS_GENHMAC_TYPE_UNKNOWN, LWS_JOSE_ENCTYPE_RSASSA_PKCS1_PSS, LWS_JOSE_ENCTYPE_NONE, - "PS384", NULL + "PS384", NULL, 2048, 4096, 0 }, - { /* optional */ + { /* optional: RSASSA-PSS using SHA-512 and MGF1 with SHA-512*/ LWS_GENHASH_TYPE_SHA512, LWS_GENHMAC_TYPE_UNKNOWN, LWS_JOSE_ENCTYPE_RSASSA_PKCS1_PSS, LWS_JOSE_ENCTYPE_NONE, - "PS512", NULL + "PS512", NULL, 2048, 4096, 0 }, +#endif }; +/* + * These came from RFC7518 (JSON Web Algorithms) Section 4 + * + * Cryptographic Algorithms for Key Management + * + * JWE uses cryptographic algorithms to encrypt or determine the Content + * Encryption Key (CEK). + */ + static const struct lws_jose_jwe_alg lws_gencrypto_jwe_alg_map[] = { - { /* recommended- */ + + /* + * This section defines the specifics of encrypting a JWE CEK with + * RSAES-PKCS1-v1_5 [RFC3447]. The "alg" (algorithm) Header Parameter + * value "RSA1_5" is used for this algorithm. + * + * A key of size 2048 bits or larger MUST be used with this algorithm. + */ + + { /* recommended-: RSAES-PKCS1-v1_5 */ LWS_GENHASH_TYPE_SHA256, LWS_GENHMAC_TYPE_UNKNOWN, LWS_JOSE_ENCTYPE_RSASSA_PKCS1_1_5, LWS_JOSE_ENCTYPE_NONE, - "RSA1_5", NULL + "RSA1_5", NULL, 2048, 4096, 0 }, - { /* recommended+ */ + { /* recommended+: RSAES OAEP using default parameters */ LWS_GENHASH_TYPE_SHA1, LWS_GENHMAC_TYPE_UNKNOWN, LWS_JOSE_ENCTYPE_RSASSA_PKCS1_OAEP, LWS_JOSE_ENCTYPE_NONE, - "RSA-OAEP", NULL + "RSA-OAEP", NULL, 2048, 4096, 0 }, - - { /* recommended */ + { /* recommended+: RSAES OAEP using SHA-256 and MGF1 SHA-256 */ LWS_GENHASH_TYPE_SHA256, LWS_GENHMAC_TYPE_UNKNOWN, LWS_JOSE_ENCTYPE_RSASSA_PKCS1_OAEP, LWS_JOSE_ENCTYPE_NONE, - "A128KW", NULL - }, - { /* recommended */ - LWS_GENHASH_TYPE_SHA256, - LWS_GENHMAC_TYPE_UNKNOWN, - LWS_JOSE_ENCTYPE_RSASSA_PKCS1_OAEP, - LWS_JOSE_ENCTYPE_NONE, - "A256KW", NULL + "RSA-OAEP", NULL, 2048, 4096, 0 }, + /* + * Key Wrapping with AES Key Wrap + * + * This section defines the specifics of encrypting a JWE CEK with the + * Advanced Encryption Standard (AES) Key Wrap Algorithm [RFC3394] using + * the default initial value specified in Section 2.2.3.1 of that + * document. + * + * + */ + { /* recommended: AES Key Wrap with AES Key Wrap with defaults + using 128-bit key */ + LWS_GENHASH_TYPE_UNKNOWN, + LWS_GENHMAC_TYPE_UNKNOWN, + LWS_JOSE_ENCTYPE_AES_ECB, + LWS_JOSE_ENCTYPE_NONE, + "A128KW", NULL, 128, 128, 64 + }, + + { /* optional: AES Key Wrap with AES Key Wrap with defaults + using 192-bit key */ + LWS_GENHASH_TYPE_UNKNOWN, + LWS_GENHMAC_TYPE_UNKNOWN, + LWS_JOSE_ENCTYPE_AES_ECB, + LWS_JOSE_ENCTYPE_NONE, + "A192KW", NULL, 192, 192, 64 + }, + + { /* recommended: AES Key Wrap with AES Key Wrap with defaults + using 256-bit key */ + LWS_GENHASH_TYPE_UNKNOWN, + LWS_GENHMAC_TYPE_UNKNOWN, + LWS_JOSE_ENCTYPE_AES_ECB, + LWS_JOSE_ENCTYPE_NONE, + "A256KW", NULL, 256, 256, 64 + }, + + /* + * This section defines the specifics of directly performing symmetric + * key encryption without performing a key wrapping step. In this case, + * the shared symmetric key is used directly as the Content Encryption + * Key (CEK) value for the "enc" algorithm. An empty octet sequence is + * used as the JWE Encrypted Key value. The "alg" (algorithm) Header + * Parameter value "dir" is used in this case. + */ { /* recommended */ LWS_GENHASH_TYPE_UNKNOWN, LWS_GENHMAC_TYPE_UNKNOWN, LWS_JOSE_ENCTYPE_NONE, - LWS_JOSE_ENCTYPE_AES_GCM, - "dir", NULL + LWS_JOSE_ENCTYPE_NONE, + "dir", NULL, 0, 0, 0 }, - { /* recommended+ */ + /* + * Key Agreement with Elliptic Curve Diffie-Hellman Ephemeral Static + * (ECDH-ES) + * + * This section defines the specifics of key agreement with Elliptic + * Curve Diffie-Hellman Ephemeral Static [RFC6090], in combination with + * the Concat KDF, as defined in Section 5.8.1 of [NIST.800-56A]. The + * key agreement result can be used in one of two ways: + * + * 1. directly as the Content Encryption Key (CEK) for the "enc" + * algorithm, in the Direct Key Agreement mode, or + * + * 2. as a symmetric key used to wrap the CEK with the "A128KW", + * "A192KW", or "A256KW" algorithms, in the Key Agreement with Key + * Wrapping mode. + * + * A new ephemeral public key value MUST be generated for each key + * agreement operation. + * + * In Direct Key Agreement mode, the output of the Concat KDF MUST be a + * key of the same length as that used by the "enc" algorithm. In this + * case, the empty octet sequence is used as the JWE Encrypted Key + * value. The "alg" (algorithm) Header Parameter value "ECDH-ES" is + * used in the Direct Key Agreement mode. + * + * In Key Agreement with Key Wrapping mode, the output of the Concat KDF + * MUST be a key of the length needed for the specified key wrapping + * algorithm. In this case, the JWE Encrypted Key is the CEK wrapped + * with the agreed-upon key. + */ + + { /* recommended+: ECDH Ephemeral Static Key agreement Concat KDF */ LWS_GENHASH_TYPE_SHA256, LWS_GENHMAC_TYPE_UNKNOWN, - LWS_JOSE_ENCTYPE_RSASSA_PKCS1_OAEP, + LWS_JOSE_ENCTYPE_ECDHES, LWS_JOSE_ENCTYPE_NONE, - "ECDH-ES", NULL + "ECDH-ES", NULL, 128, 128, 0 }, - { /* recommended */ + { /* recommended: ECDH-ES + Concat KDF + wrapped by AES128KW */ LWS_GENHASH_TYPE_SHA256, LWS_GENHMAC_TYPE_UNKNOWN, - LWS_JOSE_ENCTYPE_RSASSA_PKCS1_OAEP, - LWS_JOSE_ENCTYPE_NONE, - "ECDH-ES+A128KW", NULL + LWS_JOSE_ENCTYPE_ECDHES, + LWS_JOSE_ENCTYPE_AES_ECB, + "ECDH-ES+A128KW", NULL, 128, 128, 0 }, - { /* recommended */ + { /* optional: ECDH-ES + Concat KDF + wrapped by AES192KW */ LWS_GENHASH_TYPE_SHA256, LWS_GENHMAC_TYPE_UNKNOWN, - LWS_JOSE_ENCTYPE_RSASSA_PKCS1_OAEP, + LWS_JOSE_ENCTYPE_ECDHES, + LWS_JOSE_ENCTYPE_AES_ECB, + "ECDH-ES+A192KW", NULL, 192, 192, 0 + }, + { /* recommended: ECDH-ES + Concat KDF + wrapped by AES256KW */ + LWS_GENHASH_TYPE_SHA256, + LWS_GENHMAC_TYPE_UNKNOWN, + LWS_JOSE_ENCTYPE_ECDHES, + LWS_JOSE_ENCTYPE_AES_ECB, + "ECDH-ES+A256KW", NULL, 256, 256, 0 + }, + + /* + * Key Encryption with AES GCM + * + * This section defines the specifics of encrypting a JWE Content + * Encryption Key (CEK) with Advanced Encryption Standard (AES) in + * Galois/Counter Mode (GCM) ([AES] and [NIST.800-38D]). + * + * Use of an Initialization Vector (IV) of size 96 bits is REQUIRED with + * this algorithm. The IV is represented in base64url-encoded form as + * the "iv" (initialization vector) Header Parameter value. + * + * The Additional Authenticated Data value used is the empty octet + * string. + * + * The requested size of the Authentication Tag output MUST be 128 bits, + * regardless of the key size. + * + * The JWE Encrypted Key value is the ciphertext output. + * + * The Authentication Tag output is represented in base64url-encoded + * form as the "tag" (authentication tag) Header Parameter value. + * + * + * "iv" (Initialization Vector) Header Parameter + * + * The "iv" (initialization vector) Header Parameter value is the + * base64url-encoded representation of the 96-bit IV value used for the + * key encryption operation. This Header Parameter MUST be present and + * MUST be understood and processed by implementations when these + * algorithms are used. + * + * "tag" (Authentication Tag) Header Parameter + * + * The "tag" (authentication tag) Header Parameter value is the + * base64url-encoded representation of the 128-bit Authentication Tag + * value resulting from the key encryption operation. This Header + * Parameter MUST be present and MUST be understood and processed by + * implementations when these algorithms are used. + */ + { /* optional: Key wrapping with AES GCM using 128-bit key */ + LWS_GENHASH_TYPE_UNKNOWN, + LWS_GENHMAC_TYPE_UNKNOWN, + LWS_JOSE_ENCTYPE_AES_ECB, LWS_JOSE_ENCTYPE_NONE, - "ECDH-ES+A256KW", NULL + "A128GCMKW", NULL, 128, 128, 96 + }, + + { /* optional: Key wrapping with AES GCM using 192-bit key */ + LWS_GENHASH_TYPE_UNKNOWN, + LWS_GENHMAC_TYPE_UNKNOWN, + LWS_JOSE_ENCTYPE_AES_ECB, + LWS_JOSE_ENCTYPE_NONE, + "A192GCMKW", NULL, 192, 192, 96 + }, + + { /* optional: Key wrapping with AES GCM using 256-bit key */ + LWS_GENHASH_TYPE_UNKNOWN, + LWS_GENHMAC_TYPE_UNKNOWN, + LWS_JOSE_ENCTYPE_AES_ECB, + LWS_JOSE_ENCTYPE_NONE, + "A256GCMKW", NULL, 256, 256, 96 }, /* list terminator */ { 0, 0, 0, 0, NULL, NULL } }; +/* + * The "enc" (encryption algorithm) Header Parameter identifies the + * content encryption algorithm used to perform authenticated encryption + * on the plaintext to produce the ciphertext and the Authentication + * Tag. This algorithm MUST be an AEAD algorithm with a specified key + * length. The encrypted content is not usable if the "enc" value does + * not represent a supported algorithm. "enc" values should either be + * registered in the IANA "JSON Web Signature and Encryption Algorithms" + * registry established by [JWA] or be a value that contains a + * Collision-Resistant Name. The "enc" value is a case-sensitive ASCII + * string containing a StringOrURI value. This Header Parameter MUST be + * present and MUST be understood and processed by implementations. + */ static const struct lws_jose_jwe_alg lws_gencrypto_jwe_enc_map[] = { /* + * AES_128_CBC_HMAC_SHA_256 / 512 + * * It uses the HMAC message authentication code [RFC2104] with the * SHA-256 hash function [SHS] to provide message authentication, with * the HMAC output truncated to 128 bits, corresponding to the @@ -213,7 +497,71 @@ static const struct lws_jose_jwe_alg lws_gencrypto_jwe_enc_map[] = { LWS_GENHMAC_TYPE_SHA256, LWS_JOSE_ENCTYPE_NONE, LWS_JOSE_ENCTYPE_AES_CBC, - "A128CBC-HS256", NULL + "A128CBC-HS256", NULL, 256, 256, 128 + }, + /* + * AES_192_CBC_HMAC_SHA_384 is based on AES_128_CBC_HMAC_SHA_256, but + * with the following differences: + * + * The input key K is 48 octets long instead of 32. + * ENC_KEY_LEN is 24 octets instead of 16. + * MAC_KEY_LEN is 24 octets instead of 16. + * SHA-384 is used for the HMAC instead of SHA-256. + * The HMAC SHA-384 value is truncated to T_LEN=24 octets instead of 16. + */ + { /* required */ + LWS_GENHASH_TYPE_UNKNOWN, + LWS_GENHMAC_TYPE_SHA384, + LWS_JOSE_ENCTYPE_NONE, + LWS_JOSE_ENCTYPE_AES_CBC, + "A192CBC-HS384", NULL, 384, 384, 192 + }, + /* + * AES_256_CBC_HMAC_SHA_512 is based on AES_128_CBC_HMAC_SHA_256, but + * with the following differences: + * + * The input key K is 64 octets long instead of 32. + * ENC_KEY_LEN is 32 octets instead of 16. + * MAC_KEY_LEN is 32 octets instead of 16. + * SHA-512 is used for the HMAC instead of SHA-256. + * The HMAC SHA-512 value is truncated to T_LEN=32 octets instead of 16. + */ + { /* required */ + LWS_GENHASH_TYPE_UNKNOWN, + LWS_GENHMAC_TYPE_SHA512, + LWS_JOSE_ENCTYPE_NONE, + LWS_JOSE_ENCTYPE_AES_CBC, + "A256CBC-HS512", NULL, 512, 512, 256 + }, + + /* + * The CEK is used as the encryption key. + * + * Use of an IV of size 96 bits is REQUIRED with this algorithm. + * + * The requested size of the Authentication Tag output MUST be 128 bits, + * regardless of the key size. + */ + { /* recommended: AES GCM using 128-bit key */ + LWS_GENHASH_TYPE_UNKNOWN, + LWS_GENHMAC_TYPE_UNKNOWN, + LWS_JOSE_ENCTYPE_NONE, + LWS_JOSE_ENCTYPE_AES_GCM, + "A128GCM", NULL, 128, 128, 96 + }, + { /* optional: AES GCM using 192-bit key */ + LWS_GENHASH_TYPE_UNKNOWN, + LWS_GENHMAC_TYPE_UNKNOWN, + LWS_JOSE_ENCTYPE_NONE, + LWS_JOSE_ENCTYPE_AES_GCM, + "A192GCM", NULL, 192, 192, 96 + }, + { /* recommended: AES GCM using 256-bit key */ + LWS_GENHASH_TYPE_UNKNOWN, + LWS_GENHMAC_TYPE_UNKNOWN, + LWS_JOSE_ENCTYPE_NONE, + LWS_JOSE_ENCTYPE_AES_GCM, + "A256GCM", NULL, 256, 256, 96 }, }; @@ -306,3 +654,28 @@ lws_genhmac_size(enum lws_genhmac_types type) return 0; } + +int +lws_gencrypto_bits_to_bytes(int bits) +{ + if (bits & 7) + return (bits / 8) + 1; + + return bits / 8; +} + +int +lws_base64_size(int bytes) +{ + return ((bytes * 4) / 3) + 6; +} + +void +lws_gencrypto_destroy_elements(struct lws_gencrypto_keyelem *el, int m) +{ + int n; + + for (n = 0; n < m; n++) + if (el[n].buf) + lws_free_set_NULL(el[n].buf); +} diff --git a/lib/tls/lws-genec-common.c b/lib/tls/lws-genec-common.c index f9e7b1220..d3e6da225 100644 --- a/lib/tls/lws-genec-common.c +++ b/lib/tls/lws-genec-common.c @@ -57,6 +57,8 @@ lws_genec_dump(struct lws_gencrypto_keyelem *el) { int n; + (void)enames; + lwsl_info(" genec %p: crv: '%s'\n", el, !!el[LWS_GENCRYPTO_EC_KEYEL_CRV].buf ? (char *)el[LWS_GENCRYPTO_EC_KEYEL_CRV].buf: "no curve name"); diff --git a/lib/tls/mbedtls/lws-genaes.c b/lib/tls/mbedtls/lws-genaes.c index 8f3d87894..0e4da8179 100644 --- a/lib/tls/mbedtls/lws-genaes.c +++ b/lib/tls/mbedtls/lws-genaes.c @@ -29,9 +29,9 @@ static int operation_map[] = { MBEDTLS_AES_ENCRYPT, MBEDTLS_AES_DECRYPT }; LWS_VISIBLE int lws_genaes_create(struct lws_genaes_ctx *ctx, enum enum_aes_operation op, enum enum_aes_modes mode, struct lws_gencrypto_keyelem *el, - int padding, void *engine) + enum enum_aes_padding padding, void *engine) { - int n; + int n = 0; ctx->mode = mode; ctx->k = el; @@ -40,8 +40,12 @@ lws_genaes_create(struct lws_genaes_ctx *ctx, enum enum_aes_operation op, switch (ctx->mode) { case LWS_GAESM_XTS: +#if defined(MBEDTLS_CIPHER_MODE_XTS) mbedtls_aes_xts_init(&ctx->u.ctx_xts); break; +#else + return -1; +#endif case LWS_GAESM_GCM: mbedtls_gcm_init(&ctx->u.ctx_gcm); n = mbedtls_gcm_setkey(&ctx->u.ctx_gcm, MBEDTLS_CIPHER_ID_AES, @@ -107,23 +111,22 @@ lws_genaes_create(struct lws_genaes_ctx *ctx, enum enum_aes_operation op, LWS_VISIBLE int lws_genaes_destroy(struct lws_genaes_ctx *ctx, unsigned char *tag, size_t tlen) { - int n; + int n = 0; if (ctx->mode == LWS_GAESM_GCM) { - if (tag) { - n = mbedtls_gcm_finish(&ctx->u.ctx_gcm, tag, tlen); - if (n) - lwsl_notice("%s: mbedtls_gcm_finish: -0x%x\n", - __func__, -n); - else - if (memcmp(ctx->tag, tag, ctx->taglen)) { - lwsl_err("%s: lws_genaes_crypt tag " - "mismatch (bad first)\n", - __func__); - lwsl_hexdump_notice(tag, tlen); - lwsl_hexdump_notice(ctx->tag, ctx->taglen); - n = -1; - } + n = mbedtls_gcm_finish(&ctx->u.ctx_gcm, tag, tlen); + if (n) + lwsl_notice("%s: mbedtls_gcm_finish: -0x%x\n", + __func__, -n); + if (tag && ctx->op == MBEDTLS_AES_DECRYPT && !n) { + if (lws_timingsafe_bcmp(ctx->tag, tag, ctx->taglen)) { + lwsl_err("%s: lws_genaes_crypt tag " + "mismatch (bad first)\n", + __func__); + lwsl_hexdump_notice(tag, tlen); + lwsl_hexdump_notice(ctx->tag, ctx->taglen); + n = -1; + } } mbedtls_gcm_free(&ctx->u.ctx_gcm); return n; @@ -140,15 +143,134 @@ lws_genaes_destroy(struct lws_genaes_ctx *ctx, unsigned char *tag, size_t tlen) return 0; } +static int +lws_genaes_rfc3394_wrap(int wrap, int cek_bits, const uint8_t *kek, + int kek_bits, const uint8_t *in, uint8_t *out) +{ + int n, m, ret = -1, c64 = cek_bits / 64; + mbedtls_aes_context ctx; + uint8_t a[8], b[16]; + + /* + * notice the KEK key used to perform the wrapping or unwrapping is + * always the size of the AES key used, eg, A128KW == 128 bits. The + * key being wrapped or unwrapped may be larger and is set by the + * 'bits' parameter. + * + * If it's larger than the KEK key size bits, we iterate over it + */ + + mbedtls_aes_init(&ctx); + + if (wrap) { + /* + * The inputs to the key wrapping process are the KEK and the + * plaintext to be wrapped. The plaintext consists of n 64-bit + * blocks, containing the key data being wrapped. + * + * Inputs: Plaintext, n 64-bit values {P1, P2, ..., Pn}, + * and Key, K (the KEK). + * Outputs: Ciphertext, (n+1) 64-bit values + * {C0, C1, ..., Cn}. + * + * The default initial value (IV) is defined to be the + * hexadecimal constant: + * + * A[0] = IV = A6A6A6A6A6A6A6A6 + */ + memset(out, 0xa6, 8); + memcpy(out + 8, in, 8 * c64); + n = mbedtls_aes_setkey_enc(&ctx, kek, kek_bits); + } else { + /* + * 2.2.2 Key Unwrap + * + * The inputs to the unwrap process are the KEK and (n+1) + * 64-bit blocks of ciphertext consisting of previously + * wrapped key. It returns n blocks of plaintext consisting + * of the n 64-bit blocks of the decrypted key data. + * + * Inputs: Ciphertext, (n+1) 64-bit values {C0, C1, ..., Cn}, + * and Key, K (the KEK). + * + * Outputs: Plaintext, n 64-bit values {P1, P2, ..., Pn}. + */ + memcpy(a, in, 8); + memcpy(out, in + 8, 8 * c64); + n = mbedtls_aes_setkey_dec(&ctx, kek, kek_bits); + } + + if (n < 0) { + lwsl_err("%s: setkey failed\n", __func__); + goto bail; + } + + if (wrap) { + for (n = 0; n <= 5; n++) { + uint8_t *r = out + 8; + for (m = 1; m <= c64; m++) { + memcpy(b, out, 8); + memcpy(b + 8, r, 8); + if (mbedtls_internal_aes_encrypt(&ctx, b, b)) + goto bail; + + memcpy(out, b, 8); + out[7] ^= c64 * n + m; + memcpy(r, b + 8, 8); + r += 8; + } + } + ret = 0; + } else { + /* + * + */ + for (n = 5; n >= 0; n--) { + uint8_t *r = out + (c64 - 1) * 8; + for (m = c64; m >= 1; m--) { + memcpy(b, a, 8); + b[7] ^= c64 * n + m; + memcpy(b + 8, r, 8); + if (mbedtls_internal_aes_decrypt(&ctx, b, b)) + goto bail; + + memcpy(a, b, 8); + memcpy(r, b + 8, 8); + r -= 8; + } + } + + ret = 0; + for (n = 0; n < 8; n++) + if (a[n] != 0xa6) + ret = -1; + } + +bail: + if (ret) + lwsl_notice("%s: failed\n", __func__); + mbedtls_aes_free(&ctx); + + return ret; +} + LWS_VISIBLE int lws_genaes_crypt(struct lws_genaes_ctx *ctx, const uint8_t *in, size_t len, uint8_t *out, uint8_t *iv_or_nonce_ctr_or_data_unit_16, uint8_t *stream_block_16, size_t *nc_or_iv_off, int taglen) { - uint8_t iv[16], sb[16]; - int n; + uint8_t iv[LWS_JWE_AES_IV_BYTES], sb[16]; + int n = 0; switch (ctx->mode) { + case LWS_GAESM_KW: + /* a key of length ctx->k->len is wrapped by a 128-bit KEK */ + n = lws_genaes_rfc3394_wrap(ctx->op == MBEDTLS_AES_ENCRYPT, + ctx->op == MBEDTLS_AES_ENCRYPT ? len * 8 : + (len - 8) * 8, ctx->k->buf, + ctx->k->len * 8, + in, out); + break; case LWS_GAESM_CBC: memcpy(iv, iv_or_nonce_ctr_or_data_unit_16, 16); n = mbedtls_aes_crypt_cbc(&ctx->u.ctx, ctx->op, len, iv, @@ -181,10 +303,14 @@ lws_genaes_crypt(struct lws_genaes_ctx *ctx, const uint8_t *in, size_t len, break; case LWS_GAESM_OFB: +#if defined(MBEDTLS_CIPHER_MODE_OFB) memcpy(iv, iv_or_nonce_ctr_or_data_unit_16, 16); n = mbedtls_aes_crypt_ofb(&ctx->u.ctx, len, nc_or_iv_off, iv, in, out); break; +#else + return -1; +#endif case LWS_GAESM_XTS: #if defined(MBEDTLS_CIPHER_MODE_XTS) @@ -233,7 +359,7 @@ lws_genaes_crypt(struct lws_genaes_ctx *ctx, const uint8_t *in, size_t len, } if (n) { - lwsl_notice("%s: enc: -0x%x, len %d\n", __func__, -n, (int)len); + lwsl_notice("%s: failed: -0x%x, len %d\n", __func__, -n, (int)len); return -1; } diff --git a/lib/tls/mbedtls/lws-gencrypto.c b/lib/tls/mbedtls/lws-gencrypto.c index 8d2619340..abbfd563e 100644 --- a/lib/tls/mbedtls/lws-gencrypto.c +++ b/lib/tls/mbedtls/lws-gencrypto.c @@ -52,8 +52,10 @@ lws_gencrypto_mbedtls_hash_to_MD_TYPE(enum lws_genhash_types hash_type) int lws_gencrypto_mbedtls_rngf(void *context, unsigned char *buf, size_t len) { - if ((size_t)lws_get_random(context, buf, len) == len) + if ((size_t)lws_get_random(context, buf, len) == len) { + // lwsl_hexdump_err(buf, len); return 0; - + } + lwsl_err("%s: rng failed\n", __func__); return -1; } diff --git a/lib/tls/mbedtls/lws-genec.c b/lib/tls/mbedtls/lws-genec.c index 0b97ea852..8d0807855 100644 --- a/lib/tls/mbedtls/lws-genec.c +++ b/lib/tls/mbedtls/lws-genec.c @@ -86,6 +86,8 @@ lws_genec_keypair_import(struct lws_genec_ctx *ctx, enum enum_lws_dh_side side, el[LWS_GENCRYPTO_EC_KEYEL_Y].len)) goto bail1; + mbedtls_mpi_lset(&kp.Q.Z, 1); + switch (ctx->genec_alg) { case LEGENEC_ECDH: if (mbedtls_ecdh_get_params(ctx->u.ctx_ecdh, &kp, side)) @@ -112,6 +114,7 @@ lws_genecdh_create(struct lws_genec_ctx *ctx, struct lws_context *context, const struct lws_ec_curves *curve_table) { memset(ctx, 0, sizeof(*ctx)); + ctx->context = context; ctx->curve_table = curve_table; ctx->genec_alg = LEGENEC_ECDH; @@ -130,15 +133,16 @@ lws_genecdsa_create(struct lws_genec_ctx *ctx, struct lws_context *context, const struct lws_ec_curves *curve_table) { memset(ctx, 0, sizeof(*ctx)); + ctx->context = context; ctx->curve_table = curve_table; ctx->genec_alg = LEGENEC_ECDSA; - ctx->u.ctx_ecdh = lws_zalloc(sizeof(*ctx->u.ctx_ecdh), "genecdh"); - if (!ctx->u.ctx_ecdh) + ctx->u.ctx_ecdsa = lws_zalloc(sizeof(*ctx->u.ctx_ecdsa), "genecdsa"); + if (!ctx->u.ctx_ecdsa) return 1; - mbedtls_ecdh_init(ctx->u.ctx_ecdh); + mbedtls_ecdsa_init(ctx->u.ctx_ecdsa); return 0; } @@ -210,7 +214,8 @@ lws_genecdh_new_keypair(struct lws_genec_ctx *ctx, enum enum_lws_dh_side side, } mbedtls_ecdsa_init(&ecdsa); - n = mbedtls_ecdsa_genkey(&ecdsa, curve->tls_lib_nid, lws_gencrypto_mbedtls_rngf, + n = mbedtls_ecdsa_genkey(&ecdsa, curve->tls_lib_nid, + lws_gencrypto_mbedtls_rngf, ctx->context); if (n) { lwsl_err("mbedtls_ecdsa_genkey failed 0x%x\n", -n); @@ -241,7 +246,8 @@ lws_genecdh_new_keypair(struct lws_genec_ctx *ctx, enum enum_lws_dh_side side, goto bail1; strcpy((char *)el[LWS_GENCRYPTO_EC_KEYEL_CRV].buf, curve_name); - for (n = LWS_GENCRYPTO_EC_KEYEL_X; n < LWS_GENCRYPTO_EC_KEYEL_COUNT; n++) { + for (n = LWS_GENCRYPTO_EC_KEYEL_X; n < LWS_GENCRYPTO_EC_KEYEL_COUNT; + n++) { el[n].len = curve->key_bytes; el[n].buf = lws_malloc(curve->key_bytes, "ec"); if (!el[n].buf) @@ -288,7 +294,7 @@ lws_genecdsa_new_keypair(struct lws_genec_ctx *ctx, const char *curve_name, return -22; } - mbedtls_ecdsa_init(ctx->u.ctx_ecdsa); + //mbedtls_ecdsa_init(ctx->u.ctx_ecdsa); n = mbedtls_ecdsa_genkey(ctx->u.ctx_ecdsa, curve->tls_lib_nid, lws_gencrypto_mbedtls_rngf, ctx->context); if (n) { @@ -301,7 +307,7 @@ lws_genecdsa_new_keypair(struct lws_genec_ctx *ctx, const char *curve_name, * lws_gencrypto_keyelems, so they can be serialized, used in jwk etc */ - kp = (mbedtls_ecp_keypair *)&ctx->u.ctx_ecdsa; + kp = (mbedtls_ecp_keypair *)ctx->u.ctx_ecdsa; mpi[0] = &kp->Q.X; mpi[1] = &kp->d; @@ -314,15 +320,18 @@ lws_genecdsa_new_keypair(struct lws_genec_ctx *ctx, const char *curve_name, goto bail1; strcpy((char *)el[LWS_GENCRYPTO_EC_KEYEL_CRV].buf, curve_name); - for (n = LWS_GENCRYPTO_EC_KEYEL_X; n < LWS_GENCRYPTO_EC_KEYEL_COUNT; n++) { + for (n = LWS_GENCRYPTO_EC_KEYEL_X; n < LWS_GENCRYPTO_EC_KEYEL_COUNT; + n++) { el[n].len = curve->key_bytes; el[n].buf = lws_malloc(curve->key_bytes, "ec"); if (!el[n].buf) goto bail2; - if (mbedtls_mpi_write_binary(mpi[n - 1], el[n].buf, - curve->key_bytes)) + + if (mbedtls_mpi_write_binary(mpi[n - 1], el[n].buf, el[n].len)) { + lwsl_err("%s: mbedtls_mpi_write_binary failed\n", __func__); goto bail2; + } } return 0; @@ -339,65 +348,121 @@ bail1: } LWS_VISIBLE LWS_EXTERN int -lws_genecdsa_hash_sign(struct lws_genec_ctx *ctx, const uint8_t *in, - enum lws_genhash_types hash_type, +lws_genecdsa_hash_sign_jws(struct lws_genec_ctx *ctx, const uint8_t *in, + enum lws_genhash_types hash_type, int keybits, uint8_t *sig, size_t sig_len) { - mbedtls_md_type_t md_type = - lws_gencrypto_mbedtls_hash_to_MD_TYPE(hash_type); + int n, keybytes = lws_gencrypto_bits_to_bytes(keybits); + size_t hlen = lws_genhash_size(hash_type); + mbedtls_mpi mpi_r, mpi_s; size_t slen = sig_len; - int n; if (ctx->genec_alg != LEGENEC_ECDSA) return -1; - if (md_type < 0) - return -2; + /* + * The ECDSA P-256 SHA-256 digital signature is generated as follows: + * + * 1. Generate a digital signature of the JWS Signing Input using ECDSA + * P-256 SHA-256 with the desired private key. The output will be + * the pair (R, S), where R and S are 256-bit unsigned integers. + * + * 2. Turn R and S into octet sequences in big-endian order, with each + * array being be 32 octets long. The octet sequence + * representations MUST NOT be shortened to omit any leading zero + * octets contained in the values. + * + * 3. Concatenate the two octet sequences in the order R and then S. + * (Note that many ECDSA implementations will directly produce this + * concatenation as their output.) + * + * 4. The resulting 64-octet sequence is the JWS Signature value. + */ + mbedtls_mpi_init(&mpi_r); + mbedtls_mpi_init(&mpi_s); - n = mbedtls_ecdsa_write_signature(ctx->u.ctx_ecdsa, md_type, in, - lws_genhash_size(hash_type), sig, - &slen, lws_gencrypto_mbedtls_rngf, - ctx->context); + n = mbedtls_ecdsa_sign(&ctx->u.ctx_ecdsa->grp, &mpi_r, &mpi_s, + &ctx->u.ctx_ecdsa->d, in, hlen, + lws_gencrypto_mbedtls_rngf, ctx->context); if (n) { - lwsl_err("%s: mbedtls_ecdsa_write_signature failed: -0x%x\n", + lwsl_err("%s: mbedtls_ecdsa_sign failed: -0x%x\n", __func__, -n); - goto bail; + goto bail2; } + if (mbedtls_mpi_write_binary(&mpi_r, sig, keybytes)) + goto bail2; + mbedtls_mpi_free(&mpi_r); + if (mbedtls_mpi_write_binary(&mpi_s, sig + keybytes, keybytes)) + goto bail1; + mbedtls_mpi_free(&mpi_s); + return (int)slen; -bail: + +bail2: + mbedtls_mpi_free(&mpi_r); +bail1: + mbedtls_mpi_free(&mpi_s); return -3; } LWS_VISIBLE LWS_EXTERN int -lws_genecdsa_hash_sig_verify(struct lws_genec_ctx *ctx, const uint8_t *in, - enum lws_genhash_types hash_type, - const uint8_t *sig, size_t sig_len) +lws_genecdsa_hash_sig_verify_jws(struct lws_genec_ctx *ctx, const uint8_t *in, + enum lws_genhash_types hash_type, int keybits, + const uint8_t *sig, size_t sig_len) { - mbedtls_md_type_t md_type = - lws_gencrypto_mbedtls_hash_to_MD_TYPE(hash_type); - int n; + int n, keybytes = lws_gencrypto_bits_to_bytes(keybits); + size_t hlen = lws_genhash_size(hash_type); + mbedtls_mpi mpi_r, mpi_s; if (ctx->genec_alg != LEGENEC_ECDSA) return -1; - if (md_type < 0) - return -2; + if ((int)sig_len != keybytes * 2) + return -1; + + /* + * 1. The JWS Signature value MUST be a 64-octet sequence. If it is + * not a 64-octet sequence, the validation has failed. + * + * 2. Split the 64-octet sequence into two 32-octet sequences. The + * first octet sequence represents R and the second S. The values R + * and S are represented as octet sequences using the Integer-to- + * OctetString Conversion defined in Section 2.3.7 of SEC1 [SEC1] + * (in big-endian octet order). + * + * 3. Submit the JWS Signing Input, R, S, and the public key (x, y) to + * the ECDSA P-256 SHA-256 validator. + */ + + mbedtls_mpi_init(&mpi_r); + mbedtls_mpi_init(&mpi_s); + + if (mbedtls_mpi_read_binary(&mpi_r, sig, keybytes)) + return -1; + if (mbedtls_mpi_read_binary(&mpi_s, sig + keybytes, keybytes)) + goto bail1; + + n = mbedtls_ecdsa_verify(&ctx->u.ctx_ecdsa->grp, in, hlen, + &ctx->u.ctx_ecdsa->Q, &mpi_r, &mpi_s); + + mbedtls_mpi_free(&mpi_s); + mbedtls_mpi_free(&mpi_r); - n = mbedtls_ecdsa_read_signature(ctx->u.ctx_ecdsa, in, - lws_genhash_size(hash_type), sig, - sig_len); if (n) { - lwsl_err("%s: mbedtls_ecdsa_write_signature failed: -0x%x\n", + lwsl_err("%s: mbedtls_ecdsa_verify failed: -0x%x\n", __func__, -n); goto bail; } return 0; +bail1: + mbedtls_mpi_free(&mpi_r); + bail: return -3; diff --git a/lib/tls/mbedtls/lws-genhash.c b/lib/tls/mbedtls/lws-genhash.c index 01c453212..a5770d62e 100644 --- a/lib/tls/mbedtls/lws-genhash.c +++ b/lib/tls/mbedtls/lws-genhash.c @@ -62,6 +62,9 @@ lws_genhash_init(struct lws_genhash_ctx *ctx, enum lws_genhash_types type) int lws_genhash_update(struct lws_genhash_ctx *ctx, const void *in, size_t len) { + if (!len) + return 0; + switch (ctx->type) { case LWS_GENHASH_TYPE_SHA1: MBA(mbedtls_sha1_update)(&ctx->u.sha1, in, len); @@ -147,6 +150,9 @@ lws_genhmac_init(struct lws_genhmac_ctx *ctx, enum lws_genhmac_types type, int lws_genhmac_update(struct lws_genhmac_ctx *ctx, const void *in, size_t len) { + if (!len) + return 0; + if (mbedtls_md_hmac_update(&ctx->ctx, in, len)) return -1; diff --git a/lib/tls/mbedtls/lws-genrsa.c b/lib/tls/mbedtls/lws-genrsa.c index 4004777f0..5eb6c5b75 100644 --- a/lib/tls/mbedtls/lws-genrsa.c +++ b/lib/tls/mbedtls/lws-genrsa.c @@ -23,6 +23,7 @@ */ #include "core/private.h" #include "tls/mbedtls/private.h" +#include LWS_VISIBLE void lws_genrsa_destroy_elements(struct lws_gencrypto_keyelem *el) @@ -38,7 +39,8 @@ static int mode_map[] = { MBEDTLS_RSA_PKCS_V15, MBEDTLS_RSA_PKCS_V21 }; LWS_VISIBLE int lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_gencrypto_keyelem *el, - struct lws_context *context, enum enum_genrsa_mode mode) + struct lws_context *context, enum enum_genrsa_mode mode, + enum lws_genhash_types oaep_hashid) { memset(ctx, 0, sizeof(*ctx)); ctx->ctx = lws_zalloc(sizeof(*ctx->ctx), "genrsa"); @@ -53,6 +55,9 @@ lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_gencrypto_keyelem *el, mbedtls_rsa_init(ctx->ctx, mode_map[mode], 0); + ctx->ctx->padding = mode_map[mode]; + ctx->ctx->hash_id = lws_gencrypto_mbedtls_hash_to_MD_TYPE(oaep_hashid); + { int n; @@ -71,6 +76,20 @@ lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_gencrypto_keyelem *el, return -1; } + + /* mbedtls... compute missing P & Q */ + + if ( el[LWS_GENCRYPTO_RSA_KEYEL_D].len && + !el[LWS_GENCRYPTO_RSA_KEYEL_P].len && + !el[LWS_GENCRYPTO_RSA_KEYEL_Q].len) { + if (mbedtls_rsa_complete(ctx->ctx)) { + lwsl_notice("mbedtls_rsa_complete failed\n"); + lws_free_set_NULL(ctx->ctx); + + return -1; + } + + } } ctx->ctx->len = el[LWS_GENCRYPTO_RSA_KEYEL_N].len; @@ -153,15 +172,19 @@ lws_genrsa_public_decrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in, ctx->ctx->len = in_len; + mbedtls_rsa_complete(ctx->ctx); + switch(ctx->mode) { case LGRSAM_PKCS1_1_5: - n = mbedtls_rsa_rsaes_pkcs1_v15_decrypt(ctx->ctx, NULL, NULL, + n = mbedtls_rsa_rsaes_pkcs1_v15_decrypt(ctx->ctx, _rngf, + ctx->context, MBEDTLS_RSA_PUBLIC, &olen, in, out, out_max); break; case LGRSAM_PKCS1_OAEP_PSS: - n = mbedtls_rsa_rsaes_oaep_decrypt(ctx->ctx, NULL, NULL, + n = mbedtls_rsa_rsaes_oaep_decrypt(ctx->ctx, _rngf, + ctx->context, MBEDTLS_RSA_PUBLIC, NULL, 0, &olen, in, out, out_max); @@ -178,13 +201,86 @@ lws_genrsa_public_decrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in, return olen; } +LWS_VISIBLE int +lws_genrsa_private_decrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in, + size_t in_len, uint8_t *out, size_t out_max) +{ + size_t olen = 0; + int n; + + ctx->ctx->len = in_len; + + mbedtls_rsa_complete(ctx->ctx); + + switch(ctx->mode) { + case LGRSAM_PKCS1_1_5: + n = mbedtls_rsa_rsaes_pkcs1_v15_decrypt(ctx->ctx, _rngf, + ctx->context, + MBEDTLS_RSA_PRIVATE, + &olen, in, out, + out_max); + break; + case LGRSAM_PKCS1_OAEP_PSS: + n = mbedtls_rsa_rsaes_oaep_decrypt(ctx->ctx, _rngf, + ctx->context, + MBEDTLS_RSA_PRIVATE, + NULL, 0, + &olen, in, out, out_max); + break; + default: + return -1; + } + if (n) { + lwsl_notice("%s: -0x%x\n", __func__, -n); + + return -1; + } + + return olen; +} + LWS_VISIBLE int lws_genrsa_public_encrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in, size_t in_len, uint8_t *out) { int n; - ctx->ctx->padding = mode_map[ctx->mode]; + mbedtls_rsa_complete(ctx->ctx); + + switch(ctx->mode) { + case LGRSAM_PKCS1_1_5: + n = mbedtls_rsa_rsaes_pkcs1_v15_encrypt(ctx->ctx, _rngf, + ctx->context, + MBEDTLS_RSA_PUBLIC, + in_len, in, out); + break; + case LGRSAM_PKCS1_OAEP_PSS: + n = mbedtls_rsa_rsaes_oaep_encrypt(ctx->ctx, _rngf, + ctx->context, + MBEDTLS_RSA_PUBLIC, + NULL, 0, + in_len, in, out); + break; + default: + return -1; + } + if (n < 0) { + lwsl_notice("%s: -0x%x: in_len: %d\n", __func__, -n, + (int)in_len); + + return -1; + } + + return mbedtls_mpi_size(&ctx->ctx->N); +} + +LWS_VISIBLE int +lws_genrsa_private_encrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in, + size_t in_len, uint8_t *out) +{ + int n; + + mbedtls_rsa_complete(ctx->ctx); switch(ctx->mode) { case LGRSAM_PKCS1_1_5: @@ -210,7 +306,7 @@ lws_genrsa_public_encrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in, return -1; } - return 0; + return mbedtls_mpi_size(&ctx->ctx->N); } LWS_VISIBLE int @@ -223,6 +319,8 @@ lws_genrsa_hash_sig_verify(struct lws_genrsa_ctx *ctx, const uint8_t *in, if (h < 0) return -1; + mbedtls_rsa_complete(ctx->ctx); + switch(ctx->mode) { case LGRSAM_PKCS1_1_5: n = mbedtls_rsa_rsassa_pkcs1_v15_verify(ctx->ctx, NULL, NULL, @@ -256,6 +354,8 @@ lws_genrsa_hash_sign(struct lws_genrsa_ctx *ctx, const uint8_t *in, if (h < 0) return -1; + mbedtls_rsa_complete(ctx->ctx); + /* * The "sig" buffer must be as large as the size of ctx->N * (eg. 128 bytes if RSA-1024 is used). diff --git a/lib/tls/mbedtls/mbedtls-server.c b/lib/tls/mbedtls/mbedtls-server.c index fa0eef99c..d75500d77 100644 --- a/lib/tls/mbedtls/mbedtls-server.c +++ b/lib/tls/mbedtls/mbedtls-server.c @@ -588,7 +588,7 @@ lws_tls_acme_sni_cert_destroy(struct lws_vhost *vhost) { } -#if defined(LWS_WITH_JWS) +#if defined(LWS_WITH_JOSE) static int _rngf(void *context, unsigned char *buf, size_t len) { diff --git a/lib/tls/openssl/lws-genaes.c b/lib/tls/openssl/lws-genaes.c index 76cf5254e..43fc4ae5e 100644 --- a/lib/tls/openssl/lws-genaes.c +++ b/lib/tls/openssl/lws-genaes.c @@ -32,9 +32,9 @@ LWS_VISIBLE int lws_genaes_create(struct lws_genaes_ctx *ctx, enum enum_aes_operation op, enum enum_aes_modes mode, struct lws_gencrypto_keyelem *el, - int padding, void *engine) + enum enum_aes_padding padding, void *engine) { - int n; + int n = 0; ctx->ctx = EVP_CIPHER_CTX_new(); if (!ctx->ctx) @@ -49,6 +49,17 @@ lws_genaes_create(struct lws_genaes_ctx *ctx, enum enum_aes_operation op, switch (ctx->k->len) { case 128 / 8: switch (mode) { + case LWS_GAESM_KW: +#if defined(LWS_HAVE_EVP_aes_128_wrap) + EVP_CIPHER_CTX_set_flags(ctx->ctx, + EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); + ctx->cipher = EVP_aes_128_wrap(); + break; +#else + lwsl_err("%s: your OpenSSL lacks AES wrap apis, update it\n", + __func__); + return -1; +#endif case LWS_GAESM_CBC: ctx->cipher = EVP_aes_128_cbc(); break; @@ -75,12 +86,23 @@ lws_genaes_create(struct lws_genaes_ctx *ctx, enum enum_aes_operation op, ctx->cipher = EVP_aes_128_gcm(); break; default: - return -1; + goto bail; } break; case 192 / 8: switch (mode) { + case LWS_GAESM_KW: +#if defined(LWS_HAVE_EVP_aes_128_wrap) + EVP_CIPHER_CTX_set_flags(ctx->ctx, + EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); + ctx->cipher = EVP_aes_192_wrap(); + break; +#else + lwsl_err("%s: your OpenSSL lacks AES wrap apis, update it\n", + __func__); + return -1; +#endif case LWS_GAESM_CBC: ctx->cipher = EVP_aes_192_cbc(); break; @@ -101,17 +123,28 @@ lws_genaes_create(struct lws_genaes_ctx *ctx, enum enum_aes_operation op, break; case LWS_GAESM_XTS: lwsl_err("%s: AES XTS 192 invalid\n", __func__); - return -1; + goto bail; case LWS_GAESM_GCM: ctx->cipher = EVP_aes_192_gcm(); break; default: - return -1; + goto bail; } break; case 256 / 8: switch (mode) { + case LWS_GAESM_KW: +#if defined(LWS_HAVE_EVP_aes_128_wrap) + EVP_CIPHER_CTX_set_flags(ctx->ctx, + EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); + ctx->cipher = EVP_aes_256_wrap(); + break; +#else + lwsl_err("%s: your OpenSSL lacks AES wrap apis, update it\n", + __func__); + return -1; +#endif case LWS_GAESM_CBC: ctx->cipher = EVP_aes_256_cbc(); break; @@ -137,7 +170,7 @@ lws_genaes_create(struct lws_genaes_ctx *ctx, enum enum_aes_operation op, ctx->cipher = EVP_aes_256_gcm(); break; default: - return -1; + goto bail; } break; @@ -147,14 +180,14 @@ lws_genaes_create(struct lws_genaes_ctx *ctx, enum enum_aes_operation op, ctx->cipher = EVP_aes_256_xts(); break; default: - return -1; + goto bail; } break; default: lwsl_err("%s: unsupported AES size %d bits\n", __func__, ctx->k->len * 8); - return -1; + goto bail; } switch (ctx->op) { @@ -172,11 +205,15 @@ lws_genaes_create(struct lws_genaes_ctx *ctx, enum enum_aes_operation op, if (!n) { lwsl_err("%s: cipher init failed (cipher %p)\n", __func__, ctx->cipher); - - return -1; + lws_tls_err_describe(); + goto bail; } return 0; +bail: + EVP_CIPHER_CTX_free(ctx->ctx); + ctx->ctx = NULL; + return -1; } LWS_VISIBLE int @@ -196,31 +233,24 @@ lws_genaes_destroy(struct lws_genaes_ctx *ctx, unsigned char *tag, size_t tlen) lwsl_err("%s: enc final failed\n", __func__); n = -1; } + if (ctx->mode == LWS_GAESM_GCM) { - memset(tag, 0, tlen); if (EVP_CIPHER_CTX_ctrl(ctx->ctx, EVP_CTRL_GCM_GET_TAG, ctx->taglen, tag) != 1) { lwsl_err("get tag ctrl failed\n"); //lws_tls_err_describe(); n = 1; - } else - if (memcmp(tag, ctx->tag, ctx->taglen)) { - lwsl_err("%s: tag mismatch " - "(bad first)\n", __func__); - //lws_tls_err_describe(); - lwsl_hexdump_notice(tag, tlen); - lwsl_hexdump_notice(ctx->tag, ctx->taglen); - n = -1; } } break; case LWS_GAESO_DEC: if (EVP_DecryptFinal_ex(ctx->ctx, buf, &outl) != 1) { lwsl_err("%s: dec final failed\n", __func__); - //lws_tls_err_describe(); + lws_tls_err_describe(); n = -1; } + break; } if (outl) @@ -240,7 +270,7 @@ lws_genaes_crypt(struct lws_genaes_ctx *ctx, uint8_t *iv_or_nonce_ctr_or_data_unit_16, uint8_t *stream_block_16, size_t *nc_or_iv_off, int taglen) { - int n, outl, olen; + int n = 0, outl, olen; if (!ctx->init) { @@ -277,19 +307,20 @@ lws_genaes_crypt(struct lws_genaes_ctx *ctx, return -1; } ctx->init = 1; - if (ctx->mode == LWS_GAESM_GCM) { - /* AAD */ - if (len) - if (EVP_EncryptUpdate(ctx->ctx, NULL, &olen, - in, len) != 1) { - lwsl_err("%s: set aad failed\n", - __func__); + } - return -1; - } + if (ctx->mode == LWS_GAESM_GCM && !out) { + /* AAD */ + if (len) + if (EVP_EncryptUpdate(ctx->ctx, NULL, &olen, + in, len) != 1) { + lwsl_err("%s: set aad failed\n", + __func__); - return 0; - } + return -1; + } + + return 0; } switch (ctx->op) { @@ -299,12 +330,15 @@ lws_genaes_crypt(struct lws_genaes_ctx *ctx, case LWS_GAESO_DEC: n = EVP_DecryptUpdate(ctx->ctx, out, &outl, in, len); break; + default: + return -1; } // lwsl_notice("discarding outl %d\n", (int)outl); if (!n) { lwsl_notice("%s: update failed\n", __func__); + lws_tls_err_describe(); return -1; } diff --git a/lib/tls/openssl/lws-gencrypto.c b/lib/tls/openssl/lws-gencrypto.c index 00c63c810..995e26183 100644 --- a/lib/tls/openssl/lws-gencrypto.c +++ b/lib/tls/openssl/lws-gencrypto.c @@ -24,6 +24,11 @@ #include "core/private.h" #include "tls/openssl/private.h" +/* + * Care: many openssl apis return 1 for success. These are translated to the + * lws convention of 0 for success. + */ + int lws_gencrypto_openssl_hash_to_NID(enum lws_genhash_types hash_type) { diff --git a/lib/tls/openssl/lws-genec.c b/lib/tls/openssl/lws-genec.c index b8205017a..03b36c193 100644 --- a/lib/tls/openssl/lws-genec.c +++ b/lib/tls/openssl/lws-genec.c @@ -24,6 +24,56 @@ #include "core/private.h" #include "tls/openssl/private.h" +/* + * Care: many openssl apis return 1 for success. These are translated to the + * lws convention of 0 for success. + */ + +#if !defined(LWS_HAVE_ECDSA_SIG_set0) +static void +ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps) +{ + if (pr != NULL) + *pr = sig->r; + if (ps != NULL) + *ps = sig->s; +} + +static int +ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s) +{ + if (r == NULL || s == NULL) + return 0; + BN_clear_free(sig->r); + BN_clear_free(sig->s); + sig->r = r; + sig->s = s; + + return 1; +} +#endif +#if !defined(LWS_HAVE_BN_bn2binpad) +static int BN_bn2binpad(const BIGNUM *a, unsigned char *to, int tolen) +{ + int i; + BN_ULONG l; + + bn_check_top(a); + i = BN_num_bytes(a); + + /* Add leading zeroes if necessary */ + if (tolen > i) { + memset(to, 0, tolen - i); + to += tolen - i; + } + while (i--) { + l = a->d[i / BN_BYTES]; + *(to++) = (unsigned char)(l >> (8 * (i % BN_BYTES))) & 0xff; + } + return tolen; +} +#endif + const struct lws_ec_curves lws_ec_curves[] = { /* * These are the curves we are willing to use by default... @@ -88,15 +138,16 @@ lws_genec_eckey_import(int nid, EVP_PKEY *pkey, struct lws_gencrypto_keyelem *el } n = EC_KEY_set_private_key(ec, bn_d); - BN_free(bn_d); + BN_clear_free(bn_d); if (n != 1) { lwsl_err("%s: EC_KEY_set_private_key fail\n", __func__); goto bail; } - if (EVP_PKEY_assign_EC_KEY(pkey, ec) != 1) { + n = EVP_PKEY_assign_EC_KEY(pkey, ec); + if (n != 1) { lwsl_err("%s: EVP_PKEY_set1_EC_KEY failed\n", __func__); - goto bail; + return -1; } return 0; @@ -141,6 +192,7 @@ lws_genec_keypair_import(const struct lws_ec_curves *curve_table, *pctx = EVP_PKEY_CTX_new(pkey, NULL); EVP_PKEY_free(pkey); pkey = NULL; + if (!*pctx) goto bail; @@ -210,6 +262,11 @@ lws_genec_keypair_destroy(EVP_PKEY_CTX **pctx) { if (!*pctx) return; + +// lwsl_err("%p\n", EVP_PKEY_get1_EC_KEY(EVP_PKEY_CTX_get0_pkey(*pctx))); + +// EC_KEY_free(EVP_PKEY_get1_EC_KEY(EVP_PKEY_CTX_get0_pkey(*pctx))); + EVP_PKEY_CTX_free(*pctx); *pctx = NULL; } @@ -234,9 +291,6 @@ lws_genec_new_keypair(struct lws_genec_ctx *ctx, enum enum_lws_dh_side side, BIGNUM *bn[3]; EC_KEY *ec; - if (ctx->genec_alg != LEGENEC_ECDH) - return -1; - curve = lws_genec_curve(ctx->curve_table, curve_name); if (!curve) { lwsl_err("%s: curve '%s' not supported\n", @@ -246,11 +300,15 @@ lws_genec_new_keypair(struct lws_genec_ctx *ctx, enum enum_lws_dh_side side, } ec = EC_KEY_new_by_curve_name(curve->tls_lib_nid); - if (!ec) + if (!ec) { + lwsl_err("%s: unknown nid %d\n", __func__, curve->tls_lib_nid); return -23; + } - if (EC_KEY_generate_key(ec) != 1) + if (EC_KEY_generate_key(ec) != 1) { + lwsl_err("%s: EC_KEY_generate_key failed\n", __func__); goto bail; + } pkey = EVP_PKEY_new(); if (!pkey) @@ -273,8 +331,10 @@ lws_genec_new_keypair(struct lws_genec_ctx *ctx, enum enum_lws_dh_side side, */ pubkey = EC_KEY_get0_public_key(ec); - if (!pubkey) + if (!pubkey) { + lwsl_err("%s: EC_KEY_get0_public_key failed\n", __func__); goto bail1; + } bn[0] = BN_new(); bn[1] = (BIGNUM *)EC_KEY_get0_private_key(ec); @@ -290,8 +350,10 @@ lws_genec_new_keypair(struct lws_genec_ctx *ctx, enum enum_lws_dh_side side, el[LWS_GENCRYPTO_EC_KEYEL_CRV].len = strlen(curve_name) + 1; el[LWS_GENCRYPTO_EC_KEYEL_CRV].buf = lws_malloc(el[LWS_GENCRYPTO_EC_KEYEL_CRV].len, "ec"); - if (!el[LWS_GENCRYPTO_EC_KEYEL_CRV].buf) + if (!el[LWS_GENCRYPTO_EC_KEYEL_CRV].buf) { + lwsl_err("%s: OOM\n", __func__); goto bail2; + } strcpy((char *)el[LWS_GENCRYPTO_EC_KEYEL_CRV].buf, curve_name); @@ -302,7 +364,7 @@ lws_genec_new_keypair(struct lws_genec_ctx *ctx, enum enum_lws_dh_side side, if (!el[n].buf) goto bail2; - m = BN_bn2bin(bn[n - 1], el[n].buf); + m = BN_bn2binpad(bn[n - 1], el[n].buf, el[n].len); if (m != el[n].len) goto bail2; } @@ -310,8 +372,8 @@ lws_genec_new_keypair(struct lws_genec_ctx *ctx, enum enum_lws_dh_side side, ret = 0; bail2: - BN_free(bn[0]); - BN_free(bn[2]); + BN_clear_free(bn[0]); + BN_clear_free(bn[2]); bail1: EVP_PKEY_free(pkey); bail: @@ -341,6 +403,7 @@ lws_genecdsa_new_keypair(struct lws_genec_ctx *ctx, const char *curve_name, return lws_genec_new_keypair(ctx, LDHS_OURS, curve_name, el); } +#if 0 LWS_VISIBLE LWS_EXTERN int lws_genecdsa_hash_sign(struct lws_genec_ctx *ctx, const uint8_t *in, enum lws_genhash_types hash_type, @@ -385,47 +448,161 @@ bail: return -1; } +#endif LWS_VISIBLE LWS_EXTERN int -lws_genecdsa_hash_sig_verify(struct lws_genec_ctx *ctx, const uint8_t *in, - enum lws_genhash_types hash_type, - const uint8_t *sig, size_t sig_len) +lws_genecdsa_hash_sign_jws(struct lws_genec_ctx *ctx, const uint8_t *in, + enum lws_genhash_types hash_type, int keybits, + uint8_t *sig, size_t sig_len) { - const EVP_MD *md = lws_gencrypto_openssl_hash_to_EVP_MD(hash_type); - EVP_MD_CTX *mdctx = NULL; - int ret = -1; + int ret = -1, n, keybytes = lws_gencrypto_bits_to_bytes(keybits); + const BIGNUM *r = NULL, *s = NULL; + ECDSA_SIG *ecdsasig; + EC_KEY *eckey; - if (ctx->genec_alg != LEGENEC_ECDSA) + if (ctx->genec_alg != LEGENEC_ECDSA) { + lwsl_notice("%s: ctx alg %d\n", __func__, ctx->genec_alg); return -1; + } - if (!md) + if ((int)sig_len < keybytes * 2) { + lwsl_notice("%s: sig buff %d < %d\n", __func__, + (int)sig_len, keybytes * 2); return -1; + } - mdctx = EVP_MD_CTX_create(); - if (!mdctx) - goto bail; + eckey = EVP_PKEY_get1_EC_KEY(EVP_PKEY_CTX_get0_pkey(ctx->ctx)); - if (EVP_DigestVerifyInit(mdctx, NULL, md, NULL, - EVP_PKEY_CTX_get0_pkey(ctx->ctx))) { - lwsl_err("%s: EVP_DigestSignInit failed\n", __func__); + /* + * The ECDSA P-256 SHA-256 digital signature is generated as follows: + * + * 1. Generate a digital signature of the JWS Signing Input using ECDSA + * P-256 SHA-256 with the desired private key. The output will be + * the pair (R, S), where R and S are 256-bit unsigned integers. + * + * 2. Turn R and S into octet sequences in big-endian order, with each + * array being be 32 octets long. The octet sequence + * representations MUST NOT be shortened to omit any leading zero + * octets contained in the values. + * + * 3. Concatenate the two octet sequences in the order R and then S. + * (Note that many ECDSA implementations will directly produce this + * concatenation as their output.) + * + * 4. The resulting 64-octet sequence is the JWS Signature value. + */ + ecdsasig = ECDSA_do_sign(in, lws_genhash_size(hash_type), eckey); + EC_KEY_free(eckey); + if (!ecdsasig) { + lwsl_notice("%s: ECDSA_do_sign fail\n", __func__); goto bail; } - if (EVP_DigestVerifyUpdate(mdctx, in, EVP_MD_size(md))) { - lwsl_err("%s: EVP_DigestSignUpdate failed\n", __func__); + ECDSA_SIG_get0(ecdsasig, &r, &s); + + /* + * in the 521-bit case, we have to pad the last byte as it only + * generates 65 bytes + */ + + n = BN_bn2binpad(r, sig, keybytes); + if (n != keybytes) { + lwsl_notice("%s: bignum r fail %d %d\n", __func__, n, keybytes); goto bail; } - if (EVP_DigestVerifyFinal(mdctx, sig, sig_len)) { - lwsl_err("%s: EVP_DigestSignFinal failed\n", __func__); + n = BN_bn2binpad(s, sig + keybytes, keybytes); + if (n != keybytes) { + lwsl_notice("%s: bignum s fail %d %d\n", __func__, n, keybytes); goto bail; } ret = 0; + bail: - if (mdctx) - EVP_MD_CTX_free(mdctx); + if (ecdsasig) + ECDSA_SIG_free(ecdsasig); + + return ret; +} + +/* in is the JWS Signing Input hash */ + +LWS_VISIBLE LWS_EXTERN int +lws_genecdsa_hash_sig_verify_jws(struct lws_genec_ctx *ctx, const uint8_t *in, + enum lws_genhash_types hash_type, int keybits, + const uint8_t *sig, size_t sig_len) +{ + int ret = -1, n, keybytes = lws_gencrypto_bits_to_bytes(keybits), + hlen = lws_genhash_size(hash_type); + ECDSA_SIG *ecsig = ECDSA_SIG_new(); + BIGNUM *r = NULL, *s = NULL; + EC_KEY *eckey; + + if (!ecsig) + return -1; + + if (ctx->genec_alg != LEGENEC_ECDSA) + goto bail; + + if ((int)sig_len != keybytes * 2) { + lwsl_err("%s: sig buf too small %d vs %d\n", __func__, + (int)sig_len, keybytes * 2); + goto bail; + } + /* + * 1. The JWS Signature value MUST be a 64-octet sequence. If it is + * not a 64-octet sequence, the validation has failed. + * + * 2. Split the 64-octet sequence into two 32-octet sequences. The + * first octet sequence represents R and the second S. The values R + * and S are represented as octet sequences using the Integer-to- + * OctetString Conversion defined in Section 2.3.7 of SEC1 [SEC1] + * (in big-endian octet order). + * + * 3. Submit the JWS Signing Input, R, S, and the public key (x, y) to + * the ECDSA P-256 SHA-256 validator. + */ + + r = BN_bin2bn(sig, keybytes, NULL); + if (!r) { + lwsl_err("%s: BN_bin2bn (r) fail\n", __func__); + goto bail; + } + + s = BN_bin2bn(sig + keybytes, keybytes, NULL); + if (!s) { + lwsl_err("%s: BN_bin2bn (s) fail\n", __func__); + goto bail1; + } + + if (ECDSA_SIG_set0(ecsig, r, s) != 1) { + lwsl_err("%s: ECDSA_SIG_set0 fail\n", __func__); + goto bail1; + } + + eckey = EVP_PKEY_get1_EC_KEY(EVP_PKEY_CTX_get0_pkey(ctx->ctx)); + + n = ECDSA_do_verify(in, hlen, ecsig, eckey); + EC_KEY_free(eckey); + if (n != 1) { + lwsl_err("%s: ECDSA_do_verify fail\n", __func__); + lws_tls_err_describe(); + goto bail; + } + + ret = 0; + goto bail; + +bail1: + if (r) + BN_free(r); + if (s) + BN_free(s); + +bail: + ECDSA_SIG_free(ecsig); return ret; } diff --git a/lib/tls/openssl/lws-genhash.c b/lib/tls/openssl/lws-genhash.c index c6ca2c5ec..e9d5125b7 100644 --- a/lib/tls/openssl/lws-genhash.c +++ b/lib/tls/openssl/lws-genhash.c @@ -23,6 +23,11 @@ */ #include "libwebsockets.h" +/* + * Care: many openssl apis return 1 for success. These are translated to the + * lws convention of 0 for success. + */ + int lws_genhash_init(struct lws_genhash_ctx *ctx, enum lws_genhash_types type) { @@ -60,6 +65,9 @@ lws_genhash_init(struct lws_genhash_ctx *ctx, enum lws_genhash_types type) int lws_genhash_update(struct lws_genhash_ctx *ctx, const void *in, size_t len) { + if (!len) + return 0; + return EVP_DigestUpdate(ctx->mdctx, in, len) != 1; } diff --git a/lib/tls/openssl/lws-genrsa.c b/lib/tls/openssl/lws-genrsa.c index ca3c2d539..826c31240 100644 --- a/lib/tls/openssl/lws-genrsa.c +++ b/lib/tls/openssl/lws-genrsa.c @@ -24,14 +24,15 @@ #include "core/private.h" #include "tls/openssl/private.h" +/* + * Care: many openssl apis return 1 for success. These are translated to the + * lws convention of 0 for success. + */ + LWS_VISIBLE void lws_genrsa_destroy_elements(struct lws_gencrypto_keyelem *el) { - int n; - - for (n = 0; n < LWS_GENCRYPTO_RSA_KEYEL_COUNT; n++) - if (el[n].buf) - lws_free_set_NULL(el[n].buf); + lws_gencrypto_destroy_elements(el, LWS_GENCRYPTO_RSA_KEYEL_COUNT); } static int mode_map_crypt[] = { RSA_PKCS1_PADDING, RSA_PKCS1_OAEP_PADDING }, @@ -74,7 +75,8 @@ bail: LWS_VISIBLE int lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_gencrypto_keyelem *el, - struct lws_context *context, enum enum_genrsa_mode mode) + struct lws_context *context, enum enum_genrsa_mode mode, + enum lws_genhash_types oaep_hashid) { int n; @@ -129,7 +131,7 @@ lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_gencrypto_keyelem *el, bail: for (n = 0; n < 5; n++) if (ctx->bn[n]) { - BN_free(ctx->bn[n]); + BN_clear_free(ctx->bn[n]); ctx->bn[n] = NULL; } @@ -168,7 +170,7 @@ lws_genrsa_new_keypair(struct lws_context *context, struct lws_genrsa_ctx *ctx, } n = RSA_generate_key_ex(ctx->rsa, bits, bn, NULL); - BN_free(bn); + BN_clear_free(bn); if (n != 1) goto cleanup_1; @@ -219,27 +221,59 @@ LWS_VISIBLE int lws_genrsa_public_encrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in, size_t in_len, uint8_t *out) { - if (RSA_public_encrypt((int)in_len, in, out, ctx->rsa, - mode_map_crypt[ctx->mode]) < 0) { + int n = RSA_public_encrypt((int)in_len, in, out, ctx->rsa, + mode_map_crypt[ctx->mode]); + if (n < 0) { lwsl_err("%s: RSA_public_encrypt failed\n", __func__); lws_tls_err_describe(); return -1; } - return 0; + return n; +} + +LWS_VISIBLE int +lws_genrsa_private_encrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in, + size_t in_len, uint8_t *out) +{ + int n = RSA_private_encrypt((int)in_len, in, out, ctx->rsa, + mode_map_crypt[ctx->mode]); + if (n < 0) { + lwsl_err("%s: RSA_private_encrypt failed\n", __func__); + lws_tls_err_describe(); + return -1; + } + + return n; } LWS_VISIBLE int lws_genrsa_public_decrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in, size_t in_len, uint8_t *out, size_t out_max) { - if (RSA_public_decrypt((int)in_len, in, out, ctx->rsa, - mode_map_crypt[ctx->mode]) < 0) { + int n = RSA_public_decrypt((int)in_len, in, out, ctx->rsa, + mode_map_crypt[ctx->mode]); + if (n < 0) { lwsl_err("%s: RSA_public_decrypt failed\n", __func__); return -1; } - return 0; + return n; +} + +LWS_VISIBLE int +lws_genrsa_private_decrypt(struct lws_genrsa_ctx *ctx, const uint8_t *in, + size_t in_len, uint8_t *out, size_t out_max) +{ + int n = RSA_private_decrypt((int)in_len, in, out, ctx->rsa, + mode_map_crypt[ctx->mode]); + if (n < 0) { + lwsl_err("%s: RSA_private_decrypt failed\n", __func__); + lws_tls_err_describe(); + return -1; + } + + return n; } LWS_VISIBLE int @@ -271,7 +305,8 @@ lws_genrsa_hash_sig_verify(struct lws_genrsa_ctx *ctx, const uint8_t *in, } if (n != 1) { - lwsl_notice("%s: -0x%x\n", __func__, -n); + lwsl_notice("%s: fail\n", __func__); + lws_tls_err_describe(); return -1; } diff --git a/lib/tls/openssl/openssl-client.c b/lib/tls/openssl/openssl-client.c index 62e250b54..ed2bbdf52 100644 --- a/lib/tls/openssl/openssl-client.c +++ b/lib/tls/openssl/openssl-client.c @@ -21,6 +21,11 @@ #include "core/private.h" +/* + * Care: many openssl apis return 1 for success. These are translated to the + * lws convention of 0 for success. + */ + int lws_openssl_describe_cipher(struct lws *wsi); extern int openssl_websocket_private_data_index, diff --git a/lib/tls/openssl/openssl-server.c b/lib/tls/openssl/openssl-server.c index d680ea837..96d3767cb 100644 --- a/lib/tls/openssl/openssl-server.c +++ b/lib/tls/openssl/openssl-server.c @@ -21,6 +21,11 @@ #include "core/private.h" +/* + * Care: many openssl apis return 1 for success. These are translated to the + * lws convention of 0 for success. + */ + extern int openssl_websocket_private_data_index, openssl_SSL_CTX_private_data_index; diff --git a/lib/tls/openssl/ssl.c b/lib/tls/openssl/ssl.c index db4f7b72f..06859b3ec 100644 --- a/lib/tls/openssl/ssl.c +++ b/lib/tls/openssl/ssl.c @@ -25,6 +25,11 @@ int openssl_websocket_private_data_index, openssl_SSL_CTX_private_data_index; +/* + * Care: many openssl apis return 1 for success. These are translated to the + * lws convention of 0 for success. + */ + int lws_openssl_describe_cipher(struct lws *wsi) { #if !defined(LWS_WITH_NO_LOGS) diff --git a/lib/tls/private.h b/lib/tls/private.h index 6a1cd0012..a299b5eca 100644 --- a/lib/tls/private.h +++ b/lib/tls/private.h @@ -293,6 +293,11 @@ lws_ssl_info_callback(const lws_tls_conn *ssl, int where, int ret); int lws_tls_fake_POLLIN_for_buffered(struct lws_context_per_thread *pt); +int +lws_gencrypto_bits_to_bytes(int bits); + +void +lws_gencrypto_destroy_elements(struct lws_gencrypto_keyelem *el, int m); /* genec */ diff --git a/minimal-examples/README.md b/minimal-examples/README.md index d80dece60..2f271dbc2 100644 --- a/minimal-examples/README.md +++ b/minimal-examples/README.md @@ -1,6 +1,7 @@ |name|demonstrates| ---|--- client-server|Minimal examples providing client and server connections simultaneously +crypto|Minimal examples related to using lws crypto apis dbus-server|Minimal examples showing how to integrate DBUS into lws event loop http-client|Minimal examples providing an http client http-server|Minimal examples providing an http server diff --git a/minimal-examples/api-tests/README.md b/minimal-examples/api-tests/README.md index b047af52f..ff8d48ed3 100644 --- a/minimal-examples/api-tests/README.md +++ b/minimal-examples/api-tests/README.md @@ -1,5 +1,10 @@ +These are buildable test apps that run in CI to confirm correct api operation. + |name|tests| ---|--- -api-test-lwsac|LWS Allocated Chunks -api-test-lws_tokenize|Generic secure string tokenizer +api-test-lwsac|LWS Allocated Chunks api +api-test-lws_tokenize|Generic secure string tokenizer api +api-test-fts|LWS Full-text Search api +api-test-gencrypto|LWS Generic Crypto apis +api-test-jose|LWS JOSE apis diff --git a/minimal-examples/api-tests/api-test-gencrypto/lws-genaes.c b/minimal-examples/api-tests/api-test-gencrypto/lws-genaes.c index b14e08e59..f2f6f20f9 100644 --- a/minimal-examples/api-tests/api-test-gencrypto/lws-genaes.c +++ b/minimal-examples/api-tests/api-test-gencrypto/lws-genaes.c @@ -64,7 +64,7 @@ test_genaes_cbc(void) return -1; } - if (memcmp(cbc256_enc, res, 16)) { + if (lws_timingsafe_bcmp(cbc256_enc, res, 16)) { lwsl_err("%s: lws_genaes_crypt encoding mismatch\n", __func__); lwsl_hexdump_notice(res, 16); return -1; @@ -88,7 +88,7 @@ test_genaes_cbc(void) return -1; } - if (memcmp(cbc256, res1, 16)) { + if (lws_timingsafe_bcmp(cbc256, res1, 16)) { lwsl_err("%s: lws_genaes_crypt decoding mismatch\n", __func__); lwsl_hexdump_notice(res, 16); return -1; @@ -151,7 +151,7 @@ test_genaes_cfb128(void) return -1; } - if (memcmp(cfb128_enc, res, 16)) { + if (lws_timingsafe_bcmp(cfb128_enc, res, 16)) { lwsl_err("%s: lws_genaes_crypt encoding mismatch\n", __func__); lwsl_hexdump_notice(res, 16); return -1; @@ -175,7 +175,7 @@ test_genaes_cfb128(void) return -1; } - if (memcmp(cfb128, res1, 16)) { + if (lws_timingsafe_bcmp(cfb128, res1, 16)) { lwsl_err("%s: lws_genaes_crypt decoding mismatch\n", __func__); lwsl_hexdump_notice(res1, 16); return -1; @@ -237,7 +237,7 @@ test_genaes_cfb8(void) return -1; } - if (memcmp(cfb8_enc, res, 16)) { + if (lws_timingsafe_bcmp(cfb8_enc, res, 16)) { lwsl_err("%s: lws_genaes_crypt encoding mismatch\n", __func__); lwsl_hexdump_notice(res, 16); return -1; @@ -259,7 +259,7 @@ test_genaes_cfb8(void) return -1; } - if (memcmp(cfb8, res1, 16)) { + if (lws_timingsafe_bcmp(cfb8, res1, 16)) { lwsl_err("%s: lws_genaes_crypt decoding mismatch\n", __func__); lwsl_hexdump_notice(res1, 16); return -1; @@ -325,7 +325,7 @@ test_genaes_ctr(void) return -1; } - if (memcmp(ctr_enc, res, 16)) { + if (lws_timingsafe_bcmp(ctr_enc, res, 16)) { lwsl_err("%s: lws_genaes_crypt encoding mismatch\n", __func__); lwsl_hexdump_notice(res, 16); return -1; @@ -350,7 +350,7 @@ test_genaes_ctr(void) return -1; } - if (memcmp(ctr, res1, 16)) { + if (lws_timingsafe_bcmp(ctr, res1, 16)) { lwsl_err("%s: lws_genaes_crypt decoding mismatch\n", __func__); lwsl_hexdump_notice(res1, 16); return -1; @@ -415,7 +415,7 @@ test_genaes_ecb(void) return -1; } - if (memcmp(ecb_enc, res, 16)) { + if (lws_timingsafe_bcmp(ecb_enc, res, 16)) { lwsl_err("%s: lws_genaes_crypt encoding mismatch\n", __func__); lwsl_hexdump_notice(res, 16); return -1; @@ -436,7 +436,7 @@ test_genaes_ecb(void) return -1; } - if (memcmp(ecb, res1, 16)) { + if (lws_timingsafe_bcmp(ecb, res1, 16)) { lwsl_err("%s: lws_genaes_crypt decoding mismatch\n", __func__); lwsl_hexdump_notice(res, 16); return -1; @@ -450,6 +450,9 @@ bail: return -1; } +#if defined(MBEDTLS_CONFIG_H) && !defined(MBEDTLS_CIPHER_MODE_OFB) +#else + static const uint8_t /* * produced with (plaintext.txt contains "test plaintext\0\0") @@ -506,7 +509,7 @@ test_genaes_ofb(void) return -1; } - if (memcmp(ofb_enc, res, 16)) { + if (lws_timingsafe_bcmp(ofb_enc, res, 16)) { lwsl_err("%s: lws_genaes_crypt encoding mismatch\n", __func__); lwsl_hexdump_notice(res, 16); return -1; @@ -530,7 +533,7 @@ test_genaes_ofb(void) return -1; } - if (memcmp(ofb, res1, 16)) { + if (lws_timingsafe_bcmp(ofb, res1, 16)) { lwsl_err("%s: lws_genaes_crypt decoding mismatch\n", __func__); lwsl_hexdump_notice(res, 16); return -1; @@ -544,6 +547,8 @@ bail: return -1; } +#endif + static const uint8_t /* * Fedora openssl tool doesn't support xts... this data produced @@ -594,7 +599,7 @@ test_genaes_xts(void) return -1; } - if (memcmp(xts_enc, res, 16)) { + if (lws_timingsafe_bcmp(xts_enc, res, 16)) { lwsl_err("%s: lws_genaes_crypt encoding mismatch\n", __func__); lwsl_hexdump_notice(res, 16); return -1; @@ -615,7 +620,7 @@ test_genaes_xts(void) return -1; } - if (memcmp(xts, res1, 16)) { + if (lws_timingsafe_bcmp(xts, res1, 16)) { lwsl_err("%s: lws_genaes_crypt decoding mismatch\n", __func__); lwsl_hexdump_notice(res, 16); return -1; @@ -697,7 +702,7 @@ test_genaes_gcm(void) return -1; } - if (memcmp(gcm_ct, res, sizeof(gcm_ct))) { + if (lws_timingsafe_bcmp(gcm_ct, res, sizeof(gcm_ct))) { lwsl_err("%s: lws_genaes_crypt encoding mismatch\n", __func__); lwsl_hexdump_notice(res, sizeof(gcm_ct)); return -1; @@ -730,7 +735,7 @@ test_genaes_gcm(void) return -1; } - if (memcmp(gcm_pt, res, sizeof(gcm_pt))) { + if (lws_timingsafe_bcmp(gcm_pt, res, sizeof(gcm_pt))) { lwsl_err("%s: lws_genaes_crypt decoding mismatch\n", __func__); lwsl_hexdump_notice(res, sizeof(gcm_ct)); return -1; @@ -763,8 +768,11 @@ test_genaes(struct lws_context *context) if (test_genaes_ecb()) goto bail; +#if defined(MBEDTLS_CONFIG_H) && !defined(MBEDTLS_CIPHER_MODE_OFB) +#else if (test_genaes_ofb()) goto bail; +#endif #if defined(MBEDTLS_CONFIG_H) && !defined(MBEDTLS_CIPHER_MODE_XTS) #else diff --git a/minimal-examples/api-tests/api-test-gencrypto/lws-genec.c b/minimal-examples/api-tests/api-test-gencrypto/lws-genec.c index d640650dd..db852c9a8 100644 --- a/minimal-examples/api-tests/api-test-gencrypto/lws-genec.c +++ b/minimal-examples/api-tests/api-test-gencrypto/lws-genec.c @@ -54,7 +54,7 @@ test_genec1(struct lws_context *context) lws_jwk_dump(&jwk); - if (jwk.kty != LWS_GENCRYPTO_KYT_EC) { + if (jwk.kty != LWS_GENCRYPTO_KTY_EC) { lws_jwk_destroy(&jwk); lwsl_err("%s: jwk is not an EC key\n", __func__); return 1; @@ -76,7 +76,7 @@ test_genec1(struct lws_context *context) goto bail; } - if (memcmp(cbc256_enc, res, 16)) { + if (lws_timingsafe_bcmp(cbc256_enc, res, 16)) { lwsl_err("%s: lws_genec_crypt encoding mismatch\n", __func__); lwsl_hexdump_notice(res, 16); goto bail; @@ -95,7 +95,7 @@ test_genec1(struct lws_context *context) goto bail; } - if (memcmp(cbc256, res1, 16)) { + if (lws_timingsafe_bcmp(cbc256, res1, 16)) { lwsl_err("%s: lws_genec_crypt decoding mismatch\n", __func__); lwsl_hexdump_notice(res, 16); goto bail; diff --git a/minimal-examples/api-tests/api-test-jose/jwe.c b/minimal-examples/api-tests/api-test-jose/jwe.c index 27b8b9b3d..f619a53a6 100644 --- a/minimal-examples/api-tests/api-test-jose/jwe.c +++ b/minimal-examples/api-tests/api-test-jose/jwe.c @@ -9,331 +9,1992 @@ #include +/* + * These are the inputs and outputs from the worked example in RFC7516 + * Appendix A.1 {"alg":"RSA-OAEP","enc":"A256GCM"} + */ -/* A.2. Example JWE using RSAES-PKCS1-v1_5 and AES_128_CBC_HMAC_SHA_256 */ + +static char + +*ex_a1_ptext = + "The true sign of intelligence is not knowledge but imagination.", + +*ex_a1_compact = + "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ." + "OKOawDo13gRp2ojaHV7LFpZcgV7T6DVZKTyKOMTYUmKoTCVJRgckCL9kiMT03JGe" + "ipsEdY3mx_etLbbWSrFr05kLzcSr4qKAq7YN7e9jwQRb23nfa6c9d-StnImGyFDb" + "Sv04uVuxIp5Zms1gNxKKK2Da14B8S4rzVRltdYwam_lDp5XnZAYpQdb76FdIKLaV" + "mqgfwX7XWRxv2322i-vDxRfqNzo_tETKzpVLzfiwQyeyPGLBIO56YJ7eObdv0je8" + "1860ppamavo35UgoRdbYaBcoh9QcfylQr66oc6vFWXRcZ_ZT2LawVCWTIy3brGPi" + "6UklfCpIMfIjf7iGdXKHzg." + "48V1_ALb6US04U3b." + "5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6ji" + "SdiwkIr3ajwQzaBtQD_A." + "XFBoMYUZodetZdvTiFvSkQ", + + *ex_a1_jwk_json = + "{\"kty\":\"RSA\"," + "\"n\":\"oahUIoWw0K0usKNuOR6H4wkf4oBUXHTxRvgb48E-BVvxkeDNjbC4he8rUW" + "cJoZmds2h7M70imEVhRU5djINXtqllXI4DFqcI1DgjT9LewND8MW2Krf3S" + "psk_ZkoFnilakGygTwpZ3uesH-PFABNIUYpOiN15dsQRkgr0vEhxN92i2a" + "sbOenSZeyaxziK72UwxrrKoExv6kc5twXTq4h-QChLOln0_mtUZwfsRaMS" + "tPs6mS6XrgxnxbWhojf663tuEQueGC-FCMfra36C9knDFGzKsNa7LZK2dj" + "YgyD3JR_MB_4NUJW_TqOQtwHYbxevoJArm-L5StowjzGy-_bq6Gw\"," + "\"e\":\"AQAB\"," + "\"d\":\"kLdtIj6GbDks_ApCSTYQtelcNttlKiOyPzMrXHeI-yk1F7-kpDxY4-WY5N" + "WV5KntaEeXS1j82E375xxhWMHXyvjYecPT9fpwR_M9gV8n9Hrh2anTpTD9" + "3Dt62ypW3yDsJzBnTnrYu1iwWRgBKrEYY46qAZIrA2xAwnm2X7uGR1hghk" + "qDp0Vqj3kbSCz1XyfCs6_LehBwtxHIyh8Ripy40p24moOAbgxVw3rxT_vl" + "t3UVe4WO3JkJOzlpUf-KTVI2Ptgm-dARxTEtE-id-4OJr0h-K-VFs3VSnd" + "VTIznSxfyrj8ILL6MG_Uv8YAu7VILSB3lOW085-4qE3DzgrTjgyQ\"," + "\"p\":\"1r52Xk46c-LsfB5P442p7atdPUrxQSy4mti_tZI3Mgf2EuFVbUoDBvaRQ-" + "SWxkbkmoEzL7JXroSBjSrK3YIQgYdMgyAEPTPjXv_hI2_1eTSPVZfzL0lf" + "fNn03IXqWF5MDFuoUYE0hzb2vhrlN_rKrbfDIwUbTrjjgieRbwC6Cl0\"," + "\"q\":\"wLb35x7hmQWZsWJmB_vle87ihgZ19S8lBEROLIsZG4ayZVe9Hi9gDVCOBm" + "UDdaDYVTSNx_8Fyw1YYa9XGrGnDew00J28cRUoeBB_jKI1oma0Orv1T9aX" + "IWxKwd4gvxFImOWr3QRL9KEBRzk2RatUBnmDZJTIAfwTs0g68UZHvtc\"," + "\"dp\":\"ZK-YwE7diUh0qR1tR7w8WHtolDx3MZ_OTowiFvgfeQ3SiresXjm9gZ5KL" + "hMXvo-uz-KUJWDxS5pFQ_M0evdo1dKiRTjVw_x4NyqyXPM5nULPkcpU827" + "rnpZzAJKpdhWAgqrXGKAECQH0Xt4taznjnd_zVpAmZZq60WPMBMfKcuE\"," + "\"dq\":\"Dq0gfgJ1DdFGXiLvQEZnuKEN0UUmsJBxkjydc3j4ZYdBiMRAy86x0vHCj" + "ywcMlYYg4yoC4YZa9hNVcsjqA3FeiL19rk8g6Qn29Tt0cj8qqyFpz9vNDB" + "UfCAiJVeESOjJDZPYHdHY8v1b-o-Z2X5tvLx-TCekf7oxyeKDUqKWjis\"," + "\"qi\":\"VIMpMYbPf47dT1w_zDUXfPimsSegnMOA1zTaX7aGk_8urY6R8-ZW1FxU7" + "AlWAyLWybqq6t16VFd7hQd0y6flUK4SlOydB61gwanOsXGOAOv82cHq0E3" + "eL4HrtZkUuKvnPrMnsUUFlfUdybVzxyjz9JF_XyaY14ardLSjf4L_FNY\"" + "}" +; + +static int +test_jwe_a1(struct lws_context *context) +{ + struct lws_jose jose; + struct lws_jws jws; + struct lws_jwk jwk; + char temp[2048], compact[2048]; + int n, ret = -1, temp_len = sizeof(temp); + + lws_jose_init(&jose); + lws_jws_init(&jws, &jwk, context); + + if (lws_jwk_import(&jwk, NULL, NULL, ex_a1_jwk_json, + strlen(ex_a1_jwk_json)) < 0) { + lwsl_notice("%s: Failed to decode JWK test key\n", __func__); + goto bail; + } + + /* converts a compact serialization to jws b64 + decoded maps */ + if (lws_jws_compact_decode(ex_a1_compact, strlen(ex_a1_compact), + &jws.map, &jws.map_b64, temp, &temp_len) != 5) { + lwsl_err("%s: lws_jws_compact_decode failed\n", __func__); + goto bail; + } + + n = lws_jwe_auth_and_decrypt(&jose, &jws); + lws_jwk_destroy(&jwk); + if (n < 0) { + lwsl_err("%s: lws_jwe_auth_and_decrypt failed\n", + __func__); + goto bail; + } + + /* allowing for trailing padding, confirm the plaintext */ + if (jws.map.len[LJWE_CTXT] < strlen(ex_a1_ptext) || + lws_timingsafe_bcmp(jws.map.buf[LJWE_CTXT], ex_a1_ptext, + strlen(ex_a1_ptext))) { + lwsl_err("%s: plaintext AES decrypt wrong\n", __func__); + lwsl_hexdump_notice(ex_a1_ptext, strlen(ex_a1_ptext)); + lwsl_hexdump_notice(jws.map.buf[LJWE_CTXT], + jws.map.len[LJWE_CTXT]); + goto bail; + } + + /* + * Canned decrypt worked properly... let's also try encoding the + * plaintext ourselves and decoding that... + */ + lws_jws_destroy(&jws); + lws_jose_destroy(&jose); + temp_len = sizeof(temp); + lws_jose_init(&jose); + lws_jws_init(&jws, &jwk, context); + + if (lws_jwk_import(&jwk, NULL, NULL, ex_a1_jwk_json, + strlen(ex_a1_jwk_json)) < 0) { + lwsl_notice("%s: Failed to decode JWK test key\n", __func__); + goto bail; + } + + if (lws_gencrypto_jwe_alg_to_definition("RSA-OAEP", &jose.alg)) { + lwsl_err("Unknown cipher alg \"RSA-OAEP\"\n"); + goto bail1; + } + if (lws_gencrypto_jwe_enc_to_definition("A256GCM", &jose.enc_alg)) { + lwsl_err("Unknown payload enc alg \"A256GCM\"\n"); + goto bail1; + } + + /* we require a JOSE-formatted header to do the encryption */ + + if (temp_len < 256) + goto bail1; + jws.map.buf[LJWS_JOSE] = temp; + jws.map.len[LJWS_JOSE] = lws_snprintf(temp, temp_len, + "{\"alg\":\"%s\",\"enc\":\"%s\"}", "RSA-OAEP", "A256GCM"); + temp_len -= jws.map.len[LJWS_JOSE]; + + /* + * dup the plaintext into the ciphertext element, it will be + * encrypted in-place to a ciphertext of the same length + */ + + if (lws_jws_dup_element(&jws.map, LJWE_CTXT, + lws_concat_temp(temp, temp_len), &temp_len, + ex_a1_ptext, strlen(ex_a1_ptext), 0)) { + lwsl_notice("%s: Not enough temp space for ptext\n", __func__); + goto bail; + } + + /* CEK size is determined by hash / hmac size */ + + n = lws_gencrypto_bits_to_bytes(jose.enc_alg->keybits_fixed); + if (lws_jws_randomize_element(context, &jws.map, LJWE_EKEY, + lws_concat_temp(temp, temp_len), + &temp_len, n, + LWS_JWE_LIMIT_KEY_ELEMENT_BYTES)) { + lwsl_err("Problem getting random\n"); + goto bail1; + } + + n = lws_jwe_encrypt(&jose, &jws, lws_concat_temp(temp, temp_len), + &temp_len); + if (n < 0) { + lwsl_err("%s: lws_jwe_encrypt failed\n", __func__); + goto bail1; + } + n = lws_jwe_write_compact(&jose, &jws, compact, sizeof(compact)); + if (n < 0) { + lwsl_err("%s: lws_jwe_write_compact failed: %d\n", + __func__, n); + goto bail1; + } + + // puts(compact); + + /* + * Okay... what happens when we try to decode what we created? + */ + + lws_jws_destroy(&jws); + lws_jws_init(&jws, &jwk, context); + temp_len = sizeof(temp); + + /* converts a compact serialization to jws b64 + decoded maps */ + if (lws_jws_compact_decode(compact, strlen(compact), + &jws.map, &jws.map_b64, temp, &temp_len) != 5) { + lwsl_err("%s: lws_jws_compact_decode failed\n", __func__); + goto bail; + } + + n = lws_jwe_auth_and_decrypt(&jose, &jws); + lws_jwk_destroy(&jwk); + if (n < 0) { + lwsl_err("%s: generated lws_jwe_auth_and_decrypt failed\n", + __func__); + goto bail; + } + + ret = 0; + +bail1: + lws_jwk_destroy(&jwk); +bail: + lws_jose_destroy(&jose); + if (ret) + lwsl_err("%s: selftest failed +++++++++++++++++++\n", __func__); + else + lwsl_notice("%s: selftest OK\n", __func__); + + return ret; +} + + +/* A.2. Example JWE using RSAES-PKCS1-v1_5 and AES_128_CBC_HMAC_SHA_256 + * + * This example encrypts the plaintext "Live long and prosper." to the + * recipient using RSAES-PKCS1-v1_5 for key encryption and + * AES_128_CBC_HMAC_SHA_256 for content encryption. + */ /* "Live long and prosper." */ -static -uint8_t +static uint8_t -#if 0 -lws_jwe_ex_a2_plaintext[] = { +ex_a2_ptext[] = { + 76, 105, 118, 101, 32, 108, 111, 110, + 103, 32, 97, 110, 100, 32, 112, 114, + 111, 115, 112, 101, 114, 46 +}, *lws_jwe_ex_a2_jwk_json = (uint8_t *) + "{" + "\"kty\":\"RSA\"," + "\"n\":\"sXchDaQebHnPiGvyDOAT4saGEUetSyo9MKLOoWFsueri23bOdgWp4Dy1Wl" + "UzewbgBHod5pcM9H95GQRV3JDXboIRROSBigeC5yjU1hGzHHyXss8UDpre" + "cbAYxknTcQkhslANGRUZmdTOQ5qTRsLAt6BTYuyvVRdhS8exSZEy_c4gs_" + "7svlJJQ4H9_NxsiIoLwAEk7-Q3UXERGYw_75IDrGA84-lA_-Ct4eTlXHBI" + "Y2EaV7t7LjJaynVJCpkv4LKjTTAumiGUIuQhrNhZLuF_RJLqHpM2kgWFLU" + "7-VTdL1VbC2tejvcI2BlMkEpk1BzBZI0KQB0GaDWFLN-aEAw3vRw\"," + "\"e\":\"AQAB\"," + "\"d\":\"VFCWOqXr8nvZNyaaJLXdnNPXZKRaWCjkU5Q2egQQpTBMwhprMzWzpR8Sxq" + "1OPThh_J6MUD8Z35wky9b8eEO0pwNS8xlh1lOFRRBoNqDIKVOku0aZb-ry" + "nq8cxjDTLZQ6Fz7jSjR1Klop-YKaUHc9GsEofQqYruPhzSA-QgajZGPbE_" + "0ZaVDJHfyd7UUBUKunFMScbflYAAOYJqVIVwaYR5zWEEceUjNnTNo_CVSj" + "-VvXLO5VZfCUAVLgW4dpf1SrtZjSt34YLsRarSb127reG_DUwg9Ch-Kyvj" + "T1SkHgUWRVGcyly7uvVGRSDwsXypdrNinPA4jlhoNdizK2zF2CWQ\"," + "\"p\":\"9gY2w6I6S6L0juEKsbeDAwpd9WMfgqFoeA9vEyEUuk4kLwBKcoe1x4HG68" + "ik918hdDSE9vDQSccA3xXHOAFOPJ8R9EeIAbTi1VwBYnbTp87X-xcPWlEP" + "krdoUKW60tgs1aNd_Nnc9LEVVPMS390zbFxt8TN_biaBgelNgbC95sM\"," + "\"q\":\"uKlCKvKv_ZJMVcdIs5vVSU_6cPtYI1ljWytExV_skstvRSNi9r66jdd9-y" + "BhVfuG4shsp2j7rGnIio901RBeHo6TPKWVVykPu1iYhQXw1jIABfw-MVsN" + "-3bQ76WLdt2SDxsHs7q7zPyUyHXmps7ycZ5c72wGkUwNOjYelmkiNS0\"," + "\"dp\":\"w0kZbV63cVRvVX6yk3C8cMxo2qCM4Y8nsq1lmMSYhG4EcL6FWbX5h9yuv" + "ngs4iLEFk6eALoUS4vIWEwcL4txw9LsWH_zKI-hwoReoP77cOdSL4AVcra" + "Hawlkpyd2TWjE5evgbhWtOxnZee3cXJBkAi64Ik6jZxbvk-RR3pEhnCs\"," + "\"dq\":\"o_8V14SezckO6CNLKs_btPdFiO9_kC1DsuUTd2LAfIIVeMZ7jn1Gus_Ff" + "7B7IVx3p5KuBGOVF8L-qifLb6nQnLysgHDh132NDioZkhH7mI7hPG-PYE_" + "odApKdnqECHWw0J-F0JWnUd6D2B_1TvF9mXA2Qx-iGYn8OVV1Bsmp6qU\"," + "\"qi\":\"eNho5yRBEBxhGBtQRww9QirZsB66TrfFReG_CcteI1aCneT0ELGhYlRlC" + "tUkTRclIfuEPmNsNDPbLoLqqCVznFbvdB7x-Tl-m0l_eFTj2KiqwGqE9PZ" + "B9nNTwMVvH3VRRSLWACvPnSiwP8N5Usy-WRXS-V7TbpxIhvepTfE0NNo\"" + "}", + +*ex_a2_compact = (uint8_t *) + "eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0" + "." + "UGhIOguC7IuEvf_NPVaXsGMoLOmwvc1GyqlIKOK1nN94nHPoltGRhWhw7Zx0-kFm" + "1NJn8LE9XShH59_i8J0PH5ZZyNfGy2xGdULU7sHNF6Gp2vPLgNZ__deLKxGHZ7Pc" + "HALUzoOegEI-8E66jX2E4zyJKx-YxzZIItRzC5hlRirb6Y5Cl_p-ko3YvkkysZIF" + "NPccxRU7qve1WYPxqbb2Yw8kZqa2rMWI5ng8OtvzlV7elprCbuPhcCdZ6XDP0_F8" + "rkXds2vE4X-ncOIM8hAYHHi29NX0mcKiRaD0-D-ljQTP-cFPgwCp6X-nZZd9OHBv" + "-B3oWh2TbqmScqXMR4gp_A" + "." + "AxY8DCtDaGlsbGljb3RoZQ" + "." + "KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY" + "." + "9hH0vgRfYgPnAHOd8stkvw" +; + +static int +test_jwe_a2(struct lws_context *context) +{ + struct lws_jose jose; + struct lws_jws jws; + struct lws_jwk jwk; + char temp[2048]; + int n, ret = -1, temp_len = sizeof(temp); + + lws_jose_init(&jose); + lws_jws_init(&jws, &jwk, context); + + if (lws_jwk_import(&jwk, NULL, NULL, (char *)lws_jwe_ex_a2_jwk_json, + strlen((char *)lws_jwe_ex_a2_jwk_json)) < 0) { + lwsl_notice("%s: Failed to decode JWK test key\n", __func__); + goto bail; + } + + /* converts a compact serialization to jws b64 + decoded maps */ + if (lws_jws_compact_decode((const char *)ex_a2_compact, + strlen((char *)ex_a2_compact), + &jws.map, &jws.map_b64, + (char *)temp, &temp_len) != 5) { + lwsl_err("%s: lws_jws_compact_decode failed\n", __func__); + goto bail; + } + + n = lws_jwe_auth_and_decrypt(&jose, &jws); + lws_jwk_destroy(&jwk); + if (n < 0) { + lwsl_err("%s: lws_jwe_auth_and_decrypt failed\n", + __func__); + goto bail; + } + + /* allowing for trailing padding, confirm the plaintext */ + if (jws.map.len[LJWE_CTXT] < sizeof(ex_a2_ptext) || + lws_timingsafe_bcmp(jws.map.buf[LJWE_CTXT], ex_a2_ptext, + sizeof(ex_a2_ptext))) { + lwsl_err("%s: plaintext AES decrypt wrong\n", __func__); + lwsl_hexdump_notice(ex_a2_ptext, sizeof(ex_a2_ptext)); + lwsl_hexdump_notice(jws.map.buf[LJWE_CTXT], + jws.map.len[LJWE_CTXT]); + goto bail; + } + + ret = 0; + +bail: + lws_jws_destroy(&jws); + lws_jose_destroy(&jose); + if (ret) + lwsl_err("%s: selftest failed +++++++++++++++++++\n", __func__); + else + lwsl_notice("%s: selftest OK\n", __func__); + + return ret; +} + +/* JWE creation using RSAES-PKCS1-v1_5 and AES_128_CBC_HMAC_SHA_256 + * + * This example encrypts a different, larger plaintext using the jwk key from + * the test above, and AES_128_CBC_HMAC_SHA_256 for content encryption. + */ + +static const char *rsa256a128_jose = + "{ \"alg\":\"RSA1_5\",\"enc\":\"A128CBC-HS256\"}"; + +static uint8_t + + /* plaintext is 1024 bytes from /dev/urandom */ + +ra_ptext_1024[] = { + 0xfe, 0xc6, 0x4f, 0x3e, 0x4a, 0x19, 0xe9, 0xd7, + 0xc2, 0x13, 0xe7, 0xc5, 0x78, 0x6e, 0x71, 0xf6, + 0x6e, 0xdd, 0x04, 0xaf, 0xaa, 0x4e, 0xa8, 0xad, + 0xd8, 0xe0, 0xb3, 0x32, 0x97, 0x43, 0x7c, 0xd8, + 0xd1, 0x5f, 0x56, 0xac, 0x70, 0xaf, 0x7d, 0x0b, + 0x40, 0xa1, 0x96, 0x71, 0x7c, 0xc4, 0x4a, 0x37, + 0x0b, 0xa6, 0x06, 0xb3, 0x8c, 0x87, 0xee, 0xb6, + 0x15, 0xfe, 0xaa, 0x60, 0x7e, 0x7f, 0xdc, 0xb0, + 0xff, 0x96, 0x4b, 0x30, 0x60, 0xcf, 0xc6, 0x5d, + 0x09, 0x6a, 0x6f, 0x66, 0x0c, 0x5f, 0xb0, 0x6f, + 0x61, 0xa6, 0x26, 0x02, 0xbd, 0x46, 0xda, 0xa3, + 0x73, 0x19, 0x17, 0xff, 0xe0, 0x5f, 0x30, 0x72, + 0x7d, 0x17, 0xd8, 0xb2, 0xbe, 0x84, 0x3e, 0x4d, + 0x76, 0xbd, 0x62, 0x5d, 0x63, 0xfe, 0x11, 0x32, + 0x11, 0x41, 0xdc, 0xed, 0x96, 0xfd, 0x31, 0x38, + 0x6a, 0x84, 0x55, 0x7a, 0x33, 0x3f, 0x37, 0xc3, + 0x37, 0x7b, 0xc1, 0xb7, 0x89, 0x00, 0x39, 0xa6, + 0x94, 0x91, 0xb7, 0x19, 0x6b, 0x1d, 0x99, 0xeb, + 0xf6, 0x10, 0xb9, 0xd2, 0xcd, 0x15, 0x0d, 0xbc, + 0x24, 0x34, 0x9a, 0x52, 0x64, 0x21, 0x72, 0x1e, + 0x9a, 0x00, 0xf2, 0xcf, 0xf1, 0x7d, 0x1a, 0x12, + 0x8d, 0x39, 0xbc, 0xf9, 0x09, 0xfd, 0xd9, 0x22, + 0x27, 0x28, 0xe1, 0x3a, 0x0b, 0x82, 0xba, 0x9a, + 0xe5, 0x9d, 0xa8, 0x12, 0x6e, 0xf5, 0x4b, 0xc7, + 0x2b, 0x9c, 0xdc, 0xfe, 0xf3, 0xe8, 0x74, 0x65, + 0x3d, 0xe0, 0xaa, 0x64, 0xf3, 0x43, 0xa4, 0x88, + 0xa8, 0xbe, 0x60, 0xdb, 0xfd, 0x2d, 0x3b, 0x84, + 0x82, 0x8f, 0x4d, 0xbb, 0xe4, 0xa9, 0x59, 0xe3, + 0x6c, 0x52, 0x45, 0xe4, 0x34, 0xdb, 0x28, 0x0e, + 0x4a, 0x44, 0xb6, 0x9a, 0x25, 0x9b, 0x3b, 0xae, + 0xe1, 0x12, 0x1d, 0x1c, 0x66, 0x7d, 0xb9, 0x5b, + 0x5f, 0xc2, 0x4a, 0xaa, 0xd2, 0xe9, 0x65, 0xe2, + 0x85, 0x6f, 0xf6, 0x67, 0x66, 0x8e, 0x0b, 0xd2, + 0x60, 0xf8, 0x43, 0x60, 0x04, 0x9b, 0xa9, 0x3a, + 0x6a, 0x3c, 0x02, 0x3c, 0x08, 0x9d, 0x60, 0x1c, + 0xc4, 0x27, 0x3e, 0xff, 0xd0, 0x70, 0x94, 0x43, + 0x3e, 0x9e, 0x69, 0x19, 0x22, 0xf0, 0xec, 0x26, + 0x2d, 0xa5, 0x71, 0xf3, 0x92, 0x61, 0x95, 0xce, + 0xc3, 0xc0, 0xa0, 0xc3, 0x98, 0x22, 0xdd, 0x32, + 0x3c, 0x48, 0xcb, 0xd1, 0x61, 0xa0, 0xaa, 0x9a, + 0x7e, 0x5a, 0xfa, 0x26, 0x46, 0x49, 0xfc, 0x9c, + 0xaa, 0x21, 0x06, 0x45, 0xf1, 0xa0, 0xc9, 0xef, + 0x6b, 0x89, 0xf2, 0x01, 0x20, 0x54, 0xfa, 0x0a, + 0x23, 0xff, 0xbd, 0x64, 0x35, 0x94, 0xfd, 0x35, + 0x70, 0x52, 0x94, 0x66, 0xc5, 0xd0, 0x27, 0xc1, + 0x8f, 0x6d, 0xc4, 0xa3, 0x34, 0xc2, 0xea, 0xf0, + 0xb3, 0x0d, 0x6c, 0x13, 0xb5, 0xc9, 0x6e, 0x5c, + 0xeb, 0x8b, 0x7b, 0xf5, 0x21, 0x4c, 0xe3, 0xb7, + 0x73, 0x6d, 0x07, 0xaa, 0x44, 0xc4, 0xba, 0xc5, + 0xa5, 0x0e, 0x75, 0x28, 0xb7, 0x50, 0x22, 0x54, + 0xa7, 0xe1, 0x2e, 0xfd, 0x20, 0xcd, 0xa4, 0x31, + 0xa3, 0xb2, 0x73, 0x98, 0x7c, 0x3c, 0x8f, 0xa3, + 0x40, 0x8a, 0xaf, 0x31, 0xfa, 0xf9, 0x70, 0x4d, + 0x83, 0x10, 0xc4, 0xa0, 0x9c, 0xd6, 0xa3, 0xd5, + 0x07, 0xaf, 0xaf, 0x35, 0x15, 0xd0, 0x84, 0x09, + 0x20, 0x36, 0x88, 0xac, 0x6f, 0x16, 0x5e, 0x03, + 0xa9, 0xfc, 0xb3, 0x2d, 0x01, 0x57, 0xb3, 0xed, + 0x4b, 0x55, 0x2b, 0xbc, 0x92, 0x87, 0x3e, 0x27, + 0xc4, 0x2c, 0x44, 0xac, 0x05, 0x5f, 0x26, 0xe7, + 0xe9, 0xb0, 0x2d, 0x6b, 0x3c, 0x8c, 0xd2, 0xb4, + 0x3c, 0xb4, 0x86, 0xfe, 0x68, 0x99, 0x2a, 0x42, + 0xac, 0xa4, 0xb3, 0x89, 0x61, 0xb3, 0xd1, 0xdf, + 0x9b, 0x58, 0xc7, 0x81, 0x62, 0x87, 0x26, 0x52, + 0x51, 0xe7, 0x7d, 0x7c, 0x37, 0x14, 0xe5, 0x19, + 0x28, 0x34, 0x3e, 0x95, 0x17, 0x36, 0x12, 0xf9, + 0x5e, 0xc1, 0x3c, 0x9c, 0x28, 0x70, 0x06, 0xdf, + 0xc4, 0x6d, 0x25, 0x04, 0x46, 0xe0, 0x95, 0xf0, + 0xc8, 0x57, 0x48, 0x27, 0x26, 0xf3, 0xf7, 0x19, + 0xbe, 0xea, 0xb4, 0xd4, 0x64, 0xaf, 0x67, 0x7c, + 0xf5, 0xa9, 0xfb, 0x85, 0x4a, 0x43, 0x9c, 0x62, + 0x06, 0x5e, 0x28, 0x2a, 0x7b, 0x1e, 0xb3, 0x07, + 0xe7, 0x19, 0x32, 0xa4, 0x4e, 0xb4, 0xce, 0xe0, + 0x92, 0x56, 0xf5, 0x10, 0xcb, 0x56, 0x34, 0x4b, + 0x0d, 0xe1, 0xd3, 0x6d, 0xfe, 0xf0, 0x44, 0xf7, + 0x22, 0x1d, 0x5e, 0x6b, 0xa7, 0xa5, 0x83, 0x2e, + 0xeb, 0x14, 0xf2, 0xd7, 0x27, 0x5a, 0x2a, 0xd2, + 0x55, 0x35, 0xe6, 0x7e, 0xd9, 0x3b, 0xac, 0x4e, + 0x5a, 0x22, 0x46, 0xd5, 0x7b, 0x57, 0x9c, 0x58, + 0xfe, 0xd0, 0xda, 0xbf, 0x7d, 0xe9, 0x8c, 0xb7, + 0xba, 0x88, 0xf1, 0xc3, 0x82, 0x53, 0xc3, 0x66, + 0x20, 0x51, 0x12, 0xd3, 0xf9, 0xaf, 0xe9, 0xcb, + 0xc1, 0x7a, 0xe6, 0x22, 0x44, 0xa5, 0xdf, 0x18, + 0xb3, 0x6e, 0x6c, 0xba, 0xf3, 0xc6, 0x24, 0x5a, + 0x1c, 0x67, 0xa6, 0xa5, 0xb4, 0xb1, 0x35, 0xdf, + 0x5a, 0x60, 0x5c, 0x0b, 0x66, 0xd3, 0x1f, 0x4e, + 0x7c, 0xcb, 0x93, 0x7e, 0x2f, 0x6d, 0xbd, 0xce, + 0x26, 0x52, 0x44, 0xee, 0xbb, 0xd8, 0x8f, 0xf2, + 0x67, 0x38, 0x0d, 0x3b, 0xaa, 0x21, 0x73, 0xf8, + 0x3b, 0x54, 0x9d, 0x4e, 0x5e, 0xf1, 0xa2, 0x18, + 0x5a, 0xf1, 0x6c, 0x32, 0xbf, 0x0a, 0x73, 0x14, + 0x48, 0x4f, 0x56, 0xc0, 0x87, 0x6d, 0x3b, 0x16, + 0xcc, 0x3f, 0x44, 0x19, 0x85, 0x22, 0x43, 0x5f, + 0x8c, 0x29, 0xbd, 0xa0, 0xce, 0x84, 0xd9, 0x4a, + 0xcf, 0x00, 0x6b, 0x37, 0x35, 0xe0, 0xb3, 0xc9, + 0xd1, 0x58, 0xd1, 0x1b, 0xc3, 0x6f, 0xe3, 0x50, + 0xdb, 0xa6, 0x5e, 0x03, 0x18, 0xe5, 0xe2, 0xc1, + 0x97, 0xd5, 0xf8, 0x42, 0x6f, 0xe6, 0x61, 0x80, + 0xc9, 0x7c, 0xc6, 0x83, 0xf0, 0xad, 0x70, 0x13, + 0x0e, 0x26, 0x75, 0xc0, 0x12, 0x23, 0x14, 0xef, + 0x1f, 0xdf, 0xfd, 0x47, 0x99, 0x9f, 0x22, 0xf3, + 0x57, 0x21, 0xdc, 0x38, 0xe4, 0x79, 0x87, 0x5b, + 0x67, 0x66, 0xdd, 0x0b, 0xe0, 0xae, 0xb5, 0x97, + 0xd8, 0xa6, 0x5d, 0x02, 0xcf, 0x6b, 0x84, 0x19, + 0xc1, 0xbb, 0x25, 0xd2, 0x10, 0xb9, 0x63, 0xeb, + 0x4b, 0x27, 0x8d, 0x05, 0x31, 0xce, 0x3b, 0x0c, + 0x5f, 0xd4, 0x83, 0x47, 0xa4, 0x8b, 0xc4, 0x76, + 0x33, 0x74, 0x1a, 0x07, 0xf8, 0x18, 0x82, 0x1c, + 0x8e, 0x01, 0x75, 0x78, 0xea, 0xd9, 0x72, 0x61, + 0x71, 0xa9, 0x09, 0x44, 0x7b, 0x0f, 0x12, 0xcf, + 0x4c, 0x76, 0x7b, 0x69, 0xc8, 0x64, 0x98, 0x60, + 0x45, 0xb6, 0xc7, 0x6b, 0xd8, 0x43, 0x99, 0x08, + 0xc9, 0xd3, 0x6f, 0x01, 0x4f, 0x57, 0x6f, 0x49, + 0x4f, 0x4f, 0x72, 0xa4, 0xa2, 0x45, 0xe1, 0x0e, + 0xf2, 0x08, 0x3e, 0x67, 0xc3, 0x83, 0x5b, 0xb1, + 0x24, 0xc0, 0xe0, 0x3a, 0xf5, 0x1f, 0xf2, 0x06, + 0x4b, 0xa7, 0x6f, 0xd2, 0xb2, 0x81, 0x96, 0x91, + 0x42, 0xb1, 0x53, 0x65, 0x3a, 0x12, 0xcd, 0x33, + 0xb3, 0x7e, 0x79, 0xc0, 0x46, 0xf6, 0xd8, 0x4a, + 0x22, 0x35, 0xb8, 0x3f, 0xe4, 0x08, 0x88, 0x49, + 0x3c, 0x73, 0x9a, 0x44, 0xe3, 0x3b, 0xcc, 0xc4, + 0xae, 0x7c, 0xbe, 0xfd, 0xa6, 0x4a, 0xd4, 0x26, + 0x52, 0x58, 0x81, 0x30, 0x66, 0x44, 0x54, 0xc8, + 0xe4, 0x7c, 0x5b, 0x63, 0x06, 0x60, 0x94, 0x62, + 0xe5, 0x47, 0x45, 0xfb, 0x58, 0xf5, 0x6a, 0x7c, + 0xb2, 0x35, 0x08, 0x03, 0x15, 0x68, 0xb3, 0x13, + 0xa5, 0xbd, 0xf2, 0x1e, 0x2e, 0x1c, 0x8f, 0xc6, + 0xc7, 0xd1, 0xa9, 0x64, 0x37, 0x2b, 0x23, 0xfa, + 0x7e, 0x56, 0x22, 0xf0, 0x8a, 0xbd, 0xeb, 0x04 +}, + +r256a128_cek[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f +} +; + +static int +test_jwe_ra_ptext_1024(struct lws_context *context, char *jwk_txt, int jwk_len) +{ + struct lws_jose jose, dec_jose; + char temp[4096], compact[4096]; + struct lws_jws jws; + struct lws_jwk jwk; + int n, ret = -1, temp_len = sizeof(temp); + + lws_jose_init(&jose); + lws_jose_init(&dec_jose); + lws_jws_init(&jws, &jwk, context); + + /* reuse the rsa private key from the JWE Appendix 2 test above */ + + if (lws_jwk_import(&jwk, NULL, NULL, jwk_txt, jwk_len) < 0) { + lwsl_notice("%s: Failed to decode JWK test key\n", __func__); + goto bail; + } + + /* dup the plaintext, it will be replaced in-situ by the ciphertext */ + + if (lws_jws_dup_element(&jws.map, LJWE_CTXT, + lws_concat_temp(temp, temp_len), &temp_len, + ra_ptext_1024, sizeof(ra_ptext_1024), 0)) { + lwsl_notice("%s: Not enough temp space for ptext\n", __func__); + goto bail; + } + + /* dup the cek, since it will be replaced by the encrypted key */ + + if (lws_jws_dup_element(&jws.map, LJWE_EKEY, + lws_concat_temp(temp, temp_len), &temp_len, + r256a128_cek, sizeof(r256a128_cek), + LWS_JWE_LIMIT_KEY_ELEMENT_BYTES)) { + lwsl_notice("%s: Not enough temp space for EKEY\n", __func__); + goto bail; + } + + jws.map.buf[LJWE_JOSE] = rsa256a128_jose; + jws.map.len[LJWE_JOSE] = strlen(rsa256a128_jose); + + n = lws_jwe_parse_jose(&jose, jws.map.buf[LJWE_JOSE], + jws.map.len[LJWE_JOSE], + lws_concat_temp(temp, temp_len), &temp_len); + if (n < 0) { + lwsl_err("%s: JOSE parse failed\n", __func__); + + goto bail1; + } + + n = lws_jwe_encrypt(&jose, &jws, lws_concat_temp(temp, temp_len), + &temp_len); + if (n < 0) { + lwsl_err("%s: lws_jwe_encrypt failed\n", __func__); + goto bail1; + } + + n = lws_jwe_write_compact(&jose, &jws, compact, sizeof(compact)); + if (n < 0) { + lwsl_err("%s: lws_jwe_write_compact failed: %d\n", __func__, n); + goto bail1; + } + + // puts(compact); + + lws_jws_destroy(&jws); + lws_jws_init(&jws, &jwk, context); + temp_len = sizeof(temp); + + /* now we created the encrypted version, see if we can decrypt it */ + + if (lws_jws_compact_decode(compact, n, &jws.map, &jws.map_b64, + temp, &temp_len) != 5) { + lwsl_err("%s: failed to parse generated compact\n", __func__); + + goto bail1; + } + + n = lws_jwe_auth_and_decrypt(&dec_jose, &jws); + if (n < 0) { + lwsl_err("%s: lws_jwe_auth_and_decrypt failed\n", + __func__); + goto bail1; + } + + /* allowing for trailing padding, confirm the plaintext */ + if (jws.map.len[LJWE_CTXT] < sizeof(ra_ptext_1024) || + lws_timingsafe_bcmp(jws.map.buf[LJWE_CTXT], ra_ptext_1024, + sizeof(ra_ptext_1024))) { + lwsl_err("%s: plaintext AES decrypt wrong\n", __func__); + lwsl_hexdump_notice(ra_ptext_1024, sizeof(ra_ptext_1024)); + lwsl_hexdump_notice(jws.map.buf[LJWE_CTXT], + jws.map.len[LJWE_CTXT]); + goto bail1; + } + + ret = 0; + +bail1: + lws_jwk_destroy(&jwk); +bail: + lws_jws_destroy(&jws); + lws_jose_destroy(&dec_jose); + lws_jose_destroy(&jose); + if (ret) + lwsl_err("%s: selftest failed +++++++++++++++++++\n", __func__); + else + lwsl_notice("%s: selftest OK\n", __func__); + + return ret; +} + +static const char *rsa256a192_jose = + "{ \"alg\":\"RSA1_5\",\"enc\":\"A192CBC-HS384\"}"; + +static const uint8_t r256a192_cek[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f +} +; + +static int +test_jwe_r256a192_ptext(struct lws_context *context, char *jwk_txt, int jwk_len) +{ + struct lws_jose jose, dec_jose; + struct lws_jws jws; + struct lws_jwk jwk; + char temp[4096], compact[4096]; + int n, ret = -1, temp_len = sizeof(temp); + + lws_jose_init(&jose); + lws_jose_init(&dec_jose); + lws_jws_init(&jws, &jwk, context); + + /* reuse the rsa private key from the JWE Appendix 2 test above */ + + if (lws_jwk_import(&jwk, NULL, NULL, jwk_txt, jwk_len) < 0) { + lwsl_notice("%s: Failed to decode JWK test key\n", __func__); + goto bail; + } + + /* + * dup the plaintext into the ciphertext element, it will be + * encrypted in-place to a ciphertext of the same length + */ + + if (lws_jws_dup_element(&jws.map, LJWE_CTXT, + lws_concat_temp(temp, temp_len), &temp_len, + ra_ptext_1024, sizeof(ra_ptext_1024), 0)) { + lwsl_notice("%s: Not enough temp space for ptext\n", __func__); + goto bail; + } + + /* copy the cek, since it will be replaced by the encrypted key */ + + if (lws_jws_dup_element(&jws.map, LJWE_EKEY, + lws_concat_temp(temp, temp_len), &temp_len, + r256a192_cek, sizeof(r256a192_cek), + LWS_JWE_LIMIT_KEY_ELEMENT_BYTES)) { + lwsl_err("Problem getting random\n"); + goto bail1; + } + + jws.map.buf[LJWE_JOSE] = rsa256a192_jose; + jws.map.len[LJWE_JOSE] = strlen(rsa256a192_jose); + + n = lws_jwe_parse_jose(&jose, jws.map.buf[LJWE_JOSE], + jws.map.len[LJWE_JOSE], + lws_concat_temp(temp, temp_len), &temp_len); + if (n < 0) { + lwsl_err("%s: JOSE parse failed\n", __func__); + + goto bail1; + } + + n = lws_jwe_encrypt(&jose, &jws, lws_concat_temp(temp, temp_len), + &temp_len); + if (n < 0) { + lwsl_err("%s: lws_jwe_encrypt failed\n", __func__); + goto bail1; + } + + n = lws_jwe_write_compact(&jose, &jws, compact, sizeof(compact)); + if (n < 0) { + lwsl_err("%s: lws_jwe_write_compact failed: %d\n", __func__, n); + goto bail1; + } + + // puts(compact); + + /* now we created the encrypted version, see if we can decrypt it */ + + n = lws_jwe_auth_and_decrypt(&dec_jose, &jws); + if (n < 0) { + lwsl_err("%s: lws_jwe_auth_and_decrypt failed\n", + __func__); + goto bail1; + } + + /* allowing for trailing padding, confirm the plaintext */ + if (jws.map.len[LJWE_CTXT] < sizeof(ra_ptext_1024) || + lws_timingsafe_bcmp(jws.map.buf[LJWE_CTXT], ra_ptext_1024, + sizeof(ra_ptext_1024))) { + lwsl_err("%s: plaintext AES decrypt wrong\n", __func__); + lwsl_hexdump_notice(ra_ptext_1024, sizeof(ra_ptext_1024)); + lwsl_hexdump_notice(jws.map.buf[LJWE_CTXT], + jws.map.len[LJWE_CTXT]); + goto bail1; + } + + ret = 0; + +bail1: + lws_jwk_destroy(&jwk); +bail: + lws_jws_destroy(&jws); + lws_jose_destroy(&dec_jose); + lws_jose_destroy(&jose); + if (ret) + lwsl_err("%s: selftest failed +++++++++++++++++++\n", __func__); + else + lwsl_notice("%s: selftest OK\n", __func__); + + return ret; +} + + +static const char *rsa256a256_jose = + "{ \"alg\":\"RSA1_5\",\"enc\":\"A256CBC-HS512\"}"; + +static const uint8_t r256a256_cek[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f +} +; + +static int +test_jwe_r256a256_ptext(struct lws_context *context, char *jwk_txt, int jwk_len) +{ + struct lws_jose jose, dec_jose; + struct lws_jws jws; + struct lws_jwk jwk; + char temp[4096], compact[4096]; + int n, ret = -1, temp_len = sizeof(temp); + + lws_jose_init(&jose); + lws_jose_init(&dec_jose); + lws_jws_init(&jws, &jwk, context); + + /* reuse the rsa private key from the JWE Appendix 2 test above */ + + if (lws_jwk_import(&jwk, NULL, NULL, jwk_txt, jwk_len) < 0) { + lwsl_notice("%s: Failed to decode JWK test key\n", __func__); + goto bail; + } + + /* + * dup the plaintext into the ciphertext element, it will be + * encrypted in-place to a ciphertext of the same length + */ + + if (lws_jws_dup_element(&jws.map, LJWE_CTXT, + lws_concat_temp(temp, temp_len), &temp_len, + ra_ptext_1024, sizeof(ra_ptext_1024), 0)) { + lwsl_notice("%s: Not enough temp space for ptext\n", __func__); + goto bail; + } + + /* copy the cek, since it will be replaced by the encrypted key */ + + if (lws_jws_dup_element(&jws.map, LJWE_EKEY, + lws_concat_temp(temp, temp_len), &temp_len, + r256a256_cek, sizeof(r256a256_cek), + LWS_JWE_LIMIT_KEY_ELEMENT_BYTES)) { + lwsl_err("Problem getting random\n"); + goto bail1; + } + + jws.map.buf[LJWE_JOSE] = rsa256a256_jose; + jws.map.len[LJWE_JOSE] = strlen(rsa256a256_jose); + + n = lws_jwe_parse_jose(&jose, rsa256a256_jose, strlen(rsa256a256_jose), + lws_concat_temp(temp, temp_len), &temp_len); + if (n < 0) { + lwsl_err("%s: JOSE parse failed\n", __func__); + + goto bail1; + } + + n = lws_jwe_encrypt(&jose, &jws, lws_concat_temp(temp, temp_len), + &temp_len); + if (n < 0) { + lwsl_err("%s: lws_jwe_encrypt failed\n", __func__); + goto bail1; + } + + n = lws_jwe_write_compact(&jose, &jws, compact, sizeof(compact)); + if (n < 0) { + lwsl_err("%s: lws_jwe_write_compact failed: %d\n", __func__, n); + goto bail1; + } + + // puts(compact); + + /* now we created the encrypted version, see if we can decrypt it */ + + n = lws_jwe_auth_and_decrypt(&dec_jose, &jws); + if (n < 0) { + lwsl_err("%s: lws_jwe_auth_and_decrypt failed\n", + __func__); + goto bail1; + } + + /* allowing for trailing padding, confirm the plaintext */ + if (jws.map.len[LJWE_CTXT] < sizeof(ra_ptext_1024) || + lws_timingsafe_bcmp(jws.map.buf[LJWE_CTXT], ra_ptext_1024, + sizeof(ra_ptext_1024))) { + lwsl_err("%s: plaintext AES decrypt wrong\n", __func__); + lwsl_hexdump_notice(ra_ptext_1024, sizeof(ra_ptext_1024)); + lwsl_hexdump_notice(jws.map.buf[LJWE_CTXT], + jws.map.len[LJWE_CTXT]); + goto bail1; + } + + ret = 0; + +bail1: + lws_jwk_destroy(&jwk); +bail: + lws_jws_destroy(&jws); + lws_jose_destroy(&dec_jose); + lws_jose_destroy(&jose); + if (ret) + lwsl_err("%s: selftest failed +++++++++++++++++++\n", __func__); + else + lwsl_notice("%s: selftest OK\n", __func__); + + return ret; +} + +/* produced by running the minimal example `lws-crypto-jwk -t RSA -b 2048 -c` */ + +static const char *rsa_key_2048 = + "{" + "\"e\":\"AQAB\"," + "\"kty\":\"RSA\"," + "\"n\":\"lBJdvUq-9_8hlcduIWuBjRb0tGzzAvS4foqoNCO7g-rOXMdeAcmq" + "aSzWTbkaGIc3L1I4-Q3TOZtxn2UhuDlShZRIhM6JCQuUVNVAF3TD7oXxHtZ" + "LJ7y_BqCUlrAmW31lu-nVmhY2G3xW26yXWUsDbCxz0hfLbVnXRSvVKLzYWm" + "_yyrFyEWfxB8peDocvKGh879z_aPCKE3PDOEl2AsgzYfpnWCLytkgnrTeL6" + "qY8HXxvvV-Jw-XMaRiwH0VldpIjs4DaoN35Kj1Ex7QOZznTkbYtMIqse8bR" + "LoR8Irkxbc5ncUAuX1KSV6lpPtelsA3RtEjJ4NHV-5eEABiYh8_CFQ\"," + "\"d\":\"DDpguQ9RVQFMoJC5z2hlkvq91kvsXPv2Y9Dcki256xYlg55H7Pre" + "p__hahrABR2Jg6QVJhArt5ABjUnDQ_JL69HH6VvLD6RVVBTQ-FRBZ_3HYKY" + "Oynx5BA7tJm1BRatF5FkBCvq27i8nAc4vfjAb22o9CFvEW3FLaKAgOCncQ3" + "Tnbz9CddH89n7DXw4kBFI8q5ugF_aRIg5-i42W_hQinLaBhZ_zhAuE-nvlt" + "ZnhDal8cX3T60lNoUrDOlirqEOXKO3gXCHpm3csZ6nabHYD1UCyHOmi2RsR" + "pzjaiqjXdPbwPzQoh2DcYpavNrf1mtHiqTwLZDTJIRHWHufJzHf-sw\"," + "\"p\":\"ySeC3FtvzduDEL-FX4JqbRN06PdBhUmosCkymmbBjriuLNpkGkG-" + "1ex7r-M8neUBZbctmDdih6cpLZ8hjZv3eEDZ4b5Z2LqZnja4QvVoWLUs4Fb" + "NN_PxJCR5H28uUfT6ThxqT0Nb2enb8Dyp0Qxvd7eJUeYz6jOt7pEK-ErTB4" + "M\"," + "\"q\":\"vHG2Pd6QUH7vFZjJtXwmlVnrz5tdJvUPQvz7ggeM69cqhf4vLajz" + "sqP9GhJr7bEkp6vKVdZGmfEdiFRD8cssIZq651oAO5Wr7zZd2mR_hG9jZx7" + "8Davfuxr4SZNN-bmoxO6dbDi-X2c7fvMI2YeJwL4groNKyiosdUYILTrYRI" + "c\"," + "\"dp\":\"h5Gqf2rcokgEQGBjuigCJDtNuskRjoxDNV6-rRL99nt_X9lcR9n" + "xjOnRvowOyXeTBoN7JjCFpllBxm6ORYtNMO28KomIsimo6NmGPBJ7XfXVJe" + "k6bDBrX-l4_HeJJ1FM9SHvgDYsjGQxh-rKpIqWAYBf-yOD758e5T85vndnX" + "JM\"," + "\"dq\":\"K9LiB-dfdmjenw4mMp-JtYfw8Bn4gtvQzcpZjzbETgB-8iRXwm2" + "dJvk-HjcUhHWCyb-I0YeAacKKFK9MEconHDWIq87haPn4vyvMjcJ7aUgiPN" + "QW1_MVl8TA4xNvudi0Z__5-jYEB9nRG0fX0gbUQU-19_-uf-9o4WkE88fQj" + "bc\"," + "\"qi\":\"LEkTRqmomn9UiASeRfAKw-Z5q7cye9CSL4luSexFvA3Du7Oin-s" + "L9a7F3nJN4CuYzhtNMxQ0hM7k6ExzhDhXDlNRHxnNEDt81-CFRV98v7GVWV" + "SH1KnaKf9wgegxSSm-x536ki2SI8EN4k4qkqRF0iLVHZK7CgnWMbtt6tnpp" + "3k\"" + "}"; +/* produced by running the minimal example `lws-crypto-jwk -t RSA -b 4096 -c` */ + +static const char *rsa_key_4096 = + "{" + "\"e\":\"AQAB\"," + "\"kty\":\"RSA\"," + "\"n\":\"uiLBz1SUgd4eQ0okg6tlPdk9QUhTsqXmiJXygWVFgzT45E5_Rfkq" + "vZ2fwAqQ8DvxkDTUWiKpeXMpPRNWG5GxuBuq9n7xdA1vn1eQi8LoekB28dg" + "3MwMfozVSKCzyxG1f81xPE5x3EMVhCcx6hshhlMEHkzNNhE07d-oRO87ZC0" + "z_5L3Vh03uJBXaDKVlsgHAazoHLhn6G4odqv-ro54T6Nx1eEtyTnMmFY5ND" + "V4rN0SjQvSefbZZtsrtby8Z0JmeyvynmDwOINj7FpmPmpFLoWGXntc2yxPP" + "8SHnqfT9ESh94fxCMxRhDNohgpegRHyiYwj3M5ZYY6reCZYfOQONSWmc8yp" + "NBMJqj4LuJ2bTMGAFS17ZP4ZZWm5RP9ax100Dgk0yxP1UrybG5dCfJRQvHC" + "ncxG_aL6cSQu2o4fXqlJsNHxk3FjHtV_CMZ3tqvGTvwrs4yxvKwKv6r3fRh" + "KL01bGOePzp9THkHW2-lzVj6kUwnxBdHGZE6fcAnczOdp8ZIEdV1w6ThimC" + "m3Bw_TIyl3tkuxRWXpc_d6Q4iiSVKGKCvUvfAlESpTA4tIhQkij-T9FEoj2" + "WE2H1D35AKmjcfLCh6yszu8cmDNedn862pwnawE2RvRFAyuI113fLQeCbCz" + "tQ1JHuD8cnQt0hpGzReTa5UJ8OEOGIlyXNdWZyTpk\"," + "\"d\":\"G2ZW582AT-6xvz-IiP5fuJ9EMloygeuEeEo0aMJO3X3cfoUknJkN" + "ZtyvYa5cgBSe3la8hKkyD9_5K9WvGP9VLTAbdk4g_m-k5QyXiU9PeAGJ0Nd" + "-Zqq4y0Zj2eil8u7Tz0fhFxay-zvG6VGZnsIcBTD2C7_jUwyoaqJA17A_CH" + "gU-ifMqS56VgMGdlKZmf7Cg7ZGzM1DoS6vZ9bbfgoczaw4OZVHlg9Cxa0NI" + "CDi1S-sJcTLGN_RLISKN5H0J54ZfzF6fUEn5kNykLTZrAvj2XV7g4UUOogn" + "1cvjJYRcBVzTzQKcfxbqo2DvymDGFZbQM6pj80rYJ5HFPh2EapjggPN8hXp" + "NlTNDEvC84QFv0lo2E-0nVWQqcyHtXd431O1JH2h5X822zKjXxkaztQSCj9" + "YP7AdAeoxIaWOa3aO1vcwURH2WWaNV-_KXVkPJNzfo9-bGYwblMw_RIqIkN" + "BDayTb8rBuQHTCE_tSEHgoSnkityGpr8j_vgA-Fa-SqmdqUlbklVpwA_Mq_" + "UH7RCaqe91dWxRhS_7c85tFMRFCKOcaRXkwxEpP2LD1AYe8yvVQlr0Se8_d" + "RefuQcC-BECwMW-TCgR3VxAuL7ExNTYe4bhBD8WYXsHP7wDXWX2Q4v7IRzj" + "cfVIdpTNYuWEd69PvXBCuy75hmDniSmS3Xps3ItGU\"," + "\"p\":\"961BtLSIZkHO7Vu1KfaA3urcwGpISKJiTSB5Nh6npxJr9mSjzv_f" + "e8VoxCX6CWGY0SEeQNUQ6ceTnAAxkSHtZJQGed598jBtxIexAWEE7oc9s9d" + "b0cWu4QWIVZYXrcOTEWmK1kWN4PXmnnQknrWQF49adn81BaOXqoL-tahe7f" + "faXzXe0RXuohK543ZKbuuHQ2TxqFG7CZpXiH_qn1Syao32u0V3iDFpmmCUV" + "h9O2JCzfo8sAosTrnQwC0pXz3Nvr_9Cnk6bMluJoMrwB1Ywg_DPQ1WvpYHO" + "URezEOqVC8Y3zrko199TMX2COKGNFgutVpnzxs2_h0PyINUmwrY4zQ\"," + "\"q\":\"wGQRaxy_gBafbrVJy4f32O0a2FQHzmS--WgHhoteDoF6ZAajLcV0" + "GEvb-AVmFER1Wii62BFaFJOYQIegELvnBFFzD6oHJRX7bM4m36G8J_TC1o9" + "T1IFnxOpaoFDf4JWf2k7DCXClGg_zueyOD8fj8F6j2nqpOfytuLmikHcWMc" + "dGTHTCRtQmvOk3pm0uk2qR0cQb5L3Ocv45tCKr55tMc6Zx3DKkMt1kmUwd2" + "HFfk_0WM6R7q4LNGIjwl8dwiERppLKA8xao9i3jOOdFEfAD-Zqv8H-32cyH" + "Mg6Guo4tPNAYSzcsz8nbEYPtKVVm-PDuM2cx0iaKnS8BIK2XTbzc_Q\"," + "\"dp\":\"ZXLWIwp_hEMYWyjhP9r0VlqlKTtfeEDrOuQ-Qei0iz6EclwurK8" + "p_yyRCSb1D7qmOaLzHWMollllINUDeIsJDdWEAY8cz4L-sy1RV1tCBeHnaC" + "6iMX5jb1Aw072y3T3qk4tDjxjWUHroh6bTCR8dckkJqNfaBAFKMlGNuyLIH" + "3kSPUV3ivUM1d4NvhnJyz02HmjOgz9W-Uv65rJei_zJR9P2aCbAG00CEHXW" + "zJ_uT86VdxV11WTaHu8Abt94sER8Tv6jbuyLrUjJSs9VGew32xNcEhya4ZQ" + "VyimG8zri6fu7CDXXgPS8wtzB5ihl_c2ypnJQ4_GKrgEqwEAOrFqvUQ\"," + "\"dq\":\"uzlmngcm8R6S3qi7fL7_2fG7uyPjSN5P3uR21l8QFCu6kFbJO8S" + "4muBP20hds4F_dlLGqXgRYo7TjpCtmztQsKoWv_ql41hGCfeAawa41WViqm" + "xmlxmrgzzRHsw1YhgZrNgTAz_E290EQT3Mbd0HnCZtbDMMNisIYAj_A3lwd" + "tbHOaYyXb0dSZ_nkSUVO05tQ2aGAo8Xtl5ih0NqaQR_XNhwW2pI0lsTB__D" + "15tU-O5FSdJaq2ip8KNrBzmF8IYrDKTNykKWAKRdSEX_uFoLdD8t0mxn3SM" + "luffa8vdjXJfh3GiASmHUt3HcPOooQEAufoWBPVJWeGqCvWtRH8yYfQ\"," + "\"qi\":\"h-e9es5J49OUF48gSXUI8cynZ8ydv5cThXc1deV3mil_7_7Hg8E" + "jV3gAErO4l-irHJplFmHFZvU1ud4zs1gtBt5TA-EeeepYOHMSssWDvDK3WI" + "zsM6C3vcNTSkT-ihaSFmPWHCVwJ1R3auWfeI2In3at0jd4t-OK-cCcGZXb7" + "90-EnyyDcdFTU9WfwVSOJffRGjoUYX8DexavClv7CBzPhpdUzGoeyarNaG4" + "z9MI8Q8txHyHgc_D70lZUum1cj0bZwgEj6yDzOPzSgUmICFJiLDDj93oPaI" + "v-5CQ_Ckju7icexc_kuuYTKBOLTj_vfaURnV3KCHul2UljUYOxkfeNQ\"" + "}"; + +static const char *rsa_key_4096_no_optional = + "{" + "\"e\":\"AQAB\"," + "\"kty\":\"RSA\"," + "\"n\":\"uiLBz1SUgd4eQ0okg6tlPdk9QUhTsqXmiJXygWVFgzT45E5_Rfkq" + "vZ2fwAqQ8DvxkDTUWiKpeXMpPRNWG5GxuBuq9n7xdA1vn1eQi8LoekB28dg" + "3MwMfozVSKCzyxG1f81xPE5x3EMVhCcx6hshhlMEHkzNNhE07d-oRO87ZC0" + "z_5L3Vh03uJBXaDKVlsgHAazoHLhn6G4odqv-ro54T6Nx1eEtyTnMmFY5ND" + "V4rN0SjQvSefbZZtsrtby8Z0JmeyvynmDwOINj7FpmPmpFLoWGXntc2yxPP" + "8SHnqfT9ESh94fxCMxRhDNohgpegRHyiYwj3M5ZYY6reCZYfOQONSWmc8yp" + "NBMJqj4LuJ2bTMGAFS17ZP4ZZWm5RP9ax100Dgk0yxP1UrybG5dCfJRQvHC" + "ncxG_aL6cSQu2o4fXqlJsNHxk3FjHtV_CMZ3tqvGTvwrs4yxvKwKv6r3fRh" + "KL01bGOePzp9THkHW2-lzVj6kUwnxBdHGZE6fcAnczOdp8ZIEdV1w6ThimC" + "m3Bw_TIyl3tkuxRWXpc_d6Q4iiSVKGKCvUvfAlESpTA4tIhQkij-T9FEoj2" + "WE2H1D35AKmjcfLCh6yszu8cmDNedn862pwnawE2RvRFAyuI113fLQeCbCz" + "tQ1JHuD8cnQt0hpGzReTa5UJ8OEOGIlyXNdWZyTpk\"," + "\"d\":\"G2ZW582AT-6xvz-IiP5fuJ9EMloygeuEeEo0aMJO3X3cfoUknJkN" + "ZtyvYa5cgBSe3la8hKkyD9_5K9WvGP9VLTAbdk4g_m-k5QyXiU9PeAGJ0Nd" + "-Zqq4y0Zj2eil8u7Tz0fhFxay-zvG6VGZnsIcBTD2C7_jUwyoaqJA17A_CH" + "gU-ifMqS56VgMGdlKZmf7Cg7ZGzM1DoS6vZ9bbfgoczaw4OZVHlg9Cxa0NI" + "CDi1S-sJcTLGN_RLISKN5H0J54ZfzF6fUEn5kNykLTZrAvj2XV7g4UUOogn" + "1cvjJYRcBVzTzQKcfxbqo2DvymDGFZbQM6pj80rYJ5HFPh2EapjggPN8hXp" + "NlTNDEvC84QFv0lo2E-0nVWQqcyHtXd431O1JH2h5X822zKjXxkaztQSCj9" + "YP7AdAeoxIaWOa3aO1vcwURH2WWaNV-_KXVkPJNzfo9-bGYwblMw_RIqIkN" + "BDayTb8rBuQHTCE_tSEHgoSnkityGpr8j_vgA-Fa-SqmdqUlbklVpwA_Mq_" + "UH7RCaqe91dWxRhS_7c85tFMRFCKOcaRXkwxEpP2LD1AYe8yvVQlr0Se8_d" + "RefuQcC-BECwMW-TCgR3VxAuL7ExNTYe4bhBD8WYXsHP7wDXWX2Q4v7IRzj" + "cfVIdpTNYuWEd69PvXBCuy75hmDniSmS3Xps3ItGU\"," + "\"p\":\"961BtLSIZkHO7Vu1KfaA3urcwGpISKJiTSB5Nh6npxJr9mSjzv_f" + "e8VoxCX6CWGY0SEeQNUQ6ceTnAAxkSHtZJQGed598jBtxIexAWEE7oc9s9d" + "b0cWu4QWIVZYXrcOTEWmK1kWN4PXmnnQknrWQF49adn81BaOXqoL-tahe7f" + "faXzXe0RXuohK543ZKbuuHQ2TxqFG7CZpXiH_qn1Syao32u0V3iDFpmmCUV" + "h9O2JCzfo8sAosTrnQwC0pXz3Nvr_9Cnk6bMluJoMrwB1Ywg_DPQ1WvpYHO" + "URezEOqVC8Y3zrko199TMX2COKGNFgutVpnzxs2_h0PyINUmwrY4zQ\"," + "\"q\":\"wGQRaxy_gBafbrVJy4f32O0a2FQHzmS--WgHhoteDoF6ZAajLcV0" + "GEvb-AVmFER1Wii62BFaFJOYQIegELvnBFFzD6oHJRX7bM4m36G8J_TC1o9" + "T1IFnxOpaoFDf4JWf2k7DCXClGg_zueyOD8fj8F6j2nqpOfytuLmikHcWMc" + "dGTHTCRtQmvOk3pm0uk2qR0cQb5L3Ocv45tCKr55tMc6Zx3DKkMt1kmUwd2" + "HFfk_0WM6R7q4LNGIjwl8dwiERppLKA8xao9i3jOOdFEfAD-Zqv8H-32cyH" + "Mg6Guo4tPNAYSzcsz8nbEYPtKVVm-PDuM2cx0iaKnS8BIK2XTbzc_Q\"" + "}"; + +/* This is a compact JWE containing the plaintext ra_ptext_1024 for the key + * lws_jwe_ex_a2_jwk_json... produced by test test above running on OpenSSL. + */ + +static char *jwe_compact_rsa_cbc_openssl = + "eyAiYWxnIjoiUlNBMV81IiwiZW5jIjoiQTEyOENCQy1IUzI1NiJ9" + "." + "mWXwMv4hxwgKbUAyMFAuHxiKjg62Z5owkFYLgxho5FNT3Hm5ZGiF8plS5W3NwUTmv8t6C" + "I0kV5cOOJXE_PXPaOptsie2aoQR-_Bs6gAFixa7aZNsnsMF4lMAiIy7VkrvP2qh0s04y2" + "2poOLfmS93tB9AyWdlnQ6Z-U1wzrM9kncqO9GpPol9M4WnAss1ZtTE-9Tbc7dMHURHbZb" + "vHn2h625pBD8oD_s0osRav8YEw7jNeQjW_ch4pI6HRox-hf0dyLtk9yFCtBjxbCvysadW" + "SlZPJBj0HYv0BVqCK0fETi7URx4MCJ3zgCJnpAuQo2yq1yQzXwOYcFoLIvY0jIm44A" + "." + "WINMABhU_GQKJarmmTP_-g" + "." + "V9kHAh9ajE558EPj_zX6p_C903MevMPJLcMU4MWhfhwe1cFW_0io-LvZfcF_Xj7aNoIZd" + "vPXJ0On_jHPFsnwe4dus6kuh8RrSKFFV0sGIv-FFXrKB99FFRY_8BTPsYFrcqt_8EV2Af" + "p7toaVOO15WXOEH6Ym81a3aOWCVGdj_akMN46Qx_JrQaql-Xs_fL2HdpaEWHHTV2ac9aY" + "ah7o0Ojl9UnzkHyXieRgrjXymvCcT0te3D4OQJhrv7TzH_hfKu621O-Frmkr-NvQGSNcl" + "fVgRkte2ks34j5HPqEbJQWWKG3IDfkPRvWmDZzEXW_JTrK_1r1FM-aYtY79tLnir8Zw7I" + "WCczD-XmtlOJNYA2Ss5dbjoJDtevbqaZWVl-sDSwO1xdf-DUfiemep7S7IFoFAdl0vXLT" + "YtuNBxuFw-cP2Kwi8RyF__uENo4vD003cI4htqSYIYXeyAVqWIkmsP1BFpT7MGixfvhAu" + "VCj_ToJmowGY3bOHiMuzyT9M7wtCCiCySEBARVU-EdQBXj8X-quSj-0OnBtxXChUS4QXw" + "q2pNn3UKSMsxqvHR25HQq_6U2AbvNHxKhup3luzn0T27uy0l3XeWSz_48SwJZKRnbYPtC" + "n5Jd5mRdr5GxihpNwupaO4BWnHZo_fHUTI9-Z18lpj_4QB-c3dzDL15xFN4HEZ5lv2iO5" + "zMiRI_NlVVDdA9lqGpn4IyO44osHQieBraUjWF8X5cSXDoqktXDVymAdrxe0fYZQca6Bq" + "CsBqFTYae4CG01SpG46ysfwAXmsTEKPzj7uiOguFCRB4hClTd-Q8R2axj9JNT1jU_Vb7U" + "GKFBGeDJt5PDXJyvW5rHyiQDewykf0Lpvdp39yITT8qARmJl2SwCrDCPADZ4TwwobT42B" + "J_Cq5IKgEOeuS3S7NOdOfXxmAcNfN0yujKbmfiOxnXhwnepQ-TnpgTV0nv8snBRITN7mS" + "EgflqQlKAZus_0mDbHmBmw1nY-0q4qMWI03IEwMC57-p4JLshnWgIAupnFCGp9nyi4E_s" + "GVyQlGCxzC5VSH1Hba3rvbulQGxx_kGk0j56NGhGsQEzqvSuI4xgIsGMPo1Ii7xUh68dd" + "BzJRzaov9oDTgnWM5-hoEQQoazW7hDKAFPYccC6zqX0fnI7vBIIBZsjUsol6-5bdujpb4" + "l3LRGCjULXlSPbnNGzyk5R-mIwQC8aM9wcIiZZdcdHdr4meMNr3HmpG_B5xtBmENAJAvU" + "K3DO6pro2xhypuNKYtOAdH0Xyl8QBPIJ0EFVH6_1V-H_gHs2MLMIqGfUmFCuRev60APcw" + "Pbf-GZxLeXLutPq2DOl1HD0XLNtYL1dB1aw2j4L8OJREOC_N-KpIH3g" + "." + "n4QRlTzW2urRnNiJlwQkZw" +; + + +static int +test_jwe_r256a128_jwe_openssl(struct lws_context *context) +{ + struct lws_jose jose; + struct lws_jws jws; + struct lws_jwk jwk; + char temp[2048]; + int n, ret = -1, temp_len = sizeof(temp); + + lws_jose_init(&jose); + lws_jws_init(&jws, &jwk, context); + + if (lws_jwk_import(&jwk, NULL, NULL, (char *)lws_jwe_ex_a2_jwk_json, + strlen((char *)lws_jwe_ex_a2_jwk_json)) < 0) { + lwsl_notice("%s: Failed to decode JWK test key\n", __func__); + goto bail; + } + + /* converts a compact serialization to jws b64 + decoded maps */ + if (lws_jws_compact_decode((const char *)jwe_compact_rsa_cbc_openssl, + strlen((char *)jwe_compact_rsa_cbc_openssl), + &jws.map, &jws.map_b64, + temp, &temp_len) != 5) { + lwsl_err("%s: lws_jws_compact_decode failed\n", __func__); + goto bail; + } + + n = lws_jwe_auth_and_decrypt(&jose, &jws); + lws_jwk_destroy(&jwk); + if (n < 0) { + lwsl_err("%s: lws_jwe_auth_and_decrypt failed\n", + __func__); + goto bail; + } + + /* allowing for trailing padding, confirm the plaintext */ + if (jws.map.len[LJWE_CTXT] < sizeof(ra_ptext_1024) || + lws_timingsafe_bcmp(jws.map.buf[LJWE_CTXT], ra_ptext_1024, + sizeof(ra_ptext_1024))) { + lwsl_err("%s: plaintext RSA/AES decrypt wrong\n", __func__); + lwsl_hexdump_notice(ra_ptext_1024, sizeof(ra_ptext_1024)); + lwsl_hexdump_notice(jws.map.buf[LJWE_CTXT], + jws.map.len[LJWE_CTXT]); + goto bail; + } + + ret = 0; + +bail: + lws_jws_destroy(&jws); + lws_jose_destroy(&jose); + if (ret) + lwsl_err("%s: selftest failed +++++++++++++++++++\n", __func__); + else + lwsl_notice("%s: selftest OK\n", __func__); + + return ret; +} + + +/* This is a compact JWE containing the plaintext ra_ptext_1024 for the key + * lws_jwe_ex_a2_jwk_json... produced by test test above running on mbedTLS. + */ + +static char +*jwe_compact_rsa_cbc_mbedtls = + "eyAiYWxnIjoiUlNBMV81IiwiZW5jIjoiQTEyOENCQy1IUzI1NiJ9.oBqKJ06UJs2oryPLWZKyI8743GC0geUt_xaKLMaPtApp__swG2w0IhNtmkIBKA9LeeGyiCWKpGGzOlQUR5YSxrT99PnincHXw_pkCprOvi4j3oxThJ2pFRx-CBc9ZgPJ3Kje1QifOueT3vQt_65iiyXmqyc5PDxzuV0L_KtrA_jEsm2m1JVBMOX--qzXjYyqx_dc87d43TXY_4kuTmAtqVpQe7ixKJlUViPVSzuASyeLEUTIaNlALuEWial1wP-ICF37OQzOcZRH3OVZObrcZi1aWkDOLxF4qO4I_GtpuAgZT732a7gnobR-T2oyBpimcqCVEk88Wa7cYyBXZvAOUA.fNLEFh1mjdlyc3WKw0I2Kg.e8X-11K9yXK0KkK-8ikplEWFViruqduaKPDOA7x6lKpBk8l3RFX1aqC4s0WVc1eN0qd-fB__EoO_AIG1xsfw1ie2IDWV0p18ZaRkQRN9Th5UU-W9C9XyPFQUxcl7ShKRE-yKJU-VdZDk6L2-07FH3s-voVKx0oqLIYqkkXp9a2jvnzrZ0Psujs4PSCHOZEgcS8PNdMmdsjDHLsb0NDMifOSlXk2Mp6V2SizXRIPJtOkVJGKwuBc7FbdO02GnzzVXldiLC7GI0zoRsnSJndF8yc3pMrMQhoVRktkBClAcIujD_OxJwHG-i3OJqUg1uVfci86RoQrnULoygvB7apX_WMxF7eXXJdXbG8sPLLCf0SW4sgvuSclOHL2UXzGi6Tp_l1XjxFQTzVEfUaj7i0gD2wM74Ru79RX8yO0m-5qOOwkySU1lEXqbLTuxjJXD9WLcTQQmF0Nm5myTUyNOl7xKpeDpnNt5A0L8o6SW6iJ3DwZEzhMxk3JWQOYtQP1J2sgwAKEDM6SkGzTy9QXpCEoraKp2UEzunux9S6-roYpzgEFT2RZrq3Hg_JyequTtrcNaoiEKd5szJvE6pUc25WEjDzgg79v_n40gQm688mO62kiVBThVmc88u2JVlNpzVQFUfKt-bu2Xxiqn5lRfEMK93EEPZRd8n12vBq5aJKvvEpPN1AC4HaMepf78Ob0GNTYGR-70zSS0ErecCeIgUJ1CttE2Nn0qEOfbQcO48SjeIltecl9DRzeLT3tPN3Z4BqbzSX8kKU5LStUX5YC-obM_0Ss7swXJM19I1O-QH8VbHZl-9TADR6BLzmrsJQ9_BL_uTB6uPdLhYfqWw6VUf0eMLaqvsY92vV5-JVQqyv7s70FNLT1-8P94k79ZGiLvNdDNZgGsmRQOwA2Vk6snHI0oUYGj7NeEK4O64ZfNRZJgPfWnxtQ-LIhSYCJvxFGL7ZMoA_ijKl9_v_bRqd03_7o8YQisw2luDYqLa87Dh9u9tacOoraGAzcEBIAh-BOcnIrQEt5KoSbly5xNAkfqj7QDvL0vPHArZ5E3Gb_k3VbKjsqCzvisNMEjm887Z-Dc6tW4Y2OceYf-rfUDvJ3EXZ66CWSQ7yKhPVcP1RRtNUFEqLoIAkA4aEAAS2ZPKVHIJQwyMzbbNFAuvY_7piNYprAI5lySFcA1cz_hKl6s9xmqbAkH2XGZZduw5Nv-aY_LMXujjhmblqE2Ocej91xTdgMe74Ftr1b3y9FvPPVSqNjpTSfujCi5L57LOpjT78do8eSrDz6coG0zeRUybjWeTszoiYbif_NlyAcMScO5OMZHNkre6L8u-AVeYSKTGsdpK7em_iLN8cGSEjZABNAr_A9Lfg.6Qb_Qf-ktX0DRHWUHAJxDQ" +; + +static int +test_jwe_r256a128_jwe_mbedtls(struct lws_context *context) +{ + struct lws_jose jose; + struct lws_jws jws; + struct lws_jwk jwk; + char temp[2048]; + int n, ret = -1, temp_len = sizeof(temp); + + lws_jose_init(&jose); + lws_jws_init(&jws, &jwk, context); + + if (lws_jwk_import(&jwk, NULL, NULL, (char *)lws_jwe_ex_a2_jwk_json, + strlen((char *)lws_jwe_ex_a2_jwk_json)) < 0) { + lwsl_notice("%s: Failed to decode JWK test key\n", __func__); + goto bail; + } + + /* converts a compact serialization to jws b64 + decoded maps */ + if (lws_jws_compact_decode((const char *)jwe_compact_rsa_cbc_mbedtls, + strlen((char *)jwe_compact_rsa_cbc_mbedtls), + &jws.map, &jws.map_b64, temp, &temp_len) != 5) { + lwsl_err("%s: lws_jws_compact_decode failed\n", __func__); + goto bail; + } + + n = lws_jwe_auth_and_decrypt(&jose, &jws); + lws_jwk_destroy(&jwk); + if (n < 0) { + lwsl_err("%s: lws_jwe_auth_and_decrypt failed\n", + __func__); + goto bail; + } + + /* allowing for trailing padding, confirm the plaintext */ + if (jws.map.len[LJWE_CTXT] < sizeof(ra_ptext_1024) || + lws_timingsafe_bcmp(jws.map.buf[LJWE_CTXT], ra_ptext_1024, + sizeof(ra_ptext_1024))) { + lwsl_err("%s: plaintext RSA/AES decrypt wrong\n", __func__); + lwsl_hexdump_notice(ra_ptext_1024, sizeof(ra_ptext_1024)); + lwsl_hexdump_notice(jws.map.buf[LJWE_CTXT], + jws.map.len[LJWE_CTXT]); + goto bail; + } + + ret = 0; + +bail: + lws_jws_destroy(&jws); + lws_jose_destroy(&jose); + if (ret) + lwsl_err("%s: selftest failed +++++++++++++++++++\n", __func__); + else + lwsl_notice("%s: selftest OK\n", __func__); + + return ret; +} + + + +/* A.3. Example JWE Using AES Key Wrap and AES_128_CBC_HMAC_SHA_256 + * + * This example encrypts the plaintext "Live long and prosper." to the + * recipient using AES Key Wrap for key encryption and + * AES_128_CBC_HMAC_SHA_256 for content encryption. + */ + +/* "Live long and prosper." */ +static uint8_t + +ex_a3_ptext[] = { 76, 105, 118, 101, 32, 108, 111, 110, 103, 32, 97, 110, 100, 32, 112, 114, 111, 115, 112, 101, 114, 46 }, -#endif -*lws_jwe_ex_a2_jose_hdr = (uint8_t *) - "{\"alg\":\"RSA1_5\",\"enc\":\"A128CBC-HS256\"}", -*lws_jwe_ex_a2_jose_hdr_b64utf8 = (unsigned char *) - "eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0", +*ex_a3_compact = (uint8_t *) + "eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0" + "." + "6KB707dM9YTIgHtLvtgWQ8mKwboJW3of9locizkDTHzBC2IlrT1oOQ" + "." + "AxY8DCtDaGlsbGljb3RoZQ" + "." + "KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY" + "." + "U0m_YmjN04DJvceFICbCVQ", -lws_jwe_ex_a2_cek[] = { - 4, 211, 31, 197, 84, 157, 252, 254, - 11, 100, 157, 250, 63, 170, 106, 206, - 107, 124, 212, 45, 111, 107, 9, 219, - 200, 177, 0, 240, 143, 156, 44, 207 -}, - -*lws_jwe_ex_a2_jwk_json = (uint8_t *) -"{" - "\"kty\":\"RSA\"," - "\"n\":\"sXchDaQebHnPiGvyDOAT4saGEUetSyo9MKLOoWFsueri23bOdgWp4Dy1Wl" - "UzewbgBHod5pcM9H95GQRV3JDXboIRROSBigeC5yjU1hGzHHyXss8UDpre" - "cbAYxknTcQkhslANGRUZmdTOQ5qTRsLAt6BTYuyvVRdhS8exSZEy_c4gs_" - "7svlJJQ4H9_NxsiIoLwAEk7-Q3UXERGYw_75IDrGA84-lA_-Ct4eTlXHBI" - "Y2EaV7t7LjJaynVJCpkv4LKjTTAumiGUIuQhrNhZLuF_RJLqHpM2kgWFLU" - "7-VTdL1VbC2tejvcI2BlMkEpk1BzBZI0KQB0GaDWFLN-aEAw3vRw\"," - "\"e\":\"AQAB\"," - "\"d\":\"VFCWOqXr8nvZNyaaJLXdnNPXZKRaWCjkU5Q2egQQpTBMwhprMzWzpR8Sxq" - "1OPThh_J6MUD8Z35wky9b8eEO0pwNS8xlh1lOFRRBoNqDIKVOku0aZb-ry" - "nq8cxjDTLZQ6Fz7jSjR1Klop-YKaUHc9GsEofQqYruPhzSA-QgajZGPbE_" - "0ZaVDJHfyd7UUBUKunFMScbflYAAOYJqVIVwaYR5zWEEceUjNnTNo_CVSj" - "-VvXLO5VZfCUAVLgW4dpf1SrtZjSt34YLsRarSb127reG_DUwg9Ch-Kyvj" - "T1SkHgUWRVGcyly7uvVGRSDwsXypdrNinPA4jlhoNdizK2zF2CWQ\"," - "\"p\":\"9gY2w6I6S6L0juEKsbeDAwpd9WMfgqFoeA9vEyEUuk4kLwBKcoe1x4HG68" - "ik918hdDSE9vDQSccA3xXHOAFOPJ8R9EeIAbTi1VwBYnbTp87X-xcPWlEP" - "krdoUKW60tgs1aNd_Nnc9LEVVPMS390zbFxt8TN_biaBgelNgbC95sM\"," - "\"q\":\"uKlCKvKv_ZJMVcdIs5vVSU_6cPtYI1ljWytExV_skstvRSNi9r66jdd9-y" - "BhVfuG4shsp2j7rGnIio901RBeHo6TPKWVVykPu1iYhQXw1jIABfw-MVsN" - "-3bQ76WLdt2SDxsHs7q7zPyUyHXmps7ycZ5c72wGkUwNOjYelmkiNS0\"," - "\"dp\":\"w0kZbV63cVRvVX6yk3C8cMxo2qCM4Y8nsq1lmMSYhG4EcL6FWbX5h9yuv" - "ngs4iLEFk6eALoUS4vIWEwcL4txw9LsWH_zKI-hwoReoP77cOdSL4AVcra" - "Hawlkpyd2TWjE5evgbhWtOxnZee3cXJBkAi64Ik6jZxbvk-RR3pEhnCs\"," - "\"dq\":\"o_8V14SezckO6CNLKs_btPdFiO9_kC1DsuUTd2LAfIIVeMZ7jn1Gus_Ff" - "7B7IVx3p5KuBGOVF8L-qifLb6nQnLysgHDh132NDioZkhH7mI7hPG-PYE_" - "odApKdnqECHWw0J-F0JWnUd6D2B_1TvF9mXA2Qx-iGYn8OVV1Bsmp6qU\"," - "\"qi\":\"eNho5yRBEBxhGBtQRww9QirZsB66TrfFReG_CcteI1aCneT0ELGhYlRlC" - "tUkTRclIfuEPmNsNDPbLoLqqCVznFbvdB7x-Tl-m0l_eFTj2KiqwGqE9PZ" - "B9nNTwMVvH3VRRSLWACvPnSiwP8N5Usy-WRXS-V7TbpxIhvepTfE0NNo\"" -"}" - -#if 0 -, -lws_jwe_ex_a2_jwk_enc_key[] = { - 80, 104, 72, 58, 11, 130, 236, 139, - 132, 189, 255, 205, 61, 86, 151, 176, - 99, 40, 44, 233, 176, 189, 205, 70, - 202, 169, 72, 40, 226, 181, 156, 223, - 120, 156, 115, 232, 150, 209, 145, 133, - 104, 112, 237, 156, 116, 250, 65, 102, - 212, 210, 103, 240, 177, 61, 93, 40, - 71, 231, 223, 226, 240, 157, 15, 31, - 150, 89, 200, 215, 198, 203, 108, 70, - 117, 66, 212, 238, 193, 205, 23, 161, - 169, 218, 243, 203, 128, 214, 127, 253, - 215, 139, 43, 17, 135, 103, 179, 220, - 28, 2, 212, 206, 131, 158, 128, 66, - 62, 240, 78, 186, 141, 125, 132, 227, - 60, 137, 43, 31, 152, 199, 54, 72, - 34, 212, 115, 11, 152, 101, 70, 42, - 219, 233, 142, 66, 151, 250, 126, 146, - 141, 216, 190, 73, 50, 177, 146, 5, - 52, 247, 28, 197, 21, 59, 170, 247, - 181, 89, 131, 241, 169, 182, 246, 99, - 15, 36, 102, 166, 182, 172, 197, 136, - 230, 120, 60, 58, 219, 243, 149, 94, - 222, 150, 154, 194, 110, 227, 225, 112, - 39, 89, 233, 112, 207, 211, 241, 124, - 174, 69, 221, 179, 107, 196, 225, 127, - 167, 112, 226, 12, 242, 16, 24, 28, - 120, 182, 244, 213, 244, 153, 194, 162, - 69, 160, 244, 248, 63, 165, 141, 4, - 207, 249, 193, 79, 131, 0, 169, 233, - 127, 167, 101, 151, 125, 56, 112, 111, - 248, 29, 232, 90, 29, 147, 110, 169, - 146, 114, 165, 204, 71, 136, 41, 252 -} -, -*lws_jwe_ex_a2_jwk_enc_key_b64 = (uint8_t *) - "UGhIOguC7IuEvf_NPVaXsGMoLOmwvc1GyqlIKOK1nN94nHPoltGRhWhw7Zx0-kFm" - "1NJn8LE9XShH59_i8J0PH5ZZyNfGy2xGdULU7sHNF6Gp2vPLgNZ__deLKxGHZ7Pc" - "HALUzoOegEI-8E66jX2E4zyJKx-YxzZIItRzC5hlRirb6Y5Cl_p-ko3YvkkysZIF" - "NPccxRU7qve1WYPxqbb2Yw8kZqa2rMWI5ng8OtvzlV7elprCbuPhcCdZ6XDP0_F8" - "rkXds2vE4X-ncOIM8hAYHHi29NX0mcKiRaD0-D-ljQTP-cFPgwCp6X-nZZd9OHBv" - "-B3oWh2TbqmScqXMR4gp_A", - -lws_jwe_ex_a2_iv[] = { - 3, 22, 60, 12, 43, 67, 104, 105, - 108, 108, 105, 99, 111, 116, 104, 101 -}, - -*lws_jwe_ex_a2_iv_b64 = (uint8_t *) - "AxY8DCtDaGlsbGljb3RoZQ", - -lws_jwe_ex_a2_aad[] = { - 101, 121, 74, 104, 98, 71, 99, 105, - 79, 105, 74, 83, 85, 48, 69, 120, - 88, 122, 85, 105, 76, 67, 74, 108, - 98, 109, 77, 105, 79, 105, 74, 66, - 77, 84, 73, 52, 81, 48, 74, 68, - 76, 85, 104, 84, 77, 106, 85, 50, - 73, 110, 48 -}, - -lws_jwe_ex_a2_ciphertext[] = { - 40, 57, 83, 181, 119, 33, 133, 148, - 198, 185, 243, 24, 152, 230, 6, 75, - 129, 223, 127, 19, 210, 82, 183, 230, - 168, 33, 215, 104, 143, 112, 56, 102 -}, - -*lws_jwe_ex_a2_ciphertext_b64 = (uint8_t *) - "KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY", - -lws_jwe_ex_a2_authtag[] = { - 246, 17, 244, 190, 4, 95, 98, 3, - 231, 0, 115, 157, 242, 203, 100, 191 -}, - -*lws_jwe_ex_a2_authtag_b64 = (uint8_t *) - "9hH0vgRfYgPnAHOd8stkvw", - -*lws_jwe_ex_a2_aggregated = (uint8_t *) - "eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0." - "UGhIOguC7IuEvf_NPVaXsGMoLOmwvc1GyqlIKOK1nN94nHPoltGRhWhw7Zx0-kFm" - "1NJn8LE9XShH59_i8J0PH5ZZyNfGy2xGdULU7sHNF6Gp2vPLgNZ__deLKxGHZ7Pc" - "HALUzoOegEI-8E66jX2E4zyJKx-YxzZIItRzC5hlRirb6Y5Cl_p-ko3YvkkysZIF" - "NPccxRU7qve1WYPxqbb2Yw8kZqa2rMWI5ng8OtvzlV7elprCbuPhcCdZ6XDP0_F8" - "rkXds2vE4X-ncOIM8hAYHHi29NX0mcKiRaD0-D-ljQTP-cFPgwCp6X-nZZd9OHBv" - "-B3oWh2TbqmScqXMR4gp_A." - "AxY8DCtDaGlsbGljb3RoZQ." - "KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY." - "9hH0vgRfYgPnAHOd8stkvw" -#endif +*ex_a3_key = (uint8_t *) + "{\"kty\":\"oct\"," + "\"k\":\"GawgguFyGrWKav7AX4VKUg\"" + "}" ; -/* - * These are the inputs and outputs from the worked example in RFC7515 - * Appendix A.1. +static int +test_jwe_a3(struct lws_context *context) +{ + struct lws_jose jose; + struct lws_jws jws; + struct lws_jwk jwk; + char temp[2048]; + int n, ret = -1, temp_len = sizeof(temp); + + lws_jose_init(&jose); + lws_jws_init(&jws, &jwk, context); + + if (lws_jwk_import(&jwk, NULL, NULL, (char *)ex_a3_key, + strlen((char *)ex_a3_key)) < 0) { + lwsl_notice("%s: Failed to decode JWK test key\n", __func__); + goto bail; + } + + /* converts a compact serialization to jws b64 + decoded maps */ + if (lws_jws_compact_decode((const char *)ex_a3_compact, + strlen((char *)ex_a3_compact), + &jws.map, &jws.map_b64, temp, &temp_len) != 5) { + lwsl_err("%s: lws_jws_compact_decode failed\n", __func__); + goto bail; + } + + n = lws_jwe_auth_and_decrypt(&jose, &jws); + lws_jwk_destroy(&jwk); + if (n < 0) { + lwsl_err("%s: lws_jwe_auth_and_decrypt failed\n", + __func__); + goto bail; + } + + /* allowing for trailing padding, confirm the plaintext */ + if (jws.map.len[LJWE_CTXT] < sizeof(ex_a3_ptext) || + lws_timingsafe_bcmp(jws.map.buf[LJWE_CTXT], ex_a3_ptext, + sizeof(ex_a3_ptext))) { + lwsl_err("%s: plaintext AES decrypt wrong\n", __func__); + lwsl_hexdump_notice(ex_a3_ptext, sizeof(ex_a3_ptext)); + lwsl_hexdump_notice(jws.map.buf[LJWE_CTXT], + jws.map.len[LJWE_CTXT]); + goto bail; + } + + ret = 0; + +bail: + lws_jws_destroy(&jws); + lws_jose_destroy(&jose); + if (ret) + lwsl_err("%s: selftest failed +++++++++++++++++++\n", __func__); + else + lwsl_notice("%s: selftest OK\n", __func__); + + return ret; +} + +/* JWA B.2. Test Cases for AES_192_CBC_HMAC_SHA_384 * - * 1) has a fixed header + payload, and a fixed SHA256 HMAC key, and must give - * a fixed BASE64URL result. - * - * 2) has a fixed header + payload and is signed with a key given in JWK format + * Unfortunately JWA just gives this test case as hex literals, not + * inside a JWE. So we have to prepare the inputs "by hand". */ + +static uint8_t + +jwa_b2_ptext[] = { + 0x41, 0x20, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, + 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20, + 0x6d, 0x75, 0x73, 0x74, 0x20, 0x6e, 0x6f, 0x74, + 0x20, 0x62, 0x65, 0x20, 0x72, 0x65, 0x71, 0x75, + 0x69, 0x72, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, + 0x62, 0x65, 0x20, 0x73, 0x65, 0x63, 0x72, 0x65, + 0x74, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x69, + 0x74, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, + 0x65, 0x20, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x74, + 0x6f, 0x20, 0x66, 0x61, 0x6c, 0x6c, 0x20, 0x69, + 0x6e, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x68, 0x61, 0x6e, 0x64, 0x73, 0x20, 0x6f, 0x66, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x6e, 0x65, + 0x6d, 0x79, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6f, + 0x75, 0x74, 0x20, 0x69, 0x6e, 0x63, 0x6f, 0x6e, + 0x76, 0x65, 0x6e, 0x69, 0x65, 0x6e, 0x63, 0x65 +}, + +jwa_b2_rawkey[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, +}, + +jwa_b2_iv[] = { + 0x1a, 0xf3, 0x8c, 0x2d, 0xc2, 0xb9, 0x6f, 0xfd, + 0xd8, 0x66, 0x94, 0x09, 0x23, 0x41, 0xbc, 0x04 +}, + +jwa_b2_e[] = { + 0xea, 0x65, 0xda, 0x6b, 0x59, 0xe6, 0x1e, 0xdb, + 0x41, 0x9b, 0xe6, 0x2d, 0x19, 0x71, 0x2a, 0xe5, + 0xd3, 0x03, 0xee, 0xb5, 0x00, 0x52, 0xd0, 0xdf, + 0xd6, 0x69, 0x7f, 0x77, 0x22, 0x4c, 0x8e, 0xdb, + 0x00, 0x0d, 0x27, 0x9b, 0xdc, 0x14, 0xc1, 0x07, + 0x26, 0x54, 0xbd, 0x30, 0x94, 0x42, 0x30, 0xc6, + 0x57, 0xbe, 0xd4, 0xca, 0x0c, 0x9f, 0x4a, 0x84, + 0x66, 0xf2, 0x2b, 0x22, 0x6d, 0x17, 0x46, 0x21, + 0x4b, 0xf8, 0xcf, 0xc2, 0x40, 0x0a, 0xdd, 0x9f, + 0x51, 0x26, 0xe4, 0x79, 0x66, 0x3f, 0xc9, 0x0b, + 0x3b, 0xed, 0x78, 0x7a, 0x2f, 0x0f, 0xfc, 0xbf, + 0x39, 0x04, 0xbe, 0x2a, 0x64, 0x1d, 0x5c, 0x21, + 0x05, 0xbf, 0xe5, 0x91, 0xba, 0xe2, 0x3b, 0x1d, + 0x74, 0x49, 0xe5, 0x32, 0xee, 0xf6, 0x0a, 0x9a, + 0xc8, 0xbb, 0x6c, 0x6b, 0x01, 0xd3, 0x5d, 0x49, + 0x78, 0x7b, 0xcd, 0x57, 0xef, 0x48, 0x49, 0x27, + 0xf2, 0x80, 0xad, 0xc9, 0x1a, 0xc0, 0xc4, 0xe7, + 0x9c, 0x7b, 0x11, 0xef, 0xc6, 0x00, 0x54, 0xe3 +}, + +jwa_b2_a[] = { /* "The second principle of Auguste Kerckhoffs" */ + 0x54, 0x68, 0x65, 0x20, 0x73, 0x65, 0x63, 0x6f, + 0x6e, 0x64, 0x20, 0x70, 0x72, 0x69, 0x6e, 0x63, + 0x69, 0x70, 0x6c, 0x65, 0x20, 0x6f, 0x66, 0x20, + 0x41, 0x75, 0x67, 0x75, 0x73, 0x74, 0x65, 0x20, + 0x4b, 0x65, 0x72, 0x63, 0x6b, 0x68, 0x6f, 0x66, + 0x66, 0x73 +}, + +jwa_b2_tag[] = { + 0x84, 0x90, 0xac, 0x0e, 0x58, 0x94, 0x9b, 0xfe, + 0x51, 0x87, 0x5d, 0x73, 0x3f, 0x93, 0xac, 0x20, + 0x75, 0x16, 0x80, 0x39, 0xcc, 0xc7, 0x33, 0xd7 + +} +; + +static int +test_jwa_b2(struct lws_context *context) +{ + struct lws_jose jose; + struct lws_jws jws; + struct lws_jwk jwk; + int n, ret = -1; + char buf[2048]; + + lws_jose_init(&jose); + lws_jws_init(&jws, &jwk, context); + + /* + * normally all this is interpreted from the JWE blob. But we don't + * have JWE test vectors for AES_256_CBC_HMAC_SHA_512, just a standalone + * one. So we have to create it all by hand. + * + * See test_jwe_a3 above for a more normal usage pattern. + */ + + memset(&jwk, 0, sizeof(jwk)); + jwk.kty = LWS_GENCRYPTO_KTY_OCT; + jwk.e[LWS_GENCRYPTO_OCT_KEYEL_K].buf = (uint8_t *)jwa_b2_rawkey; + jwk.e[LWS_GENCRYPTO_OCT_KEYEL_K].len = sizeof(jwa_b2_rawkey); + + memcpy(buf, jwa_b2_e, sizeof(jwa_b2_e)); + + jws.map.buf[LJWE_IV] = (char *)jwa_b2_iv; + jws.map.len[LJWE_IV] = sizeof(jwa_b2_iv); + + jws.map.buf[LJWE_CTXT] = buf; + jws.map.len[LJWE_CTXT] = sizeof(jwa_b2_e); + + jws.map.buf[LJWE_ATAG] = (char *)jwa_b2_tag; + jws.map.len[LJWE_ATAG] = sizeof(jwa_b2_tag); + + /* + * Normally this comes from the JOSE header. But this test vector + * doesn't have one... so... + */ + + if (lws_gencrypto_jwe_alg_to_definition("A128KW", &jose.alg)) + goto bail; + if (lws_gencrypto_jwe_enc_to_definition("A192CBC-HS384", &jose.enc_alg)) + goto bail; + + n = lws_jwe_auth_and_decrypt_cbc_hs(&jose, &jws, jwa_b2_rawkey, + jwa_b2_a, sizeof(jwa_b2_a)); + if (n < 0) { + lwsl_err("%s: lws_jwe_a_cbc_hs_decrypt failed\n", __func__); + + goto bail; + } + + /* allowing for trailing padding, confirm the plaintext */ + if (jws.map.len[LJWE_CTXT] < sizeof(jwa_b2_ptext) || + lws_timingsafe_bcmp(jws.map.buf[LJWE_CTXT],jwa_b2_ptext, + sizeof(jwa_b2_ptext))) { + lwsl_err("%s: plaintext AES decrypt wrong\n", __func__); + lwsl_hexdump_notice(jwa_b2_ptext, sizeof(jwa_b2_ptext)); + lwsl_hexdump_notice(jws.map.buf[LJWE_CTXT], + jws.map.len[LJWE_CTXT]); + goto bail; + } + + ret = 0; + +bail: + lws_jws_destroy(&jws); + lws_jose_destroy(&jose); + if (ret) + lwsl_err("%s: selftest failed +++++++++++++++++++\n", __func__); + else + lwsl_notice("%s: selftest OK\n", __func__); + + return ret; +} + + + +/* JWA B.3. Test Cases for AES_256_CBC_HMAC_SHA_512 + * + * Unfortunately JWA just gives this test case as hex literals, not + * inside a JWE. So we have to prepare the inputs "by hand". + */ + +static uint8_t + +jwa_b3_ptext[] = { + 0x41, 0x20, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, + 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20, + 0x6d, 0x75, 0x73, 0x74, 0x20, 0x6e, 0x6f, 0x74, + 0x20, 0x62, 0x65, 0x20, 0x72, 0x65, 0x71, 0x75, + 0x69, 0x72, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, + 0x62, 0x65, 0x20, 0x73, 0x65, 0x63, 0x72, 0x65, + 0x74, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x69, + 0x74, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, + 0x65, 0x20, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x74, + 0x6f, 0x20, 0x66, 0x61, 0x6c, 0x6c, 0x20, 0x69, + 0x6e, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x68, 0x61, 0x6e, 0x64, 0x73, 0x20, 0x6f, 0x66, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x6e, 0x65, + 0x6d, 0x79, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6f, + 0x75, 0x74, 0x20, 0x69, 0x6e, 0x63, 0x6f, 0x6e, + 0x76, 0x65, 0x6e, 0x69, 0x65, 0x6e, 0x63, 0x65 +}, + + +jwa_b3_rawkey[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f +}, + +jwa_b3_iv[] = { + 0x1a, 0xf3, 0x8c, 0x2d, 0xc2, 0xb9, 0x6f, 0xfd, + 0xd8, 0x66, 0x94, 0x09, 0x23, 0x41, 0xbc, 0x04 +}, + +jwa_b3_e[] = { + 0x4a, 0xff, 0xaa, 0xad, 0xb7, 0x8c, 0x31, 0xc5, + 0xda, 0x4b, 0x1b, 0x59, 0x0d, 0x10, 0xff, 0xbd, + 0x3d, 0xd8, 0xd5, 0xd3, 0x02, 0x42, 0x35, 0x26, + 0x91, 0x2d, 0xa0, 0x37, 0xec, 0xbc, 0xc7, 0xbd, + 0x82, 0x2c, 0x30, 0x1d, 0xd6, 0x7c, 0x37, 0x3b, + 0xcc, 0xb5, 0x84, 0xad, 0x3e, 0x92, 0x79, 0xc2, + 0xe6, 0xd1, 0x2a, 0x13, 0x74, 0xb7, 0x7f, 0x07, + 0x75, 0x53, 0xdf, 0x82, 0x94, 0x10, 0x44, 0x6b, + 0x36, 0xeb, 0xd9, 0x70, 0x66, 0x29, 0x6a, 0xe6, + 0x42, 0x7e, 0xa7, 0x5c, 0x2e, 0x08, 0x46, 0xa1, + 0x1a, 0x09, 0xcc, 0xf5, 0x37, 0x0d, 0xc8, 0x0b, + 0xfe, 0xcb, 0xad, 0x28, 0xc7, 0x3f, 0x09, 0xb3, + 0xa3, 0xb7, 0x5e, 0x66, 0x2a, 0x25, 0x94, 0x41, + 0x0a, 0xe4, 0x96, 0xb2, 0xe2, 0xe6, 0x60, 0x9e, + 0x31, 0xe6, 0xe0, 0x2c, 0xc8, 0x37, 0xf0, 0x53, + 0xd2, 0x1f, 0x37, 0xff, 0x4f, 0x51, 0x95, 0x0b, + 0xbe, 0x26, 0x38, 0xd0, 0x9d, 0xd7, 0xa4, 0x93, + 0x09, 0x30, 0x80, 0x6d, 0x07, 0x03, 0xb1, 0xf6, +}, + +jwa_b3_a[] = { /* "The second principle of Auguste Kerckhoffs" */ + 0x54, 0x68, 0x65, 0x20, 0x73, 0x65, 0x63, 0x6f, + 0x6e, 0x64, 0x20, 0x70, 0x72, 0x69, 0x6e, 0x63, + 0x69, 0x70, 0x6c, 0x65, 0x20, 0x6f, 0x66, 0x20, + 0x41, 0x75, 0x67, 0x75, 0x73, 0x74, 0x65, 0x20, + 0x4b, 0x65, 0x72, 0x63, 0x6b, 0x68, 0x6f, 0x66, + 0x66, 0x73 +}, + +jws_b3_tag[] = { + 0x4d, 0xd3, 0xb4, 0xc0, 0x88, 0xa7, 0xf4, 0x5c, + 0x21, 0x68, 0x39, 0x64, 0x5b, 0x20, 0x12, 0xbf, + 0x2e, 0x62, 0x69, 0xa8, 0xc5, 0x6a, 0x81, 0x6d, + 0xbc, 0x1b, 0x26, 0x77, 0x61, 0x95, 0x5b, 0xc5 +} +; + +static int +test_jwa_b3(struct lws_context *context) +{ + struct lws_jose jose; + struct lws_jws jws; + struct lws_jwk jwk; + char buf[2048]; + int n, ret = -1; + + lws_jose_init(&jose); + lws_jws_init(&jws, &jwk, context); + + /* + * normally all this is interpreted from the JWE blob. But we don't + * have JWE test vectors for AES_256_CBC_HMAC_SHA_512, just a standalone + * one. So we have to create it all by hand. + * + * See test_jwe_a3 above for a more normal usage pattern. + */ + + memset(&jwk, 0, sizeof(jwk)); + jwk.kty = LWS_GENCRYPTO_KTY_OCT; + jwk.e[LWS_GENCRYPTO_OCT_KEYEL_K].buf = (uint8_t *)jwa_b3_rawkey; + jwk.e[LWS_GENCRYPTO_OCT_KEYEL_K].len = sizeof(jwa_b3_rawkey); + + memcpy(buf, jwa_b3_e, sizeof(jwa_b3_e)); + + jws.map.buf[LJWE_IV] = (char *)jwa_b3_iv; + jws.map.len[LJWE_IV] = sizeof(jwa_b3_iv); + + jws.map.buf[LJWE_CTXT] = buf; + jws.map.len[LJWE_CTXT] = sizeof(jwa_b3_e); + + jws.map.buf[LJWE_ATAG] = (char *)jws_b3_tag; + jws.map.len[LJWE_ATAG] = sizeof(jws_b3_tag); + + /* + * Normally this comes from the JOSE header. But this test vector + * doesn't feature one... + */ + + if (lws_gencrypto_jwe_alg_to_definition("A128KW", &jose.alg)) + goto bail; + if (lws_gencrypto_jwe_enc_to_definition("A256CBC-HS512", &jose.enc_alg)) + goto bail; + + n = lws_jwe_auth_and_decrypt_cbc_hs(&jose, &jws, jwa_b3_rawkey, + jwa_b3_a, sizeof(jwa_b3_a)); + if (n < 0) { + lwsl_err("%s: lws_jwe_a_cbc_hs_decrypt failed\n", __func__); + + goto bail; + } + + /* allowing for trailing padding, confirm the plaintext */ + if (jws.map.len[LJWE_CTXT] < sizeof(jwa_b3_ptext) || + lws_timingsafe_bcmp(jws.map.buf[LJWE_CTXT],jwa_b3_ptext, + sizeof(jwa_b3_ptext))) { + lwsl_err("%s: plaintext AES decrypt wrong\n", __func__); + lwsl_hexdump_notice(jwa_b3_ptext, sizeof(jwa_b3_ptext)); + lwsl_hexdump_notice(jws.map.buf[LJWE_CTXT], + jws.map.len[LJWE_CTXT]); + goto bail; + } + + ret = 0; + +bail: + if (ret) + lwsl_err("%s: selftest failed ++++++++++++++++++++\n", __func__); + else + lwsl_notice("%s: selftest OK\n", __func__); + + lws_jws_destroy(&jws); + + return ret; +} + +/* JWA C. Example ECDH-ES Key Agreement Computation + * + * This example uses ECDH-ES Key Agreement and the Concat KDF to derive + * the CEK in the manner described in Section 4.6. In this example, the + * ECDH-ES Direct Key Agreement mode ("alg" value "ECDH-ES") is used to + * produce an agreed-upon key for AES GCM with a 128-bit key ("enc" + * value "A128GCM"). + * + * In this example, a producer Alice is encrypting content to a consumer + * Bob. The producer (Alice) generates an ephemeral key for the key + * agreement computation. + * + * JWA Appendix C where this comes from ONLY goes as far as to confirm the + * direct derived key, it doesn't do any AES128-GCM. + */ + +static const char + +*ex_jwa_c_jose = + "{\"alg\":\"ECDH-ES\"," + "\"enc\":\"A128GCM\"," + "\"apu\":\"QWxpY2U\"," /* b64u("Alice") */ + "\"apv\":\"Qm9i\"," /* b64u("Bob") */ + "\"epk\":" /* public part of A's ephemeral key */ + "{\"kty\":\"EC\"," + "\"crv\":\"P-256\"," + "\"x\":\"gI0GAILBdu7T53akrFmMyGcsF3n5dO7MmwNBHKW5SV0\"," + "\"y\":\"SLW_xSffzlPWrHEVI30DHM_4egVwt3NQqeUD7nMFpps\"" + "}" + "}" +; + +static uint8_t +ex_jwa_c_z[] = { + 158, 86, 217, 29, 129, 113, 53, 211, + 114, 131, 66, 131, 191, 132, 38, 156, + 251, 49, 110, 163, 218, 128, 106, 72, + 246, 218, 167, 121, 140, 254, 144, 196 +}, +ex_jwa_c_derived_key[] = { + 86, 170, 141, 234, 248, 35, 109, 32, + 92, 34, 40, 205, 113, 167, 16, 26 +}; + + +static int +test_jwa_c(struct lws_context *context) +{ + struct lws_jose jose; + struct lws_jws jws; + char temp[2048], *p; + int ret = -1, temp_len = sizeof(temp); + + lws_jose_init(&jose); + lws_jws_init(&jws, NULL, context); + + /* + * again the JWA Appendix C test vectors are not in the form of a + * complete JWE, but just the JWE JOSE header, so we must fake up the + * pieces and perform just the (normally internal) key agreement step + * for this test. + * + * See test_jwe_a3 above for a more normal usage pattern. + */ + + if (lws_jwe_parse_jose(&jose, ex_jwa_c_jose, strlen(ex_jwa_c_jose), + temp, &temp_len) < 0) { + lwsl_err("%s: JOSE parse failed\n", __func__); + + goto bail; + } + + /* + * The ephemeral key has been parsed into a jwk "jose.jwk_ephemeral" + * + * In this example, the ECDH-ES Direct Key Agreement mode ("alg" value + * "ECDH-ES") is used to produce an agreed-upon key for AES GCM with a + * 128-bit key ("enc" value "A128GCM"). + */ + + p = lws_concat_temp(temp, temp_len); + + if (lws_jwa_concat_kdf(&jose, &jws, 1, (uint8_t *)p, + ex_jwa_c_z, sizeof(ex_jwa_c_z))) { + lwsl_err("%s: JOSE parse failed\n", __func__); + + goto bail; + } + + /* allowing for trailing padding, confirm the plaintext */ + if (lws_timingsafe_bcmp(lws_concat_temp(temp, temp_len), ex_jwa_c_derived_key, + sizeof(ex_jwa_c_derived_key))) { + lwsl_err("%s: ECDH-ES direct derived key wrong\n", __func__); + lwsl_hexdump_notice(ex_jwa_c_derived_key, + sizeof(ex_jwa_c_derived_key)); + lwsl_hexdump_notice(p, sizeof(ex_jwa_c_derived_key)); + goto bail; + } + + ret = 0; + +bail: + lws_jws_destroy(&jws); + lws_jose_destroy(&jose); + if (ret) + lwsl_err("%s: selftest failed +++++++++++++++++++\n", __func__); + else + lwsl_notice("%s: selftest OK\n", __func__); + + return ret; +} + + +/* AES Key Wrap and AES_XXX_CBC_HMAC_SHA_YYY variations + * + * These were created by, eg + * + * echo -n "plaintext0123456" | \ + * ./lws-crypto-jwe -e "A192KW A256CBC-HS512" -k aes192.key + */ + +/* "Live long and prosper." */ +static const char + *akw_ptext = "plaintext0123456", + *akw_ct_128_128 = "eyJhbGciOiJBMTI4S1ciLCAiZW5jIjoiQTEyOENCQy1IUzI1NiJ9.zbTfhhWePf1UrCRDxJD_-8eAQr2AoWAL51_nNOv0L4nV3P0e4_9ARA.qWehIhy4j4_gh_h5MF9ZEw.GD40YH6NeNOEkhhxC9ryZA.PEuU6V3rhYXeoxENrAzDgw", + *akw_ct_128_192 = "eyJhbGciOiJBMTI4S1ciLCAiZW5jIjoiQTE5MkNCQy1IUzM4NCJ9.zpkr45xH_kSJ5eTBv5dGo5PN_A6YdC4JoJSOw3_VTqcOeAYyCkCAXeGWugqIVLzMzBKgtXdabO8.O28MVhkgfketu5sxQK4Ffw.j25N7luxh251kQwpAoYURQ.Pm_NOj0KZzUq2fV9ARpHxT3Iach9feLK", + *akw_ct_128_256 = "eyJhbGciOiJBMTI4S1ciLCAiZW5jIjoiQTI1NkNCQy1IUzUxMiJ9.VvFmi121jliyh_UKzsBv7HR3TVY7-yALpcdlasHqdzmfISd8LFU5oc2fEhfn3_TKfCbgRycm5M3103NEMbVSiNULZWvJAPFe.7uLHGFO1g-PgD9YkjPbvoA.AlPwQPWSqGaB_em4qEEyjw.0LgTLld5pSffZnzGG6IRWEwXg7HhClmwP4m_p1yKnHw", + *akw_ct_192_128 = "eyJhbGciOiJBMTkyS1ciLCAiZW5jIjoiQTEyOENCQy1IUzI1NiJ9.kxlmi-xn0JN-ZlnSfkVDP-fXvricJ-L63WP2bWddWEiVK4m-os2trw.iarAWaeV873kh5s7HjoZ4Q.nFHEpnnIxvbCiYfFfsLj7Q.karz-h-R93dJgwN_YZyPmw", + *akw_ct_192_192 = "eyJhbGciOiJBMTkyS1ciLCAiZW5jIjoiQTE5MkNCQy1IUzM4NCJ9.D869MEk-JERZU_4MgFuL_6Pg24LUEbXlTvGj-t_JUnNFsJ0p8fk5L-iOATqPmx2g7AyVWgcUqU0.RrxzDsy6Bne1pzx99PBGsA.C-ZWmMwd1uswYkvhKX2_jg.bIFY0TmGuohI2APxDZyFUYpa6s1Mx2j1", + *akw_ct_192_256 = "eyJhbGciOiJBMTkyS1ciLCAiZW5jIjoiQTI1NkNCQy1IUzUxMiJ9.XNOBw0Dy1paAX2_XGkZYm2Zm455i8InAVMqM3aOrVDpXYBAADuZ_Ke_dlo3Fc8J5b9m_KNCUtVUU8f3KV0sY-yESsqyZTSXk.n3wEIV1-tL50JAp4H19Y1w.ODPd-oxmpCai9CzqaO0P3Q.b9z08hJTySSVSOw-4qp5lrTEcUur46L-RRB-SEcqPpk", + *akw_ct_256_128 = "eyJhbGciOiJBMjU2S1ciLCAiZW5jIjoiQTEyOENCQy1IUzI1NiJ9.THaIbHUOHkr7McMeiQqIO_gBcm61F0BKx79JXkzQVVSF7m0u7Z6uhA.RAU8Yx_a9rbWeqr_0YyLZA.zzfdv55bM-qblTxaR5pNzQ.cySMIOTOcEoFkcVn0D6RKQ", + *akw_ct_256_192 = "eyJhbGciOiJBMjU2S1ciLCAiZW5jIjoiQTE5MkNCQy1IUzM4NCJ9.gFcfX6fVrpmDJWN5jPqSWEvpOOoNuV4Yn2KO47p1wGsdw5qIw3r5AO5U8zOEtoGNVX68IC8vkpo.9w3tBsve4e-77lI-S9cFog.Vj3L009JDipPJlHY0tS4Iw.WYGgCedW4SmxleDF3P6Hx26BUXxnizxl", + *akw_ct_256_256 = "eyJhbGciOiJBMjU2S1ciLCAiZW5jIjoiQTI1NkNCQy1IUzUxMiJ9.ldhqlMf2LJrZ7EDl-oZvaqi0b_KPGy4cMRx2QDpKtTg92tTSWF7ALVHPPCyT4qccIybP4rygajKfdC_Q_UE16KFyUvXhBgaj.S9OCmKpY0zDkArLF5XsrJw.zvJ1X-zuHsrwLXGJJbglPA.WaRKb7Le2ZQ30pGQAV3sfp-YY1563KXxPURHQ8ntdPc", + *akw_key_128 = "{\"k\":\"JjVJVh8JsXvKf9qgHHWWBA\",\"kty\":\"oct\"}", + *akw_key_192 = "{\"k\":\"BYF6urCMDRMKFXXRxXrDSVtW71AUZghj\",\"kty\":\"oct\"}", + *akw_key_256 = "{\"k\":\"cSHyZXGEfnlgKud21cM6tAxRyXnK6xbWRTsyLUegTMk\",\"kty\":\"oct\"}" +; + +static int +test_akw_decrypt(struct lws_context *context, const char *test_name, + const char *ciphertext, const char *key) +{ + struct lws_jose jose; + struct lws_jws jws; + struct lws_jwk jwk; + char temp[2048]; + int n, ret = -1, temp_len = sizeof(temp); + + lws_jose_init(&jose); + lws_jws_init(&jws, &jwk, context); + + if (lws_jwk_import(&jwk, NULL, NULL, key, strlen(key)) < 0) { + lwsl_notice("%s: Failed to decode JWK test key\n", __func__); + goto bail; + } + + /* converts a compact serialization to jws b64 + decoded maps */ + if (lws_jws_compact_decode(ciphertext, strlen(ciphertext), + &jws.map, &jws.map_b64, + temp, &temp_len) != 5) { + lwsl_err("%s: lws_jws_compact_decode failed\n", __func__); + goto bail1; + } + + n = lws_jwe_auth_and_decrypt(&jose, &jws); + lws_jwk_destroy(&jwk); + if (n < 0) { + lwsl_err("%s: lws_jwe_auth_and_decrypt failed\n", + __func__); + goto bail1; + } + + /* allowing for trailing padding, confirm the plaintext */ + if (jws.map.len[LJWE_CTXT] < strlen(akw_ptext) || + lws_timingsafe_bcmp(jws.map.buf[LJWE_CTXT], akw_ptext, + strlen(akw_ptext))) { + lwsl_err("%s: plaintext AES decrypt wrong\n", __func__); + lwsl_hexdump_notice(akw_ptext, strlen(akw_ptext)); + lwsl_hexdump_notice(jws.map.buf[LJWE_CTXT], + jws.map.len[LJWE_CTXT]); + goto bail1; + } + + ret = 0; + +bail1: + lws_jwk_destroy(&jwk); + +bail: + lws_jws_destroy(&jws); + lws_jose_destroy(&jose); + if (ret) + lwsl_err("%s: selftest %s failed +++++++++++++++++++\n", + __func__, test_name); + else + lwsl_notice("%s: selftest %s OK\n", __func__, test_name); + + return ret; +} + +static int +test_akw_encrypt(struct lws_context *context, const char *test_name, + const char *alg, const char *enc, + const char *ciphertext, const char *key, + char *compact, int compact_len) +{ + struct lws_jose jose; + struct lws_jws jws; + struct lws_jwk jwk; + char temp[4096]; + int ret = -1, n, temp_len = sizeof(temp); + + lws_jose_init(&jose); + lws_jws_init(&jws, &jwk, context); + + if (lws_jwk_import(&jwk, NULL, NULL, key, strlen(key)) < 0) { + lwsl_notice("%s: Failed to decode JWK test key\n", __func__); + goto bail; + } + + if (lws_gencrypto_jwe_alg_to_definition(alg, &jose.alg)) { + lwsl_err("Unknown cipher alg %s\n", alg); + goto bail1; + } + if (lws_gencrypto_jwe_enc_to_definition(enc, &jose.enc_alg)) { + lwsl_err("Unknown payload enc alg %s\n", enc); + goto bail1; + } + + /* we require a JOSE-formatted header to do the encryption */ + + if (temp_len < 256) + goto bail1; + jws.map.buf[LJWS_JOSE] = temp; + jws.map.len[LJWS_JOSE] = lws_snprintf(temp, temp_len, + "{\"alg\":\"%s\", \"enc\":\"%s\"}", alg, enc); + temp_len -= jws.map.len[LJWS_JOSE]; + + /* + * dup the plaintext into the ciphertext element, it will be + * encrypted in-place to a ciphertext of the same length + */ + + if (lws_jws_dup_element(&jws.map, LJWE_CTXT, + lws_concat_temp(temp, temp_len), &temp_len, + akw_ptext, strlen(akw_ptext), 0)) { + lwsl_notice("%s: Not enough temp space for ptext\n", __func__); + goto bail; + } + + /* CEK size is determined by hash / hmac size */ + + n = lws_gencrypto_bits_to_bytes(jose.enc_alg->keybits_fixed); + if (lws_jws_randomize_element(context, &jws.map, LJWE_EKEY, + lws_concat_temp(temp, temp_len), + &temp_len, n, + LWS_JWE_LIMIT_KEY_ELEMENT_BYTES)) { + lwsl_err("Problem getting random\n"); + goto bail1; + } + + n = lws_jwe_encrypt(&jose, &jws, lws_concat_temp(temp, temp_len), + &temp_len); + if (n < 0) { + lwsl_err("%s: lws_jwe_encrypt failed\n", __func__); + goto bail1; + } + + n = lws_jwe_write_compact(&jose, &jws, compact, compact_len); + if (n < 0) { + lwsl_err("%s: lws_jwe_write_compact failed: %d\n", + __func__, n); + goto bail1; + } + + ret = 0; +bail1: + lws_jwk_destroy(&jwk); +bail: + lws_jws_destroy(&jws); + lws_jose_destroy(&jose); + if (ret) + lwsl_err("%s: selftest %s failed +++++++++++++++++++\n", + __func__, test_name); + else + lwsl_notice("%s: selftest %s OK\n", __func__, test_name); + + return ret; +} + +#if 0 +static char *complete = + "{" + "\"protected\":" + "\"eyJlbmMiOiJBMTI4Q0JDLUhTMjU2In0\"," + "\"unprotected\":" + "{\"jku\":\"https://server.example.com/keys.jwks\"}," + "\"recipients\":[" + "{\"header\":" + "{\"alg\":\"RSA1_5\",\"kid\":\"2011-04-29\"}," + "\"encrypted_key\":" + "\"UGhIOguC7IuEvf_NPVaXsGMoLOmwvc1GyqlIKOK1nN94nHPoltGRhWhw7Zx0-" + "kFm1NJn8LE9XShH59_i8J0PH5ZZyNfGy2xGdULU7sHNF6Gp2vPLgNZ__deLKx" + "GHZ7PcHALUzoOegEI-8E66jX2E4zyJKx-YxzZIItRzC5hlRirb6Y5Cl_p-ko3" + "YvkkysZIFNPccxRU7qve1WYPxqbb2Yw8kZqa2rMWI5ng8OtvzlV7elprCbuPh" + "cCdZ6XDP0_F8rkXds2vE4X-ncOIM8hAYHHi29NX0mcKiRaD0-D-ljQTP-cFPg" + "wCp6X-nZZd9OHBv-B3oWh2TbqmScqXMR4gp_A\"}," + "{\"header\":" + "{\"alg\":\"A128KW\",\"kid\":\"7\"}," + "\"encrypted_key\":" + "\"6KB707dM9YTIgHtLvtgWQ8mKwboJW3of9locizkDTHzBC2IlrT1oOQ\"}]," + "\"iv\":" + "\"AxY8DCtDaGlsbGljb3RoZQ\"," + "\"ciphertext\":" + "\"KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY\"," + "\"tag\":" + "\"Mz-VPPyU4RlcuYv1IwIvzw\"" + "}\"" +; + + +#endif + int test_jwe(struct lws_context *context) { - //const struct lws_jose_jwe_alg *jose_alg; - struct lws_genrsa_ctx rsactx; - struct lws_jwk jwk; - uint8_t enc_cek[/* sizeof(lws_jwe_ex_a2_jwk_enc_key) */ 256 + 2048]; - char buf[2048], *p = buf, *end = buf + sizeof(buf) - 1; - int n; + char compact[4096]; + int n = 0; - /* Test 1: A.2 */ + n |= test_jwe_a1(context); - /* Decode the JWK JSON key */ + n |= test_jwe_a2(context); - if (lws_jwk_import(&jwk, NULL, NULL, (char *)lws_jwe_ex_a2_jwk_json, - strlen((char *)lws_jwe_ex_a2_jwk_json)) < 0) { - lwsl_notice("Failed to decode JWK test key\n"); - return -1; - } + n |= test_jwe_ra_ptext_1024(context, (char *)lws_jwe_ex_a2_jwk_json, + strlen((char *)lws_jwe_ex_a2_jwk_json)); + n |= test_jwe_r256a192_ptext(context, (char *)lws_jwe_ex_a2_jwk_json, + strlen((char *)lws_jwe_ex_a2_jwk_json)); + n |= test_jwe_r256a256_ptext(context, (char *)lws_jwe_ex_a2_jwk_json, + strlen((char *)lws_jwe_ex_a2_jwk_json)); + n |= test_jwe_ra_ptext_1024(context, (char *)rsa_key_2048, + strlen((char *)rsa_key_2048)); + n |= test_jwe_r256a192_ptext(context, (char *)rsa_key_2048, + strlen((char *)rsa_key_2048)); + n |= test_jwe_r256a256_ptext(context, (char *)rsa_key_2048, + strlen((char *)rsa_key_2048)); + n |= test_jwe_ra_ptext_1024(context, (char *)rsa_key_4096, + strlen((char *)rsa_key_4096)); + n |= test_jwe_r256a192_ptext(context, (char *)rsa_key_4096, + strlen((char *)rsa_key_4096)); + n |= test_jwe_r256a256_ptext(context, (char *)rsa_key_4096, + strlen((char *)rsa_key_4096)); + n |= test_jwe_ra_ptext_1024(context, (char *)rsa_key_4096_no_optional, + strlen((char *)rsa_key_4096_no_optional)); + n |= test_jwe_r256a192_ptext(context, (char *)rsa_key_4096_no_optional, + strlen((char *)rsa_key_4096_no_optional)); + n |= test_jwe_r256a256_ptext(context, (char *)rsa_key_4096_no_optional, + strlen((char *)rsa_key_4096_no_optional)); - if (jwk.kty != LWS_GENCRYPTO_KYT_RSA) { - lwsl_err("%s: unexpected kty %d\n", __func__, jwk.kty); + /* AESKW decrypt all variations */ - return -1; - } + n |= test_akw_decrypt(context, "d-a128kw_128", akw_ct_128_128, akw_key_128); + n |= test_akw_decrypt(context, "d-a128kw_192", akw_ct_128_192, akw_key_128); + n |= test_akw_decrypt(context, "d-a128kw_256", akw_ct_128_256, akw_key_128); + n |= test_akw_decrypt(context, "d-a192kw_128", akw_ct_192_128, akw_key_192); + n |= test_akw_decrypt(context, "d-a192kw_192", akw_ct_192_192, akw_key_192); + n |= test_akw_decrypt(context, "d-a192kw_256", akw_ct_192_256, akw_key_192); + n |= test_akw_decrypt(context, "d-a256kw_128", akw_ct_256_128, akw_key_256); + n |= test_akw_decrypt(context, "d-a256kw_192", akw_ct_256_192, akw_key_256); + n |= test_akw_decrypt(context, "d-a256kw_256", akw_ct_256_256, akw_key_256); - /* A.2.1: encode JOSE header and confirm matches official string */ + /* AESKW encrypt then confirm decrypt */ - n = lws_jws_encode_section((char *)lws_jwe_ex_a2_jose_hdr, - strlen((char *)lws_jwe_ex_a2_jose_hdr), 1, - &p, end); - if (n < 0) - goto bail; - if (strcmp(buf, (char *)lws_jwe_ex_a2_jose_hdr_b64utf8)) - goto bail; + if (!test_akw_encrypt(context, "ed-128kw_128", "A128KW", "A128CBC-HS256", + akw_ptext, akw_key_128, compact, sizeof(compact))) + n |= test_akw_decrypt(context, "ed-128kw_128", compact, akw_key_128); + else + n = -1; + if (!test_akw_encrypt(context, "ed-128kw_192", "A128KW", "A192CBC-HS384", + akw_ptext, akw_key_128, compact, sizeof(compact))) + n |= test_akw_decrypt(context, "ed-128kw_192", compact, akw_key_128); + else + n = -1; + if (!test_akw_encrypt(context, "ed-128kw_256", "A128KW", "A256CBC-HS512", + akw_ptext, akw_key_128, compact, sizeof(compact))) + n |= test_akw_decrypt(context, "ed-128kw_256", compact, akw_key_128); + else + n = -1; - /* A.2.3: Encrypt the CEK with the recipient's public key using the - * RSAES-PKCS1-v1_5 algorithm to produce the JWE Encrypted Key. - */ + if (!test_akw_encrypt(context, "ed-192kw_128", "A192KW", "A128CBC-HS256", + akw_ptext, akw_key_192, compact, sizeof(compact))) + n |= test_akw_decrypt(context, "ed-192kw_128", compact, akw_key_192); + else + n = -1; + if (!test_akw_encrypt(context, "ed-192kw_192", "A192KW", "A192CBC-HS384", + akw_ptext, akw_key_192, compact, sizeof(compact))) + n |= test_akw_decrypt(context, "ed-192kw_192", compact, akw_key_192); + else + n = -1; + if (!test_akw_encrypt(context, "ed-192kw_256", "A192KW", "A256CBC-HS512", + akw_ptext, akw_key_192, compact, sizeof(compact))) + n |= test_akw_decrypt(context, "ed-192kw_256", compact, akw_key_192); + else + n = -1; - if (lws_genrsa_create(&rsactx, jwk.e, context, LGRSAM_PKCS1_1_5)) { - lwsl_notice("%s: lws_genrsa_public_decrypt_create\n", - __func__); - goto bail; - } + if (!test_akw_encrypt(context, "ed-256kw_128", "A256KW", "A128CBC-HS256", + akw_ptext, akw_key_256, compact, sizeof(compact))) + n |= test_akw_decrypt(context, "ed-256kw_128", compact, akw_key_256); + else + n = -1; + if (!test_akw_encrypt(context, "ed-256kw_192", "A256KW", "A192CBC-HS384", + akw_ptext, akw_key_256, compact, sizeof(compact))) + n |= test_akw_decrypt(context, "ed-256kw_192", compact, akw_key_256); + else + n = -1; + if (!test_akw_encrypt(context, "ed-256kw_256", "A256KW", "A256CBC-HS512", + akw_ptext, akw_key_256, compact, sizeof(compact))) + n |= test_akw_decrypt(context, "ed-256kw_256", compact, akw_key_256); + else + n = -1; - memset(enc_cek, 0, sizeof(enc_cek)); - - n = lws_genrsa_public_encrypt(&rsactx, lws_jwe_ex_a2_cek, - sizeof(lws_jwe_ex_a2_cek), enc_cek); - lws_genrsa_destroy(&rsactx); - if (n < 0) { - lwsl_err("%s: encrypt cek fail\n", __func__); - goto bail; - } -#if 0 - if (memcmp(enc_cek, lws_jwe_ex_a2_jwk_enc_key, sizeof(enc_cek))) { - lwsl_err("%s: encrypt cek wrong output\n", __func__); - lwsl_hexdump_notice(enc_cek, sizeof(enc_cek)); - lwsl_hexdump_notice(lws_jwe_ex_a2_jwk_enc_key, - sizeof(lws_jwe_ex_a2_jwk_enc_key)); - goto bail; - } - - - enc_ptr = p + 1; /* + 1 skips the . */ - n = lws_jws_encode_section(test2, strlen(test2), 0, &p, end); - if (n < 0) - goto bail; - if (strcmp(enc_ptr, test2_enc)) - goto bail; - - /* 1.3: use HMAC SHA-256 with known key on the hdr . payload */ - - if (lws_genhmac_init(&ctx, LWS_GENHMAC_TYPE_SHA256, - jwk.el.e[LWS_GENCRYPTO_RSA_KEYEL_E].buf, - jwk.el.e[LWS_GENCRYPTO_RSA_KEYEL_E].len)) - goto bail; - if (lws_genhmac_update(&ctx, (uint8_t *)buf, p - buf)) - goto bail_destroy_hmac; - lws_genhmac_destroy(&ctx, digest); - - /* 1.4: append a base64 encode of the computed HMAC digest */ - - enc_ptr = p + 1; /* + 1 skips the . */ - n = lws_jws_encode_section((const char *)digest, 32, 0, &p, end); - if (n < 0) - goto bail; - if (strcmp(enc_ptr, hash_enc)) /* check against known B64URL hash */ - goto bail; - - /* 1.5: Check we can agree the signature matches the payload */ - - if (lws_jws_confirm_sig(buf, p - buf, &jwk) < 0) { - lwsl_notice("confirm sig failed\n"); - goto bail; - } - - lws_jwk_destroy(&jwk); /* finished with the key from the first test */ - - /* Test 2: RSA256 on RFC7515 worked example */ - - /* 2.1: turn the known JWK key for the RSA test into a lws_jwk */ - - if (lws_jwk_import(&jwk, rfc7515_rsa_key, strlen(rfc7515_rsa_key))) { - lwsl_notice("Failed to read JWK key\n"); - goto bail2; - } - - /* 2.2: check the signature on the test packet from RFC7515 A-1 */ - - if (lws_jws_confirm_sig(rfc7515_rsa_a1, strlen(rfc7515_rsa_a1), - &jwk) < 0) { - lwsl_notice("confirm rsa sig failed\n"); - goto bail; - } - - /* 2.3: generate our own signature for a copy of the test packet */ - - memcpy(buf, rfc7515_rsa_a1, strlen(rfc7515_rsa_a1)); - - /* set p to second . */ - p = strchr(buf + 1, '.'); - p1 = strchr(p + 1, '.'); - - if (lws_gencrypto_jwe_alg_to_definition("RSA1_5", &jose_alg)) { - lwsl_err("%s: RSA1_5 not supported\n", __func__); - goto bail; - } - - n = lws_jws_sign_from_b64(buf, p - buf, p + 1, p1 - (p + 1), - p1 + 1, sizeof(buf) - (p1 - buf) - 1, - jose_alg, &jwk, context); - if (n < 0) - goto bail; - - puts(buf); - - /* 2.4: confirm our signature can be verified */ - - if (lws_jws_confirm_sig(buf, (p1 + 1 + n) - buf, &jwk) < 0) { - lwsl_notice("confirm rsa sig 2 failed\n"); - goto bail; - } -#endif - lws_jwk_destroy(&jwk); - - /* end */ - - lwsl_notice("%s: selftest OK\n", __func__); - - return 0; -#if 0 -bail_destroy_hmac: - lws_genhmac_destroy(&ctx, NULL); -#endif -bail: - lws_jwk_destroy(&jwk); -//bail2: - lwsl_err("%s: selftest failed ++++++++++++++++++++\n", __func__); - - return 1; + n |= test_jwe_r256a128_jwe_openssl(context); + n |= test_jwe_r256a128_jwe_mbedtls(context); + n |= test_jwe_a3(context); + n |= test_jwa_b2(context); + n |= test_jwa_b3(context); + n |= test_jwa_c(context); +// n |= test_jwe_json_complete(context); + return n; } diff --git a/minimal-examples/api-tests/api-test-jose/jws.c b/minimal-examples/api-tests/api-test-jose/jws.c index d66978e8d..b904f4e13 100644 --- a/minimal-examples/api-tests/api-test-jose/jws.c +++ b/minimal-examples/api-tests/api-test-jose/jws.c @@ -22,6 +22,83 @@ * */ +/* for none, the compact serialization format is b64u(jose hdr).b64u(payload) */ + +static const char *none_cser = + "eyJhbGciOiJub25lIn0" + "." + "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt" + "cGxlLmNvbS9pc19yb290Ijp0cnVlfQ", + *none_jose = "{\"alg\":\"none\"}", + *none_payload = "{\"iss\":\"joe\",\r\n \"exp\":1300819380,\r\n" + " \"http://example.com/is_root\":true}"; + +int +test_jws_none(struct lws_context *context) +{ + struct lws_jws_compact_map map; + struct lws_jose jose; + char temp[2048]; + int n, temp_len = sizeof(temp); + + lws_jose_init(&jose); + + /* A.5 Unsecured JSON "none" RFC7515 worked example */ + + /* decode the b64.b64[.b64] compact serialization blocks */ + n = lws_jws_compact_decode(none_cser, strlen(none_cser), &map, NULL, + temp, &temp_len); + if (n != 2) { + lwsl_err("%s: concat_map failed\n", __func__); + goto bail; + } + + /* confirm the decoded JOSE header is exactly what we expect */ + if (strncmp(none_jose, map.buf[LJWS_JOSE], map.len[LJWS_JOSE])) { + lwsl_err("%s: jose b64 decode wrong\n", __func__); + goto bail; + } + + /* parse the JOSE header */ + if (lws_jws_parse_jose(&jose, map.buf[LJWS_JOSE], + map.len[LJWS_JOSE], + (char *)lws_concat_temp(temp, temp_len), + &temp_len) < 0) { + lwsl_err("%s: JOSE parse failed\n", __func__); + goto bail; + } + + /* confirm we used the "none" alg as expected from JOSE hdr */ + if (strcmp(jose.alg->alg, "none")) { + lwsl_err("%s: JOSE header has wrong alg\n", __func__); + goto bail; + } + + /* confirm the payload is literally what we expect */ + if (strncmp(none_payload, map.buf[LJWS_PYLD], + map.len[LJWS_PYLD])) { + lwsl_err("%s: payload b64 decode wrong\n", __func__); + goto bail; + } + + /* end */ + + lwsl_notice("%s: selftest OK\n", __func__); + + lws_jose_destroy(&jose); + + return 0; + +bail: + lws_jose_destroy(&jose); + + lwsl_err("%s: selftest failed ++++++++++++++++++++\n", __func__); + + return 1; +} + + + static const char *test1 = "{\"typ\":\"JWT\",\r\n \"alg\":\"HS256\"}", *test1_enc = "eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9", @@ -32,9 +109,127 @@ static const char *key_jwk = "{\"kty\":\"oct\",\r\n" " \"k\":\"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQ" "Lr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow\"}", - *hash_enc = "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk", - /* the key from worked example in RFC7515 A-1, as a JWK */ - *rfc7515_rsa_key = + *hash_enc = "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk" +; + +int +test_jws_HS256(struct lws_context *context) +{ + char buf[2048], temp[256], *p = buf, *end = buf + sizeof(buf) - 1, *enc_ptr; + uint8_t digest[LWS_GENHASH_LARGEST]; + struct lws_jws_compact_map map; + int temp_len = sizeof(temp); + struct lws_genhmac_ctx ctx; + struct lws_jose jose; + struct lws_jwk jwk; + struct lws_jws jws; + int n; + + lws_jose_init(&jose); + lws_jws_init(&jws, &jwk, context); + + /* Test 1: SHA256 on RFC7515 worked example */ + + /* parse the JOSE header */ + + if (lws_jws_parse_jose(&jose, test1, strlen(test1), temp, &temp_len) < 0) { + lwsl_err("%s: JOSE parse failed\n", __func__); + goto bail; + } + + /* confirm we used the "none" alg as expected from JOSE hdr */ + if (strcmp(jose.alg->alg, "HS256")) { + lwsl_err("%s: JOSE header has wrong alg\n", __func__); + goto bail; + } + + /* 1.1: import the JWK oct key */ + + if (lws_jwk_import(&jwk, NULL, NULL, key_jwk, strlen(key_jwk)) < 0) { + lwsl_notice("Failed to decode JWK test key\n"); + return -1; + } + if (jwk.kty != LWS_GENCRYPTO_KTY_OCT) { + lwsl_err("%s: unexpected kty %d\n", __func__, jwk.kty); + + return -1; + } + + /* 1.2: create JWS known hdr + known payload */ + + n = lws_jws_encode_section(test1, strlen(test1), 1, &p, end); + if (n < 0) { + goto bail; + } + + if (strcmp(buf, test1_enc)) + goto bail; + + enc_ptr = p + 1; /* + 1 skips the . */ + n = lws_jws_encode_section(test2, strlen(test2), 0, &p, end); + if (n < 0) { + goto bail; + } + + if (strcmp(enc_ptr, test2_enc)) + goto bail; + + /* 1.3: use HMAC SHA-256 with known key on the hdr . payload */ + + if (lws_genhmac_init(&ctx, jose.alg->hmac_type, + jwk.e[LWS_GENCRYPTO_OCT_KEYEL_K].buf, + jwk.e[LWS_GENCRYPTO_OCT_KEYEL_K].len)) + goto bail; + if (lws_genhmac_update(&ctx, (uint8_t *)buf, p - buf)) + goto bail_destroy_hmac; + lws_genhmac_destroy(&ctx, digest); + + /* 1.4: append a base64 encode of the computed HMAC digest */ + + enc_ptr = p + 1; /* + 1 skips the . */ + n = lws_jws_encode_section((const char *)digest, 32, 0, &p, end); + if (n < 0) + goto bail; + if (strcmp(enc_ptr, hash_enc)) { /* check against known B64URL hash */ + lwsl_err("%s: b64 enc of computed HMAC mismatches '%s' '%s'\n", + __func__, enc_ptr, hash_enc); + goto bail; + } + + /* 1.5: Check we can agree the signature matches the payload */ + + if (lws_jws_sig_confirm_compact_b64(buf, p - buf, &map, &jwk, context, + lws_concat_temp(temp, temp_len), &temp_len) < 0) { + lwsl_notice("%s: confirm sig failed\n", __func__); + goto bail; + } + + lws_jws_destroy(&jws); + lws_jwk_destroy(&jwk); + lws_jose_destroy(&jose); + + /* end */ + + lwsl_notice("%s: selftest OK\n", __func__); + + return 0; + +bail_destroy_hmac: + lws_genhmac_destroy(&ctx, NULL); + +bail: + lws_jws_destroy(&jws); + lws_jwk_destroy(&jwk); + lws_jose_destroy(&jose); + lwsl_err("%s: selftest failed ++++++++++++++++++++\n", __func__); + + return 1; +} + + +static const char + /* the key from worked example in RFC7515 A-2, as a JWK */ + *rfc7515_rsa_key = "{\"kty\":\"RSA\"," " \"n\":\"ofgWCuLjybRlzo0tZWJjNiuSfb4p4fAkd_wWJcyQoTbji9k0l8W26mPddx" "HmfHQp-Vaw-4qPCJrcS2mJPMEzP1Pt0Bm4d4QlL-yRT-SFd2lZS-pCgNMs" @@ -65,37 +260,137 @@ static const char "y26F0EmpScGLq2MowX7fhd_QJQ3ydy5cY7YIBi87w93IKLEdfnbJtoOPLU" "W0ITrJReOgo1cq9SbsxYawBgfp_gh6A5603k2-ZQwVK0JKSHuLFkuQ3U\"" "}", - *rfc7515_rsa_a1 = /* the signed worked example in RFC7515 A-1 */ - "eyJhbGciOiJSUzI1NiJ9" - ".eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt" - "cGxlLmNvbS9pc19yb290Ijp0cnVlfQ" - ".cC4hiUPoj9Eetdgtv3hF80EGrhuB__dzERat0XF9g2VtQgr9PJbu3XOiZj5RZmh7" - "AAuHIm4Bh-0Qc_lF5YKt_O8W2Fp5jujGbds9uJdbF9CUAr7t1dnZcAcQjbKBYNX4" - "BAynRFdiuB--f_nZLgrnbyTyWzO75vRK5h6xBArLIARNPvkSjtQBMHlb1L07Qe7K" - "0GarZRmB_eSN9383LcOLn6_dO--xi12jzDwusC-eOkHWEsqtFZESc6BfI7noOPqv" - "hJ1phCnvWh6IeYI2w9QOYEUipUTI8np6LbgGY9Fs98rqVt5AXLIhWkWywlVmtVrB" - "p0igcN_IoypGlUPQGe77Rw" + *rfc7515_rsa_a1 = /* the signed worked example in RFC7515 A-1 */ + "eyJhbGciOiJSUzI1NiJ9" + ".eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt" + "cGxlLmNvbS9pc19yb290Ijp0cnVlfQ" + ".cC4hiUPoj9Eetdgtv3hF80EGrhuB__dzERat0XF9g2VtQgr9PJbu3XOiZj5RZmh7" + "AAuHIm4Bh-0Qc_lF5YKt_O8W2Fp5jujGbds9uJdbF9CUAr7t1dnZcAcQjbKBYNX4" + "BAynRFdiuB--f_nZLgrnbyTyWzO75vRK5h6xBArLIARNPvkSjtQBMHlb1L07Qe7K" + "0GarZRmB_eSN9383LcOLn6_dO--xi12jzDwusC-eOkHWEsqtFZESc6BfI7noOPqv" + "hJ1phCnvWh6IeYI2w9QOYEUipUTI8np6LbgGY9Fs98rqVt5AXLIhWkWywlVmtVrB" + "p0igcN_IoypGlUPQGe77Rw" +; -#if 0 - , - *rfc7515_ec_a3_jose = "{\"alg\":\"ES256\"}", - /* payload is the same as test2 above */ - *rfc7515_ec_a3_b64_serialization = - "eyJhbGciOiJFUzI1NiJ9" - "." - "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt" - "cGxlLmNvbS9pc19yb290Ijp0cnVlfQ" - "." - "DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSA" - "pmWQxfKTUJqPP3-Kg6NU1Q", - *rfc7515_ec_a3_jwk = - "{" +int +test_jws_RS256(struct lws_context *context) +{ + struct lws_jws_compact_map map; + struct lws_jose jose; + struct lws_jwk jwk; + struct lws_jws jws; + char temp[2048], *in; + int n, l, temp_len = sizeof(temp); + + lws_jose_init(&jose); + lws_jws_init(&jws, &jwk, context); + + /* Test 2: RS256 on RFC7515 worked example */ + + if (lws_gencrypto_jws_alg_to_definition("RS256", &jose.alg)) { + lwsl_err("%s: RS256 not supported\n", __func__); + goto bail; + } + + /* 2.1: import the jwk */ + + if (lws_jwk_import(&jwk, NULL, NULL, + rfc7515_rsa_key, strlen(rfc7515_rsa_key))) { + lwsl_notice("%s: 2.2: Failed to read JWK key\n", __func__); + goto bail2; + } + + if (jwk.kty != LWS_GENCRYPTO_KTY_RSA) { + lwsl_err("%s: 2.2: kty: %d instead of RSA\n", __func__, jwk.kty); + goto bail; + } + + /* 2.2: check the signature on the test packet from RFC7515 A-1 */ + + if (lws_jws_sig_confirm_compact_b64(rfc7515_rsa_a1, + strlen(rfc7515_rsa_a1), &map, + &jwk, context, temp, &temp_len) < 0) { + lwsl_notice("%s: 2.2: confirm rsa sig failed\n", __func__); + goto bail; + } + + if (lws_jws_b64_compact_map(rfc7515_rsa_a1, strlen(rfc7515_rsa_a1), + &jws.map_b64) != 3) { + lwsl_notice("%s: lws_jws_b64_compact_map failed\n", __func__); + goto bail; + } + + /* 2.3: generate our own signature for a copy of the test packet */ + + in = lws_concat_temp(temp, temp_len); + l = strlen(rfc7515_rsa_a1); + if (temp_len < l + 1) + goto bail; + memcpy(in, rfc7515_rsa_a1, l + 1); + temp_len -= l + 1; + + if (lws_jws_b64_compact_map(in, l, &jws.map_b64) != 3) { + lwsl_notice("%s: lws_jws_b64_compact_map failed\n", __func__); + goto bail; + } + + /* overwrite the copy of the known b64 sig (it's all placed inside temp) */ + n = lws_jws_sign_from_b64(&jose, &jws, + (char *)jws.map_b64.buf[LJWS_SIG], + jws.map_b64.len[LJWS_SIG] + 8); + if (n < 0) { + lwsl_err("%s: failed signing test packet\n", __func__); + goto bail; + } + jws.map_b64.len[LJWS_SIG] = n; + + /* 2.4: confirm our signature can be verified */ + + in[l] = '\0'; + if (lws_jws_sig_confirm_compact_b64(in, l, &map, &jwk, context, lws_concat_temp(temp, temp_len), &temp_len) < 0) { + lwsl_notice("%s: 2.2: confirm rsa sig failed\n", __func__); + goto bail; + } + + lws_jwk_destroy(&jwk); + + /* end */ + + lwsl_notice("%s: selftest OK\n", __func__); + + return 0; + +bail: + lws_jwk_destroy(&jwk); +bail2: + lws_jws_destroy(&jws); + lwsl_err("%s: selftest failed ++++++++++++++++++++\n", __func__); + + return 1; +} + +static const char + *es256_jose = "{\"alg\":\"ES256\"}", + *es256_payload = "{\"iss\":\"joe\",\r\n \"exp\":1300819380,\r\n" + " \"http://example.com/is_root\":true}", + *es256_cser = + "eyJhbGciOiJFUzI1NiJ9" + "." + "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt" + "cGxlLmNvbS9pc19yb290Ijp0cnVlfQ" + "." + "DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSA" + "pmWQxfKTUJqPP3-Kg6NU1Q", + *es256_jwk = + "{" "\"kty\":\"EC\"," "\"crv\":\"P-256\"," "\"x\":\"f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU\"," "\"y\":\"x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0\"," "\"d\":\"jpsQnnGQmL-YBIffH1136cspYG6-0iY7X1fCE9-E9LI\"" - "}", + "}" +#if 0 + , rfc7515_ec_a3_R[] = { 14, 209, 33, 83, 121, 99, 108, 72, 60, 47, 127, 21, 88, 7, 212, 2, 163, 178, 40, 3, 58, 249, 124, 126, 23, 129, @@ -109,152 +404,309 @@ static const char #endif ; -/* - * These are the inputs and outputs from the worked example in RFC7515 - * Appendix A.1. - * - * 1) has a fixed header + payload, and a fixed SHA256 HMAC key, and must give - * a fixed BASE64URL result. - * - * 2) has a fixed header + payload and is signed with a key given in JWK format - */ +int +test_jws_ES256(struct lws_context *context) +{ + uint8_t digest[LWS_GENHASH_LARGEST]; + struct lws_genhash_ctx hash_ctx; + struct lws_jws_compact_map map; + struct lws_jose jose; + struct lws_jwk jwk; + struct lws_jws jws; + char temp[2048], *p; + int ret = -1, l, n, temp_len = sizeof(temp); + + /* A.3 "ES256" RFC7515 worked example - verify */ + + lws_jose_init(&jose); + + /* decode the b64.b64[.b64] compact serialization blocks */ + if (lws_jws_compact_decode(es256_cser, strlen(es256_cser), + &jws.map, &jws.map_b64, + temp, &temp_len) != 3) { + lwsl_err("%s: concat_map failed\n", __func__); + goto bail; + } + + /* confirm the decoded JOSE header is exactly what we expect */ + if (jws.map.len[LJWS_JOSE] != strlen(es256_jose) || + strncmp(es256_jose, jws.map.buf[LJWS_JOSE], + jws.map.len[LJWS_JOSE])) { + lwsl_err("%s: jose b64 decode wrong\n", __func__); + goto bail; + } + + /* confirm the decoded payload is exactly what we expect */ + if (jws.map.len[LJWS_PYLD] != strlen(es256_payload) || + strncmp(es256_payload, jws.map.buf[LJWS_PYLD], + jws.map.len[LJWS_PYLD])) { + lwsl_err("%s: payload b64 decode wrong\n", __func__); + goto bail; + } + + /* parse the JOSE header */ + if (lws_jws_parse_jose(&jose, jws.map.buf[LJWS_JOSE], + jws.map.len[LJWS_JOSE], + (char *)lws_concat_temp(temp, temp_len), &temp_len) < 0) { + lwsl_err("%s: JOSE parse failed\n", __func__); + goto bail; + } + + /* confirm we used "ES256" alg we expect from the JOSE hdr */ + if (strcmp(jose.alg->alg, "ES256")) { + lwsl_err("%s: JOSE header has wrong alg\n", __func__); + goto bail; + } + + jws.jwk = &jwk; + jws.context = context; + + /* import the ES256 jwk */ + if (lws_jwk_import(&jwk, NULL, NULL, es256_jwk, strlen(es256_jwk))) { + lwsl_notice("%s: Failed to read JWK key\n", __func__); + goto bail; + } + + /* sanity */ + if (jwk.kty != LWS_GENCRYPTO_KTY_EC) { + lwsl_err("%s: kty: %d instead of EC\n", + __func__, jwk.kty); + goto bail1; + } + + if (lws_jws_sig_confirm(&jws.map_b64, &jws.map, &jwk, context) < 0) { + lwsl_notice("%s: confirm EC sig failed\n", __func__); + goto bail1; + } + + /* A.3 "ES256" RFC7515 worked example - sign */ + + l = strlen(es256_cser); + if (temp_len < l) + goto bail1; + p = lws_concat_temp(temp, temp_len); + memcpy(p, es256_cser, l + 1); + temp_len -= l + 1; + + /* scan the b64 compact serialization string to map the blocks */ + if (lws_jws_b64_compact_map(p, l, &jws.map_b64) != 3) + goto bail1; + + /* create the hash of the protected b64 part */ + if (lws_genhash_init(&hash_ctx, jose.alg->hash_type) || + lws_genhash_update(&hash_ctx, jws.map_b64.buf[LJWS_JOSE], + jws.map_b64.len[LJWS_JOSE]) || + lws_genhash_update(&hash_ctx, ".", 1) || + lws_genhash_update(&hash_ctx, jws.map_b64.buf[LJWS_PYLD], + jws.map_b64.len[LJWS_PYLD]) || + lws_genhash_destroy(&hash_ctx, digest)) { + lws_genhash_destroy(&hash_ctx, NULL); + + goto bail1; + } + + lwsl_hexdump(jws.map_b64.buf[LJWS_SIG], jws.map_b64.len[LJWS_SIG]); + + /* overwrite the copy of the known b64 sig (it's placed inside buf) */ + n = lws_jws_sign_from_b64(&jose, &jws, + (char *)jws.map_b64.buf[LJWS_SIG], + jws.map_b64.len[LJWS_SIG] + 8); + if (n < 0) { + lwsl_err("%s: failed signing test packet\n", __func__); + goto bail1; + } + jws.map_b64.len[LJWS_SIG] = n; + + lwsl_hexdump(jws.map_b64.buf[LJWS_SIG], jws.map_b64.len[LJWS_SIG]); + + /* 2.4: confirm our generated signature can be verified */ + + p[l] = '\0'; + if (lws_jws_sig_confirm_compact_b64(p, l, &map, &jwk, context, lws_concat_temp(temp, temp_len), &temp_len) < 0) { + lwsl_notice("%s: confirm our EC sig failed\n", __func__); + goto bail1; + } + + /* end */ + ret = 0; + +bail1: + lws_jwk_destroy(&jwk); + lws_jose_destroy(&jose); + +bail: + lwsl_notice("%s: selftest %s\n", __func__, ret < 0 ? "FAIL" : "OK"); + + return ret; +} + +static const char + *es512_jose = "{\"alg\":\"ES512\"}", + *es512_payload = "Payload", + *es512_cser = + "eyJhbGciOiJFUzUxMiJ9" + "." + "UGF5bG9hZA" + "." + "AdwMgeerwtHoh-l192l60hp9wAHZFVJbLfD_UxMi70cwnZOYaRI1bKPWROc-mZZq" + "wqT2SI-KGDKB34XO0aw_7XdtAG8GaSwFKdCAPZgoXD2YBJZCPEX3xKpRwcdOO8Kp" + "EHwJjyqOgzDO7iKvU8vcnwNrmxYbSW9ERBXukOXolLzeO_Jn", + *es512_jwk = + "{" + "\"kty\":\"EC\"," + "\"crv\":\"P-521\"," + "\"x\":\"AekpBQ8ST8a8VcfVOTNl353vSrDCLLJXmPk06wTjxrrjcBpXp5EOnYG_" + "NjFZ6OvLFV1jSfS9tsz4qUxcWceqwQGk\"," + "\"y\":\"ADSmRA43Z1DSNx_RvcLI87cdL07l6jQyyBXMoxVg_l2Th-x3S1WDhjDl" + "y79ajL4Kkd0AZMaZmh9ubmf63e3kyMj2\"," + "\"d\":\"AY5pb7A0UFiB3RELSD64fTLOSV_jazdF7fLYyuTw8lOfRhWg6Y6rUrPA" + "xerEzgdRhajnu0ferB0d53vM9mE15j2C\"" + "}" +; + +int +test_jws_ES512(struct lws_context *context) +{ + uint8_t digest[LWS_GENHASH_LARGEST]; + struct lws_genhash_ctx hash_ctx; + struct lws_jws_compact_map map; + struct lws_jose jose; + struct lws_jwk jwk; + struct lws_jws jws; + char temp[2048], *p; + int ret = -1, l, n, temp_len = sizeof(temp); + + /* A.4 "ES512" RFC7515 worked example - verify */ + + lws_jose_init(&jose); + + /* decode the b64.b64[.b64] compact serialization blocks */ + if (lws_jws_compact_decode(es512_cser, strlen(es512_cser), + &jws.map, &jws.map_b64, temp, + &temp_len) != 3) { + lwsl_err("%s: concat_map failed\n", __func__); + goto bail; + } + + /* confirm the decoded JOSE header is exactly what we expect */ + if (jws.map.len[LJWS_JOSE] != strlen(es512_jose) || + strncmp(es512_jose, jws.map.buf[LJWS_JOSE], + jws.map.len[LJWS_JOSE])) { + lwsl_err("%s: jose b64 decode wrong\n", __func__); + goto bail; + } + + /* confirm the decoded payload is exactly what we expect */ + if (jws.map.len[LJWS_PYLD] != strlen(es512_payload) || + strncmp(es512_payload, jws.map.buf[LJWS_PYLD], + jws.map.len[LJWS_PYLD])) { + lwsl_err("%s: payload b64 decode wrong\n", __func__); + goto bail; + } + + /* parse the JOSE header */ + if (lws_jws_parse_jose(&jose, jws.map.buf[LJWS_JOSE], + jws.map.len[LJWS_JOSE], + lws_concat_temp(temp, temp_len), &temp_len) < 0) { + lwsl_err("%s: JOSE parse failed\n", __func__); + goto bail; + } + + /* confirm we used "es512" alg we expect from the JOSE hdr */ + if (strcmp(jose.alg->alg, "ES512")) { + lwsl_err("%s: JOSE header has wrong alg\n", __func__); + goto bail; + } + + jws.jwk = &jwk; + jws.context = context; + + /* import the es512 jwk */ + if (lws_jwk_import(&jwk, NULL, NULL, es512_jwk, strlen(es512_jwk))) { + lwsl_notice("%s: Failed to read JWK key\n", __func__); + goto bail; + } + + /* sanity */ + if (jwk.kty != LWS_GENCRYPTO_KTY_EC) { + lwsl_err("%s: kty: %d instead of EC\n", + __func__, jwk.kty); + goto bail1; + } + + if (lws_jws_sig_confirm(&jws.map_b64, &jws.map, &jwk, context) < 0) { + lwsl_notice("%s: confirm EC sig failed\n", __func__); + goto bail1; + } + + /* A.3 "es512" RFC7515 worked example - sign */ + + l = strlen(es512_cser); + if (temp_len < l) + goto bail1; + p = lws_concat_temp(temp, temp_len); + memcpy(p, es512_cser, l + 1); + temp_len -= (l + 1); + + /* scan the b64 compact serialization string to map the blocks */ + if (lws_jws_b64_compact_map(p, l, &jws.map_b64) != 3) + goto bail1; + + /* create the hash of the protected b64 part */ + if (lws_genhash_init(&hash_ctx, jose.alg->hash_type) || + lws_genhash_update(&hash_ctx, jws.map_b64.buf[LJWS_JOSE], + jws.map_b64.len[LJWS_JOSE]) || + lws_genhash_update(&hash_ctx, ".", 1) || + lws_genhash_update(&hash_ctx, jws.map_b64.buf[LJWS_PYLD], + jws.map_b64.len[LJWS_PYLD]) || + lws_genhash_destroy(&hash_ctx, digest)) { + lws_genhash_destroy(&hash_ctx, NULL); + + goto bail1; + } + + /* overwrite the copy of the known b64 sig (it's placed inside buf) */ + n = lws_jws_sign_from_b64(&jose, &jws, + (char *)jws.map_b64.buf[LJWS_SIG], 1024); + if (n < 0) { + lwsl_err("%s: failed signing test packet\n", __func__); + goto bail1; + } + jws.map_b64.len[LJWS_SIG] = n; + + /* 2.4: confirm our generated signature can be verified */ + + p[l] = '\0'; + + if (lws_jws_sig_confirm_compact_b64(p, l, &map, &jwk, context, + lws_concat_temp(temp, temp_len), &temp_len) < 0) { + lwsl_notice("%s: confirm our ECDSA sig failed\n", __func__); + goto bail1; + } + + /* end */ + ret = 0; + +bail1: + lws_jwk_destroy(&jwk); + lws_jose_destroy(&jose); + +bail: + lwsl_notice("%s: selftest %s\n", __func__, ret < 0 ? "FAIL" : "OK"); + + return ret; +} + int test_jws(struct lws_context *context) { - char buf[2048], *p = buf, *end = buf + sizeof(buf) - 1, *enc_ptr, *p1; - const struct lws_jose_jwe_alg *jose_alg; - uint8_t digest[LWS_GENHASH_LARGEST]; - struct lws_genhmac_ctx ctx; - struct lws_jwk jwk; - int n; + int n = 0; - /* Test 1: SHA256 on RFC7515 worked example */ + n |= test_jws_none(context); + n |= test_jws_HS256(context); + n |= test_jws_RS256(context); + n |= test_jws_ES256(context); + n |= test_jws_ES512(context); - /* 1.1: decode the JWK oct key */ - - if (lws_jwk_import(&jwk, NULL, NULL, key_jwk, strlen(key_jwk)) < 0) { - lwsl_notice("Failed to decode JWK test key\n"); - return -1; - } - if (jwk.kty != LWS_GENCRYPTO_KYT_OCT) { - lwsl_err("%s: unexpected kty %d\n", __func__, jwk.kty); - - return -1; - } - - /* 1.2: create JWS known hdr + known payload */ - - n = lws_jws_encode_section(test1, strlen(test1), 1, &p, end); - if (n < 0) - goto bail; - if (strcmp(buf, test1_enc)) - goto bail; - - enc_ptr = p + 1; /* + 1 skips the . */ - n = lws_jws_encode_section(test2, strlen(test2), 0, &p, end); - if (n < 0) - goto bail; - if (strcmp(enc_ptr, test2_enc)) - goto bail; - - /* 1.3: use HMAC SHA-256 with known key on the hdr . payload */ - - if (lws_genhmac_init(&ctx, LWS_GENHMAC_TYPE_SHA256, - jwk.e[LWS_GENCRYPTO_OCT_KEYEL_K].buf, - jwk.e[LWS_GENCRYPTO_OCT_KEYEL_K].len)) - goto bail; - if (lws_genhmac_update(&ctx, (uint8_t *)buf, p - buf)) - goto bail_destroy_hmac; - lws_genhmac_destroy(&ctx, digest); - - /* 1.4: append a base64 encode of the computed HMAC digest */ - - enc_ptr = p + 1; /* + 1 skips the . */ - n = lws_jws_encode_section((const char *)digest, 32, 0, &p, end); - if (n < 0) - goto bail; - if (strcmp(enc_ptr, hash_enc)) { /* check against known B64URL hash */ - lwsl_err("%s: b64 enc of computed HMAC mismatches '%s' '%s'\n", - __func__, enc_ptr, hash_enc); - goto bail; - } - - /* 1.5: Check we can agree the signature matches the payload */ - - if (lws_jws_confirm_sig(buf, p - buf, &jwk, context) < 0) { - lwsl_notice("confirm sig failed\n"); - goto bail; - } - - lws_jwk_destroy(&jwk); /* finished with the key from the first test */ - - /* Test 2: RSA256 on RFC7515 worked example */ - - /* 2.1: turn the known JWK key for the RSA test into a lws_jwk */ - - if (lws_jwk_import(&jwk, NULL, NULL, - rfc7515_rsa_key, strlen(rfc7515_rsa_key))) { - lwsl_notice("%s: 2.2: Failed to read JWK key\n", __func__); - goto bail2; - } - - if (jwk.kty != LWS_GENCRYPTO_KYT_RSA) { - lwsl_err("%s: 2.2: kty: %d instead of RSA\n", __func__, jwk.kty); - } - - /* 2.2: check the signature on the test packet from RFC7515 A-1 */ - - if (lws_jws_confirm_sig(rfc7515_rsa_a1, strlen(rfc7515_rsa_a1), - &jwk, context) < 0) { - lwsl_notice("%s: 2.2: confirm rsa sig failed\n", __func__); - goto bail; - } - - /* 2.3: generate our own signature for a copy of the test packet */ - - memcpy(buf, rfc7515_rsa_a1, strlen(rfc7515_rsa_a1)); - - /* set p to second . */ - p = strchr(buf + 1, '.'); - p1 = strchr(p + 1, '.'); - - if (lws_gencrypto_jwe_alg_to_definition("RSA1_5", &jose_alg)) { - lwsl_err("%s: RSA1_5 not supported\n", __func__); - goto bail; - } - - n = lws_jws_sign_from_b64(buf, p - buf, p + 1, p1 - (p + 1), - p1 + 1, sizeof(buf) - (p1 - buf) - 1, - jose_alg, &jwk, context); - if (n < 0) { - lwsl_err("%s: failed signing test packet\n", __func__); - goto bail; - } - - // puts(buf); - - /* 2.4: confirm our signature can be verified */ - - if (lws_jws_confirm_sig(buf, (p1 + 1 + n) - buf, &jwk, context) < 0) { - lwsl_notice("confirm rsa sig 2 failed\n"); - goto bail; - } - - lws_jwk_destroy(&jwk); - - /* end */ - - lwsl_notice("%s: selftest OK\n", __func__); - - return 0; - -bail_destroy_hmac: - lws_genhmac_destroy(&ctx, NULL); - -bail: - lws_jwk_destroy(&jwk); -bail2: - lwsl_err("%s: selftest failed ++++++++++++++++++++\n", __func__); - - return 1; + return n; } diff --git a/minimal-examples/api-tests/api-test-lwsac/main.c b/minimal-examples/api-tests/api-test-lwsac/main.c index 854e0adc2..029d4b2aa 100644 --- a/minimal-examples/api-tests/api-test-lwsac/main.c +++ b/minimal-examples/api-tests/api-test-lwsac/main.c @@ -39,6 +39,8 @@ int main(int argc, const char **argv) for (n = 0; n < 1000; n++) { m = lwsac_use(&lwsac, sizeof(*m), 0); + if (!m) + return -1; m->payload = n; lws_list_ptr_insert(&list_head, &m->list_next, NULL); diff --git a/minimal-examples/crypto/README.md b/minimal-examples/crypto/README.md new file mode 100644 index 000000000..1fc34794c --- /dev/null +++ b/minimal-examples/crypto/README.md @@ -0,0 +1,5 @@ +|name|tests| +---|--- +minimal-crypto-jwe|Examples for lws RFC7516 JWE apis +minimal-crypto-jwk|Examples for lws RFC7517 JWK apis + diff --git a/minimal-examples/crypto/minimal-crypto-jwe/CMakeLists.txt b/minimal-examples/crypto/minimal-crypto-jwe/CMakeLists.txt new file mode 100644 index 000000000..05f737669 --- /dev/null +++ b/minimal-examples/crypto/minimal-crypto-jwe/CMakeLists.txt @@ -0,0 +1,77 @@ +cmake_minimum_required(VERSION 2.8) +include(CheckCSourceCompiles) + +set(SAMP lws-crypto-jwe) +set(SRCS main.c) + +# If we are being built as part of lws, confirm current build config supports +# reqconfig, else skip building ourselves. +# +# If we are being built externally, confirm installed lws was configured to +# support reqconfig, else error out with a helpful message about the problem. +# +MACRO(require_lws_config reqconfig _val result) + + if (DEFINED ${reqconfig}) + if (${reqconfig}) + set (rq 1) + else() + set (rq 0) + endif() + else() + set(rq 0) + endif() + + if (${_val} EQUAL ${rq}) + set(SAME 1) + else() + set(SAME 0) + endif() + + if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME}) + if (${_val}) + message("${SAMP}: skipping as lws being built without ${reqconfig}") + else() + message("${SAMP}: skipping as lws built with ${reqconfig}") + endif() + set(${result} 0) + else() + if (LWS_WITH_MINIMAL_EXAMPLES) + set(MET ${SAME}) + else() + CHECK_C_SOURCE_COMPILES("#include \nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig}) + if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig}) + set(HAS_${reqconfig} 0) + else() + set(HAS_${reqconfig} 1) + endif() + if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val})) + set(MET 1) + else() + set(MET 0) + endif() + endif() + if (NOT MET) + if (${_val}) + message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}") + else() + message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project") + endif() + endif() + endif() +ENDMACRO() + +set(requirements 1) +require_lws_config(LWS_WITH_JOSE 1 requirements) + +if (requirements) + + add_executable(${SAMP} ${SRCS}) + + if (websockets_shared) + target_link_libraries(${SAMP} websockets_shared) + add_dependencies(${SAMP} websockets_shared) + else() + target_link_libraries(${SAMP} websockets) + endif() +endif() diff --git a/minimal-examples/crypto/minimal-crypto-jwe/README.md b/minimal-examples/crypto/minimal-crypto-jwe/README.md new file mode 100644 index 000000000..a7dcfb75c --- /dev/null +++ b/minimal-examples/crypto/minimal-crypto-jwe/README.md @@ -0,0 +1,69 @@ +# lws minimal example for JWE + +Demonstrates how to encrypt and decrypt using JWE and JWK, providing a +commandline tool for creating encrypted JWE and decoding them. + +## build + +``` + $ cmake . && make +``` + +## usage + +Stdin is either the plaintext (if encrypting) or JWE (if decrypting). + +Stdout is either the JWE (if encrypting) or plaintext (if decrypting). + +You must pass a private or public key JWK file in the -k option if encrypting, +and must pass a private key JWK file in the -k option if decrypting. To be +clear, for asymmetric keys the public part of the key is required to encrypt, +and the private part required to decrypt. + +For convenience, a pair of public and private keys are provided, +`key-rsa-4096.private` and `key-rsa-4096.pub`, these were produced with just + +``` + $ lws-crypto-jwk -t RSA -b 4096 --public key-rsa-4096.pub >key-rsa-4096.private +``` + +Similar keys for EC modes may be produced with + +``` + $ lws-crypto-jwk -t EC -v P-256 --public key-ecdh-p-256.pub >key-ecdh-p-256.private +``` + +and for AES ("octet") symmetric keys + +``` + $ lws-crypto-jwk -t OCT -b 128 >key-aes-128.private +``` + +JWEs produced with openssl and mbedtls backends are completely interchangeable. + +Commandline option|Meaning +---|--- +-d |Debug verbosity in decimal, eg, -d15 +-e " "|Encrypt (default is decrypt), eg, -e "RSA1_5 A128CBC-HS256". For decrypt, the cipher information comes from the input JWE. +-k |JWK file to encrypt or decrypt with +-c|Format the JWE as a linebroken C string + +``` + $ echo -n "plaintext0123456" | ./lws-crypto-jwe -k key-rsa-4096.private -e "RSA1_5 A128CBC-HS256" +[2018/12/19 16:20:25:6519] USER: LWS JWE example tool +[2018/12/19 16:20:25:6749] NOTICE: Creating Vhost 'default' (serving disabled), 1 protocols, IPv6 off +eyJhbGciOiJSU0ExXzUiLCAiZW5jIjoiQTEyOENCQy1IUzI1NiJ9.ivFr7qzx-pQ4V_edbjpdvR9OwWL9KmojPE2rXQM52oLtW0BtnxZu2_ezqhsAelyIcaworgfobs3u4bslXHMFbeJJjPb5xD0fBDe64OYXZH1NpUGTMJh9Ka4CrJ2B3xhxe7EByGAuGqmluqE0Yezj7rhSw7vlr5JAwuOJ8FaGa8aZ8ldki5G5h_S2Furlbjdcw3Rrxk7mCoMHcLoqzfZtggMPwGAMFogCqcwUo7oSLbBeGaa6hpMbfSysugseWdr8TzObQKPM52k6iVAlGwRaOg_qdLMgZiYRhHA6nFKTQd7XBbNY6qAS8sPuj7Zz344tF3RSfJ0zX_telG71sOtVv5fMpeDU-eCdpOWlCBfu6J6FQfAFu6SJryM4ajGOif09CwFI5qUQ33SOfQfS_M3nqSyd6Vu5M4lsDrb5wK7_XX5gqUwvI9wicf_8WWR-CQomRF-JvEASnA2SIf8QqYfa8R2rP9q6Md4vwO4EZrtxIsMDPsH-4ZEFu7vDjyy09QfIWWsnEb8-UgpVXensgt2m_2bZ76r1VB8-0nZLMwMyEhaH2wra9vX2FWao5UkmNJ7ht300f4_V6QzMFoePpwCvsufWBW6jcQLB-frCWe6uitWaZHEB4LxmNPKzQSz4QwwTKhpF1jNn8Xh1-w1m-2h0gj-oe-S8QBwPveqhPI1p2fI.snuhUTXHNu5mJ6dEPQqg6g.yl36qC4o0GE4nrquQ2YyCg.Vf0MoT7_kUrZdCNWXhq1DQ +``` + +Notice the logging is on stderr, and the output alone on stdout. + +You can also pipe the output of the encrypt action directly into the decrypt +action, eg + +``` + $ echo -n "plaintext0123456" | \ + ./lws-crypto-jwe -k key-rsa-4096.pub -e "RSA1_5 A128CBC-HS256" | \ + ./lws-crypto-jwe -k key-rsa-4096.private +``` + +prints the plaintext on stdout. diff --git a/minimal-examples/crypto/minimal-crypto-jwe/key-rsa-4096.private b/minimal-examples/crypto/minimal-crypto-jwe/key-rsa-4096.private new file mode 100644 index 000000000..10841439a --- /dev/null +++ b/minimal-examples/crypto/minimal-crypto-jwe/key-rsa-4096.private @@ -0,0 +1 @@ +{"d":"XcSl3ulvs4OGomu9thRPVQGOstim0PY7CibP_bnCmzjvmGmzb8J4q5AUmJCnZT5TesOzXuXhyG95CxQWsakd9GWHSAinV1QQSLsahaezPULRG1qmo37JqKb9noKkvXguh5XU5np8HjeoeeEkF_XqtCdEo0wHijEjTL9RZar98jmyAmlizoHIY9NnECavs4DZB27onU61B61vGpw-y4xhC9jlZSIwRqIMDzeTcSv8fRKcVYR80ozm2_KwWMpue27rS2EfTQUtsMXuYmnvMAf_DHqA0tNWyD1gpUWYHvlyBh5xnYrWPuXxQBRNesImQdRQl5VMMsuvdtY-uZfIVUdN5CcsB0acronx4UsmVg-Qz-jd1NVW4koZQM9uA4oWiMZg4FEUTQ-UWelHCldg-PYLAazsItmaHPF9LcAPkLkI8jaVS33v-DhSeXHW3Pg3sibtnPhouiSvD84zMtzu1gjFT7vtapMynBeZouqeWYT-BFeu2wzppJcW1YxTQ_Ai80VJSFY__Huw-9r1MOHmDRcEW7x9W97UezWDjrh5Shhh4C6SMYbaf7ouACzFu1i_r8Q06JqKA7aY8i5izKlKA0We9tQKlTF8Fgsneu9gpxFglvZsd1ersiA-MkuP9qTBQpyAf3kJ6HS9GrQUju6r3DExdWDjdvM5Grt8QD7Zkv-qXeE","dp":"M-LFs3T2GI1JxD5LJt2GgV4cMDKbiPKBddLukfG0duUxNp0-6x2LZ0ptxrlHrhxBMMmvCg4GEaujrZdaYWCar6xCnlnkVlOELz4yZ3JBSpS86thJw03xuE7lyeR7usFY4CpSqUQGI_YveITuFeoh4YjwdKDuqPhOpDI-34ptgU93dlBRS9nnQFTiVoUdP4bhGTKOpULTiLgPXHQxQR5rfiGVD9AIwqHvMdBQ0hxQBKEt37PbRWK_eTzMslHZGWNfbg8ipwJxisvHyUn0c1X3Uelw8BRyvNVCNovNDeCj-R7kFkMvriMd_sqGVy1Go46WZ2wMkUJHkvmYk0gDlhnTGQ","dq":"qO89nQEJfdkaDtGGyD-sQE2Mm8p_PIPSpCmgMfpl8zgSOb4P9iqXBgpHyS7w10uY_UHt8KW6pY7ozy0y4Gu_f4Wk_rcXiYYdbuIhlFl0_nLI2mfFPGxr1xC64zfjjEaBr4zIJr_YzhvTpjZFtIdSAH5VG5Tv-2yUtCC2DnKnU2kzEkgUeSI6LHOEVhXqup7C0Kjiv9FJsLR0hiqwH4oLziqH7EVqVDvJI3yL1lhqoLKjAu1ogTDgH7hzSrqVhttnpwL8rDcgbtY6Q8C2csdN3Jt1ucgtGy-Yzgqf_QIULP3CRlqzDTvHrMe2A9cNAQ4dNsCbNAjW_MxxGKKWuWXAMQ","e":"AQAB","kid":"my kid","kty":"RSA","n":"2_YjG_D1sOWJxs6cohikupHf5WJfWSFfSCrnNZ7WR7AyTLnKZAF4VKyimMeJTLYYwCAXMDD5XmkF8VluI4O-hASUIJ7F9eDg3vO7nPwtkWa9lkqt-QyQZ_PjiOGpwetBLzrsaXsC9PvdVzrKXnjeNPsmmbC_Fx2cUn4H_9H_WfXi01VR75XFTBtxTrDY7hmpZHuFCFUOMCW9siTZRk9339Y6ORBznBs4jFbkGI1Pmc3op0o5f8S1gus9L81W5uyUrxfd-CkmJ6eWE8I36cfzI6irN2bhVhR_NXERUtS0QOEeJYlRJXqfYkxTMVlsXPl6zbYt__ZYLC6ZiUTCc6K2KmfGh7fihWbao4dyQW3Mq4kClhpIT0O01Y0r7sR1j4jTnFNqbmtPSl9lEMrfiUHfOLqRJo3qizQ-b6HLCDty1otFz8Q8gg0rD3copQ_zFrcTGwJGAv2Absraj7kp9EJXBqneCJ3dlRO8rzx7KB9Dsj-ygh3kZaubkPCeT1v4l_VUY2iGnK4vzIGKM7j56DQ97ZAi1Bb0y6GYSbrWB2_z0DKJu0fiU-NscbKplR68vgppUM6_iogrk48JEZg_kkTymniqbT3g7J_WeoZSx1Uu8ZHI3ysIFfUtFscOa2SJGlj1ds-lfk6Oqac_I8ahRqQeyVAEisZPmYIGSJajbJopJ4s","p":"_V4CwEjRd8Hv9-ncqGdB_vtReTIuHSWQzSx4al15J3VxvPFI2kxicNeQKyq3OAVT2kmCmUP3ETgCdwuKIgw_QbEc8qNxtS_KpM_KsuTe9a5jrQKpt8ctYhzELZfr_sy9UzUGJzr8glLjJ1IDX4x6_JAqYB_NhttP6bzgu5Dt-DKtRPNO1qZtfhrLIgmltpC2M6-AlAv-dyHSHck2VJIL84Hwk4FulozEYxop0dKuZdfM5Z1dZM8-ICo62O0zUKzoWxKmQcB9_gDZsxYaO6xZ9BLmaW6-WcPSEI6YDnPk8ptnk_Kbyc4kPW4Z3ASczxjaewBmfl2_lwkqkndFVptAeQ","q":"3j9DR6ZpKC3WrshSrxXFYAuT19Rlf6qQ_9uD_Fq7dIpTjCZdl01695Qx7UmujKoetutL3RMCpeRdZR-gCLVh8aMxpMuIc5fHC6HbhsdF-I7GoqO0DEJ6coS3n5Ey4EXL5uoLh4C3l67wBKfLmPW28bxxG2QAP59jncWXkrBQm_qbS5Qon8r7wj0tejG_tGdsPjhsFc9KdnkkBucT6MiEVpzpdwDlsn7bHpMsyPlNyc0fj5qYmRB-DN7rv5varaisBaVT0mLQdwKjBDVqNVnU2m5azPhY-2txvihHaI5_cLIsLLaqKMbB17UxGumuT_o8S03_h8-1syO3Ay87y9pPIw","qi":"JY2uUek6wPrp4fPcInX_5WdNlhyghcGVEvlqxs9iOEUeCtUc6d42n9tgiImMu605dQaigvNaH5y1pwDpLlmxUk0nOUVxqo9mv0Uw8WNXB88FyDb0fPbewLpn4Fskb8Umv6_OymJ1W814DRG-jq3sI5DsB7AjtqJQ22nP2Vs1bIrx5fUxuScwrMsWSrrjAx4Kr8-5eeSDqE-_c7DPZ_zSPYDoHaMeR2pZfNAq3mEbxp8jMukzh77rYZ3ffQEA6AyxFSCSCrxVozhP4ypQ0jAkXVWOlj4nuV6briIqlL3ZboydwsIolRwaPSgH6-bw03XS6Hb9DA0KHJKLun94N9n5kw","use":"enc"} diff --git a/minimal-examples/crypto/minimal-crypto-jwe/key-rsa-4096.pub b/minimal-examples/crypto/minimal-crypto-jwe/key-rsa-4096.pub new file mode 100644 index 000000000..e2bd85c22 --- /dev/null +++ b/minimal-examples/crypto/minimal-crypto-jwe/key-rsa-4096.pub @@ -0,0 +1 @@ +{"e":"AQAB","kid":"my kid","kty":"RSA","n":"2_YjG_D1sOWJxs6cohikupHf5WJfWSFfSCrnNZ7WR7AyTLnKZAF4VKyimMeJTLYYwCAXMDD5XmkF8VluI4O-hASUIJ7F9eDg3vO7nPwtkWa9lkqt-QyQZ_PjiOGpwetBLzrsaXsC9PvdVzrKXnjeNPsmmbC_Fx2cUn4H_9H_WfXi01VR75XFTBtxTrDY7hmpZHuFCFUOMCW9siTZRk9339Y6ORBznBs4jFbkGI1Pmc3op0o5f8S1gus9L81W5uyUrxfd-CkmJ6eWE8I36cfzI6irN2bhVhR_NXERUtS0QOEeJYlRJXqfYkxTMVlsXPl6zbYt__ZYLC6ZiUTCc6K2KmfGh7fihWbao4dyQW3Mq4kClhpIT0O01Y0r7sR1j4jTnFNqbmtPSl9lEMrfiUHfOLqRJo3qizQ-b6HLCDty1otFz8Q8gg0rD3copQ_zFrcTGwJGAv2Absraj7kp9EJXBqneCJ3dlRO8rzx7KB9Dsj-ygh3kZaubkPCeT1v4l_VUY2iGnK4vzIGKM7j56DQ97ZAi1Bb0y6GYSbrWB2_z0DKJu0fiU-NscbKplR68vgppUM6_iogrk48JEZg_kkTymniqbT3g7J_WeoZSx1Uu8ZHI3ysIFfUtFscOa2SJGlj1ds-lfk6Oqac_I8ahRqQeyVAEisZPmYIGSJajbJopJ4s"} diff --git a/minimal-examples/crypto/minimal-crypto-jwe/main.c b/minimal-examples/crypto/minimal-crypto-jwe/main.c new file mode 100644 index 000000000..e3e28551d --- /dev/null +++ b/minimal-examples/crypto/minimal-crypto-jwe/main.c @@ -0,0 +1,264 @@ +/* + * lws-crypto-jwe + * + * Copyright (C) 2018 Andy Green + * + * This file is made available under the Creative Commons CC0 1.0 + * Universal Public Domain Dedication. + */ + +#include +#include +#include + +/* + * handles escapes and line wrapping suitable for use + * defining a C char array ( -c option ) + */ + +static void +format_c(const char *key) +{ + const char *k = key; + int seq = 0; + + while (*k) { + if (*k == '{') { + putchar('\"'); + putchar('{'); + putchar('\"'); + putchar('\n'); + putchar('\t'); + putchar('\"'); + k++; + seq = 0; + continue; + } + if (*k == '}') { + putchar('\"'); + putchar('\n'); + putchar('\"'); + putchar('}'); + putchar('\"'); + putchar('\n'); + k++; + seq = 0; + continue; + } + if (*k == '\"') { + putchar('\\'); + putchar('\"'); + seq += 2; + k++; + continue; + } + if (*k == ',') { + putchar(','); + putchar('\"'); + putchar('\n'); + putchar('\t'); + putchar('\"'); + k++; + seq = 0; + continue; + } + putchar(*k); + seq++; + if (seq >= 60) { + putchar('\"'); + putchar('\n'); + putchar('\t'); + putchar(' '); + putchar('\"'); + seq = 1; + } + k++; + } +} + +int main(int argc, const char **argv) +{ + int n, enc = 0, result = 0, + logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE; + char temp[32768], compact[32768], *in; + struct lws_context_creation_info info; + int temp_len = sizeof(temp); + struct lws_context *context; + struct lws_jose jose; + struct lws_jwk jwk; + struct lws_jws jws; + const char *p; + + if ((p = lws_cmdline_option(argc, argv, "-d"))) + logs = atoi(p); + + lws_set_log_level(logs, NULL); + lwsl_user("LWS JWE example tool\n"); + + memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ + info.port = CONTEXT_PORT_NO_LISTEN; + info.options = 0; + + context = lws_create_context(&info); + if (!context) { + lwsl_err("lws init failed\n"); + return 1; + } + + lws_jose_init(&jose); + lws_jws_init(&jws, &jwk, context); + + /* if encrypting, set the ciphers */ + + if ((p = lws_cmdline_option(argc, argv, "-e"))) { + char *sp = strchr(p, ' '); + + if (!sp) { + lwsl_err("format: -e \" " + "\", eg, " + "-e \"RSA1_5 A128CBC-HS256\"\n"); + + return 1; + } + *sp = '\0'; + if (lws_gencrypto_jwe_alg_to_definition(p, &jose.alg)) { + lwsl_err("Unknown cipher alg %s\n", p); + return 1; + } + if (lws_gencrypto_jwe_enc_to_definition(sp + 1, &jose.enc_alg)) { + lwsl_err("Unknown payload enc alg %s\n", sp + 1); + return 1; + } + + /* create JOSE header, also needed for output */ + + if (lws_jws_alloc_element(&jws.map, LJWS_JOSE, + lws_concat_temp(temp, temp_len), + &temp_len, strlen(p) + + strlen(sp + 1) + 16, 0)) { + lwsl_err("%s: temp space too small\n", __func__); + return 1; + } + + jws.map.len[LJWS_JOSE] = lws_snprintf( + (char *)jws.map.buf[LJWS_JOSE], temp_len, + "{\"alg\":\"%s\",\"enc\":\"%s\"}", p, sp + 1); + + enc = 1; + } + + in = lws_concat_temp(temp, temp_len); + n = read(0, in, temp_len); + if (n < 0) { + lwsl_err("Problem reading from stdin\n"); + return 1; + } + temp_len -= n; + + /* grab the key */ + + if ((p = lws_cmdline_option(argc, argv, "-k"))) { + if (lws_jwk_load(&jwk, p, NULL, NULL)) { + lwsl_err("%s: problem loading JWK %s\n", __func__, p); + + return 1; + } + } else { + lwsl_err("-k is required\n"); + + return 1; + } + + if (enc) { + + /* point CTXT to the plaintext we read from stdin */ + + jws.map.buf[LJWE_CTXT] = in; + jws.map.len[LJWE_CTXT] = n; + + /* + * Create a random CEK and set EKEY to it + * CEK size is determined by hash / hmac size + */ + + n = lws_gencrypto_bits_to_bytes(jose.enc_alg->keybits_fixed); + if (lws_jws_randomize_element(context, &jws.map, LJWE_EKEY, + lws_concat_temp(temp, temp_len), + &temp_len, n, + LWS_JWE_LIMIT_KEY_ELEMENT_BYTES)) { + lwsl_err("Problem getting random\n"); + goto bail1; + } + + /* perform the encryption of the CEK and the plaintext */ + + n = lws_jwe_encrypt(&jose, &jws, + lws_concat_temp(temp, temp_len), + &temp_len); + if (n < 0) { + lwsl_err("%s: lws_jwe_encrypt failed\n", __func__); + goto bail1; + } + + /* output the JWE in compact form */ + + n = lws_jwe_write_compact(&jose, &jws, compact, sizeof(compact)); + if (n < 0) { + lwsl_err("%s: lws_jwe_write_compact failed: %d\n", + __func__, n); + goto bail1; + } + + if (lws_cmdline_option(argc, argv, "-c")) + format_c(compact); + else + if (write(1, compact, strlen(compact)) < 0) { + lwsl_err("Write stdout failed\n"); + goto bail1; + } + } else { + + /* + * converts a compact serialization to b64 + decoded maps + * held in jws + */ + if (lws_jws_compact_decode(in, n, &jws.map, &jws.map_b64, + lws_concat_temp(temp, temp_len), + &temp_len) != 5) { + lwsl_err("%s: lws_jws_compact_decode failed\n", + __func__); + goto bail1; + } + + /* + * Do the crypto according to what we parsed into the jose + * (information on the ciphers) and the jws (plaintext and + * signature info) + */ + + n = lws_jwe_auth_and_decrypt(&jose, &jws); + if (n < 0) { + lwsl_err("%s: lws_jwe_auth_and_decrypt failed\n", + __func__); + goto bail1; + } + + /* if it's valid, dump the plaintext and return 0 */ + + if (write(1, jws.map.buf[LJWE_CTXT], jws.map.len[LJWE_CTXT]) < 0) { + lwsl_err("Write stdout failed\n"); + goto bail1; + } + } + + result = 0; + +bail1: + + lws_jws_destroy(&jws); + lws_jwk_destroy(&jwk); + + lws_context_destroy(context); + + return result; +} diff --git a/minimal-examples/crypto/minimal-crypto-jwk/CMakeLists.txt b/minimal-examples/crypto/minimal-crypto-jwk/CMakeLists.txt new file mode 100644 index 000000000..fb8c3e372 --- /dev/null +++ b/minimal-examples/crypto/minimal-crypto-jwk/CMakeLists.txt @@ -0,0 +1,77 @@ +cmake_minimum_required(VERSION 2.8) +include(CheckCSourceCompiles) + +set(SAMP lws-crypto-jwk) +set(SRCS main.c) + +# If we are being built as part of lws, confirm current build config supports +# reqconfig, else skip building ourselves. +# +# If we are being built externally, confirm installed lws was configured to +# support reqconfig, else error out with a helpful message about the problem. +# +MACRO(require_lws_config reqconfig _val result) + + if (DEFINED ${reqconfig}) + if (${reqconfig}) + set (rq 1) + else() + set (rq 0) + endif() + else() + set(rq 0) + endif() + + if (${_val} EQUAL ${rq}) + set(SAME 1) + else() + set(SAME 0) + endif() + + if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME}) + if (${_val}) + message("${SAMP}: skipping as lws being built without ${reqconfig}") + else() + message("${SAMP}: skipping as lws built with ${reqconfig}") + endif() + set(${result} 0) + else() + if (LWS_WITH_MINIMAL_EXAMPLES) + set(MET ${SAME}) + else() + CHECK_C_SOURCE_COMPILES("#include \nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig}) + if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig}) + set(HAS_${reqconfig} 0) + else() + set(HAS_${reqconfig} 1) + endif() + if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val})) + set(MET 1) + else() + set(MET 0) + endif() + endif() + if (NOT MET) + if (${_val}) + message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}") + else() + message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project") + endif() + endif() + endif() +ENDMACRO() + +set(requirements 1) +require_lws_config(LWS_WITH_JOSE 1 requirements) + +if (requirements) + + add_executable(${SAMP} ${SRCS}) + + if (websockets_shared) + target_link_libraries(${SAMP} websockets_shared) + add_dependencies(${SAMP} websockets_shared) + else() + target_link_libraries(${SAMP} websockets) + endif() +endif() diff --git a/minimal-examples/crypto/minimal-crypto-jwk/README.md b/minimal-examples/crypto/minimal-crypto-jwk/README.md new file mode 100644 index 000000000..6807746c2 --- /dev/null +++ b/minimal-examples/crypto/minimal-crypto-jwk/README.md @@ -0,0 +1,51 @@ +# lws minimal example for JWK + +Demonstrates how to generate and format any kind of supported new random JWK keys. + +The full private key is output to stdout, a version of the key with the private +part removed and some metadata adapted can be saved to a file at the same time +using `--public `. In the public form, `key_ops` and `use` elements are +adjusted to remove activities that require a private key. + +Key elements are output in strict RFC7638 lexicographic order as required by +some applications. + +Keys produced with openssl and mbedtls backends are completely interchangeable. + +## build + +``` + $ cmake . && make +``` + +## usage + +Commandline option|Meaning +---|--- +-d |Debug verbosity in decimal, eg, -d15 +-t |RSA, OCT or EC +-b |For RSA and OCT, key size in bits +-v |For EC keys, the curve, eg, "P-384"... this implies the key bits +--kid "ID string"|Key identity string +--use "use[ use]"|Key use restriction (mutually exclusive with --key-ops): sig, enc +--key-ops "op[ op]"|Key valid operations (mutually exclusive with --use): sign, verify, encrypt, decrypt, wrapKey, unwrapKey, deriveKey, deriveBits +-c|Format the jwk as a linebroken C string +--public |Only output the full, private key, not the public version first + +For legibility the example uses -c, however this + +``` + $ ./lws-crypto-jwk -t EC -v P-256 --key-ops "sign verify" --public mykey.pub +[2018/12/18 20:19:29:6972] USER: LWS JWK example +[2018/12/18 20:19:29:7200] NOTICE: Creating Vhost 'default' (serving disabled), 1 protocols, IPv6 off +[2018/12/18 20:19:29:7251] NOTICE: lws_jwk_generate: generating ECDSA key on curve P-256 +{"crv":"P-256","d":"eMKM_S4BTL2aiebZLqvxglufV2YX4b3_32DesgEUOaM","key_ops":["sign","verify"],"kty":"EC","x":"OWauiGGtJ60ZegtqlwETQlmO1exTZdWbT2VbUs4a1hg","y":"g_eNOlqPecbguVQArL6Fd4T5xZthBgipNCBypXubPos"} +``` + +The output in `mykey.pub` is: + +``` +{"crv":"P-256","key_ops":["verify"],"kty":"EC","x":"OWauiGGtJ60ZegtqlwETQlmO1exTZdWbT2VbUs4a1hg","y":"g_eNOlqPecbguVQArL6Fd4T5xZthBgipNCBypXubPos"} +``` + +Notice the logging goes out on stderr, the key data goes on stdout. diff --git a/minimal-examples/crypto/minimal-crypto-jwk/main.c b/minimal-examples/crypto/minimal-crypto-jwk/main.c new file mode 100644 index 000000000..330898f4c --- /dev/null +++ b/minimal-examples/crypto/minimal-crypto-jwk/main.c @@ -0,0 +1,187 @@ +/* + * lws-crypto-jwk + * + * Copyright (C) 2018 Andy Green + * + * This file is made available under the Creative Commons CC0 1.0 + * Universal Public Domain Dedication. + */ + +#include +#include +#include + +/* + * handles escapes and line wrapping suitable for use + * defining a C char array ( -c option ) + */ + +static int +format_c(int fd, const char *key) +{ + const char *k = key; + int seq = 0; + + while (*k) { + if (*k == '{') { + if (write(fd, "\"{\"\n\t\"", 6) < 6) + return -1; + k++; + seq = 0; + continue; + } + if (*k == '}') { + if (write(fd, "\"\n\"}\"\n", 6) < 6) + return -1; + k++; + seq = 0; + continue; + } + if (*k == '\"') { + if (write(fd, "\\\"", 2) < 2) + return -1; + seq += 2; + k++; + continue; + } + if (*k == ',') { + if (write(fd, ",\"\n\t\"", 5) < 5) + return -1; + k++; + seq = 0; + continue; + } + if (write(fd, k, 1) < 1) + return -1; + seq++; + if (seq >= 60) { + if (write(fd, "\"\n\t \"", 5) < 5) + return -1; + seq = 1; + } + k++; + } + + return 0; +} + +int main(int argc, const char **argv) +{ + struct lws_context_creation_info info; + struct lws_context *context; + const char *p; + int result = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE; + int bits = 4096; + enum lws_gencrypto_kty kty = LWS_GENCRYPTO_KTY_RSA; + struct lws_jwk jwk; + char key[32768]; + const char *curve = "P-256"; + + if ((p = lws_cmdline_option(argc, argv, "-d"))) + logs = atoi(p); + + lws_set_log_level(logs, NULL); + lwsl_user("LWS JWK example\n"); + + if ((p = lws_cmdline_option(argc, argv, "-b"))) + bits = atoi(p); + + if ((p = lws_cmdline_option(argc, argv, "-t"))) { + if (!strcmp(p, "RSA")) + kty = LWS_GENCRYPTO_KTY_RSA; + else + if (!strcmp(p, "OCT")) + kty = LWS_GENCRYPTO_KTY_OCT; + else + if (!strcmp(p, "EC")) + kty = LWS_GENCRYPTO_KTY_EC; + else { + lwsl_err("Unknown key type (must be " + "OCT, RSA or EC)\n"); + + return 1; + } + } + + memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ + info.port = CONTEXT_PORT_NO_LISTEN; + info.options = 0; + + context = lws_create_context(&info); + if (!context) { + lwsl_err("lws init failed\n"); + return 1; + } + + if ((p = lws_cmdline_option(argc, argv, "-v"))) + curve = p; + + if (lws_jwk_generate(context, &jwk, kty, bits, curve)) { + lwsl_err("lws_jwk_generate failed\n"); + + return 1; + } + + if ((p = lws_cmdline_option(argc, argv, "--kid"))) + lws_jwk_strdup_meta(&jwk, JWK_META_KID, p, strlen(p)); + + if ((p = lws_cmdline_option(argc, argv, "--use"))) + lws_jwk_strdup_meta(&jwk, JWK_META_USE, p, strlen(p)); + + if ((p = lws_cmdline_option(argc, argv, "--key-ops"))) + lws_jwk_strdup_meta(&jwk, JWK_META_KEY_OPS, p, strlen(p)); + + if ((p = lws_cmdline_option(argc, argv, "--public")) && + kty != LWS_GENCRYPTO_KTY_OCT) { + + int fd; + + /* public version */ + + if (lws_jwk_export(&jwk, 0, key, sizeof(key)) < 0) { + lwsl_err("lws_jwk_export failed\n"); + + return 1; + } + + fd = open(p, LWS_O_CREAT | LWS_O_TRUNC | LWS_O_WRONLY, 0600); + if (fd < 0) { + lwsl_err("Can't open public key file %s\n", p); + return 1; + } + + if (lws_cmdline_option(argc, argv, "-c")) + format_c(fd, key); + else { + if (write(fd, key, strlen(key)) < 0) { + lwsl_err("Write public failed\n"); + return 1; + } + } + + close(fd); + } + + /* private version */ + + if (lws_jwk_export(&jwk, 1, key, sizeof(key)) < 0) { + lwsl_err("lws_jwk_export failed\n"); + + return 1; + } + + if (lws_cmdline_option(argc, argv, "-c")) { + if (format_c(1, key) < 0) + return 1; + } else + if (write(1, key, strlen(key)) < 0) { + lwsl_err("Write stdout failed\n"); + return 1; + } + + lws_jwk_destroy(&jwk); + + lws_context_destroy(context); + + return result; +} diff --git a/minimal-examples/crypto/minimal-crypto-jws/CMakeLists.txt b/minimal-examples/crypto/minimal-crypto-jws/CMakeLists.txt new file mode 100644 index 000000000..ddf957969 --- /dev/null +++ b/minimal-examples/crypto/minimal-crypto-jws/CMakeLists.txt @@ -0,0 +1,77 @@ +cmake_minimum_required(VERSION 2.8) +include(CheckCSourceCompiles) + +set(SAMP lws-crypto-jws) +set(SRCS main.c) + +# If we are being built as part of lws, confirm current build config supports +# reqconfig, else skip building ourselves. +# +# If we are being built externally, confirm installed lws was configured to +# support reqconfig, else error out with a helpful message about the problem. +# +MACRO(require_lws_config reqconfig _val result) + + if (DEFINED ${reqconfig}) + if (${reqconfig}) + set (rq 1) + else() + set (rq 0) + endif() + else() + set(rq 0) + endif() + + if (${_val} EQUAL ${rq}) + set(SAME 1) + else() + set(SAME 0) + endif() + + if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME}) + if (${_val}) + message("${SAMP}: skipping as lws being built without ${reqconfig}") + else() + message("${SAMP}: skipping as lws built with ${reqconfig}") + endif() + set(${result} 0) + else() + if (LWS_WITH_MINIMAL_EXAMPLES) + set(MET ${SAME}) + else() + CHECK_C_SOURCE_COMPILES("#include \nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig}) + if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig}) + set(HAS_${reqconfig} 0) + else() + set(HAS_${reqconfig} 1) + endif() + if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val})) + set(MET 1) + else() + set(MET 0) + endif() + endif() + if (NOT MET) + if (${_val}) + message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}") + else() + message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project") + endif() + endif() + endif() +ENDMACRO() + +set(requirements 1) +require_lws_config(LWS_WITH_JOSE 1 requirements) + +if (requirements) + + add_executable(${SAMP} ${SRCS}) + + if (websockets_shared) + target_link_libraries(${SAMP} websockets_shared) + add_dependencies(${SAMP} websockets_shared) + else() + target_link_libraries(${SAMP} websockets) + endif() +endif() diff --git a/minimal-examples/crypto/minimal-crypto-jws/README.md b/minimal-examples/crypto/minimal-crypto-jws/README.md new file mode 100644 index 000000000..d2c426d06 --- /dev/null +++ b/minimal-examples/crypto/minimal-crypto-jws/README.md @@ -0,0 +1,59 @@ +# lws minimal example for JWS + +Demonstrates how to sign and verify using compact JWS and JWK, providing a +commandline tool for signing and verifying stdin. + +## build + +``` + $ cmake . && make +``` + +## usage + +Stdin is either the plaintext (if signing) or compact JWS (if verifying). + +Stdout is either the JWE (if encrypting) or plaintext (if decrypting). + +You must pass a private or public key JWK file in the -k option if encrypting, +and must pass a private key JWK file in the -k option if decrypting. To be +clear, for asymmetric keys the public part of the key is required to encrypt, +and the private part required to decrypt. + +For convenience, a pair of public and private keys are provided, +`key-rsa-4096.private` and `key-rsa-4096.pub`, these were produced with just + +``` + $ lws-crypto-jwk -t RSA -b 4096 --public key-rsa-4096.pub >key-rsa-4096.private +``` + +Similar keys for EC modes may be produced with + +``` + $ lws-crypto-jwk -t EC -v P-256 --public key-ecdh-p-256.pub >key-ecdh-p-256.private +``` + +JWSs produced with openssl and mbedtls backends are completely interchangeable. + +Commandline option|Meaning +---|--- +-d |Debug verbosity in decimal, eg, -d15 +-s ""|Sign (default is verify), eg, -e "ES256". For verify, the cipher information comes from the input JWS. +-k |JWK file to sign or verify with... sign requires the key has its private part +-c|Format the JWE as a linebroken C string + +``` + $ echo -n "plaintext0123456" | ./lws-crypto-jws -s "ES256" -k ec-p256.private +[2018/12/19 16:20:25:6519] USER: LWS JWE example tool +[2018/12/19 16:20:25:6749] NOTICE: Creating Vhost 'default' (serving disabled), 1 protocols, IPv6 off +eyJhbGciOiJSU0ExXzUiLCAiZW5jIjoiQTEyOENCQy1IUzI1NiJ9.ivFr7qzx-pQ4V_edbjpdvR9OwWL9KmojPE2rXQM52oLtW0BtnxZu2_ezqhsAelyIcaworgfobs3u4bslXHMFbeJJjPb5xD0fBDe64OYXZH1NpUGTMJh9Ka4CrJ2B3xhxe7EByGAuGqmluqE0Yezj7rhSw7vlr5JAwuOJ8FaGa8aZ8ldki5G5h_S2Furlbjdcw3Rrxk7mCoMHcLoqzfZtggMPwGAMFogCqcwUo7oSLbBeGaa6hpMbfSysugseWdr8TzObQKPM52k6iVAlGwRaOg_qdLMgZiYRhHA6nFKTQd7XBbNY6qAS8sPuj7Zz344tF3RSfJ0zX_telG71sOtVv5fMpeDU-eCdpOWlCBfu6J6FQfAFu6SJryM4ajGOif09CwFI5qUQ33SOfQfS_M3nqSyd6Vu5M4lsDrb5wK7_XX5gqUwvI9wicf_8WWR-CQomRF-JvEASnA2SIf8QqYfa8R2rP9q6Md4vwO4EZrtxIsMDPsH-4ZEFu7vDjyy09QfIWWsnEb8-UgpVXensgt2m_2bZ76r1VB8-0nZLMwMyEhaH2wra9vX2FWao5UkmNJ7ht300f4_V6QzMFoePpwCvsufWBW6jcQLB-frCWe6uitWaZHEB4LxmNPKzQSz4QwwTKhpF1jNn8Xh1-w1m-2h0gj-oe-S8QBwPveqhPI1p2fI.snuhUTXHNu5mJ6dEPQqg6g.yl36qC4o0GE4nrquQ2YyCg.Vf0MoT7_kUrZdCNWXhq1DQ +``` + +Notice the logging is on stderr, and the output alone on stdout. + +When signing, the compact representation of the JWS is output on stdout. + +When verifying, if the signature is valid the plaintext is output on stdout +and the tool exits with a 0 exit code. Otherwise nothing is output on stdout +and it exits with a nonzero exit code. + diff --git a/minimal-examples/crypto/minimal-crypto-jws/main.c b/minimal-examples/crypto/minimal-crypto-jws/main.c new file mode 100644 index 000000000..8fd47c225 --- /dev/null +++ b/minimal-examples/crypto/minimal-crypto-jws/main.c @@ -0,0 +1,185 @@ +/* + * lws-crypto-jws + * + * Copyright (C) 2018 Andy Green + * + * This file is made available under the Creative Commons CC0 1.0 + * Universal Public Domain Dedication. + */ + +#include +#include +#include + + +int main(int argc, const char **argv) +{ + int n, sign = 0, result = 0, + logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE; + char temp[32768], compact[32768], *in; + struct lws_context_creation_info info; + struct lws_jws_compact_map map; + int temp_len = sizeof(temp); + struct lws_context *context; + struct lws_jose jose; + struct lws_jwk jwk; + struct lws_jws jws; + const char *p; + + if ((p = lws_cmdline_option(argc, argv, "-d"))) + logs = atoi(p); + + lws_set_log_level(logs, NULL); + lwsl_user("LWS JWS example tool\n"); + + memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ + info.port = CONTEXT_PORT_NO_LISTEN; + info.options = 0; + + context = lws_create_context(&info); + if (!context) { + lwsl_err("lws init failed\n"); + return 1; + } + + lws_jose_init(&jose); + lws_jws_init(&jws, &jwk, context); + + /* if signing, set the ciphers */ + + if ((p = lws_cmdline_option(argc, argv, "-s"))) { + + if (lws_gencrypto_jws_alg_to_definition(p, &jose.alg)) { + lwsl_err("format: -s \"\", eg, " + "-e \"RS256\"\n"); + + return 1; + } + + /* create JOSE header, also needed for output */ + + if (lws_jws_alloc_element(&jws.map, LJWS_JOSE, + lws_concat_temp(temp, temp_len), + &temp_len, strlen(p) + 10, 0)) { + lwsl_err("%s: temp space too small\n", __func__); + return 1; + } + + jws.map.len[LJWS_JOSE] = + lws_snprintf((char *)jws.map.buf[LJWS_JOSE], + temp_len, "{\"alg\":\"%s\"}", p); + sign = 1; + } + + in = lws_concat_temp(temp, temp_len); + n = read(0, in, temp_len); + if (n < 0) { + lwsl_err("Problem reading from stdin\n"); + return 1; + } + temp_len -= n; + + /* grab the key */ + + if ((p = lws_cmdline_option(argc, argv, "-k"))) { + if (lws_jwk_load(&jwk, p, NULL, NULL)) { + lwsl_err("%s: problem loading JWK %s\n", __func__, p); + + return 1; + } + } else { + lwsl_err("-k is required\n"); + + return 1; + } + + if (sign) { + + /* add the plaintext from stdin to the map and a b64 version */ + + jws.map.buf[LJWS_PYLD] = in; + jws.map.len[LJWS_PYLD] = n; + + if (lws_jws_encode_b64_element(&jws.map_b64, LJWS_PYLD, + lws_concat_temp(temp, temp_len), + &temp_len, jws.map.buf[LJWS_PYLD], + jws.map.len[LJWS_PYLD])) + goto bail1; + + /* add the b64 JOSE header to the b64 map */ + + if (lws_jws_encode_b64_element(&jws.map_b64, LJWS_JOSE, + lws_concat_temp(temp, temp_len), + &temp_len, jws.map.buf[LJWS_JOSE], + jws.map.len[LJWS_JOSE])) + goto bail1; + + /* prepare the space for the b64 signature in the map */ + + if (lws_jws_alloc_element(&jws.map, LJWS_SIG, + lws_concat_temp(temp, temp_len), + &temp_len, lws_base64_size( + LWS_JWE_LIMIT_KEY_ELEMENT_BYTES), 0)) { + lwsl_err("%s: temp space too small\n", __func__); + goto bail1; + } + + /* sign the plaintext */ + + n = lws_jws_sign_from_b64(&jose, &jws, + (char *)jws.map_b64.buf[LJWS_SIG], + jws.map_b64.len[LJWS_SIG]); + if (n < 0) { + lwsl_err("%s: failed signing test packet\n", __func__); + goto bail1; + } + /* set the actual b64 signature size */ + jws.map_b64.len[LJWS_SIG] = n; + + /* create the compact JWS representation */ + + n = lws_jws_write_compact(&jws, compact, sizeof(compact)); + if (n < 0) { + lwsl_notice("%s: write_compact failed\n", __func__); + goto bail1; + } + + /* dump the compact JWS representation on stdout */ + + if (write(1, compact, strlen(compact)) < 0) { + lwsl_err("Write stdout failed\n"); + goto bail1; + } + + } else { + /* perform the verify directly on the compact representation */ + + if (lws_jws_sig_confirm_compact_b64(in, + lws_concat_used(temp, temp_len), + &map, &jwk, context, + lws_concat_temp(temp, temp_len), + &temp_len) < 0) { + lwsl_notice("%s: confirm rsa sig failed\n", __func__); + goto bail1; + } + + lwsl_notice("VALID\n"); + + /* dump the verifed plaintext and return 0 */ + + if (write(1, jws.map.buf[LJWS_PYLD], jws.map.len[LJWS_PYLD]) < 0) { + lwsl_err("Write stdout failed\n"); + goto bail1; + } + } + + result = 0; + +bail1: + lws_jws_destroy(&jws); + lws_jwk_destroy(&jwk); + + lws_context_destroy(context); + + return result; +} diff --git a/minimal-examples/http-server/minimal-http-server-smp/minimal-http-server-smp.c b/minimal-examples/http-server/minimal-http-server-smp/minimal-http-server-smp.c index 7b687ad96..d6f51b4e5 100644 --- a/minimal-examples/http-server/minimal-http-server-smp/minimal-http-server-smp.c +++ b/minimal-examples/http-server/minimal-http-server-smp/minimal-http-server-smp.c @@ -91,9 +91,11 @@ int main(int argc, const char **argv) info.mounts = &mount; info.options = LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE; - if ((p = lws_cmdline_option(argc, argv, "-t"))) + if ((p = lws_cmdline_option(argc, argv, "-t"))) { info.count_threads = atoi(p); - else + if (info.count_threads < 1 || info.count_threads > LWS_MAX_SMP) + return 1; + } else info.count_threads = COUNT_THREADS; if (lws_cmdline_option(argc, argv, "-s")) { diff --git a/plugins/acme-client/protocol_lws_acme_client.c b/plugins/acme-client/protocol_lws_acme_client.c index 2e4695870..0e70ee098 100644 --- a/plugins/acme-client/protocol_lws_acme_client.c +++ b/plugins/acme-client/protocol_lws_acme_client.c @@ -439,7 +439,7 @@ lws_acme_load_create_auth_keys(struct per_vhost_data__lws_acme_client *vhd, NULL, NULL)) return 0; - vhd->jwk.kty = LWS_GENCRYPTO_KYT_RSA; + vhd->jwk.kty = LWS_GENCRYPTO_KTY_RSA; lwsl_notice("Generating ACME %d-bit keypair... " "will take a little while\n", bits); n = lws_genrsa_new_keypair(vhd->context, &vhd->rsactx, LGRSAM_PKCS1_1_5, @@ -549,17 +549,19 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason, *end = buf + sizeof(buf) - 1, digest[32], *failreason = NULL; const struct lws_protocol_vhost_options *pvo; struct lws_acme_cert_aging_args *caa; - const struct lws_jose_jwe_alg *args; struct acme_connection *ac = NULL; struct lws_genhash_ctx hctx; unsigned char **pp, *pend; const char *content_type; + struct lws_jose jose; struct lws *cwsi; int n, m; if (vhd) ac = vhd->ac; + lws_jose_init(&jose); + switch ((int)reason) { case LWS_CALLBACK_PROTOCOL_INIT: vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi), @@ -783,12 +785,12 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason, puts(start); pkt_add_hdrs: - if (lws_gencrypto_jwe_alg_to_definition("RSA1_5", &args)) { + if (lws_gencrypto_jwe_alg_to_definition("RSA1_5", &jose.alg)) { ac->len = 0; lwsl_notice("%s: no RSA1_5\n", __func__); goto failed; } - ac->len = lws_jwe_create_packet(&vhd->jwk, args, + ac->len = lws_jwe_create_packet(&jose, &vhd->jwk, start, p - start, ac->replay_nonce, &ac->buf[LWS_PRE], diff --git a/plugins/deaddrop/protocol_lws_deaddrop.c b/plugins/deaddrop/protocol_lws_deaddrop.c index bd12cad68..4d05b1bb5 100644 --- a/plugins/deaddrop/protocol_lws_deaddrop.c +++ b/plugins/deaddrop/protocol_lws_deaddrop.c @@ -159,7 +159,7 @@ scan_upload_dir(struct vhd_deaddrop *vhd) p += lws_snprintf(p, (filepath + sizeof(filepath)) - p, "%s/", subdir[m]); - p += lws_snprintf(p, (filepath + sizeof(filepath)) - p, "%s", + lws_snprintf(p, (filepath + sizeof(filepath)) - p, "%s", de->d_name); /* ignore temp files */ @@ -304,12 +304,14 @@ file_upload_cb(void *data, const char *name, const char *filename, if (state == LWS_UFS_CONTENT) break; - close((int)(long long)pss->fd); + if ((int)(long long)pss->fd >= 0) + close((int)(long long)pss->fd); /* the temp filename without the ~ */ lws_strncpy(filename2, pss->filename, sizeof(filename2)); filename2[strlen(filename2) - 1] = '\0'; - rename(pss->filename, filename2); + if (rename(pss->filename, filename2) < 0) + lwsl_err("%s: unable to rename\n", __func__); pss->fd = LWS_INVALID_FILE; pss->response_code = HTTP_STATUS_OK; diff --git a/plugins/raw-proxy/protocol_lws_raw_proxy.c b/plugins/raw-proxy/protocol_lws_raw_proxy.c index 8f52e661b..bfa8d6d9e 100644 --- a/plugins/raw-proxy/protocol_lws_raw_proxy.c +++ b/plugins/raw-proxy/protocol_lws_raw_proxy.c @@ -249,7 +249,7 @@ bad_onward: case LWS_CALLBACK_RAW_PROXY_CLI_ADOPT: lwsl_debug("LWS_CALLBACK_RAW_CLI_ADOPT: pss %p\n", pss); - if (conn) + if (conn || !pss) break; conn = pss->conn = lws_get_opaque_user_data(wsi); conn->established[ONW] = 1; @@ -279,6 +279,9 @@ bad_onward: case LWS_CALLBACK_RAW_PROXY_CLI_RX: lwsl_debug("LWS_CALLBACK_RAW_PROXY_CLI_RX: %d\n", (int)len); + if (!conn) + return 0; + if (!pss || !conn->wsi[ACC] || conn->closed[ACC]) { lwsl_info(" pss %p, wsi[ACC] %p, closed[ACC] %d\n", pss, conn->wsi[ACC], conn->closed[ACC]); @@ -313,6 +316,9 @@ bad_onward: case LWS_CALLBACK_RAW_PROXY_CLI_WRITEABLE: lwsl_debug("LWS_CALLBACK_RAW_PROXY_CLI_WRITEABLE\n"); + if (!conn) + break; + ppkt = lws_ring_get_element(conn->r[ACC], &conn->t[ACC]); if (!ppkt) { lwsl_info("%s: CLI_WRITABLE had nothing in acc ring\n", @@ -374,7 +380,8 @@ bad_onward: case LWS_CALLBACK_RAW_PROXY_SRV_ADOPT: lwsl_debug("LWS_CALLBACK_RAW_SRV_ADOPT\n"); - + if (!pss) + return -1; conn = pss->conn = malloc(sizeof(struct conn)); if (!pss->conn) return -1; @@ -463,7 +470,7 @@ bad_onward: case LWS_CALLBACK_RAW_PROXY_SRV_WRITEABLE: lwsl_debug("LWS_CALLBACK_RAW_PROXY_SRV_WRITEABLE\n"); - if (!conn->established[ONW] || conn->closed[ONW]) + if (!conn || !conn->established[ONW] || conn->closed[ONW]) break; ppkt = lws_ring_get_element(conn->r[ONW], &conn->t[ONW]); diff --git a/plugins/ssh-base/sshd.c b/plugins/ssh-base/sshd.c index 68cea380d..638fba455 100644 --- a/plugins/ssh-base/sshd.c +++ b/plugins/ssh-base/sshd.c @@ -86,18 +86,6 @@ lws_buf(uint8_t **p, void *s, uint32_t len) return 0; } -int -lws_timingsafe_bcmp(const void *a, const void *b, uint32_t len) -{ - const uint8_t *pa = a, *pb = b; - uint8_t sum = 0; - - while (len--) - sum |= (*pa++ ^ *pb++); - - return sum; -} - void write_task(struct per_session_data__sshd *pss, struct lws_ssh_channel *ch, int task) @@ -1250,7 +1238,8 @@ again: e[LWS_GENCRYPTO_RSA_KEYEL_N].len = m; if (lws_genrsa_create(&ctx, e, pss->vhd->context, - LGRSAM_PKCS1_1_5)) + LGRSAM_PKCS1_1_5, + LWS_GENHASH_TYPE_UNKNOWN)) goto ua_fail; /* diff --git a/scripts/autobahn-test-server.sh b/scripts/autobahn-test-server.sh index d2afd6854..ad0a76ced 100755 --- a/scripts/autobahn-test-server.sh +++ b/scripts/autobahn-test-server.sh @@ -10,7 +10,7 @@ set -u -PARALLEL=8 +PARALLEL=2 N=1 OS=`uname` diff --git a/test-apps/test-sshd.c b/test-apps/test-sshd.c index 5eb918799..1550e551f 100644 --- a/test-apps/test-sshd.c +++ b/test-apps/test-sshd.c @@ -342,7 +342,7 @@ ssh_ops_is_pubkey_authorized(const char *username, const char *type, * EN that the peer sends us */ - if (memcmp(peer, ps, peer_len)) { + if (lws_timingsafe_bcmp(peer, ps, peer_len)) { lwsl_info("factors mismatch\n"); goto bail; }