diff --git a/infrastructure/eid-wallet/src/routes/(app)/scan-qr/+page.svelte b/infrastructure/eid-wallet/src/routes/(app)/scan-qr/+page.svelte index e0fe7d25..6691621e 100644 --- a/infrastructure/eid-wallet/src/routes/(app)/scan-qr/+page.svelte +++ b/infrastructure/eid-wallet/src/routes/(app)/scan-qr/+page.svelte @@ -16,6 +16,13 @@ requestPermissions, scan, } from "@tauri-apps/plugin-barcode-scanner"; + import { + exists, + generate, + getPublicKey, + signPayload, + // verifySignature + } from "@auvo/tauri-plugin-crypto-hw-api"; import axios from "axios"; import { getContext, onDestroy, onMount } from "svelte"; import type { SVGAttributes } from "svelte/elements"; @@ -401,15 +408,40 @@ }); } - // In a real implementation, you would use the vault's signing capabilities - // For now, we'll simulate the signing process - await new Promise((resolve) => setTimeout(resolve, 2000)); // Simulate signing delay + // 🔐 REAL CRYPTOGRAPHIC SIGNING using Tauri crypto plugin + console.log("🔐 Starting cryptographic signing process..."); + + // Check if crypto hardware exists + const cryptoExists = await exists("default"); + if (!cryptoExists) { + throw new Error("Cryptographic hardware not available"); + } + + // Generate default key if it doesn't exist + try { + await generate("default"); + console.log("✅ Default key generated/verified"); + } catch (error) { + console.log( + "Default key already exists or generation failed:", + error, + ); + } + + // Get the public key + const publicKey = await getPublicKey("default"); + console.log("🔑 Public key retrieved:", publicKey); + + // Sign the message payload + console.log("✍️ Signing message:", messageToSign); + const signature = await signPayload("default", messageToSign); + console.log("✅ Message signed successfully"); - // Create the signed payload + // Create the signed payload with real signature const signedPayload = { sessionId: signingSessionId, - signature: "simulated_signature_" + Date.now(), // In real implementation, this would be the actual signature - publicKey: vault?.ename || "unknown_public_key", // Use eName as public key for now + signature: signature, + publicKey: vault?.ename || "unknown_public_key", // Use eName as public key message: messageToSign, }; @@ -560,6 +592,36 @@ throw new Error("No vault available for blind voting"); } + // 🔐 Get the real public key for voter identification + let voterPublicKey: string; + try { + const cryptoExists = await exists("default"); + if (!cryptoExists) { + throw new Error("Cryptographic hardware not available"); + } + + // Generate default key if it doesn't exist + try { + await generate("default"); + console.log( + "✅ Default key generated/verified for blind voting", + ); + } catch (edit) { + console.log( + "Default key already exists or generation failed:", + edit, + ); + } + + // Get the public key + voterPublicKey = await getPublicKey("default"); + console.log("🔑 Voter public key retrieved:", voterPublicKey); + } catch (error) { + console.error("Failed to get cryptographic public key:", error); + // Fallback to ename if crypto fails + voterPublicKey = vault.ename || "unknown_public_key"; + } + // Dynamically import the blindvote library const { VotingSystem } = await import("blindvote"); diff --git a/platforms/evoting-api/src/services/SigningService.ts b/platforms/evoting-api/src/services/SigningService.ts index aacc9dc2..47c5017e 100644 --- a/platforms/evoting-api/src/services/SigningService.ts +++ b/platforms/evoting-api/src/services/SigningService.ts @@ -128,6 +128,37 @@ export class SigningService { } try { + // 🔐 SECURITY ASSERTION: Verify that the publicKey matches the user's ename who created the session + try { + const { UserService } = await import('./UserService'); + const userService = new UserService(); + const user = await userService.getUserById(session.userId); + + if (!user) { + return { success: false, error: "User not found for session" }; + } + + // Strip @ prefix from both enames before comparison + const cleanPublicKey = publicKey.replace(/^@/, ''); + const cleanUserEname = user.ename.replace(/^@/, ''); + + if (cleanPublicKey !== cleanUserEname) { + console.error(`🔒 SECURITY VIOLATION: publicKey mismatch!`, { + publicKey, + userEname: user.ename, + cleanPublicKey, + cleanUserEname, + sessionUserId: session.userId + }); + return { success: false, error: "Public key does not match the user who created this signing session" }; + } + + console.log(`✅ Public key verification passed: ${cleanPublicKey} matches ${cleanUserEname}`); + } catch (error) { + console.error("Error during public key verification:", error); + return { success: false, error: "Failed to verify public key: " + (error instanceof Error ? error.message : "Unknown error") }; + } + // Verify the signature (basic verification for now) // In production, you'd want proper cryptographic verification const expectedMessage = JSON.stringify({ diff --git a/platforms/group-charter-manager-api/src/services/CharterSigningService.ts b/platforms/group-charter-manager-api/src/services/CharterSigningService.ts index 40cabe66..5b6fa6c5 100644 --- a/platforms/group-charter-manager-api/src/services/CharterSigningService.ts +++ b/platforms/group-charter-manager-api/src/services/CharterSigningService.ts @@ -114,6 +114,37 @@ export class CharterSigningService { throw new Error("Invalid signature data"); } + // 🔐 SECURITY ASSERTION: Verify that the publicKey matches the user's ename who created the session + try { + const { UserService } = await import('./UserService'); + const userService = new UserService(); + const user = await userService.getUserById(session.userId); + + if (!user) { + throw new Error("User not found for session"); + } + + // Strip @ prefix from both enames before comparison + const cleanPublicKey = publicKey.replace(/^@/, ''); + const cleanUserEname = user.ename.replace(/^@/, ''); + + if (cleanPublicKey !== cleanUserEname) { + console.error(`🔒 SECURITY VIOLATION: publicKey mismatch!`, { + publicKey, + userEname: user.ename, + cleanPublicKey, + cleanUserEname, + sessionUserId: session.userId + }); + throw new Error("Public key does not match the user who created this signing session"); + } + + console.log(`✅ Public key verification passed: ${cleanPublicKey} matches ${cleanUserEname}`); + } catch (error) { + console.error("Error during public key verification:", error); + throw new Error("Failed to verify public key: " + (error instanceof Error ? error.message : "Unknown error")); + } + // Record the signature in the database try { await this.signatureService.recordSignature(