Skip to content

Commit 3c86a09

Browse files
fix: store private mpcv2 prv with local encryption
Ticket: WP-5150
1 parent 48935d9 commit 3c86a09

File tree

10 files changed

+72
-28
lines changed

10 files changed

+72
-28
lines changed

src/__tests__/api/enclaved/postMpcV2Key.test.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,28 @@ describe('postMpcV2Key', () => {
7373
})
7474
.persist();
7575

76+
nock(kmsUrl)
77+
.post(`/key`)
78+
.reply(200, {
79+
pub: 'test-pub-key',
80+
coin,
81+
source: 'user',
82+
type: 'tss',
83+
})
84+
.persist();
85+
86+
nock(kmsUrl)
87+
.post(`/key`)
88+
.reply(200, {
89+
pub: 'test-pub-key',
90+
coin,
91+
source: 'backup',
92+
type: 'tss',
93+
})
94+
.persist();
95+
96+
nock(kmsUrl).post(`/postKey`).reply(200, {}).persist();
97+
7698
// mocking bitgo's GPG key generation session
7799
const bitgoGpgKey = await bitgoSdk.generateGPGKeyPair('secp256k1');
78100
const bitgoGpgPub = {

src/__tests__/api/enclaved/recoveryMusigEth.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,12 @@ describe('recoveryMultisigTransaction', () => {
7878

7979
const kmsNockUser = nock(kmsUrl)
8080
.get(`/key/${userPub}`)
81-
.query({ source: 'user' })
81+
.query({ source: 'user', useLocalEncipherment: false })
8282
.reply(200, mockKmsUserResponse);
8383

8484
const kmsNockBackup = nock(kmsUrl)
8585
.get(`/key/${backupPub}`)
86-
.query({ source: 'backup' })
86+
.query({ source: 'backup', useLocalEncipherment: false })
8787
.reply(200, mockKmsBackupResponse);
8888

8989
console.warn(nock.activeMocks());
@@ -132,12 +132,12 @@ describe('recoveryMultisigTransaction', () => {
132132

133133
const kmsNockUser = nock(kmsUrl)
134134
.get(`/key/${userPub}`)
135-
.query({ source: 'user' })
135+
.query({ source: 'user', useLocalEncipherment: false })
136136
.reply(200, mockKmsUserResponse);
137137

138138
const kmsNockBackup = nock(kmsUrl)
139139
.get(`/key/${backupPub}`)
140-
.query({ source: 'backup' })
140+
.query({ source: 'backup', useLocalEncipherment: false })
141141
.reply(200, mockKmsBackupResponse);
142142

143143
const response = await agent

src/__tests__/api/enclaved/signMpcTransaction.test.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ describe('signMpcTransaction', () => {
133133
// Mock KMS responses
134134
const kmsNock = nock(kmsUrl)
135135
.get(`/key/${input.pub}`)
136-
.query({ source: 'user' })
136+
.query({ source: 'user', useLocalEncipherment: false })
137137
.reply(200, mockKmsResponse);
138138

139139
const dataKeyNock = nock(kmsUrl).post('/generateDataKey').reply(200, mockDataKeyResponse);
@@ -171,7 +171,7 @@ describe('signMpcTransaction', () => {
171171
// Mock KMS responses for R share
172172
const rKmsNock = nock(kmsUrl)
173173
.get(`/key/${rInput.pub}`)
174-
.query({ source: 'user' })
174+
.query({ source: 'user', useLocalEncipherment: false })
175175
.reply(200, mockKmsResponse);
176176

177177
const decryptDataKeyNock = nock(kmsUrl)
@@ -233,7 +233,7 @@ describe('signMpcTransaction', () => {
233233
// Mock KMS response for G share
234234
const gKmsNock = nock(kmsUrl)
235235
.get(`/key/${gInput.pub}`)
236-
.query({ source: 'user' })
236+
.query({ source: 'user', useLocalEncipherment: false })
237237
.reply(200, mockKmsResponse);
238238

239239
const gResponse = await agent
@@ -261,7 +261,7 @@ describe('signMpcTransaction', () => {
261261

262262
const kmsNock = nock(kmsUrl)
263263
.get(`/key/${input.pub}`)
264-
.query({ source: 'user' })
264+
.query({ source: 'user', useLocalEncipherment: false })
265265
.reply(404, { error: 'Key not found' });
266266

267267
const response = await agent
@@ -300,7 +300,7 @@ describe('signMpcTransaction', () => {
300300

301301
const kmsNock = nock(kmsUrl)
302302
.get(`/key/${input.pub}`)
303-
.query({ source: 'user' })
303+
.query({ source: 'user', useLocalEncipherment: false })
304304
.reply(200, mockKmsResponse);
305305

306306
const response = await agent
@@ -400,7 +400,7 @@ describe('signMpcTransaction', () => {
400400
// Mock KMS responses for Round 1
401401
const kmsNock = nock(kmsUrl)
402402
.get(`/key/${round1Input.pub}`)
403-
.query({ source: 'user' })
403+
.query({ source: 'user', useLocalEncipherment: true })
404404
.reply(200, mockKmsResponse);
405405

406406
const dataKeyNock = nock(kmsUrl).post('/generateDataKey').reply(200, mockDataKeyResponse);
@@ -462,7 +462,7 @@ describe('signMpcTransaction', () => {
462462
// Mock KMS responses for Round 2
463463
const r2KmsNock = nock(kmsUrl)
464464
.get(`/key/${round2Input.pub}`)
465-
.query({ source: 'user' })
465+
.query({ source: 'user', useLocalEncipherment: true })
466466
.reply(200, mockKmsResponse);
467467

468468
const decryptDataKeyNock = nock(kmsUrl)
@@ -510,7 +510,7 @@ describe('signMpcTransaction', () => {
510510
// Mock KMS responses for Round 3
511511
const r3KmsNock = nock(kmsUrl)
512512
.get(`/key/${round3Input.pub}`)
513-
.query({ source: 'user' })
513+
.query({ source: 'user', useLocalEncipherment: true })
514514
.reply(200, mockKmsResponse);
515515

516516
const r3DecryptDataKeyNock = nock(kmsUrl)
@@ -592,7 +592,7 @@ describe('signMpcTransaction', () => {
592592

593593
const kmsNock = nock(kmsUrl)
594594
.get(`/key/${input.pub}`)
595-
.query({ source: 'user' })
595+
.query({ source: 'user', useLocalEncipherment: true })
596596
.reply(200, mockKmsResponse);
597597

598598
const response = await agent
@@ -627,7 +627,7 @@ describe('signMpcTransaction', () => {
627627

628628
const kmsNock = nock(kmsUrl)
629629
.get(`/key/${input.pub}`)
630-
.query({ source: 'user' })
630+
.query({ source: 'user', useLocalEncipherment: true })
631631
.reply(200, mockKmsResponse);
632632

633633
const response = await agent
@@ -658,7 +658,7 @@ describe('signMpcTransaction', () => {
658658

659659
const kmsNock = nock(kmsUrl)
660660
.get(`/key/${input.pub}`)
661-
.query({ source: 'user' })
661+
.query({ source: 'user', useLocalEncipherment: true })
662662
.reply(200, mockKmsResponse);
663663

664664
const response = await agent

src/__tests__/api/enclaved/signMultisigTransaction.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ describe('signMultisigTransaction', () => {
105105

106106
const kmsNock = nock(kmsUrl)
107107
.get(`/key/${input.pub}`)
108-
.query({ source: 'user' })
108+
.query({ source: 'user', useLocalEncipherment: false })
109109
.reply(200, mockKmsResponse);
110110

111111
const response = await agent

src/api/enclaved/handlers/mpcV2Finalize.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import {
66
} from '../../../enclavedBitgoExpress/routers/enclavedApiSpec';
77
import { KmsClient } from '../../../kms/kmsClient';
88
import assert from 'assert';
9-
import { MPCv2PartiesEnum } from '@bitgo/sdk-core/dist/src/bitgo/utils/tss/ecdsa';
109

1110
export async function mpcV2Finalize(
1211
req: EnclavedApiSpecRouteRequest<'v1.mpcv2.finalize', 'post'>,
@@ -35,12 +34,7 @@ export async function mpcV2Finalize(
3534
throw new Error('Session data is missing for finalization');
3635
}
3736
sessionData.dkgSessionBytes = new Uint8Array(Object.values(sessionData.dkgSessionBytes));
38-
const session = await DklsDkg.Dkg.restoreSession(
39-
3,
40-
2,
41-
source === 'user' ? MPCv2PartiesEnum.USER : MPCv2PartiesEnum.BACKUP,
42-
sessionData,
43-
);
37+
const session = await DklsDkg.Dkg.restoreSession(3, 2, source === 'user' ? 0 : 1, sessionData);
4438

4539
// processing incoming messages
4640
const incomingMessages = await DklsComms.decryptAndVerifyIncomingMessages(
@@ -65,6 +59,17 @@ export async function mpcV2Finalize(
6559
'Source and Bitgo Common keychains do not match',
6660
);
6761

62+
await kms.postKey({
63+
coin: req.decoded.coin,
64+
source: req.decoded.source,
65+
pub: commonKeychain,
66+
prv: privateMaterial.toString('base64'),
67+
type: 'tss',
68+
options: {
69+
useLocalEncipherment: true,
70+
},
71+
});
72+
6873
return {
6974
source,
7075
commonKeychain,

src/api/enclaved/handlers/signMpcTransaction.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,15 @@ export async function signMpcTransaction(req: EnclavedApiSpecRouteRequest<'v1.mp
8989

9090
const bitgo = req.bitgo;
9191
const coinInstance = bitgo.coin(coin);
92+
const options =
93+
coinInstance.getMPCAlgorithm() === 'ecdsa'
94+
? {
95+
useLocalEncipherment: true,
96+
}
97+
: undefined;
9298

9399
// Get private key from KMS
94-
const prv = await retrieveKmsPrvKey({ pub, source, cfg: req.config });
100+
const prv = await retrieveKmsPrvKey({ pub, source, cfg: req.config, options });
95101

96102
if (!prv) {
97103
const errorMsg = `Error while MPC signing, missing prv key for pub=${pub}, source=${source}`;

src/api/enclaved/utils.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,20 @@ export async function retrieveKmsPrvKey({
88
pub,
99
source,
1010
cfg,
11+
options,
1112
}: {
1213
pub: string;
1314
source: string;
1415
cfg: EnclavedConfig;
16+
options?: {
17+
useLocalEncipherment?: boolean;
18+
};
1519
}): Promise<string> {
1620
const kms = new KmsClient(cfg);
1721
// Retrieve the private key from KMS
1822
let prv: string;
1923
try {
20-
const res = await kms.getKey({ pub, source });
24+
const res = await kms.getKey({ pub, source, options });
2125
prv = res.prv;
2226
return prv;
2327
} catch (error: any) {

src/kms/kmsClient.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,10 @@ export class KmsClient {
6363
// Call KMS to get the key
6464
let kmsResponse: any;
6565
try {
66-
kmsResponse = await superagent
67-
.get(`${this.url}/key/${params.pub}`)
68-
.query({ source: params.source });
66+
kmsResponse = await superagent.get(`${this.url}/key/${params.pub}`).query({
67+
source: params.source,
68+
useLocalEncipherment: params.options?.useLocalEncipherment ?? false,
69+
});
6970
} catch (error: any) {
7071
console.log('Error getting key from KMS', error);
7172
throw error;

src/kms/types/getKey.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ import * as z from 'zod';
33
export interface GetKeyParams {
44
pub: string;
55
source: string;
6+
options?: {
7+
useLocalEncipherment?: boolean;
8+
};
69
}
710

811
export interface GetKeyResponse {

src/kms/types/postKey.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ export interface PostKeyParams {
77
source: string;
88
type: 'independent' | 'tss';
99
seed?: string; // Optional seed for key generation
10+
options?: {
11+
useLocalEncipherment?: boolean;
12+
};
1013
}
1114

1215
export interface PostKeyResponse {

0 commit comments

Comments
 (0)