Mise à jour de GitLab prévue ce samedi 23 octobre 2021 à partir de 9h00 CET

Commit febdf7f7 authored by Éloïs's avatar Éloïs
Browse files

[fix] ws2p heads : prevent fields injection & refactoring headsReceived

parent 121cebe4
......@@ -83,7 +83,8 @@ export const CommonConstants = {
SOFTWARE,
SOFT_VERSION,
POW_PREFIX,
ZERO_OR_POSITIVE_INT
ZERO_OR_POSITIVE_INT,
SIGNATURE
},
BLOCK_GENERATED_VERSION: 10,
......
......@@ -127,28 +127,34 @@ export class WS2PCluster {
async headsReceived(heads:WS2PHead[]) {
await Promise.all(heads.map(async (h:WS2PHead) => {
try {
if (h.messageV2) {
// HEAD v2
if (h.messageV2 && h.messageV2.match(WS2PConstants.HEAD_V2_REGEXP)) {
if (!h.sigV2) {
throw "HEAD_MESSAGE_WRONGLY_SIGNED"
}
const [,,, pub, blockstamp, ws2pId,,,,,]:string[] = h.messageV2.split(':')
this.headReceived(h, pub, [pub, ws2pId].join('-'), blockstamp)
} else if (!h.message) {
throw "EMPTY_MESSAGE_FOR_HEAD"
} else if (!h.sig) {
throw "HEAD_MESSAGE_WRONGLY_SIGNED"
} else {
if (h.message.match(WS2PConstants.HEAD_V0_REGEXP)) {
const [,, pub, blockstamp]:string[] = h.message.split(':')
const ws2pId = (this.server.conf.ws2p && this.server.conf.ws2p.uuid) || '00000000'
} else {
const [,,, pub, blockstamp, ws2pId,,,,,]:string[] = h.messageV2.split(':')
this.headReceived(h, pub, [pub, ws2pId].join('-'), blockstamp)
}
else if (h.message.match(WS2PConstants.HEAD_V1_REGEXP)) {
}
// HEAD v1 and HEAD v0
else if (h.message && h.sig) {
if (h.message.match(WS2PConstants.HEAD_V1_REGEXP)) {
const [,,, pub, blockstamp, ws2pId,,,]:string[] = h.message.split(':')
const fullId =
await this.headReceived(h, pub, [pub, ws2pId].join('-'), blockstamp)
} else if (h.message.match(WS2PConstants.HEAD_V0_REGEXP)) {
const [,,pub, blockstamp]:string[] = h.message.split(':')
await this.headReceived(h, pub, [pub, "00000000"].join('-'), blockstamp)
} else {
throw "HEAD_WRONG_FORMAT"
}
}
else if (!h.message) {
throw "EMPTY_MESSAGE_FOR_HEAD"
} else if (!h.sig) {
throw "HEAD_MESSAGE_WRONGLY_SIGNED"
} else {
throw "HEAD_WRONG_FORMAT"
}
} catch (e) {
this.server.logger.trace(e)
}
......@@ -171,29 +177,41 @@ export class WS2PCluster {
})
}
private async headReceived(head:WS2PHead, pub:string, fullId:string, blockstamp:string) {
private async headReceived(h:WS2PHead, pub:string, fullId:string, blockstamp:string) {
try {
const sigOK = verify(head.message, head.sig, pub)
const sigV2OK = (head.messageV2 !== undefined && head.sigV2 !== undefined) ? verify(head.messageV2, head.sigV2, pub):false
if ((sigV2OK && sigOK) || sigOK) {
// Already known or more recent or closer ?
const step = (this.headsCache[fullId]) ? this.headsCache[fullId].step || 0:0
if (!this.headsCache[fullId] // unknow head
|| parseInt(this.headsCache[fullId].blockstamp) < parseInt(blockstamp) // more recent head
|| (head.step !== undefined && head.step < step && this.headsCache[fullId].blockstamp === blockstamp) // closer head
) {
// Check that issuer is a member and that the block exists
const isAllowed = pub === this.server.conf.pair.pub || this.isConnectedKey(pub) || (await this.isMemberKey(pub))
if (isAllowed) {
const exists = await this.existsBlock(blockstamp)
if (exists) {
this.headsCache[fullId] = { blockstamp, message: head.message, sig: head.sig, messageV2: head.messageV2, sigV2: head.sigV2, step: head.step }
this.newHeads.push(head)
// Prevent fields injection
if ( (h.message.match(WS2PConstants.HEAD_V1_REGEXP) || h.message.match(WS2PConstants.HEAD_V0_REGEXP))
&& h.sig.match(WS2PConstants.HEAD_SIG_REGEXP)
&& (!h.messageV2 || h.messageV2.match(WS2PConstants.HEAD_V2_REGEXP))
&& (!h.sigV2 || h.sigV2.match(WS2PConstants.HEAD_SIG_REGEXP))
&& (!h.step || h.step.toFixed(0).match(/^[0-9]*$/))
) {
const head:WS2PHead = { message: h.message, sig: h.sig, messageV2: h.messageV2, sigV2: h.sigV2, step: h.step }
const sigOK = verify(head.message, head.sig, pub)
const sigV2OK = (head.messageV2 !== undefined && head.sigV2 !== undefined) ? verify(head.messageV2, head.sigV2, pub):false
if ((sigV2OK && sigOK) || sigOK) {
// Already known or more recent or closer ?
const step = (this.headsCache[fullId]) ? this.headsCache[fullId].step || 0:0
if (!this.headsCache[fullId] // unknow head
|| parseInt(this.headsCache[fullId].blockstamp) < parseInt(blockstamp) // more recent head
|| (head.step !== undefined && head.step < step && this.headsCache[fullId].blockstamp === blockstamp) // closer head
) {
// Check that issuer is a member and that the block exists
const isAllowed = pub === this.server.conf.pair.pub || this.isConnectedKey(pub) || (await this.isMemberKey(pub))
if (isAllowed) {
const exists = await this.existsBlock(blockstamp)
if (exists) {
this.headsCache[fullId] = { blockstamp, message: head.message, sig: head.sig, messageV2: head.messageV2, sigV2: head.sigV2, step: head.step }
this.newHeads.push(head)
}
}
}
} else {
throw "HEAD_MESSAGE_WRONGLY_SIGNED"
}
} else {
throw "HEAD_MESSAGE_WRONGLY_SIGNED"
throw "HEAD_WRONG_FORMAT"
}
} catch (e) {
this.server.logger.trace(e)
......
......@@ -59,8 +59,21 @@ export const WS2PConstants = {
+ '(' + CommonConstants.FORMATS.SOFTWARE + '):'
+ '(' + CommonConstants.FORMATS.SOFT_VERSION + '):'
+ '(' + CommonConstants.FORMATS.POW_PREFIX + ')'
+ '$'),
HEAD_V2_REGEXP: new RegExp('^WS2P(?:O[CT][SAM])?(?:I[CT])?:HEAD:2:'
+ '(' + CommonConstants.FORMATS.PUBKEY + '):'
+ '(' + CommonConstants.FORMATS.BLOCKSTAMP + '):'
+ '(' + CommonConstants.FORMATS.WS2PID + '):'
+ '(' + CommonConstants.FORMATS.SOFTWARE + '):'
+ '(' + CommonConstants.FORMATS.SOFT_VERSION + '):'
+ '(' + CommonConstants.FORMATS.POW_PREFIX + '):'
+ '(' + CommonConstants.FORMATS.ZERO_OR_POSITIVE_INT + '):'
+ '(' + CommonConstants.FORMATS.ZERO_OR_POSITIVE_INT + ')'
+ '(?::' + CommonConstants.FORMATS.TIMESTAMP + ')?'
+ '$'),
HEAD_SIG_REGEXP: new RegExp(CommonConstants.FORMATS.SIGNATURE),
HOST_ONION_REGEX: CommonConstants.HOST_ONION_REGEX,
FULL_ADDRESS_ONION_REGEX: CommonConstants.WS_FULL_ADDRESS_ONION_REGEX,
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment