RFC 5544

Syntax for Binding Documents with Time-Stamps

πŸ“… published February 2010, from ietf

RFC 5544: Syntax for Binding Documents with Time-Stamps πŸŽ€

  • Stream: Independent Submission
  • Request for Comments: 5544
  • Author: A. Santoni, Actalis S.p.A.
  • Category: Informational
  • Date: February 2010
  • ISSN: 2070-1721
  • Obsoletes/Updates: The header doesn't list anything this RFC obsoletes or updates.

Abstract ✨

okay so this doc describes an envelope that lets you bind a file to one or more time-stamp tokens made for that file πŸ“Ž the file doesn't have to be cryptographically protected, which is giving flexibility. "time-stamp token" means what RFC 3161 or its successors define it to mean πŸ•°οΈ other kinds of temporal evidence are allowed too.

the envelope is based on the Cryptographic Message Syntax from RFC 5652 πŸ’–

Status of This Memo πŸ“œ

bestie, this one is not an Internet Standards Track spec. it's published just for information 🌸

it's an RFC Series contribution that's independent of any other RFC stream. the RFC Editor picked to publish it at their discretion, and they make no claims about whether it's worth implementing or deploying 🫢 anything the RFC Editor approves isn't a candidate for any level of Internet Standard. see Section 2 of RFC 5741 for that.

for info on the current status, errata, and how to give feedback, check http://www.rfc-editor.org/info/rfc5544 πŸ”Ž

IESG Note πŸ’…

this RFC is not a candidate for any level of Internet Standard, periodt. the standards track spec RFC 4998, Evidence Record Syntax (ERS), offers a different mechanism. readers are encouraged to also look at RFC 4998 when deciding whether this mechanism fits their needs 🧚

Copyright (c) 2010 IETF Trust and the persons identified as the document authors. All rights reserved.

this document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (http:trustee.ietf.org/license-info) as they stand on the publication date. please read those carefully, because they spell out your rights and restrictions for this doc πŸ“–

Table of Contents πŸ—‚οΈ

1. Introduction ....................................................2
   1.1. Conventions Used in This Document ..........................3
2. Syntax for TimeStampedData ......................................3
3. Compliance Requirements .........................................6
4. Recommended Processing ..........................................6
   4.1. Generating a New TimeStampedData Structure .................7
   4.2. Verifying an Existing TimeStampedData Structure ............8
   4.3. Extending the Validity of an Existing
        TimeStampedData Structure ..................................9
5. Security Considerations .........................................9
6. Normative References ...........................................10
7. Informative References .........................................10
Appendix A. ASN.1 Module ..........................................11
Appendix B. Acknowledgments .......................................12

1. Introduction πŸ¦‹

time-stamping has basically become the go-to way to prove a document existed before a certain point in time πŸ•°οΈ a bunch of countries have laws that embrace it and set up time-stamping services, mostly so people can extend how long their signed documents stay valid. but here's the thing: time-stamping makes digital signatures stronger, and it doesn't need them to work. it can be useful to time-stamp a document even if nobody signed it. and sometimes it's useful, or even required in some cases, to time-stamp a signed document as a whole, no matter how many signatures are on it πŸ’œ

when a time-stamp is tied to a digital signature, there's already a way to keep them together. RFC 3161 [TSP] explains how one or more TimeStampTokens can be put in a SignerInfo structure as unsigned attributes πŸŽ€ but there's no standard way to keep a time-stamped document (signed or not) together with its time-stamps. πŸ’€

so right now people usually go one of two ways:

  • time-stamps are kept as separate files, and keeping track of which time-stamp goes with which document is up to the user
  • an ad hoc solution gets used for specific apps, like a ZIP archive or some proprietary "envelope"

both of those get in the way of interoperability, and interoperability is the whole point of this memo 🫢

this doc describes a simple syntax for binding one document (actually, any kind of file) to the temporal evidence that goes with it. that evidence is usually one or more RFC 3161 TimeStampTokens. other kinds of temporal evidence, like an RFC 4998 EvidenceRecord [ERS], are also supported through an "open" syntax 🌸 but for the sake of interoperability, this document puts its emphasis on TimeStampTokens.

the proposed syntax is broadly based on the Cryptographic Message Syntax (CMS) from RFC 5652 [CMS] ✨

