@blamejs/pki 0.8.12 → 0.8.15
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/CHANGELOG.md +47 -0
- package/README.md +2 -1
- package/index.js +6 -0
- package/lib/acme.js +13 -5
- package/lib/attrcert-sign.js +3 -3
- package/lib/cmc-build.js +9 -9
- package/lib/cmc-verify.js +5 -5
- package/lib/cmp-build.js +3 -4
- package/lib/cmp-session.js +6 -6
- package/lib/cms-verify.js +4 -4
- package/lib/crl-sign.js +1 -1
- package/lib/crmf-sign.js +1 -1
- package/lib/ct.js +2 -2
- package/lib/est.js +12 -13
- package/lib/framework-error.js +3 -0
- package/lib/guard-header.js +15 -1
- package/lib/guard-identifier.js +34 -0
- package/lib/hpke.js +7 -2
- package/lib/http-transport.js +5 -6
- package/lib/identity-match.js +4 -3
- package/lib/ocsp.js +5 -3
- package/lib/oid.js +1 -1
- package/lib/path-validate.js +155 -16
- package/lib/pki-build.js +1 -1
- package/lib/revocation-fetch.js +1 -1
- package/lib/scep.js +21 -9
- package/lib/schema-all.js +10 -1
- package/lib/schema-engine.js +7 -2
- package/lib/schema-pkix.js +40 -0
- package/lib/schema-trustanchor.js +469 -0
- package/lib/schema-x509.js +66 -33
- package/lib/smime.js +5 -1
- package/lib/trust.js +502 -11
- package/lib/trustanchor-build.js +278 -0
- package/lib/validator-tpm.js +1 -1
- package/lib/webauthn-mds.js +1 -1
- package/lib/webauthn.js +9 -10
- package/lib/webcrypto.js +3 -3
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright (c) blamejs contributors
|
|
3
|
+
"use strict";
|
|
4
|
+
/**
|
|
5
|
+
* @module pki.trustanchor
|
|
6
|
+
* @nav Trust
|
|
7
|
+
* @title Trust anchor lists
|
|
8
|
+
* @order 178
|
|
9
|
+
* @slug trustanchor-build
|
|
10
|
+
*
|
|
11
|
+
* @intro
|
|
12
|
+
* Write the RFC 5914 `TrustAnchorList` a root program publishes: each anchor
|
|
13
|
+
* as a certificate, as a bare `TBSCertificate`, or as a `TrustAnchorInfo`
|
|
14
|
+
* carrying the name it is known by and the constraints a relying party
|
|
15
|
+
* applies to paths beneath it. Every anchor is held to the same rules
|
|
16
|
+
* `pki.schema.trustanchor.parse` holds one to, and the result round-trips
|
|
17
|
+
* through that parser before it is returned.
|
|
18
|
+
*
|
|
19
|
+
* @card
|
|
20
|
+
* Build RFC 5914 trust anchor lists: the anchor carries its own policies,
|
|
21
|
+
* name constraints and path length.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
var asn1 = require("./asn1-der");
|
|
25
|
+
var schema = require("./schema-engine");
|
|
26
|
+
var pkix = require("./schema-pkix");
|
|
27
|
+
var trustanchor = require("./schema-trustanchor");
|
|
28
|
+
var x509 = require("./schema-x509");
|
|
29
|
+
var pkiBuild = require("./pki-build");
|
|
30
|
+
var oid = require("./oid");
|
|
31
|
+
var frameworkError = require("./framework-error");
|
|
32
|
+
var intrinsic = require("./guard-intrinsic");
|
|
33
|
+
var guard = require("./guard-all");
|
|
34
|
+
|
|
35
|
+
var TrustAnchorError = frameworkError.TrustAnchorError;
|
|
36
|
+
var b = asn1.build;
|
|
37
|
+
|
|
38
|
+
function _err(code, message, cause) { return new TrustAnchorError(code, message, cause); }
|
|
39
|
+
function O(n) { return oid.byName(n); }
|
|
40
|
+
|
|
41
|
+
var NS = pkix.makeNS("trustanchor", TrustAnchorError, oid);
|
|
42
|
+
var NAME_SCHEMA = pkix.name(NS);
|
|
43
|
+
var SPKI_SCHEMA = pkix.spki(NS);
|
|
44
|
+
var _b = pkiBuild.makeBuilder({ ErrorClass: TrustAnchorError, prefix: "trustanchor", O: O, NS: NS,
|
|
45
|
+
NAME_SCHEMA: NAME_SCHEMA, SPKI_SCHEMA: SPKI_SCHEMA, EXT_DECODERS: {} });
|
|
46
|
+
|
|
47
|
+
var CERT_EXT_DECODERS = pkix.certExtensionDecoders(NS).byOid;
|
|
48
|
+
var OID_NAME_CONSTRAINTS = oid.byName("nameConstraints");
|
|
49
|
+
|
|
50
|
+
var _ANCHOR_KEYS = intrinsic.assign(intrinsic.create(null), { certificate: 1, tbsCert: 1, taInfo: 1 });
|
|
51
|
+
var _INFO_KEYS = intrinsic.assign(intrinsic.create(null), {
|
|
52
|
+
pubKey: 1, keyId: 1, taTitle: 1, certPath: 1, exts: 1, taTitleLangTag: 1 });
|
|
53
|
+
var _CERT_PATH_KEYS = intrinsic.assign(intrinsic.create(null), {
|
|
54
|
+
taName: 1, certificate: 1, policySet: 1, policyFlags: 1, nameConstr: 1, pathLenConstraint: 1 });
|
|
55
|
+
var _FLAG_KEYS = intrinsic.assign(intrinsic.create(null), {
|
|
56
|
+
inhibitPolicyMapping: 1, requireExplicitPolicy: 1, inhibitAnyPolicy: 1 });
|
|
57
|
+
var _BUILD_KEYS = intrinsic.assign(intrinsic.create(null), { anchors: 1, pem: 1 });
|
|
58
|
+
|
|
59
|
+
/** @internal The shape check comes first, so every nested record reports a typed refusal naming
|
|
60
|
+
* the field instead of a native TypeError from the first property read below it. */
|
|
61
|
+
function _known(obj, allowed, what) {
|
|
62
|
+
guard.identifier.assertPlainRecord(obj, _err, "trustanchor/bad-input", what);
|
|
63
|
+
guard.identifier.assertKnownKeys(obj, allowed, _err, "trustanchor/bad-input", "unknown " + what + " field ");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function _policySetDer(list) {
|
|
67
|
+
if (!intrinsic.isArray(list) || list.length === 0) {
|
|
68
|
+
throw _err("trustanchor/bad-input", "certPath.policySet must be a non-empty array of policy identifiers");
|
|
69
|
+
}
|
|
70
|
+
return b.sequence(intrinsic.map(list, function (p) {
|
|
71
|
+
if (typeof p !== "string" || !oid.isDottedDecimal(p)) {
|
|
72
|
+
throw _err("trustanchor/bad-input", "certPath.policySet entries must be dotted-decimal policy identifiers");
|
|
73
|
+
}
|
|
74
|
+
/** @internal RFC 5914 sec. 2 forbids the qualifiers, so there is no place to put one and a
|
|
75
|
+
* caller cannot supply one: the element is the identifier alone. */
|
|
76
|
+
return b.sequence([b.oid(p)]);
|
|
77
|
+
}));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
var FLAG_BITS = trustanchor.policyFlagBits;
|
|
81
|
+
function _policyFlagsDer(flags) {
|
|
82
|
+
_known(flags, _FLAG_KEYS, "certPath.policyFlags");
|
|
83
|
+
var bits = [];
|
|
84
|
+
for (var i = 0; i < FLAG_BITS.length; i++) {
|
|
85
|
+
var v = flags[FLAG_BITS[i]];
|
|
86
|
+
if (v === undefined || v === false) continue;
|
|
87
|
+
if (v !== true) throw _err("trustanchor/bad-input", "certPath.policyFlags." + FLAG_BITS[i] + " must be a boolean");
|
|
88
|
+
guard.list.append(bits, i);
|
|
89
|
+
}
|
|
90
|
+
if (bits.length === 0) return null;
|
|
91
|
+
return b.implicit(2, b.namedBitString(bits));
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function _certPathDer(spec) {
|
|
95
|
+
_known(spec, _CERT_PATH_KEYS, "certPath");
|
|
96
|
+
var nameDer = _b.encodeName(spec.taName);
|
|
97
|
+
if (_b.isEmptyName(nameDer)) {
|
|
98
|
+
throw _err("trustanchor/bad-input", "certPath.taName must be a non-empty distinguished name (RFC 5914 sec. 2)");
|
|
99
|
+
}
|
|
100
|
+
var kids = [b.raw(nameDer)];
|
|
101
|
+
/** @internal The RFC 5914 module is IMPLICIT TAGS, so a context tag REPLACES the member's own
|
|
102
|
+
* universal tag rather than wrapping it. `b.implicit` re-tags the value it is given; only the
|
|
103
|
+
* three members the module writes EXPLICIT beside get a wrapper. */
|
|
104
|
+
if (spec.certificate !== undefined) {
|
|
105
|
+
guard.list.append(kids, b.implicit(0, _b.reqDer(spec.certificate, "certPath.certificate")));
|
|
106
|
+
}
|
|
107
|
+
var hasPolicySet = spec.policySet !== undefined;
|
|
108
|
+
if (hasPolicySet) guard.list.append(kids, b.implicit(1, _policySetDer(spec.policySet)));
|
|
109
|
+
if (spec.policyFlags !== undefined) {
|
|
110
|
+
if (!spec.policyFlags || typeof spec.policyFlags !== "object") {
|
|
111
|
+
throw _err("trustanchor/bad-input", "certPath.policyFlags must be an object of boolean flags");
|
|
112
|
+
}
|
|
113
|
+
/** @internal RFC 5914 sec. 2: "This bit MUST be set to FALSE if policySet is absent." Refused
|
|
114
|
+
* here as well as at the parse, so the builder cannot emit what the parser would reject. */
|
|
115
|
+
if (spec.policyFlags.requireExplicitPolicy === true && !hasPolicySet) {
|
|
116
|
+
throw _err("trustanchor/bad-input", "certPath.policyFlags.requireExplicitPolicy requires a policySet (RFC 5914 sec. 2)");
|
|
117
|
+
}
|
|
118
|
+
var flagsDer = _policyFlagsDer(spec.policyFlags);
|
|
119
|
+
if (flagsDer !== null) guard.list.append(kids,flagsDer);
|
|
120
|
+
}
|
|
121
|
+
if (spec.nameConstr !== undefined) {
|
|
122
|
+
var ncDer = _b.reqDer(spec.nameConstr, "certPath.nameConstr");
|
|
123
|
+
try { CERT_EXT_DECODERS[OID_NAME_CONSTRAINTS](ncDer); }
|
|
124
|
+
catch (e) { throw _err("trustanchor/bad-input", "certPath.nameConstr is not a well-formed NameConstraints (RFC 5280 sec. 4.2.1.10)", e); }
|
|
125
|
+
guard.list.append(kids, b.implicit(3, ncDer));
|
|
126
|
+
}
|
|
127
|
+
if (spec.pathLenConstraint !== undefined) {
|
|
128
|
+
var n = spec.pathLenConstraint;
|
|
129
|
+
if (!intrinsic.isInteger(n) || n < 0) {
|
|
130
|
+
throw _err("trustanchor/bad-input", "certPath.pathLenConstraint must be a non-negative integer (INTEGER (0..MAX), RFC 5914 sec. 2)");
|
|
131
|
+
}
|
|
132
|
+
guard.list.append(kids,b.implicit(4, b.integer(intrinsic.BigInt(n))));
|
|
133
|
+
}
|
|
134
|
+
return b.sequence(kids);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function _taInfoDer(spec) {
|
|
138
|
+
_known(spec, _INFO_KEYS, "taInfo");
|
|
139
|
+
/** @internal The version is the DEFAULT v1 and DER omits it, so it is not a field a caller sets
|
|
140
|
+
* and there is exactly one encoding of a v1 anchor. */
|
|
141
|
+
var spki = _b.reqDer(spec.pubKey, "taInfo.pubKey");
|
|
142
|
+
_b.assertValidSpki(spki, "taInfo.pubKey");
|
|
143
|
+
var keyId = guard.bytes.snapshotSource(spec.keyId, TrustAnchorError, "trustanchor/bad-input", "taInfo.keyId");
|
|
144
|
+
if (keyId.length === 0) throw _err("trustanchor/bad-input", "taInfo.keyId must not be empty");
|
|
145
|
+
var kids = [b.raw(spki), b.octetString(keyId)];
|
|
146
|
+
if (spec.taTitle !== undefined) {
|
|
147
|
+
/** @internal Counted the way the reader counts, in characters rather than UTF-16 code units,
|
|
148
|
+
* so the writer admits exactly the titles the reader does. */
|
|
149
|
+
if (typeof spec.taTitle !== "string") {
|
|
150
|
+
throw _err("trustanchor/bad-input", "taInfo.taTitle must be a string");
|
|
151
|
+
}
|
|
152
|
+
var titleLen = trustanchor.titleChars(spec.taTitle);
|
|
153
|
+
if (titleLen < 1 || titleLen > 64) {
|
|
154
|
+
throw _err("trustanchor/bad-input", "taInfo.taTitle must be 1 to 64 characters (SIZE (1..64), RFC 5914 sec. 2), got " + titleLen);
|
|
155
|
+
}
|
|
156
|
+
guard.list.append(kids,b.utf8(spec.taTitle));
|
|
157
|
+
}
|
|
158
|
+
if (spec.certPath !== undefined) guard.list.append(kids,_certPathDer(spec.certPath));
|
|
159
|
+
if (spec.exts !== undefined) {
|
|
160
|
+
if (!intrinsic.isArray(spec.exts) || spec.exts.length === 0) {
|
|
161
|
+
throw _err("trustanchor/bad-input", "taInfo.exts must be a non-empty array of pre-encoded Extension DER");
|
|
162
|
+
}
|
|
163
|
+
var extDers = intrinsic.map(spec.exts, function (e, i) {
|
|
164
|
+
var der = _b.reqDer(e, "taInfo.exts[" + i + "]");
|
|
165
|
+
var extnId;
|
|
166
|
+
try { extnId = asn1.read.oid(asn1.decode(der).children[0]); }
|
|
167
|
+
catch (err) { throw _err("trustanchor/bad-input", "taInfo.exts[" + i + "] is not a well-formed Extension", err); }
|
|
168
|
+
/** @internal RFC 5914 sec. 3 names four extension types that MUST NOT appear here. The parser
|
|
169
|
+
* ignores one that does, as the RFC says to; the builder refuses to write one, so this
|
|
170
|
+
* toolkit never produces an anchor carrying a constraint nothing will read. */
|
|
171
|
+
if (trustanchor.excludedExtensionOids[extnId] === true) {
|
|
172
|
+
throw _err("trustanchor/bad-input", "taInfo.exts must not carry " + (oid.name(extnId) || extnId) +
|
|
173
|
+
", which RFC 5914 sec. 3 excludes and a reader ignores; state it in certPath instead");
|
|
174
|
+
}
|
|
175
|
+
return b.raw(der);
|
|
176
|
+
});
|
|
177
|
+
guard.list.append(kids,b.explicit(1, b.sequence(extDers)));
|
|
178
|
+
}
|
|
179
|
+
if (spec.taTitleLangTag !== undefined) {
|
|
180
|
+
/** @internal The type carries no SIZE constraint, so the reader accepts an empty language tag
|
|
181
|
+
* and this refuses to write one: an empty tag names no language, and the field exists to say
|
|
182
|
+
* which language the title is in. The docstring states it, since the module does not. */
|
|
183
|
+
if (typeof spec.taTitleLangTag !== "string" || spec.taTitleLangTag.length === 0) {
|
|
184
|
+
throw _err("trustanchor/bad-input", "taInfo.taTitleLangTag must be a non-empty string; an empty one names no language");
|
|
185
|
+
}
|
|
186
|
+
/** @internal `[2] UTF8String` with no EXPLICIT beside it in the module, so the context tag
|
|
187
|
+
* replaces the UTF8String tag rather than wrapping it. */
|
|
188
|
+
guard.list.append(kids, b.implicit(2, b.utf8(spec.taTitleLangTag)));
|
|
189
|
+
}
|
|
190
|
+
return b.sequence(kids);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function _anchorDer(spec, i) {
|
|
194
|
+
if (!spec || typeof spec !== "object" || intrinsic.isArray(spec)) {
|
|
195
|
+
throw _err("trustanchor/bad-input", "anchors[" + i + "] must be an object naming exactly one of certificate, tbsCert or taInfo");
|
|
196
|
+
}
|
|
197
|
+
_known(spec, _ANCHOR_KEYS, "anchors[" + i + "]");
|
|
198
|
+
var named = [];
|
|
199
|
+
intrinsic.forEach(["certificate", "tbsCert", "taInfo"], function (k) {
|
|
200
|
+
if (spec[k] !== undefined) guard.list.append(named, k);
|
|
201
|
+
});
|
|
202
|
+
if (named.length !== 1) {
|
|
203
|
+
throw _err("trustanchor/bad-input", "anchors[" + i + "] must name exactly one of certificate, tbsCert or taInfo, got " +
|
|
204
|
+
(named.length === 0 ? "none" : intrinsic.join(named, " and ")));
|
|
205
|
+
}
|
|
206
|
+
if (named[0] === "certificate") return b.raw(_b.reqDer(spec.certificate, "anchors[" + i + "].certificate"));
|
|
207
|
+
if (named[0] === "tbsCert") return b.explicit(1, b.raw(_b.reqDer(spec.tbsCert, "anchors[" + i + "].tbsCert")));
|
|
208
|
+
return b.explicit(2, _taInfoDer(spec.taInfo));
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* @primitive pki.trustanchor.build
|
|
213
|
+
* @signature pki.trustanchor.build(spec, opts?) -> Buffer | string
|
|
214
|
+
* @since 0.8.13
|
|
215
|
+
* @status stable
|
|
216
|
+
* @spec RFC 5914
|
|
217
|
+
* @related pki.schema.trustanchor.parse, pki.trust.parseTrustAnchorList
|
|
218
|
+
*
|
|
219
|
+
* Build an RFC 5914 `TrustAnchorList`, the structure a root program publishes. `spec.anchors` is a
|
|
220
|
+
* non-empty array, each entry naming exactly one of `certificate` (pre-encoded Certificate DER),
|
|
221
|
+
* `tbsCert` (pre-encoded TBSCertificate DER) or `taInfo`.
|
|
222
|
+
*
|
|
223
|
+
* A `taInfo` entry is `{ pubKey, keyId, taTitle?, certPath?, exts?, taTitleLangTag? }`, where
|
|
224
|
+
* `pubKey` is SubjectPublicKeyInfo DER and `keyId` the key identifier bytes. `certPath` carries the
|
|
225
|
+
* constraints: `taName` (a distinguished name string or an array of relative names), `certificate`,
|
|
226
|
+
* `policySet` (an array of policy identifiers), `policyFlags`
|
|
227
|
+
* (`{ inhibitPolicyMapping, requireExplicitPolicy, inhibitAnyPolicy }`), `nameConstr` (pre-encoded
|
|
228
|
+
* NameConstraints DER) and `pathLenConstraint`.
|
|
229
|
+
*
|
|
230
|
+
* Every rule the parser enforces is enforced here, so this toolkit does not emit an anchor it would
|
|
231
|
+
* refuse to read: an empty `taName`, a `requireExplicitPolicy` with no `policySet`, a negative
|
|
232
|
+
* `pathLenConstraint`, and an `exts` entry naming one of the four extension types RFC 5914
|
|
233
|
+
* section 3 excludes. The result round-trips through `pki.schema.trustanchor.parse` before it is
|
|
234
|
+
* returned.
|
|
235
|
+
*
|
|
236
|
+
* The version is not a field a caller sets: v1 is the ASN.1 DEFAULT and DER omits it, so every v1
|
|
237
|
+
* anchor has one encoding.
|
|
238
|
+
*
|
|
239
|
+
* Two refusals are stricter than the module, on the principle that what this
|
|
240
|
+
* writes is what an operator publishes: `taTitleLangTag` may not be the empty string, which
|
|
241
|
+
* names no language, and `exts` may not carry one of the four extension types RFC 5914 section 3
|
|
242
|
+
* excludes, which a reader is told to ignore and which `certPath` states properly.
|
|
243
|
+
*
|
|
244
|
+
* @opts
|
|
245
|
+
* - `pem` (boolean) -- return a PEM `TRUST ANCHOR LIST` string instead of DER.
|
|
246
|
+
* @example
|
|
247
|
+
* var pair = await pki.key.generate("Ed25519");
|
|
248
|
+
* var der = pki.trustanchor.build({ anchors: [{ taInfo: {
|
|
249
|
+
* pubKey: await pki.key.export(pair.publicKey),
|
|
250
|
+
* keyId: Buffer.alloc(20, 1),
|
|
251
|
+
* taTitle: "Example Root CA",
|
|
252
|
+
* certPath: { taName: "CN=Example Root", pathLenConstraint: 2 } } }] });
|
|
253
|
+
* pki.schema.trustanchor.parse(der).anchors[0].taInfo.certPath.pathLenConstraint; // -> 2
|
|
254
|
+
*/
|
|
255
|
+
function build(spec, opts) {
|
|
256
|
+
if (!spec || typeof spec !== "object" || intrinsic.isArray(spec)) {
|
|
257
|
+
throw _err("trustanchor/bad-input", "build expects a { anchors } specification object");
|
|
258
|
+
}
|
|
259
|
+
_known(spec, _BUILD_KEYS, "build");
|
|
260
|
+
var checked = guard.identifier.optionsObject(opts, _err, "trustanchor/bad-input", "pki.trustanchor.build options");
|
|
261
|
+
guard.identifier.assertKnownKeys(checked, intrinsic.assign(intrinsic.create(null), { pem: 1 }),
|
|
262
|
+
_err, "trustanchor/bad-input", "unknown pki.trustanchor.build option ");
|
|
263
|
+
if (!intrinsic.isArray(spec.anchors) || spec.anchors.length === 0) {
|
|
264
|
+
throw _err("trustanchor/bad-input", "build: anchors must be a non-empty array (TrustAnchorList is SIZE (1..MAX))");
|
|
265
|
+
}
|
|
266
|
+
var der = b.sequence(intrinsic.map(spec.anchors, function (a, i) { return _anchorDer(a, i); }));
|
|
267
|
+
/** @internal The reader reads the writer's output back before it is returned, so a shape the two
|
|
268
|
+
* disagree about fails the build instead of reaching an operator. */
|
|
269
|
+
try { trustanchor.parse(der); }
|
|
270
|
+
catch (e) { throw _err("trustanchor/bad-input", "the built trust anchor list does not parse: " + guard.text.describeThrown(e), e); }
|
|
271
|
+
if (checked.pem === true) return trustanchor.pemEncode(der);
|
|
272
|
+
return der;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
void schema;
|
|
276
|
+
void x509;
|
|
277
|
+
|
|
278
|
+
module.exports = { build: build };
|
package/lib/validator-tpm.js
CHANGED
|
@@ -122,7 +122,7 @@ function normalizeObjectAttributePolicy(policy, E, code) {
|
|
|
122
122
|
var explicit = policy.objectAttributes;
|
|
123
123
|
if (explicit !== undefined) {
|
|
124
124
|
if (!explicit || typeof explicit !== "object" || Array.isArray(explicit)) throw new E(code, "opts.tpmPolicy.objectAttributes must be an object");
|
|
125
|
-
|
|
125
|
+
guard.identifier.optionNames(explicit).forEach(function (n) {
|
|
126
126
|
if (TPMA_OBJECT_BITS[n] === undefined) throw new E(code, "opts.tpmPolicy.objectAttributes has an unknown attribute " + JSON.stringify(n));
|
|
127
127
|
if (typeof explicit[n] !== "boolean") throw new E(code, "opts.tpmPolicy.objectAttributes." + n + " must be a boolean");
|
|
128
128
|
want[n] = explicit[n];
|
package/lib/webauthn-mds.js
CHANGED
|
@@ -440,7 +440,7 @@ function metadataAnchors(entry, opts) {
|
|
|
440
440
|
opts = opts || {};
|
|
441
441
|
if (typeof opts !== "object" || Array.isArray(opts)) throw _err("webauthn/bad-input", "metadataAnchors opts must be an object");
|
|
442
442
|
guard.identifier.assertKnownKeys(opts, _ANCHOR_OPTS, _err, "webauthn/bad-input", "metadataAnchors opts has an unknown key ");
|
|
443
|
-
opts =
|
|
443
|
+
opts = guard.identifier.ownOptions(opts);
|
|
444
444
|
if (opts.time !== undefined) guard.time.assertValid(opts.time, _err, "webauthn/bad-input", "opts.time");
|
|
445
445
|
if (opts.metadata !== undefined) {
|
|
446
446
|
if (!isVerifiedResult(opts.metadata)) {
|
package/lib/webauthn.js
CHANGED
|
@@ -906,7 +906,7 @@ function verify(attestationObject, clientDataHash, opts) {
|
|
|
906
906
|
try {
|
|
907
907
|
if (!_isPlainObject(opts)) throw _err("webauthn/bad-input", "opts must be an object");
|
|
908
908
|
guard.identifier.assertKnownKeys(opts, _VERIFY_OPTS, _err, "webauthn/bad-input", "opts has an unknown key ");
|
|
909
|
-
opts =
|
|
909
|
+
opts = guard.identifier.ownOptions(opts);
|
|
910
910
|
if (opts.time !== undefined) guard.time.assertValid(opts.time, _err, "webauthn/bad-input", "opts.time");
|
|
911
911
|
_FORMAT_SCOPED_BOOLEAN_OPTS.forEach(function (k) {
|
|
912
912
|
if (opts[k] !== undefined && typeof opts[k] !== "boolean") throw _err("webauthn/bad-input", "opts." + k + " must be a boolean");
|
|
@@ -957,10 +957,9 @@ function verify(attestationObject, clientDataHash, opts) {
|
|
|
957
957
|
var bindingChecked, vopts;
|
|
958
958
|
try {
|
|
959
959
|
bindingChecked = _applyBindings(att.authData, att.authData.credentialPublicKey, opts);
|
|
960
|
-
vopts =
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
});
|
|
960
|
+
vopts = guard.identifier.ownOptions(opts);
|
|
961
|
+
vopts.rootCertificates = _snapshotRoots(opts.rootCertificates);
|
|
962
|
+
vopts.safetyNetRoots = _snapshotRoots(opts.safetyNetRoots);
|
|
964
963
|
} catch (e) { return Promise.reject(e); }
|
|
965
964
|
return Promise.resolve().then(function () { return verifier(att, clientDataHash, vopts); })
|
|
966
965
|
.then(function (res) {
|
|
@@ -1478,8 +1477,7 @@ var _ASSERT_OPTS = Object.assign(Object.create(null), {
|
|
|
1478
1477
|
function _snapshotAssertion(input) {
|
|
1479
1478
|
if (!_isPlainObject(input)) throw _err("webauthn/bad-input", "pki.webauthn.verifyAssertion takes an options object");
|
|
1480
1479
|
guard.identifier.assertKnownKeys(input, _ASSERT_OPTS, _err, "webauthn/bad-input", "verifyAssertion input has an unknown key ");
|
|
1481
|
-
var out =
|
|
1482
|
-
for (k in input) { if (_hasOwn(input, k)) out[k] = input[k]; }
|
|
1480
|
+
var out = guard.identifier.ownOptions(input);
|
|
1483
1481
|
["authenticatorData", "clientDataJSON", "clientDataHash", "signature", "expectedChallenge"].forEach(function (f) {
|
|
1484
1482
|
if (_isBufferSource(out[f])) out[f] = guard.bytes.snapshotSource(out[f], WebauthnError, "webauthn/bad-input", f);
|
|
1485
1483
|
});
|
|
@@ -1487,9 +1485,10 @@ function _snapshotAssertion(input) {
|
|
|
1487
1485
|
out.credentialPublicKey = guard.bytes.snapshotSource(out.credentialPublicKey, WebauthnError,
|
|
1488
1486
|
"webauthn/bad-input", "credentialPublicKey");
|
|
1489
1487
|
} else if (_isPlainObject(out.credentialPublicKey)) {
|
|
1490
|
-
var key = intrinsic.create(null)
|
|
1491
|
-
|
|
1492
|
-
|
|
1488
|
+
var key = intrinsic.create(null);
|
|
1489
|
+
var coseNames = guard.identifier.optionNames(out.credentialPublicKey);
|
|
1490
|
+
for (var ci = 0; ci < coseNames.length; ci++) {
|
|
1491
|
+
var kk = coseNames[ci];
|
|
1493
1492
|
var v;
|
|
1494
1493
|
try { v = out.credentialPublicKey[kk]; }
|
|
1495
1494
|
catch (e) { throw _err("webauthn/bad-cose-key", "credentialPublicKey." + kk + " could not be read", e); }
|
package/lib/webcrypto.js
CHANGED
|
@@ -116,8 +116,7 @@ function _normalizeAlg(algorithm, who) {
|
|
|
116
116
|
if (!alg || typeof alg.name !== "string") {
|
|
117
117
|
throw new WebCryptoError("webcrypto/syntax", (who || "operation") + ": algorithm must be a string or an object with a name");
|
|
118
118
|
}
|
|
119
|
-
var out =
|
|
120
|
-
for (var k in alg) { if (_hasOwn(alg, k)) out[k] = alg[k]; }
|
|
119
|
+
var out = guard.identifier.ownOptions(alg);
|
|
121
120
|
out.name = _toUpperCase(alg.name);
|
|
122
121
|
return out;
|
|
123
122
|
}
|
|
@@ -1030,7 +1029,8 @@ function _algFromImport(name, alg, keyObject) {
|
|
|
1030
1029
|
function _curveFromKey(ko) {
|
|
1031
1030
|
try {
|
|
1032
1031
|
var jwk = ko.export({ format: "jwk" });
|
|
1033
|
-
|
|
1032
|
+
var curves = guard.identifier.optionNames(CURVE_NODE);
|
|
1033
|
+
for (var k = 0; k < curves.length; k++) { if (jwk.crv === curves[k]) return curves[k]; }
|
|
1034
1034
|
}
|
|
1035
1035
|
catch (_e) { }
|
|
1036
1036
|
return undefined;
|
package/package.json
CHANGED
package/sbom.cdx.json
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
"$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
|
|
3
3
|
"bomFormat": "CycloneDX",
|
|
4
4
|
"specVersion": "1.5",
|
|
5
|
-
"serialNumber": "urn:uuid:
|
|
5
|
+
"serialNumber": "urn:uuid:fd715296-3209-4fc3-85ee-b6af7fbfdd1c",
|
|
6
6
|
"version": 1,
|
|
7
7
|
"metadata": {
|
|
8
|
-
"timestamp": "2026-09-
|
|
8
|
+
"timestamp": "2026-09-24T03:48:38.286Z",
|
|
9
9
|
"lifecycles": [
|
|
10
10
|
{
|
|
11
11
|
"phase": "build"
|
|
@@ -19,14 +19,14 @@
|
|
|
19
19
|
}
|
|
20
20
|
],
|
|
21
21
|
"component": {
|
|
22
|
-
"bom-ref": "@blamejs/pki@0.8.
|
|
22
|
+
"bom-ref": "@blamejs/pki@0.8.15",
|
|
23
23
|
"type": "application",
|
|
24
24
|
"name": "pki",
|
|
25
|
-
"version": "0.8.
|
|
25
|
+
"version": "0.8.15",
|
|
26
26
|
"scope": "required",
|
|
27
27
|
"author": "blamejs contributors",
|
|
28
28
|
"description": "Pure-JavaScript PKI toolkit that owns its stack — X.509, ASN.1/DER, CMS, PQC-first.",
|
|
29
|
-
"purl": "pkg:npm/%40blamejs/pki@0.8.
|
|
29
|
+
"purl": "pkg:npm/%40blamejs/pki@0.8.15",
|
|
30
30
|
"properties": [],
|
|
31
31
|
"externalReferences": [
|
|
32
32
|
{
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"components": [],
|
|
55
55
|
"dependencies": [
|
|
56
56
|
{
|
|
57
|
-
"ref": "@blamejs/pki@0.8.
|
|
57
|
+
"ref": "@blamejs/pki@0.8.15",
|
|
58
58
|
"dependsOn": []
|
|
59
59
|
}
|
|
60
60
|
]
|