From 6a9c076dc4e6ed70cdd5e5e410d41e60f85889f0 Mon Sep 17 00:00:00 2001
From: Oliver Wiese <oliver.wiese@fu-berlin.de>
Date: Wed, 6 Mar 2019 11:16:22 +0100
Subject: [PATCH] update Mailhandler

---
 enzevalos_iphone/MailHandler.swift | 104 ++++++++++++++++++++++++++++-
 1 file changed, 102 insertions(+), 2 deletions(-)

diff --git a/enzevalos_iphone/MailHandler.swift b/enzevalos_iphone/MailHandler.swift
index 98885e3b..e573b474 100644
--- a/enzevalos_iphone/MailHandler.swift
+++ b/enzevalos_iphone/MailHandler.swift
@@ -512,6 +512,7 @@ class MailHandler {
                             return
                         }
                         if let parser = data {
+                            
                             _ = self.parseMail(parser: parser, record: record, folderPath: folderPath, uid: UInt64(message.uid), flags: message.flags)
 
                         }
@@ -565,7 +566,6 @@ class MailHandler {
                 }
             }
         }
-        
         if let _ = header?.extraHeaderValue(forName: Autocrypt.AUTOCRYPTHEADER) {
             autocrypt = Autocrypt(header: header!)
         }
@@ -583,12 +583,16 @@ class MailHandler {
                 cc.append(r as! MCOAddress)
             }
         }
+        var attachedSignature: Data?
         // 2. parse body
         for a in (msgParser.attachments())! {
             let at = a as! MCOAttachment
             if at.mimeType == "application/pgp-encrypted" {
                 isEnc = true
             }
+            if let signature = MailHandler.extractPGPSignature(attachment: at) {
+                attachedSignature = signature
+            }
             if isEnc && at.mimeType == "application/octet-stream" {
                 msgParser = MCOMessageParser(data: at.data)
             }
@@ -618,7 +622,21 @@ class MailHandler {
 
                 }
             }
-        } else {
+        }
+        else if let attachedSig = attachedSignature {
+            let signedData = MailHandler.extractSignedData(data: msgParser.data())
+            let pgp = SwiftPGP()
+            var keyIds = [String]()
+            if let sender = header?.from.mailbox {
+                if let adr = DataHandler.handler.findMailAddress(adr: sender) {
+                    for k in adr.publicKeys {
+                        keyIds.append(k.keyID)
+                    }
+                }
+                dec = pgp.verify(data: signedData!, attachedSignature: attachedSig, verifyIds: keyIds, fromAdr: sender)
+            }
+        }
+        else {
             body = parseBody(msgParser: msgParser)
             if let chipher = findInlinePGP(text: msgParser.plainTextRendering()) {
                 dec = decryptText(body: chipher, from: header?.from, autocrypt: autocrypt)
@@ -650,6 +668,88 @@ class MailHandler {
         }
         return nil
     }
+    
+    
+    func findSignedDataAndSignature(data: Data) -> (signedData: Data?, signature: Data?) {
+        var sig: Data?
+        if let parser = MCOMessageParser.init(data: data) {
+            for part in parser.attachments() {
+                if let attachment = part as? MCOAttachment, let data = MailHandler.extractPGPSignature(attachment: attachment) {
+                    sig = data
+                    break
+                }
+            }
+        }
+        
+        return (MailHandler.extractSignedData(data: data), sig)
+    }
+    
+    private static func matches(for regex: String, in text: String) -> [String] {
+        do {
+            let regex = try NSRegularExpression(pattern: regex)
+            let results = regex.matches(in: text,
+                                        range: NSRange(text.startIndex..., in: text))
+            return results.map {
+                String(text[Range($0.range, in: text)!])
+            }
+        } catch {
+            return []
+        }
+    }
+    private static func findBoundary(rawMail: String) -> String? {
+        let boundaries = matches(for: "boundary=.*;", in: rawMail)
+        if let bound = boundaries.first {
+            let splitted = bound.split(separator: "\"")
+            if splitted.count == 3 {
+                return "--"+String(splitted[1]) as String
+            }
+        }
+        return nil
+    }
+    
+    private static func extractSignedData(data: Data) -> Data? {
+        if let dataString = String.init(data: data, encoding: .utf8){
+            if dataString.contains("Content-Type: multipart/signed") , let boundary = findBoundary(rawMail: dataString) {
+                var parts =  dataString.components(separatedBy: boundary).dropFirst().filter({(s: String) -> Bool in
+                    // We drop pgp signature.
+                    // A messages, where a signed part is signed again, are strange and verification can fail -> What about a response etc?
+                    if s.contains("-----BEGIN PGP SIGNATURE-----") {
+                        return false
+                    }
+                    return true
+                })
+                parts = parts.map({(s: String) -> String in
+                    // Convert strings according to RFC3156. See: https://tools.ietf.org/html/rfc3156 page 6
+                    var newString = s.trimmed()
+                    newString = newString.replacingOccurrences(of: "\r\n", with: "\n")
+                    newString = newString.replacingOccurrences(of: "\n", with: "\r\n")
+                    // Sometimes tabs got lost?! TEST TODO
+                    newString = newString.replacingOccurrences(of: "    charset", with: "\tcharset")
+                    //TODO: Remove -- if last symbol
+                    if newString.hasSuffix("--") {
+                        newString = String(newString.dropLast(2))
+                    }
+                    return newString
+                })
+                if parts.count == 0 {
+                    return parts.first?.data(using: .utf8)
+                }
+                else {
+                    let res = parts.joined(separator: "\r\n")
+                    return res.data(using: .utf8)
+                }
+            }
+        }
+        return nil
+    }
+    
+    
+    private static func extractPGPSignature(attachment: MCOAttachment) -> Data? {
+        if attachment.mimeType == "application/pgp-signature" {
+           return attachment.data
+        }
+        return nil
+    }
 
     
     private func parseBody(msgParser: MCOMessageParser) -> String {
-- 
GitLab