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.
Files changed (221) hide show
  1. package/README.md +12 -4
  2. package/THIRD_PARTY_LICENSES +31 -1
  3. package/cli.js +962 -68
  4. package/node/include/js_node.h +11 -1
  5. package/node/prelude/_http_common.js +29 -0
  6. package/node/prelude/async_hooks.js +50 -11
  7. package/node/prelude/child_process.js +31 -4
  8. package/node/prelude/console.js +311 -143
  9. package/node/prelude/crypto.js +6 -4
  10. package/node/prelude/dgram.js +1169 -0
  11. package/node/prelude/diagnostics_channel.js +3 -1
  12. package/node/prelude/dns.js +250 -45
  13. package/node/prelude/dns_promises.js +8 -2
  14. package/node/prelude/fs_promises.js +9 -1
  15. package/node/prelude/http.js +395 -86
  16. package/node/prelude/https.js +13 -4
  17. package/node/prelude/internal/console_class.js +7 -0
  18. package/node/prelude/internal/console_global.js +25 -0
  19. package/node/prelude/internal/crypto/key_encryption.js +217 -0
  20. package/node/prelude/internal/crypto/keys.js +161 -26
  21. package/node/prelude/internal/crypto/random.js +24 -0
  22. package/node/prelude/internal/crypto/util.js +2 -1
  23. package/node/prelude/internal/crypto_x509.js +161 -0
  24. package/node/prelude/internal/dns_classes.js +6 -0
  25. package/node/prelude/internal/dns_resolver.js +371 -0
  26. package/node/prelude/internal/errors.js +9 -0
  27. package/node/prelude/internal/events_on.js +82 -37
  28. package/node/prelude/internal/features.js +8 -4
  29. package/node/prelude/internal/fs_filehandle.js +10 -4
  30. package/node/prelude/internal/perf_histogram.js +1 -1
  31. package/node/prelude/internal/process_more.js +32 -17
  32. package/node/prelude/internal/process_signals.js +8 -2
  33. package/node/prelude/internal/punycode.ts +163 -0
  34. package/node/prelude/internal/readline.js +648 -274
  35. package/node/prelude/internal/readline_editor.js +1240 -0
  36. package/node/prelude/internal/string_width.js +43 -0
  37. package/node/prelude/internal/tls/common.js +145 -33
  38. package/node/prelude/internal/tls/wrap.js +182 -49
  39. package/node/prelude/internal/tls/x509.js +4 -1
  40. package/node/prelude/internal/udp.js +177 -0
  41. package/node/prelude/net.js +13 -1
  42. package/node/prelude/os.js +24 -6
  43. package/node/prelude/perf_hooks.js +37 -2
  44. package/node/prelude/punycode.js +2 -130
  45. package/node/prelude/readline.js +113 -4
  46. package/node/prelude/readline_promises.js +56 -32
  47. package/node/prelude/tls.js +21 -4
  48. package/node/prelude/util.js +3 -16
  49. package/node/src/host_dns.c +623 -0
  50. package/node/src/host_http.c +12 -0
  51. package/node/src/host_net.c +46 -0
  52. package/node/src/host_os.c +1 -6
  53. package/node/src/host_sys.c +70 -0
  54. package/node/src/host_udp.c +418 -0
  55. package/node/third_party/c-ares/LICENSE.md +24 -0
  56. package/node/third_party/c-ares/config/darwin/ares_config.h +573 -0
  57. package/node/third_party/c-ares/config/freebsd/ares_config.h +573 -0
  58. package/node/third_party/c-ares/config/linux/ares_config.h +573 -0
  59. package/node/third_party/c-ares/config/openbsd/ares_config.h +583 -0
  60. package/node/third_party/c-ares/include/ares.h +1237 -0
  61. package/node/third_party/c-ares/include/ares_build.h +202 -0
  62. package/node/third_party/c-ares/include/ares_dns.h +127 -0
  63. package/node/third_party/c-ares/include/ares_dns_record.h +1119 -0
  64. package/node/third_party/c-ares/include/ares_nameser.h +510 -0
  65. package/node/third_party/c-ares/include/ares_version.h +47 -0
  66. package/node/third_party/c-ares/src/lib/ares_addrinfo2hostent.c +305 -0
  67. package/node/third_party/c-ares/src/lib/ares_addrinfo_localhost.c +245 -0
  68. package/node/third_party/c-ares/src/lib/ares_android.c +496 -0
  69. package/node/third_party/c-ares/src/lib/ares_android.h +38 -0
  70. package/node/third_party/c-ares/src/lib/ares_cancel.c +87 -0
  71. package/node/third_party/c-ares/src/lib/ares_close_sockets.c +137 -0
  72. package/node/third_party/c-ares/src/lib/ares_conn.c +511 -0
  73. package/node/third_party/c-ares/src/lib/ares_conn.h +202 -0
  74. package/node/third_party/c-ares/src/lib/ares_cookie.c +461 -0
  75. package/node/third_party/c-ares/src/lib/ares_data.c +168 -0
  76. package/node/third_party/c-ares/src/lib/ares_data.h +92 -0
  77. package/node/third_party/c-ares/src/lib/ares_destroy.c +159 -0
  78. package/node/third_party/c-ares/src/lib/ares_free_hostent.c +54 -0
  79. package/node/third_party/c-ares/src/lib/ares_free_string.c +33 -0
  80. package/node/third_party/c-ares/src/lib/ares_freeaddrinfo.c +67 -0
  81. package/node/third_party/c-ares/src/lib/ares_getaddrinfo.c +806 -0
  82. package/node/third_party/c-ares/src/lib/ares_getenv.c +38 -0
  83. package/node/third_party/c-ares/src/lib/ares_getenv.h +34 -0
  84. package/node/third_party/c-ares/src/lib/ares_gethostbyaddr.c +229 -0
  85. package/node/third_party/c-ares/src/lib/ares_gethostbyname.c +341 -0
  86. package/node/third_party/c-ares/src/lib/ares_getnameinfo.c +437 -0
  87. package/node/third_party/c-ares/src/lib/ares_hosts_file.c +960 -0
  88. package/node/third_party/c-ares/src/lib/ares_inet_net_pton.h +31 -0
  89. package/node/third_party/c-ares/src/lib/ares_init.c +631 -0
  90. package/node/third_party/c-ares/src/lib/ares_ipv6.h +115 -0
  91. package/node/third_party/c-ares/src/lib/ares_library_init.c +190 -0
  92. package/node/third_party/c-ares/src/lib/ares_metrics.c +261 -0
  93. package/node/third_party/c-ares/src/lib/ares_options.c +492 -0
  94. package/node/third_party/c-ares/src/lib/ares_parse_into_addrinfo.c +179 -0
  95. package/node/third_party/c-ares/src/lib/ares_private.h +648 -0
  96. package/node/third_party/c-ares/src/lib/ares_process.c +1649 -0
  97. package/node/third_party/c-ares/src/lib/ares_qcache.c +442 -0
  98. package/node/third_party/c-ares/src/lib/ares_query.c +151 -0
  99. package/node/third_party/c-ares/src/lib/ares_search.c +623 -0
  100. package/node/third_party/c-ares/src/lib/ares_send.c +300 -0
  101. package/node/third_party/c-ares/src/lib/ares_set_socket_functions.c +590 -0
  102. package/node/third_party/c-ares/src/lib/ares_setup.h +224 -0
  103. package/node/third_party/c-ares/src/lib/ares_socket.c +427 -0
  104. package/node/third_party/c-ares/src/lib/ares_socket.h +163 -0
  105. package/node/third_party/c-ares/src/lib/ares_sortaddrinfo.c +447 -0
  106. package/node/third_party/c-ares/src/lib/ares_strerror.c +91 -0
  107. package/node/third_party/c-ares/src/lib/ares_sysconfig.c +642 -0
  108. package/node/third_party/c-ares/src/lib/ares_sysconfig_files.c +851 -0
  109. package/node/third_party/c-ares/src/lib/ares_sysconfig_mac.c +373 -0
  110. package/node/third_party/c-ares/src/lib/ares_sysconfig_win.c +673 -0
  111. package/node/third_party/c-ares/src/lib/ares_timeout.c +162 -0
  112. package/node/third_party/c-ares/src/lib/ares_update_servers.c +1376 -0
  113. package/node/third_party/c-ares/src/lib/ares_version.c +36 -0
  114. package/node/third_party/c-ares/src/lib/config-dos.h +114 -0
  115. package/node/third_party/c-ares/src/lib/config-win32.h +396 -0
  116. package/node/third_party/c-ares/src/lib/dsa/ares_array.c +409 -0
  117. package/node/third_party/c-ares/src/lib/dsa/ares_htable.c +451 -0
  118. package/node/third_party/c-ares/src/lib/dsa/ares_htable.h +174 -0
  119. package/node/third_party/c-ares/src/lib/dsa/ares_htable_asvp.c +224 -0
  120. package/node/third_party/c-ares/src/lib/dsa/ares_htable_dict.c +230 -0
  121. package/node/third_party/c-ares/src/lib/dsa/ares_htable_strvp.c +210 -0
  122. package/node/third_party/c-ares/src/lib/dsa/ares_htable_szvp.c +188 -0
  123. package/node/third_party/c-ares/src/lib/dsa/ares_htable_vpstr.c +186 -0
  124. package/node/third_party/c-ares/src/lib/dsa/ares_htable_vpvp.c +194 -0
  125. package/node/third_party/c-ares/src/lib/dsa/ares_llist.c +385 -0
  126. package/node/third_party/c-ares/src/lib/dsa/ares_slist.c +479 -0
  127. package/node/third_party/c-ares/src/lib/dsa/ares_slist.h +207 -0
  128. package/node/third_party/c-ares/src/lib/event/ares_event.h +191 -0
  129. package/node/third_party/c-ares/src/lib/event/ares_event_configchg.c +746 -0
  130. package/node/third_party/c-ares/src/lib/event/ares_event_epoll.c +192 -0
  131. package/node/third_party/c-ares/src/lib/event/ares_event_kqueue.c +248 -0
  132. package/node/third_party/c-ares/src/lib/event/ares_event_poll.c +140 -0
  133. package/node/third_party/c-ares/src/lib/event/ares_event_select.c +159 -0
  134. package/node/third_party/c-ares/src/lib/event/ares_event_thread.c +575 -0
  135. package/node/third_party/c-ares/src/lib/event/ares_event_wake_pipe.c +172 -0
  136. package/node/third_party/c-ares/src/lib/event/ares_event_win32.c +981 -0
  137. package/node/third_party/c-ares/src/lib/event/ares_event_win32.h +161 -0
  138. package/node/third_party/c-ares/src/lib/include/ares_array.h +276 -0
  139. package/node/third_party/c-ares/src/lib/include/ares_buf.h +732 -0
  140. package/node/third_party/c-ares/src/lib/include/ares_htable_asvp.h +130 -0
  141. package/node/third_party/c-ares/src/lib/include/ares_htable_dict.h +123 -0
  142. package/node/third_party/c-ares/src/lib/include/ares_htable_strvp.h +130 -0
  143. package/node/third_party/c-ares/src/lib/include/ares_htable_szvp.h +118 -0
  144. package/node/third_party/c-ares/src/lib/include/ares_htable_vpstr.h +111 -0
  145. package/node/third_party/c-ares/src/lib/include/ares_htable_vpvp.h +128 -0
  146. package/node/third_party/c-ares/src/lib/include/ares_llist.h +239 -0
  147. package/node/third_party/c-ares/src/lib/include/ares_mem.h +41 -0
  148. package/node/third_party/c-ares/src/lib/include/ares_str.h +261 -0
  149. package/node/third_party/c-ares/src/lib/inet_net_pton.c +451 -0
  150. package/node/third_party/c-ares/src/lib/inet_ntop.c +219 -0
  151. package/node/third_party/c-ares/src/lib/legacy/ares_create_query.c +78 -0
  152. package/node/third_party/c-ares/src/lib/legacy/ares_expand_name.c +99 -0
  153. package/node/third_party/c-ares/src/lib/legacy/ares_expand_string.c +107 -0
  154. package/node/third_party/c-ares/src/lib/legacy/ares_fds.c +80 -0
  155. package/node/third_party/c-ares/src/lib/legacy/ares_getsock.c +85 -0
  156. package/node/third_party/c-ares/src/lib/legacy/ares_parse_a_reply.c +107 -0
  157. package/node/third_party/c-ares/src/lib/legacy/ares_parse_aaaa_reply.c +109 -0
  158. package/node/third_party/c-ares/src/lib/legacy/ares_parse_caa_reply.c +137 -0
  159. package/node/third_party/c-ares/src/lib/legacy/ares_parse_mx_reply.c +110 -0
  160. package/node/third_party/c-ares/src/lib/legacy/ares_parse_naptr_reply.c +132 -0
  161. package/node/third_party/c-ares/src/lib/legacy/ares_parse_ns_reply.c +154 -0
  162. package/node/third_party/c-ares/src/lib/legacy/ares_parse_ptr_reply.c +213 -0
  163. package/node/third_party/c-ares/src/lib/legacy/ares_parse_soa_reply.c +115 -0
  164. package/node/third_party/c-ares/src/lib/legacy/ares_parse_srv_reply.c +114 -0
  165. package/node/third_party/c-ares/src/lib/legacy/ares_parse_txt_reply.c +144 -0
  166. package/node/third_party/c-ares/src/lib/legacy/ares_parse_uri_reply.c +113 -0
  167. package/node/third_party/c-ares/src/lib/record/ares_dns_mapping.c +982 -0
  168. package/node/third_party/c-ares/src/lib/record/ares_dns_multistring.c +309 -0
  169. package/node/third_party/c-ares/src/lib/record/ares_dns_multistring.h +72 -0
  170. package/node/third_party/c-ares/src/lib/record/ares_dns_name.c +736 -0
  171. package/node/third_party/c-ares/src/lib/record/ares_dns_parse.c +1360 -0
  172. package/node/third_party/c-ares/src/lib/record/ares_dns_private.h +273 -0
  173. package/node/third_party/c-ares/src/lib/record/ares_dns_record.c +1701 -0
  174. package/node/third_party/c-ares/src/lib/record/ares_dns_write.c +1229 -0
  175. package/node/third_party/c-ares/src/lib/str/ares_buf.c +1510 -0
  176. package/node/third_party/c-ares/src/lib/str/ares_str.c +562 -0
  177. package/node/third_party/c-ares/src/lib/str/ares_strsplit.c +90 -0
  178. package/node/third_party/c-ares/src/lib/str/ares_strsplit.h +51 -0
  179. package/node/third_party/c-ares/src/lib/thirdparty/apple/dnsinfo.h +122 -0
  180. package/node/third_party/c-ares/src/lib/util/ares_iface_ips.c +640 -0
  181. package/node/third_party/c-ares/src/lib/util/ares_iface_ips.h +140 -0
  182. package/node/third_party/c-ares/src/lib/util/ares_math.c +167 -0
  183. package/node/third_party/c-ares/src/lib/util/ares_math.h +58 -0
  184. package/node/third_party/c-ares/src/lib/util/ares_rand.c +389 -0
  185. package/node/third_party/c-ares/src/lib/util/ares_rand.h +36 -0
  186. package/node/third_party/c-ares/src/lib/util/ares_threads.c +613 -0
  187. package/node/third_party/c-ares/src/lib/util/ares_threads.h +60 -0
  188. package/node/third_party/c-ares/src/lib/util/ares_time.h +49 -0
  189. package/node/third_party/c-ares/src/lib/util/ares_timeval.c +95 -0
  190. package/node/third_party/c-ares/src/lib/util/ares_uri.c +1627 -0
  191. package/node/third_party/c-ares/src/lib/util/ares_uri.h +252 -0
  192. package/node/third_party/c-ares/src/lib/windows_port.c +29 -0
  193. package/package.json +1 -1
  194. package/prebuilt/darwin-arm64/cares-a6286c65ca9374a3.a +0 -0
  195. package/prebuilt/darwin-x64/cares-a6286c65ca9374a3.a +0 -0
  196. package/prebuilt/linux-arm64/cares-4ba05ac8e948af8e.a +0 -0
  197. package/prebuilt/linux-arm64-musl/cares-4ba05ac8e948af8e.a +0 -0
  198. package/prebuilt/linux-x64/cares-4ba05ac8e948af8e.a +0 -0
  199. package/prebuilt/linux-x64-musl/cares-4ba05ac8e948af8e.a +0 -0
  200. package/prebuilt/win32-x64/boringssl-ce573858472b7fc9.a +0 -0
  201. package/prebuilt/win32-x64/brotli-20d86a61f30baeb3.a +0 -0
  202. package/prebuilt/win32-x64/cares-49c9ec95162b912d.a +0 -0
  203. package/prebuilt/win32-x64/uv-b11bae65d7fced82.a +0 -0
  204. package/prebuilt/win32-x64/zlib-4ce2317a4c3f5fb5.a +0 -0
  205. package/prebuilt/win32-x64/zstd-015315ac7c784c73.a +0 -0
  206. package/runtime/include/js_builtins.h +5 -0
  207. package/runtime/include/js_crypto.h +11 -0
  208. package/runtime/include/js_gc.h +13 -10
  209. package/runtime/include/js_jobs.h +2 -0
  210. package/runtime/include/js_object.h +58 -0
  211. package/runtime/include/jscontext.h +1 -0
  212. package/runtime/src/crypto_internal.h +1 -0
  213. package/runtime/src/crypto_subtle.c +66 -7
  214. package/runtime/src/crypto_tls.c +265 -19
  215. package/runtime/src/gc.c +73 -92
  216. package/runtime/src/inspect.c +18 -1
  217. package/runtime/src/jobs.c +37 -22
  218. package/runtime/src/object.c +49 -2
  219. package/runtime/src/os.c +16 -6
  220. package/runtime/src/os.h +2 -0
  221. 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
- enum { FORMAT_RAW, FORMAT_SPKI, FORMAT_PKCS8, FORMAT_JWK };
230
- static const char *const FORMATS[] = { "raw", "spki", "pkcs8", "jwk" };
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, 4, "KeyFormat", where);
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, aes_algorithm(ctx, p->name, length), usages, mask, extractable);
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) : aes_algorithm(ctx, p.name, 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);
@@ -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
- /* tlsContextSetKey(context, key handle) → 0 | 1 a key TLS can't use | 2 not the certificate's key */
267
- PRIMITIVE(js_tls_context_set_key) {
268
- UNUSED_ARGS;
269
- TlsContextObject *o = context_arg(ARG(0));
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 js_int32(1);
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
- if (!pkey) {
284
- ERR_clear_error();
285
- return js_int32(1);
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
- SSL_SESSION_free(s);
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]: feeds the
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[6] = { JS_NULL, JS_NULL, js_number((double)taken), js_int32(state), err, js_number(d->handshakes) };
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, 6);
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 || !SSL_SESSION_is_resumable(s)) return JS_UNDEFINED;
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
+ }