Skip to content

Commit

Permalink
feat: Add Noise Extensions
Browse files Browse the repository at this point in the history
  • Loading branch information
MarcoPolo committed Sep 27, 2022
1 parent 77a95fd commit df5c1b3
Show file tree
Hide file tree
Showing 9 changed files with 225 additions and 127 deletions.
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,14 @@
"uint8arrays": "^3.1.0"
},
"devDependencies": {
"@libp2p/daemon-client": "2.0.4",
"@libp2p/daemon-server": "^3.0.0",
"@libp2p/daemon-client": "^3.0.1",
"@libp2p/daemon-server": "^3.0.1",
"@libp2p/interface-connection-encrypter-compliance-tests": "^2.0.1",
"@libp2p/interop": "^2.1.0",
"@libp2p/interop": "^3.0.1",
"@libp2p/mplex": "^5.0.0",
"@libp2p/peer-id-factory": "^1.0.8",
"@libp2p/tcp": "^3.0.3",
"@multiformats/multiaddr": "^10.3.3",
"@multiformats/multiaddr": "^11.0.0",
"aegir": "^37.3.0",
"benchmark": "^2.1.4",
"execa": "^6.1.0",
Expand Down
4 changes: 3 additions & 1 deletion src/@types/handshake-interface.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import type { PeerId } from '@libp2p/interface-peer-id'
import type { bytes } from './basic.js'
import type { NoiseSession } from './handshake.js'
import type { NoiseExtensions } from '../proto/payload.js'

export interface IHandshake {
session: NoiseSession
remotePeer: PeerId
remoteEarlyData: bytes
remoteExtensions: NoiseExtensions
encrypt: (plaintext: bytes, session: NoiseSession) => bytes
decrypt: (ciphertext: bytes, session: NoiseSession) => {plaintext: bytes, valid: boolean}
decrypt: (ciphertext: bytes, session: NoiseSession) => { plaintext: bytes, valid: boolean }
}
10 changes: 10 additions & 0 deletions src/handshake-xx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@ import {
getPeerIdFromPayload,
verifySignedPayload
} from './utils.js'
import type { NoiseExtensions } from './proto/payload.js'

export class XXHandshake implements IHandshake {
public isInitiator: boolean
public session: NoiseSession
public remotePeer!: PeerId
public remoteEarlyData: bytes
public remoteExtensions: NoiseExtensions = { webtransportCerthashes: [] }

protected payload: bytes
protected connection: ProtobufStream
Expand Down Expand Up @@ -98,6 +100,7 @@ export class XXHandshake implements IHandshake {
this.remotePeer = this.remotePeer || await getPeerIdFromPayload(decodedPayload)
await verifySignedPayload(this.session.hs.rs, decodedPayload, this.remotePeer)
this.setRemoteEarlyData(decodedPayload.data)
this.setRemoteNoiseExtension(decodedPayload.extensions)
} catch (e) {
const err = e as Error
throw new UnexpectedPeerError(`Error occurred while verifying signed payload: ${err.message}`)
Expand Down Expand Up @@ -133,6 +136,7 @@ export class XXHandshake implements IHandshake {
this.remotePeer = this.remotePeer || await getPeerIdFromPayload(decodedPayload)
await verifySignedPayload(this.session.hs.rs, decodedPayload, this.remotePeer)
this.setRemoteEarlyData(decodedPayload.data)
this.setRemoteNoiseExtension(decodedPayload.extensions)
} catch (e) {
const err = e as Error
throw new UnexpectedPeerError(`Error occurred while verifying signed payload: ${err.message}`)
Expand Down Expand Up @@ -174,4 +178,10 @@ export class XXHandshake implements IHandshake {
this.remoteEarlyData = data
}
}

protected setRemoteNoiseExtension(e: NoiseExtensions | null | undefined): void {
if (e) {
this.remoteExtensions = e
}
}
}
15 changes: 10 additions & 5 deletions src/noise.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { decryptStream, encryptStream } from './crypto/streaming.js'
import { uint16BEDecode, uint16BEEncode } from './encoder.js'
import { XXHandshake } from './handshake-xx.js'
import { getPayload } from './utils.js'
import type { NoiseExtensions } from './proto/payload.js'

interface HandshakeParams {
connection: ProtobufStream
Expand All @@ -29,15 +30,15 @@ export class Noise implements INoiseConnection {

private readonly prologue: Uint8Array
private readonly staticKeys: KeyPair
private readonly earlyData?: bytes
private readonly extensions?: NoiseExtensions

/**
* @param {bytes} staticNoiseKey - x25519 private key, reuse for faster handshakes
* @param {bytes} earlyData
*/
constructor (staticNoiseKey?: bytes, earlyData?: bytes, crypto: ICryptoInterface = stablelib, prologueBytes?: Uint8Array) {
this.earlyData = earlyData ?? new Uint8Array(0)
constructor(staticNoiseKey?: bytes, extensions?: NoiseExtensions, crypto: ICryptoInterface = stablelib, prologueBytes?: Uint8Array) {
this.crypto = crypto
this.extensions = extensions

if (staticNoiseKey) {
// accepts x25519 private key of length 32
Expand Down Expand Up @@ -76,6 +77,8 @@ export class Noise implements INoiseConnection {
return {
conn,
remoteEarlyData: handshake.remoteEarlyData,
// @ts-ignore this isn't part of the interface yet. Fix me when https://github.com/libp2p/js-libp2p-interfaces/issues/291 is fixed
remoteExtensions: handshake.remoteExtensions,
remotePeer: handshake.remotePeer
}
}
Expand All @@ -88,7 +91,7 @@ export class Noise implements INoiseConnection {
* @param {PeerId} remotePeer - optional PeerId of the initiating peer, if known. This may only exist during transport upgrades.
* @returns {Promise<SecuredConnection>}
*/
public async secureInbound (localPeer: PeerId, connection: Duplex<Uint8Array>, remotePeer?: PeerId): Promise<SecuredConnection> {
public async secureInbound(localPeer: PeerId, connection: Duplex<Uint8Array>, remotePeer?: PeerId): Promise<SecuredConnection> {
const wrappedConnection = pbStream(
connection,
{
Expand All @@ -108,7 +111,9 @@ export class Noise implements INoiseConnection {
return {
conn,
remoteEarlyData: handshake.remoteEarlyData,
remotePeer: handshake.remotePeer
remotePeer: handshake.remotePeer,
// @ts-ignore this isn't part of the interface yet. Fix me when https://github.com/libp2p/js-libp2p-interfaces/issues/291 is fixed
remoteExtensions: handshake.remoteExtensions,
}
}

Expand Down
16 changes: 10 additions & 6 deletions src/proto/payload.proto
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
syntax = "proto3";
package pb;
syntax = "proto2";

message NoiseHandshakePayload {
bytes identity_key = 1;
bytes identity_sig = 2;
bytes data = 3;
message NoiseExtensions {
repeated bytes webtransport_certhashes = 1;
}

message NoiseHandshakePayload {
optional bytes identity_key = 1;
optional bytes identity_sig = 2;
optional bytes data = 3;
optional NoiseExtensions extensions = 4;
}
Loading

0 comments on commit df5c1b3

Please sign in to comment.