@virtru/dsp-sdk 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -1
- package/README.md +81 -3
- package/dist/src/fips.d.ts +7 -0
- package/dist/src/fips.js +12 -0
- package/dist/src/lib/dsp.d.ts +17 -1
- package/dist/src/lib/dsp.js +28 -5
- package/package.json +23 -2
- package/.prettierrc +0 -3
- package/.rush/temp/chunked-rush-logs/dsp-sdk._phase_build.chunks.jsonl +0 -12
- package/.rush/temp/chunked-rush-logs/dsp-sdk._phase_test.chunks.jsonl +0 -383
- package/.rush/temp/package-deps__phase_build.json +0 -76
- package/.rush/temp/shrinkwrap-deps.json +0 -1262
- package/CHANGELOG.json +0 -299
- package/buf.gen.yaml +0 -17
- package/buf.yaml +0 -4
- package/config/jest.config.json +0 -6
- package/config/rig.json +0 -8
- package/dist/tests/dsp-client.test.d.ts +0 -1
- package/dist/tests/dsp-client.test.js +0 -73
- package/dist/tests/dsp.test.d.ts +0 -1
- package/dist/tests/dsp.test.js +0 -92
- package/dist/tests/fips-crypto.unit.test.d.ts +0 -1
- package/dist/tests/fips-crypto.unit.test.js +0 -258
- package/dist/tests/mocks/create-export-artifacts.d.ts +0 -2
- package/dist/tests/mocks/create-export-artifacts.js +0 -13
- package/dist/tests/mocks/tagging-pdp-tag.d.ts +0 -2
- package/dist/tests/mocks/tagging-pdp-tag.js +0 -11
- package/dist/tests/mocks/well-known-configuration.d.ts +0 -2
- package/dist/tests/mocks/well-known-configuration.js +0 -12
- package/dist/tests/setup-msw.d.ts +0 -9
- package/dist/tests/setup-msw.js +0 -30
- package/dist/tests/setup-unit.d.ts +0 -7
- package/dist/tests/setup-unit.js +0 -70
- package/eslint.config.mjs +0 -28
- package/lib-commonjs/src/gen/buf/validate/validate_pb.js +0 -487
- package/lib-commonjs/src/gen/config/v1/config_pb.js +0 -142
- package/lib-commonjs/src/gen/config/v1/kas_config_pb.js +0 -72
- package/lib-commonjs/src/gen/config/v1/meta_pb.js +0 -36
- package/lib-commonjs/src/gen/config/v1/outlook_config_pb.js +0 -67
- package/lib-commonjs/src/gen/config/v1/secureviewer_config_pb.js +0 -67
- package/lib-commonjs/src/gen/config/v1/tagging_pb.js +0 -246
- package/lib-commonjs/src/gen/google/api/annotations_pb.js +0 -33
- package/lib-commonjs/src/gen/google/api/http_pb.js +0 -44
- package/lib-commonjs/src/gen/policyimportexport/v1/policy_import_export_pb.js +0 -93
- package/lib-commonjs/src/gen/shared/v1/shared_pb.js +0 -95
- package/lib-commonjs/src/gen/tagging/pdp/v2/tagging_pb.js +0 -277
- package/lib-commonjs/src/gen/version/v1/version_pb.js +0 -40
- package/lib-commonjs/src/gen/virtru/common/common_pb.js +0 -76
- package/lib-commonjs/src/gen/virtru/policy/certificates/v1/certificates_pb.js +0 -77
- package/lib-commonjs/src/gen/virtru/policy/objects_pb.js +0 -143
- package/lib-commonjs/src/index.js +0 -48
- package/lib-commonjs/src/lib/client.js +0 -66
- package/lib-commonjs/src/lib/consts.js +0 -10
- package/lib-commonjs/src/lib/dsp.js +0 -49
- package/lib-commonjs/src/lib/fips-crypto/asymmetric.js +0 -126
- package/lib-commonjs/src/lib/fips-crypto/key-format.js +0 -243
- package/lib-commonjs/src/lib/fips-crypto/keys.js +0 -134
- package/lib-commonjs/src/lib/fips-crypto/primitives.js +0 -112
- package/lib-commonjs/src/lib/fips-crypto/symmetric.js +0 -162
- package/lib-commonjs/src/lib/fips-crypto-service.js +0 -57
- package/lib-commonjs/src/lib/utils.js +0 -401
- package/lib-commonjs/tests/dsp-client.test.js +0 -75
- package/lib-commonjs/tests/dsp.test.js +0 -94
- package/lib-commonjs/tests/fips-crypto.unit.test.js +0 -260
- package/lib-commonjs/tests/mocks/create-export-artifacts.js +0 -17
- package/lib-commonjs/tests/mocks/tagging-pdp-tag.js +0 -15
- package/lib-commonjs/tests/mocks/well-known-configuration.js +0 -16
- package/lib-commonjs/tests/setup-msw.js +0 -33
- package/lib-commonjs/tests/setup-unit.js +0 -72
- package/public/virtru.wasm +0 -0
- package/src/gen/buf/validate/validate_pb.ts +0 -4879
- package/src/gen/config/formatters/testdata/v1/test_pb.ts +0 -287
- package/src/gen/config/v1/config_connect.ts +0 -111
- package/src/gen/config/v1/config_pb.ts +0 -439
- package/src/gen/config/v1/kas_config_pb.ts +0 -183
- package/src/gen/config/v1/meta_pb.ts +0 -72
- package/src/gen/config/v1/outlook_config_pb.ts +0 -242
- package/src/gen/config/v1/secureviewer_config_pb.ts +0 -161
- package/src/gen/config/v1/tagging_pb.ts +0 -456
- package/src/gen/google/api/annotations_pb.ts +0 -43
- package/src/gen/google/api/http_pb.ts +0 -486
- package/src/gen/helloworld/v1/helloworld_connect.ts +0 -49
- package/src/gen/helloworld/v1/helloworld_pb.ts +0 -104
- package/src/gen/kas/nanotdf/v1/nanotdf_rewrap_connect.ts +0 -39
- package/src/gen/kas/nanotdf/v1/nanotdf_rewrap_pb.ts +0 -207
- package/src/gen/policyimportexport/v1/policy_import_export_connect.ts +0 -56
- package/src/gen/policyimportexport/v1/policy_import_export_pb.ts +0 -332
- package/src/gen/shared/v1/shared_connect.ts +0 -61
- package/src/gen/shared/v1/shared_pb.ts +0 -240
- package/src/gen/shared/v2/shared_connect.ts +0 -39
- package/src/gen/shared/v2/shared_pb.ts +0 -122
- package/src/gen/tagging/pdp/v2/externalprocessors/processor_connect.ts +0 -156
- package/src/gen/tagging/pdp/v2/externalprocessors/processor_pb.ts +0 -709
- package/src/gen/tagging/pdp/v2/stanag/stanag_pb.ts +0 -953
- package/src/gen/tagging/pdp/v2/tagging_connect.ts +0 -73
- package/src/gen/tagging/pdp/v2/tagging_pb.ts +0 -1064
- package/src/gen/version/v1/version_connect.ts +0 -31
- package/src/gen/version/v1/version_pb.ts +0 -143
- package/src/gen/virtru/common/common_pb.ts +0 -201
- package/src/gen/virtru/policy/certificates/v1/certificates_connect.ts +0 -44
- package/src/gen/virtru/policy/certificates/v1/certificates_pb.ts +0 -305
- package/src/gen/virtru/policy/objects_pb.ts +0 -253
- package/src/gen/web-admin/v1/config_connect.ts +0 -52
- package/src/gen/web-admin/v1/config_pb.ts +0 -173
- package/src/index.ts +0 -62
- package/src/lib/client.ts +0 -90
- package/src/lib/consts.ts +0 -8
- package/src/lib/dsp.ts +0 -65
- package/src/lib/fips-crypto/asymmetric.ts +0 -162
- package/src/lib/fips-crypto/key-format.ts +0 -287
- package/src/lib/fips-crypto/keys.ts +0 -190
- package/src/lib/fips-crypto/primitives.ts +0 -197
- package/src/lib/fips-crypto/symmetric.ts +0 -213
- package/src/lib/fips-crypto-service.ts +0 -58
- package/src/lib/utils.test.ts +0 -415
- package/src/lib/utils.ts +0 -525
- package/src/vite-env.d.ts +0 -7
- package/temp/build/lint/_eslint-5eVG3S6w.json +0 -38
- package/temp/test/jest/haste-map-b055a9550e6d9f9b43d8ad29b1607278-49d19aee56a0732eca9c014a51272338-8710993d07b75a801b0956e67ffc46fa +0 -0
- package/tests/dsp-client.test.ts +0 -95
- package/tests/dsp.test.ts +0 -119
- package/tests/fips-crypto.unit.test.ts +0 -412
- package/tests/mocks/create-export-artifacts.ts +0 -16
- package/tests/mocks/tagging-pdp-tag.ts +0 -13
- package/tests/mocks/well-known-configuration.ts +0 -15
- package/tests/setup-msw.ts +0 -35
- package/tests/setup-unit.ts +0 -108
- package/tsconfig.json +0 -32
- package/update-protos.sh +0 -63
- package/vitest.config.ts +0 -48
package/tests/dsp.test.ts
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) Virtru Corporation. All rights reserved.
|
|
3
|
-
*
|
|
4
|
-
* Your use of this file is governed by the Virtu Terms of Service <https://www.virtru.com/terms-of-service/>.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { expect, test, vi, beforeEach } from 'vitest';
|
|
8
|
-
import { DSP } from '../src';
|
|
9
|
-
import { mockTaggingPDPResponse } from './mocks/tagging-pdp-tag';
|
|
10
|
-
import { type AuthProvider, HttpRequest, withHeaders } from '@opentdf/sdk';
|
|
11
|
-
import { mockWellKnownConfiguration } from './mocks/well-known-configuration';
|
|
12
|
-
|
|
13
|
-
const platformUrl = 'https://dsp.example.com';
|
|
14
|
-
|
|
15
|
-
// Mock fetch globally
|
|
16
|
-
const mockFetch = vi.fn();
|
|
17
|
-
global.fetch = mockFetch;
|
|
18
|
-
|
|
19
|
-
const authProvider = <AuthProvider>{
|
|
20
|
-
updateClientPublicKey: async () => {},
|
|
21
|
-
withCreds: async (req: HttpRequest): Promise<HttpRequest> =>
|
|
22
|
-
withHeaders(req, {
|
|
23
|
-
Authorization: 'Bearer dummy auth token for testing purposes',
|
|
24
|
-
}),
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
beforeEach(() => {
|
|
28
|
-
mockFetch.mockReset();
|
|
29
|
-
|
|
30
|
-
// Setup default mock responses
|
|
31
|
-
mockFetch.mockImplementation(async (url: string) => {
|
|
32
|
-
if (url.includes('/tagging.pdp.v2.TaggingPDPService/Tag')) {
|
|
33
|
-
return {
|
|
34
|
-
ok: true,
|
|
35
|
-
status: 200,
|
|
36
|
-
json: async () => mockTaggingPDPResponse(),
|
|
37
|
-
headers: new Headers({
|
|
38
|
-
'Content-Type': 'application/json',
|
|
39
|
-
}),
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
if (
|
|
44
|
-
url.includes(
|
|
45
|
-
'/wellknownconfiguration.WellKnownService/GetWellKnownConfiguration'
|
|
46
|
-
)
|
|
47
|
-
) {
|
|
48
|
-
return {
|
|
49
|
-
ok: true,
|
|
50
|
-
status: 200,
|
|
51
|
-
json: async () => mockWellKnownConfiguration(),
|
|
52
|
-
headers: new Headers({
|
|
53
|
-
'Content-Type': 'application/json',
|
|
54
|
-
}),
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return {
|
|
59
|
-
ok: false,
|
|
60
|
-
status: 404,
|
|
61
|
-
json: async () => ({}),
|
|
62
|
-
headers: new Headers(),
|
|
63
|
-
};
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
test('should create a new DSP instance with platformUrl', () => {
|
|
68
|
-
const dsp = new DSP({ platformUrl, authProvider });
|
|
69
|
-
expect(dsp).toBeInstanceOf(DSP);
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
test('should throw an error if platformUrl is not provided', () => {
|
|
73
|
-
expect(() => new DSP({ authProvider } as never)).toThrowError(
|
|
74
|
-
'platformUrl is required for DSP client'
|
|
75
|
-
);
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
test('should create a new DSP instance with platformUrl and authProvider', () => {
|
|
79
|
-
const dsp = new DSP({ platformUrl, authProvider });
|
|
80
|
-
expect(dsp).toBeInstanceOf(DSP);
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
test('should perform RPC calls using the DSP client service', async () => {
|
|
84
|
-
const dsp = new DSP({ platformUrl, authProvider });
|
|
85
|
-
const result = await dsp.services.v2.taggingPDPService.tag({});
|
|
86
|
-
expect(result.$typeName).toBe('tagging.pdp.v2.TaggingPDPResponse');
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
test('should perform RPC calls via internal PlatformClient service', async () => {
|
|
90
|
-
const dsp = new DSP({ platformUrl, authProvider });
|
|
91
|
-
const result = await dsp.services.v1.wellknown.getWellKnownConfiguration({});
|
|
92
|
-
expect(result.$typeName).toBe(
|
|
93
|
-
'wellknownconfiguration.GetWellKnownConfigurationResponse'
|
|
94
|
-
);
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
test('should use provided interceptors when making RPC calls', async () => {
|
|
98
|
-
const mockInterceptor = vi.fn((next) => next);
|
|
99
|
-
const dsp = new DSP({
|
|
100
|
-
platformUrl,
|
|
101
|
-
authProvider,
|
|
102
|
-
interceptors: [mockInterceptor],
|
|
103
|
-
});
|
|
104
|
-
await dsp.services.v2.taggingPDPService.tag({});
|
|
105
|
-
expect(mockInterceptor).toHaveBeenCalled();
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
test('should expose expected service structure', () => {
|
|
109
|
-
const dsp = new DSP({ platformUrl, authProvider });
|
|
110
|
-
expect(dsp.services).toHaveProperty('v1');
|
|
111
|
-
expect(dsp.services.v2).toHaveProperty('taggingPDPService');
|
|
112
|
-
expect(dsp.services.v1).toHaveProperty('wellknown');
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
test('should throw if authProvider is missing', () => {
|
|
116
|
-
expect(() => new DSP({ platformUrl } as never)).toThrowError(
|
|
117
|
-
'Client ID or custom AuthProvider must be defined'
|
|
118
|
-
);
|
|
119
|
-
});
|
|
@@ -1,412 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) Virtru Corporation. All rights reserved.
|
|
3
|
-
*
|
|
4
|
-
* Your use of this file is governed by the Virtu Terms of Service <https://www.virtru.com/terms-of-service/>.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { expect, test, beforeAll, afterAll, describe } from 'vitest';
|
|
8
|
-
import {
|
|
9
|
-
type KeyPair,
|
|
10
|
-
type PublicKey,
|
|
11
|
-
type PrivateKey,
|
|
12
|
-
Binary,
|
|
13
|
-
} from '@opentdf/sdk/singlecontainer';
|
|
14
|
-
import {
|
|
15
|
-
FipsCryptoService,
|
|
16
|
-
unwrapPublicKey,
|
|
17
|
-
unwrapPrivateKey,
|
|
18
|
-
importPrivateKey,
|
|
19
|
-
exportPrivateKeyPem,
|
|
20
|
-
} from '../src/lib/fips-crypto-service';
|
|
21
|
-
|
|
22
|
-
describe('FIPS CryptoService - Methods', () => {
|
|
23
|
-
// RSA key slots are finite in the WASM keystore. Each describe group that
|
|
24
|
-
// uses RSA keys creates ONE shared key pair in beforeAll and releases it in
|
|
25
|
-
// afterAll so slots are reclaimed before the next group starts.
|
|
26
|
-
|
|
27
|
-
describe('sign and verify (asymmetric)', () => {
|
|
28
|
-
let keyPair: KeyPair;
|
|
29
|
-
beforeAll(async () => {
|
|
30
|
-
keyPair = await FipsCryptoService.generateSigningKeyPair();
|
|
31
|
-
}, 60000);
|
|
32
|
-
afterAll(() => {
|
|
33
|
-
unwrapPublicKey(keyPair.publicKey).release();
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
test('should sign and verify with RS256', async () => {
|
|
37
|
-
const data = new Uint8Array([1, 2, 3, 4, 5]);
|
|
38
|
-
const signature = await FipsCryptoService.sign(
|
|
39
|
-
data,
|
|
40
|
-
keyPair.privateKey,
|
|
41
|
-
'RS256'
|
|
42
|
-
);
|
|
43
|
-
const isValid = await FipsCryptoService.verify(
|
|
44
|
-
data,
|
|
45
|
-
signature,
|
|
46
|
-
keyPair.publicKey,
|
|
47
|
-
'RS256'
|
|
48
|
-
);
|
|
49
|
-
expect(isValid).toBe(true);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
test('should reject tampered data', async () => {
|
|
53
|
-
const data = new Uint8Array([1, 2, 3, 4, 5]);
|
|
54
|
-
const signature = await FipsCryptoService.sign(
|
|
55
|
-
data,
|
|
56
|
-
keyPair.privateKey,
|
|
57
|
-
'RS256'
|
|
58
|
-
);
|
|
59
|
-
const tamperedData = new Uint8Array([1, 2, 3, 4, 6]);
|
|
60
|
-
const isValid = await FipsCryptoService.verify(
|
|
61
|
-
tamperedData,
|
|
62
|
-
signature,
|
|
63
|
-
keyPair.publicKey,
|
|
64
|
-
'RS256'
|
|
65
|
-
);
|
|
66
|
-
expect(isValid).toBe(false);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
test('should throw error for ES256 (EC not supported)', async () => {
|
|
70
|
-
await expect(
|
|
71
|
-
FipsCryptoService.sign(
|
|
72
|
-
new Uint8Array([1, 2, 3, 4]),
|
|
73
|
-
keyPair.privateKey,
|
|
74
|
-
'ES256'
|
|
75
|
-
)
|
|
76
|
-
).rejects.toThrow('not supported in FIPS mode');
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
test('encryption key pair (RSA-OAEP) should not be usable for signing', async () => {
|
|
80
|
-
// Catches algorithm mismatch: if generateKeyPair() incorrectly used
|
|
81
|
-
// RSASSA-PKCS1-v1_5 params, signing would succeed here instead of throwing.
|
|
82
|
-
const encKeyPair = await FipsCryptoService.generateKeyPair();
|
|
83
|
-
await expect(
|
|
84
|
-
FipsCryptoService.sign(
|
|
85
|
-
new Uint8Array([1, 2, 3]),
|
|
86
|
-
encKeyPair.privateKey,
|
|
87
|
-
'RS256'
|
|
88
|
-
)
|
|
89
|
-
).rejects.toThrow();
|
|
90
|
-
unwrapPublicKey(encKeyPair.publicKey).release();
|
|
91
|
-
unwrapPrivateKey(encKeyPair.privateKey).release();
|
|
92
|
-
});
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
describe('hmac and verifyHmac', () => {
|
|
96
|
-
test('should compute and verify HMAC-SHA256', async () => {
|
|
97
|
-
const crypto = FipsCryptoService;
|
|
98
|
-
const keyBytes = await crypto.randomBytes(32);
|
|
99
|
-
const symKey = await crypto.importSymmetricKey(keyBytes);
|
|
100
|
-
const data = new Uint8Array([1, 2, 3, 4, 5]);
|
|
101
|
-
const signature = await crypto.hmac(data, symKey);
|
|
102
|
-
const isValid = await crypto.verifyHmac(data, signature, symKey);
|
|
103
|
-
expect(isValid).toBe(true);
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
test('should reject invalid signature', async () => {
|
|
107
|
-
const crypto = FipsCryptoService;
|
|
108
|
-
const symKey = await crypto.generateKey(32);
|
|
109
|
-
const data = new Uint8Array([1, 2, 3, 4]);
|
|
110
|
-
const signature = await crypto.hmac(data, symKey);
|
|
111
|
-
signature[0] ^= 1; // Flip a bit
|
|
112
|
-
const isValid = await crypto.verifyHmac(data, signature, symKey);
|
|
113
|
-
expect(isValid).toBe(false);
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
test('should reject signature with wrong key', async () => {
|
|
117
|
-
const crypto = FipsCryptoService;
|
|
118
|
-
const symKey1 = await crypto.importSymmetricKey(
|
|
119
|
-
await crypto.randomBytes(32)
|
|
120
|
-
);
|
|
121
|
-
const symKey2 = await crypto.importSymmetricKey(
|
|
122
|
-
await crypto.randomBytes(32)
|
|
123
|
-
);
|
|
124
|
-
const data = new Uint8Array([1, 2, 3, 4]);
|
|
125
|
-
const signature = await crypto.hmac(data, symKey1);
|
|
126
|
-
const isValid = await crypto.verifyHmac(data, signature, symKey2);
|
|
127
|
-
expect(isValid).toBe(false);
|
|
128
|
-
});
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
describe('digest', () => {
|
|
132
|
-
test('should compute SHA-256 hash', async () => {
|
|
133
|
-
const data = new Uint8Array([1, 2, 3, 4]);
|
|
134
|
-
const hash = await FipsCryptoService.digest('SHA-256', data);
|
|
135
|
-
expect(hash).toBeInstanceOf(Uint8Array);
|
|
136
|
-
expect(hash.byteLength).toBe(32);
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
test('should produce consistent hashes', async () => {
|
|
140
|
-
const data = new Uint8Array([1, 2, 3, 4]);
|
|
141
|
-
const hash1 = await FipsCryptoService.digest('SHA-256', data);
|
|
142
|
-
const hash2 = await FipsCryptoService.digest('SHA-256', data);
|
|
143
|
-
expect(hash1).toEqual(hash2);
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
test('should throw error for SHA-384 (not supported)', async () => {
|
|
147
|
-
await expect(
|
|
148
|
-
FipsCryptoService.digest('SHA-384', new Uint8Array([1, 2, 3, 4]))
|
|
149
|
-
).rejects.toThrow('not supported in FIPS mode');
|
|
150
|
-
});
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
describe('EC placeholder methods', () => {
|
|
154
|
-
test('should throw error for generateECKeyPair', async () => {
|
|
155
|
-
await expect(FipsCryptoService.generateECKeyPair()).rejects.toThrow(
|
|
156
|
-
'not supported in FIPS mode'
|
|
157
|
-
);
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
test('should throw error for deriveKeyFromECDH', async () => {
|
|
161
|
-
await expect(
|
|
162
|
-
FipsCryptoService.deriveKeyFromECDH({} as PrivateKey, {} as PublicKey, {
|
|
163
|
-
hash: 'SHA-256',
|
|
164
|
-
salt: new Uint8Array(),
|
|
165
|
-
})
|
|
166
|
-
).rejects.toThrow('not supported in FIPS mode');
|
|
167
|
-
});
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
describe('exportPublicKeyPem', () => {
|
|
171
|
-
let keyPair: KeyPair;
|
|
172
|
-
beforeAll(async () => {
|
|
173
|
-
keyPair = await FipsCryptoService.generateKeyPair();
|
|
174
|
-
}, 60000);
|
|
175
|
-
afterAll(() => {
|
|
176
|
-
unwrapPublicKey(keyPair.publicKey).release();
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
test('should export generated public key to PEM', async () => {
|
|
180
|
-
const pem = await FipsCryptoService.exportPublicKeyPem(keyPair.publicKey);
|
|
181
|
-
expect(pem).toContain('-----BEGIN PUBLIC KEY-----');
|
|
182
|
-
expect(pem).toContain('-----END PUBLIC KEY-----');
|
|
183
|
-
});
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
describe('importPublicKey', () => {
|
|
187
|
-
let keyPair: KeyPair;
|
|
188
|
-
let importedKey: PublicKey;
|
|
189
|
-
beforeAll(async () => {
|
|
190
|
-
const crypto = FipsCryptoService;
|
|
191
|
-
keyPair = await crypto.generateKeyPair(2048);
|
|
192
|
-
const pem = await crypto.exportPublicKeyPem(keyPair.publicKey);
|
|
193
|
-
importedKey = await crypto.importPublicKey(pem, { usage: 'encrypt' });
|
|
194
|
-
}, 60000);
|
|
195
|
-
afterAll(() => {
|
|
196
|
-
unwrapPublicKey(keyPair.publicKey).release();
|
|
197
|
-
unwrapPublicKey(importedKey).release();
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
test('should import PEM and detect RSA-2048', () => {
|
|
201
|
-
expect(importedKey.algorithm).toBe('rsa:2048');
|
|
202
|
-
});
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
describe('exportPublicKeyJwk', () => {
|
|
206
|
-
let keyPair: KeyPair;
|
|
207
|
-
beforeAll(async () => {
|
|
208
|
-
keyPair = await FipsCryptoService.generateKeyPair(2048);
|
|
209
|
-
}, 60000);
|
|
210
|
-
afterAll(() => {
|
|
211
|
-
unwrapPublicKey(keyPair.publicKey).release();
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
test('should export public key to JWK', async () => {
|
|
215
|
-
const jwk = await FipsCryptoService.exportPublicKeyJwk(keyPair.publicKey);
|
|
216
|
-
expect(jwk.kty).toBe('RSA');
|
|
217
|
-
expect(jwk.n).toBeDefined();
|
|
218
|
-
expect(jwk.e).toBeDefined();
|
|
219
|
-
expect(typeof jwk.n).toBe('string');
|
|
220
|
-
expect(typeof jwk.e).toBe('string');
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
test('should produce a JWK that round-trips back to SPKI', async () => {
|
|
224
|
-
const jwk = await FipsCryptoService.exportPublicKeyJwk(keyPair.publicKey);
|
|
225
|
-
const webKey = await globalThis.crypto.subtle.importKey(
|
|
226
|
-
'jwk',
|
|
227
|
-
jwk,
|
|
228
|
-
{ name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256' },
|
|
229
|
-
true,
|
|
230
|
-
['verify']
|
|
231
|
-
);
|
|
232
|
-
const spki = await globalThis.crypto.subtle.exportKey('spki', webKey);
|
|
233
|
-
expect(spki.byteLength).toBeGreaterThan(0);
|
|
234
|
-
});
|
|
235
|
-
});
|
|
236
|
-
|
|
237
|
-
describe('encrypt and decrypt (symmetric AES-GCM)', () => {
|
|
238
|
-
test('should round-trip encrypt/decrypt', async () => {
|
|
239
|
-
const key = await FipsCryptoService.generateKey();
|
|
240
|
-
const iv = Binary.fromArrayBuffer(
|
|
241
|
-
(await FipsCryptoService.randomBytes(12)).buffer as ArrayBuffer
|
|
242
|
-
);
|
|
243
|
-
const plaintext = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
|
|
244
|
-
const { payload: cipher, authTag } = await FipsCryptoService.encrypt(
|
|
245
|
-
Binary.fromArrayBuffer(plaintext.buffer as ArrayBuffer),
|
|
246
|
-
key,
|
|
247
|
-
iv
|
|
248
|
-
);
|
|
249
|
-
const { payload: recovered } = await FipsCryptoService.decrypt(
|
|
250
|
-
cipher,
|
|
251
|
-
key,
|
|
252
|
-
iv,
|
|
253
|
-
undefined,
|
|
254
|
-
authTag
|
|
255
|
-
);
|
|
256
|
-
expect(new Uint8Array(recovered.asArrayBuffer())).toEqual(plaintext);
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
test('should produce different ciphertext for different IVs', async () => {
|
|
260
|
-
const key = await FipsCryptoService.generateKey();
|
|
261
|
-
const plaintext = Binary.fromArrayBuffer(
|
|
262
|
-
new Uint8Array([1, 2, 3, 4]).buffer as ArrayBuffer
|
|
263
|
-
);
|
|
264
|
-
const iv1 = Binary.fromArrayBuffer(
|
|
265
|
-
(await FipsCryptoService.randomBytes(12)).buffer as ArrayBuffer
|
|
266
|
-
);
|
|
267
|
-
const iv2 = Binary.fromArrayBuffer(
|
|
268
|
-
(await FipsCryptoService.randomBytes(12)).buffer as ArrayBuffer
|
|
269
|
-
);
|
|
270
|
-
const { payload: cipher1 } = await FipsCryptoService.encrypt(
|
|
271
|
-
plaintext,
|
|
272
|
-
key,
|
|
273
|
-
iv1
|
|
274
|
-
);
|
|
275
|
-
const { payload: cipher2 } = await FipsCryptoService.encrypt(
|
|
276
|
-
plaintext,
|
|
277
|
-
key,
|
|
278
|
-
iv2
|
|
279
|
-
);
|
|
280
|
-
expect(new Uint8Array(cipher1.asArrayBuffer())).not.toEqual(
|
|
281
|
-
new Uint8Array(cipher2.asArrayBuffer())
|
|
282
|
-
);
|
|
283
|
-
});
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
describe('encryptWithPublicKey and decryptWithPrivateKey (RSA-OAEP)', () => {
|
|
287
|
-
let keyPair: KeyPair;
|
|
288
|
-
beforeAll(async () => {
|
|
289
|
-
keyPair = await FipsCryptoService.generateKeyPair();
|
|
290
|
-
}, 60000);
|
|
291
|
-
afterAll(() => {
|
|
292
|
-
unwrapPublicKey(keyPair.publicKey).release();
|
|
293
|
-
});
|
|
294
|
-
|
|
295
|
-
test('should round-trip RSA encrypt/decrypt', async () => {
|
|
296
|
-
const plaintext = new Uint8Array([10, 20, 30, 40, 50]);
|
|
297
|
-
const encrypted = await FipsCryptoService.encryptWithPublicKey(
|
|
298
|
-
Binary.fromArrayBuffer(plaintext.buffer as ArrayBuffer),
|
|
299
|
-
keyPair.publicKey
|
|
300
|
-
);
|
|
301
|
-
const decrypted = await FipsCryptoService.decryptWithPrivateKey(
|
|
302
|
-
encrypted,
|
|
303
|
-
keyPair.privateKey
|
|
304
|
-
);
|
|
305
|
-
expect(new Uint8Array(decrypted.asArrayBuffer())).toEqual(plaintext);
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
test('should produce different ciphertext each call (RSA-OAEP is randomized)', async () => {
|
|
309
|
-
const payload = Binary.fromArrayBuffer(
|
|
310
|
-
new Uint8Array([1, 2, 3]).buffer as ArrayBuffer
|
|
311
|
-
);
|
|
312
|
-
const enc1 = await FipsCryptoService.encryptWithPublicKey(
|
|
313
|
-
payload,
|
|
314
|
-
keyPair.publicKey
|
|
315
|
-
);
|
|
316
|
-
const enc2 = await FipsCryptoService.encryptWithPublicKey(
|
|
317
|
-
payload,
|
|
318
|
-
keyPair.publicKey
|
|
319
|
-
);
|
|
320
|
-
expect(new Uint8Array(enc1.asArrayBuffer())).not.toEqual(
|
|
321
|
-
new Uint8Array(enc2.asArrayBuffer())
|
|
322
|
-
);
|
|
323
|
-
});
|
|
324
|
-
|
|
325
|
-
test('signing key pair (RSASSA-PKCS1-v1_5) should not be usable for encryption', async () => {
|
|
326
|
-
// Catches algorithm mismatch: if generateSigningKeyPair() incorrectly used
|
|
327
|
-
// RSA-OAEP params, encryption would succeed here instead of throwing.
|
|
328
|
-
const signingKp = await FipsCryptoService.generateSigningKeyPair();
|
|
329
|
-
await expect(
|
|
330
|
-
FipsCryptoService.encryptWithPublicKey(
|
|
331
|
-
Binary.fromArrayBuffer(
|
|
332
|
-
new Uint8Array([1, 2, 3]).buffer as ArrayBuffer
|
|
333
|
-
),
|
|
334
|
-
signingKp.publicKey
|
|
335
|
-
)
|
|
336
|
-
).rejects.toThrow();
|
|
337
|
-
unwrapPublicKey(signingKp.publicKey).release();
|
|
338
|
-
unwrapPrivateKey(signingKp.privateKey).release();
|
|
339
|
-
});
|
|
340
|
-
});
|
|
341
|
-
|
|
342
|
-
describe('importPrivateKey and exportPrivateKeyPem', () => {
|
|
343
|
-
let privKey: PrivateKey;
|
|
344
|
-
beforeAll(async () => {
|
|
345
|
-
const kp = await globalThis.crypto.subtle.generateKey(
|
|
346
|
-
{
|
|
347
|
-
name: 'RSASSA-PKCS1-v1_5',
|
|
348
|
-
modulusLength: 2048,
|
|
349
|
-
publicExponent: new Uint8Array([1, 0, 1]),
|
|
350
|
-
hash: 'SHA-256',
|
|
351
|
-
},
|
|
352
|
-
true,
|
|
353
|
-
['sign', 'verify']
|
|
354
|
-
);
|
|
355
|
-
const pkcs8 = await globalThis.crypto.subtle.exportKey(
|
|
356
|
-
'pkcs8',
|
|
357
|
-
kp.privateKey
|
|
358
|
-
);
|
|
359
|
-
const b64 = btoa(String.fromCharCode(...new Uint8Array(pkcs8)));
|
|
360
|
-
const pem = `-----BEGIN PRIVATE KEY-----\n${b64
|
|
361
|
-
.match(/.{1,64}/g)!
|
|
362
|
-
.join('\n')}\n-----END PRIVATE KEY-----`;
|
|
363
|
-
privKey = await importPrivateKey(pem, {
|
|
364
|
-
usage: 'sign',
|
|
365
|
-
extractable: true,
|
|
366
|
-
});
|
|
367
|
-
}, 60000);
|
|
368
|
-
afterAll(() => {
|
|
369
|
-
unwrapPrivateKey(privKey).release();
|
|
370
|
-
});
|
|
371
|
-
|
|
372
|
-
test('should import PKCS#8 PEM private key', () => {
|
|
373
|
-
expect(privKey.algorithm).toBe('rsa:2048');
|
|
374
|
-
});
|
|
375
|
-
|
|
376
|
-
test('should export imported private key back to PEM', async () => {
|
|
377
|
-
const exported = await exportPrivateKeyPem(privKey);
|
|
378
|
-
expect(exported).toContain('-----BEGIN PRIVATE KEY-----');
|
|
379
|
-
expect(exported).toContain('-----END PRIVATE KEY-----');
|
|
380
|
-
});
|
|
381
|
-
});
|
|
382
|
-
|
|
383
|
-
describe('splitSymmetricKey and mergeSymmetricKeys', () => {
|
|
384
|
-
test('splitSymmetricKey with 1 share returns the same key (single-KAS identity)', async () => {
|
|
385
|
-
const key = await FipsCryptoService.generateKey();
|
|
386
|
-
const shares = await FipsCryptoService.splitSymmetricKey(key, 1);
|
|
387
|
-
expect(shares).toHaveLength(1);
|
|
388
|
-
expect(shares[0]).toBe(key);
|
|
389
|
-
});
|
|
390
|
-
|
|
391
|
-
test('mergeSymmetricKeys with 1 share returns the same key (single-KAS identity)', async () => {
|
|
392
|
-
const key = await FipsCryptoService.generateKey();
|
|
393
|
-
const merged = await FipsCryptoService.mergeSymmetricKeys([key]);
|
|
394
|
-
expect(merged).toBe(key);
|
|
395
|
-
});
|
|
396
|
-
|
|
397
|
-
test('splitSymmetricKey with 2 shares throws (multi-KAS not yet supported)', async () => {
|
|
398
|
-
const key = await FipsCryptoService.generateKey();
|
|
399
|
-
await expect(FipsCryptoService.splitSymmetricKey(key, 2)).rejects.toThrow(
|
|
400
|
-
'not yet supported in FIPS mode'
|
|
401
|
-
);
|
|
402
|
-
});
|
|
403
|
-
|
|
404
|
-
test('mergeSymmetricKeys with 2 shares throws (multi-KAS not yet supported)', async () => {
|
|
405
|
-
const key1 = await FipsCryptoService.generateKey();
|
|
406
|
-
const key2 = await FipsCryptoService.generateKey();
|
|
407
|
-
await expect(
|
|
408
|
-
FipsCryptoService.mergeSymmetricKeys([key1, key2])
|
|
409
|
-
).rejects.toThrow('not yet supported in FIPS mode');
|
|
410
|
-
});
|
|
411
|
-
});
|
|
412
|
-
});
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) Virtru Corporation. All rights reserved.
|
|
3
|
-
*
|
|
4
|
-
* Your use of this file is governed by the Virtu Terms of Service <https://www.virtru.com/terms-of-service/>.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { type CreateExportArtifactsResponse } from '@src/gen/policyimportexport/v1/policy_import_export_pb';
|
|
8
|
-
|
|
9
|
-
export const mockCreateExportArtifactsResponse =
|
|
10
|
-
(): CreateExportArtifactsResponse => ({
|
|
11
|
-
$typeName: 'policyimportexport.v1.CreateExportArtifactsResponse',
|
|
12
|
-
artifact: {
|
|
13
|
-
case: undefined,
|
|
14
|
-
value: undefined,
|
|
15
|
-
},
|
|
16
|
-
});
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) Virtru Corporation. All rights reserved.
|
|
3
|
-
*
|
|
4
|
-
* Your use of this file is governed by the Virtu Terms of Service <https://www.virtru.com/terms-of-service/>.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { type TaggingPDPResponse } from '@src/gen/tagging/pdp/v2/tagging_pb';
|
|
8
|
-
|
|
9
|
-
export const mockTaggingPDPResponse = (): TaggingPDPResponse => ({
|
|
10
|
-
$typeName: 'tagging.pdp.v2.TaggingPDPResponse',
|
|
11
|
-
events: [],
|
|
12
|
-
tags: [],
|
|
13
|
-
});
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) Virtru Corporation. All rights reserved.
|
|
3
|
-
*
|
|
4
|
-
* Your use of this file is governed by the Virtu Terms of Service <https://www.virtru.com/terms-of-service/>.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { type GetWellKnownConfigurationResponse } from '@opentdf/sdk/platform/wellknownconfiguration/wellknown_configuration_pb.js';
|
|
8
|
-
|
|
9
|
-
export const mockWellKnownConfiguration =
|
|
10
|
-
(): GetWellKnownConfigurationResponse => ({
|
|
11
|
-
$typeName: 'wellknownconfiguration.GetWellKnownConfigurationResponse',
|
|
12
|
-
configuration: {
|
|
13
|
-
wellKnown: {},
|
|
14
|
-
},
|
|
15
|
-
});
|
package/tests/setup-msw.ts
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) Virtru Corporation. All rights reserved.
|
|
3
|
-
*
|
|
4
|
-
* Your use of this file is governed by the Virtu Terms of Service <https://www.virtru.com/terms-of-service/>.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { type SetupWorker, setupWorker } from 'msw/browser';
|
|
8
|
-
import { beforeAll, afterEach, afterAll } from 'vitest';
|
|
9
|
-
import { HttpHandler } from 'msw';
|
|
10
|
-
|
|
11
|
-
let worker: SetupWorker | undefined;
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Sets up the MSW (Mock Service Worker) for testing.
|
|
15
|
-
*
|
|
16
|
-
* @param handlers - An array of HTTP handlers to be used with MSW.
|
|
17
|
-
* @returns The MSW worker instance.
|
|
18
|
-
*/
|
|
19
|
-
export function setupMSW(handlers: HttpHandler[]): SetupWorker | undefined {
|
|
20
|
-
if (!worker) {
|
|
21
|
-
worker = setupWorker(...handlers);
|
|
22
|
-
|
|
23
|
-
beforeAll(async () => {
|
|
24
|
-
await worker!.start();
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
afterEach(() => worker!.resetHandlers());
|
|
28
|
-
afterAll(() => worker!.stop());
|
|
29
|
-
} else {
|
|
30
|
-
// If worker already exists, just update handlers
|
|
31
|
-
worker.resetHandlers(...handlers);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return worker;
|
|
35
|
-
}
|