challenge: make challenges expire after 10 minutes

fixes #10
This commit is contained in:
Vaxry
2025-04-14 13:26:32 +01:00
parent 4f019a97c0
commit 7e1a99a691
6 changed files with 29 additions and 13 deletions

View File

@@ -5,10 +5,11 @@
#include <fmt/format.h>
#include <glaze/glaze.hpp>
constexpr const uint64_t CHALLENGE_VERSION = 1;
constexpr const uint64_t CHALLENGE_VERSION = 2;
constexpr const uint64_t CHALLENGE_EXPIRE_TIME_S = 600; // 10 minutes
CChallenge::CChallenge(const std::string& fingerprint, const std::string& challenge, int difficulty) :
m_fingerprint(fingerprint), m_challenge(challenge), m_difficulty(difficulty) {
m_fingerprint(fingerprint), m_challenge(challenge), m_difficulty(difficulty), m_issued(std::chrono::system_clock::now()) {
std::string toSign = getSigString();
m_sig = g_pCrypto->sign(toSign);
@@ -28,6 +29,10 @@ CChallenge::CChallenge(const std::string& jsonResponse) {
m_fingerprint = s.fingerprint;
m_sig = s.sig;
try {
m_issued = std::chrono::system_clock::time_point(std::chrono::seconds(std::stoull(s.timestamp)));
} catch (std::exception& e) { return; }
if (!g_pCrypto->verifySignature(getSigString(), m_sig))
return;
@@ -54,9 +59,13 @@ std::string CChallenge::signature() const {
}
bool CChallenge::valid() const {
return m_valid;
return m_valid && std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now() - m_issued).count() < CHALLENGE_EXPIRE_TIME_S;
}
std::string CChallenge::getSigString() {
return fmt::format("{}-{},{}", CHALLENGE_VERSION, m_fingerprint, m_challenge);
return fmt::format("{}-{},{},{}", CHALLENGE_VERSION, m_fingerprint, m_challenge, std::chrono::duration_cast<std::chrono::seconds>(m_issued.time_since_epoch()).count());
}
std::string CChallenge::timestampAsString() const {
return std::to_string(std::chrono::duration_cast<std::chrono::seconds>(m_issued.time_since_epoch()).count());
}

View File

@@ -1,6 +1,7 @@
#pragma once
#include <string>
#include <chrono>
class CChallenge {
public:
@@ -10,17 +11,20 @@ class CChallenge {
std::string fingerprint() const;
std::string challenge() const;
std::string signature() const;
std::string timestampAsString() const;
bool valid() const;
private:
std::string getSigString();
std::string getSigString();
std::string m_sig, m_fingerprint, m_challenge;
bool m_valid = false;
int m_difficulty = 4;
std::string m_sig, m_fingerprint, m_challenge;
bool m_valid = false;
int m_difficulty = 4;
std::chrono::system_clock::time_point m_issued;
struct SChallengeJSON {
std::string fingerprint, challenge, sig;
std::string fingerprint, challenge, sig, timestamp;
int difficulty = 4, solution = 0;
};
};

View File

@@ -98,7 +98,7 @@ std::string CCrypto::sha256(const std::string& in) {
}
bool CCrypto::genKey() {
EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_ED25519, nullptr);
EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_ED25519, nullptr);
if (!ctx)
return false;
@@ -178,7 +178,7 @@ bool CCrypto::verifySignature(const std::string& in, const std::string& sig) {
auto sigAsArr = toByteArr(sig);
int ret = EVP_DigestVerify(ctx, sigAsArr.data(), sigAsArr.size(), (const unsigned char*)in.c_str(), in.size());
int ret = EVP_DigestVerify(ctx, sigAsArr.data(), sigAsArr.size(), (const unsigned char*)in.c_str(), in.size());
if (ret == 1) {
// match

View File

@@ -296,6 +296,7 @@ void CServerHandler::serveStop(const Pistache::Http::Request& req, Pistache::Htt
page.add("challengeNonce", CTinylatesProp(NONCE));
page.add("challengeSignature", CTinylatesProp(CHALLENGE.signature()));
page.add("challengeFingerprint", CTinylatesProp(CHALLENGE.fingerprint()));
page.add("challengeTimestamp", CTinylatesProp(CHALLENGE.timestampAsString()));
page.add("checkpointVersion", CTinylatesProp(CHECKPOINT_VERSION));
response.send(Pistache::Http::Code::Ok, page.render().value_or("error"));
}