Skip to content

Commit f79e6b2

Browse files
committed
feat: add round domain separator to adata
TICKET: HSM-1513
1 parent d067420 commit f79e6b2

1 file changed

Lines changed: 32 additions & 10 deletions

File tree

modules/sdk-core/src/bitgo/utils/tss/ecdsa/ecdsaMPCv2.ts

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ import { EcdsaMPCv2KeyGenSendFn, KeyGenSenderForEnterprise } from './ecdsaMPCv2K
5151
import { envRequiresBitgoPubGpgKeyConfig, isBitgoMpcPubKey } from '../../../tss/bitgoPubKeys';
5252

5353
export class EcdsaMPCv2Utils extends BaseEcdsaUtils {
54+
private static readonly DKLS23_SIGNING_ROUND1_STATE = 'DKLS23_SIGNING_ROUND1_STATE';
55+
private static readonly DKLS23_SIGNING_ROUND2_STATE = 'DKLS23_SIGNING_ROUND2_STATE';
56+
5457
/** @inheritdoc */
5558
async createKeychains(params: {
5659
passphrase: string;
@@ -964,19 +967,23 @@ export class EcdsaMPCv2Utils extends BaseEcdsaUtils {
964967
* @param {string} bitgoPublicGpgKey - the BitGo public GPG key
965968
* @param {string} encryptedUserGpgPrvKey - the encrypted user GPG private key
966969
* @param {string} walletPassphrase - the wallet passphrase
970+
* @param {string} adata - the additional data to validate the GPG keys
967971
* @returns {Promise<{ bitgoGpgKey: pgp.Key; userGpgKey: pgp.SerializedKeyPair<string> }>} - the BitGo and user GPG keys
968972
*/
969973
private async getBitgoAndUserGpgKeys(
970974
bitgoPublicGpgKey: string,
971975
encryptedUserGpgPrvKey: string,
972-
walletPassphrase: string
976+
walletPassphrase: string,
977+
adata: string
973978
): Promise<{
974979
bitgoGpgKey: pgp.Key;
975980
userGpgKey: pgp.SerializedKeyPair<string>;
976981
}> {
977982
const bitgoGpgKey = await pgp.readKey({ armoredKey: bitgoPublicGpgKey });
983+
const armoredUserPrvKey = this.bitgo.decrypt({ input: encryptedUserGpgPrvKey, password: walletPassphrase });
984+
this.validateAdata(adata, armoredUserPrvKey);
978985
const userDecryptedKey = await pgp.readKey({
979-
armoredKey: this.bitgo.decrypt({ input: encryptedUserGpgPrvKey, password: walletPassphrase }),
986+
armoredKey: armoredUserPrvKey,
980987
});
981988
const userGpgKey: pgp.SerializedKeyPair<string> = {
982989
privateKey: userDecryptedKey.armor(),
@@ -995,15 +1002,20 @@ export class EcdsaMPCv2Utils extends BaseEcdsaUtils {
9951002
* @returns void
9961003
* @throws {Error} if the adata or cyphertext is invalid
9971004
*/
998-
private validateAdata(adata: string, cyphertext: string): void {
1005+
private validateAdata(adata: string, cyphertext: string, roundDomainSeparator?: string): void {
9991006
let cypherJson;
10001007
try {
10011008
cypherJson = JSON.parse(cyphertext);
10021009
} catch (e) {
10031010
throw new Error('Failed to parse cyphertext to JSON, got: ' + cyphertext);
10041011
}
10051012
// using decodeURIComponent to handle special characters
1006-
if (decodeURIComponent(cypherJson.adata) !== decodeURIComponent(adata)) {
1013+
if (
1014+
(roundDomainSeparator
1015+
? decodeURIComponent(cypherJson.adata) !== decodeURIComponent(`${roundDomainSeparator}:${adata}`)
1016+
: true) &&
1017+
decodeURIComponent(cypherJson.adata) !== decodeURIComponent(adata)
1018+
) {
10071019
throw new Error('Adata does not match cyphertext adata');
10081020
}
10091021
}
@@ -1124,7 +1136,11 @@ export class EcdsaMPCv2Utils extends BaseEcdsaUtils {
11241136
const userSignerBroadcastMsg1 = await userSigner.init();
11251137
const signatureShareRound1 = await getSignatureShareRoundOne(userSignerBroadcastMsg1, userGpgKey);
11261138
const session = userSigner.getSession();
1127-
const encryptedRound1Session = this.bitgo.encrypt({ input: session, password: walletPassphrase, adata });
1139+
const encryptedRound1Session = this.bitgo.encrypt({
1140+
input: session,
1141+
password: walletPassphrase,
1142+
adata: `${EcdsaMPCv2Utils.DKLS23_SIGNING_ROUND1_STATE}:${adata}`,
1143+
});
11281144

11291145
const userGpgPubKey = userGpgKey.publicKey;
11301146
const encryptedUserGpgPrvKey = this.bitgo.encrypt({
@@ -1155,7 +1171,8 @@ export class EcdsaMPCv2Utils extends BaseEcdsaUtils {
11551171
const { bitgoGpgKey, userGpgKey } = await this.getBitgoAndUserGpgKeys(
11561172
bitgoPublicGpgKey,
11571173
encryptedUserGpgPrvKey,
1158-
walletPassphrase
1174+
walletPassphrase,
1175+
adata
11591176
);
11601177

11611178
const signatureShares = txRequest.transactions?.[0].signatureShares;
@@ -1174,7 +1191,7 @@ export class EcdsaMPCv2Utils extends BaseEcdsaUtils {
11741191

11751192
const round1Session = this.bitgo.decrypt({ input: encryptedRound1Session, password: walletPassphrase });
11761193

1177-
this.validateAdata(adata, encryptedRound1Session);
1194+
this.validateAdata(adata, encryptedRound1Session, EcdsaMPCv2Utils.DKLS23_SIGNING_ROUND1_STATE);
11781195
const userKeyShare = Buffer.from(prv, 'base64');
11791196
const userSigner = new DklsDsg.Dsg(userKeyShare, 0, derivationPath, hashBuffer);
11801197
await userSigner.setSession(round1Session);
@@ -1195,7 +1212,11 @@ export class EcdsaMPCv2Utils extends BaseEcdsaUtils {
11951212
bitgoGpgKey
11961213
);
11971214
const session = userSigner.getSession();
1198-
const encryptedRound2Session = this.bitgo.encrypt({ input: session, password: walletPassphrase, adata });
1215+
const encryptedRound2Session = this.bitgo.encrypt({
1216+
input: session,
1217+
password: walletPassphrase,
1218+
adata: `${EcdsaMPCv2Utils.DKLS23_SIGNING_ROUND2_STATE}:${adata}`,
1219+
});
11991220

12001221
return {
12011222
signatureShareRound2,
@@ -1223,7 +1244,8 @@ export class EcdsaMPCv2Utils extends BaseEcdsaUtils {
12231244
const { bitgoGpgKey, userGpgKey } = await this.getBitgoAndUserGpgKeys(
12241245
bitgoPublicGpgKey,
12251246
encryptedUserGpgPrvKey,
1226-
walletPassphrase
1247+
walletPassphrase,
1248+
adata
12271249
);
12281250

12291251
const signatureShares = txRequest.transactions?.[0].signatureShares;
@@ -1246,7 +1268,7 @@ export class EcdsaMPCv2Utils extends BaseEcdsaUtils {
12461268
});
12471269

12481270
const round2Session = this.bitgo.decrypt({ input: encryptedRound2Session, password: walletPassphrase });
1249-
this.validateAdata(adata, encryptedRound2Session);
1271+
this.validateAdata(adata, encryptedRound2Session, EcdsaMPCv2Utils.DKLS23_SIGNING_ROUND2_STATE);
12501272
const userKeyShare = Buffer.from(prv, 'base64');
12511273
const userSigner = new DklsDsg.Dsg(userKeyShare, 0, derivationPath, hashBuffer);
12521274
await userSigner.setSession(round2Session);

0 commit comments

Comments
 (0)