2016-05-22 01:03:53 +02:00
|
|
|
'use strict'
|
|
|
|
|
|
|
|
const crypto = require('libp2p-crypto')
|
|
|
|
const debug = require('debug')
|
2016-05-22 01:33:50 +02:00
|
|
|
const fs = require('fs')
|
|
|
|
const path = require('path')
|
2016-05-22 13:19:17 +02:00
|
|
|
const protobuf = require('protocol-buffers')
|
2016-05-22 01:33:50 +02:00
|
|
|
|
2016-05-22 01:03:53 +02:00
|
|
|
const log = debug('libp2p:secio:handshake')
|
|
|
|
log.error = debug('libp2p:secio:handshake:error')
|
|
|
|
|
2016-05-22 01:33:50 +02:00
|
|
|
const pbm = protobuf(fs.readFileSync(path.join(__dirname, '../secio.proto')))
|
|
|
|
|
2016-05-22 01:31:00 +02:00
|
|
|
const support = require('../support')
|
|
|
|
|
2016-05-22 18:36:31 +02:00
|
|
|
// step 2. Exchange
|
|
|
|
// -- exchange (signed) ephemeral keys. verify signatures.
|
|
|
|
module.exports = function exchange (session, cb) {
|
2016-05-22 01:03:53 +02:00
|
|
|
log('2. exchange - start')
|
|
|
|
|
2016-05-22 18:36:31 +02:00
|
|
|
let eResult
|
|
|
|
try {
|
|
|
|
eResult = crypto.generateEphemeralKeyPair(session.local.curveT)
|
|
|
|
} catch (err) {
|
|
|
|
return cb(err)
|
|
|
|
}
|
|
|
|
|
2016-05-22 01:03:53 +02:00
|
|
|
session.local.ephemeralPubKey = eResult.key
|
|
|
|
const genSharedKey = eResult.genSharedKey
|
2016-05-22 18:36:31 +02:00
|
|
|
const exchangeOut = makeExchange(session)
|
|
|
|
|
|
|
|
session.insecureLp.write(exchangeOut)
|
|
|
|
session.insecureLp.once('data', (chunk) => {
|
|
|
|
const exchangeIn = pbm.Exchange.decode(chunk)
|
|
|
|
|
|
|
|
try {
|
|
|
|
verify(session, exchangeIn)
|
|
|
|
keys(session, exchangeIn, genSharedKey)
|
|
|
|
macAndCipher(session)
|
|
|
|
} catch (err) {
|
|
|
|
return cb(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
log('2. exchange - finish')
|
|
|
|
cb()
|
|
|
|
})
|
|
|
|
}
|
2016-05-22 01:03:53 +02:00
|
|
|
|
2016-05-22 18:36:31 +02:00
|
|
|
function makeExchange (session) {
|
2016-05-22 01:03:53 +02:00
|
|
|
// Gather corpus to sign.
|
|
|
|
const selectionOut = Buffer.concat([
|
2016-05-22 18:36:31 +02:00
|
|
|
session.proposal.out,
|
|
|
|
session.proposal.in,
|
2016-05-22 01:03:53 +02:00
|
|
|
session.local.ephemeralPubKey
|
|
|
|
])
|
2016-05-22 18:36:31 +02:00
|
|
|
return pbm.Exchange({
|
2016-05-22 01:03:53 +02:00
|
|
|
epubkey: session.local.ephemeralPubKey,
|
|
|
|
signature: session.localKey.sign(selectionOut)
|
|
|
|
})
|
2016-05-22 18:36:31 +02:00
|
|
|
}
|
2016-05-22 01:03:53 +02:00
|
|
|
|
2016-05-22 18:36:31 +02:00
|
|
|
function verify (session, exchangeIn) {
|
2016-05-22 01:03:53 +02:00
|
|
|
log('2.1. verify')
|
|
|
|
|
|
|
|
session.remote.ephemeralPubKey = exchangeIn.epubkey
|
|
|
|
|
|
|
|
const selectionIn = Buffer.concat([
|
2016-05-22 18:36:31 +02:00
|
|
|
session.proposal.in,
|
|
|
|
session.proposal.out,
|
2016-05-22 01:03:53 +02:00
|
|
|
session.remote.ephemeralPubKey
|
|
|
|
])
|
|
|
|
|
|
|
|
const sigOk = session.remote.permanentPubKey.verify(selectionIn, exchangeIn.signature)
|
|
|
|
|
|
|
|
if (!sigOk) {
|
|
|
|
throw new Error('Bad signature')
|
|
|
|
}
|
|
|
|
|
|
|
|
log('2.1. verify - signature verified')
|
2016-05-22 18:36:31 +02:00
|
|
|
}
|
2016-05-22 01:03:53 +02:00
|
|
|
|
2016-05-22 18:36:31 +02:00
|
|
|
function keys (session, exchangeIn, genSharedKey) {
|
2016-05-22 01:03:53 +02:00
|
|
|
log('2.2. keys')
|
|
|
|
|
|
|
|
session.sharedSecret = genSharedKey(exchangeIn.epubkey)
|
|
|
|
|
|
|
|
const keys = crypto.keyStretcher(session.local.cipherT, session.local.hashT, session.sharedSecret)
|
|
|
|
|
|
|
|
// use random nonces to decide order.
|
2016-05-22 18:36:31 +02:00
|
|
|
if (session.proposal.order > 0) {
|
2016-05-22 01:03:53 +02:00
|
|
|
session.local.keys = keys.k1
|
|
|
|
session.remote.keys = keys.k2
|
2016-05-22 18:36:31 +02:00
|
|
|
} else if (session.proposal.order < 0) {
|
2016-05-22 01:03:53 +02:00
|
|
|
// swap
|
|
|
|
session.local.keys = keys.k2
|
|
|
|
session.remote.keys = keys.k1
|
|
|
|
} else {
|
|
|
|
// we should've bailed before this. but if not, bail here.
|
|
|
|
throw new Error('you are trying to talk to yourself')
|
|
|
|
}
|
|
|
|
|
|
|
|
log('2.2. keys - shared: %s\n\tlocal: %s\n\tremote: %s', session.sharedSecret, session.local.keys, session.remote.keys)
|
2016-05-22 18:36:31 +02:00
|
|
|
}
|
2016-05-22 01:03:53 +02:00
|
|
|
|
2016-05-22 18:36:31 +02:00
|
|
|
function macAndCipher (session) {
|
2016-05-22 01:03:53 +02:00
|
|
|
log('2.3. mac + cipher')
|
|
|
|
|
2016-05-22 01:31:00 +02:00
|
|
|
support.makeMacAndCipher(session.local)
|
|
|
|
support.makeMacAndCipher(session.remote)
|
2016-05-22 01:03:53 +02:00
|
|
|
}
|