visaljs 0.0.0-stage → 0.0.2
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/LICENSE +21 -0
- package/README.md +45 -2
- package/cli.js +8084 -0
- package/node/include/js_node.h +46 -0
- package/node/prelude/async_hooks.js +88 -0
- package/node/prelude/buffer.js +31 -0
- package/node/prelude/crypto.js +114 -0
- package/node/prelude/events.js +227 -0
- package/node/prelude/fs.js +79 -0
- package/node/prelude/http.js +536 -0
- package/node/prelude/http2.js +30 -0
- package/node/prelude/internal/crypto/asym.js +333 -0
- package/node/prelude/internal/crypto/cipher.js +205 -0
- package/node/prelude/internal/crypto/hash.js +137 -0
- package/node/prelude/internal/crypto/kdf.js +182 -0
- package/node/prelude/internal/crypto/keys.js +603 -0
- package/node/prelude/internal/crypto/random.js +118 -0
- package/node/prelude/internal/crypto/util.js +76 -0
- package/node/prelude/internal/errors.js +88 -0
- package/node/prelude/internal/querystring.js +105 -0
- package/node/prelude/module.js +53 -0
- package/node/prelude/net.js +51 -0
- package/node/prelude/os.js +129 -0
- package/node/prelude/path.js +257 -0
- package/node/prelude/process.js +21 -0
- package/node/prelude/querystring.js +469 -0
- package/node/prelude/stream.js +1327 -0
- package/node/prelude/stream_promises.js +7 -0
- package/node/prelude/stream_web.js +6 -0
- package/node/prelude/string_decoder.js +236 -0
- package/node/prelude/tty.js +18 -0
- package/node/prelude/url.js +1156 -0
- package/node/prelude/util.js +64 -0
- package/node/prelude/zlib.js +81 -0
- package/node/src/host_fs.c +126 -0
- package/node/src/host_http.c +486 -0
- package/node/src/host_os.c +505 -0
- package/node/src/host_sys.c +78 -0
- package/node/third_party/libuv/LICENSE +19 -0
- package/node/third_party/libuv/include/uv/aix.h +32 -0
- package/node/third_party/libuv/include/uv/bsd.h +34 -0
- package/node/third_party/libuv/include/uv/darwin.h +61 -0
- package/node/third_party/libuv/include/uv/errno.h +483 -0
- package/node/third_party/libuv/include/uv/linux.h +34 -0
- package/node/third_party/libuv/include/uv/os390.h +33 -0
- package/node/third_party/libuv/include/uv/posix.h +31 -0
- package/node/third_party/libuv/include/uv/sunos.h +44 -0
- package/node/third_party/libuv/include/uv/threadpool.h +37 -0
- package/node/third_party/libuv/include/uv/tree.h +521 -0
- package/node/third_party/libuv/include/uv/unix.h +512 -0
- package/node/third_party/libuv/include/uv/version.h +43 -0
- package/node/third_party/libuv/include/uv/win.h +698 -0
- package/node/third_party/libuv/include/uv.h +1990 -0
- package/node/third_party/libuv/src/fs-poll.c +290 -0
- package/node/third_party/libuv/src/heap-inl.h +245 -0
- package/node/third_party/libuv/src/idna.c +560 -0
- package/node/third_party/libuv/src/idna.h +31 -0
- package/node/third_party/libuv/src/inet.c +298 -0
- package/node/third_party/libuv/src/queue.h +90 -0
- package/node/third_party/libuv/src/random.c +123 -0
- package/node/third_party/libuv/src/strscpy.c +38 -0
- package/node/third_party/libuv/src/strscpy.h +39 -0
- package/node/third_party/libuv/src/strtok.c +52 -0
- package/node/third_party/libuv/src/strtok.h +27 -0
- package/node/third_party/libuv/src/thread-common.c +175 -0
- package/node/third_party/libuv/src/threadpool.c +419 -0
- package/node/third_party/libuv/src/timer.c +200 -0
- package/node/third_party/libuv/src/unix/async.c +418 -0
- package/node/third_party/libuv/src/unix/bsd-ifaddrs.c +164 -0
- package/node/third_party/libuv/src/unix/core.c +2104 -0
- package/node/third_party/libuv/src/unix/darwin-proctitle.c +176 -0
- package/node/third_party/libuv/src/unix/darwin-stub.h +97 -0
- package/node/third_party/libuv/src/unix/darwin-syscalls.h +17 -0
- package/node/third_party/libuv/src/unix/darwin.c +237 -0
- package/node/third_party/libuv/src/unix/dl.c +80 -0
- package/node/third_party/libuv/src/unix/fs.c +2303 -0
- package/node/third_party/libuv/src/unix/fsevents.c +906 -0
- package/node/third_party/libuv/src/unix/getaddrinfo.c +252 -0
- package/node/third_party/libuv/src/unix/getnameinfo.c +121 -0
- package/node/third_party/libuv/src/unix/internal.h +530 -0
- package/node/third_party/libuv/src/unix/kqueue.c +667 -0
- package/node/third_party/libuv/src/unix/linux.c +2761 -0
- package/node/third_party/libuv/src/unix/loop-watcher.c +68 -0
- package/node/third_party/libuv/src/unix/loop.c +240 -0
- package/node/third_party/libuv/src/unix/pipe.c +555 -0
- package/node/third_party/libuv/src/unix/poll.c +159 -0
- package/node/third_party/libuv/src/unix/process.c +1123 -0
- package/node/third_party/libuv/src/unix/procfs-exepath.c +45 -0
- package/node/third_party/libuv/src/unix/proctitle.c +157 -0
- package/node/third_party/libuv/src/unix/random-devurandom.c +93 -0
- package/node/third_party/libuv/src/unix/random-getentropy.c +57 -0
- package/node/third_party/libuv/src/unix/random-getrandom.c +86 -0
- package/node/third_party/libuv/src/unix/random-sysctl-linux.c +99 -0
- package/node/third_party/libuv/src/unix/signal.c +581 -0
- package/node/third_party/libuv/src/unix/stream.c +1567 -0
- package/node/third_party/libuv/src/unix/tcp.c +673 -0
- package/node/third_party/libuv/src/unix/thread.c +975 -0
- package/node/third_party/libuv/src/unix/tty.c +510 -0
- package/node/third_party/libuv/src/unix/udp.c +1434 -0
- package/node/third_party/libuv/src/uv-common.c +1051 -0
- package/node/third_party/libuv/src/uv-common.h +474 -0
- package/node/third_party/libuv/src/uv-data-getter-setters.c +119 -0
- package/node/third_party/libuv/src/version.c +45 -0
- package/node/third_party/llhttp/LICENSE +22 -0
- package/node/third_party/llhttp/api.c +509 -0
- package/node/third_party/llhttp/http.c +170 -0
- package/node/third_party/llhttp/llhttp.c +10099 -0
- package/node/third_party/llhttp/llhttp.h +907 -0
- package/package.json +25 -4
- package/runtime/include/js_atoms.gen.h +68 -0
- package/runtime/include/js_atoms.h +54 -0
- package/runtime/include/js_bigint.h +93 -0
- package/runtime/include/js_buffer.h +79 -0
- package/runtime/include/js_builtins.h +168 -0
- package/runtime/include/js_console.h +58 -0
- package/runtime/include/js_convert.h +22 -0
- package/runtime/include/js_core.def +188 -0
- package/runtime/include/js_crypto.h +58 -0
- package/runtime/include/js_error.h +37 -0
- package/runtime/include/js_exception.h +65 -0
- package/runtime/include/js_function.h +167 -0
- package/runtime/include/js_gc.h +195 -0
- package/runtime/include/js_generator.h +96 -0
- package/runtime/include/js_host.h +19 -0
- package/runtime/include/js_jobs.h +84 -0
- package/runtime/include/js_module.h +16 -0
- package/runtime/include/js_object.h +384 -0
- package/runtime/include/js_ops.h +111 -0
- package/runtime/include/js_promise.h +45 -0
- package/runtime/include/js_regexp.h +25 -0
- package/runtime/include/js_runtime.h +30 -0
- package/runtime/include/js_symbol.h +62 -0
- package/runtime/include/js_web.h +110 -0
- package/runtime/include/jscell.h +48 -0
- package/runtime/include/jscontext.h +240 -0
- package/runtime/include/jsnum.h +42 -0
- package/runtime/include/jsstring.h +161 -0
- package/runtime/include/jsvalue.h +142 -0
- package/runtime/src/arguments.c +115 -0
- package/runtime/src/array.c +1145 -0
- package/runtime/src/arraybuffer.c +608 -0
- package/runtime/src/async_iter.c +479 -0
- package/runtime/src/atoms.c +157 -0
- package/runtime/src/base64.c +107 -0
- package/runtime/src/bigint.c +1189 -0
- package/runtime/src/blob.c +371 -0
- package/runtime/src/buffer.c +1357 -0
- package/runtime/src/builtin_table.c +100 -0
- package/runtime/src/builtins.c +987 -0
- package/runtime/src/builtins_util.h +53 -0
- package/runtime/src/collections.c +912 -0
- package/runtime/src/components.c +28 -0
- package/runtime/src/console.c +637 -0
- package/runtime/src/convert.c +82 -0
- package/runtime/src/core_all.c +21 -0
- package/runtime/src/crypto.c +116 -0
- package/runtime/src/crypto_asym.c +644 -0
- package/runtime/src/crypto_cipher.c +671 -0
- package/runtime/src/crypto_hash.c +260 -0
- package/runtime/src/crypto_host.c +414 -0
- package/runtime/src/crypto_internal.h +304 -0
- package/runtime/src/crypto_kdf.c +143 -0
- package/runtime/src/crypto_key.c +171 -0
- package/runtime/src/crypto_pkey.c +794 -0
- package/runtime/src/crypto_subtle.c +1675 -0
- package/runtime/src/date.c +940 -0
- package/runtime/src/domexception.c +169 -0
- package/runtime/src/elements.c +312 -0
- package/runtime/src/elements.h +45 -0
- package/runtime/src/encoding.c +485 -0
- package/runtime/src/error.c +297 -0
- package/runtime/src/events.c +793 -0
- package/runtime/src/exception.c +56 -0
- package/runtime/src/fetch.c +772 -0
- package/runtime/src/function.c +530 -0
- package/runtime/src/gc.c +803 -0
- package/runtime/src/generator.c +218 -0
- package/runtime/src/global.c +119 -0
- package/runtime/src/headers.c +557 -0
- package/runtime/src/inspect.c +1792 -0
- package/runtime/src/internal.h +80 -0
- package/runtime/src/iterate.c +94 -0
- package/runtime/src/iterator.c +409 -0
- package/runtime/src/jobs.c +337 -0
- package/runtime/src/jsnum.c +353 -0
- package/runtime/src/json.c +1028 -0
- package/runtime/src/math.c +243 -0
- package/runtime/src/module.c +336 -0
- package/runtime/src/number.c +176 -0
- package/runtime/src/object.c +1265 -0
- package/runtime/src/ops.c +322 -0
- package/runtime/src/os.c +196 -0
- package/runtime/src/os.h +29 -0
- package/runtime/src/process.c +432 -0
- package/runtime/src/promise.c +721 -0
- package/runtime/src/proxy.c +570 -0
- package/runtime/src/reflect.c +194 -0
- package/runtime/src/regexp.c +1141 -0
- package/runtime/src/regexp_anchor.h +34 -0
- package/runtime/src/regexp_message.h +32 -0
- package/runtime/src/shape.c +294 -0
- package/runtime/src/shape.h +46 -0
- package/runtime/src/streams.c +1046 -0
- package/runtime/src/streams.h +47 -0
- package/runtime/src/string.c +364 -0
- package/runtime/src/string_builtins.c +837 -0
- package/runtime/src/symbol.c +143 -0
- package/runtime/src/test_host.c +59 -0
- package/runtime/src/typedarray.c +1330 -0
- package/runtime/src/tznames.gen.h +712 -0
- package/runtime/src/uri.c +169 -0
- package/runtime/src/url.c +2116 -0
- package/runtime/src/weak.c +486 -0
- package/runtime/src/web.c +214 -0
- package/runtime/src/wrapper.c +59 -0
- package/runtime/src/writable.c +1486 -0
- package/runtime/third_party/ada-idna/LICENSE-MIT +18 -0
- package/runtime/third_party/ada-idna/README.md +27 -0
- package/runtime/third_party/ada-idna/convert.mjs +83 -0
- package/runtime/third_party/ada-idna/idna.c +416 -0
- package/runtime/third_party/ada-idna/idna.h +15 -0
- package/runtime/third_party/ada-idna/idna_tables.h +2657 -0
- package/runtime/third_party/bearssl/LICENSE.txt +21 -0
- package/runtime/third_party/bearssl/README.txt +136 -0
- package/runtime/third_party/bearssl/VERSION +1 -0
- package/runtime/third_party/bearssl/inc/bearssl.h +183 -0
- package/runtime/third_party/bearssl/inc/bearssl_aead.h +1059 -0
- package/runtime/third_party/bearssl/inc/bearssl_block.h +2618 -0
- package/runtime/third_party/bearssl/inc/bearssl_ec.h +967 -0
- package/runtime/third_party/bearssl/inc/bearssl_hash.h +1346 -0
- package/runtime/third_party/bearssl/inc/bearssl_hmac.h +241 -0
- package/runtime/third_party/bearssl/inc/bearssl_kdf.h +284 -0
- package/runtime/third_party/bearssl/inc/bearssl_pem.h +294 -0
- package/runtime/third_party/bearssl/inc/bearssl_prf.h +150 -0
- package/runtime/third_party/bearssl/inc/bearssl_rand.h +397 -0
- package/runtime/third_party/bearssl/inc/bearssl_rsa.h +1655 -0
- package/runtime/third_party/bearssl/inc/bearssl_ssl.h +4296 -0
- package/runtime/third_party/bearssl/inc/bearssl_x509.h +1474 -0
- package/runtime/third_party/bearssl/src/aead/ccm.c +346 -0
- package/runtime/third_party/bearssl/src/aead/eax.c +525 -0
- package/runtime/third_party/bearssl/src/aead/gcm.c +318 -0
- package/runtime/third_party/bearssl/src/codec/ccopy.c +44 -0
- package/runtime/third_party/bearssl/src/codec/dec16be.c +38 -0
- package/runtime/third_party/bearssl/src/codec/dec16le.c +38 -0
- package/runtime/third_party/bearssl/src/codec/dec32be.c +38 -0
- package/runtime/third_party/bearssl/src/codec/dec32le.c +38 -0
- package/runtime/third_party/bearssl/src/codec/dec64be.c +38 -0
- package/runtime/third_party/bearssl/src/codec/dec64le.c +38 -0
- package/runtime/third_party/bearssl/src/codec/enc16be.c +38 -0
- package/runtime/third_party/bearssl/src/codec/enc16le.c +38 -0
- package/runtime/third_party/bearssl/src/codec/enc32be.c +38 -0
- package/runtime/third_party/bearssl/src/codec/enc32le.c +38 -0
- package/runtime/third_party/bearssl/src/codec/enc64be.c +38 -0
- package/runtime/third_party/bearssl/src/codec/enc64le.c +38 -0
- package/runtime/third_party/bearssl/src/codec/pemdec.c +526 -0
- package/runtime/third_party/bearssl/src/codec/pemdec.t0 +314 -0
- package/runtime/third_party/bearssl/src/codec/pemenc.c +173 -0
- package/runtime/third_party/bearssl/src/config.h +247 -0
- package/runtime/third_party/bearssl/src/ec/ec_all_m15.c +121 -0
- package/runtime/third_party/bearssl/src/ec/ec_all_m31.c +171 -0
- package/runtime/third_party/bearssl/src/ec/ec_c25519_i15.c +398 -0
- package/runtime/third_party/bearssl/src/ec/ec_c25519_i31.c +390 -0
- package/runtime/third_party/bearssl/src/ec/ec_c25519_m15.c +1478 -0
- package/runtime/third_party/bearssl/src/ec/ec_c25519_m31.c +800 -0
- package/runtime/third_party/bearssl/src/ec/ec_c25519_m62.c +605 -0
- package/runtime/third_party/bearssl/src/ec/ec_c25519_m64.c +831 -0
- package/runtime/third_party/bearssl/src/ec/ec_curve25519.c +46 -0
- package/runtime/third_party/bearssl/src/ec/ec_default.c +36 -0
- package/runtime/third_party/bearssl/src/ec/ec_keygen.c +86 -0
- package/runtime/third_party/bearssl/src/ec/ec_p256_m15.c +2124 -0
- package/runtime/third_party/bearssl/src/ec/ec_p256_m31.c +1469 -0
- package/runtime/third_party/bearssl/src/ec/ec_p256_m62.c +1765 -0
- package/runtime/third_party/bearssl/src/ec/ec_p256_m64.c +1781 -0
- package/runtime/third_party/bearssl/src/ec/ec_prime_i15.c +824 -0
- package/runtime/third_party/bearssl/src/ec/ec_prime_i31.c +826 -0
- package/runtime/third_party/bearssl/src/ec/ec_pubkey.c +85 -0
- package/runtime/third_party/bearssl/src/ec/ec_secp256r1.c +51 -0
- package/runtime/third_party/bearssl/src/ec/ec_secp384r1.c +57 -0
- package/runtime/third_party/bearssl/src/ec/ec_secp521r1.c +64 -0
- package/runtime/third_party/bearssl/src/ec/ecdsa_atr.c +134 -0
- package/runtime/third_party/bearssl/src/ec/ecdsa_default_sign_asn1.c +36 -0
- package/runtime/third_party/bearssl/src/ec/ecdsa_default_sign_raw.c +36 -0
- package/runtime/third_party/bearssl/src/ec/ecdsa_default_vrfy_asn1.c +36 -0
- package/runtime/third_party/bearssl/src/ec/ecdsa_default_vrfy_raw.c +36 -0
- package/runtime/third_party/bearssl/src/ec/ecdsa_i15_bits.c +47 -0
- package/runtime/third_party/bearssl/src/ec/ecdsa_i15_sign_asn1.c +45 -0
- package/runtime/third_party/bearssl/src/ec/ecdsa_i15_sign_raw.c +174 -0
- package/runtime/third_party/bearssl/src/ec/ecdsa_i15_vrfy_asn1.c +48 -0
- package/runtime/third_party/bearssl/src/ec/ecdsa_i15_vrfy_raw.c +166 -0
- package/runtime/third_party/bearssl/src/ec/ecdsa_i31_bits.c +47 -0
- package/runtime/third_party/bearssl/src/ec/ecdsa_i31_sign_asn1.c +45 -0
- package/runtime/third_party/bearssl/src/ec/ecdsa_i31_sign_raw.c +173 -0
- package/runtime/third_party/bearssl/src/ec/ecdsa_i31_vrfy_asn1.c +48 -0
- package/runtime/third_party/bearssl/src/ec/ecdsa_i31_vrfy_raw.c +165 -0
- package/runtime/third_party/bearssl/src/ec/ecdsa_rta.c +121 -0
- package/runtime/third_party/bearssl/src/hash/dig_oid.c +84 -0
- package/runtime/third_party/bearssl/src/hash/dig_size.c +50 -0
- package/runtime/third_party/bearssl/src/hash/ghash_ctmul.c +345 -0
- package/runtime/third_party/bearssl/src/hash/ghash_ctmul32.c +251 -0
- package/runtime/third_party/bearssl/src/hash/ghash_ctmul64.c +154 -0
- package/runtime/third_party/bearssl/src/hash/ghash_pclmul.c +389 -0
- package/runtime/third_party/bearssl/src/hash/ghash_pwr8.c +411 -0
- package/runtime/third_party/bearssl/src/hash/md5.c +208 -0
- package/runtime/third_party/bearssl/src/hash/md5sha1.c +141 -0
- package/runtime/third_party/bearssl/src/hash/mgf1.c +56 -0
- package/runtime/third_party/bearssl/src/hash/multihash.c +166 -0
- package/runtime/third_party/bearssl/src/hash/sha1.c +191 -0
- package/runtime/third_party/bearssl/src/hash/sha2big.c +285 -0
- package/runtime/third_party/bearssl/src/hash/sha2small.c +341 -0
- package/runtime/third_party/bearssl/src/inner.h +2577 -0
- package/runtime/third_party/bearssl/src/int/i15_add.c +46 -0
- package/runtime/third_party/bearssl/src/int/i15_bitlen.c +44 -0
- package/runtime/third_party/bearssl/src/int/i15_decmod.c +124 -0
- package/runtime/third_party/bearssl/src/int/i15_decode.c +56 -0
- package/runtime/third_party/bearssl/src/int/i15_decred.c +100 -0
- package/runtime/third_party/bearssl/src/int/i15_encode.c +56 -0
- package/runtime/third_party/bearssl/src/int/i15_fmont.c +59 -0
- package/runtime/third_party/bearssl/src/int/i15_iszero.c +39 -0
- package/runtime/third_party/bearssl/src/int/i15_moddiv.c +465 -0
- package/runtime/third_party/bearssl/src/int/i15_modpow.c +50 -0
- package/runtime/third_party/bearssl/src/int/i15_modpow2.c +160 -0
- package/runtime/third_party/bearssl/src/int/i15_montmul.c +184 -0
- package/runtime/third_party/bearssl/src/int/i15_mulacc.c +61 -0
- package/runtime/third_party/bearssl/src/int/i15_muladd.c +173 -0
- package/runtime/third_party/bearssl/src/int/i15_ninv15.c +38 -0
- package/runtime/third_party/bearssl/src/int/i15_reduce.c +66 -0
- package/runtime/third_party/bearssl/src/int/i15_rshift.c +47 -0
- package/runtime/third_party/bearssl/src/int/i15_sub.c +46 -0
- package/runtime/third_party/bearssl/src/int/i15_tmont.c +36 -0
- package/runtime/third_party/bearssl/src/int/i31_add.c +46 -0
- package/runtime/third_party/bearssl/src/int/i31_bitlen.c +44 -0
- package/runtime/third_party/bearssl/src/int/i31_decmod.c +124 -0
- package/runtime/third_party/bearssl/src/int/i31_decode.c +57 -0
- package/runtime/third_party/bearssl/src/int/i31_decred.c +103 -0
- package/runtime/third_party/bearssl/src/int/i31_encode.c +79 -0
- package/runtime/third_party/bearssl/src/int/i31_fmont.c +60 -0
- package/runtime/third_party/bearssl/src/int/i31_iszero.c +39 -0
- package/runtime/third_party/bearssl/src/int/i31_moddiv.c +488 -0
- package/runtime/third_party/bearssl/src/int/i31_modpow.c +65 -0
- package/runtime/third_party/bearssl/src/int/i31_modpow2.c +160 -0
- package/runtime/third_party/bearssl/src/int/i31_montmul.c +127 -0
- package/runtime/third_party/bearssl/src/int/i31_mulacc.c +74 -0
- package/runtime/third_party/bearssl/src/int/i31_muladd.c +157 -0
- package/runtime/third_party/bearssl/src/int/i31_ninv31.c +39 -0
- package/runtime/third_party/bearssl/src/int/i31_reduce.c +66 -0
- package/runtime/third_party/bearssl/src/int/i31_rshift.c +47 -0
- package/runtime/third_party/bearssl/src/int/i31_sub.c +46 -0
- package/runtime/third_party/bearssl/src/int/i31_tmont.c +36 -0
- package/runtime/third_party/bearssl/src/int/i32_add.c +51 -0
- package/runtime/third_party/bearssl/src/int/i32_bitlen.c +44 -0
- package/runtime/third_party/bearssl/src/int/i32_decmod.c +77 -0
- package/runtime/third_party/bearssl/src/int/i32_decode.c +63 -0
- package/runtime/third_party/bearssl/src/int/i32_decred.c +107 -0
- package/runtime/third_party/bearssl/src/int/i32_div32.c +56 -0
- package/runtime/third_party/bearssl/src/int/i32_encode.c +72 -0
- package/runtime/third_party/bearssl/src/int/i32_fmont.c +60 -0
- package/runtime/third_party/bearssl/src/int/i32_iszero.c +39 -0
- package/runtime/third_party/bearssl/src/int/i32_modpow.c +65 -0
- package/runtime/third_party/bearssl/src/int/i32_montmul.c +69 -0
- package/runtime/third_party/bearssl/src/int/i32_mulacc.c +56 -0
- package/runtime/third_party/bearssl/src/int/i32_muladd.c +138 -0
- package/runtime/third_party/bearssl/src/int/i32_ninv32.c +39 -0
- package/runtime/third_party/bearssl/src/int/i32_reduce.c +66 -0
- package/runtime/third_party/bearssl/src/int/i32_sub.c +51 -0
- package/runtime/third_party/bearssl/src/int/i32_tmont.c +36 -0
- package/runtime/third_party/bearssl/src/int/i62_modpow2.c +493 -0
- package/runtime/third_party/bearssl/src/kdf/hkdf.c +107 -0
- package/runtime/third_party/bearssl/src/kdf/shake.c +590 -0
- package/runtime/third_party/bearssl/src/mac/hmac.c +122 -0
- package/runtime/third_party/bearssl/src/mac/hmac_ct.c +193 -0
- package/runtime/third_party/bearssl/src/rand/aesctr_drbg.c +206 -0
- package/runtime/third_party/bearssl/src/rand/hmac_drbg.c +157 -0
- package/runtime/third_party/bearssl/src/rand/sysrng.c +252 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_default_keygen.c +38 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_default_modulus.c +36 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_default_oaep_decrypt.c +38 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_default_oaep_encrypt.c +38 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_default_pkcs1_sign.c +38 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_default_pkcs1_vrfy.c +38 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_default_priv.c +38 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_default_privexp.c +36 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_default_pss_sign.c +38 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_default_pss_vrfy.c +38 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_default_pub.c +38 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_default_pubexp.c +36 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i15_keygen.c +583 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i15_modulus.c +99 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i15_oaep_decrypt.c +41 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i15_oaep_encrypt.c +44 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i15_pkcs1_sign.c +37 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i15_pkcs1_vrfy.c +43 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i15_priv.c +209 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i15_privexp.c +320 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i15_pss_sign.c +40 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i15_pss_vrfy.c +44 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i15_pub.c +113 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i15_pubexp.c +152 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i31_keygen.c +37 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i31_keygen_inner.c +608 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i31_modulus.c +99 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i31_oaep_decrypt.c +41 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i31_oaep_encrypt.c +44 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i31_pkcs1_sign.c +37 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i31_pkcs1_vrfy.c +43 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i31_priv.c +203 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i31_privexp.c +318 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i31_pss_sign.c +40 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i31_pss_vrfy.c +44 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i31_pub.c +106 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i31_pubexp.c +152 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i32_oaep_decrypt.c +41 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i32_oaep_encrypt.c +44 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i32_pkcs1_sign.c +37 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i32_pkcs1_vrfy.c +43 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i32_priv.c +160 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i32_pss_sign.c +40 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i32_pss_vrfy.c +44 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i32_pub.c +77 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i62_keygen.c +57 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i62_oaep_decrypt.c +61 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i62_oaep_encrypt.c +64 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i62_pkcs1_sign.c +57 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i62_pkcs1_vrfy.c +63 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i62_priv.c +223 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i62_pss_sign.c +60 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i62_pss_vrfy.c +64 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_i62_pub.c +125 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_oaep_pad.c +112 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_oaep_unpad.c +145 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_pkcs1_sig_pad.c +100 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_pkcs1_sig_unpad.c +121 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_pss_sig_pad.c +106 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_pss_sig_unpad.c +121 -0
- package/runtime/third_party/bearssl/src/rsa/rsa_ssl_decrypt.c +52 -0
- package/runtime/third_party/bearssl/src/settings.c +306 -0
- package/runtime/third_party/bearssl/src/symcipher/aes_big_cbcdec.c +69 -0
- package/runtime/third_party/bearssl/src/symcipher/aes_big_cbcenc.c +67 -0
- package/runtime/third_party/bearssl/src/symcipher/aes_big_ctr.c +84 -0
- package/runtime/third_party/bearssl/src/symcipher/aes_big_ctrcbc.c +142 -0
- package/runtime/third_party/bearssl/src/symcipher/aes_big_dec.c +254 -0
- package/runtime/third_party/bearssl/src/symcipher/aes_big_enc.c +157 -0
- package/runtime/third_party/bearssl/src/symcipher/aes_common.c +112 -0
- package/runtime/third_party/bearssl/src/symcipher/aes_ct.c +328 -0
- package/runtime/third_party/bearssl/src/symcipher/aes_ct64.c +398 -0
- package/runtime/third_party/bearssl/src/symcipher/aes_ct64_cbcdec.c +104 -0
- package/runtime/third_party/bearssl/src/symcipher/aes_ct64_cbcenc.c +81 -0
- package/runtime/third_party/bearssl/src/symcipher/aes_ct64_ctr.c +114 -0
- package/runtime/third_party/bearssl/src/symcipher/aes_ct64_ctrcbc.c +433 -0
- package/runtime/third_party/bearssl/src/symcipher/aes_ct64_dec.c +159 -0
- package/runtime/third_party/bearssl/src/symcipher/aes_ct64_enc.c +115 -0
- package/runtime/third_party/bearssl/src/symcipher/aes_ct_cbcdec.c +111 -0
- package/runtime/third_party/bearssl/src/symcipher/aes_ct_cbcenc.c +91 -0
- package/runtime/third_party/bearssl/src/symcipher/aes_ct_ctr.c +116 -0
- package/runtime/third_party/bearssl/src/symcipher/aes_ct_ctrcbc.c +422 -0
- package/runtime/third_party/bearssl/src/symcipher/aes_ct_dec.c +170 -0
- package/runtime/third_party/bearssl/src/symcipher/aes_ct_enc.c +112 -0
- package/runtime/third_party/bearssl/src/symcipher/aes_pwr8.c +445 -0
- package/runtime/third_party/bearssl/src/symcipher/aes_pwr8_cbcdec.c +670 -0
- package/runtime/third_party/bearssl/src/symcipher/aes_pwr8_cbcenc.c +417 -0
- package/runtime/third_party/bearssl/src/symcipher/aes_pwr8_ctr.c +717 -0
- package/runtime/third_party/bearssl/src/symcipher/aes_pwr8_ctrcbc.c +946 -0
- package/runtime/third_party/bearssl/src/symcipher/aes_small_cbcdec.c +69 -0
- package/runtime/third_party/bearssl/src/symcipher/aes_small_cbcenc.c +67 -0
- package/runtime/third_party/bearssl/src/symcipher/aes_small_ctr.c +84 -0
- package/runtime/third_party/bearssl/src/symcipher/aes_small_ctrcbc.c +142 -0
- package/runtime/third_party/bearssl/src/symcipher/aes_small_dec.c +176 -0
- package/runtime/third_party/bearssl/src/symcipher/aes_small_enc.c +129 -0
- package/runtime/third_party/bearssl/src/symcipher/aes_x86ni.c +240 -0
- package/runtime/third_party/bearssl/src/symcipher/aes_x86ni_cbcdec.c +223 -0
- package/runtime/third_party/bearssl/src/symcipher/aes_x86ni_cbcenc.c +122 -0
- package/runtime/third_party/bearssl/src/symcipher/aes_x86ni_ctr.c +211 -0
- package/runtime/third_party/bearssl/src/symcipher/aes_x86ni_ctrcbc.c +596 -0
- package/runtime/third_party/bearssl/src/symcipher/chacha20_ct.c +106 -0
- package/runtime/third_party/bearssl/src/symcipher/chacha20_sse2.c +237 -0
- package/runtime/third_party/bearssl/src/symcipher/des_ct.c +411 -0
- package/runtime/third_party/bearssl/src/symcipher/des_ct_cbcdec.c +87 -0
- package/runtime/third_party/bearssl/src/symcipher/des_ct_cbcenc.c +69 -0
- package/runtime/third_party/bearssl/src/symcipher/des_support.c +166 -0
- package/runtime/third_party/bearssl/src/symcipher/des_tab.c +310 -0
- package/runtime/third_party/bearssl/src/symcipher/des_tab_cbcdec.c +85 -0
- package/runtime/third_party/bearssl/src/symcipher/des_tab_cbcenc.c +67 -0
- package/runtime/third_party/bearssl/src/symcipher/poly1305_ctmul.c +260 -0
- package/runtime/third_party/bearssl/src/symcipher/poly1305_ctmul32.c +297 -0
- package/runtime/third_party/bearssl/src/symcipher/poly1305_ctmulq.c +475 -0
- package/runtime/third_party/bearssl/src/symcipher/poly1305_i15.c +221 -0
- package/runtime/third_party/bearssl/src/x509/asn1.t0 +757 -0
- package/runtime/third_party/bearssl/src/x509/asn1enc.c +93 -0
- package/runtime/third_party/bearssl/src/x509/encode_ec_pk8der.c +110 -0
- package/runtime/third_party/bearssl/src/x509/encode_ec_rawder.c +161 -0
- package/runtime/third_party/bearssl/src/x509/encode_rsa_pk8der.c +97 -0
- package/runtime/third_party/bearssl/src/x509/encode_rsa_rawder.c +96 -0
- package/runtime/third_party/bearssl/src/x509/skey_decoder.c +653 -0
- package/runtime/third_party/bearssl/src/x509/skey_decoder.t0 +376 -0
- package/runtime/third_party/bearssl/src/x509/x509_decoder.c +776 -0
- package/runtime/third_party/bearssl/src/x509/x509_decoder.t0 +324 -0
- package/runtime/third_party/bearssl/src/x509/x509_knownkey.c +105 -0
- package/runtime/third_party/bearssl/src/x509/x509_minimal.c +1722 -0
- package/runtime/third_party/bearssl/src/x509/x509_minimal.t0 +1526 -0
- package/runtime/third_party/bearssl/src/x509/x509_minimal_full.c +59 -0
- package/runtime/third_party/quickjs-dtoa/LICENSE +22 -0
- package/runtime/third_party/quickjs-dtoa/README.md +23 -0
- package/runtime/third_party/quickjs-dtoa/dtoa.c +1640 -0
- package/runtime/third_party/quickjs-dtoa/dtoa.h +83 -0
- package/runtime/third_party/quickjs-dtoa/dtoa_compat.h +89 -0
- package/runtime/third_party/quickjs-regexp/LICENSE +22 -0
- package/runtime/third_party/quickjs-regexp/README.md +22 -0
- package/runtime/third_party/quickjs-regexp/cutils.c +641 -0
- package/runtime/third_party/quickjs-regexp/cutils.h +457 -0
- package/runtime/third_party/quickjs-regexp/libregexp-opcode.h +73 -0
- package/runtime/third_party/quickjs-regexp/libregexp.c +3448 -0
- package/runtime/third_party/quickjs-regexp/libregexp.h +65 -0
- package/runtime/third_party/quickjs-regexp/libunicode-table.h +5206 -0
- package/runtime/third_party/quickjs-regexp/libunicode.c +2124 -0
- package/runtime/third_party/quickjs-regexp/libunicode.h +196 -0
- package/runtime/third_party/v8-ieee754/LICENSE +61 -0
- package/runtime/third_party/v8-ieee754/README.md +22 -0
- package/runtime/third_party/v8-ieee754/convert.py +84 -0
- package/runtime/third_party/v8-ieee754/ieee754.c +3030 -0
- package/runtime/third_party/v8-ieee754/ieee754.h +27 -0
- package/runtime/tools/regexp_compile.c +90 -0
|
@@ -0,0 +1,1675 @@
|
|
|
1
|
+
/* SubtleCrypto (W3C Web Cryptography API §14), part of the crypto component (ADR 0018), as Node
|
|
2
|
+
* has it: its WebIDL conversions and their messages, algorithm normalization (a registry of the
|
|
3
|
+
* algorithms each operation supports, and their parameter dictionaries), and the operations.
|
|
4
|
+
* A method's errors reject its promise; its result is computed at the call, so the promise is
|
|
5
|
+
* already settled when it returns (Node settles from its thread pool). */
|
|
6
|
+
#include <math.h>
|
|
7
|
+
#include <stdio.h>
|
|
8
|
+
#include <stdlib.h>
|
|
9
|
+
#include <string.h>
|
|
10
|
+
|
|
11
|
+
#include "builtins_util.h"
|
|
12
|
+
#include "crypto_internal.h"
|
|
13
|
+
#include "internal.h"
|
|
14
|
+
#include "js_atoms.h"
|
|
15
|
+
#include "js_buffer.h"
|
|
16
|
+
#include "js_convert.h"
|
|
17
|
+
#include "js_exception.h"
|
|
18
|
+
#include "js_ops.h"
|
|
19
|
+
#include "js_promise.h"
|
|
20
|
+
#include "js_web.h"
|
|
21
|
+
#include "jscontext.h"
|
|
22
|
+
#include "jsstring.h"
|
|
23
|
+
|
|
24
|
+
static const JSClass subtle_class = { "SubtleCrypto", sizeof(JSObject), NULL, NULL, NULL, NULL, NULL, NULL, NULL };
|
|
25
|
+
|
|
26
|
+
static bool is_subtle(JSValue v) { return js_is_object(v) && js_as_object(v)->shape->cls == &subtle_class; }
|
|
27
|
+
|
|
28
|
+
/* A failure's -1, after the call that threw (the throwers' results must be used). */
|
|
29
|
+
static int fail(JSValue thrown) {
|
|
30
|
+
(void)thrown;
|
|
31
|
+
return -1;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
static JSValue rejected(JSContext *ctx, JSValue thrown) {
|
|
35
|
+
(void)thrown;
|
|
36
|
+
JSValue p = js_new_promise(ctx);
|
|
37
|
+
js_promise_reject_internal(ctx, p, js_take_exception(ctx));
|
|
38
|
+
return p;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
static JSValue settled(JSContext *ctx, JSValue v) {
|
|
42
|
+
if (js_is_exception(v)) return rejected(ctx, v);
|
|
43
|
+
JSValue p = js_new_promise(ctx);
|
|
44
|
+
js_promise_resolve_internal(ctx, p, v);
|
|
45
|
+
return p;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
static JSValue dom_error(JSContext *ctx, const char *name, const char *message) {
|
|
49
|
+
return js_throw_dom_exception(ctx, name, message);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
static JSValue op_failed(JSContext *ctx) {
|
|
53
|
+
return dom_error(ctx, "OperationError", "The operation failed for an operation-specific reason");
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
static JSValue array_buffer_of(JSContext *ctx, const uint8_t *p, size_t n) {
|
|
57
|
+
JSValue b = js_new_array_buffer(ctx, n);
|
|
58
|
+
if (js_is_exception(b)) return b;
|
|
59
|
+
if (n) memcpy(js_as_array_buffer(b)->data, p, n);
|
|
60
|
+
return b;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
static JSValue str(JSContext *ctx, const char *s) { return js_new_string_cstr(ctx, s); }
|
|
64
|
+
|
|
65
|
+
static void put(JSContext *ctx, JSValue o, const char *key, JSValue v) {
|
|
66
|
+
js_define_data(ctx, js_as_object(o), js_atom_from_cstr(ctx, key), v, JS_PROP_DEFAULT);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/* A string's characters, when they are all ASCII and fit (else ""). */
|
|
70
|
+
static void ascii_of(JSContext *ctx, JSValue s, char *buf, size_t cap) {
|
|
71
|
+
JSStrView v = js_string_view(ctx, s);
|
|
72
|
+
buf[0] = 0;
|
|
73
|
+
if (v.length >= cap) return;
|
|
74
|
+
for (uint32_t i = 0; i < v.length; i++) {
|
|
75
|
+
uint32_t c = js_view_at(v, i);
|
|
76
|
+
if (c >= 0x80) {
|
|
77
|
+
buf[0] = 0;
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
buf[i] = (char)c;
|
|
81
|
+
}
|
|
82
|
+
buf[v.length] = 0;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
static bool same_ci(const char *a, const char *b) {
|
|
86
|
+
for (; *a && *b; a++, b++) {
|
|
87
|
+
char x = *a >= 'A' && *a <= 'Z' ? (char)(*a + 32) : *a, y = *b >= 'A' && *b <= 'Z' ? (char)(*b + 32) : *b;
|
|
88
|
+
if (x != y) return false;
|
|
89
|
+
}
|
|
90
|
+
return *a == *b;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/* ---- Bytes ------------------------------------------------------------------------------------- */
|
|
94
|
+
|
|
95
|
+
/* A copy of a buffer source's bytes (the operations work on copies, as the standard says). */
|
|
96
|
+
typedef struct Bytes {
|
|
97
|
+
uint8_t *p;
|
|
98
|
+
size_t n;
|
|
99
|
+
} Bytes;
|
|
100
|
+
|
|
101
|
+
static void bytes_copy(Bytes *b, JSValue v) {
|
|
102
|
+
uint8_t *p;
|
|
103
|
+
size_t n;
|
|
104
|
+
js_buffer_source_bytes(v, &p, &n);
|
|
105
|
+
b->p = malloc(n ? n : 1);
|
|
106
|
+
if (!b->p) js_fatal("out of memory in crypto");
|
|
107
|
+
if (n) memcpy(b->p, p, n);
|
|
108
|
+
b->n = n;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
static void bytes_free(Bytes *b) {
|
|
112
|
+
free(b->p);
|
|
113
|
+
b->p = NULL;
|
|
114
|
+
b->n = 0;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/* ---- base64url (JWK) --------------------------------------------------------------------------- */
|
|
118
|
+
|
|
119
|
+
static const char B64URL[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
|
120
|
+
|
|
121
|
+
static JSValue base64url_encode(JSContext *ctx, const uint8_t *p, size_t n) {
|
|
122
|
+
size_t cap = (n + 2) / 3 * 4;
|
|
123
|
+
uint8_t *out = malloc(cap ? cap : 1);
|
|
124
|
+
if (!out) js_fatal("out of memory in crypto");
|
|
125
|
+
size_t k = 0;
|
|
126
|
+
for (size_t i = 0; i < n; i += 3) {
|
|
127
|
+
size_t rest = n - i;
|
|
128
|
+
uint32_t b = (uint32_t)p[i] << 16 | (rest > 1 ? (uint32_t)p[i + 1] << 8 : 0) | (rest > 2 ? p[i + 2] : 0);
|
|
129
|
+
out[k++] = (uint8_t)B64URL[b >> 18];
|
|
130
|
+
out[k++] = (uint8_t)B64URL[(b >> 12) & 63];
|
|
131
|
+
if (rest > 1) out[k++] = (uint8_t)B64URL[(b >> 6) & 63];
|
|
132
|
+
if (rest > 2) out[k++] = (uint8_t)B64URL[b & 63];
|
|
133
|
+
}
|
|
134
|
+
JSValue s = js_new_string_latin1(ctx, out, (uint32_t)k);
|
|
135
|
+
free(out);
|
|
136
|
+
return s;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/* Decoded as Node decodes base64url: either alphabet, other characters skipped, '=' ends it. */
|
|
140
|
+
static void base64url_decode(JSContext *ctx, JSValue s, Bytes *out) {
|
|
141
|
+
JSStrView v = js_string_view(ctx, s);
|
|
142
|
+
out->p = malloc(v.length ? v.length : 1);
|
|
143
|
+
if (!out->p) js_fatal("out of memory in crypto");
|
|
144
|
+
size_t k = 0, bits = 0;
|
|
145
|
+
uint32_t acc = 0;
|
|
146
|
+
for (uint32_t i = 0; i < v.length; i++) {
|
|
147
|
+
uint32_t c = js_view_at(v, i);
|
|
148
|
+
int x;
|
|
149
|
+
if (c >= 'A' && c <= 'Z') x = (int)(c - 'A');
|
|
150
|
+
else if (c >= 'a' && c <= 'z') x = (int)(c - 'a' + 26);
|
|
151
|
+
else if (c >= '0' && c <= '9') x = (int)(c - '0' + 52);
|
|
152
|
+
else if (c == '-' || c == '+') x = 62;
|
|
153
|
+
else if (c == '_' || c == '/') x = 63;
|
|
154
|
+
else if (c == '=') break;
|
|
155
|
+
else continue;
|
|
156
|
+
acc = acc << 6 | (uint32_t)x;
|
|
157
|
+
bits += 6;
|
|
158
|
+
if (bits >= 8) {
|
|
159
|
+
bits -= 8;
|
|
160
|
+
out->p[k++] = (uint8_t)(acc >> bits);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
out->n = k;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/* ---- WebIDL conversions ------------------------------------------------------------------------ */
|
|
167
|
+
|
|
168
|
+
static const char *const ORDINALS[] = { "1st", "2nd", "3rd", "4th", "5th", "6th", "7th" };
|
|
169
|
+
|
|
170
|
+
typedef struct Call {
|
|
171
|
+
JSContext *ctx;
|
|
172
|
+
const char *op; /* "importKey" */
|
|
173
|
+
} Call;
|
|
174
|
+
|
|
175
|
+
static JSValue throw_missing_args(Call *c, uint32_t need, uint32_t argc) {
|
|
176
|
+
return js_throw_node_error(c->ctx, JS_TYPE_ERROR, "ERR_MISSING_ARGS",
|
|
177
|
+
"Failed to execute '%s' on 'SubtleCrypto': %u argument%s required, but only %u present.", c->op,
|
|
178
|
+
need, need == 1 ? "" : "s", argc);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
static int arg_buffer_source(Call *c, JSValue v, int i) {
|
|
182
|
+
uint8_t *p;
|
|
183
|
+
size_t n;
|
|
184
|
+
if (js_buffer_source_bytes(v, &p, &n)) return 0;
|
|
185
|
+
return fail(js_throw_node_error(c->ctx, JS_TYPE_ERROR, "ERR_INVALID_ARG_TYPE",
|
|
186
|
+
"Failed to execute '%s' on 'SubtleCrypto': %s argument is not instance of ArrayBuffer, "
|
|
187
|
+
"Buffer, TypedArray, or DataView.", c->op, ORDINALS[i]));
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
static int arg_algorithm(Call *c, JSValue v, int i) {
|
|
191
|
+
if (!js_is_symbol(v)) return 0;
|
|
192
|
+
return fail(js_throw_type_error(c->ctx, "Failed to execute '%s' on 'SubtleCrypto': %s argument is not of type object or string.",
|
|
193
|
+
c->op, ORDINALS[i]));
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
static JSCryptoKey *arg_key(Call *c, JSValue v, int i) {
|
|
197
|
+
JSCryptoKey *k = js_as_crypto_key(v);
|
|
198
|
+
if (!k) (void)fail(js_throw_node_error(c->ctx, JS_TYPE_ERROR, "ERR_INVALID_ARG_TYPE",
|
|
199
|
+
"Failed to execute '%s' on 'SubtleCrypto': %s argument is not of type CryptoKey.", c->op,
|
|
200
|
+
ORDINALS[i]));
|
|
201
|
+
return k;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/* An enum value (KeyFormat, KeyUsage): its index in `values`, or -1 with a TypeError. */
|
|
205
|
+
static int arg_enum(Call *c, JSValue v, const char *const *values, int count, const char *type, const char *where) {
|
|
206
|
+
JSValue s = js_to_string(c->ctx, v);
|
|
207
|
+
if (js_is_exception(s)) return -1;
|
|
208
|
+
char buf[32];
|
|
209
|
+
ascii_of(c->ctx, s, buf, sizeof buf);
|
|
210
|
+
for (int i = 0; i < count; i++)
|
|
211
|
+
if (strcmp(buf, values[i]) == 0) return i;
|
|
212
|
+
char shown[64];
|
|
213
|
+
size_t n = js_view_to_utf8(js_string_view(c->ctx, s), shown, sizeof shown - 1);
|
|
214
|
+
shown[n < sizeof shown - 1 ? n : sizeof shown - 1] = 0;
|
|
215
|
+
return fail(js_throw_node_error(c->ctx, JS_TYPE_ERROR, "ERR_INVALID_ARG_VALUE",
|
|
216
|
+
"Failed to execute '%s' on 'SubtleCrypto': %s value '%s' is not a valid enum value of type %s.",
|
|
217
|
+
c->op, where, shown, type));
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
enum { FORMAT_RAW, FORMAT_SPKI, FORMAT_PKCS8, FORMAT_JWK };
|
|
221
|
+
static const char *const FORMATS[] = { "raw", "spki", "pkcs8", "jwk" };
|
|
222
|
+
static const char *const USAGES[] = { "encrypt", "decrypt", "sign", "verify", "deriveKey", "deriveBits", "wrapKey", "unwrapKey" };
|
|
223
|
+
|
|
224
|
+
static int arg_format(Call *c, JSValue v, int i) {
|
|
225
|
+
char where[32];
|
|
226
|
+
snprintf(where, sizeof where, "%s argument", ORDINALS[i]);
|
|
227
|
+
return arg_enum(c, v, FORMATS, 4, "KeyFormat", where);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/* sequence<KeyUsage>: a new array of the strings, in order (duplicates kept, as Node keeps them),
|
|
231
|
+
* and their bits. */
|
|
232
|
+
static JSValue arg_usages(Call *c, JSValue v, int i, uint16_t *mask) {
|
|
233
|
+
JSContext *ctx = c->ctx;
|
|
234
|
+
JSValue method = js_is_object(v) ? js_get_value(ctx, v, JS_SYMBOL(iterator)) : JS_UNDEFINED;
|
|
235
|
+
if (js_is_exception(method)) return method;
|
|
236
|
+
if (!js_is_callable(method))
|
|
237
|
+
return js_throw_node_error(ctx, JS_TYPE_ERROR, "ERR_INVALID_ARG_TYPE",
|
|
238
|
+
"Failed to execute '%s' on 'SubtleCrypto': %s argument can not be converted to sequence.", c->op,
|
|
239
|
+
ORDINALS[i]);
|
|
240
|
+
JSValue out = js_new_array(ctx, 4);
|
|
241
|
+
JSValue rec = js_iter_start(ctx, v);
|
|
242
|
+
if (js_is_exception(rec)) return rec;
|
|
243
|
+
*mask = 0;
|
|
244
|
+
for (uint32_t n = 0;; n++) {
|
|
245
|
+
JSValue u = js_iter_next(ctx, rec);
|
|
246
|
+
if (js_is_exception(u)) return u;
|
|
247
|
+
if (js_is_empty(u)) break;
|
|
248
|
+
char where[64];
|
|
249
|
+
snprintf(where, sizeof where, "%s argument, index %u", ORDINALS[i], n);
|
|
250
|
+
int k = arg_enum(c, u, USAGES, 8, "KeyUsage", where);
|
|
251
|
+
if (k < 0) {
|
|
252
|
+
js_iter_close_throw(ctx, rec);
|
|
253
|
+
return JS_EXCEPTION;
|
|
254
|
+
}
|
|
255
|
+
*mask |= (uint16_t)(1u << k);
|
|
256
|
+
if (js_array_append(ctx, out, str(ctx, USAGES[k])) < 0) return JS_EXCEPTION;
|
|
257
|
+
}
|
|
258
|
+
return out;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/* The usages of a mask, in KeyUsage's order (generateKey's: Node makes them a set). */
|
|
262
|
+
static JSValue usages_array(JSContext *ctx, JSValue given) {
|
|
263
|
+
JSValue out = js_new_array(ctx, 4);
|
|
264
|
+
uint32_t n = js_array_length(js_as_object(given));
|
|
265
|
+
for (uint32_t i = 0; i < n; i++) {
|
|
266
|
+
JSValue u = js_get_elem(ctx, given, js_int32((int32_t)i));
|
|
267
|
+
if (js_is_exception(u)) return u;
|
|
268
|
+
bool seen = false;
|
|
269
|
+
for (uint32_t j = 0; j < js_array_length(js_as_object(out)) && !seen; j++)
|
|
270
|
+
seen = js_string_equals(ctx, js_get_elem(ctx, out, js_int32((int32_t)j)), u);
|
|
271
|
+
if (!seen && js_array_append(ctx, out, u) < 0) return JS_EXCEPTION;
|
|
272
|
+
}
|
|
273
|
+
return out;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/* ---- JsonWebKey -------------------------------------------------------------------------------- */
|
|
277
|
+
|
|
278
|
+
/* A JWK's members, by name (WebIDL's order, alphabetical): undefined when absent; ext a
|
|
279
|
+
* boolean, key_ops an array of strings, the rest strings. */
|
|
280
|
+
enum { JWK_ALG, JWK_CRV, JWK_D, JWK_DP, JWK_DQ, JWK_E, JWK_EXT, JWK_K, JWK_KEY_OPS, JWK_KTY, JWK_N, JWK_P, JWK_Q, JWK_QI, JWK_USE, JWK_X, JWK_Y, JWK_COUNT };
|
|
281
|
+
static const char *const JWK_NAMES[] = { "alg", "crv", "d", "dp", "dq", "e", "ext", "k", "key_ops", "kty", "n", "p", "q", "qi", "use", "x", "y" };
|
|
282
|
+
|
|
283
|
+
typedef struct JWK {
|
|
284
|
+
JSValue m[JWK_COUNT];
|
|
285
|
+
} JWK;
|
|
286
|
+
|
|
287
|
+
/* The dictionary conversion. 0, or -1. */
|
|
288
|
+
static int arg_jwk(Call *c, JSValue v, JWK *j) {
|
|
289
|
+
JSContext *ctx = c->ctx;
|
|
290
|
+
for (int i = 0; i < JWK_COUNT; i++) j->m[i] = JS_UNDEFINED;
|
|
291
|
+
if (js_is_nullish(v)) return 0;
|
|
292
|
+
if (!js_is_object(v))
|
|
293
|
+
return fail(js_throw_node_error(ctx, JS_TYPE_ERROR, "ERR_INVALID_ARG_TYPE",
|
|
294
|
+
"Failed to execute '%s' on 'SubtleCrypto': 2nd argument can not be converted to a dictionary",
|
|
295
|
+
c->op));
|
|
296
|
+
for (int i = 0; i < JWK_COUNT; i++) {
|
|
297
|
+
JSValue m = js_get_value(ctx, v, js_atom_from_cstr(ctx, JWK_NAMES[i]));
|
|
298
|
+
if (js_is_exception(m)) return -1;
|
|
299
|
+
if (js_is_undefined(m)) continue;
|
|
300
|
+
if (i == JWK_EXT) {
|
|
301
|
+
j->m[i] = js_to_boolean(m);
|
|
302
|
+
} else if (i == JWK_KEY_OPS) {
|
|
303
|
+
JSValue method = js_is_object(m) ? js_get_value(ctx, m, JS_SYMBOL(iterator)) : JS_UNDEFINED;
|
|
304
|
+
if (js_is_exception(method)) return -1;
|
|
305
|
+
if (!js_is_callable(method))
|
|
306
|
+
return fail(js_throw_node_error(ctx, JS_TYPE_ERROR, "ERR_INVALID_ARG_TYPE",
|
|
307
|
+
"Failed to execute '%s' on 'SubtleCrypto': 'key_ops' of 'JsonWebKey' (2nd argument) "
|
|
308
|
+
"can not be converted to sequence.", c->op));
|
|
309
|
+
JSValue ops = js_new_array(ctx, 4), rec = js_iter_start(ctx, m);
|
|
310
|
+
if (js_is_exception(rec)) return -1;
|
|
311
|
+
for (;;) {
|
|
312
|
+
JSValue op = js_iter_next(ctx, rec);
|
|
313
|
+
if (js_is_exception(op)) return -1;
|
|
314
|
+
if (js_is_empty(op)) break;
|
|
315
|
+
JSValue s = js_to_string(ctx, op);
|
|
316
|
+
if (js_is_exception(s) || js_array_append(ctx, ops, s) < 0) return -1;
|
|
317
|
+
}
|
|
318
|
+
j->m[i] = ops;
|
|
319
|
+
} else {
|
|
320
|
+
JSValue s = js_to_string(ctx, m);
|
|
321
|
+
if (js_is_exception(s)) return -1;
|
|
322
|
+
j->m[i] = s;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
return 0;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
static bool string_is(JSContext *ctx, JSValue s, const char *cstr) {
|
|
329
|
+
if (!js_is_string(s)) return false;
|
|
330
|
+
char buf[64];
|
|
331
|
+
ascii_of(ctx, s, buf, sizeof buf);
|
|
332
|
+
return strcmp(buf, cstr) == 0 && js_string_view(ctx, s).length == strlen(cstr);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/* validateKeyOps: no known operation twice, and every usage among them. 0, or -1. */
|
|
336
|
+
static int jwk_check_key_ops(JSContext *ctx, JSValue key_ops, JSValue usages) {
|
|
337
|
+
if (js_is_undefined(key_ops)) return 0;
|
|
338
|
+
uint32_t n = js_array_length(js_as_object(key_ops));
|
|
339
|
+
uint32_t seen = 0;
|
|
340
|
+
for (uint32_t i = 0; i < n; i++) {
|
|
341
|
+
JSValue op = js_get_elem(ctx, key_ops, js_int32((int32_t)i));
|
|
342
|
+
for (int k = 0; k < 8; k++) {
|
|
343
|
+
if (!string_is(ctx, op, USAGES[k])) continue;
|
|
344
|
+
if (seen & (1u << k)) return fail(dom_error(ctx, "DataError", "Duplicate key operation"));
|
|
345
|
+
seen |= 1u << k;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
uint32_t m = js_array_length(js_as_object(usages));
|
|
349
|
+
for (uint32_t i = 0; i < m; i++) {
|
|
350
|
+
JSValue u = js_get_elem(ctx, usages, js_int32((int32_t)i));
|
|
351
|
+
bool found = false;
|
|
352
|
+
for (uint32_t k = 0; k < n && !found; k++) found = js_string_equals(ctx, js_get_elem(ctx, key_ops, js_int32((int32_t)k)), u);
|
|
353
|
+
if (!found) return fail(dom_error(ctx, "DataError", "Key operations and usage mismatch"));
|
|
354
|
+
}
|
|
355
|
+
return 0;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/* ---- Algorithms -------------------------------------------------------------------------------- */
|
|
359
|
+
|
|
360
|
+
typedef enum Op {
|
|
361
|
+
OP_DIGEST, OP_IMPORT_KEY, OP_GENERATE_KEY, OP_SIGN, OP_VERIFY, OP_DERIVE_BITS, OP_GET_KEY_LENGTH, OP_ENCRYPT, OP_DECRYPT,
|
|
362
|
+
OP_WRAP_KEY, OP_UNWRAP_KEY,
|
|
363
|
+
} Op;
|
|
364
|
+
|
|
365
|
+
/* Parameter dictionaries, and their members (alphabetical, as WebIDL converts them) */
|
|
366
|
+
typedef enum Dict {
|
|
367
|
+
DICT_NONE, DICT_HMAC_IMPORT, DICT_HMAC_KEYGEN, DICT_PBKDF2, DICT_HKDF, DICT_AES_CBC, DICT_AES_CTR, DICT_AES_GCM, DICT_AES_KEYGEN,
|
|
368
|
+
DICT_AES_DERIVED, DICT_RSA_HASHED_IMPORT, DICT_RSA_HASHED_KEYGEN, DICT_RSA_PSS, DICT_RSA_OAEP, DICT_EC_IMPORT, DICT_EC_KEYGEN,
|
|
369
|
+
DICT_ECDSA, DICT_ECDH_DERIVE,
|
|
370
|
+
} Dict;
|
|
371
|
+
|
|
372
|
+
typedef enum Member {
|
|
373
|
+
M_ADDITIONAL_DATA, M_COUNTER, M_HASH, M_INFO, M_ITERATIONS, M_IV, M_LABEL, M_LENGTH, M_MODULUS_LENGTH, M_NAMED_CURVE, M_PUBLIC,
|
|
374
|
+
M_PUBLIC_EXPONENT, M_SALT, M_SALT_LENGTH, M_TAG_LENGTH, M_END,
|
|
375
|
+
} Member;
|
|
376
|
+
|
|
377
|
+
static const char *const MEMBER_NAMES[] = {
|
|
378
|
+
"additionalData", "counter", "hash", "info", "iterations", "iv", "label", "length", "modulusLength", "namedCurve", "public",
|
|
379
|
+
"publicExponent", "salt", "saltLength", "tagLength",
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
static const struct {
|
|
383
|
+
const char *name;
|
|
384
|
+
Member members[4];
|
|
385
|
+
uint8_t required; /* bits of the members' positions */
|
|
386
|
+
uint32_t length_max; /* the length member's type: unsigned long, unsigned short or octet */
|
|
387
|
+
} DICTS[] = {
|
|
388
|
+
[DICT_NONE] = { "Algorithm", { M_END }, 0, 0 },
|
|
389
|
+
[DICT_HMAC_IMPORT] = { "HmacImportParams", { M_HASH, M_LENGTH, M_END }, 1, 4294967295u },
|
|
390
|
+
[DICT_HMAC_KEYGEN] = { "HmacKeyGenParams", { M_HASH, M_LENGTH, M_END }, 1, 4294967295u },
|
|
391
|
+
[DICT_PBKDF2] = { "Pbkdf2Params", { M_HASH, M_ITERATIONS, M_SALT, M_END }, 7, 0 },
|
|
392
|
+
[DICT_HKDF] = { "HkdfParams", { M_HASH, M_INFO, M_SALT, M_END }, 7, 0 },
|
|
393
|
+
[DICT_AES_CBC] = { "AesCbcParams", { M_IV, M_END }, 1, 0 },
|
|
394
|
+
[DICT_AES_CTR] = { "AesCtrParams", { M_COUNTER, M_LENGTH, M_END }, 3, 255 },
|
|
395
|
+
[DICT_AES_GCM] = { "AesGcmParams", { M_ADDITIONAL_DATA, M_IV, M_TAG_LENGTH, M_END }, 2, 0 },
|
|
396
|
+
[DICT_AES_KEYGEN] = { "AesKeyGenParams", { M_LENGTH, M_END }, 1, 65535 },
|
|
397
|
+
[DICT_AES_DERIVED] = { "AesDerivedKeyParams", { M_LENGTH, M_END }, 1, 65535 },
|
|
398
|
+
[DICT_RSA_HASHED_IMPORT] = { "RsaHashedImportParams", { M_HASH, M_END }, 1, 0 },
|
|
399
|
+
[DICT_RSA_HASHED_KEYGEN] = { "RsaHashedKeyGenParams", { M_HASH, M_MODULUS_LENGTH, M_PUBLIC_EXPONENT, M_END }, 7, 0 },
|
|
400
|
+
[DICT_RSA_PSS] = { "RsaPssParams", { M_SALT_LENGTH, M_END }, 1, 0 },
|
|
401
|
+
[DICT_RSA_OAEP] = { "RsaOaepParams", { M_LABEL, M_END }, 0, 0 },
|
|
402
|
+
[DICT_EC_IMPORT] = { "EcKeyImportParams", { M_NAMED_CURVE, M_END }, 1, 0 },
|
|
403
|
+
[DICT_EC_KEYGEN] = { "EcKeyGenParams", { M_NAMED_CURVE, M_END }, 1, 0 },
|
|
404
|
+
[DICT_ECDSA] = { "EcdsaParams", { M_HASH, M_END }, 1, 0 },
|
|
405
|
+
[DICT_ECDH_DERIVE] = { "EcdhKeyDeriveParams", { M_PUBLIC, M_END }, 1, 0 },
|
|
406
|
+
};
|
|
407
|
+
|
|
408
|
+
#define BIT(op) (1u << (op))
|
|
409
|
+
#define AES_OPS BIT(OP_IMPORT_KEY) | BIT(OP_GENERATE_KEY) | BIT(OP_ENCRYPT) | BIT(OP_DECRYPT) | BIT(OP_GET_KEY_LENGTH)
|
|
410
|
+
#define AES_DICTS(params) { [OP_ENCRYPT] = params, [OP_DECRYPT] = params, [OP_GENERATE_KEY] = DICT_AES_KEYGEN, [OP_GET_KEY_LENGTH] = DICT_AES_DERIVED }
|
|
411
|
+
#define KEY_OPS BIT(OP_IMPORT_KEY) | BIT(OP_GENERATE_KEY)
|
|
412
|
+
|
|
413
|
+
static const struct {
|
|
414
|
+
const char *name;
|
|
415
|
+
uint8_t alg; /* JSWebAlg */
|
|
416
|
+
uint32_t ops; /* BIT(op) of the operations it supports */
|
|
417
|
+
uint8_t dict[OP_UNWRAP_KEY + 1];
|
|
418
|
+
} REGISTRY[] = {
|
|
419
|
+
{ "HMAC", JS_WEB_HMAC, BIT(OP_IMPORT_KEY) | BIT(OP_GENERATE_KEY) | BIT(OP_SIGN) | BIT(OP_VERIFY) | BIT(OP_GET_KEY_LENGTH),
|
|
420
|
+
{ [OP_IMPORT_KEY] = DICT_HMAC_IMPORT, [OP_GENERATE_KEY] = DICT_HMAC_KEYGEN, [OP_GET_KEY_LENGTH] = DICT_HMAC_IMPORT } },
|
|
421
|
+
{ "PBKDF2", JS_WEB_PBKDF2, BIT(OP_IMPORT_KEY) | BIT(OP_DERIVE_BITS) | BIT(OP_GET_KEY_LENGTH), { [OP_DERIVE_BITS] = DICT_PBKDF2 } },
|
|
422
|
+
{ "HKDF", JS_WEB_HKDF, BIT(OP_IMPORT_KEY) | BIT(OP_DERIVE_BITS) | BIT(OP_GET_KEY_LENGTH), { [OP_DERIVE_BITS] = DICT_HKDF } },
|
|
423
|
+
{ "AES-CTR", JS_WEB_AES_CTR, AES_OPS, AES_DICTS(DICT_AES_CTR) },
|
|
424
|
+
{ "AES-CBC", JS_WEB_AES_CBC, AES_OPS, AES_DICTS(DICT_AES_CBC) },
|
|
425
|
+
{ "AES-GCM", JS_WEB_AES_GCM, AES_OPS, AES_DICTS(DICT_AES_GCM) },
|
|
426
|
+
{ "AES-KW", JS_WEB_AES_KW, BIT(OP_IMPORT_KEY) | BIT(OP_GENERATE_KEY) | BIT(OP_WRAP_KEY) | BIT(OP_UNWRAP_KEY) | BIT(OP_GET_KEY_LENGTH),
|
|
427
|
+
{ [OP_GENERATE_KEY] = DICT_AES_KEYGEN, [OP_GET_KEY_LENGTH] = DICT_AES_DERIVED } },
|
|
428
|
+
{ "RSASSA-PKCS1-v1_5", JS_WEB_RSASSA, KEY_OPS | BIT(OP_SIGN) | BIT(OP_VERIFY),
|
|
429
|
+
{ [OP_IMPORT_KEY] = DICT_RSA_HASHED_IMPORT, [OP_GENERATE_KEY] = DICT_RSA_HASHED_KEYGEN } },
|
|
430
|
+
{ "RSA-PSS", JS_WEB_RSA_PSS, KEY_OPS | BIT(OP_SIGN) | BIT(OP_VERIFY),
|
|
431
|
+
{ [OP_IMPORT_KEY] = DICT_RSA_HASHED_IMPORT, [OP_GENERATE_KEY] = DICT_RSA_HASHED_KEYGEN, [OP_SIGN] = DICT_RSA_PSS, [OP_VERIFY] = DICT_RSA_PSS } },
|
|
432
|
+
{ "RSA-OAEP", JS_WEB_RSA_OAEP, KEY_OPS | BIT(OP_ENCRYPT) | BIT(OP_DECRYPT),
|
|
433
|
+
{ [OP_IMPORT_KEY] = DICT_RSA_HASHED_IMPORT, [OP_GENERATE_KEY] = DICT_RSA_HASHED_KEYGEN, [OP_ENCRYPT] = DICT_RSA_OAEP, [OP_DECRYPT] = DICT_RSA_OAEP } },
|
|
434
|
+
{ "ECDSA", JS_WEB_ECDSA, KEY_OPS | BIT(OP_SIGN) | BIT(OP_VERIFY),
|
|
435
|
+
{ [OP_IMPORT_KEY] = DICT_EC_IMPORT, [OP_GENERATE_KEY] = DICT_EC_KEYGEN, [OP_SIGN] = DICT_ECDSA, [OP_VERIFY] = DICT_ECDSA } },
|
|
436
|
+
{ "ECDH", JS_WEB_ECDH, KEY_OPS | BIT(OP_DERIVE_BITS),
|
|
437
|
+
{ [OP_IMPORT_KEY] = DICT_EC_IMPORT, [OP_GENERATE_KEY] = DICT_EC_KEYGEN, [OP_DERIVE_BITS] = DICT_ECDH_DERIVE } },
|
|
438
|
+
{ "X25519", JS_WEB_X25519, KEY_OPS | BIT(OP_DERIVE_BITS), { [OP_DERIVE_BITS] = DICT_ECDH_DERIVE } },
|
|
439
|
+
};
|
|
440
|
+
|
|
441
|
+
/* A normalized algorithm: its registry entry and the members its dictionary has. */
|
|
442
|
+
typedef struct Params {
|
|
443
|
+
int entry; /* REGISTRY index; -1 for a digest */
|
|
444
|
+
const char *name; /* the registered name */
|
|
445
|
+
const JSHashAlg *hash; /* a digest's own algorithm, or the hash member */
|
|
446
|
+
bool has_length, has_tag_length, has_additional_data, has_label;
|
|
447
|
+
uint32_t length;
|
|
448
|
+
uint32_t iterations;
|
|
449
|
+
uint32_t tag_length;
|
|
450
|
+
uint32_t modulus_length, salt_length;
|
|
451
|
+
char named_curve[16]; /* "" when it's too long to be one */
|
|
452
|
+
JSCryptoKey *public_key; /* ECDH's and X25519's public */
|
|
453
|
+
Bytes salt, info, iv, counter, additional_data, label, public_exponent;
|
|
454
|
+
} Params;
|
|
455
|
+
|
|
456
|
+
static void params_free(Params *p) {
|
|
457
|
+
bytes_free(&p->salt);
|
|
458
|
+
bytes_free(&p->info);
|
|
459
|
+
bytes_free(&p->iv);
|
|
460
|
+
bytes_free(&p->counter);
|
|
461
|
+
bytes_free(&p->additional_data);
|
|
462
|
+
bytes_free(&p->label);
|
|
463
|
+
bytes_free(&p->public_exponent);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
static uint8_t params_alg(const Params *p) { return REGISTRY[p->entry].alg; }
|
|
467
|
+
|
|
468
|
+
static JSValue throw_member(JSContext *ctx, const char *code, Dict d, Member m, const char *what) {
|
|
469
|
+
return js_throw_node_error(ctx, JS_TYPE_ERROR, code, "Failed to normalize algorithm: '%s' of '%s' (passed algorithm) %s",
|
|
470
|
+
MEMBER_NAMES[m], DICTS[d].name, what);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/* An [EnforceRange] integer member of at most `max`. 0, or -1. */
|
|
474
|
+
static int member_uint(JSContext *ctx, JSValue v, Dict d, Member m, uint32_t max, uint32_t *out) {
|
|
475
|
+
double x;
|
|
476
|
+
if (js_to_number(ctx, &x, v) < 0) return -1;
|
|
477
|
+
if (!isfinite(x)) return fail(throw_member(ctx, "ERR_INVALID_ARG_TYPE", d, m, "is not a finite number."));
|
|
478
|
+
x = trunc(x);
|
|
479
|
+
if (x < 0 || x > (double)max) {
|
|
480
|
+
char what[64];
|
|
481
|
+
snprintf(what, sizeof what, "is outside the expected range of 0 to %u.", max);
|
|
482
|
+
return fail(throw_member(ctx, "ERR_OUT_OF_RANGE", d, m, what));
|
|
483
|
+
}
|
|
484
|
+
*out = (uint32_t)x;
|
|
485
|
+
return 0;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/* The name of an AlgorithmIdentifier (an object's `name`, or the string), ASCII. 0, or -1. */
|
|
489
|
+
static int algorithm_name(JSContext *ctx, JSValue alg, char *name, size_t cap) {
|
|
490
|
+
JSValue n = alg;
|
|
491
|
+
if (js_is_object(alg)) {
|
|
492
|
+
n = js_get_value(ctx, alg, JS_ATOM(name));
|
|
493
|
+
if (js_is_exception(n)) return -1;
|
|
494
|
+
if (js_is_undefined(n))
|
|
495
|
+
return fail(js_throw_node_error(ctx, JS_TYPE_ERROR, "ERR_MISSING_OPTION",
|
|
496
|
+
"Failed to normalize algorithm: passed algorithm can not be converted to 'Algorithm' "
|
|
497
|
+
"because 'name' is required in 'Algorithm'."));
|
|
498
|
+
}
|
|
499
|
+
JSValue s = js_to_string(ctx, n);
|
|
500
|
+
if (js_is_exception(s)) return -1;
|
|
501
|
+
ascii_of(ctx, s, name, cap);
|
|
502
|
+
return 0;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
static int normalize_digest(JSContext *ctx, JSValue alg, const JSHashAlg **out) {
|
|
506
|
+
char name[32];
|
|
507
|
+
if (algorithm_name(ctx, alg, name, sizeof name) < 0) return -1;
|
|
508
|
+
*out = js_hash_by_web_name(name);
|
|
509
|
+
return *out ? 0 : fail(dom_error(ctx, "NotSupportedError", "Unrecognized algorithm name"));
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/* normalizeAlgorithm(alg, op): 0, or -1 (the Params own copies of their bytes either way). */
|
|
513
|
+
static int normalize(JSContext *ctx, JSValue alg, Op op, Params *p) {
|
|
514
|
+
memset(p, 0, sizeof *p);
|
|
515
|
+
p->entry = -1;
|
|
516
|
+
if (op == OP_DIGEST) return normalize_digest(ctx, alg, &p->hash);
|
|
517
|
+
char name[32];
|
|
518
|
+
if (algorithm_name(ctx, alg, name, sizeof name) < 0) return -1;
|
|
519
|
+
for (size_t i = 0; i < JS_COUNTOF(REGISTRY); i++)
|
|
520
|
+
if ((REGISTRY[i].ops & BIT(op)) && same_ci(name, REGISTRY[i].name)) p->entry = (int)i;
|
|
521
|
+
if (p->entry < 0) return fail(dom_error(ctx, "NotSupportedError", "Unrecognized algorithm name"));
|
|
522
|
+
p->name = REGISTRY[p->entry].name;
|
|
523
|
+
Dict d = (Dict)REGISTRY[p->entry].dict[op];
|
|
524
|
+
JSValue hash = JS_UNDEFINED;
|
|
525
|
+
for (int i = 0; DICTS[d].members[i] != M_END; i++) {
|
|
526
|
+
Member m = DICTS[d].members[i];
|
|
527
|
+
JSValue v = js_is_object(alg) ? js_get_value(ctx, alg, js_atom_from_cstr(ctx, MEMBER_NAMES[m])) : JS_UNDEFINED;
|
|
528
|
+
if (js_is_exception(v)) return -1;
|
|
529
|
+
if (js_is_undefined(v)) {
|
|
530
|
+
if (DICTS[d].required & (1u << i))
|
|
531
|
+
return fail(js_throw_node_error(ctx, JS_TYPE_ERROR, "ERR_MISSING_OPTION",
|
|
532
|
+
"Failed to normalize algorithm: passed algorithm can not be converted to '%s' "
|
|
533
|
+
"because '%s' is required in '%s'.", DICTS[d].name, MEMBER_NAMES[m], DICTS[d].name));
|
|
534
|
+
continue;
|
|
535
|
+
}
|
|
536
|
+
switch (m) {
|
|
537
|
+
case M_HASH:
|
|
538
|
+
if (js_is_symbol(v)) return fail(throw_member(ctx, "ERR_INVALID_ARG_TYPE", d, m, "is not of type object or string."));
|
|
539
|
+
if (!js_is_object(v)) {
|
|
540
|
+
v = js_to_string(ctx, v);
|
|
541
|
+
if (js_is_exception(v)) return -1;
|
|
542
|
+
}
|
|
543
|
+
hash = v;
|
|
544
|
+
break;
|
|
545
|
+
case M_LENGTH:
|
|
546
|
+
if (member_uint(ctx, v, d, m, DICTS[d].length_max, &p->length) < 0) return -1;
|
|
547
|
+
p->has_length = true;
|
|
548
|
+
break;
|
|
549
|
+
case M_ITERATIONS:
|
|
550
|
+
if (member_uint(ctx, v, d, m, 4294967295u, &p->iterations) < 0) return -1;
|
|
551
|
+
break;
|
|
552
|
+
case M_MODULUS_LENGTH:
|
|
553
|
+
if (member_uint(ctx, v, d, m, 4294967295u, &p->modulus_length) < 0) return -1;
|
|
554
|
+
break;
|
|
555
|
+
case M_SALT_LENGTH:
|
|
556
|
+
if (member_uint(ctx, v, d, m, 4294967295u, &p->salt_length) < 0) return -1;
|
|
557
|
+
break;
|
|
558
|
+
case M_TAG_LENGTH:
|
|
559
|
+
if (member_uint(ctx, v, d, m, 255, &p->tag_length) < 0) return -1;
|
|
560
|
+
p->has_tag_length = true;
|
|
561
|
+
break;
|
|
562
|
+
case M_NAMED_CURVE: {
|
|
563
|
+
JSValue s = js_to_string(ctx, v);
|
|
564
|
+
if (js_is_exception(s)) return -1;
|
|
565
|
+
ascii_of(ctx, s, p->named_curve, sizeof p->named_curve);
|
|
566
|
+
break;
|
|
567
|
+
}
|
|
568
|
+
case M_PUBLIC:
|
|
569
|
+
p->public_key = js_as_crypto_key(v);
|
|
570
|
+
if (!p->public_key) return fail(throw_member(ctx, "ERR_INVALID_ARG_TYPE", d, m, "is not of type CryptoKey."));
|
|
571
|
+
break;
|
|
572
|
+
case M_PUBLIC_EXPONENT:
|
|
573
|
+
if (js_typed_array_type(v) != JS_TA_UINT8) return fail(throw_member(ctx, "ERR_INVALID_ARG_TYPE", d, m, "is not an Uint8Array object."));
|
|
574
|
+
bytes_copy(&p->public_exponent, v);
|
|
575
|
+
break;
|
|
576
|
+
case M_SALT:
|
|
577
|
+
case M_INFO:
|
|
578
|
+
case M_IV:
|
|
579
|
+
case M_COUNTER:
|
|
580
|
+
case M_LABEL:
|
|
581
|
+
case M_ADDITIONAL_DATA: {
|
|
582
|
+
uint8_t *bp;
|
|
583
|
+
size_t bn;
|
|
584
|
+
if (!js_buffer_source_bytes(v, &bp, &bn))
|
|
585
|
+
return fail(throw_member(ctx, "ERR_INVALID_ARG_TYPE", d, m, "is not instance of ArrayBuffer, Buffer, TypedArray, or DataView."));
|
|
586
|
+
Bytes *slot = m == M_SALT ? &p->salt : m == M_INFO ? &p->info : m == M_IV ? &p->iv : m == M_COUNTER ? &p->counter
|
|
587
|
+
: m == M_LABEL ? &p->label : &p->additional_data;
|
|
588
|
+
bytes_copy(slot, v);
|
|
589
|
+
if (m == M_ADDITIONAL_DATA) p->has_additional_data = true;
|
|
590
|
+
if (m == M_LABEL) p->has_label = true;
|
|
591
|
+
break;
|
|
592
|
+
}
|
|
593
|
+
case M_END:
|
|
594
|
+
break;
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
if (!js_is_undefined(hash) && normalize_digest(ctx, hash, &p->hash) < 0) return -1;
|
|
598
|
+
return 0;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
/* The `algorithm` of a key: { name: 'SHA-256' } for a hash */
|
|
602
|
+
static JSValue hash_object(JSContext *ctx, const JSHashAlg *hash) {
|
|
603
|
+
JSValue o = js_new_object(ctx);
|
|
604
|
+
put(ctx, o, "name", str(ctx, hash->web));
|
|
605
|
+
return o;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
/* ---- Keys -------------------------------------------------------------------------------------- */
|
|
609
|
+
|
|
610
|
+
static bool has_any_not_in(uint16_t mask, uint16_t allowed) { return (mask & ~allowed) != 0; }
|
|
611
|
+
|
|
612
|
+
/* HMAC: the key's object, as Node orders it: { name, hash, length } on import, { name, length,
|
|
613
|
+
* hash } when generated. */
|
|
614
|
+
static JSValue hmac_algorithm(JSContext *ctx, const JSHashAlg *hash, uint32_t length, bool generated) {
|
|
615
|
+
JSValue o = js_new_object(ctx);
|
|
616
|
+
put(ctx, o, "name", str(ctx, "HMAC"));
|
|
617
|
+
if (generated) put(ctx, o, "length", js_number(length));
|
|
618
|
+
put(ctx, o, "hash", hash_object(ctx, hash));
|
|
619
|
+
if (!generated) put(ctx, o, "length", js_number(length));
|
|
620
|
+
return o;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
static JSValue import_hmac(JSContext *ctx, int format, JSValue key_data, const JWK *jwk, Params *p, bool extractable, JSValue usages,
|
|
624
|
+
uint16_t mask) {
|
|
625
|
+
if (has_any_not_in(mask, JS_USAGE_SIGN | JS_USAGE_VERIFY)) return dom_error(ctx, "SyntaxError", "Unsupported key usage for an HMAC key");
|
|
626
|
+
Bytes raw = { 0 };
|
|
627
|
+
if (format == FORMAT_RAW) {
|
|
628
|
+
bytes_copy(&raw, key_data);
|
|
629
|
+
} else if (format == FORMAT_JWK) {
|
|
630
|
+
if (js_is_undefined(jwk->m[JWK_KTY]) || string_is(ctx, jwk->m[JWK_KTY], "")) return dom_error(ctx, "DataError", "Invalid keyData");
|
|
631
|
+
if (!string_is(ctx, jwk->m[JWK_KTY], "oct")) return dom_error(ctx, "DataError", "Invalid JWK \"kty\" Parameter");
|
|
632
|
+
if (mask && !js_is_undefined(jwk->m[JWK_USE]) && !string_is(ctx, jwk->m[JWK_USE], "sig")) return dom_error(ctx, "DataError", "Invalid JWK \"use\" Parameter");
|
|
633
|
+
if (jwk_check_key_ops(ctx, jwk->m[JWK_KEY_OPS], usages) < 0) return JS_EXCEPTION;
|
|
634
|
+
if (js_is_bool(jwk->m[JWK_EXT]) && !js_as_bool(jwk->m[JWK_EXT]) && extractable)
|
|
635
|
+
return dom_error(ctx, "DataError", "JWK \"ext\" Parameter and extractable mismatch");
|
|
636
|
+
if (js_is_undefined(jwk->m[JWK_K])) return dom_error(ctx, "DataError", "Invalid keyData");
|
|
637
|
+
base64url_decode(ctx, jwk->m[JWK_K], &raw);
|
|
638
|
+
if (!js_is_undefined(jwk->m[JWK_ALG])) {
|
|
639
|
+
char expected[8];
|
|
640
|
+
snprintf(expected, sizeof expected, "HS%s", p->hash->web + 4);
|
|
641
|
+
if (!string_is(ctx, jwk->m[JWK_ALG], expected)) {
|
|
642
|
+
bytes_free(&raw);
|
|
643
|
+
return dom_error(ctx, "DataError", "JWK \"alg\" does not match the requested algorithm");
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
} else {
|
|
647
|
+
char m[64];
|
|
648
|
+
snprintf(m, sizeof m, "Unable to import HMAC using %s format", FORMATS[format]);
|
|
649
|
+
return dom_error(ctx, "NotSupportedError", m);
|
|
650
|
+
}
|
|
651
|
+
uint32_t length = (uint32_t)raw.n * 8;
|
|
652
|
+
if (length == 0 || (p->has_length && p->length == 0)) {
|
|
653
|
+
bytes_free(&raw);
|
|
654
|
+
return dom_error(ctx, "DataError", "Zero-length key is not supported");
|
|
655
|
+
}
|
|
656
|
+
if (p->has_length && p->length != length) {
|
|
657
|
+
bytes_free(&raw);
|
|
658
|
+
return dom_error(ctx, "NotSupportedError", "Unsupported algorithm.length");
|
|
659
|
+
}
|
|
660
|
+
JSValue data = js_new_secret_key(ctx, raw.p, raw.n);
|
|
661
|
+
bytes_free(&raw);
|
|
662
|
+
return js_new_crypto_key(ctx, data, JS_WEB_HMAC, p->hash, length, hmac_algorithm(ctx, p->hash, length, false), usages, mask,
|
|
663
|
+
extractable);
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
/* PBKDF2 and HKDF keys: raw secrets, never extractable */
|
|
667
|
+
static JSValue import_generic_secret(JSContext *ctx, int format, JSValue key_data, Params *p, bool extractable, JSValue usages,
|
|
668
|
+
uint16_t mask) {
|
|
669
|
+
char m[64];
|
|
670
|
+
if (extractable) {
|
|
671
|
+
snprintf(m, sizeof m, "%s keys are not extractable", p->name);
|
|
672
|
+
return dom_error(ctx, "SyntaxError", m);
|
|
673
|
+
}
|
|
674
|
+
if (has_any_not_in(mask, JS_USAGE_DERIVE_KEY | JS_USAGE_DERIVE_BITS)) {
|
|
675
|
+
snprintf(m, sizeof m, "Unsupported key usage for a %s key", p->name);
|
|
676
|
+
return dom_error(ctx, "SyntaxError", m);
|
|
677
|
+
}
|
|
678
|
+
if (format != FORMAT_RAW) {
|
|
679
|
+
snprintf(m, sizeof m, "Unable to import %s using %s format", p->name, FORMATS[format]);
|
|
680
|
+
return dom_error(ctx, "NotSupportedError", m);
|
|
681
|
+
}
|
|
682
|
+
Bytes raw;
|
|
683
|
+
bytes_copy(&raw, key_data);
|
|
684
|
+
JSValue data = js_new_secret_key(ctx, raw.p, raw.n);
|
|
685
|
+
bytes_free(&raw);
|
|
686
|
+
JSValue alg = js_new_object(ctx);
|
|
687
|
+
put(ctx, alg, "name", str(ctx, p->name));
|
|
688
|
+
return js_new_crypto_key(ctx, data, REGISTRY[p->entry].alg, NULL, 0, alg, usages, mask, false);
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
static const char *web_alg_name(uint8_t alg) {
|
|
692
|
+
for (size_t i = 0; i < JS_COUNTOF(REGISTRY); i++)
|
|
693
|
+
if (REGISTRY[i].alg == alg) return REGISTRY[i].name;
|
|
694
|
+
return "";
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
static bool is_aes(uint8_t alg) { return alg >= JS_WEB_AES_CTR && alg <= JS_WEB_AES_KW; }
|
|
698
|
+
|
|
699
|
+
/* A JWK's `alg` for a secret key: HS256, A128GCM, … */
|
|
700
|
+
static void jwk_alg(uint8_t alg, const JSHashAlg *hash, uint32_t length, char *out, size_t cap) {
|
|
701
|
+
if (alg == JS_WEB_HMAC) snprintf(out, cap, "HS%s", hash->web + 4);
|
|
702
|
+
else snprintf(out, cap, "A%u%s", length, web_alg_name(alg) + 4);
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
static uint16_t aes_usages(uint8_t alg) {
|
|
706
|
+
return (uint16_t)(JS_USAGE_WRAP_KEY | JS_USAGE_UNWRAP_KEY | (alg == JS_WEB_AES_KW ? 0 : JS_USAGE_ENCRYPT | JS_USAGE_DECRYPT));
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
static JSValue aes_algorithm(JSContext *ctx, const char *name, uint32_t length) {
|
|
710
|
+
JSValue o = js_new_object(ctx);
|
|
711
|
+
put(ctx, o, "name", str(ctx, name));
|
|
712
|
+
put(ctx, o, "length", js_number(length));
|
|
713
|
+
return o;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
static JSValue import_aes(JSContext *ctx, int format, JSValue key_data, const JWK *jwk, Params *p, bool extractable, JSValue usages,
|
|
717
|
+
uint16_t mask) {
|
|
718
|
+
uint8_t alg = params_alg(p);
|
|
719
|
+
if (has_any_not_in(mask, aes_usages(alg))) return dom_error(ctx, "SyntaxError", "Unsupported key usage for an AES key");
|
|
720
|
+
Bytes raw = { 0 };
|
|
721
|
+
if (format == FORMAT_RAW) {
|
|
722
|
+
bytes_copy(&raw, key_data);
|
|
723
|
+
} else if (format == FORMAT_JWK) {
|
|
724
|
+
if (js_is_undefined(jwk->m[JWK_KTY]) || string_is(ctx, jwk->m[JWK_KTY], "")) return dom_error(ctx, "DataError", "Invalid keyData");
|
|
725
|
+
if (!string_is(ctx, jwk->m[JWK_KTY], "oct")) return dom_error(ctx, "DataError", "Invalid JWK \"kty\" Parameter");
|
|
726
|
+
if (mask && !js_is_undefined(jwk->m[JWK_USE]) && !string_is(ctx, jwk->m[JWK_USE], "enc")) return dom_error(ctx, "DataError", "Invalid JWK \"use\" Parameter");
|
|
727
|
+
if (jwk_check_key_ops(ctx, jwk->m[JWK_KEY_OPS], usages) < 0) return JS_EXCEPTION;
|
|
728
|
+
if (js_is_bool(jwk->m[JWK_EXT]) && !js_as_bool(jwk->m[JWK_EXT]) && extractable)
|
|
729
|
+
return dom_error(ctx, "DataError", "JWK \"ext\" Parameter and extractable mismatch");
|
|
730
|
+
if (js_is_undefined(jwk->m[JWK_K])) return dom_error(ctx, "DataError", "Invalid keyData");
|
|
731
|
+
base64url_decode(ctx, jwk->m[JWK_K], &raw);
|
|
732
|
+
} else {
|
|
733
|
+
char m[64];
|
|
734
|
+
snprintf(m, sizeof m, "Unable to import AES key with format %s", FORMATS[format]);
|
|
735
|
+
return dom_error(ctx, "NotSupportedError", m);
|
|
736
|
+
}
|
|
737
|
+
uint32_t length = (uint32_t)raw.n * 8;
|
|
738
|
+
if (length != 128 && length != 192 && length != 256) {
|
|
739
|
+
bytes_free(&raw);
|
|
740
|
+
return dom_error(ctx, "DataError", "Invalid key length");
|
|
741
|
+
}
|
|
742
|
+
if (format == FORMAT_JWK && !js_is_undefined(jwk->m[JWK_ALG])) {
|
|
743
|
+
char expected[16];
|
|
744
|
+
jwk_alg(alg, NULL, length, expected, sizeof expected);
|
|
745
|
+
if (!string_is(ctx, jwk->m[JWK_ALG], expected)) {
|
|
746
|
+
bytes_free(&raw);
|
|
747
|
+
return dom_error(ctx, "DataError", "JWK \"alg\" does not match the requested algorithm");
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
JSValue data = js_new_secret_key(ctx, raw.p, raw.n);
|
|
751
|
+
bytes_free(&raw);
|
|
752
|
+
return js_new_crypto_key(ctx, data, alg, NULL, length, aes_algorithm(ctx, p->name, length), usages, mask, extractable);
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
/* ---- Asymmetric keys: RSA, EC and X25519 --------------------------------------------------------- */
|
|
756
|
+
|
|
757
|
+
static bool is_rsa_alg(uint8_t a) { return a == JS_WEB_RSASSA || a == JS_WEB_RSA_PSS || a == JS_WEB_RSA_OAEP; }
|
|
758
|
+
static bool is_asym_alg(uint8_t a) { return a >= JS_WEB_RSASSA && a <= JS_WEB_X25519; }
|
|
759
|
+
|
|
760
|
+
static size_t bits_of(const JSKeyPart *n) {
|
|
761
|
+
size_t i = 0;
|
|
762
|
+
while (i < n->n && n->p[i] == 0) i++;
|
|
763
|
+
if (i == n->n) return 0;
|
|
764
|
+
size_t bits = (n->n - i - 1) * 8;
|
|
765
|
+
for (uint8_t top = n->p[i]; top; top >>= 1) bits++;
|
|
766
|
+
return bits;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
/* { name, modulusLength, publicExponent, hash } */
|
|
770
|
+
static JSValue rsa_algorithm(JSContext *ctx, const char *name, const JSKeyData *d, const JSHashAlg *hash) {
|
|
771
|
+
JSValue o = js_new_object(ctx);
|
|
772
|
+
put(ctx, o, "name", str(ctx, name));
|
|
773
|
+
put(ctx, o, "modulusLength", js_number((double)bits_of(&d->part[JS_RSA_N])));
|
|
774
|
+
JSValue e = js_new_uint8_array(ctx, d->part[JS_RSA_E].n);
|
|
775
|
+
uint8_t *p;
|
|
776
|
+
size_t n;
|
|
777
|
+
js_buffer_source_bytes(e, &p, &n);
|
|
778
|
+
memcpy(p, d->part[JS_RSA_E].p, n);
|
|
779
|
+
put(ctx, o, "publicExponent", e);
|
|
780
|
+
put(ctx, o, "hash", hash_object(ctx, hash));
|
|
781
|
+
return o;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
static JSValue ec_algorithm(JSContext *ctx, const char *name, int curve) {
|
|
785
|
+
JSValue o = js_new_object(ctx);
|
|
786
|
+
put(ctx, o, "name", str(ctx, name));
|
|
787
|
+
if (curve != BR_EC_curve25519) put(ctx, o, "namedCurve", str(ctx, js_ec_curve_jwk(curve)));
|
|
788
|
+
return o;
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
/* The CryptoKey of a key handle, its algorithm object made from the key. */
|
|
792
|
+
static JSValue asym_crypto_key(JSContext *ctx, JSValue data, uint8_t alg, const char *name, const JSHashAlg *hash, JSValue usages,
|
|
793
|
+
uint16_t mask, bool extractable) {
|
|
794
|
+
JSKeyData *d = js_key_data(data);
|
|
795
|
+
if (is_rsa_alg(alg))
|
|
796
|
+
return js_new_crypto_key(ctx, data, alg, hash, (uint32_t)bits_of(&d->part[JS_RSA_N]), rsa_algorithm(ctx, name, d, hash), usages, mask,
|
|
797
|
+
extractable);
|
|
798
|
+
return js_new_crypto_key(ctx, data, alg, NULL, 0, ec_algorithm(ctx, name, d->curve), usages, mask, extractable);
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
/* The usages a public or private key of an algorithm may have */
|
|
802
|
+
static uint16_t asym_usages(uint8_t alg, bool is_public) {
|
|
803
|
+
switch (alg) {
|
|
804
|
+
case JS_WEB_RSA_OAEP: return is_public ? JS_USAGE_ENCRYPT | JS_USAGE_WRAP_KEY : JS_USAGE_DECRYPT | JS_USAGE_UNWRAP_KEY;
|
|
805
|
+
case JS_WEB_ECDH:
|
|
806
|
+
case JS_WEB_X25519: return is_public ? 0 : JS_USAGE_DERIVE_KEY | JS_USAGE_DERIVE_BITS;
|
|
807
|
+
default: return is_public ? JS_USAGE_VERIFY : JS_USAGE_SIGN;
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
/* A JWK's alg for an RSA key: RS256, PS384, RSA-OAEP-256 (RSA-OAEP for SHA-1) */
|
|
812
|
+
static void rsa_jwk_alg(uint8_t alg, const JSHashAlg *hash, char *out, size_t cap) {
|
|
813
|
+
const char *bits = hash->web + 4; /* "1", "256", … */
|
|
814
|
+
if (alg == JS_WEB_RSA_OAEP) {
|
|
815
|
+
if (strcmp(bits, "1") == 0) snprintf(out, cap, "RSA-OAEP");
|
|
816
|
+
else snprintf(out, cap, "RSA-OAEP-%s", bits);
|
|
817
|
+
} else {
|
|
818
|
+
snprintf(out, cap, "%s%s", alg == JS_WEB_RSASSA ? "RS" : "PS", bits);
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
/* A JWK's parts, base64url-decoded into the key record's order. False when one is missing. */
|
|
823
|
+
static bool jwk_parts(JSContext *ctx, const JWK *jwk, const int *names, int count, JSKeyPart *parts, Bytes *owned) {
|
|
824
|
+
for (int i = 0; i < count; i++) {
|
|
825
|
+
if (names[i] < 0) continue;
|
|
826
|
+
JSValue v = jwk->m[names[i]];
|
|
827
|
+
if (!js_is_string(v)) return false;
|
|
828
|
+
base64url_decode(ctx, v, &owned[i]);
|
|
829
|
+
parts[i].p = owned[i].p;
|
|
830
|
+
parts[i].n = owned[i].n;
|
|
831
|
+
}
|
|
832
|
+
return true;
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
static JSValue import_asym(JSContext *ctx, int format, JSValue key_data, const JWK *jwk, Params *p, bool extractable, JSValue usages,
|
|
836
|
+
uint16_t mask) {
|
|
837
|
+
uint8_t alg = params_alg(p);
|
|
838
|
+
const char *name = p->name;
|
|
839
|
+
char m[96];
|
|
840
|
+
int curve = -1;
|
|
841
|
+
if (alg == JS_WEB_ECDSA || alg == JS_WEB_ECDH) {
|
|
842
|
+
curve = js_ec_curve_by_jwk(p->named_curve);
|
|
843
|
+
if (curve < 0) return dom_error(ctx, "NotSupportedError", "Unrecognized namedCurve");
|
|
844
|
+
}
|
|
845
|
+
if (is_rsa_alg(alg) && format == FORMAT_RAW) {
|
|
846
|
+
snprintf(m, sizeof m, "Unable to import %s using raw format", name);
|
|
847
|
+
return dom_error(ctx, "NotSupportedError", m);
|
|
848
|
+
}
|
|
849
|
+
bool is_public = format == FORMAT_SPKI || format == FORMAT_RAW || (format == FORMAT_JWK && js_is_undefined(jwk->m[JWK_D]));
|
|
850
|
+
if (has_any_not_in(mask, asym_usages(alg, is_public))) {
|
|
851
|
+
snprintf(m, sizeof m, "Unsupported key usage for a%s %s key", is_rsa_alg(alg) ? "n" : "", name);
|
|
852
|
+
return dom_error(ctx, "SyntaxError", m);
|
|
853
|
+
}
|
|
854
|
+
JSValue data = JS_UNDEFINED;
|
|
855
|
+
if (format == FORMAT_SPKI || format == FORMAT_PKCS8) {
|
|
856
|
+
uint8_t *bp;
|
|
857
|
+
size_t bn;
|
|
858
|
+
js_buffer_source_bytes(key_data, &bp, &bn);
|
|
859
|
+
if (js_key_parse_der(ctx, bp, bn, format == FORMAT_SPKI ? JS_KEY_ENC_SPKI : JS_KEY_ENC_PKCS8, format == FORMAT_PKCS8, &data))
|
|
860
|
+
return dom_error(ctx, "DataError", "Invalid keyData");
|
|
861
|
+
} else if (format == FORMAT_RAW) {
|
|
862
|
+
uint8_t *bp, point[133];
|
|
863
|
+
size_t bn;
|
|
864
|
+
js_buffer_source_bytes(key_data, &bp, &bn);
|
|
865
|
+
JSKeyPart parts[JS_KEY_PARTS] = { { 0 } };
|
|
866
|
+
if (alg == JS_WEB_X25519) {
|
|
867
|
+
if (bn != 32) return dom_error(ctx, "DataError", "X25519 raw keys must be exactly 32-bytes");
|
|
868
|
+
parts[JS_EC_PUB].p = bp, parts[JS_EC_PUB].n = 32;
|
|
869
|
+
} else {
|
|
870
|
+
if (!js_ec_point_uncompressed(curve, bp, bn, point)) return dom_error(ctx, "DataError", "Invalid keyData");
|
|
871
|
+
parts[JS_EC_PUB].p = point, parts[JS_EC_PUB].n = 1 + 2 * js_ec_field_size(curve);
|
|
872
|
+
}
|
|
873
|
+
if (js_key_from_parts(ctx, alg == JS_WEB_X25519 ? JS_ASYM_X25519 : JS_ASYM_EC, false, curve, parts, &data))
|
|
874
|
+
return dom_error(ctx, "DataError", "Invalid keyData");
|
|
875
|
+
} else { /* jwk */
|
|
876
|
+
const char *want_kty = is_rsa_alg(alg) ? "RSA" : alg == JS_WEB_X25519 ? "OKP" : "EC";
|
|
877
|
+
if (js_is_undefined(jwk->m[JWK_KTY]) || string_is(ctx, jwk->m[JWK_KTY], "")) return dom_error(ctx, "DataError", "Invalid keyData");
|
|
878
|
+
if (!string_is(ctx, jwk->m[JWK_KTY], want_kty)) return dom_error(ctx, "DataError", "Invalid JWK \"kty\" Parameter");
|
|
879
|
+
if (alg == JS_WEB_X25519 && !string_is(ctx, jwk->m[JWK_CRV], "X25519"))
|
|
880
|
+
return dom_error(ctx, "DataError", "JWK \"crv\" Parameter and algorithm name mismatch");
|
|
881
|
+
if ((alg == JS_WEB_ECDSA || alg == JS_WEB_ECDH) && !string_is(ctx, jwk->m[JWK_CRV], p->named_curve))
|
|
882
|
+
return dom_error(ctx, "DataError", "JWK \"crv\" does not match the requested algorithm");
|
|
883
|
+
const char *want_use = alg == JS_WEB_RSA_OAEP || alg == JS_WEB_ECDH || alg == JS_WEB_X25519 ? "enc" : "sig";
|
|
884
|
+
if (mask && !js_is_undefined(jwk->m[JWK_USE]) && !string_is(ctx, jwk->m[JWK_USE], want_use))
|
|
885
|
+
return dom_error(ctx, "DataError", "Invalid JWK \"use\" Parameter");
|
|
886
|
+
if (jwk_check_key_ops(ctx, jwk->m[JWK_KEY_OPS], usages) < 0) return JS_EXCEPTION;
|
|
887
|
+
if (js_is_bool(jwk->m[JWK_EXT]) && !js_as_bool(jwk->m[JWK_EXT]) && extractable)
|
|
888
|
+
return dom_error(ctx, "DataError", "JWK \"ext\" Parameter and extractable mismatch");
|
|
889
|
+
if (!js_is_undefined(jwk->m[JWK_ALG]) && (is_rsa_alg(alg) || alg == JS_WEB_ECDSA)) {
|
|
890
|
+
char expected[24];
|
|
891
|
+
if (is_rsa_alg(alg)) rsa_jwk_alg(alg, p->hash, expected, sizeof expected);
|
|
892
|
+
else snprintf(expected, sizeof expected, "ES%s", curve == BR_EC_secp256r1 ? "256" : curve == BR_EC_secp384r1 ? "384" : "512");
|
|
893
|
+
if (!string_is(ctx, jwk->m[JWK_ALG], expected)) return dom_error(ctx, "DataError", "JWK \"alg\" does not match the requested algorithm");
|
|
894
|
+
}
|
|
895
|
+
JSKeyPart parts[JS_KEY_PARTS] = { { 0 } };
|
|
896
|
+
Bytes owned[JS_KEY_PARTS] = { { 0 } };
|
|
897
|
+
bool ok;
|
|
898
|
+
int kind;
|
|
899
|
+
if (is_rsa_alg(alg)) {
|
|
900
|
+
static const int rsa_names[] = { JWK_N, JWK_E, JWK_D, JWK_P, JWK_Q, JWK_DP, JWK_DQ, JWK_QI };
|
|
901
|
+
ok = jwk_parts(ctx, jwk, rsa_names, is_public ? 2 : 8, parts, owned);
|
|
902
|
+
kind = JS_ASYM_RSA;
|
|
903
|
+
} else if (alg == JS_WEB_X25519) {
|
|
904
|
+
int names[] = { JWK_X, is_public ? -1 : JWK_D };
|
|
905
|
+
ok = jwk_parts(ctx, jwk, names, 2, parts, owned) && parts[0].n == 32 && (is_public || parts[1].n == 32);
|
|
906
|
+
kind = JS_ASYM_X25519;
|
|
907
|
+
} else {
|
|
908
|
+
int names[] = { JWK_X, is_public ? -1 : JWK_D, JWK_Y };
|
|
909
|
+
ok = jwk_parts(ctx, jwk, names, 3, parts, owned);
|
|
910
|
+
size_t fs = js_ec_field_size(curve);
|
|
911
|
+
uint8_t point[133];
|
|
912
|
+
if (ok && parts[0].n == fs && parts[2].n == fs) {
|
|
913
|
+
point[0] = 4;
|
|
914
|
+
memcpy(point + 1, parts[0].p, fs);
|
|
915
|
+
memcpy(point + 1 + fs, parts[2].p, fs);
|
|
916
|
+
bytes_free(&owned[0]);
|
|
917
|
+
owned[0].p = malloc(1 + 2 * fs);
|
|
918
|
+
if (!owned[0].p) js_fatal("out of memory in crypto");
|
|
919
|
+
memcpy(owned[0].p, point, 1 + 2 * fs);
|
|
920
|
+
parts[0].p = owned[0].p, parts[0].n = 1 + 2 * fs;
|
|
921
|
+
parts[2].p = NULL, parts[2].n = 0;
|
|
922
|
+
} else {
|
|
923
|
+
ok = false;
|
|
924
|
+
}
|
|
925
|
+
kind = JS_ASYM_EC;
|
|
926
|
+
}
|
|
927
|
+
int e = ok ? js_key_from_parts(ctx, kind, !is_public, curve, parts, &data) : 1;
|
|
928
|
+
for (int i = 0; i < JS_KEY_PARTS; i++) bytes_free(&owned[i]);
|
|
929
|
+
if (e) return dom_error(ctx, "DataError", "Invalid JWK");
|
|
930
|
+
}
|
|
931
|
+
JSKeyData *d = js_key_data(data);
|
|
932
|
+
uint8_t want_kind = is_rsa_alg(alg) ? JS_ASYM_RSA : alg == JS_WEB_X25519 ? JS_ASYM_X25519 : JS_ASYM_EC;
|
|
933
|
+
if (d->kind != want_kind) return dom_error(ctx, "DataError", "Invalid key type");
|
|
934
|
+
if (want_kind == JS_ASYM_EC && d->curve != curve) return dom_error(ctx, "DataError", "Named curve mismatch");
|
|
935
|
+
return asym_crypto_key(ctx, data, alg, name, p->hash, usages, mask, extractable);
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
static JSValue export_asym(JSContext *ctx, int format, JSCryptoKey *k) {
|
|
939
|
+
JSKeyData *d = js_key_data(k->data);
|
|
940
|
+
const char *name = web_alg_name(k->alg), *type = d->type == JS_KEY_PUBLIC ? "public" : "private";
|
|
941
|
+
if ((format == FORMAT_SPKI && d->type == JS_KEY_PUBLIC) || (format == FORMAT_PKCS8 && d->type == JS_KEY_PRIVATE)) {
|
|
942
|
+
JSBytesOut o = { 0 };
|
|
943
|
+
js_key_export_der(d, format == FORMAT_SPKI ? JS_KEY_ENC_SPKI : JS_KEY_ENC_PKCS8, &o);
|
|
944
|
+
JSValue r = array_buffer_of(ctx, o.p, o.n);
|
|
945
|
+
free(o.p);
|
|
946
|
+
return r;
|
|
947
|
+
}
|
|
948
|
+
if (format == FORMAT_RAW && d->type == JS_KEY_PUBLIC && !is_rsa_alg(k->alg))
|
|
949
|
+
return array_buffer_of(ctx, d->part[JS_EC_PUB].p, d->part[JS_EC_PUB].n);
|
|
950
|
+
if (format == FORMAT_JWK) {
|
|
951
|
+
JSValue o = js_new_object(ctx);
|
|
952
|
+
put(ctx, o, "key_ops", k->usages);
|
|
953
|
+
put(ctx, o, "ext", js_bool(k->extractable));
|
|
954
|
+
bool priv = d->type == JS_KEY_PRIVATE;
|
|
955
|
+
if (is_rsa_alg(k->alg)) {
|
|
956
|
+
char alg[24];
|
|
957
|
+
rsa_jwk_alg(k->alg, k->hash, alg, sizeof alg);
|
|
958
|
+
put(ctx, o, "alg", str(ctx, alg));
|
|
959
|
+
put(ctx, o, "kty", str(ctx, "RSA"));
|
|
960
|
+
static const char *const names[] = { "n", "e", "d", "p", "q", "dp", "dq", "qi" };
|
|
961
|
+
for (int i = 0; i < (priv ? 8 : 2); i++) put(ctx, o, names[i], base64url_encode(ctx, d->part[i].p, d->part[i].n));
|
|
962
|
+
} else if (k->alg == JS_WEB_X25519) {
|
|
963
|
+
put(ctx, o, "crv", str(ctx, "X25519"));
|
|
964
|
+
if (priv) put(ctx, o, "d", base64url_encode(ctx, d->part[JS_EC_PRIV].p, d->part[JS_EC_PRIV].n));
|
|
965
|
+
put(ctx, o, "x", base64url_encode(ctx, d->part[JS_EC_PUB].p, d->part[JS_EC_PUB].n));
|
|
966
|
+
put(ctx, o, "kty", str(ctx, "OKP"));
|
|
967
|
+
} else {
|
|
968
|
+
size_t fs = js_ec_field_size(d->curve);
|
|
969
|
+
put(ctx, o, "kty", str(ctx, "EC"));
|
|
970
|
+
put(ctx, o, "x", base64url_encode(ctx, d->part[JS_EC_PUB].p + 1, fs));
|
|
971
|
+
put(ctx, o, "y", base64url_encode(ctx, d->part[JS_EC_PUB].p + 1 + fs, fs));
|
|
972
|
+
put(ctx, o, "crv", str(ctx, js_ec_curve_jwk(d->curve)));
|
|
973
|
+
if (priv) put(ctx, o, "d", base64url_encode(ctx, d->part[JS_EC_PRIV].p, d->part[JS_EC_PRIV].n));
|
|
974
|
+
}
|
|
975
|
+
return o;
|
|
976
|
+
}
|
|
977
|
+
char m[96];
|
|
978
|
+
snprintf(m, sizeof m, "Unable to export %s %s key using %s format", name, type, FORMATS[format]);
|
|
979
|
+
return dom_error(ctx, "NotSupportedError", m);
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
/* The usages of a mask among `wanted`, in that order (getUsagesUnion). */
|
|
983
|
+
static JSValue usages_union(JSContext *ctx, uint16_t mask, uint16_t wanted, uint16_t *out_mask) {
|
|
984
|
+
JSValue a = js_new_array(ctx, 2);
|
|
985
|
+
*out_mask = 0;
|
|
986
|
+
static const uint16_t ORDER[] = { JS_USAGE_ENCRYPT, JS_USAGE_DECRYPT, JS_USAGE_SIGN, JS_USAGE_VERIFY, JS_USAGE_DERIVE_KEY,
|
|
987
|
+
JS_USAGE_DERIVE_BITS, JS_USAGE_WRAP_KEY, JS_USAGE_UNWRAP_KEY };
|
|
988
|
+
for (int i = 0; i < 8; i++)
|
|
989
|
+
if (mask & wanted & ORDER[i]) {
|
|
990
|
+
if (js_array_append(ctx, a, str(ctx, USAGES[i])) < 0) return JS_EXCEPTION;
|
|
991
|
+
*out_mask |= ORDER[i];
|
|
992
|
+
}
|
|
993
|
+
return a;
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
static JSValue generate_asym(JSContext *ctx, Params *p, bool extractable, uint16_t mask) {
|
|
997
|
+
uint8_t alg = params_alg(p);
|
|
998
|
+
const char *name = p->name;
|
|
999
|
+
JSValue priv;
|
|
1000
|
+
if (is_rsa_alg(alg)) {
|
|
1001
|
+
const uint8_t *e = p->public_exponent.p;
|
|
1002
|
+
size_t en = p->public_exponent.n;
|
|
1003
|
+
while (en > 0 && e[0] == 0) e++, en--;
|
|
1004
|
+
if (en > 4) return dom_error(ctx, "OperationError", "The publicExponent must be equivalent to an unsigned 32-bit value");
|
|
1005
|
+
uint32_t exponent = 0;
|
|
1006
|
+
for (size_t i = 0; i < en; i++) exponent = exponent << 8 | e[i];
|
|
1007
|
+
uint16_t allowed = alg == JS_WEB_RSA_OAEP ? JS_USAGE_ENCRYPT | JS_USAGE_DECRYPT | JS_USAGE_WRAP_KEY | JS_USAGE_UNWRAP_KEY
|
|
1008
|
+
: JS_USAGE_SIGN | JS_USAGE_VERIFY;
|
|
1009
|
+
if (has_any_not_in(mask, allowed)) return dom_error(ctx, "SyntaxError", "Unsupported key usage for a RSA key");
|
|
1010
|
+
if (js_key_generate_rsa(ctx, false, p->modulus_length, exponent, &priv)) return op_failed(ctx);
|
|
1011
|
+
} else {
|
|
1012
|
+
int curve = BR_EC_curve25519;
|
|
1013
|
+
if (alg != JS_WEB_X25519) {
|
|
1014
|
+
curve = js_ec_curve_by_jwk(p->named_curve);
|
|
1015
|
+
if (curve < 0) return dom_error(ctx, "NotSupportedError", "Unrecognized namedCurve");
|
|
1016
|
+
}
|
|
1017
|
+
char m[64];
|
|
1018
|
+
snprintf(m, sizeof m, "Unsupported key usage for an %s key", name);
|
|
1019
|
+
if (has_any_not_in(mask, asym_usages(alg, true) | asym_usages(alg, false))) return dom_error(ctx, "SyntaxError", m);
|
|
1020
|
+
if (js_key_generate_ec(ctx, curve, &priv)) return op_failed(ctx);
|
|
1021
|
+
}
|
|
1022
|
+
uint16_t pub_mask, priv_mask;
|
|
1023
|
+
JSValue pub_usages = usages_union(ctx, mask, asym_usages(alg, true), &pub_mask);
|
|
1024
|
+
JSValue priv_usages = usages_union(ctx, mask, asym_usages(alg, false), &priv_mask);
|
|
1025
|
+
if (js_is_exception(pub_usages) || js_is_exception(priv_usages)) return JS_EXCEPTION;
|
|
1026
|
+
if (js_array_length(js_as_object(priv_usages)) == 0) return dom_error(ctx, "SyntaxError", "Usages cannot be empty when creating a key.");
|
|
1027
|
+
JSValue pub = js_key_public(ctx, priv);
|
|
1028
|
+
JSValue pair = js_new_object(ctx);
|
|
1029
|
+
put(ctx, pair, "publicKey", asym_crypto_key(ctx, pub, alg, name, p->hash, pub_usages, pub_mask, true));
|
|
1030
|
+
put(ctx, pair, "privateKey", asym_crypto_key(ctx, priv, alg, name, p->hash, priv_usages, priv_mask, extractable));
|
|
1031
|
+
return pair;
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
/* importKey's steps after the `this` check, for subtle.importKey and deriveKey. */
|
|
1035
|
+
static JSValue import_key(JSContext *ctx, uint32_t argc, const JSValue *argv) {
|
|
1036
|
+
Call c = { ctx, "importKey" };
|
|
1037
|
+
if (argc < 4) return throw_missing_args(&c, 4, argc);
|
|
1038
|
+
int format = arg_format(&c, argv[0], 0);
|
|
1039
|
+
if (format < 0) return JS_EXCEPTION;
|
|
1040
|
+
JWK jwk;
|
|
1041
|
+
if (format == FORMAT_JWK ? arg_jwk(&c, argv[1], &jwk) < 0 : arg_buffer_source(&c, argv[1], 1) < 0) return JS_EXCEPTION;
|
|
1042
|
+
if (arg_algorithm(&c, argv[2], 2) < 0) return JS_EXCEPTION;
|
|
1043
|
+
bool extractable = js_truthy(argv[3]);
|
|
1044
|
+
uint16_t mask;
|
|
1045
|
+
JSValue usages = arg_usages(&c, ARG(4), 4, &mask);
|
|
1046
|
+
if (js_is_exception(usages)) return usages;
|
|
1047
|
+
Params p;
|
|
1048
|
+
if (normalize(ctx, argv[2], OP_IMPORT_KEY, &p) < 0) {
|
|
1049
|
+
params_free(&p);
|
|
1050
|
+
return JS_EXCEPTION;
|
|
1051
|
+
}
|
|
1052
|
+
JSValue key;
|
|
1053
|
+
switch (REGISTRY[p.entry].alg) {
|
|
1054
|
+
case JS_WEB_HMAC:
|
|
1055
|
+
key = import_hmac(ctx, format, argv[1], &jwk, &p, extractable, usages, mask);
|
|
1056
|
+
break;
|
|
1057
|
+
case JS_WEB_AES_CTR:
|
|
1058
|
+
case JS_WEB_AES_CBC:
|
|
1059
|
+
case JS_WEB_AES_GCM:
|
|
1060
|
+
case JS_WEB_AES_KW:
|
|
1061
|
+
key = import_aes(ctx, format, argv[1], &jwk, &p, extractable, usages, mask);
|
|
1062
|
+
break;
|
|
1063
|
+
case JS_WEB_RSASSA:
|
|
1064
|
+
case JS_WEB_RSA_PSS:
|
|
1065
|
+
case JS_WEB_RSA_OAEP:
|
|
1066
|
+
case JS_WEB_ECDSA:
|
|
1067
|
+
case JS_WEB_ECDH:
|
|
1068
|
+
case JS_WEB_X25519:
|
|
1069
|
+
key = import_asym(ctx, format, argv[1], &jwk, &p, extractable, usages, mask);
|
|
1070
|
+
break;
|
|
1071
|
+
default:
|
|
1072
|
+
key = import_generic_secret(ctx, format, argv[1], &p, extractable, usages, mask);
|
|
1073
|
+
break;
|
|
1074
|
+
}
|
|
1075
|
+
params_free(&p);
|
|
1076
|
+
if (js_is_exception(key)) return key;
|
|
1077
|
+
JSCryptoKey *k = js_as_crypto_key(key);
|
|
1078
|
+
uint8_t type = js_key_data(k->data)->type;
|
|
1079
|
+
if (type != JS_KEY_PUBLIC && js_array_length(js_as_object(k->usages)) == 0)
|
|
1080
|
+
return dom_error(ctx, "SyntaxError", type == JS_KEY_SECRET ? "Usages cannot be empty when importing a secret key."
|
|
1081
|
+
: "Usages cannot be empty when importing a private key.");
|
|
1082
|
+
return key;
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
JSValue js_crypto_import_key_steps(JSContext *ctx, uint32_t argc, const JSValue *argv) { return import_key(ctx, argc, argv); }
|
|
1086
|
+
|
|
1087
|
+
BUILTIN(subtle_import_key) {
|
|
1088
|
+
(void)callee, (void)new_target;
|
|
1089
|
+
if (!is_subtle(this_val)) return rejected(ctx, js_throw_invalid_this(ctx, "SubtleCrypto"));
|
|
1090
|
+
return settled(ctx, import_key(ctx, argc, argv));
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
static JSValue export_key(JSContext *ctx, uint32_t argc, const JSValue *argv) {
|
|
1094
|
+
Call c = { ctx, "exportKey" };
|
|
1095
|
+
if (argc < 2) return throw_missing_args(&c, 2, argc);
|
|
1096
|
+
int format = arg_format(&c, argv[0], 0);
|
|
1097
|
+
if (format < 0) return JS_EXCEPTION;
|
|
1098
|
+
JSCryptoKey *k = arg_key(&c, argv[1], 1);
|
|
1099
|
+
if (!k) return JS_EXCEPTION;
|
|
1100
|
+
char m[96];
|
|
1101
|
+
if (k->alg == JS_WEB_PBKDF2 || k->alg == JS_WEB_HKDF) {
|
|
1102
|
+
snprintf(m, sizeof m, "%s key export is not supported", k->alg == JS_WEB_PBKDF2 ? "PBKDF2" : "HKDF");
|
|
1103
|
+
return dom_error(ctx, "NotSupportedError", m);
|
|
1104
|
+
}
|
|
1105
|
+
if (!k->extractable) return dom_error(ctx, "InvalidAccessException", "key is not extractable");
|
|
1106
|
+
if (is_asym_alg(k->alg)) return export_asym(ctx, format, k);
|
|
1107
|
+
JSKeyData *d = js_key_data(k->data);
|
|
1108
|
+
if (format == FORMAT_RAW) return array_buffer_of(ctx, d->bytes, d->len);
|
|
1109
|
+
if (format == FORMAT_JWK) {
|
|
1110
|
+
JSValue o = js_new_object(ctx);
|
|
1111
|
+
put(ctx, o, "key_ops", k->usages);
|
|
1112
|
+
put(ctx, o, "ext", js_bool(k->extractable));
|
|
1113
|
+
char alg[16];
|
|
1114
|
+
jwk_alg(k->alg, k->hash, k->length, alg, sizeof alg);
|
|
1115
|
+
put(ctx, o, "alg", str(ctx, alg));
|
|
1116
|
+
put(ctx, o, "kty", str(ctx, "oct"));
|
|
1117
|
+
put(ctx, o, "k", base64url_encode(ctx, d->bytes, d->len));
|
|
1118
|
+
return o;
|
|
1119
|
+
}
|
|
1120
|
+
snprintf(m, sizeof m, "Unable to export %s secret key using %s format", web_alg_name(k->alg), FORMATS[format]);
|
|
1121
|
+
return dom_error(ctx, "NotSupportedError", m);
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
BUILTIN(subtle_export_key) {
|
|
1125
|
+
(void)callee, (void)new_target;
|
|
1126
|
+
if (!is_subtle(this_val)) return rejected(ctx, js_throw_invalid_this(ctx, "SubtleCrypto"));
|
|
1127
|
+
return settled(ctx, export_key(ctx, argc, argv));
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
static JSValue generate_key(JSContext *ctx, uint32_t argc, const JSValue *argv) {
|
|
1131
|
+
Call c = { ctx, "generateKey" };
|
|
1132
|
+
if (argc < 3) return throw_missing_args(&c, 3, argc);
|
|
1133
|
+
if (arg_algorithm(&c, argv[0], 0) < 0) return JS_EXCEPTION;
|
|
1134
|
+
bool extractable = js_truthy(argv[1]);
|
|
1135
|
+
uint16_t mask;
|
|
1136
|
+
JSValue given = arg_usages(&c, argv[2], 2, &mask);
|
|
1137
|
+
if (js_is_exception(given)) return given;
|
|
1138
|
+
Params p;
|
|
1139
|
+
int r = normalize(ctx, argv[0], OP_GENERATE_KEY, &p);
|
|
1140
|
+
if (r == 0 && is_asym_alg(params_alg(&p))) {
|
|
1141
|
+
JSValue pair = generate_asym(ctx, &p, extractable, mask);
|
|
1142
|
+
params_free(&p);
|
|
1143
|
+
return pair;
|
|
1144
|
+
}
|
|
1145
|
+
params_free(&p);
|
|
1146
|
+
if (r < 0) return JS_EXCEPTION;
|
|
1147
|
+
uint8_t alg = params_alg(&p);
|
|
1148
|
+
uint32_t length;
|
|
1149
|
+
if (alg == JS_WEB_HMAC) {
|
|
1150
|
+
length = p.has_length ? p.length : (uint32_t)p.hash->block_len * 8;
|
|
1151
|
+
if (has_any_not_in(mask, JS_USAGE_SIGN | JS_USAGE_VERIFY)) return dom_error(ctx, "SyntaxError", "Unsupported key usage for an HMAC key");
|
|
1152
|
+
if (length == 0) return dom_error(ctx, "DataError", "Zero-length key is not supported");
|
|
1153
|
+
if (length % 8) return dom_error(ctx, "NotSupportedError", "Unsupported algorithm.length");
|
|
1154
|
+
} else {
|
|
1155
|
+
length = p.length;
|
|
1156
|
+
if (length != 128 && length != 192 && length != 256)
|
|
1157
|
+
return dom_error(ctx, "OperationError", "AES key length must be 128, 192, or 256 bits");
|
|
1158
|
+
if (has_any_not_in(mask, aes_usages(alg))) return dom_error(ctx, "SyntaxError", "Unsupported key usage for an AES key");
|
|
1159
|
+
}
|
|
1160
|
+
JSValue usages = usages_array(ctx, given);
|
|
1161
|
+
if (js_is_exception(usages)) return usages;
|
|
1162
|
+
uint8_t *bytes = malloc(length / 8);
|
|
1163
|
+
if (!bytes) js_fatal("out of memory in crypto");
|
|
1164
|
+
js_crypto_random(bytes, length / 8);
|
|
1165
|
+
JSValue data = js_new_secret_key(ctx, bytes, length / 8);
|
|
1166
|
+
free(bytes);
|
|
1167
|
+
if (js_array_length(js_as_object(usages)) == 0) return dom_error(ctx, "SyntaxError", "Usages cannot be empty when creating a key.");
|
|
1168
|
+
JSValue algorithm = alg == JS_WEB_HMAC ? hmac_algorithm(ctx, p.hash, length, true) : aes_algorithm(ctx, p.name, length);
|
|
1169
|
+
return js_new_crypto_key(ctx, data, alg, p.hash, length, algorithm, usages, mask, extractable);
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
BUILTIN(subtle_generate_key) {
|
|
1173
|
+
(void)callee, (void)new_target;
|
|
1174
|
+
if (!is_subtle(this_val)) return rejected(ctx, js_throw_invalid_this(ctx, "SubtleCrypto"));
|
|
1175
|
+
return settled(ctx, generate_key(ctx, argc, argv));
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
/* ---- sign and verify --------------------------------------------------------------------------- */
|
|
1179
|
+
|
|
1180
|
+
static JSValue sign_verify(JSContext *ctx, uint32_t argc, const JSValue *argv, bool verify) {
|
|
1181
|
+
Call c = { ctx, verify ? "verify" : "sign" };
|
|
1182
|
+
uint32_t need = verify ? 4 : 3;
|
|
1183
|
+
if (argc < need) return throw_missing_args(&c, need, argc);
|
|
1184
|
+
if (arg_algorithm(&c, argv[0], 0) < 0) return JS_EXCEPTION;
|
|
1185
|
+
JSCryptoKey *k = arg_key(&c, argv[1], 1);
|
|
1186
|
+
if (!k) return JS_EXCEPTION;
|
|
1187
|
+
if (arg_buffer_source(&c, argv[2], 2) < 0 || (verify && arg_buffer_source(&c, argv[3], 3) < 0)) return JS_EXCEPTION;
|
|
1188
|
+
Params p;
|
|
1189
|
+
int r = normalize(ctx, argv[0], verify ? OP_VERIFY : OP_SIGN, &p);
|
|
1190
|
+
params_free(&p);
|
|
1191
|
+
if (r < 0) return JS_EXCEPTION;
|
|
1192
|
+
if (!(k->usage_mask & (verify ? JS_USAGE_VERIFY : JS_USAGE_SIGN)) || REGISTRY[p.entry].alg != k->alg)
|
|
1193
|
+
return dom_error(ctx, "InvalidAccessError", verify ? "Unable to use this key to verify" : "Unable to use this key to sign");
|
|
1194
|
+
JSKeyData *d = js_key_data(k->data);
|
|
1195
|
+
if (is_asym_alg(k->alg)) { /* RSASSA-PKCS1-v1_5, RSA-PSS (the key's hash), ECDSA (the params', P1363 signatures) */
|
|
1196
|
+
const JSHashAlg *h = k->alg == JS_WEB_ECDSA ? p.hash : k->hash;
|
|
1197
|
+
int padding = k->alg == JS_WEB_RSA_PSS ? JS_PADDING_PSS : JS_PADDING_PKCS1;
|
|
1198
|
+
Bytes data;
|
|
1199
|
+
bytes_copy(&data, argv[verify ? 3 : 2]);
|
|
1200
|
+
uint8_t digest[64];
|
|
1201
|
+
js_hash_once(h, data.p, data.n, digest);
|
|
1202
|
+
bytes_free(&data);
|
|
1203
|
+
if (!verify) {
|
|
1204
|
+
JSBytesOut out = { 0 };
|
|
1205
|
+
if (js_asym_sign(d, h, digest, padding, (long)p.salt_length, true, &out)) return op_failed(ctx);
|
|
1206
|
+
JSValue sig = array_buffer_of(ctx, out.p, out.n);
|
|
1207
|
+
free(out.p);
|
|
1208
|
+
return sig;
|
|
1209
|
+
}
|
|
1210
|
+
uint8_t *sig;
|
|
1211
|
+
size_t sn;
|
|
1212
|
+
js_buffer_source_bytes(argv[2], &sig, &sn);
|
|
1213
|
+
bool valid;
|
|
1214
|
+
if (js_asym_verify(d, h, digest, padding, (long)p.salt_length, true, sig, sn, &valid)) return op_failed(ctx);
|
|
1215
|
+
return js_bool(valid);
|
|
1216
|
+
}
|
|
1217
|
+
/* HMAC */
|
|
1218
|
+
Bytes data;
|
|
1219
|
+
bytes_copy(&data, argv[verify ? 3 : 2]);
|
|
1220
|
+
uint8_t mac[64];
|
|
1221
|
+
JSHmacCtx m;
|
|
1222
|
+
js_hmac_init(&m, k->hash, d->bytes, d->len);
|
|
1223
|
+
js_hmac_update(&m, data.p, data.n);
|
|
1224
|
+
js_hmac_final(&m, mac);
|
|
1225
|
+
bytes_free(&data);
|
|
1226
|
+
if (!verify) return array_buffer_of(ctx, mac, k->hash->out_len);
|
|
1227
|
+
uint8_t *sig;
|
|
1228
|
+
size_t n;
|
|
1229
|
+
js_buffer_source_bytes(argv[2], &sig, &n);
|
|
1230
|
+
return js_bool(n == k->hash->out_len && js_crypto_equal(sig, mac, n));
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
BUILTIN(subtle_sign) {
|
|
1234
|
+
(void)callee, (void)new_target;
|
|
1235
|
+
if (!is_subtle(this_val)) return rejected(ctx, js_throw_invalid_this(ctx, "SubtleCrypto"));
|
|
1236
|
+
return settled(ctx, sign_verify(ctx, argc, argv, false));
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
BUILTIN(subtle_verify) {
|
|
1240
|
+
(void)callee, (void)new_target;
|
|
1241
|
+
if (!is_subtle(this_val)) return rejected(ctx, js_throw_invalid_this(ctx, "SubtleCrypto"));
|
|
1242
|
+
return settled(ctx, sign_verify(ctx, argc, argv, true));
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
/* ---- deriveBits and deriveKey ------------------------------------------------------------------ */
|
|
1246
|
+
|
|
1247
|
+
/* WebIDL's unsigned long (no [EnforceRange]): modulo 2^32. */
|
|
1248
|
+
static int to_ulong(JSContext *ctx, JSValue v, uint32_t *out) {
|
|
1249
|
+
double x;
|
|
1250
|
+
if (js_to_number(ctx, &x, v) < 0) return -1;
|
|
1251
|
+
if (!isfinite(x) || x == 0) {
|
|
1252
|
+
*out = 0;
|
|
1253
|
+
return 0;
|
|
1254
|
+
}
|
|
1255
|
+
x = fmod(trunc(x), 4294967296.0);
|
|
1256
|
+
if (x < 0) x += 4294967296.0;
|
|
1257
|
+
*out = (uint32_t)x;
|
|
1258
|
+
return 0;
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
/* ECDH's and X25519's bits: the shared secret, or its first `length` bits (in whole bytes, the rest zero). */
|
|
1262
|
+
static JSValue ecdh_bits(JSContext *ctx, Params *p, JSCryptoKey *k, bool has_length, uint32_t length) {
|
|
1263
|
+
JSCryptoKey *pub = p->public_key;
|
|
1264
|
+
JSKeyData *pd = js_key_data(pub->data), *d = js_key_data(k->data);
|
|
1265
|
+
char m[64];
|
|
1266
|
+
if (pd->type != JS_KEY_PUBLIC) return dom_error(ctx, "InvalidAccessError", "algorithm.public must be a public key");
|
|
1267
|
+
if (pub->alg != k->alg) {
|
|
1268
|
+
snprintf(m, sizeof m, "algorithm.public must be an %s key", web_alg_name(k->alg));
|
|
1269
|
+
return dom_error(ctx, "InvalidAccessError", m);
|
|
1270
|
+
}
|
|
1271
|
+
if (pd->curve != d->curve) return dom_error(ctx, "InvalidAccessError", "Named curve mismatch");
|
|
1272
|
+
uint8_t secret[66];
|
|
1273
|
+
size_t n;
|
|
1274
|
+
if (js_ecdh(d, pd->part[JS_EC_PUB].p, pd->part[JS_EC_PUB].n, secret, &n)) return op_failed(ctx);
|
|
1275
|
+
if (has_length) {
|
|
1276
|
+
size_t want = (length + 7) / 8;
|
|
1277
|
+
if (want > n) return dom_error(ctx, "OperationError", "derived bit length is too small");
|
|
1278
|
+
n = want;
|
|
1279
|
+
if (length % 8) secret[n - 1] &= (uint8_t)(0xFF << (8 - length % 8)); /* the bits past the length, zeroed */
|
|
1280
|
+
}
|
|
1281
|
+
return array_buffer_of(ctx, secret, n);
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
/* The bits of a derivation (`has_length` false: null). */
|
|
1285
|
+
static JSValue derive_bits(JSContext *ctx, Params *p, JSCryptoKey *k, bool has_length, uint32_t length) {
|
|
1286
|
+
if (k->alg == JS_WEB_ECDH || k->alg == JS_WEB_X25519) return ecdh_bits(ctx, p, k, has_length, length);
|
|
1287
|
+
JSKeyData *d = js_key_data(k->data);
|
|
1288
|
+
if (k->alg == JS_WEB_PBKDF2 && p->iterations == 0) return dom_error(ctx, "OperationError", "iterations cannot be zero");
|
|
1289
|
+
if (has_length && length == 0) return js_new_array_buffer(ctx, 0);
|
|
1290
|
+
if (!has_length) return dom_error(ctx, "OperationError", "length cannot be null");
|
|
1291
|
+
if (length % 8) return dom_error(ctx, "OperationError", "length must be a multiple of 8");
|
|
1292
|
+
size_t n = length / 8;
|
|
1293
|
+
uint8_t *out = malloc(n);
|
|
1294
|
+
if (!out) return dom_error(ctx, "OperationError", "The operation failed for an operation-specific reason");
|
|
1295
|
+
bool ok = k->alg == JS_WEB_PBKDF2 ? js_pbkdf2(p->hash, d->bytes, d->len, p->salt.p, p->salt.n, p->iterations, out, n)
|
|
1296
|
+
: js_hkdf(p->hash, d->bytes, d->len, p->salt.p, p->salt.n, p->info.p, p->info.n, out, n);
|
|
1297
|
+
JSValue r = ok ? array_buffer_of(ctx, out, n) : dom_error(ctx, "OperationError", "The operation failed for an operation-specific reason");
|
|
1298
|
+
free(out);
|
|
1299
|
+
return r;
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
static JSValue subtle_derive_bits_steps(JSContext *ctx, uint32_t argc, const JSValue *argv) {
|
|
1303
|
+
Call c = { ctx, "deriveBits" };
|
|
1304
|
+
if (argc < 2) return throw_missing_args(&c, 2, argc);
|
|
1305
|
+
if (arg_algorithm(&c, argv[0], 0) < 0) return JS_EXCEPTION;
|
|
1306
|
+
JSCryptoKey *k = arg_key(&c, argv[1], 1);
|
|
1307
|
+
if (!k) return JS_EXCEPTION;
|
|
1308
|
+
bool has_length = argc > 2 && !js_is_nullish(argv[2]);
|
|
1309
|
+
uint32_t length = 0;
|
|
1310
|
+
if (has_length && to_ulong(ctx, argv[2], &length) < 0) return JS_EXCEPTION;
|
|
1311
|
+
Params p;
|
|
1312
|
+
if (normalize(ctx, argv[0], OP_DERIVE_BITS, &p) < 0) {
|
|
1313
|
+
params_free(&p);
|
|
1314
|
+
return JS_EXCEPTION;
|
|
1315
|
+
}
|
|
1316
|
+
JSValue r;
|
|
1317
|
+
if (!(k->usage_mask & JS_USAGE_DERIVE_BITS)) r = dom_error(ctx, "InvalidAccessError", "baseKey does not have deriveBits usage");
|
|
1318
|
+
else if (REGISTRY[p.entry].alg != k->alg) r = dom_error(ctx, "InvalidAccessError", "Key algorithm mismatch");
|
|
1319
|
+
else r = derive_bits(ctx, &p, k, has_length, length);
|
|
1320
|
+
params_free(&p);
|
|
1321
|
+
return r;
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
BUILTIN(subtle_derive_bits) {
|
|
1325
|
+
(void)callee, (void)new_target;
|
|
1326
|
+
if (!is_subtle(this_val)) return rejected(ctx, js_throw_invalid_this(ctx, "SubtleCrypto"));
|
|
1327
|
+
return settled(ctx, subtle_derive_bits_steps(ctx, argc, argv));
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
static JSValue derive_key(JSContext *ctx, uint32_t argc, const JSValue *argv) {
|
|
1331
|
+
Call c = { ctx, "deriveKey" };
|
|
1332
|
+
if (argc < 5) return throw_missing_args(&c, 5, argc);
|
|
1333
|
+
if (arg_algorithm(&c, argv[0], 0) < 0) return JS_EXCEPTION;
|
|
1334
|
+
JSCryptoKey *k = arg_key(&c, argv[1], 1);
|
|
1335
|
+
if (!k) return JS_EXCEPTION;
|
|
1336
|
+
if (arg_algorithm(&c, argv[2], 2) < 0) return JS_EXCEPTION;
|
|
1337
|
+
uint16_t mask;
|
|
1338
|
+
JSValue usages = arg_usages(&c, argv[4], 4, &mask);
|
|
1339
|
+
if (js_is_exception(usages)) return usages;
|
|
1340
|
+
Params p, derived, len;
|
|
1341
|
+
memset(&derived, 0, sizeof derived);
|
|
1342
|
+
memset(&len, 0, sizeof len);
|
|
1343
|
+
JSValue r = JS_EXCEPTION;
|
|
1344
|
+
if (normalize(ctx, argv[0], OP_DERIVE_BITS, &p) < 0 || normalize(ctx, argv[2], OP_IMPORT_KEY, &derived) < 0) goto done;
|
|
1345
|
+
if (!(k->usage_mask & JS_USAGE_DERIVE_KEY)) {
|
|
1346
|
+
r = dom_error(ctx, "InvalidAccessError", "baseKey does not have deriveKey usage");
|
|
1347
|
+
goto done;
|
|
1348
|
+
}
|
|
1349
|
+
if (REGISTRY[p.entry].alg != k->alg) {
|
|
1350
|
+
r = dom_error(ctx, "InvalidAccessError", "Key algorithm mismatch");
|
|
1351
|
+
goto done;
|
|
1352
|
+
}
|
|
1353
|
+
if (normalize(ctx, argv[2], OP_GET_KEY_LENGTH, &len) < 0) goto done;
|
|
1354
|
+
/* getKeyLength: HMAC's (its block size by default; 0 makes an empty key, which import rejects); null for PBKDF2 and HKDF */
|
|
1355
|
+
bool has_length = false;
|
|
1356
|
+
uint32_t length = 0;
|
|
1357
|
+
if (params_alg(&len) == JS_WEB_HMAC) {
|
|
1358
|
+
length = len.has_length ? len.length : (uint32_t)len.hash->block_len * 8;
|
|
1359
|
+
has_length = true;
|
|
1360
|
+
} else if (is_aes(params_alg(&len))) {
|
|
1361
|
+
if (len.length != 128 && len.length != 192 && len.length != 256) {
|
|
1362
|
+
r = dom_error(ctx, "OperationError", "AES key length must be 128, 192, or 256 bits");
|
|
1363
|
+
goto done;
|
|
1364
|
+
}
|
|
1365
|
+
length = len.length;
|
|
1366
|
+
has_length = true;
|
|
1367
|
+
}
|
|
1368
|
+
JSValue bits = derive_bits(ctx, &p, k, has_length, length);
|
|
1369
|
+
if (js_is_exception(bits)) goto done;
|
|
1370
|
+
JSValue args[5] = { str(ctx, "raw"), bits, argv[2], argv[3], argv[4] };
|
|
1371
|
+
r = import_key(ctx, 5, args);
|
|
1372
|
+
done:
|
|
1373
|
+
params_free(&p);
|
|
1374
|
+
params_free(&derived);
|
|
1375
|
+
params_free(&len);
|
|
1376
|
+
return r;
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
BUILTIN(subtle_derive_key) {
|
|
1380
|
+
(void)callee, (void)new_target;
|
|
1381
|
+
if (!is_subtle(this_val)) return rejected(ctx, js_throw_invalid_this(ctx, "SubtleCrypto"));
|
|
1382
|
+
return settled(ctx, derive_key(ctx, argc, argv));
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
/* ---- digest, and the operations no algorithm here supports yet -------------------------------- */
|
|
1386
|
+
|
|
1387
|
+
BUILTIN(subtle_digest) {
|
|
1388
|
+
(void)callee, (void)new_target;
|
|
1389
|
+
if (!is_subtle(this_val)) return rejected(ctx, js_throw_invalid_this(ctx, "SubtleCrypto"));
|
|
1390
|
+
Call c = { ctx, "digest" };
|
|
1391
|
+
if (argc < 2) return rejected(ctx, throw_missing_args(&c, 2, argc));
|
|
1392
|
+
if (arg_algorithm(&c, argv[0], 0) < 0 || arg_buffer_source(&c, argv[1], 1) < 0) return rejected(ctx, JS_EXCEPTION);
|
|
1393
|
+
Params p;
|
|
1394
|
+
if (normalize(ctx, argv[0], OP_DIGEST, &p) < 0) return rejected(ctx, JS_EXCEPTION);
|
|
1395
|
+
/* the bytes now: converting the algorithm may have run code that changed them */
|
|
1396
|
+
uint8_t *data;
|
|
1397
|
+
size_t n;
|
|
1398
|
+
js_buffer_source_bytes(argv[1], &data, &n);
|
|
1399
|
+
uint8_t out[64];
|
|
1400
|
+
js_hash_once(p.hash, data, n, out);
|
|
1401
|
+
return settled(ctx, array_buffer_of(ctx, out, p.hash->out_len));
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
/* ---- encrypt, decrypt, wrapKey, unwrapKey ------------------------------------------------------- */
|
|
1405
|
+
|
|
1406
|
+
/* One whole run of an AES cipher context (CBC, GCM, key wrap): the output, or false. */
|
|
1407
|
+
static bool run_cipher(const JSCipherAlg *alg, bool encrypt, JSKeyData *d, const uint8_t *iv, size_t iv_len, long tag_len,
|
|
1408
|
+
const Bytes *aad, const uint8_t *tag, size_t tag_n, const uint8_t *in, size_t n, JSBytesOut *out) {
|
|
1409
|
+
JSCipherCtx c;
|
|
1410
|
+
bool ok = js_cipher_init(&c, alg, encrypt, d->bytes, d->len, iv, iv_len, true, tag_len) == 0;
|
|
1411
|
+
if (ok && aad && aad->n) ok = js_cipher_set_aad(&c, aad->p, aad->n, -1) == 0;
|
|
1412
|
+
if (ok && tag) ok = js_cipher_set_auth_tag(&c, tag, tag_n) == 0;
|
|
1413
|
+
if (ok) ok = js_cipher_update(&c, in, n, out) == 0 && js_cipher_final(&c, out) == 0;
|
|
1414
|
+
if (ok && encrypt && tag_len > 0) {
|
|
1415
|
+
const uint8_t *t;
|
|
1416
|
+
size_t tn;
|
|
1417
|
+
ok = js_cipher_get_auth_tag(&c, &t, &tn);
|
|
1418
|
+
if (ok) {
|
|
1419
|
+
JSBytesOut tmp = *out; /* append the tag */
|
|
1420
|
+
uint8_t *q = realloc(tmp.p, tmp.n + tn);
|
|
1421
|
+
if (!q) js_fatal("out of memory in crypto");
|
|
1422
|
+
memcpy(q + tmp.n, t, tn);
|
|
1423
|
+
out->p = q;
|
|
1424
|
+
out->n = tmp.n + tn;
|
|
1425
|
+
out->cap = out->n;
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
js_cipher_free(&c);
|
|
1429
|
+
return ok;
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
/* aesCipher: the operation on a copy of the data. */
|
|
1433
|
+
static JSValue aes_cipher(JSContext *ctx, bool encrypt, JSCryptoKey *k, Params *p, const Bytes *data) {
|
|
1434
|
+
JSKeyData *d = js_key_data(k->data);
|
|
1435
|
+
JSBytesOut out = { 0 };
|
|
1436
|
+
bool ok;
|
|
1437
|
+
switch (k->alg) {
|
|
1438
|
+
case JS_WEB_AES_CTR: {
|
|
1439
|
+
if (p->counter.n != 16) return dom_error(ctx, "OperationError", "algorithm.counter must contain exactly 16 bytes");
|
|
1440
|
+
if (p->length == 0 || p->length > 128) return dom_error(ctx, "OperationError", "AES-CTR algorithm.length must be between 1 and 128");
|
|
1441
|
+
uint8_t *o = malloc(data->n ? data->n : 1);
|
|
1442
|
+
if (!o) js_fatal("out of memory in crypto");
|
|
1443
|
+
ok = js_aes_ctr_masked(d->bytes, d->len, p->counter.p, p->length, data->p, data->n, o);
|
|
1444
|
+
JSValue r = ok ? array_buffer_of(ctx, o, data->n) : op_failed(ctx);
|
|
1445
|
+
free(o);
|
|
1446
|
+
return r;
|
|
1447
|
+
}
|
|
1448
|
+
case JS_WEB_AES_CBC:
|
|
1449
|
+
if (p->iv.n != 16) return dom_error(ctx, "OperationError", "algorithm.iv must contain exactly 16 bytes");
|
|
1450
|
+
ok = run_cipher(js_cipher_aes(JS_CIPHER_CBC, d->len), encrypt, d, p->iv.p, 16, -1, NULL, NULL, 0, data->p, data->n, &out);
|
|
1451
|
+
break;
|
|
1452
|
+
case JS_WEB_AES_GCM: {
|
|
1453
|
+
uint32_t tag_bits = p->has_tag_length ? p->tag_length : 128;
|
|
1454
|
+
if (tag_bits != 32 && tag_bits != 64 && tag_bits != 96 && (tag_bits < 104 || tag_bits > 128 || tag_bits % 8)) {
|
|
1455
|
+
char m[64];
|
|
1456
|
+
snprintf(m, sizeof m, "%u is not a valid AES-GCM tag length", tag_bits);
|
|
1457
|
+
return dom_error(ctx, "OperationError", m);
|
|
1458
|
+
}
|
|
1459
|
+
size_t tag_n = tag_bits / 8;
|
|
1460
|
+
if (!encrypt && data->n < tag_n) return dom_error(ctx, "OperationError", "The provided data is too small.");
|
|
1461
|
+
if (p->iv.n < 12) return op_failed(ctx);
|
|
1462
|
+
const JSCipherAlg *alg = js_cipher_aes(JS_CIPHER_GCM, d->len);
|
|
1463
|
+
ok = encrypt ? run_cipher(alg, true, d, p->iv.p, p->iv.n, (long)tag_n, &p->additional_data, NULL, 0, data->p, data->n, &out)
|
|
1464
|
+
: run_cipher(alg, false, d, p->iv.p, p->iv.n, (long)tag_n, &p->additional_data, data->p + data->n - tag_n, tag_n,
|
|
1465
|
+
data->p, data->n - tag_n, &out);
|
|
1466
|
+
break;
|
|
1467
|
+
}
|
|
1468
|
+
default: { /* AES-KW, with RFC 3394's default IV */
|
|
1469
|
+
static const uint8_t KW_IV[8] = { 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6 };
|
|
1470
|
+
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);
|
|
1471
|
+
break;
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
JSValue r = ok ? array_buffer_of(ctx, out.p ? out.p : (const uint8_t *)"", out.n) : op_failed(ctx);
|
|
1475
|
+
free(out.p);
|
|
1476
|
+
return r;
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
/* cipherOrWrap: the key must be for the algorithm and allow the use. */
|
|
1480
|
+
static JSValue cipher_or_wrap(JSContext *ctx, bool encrypt, Params *p, JSCryptoKey *k, const Bytes *data, uint16_t usage) {
|
|
1481
|
+
if (params_alg(p) != k->alg || !(k->usage_mask & usage))
|
|
1482
|
+
return dom_error(ctx, "InvalidAccessError", "The requested operation is not valid for the provided key");
|
|
1483
|
+
if (k->alg == JS_WEB_RSA_OAEP) { /* encrypting with the public key, decrypting with the private one */
|
|
1484
|
+
JSKeyData *d = js_key_data(k->data);
|
|
1485
|
+
if (d->type != (encrypt ? JS_KEY_PUBLIC : JS_KEY_PRIVATE))
|
|
1486
|
+
return dom_error(ctx, "InvalidAccessError", "The requested operation is not valid for the provided key");
|
|
1487
|
+
JSBytesOut out = { 0 };
|
|
1488
|
+
if (js_rsa_crypt(d, encrypt ? JS_RSA_PUBLIC_ENCRYPT : JS_RSA_PRIVATE_DECRYPT, JS_PADDING_OAEP, k->hash, p->label.p, p->label.n,
|
|
1489
|
+
data->p, data->n, &out))
|
|
1490
|
+
return op_failed(ctx);
|
|
1491
|
+
JSValue r = array_buffer_of(ctx, out.p ? out.p : (const uint8_t *)"", out.n);
|
|
1492
|
+
free(out.p);
|
|
1493
|
+
return r;
|
|
1494
|
+
}
|
|
1495
|
+
if (k->alg == JS_WEB_AES_KW && !(usage & (JS_USAGE_WRAP_KEY | JS_USAGE_UNWRAP_KEY)))
|
|
1496
|
+
return dom_error(ctx, "NotSupportedError", "Unrecognized algorithm name");
|
|
1497
|
+
return aes_cipher(ctx, encrypt, k, p, data);
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1500
|
+
static JSValue encrypt_decrypt(JSContext *ctx, uint32_t argc, const JSValue *argv, bool encrypt) {
|
|
1501
|
+
Call c = { ctx, encrypt ? "encrypt" : "decrypt" };
|
|
1502
|
+
if (argc < 3) return throw_missing_args(&c, 3, argc);
|
|
1503
|
+
if (arg_algorithm(&c, argv[0], 0) < 0) return JS_EXCEPTION;
|
|
1504
|
+
JSCryptoKey *k = arg_key(&c, argv[1], 1);
|
|
1505
|
+
if (!k || arg_buffer_source(&c, argv[2], 2) < 0) return JS_EXCEPTION;
|
|
1506
|
+
Params p;
|
|
1507
|
+
JSValue r = JS_EXCEPTION;
|
|
1508
|
+
if (normalize(ctx, argv[0], encrypt ? OP_ENCRYPT : OP_DECRYPT, &p) == 0) {
|
|
1509
|
+
Bytes data;
|
|
1510
|
+
bytes_copy(&data, argv[2]);
|
|
1511
|
+
r = cipher_or_wrap(ctx, encrypt, &p, k, &data, encrypt ? JS_USAGE_ENCRYPT : JS_USAGE_DECRYPT);
|
|
1512
|
+
bytes_free(&data);
|
|
1513
|
+
}
|
|
1514
|
+
params_free(&p);
|
|
1515
|
+
return r;
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1518
|
+
BUILTIN(subtle_encrypt) {
|
|
1519
|
+
(void)callee, (void)new_target;
|
|
1520
|
+
if (!is_subtle(this_val)) return rejected(ctx, js_throw_invalid_this(ctx, "SubtleCrypto"));
|
|
1521
|
+
return settled(ctx, encrypt_decrypt(ctx, argc, argv, true));
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
BUILTIN(subtle_decrypt) {
|
|
1525
|
+
(void)callee, (void)new_target;
|
|
1526
|
+
if (!is_subtle(this_val)) return rejected(ctx, js_throw_invalid_this(ctx, "SubtleCrypto"));
|
|
1527
|
+
return settled(ctx, encrypt_decrypt(ctx, argc, argv, false));
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1530
|
+
/* wrapKey's and unwrapKey's algorithm: normalized for the operation, else for encrypt (decrypt). */
|
|
1531
|
+
static int normalize_wrap(JSContext *ctx, JSValue alg, bool wrap, Params *p) {
|
|
1532
|
+
if (normalize(ctx, alg, wrap ? OP_WRAP_KEY : OP_UNWRAP_KEY, p) == 0) return 0;
|
|
1533
|
+
params_free(p);
|
|
1534
|
+
js_discard(js_take_exception(ctx));
|
|
1535
|
+
return normalize(ctx, alg, wrap ? OP_ENCRYPT : OP_DECRYPT, p);
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
static JSValue wrap_key(JSContext *ctx, uint32_t argc, const JSValue *argv) {
|
|
1539
|
+
Call c = { ctx, "wrapKey" };
|
|
1540
|
+
if (argc < 4) return throw_missing_args(&c, 4, argc);
|
|
1541
|
+
if (arg_format(&c, argv[0], 0) < 0) return JS_EXCEPTION;
|
|
1542
|
+
if (!arg_key(&c, argv[1], 1)) return JS_EXCEPTION;
|
|
1543
|
+
JSCryptoKey *wrapping = arg_key(&c, argv[2], 2);
|
|
1544
|
+
if (!wrapping || arg_algorithm(&c, argv[3], 3) < 0) return JS_EXCEPTION;
|
|
1545
|
+
Params p;
|
|
1546
|
+
JSValue r = JS_EXCEPTION;
|
|
1547
|
+
if (normalize_wrap(ctx, argv[3], true, &p) == 0) {
|
|
1548
|
+
JSValue exported = export_key(ctx, 2, argv);
|
|
1549
|
+
if (!js_is_exception(exported)) {
|
|
1550
|
+
Bytes data = { 0 };
|
|
1551
|
+
if (js_is_object(exported) && !js_is_array_buffer(exported)) { /* a JWK: its JSON, as UTF-8 */
|
|
1552
|
+
JSValue json = js_json_stringify(ctx, exported, JS_UNDEFINED, JS_UNDEFINED, NULL);
|
|
1553
|
+
if (js_is_exception(json)) goto out;
|
|
1554
|
+
JSStrView v = js_string_view(ctx, json);
|
|
1555
|
+
size_t n = js_view_to_utf8(v, NULL, 0);
|
|
1556
|
+
size_t padded = params_alg(&p) == JS_WEB_AES_KW && v.length % 8 ? n + 8 - v.length % 8 : n;
|
|
1557
|
+
data.p = malloc(padded ? padded : 1);
|
|
1558
|
+
if (!data.p) js_fatal("out of memory in crypto");
|
|
1559
|
+
js_view_to_utf8(v, (char *)data.p, n);
|
|
1560
|
+
memset(data.p + n, ' ', padded - n); /* AES-KW's whole blocks */
|
|
1561
|
+
data.n = padded;
|
|
1562
|
+
} else {
|
|
1563
|
+
bytes_copy(&data, exported);
|
|
1564
|
+
}
|
|
1565
|
+
r = cipher_or_wrap(ctx, true, &p, wrapping, &data, JS_USAGE_WRAP_KEY);
|
|
1566
|
+
bytes_free(&data);
|
|
1567
|
+
}
|
|
1568
|
+
}
|
|
1569
|
+
out:
|
|
1570
|
+
params_free(&p);
|
|
1571
|
+
return r;
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1574
|
+
BUILTIN(subtle_wrap_key) {
|
|
1575
|
+
(void)callee, (void)new_target;
|
|
1576
|
+
if (!is_subtle(this_val)) return rejected(ctx, js_throw_invalid_this(ctx, "SubtleCrypto"));
|
|
1577
|
+
return settled(ctx, wrap_key(ctx, argc, argv));
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1580
|
+
/* Whether bytes are well-formed UTF-8 (TextDecoder's fatal mode). */
|
|
1581
|
+
static bool valid_utf8(const uint8_t *p, size_t n) {
|
|
1582
|
+
for (size_t i = 0; i < n;) {
|
|
1583
|
+
uint8_t b = p[i];
|
|
1584
|
+
if (b < 0x80) {
|
|
1585
|
+
i++;
|
|
1586
|
+
continue;
|
|
1587
|
+
}
|
|
1588
|
+
size_t need;
|
|
1589
|
+
uint32_t cp, min;
|
|
1590
|
+
if (b >= 0xC2 && b <= 0xDF) need = 1, cp = b & 0x1Fu, min = 0x80;
|
|
1591
|
+
else if ((b & 0xF0) == 0xE0) need = 2, cp = b & 0x0Fu, min = 0x800;
|
|
1592
|
+
else if (b >= 0xF0 && b <= 0xF4) need = 3, cp = b & 0x07u, min = 0x10000;
|
|
1593
|
+
else return false;
|
|
1594
|
+
if (n - i <= need) return false;
|
|
1595
|
+
for (size_t k = 1; k <= need; k++) {
|
|
1596
|
+
if ((p[i + k] & 0xC0) != 0x80) return false;
|
|
1597
|
+
cp = cp << 6 | (p[i + k] & 0x3Fu);
|
|
1598
|
+
}
|
|
1599
|
+
if (cp < min || cp > 0x10FFFF || (cp >= 0xD800 && cp <= 0xDFFF)) return false;
|
|
1600
|
+
i += need + 1;
|
|
1601
|
+
}
|
|
1602
|
+
return true;
|
|
1603
|
+
}
|
|
1604
|
+
|
|
1605
|
+
static JSValue unwrap_key(JSContext *ctx, uint32_t argc, const JSValue *argv) {
|
|
1606
|
+
Call c = { ctx, "unwrapKey" };
|
|
1607
|
+
if (argc < 7) return throw_missing_args(&c, 7, argc);
|
|
1608
|
+
int format = arg_format(&c, argv[0], 0);
|
|
1609
|
+
if (format < 0 || arg_buffer_source(&c, argv[1], 1) < 0) return JS_EXCEPTION;
|
|
1610
|
+
JSCryptoKey *unwrapping = arg_key(&c, argv[2], 2);
|
|
1611
|
+
if (!unwrapping || arg_algorithm(&c, argv[3], 3) < 0 || arg_algorithm(&c, argv[4], 4) < 0) return JS_EXCEPTION;
|
|
1612
|
+
uint16_t mask;
|
|
1613
|
+
if (js_is_exception(arg_usages(&c, argv[6], 6, &mask))) return JS_EXCEPTION;
|
|
1614
|
+
Params p;
|
|
1615
|
+
JSValue r = JS_EXCEPTION;
|
|
1616
|
+
if (normalize_wrap(ctx, argv[3], false, &p) == 0) {
|
|
1617
|
+
Bytes wrapped;
|
|
1618
|
+
bytes_copy(&wrapped, argv[1]);
|
|
1619
|
+
JSValue key_data = cipher_or_wrap(ctx, false, &p, unwrapping, &wrapped, JS_USAGE_UNWRAP_KEY);
|
|
1620
|
+
bytes_free(&wrapped);
|
|
1621
|
+
if (!js_is_exception(key_data) && format == FORMAT_JWK) {
|
|
1622
|
+
JSArrayBuffer *b = js_as_array_buffer(key_data);
|
|
1623
|
+
JSValue text = valid_utf8(b->data, b->byte_length) ? js_decode_utf8_bytes(ctx, b->data, b->byte_length) : JS_EXCEPTION;
|
|
1624
|
+
key_data = js_is_exception(text) ? JS_EXCEPTION : js_json_parse(ctx, text);
|
|
1625
|
+
if (js_is_exception(key_data)) {
|
|
1626
|
+
if (js_has_exception(ctx)) js_discard(js_take_exception(ctx));
|
|
1627
|
+
key_data = dom_error(ctx, "DataError", "Invalid wrapped JWK key");
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
if (!js_is_exception(key_data)) {
|
|
1631
|
+
JSValue args[5] = { argv[0], key_data, argv[4], argv[5], argv[6] };
|
|
1632
|
+
r = import_key(ctx, 5, args);
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
params_free(&p);
|
|
1636
|
+
return r;
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1639
|
+
BUILTIN(subtle_unwrap_key) {
|
|
1640
|
+
(void)callee, (void)new_target;
|
|
1641
|
+
if (!is_subtle(this_val)) return rejected(ctx, js_throw_invalid_this(ctx, "SubtleCrypto"));
|
|
1642
|
+
return settled(ctx, unwrap_key(ctx, argc, argv));
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
/* ---- Realm ------------------------------------------------------------------------------------- */
|
|
1646
|
+
|
|
1647
|
+
BUILTIN(subtle_ctor) {
|
|
1648
|
+
UNUSED_ARGS;
|
|
1649
|
+
return js_throw_node_error(ctx, JS_TYPE_ERROR, "ERR_ILLEGAL_CONSTRUCTOR", "Illegal constructor");
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1652
|
+
static const JSBuiltin subtle_proto[] = { /* Node's order and lengths */
|
|
1653
|
+
WEBIDL_OPERATION("encrypt", subtle_encrypt, 3),
|
|
1654
|
+
WEBIDL_OPERATION("decrypt", subtle_decrypt, 3),
|
|
1655
|
+
WEBIDL_OPERATION("sign", subtle_sign, 3),
|
|
1656
|
+
WEBIDL_OPERATION("verify", subtle_verify, 4),
|
|
1657
|
+
WEBIDL_OPERATION("digest", subtle_digest, 2),
|
|
1658
|
+
WEBIDL_OPERATION("generateKey", subtle_generate_key, 3),
|
|
1659
|
+
WEBIDL_OPERATION("deriveKey", subtle_derive_key, 5),
|
|
1660
|
+
WEBIDL_OPERATION("deriveBits", subtle_derive_bits, 2),
|
|
1661
|
+
WEBIDL_OPERATION("importKey", subtle_import_key, 5),
|
|
1662
|
+
WEBIDL_OPERATION("exportKey", subtle_export_key, 2),
|
|
1663
|
+
WEBIDL_OPERATION("wrapKey", subtle_wrap_key, 4),
|
|
1664
|
+
WEBIDL_OPERATION("unwrapKey", subtle_unwrap_key, 7),
|
|
1665
|
+
};
|
|
1666
|
+
|
|
1667
|
+
void js_crypto_install_subtle(JSContext *ctx, JSObject *global) {
|
|
1668
|
+
js_define_web_class(ctx, global, "SubtleCrypto", subtle_ctor, 0, ctx->intrinsics[JS_INTRINSIC_OBJECT_PROTOTYPE],
|
|
1669
|
+
JS_INTRINSIC_SUBTLE_CRYPTO_PROTOTYPE);
|
|
1670
|
+
JSValue sp = ctx->intrinsics[JS_INTRINSIC_SUBTLE_CRYPTO_PROTOTYPE];
|
|
1671
|
+
js_define_builtins(ctx, js_as_object(sp), subtle_proto, JS_COUNTOF(subtle_proto));
|
|
1672
|
+
js_define_data(ctx, js_as_object(sp), JS_SYMBOL(toStringTag), str(ctx, "SubtleCrypto"), JS_PROP_CONFIGURABLE);
|
|
1673
|
+
ctx->intrinsics[JS_INTRINSIC_SUBTLE_CRYPTO] =
|
|
1674
|
+
js_object_value(js_alloc_object(ctx, JS_CELL_OBJECT, js_shape_root(ctx, &subtle_class, sp, 0)));
|
|
1675
|
+
}
|