mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-07-25 05:05:20 +00:00
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:
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user