@blamejs/pki 0.8.51 → 0.8.53

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/cms-sign.js CHANGED
@@ -25,6 +25,11 @@ var _promiseResolve = intrinsic.uncurry(intrinsic.promiseResolve);
25
25
  var _promiseAll = intrinsic.uncurry(intrinsic.promiseAll);
26
26
  var pkiBuild = require("./pki-build");
27
27
  var cms = require("./schema-cms");
28
+ var constants = require("./constants");
29
+ /** @internal The RFC 3161 structural layer, for the one thing this module asks of a token: which
30
+ * octets its message imprint claims to cover. `schema-tsp` reaches only the schema modules, so this
31
+ * is not the signing module's own cycle back through `tsp-sign`. */
32
+ var tsp = require("./schema-tsp");
28
33
 
29
34
  var subtle = webcrypto.webcrypto.subtle;
30
35
  var CmsError = frameworkError.CmsError;
@@ -35,13 +40,14 @@ function O(name) { return oid.byName(name); }
35
40
 
36
41
  var KNOWN_SIGN_OPTS = intrinsic.assign(intrinsic.create(null), {
37
42
  signedAttributes: 1, signingTime: 1, additionalSignedAttributes: 1, unsignedAttributes: 1,
43
+ algorithmProtection: 1,
38
44
  sid: 1, eContentType: 1, detached: 1, certificates: 1, pem: 1,
39
45
  });
40
46
  var KNOWN_SIGNER_CERT_KEYS = intrinsic.assign(intrinsic.create(null), { cert: 1, key: 1, pss: 1, digestAlgorithm: 1, combinedRsaSig: 1 });
41
47
  var KNOWN_SIGNER_KEY_ONLY_KEYS = intrinsic.assign(intrinsic.create(null), { spki: 1, keyIdentifier: 1, key: 1, pss: 1, digestAlgorithm: 1, combinedRsaSig: 1 });
42
48
  var KNOWN_COUNTERSIGN_OPTS = intrinsic.assign(intrinsic.create(null), {
43
49
  signerIndex: 1, countersignatureOf: 1, signingTime: 1, certificates: 1, pem: 1,
44
- signedAttributes: 1, additionalSignedAttributes: 1, sid: 1,
50
+ signedAttributes: 1, additionalSignedAttributes: 1, sid: 1, algorithmProtection: 1,
45
51
  });
46
52
  var NS = pkix.makeNS("cms", CmsError, oid);
