I created ECDSA key pair using openssl
openssl ecparam -name prime256v1 -genkey -noout -out ecdsa_private_key.pem
openssl ec -in ecdsa_private_key.pem -pubout -out ecdsa_public_key.pem
and using text file generated signature
openssl dgst -sha256 -sign ecdsa_private_key.pem -out ecdsa_signature.bin data.txt
and then i trying to verify this signature using js webcrypto i geting false
result
import { readFile } from "node:fs/promises"
import { EOL } from "node:os";
/**
* @param { string } pem
*/
function pemToArrayBuffer(pem) {
const lines = pem.trim().split(EOL);
lines.pop();
lines.shift();
return Buffer.from(lines.join(""), "base64");
}
const pemPublicKey = await readFile("./ecdsa_public_key.pem", "utf8")
const publicKeyArrayBuffer = pemToArrayBuffer(pemPublicKey);
const publicKey = await crypto.subtle.importKey(
'spki',
publicKeyArrayBuffer,
{
name: 'ECDSA',
namedCurve: 'P-256',
},
true,
['verify']
);
const data = await readFile("./data.txt");
const signature = await readFile("./ecdsa_signature.bin");
const isValid = await crypto.subtle.verify(
{
name: 'ECDSA',
hash: { name: 'SHA-256' }
},
publicKey,
signature,
data
);
console.log(isValid); //false
when using openssl everyting is fine
openssl dgst -sha256 -verify ecdsa_public_key.pem -signature ecdsa_signature.bin data.txt
as @Topaco mentioned, problem is in signature format.
To convert ASN.1/DER
signatute to P1363
following function can be used:
/**
* @param { Uint8Array } signature
*/
function toP1363(signature) {
let i = 0;
if (signature[i++] !== 0x30) throw new Error("Invalid ASN.1 sequence header");
const length = signature[i++];
if (signature.length < length + i) throw new Error("Invalid ASN.1 sequence length");
//r
if (signature[i++] != 0x02) throw new Error('Invalid ASN.1 "r" tag');
let rLength = signature[i++];
while (signature[i] == 0x00) { i++; rLength--; }
const r = new Uint8Array(signature.buffer, i, rLength);
i += rLength;
//s
if (signature[i++] != 0x02) throw new Error('Invalid ASN.1 "s" tag');
let sLength = signature[i++];
while (signature[i] == 0x00) { i++; sLength--; }
const s = new Uint8Array(signature.buffer, i, sLength);
//r|s
const l = Math.trunc((Math.max(rLength, sLength) + 1) / 2) * 2;
const result = new Uint8Array(l * 2);
result.set(r, l - rLength);
result.set(s, (l * 2) - sLength);
return result;
}
after converting signature everything worked out