#endif
static njs_int_t njs_ext_import_key(njs_vm_t *vm, njs_value_t *args,
njs_uint_t nargs, njs_index_t unused, njs_value_t *retval);
+static njs_int_t njs_webcrypto_import_key_internal(njs_vm_t *vm,
+ njs_webcrypto_key_format_t fmt, njs_value_t *key_data,
+ njs_webcrypto_algorithm_t *alg, njs_value_t *options,
+ njs_bool_t extractable, unsigned usage, njs_value_t *retval);
static njs_int_t njs_ext_sign(njs_vm_t *vm, njs_value_t *args,
njs_uint_t nargs, njs_index_t verify, njs_value_t *retval);
static njs_int_t njs_webcrypto_export_key_raw(njs_vm_t *vm,
static njs_int_t
-njs_ext_import_key(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
- njs_index_t unused, njs_value_t *retval)
+njs_webcrypto_import_key_internal(njs_vm_t *vm, njs_webcrypto_key_format_t fmt,
+ njs_value_t *key_data, njs_webcrypto_algorithm_t *alg, njs_value_t *options,
+ njs_bool_t extractable, unsigned usage, njs_value_t *retval)
{
- int nid;
- BIO *bio;
+ int nid;
+ BIO *bio;
#if (OPENSSL_VERSION_NUMBER < 0x30000000L)
- RSA *rsa;
- EC_KEY *ec;
+ RSA *rsa;
+ EC_KEY *ec;
#else
- char gname[80];
+ char gname[80];
#endif
- unsigned mask, usage;
- EVP_PKEY *pkey;
- njs_int_t ret;
- njs_str_t key_data, kty;
- njs_value_t *options, *jwk, *val;
- const u_char *start;
+ unsigned mask;
+ EVP_PKEY *pkey;
+ njs_int_t ret;
+ njs_str_t raw_data, kty;
+ njs_value_t *jwk, *val;
+ const u_char *start;
#if (OPENSSL_VERSION_NUMBER < 0x30000000L)
- const EC_GROUP *group;
+ 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;
+ njs_opaque_value_t value;
+ njs_webcrypto_key_t *key;
+ PKCS8_PRIV_KEY_INFO *pkcs8;
+ njs_webcrypto_hash_t hash;
pkey = NULL;
- key_data.start = NULL;
- key_data.length = 0;
-
- fmt = njs_key_format(vm, njs_arg(args, nargs, 1));
- if (njs_slow_path(fmt == NJS_KEY_FORMAT_UNKNOWN)) {
- goto fail;
- }
-
- options = njs_arg(args, nargs, 3);
- alg = njs_key_algorithm(vm, options);
- if (njs_slow_path(alg == NULL)) {
- goto fail;
- }
+ raw_data.start = NULL;
+ raw_data.length = 0;
if (njs_slow_path(!(fmt & alg->fmt))) {
njs_vm_type_error(vm, "unsupported key fmt \"%V\" for \"%V\" key",
goto fail;
}
- ret = njs_key_usage(vm, njs_arg(args, nargs, 5), &usage);
- if (njs_slow_path(ret != NJS_OK)) {
- goto fail;
- }
-
if (njs_slow_path(usage & ~alg->usage)) {
njs_vm_type_error(vm, "unsupported key usage for \"%V\" key",
njs_algorithm_string(alg));
}
if (fmt != NJS_KEY_FORMAT_JWK) {
- ret = njs_vm_value_to_bytes(vm, &key_data, njs_arg(args, nargs, 2));
+ ret = njs_vm_value_to_bytes(vm, &raw_data, key_data);
if (njs_slow_path(ret != NJS_OK)) {
goto fail;
}
}
- key = njs_webcrypto_key_alloc(vm, alg, usage,
- njs_value_bool(njs_arg(args, nargs, 4)));
+ key = njs_webcrypto_key_alloc(vm, alg, usage, extractable);
if (njs_slow_path(key == NULL)) {
goto fail;
}
switch (fmt) {
case NJS_KEY_FORMAT_PKCS8:
- bio = njs_bio_new_mem_buf(key_data.start, key_data.length);
+ bio = njs_bio_new_mem_buf(raw_data.start, raw_data.length);
if (njs_slow_path(bio == NULL)) {
njs_webcrypto_error(vm, "BIO_new_mem_buf() failed");
goto fail;
break;
case NJS_KEY_FORMAT_SPKI:
- start = key_data.start;
- pkey = d2i_PUBKEY(NULL, &start, key_data.length);
+ start = raw_data.start;
+ pkey = d2i_PUBKEY(NULL, &start, raw_data.length);
if (njs_slow_path(pkey == NULL)) {
njs_webcrypto_error(vm, "d2i_PUBKEY() failed");
goto fail;
break;
case NJS_KEY_FORMAT_JWK:
- jwk = njs_arg(args, nargs, 2);
+ jwk = key_data;
if (!njs_value_is_object(jwk)) {
njs_vm_type_error(vm, "invalid JWK key data: object value "
"expected");
}
if (fmt == NJS_KEY_FORMAT_RAW) {
- pkey = njs_import_raw_ec(vm, &key_data, key);
+ pkey = njs_import_raw_ec(vm, &raw_data, key);
if (njs_slow_path(pkey == NULL)) {
goto fail;
}
case NJS_ALGORITHM_ED25519:
if (fmt == NJS_KEY_FORMAT_RAW) {
pkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL,
- key_data.start, key_data.length);
+ raw_data.start, raw_data.length);
if (njs_slow_path(pkey == NULL)) {
- njs_webcrypto_error(vm,
- "EVP_PKEY_new_raw_public_key() failed");
+ njs_webcrypto_error(vm, "EVP_PKEY_new_raw_public_key() failed");
goto fail;
}
}
case NJS_ALGORITHM_X25519:
if (fmt == NJS_KEY_FORMAT_RAW) {
pkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_X25519, NULL,
- key_data.start, key_data.length);
+ raw_data.start, raw_data.length);
if (njs_slow_path(pkey == NULL)) {
njs_webcrypto_error(vm,
"EVP_PKEY_new_raw_public_key() failed");
goto fail;
}
- key->u.s.raw = key_data;
+ key->u.s.raw = raw_data;
} else {
/* NJS_KEY_FORMAT_JWK. */
case NJS_ALGORITHM_AES_CBC:
case NJS_ALGORITHM_AES_KW:
if (fmt == NJS_KEY_FORMAT_RAW) {
- switch (key_data.length) {
+ switch (raw_data.length) {
case 16:
case 24:
case 32:
goto fail;
}
- key->u.s.raw = key_data;
+ key->u.s.raw = raw_data;
}
break;
case NJS_ALGORITHM_PBKDF2:
case NJS_ALGORITHM_HKDF:
default:
- key->u.s.raw = key_data;
+ key->u.s.raw = raw_data;
break;
}
- ret = njs_vm_external_create(vm, njs_value_arg(&value),
+ ret = njs_vm_external_create(vm, retval,
njs_webcrypto_crypto_key_proto_id, key, 0);
if (njs_slow_path(ret != NJS_OK)) {
goto fail;
}
- return njs_webcrypto_result(vm, &value, NJS_OK, retval);
+ return NJS_OK;
fail:
EVP_PKEY_free(pkey);
}
+ return NJS_ERROR;
+}
+
+
+static njs_int_t
+njs_ext_import_key(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t unused, njs_value_t *retval)
+{
+ unsigned usage;
+ njs_int_t ret;
+ njs_value_t *options;
+ njs_bool_t extractable;
+ njs_opaque_value_t value;
+ njs_webcrypto_algorithm_t *alg;
+ njs_webcrypto_key_format_t fmt;
+
+ fmt = njs_key_format(vm, njs_arg(args, nargs, 1));
+ if (njs_slow_path(fmt == NJS_KEY_FORMAT_UNKNOWN)) {
+ goto fail;
+ }
+
+ options = njs_arg(args, nargs, 3);
+ alg = njs_key_algorithm(vm, options);
+ if (njs_slow_path(alg == NULL)) {
+ goto fail;
+ }
+
+ ret = njs_key_usage(vm, njs_arg(args, nargs, 5), &usage);
+ if (njs_slow_path(ret != NJS_OK)) {
+ goto fail;
+ }
+
+ extractable = njs_value_bool(njs_arg(args, nargs, 4));
+
+ ret = njs_webcrypto_import_key_internal(vm, fmt,
+ njs_arg(args, nargs, 2),
+ alg, options, extractable,
+ usage,
+ njs_value_arg(&value));
+ if (njs_slow_path(ret != NJS_OK)) {
+ goto fail;
+ }
+
+ return njs_webcrypto_result(vm, &value, NJS_OK, retval);
+
+fail:
+
return njs_webcrypto_result(vm, NULL, NJS_ERROR, retval);
}
{
unsigned usage;
njs_int_t ret;
- njs_str_t data, key_data;
+ njs_str_t data;
njs_value_t *options;
njs_bool_t extractable;
njs_opaque_value_t decrypted, value;
- njs_webcrypto_key_t *wrapping_key, *ikey;
+ njs_webcrypto_key_t *wrapping_key;
njs_webcrypto_algorithm_t *alg, *key_alg;
njs_webcrypto_key_format_t fmt;
goto fail;
}
- ret = njs_vm_value_to_bytes(vm, &key_data, njs_value_arg(&decrypted));
- if (njs_slow_path(ret != NJS_OK)) {
- goto fail;
- }
-
- if (njs_slow_path(usage & ~key_alg->usage)) {
- njs_vm_type_error(vm, "unsupported key usage for \"%V\" key",
- njs_algorithm_string(key_alg));
- goto fail;
- }
-
- if (njs_slow_path(!(fmt & key_alg->fmt))) {
- njs_vm_type_error(vm, "unsupported key fmt for \"%V\" key",
- njs_algorithm_string(key_alg));
- goto fail;
- }
-
- ikey = njs_webcrypto_key_alloc(vm, key_alg, usage, extractable);
- if (njs_slow_path(ikey == NULL)) {
- goto fail;
- }
+ if (fmt == NJS_KEY_FORMAT_JWK) {
+ njs_str_t json_data;
+ njs_opaque_value_t json_str, jwk;
- if (fmt == NJS_KEY_FORMAT_RAW) {
- switch (key_alg->type) {
- case NJS_ALGORITHM_AES_GCM:
- case NJS_ALGORITHM_AES_CTR:
- case NJS_ALGORITHM_AES_CBC:
- case NJS_ALGORITHM_AES_KW:
- switch (key_data.length) {
- case 16:
- case 24:
- case 32:
- break;
- default:
- njs_vm_type_error(vm, "AES Invalid key length");
- goto fail;
- }
+ ret = njs_vm_value_to_bytes(vm, &json_data,
+ njs_value_arg(&decrypted));
+ if (njs_slow_path(ret != NJS_OK)) {
+ goto fail;
+ }
- ikey->u.s.raw = key_data;
- break;
+ ret = njs_vm_value_string_create(vm, njs_value_arg(&json_str),
+ json_data.start, json_data.length);
+ if (njs_slow_path(ret != NJS_OK)) {
+ goto fail;
+ }
- case NJS_ALGORITHM_HMAC:
- default:
- ikey->u.s.raw = key_data;
- break;
+ ret = njs_vm_json_parse(vm, njs_value_arg(&json_str), 1,
+ njs_value_arg(&jwk));
+ if (njs_slow_path(ret != NJS_OK)) {
+ njs_vm_type_error(vm,
+ "wrapped key is not valid JWK JSON");
+ goto fail;
}
- } else {
- njs_vm_type_error(vm, "unwrapKey: unsupported format \"%V\"",
- njs_format_string(fmt));
- goto fail;
+ njs_value_assign(&decrypted, &jwk);
}
- ret = njs_vm_external_create(vm, njs_value_arg(&value),
- njs_webcrypto_crypto_key_proto_id, ikey, 0);
+ ret = njs_webcrypto_import_key_internal(vm, fmt,
+ njs_value_arg(&decrypted),
+ key_alg,
+ njs_arg(args, nargs, 5),
+ extractable, usage,
+ njs_value_arg(&value));
if (njs_slow_path(ret != NJS_OK)) {
goto fail;
}
#endif
static JSValue qjs_webcrypto_import_key(JSContext *cx, JSValueConst this_val,
int argc, JSValueConst *argv);
+static JSValue qjs_webcrypto_import_key_internal(JSContext *cx,
+ qjs_webcrypto_key_format_t fmt, JSValueConst key_data,
+ qjs_webcrypto_algorithm_t *alg, JSValueConst options,
+ int extractable, unsigned usage);
static JSValue qjs_webcrypto_sign(JSContext *cx, JSValueConst this_val,
int argc, JSValueConst *argv, int verify);
static JSValue qjs_webcrypto_wrap_key(JSContext *cx, JSValueConst this_val,
static JSValue
-qjs_webcrypto_import_key(JSContext *cx, JSValueConst this_val, int argc,
- JSValueConst *argv)
+qjs_webcrypto_import_key_internal(JSContext *cx, qjs_webcrypto_key_format_t fmt,
+ JSValueConst key_data, qjs_webcrypto_algorithm_t *alg, JSValueConst options,
+ int extractable, unsigned usage)
{
- int nid;
- BIO *bio;
+ int nid;
+ BIO *bio;
#if (OPENSSL_VERSION_NUMBER < 0x30000000L)
- RSA *rsa;
- EC_KEY *ec;
+ RSA *rsa;
+ EC_KEY *ec;
#else
- char gname[80];
+ char gname[80];
#endif
- JSValue options, key, jwk, val, ret;
- unsigned mask, usage;
- EVP_PKEY *pkey;
- njs_str_t key_data;
- const u_char *start;
+ JSValue key, jwk, val, ret;
+ unsigned mask;
+ EVP_PKEY *pkey;
+ njs_str_t kd;
+ const u_char *start;
#if (OPENSSL_VERSION_NUMBER < 0x30000000L)
- const EC_GROUP *group;
+ const EC_GROUP *group;
#endif
- qjs_webcrypto_key_t *wkey;
- PKCS8_PRIV_KEY_INFO *pkcs8;
- qjs_webcrypto_hash_t hash;
- qjs_webcrypto_jwk_kty_t kty;
- qjs_webcrypto_algorithm_t *alg;
- qjs_webcrypto_key_format_t fmt;
+ qjs_webcrypto_key_t *wkey;
+ PKCS8_PRIV_KEY_INFO *pkcs8;
+ qjs_webcrypto_hash_t hash;
+ qjs_webcrypto_jwk_kty_t kty;
pkey = NULL;
- key_data.start = NULL;
- key_data.length = 0;
-
- fmt = qjs_key_format(cx, argv[0]);
- if (fmt == QJS_KEY_FORMAT_UNKNOWN) {
- return JS_EXCEPTION;
- }
+ kd.start = NULL;
+ kd.length = 0;
- options = argv[2];
-
- alg = qjs_key_algorithm(cx, options);
- if (alg == NULL) {
+ if (usage & ~alg->usage) {
+ JS_ThrowTypeError(cx, "unsupported key usage for \"%s\" key",
+ qjs_algorithm_string(alg));
return JS_EXCEPTION;
}
return JS_EXCEPTION;
}
- ret = qjs_key_usage(cx, argv[4], &usage);
- if (JS_IsException(ret)) {
- return JS_EXCEPTION;
- }
-
- if (usage & ~alg->usage) {
- JS_ThrowTypeError(cx, "unsupported key usage for \"%s\" key",
- qjs_algorithm_string(alg));
- return JS_EXCEPTION;
- }
-
if (fmt != QJS_KEY_FORMAT_JWK) {
- ret = qjs_typed_array_data(cx, argv[1], &key_data);
+ ret = qjs_typed_array_data(cx, key_data, &kd);
if (JS_IsException(ret)) {
return JS_EXCEPTION;
}
}
- key = qjs_webcrypto_key_make(cx, alg, usage, JS_ToBool(cx, argv[3]));
+ key = qjs_webcrypto_key_make(cx, alg, usage, extractable);
if (JS_IsException(key)) {
return JS_EXCEPTION;
}
wkey = JS_GetOpaque(key, QJS_CORE_CLASS_ID_WEBCRYPTO_KEY);
- /*
- * set by qjs_webcrypto_key_make():
- *
- * key->u.a.pkey = NULL;
- * key->u.s.raw.length = 0;
- * key->u.s.raw.start = NULL;
- * key->u.a.curve = 0;
- * key->u.a.privat = 0;
- * key->hash = QJS_HASH_UNSET;
- */
-
switch (fmt) {
case QJS_KEY_FORMAT_PKCS8:
- bio = BIO_new_mem_buf(key_data.start, key_data.length);
+ bio = BIO_new_mem_buf(kd.start, kd.length);
if (bio == NULL) {
qjs_webcrypto_error(cx, "BIO_new_mem_buf() failed");
goto fail;
break;
case QJS_KEY_FORMAT_SPKI:
- start = key_data.start;
- pkey = d2i_PUBKEY(NULL, &start, key_data.length);
+ start = kd.start;
+ pkey = d2i_PUBKEY(NULL, &start, kd.length);
if (pkey == NULL) {
qjs_webcrypto_error(cx, "d2i_PUBKEY() failed");
goto fail;
break;
case QJS_KEY_FORMAT_JWK:
- jwk = argv[1];
+ jwk = key_data;
if (!JS_IsObject(jwk)) {
JS_ThrowTypeError(cx, "invalid JWK key data: object value "
"expected");
}
if (fmt == QJS_KEY_FORMAT_RAW) {
- pkey = qjs_import_raw_ec(cx, &key_data, wkey);
+ pkey = qjs_import_raw_ec(cx, &kd, wkey);
if (pkey == NULL) {
goto fail;
}
case QJS_ALGORITHM_ED25519:
if (fmt == QJS_KEY_FORMAT_RAW) {
pkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL,
- key_data.start, key_data.length);
+ kd.start, kd.length);
if (pkey == NULL) {
qjs_webcrypto_error(cx,
"EVP_PKEY_new_raw_public_key() failed");
case QJS_ALGORITHM_X25519:
if (fmt == QJS_KEY_FORMAT_RAW) {
pkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_X25519, NULL,
- key_data.start, key_data.length);
+ kd.start, kd.length);
if (pkey == NULL) {
qjs_webcrypto_error(cx,
"EVP_PKEY_new_raw_public_key() failed");
goto fail;
}
- wkey->u.s.raw.start = js_malloc(cx, key_data.length);
+ wkey->u.s.raw.start = js_malloc(cx, kd.length);
if (wkey->u.s.raw.start == NULL) {
JS_ThrowOutOfMemory(cx);
goto fail;
}
- wkey->u.s.raw.length = key_data.length;
- memcpy(wkey->u.s.raw.start, key_data.start, key_data.length);
+ wkey->u.s.raw.length = kd.length;
+ memcpy(wkey->u.s.raw.start, kd.start, kd.length);
} else {
/* QJS_KEY_FORMAT_JWK. */
case QJS_ALGORITHM_AES_CBC:
case QJS_ALGORITHM_AES_KW:
if (fmt == QJS_KEY_FORMAT_RAW) {
- switch (key_data.length) {
+ switch (kd.length) {
case 16:
case 24:
case 32:
goto fail;
}
- wkey->u.s.raw.start = js_malloc(cx, key_data.length);
+ wkey->u.s.raw.start = js_malloc(cx, kd.length);
if (wkey->u.s.raw.start == NULL) {
JS_ThrowOutOfMemory(cx);
goto fail;
}
- wkey->u.s.raw.length = key_data.length;
- memcpy(wkey->u.s.raw.start, key_data.start, key_data.length);
+ wkey->u.s.raw.length = kd.length;
+ memcpy(wkey->u.s.raw.start, kd.start, kd.length);
}
break;
case QJS_ALGORITHM_PBKDF2:
case QJS_ALGORITHM_HKDF:
default:
- wkey->u.s.raw.start = js_malloc(cx, key_data.length);
+ wkey->u.s.raw.start = js_malloc(cx, kd.length);
if (wkey->u.s.raw.start == NULL) {
JS_ThrowOutOfMemory(cx);
goto fail;
}
- wkey->u.s.raw.length = key_data.length;
- memcpy(wkey->u.s.raw.start, key_data.start, key_data.length);
+ wkey->u.s.raw.length = kd.length;
+ memcpy(wkey->u.s.raw.start, kd.start, kd.length);
break;
}
- return qjs_promise_result(cx, key);
+ return key;
fail:
JS_FreeValue(cx, key);
- return qjs_promise_result(cx, JS_EXCEPTION);
+ return JS_EXCEPTION;
+}
+
+
+static JSValue
+qjs_webcrypto_import_key(JSContext *cx, JSValueConst this_val, int argc,
+ JSValueConst *argv)
+{
+ JSValue ret, key;
+ unsigned usage;
+ qjs_webcrypto_algorithm_t *alg;
+ qjs_webcrypto_key_format_t fmt;
+
+ fmt = qjs_key_format(cx, argv[0]);
+ if (fmt == QJS_KEY_FORMAT_UNKNOWN) {
+ return JS_EXCEPTION;
+ }
+
+ alg = qjs_key_algorithm(cx, argv[2]);
+ if (alg == NULL) {
+ return JS_EXCEPTION;
+ }
+
+ ret = qjs_key_usage(cx, argv[4], &usage);
+ if (JS_IsException(ret)) {
+ return JS_EXCEPTION;
+ }
+
+ key = qjs_webcrypto_import_key_internal(cx, fmt, argv[1], alg, argv[2],
+ JS_ToBool(cx, argv[3]), usage);
+ if (JS_IsException(key)) {
+ return qjs_promise_result(cx, JS_EXCEPTION);
+ }
+
+ return qjs_promise_result(cx, key);
}
qjs_webcrypto_unwrap_key(JSContext *cx, JSValueConst this_val, int argc,
JSValueConst *argv)
{
- unsigned mask, usage;
+ unsigned usage;
JSValue options, ret, decrypted, key_value;
njs_str_t data, key_data;
- qjs_webcrypto_key_t *wrapping_key, *ikey;
+ const char *str;
+ size_t len;
+ JSValue json_str;
+ qjs_webcrypto_key_t *wrapping_key;
qjs_webcrypto_algorithm_t *alg, *key_alg;
qjs_webcrypto_key_format_t fmt;
goto fail;
}
- mask = QJS_KEY_USAGE_UNWRAP_KEY;
- if (!(wrapping_key->usage & mask)) {
+ if (!(wrapping_key->usage & QJS_KEY_USAGE_UNWRAP_KEY)) {
JS_ThrowTypeError(cx, "unwrapping key does not support unwrapKey");
goto fail;
}
goto fail;
}
- ret = qjs_typed_array_data(cx, decrypted, &key_data);
- if (JS_IsException(ret)) {
- JS_FreeValue(cx, decrypted);
- goto fail;
- }
-
- if (usage & ~key_alg->usage) {
- JS_FreeValue(cx, decrypted);
- JS_ThrowTypeError(cx, "unsupported key usage for \"%s\" key",
- qjs_algorithm_string(key_alg));
- goto fail;
- }
-
- if (!(fmt & key_alg->fmt)) {
- JS_FreeValue(cx, decrypted);
- JS_ThrowTypeError(cx, "unsupported key fmt for \"%s\" key",
- qjs_algorithm_string(key_alg));
- goto fail;
- }
+ if (fmt == QJS_KEY_FORMAT_JWK) {
+ ret = qjs_typed_array_data(cx, decrypted, &key_data);
+ if (JS_IsException(ret)) {
+ JS_FreeValue(cx, decrypted);
+ goto fail;
+ }
- key_value = qjs_webcrypto_key_make(cx, key_alg, usage,
- JS_ToBool(cx, argv[5]));
- if (JS_IsException(key_value)) {
+ json_str = JS_NewStringLen(cx, (const char *) key_data.start,
+ key_data.length);
JS_FreeValue(cx, decrypted);
- goto fail;
- }
-
- ikey = JS_GetOpaque2(cx, key_value, QJS_CORE_CLASS_ID_WEBCRYPTO_KEY);
- if (fmt == QJS_KEY_FORMAT_RAW) {
- switch (key_alg->type) {
- case QJS_ALGORITHM_AES_GCM:
- case QJS_ALGORITHM_AES_CTR:
- case QJS_ALGORITHM_AES_CBC:
- case QJS_ALGORITHM_AES_KW:
- switch (key_data.length) {
- case 16:
- case 24:
- case 32:
- break;
- default:
- JS_FreeValue(cx, decrypted);
- JS_FreeValue(cx, key_value);
- JS_ThrowTypeError(cx, "AES Invalid key length");
- goto fail;
- }
+ if (JS_IsException(json_str)) {
+ goto fail;
+ }
- ikey->u.s.raw.start = js_malloc(cx, key_data.length);
- if (ikey->u.s.raw.start == NULL) {
- JS_FreeValue(cx, decrypted);
- JS_FreeValue(cx, key_value);
- JS_ThrowOutOfMemory(cx);
- goto fail;
- }
+ str = JS_ToCStringLen(cx, &len, json_str);
+ JS_FreeValue(cx, json_str);
- ikey->u.s.raw.length = key_data.length;
- memcpy(ikey->u.s.raw.start, key_data.start, key_data.length);
- break;
+ if (str == NULL) {
+ goto fail;
+ }
- case QJS_ALGORITHM_HMAC:
- default:
- ikey->u.s.raw.start = js_malloc(cx, key_data.length);
- if (ikey->u.s.raw.start == NULL) {
- JS_FreeValue(cx, decrypted);
- JS_FreeValue(cx, key_value);
- JS_ThrowOutOfMemory(cx);
- goto fail;
- }
+ decrypted = JS_ParseJSON(cx, str, len, "<unwrapKey>");
+ JS_FreeCString(cx, str);
- ikey->u.s.raw.length = key_data.length;
- memcpy(ikey->u.s.raw.start, key_data.start, key_data.length);
- break;
+ if (JS_IsException(decrypted)) {
+ JS_ThrowTypeError(cx, "wrapped key is not valid JWK "
+ "JSON");
+ goto fail;
}
-
- } else {
- JS_FreeValue(cx, decrypted);
- JS_FreeValue(cx, key_value);
- JS_ThrowTypeError(cx, "unwrapKey: unsupported format");
- goto fail;
}
+ key_value = qjs_webcrypto_import_key_internal(cx, fmt, decrypted,
+ key_alg, argv[4],
+ JS_ToBool(cx, argv[5]),
+ usage);
JS_FreeValue(cx, decrypted);
+ if (JS_IsException(key_value)) {
+ goto fail;
+ }
+
return qjs_promise_result(cx, key_value);
fail:
counter: crypto.getRandomValues(new Uint8Array(16)),
length: 64},
check_raw: true },
+
+ /* AES-GCM wrapping an AES key in JWK format */
+ { wrap_alg: {name: "AES-GCM", length: 256},
+ key_alg: {name: "AES-GCM", length: 128},
+ key_usage: ["encrypt", "decrypt"],
+ format: "jwk",
+ wrap_params: {name: "AES-GCM",
+ iv: crypto.getRandomValues(new Uint8Array(12))},
+ verify_encrypt: {name: "AES-GCM",
+ iv: crypto.getRandomValues(new Uint8Array(12))} },
+
+ /* AES-GCM wrapping an HMAC key in JWK format */
+ { wrap_alg: {name: "AES-GCM", length: 256},
+ key_alg: {name: "HMAC", hash: "SHA-256"},
+ key_usage: ["sign", "verify"],
+ format: "jwk",
+ wrap_params: {name: "AES-GCM",
+ iv: crypto.getRandomValues(new Uint8Array(12))},
+ verify_sign: {name: "HMAC"} },
]};
let wrap_error_tsuite = {