visaljs 0.0.10 → 0.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -4
- package/THIRD_PARTY_LICENSES +31 -1
- package/cli.js +962 -68
- package/node/include/js_node.h +11 -1
- package/node/prelude/_http_common.js +29 -0
- package/node/prelude/async_hooks.js +50 -11
- package/node/prelude/child_process.js +31 -4
- package/node/prelude/console.js +311 -143
- package/node/prelude/crypto.js +6 -4
- package/node/prelude/dgram.js +1169 -0
- package/node/prelude/diagnostics_channel.js +3 -1
- package/node/prelude/dns.js +250 -45
- package/node/prelude/dns_promises.js +8 -2
- package/node/prelude/fs_promises.js +9 -1
- package/node/prelude/http.js +395 -86
- package/node/prelude/https.js +13 -4
- package/node/prelude/internal/console_class.js +7 -0
- package/node/prelude/internal/console_global.js +25 -0
- package/node/prelude/internal/crypto/key_encryption.js +217 -0
- package/node/prelude/internal/crypto/keys.js +161 -26
- package/node/prelude/internal/crypto/random.js +24 -0
- package/node/prelude/internal/crypto/util.js +2 -1
- package/node/prelude/internal/crypto_x509.js +161 -0
- package/node/prelude/internal/dns_classes.js +6 -0
- package/node/prelude/internal/dns_resolver.js +371 -0
- package/node/prelude/internal/errors.js +9 -0
- package/node/prelude/internal/events_on.js +82 -37
- package/node/prelude/internal/features.js +8 -4
- package/node/prelude/internal/fs_filehandle.js +10 -4
- package/node/prelude/internal/perf_histogram.js +1 -1
- package/node/prelude/internal/process_more.js +32 -17
- package/node/prelude/internal/process_signals.js +8 -2
- package/node/prelude/internal/punycode.ts +163 -0
- package/node/prelude/internal/readline.js +648 -274
- package/node/prelude/internal/readline_editor.js +1240 -0
- package/node/prelude/internal/string_width.js +43 -0
- package/node/prelude/internal/tls/common.js +145 -33
- package/node/prelude/internal/tls/wrap.js +182 -49
- package/node/prelude/internal/tls/x509.js +4 -1
- package/node/prelude/internal/udp.js +177 -0
- package/node/prelude/net.js +13 -1
- package/node/prelude/os.js +24 -6
- package/node/prelude/perf_hooks.js +37 -2
- package/node/prelude/punycode.js +2 -130
- package/node/prelude/readline.js +113 -4
- package/node/prelude/readline_promises.js +56 -32
- package/node/prelude/tls.js +21 -4
- package/node/prelude/util.js +3 -16
- package/node/src/host_dns.c +623 -0
- package/node/src/host_http.c +12 -0
- package/node/src/host_net.c +46 -0
- package/node/src/host_os.c +1 -6
- package/node/src/host_sys.c +70 -0
- package/node/src/host_udp.c +418 -0
- package/node/third_party/c-ares/LICENSE.md +24 -0
- package/node/third_party/c-ares/config/darwin/ares_config.h +573 -0
- package/node/third_party/c-ares/config/freebsd/ares_config.h +573 -0
- package/node/third_party/c-ares/config/linux/ares_config.h +573 -0
- package/node/third_party/c-ares/config/openbsd/ares_config.h +583 -0
- package/node/third_party/c-ares/include/ares.h +1237 -0
- package/node/third_party/c-ares/include/ares_build.h +202 -0
- package/node/third_party/c-ares/include/ares_dns.h +127 -0
- package/node/third_party/c-ares/include/ares_dns_record.h +1119 -0
- package/node/third_party/c-ares/include/ares_nameser.h +510 -0
- package/node/third_party/c-ares/include/ares_version.h +47 -0
- package/node/third_party/c-ares/src/lib/ares_addrinfo2hostent.c +305 -0
- package/node/third_party/c-ares/src/lib/ares_addrinfo_localhost.c +245 -0
- package/node/third_party/c-ares/src/lib/ares_android.c +496 -0
- package/node/third_party/c-ares/src/lib/ares_android.h +38 -0
- package/node/third_party/c-ares/src/lib/ares_cancel.c +87 -0
- package/node/third_party/c-ares/src/lib/ares_close_sockets.c +137 -0
- package/node/third_party/c-ares/src/lib/ares_conn.c +511 -0
- package/node/third_party/c-ares/src/lib/ares_conn.h +202 -0
- package/node/third_party/c-ares/src/lib/ares_cookie.c +461 -0
- package/node/third_party/c-ares/src/lib/ares_data.c +168 -0
- package/node/third_party/c-ares/src/lib/ares_data.h +92 -0
- package/node/third_party/c-ares/src/lib/ares_destroy.c +159 -0
- package/node/third_party/c-ares/src/lib/ares_free_hostent.c +54 -0
- package/node/third_party/c-ares/src/lib/ares_free_string.c +33 -0
- package/node/third_party/c-ares/src/lib/ares_freeaddrinfo.c +67 -0
- package/node/third_party/c-ares/src/lib/ares_getaddrinfo.c +806 -0
- package/node/third_party/c-ares/src/lib/ares_getenv.c +38 -0
- package/node/third_party/c-ares/src/lib/ares_getenv.h +34 -0
- package/node/third_party/c-ares/src/lib/ares_gethostbyaddr.c +229 -0
- package/node/third_party/c-ares/src/lib/ares_gethostbyname.c +341 -0
- package/node/third_party/c-ares/src/lib/ares_getnameinfo.c +437 -0
- package/node/third_party/c-ares/src/lib/ares_hosts_file.c +960 -0
- package/node/third_party/c-ares/src/lib/ares_inet_net_pton.h +31 -0
- package/node/third_party/c-ares/src/lib/ares_init.c +631 -0
- package/node/third_party/c-ares/src/lib/ares_ipv6.h +115 -0
- package/node/third_party/c-ares/src/lib/ares_library_init.c +190 -0
- package/node/third_party/c-ares/src/lib/ares_metrics.c +261 -0
- package/node/third_party/c-ares/src/lib/ares_options.c +492 -0
- package/node/third_party/c-ares/src/lib/ares_parse_into_addrinfo.c +179 -0
- package/node/third_party/c-ares/src/lib/ares_private.h +648 -0
- package/node/third_party/c-ares/src/lib/ares_process.c +1649 -0
- package/node/third_party/c-ares/src/lib/ares_qcache.c +442 -0
- package/node/third_party/c-ares/src/lib/ares_query.c +151 -0
- package/node/third_party/c-ares/src/lib/ares_search.c +623 -0
- package/node/third_party/c-ares/src/lib/ares_send.c +300 -0
- package/node/third_party/c-ares/src/lib/ares_set_socket_functions.c +590 -0
- package/node/third_party/c-ares/src/lib/ares_setup.h +224 -0
- package/node/third_party/c-ares/src/lib/ares_socket.c +427 -0
- package/node/third_party/c-ares/src/lib/ares_socket.h +163 -0
- package/node/third_party/c-ares/src/lib/ares_sortaddrinfo.c +447 -0
- package/node/third_party/c-ares/src/lib/ares_strerror.c +91 -0
- package/node/third_party/c-ares/src/lib/ares_sysconfig.c +642 -0
- package/node/third_party/c-ares/src/lib/ares_sysconfig_files.c +851 -0
- package/node/third_party/c-ares/src/lib/ares_sysconfig_mac.c +373 -0
- package/node/third_party/c-ares/src/lib/ares_sysconfig_win.c +673 -0
- package/node/third_party/c-ares/src/lib/ares_timeout.c +162 -0
- package/node/third_party/c-ares/src/lib/ares_update_servers.c +1376 -0
- package/node/third_party/c-ares/src/lib/ares_version.c +36 -0
- package/node/third_party/c-ares/src/lib/config-dos.h +114 -0
- package/node/third_party/c-ares/src/lib/config-win32.h +396 -0
- package/node/third_party/c-ares/src/lib/dsa/ares_array.c +409 -0
- package/node/third_party/c-ares/src/lib/dsa/ares_htable.c +451 -0
- package/node/third_party/c-ares/src/lib/dsa/ares_htable.h +174 -0
- package/node/third_party/c-ares/src/lib/dsa/ares_htable_asvp.c +224 -0
- package/node/third_party/c-ares/src/lib/dsa/ares_htable_dict.c +230 -0
- package/node/third_party/c-ares/src/lib/dsa/ares_htable_strvp.c +210 -0
- package/node/third_party/c-ares/src/lib/dsa/ares_htable_szvp.c +188 -0
- package/node/third_party/c-ares/src/lib/dsa/ares_htable_vpstr.c +186 -0
- package/node/third_party/c-ares/src/lib/dsa/ares_htable_vpvp.c +194 -0
- package/node/third_party/c-ares/src/lib/dsa/ares_llist.c +385 -0
- package/node/third_party/c-ares/src/lib/dsa/ares_slist.c +479 -0
- package/node/third_party/c-ares/src/lib/dsa/ares_slist.h +207 -0
- package/node/third_party/c-ares/src/lib/event/ares_event.h +191 -0
- package/node/third_party/c-ares/src/lib/event/ares_event_configchg.c +746 -0
- package/node/third_party/c-ares/src/lib/event/ares_event_epoll.c +192 -0
- package/node/third_party/c-ares/src/lib/event/ares_event_kqueue.c +248 -0
- package/node/third_party/c-ares/src/lib/event/ares_event_poll.c +140 -0
- package/node/third_party/c-ares/src/lib/event/ares_event_select.c +159 -0
- package/node/third_party/c-ares/src/lib/event/ares_event_thread.c +575 -0
- package/node/third_party/c-ares/src/lib/event/ares_event_wake_pipe.c +172 -0
- package/node/third_party/c-ares/src/lib/event/ares_event_win32.c +981 -0
- package/node/third_party/c-ares/src/lib/event/ares_event_win32.h +161 -0
- package/node/third_party/c-ares/src/lib/include/ares_array.h +276 -0
- package/node/third_party/c-ares/src/lib/include/ares_buf.h +732 -0
- package/node/third_party/c-ares/src/lib/include/ares_htable_asvp.h +130 -0
- package/node/third_party/c-ares/src/lib/include/ares_htable_dict.h +123 -0
- package/node/third_party/c-ares/src/lib/include/ares_htable_strvp.h +130 -0
- package/node/third_party/c-ares/src/lib/include/ares_htable_szvp.h +118 -0
- package/node/third_party/c-ares/src/lib/include/ares_htable_vpstr.h +111 -0
- package/node/third_party/c-ares/src/lib/include/ares_htable_vpvp.h +128 -0
- package/node/third_party/c-ares/src/lib/include/ares_llist.h +239 -0
- package/node/third_party/c-ares/src/lib/include/ares_mem.h +41 -0
- package/node/third_party/c-ares/src/lib/include/ares_str.h +261 -0
- package/node/third_party/c-ares/src/lib/inet_net_pton.c +451 -0
- package/node/third_party/c-ares/src/lib/inet_ntop.c +219 -0
- package/node/third_party/c-ares/src/lib/legacy/ares_create_query.c +78 -0
- package/node/third_party/c-ares/src/lib/legacy/ares_expand_name.c +99 -0
- package/node/third_party/c-ares/src/lib/legacy/ares_expand_string.c +107 -0
- package/node/third_party/c-ares/src/lib/legacy/ares_fds.c +80 -0
- package/node/third_party/c-ares/src/lib/legacy/ares_getsock.c +85 -0
- package/node/third_party/c-ares/src/lib/legacy/ares_parse_a_reply.c +107 -0
- package/node/third_party/c-ares/src/lib/legacy/ares_parse_aaaa_reply.c +109 -0
- package/node/third_party/c-ares/src/lib/legacy/ares_parse_caa_reply.c +137 -0
- package/node/third_party/c-ares/src/lib/legacy/ares_parse_mx_reply.c +110 -0
- package/node/third_party/c-ares/src/lib/legacy/ares_parse_naptr_reply.c +132 -0
- package/node/third_party/c-ares/src/lib/legacy/ares_parse_ns_reply.c +154 -0
- package/node/third_party/c-ares/src/lib/legacy/ares_parse_ptr_reply.c +213 -0
- package/node/third_party/c-ares/src/lib/legacy/ares_parse_soa_reply.c +115 -0
- package/node/third_party/c-ares/src/lib/legacy/ares_parse_srv_reply.c +114 -0
- package/node/third_party/c-ares/src/lib/legacy/ares_parse_txt_reply.c +144 -0
- package/node/third_party/c-ares/src/lib/legacy/ares_parse_uri_reply.c +113 -0
- package/node/third_party/c-ares/src/lib/record/ares_dns_mapping.c +982 -0
- package/node/third_party/c-ares/src/lib/record/ares_dns_multistring.c +309 -0
- package/node/third_party/c-ares/src/lib/record/ares_dns_multistring.h +72 -0
- package/node/third_party/c-ares/src/lib/record/ares_dns_name.c +736 -0
- package/node/third_party/c-ares/src/lib/record/ares_dns_parse.c +1360 -0
- package/node/third_party/c-ares/src/lib/record/ares_dns_private.h +273 -0
- package/node/third_party/c-ares/src/lib/record/ares_dns_record.c +1701 -0
- package/node/third_party/c-ares/src/lib/record/ares_dns_write.c +1229 -0
- package/node/third_party/c-ares/src/lib/str/ares_buf.c +1510 -0
- package/node/third_party/c-ares/src/lib/str/ares_str.c +562 -0
- package/node/third_party/c-ares/src/lib/str/ares_strsplit.c +90 -0
- package/node/third_party/c-ares/src/lib/str/ares_strsplit.h +51 -0
- package/node/third_party/c-ares/src/lib/thirdparty/apple/dnsinfo.h +122 -0
- package/node/third_party/c-ares/src/lib/util/ares_iface_ips.c +640 -0
- package/node/third_party/c-ares/src/lib/util/ares_iface_ips.h +140 -0
- package/node/third_party/c-ares/src/lib/util/ares_math.c +167 -0
- package/node/third_party/c-ares/src/lib/util/ares_math.h +58 -0
- package/node/third_party/c-ares/src/lib/util/ares_rand.c +389 -0
- package/node/third_party/c-ares/src/lib/util/ares_rand.h +36 -0
- package/node/third_party/c-ares/src/lib/util/ares_threads.c +613 -0
- package/node/third_party/c-ares/src/lib/util/ares_threads.h +60 -0
- package/node/third_party/c-ares/src/lib/util/ares_time.h +49 -0
- package/node/third_party/c-ares/src/lib/util/ares_timeval.c +95 -0
- package/node/third_party/c-ares/src/lib/util/ares_uri.c +1627 -0
- package/node/third_party/c-ares/src/lib/util/ares_uri.h +252 -0
- package/node/third_party/c-ares/src/lib/windows_port.c +29 -0
- package/package.json +1 -1
- package/prebuilt/darwin-arm64/cares-a6286c65ca9374a3.a +0 -0
- package/prebuilt/darwin-x64/cares-a6286c65ca9374a3.a +0 -0
- package/prebuilt/linux-arm64/cares-4ba05ac8e948af8e.a +0 -0
- package/prebuilt/linux-arm64-musl/cares-4ba05ac8e948af8e.a +0 -0
- package/prebuilt/linux-x64/cares-4ba05ac8e948af8e.a +0 -0
- package/prebuilt/linux-x64-musl/cares-4ba05ac8e948af8e.a +0 -0
- package/prebuilt/win32-x64/boringssl-ce573858472b7fc9.a +0 -0
- package/prebuilt/win32-x64/brotli-20d86a61f30baeb3.a +0 -0
- package/prebuilt/win32-x64/cares-49c9ec95162b912d.a +0 -0
- package/prebuilt/win32-x64/uv-b11bae65d7fced82.a +0 -0
- package/prebuilt/win32-x64/zlib-4ce2317a4c3f5fb5.a +0 -0
- package/prebuilt/win32-x64/zstd-015315ac7c784c73.a +0 -0
- package/runtime/include/js_builtins.h +5 -0
- package/runtime/include/js_crypto.h +11 -0
- package/runtime/include/js_gc.h +13 -10
- package/runtime/include/js_jobs.h +2 -0
- package/runtime/include/js_object.h +58 -0
- package/runtime/include/jscontext.h +1 -0
- package/runtime/src/crypto_internal.h +1 -0
- package/runtime/src/crypto_subtle.c +66 -7
- package/runtime/src/crypto_tls.c +265 -19
- package/runtime/src/gc.c +73 -92
- package/runtime/src/inspect.c +18 -1
- package/runtime/src/jobs.c +37 -22
- package/runtime/src/object.c +49 -2
- package/runtime/src/os.c +16 -6
- package/runtime/src/os.h +2 -0
- package/runtime/src/process.c +97 -10
|
@@ -226,14 +226,15 @@ static int arg_enum(Call *c, JSValue v, const char *const *values, int count, co
|
|
|
226
226
|
c->op, where, shown, type));
|
|
227
227
|
}
|
|
228
228
|
|
|
229
|
-
|
|
230
|
-
|
|
229
|
+
/* the raw-* formats (Node 24's, from WebCrypto's Modern Algorithms draft) say which key raw is */
|
|
230
|
+
enum { FORMAT_RAW, FORMAT_SPKI, FORMAT_PKCS8, FORMAT_JWK, FORMAT_RAW_PUBLIC, FORMAT_RAW_PRIVATE, FORMAT_RAW_SEED, FORMAT_RAW_SECRET };
|
|
231
|
+
static const char *const FORMATS[] = { "raw", "spki", "pkcs8", "jwk", "raw-public", "raw-private", "raw-seed", "raw-secret" };
|
|
231
232
|
static const char *const USAGES[] = { "encrypt", "decrypt", "sign", "verify", "deriveKey", "deriveBits", "wrapKey", "unwrapKey" };
|
|
232
233
|
|
|
233
234
|
static int arg_format(Call *c, JSValue v, int i) {
|
|
234
235
|
char where[32];
|
|
235
236
|
snprintf(where, sizeof where, "%s argument", ORDINALS[i]);
|
|
236
|
-
return arg_enum(c, v, FORMATS,
|
|
237
|
+
return arg_enum(c, v, FORMATS, 8, "KeyFormat", where);
|
|
237
238
|
}
|
|
238
239
|
|
|
239
240
|
/* sequence<KeyUsage>: a new array of the strings, in order (duplicates kept, as Node keeps them),
|
|
@@ -373,7 +374,7 @@ typedef enum Op {
|
|
|
373
374
|
|
|
374
375
|
/* Parameter dictionaries, and their members (alphabetical, as WebIDL converts them) */
|
|
375
376
|
typedef enum Dict {
|
|
376
|
-
DICT_NONE, DICT_HMAC_IMPORT, DICT_HMAC_KEYGEN, DICT_PBKDF2, DICT_HKDF, DICT_AES_CBC, DICT_AES_CTR, DICT_AES_GCM, DICT_AES_KEYGEN,
|
|
377
|
+
DICT_NONE, DICT_HMAC_IMPORT, DICT_HMAC_KEYGEN, DICT_PBKDF2, DICT_HKDF, DICT_AES_CBC, DICT_AES_CTR, DICT_AES_GCM, DICT_AEAD, DICT_AES_KEYGEN,
|
|
377
378
|
DICT_AES_DERIVED, DICT_RSA_HASHED_IMPORT, DICT_RSA_HASHED_KEYGEN, DICT_RSA_PSS, DICT_RSA_OAEP, DICT_EC_IMPORT, DICT_EC_KEYGEN,
|
|
378
379
|
DICT_ECDSA, DICT_ECDH_DERIVE,
|
|
379
380
|
} Dict;
|
|
@@ -402,6 +403,7 @@ static const struct {
|
|
|
402
403
|
[DICT_AES_CBC] = { "AesCbcParams", { M_IV, M_END }, 1, 0 },
|
|
403
404
|
[DICT_AES_CTR] = { "AesCtrParams", { M_COUNTER, M_LENGTH, M_END }, 3, 255 },
|
|
404
405
|
[DICT_AES_GCM] = { "AesGcmParams", { M_ADDITIONAL_DATA, M_IV, M_TAG_LENGTH, M_END }, 2, 0 },
|
|
406
|
+
[DICT_AEAD] = { "AeadParams", { M_ADDITIONAL_DATA, M_IV, M_TAG_LENGTH, M_END }, 2, 0 },
|
|
405
407
|
[DICT_AES_KEYGEN] = { "AesKeyGenParams", { M_LENGTH, M_END }, 1, 65535 },
|
|
406
408
|
[DICT_AES_DERIVED] = { "AesDerivedKeyParams", { M_LENGTH, M_END }, 1, 65535 },
|
|
407
409
|
[DICT_RSA_HASHED_IMPORT] = { "RsaHashedImportParams", { M_HASH, M_END }, 1, 0 },
|
|
@@ -446,6 +448,8 @@ static const struct {
|
|
|
446
448
|
{ [OP_IMPORT_KEY] = DICT_EC_IMPORT, [OP_GENERATE_KEY] = DICT_EC_KEYGEN, [OP_DERIVE_BITS] = DICT_ECDH_DERIVE } },
|
|
447
449
|
{ "X25519", JS_WEB_X25519, KEY_OPS | BIT(OP_DERIVE_BITS), { [OP_DERIVE_BITS] = DICT_ECDH_DERIVE } },
|
|
448
450
|
{ "Ed25519", JS_WEB_ED25519, KEY_OPS | BIT(OP_SIGN) | BIT(OP_VERIFY), { 0 } },
|
|
451
|
+
{ "ChaCha20-Poly1305", JS_WEB_CHACHA20_POLY1305, BIT(OP_IMPORT_KEY) | BIT(OP_GENERATE_KEY) | BIT(OP_ENCRYPT) | BIT(OP_DECRYPT),
|
|
452
|
+
{ [OP_ENCRYPT] = DICT_AEAD, [OP_DECRYPT] = DICT_AEAD } },
|
|
449
453
|
};
|
|
450
454
|
|
|
451
455
|
/* A normalized algorithm: its registry entry and the members its dictionary has. */
|
|
@@ -714,6 +718,7 @@ static bool is_aes(uint8_t alg) { return alg >= JS_WEB_AES_CTR && alg <= JS_WEB_
|
|
|
714
718
|
/* A JWK's `alg` for a secret key: HS256, A128GCM, … */
|
|
715
719
|
static void jwk_alg(uint8_t alg, const JSHashAlg *hash, uint32_t length, char *out, size_t cap) {
|
|
716
720
|
if (alg == JS_WEB_HMAC) snprintf(out, cap, "HS%s", hash->web + 4);
|
|
721
|
+
else if (alg == JS_WEB_CHACHA20_POLY1305) snprintf(out, cap, "C20P");
|
|
717
722
|
else snprintf(out, cap, "A%u%s", length, web_alg_name(alg) + 4);
|
|
718
723
|
}
|
|
719
724
|
|
|
@@ -728,6 +733,14 @@ static JSValue aes_algorithm(JSContext *ctx, const char *name, uint32_t length)
|
|
|
728
733
|
return o;
|
|
729
734
|
}
|
|
730
735
|
|
|
736
|
+
/* a secret key's algorithm object: { name, length } for AES; ChaCha20-Poly1305's, { name } */
|
|
737
|
+
static JSValue secret_algorithm(JSContext *ctx, uint8_t alg, const char *name, uint32_t length) {
|
|
738
|
+
if (alg != JS_WEB_CHACHA20_POLY1305) return aes_algorithm(ctx, name, length);
|
|
739
|
+
JSValue a = js_new_object(ctx);
|
|
740
|
+
put(ctx, a, "name", str(ctx, name));
|
|
741
|
+
return a;
|
|
742
|
+
}
|
|
743
|
+
|
|
731
744
|
static JSValue import_aes(JSContext *ctx, int format, JSValue key_data, const JWK *jwk, Params *p, bool extractable, JSValue usages,
|
|
732
745
|
uint16_t mask) {
|
|
733
746
|
uint8_t alg = params_alg(p);
|
|
@@ -750,7 +763,7 @@ static JSValue import_aes(JSContext *ctx, int format, JSValue key_data, const JW
|
|
|
750
763
|
return dom_error(ctx, "NotSupportedError", m);
|
|
751
764
|
}
|
|
752
765
|
uint32_t length = (uint32_t)raw.n * 8;
|
|
753
|
-
if (length != 128 && length != 192 && length != 256) {
|
|
766
|
+
if (alg == JS_WEB_CHACHA20_POLY1305 ? length != 256 : length != 128 && length != 192 && length != 256) {
|
|
754
767
|
bytes_free(&raw);
|
|
755
768
|
return dom_error(ctx, "DataError", "Invalid key length");
|
|
756
769
|
}
|
|
@@ -764,7 +777,7 @@ static JSValue import_aes(JSContext *ctx, int format, JSValue key_data, const JW
|
|
|
764
777
|
}
|
|
765
778
|
JSValue data = js_new_secret_key(ctx, raw.p, raw.n);
|
|
766
779
|
bytes_free(&raw);
|
|
767
|
-
return js_new_crypto_key(ctx, data, alg, NULL, length,
|
|
780
|
+
return js_new_crypto_key(ctx, data, alg, NULL, length, secret_algorithm(ctx, alg, p->name, length), usages, mask, extractable);
|
|
768
781
|
}
|
|
769
782
|
|
|
770
783
|
/* ---- Asymmetric keys: RSA, EC, X25519 and Ed25519 ------------------------------------------------- */
|
|
@@ -1048,6 +1061,18 @@ static JSValue generate_asym(JSContext *ctx, Params *p, bool extractable, uint16
|
|
|
1048
1061
|
return pair;
|
|
1049
1062
|
}
|
|
1050
1063
|
|
|
1064
|
+
/* A raw-* format as raw for the algorithm it fits (raw-secret: a secret key's; raw-public: an EC,
|
|
1065
|
+
* X25519 or Ed25519 public key's), other formats as they are; -1 where it doesn't fit (raw-private
|
|
1066
|
+
* and raw-seed are ML-DSA's and ML-KEM's). */
|
|
1067
|
+
static int raw_alias(int alg, int format) {
|
|
1068
|
+
if (format == FORMAT_RAW && alg == JS_WEB_CHACHA20_POLY1305) return -1; /* Node: raw-secret only */
|
|
1069
|
+
if (format < FORMAT_RAW_PUBLIC) return format;
|
|
1070
|
+
bool secret = !is_asym_alg(alg);
|
|
1071
|
+
if (format == FORMAT_RAW_SECRET && secret) return FORMAT_RAW;
|
|
1072
|
+
if (format == FORMAT_RAW_PUBLIC && !secret && alg != JS_WEB_RSASSA && alg != JS_WEB_RSA_PSS && alg != JS_WEB_RSA_OAEP) return FORMAT_RAW;
|
|
1073
|
+
return -1;
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1051
1076
|
/* importKey's steps after the `this` check, for subtle.importKey and deriveKey. */
|
|
1052
1077
|
static JSValue import_key(JSContext *ctx, uint32_t argc, const JSValue *argv) {
|
|
1053
1078
|
Call c = { ctx, "importKey" };
|
|
@@ -1066,6 +1091,14 @@ static JSValue import_key(JSContext *ctx, uint32_t argc, const JSValue *argv) {
|
|
|
1066
1091
|
params_free(&p);
|
|
1067
1092
|
return JS_EXCEPTION;
|
|
1068
1093
|
}
|
|
1094
|
+
int raw = raw_alias(REGISTRY[p.entry].alg, format);
|
|
1095
|
+
if (raw < 0) {
|
|
1096
|
+
char m[96];
|
|
1097
|
+
snprintf(m, sizeof m, "Unable to import %s using %s format", p.name, FORMATS[format]);
|
|
1098
|
+
params_free(&p);
|
|
1099
|
+
return dom_error(ctx, "NotSupportedError", m);
|
|
1100
|
+
}
|
|
1101
|
+
format = raw;
|
|
1069
1102
|
JSValue key;
|
|
1070
1103
|
switch (REGISTRY[p.entry].alg) {
|
|
1071
1104
|
case JS_WEB_HMAC:
|
|
@@ -1075,6 +1108,7 @@ static JSValue import_key(JSContext *ctx, uint32_t argc, const JSValue *argv) {
|
|
|
1075
1108
|
case JS_WEB_AES_CBC:
|
|
1076
1109
|
case JS_WEB_AES_GCM:
|
|
1077
1110
|
case JS_WEB_AES_KW:
|
|
1111
|
+
case JS_WEB_CHACHA20_POLY1305:
|
|
1078
1112
|
key = import_aes(ctx, format, argv[1], &jwk, &p, extractable, usages, mask);
|
|
1079
1113
|
break;
|
|
1080
1114
|
case JS_WEB_RSASSA:
|
|
@@ -1121,6 +1155,14 @@ static JSValue export_key(JSContext *ctx, uint32_t argc, const JSValue *argv) {
|
|
|
1121
1155
|
return dom_error(ctx, "NotSupportedError", m);
|
|
1122
1156
|
}
|
|
1123
1157
|
if (!k->extractable) return dom_error(ctx, "InvalidAccessError", "key is not extractable");
|
|
1158
|
+
int raw = raw_alias(k->alg, format);
|
|
1159
|
+
if (raw < 0 || (format == FORMAT_RAW_PUBLIC && js_key_data(k->data)->type != JS_KEY_PUBLIC)) {
|
|
1160
|
+
uint8_t type = js_key_data(k->data)->type;
|
|
1161
|
+
snprintf(m, sizeof m, "Unable to export %s %s key using %s format", web_alg_name(k->alg),
|
|
1162
|
+
type == JS_KEY_SECRET ? "secret" : type == JS_KEY_PUBLIC ? "public" : "private", FORMATS[format]);
|
|
1163
|
+
return dom_error(ctx, "NotSupportedError", m);
|
|
1164
|
+
}
|
|
1165
|
+
format = raw;
|
|
1124
1166
|
if (is_asym_alg(k->alg)) return export_asym(ctx, format, k);
|
|
1125
1167
|
JSKeyData *d = js_key_data(k->data);
|
|
1126
1168
|
if (format == FORMAT_RAW) return array_buffer_of(ctx, d->bytes, d->len);
|
|
@@ -1229,6 +1271,9 @@ static JSValue generate_key(JSContext *ctx, uint32_t argc, const JSValue *argv)
|
|
|
1229
1271
|
if (p.has_length && p.length == 0) return dom_error(ctx, "OperationError", "HmacKeyGenParams.length cannot be 0");
|
|
1230
1272
|
length = p.has_length ? p.length : (uint32_t)p.hash->block_len * 8;
|
|
1231
1273
|
if (has_any_not_in(mask, JS_USAGE_SIGN | JS_USAGE_VERIFY)) return dom_error(ctx, "SyntaxError", "Unsupported key usage for HMAC key");
|
|
1274
|
+
} else if (alg == JS_WEB_CHACHA20_POLY1305) {
|
|
1275
|
+
length = 256;
|
|
1276
|
+
if (has_any_not_in(mask, aes_usages(alg))) return usage_error(ctx, p.name);
|
|
1232
1277
|
} else {
|
|
1233
1278
|
length = p.length;
|
|
1234
1279
|
if (length != 128 && length != 192 && length != 256)
|
|
@@ -1245,7 +1290,7 @@ static JSValue generate_key(JSContext *ctx, uint32_t argc, const JSValue *argv)
|
|
|
1245
1290
|
JSValue data = js_new_secret_key(ctx, bytes, n);
|
|
1246
1291
|
free(bytes);
|
|
1247
1292
|
if (js_array_length(js_as_object(usages)) == 0) return dom_error(ctx, "SyntaxError", "Usages cannot be empty when creating a key.");
|
|
1248
|
-
JSValue algorithm = alg == JS_WEB_HMAC ? hmac_algorithm(ctx, p.hash, length) :
|
|
1293
|
+
JSValue algorithm = alg == JS_WEB_HMAC ? hmac_algorithm(ctx, p.hash, length) : secret_algorithm(ctx, alg, p.name, length);
|
|
1249
1294
|
return js_new_crypto_key(ctx, data, alg, p.hash, length, algorithm, usages, mask, extractable);
|
|
1250
1295
|
}
|
|
1251
1296
|
|
|
@@ -1564,6 +1609,20 @@ static JSValue aes_cipher(JSContext *ctx, bool encrypt, JSCryptoKey *k, Params *
|
|
|
1564
1609
|
data->p, data->n - tag_n, &out);
|
|
1565
1610
|
break;
|
|
1566
1611
|
}
|
|
1612
|
+
case JS_WEB_CHACHA20_POLY1305: {
|
|
1613
|
+
uint32_t tag_bits = p->has_tag_length ? p->tag_length : 128;
|
|
1614
|
+
if (tag_bits != 128) {
|
|
1615
|
+
char m[64];
|
|
1616
|
+
snprintf(m, sizeof m, "%u is not a valid ChaCha20-Poly1305 tag length", tag_bits);
|
|
1617
|
+
return dom_error(ctx, "OperationError", m);
|
|
1618
|
+
}
|
|
1619
|
+
if (p->iv.n != 12) return dom_error(ctx, "OperationError", "algorithm.iv must contain exactly 12 bytes");
|
|
1620
|
+
if (!encrypt && data->n < 16) return op_failed(ctx);
|
|
1621
|
+
const JSCipherAlg *alg = js_cipher_by_name("chacha20-poly1305");
|
|
1622
|
+
ok = encrypt ? run_cipher(alg, true, d, p->iv.p, 12, 16, &p->additional_data, NULL, 0, data->p, data->n, &out)
|
|
1623
|
+
: run_cipher(alg, false, d, p->iv.p, 12, 16, &p->additional_data, data->p + data->n - 16, 16, data->p, data->n - 16, &out);
|
|
1624
|
+
break;
|
|
1625
|
+
}
|
|
1567
1626
|
default: { /* AES-KW, with RFC 3394's default IV */
|
|
1568
1627
|
static const uint8_t KW_IV[8] = { 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6 };
|
|
1569
1628
|
ok = run_cipher(js_cipher_aes(JS_CIPHER_WRAP, d->len), encrypt, d, KW_IV, 8, -1, NULL, NULL, 0, data->p, data->n, &out);
|
package/runtime/src/crypto_tls.c
CHANGED
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
#include <openssl/err.h>
|
|
21
21
|
#include <openssl/evp.h>
|
|
22
22
|
#include <openssl/pem.h>
|
|
23
|
+
#include <openssl/pkcs8.h>
|
|
23
24
|
#include <openssl/ssl.h>
|
|
24
25
|
#include <openssl/x509.h>
|
|
25
26
|
|
|
@@ -263,27 +264,33 @@ PRIMITIVE(js_tls_context_set_cert) {
|
|
|
263
264
|
return js_int32(0);
|
|
264
265
|
}
|
|
265
266
|
|
|
266
|
-
/*
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
JSKeyData *k = js_key_data(ARG(1));
|
|
271
|
-
if (!o || !k) return js_throw_type_error(ctx, "tlsContextSetKey: a context and a key expected");
|
|
272
|
-
if (k->type != JS_KEY_PRIVATE) return js_int32(1);
|
|
267
|
+
/* A key (handle) as BoringSSL's, from its PKCS#8 or SPKI DER, or NULL for one BoringSSL can't use */
|
|
268
|
+
static EVP_PKEY *pkey_of(const JSKeyData *k) {
|
|
269
|
+
bool private = k->type == JS_KEY_PRIVATE;
|
|
270
|
+
if (!private && k->type != JS_KEY_PUBLIC) return NULL;
|
|
273
271
|
JSBytesOut der = { 0 };
|
|
274
|
-
if (js_key_export_der(k, JS_KEY_ENC_PKCS8, &der) != 0) {
|
|
272
|
+
if (js_key_export_der(k, private ? JS_KEY_ENC_PKCS8 : JS_KEY_ENC_SPKI, &der) != 0) {
|
|
275
273
|
free(der.p);
|
|
276
|
-
return
|
|
274
|
+
return NULL;
|
|
277
275
|
}
|
|
278
276
|
CBS cbs;
|
|
279
277
|
CBS_init(&cbs, der.p, der.n);
|
|
280
|
-
EVP_PKEY *pkey = EVP_parse_private_key(&cbs);
|
|
278
|
+
EVP_PKEY *pkey = private ? EVP_parse_private_key(&cbs) : EVP_parse_public_key(&cbs);
|
|
281
279
|
memset(der.p, 0, der.n);
|
|
282
280
|
free(der.p);
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
281
|
+
ERR_clear_error();
|
|
282
|
+
return pkey;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/* tlsContextSetKey(context, key handle) → 0 | 1 a key TLS can't use | 2 not the certificate's key */
|
|
286
|
+
PRIMITIVE(js_tls_context_set_key) {
|
|
287
|
+
UNUSED_ARGS;
|
|
288
|
+
TlsContextObject *o = context_arg(ARG(0));
|
|
289
|
+
JSKeyData *k = js_key_data(ARG(1));
|
|
290
|
+
if (!o || !k) return js_throw_type_error(ctx, "tlsContextSetKey: a context and a key expected");
|
|
291
|
+
if (k->type != JS_KEY_PRIVATE) return js_int32(1);
|
|
292
|
+
EVP_PKEY *pkey = pkey_of(k);
|
|
293
|
+
if (!pkey) return js_int32(1);
|
|
287
294
|
int ok = SSL_CTX_use_PrivateKey(o->ctx, pkey);
|
|
288
295
|
EVP_PKEY_free(pkey);
|
|
289
296
|
ERR_clear_error();
|
|
@@ -291,6 +298,195 @@ PRIMITIVE(js_tls_context_set_key) {
|
|
|
291
298
|
return js_int32(0);
|
|
292
299
|
}
|
|
293
300
|
|
|
301
|
+
/* tlsContextAddCredential(context, [der, …], key handle) → 0 | 1 a key TLS can't use | 2 not the
|
|
302
|
+
* certificate's key: one of a server's identities (a chain, leaf first, and its key), which
|
|
303
|
+
* BoringSSL chooses among by what the client accepts, as OpenSSL does by key type */
|
|
304
|
+
PRIMITIVE(js_tls_context_add_credential) {
|
|
305
|
+
UNUSED_ARGS;
|
|
306
|
+
TlsContextObject *o = context_arg(ARG(0));
|
|
307
|
+
JSKeyData *k = js_key_data(ARG(2));
|
|
308
|
+
if (!o || !js_is_array(ARG(1)) || !k) return js_throw_type_error(ctx, "tlsContextAddCredential: a context, certificates and a key expected");
|
|
309
|
+
uint32_t n = js_array_length(js_as_object(ARG(1)));
|
|
310
|
+
if (n == 0 || n > 16) return js_throw_type_error(ctx, "tlsContextAddCredential: 1 to 16 certificates expected");
|
|
311
|
+
CRYPTO_BUFFER *certs[16] = { 0 };
|
|
312
|
+
int result = 0;
|
|
313
|
+
for (uint32_t i = 0; i < n && result == 0; i++) {
|
|
314
|
+
const uint8_t *p;
|
|
315
|
+
size_t len;
|
|
316
|
+
if (!bytes_arg(js_get_value(ctx, ARG(1), js_index_key(i)), &p, &len) || !(certs[i] = CRYPTO_BUFFER_new(p, len, NULL))) result = 1;
|
|
317
|
+
}
|
|
318
|
+
EVP_PKEY *pkey = result == 0 && k->type == JS_KEY_PRIVATE ? pkey_of(k) : NULL;
|
|
319
|
+
SSL_CREDENTIAL *cred = SSL_CREDENTIAL_new_x509();
|
|
320
|
+
if (result == 0 && (!pkey || !cred)) result = 1;
|
|
321
|
+
if (result == 0 && !SSL_CREDENTIAL_set1_cert_chain(cred, certs, n)) result = 1;
|
|
322
|
+
if (result == 0 && !SSL_CREDENTIAL_set1_private_key(cred, pkey)) result = 2;
|
|
323
|
+
if (result == 0 && !SSL_CTX_add1_credential(o->ctx, cred)) result = 1;
|
|
324
|
+
SSL_CREDENTIAL_free(cred);
|
|
325
|
+
EVP_PKEY_free(pkey);
|
|
326
|
+
for (uint32_t i = 0; i < n; i++) CRYPTO_BUFFER_free(certs[i]);
|
|
327
|
+
ERR_clear_error();
|
|
328
|
+
return js_int32(result);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/* tlsContextAllowPartialChain(context): a trusted intermediate ends a chain, as a root does
|
|
332
|
+
* (allowPartialTrustChain); on the context's parameters, as its store may be the shared roots' */
|
|
333
|
+
PRIMITIVE(js_tls_context_allow_partial_chain) {
|
|
334
|
+
UNUSED_ARGS;
|
|
335
|
+
TlsContextObject *o = context_arg(ARG(0));
|
|
336
|
+
if (!o) return js_throw_type_error(ctx, "tlsContextAllowPartialChain: a context expected");
|
|
337
|
+
X509_VERIFY_PARAM_set_flags(SSL_CTX_get0_param(o->ctx), X509_V_FLAG_PARTIAL_CHAIN);
|
|
338
|
+
return JS_UNDEFINED;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/* tlsContextTicketKeys(context, keys | null) → the 48 bytes the context's session tickets are
|
|
342
|
+
* encrypted with (after setting them to `keys`) */
|
|
343
|
+
PRIMITIVE(js_tls_context_ticket_keys) {
|
|
344
|
+
UNUSED_ARGS;
|
|
345
|
+
TlsContextObject *o = context_arg(ARG(0));
|
|
346
|
+
if (!o) return js_throw_type_error(ctx, "tlsContextTicketKeys: a context expected");
|
|
347
|
+
const uint8_t *p;
|
|
348
|
+
size_t n;
|
|
349
|
+
if (bytes_arg(ARG(1), &p, &n)) {
|
|
350
|
+
if (n != 48 || !SSL_CTX_set_tlsext_ticket_keys(o->ctx, p, n)) return js_throw_type_error(ctx, "tlsContextTicketKeys: 48 bytes expected");
|
|
351
|
+
}
|
|
352
|
+
uint8_t keys[48];
|
|
353
|
+
SSL_CTX_get_tlsext_ticket_keys(o->ctx, keys, sizeof keys);
|
|
354
|
+
return js_new_buffer_from_bytes(ctx, keys, sizeof keys);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/* tlsContextSetSessions(context, timeout | null, sessionIdContext | null): how long a session can
|
|
358
|
+
* be resumed (seconds), and the context its id is valid in */
|
|
359
|
+
PRIMITIVE(js_tls_context_set_sessions) {
|
|
360
|
+
UNUSED_ARGS;
|
|
361
|
+
TlsContextObject *o = context_arg(ARG(0));
|
|
362
|
+
if (!o) return js_throw_type_error(ctx, "tlsContextSetSessions: a context expected");
|
|
363
|
+
if (js_is_number(ARG(1))) SSL_CTX_set_timeout(o->ctx, (uint32_t)js_as_number(ARG(1)));
|
|
364
|
+
char *sid = string_dup(ctx, ARG(2));
|
|
365
|
+
if (sid) {
|
|
366
|
+
/* OpenSSL's limit, which Node passes through */
|
|
367
|
+
size_t n = strlen(sid);
|
|
368
|
+
SSL_CTX_set_session_id_context(o->ctx, (const uint8_t *)sid, n > SSL_MAX_SID_CTX_LENGTH ? SSL_MAX_SID_CTX_LENGTH : n);
|
|
369
|
+
free(sid);
|
|
370
|
+
}
|
|
371
|
+
return JS_UNDEFINED;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/* tlsPkcs12(der, password | null) → [private key (PKCS#8 DER) | null, certificate (DER) | null,
|
|
375
|
+
* [the other certificates' DER, …]] | the reason it can't be read (OpenSSL's words) */
|
|
376
|
+
PRIMITIVE(js_tls_pkcs12) {
|
|
377
|
+
UNUSED_ARGS;
|
|
378
|
+
const uint8_t *p;
|
|
379
|
+
size_t n;
|
|
380
|
+
if (!bytes_arg(ARG(0), &p, &n)) return js_throw_type_error(ctx, "tlsPkcs12: bytes expected");
|
|
381
|
+
char *password = string_dup(ctx, ARG(1));
|
|
382
|
+
PKCS12 *p12 = d2i_PKCS12(NULL, &p, (long)n);
|
|
383
|
+
EVP_PKEY *pkey = NULL;
|
|
384
|
+
X509 *cert = NULL;
|
|
385
|
+
STACK_OF(X509) *others = NULL;
|
|
386
|
+
bool ok = p12 && PKCS12_parse(p12, password, &pkey, &cert, &others);
|
|
387
|
+
if (password) {
|
|
388
|
+
memset(password, 0, strlen(password));
|
|
389
|
+
free(password);
|
|
390
|
+
}
|
|
391
|
+
PKCS12_free(p12);
|
|
392
|
+
if (!ok) {
|
|
393
|
+
const char *reason = ERR_reason_error_string(ERR_peek_last_error());
|
|
394
|
+
ERR_clear_error();
|
|
395
|
+
return js_new_string_cstr(ctx, reason ? reason : "Unknown error");
|
|
396
|
+
}
|
|
397
|
+
JSValue parts[3] = { JS_NULL, JS_NULL, JS_NULL };
|
|
398
|
+
if (pkey) {
|
|
399
|
+
CBB cbb;
|
|
400
|
+
uint8_t *der;
|
|
401
|
+
size_t len;
|
|
402
|
+
if (CBB_init(&cbb, 0) && EVP_marshal_private_key(&cbb, pkey) && CBB_finish(&cbb, &der, &len)) {
|
|
403
|
+
parts[0] = js_new_buffer_from_bytes(ctx, der, len);
|
|
404
|
+
OPENSSL_cleanse(der, len);
|
|
405
|
+
OPENSSL_free(der);
|
|
406
|
+
} else {
|
|
407
|
+
CBB_cleanup(&cbb);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
uint8_t *der = NULL;
|
|
411
|
+
int len;
|
|
412
|
+
if (cert && (len = i2d_X509(cert, &der)) > 0) parts[1] = js_new_buffer_from_bytes(ctx, der, (size_t)len);
|
|
413
|
+
OPENSSL_free(der);
|
|
414
|
+
size_t count = others ? sk_X509_num(others) : 0;
|
|
415
|
+
parts[2] = js_new_array(ctx, 0);
|
|
416
|
+
for (size_t i = 0; i < count; i++) {
|
|
417
|
+
der = NULL;
|
|
418
|
+
if ((len = i2d_X509(sk_X509_value(others, i), &der)) > 0 &&
|
|
419
|
+
js_array_append(ctx, parts[2], js_new_buffer_from_bytes(ctx, der, (size_t)len)) < 0) {
|
|
420
|
+
OPENSSL_free(der);
|
|
421
|
+
parts[2] = JS_EXCEPTION;
|
|
422
|
+
break;
|
|
423
|
+
}
|
|
424
|
+
OPENSSL_free(der);
|
|
425
|
+
}
|
|
426
|
+
EVP_PKEY_free(pkey);
|
|
427
|
+
X509_free(cert);
|
|
428
|
+
sk_X509_pop_free(others, X509_free);
|
|
429
|
+
ERR_clear_error();
|
|
430
|
+
return js_is_exception(parts[2]) ? JS_EXCEPTION : js_new_array_from(ctx, parts, 3);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/* ---- Certificates (crypto.X509Certificate's checks, as OpenSSL's) ---------------------------------- */
|
|
434
|
+
|
|
435
|
+
/* x509Check(der, kind, value, flags) → the name matched (kind 0: a host, 1: an email address,
|
|
436
|
+
* 2: an IP address) or undefined; flags are X509_CHECK_FLAG_*'s */
|
|
437
|
+
PRIMITIVE(js_x509_check) {
|
|
438
|
+
UNUSED_ARGS;
|
|
439
|
+
X509 *x = x509_arg(ARG(0));
|
|
440
|
+
char *value = string_dup(ctx, ARG(2));
|
|
441
|
+
if (!x || !value || !js_is_number(ARG(1))) {
|
|
442
|
+
X509_free(x);
|
|
443
|
+
free(value);
|
|
444
|
+
ERR_clear_error();
|
|
445
|
+
return js_throw_type_error(ctx, "x509Check: a certificate, a kind and a value expected");
|
|
446
|
+
}
|
|
447
|
+
unsigned flags = js_is_number(ARG(3)) ? (unsigned)js_as_number(ARG(3)) : 0;
|
|
448
|
+
size_t n = strlen(value);
|
|
449
|
+
char *peer = NULL;
|
|
450
|
+
int r;
|
|
451
|
+
switch ((int)js_as_number(ARG(1))) {
|
|
452
|
+
case 0: r = X509_check_host(x, value, n, flags, &peer); break;
|
|
453
|
+
case 1: r = X509_check_email(x, value, n, flags); break;
|
|
454
|
+
default: r = X509_check_ip_asc(x, value, flags); break;
|
|
455
|
+
}
|
|
456
|
+
JSValue out = JS_UNDEFINED;
|
|
457
|
+
if (r == 1) out = js_new_string_utf8(ctx, peer ? peer : value, strlen(peer ? peer : value));
|
|
458
|
+
OPENSSL_free(peer);
|
|
459
|
+
free(value);
|
|
460
|
+
X509_free(x);
|
|
461
|
+
ERR_clear_error();
|
|
462
|
+
return out;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/* x509CheckIssued(der, issuerDer) → whether the issuer's name, key identifier and key usage fit (X509_check_issued) */
|
|
466
|
+
PRIMITIVE(js_x509_check_issued) {
|
|
467
|
+
UNUSED_ARGS;
|
|
468
|
+
X509 *x = x509_arg(ARG(0)), *issuer = x509_arg(ARG(1));
|
|
469
|
+
bool ok = x && issuer && X509_check_issued(issuer, x) == X509_V_OK;
|
|
470
|
+
X509_free(x);
|
|
471
|
+
X509_free(issuer);
|
|
472
|
+
ERR_clear_error();
|
|
473
|
+
return js_bool(ok);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/* x509CheckKey(der, key handle) → for a public key, whether it signed the certificate; for a
|
|
477
|
+
* private one, whether it is the certificate's */
|
|
478
|
+
PRIMITIVE(js_x509_check_key) {
|
|
479
|
+
UNUSED_ARGS;
|
|
480
|
+
X509 *x = x509_arg(ARG(0));
|
|
481
|
+
JSKeyData *k = js_key_data(ARG(1));
|
|
482
|
+
EVP_PKEY *pkey = k ? pkey_of(k) : NULL;
|
|
483
|
+
bool ok = x && pkey && (k->type == JS_KEY_PRIVATE ? X509_check_private_key(x, pkey) : X509_verify(x, pkey)) == 1;
|
|
484
|
+
EVP_PKEY_free(pkey);
|
|
485
|
+
X509_free(x);
|
|
486
|
+
ERR_clear_error();
|
|
487
|
+
return js_bool(ok);
|
|
488
|
+
}
|
|
489
|
+
|
|
294
490
|
/* ---- Connections -------------------------------------------------------------------------------- */
|
|
295
491
|
|
|
296
492
|
typedef struct TlsConnData {
|
|
@@ -301,10 +497,13 @@ typedef struct TlsConnData {
|
|
|
301
497
|
uint32_t handshakes;
|
|
302
498
|
bool in_handshake;
|
|
303
499
|
SSL_SESSION *new_session; /* the last session (or ticket) the peer gave: tlsRun reports it once */
|
|
500
|
+
SSL_SESSION *offered_session; /* a client's, to resume */
|
|
304
501
|
bool session_reported;
|
|
305
502
|
uint8_t *alpn; /* a server's protocols, in the wire format */
|
|
306
503
|
size_t alpn_len;
|
|
307
504
|
bool alpn_strict;
|
|
505
|
+
bool keylog_on;
|
|
506
|
+
JSBytesOut keylog; /* NSS key log lines since tlsRun last reported them */
|
|
308
507
|
} TlsConnData;
|
|
309
508
|
|
|
310
509
|
typedef struct TlsConnObject {
|
|
@@ -346,7 +545,9 @@ static void conn_finalize(JSRuntime *rt, JSCell *cell) {
|
|
|
346
545
|
if (!d) return;
|
|
347
546
|
SSL_free(d->ssl); /* and its BIOs */
|
|
348
547
|
SSL_SESSION_free(d->new_session);
|
|
548
|
+
SSL_SESSION_free(d->offered_session);
|
|
349
549
|
free(d->alpn);
|
|
550
|
+
free(d->keylog.p);
|
|
350
551
|
free(d);
|
|
351
552
|
}
|
|
352
553
|
|
|
@@ -419,7 +620,7 @@ PRIMITIVE(js_tls_new) {
|
|
|
419
620
|
if (bytes_arg(ARG(4), &sp, &spn)) {
|
|
420
621
|
SSL_SESSION *s = SSL_SESSION_from_bytes(sp, spn, cx->ctx);
|
|
421
622
|
if (s) SSL_set_session(d->ssl, s);
|
|
422
|
-
|
|
623
|
+
d->offered_session = s; /* the reference from_bytes gave */
|
|
423
624
|
}
|
|
424
625
|
}
|
|
425
626
|
ERR_clear_error();
|
|
@@ -437,7 +638,8 @@ static bool fatal(int e) {
|
|
|
437
638
|
|
|
438
639
|
/* tlsRun(connection, records | null, data | null) → [records out | null, data received | null,
|
|
439
640
|
* bytes of `data` taken, state (1 established, 2 failed, 4 the peer's close_notify, 8 a new
|
|
440
|
-
* session to report), error ([library, reason, name] | 0), handshakes finished
|
|
641
|
+
* session to report), error ([library, reason, name] | 0), handshakes finished, key log lines |
|
|
642
|
+
* null]: feeds the
|
|
441
643
|
* engine what it was given and runs it until it can't go on. `data` is taken once the handshake
|
|
442
644
|
* is done (and not during a renegotiation); what isn't is given again later. */
|
|
443
645
|
PRIMITIVE(js_tls_run) {
|
|
@@ -515,16 +717,18 @@ PRIMITIVE(js_tls_run) {
|
|
|
515
717
|
d->session_reported = true;
|
|
516
718
|
state |= TLS_NEW_SESSION;
|
|
517
719
|
}
|
|
720
|
+
JSValue keylog = bytes_or_null(ctx, &d->keylog);
|
|
721
|
+
d->keylog = (JSBytesOut){ 0 };
|
|
518
722
|
JSBytesOut out = { 0 };
|
|
519
723
|
const uint8_t *p;
|
|
520
724
|
size_t n;
|
|
521
725
|
if (BIO_mem_contents(d->out, &p, &n) && n) out_append(&out, p, n);
|
|
522
726
|
BIO_reset(d->out);
|
|
523
727
|
ERR_clear_error();
|
|
524
|
-
JSValue items[
|
|
728
|
+
JSValue items[7] = { JS_NULL, JS_NULL, js_number((double)taken), js_int32(state), err, js_number(d->handshakes), keylog };
|
|
525
729
|
items[0] = bytes_or_null(ctx, &out);
|
|
526
730
|
items[1] = bytes_or_null(ctx, &app);
|
|
527
|
-
return js_new_array_from(ctx, items,
|
|
731
|
+
return js_new_array_from(ctx, items, 7);
|
|
528
732
|
}
|
|
529
733
|
|
|
530
734
|
/* tlsShutdown(connection) → the records to send | null: our close_notify; reading goes on until
|
|
@@ -605,8 +809,9 @@ PRIMITIVE(js_tls_session) {
|
|
|
605
809
|
UNUSED_ARGS;
|
|
606
810
|
TlsConnData *d = conn_arg(ARG(0));
|
|
607
811
|
if (!d || !d->established) return JS_UNDEFINED;
|
|
812
|
+
/* OpenSSL's, which Node returns: a TLS 1.3 session before its tickets too (it won't resume) */
|
|
608
813
|
SSL_SESSION *s = d->new_session ? d->new_session : SSL_get_session(d->ssl);
|
|
609
|
-
if (!s
|
|
814
|
+
if (!s) return JS_UNDEFINED;
|
|
610
815
|
uint8_t *p;
|
|
611
816
|
size_t n;
|
|
612
817
|
if (!SSL_SESSION_to_bytes(s, &p, &n)) {
|
|
@@ -618,6 +823,21 @@ PRIMITIVE(js_tls_session) {
|
|
|
618
823
|
return v;
|
|
619
824
|
}
|
|
620
825
|
|
|
826
|
+
/* tlsTicket(connection) → Buffer | undefined: the session ticket a client was given */
|
|
827
|
+
PRIMITIVE(js_tls_ticket) {
|
|
828
|
+
UNUSED_ARGS;
|
|
829
|
+
TlsConnData *d = conn_arg(ARG(0));
|
|
830
|
+
if (!d) return JS_UNDEFINED;
|
|
831
|
+
/* resumed, a TLS 1.3 session is a copy without the ticket: the one offered had it */
|
|
832
|
+
SSL_SESSION *s = d->new_session ? d->new_session
|
|
833
|
+
: SSL_session_reused(d->ssl) && d->offered_session ? d->offered_session : SSL_get_session(d->ssl);
|
|
834
|
+
const uint8_t *p;
|
|
835
|
+
size_t n;
|
|
836
|
+
if (!s || !SSL_SESSION_has_ticket(s)) return JS_UNDEFINED;
|
|
837
|
+
SSL_SESSION_get0_ticket(s, &p, &n);
|
|
838
|
+
return js_new_buffer_from_bytes(ctx, p, n);
|
|
839
|
+
}
|
|
840
|
+
|
|
621
841
|
/* tlsExportKeyingMaterial(connection, length, label, context | undefined) → Buffer | null (RFC 5705) */
|
|
622
842
|
PRIMITIVE(js_tls_export_keying_material) {
|
|
623
843
|
UNUSED_ARGS;
|
|
@@ -670,9 +890,35 @@ PRIMITIVE(js_tls_ciphers) {
|
|
|
670
890
|
|
|
671
891
|
/* tlsSetNoRenegotiation(connection): a server's requests to renegotiate are refused (BoringSSL
|
|
672
892
|
* renegotiates only as a client, when a server asks; it never starts one) */
|
|
893
|
+
static void on_keylog(const SSL *ssl, const char *line) {
|
|
894
|
+
TlsConnData *d = SSL_get_app_data(ssl);
|
|
895
|
+
if (!d || !d->keylog_on) return;
|
|
896
|
+
out_append(&d->keylog, line, strlen(line));
|
|
897
|
+
out_append(&d->keylog, "\n", 1);
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
/* tlsEnableKeylog(connection): its key log lines come with tlsRun's results (the 'keylog' event) */
|
|
901
|
+
PRIMITIVE(js_tls_enable_keylog) {
|
|
902
|
+
UNUSED_ARGS;
|
|
903
|
+
TlsConnData *d = conn_arg(ARG(0));
|
|
904
|
+
if (!d) return JS_UNDEFINED;
|
|
905
|
+
d->keylog_on = true;
|
|
906
|
+
/* the context's: BoringSSL forms the lines only for a context that has a callback */
|
|
907
|
+
SSL_CTX_set_keylog_callback(SSL_get_SSL_CTX(d->ssl), on_keylog);
|
|
908
|
+
return JS_UNDEFINED;
|
|
909
|
+
}
|
|
910
|
+
|
|
673
911
|
PRIMITIVE(js_tls_set_no_renegotiation) {
|
|
674
912
|
UNUSED_ARGS;
|
|
675
913
|
TlsConnData *d = conn_arg(ARG(0));
|
|
676
914
|
if (d && !d->server) SSL_set_renegotiate_mode(d->ssl, ssl_renegotiate_never);
|
|
677
915
|
return JS_UNDEFINED;
|
|
678
916
|
}
|
|
917
|
+
|
|
918
|
+
/* tlsSetMaxSendFragment(connection, size): the largest record's plaintext (512 to 16384) */
|
|
919
|
+
PRIMITIVE(js_tls_set_max_send_fragment) {
|
|
920
|
+
UNUSED_ARGS;
|
|
921
|
+
TlsConnData *d = conn_arg(ARG(0));
|
|
922
|
+
if (d && js_is_number(ARG(1))) SSL_set_max_send_fragment(d->ssl, (size_t)js_as_number(ARG(1)));
|
|
923
|
+
return JS_UNDEFINED;
|
|
924
|
+
}
|