gchq/CyberChef · error · OperationError

'cRLReason' CRL entry extension missing 'code' key: ${ext}

Error message

'cRLReason' CRL entry extension missing 'code' key: ${ext}

What it means

For a CRL entry extension with extname 'cRLReason', formatCRLEntryExtensions requires a 'code' key (the numeric reason code). If absent the op cannot render the revocation reason and throws. This is an assertion about jsrsasign's parsed cRLReason structure inside a revoked-cert entry.

Source

Thrown at src/core/operations/ParseX509CRL.mjs:318

        8: "Remove From CRL",
        9: "Privilege Withdrawn",
        10: "AA Compromise",
    };

    const holdInstructionOIDToName = {
        "1.2.840.10040.2.1": "Hold Instruction None",
        "1.2.840.10040.2.2": "Hold Instruction Call Issuer",
        "1.2.840.10040.2.3": "Hold Instruction Reject",
    };

    exts.forEach((ext) => {
        if (!Object.hasOwn(ext, "extname")) {
            throw new OperationError(`CRL entry extension object missing 'extname' key: ${ext}`);
        }
        switch (ext.extname) {
            case "cRLReason":
                if (!Object.hasOwn(ext, "code")) {
                    throw new OperationError(`'cRLReason' CRL entry extension missing 'code' key: ${ext}`);
                }
                out += `X509v3 CRL Reason Code:
    ${Object.hasOwn(crlReasonCodeToReasonMessage, ext.code) ? crlReasonCodeToReasonMessage[ext.code] : `invalid reason code: ${ext.code}`}\n`;
                break;
            case "2.5.29.23": // Hold instruction
                out += `Hold Instruction Code:\n\t${Object.hasOwn(holdInstructionOIDToName, ext.extn.oid) ? holdInstructionOIDToName[ext.extn.oid] : `${ext.extn.oid}: unknown hold instruction OID`}\n`;
                break;
            case "2.5.29.24": // Invalidity Date
                out += `Invalidity Date:\n\t${generalizedDateTimeToUTC(ext.extn.gentime.str)}\n`;
                break;
            default:
                out += `${ext.extname}:\n`;
                out += `\tUnsupported CRL entry extension. Try openssl CLI.\n`;
                break;
        }
    });

    return chop(out);

View on GitHub (pinned to 4290ea7539)

Solutions

  1. Inspect the entry's reason code with openssl.
  2. Re-fetch the CRL from the CA distribution point.
  3. Verify the bundled jsrsasign version.
  4. Report a conformant CRL that the op rejects so the key check can be relaxed.
Defensive patterns

Strategy: try-catch

Validate before calling

const crl = new r.X509CRL(input);
const reasonExts = (crl.getRevCertArray() || []).flatMap(rc => (rc.ext || []).filter(e => e.extname === "cRLReason"));
if (reasonExts.some(e => !Object.hasOwn(e, "code"))) {
  throw new Error("A cRLReason entry extension is missing 'code'");
}

Type guard

function isValidCrlReasonExtension(ext) {
  return ext.extname !== "cRLReason" || Object.hasOwn(ext, "code");
}

Try / catch

try {
  return parseX509CRL.run(crlInput, [inputFormat]);
} catch (e) {
  if (e.message.includes("'cRLReason' CRL entry extension missing 'code'")) {
    // non-standard reason-code encoding; validate with openssl
  }
  throw e;
}

Prevention

When it happens

Trigger: A revoked-cert entry with a cRLReason extension (OID 2.5.29.21) whose parsed object lacks 'code'; malformed reason-code value; jsrsasign returning a different key name.

Common situations: Non-standard reason-code encoding; corrupt CRL; jsrsasign version skew.

Related errors


AI-assisted analysis of gchq/CyberChef@4290ea7539 (2026-08-13). Data as JSON: /api/errors/42981104d7a6e973. Report an issue: GitHub.