@bsv/sdk 1.3.10 → 1.3.11
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 +93 -63
- package/dist/cjs/src/auth/certificates/MasterCertificate.js.map +1 -1
- package/dist/cjs/src/auth/certificates/VerifiableCertificate.js +2 -2
- 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/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 +93 -63
- package/dist/esm/src/auth/certificates/MasterCertificate.js.map +1 -1
- package/dist/esm/src/auth/certificates/VerifiableCertificate.js +2 -2
- 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/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/types/src/auth/certificates/Certificate.d.ts +3 -3
- package/dist/types/src/auth/certificates/Certificate.d.ts.map +1 -1
- package/dist/types/src/auth/certificates/MasterCertificate.d.ts +41 -11
- package/dist/types/src/auth/certificates/MasterCertificate.d.ts.map +1 -1
- package/dist/types/src/auth/certificates/VerifiableCertificate.d.ts +1 -1
- package/dist/types/src/auth/certificates/VerifiableCertificate.d.ts.map +1 -1
- package/dist/types/tsconfig.types.tsbuildinfo +1 -1
- package/dist/umd/bundle.js +1 -1
- package/docs/auth.md +59 -21
- package/package.json +1 -1
- package/src/auth/__tests/Peer.test.ts +19 -47
- package/src/auth/certificates/Certificate.ts +3 -3
- package/src/auth/certificates/MasterCertificate.ts +131 -67
- package/src/auth/certificates/VerifiableCertificate.ts +3 -4
- package/src/auth/certificates/__tests/MasterCertificate.test.ts +142 -51
- package/src/auth/certificates/__tests/VerifiableCertificate.test.ts +25 -30
- package/src/auth/utils/getVerifiableCertificates.ts +2 -2
- package/src/auth/utils/validateCertificates.ts +2 -2
package/docs/auth.md
CHANGED
|
@@ -212,7 +212,7 @@ export default class Certificate {
|
|
|
212
212
|
subject: PubKeyHex;
|
|
213
213
|
certifier: PubKeyHex;
|
|
214
214
|
revocationOutpoint: OutpointString;
|
|
215
|
-
fields: Record<CertificateFieldNameUnder50Bytes,
|
|
215
|
+
fields: Record<CertificateFieldNameUnder50Bytes, Base64String>;
|
|
216
216
|
signature?: HexString;
|
|
217
217
|
constructor(type: Base64String, serialNumber: Base64String, subject: PubKeyHex, certifier: PubKeyHex, revocationOutpoint: OutpointString, fields: Record<CertificateFieldNameUnder50Bytes, string>, signature?: HexString)
|
|
218
218
|
toBinary(includeSignature: boolean = true): number[]
|
|
@@ -269,12 +269,12 @@ See also: [PubKeyHex](#type-pubkeyhex)
|
|
|
269
269
|
|
|
270
270
|
#### Property fields
|
|
271
271
|
|
|
272
|
-
All the fields present in the certificate, with field names as keys and field values as strings.
|
|
272
|
+
All the fields present in the certificate, with field names as keys and encrypted field values as Base64 strings.
|
|
273
273
|
|
|
274
274
|
```ts
|
|
275
|
-
fields: Record<CertificateFieldNameUnder50Bytes,
|
|
275
|
+
fields: Record<CertificateFieldNameUnder50Bytes, Base64String>
|
|
276
276
|
```
|
|
277
|
-
See also: [CertificateFieldNameUnder50Bytes](#type-certificatefieldnameunder50bytes)
|
|
277
|
+
See also: [Base64String](#type-base64string), [CertificateFieldNameUnder50Bytes](#type-certificatefieldnameunder50bytes)
|
|
278
278
|
|
|
279
279
|
#### Property revocationOutpoint
|
|
280
280
|
|
|
@@ -466,9 +466,10 @@ export class MasterCertificate extends Certificate {
|
|
|
466
466
|
declare signature?: HexString;
|
|
467
467
|
masterKeyring: Record<CertificateFieldNameUnder50Bytes, Base64String>;
|
|
468
468
|
constructor(type: Base64String, serialNumber: Base64String, subject: PubKeyHex, certifier: PubKeyHex, revocationOutpoint: OutpointString, fields: Record<CertificateFieldNameUnder50Bytes, Base64String>, masterKeyring: Record<CertificateFieldNameUnder50Bytes, Base64String>, signature?: HexString)
|
|
469
|
-
async
|
|
470
|
-
async createKeyringForVerifier(subjectWallet: WalletInterface, verifier: WalletCounterparty, fieldsToReveal: string[], originator?: string): Promise<Record<CertificateFieldNameUnder50Bytes, string>>
|
|
471
|
-
static async issueCertificateForSubject(certifierWallet: WalletInterface, subject: WalletCounterparty, fields: Record<CertificateFieldNameUnder50Bytes, string>, certificateType: string, getRevocationOutpoint = async (serialNumber: string): Promise<string> => { return "Certificate revocation not tracked."; }): Promise<MasterCertificate>
|
|
469
|
+
static async createCertificateFields(creatorWallet: WalletInterface, certifierOrSubject: WalletCounterparty, fields: Record<CertificateFieldNameUnder50Bytes, string>): Promise<CreateCertificateFieldsResult>
|
|
470
|
+
static async createKeyringForVerifier(subjectWallet: WalletInterface, certifier: WalletCounterparty, verifier: WalletCounterparty, fields: Record<CertificateFieldNameUnder50Bytes, Base64String>, fieldsToReveal: string[], masterKeyring: Record<CertificateFieldNameUnder50Bytes, Base64String>, serialNumber: Base64String, originator?: string): Promise<Record<CertificateFieldNameUnder50Bytes, string>>
|
|
471
|
+
static async issueCertificateForSubject(certifierWallet: WalletInterface, subject: WalletCounterparty, fields: Record<CertificateFieldNameUnder50Bytes, string>, certificateType: string, getRevocationOutpoint = async (serialNumber: string): Promise<string> => { return "Certificate revocation not tracked."; }, serialNumber?: string): Promise<MasterCertificate>
|
|
472
|
+
static async decryptFields(subjectOrCertifierWallet: WalletInterface, masterKeyring: Record<CertificateFieldNameUnder50Bytes, Base64String>, fields: Record<CertificateFieldNameUnder50Bytes, Base64String>, counterparty: WalletCounterparty): Promise<Record<CertificateFieldNameUnder50Bytes, string>>
|
|
472
473
|
}
|
|
473
474
|
```
|
|
474
475
|
|
|
@@ -478,6 +479,34 @@ See also: [Base64String](#type-base64string), [Certificate](#class-certificate),
|
|
|
478
479
|
|
|
479
480
|
<summary>Class MasterCertificate Details</summary>
|
|
480
481
|
|
|
482
|
+
#### Method createCertificateFields
|
|
483
|
+
|
|
484
|
+
Encrypts certificate fields for a subject and generates a master keyring.
|
|
485
|
+
This method returns a master keyring tied to a specific certifier or subject who will validate
|
|
486
|
+
and sign off on the fields, along with the encrypted certificate fields.
|
|
487
|
+
|
|
488
|
+
```ts
|
|
489
|
+
static async createCertificateFields(creatorWallet: WalletInterface, certifierOrSubject: WalletCounterparty, fields: Record<CertificateFieldNameUnder50Bytes, string>): Promise<CreateCertificateFieldsResult>
|
|
490
|
+
```
|
|
491
|
+
See also: [CertificateFieldNameUnder50Bytes](#type-certificatefieldnameunder50bytes), [WalletCounterparty](#type-walletcounterparty), [WalletInterface](#interface-walletinterface)
|
|
492
|
+
|
|
493
|
+
Returns
|
|
494
|
+
|
|
495
|
+
A promise resolving to an object containing:
|
|
496
|
+
- `certificateFields` {Record<CertificateFieldNameUnder50Bytes, Base64String>}:
|
|
497
|
+
The encrypted certificate fields.
|
|
498
|
+
- `masterKeyring` {Record<CertificateFieldNameUnder50Bytes, Base64String>}:
|
|
499
|
+
The master keyring containing encrypted revelation keys for each field.
|
|
500
|
+
|
|
501
|
+
Argument Details
|
|
502
|
+
|
|
503
|
+
+ **creatorWallet**
|
|
504
|
+
+ The wallet of the creator responsible for encrypting the fields.
|
|
505
|
+
+ **certifierOrSubject**
|
|
506
|
+
+ The certifier or subject who will validate the certificate fields.
|
|
507
|
+
+ **fields**
|
|
508
|
+
+ A record of certificate field names (under 50 bytes) mapped to their values.
|
|
509
|
+
|
|
481
510
|
#### Method createKeyringForVerifier
|
|
482
511
|
|
|
483
512
|
Creates a keyring for a verifier, enabling them to decrypt specific certificate fields.
|
|
@@ -486,9 +515,9 @@ for the verifier's identity key. The result is a keyring containing the keys nec
|
|
|
486
515
|
for the verifier to access the designated fields.
|
|
487
516
|
|
|
488
517
|
```ts
|
|
489
|
-
async createKeyringForVerifier(subjectWallet: WalletInterface, verifier: WalletCounterparty, fieldsToReveal: string[], originator?: string): Promise<Record<CertificateFieldNameUnder50Bytes, string>>
|
|
518
|
+
static async createKeyringForVerifier(subjectWallet: WalletInterface, certifier: WalletCounterparty, verifier: WalletCounterparty, fields: Record<CertificateFieldNameUnder50Bytes, Base64String>, fieldsToReveal: string[], masterKeyring: Record<CertificateFieldNameUnder50Bytes, Base64String>, serialNumber: Base64String, originator?: string): Promise<Record<CertificateFieldNameUnder50Bytes, string>>
|
|
490
519
|
```
|
|
491
|
-
See also: [CertificateFieldNameUnder50Bytes](#type-certificatefieldnameunder50bytes), [WalletCounterparty](#type-walletcounterparty), [WalletInterface](#interface-walletinterface)
|
|
520
|
+
See also: [Base64String](#type-base64string), [CertificateFieldNameUnder50Bytes](#type-certificatefieldnameunder50bytes), [WalletCounterparty](#type-walletcounterparty), [WalletInterface](#interface-walletinterface)
|
|
492
521
|
|
|
493
522
|
Returns
|
|
494
523
|
|
|
@@ -514,24 +543,33 @@ Throws an error if:
|
|
|
514
543
|
|
|
515
544
|
#### Method decryptFields
|
|
516
545
|
|
|
517
|
-
Decrypts all fields in the MasterCertificate using the subject's wallet.
|
|
546
|
+
Decrypts all fields in the MasterCertificate using the subject's or certifier's wallet.
|
|
518
547
|
|
|
519
|
-
This method
|
|
520
|
-
|
|
548
|
+
This method allows the subject or certifier to decrypt the `masterKeyring` and retrieve
|
|
549
|
+
the encryption keys for each field, which are then used to decrypt the corresponding field values.
|
|
550
|
+
The counterparty used for decryption depends on how the certificate fields were created:
|
|
551
|
+
- If the certificate is self-signed, the counterparty should be set to 'self'.
|
|
552
|
+
- Otherwise, the counterparty should always be the other party involved in the certificate issuance process (the subject or certifier).
|
|
521
553
|
|
|
522
554
|
```ts
|
|
523
|
-
async decryptFields(
|
|
555
|
+
static async decryptFields(subjectOrCertifierWallet: WalletInterface, masterKeyring: Record<CertificateFieldNameUnder50Bytes, Base64String>, fields: Record<CertificateFieldNameUnder50Bytes, Base64String>, counterparty: WalletCounterparty): Promise<Record<CertificateFieldNameUnder50Bytes, string>>
|
|
524
556
|
```
|
|
525
|
-
See also: [CertificateFieldNameUnder50Bytes](#type-certificatefieldnameunder50bytes), [WalletInterface](#interface-walletinterface)
|
|
557
|
+
See also: [Base64String](#type-base64string), [CertificateFieldNameUnder50Bytes](#type-certificatefieldnameunder50bytes), [WalletCounterparty](#type-walletcounterparty), [WalletInterface](#interface-walletinterface)
|
|
526
558
|
|
|
527
559
|
Returns
|
|
528
560
|
|
|
529
|
-
|
|
561
|
+
A promise resolving to a record of field names and their decrypted values in plaintext.
|
|
530
562
|
|
|
531
563
|
Argument Details
|
|
532
564
|
|
|
533
|
-
+ **
|
|
534
|
-
+ The wallet of the subject, used to decrypt the master keyring and field values.
|
|
565
|
+
+ **subjectOrCertifierWallet**
|
|
566
|
+
+ The wallet of the subject or certifier, used to decrypt the master keyring and field values.
|
|
567
|
+
+ **masterKeyring**
|
|
568
|
+
+ A record containing encrypted keys for each field.
|
|
569
|
+
+ **fields**
|
|
570
|
+
+ A record of encrypted field names and their values.
|
|
571
|
+
+ **counterparty**
|
|
572
|
+
+ The counterparty responsible for creating or signing the certificate. For self-signed certificates, use 'self'.
|
|
535
573
|
|
|
536
574
|
Throws
|
|
537
575
|
|
|
@@ -547,7 +585,7 @@ generated symmetric key, which is then encrypted for the subject. The certificat
|
|
|
547
585
|
can also includes a revocation outpoint to manage potential revocation.
|
|
548
586
|
|
|
549
587
|
```ts
|
|
550
|
-
static async issueCertificateForSubject(certifierWallet: WalletInterface, subject: WalletCounterparty, fields: Record<CertificateFieldNameUnder50Bytes, string>, certificateType: string, getRevocationOutpoint = async (serialNumber: string): Promise<string> => { return "Certificate revocation not tracked."; }): Promise<MasterCertificate>
|
|
588
|
+
static async issueCertificateForSubject(certifierWallet: WalletInterface, subject: WalletCounterparty, fields: Record<CertificateFieldNameUnder50Bytes, string>, certificateType: string, getRevocationOutpoint = async (serialNumber: string): Promise<string> => { return "Certificate revocation not tracked."; }, serialNumber?: string): Promise<MasterCertificate>
|
|
551
589
|
```
|
|
552
590
|
See also: [CertificateFieldNameUnder50Bytes](#type-certificatefieldnameunder50bytes), [MasterCertificate](#class-mastercertificate), [WalletCounterparty](#type-walletcounterparty), [WalletInterface](#interface-walletinterface)
|
|
553
591
|
|
|
@@ -1078,7 +1116,7 @@ export class VerifiableCertificate extends Certificate {
|
|
|
1078
1116
|
declare signature?: HexString;
|
|
1079
1117
|
keyring: Record<CertificateFieldNameUnder50Bytes, string>;
|
|
1080
1118
|
decryptedFields?: Record<CertificateFieldNameUnder50Bytes, Base64String>;
|
|
1081
|
-
constructor(type: Base64String, serialNumber: Base64String, subject: PubKeyHex, certifier: PubKeyHex, revocationOutpoint: OutpointString, fields: Record<CertificateFieldNameUnder50Bytes, string>,
|
|
1119
|
+
constructor(type: Base64String, serialNumber: Base64String, subject: PubKeyHex, certifier: PubKeyHex, revocationOutpoint: OutpointString, fields: Record<CertificateFieldNameUnder50Bytes, string>, keyring: Record<CertificateFieldNameUnder50Bytes, string>, signature?: HexString, decryptedFields?: Record<CertificateFieldNameUnder50Bytes, Base64String>)
|
|
1082
1120
|
async decryptFields(verifierWallet: WalletInterface): Promise<Record<CertificateFieldNameUnder50Bytes, string>>
|
|
1083
1121
|
}
|
|
1084
1122
|
```
|
|
@@ -1214,7 +1252,7 @@ getVerifiableCertificates = async (wallet: WalletInterface, requestedCertificate
|
|
|
1214
1252
|
fieldsToReveal: requestedCertificates.types[certificate.type],
|
|
1215
1253
|
verifier: verifierIdentityKey
|
|
1216
1254
|
});
|
|
1217
|
-
return new VerifiableCertificate(certificate.type, certificate.serialNumber, certificate.subject, certificate.certifier, certificate.revocationOutpoint, certificate.fields, certificate.signature
|
|
1255
|
+
return new VerifiableCertificate(certificate.type, certificate.serialNumber, certificate.subject, certificate.certifier, certificate.revocationOutpoint, certificate.fields, keyringForVerifier, certificate.signature);
|
|
1218
1256
|
}));
|
|
1219
1257
|
}
|
|
1220
1258
|
```
|
|
@@ -1232,7 +1270,7 @@ validateCertificates = async (verifierWallet: WalletInterface, message: AuthMess
|
|
|
1232
1270
|
if (incomingCert.subject !== message.identityKey) {
|
|
1233
1271
|
throw new Error(`The subject of one of your certificates ("${incomingCert.subject}") is not the same as the request sender ("${message.identityKey}").`);
|
|
1234
1272
|
}
|
|
1235
|
-
const certToVerify = new VerifiableCertificate(incomingCert.type, incomingCert.serialNumber, incomingCert.subject, incomingCert.certifier, incomingCert.revocationOutpoint, incomingCert.fields, incomingCert.
|
|
1273
|
+
const certToVerify = new VerifiableCertificate(incomingCert.type, incomingCert.serialNumber, incomingCert.subject, incomingCert.certifier, incomingCert.revocationOutpoint, incomingCert.fields, incomingCert.keyring, incomingCert.signature);
|
|
1236
1274
|
const isValidCert = await certToVerify.verify();
|
|
1237
1275
|
if (!isValidCert) {
|
|
1238
1276
|
throw new Error(`The signature for the certificate with serial number ${certToVerify.serialNumber} is invalid!`);
|
package/package.json
CHANGED
|
@@ -7,44 +7,8 @@ import { Utils, PrivateKey, SymmetricKey } from '../../../dist/cjs/src/primitive
|
|
|
7
7
|
import { VerifiableCertificate, } from "../../../dist/cjs/src/auth/certificates/VerifiableCertificate.js"
|
|
8
8
|
import { MasterCertificate } from '../../../dist/cjs/src/auth/certificates/MasterCertificate.js'
|
|
9
9
|
import { getVerifiableCertificates } from '../../../dist/cjs/src/auth/utils/getVerifiableCertificates.js'
|
|
10
|
-
import { Certificate } from "../../../dist/cjs/src/auth/certificates/index.js"
|
|
11
10
|
jest.mock('../../../dist/cjs/src/auth/utils/getVerifiableCertificates.js')
|
|
12
11
|
|
|
13
|
-
/**
|
|
14
|
-
* A helper function to decrypt a VerifiableCertificate's fields using the provided wallets.
|
|
15
|
-
*/
|
|
16
|
-
async function decryptCertificateFields(
|
|
17
|
-
cert: VerifiableCertificate,
|
|
18
|
-
localWallet: Wallet,
|
|
19
|
-
counterpartyWallet: Wallet
|
|
20
|
-
): Promise<Record<string, string>> {
|
|
21
|
-
const entries = await Promise.all(
|
|
22
|
-
Object.entries(cert.keyring).map(async ([fieldName, encryptedKey]) => {
|
|
23
|
-
// Decrypt the per-field symmetric key
|
|
24
|
-
const { plaintext: masterFieldKey } = await localWallet.decrypt({
|
|
25
|
-
ciphertext: Utils.toArray(encryptedKey, 'base64'),
|
|
26
|
-
...Certificate.getCertificateFieldEncryptionDetails(cert.serialNumber, fieldName),
|
|
27
|
-
counterparty: (await counterpartyWallet.getPublicKey({ identityKey: true })).publicKey,
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
// Decrypt the actual field contents using the decrypted symmetric key
|
|
31
|
-
try {
|
|
32
|
-
const decryptedData = new SymmetricKey(masterFieldKey).decrypt(
|
|
33
|
-
Utils.toArray(cert.fields[fieldName], 'base64')
|
|
34
|
-
)
|
|
35
|
-
return { key: fieldName, value: Utils.toUTF8(decryptedData as number[]) }
|
|
36
|
-
} catch (_) {
|
|
37
|
-
throw new Error(`Decryption of the "${fieldName}" field with its revelation key failed.`)
|
|
38
|
-
}
|
|
39
|
-
})
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
return entries.reduce((acc, { key, value }) => {
|
|
43
|
-
acc[key] = value
|
|
44
|
-
return acc
|
|
45
|
-
}, {} as Record<string, string>)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
12
|
class LocalTransport implements Transport {
|
|
49
13
|
private peerTransport?: LocalTransport
|
|
50
14
|
private onDataCallback?: (message: AuthMessage) => void
|
|
@@ -117,7 +81,15 @@ describe('Peer class mutual authentication and certificate exchange', () => {
|
|
|
117
81
|
): Promise<VerifiableCertificate> {
|
|
118
82
|
const certifierWallet = new ProtoWallet(certifierPrivateKey)
|
|
119
83
|
|
|
120
|
-
const keyringForVerifier = await
|
|
84
|
+
const keyringForVerifier = await MasterCertificate.createKeyringForVerifier(
|
|
85
|
+
wallet,
|
|
86
|
+
certifierWallet.keyDeriver.identityKey,
|
|
87
|
+
verifierIdentityKey,
|
|
88
|
+
masterCertificate.fields,
|
|
89
|
+
fieldsToReveal,
|
|
90
|
+
masterCertificate.masterKeyring,
|
|
91
|
+
masterCertificate.serialNumber
|
|
92
|
+
)
|
|
121
93
|
return new VerifiableCertificate(
|
|
122
94
|
masterCertificate.type,
|
|
123
95
|
masterCertificate.serialNumber,
|
|
@@ -125,8 +97,8 @@ describe('Peer class mutual authentication and certificate exchange', () => {
|
|
|
125
97
|
masterCertificate.certifier,
|
|
126
98
|
masterCertificate.revocationOutpoint,
|
|
127
99
|
masterCertificate.fields,
|
|
128
|
-
|
|
129
|
-
|
|
100
|
+
keyringForVerifier,
|
|
101
|
+
masterCertificate.signature
|
|
130
102
|
)
|
|
131
103
|
}
|
|
132
104
|
|
|
@@ -234,7 +206,7 @@ describe('Peer class mutual authentication and certificate exchange', () => {
|
|
|
234
206
|
if (certificatesReceivedByBob?.length !== 0) {
|
|
235
207
|
certificatesReceivedByBob?.forEach(async cert => {
|
|
236
208
|
// Decrypt to ensure it has the correct fields
|
|
237
|
-
const decryptedFields = await
|
|
209
|
+
const decryptedFields = await cert.decryptFields(walletB)
|
|
238
210
|
if (cert.certifier !== 'bob') {
|
|
239
211
|
console.log('Bob accepted the message:', Utils.toUTF8(payload))
|
|
240
212
|
console.log('Decrypted fields:', decryptedFields)
|
|
@@ -279,7 +251,7 @@ describe('Peer class mutual authentication and certificate exchange', () => {
|
|
|
279
251
|
alice.listenForCertificatesReceived(async (senderPublicKey, certificates) => {
|
|
280
252
|
for (const cert of certificates) {
|
|
281
253
|
// Decrypt Bob's certificate fields
|
|
282
|
-
const decryptedFields = await
|
|
254
|
+
const decryptedFields = await cert.decryptFields(walletA)
|
|
283
255
|
|
|
284
256
|
// Check and use the decrypted fields
|
|
285
257
|
if (Object.keys(decryptedFields).length !== 0 && decryptedFields.libraryCardNumber) {
|
|
@@ -342,7 +314,7 @@ describe('Peer class mutual authentication and certificate exchange', () => {
|
|
|
342
314
|
if (certificates.length > 0) {
|
|
343
315
|
// Decrypt to confirm
|
|
344
316
|
for (const cert of certificates) {
|
|
345
|
-
const decrypted = await
|
|
317
|
+
const decrypted = await cert.decryptFields(walletB)
|
|
346
318
|
console.log('Bob received additional certificates from Alice:', cert)
|
|
347
319
|
console.log('Decrypted fields:', decrypted)
|
|
348
320
|
}
|
|
@@ -384,7 +356,7 @@ describe('Peer class mutual authentication and certificate exchange', () => {
|
|
|
384
356
|
bob.listenForCertificatesReceived(async (senderPublicKey, certificates) => {
|
|
385
357
|
for (const cert of certificates) {
|
|
386
358
|
// Decrypt Alice's certificate fields
|
|
387
|
-
const decryptedFields = await
|
|
359
|
+
const decryptedFields = await cert.decryptFields(walletB)
|
|
388
360
|
if (decryptedFields.membershipStatus) {
|
|
389
361
|
console.log(`Bob received Alice's membership status: ${decryptedFields.membershipStatus}`)
|
|
390
362
|
bobAcceptedMembershipStatus()
|
|
@@ -451,7 +423,7 @@ describe('Peer class mutual authentication and certificate exchange', () => {
|
|
|
451
423
|
const waitForAliceToAcceptBobDL = new Promise<void>((resolve) => {
|
|
452
424
|
alice.listenForCertificatesReceived(async (senderPublicKey, certificates) => {
|
|
453
425
|
for (const cert of certificates) {
|
|
454
|
-
const decryptedFields = await
|
|
426
|
+
const decryptedFields = await cert.decryptFields(walletA)
|
|
455
427
|
if (decryptedFields.driversLicenseNumber) {
|
|
456
428
|
console.log(`Alice received Bob's driver's license number: ${decryptedFields.driversLicenseNumber}`)
|
|
457
429
|
aliceAcceptedBobDL()
|
|
@@ -464,7 +436,7 @@ describe('Peer class mutual authentication and certificate exchange', () => {
|
|
|
464
436
|
const waitForBobToAcceptAliceDL = new Promise<void>((resolve) => {
|
|
465
437
|
bob.listenForCertificatesReceived(async (senderPublicKey, certificates) => {
|
|
466
438
|
for (const cert of certificates) {
|
|
467
|
-
const decryptedFields = await
|
|
439
|
+
const decryptedFields = await cert.decryptFields(walletB)
|
|
468
440
|
if (decryptedFields.driversLicenseNumber) {
|
|
469
441
|
console.log(`Bob received Alice's driver's license number: ${decryptedFields.driversLicenseNumber}`)
|
|
470
442
|
bobAcceptedAliceDL()
|
|
@@ -544,7 +516,7 @@ describe('Peer class mutual authentication and certificate exchange', () => {
|
|
|
544
516
|
const waitForAlicePartialCert = new Promise<void>((resolve) => {
|
|
545
517
|
alice.listenForCertificatesReceived(async (senderPublicKey, certificates) => {
|
|
546
518
|
for (const cert of certificates) {
|
|
547
|
-
const decryptedFields = await
|
|
519
|
+
const decryptedFields = await cert.decryptFields(walletA)
|
|
548
520
|
if (decryptedFields.email || decryptedFields.name) {
|
|
549
521
|
console.log(`Alice received Bob's certificate with fields: ${Object.keys(decryptedFields).join(', ')}`)
|
|
550
522
|
aliceAcceptedPartialCert()
|
|
@@ -557,7 +529,7 @@ describe('Peer class mutual authentication and certificate exchange', () => {
|
|
|
557
529
|
const waitForBobPartialCert = new Promise<void>((resolve) => {
|
|
558
530
|
bob.listenForCertificatesReceived(async (senderPublicKey, certificates) => {
|
|
559
531
|
for (const cert of certificates) {
|
|
560
|
-
const decryptedFields = await
|
|
532
|
+
const decryptedFields = await cert.decryptFields(walletB)
|
|
561
533
|
if (decryptedFields.email || decryptedFields.name) {
|
|
562
534
|
console.log(`Bob received Alice's certificate with fields: ${Object.keys(decryptedFields).join(', ')}`)
|
|
563
535
|
bobAcceptedPartialCert()
|
|
@@ -43,9 +43,9 @@ export default class Certificate {
|
|
|
43
43
|
revocationOutpoint: OutpointString
|
|
44
44
|
|
|
45
45
|
/**
|
|
46
|
-
* All the fields present in the certificate, with field names as keys and field values as strings.
|
|
46
|
+
* All the fields present in the certificate, with field names as keys and encrypted field values as Base64 strings.
|
|
47
47
|
*/
|
|
48
|
-
fields: Record<CertificateFieldNameUnder50Bytes,
|
|
48
|
+
fields: Record<CertificateFieldNameUnder50Bytes, Base64String>
|
|
49
49
|
|
|
50
50
|
/**
|
|
51
51
|
* Certificate signature by the certifier's private key, DER encoded hex string.
|
|
@@ -258,7 +258,7 @@ export default class Certificate {
|
|
|
258
258
|
* - `protocolID` (WalletProtocol): The protocol ID for certificate field encryption.
|
|
259
259
|
* - `keyID` (string): A unique key identifier derived from the serial number and field name.
|
|
260
260
|
*/
|
|
261
|
-
static getCertificateFieldEncryptionDetails(
|
|
261
|
+
static getCertificateFieldEncryptionDetails(fieldName: string, serialNumber?: string): { protocolID: WalletProtocol, keyID: string } {
|
|
262
262
|
return { protocolID: [2, 'certificate field encryption'], keyID: `${serialNumber} ${fieldName}` }
|
|
263
263
|
}
|
|
264
264
|
}
|
|
@@ -12,6 +12,11 @@ import {
|
|
|
12
12
|
} from '../../../mod.js'
|
|
13
13
|
import Certificate from './Certificate.js'
|
|
14
14
|
|
|
15
|
+
interface CreateCertificateFieldsResult {
|
|
16
|
+
certificateFields: Record<CertificateFieldNameUnder50Bytes, Base64String>
|
|
17
|
+
masterKeyring: Record<CertificateFieldNameUnder50Bytes, Base64String>
|
|
18
|
+
}
|
|
19
|
+
|
|
15
20
|
/**
|
|
16
21
|
* MasterCertificate extends the base Certificate class to manage a master keyring, enabling the creation of verifiable certificates.
|
|
17
22
|
*
|
|
@@ -56,38 +61,42 @@ export class MasterCertificate extends Certificate {
|
|
|
56
61
|
}
|
|
57
62
|
|
|
58
63
|
/**
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
* @param {
|
|
65
|
-
* @
|
|
66
|
-
*
|
|
67
|
-
*
|
|
64
|
+
* Encrypts certificate fields for a subject and generates a master keyring.
|
|
65
|
+
* This method returns a master keyring tied to a specific certifier or subject who will validate
|
|
66
|
+
* and sign off on the fields, along with the encrypted certificate fields.
|
|
67
|
+
*
|
|
68
|
+
* @param {WalletInterface} creatorWallet - The wallet of the creator responsible for encrypting the fields.
|
|
69
|
+
* @param {WalletCounterparty} certifierOrSubject - The certifier or subject who will validate the certificate fields.
|
|
70
|
+
* @param {Record<CertificateFieldNameUnder50Bytes, string>} fields - A record of certificate field names (under 50 bytes) mapped to their values.
|
|
71
|
+
* @returns {Promise<CreateCertificateFieldsResult>} A promise resolving to an object containing:
|
|
72
|
+
* - `certificateFields` {Record<CertificateFieldNameUnder50Bytes, Base64String>}:
|
|
73
|
+
* The encrypted certificate fields.
|
|
74
|
+
* - `masterKeyring` {Record<CertificateFieldNameUnder50Bytes, Base64String>}:
|
|
75
|
+
* The master keyring containing encrypted revelation keys for each field.
|
|
68
76
|
*/
|
|
69
|
-
async
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
77
|
+
static async createCertificateFields(
|
|
78
|
+
creatorWallet: WalletInterface,
|
|
79
|
+
certifierOrSubject: WalletCounterparty,
|
|
80
|
+
fields: Record<CertificateFieldNameUnder50Bytes, string>
|
|
81
|
+
): Promise<CreateCertificateFieldsResult> {
|
|
82
|
+
const certificateFields: Record<CertificateFieldNameUnder50Bytes, Base64String> = {}
|
|
83
|
+
const masterKeyring: Record<CertificateFieldNameUnder50Bytes, Base64String> = {}
|
|
84
|
+
for (const [fieldName, fieldValue] of Object.entries(fields)) {
|
|
85
|
+
const fieldSymmetricKey = SymmetricKey.fromRandom()
|
|
86
|
+
const encryptedFieldValue = fieldSymmetricKey.encrypt(Utils.toArray(fieldValue, 'utf8'))
|
|
87
|
+
certificateFields[fieldName] = Utils.toBase64(encryptedFieldValue as number[])
|
|
88
|
+
|
|
89
|
+
const { ciphertext: encryptedFieldRevelationKey } = await creatorWallet.encrypt({
|
|
90
|
+
plaintext: fieldSymmetricKey.toArray(),
|
|
91
|
+
...Certificate.getCertificateFieldEncryptionDetails(fieldName), // Only fieldName used on MasterCertificate
|
|
92
|
+
counterparty: certifierOrSubject
|
|
93
|
+
})
|
|
94
|
+
masterKeyring[fieldName] = Utils.toBase64(encryptedFieldRevelationKey)
|
|
74
95
|
}
|
|
75
96
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
const { plaintext: fieldRevelationKey } = await subjectWallet.decrypt({
|
|
80
|
-
ciphertext: Utils.toArray(this.masterKeyring[fieldName], 'base64'),
|
|
81
|
-
counterparty: this.certifier,
|
|
82
|
-
...Certificate.getCertificateFieldEncryptionDetails(this.serialNumber, fieldName)
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
const fieldValue = new SymmetricKey(fieldRevelationKey).decrypt(Utils.toArray(this.fields[fieldName], 'base64'))
|
|
86
|
-
decryptedFields[fieldName] = Utils.toUTF8(fieldValue as number[])
|
|
87
|
-
}
|
|
88
|
-
return decryptedFields
|
|
89
|
-
} catch (e) {
|
|
90
|
-
throw new Error('Failed to decrypt all master certificate fields.')
|
|
97
|
+
return {
|
|
98
|
+
certificateFields,
|
|
99
|
+
masterKeyring
|
|
91
100
|
}
|
|
92
101
|
}
|
|
93
102
|
|
|
@@ -107,37 +116,32 @@ export class MasterCertificate extends Certificate {
|
|
|
107
116
|
* - A field in `fieldsToReveal` does not exist in the certificate.
|
|
108
117
|
* - The decrypted master field key fails to decrypt the corresponding field (indicating an invalid key).
|
|
109
118
|
*/
|
|
110
|
-
async createKeyringForVerifier(
|
|
119
|
+
static async createKeyringForVerifier(
|
|
120
|
+
subjectWallet: WalletInterface,
|
|
121
|
+
certifier: WalletCounterparty,
|
|
122
|
+
verifier: WalletCounterparty,
|
|
123
|
+
fields: Record<CertificateFieldNameUnder50Bytes, Base64String>,
|
|
124
|
+
fieldsToReveal: string[],
|
|
125
|
+
masterKeyring: Record<CertificateFieldNameUnder50Bytes, Base64String>,
|
|
126
|
+
serialNumber: Base64String,
|
|
127
|
+
originator?: string): Promise<Record<CertificateFieldNameUnder50Bytes, string>> {
|
|
111
128
|
if (!Array.isArray(fieldsToReveal)) {
|
|
112
129
|
throw new Error('fieldsToReveal must be an array of strings')
|
|
113
130
|
}
|
|
114
131
|
const fieldRevelationKeyring = {}
|
|
115
132
|
for (const fieldName of fieldsToReveal) {
|
|
116
133
|
// Make sure that fields to reveal is a subset of the certificate fields
|
|
117
|
-
if (!
|
|
134
|
+
if (!fields[fieldName]) {
|
|
118
135
|
throw new Error(`Fields to reveal must be a subset of the certificate fields. Missing the "${fieldName}" field.`)
|
|
119
136
|
}
|
|
120
137
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
// Decrypt the master field key
|
|
124
|
-
const { plaintext: masterFieldKey } = await subjectWallet.decrypt({
|
|
125
|
-
ciphertext: Utils.toArray(encryptedMasterFieldKey, 'base64'),
|
|
126
|
-
...Certificate.getCertificateFieldEncryptionDetails(this.serialNumber, fieldName),
|
|
127
|
-
counterparty: this.certifier
|
|
128
|
-
}, originator)
|
|
129
|
-
|
|
130
|
-
// Verify that derived key actually decrypts requested field
|
|
131
|
-
try {
|
|
132
|
-
new SymmetricKey(masterFieldKey).decrypt(Utils.toArray(this.fields[fieldName], 'base64'))
|
|
133
|
-
} catch (_) {
|
|
134
|
-
throw new Error(`Decryption of the "${fieldName}" field with its revelation key failed.`)
|
|
135
|
-
}
|
|
138
|
+
// Decrypt the master field key and verify that derived key actually decrypts requested field
|
|
139
|
+
const masterFieldKey = (await this.decryptField(subjectWallet, masterKeyring, fieldName, fields[fieldName], certifier)).fieldRevelationKey
|
|
136
140
|
|
|
137
141
|
// Encrypt derived fieldRevelationKey for verifier
|
|
138
142
|
const { ciphertext: encryptedFieldRevelationKey } = await subjectWallet.encrypt({
|
|
139
143
|
plaintext: masterFieldKey,
|
|
140
|
-
...Certificate.getCertificateFieldEncryptionDetails(
|
|
144
|
+
...Certificate.getCertificateFieldEncryptionDetails(fieldName, serialNumber),
|
|
141
145
|
counterparty: verifier
|
|
142
146
|
}, originator)
|
|
143
147
|
|
|
@@ -175,27 +179,21 @@ export class MasterCertificate extends Certificate {
|
|
|
175
179
|
certificateType: string,
|
|
176
180
|
getRevocationOutpoint = async (
|
|
177
181
|
serialNumber: string
|
|
178
|
-
): Promise<string> => { return 'Certificate revocation not tracked.' }
|
|
182
|
+
): Promise<string> => { return 'Certificate revocation not tracked.' },
|
|
183
|
+
serialNumber?: string
|
|
179
184
|
): Promise<MasterCertificate> {
|
|
180
|
-
// 1. Generate serialNumber
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
const encryptedCertificateFields: Record<CertificateFieldNameUnder50Bytes, Base64String> = {}
|
|
184
|
-
const masterKeyringForSubject: Record<CertificateFieldNameUnder50Bytes, Base64String> = {}
|
|
185
|
-
|
|
186
|
-
// 2. For each field, generate a random key -> encrypt field -> encrypt key
|
|
187
|
-
for (const [fieldName, fieldValue] of Object.entries(fields)) {
|
|
188
|
-
const fieldSymmetricKey = SymmetricKey.fromRandom()
|
|
189
|
-
const encryptedFieldValue = fieldSymmetricKey.encrypt(Utils.toArray(fieldValue, 'utf8'))
|
|
190
|
-
encryptedCertificateFields[fieldName] = Utils.toBase64(encryptedFieldValue as number[])
|
|
191
|
-
const { ciphertext: encryptedFieldRevelationKey } = await certifierWallet.encrypt({
|
|
192
|
-
plaintext: fieldSymmetricKey.toArray(),
|
|
193
|
-
...Certificate.getCertificateFieldEncryptionDetails(serialNumber, fieldName),
|
|
194
|
-
counterparty: subject
|
|
195
|
-
})
|
|
196
|
-
masterKeyringForSubject[fieldName] = Utils.toBase64(encryptedFieldRevelationKey)
|
|
185
|
+
// 1. Generate a random serialNumber if not provided
|
|
186
|
+
if (!serialNumber) {
|
|
187
|
+
serialNumber = Utils.toBase64(Random(32))
|
|
197
188
|
}
|
|
198
189
|
|
|
190
|
+
// 2. Create encrypted certificate fields and associated master keyring
|
|
191
|
+
const { certificateFields, masterKeyring } = await this.createCertificateFields(
|
|
192
|
+
certifierWallet,
|
|
193
|
+
subject,
|
|
194
|
+
fields,
|
|
195
|
+
)
|
|
196
|
+
|
|
199
197
|
// 3. Obtain a revocation outpoint (ex. certifier can call wallet.createAction())
|
|
200
198
|
const revocationOutpoint = await getRevocationOutpoint(serialNumber)
|
|
201
199
|
// TODO: Validate revocation outpoint format
|
|
@@ -207,12 +205,78 @@ export class MasterCertificate extends Certificate {
|
|
|
207
205
|
subject,
|
|
208
206
|
(await certifierWallet.getPublicKey({ identityKey: true })).publicKey,
|
|
209
207
|
revocationOutpoint,
|
|
210
|
-
|
|
211
|
-
|
|
208
|
+
certificateFields,
|
|
209
|
+
masterKeyring
|
|
212
210
|
)
|
|
213
211
|
|
|
214
212
|
// 5. Sign and return the new MasterCertificate certifying the subject.
|
|
215
213
|
await certificate.sign(certifierWallet)
|
|
216
214
|
return certificate
|
|
217
215
|
}
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Decrypts all fields in the MasterCertificate using the subject's or certifier's wallet.
|
|
220
|
+
*
|
|
221
|
+
* This method allows the subject or certifier to decrypt the `masterKeyring` and retrieve
|
|
222
|
+
* the encryption keys for each field, which are then used to decrypt the corresponding field values.
|
|
223
|
+
* The counterparty used for decryption depends on how the certificate fields were created:
|
|
224
|
+
* - If the certificate is self-signed, the counterparty should be set to 'self'.
|
|
225
|
+
* - Otherwise, the counterparty should always be the other party involved in the certificate issuance process (the subject or certifier).
|
|
226
|
+
*
|
|
227
|
+
* @param {WalletInterface} subjectOrCertifierWallet - The wallet of the subject or certifier, used to decrypt the master keyring and field values.
|
|
228
|
+
* @param {Record<CertificateFieldNameUnder50Bytes, Base64String>} masterKeyring - A record containing encrypted keys for each field.
|
|
229
|
+
* @param {Record<CertificateFieldNameUnder50Bytes, Base64String>} fields - A record of encrypted field names and their values.
|
|
230
|
+
* @param {WalletCounterparty} counterparty - The counterparty responsible for creating or signing the certificate. For self-signed certificates, use 'self'.
|
|
231
|
+
* @returns {Promise<Record<CertificateFieldNameUnder50Bytes, string>>} A promise resolving to a record of field names and their decrypted values in plaintext.
|
|
232
|
+
*
|
|
233
|
+
* @throws {Error} Throws an error if the `masterKeyring` is invalid or if decryption fails for any field.
|
|
234
|
+
*/
|
|
235
|
+
static async decryptFields(
|
|
236
|
+
subjectOrCertifierWallet: WalletInterface,
|
|
237
|
+
masterKeyring: Record<CertificateFieldNameUnder50Bytes, Base64String>,
|
|
238
|
+
fields: Record<CertificateFieldNameUnder50Bytes, Base64String>,
|
|
239
|
+
counterparty: WalletCounterparty
|
|
240
|
+
): Promise<Record<CertificateFieldNameUnder50Bytes, string>> {
|
|
241
|
+
if (!masterKeyring || Object.keys(masterKeyring).length === 0) {
|
|
242
|
+
throw new Error('A MasterCertificate must have a valid masterKeyring!')
|
|
243
|
+
}
|
|
244
|
+
try {
|
|
245
|
+
const decryptedFields: Record<CertificateFieldNameUnder50Bytes, string> = {}
|
|
246
|
+
// Note: we want to iterate through all fields, not just masterKeyring keys/value pairs.
|
|
247
|
+
for (const fieldName of Object.keys(fields)) {
|
|
248
|
+
decryptedFields[fieldName] = (await this.decryptField(subjectOrCertifierWallet, masterKeyring, fieldName, fields[fieldName], counterparty)).decryptedFieldValue
|
|
249
|
+
}
|
|
250
|
+
return decryptedFields
|
|
251
|
+
} catch (e) {
|
|
252
|
+
throw new Error('Failed to decrypt all master certificate fields.')
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
static async decryptField(
|
|
257
|
+
subjectOrCertifierWallet: WalletInterface,
|
|
258
|
+
masterKeyring: Record<CertificateFieldNameUnder50Bytes, Base64String>,
|
|
259
|
+
fieldName: Base64String,
|
|
260
|
+
fieldValue: Base64String,
|
|
261
|
+
counterparty: WalletCounterparty
|
|
262
|
+
): Promise<{ fieldRevelationKey: number[], decryptedFieldValue: string }> {
|
|
263
|
+
if (!masterKeyring || Object.keys(masterKeyring).length === 0) {
|
|
264
|
+
throw new Error('A MasterCertificate must have a valid masterKeyring!')
|
|
265
|
+
}
|
|
266
|
+
try {
|
|
267
|
+
const { plaintext: fieldRevelationKey } = await subjectOrCertifierWallet.decrypt({
|
|
268
|
+
ciphertext: Utils.toArray(masterKeyring[fieldName], 'base64'),
|
|
269
|
+
...Certificate.getCertificateFieldEncryptionDetails(fieldName), // Only fieldName used on MasterCertificate
|
|
270
|
+
counterparty
|
|
271
|
+
})
|
|
272
|
+
|
|
273
|
+
const decryptedFieldValue = new SymmetricKey(fieldRevelationKey).decrypt(Utils.toArray(fieldValue, 'base64'))
|
|
274
|
+
return {
|
|
275
|
+
fieldRevelationKey,
|
|
276
|
+
decryptedFieldValue: Utils.toUTF8(decryptedFieldValue as number[])
|
|
277
|
+
}
|
|
278
|
+
} catch (e) {
|
|
279
|
+
throw new Error('Failed to decrypt certificate field!')
|
|
280
|
+
}
|
|
281
|
+
}
|
|
218
282
|
}
|
|
@@ -6,8 +6,7 @@ import {
|
|
|
6
6
|
HexString,
|
|
7
7
|
OutpointString,
|
|
8
8
|
PubKeyHex,
|
|
9
|
-
WalletInterface
|
|
10
|
-
WalletError
|
|
9
|
+
WalletInterface
|
|
11
10
|
} from '../../../mod.js'
|
|
12
11
|
import Certificate from './Certificate.js'
|
|
13
12
|
|
|
@@ -34,8 +33,8 @@ export class VerifiableCertificate extends Certificate {
|
|
|
34
33
|
certifier: PubKeyHex,
|
|
35
34
|
revocationOutpoint: OutpointString,
|
|
36
35
|
fields: Record<CertificateFieldNameUnder50Bytes, string>,
|
|
36
|
+
keyring: Record<CertificateFieldNameUnder50Bytes, string>,
|
|
37
37
|
signature?: HexString,
|
|
38
|
-
keyring?: Record<CertificateFieldNameUnder50Bytes, string>,
|
|
39
38
|
decryptedFields?: Record<CertificateFieldNameUnder50Bytes, Base64String>
|
|
40
39
|
) {
|
|
41
40
|
super(type, serialNumber, subject, certifier, revocationOutpoint, fields, signature)
|
|
@@ -58,7 +57,7 @@ export class VerifiableCertificate extends Certificate {
|
|
|
58
57
|
for (const fieldName in this.keyring) {
|
|
59
58
|
const { plaintext: fieldRevelationKey } = await verifierWallet.decrypt({
|
|
60
59
|
ciphertext: Utils.toArray(this.keyring[fieldName], 'base64'),
|
|
61
|
-
...Certificate.getCertificateFieldEncryptionDetails(this.serialNumber
|
|
60
|
+
...Certificate.getCertificateFieldEncryptionDetails(fieldName, this.serialNumber),
|
|
62
61
|
counterparty: this.subject
|
|
63
62
|
})
|
|
64
63
|
|