1d4afb5ceSopenharmony_ci/* 2d4afb5ceSopenharmony_ci * lws-crypto-jws 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#define MAX_SIZE (4 * 1024 * 1024) 15d4afb5ceSopenharmony_cichar temp[MAX_SIZE], compact[MAX_SIZE]; 16d4afb5ceSopenharmony_ci 17d4afb5ceSopenharmony_ciint main(int argc, const char **argv) 18d4afb5ceSopenharmony_ci{ 19d4afb5ceSopenharmony_ci int n, sign = 0, result = 0, 20d4afb5ceSopenharmony_ci logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE; 21d4afb5ceSopenharmony_ci char *in; 22d4afb5ceSopenharmony_ci struct lws_context_creation_info info; 23d4afb5ceSopenharmony_ci struct lws_jws_map map; 24d4afb5ceSopenharmony_ci int temp_len = sizeof(temp); 25d4afb5ceSopenharmony_ci struct lws_context *context; 26d4afb5ceSopenharmony_ci struct lws_jose jose; 27d4afb5ceSopenharmony_ci struct lws_jwk jwk; 28d4afb5ceSopenharmony_ci struct lws_jws jws; 29d4afb5ceSopenharmony_ci const char *p; 30d4afb5ceSopenharmony_ci 31d4afb5ceSopenharmony_ci if ((p = lws_cmdline_option(argc, argv, "-d"))) 32d4afb5ceSopenharmony_ci logs = atoi(p); 33d4afb5ceSopenharmony_ci 34d4afb5ceSopenharmony_ci lws_set_log_level(logs, NULL); 35d4afb5ceSopenharmony_ci lwsl_user("LWS JWS example tool\n"); 36d4afb5ceSopenharmony_ci 37d4afb5ceSopenharmony_ci memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ 38d4afb5ceSopenharmony_ci#if defined(LWS_WITH_NETWORK) 39d4afb5ceSopenharmony_ci info.port = CONTEXT_PORT_NO_LISTEN; 40d4afb5ceSopenharmony_ci#endif 41d4afb5ceSopenharmony_ci info.options = 0; 42d4afb5ceSopenharmony_ci 43d4afb5ceSopenharmony_ci context = lws_create_context(&info); 44d4afb5ceSopenharmony_ci if (!context) { 45d4afb5ceSopenharmony_ci lwsl_err("lws init failed\n"); 46d4afb5ceSopenharmony_ci return 1; 47d4afb5ceSopenharmony_ci } 48d4afb5ceSopenharmony_ci 49d4afb5ceSopenharmony_ci lws_jose_init(&jose); 50d4afb5ceSopenharmony_ci lws_jws_init(&jws, &jwk, context); 51d4afb5ceSopenharmony_ci 52d4afb5ceSopenharmony_ci /* if signing, set the ciphers */ 53d4afb5ceSopenharmony_ci 54d4afb5ceSopenharmony_ci if ((p = lws_cmdline_option(argc, argv, "-s"))) { 55d4afb5ceSopenharmony_ci 56d4afb5ceSopenharmony_ci if (lws_gencrypto_jws_alg_to_definition(p, &jose.alg)) { 57d4afb5ceSopenharmony_ci lwsl_err("format: -s \"<jws cipher alg>\", eg, " 58d4afb5ceSopenharmony_ci "-e \"RS256\"\n"); 59d4afb5ceSopenharmony_ci 60d4afb5ceSopenharmony_ci return 1; 61d4afb5ceSopenharmony_ci } 62d4afb5ceSopenharmony_ci 63d4afb5ceSopenharmony_ci /* create JOSE header, also needed for output */ 64d4afb5ceSopenharmony_ci 65d4afb5ceSopenharmony_ci if (lws_jws_alloc_element(&jws.map, LJWS_JOSE, 66d4afb5ceSopenharmony_ci lws_concat_temp(temp, temp_len), 67d4afb5ceSopenharmony_ci &temp_len, strlen(p) + 10, 0)) { 68d4afb5ceSopenharmony_ci lwsl_err("%s: temp space too small\n", __func__); 69d4afb5ceSopenharmony_ci return 1; 70d4afb5ceSopenharmony_ci } 71d4afb5ceSopenharmony_ci 72d4afb5ceSopenharmony_ci jws.map.len[LJWS_JOSE] = (uint32_t) 73d4afb5ceSopenharmony_ci lws_snprintf((char *)jws.map.buf[LJWS_JOSE], 74d4afb5ceSopenharmony_ci (unsigned int)temp_len, "{\"alg\":\"%s\"}", p); 75d4afb5ceSopenharmony_ci sign = 1; 76d4afb5ceSopenharmony_ci } 77d4afb5ceSopenharmony_ci 78d4afb5ceSopenharmony_ci in = lws_concat_temp(temp, temp_len); 79d4afb5ceSopenharmony_ci n = (int)read(0, in, (unsigned int)temp_len); 80d4afb5ceSopenharmony_ci if (n < 0) { 81d4afb5ceSopenharmony_ci lwsl_err("Problem reading from stdin\n"); 82d4afb5ceSopenharmony_ci return 1; 83d4afb5ceSopenharmony_ci } 84d4afb5ceSopenharmony_ci temp_len -= n; 85d4afb5ceSopenharmony_ci 86d4afb5ceSopenharmony_ci /* grab the key */ 87d4afb5ceSopenharmony_ci 88d4afb5ceSopenharmony_ci if ((p = lws_cmdline_option(argc, argv, "-k"))) { 89d4afb5ceSopenharmony_ci if (lws_jwk_load(&jwk, p, NULL, NULL)) { 90d4afb5ceSopenharmony_ci lwsl_err("%s: problem loading JWK %s\n", __func__, p); 91d4afb5ceSopenharmony_ci 92d4afb5ceSopenharmony_ci return 1; 93d4afb5ceSopenharmony_ci } 94d4afb5ceSopenharmony_ci } else { 95d4afb5ceSopenharmony_ci lwsl_err("-k <jwk file> is required\n"); 96d4afb5ceSopenharmony_ci 97d4afb5ceSopenharmony_ci return 1; 98d4afb5ceSopenharmony_ci } 99d4afb5ceSopenharmony_ci if (sign) { 100d4afb5ceSopenharmony_ci 101d4afb5ceSopenharmony_ci /* add the plaintext from stdin to the map and a b64 version */ 102d4afb5ceSopenharmony_ci 103d4afb5ceSopenharmony_ci jws.map.buf[LJWS_PYLD] = in; 104d4afb5ceSopenharmony_ci jws.map.len[LJWS_PYLD] = (unsigned int)n; 105d4afb5ceSopenharmony_ci 106d4afb5ceSopenharmony_ci if (lws_jws_encode_b64_element(&jws.map_b64, LJWS_PYLD, 107d4afb5ceSopenharmony_ci lws_concat_temp(temp, temp_len), 108d4afb5ceSopenharmony_ci &temp_len, jws.map.buf[LJWS_PYLD], 109d4afb5ceSopenharmony_ci jws.map.len[LJWS_PYLD])) 110d4afb5ceSopenharmony_ci goto bail1; 111d4afb5ceSopenharmony_ci 112d4afb5ceSopenharmony_ci /* add the b64 JOSE header to the b64 map */ 113d4afb5ceSopenharmony_ci 114d4afb5ceSopenharmony_ci if (lws_jws_encode_b64_element(&jws.map_b64, LJWS_JOSE, 115d4afb5ceSopenharmony_ci lws_concat_temp(temp, temp_len), 116d4afb5ceSopenharmony_ci &temp_len, jws.map.buf[LJWS_JOSE], 117d4afb5ceSopenharmony_ci jws.map.len[LJWS_JOSE])) 118d4afb5ceSopenharmony_ci goto bail1; 119d4afb5ceSopenharmony_ci 120d4afb5ceSopenharmony_ci /* prepare the space for the b64 signature in the map */ 121d4afb5ceSopenharmony_ci 122d4afb5ceSopenharmony_ci if (lws_jws_alloc_element(&jws.map_b64, LJWS_SIG, 123d4afb5ceSopenharmony_ci lws_concat_temp(temp, temp_len), 124d4afb5ceSopenharmony_ci &temp_len, (unsigned int)lws_base64_size( 125d4afb5ceSopenharmony_ci LWS_JWE_LIMIT_KEY_ELEMENT_BYTES), 0)) { 126d4afb5ceSopenharmony_ci lwsl_err("%s: temp space too small\n", __func__); 127d4afb5ceSopenharmony_ci goto bail1; 128d4afb5ceSopenharmony_ci } 129d4afb5ceSopenharmony_ci 130d4afb5ceSopenharmony_ci 131d4afb5ceSopenharmony_ci 132d4afb5ceSopenharmony_ci /* sign the plaintext */ 133d4afb5ceSopenharmony_ci 134d4afb5ceSopenharmony_ci n = lws_jws_sign_from_b64(&jose, &jws, 135d4afb5ceSopenharmony_ci (char *)jws.map_b64.buf[LJWS_SIG], 136d4afb5ceSopenharmony_ci jws.map_b64.len[LJWS_SIG]); 137d4afb5ceSopenharmony_ci if (n < 0) { 138d4afb5ceSopenharmony_ci lwsl_err("%s: failed signing test packet\n", __func__); 139d4afb5ceSopenharmony_ci goto bail1; 140d4afb5ceSopenharmony_ci } 141d4afb5ceSopenharmony_ci /* set the actual b64 signature size */ 142d4afb5ceSopenharmony_ci jws.map_b64.len[LJWS_SIG] = (uint32_t)n; 143d4afb5ceSopenharmony_ci 144d4afb5ceSopenharmony_ci if (lws_cmdline_option(argc, argv, "-f")) 145d4afb5ceSopenharmony_ci /* create the flattened representation */ 146d4afb5ceSopenharmony_ci n = lws_jws_write_flattened_json(&jws, compact, sizeof(compact)); 147d4afb5ceSopenharmony_ci else 148d4afb5ceSopenharmony_ci /* create the compact JWS representation */ 149d4afb5ceSopenharmony_ci n = lws_jws_write_compact(&jws, compact, sizeof(compact)); 150d4afb5ceSopenharmony_ci if (n < 0) { 151d4afb5ceSopenharmony_ci lwsl_notice("%s: write_compact failed\n", __func__); 152d4afb5ceSopenharmony_ci goto bail1; 153d4afb5ceSopenharmony_ci } 154d4afb5ceSopenharmony_ci 155d4afb5ceSopenharmony_ci /* dump the compact JWS representation on stdout */ 156d4afb5ceSopenharmony_ci 157d4afb5ceSopenharmony_ci if (write(1, compact, 158d4afb5ceSopenharmony_ci#if defined(WIN32) 159d4afb5ceSopenharmony_ci (unsigned int) 160d4afb5ceSopenharmony_ci#endif 161d4afb5ceSopenharmony_ci strlen(compact)) < 0) { 162d4afb5ceSopenharmony_ci lwsl_err("Write stdout failed\n"); 163d4afb5ceSopenharmony_ci goto bail1; 164d4afb5ceSopenharmony_ci } 165d4afb5ceSopenharmony_ci 166d4afb5ceSopenharmony_ci } else { 167d4afb5ceSopenharmony_ci /* perform the verify directly on the compact representation */ 168d4afb5ceSopenharmony_ci 169d4afb5ceSopenharmony_ci if (lws_cmdline_option(argc, argv, "-f")) { 170d4afb5ceSopenharmony_ci if (lws_jws_sig_confirm_json(in, (unsigned int)n, &jws, &jwk, context, 171d4afb5ceSopenharmony_ci lws_concat_temp(temp, temp_len), 172d4afb5ceSopenharmony_ci &temp_len) < 0) { 173d4afb5ceSopenharmony_ci lwsl_notice("%s: confirm rsa sig failed\n", 174d4afb5ceSopenharmony_ci __func__); 175d4afb5ceSopenharmony_ci lwsl_hexdump_notice(jws.map.buf[LJWS_JOSE], jws.map.len[LJWS_JOSE]); 176d4afb5ceSopenharmony_ci lwsl_hexdump_notice(jws.map.buf[LJWS_PYLD], jws.map.len[LJWS_PYLD]); 177d4afb5ceSopenharmony_ci lwsl_hexdump_notice(jws.map.buf[LJWS_SIG], jws.map.len[LJWS_SIG]); 178d4afb5ceSopenharmony_ci 179d4afb5ceSopenharmony_ci lwsl_hexdump_notice(jws.map_b64.buf[LJWS_JOSE], jws.map_b64.len[LJWS_JOSE]); 180d4afb5ceSopenharmony_ci lwsl_hexdump_notice(jws.map_b64.buf[LJWS_PYLD], jws.map_b64.len[LJWS_PYLD]); 181d4afb5ceSopenharmony_ci lwsl_hexdump_notice(jws.map_b64.buf[LJWS_SIG], jws.map_b64.len[LJWS_SIG]); 182d4afb5ceSopenharmony_ci goto bail1; 183d4afb5ceSopenharmony_ci } 184d4afb5ceSopenharmony_ci } else { 185d4afb5ceSopenharmony_ci if (lws_jws_sig_confirm_compact_b64(in, 186d4afb5ceSopenharmony_ci lws_concat_used(temp, (unsigned int)temp_len), 187d4afb5ceSopenharmony_ci &map, &jwk, context, 188d4afb5ceSopenharmony_ci lws_concat_temp(temp, temp_len), 189d4afb5ceSopenharmony_ci &temp_len) < 0) { 190d4afb5ceSopenharmony_ci lwsl_notice("%s: confirm rsa sig failed\n", 191d4afb5ceSopenharmony_ci __func__); 192d4afb5ceSopenharmony_ci goto bail1; 193d4afb5ceSopenharmony_ci } 194d4afb5ceSopenharmony_ci } 195d4afb5ceSopenharmony_ci 196d4afb5ceSopenharmony_ci lwsl_notice("VALID\n"); 197d4afb5ceSopenharmony_ci 198d4afb5ceSopenharmony_ci /* dump the verifed plaintext and return 0 */ 199d4afb5ceSopenharmony_ci 200d4afb5ceSopenharmony_ci if (write(1, jws.map.buf[LJWS_PYLD], jws.map.len[LJWS_PYLD]) < 0) { 201d4afb5ceSopenharmony_ci lwsl_err("Write stdout failed\n"); 202d4afb5ceSopenharmony_ci goto bail1; 203d4afb5ceSopenharmony_ci } 204d4afb5ceSopenharmony_ci } 205d4afb5ceSopenharmony_ci 206d4afb5ceSopenharmony_ci result = 0; 207d4afb5ceSopenharmony_ci 208d4afb5ceSopenharmony_cibail1: 209d4afb5ceSopenharmony_ci lws_jws_destroy(&jws); 210d4afb5ceSopenharmony_ci lws_jwk_destroy(&jwk); 211d4afb5ceSopenharmony_ci 212d4afb5ceSopenharmony_ci lws_context_destroy(context); 213d4afb5ceSopenharmony_ci 214d4afb5ceSopenharmony_ci return result; 215d4afb5ceSopenharmony_ci} 216