跳到主要内容
ecdsa.com
WebCrypto SubtleCrypto.importKeyWebCrypto

错误信息

TypeError: Failed to execute 'importKey' on 'SubtleCrypto': The provided value is not of type '(ArrayBuffer or ArrayBufferView or JsonWebKey)'.

也可能输出为

  • TypeError: SubtleCrypto.importKey: Argument 2 is not an object.
  • TypeError: Type error

上面是 Chromium 的文本;Firefox 报“SubtleCrypto.importKey: Argument 2 is not an object.”,Safari/WebKit 只报“Type error”。对于同样的调用,Node.js 报告的是 `ERR_INVALID_ARG_TYPE`。

WebCrypto SubtleCrypto.importKey — PEM text passed as keyData (Chromium / Firefox / WebKit)

含义

`importKey` 的 `keyData` 参数收到的是字符串。WebCrypto 从不解析文本:对于 `"spki"`、`"pkcs8"` 和 `"raw"`,它要求二进制 DER(`ArrayBuffer` 或类型化数组);对于 `"jwk"`,它要求 JavaScript 对象。浏览器在参数转换阶段就拒绝了这次调用,还没有查看格式或密钥——所以 PEM 本身可能完全有效。

原因

修复方法

  1. 1.

    去掉封装行并解码为字节

    删除 BEGIN/END 行和空白字符,做 base64 解码,然后根据标签选择格式:`PUBLIC KEY` → `spki`,`PRIVATE KEY` → `pkcs8`。

    js
    function pemToDer(pem) {
      const base64 = pem.replace(/-----(BEGIN|END) [A-Z ]+-----/g, "").replace(/\s+/g, "");
      return Uint8Array.from(atob(base64), (c) => c.charCodeAt(0));
    }
    
    const publicKey = await crypto.subtle.importKey(
      "spki", pemToDer(publicKeyPem),               // "PUBLIC KEY" -> spki, "PRIVATE KEY" -> pkcs8
      { name: "ECDSA", namedCurve: "P-256" }, false, ["verify"],
    );
  2. 2.

    以对象形式传入 JWK

    JWKS 端点返回的本来就是对象;JSON 文本只需解析一次,然后把对象连同相匹配的曲线一起传入。

    js
    const jwk = JSON.parse(jwkText);                  // an object, not the JSON string
    const key = await crypto.subtle.importKey("jwk", jwk, { name: "ECDSA", namedCurve: jwk.crv }, false, ["verify"]);

相关错误

浏览完整的签名错误库