@calimero-network/mero-js 24.7.0 → 25.0.1

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.
@@ -1,7 +1,7 @@
1
1
  export { HANDSHAKE_PATH, SEALED_CONTENT_TYPE, SEALED_PATH, SealedTransportError, StaleTransportKeyError, createAttestedSealedFetch, createSealedFetch, fetchAttestedTransportKey, transportKeyBinding, } from './sealed.js';
2
2
  export type { AttestedSealedFetchOptions, SealedFetchOptions, VerifyTransportQuote } from './sealed.js';
3
- export { createQuoteVerifier, trustedMeasurementsFromReleases } from './verify.js';
4
- export type { DcapCollateral, DcapVerifiedReport, DcapVerify, PublishedMrtds, QuoteVerifier, QuoteVerifierOptions, TrustedMeasurements, } from './verify.js';
3
+ export { PRODUCTION_PROFILE, createQuoteVerifier, trustedMeasurementsFromReleases } from './verify.js';
4
+ export type { DcapCollateral, DcapVerifiedReport, DcapVerify, PublishedMrtds, QuoteVerifier, QuoteVerifierOptions, TrustedMeasurements, TrustedProfileOptions, } from './verify.js';
5
5
  export { DEFAULT_RELEASE_MIRROR, NODE_RELEASE_SIGNER, cloudNodeReleaseUrl, createSignedReleaseSealedFetch, createSignedReleaseVerifier, fetchNodeRelease, fetchNodeReleaseVersion, nodeReleaseVersionFromImage, trustSignedRelease, verifySignedNodeRelease, } from './release.js';
6
6
  export type { SignedNodeRelease, SignedReleaseSealedFetchOptions, SignedReleaseVerifierOptions, TrustSignedReleaseOptions, VerifySignedNodeReleaseOptions, } from './release.js';
7
7
  export type { SignerIdentity } from './sigstore.js';
@@ -1,3 +1,3 @@
1
1
  export { HANDSHAKE_PATH, SEALED_CONTENT_TYPE, SEALED_PATH, SealedTransportError, StaleTransportKeyError, createAttestedSealedFetch, createSealedFetch, fetchAttestedTransportKey, transportKeyBinding, } from './sealed.js';
2
- export { createQuoteVerifier, trustedMeasurementsFromReleases } from './verify.js';
2
+ export { PRODUCTION_PROFILE, createQuoteVerifier, trustedMeasurementsFromReleases } from './verify.js';
3
3
  export { DEFAULT_RELEASE_MIRROR, NODE_RELEASE_SIGNER, cloudNodeReleaseUrl, createSignedReleaseSealedFetch, createSignedReleaseVerifier, fetchNodeRelease, fetchNodeReleaseVersion, nodeReleaseVersionFromImage, trustSignedRelease, verifySignedNodeRelease, } from './release.js';
@@ -27,7 +27,7 @@
27
27
  * another.
28
28
  */
29
29
  import { type SignerIdentity } from './sigstore.js';
30
- import { type DcapVerify, type PublishedMrtds, type QuoteVerifier, type QuoteVerifierOptions } from './verify.js';
30
+ import { type DcapVerify, type PublishedMrtds, type QuoteVerifier, type QuoteVerifierOptions, type TrustedProfileOptions } from './verify.js';
31
31
  /** The workflow that signs every mero-tee node release, and the issuer of its identity. */
32
32
  export declare const NODE_RELEASE_SIGNER: Readonly<SignerIdentity>;
33
33
  /**
@@ -107,11 +107,9 @@ export declare function fetchNodeReleaseVersion(baseUrl: string, options?: {
107
107
  }): Promise<string>;
108
108
  /** Where the cloud at `cloudUrl` (e.g. `https://cloud.calimero.network`) mirrors node release `version`. */
109
109
  export declare function cloudNodeReleaseUrl(cloudUrl: string, version: string): string;
