-
Notifications
You must be signed in to change notification settings - Fork 2
/
Channel.ts
81 lines (77 loc) · 2.97 KB
/
Channel.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import { SessionEnvelopedData } from '../../crypto/cms/envelopedData';
import { KeyStoreSet } from '../../keyStores/KeyStoreSet';
import { PayloadPlaintext } from '../../messages/payloads/PayloadPlaintext';
import { Recipient } from '../../messages/Recipient';
import { NodeError } from '../errors';
import { NodeCryptoOptions } from '../NodeCryptoOptions';
import { Node } from '../Node';
import { Peer, PeerInternetAddress } from '../peer';
import { CertificationPath } from '../../pki/CertificationPath';
import { RAMFMessageConstructor } from '../../messages/RAMFMessageConstructor';
import { MessageOptions } from '../../messages/RAMFMessage';
export abstract class Channel<
Payload extends PayloadPlaintext,
PeerAddress extends PeerInternetAddress,
> {
// noinspection TypeScriptAbstractClassConstructorCanBeMadeProtected
constructor(
public readonly node: Node<Payload, PeerAddress>,
public readonly peer: Peer<PeerAddress>,
public readonly deliveryAuthPath: CertificationPath,
public readonly keyStores: KeyStoreSet,
public cryptoOptions: Partial<NodeCryptoOptions> = {},
) {}
/**
* Generate and serialise a message with the given `payload`.
* @param payload The payload to encrypt and encapsulate
* @param messageConstructor The message class constructor
* @param options
*/
public async makeMessage(
payload: Payload | ArrayBuffer,
messageConstructor: RAMFMessageConstructor<Payload>,
options: Partial<Omit<MessageOptions, 'senderCaCertificateChain'>> = {},
): Promise<ArrayBuffer> {
const payloadSerialised = await this.wrapMessagePayload(payload);
const message = new messageConstructor(
this.getOutboundRAMFRecipient(),
this.deliveryAuthPath.leafCertificate,
Buffer.from(payloadSerialised),
{
...options,
senderCaCertificateChain: this.deliveryAuthPath.certificateAuthorities,
},
);
return message.serialize(this.node.identityKeyPair.privateKey, this.cryptoOptions.signature);
}
/**
* Encrypt and serialize the `payload`.
*
* @param payload
*
* Also store the new ephemeral session key.
*/
private async wrapMessagePayload(payload: Payload | ArrayBuffer): Promise<ArrayBuffer> {
const recipientSessionKey = await this.keyStores.publicKeyStore.retrieveLastSessionKey(
this.peer.id,
);
if (!recipientSessionKey) {
throw new NodeError(`Could not find session key for peer ${this.peer.id}`);
}
const { envelopedData, dhKeyId, dhPrivateKey } = await SessionEnvelopedData.encrypt(
payload instanceof ArrayBuffer ? payload : payload.serialize(),
recipientSessionKey,
this.cryptoOptions.encryption,
);
await this.keyStores.privateKeyStore.saveSessionKey(
dhPrivateKey,
Buffer.from(dhKeyId),
this.node.id,
this.peer.id,
);
return envelopedData.serialize();
}
public getOutboundRAMFRecipient(): Recipient {
return { id: this.peer.id, internetAddress: this.peer.internetAddress };
}
}