انتقل إلى المحتوى الرئيسي

محرك التصديق (الصدأ)

يتحقق محرك التصديق من سلامة البرامج الثابتة لـ CPS/IoT باستخدام التوقيعات الرقمية ECDSA P-256. يقوم كل جهاز طرفي بشكل دوري بتوقيع حمولة تثبت عدم التلاعب بالبرامج الثابتة الخاصة به.

لماذا شهادة الأجهزة؟

في البيئة السيبرانية المادية، يمكن أن تتسبب البرامج الثابتة المخترقة في حدوث ضرر جسدي. على عكس أصول تكنولوجيا المعلومات التي يمكنك ببساطة إعادة تصويرها، فإن جهاز التحكم المنطقي القابل للبرمجة (PLC) الذي تم العبث به والذي يتحكم في محطة معالجة المياه يمكن أن يسمم إمدادات المياه.

توفر الشهادة دليلاً رياضيًا على أن البرنامج الثابت الذي يعمل على الجهاز يطابق الإصدار المعروف.

تدفق التصديق

نموذج الطلب/الاستجابة

طلب

#[derive(Deserialize)]
pub struct AttestationVerifyRequest {
pub device_id: String,
pub firmware_hash: String, // SHA-256 hex of firmware binary
pub boot_count: u64, // Monotonic counter (never decreases)
pub signature_hex: String, // ECDSA P-256 signature in hex
pub public_key_hex: Option<String>, // Optional: for initial enrollment
pub nonce: Option<String>, // Challenge-response nonce
}

إجابة

#[derive(Serialize)]
pub struct AttestationVerifyResponse {
pub valid: bool,
pub device_id: String,
pub status: String, // "valid" | "failed" | "structural_pass"
pub reason: String, // Detailed explanation
}

عملية التحقق

الخطوة 1: بناء الرسالة

// The signed message is a concatenation of identity fields
let message = format!(
"{}{}{}{}",
req.device_id,
req.firmware_hash,
req.boot_count,
req.nonce.as_deref().unwrap_or("")
);

الخطوة 2: ملخص SHA-256

use sha2::{Sha256, Digest};

let digest = Sha256::digest(message.as_bytes());

الخطوة 3: القرار الرئيسي

// Priority order for public key:
// 1. Request-provided key (initial enrollment)
// 2. Static device registry (compile-time known devices)
// 3. HashiCorp Vault lookup (production)

let public_key = req.public_key_hex.as_deref()
.or_else(|| DEVICE_KEYS.get(req.device_id.as_str()).copied());

الخطوة 4: التحقق من ECDSA

use p256::ecdsa::{signature::Verifier, Signature, VerifyingKey};

let sig_bytes = hex::decode(&req.signature_hex)?;
let signature = Signature::from_der(&sig_bytes)?;

let key_bytes = hex::decode(public_key)?;
let verifying_key = VerifyingKey::from_sec1_bytes(&key_bytes)?;

match verifying_key.verify(&digest, &signature) {
Ok(_) => {
// Signature valid — firmware is authentic
redis.publish_attestation(&req.device_id, "valid", "Signature verified").await;
Json(AttestationVerifyResponse {
valid: true,
status: "valid".into(),
reason: "ECDSA P-256 signature verified successfully".into(),
// ...
})
}
Err(e) => {
// Signature invalid — potential tampering!
redis.publish_attestation(&req.device_id, "failed", &e.to_string()).await;
Json(AttestationVerifyResponse {
valid: false,
status: "failed".into(),
reason: format!("Signature verification failed: {}", e),
// ...
})
}
}

الخطوة 5: التراجع الهيكلي

في حالة عدم توفر مفتاح عام (تطوير أو أجهزة غير مسجلة)، يقوم المحرك بإجراء التحقق الهيكلي:

// No key available — fallback to structural check
let structural_valid = !req.firmware_hash.is_empty()
&& req.firmware_hash.len() == 64
&& req.boot_count > 0;

if structural_valid {
// Accept with lower confidence
Json(AttestationVerifyResponse {
valid: true,
status: "structural_pass".into(),
reason: "No public key — structural validation only".into(),
})
}

لماذا ECDSA P-256؟

خوارزميةحجم المفتاححجم التوقيعسرعةدعم الأجهزة
آر إس إيه-2048256 بايت256 بايتبطيءمحدود
ECDSA P-25632 بايت64 بايتسريع** STM32 PKA، nRF CC310 **
إد2551932 بايت64 بايتالأسرعنادر في وحدات MCU

تم اختيار ECDSA P-256 للأسباب التالية:

  1. تسريع الأجهزة — يتمتع كل من STM32's PKA وnRF52's CryptoCell CC310 بدعم الأجهزة P-256
  2. التوقيعات الصغيرة — يتم وضع 64 بايت في حزمة MQTT واحدة بكفاءة
  3. الامتثال للمعايير — معتمد من NIST، ويتطلبه العديد من المعايير الصناعية
  4. تخزين المفاتيح — تتلاءم المفاتيح الخاصة بسعة 32 بايت مع مناطق ذاكرة MCU OTP/UICR

حماية عدد التمهيد

يمنع عدد التمهيد الرتيب هجمات إعادة التشغيل:

Attack scenario without boot_count:
1. Attacker captures valid attestation message
2. Replays it after installing malicious firmware
3. System accepts the stale (but valid) signature

With boot_count:
1. Each boot increments a hardware counter stored in OTP
2. Counter can never decrease (hardware fuse)
3. Replayed message has stale boot_count → rejected

التكامل مع Vault PKI

في مرحلة الإنتاج، تتم إدارة المفاتيح العامة للجهاز بواسطة HashiCorp Vault:

تكوين المخزن:

  • محرك PKI: يصدر شهادات جهاز ECDSA P-256 (صلاحية لمدة عام واحد)
  • محرك النقل: يخزن مفاتيح توقيع الجهاز للتحقق منها
  • السياسة: دور aurorasoc-devices — EC P-256، مصادقة العميل EKU

ريديس للنشر

يتم نشر نتائج التصديق على دفق aurora:cps:attestation:

pub async fn publish_attestation(
&self, device_id: &str, status: &str, reason: &str
) {
let mut conn = self.pool.get().await?;
redis::cmd("XADD")
.arg("aurora:cps:attestation")
.arg("MAXLEN").arg("~").arg("10000")
.arg("*")
.arg("device_id").arg(device_id)
.arg("status").arg(status)
.arg("reason").arg(reason)
.arg("timestamp").arg(chrono::Utc::now().to_rfc3339())
.query_async(&mut conn)
.await?;
}