110
- export interface TrustSignedReleaseOptions {
110
+ export interface TrustSignedReleaseOptions extends TrustedProfileOptions {
111
111
  /** The release, from any source; it is verified here. */
112
112
  release: SignedNodeRelease;
113
- /** The image profile to trust, e.g. `locked-read-only`. */
114
- profile: string;
115
113
  /**
116
114
  * The oldest release accepted, e.g. `2.3.87`. Required: every release ever
117
115
  * signed stays validly signed, so without a floor a relay could present an
@@ -200,7 +200,10 @@ export async function trustSignedRelease(options) {
200
200
  if (compareReleaseVersions(version, minimum) < 0) {
201
201
  throw new Error(`Release ${version} is older than the minimum trusted, ${minimum}`);
202
202
  }
203
- return trustedMeasurementsFromReleases([published], { profile: options.profile });
203
+ return trustedMeasurementsFromReleases([published], {
204
+ profile: options.profile,
205
+ allowDebugProfile: options.allowDebugProfile,
206
+ });
204
207
  }
205
208
  /**
206
209
  * A {@link createQuoteVerifier} whose trusted image is the signed release the
@@ -220,6 +223,7 @@ export function createSignedReleaseVerifier(options) {
220
223
  const trusted = await trustSignedRelease({
221
224
  release: await options.release(),
222
225
  profile: options.profile,
226
+ allowDebugProfile: options.allowDebugProfile,
223
227
  minReleaseVersion: options.minReleaseVersion,
224
228
  identity: options.identity,
225
229
  issuer: options.issuer,
@@ -167,6 +167,20 @@ export interface PublishedMrtds {
167
167
  * (checked out of a release you verified) trusts that release; fetching it at
168
168
  * run time trusts whoever serves it.
169
169
  */
170
- export declare function trustedMeasurementsFromReleases(releases: PublishedMrtds[], { profile }: {
170
+ /**
171
+ * The one image profile a release publishes for production. The `debug` and
172
+ * `debug-read-only` images are signed and published beside it, but run with
173
+ * SSH and the operator's tooling inside the TD, so trusting one trusts an
174
+ * image the operator can read.
175
+ */
176
+ export declare const PRODUCTION_PROFILE = "locked-read-only";
177
+ export interface TrustedProfileOptions {
178
+ /** The image profile to trust, e.g. `locked-read-only`. */
171
179
  profile: string;
172
- }): Required<Pick<QuoteVerifierOptions, 'allowedMeasurements' | 'allowedTcbStatuses'>>;
180
+ /**
181
+ * Trust a profile other than {@link PRODUCTION_PROFILE}, such as `debug`.
182
+ * Its image is readable by whoever operates the node, so only for testing.
183
+ */
184
+ allowDebugProfile?: boolean;
185
+ }
186
+ export declare function trustedMeasurementsFromReleases(releases: PublishedMrtds[], { profile, allowDebugProfile }: TrustedProfileOptions): Required<Pick<QuoteVerifierOptions, 'allowedMeasurements' | 'allowedTcbStatuses'>>;
@@ -90,6 +90,13 @@ export function createQuoteVerifier(options) {
90
90
  throw new Error(`The platform's TCB status is ${verified.status}, which is not accepted`);
91
91
  }
92
92
  const td = tdReport(verified.report);
93
+ // TUD bit 0. A debug TD's memory and registers are open to the host, so its
94
+ // measurements prove nothing about what runs in it. Checked here, not left
95
+ // to `dcapVerify`, which a caller may swap for one that allows debug; an
96
+ // attribute field that cannot be read counts as debug.
97
+ if (td.tdAttributes?.length !== 8 || (td.tdAttributes[0] & 0x01) !== 0) {
98
+ throw new Error('The quote is from a debug TD, or its TD attributes cannot be read');
99
+ }
93
100
  const measured = [td.mrTd, td.rtMr0, td.rtMr1, td.rtMr2, td.rtMr3].map((register) => hex(register));
94
101
  if (allowedImages.length > 0 && !allowedImages.includes(measured.join())) {
95
102
  throw new Error(`The measurements (MRTD ${measured[0]}, RTMR0-3 ${measured.slice(1).join(', ')}) are not an image this verifier trusts`);
@@ -166,7 +173,14 @@ const TCB_STATUSES = [
166
173
  * (checked out of a release you verified) trusts that release; fetching it at
167
174
  * run time trusts whoever serves it.
168
175
  */
169
- export function trustedMeasurementsFromReleases(releases, { profile }) {
176
+ /**
177
+ * The one image profile a release publishes for production. The `debug` and
178
+ * `debug-read-only` images are signed and published beside it, but run with
179
+ * SSH and the operator's tooling inside the TD, so trusting one trusts an
180
+ * image the operator can read.
181
+ */
182
+ export const PRODUCTION_PROFILE = 'locked-read-only';
183
+ export function trustedMeasurementsFromReleases(releases, { profile, allowDebugProfile = false }) {
170
184
  if (releases.length === 0) {
171
185
  throw new Error('No release given, so no image would be trusted');
172
186
  }
@@ -181,6 +195,10 @@ export function trustedMeasurementsFromReleases(releases, { profile }) {
181
195
  const known = Object.keys(release?.profiles ?? {}).join(', ') || 'none';
182
196
  throw new Error(`${name} has no profile ${JSON.stringify(profile)} (it has: ${known})`);
183
197
  }
198
+ if (profile !== PRODUCTION_PROFILE && !allowDebugProfile) {
199
+ throw new Error(`${JSON.stringify(profile)} is not a production profile: its image is readable by whoever ` +
200
+ `operates the node. Trust ${JSON.stringify(PRODUCTION_PROFILE)}, or pass allowDebugProfile to test`);
201
+ }
184
202
  const accepted = (image.allowed_tcb_statuses ?? ['uptodate']).map((status) => tcbStatus(status, name));
185
203
  statuses = statuses === undefined ? accepted : statuses.filter((status) => accepted.includes(status));
186
204
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@calimero-network/mero-js",
3
- "version": "24.7.0",
3
+ "version": "25.0.1",
4
4
  "description": "Pure JavaScript SDK for Calimero",
5
5
  "type": "module",
6
6
  "exports": {