From c3bf3be7cb81ead270d56667621974fd485c1ea0 Mon Sep 17 00:00:00 2001 From: Dominik Hebeler <dominik@hebeler.club> Date: Sat, 11 Mar 2023 21:17:09 +0100 Subject: [PATCH] signing tokens with fixed time --- pass/routes/api.js | 107 ++++++++++++++++++++++++++++++--------------- 1 file changed, 71 insertions(+), 36 deletions(-) diff --git a/pass/routes/api.js b/pass/routes/api.js index 04bc7ec..1d3d20f 100644 --- a/pass/routes/api.js +++ b/pass/routes/api.js @@ -1,10 +1,7 @@ var express = require("express"); var router = express.Router(); -const { - body, - validationResult -} = require("express-validator"); +const { body, validationResult } = require("express-validator"); const config = require("config"); const Key = require("../app/Key"); @@ -187,19 +184,33 @@ router.get("/token/pubkey", async (req, res) => { }); }); -router.post("/token/sign", body("key").notEmpty(), body("date").notEmpty().custom(value => { - // Make sure the date is either for the last month or this month - let date = dayjs(value, config.get("crypto.private_key.date_format")); - let min = dayjs().millisecond(0).second(0).minute(0).hour(0).date(1).subtract(1, "month"); - let max = min.add(2, "month"); - if (!date.isValid() || date.isBefore(min) || !date.isBefore(max)) { - return Promise.reject("Submitted Date format is invalid"); - } - return true; -}), - body("blinded_tokens").notEmpty().withMessage("Blinded Tokens need to be defined") - .isArray({ min: 1, max: 10 }).withMessage("You can supply between 1 and 10 tokens to sign") - .custom(value => { +router.post( + "/token/sign", + body("key").notEmpty(), + body("date") + .notEmpty() + .custom((value) => { + // Make sure the date is either for the last month or this month + let date = dayjs(value, config.get("crypto.private_key.date_format")); + let min = dayjs() + .millisecond(0) + .second(0) + .minute(0) + .hour(0) + .date(1) + .subtract(1, "month"); + let max = min.add(2, "month"); + if (!date.isValid() || date.isBefore(min) || !date.isBefore(max)) { + return Promise.reject("Submitted Date format is invalid"); + } + return true; + }), + body("blinded_tokens") + .notEmpty() + .withMessage("Blinded Tokens need to be defined") + .isArray({ min: 1, max: 10 }) + .withMessage("You can supply between 1 and 10 tokens to sign") + .custom((value) => { let checked_tokens = {}; for (let i = 0; i < value.length; i++) { if (value[i] in checked_tokens) { @@ -209,41 +220,65 @@ router.post("/token/sign", body("key").notEmpty(), body("date").notEmpty().custo } } return true; - }) - , async (req, res) => { + }), + async (req, res) => { const errors = validationResult(req); if (!errors.isEmpty()) { res.status(422).json(errors); return; } let key = await Key.GET_KEY(req.body.key, false); - let date = dayjs(req.body.date, config.get("crypto.private_key.date_format")); + let date = dayjs( + req.body.date, + config.get("crypto.private_key.date_format") + ); let blinded_tokens = req.body.blinded_tokens; let signed_tokens = {}; + if (key.get_charge() < blinded_tokens.length) { + res.status(422).json({ + message: "Invalid Key", + }); + } + + // Make signing requests always the same duration to prevent timing attacks on the private key + let duration_millis = 1000; + let start_time = dayjs(); + let crypto = new Crypto(); - crypto.get_private_key(date).then(private_key => { - for (let i = 0; i < blinded_tokens.length; i++) { - let blinded_token = blinded_tokens[i]; - signed_tokens[blinded_token] = crypto.sign(blinded_token, private_key).toString(); - } + await crypto + .get_private_key(date) + .then((private_key) => { + for (let i = 0; i < blinded_tokens.length; i++) { + let blinded_token = blinded_tokens[i]; + signed_tokens[blinded_token] = crypto + .sign(blinded_token, private_key) + .toString(); + } + }) + .catch((reason) => { + console.error(reason); + res.status(500).json({ + status: 500, + message: "Couldn't load private key", + }); + }); + + let missing_millis = Math.max( + duration_millis - dayjs().diff(start_time, "millisecond"), + 0 + ); + setTimeout(() => { res.status(201).json({ key: key.get_key, discharged: blinded_tokens.length, date: date.format(config.get("crypto.private_key.date_format")), - signed_tokens: signed_tokens + signed_tokens: signed_tokens, }); - }).catch(reason => { - console.error(reason); - res.status(500).json({ - status: 500, - message: "Couldn't load private key" - }); - }); - - - }); + }, missing_millis); + } +); router.use((req, res) => { res.status(404).json({ -- GitLab