Server: use crypto instead of ursa for pod signature

This commit is contained in:
Chocobozzz 2017-01-04 22:23:07 +01:00
parent b981a525c3
commit bdfbd4f162
7 changed files with 94 additions and 41 deletions

View File

@ -69,7 +69,6 @@
"safe-buffer": "^5.0.1",
"scripty": "^1.5.0",
"sequelize": "^3.27.0",
"ursa": "^0.9.1",
"winston": "^2.1.1",
"ws": "^1.1.1"
},

View File

@ -1,9 +1,9 @@
'use strict'
const crypto = require('crypto')
const bcrypt = require('bcrypt')
const fs = require('fs')
const openssl = require('openssl-wrapper')
const ursa = require('ursa')
const constants = require('../initializers/constants')
const logger = require('./logger')
@ -16,12 +16,51 @@ const peertubeCrypto = {
sign
}
function checkSignature (publicKey, rawData, hexSignature) {
const crt = ursa.createPublicKey(publicKey)
const isValid = crt.hashAndVerify('sha256', new Buffer(rawData).toString('hex'), hexSignature, 'hex')
function checkSignature (publicKey, data, hexSignature) {
const verify = crypto.createVerify(constants.SIGNATURE_ALGORITHM)
let dataString
if (typeof data === 'string') {
dataString = data
} else {
try {
dataString = JSON.stringify(data)
} catch (err) {
logger.error('Cannot check signature.', { error: err })
return false
}
}
verify.update(dataString, 'utf8')
const isValid = verify.verify(publicKey, hexSignature, constants.SIGNATURE_ENCODING)
return isValid
}
function sign (data) {
const sign = crypto.createSign(constants.SIGNATURE_ALGORITHM)
let dataString
if (typeof data === 'string') {
dataString = data
} else {
try {
dataString = JSON.stringify(data)
} catch (err) {
logger.error('Cannot sign data.', { error: err })
return ''
}
}
sign.update(dataString, 'utf8')
// TODO: make async
const myKey = fs.readFileSync(constants.CONFIG.STORAGE.CERT_DIR + 'peertube.key.pem')
const signature = sign.sign(myKey, constants.SIGNATURE_ENCODING)
return signature
}
function comparePassword (plainPassword, hashPassword, callback) {
bcrypt.compare(plainPassword, hashPassword, function (err, isPasswordMatch) {
if (err) return callback(err)
@ -52,13 +91,6 @@ function cryptPassword (password, callback) {
})
}
function sign (data) {
const myKey = ursa.createPrivateKey(fs.readFileSync(constants.CONFIG.STORAGE.CERT_DIR + 'peertube.key.pem'))
const signature = myKey.hashAndSign('sha256', data, 'utf8', 'hex')
return signature
}
// ---------------------------------------------------------------------------
module.exports = peertubeCrypto

View File

@ -28,31 +28,37 @@ function makeSecureRequest (params, callback) {
url: constants.REMOTE_SCHEME.HTTP + '://' + params.toPod.host + params.path
}
// Add data with POST requst ?
if (params.method === 'POST') {
requestParams.json = {}
// Add signature if it is specified in the params
if (params.sign === true) {
const host = constants.CONFIG.WEBSERVER.HOST
requestParams.json.signature = {
host,
signature: peertubeCrypto.sign(host)
}
}
// If there are data informations
if (params.data) {
requestParams.json.data = params.data
request.post(requestParams, callback)
} else {
// No data
request.post(requestParams, callback)
}
} else {
request.get(requestParams, callback)
if (params.method !== 'POST') {
return callback(new Error('Cannot make a secure request with a non POST method.'))
}
requestParams.json = {}
// Add signature if it is specified in the params
if (params.sign === true) {
const host = constants.CONFIG.WEBSERVER.HOST
let dataToSign
if (params.data) {
dataToSign = dataToSign = params.data
} else {
// We do not have data to sign so we just take our host
// It is not ideal but the connection should be in HTTPS
dataToSign = host
}
requestParams.json.signature = {
host, // Which host we pretend to be
signature: peertubeCrypto.sign(dataToSign)
}
}
// If there are data informations
if (params.data) {
requestParams.json.data = params.data
}
request.post(requestParams, callback)
}
// ---------------------------------------------------------------------------

View File

@ -118,16 +118,21 @@ const REQUEST_ENDPOINTS = {
VIDEOS: 'videos'
}
// ---------------------------------------------------------------------------
const REMOTE_SCHEME = {
HTTP: 'https',
WS: 'wss'
}
// ---------------------------------------------------------------------------
const SIGNATURE_ALGORITHM = 'RSA-SHA256'
const SIGNATURE_ENCODING = 'hex'
// Password encryption
const BCRYPT_SALT_SIZE = 10
// ---------------------------------------------------------------------------
// Express static paths (router)
const STATIC_PATHS = {
PREVIEWS: '/static/previews/',
@ -143,6 +148,8 @@ let STATIC_MAX_AGE = '30d'
const THUMBNAILS_SIZE = '200x110'
const PREVIEWS_SIZE = '640x480'
// ---------------------------------------------------------------------------
const USER_ROLES = {
ADMIN: 'admin',
USER: 'user'
@ -180,6 +187,8 @@ module.exports = {
REQUESTS_LIMIT,
RETRY_REQUESTS,
SEARCHABLE_COLUMNS,
SIGNATURE_ALGORITHM,
SIGNATURE_ENCODING,
SORTABLE_COLUMNS,
STATIC_MAX_AGE,
STATIC_PATHS,

View File

@ -23,7 +23,14 @@ function checkSignature (req, res, next) {
logger.debug('Checking signature from %s.', host)
const signatureOk = peertubeCrypto.checkSignature(pod.publicKey, host, req.body.signature.signature)
let signatureShouldBe
if (req.body.data) {
signatureShouldBe = req.body.data
} else {
signatureShouldBe = host
}
const signatureOk = peertubeCrypto.checkSignature(pod.publicKey, signatureShouldBe, req.body.signature.signature)
if (signatureOk === true) {
res.locals.secure = {

View File

@ -11,7 +11,7 @@ function signature (req, res, next) {
req.checkBody('signature.host', 'Should have a signature host').isURL()
req.checkBody('signature.signature', 'Should have a signature').notEmpty()
logger.debug('Checking signature parameters', { parameters: { signatureHost: req.body.signature.host } })
logger.debug('Checking signature parameters', { parameters: { signature: req.body.signature } })
checkErrors(req, res, next)
}

View File

@ -122,7 +122,7 @@ function makeRequest (toPod, requestEndpoint, requestsToMake, callback) {
'Error sending secure request to %s pod.',
toPod.host,
{
error: err || new Error('Status code not 20x : ' + res.statusCode)
error: err ? err.message : 'Status code not 20x : ' + res.statusCode
}
)