javascriptpdfcryptographycertificatedigital-signature

Extracting RFC 3161 timestamp from digitally signed PDF using Javascript


I'm trying to extract the signing time from my pdf document, I know it has a timestamp from the Acrobat below :

Adobe Acrobat Info regarding timestamp

But when I try to print the authenticated attributes, I can't find them (OID for signingTime is 1.2.840.113549.1.9.5)

This is my code for finding the signingTime Attributes :

// Extract all authenticated attributes
  const authenticatedAttributes = attrs.map(attribute => {
    const oid = forge.asn1.derToOid(attribute.value[0].value);
    const attributeName = forge.pki.oids[oid] || oid; // Try to resolve OID to a human-readable name // Extract the value, which might be a date, a string, or another encoded type
    let value;
    try {
      value = forge.util.bytesToUtf8(attribute.value[1].value[0].value);
    } catch (e) {
      value = forge.util.bytesToHex(attribute.value[1].value[0].value);
    }
    return {
      oid,
      name: attributeName,
      value,
    };
  });
  console.log("Authenticated Attributes:", authenticatedAttributes);

Autenticated Attributes Console Log

But this is the console info for my "Authenticated Attributes" there are no signingTime OIDs, even though I know it exists from the Acrobat Signature Details above.

Can anyone please help?

The steps in order for me to extract the data is as follows:

const verify = (signature, signedData, signatureMeta) => {
  const message = getMessageFromSignature(signature);
  const {
    certificates,
    rawCapture: {
      signature: sig,
      authenticatedAttributes: attrs,
      digestAlgorithm,
    },
  } = message;
  // console.log(attrs);
  // Extract all authenticated attributes
  const authenticatedAttributes = attrs.map(attribute => {
    const oid = forge.asn1.derToOid(attribute.value[0].value);
    const attributeName = forge.pki.oids[oid] || oid; // Try to resolve OID to a human-readable name
    // Extract the value, which might be a date, a string, or another encoded type
    let value;
    try {
      value = forge.util.bytesToUtf8(attribute.value[1].value[0].value);
    } catch (e) {
      value = forge.util.bytesToHex(attribute.value[1].value[0].value);
    }
    return {
      oid,
      name: attributeName,
      value,
    };
  });
  console.log("Authenticated Attributes:", authenticatedAttributes);
};

I have read many similar questions :

the signature includes en embedded timeStamp but it could not be verified

How to decode timestamp from digital PKCS7 signature?

Verify RFC 3161 trusted timestamp

And have read the documentation about digital signature from:

https://www.adobe.com/devnet-docs/acrobatetk/tools/DigSigDC/Acrobat_DigitalSignatures_in_PDF.pdf

https://www.ietf.org/rfc/rfc3161.txt

But to no avail.

Update to mkl's solution (2024/08/31):

I have printed the unsigedn attributes, and have found the 1.2.840.113549.1.9.16.2.14 OID but the problem is there no value associated with that OID.

[![enter image description here][1]][1]

Update to mkl's solution number 2 (2024/09/15):

After modifying my code I have printed the value associated with 1.2.840.113549.1.9.16.2.14 OID, but the value associated with it seems to be another OID as can be seen from the image below:

[![update to mkl's solution][2]][2]

I'm still havent figured out how to print the signing time as can be seen from adobe's pdf app. [1]: https://i.sstatic.net/EPQzvaZP.png [2]: https://i.sstatic.net/e8liVmEv.png


Solution

  • I don't work with JavaScript, so I can only point out problems in your current approach but not show how to implement that in JavaScript.

    There are two major problems in your approach both of which become clear by reading RFC 3161 Appendix A.

    Wrong set of attributes

    You mention often that you look into the Authenticated Attributes (aka signed attributes). That is the wrong set of attributes to look for a time stamp in, as mentioned in RFC 3161 Appendix A:

    A sensible place to store a time-stamp is in a [CMS] structure as an unsigned attribute.

    (Thinking about this for a moment it should be obvious that a signature time stamp can not be in an attribute signed by the original signature.)

    Thus, switch to searching the correct set of attributes.

    Wrong attribute identifier

    You mention that you are looking for the attribute with the OID for signingTime (1.2.840.113549.1.9.5). But that is the wrong attribute to look for when searching a signature time stamp, as mentioned in RFC 3161 Appendix A:

    The following object identifier identifies the Signature Time-stamp attribute:

    id-aa-timeStampToken OBJECT IDENTIFIER ::= { iso(1) member-body(2)
    us(840) rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) aa(2) 14 }
    

    (The signingTime attribute you looked for is where you can put a claimed signing time, and that attribute indeed would be a signed attribute.)

    Thus, switch to searching for the attribute with identifier OID 1.2.840.113549.1.9.16.2.14.