n = njs_ec_rs_size(pkey);
- if (njs_slow_path(n == 0 || p1363_len != 2 * n)) {
- goto fail;
+ if (njs_slow_path(n == 0)) {
+ njs_webcrypto_error(vm, "cannot determine ECDSA signature length");
+ return NJS_ERROR;
+ }
+
+ if (p1363_len != 2 * n) {
+ return NJS_DECLINED;
}
ec_sig = ECDSA_SIG_new();
ret = njs_convert_p1363_to_der(vm, key->u.a.pkey, sig.start,
sig.length, &sig.start,
&sig.length);
+ if (ret == NJS_DECLINED) {
+ ret = 0;
+ goto verify_done;
+ }
+
if (njs_slow_path(ret != NJS_OK)) {
goto fail;
}
}
}
+ verify_done:
+
njs_evp_md_ctx_free(mctx);
EVP_PKEY_CTX_free(pctx);
n = qjs_ec_rs_size(pkey);
- if (n == 0 || p1363_len != 2 * n) {
- JS_ThrowTypeError(cx, "invalid ECDSA signature length %zu != %u",
- p1363_len, 2 * n);
+ if (n == 0) {
+ qjs_webcrypto_error(cx, "cannot determine ECDSA signature length");
return -1;
}
+ if (p1363_len != 2 * n) {
+ return 1;
+ }
+
ec_sig = ECDSA_SIG_new();
if (ec_sig == NULL) {
JS_ThrowOutOfMemory(cx);
rc = qjs_convert_p1363_to_der(cx, key->u.a.pkey, sig.start,
sig.length, &sig.start,
&sig.length);
+ if (rc > 0) {
+ rc = 0;
+ goto verify_done;
+ }
+
if (rc < 0) {
goto fail;
}
goto fail;
}
+ verify_done:
+
js_free(cx, dst);
}
exception: "TypeError: Unsupported key usage for a ECDSA key" },
]};
+async function test_ecdsa_signature_length(params) {
+ let pair = await crypto.subtle.generateKey(
+ {name: "ECDSA", namedCurve: params.curve}, false, ["sign", "verify"]);
+ let options = {name: "ECDSA", hash: "SHA-256"};
+ let data = new Uint8Array([1, 2, 3]);
+ let signature = await crypto.subtle.sign(options, pair.privateKey, data);
+
+ if (signature.byteLength !== params.length) {
+ throw Error("unexpected ECDSA signature length");
+ }
+
+ let lengths = [0, 3, params.length - 1, params.length + 1];
+ for (let i = 0; i < lengths.length; i++) {
+ let length = lengths[i];
+ let invalid = new Uint8Array(length);
+ invalid.set(new Uint8Array(signature).subarray(0, length));
+
+ let verified = await crypto.subtle.verify(options, pair.publicKey,
+ invalid, data);
+ if (verified !== false) {
+ throw Error(`ECDSA accepted a signature of length ${length}`);
+ }
+ }
+
+ let verified = await crypto.subtle.verify(options, pair.publicKey,
+ signature, data);
+ if (verified !== true) {
+ throw Error("ECDSA rejected a valid signature");
+ }
+
+ return "SUCCESS";
+}
+
+let ecdsa_signature_length_tsuite = {
+ name: "ECDSA signature length",
+ skip: () => !has_webcrypto(),
+ T: test_ecdsa_signature_length,
+ tests: [
+ {curve: "P-256", length: 64},
+ {curve: "P-384", length: 96},
+ {curve: "P-521", length: 132},
+ ],
+};
+
run([
hmac_tsuite,
rsassa_pkcs1_v1_5_tsuite,
rsa_pss_tsuite,
ecdsa_tsuite,
+ ecdsa_signature_length_tsuite,
verify_error_queue_tsuite
])
.then($DONE, $DONE);