@blamejs/pki 0.5.7 → 0.5.9
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 +418 -386
- package/MIGRATING.md +43 -0
- package/README.md +12 -12
- package/lib/acme.js +31 -31
- package/lib/asn1-der.js +10 -10
- package/lib/attrcert-sign.js +19 -19
- package/lib/byte-reader.js +6 -6
- package/lib/byte-writer.js +5 -5
- package/lib/cbor-det.js +27 -24
- package/lib/cmc-build.js +97 -92
- package/lib/cmc-verify.js +106 -30
- package/lib/cmp-build.js +25 -25
- package/lib/cmp-session.js +70 -70
- package/lib/cmp-verify.js +71 -57
- package/lib/cms-compress.js +7 -7
- package/lib/cms-decrypt.js +90 -72
- package/lib/cms-encrypt.js +32 -32
- package/lib/cms-sign.js +74 -55
- package/lib/cms-verify.js +97 -75
- package/lib/composite-sig.js +13 -13
- package/lib/constants.js +4 -4
- package/lib/crl-sign.js +22 -22
- package/lib/crl-verify.js +7 -6
- package/lib/crmf-sign.js +14 -14
- package/lib/csr-sign.js +8 -8
- package/lib/ct.js +37 -37
- package/lib/edwards-point.js +7 -7
- package/lib/est.js +98 -55
- package/lib/framework-error.js +5 -5
- package/lib/guard-all.js +5 -3
- package/lib/guard-async.js +4 -4
- package/lib/guard-bytes.js +79 -79
- package/lib/guard-compress.js +17 -17
- package/lib/guard-crypto.js +1 -1
- package/lib/guard-der.js +152 -0
- package/lib/guard-encoding.js +15 -15
- package/lib/guard-header.js +3 -3
- package/lib/guard-identifier.js +16 -16
- package/lib/guard-json.js +15 -15
- package/lib/guard-limits.js +7 -7
- package/lib/guard-name.js +81 -16
- package/lib/guard-parsed.js +80 -80
- package/lib/guard-range.js +19 -19
- package/lib/guard-secret.js +11 -10
- package/lib/guard-text.js +6 -6
- package/lib/guard-time.js +10 -10
- package/lib/hpke.js +18 -17
- package/lib/http-digest.js +35 -35
- package/lib/http-retry-after.js +13 -13
- package/lib/http-transport.js +20 -19
- package/lib/inspect.js +53 -53
- package/lib/ip-utils.js +2 -2
- package/lib/jose.js +13 -13
- package/lib/key.js +16 -16
- package/lib/lint.js +51 -51
- package/lib/merkle.js +51 -36
- package/lib/mime.js +18 -18
- package/lib/ocsp-verify.js +10 -10
- package/lib/ocsp.js +13 -13
- package/lib/oid.js +29 -29
- package/lib/path-validate.js +114 -113
- package/lib/pbes2.js +16 -16
- package/lib/pkcs12-build.js +53 -53
- package/lib/pki-build.js +48 -20
- package/lib/rc2.js +1 -1
- package/lib/rfc3339.js +5 -5
- package/lib/schema-all.js +31 -31
- package/lib/schema-attrcert.js +12 -12
- package/lib/schema-c509.js +149 -197
- package/lib/schema-cmc.js +58 -58
- package/lib/schema-cmp.js +43 -43
- package/lib/schema-cms.js +45 -45
- package/lib/schema-crl.js +7 -7
- package/lib/schema-crmf.js +28 -28
- package/lib/schema-csr.js +12 -12
- package/lib/schema-csrattrs.js +16 -16
- package/lib/schema-engine.js +18 -18
- package/lib/schema-ocsp.js +15 -15
- package/lib/schema-pkcs12.js +20 -20
- package/lib/schema-pkcs8.js +2 -2
- package/lib/schema-pkix.js +131 -126
- package/lib/schema-smime.js +19 -19
- package/lib/schema-tsp.js +12 -12
- package/lib/schema-x509.js +3 -3
- package/lib/shbs.js +18 -18
- package/lib/sign-scheme.js +13 -13
- package/lib/sigstore.js +10 -11
- package/lib/sleep.js +1 -1
- package/lib/smime.js +308 -96
- package/lib/tls-cert-compress.js +18 -18
- package/lib/trust.js +27 -27
- package/lib/tsp-sign.js +17 -17
- package/lib/validator-all.js +1 -1
- package/lib/validator-attcert.js +1 -1
- package/lib/validator-cose.js +43 -44
- package/lib/validator-keydesc.js +3 -3
- package/lib/validator-sig.js +13 -13
- package/lib/validator-tls.js +11 -11
- package/lib/validator-tpm.js +20 -19
- package/lib/webauthn-mds.js +66 -66
- package/lib/webauthn.js +33 -33
- package/lib/webcrypto.js +15 -15
- package/lib/x509-sign.js +13 -13
- package/package.json +3 -2
- package/sbom.cdx.json +6 -6
package/lib/attrcert-sign.js
CHANGED
|
@@ -10,14 +10,14 @@
|
|
|
10
10
|
* `AttributeCertificateInfo` binding a Holder to a set of privilege attributes (role, clearance,
|
|
11
11
|
* group, ...) over a validity window, signs it with an Attribute Authority's private key, and emits an
|
|
12
12
|
* `AttributeCertificate` that `pki.schema.attrcert.parse` accepts and re-validates byte for byte.
|
|
13
|
-
* Unlike a public-key certificate an attribute certificate is never self-signed
|
|
13
|
+
* Unlike a public-key certificate an attribute certificate is never self-signed: the holder has no
|
|
14
14
|
* key, so the issuing AA is always a distinct signer. Parsing lives at `pki.schema.attrcert.parse`.
|
|
15
15
|
* @spec RFC 5755
|
|
16
16
|
* @card Build and sign an RFC 5755 attribute certificate as an Attribute Authority.
|
|
17
17
|
*/
|
|
18
18
|
//
|
|
19
|
-
// RFC 5755 is DEFINITIONS IMPLICIT TAGS (App. B): a context [n] on a non-CHOICE component
|
|
20
|
-
// underlying tag (its children
|
|
19
|
+
// RFC 5755 is DEFINITIONS IMPLICIT TAGS (App. B): a context [n] on a non-CHOICE component replaces the
|
|
20
|
+
// underlying tag (its children are the component's fields: Holder [0]/[1]/[2], AttCertIssuer v2Form [0],
|
|
21
21
|
// RoleSyntax roleAuthority [0], IetfAttrSyntax policyAuthority [0], AAControls [0]/[1]), built with
|
|
22
22
|
// b.contextConstructed(n, ...); a context [n] wrapping a GeneralName CHOICE (roleName [1], Target [0]/[1])
|
|
23
23
|
// is EXPLICIT, built with b.explicit(n, ...). The signature algorithm resolves from the AA public key
|
|
@@ -75,7 +75,7 @@ var EXT_META = {
|
|
|
75
75
|
// hatch so an escape-hatch extension cannot ship with a criticality the profile forbids.
|
|
76
76
|
var REQUIRED_CRITICALITY = {};
|
|
77
77
|
Object.keys(EXT_META).forEach(function (k) { REQUIRED_CRITICALITY[O(EXT_META[k].name)] = EXT_META[k].critical; });
|
|
78
|
-
// ClassList ::= BIT STRING { unmarked(0) .. topSecret(5) } (RFC 5755 sec. 4.4.4)
|
|
78
|
+
// ClassList ::= BIT STRING { unmarked(0) .. topSecret(5) } (RFC 5755 sec. 4.4.4), the encode inverse of
|
|
79
79
|
// the schema-attrcert.js _CLASSLIST_NAMES decode array; DEFAULT {unclassified} (bit 1) is omitted.
|
|
80
80
|
var CLASSLIST_BIT = { unmarked: 0, unclassified: 1, restricted: 2, confidential: 3, secret: 4, topSecret: 5 };
|
|
81
81
|
|
|
@@ -91,7 +91,7 @@ function _parseCert(cert, what) {
|
|
|
91
91
|
catch (e) { if (e instanceof AttrCertError) throw e; throw _err("attrcert/bad-input", what + " is not a well-formed certificate", e); }
|
|
92
92
|
}, _err, "attrcert/bad-input", what);
|
|
93
93
|
}
|
|
94
|
-
// The raw content octets of an OBJECT IDENTIFIER (past its own tag+len)
|
|
94
|
+
// The raw content octets of an OBJECT IDENTIFIER (past its own tag+len): the body of a [0] IMPLICIT OID.
|
|
95
95
|
function _oidContent(name) {
|
|
96
96
|
var dotted = O(name) || name;
|
|
97
97
|
var enc;
|
|
@@ -107,7 +107,7 @@ function _gnList(spec) {
|
|
|
107
107
|
// ---- structural encoders (byte-exact inverses of the schema-attrcert.js readers) ----
|
|
108
108
|
|
|
109
109
|
// IssuerSerial ::= SEQUENCE { issuer GeneralNames, serial CertificateSerialNumber, issuerUID BIT STRING
|
|
110
|
-
// OPTIONAL }. Returns the
|
|
110
|
+
// OPTIONAL }. Returns the content (concatenated field TLVs) so a [n] IMPLICIT caller wraps it directly.
|
|
111
111
|
function _issuerSerialContent(is) {
|
|
112
112
|
if (!is || typeof is !== "object" || Buffer.isBuffer(is)) throw _err("attrcert/bad-input", "baseCertificateID must be an object { issuer, serial, issuerUID? }");
|
|
113
113
|
if (is.issuer == null) throw _err("attrcert/bad-input", "baseCertificateID.issuer (a GeneralNames) is required");
|
|
@@ -120,7 +120,7 @@ function _issuerSerialContent(is) {
|
|
|
120
120
|
}
|
|
121
121
|
// ObjectDigestInfo ::= SEQUENCE { digestedObjectType ENUMERATED, otherObjectTypeID OID OPTIONAL,
|
|
122
122
|
// digestAlgorithm AlgorithmIdentifier, objectDigest BIT STRING }. otherObjectTypes(2) is forbidden (sec.
|
|
123
|
-
// 7.3), so otherObjectTypeID is never emitted. Returns the
|
|
123
|
+
// 7.3), so otherObjectTypeID is never emitted. Returns the content for a [n] IMPLICIT caller.
|
|
124
124
|
var ODT_CODE = { publicKey: 0, publicKeyCert: 1 };
|
|
125
125
|
function _objectDigestInfoContent(odi) {
|
|
126
126
|
if (!odi || typeof odi !== "object" || Buffer.isBuffer(odi)) throw _err("attrcert/bad-input", "objectDigestInfo must be an object");
|
|
@@ -134,7 +134,7 @@ function _objectDigestInfoContent(odi) {
|
|
|
134
134
|
return Buffer.concat([b.enumerated(BigInt(code)), algTlv, b.bitString(odi.objectDigest, 0)]);
|
|
135
135
|
}
|
|
136
136
|
// Holder ::= SEQUENCE { baseCertificateID [0] IMPLICIT IssuerSerial, entityName [1] IMPLICIT GeneralNames,
|
|
137
|
-
// objectDigestInfo [2] IMPLICIT ObjectDigestInfo }
|
|
137
|
+
// objectDigestInfo [2] IMPLICIT ObjectDigestInfo }, exactly one form (the profile binds a real holder).
|
|
138
138
|
function _encodeHolder(holder) {
|
|
139
139
|
if (!holder || typeof holder !== "object" || Buffer.isBuffer(holder)) throw _err("attrcert/bad-input", "holder must be an object with exactly one form");
|
|
140
140
|
guard.identifier.assertKnownKeys(holder, KNOWN_HOLDER_KEYS, _err, "attrcert/bad-input", "unknown holder form ");
|
|
@@ -150,7 +150,7 @@ function _encodeHolder(holder) {
|
|
|
150
150
|
if (holder.fromCertificate != null) {
|
|
151
151
|
// Bind to a public-key certificate's identity: baseCertificateID = { issuer = the PKC's issuer DN as a
|
|
152
152
|
// directoryName, serial = the PKC serialNumber } (RFC 5755 sec. 4.1 / 7.3).
|
|
153
|
-
//
|
|
153
|
+
// Both halves come from the signed bytes. issuer and serial together are the identity, so deriving
|
|
154
154
|
// the issuer from tbsBytes while reading the serial off the object let the two name different
|
|
155
155
|
// certificates: a Holder with a genuine issuer DN and whatever serial the caller wrote.
|
|
156
156
|
var pkc = _parseCert(holder.fromCertificate, "holder.fromCertificate");
|
|
@@ -161,7 +161,7 @@ function _encodeHolder(holder) {
|
|
|
161
161
|
return b.sequence([b.contextConstructed(2, _objectDigestInfoContent(holder.objectDigestInfo))]);
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
-
// AttCertIssuer v2Form [0] IMPLICIT V2Form { issuerName GeneralNames }
|
|
164
|
+
// AttCertIssuer v2Form [0] IMPLICIT V2Form { issuerName GeneralNames }, where issuerName is exactly one
|
|
165
165
|
// directoryName [4] over a non-empty DN (RFC 5755 sec. 4.2.3). The [0] replaces the V2Form SEQUENCE tag.
|
|
166
166
|
function _encodeV2FormIssuer(dnSpec) {
|
|
167
167
|
var dnDer = _b.encodeName(dnSpec == null ? [] : dnSpec);
|
|
@@ -170,7 +170,7 @@ function _encodeV2FormIssuer(dnSpec) {
|
|
|
170
170
|
return b.contextConstructed(0, issuerNameGns);
|
|
171
171
|
}
|
|
172
172
|
// AttCertValidityPeriod ::= SEQUENCE { notBeforeTime GeneralizedTime, notAfterTime GeneralizedTime }
|
|
173
|
-
// (RFC 5755 sec. 4.2.6)
|
|
173
|
+
// (RFC 5755 sec. 4.2.6): always GeneralizedTime, never UTCTime; reject an inverted window.
|
|
174
174
|
function _encodeValidity(notBefore, notAfter) {
|
|
175
175
|
guard.time.assertValid(notBefore, _err, "attrcert/bad-input", "notBeforeTime");
|
|
176
176
|
guard.time.assertValid(notAfter, _err, "attrcert/bad-input", "notAfterTime");
|
|
@@ -263,7 +263,7 @@ var ATTR_VALUE_ENCODER = {
|
|
|
263
263
|
// ---- extension-value encoders (sec. 4.3 / 7.4) ----
|
|
264
264
|
|
|
265
265
|
// Target ::= CHOICE { targetName [0] EXPLICIT GeneralName, targetGroup [1] EXPLICIT GeneralName }
|
|
266
|
-
// (targetCert [2] is out of v1 scope
|
|
266
|
+
// (targetCert [2] is out of v1 scope; use a pre-encoded Extension DER for a targetCert-bearing value).
|
|
267
267
|
function _encodeTarget(t) {
|
|
268
268
|
if (!t || typeof t !== "object") throw _err("attrcert/bad-input", "each target must be { targetName } or { targetGroup }");
|
|
269
269
|
if (t.targetName != null) return b.explicit(0, _b.encodeGeneralName(t.targetName));
|
|
@@ -291,7 +291,7 @@ function _encodeAAControls(aac) {
|
|
|
291
291
|
var parts = [];
|
|
292
292
|
if (aac.pathLenConstraint != null) {
|
|
293
293
|
// The parser narrows pathLenConstraint through guard.range.uint31 (0..2^31-1), so a larger value the
|
|
294
|
-
// builder emits would fail the round trip
|
|
294
|
+
// builder emits would fail the round trip, so bound it to the same range at build time.
|
|
295
295
|
if (typeof aac.pathLenConstraint !== "number" || !Number.isInteger(aac.pathLenConstraint) || aac.pathLenConstraint < 0 || aac.pathLenConstraint > 0x7fffffff) throw _err("attrcert/bad-input", "aaControls.pathLenConstraint must be an integer in 0..2147483647 (RFC 5755 sec. 7.4)");
|
|
296
296
|
parts.push(b.integer(BigInt(aac.pathLenConstraint)));
|
|
297
297
|
}
|
|
@@ -319,7 +319,7 @@ function _extensionValue(key, val, aaSpki) {
|
|
|
319
319
|
|
|
320
320
|
// ---- attributes / extensions assembly ----
|
|
321
321
|
|
|
322
|
-
// attributes ::= SEQUENCE OF Attribute (RFC 5755 sec. 4.2.7)
|
|
322
|
+
// attributes ::= SEQUENCE OF Attribute (RFC 5755 sec. 4.2.7): non-empty, each AttributeType OID unique;
|
|
323
323
|
// or an array of pre-encoded Attribute DER (validated in shape AND value). Each Attribute value SET is
|
|
324
324
|
// DER-sorted.
|
|
325
325
|
function _buildAttributes(attrSpec) {
|
|
@@ -362,7 +362,7 @@ function _buildAttributes(attrSpec) {
|
|
|
362
362
|
return b.sequence(attrs);
|
|
363
363
|
}
|
|
364
364
|
|
|
365
|
-
// extensions ::= SEQUENCE OF Extension (RFC 5755 sec. 4.2.9)
|
|
365
|
+
// extensions ::= SEQUENCE OF Extension (RFC 5755 sec. 4.2.9): the recognized object form, or an array
|
|
366
366
|
// of pre-encoded Extension DER. At most one instance of a particular extension OID. Returns a universal
|
|
367
367
|
// SEQUENCE OF Extension, or null when none are requested.
|
|
368
368
|
function _buildExtensions(extSpec, aaSpki) {
|
|
@@ -427,21 +427,21 @@ function _buildExtensions(extSpec, aaSpki) {
|
|
|
427
427
|
* syntaxes -- role / clearance / group / chargingIdentity / accessIdentity / authenticationInfo -- or an
|
|
428
428
|
* array of pre-encoded Attribute DER), and optional `extensions` (an object of auditIdentity /
|
|
429
429
|
* targetInformation / noRevAvail / aaControls / acProxying / authorityKeyIdentifier, or an array of
|
|
430
|
-
* pre-encoded Extension DER). `issuer` is the signing AA
|
|
430
|
+
* pre-encoded Extension DER). `issuer` is the signing AA: `{ cert, key }` (the AA certificate DER/PEM
|
|
431
431
|
* and its private key) or `{ name, publicKey, key }` (an explicit issuer DN, AA SPKI DER, and key); an
|
|
432
432
|
* attribute certificate is never self-signed. The signature algorithm is resolved from the AA key (RSA
|
|
433
433
|
* PKCS#1 v1.5 or PSS, ECDSA, EdDSA, ML-DSA, SLH-DSA, or a composite arm), and the signature is verified
|
|
434
434
|
* under the AA public key before the certificate is returned. Returns DER, or a PEM `ATTRIBUTE
|
|
435
435
|
* CERTIFICATE` with `opts.pem`. Malformed input throws a typed `AttrCertError`; where the spec carries
|
|
436
|
-
* raw DER
|
|
436
|
+
* raw DER (a holder or issuer `Name` Buffer, a pre-encoded `Extension`) a malformed leaf inside
|
|
437
437
|
* those bytes throws `Asn1Error`. The AA certificate's own
|
|
438
|
-
* profile (RFC 5755 sec. 4.5) and validity are a verification-layer concern
|
|
438
|
+
* profile (RFC 5755 sec. 4.5) and validity are a verification-layer concern, so validate the AA
|
|
439
439
|
* certificate with `pki.path.validate` before trusting the attribute certificate. Parsing is
|
|
440
440
|
* `pki.schema.attrcert.parse`.
|
|
441
441
|
*
|
|
442
442
|
* @opts
|
|
443
443
|
* - `pem` (boolean) -- return a PEM `ATTRIBUTE CERTIFICATE` string instead of DER.
|
|
444
|
-
* - `pss` (boolean) -- sign an RSA key with RSASSA-PSS
|
|
444
|
+
* - `pss` (boolean) -- sign an RSA key with RSASSA-PSS instead of PKCS#1 v1.5.
|
|
445
445
|
* - `digestAlgorithm` (string) -- override the message digest where the algorithm permits a choice.
|
|
446
446
|
* @example
|
|
447
447
|
* var pair = await pki.key.generate("Ed25519");
|
package/lib/byte-reader.js
CHANGED
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
* primitive under the toolkit's non-ASN.1 length-prefixed wire formats (TLS-vector
|
|
8
8
|
* SCTs in pki.ct, the packed big-endian TPM2B_* / authenticatorData structures in
|
|
9
9
|
* pki.webauthn). Every read is length-checked against a hard [pos, end) window
|
|
10
|
-
*
|
|
11
|
-
* sub-reader's `end`, never the parent buffer
|
|
12
|
-
* not a per-call discipline. It carries the
|
|
13
|
-
* format keeps its own `domain/reason` fault code, exactly as the guard family does.
|
|
10
|
+
* before a byte is taken, so a lying inner length can overrun only the current
|
|
11
|
+
* sub-reader's `end`, never the parent buffer. Bounds-before-slice is structural
|
|
12
|
+
* here, not a per-call discipline. It carries the caller's typed ErrorClass so every
|
|
13
|
+
* wire format keeps its own `domain/reason` fault code, exactly as the guard family does.
|
|
14
14
|
*
|
|
15
15
|
* This is an engine primitive, not a format: a new fixed-width or length-prefixed
|
|
16
16
|
* wire field is a method here (with its own bounds check), never a hand-rolled
|
|
@@ -47,9 +47,9 @@ ByteReader.prototype.fixed = function (n, code) {
|
|
|
47
47
|
this._need(n, code);
|
|
48
48
|
var s = this.buf.subarray(this.pos, this.pos + n); this.pos += n; return s;
|
|
49
49
|
};
|
|
50
|
-
// opaque<min..max>
|
|
50
|
+
// opaque<min..max> is a length-prefixed vector (lenWidth-byte big-endian prefix:
|
|
51
51
|
// 2 or 3). The length prefix itself is a plain read (a truncation there is the
|
|
52
|
-
// default code); only a
|
|
52
|
+
// default code); only a lying length whose body overruns the bound carries `code`.
|
|
53
53
|
ByteReader.prototype.vector = function (lenWidth, min, max, code) {
|
|
54
54
|
var len = lenWidth === 3 ? this.u24() : this.u16();
|
|
55
55
|
if (len < min) throw new this.E(code, "vector length " + len + " below minimum " + min);
|
package/lib/byte-writer.js
CHANGED
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
* lib/byte-reader.js, the shared producer under the toolkit's non-ASN.1 length-prefixed
|
|
8
8
|
* wire formats (the TLS-vector SCT list pki.ct emits; any future TLS-presentation
|
|
9
9
|
* producer). Every fixed-width integer is range-checked against its field width and
|
|
10
|
-
* every length-prefixed vector against its declared bound
|
|
10
|
+
* every length-prefixed vector against its declared bound before a byte is committed,
|
|
11
11
|
* so an out-of-range value or an over-long body faults through the caller's typed
|
|
12
|
-
* ErrorClass
|
|
13
|
-
* ErrorClass exactly as ByteReader
|
|
12
|
+
* ErrorClass instead of silently truncating mod 2^(8*width). It carries the caller's
|
|
13
|
+
* ErrorClass exactly as ByteReader and the guard family do, so every wire format keeps
|
|
14
14
|
* its own `domain/reason` fault code.
|
|
15
15
|
*
|
|
16
16
|
* This is an engine primitive, not a format: a new fixed-width or length-prefixed wire
|
|
@@ -30,7 +30,7 @@ function ByteWriter(E, defaultCode) {
|
|
|
30
30
|
ByteWriter.prototype._push = function (buf) { this.parts.push(buf); this.len += buf.length; };
|
|
31
31
|
// A non-negative integer that fills exactly `width` big-endian octets; the width MUST be 1..4 (a wider
|
|
32
32
|
// or malformed width would break the max computation via 32-bit shift wrap-around and mis-size the
|
|
33
|
-
// field), and a value outside [0, 2^(8*width)-1] (or a non-integer) faults
|
|
33
|
+
// field), and a value outside [0, 2^(8*width)-1] (or a non-integer) faults instead of silently wrapping.
|
|
34
34
|
ByteWriter.prototype._uint = function (v, width, code) {
|
|
35
35
|
if (!Number.isInteger(width) || width < 1 || width > 4) throw new this.E(code || this.defaultCode, "an integer width must be 1..4, got " + width);
|
|
36
36
|
var max = width === 4 ? 0xffffffff : (1 << (8 * width)) - 1;
|
|
@@ -59,7 +59,7 @@ ByteWriter.prototype.bytes = function (buf, code) {
|
|
|
59
59
|
this._push(buf); return this;
|
|
60
60
|
};
|
|
61
61
|
// opaque<min..max> -- a `lenWidth`-byte big-endian length prefix (1..4) then `body`.
|
|
62
|
-
// The body length is bounded [min, max]
|
|
62
|
+
// The body length is bounded [min, max] before the prefix is written, so an over-long
|
|
63
63
|
// body cannot emit a prefix that disagrees with what follows.
|
|
64
64
|
ByteWriter.prototype.vector = function (lenWidth, min, max, body, code) {
|
|
65
65
|
if (!Buffer.isBuffer(body)) throw new this.E(code || this.defaultCode, "vector() body must be a Buffer");
|
package/lib/cbor-det.js
CHANGED
|
@@ -15,12 +15,13 @@
|
|
|
15
15
|
* codec that owns its stack, rejects every non-canonical shape before it
|
|
16
16
|
* returns a value, and bounds size and depth before it walks a byte.
|
|
17
17
|
*
|
|
18
|
-
*
|
|
19
|
-
* item, a non-minimal ("preferred") integer / length /
|
|
20
|
-
* non-shortest or non-canonical-NaN float, out-of-order or
|
|
21
|
-
* keys, ill-formed UTF-8,
|
|
22
|
-
* here, because deterministic CBOR is a
|
|
23
|
-
* that violates it produced invalid
|
|
18
|
+
* A lenient CBOR reader tolerates a good deal this one refuses: an
|
|
19
|
+
* indefinite-length item, a non-minimal ("preferred") integer / length /
|
|
20
|
+
* tag argument, a non-shortest or non-canonical-NaN float, out-of-order or
|
|
21
|
+
* duplicate map keys, ill-formed UTF-8, trailing bytes. Every one of them
|
|
22
|
+
* is a permanent `CborError` here, because deterministic CBOR is a
|
|
23
|
+
* canonical encoding and a producer that violates it produced invalid
|
|
24
|
+
* bytes. There is no lenient mode.
|
|
24
25
|
*
|
|
25
26
|
* `decode` returns a navigable node tree with zero-copy `bytes` / `content`
|
|
26
27
|
* views (the raw ranges an external verifier hashes); the `read.*` leaf
|
|
@@ -47,12 +48,12 @@ var _fbuf = new ArrayBuffer(8);
|
|
|
47
48
|
var _fdv = new DataView(_fbuf);
|
|
48
49
|
|
|
49
50
|
// Strict UTF-8 validator (fatal); a lone continuation / truncated sequence
|
|
50
|
-
// throws instead of substituting U+FFFD
|
|
51
|
-
// refuses
|
|
51
|
+
// throws instead of substituting U+FFFD, which is the fail-open class the
|
|
52
|
+
// toolkit refuses. This mirrors asn1-der's strict text decode.
|
|
52
53
|
var _utf8 = new TextDecoder("utf-8", { fatal: true });
|
|
53
54
|
|
|
54
55
|
// The ECMAScript Date-valid window is +/- 8,640,000,000,000,000 ms; in seconds
|
|
55
|
-
// that is +/- 8.64e12. read.time bounds an epoch value to this window
|
|
56
|
+
// that is +/- 8.64e12. read.time bounds an epoch value to this window before
|
|
56
57
|
// narrowing the BigInt to a Number, so the narrowing is lossless (well under
|
|
57
58
|
// 2^53) and the millisecond result stays a safe integer.
|
|
58
59
|
var _MAX_EPOCH_SECONDS = 8640000000000n;
|
|
@@ -135,8 +136,9 @@ function _decodeItem(buf, start, limit, depth, maxD, rules, state) {
|
|
|
135
136
|
else if (nBytes === 4) argument = BigInt(buf.readUInt32BE(p));
|
|
136
137
|
else argument = buf.readBigUInt64BE(p);
|
|
137
138
|
p += nBytes;
|
|
138
|
-
// Preferred (shortest) argument
|
|
139
|
-
// "argument" is raw float bits governed by the shortest-float
|
|
139
|
+
// Preferred (shortest) argument, required for every major type but 7. In
|
|
140
|
+
// type 7 the "argument" is raw float bits, governed by the shortest-float
|
|
141
|
+
// rule.
|
|
140
142
|
if (mt !== 7) {
|
|
141
143
|
var minForWidth = nBytes === 1 ? 24n : nBytes === 2 ? 256n : nBytes === 4 ? 65536n : 4294967296n;
|
|
142
144
|
if (argument < minForWidth) {
|
|
@@ -249,7 +251,7 @@ function _decodeItem(buf, start, limit, depth, maxD, rules, state) {
|
|
|
249
251
|
* maxBytes: number, // default: C.LIMITS.CBOR_MAX_BYTES (16 MiB)
|
|
250
252
|
* maxDepth: number, // default: C.LIMITS.CBOR_MAX_DEPTH (64)
|
|
251
253
|
* maxItems: number, // default: C.LIMITS.CBOR_MAX_ITEMS (1,000,000 total decoded items)
|
|
252
|
-
* allowTrailing: boolean, // default: false
|
|
254
|
+
* allowTrailing: boolean, // default: false; true returns the first item and permits bytes after it (CBOR Sequence)
|
|
253
255
|
* profile: string, // default: "deterministic" (the only value v1 accepts)
|
|
254
256
|
*
|
|
255
257
|
* @example
|
|
@@ -429,18 +431,19 @@ function readMap(node) {
|
|
|
429
431
|
* @status stable
|
|
430
432
|
* @spec RFC 8949 sec. 3.1 (major type 5)
|
|
431
433
|
*
|
|
432
|
-
* The value node of the map entry whose key equals `key
|
|
433
|
-
*
|
|
434
|
-
*
|
|
435
|
-
*
|
|
436
|
-
* only matches a text-string key node, an integer key only an integer key
|
|
437
|
-
* At most one entry can match
|
|
438
|
-
* the single keyed-lookup home over a decoded map
|
|
439
|
-
* `read.map
|
|
440
|
-
* pair-index a non-map's children (single nodes, whose pair index
|
|
441
|
-
* undefined). Throws `cbor/unexpected-major` when `node` is not a map
|
|
442
|
-
* lookup on a non-map
|
|
443
|
-
* a TypeError for a key that is neither a text string
|
|
434
|
+
* The value node of the map entry whose key equals `key`, or null when the map
|
|
435
|
+
* has no such entry. A key is a text string (matched against text-string keys)
|
|
436
|
+
* or an integer (a safe-integer number or a BigInt, matched against integer
|
|
437
|
+
* keys, as COSE labels are). Key matching never coerces across types: a text
|
|
438
|
+
* key only matches a text-string key node, an integer key only an integer key
|
|
439
|
+
* node. At most one entry can match, because decode already enforced key
|
|
440
|
+
* uniqueness. This is the single keyed-lookup home over a decoded map. A
|
|
441
|
+
* consumer composes it, or `read.map`; hand-walking `children` as pairs is what
|
|
442
|
+
* lets a lookup pair-index a non-map's children (single nodes, whose pair index
|
|
443
|
+
* reads undefined). Throws `cbor/unexpected-major` when `node` is not a map,
|
|
444
|
+
* treating a lookup on a non-map as malformed input and never as an
|
|
445
|
+
* absent-entry verdict, and a TypeError for a key that is neither a text string
|
|
446
|
+
* nor an integer.
|
|
444
447
|
*
|
|
445
448
|
* @example
|
|
446
449
|
* // a WebAuthn-shaped map: {3: -7, "fmt": "packed"} in deterministic key order
|