1

I'm having trouble figuring out the right parameters to verify a SHA-256 signature that was created with an ECDSA P-256 public key in web crypto. Below script outputs:

Node verify result: true
Web verify result: false

What are the parameters to make verification work with web crypto too? I think I've tried everything by now except the right thing :|

(BTW tried the web piece in Chrome as well with same result)

const crypto = require("crypto");
const webcrypto = require("node:crypto").webcrypto;

const derEncodedPublicKey = Buffer.from(
  "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE5/J6xKyJxzOJ85om+jUJUFHMqnpruqXnKx5jKRojB3E1gC29g/kAc6xHunY05IW+gn2oeAdjggnH7a4WQ8/Afg==",
  "base64"
);

const data = new Uint8Array([
  73, 150, 13, 229, 136, 14, 140, 104, 116, 52, 23, 15, 100, 118, 96, 91, 143,
  228, 174, 185, 162, 134, 50, 199, 153, 92, 243, 186, 131, 29, 151, 99, 5, 0,
  0, 0, 0, 182, 173, 217, 158, 122, 216, 45, 140, 214, 44, 204, 209, 62, 118,
  45, 12, 238, 10, 91, 88, 80, 235, 131, 5, 70, 171, 245, 252, 71, 13, 207, 235,
]);

const sig = new Uint8Array([
  48, 68, 2, 32, 58, 26, 13, 251, 116, 195, 219, 77, 90, 1, 64, 38, 54, 249, 56,
  87, 235, 24, 78, 26, 13, 88, 74, 224, 159, 58, 159, 133, 111, 98, 69, 214, 2,
  32, 87, 1, 32, 191, 170, 10, 33, 204, 86, 124, 73, 21, 153, 4, 58, 182, 248,
  175, 144, 80, 146, 173, 247, 205, 36, 51, 59, 221, 212, 133, 107, 118,
]);

function nodeVerify() {
  const nodeKey = crypto.createPublicKey({
    format: "der",
    key: derEncodedPublicKey,
    type: "spki",
  });
  const v = crypto.createVerify("SHA256").update(data);
  return v.verify(nodeKey, sig);
}

async function webVerify() {
  const webkey = await webcrypto.subtle.importKey(
    "spki",
    derEncodedPublicKey,
    {
      name: "ECDSA",
      namedCurve: "P-256",
    },
    false,
    ["verify"]
  );
  return webcrypto.subtle.verify(
    {
      name: "ECDSA",
      hash: "SHA-256",
    },
    webkey,
    sig,
    data
  );
}

(async () => {
  console.log("Node verify result:", nodeVerify());
  console.log("Web verify result:", await webVerify());
})().catch(console.error);

NodeJS is easier, it needs less parameters :)

Thank you.

Otto
  • 1,787
  • 1
  • 17
  • 25

1 Answers1

2

After more googling and trying I found the answer: the ECDSA signature that I am using, is actually an ASN.1 encoded structure. NodeJS is fine with that during verification, however webcrypto not--it wants the raw signature, which is the byte concatenation of the 2 integers in the ASN.1 encoded signature.

More information in this post: https://crypto.stackexchange.com/questions/57731/ecdsa-signature-rs-to-asn1-der-encoding-question

Otto
  • 1,787
  • 1
  • 17
  • 25
  • 1
    Bleah! I rechecked my 'hint' list and found this which I should have been able to give you earlier: https://stackoverflow.com/questions/39554165/ecdsa-signatures-between-node-js-and-webcrypto-appear-to-be-incompatible (sorry) – dave_thompson_085 Aug 17 '22 at 03:28
  • No problem, was actually a bit of fun figuring this out haha. Should have found that post in my google searches! – Otto Aug 17 '22 at 20:37