47
53
  var _b = pkiBuild.makeBuilder({
@@ -113,6 +119,12 @@ var UNSIGNED_FORBIDDEN = intrinsic.create(null);
113
119
  UNSIGNED_FORBIDDEN[O("contentType")] = "content-type";
114
120
  UNSIGNED_FORBIDDEN[O("messageDigest")] = "message-digest";
115
121
  UNSIGNED_FORBIDDEN[O("signingTime")] = "signing-time";
122
+ /** @internal RFC 6211 sec. 2: the algorithm protection attribute "MUST NOT be an unsigned
123
+ * attribute", and sec. 5 adds that one placed there "does not provide any additional security".
124
+ * Both identifiers, since the two spell one attribute. The parser refuses the placement, so without
125
+ * the door here this verb would emit a message its own verifier rejects. */
126
+ UNSIGNED_FORBIDDEN[O("cmsAlgorithmProtection")] = "algorithm protection";
127
+ UNSIGNED_FORBIDDEN[O("cmsAlgorithmProtect")] = "algorithm protection";
116
128
 
117
129
  function _buildUnsignedAttrs(list) {
118
130
  if (list == null) return null;
@@ -136,6 +148,49 @@ function _buildUnsignedAttrs(list) {
136
148
  return wire;
137
149
  }
138
150
 
151
+ /** @internal The RFC 6211 attribute built from the very TLVs the structure's own fields are built
152
+ * from. Sec. 2 says the attribute "contains a copy of the SignerInfo.digestAlgorithm field ...
153
+ * including any parameters associated with it", so the copy is made from the value in hand rather
154
+ * than re-derived from a registry row: a re-derivation can differ from the field it claims to copy,
155
+ * and the parameters are the substitution target the attribute exists to pin.
156
+ *
157
+ * `armTag` is 1 for a `SignerInfo` signature algorithm and 2 for an `AuthenticatedData` MAC
158
+ * algorithm, which sec. 2 makes exclusive to their own placements. `attrOid` is the identifier the
159
+ * caller's option resolved to, taken at the door so the pair carries the one that was asked for. */
160
+ function _algorithmProtectionPair(attrOid, digestAlgId, armAlgId, armTag) {
161
+ return { type: attrOid, values: [b.sequence([digestAlgId, b.implicit(armTag, armAlgId)])] };
162
+ }
163
+
164
+ /** @internal An asked-for protection that cannot be placed is a refusal rather than a message that
165
+ * silently lacks it. The attribute rides in the signed attributes, so with none there is nowhere to
166
+ * put it, which is why RFC 8933 sec. 4.1 conditions its SHOULD on their presence. A caller who
167
+ * names both options is asking for two things that cannot both hold.
168
+ *
169
+ * The option is resolved FIRST, on every route, and the placement question asked second. Resolving
170
+ * it inside the placement test would only read it on the route that cannot place it: a streamed
171
+ * content is consumed and hashed before the attributes are built, so a misspelled value would be
172
+ * refused after the stream had been read, which for a stream that cannot be replayed is a refusal
173
+ * the caller cannot act on, and for one that never ends is no refusal at all.
174
+ *
175
+ * The emitter below reads the same option again, which is sound because the options door refuses
176
+ * one supplied through an accessor, own or inherited, before any value is read: two reads of a
177
+ * plain field are one answer. */
178
+ function _assertProtectionPlaceable(opts) {
179
+ var wanted = cms.algorithmProtectionOid(opts.algorithmProtection, _err);
180
+ if (opts.signedAttributes === false && wanted) {
181
+ throw _err("cms/bad-input", "algorithmProtection needs signed attributes to ride in, and " +
182
+ "signedAttributes: false signs the content directly (RFC 6211 sec. 2 places the attribute in " +
183
+ "SignerInfo.signedAttrs); drop one of the two");
184
+ }
185
+ }
186
+
187
+ /** @internal The producer door, applied to this verb's attribute records. The policy itself lives in
188
+ * `schema-cms`, so the signing verbs and the authenticate verb enforce one rule rather than three
189
+ * copies of it. */
190
+ function _assertAlgorithmProtectionPairs(pairs, digestAlgId, armAlgId, armTag) {
191
+ cms.assertAlgorithmProtectionEmission(pairs, b.sequence([digestAlgId, b.implicit(armTag, armAlgId)]), _err);
192
+ }
193
+
139
194
  function _resolveSignerContext(signer, opts) {
140
195
  var so = signer || {};
141
196
  var keyOnly = so.cert == null && so.spki != null;
@@ -161,7 +216,13 @@ async function _finishSignerInfo(rc, md, content, eContentType, opts) {
161
216
  { type: O("messageDigest"), values: [b.octetString(md)] },
162
217
  ];
163
218
  if (opts.signingTime !== false) intrinsic.push(pairs, { type: O("signingTime"), values: [_timeValue(opts.signingTime)] });
219
+ var apOid = cms.algorithmProtectionOid(opts.algorithmProtection, _err);
220
+ if (apOid) {
221
+ intrinsic.push(pairs, _algorithmProtectionPair(apOid,
222
+ rc.scheme.digestAlgId, rc.scheme.sigAlgId, 1));
223
+ }
164
224
  pairs = intrinsic.concat(pairs, _resolveAttrPairs(opts.additionalSignedAttributes, "a signed attribute value"));
225
+ _assertAlgorithmProtectionPairs(pairs, rc.scheme.digestAlgId, rc.scheme.sigAlgId, 1);
165
226
  toSign = _buildSignedAttrs(pairs);
166
227
  }
167
228
  var signedBytes = toSign.setOf ? toSign.setOf : toSign;
@@ -285,6 +346,7 @@ function _signDispatch(content, signers, opts) {
285
346
  async function _signStream(stream, signers, opts) {
286
347
  opts = guard.identifier.optionsObject(opts, _err, "cms/bad-input", "pki.cms.sign options");
287
348
  guard.identifier.assertKnownKeys(opts, KNOWN_SIGN_OPTS, _err, "cms/bad-input", "unknown opts field ");
349
+ _assertProtectionPlaceable(opts);
288
350
  if (opts.detached !== true) {
289
351
  throw _err("cms/bad-input", "a streaming (async-iterable) content requires opts.detached: true; an attached " +
290
352
  "SignedData embeds the content as a definite-length OCTET STRING, which cannot be produced without buffering it");
@@ -324,6 +386,7 @@ async function _signStream(stream, signers, opts) {
324
386
  function _sign(content, signers, opts) {
325
387
  opts = guard.identifier.optionsObject(opts, _err, "cms/bad-input", "pki.cms.sign options");
326
388
  guard.identifier.assertKnownKeys(opts, KNOWN_SIGN_OPTS, _err, "cms/bad-input", "unknown opts field ");
389
+ _assertProtectionPlaceable(opts);
327
390
  var contentBuf = _toBuf(content, "content");
328
391
  var list = Array.isArray(signers) ? _b.reqDenseArray(signers, "the signer list") : [signers];
329
392
  if (!list.length) throw _err("cms/bad-input", "pki.cms.sign requires at least one signer");
@@ -460,9 +523,15 @@ function _buildCountersignature(targetSigOctets, countersigner, opts) {
460
523
  return _digest(scheme.digest, targetSigOctets).then(function (md) {
461
524
  var pairs = [{ type: O("messageDigest"), values: [b.octetString(md)] }];
462
525
  if (opts.signingTime !== false) pairs.push({ type: O("signingTime"), values: [_timeValue(opts.signingTime)] });
526
+ var csApOid = cms.algorithmProtectionOid(opts.algorithmProtection, _err);
527
+ if (csApOid) {
528
+ intrinsic.push(pairs, _algorithmProtectionPair(csApOid, scheme.digestAlgId, scheme.sigAlgId, 1));
529
+ }
463
530
  var extra = _resolveAttrPairs(opts.additionalSignedAttributes, "a countersignature signed attribute value");
464
531
  extra.forEach(function (p) { if (p.type === O("contentType")) throw _err("cms/bad-input", "a countersignature must not carry a content-type attribute (RFC 5652 sec. 11.4)"); });
465
- return _buildSignedAttrs(pairs.concat(extra));
532
+ var all = intrinsic.concat(pairs, extra);
533
+ _assertAlgorithmProtectionPairs(all, scheme.digestAlgId, scheme.sigAlgId, 1);
534
+ return _buildSignedAttrs(all);
466
535
  });
467
536
  }).then(function (attrs) {
468
537
  var preimage = attrs ? attrs.setOf : targetSigOctets;
@@ -554,6 +623,7 @@ function countersign(cmsInput, signers, opts) {
554
623
  function _countersign(cmsInput, signers, opts) {
555
624
  opts = guard.identifier.optionsObject(opts, _err, "cms/bad-input", "pki.cms.countersign options");
556
625
  guard.identifier.assertKnownKeys(opts, KNOWN_COUNTERSIGN_OPTS, _err, "cms/bad-input", "unknown opts field ");
626
+ _assertProtectionPlaceable(opts);
557
627
  var list = Array.isArray(signers) ? signers : [signers];
558
628
  if (!list.length) throw _err("cms/bad-input", "pki.cms.countersign requires at least one countersigner");
559
629
  if (opts.signingTime != null && opts.signingTime !== false) guard.time.assertEncodable(opts.signingTime, _err, "cms/bad-input", "signingTime");
@@ -628,8 +698,257 @@ function _countersign(cmsInput, signers, opts) {
628
698
  });
629
699
  }
630
700
 
701
+ /** @internal One Attribute appended to a SignerInfo's `[1] unsignedAttrs`, with every attribute
702
+ * already there kept byte for byte and the SET OF re-sorted. A NEW attribute member rather than a
703
+ * value merged into an existing one of the same type: ETSI EN 319 122-1 clause 5.3 reads "The
704
+ * signature-time-stamp attribute shall contain exactly one component of AttributeValue type", while
705
+ * RFC 5126 clause 6.1.1 has "Several instances of this attribute may occur with an electronic
706
+ * signature, from different TSAs", so n timestamps are n attribute instances each carrying a
707
+ * one-element SET. That is the opposite of the countersignature above, where RFC 5652 clause 11.4
708
+ * puts n signatures in one attribute's values, which is why the two do not share this helper.
709
+ *
710
+ * `build.set` sorts with the same comparison the parser's `derSetOrder` check applies, so the
711
+ * rebuilt SET OF cannot be in an order the reader refuses. The `0x31` to `0xA1` re-tag is sound
712
+ * because both identifiers are a single octet, leaving the length encoding untouched. */
713
+ function _appendUnsignedAttr(siNode, attrDer) {
714
+ var kids = siNode.children;
715
+ var last = kids[kids.length - 1];
716
+ var hasUa = last.tagClass === "context" && last.tagNumber === 1;
717
+ var base = intrinsic.map((hasUa ? intrinsic.arraySlice(kids, 0, kids.length - 1) : kids), function (k) { return k.bytes; });
718
+ var existing = hasUa ? intrinsic.map(last.children, function (a) { return a.bytes; }) : [];
719
+ var setOf = b.set(intrinsic.concat(existing, [attrDer]));
720
+ var wire = intrinsic.bufferFrom(setOf); wire[0] = 0xA1;
721
+ intrinsic.push(base, wire);
722
+ return b.sequence(base);
723
+ }
724
+
725
+ /** @internal The SignerInfo node a verb is targeting, with the index checked against what the message
726
+ * carries rather than against a caller's assertion. */
727
+ function _timestampTarget(der, signerIndex, who) {
728
+ var parsed = cms.parse(der);
729
+ if (!intrinsic.isArray(parsed.signerInfos)) throw _err("cms/bad-input", who + " input is not a CMS SignedData");
730
+ var idx = signerIndex == null ? 0 : signerIndex;
731
+ if (typeof idx !== "number" || !intrinsic.isInteger(idx) || idx < 0 || idx >= parsed.signerInfos.length) {
732
+ throw _err("cms/bad-input", who + " signerIndex out of range: " + guard.text.showValue(signerIndex) +
733
+ " (the message carries " + parsed.signerInfos.length + " signer" + (parsed.signerInfos.length === 1 ? "" : "s") + ")");
734
+ }
735
+ var root = asn1.decode(der);
736
+ var sd = root.children[1].children[0];
737
+ var siSet = sd.children[sd.children.length - 1];
738
+ return { parsed: parsed, root: root, sd: sd, siSet: siSet, idx: idx, siNode: siSet.children[idx] };
739
+ }
740
+
741
+ var KNOWN_IMPRINT_OPTS = intrinsic.assign(intrinsic.create(null), { signerIndex: 1, digestAlgorithm: 1 });
742
+
743
+ /**
744
+ * @primitive pki.cms.timestampImprint
745
+ * @signature pki.cms.timestampImprint(input, opts?) -> Promise<{ imprint, signerIndex }>
746
+ * @since 0.8.52
747
+ * @status stable
748
+ * @spec ETSI EN 319 122-1 clause 5.3, RFC 5126 clause 6.1.1, RFC 3161 clause 2.4.1
749
+ * @related pki.cms.attachTimestamp, pki.tsp.request, pki.tsp.verify, pki.cms.verify
750
+ *
751
+ * The message imprint a time-stamping authority is asked to sign over, for the CAdES
752
+ * signature-time-stamp attribute. EN 319 122-1 clause 5.3 fixes what it covers: "the hash value of
753
+ * the signature field (without the ASN.1 tag and length) within SignerInfo for which the
754
+ * signature-time-stamp attribute is created". So this is a digest of the contents octets of
755
+ * `SignerInfo.signature`, with the tag and length excluded, which is the same octet rule RFC 5652
756
+ * clause 11.4 states for a countersignature.
757
+ *
758
+ * `input` is the SignedData as a DER `Buffer` or a PEM `CMS` string, the same input
759
+ * `pki.cms.countersign` takes and for the same reason: the imprint covers exact octets of the
760
+ * message as it stands, so this reads the wire bytes rather than a representation of them. The
761
+ * result is `{ imprint, signerIndex }`: `imprint` is `{ hashAlgorithm, hashedMessage }`, the
762
+ * argument `pki.tsp.request` and `pki.tsp.sign` take, so a third-party authority can be driven
763
+ * without this package signing anything, and `signerIndex` is the signer it was taken for, which is
764
+ * what `pki.cms.attachTimestamp` is given when the token comes back.
765
+ *
766
+ * @opts signerIndex which signer to take the imprint for (default 0).
767
+ * @opts digestAlgorithm the digest to take (default `"sha256"`). MD5 is refused: EN 319 122-1
768
+ * clause 6.2.1 reads "In addition, MD5 algorithm shall not be used as digest
769
+ * algorithm".
770
+ * @example
771
+ * var pair = await pki.key.generate("Ed25519");
772
+ * var key = await pki.key.export(pair.privateKey);
773
+ * var cert = await pki.x509.sign({ subject: "Signer", subjectPublicKey: await pki.key.export(pair.publicKey),
774
+ * notBefore: new Date("2026-01-01T00:00:00Z"), notAfter: new Date("2036-01-01T00:00:00Z") }, { key: key });
775
+ * var signedDer = await pki.cms.sign(Buffer.from("hello"), { cert: cert, key: key });
776
+ * var taken = await pki.cms.timestampImprint(signedDer);
777
+ * var req = pki.tsp.request(taken.imprint, { certReq: true });
778
+ * taken.imprint.hashAlgorithm; // "sha256"
779
+ */
780
+ function timestampImprint(input, opts) {
781
+ return guard.bytes.fixedCall(CmsError, "cms/bad-input", [
782
+ [input, "the CMS message"], [opts, "pki.cms.timestampImprint options"],
783
+ ], _timestampImprint);
784
+ }
785
+
786
+ function _timestampImprint(input, opts) {
787
+ opts = guard.identifier.optionsObject(opts, _err, "cms/bad-input", "pki.cms.timestampImprint options");
788
+ guard.identifier.assertKnownKeys(opts, KNOWN_IMPRINT_OPTS, _err, "cms/bad-input", "unknown opts field ");
789
+ var name = opts.digestAlgorithm == null ? "sha256" : opts.digestAlgorithm;
790
+ /** @internal MD5 is answered before the build's own digest table, which does not carry it either:
791
+ * asked for by name, it gets the clause that forbids it rather than the generic "this build does
792
+ * not have that digest", which is a different thing to tell an operator. */
793
+ if (name === "md5") throw _err("cms/bad-input", "MD5 shall not be used as a digest algorithm (ETSI EN 319 122-1 clause 6.2.1)");
794
+ /** @internal Admitted against the digests a timestamp VERIFIER reads an imprint under, not the
795
+ * build's general digest table: a digest outside that set produces an imprint whose token every
796
+ * verifier here refuses, so taking one would hand an operator a request for an unusable token. */
797
+ if (typeof name !== "string" || !intrinsic.hasOwn(constants.NAMES.TIMESTAMP_IMPRINT_DIGESTS, name)) {
798
+ throw _err("cms/bad-input", "digestAlgorithm must name a digest a signature timestamp is read " +
799
+ "under (sha256, sha384 or sha512), got " + guard.text.showValue(opts.digestAlgorithm));
800
+ }
801
+ /** @internal A weak digest is refused outright here, with no opt-in beside it. `attachTimestamp`
802
+ * has one because a token that already exists may be archived under a digest that was current
803
+ * when it was made; a token this imprint would be sent for does not exist yet, so the only thing
804
+ * the option could buy is a request for a token this verb's own sibling then refuses. */
805
+ if (intrinsic.hasOwn(constants.NAMES.WEAK_DIGESTS, name)) {
806
+ throw _err("cms/bad-input", "the imprint digest " + name + " is one a signature timestamp is " +
807
+ "refused for, so a token taken over it could not be attached or verified");
808
+ }
809
+ var der = pkix.coerceToDer(input, { pemLabel: null, PemError: frameworkError.PemError, ErrorClass: CmsError, prefix: "cms" });
810
+ var t = _timestampTarget(der, opts.signerIndex, "pki.cms.timestampImprint");
811
+ /** @internal `imprint` is nested rather than spread across the result, so the object this returns
812
+ * is the one `pki.tsp.request` and `pki.tsp.sign` take: their message-imprint door admits
813
+ * `hashAlgorithm` and `hashedMessage` and refuses any other field, which a flat result carrying
814
+ * the signer index would trip. The index is what `pki.cms.attachTimestamp` is then given, so it
815
+ * is reported beside the imprint instead of inside it. */
816
+ return guard.verdict.of({
817
+ imprint: guard.verdict.of({
818
+ hashAlgorithm: name,
819
+ hashedMessage: guard.crypto.digest(name, _signatureOctets(t.siNode)),
820
+ }),
821
+ signerIndex: t.idx,
822
+ });
823
+ }
824
+
825
+ var KNOWN_ATTACH_OPTS = intrinsic.assign(intrinsic.create(null), { signerIndex: 1, pem: 1, allowWeakDigests: 1 });
826
+
827
+ /**
828
+ * @primitive pki.cms.attachTimestamp
829
+ * @signature pki.cms.attachTimestamp(input, token, opts?) -> Promise<Buffer>
830
+ * @since 0.8.52
831
+ * @status stable
832
+ * @spec ETSI EN 319 122-1 clause 5.3, RFC 5126 clause 6.1.1, RFC 3161
833
+ * @related pki.cms.timestampImprint, pki.cms.verify, pki.tsp.sign, pki.cms.countersign
834
+ *
835
+ * Attach an RFC 3161 `TimeStampToken` to a signature as the CAdES signature-time-stamp unsigned
836
+ * attribute `{ 1 2 840 113549 1 9 16 2 14 }`, taking a `SignedData` to the EN 319 122-1 B-T level.
837
+ * `input` is that SignedData as a DER `Buffer` or a PEM `CMS` string and `token` the token a
838
+ * time-stamping authority returned for the imprint `pki.cms.timestampImprint` produced, as DER or
839
+ * PEM. Both are read as wire bytes rather than as a parsed representation, because this verb
840
+ * rewrites the message's own octets.
841
+ *
842
+ * It SPLICES rather than re-signs. Re-signing produces a different signature value, so a token taken
843
+ * over the first one would no longer match it, which is measured and not reasoned: with ECDSA the
844
+ * second signature differs every time. What is preserved byte for byte is therefore everything the
845
+ * four signature inputs cover: the encapsulated content and its type, and per signer the `version`,
846
+ * `sid`, `digestAlgorithm`, `[0] signedAttrs`, `signatureAlgorithm` and `signature` TLVs, plus every
847
+ * embedded certificate, every revocation entry, and every attribute already in `unsignedAttrs`. What
848
+ * is re-encoded is the targeted signer's `[1] unsignedAttrs` SET OF and the five enclosing lengths,
849
+ * none of which appears in any signature input.
850
+ *
851
+ * Several instances may be attached, one per authority, which is what RFC 5126 clause 6.1.1 permits
852
+ * and EN 319 122-1 clause 5.3 shapes: each is its own attribute carrying exactly one value.
853
+ *
854
+ * `signerIndex` names a signer of the INPUT. `signerInfos` is a SET OF, whose members are emitted in
855
+ * DER order, so giving one member an attribute changes its encoding and can change its position:
856
+ * identify a signer of the OUTPUT by its signature value or its certificate, not by the index it
857
+ * held on the way in.
858
+ *
859
+ * The imprint is checked before anything is written, so this verb cannot produce a message its own
860
+ * verifier would reject: the token's imprint must be the hash of the targeted signer's signature
861
+ * value, and its digest must be one the verifier admits. Nothing else about the token is judged
862
+ * here; `pki.cms.verify` does that.
863
+ *
864
+ * @opts signerIndex which signer to attach to (default 0).
865
+ * @opts pem return a PEM `CMS` block rather than DER.
866
+ * @opts allowWeakDigests attach a token whose imprint is a weak digest, which both this verb and
867
+ * `pki.cms.verify` refuse by default. This is the archived-token path, and the
868
+ * same option is needed again at verification.
869
+ * @example
870
+ * var pair = await pki.key.generate("Ed25519");
871
+ * var key = await pki.key.export(pair.privateKey);
872
+ * var spki = await pki.key.export(pair.publicKey);
873
+ * var nb = new Date("2026-01-01T00:00:00Z"), na = new Date("2036-01-01T00:00:00Z");
874
+ * var cert = await pki.x509.sign({ subject: "Signer", subjectPublicKey: spki, notBefore: nb, notAfter: na }, { key: key });
875
+ * // RFC 3161 sec. 2.3: a TSA certificate's extendedKeyUsage MUST be critical and name timeStamping alone
876
+ * var tsaCert = await pki.x509.sign({ subject: "Example TSA", subjectPublicKey: spki, notBefore: nb, notAfter: na,
877
+ * extensions: { keyUsage: ["digitalSignature"], extendedKeyUsage: ["timeStamping"], extendedKeyUsageCritical: true } },
878
+ * { key: key });
879
+ * var signedDer = await pki.cms.sign(Buffer.from("hello"), { cert: cert, key: key });
880
+ * var taken = await pki.cms.timestampImprint(signedDer);
881
+ * var token = await pki.tsp.sign(taken.imprint, { cert: tsaCert, key: key },
882
+ * { policy: "1.3.6.1.4.1.1", serialNumber: 1 });
883
+ * var bT = await pki.cms.attachTimestamp(signedDer, token, { signerIndex: taken.signerIndex });
884
+ * (await pki.cms.verify(bT, { certs: [cert] })).signers[0].signatureTimeStamps[0].valid; // true
885
+ */
886
+ function attachTimestamp(input, token, opts) {
887
+ return guard.async.deferred(function () {
888
+ return guard.bytes.fixedCall(CmsError, "cms/bad-input", [
889
+ [input, "the CMS message"], [token, "the time-stamp token"], [opts, "pki.cms.attachTimestamp options"],
890
+ ], _attachTimestamp);
891
+ });
892
+ }
893
+
894
+ function _attachTimestamp(input, token, opts) {
895
+ opts = guard.identifier.optionsObject(opts, _err, "cms/bad-input", "pki.cms.attachTimestamp options");
896
+ guard.identifier.assertKnownKeys(opts, KNOWN_ATTACH_OPTS, _err, "cms/bad-input", "unknown opts field ");
897
+ var der = pkix.coerceToDer(input, { pemLabel: null, PemError: frameworkError.PemError, ErrorClass: CmsError, prefix: "cms" });
898
+ var tokenDer = pkix.coerceToDer(token, { pemLabel: null, PemError: frameworkError.PemError, ErrorClass: CmsError, prefix: "cms" });
899
+ var t = _timestampTarget(der, opts.signerIndex, "pki.cms.attachTimestamp");
900
+
901
+ /** @internal The imprint is checked HERE, before a byte is written, against the signature this
902
+ * attribute will hang on. A verb that wrote first would produce a message `pki.cms.verify` refuses
903
+ * on the row it just created, and the caller would have no way to tell a mis-addressed token from
904
+ * a corrupt one. The token's own structure, its authority's certificate and its chain are not
905
+ * judged here: those are the verifier's, and judging them twice in two places is two answers. */
906
+ var tst = tsp.parseToken(tokenDer);
907
+ var want = tst.tstInfo.messageImprint;
908
+ var name = want.hashAlgorithm && want.hashAlgorithm.name;
909
+ if (!name || !intrinsic.hasOwn(constants.NAMES.TIMESTAMP_IMPRINT_DIGESTS, name)) {
910
+ throw _err("cms/bad-input", "the token's message imprint names a digest a signature timestamp " +
911
+ "is not read under: " + guard.text.showValue(name || (want.hashAlgorithm && want.hashAlgorithm.oid)));
912
+ }
913
+ /** @internal The identifier is held to its own encoding as well as to its name: a digest
914
+ * AlgorithmIdentifier carries absent or DER NULL parameters (RFC 5754 clause 2), and the ANY
915
+ * field is carried through the parse unvalidated, so one naming sha256 beside arbitrary bytes
916
+ * would otherwise be hashed as a well-formed imprint. */
917
+ if (!guard.der.paramsAbsentOrNull(want.hashAlgorithm.parameters)) {
918
+ throw _err("cms/bad-input", "the token's message imprint algorithm identifier carries " +
919
+ "parameters other than DER NULL, which a digest identifier does not (RFC 5754 clause 2)");
920
+ }
921
+ /** @internal The same digest posture the verifier holds this attribute to, read from the one
922
+ * membership list: a token whose imprint is a weak digest is refused here too, under the option
923
+ * that admits it there, so the verb does not write an attribute whose row `pki.cms.verify` then
924
+ * refuses by default. The imprint carries the whole binding between the token and the signature,
925
+ * and a collision in it substitutes one signature under a genuine token. */
926
+ if (opts.allowWeakDigests !== true && intrinsic.hasOwn(constants.NAMES.WEAK_DIGESTS, name)) {
927
+ throw _err("cms/weak-timestamp-imprint", "the token's message imprint is a " + name + " digest, " +
928
+ "which a signature timestamp is refused for by default; pass allowWeakDigests: true to attach " +
929
+ "an archived token under it");
930
+ }
931
+ var have = guard.crypto.digest(name, _signatureOctets(t.siNode));
932
+ if (!guard.crypto.constantTimeEqual(have, want.hashedMessage)) {
933
+ throw _err("cms/timestamp-imprint-mismatch", "the token's message imprint is not the hash of this " +
934
+ "signer's signature value, so attaching it would produce a signature timestamp that does not " +
935
+ "verify (ETSI EN 319 122-1 clause 5.3)");
936
+ }
937
+
938
+ var attr = b.sequence([b.oid(O("timeStampToken")), b.set([tokenDer])]);
939
+ var newSiSet = b.set(intrinsic.map(t.siSet.children, function (siNode, i) {
940
+ return i === t.idx ? _appendUnsignedAttr(siNode, attr) : siNode.bytes;
941
+ }));
942
+ var sdKids = t.sd.children;
943
+ var newSdFields = intrinsic.map(intrinsic.arraySlice(sdKids, 0, sdKids.length - 1), function (k) { return k.bytes; });
944
+ intrinsic.push(newSdFields, newSiSet);
945
+ var out = b.sequence([t.root.children[0].bytes, b.explicit(0, b.sequence(newSdFields))]);
946
+ return opts.pem ? pkix.pemEncode(out, "CMS", frameworkError.PemError) : out;
947
+ }
948
+
631
949
  module.exports = {
632
950
  sign: sign, countersign: countersign, certsOnly: certsOnly,
951
+ timestampImprint: timestampImprint, attachTimestamp: attachTimestamp,
633
952
  // @internal
634
953
  KNOWN_SIGNER_CERT_KEYS: KNOWN_SIGNER_CERT_KEYS,
635
954
  KNOWN_SIGNER_KEY_ONLY_KEYS: KNOWN_SIGNER_KEY_ONLY_KEYS,