diff --git a/src/__tests__/api/advancedWalletManager/postMpcV2Key.test.ts b/src/__tests__/api/advancedWalletManager/postMpcV2Key.test.ts index 634aeeca..26be2410 100644 --- a/src/__tests__/api/advancedWalletManager/postMpcV2Key.test.ts +++ b/src/__tests__/api/advancedWalletManager/postMpcV2Key.test.ts @@ -21,8 +21,8 @@ describe('postMpcV2Key', () => { const coin = 'hteth'; const accessToken = 'test-token'; - // sinon stubs - let configStub: sinon.SinonStub; + // sinon sandbox + const sandbox = sinon.createSandbox(); before(() => { // nock config @@ -42,7 +42,7 @@ describe('postMpcV2Key', () => { clientCertAllowSelfSigned: true, }; - configStub = sinon.stub(configModule, 'initConfig').returns(cfg); + sandbox.stub(configModule, 'initConfig').returns(cfg); // app setup app = advancedWalletManagerApp(cfg); @@ -93,7 +93,7 @@ describe('postMpcV2Key', () => { }); after(() => { - configStub.restore(); + sandbox.restore(); }); it('should be able to create a new MPC V2 wallet', async () => { diff --git a/src/__tests__/api/advancedWalletManager/recoveryMpc.test.ts b/src/__tests__/api/advancedWalletManager/recoveryMpc.test.ts index 93939f0a..971ac2a8 100644 --- a/src/__tests__/api/advancedWalletManager/recoveryMpc.test.ts +++ b/src/__tests__/api/advancedWalletManager/recoveryMpc.test.ts @@ -142,6 +142,85 @@ describe('recoveryMpc', () => { }); }); + describe('EdDSA dual-KMS recovery', () => { + it('should route backup key retrieval to backup KMS when configured', async () => { + const primaryKmsUrl = 'http://primary-kms.invalid'; + const backupKmsUrl = 'http://backup-kms.invalid'; + + const commonKeychain = + 'b6f5fb808f538a32735a89609e98fab75690a2c79b26f50a54c4cbf0fbca287138b733783f1590e12b4916ef0f6053b22044860117274bda44bd5d711855f174'; + + const mockKmsUserResponse = { + prv: '{"uShare":{"i":1,"t":2,"n":3,"y":"85aa6462d927329418f70f6d0863cf6cf33e7da2934f935e5927f1b13062d779","seed":"2f55c80fd6b5583dcde8037b2ee461d2e7d445a4d3e7a9b2a0d3d00b5f534169","chaincode":"66e80f2bf41a5706608352d51ceb07a5aa1729cab6c6993c124d5731546ed9a1"},"bitgoYShare":{"i":1,"j":3,"y":"483e53b72de3aa893df698d0b20b20777fb3d2716cc8483a9e9797174fd52b16","v":"e70696459e46434a2a12cc988e3ae714a61fe96da8a6764d058b849cab50d6dc","u":"49abf8144d265a77cf6d098eff784d6ce56ec77a182f6b39f47d5d8e28f2a802","chaincode":"797348468202f1d7fede0a7851f80162b02e7da306e65075dd864b6789b9bc5b"},"backupYShare":{"i":1,"j":2,"y":"249a9798d0064a989a16cd8f479edf09ffaee73f4175d2ac555ba90ff41b89da","v":"98e31d2b643e40060ba344c6a41fc096ea7e39a1ae879f65e4af645870e90ee0","u":"ac047b1bceab2e1a42d97ab540b39176e545d9c0af4a192aee8e1dae91a4240b","chaincode":"585bdc05c8f84802cbe7b9a1a07d4aa9c5fede93597a622854e9bad83a2d5b78"}}', + pub: commonKeychain, + source: 'user', + type: 'tss', + }; + + const mockKmsBackupResponse = { + prv: '{"uShare":{"i":2,"t":2,"n":3,"y":"249a9798d0064a989a16cd8f479edf09ffaee73f4175d2ac555ba90ff41b89da","seed":"abab5be2b32d07cf39b2a162af0f78bad8325b2fbdc89d14fd8b4e5767b74097","chaincode":"585bdc05c8f84802cbe7b9a1a07d4aa9c5fede93597a622854e9bad83a2d5b78"},"bitgoYShare":{"i":2,"j":3,"y":"483e53b72de3aa893df698d0b20b20777fb3d2716cc8483a9e9797174fd52b16","v":"e70696459e46434a2a12cc988e3ae714a61fe96da8a6764d058b849cab50d6dc","u":"eb54da28da3da22eb3d61797a02a96264be8940b7115aefbb90b9dd044db7f06","chaincode":"797348468202f1d7fede0a7851f80162b02e7da306e65075dd864b6789b9bc5b"},"userYShare":{"i":2,"j":1,"y":"85aa6462d927329418f70f6d0863cf6cf33e7da2934f935e5927f1b13062d779","v":"76cfdcbf0f769f21c64e0faf0072ebccbcc3aaa844522336af27f8e50ed7ca5f","u":"6ce814af82683423c8d8befd13f6eeeb0cd3f7274d1ebfdd5807fd2e4eaadb08","chaincode":"66e80f2bf41a5706608352d51ceb07a5aa1729cab6c6993c124d5731546ed9a1"}}', + pub: commonKeychain, + source: 'backup', + type: 'tss', + }; + + const dualCfg: AdvancedWalletManagerConfig = { + appMode: AppMode.ADVANCED_WALLET_MANAGER, + signingMode: SigningMode.LOCAL, + port: 0, + bind: 'localhost', + timeout: 60000, + keyProviderUrl: primaryKmsUrl, + backupKmsUrl, + httpLoggerFile: '', + tlsMode: TlsMode.DISABLED, + recoveryMode: true, + }; + + const dualApp = expressApp(dualCfg); + const dualAgent = request.agent(dualApp); + + // User key served from primary KMS + const userKmsNock = nock(primaryKmsUrl) + .get(`/key/${commonKeychain}`) + .query({ source: 'user' }) + .reply(200, mockKmsUserResponse) + .persist(); + + // Backup key served from backup KMS + const backupKmsNock = nock(backupKmsUrl) + .get(`/key/${commonKeychain}`) + .query({ source: 'backup' }) + .reply(200, mockKmsBackupResponse) + .persist(); + + const input = { + commonKeychain, + unsignedSweepPrebuildTx: { + txRequests: [ + { + unsignedTx: '', + signableHex: + 'AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAECvoOqYkvCPusjYyhX4GdUtzSeVIcx6GkwdpSk8SkU0/cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIQtFGO2YBsrubq15CKqJLwXG3VEF1aEs36Rao6EaJDLAQECAAAMAgAAALhJxgAAAAAA', + derivationPath: 'm/0', + }, + ], + }, + }; + + const response = await dualAgent + .post(`/api/${sol}/mpc/recovery`) + .set('Authorization', `Bearer ${accessToken}`) + .send(input); + + response.status.should.equal(200); + response.body.should.have.property('txHex'); + + userKmsNock.isDone().should.be.true(); + backupKmsNock.isDone().should.be.true(); + }); + }); + describe('ECDSA sui recovery', () => { it('should successfully generate MPC sui transactions', async () => { const mockKeyProviderUserResponse = { diff --git a/src/__tests__/api/advancedWalletManager/recoveryMpcV2.test.ts b/src/__tests__/api/advancedWalletManager/recoveryMpcV2.test.ts index c6b971d6..78128c11 100644 --- a/src/__tests__/api/advancedWalletManager/recoveryMpcV2.test.ts +++ b/src/__tests__/api/advancedWalletManager/recoveryMpcV2.test.ts @@ -20,24 +20,22 @@ describe('recoveryMpcV2', () => { const cosmosLikeCoin = 'tsei'; const accessToken = 'test-token'; - // sinon stubs + // sinon sandbox + const sandbox = sinon.createSandbox(); let configStub: sinon.SinonStub; - // key provider nocks setup — initialized in before() - let commonKeychain!: string; + // key provider nocks setup + let userKeyShare: string; + let backupKeyShare: string; + let commonKeychain: string; let mockKeyProviderUserResponse: { prv: string; pub: string; source: string; type: string }; let mockKeyProviderBackupResponse: { prv: string; pub: string; source: string; type: string }; let input: { txHex: string; pub: string }; before(async () => { - // nock config - nock.disableNetConnect(); - nock.enableNetConnect('127.0.0.1'); - - // generate DKG key shares const [userShare, backupShare] = await DklsUtils.generateDKGKeyShares(); - const userKeyShare = userShare.getKeyShare().toString('base64'); - const backupKeyShare = backupShare.getKeyShare().toString('base64'); + userKeyShare = userShare.getKeyShare().toString('base64'); + backupKeyShare = backupShare.getKeyShare().toString('base64'); commonKeychain = DklsTypes.getCommonKeychain(userShare.getKeyShare()); mockKeyProviderUserResponse = { @@ -60,6 +58,10 @@ describe('recoveryMpcV2', () => { pub: commonKeychain, }; + // nock config + nock.disableNetConnect(); + nock.enableNetConnect('127.0.0.1'); + // app config cfg = { appMode: AppMode.ADVANCED_WALLET_MANAGER, @@ -74,7 +76,7 @@ describe('recoveryMpcV2', () => { recoveryMode: true, }; - configStub = sinon.stub(configModule, 'initConfig').returns(cfg); + configStub = sandbox.stub(configModule, 'initConfig').returns(cfg); // app setup app = advancedWalletManagerApp(cfg); @@ -86,7 +88,7 @@ describe('recoveryMpcV2', () => { }); after(() => { - configStub.restore(); + sandbox.restore(); }); // happy path test @@ -139,6 +141,61 @@ describe('recoveryMpcV2', () => { backupKeyProviderNock.isDone().should.be.true(); }); + it('should route backup key retrieval to backup KMS when configured', async () => { + const kmsUrl = 'http://kms.invalid'; + const backupKmsUrl = 'http://backup-kms.invalid'; + + const mockKmsUserResponse = { + prv: JSON.stringify(userKeyShare), + pub: commonKeychain, + source: 'user', + type: 'tss', + }; + + const mockKmsBackupResponse = { + prv: JSON.stringify(backupKeyShare), + pub: commonKeychain, + source: 'backup', + type: 'tss', + }; + + // Reconfigure app with backup KMS URL + const dualCfg: AdvancedWalletManagerConfig = { + ...cfg, + keyProviderUrl: kmsUrl, + backupKmsUrl, + }; + configStub.returns(dualCfg); + const dualApp = advancedWalletManagerApp(dualCfg); + const dualAgent = request.agent(dualApp); + + // User key served from primary KMS + const userKmsNock = nock(kmsUrl) + .get(`/key/${input.pub}`) + .query({ source: 'user' }) + .reply(200, mockKmsUserResponse) + .persist(); + + // Backup key served from backup KMS + const backupKmsNock = nock(backupKmsUrl) + .get(`/key/${input.pub}`) + .query({ source: 'backup' }) + .reply(200, mockKmsBackupResponse) + .persist(); + + const response = await dualAgent + .post(`/api/${ethLikeCoin}/mpcv2/recovery`) + .set('Authorization', `Bearer ${accessToken}`) + .send(input); + + response.status.should.equal(200); + response.body.should.have.property('txHex'); + response.body.should.have.property('stringifiedSignature'); + + userKmsNock.isDone().should.be.true(); + backupKmsNock.isDone().should.be.true(); + }); + // failure test case it('should throw 400 Bad Request if failed to construct eth transaction from message hex', async () => { const input = { diff --git a/src/__tests__/api/advancedWalletManager/recoveryMusigEth.test.ts b/src/__tests__/api/advancedWalletManager/recoveryMusigEth.test.ts index a9436ddc..b2b4ff6c 100644 --- a/src/__tests__/api/advancedWalletManager/recoveryMusigEth.test.ts +++ b/src/__tests__/api/advancedWalletManager/recoveryMusigEth.test.ts @@ -22,7 +22,8 @@ describe('recoveryMultisigTransaction', () => { const coin = 'hteth'; const accessToken = 'test-token'; - // sinon stubs + // sinon sandbox + const sandbox = sinon.createSandbox(); let configStub: sinon.SinonStub; before(() => { @@ -44,7 +45,7 @@ describe('recoveryMultisigTransaction', () => { recoveryMode: true, }; - configStub = sinon.stub(configModule, 'initConfig').returns(cfg); + configStub = sandbox.stub(configModule, 'initConfig').returns(cfg); // app setup app = advancedWalletManagerApp(cfg); @@ -56,7 +57,7 @@ describe('recoveryMultisigTransaction', () => { }); after(() => { - configStub.restore(); + sandbox.restore(); }); it('should generate a successful txHex from unsigned sweep prebuild data', async () => { @@ -106,6 +107,67 @@ describe('recoveryMultisigTransaction', () => { keyProviderNockBackup.done(); }); + it('should route backup key retrieval to backup KMS when configured', async () => { + const kmsUrl = 'http://kms.invalid'; + const backupKmsUrl = 'http://backup-kms.invalid'; + const { userPub, backupPub, walletContractAddress, userPrv, backupPrv, txHexResult } = awmData; + const unsignedSweepPrebuildTx = unsignedSweepRecJSON as unknown as any; + + // Reconfigure app with backup KMS URL + const dualCfg: AdvancedWalletManagerConfig = { + ...cfg, + keyProviderUrl: kmsUrl, + backupKmsUrl, + }; + configStub.returns(dualCfg); + const dualApp = advancedWalletManagerApp(dualCfg); + const dualAgent = request.agent(dualApp); + + const mockKmsUserResponse = { + prv: userPrv, + pub: userPub, + source: 'user', + type: 'independent', + }; + + const mockKmsBackupResponse = { + prv: backupPrv, + pub: backupPub, + source: 'backup', + type: 'independent', + }; + + // User key from primary KMS + const kmsNockUser = nock(kmsUrl) + .get(`/key/${userPub}`) + .query({ source: 'user' }) + .reply(200, mockKmsUserResponse); + + // Backup key from backup KMS + const kmsNockBackup = nock(backupKmsUrl) + .get(`/key/${backupPub}`) + .query({ source: 'backup' }) + .reply(200, mockKmsBackupResponse); + + const response = await dualAgent + .post(`/api/${coin}/multisig/recovery`) + .set('Authorization', `Bearer ${accessToken}`) + .send({ + userPub, + backupPub, + apiKey: 'etherscan-api-token', + unsignedSweepPrebuildTx, + walletContractAddress, + coinSpecificParams: undefined, + }); + + response.status.should.equal(200); + response.body.should.have.property('txHex', txHexResult); + + kmsNockUser.done(); + kmsNockBackup.done(); + }); + it('should fail when prv keys non related to pub keys', async () => { const { userPub, backupPub, walletContractAddress } = awmData; const unsignedSweepPrebuildTx = unsignedSweepRecJSON as unknown as any; diff --git a/src/advancedWalletManager/handlers/ecdsaMPCV2Recovery.ts b/src/advancedWalletManager/handlers/ecdsaMPCV2Recovery.ts index af957421..25a2ee04 100644 --- a/src/advancedWalletManager/handlers/ecdsaMPCV2Recovery.ts +++ b/src/advancedWalletManager/handlers/ecdsaMPCV2Recovery.ts @@ -3,12 +3,12 @@ import { AwmApiSpecRouteRequest, MpcV2RecoveryResponseType, } from '../routers/advancedWalletManagerApiSpec'; -import { KeyProviderClient } from '../keyProviderClient/keyProviderClient'; import { BaseCoin, ECDSAMethodTypes } from '@bitgo-beta/sdk-core'; import { isCosmosLikeCoin, isEcdsaCoin, isEthLikeCoin } from '../../shared/coinUtils'; import { BadRequestError, NotImplementedError } from '../../shared/errors'; import logger from '../../shared/logger'; import coinFactory from '../../shared/coinFactory'; +import { buildBackupKmsConfig, retrieveKeyProviderPrvKey } from './utils/utils'; async function getMessageHash(coin: BaseCoin, txHex: string): Promise { const txBuffer = Buffer.from(txHex, 'hex'); @@ -52,11 +52,10 @@ export async function ecdsaMPCv2Recovery( ); } - // setup clients and retreive the keys - // TODO: this needs to be segerated if the EBE instance cannot retrieve both keys - const keyProvider = new KeyProviderClient(req.config); - const { prv: userPrv } = await keyProvider.getKey({ pub, source: 'user' }); - const { prv: backupPrv } = await keyProvider.getKey({ pub, source: 'backup' }); + // setup clients and retrieve the keys + const backupCfg = buildBackupKmsConfig(req.config); + const userPrv = await retrieveKeyProviderPrvKey({ pub, source: 'user', cfg: req.config }); + const backupPrv = await retrieveKeyProviderPrvKey({ pub, source: 'backup', cfg: backupCfg }); // construct tx builder const txHash = await getMessageHash(coin, txHex); diff --git a/src/advancedWalletManager/handlers/utils/utils.ts b/src/advancedWalletManager/handlers/utils/utils.ts index 02fd6f11..a3faa707 100644 --- a/src/advancedWalletManager/handlers/utils/utils.ts +++ b/src/advancedWalletManager/handlers/utils/utils.ts @@ -8,6 +8,30 @@ import { GenerateDataKeyResponse } from '../../keyProviderClient/types/dataKey'; import { AdvancedWalletManagerConfig, KeySource, SigningMode } from '../../../shared/types'; import { isUtxoCoin } from '../../../shared/coinUtils'; +export function buildBackupKmsConfig( + cfg: AdvancedWalletManagerConfig, +): AdvancedWalletManagerConfig { + if (!cfg.backupKmsUrl) { + return cfg; + } + return { + ...cfg, + keyProviderUrl: cfg.backupKmsUrl, + ...(cfg.backupKmsServerCaCert !== undefined && { + keyProviderServerCaCert: cfg.backupKmsServerCaCert, + }), + ...(cfg.backupKmsClientTlsKey !== undefined && { + keyProviderClientTlsKey: cfg.backupKmsClientTlsKey, + }), + ...(cfg.backupKmsClientTlsCert !== undefined && { + keyProviderClientTlsCert: cfg.backupKmsClientTlsCert, + }), + ...(cfg.backupKmsServerCertAllowSelfSigned !== true && { + keyProviderServerCertAllowSelfSigned: cfg.backupKmsServerCertAllowSelfSigned, + }), + }; +} + export async function retrieveKeyProviderPrvKey({ pub, source, @@ -17,7 +41,8 @@ export async function retrieveKeyProviderPrvKey({ source: string; cfg: AdvancedWalletManagerConfig; }): Promise { - const keyProvider = new KeyProviderClient(cfg); + const effectiveCfg = source === 'backup' ? buildBackupKmsConfig(cfg) : cfg; + const keyProvider = new KeyProviderClient(effectiveCfg); // Retrieve the private key from key provider let prv: string; try { diff --git a/src/advancedWalletManager/routers/advancedWalletManagerApiSpec.ts b/src/advancedWalletManager/routers/advancedWalletManagerApiSpec.ts index 0b84ace0..3a07cb7a 100644 --- a/src/advancedWalletManager/routers/advancedWalletManagerApiSpec.ts +++ b/src/advancedWalletManager/routers/advancedWalletManagerApiSpec.ts @@ -72,6 +72,11 @@ const RecoveryMultisigRequest = { bitgoPub: optional(t.string), unsignedSweepPrebuildTx: t.any, walletContractAddress: optional(t.string), + // When set, only sign with the specified key (user half-sign or backup full-sign). + // When omitted, the endpoint signs with both keys (default single-AWM behavior). + keyToSign: optional(t.union([t.literal('user'), t.literal('backup')])), + // Required when keyToSign is 'backup': the half-signed transaction from the user-key phase. + halfSignedTransaction: optional(t.any), }; // Response type for /multisig/recovery endpoint diff --git a/src/initConfig.ts b/src/initConfig.ts index 08cabe9d..62b5fad7 100644 --- a/src/initConfig.ts +++ b/src/initConfig.ts @@ -161,6 +161,16 @@ function advancedWalletManagerEnvConfig(): Partial keyProviderClientTlsCert: readEnvVar('KEY_PROVIDER_CLIENT_TLS_CERT'), keyProviderServerCertAllowSelfSigned: readEnvVar('KEY_PROVIDER_SERVER_CERT_ALLOW_SELF_SIGNED') === 'true', + // backup KMS settings + backupKmsUrl: readEnvVar('BACKUP_KMS_URL'), + backupKmsServerCaCertPath: readEnvVar('BACKUP_KMS_SERVER_CA_CERT_PATH'), + backupKmsServerCaCert: readEnvVar('BACKUP_KMS_SERVER_CA_CERT'), + backupKmsClientTlsKeyPath: readEnvVar('BACKUP_KMS_CLIENT_TLS_KEY_PATH'), + backupKmsClientTlsCertPath: readEnvVar('BACKUP_KMS_CLIENT_TLS_CERT_PATH'), + backupKmsClientTlsKey: readEnvVar('BACKUP_KMS_CLIENT_TLS_KEY'), + backupKmsClientTlsCert: readEnvVar('BACKUP_KMS_CLIENT_TLS_CERT'), + backupKmsServerCertAllowSelfSigned: + readEnvVar('BACKUP_KMS_SERVER_CERT_ALLOW_SELF_SIGNED') === 'true', // mTLS server settings serverTlsKeyPath: readEnvVar('SERVER_TLS_KEY_PATH'), serverTlsCertPath: readEnvVar('SERVER_TLS_CERT_PATH'), @@ -202,6 +212,15 @@ function mergeAkmConfigs( keyProviderClientTlsKey: get('keyProviderClientTlsKey'), keyProviderClientTlsCert: get('keyProviderClientTlsCert'), keyProviderServerCertAllowSelfSigned: get('keyProviderServerCertAllowSelfSigned'), + // Backup KMS configs + backupKmsUrl: get('backupKmsUrl'), + backupKmsServerCaCertPath: get('backupKmsServerCaCertPath'), + backupKmsServerCaCert: get('backupKmsServerCaCert'), + backupKmsClientTlsKeyPath: get('backupKmsClientTlsKeyPath'), + backupKmsClientTlsCertPath: get('backupKmsClientTlsCertPath'), + backupKmsClientTlsKey: get('backupKmsClientTlsKey'), + backupKmsClientTlsCert: get('backupKmsClientTlsCert'), + backupKmsServerCertAllowSelfSigned: get('backupKmsServerCertAllowSelfSigned'), serverTlsKeyPath: get('serverTlsKeyPath'), serverTlsCertPath: get('serverTlsCertPath'), serverTlsKey: get('serverTlsKey'), @@ -260,6 +279,36 @@ function configureAdvancedWalletManagerMode(): AdvancedWalletManagerConfig { validateTlsCertificates(config); } + // Handle cert loading for backup KMS (only when backup KMS URL is configured) + if (config.backupKmsUrl) { + config = { + ...config, + backupKmsServerCaCert: loadCert( + config.backupKmsServerCaCert, + config.backupKmsServerCaCertPath, + 'Backup KMS server CA certificate', + ), + backupKmsClientTlsKey: loadCert( + config.backupKmsClientTlsKey, + config.backupKmsClientTlsKeyPath, + 'Backup KMS client key', + ), + backupKmsClientTlsCert: loadCert( + config.backupKmsClientTlsCert, + config.backupKmsClientTlsCertPath, + 'Backup KMS client certificate', + ), + }; + + if (config.tlsMode === TlsMode.MTLS) { + if (!config.backupKmsClientTlsKey || !config.backupKmsClientTlsCert) { + throw new Error( + 'BACKUP_KMS_CLIENT_TLS_KEY_PATH and BACKUP_KMS_CLIENT_TLS_CERT_PATH (or BACKUP_KMS_CLIENT_TLS_KEY and BACKUP_KMS_CLIENT_TLS_CERT) are required for outbound mTLS connections to backup KMS when BACKUP_KMS_URL is configured.', + ); + } + } + } + logger.info('=========================='); return config; diff --git a/src/masterBitgoExpress/clients/advancedWalletManagerClient.ts b/src/masterBitgoExpress/clients/advancedWalletManagerClient.ts index 10352446..ff39ca61 100644 --- a/src/masterBitgoExpress/clients/advancedWalletManagerClient.ts +++ b/src/masterBitgoExpress/clients/advancedWalletManagerClient.ts @@ -99,6 +99,10 @@ interface RecoveryMultisigOptions { | MPCTx | RecoveryTransaction; walletContractAddress: string; + // When set, only sign with the specified key (user half-sign or backup full-sign). + keyToSign?: 'user' | 'backup'; + // Required when keyToSign is 'backup': the half-signed transaction from the user-key phase. + halfSignedTransaction?: any; } interface SignMpcCommitmentParams { diff --git a/src/shared/types/index.ts b/src/shared/types/index.ts index 219b2f6a..e12a7665 100644 --- a/src/shared/types/index.ts +++ b/src/shared/types/index.ts @@ -46,6 +46,16 @@ export interface AdvancedWalletManagerConfig extends BaseConfig { keyProviderClientTlsCert?: string; keyProviderServerCertAllowSelfSigned?: boolean; + // Backup KMS settings (separate HSM for backup key) + backupKmsUrl?: string; + backupKmsServerCaCertPath?: string; + backupKmsServerCaCert?: string; + backupKmsClientTlsKeyPath?: string; + backupKmsClientTlsCertPath?: string; + backupKmsClientTlsKey?: string; + backupKmsClientTlsCert?: string; + backupKmsServerCertAllowSelfSigned?: boolean; + // mTLS server settings serverTlsKeyPath?: string; serverTlsCertPath?: string;