@byok-sdk/core 0.30.0 → 0.30.2
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.
|
@@ -10,11 +10,13 @@
|
|
|
10
10
|
export { SEALED_CATEGORIES, SEALED_CONTENT_SUITE, SEALED_CONTENT_VERSION, SEALED_DIRECTIONS, SealedContentHeaderV1Schema, openSealedContent, sealContent, } from './sealed-content';
|
|
11
11
|
export type { OpenSealedContentInput, SealContentInput, SealedBinding, SealedCategory, SealedContent, SealedContentHeaderV1, SealedContentOpenFailure, SealedContentOpenResult, SealedDirection, SealedScopePolicy, } from './sealed-content';
|
|
12
12
|
export { deriveScopeKeyId, generateScopeKey, openScopeKeyPackage, sealScopeKeyPackage } from './scope-key';
|
|
13
|
-
export type { OpenScopeKeyPackageInput, ScopeKeyPackageOpenResult, ScopeKeyPackageV1, SealScopeKeyPackageInput, } from './scope-key';
|
|
13
|
+
export type { OpenScopeKeyPackageInput, ScopeKeyPackage, ScopeKeyPackageOpenResult, ScopeKeyPackageV1, ScopeKeyPackageV2, SealScopeKeyPackageInput, } from './scope-key';
|
|
14
14
|
export { MEMBER_CHAIN_OPS, deriveMemberId, memberChainEntryHash, signMemberChainEntry, verifyMemberChainEntry, } from './member-chain';
|
|
15
15
|
export type { MemberChainEntryV1, MemberChainEntryVerifyResult, MemberChainOp, UnsignedMemberChainEntryV1, } from './member-chain';
|
|
16
16
|
export { MEMBER_KEY_BUNDLE_VERSION, createMemberKeyBundle, parseMemberKeyBundle, verifyMemberKem } from './member-bundle';
|
|
17
17
|
export type { CreateMemberKeyBundleInput, MemberKeyBundleV1 } from './member-bundle';
|
|
18
|
+
export { beginMemberKemRotation, finishMemberKemRotation, generateMemberKeyRecord, openMemberKeyRecord, } from './member-key-record';
|
|
19
|
+
export type { MemberKemKey, MemberKeyBinding, MemberKeyStore, MemberKeys } from './member-key-record';
|
|
18
20
|
export { MEMBER_FINGERPRINT_DOMAIN, memberApprovalCode, memberFingerprint } from './member-fingerprint';
|
|
19
21
|
export type { MemberFingerprintInput } from './member-fingerprint';
|
|
20
22
|
export { CLIENT_PAIRING_MAC_DOMAIN, DEVICE_PAIRING_MAC_DOMAIN, PAIRING_VERIFICATION_SECRET_BYTES, computeClientPairingMac, computeDevicePairingMac, decodePairingVerificationSecret, encodePairingVerificationSecret, formatPairingInput, generatePairingVerificationSecret, parsePairingInput, verifyClientPairingMac, verifyDevicePairingMac, } from './pairing-verification';
|
|
@@ -679,6 +679,87 @@ async function verifyMemberChainEntry(entry, signerPublicJwk) {
|
|
|
679
679
|
}
|
|
680
680
|
return { ok: true, entry: parsed.data, hash: `sha256:${hex(await sha256(input))}` };
|
|
681
681
|
}
|
|
682
|
+
var MEMBER_KEY_BUNDLE_VERSION = 1;
|
|
683
|
+
var MEMBER_KEM_DOMAIN_PREFIX = "byok-member-kem-v1\n";
|
|
684
|
+
var KemEpochSchema = z.number().int().positive().max(Number.MAX_SAFE_INTEGER);
|
|
685
|
+
var KemSigSchema = base64UrlBytes(64);
|
|
686
|
+
var MemberKeyBundleV1Schema = z.strictObject({
|
|
687
|
+
v: z.literal(MEMBER_KEY_BUNDLE_VERSION),
|
|
688
|
+
memberId: z.string().regex(MEMBER_ID_PATTERN),
|
|
689
|
+
signingPublicJwk: P256PublicJwkSchema,
|
|
690
|
+
kemPublicJwk: P256PublicJwkSchema,
|
|
691
|
+
kemEpoch: KemEpochSchema,
|
|
692
|
+
kemSig: KemSigSchema,
|
|
693
|
+
deviceId: z.string().min(1).optional()
|
|
694
|
+
});
|
|
695
|
+
var CreateInputSchema = z.object({
|
|
696
|
+
signingPublicJwk: P256PublicJwkSchema,
|
|
697
|
+
signingPrivateKey: z.custom(),
|
|
698
|
+
kemPublicJwk: P256PublicJwkSchema,
|
|
699
|
+
kemEpoch: KemEpochSchema,
|
|
700
|
+
deviceId: z.string().min(1).optional()
|
|
701
|
+
});
|
|
702
|
+
var KemSignerSchema = z.object({ memberId: z.string().regex(MEMBER_ID_PATTERN), signingPublicJwk: P256PublicJwkSchema });
|
|
703
|
+
var KemStatementSchema = z.object({ kemPublicJwk: P256PublicJwkSchema, kemEpoch: KemEpochSchema, kemSig: KemSigSchema });
|
|
704
|
+
function memberKemSigningInput(memberId, kemPublicJwk, kemEpoch) {
|
|
705
|
+
return concat2(
|
|
706
|
+
utf82(MEMBER_KEM_DOMAIN_PREFIX),
|
|
707
|
+
canonicalizeJsonBytes({ memberId, kemPublicKey: { x: kemPublicJwk.x, y: kemPublicJwk.y }, kemEpoch })
|
|
708
|
+
);
|
|
709
|
+
}
|
|
710
|
+
async function createMemberKeyBundle(input) {
|
|
711
|
+
const parsed = safeParseTotal(CreateInputSchema, input);
|
|
712
|
+
if (!parsed.success) throw invalidInput("Member key bundle input is invalid");
|
|
713
|
+
const { signingPublicJwk, signingPrivateKey, kemPublicJwk, kemEpoch, deviceId } = parsed.data;
|
|
714
|
+
const memberId = await deriveMemberId(signingPublicJwk);
|
|
715
|
+
if (!await isValidMemberKemKey(kemPublicJwk, signingPublicJwk)) throw invalidInput("Member KEM key is invalid");
|
|
716
|
+
const kemSig = await ecdsaSign(signingPublicJwk, signingPrivateKey, memberKemSigningInput(memberId, kemPublicJwk, kemEpoch));
|
|
717
|
+
return {
|
|
718
|
+
v: MEMBER_KEY_BUNDLE_VERSION,
|
|
719
|
+
memberId,
|
|
720
|
+
signingPublicJwk,
|
|
721
|
+
kemPublicJwk,
|
|
722
|
+
kemEpoch,
|
|
723
|
+
kemSig,
|
|
724
|
+
...deviceId === void 0 ? {} : { deviceId }
|
|
725
|
+
};
|
|
726
|
+
}
|
|
727
|
+
async function isValidMemberKemKey(kemPublicJwk, signingPublicJwk) {
|
|
728
|
+
if (kemPublicJwk.x === signingPublicJwk.x && kemPublicJwk.y === signingPublicJwk.y) return false;
|
|
729
|
+
try {
|
|
730
|
+
await p256PublicKeyBytes(kemPublicJwk);
|
|
731
|
+
return true;
|
|
732
|
+
} catch {
|
|
733
|
+
return false;
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
async function verifyMemberKem(member, kem) {
|
|
737
|
+
const signer = safeParseTotal(KemSignerSchema, member);
|
|
738
|
+
const statement = safeParseTotal(KemStatementSchema, kem);
|
|
739
|
+
if (!signer.success || !statement.success) return false;
|
|
740
|
+
const { memberId, signingPublicJwk } = signer.data;
|
|
741
|
+
const { kemPublicJwk, kemEpoch, kemSig } = statement.data;
|
|
742
|
+
if (!await isValidMemberKemKey(kemPublicJwk, signingPublicJwk)) return false;
|
|
743
|
+
try {
|
|
744
|
+
return await ecdsaVerify(signingPublicJwk, kemSig, memberKemSigningInput(memberId, kemPublicJwk, kemEpoch));
|
|
745
|
+
} catch {
|
|
746
|
+
return false;
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
async function parseMemberKeyBundle(value) {
|
|
750
|
+
const parsed = safeParseTotal(MemberKeyBundleV1Schema, value);
|
|
751
|
+
if (!parsed.success) return void 0;
|
|
752
|
+
const bundle = parsed.data;
|
|
753
|
+
try {
|
|
754
|
+
if (await deriveMemberId(bundle.signingPublicJwk) !== bundle.memberId) return void 0;
|
|
755
|
+
} catch {
|
|
756
|
+
return void 0;
|
|
757
|
+
}
|
|
758
|
+
if (!await verifyMemberKem(bundle, bundle)) return void 0;
|
|
759
|
+
return bundle;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
// src/sealed-payload/scope-key.ts
|
|
682
763
|
var SCOPE_KEY_BYTES = 32;
|
|
683
764
|
var SCOPE_KEY_ID_PATTERN = /^[A-Za-z0-9_-]{22}$/u;
|
|
684
765
|
var KEY_ID_MESSAGE = "byok-scope-key-id-v1";
|
|
@@ -688,6 +769,9 @@ var SEALED_SALT_BYTES = 32;
|
|
|
688
769
|
var SCOPE_KEY_PACKAGE_VERSION = 1;
|
|
689
770
|
var SCOPE_KEY_HPKE_INFO = "byok-sdk.scope-key.v1";
|
|
690
771
|
var SCOPE_KEY_PACKAGE_DOMAIN_PREFIX = "byok-scope-key-package-v1\n";
|
|
772
|
+
var SCOPE_KEY_PACKAGE_V2 = 2;
|
|
773
|
+
var SCOPE_KEY_HPKE_INFO_V2 = "byok-sdk.scope-key.v2";
|
|
774
|
+
var SCOPE_KEY_PACKAGE_V2_DOMAIN_PREFIX = "byok-scope-key-package-v2\n";
|
|
691
775
|
var P256_POINT_BYTES = 65;
|
|
692
776
|
var AEAD_TAG_BYTES = 16;
|
|
693
777
|
function assertScopeKey(scopeKey) {
|
|
@@ -722,49 +806,35 @@ var ScopeKeyPackageV1Schema = z.strictObject({
|
|
|
722
806
|
ciphertext: base64UrlBytes(SCOPE_KEY_BYTES + AEAD_TAG_BYTES),
|
|
723
807
|
sig: base64UrlBytes(64)
|
|
724
808
|
});
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
sender: identity.sender
|
|
734
|
-
});
|
|
809
|
+
var ScopeKeyPackageV2Schema = z.strictObject({
|
|
810
|
+
...ScopeKeyPackageV1Schema.shape,
|
|
811
|
+
v: z.literal(SCOPE_KEY_PACKAGE_V2),
|
|
812
|
+
recipientKemEpoch: KemEpochSchema
|
|
813
|
+
});
|
|
814
|
+
var ScopeKeyPackageSchema = z.union([ScopeKeyPackageV1Schema, ScopeKeyPackageV2Schema]);
|
|
815
|
+
function packageAad({ enc: _enc, ciphertext: _ciphertext, sig: _sig, ...identity }) {
|
|
816
|
+
return canonicalizeJsonBytes(identity);
|
|
735
817
|
}
|
|
736
|
-
function packageSigningInput(pkg) {
|
|
737
|
-
return concat2(
|
|
738
|
-
utf82(SCOPE_KEY_PACKAGE_DOMAIN_PREFIX),
|
|
739
|
-
canonicalizeJsonBytes({
|
|
740
|
-
v: pkg.v,
|
|
741
|
-
tenantId: pkg.tenantId,
|
|
742
|
-
scopeId: pkg.scopeId,
|
|
743
|
-
epoch: pkg.epoch,
|
|
744
|
-
keyId: pkg.keyId,
|
|
745
|
-
recipient: pkg.recipient,
|
|
746
|
-
sender: pkg.sender,
|
|
747
|
-
enc: pkg.enc,
|
|
748
|
-
ciphertext: pkg.ciphertext
|
|
749
|
-
})
|
|
750
|
-
);
|
|
818
|
+
function packageSigningInput({ sig: _sig, ...pkg }) {
|
|
819
|
+
return concat2(utf82(pkg.v === SCOPE_KEY_PACKAGE_V2 ? SCOPE_KEY_PACKAGE_V2_DOMAIN_PREFIX : SCOPE_KEY_PACKAGE_DOMAIN_PREFIX), canonicalizeJsonBytes(pkg));
|
|
751
820
|
}
|
|
752
|
-
var PackageIdentitySchema =
|
|
821
|
+
var PackageIdentitySchema = ScopeKeyPackageV2Schema.omit({ enc: true, ciphertext: true, sig: true });
|
|
753
822
|
async function sealScopeKeyPackage(input) {
|
|
754
823
|
const parsed = safeParseTotal(PackageIdentitySchema, {
|
|
755
|
-
v:
|
|
824
|
+
v: SCOPE_KEY_PACKAGE_V2,
|
|
756
825
|
tenantId: input.tenantId,
|
|
757
826
|
scopeId: input.scopeId,
|
|
758
827
|
epoch: input.epoch,
|
|
759
828
|
keyId: await deriveScopeKeyId(input.scopeKey),
|
|
760
829
|
recipient: input.recipient.memberId,
|
|
830
|
+
recipientKemEpoch: input.recipient.kemEpoch,
|
|
761
831
|
sender: await deriveMemberId(input.sender.signingPublicJwk)
|
|
762
832
|
});
|
|
763
833
|
if (!parsed.success) throw invalidInput("Scope key package input is invalid");
|
|
764
834
|
const identity = parsed.data;
|
|
765
835
|
const { enc, ciphertext } = await hpkeSealBase({
|
|
766
836
|
recipientPublicKey: await p256PublicKeyBytes(input.recipient.kemPublicJwk),
|
|
767
|
-
info: utf82(
|
|
837
|
+
info: utf82(SCOPE_KEY_HPKE_INFO_V2),
|
|
768
838
|
aad: packageAad(identity),
|
|
769
839
|
plaintext: input.scopeKey
|
|
770
840
|
});
|
|
@@ -772,10 +842,10 @@ async function sealScopeKeyPackage(input) {
|
|
|
772
842
|
return { ...unsigned, sig: await ecdsaSign(input.sender.signingPublicJwk, input.sender.signingPrivateKey, packageSigningInput(unsigned)) };
|
|
773
843
|
}
|
|
774
844
|
async function openScopeKeyPackage(input) {
|
|
775
|
-
const parsed = safeParseTotal(
|
|
845
|
+
const parsed = safeParseTotal(ScopeKeyPackageSchema, input.package);
|
|
776
846
|
if (!parsed.success) return { ok: false, reason: "key_package_invalid" };
|
|
777
847
|
const pkg = parsed.data;
|
|
778
|
-
if (pkg.recipient !== input.recipient.memberId || pkg.tenantId !== input.expected.tenantId || pkg.scopeId !== input.expected.scopeId || pkg.epoch !== input.expected.epoch || pkg.sender !== await deriveMemberId(input.senderSigningPublicJwk)) {
|
|
848
|
+
if (pkg.recipient !== input.recipient.memberId || pkg.v === SCOPE_KEY_PACKAGE_V2 && pkg.recipientKemEpoch !== input.recipient.kemEpoch || pkg.tenantId !== input.expected.tenantId || pkg.scopeId !== input.expected.scopeId || pkg.epoch !== input.expected.epoch || pkg.sender !== await deriveMemberId(input.senderSigningPublicJwk)) {
|
|
779
849
|
return { ok: false, reason: "key_package_invalid" };
|
|
780
850
|
}
|
|
781
851
|
if (!await ecdsaVerify(input.senderSigningPublicJwk, pkg.sig, packageSigningInput(pkg))) {
|
|
@@ -787,7 +857,7 @@ async function openScopeKeyPackage(input) {
|
|
|
787
857
|
recipientPrivateKey: input.recipient.kemPrivateKey,
|
|
788
858
|
recipientPublicKey: await p256PublicKeyBytes(input.recipient.kemPublicJwk),
|
|
789
859
|
enc: decodeBase64Url(pkg.enc, "enc"),
|
|
790
|
-
info: utf82(SCOPE_KEY_HPKE_INFO),
|
|
860
|
+
info: utf82(pkg.v === SCOPE_KEY_PACKAGE_V2 ? SCOPE_KEY_HPKE_INFO_V2 : SCOPE_KEY_HPKE_INFO),
|
|
791
861
|
aad: packageAad(pkg),
|
|
792
862
|
ciphertext: decodeBase64Url(pkg.ciphertext, "ciphertext")
|
|
793
863
|
});
|
|
@@ -1086,84 +1156,114 @@ async function openSealedContent(input) {
|
|
|
1086
1156
|
frame.fill(0);
|
|
1087
1157
|
}
|
|
1088
1158
|
}
|
|
1089
|
-
var
|
|
1090
|
-
var
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
signingPublicJwk: P256PublicJwkSchema,
|
|
1097
|
-
kemPublicJwk: P256PublicJwkSchema,
|
|
1098
|
-
kemEpoch: KemEpochSchema,
|
|
1099
|
-
kemSig: KemSigSchema,
|
|
1100
|
-
deviceId: z.string().min(1).optional()
|
|
1101
|
-
});
|
|
1102
|
-
var CreateInputSchema = z.object({
|
|
1103
|
-
signingPublicJwk: P256PublicJwkSchema,
|
|
1104
|
-
signingPrivateKey: z.custom(),
|
|
1105
|
-
kemPublicJwk: P256PublicJwkSchema,
|
|
1106
|
-
kemEpoch: KemEpochSchema,
|
|
1107
|
-
deviceId: z.string().min(1).optional()
|
|
1159
|
+
var MEMBER_KEY_RECORD_VERSION = 1;
|
|
1160
|
+
var PrivateJwkSchema = z.strictObject({
|
|
1161
|
+
kty: z.literal("EC"),
|
|
1162
|
+
crv: z.literal("P-256"),
|
|
1163
|
+
x: base64UrlBytes(32),
|
|
1164
|
+
y: base64UrlBytes(32),
|
|
1165
|
+
d: base64UrlBytes(32)
|
|
1108
1166
|
});
|
|
1109
|
-
var
|
|
1110
|
-
var
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1167
|
+
var KemEpochSchema2 = z.number().int().positive().max(Number.MAX_SAFE_INTEGER);
|
|
1168
|
+
var MemberKeyRecordV1Schema = z.strictObject({
|
|
1169
|
+
v: z.literal(MEMBER_KEY_RECORD_VERSION),
|
|
1170
|
+
tenantId: z.string().min(1),
|
|
1171
|
+
deviceId: z.string().min(1).optional(),
|
|
1172
|
+
signingJwk: PrivateJwkSchema,
|
|
1173
|
+
kemEpoch: KemEpochSchema2,
|
|
1174
|
+
kemJwk: PrivateJwkSchema,
|
|
1175
|
+
nextKem: z.strictObject({ epoch: KemEpochSchema2, jwk: PrivateJwkSchema }).optional()
|
|
1176
|
+
}).refine((record) => record.nextKem === void 0 || record.nextKem.epoch === record.kemEpoch + 1);
|
|
1177
|
+
var BindingSchema = z.object({ tenantId: z.string().min(1), deviceId: z.string().min(1).optional() });
|
|
1178
|
+
function keySubtle() {
|
|
1179
|
+
return webCryptoSubtle();
|
|
1116
1180
|
}
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
const
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1181
|
+
var ECDSA_P2562 = { name: "ECDSA", namedCurve: "P-256" };
|
|
1182
|
+
var ECDSA_SHA2562 = { name: "ECDSA", hash: "SHA-256" };
|
|
1183
|
+
var ECDH_P256 = { name: "ECDH", namedCurve: "P-256" };
|
|
1184
|
+
async function generatePrivateJwk(algorithm, usages) {
|
|
1185
|
+
const pair = await keySubtle().generateKey(algorithm, true, usages);
|
|
1186
|
+
const { kty, crv, x, y, d } = await keySubtle().exportKey("jwk", pair.privateKey);
|
|
1187
|
+
return PrivateJwkSchema.parse({ kty, crv, x, y, d });
|
|
1188
|
+
}
|
|
1189
|
+
async function generateMemberKeyRecord(binding) {
|
|
1190
|
+
const parsed = safeParseTotal(BindingSchema, binding);
|
|
1191
|
+
if (!parsed.success) throw invalidInput("Member key binding is invalid");
|
|
1192
|
+
const { tenantId, deviceId } = parsed.data;
|
|
1193
|
+
return canonicalizeJson({
|
|
1194
|
+
v: MEMBER_KEY_RECORD_VERSION,
|
|
1195
|
+
tenantId,
|
|
1196
|
+
...deviceId === void 0 ? {} : { deviceId },
|
|
1197
|
+
signingJwk: await generatePrivateJwk(ECDSA_P2562, ["sign", "verify"]),
|
|
1198
|
+
kemEpoch: 1,
|
|
1199
|
+
kemJwk: await generatePrivateJwk(ECDH_P256, ["deriveBits"])
|
|
1200
|
+
});
|
|
1133
1201
|
}
|
|
1134
|
-
|
|
1135
|
-
|
|
1202
|
+
function publicJwkOf(jwk) {
|
|
1203
|
+
return P256PublicJwkSchema.parse({ kty: jwk.kty, crv: jwk.crv, x: jwk.x, y: jwk.y });
|
|
1204
|
+
}
|
|
1205
|
+
function bytesEqual(left, right) {
|
|
1206
|
+
const a = new Uint8Array(left);
|
|
1207
|
+
const b = new Uint8Array(right);
|
|
1208
|
+
return a.length === b.length && a.every((byte, index) => byte === b[index]);
|
|
1209
|
+
}
|
|
1210
|
+
async function importSigningKey(jwk) {
|
|
1211
|
+
const subtle = keySubtle();
|
|
1212
|
+
const publicJwk = publicJwkOf(jwk);
|
|
1213
|
+
const privateKey = await subtle.importKey("jwk", { ...jwk, ext: false }, ECDSA_P2562, false, ["sign"]);
|
|
1214
|
+
const publicKey = await subtle.importKey("jwk", publicJwk, ECDSA_P2562, true, ["verify"]);
|
|
1215
|
+
const probe = randomBytes(32);
|
|
1216
|
+
if (!await subtle.verify(ECDSA_SHA2562, publicKey, await subtle.sign(ECDSA_SHA2562, privateKey, probe), probe)) {
|
|
1217
|
+
throw new TypeError("signing scalar does not match its public point");
|
|
1218
|
+
}
|
|
1219
|
+
return { publicJwk, privateKey };
|
|
1220
|
+
}
|
|
1221
|
+
async function importKemKey(jwk) {
|
|
1222
|
+
const subtle = keySubtle();
|
|
1223
|
+
const publicJwk = publicJwkOf(jwk);
|
|
1224
|
+
const privateKey = await subtle.importKey("jwk", { ...jwk, ext: false }, ECDH_P256, false, ["deriveBits"]);
|
|
1225
|
+
const publicKey = await subtle.importKey("jwk", publicJwk, ECDH_P256, true, []);
|
|
1226
|
+
const probe = await subtle.generateKey(ECDH_P256, false, ["deriveBits"]);
|
|
1227
|
+
const viaMember = await subtle.deriveBits({ name: "ECDH", public: probe.publicKey }, privateKey, 256);
|
|
1228
|
+
const viaProbe = await subtle.deriveBits({ name: "ECDH", public: publicKey }, probe.privateKey, 256);
|
|
1229
|
+
if (!bytesEqual(viaMember, viaProbe)) throw new TypeError("KEM scalar does not match its public point");
|
|
1230
|
+
return { publicJwk, privateKey };
|
|
1231
|
+
}
|
|
1232
|
+
async function openMemberKeyRecord(text) {
|
|
1233
|
+
const record = parseRecord(text);
|
|
1234
|
+
if (record === void 0) return void 0;
|
|
1136
1235
|
try {
|
|
1137
|
-
await
|
|
1138
|
-
|
|
1236
|
+
const signing = await importSigningKey(record.signingJwk);
|
|
1237
|
+
const kem = { epoch: record.kemEpoch, ...await importKemKey(record.kemJwk) };
|
|
1238
|
+
const binding = record.deviceId === void 0 ? { tenantId: record.tenantId } : { tenantId: record.tenantId, deviceId: record.deviceId };
|
|
1239
|
+
if (record.nextKem === void 0) return { binding, signing, kem };
|
|
1240
|
+
return { binding, signing, kem, nextKem: { epoch: record.nextKem.epoch, ...await importKemKey(record.nextKem.jwk) } };
|
|
1139
1241
|
} catch {
|
|
1140
|
-
return
|
|
1242
|
+
return void 0;
|
|
1141
1243
|
}
|
|
1142
1244
|
}
|
|
1143
|
-
async function
|
|
1144
|
-
const
|
|
1145
|
-
|
|
1146
|
-
if (
|
|
1147
|
-
|
|
1148
|
-
const { kemPublicJwk, kemEpoch, kemSig } = statement.data;
|
|
1149
|
-
if (!await isValidMemberKemKey(kemPublicJwk, signingPublicJwk)) return false;
|
|
1150
|
-
try {
|
|
1151
|
-
return await ecdsaVerify(signingPublicJwk, kemSig, memberKemSigningInput(memberId, kemPublicJwk, kemEpoch));
|
|
1152
|
-
} catch {
|
|
1153
|
-
return false;
|
|
1154
|
-
}
|
|
1245
|
+
async function beginMemberKemRotation(text) {
|
|
1246
|
+
const record = parseRecord(text);
|
|
1247
|
+
if (record === void 0) throw invalidInput("Member key record is invalid");
|
|
1248
|
+
if (record.nextKem !== void 0) return text;
|
|
1249
|
+
return canonicalizeJson({ ...record, nextKem: { epoch: record.kemEpoch + 1, jwk: await generatePrivateJwk(ECDH_P256, ["deriveBits"]) } });
|
|
1155
1250
|
}
|
|
1156
|
-
|
|
1157
|
-
const
|
|
1158
|
-
if (
|
|
1159
|
-
|
|
1251
|
+
function finishMemberKemRotation(text, epoch) {
|
|
1252
|
+
const record = parseRecord(text);
|
|
1253
|
+
if (record === void 0) throw invalidInput("Member key record is invalid");
|
|
1254
|
+
if (record.nextKem === void 0) return record.kemEpoch === epoch ? text : void 0;
|
|
1255
|
+
if (record.nextKem.epoch !== epoch) return void 0;
|
|
1256
|
+
const { nextKem, ...rest } = record;
|
|
1257
|
+
return canonicalizeJson({ ...rest, kemEpoch: nextKem.epoch, kemJwk: nextKem.jwk });
|
|
1258
|
+
}
|
|
1259
|
+
function parseRecord(text) {
|
|
1260
|
+
if (typeof text !== "string") return void 0;
|
|
1160
1261
|
try {
|
|
1161
|
-
|
|
1262
|
+
const parsed = safeParseTotal(MemberKeyRecordV1Schema, JSON.parse(text));
|
|
1263
|
+
return parsed.success && canonicalizeJson(parsed.data) === text ? parsed.data : void 0;
|
|
1162
1264
|
} catch {
|
|
1163
1265
|
return void 0;
|
|
1164
1266
|
}
|
|
1165
|
-
if (!await verifyMemberKem(bundle, bundle)) return void 0;
|
|
1166
|
-
return bundle;
|
|
1167
1267
|
}
|
|
1168
1268
|
var MEMBER_FINGERPRINT_DOMAIN = "byok-member-fingerprint-v1\n";
|
|
1169
1269
|
var FINGERPRINT_GROUPS = 5;
|
|
@@ -1481,6 +1581,6 @@ async function verifyMemberChainFromAnchor(input) {
|
|
|
1481
1581
|
return { ok: true, state: outcome.state, anchorSeq: anchor.seq };
|
|
1482
1582
|
}
|
|
1483
1583
|
|
|
1484
|
-
export { CLIENT_PAIRING_MAC_DOMAIN, DEVICE_PAIRING_MAC_DOMAIN, MEMBER_CHAIN_OPS, MEMBER_FINGERPRINT_DOMAIN, MEMBER_KEY_BUNDLE_VERSION, PAIRING_VERIFICATION_SECRET_BYTES, SEALED_CATEGORIES, SEALED_CONTENT_SUITE, SEALED_CONTENT_VERSION, SEALED_DIRECTIONS, SealedContentHeaderV1Schema, applyMemberChainEntries, computeClientPairingMac, computeDevicePairingMac, createMemberKeyBundle, decodePairingVerificationSecret, deriveMemberId, deriveScopeKeyId, emptyMemberChainState, encodePairingVerificationSecret, formatPairingInput, generatePairingVerificationSecret, generateScopeKey, memberApprovalCode, memberChainEntryHash, memberChainScopeRecipients, memberFingerprint, openScopeKeyPackage, openSealedContent, parseMemberKeyBundle, parsePairingInput, sealContent, sealScopeKeyPackage, signMemberChainEntry, verifyClientPairingMac, verifyDevicePairingMac, verifyMemberChainEntry, verifyMemberChainFromAnchor, verifyMemberKem };
|
|
1584
|
+
export { CLIENT_PAIRING_MAC_DOMAIN, DEVICE_PAIRING_MAC_DOMAIN, MEMBER_CHAIN_OPS, MEMBER_FINGERPRINT_DOMAIN, MEMBER_KEY_BUNDLE_VERSION, PAIRING_VERIFICATION_SECRET_BYTES, SEALED_CATEGORIES, SEALED_CONTENT_SUITE, SEALED_CONTENT_VERSION, SEALED_DIRECTIONS, SealedContentHeaderV1Schema, applyMemberChainEntries, beginMemberKemRotation, computeClientPairingMac, computeDevicePairingMac, createMemberKeyBundle, decodePairingVerificationSecret, deriveMemberId, deriveScopeKeyId, emptyMemberChainState, encodePairingVerificationSecret, finishMemberKemRotation, formatPairingInput, generateMemberKeyRecord, generatePairingVerificationSecret, generateScopeKey, memberApprovalCode, memberChainEntryHash, memberChainScopeRecipients, memberFingerprint, openMemberKeyRecord, openScopeKeyPackage, openSealedContent, parseMemberKeyBundle, parsePairingInput, sealContent, sealScopeKeyPackage, signMemberChainEntry, verifyClientPairingMac, verifyDevicePairingMac, verifyMemberChainEntry, verifyMemberChainFromAnchor, verifyMemberKem };
|
|
1485
1585
|
//# sourceMappingURL=index.js.map
|
|
1486
1586
|
//# sourceMappingURL=index.js.map
|