@bsv/sdk 1.3.10 → 1.3.12
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/dist/cjs/package.json +1 -1
- package/dist/cjs/src/auth/certificates/Certificate.js +1 -1
- package/dist/cjs/src/auth/certificates/Certificate.js.map +1 -1
- package/dist/cjs/src/auth/certificates/MasterCertificate.js +95 -65
- package/dist/cjs/src/auth/certificates/MasterCertificate.js.map +1 -1
- package/dist/cjs/src/auth/certificates/VerifiableCertificate.js +3 -3
- package/dist/cjs/src/auth/certificates/VerifiableCertificate.js.map +1 -1
- package/dist/cjs/src/auth/utils/getVerifiableCertificates.js +1 -1
- package/dist/cjs/src/auth/utils/getVerifiableCertificates.js.map +1 -1
- package/dist/cjs/src/auth/utils/validateCertificates.js +1 -1
- package/dist/cjs/src/auth/utils/validateCertificates.js.map +1 -1
- package/dist/cjs/src/wallet/ProtoWallet.js +9 -9
- package/dist/cjs/src/wallet/ProtoWallet.js.map +1 -1
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/src/auth/certificates/Certificate.js +2 -2
- package/dist/esm/src/auth/certificates/Certificate.js.map +1 -1
- package/dist/esm/src/auth/certificates/MasterCertificate.js +95 -65
- package/dist/esm/src/auth/certificates/MasterCertificate.js.map +1 -1
- package/dist/esm/src/auth/certificates/VerifiableCertificate.js +3 -3
- package/dist/esm/src/auth/certificates/VerifiableCertificate.js.map +1 -1
- package/dist/esm/src/auth/utils/getVerifiableCertificates.js +1 -1
- package/dist/esm/src/auth/utils/getVerifiableCertificates.js.map +1 -1
- package/dist/esm/src/auth/utils/validateCertificates.js +1 -1
- package/dist/esm/src/auth/utils/validateCertificates.js.map +1 -1
- package/dist/esm/src/wallet/ProtoWallet.js +9 -9
- package/dist/esm/src/wallet/ProtoWallet.js.map +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/types/src/auth/certificates/Certificate.d.ts +5 -5
- package/dist/types/src/auth/certificates/Certificate.d.ts.map +1 -1
- package/dist/types/src/auth/certificates/MasterCertificate.d.ts +44 -14
- package/dist/types/src/auth/certificates/MasterCertificate.d.ts.map +1 -1
- package/dist/types/src/auth/certificates/VerifiableCertificate.d.ts +4 -4
- package/dist/types/src/auth/certificates/VerifiableCertificate.d.ts.map +1 -1
- package/dist/types/src/wallet/ProtoWallet.d.ts +12 -12
- package/dist/types/src/wallet/ProtoWallet.d.ts.map +1 -1
- package/dist/types/tsconfig.types.tsbuildinfo +1 -1
- package/dist/umd/bundle.js +1 -1
- package/docs/auth.md +75 -33
- package/docs/wallet.md +12 -12
- package/package.json +1 -1
- package/src/auth/__tests/Peer.test.ts +19 -47
- package/src/auth/certificates/Certificate.ts +4 -5
- package/src/auth/certificates/MasterCertificate.ts +138 -71
- package/src/auth/certificates/VerifiableCertificate.ts +5 -6
- package/src/auth/certificates/__tests/MasterCertificate.test.ts +142 -51
- package/src/auth/certificates/__tests/VerifiableCertificate.test.ts +54 -30
- package/src/auth/utils/getVerifiableCertificates.ts +2 -2
- package/src/auth/utils/validateCertificates.ts +2 -2
- package/src/wallet/ProtoWallet.ts +20 -11
|
@@ -19,11 +19,12 @@ describe('MasterCertificate', () => {
|
|
|
19
19
|
|
|
20
20
|
const subjectWallet = new CompletedProtoWallet(subjectPrivateKey)
|
|
21
21
|
const certifierWallet = new CompletedProtoWallet(certifierPrivateKey)
|
|
22
|
-
let
|
|
22
|
+
let subjectIdentityKey: string
|
|
23
|
+
let certifierIdentityKey: string
|
|
23
24
|
|
|
24
25
|
beforeAll(async () => {
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
subjectIdentityKey = (await subjectWallet.getPublicKey({ identityKey: true })).publicKey
|
|
27
|
+
certifierIdentityKey = (await certifierWallet.getPublicKey({ identityKey: true })).publicKey
|
|
27
28
|
})
|
|
28
29
|
|
|
29
30
|
describe('constructor', () => {
|
|
@@ -42,8 +43,8 @@ describe('MasterCertificate', () => {
|
|
|
42
43
|
const certificate = new MasterCertificate(
|
|
43
44
|
Utils.toBase64(Random(16)), // type
|
|
44
45
|
Utils.toBase64(Random(16)), // serialNumber
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
subjectIdentityKey,
|
|
47
|
+
certifierIdentityKey,
|
|
47
48
|
mockRevocationOutpoint,
|
|
48
49
|
fields,
|
|
49
50
|
masterKeyring
|
|
@@ -52,8 +53,8 @@ describe('MasterCertificate', () => {
|
|
|
52
53
|
expect(certificate).toBeInstanceOf(MasterCertificate)
|
|
53
54
|
expect(certificate.fields).toEqual(fields)
|
|
54
55
|
expect(certificate.masterKeyring).toEqual(masterKeyring)
|
|
55
|
-
expect(certificate.subject).toEqual(
|
|
56
|
-
expect(certificate.certifier).toEqual(
|
|
56
|
+
expect(certificate.subject).toEqual(subjectIdentityKey)
|
|
57
|
+
expect(certificate.certifier).toEqual(certifierIdentityKey)
|
|
57
58
|
})
|
|
58
59
|
|
|
59
60
|
it('should throw if masterKeyring is missing a key for any field', () => {
|
|
@@ -64,8 +65,8 @@ describe('MasterCertificate', () => {
|
|
|
64
65
|
new MasterCertificate(
|
|
65
66
|
Utils.toBase64(Random(16)), // type
|
|
66
67
|
Utils.toBase64(Random(16)), // serialNumber
|
|
67
|
-
|
|
68
|
-
|
|
68
|
+
subjectIdentityKey,
|
|
69
|
+
certifierIdentityKey,
|
|
69
70
|
mockRevocationOutpoint,
|
|
70
71
|
fields,
|
|
71
72
|
masterKeyring
|
|
@@ -74,18 +75,23 @@ describe('MasterCertificate', () => {
|
|
|
74
75
|
})
|
|
75
76
|
})
|
|
76
77
|
|
|
77
|
-
describe('decryptFields', () => {
|
|
78
|
+
describe('decryptFields (static)', () => {
|
|
78
79
|
it('should decrypt all fields correctly using subject wallet', async () => {
|
|
79
80
|
// Issue a certificate for the subject, which includes a valid masterKeyring
|
|
80
81
|
const certificate = await MasterCertificate.issueCertificateForSubject(
|
|
81
82
|
certifierWallet,
|
|
82
|
-
|
|
83
|
+
subjectIdentityKey,
|
|
83
84
|
plaintextFields,
|
|
84
85
|
'TEST_CERT'
|
|
85
86
|
)
|
|
86
87
|
|
|
87
|
-
// Now subject should be able to decrypt all fields
|
|
88
|
-
const decrypted = await
|
|
88
|
+
// Now subject should be able to decrypt all fields via static method
|
|
89
|
+
const decrypted = await MasterCertificate.decryptFields(
|
|
90
|
+
subjectWallet,
|
|
91
|
+
certificate.masterKeyring,
|
|
92
|
+
certificate.fields,
|
|
93
|
+
certificate.certifier // because certifier was the encryption counterparty
|
|
94
|
+
)
|
|
89
95
|
expect(decrypted).toEqual(plaintextFields)
|
|
90
96
|
})
|
|
91
97
|
|
|
@@ -94,8 +100,8 @@ describe('MasterCertificate', () => {
|
|
|
94
100
|
expect(() => new MasterCertificate(
|
|
95
101
|
Utils.toBase64(Random(16)),
|
|
96
102
|
Utils.toBase64(Random(16)),
|
|
97
|
-
|
|
98
|
-
|
|
103
|
+
subjectIdentityKey,
|
|
104
|
+
certifierIdentityKey,
|
|
99
105
|
mockRevocationOutpoint,
|
|
100
106
|
{ name: Utils.toBase64([1, 2, 3]) },
|
|
101
107
|
{}
|
|
@@ -108,8 +114,8 @@ describe('MasterCertificate', () => {
|
|
|
108
114
|
const badKeyCertificate = new MasterCertificate(
|
|
109
115
|
Utils.toBase64(Random(16)),
|
|
110
116
|
Utils.toBase64(Random(16)),
|
|
111
|
-
|
|
112
|
-
|
|
117
|
+
subjectIdentityKey,
|
|
118
|
+
certifierIdentityKey,
|
|
113
119
|
mockRevocationOutpoint,
|
|
114
120
|
{
|
|
115
121
|
name: Utils.toBase64(SymmetricKey.fromRandom().encrypt(Utils.toArray('Alice', 'utf8')) as number[])
|
|
@@ -117,24 +123,30 @@ describe('MasterCertificate', () => {
|
|
|
117
123
|
{ name: badKeyMasterKeyring }
|
|
118
124
|
)
|
|
119
125
|
|
|
120
|
-
await expect(
|
|
121
|
-
.
|
|
122
|
-
|
|
126
|
+
await expect(
|
|
127
|
+
MasterCertificate.decryptFields(
|
|
128
|
+
subjectWallet,
|
|
129
|
+
badKeyCertificate.masterKeyring,
|
|
130
|
+
badKeyCertificate.fields,
|
|
131
|
+
badKeyCertificate.certifier
|
|
132
|
+
)
|
|
133
|
+
).rejects.toThrow('Failed to decrypt all master certificate fields.')
|
|
123
134
|
})
|
|
124
135
|
})
|
|
125
136
|
|
|
126
|
-
describe('createKeyringForVerifier', () => {
|
|
137
|
+
describe('createKeyringForVerifier (static)', () => {
|
|
127
138
|
const verifierPrivateKey = PrivateKey.fromRandom()
|
|
128
139
|
const verifierWallet = new CompletedProtoWallet(verifierPrivateKey)
|
|
129
|
-
let
|
|
140
|
+
let verifierIdentityKey: string
|
|
130
141
|
|
|
131
142
|
let issuedCert: MasterCertificate
|
|
132
143
|
|
|
133
144
|
beforeAll(async () => {
|
|
134
|
-
|
|
145
|
+
verifierIdentityKey = (await verifierWallet.getPublicKey({ identityKey: true })).publicKey
|
|
146
|
+
// Issue a certificate to reuse in tests
|
|
135
147
|
issuedCert = await MasterCertificate.issueCertificateForSubject(
|
|
136
148
|
certifierWallet,
|
|
137
|
-
|
|
149
|
+
subjectIdentityKey,
|
|
138
150
|
plaintextFields,
|
|
139
151
|
'TEST_CERT'
|
|
140
152
|
)
|
|
@@ -143,10 +155,15 @@ describe('MasterCertificate', () => {
|
|
|
143
155
|
it('should create a verifier keyring for specified fields', async () => {
|
|
144
156
|
// We only want to share "name" with the verifier
|
|
145
157
|
const fieldsToReveal = ['name']
|
|
146
|
-
|
|
158
|
+
|
|
159
|
+
const keyringForVerifier = await MasterCertificate.createKeyringForVerifier(
|
|
147
160
|
subjectWallet,
|
|
148
|
-
|
|
149
|
-
|
|
161
|
+
issuedCert.certifier, // the original certifier
|
|
162
|
+
verifierIdentityKey, // the new verifier
|
|
163
|
+
issuedCert.fields, // encrypted fields
|
|
164
|
+
fieldsToReveal,
|
|
165
|
+
issuedCert.masterKeyring,
|
|
166
|
+
issuedCert.serialNumber
|
|
150
167
|
)
|
|
151
168
|
|
|
152
169
|
// The new keyring should only contain "name"
|
|
@@ -161,8 +178,8 @@ describe('MasterCertificate', () => {
|
|
|
161
178
|
issuedCert.certifier,
|
|
162
179
|
issuedCert.revocationOutpoint,
|
|
163
180
|
issuedCert.fields,
|
|
164
|
-
|
|
165
|
-
|
|
181
|
+
keyringForVerifier,
|
|
182
|
+
issuedCert.signature
|
|
166
183
|
)
|
|
167
184
|
|
|
168
185
|
// The verifier should successfully decrypt the "name" field
|
|
@@ -170,16 +187,23 @@ describe('MasterCertificate', () => {
|
|
|
170
187
|
expect(decrypted).toEqual({ name: plaintextFields.name })
|
|
171
188
|
})
|
|
172
189
|
|
|
173
|
-
it('should throw if fields to reveal are not subset of the certificate fields', async () => {
|
|
190
|
+
it('should throw if fields to reveal are not a subset of the certificate fields', async () => {
|
|
174
191
|
await expect(
|
|
175
|
-
|
|
192
|
+
MasterCertificate.createKeyringForVerifier(
|
|
193
|
+
subjectWallet,
|
|
194
|
+
issuedCert.certifier,
|
|
195
|
+
verifierIdentityKey,
|
|
196
|
+
issuedCert.fields,
|
|
197
|
+
['nonexistent_field'],
|
|
198
|
+
issuedCert.masterKeyring
|
|
199
|
+
)
|
|
176
200
|
).rejects.toThrow(
|
|
177
201
|
/Fields to reveal must be a subset of the certificate fields\. Missing the "nonexistent_field" field\./
|
|
178
202
|
)
|
|
179
203
|
})
|
|
180
204
|
|
|
181
205
|
it('should throw if the master key fails to decrypt the corresponding field', async () => {
|
|
182
|
-
// We'll tamper the certificate's masterKeyring so that a field key is invalid
|
|
206
|
+
// We'll tamper with the certificate's masterKeyring so that a field key is invalid
|
|
183
207
|
const tamperedCert = new MasterCertificate(
|
|
184
208
|
issuedCert.type,
|
|
185
209
|
issuedCert.serialNumber,
|
|
@@ -197,46 +221,65 @@ describe('MasterCertificate', () => {
|
|
|
197
221
|
)
|
|
198
222
|
|
|
199
223
|
await expect(
|
|
200
|
-
|
|
201
|
-
|
|
224
|
+
MasterCertificate.createKeyringForVerifier(
|
|
225
|
+
subjectWallet,
|
|
226
|
+
tamperedCert.certifier,
|
|
227
|
+
verifierIdentityKey,
|
|
228
|
+
tamperedCert.fields,
|
|
229
|
+
['name'],
|
|
230
|
+
tamperedCert.masterKeyring,
|
|
231
|
+
tamperedCert.serialNumber
|
|
232
|
+
)
|
|
233
|
+
).rejects.toThrow('Failed to decrypt certificate field!')
|
|
202
234
|
})
|
|
203
235
|
|
|
204
236
|
it('should support optional originator parameter', async () => {
|
|
205
|
-
// Just to ensure coverage for the originator-based flows
|
|
206
237
|
const fieldsToReveal = ['name']
|
|
207
|
-
const keyringForVerifier = await
|
|
238
|
+
const keyringForVerifier = await MasterCertificate.createKeyringForVerifier(
|
|
208
239
|
subjectWallet,
|
|
209
|
-
|
|
240
|
+
issuedCert.certifier,
|
|
241
|
+
verifierIdentityKey,
|
|
242
|
+
issuedCert.fields,
|
|
210
243
|
fieldsToReveal,
|
|
244
|
+
issuedCert.masterKeyring,
|
|
245
|
+
issuedCert.serialNumber,
|
|
211
246
|
'my-originator'
|
|
212
247
|
)
|
|
213
248
|
expect(keyringForVerifier).toHaveProperty('name')
|
|
214
249
|
})
|
|
215
250
|
|
|
216
|
-
it('should support counterparty of "anyone"', async () => {
|
|
217
|
-
// Create a keyring for public disclosure of selected fields.
|
|
251
|
+
it('should support counterparty of "anyone" or "self"', async () => {
|
|
218
252
|
const fieldsToReveal = ['name']
|
|
219
|
-
|
|
253
|
+
|
|
254
|
+
// "anyone"
|
|
255
|
+
const anyoneKeyring = await MasterCertificate.createKeyringForVerifier(
|
|
220
256
|
subjectWallet,
|
|
257
|
+
issuedCert.certifier,
|
|
221
258
|
'anyone',
|
|
259
|
+
issuedCert.fields,
|
|
222
260
|
fieldsToReveal,
|
|
261
|
+
issuedCert.masterKeyring,
|
|
262
|
+
issuedCert.serialNumber,
|
|
223
263
|
'my-originator'
|
|
224
264
|
)
|
|
225
|
-
expect(
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
const
|
|
229
|
-
const keyringForVerifier = await issuedCert.createKeyringForVerifier(
|
|
265
|
+
expect(anyoneKeyring).toHaveProperty('name')
|
|
266
|
+
|
|
267
|
+
// "self"
|
|
268
|
+
const selfKeyring = await MasterCertificate.createKeyringForVerifier(
|
|
230
269
|
subjectWallet,
|
|
270
|
+
issuedCert.certifier,
|
|
231
271
|
'self',
|
|
272
|
+
issuedCert.fields,
|
|
232
273
|
fieldsToReveal,
|
|
274
|
+
issuedCert.masterKeyring,
|
|
275
|
+
issuedCert.serialNumber,
|
|
233
276
|
'my-originator'
|
|
234
277
|
)
|
|
235
|
-
expect(
|
|
278
|
+
expect(selfKeyring).toHaveProperty('name')
|
|
236
279
|
})
|
|
237
280
|
})
|
|
238
281
|
|
|
239
|
-
describe('issueCertificateForSubject', () => {
|
|
282
|
+
describe('issueCertificateForSubject (static)', () => {
|
|
240
283
|
it('should issue a valid MasterCertificate for the given subject', async () => {
|
|
241
284
|
const newPlaintextFields = {
|
|
242
285
|
project: 'Top Secret',
|
|
@@ -247,16 +290,16 @@ describe('MasterCertificate', () => {
|
|
|
247
290
|
|
|
248
291
|
const newCert = await MasterCertificate.issueCertificateForSubject(
|
|
249
292
|
certifierWallet,
|
|
250
|
-
|
|
293
|
+
subjectIdentityKey,
|
|
251
294
|
newPlaintextFields,
|
|
252
295
|
'TEST_CERT',
|
|
253
|
-
revocationFn
|
|
296
|
+
revocationFn
|
|
254
297
|
)
|
|
255
298
|
|
|
256
299
|
expect(newCert).toBeInstanceOf(MasterCertificate)
|
|
257
300
|
// The certificate's fields should be encrypted base64
|
|
258
301
|
for (const fieldName in newPlaintextFields) {
|
|
259
|
-
expect(newCert.fields[fieldName]).toMatch(/^[A-Za-z0-9+/]+=*$/) // base64 check
|
|
302
|
+
expect(newCert.fields[fieldName]).toMatch(/^[A-Za-z0-9+/]+=*$/) // quick base64 check
|
|
260
303
|
}
|
|
261
304
|
// The masterKeyring should also contain base64 strings
|
|
262
305
|
for (const fieldName in newPlaintextFields) {
|
|
@@ -266,8 +309,56 @@ describe('MasterCertificate', () => {
|
|
|
266
309
|
expect(newCert.revocationOutpoint).toEqual(mockRevocationOutpoint)
|
|
267
310
|
// Check we have a signature
|
|
268
311
|
expect(newCert.signature).toBeDefined()
|
|
269
|
-
// Check that the revocationFn
|
|
312
|
+
// Check that the revocationFn was called
|
|
270
313
|
expect(revocationFn).toHaveBeenCalledWith(newCert.serialNumber)
|
|
271
314
|
})
|
|
315
|
+
|
|
316
|
+
it('should allow passing a custom serial number when issuing the certificate', async () => {
|
|
317
|
+
const customSerialNumber = Utils.toBase64(Random(32))
|
|
318
|
+
const newPlaintextFields = { status: 'Approved' }
|
|
319
|
+
const newCert = await MasterCertificate.issueCertificateForSubject(
|
|
320
|
+
certifierWallet,
|
|
321
|
+
subjectIdentityKey,
|
|
322
|
+
newPlaintextFields,
|
|
323
|
+
'TEST_CERT',
|
|
324
|
+
undefined, // No custom revocation function
|
|
325
|
+
customSerialNumber // Pass our custom serial number
|
|
326
|
+
)
|
|
327
|
+
|
|
328
|
+
expect(newCert).toBeInstanceOf(MasterCertificate)
|
|
329
|
+
expect(newCert.serialNumber).toEqual(customSerialNumber) // Must match exactly
|
|
330
|
+
// Check encryption
|
|
331
|
+
for (const fieldName in newPlaintextFields) {
|
|
332
|
+
expect(newCert.fields[fieldName]).toMatch(/^[A-Za-z0-9+/]+=*$/)
|
|
333
|
+
}
|
|
334
|
+
})
|
|
335
|
+
it('should allow issuing a self-signed certificate and decrypt it with the same wallet', async () => {
|
|
336
|
+
// In a self-signed scenario, the subject and certifier are the same
|
|
337
|
+
const subjectWallet = new CompletedProtoWallet(PrivateKey.fromRandom())
|
|
338
|
+
|
|
339
|
+
// Some sample fields
|
|
340
|
+
const selfSignedFields = {
|
|
341
|
+
owner: 'Bob',
|
|
342
|
+
organization: 'SelfCo'
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Issue the certificate for "self"
|
|
346
|
+
const selfSignedCert = await MasterCertificate.issueCertificateForSubject(
|
|
347
|
+
subjectWallet, // act as certifier
|
|
348
|
+
'self',
|
|
349
|
+
selfSignedFields,
|
|
350
|
+
'SELF_SIGNED_TEST'
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
// Now we attempt to decrypt the fields with the same wallet
|
|
354
|
+
const decrypted = await MasterCertificate.decryptFields(
|
|
355
|
+
subjectWallet,
|
|
356
|
+
selfSignedCert.masterKeyring,
|
|
357
|
+
selfSignedCert.fields,
|
|
358
|
+
'self'
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
expect(decrypted).toEqual(selfSignedFields)
|
|
362
|
+
})
|
|
272
363
|
})
|
|
273
364
|
})
|
|
@@ -2,14 +2,16 @@ import { VerifiableCertificate } from '../../../../dist/cjs/src/auth/certificate
|
|
|
2
2
|
import { PrivateKey, SymmetricKey, Utils } from '../../../../dist/cjs/src/primitives/index.js'
|
|
3
3
|
import { CompletedProtoWallet } from '../../../../dist/cjs/src/auth/certificates/__tests/CompletedProtoWallet.js'
|
|
4
4
|
import { Certificate } from '../../../../dist/cjs/src/auth/certificates/index.js'
|
|
5
|
+
import { MasterCertificate } from '../../../../dist/cjs/src/auth/certificates/MasterCertificate.js'
|
|
6
|
+
import { ProtoWallet } from '../../../../dist/cjs/src/wallet/index.js'
|
|
5
7
|
|
|
6
8
|
describe('VerifiableCertificate', () => {
|
|
7
9
|
const subjectPrivateKey = PrivateKey.fromRandom()
|
|
8
|
-
const
|
|
10
|
+
const subjectIdentityKey = subjectPrivateKey.toPublicKey().toString()
|
|
9
11
|
const certifierPrivateKey = PrivateKey.fromRandom()
|
|
10
|
-
const
|
|
12
|
+
const certifierIdentityKey = certifierPrivateKey.toPublicKey().toString()
|
|
11
13
|
const verifierPrivateKey = PrivateKey.fromRandom()
|
|
12
|
-
const
|
|
14
|
+
const verifierIdentityKey = verifierPrivateKey.toPublicKey().toString()
|
|
13
15
|
|
|
14
16
|
const subjectWallet = new CompletedProtoWallet(subjectPrivateKey)
|
|
15
17
|
const verifierWallet = new CompletedProtoWallet(verifierPrivateKey)
|
|
@@ -28,34 +30,28 @@ describe('VerifiableCertificate', () => {
|
|
|
28
30
|
|
|
29
31
|
beforeEach(async () => {
|
|
30
32
|
// For each test, we'll build a fresh VerifiableCertificate with valid encryption
|
|
31
|
-
const certificateFields =
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
counterparty: verifierPubKey
|
|
46
|
-
})
|
|
47
|
-
keyring[fieldName] = Utils.toBase64(encryptedRevelationKey)
|
|
48
|
-
}
|
|
49
|
-
|
|
33
|
+
const { certificateFields, masterKeyring } = await MasterCertificate.createCertificateFields(
|
|
34
|
+
subjectWallet,
|
|
35
|
+
certifierIdentityKey,
|
|
36
|
+
plaintextFields
|
|
37
|
+
)
|
|
38
|
+
const keyringForVerifier = await MasterCertificate.createKeyringForVerifier(
|
|
39
|
+
subjectWallet,
|
|
40
|
+
certifierIdentityKey,
|
|
41
|
+
verifierIdentityKey,
|
|
42
|
+
certificateFields,
|
|
43
|
+
Object.keys(certificateFields),
|
|
44
|
+
masterKeyring,
|
|
45
|
+
sampleSerialNumber
|
|
46
|
+
)
|
|
50
47
|
verifiableCert = new VerifiableCertificate(
|
|
51
48
|
sampleType,
|
|
52
49
|
sampleSerialNumber,
|
|
53
|
-
|
|
54
|
-
|
|
50
|
+
subjectIdentityKey,
|
|
51
|
+
certifierIdentityKey,
|
|
55
52
|
sampleRevocationOutpoint,
|
|
56
53
|
certificateFields,
|
|
57
|
-
|
|
58
|
-
keyring
|
|
54
|
+
keyringForVerifier
|
|
59
55
|
)
|
|
60
56
|
})
|
|
61
57
|
|
|
@@ -64,8 +60,8 @@ describe('VerifiableCertificate', () => {
|
|
|
64
60
|
expect(verifiableCert).toBeInstanceOf(VerifiableCertificate)
|
|
65
61
|
expect(verifiableCert.type).toEqual(sampleType)
|
|
66
62
|
expect(verifiableCert.serialNumber).toEqual(sampleSerialNumber)
|
|
67
|
-
expect(verifiableCert.subject).toEqual(
|
|
68
|
-
expect(verifiableCert.certifier).toEqual(
|
|
63
|
+
expect(verifiableCert.subject).toEqual(subjectIdentityKey)
|
|
64
|
+
expect(verifiableCert.certifier).toEqual(certifierIdentityKey)
|
|
69
65
|
expect(verifiableCert.revocationOutpoint).toEqual(sampleRevocationOutpoint)
|
|
70
66
|
expect(verifiableCert.fields).toBeDefined()
|
|
71
67
|
expect(verifiableCert.keyring).toBeDefined()
|
|
@@ -97,8 +93,8 @@ describe('VerifiableCertificate', () => {
|
|
|
97
93
|
verifiableCert.certifier,
|
|
98
94
|
verifiableCert.revocationOutpoint,
|
|
99
95
|
fields,
|
|
100
|
-
|
|
101
|
-
|
|
96
|
+
{}, // empty
|
|
97
|
+
verifiableCert.signature
|
|
102
98
|
)
|
|
103
99
|
|
|
104
100
|
await expect(emptyKeyringCert.decryptFields(verifierWallet)).rejects.toThrow(
|
|
@@ -113,5 +109,33 @@ describe('VerifiableCertificate', () => {
|
|
|
113
109
|
/Failed to decrypt selectively revealed certificate fields using keyring/
|
|
114
110
|
)
|
|
115
111
|
})
|
|
112
|
+
|
|
113
|
+
it('should be able to decrypt fields using the anyone wallet', async () => {
|
|
114
|
+
const { certificateFields, masterKeyring } = await MasterCertificate.createCertificateFields(
|
|
115
|
+
subjectWallet,
|
|
116
|
+
certifierIdentityKey,
|
|
117
|
+
plaintextFields
|
|
118
|
+
)
|
|
119
|
+
const keyringForVerifier = await MasterCertificate.createKeyringForVerifier(
|
|
120
|
+
subjectWallet,
|
|
121
|
+
certifierIdentityKey,
|
|
122
|
+
'anyone',
|
|
123
|
+
certificateFields,
|
|
124
|
+
Object.keys(certificateFields),
|
|
125
|
+
masterKeyring,
|
|
126
|
+
sampleSerialNumber
|
|
127
|
+
)
|
|
128
|
+
verifiableCert = new VerifiableCertificate(
|
|
129
|
+
sampleType,
|
|
130
|
+
sampleSerialNumber,
|
|
131
|
+
subjectIdentityKey,
|
|
132
|
+
'anyone',
|
|
133
|
+
sampleRevocationOutpoint,
|
|
134
|
+
certificateFields,
|
|
135
|
+
keyringForVerifier
|
|
136
|
+
)
|
|
137
|
+
const decrypted = await verifiableCert.decryptFields(new ProtoWallet('anyone'))
|
|
138
|
+
expect(decrypted).toEqual(plaintextFields)
|
|
139
|
+
})
|
|
116
140
|
})
|
|
117
141
|
})
|
|
@@ -33,8 +33,8 @@ export const getVerifiableCertificates = async (wallet: WalletInterface, request
|
|
|
33
33
|
certificate.certifier,
|
|
34
34
|
certificate.revocationOutpoint,
|
|
35
35
|
certificate.fields,
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
keyringForVerifier,
|
|
37
|
+
certificate.signature
|
|
38
38
|
)
|
|
39
39
|
}))
|
|
40
40
|
}
|
|
@@ -24,8 +24,8 @@ export const validateCertificates = async (verifierWallet: WalletInterface, mess
|
|
|
24
24
|
incomingCert.certifier,
|
|
25
25
|
incomingCert.revocationOutpoint,
|
|
26
26
|
incomingCert.fields,
|
|
27
|
-
incomingCert.
|
|
28
|
-
incomingCert.
|
|
27
|
+
incomingCert.keyring,
|
|
28
|
+
incomingCert.signature
|
|
29
29
|
)
|
|
30
30
|
const isValidCert = await certToVerify.verify()
|
|
31
31
|
if (!isValidCert) {
|
|
@@ -33,9 +33,9 @@ import {
|
|
|
33
33
|
* enable the management of identity certificates, or store any data. It is also not concerned with privileged keys.
|
|
34
34
|
*/
|
|
35
35
|
export class ProtoWallet {
|
|
36
|
-
keyDeriver
|
|
36
|
+
keyDeriver?: KeyDeriverApi
|
|
37
37
|
|
|
38
|
-
constructor (rootKeyOrKeyDeriver
|
|
38
|
+
constructor (rootKeyOrKeyDeriver?: PrivateKey | 'anyone' | KeyDeriverApi) {
|
|
39
39
|
if (typeof (rootKeyOrKeyDeriver as KeyDeriver).identityKey !== 'string') {
|
|
40
40
|
rootKeyOrKeyDeriver = new KeyDeriver(rootKeyOrKeyDeriver as PrivateKey | 'anyone')
|
|
41
41
|
}
|
|
@@ -43,7 +43,8 @@ export class ProtoWallet {
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
async getPublicKey (
|
|
46
|
-
args: GetPublicKeyArgs
|
|
46
|
+
args: GetPublicKeyArgs,
|
|
47
|
+
originator?: OriginatorDomainNameStringUnder250Bytes
|
|
47
48
|
): Promise<{ publicKey: PubKeyHex }> {
|
|
48
49
|
if (args.identityKey) {
|
|
49
50
|
return { publicKey: this.keyDeriver.rootKey.toPublicKey().toString() }
|
|
@@ -65,7 +66,8 @@ export class ProtoWallet {
|
|
|
65
66
|
}
|
|
66
67
|
|
|
67
68
|
async revealCounterpartyKeyLinkage (
|
|
68
|
-
args: RevealCounterpartyKeyLinkageArgs
|
|
69
|
+
args: RevealCounterpartyKeyLinkageArgs,
|
|
70
|
+
originator?: OriginatorDomainNameStringUnder250Bytes
|
|
69
71
|
): Promise<RevealCounterpartyKeyLinkageResult> {
|
|
70
72
|
const { publicKey: identityKey } = await this.getPublicKey({ identityKey: true })
|
|
71
73
|
const linkage = this.keyDeriver.revealCounterpartySecret(args.counterparty)
|
|
@@ -99,7 +101,8 @@ export class ProtoWallet {
|
|
|
99
101
|
}
|
|
100
102
|
|
|
101
103
|
async revealSpecificKeyLinkage (
|
|
102
|
-
args: RevealSpecificKeyLinkageArgs
|
|
104
|
+
args: RevealSpecificKeyLinkageArgs,
|
|
105
|
+
originator?: OriginatorDomainNameStringUnder250Bytes
|
|
103
106
|
): Promise<RevealSpecificKeyLinkageResult> {
|
|
104
107
|
const { publicKey: identityKey } = await this.getPublicKey({ identityKey: true })
|
|
105
108
|
const linkage = this.keyDeriver.revealSpecificSecret(
|
|
@@ -132,7 +135,8 @@ export class ProtoWallet {
|
|
|
132
135
|
}
|
|
133
136
|
|
|
134
137
|
async encrypt (
|
|
135
|
-
args: WalletEncryptArgs
|
|
138
|
+
args: WalletEncryptArgs,
|
|
139
|
+
originator?: OriginatorDomainNameStringUnder250Bytes
|
|
136
140
|
): Promise<WalletEncryptResult> {
|
|
137
141
|
const key = this.keyDeriver.deriveSymmetricKey(
|
|
138
142
|
args.protocolID,
|
|
@@ -143,7 +147,8 @@ export class ProtoWallet {
|
|
|
143
147
|
}
|
|
144
148
|
|
|
145
149
|
async decrypt (
|
|
146
|
-
args: WalletDecryptArgs
|
|
150
|
+
args: WalletDecryptArgs,
|
|
151
|
+
originator?: OriginatorDomainNameStringUnder250Bytes
|
|
147
152
|
): Promise<WalletDecryptResult> {
|
|
148
153
|
const key = this.keyDeriver.deriveSymmetricKey(
|
|
149
154
|
args.protocolID,
|
|
@@ -154,7 +159,8 @@ export class ProtoWallet {
|
|
|
154
159
|
}
|
|
155
160
|
|
|
156
161
|
async createHmac (
|
|
157
|
-
args: CreateHmacArgs
|
|
162
|
+
args: CreateHmacArgs,
|
|
163
|
+
originator?: OriginatorDomainNameStringUnder250Bytes
|
|
158
164
|
): Promise<CreateHmacResult> {
|
|
159
165
|
const key = this.keyDeriver.deriveSymmetricKey(
|
|
160
166
|
args.protocolID,
|
|
@@ -165,7 +171,8 @@ export class ProtoWallet {
|
|
|
165
171
|
}
|
|
166
172
|
|
|
167
173
|
async verifyHmac (
|
|
168
|
-
args: VerifyHmacArgs
|
|
174
|
+
args: VerifyHmacArgs,
|
|
175
|
+
originator?: OriginatorDomainNameStringUnder250Bytes
|
|
169
176
|
): Promise<VerifyHmacResult> {
|
|
170
177
|
const key = this.keyDeriver.deriveSymmetricKey(
|
|
171
178
|
args.protocolID,
|
|
@@ -182,7 +189,8 @@ export class ProtoWallet {
|
|
|
182
189
|
}
|
|
183
190
|
|
|
184
191
|
async createSignature (
|
|
185
|
-
args: CreateSignatureArgs
|
|
192
|
+
args: CreateSignatureArgs,
|
|
193
|
+
originator?: OriginatorDomainNameStringUnder250Bytes
|
|
186
194
|
): Promise<CreateSignatureResult> {
|
|
187
195
|
if (!args.hashToDirectlySign && !args.data) {
|
|
188
196
|
throw new Error('args.data or args.hashToDirectlySign must be valid')
|
|
@@ -197,7 +205,8 @@ export class ProtoWallet {
|
|
|
197
205
|
}
|
|
198
206
|
|
|
199
207
|
async verifySignature (
|
|
200
|
-
args: VerifySignatureArgs
|
|
208
|
+
args: VerifySignatureArgs,
|
|
209
|
+
originator?: OriginatorDomainNameStringUnder250Bytes
|
|
201
210
|
): Promise<VerifySignatureResult> {
|
|
202
211
|
if (!args.hashToDirectlyVerify && !args.data) {
|
|
203
212
|
throw new Error('args.data or args.hashToDirectlyVerify must be valid')
|