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.
|
||||
const d = kdfKw({
|
||||
outputLength: 32,
|
||||
ikm: stringToBytes("ver"),
|
||||
salt: decodeCrock(userId),
|
||||
ikm: 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);
|
||||
return {
|
||||
priv: encodeCrock(pair.secretKey),
|
||||
priv: encodeCrock(d),
|
||||
pub: encodeCrock(pair.publicKey),
|
||||
};
|
||||
}
|
||||
|
@ -1,10 +1,14 @@
|
||||
import {
|
||||
AmountString,
|
||||
buildSigPS,
|
||||
codecForGetExchangeWithdrawalInfo,
|
||||
decodeCrock,
|
||||
eddsaSign,
|
||||
encodeCrock,
|
||||
getRandomBytes,
|
||||
hash,
|
||||
TalerErrorCode,
|
||||
TalerSignaturePurpose,
|
||||
} from "@gnu-taler/taler-util";
|
||||
import { anastasisData } from "./anastasis-data.js";
|
||||
import {
|
||||
@ -33,6 +37,7 @@ import {
|
||||
ReducerStateBackupUserAttributesCollecting,
|
||||
ReducerStateError,
|
||||
ReducerStateRecovery,
|
||||
SuccessDetails,
|
||||
} from "./reducer-types.js";
|
||||
import fetchPonyfill from "fetch-ponyfill";
|
||||
import {
|
||||
@ -43,6 +48,7 @@ import {
|
||||
encryptTruth,
|
||||
PolicyKey,
|
||||
policyKeyDerive,
|
||||
PolicySalt,
|
||||
UserIdentifier,
|
||||
userIdentifierDerive,
|
||||
} from "./crypto.js";
|
||||
@ -393,12 +399,17 @@ async function uploadSecret(
|
||||
const coreSecret = state.core_secret?.value!;
|
||||
// Truth key is `${methodIndex}/${providerUrl}`
|
||||
const truthMetadataMap: Record<string, TruthMetaData> = {};
|
||||
|
||||
const policyKeys: PolicyKey[] = [];
|
||||
const policySalts: PolicySalt[] = [];
|
||||
// truth UUIDs for every policy.
|
||||
const policyUuids: string[][] = [];
|
||||
|
||||
for (let policyIndex = 0; policyIndex < policies.length; policyIndex++) {
|
||||
const pol = policies[policyIndex];
|
||||
const policySalt = encodeCrock(getRandomBytes(64));
|
||||
const keyShares: string[] = [];
|
||||
const methUuids: string[] = [];
|
||||
for (let methIndex = 0; methIndex < pol.methods.length; methIndex++) {
|
||||
const meth = pol.methods[methIndex];
|
||||
const truthKey = `${meth.authentication_method}:${meth.provider}`;
|
||||
@ -416,10 +427,12 @@ async function uploadSecret(
|
||||
pol_method_index: methIndex,
|
||||
policy_index: policyIndex,
|
||||
};
|
||||
methUuids.push(tm.uuid);
|
||||
truthMetadataMap[truthKey] = tm;
|
||||
}
|
||||
const policyKey = await policyKeyDerive(keyShares, policySalt);
|
||||
policyKeys.push(policyKey);
|
||||
policySalts.push(policySalt);
|
||||
}
|
||||
|
||||
const csr = await coreSecretEncrypt(policyKeys, coreSecret);
|
||||
@ -472,6 +485,13 @@ async function uploadSecret(
|
||||
body: JSON.stringify(tur),
|
||||
});
|
||||
|
||||
if (resp.status !== 204) {
|
||||
return {
|
||||
code: TalerErrorCode.ANASTASIS_REDUCER_NETWORK_FAILED,
|
||||
hint: "could not upload policy",
|
||||
};
|
||||
}
|
||||
|
||||
escrowMethods.push({
|
||||
escrow_type: authMethod.type,
|
||||
instructions: authMethod.instructions,
|
||||
@ -494,30 +514,56 @@ async function uploadSecret(
|
||||
policies: policies.map((x, i) => {
|
||||
return {
|
||||
master_key: csr.encMasterKeys[i],
|
||||
// FIXME: ...
|
||||
uuid: [],
|
||||
salt: undefined as any,
|
||||
uuid: policyUuids[i],
|
||||
salt: policySalts[i],
|
||||
};
|
||||
}),
|
||||
};
|
||||
|
||||
const successDetails: SuccessDetails = {};
|
||||
|
||||
for (const prov of state.policy_providers!) {
|
||||
const uid = uidMap[prov.provider_url]
|
||||
const uid = uidMap[prov.provider_url];
|
||||
const acctKeypair = accountKeypairDerive(uid);
|
||||
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(
|
||||
new URL(`policy/${acctKeypair.pub}`, prov.provider_url).href,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Anastasis-Policy-Signature": encodeCrock(sig),
|
||||
"If-None-Match": encodeCrock(bodyHash),
|
||||
},
|
||||
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 {
|
||||
code: 123,
|
||||
hint: "not implemented",
|
||||
...state,
|
||||
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 {
|
||||
code: TalerErrorCode.ANASTASIS_REDUCER_ACTION_INVALID,
|
||||
hint: "Reducer action invalid",
|
||||
|
@ -27,6 +27,12 @@ export interface PolicyProvider {
|
||||
provider_url: string;
|
||||
}
|
||||
|
||||
export interface SuccessDetails {
|
||||
[provider_url: string]: {
|
||||
policy_version: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ReducerStateBackup {
|
||||
recovery_state?: undefined;
|
||||
backup_state: BackupStates;
|
||||
@ -47,11 +53,7 @@ export interface ReducerStateBackup {
|
||||
* and that are actually used in policies.
|
||||
*/
|
||||
policy_providers?: PolicyProvider[];
|
||||
success_details?: {
|
||||
[provider_url: string]: {
|
||||
policy_version: number;
|
||||
};
|
||||
};
|
||||
success_details?: SuccessDetails;
|
||||
payments?: string[];
|
||||
policy_payment_requests?: {
|
||||
payto: string;
|
||||
|
@ -2926,7 +2926,8 @@ export function crypto_sign_keyPair_fromSeed(
|
||||
secretKey: Uint8Array;
|
||||
} {
|
||||
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 sk = new Uint8Array(crypto_sign_SECRETKEYBYTES);
|
||||
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;
|
||||
return m.subarray(crypto_secretbox_ZEROBYTES);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user