Files
RouterOS/RouterOSAssistant/Core/Networking/CertificateFingerprint.swift
T
KayandClaude Sonnet 5 aad2ccb7d4 Härtung: REST-Query-Injection-Parität + TOFU-Fingerprint-Fallback
Dritter, sicherheitsfokussierter Deep-Dive-Durchgang ("maximale Sicherheit"):

- RestTransport.fetchFieldValues hatte dieselbe ungeschützte
  String-Interpolation wie das SSH-Pendant aus dem vorigen Fix, nur als
  URL-Query statt CLI-Zeile - beim ersten Fix übersehen. Jetzt
  RFC-3986-konform percent-encoded.
- CertificateFingerprint.sha256 fiel bei Extraktionsfehlern auf einen
  festen String "unbekannt" zurück statt echtem Fingerabdruck -
  theoretisches TOFU-Pinning-Bypass-Fenster (zwei verschiedene,
  extraktions-fehlschlagende Zertifikate hätten sich denselben
  "Fingerabdruck" geteilt). Rückgabetyp optional, Extraktionsfehler
  führt jetzt zu hartem Verbindungsabbruch statt Trust-Dialog.

Beide Fixes defensiv/gehärtet, nicht live exploitiert. Zugangsdaten-
Speicherung (Keychain) und BackupServices eigene Escaping-Logik
gegengeprüft - bereits korrekt. Build + alle 101 Unit-Tests grün.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-17 18:14:44 +02:00

25 lines
1.2 KiB
Swift

import Foundation
import Security
import CryptoKit
enum CertificateFingerprint {
/// `nil` means the certificate chain couldn't be read at all — the caller must treat that as
/// a hard connection failure, never as a fingerprint to compare or offer for trust. The
/// previous version returned the fixed string `"unbekannt"` in that case, which — however
/// unlikely to trigger in practice — meant every certificate that failed extraction shared
/// the exact same "fingerprint", so trusting one such (extraction-failed) certificate would
/// have silently trusted every other one too, defeating TOFU pinning for that host. bugs.md,
/// "maximale Sicherheit"-Durchgang, 2026-09-17 — hardening, not a live-reproduced exploit.
static func sha256(of trust: SecTrust) -> String? {
guard
let chain = SecTrustCopyCertificateChain(trust) as? [SecCertificate],
let leaf = chain.first
else {
return nil
}
let data = SecCertificateCopyData(leaf) as Data
let digest = SHA256.hash(data: data)
return digest.map { String(format: "%02X", $0) }.joined(separator: ":")
}
}