1.1. Conventions Used in This Document πŸ“

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 [KWORDS].

the terms "document" and "file" get used interchangeably. same deal with "TimeStampToken" and "time-stamp token", which both refer to the data structure defined in RFC 3161 πŸ“

2. Syntax for TimeStampedData 🧁

the proposed data structure is called TimeStampedData, and it's built on the ContentInfo envelope from [CMS] πŸ’–

   ContentInfo ::= SEQUENCE {
      contentType ContentType,
      content [0] EXPLICIT ANY DEFINED BY contentType }

   ContentType ::= OBJECT IDENTIFIER

CMS defines six content types (data, signed-data, enveloped-data, digested-data, encrypted-data, and authenticated-data), and this memo adds one more: timestamped-data. it's identified by this Object Identifier (OID) πŸ‘‘

   id-ct-timestampedData OBJECT IDENTIFIER ::= {
            iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1)
            pkcs9(9) id-smime(16) id-ct(1) 31 }

this particular OID signals that the content field of the ContentInfo has the following syntax πŸ”₯

   TimeStampedData ::= SEQUENCE {
      version              INTEGER { v1(1) },
      dataUri              IA5String OPTIONAL,
      metaData             MetaData OPTIONAL,
      content              OCTET STRING OPTIONAL,
      temporalEvidence     Evidence
   }

   MetaData ::= SEQUENCE {
      hashProtected        BOOLEAN,
      fileName             UTF8String OPTIONAL,
      mediaType            IA5String OPTIONAL,
      otherMetaData        Attributes OPTIONAL
   }

   Attributes ::=
      SET SIZE(1..MAX) OF Attribute -- according to RFC 5652

   Evidence ::= CHOICE {
      tstEvidence    [0] TimeStampTokenEvidence,   -- see RFC 3161
      ersEvidence    [1] EvidenceRecord,           -- see RFC 4998
      otherEvidence  [2] OtherEvidence
   }

   OtherEvidence ::= SEQUENCE {
      oeType               OBJECT IDENTIFIER,
      oeValue              ANY DEFINED BY oeType }

   TimeStampTokenEvidence ::=
      SEQUENCE SIZE(1..MAX) OF TimeStampAndCRL

   TimeStampAndCRL ::= SEQUENCE {
      timeStamp   TimeStampToken,          -- according to RFC 3161
      crl         CertificateList OPTIONAL -- according to RFC 5280
   }

the version field holds the version number of the TimeStampedData syntax. it SHALL be 1 for this version of the document πŸŽ€

the dataUri field has a URI reference that conforms to [URI]. when the content field is missing, dataUri MUST be present and contain a URI that lets you retrieve the time-stamped document (unless the doc has since moved) πŸ”— when the content field is there, this field MAY also be there 🫧

the metaData field holds metadata about the time-stamped document, if that applies. specifically:

  • hashProtected says whether the metadata got included when computing the digest inside the first TimeStampToken (more on that below). this is what lets you spot if the metadata was changed later πŸ•΅οΈβ€β™€οΈ
  • fileName holds the original filename of the time-stamped document πŸ“
  • mediaType holds a media type/subtype and any parameters for the time-stamped document, per [MIME]. this can help decide how to "open" or handle the doc πŸ“‚
  • otherMetaData holds extra attributes of the time-stamped document (like a description, a claimed author, and so on). each attribute is specified by an object identifier plus a matching set of values, as described in [CMS]. when this field is there, it MUST contain at least one Attribute ✨

