Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

QuickJS: fixed alg may be used uninitialized in SubtleCrypto.import(). #855

Merged
merged 5 commits into from
Feb 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions external/njs_shell.c
Original file line number Diff line number Diff line change
Expand Up @@ -2590,7 +2590,7 @@ njs_qjs_module_loader(JSContext *ctx, const char *module_name, void *opaque)
(void) close(info.fd);

if (njs_slow_path(ret != NJS_OK)) {
JS_ThrowInternalError(ctx, "while reading \"%*s\" module",
JS_ThrowInternalError(ctx, "while reading \"%.*s\" module",
(int) info.file.length, info.file.start);
return NULL;
}
Expand All @@ -2599,7 +2599,7 @@ njs_qjs_module_loader(JSContext *ctx, const char *module_name, void *opaque)

ret = njs_console_set_cwd(console, &info.file);
if (njs_slow_path(ret != NJS_OK)) {
JS_ThrowInternalError(ctx, "while setting cwd for \"%*s\" module",
JS_ThrowInternalError(ctx, "while setting cwd for \"%.*s\" module",
(int) info.file.length, info.file.start);
return NULL;
}
Expand Down Expand Up @@ -2827,7 +2827,7 @@ njs_engine_qjs_unhandled_rejection(njs_engine_t *engine)
return -1;
}

JS_ThrowTypeError(ctx, "unhandled promise rejection: %*s", (int) len, str);
JS_ThrowTypeError(ctx, "unhandled promise rejection: %.*s", (int) len, str);
JS_FreeCString(ctx, str);

for (i = 0; i < console->rejected_promises->items; i++) {
Expand Down
47 changes: 25 additions & 22 deletions external/njs_webcrypto_module.c
Original file line number Diff line number Diff line change
Expand Up @@ -3207,37 +3207,40 @@ njs_import_jwk_oct(njs_vm_t *vm, njs_value_t *jwk, njs_webcrypto_key_t *key)

njs_decode_base64url(&key->u.s.raw, &b64);

size = 16;

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 (njs_slow_path(val == NULL || !njs_value_is_string(val))) {
njs_vm_type_error(vm, "Invalid JWK oct alg");
return NJS_ERROR;
}

if (key->alg->type == NJS_ALGORITHM_HMAC) {
for (w = &hashes[0]; w->name.length != 0; w++) {
if (njs_strstr_eq(&alg, &w->name)) {
key->hash = w->value;
goto done;
}
}
njs_value_string_get(val, &alg);

} else {
type = key->alg->type;
a = &njs_webcrypto_alg_aes_name[type - NJS_ALGORITHM_AES_GCM][0];
for (; a->length != 0; a++) {
if (njs_strstr_eq(&alg, a)) {
goto done;
}
size = 16;

size += 8;
if (key->alg->type == NJS_ALGORITHM_HMAC) {
for (w = &hashes[0]; w->name.length != 0; w++) {
if (njs_strstr_eq(&alg, &w->name)) {
key->hash = w->value;
goto done;
}
}

njs_vm_type_error(vm, "unexpected \"alg\" value \"%V\" for JWK key",
&alg);
return NJS_ERROR;
} else {
type = key->alg->type;
a = &njs_webcrypto_alg_aes_name[type - NJS_ALGORITHM_AES_GCM][0];
for (; a->length != 0; a++) {
if (njs_strstr_eq(&alg, a)) {
goto done;
}

size += 8;
}
}

njs_vm_type_error(vm, "unexpected \"alg\" value \"%V\" for JWK key",
&alg);
return NJS_ERROR;

done:

if (key->alg->type != NJS_ALGORITHM_HMAC) {
Expand Down
97 changes: 45 additions & 52 deletions external/qjs_webcrypto_module.c
Original file line number Diff line number Diff line change
Expand Up @@ -3064,50 +3064,49 @@ qjs_import_jwk_oct(JSContext *cx, JSValue jwk, qjs_webcrypto_key_t *key)
qjs_base64url_decode(cx, &b64, &key->u.s.raw);
JS_FreeCString(cx, (char *) b64.start);

size = 16;

val = JS_GetPropertyStr(cx, jwk, "alg");
if (JS_IsException(val)) {
return JS_EXCEPTION;
}

if (JS_IsString(val)) {
alg.start = (u_char *) JS_ToCStringLen(cx, &alg.length, val);
if (!JS_IsString(val)) {
JS_FreeValue(cx, val);
val = JS_UNDEFINED;

if (alg.start == NULL) {
JS_ThrowOutOfMemory(cx);
return JS_EXCEPTION;
}
return JS_ThrowTypeError(cx, "Invalid JWK oct alg");
}

if (key->alg->type == QJS_ALGORITHM_HMAC) {
for (w = &hashes[0]; w->name.length != 0; w++) {
if (njs_strstr_eq(&alg, &w->name)) {
key->hash = w->value;
goto done;
}
}
alg.start = (u_char *) JS_ToCStringLen(cx, &alg.length, val);
JS_FreeValue(cx, val);
if (alg.start == NULL) {
JS_ThrowOutOfMemory(cx);
return JS_EXCEPTION;
}

} else {
type = key->alg->type;
a = &qjs_webcrypto_alg_aes_name[type - QJS_ALGORITHM_AES_GCM][0];
for (; a->length != 0; a++) {
if (njs_strstr_eq(&alg, a)) {
goto done;
}
size = 16;

size += 8;
if (key->alg->type == QJS_ALGORITHM_HMAC) {
for (w = &hashes[0]; w->name.length != 0; w++) {
if (njs_strstr_eq(&alg, &w->name)) {
key->hash = w->value;
goto done;
}
}

JS_ThrowTypeError(cx, "unexpected \"alg\" value \"%s\" for JWK key",
alg.start);
JS_FreeCString(cx, (char *) alg.start);
return JS_EXCEPTION;
} else {
type = key->alg->type;
a = &qjs_webcrypto_alg_aes_name[type - QJS_ALGORITHM_AES_GCM][0];
for (; a->length != 0; a++) {
if (njs_strstr_eq(&alg, a)) {
goto done;
}

size += 8;
}
}

JS_FreeValue(cx, val);
JS_ThrowTypeError(cx, "unexpected \"alg\" value \"%s\" for JWK key",
alg.start);
JS_FreeCString(cx, (char *) alg.start);
return JS_EXCEPTION;

done:

Expand Down Expand Up @@ -3243,22 +3242,22 @@ qjs_webcrypto_import_key(JSContext *cx, JSValueConst this_val, int argc,
case QJS_KEY_FORMAT_PKCS8:
bio = BIO_new_mem_buf(key_data.start, key_data.length);
if (bio == NULL) {
JS_ThrowTypeError(cx, "BIO_new_mem_buf() failed");
qjs_webcrypto_error(cx, "BIO_new_mem_buf() failed");
goto fail;
}

pkcs8 = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, NULL);
if (pkcs8 == NULL) {
BIO_free(bio);
JS_ThrowTypeError(cx, "d2i_PKCS8_PRIV_KEY_INFO_bio() failed");
qjs_webcrypto_error(cx, "d2i_PKCS8_PRIV_KEY_INFO_bio() failed");
goto fail;
}

pkey = EVP_PKCS82PKEY(pkcs8);
if (pkey == NULL) {
PKCS8_PRIV_KEY_INFO_free(pkcs8);
BIO_free(bio);
JS_ThrowTypeError(cx, "EVP_PKCS82PKEY() failed");
qjs_webcrypto_error(cx, "EVP_PKCS82PKEY() failed");
goto fail;
}

Expand All @@ -3273,7 +3272,7 @@ qjs_webcrypto_import_key(JSContext *cx, JSValueConst this_val, int argc,
start = key_data.start;
pkey = d2i_PUBKEY(NULL, &start, key_data.length);
if (pkey == NULL) {
JS_ThrowTypeError(cx, "d2i_PUBKEY() failed");
qjs_webcrypto_error(cx, "d2i_PUBKEY() failed");
goto fail;
}

Expand Down Expand Up @@ -3721,7 +3720,7 @@ qjs_convert_p1363_to_der(JSContext *cx, EVP_PKEY *pkey, u_char *p1363,

if (len < 0) {
js_free(cx, data);
JS_ThrowTypeError(cx, "i2d_ECDSA_SIG() failed");
qjs_webcrypto_error(cx, "i2d_ECDSA_SIG() failed");
goto fail;
}

Expand Down Expand Up @@ -4168,20 +4167,7 @@ qjs_webcrypto_key_algorithm(JSContext *cx, JSValueConst this_val)
return JS_EXCEPTION;
}

ret = JS_NewObject(cx);
if (JS_IsException(ret)) {
JS_FreeValue(cx, obj);
return JS_EXCEPTION;
}

if (JS_DefinePropertyValueStr(cx, ret, "name", hash, JS_PROP_C_W_E)
< 0)
{
JS_FreeValue(cx, obj);
return JS_EXCEPTION;
}

if (JS_DefinePropertyValueStr(cx, obj, "hash", ret, JS_PROP_C_W_E)
if (JS_DefinePropertyValueStr(cx, obj, "hash", hash, JS_PROP_C_W_E)
< 0)
{
JS_FreeValue(cx, obj);
Expand Down Expand Up @@ -4378,7 +4364,7 @@ qjs_jwk_kty(JSContext *cx, JSValueConst value)
}
}

JS_ThrowTypeError(cx, "invalid JWK key type: %s", kty.start);
JS_ThrowTypeError(cx, "invalid JWK key type: \"%s\"", kty.start);
JS_FreeCString(cx, (char *) kty.start);

return QJS_KEY_JWK_KTY_UNKNOWN;
Expand Down Expand Up @@ -4638,10 +4624,17 @@ qjs_key_usage(JSContext *cx, JSValue value, unsigned *mask)
for (e = &qjs_webcrypto_usage[0]; e->name.length != 0; e++) {
if (njs_strstr_eq(&s, &e->name)) {
*mask |= e->value;
break;
goto done;
}
}

JS_ThrowTypeError(cx, "unknown key usage: \"%.*s\"", (int) s.length,
s.start);
JS_FreeCString(cx, (char *) s.start);
return JS_EXCEPTION;

done:

JS_FreeCString(cx, (char *) s.start);
}

Expand Down Expand Up @@ -4803,7 +4796,7 @@ qjs_webcrypto_error(JSContext *cx, const char *fmt, ...)
}
}

JS_ThrowTypeError(cx, "%*s", (int) (p - errstr), errstr);
JS_ThrowTypeError(cx, "%.*s", (int) (p - errstr), errstr);
}


Expand Down
4 changes: 2 additions & 2 deletions nginx/ngx_js.c
Original file line number Diff line number Diff line change
Expand Up @@ -1988,7 +1988,7 @@ ngx_qjs_module_loader(JSContext *cx, const char *module_name, void *opaque)
(void) close(info.fd);

if (ret != NJS_OK) {
JS_ThrowInternalError(cx, "while reading \"%*s\" module",
JS_ThrowInternalError(cx, "while reading \"%.*s\" module",
(int) info.file.length, info.file.start);
return NULL;
}
Expand Down Expand Up @@ -2057,7 +2057,7 @@ ngx_qjs_unhandled_rejection(ngx_js_ctx_t *ctx)
return -1;
}

JS_ThrowTypeError(cx, "unhandled promise rejection: %*s", (int) len, str);
JS_ThrowTypeError(cx, "unhandled promise rejection: %.*s", (int) len, str);
JS_FreeCString(cx, str);

for (i = 0; i < ctx->rejected_promises->items; i++) {
Expand Down
2 changes: 1 addition & 1 deletion nginx/ngx_stream_js_module.c
Original file line number Diff line number Diff line change
Expand Up @@ -2126,7 +2126,7 @@ ngx_stream_qjs_event(ngx_stream_session_t *s, JSContext *cx, ngx_str_t *event)
}

if (i == n) {
(void) JS_ThrowInternalError(cx, "unknown event \"%*s\"",
(void) JS_ThrowInternalError(cx, "unknown event \"%.*s\"",
(int) event->len, event->data);
return NULL;
}
Expand Down
2 changes: 1 addition & 1 deletion src/qjs_buffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -2099,7 +2099,7 @@ qjs_buffer_encoding(JSContext *ctx, JSValueConst value, JS_BOOL thrw)
JS_FreeCString(ctx, (char *) name.start);

if (thrw) {
JS_ThrowTypeError(ctx, "\"%*s\" encoding is not supported",
JS_ThrowTypeError(ctx, "\"%.*s\" encoding is not supported",
(int) name.length, name.start);
}

Expand Down
3 changes: 0 additions & 3 deletions test/webcrypto/aes.t.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ let aes_tsuite = {
{ name: "AES-GCM", data: "aabbcc", tagLength: 96 },
{ name: "AES-GCM", data: "aabbcc", tagLength: 112 },
{ name: "AES-GCM", data: "aabbcc", tagLength: 113, exception: "TypeError: AES-GCM Invalid tagLength" },
{ name: "AES-GCM", data: "aabbcc", key: "aabbcc", exception: "TypeError: Invalid key length" },
{ name: "AES-GCM", data: "aabbcc", key: "001122330011223300112233001122330011223300112233" },
{ name: "AES-GCM", data: "aabbccdd".repeat(4096) },

Expand All @@ -88,14 +87,12 @@ let aes_tsuite = {
{ name: "AES-CTR", data: "aabbcc", key: "001122330011223300112233001122330011223300112233" },
{ name: "AES-CTR", data: "aabbccdd", length: 129,
exception: "TypeError: AES-CTR algorithm.length must be between 1 and 128" },
{ name: "AES-CTR", data: "aabbcc", key: "aabbcc", exception: "TypeError: Invalid key length" },

{ name: "AES-CBC", data: "aa" },
{ name: "AES-CBC", data: "aabbccdd".repeat(4) },
{ name: "AES-CBC", data: "aabbccdd".repeat(4096) },
{ name: "AES-CBC", data: "aabbccdd".repeat(5), iv: "ffffffffffffffffffffffffffffffff" },
{ name: "AES-CBC", data: "aabbcc", key: "001122330011223300112233001122330011223300112233" },
{ name: "AES-CBC", data: "aabbcc", key: "aabbcc", exception: "TypeError: Invalid key length" },
]};

run([aes_tsuite])
Expand Down
Loading