diff options
author | Chocobozzz <florian.bigard@gmail.com> | 2017-01-04 22:23:07 +0100 |
---|---|---|
committer | Chocobozzz <florian.bigard@gmail.com> | 2017-01-04 22:23:07 +0100 |
commit | bdfbd4f162d66c3a6bd7c312a99e0b692e830792 (patch) | |
tree | 30b857f73fe62771a94320e3e78030a1345dc3a8 | |
parent | b981a525c37d226b3fa59287a6ce338f54583d0c (diff) | |
download | PeerTube-bdfbd4f162d66c3a6bd7c312a99e0b692e830792.tar.gz PeerTube-bdfbd4f162d66c3a6bd7c312a99e0b692e830792.tar.zst PeerTube-bdfbd4f162d66c3a6bd7c312a99e0b692e830792.zip |
Server: use crypto instead of ursa for pod signature
-rw-r--r-- | package.json | 1 | ||||
-rw-r--r-- | server/helpers/peertube-crypto.js | 54 | ||||
-rw-r--r-- | server/helpers/requests.js | 46 | ||||
-rw-r--r-- | server/initializers/constants.js | 13 | ||||
-rw-r--r-- | server/middlewares/secure.js | 9 | ||||
-rw-r--r-- | server/middlewares/validators/remote/signature.js | 2 | ||||
-rw-r--r-- | server/models/request.js | 2 |
7 files changed, 90 insertions, 37 deletions
diff --git a/package.json b/package.json index 5eadcc363..554ad16df 100644 --- a/package.json +++ b/package.json | |||
@@ -69,7 +69,6 @@ | |||
69 | "safe-buffer": "^5.0.1", | 69 | "safe-buffer": "^5.0.1", |
70 | "scripty": "^1.5.0", | 70 | "scripty": "^1.5.0", |
71 | "sequelize": "^3.27.0", | 71 | "sequelize": "^3.27.0", |
72 | "ursa": "^0.9.1", | ||
73 | "winston": "^2.1.1", | 72 | "winston": "^2.1.1", |
74 | "ws": "^1.1.1" | 73 | "ws": "^1.1.1" |
75 | }, | 74 | }, |
diff --git a/server/helpers/peertube-crypto.js b/server/helpers/peertube-crypto.js index 610cb16cd..0f1e02ad6 100644 --- a/server/helpers/peertube-crypto.js +++ b/server/helpers/peertube-crypto.js | |||
@@ -1,9 +1,9 @@ | |||
1 | 'use strict' | 1 | 'use strict' |
2 | 2 | ||
3 | const crypto = require('crypto') | ||
3 | const bcrypt = require('bcrypt') | 4 | const bcrypt = require('bcrypt') |
4 | const fs = require('fs') | 5 | const fs = require('fs') |
5 | const openssl = require('openssl-wrapper') | 6 | const openssl = require('openssl-wrapper') |
6 | const ursa = require('ursa') | ||
7 | 7 | ||
8 | const constants = require('../initializers/constants') | 8 | const constants = require('../initializers/constants') |
9 | const logger = require('./logger') | 9 | const logger = require('./logger') |
@@ -16,12 +16,51 @@ const peertubeCrypto = { | |||
16 | sign | 16 | sign |
17 | } | 17 | } |
18 | 18 | ||
19 | function checkSignature (publicKey, rawData, hexSignature) { | 19 | function checkSignature (publicKey, data, hexSignature) { |
20 | const crt = ursa.createPublicKey(publicKey) | 20 | const verify = crypto.createVerify(constants.SIGNATURE_ALGORITHM) |
21 | const isValid = crt.hashAndVerify('sha256', new Buffer(rawData).toString('hex'), hexSignature, 'hex') | 21 | |
22 | let dataString | ||
23 | if (typeof data === 'string') { | ||
24 | dataString = data | ||
25 | } else { | ||
26 | try { | ||
27 | dataString = JSON.stringify(data) | ||
28 | } catch (err) { | ||
29 | logger.error('Cannot check signature.', { error: err }) | ||
30 | return false | ||
31 | } | ||
32 | } | ||
33 | |||
34 | verify.update(dataString, 'utf8') | ||
35 | |||
36 | const isValid = verify.verify(publicKey, hexSignature, constants.SIGNATURE_ENCODING) | ||
22 | return isValid | 37 | return isValid |
23 | } | 38 | } |
24 | 39 | ||
40 | function sign (data) { | ||
41 | const sign = crypto.createSign(constants.SIGNATURE_ALGORITHM) | ||
42 | |||
43 | let dataString | ||
44 | if (typeof data === 'string') { | ||
45 | dataString = data | ||
46 | } else { | ||
47 | try { | ||
48 | dataString = JSON.stringify(data) | ||
49 | } catch (err) { | ||
50 | logger.error('Cannot sign data.', { error: err }) | ||
51 | return '' | ||
52 | } | ||
53 | } | ||
54 | |||
55 | sign.update(dataString, 'utf8') | ||
56 | |||
57 | // TODO: make async | ||
58 | const myKey = fs.readFileSync(constants.CONFIG.STORAGE.CERT_DIR + 'peertube.key.pem') | ||
59 | const signature = sign.sign(myKey, constants.SIGNATURE_ENCODING) | ||
60 | |||
61 | return signature | ||
62 | } | ||
63 | |||
25 | function comparePassword (plainPassword, hashPassword, callback) { | 64 | function comparePassword (plainPassword, hashPassword, callback) { |
26 | bcrypt.compare(plainPassword, hashPassword, function (err, isPasswordMatch) { | 65 | bcrypt.compare(plainPassword, hashPassword, function (err, isPasswordMatch) { |
27 | if (err) return callback(err) | 66 | if (err) return callback(err) |
@@ -52,13 +91,6 @@ function cryptPassword (password, callback) { | |||
52 | }) | 91 | }) |
53 | } | 92 | } |
54 | 93 | ||
55 | function sign (data) { | ||
56 | const myKey = ursa.createPrivateKey(fs.readFileSync(constants.CONFIG.STORAGE.CERT_DIR + 'peertube.key.pem')) | ||
57 | const signature = myKey.hashAndSign('sha256', data, 'utf8', 'hex') | ||
58 | |||
59 | return signature | ||
60 | } | ||
61 | |||
62 | // --------------------------------------------------------------------------- | 94 | // --------------------------------------------------------------------------- |
63 | 95 | ||
64 | module.exports = peertubeCrypto | 96 | module.exports = peertubeCrypto |
diff --git a/server/helpers/requests.js b/server/helpers/requests.js index b0cda09fe..095b95e1c 100644 --- a/server/helpers/requests.js +++ b/server/helpers/requests.js | |||
@@ -28,31 +28,37 @@ function makeSecureRequest (params, callback) { | |||
28 | url: constants.REMOTE_SCHEME.HTTP + '://' + params.toPod.host + params.path | 28 | url: constants.REMOTE_SCHEME.HTTP + '://' + params.toPod.host + params.path |
29 | } | 29 | } |
30 | 30 | ||
31 | // Add data with POST requst ? | 31 | if (params.method !== 'POST') { |
32 | if (params.method === 'POST') { | 32 | return callback(new Error('Cannot make a secure request with a non POST method.')) |
33 | requestParams.json = {} | 33 | } |
34 | 34 | ||
35 | // Add signature if it is specified in the params | 35 | requestParams.json = {} |
36 | if (params.sign === true) { | ||
37 | const host = constants.CONFIG.WEBSERVER.HOST | ||
38 | |||
39 | requestParams.json.signature = { | ||
40 | host, | ||
41 | signature: peertubeCrypto.sign(host) | ||
42 | } | ||
43 | } | ||
44 | 36 | ||
45 | // If there are data informations | 37 | // Add signature if it is specified in the params |
38 | if (params.sign === true) { | ||
39 | const host = constants.CONFIG.WEBSERVER.HOST | ||
40 | |||
41 | let dataToSign | ||
46 | if (params.data) { | 42 | if (params.data) { |
47 | requestParams.json.data = params.data | 43 | dataToSign = dataToSign = params.data |
48 | request.post(requestParams, callback) | ||
49 | } else { | 44 | } else { |
50 | // No data | 45 | // We do not have data to sign so we just take our host |
51 | request.post(requestParams, callback) | 46 | // It is not ideal but the connection should be in HTTPS |
47 | dataToSign = host | ||
52 | } | 48 | } |
53 | } else { | 49 | |
54 | request.get(requestParams, callback) | 50 | requestParams.json.signature = { |
51 | host, // Which host we pretend to be | ||
52 | signature: peertubeCrypto.sign(dataToSign) | ||
53 | } | ||
54 | } | ||
55 | |||
56 | // If there are data informations | ||
57 | if (params.data) { | ||
58 | requestParams.json.data = params.data | ||
55 | } | 59 | } |
60 | |||
61 | request.post(requestParams, callback) | ||
56 | } | 62 | } |
57 | 63 | ||
58 | // --------------------------------------------------------------------------- | 64 | // --------------------------------------------------------------------------- |
diff --git a/server/initializers/constants.js b/server/initializers/constants.js index 6ba8a9da0..a6adb75bf 100644 --- a/server/initializers/constants.js +++ b/server/initializers/constants.js | |||
@@ -118,16 +118,21 @@ const REQUEST_ENDPOINTS = { | |||
118 | VIDEOS: 'videos' | 118 | VIDEOS: 'videos' |
119 | } | 119 | } |
120 | 120 | ||
121 | // --------------------------------------------------------------------------- | ||
122 | |||
123 | const REMOTE_SCHEME = { | 121 | const REMOTE_SCHEME = { |
124 | HTTP: 'https', | 122 | HTTP: 'https', |
125 | WS: 'wss' | 123 | WS: 'wss' |
126 | } | 124 | } |
127 | 125 | ||
126 | // --------------------------------------------------------------------------- | ||
127 | |||
128 | const SIGNATURE_ALGORITHM = 'RSA-SHA256' | ||
129 | const SIGNATURE_ENCODING = 'hex' | ||
130 | |||
128 | // Password encryption | 131 | // Password encryption |
129 | const BCRYPT_SALT_SIZE = 10 | 132 | const BCRYPT_SALT_SIZE = 10 |
130 | 133 | ||
134 | // --------------------------------------------------------------------------- | ||
135 | |||
131 | // Express static paths (router) | 136 | // Express static paths (router) |
132 | const STATIC_PATHS = { | 137 | const STATIC_PATHS = { |
133 | PREVIEWS: '/static/previews/', | 138 | PREVIEWS: '/static/previews/', |
@@ -143,6 +148,8 @@ let STATIC_MAX_AGE = '30d' | |||
143 | const THUMBNAILS_SIZE = '200x110' | 148 | const THUMBNAILS_SIZE = '200x110' |
144 | const PREVIEWS_SIZE = '640x480' | 149 | const PREVIEWS_SIZE = '640x480' |
145 | 150 | ||
151 | // --------------------------------------------------------------------------- | ||
152 | |||
146 | const USER_ROLES = { | 153 | const USER_ROLES = { |
147 | ADMIN: 'admin', | 154 | ADMIN: 'admin', |
148 | USER: 'user' | 155 | USER: 'user' |
@@ -180,6 +187,8 @@ module.exports = { | |||
180 | REQUESTS_LIMIT, | 187 | REQUESTS_LIMIT, |
181 | RETRY_REQUESTS, | 188 | RETRY_REQUESTS, |
182 | SEARCHABLE_COLUMNS, | 189 | SEARCHABLE_COLUMNS, |
190 | SIGNATURE_ALGORITHM, | ||
191 | SIGNATURE_ENCODING, | ||
183 | SORTABLE_COLUMNS, | 192 | SORTABLE_COLUMNS, |
184 | STATIC_MAX_AGE, | 193 | STATIC_MAX_AGE, |
185 | STATIC_PATHS, | 194 | STATIC_PATHS, |
diff --git a/server/middlewares/secure.js b/server/middlewares/secure.js index 2aae715c4..b6e6d818b 100644 --- a/server/middlewares/secure.js +++ b/server/middlewares/secure.js | |||
@@ -23,7 +23,14 @@ function checkSignature (req, res, next) { | |||
23 | 23 | ||
24 | logger.debug('Checking signature from %s.', host) | 24 | logger.debug('Checking signature from %s.', host) |
25 | 25 | ||
26 | const signatureOk = peertubeCrypto.checkSignature(pod.publicKey, host, req.body.signature.signature) | 26 | let signatureShouldBe |
27 | if (req.body.data) { | ||
28 | signatureShouldBe = req.body.data | ||
29 | } else { | ||
30 | signatureShouldBe = host | ||
31 | } | ||
32 | |||
33 | const signatureOk = peertubeCrypto.checkSignature(pod.publicKey, signatureShouldBe, req.body.signature.signature) | ||
27 | 34 | ||
28 | if (signatureOk === true) { | 35 | if (signatureOk === true) { |
29 | res.locals.secure = { | 36 | res.locals.secure = { |
diff --git a/server/middlewares/validators/remote/signature.js b/server/middlewares/validators/remote/signature.js index 5880a2c2c..002232c05 100644 --- a/server/middlewares/validators/remote/signature.js +++ b/server/middlewares/validators/remote/signature.js | |||
@@ -11,7 +11,7 @@ function signature (req, res, next) { | |||
11 | req.checkBody('signature.host', 'Should have a signature host').isURL() | 11 | req.checkBody('signature.host', 'Should have a signature host').isURL() |
12 | req.checkBody('signature.signature', 'Should have a signature').notEmpty() | 12 | req.checkBody('signature.signature', 'Should have a signature').notEmpty() |
13 | 13 | ||
14 | logger.debug('Checking signature parameters', { parameters: { signatureHost: req.body.signature.host } }) | 14 | logger.debug('Checking signature parameters', { parameters: { signature: req.body.signature } }) |
15 | 15 | ||
16 | checkErrors(req, res, next) | 16 | checkErrors(req, res, next) |
17 | } | 17 | } |
diff --git a/server/models/request.js b/server/models/request.js index e18f8fe3d..bae227c05 100644 --- a/server/models/request.js +++ b/server/models/request.js | |||
@@ -122,7 +122,7 @@ function makeRequest (toPod, requestEndpoint, requestsToMake, callback) { | |||
122 | 'Error sending secure request to %s pod.', | 122 | 'Error sending secure request to %s pod.', |
123 | toPod.host, | 123 | toPod.host, |
124 | { | 124 | { |
125 | error: err || new Error('Status code not 20x : ' + res.statusCode) | 125 | error: err ? err.message : 'Status code not 20x : ' + res.statusCode |
126 | } | 126 | } |
127 | ) | 127 | ) |
128 | 128 | ||