Merge pull request #53 from mpetrun5/early-data-api

Early data api
This commit is contained in:
Belma Gutlic 2020-04-22 09:33:54 +02:00 committed by GitHub
commit e553392f6b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 51 additions and 0 deletions

View File

@ -5,6 +5,7 @@ import PeerId from "peer-id";
export interface IHandshake { export interface IHandshake {
session: NoiseSession; session: NoiseSession;
remotePeer: PeerId; remotePeer: PeerId;
remoteEarlyData: Buffer;
encrypt(plaintext: bytes, session: NoiseSession): bytes; encrypt(plaintext: bytes, session: NoiseSession): bytes;
decrypt(ciphertext: bytes, session: NoiseSession): {plaintext: bytes; valid: boolean}; decrypt(ciphertext: bytes, session: NoiseSession): {plaintext: bytes; valid: boolean};
} }

View File

@ -14,6 +14,7 @@ export interface INoiseConnection {
export type SecureOutbound = { export type SecureOutbound = {
conn: any; conn: any;
remoteEarlyData: Buffer;
remotePeer: PeerId; remotePeer: PeerId;
} }

View File

@ -22,6 +22,7 @@ export class IKHandshake implements IHandshake {
public isInitiator: boolean; public isInitiator: boolean;
public session: NoiseSession; public session: NoiseSession;
public remotePeer!: PeerId; public remotePeer!: PeerId;
public remoteEarlyData: Buffer;
private payload: bytes; private payload: bytes;
private prologue: bytes32; private prologue: bytes32;
@ -49,6 +50,7 @@ export class IKHandshake implements IHandshake {
} }
this.ik = handshake || new IK(); this.ik = handshake || new IK();
this.session = this.ik.initSession(this.isInitiator, this.prologue, this.staticKeypair, remoteStaticKey); this.session = this.ik.initSession(this.isInitiator, this.prologue, this.staticKeypair, remoteStaticKey);
this.remoteEarlyData = Buffer.alloc(0)
} }
public async stage0(): Promise<void> { public async stage0(): Promise<void> {
@ -73,6 +75,7 @@ export class IKHandshake implements IHandshake {
const decodedPayload = await decodePayload(plaintext); const decodedPayload = await decodePayload(plaintext);
this.remotePeer = this.remotePeer || await getPeerIdFromPayload(decodedPayload); this.remotePeer = this.remotePeer || await getPeerIdFromPayload(decodedPayload);
await verifySignedPayload(this.session.hs.rs, decodedPayload, this.remotePeer); await verifySignedPayload(this.session.hs.rs, decodedPayload, this.remotePeer);
this.setRemoteEarlyData(decodedPayload.data);
logger("IK Stage 0 - Responder successfully verified payload!"); logger("IK Stage 0 - Responder successfully verified payload!");
logRemoteEphemeralKey(this.session.hs.re) logRemoteEphemeralKey(this.session.hs.re)
} catch (e) { } catch (e) {
@ -97,6 +100,7 @@ export class IKHandshake implements IHandshake {
const decodedPayload = await decodePayload(plaintext); const decodedPayload = await decodePayload(plaintext);
this.remotePeer = this.remotePeer || await getPeerIdFromPayload(decodedPayload); this.remotePeer = this.remotePeer || await getPeerIdFromPayload(decodedPayload);
await verifySignedPayload(receivedMessageBuffer.ns.slice(0, 32), decodedPayload, this.remotePeer); await verifySignedPayload(receivedMessageBuffer.ns.slice(0, 32), decodedPayload, this.remotePeer);
this.setRemoteEarlyData(decodedPayload.data);
logger("IK Stage 1 - Initiator successfully verified payload!"); logger("IK Stage 1 - Initiator successfully verified payload!");
logRemoteEphemeralKey(this.session.hs.re) logRemoteEphemeralKey(this.session.hs.re)
} catch (e) { } catch (e) {
@ -142,4 +146,10 @@ export class IKHandshake implements IHandshake {
return encryption ? session.cs2 : session.cs1; return encryption ? session.cs2 : session.cs1;
} }
} }
private setRemoteEarlyData(data: Uint8Array|null|undefined): void {
if(data){
this.remoteEarlyData = Buffer.from(data.buffer, data.byteOffset, data.length);
}
}
} }

View File

@ -70,6 +70,7 @@ export class XXFallbackHandshake extends XXHandshake {
const decodedPayload = await decodePayload(plaintext); const decodedPayload = await decodePayload(plaintext);
this.remotePeer = this.remotePeer || await getPeerIdFromPayload(decodedPayload); this.remotePeer = this.remotePeer || await getPeerIdFromPayload(decodedPayload);
await verifySignedPayload(this.session.hs.rs, decodedPayload, this.remotePeer); await verifySignedPayload(this.session.hs.rs, decodedPayload, this.remotePeer);
this.setRemoteEarlyData(decodedPayload.data)
} catch (e) { } catch (e) {
throw new Error(`Error occurred while verifying signed payload from responder: ${e.message}`); throw new Error(`Error occurred while verifying signed payload from responder: ${e.message}`);
} }

