aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/helpers/peertube-crypto.ts
diff options
context:
space:
mode:
Diffstat (limited to 'server/helpers/peertube-crypto.ts')
-rw-r--r--server/helpers/peertube-crypto.ts71
1 files changed, 64 insertions, 7 deletions
diff --git a/server/helpers/peertube-crypto.ts b/server/helpers/peertube-crypto.ts
index 8ef7b1359..ab9ec077e 100644
--- a/server/helpers/peertube-crypto.ts
+++ b/server/helpers/peertube-crypto.ts
@@ -1,9 +1,12 @@
1import { Request } from 'express' 1import { Request } from 'express'
2import { BCRYPT_SALT_SIZE, HTTP_SIGNATURE, PRIVATE_RSA_KEY_SIZE } from '../initializers' 2import { BCRYPT_SALT_SIZE, HTTP_SIGNATURE, PRIVATE_RSA_KEY_SIZE } from '../initializers'
3import { ActorModel } from '../models/activitypub/actor' 3import { ActorModel } from '../models/activitypub/actor'
4import { bcryptComparePromise, bcryptGenSaltPromise, bcryptHashPromise, createPrivateKey, getPublicKey } from './core-utils' 4import { bcryptComparePromise, bcryptGenSaltPromise, bcryptHashPromise, createPrivateKey, getPublicKey, sha256 } from './core-utils'
5import { jsig } from './custom-jsonld-signature' 5import { jsig, jsonld } from './custom-jsonld-signature'
6import { logger } from './logger' 6import { logger } from './logger'
7import { cloneDeep } from 'lodash'
8import { createVerify } from 'crypto'
9import { buildDigest } from '../lib/job-queue/handlers/utils/activitypub-http-utils'
7 10
8const httpSignature = require('http-signature') 11const httpSignature = require('http-signature')
9 12
@@ -30,21 +33,36 @@ async function cryptPassword (password: string) {
30 33
31// HTTP Signature 34// HTTP Signature
32 35
33function isHTTPSignatureVerified (httpSignatureParsed: any, actor: ActorModel) { 36function isHTTPSignatureDigestValid (rawBody: Buffer, req: Request): boolean {
37 if (req.headers[HTTP_SIGNATURE.HEADER_NAME] && req.headers['digest']) {
38 return buildDigest(rawBody.toString()) === req.headers['digest']
39 }
40
41 return true
42}
43
44function isHTTPSignatureVerified (httpSignatureParsed: any, actor: ActorModel): boolean {
34 return httpSignature.verifySignature(httpSignatureParsed, actor.publicKey) === true 45 return httpSignature.verifySignature(httpSignatureParsed, actor.publicKey) === true
35} 46}
36 47
37function parseHTTPSignature (req: Request) { 48function parseHTTPSignature (req: Request, clockSkew?: number) {
38 return httpSignature.parse(req, { authorizationHeaderName: HTTP_SIGNATURE.HEADER_NAME }) 49 return httpSignature.parse(req, { authorizationHeaderName: HTTP_SIGNATURE.HEADER_NAME, clockSkew })
39} 50}
40 51
41// JSONLD 52// JSONLD
42 53
43function isJsonLDSignatureVerified (fromActor: ActorModel, signedDocument: any) { 54async function isJsonLDSignatureVerified (fromActor: ActorModel, signedDocument: any): Promise<boolean> {
55 if (signedDocument.signature.type === 'RsaSignature2017') {
56 // Mastodon algorithm
57 const res = await isJsonLDRSA2017Verified(fromActor, signedDocument)
58 // Success? If no, try with our library
59 if (res === true) return true
60 }
61
44 const publicKeyObject = { 62 const publicKeyObject = {
45 '@context': jsig.SECURITY_CONTEXT_URL, 63 '@context': jsig.SECURITY_CONTEXT_URL,
46 id: fromActor.url, 64 id: fromActor.url,
47 type: 'CryptographicKey', 65 type: 'CryptographicKey',
48 owner: fromActor.url, 66 owner: fromActor.url,
49 publicKeyPem: fromActor.publicKey 67 publicKeyPem: fromActor.publicKey
50 } 68 }
@@ -69,6 +87,44 @@ function isJsonLDSignatureVerified (fromActor: ActorModel, signedDocument: any)
69 }) 87 })
70} 88}
71 89
90// Backward compatibility with "other" implementations
91async function isJsonLDRSA2017Verified (fromActor: ActorModel, signedDocument: any) {
92 function hash (obj: any): Promise<any> {
93 return jsonld.promises
94 .normalize(obj, {
95 algorithm: 'URDNA2015',
96 format: 'application/n-quads'
97 })
98 .then(res => sha256(res))
99 }
100
101 const signatureCopy = cloneDeep(signedDocument.signature)
102 Object.assign(signatureCopy, {
103 '@context': [
104 'https://w3id.org/security/v1',
105 { RsaSignature2017: 'https://w3id.org/security#RsaSignature2017' }
106 ]
107 })
108 delete signatureCopy.type
109 delete signatureCopy.id
110 delete signatureCopy.signatureValue
111
112 const docWithoutSignature = cloneDeep(signedDocument)
113 delete docWithoutSignature.signature
114
115 const [ documentHash, optionsHash ] = await Promise.all([
116 hash(docWithoutSignature),
117 hash(signatureCopy)
118 ])
119
120 const toVerify = optionsHash + documentHash
121
122 const verify = createVerify('RSA-SHA256')
123 verify.update(toVerify, 'utf8')
124
125 return verify.verify(fromActor.publicKey, signedDocument.signature.signatureValue, 'base64')
126}
127
72function signJsonLDObject (byActor: ActorModel, data: any) { 128function signJsonLDObject (byActor: ActorModel, data: any) {
73 const options = { 129 const options = {
74 privateKeyPem: byActor.privateKey, 130 privateKeyPem: byActor.privateKey,
@@ -82,6 +138,7 @@ function signJsonLDObject (byActor: ActorModel, data: any) {
82// --------------------------------------------------------------------------- 138// ---------------------------------------------------------------------------
83 139
84export { 140export {
141 isHTTPSignatureDigestValid,
85 parseHTTPSignature, 142 parseHTTPSignature,
86 isHTTPSignatureVerified, 143 isHTTPSignatureVerified,
87 isJsonLDSignatureVerified, 144 isJsonLDSignatureVerified,