inside metaData (if it's there), at least one of the fileName, mediaType, and otherMetaData sub-fields MUST be present πŸ™ˆ

the Attribute values inside otherMetaData MUST be DER encoded, even if the rest of the structure is BER encoded 🧠

the content field, when present, carries the entire contents of the time-stamped document, in its original format and encoding. and I mean any kind of data: a text doc, an executable, a movie, a message, whatever 🎬 leaving out content lets you bind the temporal evidence to external data. in that case, the temporal evidence gets computed as though the content field were there πŸ¦‹

the temporalEvidence field carries the evidence that the time-stamped document existed before a certain point in time. a few types of evidence are allowed, but compliant apps only have to support the RFC 3161 type, which is the tstEvidence choice πŸ’…

the TimeStampTimeEvidence sequence MUST contain at least one element of type TimeStampAndCRL.

wait, correction bestie, the rule is about the TimeStampTokenEvidence sequence, so let me say it right: the TimeStampTokenEvidence sequence MUST contain at least one element of type TimeStampAndCRL πŸ™

the elements of the TimeStampTokenEvidence sequence MUST follow this rule:

  • if the metaData field is absent, or its hashProtected field is FALSE, then the TimeStampToken inside the first element SHALL be computed over the value octets of the content field (if content is absent, use the octets retrieved via the dataUri field) πŸ”
  • otherwise (metaData is present and its hashProtected field is TRUE), the TimeStampToken inside the first element SHALL be computed over the concatenation of these fields:
    • the DER encoding of the metaData field
    • the value octets of the content field (if content is absent, use the octets retrieved via the dataUri field)
  • the TimeStampToken inside the second element SHALL be computed over the first element πŸ”—
  • the TimeStampToken inside each subsequent element SHALL be computed over its preceding element in the sequence 🧚

inside the TimeStampAndCRL construct, the optional crl field carries a suitable CRL (Certificate Revocation List). that CRL shows the certificate of the TSA (Time-Stamping Authority) that issued the TimeStampToken wasn't revoked at the time the next element in the TimeStampTokenEvidence sequence got added. the Security Considerations section goes deeper on this, and it's worth a read 🌈

3. Compliance Requirements πŸ’…

okay so bestie, the bare minimum here is that compliant applications MUST support at least the RFC 3161-based type of evidence, aka the tstEvidence CHOICE πŸŽ€. that's the non-negotiable one 😀

this section is all about the RFC 3161-based type of evidence 🧚 other kinds of evidence get processed in a similar way, so once you get this one you basically have them too πŸ’–

4.1. Generating a New TimeStampedData Structure 🌸

okay so when an application is making a brand new one, it should do the following:

  • fill in the version field with the integer value v1(1) πŸ“
  • if you're making a self-contained envelope, always fill in the content field with the file's content in its original format and encoding. depending on the app, you may also add the dataUri field 🫢
  • otherwise (you're making a detached envelope), always fill in the dataUri field with the URI of the time-stamped document, like http://foo.example.com/Contract12345.pdf. whether you use an absolute URI or a relative reference is up to the app πŸ”—
  • if you're adding the metaData field, decide what its hashProtected field should be. set it to TRUE if the app needs the rest of the metaData construct to be hash-protected as described in Section 2. otherwise, set it to FALSE ✨
  • if you're adding the metaData field, you can optionally fill in the fileName field (like "Contract12345.pdf"), the mediaType field with a suitable media type/subtype and any parameters according to [MIME], and the otherMetaData field, depending on the app πŸ¦‹
  • pick a suitable one-way hash function and compute a hash value over the content, or over the concatenation of the metadata and the content, as described in Section 2. that hash value is what gets used to request the first TimeStampToken πŸ’œ
  • get the first temporal evidence from a TSA and add it to the temporalEvidence field πŸ•°οΈ
  • stick the TimeStampedData into a ContentInfo structure, with the id-ct-timestampedData OID in the contentType field πŸ’…
  • BER-encode the ContentInfo structure (except for the fields that are required to be DER encoded) and save it with a reasonable file name, like one derived from the name of the time-stamped file πŸ“

4.2. Verifying an Existing TimeStampedData Structure πŸ”

okay so when an application is verifying one that already exists, it should do the following:

  • check that the contentType field of the ContentInfo structure has the expected value (id-ct-timestampedData) in its contentType field. then extract the inner TimeStampedData structure and keep processing 🫧
  • check the version field. it should be v1 🌈
  • check that the temporalEvidence field is not empty πŸ‘€
  • check whether the content is present. if it isn't, use the dataUri field to retrieve the file πŸ“₯
  • open the first element of the TimeStampTokenEvidence sequence, open the time-stamp token inside it, and use the hash function that was used to get it to re-compute the hash of the fields indicated in Section 2. if the re-computed hash value matches the one inside the time-stamp token, keep processing. otherwise, the TimeStampedData structure has been modified 🚨
  • validate the temporalEvidence by checking that:
    • each TimeStampToken in the chain does contain the correct digest value (according to the rule described in Section 2) and it was signed by a trusted TSA,
    • the corresponding TSA signing certificate was not revoked at the time when the subsequent TimeStampToken was issued, based on the associated CRL;
  • depending on the app, use the temporal evidence for whatever purpose the app was built for 🎯
  • depending on the app, show the dataUri, the fileName, the mediaType, the otherMetaData, and the temporal evidence to the user πŸ‘‘
  • depending on the app, save the content to a separate file πŸ’Ύ
  • depending on the app, store the content that was retrieved using the dataUri field somewhere else, then update the dataUri field to match πŸ—‚οΈ
  • depending on the app, show the time-stamped file to the user, maybe by opening a suitable "viewer" πŸ‘οΈ

4.3. Extending the Validity of an Existing TimeStampedData Structure ⏳

okay so when you want to extend the validity of one that already exists, it should do the following:

  • validate the TimeStampedData structure as described above 🧐
  • pick the time-stamp token from the last TimeStampAndCRL element in the chain, and get the latest available CRL for the corresponding TSA certificate. if that CRL isn't fresh enough, wait until the next one is available. then store it in the TimeStampAndCRL element πŸ“œ
  • create a new TimeStampAndCRL element and get a new time-stamp token computed over the previous one, according to the rule described in Section 2. put the new time-stamp token into the new TimeStampAndCRL element, then add that element to the end of the chain πŸ”—

See the Security Considerations section for further discussion on extending the validity of an existing TimeStampedData structure. it's a whole topic, trust me πŸ™ˆ

5. Security Considerations πŸ”

⚠️ this section is SERIOUS, bestie. don't skip it 😭

okay so when the metaData field is present and its hashProtected sub-field is set to TRUE, the metadata is also part of the digest computed inside the first time-stamp token. that means any later change to the metadata gets caught super easily πŸ•΅οΈβ€β™€οΈ BUT (and this is a big but) the fact that hash-protected metadata hasn't been changed does NOT mean the metadata was correct when the TimeStampedData object was created. you can only figure that out some other way, like from context 🧩 for example, if an archival service provider made the TimeStampedData objects, it may be reasonable to assume the metadata was correct when it was created. but if a TimeStampedData object shows up from an unknown party, the recipient can't safely assume the metadata is correct without more info 🚫

in general, a time-stamp token should not be considered valid after the certificate of the issuing TSA has expired. (this also depends on the legislation and the policy the TSA runs under πŸ“š) however, a time-stamp token can itself be time-stamped to extend the validity of the TSA's signature. if you keep doing that, a whole chain of time-stamp tokens can grow to extend the validity of the first one ad libitum ♾️ so this approach can be used to extend the validity of a TimeStampedData structure past the expiry date of the first TimeStampToken inside it, by adding more elements to the TimeStampTokenEvidence sequence according to the rule described in Section 2. of course, each additional TimeStampToken must be added in a timely manner, before the previous one has expired or been revoked ⏰

the validity extension technique described above requires that the TSA signing certificates can still be verified long after they've expired, usually by checking a CRL 🫠 the CRL has to be captured at the right time, because expired certificates are usually removed from the CRL whether or not they were revoked πŸ—‘οΈ the TimeStampAndCRL construct lets you add a CRL right next to the related TimeStampToken, so the TSA certificate will still be verifiable at any later time πŸ’œ the CRL must be captured at the time when another element is about to be added to the TimeStampTokenEvidence sequence, or even later, to allow for a last-minute revocation request to be processed by the CA (see the discussion about "grace periods" in [CADES]). that's the grace period tea β˜•

6. Normative References πŸ“š

[CMS] Housley, R., "Cryptographic Message Syntax (CMS)", RFC 5652, September 2009.

[ERS] Gondrom, T., Brandner, R., and U. Pordesch, "Evidence Record Syntax (ERS)", RFC 4998, August 2007.

[KWORDS] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997.

[MIME] Freed, N. and N. Borenstein, "Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies", RFC 2045, November 1996.

[PKIX1] Cooper, D., Santesson, S., Farrell, S., Boeyen, S., Housley, R., and W. Polk, "Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile", RFC 5280, May 2008.

[TSP] Adams, C., Cain, P., Pinkas, D., and R. Zuccherato, "Internet X.509 Public Key Infrastructure Time-Stamp Protocol (TSP)", RFC 3161, August 2001.

[URI] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform Resource Identifier (URI): Generic Syntax", STD 66, RFC 3986, January 2005.

7. Informative References πŸ¦‹

[CADES] Pinkas, D., Pope, N., and J. Ross, "CMS Advanced Electronic Signatures (CAdES)", RFC 5126, March 2008.

Appendix A. ASN.1 Module πŸ“œβœ¨

okay so this appendix is the actual ASN.1 module, bestie 🧚 it's the grammar that defines all the structures you need to implement this spec. and it's giving "use me alongside the other modules" energy: the ones from [CMS], [TSP], [PKIX1], and [ERS] πŸ’…

TimeStampedDataModule
   { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1)
     pkcs-9(9) smime(16) modules(0) 35 }

   DEFINITIONS IMPLICIT TAGS ::=
   BEGIN

   IMPORTS

      -- Imports from RFC 5652 [CMS]
      Attribute
         FROM CryptographicMessageSyntax2004
            { iso(1) member-body(2) us(840) rsadsi(113549)
              pkcs(1) pkcs-9(9) smime(16) modules(0) cms-2004(24) }

      -- Imports from RFC 3161 [TSP]
      TimeStampToken
         FROM PKIXTSP
            { iso(1) identified-organization(3) dod(6) internet(1)
              security(5) mechanisms(5) pkix(7) id-mod(0)
              id-mod-tsp(13)}

      -- Imports from RFC 5280 [PKIX1]
      CertificateList
         FROM PKIX1Explicit88
            { iso(1) identified-organization(3) dod(6) internet(1)
              security(5) mechanisms(5) pkix(7) id-mod(0)
              id-pkix1-explicit-88(18)}

      -- Imports from RFC 4998 [ERS]
      EvidenceRecord
         FROM ERS
            { iso(1) identified-organization(3) dod(6) internet(1)
              security(5) mechanisms(5) ltans(11) id-mod(0)
              id-mod-ers88(2) id-mod-ers88-v1(1) };

   -- TimeStampedData Content Type and Object Identifier

   id-ct-timestampedData OBJECT IDENTIFIER ::= {
      iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
      id-smime(16) id-ct(1) 31 }

   TimeStampedData ::= SEQUENCE {
      version              INTEGER { v1(1) },
      dataUri              IA5String OPTIONAL,
      metaData             MetaData OPTIONAL,
      content              OCTET STRING OPTIONAL,
      temporalEvidence     Evidence
   }

   MetaData ::= SEQUENCE {
      hashProtected        BOOLEAN,
      fileName             UTF8String OPTIONAL,
      mediaType            IA5String OPTIONAL,
      otherMetaData        Attributes OPTIONAL
   }

   Attributes ::=
      SET SIZE(1..MAX) OF Attribute -- according to RFC 5652

   Evidence ::= CHOICE {
      tstEvidence    [0] TimeStampTokenEvidence,   -- see RFC 3161
      ersEvidence    [1] EvidenceRecord,           -- see RFC 4998
      otherEvidence  [2] OtherEvidence
   }

   OtherEvidence ::= SEQUENCE {
      oeType            OBJECT IDENTIFIER,
      oeValue           ANY DEFINED BY oeType }

   TimeStampTokenEvidence ::=
      SEQUENCE SIZE(1..MAX) OF TimeStampAndCRL

   TimeStampAndCRL ::= SEQUENCE {
      timeStamp   TimeStampToken,          -- according to RFC 3161
      crl         CertificateList OPTIONAL -- according to RFC 5280
   }

   END

Appendix B. Acknowledgments 🫢

Thanks to Stephen Kent for encouraging the author in the early stages of this work. 🌸

Thanks to Russ Housley for reviewing this memo, suggesting useful amendments and assigning a value to the OIDs herein defined. πŸ’–

Thanks are also due to other people who reviewed this memo and helped improve it, but prefer not to be mentioned. πŸ™ˆ

Author's Address πŸŽ€

Adriano Santoni Actalis S.p.A. Via Taramelli 26 I-20124 Milano Italy

EMail: adriano.santoni@actalis.it


That's the whole doc, bestie! βœ¨πŸ‘‘ Literally obsessed with how it all fits together πŸ¦‹

πŸ“¦ where this page comes from