1d4afb5ceSopenharmony_ci/* 2d4afb5ceSopenharmony_ci * lws-crypto-jwe 3d4afb5ceSopenharmony_ci * 4d4afb5ceSopenharmony_ci * Written in 2010-2020 by Andy Green <andy@warmcat.com> 5d4afb5ceSopenharmony_ci * 6d4afb5ceSopenharmony_ci * This file is made available under the Creative Commons CC0 1.0 7d4afb5ceSopenharmony_ci * Universal Public Domain Dedication. 8d4afb5ceSopenharmony_ci */ 9d4afb5ceSopenharmony_ci 10d4afb5ceSopenharmony_ci#include <libwebsockets.h> 11d4afb5ceSopenharmony_ci#include <sys/types.h> 12d4afb5ceSopenharmony_ci#include <fcntl.h> 13d4afb5ceSopenharmony_ci 14d4afb5ceSopenharmony_ci/* 15d4afb5ceSopenharmony_ci * handles escapes and line wrapping suitable for use 16d4afb5ceSopenharmony_ci * defining a C char array ( -c option ) 17d4afb5ceSopenharmony_ci */ 18d4afb5ceSopenharmony_ci 19d4afb5ceSopenharmony_cistatic void 20d4afb5ceSopenharmony_ciformat_c(const char *key) 21d4afb5ceSopenharmony_ci{ 22d4afb5ceSopenharmony_ci const char *k = key; 23d4afb5ceSopenharmony_ci int seq = 0; 24d4afb5ceSopenharmony_ci 25d4afb5ceSopenharmony_ci while (*k) { 26d4afb5ceSopenharmony_ci if (*k == '{') { 27d4afb5ceSopenharmony_ci putchar('\"'); 28d4afb5ceSopenharmony_ci putchar('{'); 29d4afb5ceSopenharmony_ci putchar('\"'); 30d4afb5ceSopenharmony_ci putchar('\n'); 31d4afb5ceSopenharmony_ci putchar('\t'); 32d4afb5ceSopenharmony_ci putchar('\"'); 33d4afb5ceSopenharmony_ci k++; 34d4afb5ceSopenharmony_ci seq = 0; 35d4afb5ceSopenharmony_ci continue; 36d4afb5ceSopenharmony_ci } 37d4afb5ceSopenharmony_ci if (*k == '}') { 38d4afb5ceSopenharmony_ci putchar('\"'); 39d4afb5ceSopenharmony_ci putchar('\n'); 40d4afb5ceSopenharmony_ci putchar('\"'); 41d4afb5ceSopenharmony_ci putchar('}'); 42d4afb5ceSopenharmony_ci putchar('\"'); 43d4afb5ceSopenharmony_ci putchar('\n'); 44d4afb5ceSopenharmony_ci k++; 45d4afb5ceSopenharmony_ci seq = 0; 46d4afb5ceSopenharmony_ci continue; 47d4afb5ceSopenharmony_ci } 48d4afb5ceSopenharmony_ci if (*k == '\"') { 49d4afb5ceSopenharmony_ci putchar('\\'); 50d4afb5ceSopenharmony_ci putchar('\"'); 51d4afb5ceSopenharmony_ci seq += 2; 52d4afb5ceSopenharmony_ci k++; 53d4afb5ceSopenharmony_ci continue; 54d4afb5ceSopenharmony_ci } 55d4afb5ceSopenharmony_ci if (*k == ',') { 56d4afb5ceSopenharmony_ci putchar(','); 57d4afb5ceSopenharmony_ci putchar('\"'); 58d4afb5ceSopenharmony_ci putchar('\n'); 59d4afb5ceSopenharmony_ci putchar('\t'); 60d4afb5ceSopenharmony_ci putchar('\"'); 61d4afb5ceSopenharmony_ci k++; 62d4afb5ceSopenharmony_ci seq = 0; 63d4afb5ceSopenharmony_ci continue; 64d4afb5ceSopenharmony_ci } 65d4afb5ceSopenharmony_ci putchar(*k); 66d4afb5ceSopenharmony_ci seq++; 67d4afb5ceSopenharmony_ci if (seq >= 60) { 68d4afb5ceSopenharmony_ci putchar('\"'); 69d4afb5ceSopenharmony_ci putchar('\n'); 70d4afb5ceSopenharmony_ci putchar('\t'); 71d4afb5ceSopenharmony_ci putchar(' '); 72d4afb5ceSopenharmony_ci putchar('\"'); 73d4afb5ceSopenharmony_ci seq = 1; 74d4afb5ceSopenharmony_ci } 75d4afb5ceSopenharmony_ci k++; 76d4afb5ceSopenharmony_ci } 77d4afb5ceSopenharmony_ci} 78d4afb5ceSopenharmony_ci 79d4afb5ceSopenharmony_ci#define MAX_SIZE (4 * 1024 * 1024) 80d4afb5ceSopenharmony_ci char temp[MAX_SIZE], compact[MAX_SIZE]; 81d4afb5ceSopenharmony_ci 82d4afb5ceSopenharmony_ciint main(int argc, const char **argv) 83d4afb5ceSopenharmony_ci{ 84d4afb5ceSopenharmony_ci int n, enc = 0, result = 0, 85d4afb5ceSopenharmony_ci logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE; 86d4afb5ceSopenharmony_ci char *in; 87d4afb5ceSopenharmony_ci struct lws_context_creation_info info; 88d4afb5ceSopenharmony_ci int temp_len = sizeof(temp); 89d4afb5ceSopenharmony_ci struct lws_context *context; 90d4afb5ceSopenharmony_ci struct lws_jwe jwe; 91d4afb5ceSopenharmony_ci const char *p; 92d4afb5ceSopenharmony_ci 93d4afb5ceSopenharmony_ci if ((p = lws_cmdline_option(argc, argv, "-d"))) 94d4afb5ceSopenharmony_ci logs = atoi(p); 95d4afb5ceSopenharmony_ci 96d4afb5ceSopenharmony_ci lws_set_log_level(logs, NULL); 97d4afb5ceSopenharmony_ci lwsl_user("LWS JWE example tool\n"); 98d4afb5ceSopenharmony_ci 99d4afb5ceSopenharmony_ci memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ 100d4afb5ceSopenharmony_ci#if defined(LWS_WITH_NETWORK) 101d4afb5ceSopenharmony_ci info.port = CONTEXT_PORT_NO_LISTEN; 102d4afb5ceSopenharmony_ci#endif 103d4afb5ceSopenharmony_ci info.options = 0; 104d4afb5ceSopenharmony_ci 105d4afb5ceSopenharmony_ci context = lws_create_context(&info); 106d4afb5ceSopenharmony_ci if (!context) { 107d4afb5ceSopenharmony_ci lwsl_err("lws init failed\n"); 108d4afb5ceSopenharmony_ci return 1; 109d4afb5ceSopenharmony_ci } 110d4afb5ceSopenharmony_ci 111d4afb5ceSopenharmony_ci lws_jwe_init(&jwe, context); 112d4afb5ceSopenharmony_ci 113d4afb5ceSopenharmony_ci /* if encrypting, set the ciphers */ 114d4afb5ceSopenharmony_ci 115d4afb5ceSopenharmony_ci if ((p = lws_cmdline_option(argc, argv, "-e"))) { 116d4afb5ceSopenharmony_ci char *sp = strchr(p, ' '); 117d4afb5ceSopenharmony_ci 118d4afb5ceSopenharmony_ci if (!sp) { 119d4afb5ceSopenharmony_ci lwsl_err("format: -e \"<cek cipher alg> " 120d4afb5ceSopenharmony_ci "<payload enc alg>\", eg, " 121d4afb5ceSopenharmony_ci "-e \"RSA1_5 A128CBC-HS256\"\n"); 122d4afb5ceSopenharmony_ci 123d4afb5ceSopenharmony_ci return 1; 124d4afb5ceSopenharmony_ci } 125d4afb5ceSopenharmony_ci *sp = '\0'; 126d4afb5ceSopenharmony_ci if (lws_gencrypto_jwe_alg_to_definition(p, &jwe.jose.alg)) { 127d4afb5ceSopenharmony_ci lwsl_err("Unknown cipher alg %s\n", p); 128d4afb5ceSopenharmony_ci return 1; 129d4afb5ceSopenharmony_ci } 130d4afb5ceSopenharmony_ci if (lws_gencrypto_jwe_enc_to_definition(sp + 1, &jwe.jose.enc_alg)) { 131d4afb5ceSopenharmony_ci lwsl_err("Unknown payload enc alg %s\n", sp + 1); 132d4afb5ceSopenharmony_ci return 1; 133d4afb5ceSopenharmony_ci } 134d4afb5ceSopenharmony_ci 135d4afb5ceSopenharmony_ci /* create JOSE header, also needed for output */ 136d4afb5ceSopenharmony_ci 137d4afb5ceSopenharmony_ci if (lws_jws_alloc_element(&jwe.jws.map, LJWS_JOSE, 138d4afb5ceSopenharmony_ci lws_concat_temp(temp, temp_len), 139d4afb5ceSopenharmony_ci &temp_len, strlen(p) + 140d4afb5ceSopenharmony_ci strlen(sp + 1) + 32, 0)) { 141d4afb5ceSopenharmony_ci lwsl_err("%s: temp space too small\n", __func__); 142d4afb5ceSopenharmony_ci return 1; 143d4afb5ceSopenharmony_ci } 144d4afb5ceSopenharmony_ci 145d4afb5ceSopenharmony_ci jwe.jws.map.len[LJWS_JOSE] = (uint32_t)lws_snprintf( 146d4afb5ceSopenharmony_ci (char *)jwe.jws.map.buf[LJWS_JOSE], (unsigned int)temp_len, 147d4afb5ceSopenharmony_ci "{\"alg\":\"%s\",\"enc\":\"%s\"}", p, sp + 1); 148d4afb5ceSopenharmony_ci 149d4afb5ceSopenharmony_ci enc = 1; 150d4afb5ceSopenharmony_ci } 151d4afb5ceSopenharmony_ci 152d4afb5ceSopenharmony_ci in = lws_concat_temp(temp, temp_len); 153d4afb5ceSopenharmony_ci n = (int)read(0, in, (unsigned int)temp_len); 154d4afb5ceSopenharmony_ci if (n < 0) { 155d4afb5ceSopenharmony_ci lwsl_err("Problem reading from stdin\n"); 156d4afb5ceSopenharmony_ci return 1; 157d4afb5ceSopenharmony_ci } 158d4afb5ceSopenharmony_ci 159d4afb5ceSopenharmony_ci /* account for padding as well */ 160d4afb5ceSopenharmony_ci 161d4afb5ceSopenharmony_ci temp_len -= (int)lws_gencrypto_padded_length(LWS_AES_CBC_BLOCKLEN, (unsigned int)n); 162d4afb5ceSopenharmony_ci 163d4afb5ceSopenharmony_ci /* grab the key */ 164d4afb5ceSopenharmony_ci 165d4afb5ceSopenharmony_ci if ((p = lws_cmdline_option(argc, argv, "-k"))) { 166d4afb5ceSopenharmony_ci if (lws_jwk_load(&jwe.jwk, p, NULL, NULL)) { 167d4afb5ceSopenharmony_ci lwsl_err("%s: problem loading JWK %s\n", __func__, p); 168d4afb5ceSopenharmony_ci 169d4afb5ceSopenharmony_ci return 1; 170d4afb5ceSopenharmony_ci } 171d4afb5ceSopenharmony_ci } else { 172d4afb5ceSopenharmony_ci lwsl_err("-k <jwk file> is required\n"); 173d4afb5ceSopenharmony_ci 174d4afb5ceSopenharmony_ci return 1; 175d4afb5ceSopenharmony_ci } 176d4afb5ceSopenharmony_ci 177d4afb5ceSopenharmony_ci if (enc) { 178d4afb5ceSopenharmony_ci 179d4afb5ceSopenharmony_ci /* point CTXT to the plaintext we read from stdin */ 180d4afb5ceSopenharmony_ci 181d4afb5ceSopenharmony_ci jwe.jws.map.buf[LJWE_CTXT] = in; 182d4afb5ceSopenharmony_ci jwe.jws.map.len[LJWE_CTXT] = (uint32_t)n; 183d4afb5ceSopenharmony_ci 184d4afb5ceSopenharmony_ci /* 185d4afb5ceSopenharmony_ci * Create a random CEK and set EKEY to it 186d4afb5ceSopenharmony_ci * CEK size is determined by hash / hmac size 187d4afb5ceSopenharmony_ci */ 188d4afb5ceSopenharmony_ci 189d4afb5ceSopenharmony_ci n = lws_gencrypto_bits_to_bytes(jwe.jose.enc_alg->keybits_fixed); 190d4afb5ceSopenharmony_ci if (lws_jws_randomize_element(context, &jwe.jws.map, LJWE_EKEY, 191d4afb5ceSopenharmony_ci lws_concat_temp(temp, temp_len), 192d4afb5ceSopenharmony_ci &temp_len, (unsigned int)n, 193d4afb5ceSopenharmony_ci LWS_JWE_LIMIT_KEY_ELEMENT_BYTES)) { 194d4afb5ceSopenharmony_ci lwsl_err("Problem getting random\n"); 195d4afb5ceSopenharmony_ci goto bail1; 196d4afb5ceSopenharmony_ci } 197d4afb5ceSopenharmony_ci 198d4afb5ceSopenharmony_ci /* perform the encryption of the CEK and the plaintext */ 199d4afb5ceSopenharmony_ci 200d4afb5ceSopenharmony_ci n = lws_jwe_encrypt(&jwe, lws_concat_temp(temp, temp_len), 201d4afb5ceSopenharmony_ci &temp_len); 202d4afb5ceSopenharmony_ci if (n < 0) { 203d4afb5ceSopenharmony_ci lwsl_err("%s: lws_jwe_encrypt failed\n", __func__); 204d4afb5ceSopenharmony_ci goto bail1; 205d4afb5ceSopenharmony_ci } 206d4afb5ceSopenharmony_ci if (lws_cmdline_option(argc, argv, "-f")) 207d4afb5ceSopenharmony_ci /* output the JWE in flattened form */ 208d4afb5ceSopenharmony_ci n = lws_jwe_render_flattened(&jwe, compact, 209d4afb5ceSopenharmony_ci sizeof(compact)); 210d4afb5ceSopenharmony_ci else 211d4afb5ceSopenharmony_ci /* output the JWE in compact form */ 212d4afb5ceSopenharmony_ci n = lws_jwe_render_compact(&jwe, compact, 213d4afb5ceSopenharmony_ci sizeof(compact)); 214d4afb5ceSopenharmony_ci 215d4afb5ceSopenharmony_ci if (n < 0) { 216d4afb5ceSopenharmony_ci lwsl_err("%s: lws_jwe_render failed: %d\n", 217d4afb5ceSopenharmony_ci __func__, n); 218d4afb5ceSopenharmony_ci goto bail1; 219d4afb5ceSopenharmony_ci } 220d4afb5ceSopenharmony_ci 221d4afb5ceSopenharmony_ci if (lws_cmdline_option(argc, argv, "-c")) 222d4afb5ceSopenharmony_ci format_c(compact); 223d4afb5ceSopenharmony_ci else 224d4afb5ceSopenharmony_ci if (write(1, compact, 225d4afb5ceSopenharmony_ci#if defined(WIN32) 226d4afb5ceSopenharmony_ci (unsigned int) 227d4afb5ceSopenharmony_ci#endif 228d4afb5ceSopenharmony_ci strlen(compact)) < 0) { 229d4afb5ceSopenharmony_ci lwsl_err("Write stdout failed\n"); 230d4afb5ceSopenharmony_ci goto bail1; 231d4afb5ceSopenharmony_ci } 232d4afb5ceSopenharmony_ci } else { 233d4afb5ceSopenharmony_ci if (lws_cmdline_option(argc, argv, "-f")) { 234d4afb5ceSopenharmony_ci if (lws_jwe_json_parse(&jwe, (uint8_t *)in, n, 235d4afb5ceSopenharmony_ci lws_concat_temp(temp, temp_len), 236d4afb5ceSopenharmony_ci &temp_len)) { 237d4afb5ceSopenharmony_ci lwsl_err("%s: lws_jwe_json_parse failed\n", 238d4afb5ceSopenharmony_ci __func__); 239d4afb5ceSopenharmony_ci goto bail1; 240d4afb5ceSopenharmony_ci } 241d4afb5ceSopenharmony_ci } else 242d4afb5ceSopenharmony_ci /* 243d4afb5ceSopenharmony_ci * converts a compact serialization to b64 + decoded maps 244d4afb5ceSopenharmony_ci * held in jws 245d4afb5ceSopenharmony_ci */ 246d4afb5ceSopenharmony_ci if (lws_jws_compact_decode(in, n, &jwe.jws.map, 247d4afb5ceSopenharmony_ci &jwe.jws.map_b64, 248d4afb5ceSopenharmony_ci lws_concat_temp(temp, temp_len), 249d4afb5ceSopenharmony_ci &temp_len) != 5) { 250d4afb5ceSopenharmony_ci lwsl_err("%s: lws_jws_compact_decode failed\n", 251d4afb5ceSopenharmony_ci __func__); 252d4afb5ceSopenharmony_ci goto bail1; 253d4afb5ceSopenharmony_ci } 254d4afb5ceSopenharmony_ci 255d4afb5ceSopenharmony_ci /* 256d4afb5ceSopenharmony_ci * Do the crypto according to what we parsed into the jose 257d4afb5ceSopenharmony_ci * (information on the ciphers) and the jws (plaintext and 258d4afb5ceSopenharmony_ci * signature info) 259d4afb5ceSopenharmony_ci */ 260d4afb5ceSopenharmony_ci 261d4afb5ceSopenharmony_ci n = lws_jwe_auth_and_decrypt(&jwe, 262d4afb5ceSopenharmony_ci lws_concat_temp(temp, temp_len), 263d4afb5ceSopenharmony_ci &temp_len); 264d4afb5ceSopenharmony_ci if (n < 0) { 265d4afb5ceSopenharmony_ci lwsl_err("%s: lws_jwe_auth_and_decrypt failed\n", 266d4afb5ceSopenharmony_ci __func__); 267d4afb5ceSopenharmony_ci goto bail1; 268d4afb5ceSopenharmony_ci } 269d4afb5ceSopenharmony_ci 270d4afb5ceSopenharmony_ci /* if it's valid, dump the plaintext and return 0 */ 271d4afb5ceSopenharmony_ci 272d4afb5ceSopenharmony_ci if (write(1, jwe.jws.map.buf[LJWE_CTXT], 273d4afb5ceSopenharmony_ci jwe.jws.map.len[LJWE_CTXT]) < 0) { 274d4afb5ceSopenharmony_ci lwsl_err("Write stdout failed\n"); 275d4afb5ceSopenharmony_ci goto bail1; 276d4afb5ceSopenharmony_ci } 277d4afb5ceSopenharmony_ci } 278d4afb5ceSopenharmony_ci 279d4afb5ceSopenharmony_ci result = 0; 280d4afb5ceSopenharmony_ci 281d4afb5ceSopenharmony_cibail1: 282d4afb5ceSopenharmony_ci 283d4afb5ceSopenharmony_ci lws_jwe_destroy(&jwe); 284d4afb5ceSopenharmony_ci 285d4afb5ceSopenharmony_ci lws_context_destroy(context); 286d4afb5ceSopenharmony_ci 287d4afb5ceSopenharmony_ci return result; 288d4afb5ceSopenharmony_ci} 289