Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 68 additions & 6 deletions infrastructure/eid-wallet/src/routes/(app)/scan-qr/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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,
};

Expand Down Expand Up @@ -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");

Expand Down
31 changes: 31 additions & 0 deletions platforms/evoting-api/src/services/SigningService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Loading