anastasis-core: crypto fixes
This commit is contained in:
parent
aac2bc389a
commit
26738d14f1
@ -66,16 +66,12 @@ export function accountKeypairDerive(userId: UserIdentifier): AccountKeyPair {
|
|||||||
// FIXME: the KDF invocation looks fishy, but that's what the C code presently does.
|
// FIXME: the KDF invocation looks fishy, but that's what the C code presently does.
|
||||||
const d = kdfKw({
|
const d = kdfKw({
|
||||||
outputLength: 32,
|
outputLength: 32,
|
||||||
ikm: stringToBytes("ver"),
|
ikm: decodeCrock(userId),
|
||||||
salt: decodeCrock(userId),
|
info: stringToBytes("ver"),
|
||||||
});
|
});
|
||||||
// FIXME: This bit twiddling seems wrong/unnecessary.
|
|
||||||
d[0] &= 248;
|
|
||||||
d[31] &= 127;
|
|
||||||
d[31] |= 64;
|
|
||||||
const pair = crypto_sign_keyPair_fromSeed(d);
|
const pair = crypto_sign_keyPair_fromSeed(d);
|
||||||
return {
|
return {
|
||||||
priv: encodeCrock(pair.secretKey),
|
priv: encodeCrock(d),
|
||||||
pub: encodeCrock(pair.publicKey),
|
pub: encodeCrock(pair.publicKey),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
import {
|
import {
|
||||||
AmountString,
|
AmountString,
|
||||||
|
buildSigPS,
|
||||||
codecForGetExchangeWithdrawalInfo,
|
codecForGetExchangeWithdrawalInfo,
|
||||||
decodeCrock,
|
decodeCrock,
|
||||||
|
eddsaSign,
|
||||||
encodeCrock,
|
encodeCrock,
|
||||||
getRandomBytes,
|
getRandomBytes,
|
||||||
|
hash,
|
||||||
TalerErrorCode,
|
TalerErrorCode,
|
||||||
|
TalerSignaturePurpose,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
import { anastasisData } from "./anastasis-data.js";
|
import { anastasisData } from "./anastasis-data.js";
|
||||||
import {
|
import {
|
||||||
@ -33,6 +37,7 @@ import {
|
|||||||
ReducerStateBackupUserAttributesCollecting,
|
ReducerStateBackupUserAttributesCollecting,
|
||||||
ReducerStateError,
|
ReducerStateError,
|
||||||
ReducerStateRecovery,
|
ReducerStateRecovery,
|
||||||
|
SuccessDetails,
|
||||||
} from "./reducer-types.js";
|
} from "./reducer-types.js";
|
||||||
import fetchPonyfill from "fetch-ponyfill";
|
import fetchPonyfill from "fetch-ponyfill";
|
||||||
import {
|
import {
|
||||||
@ -43,6 +48,7 @@ import {
|
|||||||
encryptTruth,
|
encryptTruth,
|
||||||
PolicyKey,
|
PolicyKey,
|
||||||
policyKeyDerive,
|
policyKeyDerive,
|
||||||
|
PolicySalt,
|
||||||
UserIdentifier,
|
UserIdentifier,
|
||||||
userIdentifierDerive,
|
userIdentifierDerive,
|
||||||
} from "./crypto.js";
|
} from "./crypto.js";
|
||||||
@ -393,12 +399,17 @@ async function uploadSecret(
|
|||||||
const coreSecret = state.core_secret?.value!;
|
const coreSecret = state.core_secret?.value!;
|
||||||
// Truth key is `${methodIndex}/${providerUrl}`
|
// Truth key is `${methodIndex}/${providerUrl}`
|
||||||
const truthMetadataMap: Record<string, TruthMetaData> = {};
|
const truthMetadataMap: Record<string, TruthMetaData> = {};
|
||||||
|
|
||||||
const policyKeys: PolicyKey[] = [];
|
const policyKeys: PolicyKey[] = [];
|
||||||
|
const policySalts: PolicySalt[] = [];
|
||||||
|
// truth UUIDs for every policy.
|
||||||
|
const policyUuids: string[][] = [];
|
||||||
|
|
||||||
for (let policyIndex = 0; policyIndex < policies.length; policyIndex++) {
|
for (let policyIndex = 0; policyIndex < policies.length; policyIndex++) {
|
||||||
const pol = policies[policyIndex];
|
const pol = policies[policyIndex];
|
||||||
const policySalt = encodeCrock(getRandomBytes(64));
|
const policySalt = encodeCrock(getRandomBytes(64));
|
||||||
const keyShares: string[] = [];
|
const keyShares: string[] = [];
|
||||||
|
const methUuids: string[] = [];
|
||||||
for (let methIndex = 0; methIndex < pol.methods.length; methIndex++) {
|
for (let methIndex = 0; methIndex < pol.methods.length; methIndex++) {
|
||||||
const meth = pol.methods[methIndex];
|
const meth = pol.methods[methIndex];
|
||||||
const truthKey = `${meth.authentication_method}:${meth.provider}`;
|
const truthKey = `${meth.authentication_method}:${meth.provider}`;
|
||||||
@ -416,10 +427,12 @@ async function uploadSecret(
|
|||||||
pol_method_index: methIndex,
|
pol_method_index: methIndex,
|
||||||
policy_index: policyIndex,
|
policy_index: policyIndex,
|
||||||
};
|
};
|
||||||
|
methUuids.push(tm.uuid);
|
||||||
truthMetadataMap[truthKey] = tm;
|
truthMetadataMap[truthKey] = tm;
|
||||||
}
|
}
|
||||||
const policyKey = await policyKeyDerive(keyShares, policySalt);
|
const policyKey = await policyKeyDerive(keyShares, policySalt);
|
||||||
policyKeys.push(policyKey);
|
policyKeys.push(policyKey);
|
||||||
|
policySalts.push(policySalt);
|
||||||
}
|
}
|
||||||
|
|
||||||
const csr = await coreSecretEncrypt(policyKeys, coreSecret);
|
const csr = await coreSecretEncrypt(policyKeys, coreSecret);
|
||||||
@ -472,6 +485,13 @@ async function uploadSecret(
|
|||||||
body: JSON.stringify(tur),
|
body: JSON.stringify(tur),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (resp.status !== 204) {
|
||||||
|
return {
|
||||||
|
code: TalerErrorCode.ANASTASIS_REDUCER_NETWORK_FAILED,
|
||||||
|
hint: "could not upload policy",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
escrowMethods.push({
|
escrowMethods.push({
|
||||||
escrow_type: authMethod.type,
|
escrow_type: authMethod.type,
|
||||||
instructions: authMethod.instructions,
|
instructions: authMethod.instructions,
|
||||||
@ -494,30 +514,56 @@ async function uploadSecret(
|
|||||||
policies: policies.map((x, i) => {
|
policies: policies.map((x, i) => {
|
||||||
return {
|
return {
|
||||||
master_key: csr.encMasterKeys[i],
|
master_key: csr.encMasterKeys[i],
|
||||||
// FIXME: ...
|
uuid: policyUuids[i],
|
||||||
uuid: [],
|
salt: policySalts[i],
|
||||||
salt: undefined as any,
|
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const successDetails: SuccessDetails = {};
|
||||||
|
|
||||||
for (const prov of state.policy_providers!) {
|
for (const prov of state.policy_providers!) {
|
||||||
const uid = uidMap[prov.provider_url]
|
const uid = uidMap[prov.provider_url];
|
||||||
const acctKeypair = accountKeypairDerive(uid);
|
const acctKeypair = accountKeypairDerive(uid);
|
||||||
const encRecoveryDoc = await encryptRecoveryDocument(uid, rd);
|
const encRecoveryDoc = await encryptRecoveryDocument(uid, rd);
|
||||||
// FIXME: Upload recovery document.
|
const bodyHash = hash(decodeCrock(encRecoveryDoc));
|
||||||
|
const sigPS = buildSigPS(TalerSignaturePurpose.ANASTASIS_POLICY_UPLOAD)
|
||||||
|
.put(bodyHash)
|
||||||
|
.build();
|
||||||
|
const sig = eddsaSign(sigPS, decodeCrock(acctKeypair.priv));
|
||||||
const resp = await fetch(
|
const resp = await fetch(
|
||||||
new URL(`policy/${acctKeypair.pub}`, prov.provider_url).href,
|
new URL(`policy/${acctKeypair.pub}`, prov.provider_url).href,
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Anastasis-Policy-Signature": encodeCrock(sig),
|
||||||
|
"If-None-Match": encodeCrock(bodyHash),
|
||||||
|
},
|
||||||
body: decodeCrock(encRecoveryDoc),
|
body: decodeCrock(encRecoveryDoc),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
if (resp.status !== 204) {
|
||||||
|
return {
|
||||||
|
code: TalerErrorCode.ANASTASIS_REDUCER_NETWORK_FAILED,
|
||||||
|
hint: "could not upload policy",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
let policyVersion = 0;
|
||||||
|
console.log(resp);
|
||||||
|
console.log(resp.headers);
|
||||||
|
console.log(resp.headers.get("Anastasis-Version"));
|
||||||
|
try {
|
||||||
|
policyVersion = Number(resp.headers.get("Anastasis-Version") ?? "0");
|
||||||
|
} catch (e) {}
|
||||||
|
successDetails[prov.provider_url] = {
|
||||||
|
policy_version: policyVersion,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
code: 123,
|
...state,
|
||||||
hint: "not implemented",
|
backup_state: BackupStates.BackupFinished,
|
||||||
|
success_details: successDetails,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -703,6 +749,19 @@ export async function reduceAction(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (state.backup_state === BackupStates.BackupFinished) {
|
||||||
|
if (action === "back") {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
backup_state: BackupStates.SecretEditing,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
code: TalerErrorCode.ANASTASIS_REDUCER_ACTION_INVALID,
|
||||||
|
hint: `Unsupported action '${action}'`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
code: TalerErrorCode.ANASTASIS_REDUCER_ACTION_INVALID,
|
code: TalerErrorCode.ANASTASIS_REDUCER_ACTION_INVALID,
|
||||||
hint: "Reducer action invalid",
|
hint: "Reducer action invalid",
|
||||||
|
@ -27,6 +27,12 @@ export interface PolicyProvider {
|
|||||||
provider_url: string;
|
provider_url: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SuccessDetails {
|
||||||
|
[provider_url: string]: {
|
||||||
|
policy_version: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export interface ReducerStateBackup {
|
export interface ReducerStateBackup {
|
||||||
recovery_state?: undefined;
|
recovery_state?: undefined;
|
||||||
backup_state: BackupStates;
|
backup_state: BackupStates;
|
||||||
@ -47,11 +53,7 @@ export interface ReducerStateBackup {
|
|||||||
* and that are actually used in policies.
|
* and that are actually used in policies.
|
||||||
*/
|
*/
|
||||||
policy_providers?: PolicyProvider[];
|
policy_providers?: PolicyProvider[];
|
||||||
success_details?: {
|
success_details?: SuccessDetails;
|
||||||
[provider_url: string]: {
|
|
||||||
policy_version: number;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
payments?: string[];
|
payments?: string[];
|
||||||
policy_payment_requests?: {
|
policy_payment_requests?: {
|
||||||
payto: string;
|
payto: string;
|
||||||
|
@ -2926,7 +2926,8 @@ export function crypto_sign_keyPair_fromSeed(
|
|||||||
secretKey: Uint8Array;
|
secretKey: Uint8Array;
|
||||||
} {
|
} {
|
||||||
checkArrayTypes(seed);
|
checkArrayTypes(seed);
|
||||||
if (seed.length !== crypto_sign_SEEDBYTES) throw new Error("bad seed size");
|
if (seed.length !== crypto_sign_SEEDBYTES)
|
||||||
|
throw new Error(`bad seed size: ${seed.length}`);
|
||||||
const pk = new Uint8Array(crypto_sign_PUBLICKEYBYTES);
|
const pk = new Uint8Array(crypto_sign_PUBLICKEYBYTES);
|
||||||
const sk = new Uint8Array(crypto_sign_SECRETKEYBYTES);
|
const sk = new Uint8Array(crypto_sign_SECRETKEYBYTES);
|
||||||
for (let i = 0; i < 32; i++) sk[i] = seed[i];
|
for (let i = 0; i < 32; i++) sk[i] = seed[i];
|
||||||
@ -3015,4 +3016,3 @@ export function secretbox_open(
|
|||||||
if (crypto_secretbox_open(m, c, c.length, nonce, key) !== 0) return undefined;
|
if (crypto_secretbox_open(m, c, c.length, nonce, key) !== 0) return undefined;
|
||||||
return m.subarray(crypto_secretbox_ZEROBYTES);
|
return m.subarray(crypto_secretbox_ZEROBYTES);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user