Enforce mandatory packet signature verification (#546)

* security: enforce mandatory packet signature verification

* tests: add comprehensive unit tests for packet signature verification
This commit is contained in:
callebtc
2026-01-04 18:47:24 +07:00
committed by GitHub
parent c663e8ede0
commit 55b2d68def
3 changed files with 309 additions and 25 deletions
@@ -69,8 +69,11 @@ class SecurityManager(private val encryptionService: EncryptionService, private
// They are signed/idempotent and we need to ensure first-announce per-connection can bind.
}
// NEW: Signature verification logging (not rejecting yet)
verifyPacketSignatureWithLogging(packet, peerID)
// Enforce mandatory signature verification
if (!verifyPacketSignature(packet, peerID)) {
Log.w(TAG, "Dropping packet from $peerID due to signature verification failure")
return false
}
Log.d(TAG, "Packet validation passed for $peerID, messageID: $messageID")
return true
@@ -223,34 +226,50 @@ class SecurityManager(private val encryptionService: EncryptionService, private
}
/**
* Verify packet signature using peer's signing public key and log the result
* Verify packet signature using peer's signing public key
* Returns true only if signature is present and valid
*/
private fun verifyPacketSignatureWithLogging(packet: BitchatPacket, peerID: String) {
private fun verifyPacketSignature(packet: BitchatPacket, peerID: String): Boolean {
try {
// Check if packet has a signature
// 1. Mandatory Signature Check
if (packet.signature == null) {
Log.d(TAG, "📝 Signature check for $peerID: NO_SIGNATURE (packet type ${packet.type})")
return
Log.w(TAG, " Signature check for $peerID: NO_SIGNATURE (packet type ${packet.type})")
return false
}
// Try to get peer's signing public key from peer info
val peerInfo = delegate?.getPeerInfo(peerID)
val signingPublicKey = peerInfo?.signingPublicKey
// 2. Get Signing Public Key
var signingPublicKey: ByteArray? = null
if (MessageType.fromValue(packet.type) == MessageType.ANNOUNCE) {
// Special Case: ANNOUNCE packets carry their own signing key
try {
val announcement = com.bitchat.android.model.IdentityAnnouncement.decode(packet.payload)
signingPublicKey = announcement?.signingPublicKey
} catch (e: Exception) {
Log.w(TAG, "Failed to decode announcement for key extraction: ${e.message}")
}
} else {
// Standard Case: Get key from known peer info
val peerInfo = delegate?.getPeerInfo(peerID)
signingPublicKey = peerInfo?.signingPublicKey
}
if (signingPublicKey == null) {
Log.d(TAG, "📝 Signature check for $peerID: NO_SIGNING_KEY (packet type ${packet.type})")
return
// If we don't have a key (and it's not an announce), we can't verify.
// For security, we must reject packets from unknown peers unless it's an announce.
Log.w(TAG, "❌ Signature check for $peerID: NO_SIGNING_KEY_AVAILABLE (packet type ${packet.type})")
return false
}
// Get the canonical packet data for signature verification (without signature)
// 3. Get Canonical Data
val packetDataForSigning = packet.toBinaryDataForSigning()
if (packetDataForSigning == null) {
Log.w(TAG, "📝 Signature check for $peerID: ENCODING_ERROR (packet type ${packet.type})")
return
Log.w(TAG, " Signature check for $peerID: ENCODING_ERROR (packet type ${packet.type})")
return false
}
// Verify the signature using the peer's signing public key
val signature = packet.signature!! // We already checked for null above
// 4. Verify Signature
val signature = packet.signature!!
val isSignatureValid = encryptionService.verifyEd25519Signature(
signature,
packetDataForSigning,
@@ -258,13 +277,16 @@ class SecurityManager(private val encryptionService: EncryptionService, private
)
if (isSignatureValid) {
Log.d(TAG, "📝 Signature check for $peerID: ✅ VALID (packet type ${packet.type})")
// Log.v(TAG, "✅ Signature verified for $peerID (type ${packet.type})")
return true
} else {
Log.w(TAG, "📝 Signature check for $peerID: ❌ INVALID (packet type ${packet.type})")
Log.w(TAG, " Signature INVALID for $peerID (type ${packet.type})")
return false
}
} catch (e: Exception) {
Log.w(TAG, "📝 Signature check for $peerID: ERROR - ${e.message} (packet type ${packet.type})")
Log.e(TAG, " Signature verification error for $peerID: ${e.message}")
return false
}
}