diff --git a/enzevalos_iphone.xcodeproj/xcshareddata/xcschemes/enzevalos_iphone.xcscheme b/enzevalos_iphone.xcodeproj/xcshareddata/xcschemes/enzevalos_iphone.xcscheme index a96d2b4f5b40e52bd3d386370f8e2734d997743e..5750422cbbc26f8b1dec60b3add457775f258a4b 100644 --- a/enzevalos_iphone.xcodeproj/xcshareddata/xcschemes/enzevalos_iphone.xcscheme +++ b/enzevalos_iphone.xcodeproj/xcshareddata/xcschemes/enzevalos_iphone.xcscheme @@ -26,8 +26,17 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - codeCoverageEnabled = "YES" - shouldUseLaunchSchemeArgsEnv = "YES"> + shouldUseLaunchSchemeArgsEnv = "YES" + codeCoverageEnabled = "YES"> + <MacroExpansion> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "A13526741D955BDF00D3BFE1" + BuildableName = "enzevalos_iphone.app" + BlueprintName = "enzevalos_iphone" + ReferencedContainer = "container:enzevalos_iphone.xcodeproj"> + </BuildableReference> + </MacroExpansion> <Testables> <TestableReference skipped = "NO"> @@ -55,17 +64,6 @@ </BuildableReference> </TestableReference> </Testables> - <MacroExpansion> - <BuildableReference - BuildableIdentifier = "primary" - BlueprintIdentifier = "A13526741D955BDF00D3BFE1" - BuildableName = "enzevalos_iphone.app" - BlueprintName = "enzevalos_iphone" - ReferencedContainer = "container:enzevalos_iphone.xcodeproj"> - </BuildableReference> - </MacroExpansion> - <AdditionalOptions> - </AdditionalOptions> </TestAction> <LaunchAction buildConfiguration = "Debug" @@ -88,8 +86,6 @@ ReferencedContainer = "container:enzevalos_iphone.xcodeproj"> </BuildableReference> </BuildableProductRunnable> - <AdditionalOptions> - </AdditionalOptions> <LocationScenarioReference identifier = "com.apple.dt.IDEFoundation.CurrentLocationScenarioIdentifier" referenceType = "1"> diff --git a/enzevalos_iphone/Certificate.swift b/enzevalos_iphone/Certificate.swift index f81ccf199151c59b904ea5807d90d07ea08231a9..57461a560f1ee3dece36bafc88fdb78075d40c75 100644 --- a/enzevalos_iphone/Certificate.swift +++ b/enzevalos_iphone/Certificate.swift @@ -8,19 +8,6 @@ import Foundation -struct SMIMEError : Error { - enum ErrorType { - case fingerPrint - case encryption - case decryption - case signing - } - - let message: String? - let errorArray: [UInt]? - let type: ErrorType -} - class Certificate { // TODO: make all attributes private with getters let pem: String // raw PEM string diff --git a/enzevalos_iphone/SMIME.swift b/enzevalos_iphone/SMIME.swift index 4308dc483d402a3c4427df5dbe543bf12cb617cf..34b80fb9b2c58e530774f0bd26d9a4ea12987cbe 100644 --- a/enzevalos_iphone/SMIME.swift +++ b/enzevalos_iphone/SMIME.swift @@ -276,6 +276,7 @@ PkfA6mR7rtcyIbHi34tfkCv/qolV3QivMHov0IJpRyNO for cert in certs { let (fp, _, _) = getFingerprintFromPem(pem: cert) + // TODO Exception if fp != nil { keychain[fp!] = cert fingerprints.append(fp!) @@ -383,6 +384,10 @@ PkfA6mR7rtcyIbHi34tfkCv/qolV3QivMHov0IJpRyNO } } + func getOwnKeyFP() -> String? { + return privateKeyKeychain["ownkey"] + } + func testSMIMEencrypt(){ // OpenSSL_print_ver() @@ -495,10 +500,122 @@ PkfA6mR7rtcyIbHi34tfkCv/qolV3QivMHov0IJpRyNO } } - func encrypt() -> CryptoObject? { - // TODO: do we need a keychain that sotres userID -> user key/cert fp. - // MY IDEA WAS SAVING THE FP under the email in the cert kezchain + // Note: we ignore the Encryption interface because some things are built with PGP in mind and make no sense in the context of SMIME (signatureIDs for example) + func decrypt(data: Data, attatchedSig: Data? = nil, fromAddr: String) -> CryptoObject { + // NOTE TO SELF: Implement verify with CryptoObject BEFORE decrypt + + } + + func sign(plainData: Data, myEmail: String, detached: Bool = true) throws -> CryptoObject { + let fp = getOwnKeyFP() + let cert = certsKeychain[fp!]! + let key = privateKeyKeychain[fp!]! + + let text = String(data: plainData, encoding: .utf8) + + let (sigText, errArr) = signWithPem(message: text!, certAsPem: cert, keyAsPem: key, detached: detached) + + // TODO: Exception + + return CryptoObject(chiphertext: sigText!.data(using: .utf8), plaintext: text, decryptedData: plainData, sigState: SignatureState.ValidSignature, encState: EncryptionState.NoEncryption, signKey: fp, encType: CryptoScheme.SMIME, signedAdrs: [myEmail]) + } + + // If multiple signatures are present, ALL need to be valid AND have a matching mail address, else the signature is invalid. + func verify(data: Data, attacthedSig: Data?, email: String, isMailNew: Bool) -> SignatureState? { + var CAs : [String] = [] + CAKeychain.allKeys().forEach({ (key) in + CAs.append(CAKeychain[key]!) + }) + let text = String(data: data, encoding: .utf8)! + + let (verStr, certsFPArr, errArr) = verifyWithCApem(message: text, pemCAArr: CAs) + if certsFPArr != nil { + var newCerts: [String] = [] // all certs that came from the email and weren't available before + var mailMatch = true + if certsFPArr?.count == 0 {mailMatch = false} + for item in certsFPArr! { + var mailFound = false + let (fp, cert) = item + let certObj = Certificate(pem: cert) + // check if the email from the parameters matches with one of the emails in each of the certs used to sign the message + for addr in certObj.eMails ?? [] { + if addr == email { + mailFound = true + break + } + } + mailMatch = mailFound && mailMatch + // check if cert is already in the keychain + if let _ = try? certsKeychain.get(fp) { + continue + } + newCerts.append(cert) + } + + let fps = importCerts(certs: newCerts) + // check if the email has no certificate or the certificate is newer than the present one and update accordingly + for fp in fps{ + let cert = Certificate(pem: certsKeychain[fp]!) + for email in cert.eMails ?? [] + { + if isMailNew || certsKeychain[email] == nil + { + certsKeychain[email] = fp + } + } + } + + return mailMatch ? SignatureState.ValidSignature : SignatureState.InvalidSignature + } + + return nil + // TODO: Exception no valid signatures + } + + func encrypt(plainData: Data, ids: [String], ownId: String, encryptForMyId: Bool = true) -> CryptoObject? { + let text = String(data: plainData, encoding: .utf8) + var pems: [String] = [] + var ownFp: String? = nil + for id in ids { + if let fp = certsKeychain[id] { + // TODO: Exception try catch + pems.append(certsKeychain[fp]!) + } + else{ + // TODO: Exception + print("No cert for email ", id) + } + } + // TODO: Ask Oliver why signing is allowed only with encryptForMyID = true + if encryptForMyId { + if let fp = getOwnKeyFP() { + ownFp = fp + // TODO: Exception try catch + pems.append(certsKeychain[fp]!) + } + else { + // TODO: Exception + print("No cert for own key!") + } + } + // TODO: try-catch text + let (encStr, errArr) = encryptWithPem(message: text!, certPems: pems) + let encData = encStr?.data(using: .utf8) + + // TODO: check if errArr empty, exception + + if ownFp != nil { + let ownCert = certsKeychain[ownFp!]! + let ownPk = privateKeyKeychain[ownFp!]! + let (sigText, sigErrArr) = signWithPem(message: encStr!, certAsPem: ownCert, keyAsPem: ownPk, detached: false) + // TODO: check if errArr empty, exception + + return CryptoObject(chiphertext: sigText!.data(using: .utf8), plaintext: text, decryptedData: plainData, sigState: SignatureState.ValidSignature, encState: EncryptionState.ValidedEncryptedWithCurrentKey, signKey: ownFp, encType: CryptoScheme.SMIME, signedAdrs: [ownId]) + } + return nil + // TODO: Exception + // throw SMIMEError } } diff --git a/enzevalos_iphone/SMIMEHelpers.swift b/enzevalos_iphone/SMIMEHelpers.swift index 0fecac3698d6799666a97eb70fdfc57e00b96b7a..8c832258bd4e5c4fb35745f1fc840700ebb63622 100644 --- a/enzevalos_iphone/SMIMEHelpers.swift +++ b/enzevalos_iphone/SMIMEHelpers.swift @@ -8,12 +8,24 @@ import Foundation +struct SMIMEError : Error { + enum ErrorType { + case fingerPrint + case encryption + case decryption + case signing + } + + let message: String? + let errorArray: [UInt]? + let type: ErrorType +} + func encryptWithPem(message: String,certPems: [String]) -> (String?, [UInt]?) { let cCertsArray = createCStrArr(sarr: certPems) let enc = OpenSSL_encrypt(message, cCertsArray, Int32(certPems.count)) defer { deallocateResult(res: enc) - // enc?.deallocate() } let result = enc?.pointee; @@ -28,7 +40,6 @@ func decryptWithPem(message:String, certAsPem: String, keyAsPem:String) -> (Stri let dec = OpenSSL_decrypt(message, certAsPem, keyAsPem) defer { deallocateResult(res: dec) - // dec?.deallocate() } let result = dec?.pointee; @@ -47,7 +58,6 @@ func signWithPem(message:String, certAsPem: String, keyAsPem:String, detached:Bo let sig = OpenSSL_sign(message, certAsPem, keyAsPem, detFlag) defer { deallocateResult(res: sig) - // sig?.deallocate() } let result = sig?.pointee @@ -98,7 +108,6 @@ func getFingerprintFromPem (pem: String) -> (String?, [String]?, [UInt]?) { let res = get_fingerprint_from_pem(pem, 0); defer { deallocateResult(res: res) - // res?.deallocate() } let result = res?.pointee;