Skip to content

AlgorithmIdentifier parameters accepted for ecdsa-with-SHA256 in CMS SignerInfo #464

@franrojasblaze

Description

@franrojasblaze

Summary

PKIjs accepts CMS SignerInfo.signatureAlgorithm values where the AlgorithmIdentifier contains unexpected parameters for the algorithm ecdsa-with-SHA256 (1.2.840.10045.4.3.2).

According to common ASN.1 usage and interoperability expectations for ECDSA-with-SHA2 identifiers, the AlgorithmIdentifier.parameters field should be absent.

However, PKIjs successfully parses CMS structures where parameters are present and contain unexpected types such as:

  • NULL

  • OCTET STRING

These structures are still considered valid during signature verification.

While major crypto stacks (e.g. OpenSSL and BouncyCastle) behave similarly and ignore the parameters, the acceptance of unexpected parameter encodings can create semantic ambiguity and policy mismatches across implementations.


Affected Component

CMS parsing and verification in PKIjs.

Relevant structure:

SignerInfo.signatureAlgorithm

ASN.1 structure:

AlgorithmIdentifier ::= SEQUENCE {
algorithm OBJECT IDENTIFIER,
parameters ANY DEFINED BY algorithm OPTIONAL
}

Tested algorithm:

ecdsa-with-SHA256
OID: 1.2.840.10045.4.3.2

Security Implication

Although the signature still verifies cryptographically, accepting arbitrary parameter encodings may enable:

  • inconsistent algorithm interpretation across implementations

  • policy validation bypass when strict DER/semantic validation is expected

  • potential parser differential scenarios in heterogeneous verification pipelines

Example scenario:

Component A (strict validator)
→ rejects AlgorithmIdentifier parameters

Component B (PKIjs)
→ ignores parameters and verifies signature

This creates a verification policy mismatch.

Such mismatches have historically led to signature verification issues in cryptographic systems.


Proof of Concept

The following PoC generates CMS structures where:

AlgorithmIdentifier.algorithm = ecdsa-with-SHA256
AlgorithmIdentifier.parameters = NULL or OCTET STRING

and demonstrates that PKIjs still verifies the signature.


PoC Environment

Node.js

Node 24.x
PKIjs
asn1js
OpenSSL

PoC Script (PKIjs)

import fs from "fs";
import * as asn1js from "asn1js";
import * as pkijs from "pkijs";

const webcrypto = globalThis.crypto;

pkijs.setEngine(
"nodeEngine",
webcrypto,
new pkijs.CryptoEngine({
name: "nodeEngine",
crypto: webcrypto,
subtle: webcrypto.subtle
})
);

function readDER(path) {
const b = fs.readFileSync(path);
return b.buffer.slice(b.byteOffset, b.byteOffset + b.byteLength);
}

function inspectCMS(path) {
const der = readDER(path);

const asn1 = asn1js.fromBER(der);

const contentInfo = new pkijs.ContentInfo({
schema: asn1.result
});

const signedData = new pkijs.SignedData({
schema: contentInfo.content
});

console.log("signerInfos:", signedData.signerInfos.length);

signedData.signerInfos.forEach((si, i) => {
const alg = si.signatureAlgorithm;

console.log(
`SignerInfo[${i}]`,
"sigAlg OID=" + alg.algorithmId,
"params=" +
(alg.algorithmParams
? alg.algorithmParams.constructor.name
: "absent")
);
});
}

inspectCMS("bad_a1_pkijs.cms.der");
inspectCMS("bad_a2_pkijs.cms.der");

Example Outputs

Valid CMS

SignerInfo[0] sigAlg OID=1.2.840.10045.4.3.2 params=absent

Modified CMS

SignerInfo[0] sigAlg OID=1.2.840.10045.4.3.2 params=OCTET STRING
SignerInfo[0] sigAlg OID=1.2.840.10045.4.3.2 params=NULL

Despite the parameter manipulation, the CMS signature remains valid.


Verification Behavior

Observed behavior:

Implementation | Result -- | -- PKIjs | accepts OpenSSL | accepts BouncyCastle | accepts

The parameters appear to be ignored during verification.


DER Example

Example DER encoding used in the PoC:

AlgorithmIdentifier
SEQUENCE
OBJECT IDENTIFIER 1.2.840.10045.4.3.2
OCTET STRING 00

Hex:

300d06082a8648ce3d040302040100

Recommendation

PKIjs could optionally enforce stricter validation rules for AlgorithmIdentifier parameters.

Suggested behavior:

If algorithm == ecdsa-with-SHA256
then parameters MUST be absent

Possible implementation:

if (algOID === "1.2.840.10045.4.3.2" && paramsPresent)
reject

Alternatively:

  • provide a strict validation mode

  • warn on unexpected parameter encodings


Disclosure Intent

This report is intended to highlight a semantic validation gap that may lead to interoperability issues or policy bypass in mixed cryptographic environments.

No direct exploit has been identified.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions