kxco-post-quantum 1.7.2 → 1.7.5
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 +38 -0
- package/CRYPTO-INVENTORY.md +227 -0
- package/HNDL.md +84 -0
- package/PQCMM.md +164 -0
- package/README.md +149 -87
- package/package.json +42 -16
- package/src/_native.node.js +110 -9
- package/src/_native.stub.js +4 -0
- package/src/backend.d.ts +25 -0
- package/src/backend.js +47 -12
- package/src/index.js +1 -1
- package/src/ml-dsa-87.js +8 -3
- package/src/ml-dsa.js +12 -6
- package/src/slh-dsa.js +8 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,43 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.7.5
|
|
4
|
+
|
|
5
|
+
Documentation. No source change.
|
|
6
|
+
|
|
7
|
+
**The npm page leads with what the package proves.** The first screen now carries the standards, the NIST ACVP and interoperability
|
|
8
|
+
results, the CNSA 2.0 parameter sets, the native OpenSSL 3.5 backend and the
|
|
9
|
+
supply-chain evidence, then the migration dates set by NIST, Executive Order
|
|
10
|
+
14412, OMB M-26-15 and the UK NCSC.
|
|
11
|
+
|
|
12
|
+
A family table maps every KXCO package to the job it does, and a new For
|
|
13
|
+
institutions section sets out the operated services and how to reach us. The
|
|
14
|
+
evidence documents are unchanged and linked from the page.
|
|
15
|
+
|
|
16
|
+
## 1.7.3
|
|
17
|
+
|
|
18
|
+
One resolution fix that consumers could hit, plus the ACVTS tooling and two
|
|
19
|
+
maturity documents. No change to any algorithm, key format or wire format.
|
|
20
|
+
|
|
21
|
+
**Every export subpath now carries a `default` condition.** All twelve declared
|
|
22
|
+
only `types` and `import`, so a consumer resolving outside an import context got
|
|
23
|
+
`ERR_PACKAGE_PATH_NOT_EXPORTED` and could not load the package at all. That is a
|
|
24
|
+
packaging defect rather than a library one: nothing about the code changed, only
|
|
25
|
+
what Node is willing to resolve. It was found from the other side, in a project
|
|
26
|
+
that had to pass `--conditions=import` on every test invocation to work around
|
|
27
|
+
it, and that workaround can come out once this is published.
|
|
28
|
+
|
|
29
|
+
The addition is purely additive. A subpath that resolved before resolves to the
|
|
30
|
+
same file now.
|
|
31
|
+
|
|
32
|
+
**ACVTS tooling is committed rather than kept locally.** The selftest, the
|
|
33
|
+
validation printer and the demo certificate verifier were written against the
|
|
34
|
+
NIST demo submission and existed only on one machine, which makes them evidence
|
|
35
|
+
nobody else can re-run.
|
|
36
|
+
|
|
37
|
+
**Two PQCMM gaps closed and Level 3 re-declared**, against the PKI Consortium's
|
|
38
|
+
Post-Quantum Cryptography Maturity Model, with the self-assessment written down
|
|
39
|
+
rather than asserted.
|
|
40
|
+
|
|
3
41
|
## 1.7.2
|
|
4
42
|
|
|
5
43
|
Documentation, and one typing fix. No source change to the library and no wire
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
# Cryptographic inventory
|
|
2
|
+
|
|
3
|
+
Every use case in this package where cryptography is applied, mapped onto the
|
|
4
|
+
ten categories of the PKI Consortium PQCMM cryptographic inventory taxonomy.
|
|
5
|
+
|
|
6
|
+
The model requires that no category is omitted. A category that does not apply
|
|
7
|
+
is marked not applicable with a written reason, because "we do not do that" and
|
|
8
|
+
"we did not look" are indistinguishable from the outside unless the reason is
|
|
9
|
+
recorded. Four of the ten genuinely do not apply to a library with no sockets
|
|
10
|
+
and no persistent state, and saying so in one line each is the honest answer
|
|
11
|
+
rather than a padded one.
|
|
12
|
+
|
|
13
|
+
Scope: `kxco-post-quantum` 1.7.2. `BOUNDARY.md` is the companion document and
|
|
14
|
+
explains the difference between cryptography this package performs, depends on,
|
|
15
|
+
and merely offers to a caller. The distinction matters here: a caller can use
|
|
16
|
+
this package inside a category that the package itself does not implement.
|
|
17
|
+
|
|
18
|
+
## 1. Data in transit
|
|
19
|
+
|
|
20
|
+
**Not applicable to the library. Applicable to its delivery.**
|
|
21
|
+
|
|
22
|
+
Nothing in `src/` opens a socket. The library performs no network operation at
|
|
23
|
+
any point: no licence check, no telemetry, no key server, no call home. There
|
|
24
|
+
is no transport for it to protect.
|
|
25
|
+
|
|
26
|
+
Its own delivery is a different matter and is not quantum-safe. Fetching the
|
|
27
|
+
package is classical TLS to the npm registry or to GitHub, as was the transport
|
|
28
|
+
that delivered any git clone. That residual is stated in `BOUNDARY.md` and is
|
|
29
|
+
mitigated by an ML-DSA-65 signature over every release asset plus a second copy
|
|
30
|
+
of the public key committed to the repository, so that a verifier is not
|
|
31
|
+
trusting the same channel twice. Mitigated, not eliminated.
|
|
32
|
+
|
|
33
|
+
What the package offers a caller for this category is the ML-KEM key
|
|
34
|
+
encapsulation below, from which a caller may build a transport. Offering a
|
|
35
|
+
primitive is not the same as protecting a transport, and the two should not be
|
|
36
|
+
reported as one.
|
|
37
|
+
|
|
38
|
+
| Use | Algorithm | Quantum-safe |
|
|
39
|
+
|---|---|---|
|
|
40
|
+
| Package delivery | TLS to registry and GitHub, classical | No, mitigated by signature |
|
|
41
|
+
| Primitive offered to callers | ML-KEM-768, ML-KEM-1024 | Yes |
|
|
42
|
+
|
|
43
|
+
## 2. Data at rest
|
|
44
|
+
|
|
45
|
+
**Not applicable.** The package writes no files and keeps no state between
|
|
46
|
+
calls. There is no disk, database or object storage in its boundary to encrypt.
|
|
47
|
+
|
|
48
|
+
A caller who persists a key or a seed produced by this package is performing
|
|
49
|
+
data-at-rest protection in their own system, with their own choice of
|
|
50
|
+
algorithm, and this package neither sees nor constrains it. The one supported
|
|
51
|
+
route that removes the question is `kxco-pq-hsm`, which generates ML-DSA keys
|
|
52
|
+
on a PKCS#11 token with `CKA_EXTRACTABLE=false`, after which this package
|
|
53
|
+
handles verification only and touches no secret.
|
|
54
|
+
|
|
55
|
+
## 3. Identity, authentication and certificates
|
|
56
|
+
|
|
57
|
+
**Applicable, and quantum-safe within the package.**
|
|
58
|
+
|
|
59
|
+
No X.509. No certificate chain, no path validation, no revocation. Identity
|
|
60
|
+
here is a raw key plus a key identifier, and the package deliberately does not
|
|
61
|
+
pretend to be a PKI.
|
|
62
|
+
|
|
63
|
+
| Use | Algorithm | Quantum-safe |
|
|
64
|
+
|---|---|---|
|
|
65
|
+
| Signature and verification | ML-DSA-65, ML-DSA-87 (FIPS 204) | Yes |
|
|
66
|
+
| Hash-based alternative | SLH-DSA, ten parameter sets (FIPS 205) | Yes |
|
|
67
|
+
| Key identifier | SHA-256 over the public key, truncated to 16 hex characters (`kid.js`) | Yes, second-preimage bound |
|
|
68
|
+
| Key interchange | JWK `kty: AKP` per RFC 9964, and PKCS#8 seed export | Format, not an algorithm |
|
|
69
|
+
| JWS signing | ML-DSA over the JWS signing input (`jws.js`) | Yes |
|
|
70
|
+
| Webhook delivery signing | HMAC-SHA-256 **and** ML-DSA-65, both (`webhook.js`) | Yes, hybrid |
|
|
71
|
+
|
|
72
|
+
The `kid` is a truncated SHA-256, so it is a 64-bit identifier and not a
|
|
73
|
+
security boundary. It identifies which key to try; it does not authenticate
|
|
74
|
+
anything. Grover halves the preimage work on SHA-256 and the truncation
|
|
75
|
+
dominates that anyway, which is why nothing in the package makes a trust
|
|
76
|
+
decision on a `kid` alone.
|
|
77
|
+
|
|
78
|
+
## 4. Code, firmware and update signing
|
|
79
|
+
|
|
80
|
+
**Applicable, and quantum-safe.**
|
|
81
|
+
|
|
82
|
+
Every release asset is signed with ML-DSA-65 by this package's own signing
|
|
83
|
+
path, which means the signing of the package is performed by the thing being
|
|
84
|
+
signed. The public key is committed to the repository at
|
|
85
|
+
`release-signing-key.pub.hex` and published as a release asset, so a verifier
|
|
86
|
+
can obtain it by a path other than the one that delivered the artefact.
|
|
87
|
+
Verification is four lines and is in `README.md`.
|
|
88
|
+
|
|
89
|
+
No firmware. The package ships no binary and no native build of its own; the
|
|
90
|
+
native path calls the OpenSSL already present in the host runtime.
|
|
91
|
+
|
|
92
|
+
| Use | Algorithm | Quantum-safe |
|
|
93
|
+
|---|---|---|
|
|
94
|
+
| Release asset signing | ML-DSA-65 | Yes |
|
|
95
|
+
| Signature over the evidence bundle | ML-DSA-65, `.sig` beside each bundle | Yes |
|
|
96
|
+
|
|
97
|
+
## 5. Key wrapping and key-encryption keys
|
|
98
|
+
|
|
99
|
+
**Applicable in a limited form, and quantum-safe.**
|
|
100
|
+
|
|
101
|
+
The package wraps no keys. It has no KEK hierarchy, no envelope encryption and
|
|
102
|
+
no key store.
|
|
103
|
+
|
|
104
|
+
What it does have is deterministic derivation, which occupies the same place in
|
|
105
|
+
a design without being key wrapping. `keypairFromMaster` derives a per-purpose
|
|
106
|
+
seed from a caller-held master secret using HKDF-SHA-512 with an empty salt and
|
|
107
|
+
a caller-chosen `info` string, then generates the keypair from that seed. A
|
|
108
|
+
master secret therefore stands in the position a KEK would occupy, and its
|
|
109
|
+
protection is entirely the caller's.
|
|
110
|
+
|
|
111
|
+
| Use | Algorithm | Quantum-safe |
|
|
112
|
+
|---|---|---|
|
|
113
|
+
| Seed derivation from a master secret | HKDF-SHA-512 (`derive.js`) | Yes, symmetric |
|
|
114
|
+
| Key encapsulation offered to callers | ML-KEM-768, ML-KEM-1024 (FIPS 203) | Yes |
|
|
115
|
+
| Hybrid key establishment | `deriveSeed` combines an ML-KEM shared secret with a classical secret through the KDF | Yes, holds if either half holds |
|
|
116
|
+
|
|
117
|
+
## 6. Random number generation and entropy sources
|
|
118
|
+
|
|
119
|
+
**Applicable, and this is the entry a reader should not skim.**
|
|
120
|
+
|
|
121
|
+
**This package generates no randomness in its JavaScript backend.** There is no
|
|
122
|
+
`randomBytes`, no `getRandomValues`, no `randomFillSync` anywhere in `src/`
|
|
123
|
+
outside the native path. Every keypair is produced from a seed the caller
|
|
124
|
+
supplies, either directly through `keypairFromSeed` or derived from a
|
|
125
|
+
caller-held master through `keypairFromMaster`. Seed length is enforced against
|
|
126
|
+
the FIPS parameter set and a wrong length is a `RangeError`, not a silent pad.
|
|
127
|
+
|
|
128
|
+
The consequence is worth stating plainly: **in the JavaScript backend, the
|
|
129
|
+
quality of every private key in this system is a property of the caller's
|
|
130
|
+
entropy source, not of this package.** A caller who supplies a low-entropy seed
|
|
131
|
+
gets a low-entropy key and the library cannot detect it. This is a deliberate
|
|
132
|
+
design choice, because deterministic derivation is what makes the keys
|
|
133
|
+
reproducible and the conformance vectors pinnable, but it relocates a security
|
|
134
|
+
property rather than solving it.
|
|
135
|
+
|
|
136
|
+
The native backend is different. `crypto.generateKeyPairSync` in `_native.node.js`
|
|
137
|
+
delegates to Node and thence to the OpenSSL DRBG, so on that path entropy comes
|
|
138
|
+
from the operating system.
|
|
139
|
+
|
|
140
|
+
| Path | Entropy source | Whose responsibility |
|
|
141
|
+
|---|---|---|
|
|
142
|
+
| JavaScript backend | Caller-supplied seed | The caller |
|
|
143
|
+
| JavaScript backend, derived | HKDF-SHA-512 over a caller-supplied master | The caller |
|
|
144
|
+
| Native backend keygen | OpenSSL DRBG via `crypto.generateKeyPairSync` | The operating system |
|
|
145
|
+
|
|
146
|
+
No category of quantum attack applies to a DRBG in the way it applies to a
|
|
147
|
+
public-key primitive; the risk here is classical and it is entropy starvation.
|
|
148
|
+
|
|
149
|
+
## 7. Telemetry, logging and audit-trail integrity
|
|
150
|
+
|
|
151
|
+
**Not applicable.** The package emits no telemetry and writes no log. It keeps
|
|
152
|
+
no state between calls, so there is no audit trail of its own to protect.
|
|
153
|
+
|
|
154
|
+
Log integrity in the wider KXCO estate is `kxco-pq-audit`, a separate package:
|
|
155
|
+
SHA-256 hash-chained entries, each signed with ML-DSA-65, with periodic seals
|
|
156
|
+
anchored on Armature L1 so that a verifier who does not trust the log operator
|
|
157
|
+
still has an independent time bound. What this package contributes to that is
|
|
158
|
+
the signature primitive and nothing else.
|
|
159
|
+
|
|
160
|
+
## 8. Build, CI/CD and supply-chain signing
|
|
161
|
+
|
|
162
|
+
**Applicable, and quantum-safe for what we sign, classical for what GitHub and
|
|
163
|
+
npm sign.** This split is the honest answer and collapsing it would be an
|
|
164
|
+
overclaim.
|
|
165
|
+
|
|
166
|
+
| Use | Algorithm | Quantum-safe |
|
|
167
|
+
|---|---|---|
|
|
168
|
+
| Release assets and evidence bundle | ML-DSA-65, ours | Yes |
|
|
169
|
+
| SLSA provenance attestation | Sigstore, classical (ECDSA and the Fulcio and Rekor chain) | **No** |
|
|
170
|
+
| npm registry signature and provenance | npm's own, classical | **No** |
|
|
171
|
+
| Reproducible build | Not a signature. The published tarball rebuilds bit-for-bit from its own tag, verified in CI on every run | Not applicable |
|
|
172
|
+
| CycloneDX SBOM | Generated by `npm sbom` from the published tree; integrity carried by the ML-DSA signature over the release | Yes, via the release signature |
|
|
173
|
+
|
|
174
|
+
The reproducible build is the part of this category that does not depend on any
|
|
175
|
+
signature algorithm at all, and it is the reason the classical rows above are a
|
|
176
|
+
weaker residual than they look: a verifier who rebuilds from source is not
|
|
177
|
+
trusting Sigstore, npm or us.
|
|
178
|
+
|
|
179
|
+
## 9. Attestation and remote attestation
|
|
180
|
+
|
|
181
|
+
**Applicable in the supply-chain sense only.**
|
|
182
|
+
|
|
183
|
+
There is no hardware attestation, no TPM quote, no confidential-computing
|
|
184
|
+
report and no remote-attestation protocol in this package.
|
|
185
|
+
|
|
186
|
+
What exists is build attestation: an in-toto statement at
|
|
187
|
+
`evidence.intoto.jsonl` and an evidence manifest that pins the commit, the
|
|
188
|
+
toolchain, the backend, the dependency versions and every step with its exact
|
|
189
|
+
command, result and duration, with a SHA-256 for each file in the bundle. The
|
|
190
|
+
in-toto and SLSA layer is signed classically by Sigstore, as row 2 of category
|
|
191
|
+
8 records. The manifest and bundle are additionally signed with ML-DSA-65 by us.
|
|
192
|
+
|
|
193
|
+
## 10. Backup, archival and long-term storage
|
|
194
|
+
|
|
195
|
+
**Applicable as a stated gap, and this is the weakest category.**
|
|
196
|
+
|
|
197
|
+
Verification of old records holds: a signature made by any version of this
|
|
198
|
+
package verifies under any later version. Wire formats have not changed, and
|
|
199
|
+
the conformance evidence is regenerated against pinned vectors on every
|
|
200
|
+
dependency bump, which is the control that would catch a change breaking them.
|
|
201
|
+
|
|
202
|
+
Long-term trust does not hold and is a different question. This package has no
|
|
203
|
+
notion of key validity windows, no revocation and no trusted timestamps. It can
|
|
204
|
+
tell you a signature is arithmetically valid. It cannot tell you the key was
|
|
205
|
+
still trusted when the signature was made. Anything that has to hold for years
|
|
206
|
+
needs a time anchor outside the signature. Inside the KXCO estate that anchor
|
|
207
|
+
is `kxco-pq-audit`'s on-chain seals. Outside it, this is a gap the deployment
|
|
208
|
+
has to close, and this package should not be cited as closing it.
|
|
209
|
+
|
|
210
|
+
## Summary
|
|
211
|
+
|
|
212
|
+
| # | Category | Status |
|
|
213
|
+
|---|---|---|
|
|
214
|
+
| 1 | Data in transit | Library N/A; delivery is classical TLS, signature-mitigated |
|
|
215
|
+
| 2 | Data at rest | N/A, no persistence |
|
|
216
|
+
| 3 | Identity, authentication, certificates | Quantum-safe, no X.509 |
|
|
217
|
+
| 4 | Code, firmware, update signing | Quantum-safe |
|
|
218
|
+
| 5 | Key wrapping and KEKs | Quantum-safe, no wrapping; master secret is the caller's |
|
|
219
|
+
| 6 | RNG and entropy | **Relocated to the caller** in the JavaScript backend |
|
|
220
|
+
| 7 | Telemetry, logging, audit integrity | N/A, separate package |
|
|
221
|
+
| 8 | Build, CI/CD, supply chain | Split: ours quantum-safe, Sigstore and npm classical |
|
|
222
|
+
| 9 | Attestation | Build attestation only, classically signed at the Sigstore layer |
|
|
223
|
+
| 10 | Backup, archival, long-term | **Gap.** No timestamps, validity windows or revocation |
|
|
224
|
+
|
|
225
|
+
Three residuals carry forward into `PQCMM.md` and `HNDL.md` rather than being
|
|
226
|
+
recorded only here: classical release transport, the classical Sigstore and npm
|
|
227
|
+
signature layer, and the absence of long-term validation.
|
package/HNDL.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# HNDL exposure register
|
|
2
|
+
|
|
3
|
+
Harvest-now-decrypt-later exposure for `kxco-post-quantum` 1.7.2, as required
|
|
4
|
+
at Level 3 of the PKI Consortium PQCMM: which data flows handled by the product
|
|
5
|
+
carry a long-lived confidentiality requirement, and which algorithm protects
|
|
6
|
+
each.
|
|
7
|
+
|
|
8
|
+
## What HNDL is, and why most of this register is short
|
|
9
|
+
|
|
10
|
+
HNDL is a confidentiality attack. An adversary records ciphertext today and
|
|
11
|
+
decrypts it once a cryptographically relevant quantum computer exists. It
|
|
12
|
+
applies to data whose confidentiality must outlast that machine.
|
|
13
|
+
|
|
14
|
+
It does **not** apply to signatures in the same way. A signature forged in 2040
|
|
15
|
+
is worthless against a document verified in 2026, because the verification
|
|
16
|
+
already happened. The quantum risk to a signature scheme is forgery of *future*
|
|
17
|
+
verifications, which is an integrity and non-repudiation problem with a
|
|
18
|
+
different shape and a different deadline. Registers that fold the two together
|
|
19
|
+
overstate their own exposure, and this one keeps them apart.
|
|
20
|
+
|
|
21
|
+
**This package is predominantly a signing library.** Most of what it handles is
|
|
22
|
+
therefore outside HNDL by nature, and the register is short for a real reason
|
|
23
|
+
rather than an incomplete one. Where confidentiality genuinely is at stake, the
|
|
24
|
+
rows below say so.
|
|
25
|
+
|
|
26
|
+
## Register
|
|
27
|
+
|
|
28
|
+
| # | Data flow | Long-lived confidentiality? | Protected by | Quantum-safe | Residual |
|
|
29
|
+
|---|---|---|---|---|---|
|
|
30
|
+
| 1 | Private keys and seeds held in caller memory | **Yes, for the key's whole life** | Nothing in this package. Caller's process isolation | Not a cryptographic control | **The primary exposure.** See below |
|
|
31
|
+
| 2 | Master secret used by `keypairFromMaster` | **Yes, and it is worse than a single key** | Nothing in this package. Caller's storage | Not a cryptographic control | Compromise derives every child key, past and future |
|
|
32
|
+
| 3 | ML-KEM shared secret, in transit | Depends entirely on the caller's use | ML-KEM-768 or ML-KEM-1024 (FIPS 203) | **Yes** | The classical half of a hybrid pairing, if the caller adds one |
|
|
33
|
+
| 4 | Payload a caller encrypts under an ML-KEM-derived key | Caller's to determine | The caller's AEAD, not ours | Symmetric, so Grover only | Key size is the caller's choice; this package does not perform the encryption |
|
|
34
|
+
| 5 | Package delivery over TLS to npm or GitHub | **No** | Classical TLS | No | Confidentiality is irrelevant: the package is public. Integrity is the concern and ML-DSA-65 covers it |
|
|
35
|
+
| 6 | Signatures, JWS, webhook envelopes | **No** | ML-DSA-65 or SLH-DSA, plus HMAC-SHA-256 on webhooks | Yes | Integrity risk, not HNDL. Recorded here only so its absence is deliberate |
|
|
36
|
+
| 7 | Evidence bundle and SBOM | **No** | Published deliberately | Not applicable | Public by design |
|
|
37
|
+
| 8 | Keys held on a PKCS#11 token via `kxco-pq-hsm` | Yes, but outside this boundary | `CKA_EXTRACTABLE=false` | Hardware control | The vendor's channel to the token is the vendor's, per `BOUNDARY.md` |
|
|
38
|
+
|
|
39
|
+
## The two rows that matter
|
|
40
|
+
|
|
41
|
+
**Rows 1 and 2 are the real HNDL exposure of this product, and neither is
|
|
42
|
+
solved by a post-quantum algorithm.**
|
|
43
|
+
|
|
44
|
+
A private key is confidential for its entire life, which is exactly the
|
|
45
|
+
long-lived requirement HNDL describes. An adversary who harvests a stored
|
|
46
|
+
ML-DSA private key today does not need a quantum computer at all; they need the
|
|
47
|
+
key. The algorithm being post-quantum protects the signature against
|
|
48
|
+
cryptanalysis, not the key against theft. So the strongest post-quantum
|
|
49
|
+
posture in this package does nothing for its largest confidentiality asset.
|
|
50
|
+
|
|
51
|
+
Row 2 is worse in one specific way. A master secret under HKDF-SHA-512
|
|
52
|
+
regenerates every derived keypair, for every `info` string, past and future. It
|
|
53
|
+
is a single point whose compromise is not bounded in time. That is the correct
|
|
54
|
+
tradeoff for reproducible keys and pinnable conformance vectors, and it is the
|
|
55
|
+
right design, but the concentration of risk should be visible rather than
|
|
56
|
+
implied.
|
|
57
|
+
|
|
58
|
+
Neither row has a cryptographic mitigation available inside a library. What
|
|
59
|
+
exists is the escape in row 8: `kxco-pq-hsm` generates keys on a PKCS#11 token
|
|
60
|
+
with `CKA_EXTRACTABLE=false`, after which this package handles verification
|
|
61
|
+
only and touches no secret. **A deployment with a long-lived confidentiality
|
|
62
|
+
requirement on its keys should be using that path, and this register exists in
|
|
63
|
+
part to say so.**
|
|
64
|
+
|
|
65
|
+
## What this register does not cover
|
|
66
|
+
|
|
67
|
+
Callers. This package has no visibility into what a caller encrypts, how long
|
|
68
|
+
they need it confidential, or where they put a key. Rows 3 and 4 are marked as
|
|
69
|
+
the caller's to determine because they genuinely are, and a register claiming
|
|
70
|
+
otherwise would be inventing knowledge it does not have.
|
|
71
|
+
|
|
72
|
+
The absence of long-term validation, recorded as category 10 of
|
|
73
|
+
`CRYPTO-INVENTORY.md`, is an adjacent gap rather than an HNDL one. No
|
|
74
|
+
timestamps, no validity windows, no revocation. It bears on whether an old
|
|
75
|
+
signature can still be trusted, not on whether old ciphertext can be read.
|
|
76
|
+
|
|
77
|
+
## Review
|
|
78
|
+
|
|
79
|
+
This register is a claim about a shipped version and it ages. It should be
|
|
80
|
+
re-read whenever a new cryptographic use case enters the package, whenever a
|
|
81
|
+
category in `CRYPTO-INVENTORY.md` changes status, and on any change to how
|
|
82
|
+
seeds or master secrets are handled.
|
|
83
|
+
|
|
84
|
+
Last reviewed against 1.7.2 on 2026-09-09.
|
package/PQCMM.md
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# PQC Maturity Model self-assessment
|
|
2
|
+
|
|
3
|
+
PKI Consortium PQC Maturity Model (PQCMM), assessed against the model as
|
|
4
|
+
published at <https://pkic.org/wg/pqc/pqcmm/>.
|
|
5
|
+
|
|
6
|
+
**Declared level: 3 (Advanced).**
|
|
7
|
+
|
|
8
|
+
A self-assessment is indicative, not authoritative. It is the vendor's own view
|
|
9
|
+
and it has not been independently verified. The model says relying parties
|
|
10
|
+
should treat a self-assessed level as a signal rather than a guarantee, and that
|
|
11
|
+
is how this document should be read. Where a criterion is not met, this document
|
|
12
|
+
says so and names what is missing rather than reporting a partial as a pass.
|
|
13
|
+
|
|
14
|
+
## Scope
|
|
15
|
+
|
|
16
|
+
| Field | Value |
|
|
17
|
+
|---|---|
|
|
18
|
+
| Product | `kxco-post-quantum` |
|
|
19
|
+
| Version assessed | 1.7.2 |
|
|
20
|
+
| Commit | `90b5778b4d19ed0f78715e143a6a50b9170b70f9`, clean tree |
|
|
21
|
+
| Registry | <https://www.npmjs.com/package/kxco-post-quantum> |
|
|
22
|
+
| Licence | Apache-2.0 |
|
|
23
|
+
| Assurance method | Self-assessment |
|
|
24
|
+
| Date | 2026-09-09 |
|
|
25
|
+
|
|
26
|
+
A PQCMM assessment applies to a single product. The other `kxco-pq-*` packages
|
|
27
|
+
depend on this one and are not covered here; each needs its own assessment.
|
|
28
|
+
|
|
29
|
+
## Evidence available to an assessor
|
|
30
|
+
|
|
31
|
+
Everything cited below is a permanent unauthenticated URL. No account, no
|
|
32
|
+
request to us, no expiring artifact.
|
|
33
|
+
|
|
34
|
+
| Artefact | Path under the release |
|
|
35
|
+
|---|---|
|
|
36
|
+
| Evidence manifest | `releases/latest/download/manifest-node24.x.json` |
|
|
37
|
+
| Evidence bundle | `releases/latest/download/evidence-node24.x.zip` |
|
|
38
|
+
| CycloneDX SBOM | `releases/latest/download/sbom.cyclonedx.json` |
|
|
39
|
+
| In-toto attestation | `releases/latest/download/evidence.intoto.jsonl` |
|
|
40
|
+
| Release signing key | `releases/latest/download/release-signing-key.pub.hex` |
|
|
41
|
+
|
|
42
|
+
Base: `https://github.com/KnightsbridgeAIQ/kxco-post-quantum/`
|
|
43
|
+
|
|
44
|
+
Two documents in the repository carry the Level 3 evidence and are cited
|
|
45
|
+
throughout: `CRYPTO-INVENTORY.md` for the ten-category cryptographic inventory,
|
|
46
|
+
and `HNDL.md` for the harvest-now-decrypt-later exposure register.
|
|
47
|
+
|
|
48
|
+
The manifest pins the commit, the toolchain (Node 24.20.0, OpenSSL 3.5.7), the
|
|
49
|
+
backend, the dependency versions, and every step with its exact command, its
|
|
50
|
+
result and its duration. Each file in the bundle carries its SHA-256. The
|
|
51
|
+
conformance and interop runs are reproducible from the commands recorded in the
|
|
52
|
+
manifest rather than taken on our word.
|
|
53
|
+
|
|
54
|
+
## Level 1, Initial: MET
|
|
55
|
+
|
|
56
|
+
| # | Criterion | Answer | Evidence |
|
|
57
|
+
|---|---|---|---|
|
|
58
|
+
| 1 | A quantum-safe algorithm in a released build | Yes | ML-DSA-65 (FIPS 204), ML-KEM-768 (FIPS 203), SLH-DSA-SHA2-192s (FIPS 205) in 1.7.2 on the public npm stable channel. Category 5 sets ML-DSA-87 and ML-KEM-1024 also ship. |
|
|
59
|
+
| 2 | The feature can be enabled | Yes | Available on import. No flag, no custom build, no source modification. |
|
|
60
|
+
| 3 | Documented for evaluation | Yes | `README.md`, with a per-function API reference. |
|
|
61
|
+
|
|
62
|
+
Release channel is stable and public, available to all consumers, with no
|
|
63
|
+
programme enrolment. Ten SLH-DSA parameter sets are exposed, not one.
|
|
64
|
+
|
|
65
|
+
## Level 2, Foundational: MET
|
|
66
|
+
|
|
67
|
+
| # | Criterion | Answer | Evidence |
|
|
68
|
+
|---|---|---|---|
|
|
69
|
+
| 1 | Quantum-safe algorithms in core production functionality | Yes | Signing, key encapsulation, key derivation and fingerprinting are the product's core, not a preview channel. |
|
|
70
|
+
| 2 | Compatibility with a published standard from a recognised body | Yes | NIST FIPS 203, 204 and 205. |
|
|
71
|
+
| 3a | Standards-conformance testing | Yes | 2,103 NIST ACVP vectors: 1,793 passed, 0 failed, 310 skipped. Every skip is this library refusing a pre-hash weaker than the parameter set, listed individually with its reason. A skip is not counted as a pass. See `CONFORMANCE.md` and manifest steps `acvp`, `acvp-fips205`, `acvp-fips205-siggen`. |
|
|
72
|
+
| 3b | Interoperability against an independent conformant implementation | Yes, four of them | 225 cross-implementation checks, 0 failed, both directions, with negative controls, against liboqs, Bouncy Castle and two pure-Python implementations. Run against both backends. Manifest step `interop`. |
|
|
73
|
+
| 3c | Functional security testing as configured for production | Yes | `npm test` recorded in the manifest, plus the fuzz corpus under `fuzz/`. |
|
|
74
|
+
| 3d | Smoke performance test under representative load | Yes | `BENCHMARKS.md`: per-algorithm p95 and p99 on both backends, on x86-64 and arm64, plus memory. |
|
|
75
|
+
| 4 | Documented for production use including known limitations | Yes | `THREAT-MODEL.md` for what is and is not defended, `BOUNDARY.md` for which cryptography this package performs versus depends on versus offers, plus `LIFECYCLE.md` and `MIGRATION.md`. |
|
|
76
|
+
|
|
77
|
+
Level 2 asks for CAVP or ACVTS results "or equivalent". Ours are the NIST ACVP
|
|
78
|
+
vectors run by us and published with the commands to reproduce them. That is
|
|
79
|
+
equivalent evidence, not a NIST certificate. **There is no CAVP certificate
|
|
80
|
+
number for this product.** An assessor checking the CAVP or CMVP database will
|
|
81
|
+
find nothing, and should record that.
|
|
82
|
+
|
|
83
|
+
## Level 3, Advanced: MET
|
|
84
|
+
|
|
85
|
+
| # | Criterion | Answer | Evidence |
|
|
86
|
+
|---|---|---|---|
|
|
87
|
+
| 1 | Full cryptographic inventory across every applicable taxonomy category | Yes | `CRYPTO-INVENTORY.md` covers all ten categories. Four are marked not applicable with a written reason; none is omitted. |
|
|
88
|
+
| 2 | Non-quantum-safe features documented and flagged | Yes | `BOUNDARY.md`, "The gaps, collected", and the classical rows of `CRYPTO-INVENTORY.md` categories 1, 8 and 9. |
|
|
89
|
+
| 3 | SBOM or equivalent component inventory | Yes | CycloneDX SBOM as a release asset at a permanent URL, generated by `npm sbom` from the tree that was published. Manifest step `sbom`. |
|
|
90
|
+
| 4 | Crypto agility, two algorithms selectable in the same role | Yes | ML-DSA-65 and SLH-DSA-SHA2-192s are both available in the signature role by configuration, which is two different algorithms rather than two parameter sets of one. `AGILITY.md` separates the replacement plan, the implemented mechanism and the interoperable transition, and states what the package does not give you. |
|
|
91
|
+
| 5 | Documented HNDL exposure register | Yes | `HNDL.md`. Eight data flows, each with its confidentiality horizon, its protecting algorithm and its residual. |
|
|
92
|
+
|
|
93
|
+
Writing the inventory against the taxonomy produced two findings that this
|
|
94
|
+
package's own audit documents had not stated, and both are recorded rather than
|
|
95
|
+
smoothed over.
|
|
96
|
+
|
|
97
|
+
**The library generates no randomness in its JavaScript backend.** Every
|
|
98
|
+
keypair comes from a caller-supplied seed, or from a master secret through
|
|
99
|
+
HKDF-SHA-512. So in that backend the entropy quality of every private key is a
|
|
100
|
+
property of the caller, not of this package, and the package cannot detect a
|
|
101
|
+
weak seed. The native backend differs: `crypto.generateKeyPairSync` uses the
|
|
102
|
+
OpenSSL DRBG. `CRYPTO-INVENTORY.md` category 6.
|
|
103
|
+
|
|
104
|
+
**The largest HNDL exposure in this product has no post-quantum mitigation.**
|
|
105
|
+
Private keys and, more sharply, the master secret behind `keypairFromMaster`
|
|
106
|
+
are confidential for their whole life, which is precisely the long-lived
|
|
107
|
+
requirement HNDL describes. A post-quantum algorithm protects the signature
|
|
108
|
+
against cryptanalysis and does nothing for the key against theft. The available
|
|
109
|
+
answer is the PKCS#11 path in `kxco-pq-hsm`, not an algorithm choice here.
|
|
110
|
+
`HNDL.md`, rows 1 and 2.
|
|
111
|
+
|
|
112
|
+
## Level 4, Managed: NOT MET
|
|
113
|
+
|
|
114
|
+
| # | Criterion | Answer | Evidence or gap |
|
|
115
|
+
|---|---|---|---|
|
|
116
|
+
| 1 | CBOM maintained | **No** | The product publishes an SBOM, not a CBOM. `CRYPTO-INVENTORY.md` now records each algorithm with its protocol context and usage purpose, which is the human-readable half of what a CBOM carries, but it is prose rather than a machine-readable CBOM and key sizes are stated by parameter set rather than per field. Closing this means emitting a CycloneDX CBOM as a release asset, which is a build change rather than a document. |
|
|
117
|
+
| 2 | Zero-legacy capability across every in-scope component | **Not determined** | Not assessed against the model's wording, which extends to boot, firmware update signing, hardware-bound operations and internal diagnostics. Claiming it without that determination would be an overclaim. |
|
|
118
|
+
| 3 | Symmetric and hash strengths adequate beyond CRQC availability | Yes | SHA-256 for key identifiers and webhook HMAC, SHA-512 under HKDF for seed derivation, via `@noble/hashes` 2.4.0. Per-use detail in `CRYPTO-INVENTORY.md`. |
|
|
119
|
+
| 4 | Hybrid and composite support documented, with contexts | Partial | Hybrid is documented: `webhook` performs HMAC plus ML-DSA-65 delivery signing, and `deriveSeed` exists to combine an ML-KEM shared secret with a classical secret through a KDF. Composite, in the algorithm-fused sense, is not supported and is not currently stated as unsupported. |
|
|
120
|
+
|
|
121
|
+
## Level 5, Optimized: NOT MET
|
|
122
|
+
|
|
123
|
+
| # | Criterion | Answer | Evidence or gap |
|
|
124
|
+
|---|---|---|---|
|
|
125
|
+
| 1 | Quantum-safe by default, legacy requires explicit enablement | Yes | There is no classical algorithm to fall back to. The default parameter set is Category 3. |
|
|
126
|
+
| 2 | Benchmarked and tuned against operational requirements | Yes | `BENCHMARKS.md`. Two figures stated rather than hidden: ML-DSA signing keeps a rejection-sampling tail on either backend, and SLH-DSA-SHA2-192s signs in seconds rather than milliseconds. |
|
|
127
|
+
| 3 | Primarily follows standards from a recognised body | Yes | FIPS 203, 204 and 205. |
|
|
128
|
+
| 4 | **Independently verified or certified** | **No** | No FIPS 140 validation. No Common Criteria evaluation. The underlying `@noble/post-quantum` 0.7.0 has no published third-party formal security analysis covering the implemented PQC algorithms, so the library-based route in the model's wording is not available either. |
|
|
129
|
+
|
|
130
|
+
Criterion 4 is the binding constraint and it cannot be closed by documentation.
|
|
131
|
+
It requires a paid engagement: a CAVP or CMVP validation through an accredited
|
|
132
|
+
laboratory, a Common Criteria evaluation, or a published independent audit of
|
|
133
|
+
the cryptographic implementation.
|
|
134
|
+
|
|
135
|
+
## Assessment methodology record
|
|
136
|
+
|
|
137
|
+
The model requires this record to accompany an assessment.
|
|
138
|
+
|
|
139
|
+
- **Evidence method.** Documentation review, plus the published evidence
|
|
140
|
+
manifest, plus verification of the licence state of every published package
|
|
141
|
+
against the public npm registry on 2026-09-09.
|
|
142
|
+
- **Cryptographic library.** `@noble/post-quantum` 0.7.0 and `@noble/hashes`
|
|
143
|
+
2.4.0 in the JavaScript backend; `node:crypto` on OpenSSL 3.5.7 in the native
|
|
144
|
+
backend. Both versions are recorded in the manifest. `@noble/post-quantum` is
|
|
145
|
+
maintained, and its PQC support is confirmed from its public repository. It
|
|
146
|
+
has **not** been independently audited. Version 0.7.1 is deliberately not
|
|
147
|
+
adopted because it regressed SLH-DSA, so the dependency is pinned at 0.7.0.
|
|
148
|
+
- **Reproduction attempts.** All conformance, interop, test and SBOM steps in
|
|
149
|
+
the manifest ran in CI from a clean tree at commit `90b5778`, on Node
|
|
150
|
+
24.20.0, linux-x64, on 2026-09-08. Every step reports `ok: true`, and
|
|
151
|
+
`sampling.full` is `true`.
|
|
152
|
+
- **Public database checks.** npm registry, all sixteen published `kxco-*`
|
|
153
|
+
packages, 2026-09-09: every one reports `Apache-2.0`. NIST CAVP and CMVP: no
|
|
154
|
+
certificate exists for this product, confirmed rather than assumed.
|
|
155
|
+
- **Unverified claims.** Every criterion answered Yes above is vendor-stated and
|
|
156
|
+
not independently verified. That is what a self-assessment is. The manifest
|
|
157
|
+
and the bundle exist so that an assessor can convert these into verified
|
|
158
|
+
findings without asking us for anything.
|
|
159
|
+
|
|
160
|
+
## Corrections
|
|
161
|
+
|
|
162
|
+
If any statement here is wrong, it should be corrected here first, and the
|
|
163
|
+
correction dated. Facts about this package that are commonly recorded wrongly,
|
|
164
|
+
with the one-line check for each, are listed at the top of `README.md`.
|