@nextera.one/axis-server-sdk 1.5.0 → 1.6.0
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/dist/index.d.mts +894 -386
- package/dist/index.d.ts +894 -386
- package/dist/index.js +1411 -38
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1398 -30
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -64,6 +64,9 @@ __export(index_exports, {
|
|
|
64
64
|
BAND: () => BAND,
|
|
65
65
|
BodyProfile: () => import_axis_protocol2.BodyProfile,
|
|
66
66
|
CAPABILITIES: () => CAPABILITIES,
|
|
67
|
+
CCE_ERROR: () => CCE_ERROR,
|
|
68
|
+
CCE_PROTOCOL_VERSION: () => CCE_PROTOCOL_VERSION,
|
|
69
|
+
CceError: () => CceError,
|
|
67
70
|
ContractViolationError: () => ContractViolationError,
|
|
68
71
|
DEFAULT_CONTRACTS: () => DEFAULT_CONTRACTS,
|
|
69
72
|
DEFAULT_TIMEOUT: () => DEFAULT_TIMEOUT,
|
|
@@ -190,6 +193,7 @@ __export(index_exports, {
|
|
|
190
193
|
canonicalJson: () => canonicalJson,
|
|
191
194
|
canonicalJsonExcluding: () => canonicalJsonExcluding,
|
|
192
195
|
canonicalizeObservation: () => canonicalizeObservation,
|
|
196
|
+
cce: () => cce_exports,
|
|
193
197
|
classifyIntent: () => classifyIntent,
|
|
194
198
|
computeReceiptHash: () => computeReceiptHash,
|
|
195
199
|
computeSignaturePayload: () => computeSignaturePayload,
|
|
@@ -213,6 +217,7 @@ __export(index_exports, {
|
|
|
213
217
|
encodeVarint: () => import_axis_protocol3.encodeVarint,
|
|
214
218
|
endStage: () => endStage,
|
|
215
219
|
engine: () => engine_exports,
|
|
220
|
+
executeCcePipeline: () => executeCcePipeline,
|
|
216
221
|
extractDtoSchema: () => extractDtoSchema,
|
|
217
222
|
finalizeObservation: () => finalizeObservation,
|
|
218
223
|
generateEd25519KeyPair: () => generateEd25519KeyPair,
|
|
@@ -239,7 +244,7 @@ __export(index_exports, {
|
|
|
239
244
|
security: () => security_exports,
|
|
240
245
|
sensitivityName: () => sensitivityName,
|
|
241
246
|
sensors: () => sensors_exports,
|
|
242
|
-
sha256: () =>
|
|
247
|
+
sha256: () => sha2564,
|
|
243
248
|
signFrame: () => signFrame,
|
|
244
249
|
stableJsonStringify: () => stableJsonStringify,
|
|
245
250
|
startStage: () => startStage,
|
|
@@ -636,6 +641,626 @@ var SensorDecisions = {
|
|
|
636
641
|
}
|
|
637
642
|
};
|
|
638
643
|
|
|
644
|
+
// src/cce/cce-derivation.service.ts
|
|
645
|
+
var import_utils = require("@noble/hashes/utils.js");
|
|
646
|
+
var import_hkdf = require("@noble/hashes/hkdf.js");
|
|
647
|
+
var import_sha2 = require("@noble/hashes/sha2.js");
|
|
648
|
+
|
|
649
|
+
// src/cce/cce.types.ts
|
|
650
|
+
var CCE_PROTOCOL_VERSION = "cce-v1";
|
|
651
|
+
var CCE_DERIVATION = {
|
|
652
|
+
/** Request execution context */
|
|
653
|
+
REQUEST: "axis:cce:req:v1",
|
|
654
|
+
/** Response execution context */
|
|
655
|
+
RESPONSE: "axis:cce:resp:v1",
|
|
656
|
+
/** Witness binding context */
|
|
657
|
+
WITNESS: "axis:cce:witness:v1"
|
|
658
|
+
};
|
|
659
|
+
var CCE_AES_KEY_BYTES = 32;
|
|
660
|
+
var CCE_IV_BYTES = 12;
|
|
661
|
+
var CCE_TAG_BYTES = 16;
|
|
662
|
+
var CCE_NONCE_BYTES = 32;
|
|
663
|
+
var CCE_ERROR = {
|
|
664
|
+
// Envelope errors
|
|
665
|
+
INVALID_ENVELOPE: "CCE_INVALID_ENVELOPE",
|
|
666
|
+
UNSUPPORTED_VERSION: "CCE_UNSUPPORTED_VERSION",
|
|
667
|
+
MISSING_CAPSULE: "CCE_MISSING_CAPSULE",
|
|
668
|
+
MISSING_ENCRYPTED_KEY: "CCE_MISSING_ENCRYPTED_KEY",
|
|
669
|
+
// Signature errors
|
|
670
|
+
CLIENT_SIG_INVALID: "CCE_CLIENT_SIG_INVALID",
|
|
671
|
+
CLIENT_KEY_NOT_FOUND: "CCE_CLIENT_KEY_NOT_FOUND",
|
|
672
|
+
// Capsule errors
|
|
673
|
+
CAPSULE_SIG_INVALID: "CCE_CAPSULE_SIG_INVALID",
|
|
674
|
+
CAPSULE_EXPIRED: "CCE_CAPSULE_EXPIRED",
|
|
675
|
+
CAPSULE_NOT_YET_VALID: "CCE_CAPSULE_NOT_YET_VALID",
|
|
676
|
+
CAPSULE_REVOKED: "CCE_CAPSULE_REVOKED",
|
|
677
|
+
CAPSULE_CONSUMED: "CCE_CAPSULE_CONSUMED",
|
|
678
|
+
// Binding errors
|
|
679
|
+
AUDIENCE_MISMATCH: "CCE_AUDIENCE_MISMATCH",
|
|
680
|
+
INTENT_MISMATCH: "CCE_INTENT_MISMATCH",
|
|
681
|
+
TPS_WINDOW_EXPIRED: "CCE_TPS_WINDOW_EXPIRED",
|
|
682
|
+
TPS_WINDOW_FUTURE: "CCE_TPS_WINDOW_FUTURE",
|
|
683
|
+
// Replay / nonce errors
|
|
684
|
+
REPLAY_DETECTED: "CCE_REPLAY_DETECTED",
|
|
685
|
+
NONCE_REUSED: "CCE_NONCE_REUSED",
|
|
686
|
+
// Decryption errors
|
|
687
|
+
DECRYPTION_FAILED: "CCE_DECRYPTION_FAILED",
|
|
688
|
+
KEY_UNWRAP_FAILED: "CCE_KEY_UNWRAP_FAILED",
|
|
689
|
+
AEAD_TAG_MISMATCH: "CCE_AEAD_TAG_MISMATCH",
|
|
690
|
+
PAYLOAD_TOO_LARGE: "CCE_PAYLOAD_TOO_LARGE",
|
|
691
|
+
// Schema / validation errors
|
|
692
|
+
PAYLOAD_SCHEMA_INVALID: "CCE_PAYLOAD_SCHEMA_INVALID",
|
|
693
|
+
INTENT_SCHEMA_MISMATCH: "CCE_INTENT_SCHEMA_MISMATCH",
|
|
694
|
+
// Policy errors
|
|
695
|
+
POLICY_DENIED: "CCE_POLICY_DENIED",
|
|
696
|
+
CONSTRAINT_VIOLATED: "CCE_CONSTRAINT_VIOLATED",
|
|
697
|
+
// Handler errors
|
|
698
|
+
HANDLER_NOT_FOUND: "CCE_HANDLER_NOT_FOUND",
|
|
699
|
+
HANDLER_EXECUTION_FAILED: "CCE_HANDLER_EXECUTION_FAILED",
|
|
700
|
+
HANDLER_TIMEOUT: "CCE_HANDLER_TIMEOUT",
|
|
701
|
+
// Response errors
|
|
702
|
+
RESPONSE_ENCRYPTION_FAILED: "CCE_RESPONSE_ENCRYPTION_FAILED"
|
|
703
|
+
};
|
|
704
|
+
var CceError = class extends Error {
|
|
705
|
+
constructor(code, message, metadata) {
|
|
706
|
+
super(`[${code}] ${message}`);
|
|
707
|
+
this.code = code;
|
|
708
|
+
this.metadata = metadata;
|
|
709
|
+
this.name = "CceError";
|
|
710
|
+
}
|
|
711
|
+
/** Whether this error is safe to expose to the client */
|
|
712
|
+
get clientSafe() {
|
|
713
|
+
const internal = [
|
|
714
|
+
CCE_ERROR.DECRYPTION_FAILED,
|
|
715
|
+
CCE_ERROR.KEY_UNWRAP_FAILED,
|
|
716
|
+
CCE_ERROR.AEAD_TAG_MISMATCH,
|
|
717
|
+
CCE_ERROR.HANDLER_EXECUTION_FAILED,
|
|
718
|
+
CCE_ERROR.RESPONSE_ENCRYPTION_FAILED
|
|
719
|
+
];
|
|
720
|
+
return !internal.includes(this.code);
|
|
721
|
+
}
|
|
722
|
+
/** Get client-safe representation */
|
|
723
|
+
toClientError() {
|
|
724
|
+
if (this.clientSafe) {
|
|
725
|
+
return { code: this.code, message: this.message };
|
|
726
|
+
}
|
|
727
|
+
return {
|
|
728
|
+
code: CCE_ERROR.DECRYPTION_FAILED,
|
|
729
|
+
message: "Request processing failed"
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
};
|
|
733
|
+
|
|
734
|
+
// src/cce/cce-derivation.service.ts
|
|
735
|
+
function buildSalt(capsuleId, capsuleNonce, requestNonce) {
|
|
736
|
+
const encoder = new TextEncoder();
|
|
737
|
+
const data = encoder.encode(
|
|
738
|
+
capsuleId + "|" + capsuleNonce + "|" + requestNonce
|
|
739
|
+
);
|
|
740
|
+
return (0, import_sha2.sha256)(data);
|
|
741
|
+
}
|
|
742
|
+
function buildInfo(contextPrefix, capsule, extraNonce) {
|
|
743
|
+
const encoder = new TextEncoder();
|
|
744
|
+
const parts = [
|
|
745
|
+
contextPrefix,
|
|
746
|
+
capsule.sub,
|
|
747
|
+
capsule.kid,
|
|
748
|
+
capsule.intent,
|
|
749
|
+
capsule.aud,
|
|
750
|
+
String(capsule.tps_from),
|
|
751
|
+
String(capsule.tps_to),
|
|
752
|
+
capsule.policy_hash ?? "",
|
|
753
|
+
capsule.ver
|
|
754
|
+
];
|
|
755
|
+
if (extraNonce) {
|
|
756
|
+
parts.push(extraNonce);
|
|
757
|
+
}
|
|
758
|
+
return encoder.encode(parts.join("|"));
|
|
759
|
+
}
|
|
760
|
+
function deriveRequestExecutionKey(input) {
|
|
761
|
+
const ikm = (0, import_utils.hexToBytes)(input.axisLocalSecret);
|
|
762
|
+
const salt = buildSalt(
|
|
763
|
+
input.capsule.capsule_id,
|
|
764
|
+
input.capsule.capsule_nonce,
|
|
765
|
+
input.requestNonce
|
|
766
|
+
);
|
|
767
|
+
const info = buildInfo(CCE_DERIVATION.REQUEST, input.capsule);
|
|
768
|
+
return (0, import_hkdf.hkdf)(import_sha2.sha256, ikm, salt, info, CCE_AES_KEY_BYTES);
|
|
769
|
+
}
|
|
770
|
+
function deriveResponseExecutionKey(input) {
|
|
771
|
+
const ikm = (0, import_utils.hexToBytes)(input.axisLocalSecret);
|
|
772
|
+
const encoder = new TextEncoder();
|
|
773
|
+
const saltData = encoder.encode(
|
|
774
|
+
input.capsule.capsule_id + "|" + input.capsule.capsule_nonce + "|" + input.requestNonce + "|" + input.responseNonce
|
|
775
|
+
);
|
|
776
|
+
const salt = (0, import_sha2.sha256)(saltData);
|
|
777
|
+
const info = buildInfo(
|
|
778
|
+
CCE_DERIVATION.RESPONSE,
|
|
779
|
+
input.capsule,
|
|
780
|
+
input.responseNonce
|
|
781
|
+
);
|
|
782
|
+
return (0, import_hkdf.hkdf)(import_sha2.sha256, ikm, salt, info, CCE_AES_KEY_BYTES);
|
|
783
|
+
}
|
|
784
|
+
function deriveWitnessKey(input) {
|
|
785
|
+
const ikm = (0, import_utils.hexToBytes)(input.axisLocalSecret);
|
|
786
|
+
const salt = buildSalt(
|
|
787
|
+
input.capsule.capsule_id,
|
|
788
|
+
input.capsule.capsule_nonce,
|
|
789
|
+
input.requestNonce
|
|
790
|
+
);
|
|
791
|
+
const info = buildInfo(CCE_DERIVATION.WITNESS, input.capsule);
|
|
792
|
+
return (0, import_hkdf.hkdf)(import_sha2.sha256, ikm, salt, info, CCE_AES_KEY_BYTES);
|
|
793
|
+
}
|
|
794
|
+
function buildExecutionContext(input, requestId) {
|
|
795
|
+
const executionKey = deriveRequestExecutionKey(input);
|
|
796
|
+
const keyHash = (0, import_utils.bytesToHex)((0, import_sha2.sha256)(executionKey));
|
|
797
|
+
executionKey.fill(0);
|
|
798
|
+
return {
|
|
799
|
+
execution_key_hash: keyHash,
|
|
800
|
+
request_id: requestId,
|
|
801
|
+
capsule_id: input.capsule.capsule_id,
|
|
802
|
+
sub: input.capsule.sub,
|
|
803
|
+
kid: input.capsule.kid,
|
|
804
|
+
intent: input.capsule.intent,
|
|
805
|
+
aud: input.capsule.aud,
|
|
806
|
+
tps_from: input.capsule.tps_from,
|
|
807
|
+
tps_to: input.capsule.tps_to,
|
|
808
|
+
policy_hash: input.capsule.policy_hash,
|
|
809
|
+
derived_at: Math.floor(Date.now() / 1e3),
|
|
810
|
+
valid: true
|
|
811
|
+
};
|
|
812
|
+
}
|
|
813
|
+
function generateCceNonce() {
|
|
814
|
+
const bytes2 = new Uint8Array(CCE_NONCE_BYTES);
|
|
815
|
+
crypto.getRandomValues(bytes2);
|
|
816
|
+
return (0, import_utils.bytesToHex)(bytes2);
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
// src/cce/cce-response.service.ts
|
|
820
|
+
var import_utils3 = require("@noble/hashes/utils.js");
|
|
821
|
+
var import_crypto2 = require("crypto");
|
|
822
|
+
|
|
823
|
+
// src/cce/cce-crypto.ts
|
|
824
|
+
var import_utils2 = require("@noble/hashes/utils.js");
|
|
825
|
+
var import_sha22 = require("@noble/hashes/sha2.js");
|
|
826
|
+
var import_crypto = require("crypto");
|
|
827
|
+
function aesGcmEncrypt(key, plaintext, aad) {
|
|
828
|
+
if (key.length !== CCE_AES_KEY_BYTES) {
|
|
829
|
+
throw new Error(`AES key must be ${CCE_AES_KEY_BYTES} bytes`);
|
|
830
|
+
}
|
|
831
|
+
const iv = (0, import_crypto.randomBytes)(CCE_IV_BYTES);
|
|
832
|
+
const cipher = (0, import_crypto.createCipheriv)("aes-256-gcm", key, iv);
|
|
833
|
+
if (aad) {
|
|
834
|
+
cipher.setAAD(aad);
|
|
835
|
+
}
|
|
836
|
+
const encrypted = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
837
|
+
const tag = cipher.getAuthTag();
|
|
838
|
+
return {
|
|
839
|
+
iv: new Uint8Array(iv),
|
|
840
|
+
ciphertext: new Uint8Array(encrypted),
|
|
841
|
+
tag: new Uint8Array(tag)
|
|
842
|
+
};
|
|
843
|
+
}
|
|
844
|
+
function aesGcmDecrypt(key, iv, ciphertext, tag, aad) {
|
|
845
|
+
if (key.length !== CCE_AES_KEY_BYTES) {
|
|
846
|
+
throw new Error(`AES key must be ${CCE_AES_KEY_BYTES} bytes`);
|
|
847
|
+
}
|
|
848
|
+
if (iv.length !== CCE_IV_BYTES) {
|
|
849
|
+
throw new Error(`IV must be ${CCE_IV_BYTES} bytes`);
|
|
850
|
+
}
|
|
851
|
+
if (tag.length !== CCE_TAG_BYTES) {
|
|
852
|
+
throw new Error(`Tag must be ${CCE_TAG_BYTES} bytes`);
|
|
853
|
+
}
|
|
854
|
+
try {
|
|
855
|
+
const decipher = (0, import_crypto.createDecipheriv)("aes-256-gcm", key, iv);
|
|
856
|
+
decipher.setAuthTag(tag);
|
|
857
|
+
if (aad) {
|
|
858
|
+
decipher.setAAD(aad);
|
|
859
|
+
}
|
|
860
|
+
const decrypted = Buffer.concat([
|
|
861
|
+
decipher.update(ciphertext),
|
|
862
|
+
decipher.final()
|
|
863
|
+
]);
|
|
864
|
+
return new Uint8Array(decrypted);
|
|
865
|
+
} catch {
|
|
866
|
+
return null;
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
function generateAesKey() {
|
|
870
|
+
return new Uint8Array((0, import_crypto.randomBytes)(CCE_AES_KEY_BYTES));
|
|
871
|
+
}
|
|
872
|
+
function generateIv() {
|
|
873
|
+
return new Uint8Array((0, import_crypto.randomBytes)(CCE_IV_BYTES));
|
|
874
|
+
}
|
|
875
|
+
function base64UrlEncode(bytes2) {
|
|
876
|
+
return Buffer.from(bytes2).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
877
|
+
}
|
|
878
|
+
function base64UrlDecode(input) {
|
|
879
|
+
const base64 = input.replace(/-/g, "+").replace(/_/g, "/");
|
|
880
|
+
const padding = "=".repeat((4 - base64.length % 4) % 4);
|
|
881
|
+
return new Uint8Array(Buffer.from(base64 + padding, "base64"));
|
|
882
|
+
}
|
|
883
|
+
function hashPayload(payload) {
|
|
884
|
+
return (0, import_utils2.bytesToHex)((0, import_sha22.sha256)(payload));
|
|
885
|
+
}
|
|
886
|
+
var nodeAesGcmProvider = {
|
|
887
|
+
async decrypt(key, iv, ciphertext, tag, aad) {
|
|
888
|
+
return aesGcmDecrypt(key, iv, ciphertext, tag, aad);
|
|
889
|
+
}
|
|
890
|
+
};
|
|
891
|
+
|
|
892
|
+
// src/cce/cce-response.service.ts
|
|
893
|
+
async function buildCceResponse(options, clientKeyEncryptor, axisSigner) {
|
|
894
|
+
const { request, capsule, status, body, clientPublicKeyHex, witnessRef } = options;
|
|
895
|
+
const responseNonce = (0, import_utils3.bytesToHex)(
|
|
896
|
+
new Uint8Array((0, import_crypto2.randomBytes)(CCE_NONCE_BYTES))
|
|
897
|
+
);
|
|
898
|
+
const responseId = generateResponseId();
|
|
899
|
+
const aesKey = generateAesKey();
|
|
900
|
+
const aad = buildResponseAad(
|
|
901
|
+
request.request_id,
|
|
902
|
+
responseId,
|
|
903
|
+
request.correlation_id,
|
|
904
|
+
capsule.capsule_id,
|
|
905
|
+
responseNonce
|
|
906
|
+
);
|
|
907
|
+
const { iv, ciphertext, tag } = aesGcmEncrypt(aesKey, body, aad);
|
|
908
|
+
const encryptedKey = await clientKeyEncryptor.wrapKey(
|
|
909
|
+
aesKey,
|
|
910
|
+
request.client_kid,
|
|
911
|
+
clientPublicKeyHex
|
|
912
|
+
);
|
|
913
|
+
aesKey.fill(0);
|
|
914
|
+
const encryptedPayload = {
|
|
915
|
+
alg: "AES-256-GCM",
|
|
916
|
+
iv: base64UrlEncode(iv),
|
|
917
|
+
ciphertext: base64UrlEncode(ciphertext),
|
|
918
|
+
tag: base64UrlEncode(tag)
|
|
919
|
+
};
|
|
920
|
+
const algorithms = {
|
|
921
|
+
kem: encryptedKey.alg,
|
|
922
|
+
enc: "AES-256-GCM",
|
|
923
|
+
kdf: "HKDF-SHA256",
|
|
924
|
+
sig: "EdDSA"
|
|
925
|
+
};
|
|
926
|
+
const unsignedResponse = {
|
|
927
|
+
ver: CCE_PROTOCOL_VERSION,
|
|
928
|
+
response_id: responseId,
|
|
929
|
+
request_id: request.request_id,
|
|
930
|
+
correlation_id: request.correlation_id,
|
|
931
|
+
encrypted_key: encryptedKey,
|
|
932
|
+
encrypted_payload: encryptedPayload,
|
|
933
|
+
response_nonce: responseNonce,
|
|
934
|
+
algorithms,
|
|
935
|
+
status,
|
|
936
|
+
...witnessRef ? { witness_ref: witnessRef } : {}
|
|
937
|
+
};
|
|
938
|
+
const signPayload = new TextEncoder().encode(canonicalize(unsignedResponse));
|
|
939
|
+
const axisSig = await axisSigner.sign(signPayload);
|
|
940
|
+
const envelope = {
|
|
941
|
+
...unsignedResponse,
|
|
942
|
+
axis_sig: axisSig
|
|
943
|
+
};
|
|
944
|
+
return {
|
|
945
|
+
envelope,
|
|
946
|
+
responsePayloadHash: hashPayload(body)
|
|
947
|
+
};
|
|
948
|
+
}
|
|
949
|
+
function buildCceErrorResponse(requestId, correlationId, status, errorCode, message) {
|
|
950
|
+
return {
|
|
951
|
+
ver: CCE_PROTOCOL_VERSION,
|
|
952
|
+
request_id: requestId,
|
|
953
|
+
correlation_id: correlationId,
|
|
954
|
+
status,
|
|
955
|
+
error: { code: errorCode, message }
|
|
956
|
+
};
|
|
957
|
+
}
|
|
958
|
+
function generateResponseId() {
|
|
959
|
+
const bytes2 = (0, import_crypto2.randomBytes)(16);
|
|
960
|
+
return "resp_" + (0, import_utils3.bytesToHex)(new Uint8Array(bytes2)).slice(0, 24);
|
|
961
|
+
}
|
|
962
|
+
function buildResponseAad(requestId, responseId, correlationId, capsuleId, responseNonce) {
|
|
963
|
+
const parts = [
|
|
964
|
+
requestId,
|
|
965
|
+
responseId,
|
|
966
|
+
correlationId,
|
|
967
|
+
capsuleId,
|
|
968
|
+
responseNonce
|
|
969
|
+
];
|
|
970
|
+
return new TextEncoder().encode(parts.join("|"));
|
|
971
|
+
}
|
|
972
|
+
function canonicalize(obj) {
|
|
973
|
+
if (Array.isArray(obj)) {
|
|
974
|
+
return "[" + obj.map(canonicalize).join(",") + "]";
|
|
975
|
+
}
|
|
976
|
+
if (obj !== null && typeof obj === "object") {
|
|
977
|
+
const sorted = Object.keys(obj).sort().map(
|
|
978
|
+
(k) => JSON.stringify(k) + ":" + canonicalize(obj[k])
|
|
979
|
+
);
|
|
980
|
+
return "{" + sorted.join(",") + "}";
|
|
981
|
+
}
|
|
982
|
+
return JSON.stringify(obj);
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
// src/cce/cce-witness.observer.ts
|
|
986
|
+
var import_utils4 = require("@noble/hashes/utils.js");
|
|
987
|
+
var import_hkdf2 = require("@noble/hashes/hkdf.js");
|
|
988
|
+
var import_sha23 = require("@noble/hashes/sha2.js");
|
|
989
|
+
var InMemoryCceWitnessStore = class {
|
|
990
|
+
constructor() {
|
|
991
|
+
this.records = [];
|
|
992
|
+
}
|
|
993
|
+
async record(witness) {
|
|
994
|
+
this.records.push(witness);
|
|
995
|
+
}
|
|
996
|
+
getByRequestId(requestId) {
|
|
997
|
+
return this.records.find((w) => w.request_id === requestId);
|
|
998
|
+
}
|
|
999
|
+
getByCapsuleId(capsuleId) {
|
|
1000
|
+
return this.records.filter((w) => w.capsule_id === capsuleId);
|
|
1001
|
+
}
|
|
1002
|
+
};
|
|
1003
|
+
function buildWitnessRecord(envelope, capsule, verification, execution, options) {
|
|
1004
|
+
const witnessId = generateWitnessId(envelope.request_id, capsule.capsule_id);
|
|
1005
|
+
const executionContextHash = computeExecutionContextHash(
|
|
1006
|
+
options.axisLocalSecret,
|
|
1007
|
+
capsule,
|
|
1008
|
+
envelope.request_nonce
|
|
1009
|
+
);
|
|
1010
|
+
return {
|
|
1011
|
+
witness_id: witnessId,
|
|
1012
|
+
request_id: envelope.request_id,
|
|
1013
|
+
capsule_id: capsule.capsule_id,
|
|
1014
|
+
sub: capsule.sub,
|
|
1015
|
+
intent: capsule.intent,
|
|
1016
|
+
aud: capsule.aud,
|
|
1017
|
+
tps_from: capsule.tps_from,
|
|
1018
|
+
tps_to: capsule.tps_to,
|
|
1019
|
+
timestamp: Math.floor(Date.now() / 1e3),
|
|
1020
|
+
verification: {
|
|
1021
|
+
client_sig: verification.clientSigVerified,
|
|
1022
|
+
capsule_sig: verification.capsuleSigVerified,
|
|
1023
|
+
tps_valid: verification.tpsValid,
|
|
1024
|
+
audience_match: verification.audienceMatch,
|
|
1025
|
+
intent_match: verification.intentMatch,
|
|
1026
|
+
replay_clean: verification.replayClean,
|
|
1027
|
+
nonce_unique: verification.nonceUnique,
|
|
1028
|
+
decryption_ok: verification.decryptionOk
|
|
1029
|
+
},
|
|
1030
|
+
execution: {
|
|
1031
|
+
status: execution.status,
|
|
1032
|
+
handler_duration_ms: execution.handlerDurationMs,
|
|
1033
|
+
...execution.effect ? { effect: execution.effect } : {}
|
|
1034
|
+
},
|
|
1035
|
+
response_encrypted: options.responseEncrypted,
|
|
1036
|
+
execution_context_hash: executionContextHash,
|
|
1037
|
+
...options.requestPayload ? { request_payload_hash: hashPayload(options.requestPayload) } : {},
|
|
1038
|
+
...options.responsePayload ? { response_payload_hash: hashPayload(options.responsePayload) } : {}
|
|
1039
|
+
};
|
|
1040
|
+
}
|
|
1041
|
+
function extractVerificationState(metadata) {
|
|
1042
|
+
return {
|
|
1043
|
+
clientSigVerified: metadata.cceClientSigVerified === true,
|
|
1044
|
+
capsuleSigVerified: metadata.cceCapsuleVerified === true,
|
|
1045
|
+
tpsValid: metadata.cceTpsValid === true,
|
|
1046
|
+
audienceMatch: metadata.cceBindingVerified === true,
|
|
1047
|
+
intentMatch: metadata.cceBindingVerified === true,
|
|
1048
|
+
replayClean: metadata.cceReplayClean === true,
|
|
1049
|
+
nonceUnique: metadata.cceReplayClean === true,
|
|
1050
|
+
decryptionOk: metadata.cceDecryptionOk === true
|
|
1051
|
+
};
|
|
1052
|
+
}
|
|
1053
|
+
function generateWitnessId(requestId, capsuleId) {
|
|
1054
|
+
const input = `witness:${requestId}:${capsuleId}:${Date.now()}`;
|
|
1055
|
+
const hash = (0, import_sha23.sha256)(new TextEncoder().encode(input));
|
|
1056
|
+
return "wit_" + (0, import_utils4.bytesToHex)(hash).slice(0, 24);
|
|
1057
|
+
}
|
|
1058
|
+
function computeExecutionContextHash(axisLocalSecret, capsule, requestNonce) {
|
|
1059
|
+
const encoder = new TextEncoder();
|
|
1060
|
+
const ikm = hexToBytes2(axisLocalSecret);
|
|
1061
|
+
const salt = (0, import_sha23.sha256)(
|
|
1062
|
+
encoder.encode(
|
|
1063
|
+
capsule.capsule_id + "|" + capsule.capsule_nonce + "|" + requestNonce
|
|
1064
|
+
)
|
|
1065
|
+
);
|
|
1066
|
+
const info = encoder.encode(
|
|
1067
|
+
[
|
|
1068
|
+
CCE_DERIVATION.WITNESS,
|
|
1069
|
+
capsule.sub,
|
|
1070
|
+
capsule.kid,
|
|
1071
|
+
capsule.intent,
|
|
1072
|
+
capsule.aud,
|
|
1073
|
+
String(capsule.tps_from),
|
|
1074
|
+
String(capsule.tps_to),
|
|
1075
|
+
capsule.policy_hash ?? "",
|
|
1076
|
+
capsule.ver
|
|
1077
|
+
].join("|")
|
|
1078
|
+
);
|
|
1079
|
+
const witnessKey = (0, import_hkdf2.hkdf)(import_sha23.sha256, ikm, salt, info, 32);
|
|
1080
|
+
const hash = (0, import_utils4.bytesToHex)((0, import_sha23.sha256)(witnessKey));
|
|
1081
|
+
witnessKey.fill(0);
|
|
1082
|
+
return hash;
|
|
1083
|
+
}
|
|
1084
|
+
function hexToBytes2(hex) {
|
|
1085
|
+
const bytes2 = new Uint8Array(hex.length / 2);
|
|
1086
|
+
for (let i = 0; i < bytes2.length; i++) {
|
|
1087
|
+
bytes2[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
1088
|
+
}
|
|
1089
|
+
return bytes2;
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
// src/cce/cce-pipeline.ts
|
|
1093
|
+
async function executeCcePipeline(envelope, config) {
|
|
1094
|
+
const startTime = Date.now();
|
|
1095
|
+
if (envelope.ver !== CCE_PROTOCOL_VERSION) {
|
|
1096
|
+
return {
|
|
1097
|
+
ok: false,
|
|
1098
|
+
error: {
|
|
1099
|
+
code: CCE_ERROR.UNSUPPORTED_VERSION,
|
|
1100
|
+
message: `Unsupported version: ${envelope.ver}`
|
|
1101
|
+
},
|
|
1102
|
+
status: "ERROR"
|
|
1103
|
+
};
|
|
1104
|
+
}
|
|
1105
|
+
const sensorInput = {
|
|
1106
|
+
intent: envelope.capsule.intent,
|
|
1107
|
+
metadata: {
|
|
1108
|
+
cce: true,
|
|
1109
|
+
cceEnvelope: envelope,
|
|
1110
|
+
contentType: "application/axis-cce"
|
|
1111
|
+
}
|
|
1112
|
+
};
|
|
1113
|
+
const sortedSensors = [...config.sensors].sort(
|
|
1114
|
+
(a, b) => (a.order ?? 999) - (b.order ?? 999)
|
|
1115
|
+
);
|
|
1116
|
+
for (const sensor of sortedSensors) {
|
|
1117
|
+
if (sensor.supports && !sensor.supports(sensorInput)) {
|
|
1118
|
+
continue;
|
|
1119
|
+
}
|
|
1120
|
+
let decision;
|
|
1121
|
+
try {
|
|
1122
|
+
decision = await sensor.run(sensorInput);
|
|
1123
|
+
} catch (err) {
|
|
1124
|
+
return {
|
|
1125
|
+
ok: false,
|
|
1126
|
+
error: {
|
|
1127
|
+
code: CCE_ERROR.DECRYPTION_FAILED,
|
|
1128
|
+
message: `Sensor ${sensor.name} failed`
|
|
1129
|
+
},
|
|
1130
|
+
status: "ERROR"
|
|
1131
|
+
};
|
|
1132
|
+
}
|
|
1133
|
+
const normalized = normalizeSensorDecision(decision);
|
|
1134
|
+
if (!normalized.allow) {
|
|
1135
|
+
const code = normalized.reasons[0]?.split(":")[0] ?? CCE_ERROR.DECRYPTION_FAILED;
|
|
1136
|
+
return {
|
|
1137
|
+
ok: false,
|
|
1138
|
+
error: { code, message: normalized.reasons.join("; ") },
|
|
1139
|
+
status: "DENIED"
|
|
1140
|
+
};
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
const capsule = sensorInput.metadata?.cceCapsule;
|
|
1144
|
+
const decryptedPayload = sensorInput.metadata?.cceDecryptedPayload;
|
|
1145
|
+
const clientKey = sensorInput.metadata?.cceClientKey;
|
|
1146
|
+
if (!capsule || !decryptedPayload || !clientKey) {
|
|
1147
|
+
return {
|
|
1148
|
+
ok: false,
|
|
1149
|
+
error: {
|
|
1150
|
+
code: CCE_ERROR.DECRYPTION_FAILED,
|
|
1151
|
+
message: "Sensor chain did not produce required outputs"
|
|
1152
|
+
},
|
|
1153
|
+
status: "ERROR"
|
|
1154
|
+
};
|
|
1155
|
+
}
|
|
1156
|
+
const derivationInput = {
|
|
1157
|
+
axisLocalSecret: config.axisLocalSecret,
|
|
1158
|
+
capsule,
|
|
1159
|
+
requestNonce: envelope.request_nonce
|
|
1160
|
+
};
|
|
1161
|
+
const executionContext = buildExecutionContext(
|
|
1162
|
+
derivationInput,
|
|
1163
|
+
envelope.request_id
|
|
1164
|
+
);
|
|
1165
|
+
const handler = config.handlers.get(capsule.intent);
|
|
1166
|
+
if (!handler) {
|
|
1167
|
+
return {
|
|
1168
|
+
ok: false,
|
|
1169
|
+
error: {
|
|
1170
|
+
code: CCE_ERROR.HANDLER_NOT_FOUND,
|
|
1171
|
+
message: `No handler for intent: ${capsule.intent}`
|
|
1172
|
+
},
|
|
1173
|
+
status: "ERROR"
|
|
1174
|
+
};
|
|
1175
|
+
}
|
|
1176
|
+
const handlerContext = {
|
|
1177
|
+
capsule,
|
|
1178
|
+
executionContext,
|
|
1179
|
+
envelope,
|
|
1180
|
+
clientPublicKeyHex: clientKey.publicKeyHex,
|
|
1181
|
+
intent: capsule.intent,
|
|
1182
|
+
sub: capsule.sub
|
|
1183
|
+
};
|
|
1184
|
+
let result;
|
|
1185
|
+
const handlerStart = Date.now();
|
|
1186
|
+
try {
|
|
1187
|
+
result = await handler(decryptedPayload, handlerContext);
|
|
1188
|
+
} catch (err) {
|
|
1189
|
+
const handlerDuration2 = Date.now() - handlerStart;
|
|
1190
|
+
const verification2 = extractVerificationState(sensorInput.metadata ?? {});
|
|
1191
|
+
const witness2 = buildWitnessRecord(
|
|
1192
|
+
envelope,
|
|
1193
|
+
capsule,
|
|
1194
|
+
verification2,
|
|
1195
|
+
{ status: "FAILED", handlerDurationMs: handlerDuration2 },
|
|
1196
|
+
{
|
|
1197
|
+
axisLocalSecret: config.axisLocalSecret,
|
|
1198
|
+
requestPayload: decryptedPayload,
|
|
1199
|
+
responseEncrypted: false
|
|
1200
|
+
}
|
|
1201
|
+
);
|
|
1202
|
+
await config.witnessStore.record(witness2);
|
|
1203
|
+
return {
|
|
1204
|
+
ok: false,
|
|
1205
|
+
error: {
|
|
1206
|
+
code: CCE_ERROR.HANDLER_EXECUTION_FAILED,
|
|
1207
|
+
message: "Handler execution failed"
|
|
1208
|
+
},
|
|
1209
|
+
status: "FAILED"
|
|
1210
|
+
};
|
|
1211
|
+
}
|
|
1212
|
+
const handlerDuration = Date.now() - handlerStart;
|
|
1213
|
+
let responseEnvelope;
|
|
1214
|
+
let responsePayloadHash;
|
|
1215
|
+
try {
|
|
1216
|
+
const responseResult = await buildCceResponse(
|
|
1217
|
+
{
|
|
1218
|
+
request: envelope,
|
|
1219
|
+
capsule,
|
|
1220
|
+
status: result.status,
|
|
1221
|
+
body: result.body,
|
|
1222
|
+
clientPublicKeyHex: clientKey.publicKeyHex
|
|
1223
|
+
},
|
|
1224
|
+
config.clientKeyEncryptor,
|
|
1225
|
+
config.axisSigner
|
|
1226
|
+
);
|
|
1227
|
+
responseEnvelope = responseResult.envelope;
|
|
1228
|
+
responsePayloadHash = responseResult.responsePayloadHash;
|
|
1229
|
+
} catch (err) {
|
|
1230
|
+
return {
|
|
1231
|
+
ok: false,
|
|
1232
|
+
error: {
|
|
1233
|
+
code: CCE_ERROR.RESPONSE_ENCRYPTION_FAILED,
|
|
1234
|
+
message: "Response encryption failed"
|
|
1235
|
+
},
|
|
1236
|
+
status: "ERROR"
|
|
1237
|
+
};
|
|
1238
|
+
}
|
|
1239
|
+
const verification = extractVerificationState(sensorInput.metadata ?? {});
|
|
1240
|
+
const witness = buildWitnessRecord(
|
|
1241
|
+
envelope,
|
|
1242
|
+
capsule,
|
|
1243
|
+
verification,
|
|
1244
|
+
{
|
|
1245
|
+
status: result.status,
|
|
1246
|
+
handlerDurationMs: handlerDuration,
|
|
1247
|
+
effect: result.effect
|
|
1248
|
+
},
|
|
1249
|
+
{
|
|
1250
|
+
axisLocalSecret: config.axisLocalSecret,
|
|
1251
|
+
requestPayload: decryptedPayload,
|
|
1252
|
+
responsePayload: result.body,
|
|
1253
|
+
responseEncrypted: true
|
|
1254
|
+
}
|
|
1255
|
+
);
|
|
1256
|
+
await config.witnessStore.record(witness);
|
|
1257
|
+
return {
|
|
1258
|
+
ok: true,
|
|
1259
|
+
response: responseEnvelope,
|
|
1260
|
+
witnessId: witness.witness_id
|
|
1261
|
+
};
|
|
1262
|
+
}
|
|
1263
|
+
|
|
639
1264
|
// src/engine/intent.router.ts
|
|
640
1265
|
var IntentRouter = class {
|
|
641
1266
|
constructor(moduleRef) {
|
|
@@ -653,6 +1278,10 @@ var IntentRouter = class {
|
|
|
653
1278
|
this.intentValidators = /* @__PURE__ */ new Map();
|
|
654
1279
|
/** Per-intent operation kind */
|
|
655
1280
|
this.intentKinds = /* @__PURE__ */ new Map();
|
|
1281
|
+
/** CCE handler registry */
|
|
1282
|
+
this.cceHandlers = /* @__PURE__ */ new Map();
|
|
1283
|
+
/** CCE pipeline configuration (set via configureCce) */
|
|
1284
|
+
this.ccePipelineConfig = null;
|
|
656
1285
|
}
|
|
657
1286
|
getSchema(intent) {
|
|
658
1287
|
return this.intentSchemas.get(intent);
|
|
@@ -916,6 +1545,58 @@ var IntentRouter = class {
|
|
|
916
1545
|
}
|
|
917
1546
|
}
|
|
918
1547
|
}
|
|
1548
|
+
// ===========================================================================
|
|
1549
|
+
// CCE — Capsule-Carried Encryption Support
|
|
1550
|
+
// ===========================================================================
|
|
1551
|
+
/**
|
|
1552
|
+
* Configure the CCE pipeline.
|
|
1553
|
+
* Must be called before routeCce() can process encrypted requests.
|
|
1554
|
+
*/
|
|
1555
|
+
configureCce(config) {
|
|
1556
|
+
this.ccePipelineConfig = config;
|
|
1557
|
+
this.logger.log("CCE pipeline configured");
|
|
1558
|
+
}
|
|
1559
|
+
/**
|
|
1560
|
+
* Register a CCE-encrypted intent handler.
|
|
1561
|
+
* CCE handlers receive decrypted payloads and execution context.
|
|
1562
|
+
*/
|
|
1563
|
+
registerCceHandler(intent, handler) {
|
|
1564
|
+
this.cceHandlers.set(intent, handler);
|
|
1565
|
+
this.logger.debug(`CCE handler registered: ${intent}`);
|
|
1566
|
+
}
|
|
1567
|
+
/**
|
|
1568
|
+
* Check if a CCE handler exists for the given intent.
|
|
1569
|
+
*/
|
|
1570
|
+
hasCceHandler(intent) {
|
|
1571
|
+
return this.cceHandlers.has(intent);
|
|
1572
|
+
}
|
|
1573
|
+
/**
|
|
1574
|
+
* Route a CCE-encrypted request through the full pipeline.
|
|
1575
|
+
*
|
|
1576
|
+
* Steps:
|
|
1577
|
+
* 1. Sensor chain (envelope validation → capsule verification → replay → decrypt)
|
|
1578
|
+
* 2. Execution context derivation
|
|
1579
|
+
* 3. Handler execution
|
|
1580
|
+
* 4. Response encryption
|
|
1581
|
+
* 5. Witness recording
|
|
1582
|
+
*/
|
|
1583
|
+
async routeCce(envelope) {
|
|
1584
|
+
if (!this.ccePipelineConfig) {
|
|
1585
|
+
return {
|
|
1586
|
+
ok: false,
|
|
1587
|
+
error: {
|
|
1588
|
+
code: "CCE_NOT_CONFIGURED",
|
|
1589
|
+
message: "CCE pipeline not configured. Call configureCce() first."
|
|
1590
|
+
},
|
|
1591
|
+
status: "ERROR"
|
|
1592
|
+
};
|
|
1593
|
+
}
|
|
1594
|
+
const config = {
|
|
1595
|
+
...this.ccePipelineConfig,
|
|
1596
|
+
handlers: this.cceHandlers
|
|
1597
|
+
};
|
|
1598
|
+
return executeCcePipeline(envelope, config);
|
|
1599
|
+
}
|
|
919
1600
|
storeSchema(meta) {
|
|
920
1601
|
if (meta.dto) {
|
|
921
1602
|
if (meta.tlv && meta.tlv.length > 0) {
|
|
@@ -1095,7 +1776,7 @@ function fieldsToMap(fields) {
|
|
|
1095
1776
|
}
|
|
1096
1777
|
|
|
1097
1778
|
// src/engine/observation/observation-hash.ts
|
|
1098
|
-
var
|
|
1779
|
+
var import_crypto3 = require("crypto");
|
|
1099
1780
|
function canonicalizeObservation(obs) {
|
|
1100
1781
|
const obj = {
|
|
1101
1782
|
id: obs.id,
|
|
@@ -1132,7 +1813,7 @@ function canonicalizeObservation(obs) {
|
|
|
1132
1813
|
}
|
|
1133
1814
|
function hashObservation(obs) {
|
|
1134
1815
|
const canonical = canonicalizeObservation(obs);
|
|
1135
|
-
return (0,
|
|
1816
|
+
return (0, import_crypto3.createHash)("sha256").update(canonical).digest("hex");
|
|
1136
1817
|
}
|
|
1137
1818
|
function buildUnsignedWitness(obs) {
|
|
1138
1819
|
if (!obs.decision || !obs.endMs) {
|
|
@@ -1207,7 +1888,7 @@ function verifyResponse(ctx, response) {
|
|
|
1207
1888
|
var import_axis_protocol3 = require("@nextera.one/axis-protocol");
|
|
1208
1889
|
|
|
1209
1890
|
// src/core/signature.ts
|
|
1210
|
-
var
|
|
1891
|
+
var crypto2 = __toESM(require("crypto"));
|
|
1211
1892
|
|
|
1212
1893
|
// src/core/axis-bin.ts
|
|
1213
1894
|
var z = __toESM(require("zod"));
|
|
@@ -1337,19 +2018,19 @@ function signFrame(frame, privateKey) {
|
|
|
1337
2018
|
32
|
|
1338
2019
|
]);
|
|
1339
2020
|
const pkcs8Key = Buffer.concat([pkcs8Prefix, privateKey]);
|
|
1340
|
-
keyObject =
|
|
2021
|
+
keyObject = crypto2.createPrivateKey({
|
|
1341
2022
|
key: pkcs8Key,
|
|
1342
2023
|
format: "der",
|
|
1343
2024
|
type: "pkcs8"
|
|
1344
2025
|
});
|
|
1345
2026
|
} else {
|
|
1346
|
-
keyObject =
|
|
2027
|
+
keyObject = crypto2.createPrivateKey({
|
|
1347
2028
|
key: privateKey,
|
|
1348
2029
|
format: "der",
|
|
1349
2030
|
type: "pkcs8"
|
|
1350
2031
|
});
|
|
1351
2032
|
}
|
|
1352
|
-
const signature =
|
|
2033
|
+
const signature = crypto2.sign(null, payload, keyObject);
|
|
1353
2034
|
if (signature.length !== 64) {
|
|
1354
2035
|
throw new Error("Ed25519 signature must be 64 bytes");
|
|
1355
2036
|
}
|
|
@@ -1381,19 +2062,19 @@ function verifyFrameSignature(frame, publicKey) {
|
|
|
1381
2062
|
0
|
|
1382
2063
|
]);
|
|
1383
2064
|
const spkiKey = Buffer.concat([spkiPrefix, publicKey]);
|
|
1384
|
-
keyObject =
|
|
2065
|
+
keyObject = crypto2.createPublicKey({
|
|
1385
2066
|
key: spkiKey,
|
|
1386
2067
|
format: "der",
|
|
1387
2068
|
type: "spki"
|
|
1388
2069
|
});
|
|
1389
2070
|
} else {
|
|
1390
|
-
keyObject =
|
|
2071
|
+
keyObject = crypto2.createPublicKey({
|
|
1391
2072
|
key: publicKey,
|
|
1392
2073
|
format: "der",
|
|
1393
2074
|
type: "spki"
|
|
1394
2075
|
});
|
|
1395
2076
|
}
|
|
1396
|
-
const valid =
|
|
2077
|
+
const valid = crypto2.verify(
|
|
1397
2078
|
null,
|
|
1398
2079
|
payload,
|
|
1399
2080
|
keyObject,
|
|
@@ -1405,17 +2086,17 @@ function verifyFrameSignature(frame, publicKey) {
|
|
|
1405
2086
|
}
|
|
1406
2087
|
}
|
|
1407
2088
|
function generateEd25519KeyPair() {
|
|
1408
|
-
const { privateKey, publicKey } =
|
|
2089
|
+
const { privateKey, publicKey } = crypto2.generateKeyPairSync("ed25519");
|
|
1409
2090
|
return {
|
|
1410
2091
|
privateKey: privateKey.export({ type: "pkcs8", format: "der" }),
|
|
1411
2092
|
publicKey: publicKey.export({ type: "spki", format: "der" })
|
|
1412
2093
|
};
|
|
1413
2094
|
}
|
|
1414
|
-
function
|
|
1415
|
-
return
|
|
2095
|
+
function sha2564(data) {
|
|
2096
|
+
return crypto2.createHash("sha256").update(data).digest();
|
|
1416
2097
|
}
|
|
1417
2098
|
function computeReceiptHash(receiptBytes, prevHash) {
|
|
1418
|
-
const hasher =
|
|
2099
|
+
const hasher = crypto2.createHash("sha256");
|
|
1419
2100
|
hasher.update(receiptBytes);
|
|
1420
2101
|
if (prevHash && prevHash.length > 0) {
|
|
1421
2102
|
hasher.update(prevHash);
|
|
@@ -1473,12 +2154,12 @@ __export(ats1_exports, {
|
|
|
1473
2154
|
encodeU64BE: () => encodeU64BE,
|
|
1474
2155
|
encodeUVarint: () => encodeUVarint,
|
|
1475
2156
|
logicalBodyToTLVs: () => logicalBodyToTLVs,
|
|
1476
|
-
sha256: () =>
|
|
2157
|
+
sha256: () => sha2565,
|
|
1477
2158
|
tlvsToLogicalBody: () => tlvsToLogicalBody,
|
|
1478
2159
|
tlvsToMap: () => tlvsToMap,
|
|
1479
2160
|
validateTLVsAgainstSchema: () => validateTLVsAgainstSchema
|
|
1480
2161
|
});
|
|
1481
|
-
var
|
|
2162
|
+
var import_crypto4 = require("crypto");
|
|
1482
2163
|
var DEFAULT_LIMITS = {
|
|
1483
2164
|
maxVarintBytes: 10,
|
|
1484
2165
|
maxTlvCount: 512,
|
|
@@ -1527,8 +2208,8 @@ function decodeU64BE(buf) {
|
|
|
1527
2208
|
if (buf.length !== 8) throw new Error("decodeU64BE: length must be 8");
|
|
1528
2209
|
return buf.readBigUInt64BE(0);
|
|
1529
2210
|
}
|
|
1530
|
-
function
|
|
1531
|
-
return (0,
|
|
2211
|
+
function sha2565(data) {
|
|
2212
|
+
return (0, import_crypto4.createHash)("sha256").update(data).digest();
|
|
1532
2213
|
}
|
|
1533
2214
|
function encodeTLV(tag, value) {
|
|
1534
2215
|
if (!Number.isInteger(tag) || tag <= 0)
|
|
@@ -1844,7 +2525,7 @@ function decodeAxisHeaderFromTLVs(hdrTlvs, limits = DEFAULT_LIMITS) {
|
|
|
1844
2525
|
function encodeAxisRequestBinary(schema, req, limits = DEFAULT_LIMITS) {
|
|
1845
2526
|
const bodyTlvs = logicalBodyToTLVs(schema, req.body, limits);
|
|
1846
2527
|
const bodyBytes = encodeTLVStreamCanonical(bodyTlvs);
|
|
1847
|
-
const bodyHash =
|
|
2528
|
+
const bodyHash = sha2565(bodyBytes);
|
|
1848
2529
|
const hdr = {
|
|
1849
2530
|
...req.hdr,
|
|
1850
2531
|
schemaId: schema.schemaId,
|
|
@@ -1860,7 +2541,7 @@ function decodeAxisRequestBinary(schema, hdrBytes, bodyBytes, limits = DEFAULT_L
|
|
|
1860
2541
|
const hdr = decodeAxisHeaderFromTLVs(hdrTlvs, limits);
|
|
1861
2542
|
if (hdr.schemaId !== schema.schemaId)
|
|
1862
2543
|
throw new Error("decodeAxisRequestBinary: schemaId mismatch");
|
|
1863
|
-
const bh =
|
|
2544
|
+
const bh = sha2565(bodyBytes);
|
|
1864
2545
|
if (!Buffer.from(hdr.bodyHash).equals(bh))
|
|
1865
2546
|
throw new Error("decodeAxisRequestBinary: body_hash mismatch");
|
|
1866
2547
|
const body = tlvsToLogicalBody(schema, bodyTlvs, limits);
|
|
@@ -1933,7 +2614,7 @@ function packPasskeyLoginOptionsReq(params) {
|
|
|
1933
2614
|
}
|
|
1934
2615
|
);
|
|
1935
2616
|
const body = encodeTLVStreamCanonical(bodyTlvs);
|
|
1936
|
-
const bodyHash =
|
|
2617
|
+
const bodyHash = sha2565(body);
|
|
1937
2618
|
const hdr = buildAts1Hdr({
|
|
1938
2619
|
intentId: params.intentId,
|
|
1939
2620
|
schemaId: ATS1_SCHEMA.PASSKEY_LOGIN_OPTIONS_REQ,
|
|
@@ -2002,7 +2683,7 @@ function packPasskeyRegisterOptionsReq(params) {
|
|
|
2002
2683
|
}
|
|
2003
2684
|
);
|
|
2004
2685
|
const body = encodeTLVStreamCanonical(bodyTlvs);
|
|
2005
|
-
const bodyHash =
|
|
2686
|
+
const bodyHash = sha2565(body);
|
|
2006
2687
|
const hdr = buildAts1Hdr({
|
|
2007
2688
|
intentId: params.intentId,
|
|
2008
2689
|
schemaId: ATS1_SCHEMA.PASSKEY_REGISTER_OPTIONS_REQ,
|
|
@@ -2033,7 +2714,7 @@ function packPasskeyLoginVerifyReq(params) {
|
|
|
2033
2714
|
}
|
|
2034
2715
|
});
|
|
2035
2716
|
const body = encodeTLVStreamCanonical(bodyTlvs);
|
|
2036
|
-
const bodyHash =
|
|
2717
|
+
const bodyHash = sha2565(body);
|
|
2037
2718
|
const hdr = buildAts1Hdr({
|
|
2038
2719
|
intentId: params.intentId,
|
|
2039
2720
|
schemaId: ATS1_SCHEMA.PASSKEY_LOGIN_VERIFY_REQ,
|
|
@@ -2117,7 +2798,7 @@ function packPasskeyLoginVerifyRes(params) {
|
|
|
2117
2798
|
}
|
|
2118
2799
|
|
|
2119
2800
|
// src/codec/tlv.encode.ts
|
|
2120
|
-
var
|
|
2801
|
+
var import_crypto5 = require("crypto");
|
|
2121
2802
|
function encVarint(x) {
|
|
2122
2803
|
if (x < 0n) throw new Error("VARINT_NEG");
|
|
2123
2804
|
const out = [];
|
|
@@ -2145,7 +2826,7 @@ function bytes(b) {
|
|
|
2145
2826
|
return Buffer.isBuffer(b) ? b : Buffer.from(b);
|
|
2146
2827
|
}
|
|
2147
2828
|
function nonce16() {
|
|
2148
|
-
return (0,
|
|
2829
|
+
return (0, import_crypto5.randomBytes)(16);
|
|
2149
2830
|
}
|
|
2150
2831
|
function tlv(type, value) {
|
|
2151
2832
|
if (!Number.isSafeInteger(type) || type < 0) throw new Error("TLV_BAD_TYPE");
|
|
@@ -2691,9 +3372,9 @@ function isAdminOpcode(op) {
|
|
|
2691
3372
|
}
|
|
2692
3373
|
|
|
2693
3374
|
// src/core/receipt.ts
|
|
2694
|
-
var
|
|
3375
|
+
var import_crypto6 = require("crypto");
|
|
2695
3376
|
function buildReceiptHash(prevHash, pid, actorId, intent, effect, ts) {
|
|
2696
|
-
const h = (0,
|
|
3377
|
+
const h = (0, import_crypto6.createHash)("sha256");
|
|
2697
3378
|
if (prevHash) h.update(prevHash);
|
|
2698
3379
|
h.update(pid);
|
|
2699
3380
|
h.update(Buffer.from(actorId, "utf8"));
|
|
@@ -2873,7 +3554,7 @@ function isTimestampValid(ts, skewSeconds = 120) {
|
|
|
2873
3554
|
|
|
2874
3555
|
// src/upload/axis-files.handlers.ts
|
|
2875
3556
|
var import_common4 = require("@nestjs/common");
|
|
2876
|
-
var
|
|
3557
|
+
var crypto3 = __toESM(require("crypto"));
|
|
2877
3558
|
|
|
2878
3559
|
// src/upload/upload.tokens.ts
|
|
2879
3560
|
var AXIS_UPLOAD_SESSION_STORE = "AXIS_UPLOAD_SESSION_STORE";
|
|
@@ -2974,7 +3655,7 @@ var AxisFilesFinalizeHandler = class {
|
|
|
2974
3655
|
if (!await this.files.hasTemp(fileId)) {
|
|
2975
3656
|
throw new Error("CHUNKS_NOT_FOUND");
|
|
2976
3657
|
}
|
|
2977
|
-
const hash =
|
|
3658
|
+
const hash = crypto3.createHash("sha256");
|
|
2978
3659
|
const rs = this.files.createTempReadStream(fileId);
|
|
2979
3660
|
for await (const chunk of rs) {
|
|
2980
3661
|
hash.update(chunk);
|
|
@@ -3394,10 +4075,10 @@ SensorRegistry = __decorateClass([
|
|
|
3394
4075
|
], SensorRegistry);
|
|
3395
4076
|
|
|
3396
4077
|
// src/engine/axis-observation.ts
|
|
3397
|
-
var
|
|
4078
|
+
var import_crypto7 = require("crypto");
|
|
3398
4079
|
function createObservation(transport, ip) {
|
|
3399
4080
|
return {
|
|
3400
|
-
id: (0,
|
|
4081
|
+
id: (0, import_crypto7.randomBytes)(16).toString("hex"),
|
|
3401
4082
|
startMs: Date.now(),
|
|
3402
4083
|
transport,
|
|
3403
4084
|
ip,
|
|
@@ -3555,6 +4236,693 @@ AxisSensorChainService = __decorateClass([
|
|
|
3555
4236
|
(0, import_common9.Injectable)()
|
|
3556
4237
|
], AxisSensorChainService);
|
|
3557
4238
|
|
|
4239
|
+
// src/cce/index.ts
|
|
4240
|
+
var cce_exports = {};
|
|
4241
|
+
__export(cce_exports, {
|
|
4242
|
+
CCE_AES_KEY_BYTES: () => CCE_AES_KEY_BYTES,
|
|
4243
|
+
CCE_DERIVATION: () => CCE_DERIVATION,
|
|
4244
|
+
CCE_ERROR: () => CCE_ERROR,
|
|
4245
|
+
CCE_IV_BYTES: () => CCE_IV_BYTES,
|
|
4246
|
+
CCE_NONCE_BYTES: () => CCE_NONCE_BYTES,
|
|
4247
|
+
CCE_PROTOCOL_VERSION: () => CCE_PROTOCOL_VERSION,
|
|
4248
|
+
CCE_TAG_BYTES: () => CCE_TAG_BYTES,
|
|
4249
|
+
CceAudienceIntentBindingSensor: () => CceAudienceIntentBindingSensor,
|
|
4250
|
+
CceCapsuleVerificationSensor: () => CceCapsuleVerificationSensor,
|
|
4251
|
+
CceClientSignatureSensor: () => CceClientSignatureSensor,
|
|
4252
|
+
CceEnvelopeValidationSensor: () => CceEnvelopeValidationSensor,
|
|
4253
|
+
CceError: () => CceError,
|
|
4254
|
+
CcePayloadDecryptionSensor: () => CcePayloadDecryptionSensor,
|
|
4255
|
+
CceReplayProtectionSensor: () => CceReplayProtectionSensor,
|
|
4256
|
+
CceTpsWindowSensor: () => CceTpsWindowSensor,
|
|
4257
|
+
InMemoryCceReplayStore: () => InMemoryCceReplayStore,
|
|
4258
|
+
InMemoryCceWitnessStore: () => InMemoryCceWitnessStore,
|
|
4259
|
+
aesGcmDecrypt: () => aesGcmDecrypt,
|
|
4260
|
+
aesGcmEncrypt: () => aesGcmEncrypt,
|
|
4261
|
+
base64UrlDecode: () => base64UrlDecode,
|
|
4262
|
+
base64UrlEncode: () => base64UrlEncode,
|
|
4263
|
+
buildCceErrorResponse: () => buildCceErrorResponse,
|
|
4264
|
+
buildCceResponse: () => buildCceResponse,
|
|
4265
|
+
buildExecutionContext: () => buildExecutionContext,
|
|
4266
|
+
buildWitnessRecord: () => buildWitnessRecord,
|
|
4267
|
+
deriveRequestExecutionKey: () => deriveRequestExecutionKey,
|
|
4268
|
+
deriveResponseExecutionKey: () => deriveResponseExecutionKey,
|
|
4269
|
+
deriveWitnessKey: () => deriveWitnessKey,
|
|
4270
|
+
executeCcePipeline: () => executeCcePipeline,
|
|
4271
|
+
extractVerificationState: () => extractVerificationState,
|
|
4272
|
+
generateAesKey: () => generateAesKey,
|
|
4273
|
+
generateCceNonce: () => generateCceNonce,
|
|
4274
|
+
generateIv: () => generateIv,
|
|
4275
|
+
hashPayload: () => hashPayload,
|
|
4276
|
+
nodeAesGcmProvider: () => nodeAesGcmProvider
|
|
4277
|
+
});
|
|
4278
|
+
|
|
4279
|
+
// src/cce/sensors/cce-envelope-validation.sensor.ts
|
|
4280
|
+
var REQUIRED_FIELDS = [
|
|
4281
|
+
"ver",
|
|
4282
|
+
"request_id",
|
|
4283
|
+
"correlation_id",
|
|
4284
|
+
"client_kid",
|
|
4285
|
+
"capsule",
|
|
4286
|
+
"encrypted_key",
|
|
4287
|
+
"encrypted_payload",
|
|
4288
|
+
"request_nonce",
|
|
4289
|
+
"client_sig",
|
|
4290
|
+
"algorithms"
|
|
4291
|
+
];
|
|
4292
|
+
var CceEnvelopeValidationSensor = class {
|
|
4293
|
+
constructor() {
|
|
4294
|
+
this.name = "cce.envelope.validation";
|
|
4295
|
+
this.order = 5;
|
|
4296
|
+
this.phase = "PRE_DECODE";
|
|
4297
|
+
}
|
|
4298
|
+
supports(input) {
|
|
4299
|
+
return input.metadata?.cce === true || input.metadata?.contentType === "application/axis-cce";
|
|
4300
|
+
}
|
|
4301
|
+
async run(input) {
|
|
4302
|
+
const envelope = input.metadata?.cceEnvelope;
|
|
4303
|
+
if (!envelope) {
|
|
4304
|
+
return {
|
|
4305
|
+
allow: false,
|
|
4306
|
+
riskScore: 100,
|
|
4307
|
+
reasons: [CCE_ERROR.INVALID_ENVELOPE],
|
|
4308
|
+
code: CCE_ERROR.INVALID_ENVELOPE
|
|
4309
|
+
};
|
|
4310
|
+
}
|
|
4311
|
+
for (const field of REQUIRED_FIELDS) {
|
|
4312
|
+
if (envelope[field] === void 0 || envelope[field] === null) {
|
|
4313
|
+
return {
|
|
4314
|
+
allow: false,
|
|
4315
|
+
riskScore: 100,
|
|
4316
|
+
reasons: [`${CCE_ERROR.INVALID_ENVELOPE}: missing ${field}`],
|
|
4317
|
+
code: CCE_ERROR.INVALID_ENVELOPE
|
|
4318
|
+
};
|
|
4319
|
+
}
|
|
4320
|
+
}
|
|
4321
|
+
if (envelope.ver !== CCE_PROTOCOL_VERSION) {
|
|
4322
|
+
return {
|
|
4323
|
+
allow: false,
|
|
4324
|
+
riskScore: 100,
|
|
4325
|
+
reasons: [`${CCE_ERROR.UNSUPPORTED_VERSION}: ${envelope.ver}`],
|
|
4326
|
+
code: CCE_ERROR.UNSUPPORTED_VERSION
|
|
4327
|
+
};
|
|
4328
|
+
}
|
|
4329
|
+
if (!/^[0-9a-f]+$/i.test(envelope.request_nonce)) {
|
|
4330
|
+
return {
|
|
4331
|
+
allow: false,
|
|
4332
|
+
riskScore: 100,
|
|
4333
|
+
reasons: [
|
|
4334
|
+
`${CCE_ERROR.INVALID_ENVELOPE}: invalid request_nonce format`
|
|
4335
|
+
],
|
|
4336
|
+
code: CCE_ERROR.INVALID_ENVELOPE
|
|
4337
|
+
};
|
|
4338
|
+
}
|
|
4339
|
+
if (envelope.request_nonce.length !== CCE_NONCE_BYTES * 2) {
|
|
4340
|
+
return {
|
|
4341
|
+
allow: false,
|
|
4342
|
+
riskScore: 100,
|
|
4343
|
+
reasons: [`${CCE_ERROR.INVALID_ENVELOPE}: request_nonce wrong length`],
|
|
4344
|
+
code: CCE_ERROR.INVALID_ENVELOPE
|
|
4345
|
+
};
|
|
4346
|
+
}
|
|
4347
|
+
const capsule = envelope.capsule;
|
|
4348
|
+
if (!capsule.capsule_id || !capsule.ver || !capsule.sub || !capsule.kid || !capsule.intent || !capsule.aud || !capsule.issuer_sig) {
|
|
4349
|
+
return {
|
|
4350
|
+
allow: false,
|
|
4351
|
+
riskScore: 100,
|
|
4352
|
+
reasons: [`${CCE_ERROR.MISSING_CAPSULE}: incomplete capsule claims`],
|
|
4353
|
+
code: CCE_ERROR.MISSING_CAPSULE
|
|
4354
|
+
};
|
|
4355
|
+
}
|
|
4356
|
+
if (!envelope.encrypted_key.ciphertext || !envelope.encrypted_key.alg) {
|
|
4357
|
+
return {
|
|
4358
|
+
allow: false,
|
|
4359
|
+
riskScore: 100,
|
|
4360
|
+
reasons: [
|
|
4361
|
+
`${CCE_ERROR.MISSING_ENCRYPTED_KEY}: incomplete encrypted_key`
|
|
4362
|
+
],
|
|
4363
|
+
code: CCE_ERROR.MISSING_ENCRYPTED_KEY
|
|
4364
|
+
};
|
|
4365
|
+
}
|
|
4366
|
+
input.metadata = input.metadata ?? {};
|
|
4367
|
+
input.metadata.cceEnvelopeValid = true;
|
|
4368
|
+
return {
|
|
4369
|
+
decision: "ALLOW" /* ALLOW */,
|
|
4370
|
+
allow: true,
|
|
4371
|
+
riskScore: 0,
|
|
4372
|
+
reasons: []
|
|
4373
|
+
};
|
|
4374
|
+
}
|
|
4375
|
+
};
|
|
4376
|
+
|
|
4377
|
+
// src/cce/sensors/cce-client-signature.sensor.ts
|
|
4378
|
+
var CceClientSignatureSensor = class {
|
|
4379
|
+
constructor(keyResolver, signatureVerifier) {
|
|
4380
|
+
this.keyResolver = keyResolver;
|
|
4381
|
+
this.signatureVerifier = signatureVerifier;
|
|
4382
|
+
this.name = "cce.client.signature";
|
|
4383
|
+
this.order = 45;
|
|
4384
|
+
this.phase = "POST_DECODE";
|
|
4385
|
+
}
|
|
4386
|
+
supports(input) {
|
|
4387
|
+
return input.metadata?.cceEnvelopeValid === true;
|
|
4388
|
+
}
|
|
4389
|
+
async run(input) {
|
|
4390
|
+
const envelope = input.metadata?.cceEnvelope;
|
|
4391
|
+
if (!envelope) {
|
|
4392
|
+
return {
|
|
4393
|
+
allow: false,
|
|
4394
|
+
riskScore: 100,
|
|
4395
|
+
reasons: [CCE_ERROR.INVALID_ENVELOPE],
|
|
4396
|
+
code: CCE_ERROR.INVALID_ENVELOPE
|
|
4397
|
+
};
|
|
4398
|
+
}
|
|
4399
|
+
const keyRecord = await this.keyResolver.resolve(envelope.client_kid);
|
|
4400
|
+
if (!keyRecord) {
|
|
4401
|
+
return {
|
|
4402
|
+
allow: false,
|
|
4403
|
+
riskScore: 100,
|
|
4404
|
+
reasons: [
|
|
4405
|
+
`${CCE_ERROR.CLIENT_KEY_NOT_FOUND}: kid=${envelope.client_kid}`
|
|
4406
|
+
],
|
|
4407
|
+
code: CCE_ERROR.CLIENT_KEY_NOT_FOUND
|
|
4408
|
+
};
|
|
4409
|
+
}
|
|
4410
|
+
const { client_sig, ...signable } = envelope;
|
|
4411
|
+
const canonical = canonicalize2(signable);
|
|
4412
|
+
const message = new TextEncoder().encode(canonical);
|
|
4413
|
+
const valid = await this.signatureVerifier.verify(
|
|
4414
|
+
message,
|
|
4415
|
+
client_sig.value,
|
|
4416
|
+
keyRecord.publicKeyHex,
|
|
4417
|
+
keyRecord.alg
|
|
4418
|
+
);
|
|
4419
|
+
if (!valid) {
|
|
4420
|
+
return {
|
|
4421
|
+
allow: false,
|
|
4422
|
+
riskScore: 100,
|
|
4423
|
+
reasons: [CCE_ERROR.CLIENT_SIG_INVALID],
|
|
4424
|
+
code: CCE_ERROR.CLIENT_SIG_INVALID
|
|
4425
|
+
};
|
|
4426
|
+
}
|
|
4427
|
+
input.metadata = input.metadata ?? {};
|
|
4428
|
+
input.metadata.cceClientKey = keyRecord;
|
|
4429
|
+
input.metadata.cceClientSigVerified = true;
|
|
4430
|
+
return {
|
|
4431
|
+
decision: "ALLOW" /* ALLOW */,
|
|
4432
|
+
allow: true,
|
|
4433
|
+
riskScore: 0,
|
|
4434
|
+
reasons: [],
|
|
4435
|
+
meta: { kid: envelope.client_kid }
|
|
4436
|
+
};
|
|
4437
|
+
}
|
|
4438
|
+
};
|
|
4439
|
+
function canonicalize2(obj) {
|
|
4440
|
+
if (Array.isArray(obj)) {
|
|
4441
|
+
return "[" + obj.map(canonicalize2).join(",") + "]";
|
|
4442
|
+
}
|
|
4443
|
+
if (obj !== null && typeof obj === "object") {
|
|
4444
|
+
const sorted = Object.keys(obj).sort().map(
|
|
4445
|
+
(k) => JSON.stringify(k) + ":" + canonicalize2(obj[k])
|
|
4446
|
+
);
|
|
4447
|
+
return "{" + sorted.join(",") + "}";
|
|
4448
|
+
}
|
|
4449
|
+
return JSON.stringify(obj);
|
|
4450
|
+
}
|
|
4451
|
+
|
|
4452
|
+
// src/cce/sensors/cce-capsule-verification.sensor.ts
|
|
4453
|
+
var import_blake3 = require("@noble/hashes/blake3.js");
|
|
4454
|
+
var import_utils5 = require("@noble/hashes/utils.js");
|
|
4455
|
+
var CceCapsuleVerificationSensor = class {
|
|
4456
|
+
constructor(issuerKeyResolver, capsuleVerifier) {
|
|
4457
|
+
this.issuerKeyResolver = issuerKeyResolver;
|
|
4458
|
+
this.capsuleVerifier = capsuleVerifier;
|
|
4459
|
+
this.name = "cce.capsule.verification";
|
|
4460
|
+
this.order = 50;
|
|
4461
|
+
this.phase = "POST_DECODE";
|
|
4462
|
+
}
|
|
4463
|
+
supports(input) {
|
|
4464
|
+
return input.metadata?.cceEnvelopeValid === true;
|
|
4465
|
+
}
|
|
4466
|
+
async run(input) {
|
|
4467
|
+
const capsule = input.metadata?.cceEnvelope?.capsule;
|
|
4468
|
+
if (!capsule) {
|
|
4469
|
+
return {
|
|
4470
|
+
allow: false,
|
|
4471
|
+
riskScore: 100,
|
|
4472
|
+
reasons: [CCE_ERROR.MISSING_CAPSULE],
|
|
4473
|
+
code: CCE_ERROR.MISSING_CAPSULE
|
|
4474
|
+
};
|
|
4475
|
+
}
|
|
4476
|
+
if (capsule.ver !== CCE_PROTOCOL_VERSION) {
|
|
4477
|
+
return {
|
|
4478
|
+
allow: false,
|
|
4479
|
+
riskScore: 100,
|
|
4480
|
+
reasons: [
|
|
4481
|
+
`${CCE_ERROR.CAPSULE_SIG_INVALID}: wrong version ${capsule.ver}`
|
|
4482
|
+
],
|
|
4483
|
+
code: CCE_ERROR.CAPSULE_SIG_INVALID
|
|
4484
|
+
};
|
|
4485
|
+
}
|
|
4486
|
+
const { capsule_id, issuer_sig, ...claimsBody } = capsule;
|
|
4487
|
+
const expectedId = computeCceCapsuleId(claimsBody);
|
|
4488
|
+
if (capsule_id !== expectedId) {
|
|
4489
|
+
return {
|
|
4490
|
+
allow: false,
|
|
4491
|
+
riskScore: 100,
|
|
4492
|
+
reasons: [`${CCE_ERROR.CAPSULE_SIG_INVALID}: content hash mismatch`],
|
|
4493
|
+
code: CCE_ERROR.CAPSULE_SIG_INVALID
|
|
4494
|
+
};
|
|
4495
|
+
}
|
|
4496
|
+
const issuerKey = await this.issuerKeyResolver.resolve(
|
|
4497
|
+
capsule.issuer_sig.kid
|
|
4498
|
+
);
|
|
4499
|
+
if (!issuerKey) {
|
|
4500
|
+
return {
|
|
4501
|
+
allow: false,
|
|
4502
|
+
riskScore: 100,
|
|
4503
|
+
reasons: [`${CCE_ERROR.CAPSULE_SIG_INVALID}: issuer key not found`],
|
|
4504
|
+
code: CCE_ERROR.CAPSULE_SIG_INVALID
|
|
4505
|
+
};
|
|
4506
|
+
}
|
|
4507
|
+
const { issuer_sig: sig, ...rest } = capsule;
|
|
4508
|
+
const sigValid = await this.capsuleVerifier.verify(
|
|
4509
|
+
rest,
|
|
4510
|
+
sig,
|
|
4511
|
+
issuerKey.publicKeyHex
|
|
4512
|
+
);
|
|
4513
|
+
if (!sigValid) {
|
|
4514
|
+
return {
|
|
4515
|
+
allow: false,
|
|
4516
|
+
riskScore: 100,
|
|
4517
|
+
reasons: [CCE_ERROR.CAPSULE_SIG_INVALID],
|
|
4518
|
+
code: CCE_ERROR.CAPSULE_SIG_INVALID
|
|
4519
|
+
};
|
|
4520
|
+
}
|
|
4521
|
+
const nowSeconds = Math.floor(Date.now() / 1e3);
|
|
4522
|
+
if (capsule.exp < nowSeconds) {
|
|
4523
|
+
return {
|
|
4524
|
+
allow: false,
|
|
4525
|
+
riskScore: 100,
|
|
4526
|
+
reasons: [`${CCE_ERROR.CAPSULE_EXPIRED}: exp=${capsule.exp}`],
|
|
4527
|
+
code: CCE_ERROR.CAPSULE_EXPIRED
|
|
4528
|
+
};
|
|
4529
|
+
}
|
|
4530
|
+
if (capsule.iat > nowSeconds + 5) {
|
|
4531
|
+
return {
|
|
4532
|
+
allow: false,
|
|
4533
|
+
riskScore: 100,
|
|
4534
|
+
reasons: [`${CCE_ERROR.CAPSULE_NOT_YET_VALID}: iat=${capsule.iat}`],
|
|
4535
|
+
code: CCE_ERROR.CAPSULE_NOT_YET_VALID
|
|
4536
|
+
};
|
|
4537
|
+
}
|
|
4538
|
+
input.metadata = input.metadata ?? {};
|
|
4539
|
+
input.metadata.cceCapsuleVerified = true;
|
|
4540
|
+
input.metadata.cceCapsule = capsule;
|
|
4541
|
+
return {
|
|
4542
|
+
decision: "ALLOW" /* ALLOW */,
|
|
4543
|
+
allow: true,
|
|
4544
|
+
riskScore: 0,
|
|
4545
|
+
reasons: [],
|
|
4546
|
+
meta: { capsule_id: capsule.capsule_id }
|
|
4547
|
+
};
|
|
4548
|
+
}
|
|
4549
|
+
};
|
|
4550
|
+
function canonicalize3(obj) {
|
|
4551
|
+
if (Array.isArray(obj)) {
|
|
4552
|
+
return "[" + obj.map(canonicalize3).join(",") + "]";
|
|
4553
|
+
}
|
|
4554
|
+
if (obj !== null && typeof obj === "object") {
|
|
4555
|
+
const sorted = Object.keys(obj).sort().map(
|
|
4556
|
+
(k) => JSON.stringify(k) + ":" + canonicalize3(obj[k])
|
|
4557
|
+
);
|
|
4558
|
+
return "{" + sorted.join(",") + "}";
|
|
4559
|
+
}
|
|
4560
|
+
return JSON.stringify(obj);
|
|
4561
|
+
}
|
|
4562
|
+
function computeCceCapsuleId(claims) {
|
|
4563
|
+
const canonical = canonicalize3(claims);
|
|
4564
|
+
const hash = (0, import_blake3.blake3)(new TextEncoder().encode(canonical));
|
|
4565
|
+
return "cce_b3_" + (0, import_utils5.bytesToHex)(hash).slice(0, 32);
|
|
4566
|
+
}
|
|
4567
|
+
|
|
4568
|
+
// src/cce/sensors/cce-tps-window.sensor.ts
|
|
4569
|
+
var DEFAULT_SKEW_MS = 5e3;
|
|
4570
|
+
var CceTpsWindowSensor = class {
|
|
4571
|
+
constructor(skewMs = DEFAULT_SKEW_MS) {
|
|
4572
|
+
this.skewMs = skewMs;
|
|
4573
|
+
this.name = "cce.tps.window";
|
|
4574
|
+
this.order = 92;
|
|
4575
|
+
this.phase = "POST_DECODE";
|
|
4576
|
+
}
|
|
4577
|
+
supports(input) {
|
|
4578
|
+
return input.metadata?.cceCapsuleVerified === true;
|
|
4579
|
+
}
|
|
4580
|
+
async run(input) {
|
|
4581
|
+
const capsule = input.metadata?.cceCapsule;
|
|
4582
|
+
if (!capsule) {
|
|
4583
|
+
return {
|
|
4584
|
+
allow: false,
|
|
4585
|
+
riskScore: 100,
|
|
4586
|
+
reasons: [CCE_ERROR.MISSING_CAPSULE],
|
|
4587
|
+
code: CCE_ERROR.MISSING_CAPSULE
|
|
4588
|
+
};
|
|
4589
|
+
}
|
|
4590
|
+
const nowMs = Date.now();
|
|
4591
|
+
if (nowMs > capsule.tps_to + this.skewMs) {
|
|
4592
|
+
return {
|
|
4593
|
+
allow: false,
|
|
4594
|
+
riskScore: 100,
|
|
4595
|
+
reasons: [
|
|
4596
|
+
`${CCE_ERROR.TPS_WINDOW_EXPIRED}: window ended at ${capsule.tps_to}, now=${nowMs}`
|
|
4597
|
+
],
|
|
4598
|
+
code: CCE_ERROR.TPS_WINDOW_EXPIRED
|
|
4599
|
+
};
|
|
4600
|
+
}
|
|
4601
|
+
if (nowMs < capsule.tps_from - this.skewMs) {
|
|
4602
|
+
return {
|
|
4603
|
+
allow: false,
|
|
4604
|
+
riskScore: 100,
|
|
4605
|
+
reasons: [
|
|
4606
|
+
`${CCE_ERROR.TPS_WINDOW_FUTURE}: window starts at ${capsule.tps_from}, now=${nowMs}`
|
|
4607
|
+
],
|
|
4608
|
+
code: CCE_ERROR.TPS_WINDOW_FUTURE
|
|
4609
|
+
};
|
|
4610
|
+
}
|
|
4611
|
+
input.metadata = input.metadata ?? {};
|
|
4612
|
+
input.metadata.cceTpsValid = true;
|
|
4613
|
+
return {
|
|
4614
|
+
decision: "ALLOW" /* ALLOW */,
|
|
4615
|
+
allow: true,
|
|
4616
|
+
riskScore: 0,
|
|
4617
|
+
reasons: []
|
|
4618
|
+
};
|
|
4619
|
+
}
|
|
4620
|
+
};
|
|
4621
|
+
|
|
4622
|
+
// src/cce/sensors/cce-audience-intent-binding.sensor.ts
|
|
4623
|
+
var CceAudienceIntentBindingSensor = class {
|
|
4624
|
+
constructor(axisAudience) {
|
|
4625
|
+
this.axisAudience = axisAudience;
|
|
4626
|
+
this.name = "cce.audience.intent.binding";
|
|
4627
|
+
this.order = 95;
|
|
4628
|
+
this.phase = "POST_DECODE";
|
|
4629
|
+
}
|
|
4630
|
+
supports(input) {
|
|
4631
|
+
return input.metadata?.cceCapsuleVerified === true;
|
|
4632
|
+
}
|
|
4633
|
+
async run(input) {
|
|
4634
|
+
const capsule = input.metadata?.cceCapsule;
|
|
4635
|
+
const envelope = input.metadata?.cceEnvelope;
|
|
4636
|
+
if (!capsule || !envelope) {
|
|
4637
|
+
return {
|
|
4638
|
+
allow: false,
|
|
4639
|
+
riskScore: 100,
|
|
4640
|
+
reasons: [CCE_ERROR.MISSING_CAPSULE],
|
|
4641
|
+
code: CCE_ERROR.MISSING_CAPSULE
|
|
4642
|
+
};
|
|
4643
|
+
}
|
|
4644
|
+
if (capsule.aud !== this.axisAudience) {
|
|
4645
|
+
return {
|
|
4646
|
+
allow: false,
|
|
4647
|
+
riskScore: 100,
|
|
4648
|
+
reasons: [
|
|
4649
|
+
`${CCE_ERROR.AUDIENCE_MISMATCH}: capsule.aud=${capsule.aud}, expected=${this.axisAudience}`
|
|
4650
|
+
],
|
|
4651
|
+
code: CCE_ERROR.AUDIENCE_MISMATCH
|
|
4652
|
+
};
|
|
4653
|
+
}
|
|
4654
|
+
const requestIntent = input.intent ?? input.metadata?.cceRequestIntent;
|
|
4655
|
+
if (requestIntent && capsule.intent !== requestIntent) {
|
|
4656
|
+
return {
|
|
4657
|
+
allow: false,
|
|
4658
|
+
riskScore: 100,
|
|
4659
|
+
reasons: [
|
|
4660
|
+
`${CCE_ERROR.INTENT_MISMATCH}: capsule.intent=${capsule.intent}, request=${requestIntent}`
|
|
4661
|
+
],
|
|
4662
|
+
code: CCE_ERROR.INTENT_MISMATCH
|
|
4663
|
+
};
|
|
4664
|
+
}
|
|
4665
|
+
if (envelope.client_kid !== capsule.kid) {
|
|
4666
|
+
return {
|
|
4667
|
+
allow: false,
|
|
4668
|
+
riskScore: 100,
|
|
4669
|
+
reasons: [
|
|
4670
|
+
`${CCE_ERROR.INTENT_MISMATCH}: envelope.kid=${envelope.client_kid}, capsule.kid=${capsule.kid}`
|
|
4671
|
+
],
|
|
4672
|
+
code: CCE_ERROR.INTENT_MISMATCH
|
|
4673
|
+
};
|
|
4674
|
+
}
|
|
4675
|
+
input.metadata = input.metadata ?? {};
|
|
4676
|
+
input.metadata.cceBindingVerified = true;
|
|
4677
|
+
return {
|
|
4678
|
+
decision: "ALLOW" /* ALLOW */,
|
|
4679
|
+
allow: true,
|
|
4680
|
+
riskScore: 0,
|
|
4681
|
+
reasons: []
|
|
4682
|
+
};
|
|
4683
|
+
}
|
|
4684
|
+
};
|
|
4685
|
+
|
|
4686
|
+
// src/cce/sensors/cce-replay-protection.sensor.ts
|
|
4687
|
+
var InMemoryCceReplayStore = class {
|
|
4688
|
+
constructor() {
|
|
4689
|
+
this.nonces = /* @__PURE__ */ new Map();
|
|
4690
|
+
this.consumed = /* @__PURE__ */ new Set();
|
|
4691
|
+
this.revoked = /* @__PURE__ */ new Set();
|
|
4692
|
+
}
|
|
4693
|
+
async checkAndMark(key, ttlMs) {
|
|
4694
|
+
this.cleanup();
|
|
4695
|
+
if (this.nonces.has(key)) return false;
|
|
4696
|
+
this.nonces.set(key, Date.now() + ttlMs);
|
|
4697
|
+
return true;
|
|
4698
|
+
}
|
|
4699
|
+
async isCapsuleConsumed(capsuleId) {
|
|
4700
|
+
return this.consumed.has(capsuleId);
|
|
4701
|
+
}
|
|
4702
|
+
async markCapsuleConsumed(capsuleId, _ttlMs) {
|
|
4703
|
+
this.consumed.add(capsuleId);
|
|
4704
|
+
}
|
|
4705
|
+
async isCapsuleRevoked(capsuleId) {
|
|
4706
|
+
return this.revoked.has(capsuleId);
|
|
4707
|
+
}
|
|
4708
|
+
/** Revoke a capsule (for testing/admin) */
|
|
4709
|
+
revoke(capsuleId) {
|
|
4710
|
+
this.revoked.add(capsuleId);
|
|
4711
|
+
}
|
|
4712
|
+
cleanup() {
|
|
4713
|
+
const now = Date.now();
|
|
4714
|
+
for (const [key, expiresAt] of this.nonces) {
|
|
4715
|
+
if (expiresAt < now) this.nonces.delete(key);
|
|
4716
|
+
}
|
|
4717
|
+
}
|
|
4718
|
+
};
|
|
4719
|
+
var CceReplayProtectionSensor = class {
|
|
4720
|
+
constructor(replayStore, options) {
|
|
4721
|
+
this.replayStore = replayStore;
|
|
4722
|
+
this.name = "cce.replay.protection";
|
|
4723
|
+
this.order = 98;
|
|
4724
|
+
this.phase = "POST_DECODE";
|
|
4725
|
+
this.nonceTtlMs = options?.nonceTtlMs ?? 5 * 60 * 1e3;
|
|
4726
|
+
}
|
|
4727
|
+
supports(input) {
|
|
4728
|
+
return input.metadata?.cceCapsuleVerified === true;
|
|
4729
|
+
}
|
|
4730
|
+
async run(input) {
|
|
4731
|
+
const capsule = input.metadata?.cceCapsule;
|
|
4732
|
+
const envelope = input.metadata?.cceEnvelope;
|
|
4733
|
+
if (!capsule || !envelope) {
|
|
4734
|
+
return {
|
|
4735
|
+
allow: false,
|
|
4736
|
+
riskScore: 100,
|
|
4737
|
+
reasons: [CCE_ERROR.MISSING_CAPSULE],
|
|
4738
|
+
code: CCE_ERROR.MISSING_CAPSULE
|
|
4739
|
+
};
|
|
4740
|
+
}
|
|
4741
|
+
const revoked = await this.replayStore.isCapsuleRevoked(capsule.capsule_id);
|
|
4742
|
+
if (revoked) {
|
|
4743
|
+
return {
|
|
4744
|
+
allow: false,
|
|
4745
|
+
riskScore: 100,
|
|
4746
|
+
reasons: [`${CCE_ERROR.CAPSULE_REVOKED}: ${capsule.capsule_id}`],
|
|
4747
|
+
code: CCE_ERROR.CAPSULE_REVOKED
|
|
4748
|
+
};
|
|
4749
|
+
}
|
|
4750
|
+
if (capsule.mode === "SINGLE_USE") {
|
|
4751
|
+
const consumed = await this.replayStore.isCapsuleConsumed(
|
|
4752
|
+
capsule.capsule_id
|
|
4753
|
+
);
|
|
4754
|
+
if (consumed) {
|
|
4755
|
+
return {
|
|
4756
|
+
allow: false,
|
|
4757
|
+
riskScore: 100,
|
|
4758
|
+
reasons: [`${CCE_ERROR.CAPSULE_CONSUMED}: ${capsule.capsule_id}`],
|
|
4759
|
+
code: CCE_ERROR.CAPSULE_CONSUMED
|
|
4760
|
+
};
|
|
4761
|
+
}
|
|
4762
|
+
}
|
|
4763
|
+
const nonceKey = `cce:nonce:${capsule.sub}:${capsule.aud}:${capsule.intent}:${envelope.request_nonce}`;
|
|
4764
|
+
const nonceValid = await this.replayStore.checkAndMark(
|
|
4765
|
+
nonceKey,
|
|
4766
|
+
this.nonceTtlMs
|
|
4767
|
+
);
|
|
4768
|
+
if (!nonceValid) {
|
|
4769
|
+
return {
|
|
4770
|
+
allow: false,
|
|
4771
|
+
riskScore: 100,
|
|
4772
|
+
reasons: [
|
|
4773
|
+
`${CCE_ERROR.NONCE_REUSED}: ${envelope.request_nonce.slice(0, 16)}...`
|
|
4774
|
+
],
|
|
4775
|
+
code: CCE_ERROR.NONCE_REUSED
|
|
4776
|
+
};
|
|
4777
|
+
}
|
|
4778
|
+
if (capsule.mode === "SINGLE_USE") {
|
|
4779
|
+
const capsuleTtl = (capsule.exp - capsule.iat) * 1e3 + 6e4;
|
|
4780
|
+
await this.replayStore.markCapsuleConsumed(
|
|
4781
|
+
capsule.capsule_id,
|
|
4782
|
+
capsuleTtl
|
|
4783
|
+
);
|
|
4784
|
+
}
|
|
4785
|
+
input.metadata = input.metadata ?? {};
|
|
4786
|
+
input.metadata.cceReplayClean = true;
|
|
4787
|
+
return {
|
|
4788
|
+
decision: "ALLOW" /* ALLOW */,
|
|
4789
|
+
allow: true,
|
|
4790
|
+
riskScore: 0,
|
|
4791
|
+
reasons: []
|
|
4792
|
+
};
|
|
4793
|
+
}
|
|
4794
|
+
};
|
|
4795
|
+
|
|
4796
|
+
// src/cce/sensors/cce-payload-decryption.sensor.ts
|
|
4797
|
+
var CcePayloadDecryptionSensor = class {
|
|
4798
|
+
constructor(keyProvider, aesProvider, maxPayloadBytes = 64 * 1024) {
|
|
4799
|
+
this.keyProvider = keyProvider;
|
|
4800
|
+
this.aesProvider = aesProvider;
|
|
4801
|
+
this.maxPayloadBytes = maxPayloadBytes;
|
|
4802
|
+
this.name = "cce.payload.decryption";
|
|
4803
|
+
this.order = 145;
|
|
4804
|
+
this.phase = "POST_DECODE";
|
|
4805
|
+
}
|
|
4806
|
+
supports(input) {
|
|
4807
|
+
return input.metadata?.cceEnvelopeValid === true && input.metadata?.cceClientSigVerified === true && input.metadata?.cceCapsuleVerified === true && input.metadata?.cceReplayClean === true;
|
|
4808
|
+
}
|
|
4809
|
+
async run(input) {
|
|
4810
|
+
const envelope = input.metadata?.cceEnvelope;
|
|
4811
|
+
if (!envelope) {
|
|
4812
|
+
return {
|
|
4813
|
+
allow: false,
|
|
4814
|
+
riskScore: 100,
|
|
4815
|
+
reasons: [CCE_ERROR.INVALID_ENVELOPE],
|
|
4816
|
+
code: CCE_ERROR.INVALID_ENVELOPE
|
|
4817
|
+
};
|
|
4818
|
+
}
|
|
4819
|
+
let aesKey;
|
|
4820
|
+
try {
|
|
4821
|
+
aesKey = await this.keyProvider.unwrapKey(
|
|
4822
|
+
envelope.encrypted_key.ciphertext,
|
|
4823
|
+
envelope.encrypted_key.alg,
|
|
4824
|
+
envelope.encrypted_key.axis_kid,
|
|
4825
|
+
envelope.encrypted_key.ephemeral_pk
|
|
4826
|
+
);
|
|
4827
|
+
} catch {
|
|
4828
|
+
return {
|
|
4829
|
+
allow: false,
|
|
4830
|
+
riskScore: 100,
|
|
4831
|
+
reasons: [CCE_ERROR.KEY_UNWRAP_FAILED],
|
|
4832
|
+
code: CCE_ERROR.KEY_UNWRAP_FAILED
|
|
4833
|
+
};
|
|
4834
|
+
}
|
|
4835
|
+
if (!aesKey) {
|
|
4836
|
+
return {
|
|
4837
|
+
allow: false,
|
|
4838
|
+
riskScore: 100,
|
|
4839
|
+
reasons: [CCE_ERROR.KEY_UNWRAP_FAILED],
|
|
4840
|
+
code: CCE_ERROR.KEY_UNWRAP_FAILED
|
|
4841
|
+
};
|
|
4842
|
+
}
|
|
4843
|
+
let iv;
|
|
4844
|
+
let ciphertext;
|
|
4845
|
+
let tag;
|
|
4846
|
+
try {
|
|
4847
|
+
iv = base64UrlDecode2(envelope.encrypted_payload.iv);
|
|
4848
|
+
ciphertext = base64UrlDecode2(envelope.encrypted_payload.ciphertext);
|
|
4849
|
+
tag = base64UrlDecode2(envelope.encrypted_payload.tag);
|
|
4850
|
+
} catch {
|
|
4851
|
+
return {
|
|
4852
|
+
allow: false,
|
|
4853
|
+
riskScore: 100,
|
|
4854
|
+
reasons: [`${CCE_ERROR.DECRYPTION_FAILED}: invalid base64url encoding`],
|
|
4855
|
+
code: CCE_ERROR.DECRYPTION_FAILED
|
|
4856
|
+
};
|
|
4857
|
+
}
|
|
4858
|
+
if (ciphertext.length > this.maxPayloadBytes) {
|
|
4859
|
+
return {
|
|
4860
|
+
allow: false,
|
|
4861
|
+
riskScore: 100,
|
|
4862
|
+
reasons: [
|
|
4863
|
+
`${CCE_ERROR.PAYLOAD_TOO_LARGE}: ${ciphertext.length} > ${this.maxPayloadBytes}`
|
|
4864
|
+
],
|
|
4865
|
+
code: CCE_ERROR.PAYLOAD_TOO_LARGE
|
|
4866
|
+
};
|
|
4867
|
+
}
|
|
4868
|
+
const aad = buildAad(envelope);
|
|
4869
|
+
let plaintext;
|
|
4870
|
+
try {
|
|
4871
|
+
plaintext = await this.aesProvider.decrypt(
|
|
4872
|
+
aesKey,
|
|
4873
|
+
iv,
|
|
4874
|
+
ciphertext,
|
|
4875
|
+
tag,
|
|
4876
|
+
aad
|
|
4877
|
+
);
|
|
4878
|
+
} catch {
|
|
4879
|
+
plaintext = null;
|
|
4880
|
+
} finally {
|
|
4881
|
+
aesKey.fill(0);
|
|
4882
|
+
}
|
|
4883
|
+
if (!plaintext) {
|
|
4884
|
+
return {
|
|
4885
|
+
allow: false,
|
|
4886
|
+
riskScore: 100,
|
|
4887
|
+
reasons: [CCE_ERROR.AEAD_TAG_MISMATCH],
|
|
4888
|
+
code: CCE_ERROR.AEAD_TAG_MISMATCH
|
|
4889
|
+
};
|
|
4890
|
+
}
|
|
4891
|
+
input.metadata = input.metadata ?? {};
|
|
4892
|
+
input.metadata.cceDecryptedPayload = plaintext;
|
|
4893
|
+
input.metadata.cceDecryptionOk = true;
|
|
4894
|
+
return {
|
|
4895
|
+
decision: "ALLOW" /* ALLOW */,
|
|
4896
|
+
allow: true,
|
|
4897
|
+
riskScore: 0,
|
|
4898
|
+
reasons: []
|
|
4899
|
+
};
|
|
4900
|
+
}
|
|
4901
|
+
};
|
|
4902
|
+
function buildAad(envelope) {
|
|
4903
|
+
const parts = [
|
|
4904
|
+
envelope.ver,
|
|
4905
|
+
envelope.request_id,
|
|
4906
|
+
envelope.correlation_id,
|
|
4907
|
+
envelope.client_kid,
|
|
4908
|
+
envelope.capsule.capsule_id,
|
|
4909
|
+
envelope.capsule.intent,
|
|
4910
|
+
envelope.capsule.aud,
|
|
4911
|
+
envelope.request_nonce
|
|
4912
|
+
];
|
|
4913
|
+
return new TextEncoder().encode(parts.join("|"));
|
|
4914
|
+
}
|
|
4915
|
+
function base64UrlDecode2(input) {
|
|
4916
|
+
const base64 = input.replace(/-/g, "+").replace(/_/g, "/");
|
|
4917
|
+
const padding = "=".repeat((4 - base64.length % 4) % 4);
|
|
4918
|
+
const binary = atob(base64 + padding);
|
|
4919
|
+
const bytes2 = new Uint8Array(binary.length);
|
|
4920
|
+
for (let i = 0; i < binary.length; i++) {
|
|
4921
|
+
bytes2[i] = binary.charCodeAt(i);
|
|
4922
|
+
}
|
|
4923
|
+
return bytes2;
|
|
4924
|
+
}
|
|
4925
|
+
|
|
3558
4926
|
// src/core/index.ts
|
|
3559
4927
|
var core_exports = {};
|
|
3560
4928
|
__export(core_exports, {
|
|
@@ -3636,7 +5004,7 @@ __export(core_exports, {
|
|
|
3636
5004
|
encodeVarint: () => import_axis_protocol3.encodeVarint,
|
|
3637
5005
|
generateEd25519KeyPair: () => generateEd25519KeyPair,
|
|
3638
5006
|
getSignTarget: () => getSignTarget,
|
|
3639
|
-
sha256: () =>
|
|
5007
|
+
sha256: () => sha2564,
|
|
3640
5008
|
signFrame: () => signFrame,
|
|
3641
5009
|
varintLength: () => import_axis_protocol3.varintLength,
|
|
3642
5010
|
verifyFrameSignature: () => verifyFrameSignature
|
|
@@ -3656,7 +5024,7 @@ __export(crypto_exports, {
|
|
|
3656
5024
|
|
|
3657
5025
|
// src/crypto/proof-verification.service.ts
|
|
3658
5026
|
var import_common10 = require("@nestjs/common");
|
|
3659
|
-
var
|
|
5027
|
+
var crypto4 = __toESM(require("crypto"));
|
|
3660
5028
|
var nacl = __toESM(require("tweetnacl"));
|
|
3661
5029
|
var ProofVerificationService = class {
|
|
3662
5030
|
constructor() {
|
|
@@ -3868,7 +5236,7 @@ var ProofVerificationService = class {
|
|
|
3868
5236
|
certPem.replace(/-----BEGIN CERTIFICATE-----/, "").replace(/-----END CERTIFICATE-----/, "").replace(/\s/g, ""),
|
|
3869
5237
|
"base64"
|
|
3870
5238
|
);
|
|
3871
|
-
return
|
|
5239
|
+
return crypto4.createHash("sha256").update(der).digest("hex");
|
|
3872
5240
|
}
|
|
3873
5241
|
};
|
|
3874
5242
|
ProofVerificationService = __decorateClass([
|
|
@@ -4681,7 +6049,7 @@ CapabilityEnforcementSensor = __decorateClass([
|
|
|
4681
6049
|
|
|
4682
6050
|
// src/sensors/chunk-hash.sensor.ts
|
|
4683
6051
|
var import_common15 = require("@nestjs/common");
|
|
4684
|
-
var
|
|
6052
|
+
var import_crypto8 = require("crypto");
|
|
4685
6053
|
var ChunkHashSensor = class {
|
|
4686
6054
|
constructor() {
|
|
4687
6055
|
/** Sensor identifier */
|
|
@@ -4740,7 +6108,7 @@ var ChunkHashSensor = class {
|
|
|
4740
6108
|
reason: "Missing sha256Chunk TLV in header"
|
|
4741
6109
|
};
|
|
4742
6110
|
}
|
|
4743
|
-
const actual = (0,
|
|
6111
|
+
const actual = (0, import_crypto8.createHash)("sha256").update(bodyBytes).digest();
|
|
4744
6112
|
if (!Buffer.from(actual).equals(Buffer.from(expected))) {
|
|
4745
6113
|
return {
|
|
4746
6114
|
action: "DENY",
|
|
@@ -4758,7 +6126,7 @@ ChunkHashSensor = __decorateClass([
|
|
|
4758
6126
|
|
|
4759
6127
|
// src/sensors/entropy.sensor.ts
|
|
4760
6128
|
var import_common16 = require("@nestjs/common");
|
|
4761
|
-
var
|
|
6129
|
+
var crypto5 = __toESM(require("crypto"));
|
|
4762
6130
|
var EntropySensor = class {
|
|
4763
6131
|
constructor() {
|
|
4764
6132
|
this.logger = new import_common16.Logger(EntropySensor.name);
|
|
@@ -4926,7 +6294,7 @@ var EntropySensor = class {
|
|
|
4926
6294
|
* @returns {Uint8Array} Cryptographically secure random bytes
|
|
4927
6295
|
*/
|
|
4928
6296
|
static generateSecureRandom(length) {
|
|
4929
|
-
return new Uint8Array(
|
|
6297
|
+
return new Uint8Array(crypto5.randomBytes(length));
|
|
4930
6298
|
}
|
|
4931
6299
|
};
|
|
4932
6300
|
EntropySensor = __decorateClass([
|
|
@@ -6070,6 +7438,9 @@ function toBuffer(value) {
|
|
|
6070
7438
|
BAND,
|
|
6071
7439
|
BodyProfile,
|
|
6072
7440
|
CAPABILITIES,
|
|
7441
|
+
CCE_ERROR,
|
|
7442
|
+
CCE_PROTOCOL_VERSION,
|
|
7443
|
+
CceError,
|
|
6073
7444
|
ContractViolationError,
|
|
6074
7445
|
DEFAULT_CONTRACTS,
|
|
6075
7446
|
DEFAULT_TIMEOUT,
|
|
@@ -6196,6 +7567,7 @@ function toBuffer(value) {
|
|
|
6196
7567
|
canonicalJson,
|
|
6197
7568
|
canonicalJsonExcluding,
|
|
6198
7569
|
canonicalizeObservation,
|
|
7570
|
+
cce,
|
|
6199
7571
|
classifyIntent,
|
|
6200
7572
|
computeReceiptHash,
|
|
6201
7573
|
computeSignaturePayload,
|
|
@@ -6219,6 +7591,7 @@ function toBuffer(value) {
|
|
|
6219
7591
|
encodeVarint,
|
|
6220
7592
|
endStage,
|
|
6221
7593
|
engine,
|
|
7594
|
+
executeCcePipeline,
|
|
6222
7595
|
extractDtoSchema,
|
|
6223
7596
|
finalizeObservation,
|
|
6224
7597
|
generateEd25519KeyPair,
|