denoland/deno · error · DOMException

Named curve mismatch

Error message

Named curve mismatch

What it means

_validateEcNamedCurve throws DOMException DataError 'Named curve mismatch' when an EC KeyObject on one curve is converted via toCryptoKey() with an algorithm object whose namedCurve names a different curve. The polyfill first normalizes OpenSSL names (prime256v1/secp384r1/secp521r1) and WebCrypto names (P-256/P-384/P-521) to a common form, so only genuine mismatches throw — either naming style works if it is the right curve.

Source

Thrown at ext/node/polyfills/internal/crypto/keys.ts:1063

function _validateEcNamedCurve(
  keyObject: AsymmetricKeyObject,
  algorithm: object,
) {
  const details = keyObject.asymmetricKeyDetails;
  const alg = algorithm as { namedCurve?: string };
  if (alg.namedCurve && details?.namedCurve) {
    const curveMap: Record<string, string> = {
      "prime256v1": "P-256",
      "secp384r1": "P-384",
      "secp521r1": "P-521",
      "P-256": "P-256",
      "P-384": "P-384",
      "P-521": "P-521",
    };
    const keyCurve = curveMap[details.namedCurve] || details.namedCurve;
    if (keyCurve !== alg.namedCurve) {
      throw new DOMException("Named curve mismatch", "DataError");
    }
  }
}

function createSecretKey(
  key: string | ArrayBufferView | ArrayBuffer | KeyObject | CryptoKey,
  encoding?: string,
): KeyObject {
  if (isCryptoKey(key)) {
    if (key.type !== "secret") {
      throw new ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE(key.type, "secret");
    }
    return KeyObject.from(key);
  }
  const preparedKey = prepareSecretKey(key, encoding, true);
  if (isArrayBufferView(preparedKey) || isAnyArrayBuffer(preparedKey)) {
    const handle = op_node_create_secret_key(preparedKey);
    return new SecretKeyObject(handle);

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Set namedCurve to the key's actual curve: 'P-256', 'P-384' or 'P-521'
  2. Read keyObject.asymmetricKeyDetails.namedCurve and feed that value into the algorithm object
  3. Centralize the curve in one constant used by both generation and conversion code

Example fix

// before
const ck = privateKey.toCryptoKey({ name: 'ECDSA', namedCurve: 'P-384' }, true, ['sign']); // key is P-256 -> throws

// after
const details = privateKey.asymmetricKeyDetails;
const ck = privateKey.toCryptoKey({ name: 'ECDSA', namedCurve: details.namedCurve }, true, ['sign']);
Defensive patterns

Strategy: validation

Validate before calling

const NORMALIZE: Record<string, string> = {
  prime256v1: 'P-256', secp384r1: 'P-384', secp521r1: 'P-521',
};
const details = privateKey.asymmetricKeyDetails;
if (details?.namedCurve && params.namedCurve) {
  const keyCurve = NORMALIZE[details.namedCurve] ?? details.namedCurve;
  if (keyCurve !== params.namedCurve) {
    params = { ...params, namedCurve: keyCurve };
  }
}
const ck = privateKey.toCryptoKey(params, true, ['sign']);

Type guard

function namedCurveMatches(keyObject: KeyObject, namedCurve: string): boolean {
  const map: Record<string, string> = {
    prime256v1: 'P-256', secp384r1: 'P-384', secp521r1: 'P-521',
  };
  const d = keyObject.asymmetricKeyDetails?.namedCurve;
  return !d || !namedCurve || (map[d] ?? d) === namedCurve;
}

Try / catch

try {
  ck = privateKey.toCryptoKey(params, true, usages);
} catch (e) {
  if (e instanceof DOMException && e.name === 'DataError' && e.message === 'Named curve mismatch') {
    const actual = privateKey.asymmetricKeyDetails.namedCurve;
    ck = privateKey.toCryptoKey({ ...params, namedCurve: actual }, true, usages);
  } else throw e;
}

Prevention

When it happens

Trigger: generateKeyPairSync('ec', { namedCurve: 'prime256v1' }).privateKey.toCryptoKey({ name: 'ECDSA', namedCurve: 'P-384' }, true, ['sign']) — key is P-256, params say P-384.

Common situations: Curve configured in one place for key generation and in another for import/use; a shared default namedCurve drifting from the keys actually issued; compliance-mandated migration to P-384 while old P-256 keys are still converted by the same code.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/4a7e6cd74ddf1650. Report an issue: GitHub.