View File

@ -26,6 +26,7 @@ export class XXHandshake implements IHandshake {
public isInitiator: boolean; public isInitiator: boolean;
public session: NoiseSession; public session: NoiseSession;
public remotePeer!: PeerId; public remotePeer!: PeerId;
public remoteEarlyData: Buffer;
protected payload: bytes; protected payload: bytes;
protected connection: WrappedConnection; protected connection: WrappedConnection;
@ -53,6 +54,7 @@ export class XXHandshake implements IHandshake {
} }
this.xx = handshake || new XX(); this.xx = handshake || new XX();
this.session = this.xx.initSession(this.isInitiator, this.prologue, this.staticKeypair); this.session = this.xx.initSession(this.isInitiator, this.prologue, this.staticKeypair);
this.remoteEarlyData = Buffer.alloc(0)
} }
// stage 0 // stage 0
@ -94,6 +96,7 @@ export class XXHandshake implements IHandshake {
const decodedPayload = await decodePayload(plaintext); const decodedPayload = await decodePayload(plaintext);
this.remotePeer = this.remotePeer || await getPeerIdFromPayload(decodedPayload); this.remotePeer = this.remotePeer || await getPeerIdFromPayload(decodedPayload);
this.remotePeer = await verifySignedPayload(receivedMessageBuffer.ns, decodedPayload, this.remotePeer); this.remotePeer = await verifySignedPayload(receivedMessageBuffer.ns, decodedPayload, this.remotePeer);
this.setRemoteEarlyData(decodedPayload.data)
} catch (e) { } catch (e) {
throw new Error(`Error occurred while verifying signed payload: ${e.message}`); throw new Error(`Error occurred while verifying signed payload: ${e.message}`);
} }
@ -127,6 +130,7 @@ export class XXHandshake implements IHandshake {
const decodedPayload = await decodePayload(plaintext); const decodedPayload = await decodePayload(plaintext);
this.remotePeer = this.remotePeer || await getPeerIdFromPayload(decodedPayload); this.remotePeer = this.remotePeer || await getPeerIdFromPayload(decodedPayload);
await verifySignedPayload(this.session.hs.rs, decodedPayload, this.remotePeer); await verifySignedPayload(this.session.hs.rs, decodedPayload, this.remotePeer);
this.setRemoteEarlyData(decodedPayload.data)
} catch (e) { } catch (e) {
throw new Error(`Error occurred while verifying signed payload: ${e.message}`); throw new Error(`Error occurred while verifying signed payload: ${e.message}`);
} }
@ -160,4 +164,10 @@ export class XXHandshake implements IHandshake {
return encryption ? session.cs2 : session.cs1; return encryption ? session.cs2 : session.cs1;
} }
} }
protected setRemoteEarlyData(data: Uint8Array|null|undefined): void {
if(data){
this.remoteEarlyData = Buffer.from(data.buffer, data.byteOffset, data.length);
}
}
} }

View File

@ -85,6 +85,7 @@ export class Noise implements INoiseConnection {
return { return {
conn, conn,
remoteEarlyData: handshake.remoteEarlyData,
remotePeer: handshake.remotePeer, remotePeer: handshake.remotePeer,
} }
} }
@ -115,6 +116,7 @@ export class Noise implements INoiseConnection {
return { return {
conn, conn,
remoteEarlyData: handshake.remoteEarlyData,
remotePeer: handshake.remotePeer remotePeer: handshake.remotePeer
}; };
} }

View File

@ -336,4 +336,30 @@ describe("Noise", () => {
assert(false, e.message); assert(false, e.message);
} }
}); });
it("should accept and return early data from remote peer", async() => {
try {
const localPeerEarlyData = Buffer.from('early data')
const staticKeysInitiator = generateKeypair();
const noiseInit = new Noise(staticKeysInitiator.privateKey, localPeerEarlyData);
const staticKeysResponder = generateKeypair();
const noiseResp = new Noise(staticKeysResponder.privateKey);
// Prepare key cache for noise pipes
KeyCache.store(localPeer, staticKeysInitiator.publicKey);
KeyCache.store(remotePeer, staticKeysResponder.publicKey);
const [inboundConnection, outboundConnection] = DuplexPair();
const [outbound, inbound] = await Promise.all([
noiseInit.secureOutbound(localPeer, outboundConnection, remotePeer),
noiseResp.secureInbound(remotePeer, inboundConnection),
]);
assert(inbound.remoteEarlyData.equals(localPeerEarlyData))
assert(outbound.remoteEarlyData.equals(Buffer.alloc(0)))
} catch (e) {
console.error(e);
assert(false, e.message);
}
});
}); });