]> git.kaiwu.me - njs.git/commitdiff
WebCrypto: module is rewritten using public API.
authorDmitry Volyntsev <xeioex@nginx.com>
Wed, 3 May 2023 03:50:57 +0000 (20:50 -0700)
committerDmitry Volyntsev <xeioex@nginx.com>
Wed, 3 May 2023 03:50:57 +0000 (20:50 -0700)
external/njs_webcrypto_module.c
src/njs.h
src/njs_iterator.h
src/njs_vm.c
test/harness/runTsuite.js

index 2c738498b60c703f185a7bcd948c26b6ab5f5675..9e250bd2ad746891340c9522dd9dc701aa3cfadc 100644 (file)
@@ -5,7 +5,9 @@
  */
 
 
-#include <njs_main.h>
+#include <njs.h>
+#include <njs_assert.h>
+#include <njs_string.h>
 #include "njs_openssl.h"
 
 typedef enum {
@@ -126,7 +128,8 @@ static njs_webcrypto_key_format_t njs_key_format(njs_vm_t *vm,
 static njs_str_t *njs_format_string(njs_webcrypto_key_format_t fmt);
 static njs_int_t njs_key_usage(njs_vm_t *vm, njs_value_t *value,
     unsigned *mask);
-static njs_int_t njs_key_ops(njs_vm_t *vm, njs_value_t *retval, unsigned mask);
+static njs_int_t njs_key_ops(njs_vm_t *vm, njs_opaque_value_t *retval,
+    unsigned mask);
 static njs_webcrypto_algorithm_t *njs_key_algorithm(njs_vm_t *vm,
     njs_value_t *value);
 static njs_str_t *njs_algorithm_string(njs_webcrypto_algorithm_t *algorithm);
@@ -136,7 +139,7 @@ static const EVP_MD *njs_algorithm_hash_digest(njs_webcrypto_hash_t hash);
 static njs_int_t njs_algorithm_curve(njs_vm_t *vm, njs_value_t *value,
     int *curve);
 
-static njs_int_t njs_webcrypto_result(njs_vm_t *vm, njs_value_t *result,
+static njs_int_t njs_webcrypto_result(njs_vm_t *vm, njs_opaque_value_t *result,
     njs_int_t rc, njs_value_t *retval);
 static njs_int_t njs_webcrypto_array_buffer(njs_vm_t *vm, njs_value_t *retval,
     u_char *start, size_t length);
@@ -593,23 +596,23 @@ njs_module_t  njs_webcrypto_module = {
 };
 
 
-static const njs_value_t  string_alg = njs_string("alg");
-static const njs_value_t  string_d = njs_string("d");
-static const njs_value_t  string_dp = njs_string("dp");
-static const njs_value_t  string_dq = njs_string("dq");
-static const njs_value_t  string_e = njs_string("e");
-static const njs_value_t  string_k = njs_string("k");
-static const njs_value_t  string_n = njs_string("n");
-static const njs_value_t  string_p = njs_string("p");
-static const njs_value_t  string_q = njs_string("q");
-static const njs_value_t  string_qi = njs_string("qi");
-static const njs_value_t  string_x = njs_string("x");
-static const njs_value_t  string_y = njs_string("y");
-static const njs_value_t  string_ext = njs_string("ext");
-static const njs_value_t  string_crv = njs_string("crv");
-static const njs_value_t  string_kty = njs_string("kty");
-static const njs_value_t  key_ops = njs_string("key_ops");
-static const njs_value_t  string_length = njs_string("length");
+static const njs_str_t  string_alg = njs_str("alg");
+static const njs_str_t  string_d = njs_str("d");
+static const njs_str_t  string_dp = njs_str("dp");
+static const njs_str_t  string_dq = njs_str("dq");
+static const njs_str_t  string_e = njs_str("e");
+static const njs_str_t  string_k = njs_str("k");
+static const njs_str_t  string_n = njs_str("n");
+static const njs_str_t  string_p = njs_str("p");
+static const njs_str_t  string_q = njs_str("q");
+static const njs_str_t  string_qi = njs_str("qi");
+static const njs_str_t  string_x = njs_str("x");
+static const njs_str_t  string_y = njs_str("y");
+static const njs_str_t  string_ext = njs_str("ext");
+static const njs_str_t  string_crv = njs_str("crv");
+static const njs_str_t  string_kty = njs_str("kty");
+static const njs_str_t  key_ops = njs_str("key_ops");
+static const njs_str_t  string_length = njs_str("length");
 
 
 static njs_int_t    njs_webcrypto_crypto_key_proto_id;
@@ -622,7 +625,8 @@ njs_ext_cipher(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     unsigned                   mask;
     njs_int_t                  ret;
     njs_str_t                  data;
-    njs_value_t                *options, value;
+    njs_value_t                *options;
+    njs_opaque_value_t         result;
     njs_webcrypto_key_t        *key;
     njs_webcrypto_algorithm_t  *alg;
 
@@ -635,22 +639,22 @@ njs_ext_cipher(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     key = njs_vm_external(vm, njs_webcrypto_crypto_key_proto_id,
                           njs_arg(args, nargs, 2));
     if (njs_slow_path(key == NULL)) {
-        njs_type_error(vm, "\"key\" is not a CryptoKey object");
+        njs_vm_error(vm, "\"key\" is not a CryptoKey object");
         goto fail;
     }
 
     mask = encrypt ? NJS_KEY_USAGE_ENCRYPT : NJS_KEY_USAGE_DECRYPT;
     if (njs_slow_path(!(key->usage & mask))) {
-        njs_type_error(vm, "provide key does not support %s operation",
-                       encrypt ? "encrypt" : "decrypt");
+        njs_vm_error(vm, "provide key does not support %s operation",
+                     encrypt ? "encrypt" : "decrypt");
         goto fail;
     }
 
     if (njs_slow_path(key->alg != alg)) {
-        njs_type_error(vm, "cannot %s using \"%V\" with \"%V\" key",
-                       encrypt ? "encrypt" : "decrypt",
-                       njs_algorithm_string(key->alg),
-                       njs_algorithm_string(alg));
+        njs_vm_error(vm, "cannot %s using \"%V\" with \"%V\" key",
+                     encrypt ? "encrypt" : "decrypt",
+                     njs_algorithm_string(key->alg),
+                     njs_algorithm_string(alg));
         goto fail;
     }
 
@@ -661,23 +665,26 @@ njs_ext_cipher(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
 
     switch (alg->type) {
     case NJS_ALGORITHM_RSA_OAEP:
-        ret = njs_cipher_pkey(vm, &data, key, encrypt, &value);
+        ret = njs_cipher_pkey(vm, &data, key, encrypt, njs_value_arg(&result));
         break;
 
     case NJS_ALGORITHM_AES_GCM:
-        ret = njs_cipher_aes_gcm(vm, &data, key, options, encrypt, &value);
+        ret = njs_cipher_aes_gcm(vm, &data, key, options, encrypt,
+                                 njs_value_arg(&result));
         break;
 
     case NJS_ALGORITHM_AES_CTR:
-        ret = njs_cipher_aes_ctr(vm, &data, key, options, encrypt, &value);
+        ret = njs_cipher_aes_ctr(vm, &data, key, options, encrypt,
+                                 njs_value_arg(&result));
         break;
 
     case NJS_ALGORITHM_AES_CBC:
     default:
-        ret = njs_cipher_aes_cbc(vm, &data, key, options, encrypt, &value);
+        ret = njs_cipher_aes_cbc(vm, &data, key, options, encrypt,
+                                 njs_value_arg(&result));
     }
 
-    return njs_webcrypto_result(vm, &value, ret, retval);
+    return njs_webcrypto_result(vm, &result, ret, retval);
 
 fail:
 
@@ -736,7 +743,7 @@ njs_cipher_pkey(njs_vm_t *vm, njs_str_t *data, njs_webcrypto_key_t *key,
 
     dst = njs_mp_alloc(njs_vm_memory_pool(vm), outlen);
     if (njs_slow_path(dst == NULL)) {
-        njs_memory_error(vm);
+        njs_vm_memory_error(vm);
         ret = NJS_ERROR;
         goto fail;
     }
@@ -763,18 +770,19 @@ static njs_int_t
 njs_cipher_aes_gcm(njs_vm_t *vm, njs_str_t *data, njs_webcrypto_key_t *key,
     njs_value_t *options, njs_bool_t encrypt, njs_value_t *retval)
 {
-    int               len, outlen, dstlen;
-    u_char            *dst, *p;
-    int64_t           taglen;
-    njs_str_t         iv, aad;
-    njs_int_t         ret;
-    njs_value_t       value;
-    EVP_CIPHER_CTX    *ctx;
-    const EVP_CIPHER  *cipher;
-
-    static const njs_value_t  string_iv = njs_string("iv");
-    static const njs_value_t  string_ad = njs_string("additionalData");
-    static const njs_value_t  string_tl = njs_string("tagLength");
+    int                 len, outlen, dstlen;
+    u_char              *dst, *p;
+    int64_t             taglen;
+    njs_str_t           iv, aad;
+    njs_int_t           ret;
+    njs_value_t         *value;
+    EVP_CIPHER_CTX      *ctx;
+    const EVP_CIPHER    *cipher;
+    njs_opaque_value_t  lvalue;
+
+    static const njs_str_t  string_iv = njs_str("iv");
+    static const njs_str_t  string_ad = njs_str("additionalData");
+    static const njs_str_t  string_tl = njs_str("tagLength");
 
     switch (key->raw.length) {
     case 16:
@@ -790,33 +798,26 @@ njs_cipher_aes_gcm(njs_vm_t *vm, njs_str_t *data, njs_webcrypto_key_t *key,
         break;
 
     default:
-        njs_type_error(vm, "AES-GCM Invalid key length");
+        njs_vm_error(vm, "AES-GCM Invalid key length");
         return NJS_ERROR;
     }
 
-    ret = njs_value_property(vm, options, njs_value_arg(&string_iv), &value);
-    if (njs_slow_path(ret != NJS_OK)) {
-        if (ret == NJS_DECLINED) {
-            njs_type_error(vm, "AES-GCM algorithm.iv is not provided");
-        }
-
+    value = njs_vm_object_prop(vm, options, &string_iv, &lvalue);
+    if (value == NULL) {
+        njs_vm_error(vm, "AES-GCM algorithm.iv is not provided");
         return NJS_ERROR;
     }
 
-    ret = njs_vm_value_to_bytes(vm, &iv, &value);
+    ret = njs_vm_value_to_bytes(vm, &iv, njs_value_arg(&lvalue));
     if (njs_slow_path(ret != NJS_OK)) {
         return NJS_ERROR;
     }
 
     taglen = 128;
 
-    ret = njs_value_property(vm, options, njs_value_arg(&string_tl), &value);
-    if (njs_slow_path(ret == NJS_ERROR)) {
-        return NJS_ERROR;
-    }
-
-    if (njs_is_defined(&value)) {
-        ret = njs_value_to_integer(vm, &value, &taglen);
+    value = njs_vm_object_prop(vm, options, &string_tl, &lvalue);
+    if (value != NULL && !njs_value_is_undefined(value)) {
+        ret = njs_value_to_integer(vm, value, &taglen);
         if (njs_slow_path(ret != NJS_OK)) {
             return NJS_ERROR;
         }
@@ -830,14 +831,14 @@ njs_cipher_aes_gcm(njs_vm_t *vm, njs_str_t *data, njs_webcrypto_key_t *key,
                       && taglen != 120
                       && taglen != 128))
     {
-        njs_type_error(vm, "AES-GCM Invalid tagLength");
+        njs_vm_error(vm, "AES-GCM Invalid tagLength");
         return NJS_ERROR;
     }
 
     taglen /= 8;
 
     if (njs_slow_path(!encrypt && (data->length < (size_t) taglen))) {
-        njs_type_error(vm, "AES-GCM data is too short");
+        njs_vm_error(vm, "AES-GCM data is too short");
         return NJS_ERROR;
     }
 
@@ -881,15 +882,11 @@ njs_cipher_aes_gcm(njs_vm_t *vm, njs_str_t *data, njs_webcrypto_key_t *key,
         }
     }
 
-    ret = njs_value_property(vm, options, njs_value_arg(&string_ad), &value);
-    if (njs_slow_path(ret == NJS_ERROR)) {
-        return NJS_ERROR;
-    }
-
     aad.length = 0;
 
-    if (njs_is_defined(&value)) {
-        ret = njs_vm_value_to_bytes(vm, &aad, &value);
+    value = njs_vm_object_prop(vm, options, &string_ad, &lvalue);
+    if (value != NULL && !njs_value_is_undefined(value)) {
+        ret = njs_vm_value_to_bytes(vm, &aad, value);
         if (njs_slow_path(ret != NJS_OK)) {
             return NJS_ERROR;
         }
@@ -908,7 +905,7 @@ njs_cipher_aes_gcm(njs_vm_t *vm, njs_str_t *data, njs_webcrypto_key_t *key,
     dstlen = data->length + EVP_CIPHER_CTX_block_size(ctx) + taglen;
     dst = njs_mp_alloc(njs_vm_memory_pool(vm), dstlen);
     if (njs_slow_path(dst == NULL)) {
-        njs_memory_error(vm);
+        njs_vm_memory_error(vm);
         return NJS_ERROR;
     }
 
@@ -1064,18 +1061,19 @@ static njs_int_t
 njs_cipher_aes_ctr(njs_vm_t *vm, njs_str_t *data, njs_webcrypto_key_t *key,
     njs_value_t *options, njs_bool_t encrypt, njs_value_t *retval)
 {
-    int               len, len2;
-    u_char            *dst;
-    int64_t           length;
-    BIGNUM            *total, *blocks, *left, *ctr;
-    njs_int_t         ret;
-    njs_str_t         iv;
-    njs_uint_t        size1;
-    njs_value_t       value;
-    const EVP_CIPHER  *cipher;
-    u_char            iv2[16];
-
-    static const njs_value_t  string_counter = njs_string("counter");
+    int                 len, len2;
+    u_char              *dst;
+    int64_t             length;
+    BIGNUM              *total, *blocks, *left, *ctr;
+    njs_int_t           ret;
+    njs_str_t           iv;
+    njs_uint_t          size1;
+    njs_value_t         *value;
+    const EVP_CIPHER    *cipher;
+    njs_opaque_value_t  lvalue;
+    u_char              iv2[16];
+
+    static const njs_str_t  string_counter = njs_str("counter");
 
     switch (key->raw.length) {
     case 16:
@@ -1091,48 +1089,39 @@ njs_cipher_aes_ctr(njs_vm_t *vm, njs_str_t *data, njs_webcrypto_key_t *key,
         break;
 
     default:
-        njs_type_error(vm, "AES-CTR Invalid key length");
+        njs_vm_error(vm, "AES-CTR Invalid key length");
         return NJS_ERROR;
     }
 
-    ret = njs_value_property(vm, options, njs_value_arg(&string_counter),
-                             &value);
-    if (njs_slow_path(ret != NJS_OK)) {
-        if (ret == NJS_DECLINED) {
-            njs_type_error(vm, "AES-CTR algorithm.counter is not provided");
-        }
-
+    value = njs_vm_object_prop(vm, options, &string_counter, &lvalue);
+    if (value == NULL) {
+        njs_vm_error(vm, "AES-CTR algorithm.counter is not provided");
         return NJS_ERROR;
     }
 
-    ret = njs_vm_value_to_bytes(vm, &iv, &value);
+    ret = njs_vm_value_to_bytes(vm, &iv, value);
     if (njs_slow_path(ret != NJS_OK)) {
         return NJS_ERROR;
     }
 
     if (njs_slow_path(iv.length != 16)) {
-        njs_type_error(vm, "AES-CTR algorithm.counter must be 16 bytes long");
+        njs_vm_error(vm, "AES-CTR algorithm.counter must be 16 bytes long");
         return NJS_ERROR;
     }
 
-    ret = njs_value_property(vm, options, njs_value_arg(&string_length),
-                             &value);
-    if (njs_slow_path(ret != NJS_OK)) {
-        if (ret == NJS_DECLINED) {
-            njs_type_error(vm, "AES-CTR algorithm.length is not provided");
-        }
-
+    value = njs_vm_object_prop(vm, options, &string_length, &lvalue);
+    if (value == NULL) {
+        njs_vm_error(vm, "AES-CTR algorithm.length is not provided");
         return NJS_ERROR;
     }
 
-    ret = njs_value_to_integer(vm, &value, &length);
+    ret = njs_value_to_integer(vm, value, &length);
     if (njs_slow_path(ret != NJS_OK)) {
         return NJS_ERROR;
     }
 
     if (njs_slow_path(length == 0 || length > 128)) {
-        njs_type_error(vm, "AES-CTR algorithm.length "
-                       "must be between 1 and 128");
+        njs_vm_error(vm, "AES-CTR algorithm.length must be between 1 and 128");
         return NJS_ERROR;
     }
 
@@ -1175,7 +1164,7 @@ njs_cipher_aes_ctr(njs_vm_t *vm, njs_str_t *data, njs_webcrypto_key_t *key,
 
     ret = BN_cmp(blocks, total);
     if (njs_slow_path(ret > 0)) {
-        njs_type_error(vm, "AES-CTR repeated counter");
+        njs_vm_error(vm, "AES-CTR repeated counter");
         ret = NJS_ERROR;
         goto fail;
     }
@@ -1196,7 +1185,7 @@ njs_cipher_aes_ctr(njs_vm_t *vm, njs_str_t *data, njs_webcrypto_key_t *key,
     dst = njs_mp_alloc(njs_vm_memory_pool(vm),
                        data->length + EVP_MAX_BLOCK_LENGTH);
     if (njs_slow_path(dst == NULL)) {
-        njs_memory_error(vm);
+        njs_vm_memory_error(vm);
         return NJS_ERROR;
     }
 
@@ -1271,16 +1260,17 @@ static njs_int_t
 njs_cipher_aes_cbc(njs_vm_t *vm, njs_str_t *data, njs_webcrypto_key_t *key,
     njs_value_t *options, njs_bool_t encrypt, njs_value_t *retval)
 {
-    int               olen_max, olen, olen2;
-    u_char            *dst;
-    unsigned          remainder;
-    njs_str_t         iv;
-    njs_int_t         ret;
-    njs_value_t       value;
-    EVP_CIPHER_CTX    *ctx;
-    const EVP_CIPHER  *cipher;
-
-    static const njs_value_t  string_iv = njs_string("iv");
+    int                 olen_max, olen, olen2;
+    u_char              *dst;
+    unsigned            remainder;
+    njs_str_t           iv;
+    njs_int_t           ret;
+    njs_value_t         *value;
+    EVP_CIPHER_CTX      *ctx;
+    const EVP_CIPHER    *cipher;
+    njs_opaque_value_t  lvalue;
+
+    static const njs_str_t  string_iv = njs_str("iv");
 
     switch (key->raw.length) {
     case 16:
@@ -1296,26 +1286,23 @@ njs_cipher_aes_cbc(njs_vm_t *vm, njs_str_t *data, njs_webcrypto_key_t *key,
         break;
 
     default:
-        njs_type_error(vm, "AES-CBC Invalid key length");
+        njs_vm_error(vm, "AES-CBC Invalid key length");
         return NJS_ERROR;
     }
 
-    ret = njs_value_property(vm, options, njs_value_arg(&string_iv), &value);
-    if (njs_slow_path(ret != NJS_OK)) {
-        if (ret == NJS_DECLINED) {
-            njs_type_error(vm, "AES-CBC algorithm.iv is not provided");
-        }
-
+    value = njs_vm_object_prop(vm, options, &string_iv, &lvalue);
+    if (value == NULL) {
+        njs_vm_error(vm, "AES-CBC algorithm.iv is not provided");
         return NJS_ERROR;
     }
 
-    ret = njs_vm_value_to_bytes(vm, &iv, &value);
+    ret = njs_vm_value_to_bytes(vm, &iv, value);
     if (njs_slow_path(ret != NJS_OK)) {
         return NJS_ERROR;
     }
 
     if (njs_slow_path(iv.length != 16)) {
-        njs_type_error(vm, "AES-CBC algorithm.iv must be 16 bytes long");
+        njs_vm_error(vm, "AES-CBC algorithm.iv must be 16 bytes long");
         return NJS_ERROR;
     }
 
@@ -1343,7 +1330,7 @@ njs_cipher_aes_cbc(njs_vm_t *vm, njs_str_t *data, njs_webcrypto_key_t *key,
 
     dst = njs_mp_alloc(njs_vm_memory_pool(vm), olen_max);
     if (njs_slow_path(dst == NULL)) {
-        njs_memory_error(vm);
+        njs_vm_memory_error(vm);
         ret = NJS_ERROR;
         goto fail;
     }
@@ -1386,16 +1373,17 @@ njs_ext_derive(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     unsigned                   usage, mask;
     njs_int_t                  ret;
     njs_str_t                  salt, info;
-    njs_value_t                value, *aobject, *dobject;
+    njs_value_t                *value, *aobject, *dobject;
     const EVP_MD               *md;
     EVP_PKEY_CTX               *pctx;
     njs_webcrypto_key_t        *key, *dkey;
+    njs_opaque_value_t         lvalue;
     njs_webcrypto_hash_t       hash;
     njs_webcrypto_algorithm_t  *alg, *dalg;
 
-    static const njs_value_t  string_info = njs_string("info");
-    static const njs_value_t  string_salt = njs_string("salt");
-    static const njs_value_t  string_iterations = njs_string("iterations");
+    static const njs_str_t  string_info = njs_str("info");
+    static const njs_str_t  string_salt = njs_str("salt");
+    static const njs_str_t  string_iterations = njs_str("iterations");
 
     aobject = njs_arg(args, nargs, 1);
     alg = njs_key_algorithm(vm, aobject);
@@ -1406,22 +1394,22 @@ njs_ext_derive(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     key = njs_vm_external(vm, njs_webcrypto_crypto_key_proto_id,
                           njs_arg(args, nargs, 2));
     if (njs_slow_path(key == NULL)) {
-        njs_type_error(vm, "\"baseKey\" is not a CryptoKey object");
+        njs_vm_error(vm, "\"baseKey\" is not a CryptoKey object");
         goto fail;
     }
 
     mask = derive_key ? NJS_KEY_USAGE_DERIVE_KEY : NJS_KEY_USAGE_DERIVE_BITS;
     if (njs_slow_path(!(key->usage & mask))) {
-        njs_type_error(vm, "provide key does not support \"%s\" operation",
-                       derive_key ? "deriveKey" : "deriveBits");
+        njs_vm_error(vm, "provide key does not support \"%s\" operation",
+                     derive_key ? "deriveKey" : "deriveBits");
         goto fail;
     }
 
     if (njs_slow_path(key->alg != alg)) {
-        njs_type_error(vm, "cannot derive %s using \"%V\" with \"%V\" key",
-                       derive_key ? "key" : "bits",
-                       njs_algorithm_string(key->alg),
-                       njs_algorithm_string(alg));
+        njs_vm_error(vm, "cannot derive %s using \"%V\" with \"%V\" key",
+                     derive_key ? "key" : "bits",
+                     njs_algorithm_string(key->alg),
+                     njs_algorithm_string(alg));
         goto fail;
     }
 
@@ -1433,22 +1421,18 @@ njs_ext_derive(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
             goto fail;
         }
 
-        ret = njs_value_property(vm, dobject, njs_value_arg(&string_length),
-                                 &value);
-        if (njs_slow_path(ret != NJS_OK)) {
-                if (ret == NJS_DECLINED) {
-                    njs_type_error(vm, "derivedKeyAlgorithm.length "
-                                   "is not provided");
-                    goto fail;
-                }
+        value = njs_vm_object_prop(vm, dobject, &string_length, &lvalue);
+        if (value == NULL) {
+            njs_vm_error(vm, "derivedKeyAlgorithm.length is not provided");
+            goto fail;
         }
 
     } else {
         dalg = NULL;
-        njs_value_assign(&value, dobject);
+        value = dobject;
     }
 
-    ret = njs_value_to_integer(vm, &value, &length);
+    ret = njs_value_to_integer(vm, value, &length);
     if (njs_slow_path(ret != NJS_OK)) {
         goto fail;
     }
@@ -1463,16 +1447,16 @@ njs_ext_derive(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
         case NJS_ALGORITHM_AES_CBC:
 
             if (length != 16 && length != 32) {
-                njs_type_error(vm, "deriveKey \"%V\" length must be 128 or 256",
-                               njs_algorithm_string(dalg));
+                njs_vm_error(vm, "deriveKey \"%V\" length must be 128 or 256",
+                             njs_algorithm_string(dalg));
                 goto fail;
             }
 
             break;
 
         default:
-            njs_internal_error(vm, "not implemented deriveKey: \"%V\"",
-                               njs_algorithm_string(dalg));
+            njs_vm_error(vm, "not implemented deriveKey: \"%V\"",
+                         njs_algorithm_string(dalg));
             goto fail;
         }
 
@@ -1482,15 +1466,15 @@ njs_ext_derive(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
         }
 
         if (njs_slow_path(usage & ~dalg->usage)) {
-            njs_type_error(vm, "unsupported key usage for \"%V\" key",
-                           njs_algorithm_string(alg));
+            njs_vm_error(vm, "unsupported key usage for \"%V\" key",
+                         njs_algorithm_string(alg));
             goto fail;
         }
 
         dkey = njs_mp_zalloc(njs_vm_memory_pool(vm),
                              sizeof(njs_webcrypto_key_t));
         if (njs_slow_path(dkey == NULL)) {
-            njs_memory_error(vm);
+            njs_vm_memory_error(vm);
             goto fail;
         }
 
@@ -1500,7 +1484,7 @@ njs_ext_derive(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
 
     k = njs_mp_zalloc(njs_vm_memory_pool(vm), length);
     if (njs_slow_path(k == NULL)) {
-        njs_memory_error(vm);
+        njs_vm_memory_error(vm);
         goto fail;
     }
 
@@ -1511,39 +1495,30 @@ njs_ext_derive(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
             goto fail;
         }
 
-        ret = njs_value_property(vm, aobject, njs_value_arg(&string_salt),
-                                 &value);
-        if (njs_slow_path(ret != NJS_OK)) {
-            if (ret == NJS_DECLINED) {
-                njs_type_error(vm, "PBKDF2 algorithm.salt is not provided");
-            }
-
+        value = njs_vm_object_prop(vm, aobject, &string_salt, &lvalue);
+        if (value == NULL) {
+            njs_vm_error(vm, "PBKDF2 algorithm.salt is not provided");
             goto fail;
         }
 
-        ret = njs_vm_value_to_bytes(vm, &salt, &value);
+        ret = njs_vm_value_to_bytes(vm, &salt, value);
         if (njs_slow_path(ret != NJS_OK)) {
             goto fail;
         }
 
         if (njs_slow_path(salt.length < 16)) {
-            njs_type_error(vm, "PBKDF2 algorithm.salt must be "
-                           "at least 16 bytes long");
+            njs_vm_error(vm, "PBKDF2 algorithm.salt must be "
+                         "at least 16 bytes long");
             goto fail;
         }
 
-        ret = njs_value_property(vm, aobject, njs_value_arg(&string_iterations),
-                                 &value);
-        if (njs_slow_path(ret != NJS_OK)) {
-            if (ret == NJS_DECLINED) {
-                njs_type_error(vm, "PBKDF2 algorithm.iterations "
-                               "is not provided");
-            }
-
+        value = njs_vm_object_prop(vm, aobject, &string_iterations, &lvalue);
+        if (value == NULL) {
+            njs_vm_error(vm, "PBKDF2 algorithm.iterations is not provided");
             goto fail;
         }
 
-        ret = njs_value_to_integer(vm, &value, &iterations);
+        ret = njs_value_to_integer(vm, value, &iterations);
         if (njs_slow_path(ret != NJS_OK)) {
             goto fail;
         }
@@ -1566,32 +1541,24 @@ njs_ext_derive(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
             goto fail;
         }
 
-        ret = njs_value_property(vm, aobject, njs_value_arg(&string_salt),
-                                 &value);
-        if (njs_slow_path(ret != NJS_OK)) {
-            if (ret == NJS_DECLINED) {
-                njs_type_error(vm, "HKDF algorithm.salt is not provided");
-            }
-
+        value = njs_vm_object_prop(vm, aobject, &string_salt, &lvalue);
+        if (value == NULL) {
+            njs_vm_error(vm, "HKDF algorithm.salt is not provided");
             goto fail;
         }
 
-        ret = njs_vm_value_to_bytes(vm, &salt, &value);
+        ret = njs_vm_value_to_bytes(vm, &salt, value);
         if (njs_slow_path(ret != NJS_OK)) {
             goto fail;
         }
 
-        ret = njs_value_property(vm, aobject, njs_value_arg(&string_info),
-                                 &value);
-        if (njs_slow_path(ret != NJS_OK)) {
-            if (ret == NJS_DECLINED) {
-                njs_type_error(vm, "HKDF algorithm.info is not provided");
-            }
-
+        value = njs_vm_object_prop(vm, aobject, &string_info, &lvalue);
+        if (value == NULL) {
+            njs_vm_error(vm, "HKDF algorithm.info is not provided");
             goto fail;
         }
 
-        ret = njs_vm_value_to_bytes(vm, &info, &value);
+        ret = njs_vm_value_to_bytes(vm, &info, value);
         if (njs_slow_path(ret != NJS_OK)) {
             goto fail;
         }
@@ -1659,8 +1626,8 @@ free:
 
     case NJS_ALGORITHM_ECDH:
     default:
-        njs_internal_error(vm, "not implemented deriveKey "
-                           "algorithm: \"%V\"", njs_algorithm_string(alg));
+        njs_vm_error(vm, "not implemented deriveKey "
+                     "algorithm: \"%V\"", njs_algorithm_string(alg));
         goto fail;
     }
 
@@ -1675,18 +1642,19 @@ free:
         dkey->raw.start = k;
         dkey->raw.length = length;
 
-        ret = njs_vm_external_create(vm, &value,
+        ret = njs_vm_external_create(vm, njs_value_arg(&lvalue),
                                      njs_webcrypto_crypto_key_proto_id,
                                      dkey, 0);
     } else {
-        ret = njs_vm_value_array_buffer_set(vm, &value, k, length);
+        ret = njs_vm_value_array_buffer_set(vm, njs_value_arg(&lvalue), k,
+                                            length);
     }
 
     if (njs_slow_path(ret != NJS_OK)) {
         goto fail;
     }
 
-    return njs_webcrypto_result(vm, &value, NJS_OK, retval);
+    return njs_webcrypto_result(vm, &lvalue, NJS_OK, retval);
 
 fail:
 
@@ -1702,8 +1670,8 @@ njs_ext_digest(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     u_char                *dst;
     njs_str_t             data;
     njs_int_t             ret;
-    njs_value_t           value;
     const EVP_MD          *md;
+    njs_opaque_value_t    result;
     njs_webcrypto_hash_t  hash;
 
     ret = njs_algorithm_hash(vm, njs_arg(args, nargs, 1), &hash);
@@ -1721,7 +1689,7 @@ njs_ext_digest(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
 
     dst = njs_mp_zalloc(njs_vm_memory_pool(vm), olen);
     if (njs_slow_path(dst == NULL)) {
-        njs_memory_error(vm);
+        njs_vm_memory_error(vm);
         goto fail;
     }
 
@@ -1731,12 +1699,12 @@ njs_ext_digest(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
         goto fail;
     }
 
-    ret = njs_vm_value_array_buffer_set(vm, &value, dst, olen);
+    ret = njs_vm_value_array_buffer_set(vm, njs_value_arg(&result), dst, olen);
     if (njs_slow_path(ret != NJS_OK)) {
         goto fail;
     }
 
-    return njs_webcrypto_result(vm, &value, NJS_OK, retval);
+    return njs_webcrypto_result(vm, &result, NJS_OK, retval);
 
 fail:
 
@@ -1745,8 +1713,8 @@ fail:
 
 
 static njs_int_t
-njs_export_base64url_bignum(njs_vm_t *vm, njs_value_t *retval, const BIGNUM *v,
-    size_t size)
+njs_export_base64url_bignum(njs_vm_t *vm, njs_opaque_value_t *retval,
+    const BIGNUM *v, size_t size)
 {
     njs_str_t  src;
     u_char     buf[512];
@@ -1762,36 +1730,35 @@ njs_export_base64url_bignum(njs_vm_t *vm, njs_value_t *retval, const BIGNUM *v,
     src.start = buf;
     src.length = size;
 
-    return njs_string_base64url(vm, retval, &src);
+    return njs_string_base64url(vm, njs_value_arg(retval), &src);
 }
 
 
 static njs_int_t
-njs_base64url_bignum_set(njs_vm_t *vm, njs_value_t *jwk, njs_value_t *key,
+njs_base64url_bignum_set(njs_vm_t *vm, njs_value_t *jwk, const njs_str_t *key,
     const BIGNUM *v, size_t size)
 {
-    njs_int_t    ret;
-    njs_value_t  value;
+    njs_int_t           ret;
+    njs_opaque_value_t  value;
 
     ret = njs_export_base64url_bignum(vm, &value, v, size);
     if (ret != NJS_OK) {
         return NJS_ERROR;
     }
 
-    return njs_value_property_set(vm, jwk, key, &value);
+    return njs_vm_object_prop_set(vm, jwk, key, &value);
 }
 
 
 static njs_int_t
 njs_export_jwk_rsa(njs_vm_t *vm, njs_webcrypto_key_t *key, njs_value_t *retval)
 {
-    njs_int_t     ret;
-    const RSA     *rsa;
-    njs_str_t     *nm;
-    njs_value_t   nvalue, evalue, alg;
-    const BIGNUM  *n_bn, *e_bn, *d_bn, *p_bn, *q_bn, *dp_bn, *dq_bn, *qi_bn;
-
-    static const njs_value_t  rsa_str = njs_string("RSA");
+    njs_int_t           ret;
+    const RSA           *rsa;
+    njs_str_t           *nm;
+    const BIGNUM        *n_bn, *e_bn, *d_bn, *p_bn, *q_bn, *dp_bn, *dq_bn,
+                        *qi_bn;
+    njs_opaque_value_t  nvalue, evalue, alg, rsa_s;
 
     rsa = njs_pkey_get_rsa_key(key->pkey);
 
@@ -1807,8 +1774,24 @@ njs_export_jwk_rsa(njs_vm_t *vm, njs_webcrypto_key_t *key, njs_value_t *retval)
         return NJS_ERROR;
     }
 
-    ret = njs_vm_object_alloc(vm, retval, &string_kty, &rsa_str, &string_n,
-                              &nvalue, &string_e, &evalue, NULL);
+    ret = njs_vm_object_alloc(vm, retval, NULL);
+    if (ret != NJS_OK) {
+        return NJS_ERROR;
+    }
+
+    njs_vm_value_string_set(vm, njs_value_arg(&rsa_s), (u_char *) "RSA", 3);
+
+    ret = njs_vm_object_prop_set(vm, retval, &string_kty, &rsa_s);
+    if (ret != NJS_OK) {
+        return NJS_ERROR;
+    }
+
+    ret = njs_vm_object_prop_set(vm, retval, &string_n, &nvalue);
+    if (ret != NJS_OK) {
+        return NJS_ERROR;
+    }
+
+    ret = njs_vm_object_prop_set(vm, retval, &string_e, &evalue);
     if (ret != NJS_OK) {
         return NJS_ERROR;
     }
@@ -1817,38 +1800,32 @@ njs_export_jwk_rsa(njs_vm_t *vm, njs_webcrypto_key_t *key, njs_value_t *retval)
         njs_rsa_get0_factors(rsa, &p_bn, &q_bn);
         njs_rsa_get0_ctr_params(rsa, &dp_bn, &dq_bn, &qi_bn);
 
-        ret = njs_base64url_bignum_set(vm, retval, njs_value_arg(&string_d),
-                                       d_bn, 0);
+        ret = njs_base64url_bignum_set(vm, retval, &string_d, d_bn, 0);
         if (ret != NJS_OK) {
             return NJS_ERROR;
         }
 
-        ret = njs_base64url_bignum_set(vm, retval, njs_value_arg(&string_p),
-                                       p_bn, 0);
+        ret = njs_base64url_bignum_set(vm, retval, &string_p, p_bn, 0);
         if (ret != NJS_OK) {
             return NJS_ERROR;
         }
 
-        ret = njs_base64url_bignum_set(vm, retval, njs_value_arg(&string_q),
-                                       q_bn, 0);
+        ret = njs_base64url_bignum_set(vm, retval, &string_q, q_bn, 0);
         if (ret != NJS_OK) {
             return NJS_ERROR;
         }
 
-        ret = njs_base64url_bignum_set(vm, retval, njs_value_arg(&string_dp),
-                                       dp_bn, 0);
+        ret = njs_base64url_bignum_set(vm, retval, &string_dp, dp_bn, 0);
         if (ret != NJS_OK) {
             return NJS_ERROR;
         }
 
-        ret = njs_base64url_bignum_set(vm, retval, njs_value_arg(&string_dq),
-                                       dq_bn, 0);
+        ret = njs_base64url_bignum_set(vm, retval, &string_dq, dq_bn, 0);
         if (ret != NJS_OK) {
             return NJS_ERROR;
         }
 
-        ret = njs_base64url_bignum_set(vm, retval, njs_value_arg(&string_qi),
-                                       qi_bn, 0);
+        ret = njs_base64url_bignum_set(vm, retval, &string_qi, qi_bn, 0);
         if (ret != NJS_OK) {
             return NJS_ERROR;
         }
@@ -1856,9 +1833,10 @@ njs_export_jwk_rsa(njs_vm_t *vm, njs_webcrypto_key_t *key, njs_value_t *retval)
 
     nm = &njs_webcrypto_alg_name[key->alg->type][key->hash];
 
-    (void) njs_vm_value_string_set(vm, &alg, nm->start, nm->length);
+    (void) njs_vm_value_string_set(vm, njs_value_arg(&alg), nm->start,
+                                   nm->length);
 
-    return njs_value_property_set(vm, retval, njs_value_arg(&string_alg), &alg);
+    return njs_vm_object_prop_set(vm, retval, &string_alg, &alg);
 }
 
 
@@ -1868,15 +1846,13 @@ njs_export_jwk_ec(njs_vm_t *vm, njs_webcrypto_key_t *key, njs_value_t *retval)
     int                    nid, group_bits, group_bytes;
     BIGNUM                 *x_bn, *y_bn;
     njs_int_t              ret;
-    njs_value_t            xvalue, yvalue, dvalue, name;
     const EC_KEY           *ec;
     const BIGNUM           *d_bn;
     const EC_POINT         *pub;
     const EC_GROUP         *group;
+    njs_opaque_value_t     xvalue, yvalue, dvalue, name, ec_s;
     njs_webcrypto_entry_t  *e;
 
-    static const njs_value_t  ec_str = njs_string("EC");
-
     x_bn = NULL;
     y_bn = NULL;
     d_bn = NULL;
@@ -1924,24 +1900,44 @@ njs_export_jwk_ec(njs_vm_t *vm, njs_webcrypto_key_t *key, njs_value_t *retval)
 
     for (e = &njs_webcrypto_curve[0]; e->name.length != 0; e++) {
         if ((uintptr_t) nid == e->value) {
-            (void) njs_vm_value_string_set(vm, &name, e->name.start,
-                                           e->name.length);
+            (void) njs_vm_value_string_set(vm, njs_value_arg(&name),
+                                           e->name.start, e->name.length);
             break;
         }
     }
 
     if (e->name.length == 0) {
-        njs_type_error(vm, "Unsupported JWK EC curve: %s", OBJ_nid2sn(nid));
+        njs_vm_error(vm, "Unsupported JWK EC curve: %s", OBJ_nid2sn(nid));
         goto fail;
     }
 
-    ret = njs_vm_object_alloc(vm, retval, &string_kty, &ec_str, &string_x,
-                              &xvalue, &string_y, &yvalue, &string_crv, &name,
-                              NULL);
+    ret = njs_vm_object_alloc(vm, retval, NULL);
     if (ret != NJS_OK) {
         goto fail;
     }
 
+    njs_vm_value_string_set(vm, njs_value_arg(&ec_s), (u_char *) "EC", 2);
+
+    ret = njs_vm_object_prop_set(vm, retval, &string_kty, &ec_s);
+    if (ret != NJS_OK) {
+        return NJS_ERROR;
+    }
+
+    ret = njs_vm_object_prop_set(vm, retval, &string_x, &xvalue);
+    if (ret != NJS_OK) {
+        return NJS_ERROR;
+    }
+
+    ret = njs_vm_object_prop_set(vm, retval, &string_y, &yvalue);
+    if (ret != NJS_OK) {
+        return NJS_ERROR;
+    }
+
+    ret = njs_vm_object_prop_set(vm, retval, &string_crv, &name);
+    if (ret != NJS_OK) {
+        return NJS_ERROR;
+    }
+
     if (key->privat) {
         d_bn = EC_KEY_get0_private_key(ec);
 
@@ -1950,8 +1946,7 @@ njs_export_jwk_ec(njs_vm_t *vm, njs_webcrypto_key_t *key, njs_value_t *retval)
             goto fail;
         }
 
-        ret = njs_value_property_set(vm, retval, njs_value_arg(&string_d),
-                                     &dvalue);
+        ret = njs_vm_object_prop_set(vm, retval, &string_d, &dvalue);
         if (ret != NJS_OK) {
             goto fail;
         }
@@ -1986,8 +1981,8 @@ njs_export_raw_ec(njs_vm_t *vm, njs_webcrypto_key_t *key, njs_value_t *retval)
     njs_assert(key->pkey != NULL);
 
     if (key->privat) {
-        njs_type_error(vm, "private key of \"%V\" cannot be exported "
-                       "in \"raw\" format", njs_algorithm_string(key->alg));
+        njs_vm_error(vm, "private key of \"%V\" cannot be exported "
+                     "in \"raw\" format", njs_algorithm_string(key->alg));
         return NJS_ERROR;
     }
 
@@ -2022,8 +2017,8 @@ static njs_int_t
 njs_export_jwk_asymmetric(njs_vm_t *vm, njs_webcrypto_key_t *key,
     njs_value_t *retval)
 {
-    njs_int_t    ret;
-    njs_value_t  ops, extractable;
+    njs_int_t           ret;
+    njs_opaque_value_t  ops, extractable;
 
     njs_assert(key->pkey != NULL);
 
@@ -2048,7 +2043,7 @@ njs_export_jwk_asymmetric(njs_vm_t *vm, njs_webcrypto_key_t *key,
         break;
 
     default:
-        njs_type_error(vm, "provided key cannot be exported as JWK");
+        njs_vm_error(vm, "provided key cannot be exported as JWK");
         return NJS_ERROR;
     }
 
@@ -2057,15 +2052,14 @@ njs_export_jwk_asymmetric(njs_vm_t *vm, njs_webcrypto_key_t *key,
         return NJS_ERROR;
     }
 
-    ret = njs_value_property_set(vm, retval, njs_value_arg(&key_ops), &ops);
+    ret = njs_vm_object_prop_set(vm, retval, &key_ops, &ops);
     if (njs_slow_path(ret != NJS_OK)) {
         return NJS_ERROR;
     }
 
-    njs_value_boolean_set(&extractable, key->extractable);
+    njs_value_boolean_set(njs_value_arg(&extractable), key->extractable);
 
-    return njs_value_property_set(vm, retval, njs_value_arg(&string_ext),
-                                  &extractable);
+    return njs_vm_object_prop_set(vm, retval, &string_ext, &extractable);
 }
 
 
@@ -2074,14 +2068,12 @@ njs_export_jwk_oct(njs_vm_t *vm, njs_webcrypto_key_t *key, njs_value_t *retval)
 {
     njs_int_t            ret;
     njs_str_t            *nm;
-    njs_value_t          k, alg, ops, extractable;
+    njs_opaque_value_t   k, alg, ops, extractable, oct_s;
     njs_webcrypto_alg_t  type;
 
-    static const njs_value_t  oct_str = njs_string("oct");
-
     njs_assert(key->raw.start != NULL);
 
-    ret = njs_string_base64url(vm, &k, &key->raw);
+    ret = njs_string_base64url(vm, njs_value_arg(&k), &key->raw);
     if (njs_slow_path(ret != NJS_OK)) {
         return NJS_ERROR;
     }
@@ -2090,7 +2082,8 @@ njs_export_jwk_oct(njs_vm_t *vm, njs_webcrypto_key_t *key, njs_value_t *retval)
 
     if (key->alg->type == NJS_ALGORITHM_HMAC) {
         nm = &njs_webcrypto_alg_name[type][key->hash];
-        (void) njs_vm_value_string_set(vm, &alg, nm->start, nm->length);
+        (void) njs_vm_value_string_set(vm, njs_value_arg(&alg), nm->start,
+                                       nm->length);
 
     } else {
         switch (key->raw.length) {
@@ -2099,11 +2092,12 @@ njs_export_jwk_oct(njs_vm_t *vm, njs_webcrypto_key_t *key, njs_value_t *retval)
         case 32:
             nm = &njs_webcrypto_alg_aes_name
                     [type - NJS_ALGORITHM_AES_GCM][(key->raw.length - 16) / 8];
-            (void) njs_vm_value_string_set(vm, &alg, nm->start, nm->length);
+            (void) njs_vm_value_string_set(vm, njs_value_arg(&alg), nm->start,
+                                           nm->length);
             break;
 
         default:
-            njs_value_undefined_set(&alg);
+            njs_value_undefined_set(njs_value_arg(&alg));
             break;
         }
     }
@@ -2113,18 +2107,37 @@ njs_export_jwk_oct(njs_vm_t *vm, njs_webcrypto_key_t *key, njs_value_t *retval)
         return NJS_ERROR;
     }
 
-    njs_value_boolean_set(&extractable, key->extractable);
+    njs_value_boolean_set(njs_value_arg(&extractable), key->extractable);
 
-    ret = njs_vm_object_alloc(vm, retval, &string_kty, &oct_str, &string_k,
-                               &k, &key_ops, &ops, &string_ext, &extractable,
-                               NULL);
+    ret = njs_vm_object_alloc(vm, retval, NULL);
     if (njs_slow_path(ret != NJS_OK)) {
         return NJS_ERROR;
     }
 
-    if (njs_is_defined(&alg)) {
-        ret = njs_value_property_set(vm, retval, njs_value_arg(&string_alg),
-                                     &alg);
+    njs_vm_value_string_set(vm, njs_value_arg(&oct_s), (u_char *) "oct", 3);
+
+    ret = njs_vm_object_prop_set(vm, retval, &string_kty, &oct_s);
+    if (ret != NJS_OK) {
+        return NJS_ERROR;
+    }
+
+    ret = njs_vm_object_prop_set(vm, retval, &string_k, &k);
+    if (ret != NJS_OK) {
+        return NJS_ERROR;
+    }
+
+    ret = njs_vm_object_prop_set(vm, retval, &key_ops, &ops);
+    if (ret != NJS_OK) {
+        return NJS_ERROR;
+    }
+
+    ret = njs_vm_object_prop_set(vm, retval, &string_ext, &extractable);
+    if (ret != NJS_OK) {
+        return NJS_ERROR;
+    }
+
+    if (!njs_value_is_undefined(njs_value_arg(&alg))) {
+        ret = njs_vm_object_prop_set(vm, retval, &string_alg, &alg);
         if (njs_slow_path(ret != NJS_OK)) {
             return NJS_ERROR;
         }
@@ -2141,9 +2154,9 @@ njs_ext_export_key(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     BIO                         *bio;
     BUF_MEM                     *mem;
     njs_int_t                   ret;
-    njs_value_t                 value;
     njs_webcrypto_key_t         *key;
     PKCS8_PRIV_KEY_INFO         *pkcs8;
+    njs_opaque_value_t          value;
     njs_webcrypto_key_format_t  fmt;
 
     fmt = njs_key_format(vm, njs_arg(args, nargs, 1));
@@ -2154,19 +2167,19 @@ njs_ext_export_key(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     key = njs_vm_external(vm, njs_webcrypto_crypto_key_proto_id,
                           njs_arg(args, nargs, 2));
     if (njs_slow_path(key == NULL)) {
-        njs_type_error(vm, "\"key\" is not a CryptoKey object");
+        njs_vm_error(vm, "\"key\" is not a CryptoKey object");
         goto fail;
     }
 
     if (njs_slow_path(!(fmt & key->alg->fmt))) {
-        njs_type_error(vm, "unsupported key fmt \"%V\" for \"%V\" key",
-                       njs_format_string(fmt),
-                       njs_algorithm_string(key->alg));
+        njs_vm_error(vm, "unsupported key fmt \"%V\" for \"%V\" key",
+                     njs_format_string(fmt),
+                     njs_algorithm_string(key->alg));
         goto fail;
     }
 
     if (njs_slow_path(!key->extractable)) {
-        njs_type_error(vm, "provided key cannot be extracted");
+        njs_vm_error(vm, "provided key cannot be extracted");
         goto fail;
     }
 
@@ -2177,7 +2190,7 @@ njs_ext_export_key(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
         case NJS_ALGORITHM_RSA_PSS:
         case NJS_ALGORITHM_RSA_OAEP:
         case NJS_ALGORITHM_ECDSA:
-            ret = njs_export_jwk_asymmetric(vm, key, &value);
+            ret = njs_export_jwk_asymmetric(vm, key, njs_value_arg(&value));
             if (njs_slow_path(ret != NJS_OK)) {
                 goto fail;
             }
@@ -2188,7 +2201,7 @@ njs_ext_export_key(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
         case NJS_ALGORITHM_AES_CTR:
         case NJS_ALGORITHM_AES_CBC:
         case NJS_ALGORITHM_HMAC:
-            ret = njs_export_jwk_oct(vm, key, &value);
+            ret = njs_export_jwk_oct(vm, key, njs_value_arg(&value));
             if (njs_slow_path(ret != NJS_OK)) {
                 goto fail;
             }
@@ -2203,8 +2216,8 @@ njs_ext_export_key(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
 
     case NJS_KEY_FORMAT_PKCS8:
         if (!key->privat) {
-            njs_type_error(vm, "public key of \"%V\" cannot be exported "
-                           "as PKCS8", njs_algorithm_string(key->alg));
+            njs_vm_error(vm, "public key of \"%V\" cannot be exported "
+                         "as PKCS8", njs_algorithm_string(key->alg));
             goto fail;
         }
 
@@ -2232,8 +2245,8 @@ njs_ext_export_key(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
 
         BIO_get_mem_ptr(bio, &mem);
 
-        ret = njs_webcrypto_array_buffer(vm, &value, (u_char *) mem->data,
-                                         mem->length);
+        ret = njs_webcrypto_array_buffer(vm, njs_value_arg(&value),
+                                         (u_char *) mem->data, mem->length);
 
         BIO_free(bio);
         PKCS8_PRIV_KEY_INFO_free(pkcs8);
@@ -2246,8 +2259,8 @@ njs_ext_export_key(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
 
     case NJS_KEY_FORMAT_SPKI:
         if (key->privat) {
-            njs_type_error(vm, "private key of \"%V\" cannot be exported "
-                           "as SPKI", njs_algorithm_string(key->alg));
+            njs_vm_error(vm, "private key of \"%V\" cannot be exported "
+                         "as SPKI", njs_algorithm_string(key->alg));
             goto fail;
         }
 
@@ -2267,8 +2280,8 @@ njs_ext_export_key(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
 
         BIO_get_mem_ptr(bio, &mem);
 
-        ret = njs_webcrypto_array_buffer(vm, &value, (u_char *) mem->data,
-                                         mem->length);
+        ret = njs_webcrypto_array_buffer(vm, njs_value_arg(&value),
+                                         (u_char *) mem->data, mem->length);
 
         BIO_free(bio);
 
@@ -2281,7 +2294,7 @@ njs_ext_export_key(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     case NJS_KEY_FORMAT_RAW:
     default:
         if (key->alg->type == NJS_ALGORITHM_ECDSA) {
-            ret = njs_export_raw_ec(vm, key, &value);
+            ret = njs_export_raw_ec(vm, key, njs_value_arg(&value));
             if (njs_slow_path(ret != NJS_OK)) {
                 goto fail;
             }
@@ -2289,8 +2302,8 @@ njs_ext_export_key(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
             break;
         }
 
-        ret = njs_vm_value_array_buffer_set(vm, &value, key->raw.start,
-                                            key->raw.length);
+        ret = njs_vm_value_array_buffer_set(vm, njs_value_arg(&value),
+                                            key->raw.start, key->raw.length);
         if (njs_slow_path(ret != NJS_OK)) {
             goto fail;
         }
@@ -2314,14 +2327,15 @@ njs_ext_generate_key(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     unsigned                   usage;
     njs_int_t                  ret;
     njs_bool_t                 extractable;
-    njs_value_t                value, pub, priv, *aobject;
+    njs_value_t                *aobject, *val;
     EVP_PKEY_CTX               *ctx;
     njs_webcrypto_key_t        *key, *keypub;
+    njs_opaque_value_t         value, pub, priv;
     njs_webcrypto_algorithm_t  *alg;
 
-    static const njs_value_t  string_ml = njs_string("modulusLength");
-    static const njs_value_t  string_priv = njs_string("privateKey");
-    static const njs_value_t  string_pub = njs_string("publicKey");
+    static const njs_str_t  string_ml = njs_str("modulusLength");
+    static const njs_str_t  string_priv = njs_str("privateKey");
+    static const njs_str_t  string_pub = njs_str("publicKey");
 
     ctx = NULL;
 
@@ -2344,8 +2358,8 @@ njs_ext_generate_key(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     }
 
     if (njs_slow_path(usage & ~alg->usage)) {
-        njs_type_error(vm, "unsupported key usage for \"%V\" key",
-                       njs_algorithm_string(alg));
+        njs_vm_error(vm, "unsupported key usage for \"%V\" key",
+                     njs_algorithm_string(alg));
         goto fail;
     }
 
@@ -2358,14 +2372,13 @@ njs_ext_generate_key(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
             goto fail;
         }
 
-        ret = njs_value_property(vm, aobject, njs_value_arg(&string_ml),
-                                 &value);
-        if (njs_slow_path(ret == NJS_ERROR)) {
+        val = njs_vm_object_prop(vm, aobject, &string_ml, &value);
+        if (njs_slow_path(val == NULL)) {
             goto fail;
         }
 
-        if (!njs_is_number(&value)) {
-            njs_type_error(vm, "\"modulusLength\" is not a number");
+        if (!njs_value_is_number(val)) {
+            njs_vm_error(vm, "\"modulusLength\" is not a number");
             goto fail;
         }
 
@@ -2380,7 +2393,7 @@ njs_ext_generate_key(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
             goto fail;
         }
 
-        if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, njs_number(&value)) <= 0) {
+        if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, njs_value_number(val)) <= 0) {
             njs_webcrypto_error(vm, "EVP_PKEY_CTX_set_rsa_keygen_bits() "
                                 "failed");
             goto fail;
@@ -2415,20 +2428,31 @@ njs_ext_generate_key(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
                           ? NJS_KEY_USAGE_ENCRYPT
                           : NJS_KEY_USAGE_VERIFY;
 
-        ret = njs_vm_external_create(vm, &priv,
+        ret = njs_vm_external_create(vm, njs_value_arg(&priv),
                                      njs_webcrypto_crypto_key_proto_id, key, 0);
         if (njs_slow_path(ret != NJS_OK)) {
             goto fail;
         }
 
-        ret = njs_vm_external_create(vm, &pub,
+        ret = njs_vm_external_create(vm, njs_value_arg(&pub),
                                   njs_webcrypto_crypto_key_proto_id, keypub, 0);
         if (njs_slow_path(ret != NJS_OK)) {
             goto fail;
         }
 
-        ret = njs_vm_object_alloc(vm, &value, &string_priv, &priv, &string_pub,
-                                  &pub, NULL);
+        ret = njs_vm_object_alloc(vm, njs_value_arg(&value), NULL);
+        if (ret != NJS_OK) {
+            goto fail;
+        }
+
+        ret = njs_vm_object_prop_set(vm, njs_value_arg(&value), &string_priv,
+                                     &priv);
+        if (ret != NJS_OK) {
+            goto fail;
+        }
+
+        ret = njs_vm_object_prop_set(vm, njs_value_arg(&value), &string_pub,
+                                     &pub);
         if (ret != NJS_OK) {
             goto fail;
         }
@@ -2484,20 +2508,31 @@ njs_ext_generate_key(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
         keypub->curve = key->curve;
         keypub->usage = NJS_KEY_USAGE_VERIFY;
 
-        ret = njs_vm_external_create(vm, &priv,
+        ret = njs_vm_external_create(vm, njs_value_arg(&priv),
                                      njs_webcrypto_crypto_key_proto_id, key, 0);
         if (njs_slow_path(ret != NJS_OK)) {
             goto fail;
         }
 
-        ret = njs_vm_external_create(vm, &pub,
+        ret = njs_vm_external_create(vm, njs_value_arg(&pub),
                                   njs_webcrypto_crypto_key_proto_id, keypub, 0);
         if (njs_slow_path(ret != NJS_OK)) {
             goto fail;
         }
 
-        ret = njs_vm_object_alloc(vm, &value, &string_priv, &priv, &string_pub,
-                                  &pub, NULL);
+        ret = njs_vm_object_alloc(vm, njs_value_arg(&value), NULL);
+        if (ret != NJS_OK) {
+            goto fail;
+        }
+
+        ret = njs_vm_object_prop_set(vm, njs_value_arg(&value), &string_priv,
+                                     &priv);
+        if (ret != NJS_OK) {
+            goto fail;
+        }
+
+        ret = njs_vm_object_prop_set(vm, njs_value_arg(&value), &string_pub,
+                                     &pub);
         if (ret != NJS_OK) {
             goto fail;
         }
@@ -2518,27 +2553,24 @@ njs_ext_generate_key(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
             key->raw.length = EVP_MD_size(njs_algorithm_hash_digest(key->hash));
 
         } else {
-            ret = njs_value_property(vm, aobject, njs_value_arg(&string_length),
-                                     &value);
-            if (njs_slow_path(ret == NJS_ERROR)) {
-                goto fail;
-            }
-
-            key->raw.length = njs_number(&value) / 8;
-
-            if (key->raw.length != 16
-                && key->raw.length != 24
-                && key->raw.length != 32)
-            {
-                njs_type_error(vm, "length for \"%V\" key should be one of "
-                               "128, 192, 256", njs_algorithm_string(alg));
-                goto fail;
+            val = njs_vm_object_prop(vm, aobject, &string_length, &value);
+            if (val != NULL) {
+                key->raw.length = njs_value_number(val) / 8;
+
+                if (key->raw.length != 16
+                    && key->raw.length != 24
+                    && key->raw.length != 32)
+                {
+                    njs_vm_error(vm, "length for \"%V\" key should be one of "
+                                 "128, 192, 256", njs_algorithm_string(alg));
+                    goto fail;
+                }
             }
         }
 
         key->raw.start = njs_mp_alloc(njs_vm_memory_pool(vm), key->raw.length);
         if (njs_slow_path(key->raw.start == NULL)) {
-            njs_memory_error(vm);
+            njs_vm_memory_error(vm);
             goto fail;
         }
 
@@ -2547,7 +2579,7 @@ njs_ext_generate_key(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
             goto fail;
         }
 
-        ret = njs_vm_external_create(vm, &value,
+        ret = njs_vm_external_create(vm, njs_value_arg(&value),
                                      njs_webcrypto_crypto_key_proto_id, key, 0);
         if (njs_slow_path(ret != NJS_OK)) {
             goto fail;
@@ -2556,8 +2588,8 @@ njs_ext_generate_key(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
         break;
 
     default:
-        njs_internal_error(vm, "not implemented generateKey"
-                           "algorithm: \"%V\"", njs_algorithm_string(alg));
+        njs_vm_error(vm, "not implemented generateKey"
+                     "algorithm: \"%V\"", njs_algorithm_string(alg));
         return NJS_ERROR;
     }
 
@@ -2574,13 +2606,13 @@ fail:
 
 
 static BIGNUM *
-njs_import_base64url_bignum(njs_vm_t *vm, njs_value_t *value)
+njs_import_base64url_bignum(njs_vm_t *vm, njs_opaque_value_t *value)
 {
     njs_int_t  ret;
     njs_str_t  data, decoded;
     u_char     buf[512];
 
-    ret = njs_vm_value_to_bytes(vm, &data, value);
+    ret = njs_vm_value_to_bytes(vm, &data, njs_value_arg(value));
     if (njs_slow_path(ret != NJS_OK)) {
         return NULL;
     }
@@ -2609,63 +2641,58 @@ njs_import_jwk_rsa(njs_vm_t *vm, njs_value_t *jwk, njs_webcrypto_key_t *key)
     unsigned               usage;
     EVP_PKEY               *pkey;
     njs_int_t              ret;
-    njs_value_t            n, e, d, p, q, dp, dq, qi, value;
+    njs_value_t            *val;
+    njs_opaque_value_t     n, e, d, p, q, dp, dq, qi, value;
     njs_webcrypto_entry_t  *w;
 
-    ret = njs_value_property(vm, jwk, njs_value_arg(&string_n), &n);
-    if (njs_slow_path(ret == NJS_ERROR)) {
-        return NULL;
+    val = njs_vm_object_prop(vm, jwk, &string_n, &n);
+    if (njs_slow_path(val == NULL)) {
+        goto fail0;
     }
 
-    ret = njs_value_property(vm, jwk, njs_value_arg(&string_e), &e);
-    if (njs_slow_path(ret == NJS_ERROR)) {
-        return NULL;
+    val = njs_vm_object_prop(vm, jwk, &string_e, &e);
+    if (njs_slow_path(val == NULL)) {
+        goto fail0;
     }
 
-    ret = njs_value_property(vm, jwk, njs_value_arg(&string_d), &d);
-    if (njs_slow_path(ret == NJS_ERROR)) {
-        return NULL;
+    val = njs_vm_object_prop(vm, jwk, &string_d, &d);
+    if (njs_slow_path(val == NULL)) {
+        njs_value_undefined_set(njs_value_arg(&d));
     }
 
-    if (!njs_value_is_string(&n)
-        || !njs_value_is_string(&e)
-        || (!njs_value_is_undefined(&d) && !njs_value_is_string(&d)))
+    if (!njs_value_is_string(njs_value_arg(&n))
+        || !njs_value_is_string(njs_value_arg(&e))
+        || (!njs_value_is_undefined(njs_value_arg(&d))
+            && !njs_value_is_string(njs_value_arg(&d))))
     {
-        njs_type_error(vm, "Invalid JWK RSA key");
+fail0:
+        njs_vm_error(vm, "Invalid JWK RSA key");
         return NULL;
     }
 
-    key->privat = njs_value_is_string(&d);
-
-    ret = njs_value_property(vm, jwk, njs_value_arg(&key_ops), &value);
-    if (njs_slow_path(ret == NJS_ERROR)) {
-        return NULL;
-    }
+    key->privat = njs_value_is_string(njs_value_arg(&d));
 
-    if (njs_is_defined(&value)) {
-        ret = njs_key_usage(vm, &value, &usage);
+    val = njs_vm_object_prop(vm, jwk, &key_ops, &value);
+    if (val != NULL && !njs_value_is_undefined(val)){
+        ret = njs_key_usage(vm, val, &usage);
         if (njs_slow_path(ret != NJS_OK)) {
             return NULL;
         }
 
         if ((key->usage & usage) != key->usage) {
-            njs_type_error(vm, "Key operations and usage mismatch");
+            njs_vm_error(vm, "Key operations and usage mismatch");
             return NULL;
         }
     }
 
-    ret = njs_value_property(vm, jwk, njs_value_arg(&string_alg), &value);
-    if (njs_slow_path(ret == NJS_ERROR)) {
-        return NULL;
-    }
-
-    if (njs_is_defined(&value)) {
-        ret = njs_value_to_string(vm, &value, &value);
+    val = njs_vm_object_prop(vm, jwk, &string_alg, &value);
+    if (val != NULL && !njs_value_is_undefined(val)){
+        ret = njs_value_to_string(vm, val, val);
         if (njs_slow_path(ret != NJS_OK)) {
             return NULL;
         }
 
-        njs_string_get(&value, &alg);
+        njs_value_string_get(val, &alg);
 
         for (w = &njs_webcrypto_alg_hash[0]; w->name.length != 0; w++) {
             if (njs_strstr_eq(&alg, &w->name)) {
@@ -2676,13 +2703,12 @@ njs_import_jwk_rsa(njs_vm_t *vm, njs_value_t *jwk, njs_webcrypto_key_t *key)
     }
 
     if (key->extractable) {
-        ret = njs_value_property(vm, jwk, njs_value_arg(&string_ext), &value);
-        if (njs_slow_path(ret == NJS_ERROR)) {
-            return NULL;
-        }
-
-        if (njs_is_defined(&value) && !njs_value_bool(&value)) {
-            njs_type_error(vm, "JWK RSA is not extractable");
+        val = njs_vm_object_prop(vm, jwk, &string_ext, &value);
+        if (val != NULL
+            && !njs_value_is_undefined(val)
+            && !njs_value_bool(val))
+        {
+            njs_vm_error(vm, "JWK RSA is not extractable");
             return NULL;
         }
     }
@@ -2715,39 +2741,40 @@ njs_import_jwk_rsa(njs_vm_t *vm, njs_value_t *jwk, njs_webcrypto_key_t *key)
         goto done;
     }
 
-    ret = njs_value_property(vm, jwk, njs_value_arg(&string_p), &p);
-    if (njs_slow_path(ret == NJS_ERROR)) {
-        goto fail;
+    val = njs_vm_object_prop(vm, jwk, &string_p, &p);
+    if (njs_slow_path(val == NULL)) {
+        goto fail1;
     }
 
-    ret = njs_value_property(vm, jwk, njs_value_arg(&string_q), &q);
-    if (njs_slow_path(ret == NJS_ERROR)) {
-        goto fail;
+    val = njs_vm_object_prop(vm, jwk, &string_q, &q);
+    if (njs_slow_path(val == NULL)) {
+        goto fail1;
     }
 
-    ret = njs_value_property(vm, jwk, njs_value_arg(&string_dp), &dp);
-    if (njs_slow_path(ret == NJS_ERROR)) {
-        goto fail;
+    val = njs_vm_object_prop(vm, jwk, &string_dp, &dp);
+    if (njs_slow_path(val == NULL)) {
+        goto fail1;
     }
 
-    ret = njs_value_property(vm, jwk, njs_value_arg(&string_dq), &dq);
-    if (njs_slow_path(ret == NJS_ERROR)) {
-        goto fail;
+    val = njs_vm_object_prop(vm, jwk, &string_dq, &dq);
+    if (njs_slow_path(val == NULL)) {
+        goto fail1;
     }
 
-    ret = njs_value_property(vm, jwk, njs_value_arg(&string_qi), &qi);
-    if (njs_slow_path(ret == NJS_ERROR)) {
-        goto fail;
+    val = njs_vm_object_prop(vm, jwk, &string_qi, &qi);
+    if (njs_slow_path(val == NULL)) {
+        goto fail1;
     }
 
-    if (!njs_value_is_string(&d)
-        || !njs_value_is_string(&p)
-        || !njs_value_is_string(&q)
-        || !njs_value_is_string(&dp)
-        || !njs_value_is_string(&dq)
-        || !njs_value_is_string(&qi))
+    if (!njs_value_is_string(njs_value_arg(&d))
+        || !njs_value_is_string(njs_value_arg(&p))
+        || !njs_value_is_string(njs_value_arg(&q))
+        || !njs_value_is_string(njs_value_arg(&dp))
+        || !njs_value_is_string(njs_value_arg(&dq))
+        || !njs_value_is_string(njs_value_arg(&qi)))
     {
-        njs_type_error(vm, "Invalid JWK RSA key");
+fail1:
+        njs_vm_error(vm, "Invalid JWK RSA key");
         goto fail;
     }
 
@@ -2902,7 +2929,8 @@ njs_import_jwk_ec(njs_vm_t *vm, njs_value_t *jwk, njs_webcrypto_key_t *key)
     EVP_PKEY               *pkey;
     njs_str_t              name;
     njs_int_t              ret;
-    njs_value_t            x, y, d, value;
+    njs_value_t            *val;
+    njs_opaque_value_t     x, y, d, value;
     njs_webcrypto_entry_t  *e;
 
     ec = NULL;
@@ -2910,77 +2938,73 @@ njs_import_jwk_ec(njs_vm_t *vm, njs_value_t *jwk, njs_webcrypto_key_t *key)
     y_bn = NULL;
     d_bn = NULL;
 
-    ret = njs_value_property(vm, jwk, njs_value_arg(&string_x), &x);
-    if (njs_slow_path(ret == NJS_ERROR)) {
-        return NULL;
+    val = njs_vm_object_prop(vm, jwk, &string_x, &x);
+    if (njs_slow_path(val == NULL)) {
+        goto fail0;
     }
 
-    ret = njs_value_property(vm, jwk, njs_value_arg(&string_y), &y);
-    if (njs_slow_path(ret == NJS_ERROR)) {
-        return NULL;
+    val = njs_vm_object_prop(vm, jwk, &string_y, &y);
+    if (njs_slow_path(val == NULL)) {
+        goto fail0;
     }
 
-    ret = njs_value_property(vm, jwk, njs_value_arg(&string_d), &d);
-    if (njs_slow_path(ret == NJS_ERROR)) {
-        return NULL;
+    val = njs_vm_object_prop(vm, jwk, &string_d, &d);
+    if (njs_slow_path(val == NULL)) {
+        njs_value_undefined_set(njs_value_arg(&d));
     }
 
-    if (!njs_value_is_string(&x)
-        || !njs_value_is_string(&y)
-        || (!njs_value_is_undefined(&d) && !njs_value_is_string(&d)))
+    if (!njs_value_is_string(njs_value_arg(&x))
+        || !njs_value_is_string(njs_value_arg(&y))
+        || (!njs_value_is_undefined(njs_value_arg(&d))
+            && !njs_value_is_string(njs_value_arg(&d))))
     {
-        njs_type_error(vm, "Invalid JWK EC key");
+fail0:
+        njs_vm_error(vm, "Invalid JWK EC key");
         return NULL;
     }
 
-    key->privat = njs_value_is_string(&d);
+    key->privat = njs_value_is_string(njs_value_arg(&d));
 
-    ret = njs_value_property(vm, jwk, njs_value_arg(&key_ops), &value);
-    if (njs_slow_path(ret == NJS_ERROR)) {
-        return NULL;
-    }
-
-    if (njs_is_defined(&value)) {
-        ret = njs_key_usage(vm, &value, &usage);
+    val = njs_vm_object_prop(vm, jwk, &key_ops, &value);
+    if (val != NULL && !njs_value_is_undefined(val)) {
+        ret = njs_key_usage(vm, val, &usage);
         if (njs_slow_path(ret != NJS_OK)) {
             return NULL;
         }
 
         if ((key->usage & usage) != key->usage) {
-            njs_type_error(vm, "Key operations and usage mismatch");
+            njs_vm_error(vm, "Key operations and usage mismatch");
             return NULL;
         }
     }
 
     if (key->extractable) {
-        ret = njs_value_property(vm, jwk, njs_value_arg(&string_ext), &value);
-        if (njs_slow_path(ret == NJS_ERROR)) {
+        val = njs_vm_object_prop(vm, jwk, &string_ext, &value);
+        if (val != NULL
+            && !njs_value_is_undefined(val)
+            && !njs_value_bool(val))
+        {
+            njs_vm_error(vm, "JWK EC is not extractable");
             return NULL;
         }
-
-        if (njs_is_defined(&value) && !njs_value_bool(&value)) {
-            njs_type_error(vm, "JWK EC is not extractable");
-            return NULL;
-        }
-    }
-
-    ret = njs_value_property(vm, jwk, njs_value_arg(&string_crv), &value);
-    if (njs_slow_path(ret == NJS_ERROR)) {
-        return NULL;
     }
 
     curve = 0;
-    njs_string_get(&value, &name);
 
-    for (e = &njs_webcrypto_curve[0]; e->name.length != 0; e++) {
-        if (njs_strstr_eq(&name, &e->name)) {
-            curve = e->value;
-            break;
+    val = njs_vm_object_prop(vm, jwk, &string_crv, &value);
+    if (val != NULL && !njs_value_is_undefined(val)) {
+        njs_value_string_get(val, &name);
+
+        for (e = &njs_webcrypto_curve[0]; e->name.length != 0; e++) {
+            if (njs_strstr_eq(&name, &e->name)) {
+                curve = e->value;
+                break;
+            }
         }
     }
 
     if (curve != key->curve) {
-        njs_type_error(vm, "JWK EC curve mismatch");
+        njs_vm_error(vm, "JWK EC curve mismatch");
         return NULL;
     }
 
@@ -3076,7 +3100,8 @@ njs_import_jwk_oct(njs_vm_t *vm, njs_value_t *jwk, njs_webcrypto_key_t *key)
     unsigned               usage;
     njs_int_t              ret;
     njs_str_t              *a, alg, b64;
-    njs_value_t            value;
+    njs_value_t            *val;
+    njs_opaque_value_t     value;
     njs_webcrypto_alg_t    type;
     njs_webcrypto_entry_t  *w;
 
@@ -3088,37 +3113,29 @@ njs_import_jwk_oct(njs_vm_t *vm, njs_value_t *jwk, njs_webcrypto_key_t *key)
         { njs_null_str, 0 }
     };
 
-    ret = njs_value_property(vm, jwk, njs_value_arg(&string_k), &value);
-    if (njs_slow_path(ret == NJS_ERROR)) {
-        return NJS_ERROR;
-    }
-
-    if (!njs_value_is_string(&value)) {
-        njs_type_error(vm, "Invalid JWK oct key");
+    val = njs_vm_object_prop(vm, jwk, &string_k, &value);
+    if (njs_slow_path(val == NULL || !njs_value_is_string(val))) {
+        njs_vm_error(vm, "Invalid JWK oct key");
         return NJS_ERROR;
     }
 
-    njs_string_get(&value, &b64);
+    njs_value_string_get(val, &b64);
 
     (void) njs_decode_base64url_length(&b64, &key->raw.length);
 
     key->raw.start = njs_mp_alloc(njs_vm_memory_pool(vm), key->raw.length);
     if (njs_slow_path(key->raw.start == NULL)) {
-        njs_memory_error(vm);
+        njs_vm_memory_error(vm);
         return NJS_ERROR;
     }
 
     njs_decode_base64url(&key->raw, &b64);
 
-    ret = njs_value_property(vm, jwk, njs_value_arg(&string_alg), &value);
-    if (njs_slow_path(ret == NJS_ERROR)) {
-        return NJS_ERROR;
-    }
-
     size = 16;
 
-    if (njs_value_is_string(&value)) {
-        njs_string_get(&value, &alg);
+    val = njs_vm_object_prop(vm, jwk, &string_alg, &value);
+    if (val != NULL && njs_value_is_string(val)) {
+        njs_value_string_get(val, &alg);
 
         if (key->alg->type == NJS_ALGORITHM_HMAC) {
             for (w = &hashes[0]; w->name.length != 0; w++) {
@@ -3140,7 +3157,7 @@ njs_import_jwk_oct(njs_vm_t *vm, njs_value_t *jwk, njs_webcrypto_key_t *key)
             }
         }
 
-        njs_type_error(vm, "unexpected \"alg\" value \"%V\" for JWK key", &alg);
+        njs_vm_error(vm, "unexpected \"alg\" value \"%V\" for JWK key", &alg);
         return NJS_ERROR;
     }
 
@@ -3148,37 +3165,32 @@ done:
 
     if (key->alg->type != NJS_ALGORITHM_HMAC) {
         if (key->raw.length != size) {
-            njs_type_error(vm, "key size and \"alg\" value \"%V\" mismatch",
-                           &alg);
+            njs_vm_error(vm, "key size and \"alg\" value \"%V\" mismatch",
+                         &alg);
             return NJS_ERROR;
         }
     }
 
-    ret = njs_value_property(vm, jwk, njs_value_arg(&key_ops), &value);
-    if (njs_slow_path(ret == NJS_ERROR)) {
-        return NJS_ERROR;
-    }
-
-    if (njs_is_defined(&value)) {
-        ret = njs_key_usage(vm, &value, &usage);
+    val = njs_vm_object_prop(vm, jwk, &key_ops, &value);
+    if (val != NULL && !njs_value_is_undefined(val)) {
+        ret = njs_key_usage(vm, val, &usage);
         if (njs_slow_path(ret != NJS_OK)) {
             return NJS_ERROR;
         }
 
         if ((key->usage & usage) != key->usage) {
-            njs_type_error(vm, "Key operations and usage mismatch");
+            njs_vm_error(vm, "Key operations and usage mismatch");
             return NJS_ERROR;
         }
     }
 
     if (key->extractable) {
-        ret = njs_value_property(vm, jwk, njs_value_arg(&string_ext), &value);
-        if (njs_slow_path(ret == NJS_ERROR)) {
-            return NJS_ERROR;
-        }
-
-        if (njs_is_defined(&value) && !njs_value_bool(&value)) {
-            njs_type_error(vm, "JWK oct is not extractable");
+        val = njs_vm_object_prop(vm, jwk, &string_ext, &value);
+        if (val != NULL
+            && !njs_value_is_undefined(val)
+            && !njs_value_bool(val))
+        {
+            njs_vm_error(vm, "JWK oct is not extractable");
             return NJS_ERROR;
         }
     }
@@ -3203,13 +3215,14 @@ njs_ext_import_key(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     EVP_PKEY                    *pkey;
     njs_int_t                   ret;
     njs_str_t                   key_data, kty;
-    njs_value_t                 value, *options, *jwk;
+    njs_value_t                 *options, *jwk, *val;
     const u_char                *start;
 #if (OPENSSL_VERSION_NUMBER < 0x30000000L)
     const EC_GROUP              *group;
 #endif
     njs_webcrypto_key_t         *key;
     PKCS8_PRIV_KEY_INFO         *pkcs8;
+    njs_opaque_value_t          value;
     njs_webcrypto_hash_t        hash;
     njs_webcrypto_algorithm_t   *alg;
     njs_webcrypto_key_format_t  fmt;
@@ -3230,9 +3243,9 @@ njs_ext_import_key(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     }
 
     if (njs_slow_path(!(fmt & alg->fmt))) {
-        njs_type_error(vm, "unsupported key fmt \"%V\" for \"%V\" key",
-                       njs_format_string(fmt),
-                       njs_algorithm_string(alg));
+        njs_vm_error(vm, "unsupported key fmt \"%V\" for \"%V\" key",
+                     njs_format_string(fmt),
+                     njs_algorithm_string(alg));
         goto fail;
     }
 
@@ -3242,8 +3255,8 @@ njs_ext_import_key(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     }
 
     if (njs_slow_path(usage & ~alg->usage)) {
-        njs_type_error(vm, "unsupported key usage for \"%V\" key",
-                       njs_algorithm_string(alg));
+        njs_vm_error(vm, "unsupported key usage for \"%V\" key",
+                     njs_algorithm_string(alg));
         goto fail;
     }
 
@@ -3314,16 +3327,16 @@ njs_ext_import_key(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     case NJS_KEY_FORMAT_JWK:
         jwk = njs_arg(args, nargs, 2);
         if (!njs_value_is_object(jwk)) {
-            njs_type_error(vm, "invalid JWK key data: object value expected");
+            njs_vm_error(vm, "invalid JWK key data: object value expected");
             goto fail;
         }
 
-        ret = njs_value_property(vm, jwk, njs_value_arg(&string_kty), &value);
-        if (njs_slow_path(ret == NJS_ERROR)) {
-            goto fail;
+        val = njs_vm_object_prop(vm, jwk, &string_kty, &value);
+        if (njs_slow_path(val == NULL)) {
+            val = njs_value_arg(&njs_value_undefined);
         }
 
-        ret = njs_vm_value_to_bytes(vm, &kty, &value);
+        ret = njs_vm_value_to_bytes(vm, &kty, val);
         if (njs_slow_path(ret != NJS_OK)) {
             goto fail;
         }
@@ -3352,7 +3365,7 @@ njs_ext_import_key(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
             }
 
         } else {
-            njs_type_error(vm, "invalid JWK key type: %V", &kty);
+            njs_vm_error(vm, "invalid JWK key type: %V", &kty);
             goto fail;
         }
 
@@ -3391,7 +3404,7 @@ njs_ext_import_key(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
         }
 
         if (key->hash != NJS_HASH_UNSET && key->hash != hash) {
-            njs_type_error(vm, "RSA JWK hash mismatch");
+            njs_vm_error(vm, "RSA JWK hash mismatch");
             goto fail;
         }
 
@@ -3406,8 +3419,8 @@ njs_ext_import_key(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
         }
 
         if (key->usage & mask) {
-            njs_type_error(vm, "key usage mismatch for \"%V\" key",
-                           njs_algorithm_string(alg));
+            njs_vm_error(vm, "key usage mismatch for \"%V\" key",
+                         njs_algorithm_string(alg));
             goto fail;
         }
 
@@ -3466,8 +3479,8 @@ njs_ext_import_key(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
         mask = key->privat ? ~NJS_KEY_USAGE_SIGN : ~NJS_KEY_USAGE_VERIFY;
 
         if (key->usage & mask) {
-            njs_type_error(vm, "key usage mismatch for \"%V\" key",
-                           njs_algorithm_string(alg));
+            njs_vm_error(vm, "key usage mismatch for \"%V\" key",
+                         njs_algorithm_string(alg));
             goto fail;
         }
 
@@ -3493,7 +3506,7 @@ njs_ext_import_key(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
             }
 
             if (key->hash != NJS_HASH_UNSET && key->hash != hash) {
-                njs_type_error(vm, "HMAC JWK hash mismatch");
+                njs_vm_error(vm, "HMAC JWK hash mismatch");
                 goto fail;
             }
         }
@@ -3511,7 +3524,7 @@ njs_ext_import_key(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
                 break;
 
             default:
-                njs_type_error(vm, "AES Invalid key length");
+                njs_vm_error(vm, "AES Invalid key length");
                 goto fail;
             }
 
@@ -3527,8 +3540,8 @@ njs_ext_import_key(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
         break;
     }
 
-    ret = njs_vm_external_create(vm, &value, njs_webcrypto_crypto_key_proto_id,
-                                 key, 0);
+    ret = njs_vm_external_create(vm, njs_value_arg(&value),
+                                 njs_webcrypto_crypto_key_proto_id, key, 0);
     if (njs_slow_path(ret != NJS_OK)) {
         goto fail;
     }
@@ -3549,12 +3562,13 @@ static njs_int_t
 njs_set_rsa_padding(njs_vm_t *vm, njs_value_t *options, EVP_PKEY *pkey,
     EVP_PKEY_CTX *ctx, njs_webcrypto_alg_t type)
 {
-    int          padding;
-    int64_t      salt_length;
-    njs_int_t    ret;
-    njs_value_t  value;
+    int                 padding;
+    int64_t             salt_length;
+    njs_int_t           ret;
+    njs_value_t         *value;
+    njs_opaque_value_t  lvalue;
 
-    static const njs_value_t  string_saltl = njs_string("saltLength");
+    static const njs_str_t  string_saltl = njs_str("saltLength");
 
     if (type == NJS_ALGORITHM_ECDSA) {
         return NJS_OK;
@@ -3569,18 +3583,13 @@ njs_set_rsa_padding(njs_vm_t *vm, njs_value_t *options, EVP_PKEY *pkey,
     }
 
     if (padding == RSA_PKCS1_PSS_PADDING) {
-        ret = njs_value_property(vm, options, njs_value_arg(&string_saltl),
-                                 &value);
-        if (njs_slow_path(ret != NJS_OK)) {
-            if (ret == NJS_DECLINED) {
-                njs_type_error(vm, "RSA-PSS algorithm.saltLength "
-                               "is not provided");
-            }
-
+        value = njs_vm_object_prop(vm, options, &string_saltl, &lvalue);
+        if (njs_slow_path(value == NULL)) {
+            njs_vm_error(vm, "RSA-PSS algorithm.saltLength is not provided");
             return NJS_ERROR;
         }
 
-        ret = njs_value_to_integer(vm, &value, &salt_length);
+        ret = njs_value_to_integer(vm, value, &salt_length);
         if (njs_slow_path(ret != NJS_OK)) {
             return NJS_ERROR;
         }
@@ -3778,9 +3787,10 @@ njs_ext_sign(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_int_t                  ret;
     njs_str_t                  data, sig;
     EVP_MD_CTX                 *mctx;
-    njs_value_t                value, *options;
+    njs_value_t                *options;
     EVP_PKEY_CTX               *pctx;
     const EVP_MD               *md;
+    njs_opaque_value_t         result;
     njs_webcrypto_key_t        *key;
     njs_webcrypto_hash_t       hash;
     njs_webcrypto_algorithm_t  *alg;
@@ -3798,21 +3808,21 @@ njs_ext_sign(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     key = njs_vm_external(vm, njs_webcrypto_crypto_key_proto_id,
                           njs_arg(args, nargs, 2));
     if (njs_slow_path(key == NULL)) {
-        njs_type_error(vm, "\"key\" is not a CryptoKey object");
+        njs_vm_error(vm, "\"key\" is not a CryptoKey object");
         goto fail;
     }
 
     mask = verify ? NJS_KEY_USAGE_VERIFY : NJS_KEY_USAGE_SIGN;
     if (njs_slow_path(!(key->usage & mask))) {
-        njs_type_error(vm, "provide key does not support \"sign\" operation");
+        njs_vm_error(vm, "provide key does not support \"sign\" operation");
         goto fail;
     }
 
     if (njs_slow_path(key->alg != alg)) {
-        njs_type_error(vm, "cannot %s using \"%V\" with \"%V\" key",
-                       verify ? "verify" : "sign",
-                       njs_algorithm_string(key->alg),
-                       njs_algorithm_string(alg));
+        njs_vm_error(vm, "cannot %s using \"%V\" with \"%V\" key",
+                     verify ? "verify" : "sign",
+                     njs_algorithm_string(key->alg),
+                     njs_algorithm_string(alg));
         goto fail;
     }
 
@@ -3855,7 +3865,7 @@ njs_ext_sign(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
         if (!verify) {
             dst = njs_mp_alloc(njs_vm_memory_pool(vm), m_len);
             if (njs_slow_path(dst == NULL)) {
-                njs_memory_error(vm);
+                njs_vm_memory_error(vm);
                 goto fail;
             }
 
@@ -3910,7 +3920,7 @@ njs_ext_sign(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
         olen = EVP_PKEY_size(key->pkey);
         dst = njs_mp_zalloc(njs_vm_memory_pool(vm), olen);
         if (njs_slow_path(dst == NULL)) {
-            njs_memory_error(vm);
+            njs_vm_memory_error(vm);
             goto fail;
         }
 
@@ -3987,16 +3997,17 @@ njs_ext_sign(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     }
 
     if (!verify) {
-        ret = njs_vm_value_array_buffer_set(vm, &value, dst, outlen);
+        ret = njs_vm_value_array_buffer_set(vm, njs_value_arg(&result), dst,
+                                            outlen);
         if (njs_slow_path(ret != NJS_OK)) {
             goto fail;
         }
 
     } else {
-        njs_set_boolean(&value, ret != 0);
+        njs_value_boolean_set(njs_value_arg(&result), ret != 0);
     }
 
-    return njs_webcrypto_result(vm, &value, NJS_OK, retval);
+    return njs_webcrypto_result(vm, &result, NJS_OK, retval);
 
 fail:
 
@@ -4016,7 +4027,7 @@ static njs_int_t
 njs_ext_unwrap_key(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t unused, njs_value_t *retval)
 {
-    njs_internal_error(vm, "\"unwrapKey\" not implemented");
+    njs_vm_error(vm, "\"unwrapKey\" not implemented");
     return NJS_ERROR;
 }
 
@@ -4025,7 +4036,7 @@ static njs_int_t
 njs_ext_wrap_key(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t unused, njs_value_t *retval)
 {
-    njs_internal_error(vm, "\"wrapKey\" not implemented");
+    njs_vm_error(vm, "\"wrapKey\" not implemented");
     return NJS_ERROR;
 }
 
@@ -4046,7 +4057,7 @@ njs_ext_get_random_values(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     }
 
     if (njs_slow_path(fill.length > 65536)) {
-        njs_type_error(vm, "requested length exceeds 65536 bytes");
+        njs_vm_error(vm, "requested length exceeds 65536 bytes");
         return NJS_ERROR;
     }
 
@@ -4081,13 +4092,13 @@ njs_webcrypto_key_alloc(njs_vm_t *vm, njs_webcrypto_algorithm_t *alg,
 
     key = njs_mp_zalloc(njs_vm_memory_pool(vm), sizeof(njs_webcrypto_key_t));
     if (njs_slow_path(key == NULL)) {
-        njs_memory_error(vm);
+        njs_vm_memory_error(vm);
         return NULL;
     }
 
     cln = njs_mp_cleanup_add(njs_vm_memory_pool(vm), 0);
     if (cln == NULL) {
-        njs_memory_error(vm);
+        njs_vm_memory_error(vm);
         return NULL;
     }
 
@@ -4107,15 +4118,15 @@ njs_key_format(njs_vm_t *vm, njs_value_t *value)
 {
     njs_int_t              ret;
     njs_str_t              format;
-    njs_value_t            string;
+    njs_opaque_value_t     string;
     njs_webcrypto_entry_t  *e;
 
-    ret = njs_value_to_string(vm, &string, value);
+    ret = njs_value_to_string(vm, njs_value_arg(&string), value);
     if (njs_slow_path(ret != NJS_OK)) {
         return NJS_KEY_FORMAT_UNKNOWN;
     }
 
-    njs_string_get(&string, &format);
+    njs_value_string_get(njs_value_arg(&string), &format);
 
     for (e = &njs_webcrypto_format[0]; e->name.length != 0; e++) {
         if (njs_strstr_eq(&format, &e->name)) {
@@ -4123,7 +4134,7 @@ njs_key_format(njs_vm_t *vm, njs_value_t *value)
         }
     }
 
-    njs_type_error(vm, "unknown key format: \"%V\"", &format);
+    njs_vm_error(vm, "unknown key format: \"%V\"", &format);
 
     return NJS_KEY_FORMAT_UNKNOWN;
 }
@@ -4151,17 +4162,17 @@ njs_key_usage_array_handler(njs_vm_t *vm, njs_iterator_args_t *args,
     unsigned               *mask;
     njs_str_t              u;
     njs_int_t              ret;
-    njs_value_t            usage;
+    njs_opaque_value_t     usage;
     njs_webcrypto_entry_t  *e;
 
     njs_value_assign(&usage, value);
 
-    ret = njs_value_to_string(vm, &usage, &usage);
+    ret = njs_value_to_string(vm, njs_value_arg(&usage), njs_value_arg(&usage));
     if (njs_slow_path(ret != NJS_OK)) {
         return NJS_ERROR;
     }
 
-    njs_string_get(&usage, &u);
+    njs_value_string_get(njs_value_arg(&usage), &u);
 
     for (e = &njs_webcrypto_usage[0]; e->name.length != 0; e++) {
         if (njs_strstr_eq(&u, &e->name)) {
@@ -4171,7 +4182,7 @@ njs_key_usage_array_handler(njs_vm_t *vm, njs_iterator_args_t *args,
         }
     }
 
-    njs_type_error(vm, "unknown key usage: \"%V\"", &u);
+    njs_vm_error(vm, "unknown key usage: \"%V\"", &u);
 
     return NJS_ERROR;
 }
@@ -4182,15 +4193,15 @@ njs_key_usage(njs_vm_t *vm, njs_value_t *value, unsigned *mask)
 {
     int64_t              length;
     njs_int_t            ret;
-    njs_value_t          retval;
+    njs_opaque_value_t   retval;
     njs_iterator_args_t  args;
 
-    if (!njs_value_is_object(value)) {
-        njs_type_error(vm, "\"keyUsages\" argument must be an Array");
+    if (!njs_value_is_array(value)) {
+        njs_vm_error(vm, "\"keyUsages\" argument must be an Array");
         return NJS_ERROR;
     }
 
-    ret = njs_object_length(vm, value, &length);
+    ret = njs_vm_array_length(vm, value, &length);
     if (njs_slow_path(ret != NJS_OK)) {
         return NJS_ERROR;
     }
@@ -4202,26 +4213,26 @@ njs_key_usage(njs_vm_t *vm, njs_value_t *value, unsigned *mask)
     args.to = length;
     args.data = mask;
 
-    return njs_object_iterate(vm, &args, njs_key_usage_array_handler,
-                              &retval);
+    return njs_vm_object_iterate(vm, &args, njs_key_usage_array_handler,
+                                 njs_value_arg(&retval));
 }
 
 
 static njs_int_t
-njs_key_ops(njs_vm_t *vm, njs_value_t *retval, unsigned mask)
+njs_key_ops(njs_vm_t *vm, njs_opaque_value_t *retval, unsigned mask)
 {
     njs_int_t              ret;
     njs_value_t            *value;
     njs_webcrypto_entry_t  *e;
 
-    ret = njs_vm_array_alloc(vm, retval, 4);
+    ret = njs_vm_array_alloc(vm, njs_value_arg(retval), 4);
     if (njs_slow_path(ret != NJS_OK)) {
         return NJS_ERROR;
     }
 
     for (e = &njs_webcrypto_usage[0]; e->name.length != 0; e++) {
         if (mask & e->value) {
-            value = njs_vm_array_push(vm, retval);
+            value = njs_vm_array_push(vm, njs_value_arg(retval));
             if (value == NULL) {
                 return NJS_ERROR;
             }
@@ -4243,20 +4254,17 @@ njs_key_algorithm(njs_vm_t *vm, njs_value_t *options)
 {
     njs_int_t                  ret;
     njs_str_t                  a;
-    njs_value_t                name;
+    njs_value_t                *val;
+    njs_opaque_value_t         name;
     njs_webcrypto_entry_t      *e;
     njs_webcrypto_algorithm_t  *alg;
 
-    static const njs_value_t  string_name = njs_string("name");
-
-    if (njs_is_object(options)) {
-        ret = njs_value_property(vm, options, njs_value_arg(&string_name),
-                                 &name);
-        if (njs_slow_path(ret != NJS_OK)) {
-            if (ret == NJS_DECLINED) {
-                njs_type_error(vm, "algorithm name is not provided");
-            }
+    static const njs_str_t  string_name = njs_str("name");
 
+    if (njs_value_is_object(options)) {
+        val = njs_vm_object_prop(vm, options, &string_name, &name);
+        if (njs_slow_path(val == NULL)) {
+            njs_vm_error(vm, "algorithm name is not provided");
             return NULL;
         }
 
@@ -4264,18 +4272,18 @@ njs_key_algorithm(njs_vm_t *vm, njs_value_t *options)
         njs_value_assign(&name, options);
     }
 
-    ret = njs_value_to_string(vm, &name, &name);
+    ret = njs_value_to_string(vm, njs_value_arg(&name), njs_value_arg(&name));
     if (njs_slow_path(ret != NJS_OK)) {
         return NULL;
     }
 
-    njs_string_get(&name, &a);
+    njs_value_string_get(njs_value_arg(&name), &a);
 
     for (e = &njs_webcrypto_alg[0]; e->name.length != 0; e++) {
         if (njs_strstr_case_eq(&a, &e->name)) {
             alg = (njs_webcrypto_algorithm_t *) e->value;
             if (alg->usage & NJS_KEY_USAGE_UNSUPPORTED) {
-                njs_type_error(vm, "unsupported algorithm: \"%V\"", &a);
+                njs_vm_error(vm, "unsupported algorithm: \"%V\"", &a);
                 return NULL;
             }
 
@@ -4283,7 +4291,7 @@ njs_key_algorithm(njs_vm_t *vm, njs_value_t *options)
         }
     }
 
-    njs_type_error(vm, "unknown algorithm name: \"%V\"", &a);
+    njs_vm_error(vm, "unknown algorithm name: \"%V\"", &a);
 
     return NULL;
 }
@@ -4312,28 +4320,28 @@ njs_algorithm_hash(njs_vm_t *vm, njs_value_t *options,
 {
     njs_int_t              ret;
     njs_str_t              name;
-    njs_value_t            value;
+    njs_value_t            *val;
+    njs_opaque_value_t     value;
     njs_webcrypto_entry_t  *e;
 
-    static const njs_value_t  string_hash = njs_string("hash");
+    static const njs_str_t  string_hash = njs_str("hash");
 
-    if (njs_is_object(options)) {
-        ret = njs_value_property(vm, options, njs_value_arg(&string_hash),
-                                 &value);
-        if (njs_slow_path(ret == NJS_ERROR)) {
-            return NJS_ERROR;
+    if (njs_value_is_object(options)) {
+        val = njs_vm_object_prop(vm, options, &string_hash, &value);
+        if (njs_slow_path(val == NULL)) {
+            njs_value_undefined_set(njs_value_arg(&value));
         }
 
     } else {
         njs_value_assign(&value, options);
     }
 
-    ret = njs_value_to_string(vm, &value, &value);
+    ret = njs_value_to_string(vm, njs_value_arg(&value), njs_value_arg(&value));
     if (njs_slow_path(ret != NJS_OK)) {
         return NJS_ERROR;
     }
 
-    njs_string_get(&value, &name);
+    njs_value_string_get(njs_value_arg(&value), &name);
 
     for (e = &njs_webcrypto_hash[0]; e->name.length != 0; e++) {
         if (njs_strstr_eq(&name, &e->name)) {
@@ -4342,7 +4350,7 @@ njs_algorithm_hash(njs_vm_t *vm, njs_value_t *options,
         }
     }
 
-    njs_type_error(vm, "unknown hash name: \"%V\"", &name);
+    njs_vm_error(vm, "unknown hash name: \"%V\"", &name);
 
     return NJS_ERROR;
 }
@@ -4375,27 +4383,27 @@ njs_algorithm_curve(njs_vm_t *vm, njs_value_t *options, int *curve)
 {
     njs_int_t              ret;
     njs_str_t              name;
-    njs_value_t            value;
+    njs_value_t            *val;
+    njs_opaque_value_t     value;
     njs_webcrypto_entry_t  *e;
 
-    static const njs_value_t  string_curve = njs_string("namedCurve");
+    static const njs_str_t  string_curve = njs_str("namedCurve");
 
     if (*curve != 0) {
         return NJS_OK;
     }
 
-    ret = njs_value_property(vm, options, njs_value_arg(&string_curve),
-                             &value);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return ret;
+    val = njs_vm_object_prop(vm, options, &string_curve, &value);
+    if (njs_slow_path(val == NULL)) {
+        njs_value_undefined_set(njs_value_arg(&value));
     }
 
-    ret = njs_value_to_string(vm, &value, &value);
+    ret = njs_value_to_string(vm, njs_value_arg(&value), njs_value_arg(&value));
     if (njs_slow_path(ret != NJS_OK)) {
         return NJS_ERROR;
     }
 
-    njs_string_get(&value, &name);
+    njs_value_string_get(njs_value_arg(&value), &name);
 
     for (e = &njs_webcrypto_curve[0]; e->name.length != 0; e++) {
         if (njs_strstr_eq(&name, &e->name)) {
@@ -4404,7 +4412,7 @@ njs_algorithm_curve(njs_vm_t *vm, njs_value_t *options, int *curve)
         }
     }
 
-    njs_type_error(vm, "unknown namedCurve: \"%V\"", &name);
+    njs_vm_error(vm, "unknown namedCurve: \"%V\"", &name);
 
     return NJS_ERROR;
 }
@@ -4427,15 +4435,16 @@ njs_promise_trampoline(njs_vm_t *vm, njs_value_t *args,
 
 
 static njs_int_t
-njs_webcrypto_result(njs_vm_t *vm, njs_value_t *result, njs_int_t rc,
+njs_webcrypto_result(njs_vm_t *vm, njs_opaque_value_t *result, njs_int_t rc,
     njs_value_t *retval)
 {
-    njs_int_t       ret;
-    njs_value_t     promise, arguments[2];
-    njs_function_t  *callback;
-    njs_vm_event_t  vm_event;
+    njs_int_t           ret;
+    njs_function_t      *callback;
+    njs_vm_event_t      vm_event;
+    njs_opaque_value_t  promise, arguments[2];
 
-    ret = njs_vm_promise_create(vm, &promise, njs_value_arg(&arguments));
+    ret = njs_vm_promise_create(vm, njs_value_arg(&promise),
+                                njs_value_arg(&arguments));
     if (ret != NJS_OK) {
         goto error;
     }
@@ -4484,7 +4493,7 @@ njs_webcrypto_array_buffer(njs_vm_t *vm, njs_value_t *retval,
 
     dst = njs_mp_alloc(njs_vm_memory_pool(vm), length);
     if (njs_slow_path(dst == NULL)) {
-        njs_memory_error(vm);
+        njs_vm_memory_error(vm);
         return NJS_ERROR;
     }
 
index 34e95e0f3d2ddc03441b5e147d824ec2fd242273..7a091e66c0c7d76e7c9533d5223f420130b2a932 100644 (file)
--- a/src/njs.h
+++ b/src/njs.h
@@ -304,6 +304,23 @@ typedef struct {
 } njs_vm_opt_t;
 
 
+typedef struct {
+    njs_function_t      *function;
+    njs_opaque_value_t  argument;
+    njs_opaque_value_t  value;
+
+    void                *data;
+
+    int64_t             from;
+    int64_t             to;
+} njs_iterator_args_t;
+
+
+typedef njs_int_t (*njs_iterator_handler_t)(njs_vm_t *vm,
+    njs_iterator_args_t *args, njs_value_t *entry, int64_t n,
+    njs_value_t *retval);
+
+
 NJS_EXPORT void njs_vm_opt_init(njs_vm_opt_t *options);
 NJS_EXPORT njs_vm_t *njs_vm_create(njs_vm_opt_t *options);
 NJS_EXPORT void njs_vm_destroy(njs_vm_t *vm);
@@ -520,6 +537,9 @@ NJS_EXPORT njs_value_t *njs_vm_object_prop(njs_vm_t *vm,
     njs_value_t *value, const njs_str_t *key, njs_opaque_value_t *retval);
 NJS_EXPORT njs_int_t njs_vm_object_prop_set(njs_vm_t *vm, njs_value_t *value,
     const njs_str_t *prop, njs_opaque_value_t *setval);
+NJS_EXPORT njs_int_t njs_vm_object_iterate(njs_vm_t *vm,
+    njs_iterator_args_t *args, njs_iterator_handler_t handler,
+    njs_value_t *retval);
 
 NJS_EXPORT njs_int_t njs_vm_array_alloc(njs_vm_t *vm, njs_value_t *retval,
     uint32_t spare);
index f04fa9315c720c592e0394485eb9a2e1b6aa4ae2..3ff079b028bbc732fd259b814f5d1fa2bf5d576d 100644 (file)
@@ -8,23 +8,6 @@
 #define _NJS_ITERATOR_H_INCLUDED_
 
 
-typedef struct {
-    njs_function_t      *function;
-    njs_opaque_value_t  argument;
-    njs_opaque_value_t  value;
-
-    void                *data;
-
-    int64_t             from;
-    int64_t             to;
-} njs_iterator_args_t;
-
-
-typedef njs_int_t (*njs_iterator_handler_t)(njs_vm_t *vm,
-    njs_iterator_args_t *args, njs_value_t *entry, int64_t n,
-    njs_value_t *retval);
-
-
 njs_int_t njs_array_iterator_create(njs_vm_t *vm, const njs_value_t *src,
     njs_value_t *dst, njs_object_enum_t kind);
 
index 90a1795385ab1dc617a5ac85d6f9fef0c7439674..cf1b271bdebe3479eb26e1a5913e4c5c9d0870b6 100644 (file)
@@ -1215,6 +1215,14 @@ njs_vm_array_prop(njs_vm_t *vm, njs_value_t *value, int64_t index,
 }
 
 
+njs_int_t
+njs_vm_object_iterate(njs_vm_t *vm, njs_iterator_args_t *args,
+    njs_iterator_handler_t handler, njs_value_t *retval)
+{
+    return njs_object_iterate(vm, args, handler, retval);
+}
+
+
 njs_value_t *
 njs_vm_array_start(njs_vm_t *vm, njs_value_t *value)
 {
index 3d82680727cfe0a0c8c19ec8859edc7ad879ffe8..d9d6b48ff4c6166d62bc73cf40d46f0eb3c87d97 100644 (file)
@@ -13,7 +13,7 @@ async function run(tlist) {
         }
 
         if (r.status == "rejected" && t[i].optional) {
-            return r.reason.toString().startsWith("InternalError: not implemented");
+            return r.reason.toString().startsWith("Error: not implemented");
         }
 
         return false;