Remove logging for malformed protobuf, remove hint about deleting partial received file errors, firewall alert opening only for specific error code

This commit is contained in:
Leon Böttger committed 2025-05-16 12:58:57 +02:00
1 parent 0115a6453e
commit cbcbb20077
2 files changed
+67 -73

No files matched your search

+10 -18
View File
@@ -33,11 +33,8 @@ class InboundNearbyConnection: NearbyConnection {
override func handleConnectionClosure() {
super.handleConnectionClosure()
currentState = .disconnected
do {
try deletePartiallyReceivedFiles()
} catch {
log("Error deleting partially received files: \(error)")
}
deletePartiallyReceivedFiles()
DispatchQueue.main.async {
self.delegate?.connectionWasTerminated(connection: self, error: self.lastError)
@@ -80,17 +77,7 @@ class InboundNearbyConnection: NearbyConnection {
}
} catch {
lastError = error
log("Deserialization error: \(error) in state \(currentState). Payload: \(frameData.hex)")
// log("Public Key: \(publicKey?.pem ?? "nil")")
// log("Private Key: \(privateKey?.pem ?? "nil")")
// log("Ukey Client Init Msg: \(ukeyClientInitMsgData?.hex ?? "nil")")
// log("Ukey Server Init Msg: \(ukeyServerInitMsgData?.hex ?? "nil")")
log("S1: \(decryptKey?.map { String(format: "%02x", $0) }.joined() ?? "nil")")
// log("Encrypt Key: \(encryptKey?.map { String(format: "%02x", $0) }.joined() ?? "nil")")
log("Received HMAC/Signature Key: \(recvHmacKey?.withUnsafeBytes { Data(Array($0)) }.map { String(format: "%02x", $0) }.joined() ?? "nil")")
log("Sent HMAC/Signature Key: \(sendHmacKey?.withUnsafeBytes { Data(Array($0)) }.map { String(format: "%02x", $0) }.joined() ?? "nil")")
log("Deserialization error: \(error) in state \(currentState).")
protocolError()
}
}
@@ -435,10 +422,15 @@ class InboundNearbyConnection: NearbyConnection {
}
}
private func deletePartiallyReceivedFiles() throws {
private func deletePartiallyReceivedFiles() {
for (_, file) in transferredFiles {
guard file.created else { continue }
try FileManager.default.removeItem(at: file.destinationURL)
do {
try FileManager.default.removeItem(at: file.destinationURL)
}
catch {
// if it fails, we don't care. Could be because file was not created yet
}
}
}
}
+57 -55
View File
@@ -17,7 +17,7 @@ import SwiftECC
class NearbyConnection {
static let SANE_FRAME_LENGTH = 5 * 1024 * 1024
private static let dispatchQueue = DispatchQueue(label: "com.leonboettger.quickdrop.queue", qos: .utility) // FIFO (non-concurrent) queue to avoid those exciting concurrency bugs
let connection: NWConnection
var remoteDeviceInfo: RemoteDeviceInfo?
private var payloadBuffers: [Int64: NSMutableData] = [:]
@@ -26,30 +26,30 @@ class NearbyConnection {
public let id: String
var lastError: Error?
private var connectionClosed: Bool = false
// UKEY2-related state
var publicKey: ECPublicKey?
var privateKey: ECPrivateKey?
var ukeyClientInitMsgData: Data?
var ukeyServerInitMsgData: Data?
// SecureMessage encryption keys
var decryptKey: [UInt8]?
var encryptKey: [UInt8]?
var recvHmacKey: SymmetricKey?
var sendHmacKey: SymmetricKey?
// SecureMessage sequence numbers
private var serverSeq: Int32 = 0
private var clientSeq: Int32 = 0
private(set) var pinCode: String?
init(connection: NWConnection, id: String) {
self.connection = connection
self.id = id
}
func start() {
connection.stateUpdateHandler = { state in
if case .ready = state {
@@ -59,8 +59,10 @@ class NearbyConnection {
self.lastError = err
log("Error opening socket: \(err)")
ConnectionFailureTracker.shared.recordFailure {
NearbyConnectionManager.shared.mainAppDelegate?.showFirewallAlert()
if err == .posix(.ENOTCONN) {
ConnectionFailureTracker.shared.recordFailure {
NearbyConnectionManager.shared.mainAppDelegate?.showFirewallAlert()
}
}
self.handleConnectionClosure()
@@ -69,37 +71,37 @@ class NearbyConnection {
// connection.start(queue: .global(qos: .utility))
connection.start(queue: NearbyConnection.dispatchQueue)
}
func connectionReady() {}
func handleConnectionClosure() {
log("Connection closed")
}
func protocolError() {
disconnect()
}
func processReceivedFrame(frameData _: Data) {
fatalError()
}
func processTransferSetupFrame(_: Sharing_Nearby_Frame) throws {
fatalError()
}
func isServer() -> Bool {
fatalError()
}
func processFileChunk(frame _: Location_Nearby_Connections_PayloadTransferFrame) throws {
protocolError()
}
func processBytesPayload(payload _: Data, id _: Int64) throws -> Bool {
return false
}
private func receiveFrameAsync() {
connection.receive(minimumIncompleteLength: 4, maximumLength: 4) { content, _, isComplete, error in
if self.connectionClosed {
@@ -127,7 +129,7 @@ class NearbyConnection {
self.receiveFrameAsync(length: frameLength)
}
}
private func receiveFrameAsync(length: UInt32) {
connection.receive(minimumIncompleteLength: Int(length), maximumLength: Int(length)) { content, _, isComplete, _ in
if self.connectionClosed {
@@ -145,7 +147,7 @@ class NearbyConnection {
self.receiveFrameAsync()
}
}
func sendFrameAsync(_ frame: Data, completion: (() -> Void)? = nil) {
if connectionClosed {
return
@@ -165,13 +167,13 @@ class NearbyConnection {
}
})
}
func encryptAndSendOfflineFrame(_ frame: Location_Nearby_Connections_OfflineFrame, completion: (() -> Void)? = nil) throws {
var d2dMsg = Securegcm_DeviceToDeviceMessage()
serverSeq += 1
d2dMsg.sequenceNumber = serverSeq
d2dMsg.message = try frame.serializedData()
let serializedMsg = try [UInt8](d2dMsg.serializedData())
let iv = Data.randomData(length: 16)
var encryptedData = Data(count: serializedMsg.count + 16)
@@ -189,7 +191,7 @@ class NearbyConnection {
)
guard status == kCCSuccess else { fatalError("CCCrypt error: \(status)") }
}
var hb = Securemessage_HeaderAndBody()
hb.body = encryptedData.prefix(encryptedLength)
hb.header = Securemessage_Header()
@@ -200,17 +202,17 @@ class NearbyConnection {
md.type = .deviceToDeviceMessage
md.version = 1
hb.header.publicMetadata = try md.serializedData()
var smsg = Securemessage_SecureMessage()
smsg.headerAndBody = try hb.serializedData()
smsg.signature = Data(HMAC<SHA256>.authenticationCode(for: smsg.headerAndBody, using: sendHmacKey!))
try sendFrameAsync(smsg.serializedData(), completion: completion)
}
func sendTransferSetupFrame(_ frame: Sharing_Nearby_Frame) throws {
try sendBytesPayload(data: frame.serializedData(), id: Int64.random(in: Int64.min ... Int64.max))
}
func sendBytesPayload(data: Data, id: Int64) throws {
var transfer = Location_Nearby_Connections_PayloadTransferFrame()
transfer.packetType = .data
@@ -221,32 +223,32 @@ class NearbyConnection {
transfer.payloadHeader.type = .bytes
transfer.payloadHeader.totalSize = Int64(transfer.payloadChunk.body.count)
transfer.payloadHeader.isSensitive = false
var wrapper = Location_Nearby_Connections_OfflineFrame()
wrapper.version = .v1
wrapper.v1 = Location_Nearby_Connections_V1Frame()
wrapper.v1.type = .payloadTransfer
wrapper.v1.payloadTransfer = transfer
try encryptAndSendOfflineFrame(wrapper)
transfer.payloadChunk.flags = 1 // .lastChunk
transfer.payloadChunk.offset = Int64(transfer.payloadChunk.body.count)
transfer.payloadChunk.clearBody()
wrapper.v1.payloadTransfer = transfer
try encryptAndSendOfflineFrame(wrapper)
}
func decryptAndProcessReceivedSecureMessage(_ smsg: Securemessage_SecureMessage) throws {
guard smsg.hasSignature, smsg.hasHeaderAndBody else { throw NearbyError.requiredFieldMissing("secureMessage.signature|headerAndBody") }
if NearbyConnectionManager.shared.checkSignature {
let hmac = Data(HMAC<SHA256>.authenticationCode(for: smsg.headerAndBody, using: recvHmacKey!))
guard hmac == smsg.signature else { throw NearbyError.protocolError("hmac!=signature: Expected \(hmac), got \(smsg.signature)") }
}
let headerAndBody = try Securemessage_HeaderAndBody(serializedBytes: smsg.headerAndBody)
var decryptedData = Data(count: headerAndBody.body.count)
var decryptedLength = 0
decryptedData.withUnsafeMutableBytes {
let status = CCCrypt(
@@ -267,7 +269,7 @@ class NearbyConnection {
clientSeq += 1
guard d2dMsg.sequenceNumber == clientSeq else { throw NearbyError.protocolError("Wrong sequence number. Expected \(clientSeq), got \(d2dMsg.sequenceNumber)") }
let offlineFrame = try Location_Nearby_Connections_OfflineFrame(serializedBytes: d2dMsg.message)
if offlineFrame.hasV1, offlineFrame.v1.hasType, case .payloadTransfer = offlineFrame.v1.type {
guard offlineFrame.v1.hasPayloadTransfer else { throw NearbyError.requiredFieldMissing("offlineFrame.v1.payloadTransfer") }
let payloadTransfer = offlineFrame.v1.payloadTransfer
@@ -309,27 +311,27 @@ class NearbyConnection {
log("Unhandled offline frame encrypted: \(offlineFrame)")
}
}
static func pinCodeFromAuthKey(_ key: SymmetricKey) -> String {
var hash = 0
var multiplier = 1
let keyBytes: [UInt8] = key.withUnsafeBytes {
[UInt8]($0)
}
for _byte in keyBytes {
let byte = Int(Int8(bitPattern: _byte))
hash = (hash + byte * multiplier) % 9973
multiplier = (multiplier * 31) % 9973
}
return String(format: "%04d", abs(hash))
}
static func hkdfExtract(salt: Data, ikm: Data) -> Data {
return HMAC<SHA256>.authenticationCode(for: ikm, using: SymmetricKey(data: salt)).withUnsafeBytes { Data(bytes: $0.baseAddress!, count: $0.count) }
}
static func hkdfExpand(prk: Data, info: Data, length: Int) -> Data {
var okm = Data()
var t = Data()
@@ -342,7 +344,7 @@ class NearbyConnection {
}
return okm.subdata(in: 0 ..< length)
}
static func hkdf(inputKeyMaterial: SymmetricKey, salt: Data, info: Data, outputByteCount: Int) -> SymmetricKey {
if #available(macOS 11.0, *) {
return HKDF<SHA256>.deriveKey(inputKeyMaterial: inputKeyMaterial, salt: salt, info: info, outputByteCount: outputByteCount)
@@ -350,10 +352,10 @@ class NearbyConnection {
return SymmetricKey(data: hkdfExpand(prk: hkdfExtract(salt: salt, ikm: inputKeyMaterial.withUnsafeBytes { Data(bytes: $0.baseAddress!, count: $0.count) }), info: info, length: outputByteCount))
}
}
func finalizeKeyExchange(peerKey: Securemessage_GenericPublicKey) throws {
guard peerKey.hasEcP256PublicKey else { throw NearbyError.requiredFieldMissing("peerKey.ecP256PublicKey") }
let domain = Domain.instance(curve: .EC256r1)
var clientX = peerKey.ecP256PublicKey.x
var clientY = peerKey.ecP256PublicKey.y
@@ -364,36 +366,36 @@ class NearbyConnection {
clientY = clientY.suffix(32)
}
let key = try ECPublicKey(domain: domain, w: Point(BInt(magnitude: [UInt8](clientX)), BInt(magnitude: [UInt8](clientY))))
let dhs = try (privateKey?.domain.multiplyPoint(key.w, privateKey!.s).x.asMagnitudeBytes())!
var sha = SHA256()
sha.update(data: dhs)
let derivedSecretKey = Data(sha.finalize())
var ukeyInfo = Data()
ukeyInfo.append(ukeyClientInitMsgData!)
ukeyInfo.append(ukeyServerInitMsgData!)
let authString = NearbyConnection.hkdf(inputKeyMaterial: SymmetricKey(data: derivedSecretKey), salt: "UKEY2 v1 auth".data(using: .utf8)!, info: ukeyInfo, outputByteCount: 32)
let nextSecret = NearbyConnection.hkdf(inputKeyMaterial: SymmetricKey(data: derivedSecretKey), salt: "UKEY2 v1 next".data(using: .utf8)!, info: ukeyInfo, outputByteCount: 32)
pinCode = NearbyConnection.pinCodeFromAuthKey(authString)
let salt = Data([0x82, 0xAA, 0x55, 0xA0, 0xD3, 0x97, 0xF8, 0x83, 0x46, 0xCA, 0x1C,
0xEE, 0x8D, 0x39, 0x09, 0xB9, 0x5F, 0x13, 0xFA, 0x7D, 0xEB, 0x1D,
0x4A, 0xB3, 0x83, 0x76, 0xB8, 0x25, 0x6D, 0xA8, 0x55, 0x10])
let d2dClientKey = NearbyConnection.hkdf(inputKeyMaterial: nextSecret, salt: salt, info: "client".data(using: .utf8)!, outputByteCount: 32)
let d2dServerKey = NearbyConnection.hkdf(inputKeyMaterial: nextSecret, salt: salt, info: "server".data(using: .utf8)!, outputByteCount: 32)
sha = SHA256()
sha.update(data: "SecureMessage".data(using: .utf8)!)
let smsgSalt = Data(sha.finalize())
let clientKey = NearbyConnection.hkdf(inputKeyMaterial: d2dClientKey, salt: smsgSalt, info: "ENC:2".data(using: .utf8)!, outputByteCount: 32).withUnsafeBytes { [UInt8]($0) }
let clientHmacKey = NearbyConnection.hkdf(inputKeyMaterial: d2dClientKey, salt: smsgSalt, info: "SIG:1".data(using: .utf8)!, outputByteCount: 32)
let serverKey = NearbyConnection.hkdf(inputKeyMaterial: d2dServerKey, salt: smsgSalt, info: "ENC:2".data(using: .utf8)!, outputByteCount: 32).withUnsafeBytes { [UInt8]($0) }
let serverHmacKey = NearbyConnection.hkdf(inputKeyMaterial: d2dServerKey, salt: smsgSalt, info: "SIG:1".data(using: .utf8)!, outputByteCount: 32)
if isServer() {
decryptKey = clientKey
recvHmacKey = clientHmacKey
@@ -406,20 +408,20 @@ class NearbyConnection {
sendHmacKey = clientHmacKey
}
}
func disconnect() {
connection.send(content: nil, isComplete: true, completion: .contentProcessed { _ in
self.handleConnectionClosure()
})
connectionClosed = true
}
func sendDisconnectionAndDisconnect() throws {
var offlineFrame = Location_Nearby_Connections_OfflineFrame()
offlineFrame.version = .v1
offlineFrame.v1.type = .disconnection
offlineFrame.v1.disconnection = Location_Nearby_Connections_DisconnectionFrame()
if encryptionDone {
try encryptAndSendOfflineFrame(offlineFrame)
} else {
@@ -427,7 +429,7 @@ class NearbyConnection {
}
disconnect()
}
func sendUkey2Alert(type: Securegcm_Ukey2Alert.AlertType) {
var alert = Securegcm_Ukey2Alert()
alert.type = type
@@ -437,13 +439,13 @@ class NearbyConnection {
sendFrameAsync(try! msg.serializedData())
disconnect()
}
func sendKeepAlive(ack: Bool) {
var offlineFrame = Location_Nearby_Connections_OfflineFrame()
offlineFrame.version = .v1
offlineFrame.v1.type = .keepAlive
offlineFrame.v1.keepAlive.ack = ack
do {
if encryptionDone {
try encryptAndSendOfflineFrame(offlineFrame)