100 lines
2.8 KiB
TypeScript
100 lines
2.8 KiB
TypeScript
// Copyright 2022 Signal Messenger, LLC
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
import { Cds2Client } from '@signalapp/libsignal-client';
|
|
|
|
import { strictAssert } from '../../util/assert';
|
|
import { DAY } from '../../util/durations';
|
|
import { SignalService as Proto } from '../../protobuf';
|
|
import { CDSSocketBase, CDSSocketState } from './CDSSocketBase';
|
|
import type { CDSSocketBaseOptionsType } from './CDSSocketBase';
|
|
|
|
export type CDSISocketOptionsType = Readonly<{
|
|
mrenclave: Buffer;
|
|
trustedCaCert: Buffer;
|
|
}> &
|
|
CDSSocketBaseOptionsType;
|
|
|
|
export class CDSISocket extends CDSSocketBase<CDSISocketOptionsType> {
|
|
private privCdsClient: Cds2Client | undefined;
|
|
|
|
public override async handshake(): Promise<void> {
|
|
strictAssert(
|
|
this.state === CDSSocketState.Open,
|
|
'CDSI handshake called twice'
|
|
);
|
|
this.state = CDSSocketState.Handshake;
|
|
|
|
{
|
|
const { done, value: attestationMessage } =
|
|
await this.socketIterator.next();
|
|
strictAssert(!done, 'CDSI socket closed before handshake');
|
|
|
|
const earliestValidTimestamp = new Date(Date.now() - DAY);
|
|
|
|
strictAssert(
|
|
this.privCdsClient === undefined,
|
|
'CDSI handshake called twice'
|
|
);
|
|
this.privCdsClient = Cds2Client.new_NOT_FOR_PRODUCTION(
|
|
this.options.mrenclave,
|
|
this.options.trustedCaCert,
|
|
attestationMessage,
|
|
earliestValidTimestamp
|
|
);
|
|
}
|
|
|
|
this.socket.sendBytes(this.cdsClient.initialRequest());
|
|
|
|
{
|
|
const { done, value: message } = await this.socketIterator.next();
|
|
strictAssert(!done, 'CDSI socket expected handshake data');
|
|
|
|
this.cdsClient.completeHandshake(message);
|
|
}
|
|
|
|
this.state = CDSSocketState.Established;
|
|
}
|
|
|
|
protected override async sendRequest(
|
|
_version: number,
|
|
request: Buffer
|
|
): Promise<void> {
|
|
this.socket.sendBytes(this.cdsClient.establishedSend(request));
|
|
|
|
const { done, value: ciphertext } = await this.socketIterator.next();
|
|
strictAssert(!done, 'CDSISocket.sendRequest(): expected token message');
|
|
|
|
const message = await this.decryptResponse(ciphertext);
|
|
|
|
this.logger.info('CDSISocket.sendRequest(): processing token message');
|
|
|
|
const { token } = Proto.CDSClientResponse.decode(message);
|
|
strictAssert(token, 'CDSISocket.sendRequest(): expected token');
|
|
|
|
this.socket.sendBytes(
|
|
this.cdsClient.establishedSend(
|
|
Buffer.from(
|
|
Proto.CDSClientRequest.encode({
|
|
tokenAck: true,
|
|
}).finish()
|
|
)
|
|
)
|
|
);
|
|
}
|
|
|
|
protected override async decryptResponse(
|
|
ciphertext: Buffer
|
|
): Promise<Buffer> {
|
|
return this.cdsClient.establishedRecv(ciphertext);
|
|
}
|
|
|
|
//
|
|
// Private
|
|
//
|
|
|
|
private get cdsClient(): Cds2Client {
|
|
strictAssert(this.privCdsClient, 'CDSISocket did not start handshake');
|
|
return this.privCdsClient;
|
|
}
|
|
}
|