From 038ddb78e70f73ab376f22dbfa40e98a62aa13ec Mon Sep 17 00:00:00 2001 From: Mento Date: Wed, 14 Jan 2015 01:23:59 +0100 Subject: [PATCH 01/56] installerHelper requests privileges. Use authorization functions to get privileges. --- Installer/libmacgpg_core-postinstall.sh | 1 - Libmacgpg.xcodeproj/project.pbxproj | 299 +++++++++++------- .../xcschemes/Libmacgpg + XPC.xcscheme | 4 +- installerHelper/installerHelper-Info.plist | 30 ++ installerHelper/main.m | 105 ++++-- 5 files changed, 287 insertions(+), 152 deletions(-) create mode 100644 installerHelper/installerHelper-Info.plist diff --git a/Installer/libmacgpg_core-postinstall.sh b/Installer/libmacgpg_core-postinstall.sh index caaf0b7..8c3cbfc 100755 --- a/Installer/libmacgpg_core-postinstall.sh +++ b/Installer/libmacgpg_core-postinstall.sh @@ -1,4 +1,3 @@ #!/bin/bash -chmod u+s "/Library/Frameworks/Libmacgpg.framework/Resources/installerHelper" exit 0 diff --git a/Libmacgpg.xcodeproj/project.pbxproj b/Libmacgpg.xcodeproj/project.pbxproj index 3fbc906..b595ed5 100644 --- a/Libmacgpg.xcodeproj/project.pbxproj +++ b/Libmacgpg.xcodeproj/project.pbxproj @@ -40,13 +40,19 @@ 1BD78BBA1726B6060005F251 /* Libmacgpg.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8DC2EF5B0486A6940098B216 /* Libmacgpg.framework */; }; 1BD78BBC1726B6230005F251 /* Libmacgpg.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8DC2EF5B0486A6940098B216 /* Libmacgpg.framework */; }; 1BDA56BC1618A94300185C72 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4591C4D314F86D38007F6D47 /* AppKit.framework */; }; - 3002C04416EE388B00D57C1E /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 3002C04316EE388B00D57C1E /* libcrypto.dylib */; }; - 3002C04616EE389100D57C1E /* libxar.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 3002C04516EE389100D57C1E /* libxar.dylib */; }; 3002C04716EE38C900D57C1E /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 3002C04316EE388B00D57C1E /* libcrypto.dylib */; }; 300DD0FA1853AF300057B05F /* How to get the source code in Resources */ = {isa = PBXBuildFile; fileRef = 300DD0F91853AF300057B05F /* How to get the source code */; }; 301D5D9F178C9871003026E7 /* GPGKeyserver.h in Headers */ = {isa = PBXBuildFile; fileRef = 301D5D9D178C9871003026E7 /* GPGKeyserver.h */; }; 301D5DA0178C9871003026E7 /* GPGKeyserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 301D5D9E178C9871003026E7 /* GPGKeyserver.m */; }; 3026F4AF13A203A000F3CA02 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3026F4AE13A203A000F3CA02 /* Security.framework */; }; + 30444C461A65E3D70052CB94 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 30DF7CBB16D39EAA00C8225C /* main.m */; }; + 30444C491A65E46F0052CB94 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4591C4D514F86D38007F6D47 /* Foundation.framework */; }; + 30444C4A1A65E4740052CB94 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3026F4AE13A203A000F3CA02 /* Security.framework */; }; + 30444C4B1A65E4790052CB94 /* SecurityFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3077AE881A6547D2001EC508 /* SecurityFoundation.framework */; }; + 30444C4C1A65E4800052CB94 /* libxar.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 3002C04516EE389100D57C1E /* libxar.dylib */; }; + 30444C4D1A65E4B50052CB94 /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 3002C04316EE388B00D57C1E /* libcrypto.dylib */; }; + 30444C4F1A65E6F00052CB94 /* gpgtools.icns in Resources */ = {isa = PBXBuildFile; fileRef = 30444C4E1A65E6F00052CB94 /* gpgtools.icns */; }; + 30444C501A65E83D0052CB94 /* GPGTools.app in Resources */ = {isa = PBXBuildFile; fileRef = 30444C181A65E0590052CB94 /* GPGTools.app */; }; 3048830B1462B11700F2E5F4 /* DirectoryWatcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 304883091462B11700F2E5F4 /* DirectoryWatcher.h */; }; 3048830C1462B11700F2E5F4 /* DirectoryWatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 3048830A1462B11700F2E5F4 /* DirectoryWatcher.m */; }; 3048830F1462B22000F2E5F4 /* GPGWatcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 3048830D1462B22000F2E5F4 /* GPGWatcher.h */; }; @@ -69,10 +75,6 @@ 30C8B3B11395072C00F49AA1 /* Libmacgpg.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8DC2EF5B0486A6940098B216 /* Libmacgpg.framework */; }; 30D5E2A41483A0F700F31454 /* GPGConf.h in Headers */ = {isa = PBXBuildFile; fileRef = 30D5E2A21483A0F700F31454 /* GPGConf.h */; }; 30D5E2A51483A0F700F31454 /* GPGConf.m in Sources */ = {isa = PBXBuildFile; fileRef = 30D5E2A31483A0F700F31454 /* GPGConf.m */; }; - 30DF7CB916D39EAA00C8225C /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1B3D64DF1565BC6600D93BBE /* Foundation.framework */; }; - 30DF7CBC16D39EAA00C8225C /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 30DF7CBB16D39EAA00C8225C /* main.m */; }; - 30DF7CC416D3A12F00C8225C /* installerHelper in Resources */ = {isa = PBXBuildFile; fileRef = 30DF7CB816D39EAA00C8225C /* installerHelper */; }; - 30DF7CD116D3A44000C8225C /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3026F4AE13A203A000F3CA02 /* Security.framework */; }; 30FF413712FAC6CD00F39832 /* GPGController.h in Headers */ = {isa = PBXBuildFile; fileRef = 30FF411D12FAC6CD00F39832 /* GPGController.h */; settings = {ATTRIBUTES = (Public, ); }; }; 30FF413812FAC6CD00F39832 /* GPGController.m in Sources */ = {isa = PBXBuildFile; fileRef = 30FF411E12FAC6CD00F39832 /* GPGController.m */; }; 30FF413B12FAC6CD00F39832 /* GPGGlobals.h in Headers */ = {isa = PBXBuildFile; fileRef = 30FF412112FAC6CD00F39832 /* GPGGlobals.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -135,6 +137,13 @@ remoteGlobalIDString = 8DC2EF4F0486A6940098B216; remoteInfo = Libmacgpg; }; + 30444C471A65E3E30052CB94 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 30444C171A65E0590052CB94; + remoteInfo = installerHelper; + }; 30C412B0149A34D80035D35F /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 30C412A8149A34D80035D35F /* pinentry-mac.xcodeproj */; @@ -156,13 +165,6 @@ remoteGlobalIDString = 8DC2EF4F0486A6940098B216; remoteInfo = Libmacgpg; }; - 30DF7CC516D3A13300C8225C /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 30DF7CB716D39EAA00C8225C; - remoteInfo = installerHelper; - }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -176,15 +178,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 30DF7CB616D39EAA00C8225C /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = /usr/share/man/man1/; - dstSubfolderSpec = 0; - files = ( - ); - runOnlyForDeploymentPostprocessing = 1; - }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ @@ -227,6 +220,13 @@ 301D5D9D178C9871003026E7 /* GPGKeyserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGKeyserver.h; sourceTree = ""; }; 301D5D9E178C9871003026E7 /* GPGKeyserver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGKeyserver.m; sourceTree = ""; }; 3026F4AE13A203A000F3CA02 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; + 30444C181A65E0590052CB94 /* GPGTools.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = GPGTools.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 30444C1C1A65E0590052CB94 /* installerHelper-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "installerHelper-Info.plist"; sourceTree = ""; }; + 30444C331A65E0590052CB94 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; + 30444C3A1A65E0590052CB94 /* installerHelperTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "installerHelperTests-Info.plist"; sourceTree = ""; }; + 30444C3C1A65E0590052CB94 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + 30444C3E1A65E0590052CB94 /* installerHelperTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = installerHelperTests.m; sourceTree = ""; }; + 30444C4E1A65E6F00052CB94 /* gpgtools.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = gpgtools.icns; path = ../../GPGTools_Core/images/gpgtools.icns; sourceTree = ""; }; 304883091462B11700F2E5F4 /* DirectoryWatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DirectoryWatcher.h; sourceTree = ""; }; 3048830A1462B11700F2E5F4 /* DirectoryWatcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DirectoryWatcher.m; sourceTree = ""; }; 3048830D1462B22000F2E5F4 /* GPGWatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGWatcher.h; sourceTree = ""; }; @@ -235,6 +235,7 @@ 3059AF1014239FAB00AD5B30 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; 30691AA2136AECC4004AA469 /* GPGOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGOptions.h; sourceTree = ""; }; 30691AA3136AECC4004AA469 /* GPGOptions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGOptions.m; sourceTree = ""; }; + 3077AE881A6547D2001EC508 /* SecurityFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SecurityFoundation.framework; path = System/Library/Frameworks/SecurityFoundation.framework; sourceTree = SDKROOT; }; 307D79101340B71A005C9C32 /* TODO */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = TODO; sourceTree = ""; }; 309A18CE13E3812E0069DC0F /* GPGTransformer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGTransformer.h; sourceTree = ""; }; 309A18CF13E3812E0069DC0F /* GPGTransformer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGTransformer.m; sourceTree = ""; }; @@ -254,7 +255,6 @@ 30C8B39B1395052D00F49AA1 /* Test1.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Test1.m; sourceTree = ""; }; 30D5E2A21483A0F700F31454 /* GPGConf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = GPGConf.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 30D5E2A31483A0F700F31454 /* GPGConf.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGConf.m; sourceTree = ""; }; - 30DF7CB816D39EAA00C8225C /* installerHelper */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = installerHelper; sourceTree = BUILT_PRODUCTS_DIR; }; 30DF7CBB16D39EAA00C8225C /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 30FF411D12FAC6CD00F39832 /* GPGController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGController.h; sourceTree = ""; }; 30FF411E12FAC6CD00F39832 /* GPGController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGController.m; sourceTree = ""; }; @@ -338,22 +338,23 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 30C8B38B139503A800F49AA1 /* Frameworks */ = { + 30444C151A65E0590052CB94 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 30C8B3B11395072C00F49AA1 /* Libmacgpg.framework in Frameworks */, + 30444C4D1A65E4B50052CB94 /* libcrypto.dylib in Frameworks */, + 30444C4C1A65E4800052CB94 /* libxar.dylib in Frameworks */, + 30444C4B1A65E4790052CB94 /* SecurityFoundation.framework in Frameworks */, + 30444C4A1A65E4740052CB94 /* Security.framework in Frameworks */, + 30444C491A65E46F0052CB94 /* Foundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; - 30DF7CB516D39EAA00C8225C /* Frameworks */ = { + 30C8B38B139503A800F49AA1 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 30DF7CD116D3A44000C8225C /* Security.framework in Frameworks */, - 30DF7CB916D39EAA00C8225C /* Foundation.framework in Frameworks */, - 3002C04616EE389100D57C1E /* libxar.dylib in Frameworks */, - 3002C04416EE388B00D57C1E /* libcrypto.dylib in Frameworks */, + 30C8B3B11395072C00F49AA1 /* Libmacgpg.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -377,8 +378,8 @@ children = ( 8DC2EF5B0486A6940098B216 /* Libmacgpg.framework */, 1B46CFCC161555DF00CF9C5F /* org.gpgtools.Libmacgpg.xpc */, - 30DF7CB816D39EAA00C8225C /* installerHelper */, 1BD78B9F1726B2820005F251 /* LeakFinder.app */, + 30444C181A65E0590052CB94 /* GPGTools.app */, ); name = Products; sourceTree = ""; @@ -394,6 +395,7 @@ 1B46CFCF161555DF00CF9C5F /* org.gpgtools.Libmacgpg.xpc */, 30DF7CBA16D39EAA00C8225C /* installerHelper */, 1BD78BA11726B2830005F251 /* LeakFinder */, + 30444C381A65E0590052CB94 /* installerHelperTests */, 0867D69AFE84028FC02AAC07 /* Frameworks */, 034768DFFF38A50411DB9C8B /* Products */, 30C8B399139504DC00F49AA1 /* UnitTest */, @@ -405,12 +407,14 @@ 0867D69AFE84028FC02AAC07 /* Frameworks */ = { isa = PBXGroup; children = ( + 3077AE881A6547D2001EC508 /* SecurityFoundation.framework */, 1058C7B1FEA5585E11CA2CBB /* Cocoa.framework */, 30BA88F1138FE593005982D9 /* SystemConfiguration.framework */, 3026F4AE13A203A000F3CA02 /* Security.framework */, 3002C04516EE389100D57C1E /* libxar.dylib */, 3002C04316EE388B00D57C1E /* libcrypto.dylib */, 1B3D64DF1565BC6600D93BBE /* Foundation.framework */, + 30444C331A65E0590052CB94 /* XCTest.framework */, 4591C4D214F86D38007F6D47 /* Other Frameworks */, ); path = Frameworks; @@ -558,6 +562,24 @@ name = GPGKey; sourceTree = ""; }; + 30444C381A65E0590052CB94 /* installerHelperTests */ = { + isa = PBXGroup; + children = ( + 30444C3E1A65E0590052CB94 /* installerHelperTests.m */, + 30444C391A65E0590052CB94 /* Supporting Files */, + ); + path = installerHelperTests; + sourceTree = ""; + }; + 30444C391A65E0590052CB94 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 30444C3A1A65E0590052CB94 /* installerHelperTests-Info.plist */, + 30444C3B1A65E0590052CB94 /* InfoPlist.strings */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; 307FAABB13F26BB4003FA99B /* GPGOptions */ = { isa = PBXGroup; children = ( @@ -616,6 +638,8 @@ 30DF7CBA16D39EAA00C8225C /* installerHelper */ = { isa = PBXGroup; children = ( + 30444C4E1A65E6F00052CB94 /* gpgtools.icns */, + 30444C1C1A65E0590052CB94 /* installerHelper-Info.plist */, 30DF7CBB16D39EAA00C8225C /* main.m */, ); path = installerHelper; @@ -740,6 +764,23 @@ productReference = 1BD78B9F1726B2820005F251 /* LeakFinder.app */; productType = "com.apple.product-type.application"; }; + 30444C171A65E0590052CB94 /* installerHelper */ = { + isa = PBXNativeTarget; + buildConfigurationList = 30444C401A65E0590052CB94 /* Build configuration list for PBXNativeTarget "installerHelper" */; + buildPhases = ( + 30444C141A65E0590052CB94 /* Sources */, + 30444C151A65E0590052CB94 /* Frameworks */, + 30444C161A65E0590052CB94 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = installerHelper; + productName = installerHelper; + productReference = 30444C181A65E0590052CB94 /* GPGTools.app */; + productType = "com.apple.product-type.application"; + }; 30C8B38D139503A800F49AA1 /* UnitTest */ = { isa = PBXNativeTarget; buildConfigurationList = 30C8B392139503A900F49AA1 /* Build configuration list for PBXNativeTarget "UnitTest" */; @@ -759,23 +800,6 @@ productReference = 30C8B38E139503A800F49AA1 /* UnitTest.octest */; productType = "com.apple.product-type.bundle"; }; - 30DF7CB716D39EAA00C8225C /* installerHelper */ = { - isa = PBXNativeTarget; - buildConfigurationList = 30DF7CC316D39EAA00C8225C /* Build configuration list for PBXNativeTarget "installerHelper" */; - buildPhases = ( - 30DF7CB416D39EAA00C8225C /* Sources */, - 30DF7CB516D39EAA00C8225C /* Frameworks */, - 30DF7CB616D39EAA00C8225C /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = installerHelper; - productName = installerHelper; - productReference = 30DF7CB816D39EAA00C8225C /* installerHelper */; - productType = "com.apple.product-type.tool"; - }; 8DC2EF4F0486A6940098B216 /* Libmacgpg */ = { isa = PBXNativeTarget; buildConfigurationList = 1DEB91AD08733DA50010E9CD /* Build configuration list for PBXNativeTarget "Libmacgpg" */; @@ -790,8 +814,8 @@ buildRules = ( ); dependencies = ( + 30444C481A65E3E30052CB94 /* PBXTargetDependency */, 30C412B4149A34E80035D35F /* PBXTargetDependency */, - 30DF7CC616D3A13300C8225C /* PBXTargetDependency */, ); name = Libmacgpg; productInstallPath = "$(HOME)/Library/Frameworks"; @@ -818,6 +842,7 @@ German, en, de, + Base, ); mainGroup = 0867D691FE84028FC02AAC07 /* Libmacgpg */; productRefGroup = 034768DFFF38A50411DB9C8B /* Products */; @@ -833,8 +858,8 @@ 8DC2EF4F0486A6940098B216 /* Libmacgpg */, 30C8B38D139503A800F49AA1 /* UnitTest */, 1B46CFCB161555DF00CF9C5F /* org.gpgtools.Libmacgpg.xpc */, - 30DF7CB716D39EAA00C8225C /* installerHelper */, 1BD78B9E1726B2820005F251 /* LeakFinder */, + 30444C171A65E0590052CB94 /* installerHelper */, ); }; /* End PBXProject section */ @@ -860,6 +885,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 30444C161A65E0590052CB94 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 30444C4F1A65E6F00052CB94 /* gpgtools.icns in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 30C8B389139503A800F49AA1 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -875,12 +908,12 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 30444C501A65E83D0052CB94 /* GPGTools.app in Resources */, 30B586F5141E255C000373F1 /* Keyservers.plist in Resources */, 30516558142281270038AAF0 /* Localizable.strings in Resources */, 45C6E82714F8913B00ED67C6 /* pinentry-mac.app in Resources */, 1B46CFA2161531DC00CF9C5F /* org.gpgtools.Libmacgpg.xpc.plist in Resources */, 300DD0FA1853AF300057B05F /* How to get the source code in Resources */, - 30DF7CC416D3A12F00C8225C /* installerHelper in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -991,6 +1024,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 30444C141A65E0590052CB94 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 30444C461A65E3D70052CB94 /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 30C8B38A139503A800F49AA1 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -1009,14 +1050,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 30DF7CB416D39EAA00C8225C /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 30DF7CBC16D39EAA00C8225C /* main.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 8DC2EF540486A6940098B216 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -1065,6 +1098,11 @@ target = 8DC2EF4F0486A6940098B216 /* Libmacgpg */; targetProxy = 1BD78BB81726B5190005F251 /* PBXContainerItemProxy */; }; + 30444C481A65E3E30052CB94 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 30444C171A65E0590052CB94 /* installerHelper */; + targetProxy = 30444C471A65E3E30052CB94 /* PBXContainerItemProxy */; + }; 30C412B4149A34E80035D35F /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = "pinentry-mac"; @@ -1075,11 +1113,6 @@ target = 8DC2EF4F0486A6940098B216 /* Libmacgpg */; targetProxy = 30C8B3931395046400F49AA1 /* PBXContainerItemProxy */; }; - 30DF7CC616D3A13300C8225C /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 30DF7CB716D39EAA00C8225C /* installerHelper */; - targetProxy = 30DF7CC516D3A13300C8225C /* PBXContainerItemProxy */; - }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ @@ -1107,6 +1140,14 @@ name = MainMenu.xib; sourceTree = ""; }; + 30444C3B1A65E0590052CB94 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 30444C3C1A65E0590052CB94 /* en */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; 30516556142281270038AAF0 /* Localizable.strings */ = { isa = PBXVariantGroup; children = ( @@ -1361,6 +1402,72 @@ }; name = Release; }; + 30444C411A65E0590052CB94 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + EXECUTABLE_NAME = installerHelper; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + INFOPLIST_FILE = "installerHelper/installerHelper-Info.plist"; + MACOSX_DEPLOYMENT_TARGET = 10.9; + PRODUCT_NAME = GPGTools; + WRAPPER_EXTENSION = app; + }; + name = Debug; + }; + 30444C421A65E0590052CB94 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + EXECUTABLE_NAME = installerHelper; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + INFOPLIST_FILE = "installerHelper/installerHelper-Info.plist"; + MACOSX_DEPLOYMENT_TARGET = 10.9; + PRODUCT_NAME = GPGTools; + WRAPPER_EXTENSION = app; + }; + name = Release; + }; 30C8B390139503A900F49AA1 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -1423,57 +1530,6 @@ }; name = Release; }; - 30DF7CC116D39EAA00C8225C /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - GCC_DYNAMIC_NO_PIC = NO; - GCC_ENABLE_OBJC_EXCEPTIONS = YES; - GCC_ENABLE_OBJC_GC = unsupported; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_SYMBOLS_PRIVATE_EXTERN = NO; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - INSTALL_PATH = /Library/Frameworks/Libmacgpg.framework/Resources; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 30DF7CC216D39EAA00C8225C /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = YES; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - GCC_ENABLE_OBJC_EXCEPTIONS = YES; - GCC_ENABLE_OBJC_GC = unsupported; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - INSTALL_PATH = /Library/Frameworks/Libmacgpg.framework/Resources; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -1513,20 +1569,19 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 30C8B392139503A900F49AA1 /* Build configuration list for PBXNativeTarget "UnitTest" */ = { + 30444C401A65E0590052CB94 /* Build configuration list for PBXNativeTarget "installerHelper" */ = { isa = XCConfigurationList; buildConfigurations = ( - 30C8B390139503A900F49AA1 /* Debug */, - 30C8B391139503A900F49AA1 /* Release */, + 30444C411A65E0590052CB94 /* Debug */, + 30444C421A65E0590052CB94 /* Release */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; }; - 30DF7CC316D39EAA00C8225C /* Build configuration list for PBXNativeTarget "installerHelper" */ = { + 30C8B392139503A900F49AA1 /* Build configuration list for PBXNativeTarget "UnitTest" */ = { isa = XCConfigurationList; buildConfigurations = ( - 30DF7CC116D39EAA00C8225C /* Debug */, - 30DF7CC216D39EAA00C8225C /* Release */, + 30C8B390139503A900F49AA1 /* Debug */, + 30C8B391139503A900F49AA1 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; diff --git a/Libmacgpg.xcodeproj/xcshareddata/xcschemes/Libmacgpg + XPC.xcscheme b/Libmacgpg.xcodeproj/xcshareddata/xcschemes/Libmacgpg + XPC.xcscheme index 35138e6..b08a878 100644 --- a/Libmacgpg.xcodeproj/xcshareddata/xcschemes/Libmacgpg + XPC.xcscheme +++ b/Libmacgpg.xcodeproj/xcshareddata/xcschemes/Libmacgpg + XPC.xcscheme @@ -10,7 +10,7 @@ ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction"> + scriptText = "mkdir -p "$SOURCE_ROOT/build/$CONFIGURATION" if [ ! -z "$(ls "$BUILT_PRODUCTS_DIR" 2>/dev/null)" ]; then cp -R "$BUILT_PRODUCTS_DIR/"* "$SOURCE_ROOT/build/$CONFIGURATION/" cp -R "$BUILD_ROOT/org.gpgtools.Libmacgpg.xpc.plist" "$SOURCE_ROOT/build/" fi "> diff --git a/installerHelper/installerHelper-Info.plist b/installerHelper/installerHelper-Info.plist new file mode 100644 index 0000000..b9c5ac2 --- /dev/null +++ b/installerHelper/installerHelper-Info.plist @@ -0,0 +1,30 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + gpgtools.icns + CFBundleIdentifier + org.gpgtools.installerHelper + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSMinimumSystemVersion + ${MACOSX_DEPLOYMENT_TARGET} + LSUIElement + + + diff --git a/installerHelper/main.m b/installerHelper/main.m index 3feae02..4402ed4 100644 --- a/installerHelper/main.m +++ b/installerHelper/main.m @@ -1,17 +1,30 @@ #import #import +#import #import #import +BOOL isBundleValidSigned(NSBundle *bundle); BOOL checkPackage(NSString *pkgPath); +BOOL installerCertificateIsTrustworthy(NSString *pkgPath); BOOL installPackage(NSString *pkgPath, NSString *xmlPath); +BOOL executeWithPrivilegesAndWait(NSString *executable, NSArray *arguments); const char *helpText = "This tool checks the signature of a pkg-file and installs it.\nYou can provide a pkg-file.xml to override the standard choices."; -int main(int argc, const char *argv[]) { +int main(int argc, char *argv[]) { @autoreleasepool { +#ifdef CODE_SIGN_CHECK + /* Check the validity of the code signature. */ + if (!isBundleValidSigned([NSBundle mainBundle])) { + printf("installerHelper isn't signed correctly!\n"); + return 66; + } +#endif + + if (argc != 2) { printf("Usage: installerHelper pkg-file\n%s\n", helpText); return 1; @@ -50,13 +63,30 @@ int main(int argc, const char *argv[]) { return 0; } +BOOL isBundleValidSigned(NSBundle *bundle) { + SecRequirementRef requirement = nil; + SecStaticCodeRef staticCode = nil; + + SecStaticCodeCreateWithPath((__bridge CFURLRef)[bundle bundleURL], 0, &staticCode); + SecRequirementCreateWithString(CFSTR("anchor apple generic and cert leaf = H\"233B4E43187B51BF7D6711053DD652DDF54B43BE\""), 0, &requirement); + + OSStatus result = SecStaticCodeCheckValidity(staticCode, 0, requirement); + + if (staticCode) CFRelease(staticCode); + if (requirement) CFRelease(requirement); + return result == noErr; +} + + + + + BOOL installerCertificateIsTrustworthy(NSString *pkgPath) { OSStatus error = noErr; NSMutableArray *certificates = nil; SecPolicyRef policy = NULL; SecTrustRef trust = NULL; SecTrustResultType trustResult; - CSSM_OID oid = CSSMOID_APPLE_X509_BASIC; xar_t pkg = NULL; xar_signature_t signature = NULL; @@ -261,40 +291,64 @@ BOOL checkPackage(NSString *pkgPath) { BOOL installPackage(NSString *pkgPath, NSString *xmlPath) { // Run the installer command. - NSArray *arguments; if (xmlPath) { arguments = @[@"-applyChoiceChangesXML", xmlPath, @"-pkg", pkgPath, @"-target", @"/"]; } else { arguments = @[@"-pkg", pkgPath, @"-target", @"/"]; } - - NSTask *task = [[NSTask alloc] init]; - task.launchPath = @"/usr/sbin/installer"; - task.arguments = arguments; + BOOL result = executeWithPrivilegesAndWait(@"/usr/sbin/installer", arguments); - uid_t uid = getuid(); - int result = setuid(0); - if (result == 0) { - //Run only this command with root privileges. - [task launch]; - [task waitUntilExit]; - result = task.terminationStatus; - setuid(uid); - } else { - printf("This tool needs the setuid-bit to be set and the owner must be root!\nStarting a normal installation using the GUI.\n"); - - task.launchPath = @"/usr/bin/open"; - task.arguments = @[@"-Wnb", @"com.apple.installer", pkgPath]; + return result; +} - [task launch]; - [task waitUntilExit]; - result = task.terminationStatus; + + +BOOL executeWithPrivilegesAndWait(NSString *executable, NSArray *arguments) { + const char *path = executable.UTF8String; + + NSUInteger i = 0; + NSUInteger count = arguments.count; + const char *args[count + 1]; + + for (; i < count; i++) { + args[i] = [[arguments objectAtIndex:i] UTF8String]; } + args[i] = nil; - return result == 0; + AuthorizationItem items[1]; + items[0].name = kAuthorizationRightExecute; + items[0].value = (void *)path; + items[0].valueLength = strlen(path); + items[0].flags = 0; + + AuthorizationRights rights; + rights.count = 1; + rights.items = items; + + SFAuthorization *sfAuth = [SFAuthorization authorizationWithFlags:kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights + rights:&rights + environment:nil]; + AuthorizationRef authRef = [sfAuth authorizationRef]; + + if(authRef) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + OSStatus result = AuthorizationExecuteWithPrivileges(authRef, path, 0, (char* const*)args, nil); +#pragma clang diagnostic pop + + if (result == errAuthorizationSuccess) { + int status; + pid_t pid = wait(&status); + if (pid != -1 && WIFEXITED(status) && WEXITSTATUS(status) == 0) { + return YES; + } + } + } + + return NO; } @@ -303,6 +357,3 @@ BOOL installPackage(NSString *pkgPath, NSString *xmlPath) { - - - From e0b45a42fb9f2a82705917244dd477c5b1567e18 Mon Sep 17 00:00:00 2001 From: Mento Date: Wed, 14 Jan 2015 01:39:47 +0100 Subject: [PATCH 02/56] Symlink for installerHelper --- Libmacgpg.xcodeproj/project.pbxproj | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Libmacgpg.xcodeproj/project.pbxproj b/Libmacgpg.xcodeproj/project.pbxproj index b595ed5..f673555 100644 --- a/Libmacgpg.xcodeproj/project.pbxproj +++ b/Libmacgpg.xcodeproj/project.pbxproj @@ -806,6 +806,7 @@ buildPhases = ( 8DC2EF500486A6940098B216 /* Headers */, 8DC2EF520486A6940098B216 /* Resources */, + 30444C531A65F0080052CB94 /* Create installerHelper symlink */, 8DC2EF540486A6940098B216 /* Sources */, 8DC2EF560486A6940098B216 /* Frameworks */, 30C2960E16775037006EF09C /* Fill Info.plist */, @@ -933,6 +934,7 @@ runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "[[ \"$CONFIGURATION\" == \"Debug\" ]] || exit 0\nUSER_LIBRARY=\"$HOME/Library\"\nmkdir -p \"$USER_LIBRARY/Application Support/GPGTools\"\ncp -R \"${BUILT_PRODUCTS_DIR}/org.gpgtools.Libmacgpg.xpc\" \"$USER_LIBRARY/Application Support/GPGTools\"\n# Reload the launchd.plist\nif [ -f \"/Library/LaunchAgents/org.gpgtools.Libmacgpg.xpc.plist\" ]; then\n launchctl unload /Library/LaunchAgents/org.gpgtools.Libmacgpg.xpc.plist\nfi\nif [ -f \"$USER_LIBRARY/LaunchAgents/org.gpgtools.Libmacgpg.xpc.plist\" ]; then\n launchctl unload \"$USER_LIBRARY/LaunchAgents/org.gpgtools.Libmacgpg.xpc.plist\"\n sleep 3\n launchctl load \"$USER_LIBRARY/LaunchAgents/org.gpgtools.Libmacgpg.xpc.plist\"\nfi"; + showEnvVarsInLog = 0; }; 1B483E061619E69900D692EB /* Prepare XPC Launchd.plist for the Packager */ = { isa = PBXShellScriptBuildPhase; @@ -947,6 +949,7 @@ runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "JAILFREE_PLIST=\"${EXECUTABLE_NAME}.plist\"\nBUILD_LAUNCHAGENT_PATH=\"${BUILD_DIR}/${JAILFREE_PLIST}\"\nINSTALL_JAILFREE_PATH=\"/Library/Application\\ Support/GPGTools/${EXECUTABLE_NAME}\"\nJAILFREE_PATH=\"${BUILT_PRODUCTS_DIR}/${EXECUTABLE_NAME}\"\n\nXPC_NAME=$(\n for x in $GCC_PREPROCESSOR_DEFINITIONS_NOT_USED_IN_PRECOMPS; do\n echo $x | while IFS=\"=\" read name value; do\n if [ \"$name\" == \"JAILFREE_XPC_NAME\" ]; then\n echo $value | sed \"s/\\\"//g\" | sed \"s/@//g\"\n break\n fi\n done\n done\n)\ncp \"${PROJECT_DIR}/Source/${EXECUTABLE_NAME}/${JAILFREE_PLIST}\" \"${BUILD_LAUNCHAGENT_PATH}\"\n/usr/libexec/PlistBuddy -c \"Delete :MachServices\" \"${BUILD_LAUNCHAGENT_PATH}\"\n/usr/libexec/PlistBuddy -c \"Add :MachServices:$XPC_NAME bool true\" \"${BUILD_LAUNCHAGENT_PATH}\"\n/usr/libexec/PlistBuddy -c \"Set :ProgramArguments:0 \\\"${INSTALL_JAILFREE_PATH}\\\"\" \"${BUILD_LAUNCHAGENT_PATH}\""; + showEnvVarsInLog = 0; }; 1BC07F34174660F3004263BB /* Link Libmacgpg into ~/Library/Frameworks */ = { isa = PBXShellScriptBuildPhase; @@ -961,6 +964,7 @@ runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "[[ \"$CONFIGURATION\" == \"Debug\" ]] || exit 0\n# Copy the Framework into ~/Library for testing with other libs.\nFRAMEWORKS_DIR=\"$HOME/Library/Frameworks\"\nFRAMEWORK_NAME=\"Libmacgpg.framework\"\n\n# ~/Library/Frameworks doesn't exist in most cases, create it.\nif [ ! -d \"$FRAMEWORKS_DIR\" ]; then\n mkdir -p \"$FRAMEWORKS_DIR\"\nfi\n\nln -Fs \"$BUILT_PRODUCTS_DIR/$FRAMEWORK_NAME\" \"$FRAMEWORKS_DIR/\"\n"; + showEnvVarsInLog = 0; }; 1BCE0CCB16176C920026DCFF /* Install XPC Launchd and Insert Mach Name */ = { isa = PBXShellScriptBuildPhase; @@ -975,6 +979,22 @@ runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "[[ \"$CONFIGURATION\" == \"Debug\" ]] || exit 0\nUSER_LIBRARY=\"$HOME/Library\"\nJAILFREE_PLIST=\"${EXECUTABLE_NAME}.plist\"\nLAUNCHAGENT_PATH=\"${USER_LIBRARY}/LaunchAgents/${JAILFREE_PLIST}\"\nJAILFREE_PATH=\"${BUILT_PRODUCTS_DIR}/${EXECUTABLE_NAME}\"\nBUILD_LAUNCHAGENT_PATH=\"${BUILD_DIR}/${JAILFREE_PLIST}\"\n\nif [ -d \"${USER_LIBRARY}/LaunchAgents\" ] && [ -w \"${USER_LIBRARY}/LaunchAgents\" ] && [ -x \"${USER_LIBRARY}/LaunchAgents\" ]; then\n cp \"${BUILD_LAUNCHAGENT_PATH}\" \"${LAUNCHAGENT_PATH}\"\n /usr/libexec/PlistBuddy -c \"Set :ProgramArguments:0 \\\"${JAILFREE_PATH}\\\"\" \"${LAUNCHAGENT_PATH}\"\nfi"; + showEnvVarsInLog = 0; + }; + 30444C531A65F0080052CB94 /* Create installerHelper symlink */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Create installerHelper symlink"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "ln -fs GPGTools.app/Contents/MacOS/installerHelper \"$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME/Resources/\""; + showEnvVarsInLog = 0; }; 30C2960E16775037006EF09C /* Fill Info.plist */ = { isa = PBXShellScriptBuildPhase; @@ -989,6 +1009,7 @@ runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "source \"$SRCROOT/Makefile.config\" || exit 1\n\nPLIST=\"$BUILT_PRODUCTS_DIR/$INFOPLIST_PATH\"\n\n/usr/libexec/PlistBuddy -c \"Set CommitHash \\\"$commitHash\\\"\" -c \"Set BuildNumber \\\"$buildNumber\\\"\" -c \"Set CFBundleVersion \\\"$build_version\\\"\" -c \"Set CFBundleShortVersionString \\\"$version\\\"\" \"$PLIST\" || exit 2\n"; + showEnvVarsInLog = 0; }; 30C8B38C139503A800F49AA1 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; From 69e895742677801a187635191f171ba3e189e6c0 Mon Sep 17 00:00:00 2001 From: Mento Date: Wed, 11 Mar 2015 16:43:13 +0100 Subject: [PATCH 03/56] XPC_INSTALLATION_DIR for Release. --- Libmacgpg.xcodeproj/project.pbxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libmacgpg.xcodeproj/project.pbxproj b/Libmacgpg.xcodeproj/project.pbxproj index 9204113..9c26000 100644 --- a/Libmacgpg.xcodeproj/project.pbxproj +++ b/Libmacgpg.xcodeproj/project.pbxproj @@ -870,7 +870,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "JAILFREE_PLIST=\"${EXECUTABLE_NAME}.plist\"\nBUILD_LAUNCHAGENT_PATH=\"${BUILD_DIR}/${JAILFREE_PLIST}\"\nif [[ -z \"${XPC_INSTALLATION_DIR}\" ]]; then\n XPC_INSTALLATION_DIR=\"/Library/Application\\ Support/GPGTools\"\nfi\nXPC_INSTALLATION_PATH=\"${XPC_INSTALLATION_DIR}/${EXECUTABLE_NAME}\"\n\nXPC_NAME=$(\n for x in $GCC_PREPROCESSOR_DEFINITIONS_NOT_USED_IN_PRECOMPS; do\n echo $x | while IFS=\"=\" read name value; do\n if [ \"$name\" == \"JAILFREE_XPC_NAME\" ]; then\n echo $value | sed \"s/\\\"//g\" | sed \"s/@//g\"\n break\n fi\n done\n done\n)\ncp \"${PROJECT_DIR}/Source/${EXECUTABLE_NAME}/${JAILFREE_PLIST}\" \"${BUILD_LAUNCHAGENT_PATH}\"\n/usr/libexec/PlistBuddy -c \"Delete :MachServices\" \"${BUILD_LAUNCHAGENT_PATH}\"\n/usr/libexec/PlistBuddy -c \"Add :MachServices:$XPC_NAME bool true\" \"${BUILD_LAUNCHAGENT_PATH}\"\n/usr/libexec/PlistBuddy -c \"Set :ProgramArguments:0 \\\"${XPC_INSTALLATION_PATH}\\\"\" \"${BUILD_LAUNCHAGENT_PATH}\""; + shellScript = "JAILFREE_PLIST=\"${EXECUTABLE_NAME}.plist\"\nBUILD_LAUNCHAGENT_PATH=\"${BUILD_DIR}/${JAILFREE_PLIST}\"\nif [[ -z \"${XPC_INSTALLATION_DIR}\" || \"CONFIGURATION\" != \"Debug\" ]]; then\n XPC_INSTALLATION_DIR=\"/Library/Application\\ Support/GPGTools\"\nfi\nXPC_INSTALLATION_PATH=\"${XPC_INSTALLATION_DIR}/${EXECUTABLE_NAME}\"\n\nXPC_NAME=$(\n for x in $GCC_PREPROCESSOR_DEFINITIONS_NOT_USED_IN_PRECOMPS; do\n echo $x | while IFS=\"=\" read name value; do\n if [ \"$name\" == \"JAILFREE_XPC_NAME\" ]; then\n echo $value | sed \"s/\\\"//g\" | sed \"s/@//g\"\n break\n fi\n done\n done\n)\ncp \"${PROJECT_DIR}/Source/${EXECUTABLE_NAME}/${JAILFREE_PLIST}\" \"${BUILD_LAUNCHAGENT_PATH}\"\n/usr/libexec/PlistBuddy -c \"Delete :MachServices\" \"${BUILD_LAUNCHAGENT_PATH}\"\n/usr/libexec/PlistBuddy -c \"Add :MachServices:$XPC_NAME bool true\" \"${BUILD_LAUNCHAGENT_PATH}\"\n/usr/libexec/PlistBuddy -c \"Set :ProgramArguments:0 \\\"${XPC_INSTALLATION_PATH}\\\"\" \"${BUILD_LAUNCHAGENT_PATH}\""; showEnvVarsInLog = 0; }; 1B49BC6B1A97A8D6000440E9 /* Copy "How to get the source code" into Resources */ = { From 60309de1862016fb61e734bb89acd852b81a3e18 Mon Sep 17 00:00:00 2001 From: Mento Date: Sat, 28 Mar 2015 12:32:08 +0100 Subject: [PATCH 04/56] Get fingerprints from weak keys. --- Source/GPGController.m | 1 + Source/GPGKeyManager.m | 2 ++ 2 files changed, 3 insertions(+) diff --git a/Source/GPGController.m b/Source/GPGController.m index 700ff88..6d3659b 100644 --- a/Source/GPGController.m +++ b/Source/GPGController.m @@ -2256,6 +2256,7 @@ - (NSInteger)indexOfSubkey:(NSObject *)subkey fromKey:(NSObject self.gpgTask = [GPGTask gpgTask]; [self addArgumentsForOptions]; [gpgTask addArgument:@"-k"]; + [gpgTask addArgument:@"--allow-weak-digest-algos"]; [gpgTask addArgument:@"--with-fingerprint"]; [gpgTask addArgument:@"--with-fingerprint"]; [gpgTask addArgument:[key description]]; diff --git a/Source/GPGKeyManager.m b/Source/GPGKeyManager.m index 90e5261..1e1f50a 100644 --- a/Source/GPGKeyManager.m +++ b/Source/GPGKeyManager.m @@ -42,6 +42,7 @@ - (void)_loadKeys:(NSSet *)keys fetchSignatures:(BOOL)fetchSignatures fetchUserA // Get all fingerprints of the secret keys. GPGTask *gpgTask = [GPGTask gpgTask]; gpgTask.batchMode = YES; + [gpgTask addArgument:@"--allow-weak-digest-algos"]; [gpgTask addArgument:@"--list-secret-keys"]; [gpgTask addArgument:@"--with-fingerprint"]; [gpgTask addArgument:@"--with-fingerprint"]; @@ -71,6 +72,7 @@ - (void)_loadKeys:(NSSet *)keys fetchSignatures:(BOOL)fetchSignatures fetchUserA gpgTask.getAttributeData = YES; gpgTask.delegate = self; } + [gpgTask addArgument:@"--allow-weak-digest-algos"]; [gpgTask addArgument:@"--with-fingerprint"]; [gpgTask addArgument:@"--with-fingerprint"]; [gpgTask addArguments:keyArguments]; From 722b5aa072e9fbb1eb7e48aeacf44a4e9ae15263 Mon Sep 17 00:00:00 2001 From: Mento Date: Wed, 1 Apr 2015 12:26:35 +0200 Subject: [PATCH 05/56] [NEW] GPGUserIDSignature hashAlgorithm. --- Source/GPGKeyManager.m | 1 + Source/GPGTransformer.h | 9 +++++++++ Source/GPGTransformer.m | 34 ++++++++++++++++++++++++++++++++++ Source/GPGTypesRW.h | 1 + Source/GPGUserIDSignature.h | 2 ++ Source/GPGUserIDSignature.m | 4 +++- 6 files changed, 50 insertions(+), 1 deletion(-) diff --git a/Source/GPGKeyManager.m b/Source/GPGKeyManager.m index 1e1f50a..aa74b9e 100644 --- a/Source/GPGKeyManager.m +++ b/Source/GPGKeyManager.m @@ -416,6 +416,7 @@ - (void)fillKey:(GPGKey *)primaryKey withRange:(NSRange)lineRange { signature.signatureClass = hexToByte([field UTF8String]); signature.local = [field hasSuffix:@"l"]; + signature.hashAlgorithm = [[parts objectAtIndex:15] intValue]; [signatures addObject:signature]; diff --git a/Source/GPGTransformer.h b/Source/GPGTransformer.h index 78983e7..abab013 100644 --- a/Source/GPGTransformer.h +++ b/Source/GPGTransformer.h @@ -29,6 +29,15 @@ - (id)transformedIntegerValue:(NSInteger)value; @end +@interface GPGHashAlgorithmNameTransformer : NSValueTransformer { + BOOL _keepUnlocalized; // default NO; used for Unit Testing +} +// default NO +@property (nonatomic, assign) BOOL keepUnlocalized; + +- (id)transformedIntegerValue:(NSInteger)value; +@end + @interface GPGValidityDescriptionTransformer : NSValueTransformer { BOOL _keepUnlocalized; // default NO; used for Unit Testing } diff --git a/Source/GPGTransformer.m b/Source/GPGTransformer.m index b5ac2ae..520dc9d 100644 --- a/Source/GPGTransformer.m +++ b/Source/GPGTransformer.m @@ -59,6 +59,40 @@ - (id)transformedIntegerValue:(NSInteger)value { @end +@implementation GPGHashAlgorithmNameTransformer +@synthesize keepUnlocalized = _keepUnlocalized; + ++ (Class)transformedValueClass { return [NSString class]; } ++ (BOOL)allowsReverseTransformation { return NO; } +- (id)transformedValue:(id)value { + return [self transformedIntegerValue:[value integerValue]]; +} + +- (id)transformedIntegerValue:(NSInteger)value { + switch (value) { + case GPGHashAlgorithmMD5: + return maybeLocalize(@"DIGEST_ALGO_MD5"); + case GPGHashAlgorithmSHA1: + return maybeLocalize(@"DIGEST_ALGO_SHA1"); + case GPGHashAlgorithmRMD160: + return maybeLocalize(@"DIGEST_ALGO_RMD160"); + case GPGHashAlgorithmSHA256: + return maybeLocalize(@"DIGEST_ALGO_SHA256"); + case GPGHashAlgorithmSHA384: + return maybeLocalize(@"DIGEST_ALGO_SHA384"); + case GPGHashAlgorithmSHA512: + return maybeLocalize(@"DIGEST_ALGO_SHA512"); + case GPGHashAlgorithmSHA224: + return maybeLocalize(@"DIGEST_ALGO_SHA224"); + case 0: + return @""; + default: + return [NSString stringWithFormat:maybeLocalize(@"Algorithm_%i"), value]; + } +} + +@end + @implementation GPGValidityDescriptionTransformer @synthesize keepUnlocalized = _keepUnlocalized; diff --git a/Source/GPGTypesRW.h b/Source/GPGTypesRW.h index 581d431..d578208 100644 --- a/Source/GPGTypesRW.h +++ b/Source/GPGTypesRW.h @@ -92,6 +92,7 @@ @property (assign, readwrite) int signatureClass; @property (assign, readwrite) BOOL revocation; @property (assign, readwrite) BOOL local; +@property (assign, readwrite) GPGHashAlgorithm hashAlgorithm; @property (assign, readwrite) GPGKey *primaryKey; diff --git a/Source/GPGUserIDSignature.h b/Source/GPGUserIDSignature.h index f9bb53e..f89193a 100644 --- a/Source/GPGUserIDSignature.h +++ b/Source/GPGUserIDSignature.h @@ -26,6 +26,7 @@ @interface GPGUserIDSignature : NSObject { NSString *_keyID; GPGPublicKeyAlgorithm _algorithm; + GPGHashAlgorithm _hashAlgorithm; NSDate *_creationDate; NSDate *_expirationDate; NSString *_reason; @@ -41,6 +42,7 @@ @property (nonatomic, readonly) NSString *keyID; @property (nonatomic, readonly) GPGPublicKeyAlgorithm algorithm; +@property (nonatomic, readonly) GPGHashAlgorithm hashAlgorithm; @property (nonatomic, readonly) NSDate *creationDate; @property (nonatomic, readonly) NSDate *expirationDate; @property (nonatomic, readonly) NSString *reason; diff --git a/Source/GPGUserIDSignature.m b/Source/GPGUserIDSignature.m index f9e75e0..3a33d61 100644 --- a/Source/GPGUserIDSignature.m +++ b/Source/GPGUserIDSignature.m @@ -22,7 +22,9 @@ @implementation GPGUserIDSignature -@synthesize keyID=_keyID, algorithm=_algorithm, creationDate=_creationDate, expirationDate=_expirationDate, reason=_reason, signatureClass=_signatureClass, revocation=_revocation, local=_local, primaryKey=_primaryKey; +@synthesize keyID=_keyID, algorithm=_algorithm, creationDate=_creationDate, expirationDate=_expirationDate, +reason=_reason, signatureClass=_signatureClass, revocation=_revocation, local=_local, primaryKey=_primaryKey, +hashAlgorithm=_hashAlgorithm; - (instancetype)init { return [self initWithKeyID:nil]; From ae6823456d8da02798a9808b0f5276f4be2e7c72 Mon Sep 17 00:00:00 2001 From: Mento Date: Wed, 1 Apr 2015 12:46:39 +0200 Subject: [PATCH 06/56] GPGKeyManager allowWeakDigestAlgos. --- Source/GPGKeyManager.h | 5 ++++- Source/GPGKeyManager.m | 12 +++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Source/GPGKeyManager.h b/Source/GPGKeyManager.h index 89f93b9..eb54c5b 100644 --- a/Source/GPGKeyManager.h +++ b/Source/GPGKeyManager.h @@ -29,10 +29,13 @@ NSUInteger _attributeDataLocation; BOOL _fetchUserAttributes; BOOL _fetchSignatures; - + BOOL _allowWeakDigestAlgos; + dispatch_semaphore_t _allKeysAndSubkeysOnce; } +@property (nonatomic) BOOL allowWeakDigestAlgos; + @property (nonatomic, readonly) NSSet *allKeys; @property (nonatomic, readonly) NSSet *allKeysAndSubkeys; @property (nonatomic, readonly) NSDictionary *keysByKeyID; diff --git a/Source/GPGKeyManager.m b/Source/GPGKeyManager.m index aa74b9e..c1060e4 100644 --- a/Source/GPGKeyManager.m +++ b/Source/GPGKeyManager.m @@ -15,7 +15,9 @@ @interface GPGKeyManager () @implementation GPGKeyManager -@synthesize allKeys=_allKeys, keysByKeyID=_keysByKeyID, secretKeys=_secretKeys, completionQueue=_completionQueue; +@synthesize allKeys=_allKeys, keysByKeyID=_keysByKeyID, + secretKeys=_secretKeys, completionQueue=_completionQueue, + allowWeakDigestAlgos=_allowWeakDigestAlgos; - (void)loadAllKeys { [self loadKeys:nil fetchSignatures:NO fetchUserAttributes:NO]; @@ -42,7 +44,9 @@ - (void)_loadKeys:(NSSet *)keys fetchSignatures:(BOOL)fetchSignatures fetchUserA // Get all fingerprints of the secret keys. GPGTask *gpgTask = [GPGTask gpgTask]; gpgTask.batchMode = YES; - [gpgTask addArgument:@"--allow-weak-digest-algos"]; + if (self.allowWeakDigestAlgos) { + [gpgTask addArgument:@"--allow-weak-digest-algos"]; + } [gpgTask addArgument:@"--list-secret-keys"]; [gpgTask addArgument:@"--with-fingerprint"]; [gpgTask addArgument:@"--with-fingerprint"]; @@ -72,7 +76,9 @@ - (void)_loadKeys:(NSSet *)keys fetchSignatures:(BOOL)fetchSignatures fetchUserA gpgTask.getAttributeData = YES; gpgTask.delegate = self; } - [gpgTask addArgument:@"--allow-weak-digest-algos"]; + if (self.allowWeakDigestAlgos) { + [gpgTask addArgument:@"--allow-weak-digest-algos"]; + } [gpgTask addArgument:@"--with-fingerprint"]; [gpgTask addArgument:@"--with-fingerprint"]; [gpgTask addArguments:keyArguments]; From 4b9285685ad8de2464827485047130392b597b1c Mon Sep 17 00:00:00 2001 From: Mento Date: Wed, 1 Apr 2015 14:05:04 +0200 Subject: [PATCH 07/56] Use KeyID if the fingerprint is nulled. [#140 state:fixed assigned:mento] --- Source/GPGKeyManager.m | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/GPGKeyManager.m b/Source/GPGKeyManager.m index c1060e4..39ee612 100644 --- a/Source/GPGKeyManager.m +++ b/Source/GPGKeyManager.m @@ -395,6 +395,10 @@ - (void)fillKey:(GPGKey *)primaryKey withRange:(NSRange)lineRange { } else if ([type isEqualToString:@"fpr"]) { // Fingerprint. NSString *fingerprint = [parts objectAtIndex:9]; + if ([fingerprint isEqualToString:@"00000000000000000000000000000000"]) { + fingerprint = primaryKey.keyID; + } + key.fingerprint = fingerprint; NSDictionary *secKeyInfo = [_secKeyInfos objectForKey:fingerprint]; From 92e4934270475e43dacd2a47a01ea67afb636c54 Mon Sep 17 00:00:00 2001 From: Mento Date: Wed, 1 Apr 2015 17:55:35 +0200 Subject: [PATCH 08/56] Call pinentryPath in GPGTask -start. --- Source/GPGController.m | 6 ------ Source/GPGTask.m | 4 +++- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/Source/GPGController.m b/Source/GPGController.m index 6d3659b..3a7a21f 100644 --- a/Source/GPGController.m +++ b/Source/GPGController.m @@ -249,12 +249,6 @@ - (id)init { return self; } -+ (void)initialize { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - [GPGTaskHelper pinentryPath]; - [pool release]; -} - - (void)cancel { canceled = YES; diff --git a/Source/GPGTask.m b/Source/GPGTask.m index 4eef876..7f7e108 100644 --- a/Source/GPGTask.m +++ b/Source/GPGTask.m @@ -291,8 +291,10 @@ - (void)addArguments:(NSArray *)args { - (NSInteger)start { isRunning = YES; - // Default arguments which every call to GPG needs. + // Force a valid pinentry to be set in gpg-agent.conf + [GPGTaskHelper pinentryPath]; + // Default arguments which every call to GPG needs. NSMutableArray *defaultArguments = [NSMutableArray arrayWithObjects: @"--no-greeting", @"--no-tty", @"--with-colons", @"--fixed-list-mode", @"--utf8-strings", @"--display-charset", @"utf-8", @"--enable-special-filenames", From 91651388801eb8f11b8d7493d3dddc5d52f52f5f Mon Sep 17 00:00:00 2001 From: Lukas Pitschl Date: Thu, 23 Apr 2015 01:53:01 +0200 Subject: [PATCH 09/56] [FIX] Don't reference self directly within hasCompleted check [#142 state:fixed] - Using self creates a retain cycle which causes the LPXTTask to never be dealloced - Use __block to break the retain cycle. --- Source/LPXTTask.m | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Source/LPXTTask.m b/Source/LPXTTask.m index 2d0a468..d313181 100644 --- a/Source/LPXTTask.m +++ b/Source/LPXTTask.m @@ -385,8 +385,9 @@ - (void)setCompleted:(BOOL)hasCompleted { completed = YES; return; } + __block LPXTTask *weakSelf = self; dispatch_async(hasCompletedQueue, ^{ - completed = YES; + weakSelf->completed = YES; }); } @@ -395,8 +396,9 @@ - (BOOL)completed { if(hasCompletedQueue == NULL) { return YES; } + __block LPXTTask *weakSelf = self; dispatch_sync(hasCompletedQueue, ^{ - hasCompleted = completed; + hasCompleted = weakSelf->completed; }); return hasCompleted; } From 119f140eaf2fb462102200357f99ced356b568e4 Mon Sep 17 00:00:00 2001 From: Mento Date: Mon, 27 Apr 2015 16:45:39 +0200 Subject: [PATCH 10/56] retainArguments after setTarget. --- Source/GPGGlobals.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/GPGGlobals.m b/Source/GPGGlobals.m index fc28901..8d183a4 100644 --- a/Source/GPGGlobals.m +++ b/Source/GPGGlobals.m @@ -483,8 +483,8 @@ - (void)invokeWithPool:(NSInvocation *)anInvocation { [pool drain]; } - (void)forwardInvocation:(NSInvocation *)anInvocation { - [anInvocation retainArguments]; [anInvocation setTarget:realObject]; + [anInvocation retainArguments]; [NSThread detachNewThreadSelector:@selector(invokeWithPool:) toTarget:self withObject:anInvocation]; } + (id)proxyWithRealObject:(NSObject *)object { From bd1db9cb785a970a241aca477cef2a63504221ed Mon Sep 17 00:00:00 2001 From: Mento Date: Mon, 27 Apr 2015 16:47:46 +0200 Subject: [PATCH 11/56] retain autorelease for _allKeysAndSubkeys. --- Source/GPGKeyManager.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/GPGKeyManager.m b/Source/GPGKeyManager.m index 39ee612..69313e9 100644 --- a/Source/GPGKeyManager.m +++ b/Source/GPGKeyManager.m @@ -510,7 +510,7 @@ - (NSSet *)allKeysAndSubkeys { dispatch_semaphore_signal(_allKeysAndSubkeysOnce); - return _allKeysAndSubkeys; + return [[_allKeysAndSubkeys retain] autorelease]; } - (NSSet *)secretKeys { From 636e7b414dce0c9f58ff30f5a830880f7040aae8 Mon Sep 17 00:00:00 2001 From: Mento Date: Tue, 28 Apr 2015 12:14:36 +0200 Subject: [PATCH 12/56] Fill keys synchronous. --- Source/GPGKeyManager.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/GPGKeyManager.m b/Source/GPGKeyManager.m index 69313e9..4237817 100644 --- a/Source/GPGKeyManager.m +++ b/Source/GPGKeyManager.m @@ -112,9 +112,9 @@ - (void)_loadKeys:(NSSet *)keys fetchSignatures:(BOOL)fetchSignatures fetchUserA [newKeys addObject:key]; [key release]; - dispatch_group_async(dispatchGroup, dispatchQueue, ^{ + @autoreleasepool { [self fillKey:key withRange:NSMakeRange(index, lastLine - index)]; - }); + } lastLine = index; } From 67c90665bc423e8901f9db1701d1abe12bf55bd3 Mon Sep 17 00:00:00 2001 From: Mento Date: Wed, 29 Apr 2015 16:00:33 +0200 Subject: [PATCH 13/56] Use a script instead of a symlink. --- Libmacgpg.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Libmacgpg.xcodeproj/project.pbxproj b/Libmacgpg.xcodeproj/project.pbxproj index 188a494..eaf9781 100644 --- a/Libmacgpg.xcodeproj/project.pbxproj +++ b/Libmacgpg.xcodeproj/project.pbxproj @@ -790,7 +790,6 @@ buildRules = ( ); dependencies = ( - 30DF7CC616D3A13300C8225C /* PBXTargetDependency */, 30444C481A65E3E30052CB94 /* PBXTargetDependency */, ); name = Libmacgpg; @@ -965,7 +964,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "ln -fs GPGTools.app/Contents/MacOS/installerHelper \"$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME/Resources/\""; + shellScript = "echo -e '#!/bin/bash'\"\\n\"'\"$(dirname \"$0\")/GPGTools.app/Contents/MacOS/installerHelper\" \"$@\"' > \"$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME/Resources/installerHelper\"\nchmod +x \"$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME/Resources/installerHelper\"\n"; showEnvVarsInLog = 0; }; 30C2960E16775037006EF09C /* Fill Info.plist */ = { @@ -1567,6 +1566,7 @@ 30444C421A65E0590052CB94 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; 30C8B392139503A900F49AA1 /* Build configuration list for PBXNativeTarget "UnitTest" */ = { isa = XCConfigurationList; From 1d7d9a6b58cd90fbecffc4ed8bdf5e3118ec3c5e Mon Sep 17 00:00:00 2001 From: Mento Date: Thu, 14 May 2015 16:49:17 +0200 Subject: [PATCH 14/56] Stop building, when script fails. --- Libmacgpg.xcodeproj/project.pbxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libmacgpg.xcodeproj/project.pbxproj b/Libmacgpg.xcodeproj/project.pbxproj index eaf9781..80c1660 100644 --- a/Libmacgpg.xcodeproj/project.pbxproj +++ b/Libmacgpg.xcodeproj/project.pbxproj @@ -964,7 +964,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "echo -e '#!/bin/bash'\"\\n\"'\"$(dirname \"$0\")/GPGTools.app/Contents/MacOS/installerHelper\" \"$@\"' > \"$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME/Resources/installerHelper\"\nchmod +x \"$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME/Resources/installerHelper\"\n"; + shellScript = "echo -e '#!/bin/bash'\"\\n\"'\"$(dirname \"$0\")/GPGTools.app/Contents/MacOS/installerHelper\" \"$@\"' > \"$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME/Resources/installerHelper\" || exit 1\nchmod +x \"$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME/Resources/installerHelper\" || exit 1\n"; showEnvVarsInLog = 0; }; 30C2960E16775037006EF09C /* Fill Info.plist */ = { From 9be44449ae4c1a581d6d03c12de325bd60b9f849 Mon Sep 17 00:00:00 2001 From: Lukas Pitschl Date: Wed, 27 May 2015 20:51:10 +0200 Subject: [PATCH 15/56] Start preparing release of version 0.5 --- Version.config | 2 -- 1 file changed, 2 deletions(-) diff --git a/Version.config b/Version.config index 04ea795..c6b16ea 100644 --- a/Version.config +++ b/Version.config @@ -1,6 +1,4 @@ MAJOR=0 MINOR=5 -#REVISION=0 -#PRERELEASE=0 VERSION="${MAJOR}.${MINOR}${REVISION:+.$REVISION}${PRERELEASE}" From f7e29b162e2658c7c717239756900d926dd950f4 Mon Sep 17 00:00:00 2001 From: Mento Date: Thu, 28 May 2015 14:49:53 +0200 Subject: [PATCH 16/56] References to GPGTools_Core removed. --- Libmacgpg.xcodeproj/project.pbxproj | 25 +++++++++++++++++++------ Resources/gpgtools.icns | Bin 0 -> 43060 bytes 2 files changed, 19 insertions(+), 6 deletions(-) create mode 100644 Resources/gpgtools.icns diff --git a/Libmacgpg.xcodeproj/project.pbxproj b/Libmacgpg.xcodeproj/project.pbxproj index 80c1660..d13d9a4 100644 --- a/Libmacgpg.xcodeproj/project.pbxproj +++ b/Libmacgpg.xcodeproj/project.pbxproj @@ -50,7 +50,6 @@ 30444C4B1A65E4790052CB94 /* SecurityFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3077AE881A6547D2001EC508 /* SecurityFoundation.framework */; }; 30444C4C1A65E4800052CB94 /* libxar.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 3002C04516EE389100D57C1E /* libxar.dylib */; }; 30444C4D1A65E4B50052CB94 /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 3002C04316EE388B00D57C1E /* libcrypto.dylib */; }; - 30444C4F1A65E6F00052CB94 /* gpgtools.icns in Resources */ = {isa = PBXBuildFile; fileRef = 30444C4E1A65E6F00052CB94 /* gpgtools.icns */; }; 30444C501A65E83D0052CB94 /* GPGTools.app in Resources */ = {isa = PBXBuildFile; fileRef = 30444C181A65E0590052CB94 /* GPGTools.app */; }; 3048830B1462B11700F2E5F4 /* DirectoryWatcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 304883091462B11700F2E5F4 /* DirectoryWatcher.h */; }; 3048830C1462B11700F2E5F4 /* DirectoryWatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 3048830A1462B11700F2E5F4 /* DirectoryWatcher.m */; }; @@ -59,6 +58,7 @@ 30516558142281270038AAF0 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 30516556142281270038AAF0 /* Localizable.strings */; }; 30691AA4136AECC4004AA469 /* GPGOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 30691AA2136AECC4004AA469 /* GPGOptions.h */; settings = {ATTRIBUTES = (Public, ); }; }; 30691AA5136AECC4004AA469 /* GPGOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 30691AA3136AECC4004AA469 /* GPGOptions.m */; }; + 307C211C1B1745F5006B07A7 /* gpgtools.icns in Resources */ = {isa = PBXBuildFile; fileRef = 307C211B1B1745F5006B07A7 /* gpgtools.icns */; }; 309A18D013E3812E0069DC0F /* GPGTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 309A18CE13E3812E0069DC0F /* GPGTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; }; 309A18D113E3812E0069DC0F /* GPGTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 309A18CF13E3812E0069DC0F /* GPGTransformer.m */; }; 309A20FB13587D5B0041E0AA /* GPGPacket.h in Headers */ = {isa = PBXBuildFile; fileRef = 309A20F913587D5B0041E0AA /* GPGPacket.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -200,7 +200,6 @@ 1BD78BB11726B2830005F251 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainMenu.xib; sourceTree = ""; }; 3002C04316EE388B00D57C1E /* libcrypto.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libcrypto.dylib; path = usr/lib/libcrypto.dylib; sourceTree = SDKROOT; }; 3002C04516EE389100D57C1E /* libxar.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libxar.dylib; path = usr/lib/libxar.dylib; sourceTree = SDKROOT; }; - 300DD0F91853AF300057B05F /* How to get the source code */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = "How to get the source code"; path = "../../GPGTools_Core/resources/How to get the source code"; sourceTree = ""; }; 301D5D9D178C9871003026E7 /* GPGKeyserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGKeyserver.h; sourceTree = ""; }; 301D5D9E178C9871003026E7 /* GPGKeyserver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGKeyserver.m; sourceTree = ""; }; 3026F4AE13A203A000F3CA02 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; @@ -210,7 +209,6 @@ 30444C3A1A65E0590052CB94 /* installerHelperTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "installerHelperTests-Info.plist"; sourceTree = ""; }; 30444C3C1A65E0590052CB94 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 30444C3E1A65E0590052CB94 /* installerHelperTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = installerHelperTests.m; sourceTree = ""; }; - 30444C4E1A65E6F00052CB94 /* gpgtools.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = gpgtools.icns; path = ../../GPGTools_Core/images/gpgtools.icns; sourceTree = ""; }; 304883091462B11700F2E5F4 /* DirectoryWatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DirectoryWatcher.h; sourceTree = ""; }; 3048830A1462B11700F2E5F4 /* DirectoryWatcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DirectoryWatcher.m; sourceTree = ""; }; 3048830D1462B22000F2E5F4 /* GPGWatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGWatcher.h; sourceTree = ""; }; @@ -220,6 +218,7 @@ 30691AA2136AECC4004AA469 /* GPGOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGOptions.h; sourceTree = ""; }; 30691AA3136AECC4004AA469 /* GPGOptions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGOptions.m; sourceTree = ""; }; 3077AE881A6547D2001EC508 /* SecurityFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SecurityFoundation.framework; path = System/Library/Frameworks/SecurityFoundation.framework; sourceTree = SDKROOT; }; + 307C211B1B1745F5006B07A7 /* gpgtools.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = gpgtools.icns; path = Resources/gpgtools.icns; sourceTree = SOURCE_ROOT; }; 307D79101340B71A005C9C32 /* TODO */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = TODO; sourceTree = ""; }; 309A18CE13E3812E0069DC0F /* GPGTransformer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGTransformer.h; sourceTree = ""; }; 309A18CF13E3812E0069DC0F /* GPGTransformer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGTransformer.m; sourceTree = ""; }; @@ -405,7 +404,6 @@ 089C1665FE841158C02AAC07 /* Resources */ = { isa = PBXGroup; children = ( - 300DD0F91853AF300057B05F /* How to get the source code */, 30516556142281270038AAF0 /* Localizable.strings */, 30B586F4141E255C000373F1 /* Keyservers.plist */, 8DC2EF5A0486A6940098B216 /* Info.plist */, @@ -612,7 +610,7 @@ 30DF7CBA16D39EAA00C8225C /* installerHelper */ = { isa = PBXGroup; children = ( - 30444C4E1A65E6F00052CB94 /* gpgtools.icns */, + 307C211B1B1745F5006B07A7 /* gpgtools.icns */, 30444C1C1A65E0590052CB94 /* installerHelper-Info.plist */, 30DF7CBB16D39EAA00C8225C /* main.m */, ); @@ -786,6 +784,7 @@ 30C2960E16775037006EF09C /* Fill Info.plist */, 1B49BC6B1A97A8D6000440E9 /* Copy "How to get the source code" into Resources */, 1BC07F34174660F3004263BB /* Link Libmacgpg into ~/Library/Frameworks */, + 30A8B42C1B17452E002F88BB /* Copy "How to get the source code" into Resources */, ); buildRules = ( ); @@ -848,7 +847,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 30444C4F1A65E6F00052CB94 /* gpgtools.icns in Resources */, + 307C211C1B1745F5006B07A7 /* gpgtools.icns in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -967,6 +966,20 @@ shellScript = "echo -e '#!/bin/bash'\"\\n\"'\"$(dirname \"$0\")/GPGTools.app/Contents/MacOS/installerHelper\" \"$@\"' > \"$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME/Resources/installerHelper\" || exit 1\nchmod +x \"$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME/Resources/installerHelper\" || exit 1\n"; showEnvVarsInLog = 0; }; + 30A8B42C1B17452E002F88BB /* Copy "How to get the source code" into Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Copy \"How to get the source code\" into Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "[[ -d \"$DEPLOY_RESOURCES_DIR\" ]] || exit 0\n \n HOWTO_PATH=\"$DEPLOY_RESOURCES_DIR/resources/How to get the source code\"\n cp \"$HOWTO_PATH\" \"$BUILT_PRODUCTS_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH/\""; + }; 30C2960E16775037006EF09C /* Fill Info.plist */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; diff --git a/Resources/gpgtools.icns b/Resources/gpgtools.icns new file mode 100644 index 0000000000000000000000000000000000000000..237d9f5b0a73c2f429e9f50702c4b55fdeb2110d GIT binary patch literal 43060 zcmeIb2UrzH7dO6_b}PNBSfeI(1r?EZ_-pbJ9Gu?^2pXM5aJk!Y?Wk@<|f$1%<^$f+7Jg z+LQQ}8l%0Cm(Sy6CM6_i^Ghn1)znm16!9{W6Vvj@?3`pz;yNYo7n_!m6qCqb(|-2b zdrw~eg5D_n^7{FsJJ*hGt;&s$&&W&-F}h5BPI$)0$AqV^Jbdd}KSlNb^78qUCyyUL zdG`Eu|2v9$^WgH1MF~-f3%Mp2si__j+@OV3NALGj{VyNi`~Jq&i)Z?JPoC`UJNM=F zTX!BjdreUNhpD?cRU%%$09{{P`vI=1O&-hm+w+YOc14wO{=ms{iqi-(0(Rs(WwS=DJnOD$7cX ziwcX1N*0wbUB0@$X-8+znaf|_zW4myoAUx!Geh}f)O_u^mgq`<|D*43T)TXxXYZE! zn(|^kB1t}9AQTD&d=inuk|iq}wssypclG)=cb`))+QZG~tM*U}hzYaZw!WaA{BZs1 z)k`NjTh=ToMEU%}k}{}`RkgJ%Ye0b#A(>AWSJiDjcEijmqX%|2u3c7MNahQc)bBic@%pu^ zw;#QG(PICFRu`p3jF^V*QcrGOy?X6xU+2b3e!i$;)#kk?uYUjY^I!VWJFWgVFQ44| z_Tu3k4a>^}Jkj!&uJeHK_1%}$ai1~D2PhLlaoW;n@9tl}eC7Jp-kr6D`GreC%=P;( zq0*oK>-N`IuiXG6zoYt}{c!Q%mem!4{6+PhXRlwoa`pBz>MC~(b00N^;7nQh`j;QB zUIL60ZBT&=_-J*}Na{;xOY=L!mP zQ@CM1o(?9S{?RE}IecDbQRf5d^$%y;H!kHb*?IQ*)yo&J{)_tBQ;FC^X)#8nJbC@i z`SX{rUh8WuDz4kz_x(%iZc|1|dR(wAQ9^0SdPXIr#S4zSeE0LUBimL9%lBNocJ<5i zm+w)17HY&UY9ukv>xcet&z`$<dSjU(}?Yq+PtvGPtG4dd+E!IC+kYu zj-30k|L0N@ZB8wvHdDvBoqB$~w`*fjYai_IJM}HqWj1vir8d{1yZ`FZUhvf3t;LPq zz2E%utZeRQ#2QL%7f?lxN~RZpkBXT4n~&YkZ)u(Eu| z{@#C4?FNcOJ*7&FvoO51Z+24KY?5VCz#q~S8 zuJ_;YP$L>B6=FikFF*IS?^wBLYfsyLT3y0 z<&KTZc}0x}PaNOhdiIC#h-OMT!}-XSbz6ImcC{?ZDq7ui>X)v0oF+=?bH7J-_HJ0o z&#vBa_-I$t&ih4P&6JW);MaSX?>KUJ*UG%CMXOt{zs{Nk@^m_19&V@+Ws>#nJzXv9 zu5Pst0R)@OYqeE-yE``)W#yEu+HvuGVR6LhMMB6obr|fU0bX7opAAKq7)4( zj}|R!-`}>3mzi5uv+wa*?JblNVR`Mw#_E#nEOPa(gF7nf`hsj4DJ9RjbxpY|_wH#Z z%+1Ivt2y$o(2=c_;>4yOn<`7PvhvEB+ILhe>P|2KQa!!8ij3M_t;=}1X}r>!-m}Ik zt(1~-;_a>F#n~Bo{M9>lEaA0eX%m|%Ma{X(a#B}st1r&WNy{s$>Dx4QD`;SSc1KxZ zc6uJKqH*iew5se$m~^Bb8JoJQsfOfbr{)zd@5xbbqZDUs*;*pXPRr#9*ETIpdSbTQdqggLk1`{1@(o3?9?1ye)WcmxH#@u4p1u0^7T!wUM0-qWu@ft zOUiVaK&ceCh$OR9a(H>AtIJ}7+%@EYQtAtP&!qB7ULG$qB^TwzPXZTLWSAyrlUXU* zygYt&akQt^Nbn9tsqrSR@x`UNaJ){=<;A&aVoK&r|AhRkWT51g2_l{J)un(^VvL@1 ztU!>>gF|_4R*t*c^3Ti$ zOkNh59cn#ufO4d^U3gY@7B4R&IVaX}rUIrUH0OIHXC(uBR&H95<@5o{5p!%q(=tJ& zjFij>n`!c5N)2u2*i1~BnVA$|K21q1eZ(A_;G{G$Wm<^klmSZh+4hm?$(cZz7Vr0O z%GuTd@u@(Wo{|(`_Jy1nQ+<|AXo^^RYK*tp)c2UPt^8uKk<*joeM~;zo0)2gwg|d%1wu_lMRl@6WNMhZwceDG8XBa! zgqo6in~Joun!1|0I?|Avpl#yfZ9RYHL?tGZ!z5}cLKSJSG)I_oqVUqhfyQ&VqI zlK^JEx}t`LriLO*VZt2UsUt84`vZr@NQ>|U4};MlN}yh-MyT>(tx%IxRaH|(uvwx; z0=K#no5fL`Fh_6NNX*P;)>85+PzH@LW)X>=Mp~Mh8XA0cks4B^si_H62{j?CWvUWt zYN|zQNL^8h&1B2Us!s%f5g!0JDo`v9EvtwGPouFQ9;pk}nt)%GRFhFxQ)DsO93;!u z0G{dp7AmWv3Ou94JmauMg=(#;GHPln3M?jzSHY< z61`0(YJdm_^NC*6(w0Flf~w+IasphM4bgQM&Z(8 zB#t5$J=!un(c5So2qvM3>j8(ZqNKoKGC(@}y?pHj(?q`l}P~OC@Ct)$wDdV0KhE52m&_3#srA@QWkm&$t}svneXmeE9Ze9f3i{JOlpGCk zt`{rLkyX+%PxhIlsshls=&}lmp!j@`Aluo%h(K!wR2qwc%e#fe2Vrb2m)J1NDWIu> zJaA~pLRpnnb=>@IW{O3DxfR$r|;%sgjbvk9OJ7^#+G%gV_E?JNgRlc_)|Ax%S?s6Tn#V zvfyw^EICj@WvZ>a!6Y>`Wi~h_yMsl@B2_tXDa|=HZu(lF6rBUKax7UnPnOT;8tg-ij94ta8lP?Jar zDdRRedHQD>;83#Q;NJe#dGPD3oDfho=6 zKwT;b<@pLAfsT#Nk<}WnI7j$zzD0DfFkCU7s|=V%i&fFZH{1yKqgb$PF38F8Dd6hX>eDTlDaHn3xQD* ztRpMpKzX2@(&;iXbh>~kWI^vX(`+*Efu{H${@?0siveddY}v#lO-uFErU%dhaqc#j1MdL4x@W!}@1KwZjQ%pjPEAps4F1moiVfx%>yF%?+qiV6x)tt!xB!3r|} zW@LaZ_^fg!^h68|X8^g_u27^B z(2T*XW60uy;4iSq$;u)*1nMx}o9*{Zd{z;&g&|F6vgPFENLfC(4balX1*c9g~cf@??6V^gU4rK#}!#c2wIi#!v937AxQ(oL61~}+gWo$yk5->{{ zMcBo}Y%ov|>kf>PP_GPu938iY0WNI!0mHL|%o0YK_>jedMgb+2fRRNpo5o@DIdtq1 zpt~G`{NJ#P>p@&^LS`XDk`9MVK3xJT5jrL?t0W#8EoC#XG@xQI1+q-g<=@i9W`-Ri zrjS9SgT7LDya2}!l1*c=%At?OM`0OIkWMmapc53G4##u`UHad)hkZiu$R%__21!fO zq3a}BMQjrK8sL1Il+LPuwk)szab(Sopeb+5Ff_Dlpjc-_+lJB-p^pm zLNgPO73eJH2NI}NF$t8vT};C%g2NyXV6#XQD=9WXeIQ|A5*Qb<%fN;p1(Qg@?&Xv; zT-XIFBu&V4&~eYjuEZjsGL5SIRfF*$+4^FCB zG9UtD@QJ0A@I65*9I_mi4-0BS=J%waWFvD| zqEkvrVv@NY2T7HRcS^7(j66n2aK>qrL;8VuEvN2*BKL?T)K6fMJ47)xd^vsia{BP) z^x@0t!t zxSVbvzMM`FAN^V1jlJI>Y^iEIh&H59$M=Sbg~D`(G<7v#?Ooj!fy zXixXS{q0AO9O>mBQSUv{+Y4LpJp~)5;44lXLA~S=>481ylu~bRPy2!WhmRaTb^7#~ zi(hr;`-Y=fNiNqPPKU;|_nqjw^!2yj{doK4^(zojaPrvEqdi9sbsao#VBdj#@I8P! zr8_$Jb$0G6>6Gf|=eMI zrtCP>4fmO^e{=K3^(z<7^!1%M*4^C&zyR8@r(;iNN9UgQjy=2E_w4E5w-dWj`}B^E zc1Ypx?mg}89i8oaIy*s$0U;+Zo>=1T5u2Kpk`Nmm5gP1SOO4rju_WR)dv@>Kxoan6?cB}ZGZMsf zwC_7`uY}>vazFW~Y2Hx0) zlW4nW8v$a_&XG`#UAsHF+RJ@y{UaB~#3dw&DsE5R=FUAG zEkaLgUv5NXR7`9_VsdJ7LNvrFc!7*@t6SUJyH8&H8sdD;pE-WGs|#ukj14h7ZChKL zn_F62P_uLsY&5s!lVF4b2D2vKmWjh zz@QLN8!VHMAXYonhqnQ+H5RSj(As{u@5;4HXL^t0M!Re0j#dB$T8#XmGpbe-& zdc%f>h7GVet6{^&#-^sm4Qr~4GQvGFRK96EUg+SiFA-TT{j?`UgnX>8ntHcB@%tY2SWC#aXKt6SGVZcu7i zU%Pyg!gpZG}H^4&~06uzQ9EOjGS=(A$kzPxU7A~#bw7v7l zg|E(@h7xq_+PS@T3!rZlL)WiEb!h#l`gN;omXxB*xG*0lYcpd*V{>aq7dKBYFHcVo zPl1=Fx0f$2Kwxl4Sa=jvKype<{A1mI@i+%t7~Qf zs4mD|#tZa?ZtPk*?-O1Lb%3aEGr4-(AJc&D~wR;$QrQq`Sa_@I+p!J_CAlBO>D0 z^nH1(y={GUQEqfCH6j(2RIlH<{{%Km`<@-GEiLN>fmX&A4zBLV1G$&DNx8bZxw#g> zzZ+}_+(&p|Q+Ru0JA?#>i`sin_x0>)UR@!~1U$`!dBTdd&Fv@pjvv~;cYE8m^%)Lk zc2G$k0EXOXE^b0sX}|+0(v@&Sza~gG(p|#?8yQ^PKOlX>q3**c`?_~-UbUzo6_C{; z(@=Ts=Do*y4ed20% z?cTG$`*`ocZR=|mWyktM$-|O!OIB>!efY%T1AF$a3$*qO@B>$Z+IDy2yUMsY1B|n) z$c5(Y%y%JRrMWsIjP3%4Al=nGfOKJHYimo}?)F1Rj_+%0C=D`+1Yq^x_)O8#`nE$y z4s`Aj+PMY#`+=GOi(L6G#m;mmXBQ_YXJ?l}XTnJUxSD|H>K0wLX+zzHrY+m|bao#* zurA6-$2$?aBu$@%si;CTUZLxL%Ap!or-hhQIC~%Q*c5*Iq!oSD~G;|^yNhi9a zlamW554vhNxW_N4tF2kJwti#twq2b)9eH+^whn1wfUEAxP0TA>)!cD-V}N^DZ~*A& z<>~I`;)_}N?cwHzT#&P*gOh_35(6>p9USc8 z<6uuZ$cVQc0G?(KKcnq!9YPA0R+lX*E3d3xzG`({(|Vq#dvtV=YalPe#}xE;3W!W4 zD>n(;BckB|imd|m=Hlc`Il2M784g2^$clLNAsva_=V4Q&aVB3nrtTU#4}Ez1T_xj7}JWG)ZoYZercpmAZc zn+dpTaA;&qTu9EMv`8NZ9XJG-xCBJon*~J1M00}!{CvUO;Jr?cU|Tx|6dv&43j;kH z5>|n&yp4^um5p0uUU5l5PHs+iF5&?`A0_*k8CbhR+YSneh>prxfs(i$wt%l@=-_Rz zz{NjeVPq)adwC7OJL0lS+5ooDny?XC&$h9)wz9Nz@Quqa6!9|BGcvO>vmpK_CoR&= zSkJ`X)g9WSe_${-oY%0J7a!zm1=yN;Hgo4#I{Jh~g@*+B`G84WvF2b8TfPm$+Qu4m zg;iiJ5C68#{;@ftB9xV$mY#t!$7W@u!~{E=&Yx#!hFCaKDuVqb1c1(bi z8Q`nVoBqWDa|iFRC~!qTZ}1XlM}Q~6zM!pGVJpiLt68p*3l~O&!Ld7%%MJGPbhI*> zuQPXnu{D^_!2!1_cQ{7+@tQW(h|(gx?ToNlMo*ZfYij2e8Ue!~Z*O;37bi#XGg}0D zTU%Md*V0m8MZ-Umrh0R=(Hv5nIY(P(?tFb?Q%h@PqhV)jV`m5GE^Z#4-US=#)>o6s zTu*ELSnwqt1mlPz1xLGa$XvL9}r_D9CaSsG%@$tg#2G^vGB-R;Om0C(z zSXv=V!a`(8x3C0Q_>urivjJyU!nO#nSXy4aYW3p0xIky~`IEr`M^2ooV_@wX0BzC7 z!`0OVo7fiD90H`p7NDqwgr$WgX~D3x089(`2&^=)mY}4aYsQk|;zgCqSCr=y(*lbb8J19S@58IWa>g|wN4nYo1--$LFT z{vcstA>J@I6IhUz>eyerata}&us~3>sA4HUh3jRbKTC`{{)<`q7LGpP3b?i$9dWZ0 zqk?i~q=gJX0Ukh00L zW)5f)rlux^ri2L}R*@;q#Dp{*XJTq%Z0a1DofQ`m6}>Pv77sr&b8-v#!mMaNN7K1e z098qS%p^dyb;G*C0m>e%OMCh`7GCk54d~M1I9D6lp(sUg|8y7EeGqVRblK_2j!2yh6W@=^v3YwT9Q=y5J z8Qw&ulTD0`jIBJP(lQexU|bIP;V^85lZwRDgw)LJ{DPElZ+l}gyecR@RmaHMMcmXJ zz!+d*3kzf}V=9IX+c1r$L+Wz59sI{N00Pyz=BXnD{yq|BiP&G;ro#)JuJOfxbf z4Hb<|tX=)1lhRURxG>BL3=9tD1GY*;WT>a9wrN^&a#|+D^10g>%$Y1k9Ssc|P{E(U z-Zo$pP@6F2i}8#_hRVh!mbT7b!O@8+X({m$FhBuJGGH`}!tvQkI5)u6R7YFSIz0hK z{AuY6q0iSBBde&4o;XEY-^?Bww%8!xv}UHrOv=OKTM@GjaCa0vNCMUv? zC%_l^eU1eL`1|8QVo)#~L_KWu=FC}OW?_|(5VbHqF(o<5-x)f&_sV}ZWsaVyHMDPR zatm|POak1DZ_GDRGO@IG^$iZ=hK0a^*w@Dg5Ro79p9CjCfpD%B;Nxa*raNnf_Ix8# zGgFJ$I2bxFjEzqS_jNMYn>h(gqo|@aVahCBV@rEGadm>NONPj7*q zt{$l?xjB{9=NY*~Lu8FPz4dY%8Db#O!#7kww}KJ0?=@QF8nUw>q^dt?Zvvpf%asOpJ6Y3qT=qzND`1d|lCe zX($|Qp!o>$&^$Ii7ICAaf;=1@9Eu%j4i3msUJU8v>}X@EKX=BYv5I_%BH$BrdCk!i zCQq9+uY5i+uM~I*9i*)|cb=}Xm5Xmk1Y8<)cYtBPgTS7ELAw+_DS&ad(1C7avS7}% zNn;iGaGzd4uoN`3#!s3$Q)k}%`9<>>I&*YDpLz42rK z+|1j>9uG#5EzJ&wzJyJ=Edl=w8%v}4v!_fP!xX^%e*soaYr-U`iK2PZbLT8@@aLik zk}DG)#*M%Sp$IlNB*4eh6^@El)-W0;?1V6ih9L-PD{b?Bq)xMe6y015tHluzx;q?a}k1A4B`>RdA=oPAy0s(Y$y~at*0d3zIl6$l6$o+CNfVX6u^WI0%2k1 zdW!b8pQMPlTVXAy=x_EXh2@X}*exv}kx&SC|7g!C^j4DUfBUu)h~Hx38dw)ojQ&Fz zVOc^UDIkFwAyNR;tS8i)U;5wnzkSo+Uj#xaV33Aiih9eZi2k*d##`8a1Dr6E2Ydt| z3{)9lWoC6zj#gnrLp8s1S4~g;HV@BP5ZZ2NFj8`10|S=O6-b z-r%AD6Y&4?5}@9^Dts;V=Jo6TH~iOCoc?;qZO{N%;US74x5uYP$2*zo)6<*V1PUZPj>P^wq3^VRE@FJIv= zdNoSC^#XohgWdWceRHg#C^;-NE_*;9bcapQ0DzVe7@S7tdb7`r_$}*SJ1j+`HMkZ5b~vEF?T3s{lX+ z5<-}sMW}!ag3BU;r)YC`{B-9MTvNI7<9Bx-Jbo(H@)deP1JGxZPo6z_LOvy)p{KNG z&-hOzo;-O;zEOMi?A~{mkL_Grk{KNm%#BISE&xEVh=2p&*mr~?_zFo8UC1judhhm4 zu#^0`Ti@RK>HeeVzr1|;;`xi`PcY;)L<+0%!2zP@l|_r_(S%y@1n z+{B7c%gG08kR%6O5#bfu2DAa8qyTCI;PaPVxp(`uHs_vAVG zMCIY5hY#;Rc>MUgLp9mqK~Q-a04pT&cme@XG+Y3?A z-utf}{`B3AFHaw71rObKviHLETR%N~4s+!^c!>4>v9l;5C^7|5Ny!4xuB3pGUr+#m z0817~12iN-@d6DJVQlO#h^)W%{OO|yKi;}>_E;C-ehw2roW64N4w(7j!w2{7Ke@d* zE+j4+8xnX5^7DDH0#JTFDxl>T@be{5em+?s0njk{Oo0>#!$m-(q5$Pr_da|AHFp2I z8!#tMXC2%<+W_%M7r*}T!6W$Gdw6eq95<6Bv3imilFwrm@bU|Iyn+JwBA$FfKAvO< zWI`Hp^AL}g&qDQ0VW>-uOtX4AbH9FDaOUWfDZ-ZLAD|Y#03Ot<(;?h-M#zMee{5S=iBRt zii1}I{HWEfJGxF?zIpdP>}rlk#9jc@z@5*_1AdfGl%^Tm|y8Zo+cYb!b2TU=bR)98Z`los*lJ4U>Z8KnZfBvhiJQltatT7UjsoW=>9KCb{~+ z#VcQ)Ll;#pT>SFO>o?D?j*ZAIE=1Ys%^RzW0a!L?(ejPEkCa6T3c(~`YngnkPi}5u zj$}4Kpll+CgcW5ov$C=QbRcs=Mn-Pc_TGyZ&i3`4K6mc?xeJ%Cbd`rk^*+^^tp?@o3n!=v!Ig{78d5#>~C68k_WKzNoeuP82=myJAf_&+zI6}v1*_k zD2cL!nY1jpQ!bT(Z^omn>6w}78L4S`m95>UPaZ!CF__1WLQv)DV_OTk0nype&=4F( z$Ynh{8mfgEfUmkRPvqy3lue4De*o{p#)J<)lL?5Ku);6OP=kB@@Db;vr>16!YPWTr zJbvU5>XGXP{Nu+u>I%Yq!%}j=y=0;EBwEpXsBK+EehNg)s6?hZ+J)m8AHe8f6|8zT z=uFGV;HRTB>GbrpwDfc`ji0WSky~8TeBkJ@Bi&sP4|=4hr>moRMShg8S7;(c8lWus zoIKp*YR;eTXsRvEjstW}Ukekju-No`=!3-SXJI|lGax*HOrxczp;Vc))YP=}v{Yf5 zdTx2my84Zqnwy$7u3ueUlAj#z=j9y~l|p8!WI<`Oa-dP<)n5Ga_})#+Md{%X?4qWv zXXgc;$v->^x~054&=#6V8rYUhVPF-p zj>#y6OeO#r)K3y6(~`g%Yb=my1%vaAc1BG+k2% zpYTN7KjlE{dv9W_P!a<)#GfSCmPkxWB0>MeM1GQFGW?0NV22=C9pon#tl!_hw|)P? zuI`?mJq=4yQjjy&{PX!H_TJq1>;ljmn;9#Db)_XGlYmDiNr{aBih~ppmI!h{CXi?( zB_-sn+}*xoCj=_*KX9nKduM%Req109`(b@P&jg}R;sjv$?w zn3RYm@Ig%iRvAErtYl%*=tL|qF_E`s=WYn~1@OHcot*~`?O0o$8{>yVeq=w_F}C#x ziOb|=Z-L?aZ*uNE8C7%2Ryl*1haCZ-mO~-zn4#C!`aF-WUO5i7w2}FEhf&}0S z69`Bt#}9zV$Hm2GRW!D>;^EX z&=cYXaYnJ&00V1$TrA#>jg5(nNz5r-xv6Q>`nolB^$>$w*RZ~!VbjK@##QMV*!FGf zE6J2FHw%!UJW*TU3c|ROGoT%$Kt1A$BjcH|7%dilV@RwxBv7nEOmq|kVJBw^D_3u9 z+*rSM6X-LxOmWYBxoKR6B8X1lP)SQS+uyKs-|{b zJy?2u-P%>;3i_&*__MMGt<+kzdfl4kMX7<#E&-A8iOV+Dt>3tD^X8SM*|C96CLlw0 z;%q&0NAIvWFg<9FKy3!tAv!8L8gAW1D@8^nWEEDgTDx}j>XkLimn~afvm7l$%hhXY zR;*mHa#hXJqTD!tX9u^yh?v-@*y?(;hF!OQeZ%siOo(H_0@NqY(lvAR3XK7Lv2EgF zVxsUDMN39SMuQCF$WVVb2RkTea;~7HymHy{<$zvOv#hG3tO&vMOWsa)4iLN*9fhku zZdv`xRjcrHly%jj^eBG^EJS`h1g6=0hQxyH#TAQUWMX5YA|s&!B1c6)kQ>AWM23g> zdpSd#mV>jayPKDsWtX)%yqh{=k z2Sh-4nnzG{Jhna1p(tUbbOc1fM1-SA3Gt0i6_5k*bP!_!F&n;qfjELajEjIQG6E?1 zk*eVZYga6-h8aVbFJG~$rW^;&*c#w!7(ZjaiLHB36x1x#D~h6p!;MoEDFb&jb?xwNt{8)6Bp7ffDB$r04}>2nROoqfXqlN*k>qA+17 z5r#q~fN>FQ@nIE&a>BwwLShBWsvw}Xq=YO*i_l_r`C>8y0GDV_7QDI>bDr6NE=BI@FIhoC${63g~GjfJ7`9 zN9QJSeH=~aje8$Vpfv?zexM42f&&)?5rO<5PGC?F#D2gR{sU1E3Pb@c{~&IBmS}NB znFtT&VU&YUTk)wXoSe$yvndi~Lu;}#nLB16rhqXTa7}Gp{DR0p(2pM|i6I4n5}+Rn zlnB6~O{AZ4Ku}mrN-kMizPLn)&r$IyAIc{R$b2=t4TCj&+KbPy)8j%sY>jnB4a6FZ z9`(g+T@xE;9~@o+K`*dE$cnFzFO=Tj&lh5ZR01HZJ{X=~h)d4kkwv9ti%LZW`DBh1 zoHF4PBsc-drRC%ZVFTrIV5pp%lNuT524OQJ20{vC?geeP#-S5vvawOrbC!3!`Pl*V01?Ugq z2TGG>%{R7k@_;ZYSw9Gw^7RSLDJe#I+1VtVbFs3435HI1h>9}lSuoInu^*gr5O8Wk z%ghkLxs4R;&(7j!GvVl*$c1np-KjVLK}2wv@=B^&|M3(5)FDEZ?AO2ZIvyu8&_;q#fq{{+R|EasQYG5;i+t4Iy(-)`Qwv|BMD!`vyt+qvXrFX@9>4Q<~v2`JY`Lm#F-`8pxzQ z{IjwL=)Q9KI~DkR|9>YPsNdBn{%sm~-ubV^1H7@e-IC>@a};BWuYzq-^5dIL;n}?MD~9W4>u_P1I2TT z|3Lw#KRD8X%(q{+34+Y$&77rY8?|`fkAJMi_v8Pv0%O1bBiM7KF6XzfDmKe*{Soax z`fn-!i*3oBLqqm&w;2LbDfGn9rq-h>pqKJw2jG&xuX zpZvaSVw|L!N8``;}e z-LSY1{MS?e!#%pSgSGyf)BRt3x)S#M&GJ5iGx)UpT^}+0%^CW`@;_yPVf+8h{x%qH z*#AD|e()yTe|Q;lXa#7JG90=6f4jgzfNt^}8Ofmx0L5o2sva6d{yFY#_uod<)fuKqycC&DTch}_=x*|8TrpJzU|PRq$$sk`nU;*%|G($5!x2WXrSc+CZrKlr?CB=opf+P!_&qoef0a(7mh>3Ib&1@av?O`qpm%`h!-2Rru zHNJ}P1uqbDakMovm@{#N!cY!?Tc5o8Sa=nNk%^f(yivi>2><;pi^%|%nTZj+>|m@q z*#F}eNCW?4D{8>&52nqS3Cpa%dBK=7ror_48j5UafFHL&==~UM1r?2vT3Vz3p+!q; zq=t$Dn=xb$2nLX*GdXhd3jg3DFUMihrH3j$0mmf?Nog56o$(JYbh?bRq{I-`$45j^ zKte+DA6`Jj@5C>R)1E^R^aG`ov{g)I=0cNdicN&C+H>U8sh(ZSg5mWKvU961-a6d4 zuCDpW?K5Scl~eMTJMML_Z0bI7qHEL2WA~eN$|yzC&O5tX&bK$LShZo_xy|iAZPhNN z=o(vYAJ}&y$AF~h`ohzD4*jr}D50dQzUtX_(n~~1N1oks{4&3olGfgGV%6cwB1*dc zz?xH=3D^i)-B`HI6E@Pe3%Ard6j4%!s2pZ!prna1atTidGDdRA9IFya$|08@s0L|e z4_?A#NKZ}XIV<3_b6(^)NKcN*wZ&;g$AX9nke;-#z?LPV=!D{2C%qY?G>b;aXpWqv zr>7w!q@>3x8d@uBNHGb{3_T?|HjBwDVo9-8&A;FXDM^Aod1?uZ!DO-J zlvJi^FvMBvs)!|GGFcos1qFGInmQZQAY^0}SS%rv#$qFm44|;ar~|bWA&AWO&mQVcAaA;DyGkgS9}M+!6JOvI3)g90o*TLvgNa_oUU zbS6VU=Q9u;`T!1x1(}kBlnkR3S_2CT#%79hXfiU0juD`ZFoi5hCPNDB08>av%gRX8 zL18*yMvAQ{lwKk^&;2j}3 z5x(xu_$7#JTRWGaWPTCMl$#I;oQ@GT|7T zm|HvhMa0I$^Fn8X-o#iFCu?(fx0$)Ui-&Ijysyg3$u2a-XS$G*A;#!io0-6?lH`ox zonNLVM*0gZd_yB#rr~{~=b9QB7$AML0O>Id%$>YEz5T2|7g7?0)*NyH(q|gL3uUbx z+~CD{$VI|zA{bDHP@Oz?hPE*>AU3f5u-4>#QJkvA>QC z%eIDImwDs(rvKf$ zw{KoP`u^hnIuTF67j1-n>#jY4NsS*|@7=#`W9^bcm@tt?3JNMt-4s%C=*ZpYx3-kz z;aNdpf=E1ZXr8e3?!8W^$&f8KPZVb7iFizy`%kp-!oMz7mqIrdQr&=H(x4ncHWMvv zJ9)0NhPSj595W<1iOhu=D*5T`+=}|m>&kg4>FaiZo6`y7_=0Sh(vF|PPENuz!X;&` zJ=GY2_vkOo%SgpjD&k50m@sWwT5;pPL$$ux0reuXQt?b<;(5RlQuE8}S{gU(T;hWF z%?(LSgo)&0;?nYkWmPNTwaxjdOPdOz8E6pN{_!xW7tCc90k2YqH?4<-#FnnC&9lM1 z?HsSja1^Ex8Va*eg#-tO#pITjl~tsg3Mpk`rdt@~bHm_WM^Q0JnFwZDM4niT?lXq)(KzuWK2pD*#7AwewYByi&Hush-TBiyczXWF zHus^Xidk^%*RzN&7#9p$e18|1`@nh7ZtItr`(ekjn*ERQ)|1}{o2uS`ytmcjSmw#A zF~P;(JJPgKVm%~J{iYDJ;hD=v<9^*g?FB`>nD}ej z9q14Lnj|F8K!)Y786lAT-E(dokm2_G{Vl&H2?Ad$_%HSc0C^J(@;)pCj`el?04Q0C zpIH0>rc?Z|Z2Ji^PG!9(V0;6qA(rDG_G9Y|u^f6o(r5h9{{O^3ykBgA|75?9o_Bm- z7bo98GOyBn;m(x{zhBN@`{DfRf#-5*vJ+rh|wmXTnsnt#3P@ zlGID^@P8}~@!Qf!624yIvibYt!gL>QMZ2YU?cPl6^dO$&tr>3G?~>pi6` zY=cCuuy?wHg^9VXqnoE+f+-{?nc??9nwr~s2IwGor=ixYx$p`@LwGl(>1Y2yxqhuB z{{UQR&%gcV?K|on_2N)*IwbE=FYjDC*RyktVEJxHo;<%KKL=)Vb;BX|N6BMZZzViVWohH7r*#7zZ?qvLJ>YPw?fx0<*AY(1n#D<54 z+u&3IFS6gg5I^$y#p|0)oYr{!J?th3`MVFqM>dT|-^)go+7s@=e80J@x$Uo{5C4j{2l#1=j~*CU4jvUj8EJHI@_~iLpb`HE*^^K! literal 0 HcmV?d00001 From 3edfa9ba7c3ff9f8dc4e8438dcef5a7e867288b6 Mon Sep 17 00:00:00 2001 From: Lukas Pitschl Date: Fri, 19 Jun 2015 19:54:12 +0200 Subject: [PATCH 17/56] [FIX] Prevent Libmacgpg from segfaulting if XPC connection can't be established [#143 state:fixed] - Store the errors which are created in different instance variables, so there's no chance one is overwritten. - Throw the most appropriate error. --- Source/GPGTaskHelperXPC.h | 3 ++ Source/GPGTaskHelperXPC.m | 97 +++++++++++++++++++++++++++------------ 2 files changed, 70 insertions(+), 30 deletions(-) diff --git a/Source/GPGTaskHelperXPC.h b/Source/GPGTaskHelperXPC.h index 51d7026..f2b23ec 100644 --- a/Source/GPGTaskHelperXPC.h +++ b/Source/GPGTaskHelperXPC.h @@ -53,6 +53,9 @@ id _jailfree; BOOL _wasShutdown; NSException *_connectionError; + NSException *_callError; + NSException *_taskError; + BOOL _success; } - (id)init; diff --git a/Source/GPGTaskHelperXPC.m b/Source/GPGTaskHelperXPC.m index 8b698b9..bc47960 100644 --- a/Source/GPGTaskHelperXPC.m +++ b/Source/GPGTaskHelperXPC.m @@ -39,12 +39,15 @@ @interface GPGTaskHelperXPC () @property (nonatomic) dispatch_semaphore_t taskLock; @property (nonatomic) BOOL wasShutdown; @property (nonatomic, retain, readwrite) NSException *connectionError; +@property (nonatomic, retain, readwrite) NSException *callError; +@property (nonatomic, retain, readwrite) NSException *taskError; +@property (nonatomic) BOOL success; @end @implementation GPGTaskHelperXPC -@synthesize connection=_connection, taskLock=_taskLock, progressHandler=_progressHandler, processStatus=_processStatus, wasShutdown=_wasShutdown, connectionError=_connectionError; +@synthesize connection=_connection, taskLock=_taskLock, progressHandler=_progressHandler, processStatus=_processStatus, wasShutdown=_wasShutdown, connectionError=_connectionError, callError=_callError, taskError=_taskError, success=_success; #pragma mark - XPC connection helpers @@ -56,9 +59,11 @@ - (id)init { _connection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(Jail)]; _connection.exportedObject = self; + _success = false; + // The invalidation handler is called when there's a problem establishing // the connection to the xpc service or it can't be found at all. - __block typeof(self) weakSelf = self; + __block GPGTaskHelperXPC *weakSelf = self; _connection.invalidationHandler = ^{ // Signal any outstanding tasks that they are done. // This handler is always called, when the connection is shutdown, @@ -69,13 +74,14 @@ - (id)init { weakSelf.connectionError = [GPGException exceptionWithReason:@"[Libmacgpg] Failed to establish connection to org.gpgtools.Libmacgpg.xpc" errorCode:GPGErrorXPCConnectionError]; - [weakSelf completeTask]; + [weakSelf completeTaskWithFailure]; }; _taskLock = dispatch_semaphore_create(0); // Setup the remote object with error handler. _connectionError = nil; + _callError = nil; // The error handler is invoked in the following cases: // - The xpc service crashes due to some error (for example overrelease.) @@ -88,9 +94,9 @@ - (id)init { if(weakSelf.wasShutdown) return; - weakSelf.connectionError = [GPGException exceptionWithReason:@"[Libmacgpg] Failed to invoke XPC method" errorCode:GPGErrorXPCConnectionInterruptedError]; + weakSelf.callError = [GPGException exceptionWithReason:@"[Libmacgpg] Failed to invoke XPC method" errorCode:GPGErrorXPCConnectionInterruptedError]; - [weakSelf completeTask]; + [weakSelf completeTaskWithFailure]; }]; } return self; @@ -115,13 +121,14 @@ - (BOOL)healthyXPCBinaryExists { - (void)prepareTask { // Reset connection error. self.connectionError = nil; + self.callError = nil; // NSXPCConnection is not checking if the binary for the xpc service actually // exists and hence doesn't invoke an error handler if it doesn't. // So we do the check for it, and throw an error if necessary. if(![self healthyXPCBinaryExists]) { self.connectionError = [GPGException exceptionWithReason:@"[Libmacgpg] The xpc service binary is not available. Please re-install GPGTools from https://gpgtools.org" errorCode:GPGErrorXPCBinaryError]; - [self shutdownAndThrowError:self.connectionError]; + [self shutdownAndThrowError]; } // Resume will trigger the invalidationHandler if the connection can't // be established, for example, if the xpc service is not registered. @@ -135,29 +142,49 @@ - (void)waitForTaskToCompleteAndShutdown:(BOOL)shutdown throwExceptionIfNecessar _taskLock = nil; if(shutdown) { - if(self.connectionError && throwException) - [self shutdownAndThrowError:self.connectionError]; + if(!_success && throwException) + [self shutdownAndThrowError]; else [self shutdown]; } } -- (void)shutdownAndThrowError:(NSException *)error { - NSException *errorCopy = nil; - if(error == self.connectionError) { - errorCopy = [_connectionError copy]; - } - // Connection error is set to nil, so throw the errorCopy; +- (void)shutdownAndThrowError { + NSException *errorToThrow = nil; + + // Errors are thrown in the following order: + // - taskError + // - connectionError + // - callError + // + // If connection error is set, call error is most likely also set, since both error + // handlers are invoked by XPC Connection in case of a connection error. + + if(self.taskError) + errorToThrow = [self.taskError copy]; + else if(self.connectionError) + errorToThrow = [self.connectionError copy]; + else if(self.callError) + errorToThrow = [self.callError copy]; + [self shutdown]; - @throw errorCopy != nil ? [errorCopy autorelease] : error; + @throw [errorToThrow autorelease]; } -- (void)completeTask { +- (void)completeTaskWithStatus:(BOOL)status { + _success = status == true ? true : false; if(_taskLock != NULL) dispatch_semaphore_signal(_taskLock); } +- (void)completeTaskWithSuccess { + [self completeTaskWithStatus:true]; +} + +- (void)completeTaskWithFailure { + [self completeTaskWithStatus:false]; +} #pragma mark XPC service methods - (NSDictionary *)launchGPGWithArguments:(NSArray *)arguments data:(NSArray *)data readAttributes:(BOOL)readAttributes { @@ -179,7 +206,7 @@ - (NSDictionary *)launchGPGWithArguments:(NSArray *)arguments data:(NSArray *)da } taskError = [exception retain]; - [self completeTask]; + [self completeTaskWithFailure]; return; } @@ -188,7 +215,7 @@ - (NSDictionary *)launchGPGWithArguments:(NSArray *)arguments data:(NSArray *)da // dictionary elements is not set. In that case, throw a general error. if(![info objectForKey:@"status"] || ![info objectForKey:@"errors"] || ![info objectForKey:@"exitcode"] || ![info objectForKey:@"output"]) { taskError = [[GPGException exceptionWithReason:@"Erron in XPC response" errorCode:GPGErrorXPCConnectionError] retain]; - [self completeTask]; + [self completeTaskWithFailure]; return; } @@ -199,14 +226,17 @@ - (NSDictionary *)launchGPGWithArguments:(NSArray *)arguments data:(NSArray *)da [result setObject:[info objectForKey:@"exitcode"] forKey:@"exitStatus"]; [result setObject:[info objectForKey:@"output"] forKey:@"output"]; - [self completeTask]; + [self completeTaskWithSuccess]; }]; [self waitForTaskToCompleteAndShutdown:NO throwExceptionIfNecessary:NO]; - if(self.connectionError || taskError) { + if(!_success) { + if(taskError) + self.taskError = taskError; + [result release]; - [self shutdownAndThrowError:self.connectionError ? self.connectionError : taskError]; + [self shutdownAndThrowError]; return nil; } @@ -224,14 +254,14 @@ - (NSString *)loadConfigFileAtPath:(NSString *)path { if(content) [result appendString:content]; - [self completeTask]; + [self completeTaskWithSuccess]; }]; [self waitForTaskToCompleteAndShutdown:NO throwExceptionIfNecessary:NO]; - if(self.connectionError) { + if(!_success) { [result release]; - [self shutdownAndThrowError:self.connectionError]; + [self shutdownAndThrowError]; return nil; } @@ -249,14 +279,14 @@ - (NSDictionary *)loadUserDefaultsForName:(NSString *)domainName { if(defaults) [result addEntriesFromDictionary:defaults]; - [self completeTask]; + [self completeTaskWithSuccess]; }]; [self waitForTaskToCompleteAndShutdown:NO throwExceptionIfNecessary:NO]; - if(self.connectionError) { + if(!_success) { [result release]; - [self shutdownAndThrowError:self.connectionError]; + [self shutdownAndThrowError]; return nil; } @@ -273,7 +303,7 @@ - (void)setUserDefaults:(NSDictionary *)domain forName:(NSString *)domainName { [_jailfree setUserDefaults:domain forName:domainName reply:^(BOOL result) { success = result; - [self completeTask]; + [self completeTaskWithSuccess]; }]; [self waitForTaskToCompleteAndShutdown:YES throwExceptionIfNecessary:YES]; @@ -288,7 +318,7 @@ - (BOOL)launchGeneralTask:(NSString *)path withArguments:(NSArray *)arguments wa [_jailfree launchGeneralTask:path withArguments:arguments wait:wait reply:^(BOOL result) { success = result; - [self completeTask]; + [self completeTaskWithSuccess]; }]; [self waitForTaskToCompleteAndShutdown:YES throwExceptionIfNecessary:YES]; @@ -304,7 +334,7 @@ - (BOOL)isPassphraseForKeyInGPGAgentCache:(NSString *)key { [_jailfree isPassphraseForKeyInGPGAgentCache:key reply:^(BOOL result) { inCache = result; - [self completeTask]; + [self completeTaskWithSuccess]; }]; [self waitForTaskToCompleteAndShutdown:YES throwExceptionIfNecessary:YES]; @@ -331,6 +361,13 @@ - (void)progress:(NSUInteger)processedBytes total:(NSUInteger)total { - (void)shutdown { self.wasShutdown = YES; + _success = false; + + [_taskError release]; + _taskError = nil; + + [_callError release]; + _callError = nil; [_connectionError release]; _connectionError = nil; From aef754685042f87d41f9c8450dce2818176faf49 Mon Sep 17 00:00:00 2001 From: Lukas Pitschl Date: Fri, 19 Jun 2015 19:56:40 +0200 Subject: [PATCH 18/56] [FIX] Reply to a processStatus request even if no handler is setup - If the reply block is not invoked, the xpc method could wait forever and stall. --- Source/GPGTaskHelperXPC.m | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/Source/GPGTaskHelperXPC.m b/Source/GPGTaskHelperXPC.m index bc47960..59f5195 100644 --- a/Source/GPGTaskHelperXPC.m +++ b/Source/GPGTaskHelperXPC.m @@ -343,13 +343,16 @@ - (BOOL)isPassphraseForKeyInGPGAgentCache:(NSString *)key { } - (void)processStatusWithKey:(NSString *)keyword value:(NSString *)value reply:(void (^)(NSData *))reply { - if(!self.processStatus) - return; - - NSData *response = self.processStatus(keyword, value); - // Response can't be nil otherwise the reply won't be send as it turns out. - response = response ? response : [[NSData alloc] init]; - reply(response); + // If process status is not set, we still have to reply otherwise the request might hang forever. + NSData *response = nil; + if(self.processStatus) + response = self.processStatus(keyword, value); + + // Response can't be nil otherwise the reply won't be send as it turns out. + if(!response) + response = [NSData data]; + + reply(response); } - (void)progress:(NSUInteger)processedBytes total:(NSUInteger)total { From bca33c380046285f52176387c50f843dbf7bd5a5 Mon Sep 17 00:00:00 2001 From: Mento Date: Thu, 2 Jul 2015 21:59:54 +0200 Subject: [PATCH 19/56] GPGStream offset methods added. --- Source/GPGFileStream.m | 24 ++++++++++++++++++++++++ Source/GPGMemoryStream.m | 23 +++++++++++++++++++++++ Source/GPGStream.h | 5 +++++ Source/GPGStream.m | 9 ++++++++- 4 files changed, 60 insertions(+), 1 deletion(-) diff --git a/Source/GPGFileStream.m b/Source/GPGFileStream.m index 7429959..ee2fcac 100644 --- a/Source/GPGFileStream.m +++ b/Source/GPGFileStream.m @@ -148,6 +148,30 @@ - (void)seekToBeginning [_readfh seekToFileOffset:0]; } } +- (void)seekToOffset:(NSUInteger)offset { + if (_fh) { + if (offset > _fh.offsetInFile) { + @throw [NSException exceptionWithName:NSRangeException reason:[NSString stringWithFormat:@"offset %lu exceeds file length", (unsigned long)offset] userInfo:nil]; + } + [_fh truncateFileAtOffset:offset]; + } + if (_readfh) { + if (offset > _flength) { + @throw [NSException exceptionWithName:NSRangeException reason:[NSString stringWithFormat:@"offset %lu exceeds file length", (unsigned long)offset] userInfo:nil]; + } + [_readfh seekToFileOffset:offset]; + } +} +- (NSUInteger)offset { + if (_fh) { + return _fh.offsetInFile; + } + if (_readfh) { + return _readfh.offsetInFile; + } + return NSIntegerMax; +} + - (unsigned long long)length { diff --git a/Source/GPGMemoryStream.m b/Source/GPGMemoryStream.m index 8c3e965..76ebd9b 100644 --- a/Source/GPGMemoryStream.m +++ b/Source/GPGMemoryStream.m @@ -119,6 +119,29 @@ - (void)seekToBeginning if (_readableData) _readPos = 0; } +- (void)seekToOffset:(NSUInteger)offset { + if (_data) { + if (offset > _data.length) { + @throw [NSException exceptionWithName:NSRangeException reason:[NSString stringWithFormat:@"offset %lu exceeds data length", (unsigned long)offset] userInfo:nil]; + } + [_data setLength:offset]; + } + if (_readableData) { + if (offset > _readableData.length) { + @throw [NSException exceptionWithName:NSRangeException reason:[NSString stringWithFormat:@"offset %lu exceeds data length", (unsigned long)offset] userInfo:nil]; + } + _readPos = offset; + } +} +- (NSUInteger)offset { + if (_data) { + return _data.length; + } + if (_readableData) { + return _readPos; + } + return NSIntegerMax; +} - (unsigned long long)length { diff --git a/Source/GPGStream.h b/Source/GPGStream.h index 8f50e4b..3f9026d 100644 --- a/Source/GPGStream.h +++ b/Source/GPGStream.h @@ -30,6 +30,11 @@ // seek the underlying representation back to the beginning; // for a writeable stream, this truncates all data - (void)seekToBeginning; +// seek the underlying representation to the given offset; +// for a writeable stream, this truncates to the given offeset +- (void)seekToOffset:(NSUInteger)offset; +// the current offset in the stream. +- (NSUInteger)offset; // readable streams may indicate total length; // writeable streams may indicate length written; diff --git a/Source/GPGStream.m b/Source/GPGStream.m index 806abba..cab1ffe 100644 --- a/Source/GPGStream.m +++ b/Source/GPGStream.m @@ -39,7 +39,14 @@ - (void)flush { } - (void)seekToBeginning { - @throw [NSException exceptionWithName:@"NotImplementedException" reason:@"abstract method" userInfo:nil]; + @throw [NSException exceptionWithName:@"NotImplementedException" reason:@"abstract method" userInfo:nil]; +} +- (void)seekToOffset:(NSUInteger)offset { + @throw [NSException exceptionWithName:@"NotImplementedException" reason:@"abstract method" userInfo:nil]; +} +- (NSUInteger)offset { + @throw [NSException exceptionWithName:@"NotImplementedException" reason:@"abstract method" userInfo:nil]; + return NSIntegerMax; } - (unsigned long long)length { From ae864812105a157382991d4343101b62c677e68a Mon Sep 17 00:00:00 2001 From: Mento Date: Thu, 2 Jul 2015 22:02:54 +0200 Subject: [PATCH 20/56] GPGUnArmor added. --- Libmacgpg.xcodeproj/project.pbxproj | 30 +- Source/GPGGlobals.h | 4 + Source/GPGGlobals.m | 79 ++ Source/GPGPacket.h | 17 +- Source/GPGPacket.m | 440 +----------- Source/GPGUnArmor.h | 103 +++ Source/GPGUnArmor.m | 1031 +++++++++++++++++++++++++++ Source/Libmacgpg.h | 1 + 8 files changed, 1277 insertions(+), 428 deletions(-) create mode 100644 Source/GPGUnArmor.h create mode 100644 Source/GPGUnArmor.m diff --git a/Libmacgpg.xcodeproj/project.pbxproj b/Libmacgpg.xcodeproj/project.pbxproj index d13d9a4..b93eb7f 100644 --- a/Libmacgpg.xcodeproj/project.pbxproj +++ b/Libmacgpg.xcodeproj/project.pbxproj @@ -41,6 +41,8 @@ 1BD78BBC1726B6230005F251 /* Libmacgpg.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8DC2EF5B0486A6940098B216 /* Libmacgpg.framework */; }; 1BDA56BC1618A94300185C72 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4591C4D314F86D38007F6D47 /* AppKit.framework */; }; 3002C04716EE38C900D57C1E /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 3002C04316EE388B00D57C1E /* libcrypto.dylib */; }; + 301A44CD1B436405002A38E4 /* GPGUnArmor.h in Headers */ = {isa = PBXBuildFile; fileRef = 301A44CB1B436405002A38E4 /* GPGUnArmor.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 301A44CE1B436405002A38E4 /* GPGUnArmor.m in Sources */ = {isa = PBXBuildFile; fileRef = 301A44CC1B436405002A38E4 /* GPGUnArmor.m */; }; 301D5D9F178C9871003026E7 /* GPGKeyserver.h in Headers */ = {isa = PBXBuildFile; fileRef = 301D5D9D178C9871003026E7 /* GPGKeyserver.h */; }; 301D5DA0178C9871003026E7 /* GPGKeyserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 301D5D9E178C9871003026E7 /* GPGKeyserver.m */; }; 3026F4AF13A203A000F3CA02 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3026F4AE13A203A000F3CA02 /* Security.framework */; }; @@ -200,6 +202,8 @@ 1BD78BB11726B2830005F251 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainMenu.xib; sourceTree = ""; }; 3002C04316EE388B00D57C1E /* libcrypto.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libcrypto.dylib; path = usr/lib/libcrypto.dylib; sourceTree = SDKROOT; }; 3002C04516EE389100D57C1E /* libxar.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libxar.dylib; path = usr/lib/libxar.dylib; sourceTree = SDKROOT; }; + 301A44CB1B436405002A38E4 /* GPGUnArmor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGUnArmor.h; sourceTree = ""; }; + 301A44CC1B436405002A38E4 /* GPGUnArmor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGUnArmor.m; sourceTree = ""; }; 301D5D9D178C9871003026E7 /* GPGKeyserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGKeyserver.h; sourceTree = ""; }; 301D5D9E178C9871003026E7 /* GPGKeyserver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGKeyserver.m; sourceTree = ""; }; 3026F4AE13A203A000F3CA02 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; @@ -417,6 +421,7 @@ 1B72F73E157AE85B00101194 /* Additions */, 302AA377133605FE0022A371 /* GPGKey */, 307FAABB13F26BB4003FA99B /* GPGOptions */, + 306C73821B45B0F200A34730 /* GPGStream */, 30C60EEE12FF3321006BB8DA /* Libmacgpg.h */, 30FF411D12FAC6CD00F39832 /* GPGController.h */, 30FF411E12FAC6CD00F39832 /* GPGController.m */, @@ -428,6 +433,8 @@ 30FF412212FAC6CD00F39832 /* GPGGlobals.m */, 309A20F913587D5B0041E0AA /* GPGPacket.h */, 309A20FA13587D5B0041E0AA /* GPGPacket.m */, + 301A44CB1B436405002A38E4 /* GPGUnArmor.h */, + 301A44CC1B436405002A38E4 /* GPGUnArmor.m */, 30FF413112FAC6CD00F39832 /* GPGTask.h */, 30FF413212FAC6CD00F39832 /* GPGTask.m */, 1B9DB26815784DB700488353 /* GPGTaskHelper.h */, @@ -442,12 +449,6 @@ 3048830E1462B22000F2E5F4 /* GPGWatcher.m */, 304883091462B11700F2E5F4 /* DirectoryWatcher.h */, 3048830A1462B11700F2E5F4 /* DirectoryWatcher.m */, - 451D8827156A7AD900A0B890 /* GPGStream.h */, - 451D8828156A7AD900A0B890 /* GPGStream.m */, - 451D882B156A7CA300A0B890 /* GPGMemoryStream.h */, - 451D882C156A7CA300A0B890 /* GPGMemoryStream.m */, - 451D882F156A7E4900A0B890 /* GPGFileStream.h */, - 451D8830156A7E4900A0B890 /* GPGFileStream.m */, 1B9FF20E17257A69004FB017 /* GPGTaskHelperXPC.h */, 1B9FF20F17257A69004FB017 /* GPGTaskHelperXPC.m */, 301D5D9D178C9871003026E7 /* GPGKeyserver.h */, @@ -560,6 +561,19 @@ name = "Supporting Files"; sourceTree = ""; }; + 306C73821B45B0F200A34730 /* GPGStream */ = { + isa = PBXGroup; + children = ( + 451D8827156A7AD900A0B890 /* GPGStream.h */, + 451D8828156A7AD900A0B890 /* GPGStream.m */, + 451D882B156A7CA300A0B890 /* GPGMemoryStream.h */, + 451D882C156A7CA300A0B890 /* GPGMemoryStream.m */, + 451D882F156A7E4900A0B890 /* GPGFileStream.h */, + 451D8830156A7E4900A0B890 /* GPGFileStream.m */, + ); + name = GPGStream; + sourceTree = ""; + }; 307FAABB13F26BB4003FA99B /* GPGOptions */ = { isa = PBXGroup; children = ( @@ -673,6 +687,7 @@ 451D882D156A7CA300A0B890 /* GPGMemoryStream.h in Headers */, 451D8831156A7E4900A0B890 /* GPGFileStream.h in Headers */, 1BCE0CD11617A3DF0026DCFF /* NSBundle+Sandbox.h in Headers */, + 301A44CD1B436405002A38E4 /* GPGUnArmor.h in Headers */, 1B16DD21179C83F000BC1366 /* GPGTypesRW.h in Headers */, 30FF414D12FAC6CD00F39832 /* GPGTaskOrder.h in Headers */, 1BC7A50013D300A600AE57BA /* LPXTTask.h in Headers */, @@ -1075,6 +1090,7 @@ 30691AA5136AECC4004AA469 /* GPGOptions.m in Sources */, 1BC7A50113D300A600AE57BA /* LPXTTask.m in Sources */, 309A18D113E3812E0069DC0F /* GPGTransformer.m in Sources */, + 301A44CE1B436405002A38E4 /* GPGUnArmor.m in Sources */, 30A70EE613EF328000EE9CD9 /* GPGException.m in Sources */, 3048830C1462B11700F2E5F4 /* DirectoryWatcher.m in Sources */, 304883101462B22000F2E5F4 /* GPGWatcher.m in Sources */, @@ -1298,7 +1314,6 @@ GCC_OPTIMIZATION_LEVEL = 0; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = Source/Libmacgpg_Prefix.pch; - GCC_WARN_PEDANTIC = YES; GCC_WARN_SHADOW = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; HEADER_SEARCH_PATHS = ( @@ -1332,7 +1347,6 @@ GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = Source/Libmacgpg_Prefix.pch; GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)"; - GCC_WARN_PEDANTIC = YES; GCC_WARN_SHADOW = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; HEADER_SEARCH_PATHS = ( diff --git a/Source/GPGGlobals.h b/Source/GPGGlobals.h index f7edc80..c4ff5f4 100644 --- a/Source/GPGGlobals.h +++ b/Source/GPGGlobals.h @@ -239,6 +239,8 @@ enum gpgStatusCodes { #define GPGDebugLog(...) {;} #endif +#define LibmacgpgErrorDomain @"LibmacgpgErrorDomain" + #define GPG_SERVICE_NAME "GnuPG" #define JAILFREE_XPC_MACH_NAME JAILFREE_XPC_NAME @@ -250,6 +252,8 @@ NSString *localizedLibmacgpgString(NSString *key); @interface NSData (GPGExtension) - (NSString *)gpgString; - (NSArray *)gpgLines; +- (NSData *)base64DecodedData; +- (UInt32)crc24; @end @interface NSString (GPGExtension) diff --git a/Source/GPGGlobals.m b/Source/GPGGlobals.m index 8d183a4..f0879fa 100644 --- a/Source/GPGGlobals.m +++ b/Source/GPGGlobals.m @@ -205,6 +205,85 @@ - (NSArray *)gpgLines { return [lines copy]; } +- (NSData *)base64DecodedData { + NSData *result = nil; + + if (floor(NSAppKitVersionNumber) < NSAppKitVersionNumber10_9) { + SecTransformRef transform = SecDecodeTransformCreate(kSecBase64Encoding, nil); + if (!transform) { + return nil; + } + + if (SecTransformSetAttribute(transform, kSecTransformInputAttributeName, self, nil)) { + result = (NSData *)SecTransformExecute(transform, nil); + } + + CFRelease(transform); + } else { + result = [[NSData alloc] initWithBase64EncodedData:self options:NSDataBase64DecodingIgnoreUnknownCharacters]; + } + + return [result autorelease]; +} + +static const UInt32 crcTable[256] = { + 0x00000000, 0x00864cfb, 0x018ad50d, 0x010c99f6, 0x0393e6e1, 0x0315aa1a, + 0x021933ec, 0x029f7f17, 0x07a18139, 0x0727cdc2, 0x062b5434, 0x06ad18cf, + 0x043267d8, 0x04b42b23, 0x05b8b2d5, 0x053efe2e, 0x0fc54e89, 0x0f430272, + 0x0e4f9b84, 0x0ec9d77f, 0x0c56a868, 0x0cd0e493, 0x0ddc7d65, 0x0d5a319e, + 0x0864cfb0, 0x08e2834b, 0x09ee1abd, 0x09685646, 0x0bf72951, 0x0b7165aa, + 0x0a7dfc5c, 0x0afbb0a7, 0x1f0cd1e9, 0x1f8a9d12, 0x1e8604e4, 0x1e00481f, + 0x1c9f3708, 0x1c197bf3, 0x1d15e205, 0x1d93aefe, 0x18ad50d0, 0x182b1c2b, + 0x192785dd, 0x19a1c926, 0x1b3eb631, 0x1bb8faca, 0x1ab4633c, 0x1a322fc7, + 0x10c99f60, 0x104fd39b, 0x11434a6d, 0x11c50696, 0x135a7981, 0x13dc357a, + 0x12d0ac8c, 0x1256e077, 0x17681e59, 0x17ee52a2, 0x16e2cb54, 0x166487af, + 0x14fbf8b8, 0x147db443, 0x15712db5, 0x15f7614e, 0x3e19a3d2, 0x3e9fef29, + 0x3f9376df, 0x3f153a24, 0x3d8a4533, 0x3d0c09c8, 0x3c00903e, 0x3c86dcc5, + 0x39b822eb, 0x393e6e10, 0x3832f7e6, 0x38b4bb1d, 0x3a2bc40a, 0x3aad88f1, + 0x3ba11107, 0x3b275dfc, 0x31dced5b, 0x315aa1a0, 0x30563856, 0x30d074ad, + 0x324f0bba, 0x32c94741, 0x33c5deb7, 0x3343924c, 0x367d6c62, 0x36fb2099, + 0x37f7b96f, 0x3771f594, 0x35ee8a83, 0x3568c678, 0x34645f8e, 0x34e21375, + 0x2115723b, 0x21933ec0, 0x209fa736, 0x2019ebcd, 0x228694da, 0x2200d821, + 0x230c41d7, 0x238a0d2c, 0x26b4f302, 0x2632bff9, 0x273e260f, 0x27b86af4, + 0x252715e3, 0x25a15918, 0x24adc0ee, 0x242b8c15, 0x2ed03cb2, 0x2e567049, + 0x2f5ae9bf, 0x2fdca544, 0x2d43da53, 0x2dc596a8, 0x2cc90f5e, 0x2c4f43a5, + 0x2971bd8b, 0x29f7f170, 0x28fb6886, 0x287d247d, 0x2ae25b6a, 0x2a641791, + 0x2b688e67, 0x2beec29c, 0x7c3347a4, 0x7cb50b5f, 0x7db992a9, 0x7d3fde52, + 0x7fa0a145, 0x7f26edbe, 0x7e2a7448, 0x7eac38b3, 0x7b92c69d, 0x7b148a66, + 0x7a181390, 0x7a9e5f6b, 0x7801207c, 0x78876c87, 0x798bf571, 0x790db98a, + 0x73f6092d, 0x737045d6, 0x727cdc20, 0x72fa90db, 0x7065efcc, 0x70e3a337, + 0x71ef3ac1, 0x7169763a, 0x74578814, 0x74d1c4ef, 0x75dd5d19, 0x755b11e2, + 0x77c46ef5, 0x7742220e, 0x764ebbf8, 0x76c8f703, 0x633f964d, 0x63b9dab6, + 0x62b54340, 0x62330fbb, 0x60ac70ac, 0x602a3c57, 0x6126a5a1, 0x61a0e95a, + 0x649e1774, 0x64185b8f, 0x6514c279, 0x65928e82, 0x670df195, 0x678bbd6e, + 0x66872498, 0x66016863, 0x6cfad8c4, 0x6c7c943f, 0x6d700dc9, 0x6df64132, + 0x6f693e25, 0x6fef72de, 0x6ee3eb28, 0x6e65a7d3, 0x6b5b59fd, 0x6bdd1506, + 0x6ad18cf0, 0x6a57c00b, 0x68c8bf1c, 0x684ef3e7, 0x69426a11, 0x69c426ea, + 0x422ae476, 0x42aca88d, 0x43a0317b, 0x43267d80, 0x41b90297, 0x413f4e6c, + 0x4033d79a, 0x40b59b61, 0x458b654f, 0x450d29b4, 0x4401b042, 0x4487fcb9, + 0x461883ae, 0x469ecf55, 0x479256a3, 0x47141a58, 0x4defaaff, 0x4d69e604, + 0x4c657ff2, 0x4ce33309, 0x4e7c4c1e, 0x4efa00e5, 0x4ff69913, 0x4f70d5e8, + 0x4a4e2bc6, 0x4ac8673d, 0x4bc4fecb, 0x4b42b230, 0x49ddcd27, 0x495b81dc, + 0x4857182a, 0x48d154d1, 0x5d26359f, 0x5da07964, 0x5cace092, 0x5c2aac69, + 0x5eb5d37e, 0x5e339f85, 0x5f3f0673, 0x5fb94a88, 0x5a87b4a6, 0x5a01f85d, + 0x5b0d61ab, 0x5b8b2d50, 0x59145247, 0x59921ebc, 0x589e874a, 0x5818cbb1, + 0x52e37b16, 0x526537ed, 0x5369ae1b, 0x53efe2e0, 0x51709df7, 0x51f6d10c, + 0x50fa48fa, 0x507c0401, 0x5542fa2f, 0x55c4b6d4, 0x54c82f22, 0x544e63d9, + 0x56d11cce, 0x56575035, 0x575bc9c3, 0x57dd8538 +}; +- (UInt32)crc24 { + UInt32 crc = 0xB704CEL; + const UInt8 *bytes = self.bytes; + NSUInteger n = self.length; + + for (; n; bytes++, n--) { + crc = (crc << 8) ^ crcTable[((crc >> 16) & 0xff) ^ *bytes]; + } + + return crc & 0xFFFFFF; +} + + @end @implementation NSString (GPGExtension) diff --git a/Source/GPGPacket.h b/Source/GPGPacket.h index b5b8645..196835b 100644 --- a/Source/GPGPacket.h +++ b/Source/GPGPacket.h @@ -47,16 +47,15 @@ @property (nonatomic, readonly) NSArray *subpackets; // At the moment a array of dicts. Can change at any time. - + (id)packetsWithData:(NSData *)data; + (void)enumeratePacketsWithData:(NSData *)theData block:(void (^)(GPGPacket *packet, BOOL *stop))block; -+ (BOOL)isArmored:(const uint8_t)byte; -// if return nil, input stream is not armored; should be reset and used directly -+ (NSData *)unArmorFrom:(GPGStream *)input clearText:(NSData **)clearText; -+ (NSData *)unArmor:(NSData *)data; -+ (NSData *)unArmor:(NSData *)theData clearText:(NSData **)clearText; -+ (NSData *)repairPacketData:(NSData *)data; - -long crc24(char *bytes, NSUInteger length); + + + + +// Old methods, only for compatibility: + ++ (NSData *)unArmor:(NSData *)data DEPRECATED_ATTRIBUTE; ++ (NSData *)unArmor:(NSData *)data clearText:(NSData **)clearText DEPRECATED_ATTRIBUTE; @end diff --git a/Source/GPGPacket.m b/Source/GPGPacket.m index cf4dbab..272edce 100644 --- a/Source/GPGPacket.m +++ b/Source/GPGPacket.m @@ -24,6 +24,7 @@ #include #include #include +#import "GPGUnArmor.h" #define COMMON_DIGEST_FOR_OPENSSL #include @@ -39,42 +40,20 @@ -@interface GPGPacket (Private) + +@interface GPGPacket () - (id)initWithBytes:(const uint8_t *)bytes length:(NSUInteger)dataLength nextPacketStart:(const uint8_t **)nextPacket; @end -typedef enum { - state_searchStart = 0, - state_parseStart, - state_waitForText, - state_waitForEnd -} myState; - @implementation GPGPacket @synthesize type, data, keyID, fingerprint, publicKeyAlgorithm, symetricAlgorithm, hashAlgorithm, signatureType, subpackets; -static const char armorBeginMark[] = "\n-----BEGIN PGP "; -const int armorBeginMarkLength = 16; -static const char armorEndMark[] = "\n-----END PGP "; -const int armorEndMarkLength = 14; -static const char *armorTypeStrings[] = { //The first byte contains the length of the string. - "\x13SIGNED MESSAGE-----", - "\x0cMESSAGE-----", - "\x15PUBLIC KEY BLOCK-----", - "\x0eSIGNATURE-----", - "\021ARMORED FILE-----", - "\x16PRIVATE KEY BLOCK-----", - "\x15SECRET KEY BLOCK-----" -}; -const int armorTypeStringsCount = 7; - - + (id)packetsWithData:(NSData *)theData { __block NSMutableArray *packets = [NSMutableArray array]; @@ -86,9 +65,18 @@ + (id)packetsWithData:(NSData *)theData { return packets; } - + (void)enumeratePacketsWithData:(NSData *)theData block:(void (^)(GPGPacket *packet, BOOL *stop))block { - theData = [self unArmor:theData]; + + if (theData.isArmored) { + GPGMemoryStream *stream = [GPGMemoryStream memoryStreamForReading:theData]; + GPGUnArmor *unArmor = [GPGUnArmor unArmorWithGPGStream:stream]; + + [unArmor decodeAll]; + + theData = unArmor.data; + } + + if (theData.length < 10) { return; } @@ -117,7 +105,6 @@ + (void)enumeratePacketsWithData:(NSData *)theData block:(void (^)(GPGPacket *pa } } - - (id)initWithBytes:(const uint8_t *)bytes length:(NSUInteger)dataLength nextPacketStart:(const uint8_t **)nextPacket { if (!(self = [super init])) { return nil; @@ -348,405 +335,36 @@ - (void)dealloc { [super dealloc]; } - -+ (NSData *)unArmor:(NSData *)theData { - return [self unArmor:theData clearText:nil]; -} - -+ (NSData *)unArmor:(NSData *)theData clearText:(NSData **)clearText { - GPGMemoryStream *input = [GPGMemoryStream memoryStreamForReading:theData]; - NSData *unarmored = [self unArmorFrom:input clearText:clearText]; - if ([unarmored length]) - return unarmored; - return theData; -} - -+ (NSData *)unArmorFrom:(GPGStream *)input clearText:(NSData **)clearText { - // This methode decodes any PGP-Message and return the decoded data and the clear-text, if any. - - if ([input length] < 50 || ![self isArmored:[input peekByte]]) { - return nil; // Don't try to decode too short messages. - } - - NSData *theData = [input readAllData]; - const char *bytes = [theData bytes]; - NSUInteger dataLength = [theData length]; - const char *readPos, *endPos; - const char *textStart, *textEnd; - int newlineCount, armorType, maxCRToAdd = 0; - BOOL haveClearText = NO; - NSMutableData *decodedData = [NSMutableData data]; - myState state = state_searchStart; - BOOL failed = NO; - BOOL containsColon = YES; - const char *oldReadPos; - - - // Allocate space and copy the message, so we can manipulate the message data. - char *mutableBytes = malloc(dataLength); - if (!mutableBytes) { - NSLog(@"unArmorFrom:clearText: malloc failed!"); - failed = YES; - goto endOfBuffer; - } - memcpy(mutableBytes, bytes, dataLength); - char *mutableReadPos = mutableBytes; - endPos = mutableBytes + dataLength; - - - - - - // Replace \r and \0 by \n. - for (; mutableReadPos < endPos; mutableReadPos++) { - switch (mutableReadPos[0]) { - case '\r': - if (mutableReadPos[1] != '\n') { - mutableReadPos[0] = '\n'; - } - break; - case 0: - mutableReadPos[0] = '\n'; - case '\n': - maxCRToAdd++; - default: - break; - } - } - readPos = bytes = mutableBytes; - - - // Check if the message starts with a begin-mark without \n. "-----BEGIN PGP ". - if (memcmp(armorBeginMark+1, readPos, armorBeginMarkLength - 1) == 0) { - state = state_parseStart; // so let's search for the beginning of the base64 data. - readPos += armorBeginMarkLength - 1; +- (NSString *)description { + if (!description) { + description = [[NSString alloc] initWithFormat:@"GPGPacket type: %i, keyID %@", self.type, self.keyID]; } - - - for (;readPos < endPos - 25; readPos++) { - switch (state) { - case state_searchStart: // Look for a begin-mark. "\n-----BEGIN PGP ". - readPos = lm_memmem(readPos, endPos - readPos - 20, armorBeginMark, armorBeginMarkLength); - if (!readPos) { - goto endOfBuffer; - } - readPos += armorBeginMarkLength; - // Fall through. - case state_parseStart: - canRead(40); - - if (haveClearText) { - // We have a clear-text part. Return it using the clearText variable. - - armorType = 3; - if (memcmp(armorTypeStrings[armorType]+1, readPos, armorTypeStrings[armorType][0])) { - GPGDebugLog(@"GPGPacket unarmor: \"-----BEGIN PGP SIGNATURE-----\" expected but not found.") - goto endOfBuffer; - } - textEnd = readPos - armorBeginMarkLength; - - char *clearBytes = malloc(textEnd - textStart + maxCRToAdd); - if (!clearBytes) { - NSLog(@"unArmorFrom:clearText: malloc failed!"); - failed = YES; - goto endOfBuffer; - } - if (textStart[0] == '-' && textStart[1] == ' ') { - textStart += 2; - } - readPos = textStart; - char *clearBytesPtr = clearBytes; - const char *newlinePos; - while ((newlinePos = memchr(readPos, '\n', textEnd - readPos))) { - readPos = newlinePos - 1; - if (*readPos == '\r') { // Remove \n as well as \r\n. - readPos--; - } - - while (*readPos == ' ' || *readPos == '\t') { // Remove spaces and tabs from the end of lines. - readPos--; - } - - readPos++; - memcpy(clearBytesPtr, textStart, readPos - textStart); - clearBytesPtr += readPos - textStart; - - clearBytesPtr[0] = '\r'; - clearBytesPtr[1] = '\n'; - clearBytesPtr += 2; - - readPos = newlinePos + 1; - if (readPos[0] == '-' && readPos[1] == ' ') { - readPos += 2; - } - textStart = readPos; - } - while (textEnd[-1] == ' ' || textEnd[-1] == '\t') { // Remove spaces and tabs from the end of the last line. - textEnd--; - } - - // Copy the clear-text... - memcpy(clearBytesPtr, textStart, textEnd - textStart); - clearBytesPtr += textEnd - textStart; - - // and return it using *clearText. - *clearText = [NSData dataWithBytes:clearBytes length:clearBytesPtr - clearBytes]; - free(clearBytes); - haveClearText = NO; - - // Set readPos to the next begin-mark. - readPos = textEnd + armorBeginMarkLength + armorTypeStrings[armorType][0]; - // Wait for base64 data. - state = state_waitForText; - } else { - // Detect the message type. - BOOL found = NO; - for (armorType = 0; armorType < armorTypeStringsCount; armorType++) { // Try all types. - if (memcmp(armorTypeStrings[armorType]+1, readPos, armorTypeStrings[armorType][0]) == 0) { - readPos += armorTypeStrings[armorType][0] - 1; - - if (armorType == 0) { //Is "-----BEGIN PGP SIGNED MESSAGE-----". - if (clearText) { // If the user don't want the clear text, ignore it. - haveClearText = YES; - found = YES; - } - } else { - found = YES; - } - break; - } - } - if (!found) { - // Isn't a known message type. Let's look for the next begin-mark. - state = state_searchStart; - break; - } - state = state_waitForText; - readPos++; - } - newlineCount = 0; - case state_waitForText: - // Wait for base64/clear-text. - switch (*readPos) { - case '\n': - newlineCount++; - if (newlineCount == 2) { - // In a normal message, the base64/clear-text comes after 2 new lines. - state = haveClearText ? state_searchStart : state_waitForEnd; - textStart = readPos + 1; - } else if (haveClearText == NO) { // Perform the following check only, if we are looking for base64. And NOT for clear-text. - // In some malformed messages, the 2 new lines are missing. - // So we look for the first line, without a colon ":", and treat this as the base64 start. - if (containsColon) { - containsColon = NO; - oldReadPos = readPos; - } else { - state = state_waitForEnd; - readPos = oldReadPos; - textStart = readPos + 1; - } - } - case '\r': - case ' ': - case '\t': - break; - case ':': - containsColon = YES; - //no break - default: - newlineCount = 0; - } - break; - case state_waitForEnd: { - // Search for the end of the base64 data. - - // Do we have a crc? - textEnd = lm_memmem(readPos, endPos - readPos, "\n=", 2); - const char *crcPos = NULL; - if (textEnd) { - textEnd++; - crcPos = textEnd + 1; - readPos = textEnd + 5; - } - - // Look for the end-mark. - oldReadPos = readPos; - readPos = lm_memmem(readPos, endPos - readPos, armorEndMark, armorEndMarkLength); - if (!readPos) { - readPos = lm_memmem(oldReadPos, endPos - oldReadPos, armorEndMark + 1, armorEndMarkLength - 1); - - if (!readPos) { - goto endOfBuffer; - } - readPos--; - } - - if (!textEnd) { - // If the text-end isn't set by the crc, set it now. - textEnd = readPos + 1; - } - - - readPos += armorEndMarkLength; - - int length = armorTypeStrings[armorType][0]; - canRead(length); - // Check for the type strng. It's something like "SIGNED MESSAGE-----". - if (memcmp(armorTypeStrings[armorType]+1, readPos, armorTypeStrings[armorType][0]) != 0) { - goto endOfBuffer; - } - - - // Allocate a buffer for the decoded data. - length = (textEnd - textStart) * 3 / 4; - char *binaryBuffer = malloc(length); - if (!binaryBuffer) { - goto endOfBuffer; - } - - // Decode base64. - BIO *filter = BIO_new(BIO_f_base64()); - BIO *bio = BIO_new_mem_buf((void *)textStart, textEnd - textStart); - bio = BIO_push(filter, bio); - length = BIO_read(bio, binaryBuffer, length); - BIO_free_all(bio); - - - if (crcPos) { - // We have a crc, so let's check it. - uint32_t crc1, crc2; - uint8_t crcBuffer[3]; - - // Decode crc. - filter = BIO_new(BIO_f_base64()); - bio = BIO_new_mem_buf((void *)crcPos, 6); - bio = BIO_push(filter, bio); - int crcLength = BIO_read(bio, crcBuffer, 3); - BIO_free_all(bio); - - if (crcLength != 3) { - // Decoded crc is malformed. - NSLog(@"unArmorFrom:clearText: %@", localizedLibmacgpgString(@"CRC Error")); - failed = YES; - goto endOfBuffer; - } - - // crc array to integer. - crc1 = (crcBuffer[0] << 16) + (crcBuffer[1] << 8) + crcBuffer[2]; - - // Calculate crc of the decoded base64 data. - crc2 = crc24(binaryBuffer, length); - - // Check crc. - if (crc1 != crc2) { - NSLog(@"unArmorFrom:clearText: %@", localizedLibmacgpgString(@"CRC Error")); - failed = YES; - goto endOfBuffer; - } - } - - if (length > 0) { - // Append decoded base64. - [decodedData appendBytes:binaryBuffer length:length]; - } - free(binaryBuffer); - - - readPos += armorTypeStrings[armorType][0] - 1; - state = state_searchStart; - break; } - } - } //for - - -endOfBuffer: - free(mutableBytes); - if (failed) { - return nil; - } - return decodedData; + return [[description retain] autorelease]; } -long crc24(char *bytes, NSUInteger length) { - long crc = 0xB704CEL; - while (length--) { - crc ^= (*bytes++) << 16; - for (int i = 0; i < 8; i++) { - crc <<= 1; - if (crc & 0x1000000) - crc ^= 0x1864CFBL; - } - } - return crc & 0xFFFFFFL; -} +// Old methods, only for compatibility. -+ (BOOL)isArmored:(const uint8_t)byte { - if (!(byte & 0x80)) { - return YES; - } - switch ((byte & 0x40) ? (byte & 0x3F) : ((byte & 0x3C) >> 2)) { - case GPGPublicKeyEncryptedSessionKeyPacket: - case GPGSignaturePacket: - case GPGSymmetricEncryptedSessionKeyPacket: - case GPGOnePassSignaturePacket: - case GPGPublicKeyPacket: - case GPGPublicSubkeyPacket: - case GPGSecretKeyPacket: - case GPGSecretSubkeyPacket: - case GPGCompressedDataPacket: - case GPGSymmetricEncryptedDataPacket: - case GPGMarkerPacket: - case GPGLiteralDataPacket: - case GPGTrustPacket: - case GPGUserIDPacket: - case GPGUserAttributePacket: - case GPGSymmetricEncryptedProtectedDataPacket: - case GPGModificationDetectionCodePacket: - return NO; - } - return YES; +// if return nil, input stream is not armored; should be reset and used directly ++ (NSData *)unArmor:(NSData *)data { + return [self unArmor:data clearText:nil]; } - - - -+ (NSData *)repairPacketData:(NSData *)theData { - const char *bytes = [theData bytes]; - NSUInteger dataLength = [theData length]; - - if (dataLength < 50 || ![self isArmored:*bytes]) { - return theData; - } - - const char *readPos = bytes; - const char *endPos = bytes + dataLength; - NSMutableData *repairedData = [NSMutableData data]; ++ (NSData *)unArmor:(NSData *)data clearText:(NSData **)clearText { + GPGMemoryStream *stream = [GPGMemoryStream memoryStreamForReading:data]; + GPGUnArmor *unArmor = [GPGUnArmor unArmorWithGPGStream:stream]; + [unArmor decodeAll]; - readPos = lm_memmem(readPos, endPos - readPos - 20, armorBeginMark, armorBeginMarkLength); - if (!readPos) { - goto endOfBuffer; + if (clearText) { + *clearText = unArmor.clearText; } - //TODO - - - - - -endOfBuffer: - return repairedData; + return unArmor.data; } -- (NSString *)description { - if (!description) { - description = [[NSString alloc] initWithFormat:@"GPGPacket type: %i, keyID %@", self.type, self.keyID]; - } - return [[description retain] autorelease]; -} @end diff --git a/Source/GPGUnArmor.h b/Source/GPGUnArmor.h new file mode 100644 index 0000000..d6a387f --- /dev/null +++ b/Source/GPGUnArmor.h @@ -0,0 +1,103 @@ +#import +#import +#import + + + +@interface GPGUnArmor : NSObject { + GPGStream *stream; + + // Cache + NSData *cacheData; + const UInt8 *cacheBytes; + NSUInteger cacheIndex; + NSUInteger cacheEnd; + NSUInteger streamOffset; + + + // State vars for parsing. + NSMutableData *base64Data; + BOOL preferAlternative; + NSUInteger alternativeStart; + BOOL invalidCharInLine; + + NSInteger equalsAdded; + BOOL haveCRC; + UInt8 crcBytes[4]; + + + // Properties + NSError *error; + NSData *clearText; + NSData *data; + BOOL eof; +} + +@property (nonatomic, readonly, strong) NSError *error; +@property (nonatomic, readonly, strong) NSData *clearText; +@property (nonatomic, readonly, strong) NSData *data; +@property (nonatomic, readonly) BOOL eof; + + +/** + * Decodes and returns all packets in the stream. + * If the input is not armored, it returns the original data from the stream. + * + * @param clear Upon return contains the clear-text, if any. Pass NULL if you do not want the clear-text. + * @param error If an error occurs, upon return contains an NSError object that describes the problem. Pass NULL if you do not want error information. + * @return A GPGStream containing the decoded data or the original stream, if the input wasn't armored. + */ ++ (GPGStream *)unArmor:(GPGStream *)stream clearText:(NSData **)clearText error:(NSError **)error; + +/** + * Decodes and returns all packets in the stream. + * If the input is not armored, it returns the original data from the stream. + * + * @param clear Upon return contains the clear-text, if any. Pass NULL if you do not want the clear-text. + * @return A GPGStream containing the decoded data or the original stream, if the input wasn't armored. + */ ++ (GPGStream *)unArmor:(GPGStream *)stream clearText:(NSData **)clearText; + +/** + * Decodes and returns all packets in the stream. + * If the input is not armored, it returns the original data from the stream. + * + * @return A GPGStream containing the decoded data or the original stream, if the input wasn't armored. + */ ++ (GPGStream *)unArmor:(GPGStream *)stream; + + + + + + +void a() { + [NSFileHandle fileHandleForReadingFromURL:nil error:nil]; +} + ++ (instancetype)unArmorWithGPGStream:(GPGStream *)theStream; +- (instancetype)initWithGPGStream:(GPGStream *)stream; + +/** + * Decodes and returns the next armored packet in the stream. + * + * @return The decoded data or NULL if the input wasn't armored. + */ +- (NSData *)decodeNext; + +/** + * Decodes and returns all packets in the stream. + * + * @return The decoded data or NULL if the input wasn't armored. + */ +- (NSData *)decodeAll; + +@end + +@interface GPGStream (IsArmoredExtension) +- (BOOL)isArmored; +@end +@interface NSData (IsArmoredExtension) +- (BOOL)isArmored; +@end + diff --git a/Source/GPGUnArmor.m b/Source/GPGUnArmor.m new file mode 100644 index 0000000..3e6be85 --- /dev/null +++ b/Source/GPGUnArmor.m @@ -0,0 +1,1031 @@ +#import "GPGUnArmor.h" +#import "GPGException.h" +#import "GPGMemoryStream.h" + +const NSUInteger cacheSize = 1000; + +typedef enum { + stateSearchBegin = 0, + stateParseBegin, + stateSearchBase64, + stateSearchClearText, + stateParseClearText, + stateSearchSeperator, + stateParseBase64, + stateParseEnd, + stateParseCRC, + stateTrashEnd, + stateError, + stateEOF, + stateFinish +} parsingState; + + + +@interface GPGUnArmor () +@property (nonatomic, readwrite, strong) NSError *error; +@property (nonatomic, readwrite, strong) NSData *clearText; +@property (nonatomic, readwrite, strong) NSData *data; +@end + + + +@implementation GPGUnArmor +@synthesize error, clearText, data, eof; + + +#pragma Public methods + ++ (GPGStream *)unArmor:(GPGStream *)stream clearText:(NSData **)clearText error:(NSError **)error { + if (!stream.isArmored) { + return stream; + } + + GPGUnArmor *unArmor = [[self alloc] initWithGPGStream:stream]; + + [unArmor decodeAll]; + + if (clearText) { + *clearText = unArmor.clearText; + } + if (error) { + *error = unArmor.error; + } + GPGMemoryStream *output = [GPGMemoryStream memoryStreamForReading:unArmor.data]; + + [unArmor release]; + + return output; +} ++ (GPGStream *)unArmor:(GPGStream *)stream clearText:(NSData **)clearText { + return [self unArmor:stream clearText:clearText error:nil]; +} ++ (GPGStream *)unArmor:(GPGStream *)stream { + return [self unArmor:stream clearText:nil error:nil]; +} + + +- (NSData *)decodeNext { + // The main decoding methode. + // Mainly it invokes the different methods. + + self.error = nil; + self.clearText = nil; + self.data = nil; + + + parsingState state = stateSearchBegin; + BOOL running = YES; + + while (running) { + switch (state) { + case stateSearchBegin: + state = [self searchBegin]; + break; + case stateParseBegin: + state = [self parseBegin]; + break; + case stateSearchBase64: + state = [self searchBase64]; + break; + case stateSearchSeperator: + state = [self searchSeperator]; + break; + case stateParseBase64: + state = [self parseBase64]; + break; + case stateParseCRC: + state = [self parseCRC]; + break; + case stateSearchClearText: + state = [self searchClearText]; + break; + case stateParseClearText: + state = [self parseClearText]; + break; + case stateParseEnd: + state = [self parseEnd]; + break; + case stateTrashEnd: + state = [self trashEnd]; + break; + + case stateError: + running = NO; + break; + case stateEOF: + eof = YES; + running = NO; + break; + case stateFinish: + running = NO; + break; + } + } + + + return self.data; +} + +- (NSData *)decodeAll { + + NSMutableData *result = [NSMutableData data]; + NSData *clearTextResult = nil; + + + while (!eof) { + [self decodeNext]; + if (data.length > 0) { + [result appendData:data]; + } + if (clearText.length > 0) { + clearTextResult = self.clearText; + } + } + + self.clearText = clearTextResult; + self.data = result; + + return self.data; +} + + + + +#pragma Operation methods + + + +- (parsingState)searchBegin { + // Called at the beginning or after parseEnd if it has no data to decode. + // Locate "-----BEGIN PGP " in the stream. + + const char beginMark[] = "BEGIN PGP "; + NSInteger byte; + NSInteger dashes = 0; + NSInteger beginMarkIndex = 0; + + while ((byte = [self nextByte]) >= 0) { + if (dashes < 5) { + if (byte == '-') { + dashes++; + } else { + dashes = 0; + } + } else { + if (byte == '-' && beginMarkIndex == 0) { + // Ignore + } else if (byte == beginMark[beginMarkIndex]) { + beginMarkIndex++; + if (beginMark[beginMarkIndex] == 0) { + return stateParseBegin; + } + } else { + beginMarkIndex = 0; + if (byte == '-') { + dashes = 1; + } else { + dashes = 0; + } + } + } + } + + return stateEOF; +} + + +- (parsingState)parseBegin { + // Called after searchBegin. + // Parse the armor header line. + // Succeess: searchClearText or searchBase64. + // Fail: searchBegin. + + NSInteger byte; + NSInteger dashes = 0; + NSInteger headerLength = 0; + + + UInt32 headerType = 0xFFFFFFFF; + /* + Header types: + 0x99FC7209 SIGNED MESSAGE + 0x7607319A MESSAGE + 0x72E896AA PUBLIC KEY BLOCK + 0x15B5E051 SIGNATURE + 0xAA272B8F ARMORED FILE + 0xD9AC365B PRIVATE KEY BLOCK + 0x4E6B6AC2 SECRET KEY BLOCK + */ + + invalidCharInLine = NO; + + while ((byte = [self nextByte]) >= 0) { + + switch (byte) { + case '-': + dashes++; + if (dashes == 5) { + if (headerType == 0x99FC7209) { + // SIGNED MESSAGE: Clear-text follows. + return stateSearchClearText; + } + return stateSearchBase64; + } + break; + case 'A' ... 'G': + case 'I': + case 'K' ... 'P': + case 'R' ... 'V': + case 'Y': + case ' ': + headerLength++; + if (dashes > 0 || headerLength > 17) { + return stateSearchBegin; + } + headerType = crc32_tab[(headerType ^ byte) & 0xFF] ^ (headerType >> 8); + break; + default: + // Invalid char. + return stateSearchBegin; + break; + } + } + + return stateEOF; +} + + +- (parsingState)searchClearText { + // Called after parseBegin. + // Wait for the clear-text. + // Success: parseClearText. + + NSInteger byte; + NSInteger newlineCount = 0; + + while ((byte = [self nextByte]) >= 0) { + switch (byte) { + case '\n': + newlineCount++; + if (newlineCount == 2) { + // The clear-text comes after 2 new lines. + return stateParseClearText; + } + case '\r': + case ' ': + case '\t': + case 0: + break; + default: + newlineCount = 0; + break; + } + + } + + return stateEOF; +} + + +- (parsingState)parseClearText { + // Called after searchClearText. + // Parse the clear-text and store it in self.clearText. + // Success: parseBegin. + + const char beginMark[] = "BEGIN PGP "; + NSInteger byte; + NSInteger dashes = -1; + NSInteger beginMarkIndex = 0; + NSMutableData *tempClearData = [[NSMutableData alloc] init]; + + + while ((byte = [self nextByte]) >= 0) { + UInt8 theByte = (UInt8)byte; + [tempClearData appendBytes:&theByte length:1]; + + if (dashes == -1) { + if (byte == '\n') { + dashes = 0; + } + } else if (dashes < 5) { + if (byte == '-') { + dashes++; + } else { + dashes = -1; + } + } else { + if (byte == beginMark[beginMarkIndex]) { + beginMarkIndex++; + if (beginMark[beginMarkIndex] == 0) { + NSUInteger length = tempClearData.length - 16; + [tempClearData setLength:length]; + + self.clearText = [self parseClearTextData:tempClearData]; + + [tempClearData release]; + + return stateParseBegin; + } + } else { + beginMarkIndex = 0; + if (byte == '\n') { + dashes = 0; + } else { + dashes = -1; + } + } + } + } + + [tempClearData release]; + + return stateEOF; +} + + +- (parsingState)searchSeperator { + // Called after searchBase64, parseBase64, parseCRC or parseEnd. + // Locate the next seperator (one of \n \r \t \0 or " "). + // Success: searchBase64. + + NSInteger byte; + + while ((byte = [self nextByte]) >= 0) { + switch (byte) { + case '\n': + case '\r': + case ' ': + case '\t': + case 0: + return stateSearchBase64; + } + } + + return stateEOF; +} + + +- (parsingState)searchBase64 { + // Called after parseBegin, searchSeperator, parseCRC or parseEnd. + // Locate the first byte of the base64 encoded data. + // Success: parseBase64. + // Fail: searchSeperator or parseEnd. + + NSInteger byte; + + while ((byte = [self nextByte]) >= 0) { + switch (byte) { + case '\n': + case '\r': + case ' ': + case '\t': + case 0: + break; + case 'g'...'z': + case '0'...'9': + case '+': + case '/': + // The first base64 char, can only be one of them, + // because the first bit of a packet is 1. + + [base64Data setLength:0]; + [base64Data appendBytes:&byte length:1]; + return stateParseBase64; + case '-': + return stateParseEnd; + default: + return stateSearchSeperator; + } + } + + return stateEOF; +} + + +- (parsingState)parseBase64 { + // Called after searchBase64. + // Store the base64 encodeed data into base64Data. + // Success: parseCRC or parseEnd. + // Fail: searchSeperator. + + NSInteger byte; + + alternativeStart = 0; + haveCRC = NO; + BOOL isLineInvalid = invalidCharInLine; + + + while ((byte = [self nextByte]) >= 0) { + switch (byte) { + case 'a'...'z': + case 'A'...'Z': + case '0'...'9': + case '+': + case '/': + [base64Data appendBytes:&byte length:1]; + break; + case '\n': + if (alternativeStart == 0) { + alternativeStart = base64Data.length; + preferAlternative = isLineInvalid; + isLineInvalid = NO; + } + break; + case '\r': + case ' ': + case '\t': + case 0: + break; + case '-': + return stateParseEnd; + case '=': + return stateParseCRC; + default: + return stateSearchSeperator; + } + + } + + return stateEOF; +} + + +- (parsingState)parseCRC { + // Called after parseBase64. + // Store the base64 encoded crc24 into crcBytes. + // Success: parseEnd. + // Fail: searchSeperator or searchBase64. + + NSInteger byte; + UInt8 lastByte = '='; + + NSInteger crcLength = -1; + equalsAdded = 0; + + + while ((byte = [self nextByte]) >= 0) { + if (crcLength == -1) { + switch (byte) { + case '\n': + case '\r': + case ' ': + case '\t': + case 0: + break; + case '=': + equalsAdded++; + if (equalsAdded == 2) { + crcLength = 0; + } + [base64Data appendBytes:"=" length:1]; + break; + case 'a'...'z': + case 'A'...'Z': + case '0'...'9': + case '+': + case '/': + if (lastByte != '=') { + return stateSearchSeperator; + } + crcBytes[0] = (UInt8)byte; + crcLength = 1; + break; + case '-': + equalsAdded++; + [base64Data appendBytes:"=" length:1]; + return stateParseEnd; + default: + return stateSearchSeperator; + break; + } + lastByte = (UInt8)byte; + } else if (crcLength < 4) { + switch (byte) { + case '\n': + case '\r': + case ' ': + case '\t': + case 0: + return stateSearchBase64; + case 'a'...'z': + case 'A'...'Z': + case '0'...'9': + case '+': + case '/': + crcBytes[crcLength] = (UInt8)byte; + crcLength++; + break; + default: + return stateSearchSeperator; + break; + } + lastByte = (UInt8)byte; + } else { + switch (byte) { + case '\n': + case '\r': + case ' ': + case '\t': + case 0: + break; + case '-': + if (crcLength == 4) { + haveCRC = YES; + } else { + NSLog(@"unArmor: 'CRC malformed'"); + self.error = [NSError errorWithDomain:LibmacgpgErrorDomain code:GPGErrorChecksumError userInfo:nil]; + } + return stateParseEnd; + default: + return stateSearchSeperator; + } + } + } + + return stateEOF; +} + + +- (parsingState)parseEnd { + // Called after searchBase64, parseBase64 or parseCRC. + // Locate the end of the armored data. + // Decode the base64 data and check the crc. + // Store the decoded data in self.data. + // Success: trashEnd. + // Fail: searchSeperator, searchBase64, searchBegin. + + const char endMark[] = "----END PGP "; + NSInteger byte; + NSInteger endMarkIndex = 0; + BOOL found = NO; + + + while ((byte = [self nextByte]) >= 0) { + if (byte == endMark[endMarkIndex]) { + endMarkIndex++; + if (endMark[endMarkIndex] == 0) { + found = YES; + break; + } + } else { + haveCRC = NO; + endMarkIndex = 0; + switch (byte) { + case '\n': + case '\r': + case ' ': + case '\t': + case 0: + return stateSearchBase64; + default: + return stateSearchSeperator; + } + } + } + if (!found) { + return stateEOF; + } + + + UInt32 crc; + if (haveCRC) { + NSData *decodedCRC = nil; + + decodedCRC = [[NSData dataWithBytes:crcBytes length:4] base64DecodedData]; + + if (decodedCRC.length == 3) { + const uint8_t *crcBuffer = decodedCRC.bytes; + + // crc array to integer. + crc = (crcBuffer[0] << 16) + (crcBuffer[1] << 8) + crcBuffer[2]; + } else { + haveCRC = NO; + // Decoded crc is malformed. + NSLog(@"unArmor: 'CRC decoding failed'"); + self.error = [NSError errorWithDomain:LibmacgpgErrorDomain code:GPGErrorChecksumError userInfo:nil]; + } + } + + + NSData *preferedData = nil, *secondData = nil; + + if (alternativeStart && base64Data.length % 4 == 0 && (base64Data.length - alternativeStart) % 4 != 0) { + preferAlternative = NO; + } + + [base64Data appendBytes:"==" length:2 - equalsAdded]; + + if (alternativeStart) { + NSUInteger newLength = (base64Data.length - alternativeStart) & ~3; + NSData *alternativeData = [base64Data subdataWithRange:NSMakeRange(alternativeStart, newLength)]; + + if (preferAlternative) { + preferedData = alternativeData; + } else { + secondData = alternativeData; + } + } + + [base64Data setLength:base64Data.length & ~3]; + + + if (preferedData) { + secondData = base64Data; + } else { + preferedData = base64Data; + } + + + + NSData *result = nil; + if ([self isDataBase64EncodedPGP:preferedData]) { + result = [preferedData base64DecodedData]; + } + NSData *alternativeResult = result; + + if (haveCRC && result) { + // Calculate crc of the decoded base64 data. + UInt32 dataCRC = result.crc24; + + if (crc != dataCRC) { + result = nil; + } + } + + if (!result) { + if ([self isDataBase64EncodedPGP:secondData]) { + result = [secondData base64DecodedData]; + } + if (!result) { + NSLog(@"unArmor: 'No Data'"); + self.error = [NSError errorWithDomain:LibmacgpgErrorDomain code:GPGErrorNoData userInfo:nil]; + return stateSearchBegin; + } + + if (haveCRC) { + // Calculate crc of the decoded base64 data. + UInt32 dataCRC = result.crc24; + + if (crc != dataCRC) { + if (alternativeResult) { + result = alternativeResult; + } + + NSLog(@"unArmor: 'CRC Error'"); + self.error = [NSError errorWithDomain:LibmacgpgErrorDomain code:GPGErrorChecksumError userInfo:nil]; + } + } + } + + self.data = result; + + return stateTrashEnd; +} + + +- (parsingState)trashEnd { + // Called after parseEnd. + // Read the stream to the end of the armor wrapping. + // Success: stateFinish. + + NSInteger byte; + NSInteger endMarkIndex = 0; + NSInteger dashes = 0; + + while ((byte = [self nextByte]) >= 0) { + endMarkIndex++; + if (byte == '-') { + dashes++; + } + if (endMarkIndex == 22 || dashes == 5) { + [stream seekToOffset:streamOffset]; + return stateFinish; + } + } + + return stateEOF; +} + + + +#pragma Helper + +static UInt32 crc32_tab[] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + + +- (NSData *)parseClearTextData:(NSData *)theData { + NSInteger length = theData.length; + const char *bytes = theData.bytes; + + + NSMutableData *result = [NSMutableData dataWithCapacity:length]; + if (!result) { + NSLog(@"parseClearText: dataWithCapacity failed!"); + return nil; + } + + + NSData *newLine = [NSData dataWithBytesNoCopy:"\n" length:1 freeWhenDone:NO]; + NSRange range = NSMakeRange(0, length); + + + while (range.location < length) { + NSRange foundRange = [theData rangeOfData:newLine options:0 range:range]; + if (foundRange.length == 0) { + foundRange.location = length; + } + + range.length = foundRange.location - range.location; + + // Remove leading "- ". + if (range.length >= 2) { + if (bytes[range.location] == '-' && bytes[range.location + 1] == ' ' ) { + range.location += 2; + range.length -= 2; + } + } + + // Remove trailing unprintable characters. + BOOL stop = NO; + while (range.length > 0 && stop == NO) { + switch (bytes[range.location + range.length - 1]) { + case 0: + case '\t': + case '\r': + case ' ': + range.length--; + break; + default: + stop = YES; + break; + } + } + + [result appendBytes:bytes + range.location length:range.length]; + [result appendBytes:"\r\n" length:2]; + + + range.location = foundRange.location + 1; + range.length = length - range.location; + } + + if (result.length >= 2) { + result.length = result.length - 2; + } + + return result; +} + + +- (BOOL)isDataBase64EncodedPGP:(NSData *)theData { + if (theData.length < 8) { + return NO; + } + NSData *decoded = [[theData subdataWithRange:NSMakeRange(0, 8)] base64DecodedData]; + if (decoded.length != 6) { + return NO; + } + const UInt8 *bytes = decoded.bytes; + + if ((bytes[0] & 0x80) == 0) { + return NO; + } + + NSUInteger length; + UInt8 tag; + + if (bytes[0] & 0x40) { + // New Format + tag = bytes[0] & 0x3F; + + if (bytes[1] < 192) { + length = bytes[1] + 2; + } else if (bytes[1] < 224) { + length = ((bytes[1] - 192) << 8) + bytes[2] + 192 + 3; + } else if (bytes[1] < 255) { + length = 1 << (bytes[1] & 0x1F); + if (length < 512) { + return NO; + } + switch (tag) { + case 8: + case 9: + case 11: + case 18: + break; + default: + return NO; + } + length += 2; + } else { + length = (bytes[2] << 24) + (bytes[3] << 16) + (bytes[4] << 8) + bytes[5] + 6; + } + } else { + // Old Format + + tag = (bytes[0] & 0x3C) >> 2; + + + switch (bytes[0] & 3) { + case 0: + length = bytes[1] + 2; + break; + case 1: + length = (bytes[1] << 8) + bytes[2] + 3; + break; + case 2: + length = (bytes[1] << 24) + (bytes[2] << 16) + (bytes[3] << 8) + bytes[4] + 5; + break; + default: + return NO; + } + } + + if (theData.length < length) { + return NO; + } + + switch (tag) { + case 1 ... 14: + case 17 ... 19: + break; + default: + return NO; + } + + return YES; +} + + + +- (NSInteger)nextByte { + if (cacheIndex == cacheSize) { + cacheIndex = 0; + cacheData = [stream readDataOfLength:cacheSize]; + + NSUInteger cacheDataLength = cacheData.length; + if (cacheDataLength < cacheSize) { + cacheEnd = cacheDataLength; + } + + cacheBytes = cacheData.bytes; + } + if (cacheIndex == cacheEnd) { + return -1; + } + + UInt8 byte = cacheBytes[cacheIndex]; + cacheIndex++; + streamOffset++; + + switch (byte) { + case '\n': + invalidCharInLine = NO; + break; + case '\r': + case ' ': + case '\t': + case 0: + case 'a'...'z': + case 'A'...'Z': + case '0'...'9': + case '+': + case '/': + break; + default: + invalidCharInLine = YES; + break; + } + + + return byte; +} + + +#pragma init, dealloc, etc. + ++ (instancetype)unArmorWithGPGStream:(GPGStream *)theStream { + return [[[self alloc] initWithGPGStream:theStream] autorelease]; +} + +- (instancetype)initWithGPGStream:(GPGStream *)theStream { + self = [super init]; + if (!self) { + return nil; + } + + stream = [theStream retain]; + streamOffset = stream.offset; + cacheEnd = NSUIntegerMax; + cacheIndex = cacheSize; + base64Data = [[NSMutableData alloc] init]; + + + return self; +} + +- (void)dealloc { + [stream release]; + [base64Data release]; + self.data = nil; + self.clearText = nil; + self.error = nil; + [super dealloc]; +} + +@end + + +static BOOL isArmoredByte(UInt8 byte) { + if (!(byte & 0x80)) { + return YES; + } + UInt8 tag = (byte & 0x40) ? (byte & 0x3F) : ((byte & 0x3C) >> 2); + switch (tag) { + case GPGPublicKeyEncryptedSessionKeyPacket: + case GPGSignaturePacket: + case GPGSymmetricEncryptedSessionKeyPacket: + case GPGOnePassSignaturePacket: + case GPGPublicKeyPacket: + case GPGPublicSubkeyPacket: + case GPGSecretKeyPacket: + case GPGSecretSubkeyPacket: + case GPGCompressedDataPacket: + case GPGSymmetricEncryptedDataPacket: + case GPGMarkerPacket: + case GPGLiteralDataPacket: + case GPGTrustPacket: + case GPGUserIDPacket: + case GPGUserAttributePacket: + case GPGSymmetricEncryptedProtectedDataPacket: + case GPGModificationDetectionCodePacket: + return NO; + } + return YES; +} + + +@implementation GPGStream (IsArmoredExtension) +- (BOOL)isArmored { + UInt8 byte = [self peekByte]; + return isArmoredByte(byte); +} +@end +@implementation NSData (IsArmoredExtension) +- (BOOL)isArmored { + if (self.length == 0) { + return NO; + } + UInt8 byte = ((UInt8 *)self.bytes)[0]; + return isArmoredByte(byte); +} +@end + + + + diff --git a/Source/Libmacgpg.h b/Source/Libmacgpg.h index 8c1ecec..9edace6 100644 --- a/Source/Libmacgpg.h +++ b/Source/Libmacgpg.h @@ -35,3 +35,4 @@ #import #import #import +#import From 717be7a23495fb93960c7bb950786abb8cd2ee9f Mon Sep 17 00:00:00 2001 From: Mento Date: Thu, 2 Jul 2015 22:03:07 +0200 Subject: [PATCH 21/56] Use GPGUnArmor. --- Source/GPGController.m | 71 ++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 37 deletions(-) diff --git a/Source/GPGController.m b/Source/GPGController.m index 3a7a21f..8387ba1 100644 --- a/Source/GPGController.m +++ b/Source/GPGController.m @@ -31,6 +31,7 @@ #import "GPGKeyserver.h" #import "GPGTaskHelper.h" #import "GPGTask.h" +#import "GPGUnArmor.h" #if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 #import "GPGTaskHelperXPC.h" #import "NSBundle+Sandbox.h" @@ -392,13 +393,7 @@ - (NSData *)decryptData:(NSData *)data { - (void)decryptTo:(GPGStream *)output data:(GPGStream *)input { @try { - NSData *unarmored = [GPGPacket unArmorFrom:input clearText:nil]; - if (unarmored) { - input = [GPGMemoryStream memoryStreamForReading:unarmored]; - } - else { - [input seekToBeginning]; - } + input = [GPGUnArmor unArmor:input]; self.gpgTask = [GPGTask gpgTask]; [self addArgumentsForOptions]; @@ -437,18 +432,11 @@ - (NSArray *)verifySignatureOf:(GPGStream *)signatureInput originalData:(GPGStre @try { [self operationDidStart]; - NSData *originalData = nil; - NSData *unarmored = [GPGPacket unArmorFrom:signatureInput clearText:originalInput ? nil : &originalData]; - if (unarmored) { - signatureInput = [GPGMemoryStream memoryStreamForReading:unarmored]; - } - else { - [signatureInput seekToBeginning]; - } - - if (originalData) - originalInput = [GPGMemoryStream memoryStreamForReading:originalData]; - + NSData *originalData = nil; + signatureInput = [GPGUnArmor unArmor:signatureInput clearText:originalInput ? nil : &originalData]; + if (originalData) { + originalInput = [GPGMemoryStream memoryStreamForReading:originalData]; + } self.gpgTask = [GPGTask gpgTask]; [self addArgumentsForOptions]; @@ -879,6 +867,7 @@ - (void)changePassphraseForKey:(NSObject *)key { - (NSArray *)algorithmPreferencesForKey:(GPGKey *)key { self.gpgTask = [GPGTask gpgTask]; + [self addArgumentsForOptions]; [gpgTask addArgument:@"--edit-key"]; [gpgTask addArgument:[key description]]; [gpgTask addArgument:@"quit"]; @@ -1079,34 +1068,42 @@ - (NSString *)importFromData:(NSData *)data fullImport:(BOOL)fullImport { return nil; } @try { - BOOL encrypted = NO; - data = [GPGPacket unArmor:data]; + + NSData *dataToCheck = data; NSSet *keys = nil; int i = 3; // Max 3 loops. - while (dataToCheck && i-- > 0) { + while (dataToCheck.length > 0 && i-- > 0) { + NSData *unchangedData = dataToCheck; + BOOL encrypted = NO; keys = [self keysInExportedData:dataToCheck encrypted:&encrypted]; if (keys.count > 0) { data = dataToCheck; break; - } else { - if (encrypted) { - // Decrypt to allow import of encrypted keys. - dataToCheck = [self decryptData:dataToCheck]; - dataToCheck = [GPGPacket unArmor:dataToCheck]; - } else { - //Get keys from RTF data. - dataToCheck = [[[[NSAttributedString alloc] initWithData:dataToCheck options:nil documentAttributes:nil error:nil] string] dataUsingEncoding:NSUTF8StringEncoding]; - NSData *newData = [GPGPacket unArmor:dataToCheck]; - if (newData == dataToCheck) { - break; - } - } - } + } else if (encrypted) { + // Decrypt to allow import of encrypted keys. + dataToCheck = [self decryptData:dataToCheck]; + if (dataToCheck.isArmored) { + GPGUnArmor *unArmor = [GPGUnArmor unArmorWithGPGStream:[GPGMemoryStream memoryStreamForReading:dataToCheck]]; + dataToCheck = [unArmor decodeAll]; + } + } else if (dataToCheck.length > 4 && memcmp(dataToCheck.bytes, "{\\rtf", 4) == 0) { + // Data is RTF encoded. + + //Get keys from RTF data. + dataToCheck = [[[[NSAttributedString alloc] initWithData:data options:nil documentAttributes:nil error:nil] string] dataUsingEncoding:NSUTF8StringEncoding]; + if (dataToCheck.isArmored) { + GPGUnArmor *unArmor = [GPGUnArmor unArmorWithGPGStream:[GPGMemoryStream memoryStreamForReading:dataToCheck]]; + dataToCheck = [unArmor decodeAll]; + } + } + if (unchangedData == dataToCheck) { + break; + } } - + //TODO: Uncomment the following lines when keysInExportedData: fully works! From eb388f5dcbf91e8c66a17b80fb35beea1b35db4b Mon Sep 17 00:00:00 2001 From: Mento Date: Fri, 3 Jul 2015 00:05:46 +0200 Subject: [PATCH 22/56] Missing commit message for ae86481. [#14 state:fixed assigned:mento] [#38 state:fixed assigned:mento] [#145 state:fixed assigned:mento] --- Source/GPGUnArmor.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/GPGUnArmor.m b/Source/GPGUnArmor.m index 3e6be85..4461978 100644 --- a/Source/GPGUnArmor.m +++ b/Source/GPGUnArmor.m @@ -586,8 +586,8 @@ - (parsingState)parseEnd { if (!found) { return stateEOF; } - - + + UInt32 crc; if (haveCRC) { NSData *decodedCRC = nil; From 80b82f85f48435e0866b3803ce849d7af81587de Mon Sep 17 00:00:00 2001 From: Mento Date: Fri, 3 Jul 2015 21:17:37 +0200 Subject: [PATCH 23/56] Handle cacheData correctly. --- Source/GPGUnArmor.m | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Source/GPGUnArmor.m b/Source/GPGUnArmor.m index 4461978..f3bbc6e 100644 --- a/Source/GPGUnArmor.m +++ b/Source/GPGUnArmor.m @@ -26,12 +26,15 @@ @interface GPGUnArmor () @property (nonatomic, readwrite, strong) NSError *error; @property (nonatomic, readwrite, strong) NSData *clearText; @property (nonatomic, readwrite, strong) NSData *data; + +@property (nonatomic, strong) NSData *cacheData; @end @implementation GPGUnArmor @synthesize error, clearText, data, eof; +@synthesize cacheData; #pragma Public methods @@ -700,6 +703,7 @@ - (parsingState)trashEnd { } if (endMarkIndex == 22 || dashes == 5) { [stream seekToOffset:streamOffset]; + cacheIndex = cacheSize; return stateFinish; } } @@ -906,7 +910,7 @@ - (BOOL)isDataBase64EncodedPGP:(NSData *)theData { - (NSInteger)nextByte { if (cacheIndex == cacheSize) { cacheIndex = 0; - cacheData = [stream readDataOfLength:cacheSize]; + self.cacheData = [stream readDataOfLength:cacheSize]; NSUInteger cacheDataLength = cacheData.length; if (cacheDataLength < cacheSize) { @@ -972,6 +976,7 @@ - (instancetype)initWithGPGStream:(GPGStream *)theStream { - (void)dealloc { [stream release]; [base64Data release]; + self.cacheData = nil; self.data = nil; self.clearText = nil; self.error = nil; From d47805e06dc3d05c0fe10b815e3fee50c104dcb3 Mon Sep 17 00:00:00 2001 From: Mento Date: Fri, 3 Jul 2015 21:32:38 +0200 Subject: [PATCH 24/56] Un armor before passing to keysInExportedData. --- Source/GPGController.m | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Source/GPGController.m b/Source/GPGController.m index 8387ba1..3e7c864 100644 --- a/Source/GPGController.m +++ b/Source/GPGController.m @@ -1077,10 +1077,16 @@ - (NSString *)importFromData:(NSData *)data fullImport:(BOOL)fullImport { while (dataToCheck.length > 0 && i-- > 0) { NSData *unchangedData = dataToCheck; BOOL encrypted = NO; - keys = [self keysInExportedData:dataToCheck encrypted:&encrypted]; + + NSData *tempData = dataToCheck; + if (tempData.isArmored) { + GPGUnArmor *unArmor = [GPGUnArmor unArmorWithGPGStream:[GPGMemoryStream memoryStreamForReading:tempData]]; + tempData = [unArmor decodeAll]; + } + keys = [self keysInExportedData:tempData encrypted:&encrypted]; if (keys.count > 0) { - data = dataToCheck; + data = tempData; break; } else if (encrypted) { // Decrypt to allow import of encrypted keys. From e643f023bf668f3bd8cfef117462884dc3a70bc8 Mon Sep 17 00:00:00 2001 From: Lukas Pitschl Date: Sun, 5 Jul 2015 01:17:50 +0200 Subject: [PATCH 25/56] [FIX] Properly close socket connection to gpg-agent when querying if a passphrase is in cache [#147 state:fixed] - Before the socket was not closed, if the passphrase was found in the gpg-agent's cache. After a while the available file descriptors where exhausted and many IO operations using gpg-agent would fail. - Adds the GPGSocketCloseTest unit test which fails if the socket connections are not properly closed. --- Libmacgpg.xcodeproj/project.pbxproj | 168 ++++++++++++++++++++++ NewUnitTests/GPGSocketCloseTest.m | 216 ++++++++++++++++++++++++++++ NewUnitTests/Info.plist | 24 ++++ Source/GPGTaskHelper.m | 118 +++++++++------ 4 files changed, 480 insertions(+), 46 deletions(-) create mode 100644 NewUnitTests/GPGSocketCloseTest.m create mode 100644 NewUnitTests/Info.plist diff --git a/Libmacgpg.xcodeproj/project.pbxproj b/Libmacgpg.xcodeproj/project.pbxproj index b93eb7f..23a7897 100644 --- a/Libmacgpg.xcodeproj/project.pbxproj +++ b/Libmacgpg.xcodeproj/project.pbxproj @@ -40,6 +40,8 @@ 1BD78BBA1726B6060005F251 /* Libmacgpg.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8DC2EF5B0486A6940098B216 /* Libmacgpg.framework */; }; 1BD78BBC1726B6230005F251 /* Libmacgpg.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8DC2EF5B0486A6940098B216 /* Libmacgpg.framework */; }; 1BDA56BC1618A94300185C72 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4591C4D314F86D38007F6D47 /* AppKit.framework */; }; + 1BE88B3E1B47D7F900A812B6 /* GPGSocketCloseTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1BE88B3D1B47D7F900A812B6 /* GPGSocketCloseTest.m */; }; + 1BE88B3F1B47D7F900A812B6 /* Libmacgpg.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8DC2EF5B0486A6940098B216 /* Libmacgpg.framework */; }; 3002C04716EE38C900D57C1E /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 3002C04316EE388B00D57C1E /* libcrypto.dylib */; }; 301A44CD1B436405002A38E4 /* GPGUnArmor.h in Headers */ = {isa = PBXBuildFile; fileRef = 301A44CB1B436405002A38E4 /* GPGUnArmor.h */; settings = {ATTRIBUTES = (Public, ); }; }; 301A44CE1B436405002A38E4 /* GPGUnArmor.m in Sources */ = {isa = PBXBuildFile; fileRef = 301A44CC1B436405002A38E4 /* GPGUnArmor.m */; }; @@ -137,6 +139,13 @@ remoteGlobalIDString = 8DC2EF4F0486A6940098B216; remoteInfo = Libmacgpg; }; + 1BE88B401B47D7F900A812B6 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 8DC2EF4F0486A6940098B216; + remoteInfo = Libmacgpg; + }; 30444C471A65E3E30052CB94 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; @@ -200,6 +209,9 @@ 1BD78BAD1726B2830005F251 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 1BD78BAE1726B2830005F251 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 1BD78BB11726B2830005F251 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainMenu.xib; sourceTree = ""; }; + 1BE88B391B47D7F900A812B6 /* NewUnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NewUnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 1BE88B3C1B47D7F900A812B6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 1BE88B3D1B47D7F900A812B6 /* GPGSocketCloseTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GPGSocketCloseTest.m; sourceTree = ""; }; 3002C04316EE388B00D57C1E /* libcrypto.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libcrypto.dylib; path = usr/lib/libcrypto.dylib; sourceTree = SDKROOT; }; 3002C04516EE389100D57C1E /* libxar.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libxar.dylib; path = usr/lib/libxar.dylib; sourceTree = SDKROOT; }; 301A44CB1B436405002A38E4 /* GPGUnArmor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGUnArmor.h; sourceTree = ""; }; @@ -324,6 +336,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 1BE88B361B47D7F900A812B6 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 1BE88B3F1B47D7F900A812B6 /* Libmacgpg.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 30444C151A65E0590052CB94 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -366,6 +386,7 @@ 1B46CFCC161555DF00CF9C5F /* org.gpgtools.Libmacgpg.xpc */, 1BD78B9F1726B2820005F251 /* LeakFinder.app */, 30444C181A65E0590052CB94 /* GPGTools.app */, + 1BE88B391B47D7F900A812B6 /* NewUnitTests.xctest */, ); name = Products; sourceTree = ""; @@ -382,6 +403,7 @@ 30DF7CBA16D39EAA00C8225C /* installerHelper */, 1BD78BA11726B2830005F251 /* LeakFinder */, 30444C381A65E0590052CB94 /* installerHelperTests */, + 1BE88B3A1B47D7F900A812B6 /* NewUnitTests */, 0867D69AFE84028FC02AAC07 /* Frameworks */, 034768DFFF38A50411DB9C8B /* Products */, 30C8B399139504DC00F49AA1 /* UnitTest */, @@ -523,6 +545,23 @@ name = "Supporting Files"; sourceTree = ""; }; + 1BE88B3A1B47D7F900A812B6 /* NewUnitTests */ = { + isa = PBXGroup; + children = ( + 1BE88B3D1B47D7F900A812B6 /* GPGSocketCloseTest.m */, + 1BE88B3B1B47D7F900A812B6 /* Supporting Files */, + ); + path = NewUnitTests; + sourceTree = ""; + }; + 1BE88B3B1B47D7F900A812B6 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 1BE88B3C1B47D7F900A812B6 /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; 302AA377133605FE0022A371 /* GPGKey */ = { isa = PBXGroup; children = ( @@ -751,6 +790,24 @@ productReference = 1BD78B9F1726B2820005F251 /* LeakFinder.app */; productType = "com.apple.product-type.application"; }; + 1BE88B381B47D7F900A812B6 /* NewUnitTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1BE88B421B47D7F900A812B6 /* Build configuration list for PBXNativeTarget "NewUnitTests" */; + buildPhases = ( + 1BE88B351B47D7F900A812B6 /* Sources */, + 1BE88B361B47D7F900A812B6 /* Frameworks */, + 1BE88B371B47D7F900A812B6 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 1BE88B411B47D7F900A812B6 /* PBXTargetDependency */, + ); + name = NewUnitTests; + productName = NewUnitTests; + productReference = 1BE88B391B47D7F900A812B6 /* NewUnitTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; 30444C171A65E0590052CB94 /* installerHelper */ = { isa = PBXNativeTarget; buildConfigurationList = 30444C401A65E0590052CB94 /* Build configuration list for PBXNativeTarget "installerHelper" */; @@ -819,6 +876,11 @@ isa = PBXProject; attributes = { LastUpgradeCheck = 0450; + TargetAttributes = { + 1BE88B381B47D7F900A812B6 = { + CreatedOnToolsVersion = 6.2; + }; + }; }; buildConfigurationList = 1DEB91B108733DA50010E9CD /* Build configuration list for PBXProject "Libmacgpg" */; compatibilityVersion = "Xcode 3.2"; @@ -843,6 +905,7 @@ 1B46CFCB161555DF00CF9C5F /* org.gpgtools.Libmacgpg.xpc */, 1BD78B9E1726B2820005F251 /* LeakFinder */, 30444C171A65E0590052CB94 /* installerHelper */, + 1BE88B381B47D7F900A812B6 /* NewUnitTests */, ); }; /* End PBXProject section */ @@ -858,6 +921,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 1BE88B371B47D7F900A812B6 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 30444C161A65E0590052CB94 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -1045,6 +1115,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 1BE88B351B47D7F900A812B6 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1BE88B3E1B47D7F900A812B6 /* GPGSocketCloseTest.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 30444C141A65E0590052CB94 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -1120,6 +1198,11 @@ target = 8DC2EF4F0486A6940098B216 /* Libmacgpg */; targetProxy = 1BD78BB81726B5190005F251 /* PBXContainerItemProxy */; }; + 1BE88B411B47D7F900A812B6 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 8DC2EF4F0486A6940098B216 /* Libmacgpg */; + targetProxy = 1BE88B401B47D7F900A812B6 /* PBXContainerItemProxy */; + }; 30444C481A65E3E30052CB94 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 30444C171A65E0590052CB94 /* installerHelper */; @@ -1297,6 +1380,83 @@ }; name = Release; }; + 1BE88B431B47D7F900A812B6 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(DEVELOPER_FRAMEWORKS_DIR)", + "$(inherited)", + ); + GCC_DYNAMIC_NO_PIC = NO; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + HEADER_SEARCH_PATHS = "${PROJECT_DIR}/Dependencies/XPCKit"; + INFOPLIST_FILE = NewUnitTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.9; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 1BE88B441B47D7F900A812B6 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(DEVELOPER_FRAMEWORKS_DIR)", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + HEADER_SEARCH_PATHS = "${PROJECT_DIR}/Dependencies/XPCKit"; + INFOPLIST_FILE = NewUnitTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.9; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; 1DEB91AE08733DA50010E9CD /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -1568,6 +1728,14 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 1BE88B421B47D7F900A812B6 /* Build configuration list for PBXNativeTarget "NewUnitTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1BE88B431B47D7F900A812B6 /* Debug */, + 1BE88B441B47D7F900A812B6 /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; 1DEB91AD08733DA50010E9CD /* Build configuration list for PBXNativeTarget "Libmacgpg" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/NewUnitTests/GPGSocketCloseTest.m b/NewUnitTests/GPGSocketCloseTest.m new file mode 100644 index 0000000..c72f6e0 --- /dev/null +++ b/NewUnitTests/GPGSocketCloseTest.m @@ -0,0 +1,216 @@ +// +// GPGSocketCloseTest.m +// Libmacgpg +// +// Created by Lukas Pitschl on 04.07.15. +// +// + +#import +#import +#import +#import +#import +#import +#import +#import "Libmacgpg.h" +#import "GPGTaskHelper.h" + +uid_t uidFromPid(pid_t pid) { + uid_t uid = -1; + + struct kinfo_proc process; + size_t procBufferSize = sizeof(process); + + // Compose search path for sysctl. Here you can specify PID directly. + const u_int pathLenth = 4; + int path[pathLenth] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}; + + int sysctlResult = sysctl(path, pathLenth, &process, &procBufferSize, NULL, 0); + + // If sysctl did not fail and process with PID available - take UID. + if ((sysctlResult == 0) && (procBufferSize != 0)) { + uid = process.kp_eproc.e_ucred.cr_uid; + } + + return uid; +} + +@interface GPGSocketCloseTest : XCTestCase + +@end + +@implementation GPGSocketCloseTest + +- (NSInteger)pidForProcessWithName:(NSString *)name { + NSMutableArray *ret = [NSMutableArray arrayWithCapacity:1]; + + int numberOfProcesses = proc_listpids(PROC_ALL_PIDS, 0, NULL, 0); + pid_t pids[1024]; + bzero(pids, 1024); + proc_listpids(PROC_ALL_PIDS, 0, pids, sizeof(pids)); + for (int i = 0; i < numberOfProcesses; ++i) { + if (pids[i] == 0) { continue; } + char pathBuffer[PROC_PIDPATHINFO_MAXSIZE]; + bzero(pathBuffer, PROC_PIDPATHINFO_MAXSIZE); + proc_pidpath(pids[i], pathBuffer, sizeof(pathBuffer)); + + NSMutableDictionary *process = [[NSMutableDictionary alloc] init]; + + process[@"pid"] = @(pids[i]); + process[@"uid"] = @(uidFromPid(pids[i])); + process[@"name"] = [@(pathBuffer) lastPathComponent]; + + [ret addObject:process]; + } + + + unsigned int current_user_id = getuid(); + + NSInteger pid = -1; + for(NSDictionary *process in ret) { + // Skip processes that don't belong to the current user. + if([process[@"uid"] integerValue] != current_user_id) + continue; + if([process[@"name"] isEqualToString:name]) + pid = [process[@"pid"] integerValue]; + } + + return pid; +} + +- (NSArray *)openSocketConnectionForPid:(NSInteger)pid { + int i, nb, nf; + struct proc_fdinfo *fdp; + struct proc_taskallinfo tai; + + NSMutableArray *sockets = [NSMutableArray array]; + + static struct proc_fdinfo *Fds = (struct proc_fdinfo *)NULL; + /* FD buffer */ + static int NbFds = 0; /* bytes allocated to FDs */ + + nb = proc_pidinfo((int)pid, PROC_PIDTASKALLINFO, 0, &tai, sizeof(tai)); + int n = tai.pbsd.pbi_nfiles; + + /* + * Make sure an FD buffer has been allocated. + */ + if (!Fds) { + NbFds = sizeof(struct proc_fdinfo) * n; + Fds = (struct proc_fdinfo *)malloc(NbFds); + } else if (NbFds < sizeof(struct proc_fdinfo) * n) { + + /* + * More proc_fdinfo space is required. Allocate it. + */ + NbFds = sizeof(struct proc_fdinfo) * n; + Fds = (struct proc_fdinfo *)realloc((void *)Fds, + NbFds); + } + /* + * Get FD information for the process. + */ + nb = proc_pidinfo((int)pid, PROC_PIDLISTFDS, 0, Fds, NbFds); + if (nb <= 0) { + if (errno == ESRCH) { + + /* + * Quit if no FD information is available for the process. + */ + return nil; + } + } + nf = (int)(nb / sizeof(struct proc_fdinfo)); + /* + * Loop through the file descriptors. + */ + for (i = 0; i < nf; i++) { + fdp = &Fds[i]; + int fd = fdp->proc_fd; + + if(fdp->proc_fdtype != PROX_FDTYPE_SOCKET) + continue; + + struct socket_fdinfo si; + nb = proc_pidfdinfo((int)pid, fd, PROC_PIDFDSOCKETINFO, &si, sizeof(si)); + // Not necessary to add any error code, since the test will simply fail if an error occurs. + + int fam = si.psi.soi_family; + if(fam != AF_UNIX) + continue; + if (si.psi.soi_kind != SOCKINFO_UN) + continue; + + int unl; + if (si.psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_path[0]) { + unl = si.psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_len - offsetof(struct sockaddr_un, sun_path); + if ((unl < 0) || (unl >= sizeof(si.psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_path))) + unl = sizeof(si.psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_path) - 1; + si.psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_path[unl] = '\0'; + + [sockets addObject:@{@"sunPath": @(si.psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_path)}]; + } + } + + + return sockets; +} + +- (NSInteger)numberOfOpenSocketConnections { + NSArray *sockets = [self openSocketConnectionForPid:[self pidForProcessWithName:@"gpg-agent"]]; + NSInteger nrOfSockets = 0; + for(NSDictionary *socket in sockets) { + if(![[socket[@"sunPath"] lastPathComponent] isEqualToString:@"S.gpg-agent"]) + continue; + nrOfSockets++; + } + return nrOfSockets; +} + +- (void)testPassphraseInAgentSocketCloseBug { + // Calling isPassphraseForKeyInGPGAgentCache: seems to trigger a bug where the socket connection + // which is established to the gpg-agent is not always closed. + // This test will only pass if all sockets are properly closed after usage. + + // In order to warm the passphrase cache some random data is signed. + GPGController *gpgc = [[GPGController alloc] init]; + NSString *content = @"This content is signed to warm up the passphrase cache."; + NSData *contentData = [content dataUsingEncoding:NSUTF8StringEncoding]; + + gpgc.useArmor = YES; + gpgc.useTextMode = YES; + // Automatically trust keys, even though they are not specifically + // marked as such. + // Eventually add warning for this. + gpgc.trustAllKeys = YES; + + GPGKey *signerKey = [[[GPGKeyManager sharedInstance] secretKeys] anyObject]; + XCTAssert(signerKey != nil, @"For this test to run properly, it's necessary to have at least one secret key."); + + gpgc.signerKey = signerKey; + + NSData *signedContent = [gpgc processData:contentData withEncryptSignMode:GPGSign recipients:nil hiddenRecipients:nil]; + XCTAssertNil(gpgc.error, @"Error occured while signing data: %@", gpgc.error); + XCTAssertNotNil(signedContent, @"Failed to sign data"); + + NSInteger currentNumberOfOpenSocketConnections = [self numberOfOpenSocketConnections]; + + int maxRuns = 300; + int i = 0; + for(; i < 300; i++) { + BOOL inCache = [GPGTaskHelper isPassphraseInGPGAgentCache:signerKey.fingerprint]; + if(!inCache) { + if(i > 0 && i < maxRuns - 1) { + XCTFail(@"Number of available FDs probably exhausted. Bug caught!"); + } + else { + XCTFail(@"The passphrase has to be cached in order for the bug to reveal itself."); + } + break; + } + } + XCTAssert([self numberOfOpenSocketConnections] == currentNumberOfOpenSocketConnections, @"What now, a connection still open? Houston, we have a bug"); +} + +@end diff --git a/NewUnitTests/Info.plist b/NewUnitTests/Info.plist new file mode 100644 index 0000000..a2dc66c --- /dev/null +++ b/NewUnitTests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + org.gpgtools.$(PRODUCT_NAME:rfc1034identifier) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/Source/GPGTaskHelper.m b/Source/GPGTaskHelper.m index ae538d0..dbb5e53 100644 --- a/Source/GPGTaskHelper.m +++ b/Source/GPGTaskHelper.m @@ -914,56 +914,82 @@ + (BOOL)isPassphraseInGPGAgentCache:(id)key { return NO; NSString *socketPath = [GPGTaskHelper gpgAgentSocket]; - if (socketPath) { - int sock; - if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { - perror("socket"); - return NO; - } - - unsigned long length = [socketPath lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 3; - char addressInfo[length]; - addressInfo[0] = AF_UNIX; - addressInfo[1] = 0; - strncpy(addressInfo+2, [socketPath UTF8String], length - 2); - - if (connect(sock, (const struct sockaddr *)addressInfo, (socklen_t)length ) == -1) { - perror("connect"); - goto closeSocket; + // No socket path available? Can't query the cache, so bail. + if(!socketPath) { + GPGDebugLog(@"No gpg-agent socket path available!"); + return NO; + } + + __block int sock = -1; + if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + perror("+[GPGTaskHelper isPassphraseInGPGAgentCache:] failed to initiate socket"); + return NO; + } + + BOOL (^cleanup)(BOOL) = ^(BOOL inCache){ + if(sock != -1) + close(sock); + return inCache; + }; + + const char *socketPathName = [socketPath UTF8String]; + unsigned long socketPathLength = [socketPath lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; + + struct sockaddr_un server; + bzero((char *)&server, sizeof(struct sockaddr_un)); + server.sun_family = AF_UNIX; + strncpy(server.sun_path, socketPathName, socketPathLength); + // On BSD systems, sun_path is not to be expected to be terminated with a null byte. + if (connect(sock, (struct sockaddr *)&server, sizeof(struct sockaddr_un)) < 0) { + perror("+[GPGTaskHelper isPassphraseInGPGAgentCache:] failed to connect to gpg-agent socket"); + return cleanup(NO); + } + + struct timeval socketTimeout; + socketTimeout.tv_usec = 0; + socketTimeout.tv_sec = 2; + if(setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &socketTimeout, sizeof(socketTimeout)) < 0) { + perror("+[GPGTaskHelper isPassphraseInGPGAgentCache:] failed to configure socket timeout"); + return cleanup(NO); + } + + char buffer[100]; + bzero(&buffer, sizeof(buffer)); + // Check if server is responding by receiving the message OK, otherwise bail. + if(recv(sock, buffer, 100, 0) <= 2) { + GPGDebugLog(@"Failed to receive OK from gpg-agent."); + return cleanup(NO); + } + if (strncmp(buffer, "OK", 2)) { + GPGDebugLog(@"No OK from gpg-agent."); + return cleanup(NO); + } + + NSString *command = [NSString stringWithFormat:@"GET_PASSPHRASE --no-ask %@ . . .\n", key]; + // Request the passphrase connected to the key. + send(sock, [command UTF8String], [command lengthOfBytesUsingEncoding:NSUTF8StringEncoding], 0); + + int pos = 0; + int length = 0; + bzero(&buffer, sizeof(buffer)); + BOOL inCache = NO; + + while ((length = recv(sock, buffer+pos, 100-pos, 0)) > 0) { + pos += length; + // Yes, we have the passphrase in cache! + if(strnstr(buffer, "OK", pos)) { + inCache = YES; + break; } - - struct timeval socketTimeout; - socketTimeout.tv_usec = 0; - socketTimeout.tv_sec = 2; - setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &socketTimeout, sizeof(socketTimeout)); - - - char buffer[100]; - if (recv(sock, buffer, 100, 0) > 2) { - if (strncmp(buffer, "OK", 2)) { - GPGDebugLog(@"No OK from gpg-agent."); - goto closeSocket; - } - NSString *command = [NSString stringWithFormat:@"GET_PASSPHRASE --no-ask %@ . . .\n", key]; - send(sock, [command UTF8String], [command lengthOfBytesUsingEncoding:NSUTF8StringEncoding], 0); - - int pos = 0; - while ((length = recv(sock, buffer+pos, 100-pos, 0)) > 0) { - pos += length; - if (strnstr(buffer, "OK", pos)) { - return YES; - } else if (strnstr(buffer, "ERR", pos)) { - goto closeSocket; - } - } - } else { - return NO; + // gpg-agent is saying that we don't have the passphrase in cache! + if(strnstr(buffer, "ERR", pos)) { + inCache = NO; + break; } - closeSocket: - close(sock); } - return NO; + + return cleanup(inCache); } - (void)dealloc { From f88d3060ba98d3019120abf0b69b874e02ea5bfa Mon Sep 17 00:00:00 2001 From: Mento Date: Mon, 6 Jul 2015 14:15:34 +0200 Subject: [PATCH 26/56] GPGPacket copy NSData. [#146 state:fixed assigned:mento] --- Source/GPGPacket.m | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Source/GPGPacket.m b/Source/GPGPacket.m index 272edce..32564ee 100644 --- a/Source/GPGPacket.m +++ b/Source/GPGPacket.m @@ -56,7 +56,7 @@ @implementation GPGPacket + (id)packetsWithData:(NSData *)theData { - __block NSMutableArray *packets = [NSMutableArray array]; + NSMutableArray *packets = [NSMutableArray array]; [self enumeratePacketsWithData:theData block:^(GPGPacket *packet, BOOL *stop) { [packets addObject:packet]; @@ -66,6 +66,7 @@ + (id)packetsWithData:(NSData *)theData { } + (void)enumeratePacketsWithData:(NSData *)theData block:(void (^)(GPGPacket *packet, BOOL *stop))block { + theData = [theData copy]; if (theData.isArmored) { GPGMemoryStream *stream = [GPGMemoryStream memoryStreamForReading:theData]; @@ -73,11 +74,13 @@ + (void)enumeratePacketsWithData:(NSData *)theData block:(void (^)(GPGPacket *pa [unArmor decodeAll]; - theData = unArmor.data; + [theData release]; + theData = [unArmor.data retain]; } if (theData.length < 10) { + [theData release]; return; } const uint8_t *bytes = theData.bytes; @@ -95,6 +98,7 @@ + (void)enumeratePacketsWithData:(NSData *)theData block:(void (^)(GPGPacket *pa block(packet, &stop); [packet release]; if (stop) { + [theData release]; return; } } @@ -103,6 +107,8 @@ + (void)enumeratePacketsWithData:(NSData *)theData block:(void (^)(GPGPacket *pa } currentPos = nextPacketPos; } + + [theData release]; } - (id)initWithBytes:(const uint8_t *)bytes length:(NSUInteger)dataLength nextPacketStart:(const uint8_t **)nextPacket { From 211c65e993a5a95404b31ed9c916828f4da9e5c1 Mon Sep 17 00:00:00 2001 From: Mento Date: Fri, 10 Jul 2015 15:42:46 +0200 Subject: [PATCH 27/56] GPGStream readByte added. GPGFileStream uses a cache to speed up single byte reading. --- Source/GPGFileStream.h | 8 ++ Source/GPGFileStream.m | 163 +++++++++++++++++++++++++++------------ Source/GPGMemoryStream.h | 2 + Source/GPGMemoryStream.m | 49 ++++++++---- Source/GPGStream.h | 5 ++ Source/GPGStream.m | 4 + 6 files changed, 168 insertions(+), 63 deletions(-) diff --git a/Source/GPGFileStream.h b/Source/GPGFileStream.h index 649a2c4..587a337 100644 --- a/Source/GPGFileStream.h +++ b/Source/GPGFileStream.h @@ -19,6 +19,14 @@ NSFileHandle *_readfh; // for readable files unsigned long long _flength; + + // cache to speed-up byte wise reading. + NSData *_cacheData; + const UInt8 *_cacheBytes; + NSUInteger _cacheLocation; + NSUInteger _cacheAvailableBytes; + NSUInteger _realOffset; + } // returns nil if creating file for writing failed diff --git a/Source/GPGFileStream.m b/Source/GPGFileStream.m index ee2fcac..5fc0a93 100644 --- a/Source/GPGFileStream.m +++ b/Source/GPGFileStream.m @@ -8,6 +8,7 @@ #import "GPGFileStream.h" + @interface GPGFileStream () // might be called (internally) for a writeable stream after writing - (void)openForReading; @@ -20,6 +21,7 @@ - (void)dealloc [_filepath release]; [_fh release]; [_readfh release]; + [_cacheData release]; [super dealloc]; } @@ -30,90 +32,150 @@ - (id)init { + (id)fileStreamForWritingAtPath:(NSString *)path { NSError *error = nil; id newObject = [[[self alloc] initForWritingAtPath:path error:&error] autorelease]; - if (error) + if (error) { return nil; + } return newObject; } + (id)fileStreamForReadingAtPath:(NSString *)path { NSError *error = nil; id newObject = [[[self alloc] initForReadingAtPath:path error:&error] autorelease]; - if (error) + if (error) { return nil; + } return newObject; } -- (id)initForWritingAtPath:(NSString *)path error:(NSError **)error -{ - if (self = [super init]) { - _filepath = [path retain]; - - if (path) { - _fh = [[NSFileHandle fileHandleForWritingAtPath:path] retain]; - - if (!_fh) { - if (error) - *error = [NSError errorWithDomain:@"libc" code:0 userInfo:nil]; - } - } - else { - _fh = [[NSFileHandle fileHandleWithNullDevice] retain]; - } - } +- (id)initForWritingAtPath:(NSString *)path error:(NSError **)error { + self = [super init]; + if (!self) { + return nil; + } + + if (!path) { + [self release]; + return nil; + } + + _filepath = [path retain]; + + _fh = [[NSFileHandle fileHandleForWritingAtPath:path] retain]; + if (!_fh) { + if (error) { + *error = [NSError errorWithDomain:@"libc" code:0 userInfo:nil]; + } + [self release]; + return nil; + } return self; } -- (id)initForReadingAtPath:(NSString *)path error:(NSError **)error -{ - if (self = [super init]) { - _filepath = [path retain]; - - if (path) { - [self openForReading]; - if (!_readfh) { - if (error) - *error = [NSError errorWithDomain:@"libc" code:0 userInfo:nil]; - } - } - else { - _readfh = [[NSFileHandle fileHandleWithNullDevice] retain]; - } - } - +- (id)initForReadingAtPath:(NSString *)path error:(NSError **)error { + self = [super init]; + if (!self) { + return nil; + } + + if (!path) { + [self release]; + return nil; + } + + _filepath = [path retain]; + + [self openForReading]; + if (!_readfh) { + if (error) { + *error = [NSError errorWithDomain:@"libc" code:0 userInfo:nil]; + } + [self release]; + return nil; + } + return self; } -- (void)writeData:(NSData *)data +- (void)writeData:(NSData *)data { - if (_readfh) + if (_readfh) { @throw [NSException exceptionWithName:@"InvalidOperationException" reason:@"stream is readable" userInfo:nil]; + } [_fh writeData:data]; } -- (NSData *)readDataToEndOfStream -{ - if (!_readfh) +- (NSData *)readDataToEndOfStream { + if (!_readfh) { [self openForReading]; - return [_readfh readDataToEndOfFile]; + } + if (_realOffset != NSUIntegerMax) { + _cacheAvailableBytes = 0; + [_readfh seekToFileOffset:_realOffset]; + _realOffset = NSUIntegerMax; + } + + return [_readfh readDataToEndOfFile]; } - (NSData *)readDataOfLength:(NSUInteger)length { - if (!_readfh) - [self openForReading]; + if (!_readfh) { + [self openForReading]; + } + if (_realOffset != NSUIntegerMax) { + _cacheAvailableBytes = 0; + [_readfh seekToFileOffset:_realOffset]; + _realOffset = NSUIntegerMax; + } + return [_readfh readDataOfLength:length]; } - (NSData *)readAllData { - if (!_readfh) + if (!_readfh) { [self openForReading]; + } + _cacheAvailableBytes = 0; + _realOffset = NSUIntegerMax; + [_readfh seekToFileOffset:0]; return [_readfh readDataToEndOfFile]; } +- (NSInteger)readByte { + const NSUInteger cacheSize = 1024; + + if (!_readfh) { + [self openForReading]; + } + + if (_cacheAvailableBytes == 0) { + _cacheLocation = 0; + + if (_realOffset == NSUIntegerMax) { + _realOffset = _readfh.offsetInFile; + } + + [_cacheData release]; + _cacheData = [[_readfh readDataOfLength:cacheSize] retain]; + + _cacheAvailableBytes = _cacheData.length; + if (_cacheAvailableBytes == 0) { + return EOF; + } + + _cacheBytes = _cacheData.bytes; + } + + _realOffset++; + _cacheAvailableBytes--; + return _cacheBytes[_cacheLocation++]; +} + - (char)peekByte { - if (!_readfh) - [self openForReading]; + if (!_readfh) { + [self openForReading]; + } unsigned long long currentPos = [_readfh offsetInFile]; NSData *peek = [_readfh readDataOfLength:1]; @@ -175,8 +237,9 @@ - (NSUInteger)offset { - (unsigned long long)length { - if (_readfh) + if (_readfh) { return _flength; + } return [_fh offsetInFile]; } @@ -189,11 +252,11 @@ - (void)openForReading [_fh release]; _fh = nil; } - if (!_readfh) - { + if (!_readfh) { _readfh = [[NSFileHandle fileHandleForReadingAtPath:_filepath] retain]; _flength = [_readfh seekToEndOfFile]; [_readfh seekToFileOffset:0]; + _realOffset = NSUIntegerMax; } } diff --git a/Source/GPGMemoryStream.h b/Source/GPGMemoryStream.h index a7bcd28..b0d8b6c 100644 --- a/Source/GPGMemoryStream.h +++ b/Source/GPGMemoryStream.h @@ -15,6 +15,8 @@ NSMutableData *_data; NSData *_readableData; NSUInteger _readPos; + const UInt8 *_readableBytes; + NSUInteger _readableLength; } // return a new, autoreleased memory stream diff --git a/Source/GPGMemoryStream.m b/Source/GPGMemoryStream.m index 76ebd9b..675c931 100644 --- a/Source/GPGMemoryStream.m +++ b/Source/GPGMemoryStream.m @@ -36,6 +36,8 @@ - (id)initForReading:(NSData *)data if (self = [super init]) { // _data stays nil _readableData = [data retain]; + _readableBytes = _readableData.bytes; + _readableLength = _readableData.length; } return self; } @@ -52,15 +54,17 @@ + (id)memoryStreamForReading:(NSData *)data - (void)writeData:(NSData *)data { - if (!_data) + if (!_data) { @throw [NSException exceptionWithName:@"InvalidOperationException" reason:@"stream is readable" userInfo:nil]; + } [_data appendData:data]; } - (NSData *)readDataToEndOfStream { - if (!_readableData) - [self openForReading]; + if (!_readableData) { + [self openForReading]; + } NSUInteger rlength = [_readableData length]; if (_readPos >= rlength) @@ -73,9 +77,10 @@ - (NSData *)readDataToEndOfStream - (NSData *)readDataOfLength:(NSUInteger)length { - if (!_readableData) - [self openForReading]; - + if (!_readableData) { + [self openForReading]; + } + NSUInteger rlength = [_readableData length]; if (_readPos >= rlength) return [NSData data]; @@ -88,16 +93,28 @@ - (NSData *)readDataOfLength:(NSUInteger)length - (NSData *)readAllData { - if (!_readableData) - [self openForReading]; + if (!_readableData) { + [self openForReading]; + } return _readableData; } +- (NSInteger)readByte { + if (!_readableData) { + [self openForReading]; + } + if (_readPos >= _readableLength) { + return -1; + } + return _readableBytes[_readPos++]; // Post-increment. +} + - (char)peekByte { - if (!_readableData) + if (!_readableData) { [self openForReading]; + } unsigned long long rlength = [_readableData length]; if (_readPos >= rlength) @@ -114,10 +131,12 @@ - (char)peekByte - (void)seekToBeginning { - if (_data) + if (_data) { [_data setLength:0]; - if (_readableData) + } + if (_readableData) { _readPos = 0; + } } - (void)seekToOffset:(NSUInteger)offset { if (_data) { @@ -145,8 +164,9 @@ - (NSUInteger)offset { - (unsigned long long)length { - if (_readableData) + if (_readableData) { return [_readableData length]; + } return [_data length]; } @@ -154,8 +174,11 @@ - (unsigned long long)length - (void)openForReading { - if (!_readableData) + if (!_readableData) { _readableData = [[NSData dataWithData:_data] retain]; + _readableBytes = _readableData.bytes; + _readableLength = _readableData.length; + } if (_data) { [_data release]; _data = nil; diff --git a/Source/GPGStream.h b/Source/GPGStream.h index 3f9026d..847b3e7 100644 --- a/Source/GPGStream.h +++ b/Source/GPGStream.h @@ -20,6 +20,11 @@ - (NSData *)readDataOfLength:(NSUInteger)length; // (re)read all data from the stream - (NSData *)readAllData; +/** + Read the next byte from the stream. + @returns The next byte or EOF. +*/ +- (NSInteger)readByte; // return the character at the next position, without advancing position - (char)peekByte; diff --git a/Source/GPGStream.m b/Source/GPGStream.m index cab1ffe..a247099 100644 --- a/Source/GPGStream.m +++ b/Source/GPGStream.m @@ -26,6 +26,10 @@ - (NSData *)readAllData { @throw [NSException exceptionWithName:@"NotImplementedException" reason:@"abstract method" userInfo:nil]; } +- (NSInteger)readByte { + @throw [NSException exceptionWithName:@"NotImplementedException" reason:@"abstract method" userInfo:nil]; +} + - (char)peekByte { @throw [NSException exceptionWithName:@"NotImplementedException" reason:@"abstract method" userInfo:nil]; } From 1d1f8ee957a133ad554e84af8c2b73a887a0b5ef Mon Sep 17 00:00:00 2001 From: Mento Date: Fri, 10 Jul 2015 15:43:26 +0200 Subject: [PATCH 28/56] Little fixes in GPGUnArmor --- Source/GPGUnArmor.m | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/Source/GPGUnArmor.m b/Source/GPGUnArmor.m index f3bbc6e..3db6207 100644 --- a/Source/GPGUnArmor.m +++ b/Source/GPGUnArmor.m @@ -2,7 +2,7 @@ #import "GPGException.h" #import "GPGMemoryStream.h" -const NSUInteger cacheSize = 1000; +static const NSUInteger cacheSize = 1000; typedef enum { stateSearchBegin = 0, @@ -885,6 +885,10 @@ - (BOOL)isDataBase64EncodedPGP:(NSData *)theData { case 2: length = (bytes[1] << 24) + (bytes[2] << 16) + (bytes[3] << 8) + bytes[4] + 5; break; + case 3: + // Indeterminate length. + length = 1; + break; default: return NO; } @@ -992,23 +996,8 @@ static BOOL isArmoredByte(UInt8 byte) { } UInt8 tag = (byte & 0x40) ? (byte & 0x3F) : ((byte & 0x3C) >> 2); switch (tag) { - case GPGPublicKeyEncryptedSessionKeyPacket: - case GPGSignaturePacket: - case GPGSymmetricEncryptedSessionKeyPacket: - case GPGOnePassSignaturePacket: - case GPGPublicKeyPacket: - case GPGPublicSubkeyPacket: - case GPGSecretKeyPacket: - case GPGSecretSubkeyPacket: - case GPGCompressedDataPacket: - case GPGSymmetricEncryptedDataPacket: - case GPGMarkerPacket: - case GPGLiteralDataPacket: - case GPGTrustPacket: - case GPGUserIDPacket: - case GPGUserAttributePacket: - case GPGSymmetricEncryptedProtectedDataPacket: - case GPGModificationDetectionCodePacket: + case 1 ... 14: + case 17 ... 19: return NO; } return YES; From e7658ca9a3394dc11a8f767a4f03cc4eb8771eb5 Mon Sep 17 00:00:00 2001 From: Mento Date: Mon, 13 Jul 2015 14:15:31 +0200 Subject: [PATCH 29/56] GPGPacket rewrite. GPGPacket is split in multiple sub-classes. GPGPacketParser is used to get packets out of a GPGStream. keysInExportedData adjusted. Version set to 0.6. --- Libmacgpg.xcodeproj/project.pbxproj | 137 ++++- Source/GPGController.m | 62 +-- Source/GPGGlobals.h | 20 - Source/GPGPacket.h | 61 --- Source/GPGPacket.m | 376 ------------- Source/GPGPacket/COPYING.pgpdump | 30 ++ Source/GPGPacket/GPGCompressedDataPacket.h | 34 ++ Source/GPGPacket/GPGCompressedDataPacket.m | 312 +++++++++++ .../GPGCompressedDataPacket_Private.h | 29 + Source/GPGPacket/GPGIgnoredPackets.h | 37 ++ Source/GPGPacket/GPGIgnoredPackets.m | 61 +++ Source/GPGPacket/GPGKeyMaterialPacket.h | 55 ++ Source/GPGPacket/GPGKeyMaterialPacket.m | 199 +++++++ Source/GPGPacket/GPGLiteralDataPacket.h | 37 ++ Source/GPGPacket/GPGLiteralDataPacket.m | 90 ++++ Source/GPGPacket/GPGOnePassSignaturePacket.h | 39 ++ Source/GPGPacket/GPGOnePassSignaturePacket.m | 64 +++ Source/GPGPacket/GPGPacket.h | 62 +++ Source/GPGPacket/GPGPacket.m | 128 +++++ Source/GPGPacket/GPGPacketParser.h | 55 ++ Source/GPGPacket/GPGPacketParser.m | 509 ++++++++++++++++++ Source/GPGPacket/GPGPacketParser_Private.h | 45 ++ Source/GPGPacket/GPGPacket_Private.h | 31 ++ .../GPGPublicKeyEncryptedSessionKeyPacket.h | 35 ++ .../GPGPublicKeyEncryptedSessionKeyPacket.m | 80 +++ Source/GPGPacket/GPGSignaturePacket.h | 80 +++ Source/GPGPacket/GPGSignaturePacket.m | 178 ++++++ .../GPGSymmetricEncryptedSessionKeyPacket.h | 35 ++ .../GPGSymmetricEncryptedSessionKeyPacket.m | 63 +++ Source/GPGPacket/GPGUserAttributePacket.h | 30 ++ Source/GPGPacket/GPGUserAttributePacket.m | 124 +++++ Source/GPGPacket/GPGUserIDPacket.h | 30 ++ Source/GPGPacket/GPGUserIDPacket.m | 60 +++ Source/Libmacgpg.h | 13 +- Version.config | 2 +- 35 files changed, 2705 insertions(+), 498 deletions(-) delete mode 100644 Source/GPGPacket.h delete mode 100644 Source/GPGPacket.m create mode 100644 Source/GPGPacket/COPYING.pgpdump create mode 100644 Source/GPGPacket/GPGCompressedDataPacket.h create mode 100644 Source/GPGPacket/GPGCompressedDataPacket.m create mode 100644 Source/GPGPacket/GPGCompressedDataPacket_Private.h create mode 100644 Source/GPGPacket/GPGIgnoredPackets.h create mode 100644 Source/GPGPacket/GPGIgnoredPackets.m create mode 100644 Source/GPGPacket/GPGKeyMaterialPacket.h create mode 100644 Source/GPGPacket/GPGKeyMaterialPacket.m create mode 100644 Source/GPGPacket/GPGLiteralDataPacket.h create mode 100644 Source/GPGPacket/GPGLiteralDataPacket.m create mode 100644 Source/GPGPacket/GPGOnePassSignaturePacket.h create mode 100644 Source/GPGPacket/GPGOnePassSignaturePacket.m create mode 100644 Source/GPGPacket/GPGPacket.h create mode 100644 Source/GPGPacket/GPGPacket.m create mode 100644 Source/GPGPacket/GPGPacketParser.h create mode 100644 Source/GPGPacket/GPGPacketParser.m create mode 100644 Source/GPGPacket/GPGPacketParser_Private.h create mode 100644 Source/GPGPacket/GPGPacket_Private.h create mode 100644 Source/GPGPacket/GPGPublicKeyEncryptedSessionKeyPacket.h create mode 100644 Source/GPGPacket/GPGPublicKeyEncryptedSessionKeyPacket.m create mode 100644 Source/GPGPacket/GPGSignaturePacket.h create mode 100644 Source/GPGPacket/GPGSignaturePacket.m create mode 100644 Source/GPGPacket/GPGSymmetricEncryptedSessionKeyPacket.h create mode 100644 Source/GPGPacket/GPGSymmetricEncryptedSessionKeyPacket.m create mode 100644 Source/GPGPacket/GPGUserAttributePacket.h create mode 100644 Source/GPGPacket/GPGUserAttributePacket.m create mode 100644 Source/GPGPacket/GPGUserIDPacket.h create mode 100644 Source/GPGPacket/GPGUserIDPacket.m diff --git a/Libmacgpg.xcodeproj/project.pbxproj b/Libmacgpg.xcodeproj/project.pbxproj index 23a7897..0ef7e88 100644 --- a/Libmacgpg.xcodeproj/project.pbxproj +++ b/Libmacgpg.xcodeproj/project.pbxproj @@ -43,8 +43,16 @@ 1BE88B3E1B47D7F900A812B6 /* GPGSocketCloseTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1BE88B3D1B47D7F900A812B6 /* GPGSocketCloseTest.m */; }; 1BE88B3F1B47D7F900A812B6 /* Libmacgpg.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8DC2EF5B0486A6940098B216 /* Libmacgpg.framework */; }; 3002C04716EE38C900D57C1E /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 3002C04316EE388B00D57C1E /* libcrypto.dylib */; }; + 300F3DB51B4AC2CE00E36AAA /* libbz2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 300F3DB31B4AC2CE00E36AAA /* libbz2.dylib */; }; + 300F3DB61B4AC2CE00E36AAA /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 300F3DB41B4AC2CE00E36AAA /* libz.dylib */; }; 301A44CD1B436405002A38E4 /* GPGUnArmor.h in Headers */ = {isa = PBXBuildFile; fileRef = 301A44CB1B436405002A38E4 /* GPGUnArmor.h */; settings = {ATTRIBUTES = (Public, ); }; }; 301A44CE1B436405002A38E4 /* GPGUnArmor.m in Sources */ = {isa = PBXBuildFile; fileRef = 301A44CC1B436405002A38E4 /* GPGUnArmor.m */; }; + 301D291D1B4BE4F500599BE8 /* GPGPacketParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 301D291B1B4BE4F500599BE8 /* GPGPacketParser.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 301D291E1B4BE4F500599BE8 /* GPGPacketParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 301D291C1B4BE4F500599BE8 /* GPGPacketParser.m */; }; + 301D29211B4BFD9800599BE8 /* GPGPacket.h in Headers */ = {isa = PBXBuildFile; fileRef = 301D291F1B4BFD9800599BE8 /* GPGPacket.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 301D29221B4BFD9800599BE8 /* GPGPacket.m in Sources */ = {isa = PBXBuildFile; fileRef = 301D29201B4BFD9800599BE8 /* GPGPacket.m */; }; + 301D29261B4C032D00599BE8 /* GPGPublicKeyEncryptedSessionKeyPacket.h in Headers */ = {isa = PBXBuildFile; fileRef = 301D29241B4C032D00599BE8 /* GPGPublicKeyEncryptedSessionKeyPacket.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 301D29271B4C032D00599BE8 /* GPGPublicKeyEncryptedSessionKeyPacket.m in Sources */ = {isa = PBXBuildFile; fileRef = 301D29251B4C032D00599BE8 /* GPGPublicKeyEncryptedSessionKeyPacket.m */; }; 301D5D9F178C9871003026E7 /* GPGKeyserver.h in Headers */ = {isa = PBXBuildFile; fileRef = 301D5D9D178C9871003026E7 /* GPGKeyserver.h */; }; 301D5DA0178C9871003026E7 /* GPGKeyserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 301D5D9E178C9871003026E7 /* GPGKeyserver.m */; }; 3026F4AF13A203A000F3CA02 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3026F4AE13A203A000F3CA02 /* Security.framework */; }; @@ -63,21 +71,39 @@ 30691AA4136AECC4004AA469 /* GPGOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 30691AA2136AECC4004AA469 /* GPGOptions.h */; settings = {ATTRIBUTES = (Public, ); }; }; 30691AA5136AECC4004AA469 /* GPGOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 30691AA3136AECC4004AA469 /* GPGOptions.m */; }; 307C211C1B1745F5006B07A7 /* gpgtools.icns in Resources */ = {isa = PBXBuildFile; fileRef = 307C211B1B1745F5006B07A7 /* gpgtools.icns */; }; + 307FDE421B4E636A00462E4E /* GPGCompressedDataPacket.h in Headers */ = {isa = PBXBuildFile; fileRef = 307FDE401B4E636A00462E4E /* GPGCompressedDataPacket.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 307FDE431B4E636A00462E4E /* GPGCompressedDataPacket.m in Sources */ = {isa = PBXBuildFile; fileRef = 307FDE411B4E636A00462E4E /* GPGCompressedDataPacket.m */; }; 309A18D013E3812E0069DC0F /* GPGTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 309A18CE13E3812E0069DC0F /* GPGTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; }; 309A18D113E3812E0069DC0F /* GPGTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 309A18CF13E3812E0069DC0F /* GPGTransformer.m */; }; - 309A20FB13587D5B0041E0AA /* GPGPacket.h in Headers */ = {isa = PBXBuildFile; fileRef = 309A20F913587D5B0041E0AA /* GPGPacket.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 309A20FC13587D5B0041E0AA /* GPGPacket.m in Sources */ = {isa = PBXBuildFile; fileRef = 309A20FA13587D5B0041E0AA /* GPGPacket.m */; }; 30A058391799E2DC00E1AD20 /* GPGKeyManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 30A058371799E2DC00E1AD20 /* GPGKeyManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; 30A0583A1799E2DC00E1AD20 /* GPGKeyManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 30A058381799E2DC00E1AD20 /* GPGKeyManager.m */; }; + 30A48E8E1B4C1344006AD363 /* GPGSignaturePacket.h in Headers */ = {isa = PBXBuildFile; fileRef = 30A48E8C1B4C1344006AD363 /* GPGSignaturePacket.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 30A48E8F1B4C1344006AD363 /* GPGSignaturePacket.m in Sources */ = {isa = PBXBuildFile; fileRef = 30A48E8D1B4C1344006AD363 /* GPGSignaturePacket.m */; }; 30A70EE513EF328000EE9CD9 /* GPGException.h in Headers */ = {isa = PBXBuildFile; fileRef = 30A70EE313EF328000EE9CD9 /* GPGException.h */; settings = {ATTRIBUTES = (Public, ); }; }; 30A70EE613EF328000EE9CD9 /* GPGException.m in Sources */ = {isa = PBXBuildFile; fileRef = 30A70EE413EF328000EE9CD9 /* GPGException.m */; }; 30B586F5141E255C000373F1 /* Keyservers.plist in Resources */ = {isa = PBXBuildFile; fileRef = 30B586F4141E255C000373F1 /* Keyservers.plist */; }; 30BA88F2138FE593005982D9 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 30BA88F1138FE593005982D9 /* SystemConfiguration.framework */; }; + 30BB7C681B4D2742006A1E47 /* GPGSymmetricEncryptedSessionKeyPacket.h in Headers */ = {isa = PBXBuildFile; fileRef = 30BB7C661B4D2742006A1E47 /* GPGSymmetricEncryptedSessionKeyPacket.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 30BB7C691B4D2742006A1E47 /* GPGSymmetricEncryptedSessionKeyPacket.m in Sources */ = {isa = PBXBuildFile; fileRef = 30BB7C671B4D2742006A1E47 /* GPGSymmetricEncryptedSessionKeyPacket.m */; }; + 30BB7C6C1B4D2E38006A1E47 /* GPGOnePassSignaturePacket.h in Headers */ = {isa = PBXBuildFile; fileRef = 30BB7C6A1B4D2E38006A1E47 /* GPGOnePassSignaturePacket.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 30BB7C6D1B4D2E38006A1E47 /* GPGOnePassSignaturePacket.m in Sources */ = {isa = PBXBuildFile; fileRef = 30BB7C6B1B4D2E38006A1E47 /* GPGOnePassSignaturePacket.m */; }; + 30BB7C701B4D3244006A1E47 /* GPGKeyMaterialPacket.h in Headers */ = {isa = PBXBuildFile; fileRef = 30BB7C6E1B4D3244006A1E47 /* GPGKeyMaterialPacket.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 30BB7C711B4D3244006A1E47 /* GPGKeyMaterialPacket.m in Sources */ = {isa = PBXBuildFile; fileRef = 30BB7C6F1B4D3244006A1E47 /* GPGKeyMaterialPacket.m */; }; + 30BB7C781B4D3F24006A1E47 /* GPGIgnoredPackets.h in Headers */ = {isa = PBXBuildFile; fileRef = 30BB7C761B4D3F24006A1E47 /* GPGIgnoredPackets.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 30BB7C791B4D3F24006A1E47 /* GPGIgnoredPackets.m in Sources */ = {isa = PBXBuildFile; fileRef = 30BB7C771B4D3F24006A1E47 /* GPGIgnoredPackets.m */; }; + 30BB7C7C1B4D4146006A1E47 /* GPGLiteralDataPacket.h in Headers */ = {isa = PBXBuildFile; fileRef = 30BB7C7A1B4D4146006A1E47 /* GPGLiteralDataPacket.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 30BB7C7D1B4D4146006A1E47 /* GPGLiteralDataPacket.m in Sources */ = {isa = PBXBuildFile; fileRef = 30BB7C7B1B4D4146006A1E47 /* GPGLiteralDataPacket.m */; }; + 30BB7C801B4D4A59006A1E47 /* GPGUserIDPacket.h in Headers */ = {isa = PBXBuildFile; fileRef = 30BB7C7E1B4D4A59006A1E47 /* GPGUserIDPacket.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 30BB7C811B4D4A59006A1E47 /* GPGUserIDPacket.m in Sources */ = {isa = PBXBuildFile; fileRef = 30BB7C7F1B4D4A59006A1E47 /* GPGUserIDPacket.m */; }; + 30BB7C841B4D4BF8006A1E47 /* GPGUserAttributePacket.h in Headers */ = {isa = PBXBuildFile; fileRef = 30BB7C821B4D4BF8006A1E47 /* GPGUserAttributePacket.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 30BB7C851B4D4BF8006A1E47 /* GPGUserAttributePacket.m in Sources */ = {isa = PBXBuildFile; fileRef = 30BB7C831B4D4BF8006A1E47 /* GPGUserAttributePacket.m */; }; + 30C045931B4FDB9800080903 /* GPGCompressedDataPacket_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 30C045921B4FDB9800080903 /* GPGCompressedDataPacket_Private.h */; }; 30C60EEF12FF3321006BB8DA /* Libmacgpg.h in Headers */ = {isa = PBXBuildFile; fileRef = 30C60EEE12FF3321006BB8DA /* Libmacgpg.h */; settings = {ATTRIBUTES = (Public, ); }; }; 30C8B39C1395052D00F49AA1 /* Test1.m in Sources */ = {isa = PBXBuildFile; fileRef = 30C8B39B1395052D00F49AA1 /* Test1.m */; }; 30C8B3B11395072C00F49AA1 /* Libmacgpg.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8DC2EF5B0486A6940098B216 /* Libmacgpg.framework */; }; 30D5E2A41483A0F700F31454 /* GPGConf.h in Headers */ = {isa = PBXBuildFile; fileRef = 30D5E2A21483A0F700F31454 /* GPGConf.h */; }; 30D5E2A51483A0F700F31454 /* GPGConf.m in Sources */ = {isa = PBXBuildFile; fileRef = 30D5E2A31483A0F700F31454 /* GPGConf.m */; }; + 30D68BC51B4FF5D500F7865C /* COPYING.pgpdump in Resources */ = {isa = PBXBuildFile; fileRef = 30D68BC41B4FF5D500F7865C /* COPYING.pgpdump */; }; 30FF413712FAC6CD00F39832 /* GPGController.h in Headers */ = {isa = PBXBuildFile; fileRef = 30FF411D12FAC6CD00F39832 /* GPGController.h */; settings = {ATTRIBUTES = (Public, ); }; }; 30FF413812FAC6CD00F39832 /* GPGController.m in Sources */ = {isa = PBXBuildFile; fileRef = 30FF411E12FAC6CD00F39832 /* GPGController.m */; }; 30FF413B12FAC6CD00F39832 /* GPGGlobals.h in Headers */ = {isa = PBXBuildFile; fileRef = 30FF412112FAC6CD00F39832 /* GPGGlobals.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -214,8 +240,18 @@ 1BE88B3D1B47D7F900A812B6 /* GPGSocketCloseTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GPGSocketCloseTest.m; sourceTree = ""; }; 3002C04316EE388B00D57C1E /* libcrypto.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libcrypto.dylib; path = usr/lib/libcrypto.dylib; sourceTree = SDKROOT; }; 3002C04516EE389100D57C1E /* libxar.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libxar.dylib; path = usr/lib/libxar.dylib; sourceTree = SDKROOT; }; + 300F3DB31B4AC2CE00E36AAA /* libbz2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libbz2.dylib; path = usr/lib/libbz2.dylib; sourceTree = SDKROOT; }; + 300F3DB41B4AC2CE00E36AAA /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; 301A44CB1B436405002A38E4 /* GPGUnArmor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGUnArmor.h; sourceTree = ""; }; 301A44CC1B436405002A38E4 /* GPGUnArmor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGUnArmor.m; sourceTree = ""; }; + 301D291B1B4BE4F500599BE8 /* GPGPacketParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPGPacketParser.h; path = GPGPacket/GPGPacketParser.h; sourceTree = ""; }; + 301D291C1B4BE4F500599BE8 /* GPGPacketParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGPacketParser.m; path = GPGPacket/GPGPacketParser.m; sourceTree = ""; }; + 301D291F1B4BFD9800599BE8 /* GPGPacket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPGPacket.h; path = GPGPacket/GPGPacket.h; sourceTree = ""; }; + 301D29201B4BFD9800599BE8 /* GPGPacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGPacket.m; path = GPGPacket/GPGPacket.m; sourceTree = ""; }; + 301D29231B4BFDCE00599BE8 /* GPGPacket_Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = GPGPacket_Private.h; path = GPGPacket/GPGPacket_Private.h; sourceTree = ""; }; + 301D29241B4C032D00599BE8 /* GPGPublicKeyEncryptedSessionKeyPacket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPGPublicKeyEncryptedSessionKeyPacket.h; path = GPGPacket/GPGPublicKeyEncryptedSessionKeyPacket.h; sourceTree = ""; }; + 301D29251B4C032D00599BE8 /* GPGPublicKeyEncryptedSessionKeyPacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGPublicKeyEncryptedSessionKeyPacket.m; path = GPGPacket/GPGPublicKeyEncryptedSessionKeyPacket.m; sourceTree = ""; }; + 301D29281B4C049C00599BE8 /* GPGPacketParser_Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = GPGPacketParser_Private.h; path = GPGPacket/GPGPacketParser_Private.h; sourceTree = ""; }; 301D5D9D178C9871003026E7 /* GPGKeyserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGKeyserver.h; sourceTree = ""; }; 301D5D9E178C9871003026E7 /* GPGKeyserver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGKeyserver.m; sourceTree = ""; }; 3026F4AE13A203A000F3CA02 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; @@ -236,16 +272,33 @@ 3077AE881A6547D2001EC508 /* SecurityFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SecurityFoundation.framework; path = System/Library/Frameworks/SecurityFoundation.framework; sourceTree = SDKROOT; }; 307C211B1B1745F5006B07A7 /* gpgtools.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = gpgtools.icns; path = Resources/gpgtools.icns; sourceTree = SOURCE_ROOT; }; 307D79101340B71A005C9C32 /* TODO */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = TODO; sourceTree = ""; }; + 307FDE401B4E636A00462E4E /* GPGCompressedDataPacket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPGCompressedDataPacket.h; path = GPGPacket/GPGCompressedDataPacket.h; sourceTree = ""; }; + 307FDE411B4E636A00462E4E /* GPGCompressedDataPacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGCompressedDataPacket.m; path = GPGPacket/GPGCompressedDataPacket.m; sourceTree = ""; }; 309A18CE13E3812E0069DC0F /* GPGTransformer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGTransformer.h; sourceTree = ""; }; 309A18CF13E3812E0069DC0F /* GPGTransformer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGTransformer.m; sourceTree = ""; }; - 309A20F913587D5B0041E0AA /* GPGPacket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGPacket.h; sourceTree = ""; }; - 309A20FA13587D5B0041E0AA /* GPGPacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGPacket.m; sourceTree = ""; }; 30A058371799E2DC00E1AD20 /* GPGKeyManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGKeyManager.h; sourceTree = ""; }; 30A058381799E2DC00E1AD20 /* GPGKeyManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGKeyManager.m; sourceTree = ""; }; + 30A48E8C1B4C1344006AD363 /* GPGSignaturePacket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPGSignaturePacket.h; path = GPGPacket/GPGSignaturePacket.h; sourceTree = ""; }; + 30A48E8D1B4C1344006AD363 /* GPGSignaturePacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGSignaturePacket.m; path = GPGPacket/GPGSignaturePacket.m; sourceTree = ""; }; 30A70EE313EF328000EE9CD9 /* GPGException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGException.h; sourceTree = ""; }; 30A70EE413EF328000EE9CD9 /* GPGException.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGException.m; sourceTree = ""; }; 30B586F4141E255C000373F1 /* Keyservers.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Keyservers.plist; sourceTree = ""; }; 30BA88F1138FE593005982D9 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; + 30BB7C661B4D2742006A1E47 /* GPGSymmetricEncryptedSessionKeyPacket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPGSymmetricEncryptedSessionKeyPacket.h; path = GPGPacket/GPGSymmetricEncryptedSessionKeyPacket.h; sourceTree = ""; }; + 30BB7C671B4D2742006A1E47 /* GPGSymmetricEncryptedSessionKeyPacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGSymmetricEncryptedSessionKeyPacket.m; path = GPGPacket/GPGSymmetricEncryptedSessionKeyPacket.m; sourceTree = ""; }; + 30BB7C6A1B4D2E38006A1E47 /* GPGOnePassSignaturePacket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPGOnePassSignaturePacket.h; path = GPGPacket/GPGOnePassSignaturePacket.h; sourceTree = ""; }; + 30BB7C6B1B4D2E38006A1E47 /* GPGOnePassSignaturePacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGOnePassSignaturePacket.m; path = GPGPacket/GPGOnePassSignaturePacket.m; sourceTree = ""; }; + 30BB7C6E1B4D3244006A1E47 /* GPGKeyMaterialPacket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPGKeyMaterialPacket.h; path = GPGPacket/GPGKeyMaterialPacket.h; sourceTree = ""; }; + 30BB7C6F1B4D3244006A1E47 /* GPGKeyMaterialPacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGKeyMaterialPacket.m; path = GPGPacket/GPGKeyMaterialPacket.m; sourceTree = ""; }; + 30BB7C761B4D3F24006A1E47 /* GPGIgnoredPackets.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPGIgnoredPackets.h; path = GPGPacket/GPGIgnoredPackets.h; sourceTree = ""; }; + 30BB7C771B4D3F24006A1E47 /* GPGIgnoredPackets.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGIgnoredPackets.m; path = GPGPacket/GPGIgnoredPackets.m; sourceTree = ""; }; + 30BB7C7A1B4D4146006A1E47 /* GPGLiteralDataPacket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPGLiteralDataPacket.h; path = GPGPacket/GPGLiteralDataPacket.h; sourceTree = ""; }; + 30BB7C7B1B4D4146006A1E47 /* GPGLiteralDataPacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGLiteralDataPacket.m; path = GPGPacket/GPGLiteralDataPacket.m; sourceTree = ""; }; + 30BB7C7E1B4D4A59006A1E47 /* GPGUserIDPacket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPGUserIDPacket.h; path = GPGPacket/GPGUserIDPacket.h; sourceTree = ""; }; + 30BB7C7F1B4D4A59006A1E47 /* GPGUserIDPacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGUserIDPacket.m; path = GPGPacket/GPGUserIDPacket.m; sourceTree = ""; }; + 30BB7C821B4D4BF8006A1E47 /* GPGUserAttributePacket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPGUserAttributePacket.h; path = GPGPacket/GPGUserAttributePacket.h; sourceTree = ""; }; + 30BB7C831B4D4BF8006A1E47 /* GPGUserAttributePacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGUserAttributePacket.m; path = GPGPacket/GPGUserAttributePacket.m; sourceTree = ""; }; + 30C045921B4FDB9800080903 /* GPGCompressedDataPacket_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPGCompressedDataPacket_Private.h; path = GPGPacket/GPGCompressedDataPacket_Private.h; sourceTree = ""; }; 30C60EEE12FF3321006BB8DA /* Libmacgpg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Libmacgpg.h; sourceTree = ""; }; 30C8B38E139503A800F49AA1 /* UnitTest.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UnitTest.octest; sourceTree = BUILT_PRODUCTS_DIR; }; 30C8B38F139503A800F49AA1 /* UnitTest-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "UnitTest-Info.plist"; sourceTree = ""; }; @@ -253,6 +306,9 @@ 30C8B39B1395052D00F49AA1 /* Test1.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Test1.m; sourceTree = ""; }; 30D5E2A21483A0F700F31454 /* GPGConf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = GPGConf.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 30D5E2A31483A0F700F31454 /* GPGConf.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGConf.m; sourceTree = ""; }; + 30D68BC41B4FF5D500F7865C /* COPYING.pgpdump */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = COPYING.pgpdump; path = Source/GPGPacket/COPYING.pgpdump; sourceTree = SOURCE_ROOT; }; + 30D8099D1B5004FE007E9D63 /* GPGPacket2.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPGPacket2.h; sourceTree = ""; }; + 30D8099E1B5004FE007E9D63 /* GPGPacket2.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GPGPacket2.m; sourceTree = ""; }; 30DF7CBB16D39EAA00C8225C /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 30FF411D12FAC6CD00F39832 /* GPGController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGController.h; sourceTree = ""; }; 30FF411E12FAC6CD00F39832 /* GPGController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGController.m; sourceTree = ""; }; @@ -368,6 +424,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 300F3DB51B4AC2CE00E36AAA /* libbz2.dylib in Frameworks */, + 300F3DB61B4AC2CE00E36AAA /* libz.dylib in Frameworks */, 1B3D657A1565C60100D93BBE /* Foundation.framework in Frameworks */, 8DC2EF570486A6940098B216 /* Cocoa.framework in Frameworks */, 30BA88F2138FE593005982D9 /* SystemConfiguration.framework in Frameworks */, @@ -414,6 +472,8 @@ 0867D69AFE84028FC02AAC07 /* Frameworks */ = { isa = PBXGroup; children = ( + 300F3DB31B4AC2CE00E36AAA /* libbz2.dylib */, + 300F3DB41B4AC2CE00E36AAA /* libz.dylib */, 3077AE881A6547D2001EC508 /* SecurityFoundation.framework */, 1058C7B1FEA5585E11CA2CBB /* Cocoa.framework */, 30BA88F1138FE593005982D9 /* SystemConfiguration.framework */, @@ -433,6 +493,7 @@ 30516556142281270038AAF0 /* Localizable.strings */, 30B586F4141E255C000373F1 /* Keyservers.plist */, 8DC2EF5A0486A6940098B216 /* Info.plist */, + 30D68BC41B4FF5D500F7865C /* COPYING.pgpdump */, ); path = Resources; sourceTree = ""; @@ -443,6 +504,7 @@ 1B72F73E157AE85B00101194 /* Additions */, 302AA377133605FE0022A371 /* GPGKey */, 307FAABB13F26BB4003FA99B /* GPGOptions */, + 301D291A1B4BE47100599BE8 /* GPGPacket */, 306C73821B45B0F200A34730 /* GPGStream */, 30C60EEE12FF3321006BB8DA /* Libmacgpg.h */, 30FF411D12FAC6CD00F39832 /* GPGController.h */, @@ -453,8 +515,6 @@ 30A70EE413EF328000EE9CD9 /* GPGException.m */, 30FF412112FAC6CD00F39832 /* GPGGlobals.h */, 30FF412212FAC6CD00F39832 /* GPGGlobals.m */, - 309A20F913587D5B0041E0AA /* GPGPacket.h */, - 309A20FA13587D5B0041E0AA /* GPGPacket.m */, 301A44CB1B436405002A38E4 /* GPGUnArmor.h */, 301A44CC1B436405002A38E4 /* GPGUnArmor.m */, 30FF413112FAC6CD00F39832 /* GPGTask.h */, @@ -562,6 +622,42 @@ name = "Supporting Files"; sourceTree = ""; }; + 301D291A1B4BE47100599BE8 /* GPGPacket */ = { + isa = PBXGroup; + children = ( + 30D8099D1B5004FE007E9D63 /* GPGPacket2.h */, + 30D8099E1B5004FE007E9D63 /* GPGPacket2.m */, + 301D291B1B4BE4F500599BE8 /* GPGPacketParser.h */, + 301D29281B4C049C00599BE8 /* GPGPacketParser_Private.h */, + 301D291C1B4BE4F500599BE8 /* GPGPacketParser.m */, + 301D291F1B4BFD9800599BE8 /* GPGPacket.h */, + 301D29231B4BFDCE00599BE8 /* GPGPacket_Private.h */, + 301D29201B4BFD9800599BE8 /* GPGPacket.m */, + 301D29241B4C032D00599BE8 /* GPGPublicKeyEncryptedSessionKeyPacket.h */, + 301D29251B4C032D00599BE8 /* GPGPublicKeyEncryptedSessionKeyPacket.m */, + 30A48E8C1B4C1344006AD363 /* GPGSignaturePacket.h */, + 30A48E8D1B4C1344006AD363 /* GPGSignaturePacket.m */, + 30BB7C661B4D2742006A1E47 /* GPGSymmetricEncryptedSessionKeyPacket.h */, + 30BB7C671B4D2742006A1E47 /* GPGSymmetricEncryptedSessionKeyPacket.m */, + 30BB7C6A1B4D2E38006A1E47 /* GPGOnePassSignaturePacket.h */, + 30BB7C6B1B4D2E38006A1E47 /* GPGOnePassSignaturePacket.m */, + 30BB7C6E1B4D3244006A1E47 /* GPGKeyMaterialPacket.h */, + 30BB7C6F1B4D3244006A1E47 /* GPGKeyMaterialPacket.m */, + 30BB7C761B4D3F24006A1E47 /* GPGIgnoredPackets.h */, + 30BB7C771B4D3F24006A1E47 /* GPGIgnoredPackets.m */, + 30BB7C7A1B4D4146006A1E47 /* GPGLiteralDataPacket.h */, + 30BB7C7B1B4D4146006A1E47 /* GPGLiteralDataPacket.m */, + 30BB7C7E1B4D4A59006A1E47 /* GPGUserIDPacket.h */, + 30BB7C7F1B4D4A59006A1E47 /* GPGUserIDPacket.m */, + 30BB7C821B4D4BF8006A1E47 /* GPGUserAttributePacket.h */, + 30BB7C831B4D4BF8006A1E47 /* GPGUserAttributePacket.m */, + 307FDE401B4E636A00462E4E /* GPGCompressedDataPacket.h */, + 30C045921B4FDB9800080903 /* GPGCompressedDataPacket_Private.h */, + 307FDE411B4E636A00462E4E /* GPGCompressedDataPacket.m */, + ); + name = GPGPacket; + sourceTree = ""; + }; 302AA377133605FE0022A371 /* GPGKey */ = { isa = PBXGroup; children = ( @@ -717,13 +813,25 @@ 30FF414B12FAC6CD00F39832 /* GPGTask.h in Headers */, 30FF414712FAC6CD00F39832 /* GPGSignature.h in Headers */, 30FF414F12FAC6CD00F39832 /* GPGUserID.h in Headers */, - 309A20FB13587D5B0041E0AA /* GPGPacket.h in Headers */, 30691AA4136AECC4004AA469 /* GPGOptions.h in Headers */, 309A18D013E3812E0069DC0F /* GPGTransformer.h in Headers */, 30A70EE513EF328000EE9CD9 /* GPGException.h in Headers */, + 301D291D1B4BE4F500599BE8 /* GPGPacketParser.h in Headers */, + 307FDE421B4E636A00462E4E /* GPGCompressedDataPacket.h in Headers */, + 301D29211B4BFD9800599BE8 /* GPGPacket.h in Headers */, + 301D29261B4C032D00599BE8 /* GPGPublicKeyEncryptedSessionKeyPacket.h in Headers */, + 30BB7C841B4D4BF8006A1E47 /* GPGUserAttributePacket.h in Headers */, + 30BB7C7C1B4D4146006A1E47 /* GPGLiteralDataPacket.h in Headers */, + 30BB7C6C1B4D2E38006A1E47 /* GPGOnePassSignaturePacket.h in Headers */, + 30BB7C701B4D3244006A1E47 /* GPGKeyMaterialPacket.h in Headers */, + 30A48E8E1B4C1344006AD363 /* GPGSignaturePacket.h in Headers */, + 30BB7C801B4D4A59006A1E47 /* GPGUserIDPacket.h in Headers */, + 30BB7C681B4D2742006A1E47 /* GPGSymmetricEncryptedSessionKeyPacket.h in Headers */, 451D8829156A7AD900A0B890 /* GPGStream.h in Headers */, + 30C045931B4FDB9800080903 /* GPGCompressedDataPacket_Private.h in Headers */, 30A058391799E2DC00E1AD20 /* GPGKeyManager.h in Headers */, 451D882D156A7CA300A0B890 /* GPGMemoryStream.h in Headers */, + 30BB7C781B4D3F24006A1E47 /* GPGIgnoredPackets.h in Headers */, 451D8831156A7E4900A0B890 /* GPGFileStream.h in Headers */, 1BCE0CD11617A3DF0026DCFF /* NSBundle+Sandbox.h in Headers */, 301A44CD1B436405002A38E4 /* GPGUnArmor.h in Headers */, @@ -953,6 +1061,7 @@ files = ( 30444C501A65E83D0052CB94 /* GPGTools.app in Resources */, 30B586F5141E255C000373F1 /* Keyservers.plist in Resources */, + 30D68BC51B4FF5D500F7865C /* COPYING.pgpdump in Resources */, 30516558142281270038AAF0 /* Localizable.strings in Resources */, 1B46CFA2161531DC00CF9C5F /* org.gpgtools.Libmacgpg.xpc.plist in Resources */, ); @@ -1153,38 +1262,49 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 30A48E8F1B4C1344006AD363 /* GPGSignaturePacket.m in Sources */, 30FF413812FAC6CD00F39832 /* GPGController.m in Sources */, 30FF413C12FAC6CD00F39832 /* GPGGlobals.m in Sources */, 30FF413E12FAC6CD00F39832 /* GPGKey.m in Sources */, 30FF414012FAC6CD00F39832 /* GPGUserIDSignature.m in Sources */, 30FF414412FAC6CD00F39832 /* GPGRemoteKey.m in Sources */, 30FF414612FAC6CD00F39832 /* GPGRemoteUserID.m in Sources */, + 301D291E1B4BE4F500599BE8 /* GPGPacketParser.m in Sources */, 30FF414812FAC6CD00F39832 /* GPGSignature.m in Sources */, + 30BB7C711B4D3244006A1E47 /* GPGKeyMaterialPacket.m in Sources */, 30A0583A1799E2DC00E1AD20 /* GPGKeyManager.m in Sources */, + 301D29221B4BFD9800599BE8 /* GPGPacket.m in Sources */, 30FF414C12FAC6CD00F39832 /* GPGTask.m in Sources */, 30FF414E12FAC6CD00F39832 /* GPGTaskOrder.m in Sources */, + 30BB7C6D1B4D2E38006A1E47 /* GPGOnePassSignaturePacket.m in Sources */, 30FF415012FAC6CD00F39832 /* GPGUserID.m in Sources */, - 309A20FC13587D5B0041E0AA /* GPGPacket.m in Sources */, 30691AA5136AECC4004AA469 /* GPGOptions.m in Sources */, 1BC7A50113D300A600AE57BA /* LPXTTask.m in Sources */, 309A18D113E3812E0069DC0F /* GPGTransformer.m in Sources */, 301A44CE1B436405002A38E4 /* GPGUnArmor.m in Sources */, + 307FDE431B4E636A00462E4E /* GPGCompressedDataPacket.m in Sources */, 30A70EE613EF328000EE9CD9 /* GPGException.m in Sources */, 3048830C1462B11700F2E5F4 /* DirectoryWatcher.m in Sources */, 304883101462B22000F2E5F4 /* GPGWatcher.m in Sources */, 30D5E2A51483A0F700F31454 /* GPGConf.m in Sources */, 451932F614F8061100D1F727 /* GPGStdSetting.m in Sources */, + 30BB7C7D1B4D4146006A1E47 /* GPGLiteralDataPacket.m in Sources */, 301D5DA0178C9871003026E7 /* GPGKeyserver.m in Sources */, 4570876714FAA7C90030AAE6 /* GPGConfReader.m in Sources */, 45156A1D14FB1B1200129FE7 /* GPGLinesSetting.m in Sources */, + 30BB7C791B4D3F24006A1E47 /* GPGIgnoredPackets.m in Sources */, + 30BB7C851B4D4BF8006A1E47 /* GPGUserAttributePacket.m in Sources */, 45156A2114FB1D7D00129FE7 /* GPGDictSetting.m in Sources */, 45156A2B14FB3EF700129FE7 /* GPGArraySetting.m in Sources */, 451D882A156A7AD900A0B890 /* GPGStream.m in Sources */, 451D882E156A7CA300A0B890 /* GPGMemoryStream.m in Sources */, + 301D29271B4C032D00599BE8 /* GPGPublicKeyEncryptedSessionKeyPacket.m in Sources */, 451D8832156A7E4900A0B890 /* GPGFileStream.m in Sources */, 1B9DB26B15784DB700488353 /* GPGTaskHelper.m in Sources */, 1B72F742157AE89600101194 /* NSPipe+NoSigPipe.m in Sources */, 1BCE0CD21617A3DF0026DCFF /* NSBundle+Sandbox.m in Sources */, + 30BB7C811B4D4A59006A1E47 /* GPGUserIDPacket.m in Sources */, + 30BB7C691B4D2742006A1E47 /* GPGSymmetricEncryptedSessionKeyPacket.m in Sources */, 1B9FF21117257A69004FB017 /* GPGTaskHelperXPC.m in Sources */, 1B84028817296EA4009A40E6 /* GPGUserDefaults.m in Sources */, ); @@ -1735,6 +1855,7 @@ 1BE88B441B47D7F900A812B6 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; 1DEB91AD08733DA50010E9CD /* Build configuration list for PBXNativeTarget "Libmacgpg" */ = { isa = XCConfigurationList; diff --git a/Source/GPGController.m b/Source/GPGController.m index 3e7c864..57b1698 100644 --- a/Source/GPGController.m +++ b/Source/GPGController.m @@ -17,21 +17,12 @@ Programm erhalten haben. Falls nicht, siehe . */ -#import "GPGController.h" -#import "GPGKey.h" +#import "Libmacgpg.h" #import "GPGTaskOrder.h" -#import "GPGRemoteKey.h" -#import "GPGSignature.h" -#import "GPGOptions.h" -#import "GPGPacket.h" -#import "GPGWatcher.h" -#import "GPGMemoryStream.h" #import "GPGTypesRW.h" -#import "GPGKeyManager.h" #import "GPGKeyserver.h" #import "GPGTaskHelper.h" -#import "GPGTask.h" -#import "GPGUnArmor.h" +#import "GPGWatcher.h" #if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 #import "GPGTaskHelperXPC.h" #import "NSBundle+Sandbox.h" @@ -2282,29 +2273,39 @@ - (NSInteger)indexOfSubkey:(NSObject *)subkey fromKey:(NSObject - (NSSet *)keysInExportedData:(NSData *)data encrypted:(BOOL *)encrypted { // Returns a set of fingerprints and keyIDs of keys and key-parts (like signatures) in the data. + NSMutableSet *keys = [NSMutableSet set]; NSMutableSet *keyIDs = [NSMutableSet set]; + - NSArray *packets = [GPGPacket packetsWithData:data]; + GPGMemoryStream *stream = [GPGMemoryStream memoryStreamForReading:data]; + GPGPacketParser *parser = [GPGPacketParser packetParserWithStream:stream]; - if (encrypted) { - *encrypted = NO; - } - - - for (GPGPacket *packet in packets) { - if (packet.type == GPGPublicKeyPacket || packet.type == GPGSecretKeyPacket) { - [keys addObject:packet.fingerprint]; - } else if (packet.type == GPGPublicKeyEncryptedSessionKeyPacket || packet.type == GPGSymmetricEncryptedSessionKeyPacket) { - if (encrypted) { - *encrypted = YES; - } - } else if (packet.type == GPGSignaturePacket) { - if (packet.fingerprint.length > 0) { - [keys addObject:packet.fingerprint]; - } else if (packet.keyID) { - [keyIDs addObject:packet.keyID]; + GPGPacket *packet; + + while ((packet = parser.nextPacket)) { + switch (packet.tag) { + case GPGPublicKeyPacketTag: + case GPGSecretKeyPacketTag: + case GPGPublicSubkeyPacketTag: + case GPGSecretSubkeyPacketTag: + [keys addObject:[(GPGPublicKeyPacket *)packet fingerprint]]; + break; + case GPGSymmetricEncryptedSessionKeyPacketTag: + case GPGPublicKeyEncryptedSessionKeyPacketTag: + if (encrypted) { + *encrypted = YES; + } + break; + case GPGSignaturePacketTag: { + GPGSignaturePacket *signaturePacket = (GPGSignaturePacket *)packet; + if (signaturePacket.keyID) { + [keyIDs addObject:signaturePacket.keyID]; + } + break; } + default: + break; } } @@ -2315,8 +2316,7 @@ - (NSSet *)keysInExportedData:(NSData *)data encrypted:(BOOL *)encrypted { } [keys unionSet:keyIDs]; } - - + return keys; } diff --git a/Source/GPGGlobals.h b/Source/GPGGlobals.h index c4ff5f4..e424ff4 100644 --- a/Source/GPGGlobals.h +++ b/Source/GPGGlobals.h @@ -80,26 +80,6 @@ typedef enum { GPGDeletePublicAndSecretKey } GPGDeleteKeyMode; -typedef enum { - GPGPublicKeyEncryptedSessionKeyPacket = 1, - GPGSignaturePacket = 2, - GPGSymmetricEncryptedSessionKeyPacket = 3, - GPGOnePassSignaturePacket = 4, - GPGSecretKeyPacket = 5, - GPGPublicKeyPacket = 6, - GPGSecretSubkeyPacket = 7, - GPGCompressedDataPacket = 8, - GPGSymmetricEncryptedDataPacket = 9, - GPGMarkerPacket = 10, - GPGLiteralDataPacket = 11, - GPGTrustPacket = 12, - GPGUserIDPacket = 13, - GPGPublicSubkeyPacket = 14, - GPGUserAttributePacket = 17, - GPGSymmetricEncryptedProtectedDataPacket = 18, - GPGModificationDetectionCodePacket = 19 -} GPGPacketType; - typedef enum { GPGBinarySignature = 0, GPGTextSignature = 1, diff --git a/Source/GPGPacket.h b/Source/GPGPacket.h deleted file mode 100644 index 196835b..0000000 --- a/Source/GPGPacket.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - Copyright © Roman Zechmeister, 2014 - - Diese Datei ist Teil von Libmacgpg. - - Libmacgpg ist freie Software. Sie können es unter den Bedingungen - der GNU General Public License, wie von der Free Software Foundation - veröffentlicht, weitergeben und/oder modifizieren, entweder gemäß - Version 3 der Lizenz oder (nach Ihrer Option) jeder späteren Version. - - Die Veröffentlichung von Libmacgpg erfolgt in der Hoffnung, daß es Ihnen - von Nutzen sein wird, aber ohne irgendeine Garantie, sogar ohne die implizite - Garantie der Marktreife oder der Verwendbarkeit für einen bestimmten Zweck. - Details finden Sie in der GNU General Public License. - - Sie sollten ein Exemplar der GNU General Public License zusammen mit diesem - Programm erhalten haben. Falls nicht, siehe . -*/ - -#import - -@class GPGStream; - - -@interface GPGPacket : NSObject { - GPGPacketType type; - NSData *data; - NSString *keyID; - NSString *fingerprint; - uint8_t publicKeyAlgorithm; - uint8_t symetricAlgorithm; - uint8_t hashAlgorithm; - uint8_t signatureType; - NSString *description; - NSMutableArray *subpackets; -} - -@property (nonatomic, readonly) GPGPacketType type; -@property (nonatomic, readonly) NSData *data; -@property (nonatomic, readonly) NSString *keyID; -@property (nonatomic, readonly) NSString *fingerprint; -@property (nonatomic, readonly) uint8_t publicKeyAlgorithm; -@property (nonatomic, readonly) uint8_t symetricAlgorithm; -@property (nonatomic, readonly) uint8_t hashAlgorithm; -@property (nonatomic, readonly) uint8_t signatureType; - -@property (nonatomic, readonly) NSArray *subpackets; // At the moment a array of dicts. Can change at any time. - - -+ (id)packetsWithData:(NSData *)data; -+ (void)enumeratePacketsWithData:(NSData *)theData block:(void (^)(GPGPacket *packet, BOOL *stop))block; - - - - -// Old methods, only for compatibility: - -+ (NSData *)unArmor:(NSData *)data DEPRECATED_ATTRIBUTE; -+ (NSData *)unArmor:(NSData *)data clearText:(NSData **)clearText DEPRECATED_ATTRIBUTE; - -@end diff --git a/Source/GPGPacket.m b/Source/GPGPacket.m deleted file mode 100644 index 32564ee..0000000 --- a/Source/GPGPacket.m +++ /dev/null @@ -1,376 +0,0 @@ -/* - Copyright © Roman Zechmeister, 2014 - - Diese Datei ist Teil von Libmacgpg. - - Libmacgpg ist freie Software. Sie können es unter den Bedingungen - der GNU General Public License, wie von der Free Software Foundation - veröffentlicht, weitergeben und/oder modifizieren, entweder gemäß - Version 3 der Lizenz oder (nach Ihrer Option) jeder späteren Version. - - Die Veröffentlichung von Libmacgpg erfolgt in der Hoffnung, daß es Ihnen - von Nutzen sein wird, aber ohne irgendeine Garantie, sogar ohne die implizite - Garantie der Marktreife oder der Verwendbarkeit für einen bestimmten Zweck. - Details finden Sie in der GNU General Public License. - - Sie sollten ein Exemplar der GNU General Public License zusammen mit diesem - Programm erhalten haben. Falls nicht, siehe . - */ - -#import "GPGPacket.h" -#import "GPGMemoryStream.h" -#import "GPGGlobals.h" -#import "GPGException.h" -#include -#include -#include -#import "GPGUnArmor.h" - -#define COMMON_DIGEST_FOR_OPENSSL -#include - - -#define readUint8 (*((*((uint8_t**)&readPos))++)) -#define readUint16 CFSwapInt16BigToHost(*((*((uint16_t**)&readPos))++)) -#define readUint32 CFSwapInt32BigToHost(*((*((uint32_t**)&readPos))++)) -#define readUint64 CFSwapInt64BigToHost(*((*((uint64_t**)&readPos))++)) -#define abortInit [self release]; return nil; -#define abortSwitch type = 0; break; -#define canRead(x) if (readPos-bytes+(x) > dataLength) {goto endOfBuffer;} - - - - - -@interface GPGPacket () -- (id)initWithBytes:(const uint8_t *)bytes length:(NSUInteger)dataLength nextPacketStart:(const uint8_t **)nextPacket; - -@end - - - - -@implementation GPGPacket -@synthesize type, data, keyID, fingerprint, publicKeyAlgorithm, symetricAlgorithm, hashAlgorithm, signatureType, subpackets; - - - -+ (id)packetsWithData:(NSData *)theData { - NSMutableArray *packets = [NSMutableArray array]; - - [self enumeratePacketsWithData:theData block:^(GPGPacket *packet, BOOL *stop) { - [packets addObject:packet]; - }]; - - return packets; -} - -+ (void)enumeratePacketsWithData:(NSData *)theData block:(void (^)(GPGPacket *packet, BOOL *stop))block { - theData = [theData copy]; - - if (theData.isArmored) { - GPGMemoryStream *stream = [GPGMemoryStream memoryStreamForReading:theData]; - GPGUnArmor *unArmor = [GPGUnArmor unArmorWithGPGStream:stream]; - - [unArmor decodeAll]; - - [theData release]; - theData = [unArmor.data retain]; - } - - - if (theData.length < 10) { - [theData release]; - return; - } - const uint8_t *bytes = theData.bytes; - - - const uint8_t *endPos = bytes + theData.length; - const uint8_t *currentPos = bytes; - const uint8_t *nextPacketPos = 0; - BOOL stop = NO; - - while (currentPos < endPos) { - nextPacketPos = 0; - GPGPacket *packet = [[self alloc] initWithBytes:currentPos length:endPos - currentPos nextPacketStart:&nextPacketPos]; - if (packet) { - block(packet, &stop); - [packet release]; - if (stop) { - [theData release]; - return; - } - } - if (nextPacketPos <= currentPos) { - break; - } - currentPos = nextPacketPos; - } - - [theData release]; -} - -- (id)initWithBytes:(const uint8_t *)bytes length:(NSUInteger)dataLength nextPacketStart:(const uint8_t **)nextPacket { - if (!(self = [super init])) { - return nil; - } - description = nil; - - const uint8_t *readPos = bytes; - canRead(1); - - if (!(bytes[0] & 0x80)) { - [self release]; - return nil; - } - - BOOL newFormat = bytes[0] & 0x40; - unsigned int length; - - if (newFormat) { - type = *readPos & 0x3F; - readPos++; - const uint8_t *oldReadPos = readPos; - - length = 0; - while (1) { - canRead(1); - if (*readPos < 192) { - length += *readPos; - readPos = oldReadPos + 1; - break; - } else if (*readPos < 224) { - canRead(2); - length += ((readPos[0] - 192) << 8) + readPos[1] + 192; - readPos = oldReadPos + 2; - break; - } else if (*readPos == 255) { - readPos++; - canRead(4); - length += readUint32; - readPos = oldReadPos + 4; - break; - } - //TODO: Full support for Partial Packets. - unsigned int partLength = (1 << (*readPos & 0x1F)) + 1; - readPos += partLength; - length += partLength; - } - - } else { - type = (*readPos & 0x3C) >> 2; - if (type == 0) { - abortInit; - } - switch (*(readPos++) & 3) { - case 0: - canRead(1); - length = readUint8; - break; - case 1: - canRead(2); - length = readUint16; - break; - case 2: - canRead(4); - length = readUint32; - break; - default: - length = dataLength - 1; - break; - } - } - canRead(length); - data = [[NSData alloc] initWithBytes:bytes length:readPos - bytes + length]; - - *nextPacket = readPos + length; - - - - - switch (type) { //TODO: Parse packet content. - case GPGPublicKeyEncryptedSessionKeyPacket: - canRead(10); - if (readUint8 != 3) { - abortSwitch; - } - keyID = [[NSString alloc] initWithFormat:@"%016llX", readUint64]; - publicKeyAlgorithm = readUint8; - break; - case GPGSignaturePacket: - canRead(12); - switch (readUint8) { - case 3: - //TODO - break; - case 4: { - signatureType = readUint8; - publicKeyAlgorithm = readUint8; - hashAlgorithm = readUint8; - - - - // Subpackets verarbeiten. - subpackets = [[NSMutableArray alloc] init]; - - for (int i = 0; i < 2; i++) { // Zweimal da es hashed und unhashed subpackets geben kann! - const uint8_t *subpacketEnd = readUint16 + readPos; - while (readPos < subpacketEnd) { - NSMutableDictionary *subpacket = [[NSMutableDictionary alloc] init]; - - uint32_t subpacketLength = readUint8; - if (subpacketLength == 255) { - subpacketLength = readUint32; - } else if (subpacketLength >= 192) { - subpacketLength = ((subpacketLength - 192) << 8) + readUint8 + 192; - } - uint8_t subpacketType = readUint8; - - [subpacket setObject:@(subpacketLength) forKey:@"length"]; - [subpacket setObject:@(subpacketType) forKey:@"type"]; - - if (subpacketType == 16 && subpacketLength == 9) { - keyID = [bytesToHexString(readPos, 8) retain]; - } - - - [subpackets addObject:subpacket]; - [subpacket release]; - - readPos += subpacketLength - 1; - } - } - - - break; } - } - break; - case GPGSymmetricEncryptedSessionKeyPacket: - canRead(2); - if (readUint8 != 3) { - abortSwitch; - } - symetricAlgorithm = readUint8; - break; - case GPGOnePassSignaturePacket: - canRead(13); - if (readUint8 != 4) { - abortSwitch; - } - signatureType = readUint8; - hashAlgorithm = readUint8; - publicKeyAlgorithm = readUint8; - keyID = [[NSString alloc] initWithFormat:@"%016llX", readUint64]; - break; - case GPGPublicKeyPacket: - case GPGPublicSubkeyPacket: - case GPGSecretKeyPacket: - case GPGSecretSubkeyPacket: { - const uint8_t *packetStart = readPos; - canRead(6); - if (readUint8 != 4) { - abortSwitch; - } - readPos += 4; - publicKeyAlgorithm = readUint8; - - - uint8_t bytesForSHA1[length + 3]; - bytesForSHA1[0] = 0x99; - uint16_t temp = (uint16_t)length; - bytesForSHA1[1] = ((uint8_t*)&temp)[1]; - bytesForSHA1[2] = ((uint8_t*)&temp)[0]; - memcpy(bytesForSHA1+3, packetStart, length); - - uint8_t fingerprintBytes[20]; - CC_SHA1(bytesForSHA1, length + 3, fingerprintBytes); - fingerprint = [bytesToHexString(fingerprintBytes, 20) retain]; - keyID = [[fingerprint keyID] retain]; - - break; } - case GPGCompressedDataPacket: - //TODO - break; - case GPGSymmetricEncryptedDataPacket: - //TODO - break; - case GPGMarkerPacket: - //TODO - break; - case GPGLiteralDataPacket: - //TODO - break; - case GPGTrustPacket: - //TODO - break; - case GPGUserIDPacket: - //TODO - break; - case GPGUserAttributePacket: - //TODO - break; - case GPGSymmetricEncryptedProtectedDataPacket: - //TODO - break; - case GPGModificationDetectionCodePacket: - //TODO - break; - default: //Unknown packet type. - abortSwitch; - } - - - return self; -endOfBuffer: - abortInit; -} - -- (id)init { - [self release]; - return nil; -} - -- (void)dealloc { - [data release]; - [fingerprint release]; - [keyID release]; - [description release]; - [subpackets release]; - - [super dealloc]; -} - -- (NSString *)description { - if (!description) { - description = [[NSString alloc] initWithFormat:@"GPGPacket type: %i, keyID %@", self.type, self.keyID]; - } - - return [[description retain] autorelease]; -} - - - -// Old methods, only for compatibility. - -// if return nil, input stream is not armored; should be reset and used directly -+ (NSData *)unArmor:(NSData *)data { - return [self unArmor:data clearText:nil]; -} -+ (NSData *)unArmor:(NSData *)data clearText:(NSData **)clearText { - GPGMemoryStream *stream = [GPGMemoryStream memoryStreamForReading:data]; - GPGUnArmor *unArmor = [GPGUnArmor unArmorWithGPGStream:stream]; - - [unArmor decodeAll]; - - if (clearText) { - *clearText = unArmor.clearText; - } - - return unArmor.data; -} - - - - -@end diff --git a/Source/GPGPacket/COPYING.pgpdump b/Source/GPGPacket/COPYING.pgpdump new file mode 100644 index 0000000..680875a --- /dev/null +++ b/Source/GPGPacket/COPYING.pgpdump @@ -0,0 +1,30 @@ +Copyright of pgpdump, it does NOT apply to Libmacgpg. +For the original source see: https://github.com/kazu-yamamoto/pgpdump + +Copyright (C) 1998 Kazuhiko Yamamoto +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the name of the author nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Source/GPGPacket/GPGCompressedDataPacket.h b/Source/GPGPacket/GPGCompressedDataPacket.h new file mode 100644 index 0000000..94387fc --- /dev/null +++ b/Source/GPGPacket/GPGCompressedDataPacket.h @@ -0,0 +1,34 @@ +/* GPGCompressedDataPacket.h + Copyright © Roman Zechmeister, 2015 + + This file is part of Libmacgpg. + + Libmacgpg is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Libmacgpg is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA + */ + +#import + +@class GPGPacketParser, GPGDecompressStream; + +@interface GPGCompressedDataPacket : GPGPacket { + NSInteger compressAlgorithm; + GPGDecompressStream *decompressStream; + GPGPacketParser *subParser; +} + +@property (nonatomic, readonly) NSInteger compressAlgorithm; + +@end diff --git a/Source/GPGPacket/GPGCompressedDataPacket.m b/Source/GPGPacket/GPGCompressedDataPacket.m new file mode 100644 index 0000000..2b62535 --- /dev/null +++ b/Source/GPGPacket/GPGCompressedDataPacket.m @@ -0,0 +1,312 @@ +/* GPGCompressedDataPacket.m + Based on pgpdump (https://github.com/kazu-yamamoto/pgpdump) from Kazuhiko Yamamoto. + Copyright © Roman Zechmeister, 2015 + + This file is part of Libmacgpg. + + Libmacgpg is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Libmacgpg is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA + */ + +#import "GPGCompressedDataPacket.h" +#import "GPGCompressedDataPacket_Private.h" +#import "GPGPacket_Private.h" +#import "GPGPacketParser.h" +#import "GPGStream.h" +#import +#import + + +@interface GPGDecompressStream : GPGStream { + GPGPacketParser *parser; + NSInteger algorithm; + z_stream zStream; + bz_stream bzStream; + + NSUInteger packetLength; + + BOOL streamEnd; + NSUInteger availablePacketBytes; + NSMutableData *inputData; + UInt8 *inputBytes; + NSUInteger inputSize; + + NSMutableData *cacheData; + UInt8 *cacheBytes; + + NSUInteger cacheLocation; + NSUInteger cacheAvailableBytes; +} +- (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)length algorithm:(NSInteger)algorithm; +@end + + + +@interface GPGCompressedDataPacket () +@property (nonatomic, readwrite) NSInteger compressAlgorithm; +@property (nonatomic, strong, readwrite) GPGDecompressStream *decompressStream; +@property (nonatomic, strong) GPGPacketParser *subParser; +@end + + +@implementation GPGCompressedDataPacket +@synthesize compressAlgorithm, decompressStream, subParser; + +- (instancetype)initWithParser:(GPGPacketParser *)theParser length:(NSUInteger)length { + self = [super init]; + if (!self) { + return nil; + } + self.compressAlgorithm = theParser.byte; + length--; + + switch (compressAlgorithm) { + case 0: + case 1: + case 2: + case 3: + break; + default: + [theParser skip:length]; + return self; + } + + self.decompressStream = [[GPGDecompressStream alloc] initWithParser:theParser length:length algorithm:compressAlgorithm]; + if (decompressStream) { + self.subParser = [[GPGPacketParser alloc] initWithStream:self.decompressStream]; + } + + return self; +} + +- (GPGPacket *)nextPacket { + GPGPacket *packet = [subParser nextPacket]; + if (!packet) { + self.decompressStream = nil; + self.subParser = nil; + } + return packet; +} + +- (BOOL)canDecompress { + return !!subParser; +} + +- (GPGPacketTag)tag { + return 8; +} + +- (void)dealloc { + self.decompressStream = nil; + self.subParser = nil; + [super dealloc]; +} +@end + + + +@implementation GPGDecompressStream +const NSUInteger cacheSize = 1024 * 32; + +- (void)dealloc { + [cacheData release]; + [inputData release]; + [parser release]; + [super dealloc]; +} + +- (instancetype)initWithParser:(GPGPacketParser *)theParser length:(NSUInteger)length algorithm:(NSInteger)theAlgorithm { + self = [super init]; + if (!self) { + return nil; + } + + + parser = [theParser retain]; + algorithm = theAlgorithm; + packetLength = length; + availablePacketBytes = packetLength; + + inputData = [[NSMutableData alloc] initWithLength:cacheSize]; + cacheData = [[NSMutableData alloc] initWithLength:cacheSize]; + + int status = 0; + + switch (algorithm) { + case 0: + // No compresseion. + [inputData release]; + inputData = [cacheData retain]; + break; + case 1: + status = inflateInit2(&zStream, -13); + break; + case 2: + status = inflateInit(&zStream); + break; + case 3: + status = BZ2_bzDecompressInit(&bzStream, 0, 0); + break; + } + + if (status != 0) { + [self release]; + return nil; + } + + inputBytes = inputData.mutableBytes; + cacheBytes = cacheData.mutableBytes; + + + return self; +} + +- (void)fillInput { + inputSize = 0; + if (packetLength != 0) { + for (; inputSize < cacheSize; inputSize++) { + NSInteger byte = parser.byteOrEOF; + if (byte == EOF) { + break; + } + inputBytes[inputSize] = (UInt8)byte; + availablePacketBytes--; + + if (availablePacketBytes == 0) { + if (parser.partial) { + packetLength = parser.nextPartialLength; + availablePacketBytes = packetLength; + } else { + packetLength = 0; + } + if (packetLength == 0) { + // We have no more data. + break; + } + } + } + } + +} + +- (BOOL)zlibFillCache { + zStream.avail_out = cacheSize; + zStream.next_out = cacheBytes; + + do { + if (zStream.avail_in == 0) { + // We need more input Data, fill the buffer. + [self fillInput]; + zStream.avail_in = inputSize; + zStream.next_in = inputBytes; + } + + + int status = inflate(&zStream, Z_SYNC_FLUSH); + + if (status != Z_OK) { + inflateEnd(&zStream); + streamEnd = YES; + if (status != Z_STREAM_END) { + return NO; + } + } + + } while (zStream.avail_out == cacheSize); + + + cacheAvailableBytes = cacheSize - zStream.avail_out; + + return YES; +} + +- (BOOL)bzFillCache { + bzStream.avail_out = cacheSize; + bzStream.next_out = (char *)cacheBytes; + + do { + if (bzStream.avail_in == 0) { + // We need more input Data, fill the buffer. + [self fillInput]; + bzStream.avail_in = inputSize; + bzStream.next_in = (char *)inputBytes; + } + + int status = BZ2_bzDecompress(&bzStream); + + if (status != BZ_OK) { + BZ2_bzDecompressEnd(&bzStream); + streamEnd = YES; + if (status != BZ_STREAM_END) { + return NO; + } + } + + } while (bzStream.avail_out == cacheSize); + + + cacheAvailableBytes = cacheSize - bzStream.avail_out; + + return YES; +} + +- (BOOL)uncompressedFillCache { + [self fillInput]; + + if (inputSize == 0) { + streamEnd = YES; + return NO; + } + cacheAvailableBytes = inputSize; + + return YES; +} + +- (NSInteger)readByte { + if (cacheAvailableBytes == 0) { + if (streamEnd) { + return EOF; + } + cacheLocation = 0; + + BOOL moreData = NO; + + switch (algorithm) { + case 0: + moreData = [self uncompressedFillCache]; + break; + case 1: + case 2: + moreData = [self zlibFillCache]; + break; + case 3: + moreData = [self bzFillCache]; + break; + } + if (streamEnd) { + [parser release]; + parser = nil; + } + if (!moreData) { + return EOF; + } + + } + + cacheAvailableBytes--; + return cacheBytes[cacheLocation++]; +} + +@end diff --git a/Source/GPGPacket/GPGCompressedDataPacket_Private.h b/Source/GPGPacket/GPGCompressedDataPacket_Private.h new file mode 100644 index 0000000..b7917ae --- /dev/null +++ b/Source/GPGPacket/GPGCompressedDataPacket_Private.h @@ -0,0 +1,29 @@ +/* GPGCompressedDataPacket_Private.h + Copyright © Roman Zechmeister, 2015 + + This file is part of Libmacgpg. + + Libmacgpg is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Libmacgpg is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA + */ + +#import "GPGCompressedDataPacket.h" + +@interface GPGCompressedDataPacket () +- (BOOL)canDecompress; +- (GPGPacket *)nextPacket; +@end + + diff --git a/Source/GPGPacket/GPGIgnoredPackets.h b/Source/GPGPacket/GPGIgnoredPackets.h new file mode 100644 index 0000000..d26b92f --- /dev/null +++ b/Source/GPGPacket/GPGIgnoredPackets.h @@ -0,0 +1,37 @@ +/* GPGIgnoredPackets.h + Copyright © Roman Zechmeister, 2015 + + This file is part of Libmacgpg. + + Libmacgpg is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Libmacgpg is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA + */ + +#import + +@interface GPGIgnoredPacket : GPGPacket +@end + +@interface GPGEncryptedDataPacket : GPGIgnoredPacket +@end + +@interface GPGMarkerPacket : GPGIgnoredPacket +@end + +@interface GPGTrustPacket : GPGIgnoredPacket +@end + +@interface GPGEncryptedProtectedDataPacket : GPGIgnoredPacket +@end diff --git a/Source/GPGPacket/GPGIgnoredPackets.m b/Source/GPGPacket/GPGIgnoredPackets.m new file mode 100644 index 0000000..37a62d7 --- /dev/null +++ b/Source/GPGPacket/GPGIgnoredPackets.m @@ -0,0 +1,61 @@ +/* GPGIgnoredPackets.m + Copyright © Roman Zechmeister, 2015 + + This file is part of Libmacgpg. + + Libmacgpg is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Libmacgpg is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA + */ + +#import "GPGIgnoredPackets.h" +#import "GPGPacket_Private.h" + + +@implementation GPGIgnoredPacket +- (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)length { + self = [super init]; + if (!self) { + return nil; + } + + [parser skip:length]; + return self; +} +@end + +@implementation GPGEncryptedDataPacket +- (GPGPacketTag)tag { + return 9; +} +@end + +@implementation GPGMarkerPacket +- (GPGPacketTag)tag { + return 10; +} +@end + +@implementation GPGTrustPacket +- (GPGPacketTag)tag { + return 12; +} +@end + +@implementation GPGEncryptedProtectedDataPacket +- (GPGPacketTag)tag { + return 18; +} +@end + diff --git a/Source/GPGPacket/GPGKeyMaterialPacket.h b/Source/GPGPacket/GPGKeyMaterialPacket.h new file mode 100644 index 0000000..a046550 --- /dev/null +++ b/Source/GPGPacket/GPGKeyMaterialPacket.h @@ -0,0 +1,55 @@ +/* GPGKeyMaterialPacket.h + Copyright © Roman Zechmeister, 2015 + + This file is part of Libmacgpg. + + Libmacgpg is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Libmacgpg is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA + */ + +#import + +@interface GPGPublicKeyPacket : GPGPacket { + NSInteger publicAlgorithm; + NSInteger version; + NSInteger validDays; + NSDate *creationDate; + NSString *fingerprint; + NSString *keyID; +} + +@property (nonatomic, readonly) NSInteger publicAlgorithm; +@property (nonatomic, readonly) NSInteger version; +@property (nonatomic, readonly) NSInteger validDays; // Only set on old keys. +@property (nonatomic, strong, readonly) NSDate *creationDate; +@property (nonatomic, strong, readonly) NSString *fingerprint; +@property (nonatomic, strong, readonly) NSString *keyID; + + +@end + +@interface GPGPublicSubkeyPacket : GPGPublicKeyPacket +@end + + +@interface GPGSecretKeyPacket : GPGPublicKeyPacket +@end + + +@interface GPGSecretSubkeyPacket : GPGSecretKeyPacket +@end + + + diff --git a/Source/GPGPacket/GPGKeyMaterialPacket.m b/Source/GPGPacket/GPGKeyMaterialPacket.m new file mode 100644 index 0000000..612a5a6 --- /dev/null +++ b/Source/GPGPacket/GPGKeyMaterialPacket.m @@ -0,0 +1,199 @@ +/* GPGKeyMaterialPacket.m + Based on pgpdump (https://github.com/kazu-yamamoto/pgpdump) from Kazuhiko Yamamoto. + Copyright © Roman Zechmeister, 2015 + + This file is part of Libmacgpg. + + Libmacgpg is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Libmacgpg is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA + */ + +#import "GPGKeyMaterialPacket.h" +#import "GPGPacket_Private.h" +#import "GPGGlobals.h" +#import + +@interface GPGPublicKeyPacket () +@property (nonatomic, readwrite) NSInteger publicAlgorithm; +@property (nonatomic, readwrite) NSInteger version; +@property (nonatomic, readwrite) NSInteger validDays; +@property (nonatomic, strong, readwrite) NSDate *creationDate; +@property (nonatomic, strong, readwrite) NSString *fingerprint; +@property (nonatomic, strong, readwrite) NSString *keyID; +@end + + +@implementation GPGPublicKeyPacket +@synthesize publicAlgorithm, version, validDays, creationDate, fingerprint, keyID; + +- (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)length { + self = [super init]; + if (!self) { + return nil; + } + + self.version = parser.byte; + switch (version) { + case 2: + case 3: { + // Old format, deprecated and weak! + + self.creationDate = parser.date; + self.validDays = parser.uint16; + + self.publicAlgorithm = parser.byte; // Should be 1. + + + CC_MD5_CTX md5; + CC_MD5_Init(&md5); + + NSData *modulus = [parser multiPrecisionInteger]; // "RSA n" + if (modulus.length >= 8) { + // The Key ID is the low 64 bits of the modulus. + self.keyID = bytesToHexString(modulus.bytes + modulus.length - 8, 8); + } + NSData *exponent = [parser multiPrecisionInteger]; // "RSA e" + + CC_MD5_Update(&md5, modulus.bytes, modulus.length); + CC_MD5_Update(&md5, exponent.bytes, exponent.length); + + UInt8 fingerprintBytes[16]; + CC_MD5_Final(fingerprintBytes, &md5); + + // The fingerprint is the md5 hashed modulus and exponent. + self.fingerprint = bytesToHexString(fingerprintBytes, 16); + + break; + } + case 4: { + // New format. + + + // The fingerprint is the SHA1 over "0x99, (UInt16)length, 0x04 and the remaining bytes of the packet. + // We use the byteCallback to put every byte into dataToHash. + NSUInteger dataLength = length + 3; + NSMutableData *dataToHash = [NSMutableData dataWithLength:dataLength]; + __block UInt8 *bytesToHash = dataToHash.mutableBytes; + bytesToHash[0] = 0x99; + bytesToHash[1] = (length >> 8) & 0xFF; + bytesToHash[2] = length & 0xFF; + bytesToHash[3] = 4; // Version + __block NSUInteger i = 4; + + ByteCallback callback = ^(NSInteger byte) { + if (i < dataLength) { + bytesToHash[i] = (UInt8)byte; + i++; + } + }; + + parser.byteCallback = callback; + + + self.creationDate = parser.date; + self.publicAlgorithm = parser.byte; + + switch (publicAlgorithm) { + case 1: + case 2: + case 3: + [parser multiPrecisionInteger]; // "RSA n" + [parser multiPrecisionInteger]; // "RSA e" + break; + case 16: + case 20: + [parser multiPrecisionInteger]; // "ElGamal p" + [parser multiPrecisionInteger]; // "ElGamal g" + [parser multiPrecisionInteger]; // "ElGamal y" + break; + case 17: + [parser multiPrecisionInteger]; // "DSA p" + [parser multiPrecisionInteger]; // "DSA q" + [parser multiPrecisionInteger]; // "DSA g" + [parser multiPrecisionInteger]; // "DSA y" + break; + default: + [parser skip:length - 6]; + break; + } + + parser.byteCallback = nil; + + // Get the fingerprint by hashing dataToHash using SHA1. + uint8_t fingerprintBytes[20]; + CC_SHA1(bytesToHash, dataLength, fingerprintBytes); + + self.fingerprint = bytesToHexString(fingerprintBytes, 20); + self.keyID = [fingerprint keyID]; + + break; + } + default: + [parser skip:length - 1]; + break; + } + + + return self; +} + +- (GPGPacketTag)tag { + return 6; +} + +- (void)dealloc { + self.creationDate = nil; + self.fingerprint = nil; + self.keyID = nil; + [super dealloc]; +} +@end + + +@implementation GPGPublicSubkeyPacket +- (GPGPacketTag)tag { + return 14; +} +@end + + +@implementation GPGSecretKeyPacket +- (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)length { + self = [super initWithParser:parser length:length]; + if (!self) { + return nil; + } + + //TODO: Parse secret-key. + + [parser skipRemaining]; + + return self; +} + +- (GPGPacketTag)tag { + return 5; +} +@end + + +@implementation GPGSecretSubkeyPacket +- (GPGPacketTag)tag { + return 7; +} +@end + + + diff --git a/Source/GPGPacket/GPGLiteralDataPacket.h b/Source/GPGPacket/GPGLiteralDataPacket.h new file mode 100644 index 0000000..fd34312 --- /dev/null +++ b/Source/GPGPacket/GPGLiteralDataPacket.h @@ -0,0 +1,37 @@ +/* GPGLiteralDataPacket.h + Copyright © Roman Zechmeister, 2015 + + This file is part of Libmacgpg. + + Libmacgpg is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Libmacgpg is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA + */ + +#import + +@interface GPGLiteralDataPacket : GPGPacket { + NSInteger format; + NSString *filename; + NSDate *date; + NSData *content; +} + +@property (nonatomic, readonly) NSInteger format; +@property (nonatomic, strong, readonly) NSString *filename; // "_CONSOLE" means "for your eyes only". +@property (nonatomic, strong, readonly) NSDate *date; +@property (nonatomic, copy, readonly) NSData *content; + +@end + diff --git a/Source/GPGPacket/GPGLiteralDataPacket.m b/Source/GPGPacket/GPGLiteralDataPacket.m new file mode 100644 index 0000000..98740cd --- /dev/null +++ b/Source/GPGPacket/GPGLiteralDataPacket.m @@ -0,0 +1,90 @@ +/* GPGLiteralDataPacket.m + Copyright © Roman Zechmeister, 2015 + + This file is part of Libmacgpg. + + Libmacgpg is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Libmacgpg is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA + */ + +#import "GPGLiteralDataPacket.h" +#import "GPGPacket_Private.h" + +@interface GPGLiteralDataPacket () +@property (nonatomic, readwrite) NSInteger format; +@property (nonatomic, strong, readwrite) NSString *filename; +@property (nonatomic, strong, readwrite) NSDate *date; +@property (nonatomic, copy, readwrite) NSData *content; +@end + + +@implementation GPGLiteralDataPacket +@synthesize format, filename, date, content; + + +- (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)length { + self = [super init]; + if (!self) { + return nil; + } + + self.format = parser.byte; + + NSUInteger len = parser.byte; + + self.filename = [parser stringWithLength:len]; + + self.date = parser.date; + length = length - 6 - len; + + + NSMutableData *tempData = [NSMutableData data]; + NSUInteger i = 0; + + while (length > 0) { + tempData.length += length; + UInt8 *bytes = tempData.mutableBytes; + + for (NSUInteger j = 0; j < length; j++) { + bytes[i++] = (UInt8)parser.byte; + } + + if (parser.partial) { + length = parser.nextPartialLength; + } else { + length = 0; + } + } + + self.content = tempData; + + + return self; +} + +- (GPGPacketTag)tag { + return 11; +} + +- (void)dealloc { + self.filename = nil; + self.date = nil; + self.content = nil; + [super dealloc]; +} + + +@end + diff --git a/Source/GPGPacket/GPGOnePassSignaturePacket.h b/Source/GPGPacket/GPGOnePassSignaturePacket.h new file mode 100644 index 0000000..6b40c1d --- /dev/null +++ b/Source/GPGPacket/GPGOnePassSignaturePacket.h @@ -0,0 +1,39 @@ +/* GPGOnePassSignaturePacket.h + Copyright © Roman Zechmeister, 2015 + + This file is part of Libmacgpg. + + Libmacgpg is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Libmacgpg is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA + */ + +#import + +@interface GPGOnePassSignaturePacket : GPGPacket { + NSInteger publicAlgorithm; + NSInteger hashAlgorithm; + NSInteger type; + NSInteger version; + NSString *keyID; +} + +@property (nonatomic, readonly) NSInteger publicAlgorithm; +@property (nonatomic, readonly) NSInteger hashAlgorithm; +@property (nonatomic, readonly) NSInteger type; +@property (nonatomic, readonly) NSInteger version; +@property (nonatomic, strong, readonly) NSString *keyID; + + +@end diff --git a/Source/GPGPacket/GPGOnePassSignaturePacket.m b/Source/GPGPacket/GPGOnePassSignaturePacket.m new file mode 100644 index 0000000..ac491f7 --- /dev/null +++ b/Source/GPGPacket/GPGOnePassSignaturePacket.m @@ -0,0 +1,64 @@ +/* GPGOnePassSignaturePacket.m + Copyright © Roman Zechmeister, 2015 + + This file is part of Libmacgpg. + + Libmacgpg is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Libmacgpg is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA + */ + +#import "GPGOnePassSignaturePacket.h" +#import "GPGPacket_Private.h" + +@interface GPGOnePassSignaturePacket () +@property (nonatomic, readwrite) NSInteger publicAlgorithm; +@property (nonatomic, readwrite) NSInteger hashAlgorithm; +@property (nonatomic, readwrite) NSInteger type; +@property (nonatomic, readwrite) NSInteger version; +@property (nonatomic, strong, readwrite) NSString *keyID; +@end + + +@implementation GPGOnePassSignaturePacket +@synthesize publicAlgorithm, hashAlgorithm, type, version, keyID; + +- (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)length { + self = [super init]; + if (!self) { + return nil; + } + + self.version = parser.byte; + self.type = parser.byte; + self.hashAlgorithm = parser.byte; + self.publicAlgorithm = parser.byte; + self.keyID = parser.keyID; + + [parser byte]; // Ignore (0 = the next packet is another one-pass signature) + + return self; +} + +- (GPGPacketTag)tag { + return 4; +} + +- (void)dealloc { + self.keyID = nil; + [super dealloc]; +} + + +@end diff --git a/Source/GPGPacket/GPGPacket.h b/Source/GPGPacket/GPGPacket.h new file mode 100644 index 0000000..4e8603b --- /dev/null +++ b/Source/GPGPacket/GPGPacket.h @@ -0,0 +1,62 @@ +/* GPGPacket.h + Copyright © Roman Zechmeister, 2015 + + This file is part of Libmacgpg. + + Libmacgpg is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Libmacgpg is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA + */ + +typedef NS_ENUM(NSInteger, GPGPacketTag) { + GPGPublicKeyEncryptedSessionKeyPacketTag = 1, + GPGSignaturePacketTag = 2, + GPGSymmetricEncryptedSessionKeyPacketTag = 3, + GPGOnePassSignaturePacketTag = 4, + GPGSecretKeyPacketTag = 5, + GPGPublicKeyPacketTag = 6, + GPGSecretSubkeyPacketTag = 7, + GPGCompressedDataPacketTag = 8, + GPGEncryptedDataPacketTag = 9, + GPGMarkerPacketTag = 10, + GPGLiteralDataPacketTag = 11, + GPGTrustPacketTag = 12, + GPGUserIDPacketTag = 13, + GPGPublicSubkeyPacketTag = 14, + GPGUserAttributePacketTag = 17, + GPGEncryptedProtectedDataPacketTag = 18, +}; + + + + + +@interface GPGPacket : NSObject +@property (readonly) GPGPacketTag tag; + + + +// Old methods, only for compatibility: + +- (NSInteger)type UNAVAILABLE_ATTRIBUTE; +- (NSString *)keyID UNAVAILABLE_ATTRIBUTE; +- (NSInteger)signatureType UNAVAILABLE_ATTRIBUTE; + ++ (id)packetsWithData:(NSData *)data DEPRECATED_ATTRIBUTE; ++ (void)enumeratePacketsWithData:(NSData *)theData block:(void (^)(GPGPacket *packet, BOOL *stop))block DEPRECATED_ATTRIBUTE; ++ (NSData *)unArmor:(NSData *)data DEPRECATED_ATTRIBUTE; ++ (NSData *)unArmor:(NSData *)data clearText:(NSData **)clearText DEPRECATED_ATTRIBUTE; + + +@end diff --git a/Source/GPGPacket/GPGPacket.m b/Source/GPGPacket/GPGPacket.m new file mode 100644 index 0000000..c8dca3b --- /dev/null +++ b/Source/GPGPacket/GPGPacket.m @@ -0,0 +1,128 @@ +/* GPGPacket.m + Copyright © Roman Zechmeister, 2015 + + This file is part of Libmacgpg. + + Libmacgpg is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Libmacgpg is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA + */ + +#import "GPGPacket.h" +#import "GPGPacket_Private.h" +#import "GPGPacketParser.h" + +#import "GPGMemoryStream.h" +#import "GPGUnArmor.h" + + +@implementation GPGPacket + +- (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)length { + return [super init]; +} +- (GPGPacketTag)tag { + return 0; +} + + + + + + + +// Old methods, only for compatibility. + +- (NSInteger)type { + return self.tag; +} +- (NSString *)keyID { + return nil; +} +- (NSInteger)signatureType { + if (self.tag == GPGSignaturePacketTag) { + return [self type]; + } else { + return 0; + } +} + + ++ (id)packetsWithData:(NSData *)theData { + NSMutableArray *packets = [NSMutableArray array]; + + [self enumeratePacketsWithData:theData block:^(GPGPacket *packet, BOOL *stop) { + [packets addObject:packet]; + }]; + + return packets; +} + ++ (void)enumeratePacketsWithData:(NSData *)theData block:(void (^)(GPGPacket *packet, BOOL *stop))block { + theData = [theData copy]; + + if (theData.isArmored) { + GPGMemoryStream *stream = [GPGMemoryStream memoryStreamForReading:theData]; + GPGUnArmor *unArmor = [GPGUnArmor unArmorWithGPGStream:stream]; + + [unArmor decodeAll]; + + [theData release]; + theData = [unArmor.data retain]; + } + + if (theData.length < 10) { + [theData release]; + return; + } + + GPGMemoryStream *stream = [[GPGMemoryStream alloc] initForReading:theData]; + GPGPacketParser *parser = [[GPGPacketParser alloc] initWithStream:stream]; + GPGPacket *packet; + + while ((packet = [parser nextPacket])) { + BOOL stop = NO; + block(packet, &stop); + if (stop) { + break; + } + } + + [parser release]; + [stream release]; + [theData release]; +} + +// if return nil, input stream is not armored; should be reset and used directly ++ (NSData *)unArmor:(NSData *)data { + return [self unArmor:data clearText:nil]; +} ++ (NSData *)unArmor:(NSData *)data clearText:(NSData **)clearText { + GPGMemoryStream *stream = [GPGMemoryStream memoryStreamForReading:data]; + GPGUnArmor *unArmor = [GPGUnArmor unArmorWithGPGStream:stream]; + + [unArmor decodeAll]; + + if (clearText) { + *clearText = unArmor.clearText; + } + + return unArmor.data; +} + + + + + +@end diff --git a/Source/GPGPacket/GPGPacketParser.h b/Source/GPGPacket/GPGPacketParser.h new file mode 100644 index 0000000..1854b63 --- /dev/null +++ b/Source/GPGPacket/GPGPacketParser.h @@ -0,0 +1,55 @@ +/* GPGPacketParser.h + Copyright © Roman Zechmeister, 2015 + + This file is part of Libmacgpg. + + Libmacgpg is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Libmacgpg is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA + */ + +@class GPGStream; +@class GPGPacket; +@class GPGCompressedDataPacket; + +typedef void (^ByteCallback)(NSInteger); + + +@interface GPGPacketParser : NSObject { + + // Properties + GPGStream *stream; + NSError *error; + + ByteCallback byteCallback; + GPGCompressedDataPacket *compressedPacket; + + BOOL partial; + NSUInteger packetLength; +} + +@property (nonatomic, readonly, strong) NSError *error; + + ++ (instancetype)packetParserWithStream:(GPGStream *)stream; + +- (instancetype)initWithStream:(GPGStream *)stream; +/** + Get the next packet from the stream. + Sets error if an error occurred. + @returns The next packet (subclass of GPGPacket) or nil if an error occurred or it was the last packet. + */ +- (GPGPacket *)nextPacket; + +@end diff --git a/Source/GPGPacket/GPGPacketParser.m b/Source/GPGPacket/GPGPacketParser.m new file mode 100644 index 0000000..a4766aa --- /dev/null +++ b/Source/GPGPacket/GPGPacketParser.m @@ -0,0 +1,509 @@ +/* GPGPacketParser.m + Based on pgpdump (https://github.com/kazu-yamamoto/pgpdump) from Kazuhiko Yamamoto. + Copyright © Roman Zechmeister, 2015 + + This file is part of Libmacgpg. + + Libmacgpg is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Libmacgpg is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA + */ + +#import "GPGPacketParser.h" +#import "GPGStream.h" +#import "GPGGlobals.h" +#import "GPGException.h" +#import "GPGPacket.h" +#import "GPGPacket_Private.h" +#import "GPGPublicKeyEncryptedSessionKeyPacket.h" +#import "GPGSignaturePacket.h" +#import "GPGSymmetricEncryptedSessionKeyPacket.h" +#import "GPGOnePassSignaturePacket.h" +#import "GPGKeyMaterialPacket.h" +#import "GPGIgnoredPackets.h" +#import "GPGLiteralDataPacket.h" +#import "GPGUserIDPacket.h" +#import "GPGUserAttributePacket.h" +#import "GPGCompressedDataPacket_Private.h" + + +#define BINARY_TAG_FLAG 0x80 +#define NEW_TAG_FLAG 0x40 +#define TAG_MASK 0x3f +#define PARTIAL_MASK 0x1f +#define TAG_COMPRESSED 8 + +#define OLD_TAG_SHIFT 2 +#define OLD_LEN_MASK 0x03 + +#define CRITICAL_BIT 0x80 +#define CRITICAL_MASK 0x7f + +static NSString * const endOfFileException = @"endOfFileException"; +static NSArray *tagClasses = nil; + +@interface GPGPacketParser () +@property (nonatomic, readwrite, strong) NSError *error; +@property (nonatomic, strong) GPGStream *stream; +@property (nonatomic, strong) GPGCompressedDataPacket *compressedPacket; +@end + + +@implementation GPGPacketParser +@synthesize stream, compressedPacket; +@synthesize error; +@synthesize byteCallback; + +#pragma mark Main methods + +- (GPGPacket *)nextPacket { + @try { + if (compressedPacket.canDecompress) { + // We have a compressed packet, get the next decompressed packet. + GPGPacket *tempPacket = [compressedPacket nextPacket]; + if (tempPacket) { + return tempPacket; + } else { + self.compressedPacket = nil; + } + } + + NSInteger c = [stream readByte]; + if (c == EOF) { + self.error = nil; + return nil; + } + if ((c & BINARY_TAG_FLAG) == 0) { + self.error = [NSError errorWithDomain:LibmacgpgErrorDomain code:GPGErrorInvalidData userInfo:nil]; + return nil; + } + + + NSInteger tag = c & TAG_MASK; + NSUInteger len = 0; + partial = NO; + + if (c & NEW_TAG_FLAG) { + // New format. + c = self.byte; + len = [self getNewLen:c]; + partial = isPartial(c); + if (partial && len < 512) { + self.error = [NSError errorWithDomain:LibmacgpgErrorDomain code:GPGErrorBadData userInfo:nil]; + return nil; + } + } else { + // Old format. + NSUInteger tlen; + + tlen = c & OLD_LEN_MASK; + tag >>= OLD_TAG_SHIFT; + + switch (tlen) { + case 0: + len = self.byte; + break; + case 1: + len = (self.byte << 8); + len += self.byte; + break; + case 2: + len = self.byte << 24; + len |= self.byte << 16; + len |= self.byte << 8; + len |= self.byte; + break; + case 3: + len = NSUIntegerMax; + break; + } + } + + GPGPacket *packet = nil; + Class class = nil; + + if (tag < tagClasses.count) { + class = tagClasses[tag]; + if (class == [NSNull null]) { + class = nil; + [self skip:len]; + } else { + packetLength = len; + packet = [[[class alloc] initWithParser:self length:len] autorelease]; + + if (tag == TAG_COMPRESSED && [(GPGCompressedDataPacket *)packet canDecompress]) { + self.compressedPacket = (GPGCompressedDataPacket *)packet; + + GPGPacket *tempPacket = [compressedPacket nextPacket]; + if (tempPacket) { + return tempPacket; + } else { + self.compressedPacket = nil; + } + } + } + } else { + [self skip:len]; + } + + while (partial == YES) { + c = self.byte; + len = [self getNewLen:c]; + partial = isPartial(c); + + [self skip:len]; + } + + return packet; + } @catch (NSException *exception) { + if ([exception.name isEqualToString:endOfFileException]) { + self.error = [NSError errorWithDomain:LibmacgpgErrorDomain code:GPGErrorEOF userInfo:nil]; + } else { + @throw; + } + } + + return nil; +} + + +#pragma mark Helper + +- (NSInteger)byte { + NSInteger byte = [stream readByte]; + if (byte == EOF) { + @throw [NSException exceptionWithName:endOfFileException reason:@"unexpected end of file." userInfo:nil]; + } + + packetLength--; + + if (byteCallback) { + byteCallback(byte); + } + + return byte; +} + +- (NSInteger)byteOrEOF { + NSInteger byte = [stream readByte]; + packetLength--; + + if (byteCallback && byte != EOF) { + byteCallback(byte); + } + + return byte; +} + +- (void)skip:(NSUInteger)count { + for (; count > 0; count--) { + [self byte]; + } +} + +static BOOL isPartial(NSInteger c) { + if (c < 224 || c == 255) { + return NO; + } else { + return YES; + } +} + +- (NSUInteger)getNewLen:(NSInteger)c { + NSUInteger len; + + if (c < 192) { + len = c; + } else if (c < 224) { + len = ((c - 192) << 8) + self.byte + 192; + } else if (c == 255) { + len = (self.byte << 24); + len |= (self.byte << 16); + len |= (self.byte << 8); + len |= self.byte; + } else { + len = 1 << (c & PARTIAL_MASK); + } + return len; +} + + +#pragma mark Parsing methods, used by GPGPacket + +- (NSUInteger)nextPartialLength { + if (partial == NO) { + return 0; + } + + NSInteger c = self.byte; + NSUInteger length = [self getNewLen:c]; + partial = isPartial(c); + + return length; +} + +- (BOOL)partial { + return partial; +} + +- (void)skipRemaining { + [self skip:packetLength]; +} + +- (NSString *)keyID { + NSString *keyID = [NSString stringWithFormat:@"%02X%02X%02X%02X%02X%02X%02X%02X", + (UInt8)self.byte, + (UInt8)self.byte, + (UInt8)self.byte, + (UInt8)self.byte, + (UInt8)self.byte, + (UInt8)self.byte, + (UInt8)self.byte, + (UInt8)self.byte]; + + return keyID; +} + +- (id)multiPrecisionInteger { + NSUInteger byteCount; + NSUInteger bits = self.byte * 256; + bits += self.byte; + byteCount = (bits + 7) / 8; + + NSMutableData *data = [NSMutableData dataWithLength:byteCount]; + UInt8 *bytes = data.mutableBytes; + + for (NSUInteger i = 0; i < byteCount; i++) { + bytes[i] = (UInt8)self.byte; + } + + + return data; +} + +- (NSDate *)date { + NSUInteger time; + + time = self.byte << 24; + time |= self.byte << 16; + time |= self.byte << 8; + time |= self.byte; + + if (time == 0) { + return nil; + } + + NSDate *date = [NSDate dateWithTimeIntervalSince1970:time]; + + return date; +} + +- (UInt16)uint16 { + UInt16 value = (UInt16)((self.byte << 8) | self.byte); + return value; +} + +- (NSString *)stringWithLength:(NSUInteger)length { + char tempString[length + 1]; + tempString[length] = 0; + for (NSUInteger i = 0; i < length; i++) { + tempString[i] = (char)self.byte; + } + + NSString *string = [NSString stringWithUTF8String:tempString]; + + return string; +} + +- (NSArray *)signatureSubpacketsWithLength:(NSUInteger)fullLength { + NSMutableArray *packets = [NSMutableArray array]; + + while (fullLength > 0) { + NSUInteger length = self.byte; + if (length < 192) { + fullLength--; + } else if (length < 255) { + length = ((length - 192) << 8) + self.byte + 192; + fullLength -= 2; + } else if (length == 255) { + length = self.byte << 24; + length |= self.byte << 16; + length |= self.byte << 8; + length |= self.byte; + fullLength -= 5; + } + fullLength -= length; + + + NSUInteger remainingLength = packetLength - length; + + + GPGSubpacketTag subtag = self.byte; /* len includes this field byte */ + length--; + + /* Handle critical bit of subpacket type */ + BOOL critical = NO; + if (subtag & CRITICAL_BIT) { + critical = YES; + subtag &= CRITICAL_MASK; + } + + + NSMutableDictionary *packet = [NSMutableDictionary dictionaryWithObjectsAndKeys:@(subtag), @"tag", nil]; + + if (critical) { + packet[@"critical"] = @YES; + } + + + switch (subtag) { + case GPGSignatureCreationTimeTag: + case GPGSignatureExpirationTimeTag: + case GPGKeyExpirationTimeTag: { + NSDate *date = [self date]; + if (date) { + packet[@"date"] = date; + } + break; + } + case GPGIssuerTag: { + NSString *keyID = [self keyID]; + if (keyID) { + packet[@"keyID"] = keyID; + } + break; + } + case GPGPolicyURITag: + case GPGPreferredKeyServerTag: + case GPGSignersUserIDTag: { + NSString *string = [self stringWithLength:length]; + if (string) { + if (subtag == GPGSignersUserIDTag) { + packet[@"userID"] = string; + } else { + packet[@"URI"] = string; + } + } + break; + } + case GPGPrimaryUserIDTag: { + BOOL primary = !!self.byte; + packet[@"primary"] = @(primary); + break; + } + case GPGKeyFlagsTag: { + NSInteger flags = self.byte; + + packet[@"canCertify"] = @(!!(flags & 0x01)); + packet[@"canSign"] = @(!!(flags & 0x02)); + packet[@"canEncryptCommunications"] = @(!!(flags & 0x04)); + packet[@"canEncryptStorage"] = @(!!(flags & 0x08)); + packet[@"maySplitted"] = @(!!(flags & 0x10)); + packet[@"canAuthentication"] = @(!!(flags & 0x20)); + packet[@"multipleOwners"] = @(!!(flags & 0x80)); + + break; + } + case GPGReasonForRevocationTag: { + packet[@"code"] = @(self.byte); + NSString *string = [self stringWithLength:length - 1]; + if (string) { + packet[@"reason"] = string; + } + break; + } + case GPGSignatureTargetTag: { + packet[@"publicAlgorithm"] = @(self.byte); + packet[@"hashAlgorithm"] = @(self.byte); + length -= 2; + + NSMutableData *data = [NSMutableData dataWithLength:length]; + if (data) { + UInt8 *bytes = data.mutableBytes; + + for (NSUInteger i = 0; i < length; i++) { + bytes[i] = (UInt8)self.byte; + } + + packet[@"hash"] = [[data copy] autorelease]; + } + break; + } + default: + break; + } + + [packets addObject:packet]; + + + length = packetLength - remainingLength; + [self skip:length]; + } + + + return packets; +} + + +#pragma mark init etc. + ++ (instancetype)packetParserWithStream:(GPGStream *)stream { + return [[(GPGPacketParser *)[self alloc] initWithStream:stream] autorelease]; +} + +- (instancetype)initWithStream:(GPGStream *)theStream { + self = [super init]; + if (!self) { + return nil; + } + + self.stream = theStream; + + return self; +} + ++ (void)initialize { + tagClasses = [@[ + [NSNull null], + [GPGPublicKeyEncryptedSessionKeyPacket class], // 1 + [GPGSignaturePacket class], // 2 + [GPGSymmetricEncryptedSessionKeyPacket class], // 3 + [GPGOnePassSignaturePacket class], // 4 + [GPGSecretKeyPacket class], // 5 + [GPGPublicKeyPacket class], // 6 + [GPGSecretSubkeyPacket class], // 7 + [GPGCompressedDataPacket class], // 8 + [GPGEncryptedDataPacket class], // 9 + [GPGMarkerPacket class], // 10 + [GPGLiteralDataPacket class], // 11 + [GPGTrustPacket class], // 12 + [GPGUserIDPacket class], // 13 + [GPGPublicSubkeyPacket class], // 14 + [NSNull null], // 15 + [NSNull null], // 16 + [GPGUserAttributePacket class], // 17 + [GPGEncryptedProtectedDataPacket class] // 18 + ] retain]; +} + +- (void)dealloc { + self.stream = nil; + self.error = nil; + self.compressedPacket = nil; + self.byteCallback = nil; + [super dealloc]; +} + + +@end diff --git a/Source/GPGPacket/GPGPacketParser_Private.h b/Source/GPGPacket/GPGPacketParser_Private.h new file mode 100644 index 0000000..01aaecb --- /dev/null +++ b/Source/GPGPacket/GPGPacketParser_Private.h @@ -0,0 +1,45 @@ +/* GPGPacketParser_Private.h + Copyright © Roman Zechmeister, 2015 + + This file is part of Libmacgpg. + + Libmacgpg is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Libmacgpg is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA + */ + +#import "GPGPacketParser.h" + + + +@interface GPGPacketParser () + +@property (nonatomic, copy) ByteCallback byteCallback; // Called every time a byte is read. + +- (NSInteger)byte; +- (NSInteger)byteOrEOF; +- (void)skip:(NSUInteger)count; +- (void)skipRemaining; + +- (NSUInteger)nextPartialLength; +- (BOOL)partial; + +- (NSString *)keyID; +- (id)multiPrecisionInteger; +- (NSDate *)date; +- (UInt16)uint16; +- (NSString *)stringWithLength:(NSUInteger)length; +- (NSArray *)signatureSubpacketsWithLength:(NSUInteger)fullLength; + +@end diff --git a/Source/GPGPacket/GPGPacket_Private.h b/Source/GPGPacket/GPGPacket_Private.h new file mode 100644 index 0000000..95c4d3c --- /dev/null +++ b/Source/GPGPacket/GPGPacket_Private.h @@ -0,0 +1,31 @@ +/* GPGPacket_Private.h + Copyright © Roman Zechmeister, 2015 + + This file is part of Libmacgpg. + + Libmacgpg is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Libmacgpg is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA + */ + +#import "GPGPacketParser_Private.h" + +@class GPGPacketParser; + +@interface GPGPacket () + +- (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)length; + + +@end diff --git a/Source/GPGPacket/GPGPublicKeyEncryptedSessionKeyPacket.h b/Source/GPGPacket/GPGPublicKeyEncryptedSessionKeyPacket.h new file mode 100644 index 0000000..1399c32 --- /dev/null +++ b/Source/GPGPacket/GPGPublicKeyEncryptedSessionKeyPacket.h @@ -0,0 +1,35 @@ +/* GPGPublicKeyEncryptedSessionKeyPacket.h + Copyright © Roman Zechmeister, 2015 + + This file is part of Libmacgpg. + + Libmacgpg is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Libmacgpg is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA + */ + +#import + +@interface GPGPublicKeyEncryptedSessionKeyPacket : GPGPacket { + NSInteger publicAlgorithm; + NSInteger version; + NSString *keyID; +} + +@property (nonatomic, readonly) NSInteger publicAlgorithm; +@property (nonatomic, readonly) NSInteger version; +@property (nonatomic, strong, readonly) NSString *keyID; + + +@end diff --git a/Source/GPGPacket/GPGPublicKeyEncryptedSessionKeyPacket.m b/Source/GPGPacket/GPGPublicKeyEncryptedSessionKeyPacket.m new file mode 100644 index 0000000..bbc3e2b --- /dev/null +++ b/Source/GPGPacket/GPGPublicKeyEncryptedSessionKeyPacket.m @@ -0,0 +1,80 @@ +/* GPGPublicKeyEncryptedSessionKeyPacket.m + Based on pgpdump (https://github.com/kazu-yamamoto/pgpdump) from Kazuhiko Yamamoto. + Copyright © Roman Zechmeister, 2015 + + This file is part of Libmacgpg. + + Libmacgpg is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Libmacgpg is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA + */ + +#import "GPGPublicKeyEncryptedSessionKeyPacket.h" +#import "GPGPacket_Private.h" + +@interface GPGPublicKeyEncryptedSessionKeyPacket () +@property (nonatomic, readwrite) NSInteger publicAlgorithm; +@property (nonatomic, readwrite) NSInteger version; +@property (nonatomic, strong, readwrite) NSString *keyID; +@end + + +@implementation GPGPublicKeyEncryptedSessionKeyPacket +@synthesize publicAlgorithm, version, keyID; + +- (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)length { + self = [super init]; + if (!self) { + return nil; + } + + self.version = parser.byte; + self.keyID = parser.keyID; + self.publicAlgorithm = parser.byte; + + switch (publicAlgorithm) { + case 1: + case 2: + case 3: + [parser multiPrecisionInteger]; // "RSA m^e mod n" + break; + case 16: + case 20: + [parser multiPrecisionInteger]; // "ElGamal g^k mod p" + [parser multiPrecisionInteger]; // "ElGamal m * y^k mod p" + break; + case 17: + [parser multiPrecisionInteger]; // "DSA ?" + [parser multiPrecisionInteger]; // "DSA ?" + break; + default: + [parser skip:length - 10]; + break; + } + + + return self; +} + +- (GPGPacketTag)tag { + return 1; +} + +- (void)dealloc { + self.keyID = nil; + [super dealloc]; +} + + +@end diff --git a/Source/GPGPacket/GPGSignaturePacket.h b/Source/GPGPacket/GPGSignaturePacket.h new file mode 100644 index 0000000..45036dc --- /dev/null +++ b/Source/GPGPacket/GPGSignaturePacket.h @@ -0,0 +1,80 @@ +/* GPGSignaturePacket.h + Copyright © Roman Zechmeister, 2015 + + This file is part of Libmacgpg. + + Libmacgpg is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Libmacgpg is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA + */ + +#import + + +// Subpacket tags. +typedef enum { + GPGSignatureCreationTimeTag = 2, + GPGSignatureExpirationTimeTag = 3, + GPGExportableCertificationTag = 4, + GPGTrustSignatureTag = 5, + GPGRegularExpressionTag = 6, + GPGRevocableTag = 7, + GPGKeyExpirationTimeTag = 9, + GPGPreferredSymmetricAlgorithmsTag = 11, + GPGRevocationKeyTag = 12, + GPGIssuerTag = 16, + GPGNotationDataTag = 20, + GPGPreferredHashAlgorithmsTag = 21, + GPGPreferredCompressionAlgorithmsTag = 22, + GPGKeyServerPreferencesTag = 23, + GPGPreferredKeyServerTag = 24, + GPGPrimaryUserIDTag = 25, + GPGPolicyURITag = 26, + GPGKeyFlagsTag = 27, + GPGSignersUserIDTag = 28, + GPGReasonForRevocationTag = 29, + GPGFeaturesTag = 30, + GPGSignatureTargetTag = 31, + GPGEmbeddedSignatureTag = 32 +} GPGSubpacketTag; + + + +@interface GPGSignaturePacket : GPGPacket { + NSInteger publicAlgorithm; + NSInteger hashAlgorithm; + NSInteger type; + NSInteger version; + UInt16 hashStart; + NSString *keyID; + NSDate *creationDate; + NSArray *hashedSubpackets; + NSArray *unhashedSubpackets; + NSArray *subpackets; +} + +@property (nonatomic, readonly) NSInteger publicAlgorithm; +@property (nonatomic, readonly) NSInteger hashAlgorithm; +@property (nonatomic, readonly) NSInteger type; +@property (nonatomic, readonly) NSInteger version; +@property (nonatomic, readonly) UInt16 hashStart; +@property (nonatomic, copy, readonly) NSString *keyID; +@property (nonatomic, copy, readonly) NSDate *creationDate; +@property (nonatomic, copy, readonly) NSArray *hashedSubpackets; +@property (nonatomic, copy, readonly) NSArray *unhashedSubpackets; +@property (nonatomic, copy, readonly) NSArray *subpackets; // Combination of unhashedSubpackets and hashedSubpackets. Order is undefined! + + + +@end diff --git a/Source/GPGPacket/GPGSignaturePacket.m b/Source/GPGPacket/GPGSignaturePacket.m new file mode 100644 index 0000000..59c6044 --- /dev/null +++ b/Source/GPGPacket/GPGSignaturePacket.m @@ -0,0 +1,178 @@ +/* GPGSignaturePacket.m + Based on pgpdump (https://github.com/kazu-yamamoto/pgpdump) from Kazuhiko Yamamoto. + Copyright © Roman Zechmeister, 2015 + + This file is part of Libmacgpg. + + Libmacgpg is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Libmacgpg is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA + */ + +#import "GPGSignaturePacket.h" +#import "GPGPacket_Private.h" + +@interface GPGSignaturePacket () +@property (nonatomic, readwrite) NSInteger publicAlgorithm; +@property (nonatomic, readwrite) NSInteger hashAlgorithm; +@property (nonatomic, readwrite) NSInteger type; +@property (nonatomic, readwrite) NSInteger version; +@property (nonatomic, readwrite) UInt16 hashStart; +@property (nonatomic, copy, readwrite) NSString *keyID; +@property (nonatomic, copy, readwrite) NSDate *creationDate; +@property (nonatomic, copy, readwrite) NSArray *hashedSubpackets; +@property (nonatomic, copy, readwrite) NSArray *unhashedSubpackets; +@property (nonatomic, copy, readwrite) NSArray *subpackets; +@end + + +@implementation GPGSignaturePacket +@synthesize publicAlgorithm, hashAlgorithm, type, version, hashStart, keyID, creationDate, + hashedSubpackets, unhashedSubpackets, subpackets; + +- (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)length { + self = [super init]; + if (!self) { + return nil; + } + + self.version = parser.byte; + + switch (version) { + case 2: + case 3: + // Old format. + + [parser byte]; // Ignore (length of type + creationDate. MUST be 5.) + self.type = parser.byte; + self.creationDate = parser.date; + + self.keyID = parser.keyID; + self.publicAlgorithm = parser.byte; + self.hashAlgorithm = parser.byte; + self.hashStart = parser.uint16; + + switch (publicAlgorithm) { + case 1: + case 2: + case 3: + [parser multiPrecisionInteger]; // "RSA m^d mod n" + break; + case 16: + case 20: + [parser multiPrecisionInteger]; // "ElGamal a = g^k mod p" + [parser multiPrecisionInteger]; // "ElGamal b = (h - a*x)/k mod p - 1" + break; + case 17: + [parser multiPrecisionInteger]; // "DSA r" + [parser multiPrecisionInteger]; // "DSA s" + break; + default: + [parser skip:length - 19]; + break; + } + + break; + case 4: { + // New format. + + self.type = parser.byte; + self.publicAlgorithm = parser.byte; + self.hashAlgorithm = parser.byte; + + NSUInteger hsplen = parser.uint16; + self.hashedSubpackets = [parser signatureSubpacketsWithLength:hsplen]; + + NSUInteger usplen = parser.uint16; + self.unhashedSubpackets = [parser signatureSubpacketsWithLength:usplen]; + + NSMutableArray *theSubpackets = [NSMutableArray arrayWithArray:unhashedSubpackets]; + [theSubpackets addObjectsFromArray:hashedSubpackets]; + self.subpackets = theSubpackets; + + + // Get some infos out of the subpackets. + for (NSDictionary *subpacket in subpackets) { + switch ((GPGSubpacketTag)[subpacket[@"tag"] integerValue]) { + case GPGSignatureCreationTimeTag: + self.creationDate = subpacket[@"date"]; + break; + case GPGIssuerTag: + self.keyID = subpacket[@"keyID"]; + break; + default: + break; + } + } + + + + self.hashStart = parser.uint16; + + switch (publicAlgorithm) { + case 1: + case 2: + case 3: + [parser multiPrecisionInteger]; // "RSA m^d mod n" + break; + case 16: + case 20: + [parser multiPrecisionInteger]; // "ElGamal a = g^k mod p" + [parser multiPrecisionInteger]; // "ElGamal b = (h - a*x)/k mod p - 1" + break; + case 17: + [parser multiPrecisionInteger]; // "DSA r" + [parser multiPrecisionInteger]; // "DSA s" + break; + default: + [parser skip:length - 10 - hsplen - usplen]; + break; + } + break; + } + default: + // Unknown signature packet. + [parser skip:length - 1]; + break; + } + + return self; +} + +- (GPGPacketTag)tag { + return 2; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"%@ v%li: %li\nIssuer: %@\nCreation Date: %@", self.className, + (long)self.version, + (long)self.type, + self.keyID, + self.creationDate]; +} + +- (void)dealloc { + self.keyID = nil; + self.creationDate = nil; + self.hashedSubpackets = nil; + self.unhashedSubpackets = nil; + [super dealloc]; +} + + + + + + +@end diff --git a/Source/GPGPacket/GPGSymmetricEncryptedSessionKeyPacket.h b/Source/GPGPacket/GPGSymmetricEncryptedSessionKeyPacket.h new file mode 100644 index 0000000..6683218 --- /dev/null +++ b/Source/GPGPacket/GPGSymmetricEncryptedSessionKeyPacket.h @@ -0,0 +1,35 @@ +/* GPGSymmetricEncryptedSessionKeyPacket.h + Copyright © Roman Zechmeister, 2015 + + This file is part of Libmacgpg. + + Libmacgpg is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Libmacgpg is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA + */ + +#import + +@interface GPGSymmetricEncryptedSessionKeyPacket : GPGPacket { + NSInteger symmetricAlgorithm; + NSInteger version; + NSString *keyID; +} + +@property (nonatomic, readonly) NSInteger symmetricAlgorithm; +@property (nonatomic, readonly) NSInteger version; +@property (nonatomic, strong, readonly) NSString *keyID; + + +@end diff --git a/Source/GPGPacket/GPGSymmetricEncryptedSessionKeyPacket.m b/Source/GPGPacket/GPGSymmetricEncryptedSessionKeyPacket.m new file mode 100644 index 0000000..882ec1a --- /dev/null +++ b/Source/GPGPacket/GPGSymmetricEncryptedSessionKeyPacket.m @@ -0,0 +1,63 @@ +/* GPGSymmetricEncryptedSessionKeyPacket.m + Copyright © Roman Zechmeister, 2015 + + This file is part of Libmacgpg. + + Libmacgpg is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Libmacgpg is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA + */ + +#import "GPGSymmetricEncryptedSessionKeyPacket.h" +#import "GPGPacket_Private.h" + +@interface GPGSymmetricEncryptedSessionKeyPacket () +@property (nonatomic, readwrite) NSInteger symmetricAlgorithm; +@property (nonatomic, readwrite) NSInteger version; +@property (nonatomic, strong, readwrite) NSString *keyID; +@end + + +@implementation GPGSymmetricEncryptedSessionKeyPacket +@synthesize symmetricAlgorithm, version, keyID; + +- (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)length { + self = [super init]; + if (!self) { + return nil; + } + + self.version = parser.byte; + self.symmetricAlgorithm = parser.byte; + + + // TODO: parse string-to-key. + + + [parser skipRemaining]; + + return self; +} + +- (GPGPacketTag)tag { + return 3; +} + +- (void)dealloc { + self.keyID = nil; + [super dealloc]; +} + + +@end diff --git a/Source/GPGPacket/GPGUserAttributePacket.h b/Source/GPGPacket/GPGUserAttributePacket.h new file mode 100644 index 0000000..a035337 --- /dev/null +++ b/Source/GPGPacket/GPGUserAttributePacket.h @@ -0,0 +1,30 @@ +/* GPGUserAttributePacket.h + Copyright © Roman Zechmeister, 2015 + + This file is part of Libmacgpg. + + Libmacgpg is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Libmacgpg is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA + */ + +#import + +@interface GPGUserAttributePacket : GPGPacket { + NSArray *subpackets; +} + +@property (nonatomic, copy, readonly) NSArray *subpackets; + +@end diff --git a/Source/GPGPacket/GPGUserAttributePacket.m b/Source/GPGPacket/GPGUserAttributePacket.m new file mode 100644 index 0000000..38acd88 --- /dev/null +++ b/Source/GPGPacket/GPGUserAttributePacket.m @@ -0,0 +1,124 @@ +/* GPGUserAttributePacket.m + Based on pgpdump (https://github.com/kazu-yamamoto/pgpdump) from Kazuhiko Yamamoto. + Copyright © Roman Zechmeister, 2015 + + This file is part of Libmacgpg. + + Libmacgpg is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Libmacgpg is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA + */ + +#import "GPGUserAttributePacket.h" +#import "GPGPacket_Private.h" + +@interface GPGUserAttributePacket () +@property (nonatomic, copy, readwrite) NSArray *subpackets; +@end + + +@implementation GPGUserAttributePacket +@synthesize subpackets; + + +- (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)length { + self = [super init]; + if (!self) { + return nil; + } + + NSMutableArray *packets = [NSMutableArray array]; + NSUInteger fullLength = length; + + while (fullLength > 0) { + + NSUInteger subLength = parser.byte; + + if (subLength < 192) { + fullLength--; + } else if (subLength < 255) { + subLength = ((subLength - 192) << 8) + parser.byte + 192; + fullLength -= 2; + } else if (subLength == 255) { + subLength = parser.byte << 24; + subLength |= parser.byte << 16; + subLength |= parser.byte << 8; + subLength |= parser.byte; + fullLength -= 5; + } + fullLength -= subLength; + NSInteger subtype = parser.byte; /* len includes this field byte */ + subLength--; + + + + switch (subtype) { + case 1: { + + NSUInteger headerLength = parser.byte; + headerLength |= parser.byte << 8; // little-endian, because of a "historical accident"! + + NSInteger headerVersion = parser.byte; + subLength -= 3; + + if (headerLength == 16 && headerVersion == 1) { + NSInteger format = parser.byte; + subLength--; + + if (format == 1) { // JPEG is the only currently defined format. + [parser skip:12]; + subLength -= 12; + + NSMutableData *tempData = [NSMutableData dataWithLength:subLength]; + UInt8 *bytes = tempData.mutableBytes; + for (NSUInteger i = 0; i < subLength; i++) { + bytes[i] = (UInt8)parser.byte; + } + + subLength = 0; + + NSImage *image = [[NSImage alloc] initWithData:tempData]; + + if (image) { + NSDictionary *subpacket = @{@"image": image}; + [packets addObject:subpacket]; + } + } + } + break; + } + default: + break; + } + + [parser skip:subLength]; + } + + self.subpackets = packets; + + return self; +} + +- (GPGPacketTag)tag { + return 17; +} + +- (void)dealloc { + self.subpackets = nil; + [super dealloc]; +} + + +@end + diff --git a/Source/GPGPacket/GPGUserIDPacket.h b/Source/GPGPacket/GPGUserIDPacket.h new file mode 100644 index 0000000..ad48e62 --- /dev/null +++ b/Source/GPGPacket/GPGUserIDPacket.h @@ -0,0 +1,30 @@ +/* GPGUserIDPacket.h + Copyright © Roman Zechmeister, 2015 + + This file is part of Libmacgpg. + + Libmacgpg is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Libmacgpg is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA + */ + +#import + +@interface GPGUserIDPacket : GPGPacket { + NSString *userID; +} + +@property (nonatomic, strong, readonly) NSString *userID; + +@end diff --git a/Source/GPGPacket/GPGUserIDPacket.m b/Source/GPGPacket/GPGUserIDPacket.m new file mode 100644 index 0000000..fbedaab --- /dev/null +++ b/Source/GPGPacket/GPGUserIDPacket.m @@ -0,0 +1,60 @@ +/* GPGUserIDPacket.m + Copyright © Roman Zechmeister, 2015 + + This file is part of Libmacgpg. + + Libmacgpg is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Libmacgpg is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA + */ + +#import "GPGUserIDPacket.h" +#import "GPGPacket_Private.h" + +@interface GPGUserIDPacket () +@property (nonatomic, strong, readwrite) NSString *userID; +@end + + +@implementation GPGUserIDPacket +@synthesize userID; + + +- (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)length { + self = [super init]; + if (!self) { + return nil; + } + + self.userID = [parser stringWithLength:length]; + + return self; +} + +- (GPGPacketTag)tag { + return 13; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"%@: \"%@\"", self.className, self.userID]; +} + +- (void)dealloc { + self.userID = nil; + [super dealloc]; +} + + +@end + diff --git a/Source/Libmacgpg.h b/Source/Libmacgpg.h index 9edace6..4c015dc 100644 --- a/Source/Libmacgpg.h +++ b/Source/Libmacgpg.h @@ -25,7 +25,6 @@ #import #import #import -#import #import #import #import @@ -36,3 +35,15 @@ #import #import #import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import diff --git a/Version.config b/Version.config index c6b16ea..00b9d0f 100644 --- a/Version.config +++ b/Version.config @@ -1,4 +1,4 @@ MAJOR=0 -MINOR=5 +MINOR=6 VERSION="${MAJOR}.${MINOR}${REVISION:+.$REVISION}${PRERELEASE}" From ab1f195ee74b4f5ac028c2c9624f1b4cf706d616 Mon Sep 17 00:00:00 2001 From: Mento Date: Mon, 13 Jul 2015 19:01:29 +0200 Subject: [PATCH 30/56] Wrong name of delegate method. --- Source/GPGController.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/GPGController.m b/Source/GPGController.m index 57b1698..b79da29 100644 --- a/Source/GPGController.m +++ b/Source/GPGController.m @@ -2500,7 +2500,7 @@ - (id)gpgTask:(GPGTask *)task statusCode:(NSInteger)status prompt:(NSString *)pr return nil; } -- (void)gpgTaskDidStart:(GPGTask *)task { +- (void)gpgTaskWillStart:(GPGTask *)task { if ([signatures count] > 0) { self.lastSignature = nil; [signatures release]; From 0fb5d1f003bfc430ed2175133e83cecac56f4b46 Mon Sep 17 00:00:00 2001 From: Mento Date: Mon, 13 Jul 2015 19:02:17 +0200 Subject: [PATCH 31/56] GPGKeyManager homedir added. --- Source/GPGKeyManager.h | 4 ++++ Source/GPGKeyManager.m | 11 ++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Source/GPGKeyManager.h b/Source/GPGKeyManager.h index eb54c5b..4b7d13f 100644 --- a/Source/GPGKeyManager.h +++ b/Source/GPGKeyManager.h @@ -1,6 +1,8 @@ @interface GPGKeyManager : NSObject { + NSString *_homedir; + NSSet *_allKeys; NSSet *_allKeysAndSubkeys; @@ -34,6 +36,8 @@ dispatch_semaphore_t _allKeysAndSubkeysOnce; } +@property (nonatomic, copy) NSString *homedir; + @property (nonatomic) BOOL allowWeakDigestAlgos; @property (nonatomic, readonly) NSSet *allKeys; diff --git a/Source/GPGKeyManager.m b/Source/GPGKeyManager.m index 4237817..0b3aba4 100644 --- a/Source/GPGKeyManager.m +++ b/Source/GPGKeyManager.m @@ -17,7 +17,8 @@ @implementation GPGKeyManager @synthesize allKeys=_allKeys, keysByKeyID=_keysByKeyID, secretKeys=_secretKeys, completionQueue=_completionQueue, - allowWeakDigestAlgos=_allowWeakDigestAlgos; + allowWeakDigestAlgos=_allowWeakDigestAlgos, + homedir=_homedir; - (void)loadAllKeys { [self loadKeys:nil fetchSignatures:NO fetchUserAttributes:NO]; @@ -43,6 +44,10 @@ - (void)_loadKeys:(NSSet *)keys fetchSignatures:(BOOL)fetchSignatures fetchUserA @try { // Get all fingerprints of the secret keys. GPGTask *gpgTask = [GPGTask gpgTask]; + if (_homedir) { + [gpgTask addArgument:@"--homedir"]; + [gpgTask addArgument:_homedir]; + } gpgTask.batchMode = YES; if (self.allowWeakDigestAlgos) { [gpgTask addArgument:@"--allow-weak-digest-algos"]; @@ -63,6 +68,10 @@ - (void)_loadKeys:(NSSet *)keys fetchSignatures:(BOOL)fetchSignatures fetchUserA // Get the infos from gpg. GPGTask *gpgTask = [GPGTask gpgTask]; + if (_homedir) { + [gpgTask addArgument:@"--homedir"]; + [gpgTask addArgument:_homedir]; + } if (fetchSignatures) { [gpgTask addArgument:@"--list-sigs"]; [gpgTask addArgument:@"--list-options"]; From ba0bed8c39f31e83d545eb9f4d7cb8a3da958acd Mon Sep 17 00:00:00 2001 From: Mento Date: Mon, 13 Jul 2015 19:02:41 +0200 Subject: [PATCH 32/56] UnitTests fixed. --- Libmacgpg.xcodeproj/project.pbxproj | 472 ++++++++----------------- NewUnitTests/GPGSocketCloseTest.m | 26 +- Source/GPGTaskHelper.m | 4 + UnitTest/GPGArraySettingTest.m | 25 +- UnitTest/GPGConfReaderTest.m | 69 ++-- UnitTest/GPGDictSettingTest.m | 27 +- UnitTest/GPGLinesSettingTest.m | 27 +- UnitTest/GPGOptionsTest.m | 10 +- UnitTest/GPGResourceUtil.h | 15 - UnitTest/GPGResourceUtil.m | 22 -- UnitTest/GPGSignatureTest.m | 77 ---- UnitTest/GPGStdSettingTest.m | 43 +-- UnitTest/GPGTestVerify.m | 135 ++++--- UnitTest/NSRunLoop+TimeOutAndFlag.h | 11 - UnitTest/NSRunLoop+TimeOutAndFlag.m | 19 - UnitTest/Resources/OpenPGP.asc | 152 +++++--- UnitTest/Test1.h | 11 - UnitTest/Test1.m | 206 ----------- UnitTests/GPGUnitTest.h | 19 + UnitTests/GPGUnitTest.m | 53 +++ {NewUnitTests => UnitTests}/Info.plist | 0 21 files changed, 507 insertions(+), 916 deletions(-) delete mode 100644 UnitTest/GPGResourceUtil.h delete mode 100644 UnitTest/GPGResourceUtil.m delete mode 100644 UnitTest/GPGSignatureTest.m delete mode 100644 UnitTest/NSRunLoop+TimeOutAndFlag.h delete mode 100644 UnitTest/NSRunLoop+TimeOutAndFlag.m delete mode 100644 UnitTest/Test1.h delete mode 100644 UnitTest/Test1.m create mode 100644 UnitTests/GPGUnitTest.h create mode 100644 UnitTests/GPGUnitTest.m rename {NewUnitTests => UnitTests}/Info.plist (100%) diff --git a/Libmacgpg.xcodeproj/project.pbxproj b/Libmacgpg.xcodeproj/project.pbxproj index 0ef7e88..6831f5c 100644 --- a/Libmacgpg.xcodeproj/project.pbxproj +++ b/Libmacgpg.xcodeproj/project.pbxproj @@ -40,8 +40,6 @@ 1BD78BBA1726B6060005F251 /* Libmacgpg.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8DC2EF5B0486A6940098B216 /* Libmacgpg.framework */; }; 1BD78BBC1726B6230005F251 /* Libmacgpg.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8DC2EF5B0486A6940098B216 /* Libmacgpg.framework */; }; 1BDA56BC1618A94300185C72 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4591C4D314F86D38007F6D47 /* AppKit.framework */; }; - 1BE88B3E1B47D7F900A812B6 /* GPGSocketCloseTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1BE88B3D1B47D7F900A812B6 /* GPGSocketCloseTest.m */; }; - 1BE88B3F1B47D7F900A812B6 /* Libmacgpg.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8DC2EF5B0486A6940098B216 /* Libmacgpg.framework */; }; 3002C04716EE38C900D57C1E /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 3002C04316EE388B00D57C1E /* libcrypto.dylib */; }; 300F3DB51B4AC2CE00E36AAA /* libbz2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 300F3DB31B4AC2CE00E36AAA /* libbz2.dylib */; }; 300F3DB61B4AC2CE00E36AAA /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 300F3DB41B4AC2CE00E36AAA /* libz.dylib */; }; @@ -97,10 +95,22 @@ 30BB7C811B4D4A59006A1E47 /* GPGUserIDPacket.m in Sources */ = {isa = PBXBuildFile; fileRef = 30BB7C7F1B4D4A59006A1E47 /* GPGUserIDPacket.m */; }; 30BB7C841B4D4BF8006A1E47 /* GPGUserAttributePacket.h in Headers */ = {isa = PBXBuildFile; fileRef = 30BB7C821B4D4BF8006A1E47 /* GPGUserAttributePacket.h */; settings = {ATTRIBUTES = (Public, ); }; }; 30BB7C851B4D4BF8006A1E47 /* GPGUserAttributePacket.m in Sources */ = {isa = PBXBuildFile; fileRef = 30BB7C831B4D4BF8006A1E47 /* GPGUserAttributePacket.m */; }; + 30BE73C41B54015C001A2137 /* Libmacgpg.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8DC2EF5B0486A6940098B216 /* Libmacgpg.framework */; }; + 30BE73DC1B5407E3001A2137 /* GPGTestVerify.m in Sources */ = {isa = PBXBuildFile; fileRef = 45C0BC02151B65C700AA8BF6 /* GPGTestVerify.m */; }; + 30BE73DD1B541039001A2137 /* OpenPGP.asc in Resources */ = {isa = PBXBuildFile; fileRef = 45B9A7F5151C9A6D00DAD67A /* OpenPGP.asc */; }; + 30BE73DE1B541039001A2137 /* SignedInputStringCR.txt in Resources */ = {isa = PBXBuildFile; fileRef = 45891A40151BA1EC002D7410 /* SignedInputStringCR.txt */; }; + 30BE73DF1B541039001A2137 /* SignedInputStringCRLF.txt in Resources */ = {isa = PBXBuildFile; fileRef = 45891A3C151BA1C9002D7410 /* SignedInputStringCRLF.txt */; }; + 30BE73E01B541039001A2137 /* SignedInputStringLF.txt in Resources */ = {isa = PBXBuildFile; fileRef = 45891A3D151BA1C9002D7410 /* SignedInputStringLF.txt */; }; + 30BE73E11B5411C2001A2137 /* GPGConfReaderTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4591C4C914F85AA3007F6D47 /* GPGConfReaderTest.m */; }; + 30BE73E21B5411C2001A2137 /* GPGStdSettingTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4547646514FBC8A900A37306 /* GPGStdSettingTest.m */; }; + 30BE73E31B5411C2001A2137 /* GPGLinesSettingTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 45156A2314FB310300129FE7 /* GPGLinesSettingTest.m */; }; + 30BE73E41B5411C2001A2137 /* GPGArraySettingTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 45156A2C14FB506E00129FE7 /* GPGArraySettingTest.m */; }; + 30BE73E51B5411C2001A2137 /* GPGDictSettingTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 45156A2614FB35DC00129FE7 /* GPGDictSettingTest.m */; }; + 30BE73E61B5411C2001A2137 /* GPGOptionsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 455B17B915143D9A00FAD47D /* GPGOptionsTest.m */; }; + 30BE73EA1B541F5B001A2137 /* GPGUnitTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 30BE73E91B541F5B001A2137 /* GPGUnitTest.m */; }; + 30BE73EC1B54238F001A2137 /* GPGSocketCloseTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1BE88B3D1B47D7F900A812B6 /* GPGSocketCloseTest.m */; }; 30C045931B4FDB9800080903 /* GPGCompressedDataPacket_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 30C045921B4FDB9800080903 /* GPGCompressedDataPacket_Private.h */; }; 30C60EEF12FF3321006BB8DA /* Libmacgpg.h in Headers */ = {isa = PBXBuildFile; fileRef = 30C60EEE12FF3321006BB8DA /* Libmacgpg.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 30C8B39C1395052D00F49AA1 /* Test1.m in Sources */ = {isa = PBXBuildFile; fileRef = 30C8B39B1395052D00F49AA1 /* Test1.m */; }; - 30C8B3B11395072C00F49AA1 /* Libmacgpg.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8DC2EF5B0486A6940098B216 /* Libmacgpg.framework */; }; 30D5E2A41483A0F700F31454 /* GPGConf.h in Headers */ = {isa = PBXBuildFile; fileRef = 30D5E2A21483A0F700F31454 /* GPGConf.h */; }; 30D5E2A51483A0F700F31454 /* GPGConf.m in Sources */ = {isa = PBXBuildFile; fileRef = 30D5E2A31483A0F700F31454 /* GPGConf.m */; }; 30D68BC51B4FF5D500F7865C /* COPYING.pgpdump in Resources */ = {isa = PBXBuildFile; fileRef = 30D68BC41B4FF5D500F7865C /* COPYING.pgpdump */; }; @@ -128,11 +138,8 @@ 45156A1D14FB1B1200129FE7 /* GPGLinesSetting.m in Sources */ = {isa = PBXBuildFile; fileRef = 45156A1B14FB1B1200129FE7 /* GPGLinesSetting.m */; }; 45156A2014FB1D7D00129FE7 /* GPGDictSetting.h in Headers */ = {isa = PBXBuildFile; fileRef = 45156A1E14FB1D7D00129FE7 /* GPGDictSetting.h */; }; 45156A2114FB1D7D00129FE7 /* GPGDictSetting.m in Sources */ = {isa = PBXBuildFile; fileRef = 45156A1F14FB1D7D00129FE7 /* GPGDictSetting.m */; }; - 45156A2414FB310300129FE7 /* GPGLinesSettingTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 45156A2314FB310300129FE7 /* GPGLinesSettingTest.m */; }; - 45156A2714FB35DC00129FE7 /* GPGDictSettingTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 45156A2614FB35DC00129FE7 /* GPGDictSettingTest.m */; }; 45156A2A14FB3EF700129FE7 /* GPGArraySetting.h in Headers */ = {isa = PBXBuildFile; fileRef = 45156A2814FB3EF700129FE7 /* GPGArraySetting.h */; }; 45156A2B14FB3EF700129FE7 /* GPGArraySetting.m in Sources */ = {isa = PBXBuildFile; fileRef = 45156A2914FB3EF700129FE7 /* GPGArraySetting.m */; }; - 45156A2D14FB506E00129FE7 /* GPGArraySettingTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 45156A2C14FB506E00129FE7 /* GPGArraySettingTest.m */; }; 451932F514F8061100D1F727 /* GPGStdSetting.h in Headers */ = {isa = PBXBuildFile; fileRef = 451932F314F8061100D1F727 /* GPGStdSetting.h */; }; 451932F614F8061100D1F727 /* GPGStdSetting.m in Sources */ = {isa = PBXBuildFile; fileRef = 451932F414F8061100D1F727 /* GPGStdSetting.m */; }; 451D8829156A7AD900A0B890 /* GPGStream.h in Headers */ = {isa = PBXBuildFile; fileRef = 451D8827156A7AD900A0B890 /* GPGStream.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -141,19 +148,8 @@ 451D882E156A7CA300A0B890 /* GPGMemoryStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 451D882C156A7CA300A0B890 /* GPGMemoryStream.m */; }; 451D8831156A7E4900A0B890 /* GPGFileStream.h in Headers */ = {isa = PBXBuildFile; fileRef = 451D882F156A7E4900A0B890 /* GPGFileStream.h */; settings = {ATTRIBUTES = (Public, ); }; }; 451D8832156A7E4900A0B890 /* GPGFileStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 451D8830156A7E4900A0B890 /* GPGFileStream.m */; }; - 4547646614FBC8A900A37306 /* GPGStdSettingTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4547646514FBC8A900A37306 /* GPGStdSettingTest.m */; }; - 455B17BA15143D9A00FAD47D /* GPGOptionsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 455B17B915143D9A00FAD47D /* GPGOptionsTest.m */; }; 4570876614FAA7C90030AAE6 /* GPGConfReader.h in Headers */ = {isa = PBXBuildFile; fileRef = 4570876414FAA7C90030AAE6 /* GPGConfReader.h */; }; 4570876714FAA7C90030AAE6 /* GPGConfReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 4570876514FAA7C90030AAE6 /* GPGConfReader.m */; }; - 45891A3E151BA1C9002D7410 /* SignedInputStringCRLF.txt in Resources */ = {isa = PBXBuildFile; fileRef = 45891A3C151BA1C9002D7410 /* SignedInputStringCRLF.txt */; }; - 45891A3F151BA1C9002D7410 /* SignedInputStringLF.txt in Resources */ = {isa = PBXBuildFile; fileRef = 45891A3D151BA1C9002D7410 /* SignedInputStringLF.txt */; }; - 45891A41151BA1EC002D7410 /* SignedInputStringCR.txt in Resources */ = {isa = PBXBuildFile; fileRef = 45891A40151BA1EC002D7410 /* SignedInputStringCR.txt */; }; - 4591C4CA14F85AA3007F6D47 /* GPGConfReaderTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4591C4C914F85AA3007F6D47 /* GPGConfReaderTest.m */; }; - 45B8C6AC157140A600FD49CD /* NSRunLoop+TimeOutAndFlag.m in Sources */ = {isa = PBXBuildFile; fileRef = 45B8C6AB157140A600FD49CD /* NSRunLoop+TimeOutAndFlag.m */; }; - 45B9A7F6151C9A6D00DAD67A /* OpenPGP.asc in Resources */ = {isa = PBXBuildFile; fileRef = 45B9A7F5151C9A6D00DAD67A /* OpenPGP.asc */; }; - 45C0BC03151B65C700AA8BF6 /* GPGTestVerify.m in Sources */ = {isa = PBXBuildFile; fileRef = 45C0BC02151B65C700AA8BF6 /* GPGTestVerify.m */; }; - 45C0BC18151B66F500AA8BF6 /* GPGResourceUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 45C0BC17151B66F500AA8BF6 /* GPGResourceUtil.m */; }; - 45DD3D4C15642A0D00C9A4C1 /* GPGSignatureTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 45DD3D4B15642A0D00C9A4C1 /* GPGSignatureTest.m */; }; 8DC2EF570486A6940098B216 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7B1FEA5585E11CA2CBB /* Cocoa.framework */; }; /* End PBXBuildFile section */ @@ -165,13 +161,6 @@ remoteGlobalIDString = 8DC2EF4F0486A6940098B216; remoteInfo = Libmacgpg; }; - 1BE88B401B47D7F900A812B6 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 8DC2EF4F0486A6940098B216; - remoteInfo = Libmacgpg; - }; 30444C471A65E3E30052CB94 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; @@ -179,7 +168,7 @@ remoteGlobalIDString = 30444C171A65E0590052CB94; remoteInfo = installerHelper; }; - 30C8B3931395046400F49AA1 /* PBXContainerItemProxy */ = { + 30BE73C51B54015C001A2137 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; proxyType = 1; @@ -235,9 +224,7 @@ 1BD78BAD1726B2830005F251 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 1BD78BAE1726B2830005F251 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 1BD78BB11726B2830005F251 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainMenu.xib; sourceTree = ""; }; - 1BE88B391B47D7F900A812B6 /* NewUnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NewUnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 1BE88B3C1B47D7F900A812B6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 1BE88B3D1B47D7F900A812B6 /* GPGSocketCloseTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GPGSocketCloseTest.m; sourceTree = ""; }; + 1BE88B3D1B47D7F900A812B6 /* GPGSocketCloseTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = GPGSocketCloseTest.m; path = ../NewUnitTests/GPGSocketCloseTest.m; sourceTree = ""; }; 3002C04316EE388B00D57C1E /* libcrypto.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libcrypto.dylib; path = usr/lib/libcrypto.dylib; sourceTree = SDKROOT; }; 3002C04516EE389100D57C1E /* libxar.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libxar.dylib; path = usr/lib/libxar.dylib; sourceTree = SDKROOT; }; 300F3DB31B4AC2CE00E36AAA /* libbz2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libbz2.dylib; path = usr/lib/libbz2.dylib; sourceTree = SDKROOT; }; @@ -298,12 +285,13 @@ 30BB7C7F1B4D4A59006A1E47 /* GPGUserIDPacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGUserIDPacket.m; path = GPGPacket/GPGUserIDPacket.m; sourceTree = ""; }; 30BB7C821B4D4BF8006A1E47 /* GPGUserAttributePacket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPGUserAttributePacket.h; path = GPGPacket/GPGUserAttributePacket.h; sourceTree = ""; }; 30BB7C831B4D4BF8006A1E47 /* GPGUserAttributePacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGUserAttributePacket.m; path = GPGPacket/GPGUserAttributePacket.m; sourceTree = ""; }; + 30BE73BE1B54015C001A2137 /* UnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 30BE73C11B54015C001A2137 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 30BE73E81B541F5B001A2137 /* GPGUnitTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGUnitTest.h; sourceTree = ""; }; + 30BE73E91B541F5B001A2137 /* GPGUnitTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGUnitTest.m; sourceTree = ""; }; 30C045921B4FDB9800080903 /* GPGCompressedDataPacket_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPGCompressedDataPacket_Private.h; path = GPGPacket/GPGCompressedDataPacket_Private.h; sourceTree = ""; }; 30C60EEE12FF3321006BB8DA /* Libmacgpg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Libmacgpg.h; sourceTree = ""; }; - 30C8B38E139503A800F49AA1 /* UnitTest.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UnitTest.octest; sourceTree = BUILT_PRODUCTS_DIR; }; - 30C8B38F139503A800F49AA1 /* UnitTest-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "UnitTest-Info.plist"; sourceTree = ""; }; - 30C8B39A1395052D00F49AA1 /* Test1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Test1.h; sourceTree = ""; }; - 30C8B39B1395052D00F49AA1 /* Test1.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Test1.m; sourceTree = ""; }; + 30C8B38F139503A800F49AA1 /* UnitTest-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "UnitTest-Info.plist"; path = "../UnitTest-Info.plist"; sourceTree = ""; }; 30D5E2A21483A0F700F31454 /* GPGConf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = GPGConf.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 30D5E2A31483A0F700F31454 /* GPGConf.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGConf.m; sourceTree = ""; }; 30D68BC41B4FF5D500F7865C /* COPYING.pgpdump */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = COPYING.pgpdump; path = Source/GPGPacket/COPYING.pgpdump; sourceTree = SOURCE_ROOT; }; @@ -335,11 +323,11 @@ 45156A1B14FB1B1200129FE7 /* GPGLinesSetting.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGLinesSetting.m; sourceTree = ""; }; 45156A1E14FB1D7D00129FE7 /* GPGDictSetting.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGDictSetting.h; sourceTree = ""; }; 45156A1F14FB1D7D00129FE7 /* GPGDictSetting.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGDictSetting.m; sourceTree = ""; }; - 45156A2314FB310300129FE7 /* GPGLinesSettingTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGLinesSettingTest.m; sourceTree = ""; }; - 45156A2614FB35DC00129FE7 /* GPGDictSettingTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGDictSettingTest.m; sourceTree = ""; }; + 45156A2314FB310300129FE7 /* GPGLinesSettingTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGLinesSettingTest.m; path = ../UnitTest/GPGLinesSettingTest.m; sourceTree = ""; }; + 45156A2614FB35DC00129FE7 /* GPGDictSettingTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGDictSettingTest.m; path = ../UnitTest/GPGDictSettingTest.m; sourceTree = ""; }; 45156A2814FB3EF700129FE7 /* GPGArraySetting.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGArraySetting.h; sourceTree = ""; }; 45156A2914FB3EF700129FE7 /* GPGArraySetting.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGArraySetting.m; sourceTree = ""; }; - 45156A2C14FB506E00129FE7 /* GPGArraySettingTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGArraySettingTest.m; sourceTree = ""; }; + 45156A2C14FB506E00129FE7 /* GPGArraySettingTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGArraySettingTest.m; path = ../UnitTest/GPGArraySettingTest.m; sourceTree = ""; }; 451932F314F8061100D1F727 /* GPGStdSetting.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = GPGStdSetting.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 451932F414F8061100D1F727 /* GPGStdSetting.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = GPGStdSetting.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 451D8827156A7AD900A0B890 /* GPGStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGStream.h; sourceTree = ""; }; @@ -348,24 +336,19 @@ 451D882C156A7CA300A0B890 /* GPGMemoryStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGMemoryStream.m; sourceTree = ""; }; 451D882F156A7E4900A0B890 /* GPGFileStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGFileStream.h; sourceTree = ""; }; 451D8830156A7E4900A0B890 /* GPGFileStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGFileStream.m; sourceTree = ""; }; - 4547646514FBC8A900A37306 /* GPGStdSettingTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGStdSettingTest.m; sourceTree = ""; }; - 455B17B915143D9A00FAD47D /* GPGOptionsTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGOptionsTest.m; sourceTree = ""; }; + 4547646514FBC8A900A37306 /* GPGStdSettingTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGStdSettingTest.m; path = ../UnitTest/GPGStdSettingTest.m; sourceTree = ""; }; + 455B17B915143D9A00FAD47D /* GPGOptionsTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGOptionsTest.m; path = ../UnitTest/GPGOptionsTest.m; sourceTree = ""; }; 4570876414FAA7C90030AAE6 /* GPGConfReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = GPGConfReader.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 4570876514FAA7C90030AAE6 /* GPGConfReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = GPGConfReader.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 45891A3C151BA1C9002D7410 /* SignedInputStringCRLF.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = SignedInputStringCRLF.txt; sourceTree = ""; }; 45891A3D151BA1C9002D7410 /* SignedInputStringLF.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = SignedInputStringLF.txt; sourceTree = ""; }; 45891A40151BA1EC002D7410 /* SignedInputStringCR.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = SignedInputStringCR.txt; sourceTree = ""; }; - 4591C4C914F85AA3007F6D47 /* GPGConfReaderTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = GPGConfReaderTest.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; + 4591C4C914F85AA3007F6D47 /* GPGConfReaderTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; name = GPGConfReaderTest.m; path = ../UnitTest/GPGConfReaderTest.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 4591C4D314F86D38007F6D47 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; 4591C4D414F86D38007F6D47 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; 4591C4D514F86D38007F6D47 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; - 45B8C6AA157140A600FD49CD /* NSRunLoop+TimeOutAndFlag.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSRunLoop+TimeOutAndFlag.h"; sourceTree = ""; }; - 45B8C6AB157140A600FD49CD /* NSRunLoop+TimeOutAndFlag.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSRunLoop+TimeOutAndFlag.m"; sourceTree = ""; }; 45B9A7F5151C9A6D00DAD67A /* OpenPGP.asc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = OpenPGP.asc; sourceTree = ""; }; - 45C0BC02151B65C700AA8BF6 /* GPGTestVerify.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGTestVerify.m; sourceTree = ""; }; - 45C0BC16151B66F500AA8BF6 /* GPGResourceUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGResourceUtil.h; sourceTree = ""; }; - 45C0BC17151B66F500AA8BF6 /* GPGResourceUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGResourceUtil.m; sourceTree = ""; }; - 45DD3D4B15642A0D00C9A4C1 /* GPGSignatureTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGSignatureTest.m; sourceTree = ""; }; + 45C0BC02151B65C700AA8BF6 /* GPGTestVerify.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGTestVerify.m; path = ../UnitTest/GPGTestVerify.m; sourceTree = ""; }; 8DC2EF5A0486A6940098B216 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 8DC2EF5B0486A6940098B216 /* Libmacgpg.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Libmacgpg.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -392,14 +375,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 1BE88B361B47D7F900A812B6 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 1BE88B3F1B47D7F900A812B6 /* Libmacgpg.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 30444C151A65E0590052CB94 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -412,11 +387,11 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 30C8B38B139503A800F49AA1 /* Frameworks */ = { + 30BE73BB1B54015C001A2137 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 30C8B3B11395072C00F49AA1 /* Libmacgpg.framework in Frameworks */, + 30BE73C41B54015C001A2137 /* Libmacgpg.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -444,7 +419,7 @@ 1B46CFCC161555DF00CF9C5F /* org.gpgtools.Libmacgpg.xpc */, 1BD78B9F1726B2820005F251 /* LeakFinder.app */, 30444C181A65E0590052CB94 /* GPGTools.app */, - 1BE88B391B47D7F900A812B6 /* NewUnitTests.xctest */, + 30BE73BE1B54015C001A2137 /* UnitTests.xctest */, ); name = Products; sourceTree = ""; @@ -461,10 +436,9 @@ 30DF7CBA16D39EAA00C8225C /* installerHelper */, 1BD78BA11726B2830005F251 /* LeakFinder */, 30444C381A65E0590052CB94 /* installerHelperTests */, - 1BE88B3A1B47D7F900A812B6 /* NewUnitTests */, + 30BE73BF1B54015C001A2137 /* UnitTests */, 0867D69AFE84028FC02AAC07 /* Frameworks */, 034768DFFF38A50411DB9C8B /* Products */, - 30C8B399139504DC00F49AA1 /* UnitTest */, ); name = Libmacgpg; sourceTree = ""; @@ -506,6 +480,7 @@ 307FAABB13F26BB4003FA99B /* GPGOptions */, 301D291A1B4BE47100599BE8 /* GPGPacket */, 306C73821B45B0F200A34730 /* GPGStream */, + 30BE73D51B5405B7001A2137 /* GPGTask */, 30C60EEE12FF3321006BB8DA /* Libmacgpg.h */, 30FF411D12FAC6CD00F39832 /* GPGController.h */, 30FF411E12FAC6CD00F39832 /* GPGController.m */, @@ -517,22 +492,12 @@ 30FF412212FAC6CD00F39832 /* GPGGlobals.m */, 301A44CB1B436405002A38E4 /* GPGUnArmor.h */, 301A44CC1B436405002A38E4 /* GPGUnArmor.m */, - 30FF413112FAC6CD00F39832 /* GPGTask.h */, - 30FF413212FAC6CD00F39832 /* GPGTask.m */, - 1B9DB26815784DB700488353 /* GPGTaskHelper.h */, - 1B9DB26915784DB700488353 /* GPGTaskHelper.m */, - 30FF413312FAC6CD00F39832 /* GPGTaskOrder.h */, - 30FF413412FAC6CD00F39832 /* GPGTaskOrder.m */, 309A18CE13E3812E0069DC0F /* GPGTransformer.h */, 309A18CF13E3812E0069DC0F /* GPGTransformer.m */, - 1BC7A4FE13D300A600AE57BA /* LPXTTask.h */, - 1BC7A4FF13D300A600AE57BA /* LPXTTask.m */, 3048830D1462B22000F2E5F4 /* GPGWatcher.h */, 3048830E1462B22000F2E5F4 /* GPGWatcher.m */, 304883091462B11700F2E5F4 /* DirectoryWatcher.h */, 3048830A1462B11700F2E5F4 /* DirectoryWatcher.m */, - 1B9FF20E17257A69004FB017 /* GPGTaskHelperXPC.h */, - 1B9FF20F17257A69004FB017 /* GPGTaskHelperXPC.m */, 301D5D9D178C9871003026E7 /* GPGKeyserver.h */, 301D5D9E178C9871003026E7 /* GPGKeyserver.m */, ); @@ -605,23 +570,6 @@ name = "Supporting Files"; sourceTree = ""; }; - 1BE88B3A1B47D7F900A812B6 /* NewUnitTests */ = { - isa = PBXGroup; - children = ( - 1BE88B3D1B47D7F900A812B6 /* GPGSocketCloseTest.m */, - 1BE88B3B1B47D7F900A812B6 /* Supporting Files */, - ); - path = NewUnitTests; - sourceTree = ""; - }; - 1BE88B3B1B47D7F900A812B6 /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 1BE88B3C1B47D7F900A812B6 /* Info.plist */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; 301D291A1B4BE47100599BE8 /* GPGPacket */ = { isa = PBXGroup; children = ( @@ -732,18 +680,11 @@ name = GPGOptions; sourceTree = ""; }; - 30C8B399139504DC00F49AA1 /* UnitTest */ = { + 30BE73BF1B54015C001A2137 /* UnitTests */ = { isa = PBXGroup; children = ( - 45C0BC13151B664D00AA8BF6 /* Resources */, - 45B8C6AA157140A600FD49CD /* NSRunLoop+TimeOutAndFlag.h */, - 45B8C6AB157140A600FD49CD /* NSRunLoop+TimeOutAndFlag.m */, - 45C0BC16151B66F500AA8BF6 /* GPGResourceUtil.h */, - 45C0BC17151B66F500AA8BF6 /* GPGResourceUtil.m */, - 30C8B39A1395052D00F49AA1 /* Test1.h */, - 30C8B39B1395052D00F49AA1 /* Test1.m */, - 30C8B38F139503A800F49AA1 /* UnitTest-Info.plist */, - 30C8B38E139503A800F49AA1 /* UnitTest.octest */, + 30BE73E81B541F5B001A2137 /* GPGUnitTest.h */, + 30BE73E91B541F5B001A2137 /* GPGUnitTest.m */, 4591C4C914F85AA3007F6D47 /* GPGConfReaderTest.m */, 4547646514FBC8A900A37306 /* GPGStdSettingTest.m */, 45156A2314FB310300129FE7 /* GPGLinesSettingTest.m */, @@ -751,9 +692,36 @@ 45156A2614FB35DC00129FE7 /* GPGDictSettingTest.m */, 455B17B915143D9A00FAD47D /* GPGOptionsTest.m */, 45C0BC02151B65C700AA8BF6 /* GPGTestVerify.m */, - 45DD3D4B15642A0D00C9A4C1 /* GPGSignatureTest.m */, + 1BE88B3D1B47D7F900A812B6 /* GPGSocketCloseTest.m */, + 45C0BC13151B664D00AA8BF6 /* Resources */, + 30BE73C01B54015C001A2137 /* Supporting Files */, + ); + path = UnitTests; + sourceTree = ""; + }; + 30BE73C01B54015C001A2137 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 30BE73C11B54015C001A2137 /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 30BE73D51B5405B7001A2137 /* GPGTask */ = { + isa = PBXGroup; + children = ( + 30FF413112FAC6CD00F39832 /* GPGTask.h */, + 30FF413212FAC6CD00F39832 /* GPGTask.m */, + 1B9DB26815784DB700488353 /* GPGTaskHelper.h */, + 1B9DB26915784DB700488353 /* GPGTaskHelper.m */, + 30FF413312FAC6CD00F39832 /* GPGTaskOrder.h */, + 30FF413412FAC6CD00F39832 /* GPGTaskOrder.m */, + 1BC7A4FE13D300A600AE57BA /* LPXTTask.h */, + 1BC7A4FF13D300A600AE57BA /* LPXTTask.m */, + 1B9FF20E17257A69004FB017 /* GPGTaskHelperXPC.h */, + 1B9FF20F17257A69004FB017 /* GPGTaskHelperXPC.m */, ); - path = UnitTest; + name = GPGTask; sourceTree = ""; }; 30DF7CBA16D39EAA00C8225C /* installerHelper */ = { @@ -788,12 +756,14 @@ 45C0BC13151B664D00AA8BF6 /* Resources */ = { isa = PBXGroup; children = ( + 30C8B38F139503A800F49AA1 /* UnitTest-Info.plist */, 45B9A7F5151C9A6D00DAD67A /* OpenPGP.asc */, 45891A40151BA1EC002D7410 /* SignedInputStringCR.txt */, 45891A3C151BA1C9002D7410 /* SignedInputStringCRLF.txt */, 45891A3D151BA1C9002D7410 /* SignedInputStringLF.txt */, ); - path = Resources; + name = Resources; + path = ../UnitTest/Resources; sourceTree = ""; }; /* End PBXGroup section */ @@ -898,24 +868,6 @@ productReference = 1BD78B9F1726B2820005F251 /* LeakFinder.app */; productType = "com.apple.product-type.application"; }; - 1BE88B381B47D7F900A812B6 /* NewUnitTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 1BE88B421B47D7F900A812B6 /* Build configuration list for PBXNativeTarget "NewUnitTests" */; - buildPhases = ( - 1BE88B351B47D7F900A812B6 /* Sources */, - 1BE88B361B47D7F900A812B6 /* Frameworks */, - 1BE88B371B47D7F900A812B6 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 1BE88B411B47D7F900A812B6 /* PBXTargetDependency */, - ); - name = NewUnitTests; - productName = NewUnitTests; - productReference = 1BE88B391B47D7F900A812B6 /* NewUnitTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; 30444C171A65E0590052CB94 /* installerHelper */ = { isa = PBXNativeTarget; buildConfigurationList = 30444C401A65E0590052CB94 /* Build configuration list for PBXNativeTarget "installerHelper" */; @@ -933,24 +885,23 @@ productReference = 30444C181A65E0590052CB94 /* GPGTools.app */; productType = "com.apple.product-type.application"; }; - 30C8B38D139503A800F49AA1 /* UnitTest */ = { + 30BE73BD1B54015C001A2137 /* UnitTests */ = { isa = PBXNativeTarget; - buildConfigurationList = 30C8B392139503A900F49AA1 /* Build configuration list for PBXNativeTarget "UnitTest" */; + buildConfigurationList = 30BE73C71B54015C001A2137 /* Build configuration list for PBXNativeTarget "UnitTests" */; buildPhases = ( - 30C8B389139503A800F49AA1 /* Resources */, - 30C8B38A139503A800F49AA1 /* Sources */, - 30C8B38B139503A800F49AA1 /* Frameworks */, - 30C8B38C139503A800F49AA1 /* ShellScript */, + 30BE73BA1B54015C001A2137 /* Sources */, + 30BE73BB1B54015C001A2137 /* Frameworks */, + 30BE73BC1B54015C001A2137 /* Resources */, ); buildRules = ( ); dependencies = ( - 30C8B3941395046400F49AA1 /* PBXTargetDependency */, + 30BE73C61B54015C001A2137 /* PBXTargetDependency */, ); - name = UnitTest; - productName = UnitTest; - productReference = 30C8B38E139503A800F49AA1 /* UnitTest.octest */; - productType = "com.apple.product-type.bundle.ocunit-test"; + name = UnitTests; + productName = UnitTests; + productReference = 30BE73BE1B54015C001A2137 /* UnitTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; }; 8DC2EF4F0486A6940098B216 /* Libmacgpg */ = { isa = PBXNativeTarget; @@ -985,8 +936,8 @@ attributes = { LastUpgradeCheck = 0450; TargetAttributes = { - 1BE88B381B47D7F900A812B6 = { - CreatedOnToolsVersion = 6.2; + 30BE73BD1B54015C001A2137 = { + CreatedOnToolsVersion = 6.1.1; }; }; }; @@ -1009,11 +960,10 @@ projectRoot = ""; targets = ( 8DC2EF4F0486A6940098B216 /* Libmacgpg */, - 30C8B38D139503A800F49AA1 /* UnitTest */, + 30BE73BD1B54015C001A2137 /* UnitTests */, 1B46CFCB161555DF00CF9C5F /* org.gpgtools.Libmacgpg.xpc */, 1BD78B9E1726B2820005F251 /* LeakFinder */, 30444C171A65E0590052CB94 /* installerHelper */, - 1BE88B381B47D7F900A812B6 /* NewUnitTests */, ); }; /* End PBXProject section */ @@ -1029,13 +979,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 1BE88B371B47D7F900A812B6 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; 30444C161A65E0590052CB94 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -1044,14 +987,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 30C8B389139503A800F49AA1 /* Resources */ = { + 30BE73BC1B54015C001A2137 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 45891A3E151BA1C9002D7410 /* SignedInputStringCRLF.txt in Resources */, - 45891A3F151BA1C9002D7410 /* SignedInputStringLF.txt in Resources */, - 45891A41151BA1EC002D7410 /* SignedInputStringCR.txt in Resources */, - 45B9A7F6151C9A6D00DAD67A /* OpenPGP.asc in Resources */, + 30BE73DD1B541039001A2137 /* OpenPGP.asc in Resources */, + 30BE73DE1B541039001A2137 /* SignedInputStringCR.txt in Resources */, + 30BE73DF1B541039001A2137 /* SignedInputStringCRLF.txt in Resources */, + 30BE73E01B541039001A2137 /* SignedInputStringLF.txt in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1189,20 +1132,6 @@ shellScript = "if [[ -d \"$DEPLOY_RESOURCES_DIR\" ]] ;then\n source \"$DEPLOY_RESOURCES_DIR/config/versioning.sh\"\nelse\n source \"$SRCROOT/Version.config\"\nfi\n[[ -n \"$VERSION\" ]] || { echo \"Missing Version!\"; exit 1; }\n\n\n/usr/libexec/PlistBuddy \\\n -c \"Set CommitHash '${COMMIT_HASH:--}'\" \\\n -c \"Set BuildNumber '${BUILD_NUMBER:-0}'\" \\\n -c \"Set CFBundleVersion '${BUILD_VERSION:-0n}'\" \\\n -c \"Set CFBundleShortVersionString '$VERSION'\" \\\n \"$BUILT_PRODUCTS_DIR/$INFOPLIST_PATH\" || exit 2\n"; showEnvVarsInLog = 0; }; - 30C8B38C139503A800F49AA1 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "# Run the unit tests in this test bundle.\n\"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests\"\n"; - showEnvVarsInLog = 0; - }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -1224,14 +1153,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 1BE88B351B47D7F900A812B6 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 1BE88B3E1B47D7F900A812B6 /* GPGSocketCloseTest.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 30444C141A65E0590052CB94 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -1240,21 +1161,19 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 30C8B38A139503A800F49AA1 /* Sources */ = { + 30BE73BA1B54015C001A2137 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 30C8B39C1395052D00F49AA1 /* Test1.m in Sources */, - 4591C4CA14F85AA3007F6D47 /* GPGConfReaderTest.m in Sources */, - 45156A2414FB310300129FE7 /* GPGLinesSettingTest.m in Sources */, - 45156A2714FB35DC00129FE7 /* GPGDictSettingTest.m in Sources */, - 45156A2D14FB506E00129FE7 /* GPGArraySettingTest.m in Sources */, - 4547646614FBC8A900A37306 /* GPGStdSettingTest.m in Sources */, - 455B17BA15143D9A00FAD47D /* GPGOptionsTest.m in Sources */, - 45C0BC03151B65C700AA8BF6 /* GPGTestVerify.m in Sources */, - 45C0BC18151B66F500AA8BF6 /* GPGResourceUtil.m in Sources */, - 45DD3D4C15642A0D00C9A4C1 /* GPGSignatureTest.m in Sources */, - 45B8C6AC157140A600FD49CD /* NSRunLoop+TimeOutAndFlag.m in Sources */, + 30BE73EC1B54238F001A2137 /* GPGSocketCloseTest.m in Sources */, + 30BE73DC1B5407E3001A2137 /* GPGTestVerify.m in Sources */, + 30BE73E11B5411C2001A2137 /* GPGConfReaderTest.m in Sources */, + 30BE73E21B5411C2001A2137 /* GPGStdSettingTest.m in Sources */, + 30BE73E31B5411C2001A2137 /* GPGLinesSettingTest.m in Sources */, + 30BE73E41B5411C2001A2137 /* GPGArraySettingTest.m in Sources */, + 30BE73E51B5411C2001A2137 /* GPGDictSettingTest.m in Sources */, + 30BE73EA1B541F5B001A2137 /* GPGUnitTest.m in Sources */, + 30BE73E61B5411C2001A2137 /* GPGOptionsTest.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1318,20 +1237,15 @@ target = 8DC2EF4F0486A6940098B216 /* Libmacgpg */; targetProxy = 1BD78BB81726B5190005F251 /* PBXContainerItemProxy */; }; - 1BE88B411B47D7F900A812B6 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 8DC2EF4F0486A6940098B216 /* Libmacgpg */; - targetProxy = 1BE88B401B47D7F900A812B6 /* PBXContainerItemProxy */; - }; 30444C481A65E3E30052CB94 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 30444C171A65E0590052CB94 /* installerHelper */; targetProxy = 30444C471A65E3E30052CB94 /* PBXContainerItemProxy */; }; - 30C8B3941395046400F49AA1 /* PBXTargetDependency */ = { + 30BE73C61B54015C001A2137 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 8DC2EF4F0486A6940098B216 /* Libmacgpg */; - targetProxy = 30C8B3931395046400F49AA1 /* PBXContainerItemProxy */; + targetProxy = 30BE73C51B54015C001A2137 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ @@ -1500,83 +1414,6 @@ }; name = Release; }; - 1BE88B431B47D7F900A812B6 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNREACHABLE_CODE = YES; - COMBINE_HIDPI_IMAGES = YES; - COPY_PHASE_STRIP = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(DEVELOPER_FRAMEWORKS_DIR)", - "$(inherited)", - ); - GCC_DYNAMIC_NO_PIC = NO; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_SYMBOLS_PRIVATE_EXTERN = NO; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - HEADER_SEARCH_PATHS = "${PROJECT_DIR}/Dependencies/XPCKit"; - INFOPLIST_FILE = NewUnitTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.9; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 1BE88B441B47D7F900A812B6 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNREACHABLE_CODE = YES; - COMBINE_HIDPI_IMAGES = YES; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(DEVELOPER_FRAMEWORKS_DIR)", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - HEADER_SEARCH_PATHS = "${PROJECT_DIR}/Dependencies/XPCKit"; - INFOPLIST_FILE = NewUnitTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.9; - MTL_ENABLE_DEBUG_INFO = NO; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; 1DEB91AE08733DA50010E9CD /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -1765,65 +1602,78 @@ }; name = Release; }; - 30C8B390139503A900F49AA1 /* Debug */ = { + 30BE73C81B54015C001A2137 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; - FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(DEVELOPER_FRAMEWORKS_DIR)", + "$(inherited)", + ); GCC_DYNAMIC_NO_PIC = NO; - GCC_ENABLE_OBJC_EXCEPTIONS = YES; - GCC_ENABLE_OBJC_GC = unsupported; - GCC_MODEL_TUNING = G5; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Cocoa.framework/Headers/Cocoa.h"; - HEADER_SEARCH_PATHS = "${PROJECT_DIR}/Dependencies/XPCKit"; - INFOPLIST_FILE = "UnitTest/UnitTest-Info.plist"; - INSTALL_PATH = "$(USER_LIBRARY_DIR)/Bundles"; - LD_RUNPATH_SEARCH_PATHS = "${CONFIGURATION_BUILD_DIR}/Libmacgpg.framework/Versions/A/Frameworks"; - OTHER_LDFLAGS = ( - "-framework", - Cocoa, - "-framework", - SenTestingKit, - "-ObjC", - "-all_load", + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", ); - PRODUCT_NAME = UnitTest; - WRAPPER_EXTENSION = octest; + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + INFOPLIST_FILE = UnitTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.9; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; - 30C8B391139503A900F49AA1 /* Release */ = { + 30BE73C91B54015C001A2137 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - FRAMEWORK_SEARCH_PATHS = "$(DEVELOPER_LIBRARY_DIR)/Frameworks"; - GCC_ENABLE_OBJC_EXCEPTIONS = YES; - GCC_ENABLE_OBJC_GC = unsupported; - GCC_MODEL_TUNING = G5; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Cocoa.framework/Headers/Cocoa.h"; - HEADER_SEARCH_PATHS = "${PROJECT_DIR}/Dependencies/XPCKit"; - INFOPLIST_FILE = "UnitTest/UnitTest-Info.plist"; - INSTALL_PATH = "$(USER_LIBRARY_DIR)/Bundles"; - LD_RUNPATH_SEARCH_PATHS = "${CONFIGURATION_BUILD_DIR}/Libmacgpg.framework/Versions/A/Frameworks"; - OTHER_LDFLAGS = ( - "-framework", - Cocoa, - "-framework", - SenTestingKit, - "-ObjC", - "-all_load", + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(DEVELOPER_FRAMEWORKS_DIR)", + "$(inherited)", ); - PRODUCT_NAME = UnitTest; - WRAPPER_EXTENSION = octest; - ZERO_LINK = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + INFOPLIST_FILE = UnitTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.9; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; @@ -1848,15 +1698,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 1BE88B421B47D7F900A812B6 /* Build configuration list for PBXNativeTarget "NewUnitTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 1BE88B431B47D7F900A812B6 /* Debug */, - 1BE88B441B47D7F900A812B6 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; 1DEB91AD08733DA50010E9CD /* Build configuration list for PBXNativeTarget "Libmacgpg" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -1884,14 +1725,13 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 30C8B392139503A900F49AA1 /* Build configuration list for PBXNativeTarget "UnitTest" */ = { + 30BE73C71B54015C001A2137 /* Build configuration list for PBXNativeTarget "UnitTests" */ = { isa = XCConfigurationList; buildConfigurations = ( - 30C8B390139503A900F49AA1 /* Debug */, - 30C8B391139503A900F49AA1 /* Release */, + 30BE73C81B54015C001A2137 /* Debug */, + 30BE73C91B54015C001A2137 /* Release */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; diff --git a/NewUnitTests/GPGSocketCloseTest.m b/NewUnitTests/GPGSocketCloseTest.m index c72f6e0..699efb1 100644 --- a/NewUnitTests/GPGSocketCloseTest.m +++ b/NewUnitTests/GPGSocketCloseTest.m @@ -14,9 +14,23 @@ #import #import #import "Libmacgpg.h" +#import "GPGUnitTest.h" #import "GPGTaskHelper.h" -uid_t uidFromPid(pid_t pid) { + + +@interface GPGSocketCloseTest : XCTestCase +@end + +@implementation GPGSocketCloseTest + + ++ (void)setUp { + [GPGUnitTest setUpTestDirectory]; +} + + +- (uid_t)uidFromPid:(pid_t)pid { uid_t uid = -1; struct kinfo_proc process; @@ -36,11 +50,6 @@ uid_t uidFromPid(pid_t pid) { return uid; } -@interface GPGSocketCloseTest : XCTestCase - -@end - -@implementation GPGSocketCloseTest - (NSInteger)pidForProcessWithName:(NSString *)name { NSMutableArray *ret = [NSMutableArray arrayWithCapacity:1]; @@ -58,7 +67,7 @@ - (NSInteger)pidForProcessWithName:(NSString *)name { NSMutableDictionary *process = [[NSMutableDictionary alloc] init]; process[@"pid"] = @(pids[i]); - process[@"uid"] = @(uidFromPid(pids[i])); + process[@"uid"] = @([self uidFromPid:pids[i]]); process[@"name"] = [@(pathBuffer) lastPathComponent]; [ret addObject:process]; @@ -174,7 +183,6 @@ - (void)testPassphraseInAgentSocketCloseBug { // This test will only pass if all sockets are properly closed after usage. // In order to warm the passphrase cache some random data is signed. - GPGController *gpgc = [[GPGController alloc] init]; NSString *content = @"This content is signed to warm up the passphrase cache."; NSData *contentData = [content dataUsingEncoding:NSUTF8StringEncoding]; @@ -185,7 +193,7 @@ - (void)testPassphraseInAgentSocketCloseBug { // Eventually add warning for this. gpgc.trustAllKeys = YES; - GPGKey *signerKey = [[[GPGKeyManager sharedInstance] secretKeys] anyObject]; + GPGKey *signerKey = [[GPGKeyManager sharedInstance].allKeys member:testKey2]; XCTAssert(signerKey != nil, @"For this test to run properly, it's necessary to have at least one secret key."); gpgc.signerKey = signerKey; diff --git a/Source/GPGTaskHelper.m b/Source/GPGTaskHelper.m index dbb5e53..2e10f49 100644 --- a/Source/GPGTaskHelper.m +++ b/Source/GPGTaskHelper.m @@ -906,6 +906,10 @@ + (NSString *)gpgAgentSocket { if ([self isGPGAgentSocket:socketPath]) { return socketPath; } + socketPath = [NSString stringWithFormat:@"/tmp/gpg-agent/%@/S.gpg-agent", NSUserName()]; + if ([self isGPGAgentSocket:socketPath]) { + return socketPath; + } return nil; } diff --git a/UnitTest/GPGArraySettingTest.m b/UnitTest/GPGArraySettingTest.m index 330d434..4215435 100644 --- a/UnitTest/GPGArraySettingTest.m +++ b/UnitTest/GPGArraySettingTest.m @@ -18,11 +18,11 @@ along with this program. If not, see . */ -#import +#import #import "GPGArraySetting.h" #import "GPGConfReader.h" -@interface GPGArraySettingTest : SenTestCase { +@interface GPGArraySettingTest : XCTestCase { NSString *key; NSArray *testwords; } @@ -33,11 +33,10 @@ @implementation GPGArraySettingTest - (void) setUp { key = @"auto-key-locate"; - testwords = [[NSArray arrayWithObjects:@"cert", @"pka", nil] retain]; + testwords = [NSArray arrayWithObjects:@"cert", @"pka", nil]; } - (void) tearDown { - [testwords release]; testwords = nil; } @@ -46,9 +45,8 @@ - (void) testSetValue { [setting setValue:testwords]; id value = [setting value]; - STAssertNotNil(value, @"Unexpectedly nil!"); - STAssertTrue([value count] == [testwords count], @"Incorrect count!"); - [setting release]; + XCTAssertNotNil(value, @"Unexpectedly nil!"); + XCTAssertTrue([value count] == [testwords count], @"Incorrect count!"); } - (void) testSetNil { @@ -57,18 +55,15 @@ - (void) testSetNil { [setting setValue:nil]; id value = [setting value]; - STAssertNotNil(value, @"Unexpectedly nil!"); - STAssertTrue([value count] == 0, @"Incorrect count!"); - [setting release]; + XCTAssertNotNil(value, @"Unexpectedly nil!"); + XCTAssertTrue([value count] == 0, @"Incorrect count!"); } - (void) testGetValue { GPGArraySetting *setting = [[GPGArraySetting alloc] initForKey:key]; [setting setValue:testwords]; NSString* desc = [setting description]; - STAssertEqualObjects(@"auto-key-locate cert pka\n", desc, @"description not as expected!"); - - [setting release]; + XCTAssertEqualObjects(@"auto-key-locate cert pka\n", desc, @"description not as expected!"); } - (void) testAppendLine { @@ -77,9 +72,7 @@ - (void) testAppendLine { [setting appendLine:@"auto-key-locate cert,pka" withReader:reader]; setting.isActive = FALSE; NSString* desc = [setting description]; - STAssertEqualObjects(@"#auto-key-locate cert pka\n", desc, @"description not as expected!"); - - [setting release]; + XCTAssertEqualObjects(@"#auto-key-locate cert pka\n", desc, @"description not as expected!"); } @end diff --git a/UnitTest/GPGConfReaderTest.m b/UnitTest/GPGConfReaderTest.m index e63e2d1..66afc53 100644 --- a/UnitTest/GPGConfReaderTest.m +++ b/UnitTest/GPGConfReaderTest.m @@ -18,14 +18,12 @@ along with this program. If not, see . */ -#import +#import #import "GPGConfReader.h" #import "GPGStdSetting.h" #import "GPGArraySetting.h" -#import "GPGDictSetting.h" - -@interface GPGConfReaderTest : SenTestCase +@interface GPGConfReaderTest : XCTestCase @end @implementation GPGConfReaderTest @@ -36,10 +34,10 @@ - (void) testComponentsSeparatedOnWhitespace { NSString *input = @" a b c "; NSString *trimmedInput = [input stringByTrimmingCharactersInSet:whsp]; - STAssertEqualObjects(@"a b c", trimmedInput, @"Not trimmed as expected!"); + XCTAssertEqualObjects(@"a b c", trimmedInput, @"Not trimmed as expected!"); NSArray *splitTrimmed = [trimmedInput componentsSeparatedByCharactersInSet:whsp]; - STAssertTrue(4 == [splitTrimmed count], @"Not split as expected!"); + XCTAssertTrue(4 == [splitTrimmed count], @"Not split as expected!"); } - (void) testSplitString { @@ -48,29 +46,29 @@ - (void) testSplitString { NSString *input = @"a bb ccc ddddd"; NSArray *splitTrimmed = [GPGConfReader splitString:input bySet:whsp maxCount:NSIntegerMax]; - STAssertTrue(4 == [splitTrimmed count], @"Not split as expected!"); + XCTAssertTrue(4 == [splitTrimmed count], @"Not split as expected!"); - STAssertEqualObjects(@"a", [splitTrimmed objectAtIndex:0], @"Element not as expected!"); - STAssertEqualObjects(@"bb", [splitTrimmed objectAtIndex:1], @"Element not as expected!"); - STAssertEqualObjects(@"ccc", [splitTrimmed objectAtIndex:2], @"Element not as expected!"); - STAssertEqualObjects(@"ddddd", [splitTrimmed objectAtIndex:3], @"Element not as expected!"); + XCTAssertEqualObjects(@"a", [splitTrimmed objectAtIndex:0], @"Element not as expected!"); + XCTAssertEqualObjects(@"bb", [splitTrimmed objectAtIndex:1], @"Element not as expected!"); + XCTAssertEqualObjects(@"ccc", [splitTrimmed objectAtIndex:2], @"Element not as expected!"); + XCTAssertEqualObjects(@"ddddd", [splitTrimmed objectAtIndex:3], @"Element not as expected!"); input = @"a bb "; splitTrimmed = [GPGConfReader splitString:input bySet:whsp maxCount:NSIntegerMax]; - STAssertTrue(3 == [splitTrimmed count], @"Not split as expected!"); + XCTAssertTrue(3 == [splitTrimmed count], @"Not split as expected!"); - STAssertEqualObjects(@"a", [splitTrimmed objectAtIndex:0], @"Element not as expected!"); - STAssertEqualObjects(@"bb", [splitTrimmed objectAtIndex:1], @"Element not as expected!"); - STAssertEqualObjects(@"", [splitTrimmed objectAtIndex:2], @"Element not as expected!"); + XCTAssertEqualObjects(@"a", [splitTrimmed objectAtIndex:0], @"Element not as expected!"); + XCTAssertEqualObjects(@"bb", [splitTrimmed objectAtIndex:1], @"Element not as expected!"); + XCTAssertEqualObjects(@"", [splitTrimmed objectAtIndex:2], @"Element not as expected!"); input = @" a bb "; splitTrimmed = [GPGConfReader splitString:input bySet:whsp maxCount:NSIntegerMax]; - STAssertTrue(4 == [splitTrimmed count], @"Not split as expected!"); + XCTAssertTrue(4 == [splitTrimmed count], @"Not split as expected!"); - STAssertEqualObjects(@"", [splitTrimmed objectAtIndex:0], @"Element not as expected!"); - STAssertEqualObjects(@"a", [splitTrimmed objectAtIndex:1], @"Element not as expected!"); - STAssertEqualObjects(@"bb", [splitTrimmed objectAtIndex:2], @"Element not as expected!"); - STAssertEqualObjects(@"", [splitTrimmed objectAtIndex:3], @"Element not as expected!"); + XCTAssertEqualObjects(@"", [splitTrimmed objectAtIndex:0], @"Element not as expected!"); + XCTAssertEqualObjects(@"a", [splitTrimmed objectAtIndex:1], @"Element not as expected!"); + XCTAssertEqualObjects(@"bb", [splitTrimmed objectAtIndex:2], @"Element not as expected!"); + XCTAssertEqualObjects(@"", [splitTrimmed objectAtIndex:3], @"Element not as expected!"); } - (void) testLimitedSplitString { @@ -80,45 +78,40 @@ - (void) testLimitedSplitString { NSString *input = @"a = bb ccc "; NSArray *splitTrimmed = [GPGConfReader splitString:input bySet:whspeqsign maxCount:2]; - STAssertTrue(2 == [splitTrimmed count], @"Not split as expected!"); + XCTAssertTrue(2 == [splitTrimmed count], @"Not split as expected!"); - STAssertEqualObjects(@"a", [splitTrimmed objectAtIndex:0], @"Element not as expected!"); - STAssertEqualObjects(@"bb ccc ", [splitTrimmed objectAtIndex:1], @"Element not as expected!"); + XCTAssertEqualObjects(@"a", [splitTrimmed objectAtIndex:0], @"Element not as expected!"); + XCTAssertEqualObjects(@"bb ccc ", [splitTrimmed objectAtIndex:1], @"Element not as expected!"); } - (void) testKeyForLine { GPGConfReader *reader = [GPGConfReader readerForDomain:GPGDomain_gpgConf]; NSString *key = [reader condensedKeyForLine:@" option1 a=b"]; - STAssertEqualObjects(@"option1", key, @"Setting key not as expected!"); + XCTAssertEqualObjects(@"option1", key, @"Setting key not as expected!"); key = [reader condensedKeyForLine:@" #option1 a=b"]; - STAssertNil(key, @"Unknown commented option not ignored!"); + XCTAssertNil(key, @"Unknown commented option not ignored!"); key = [reader condensedKeyForLine:@" #no-sig-cache"]; - STAssertEqualObjects(@"sig-cache", key, @"\"no-\" not removed as expected!"); + XCTAssertEqualObjects(@"sig-cache", key, @"\"no-\" not removed as expected!"); key = [reader condensedKeyForLine:@" #no-auto-key-locate"]; - STAssertEqualObjects(@"no-auto-key-locate", key, @"Special case not handled as expected!"); + XCTAssertEqualObjects(@"no-auto-key-locate", key, @"Special case not handled as expected!"); } - (void) testClassForLine { GPGConfReader *reader = [GPGConfReader readerForDomain:GPGDomain_gpgConf]; GPGStdSetting *setting = [reader buildForLine:@" #no-auto-key-locate "]; - STAssertNotNil(setting, @"Unexpectedly nil!"); - STAssertEqualObjects(@"no-auto-key-locate", setting.key, @"Unexpected key!"); - STAssertTrue([setting isKindOfClass:[GPGStdSetting class]], @"Unexpected class!"); - - setting = [reader buildForLine:@" keyserver-options k1=cert"]; - STAssertNotNil(setting, @"Unexpectedly nil!"); - STAssertEqualObjects(@"keyserver-options", setting.key, @"Unexpected key!"); - STAssertTrue([setting isKindOfClass:[GPGDictSetting class]], @"Unexpected class!"); + XCTAssertNotNil(setting, @"Unexpectedly nil!"); + XCTAssertEqualObjects(@"no-auto-key-locate", setting.key, @"Unexpected key!"); + XCTAssertTrue([setting isKindOfClass:[GPGStdSetting class]], @"Unexpected class!"); setting = [reader buildForLine:@" export-options export-minimal"]; - STAssertNotNil(setting, @"Unexpectedly nil!"); - STAssertEqualObjects(@"export-options", setting.key, @"Unexpected key!"); - STAssertTrue([setting isKindOfClass:[GPGArraySetting class]], @"Unexpected class!"); + XCTAssertNotNil(setting, @"Unexpectedly nil!"); + XCTAssertEqualObjects(@"export-options", setting.key, @"Unexpected key!"); + XCTAssertTrue([setting isKindOfClass:[GPGArraySetting class]], @"Unexpected class!"); } @end diff --git a/UnitTest/GPGDictSettingTest.m b/UnitTest/GPGDictSettingTest.m index 82cbc87..e3d1b93 100644 --- a/UnitTest/GPGDictSettingTest.m +++ b/UnitTest/GPGDictSettingTest.m @@ -18,11 +18,11 @@ along with this program. If not, see . */ -#import +#import #import "GPGDictSetting.h" #import "GPGConfReader.h" -@interface GPGDictSettingTest : SenTestCase { +@interface GPGDictSettingTest : XCTestCase { NSString *key; NSDictionary *testdict; } @@ -33,22 +33,17 @@ @implementation GPGDictSettingTest - (void) setUp { key = @"keyserver-options"; - testdict = [[NSDictionary dictionaryWithObjectsAndKeys:[NSArray arrayWithObjects:@"abc", @"def", nil], - @"keyserver1", nil] retain]; + testdict = [NSDictionary dictionaryWithObjectsAndKeys:[NSArray arrayWithObjects:@"abc", @"def", nil], @"keyserver1", nil]; } -- (void) tearDown { - [testdict release]; -} - (void) testSetValue { GPGDictSetting *setting = [[GPGDictSetting alloc] initForKey:key]; [setting setValue:testdict]; id value = [setting value]; - STAssertNotNil(value, @"Unexpectedly nil!"); - STAssertTrue([value count] == [testdict count], @"Incorrect count!"); - [setting release]; + XCTAssertNotNil(value, @"Unexpectedly nil!"); + XCTAssertTrue([value count] == [testdict count], @"Incorrect count!"); } - (void) testSetNil { @@ -57,9 +52,8 @@ - (void) testSetNil { [setting setValue:nil]; id value = [setting value]; - STAssertNotNil(value, @"Unexpectedly nil!"); - STAssertTrue([value count] == 0, @"Incorrect count!"); - [setting release]; + XCTAssertNotNil(value, @"Unexpectedly nil!"); + XCTAssertTrue([value count] == 0, @"Incorrect count!"); } - (void) testGetValue { @@ -67,9 +61,8 @@ - (void) testGetValue { GPGDictSetting *setting = [[GPGDictSetting alloc] initForKey:key]; [setting setValue:testdict]; NSString* desc = [setting description]; - STAssertEqualObjects(@"keyserver-options keyserver1=abc def\n", desc, @"description not as expected!"); + XCTAssertEqualObjects(@"keyserver-options keyserver1=abc def\n", desc, @"description not as expected!"); - [setting release]; } - (void) testAppendLine { @@ -79,9 +72,7 @@ - (void) testAppendLine { [setting appendLine:@"keyserver-options keyserver1=c, d" withReader:reader]; setting.isActive = FALSE; NSString* desc = [setting description]; - STAssertEqualObjects(@"#keyserver-options keyserver1=c d\n", desc, @"description not as expected!"); - - [setting release]; + XCTAssertEqualObjects(@"#keyserver-options keyserver1=c d\n", desc, @"description not as expected!"); } @end diff --git a/UnitTest/GPGLinesSettingTest.m b/UnitTest/GPGLinesSettingTest.m index 7e470c1..34afc20 100644 --- a/UnitTest/GPGLinesSettingTest.m +++ b/UnitTest/GPGLinesSettingTest.m @@ -18,11 +18,11 @@ along with this program. If not, see . */ -#import +#import #import "GPGLinesSetting.h" #import "GPGConfReader.h" -@interface GPGLinesSettingTest : SenTestCase { +@interface GPGLinesSettingTest : XCTestCase { NSString *key; NSArray *testlines; } @@ -33,11 +33,7 @@ @implementation GPGLinesSettingTest - (void) setUp { key = @"comment"; - testlines = [[NSArray arrayWithObjects:@"abc", @"def", nil] retain]; -} - -- (void) tearDown { - [testlines release]; + testlines = [NSArray arrayWithObjects:@"abc", @"def", nil]; } - (void) testSetValue { @@ -45,9 +41,8 @@ - (void) testSetValue { [setting setValue:testlines]; id value = [setting value]; - STAssertNotNil(value, @"Unexpectedly nil!"); - STAssertTrue([value count] == [testlines count], @"Incorrect count!"); - [setting release]; + XCTAssertNotNil(value, @"Unexpectedly nil!"); + XCTAssertTrue([value count] == [testlines count], @"Incorrect count!"); } - (void) testSetNil { @@ -56,18 +51,16 @@ - (void) testSetNil { [setting setValue:nil]; id value = [setting value]; - STAssertNotNil(value, @"Unexpectedly nil!"); - STAssertTrue([value count] == 0, @"Incorrect count!"); - [setting release]; + XCTAssertNotNil(value, @"Unexpectedly nil!"); + XCTAssertTrue([value count] == 0, @"Incorrect count!"); } - (void) testGetValue { GPGLinesSetting *setting = [[GPGLinesSetting alloc] initForKey:key]; [setting setValue:testlines]; NSString* desc = [setting description]; - STAssertEqualObjects(@"comment abc\ncomment def\n", desc, @"description not as expected!"); + XCTAssertEqualObjects(@"comment abc\ncomment def\n", desc, @"description not as expected!"); - [setting release]; } - (void) testAppendLine { @@ -77,9 +70,7 @@ - (void) testAppendLine { [setting appendLine:@"comment line 2." withReader:reader]; setting.isActive = FALSE; NSString* desc = [setting description]; - STAssertEqualObjects(@"#comment line 1.\n#comment line 2.\n", desc, @"description not as expected!"); - - [setting release]; + XCTAssertEqualObjects(@"#comment line 1.\n#comment line 2.\n", desc, @"description not as expected!"); } @end diff --git a/UnitTest/GPGOptionsTest.m b/UnitTest/GPGOptionsTest.m index 32a97e4..9b80cb7 100644 --- a/UnitTest/GPGOptionsTest.m +++ b/UnitTest/GPGOptionsTest.m @@ -1,7 +1,7 @@ -#import +#import #import "GPGOptions.h" -@interface GPGOptionsTest : SenTestCase +@interface GPGOptionsTest : XCTestCase @end @@ -11,21 +11,21 @@ - (void)testDomainForKey1 { GPGOptions *options = [GPGOptions sharedOptions]; GPGOptionsDomain domain = [options domainForKey:@"marginals-needed"]; - STAssertEquals(domain, GPGDomain_gpgConf, @"unexpected domain"); + XCTAssertEqual(domain, GPGDomain_gpgConf, @"unexpected domain"); } - (void)testDomainForKey2 { GPGOptions *options = [GPGOptions sharedOptions]; GPGOptionsDomain domain = [options domainForKey:@"min-passphrase-nonalpha"]; - STAssertEquals(domain, GPGDomain_gpgAgentConf, @"unexpected domain"); + XCTAssertEqual(domain, GPGDomain_gpgAgentConf, @"unexpected domain"); } - (void)testDomainForKey3 { GPGOptions *options = [GPGOptions sharedOptions]; GPGOptionsDomain domain = [options domainForKey:@"ShowPassphrase"]; - STAssertEquals(domain, GPGDomain_common, @"unexpected domain"); + XCTAssertEqual(domain, GPGDomain_common, @"unexpected domain"); } @end diff --git a/UnitTest/GPGResourceUtil.h b/UnitTest/GPGResourceUtil.h deleted file mode 100644 index 2cd8a47..0000000 --- a/UnitTest/GPGResourceUtil.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// GPGResourceUtil.h -// Libmacgpg -// -// Created by Chris Fraire on 3/22/12. -// Copyright (c) 2012 Chris Fraire. All rights reserved. -// - -#import - -@interface GPGResourceUtil : NSObject - -+ (NSData *)dataForResourceAtPath:(NSString *)path ofType:(NSString *)rtype; - -@end diff --git a/UnitTest/GPGResourceUtil.m b/UnitTest/GPGResourceUtil.m deleted file mode 100644 index a3c1260..0000000 --- a/UnitTest/GPGResourceUtil.m +++ /dev/null @@ -1,22 +0,0 @@ -// -// GPGResourceUtil.m -// Libmacgpg -// -// Created by Chris Fraire on 3/22/12. -// Copyright (c) 2012 Chris Fraire. All rights reserved. -// - -#import "GPGResourceUtil.h" - -@implementation GPGResourceUtil - -+ (NSData *)dataForResourceAtPath:(NSString *)path ofType:(NSString *)rtype { - NSBundle *execBundl = [NSBundle bundleForClass:[self class]]; - NSString *file = [execBundl pathForResource:path ofType:rtype]; - NSData *data = [NSData dataWithContentsOfFile:file]; - if (!data) - @throw [NSException exceptionWithName:@"ApplicationException" reason:@"missing resource" userInfo:nil]; - return data; -} - -@end diff --git a/UnitTest/GPGSignatureTest.m b/UnitTest/GPGSignatureTest.m deleted file mode 100644 index edbcd0b..0000000 --- a/UnitTest/GPGSignatureTest.m +++ /dev/null @@ -1,77 +0,0 @@ -// -// GPGSignatureTest.m -// Libmacgpg -// -// Created by Chris Fraire on 5/16/12. -// Copyright (c) 2012 Chris Fraire. All rights reserved. -// - -#import -#import "GPGSignature.h" -#import "GPGGlobals.h" - -@interface GPGSignatureTest : SenTestCase - -@end - -@implementation GPGSignatureTest - -- (void)testGoodSignatureDesc { - GPGSignature *sig = [[GPGSignature alloc] init]; - [sig addInfoFromStatusCode:GPG_STATUS_GOODSIG andPrompt:@"ABCZYX someone@someplace.com"]; - NSString *desc = [sig humanReadableDescriptionShouldLocalize:NO]; - STAssertEqualObjects(desc, @"Signed (someone@someplace.com)", @"Unreadable!"); - [sig release]; -} - -- (void)testExpiredSignatureDesc { - GPGSignature *sig = [[GPGSignature alloc] init]; - [sig addInfoFromStatusCode:GPG_STATUS_EXPSIG andPrompt:@"ABCZYX someone@someplace.com"]; - NSString *desc = [sig humanReadableDescriptionShouldLocalize:NO]; - STAssertEqualObjects(desc, @"Signature expired (someone@someplace.com)", @"Unreadable!"); - [sig release]; -} - -- (void)testExpiredKeyDesc { - // same as expired signature - GPGSignature *sig = [[GPGSignature alloc] init]; - [sig addInfoFromStatusCode:GPG_STATUS_EXPKEYSIG andPrompt:@"ABCZYX someone@someplace.com"]; - NSString *desc = [sig humanReadableDescriptionShouldLocalize:NO]; - STAssertEqualObjects(desc, @"Signature expired (someone@someplace.com)", @"Unreadable!"); - [sig release]; -} - -- (void)testBadKeyDesc { - GPGSignature *sig = [[GPGSignature alloc] init]; - [sig addInfoFromStatusCode:GPG_STATUS_BADSIG andPrompt:@"ABCZYX someone@someplace.com"]; - NSString *desc = [sig humanReadableDescriptionShouldLocalize:NO]; - STAssertEqualObjects(desc, @"Bad signature (someone@someplace.com)", @"Unreadable!"); - [sig release]; -} - -- (void)testNoPublicKeyDesc { - GPGSignature *sig = [[GPGSignature alloc] init]; - [sig addInfoFromStatusCode:GPG_STATUS_ERRSIG andPrompt:@"ABCZYX 1 hash class date 9"]; - NSString *desc = [sig humanReadableDescriptionShouldLocalize:NO]; - STAssertEqualObjects(desc, @"Signed by stranger (ABCZYX GPG_RSAAlgorithm)", @"Unreadable!"); - [sig release]; -} - -- (void)testUnknownAlgorithmDesc { - GPGSignature *sig = [[GPGSignature alloc] init]; - [sig addInfoFromStatusCode:GPG_STATUS_ERRSIG andPrompt:@"ABCZYX 244 hash class date 4"]; - NSString *desc = [sig humanReadableDescriptionShouldLocalize:NO]; - STAssertEqualObjects(desc, @"Unverifiable signature (ABCZYX Algorithm_244)", @"Unreadable!"); - [sig release]; -} - -- (void)testGeneralErrorDesc { - GPGSignature *sig = [[GPGSignature alloc] init]; - [sig addInfoFromStatusCode:GPG_STATUS_BADSIG andPrompt:@"ABCZYX someone@someplace.com"]; - [sig addInfoFromStatusCode:GPG_STATUS_ERRSIG andPrompt:@"ABCZYX alg hash class date 999"]; - NSString *desc = [sig humanReadableDescriptionShouldLocalize:NO]; - STAssertEqualObjects(desc, @"Signature error (someone@someplace.com)", @"Unreadable!"); - [sig release]; -} - -@end diff --git a/UnitTest/GPGStdSettingTest.m b/UnitTest/GPGStdSettingTest.m index 9d7759b..4ba00ff 100644 --- a/UnitTest/GPGStdSettingTest.m +++ b/UnitTest/GPGStdSettingTest.m @@ -18,13 +18,11 @@ along with this program. If not, see . */ -#import +#import #import "GPGStdSetting.h" #import "GPGConfReader.h" -@interface GPGStdSettingTest : SenTestCase { -} - +@interface GPGStdSettingTest : XCTestCase @end @implementation GPGStdSettingTest @@ -35,8 +33,7 @@ - (void) testSetString { [setting setValue:value]; id value2 = [setting value]; - STAssertNotNil(value2, @"Unexpectedly nil!"); - [setting release]; + XCTAssertNotNil(value2, @"Unexpectedly nil!"); } - (void) testSetNil { @@ -45,8 +42,7 @@ - (void) testSetNil { [setting setValue:nil]; id value2 = [setting value]; - STAssertNil(value2, @"Unexpectedly defined!"); - [setting release]; + XCTAssertNil(value2, @"Unexpectedly defined!"); } - (void) testDescription { @@ -55,13 +51,12 @@ - (void) testDescription { [setting setValue:value]; NSString* desc = [setting description]; - STAssertEqualObjects(@"keyserver hkp://domain.com\n", desc, @"description not as expected!"); + XCTAssertEqualObjects(@"keyserver hkp://domain.com\n", desc, @"description not as expected!"); [setting setValue:nil]; desc = [setting description]; - STAssertEqualObjects(@"#keyserver\n", desc, @"description not as expected!"); + XCTAssertEqualObjects(@"#keyserver\n", desc, @"description not as expected!"); - [setting release]; } - (void) testAppendLineString { @@ -71,9 +66,8 @@ - (void) testAppendLineString { [setting appendLine:@"keyserver hkp://domain.com" withReader:reader]; setting.isActive = FALSE; NSString* desc = [setting description]; - STAssertEqualObjects(@"#keyserver hkp://domain.com\n", desc, @"description not as expected!"); + XCTAssertEqualObjects(@"#keyserver hkp://domain.com\n", desc, @"description not as expected!"); - [setting release]; } - (void) testAppendLineTRUE { @@ -83,14 +77,13 @@ - (void) testAppendLineTRUE { [setting appendLine:@"ask-cert-level " withReader:reader]; id value = [setting value]; - STAssertTrue([value isKindOfClass:[NSNumber class]], @"Not NSNumber as expected!"); - STAssertTrue([value boolValue], @"Not TRUE as expected!"); + XCTAssertTrue([value isKindOfClass:[NSNumber class]], @"Not NSNumber as expected!"); + XCTAssertTrue([value boolValue], @"Not TRUE as expected!"); setting.isActive = FALSE; NSString* desc = [setting description]; - STAssertEqualObjects(@"#ask-cert-level\n", desc, @"description not as expected!"); + XCTAssertEqualObjects(@"#ask-cert-level\n", desc, @"description not as expected!"); - [setting release]; } - (void) testAppendLineFALSE { @@ -100,14 +93,13 @@ - (void) testAppendLineFALSE { [setting appendLine:@"no-ask-cert-level " withReader:reader]; id value = [setting value]; - STAssertTrue([value isKindOfClass:[NSNumber class]], @"Not NSNumber as expected!"); - STAssertFalse([value boolValue], @"Not FALSE as expected!"); + XCTAssertTrue([value isKindOfClass:[NSNumber class]], @"Not NSNumber as expected!"); + XCTAssertFalse([value boolValue], @"Not FALSE as expected!"); setting.isActive = FALSE; NSString* desc = [setting description]; - STAssertEqualObjects(@"#no-ask-cert-level\n", desc, @"description not as expected!"); + XCTAssertEqualObjects(@"#no-ask-cert-level\n", desc, @"description not as expected!"); - [setting release]; } - (void) testgpgdotconf1 { @@ -126,19 +118,18 @@ - (void) testgpgdotconf1 { } id value = [setting value]; - STAssertTrue([value isKindOfClass:[NSNumber class]], @"Not NSNumber as expected!"); - STAssertFalse([value boolValue], @"Not FALSE as expected!"); + XCTAssertTrue([value isKindOfClass:[NSNumber class]], @"Not NSNumber as expected!"); + XCTAssertFalse([value boolValue], @"Not FALSE as expected!"); NSString* desc = [setting description]; NSString* expected = [NSString stringWithFormat:@"%@\n", [lines componentsJoinedByString:@"\n"]]; - STAssertEqualObjects(expected, desc, @"description not as expected!"); + XCTAssertEqualObjects(expected, desc, @"description not as expected!"); setting.isActive = FALSE; desc = [setting description]; expected = @"# Some comment.\n# More comment. \n#no-ask-cert-level\n"; - STAssertEqualObjects(expected, desc, @"description not as expected!"); + XCTAssertEqualObjects(expected, desc, @"description not as expected!"); - [setting release]; } @end diff --git a/UnitTest/GPGTestVerify.m b/UnitTest/GPGTestVerify.m index a316853..45b79fd 100644 --- a/UnitTest/GPGTestVerify.m +++ b/UnitTest/GPGTestVerify.m @@ -5,107 +5,104 @@ // Created by Chris Fraire on 3/22/12. // Copyright (c) 2012 Chris Fraire. All rights reserved. // -#import -#import "GPGController.h" -#import "GPGResourceUtil.h" -#import "GPGSignature.h" +#import +#import "Libmacgpg.h" +#import "GPGUnitTest.h" +//#import "GPGController.h" +//#import "GPGResourceUtil.h" +//#import "GPGSignature.h" + -@interface GPGTestVerify : SenTestCase { - BOOL _didImport; -} +@interface GPGTestVerify : XCTestCase @end @implementation GPGTestVerify -- (void)setUp { - if (!_didImport) { - NSData *data = [GPGResourceUtil dataForResourceAtPath:@"OpenPGP" ofType:@"asc"]; - GPGController* ctx = [GPGController gpgController]; - [ctx importFromData:data fullImport:TRUE]; - _didImport = TRUE; - } ++ (void)setUp { + [GPGUnitTest setUpTestDirectory]; } -- (void)testAAAFindTestKey { - GPGController* ctx = [GPGController gpgController]; - NSSet *foundKeys = [ctx keysForSearchPattern:@"test@gpgtools.org"]; - STAssertTrue([foundKeys count] > 0, @"Test key not imported!"); +- (void)testCheckTestKey { + GPGKey *key = [manager.allKeys member:testKey]; + XCTAssertNotNil(key, @"Test key not imported!"); + XCTAssertTrue([key.fingerprint isEqualToString:testKey], @"Test key fingerprint does not match!"); } - (void)testVerifyDataLF { - NSData *data = [GPGResourceUtil dataForResourceAtPath:@"SignedInputStringLF" ofType:@"txt"]; - GPGController* ctx = [GPGController gpgController]; - ctx.useArmor = YES; - NSArray* sigs = [ctx verifySignature:data originalData:nil]; - STAssertTrue(1 == [sigs count], @"Did not verify as expected!"); - GPGSignature *signature = ([sigs count]) ? [sigs objectAtIndex:0] : nil; - STAssertEquals(signature.status, GPGErrorNoError, @"Did not verify as expected!"); - STAssertTrue(signature.hasFilled, @"Did not verify as expected!"); + NSData *data = [GPGUnitTest dataForResource:@"SignedInputStringLF.txt"]; + + NSArray *sigs = [gpgc verifySignature:data originalData:nil]; + + XCTAssertTrue(sigs.count == 1, @"Did not verify as expected!"); + GPGSignature *signature = sigs[0]; + XCTAssertEqual(signature.status, GPGErrorNoError, @"Did not verify as expected!"); + XCTAssertEqualObjects(signature.fingerprint, testSubkey, @"Did not verify as expected!"); } + - (void)testVerifyDataCRLF { - NSData *data = [GPGResourceUtil dataForResourceAtPath:@"SignedInputStringCRLF" ofType:@"txt"]; - GPGController* ctx = [GPGController gpgController]; - ctx.useArmor = YES; - NSArray* sigs = [ctx verifySignature:data originalData:nil]; - STAssertTrue(1 == [sigs count], @"Did not verify as expected!"); - GPGSignature *signature = ([sigs count]) ? [sigs objectAtIndex:0] : nil; - STAssertEquals(signature.status, GPGErrorNoError, @"Did not verify as expected!"); - STAssertTrue(signature.hasFilled, @"Did not verify as expected!"); + NSData *data = [GPGUnitTest dataForResource:@"SignedInputStringCRLF.txt"]; + + NSArray *sigs = [gpgc verifySignature:data originalData:nil]; + + XCTAssertTrue(sigs.count == 1, @"Did not verify as expected!"); + GPGSignature *signature = sigs[0]; + XCTAssertEqual(signature.status, GPGErrorNoError, @"Did not verify as expected!"); + XCTAssertEqualObjects(signature.fingerprint, testSubkey, @"Did not verify as expected!"); } - (void)testVerifyDataCR { - NSData *data = [GPGResourceUtil dataForResourceAtPath:@"SignedInputStringCR" ofType:@"txt"]; - GPGController* ctx = [GPGController gpgController]; - ctx.useArmor = YES; - NSArray* sigs = [ctx verifySignature:data originalData:nil]; - STAssertTrue(1 == [sigs count], @"Did not verify as expected!"); - GPGSignature *signature = ([sigs count]) ? [sigs objectAtIndex:0] : nil; - STAssertEquals(signature.status, GPGErrorNoError, @"Did not verify as expected!"); - STAssertTrue(signature.hasFilled, @"Did not verify as expected!"); + NSData *data = [GPGUnitTest dataForResource:@"SignedInputStringCR.txt"]; + + NSArray *sigs = [gpgc verifySignature:data originalData:nil]; + + XCTAssertTrue(sigs.count == 1, @"Did not verify as expected!"); + GPGSignature *signature = sigs[0]; + XCTAssertEqual(signature.status, GPGErrorNoError, @"Did not verify as expected!"); + XCTAssertEqualObjects(signature.fingerprint, testSubkey, @"Did not verify as expected!"); } - (void)testVerifyForceLF_to_CRLF { - NSData *data = [GPGResourceUtil dataForResourceAtPath:@"SignedInputStringLF" ofType:@"txt"]; - NSString *dstring = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]; + NSData *data = [GPGUnitTest dataForResource:@"SignedInputStringLF.txt"]; + NSString *dstring = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; dstring = [dstring stringByReplacingOccurrencesOfString:@"\n" withString:@"\r\n"]; data = [dstring UTF8Data]; - GPGController* ctx = [GPGController gpgController]; - ctx.useArmor = YES; - NSArray* sigs = [ctx verifySignature:data originalData:nil]; - STAssertTrue(1 == [sigs count], @"Did not verify as expected!"); - GPGSignature *signature = ([sigs count]) ? [sigs objectAtIndex:0] : nil; - STAssertEquals(signature.status, GPGErrorNoError, @"Did not verify as expected!"); - STAssertTrue(signature.hasFilled, @"Did not verify as expected!"); + + NSArray *sigs = [gpgc verifySignature:data originalData:nil]; + + XCTAssertTrue(sigs.count == 1, @"Did not verify as expected!"); + GPGSignature *signature = sigs[0]; + XCTAssertEqual(signature.status, GPGErrorNoError, @"Did not verify as expected!"); + XCTAssertEqualObjects(signature.fingerprint, testSubkey, @"Did not verify as expected!"); } - (void)testVerifyForceCRLF_to_LF { - NSData *data = [GPGResourceUtil dataForResourceAtPath:@"SignedInputStringCRLF" ofType:@"txt"]; - NSString *dstring = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]; + NSData *data = [GPGUnitTest dataForResource:@"SignedInputStringCRLF.txt"]; + NSString *dstring = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; dstring = [dstring stringByReplacingOccurrencesOfString:@"\r\n" withString:@"\n"]; data = [dstring UTF8Data]; - GPGController* ctx = [GPGController gpgController]; - ctx.useArmor = YES; - NSArray* sigs = [ctx verifySignature:data originalData:nil]; - STAssertTrue(1 == [sigs count], @"Did not verify as expected!"); - GPGSignature *signature = ([sigs count]) ? [sigs objectAtIndex:0] : nil; - STAssertEquals(signature.status, GPGErrorNoError, @"Did not verify as expected!"); - STAssertTrue(signature.hasFilled, @"Did not verify as expected!"); + + NSArray *sigs = [gpgc verifySignature:data originalData:nil]; + + XCTAssertTrue(sigs.count == 1, @"Did not verify as expected!"); + GPGSignature *signature = sigs[0]; + XCTAssertEqual(signature.status, GPGErrorNoError, @"Did not verify as expected!"); + XCTAssertEqualObjects(signature.fingerprint, testSubkey, @"Did not verify as expected!"); } - (void)testBadVerifyForceCR_to_LF { - NSData *data = [GPGResourceUtil dataForResourceAtPath:@"SignedInputStringCR" ofType:@"txt"]; - NSString *dstring = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]; + NSData *data = [GPGUnitTest dataForResource:@"SignedInputStringCR.txt"]; + NSString *dstring = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; dstring = [dstring stringByReplacingOccurrencesOfString:@"\r" withString:@"\n"]; data = [dstring UTF8Data]; - GPGController* ctx = [GPGController gpgController]; - ctx.useArmor = YES; - NSArray* sigs = [ctx verifySignature:data originalData:nil]; - STAssertTrue(1 == [sigs count], @"Did not verify as expected!"); - GPGSignature *signature = ([sigs count]) ? [sigs objectAtIndex:0] : nil; - STAssertEquals(signature.status, GPGErrorBadSignature, @"Verified unexpectedly!"); - STAssertTrue(signature.hasFilled, @"Did not get entry as expected!"); + + NSArray *sigs = [gpgc verifySignature:data originalData:nil]; + + XCTAssertTrue(sigs.count == 1, @"Did not verify as expected!"); + GPGSignature *signature = sigs[0]; + XCTAssertEqual(signature.status, GPGErrorBadSignature, @"Verified unexpectedly!"); + XCTAssertEqualObjects(signature.fingerprint, testSubkey, @"Did not verify as expected!"); } @end diff --git a/UnitTest/NSRunLoop+TimeOutAndFlag.h b/UnitTest/NSRunLoop+TimeOutAndFlag.h deleted file mode 100644 index 1632bf6..0000000 --- a/UnitTest/NSRunLoop+TimeOutAndFlag.h +++ /dev/null @@ -1,11 +0,0 @@ -// -// NSRunLoop+TimeOutAndFlag.h -// -// https://gist.github.com/n-b -// - -@interface NSRunLoop (TimeOutAndFlag) - -- (void)runUntilTimeout:(NSTimeInterval)delay orFinishedFlag:(BOOL*)finished; - -@end diff --git a/UnitTest/NSRunLoop+TimeOutAndFlag.m b/UnitTest/NSRunLoop+TimeOutAndFlag.m deleted file mode 100644 index 37dd5bc..0000000 --- a/UnitTest/NSRunLoop+TimeOutAndFlag.m +++ /dev/null @@ -1,19 +0,0 @@ -// -// NSRunLoop+TimeOutAndFlag.m -// -// https://gist.github.com/n-b -// - -#import "NSRunLoop+TimeOutAndFlag.h" - -@implementation NSRunLoop (TimeOutAndFlag) - -- (void)runUntilTimeout:(NSTimeInterval)delay orFinishedFlag:(BOOL*)finished; -{ - NSDate * endDate = [NSDate dateWithTimeIntervalSinceNow:delay]; - do { - [self runMode:NSDefaultRunLoopMode beforeDate:nil]; - } while (!*finished && [endDate compare:[NSDate date]]==NSOrderedDescending); -} - -@end diff --git a/UnitTest/Resources/OpenPGP.asc b/UnitTest/Resources/OpenPGP.asc index 5876b41..176c327 100644 --- a/UnitTest/Resources/OpenPGP.asc +++ b/UnitTest/Resources/OpenPGP.asc @@ -1,44 +1,5 @@ ------BEGIN PGP PUBLIC KEY BLOCK----- -Version: GnuPG/MacGPG2 v2.0.17 (Darwin) -Comment: GPGTools - http://gpgtools.org - -mQENBE5EYggBCADmanTuJWEAyEWh90eSrrNIEYKLe922pwmVKhJCCXbnbfV00+cb -hrg92Dvt3o7QlpF9CssMausWfqycpjNrMKYZXfnH4ToMTnl2TBNav6A1SMkPGj82 -R600A7wEPa905PJczBbgiJ6IwWIz+OcQcyU0Yqg9Duqqjgwat/+ViyaNY9qTpLmp -GCjbksHrWgZ/BA/cJOjMeHvuGDPE/J/n6BV+UPvtUrTUZAZuexahC8lazJTxe9ap -NEuDY48uBHMdT669h6sRzGxDyy3dvvBItO3KRVQ80iFUg/2MZjMjF66kaJbTVJ/1 -FcbiNpXKC+sPC3fnP0vCxrdgaKyO9fL3E3H3ABEBAAG0QkdQR1Rvb2xzIFRlc3Qg -S2V5IChGb3IgdGVzdGluZyBwdXJwb3NlcyBvbmx5ISkgPHRlc3RAZ3BndG9vbHMu -b3JnPokBOAQTAQIAIgUCTkRiCAIbLwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AA -CgkQ+YikWQ2wOn3/BQf/e4AS3QdOvViKKPC1t66xIxyYPDD+j2h7/NmGNRHXkuCz -c2MzGxUzEDKQ+MuQBquo/N/F6+pNTLtVOe48ktAS0gjRgoG5PUOPGUAkE/S3+576 -4QegSDUVjdZLzWsrne4fvUmmFOGEHOa0lHMt82KiGICR1FrfHup/oPwc68lCirIL -K7efPuNFy96zsdDDzAmUmXcuG6PDsLMgo2dwZVCL5k2Ez++/w3cZpYYJLHn1iBII -ozJpUxSDxFll5XY3va6GaJKvUy2F1Y2vEgOXz6RXlS6g6A+MwZ92wZmGJiETQ150 -ZlXPPlXGqdqpsNUE2vZAtckDWISnJnrZcnpRj3y0LbkBDQRORGIIAQgAz5KHvSv8 -n2zh/0b3L8GBNAA0Jongfw3MPVQifw8MqU90CJBtD4VTJuq4HrefxNwtqv35rPwI -GUpGXrVENsPSwBvcR99o2khkE6Nka+sCWU5uHVmSJSNgxLn42vsDpNFJuzT89t+R -y88W5MdIqQn0nAX0CXaIPUuHfzOj0inMb32Ppm0uV86UUj/J4x2JOBKsV4z1rc/x -Zt7T630UWpzfydFx/JkL5V3piNRje9YUZxEnzQ9cXUJH8ajsVOiBMF8sSBtCggIZ -LrEstpKMJBwD8yhYwyQSWqCV4qg6XiD4OzfvRIxs7YFZ8nDsjBbljIZBRb7KKMcN -ZWM9J+x7M6FDsQARAQABiQI+BBgBAgAJBQJORGIIAhsuASkJEPmIpFkNsDp9wF0g -BBkBAgAGBQJORGIIAAoJEFJrCfEKo9qCJEkIALcfhN9auz6RqiJkff/zfnGNXRnl -UVoU7kmAjN4eDSwSo5AJYp8gAKn5GjhqQfmv2XPfphWLt/q3xNJKrbnJ//WM0I7Z -4yht8taR8LCW7gSvtO0t3fUYofAw2OHsIdSTuRgtR5kpspbT9PA+nEY1YFvNVhUG -LyAwZD9z1v9az/8nLWKikEJaYHTNzm0DVKybLERn6GqJG7dGO+Y+DuXCA5kQnCUC -DIy7JX0oM918HSagh17MpztS1Fadnb9hMSVjLoVd3UlT6yPbNXXYFX6MK/XJnbCw -QP8Fw1Iq4gT0AnH/wsinS6eaP7XKepXAzwlz5HpkFoPOEC1otnyjtWN3DN/3uAf/ -fFIzXJ7cB07KaoL4ohypM3Ibpkx2tvUr1E67YqKlHFRJVGLXIamu75jo5HWMcqLQ -cMgkLONgsdU/eyBhQkbKpDg5wK3Jt2eGbD3cWOgQk+jd2u5MrYlDPanB3vWIUajH -4hMnda84WJ0w2jYBV5r38mhLXYnRCuKfEKY1P5edB7FigqXY38nB1YnJY1g6FeSh -C+05mQDLfUtyq145+EfpPgk/MufNkktdkmbLsBcOC/l8rJQkmuUX1+BsmPM/XtLo -D8KDE9F83UA2GiLccW/nAtUzEPQkx1G1/RLRrdhHGi0Qjpagg6UEocbVtVS2u5FX -Hb6n8CtnCz80WDJxUTM/og== -=sUBS ------END PGP PUBLIC KEY BLOCK----- -----BEGIN PGP PRIVATE KEY BLOCK----- -Version: GnuPG/MacGPG2 v2.0.17 (Darwin) -Comment: GPGTools - http://gpgtools.org +Comment: GPGTools Test Key 2 (0DB03A7D) lQOYBE5EYggBCADmanTuJWEAyEWh90eSrrNIEYKLe922pwmVKhJCCXbnbfV00+cb hrg92Dvt3o7QlpF9CssMausWfqycpjNrMKYZXfnH4ToMTnl2TBNav6A1SMkPGj82 @@ -101,3 +62,114 @@ WDoV5KEL7TmZAMt9S3KrXjn4R+k+CT8y582SS12SZsuwFw4L+XyslCSa5RfX4GyY VLa7kVcdvqfwK2cLPzRYMnFRMz+i =Jf/Z -----END PGP PRIVATE KEY BLOCK----- + + +-----BEGIN PGP PRIVATE KEY BLOCK----- +Comment: GPGTools Test Key 2 (274090B4) + +lQc+BFWj7LkBEAC/SpWTtzltRMUKK5VtbNdTHvKKGkQDBsEn79MWBH+a38FePjGA +O0eN3dgLj9NUeBwbQ0FwuHbgYSgB9FoliYvEZMLwonIAVegxIovKaalP7g2FsJXM +IatzHypqI9f4E7cfTyeTu+EX0eS2L1z50btjNwubnZxbzcyWaLZfk+PhFNSW1n+b +Vq7pTiH4X8M9XDa3SynDSzmkgOVo7JVZlCcRvHYMhBloRz+NMyqQcpaHfQmydGZq +9zu1QN28ebz/Xu3zXqHZeQT81x92Ist53h5a7MIYt8laDxCtXLz4gLzjjIhQ3//W +NA14Y3n7urMgaZaxH7nPqimcOQN8CS5zgPfdVZ2Yuxy0Z3IK7csi3sa/658zS47b +mUn28X8AQrGdY9HsTxGvNl91zDLdsEjk9yj/Ss9XKzn281LYBmUxyhKeepprewjR +ZRYsc2i9gAyPPtgXoma2wOEbqxPF06GBWqSnH1kCYwWoMP6BBiYnCDAE4226T8Rr +/zSNldjDzvCs2cHCysFiOah79NQcDWMckkNnLBcAmkToQrgVGk/S3G9FoLfY85sV +fBb2wV18n0+XGq9VRpi+569XjH6aT1XrRuHY7CgOydcb1hfrULdcCoR5yxByYbXS +IzQ6oZaHEMomcDF5Jwtpr7du92TFKxbcq8Bi/KLeZEPb/Ef7dmsFuysjnQARAQAB +/gMDAr5kJBg1/E9Q4enx0nRZ7jRXFe/Dy3X4Cl6UKotKpbBO5055OOwUwaYpakVj +rQuTNHnKmUOQaKR2JN9aYNMkuHdKxJB15Qc2T18t+0Wq+RtFStguD6AYSbm6yYa1 +FKV3zGtV90zXwWlOnhwI0eLvdA07NIwC6xDczDKxyvDcgTGAB0yYv6zFldxdeD2e +KzVBDemshPWuuHo8s7t6WbgxIC+eyZ8HxCTW+LlEb+LrPdkC9JFfJ3WeN7QOLdJb +o9mBaahPf7B3f5VAJseu05w4K3v10V6uH5qR/aVoC8tNN2+Qv00K9vQRMIYHIw2m +WOLtqeNd8DLXCgbuN/PCsCiYh3i1RYb8MT4/KlVV7IhyAqG70ibH4+EB+epoJURO +46PWfTZ7s5wx7htQYAEHbZ9O3UXEN9gwGapsavSumFmgMq1LhY3NwApq+MdNvNaY +5e8jxX6EbmYX9+p8lHF4hyfXADyzMucpLTNig5A9bnLXyHbmsNT/MH/U5zkySN5p +IscLaTlduaXGkETj7vvlbrvjCPoeqYmTvAxMIejU7Omy0mVnmCr1/ZyHLCq7516n +XLYWr8ZkJcDR4StO+l8U45RBBC+7ldSHYVC7kes0AdMJAwE7YPt0MmYIjhog/osq +9eikoGpBiZv07vs9uWzYHy66xzhevzvDpIeSJo4aOLLNy7DNc7hqh64GthA06ylg +9HvIxHRgi6tGtJjDRSAPcuqgMmD3oydBF1E4cRdAWeD1wXGtlCFlzC+kDwUG3pgx +vhXL+8C0wQzWRoHDcAztz4bc4zMq4G1PYsjZe9AP+SQQfn/Rc2HdU8+Jn4avI79i +nUfroJ2TNTfZu863yj1nEWF0+AFhd5PV5OlZD6NXsXLNzhU0fDr+YT3xb2xgCi/J +yzBK9DmASfmPK+E4Gtc5ejacJjMDZt4ap9zsPCCcMMhWa7YO1l2MA+hFtYWPfNOm +P0i+EfqZLEOHK70W5CmI/Uh6LSFahFBwy0HFlD9Ck3qLNHpZKxMRdLxnETyvrPbo +4xL32gaQv6kt2TCOMFrHuF3KBoYdgeIki3csea/A2iAQsru07QQEhzg/S096CRKQ +jRtgZVnv6xYGytnd1JQAhCUEar+GerqAoDvo3LD/tEQI1SU5CPD00R01WLoTIb18 +RiY4gXqky+iLxrhxEPUpSR5GHAI7oZNbOkKFmF1kpX08ZDAHnJmewQW2SlrKaHSI +4xbv33E1D3WwymDSZv4HBro5VcHxT8OIFzsTpGKzbaegNVVShlDlomlBxudmkwCm +LWyfwiO/EHfv5QE3H6ONKG3YyY1ggfhlY3QDOzRxvMY4hf6qZ2L/XWULEvqzbCsw +6041gO6ld7mBrlAtDK7YoIEHPP14ffMBGANcoScc9W1Ae/SIPlqqpUqfDdB0hXG7 +Nd+xpsMSvO+B+ad7fjKZvlVKfl8JroAT0IguIKn3ZvpjHUFFhZO7ouV1DlvXckDX +DtXb/A78+OnJwVydf0h/8bzTCxCAnltFlyT1xRsc+REbi6iNyTtLrjueJbDUei53 +ILhMFcQURBkn0j4tOW0xi7MCtaVg7y4O3wC0ZETBGNwxq/hVv8eapUouBpgPngNs +7pcA5HaLHG5+9SPEt7vytS702K5ZvG45MGeYvmUbIXMynn92Nx346z+oDbfLvhZM +s6njxsNzPFV/0MOa6ScqyXU/F17h9sys7drOhZphc7OOHwYagWbzD4bxTsAMrTsP +aqLXky9G9cBCLjVhI1aGJb7VSLdTnkDSE7fj6Is3LN7+tEVHUEdUb29scyBUZXN0 +IEtleSAyIChGb3IgdGVzdGluZyBwdXJwb3NlcyBvbmx5ISBQYXNzcGhyYXNlIGlz +ICIxMjMiLimJAjcEEwEKACEFAlWj7LkCGwMFCwkIBwMFFQoJCAsFFgIDAQACHgEC +F4AACgkQ//YwBidAkLROQA/+MxftfeNClxCJwsnfvp/raSl8wtLV2640HOoplFyf +85a6I8AGw1PbxTlpjHdBDD52Lzu46eXxlLEWNDWJol8mZPWDGEsM4R4y19V8+UTN +d1eJYaD1kkfSYtolc36I7x2tRtrSsSmSTm/uvKGuxVIe5FubGCud8Wx45zkAiUe7 +K3XpKZaCY5BA3T6dKnM4q6WXSgbb4CEvjmMUfgWHtIsfijF9bU89P21MoHLxuVfU +jMjO3vDGhFDGYr23QIli530WXPFbh1TSU/VTKCa6WrjXOIdU+2Q2ql5KgJ9es/TD +GQIfFOhu7pNqMW/MazBMQv9HTqlV0FRl3zGfWFhJQgZ5zZh/0nOgN95okgGpOZL4 +Q+t1pYdF4s6jhhFLKNZiMRY8eqYAH4MGNhDldHT9C2Qr6BegyHgCeTfl24JE4o9q +nIcQiMseHEYdVWioGusoov8Zp7aICrPphppwFncOTsp4/8AiSg2OaSQ4SigpFkWo +6EFAOYc6a9MTSqJjd9yEKJDANzOyfem/ebBFVUJPZkNKv3S2RXG0SP6V7ZnWi4nu +jHt8w8lQxP/74LRcslUcKZ5iuxtyL36OKwx2W271kdSbTG1TiTD/TFZLTRzeYV+W +RdY3HbTiYEit05v4YQTC9tNk9sWkQ/rRDJu5SYTiC32fYCgFZo61/OD7Yjg1SHn+ +VnydBz0EVaPsuQEQANrkXTTFojLNPQCE8kA//XmGMCtMZfcYnPPRIAWMA/H+PhZX +QWFJApMB55JUiL7hyZ5opwduO/miqA1cu6E32gVtiLVqz/Fa7lIvjPBoaLLBmPIe +PpMBjGkPYmyxFMAUMLKVKp0DeFBLH6bEL1MGxw9rJH1U+l0IbWpB4MOciMuk1oyV +K0HivV8ePPZDslhuNSHq1H76ukg7JoDwv4kNlx5p3WCaPlr9RMtsFfdEdHAd+L6s +tqBlUbK2Ni4ipEPN9X8+N4w68ju9yW/FjvG8MFkU+NqKGkqjYDPdEUIfkU5NglDb +Z6PbyQ0SIwfgnWyrfx6K1F8QGlImTsozS4o6ZT/hXQvRQg7YSjzUqM2LECxS6hu3 +i5UFALuXu+wgJxIN77XPLkCoj+gdB24cZAXP8fVF6fQo0zKKLDUF4meFKOnpPaXp +WFx/OWAWorNaY0zgktBLMUAPeCx7ds7x2Zd0jeVHppQToCm56SzpmD6bE+m1jNIM +cPM99r5UuINUU8QdK1+FRaIeESNuejwZVvGYxNnrvWRVMKZB3d2VWfrpqJ3kAdQy ++ZfZnyTuroJoa0MqoR0ADX1+Cddss+BmJfzAR6xl9USFuhY0GgyggOzT9WnJFoce +VzzYvS544AxbhnPEJestW5TqHDPgif3k5AExJHfFphRCdmrXeKsizzCMqVLBABEB +AAH+AwMCvmQkGDX8T1DhlAhs7QpFBJr9ZdQgS4/WrToklGQghaeK6gf4mzWq9HeJ +2exnrSq55yiwc27K36AvuIyxMG7+iUHbpgR5IbjgLPatkZmcgKUsCc30sU4ldLw9 +5avUZqe/wKJS90sWZwKmcIhqhdMRX3PUKqzPh8fb0iQB3AktJZkh8D1cIqZwapLg +wtwGmcZzDb3EEZTtjrXszh/b8rqSYwTvLjimQlDHM6WKkAy+FtR7Xnog14vjhtWc +5pl/IxgBLDFfXjA3N1MtiNZX9jqve/MM2EWmqYODhn4nllfNzGhosackI2ubrzBA +gb4xmcVDOtuxzDJwY9jAwaqUbmsVyv2YzoEiDce6dX6Ymssd54YMLVitRy1/e2a1 +DtlsMfBiTzmsHvz1xw1zSfs55yBLXmGavTMpHLcCkJHij5S7SfDPDklWJjKWhB+6 +nBO/8GX/8xIKTji8ooJ2ev3NUFqWDV2YqfOfwY5xVWp982WNM2tXDaqfvL+e4X3Y +iNOmfmr9GwkPOybwB7qu28XneMJUy7/hEC27cbZb3DZGemGszGvrMAmbsrhbPuHQ +dipKUFWDDoJO4kLzqAzRn2FsY3BEX62QRsV0nff/G13/dkRuH/uRKEUC6kiRbR02 +OPx49oPdYpAEkFdkWcRzqFMo8W7rtfIvmrZfDpxLBtQkeJZJHFrFOtWO9XJiGYYN +nN1L12mmjCaOr4ATviVn2pWlQ6aQEFl6YRbHp8ufBoZH50GXYPaDbtOiqiO5tARW +zyJqDQoVIhIgRJc75Gjolk1QwiFqNKfd31cjMFgqipU7c0IlvEtJ0puRVdaGbjek +F8YSkwvkszh9XcxgMDm6xm4x4w1e2ZFFolepNAMKSGEcP2KOALtDtLZ56wLdMJqX +x0BTUxIKT9TY9PoHitdz+KafZzNRpzfHWNCBC6g+yc/jjDd6HPQHy2K0KXvxjpx4 +J6HtrXsjllB6lph/9biCaYLyDBPtb8oLtgdnbnuITChCOtjcjHY1BoKFpV+mV3X6 +bk5tY0kbTNSnaDizxI2Mmqr9SEBZjg6wPA2eRiyaGtacJSSKcI+DcJllmPB/2dUU +5pxNreid0iFfwU74VK5Pr8ameZcSwReOki3i09b+PzE/TBaDylDYy3IQuzt11c8B +RfG95PMKVyDB1Np6rO/CuYjAtLaWHrTYfYM/ARjH4Qr/mVlYsA0ICRUFKcqPDyYp +46SaoOgfeNCDTKzDqGuMMrGYE9idt8cMuJuA0DwENvBtKP5+ky9Z+eWkmS+Ix/4c +B6uJLai/fOFPYVXxf5SNxmSGOIU2L8672qq2aPs8VkkZLLBQ423gHeyHSK2wrknd +2KOteXUJkpTxuQjJVYNJpBYbhfh38DjNHvP37M+rUTT9+mWhMeNMJwrMSMcIriCc +8uqFCr+eRVlQ7Abfatg6umHnUoSp4MIutvdiITtIJfp13nlafmCzvFW3dPlK9lOL +xNCjsUn2rxF6nQL7LdxJ5dTO98xtgSq1pU9rResdVsub4y47DdO9qLDJcsCTQYXi +WEwbr3pcTWN7Ed3NaYZrmQAX27ICWiGz3q+w3qJe5GP9CtucmPideXlkLakDygwK +vJ+s/Kv6TLyapkpgdVwu4DhCEY64xRFF91N6Qohj8/Ytzrn0EnJhcOsRWEOK1qE8 +Lx8F8XJpocP24qVjVlwChrK2XQpVsiRjYA+5yHqlWMC+xk/nVynNBhn9rSMlYKD5 +N2UDcG0xGkHr3Fjpzxujlvyjn2W2FHOCIuuvVoNGyD7ARokCHwQYAQoACQUCVaPs +uQIbDAAKCRD/9jAGJ0CQtBGMD/0QAsGLcdRpXKGNzUbO4yoDiezWKzFLDqGrV0HQ +qtzCnvDBQnP2shrqqFhcTa2o3IEbhbV8urywlUL3cmOlSu3LXCutBicte7Dl7Kzr +yda/nxPX1GFLzo1pJz+nvCKYYQ3u57lIw6oXno2hOtcKRMKPCKUNSU3f4MYN0xLV +KsDuYN8AT8to+vq0fGyqvJPeXJXa28Q2ymfy7JHMm8sJ34mcMJl/MnL20bI70lgo +Re1Fn6Lschr4FNAswA9lDD1SAD0yYtCUSNocG1ApfjszpcGDY6NwRHUiDAxHD79X +WU4lNtn0CpmG3RxLxkRN3lFov78681f4BlDWjPBdyNY5fs1lj/yefydgUuZCXtZe +RnUyKBx/fHcTQ1OfHZPNyFblvKHWuZ/npKpCQigesfv3JHyH0z3VUdWdPbOTC+Vs +rJlkZ4kguXEwRr5T/hUWVn017HBcbP2wy/1meltCt+UUXM/CHFkdvM+af5fZIQZf +GSX3auDUgluJFFwZ/rMxBkbJspOd87AGEVhuj/qZCK0RDsGwNT9bnyBynGEEooAL +07+sTKkpdLwZKp92fzq+N3W/DNy4wlN8jqfUpTWzbakd1qBzckWbir4Z27U5RyqD +3k7MSoj34G99LesvtnNmSNJre1KTYIB4gfAVgOmpJS5cLinp2W2vhD5ckLaIAn3H +zBOuYA== +=fx79 +-----END PGP PRIVATE KEY BLOCK----- + diff --git a/UnitTest/Test1.h b/UnitTest/Test1.h deleted file mode 100644 index b86e787..0000000 --- a/UnitTest/Test1.h +++ /dev/null @@ -1,11 +0,0 @@ -#import - -@class GPGController; - -@interface Test1 : SenTestCase { - GPGController *gpgc; - NSString *tempDir; - NSUInteger confTouches; -} -- (void)logDataContent:(NSData *)data message:(NSString *)message; -@end diff --git a/UnitTest/Test1.m b/UnitTest/Test1.m deleted file mode 100644 index e63dc23..0000000 --- a/UnitTest/Test1.m +++ /dev/null @@ -1,206 +0,0 @@ -#import "Test1.h" -#import -#import "LPXTTask.h" -#include -#include -#include "GPGStdSetting.h" -#import "GPGWatcher.h" -#import "NSRunLoop+TimeOutAndFlag.h" - -#define BDSKSpecialPipeServiceRunLoopMode @"BDSKSpecialPipeServiceRunLoopMode" - -static NSString *skelconf = @"/usr/local/MacGPG2/share/gnupg/gpg-conf.skel"; - -@interface Test1 () -- (void)confHasChanged:(id)sender; -- (void)touchGpgConf:(id)sender; -@end - -@implementation Test1 - -- (void)setUp { - gpgc = [[GPGController alloc] init]; - char tempPath[] = "/tmp/Libmacgpg_UnitTest-XXXXXX"; - tempDir = [NSString stringWithUTF8String:mkdtemp(tempPath)]; - NSFileManager *fileManager = [NSFileManager defaultManager]; - BOOL isDirectory; - if (!([fileManager fileExistsAtPath:tempDir isDirectory:&isDirectory] && isDirectory)) { - tempDir = nil; - [NSException raise:@"Error" format:@"Can’t create temporary diretory."]; - } - gpgc.gpgHome = tempDir; -} - -- (void)tearDown { - // comment out to preserve temp directory - if (tempDir) { - NSFileManager *fileManager = [NSFileManager defaultManager]; - [fileManager removeItemAtPath:tempDir error:nil]; - } - [gpgc release]; -} - -- (void)testGPGWatcher -{ - GPGWatcher *myWatcher = [[GPGWatcher alloc] initWithGpgHome:gpgc.gpgHome]; - myWatcher.toleranceBefore = 0; - myWatcher.toleranceAfter = 0; - - [[NSDistributedNotificationCenter defaultCenter] - addObserver:self selector:@selector(confHasChanged:) name:GPGConfigurationModifiedNotification object:nil]; - - NSTimer *touchTimer = [NSTimer timerWithTimeInterval:1. - target:self selector:@selector(touchGpgConf:) userInfo:nil repeats:NO]; - [[NSRunLoop currentRunLoop] addTimer:touchTimer forMode:NSDefaultRunLoopMode]; - - BOOL finishedFlag = NO; - // GPGWatcher sets a latency of 5, so wait 7 - [[NSRunLoop currentRunLoop] runUntilTimeout:7 orFinishedFlag:&finishedFlag]; - - STAssertTrue(confTouches > 0, @"GPGConfigurationModifiedNotification was not raised!"); - [myWatcher release]; -} - -- (void)confHasChanged:(id)sender { - ++confTouches; -} - -- (void)touchGpgConf:(id)sender { - NSString *touchCmd = [NSString stringWithFormat:@"touch \"%@/gpg.conf\"", gpgc.gpgHome]; - system([touchCmd UTF8String]); -} - -- (void)testTimeout { - NSLog(@"Dispatch QUICK: %lld", GPGTASKHELPER_DISPATCH_TIMEOUT_QUICKLY); - gpgc.timeout = GPGTASKHELPER_DISPATCH_TIMEOUT_QUICKLY; - NSSet *keys = [gpgc allKeys]; - NSLog(@"Keys: %@", keys); - - STAssertTrue(keys.count == 0, @"Timeout was not quick enough"); -} - -- (void)testCase1 { - STAssertNotNil(gpgc, @"Can’t init GPGController."); - - NSSet *keys = [gpgc allKeys]; - STAssertTrue(keys != nil && [keys count] == 0, @"Can’t list keys."); - - NSString *testKey_name = @"Test Key"; - NSString *testKey_email = @"nomail@example.com"; - NSString *testKey_comment = @""; - - [gpgc generateNewKeyWithName:testKey_name email:testKey_email comment:testKey_comment keyType:1 keyLength:1024 subkeyType:1 subkeyLength:1024 daysToExpire:5 preferences:nil passphrase:@""]; - keys = [gpgc allKeys]; - STAssertTrue([keys count] == 1, @"Can’t generate key."); - - GPGKey *key = [keys anyObject]; - STAssertTrue([key.name isEqualToString:testKey_name] && [key.email isEqualToString:testKey_email], @"Generate key faild."); - - NSString *keyID = key.keyID; - - NSData *input = [@"This is a test text." dataUsingEncoding:NSUTF8StringEncoding]; - NSData *output = [gpgc processData:input withEncryptSignMode:GPGEncryptSign recipients:[NSSet setWithObject:keyID] hiddenRecipients:nil]; - STAssertNotNil(output, @"processData faild."); - STAssertTrue(![input isEqualToData:output], @"Signing did not produce different data!"); - - NSData *decryptedData = [gpgc decryptData:output]; - STAssertNotNil(decryptedData, @"decryptData failed."); - STAssertTrue([decryptedData isEqualToData:input], @"Round-trip sign/unsign failed!"); -} - -- (void)logDataContent:(NSData *)data message:(NSString *)message { - NSString *tmpString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; - printf("[DEBUG] %s: %s >>\n", [message UTF8String], [tmpString UTF8String]); - [tmpString release]; -} - -- (void)stdoutNowAvailable:(NSNotification *)notification { - //NSData *outputData = [[notification userInfo] objectForKey:NSFileHandleNotificationDataItem]; - NSFileHandle *fh = [notification object]; - - //if ([outputData length]) - // stdoutData = [outputData retain]; - [self logDataContent:[fh availableData] message:@"GO FUCK THIS"]; - [fh waitForDataInBackgroundAndNotify]; -} - - - -- (void)testGPGConfGetContents { - GPGConf *conf = [[GPGConf alloc] initWithPath:skelconf andDomain:GPGDomain_gpgConf]; - - NSError *error = nil; - NSString *skelContents = [NSString stringWithContentsOfFile:skelconf usedEncoding:nil error:&error]; - STAssertNotNil(skelContents, @"Unexpectedly nil!"); - NSString *reencoded = [conf getContents]; - STAssertEquals([skelContents length], [reencoded length], @"Content length mis-match!"); - STAssertEqualObjects(skelContents, reencoded, @"GPGConf did not round-trip contents!"); -} - -- (void)testGPGConfAlterContents { - // Disabled because it doesn't work on the BuildBot. - return; - GPGConf *conf = [[GPGConf alloc] initWithPath:skelconf andDomain:GPGDomain_gpgConf]; - - NSError *error = nil; - NSString *skelContents = [NSString stringWithContentsOfFile:skelconf usedEncoding:nil error:&error]; - STAssertNotNil(skelContents, @"Unexpectedly nil!"); - - [conf setValue:[NSNumber numberWithBool:TRUE] forKey:@"greeting"]; - NSString *reencoded = [conf getContents]; - NSString *gpath = [tempDir stringByAppendingPathComponent:@"gpg-testing.conf"]; - [reencoded writeToFile:gpath atomically:YES encoding:NSUTF8StringEncoding error:&error]; - STAssertNil(error, @"writeToFile unexpectedly failed!"); - - NSTask *task; - task = [[NSTask alloc] init]; - [task setLaunchPath: @"/usr/bin/diff"]; - - NSArray *arguments; - arguments = [NSArray arrayWithObjects: skelconf, gpath, nil]; - [task setArguments: arguments]; - - NSPipe *pipe; - pipe = [NSPipe pipe]; - [task setStandardOutput: pipe]; - - NSFileHandle *file; - file = [pipe fileHandleForReading]; - - [task launch]; - - NSData *data; - data = [file readDataToEndOfFile]; - - NSString *diffout; - diffout = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding]; - printf("diff returned:\n%s\n", [diffout UTF8String]); - NSString *expected = @"28c28\n< #no-greeting\n---\n> greeting\n"; - STAssertEqualObjects(expected, diffout, @"Diff not as expected!"); - - [diffout release]; - [task release]; -} - -//- (void)stdoutNowAvailable:(NSNotification *)notification { -// NSLog(@"Data coming in..."); -// NSLog(@"Notification: %@", notification); -//// NSFileHandle *fileHandle = (NSFileHandle*) [notification -//// object]; -// NSData *outputData = [[notification userInfo] objectForKey:NSFileHandleNotificationDataItem]; -// [self logDataContent:outputData message:@"Available Data"]; -// //[fileHandle waitForDataInBackgroundAndNotifyForModes:[NSArray arrayWithObject:BDSKSpecialPipeServiceRunLoopMode]]; -//} - -@end - -/* - STAssertNotNil(a1, description, ...) - STAssertTrue(expression, description, ...) - STAssertFalse(expression, description, ...) - STAssertEqualObjects(a1, a2, description, ...) - STAssertEquals(a1, a2, description, ...) - STAssertThrows(expression, description, ...) - STAssertNoThrow(expression, description, ...) - STFail(description, ...) -*/ diff --git a/UnitTests/GPGUnitTest.h b/UnitTests/GPGUnitTest.h new file mode 100644 index 0000000..71ccc9b --- /dev/null +++ b/UnitTests/GPGUnitTest.h @@ -0,0 +1,19 @@ +#import +#import "Libmacgpg.h" + + +extern NSString *testKey; +extern NSString *testKey2; +extern NSString *testSubkey; +extern NSString *unitTestHome; + +extern GPGController *gpgc; +extern GPGKeyManager *manager; + + +@interface GPGUnitTest : NSObject + ++ (void)setUpTestDirectory; ++ (NSData *)dataForResource:(NSString *)name; + +@end diff --git a/UnitTests/GPGUnitTest.m b/UnitTests/GPGUnitTest.m new file mode 100644 index 0000000..8ce8bc6 --- /dev/null +++ b/UnitTests/GPGUnitTest.m @@ -0,0 +1,53 @@ +#import "GPGUnitTest.h" + +NSString *testKey = @"77270A31BEE39087C6B7E771F988A4590DB03A7D"; +NSString *testKey2 = @"672730F976B5D34B21FE47EBFFF63006274090B4"; +NSString *testSubkey = @"30BD46FC8599CB334466CFC5526B09F10AA3DA82"; +NSString *unitTestHome = @"/tmp/Libmacgpg_UnitTest"; +GPGController *gpgc = nil; +GPGKeyManager *manager = nil; + + + +@implementation GPGUnitTest + ++ (void)setUpTestDirectory { + static BOOL didSetUp = NO; + + if (!didSetUp) { + didSetUp = YES; + + NSFileManager *fileManager = [NSFileManager defaultManager]; + BOOL isDirectory; + + if ([fileManager fileExistsAtPath:unitTestHome isDirectory:&isDirectory] && isDirectory) { + [fileManager removeItemAtPath:unitTestHome error:nil]; + } + [fileManager createDirectoryAtPath:unitTestHome withIntermediateDirectories:NO attributes:nil error:nil]; + + + manager = [GPGKeyManager sharedInstance]; + manager.homedir = unitTestHome; + + gpgc = [[GPGController alloc] init]; + gpgc.gpgHome = unitTestHome; + + NSData *data = [self dataForResource:@"OpenPGP.asc"]; + [gpgc importFromData:data fullImport:TRUE]; + } +} + ++ (NSData *)dataForResource:(NSString *)name { + NSBundle *unitTestBundle = [NSBundle bundleForClass:[self class]]; + NSString *path = [unitTestBundle pathForResource:name ofType:@""]; + NSData *data = [NSData dataWithContentsOfFile:path]; + if (!data) { + @throw [NSException exceptionWithName:@"ApplicationException" reason:@"missing resource" userInfo:nil]; + } + return data; +} + + +@end + + diff --git a/NewUnitTests/Info.plist b/UnitTests/Info.plist similarity index 100% rename from NewUnitTests/Info.plist rename to UnitTests/Info.plist From 96b63ccbb159767d86d5bb9f44a0e8a0b6c35203 Mon Sep 17 00:00:00 2001 From: Mento Date: Tue, 14 Jul 2015 14:03:23 +0200 Subject: [PATCH 33/56] GPGPacket commented. --- Source/GPGPacket/GPGCompressedDataPacket.h | 4 + Source/GPGPacket/GPGCompressedDataPacket.m | 62 ++++++-- Source/GPGPacket/GPGIgnoredPackets.h | 3 + Source/GPGPacket/GPGKeyMaterialPacket.h | 3 + Source/GPGPacket/GPGKeyMaterialPacket.m | 35 +++-- Source/GPGPacket/GPGLiteralDataPacket.h | 3 + Source/GPGPacket/GPGLiteralDataPacket.m | 14 +- Source/GPGPacket/GPGOnePassSignaturePacket.h | 6 + Source/GPGPacket/GPGOnePassSignaturePacket.m | 2 +- Source/GPGPacket/GPGPacket.h | 9 +- Source/GPGPacket/GPGPacket.m | 2 + Source/GPGPacket/GPGPacketParser.m | 135 +++++++++++++----- Source/GPGPacket/GPGPacket_Private.h | 4 +- .../GPGPublicKeyEncryptedSessionKeyPacket.m | 1 + Source/GPGPacket/GPGSignaturePacket.h | 15 ++ Source/GPGPacket/GPGSignaturePacket.m | 14 +- .../GPGSymmetricEncryptedSessionKeyPacket.h | 3 + Source/GPGPacket/GPGUserAttributePacket.m | 25 +++- 18 files changed, 257 insertions(+), 83 deletions(-) diff --git a/Source/GPGPacket/GPGCompressedDataPacket.h b/Source/GPGPacket/GPGCompressedDataPacket.h index 94387fc..0daaeea 100644 --- a/Source/GPGPacket/GPGCompressedDataPacket.h +++ b/Source/GPGPacket/GPGCompressedDataPacket.h @@ -23,6 +23,10 @@ @class GPGPacketParser, GPGDecompressStream; +/** + This packet is normally only used by GPGPacketParser. + Use GPGPacketParser to get it's content. + */ @interface GPGCompressedDataPacket : GPGPacket { NSInteger compressAlgorithm; GPGDecompressStream *decompressStream; diff --git a/Source/GPGPacket/GPGCompressedDataPacket.m b/Source/GPGPacket/GPGCompressedDataPacket.m index 2b62535..2aac1e6 100644 --- a/Source/GPGPacket/GPGCompressedDataPacket.m +++ b/Source/GPGPacket/GPGCompressedDataPacket.m @@ -28,7 +28,7 @@ Based on pgpdump (https://github.com/kazu-yamamoto/pgpdump) from Kazuhiko Yamamo #import #import - +// A primitive GPGStream to read data out of compressed packets. @interface GPGDecompressStream : GPGStream { GPGPacketParser *parser; NSInteger algorithm; @@ -73,16 +73,18 @@ - (instancetype)initWithParser:(GPGPacketParser *)theParser length:(NSUInteger)l length--; switch (compressAlgorithm) { - case 0: - case 1: - case 2: - case 3: + case 0: // Uncompressed. Why should this happen? + case 1: // ZIP [RFC1951] + case 2: // ZLIB [RFC1950] + case 3: // BZip2 break; default: + // Unknown/invalid compression algorithm. [theParser skip:length]; return self; } + // The GPGDecompressStream will be given to a new GPGPacketParser, to decode the packets inside of this packet. self.decompressStream = [[GPGDecompressStream alloc] initWithParser:theParser length:length algorithm:compressAlgorithm]; if (decompressStream) { self.subParser = [[GPGPacketParser alloc] initWithStream:self.decompressStream]; @@ -92,6 +94,7 @@ - (instancetype)initWithParser:(GPGPacketParser *)theParser length:(NSUInteger)l } - (GPGPacket *)nextPacket { + // Return the next decompressed packet. GPGPacket *packet = [subParser nextPacket]; if (!packet) { self.decompressStream = nil; @@ -101,6 +104,7 @@ - (GPGPacket *)nextPacket { } - (BOOL)canDecompress { + // Indicate if we are able to decompress this packet. return !!subParser; } @@ -142,8 +146,8 @@ - (instancetype)initWithParser:(GPGPacketParser *)theParser length:(NSUInteger)l inputData = [[NSMutableData alloc] initWithLength:cacheSize]; cacheData = [[NSMutableData alloc] initWithLength:cacheSize]; + // Initialize the right decompression engine. int status = 0; - switch (algorithm) { case 0: // No compresseion. @@ -151,44 +155,56 @@ - (instancetype)initWithParser:(GPGPacketParser *)theParser length:(NSUInteger)l inputData = [cacheData retain]; break; case 1: + // ZIP (zlib with another init) status = inflateInit2(&zStream, -13); break; case 2: + // ZLIB status = inflateInit(&zStream); break; case 3: + // BZip2 status = BZ2_bzDecompressInit(&bzStream, 0, 0); break; } if (status != 0) { + // Something went wrong. [self release]; return nil; } inputBytes = inputData.mutableBytes; cacheBytes = cacheData.mutableBytes; - return self; } - (void)fillInput { + // Read up to cacheSize bytes and store it in inputBytes. + inputSize = 0; if (packetLength != 0) { for (; inputSize < cacheSize; inputSize++) { + // Read a byte. NSInteger byte = parser.byteOrEOF; if (byte == EOF) { break; } + // Store it in inputBytes. inputBytes[inputSize] = (UInt8)byte; availablePacketBytes--; + if (availablePacketBytes == 0) { + // We have reached the end of this packet/part. + if (parser.partial) { + // It's a partial packet, we have to read the next part. packetLength = parser.nextPartialLength; availablePacketBytes = packetLength; } else { + // It's a normal packet, so we are really at the end. packetLength = 0; } if (packetLength == 0) { @@ -202,6 +218,9 @@ - (void)fillInput { } - (BOOL)zlibFillCache { + // Fill our cache by decompressing using zlib. + + // Let zlib write directly in our cache. zStream.avail_out = cacheSize; zStream.next_out = cacheBytes; @@ -213,26 +232,30 @@ - (BOOL)zlibFillCache { zStream.next_in = inputBytes; } - + // Decompress. int status = inflate(&zStream, Z_SYNC_FLUSH); if (status != Z_OK) { inflateEnd(&zStream); streamEnd = YES; if (status != Z_STREAM_END) { + // Something went wrong. return NO; } } } while (zStream.avail_out == cacheSize); - + // Calculate number of bytes in cache. cacheAvailableBytes = cacheSize - zStream.avail_out; return YES; } - (BOOL)bzFillCache { + // Fill our cache by decompressing using bzip2. + + // Let bzip2 write directly in our cache. bzStream.avail_out = cacheSize; bzStream.next_out = (char *)cacheBytes; @@ -244,12 +267,14 @@ - (BOOL)bzFillCache { bzStream.next_in = (char *)inputBytes; } + // Decompress. int status = BZ2_bzDecompress(&bzStream); if (status != BZ_OK) { BZ2_bzDecompressEnd(&bzStream); streamEnd = YES; if (status != BZ_STREAM_END) { + // Something went wrong. return NO; } } @@ -257,12 +282,16 @@ - (BOOL)bzFillCache { } while (bzStream.avail_out == cacheSize); + // Calculate number of bytes in cache. cacheAvailableBytes = cacheSize - bzStream.avail_out; return YES; } - (BOOL)uncompressedFillCache { + // inputData and cacheData are the same, so we have simply to fill the input, + // and set the number of bytes in cache to inputSize. + [self fillInput]; if (inputSize == 0) { @@ -275,14 +304,20 @@ - (BOOL)uncompressedFillCache { } - (NSInteger)readByte { - if (cacheAvailableBytes == 0) { + // Read the next byte from the cache. + // Refill the cache if empty. + + if (cacheAvailableBytes == 0) { // Cache is emtpy. + if (streamEnd) { + // We have already reached the end of the stream. return EOF; } - cacheLocation = 0; + cacheLocation = 0; // Reset the cache read "pointer". - BOOL moreData = NO; + // Fill the cache. + BOOL moreData = NO; switch (algorithm) { case 0: moreData = [self uncompressedFillCache]; @@ -295,7 +330,10 @@ - (NSInteger)readByte { moreData = [self bzFillCache]; break; } + if (streamEnd) { + // We have reached the end of the stream. + // Release the parser to prevent a retain cycle. [parser release]; parser = nil; } diff --git a/Source/GPGPacket/GPGIgnoredPackets.h b/Source/GPGPacket/GPGIgnoredPackets.h index d26b92f..28f4ef0 100644 --- a/Source/GPGPacket/GPGIgnoredPackets.h +++ b/Source/GPGPacket/GPGIgnoredPackets.h @@ -21,6 +21,9 @@ #import + +// Ignore the content of these packets. +// Still use a real subclass and report the right tag. @interface GPGIgnoredPacket : GPGPacket @end diff --git a/Source/GPGPacket/GPGKeyMaterialPacket.h b/Source/GPGPacket/GPGKeyMaterialPacket.h index a046550..3cdd7ef 100644 --- a/Source/GPGPacket/GPGKeyMaterialPacket.h +++ b/Source/GPGPacket/GPGKeyMaterialPacket.h @@ -30,6 +30,9 @@ NSString *keyID; } +/** + Public-Key Algorithm used. See: https://tools.ietf.org/html/rfc4880#section-9.1 + */ @property (nonatomic, readonly) NSInteger publicAlgorithm; @property (nonatomic, readonly) NSInteger version; @property (nonatomic, readonly) NSInteger validDays; // Only set on old keys. diff --git a/Source/GPGPacket/GPGKeyMaterialPacket.m b/Source/GPGPacket/GPGKeyMaterialPacket.m index 612a5a6..c5a72d6 100644 --- a/Source/GPGPacket/GPGKeyMaterialPacket.m +++ b/Source/GPGPacket/GPGKeyMaterialPacket.m @@ -51,14 +51,11 @@ - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)leng // Old format, deprecated and weak! self.creationDate = parser.date; - self.validDays = parser.uint16; + self.validDays = parser.uint16; // How many days the key is valid. - self.publicAlgorithm = parser.byte; // Should be 1. + self.publicAlgorithm = parser.byte; // Should be 1 (RSA). - CC_MD5_CTX md5; - CC_MD5_Init(&md5); - NSData *modulus = [parser multiPrecisionInteger]; // "RSA n" if (modulus.length >= 8) { // The Key ID is the low 64 bits of the modulus. @@ -66,15 +63,17 @@ - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)leng } NSData *exponent = [parser multiPrecisionInteger]; // "RSA e" - CC_MD5_Update(&md5, modulus.bytes, modulus.length); - CC_MD5_Update(&md5, exponent.bytes, exponent.length); - + + // The fingerprint is the MD5 of modulus and exponent. + CC_MD5_CTX md5; + CC_MD5_Init(&md5); + CC_MD5_Update(&md5, modulus.bytes, modulus.length); // Hash modulus, + CC_MD5_Update(&md5, exponent.bytes, exponent.length); // and exponent. UInt8 fingerprintBytes[16]; CC_MD5_Final(fingerprintBytes, &md5); - - // The fingerprint is the md5 hashed modulus and exponent. self.fingerprint = bytesToHexString(fingerprintBytes, 16); + break; } case 4: { @@ -92,19 +91,22 @@ - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)leng bytesToHash[3] = 4; // Version __block NSUInteger i = 4; + + // The callback get every byte read from the parser, so we can calculate the SHA1. ByteCallback callback = ^(NSInteger byte) { if (i < dataLength) { - bytesToHash[i] = (UInt8)byte; - i++; + // Append byte to bytesToHash; + bytesToHash[i++] = (UInt8)byte; } }; - + // Set the callback. parser.byteCallback = callback; self.creationDate = parser.date; self.publicAlgorithm = parser.byte; + // Ignore the MPIs. But we recognize them. switch (publicAlgorithm) { case 1: case 2: @@ -129,18 +131,23 @@ - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)leng break; } + // We have all bytes for the SHA1. Unset the callback. parser.byteCallback = nil; - // Get the fingerprint by hashing dataToHash using SHA1. + + // Get the fingerprint by hashing bytesToHash using SHA1. uint8_t fingerprintBytes[20]; CC_SHA1(bytesToHash, dataLength, fingerprintBytes); + self.fingerprint = bytesToHexString(fingerprintBytes, 20); + // The Key ID is the low 64 bits of the fingerprint. self.keyID = [fingerprint keyID]; break; } default: + // Unknown key format, ignore the content. [parser skip:length - 1]; break; } diff --git a/Source/GPGPacket/GPGLiteralDataPacket.h b/Source/GPGPacket/GPGLiteralDataPacket.h index fd34312..15d4b94 100644 --- a/Source/GPGPacket/GPGLiteralDataPacket.h +++ b/Source/GPGPacket/GPGLiteralDataPacket.h @@ -21,6 +21,9 @@ #import +/** + See: https://tools.ietf.org/html/rfc4880#section-5.9 +*/ @interface GPGLiteralDataPacket : GPGPacket { NSInteger format; NSString *filename; diff --git a/Source/GPGPacket/GPGLiteralDataPacket.m b/Source/GPGPacket/GPGLiteralDataPacket.m index 98740cd..4ba8a3d 100644 --- a/Source/GPGPacket/GPGLiteralDataPacket.m +++ b/Source/GPGPacket/GPGLiteralDataPacket.m @@ -40,19 +40,23 @@ - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)leng return nil; } + // 'b': binary, 't': text (convert line-endings), 'u': like 't' but UTF8. self.format = parser.byte; - NSUInteger len = parser.byte; - - self.filename = [parser stringWithLength:len]; + // filename could be empty. + NSUInteger filenameLength = parser.byte; + self.filename = [parser stringWithLength:filenameLength]; self.date = parser.date; - length = length - 6 - len; + + // Decrement by the number of bytes read. + length = length - 6 - filenameLength; + + // Read the content bytes of the packet. NSMutableData *tempData = [NSMutableData data]; NSUInteger i = 0; - while (length > 0) { tempData.length += length; UInt8 *bytes = tempData.mutableBytes; diff --git a/Source/GPGPacket/GPGOnePassSignaturePacket.h b/Source/GPGPacket/GPGOnePassSignaturePacket.h index 6b40c1d..df1aaf8 100644 --- a/Source/GPGPacket/GPGOnePassSignaturePacket.h +++ b/Source/GPGPacket/GPGOnePassSignaturePacket.h @@ -29,7 +29,13 @@ NSString *keyID; } +/** + Public-Key Algorithm used. See: https://tools.ietf.org/html/rfc4880#section-9.1 + */ @property (nonatomic, readonly) NSInteger publicAlgorithm; +/** + Hash Algorithm used. See: https://tools.ietf.org/html/rfc4880#section-9.4 + */ @property (nonatomic, readonly) NSInteger hashAlgorithm; @property (nonatomic, readonly) NSInteger type; @property (nonatomic, readonly) NSInteger version; diff --git a/Source/GPGPacket/GPGOnePassSignaturePacket.m b/Source/GPGPacket/GPGOnePassSignaturePacket.m index ac491f7..8db9242 100644 --- a/Source/GPGPacket/GPGOnePassSignaturePacket.m +++ b/Source/GPGPacket/GPGOnePassSignaturePacket.m @@ -46,7 +46,7 @@ - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)leng self.publicAlgorithm = parser.byte; self.keyID = parser.keyID; - [parser byte]; // Ignore (0 = the next packet is another one-pass signature) + [parser byte]; // Ignore (0 means the next packet is another one-pass signature) return self; } diff --git a/Source/GPGPacket/GPGPacket.h b/Source/GPGPacket/GPGPacket.h index 4e8603b..a648a97 100644 --- a/Source/GPGPacket/GPGPacket.h +++ b/Source/GPGPacket/GPGPacket.h @@ -19,6 +19,9 @@ 02111-1307, USA */ + + +// Every subclass of GPGPacket returns one of these tags. typedef NS_ENUM(NSInteger, GPGPacketTag) { GPGPublicKeyEncryptedSessionKeyPacketTag = 1, GPGSignaturePacketTag = 2, @@ -39,9 +42,9 @@ typedef NS_ENUM(NSInteger, GPGPacketTag) { }; - - - +/** + GPGPacket is an abstract super-class and should never be used directly. +*/ @interface GPGPacket : NSObject @property (readonly) GPGPacketTag tag; diff --git a/Source/GPGPacket/GPGPacket.m b/Source/GPGPacket/GPGPacket.m index c8dca3b..8858b39 100644 --- a/Source/GPGPacket/GPGPacket.m +++ b/Source/GPGPacket/GPGPacket.m @@ -29,6 +29,7 @@ @implementation GPGPacket +// Only placeholder methods. - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)length { return [super init]; } @@ -43,6 +44,7 @@ - (GPGPacketTag)tag { // Old methods, only for compatibility. +// They will be removed in the future. - (NSInteger)type { return self.tag; diff --git a/Source/GPGPacket/GPGPacketParser.m b/Source/GPGPacket/GPGPacketParser.m index a4766aa..7149f38 100644 --- a/Source/GPGPacket/GPGPacketParser.m +++ b/Source/GPGPacket/GPGPacketParser.m @@ -75,102 +75,127 @@ - (GPGPacket *)nextPacket { if (tempPacket) { return tempPacket; } else { + // It was the last packet in the compressed packet. + // Now we run normally to get the remaining packet, if any. self.compressedPacket = nil; } } NSInteger c = [stream readByte]; if (c == EOF) { + // We have no (more) data. self.error = nil; return nil; } if ((c & BINARY_TAG_FLAG) == 0) { + // The high-bit of the first byte MUST be 1. self.error = [NSError errorWithDomain:LibmacgpgErrorDomain code:GPGErrorInvalidData userInfo:nil]; return nil; } NSInteger tag = c & TAG_MASK; - NSUInteger len = 0; + NSUInteger length = 0; partial = NO; if (c & NEW_TAG_FLAG) { // New format. + + // Get the packet length. c = self.byte; - len = [self getNewLen:c]; + length = [self getNewLen:c]; + partial = isPartial(c); - if (partial && len < 512) { + if (partial && length < 512) { + // The first partial packet MUST be at least 512 byte long. self.error = [NSError errorWithDomain:LibmacgpgErrorDomain code:GPGErrorBadData userInfo:nil]; return nil; } } else { // Old format. - NSUInteger tlen; - tlen = c & OLD_LEN_MASK; + // The two low-bits define how the length of the packet is stored. + // So we have to shift the tag accordingly. tag >>= OLD_TAG_SHIFT; - switch (tlen) { + switch (c & OLD_LEN_MASK) { case 0: - len = self.byte; + length = self.byte; break; case 1: - len = (self.byte << 8); - len += self.byte; + length = (self.byte << 8); + length += self.byte; break; case 2: - len = self.byte << 24; - len |= self.byte << 16; - len |= self.byte << 8; - len |= self.byte; + length = self.byte << 24; + length |= self.byte << 16; + length |= self.byte << 8; + length |= self.byte; break; case 3: - len = NSUIntegerMax; + length = NSUIntegerMax; break; } } GPGPacket *packet = nil; - Class class = nil; if (tag < tagClasses.count) { - class = tagClasses[tag]; + // Get the right GPGPacket subclass for this packet. + Class class = tagClasses[tag]; + if (class == [NSNull null]) { - class = nil; - [self skip:len]; + // Reserved/unknown packet, skip it. + [self skip:length]; } else { - packetLength = len; - packet = [[[class alloc] initWithParser:self length:len] autorelease]; + // Store the packet length for skipRemaining. + packetLength = length; + + // The packet content is parsed in -initWithParser:length:. + packet = [[[class alloc] initWithParser:self length:length] autorelease]; + if (tag == TAG_COMPRESSED && [(GPGCompressedDataPacket *)packet canDecompress]) { + // We have a compressed packet, we are able to decompress. + + // Store a reference for the next run of [self nextPacket]. self.compressedPacket = (GPGCompressedDataPacket *)packet; + // Get the first packet inside of the compressed packet. GPGPacket *tempPacket = [compressedPacket nextPacket]; if (tempPacket) { return tempPacket; } else { + // We don't have any packet inside, + // return the GPGCompressedDataPacket itself. self.compressedPacket = nil; } } } } else { - [self skip:len]; + // Skip unknown packets. + [self skip:length]; } + // Skip remaining data of a partial packet. while (partial == YES) { c = self.byte; - len = [self getNewLen:c]; + length = [self getNewLen:c]; partial = isPartial(c); - [self skip:len]; + [self skip:length]; } return packet; } @catch (NSException *exception) { if ([exception.name isEqualToString:endOfFileException]) { + // An endOfFileException is thrown by [self byte], when a unexpected EOF is reached. + // Set self.error to signal this. self.error = [NSError errorWithDomain:LibmacgpgErrorDomain code:GPGErrorEOF userInfo:nil]; } else { - @throw; + // Never throw an exception, instead log it and set self.error. + NSLog(@"Uncaught exception in [GPGPacketParser nextPacket]: \"%@\"", exception); + self.error = [NSError errorWithDomain:LibmacgpgErrorDomain code:GPGErrorUnexpected userInfo:@{@"exception": exception}]; } } @@ -181,6 +206,8 @@ - (GPGPacket *)nextPacket { #pragma mark Helper - (NSInteger)byte { + // Get the next byte from the strem. + NSInteger byte = [stream readByte]; if (byte == EOF) { @throw [NSException exceptionWithName:endOfFileException reason:@"unexpected end of file." userInfo:nil]; @@ -189,6 +216,7 @@ - (NSInteger)byte { packetLength--; if (byteCallback) { + // Return the byte via byteCallback AND as a normal return value. byteCallback(byte); } @@ -196,6 +224,8 @@ - (NSInteger)byte { } - (NSInteger)byteOrEOF { + // Same as [self byte], but can also return EOF. + NSInteger byte = [stream readByte]; packetLength--; @@ -207,6 +237,7 @@ - (NSInteger)byteOrEOF { } - (void)skip:(NSUInteger)count { + // skip count bytes. for (; count > 0; count--) { [self byte]; } @@ -221,27 +252,31 @@ static BOOL isPartial(NSInteger c) { } - (NSUInteger)getNewLen:(NSInteger)c { - NSUInteger len; + // Get the packet new format packet length. + + NSUInteger length; if (c < 192) { - len = c; + length = c; } else if (c < 224) { - len = ((c - 192) << 8) + self.byte + 192; + length = ((c - 192) << 8) + self.byte + 192; } else if (c == 255) { - len = (self.byte << 24); - len |= (self.byte << 16); - len |= (self.byte << 8); - len |= self.byte; + length = (self.byte << 24); + length |= (self.byte << 16); + length |= (self.byte << 8); + length |= self.byte; } else { - len = 1 << (c & PARTIAL_MASK); + length = 1 << (c & PARTIAL_MASK); } - return len; + return length; } -#pragma mark Parsing methods, used by GPGPacket +#pragma mark Helper methods used by GPGPacket - (NSUInteger)nextPartialLength { + // Returns the length of the next part. + if (partial == NO) { return 0; } @@ -258,10 +293,17 @@ - (BOOL)partial { } - (void)skipRemaining { + // Skip the remaining byte of the current packet. + [self skip:packetLength]; } + +#pragma mark Parsing methods used by GPGPacket + - (NSString *)keyID { + // Read a key ID. Consumes 8 bytes. + NSString *keyID = [NSString stringWithFormat:@"%02X%02X%02X%02X%02X%02X%02X%02X", (UInt8)self.byte, (UInt8)self.byte, @@ -276,6 +318,8 @@ - (NSString *)keyID { } - (id)multiPrecisionInteger { + // Read a MPI. + NSUInteger byteCount; NSUInteger bits = self.byte * 256; bits += self.byte; @@ -293,6 +337,8 @@ - (id)multiPrecisionInteger { } - (NSDate *)date { + // Read a date. Consumes 4 bytes. + NSUInteger time; time = self.byte << 24; @@ -310,11 +356,15 @@ - (NSDate *)date { } - (UInt16)uint16 { + // Read a unsigned 16-bit integer. Consumes 2 bytes. + UInt16 value = (UInt16)((self.byte << 8) | self.byte); return value; } - (NSString *)stringWithLength:(NSUInteger)length { + // Read an UTF8 string. + char tempString[length + 1]; tempString[length] = 0; for (NSUInteger i = 0; i < length; i++) { @@ -327,9 +377,14 @@ - (NSString *)stringWithLength:(NSUInteger)length { } - (NSArray *)signatureSubpacketsWithLength:(NSUInteger)fullLength { + // Parse the signature subpackets. + // fullLength is the length of all subpackets. + NSMutableArray *packets = [NSMutableArray array]; while (fullLength > 0) { + + // Get the length of the subpacket. NSUInteger length = self.byte; if (length < 192) { fullLength--; @@ -345,13 +400,14 @@ - (NSArray *)signatureSubpacketsWithLength:(NSUInteger)fullLength { } fullLength -= length; - + // Used to skip the remaining subpacket bytes. NSUInteger remainingLength = packetLength - length; - GPGSubpacketTag subtag = self.byte; /* len includes this field byte */ + GPGSubpacketTag subtag = self.byte; // length includes this byte. length--; + /* Handle critical bit of subpacket type */ BOOL critical = NO; if (subtag & CRITICAL_BIT) { @@ -360,13 +416,14 @@ - (NSArray *)signatureSubpacketsWithLength:(NSUInteger)fullLength { } + // Currently a subpacket is represented by a NSDictionary. This can change in the future. NSMutableDictionary *packet = [NSMutableDictionary dictionaryWithObjectsAndKeys:@(subtag), @"tag", nil]; if (critical) { packet[@"critical"] = @YES; } - + // Parse the subpacket content. switch (subtag) { case GPGSignatureCreationTimeTag: case GPGSignatureExpirationTimeTag: @@ -444,9 +501,10 @@ - (NSArray *)signatureSubpacketsWithLength:(NSUInteger)fullLength { break; } + // Add the subpacket to the list. [packets addObject:packet]; - + // Skip all remaining bytes of this subpacket, if any. length = packetLength - remainingLength; [self skip:length]; } @@ -474,6 +532,7 @@ - (instancetype)initWithStream:(GPGStream *)theStream { } + (void)initialize { + // This list of GPGPacket subclasses. tagClasses = [@[ [NSNull null], [GPGPublicKeyEncryptedSessionKeyPacket class], // 1 diff --git a/Source/GPGPacket/GPGPacket_Private.h b/Source/GPGPacket/GPGPacket_Private.h index 95c4d3c..b339500 100644 --- a/Source/GPGPacket/GPGPacket_Private.h +++ b/Source/GPGPacket/GPGPacket_Private.h @@ -25,7 +25,9 @@ @interface GPGPacket () +// This is the designated initializer of the sub-classes. +// This method may read up to length bytes from parser, +// it could read more, if it's a partial packet. - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)length; - @end diff --git a/Source/GPGPacket/GPGPublicKeyEncryptedSessionKeyPacket.m b/Source/GPGPacket/GPGPublicKeyEncryptedSessionKeyPacket.m index bbc3e2b..fb868fe 100644 --- a/Source/GPGPacket/GPGPublicKeyEncryptedSessionKeyPacket.m +++ b/Source/GPGPacket/GPGPublicKeyEncryptedSessionKeyPacket.m @@ -43,6 +43,7 @@ - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)leng self.keyID = parser.keyID; self.publicAlgorithm = parser.byte; + // We ignore the MPIs at the moment. switch (publicAlgorithm) { case 1: case 2: diff --git a/Source/GPGPacket/GPGSignaturePacket.h b/Source/GPGPacket/GPGSignaturePacket.h index 45036dc..47f0034 100644 --- a/Source/GPGPacket/GPGSignaturePacket.h +++ b/Source/GPGPacket/GPGSignaturePacket.h @@ -66,13 +66,28 @@ typedef enum { @property (nonatomic, readonly) NSInteger publicAlgorithm; @property (nonatomic, readonly) NSInteger hashAlgorithm; +/** + Type of the signature. See: https://tools.ietf.org/html/rfc4880#section-5.2.1 + */ @property (nonatomic, readonly) NSInteger type; @property (nonatomic, readonly) NSInteger version; @property (nonatomic, readonly) UInt16 hashStart; @property (nonatomic, copy, readonly) NSString *keyID; @property (nonatomic, copy, readonly) NSDate *creationDate; +/** + The hashed subpackets of the GPGSignaturePacket. + @returns List of NSDictionarys, this can change at any time, so you're required to test for it. + */ @property (nonatomic, copy, readonly) NSArray *hashedSubpackets; +/** + The unhashed subpackets of the GPGSignaturePacket. They are NOT secured by the signature. + @returns List of NSDictionarys, this can change at any time, so you're required to test for it. + */ @property (nonatomic, copy, readonly) NSArray *unhashedSubpackets; +/** + Array containing all elements of unhashedSubpackets and hashedSubpackets. + @returns List of NSDictionarys, this can change at any time, so you're required to test for it. + */ @property (nonatomic, copy, readonly) NSArray *subpackets; // Combination of unhashedSubpackets and hashedSubpackets. Order is undefined! diff --git a/Source/GPGPacket/GPGSignaturePacket.m b/Source/GPGPacket/GPGSignaturePacket.m index 59c6044..54b2a5e 100644 --- a/Source/GPGPacket/GPGSignaturePacket.m +++ b/Source/GPGPacket/GPGSignaturePacket.m @@ -54,13 +54,15 @@ - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)leng case 3: // Old format. - [parser byte]; // Ignore (length of type + creationDate. MUST be 5.) + [parser byte]; // Ignore (length of type(1 byte) and creationDate(4 bytes). MUST be 5.) self.type = parser.byte; self.creationDate = parser.date; + // KeyID of the issuer. self.keyID = parser.keyID; self.publicAlgorithm = parser.byte; self.hashAlgorithm = parser.byte; + // The first 16 bit of the hash, verified by this signature. self.hashStart = parser.uint16; switch (publicAlgorithm) { @@ -91,12 +93,15 @@ - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)leng self.publicAlgorithm = parser.byte; self.hashAlgorithm = parser.byte; - NSUInteger hsplen = parser.uint16; + NSUInteger hsplen = parser.uint16; // Length of the hashed subpackets. + // The hashed subpackets are secured by the signature itself. self.hashedSubpackets = [parser signatureSubpacketsWithLength:hsplen]; - NSUInteger usplen = parser.uint16; + NSUInteger usplen = parser.uint16; // Length of the unhashed subpackets. + // The unhashed subpackets are NOT secured. Don't trust them. self.unhashedSubpackets = [parser signatureSubpacketsWithLength:usplen]; + // Combined list of subpackets for convenience. NSMutableArray *theSubpackets = [NSMutableArray arrayWithArray:unhashedSubpackets]; [theSubpackets addObjectsFromArray:hashedSubpackets]; self.subpackets = theSubpackets; @@ -117,9 +122,10 @@ - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)leng } - + // The first 16 bit of the hash, verified by this signature. self.hashStart = parser.uint16; + // Ignore the MPIs. switch (publicAlgorithm) { case 1: case 2: diff --git a/Source/GPGPacket/GPGSymmetricEncryptedSessionKeyPacket.h b/Source/GPGPacket/GPGSymmetricEncryptedSessionKeyPacket.h index 6683218..054f89b 100644 --- a/Source/GPGPacket/GPGSymmetricEncryptedSessionKeyPacket.h +++ b/Source/GPGPacket/GPGSymmetricEncryptedSessionKeyPacket.h @@ -27,6 +27,9 @@ NSString *keyID; } +/** + Symmetric-Key Algorithm used. See: https://tools.ietf.org/html/rfc4880#section-9.2 + */ @property (nonatomic, readonly) NSInteger symmetricAlgorithm; @property (nonatomic, readonly) NSInteger version; @property (nonatomic, strong, readonly) NSString *keyID; diff --git a/Source/GPGPacket/GPGUserAttributePacket.m b/Source/GPGPacket/GPGUserAttributePacket.m index 38acd88..332725c 100644 --- a/Source/GPGPacket/GPGUserAttributePacket.m +++ b/Source/GPGPacket/GPGUserAttributePacket.m @@ -39,12 +39,14 @@ - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)leng } NSMutableArray *packets = [NSMutableArray array]; + + // The length of all subpackets. NSUInteger fullLength = length; while (fullLength > 0) { + // Length of this subpacket. NSUInteger subLength = parser.byte; - if (subLength < 192) { fullLength--; } else if (subLength < 255) { @@ -57,29 +59,39 @@ - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)leng subLength |= parser.byte; fullLength -= 5; } + + // Subtract the subpacket length. fullLength -= subLength; - NSInteger subtype = parser.byte; /* len includes this field byte */ - subLength--; + NSInteger subtype = parser.byte; // subLength includes this byte, + subLength--; // so we have to decrement by one. + + + // Only a subtype of 1 is specified currently in the RFC. switch (subtype) { case 1: { + // Length of the subpacket header, 16 is currently the only valid value. NSUInteger headerLength = parser.byte; headerLength |= parser.byte << 8; // little-endian, because of a "historical accident"! + // Only the headerVersion 1 is specified currently in the RFC. NSInteger headerVersion = parser.byte; - subLength -= 3; + subLength -= 3; // We have read 3 bytes. + + if (headerLength == 16 && headerVersion == 1) { NSInteger format = parser.byte; subLength--; if (format == 1) { // JPEG is the only currently defined format. - [parser skip:12]; + [parser skip:12]; // Skip the remaining header. subLength -= 12; + // Read the image data. NSMutableData *tempData = [NSMutableData dataWithLength:subLength]; UInt8 *bytes = tempData.mutableBytes; for (NSUInteger i = 0; i < subLength; i++) { @@ -88,9 +100,11 @@ - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)leng subLength = 0; + // And convert it into an image. NSImage *image = [[NSImage alloc] initWithData:tempData]; if (image) { + // Only subpackets with an valid image are added. NSDictionary *subpacket = @{@"image": image}; [packets addObject:subpacket]; } @@ -102,6 +116,7 @@ - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)leng break; } + // Skip the remaing bytes of the subpacket, if any. [parser skip:subLength]; } From 5e4218b1729cff920819bf6e777d2a4ab74d2cb3 Mon Sep 17 00:00:00 2001 From: Mento Date: Tue, 14 Jul 2015 14:20:55 +0200 Subject: [PATCH 34/56] Some strange code fragment removed. --- Source/GPGUnArmor.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Source/GPGUnArmor.h b/Source/GPGUnArmor.h index d6a387f..de14120 100644 --- a/Source/GPGUnArmor.h +++ b/Source/GPGUnArmor.h @@ -70,11 +70,6 @@ - -void a() { - [NSFileHandle fileHandleForReadingFromURL:nil error:nil]; -} - + (instancetype)unArmorWithGPGStream:(GPGStream *)theStream; - (instancetype)initWithGPGStream:(GPGStream *)stream; From 02a9ee49a4bdb8c30af4093400fdbe17b7c05045 Mon Sep 17 00:00:00 2001 From: Mento Date: Tue, 14 Jul 2015 19:10:28 +0200 Subject: [PATCH 35/56] More unit tests. Unit test for GPGUnArmor added. --- Libmacgpg.xcodeproj/project.pbxproj | 111 ++++++++++++++---- UnitTest/UnitTest-Info.plist | 22 ---- {UnitTest => UnitTests}/GPGArraySettingTest.m | 0 {UnitTest => UnitTests}/GPGConfReaderTest.m | 0 {UnitTest => UnitTests}/GPGDictSettingTest.m | 0 {UnitTest => UnitTests}/GPGLinesSettingTest.m | 0 {UnitTest => UnitTests}/GPGOptionsTest.m | 0 {UnitTest => UnitTests}/GPGStdSettingTest.m | 0 {UnitTest => UnitTests}/GPGTestVerify.m | 0 UnitTests/GPGUnarmorTest.m | 47 ++++++++ UnitTests/GPGUnitTest.h | 1 + UnitTests/GPGUnitTest.m | 10 ++ {UnitTest => UnitTests}/Resources/OpenPGP.asc | 0 .../Resources/SignedInputStringCR.txt | 0 .../Resources/SignedInputStringCRLF.txt | 0 .../Resources/SignedInputStringLF.txt | 0 .../Unarmor/Unarmor_DoubleNewline.res | Bin 0 -> 335 bytes .../Unarmor/Unarmor_DoubleNewline.txt | 24 ++++ .../Unarmor/Unarmor_InvalidComment.res | Bin 0 -> 335 bytes .../Unarmor/Unarmor_InvalidComment.txt | 12 ++ .../Unarmor/Unarmor_InvalidVersion.res | Bin 0 -> 335 bytes .../Unarmor/Unarmor_InvalidVersion.txt | 12 ++ .../Unarmor/Unarmor_MissingNewline.res | Bin 0 -> 335 bytes .../Unarmor/Unarmor_MissingNewline.txt | 11 ++ .../Resources/Unarmor/Unarmor_NoNewline.res | Bin 0 -> 335 bytes .../Resources/Unarmor/Unarmor_NoNewline.txt | 1 + .../Resources/Unarmor/Unarmor_Normal.res | Bin 0 -> 335 bytes .../Resources/Unarmor/Unarmor_Normal.txt | 12 ++ .../Resources/Unarmor/Unarmor_Version.res | Bin 0 -> 335 bytes .../Resources/Unarmor/Unarmor_Version.txt | 12 ++ .../Unarmor/Unarmor_VersionOnline.res | Bin 0 -> 335 bytes .../Unarmor/Unarmor_VersionOnline.txt | 12 ++ 32 files changed, 239 insertions(+), 48 deletions(-) delete mode 100644 UnitTest/UnitTest-Info.plist rename {UnitTest => UnitTests}/GPGArraySettingTest.m (100%) rename {UnitTest => UnitTests}/GPGConfReaderTest.m (100%) rename {UnitTest => UnitTests}/GPGDictSettingTest.m (100%) rename {UnitTest => UnitTests}/GPGLinesSettingTest.m (100%) rename {UnitTest => UnitTests}/GPGOptionsTest.m (100%) rename {UnitTest => UnitTests}/GPGStdSettingTest.m (100%) rename {UnitTest => UnitTests}/GPGTestVerify.m (100%) create mode 100644 UnitTests/GPGUnarmorTest.m rename {UnitTest => UnitTests}/Resources/OpenPGP.asc (100%) rename {UnitTest => UnitTests}/Resources/SignedInputStringCR.txt (100%) rename {UnitTest => UnitTests}/Resources/SignedInputStringCRLF.txt (100%) rename {UnitTest => UnitTests}/Resources/SignedInputStringLF.txt (100%) create mode 100644 UnitTests/Resources/Unarmor/Unarmor_DoubleNewline.res create mode 100644 UnitTests/Resources/Unarmor/Unarmor_DoubleNewline.txt create mode 100644 UnitTests/Resources/Unarmor/Unarmor_InvalidComment.res create mode 100644 UnitTests/Resources/Unarmor/Unarmor_InvalidComment.txt create mode 100644 UnitTests/Resources/Unarmor/Unarmor_InvalidVersion.res create mode 100644 UnitTests/Resources/Unarmor/Unarmor_InvalidVersion.txt create mode 100644 UnitTests/Resources/Unarmor/Unarmor_MissingNewline.res create mode 100644 UnitTests/Resources/Unarmor/Unarmor_MissingNewline.txt create mode 100644 UnitTests/Resources/Unarmor/Unarmor_NoNewline.res create mode 100644 UnitTests/Resources/Unarmor/Unarmor_NoNewline.txt create mode 100644 UnitTests/Resources/Unarmor/Unarmor_Normal.res create mode 100644 UnitTests/Resources/Unarmor/Unarmor_Normal.txt create mode 100644 UnitTests/Resources/Unarmor/Unarmor_Version.res create mode 100644 UnitTests/Resources/Unarmor/Unarmor_Version.txt create mode 100644 UnitTests/Resources/Unarmor/Unarmor_VersionOnline.res create mode 100644 UnitTests/Resources/Unarmor/Unarmor_VersionOnline.txt diff --git a/Libmacgpg.xcodeproj/project.pbxproj b/Libmacgpg.xcodeproj/project.pbxproj index 6831f5c..b73137e 100644 --- a/Libmacgpg.xcodeproj/project.pbxproj +++ b/Libmacgpg.xcodeproj/project.pbxproj @@ -75,6 +75,23 @@ 309A18D113E3812E0069DC0F /* GPGTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 309A18CF13E3812E0069DC0F /* GPGTransformer.m */; }; 30A058391799E2DC00E1AD20 /* GPGKeyManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 30A058371799E2DC00E1AD20 /* GPGKeyManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; 30A0583A1799E2DC00E1AD20 /* GPGKeyManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 30A058381799E2DC00E1AD20 /* GPGKeyManager.m */; }; + 30A218231B5543A500D01E37 /* GPGUnarmorTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 30A218221B5543A500D01E37 /* GPGUnarmorTest.m */; }; + 30A2186B1B5579A200D01E37 /* Unarmor_DoubleNewline.res in Resources */ = {isa = PBXBuildFile; fileRef = 30A2185B1B5579A200D01E37 /* Unarmor_DoubleNewline.res */; }; + 30A2186C1B5579A200D01E37 /* Unarmor_DoubleNewline.txt in Resources */ = {isa = PBXBuildFile; fileRef = 30A2185C1B5579A200D01E37 /* Unarmor_DoubleNewline.txt */; }; + 30A2186D1B5579A200D01E37 /* Unarmor_InvalidComment.res in Resources */ = {isa = PBXBuildFile; fileRef = 30A2185D1B5579A200D01E37 /* Unarmor_InvalidComment.res */; }; + 30A2186E1B5579A200D01E37 /* Unarmor_InvalidComment.txt in Resources */ = {isa = PBXBuildFile; fileRef = 30A2185E1B5579A200D01E37 /* Unarmor_InvalidComment.txt */; }; + 30A2186F1B5579A200D01E37 /* Unarmor_InvalidVersion.res in Resources */ = {isa = PBXBuildFile; fileRef = 30A2185F1B5579A200D01E37 /* Unarmor_InvalidVersion.res */; }; + 30A218701B5579A200D01E37 /* Unarmor_InvalidVersion.txt in Resources */ = {isa = PBXBuildFile; fileRef = 30A218601B5579A200D01E37 /* Unarmor_InvalidVersion.txt */; }; + 30A218711B5579A200D01E37 /* Unarmor_MissingNewline.res in Resources */ = {isa = PBXBuildFile; fileRef = 30A218611B5579A200D01E37 /* Unarmor_MissingNewline.res */; }; + 30A218721B5579A200D01E37 /* Unarmor_MissingNewline.txt in Resources */ = {isa = PBXBuildFile; fileRef = 30A218621B5579A200D01E37 /* Unarmor_MissingNewline.txt */; }; + 30A218731B5579A200D01E37 /* Unarmor_NoNewline.res in Resources */ = {isa = PBXBuildFile; fileRef = 30A218631B5579A200D01E37 /* Unarmor_NoNewline.res */; }; + 30A218741B5579A200D01E37 /* Unarmor_NoNewline.txt in Resources */ = {isa = PBXBuildFile; fileRef = 30A218641B5579A200D01E37 /* Unarmor_NoNewline.txt */; }; + 30A218751B5579A200D01E37 /* Unarmor_Normal.res in Resources */ = {isa = PBXBuildFile; fileRef = 30A218651B5579A200D01E37 /* Unarmor_Normal.res */; }; + 30A218761B5579A200D01E37 /* Unarmor_Normal.txt in Resources */ = {isa = PBXBuildFile; fileRef = 30A218661B5579A200D01E37 /* Unarmor_Normal.txt */; }; + 30A218771B5579A200D01E37 /* Unarmor_Version.res in Resources */ = {isa = PBXBuildFile; fileRef = 30A218671B5579A200D01E37 /* Unarmor_Version.res */; }; + 30A218781B5579A200D01E37 /* Unarmor_Version.txt in Resources */ = {isa = PBXBuildFile; fileRef = 30A218681B5579A200D01E37 /* Unarmor_Version.txt */; }; + 30A218791B5579A200D01E37 /* Unarmor_VersionOnline.res in Resources */ = {isa = PBXBuildFile; fileRef = 30A218691B5579A200D01E37 /* Unarmor_VersionOnline.res */; }; + 30A2187A1B5579A200D01E37 /* Unarmor_VersionOnline.txt in Resources */ = {isa = PBXBuildFile; fileRef = 30A2186A1B5579A200D01E37 /* Unarmor_VersionOnline.txt */; }; 30A48E8E1B4C1344006AD363 /* GPGSignaturePacket.h in Headers */ = {isa = PBXBuildFile; fileRef = 30A48E8C1B4C1344006AD363 /* GPGSignaturePacket.h */; settings = {ATTRIBUTES = (Public, ); }; }; 30A48E8F1B4C1344006AD363 /* GPGSignaturePacket.m in Sources */ = {isa = PBXBuildFile; fileRef = 30A48E8D1B4C1344006AD363 /* GPGSignaturePacket.m */; }; 30A70EE513EF328000EE9CD9 /* GPGException.h in Headers */ = {isa = PBXBuildFile; fileRef = 30A70EE313EF328000EE9CD9 /* GPGException.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -96,19 +113,11 @@ 30BB7C841B4D4BF8006A1E47 /* GPGUserAttributePacket.h in Headers */ = {isa = PBXBuildFile; fileRef = 30BB7C821B4D4BF8006A1E47 /* GPGUserAttributePacket.h */; settings = {ATTRIBUTES = (Public, ); }; }; 30BB7C851B4D4BF8006A1E47 /* GPGUserAttributePacket.m in Sources */ = {isa = PBXBuildFile; fileRef = 30BB7C831B4D4BF8006A1E47 /* GPGUserAttributePacket.m */; }; 30BE73C41B54015C001A2137 /* Libmacgpg.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8DC2EF5B0486A6940098B216 /* Libmacgpg.framework */; }; - 30BE73DC1B5407E3001A2137 /* GPGTestVerify.m in Sources */ = {isa = PBXBuildFile; fileRef = 45C0BC02151B65C700AA8BF6 /* GPGTestVerify.m */; }; 30BE73DD1B541039001A2137 /* OpenPGP.asc in Resources */ = {isa = PBXBuildFile; fileRef = 45B9A7F5151C9A6D00DAD67A /* OpenPGP.asc */; }; 30BE73DE1B541039001A2137 /* SignedInputStringCR.txt in Resources */ = {isa = PBXBuildFile; fileRef = 45891A40151BA1EC002D7410 /* SignedInputStringCR.txt */; }; 30BE73DF1B541039001A2137 /* SignedInputStringCRLF.txt in Resources */ = {isa = PBXBuildFile; fileRef = 45891A3C151BA1C9002D7410 /* SignedInputStringCRLF.txt */; }; 30BE73E01B541039001A2137 /* SignedInputStringLF.txt in Resources */ = {isa = PBXBuildFile; fileRef = 45891A3D151BA1C9002D7410 /* SignedInputStringLF.txt */; }; - 30BE73E11B5411C2001A2137 /* GPGConfReaderTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4591C4C914F85AA3007F6D47 /* GPGConfReaderTest.m */; }; - 30BE73E21B5411C2001A2137 /* GPGStdSettingTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4547646514FBC8A900A37306 /* GPGStdSettingTest.m */; }; - 30BE73E31B5411C2001A2137 /* GPGLinesSettingTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 45156A2314FB310300129FE7 /* GPGLinesSettingTest.m */; }; - 30BE73E41B5411C2001A2137 /* GPGArraySettingTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 45156A2C14FB506E00129FE7 /* GPGArraySettingTest.m */; }; - 30BE73E51B5411C2001A2137 /* GPGDictSettingTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 45156A2614FB35DC00129FE7 /* GPGDictSettingTest.m */; }; - 30BE73E61B5411C2001A2137 /* GPGOptionsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 455B17B915143D9A00FAD47D /* GPGOptionsTest.m */; }; 30BE73EA1B541F5B001A2137 /* GPGUnitTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 30BE73E91B541F5B001A2137 /* GPGUnitTest.m */; }; - 30BE73EC1B54238F001A2137 /* GPGSocketCloseTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1BE88B3D1B47D7F900A812B6 /* GPGSocketCloseTest.m */; }; 30C045931B4FDB9800080903 /* GPGCompressedDataPacket_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 30C045921B4FDB9800080903 /* GPGCompressedDataPacket_Private.h */; }; 30C60EEF12FF3321006BB8DA /* Libmacgpg.h in Headers */ = {isa = PBXBuildFile; fileRef = 30C60EEE12FF3321006BB8DA /* Libmacgpg.h */; settings = {ATTRIBUTES = (Public, ); }; }; 30D5E2A41483A0F700F31454 /* GPGConf.h in Headers */ = {isa = PBXBuildFile; fileRef = 30D5E2A21483A0F700F31454 /* GPGConf.h */; }; @@ -265,6 +274,23 @@ 309A18CF13E3812E0069DC0F /* GPGTransformer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGTransformer.m; sourceTree = ""; }; 30A058371799E2DC00E1AD20 /* GPGKeyManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGKeyManager.h; sourceTree = ""; }; 30A058381799E2DC00E1AD20 /* GPGKeyManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGKeyManager.m; sourceTree = ""; }; + 30A218221B5543A500D01E37 /* GPGUnarmorTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGUnarmorTest.m; sourceTree = ""; }; + 30A2185B1B5579A200D01E37 /* Unarmor_DoubleNewline.res */ = {isa = PBXFileReference; lastKnownFileType = file; name = Unarmor_DoubleNewline.res; path = Unarmor/Unarmor_DoubleNewline.res; sourceTree = ""; }; + 30A2185C1B5579A200D01E37 /* Unarmor_DoubleNewline.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Unarmor_DoubleNewline.txt; path = Unarmor/Unarmor_DoubleNewline.txt; sourceTree = ""; }; + 30A2185D1B5579A200D01E37 /* Unarmor_InvalidComment.res */ = {isa = PBXFileReference; lastKnownFileType = file; name = Unarmor_InvalidComment.res; path = Unarmor/Unarmor_InvalidComment.res; sourceTree = ""; }; + 30A2185E1B5579A200D01E37 /* Unarmor_InvalidComment.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Unarmor_InvalidComment.txt; path = Unarmor/Unarmor_InvalidComment.txt; sourceTree = ""; }; + 30A2185F1B5579A200D01E37 /* Unarmor_InvalidVersion.res */ = {isa = PBXFileReference; lastKnownFileType = file; name = Unarmor_InvalidVersion.res; path = Unarmor/Unarmor_InvalidVersion.res; sourceTree = ""; }; + 30A218601B5579A200D01E37 /* Unarmor_InvalidVersion.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Unarmor_InvalidVersion.txt; path = Unarmor/Unarmor_InvalidVersion.txt; sourceTree = ""; }; + 30A218611B5579A200D01E37 /* Unarmor_MissingNewline.res */ = {isa = PBXFileReference; lastKnownFileType = file; name = Unarmor_MissingNewline.res; path = Unarmor/Unarmor_MissingNewline.res; sourceTree = ""; }; + 30A218621B5579A200D01E37 /* Unarmor_MissingNewline.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Unarmor_MissingNewline.txt; path = Unarmor/Unarmor_MissingNewline.txt; sourceTree = ""; }; + 30A218631B5579A200D01E37 /* Unarmor_NoNewline.res */ = {isa = PBXFileReference; lastKnownFileType = file; name = Unarmor_NoNewline.res; path = Unarmor/Unarmor_NoNewline.res; sourceTree = ""; }; + 30A218641B5579A200D01E37 /* Unarmor_NoNewline.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Unarmor_NoNewline.txt; path = Unarmor/Unarmor_NoNewline.txt; sourceTree = ""; }; + 30A218651B5579A200D01E37 /* Unarmor_Normal.res */ = {isa = PBXFileReference; lastKnownFileType = file; name = Unarmor_Normal.res; path = Unarmor/Unarmor_Normal.res; sourceTree = ""; }; + 30A218661B5579A200D01E37 /* Unarmor_Normal.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Unarmor_Normal.txt; path = Unarmor/Unarmor_Normal.txt; sourceTree = ""; }; + 30A218671B5579A200D01E37 /* Unarmor_Version.res */ = {isa = PBXFileReference; lastKnownFileType = file; name = Unarmor_Version.res; path = Unarmor/Unarmor_Version.res; sourceTree = ""; }; + 30A218681B5579A200D01E37 /* Unarmor_Version.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Unarmor_Version.txt; path = Unarmor/Unarmor_Version.txt; sourceTree = ""; }; + 30A218691B5579A200D01E37 /* Unarmor_VersionOnline.res */ = {isa = PBXFileReference; lastKnownFileType = file; name = Unarmor_VersionOnline.res; path = Unarmor/Unarmor_VersionOnline.res; sourceTree = ""; }; + 30A2186A1B5579A200D01E37 /* Unarmor_VersionOnline.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Unarmor_VersionOnline.txt; path = Unarmor/Unarmor_VersionOnline.txt; sourceTree = ""; }; 30A48E8C1B4C1344006AD363 /* GPGSignaturePacket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPGSignaturePacket.h; path = GPGPacket/GPGSignaturePacket.h; sourceTree = ""; }; 30A48E8D1B4C1344006AD363 /* GPGSignaturePacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGSignaturePacket.m; path = GPGPacket/GPGSignaturePacket.m; sourceTree = ""; }; 30A70EE313EF328000EE9CD9 /* GPGException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGException.h; sourceTree = ""; }; @@ -291,7 +317,6 @@ 30BE73E91B541F5B001A2137 /* GPGUnitTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGUnitTest.m; sourceTree = ""; }; 30C045921B4FDB9800080903 /* GPGCompressedDataPacket_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPGCompressedDataPacket_Private.h; path = GPGPacket/GPGCompressedDataPacket_Private.h; sourceTree = ""; }; 30C60EEE12FF3321006BB8DA /* Libmacgpg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Libmacgpg.h; sourceTree = ""; }; - 30C8B38F139503A800F49AA1 /* UnitTest-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "UnitTest-Info.plist"; path = "../UnitTest-Info.plist"; sourceTree = ""; }; 30D5E2A21483A0F700F31454 /* GPGConf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = GPGConf.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 30D5E2A31483A0F700F31454 /* GPGConf.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGConf.m; sourceTree = ""; }; 30D68BC41B4FF5D500F7865C /* COPYING.pgpdump */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = COPYING.pgpdump; path = Source/GPGPacket/COPYING.pgpdump; sourceTree = SOURCE_ROOT; }; @@ -323,11 +348,11 @@ 45156A1B14FB1B1200129FE7 /* GPGLinesSetting.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGLinesSetting.m; sourceTree = ""; }; 45156A1E14FB1D7D00129FE7 /* GPGDictSetting.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGDictSetting.h; sourceTree = ""; }; 45156A1F14FB1D7D00129FE7 /* GPGDictSetting.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGDictSetting.m; sourceTree = ""; }; - 45156A2314FB310300129FE7 /* GPGLinesSettingTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGLinesSettingTest.m; path = ../UnitTest/GPGLinesSettingTest.m; sourceTree = ""; }; - 45156A2614FB35DC00129FE7 /* GPGDictSettingTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGDictSettingTest.m; path = ../UnitTest/GPGDictSettingTest.m; sourceTree = ""; }; + 45156A2314FB310300129FE7 /* GPGLinesSettingTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGLinesSettingTest.m; path = ../UnitTests/GPGLinesSettingTest.m; sourceTree = ""; }; + 45156A2614FB35DC00129FE7 /* GPGDictSettingTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGDictSettingTest.m; path = ../UnitTests/GPGDictSettingTest.m; sourceTree = ""; }; 45156A2814FB3EF700129FE7 /* GPGArraySetting.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGArraySetting.h; sourceTree = ""; }; 45156A2914FB3EF700129FE7 /* GPGArraySetting.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGArraySetting.m; sourceTree = ""; }; - 45156A2C14FB506E00129FE7 /* GPGArraySettingTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGArraySettingTest.m; path = ../UnitTest/GPGArraySettingTest.m; sourceTree = ""; }; + 45156A2C14FB506E00129FE7 /* GPGArraySettingTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGArraySettingTest.m; path = ../UnitTests/GPGArraySettingTest.m; sourceTree = ""; }; 451932F314F8061100D1F727 /* GPGStdSetting.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = GPGStdSetting.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 451932F414F8061100D1F727 /* GPGStdSetting.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = GPGStdSetting.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 451D8827156A7AD900A0B890 /* GPGStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGStream.h; sourceTree = ""; }; @@ -336,19 +361,19 @@ 451D882C156A7CA300A0B890 /* GPGMemoryStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGMemoryStream.m; sourceTree = ""; }; 451D882F156A7E4900A0B890 /* GPGFileStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGFileStream.h; sourceTree = ""; }; 451D8830156A7E4900A0B890 /* GPGFileStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGFileStream.m; sourceTree = ""; }; - 4547646514FBC8A900A37306 /* GPGStdSettingTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGStdSettingTest.m; path = ../UnitTest/GPGStdSettingTest.m; sourceTree = ""; }; - 455B17B915143D9A00FAD47D /* GPGOptionsTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGOptionsTest.m; path = ../UnitTest/GPGOptionsTest.m; sourceTree = ""; }; + 4547646514FBC8A900A37306 /* GPGStdSettingTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGStdSettingTest.m; path = ../UnitTests/GPGStdSettingTest.m; sourceTree = ""; }; + 455B17B915143D9A00FAD47D /* GPGOptionsTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGOptionsTest.m; path = ../UnitTests/GPGOptionsTest.m; sourceTree = ""; }; 4570876414FAA7C90030AAE6 /* GPGConfReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = GPGConfReader.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 4570876514FAA7C90030AAE6 /* GPGConfReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = GPGConfReader.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 45891A3C151BA1C9002D7410 /* SignedInputStringCRLF.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = SignedInputStringCRLF.txt; sourceTree = ""; }; 45891A3D151BA1C9002D7410 /* SignedInputStringLF.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = SignedInputStringLF.txt; sourceTree = ""; }; 45891A40151BA1EC002D7410 /* SignedInputStringCR.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = SignedInputStringCR.txt; sourceTree = ""; }; - 4591C4C914F85AA3007F6D47 /* GPGConfReaderTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; name = GPGConfReaderTest.m; path = ../UnitTest/GPGConfReaderTest.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; + 4591C4C914F85AA3007F6D47 /* GPGConfReaderTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; name = GPGConfReaderTest.m; path = ../UnitTests/GPGConfReaderTest.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 4591C4D314F86D38007F6D47 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; 4591C4D414F86D38007F6D47 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; 4591C4D514F86D38007F6D47 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 45B9A7F5151C9A6D00DAD67A /* OpenPGP.asc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = OpenPGP.asc; sourceTree = ""; }; - 45C0BC02151B65C700AA8BF6 /* GPGTestVerify.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGTestVerify.m; path = ../UnitTest/GPGTestVerify.m; sourceTree = ""; }; + 45C0BC02151B65C700AA8BF6 /* GPGTestVerify.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGTestVerify.m; path = ../UnitTests/GPGTestVerify.m; sourceTree = ""; }; 8DC2EF5A0486A6940098B216 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 8DC2EF5B0486A6940098B216 /* Libmacgpg.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Libmacgpg.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -680,6 +705,29 @@ name = GPGOptions; sourceTree = ""; }; + 30A2183A1B55753100D01E37 /* Unarmor */ = { + isa = PBXGroup; + children = ( + 30A2185B1B5579A200D01E37 /* Unarmor_DoubleNewline.res */, + 30A2185C1B5579A200D01E37 /* Unarmor_DoubleNewline.txt */, + 30A2185D1B5579A200D01E37 /* Unarmor_InvalidComment.res */, + 30A2185E1B5579A200D01E37 /* Unarmor_InvalidComment.txt */, + 30A2185F1B5579A200D01E37 /* Unarmor_InvalidVersion.res */, + 30A218601B5579A200D01E37 /* Unarmor_InvalidVersion.txt */, + 30A218611B5579A200D01E37 /* Unarmor_MissingNewline.res */, + 30A218621B5579A200D01E37 /* Unarmor_MissingNewline.txt */, + 30A218631B5579A200D01E37 /* Unarmor_NoNewline.res */, + 30A218641B5579A200D01E37 /* Unarmor_NoNewline.txt */, + 30A218651B5579A200D01E37 /* Unarmor_Normal.res */, + 30A218661B5579A200D01E37 /* Unarmor_Normal.txt */, + 30A218671B5579A200D01E37 /* Unarmor_Version.res */, + 30A218681B5579A200D01E37 /* Unarmor_Version.txt */, + 30A218691B5579A200D01E37 /* Unarmor_VersionOnline.res */, + 30A2186A1B5579A200D01E37 /* Unarmor_VersionOnline.txt */, + ); + name = Unarmor; + sourceTree = ""; + }; 30BE73BF1B54015C001A2137 /* UnitTests */ = { isa = PBXGroup; children = ( @@ -693,6 +741,7 @@ 455B17B915143D9A00FAD47D /* GPGOptionsTest.m */, 45C0BC02151B65C700AA8BF6 /* GPGTestVerify.m */, 1BE88B3D1B47D7F900A812B6 /* GPGSocketCloseTest.m */, + 30A218221B5543A500D01E37 /* GPGUnarmorTest.m */, 45C0BC13151B664D00AA8BF6 /* Resources */, 30BE73C01B54015C001A2137 /* Supporting Files */, ); @@ -756,14 +805,14 @@ 45C0BC13151B664D00AA8BF6 /* Resources */ = { isa = PBXGroup; children = ( - 30C8B38F139503A800F49AA1 /* UnitTest-Info.plist */, 45B9A7F5151C9A6D00DAD67A /* OpenPGP.asc */, 45891A40151BA1EC002D7410 /* SignedInputStringCR.txt */, 45891A3C151BA1C9002D7410 /* SignedInputStringCRLF.txt */, 45891A3D151BA1C9002D7410 /* SignedInputStringLF.txt */, + 30A2183A1B55753100D01E37 /* Unarmor */, ); name = Resources; - path = ../UnitTest/Resources; + path = ../UnitTests/Resources; sourceTree = ""; }; /* End PBXGroup section */ @@ -991,10 +1040,26 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 30A2186B1B5579A200D01E37 /* Unarmor_DoubleNewline.res in Resources */, + 30A2186C1B5579A200D01E37 /* Unarmor_DoubleNewline.txt in Resources */, + 30A218781B5579A200D01E37 /* Unarmor_Version.txt in Resources */, + 30A218701B5579A200D01E37 /* Unarmor_InvalidVersion.txt in Resources */, + 30A218721B5579A200D01E37 /* Unarmor_MissingNewline.txt in Resources */, + 30A2187A1B5579A200D01E37 /* Unarmor_VersionOnline.txt in Resources */, 30BE73DD1B541039001A2137 /* OpenPGP.asc in Resources */, + 30A218731B5579A200D01E37 /* Unarmor_NoNewline.res in Resources */, + 30A218711B5579A200D01E37 /* Unarmor_MissingNewline.res in Resources */, 30BE73DE1B541039001A2137 /* SignedInputStringCR.txt in Resources */, + 30A218791B5579A200D01E37 /* Unarmor_VersionOnline.res in Resources */, + 30A218751B5579A200D01E37 /* Unarmor_Normal.res in Resources */, 30BE73DF1B541039001A2137 /* SignedInputStringCRLF.txt in Resources */, + 30A2186F1B5579A200D01E37 /* Unarmor_InvalidVersion.res in Resources */, + 30A2186E1B5579A200D01E37 /* Unarmor_InvalidComment.txt in Resources */, + 30A218761B5579A200D01E37 /* Unarmor_Normal.txt in Resources */, + 30A218741B5579A200D01E37 /* Unarmor_NoNewline.txt in Resources */, + 30A218771B5579A200D01E37 /* Unarmor_Version.res in Resources */, 30BE73E01B541039001A2137 /* SignedInputStringLF.txt in Resources */, + 30A2186D1B5579A200D01E37 /* Unarmor_InvalidComment.res in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1165,15 +1230,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 30BE73EC1B54238F001A2137 /* GPGSocketCloseTest.m in Sources */, - 30BE73DC1B5407E3001A2137 /* GPGTestVerify.m in Sources */, - 30BE73E11B5411C2001A2137 /* GPGConfReaderTest.m in Sources */, - 30BE73E21B5411C2001A2137 /* GPGStdSettingTest.m in Sources */, - 30BE73E31B5411C2001A2137 /* GPGLinesSettingTest.m in Sources */, - 30BE73E41B5411C2001A2137 /* GPGArraySettingTest.m in Sources */, - 30BE73E51B5411C2001A2137 /* GPGDictSettingTest.m in Sources */, + 30A218231B5543A500D01E37 /* GPGUnarmorTest.m in Sources */, 30BE73EA1B541F5B001A2137 /* GPGUnitTest.m in Sources */, - 30BE73E61B5411C2001A2137 /* GPGOptionsTest.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1732,6 +1790,7 @@ 30BE73C91B54015C001A2137 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; diff --git a/UnitTest/UnitTest-Info.plist b/UnitTest/UnitTest-Info.plist deleted file mode 100644 index c285a47..0000000 --- a/UnitTest/UnitTest-Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - ${EXECUTABLE_NAME} - CFBundleIdentifier - com.yourcompany.${PRODUCT_NAME:rfc1034identifier} - CFBundleInfoDictionaryVersion - 6.0 - CFBundlePackageType - BNDL - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1 - - diff --git a/UnitTest/GPGArraySettingTest.m b/UnitTests/GPGArraySettingTest.m similarity index 100% rename from UnitTest/GPGArraySettingTest.m rename to UnitTests/GPGArraySettingTest.m diff --git a/UnitTest/GPGConfReaderTest.m b/UnitTests/GPGConfReaderTest.m similarity index 100% rename from UnitTest/GPGConfReaderTest.m rename to UnitTests/GPGConfReaderTest.m diff --git a/UnitTest/GPGDictSettingTest.m b/UnitTests/GPGDictSettingTest.m similarity index 100% rename from UnitTest/GPGDictSettingTest.m rename to UnitTests/GPGDictSettingTest.m diff --git a/UnitTest/GPGLinesSettingTest.m b/UnitTests/GPGLinesSettingTest.m similarity index 100% rename from UnitTest/GPGLinesSettingTest.m rename to UnitTests/GPGLinesSettingTest.m diff --git a/UnitTest/GPGOptionsTest.m b/UnitTests/GPGOptionsTest.m similarity index 100% rename from UnitTest/GPGOptionsTest.m rename to UnitTests/GPGOptionsTest.m diff --git a/UnitTest/GPGStdSettingTest.m b/UnitTests/GPGStdSettingTest.m similarity index 100% rename from UnitTest/GPGStdSettingTest.m rename to UnitTests/GPGStdSettingTest.m diff --git a/UnitTest/GPGTestVerify.m b/UnitTests/GPGTestVerify.m similarity index 100% rename from UnitTest/GPGTestVerify.m rename to UnitTests/GPGTestVerify.m diff --git a/UnitTests/GPGUnarmorTest.m b/UnitTests/GPGUnarmorTest.m new file mode 100644 index 0000000..a9c2968 --- /dev/null +++ b/UnitTests/GPGUnarmorTest.m @@ -0,0 +1,47 @@ +#import +#import "GPGUnitTest.h" +#import "GPGUnArmor.h" + + +@interface GPGUnArmorTest : XCTestCase +@end + +@implementation GPGUnArmorTest + + +- (void)testGPGUnArmor { + // UnArmor every "Unarmor*.txt" file and compre it with "Unarmor*.res". + + NSString *resourcePath = [[NSBundle bundleForClass:[self class]] resourcePath]; + NSFileManager *fileManager = [NSFileManager defaultManager]; + + NSArray *files = [fileManager contentsOfDirectoryAtPath:resourcePath error:nil]; + XCTAssertNotNil(files, @"Unable to find test files!"); + + + for (NSString *filename in files) { + if (filename.length >= 11 && [[filename substringToIndex:7] isEqualToString:@"Unarmor"]) { + if ([[filename substringWithRange:NSMakeRange(filename.length - 4, 4)] isEqualToString:@".txt"]) { + NSString *filePath = [resourcePath stringByAppendingPathComponent:filename]; + NSString *resPath = [[filePath substringToIndex:filePath.length - 3] stringByAppendingString:@"res"]; + NSData *expectedData = [NSData dataWithContentsOfFile:resPath]; + + GPGStream *stream = [GPGFileStream fileStreamForReadingAtPath:filePath]; + + // The method to test + NSData *unArmored = [[GPGUnArmor unArmor:stream] readAllData]; + + + if (unArmored.length == 0 || ![unArmored isEqualToData:expectedData]) { + XCTFail(@"Test %@ failed!", filename); + continue; + } + + printf("%s\n", [[NSString stringWithFormat:@"Test %@ passed.", filename] UTF8String]); + } + } + } +} + + +@end diff --git a/UnitTests/GPGUnitTest.h b/UnitTests/GPGUnitTest.h index 71ccc9b..4a4692d 100644 --- a/UnitTests/GPGUnitTest.h +++ b/UnitTests/GPGUnitTest.h @@ -15,5 +15,6 @@ extern GPGKeyManager *manager; + (void)setUpTestDirectory; + (NSData *)dataForResource:(NSString *)name; ++ (GPGStream *)streamForResource:(NSString *)name; @end diff --git a/UnitTests/GPGUnitTest.m b/UnitTests/GPGUnitTest.m index 8ce8bc6..1862555 100644 --- a/UnitTests/GPGUnitTest.m +++ b/UnitTests/GPGUnitTest.m @@ -47,6 +47,16 @@ + (NSData *)dataForResource:(NSString *)name { return data; } ++ (GPGStream *)streamForResource:(NSString *)name { + NSBundle *unitTestBundle = [NSBundle bundleForClass:[self class]]; + NSString *path = [unitTestBundle pathForResource:name ofType:@""]; + GPGFileStream *stream = [GPGFileStream fileStreamForReadingAtPath:path]; + if (!stream) { + @throw [NSException exceptionWithName:@"ApplicationException" reason:@"missing resource" userInfo:nil]; + } + return stream; +} + @end diff --git a/UnitTest/Resources/OpenPGP.asc b/UnitTests/Resources/OpenPGP.asc similarity index 100% rename from UnitTest/Resources/OpenPGP.asc rename to UnitTests/Resources/OpenPGP.asc diff --git a/UnitTest/Resources/SignedInputStringCR.txt b/UnitTests/Resources/SignedInputStringCR.txt similarity index 100% rename from UnitTest/Resources/SignedInputStringCR.txt rename to UnitTests/Resources/SignedInputStringCR.txt diff --git a/UnitTest/Resources/SignedInputStringCRLF.txt b/UnitTests/Resources/SignedInputStringCRLF.txt similarity index 100% rename from UnitTest/Resources/SignedInputStringCRLF.txt rename to UnitTests/Resources/SignedInputStringCRLF.txt diff --git a/UnitTest/Resources/SignedInputStringLF.txt b/UnitTests/Resources/SignedInputStringLF.txt similarity index 100% rename from UnitTest/Resources/SignedInputStringLF.txt rename to UnitTests/Resources/SignedInputStringLF.txt diff --git a/UnitTests/Resources/Unarmor/Unarmor_DoubleNewline.res b/UnitTests/Resources/Unarmor/Unarmor_DoubleNewline.res new file mode 100644 index 0000000000000000000000000000000000000000..a37667a00e95ad0d43012648a2bf7b1dfa876bf8 GIT binary patch literal 335 zcmV-V0kHms0Sp6DYYFiRquPQ22mq3hTc3N(WVYf7Gf12+b~pJ@+4Cb&^rR34V&|5z znNpou;aHL~FiD0nkoz5l2BsvbmTNch8Y`PGf(l|X%eS%w9ff;bQ{HNWJiH)?!K>#@N#Hes?^PqctYb9(C^V)S2h8ZS<^6e< zknJsTeU?Va(_BrI?kD+oq9T#}dK^3zbTAA3`il~rjlhH=a0dKvdsm@N$)cLhUY hZ5)b^ZeMAldi~^3a&H+d&%hlb)XCsX{-)PFaaJBPpkDw0 literal 0 HcmV?d00001 diff --git a/UnitTests/Resources/Unarmor/Unarmor_DoubleNewline.txt b/UnitTests/Resources/Unarmor/Unarmor_DoubleNewline.txt new file mode 100644 index 0000000..025b259 --- /dev/null +++ b/UnitTests/Resources/Unarmor/Unarmor_DoubleNewline.txt @@ -0,0 +1,24 @@ +-----BEGIN PGP MESSAGE----- + +Comment: GPGTools - https://gpgtools.org + + + +hQEMA1JrCfEKo9qCAQgAkpBbn3vMZLbiCTNInC52N/lQ2fMjUfSkEAVi55axmVKd + +WeFYkjIwSYYxkPsdhQamJKmWazfxGiubL4IKYjLLt7IEHYV7gO0zIQw1o4Co/QFO + +vExkgWv+JC0CRsa/uiSepmZT3mqDPLwgiMGr501J4DWB71UjvaxjNP4oNKYZB8zo + +tOX9eZaQ7S1xfZZGydNcTZTuJ/l3oiKR/HocPBV0NwoQ9iH26KH/L+xPE1cKqg0W + +BwK+y694cZMR6bmwpoqolwTHT8v1cV2JqX4V2afVcOdqAQyk4ZdVOYBbSL+2mt+C + +ESdIdp3V8zT6+Y6MgzusjdicumXop1KGGvpbpxSYJdI+ASGXpCWJRv01UODdtB5B + +xYZxy+Z6GfdVmC0NHHcFQ2JtHIqPbl9ponr95FBybxksz8AdItTJ4Ez+ptc8cVY= + +=Pp5D + +-----END PGP MESSAGE----- + diff --git a/UnitTests/Resources/Unarmor/Unarmor_InvalidComment.res b/UnitTests/Resources/Unarmor/Unarmor_InvalidComment.res new file mode 100644 index 0000000000000000000000000000000000000000..a37667a00e95ad0d43012648a2bf7b1dfa876bf8 GIT binary patch literal 335 zcmV-V0kHms0Sp6DYYFiRquPQ22mq3hTc3N(WVYf7Gf12+b~pJ@+4Cb&^rR34V&|5z znNpou;aHL~FiD0nkoz5l2BsvbmTNch8Y`PGf(l|X%eS%w9ff;bQ{HNWJiH)?!K>#@N#Hes?^PqctYb9(C^V)S2h8ZS<^6e< zknJsTeU?Va(_BrI?kD+oq9T#}dK^3zbTAA3`il~rjlhH=a0dKvdsm@N$)cLhUY hZ5)b^ZeMAldi~^3a&H+d&%hlb)XCsX{-)PFaaJBPpkDw0 literal 0 HcmV?d00001 diff --git a/UnitTests/Resources/Unarmor/Unarmor_InvalidComment.txt b/UnitTests/Resources/Unarmor/Unarmor_InvalidComment.txt new file mode 100644 index 0000000..217c045 --- /dev/null +++ b/UnitTests/Resources/Unarmor/Unarmor_InvalidComment.txt @@ -0,0 +1,12 @@ +-----BEGIN PGP MESSAGE----- +Comment GPGTools - https://gpgtools.org + +hQEMA1JrCfEKo9qCAQgAkpBbn3vMZLbiCTNInC52N/lQ2fMjUfSkEAVi55axmVKd +WeFYkjIwSYYxkPsdhQamJKmWazfxGiubL4IKYjLLt7IEHYV7gO0zIQw1o4Co/QFO +vExkgWv+JC0CRsa/uiSepmZT3mqDPLwgiMGr501J4DWB71UjvaxjNP4oNKYZB8zo +tOX9eZaQ7S1xfZZGydNcTZTuJ/l3oiKR/HocPBV0NwoQ9iH26KH/L+xPE1cKqg0W +BwK+y694cZMR6bmwpoqolwTHT8v1cV2JqX4V2afVcOdqAQyk4ZdVOYBbSL+2mt+C +ESdIdp3V8zT6+Y6MgzusjdicumXop1KGGvpbpxSYJdI+ASGXpCWJRv01UODdtB5B +xYZxy+Z6GfdVmC0NHHcFQ2JtHIqPbl9ponr95FBybxksz8AdItTJ4Ez+ptc8cVY= +=Pp5D +-----END PGP MESSAGE----- diff --git a/UnitTests/Resources/Unarmor/Unarmor_InvalidVersion.res b/UnitTests/Resources/Unarmor/Unarmor_InvalidVersion.res new file mode 100644 index 0000000000000000000000000000000000000000..a37667a00e95ad0d43012648a2bf7b1dfa876bf8 GIT binary patch literal 335 zcmV-V0kHms0Sp6DYYFiRquPQ22mq3hTc3N(WVYf7Gf12+b~pJ@+4Cb&^rR34V&|5z znNpou;aHL~FiD0nkoz5l2BsvbmTNch8Y`PGf(l|X%eS%w9ff;bQ{HNWJiH)?!K>#@N#Hes?^PqctYb9(C^V)S2h8ZS<^6e< zknJsTeU?Va(_BrI?kD+oq9T#}dK^3zbTAA3`il~rjlhH=a0dKvdsm@N$)cLhUY hZ5)b^ZeMAldi~^3a&H+d&%hlb)XCsX{-)PFaaJBPpkDw0 literal 0 HcmV?d00001 diff --git a/UnitTests/Resources/Unarmor/Unarmor_InvalidVersion.txt b/UnitTests/Resources/Unarmor/Unarmor_InvalidVersion.txt new file mode 100644 index 0000000..337abe9 --- /dev/null +++ b/UnitTests/Resources/Unarmor/Unarmor_InvalidVersion.txt @@ -0,0 +1,12 @@ +-----BEGIN PGP MESSAGE----- +Version GnuPG v2 + +hQEMA1JrCfEKo9qCAQgAkpBbn3vMZLbiCTNInC52N/lQ2fMjUfSkEAVi55axmVKd +WeFYkjIwSYYxkPsdhQamJKmWazfxGiubL4IKYjLLt7IEHYV7gO0zIQw1o4Co/QFO +vExkgWv+JC0CRsa/uiSepmZT3mqDPLwgiMGr501J4DWB71UjvaxjNP4oNKYZB8zo +tOX9eZaQ7S1xfZZGydNcTZTuJ/l3oiKR/HocPBV0NwoQ9iH26KH/L+xPE1cKqg0W +BwK+y694cZMR6bmwpoqolwTHT8v1cV2JqX4V2afVcOdqAQyk4ZdVOYBbSL+2mt+C +ESdIdp3V8zT6+Y6MgzusjdicumXop1KGGvpbpxSYJdI+ASGXpCWJRv01UODdtB5B +xYZxy+Z6GfdVmC0NHHcFQ2JtHIqPbl9ponr95FBybxksz8AdItTJ4Ez+ptc8cVY= +=Pp5D +-----END PGP MESSAGE----- diff --git a/UnitTests/Resources/Unarmor/Unarmor_MissingNewline.res b/UnitTests/Resources/Unarmor/Unarmor_MissingNewline.res new file mode 100644 index 0000000000000000000000000000000000000000..a37667a00e95ad0d43012648a2bf7b1dfa876bf8 GIT binary patch literal 335 zcmV-V0kHms0Sp6DYYFiRquPQ22mq3hTc3N(WVYf7Gf12+b~pJ@+4Cb&^rR34V&|5z znNpou;aHL~FiD0nkoz5l2BsvbmTNch8Y`PGf(l|X%eS%w9ff;bQ{HNWJiH)?!K>#@N#Hes?^PqctYb9(C^V)S2h8ZS<^6e< zknJsTeU?Va(_BrI?kD+oq9T#}dK^3zbTAA3`il~rjlhH=a0dKvdsm@N$)cLhUY hZ5)b^ZeMAldi~^3a&H+d&%hlb)XCsX{-)PFaaJBPpkDw0 literal 0 HcmV?d00001 diff --git a/UnitTests/Resources/Unarmor/Unarmor_MissingNewline.txt b/UnitTests/Resources/Unarmor/Unarmor_MissingNewline.txt new file mode 100644 index 0000000..de70797 --- /dev/null +++ b/UnitTests/Resources/Unarmor/Unarmor_MissingNewline.txt @@ -0,0 +1,11 @@ +-----BEGIN PGP MESSAGE----- +Comment: GPGTools - https://gpgtools.org +hQEMA1JrCfEKo9qCAQgAkpBbn3vMZLbiCTNInC52N/lQ2fMjUfSkEAVi55axmVKd +WeFYkjIwSYYxkPsdhQamJKmWazfxGiubL4IKYjLLt7IEHYV7gO0zIQw1o4Co/QFO +vExkgWv+JC0CRsa/uiSepmZT3mqDPLwgiMGr501J4DWB71UjvaxjNP4oNKYZB8zo +tOX9eZaQ7S1xfZZGydNcTZTuJ/l3oiKR/HocPBV0NwoQ9iH26KH/L+xPE1cKqg0W +BwK+y694cZMR6bmwpoqolwTHT8v1cV2JqX4V2afVcOdqAQyk4ZdVOYBbSL+2mt+C +ESdIdp3V8zT6+Y6MgzusjdicumXop1KGGvpbpxSYJdI+ASGXpCWJRv01UODdtB5B +xYZxy+Z6GfdVmC0NHHcFQ2JtHIqPbl9ponr95FBybxksz8AdItTJ4Ez+ptc8cVY= +=Pp5D +-----END PGP MESSAGE----- diff --git a/UnitTests/Resources/Unarmor/Unarmor_NoNewline.res b/UnitTests/Resources/Unarmor/Unarmor_NoNewline.res new file mode 100644 index 0000000000000000000000000000000000000000..a37667a00e95ad0d43012648a2bf7b1dfa876bf8 GIT binary patch literal 335 zcmV-V0kHms0Sp6DYYFiRquPQ22mq3hTc3N(WVYf7Gf12+b~pJ@+4Cb&^rR34V&|5z znNpou;aHL~FiD0nkoz5l2BsvbmTNch8Y`PGf(l|X%eS%w9ff;bQ{HNWJiH)?!K>#@N#Hes?^PqctYb9(C^V)S2h8ZS<^6e< zknJsTeU?Va(_BrI?kD+oq9T#}dK^3zbTAA3`il~rjlhH=a0dKvdsm@N$)cLhUY hZ5)b^ZeMAldi~^3a&H+d&%hlb)XCsX{-)PFaaJBPpkDw0 literal 0 HcmV?d00001 diff --git a/UnitTests/Resources/Unarmor/Unarmor_NoNewline.txt b/UnitTests/Resources/Unarmor/Unarmor_NoNewline.txt new file mode 100644 index 0000000..ad75515 --- /dev/null +++ b/UnitTests/Resources/Unarmor/Unarmor_NoNewline.txt @@ -0,0 +1 @@ +-----BEGIN PGP MESSAGE----- Comment: GPGTools - https://gpgtools.org hQEMA1JrCfEKo9qCAQgAkpBbn3vMZLbiCTNInC52N/lQ2fMjUfSkEAVi55axmVKd WeFYkjIwSYYxkPsdhQamJKmWazfxGiubL4IKYjLLt7IEHYV7gO0zIQw1o4Co/QFO vExkgWv+JC0CRsa/uiSepmZT3mqDPLwgiMGr501J4DWB71UjvaxjNP4oNKYZB8zo tOX9eZaQ7S1xfZZGydNcTZTuJ/l3oiKR/HocPBV0NwoQ9iH26KH/L+xPE1cKqg0W BwK+y694cZMR6bmwpoqolwTHT8v1cV2JqX4V2afVcOdqAQyk4ZdVOYBbSL+2mt+C ESdIdp3V8zT6+Y6MgzusjdicumXop1KGGvpbpxSYJdI+ASGXpCWJRv01UODdtB5B xYZxy+Z6GfdVmC0NHHcFQ2JtHIqPbl9ponr95FBybxksz8AdItTJ4Ez+ptc8cVY= =Pp5D -----END PGP MESSAGE----- \ No newline at end of file diff --git a/UnitTests/Resources/Unarmor/Unarmor_Normal.res b/UnitTests/Resources/Unarmor/Unarmor_Normal.res new file mode 100644 index 0000000000000000000000000000000000000000..a37667a00e95ad0d43012648a2bf7b1dfa876bf8 GIT binary patch literal 335 zcmV-V0kHms0Sp6DYYFiRquPQ22mq3hTc3N(WVYf7Gf12+b~pJ@+4Cb&^rR34V&|5z znNpou;aHL~FiD0nkoz5l2BsvbmTNch8Y`PGf(l|X%eS%w9ff;bQ{HNWJiH)?!K>#@N#Hes?^PqctYb9(C^V)S2h8ZS<^6e< zknJsTeU?Va(_BrI?kD+oq9T#}dK^3zbTAA3`il~rjlhH=a0dKvdsm@N$)cLhUY hZ5)b^ZeMAldi~^3a&H+d&%hlb)XCsX{-)PFaaJBPpkDw0 literal 0 HcmV?d00001 diff --git a/UnitTests/Resources/Unarmor/Unarmor_Normal.txt b/UnitTests/Resources/Unarmor/Unarmor_Normal.txt new file mode 100644 index 0000000..2165dde --- /dev/null +++ b/UnitTests/Resources/Unarmor/Unarmor_Normal.txt @@ -0,0 +1,12 @@ +-----BEGIN PGP MESSAGE----- +Comment: GPGTools - https://gpgtools.org + +hQEMA1JrCfEKo9qCAQgAkpBbn3vMZLbiCTNInC52N/lQ2fMjUfSkEAVi55axmVKd +WeFYkjIwSYYxkPsdhQamJKmWazfxGiubL4IKYjLLt7IEHYV7gO0zIQw1o4Co/QFO +vExkgWv+JC0CRsa/uiSepmZT3mqDPLwgiMGr501J4DWB71UjvaxjNP4oNKYZB8zo +tOX9eZaQ7S1xfZZGydNcTZTuJ/l3oiKR/HocPBV0NwoQ9iH26KH/L+xPE1cKqg0W +BwK+y694cZMR6bmwpoqolwTHT8v1cV2JqX4V2afVcOdqAQyk4ZdVOYBbSL+2mt+C +ESdIdp3V8zT6+Y6MgzusjdicumXop1KGGvpbpxSYJdI+ASGXpCWJRv01UODdtB5B +xYZxy+Z6GfdVmC0NHHcFQ2JtHIqPbl9ponr95FBybxksz8AdItTJ4Ez+ptc8cVY= +=Pp5D +-----END PGP MESSAGE----- diff --git a/UnitTests/Resources/Unarmor/Unarmor_Version.res b/UnitTests/Resources/Unarmor/Unarmor_Version.res new file mode 100644 index 0000000000000000000000000000000000000000..a37667a00e95ad0d43012648a2bf7b1dfa876bf8 GIT binary patch literal 335 zcmV-V0kHms0Sp6DYYFiRquPQ22mq3hTc3N(WVYf7Gf12+b~pJ@+4Cb&^rR34V&|5z znNpou;aHL~FiD0nkoz5l2BsvbmTNch8Y`PGf(l|X%eS%w9ff;bQ{HNWJiH)?!K>#@N#Hes?^PqctYb9(C^V)S2h8ZS<^6e< zknJsTeU?Va(_BrI?kD+oq9T#}dK^3zbTAA3`il~rjlhH=a0dKvdsm@N$)cLhUY hZ5)b^ZeMAldi~^3a&H+d&%hlb)XCsX{-)PFaaJBPpkDw0 literal 0 HcmV?d00001 diff --git a/UnitTests/Resources/Unarmor/Unarmor_Version.txt b/UnitTests/Resources/Unarmor/Unarmor_Version.txt new file mode 100644 index 0000000..433268c --- /dev/null +++ b/UnitTests/Resources/Unarmor/Unarmor_Version.txt @@ -0,0 +1,12 @@ +-----BEGIN PGP MESSAGE----- +Version: GnuPG v2 + +hQEMA1JrCfEKo9qCAQgAkpBbn3vMZLbiCTNInC52N/lQ2fMjUfSkEAVi55axmVKd +WeFYkjIwSYYxkPsdhQamJKmWazfxGiubL4IKYjLLt7IEHYV7gO0zIQw1o4Co/QFO +vExkgWv+JC0CRsa/uiSepmZT3mqDPLwgiMGr501J4DWB71UjvaxjNP4oNKYZB8zo +tOX9eZaQ7S1xfZZGydNcTZTuJ/l3oiKR/HocPBV0NwoQ9iH26KH/L+xPE1cKqg0W +BwK+y694cZMR6bmwpoqolwTHT8v1cV2JqX4V2afVcOdqAQyk4ZdVOYBbSL+2mt+C +ESdIdp3V8zT6+Y6MgzusjdicumXop1KGGvpbpxSYJdI+ASGXpCWJRv01UODdtB5B +xYZxy+Z6GfdVmC0NHHcFQ2JtHIqPbl9ponr95FBybxksz8AdItTJ4Ez+ptc8cVY= +=Pp5D +-----END PGP MESSAGE----- diff --git a/UnitTests/Resources/Unarmor/Unarmor_VersionOnline.res b/UnitTests/Resources/Unarmor/Unarmor_VersionOnline.res new file mode 100644 index 0000000000000000000000000000000000000000..a37667a00e95ad0d43012648a2bf7b1dfa876bf8 GIT binary patch literal 335 zcmV-V0kHms0Sp6DYYFiRquPQ22mq3hTc3N(WVYf7Gf12+b~pJ@+4Cb&^rR34V&|5z znNpou;aHL~FiD0nkoz5l2BsvbmTNch8Y`PGf(l|X%eS%w9ff;bQ{HNWJiH)?!K>#@N#Hes?^PqctYb9(C^V)S2h8ZS<^6e< zknJsTeU?Va(_BrI?kD+oq9T#}dK^3zbTAA3`il~rjlhH=a0dKvdsm@N$)cLhUY hZ5)b^ZeMAldi~^3a&H+d&%hlb)XCsX{-)PFaaJBPpkDw0 literal 0 HcmV?d00001 diff --git a/UnitTests/Resources/Unarmor/Unarmor_VersionOnline.txt b/UnitTests/Resources/Unarmor/Unarmor_VersionOnline.txt new file mode 100644 index 0000000..e138e1e --- /dev/null +++ b/UnitTests/Resources/Unarmor/Unarmor_VersionOnline.txt @@ -0,0 +1,12 @@ +-----BEGIN PGP MESSAGE----- Version: OpenPGP.js v.1.20121015 + +Comment: http://openpgpjs.org + +hQEMA1JrCfEKo9qCAQgAkpBbn3vMZLbiCTNInC52N/lQ2fMjUfSkEAVi55axmVKd +WeFYkjIwSYYxkPsdhQamJKmWazfxGiubL4IKYjLLt7IEHYV7gO0zIQw1o4Co/QFO +vExkgWv+JC0CRsa/uiSepmZT3mqDPLwgiMGr501J4DWB71UjvaxjNP4oNKYZB8zo +tOX9eZaQ7S1xfZZGydNcTZTuJ/l3oiKR/HocPBV0NwoQ9iH26KH/L+xPE1cKqg0W +BwK+y694cZMR6bmwpoqolwTHT8v1cV2JqX4V2afVcOdqAQyk4ZdVOYBbSL+2mt+C +ESdIdp3V8zT6+Y6MgzusjdicumXop1KGGvpbpxSYJdI+ASGXpCWJRv01UODdtB5B +xYZxy+Z6GfdVmC0NHHcFQ2JtHIqPbl9ponr95FBybxksz8AdItTJ4Ez+ptc8cVY= +-----END PGP MESSAGE----- From 696aa0a2d2bec268eaffdd9b0e30b0b70bc15328 Mon Sep 17 00:00:00 2001 From: Mento Date: Wed, 15 Jul 2015 13:15:18 +0200 Subject: [PATCH 36/56] GPGPacket unit test added. --- Libmacgpg.xcodeproj/project.pbxproj | 22 +++- UnitTests/GPGPacketTest.m | 109 ++++++++++++++++++ UnitTests/Resources/GPGPacket/compressed1.gpg | Bin 0 -> 17 bytes UnitTests/Resources/GPGPacket/key1.gpg | Bin 0 -> 1504 bytes 4 files changed, 129 insertions(+), 2 deletions(-) create mode 100644 UnitTests/GPGPacketTest.m create mode 100644 UnitTests/Resources/GPGPacket/compressed1.gpg create mode 100644 UnitTests/Resources/GPGPacket/key1.gpg diff --git a/Libmacgpg.xcodeproj/project.pbxproj b/Libmacgpg.xcodeproj/project.pbxproj index b73137e..4a135bd 100644 --- a/Libmacgpg.xcodeproj/project.pbxproj +++ b/Libmacgpg.xcodeproj/project.pbxproj @@ -68,6 +68,9 @@ 30516558142281270038AAF0 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 30516556142281270038AAF0 /* Localizable.strings */; }; 30691AA4136AECC4004AA469 /* GPGOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 30691AA2136AECC4004AA469 /* GPGOptions.h */; settings = {ATTRIBUTES = (Public, ); }; }; 30691AA5136AECC4004AA469 /* GPGOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 30691AA3136AECC4004AA469 /* GPGOptions.m */; }; + 3075ADD61B566D0900A5F89A /* GPGPacketTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 3075ADD51B566D0900A5F89A /* GPGPacketTest.m */; }; + 3075ADDB1B5675D200A5F89A /* key1.gpg in Resources */ = {isa = PBXBuildFile; fileRef = 3075ADDA1B5675B500A5F89A /* key1.gpg */; }; + 3075ADDD1B56760F00A5F89A /* compressed1.gpg in Resources */ = {isa = PBXBuildFile; fileRef = 3075ADDC1B56760F00A5F89A /* compressed1.gpg */; }; 307C211C1B1745F5006B07A7 /* gpgtools.icns in Resources */ = {isa = PBXBuildFile; fileRef = 307C211B1B1745F5006B07A7 /* gpgtools.icns */; }; 307FDE421B4E636A00462E4E /* GPGCompressedDataPacket.h in Headers */ = {isa = PBXBuildFile; fileRef = 307FDE401B4E636A00462E4E /* GPGCompressedDataPacket.h */; settings = {ATTRIBUTES = (Public, ); }; }; 307FDE431B4E636A00462E4E /* GPGCompressedDataPacket.m in Sources */ = {isa = PBXBuildFile; fileRef = 307FDE411B4E636A00462E4E /* GPGCompressedDataPacket.m */; }; @@ -75,7 +78,6 @@ 309A18D113E3812E0069DC0F /* GPGTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 309A18CF13E3812E0069DC0F /* GPGTransformer.m */; }; 30A058391799E2DC00E1AD20 /* GPGKeyManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 30A058371799E2DC00E1AD20 /* GPGKeyManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; 30A0583A1799E2DC00E1AD20 /* GPGKeyManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 30A058381799E2DC00E1AD20 /* GPGKeyManager.m */; }; - 30A218231B5543A500D01E37 /* GPGUnarmorTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 30A218221B5543A500D01E37 /* GPGUnarmorTest.m */; }; 30A2186B1B5579A200D01E37 /* Unarmor_DoubleNewline.res in Resources */ = {isa = PBXBuildFile; fileRef = 30A2185B1B5579A200D01E37 /* Unarmor_DoubleNewline.res */; }; 30A2186C1B5579A200D01E37 /* Unarmor_DoubleNewline.txt in Resources */ = {isa = PBXBuildFile; fileRef = 30A2185C1B5579A200D01E37 /* Unarmor_DoubleNewline.txt */; }; 30A2186D1B5579A200D01E37 /* Unarmor_InvalidComment.res in Resources */ = {isa = PBXBuildFile; fileRef = 30A2185D1B5579A200D01E37 /* Unarmor_InvalidComment.res */; }; @@ -265,6 +267,9 @@ 3059AF1014239FAB00AD5B30 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; 30691AA2136AECC4004AA469 /* GPGOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGOptions.h; sourceTree = ""; }; 30691AA3136AECC4004AA469 /* GPGOptions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGOptions.m; sourceTree = ""; }; + 3075ADD51B566D0900A5F89A /* GPGPacketTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGPacketTest.m; sourceTree = ""; }; + 3075ADDA1B5675B500A5F89A /* key1.gpg */ = {isa = PBXFileReference; lastKnownFileType = file; path = key1.gpg; sourceTree = ""; }; + 3075ADDC1B56760F00A5F89A /* compressed1.gpg */ = {isa = PBXFileReference; lastKnownFileType = file; path = compressed1.gpg; sourceTree = ""; }; 3077AE881A6547D2001EC508 /* SecurityFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SecurityFoundation.framework; path = System/Library/Frameworks/SecurityFoundation.framework; sourceTree = SDKROOT; }; 307C211B1B1745F5006B07A7 /* gpgtools.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = gpgtools.icns; path = Resources/gpgtools.icns; sourceTree = SOURCE_ROOT; }; 307D79101340B71A005C9C32 /* TODO */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = TODO; sourceTree = ""; }; @@ -682,6 +687,15 @@ name = GPGStream; sourceTree = ""; }; + 3075ADD71B566E9A00A5F89A /* GPGPacket */ = { + isa = PBXGroup; + children = ( + 3075ADDA1B5675B500A5F89A /* key1.gpg */, + 3075ADDC1B56760F00A5F89A /* compressed1.gpg */, + ); + path = GPGPacket; + sourceTree = ""; + }; 307FAABB13F26BB4003FA99B /* GPGOptions */ = { isa = PBXGroup; children = ( @@ -739,6 +753,7 @@ 45156A2C14FB506E00129FE7 /* GPGArraySettingTest.m */, 45156A2614FB35DC00129FE7 /* GPGDictSettingTest.m */, 455B17B915143D9A00FAD47D /* GPGOptionsTest.m */, + 3075ADD51B566D0900A5F89A /* GPGPacketTest.m */, 45C0BC02151B65C700AA8BF6 /* GPGTestVerify.m */, 1BE88B3D1B47D7F900A812B6 /* GPGSocketCloseTest.m */, 30A218221B5543A500D01E37 /* GPGUnarmorTest.m */, @@ -810,6 +825,7 @@ 45891A3C151BA1C9002D7410 /* SignedInputStringCRLF.txt */, 45891A3D151BA1C9002D7410 /* SignedInputStringLF.txt */, 30A2183A1B55753100D01E37 /* Unarmor */, + 3075ADD71B566E9A00A5F89A /* GPGPacket */, ); name = Resources; path = ../UnitTests/Resources; @@ -1043,6 +1059,7 @@ 30A2186B1B5579A200D01E37 /* Unarmor_DoubleNewline.res in Resources */, 30A2186C1B5579A200D01E37 /* Unarmor_DoubleNewline.txt in Resources */, 30A218781B5579A200D01E37 /* Unarmor_Version.txt in Resources */, + 3075ADDD1B56760F00A5F89A /* compressed1.gpg in Resources */, 30A218701B5579A200D01E37 /* Unarmor_InvalidVersion.txt in Resources */, 30A218721B5579A200D01E37 /* Unarmor_MissingNewline.txt in Resources */, 30A2187A1B5579A200D01E37 /* Unarmor_VersionOnline.txt in Resources */, @@ -1060,6 +1077,7 @@ 30A218771B5579A200D01E37 /* Unarmor_Version.res in Resources */, 30BE73E01B541039001A2137 /* SignedInputStringLF.txt in Resources */, 30A2186D1B5579A200D01E37 /* Unarmor_InvalidComment.res in Resources */, + 3075ADDB1B5675D200A5F89A /* key1.gpg in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1230,8 +1248,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 30A218231B5543A500D01E37 /* GPGUnarmorTest.m in Sources */, 30BE73EA1B541F5B001A2137 /* GPGUnitTest.m in Sources */, + 3075ADD61B566D0900A5F89A /* GPGPacketTest.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/UnitTests/GPGPacketTest.m b/UnitTests/GPGPacketTest.m new file mode 100644 index 0000000..29057f3 --- /dev/null +++ b/UnitTests/GPGPacketTest.m @@ -0,0 +1,109 @@ +#import +#import "GPGUnitTest.h" + + +@interface GPGPacketTest : XCTestCase +@end + +@implementation GPGPacketTest + + +- (void)testKey1 { + GPGStream *stream = [GPGUnitTest streamForResource:@"key1.gpg"]; + GPGPacketParser *parser = [GPGPacketParser packetParserWithStream:stream]; + GPGPacket *packet; + NSUInteger i = 0; + + NSArray *conditionList = @[ + @{@"fingerprint": @"77270A31BEE39087C6B7E771F988A4590DB03A7D", + @"keyID": @"F988A4590DB03A7D", + @"version": @4, + @"creationDate": [NSDate dateWithTimeIntervalSince1970:1313104392], + @"publicAlgorithm": @1}, + @{@"userID": @"GPGTools Test Key (For testing purposes only!) "}, + @{@"keyID": @"F988A4590DB03A7D", + @"version": @4, + @"creationDate": [NSDate dateWithTimeIntervalSince1970:1313104392], + @"publicAlgorithm": @1, + @"hashStart": @65285, + @"type": @19, + @"hashAlgorithm": @2}, + @{@"fingerprint": @"30BD46FC8599CB334466CFC5526B09F10AA3DA82", + @"keyID": @"526B09F10AA3DA82", + @"version": @4, + @"creationDate": [NSDate dateWithTimeIntervalSince1970:1313104392], + @"publicAlgorithm": @1}, + @{@"keyID": @"F988A4590DB03A7D", + @"version": @4, + @"creationDate": [NSDate dateWithTimeIntervalSince1970:1313104392], + @"publicAlgorithm": @1, + @"hashStart": @63416, + @"type": @24, + @"hashAlgorithm": @2} + ]; + + + + while ((packet = [parser nextPacket])) { + if (i >= conditionList.count) { + XCTFail(@"Too many packets parsed! (%lu > %lu)", i+1, conditionList.count); + break; + } + + NSDictionary *conditions = conditionList[i]; + for (NSString *key in conditions) { + id expectedValue = conditions[key]; + id value = [packet valueForKey:key]; + + XCTAssertEqualObjects(expectedValue, value, @"Wrong value returned by GPGPacket."); + } + + i++; + } + + if (i < conditionList.count) { + XCTFail(@"Not enough packets parsed! (%lu < %lu)", i, conditionList.count); + } +} + + +- (void)testCompressed { + GPGStream *stream = [GPGUnitTest streamForResource:@"compressed1.gpg"]; + GPGPacketParser *parser = [GPGPacketParser packetParserWithStream:stream]; + GPGPacket *packet; + NSUInteger i = 0; + + NSArray *conditionList = @[ + @{@"format": @98, + @"filename": @"tv", + @"date": [NSDate dateWithTimeIntervalSince1970:1436958747], + @"content": [NSData dataWithBytes:"ok\n" length:3]}, + ]; + + while ((packet = [parser nextPacket])) { + if (i >= conditionList.count) { + XCTFail(@"Too many packets parsed! (%lu > %lu)", i+1, conditionList.count); + break; + } + + NSDictionary *conditions = conditionList[i]; + for (NSString *key in conditions) { + id expectedValue = conditions[key]; + id value = [packet valueForKey:key]; + + XCTAssertEqualObjects(expectedValue, value, @"Wrong value returned by GPGPacket."); + } + + i++; + } + + if (i < conditionList.count) { + XCTFail(@"Not enough packets parsed! (%lu < %lu)", i, conditionList.count); + } + +} + + + + +@end diff --git a/UnitTests/Resources/GPGPacket/compressed1.gpg b/UnitTests/Resources/GPGPacket/compressed1.gpg new file mode 100644 index 0000000000000000000000000000000000000000..402cf55214c603fc71ac44bf6d8fe4254341306a GIT binary patch literal 17 ZcmZ3?Xnl6>k&qy}PW`002Wx2Cx7C literal 0 HcmV?d00001 diff --git a/UnitTests/Resources/GPGPacket/key1.gpg b/UnitTests/Resources/GPGPacket/key1.gpg new file mode 100644 index 0000000000000000000000000000000000000000..c41737110518d566089f688111ad8e129b1da6e8 GIT binary patch literal 1504 zcmV<61t0pE0SyFBL}Ca52mt14bnYc#0LVq5_eYYhvq%wwi+kO+rwNrR5<&@f=WX?L z)8`w8xINfA?cR>imXUo5%M5Dk7JjUprZa0WrWsxN$Kg5*PI-1r6I#EZHAu-18b3Bi ztuzC?1U;{GskhX1P|OK=*)O~?ie$~{GaFO6@F0r?NYSVWCm_~7NHBtTFjL3d)BEmOM_#NE(CKO zPp-X(s}am>L(47QzVJx2?aD<|JklXlgZ+$VGb0zSq-d7YRG;+~#^N@W$_wic3wP%~ zOTxytU}&t4_44-MmA zaCLHUZ*ygHAa8DLc_AqvJalDqbU25SGY~S6_{)$6tEl|n#p~)#OuJP%?mUvv z64D6Kf`Pd`Lys9iBop+v`=0vY2cSqb6^+(Q&1);2?jOBLrWE0X9Okr?b1m~?q8NaY z)LP#j>VKg89P7zKin0qUx1T=aMa$l^vCzZJ36z<4E*qo6u(KeeXK-aui{?#)&+os( zcNwLI2`qW_h!O~+GHFv3gTz^7<#so{u7+rmuTw3B)s3$b1DDUFSCuZH=nss+pLW5S zh9)5sLtb=dRnI7Z4ZT0ChE8zx1Yq^Evo(bto#TW zN=9C_L^i|Hz#H60-)P!MWD}!gYwH48PHr7pk|iTx#JTv|`vauWNxL-s_TQ1q&lcpz zNT~_*oCWj=c8EPohkrAp(kaYueUGMXE?3T!Qa{P#9f>#+tXGWnt4?;0d)5?Z5hu+LTwOv(@u=)n=z%a_EJzzdf&v*Xu`ITdj3gWb^C(!u zBobPnmEx#6ULg28H}6D@Z0&(r@^I{o7UhhFK}EjGD8~(DV?8JAdo!U!u>cVP00D^t zJ_Hy60ssjG0!~C?2m%`}0VxR(`G}-h4X`?Wz+E5&836(S1_c66L}Ca43JDNWYYFiR zquPQbNeBS9AB5jpyFQVsB4mC4^L}xST^Z$3S`_X{fQ;TA4J;C)kO^X+AONZP8aQe} z`LEe?-=-CdxB9ol(n_tl$^Z3?(2m*TC~flAk?^pV?gX#2?JeE)7@_bm*x~FU)RVaw zEk~ItvX;~I@IIVIHDFuKRuu*>ATVSm%DW zb=Vbtj4SoYov^S#{{_QRD&hq60&)Ms$frxEnm@J5dX>P>33KFnWEO+Y5G`o7e518v zcMRY6xCj4yQZrnh+y_p|YJ&Kp9H}#M8>UQlw)HF2PP<~Fr5sdARASd5sjlys=;U>b za-z_1$RsS|V6oLddmv##M#`i(Il!&Sw`YcIJ=|F65R>TL+U`uPi9aEf~DBs$-&i$$zxbL7384{?KznM z%Y937t6n+yN9jHZKQiadl1p8ZX3MY_4h#8wtdu00 Date: Wed, 15 Jul 2015 17:40:23 +0200 Subject: [PATCH 37/56] Run all unit tests. --- Libmacgpg.xcodeproj/project.pbxproj | 48 +++++++++++------------------ 1 file changed, 18 insertions(+), 30 deletions(-) diff --git a/Libmacgpg.xcodeproj/project.pbxproj b/Libmacgpg.xcodeproj/project.pbxproj index 4a135bd..e0a20be 100644 --- a/Libmacgpg.xcodeproj/project.pbxproj +++ b/Libmacgpg.xcodeproj/project.pbxproj @@ -71,6 +71,15 @@ 3075ADD61B566D0900A5F89A /* GPGPacketTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 3075ADD51B566D0900A5F89A /* GPGPacketTest.m */; }; 3075ADDB1B5675D200A5F89A /* key1.gpg in Resources */ = {isa = PBXBuildFile; fileRef = 3075ADDA1B5675B500A5F89A /* key1.gpg */; }; 3075ADDD1B56760F00A5F89A /* compressed1.gpg in Resources */ = {isa = PBXBuildFile; fileRef = 3075ADDC1B56760F00A5F89A /* compressed1.gpg */; }; + 307698C81B56B61500566B20 /* GPGConfReaderTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4591C4C914F85AA3007F6D47 /* GPGConfReaderTest.m */; }; + 307698C91B56B61500566B20 /* GPGStdSettingTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4547646514FBC8A900A37306 /* GPGStdSettingTest.m */; }; + 307698CA1B56B61500566B20 /* GPGLinesSettingTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 45156A2314FB310300129FE7 /* GPGLinesSettingTest.m */; }; + 307698CB1B56B61500566B20 /* GPGArraySettingTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 45156A2C14FB506E00129FE7 /* GPGArraySettingTest.m */; }; + 307698CC1B56B61500566B20 /* GPGDictSettingTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 45156A2614FB35DC00129FE7 /* GPGDictSettingTest.m */; }; + 307698CD1B56B61500566B20 /* GPGOptionsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 455B17B915143D9A00FAD47D /* GPGOptionsTest.m */; }; + 307698CE1B56B61500566B20 /* GPGTestVerify.m in Sources */ = {isa = PBXBuildFile; fileRef = 45C0BC02151B65C700AA8BF6 /* GPGTestVerify.m */; }; + 307698CF1B56B61500566B20 /* GPGSocketCloseTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1BE88B3D1B47D7F900A812B6 /* GPGSocketCloseTest.m */; }; + 307698D01B56B61500566B20 /* GPGUnarmorTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 30A218221B5543A500D01E37 /* GPGUnarmorTest.m */; }; 307C211C1B1745F5006B07A7 /* gpgtools.icns in Resources */ = {isa = PBXBuildFile; fileRef = 307C211B1B1745F5006B07A7 /* gpgtools.icns */; }; 307FDE421B4E636A00462E4E /* GPGCompressedDataPacket.h in Headers */ = {isa = PBXBuildFile; fileRef = 307FDE401B4E636A00462E4E /* GPGCompressedDataPacket.h */; settings = {ATTRIBUTES = (Public, ); }; }; 307FDE431B4E636A00462E4E /* GPGCompressedDataPacket.m in Sources */ = {isa = PBXBuildFile; fileRef = 307FDE411B4E636A00462E4E /* GPGCompressedDataPacket.m */; }; @@ -256,9 +265,6 @@ 30444C181A65E0590052CB94 /* GPGTools.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = GPGTools.app; sourceTree = BUILT_PRODUCTS_DIR; }; 30444C1C1A65E0590052CB94 /* installerHelper-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "installerHelper-Info.plist"; sourceTree = ""; }; 30444C331A65E0590052CB94 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; - 30444C3A1A65E0590052CB94 /* installerHelperTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "installerHelperTests-Info.plist"; sourceTree = ""; }; - 30444C3C1A65E0590052CB94 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; - 30444C3E1A65E0590052CB94 /* installerHelperTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = installerHelperTests.m; sourceTree = ""; }; 304883091462B11700F2E5F4 /* DirectoryWatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DirectoryWatcher.h; sourceTree = ""; }; 3048830A1462B11700F2E5F4 /* DirectoryWatcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DirectoryWatcher.m; sourceTree = ""; }; 3048830D1462B22000F2E5F4 /* GPGWatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGWatcher.h; sourceTree = ""; }; @@ -465,7 +471,6 @@ 1B46CFCF161555DF00CF9C5F /* org.gpgtools.Libmacgpg.xpc */, 30DF7CBA16D39EAA00C8225C /* installerHelper */, 1BD78BA11726B2830005F251 /* LeakFinder */, - 30444C381A65E0590052CB94 /* installerHelperTests */, 30BE73BF1B54015C001A2137 /* UnitTests */, 0867D69AFE84028FC02AAC07 /* Frameworks */, 034768DFFF38A50411DB9C8B /* Products */, @@ -656,24 +661,6 @@ name = GPGKey; sourceTree = ""; }; - 30444C381A65E0590052CB94 /* installerHelperTests */ = { - isa = PBXGroup; - children = ( - 30444C3E1A65E0590052CB94 /* installerHelperTests.m */, - 30444C391A65E0590052CB94 /* Supporting Files */, - ); - path = installerHelperTests; - sourceTree = ""; - }; - 30444C391A65E0590052CB94 /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 30444C3A1A65E0590052CB94 /* installerHelperTests-Info.plist */, - 30444C3B1A65E0590052CB94 /* InfoPlist.strings */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; 306C73821B45B0F200A34730 /* GPGStream */ = { isa = PBXGroup; children = ( @@ -1249,7 +1236,16 @@ buildActionMask = 2147483647; files = ( 30BE73EA1B541F5B001A2137 /* GPGUnitTest.m in Sources */, + 307698C81B56B61500566B20 /* GPGConfReaderTest.m in Sources */, + 307698C91B56B61500566B20 /* GPGStdSettingTest.m in Sources */, + 307698CA1B56B61500566B20 /* GPGLinesSettingTest.m in Sources */, + 307698CB1B56B61500566B20 /* GPGArraySettingTest.m in Sources */, + 307698CC1B56B61500566B20 /* GPGDictSettingTest.m in Sources */, + 307698CD1B56B61500566B20 /* GPGOptionsTest.m in Sources */, 3075ADD61B566D0900A5F89A /* GPGPacketTest.m in Sources */, + 307698CE1B56B61500566B20 /* GPGTestVerify.m in Sources */, + 307698CF1B56B61500566B20 /* GPGSocketCloseTest.m in Sources */, + 307698D01B56B61500566B20 /* GPGUnarmorTest.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1350,14 +1346,6 @@ name = MainMenu.xib; sourceTree = ""; }; - 30444C3B1A65E0590052CB94 /* InfoPlist.strings */ = { - isa = PBXVariantGroup; - children = ( - 30444C3C1A65E0590052CB94 /* en */, - ); - name = InfoPlist.strings; - sourceTree = ""; - }; 30516556142281270038AAF0 /* Localizable.strings */ = { isa = PBXVariantGroup; children = ( From 53067839d610d32eaed75ef45fdf367173cf13e8 Mon Sep 17 00:00:00 2001 From: Mento Date: Sun, 19 Jul 2015 16:21:40 +0200 Subject: [PATCH 38/56] Correct handle clear-text with an even number of newlines at the end. --- Source/GPGUnArmor.m | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/GPGUnArmor.m b/Source/GPGUnArmor.m index 3db6207..a1c4427 100644 --- a/Source/GPGUnArmor.m +++ b/Source/GPGUnArmor.m @@ -314,6 +314,8 @@ - (parsingState)parseClearText { } else if (dashes < 5) { if (byte == '-') { dashes++; + } else if (byte == '\n') { + dashes = 0; } else { dashes = -1; } From bcf3ff19eab72061e34e594edc78d137e2df9983 Mon Sep 17 00:00:00 2001 From: Mento Date: Sun, 19 Jul 2015 16:49:31 +0200 Subject: [PATCH 39/56] Newline bug in clear-signed text. --- Source/GPGUnArmor.m | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Source/GPGUnArmor.m b/Source/GPGUnArmor.m index a1c4427..069d5e3 100644 --- a/Source/GPGUnArmor.m +++ b/Source/GPGUnArmor.m @@ -783,9 +783,11 @@ - (NSData *)parseClearTextData:(NSData *)theData { while (range.location < length) { NSRange foundRange = [theData rangeOfData:newLine options:0 range:range]; if (foundRange.length == 0) { + // No newline found. So this is the last line. foundRange.location = length; } + // Length of this line. range.length = foundRange.location - range.location; // Remove leading "- ". @@ -812,18 +814,19 @@ - (NSData *)parseClearTextData:(NSData *)theData { } } + // Append the line to the result data. [result appendBytes:bytes + range.location length:range.length]; - [result appendBytes:"\r\n" length:2]; + if (foundRange.location < length) { + // This isn't the last line. Append CRLF. + [result appendBytes:"\r\n" length:2]; + } + // Calculate the range of the remaining data. range.location = foundRange.location + 1; range.length = length - range.location; } - if (result.length >= 2) { - result.length = result.length - 2; - } - return result; } From 137332cf84a05b4b26a1693a62d9ec37f041b217 Mon Sep 17 00:00:00 2001 From: Mento Date: Mon, 20 Jul 2015 11:24:08 +0200 Subject: [PATCH 40/56] Clear-signed unit test for GPGUnArmor. --- Libmacgpg.xcodeproj/project.pbxproj | 48 ++++++++++++++++++ UnitTests/GPGUnarmorTest.m | 34 +++++++++++-- .../Unarmor_ClearsignComplicated.clear | 14 +++++ .../Unarmor/Unarmor_ClearsignComplicated.res | Bin 0 -> 287 bytes .../Unarmor/Unarmor_ClearsignComplicated.txt | 29 +++++++++++ .../Unarmor/Unarmor_ClearsignNoLF.clear | 1 + .../Unarmor/Unarmor_ClearsignNoLF.res | Bin 0 -> 287 bytes .../Unarmor/Unarmor_ClearsignNoLF.txt | 15 ++++++ .../Unarmor/Unarmor_ClearsignOneLF.clear | 1 + .../Unarmor/Unarmor_ClearsignOneLF.res | Bin 0 -> 287 bytes .../Unarmor/Unarmor_ClearsignOneLF.txt | 16 ++++++ .../Unarmor/Unarmor_ClearsignTwoLF.clear | 2 + .../Unarmor/Unarmor_ClearsignTwoLF.res | Bin 0 -> 287 bytes .../Unarmor/Unarmor_ClearsignTwoLF.txt | 17 +++++++ 14 files changed, 173 insertions(+), 4 deletions(-) create mode 100644 UnitTests/Resources/Unarmor/Unarmor_ClearsignComplicated.clear create mode 100644 UnitTests/Resources/Unarmor/Unarmor_ClearsignComplicated.res create mode 100644 UnitTests/Resources/Unarmor/Unarmor_ClearsignComplicated.txt create mode 100644 UnitTests/Resources/Unarmor/Unarmor_ClearsignNoLF.clear create mode 100644 UnitTests/Resources/Unarmor/Unarmor_ClearsignNoLF.res create mode 100644 UnitTests/Resources/Unarmor/Unarmor_ClearsignNoLF.txt create mode 100644 UnitTests/Resources/Unarmor/Unarmor_ClearsignOneLF.clear create mode 100644 UnitTests/Resources/Unarmor/Unarmor_ClearsignOneLF.res create mode 100644 UnitTests/Resources/Unarmor/Unarmor_ClearsignOneLF.txt create mode 100644 UnitTests/Resources/Unarmor/Unarmor_ClearsignTwoLF.clear create mode 100644 UnitTests/Resources/Unarmor/Unarmor_ClearsignTwoLF.res create mode 100644 UnitTests/Resources/Unarmor/Unarmor_ClearsignTwoLF.txt diff --git a/Libmacgpg.xcodeproj/project.pbxproj b/Libmacgpg.xcodeproj/project.pbxproj index e0a20be..17e619a 100644 --- a/Libmacgpg.xcodeproj/project.pbxproj +++ b/Libmacgpg.xcodeproj/project.pbxproj @@ -53,6 +53,18 @@ 301D29271B4C032D00599BE8 /* GPGPublicKeyEncryptedSessionKeyPacket.m in Sources */ = {isa = PBXBuildFile; fileRef = 301D29251B4C032D00599BE8 /* GPGPublicKeyEncryptedSessionKeyPacket.m */; }; 301D5D9F178C9871003026E7 /* GPGKeyserver.h in Headers */ = {isa = PBXBuildFile; fileRef = 301D5D9D178C9871003026E7 /* GPGKeyserver.h */; }; 301D5DA0178C9871003026E7 /* GPGKeyserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 301D5D9E178C9871003026E7 /* GPGKeyserver.m */; }; + 302481D61B5CF46800C86A07 /* Unarmor_ClearsignComplicated.clear in Resources */ = {isa = PBXBuildFile; fileRef = 302481CA1B5CF46800C86A07 /* Unarmor_ClearsignComplicated.clear */; }; + 302481D71B5CF46800C86A07 /* Unarmor_ClearsignComplicated.res in Resources */ = {isa = PBXBuildFile; fileRef = 302481CB1B5CF46800C86A07 /* Unarmor_ClearsignComplicated.res */; }; + 302481D81B5CF46800C86A07 /* Unarmor_ClearsignComplicated.txt in Resources */ = {isa = PBXBuildFile; fileRef = 302481CC1B5CF46800C86A07 /* Unarmor_ClearsignComplicated.txt */; }; + 302481D91B5CF46800C86A07 /* Unarmor_ClearsignNoLF.clear in Resources */ = {isa = PBXBuildFile; fileRef = 302481CD1B5CF46800C86A07 /* Unarmor_ClearsignNoLF.clear */; }; + 302481DA1B5CF46800C86A07 /* Unarmor_ClearsignNoLF.res in Resources */ = {isa = PBXBuildFile; fileRef = 302481CE1B5CF46800C86A07 /* Unarmor_ClearsignNoLF.res */; }; + 302481DB1B5CF46800C86A07 /* Unarmor_ClearsignNoLF.txt in Resources */ = {isa = PBXBuildFile; fileRef = 302481CF1B5CF46800C86A07 /* Unarmor_ClearsignNoLF.txt */; }; + 302481DC1B5CF46800C86A07 /* Unarmor_ClearsignOneLF.clear in Resources */ = {isa = PBXBuildFile; fileRef = 302481D01B5CF46800C86A07 /* Unarmor_ClearsignOneLF.clear */; }; + 302481DD1B5CF46800C86A07 /* Unarmor_ClearsignOneLF.res in Resources */ = {isa = PBXBuildFile; fileRef = 302481D11B5CF46800C86A07 /* Unarmor_ClearsignOneLF.res */; }; + 302481DE1B5CF46800C86A07 /* Unarmor_ClearsignOneLF.txt in Resources */ = {isa = PBXBuildFile; fileRef = 302481D21B5CF46800C86A07 /* Unarmor_ClearsignOneLF.txt */; }; + 302481DF1B5CF46800C86A07 /* Unarmor_ClearsignTwoLF.clear in Resources */ = {isa = PBXBuildFile; fileRef = 302481D31B5CF46800C86A07 /* Unarmor_ClearsignTwoLF.clear */; }; + 302481E01B5CF46800C86A07 /* Unarmor_ClearsignTwoLF.res in Resources */ = {isa = PBXBuildFile; fileRef = 302481D41B5CF46800C86A07 /* Unarmor_ClearsignTwoLF.res */; }; + 302481E11B5CF46800C86A07 /* Unarmor_ClearsignTwoLF.txt in Resources */ = {isa = PBXBuildFile; fileRef = 302481D51B5CF46800C86A07 /* Unarmor_ClearsignTwoLF.txt */; }; 3026F4AF13A203A000F3CA02 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3026F4AE13A203A000F3CA02 /* Security.framework */; }; 30444C461A65E3D70052CB94 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 30DF7CBB16D39EAA00C8225C /* main.m */; }; 30444C491A65E46F0052CB94 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4591C4D514F86D38007F6D47 /* Foundation.framework */; }; @@ -261,6 +273,18 @@ 301D29281B4C049C00599BE8 /* GPGPacketParser_Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = GPGPacketParser_Private.h; path = GPGPacket/GPGPacketParser_Private.h; sourceTree = ""; }; 301D5D9D178C9871003026E7 /* GPGKeyserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGKeyserver.h; sourceTree = ""; }; 301D5D9E178C9871003026E7 /* GPGKeyserver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGKeyserver.m; sourceTree = ""; }; + 302481CA1B5CF46800C86A07 /* Unarmor_ClearsignComplicated.clear */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Unarmor_ClearsignComplicated.clear; path = Unarmor/Unarmor_ClearsignComplicated.clear; sourceTree = ""; }; + 302481CB1B5CF46800C86A07 /* Unarmor_ClearsignComplicated.res */ = {isa = PBXFileReference; lastKnownFileType = file; name = Unarmor_ClearsignComplicated.res; path = Unarmor/Unarmor_ClearsignComplicated.res; sourceTree = ""; }; + 302481CC1B5CF46800C86A07 /* Unarmor_ClearsignComplicated.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Unarmor_ClearsignComplicated.txt; path = Unarmor/Unarmor_ClearsignComplicated.txt; sourceTree = ""; }; + 302481CD1B5CF46800C86A07 /* Unarmor_ClearsignNoLF.clear */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Unarmor_ClearsignNoLF.clear; path = Unarmor/Unarmor_ClearsignNoLF.clear; sourceTree = ""; }; + 302481CE1B5CF46800C86A07 /* Unarmor_ClearsignNoLF.res */ = {isa = PBXFileReference; lastKnownFileType = file; name = Unarmor_ClearsignNoLF.res; path = Unarmor/Unarmor_ClearsignNoLF.res; sourceTree = ""; }; + 302481CF1B5CF46800C86A07 /* Unarmor_ClearsignNoLF.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Unarmor_ClearsignNoLF.txt; path = Unarmor/Unarmor_ClearsignNoLF.txt; sourceTree = ""; }; + 302481D01B5CF46800C86A07 /* Unarmor_ClearsignOneLF.clear */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Unarmor_ClearsignOneLF.clear; path = Unarmor/Unarmor_ClearsignOneLF.clear; sourceTree = ""; }; + 302481D11B5CF46800C86A07 /* Unarmor_ClearsignOneLF.res */ = {isa = PBXFileReference; lastKnownFileType = file; name = Unarmor_ClearsignOneLF.res; path = Unarmor/Unarmor_ClearsignOneLF.res; sourceTree = ""; }; + 302481D21B5CF46800C86A07 /* Unarmor_ClearsignOneLF.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Unarmor_ClearsignOneLF.txt; path = Unarmor/Unarmor_ClearsignOneLF.txt; sourceTree = ""; }; + 302481D31B5CF46800C86A07 /* Unarmor_ClearsignTwoLF.clear */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Unarmor_ClearsignTwoLF.clear; path = Unarmor/Unarmor_ClearsignTwoLF.clear; sourceTree = ""; }; + 302481D41B5CF46800C86A07 /* Unarmor_ClearsignTwoLF.res */ = {isa = PBXFileReference; lastKnownFileType = file; name = Unarmor_ClearsignTwoLF.res; path = Unarmor/Unarmor_ClearsignTwoLF.res; sourceTree = ""; }; + 302481D51B5CF46800C86A07 /* Unarmor_ClearsignTwoLF.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Unarmor_ClearsignTwoLF.txt; path = Unarmor/Unarmor_ClearsignTwoLF.txt; sourceTree = ""; }; 3026F4AE13A203A000F3CA02 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 30444C181A65E0590052CB94 /* GPGTools.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = GPGTools.app; sourceTree = BUILT_PRODUCTS_DIR; }; 30444C1C1A65E0590052CB94 /* installerHelper-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "installerHelper-Info.plist"; sourceTree = ""; }; @@ -709,6 +733,18 @@ 30A2183A1B55753100D01E37 /* Unarmor */ = { isa = PBXGroup; children = ( + 302481CA1B5CF46800C86A07 /* Unarmor_ClearsignComplicated.clear */, + 302481CB1B5CF46800C86A07 /* Unarmor_ClearsignComplicated.res */, + 302481CC1B5CF46800C86A07 /* Unarmor_ClearsignComplicated.txt */, + 302481CD1B5CF46800C86A07 /* Unarmor_ClearsignNoLF.clear */, + 302481CE1B5CF46800C86A07 /* Unarmor_ClearsignNoLF.res */, + 302481CF1B5CF46800C86A07 /* Unarmor_ClearsignNoLF.txt */, + 302481D01B5CF46800C86A07 /* Unarmor_ClearsignOneLF.clear */, + 302481D11B5CF46800C86A07 /* Unarmor_ClearsignOneLF.res */, + 302481D21B5CF46800C86A07 /* Unarmor_ClearsignOneLF.txt */, + 302481D31B5CF46800C86A07 /* Unarmor_ClearsignTwoLF.clear */, + 302481D41B5CF46800C86A07 /* Unarmor_ClearsignTwoLF.res */, + 302481D51B5CF46800C86A07 /* Unarmor_ClearsignTwoLF.txt */, 30A2185B1B5579A200D01E37 /* Unarmor_DoubleNewline.res */, 30A2185C1B5579A200D01E37 /* Unarmor_DoubleNewline.txt */, 30A2185D1B5579A200D01E37 /* Unarmor_InvalidComment.res */, @@ -1043,21 +1079,32 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 302481DE1B5CF46800C86A07 /* Unarmor_ClearsignOneLF.txt in Resources */, + 302481DA1B5CF46800C86A07 /* Unarmor_ClearsignNoLF.res in Resources */, 30A2186B1B5579A200D01E37 /* Unarmor_DoubleNewline.res in Resources */, 30A2186C1B5579A200D01E37 /* Unarmor_DoubleNewline.txt in Resources */, 30A218781B5579A200D01E37 /* Unarmor_Version.txt in Resources */, 3075ADDD1B56760F00A5F89A /* compressed1.gpg in Resources */, + 302481DB1B5CF46800C86A07 /* Unarmor_ClearsignNoLF.txt in Resources */, 30A218701B5579A200D01E37 /* Unarmor_InvalidVersion.txt in Resources */, 30A218721B5579A200D01E37 /* Unarmor_MissingNewline.txt in Resources */, 30A2187A1B5579A200D01E37 /* Unarmor_VersionOnline.txt in Resources */, + 302481E01B5CF46800C86A07 /* Unarmor_ClearsignTwoLF.res in Resources */, + 302481DD1B5CF46800C86A07 /* Unarmor_ClearsignOneLF.res in Resources */, + 302481D81B5CF46800C86A07 /* Unarmor_ClearsignComplicated.txt in Resources */, + 302481D91B5CF46800C86A07 /* Unarmor_ClearsignNoLF.clear in Resources */, 30BE73DD1B541039001A2137 /* OpenPGP.asc in Resources */, + 302481DC1B5CF46800C86A07 /* Unarmor_ClearsignOneLF.clear in Resources */, 30A218731B5579A200D01E37 /* Unarmor_NoNewline.res in Resources */, + 302481D61B5CF46800C86A07 /* Unarmor_ClearsignComplicated.clear in Resources */, 30A218711B5579A200D01E37 /* Unarmor_MissingNewline.res in Resources */, 30BE73DE1B541039001A2137 /* SignedInputStringCR.txt in Resources */, 30A218791B5579A200D01E37 /* Unarmor_VersionOnline.res in Resources */, 30A218751B5579A200D01E37 /* Unarmor_Normal.res in Resources */, 30BE73DF1B541039001A2137 /* SignedInputStringCRLF.txt in Resources */, 30A2186F1B5579A200D01E37 /* Unarmor_InvalidVersion.res in Resources */, + 302481D71B5CF46800C86A07 /* Unarmor_ClearsignComplicated.res in Resources */, + 302481DF1B5CF46800C86A07 /* Unarmor_ClearsignTwoLF.clear in Resources */, 30A2186E1B5579A200D01E37 /* Unarmor_InvalidComment.txt in Resources */, 30A218761B5579A200D01E37 /* Unarmor_Normal.txt in Resources */, 30A218741B5579A200D01E37 /* Unarmor_NoNewline.txt in Resources */, @@ -1065,6 +1112,7 @@ 30BE73E01B541039001A2137 /* SignedInputStringLF.txt in Resources */, 30A2186D1B5579A200D01E37 /* Unarmor_InvalidComment.res in Resources */, 3075ADDB1B5675D200A5F89A /* key1.gpg in Resources */, + 302481E11B5CF46800C86A07 /* Unarmor_ClearsignTwoLF.txt in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/UnitTests/GPGUnarmorTest.m b/UnitTests/GPGUnarmorTest.m index a9c2968..a49e888 100644 --- a/UnitTests/GPGUnarmorTest.m +++ b/UnitTests/GPGUnarmorTest.m @@ -26,18 +26,44 @@ - (void)testGPGUnArmor { NSString *resPath = [[filePath substringToIndex:filePath.length - 3] stringByAppendingString:@"res"]; NSData *expectedData = [NSData dataWithContentsOfFile:resPath]; + NSString *clearPath = [[filePath substringToIndex:filePath.length - 3] stringByAppendingString:@"clear"]; + NSData *expectedClearData = nil; + if ([fileManager fileExistsAtPath:clearPath]) { + expectedClearData = [NSData dataWithContentsOfFile:clearPath]; + if (expectedClearData == nil) { + XCTFail(@"Unable to read %@!", clearPath); + } + } + GPGStream *stream = [GPGFileStream fileStreamForReadingAtPath:filePath]; - // The method to test - NSData *unArmored = [[GPGUnArmor unArmor:stream] readAllData]; + + + GPGUnArmor *unArmor = [GPGUnArmor unArmorWithGPGStream:stream]; + // The method to test + NSData *unArmored = [unArmor decodeAll]; + + + + BOOL passed = YES; + if (expectedClearData) { + NSData *clearData = unArmor.clearText; + if (![expectedClearData isEqualToData:clearData]) { + passed = NO; + XCTFail(@"Clear-text %@ failed!", filename); + } + } + if (unArmored.length == 0 || ![unArmored isEqualToData:expectedData]) { + passed = NO; XCTFail(@"Test %@ failed!", filename); - continue; } - printf("%s\n", [[NSString stringWithFormat:@"Test %@ passed.", filename] UTF8String]); + if (passed) { + printf("%s\n", [[NSString stringWithFormat:@"Test %@ passed.", filename] UTF8String]); + } } } } diff --git a/UnitTests/Resources/Unarmor/Unarmor_ClearsignComplicated.clear b/UnitTests/Resources/Unarmor/Unarmor_ClearsignComplicated.clear new file mode 100644 index 0000000..d128a6a --- /dev/null +++ b/UnitTests/Resources/Unarmor/Unarmor_ClearsignComplicated.clear @@ -0,0 +1,14 @@ +Some complicated text. + + + + +----Hey---- +Unicode: äö@‘±Œ’˙\¯^£#£\^˜\·¯˜·\^fi£ +Much more Unicode: °·ØÛ\™¸fiˇÇ˝◊Ûˇ‹Ø·˜\^fi™„Á˝Û\ˇØ·˙ÅÍÇ∏fl∏ıfl±æπ¿≠{≠|][{¢]¶|]{?)=)(=&/)%&$(æ±πøºª©⁄fi^Ç^\ÌÓ·ı∏ıÓÌÏ™fi£Ì\˜·¯˙ˆ¯Á˜·\^fiÇ\£„™^Ϙ\Ì^·¯ˆ∏·ıÓ‹˝^ fi‰^\^˜\·˜¯ı·°˘ˆÆÆ’—Æ—÷˛ØÛ˝\ÏÅÍ^Á◊ + +and some +toher text +over +multiple +lines. diff --git a/UnitTests/Resources/Unarmor/Unarmor_ClearsignComplicated.res b/UnitTests/Resources/Unarmor/Unarmor_ClearsignComplicated.res new file mode 100644 index 0000000000000000000000000000000000000000..16b902c994c0b749ccf3303134be9875e4cd7a18 GIT binary patch literal 287 zcmV+)0pR|L0UQJY0SW*H1p-y9xUB#R2@q0i3GoV}+JejC2mqKrLC>qK-P@c+^Zl@> zp~P>$=qLc+gv;*>OKREf%>1aG?S*oDgFS2b(%1F*>Vx=6&q|M@ZP;r9(nSg*`3%<(&uxmS8|%%%IA3x>`vlJ6>Rr57t5r*?h#MgvNOmw*4uh2; zdhZJH+IWYhVK1BhDsYLbnL+9j?;i6L&BiW0%QB6V@3q8gzbK&l{!7M0T7j5jFuN;E z*-k=CNPj1g63U^f0#PSFB6%(X~euC6Oe#?(z l#xLZED>RG!F2S{Z4+~^F>pK`NTT2qmaCvO<`iv1syNjz4>= zQLFNW4A<=6@+jMBM3-R0q5;fl0lO-Ug^f}WB%)FnC;ezcKQ0>WY5Gq&Wgl*a3kR)G z_`#!;H)fJlEK}}J7h2lW&XU?T-o~1W7I@vq>9H;ua0e$4Tw40kcHr}1Ft&$Qc;6pu zE@#M6cFb}I#uFBjNYwP9o+13+%eGt3QFv!yLCOj(HxErt1s{Uab-w<`)m7uK>QYe5 zRs%Fr<$0!+$+aK~l-*7i9Zs#71y`cEjAzl!a^mrgE(dCjn)X;%DFt85+hx~$!I>a- l^OOHsL-RcD^*h&(FqnZSc?&Oty1f5z-(t-A!1c=1+lS7BiX;F4 literal 0 HcmV?d00001 diff --git a/UnitTests/Resources/Unarmor/Unarmor_ClearsignOneLF.txt b/UnitTests/Resources/Unarmor/Unarmor_ClearsignOneLF.txt new file mode 100644 index 0000000..26b80f7 --- /dev/null +++ b/UnitTests/Resources/Unarmor/Unarmor_ClearsignOneLF.txt @@ -0,0 +1,16 @@ +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA512 + +One line of text. One newline. + +-----BEGIN PGP SIGNATURE----- +Comment: GPGTools - https://gpgtools.org + +iQEcBAEBCgAGBQJVrLfaAAoJEFJrCfEKo9qCbBkH/jJ3qkC7Src655KOP3urUavy +hQzX7N/yKNtpRJdgw6IBzGkBuyqMhY1SECSiUhgn/WhDPy4a7Wn6TzllH26GCwet +UPjBo5Q3ZpJULFPuTxda2tPOkto23saaihZ43cfpsS4ZcAcnEFxa+tF24PNgMLaH +VnjfH2suZ8hSdsxyB8YTFpJI1PShniH83su2W89ReGdgQcoKLTcPTU4FH4LSdb7+ +x9VV46/qUlDMVgM0UuV5ppXJtSAKlN1OFh1OrZgFV6K5jGfRzXLi8Y0uB2qNmvZY +VykFX8zbZdd8wZkgdvOT/1lD8zzu9TvXjzCYgSd5Cy+Durz/cN9izPrA9crU24c= +=33oJ +-----END PGP SIGNATURE----- diff --git a/UnitTests/Resources/Unarmor/Unarmor_ClearsignTwoLF.clear b/UnitTests/Resources/Unarmor/Unarmor_ClearsignTwoLF.clear new file mode 100644 index 0000000..afab9f9 --- /dev/null +++ b/UnitTests/Resources/Unarmor/Unarmor_ClearsignTwoLF.clear @@ -0,0 +1,2 @@ +One line of text. Two newlines. + diff --git a/UnitTests/Resources/Unarmor/Unarmor_ClearsignTwoLF.res b/UnitTests/Resources/Unarmor/Unarmor_ClearsignTwoLF.res new file mode 100644 index 0000000000000000000000000000000000000000..dde4cf014433a5430daf560b434380bbdda95d59 GIT binary patch literal 287 zcmV+)0pR|L0UQJY0SW*H1p-y9xE25k2@q0i3GoV}+JYcu2mpkpu-Vx3h{Icug{vUg z?c5&OCN1cOBHl^ct@w3o$upk=K(BaHq&*sagx8p2=qT1;o?!eMX?;P?K#h+rBAx>2u)S9m>ChZUBFcg-7V zo4BwG1}QLqH?T4mZdN>H}Vegg&>IN{Ow%kbT85IEio`hCToQ literal 0 HcmV?d00001 diff --git a/UnitTests/Resources/Unarmor/Unarmor_ClearsignTwoLF.txt b/UnitTests/Resources/Unarmor/Unarmor_ClearsignTwoLF.txt new file mode 100644 index 0000000..831177e --- /dev/null +++ b/UnitTests/Resources/Unarmor/Unarmor_ClearsignTwoLF.txt @@ -0,0 +1,17 @@ +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA512 + +One line of text. Two newlines. + + +-----BEGIN PGP SIGNATURE----- +Comment: GPGTools - https://gpgtools.org + +iQEcBAEBCgAGBQJVrLgWAAoJEFJrCfEKo9qCIGUIAISmsNnY9IjDW5CFqyDY7dwe +2SYt6IYi3knbrfh1a8kznwNAr3hTpD2BFe6jAxWCRQ1kyER/6zHhRDNj7uhy+MgZ +weVCd59D+gnpXRQ9B2HBXK9oyY2u1qCDNFZHibezqBHBTjwVnBSSyQkSfsgtGgSA +M01lyYna74JziLKSo/ffXhXYrc/kGsJf91pMZ+jCYXAN4Pf+vIhgGge6Ua+IV3g9 +VIcVloZ3zRtpm7iwCwYpMH83sDIWblY8nV8t1KSqb71eNqDCaTm+oLVYpdwN9ex6 +UiMuO22WHuRKM47OsZTsipVHqG/O92wu0SVOUVHqA16GhD63l0qJrb+QfcUxOIk= +=zz0M +-----END PGP SIGNATURE----- From df30d907ccff59739ed6038786919461a5225508 Mon Sep 17 00:00:00 2001 From: Mento Date: Fri, 24 Jul 2015 14:47:30 +0200 Subject: [PATCH 41/56] GPGKey revocationSignature added. --- Source/GPGKey.h | 4 +++- Source/GPGKey.m | 30 ++++++++++++++++++++++++++++++ Source/GPGKeyManager.m | 2 +- Source/GPGTransformer.m | 29 +++++++++++++++++++++++++++-- Source/GPGUserID.h | 4 +++- Source/GPGUserID.m | 33 ++++++++++++++++++++++++++++++++- 6 files changed, 96 insertions(+), 6 deletions(-) diff --git a/Source/GPGKey.h b/Source/GPGKey.h index 5433d1c..c5ba387 100644 --- a/Source/GPGKey.h +++ b/Source/GPGKey.h @@ -19,7 +19,7 @@ #import #import - +@class GPGUserIDSignature; @interface GPGKey : NSObject { NSString *_keyID; @@ -49,6 +49,7 @@ NSArray *_subkeys; NSArray *_userIDs; NSArray *_signatures; + GPGUserIDSignature *_revocationSignature; // Contains all information of the key concatenated for quicker search. NSString *_textForFilter; @@ -82,6 +83,7 @@ @property (nonatomic, readonly) NSArray *subkeys; @property (nonatomic, readonly) NSArray *userIDs; @property (nonatomic, readonly) NSArray *signatures; +@property (nonatomic, readonly) GPGUserIDSignature *revocationSignature; @property (nonatomic, readonly) GPGKey *primaryKey; @property (nonatomic, readonly) GPGUserID *primaryUserID; diff --git a/Source/GPGKey.m b/Source/GPGKey.m index b3e7a07..db3e3e0 100644 --- a/Source/GPGKey.m +++ b/Source/GPGKey.m @@ -57,6 +57,33 @@ - (void)setUserIDs:(NSArray *)userIDs { if([_userIDs count]) self.primaryUserID = [_userIDs objectAtIndex:0]; } +- (void)setSignatures:(NSArray *)signatures { + if (signatures != _signatures) { + id oldValue = _signatures; + _signatures = [signatures copy]; + [oldValue release]; + + GPGUserIDSignature *revSig = nil; + for (GPGUserIDSignature *sig in signatures) { + if (sig.revocation) { + revSig = sig; + break; + } + } + if (revSig != _revocationSignature) { + oldValue = _revocationSignature; + _revocationSignature = [revSig retain]; + [oldValue release]; + } + + } +} +- (NSArray *)signatures { + return [[_signatures retain] autorelease]; +} +- (GPGUserIDSignature *)revocationSignature { + return [[_revocationSignature retain] autorelease]; +} - (NSString *)email { return self.primaryUserID.email; @@ -174,6 +201,9 @@ - (void)dealloc { [_cardID release]; _cardID = nil; + [_revocationSignature release]; + _revocationSignature = nil; + dispatch_release(_textForFilterOnce); _textForFilterOnce = NULL; diff --git a/Source/GPGKeyManager.m b/Source/GPGKeyManager.m index 0b3aba4..f25d9ef 100644 --- a/Source/GPGKeyManager.m +++ b/Source/GPGKeyManager.m @@ -246,7 +246,7 @@ - (void)fillKey:(GPGKey *)primaryKey withRange:(NSRange)lineRange { if (([type isEqualToString:@"pub"] && (isPub = YES)) || [type isEqualToString:@"sub"]) { // Primary-key or subkey. if (_fetchSignatures) { signedObject.signatures = signatures; - signatures = nil; + signatures = [NSMutableArray array]; } if (isPub) { key = primaryKey; diff --git a/Source/GPGTransformer.m b/Source/GPGTransformer.m index 520dc9d..b233f68 100644 --- a/Source/GPGTransformer.m +++ b/Source/GPGTransformer.m @@ -19,6 +19,8 @@ #import "GPGTransformer.h" #import "GPGGlobals.h" +#import "GPGKey.h" +#import "GPGUserIDSignature.h" #define maybeLocalize(key) (!_keepUnlocalized ? localizedLibmacgpgString(key) : key) @@ -100,7 +102,19 @@ + (Class)transformedValueClass { return [NSString class]; } + (BOOL)allowsReverseTransformation { return NO; } - (id)transformedValue:(id)value { NSMutableArray *strings = [NSMutableArray array]; - NSInteger intValue = [value integerValue]; + NSInteger intValue; + GPGUserIDSignature *revSig = nil; + + if ([value isKindOfClass:[NSNumber class]]) { + intValue = [value integerValue]; + } else { + GPGKey *key = value; + intValue = key.validity; + if ([key respondsToSelector:@selector(revocationSignature)]) { + revSig = key.revocationSignature; + } + } + switch (intValue & 7) { case 2: @@ -126,7 +140,18 @@ - (id)transformedValue:(id)value { [strings addObject:maybeLocalize(@"Invalid")]; } if (intValue & GPGValidityRevoked) { - [strings addObject:maybeLocalize(@"Revoked")]; + NSString *revString = maybeLocalize(@"Revoked"); + if (revSig) { + NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; + dateFormatter.timeStyle = NSDateFormatterNoStyle; + dateFormatter.dateStyle = NSDateFormatterLongStyle; + + NSString *dateString = [dateFormatter stringFromDate:revSig.creationDate]; + + revString = [NSString stringWithFormat:@"%@ (%@)", revString, dateString]; + } + + [strings addObject:revString]; } if (intValue & GPGValidityExpired) { [strings addObject:maybeLocalize(@"Expired")]; diff --git a/Source/GPGUserID.h b/Source/GPGUserID.h index 800a145..ec06a2c 100644 --- a/Source/GPGUserID.h +++ b/Source/GPGUserID.h @@ -19,7 +19,7 @@ #import -@class GPGKey, NSImage; +@class GPGKey, NSImage, GPGUserIDSignature; @protocol GPGUserIDProtocol @@ -44,6 +44,7 @@ GPGKey *_primaryKey; NSArray *_signatures; + GPGUserIDSignature *_revocationSignature; } @@ -61,6 +62,7 @@ @property (nonatomic, readonly) GPGValidity validity; @property (nonatomic, readonly) NSArray *signatures; +@property (nonatomic, readonly) GPGUserIDSignature *revocationSignature; @property (nonatomic, readonly) GPGKey *primaryKey; @end diff --git a/Source/GPGUserID.m b/Source/GPGUserID.m index 5b29e05..e6d1c27 100644 --- a/Source/GPGUserID.m +++ b/Source/GPGUserID.m @@ -22,7 +22,7 @@ @implementation GPGUserID -@synthesize userIDDescription=_userIDDescription, name=_name, email=_email, comment=_comment, hashID=_hashID, primaryKey=_primaryKey, signatures=_signatures, image=_image, expirationDate=_expirationDate, creationDate=_creationDate, validity=_validity; +@synthesize userIDDescription=_userIDDescription, name=_name, email=_email, comment=_comment, hashID=_hashID, primaryKey=_primaryKey, image=_image, expirationDate=_expirationDate, creationDate=_creationDate, validity=_validity; - (instancetype)init { return [self initWithUserIDDescription:nil]; @@ -47,6 +47,35 @@ - (NSString *)description { return self.hashID; } +- (void)setSignatures:(NSArray *)signatures { + if (signatures != _signatures) { + id oldValue = _signatures; + _signatures = [signatures copy]; + [oldValue release]; + + GPGUserIDSignature *revSig = nil; + for (GPGUserIDSignature *sig in signatures) { + if (sig.revocation) { + revSig = sig; + break; + } + } + if (revSig != _revocationSignature) { + oldValue = _revocationSignature; + _revocationSignature = [revSig retain]; + [oldValue release]; + } + + } +} +- (NSArray *)signatures { + return [[_signatures retain] autorelease]; +} +- (GPGUserIDSignature *)revocationSignature { + return [[_revocationSignature retain] autorelease]; +} + + //- (void)updatePreferences:(NSString *)listing { // NSArray *split = [[[listing componentsSeparatedByString:@":"] objectAtIndex:12] componentsSeparatedByString:@","]; // NSString *prefs = [split objectAtIndex:0]; @@ -103,6 +132,8 @@ - (void)dealloc { _image = nil; [_hashID release]; _hashID = nil; + [_revocationSignature release]; + _revocationSignature = nil; _primaryKey = nil; [_signatures release]; From 84cca8eefdb3b90af12915f884e049254802e0c4 Mon Sep 17 00:00:00 2001 From: Mento Date: Fri, 24 Jul 2015 18:49:54 +0200 Subject: [PATCH 42/56] MACOSX_DEPLOYMENT_TARGET for installerHelper removed. --- Libmacgpg.xcodeproj/project.pbxproj | 2 -- 1 file changed, 2 deletions(-) diff --git a/Libmacgpg.xcodeproj/project.pbxproj b/Libmacgpg.xcodeproj/project.pbxproj index 17e619a..7435092 100644 --- a/Libmacgpg.xcodeproj/project.pbxproj +++ b/Libmacgpg.xcodeproj/project.pbxproj @@ -1677,7 +1677,6 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; INFOPLIST_FILE = "installerHelper/installerHelper-Info.plist"; - MACOSX_DEPLOYMENT_TARGET = 10.9; PRODUCT_NAME = GPGTools; WRAPPER_EXTENSION = app; }; @@ -1708,7 +1707,6 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; INFOPLIST_FILE = "installerHelper/installerHelper-Info.plist"; - MACOSX_DEPLOYMENT_TARGET = 10.9; PRODUCT_NAME = GPGTools; WRAPPER_EXTENSION = app; }; From 2e5b21ffb9f2e6c8b7e05ff787a1f81f0af6ede6 Mon Sep 17 00:00:00 2001 From: Mento Date: Tue, 4 Aug 2015 19:30:43 +0200 Subject: [PATCH 43/56] base64DecodedData crash on 10.6 --- Source/GPGGlobals.m | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/Source/GPGGlobals.m b/Source/GPGGlobals.m index f0879fa..67e630b 100644 --- a/Source/GPGGlobals.m +++ b/Source/GPGGlobals.m @@ -209,16 +209,9 @@ - (NSData *)base64DecodedData { NSData *result = nil; if (floor(NSAppKitVersionNumber) < NSAppKitVersionNumber10_9) { - SecTransformRef transform = SecDecodeTransformCreate(kSecBase64Encoding, nil); - if (!transform) { - return nil; - } - - if (SecTransformSetAttribute(transform, kSecTransformInputAttributeName, self, nil)) { - result = (NSData *)SecTransformExecute(transform, nil); - } - - CFRelease(transform); + NSString *base64String = [[NSString alloc] initWithData:self encoding:NSASCIIStringEncoding]; + result = [[NSData alloc] initWithBase64Encoding:base64String]; + [base64String release]; } else { result = [[NSData alloc] initWithBase64EncodedData:self options:NSDataBase64DecodingIgnoreUnknownCharacters]; } From 7f92bd30de2c85aa3b349ea82818e4c8e61870fc Mon Sep 17 00:00:00 2001 From: Mento Date: Fri, 7 Aug 2015 15:59:52 +0200 Subject: [PATCH 44/56] Better way to find the right pinentry. --- Source/GPGTaskHelper.m | 55 +++++++++++++++--------------------------- 1 file changed, 19 insertions(+), 36 deletions(-) diff --git a/Source/GPGTaskHelper.m b/Source/GPGTaskHelper.m index 2e10f49..4f61c4c 100644 --- a/Source/GPGTaskHelper.m +++ b/Source/GPGTaskHelper.m @@ -171,50 +171,33 @@ + (NSString *)pinentryPath { static dispatch_once_t pinentryToken; dispatch_once(&pinentryToken, ^{ - // New checking order: - // 1. a defined "pinentry-program" in gpg-agent.conf - // 2. pinentry-mac in a bundle named "org.gpgtools.Libmacgpg" - // 3. a pinentry-mac executable in a set of dirs (e.g., /usr/local/bin) - - - NSString *foundPath = nil; - NSFileManager *fileManager = [NSFileManager defaultManager]; static NSString * const kPinentry_program = @"pinentry-program"; GPGOptions *options = [GPGOptions sharedOptions]; - // 1. - // Read pinentry path from gpg-agent.conf - NSString *inconfPath = [options valueForKey:kPinentry_program inDomain:GPGDomain_gpgAgentConf]; - inconfPath = [inconfPath stringByStandardizingPath]; - - if (inconfPath && [fileManager isExecutableFileAtPath:inconfPath]) { - foundPath = inconfPath; // Use it, if valid. - } else { // No valid pinentryPath. - inconfPath = nil; - - // 2. - // Search for pinentry in Libmacgpg. - NSString *bundlePath = [[NSBundle bundleWithIdentifier:@"org.gpgtools.Libmacgpg"] pathForResource:@"pinentry-mac" ofType:@"" inDirectory:@"pinentry-mac.app/Contents/MacOS"]; - if (bundlePath && [fileManager isExecutableFileAtPath:bundlePath]) - foundPath = bundlePath; - } + // MacGPG2 has the default path to pinentry-mac hardcoded + // so we don't need to force set a path in gpg-agent.conf. + // Read pinentry path from gpg-agent.conf. + pinentryPath = [options valueForKey:kPinentry_program inDomain:GPGDomain_gpgAgentConf]; + pinentryPath = [pinentryPath stringByStandardizingPath]; - if (!inconfPath) { // No (valid) pinentry ing pg-agent.conf - if (!foundPath) { - // 3. - foundPath = [self findExecutableWithName:@"../libexec/pinentry-mac.app/Contents/MacOS/pinentry-mac"]; - } - if (foundPath) { - // Set valid pinentry. - [options setValue:foundPath forKey:kPinentry_program inDomain:GPGDomain_gpgAgentConf]; - [options gpgAgentFlush]; - } - } + if (pinentryPath) { + // Remove an invalid path from gpg-agent.conf. + // A pinentry in Libmacgpg is an old version, don't use it anymore. + if ([pinentryPath rangeOfString:@"/Libmacgpg.framework/"].length > 0 || ![fileManager isExecutableFileAtPath:pinentryPath]) { + pinentryPath = nil; + [options setValue:nil forKey:kPinentry_program inDomain:GPGDomain_gpgAgentConf]; + [options gpgAgentFlush]; + } + } - pinentryPath = [foundPath retain]; + if (!pinentryPath) { + pinentryPath = @"/usr/local/MacGPG2/libexec/pinentry-mac.app/Contents/MacOS/pinentry-mac"; + } + + [pinentryPath retain]; }); return pinentryPath; } From 143a1188257c3df3ab31fa25eebef0126dc3e580 Mon Sep 17 00:00:00 2001 From: Mento Date: Fri, 7 Aug 2015 16:03:07 +0200 Subject: [PATCH 45/56] GPGPacket use seconds instead of date. --- Source/GPGPacket/GPGKeyMaterialPacket.h | 4 ++-- Source/GPGPacket/GPGKeyMaterialPacket.m | 18 +++++++++++++----- Source/GPGPacket/GPGLiteralDataPacket.h | 4 ++-- Source/GPGPacket/GPGLiteralDataPacket.m | 7 +++---- Source/GPGPacket/GPGPacketParser.m | 16 +++++----------- Source/GPGPacket/GPGPacketParser_Private.h | 2 +- Source/GPGPacket/GPGSignaturePacket.h | 4 ++-- Source/GPGPacket/GPGSignaturePacket.m | 15 +++++++-------- UnitTests/GPGPacketTest.m | 10 +++++----- 9 files changed, 40 insertions(+), 40 deletions(-) diff --git a/Source/GPGPacket/GPGKeyMaterialPacket.h b/Source/GPGPacket/GPGKeyMaterialPacket.h index 3cdd7ef..fc43bc2 100644 --- a/Source/GPGPacket/GPGKeyMaterialPacket.h +++ b/Source/GPGPacket/GPGKeyMaterialPacket.h @@ -25,7 +25,7 @@ NSInteger publicAlgorithm; NSInteger version; NSInteger validDays; - NSDate *creationDate; + NSUInteger creationTime; NSString *fingerprint; NSString *keyID; } @@ -36,7 +36,7 @@ @property (nonatomic, readonly) NSInteger publicAlgorithm; @property (nonatomic, readonly) NSInteger version; @property (nonatomic, readonly) NSInteger validDays; // Only set on old keys. -@property (nonatomic, strong, readonly) NSDate *creationDate; +@property (nonatomic, readonly) NSUInteger creationTime; @property (nonatomic, strong, readonly) NSString *fingerprint; @property (nonatomic, strong, readonly) NSString *keyID; diff --git a/Source/GPGPacket/GPGKeyMaterialPacket.m b/Source/GPGPacket/GPGKeyMaterialPacket.m index c5a72d6..f98f314 100644 --- a/Source/GPGPacket/GPGKeyMaterialPacket.m +++ b/Source/GPGPacket/GPGKeyMaterialPacket.m @@ -29,14 +29,14 @@ @interface GPGPublicKeyPacket () @property (nonatomic, readwrite) NSInteger publicAlgorithm; @property (nonatomic, readwrite) NSInteger version; @property (nonatomic, readwrite) NSInteger validDays; -@property (nonatomic, strong, readwrite) NSDate *creationDate; +@property (nonatomic, readwrite) NSUInteger creationTime; @property (nonatomic, strong, readwrite) NSString *fingerprint; @property (nonatomic, strong, readwrite) NSString *keyID; @end @implementation GPGPublicKeyPacket -@synthesize publicAlgorithm, version, validDays, creationDate, fingerprint, keyID; +@synthesize publicAlgorithm, version, validDays, creationTime, fingerprint, keyID; - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)length { self = [super init]; @@ -50,7 +50,7 @@ - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)leng case 3: { // Old format, deprecated and weak! - self.creationDate = parser.date; + self.creationTime = parser.time; self.validDays = parser.uint16; // How many days the key is valid. self.publicAlgorithm = parser.byte; // Should be 1 (RSA). @@ -103,7 +103,7 @@ - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)leng parser.byteCallback = callback; - self.creationDate = parser.date; + self.creationTime = parser.time; self.publicAlgorithm = parser.byte; // Ignore the MPIs. But we recognize them. @@ -160,8 +160,16 @@ - (GPGPacketTag)tag { return 6; } +- (NSString *)description { + return [NSString stringWithFormat:@"%@ v%li: %li\nFingerprint: %@\nKeyID: %@\nCreation Time: %lu", self.className, + (long)self.version, + (long)self.publicAlgorithm, + self.fingerprint, + self.keyID, + (unsigned long)self.creationTime]; +} + - (void)dealloc { - self.creationDate = nil; self.fingerprint = nil; self.keyID = nil; [super dealloc]; diff --git a/Source/GPGPacket/GPGLiteralDataPacket.h b/Source/GPGPacket/GPGLiteralDataPacket.h index 15d4b94..24acebb 100644 --- a/Source/GPGPacket/GPGLiteralDataPacket.h +++ b/Source/GPGPacket/GPGLiteralDataPacket.h @@ -27,13 +27,13 @@ @interface GPGLiteralDataPacket : GPGPacket { NSInteger format; NSString *filename; - NSDate *date; + NSUInteger time; NSData *content; } @property (nonatomic, readonly) NSInteger format; @property (nonatomic, strong, readonly) NSString *filename; // "_CONSOLE" means "for your eyes only". -@property (nonatomic, strong, readonly) NSDate *date; +@property (nonatomic, readonly) NSUInteger time; @property (nonatomic, copy, readonly) NSData *content; @end diff --git a/Source/GPGPacket/GPGLiteralDataPacket.m b/Source/GPGPacket/GPGLiteralDataPacket.m index 4ba8a3d..196394a 100644 --- a/Source/GPGPacket/GPGLiteralDataPacket.m +++ b/Source/GPGPacket/GPGLiteralDataPacket.m @@ -25,13 +25,13 @@ @interface GPGLiteralDataPacket () @property (nonatomic, readwrite) NSInteger format; @property (nonatomic, strong, readwrite) NSString *filename; -@property (nonatomic, strong, readwrite) NSDate *date; +@property (nonatomic, readwrite) NSUInteger time; @property (nonatomic, copy, readwrite) NSData *content; @end @implementation GPGLiteralDataPacket -@synthesize format, filename, date, content; +@synthesize format, filename, time, content; - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)length { @@ -47,7 +47,7 @@ - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)leng NSUInteger filenameLength = parser.byte; self.filename = [parser stringWithLength:filenameLength]; - self.date = parser.date; + self.time = parser.time; // Decrement by the number of bytes read. length = length - 6 - filenameLength; @@ -84,7 +84,6 @@ - (GPGPacketTag)tag { - (void)dealloc { self.filename = nil; - self.date = nil; self.content = nil; [super dealloc]; } diff --git a/Source/GPGPacket/GPGPacketParser.m b/Source/GPGPacket/GPGPacketParser.m index 7149f38..4ae17da 100644 --- a/Source/GPGPacket/GPGPacketParser.m +++ b/Source/GPGPacket/GPGPacketParser.m @@ -336,7 +336,7 @@ - (id)multiPrecisionInteger { return data; } -- (NSDate *)date { +- (NSUInteger)time { // Read a date. Consumes 4 bytes. NSUInteger time; @@ -346,13 +346,7 @@ - (NSDate *)date { time |= self.byte << 8; time |= self.byte; - if (time == 0) { - return nil; - } - - NSDate *date = [NSDate dateWithTimeIntervalSince1970:time]; - - return date; + return time; } - (UInt16)uint16 { @@ -428,9 +422,9 @@ - (NSArray *)signatureSubpacketsWithLength:(NSUInteger)fullLength { case GPGSignatureCreationTimeTag: case GPGSignatureExpirationTimeTag: case GPGKeyExpirationTimeTag: { - NSDate *date = [self date]; - if (date) { - packet[@"date"] = date; + NSUInteger time = [self time]; + if (time) { + packet[@"time"] = @(time); } break; } diff --git a/Source/GPGPacket/GPGPacketParser_Private.h b/Source/GPGPacket/GPGPacketParser_Private.h index 01aaecb..4e586c2 100644 --- a/Source/GPGPacket/GPGPacketParser_Private.h +++ b/Source/GPGPacket/GPGPacketParser_Private.h @@ -37,7 +37,7 @@ - (NSString *)keyID; - (id)multiPrecisionInteger; -- (NSDate *)date; +- (NSUInteger)time; - (UInt16)uint16; - (NSString *)stringWithLength:(NSUInteger)length; - (NSArray *)signatureSubpacketsWithLength:(NSUInteger)fullLength; diff --git a/Source/GPGPacket/GPGSignaturePacket.h b/Source/GPGPacket/GPGSignaturePacket.h index 47f0034..aa5e6c7 100644 --- a/Source/GPGPacket/GPGSignaturePacket.h +++ b/Source/GPGPacket/GPGSignaturePacket.h @@ -58,7 +58,7 @@ typedef enum { NSInteger version; UInt16 hashStart; NSString *keyID; - NSDate *creationDate; + NSUInteger creationTime; NSArray *hashedSubpackets; NSArray *unhashedSubpackets; NSArray *subpackets; @@ -73,7 +73,7 @@ typedef enum { @property (nonatomic, readonly) NSInteger version; @property (nonatomic, readonly) UInt16 hashStart; @property (nonatomic, copy, readonly) NSString *keyID; -@property (nonatomic, copy, readonly) NSDate *creationDate; +@property (nonatomic, readonly) NSUInteger creationTime; /** The hashed subpackets of the GPGSignaturePacket. @returns List of NSDictionarys, this can change at any time, so you're required to test for it. diff --git a/Source/GPGPacket/GPGSignaturePacket.m b/Source/GPGPacket/GPGSignaturePacket.m index 54b2a5e..c582621 100644 --- a/Source/GPGPacket/GPGSignaturePacket.m +++ b/Source/GPGPacket/GPGSignaturePacket.m @@ -29,8 +29,8 @@ @interface GPGSignaturePacket () @property (nonatomic, readwrite) NSInteger type; @property (nonatomic, readwrite) NSInteger version; @property (nonatomic, readwrite) UInt16 hashStart; +@property (nonatomic, readwrite) NSUInteger creationTime; @property (nonatomic, copy, readwrite) NSString *keyID; -@property (nonatomic, copy, readwrite) NSDate *creationDate; @property (nonatomic, copy, readwrite) NSArray *hashedSubpackets; @property (nonatomic, copy, readwrite) NSArray *unhashedSubpackets; @property (nonatomic, copy, readwrite) NSArray *subpackets; @@ -38,7 +38,7 @@ @interface GPGSignaturePacket () @implementation GPGSignaturePacket -@synthesize publicAlgorithm, hashAlgorithm, type, version, hashStart, keyID, creationDate, +@synthesize publicAlgorithm, hashAlgorithm, type, version, hashStart, keyID, creationTime, hashedSubpackets, unhashedSubpackets, subpackets; - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)length { @@ -54,9 +54,9 @@ - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)leng case 3: // Old format. - [parser byte]; // Ignore (length of type(1 byte) and creationDate(4 bytes). MUST be 5.) + [parser byte]; // Ignore (length of type(1 byte) and creationTime(4 bytes). MUST be 5.) self.type = parser.byte; - self.creationDate = parser.date; + self.creationTime = parser.time; // KeyID of the issuer. self.keyID = parser.keyID; @@ -111,7 +111,7 @@ - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)leng for (NSDictionary *subpacket in subpackets) { switch ((GPGSubpacketTag)[subpacket[@"tag"] integerValue]) { case GPGSignatureCreationTimeTag: - self.creationDate = subpacket[@"date"]; + self.creationTime = [subpacket[@"time"] unsignedIntegerValue]; break; case GPGIssuerTag: self.keyID = subpacket[@"keyID"]; @@ -161,16 +161,15 @@ - (GPGPacketTag)tag { } - (NSString *)description { - return [NSString stringWithFormat:@"%@ v%li: %li\nIssuer: %@\nCreation Date: %@", self.className, + return [NSString stringWithFormat:@"%@ v%li: %li\nIssuer: %@\nCreation Time: %lu", self.className, (long)self.version, (long)self.type, self.keyID, - self.creationDate]; + (unsigned long)self.creationTime]; } - (void)dealloc { self.keyID = nil; - self.creationDate = nil; self.hashedSubpackets = nil; self.unhashedSubpackets = nil; [super dealloc]; diff --git a/UnitTests/GPGPacketTest.m b/UnitTests/GPGPacketTest.m index 29057f3..1e2b857 100644 --- a/UnitTests/GPGPacketTest.m +++ b/UnitTests/GPGPacketTest.m @@ -18,12 +18,12 @@ - (void)testKey1 { @{@"fingerprint": @"77270A31BEE39087C6B7E771F988A4590DB03A7D", @"keyID": @"F988A4590DB03A7D", @"version": @4, - @"creationDate": [NSDate dateWithTimeIntervalSince1970:1313104392], + @"creationTime": @1313104392, @"publicAlgorithm": @1}, @{@"userID": @"GPGTools Test Key (For testing purposes only!) "}, @{@"keyID": @"F988A4590DB03A7D", @"version": @4, - @"creationDate": [NSDate dateWithTimeIntervalSince1970:1313104392], + @"creationTime": @1313104392, @"publicAlgorithm": @1, @"hashStart": @65285, @"type": @19, @@ -31,11 +31,11 @@ - (void)testKey1 { @{@"fingerprint": @"30BD46FC8599CB334466CFC5526B09F10AA3DA82", @"keyID": @"526B09F10AA3DA82", @"version": @4, - @"creationDate": [NSDate dateWithTimeIntervalSince1970:1313104392], + @"creationTime": @1313104392, @"publicAlgorithm": @1}, @{@"keyID": @"F988A4590DB03A7D", @"version": @4, - @"creationDate": [NSDate dateWithTimeIntervalSince1970:1313104392], + @"creationTime": @1313104392, @"publicAlgorithm": @1, @"hashStart": @63416, @"type": @24, @@ -76,7 +76,7 @@ - (void)testCompressed { NSArray *conditionList = @[ @{@"format": @98, @"filename": @"tv", - @"date": [NSDate dateWithTimeIntervalSince1970:1436958747], + @"time": @1436958747, @"content": [NSData dataWithBytes:"ok\n" length:3]}, ]; From a38a0297b4ba32bfac05a45fbb9a1259fca6878e Mon Sep 17 00:00:00 2001 From: Mento Date: Fri, 7 Aug 2015 16:04:50 +0200 Subject: [PATCH 46/56] Add +capabilitiesOfPackets to GPGPacket. --- Source/GPGPacket/GPGPacket.h | 8 +- Source/GPGPacket/GPGPacket.m | 183 ++++++++++++++++++++++++++++++++--- 2 files changed, 174 insertions(+), 17 deletions(-) diff --git a/Source/GPGPacket/GPGPacket.h b/Source/GPGPacket/GPGPacket.h index a648a97..b5a4f13 100644 --- a/Source/GPGPacket/GPGPacket.h +++ b/Source/GPGPacket/GPGPacket.h @@ -50,14 +50,18 @@ typedef NS_ENUM(NSInteger, GPGPacketTag) { ++ (NSDictionary *)capabilitiesOfPackets:(NSArray *)packets; + ++ (id)packetsWithData:(NSData *)data; ++ (void)enumeratePacketsWithData:(NSData *)theData block:(void (^)(GPGPacket *packet, BOOL *stop))block; + + // Old methods, only for compatibility: - (NSInteger)type UNAVAILABLE_ATTRIBUTE; - (NSString *)keyID UNAVAILABLE_ATTRIBUTE; - (NSInteger)signatureType UNAVAILABLE_ATTRIBUTE; -+ (id)packetsWithData:(NSData *)data DEPRECATED_ATTRIBUTE; -+ (void)enumeratePacketsWithData:(NSData *)theData block:(void (^)(GPGPacket *packet, BOOL *stop))block DEPRECATED_ATTRIBUTE; + (NSData *)unArmor:(NSData *)data DEPRECATED_ATTRIBUTE; + (NSData *)unArmor:(NSData *)data clearText:(NSData **)clearText DEPRECATED_ATTRIBUTE; diff --git a/Source/GPGPacket/GPGPacket.m b/Source/GPGPacket/GPGPacket.m index 8858b39..9eb4630 100644 --- a/Source/GPGPacket/GPGPacket.m +++ b/Source/GPGPacket/GPGPacket.m @@ -19,6 +19,7 @@ 02111-1307, USA */ +#import "Libmacgpg.h" #import "GPGPacket.h" #import "GPGPacket_Private.h" #import "GPGPacketParser.h" @@ -40,25 +41,159 @@ - (GPGPacketTag)tag { ++ (NSDictionary *)capabilitiesOfPackets:(NSArray *)packets { + BOOL canEncrypt = NO; + BOOL canSign = NO; + BOOL revoked = NO; + BOOL expired = NO; + BOOL invalid = NO; + BOOL stop = NO; + GPGPacketTag lastTag; + GPGPacket *lastPacket; + + + if (packets.count == 0) { + return nil; + } + + + GPGPublicKeyPacket *mainPacket = packets[0]; + switch (mainPacket.tag) { + case 5: + case 6: + lastTag = mainPacket.tag; + lastPacket = mainPacket; + if (mainPacket.version != 4) { + // Only version 4 key are considered valid. + invalid = YES; + } + break; + default: + return nil; + } + + NSString *keyID = mainPacket.keyID; + NSUInteger now = (NSUInteger)[[NSDate date] timeIntervalSince1970]; + + + + + + for (GPGPacket *packet in packets) { + NSInteger tag = packet.tag; + + switch (tag) { + case 5: + case 6: { // Public/Secret Key + GPGPublicKeyPacket *realPacket = (id)packet; + if (![keyID isEqualToString:realPacket.keyID]) { + // Start of another key. + // Only parse the first key. + stop = YES; + } + break; + } + case 7: + case 14: { + GPGPublicSubkeyPacket *realPacket = (id)packet; + if (realPacket.version != 4) { + // Ignore the signatures of this subkey. + tag = 0; + } + break; + } + case 2: { // Signature Packet + GPGSignaturePacket *realPacket = (id)packet; + switch (realPacket.type) { + case 16: + case 17: + case 18: + case 19: { // UserID signature. + if ([keyID isEqualToString:realPacket.keyID]) { + // Self-signature. + for (NSDictionary *subpacket in realPacket.subpackets) { + NSInteger subTag = [subpacket[@"tag"] integerValue]; + if (subTag == 9) { // Key Expiration Time + NSUInteger expirationTime = [subpacket[@"time"] unsignedIntegerValue]; + if (expirationTime && now - mainPacket.creationTime >= expirationTime) { + // The key is expired. + expired = YES; + break; + } + } else if (subTag == 27) { + canEncrypt = canEncrypt || [subpacket[@"canEncryptCommunications"] boolValue] || [subpacket[@"canEncryptStorage"] boolValue]; + canSign = canSign || [subpacket[@"canSign"] boolValue]; + } + } + } + break; + } + case 24: { // Subkey Binding Signature + if ((lastTag == 7 || lastTag == 14) && [keyID isEqualToString:realPacket.keyID]) { + // Last packet was a subkey and it's issued by the primary key. + + BOOL subkeyCanEncrypt = NO; + BOOL subkeyCanSign = NO; + + for (NSDictionary *subpacket in realPacket.subpackets) { + NSInteger subTag = [subpacket[@"tag"] integerValue]; + if (subTag == 9) { // Key Expiration Time + NSUInteger expirationTime = [subpacket[@"time"] unsignedIntegerValue]; + if (expirationTime && now - [(GPGPublicSubkeyPacket *)lastPacket creationTime] >= expirationTime) { + // The subkey is expired. + subkeyCanEncrypt = NO; + subkeyCanSign = NO; + break; + } + } else if (subTag == 27) { // Key Flags + subkeyCanEncrypt = subkeyCanEncrypt || [subpacket[@"canEncryptCommunications"] boolValue] || [subpacket[@"canEncryptStorage"] boolValue]; + subkeyCanSign = subkeyCanSign || [subpacket[@"canSign"] boolValue]; + } + } + + canEncrypt = canEncrypt || subkeyCanEncrypt; + canSign = canSign || subkeyCanSign; + } + break; + } + case 32: { // Key revocation signature + if ((lastTag == 5 || lastTag == 6) && [keyID isEqualToString:realPacket.keyID]) { + revoked = YES; + } + break; + } + default: + break; + } // End switch (realPacket.type) + break; + } + + + default: + break; + } + lastTag = tag; + lastPacket = packet; + + if (stop) { + break; + } + } + + + NSDictionary *capabilities = @{@"canEncrypt": @(canEncrypt), + @"canSign": @(canSign), + @"revoked": @(revoked), + @"expired": @(expired), + @"invalid": @(invalid) + }; + + return capabilities; +} -// Old methods, only for compatibility. -// They will be removed in the future. -- (NSInteger)type { - return self.tag; -} -- (NSString *)keyID { - return nil; -} -- (NSInteger)signatureType { - if (self.tag == GPGSignaturePacketTag) { - return [self type]; - } else { - return 0; - } -} + (id)packetsWithData:(NSData *)theData { @@ -106,6 +241,24 @@ + (void)enumeratePacketsWithData:(NSData *)theData block:(void (^)(GPGPacket *pa [theData release]; } + +// Old methods, only for compatibility. +// They will be removed in the future. + +- (NSInteger)type { + return self.tag; +} +- (NSString *)keyID { + return nil; +} +- (NSInteger)signatureType { + if (self.tag == GPGSignaturePacketTag) { + return [self type]; + } else { + return 0; + } +} + // if return nil, input stream is not armored; should be reset and used directly + (NSData *)unArmor:(NSData *)data { return [self unArmor:data clearText:nil]; From 092579b6fa41ff7ffc62d3396b806aa1ca3c65e2 Mon Sep 17 00:00:00 2001 From: Mento Date: Fri, 7 Aug 2015 16:59:33 +0200 Subject: [PATCH 47/56] sig field 15 is optional. --- Source/GPGKeyManager.m | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Source/GPGKeyManager.m b/Source/GPGKeyManager.m index f25d9ef..c57a92d 100644 --- a/Source/GPGKeyManager.m +++ b/Source/GPGKeyManager.m @@ -435,7 +435,9 @@ - (void)fillKey:(GPGKey *)primaryKey withRange:(NSRange)lineRange { signature.signatureClass = hexToByte([field UTF8String]); signature.local = [field hasSuffix:@"l"]; - signature.hashAlgorithm = [[parts objectAtIndex:15] intValue]; + if (parts.count > 15) { + signature.hashAlgorithm = [[parts objectAtIndex:15] intValue]; + } [signatures addObject:signature]; From 8e02c0ca043f6acddcf72f0537d670e04e31c74c Mon Sep 17 00:00:00 2001 From: Mento Date: Tue, 11 Aug 2015 14:06:04 +0200 Subject: [PATCH 48/56] Fixed install path for Release configuration. This should prevent dylib hijacking. --- Libmacgpg.xcodeproj/project.pbxproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Libmacgpg.xcodeproj/project.pbxproj b/Libmacgpg.xcodeproj/project.pbxproj index 7435092..2efd1a4 100644 --- a/Libmacgpg.xcodeproj/project.pbxproj +++ b/Libmacgpg.xcodeproj/project.pbxproj @@ -1583,9 +1583,9 @@ /usr/include, ); INFOPLIST_FILE = Resources/Info.plist; - INSTALL_PATH = "@loader_path/../Frameworks"; - LD_DYLIB_INSTALL_NAME = "@rpath/$(EXECUTABLE_PATH)"; - LD_RUNPATH_SEARCH_PATHS = "@loader_path/Frameworks"; + INSTALL_PATH = /Library/Frameworks; + LD_DYLIB_INSTALL_NAME = "/Library/Frameworks/$(EXECUTABLE_PATH)"; + LD_RUNPATH_SEARCH_PATHS = /Library/Frameworks; OTHER_LDFLAGS = ""; PRODUCT_NAME = Libmacgpg; WRAPPER_EXTENSION = framework; From b4805fcefb0b3865b9589ec56298bdf81cb5f6ec Mon Sep 17 00:00:00 2001 From: Mento Date: Fri, 14 Aug 2015 16:31:56 +0200 Subject: [PATCH 49/56] Version 0.6 --- Release Notes/0.6.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 Release Notes/0.6.md diff --git a/Release Notes/0.6.md b/Release Notes/0.6.md new file mode 100644 index 0000000..1199b37 --- /dev/null +++ b/Release Notes/0.6.md @@ -0,0 +1,18 @@ +Libmacgpg 0.6 - Release Notes +============================== + +Features +-------- +### Be more tolerant toward malformed messages + +* To many line breaks or other minor malformations so far resulted in a message that could not be decrypted. We are now much more tolerant and flexible. [#63, #145, #14, #38] + + +Bugfixes +-------- + +* One of the most annoying, infamous bugs has finally gone down meaning users will no longer see the "no pinentry" error. Socket connection to gpg-agent was not closed under some circumstances. [#147] +* One of the most common crashes in the 2015.06 release has been fixed. GPGTaskHelperXPC no longer crashes. [#143] +* Crash in Libmacgpg GPGPacket fixed. [#146] +* Fix: Empty key list in GPG Keychain main window. [#149] +* Fix: Use new pinentry with keychain support for new MacGPG. [#148] \ No newline at end of file From 3c1bdc27dc129bea88f783da7f7060ac9167cc41 Mon Sep 17 00:00:00 2001 From: Mento Date: Mon, 7 Sep 2015 12:28:10 +0200 Subject: [PATCH 50/56] [FIX] Crash when parsing PGP messages. [#150 state:fixed assigned:mento] --- Libmacgpg.xcodeproj/project.pbxproj | 24 ++-- Source/GPGMemoryStream.m | 2 +- Source/GPGPacket/GPGCompressedDataPacket.m | 12 +- Source/GPGPacket/GPGIgnoredPackets.m | 1 + Source/GPGPacket/GPGKeyMaterialPacket.m | 13 +- Source/GPGPacket/GPGLiteralDataPacket.m | 5 +- Source/GPGPacket/GPGOnePassSignaturePacket.m | 1 + Source/GPGPacket/GPGPacketParser.h | 4 + Source/GPGPacket/GPGPacketParser.m | 132 +++++++++++------- Source/GPGPacket/GPGPacketParser_Private.h | 2 +- Source/GPGPacket/GPGPacket_Private.h | 5 + .../GPGPublicKeyEncryptedSessionKeyPacket.m | 2 +- Source/GPGPacket/GPGSignaturePacket.m | 10 +- .../GPGSymmetricEncryptedSessionKeyPacket.m | 1 + Source/GPGPacket/GPGUserAttributePacket.m | 2 + Source/GPGPacket/GPGUserIDPacket.m | 1 + 16 files changed, 136 insertions(+), 81 deletions(-) diff --git a/Libmacgpg.xcodeproj/project.pbxproj b/Libmacgpg.xcodeproj/project.pbxproj index 2efd1a4..c80eb06 100644 --- a/Libmacgpg.xcodeproj/project.pbxproj +++ b/Libmacgpg.xcodeproj/project.pbxproj @@ -269,7 +269,7 @@ 301D29201B4BFD9800599BE8 /* GPGPacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGPacket.m; path = GPGPacket/GPGPacket.m; sourceTree = ""; }; 301D29231B4BFDCE00599BE8 /* GPGPacket_Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = GPGPacket_Private.h; path = GPGPacket/GPGPacket_Private.h; sourceTree = ""; }; 301D29241B4C032D00599BE8 /* GPGPublicKeyEncryptedSessionKeyPacket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPGPublicKeyEncryptedSessionKeyPacket.h; path = GPGPacket/GPGPublicKeyEncryptedSessionKeyPacket.h; sourceTree = ""; }; - 301D29251B4C032D00599BE8 /* GPGPublicKeyEncryptedSessionKeyPacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGPublicKeyEncryptedSessionKeyPacket.m; path = GPGPacket/GPGPublicKeyEncryptedSessionKeyPacket.m; sourceTree = ""; }; + 301D29251B4C032D00599BE8 /* GPGPublicKeyEncryptedSessionKeyPacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; name = GPGPublicKeyEncryptedSessionKeyPacket.m; path = GPGPacket/GPGPublicKeyEncryptedSessionKeyPacket.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 301D29281B4C049C00599BE8 /* GPGPacketParser_Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = GPGPacketParser_Private.h; path = GPGPacket/GPGPacketParser_Private.h; sourceTree = ""; }; 301D5D9D178C9871003026E7 /* GPGKeyserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGKeyserver.h; sourceTree = ""; }; 301D5D9E178C9871003026E7 /* GPGKeyserver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGKeyserver.m; sourceTree = ""; }; @@ -304,7 +304,7 @@ 307C211B1B1745F5006B07A7 /* gpgtools.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = gpgtools.icns; path = Resources/gpgtools.icns; sourceTree = SOURCE_ROOT; }; 307D79101340B71A005C9C32 /* TODO */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = TODO; sourceTree = ""; }; 307FDE401B4E636A00462E4E /* GPGCompressedDataPacket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPGCompressedDataPacket.h; path = GPGPacket/GPGCompressedDataPacket.h; sourceTree = ""; }; - 307FDE411B4E636A00462E4E /* GPGCompressedDataPacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGCompressedDataPacket.m; path = GPGPacket/GPGCompressedDataPacket.m; sourceTree = ""; }; + 307FDE411B4E636A00462E4E /* GPGCompressedDataPacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; name = GPGCompressedDataPacket.m; path = GPGPacket/GPGCompressedDataPacket.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 309A18CE13E3812E0069DC0F /* GPGTransformer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGTransformer.h; sourceTree = ""; }; 309A18CF13E3812E0069DC0F /* GPGTransformer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGTransformer.m; sourceTree = ""; }; 30A058371799E2DC00E1AD20 /* GPGKeyManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGKeyManager.h; sourceTree = ""; }; @@ -327,25 +327,25 @@ 30A218691B5579A200D01E37 /* Unarmor_VersionOnline.res */ = {isa = PBXFileReference; lastKnownFileType = file; name = Unarmor_VersionOnline.res; path = Unarmor/Unarmor_VersionOnline.res; sourceTree = ""; }; 30A2186A1B5579A200D01E37 /* Unarmor_VersionOnline.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Unarmor_VersionOnline.txt; path = Unarmor/Unarmor_VersionOnline.txt; sourceTree = ""; }; 30A48E8C1B4C1344006AD363 /* GPGSignaturePacket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPGSignaturePacket.h; path = GPGPacket/GPGSignaturePacket.h; sourceTree = ""; }; - 30A48E8D1B4C1344006AD363 /* GPGSignaturePacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGSignaturePacket.m; path = GPGPacket/GPGSignaturePacket.m; sourceTree = ""; }; + 30A48E8D1B4C1344006AD363 /* GPGSignaturePacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; name = GPGSignaturePacket.m; path = GPGPacket/GPGSignaturePacket.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 30A70EE313EF328000EE9CD9 /* GPGException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGException.h; sourceTree = ""; }; 30A70EE413EF328000EE9CD9 /* GPGException.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGException.m; sourceTree = ""; }; 30B586F4141E255C000373F1 /* Keyservers.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Keyservers.plist; sourceTree = ""; }; 30BA88F1138FE593005982D9 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; 30BB7C661B4D2742006A1E47 /* GPGSymmetricEncryptedSessionKeyPacket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPGSymmetricEncryptedSessionKeyPacket.h; path = GPGPacket/GPGSymmetricEncryptedSessionKeyPacket.h; sourceTree = ""; }; - 30BB7C671B4D2742006A1E47 /* GPGSymmetricEncryptedSessionKeyPacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGSymmetricEncryptedSessionKeyPacket.m; path = GPGPacket/GPGSymmetricEncryptedSessionKeyPacket.m; sourceTree = ""; }; + 30BB7C671B4D2742006A1E47 /* GPGSymmetricEncryptedSessionKeyPacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; name = GPGSymmetricEncryptedSessionKeyPacket.m; path = GPGPacket/GPGSymmetricEncryptedSessionKeyPacket.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 30BB7C6A1B4D2E38006A1E47 /* GPGOnePassSignaturePacket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPGOnePassSignaturePacket.h; path = GPGPacket/GPGOnePassSignaturePacket.h; sourceTree = ""; }; - 30BB7C6B1B4D2E38006A1E47 /* GPGOnePassSignaturePacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGOnePassSignaturePacket.m; path = GPGPacket/GPGOnePassSignaturePacket.m; sourceTree = ""; }; + 30BB7C6B1B4D2E38006A1E47 /* GPGOnePassSignaturePacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; name = GPGOnePassSignaturePacket.m; path = GPGPacket/GPGOnePassSignaturePacket.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 30BB7C6E1B4D3244006A1E47 /* GPGKeyMaterialPacket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPGKeyMaterialPacket.h; path = GPGPacket/GPGKeyMaterialPacket.h; sourceTree = ""; }; - 30BB7C6F1B4D3244006A1E47 /* GPGKeyMaterialPacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGKeyMaterialPacket.m; path = GPGPacket/GPGKeyMaterialPacket.m; sourceTree = ""; }; + 30BB7C6F1B4D3244006A1E47 /* GPGKeyMaterialPacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; name = GPGKeyMaterialPacket.m; path = GPGPacket/GPGKeyMaterialPacket.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 30BB7C761B4D3F24006A1E47 /* GPGIgnoredPackets.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPGIgnoredPackets.h; path = GPGPacket/GPGIgnoredPackets.h; sourceTree = ""; }; - 30BB7C771B4D3F24006A1E47 /* GPGIgnoredPackets.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGIgnoredPackets.m; path = GPGPacket/GPGIgnoredPackets.m; sourceTree = ""; }; + 30BB7C771B4D3F24006A1E47 /* GPGIgnoredPackets.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; name = GPGIgnoredPackets.m; path = GPGPacket/GPGIgnoredPackets.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 30BB7C7A1B4D4146006A1E47 /* GPGLiteralDataPacket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPGLiteralDataPacket.h; path = GPGPacket/GPGLiteralDataPacket.h; sourceTree = ""; }; - 30BB7C7B1B4D4146006A1E47 /* GPGLiteralDataPacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGLiteralDataPacket.m; path = GPGPacket/GPGLiteralDataPacket.m; sourceTree = ""; }; + 30BB7C7B1B4D4146006A1E47 /* GPGLiteralDataPacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; name = GPGLiteralDataPacket.m; path = GPGPacket/GPGLiteralDataPacket.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 30BB7C7E1B4D4A59006A1E47 /* GPGUserIDPacket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPGUserIDPacket.h; path = GPGPacket/GPGUserIDPacket.h; sourceTree = ""; }; - 30BB7C7F1B4D4A59006A1E47 /* GPGUserIDPacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGUserIDPacket.m; path = GPGPacket/GPGUserIDPacket.m; sourceTree = ""; }; + 30BB7C7F1B4D4A59006A1E47 /* GPGUserIDPacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; name = GPGUserIDPacket.m; path = GPGPacket/GPGUserIDPacket.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 30BB7C821B4D4BF8006A1E47 /* GPGUserAttributePacket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GPGUserAttributePacket.h; path = GPGPacket/GPGUserAttributePacket.h; sourceTree = ""; }; - 30BB7C831B4D4BF8006A1E47 /* GPGUserAttributePacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GPGUserAttributePacket.m; path = GPGPacket/GPGUserAttributePacket.m; sourceTree = ""; }; + 30BB7C831B4D4BF8006A1E47 /* GPGUserAttributePacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; name = GPGUserAttributePacket.m; path = GPGPacket/GPGUserAttributePacket.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 30BE73BE1B54015C001A2137 /* UnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 30BE73C11B54015C001A2137 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 30BE73E81B541F5B001A2137 /* GPGUnitTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGUnitTest.h; sourceTree = ""; }; @@ -355,8 +355,6 @@ 30D5E2A21483A0F700F31454 /* GPGConf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = GPGConf.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 30D5E2A31483A0F700F31454 /* GPGConf.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGConf.m; sourceTree = ""; }; 30D68BC41B4FF5D500F7865C /* COPYING.pgpdump */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = COPYING.pgpdump; path = Source/GPGPacket/COPYING.pgpdump; sourceTree = SOURCE_ROOT; }; - 30D8099D1B5004FE007E9D63 /* GPGPacket2.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPGPacket2.h; sourceTree = ""; }; - 30D8099E1B5004FE007E9D63 /* GPGPacket2.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GPGPacket2.m; sourceTree = ""; }; 30DF7CBB16D39EAA00C8225C /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 30FF411D12FAC6CD00F39832 /* GPGController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGController.h; sourceTree = ""; }; 30FF411E12FAC6CD00F39832 /* GPGController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGController.m; sourceTree = ""; }; @@ -632,8 +630,6 @@ 301D291A1B4BE47100599BE8 /* GPGPacket */ = { isa = PBXGroup; children = ( - 30D8099D1B5004FE007E9D63 /* GPGPacket2.h */, - 30D8099E1B5004FE007E9D63 /* GPGPacket2.m */, 301D291B1B4BE4F500599BE8 /* GPGPacketParser.h */, 301D29281B4C049C00599BE8 /* GPGPacketParser_Private.h */, 301D291C1B4BE4F500599BE8 /* GPGPacketParser.m */, diff --git a/Source/GPGMemoryStream.m b/Source/GPGMemoryStream.m index 675c931..227c391 100644 --- a/Source/GPGMemoryStream.m +++ b/Source/GPGMemoryStream.m @@ -105,7 +105,7 @@ - (NSInteger)readByte { [self openForReading]; } if (_readPos >= _readableLength) { - return -1; + return EOF; } return _readableBytes[_readPos++]; // Post-increment. } diff --git a/Source/GPGPacket/GPGCompressedDataPacket.m b/Source/GPGPacket/GPGCompressedDataPacket.m index 2aac1e6..cdedfd6 100644 --- a/Source/GPGPacket/GPGCompressedDataPacket.m +++ b/Source/GPGPacket/GPGCompressedDataPacket.m @@ -64,12 +64,12 @@ @interface GPGCompressedDataPacket () @implementation GPGCompressedDataPacket @synthesize compressAlgorithm, decompressStream, subParser; -- (instancetype)initWithParser:(GPGPacketParser *)theParser length:(NSUInteger)length { +- (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)length { self = [super init]; if (!self) { return nil; } - self.compressAlgorithm = theParser.byte; + self.compressAlgorithm = parser.byte; length--; switch (compressAlgorithm) { @@ -80,16 +80,18 @@ - (instancetype)initWithParser:(GPGPacketParser *)theParser length:(NSUInteger)l break; default: // Unknown/invalid compression algorithm. - [theParser skip:length]; + [parser skip:length]; return self; } + cancelInitOnEOF(); // The GPGDecompressStream will be given to a new GPGPacketParser, to decode the packets inside of this packet. - self.decompressStream = [[GPGDecompressStream alloc] initWithParser:theParser length:length algorithm:compressAlgorithm]; + self.decompressStream = [[GPGDecompressStream alloc] initWithParser:parser length:length algorithm:compressAlgorithm]; if (decompressStream) { self.subParser = [[GPGPacketParser alloc] initWithStream:self.decompressStream]; } + cancelInitOnEOF(); return self; } @@ -187,7 +189,7 @@ - (void)fillInput { if (packetLength != 0) { for (; inputSize < cacheSize; inputSize++) { // Read a byte. - NSInteger byte = parser.byteOrEOF; + NSInteger byte = parser.byte; if (byte == EOF) { break; } diff --git a/Source/GPGPacket/GPGIgnoredPackets.m b/Source/GPGPacket/GPGIgnoredPackets.m index 37a62d7..dbefedb 100644 --- a/Source/GPGPacket/GPGIgnoredPackets.m +++ b/Source/GPGPacket/GPGIgnoredPackets.m @@ -31,6 +31,7 @@ - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)leng } [parser skip:length]; + cancelInitOnEOF(); return self; } @end diff --git a/Source/GPGPacket/GPGKeyMaterialPacket.m b/Source/GPGPacket/GPGKeyMaterialPacket.m index f98f314..7ae47db 100644 --- a/Source/GPGPacket/GPGKeyMaterialPacket.m +++ b/Source/GPGPacket/GPGKeyMaterialPacket.m @@ -43,8 +43,10 @@ - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)leng if (!self) { return nil; } - + self.version = parser.byte; + cancelInitOnEOF(); + switch (version) { case 2: case 3: { @@ -62,7 +64,8 @@ - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)leng self.keyID = bytesToHexString(modulus.bytes + modulus.length - 8, 8); } NSData *exponent = [parser multiPrecisionInteger]; // "RSA e" - + cancelInitOnEOF(); + // The fingerprint is the MD5 of modulus and exponent. CC_MD5_CTX md5; @@ -134,6 +137,8 @@ - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)leng // We have all bytes for the SHA1. Unset the callback. parser.byteCallback = nil; + cancelInitOnEOF(); + // Get the fingerprint by hashing bytesToHash using SHA1. uint8_t fingerprintBytes[20]; @@ -151,8 +156,8 @@ - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)leng [parser skip:length - 1]; break; } - - + + cancelInitOnEOF(); return self; } diff --git a/Source/GPGPacket/GPGLiteralDataPacket.m b/Source/GPGPacket/GPGLiteralDataPacket.m index 196394a..50cc6cf 100644 --- a/Source/GPGPacket/GPGLiteralDataPacket.m +++ b/Source/GPGPacket/GPGLiteralDataPacket.m @@ -52,7 +52,7 @@ - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)leng // Decrement by the number of bytes read. length = length - 6 - filenameLength; - + cancelInitOnEOF(); // Read the content bytes of the packet. NSMutableData *tempData = [NSMutableData data]; @@ -63,6 +63,7 @@ - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)leng for (NSUInteger j = 0; j < length; j++) { bytes[i++] = (UInt8)parser.byte; + cancelInitOnEOF(); } if (parser.partial) { @@ -74,7 +75,7 @@ - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)leng self.content = tempData; - + cancelInitOnEOF(); return self; } diff --git a/Source/GPGPacket/GPGOnePassSignaturePacket.m b/Source/GPGPacket/GPGOnePassSignaturePacket.m index 8db9242..a59e9f4 100644 --- a/Source/GPGPacket/GPGOnePassSignaturePacket.m +++ b/Source/GPGPacket/GPGOnePassSignaturePacket.m @@ -48,6 +48,7 @@ - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)leng [parser byte]; // Ignore (0 means the next packet is another one-pass signature) + cancelInitOnEOF(); return self; } diff --git a/Source/GPGPacket/GPGPacketParser.h b/Source/GPGPacket/GPGPacketParser.h index 1854b63..8632b32 100644 --- a/Source/GPGPacket/GPGPacketParser.h +++ b/Source/GPGPacket/GPGPacketParser.h @@ -37,6 +37,10 @@ typedef void (^ByteCallback)(NSInteger); BOOL partial; NSUInteger packetLength; + + + // Private + BOOL eofReached; } @property (nonatomic, readonly, strong) NSError *error; diff --git a/Source/GPGPacket/GPGPacketParser.m b/Source/GPGPacket/GPGPacketParser.m index 4ae17da..ca4cf7d 100644 --- a/Source/GPGPacket/GPGPacketParser.m +++ b/Source/GPGPacket/GPGPacketParser.m @@ -50,7 +50,13 @@ Based on pgpdump (https://github.com/kazu-yamamoto/pgpdump) from Kazuhiko Yamamo #define CRITICAL_BIT 0x80 #define CRITICAL_MASK 0x7f -static NSString * const endOfFileException = @"endOfFileException"; +// Return a GPGErrorEOF, if the end of file is reached unexpected. +#define returnErrorOnEOF() if (eofReached) {self.error = [NSError errorWithDomain:LibmacgpgErrorDomain code:GPGErrorEOF userInfo:nil]; return nil;} +// Return 0 or nil, if the end of file is reached. +#define stopOnEOF() if (eofReached) {return 0;} + + + static NSArray *tagClasses = nil; @interface GPGPacketParser () @@ -68,10 +74,14 @@ @implementation GPGPacketParser #pragma mark Main methods - (GPGPacket *)nextPacket { + + returnErrorOnEOF(); + @try { if (compressedPacket.canDecompress) { // We have a compressed packet, get the next decompressed packet. GPGPacket *tempPacket = [compressedPacket nextPacket]; + returnErrorOnEOF(); if (tempPacket) { return tempPacket; } else { @@ -103,8 +113,11 @@ - (GPGPacket *)nextPacket { // Get the packet length. c = self.byte; + returnErrorOnEOF(); + length = [self getNewLen:c]; - + returnErrorOnEOF(); + partial = isPartial(c); if (partial && length < 512) { // The first partial packet MUST be at least 512 byte long. @@ -113,11 +126,11 @@ - (GPGPacket *)nextPacket { } } else { // Old format. - + // The two low-bits define how the length of the packet is stored. // So we have to shift the tag accordingly. tag >>= OLD_TAG_SHIFT; - + switch (c & OLD_LEN_MASK) { case 0: length = self.byte; @@ -136,6 +149,8 @@ - (GPGPacket *)nextPacket { length = NSUIntegerMax; break; } + + returnErrorOnEOF(); } GPGPacket *packet = nil; @@ -154,6 +169,8 @@ - (GPGPacket *)nextPacket { // The packet content is parsed in -initWithParser:length:. packet = [[[class alloc] initWithParser:self length:length] autorelease]; + returnErrorOnEOF(); + if (tag == TAG_COMPRESSED && [(GPGCompressedDataPacket *)packet canDecompress]) { // We have a compressed packet, we are able to decompress. @@ -163,6 +180,7 @@ - (GPGPacket *)nextPacket { // Get the first packet inside of the compressed packet. GPGPacket *tempPacket = [compressedPacket nextPacket]; + returnErrorOnEOF(); if (tempPacket) { return tempPacket; } else { @@ -176,27 +194,24 @@ - (GPGPacket *)nextPacket { // Skip unknown packets. [self skip:length]; } - + returnErrorOnEOF(); + // Skip remaining data of a partial packet. while (partial == YES) { c = self.byte; length = [self getNewLen:c]; partial = isPartial(c); - + returnErrorOnEOF(); + [self skip:length]; } + returnErrorOnEOF(); return packet; } @catch (NSException *exception) { - if ([exception.name isEqualToString:endOfFileException]) { - // An endOfFileException is thrown by [self byte], when a unexpected EOF is reached. - // Set self.error to signal this. - self.error = [NSError errorWithDomain:LibmacgpgErrorDomain code:GPGErrorEOF userInfo:nil]; - } else { - // Never throw an exception, instead log it and set self.error. - NSLog(@"Uncaught exception in [GPGPacketParser nextPacket]: \"%@\"", exception); - self.error = [NSError errorWithDomain:LibmacgpgErrorDomain code:GPGErrorUnexpected userInfo:@{@"exception": exception}]; - } + // Never throw an exception, instead log it and set self.error. + NSLog(@"Uncaught exception in [GPGPacketParser nextPacket]: \"%@\"", exception); + self.error = [NSError errorWithDomain:LibmacgpgErrorDomain code:GPGErrorUnexpected userInfo:@{@"exception": exception}]; } return nil; @@ -206,40 +221,35 @@ - (GPGPacket *)nextPacket { #pragma mark Helper - (NSInteger)byte { - // Get the next byte from the strem. + // Gets the next byte from the strem. + // If the end of file is reached sets eofReached and returns EOF. - NSInteger byte = [stream readByte]; - if (byte == EOF) { - @throw [NSException exceptionWithName:endOfFileException reason:@"unexpected end of file." userInfo:nil]; + if (eofReached) { + return EOF; } - packetLength--; - - if (byteCallback) { - // Return the byte via byteCallback AND as a normal return value. - byteCallback(byte); - } - - return byte; -} - -- (NSInteger)byteOrEOF { - // Same as [self byte], but can also return EOF. - NSInteger byte = [stream readByte]; packetLength--; - if (byteCallback && byte != EOF) { + if (byte == EOF) { + eofReached = YES; + } else if (byteCallback) { byteCallback(byte); } return byte; } +- (BOOL)eofReached { + return eofReached; +} + - (void)skip:(NSUInteger)count { // skip count bytes. for (; count > 0; count--) { - [self byte]; + if (self.byte == EOF) { + return; + } } } @@ -268,6 +278,8 @@ - (NSUInteger)getNewLen:(NSInteger)c { } else { length = 1 << (c & PARTIAL_MASK); } + stopOnEOF(); + return length; } @@ -276,15 +288,17 @@ - (NSUInteger)getNewLen:(NSInteger)c { - (NSUInteger)nextPartialLength { // Returns the length of the next part. - + if (partial == NO) { return 0; } - + NSInteger c = self.byte; NSUInteger length = [self getNewLen:c]; partial = isPartial(c); - + + stopOnEOF(); + return length; } @@ -314,6 +328,7 @@ - (NSString *)keyID { (UInt8)self.byte, (UInt8)self.byte]; + stopOnEOF(); return keyID; } @@ -324,12 +339,14 @@ - (id)multiPrecisionInteger { NSUInteger bits = self.byte * 256; bits += self.byte; byteCount = (bits + 7) / 8; - + stopOnEOF(); + NSMutableData *data = [NSMutableData dataWithLength:byteCount]; UInt8 *bytes = data.mutableBytes; for (NSUInteger i = 0; i < byteCount; i++) { bytes[i] = (UInt8)self.byte; + stopOnEOF(); } @@ -346,38 +363,44 @@ - (NSUInteger)time { time |= self.byte << 8; time |= self.byte; + stopOnEOF(); return time; } - (UInt16)uint16 { // Read a unsigned 16-bit integer. Consumes 2 bytes. - + UInt16 value = (UInt16)((self.byte << 8) | self.byte); + + stopOnEOF(); return value; } - (NSString *)stringWithLength:(NSUInteger)length { // Read an UTF8 string. + stopOnEOF(); char tempString[length + 1]; tempString[length] = 0; for (NSUInteger i = 0; i < length; i++) { tempString[i] = (char)self.byte; + stopOnEOF(); } - + NSString *string = [NSString stringWithUTF8String:tempString]; - + return string; } - (NSArray *)signatureSubpacketsWithLength:(NSUInteger)fullLength { // Parse the signature subpackets. // fullLength is the length of all subpackets. - + + stopOnEOF(); NSMutableArray *packets = [NSMutableArray array]; - + while (fullLength > 0) { - + // Get the length of the subpacket. NSUInteger length = self.byte; if (length < 192) { @@ -393,15 +416,17 @@ - (NSArray *)signatureSubpacketsWithLength:(NSUInteger)fullLength { fullLength -= 5; } fullLength -= length; - + + // Used to skip the remaining subpacket bytes. NSUInteger remainingLength = packetLength - length; - + GPGSubpacketTag subtag = self.byte; // length includes this byte. + stopOnEOF(); length--; - - + + /* Handle critical bit of subpacket type */ BOOL critical = NO; if (subtag & CRITICAL_BIT) { @@ -479,12 +504,14 @@ - (NSArray *)signatureSubpacketsWithLength:(NSUInteger)fullLength { packet[@"hashAlgorithm"] = @(self.byte); length -= 2; + stopOnEOF(); NSMutableData *data = [NSMutableData dataWithLength:length]; if (data) { UInt8 *bytes = data.mutableBytes; for (NSUInteger i = 0; i < length; i++) { bytes[i] = (UInt8)self.byte; + stopOnEOF(); } packet[@"hash"] = [[data copy] autorelease]; @@ -494,16 +521,21 @@ - (NSArray *)signatureSubpacketsWithLength:(NSUInteger)fullLength { default: break; } - + + stopOnEOF(); + + // Add the subpacket to the list. [packets addObject:packet]; // Skip all remaining bytes of this subpacket, if any. length = packetLength - remainingLength; [self skip:length]; + + stopOnEOF(); } - + return packets; } diff --git a/Source/GPGPacket/GPGPacketParser_Private.h b/Source/GPGPacket/GPGPacketParser_Private.h index 4e586c2..42d832e 100644 --- a/Source/GPGPacket/GPGPacketParser_Private.h +++ b/Source/GPGPacket/GPGPacketParser_Private.h @@ -28,9 +28,9 @@ @property (nonatomic, copy) ByteCallback byteCallback; // Called every time a byte is read. - (NSInteger)byte; -- (NSInteger)byteOrEOF; - (void)skip:(NSUInteger)count; - (void)skipRemaining; +- (BOOL)eofReached; - (NSUInteger)nextPartialLength; - (BOOL)partial; diff --git a/Source/GPGPacket/GPGPacket_Private.h b/Source/GPGPacket/GPGPacket_Private.h index b339500..07e063d 100644 --- a/Source/GPGPacket/GPGPacket_Private.h +++ b/Source/GPGPacket/GPGPacket_Private.h @@ -21,6 +21,11 @@ #import "GPGPacketParser_Private.h" +// If the end of file is reached during init, the packet +// is invalid: Release it and return nil. +#define cancelInitOnEOF() if (parser.eofReached) {[self release]; return nil;} + + @class GPGPacketParser; @interface GPGPacket () diff --git a/Source/GPGPacket/GPGPublicKeyEncryptedSessionKeyPacket.m b/Source/GPGPacket/GPGPublicKeyEncryptedSessionKeyPacket.m index fb868fe..c1b377b 100644 --- a/Source/GPGPacket/GPGPublicKeyEncryptedSessionKeyPacket.m +++ b/Source/GPGPacket/GPGPublicKeyEncryptedSessionKeyPacket.m @@ -64,7 +64,7 @@ - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)leng break; } - + cancelInitOnEOF(); return self; } diff --git a/Source/GPGPacket/GPGSignaturePacket.m b/Source/GPGPacket/GPGSignaturePacket.m index c582621..116cb5c 100644 --- a/Source/GPGPacket/GPGSignaturePacket.m +++ b/Source/GPGPacket/GPGSignaturePacket.m @@ -48,6 +48,7 @@ - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)leng } self.version = parser.byte; + cancelInitOnEOF(); switch (version) { case 2: @@ -100,13 +101,15 @@ - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)leng NSUInteger usplen = parser.uint16; // Length of the unhashed subpackets. // The unhashed subpackets are NOT secured. Don't trust them. self.unhashedSubpackets = [parser signatureSubpacketsWithLength:usplen]; - + + cancelInitOnEOF(); + // Combined list of subpackets for convenience. NSMutableArray *theSubpackets = [NSMutableArray arrayWithArray:unhashedSubpackets]; [theSubpackets addObjectsFromArray:hashedSubpackets]; self.subpackets = theSubpackets; - - + + // Get some infos out of the subpackets. for (NSDictionary *subpacket in subpackets) { switch ((GPGSubpacketTag)[subpacket[@"tag"] integerValue]) { @@ -153,6 +156,7 @@ - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)leng break; } + cancelInitOnEOF(); return self; } diff --git a/Source/GPGPacket/GPGSymmetricEncryptedSessionKeyPacket.m b/Source/GPGPacket/GPGSymmetricEncryptedSessionKeyPacket.m index 882ec1a..5d6c4fb 100644 --- a/Source/GPGPacket/GPGSymmetricEncryptedSessionKeyPacket.m +++ b/Source/GPGPacket/GPGSymmetricEncryptedSessionKeyPacket.m @@ -47,6 +47,7 @@ - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)leng [parser skipRemaining]; + cancelInitOnEOF(); return self; } diff --git a/Source/GPGPacket/GPGUserAttributePacket.m b/Source/GPGPacket/GPGUserAttributePacket.m index 332725c..3d40dd3 100644 --- a/Source/GPGPacket/GPGUserAttributePacket.m +++ b/Source/GPGPacket/GPGUserAttributePacket.m @@ -96,6 +96,7 @@ - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)leng UInt8 *bytes = tempData.mutableBytes; for (NSUInteger i = 0; i < subLength; i++) { bytes[i] = (UInt8)parser.byte; + cancelInitOnEOF(); } subLength = 0; @@ -122,6 +123,7 @@ - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)leng self.subpackets = packets; + cancelInitOnEOF(); return self; } diff --git a/Source/GPGPacket/GPGUserIDPacket.m b/Source/GPGPacket/GPGUserIDPacket.m index fbedaab..c160039 100644 --- a/Source/GPGPacket/GPGUserIDPacket.m +++ b/Source/GPGPacket/GPGUserIDPacket.m @@ -39,6 +39,7 @@ - (instancetype)initWithParser:(GPGPacketParser *)parser length:(NSUInteger)leng self.userID = [parser stringWithLength:length]; + cancelInitOnEOF(); return self; } From 5e7154dd552303309e2d7c4e70a0512dd76cbb91 Mon Sep 17 00:00:00 2001 From: Mento Date: Mon, 7 Sep 2015 12:32:21 +0200 Subject: [PATCH 51/56] Working on GPGKeyFetcher. --- Libmacgpg.xcodeproj/project.pbxproj | 8 ++ Source/GPGKeyFetcher.h | 8 ++ Source/GPGKeyFetcher.m | 122 ++++++++++++++++++++++++++++ Source/GPGKeyserver.m | 7 ++ 4 files changed, 145 insertions(+) create mode 100644 Source/GPGKeyFetcher.h create mode 100644 Source/GPGKeyFetcher.m diff --git a/Libmacgpg.xcodeproj/project.pbxproj b/Libmacgpg.xcodeproj/project.pbxproj index c80eb06..e91dd7a 100644 --- a/Libmacgpg.xcodeproj/project.pbxproj +++ b/Libmacgpg.xcodeproj/project.pbxproj @@ -97,6 +97,8 @@ 307FDE431B4E636A00462E4E /* GPGCompressedDataPacket.m in Sources */ = {isa = PBXBuildFile; fileRef = 307FDE411B4E636A00462E4E /* GPGCompressedDataPacket.m */; }; 309A18D013E3812E0069DC0F /* GPGTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 309A18CE13E3812E0069DC0F /* GPGTransformer.h */; settings = {ATTRIBUTES = (Public, ); }; }; 309A18D113E3812E0069DC0F /* GPGTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 309A18CF13E3812E0069DC0F /* GPGTransformer.m */; }; + 309D8A121B87469B00D945BA /* GPGKeyFetcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 309D8A101B87469B00D945BA /* GPGKeyFetcher.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 309D8A131B87469B00D945BA /* GPGKeyFetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 309D8A111B87469B00D945BA /* GPGKeyFetcher.m */; }; 30A058391799E2DC00E1AD20 /* GPGKeyManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 30A058371799E2DC00E1AD20 /* GPGKeyManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; 30A0583A1799E2DC00E1AD20 /* GPGKeyManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 30A058381799E2DC00E1AD20 /* GPGKeyManager.m */; }; 30A2186B1B5579A200D01E37 /* Unarmor_DoubleNewline.res in Resources */ = {isa = PBXBuildFile; fileRef = 30A2185B1B5579A200D01E37 /* Unarmor_DoubleNewline.res */; }; @@ -307,6 +309,8 @@ 307FDE411B4E636A00462E4E /* GPGCompressedDataPacket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; name = GPGCompressedDataPacket.m; path = GPGPacket/GPGCompressedDataPacket.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 309A18CE13E3812E0069DC0F /* GPGTransformer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGTransformer.h; sourceTree = ""; }; 309A18CF13E3812E0069DC0F /* GPGTransformer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGTransformer.m; sourceTree = ""; }; + 309D8A101B87469B00D945BA /* GPGKeyFetcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGKeyFetcher.h; sourceTree = ""; }; + 309D8A111B87469B00D945BA /* GPGKeyFetcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGKeyFetcher.m; sourceTree = ""; }; 30A058371799E2DC00E1AD20 /* GPGKeyManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPGKeyManager.h; sourceTree = ""; }; 30A058381799E2DC00E1AD20 /* GPGKeyManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGKeyManager.m; sourceTree = ""; }; 30A218221B5543A500D01E37 /* GPGUnarmorTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPGUnarmorTest.m; sourceTree = ""; }; @@ -557,6 +561,8 @@ 3048830A1462B11700F2E5F4 /* DirectoryWatcher.m */, 301D5D9D178C9871003026E7 /* GPGKeyserver.h */, 301D5D9E178C9871003026E7 /* GPGKeyserver.m */, + 309D8A101B87469B00D945BA /* GPGKeyFetcher.h */, + 309D8A111B87469B00D945BA /* GPGKeyFetcher.m */, ); name = Classes; path = Source; @@ -886,6 +892,7 @@ 30A058391799E2DC00E1AD20 /* GPGKeyManager.h in Headers */, 451D882D156A7CA300A0B890 /* GPGMemoryStream.h in Headers */, 30BB7C781B4D3F24006A1E47 /* GPGIgnoredPackets.h in Headers */, + 309D8A121B87469B00D945BA /* GPGKeyFetcher.h in Headers */, 451D8831156A7E4900A0B890 /* GPGFileStream.h in Headers */, 1BCE0CD11617A3DF0026DCFF /* NSBundle+Sandbox.h in Headers */, 301A44CD1B436405002A38E4 /* GPGUnArmor.h in Headers */, @@ -1317,6 +1324,7 @@ 1BC7A50113D300A600AE57BA /* LPXTTask.m in Sources */, 309A18D113E3812E0069DC0F /* GPGTransformer.m in Sources */, 301A44CE1B436405002A38E4 /* GPGUnArmor.m in Sources */, + 309D8A131B87469B00D945BA /* GPGKeyFetcher.m in Sources */, 307FDE431B4E636A00462E4E /* GPGCompressedDataPacket.m in Sources */, 30A70EE613EF328000EE9CD9 /* GPGException.m in Sources */, 3048830C1462B11700F2E5F4 /* DirectoryWatcher.m in Sources */, diff --git a/Source/GPGKeyFetcher.h b/Source/GPGKeyFetcher.h new file mode 100644 index 0000000..72d009a --- /dev/null +++ b/Source/GPGKeyFetcher.h @@ -0,0 +1,8 @@ + +@interface GPGKeyFetcher : NSObject { + NSCache *cache; +} + +- (void)fetchKeyForMailAddress:(NSString *)mailAddress block:(void (^)(NSData *data, NSString *verifiedMail, NSError *error))block; + +@end diff --git a/Source/GPGKeyFetcher.m b/Source/GPGKeyFetcher.m new file mode 100644 index 0000000..6c25983 --- /dev/null +++ b/Source/GPGKeyFetcher.m @@ -0,0 +1,122 @@ +#import "GPGKeyFetcher.h" +#import "Libmacgpg.h" + +@implementation GPGKeyFetcher + + +- (void)fetchKeyForMailAddress:(NSString *)mailAddress block:(void (^)(NSData *data, NSString *verifiedMail, NSError *error))block { + mailAddress = [[mailAddress copy] autorelease]; // We need it immutable for NSCache. + + NSDictionary *chachedEntry = [cache objectForKey:mailAddress]; + if (chachedEntry) { + block(chachedEntry[@"data"], chachedEntry[@"verifiedMail"], nil); + return; + } + + + NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"https://keys.whiteout.io/%@", mailAddress]]; + NSURLRequest *request = [[[NSURLRequest alloc] initWithURL:url cachePolicy:0 timeoutInterval:10] autorelease]; + + + NSOperationQueue *queue = [NSOperationQueue currentQueue]; + if (!queue) { + queue = [NSOperationQueue mainQueue]; + if (!queue) { + @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"No operation queue" userInfo:nil]; + + } + } + + [NSURLConnection sendAsynchronousRequest:request + queue:queue + completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) + { + NSString *verifiedMail = nil; + + // A valid response contains at least 100 bytes of data and is armored. + if (data.length > 100 && data.isArmored) { + + // Look if the key wasn't from the whiteout keyserver. + NSData *newline = [NSData dataWithBytesNoCopy:"\n" length:1 freeWhenDone:NO]; + NSCharacterSet *nonWhitespaceSet = [[NSCharacterSet characterSetWithCharactersInString:@"\r\t "] invertedSet]; + NSRange searchRange = NSMakeRange(0, data.length); + NSRange range; + verifiedMail = mailAddress; + + while ((range = [data rangeOfData:newline options:0 range:searchRange]).length > 0) { + NSRange lineRange = NSMakeRange(searchRange.location, range.location - searchRange.location); + NSData *lineData = [data subdataWithRange:lineRange]; + NSString *line = lineData.gpgString; + + if (!line) { + // Should never happen! + verifiedMail = nil; + break; + } + if ([line rangeOfCharacterFromSet:nonWhitespaceSet].length == 0) { + // An empty line seperates the header from the base64. + break; + } + if (line.length > 19 && [[line substringToIndex:19] isEqualToString:@"Comment: Hostname: "]) { + // The key is from another keyserver. So the Mail-Address is not verified. + verifiedMail = nil; + break; + } + + searchRange.location = range.location + 1; + searchRange.length = data.length - searchRange.location; + } + + // UnArmor the data. + data = [[GPGUnArmor unArmor:[GPGMemoryStream memoryStreamForReading:data]] readAllData]; + } else { + data = nil; + } + + + if ([response isKindOfClass:[NSHTTPURLResponse class]]) { + NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode]; + + // Only cache if the server says the key was found or there is no key for this mail address. + // Don't cache if there was a connectionError or something. + if (statusCode == 200 || statusCode == 404) { + NSDictionary *cacheEntry = [NSDictionary dictionaryWithObjectsAndKeys:data, @"data", verifiedMail, @"verifiedMail", nil]; + [cache setObject:cacheEntry forKey:mailAddress]; + + // Case insensitive cache. + if (verifiedMail) { + NSString *caseInsensitiveKey = [[mailAddress lowercaseString] stringByAppendingString:@"_insensitive"]; + [cache setObject:cacheEntry forKey:caseInsensitiveKey]; + } + } + } + + block(data, verifiedMail, connectionError); + }]; + +} + + + + + + + +- (instancetype)init { + self = [super init]; + if (!self) { + return nil; + } + + cache = [NSCache new]; + + return self; +} + +- (void)dealloc { + [cache release]; + [super dealloc]; +} + + +@end diff --git a/Source/GPGKeyserver.m b/Source/GPGKeyserver.m index 71c6ceb..742e721 100644 --- a/Source/GPGKeyserver.m +++ b/Source/GPGKeyserver.m @@ -95,6 +95,11 @@ - (void)cancel { } + + + + + #pragma mark Internal methods - (void)start { @@ -132,6 +137,8 @@ - (NSURL *)keyserverURLWithQuery:(NSString *)query error:(NSError **)error { if (!port) { if ([url.scheme isEqualToString:@"http"]) { port = @"80"; + } else if ([url.scheme isEqualToString:@"https"]) { + port = @"443"; } else { port = @"11371"; } From cd5c7307d923c890903c413725208ac3da5e1fc6 Mon Sep 17 00:00:00 2001 From: Mento Date: Mon, 7 Sep 2015 15:02:35 +0200 Subject: [PATCH 52/56] GPGRemoteKey fingerprint added. --- Source/GPGRemoteKey.h | 3 ++- Source/GPGRemoteKey.m | 18 +++++++++++------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/Source/GPGRemoteKey.h b/Source/GPGRemoteKey.h index 49905e1..55b619f 100644 --- a/Source/GPGRemoteKey.h +++ b/Source/GPGRemoteKey.h @@ -21,7 +21,7 @@ @interface GPGRemoteKey : NSObject { - NSString *keyID; + NSString *fingerprint; GPGPublicKeyAlgorithm algorithm; NSUInteger length; NSDate *creationDate; @@ -35,6 +35,7 @@ @property (nonatomic, readonly) NSUInteger length; @property (nonatomic, readonly) BOOL expired; @property (nonatomic, readonly) BOOL revoked; +@property (nonatomic, readonly, retain) NSString *fingerprint; @property (nonatomic, readonly, retain) NSString *keyID; @property (nonatomic, readonly, retain) NSDate *creationDate; @property (nonatomic, readonly, retain) NSDate *expirationDate; diff --git a/Source/GPGRemoteKey.m b/Source/GPGRemoteKey.m index e5e64e4..0e13658 100644 --- a/Source/GPGRemoteKey.m +++ b/Source/GPGRemoteKey.m @@ -26,7 +26,7 @@ @interface GPGRemoteKey () @property (nonatomic) NSUInteger length; @property (nonatomic) BOOL expired; @property (nonatomic) BOOL revoked; -@property (nonatomic, retain) NSString *keyID; +@property (nonatomic, retain) NSString *fingerprint; @property (nonatomic, retain) NSDate *creationDate; @property (nonatomic, retain) NSDate *expirationDate; @property (nonatomic, retain) NSArray *userIDs; @@ -35,7 +35,7 @@ @interface GPGRemoteKey () @implementation GPGRemoteKey -@synthesize keyID, algorithm, length, creationDate, expirationDate, expired, revoked, userIDs; +@synthesize fingerprint, algorithm, length, creationDate, expirationDate, expired, revoked, userIDs; @@ -75,7 +75,7 @@ - (id)initWithListing:(NSArray *)listing { NSArray *splitedLine = [[listing objectAtIndex:0] componentsSeparatedByString:@":"]; - self.keyID = [[splitedLine objectAtIndex:1] shortKeyID]; + self.fingerprint = splitedLine[1]; self.algorithm = [[splitedLine objectAtIndex:2] intValue]; self.length = [[splitedLine objectAtIndex:3] integerValue]; @@ -107,8 +107,12 @@ - (id)initWithListing:(NSArray *)listing { return self; } +- (NSString *)keyID { + return self.fingerprint.shortKeyID; +} + - (void)dealloc { - [keyID release]; + [fingerprint release]; [creationDate release]; [expirationDate release]; [userIDs release]; @@ -116,13 +120,13 @@ - (void)dealloc { } - (NSUInteger)hash { - return [keyID hash]; + return [fingerprint hash]; } - (BOOL)isEqual:(id)anObject { - return [keyID isEqualToString:[anObject description]]; + return [fingerprint isEqualToString:[anObject description]]; } - (NSString *)description { - return [[keyID retain] autorelease]; + return [[fingerprint retain] autorelease]; } From c3bec96f7119ed216021e6a46c1b3f2977f443df Mon Sep 17 00:00:00 2001 From: Mento Date: Fri, 18 Sep 2015 11:02:57 +0200 Subject: [PATCH 53/56] Use malloc and limit string length. --- Source/GPGPacket/GPGPacketParser.m | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Source/GPGPacket/GPGPacketParser.m b/Source/GPGPacket/GPGPacketParser.m index ca4cf7d..6011100 100644 --- a/Source/GPGPacket/GPGPacketParser.m +++ b/Source/GPGPacket/GPGPacketParser.m @@ -380,7 +380,13 @@ - (NSString *)stringWithLength:(NSUInteger)length { // Read an UTF8 string. stopOnEOF(); - char tempString[length + 1]; + if (length > 100000) { + return nil; + } + char *tempString = malloc(length + 1); + if (tempString == nil) { + return nil; + } tempString[length] = 0; for (NSUInteger i = 0; i < length; i++) { tempString[i] = (char)self.byte; @@ -388,6 +394,7 @@ - (NSString *)stringWithLength:(NSUInteger)length { } NSString *string = [NSString stringWithUTF8String:tempString]; + free(tempString); return string; } From 52f2351a4cba3f3d3234d9410595493735751312 Mon Sep 17 00:00:00 2001 From: Mento Date: Mon, 21 Sep 2015 11:18:34 +0200 Subject: [PATCH 54/56] GPGPacket: Use the right expiration date. --- Source/GPGPacket/GPGPacket.m | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/Source/GPGPacket/GPGPacket.m b/Source/GPGPacket/GPGPacket.m index 9eb4630..7d87f2b 100644 --- a/Source/GPGPacket/GPGPacket.m +++ b/Source/GPGPacket/GPGPacket.m @@ -45,9 +45,9 @@ + (NSDictionary *)capabilitiesOfPackets:(NSArray *)packets { BOOL canEncrypt = NO; BOOL canSign = NO; BOOL revoked = NO; - BOOL expired = NO; BOOL invalid = NO; BOOL stop = NO; + NSUInteger expirationTime = 0; GPGPacketTag lastTag; GPGPacket *lastPacket; @@ -115,10 +115,14 @@ + (NSDictionary *)capabilitiesOfPackets:(NSArray *)packets { NSInteger subTag = [subpacket[@"tag"] integerValue]; if (subTag == 9) { // Key Expiration Time - NSUInteger expirationTime = [subpacket[@"time"] unsignedIntegerValue]; - if (expirationTime && now - mainPacket.creationTime >= expirationTime) { - // The key is expired. - expired = YES; + NSUInteger tempExpirationTime = [subpacket[@"time"] unsignedIntegerValue]; + if (tempExpirationTime) { + tempExpirationTime = realPacket.creationTime + tempExpirationTime; + + if (tempExpirationTime > expirationTime) { + // Save the latest expiration time. + expirationTime = tempExpirationTime; + } break; } } else if (subTag == 27) { @@ -139,8 +143,8 @@ + (NSDictionary *)capabilitiesOfPackets:(NSArray *)packets { for (NSDictionary *subpacket in realPacket.subpackets) { NSInteger subTag = [subpacket[@"tag"] integerValue]; if (subTag == 9) { // Key Expiration Time - NSUInteger expirationTime = [subpacket[@"time"] unsignedIntegerValue]; - if (expirationTime && now - [(GPGPublicSubkeyPacket *)lastPacket creationTime] >= expirationTime) { + NSUInteger tempExpirationTime = [subpacket[@"time"] unsignedIntegerValue]; + if (tempExpirationTime && now - [(GPGPublicSubkeyPacket *)lastPacket creationTime] >= tempExpirationTime) { // The subkey is expired. subkeyCanEncrypt = NO; subkeyCanSign = NO; @@ -181,6 +185,7 @@ + (NSDictionary *)capabilitiesOfPackets:(NSArray *)packets { } } + BOOL expired = expirationTime > 0 && now >= expirationTime; NSDictionary *capabilities = @{@"canEncrypt": @(canEncrypt), @"canSign": @(canSign), From f27b8adc9629825b7ca6a0551b3df3d7d57d1964 Mon Sep 17 00:00:00 2001 From: Mento Date: Wed, 23 Sep 2015 19:47:56 +0200 Subject: [PATCH 55/56] Version 0.6.1 --- Version.config | 1 + 1 file changed, 1 insertion(+) diff --git a/Version.config b/Version.config index 00b9d0f..6dc8a66 100644 --- a/Version.config +++ b/Version.config @@ -1,4 +1,5 @@ MAJOR=0 MINOR=6 +REVISION=1 VERSION="${MAJOR}.${MINOR}${REVISION:+.$REVISION}${PRERELEASE}" From f9498f353fc5d8d9e561a7ed7da75b0f6de9cc51 Mon Sep 17 00:00:00 2001 From: Mento Date: Tue, 29 Sep 2015 12:01:12 +0200 Subject: [PATCH 56/56] GPGUnArmor: Handle unicode line separators. [#64 state:fixed assigned:mento milestone:0.7] --- Source/GPGUnArmor.h | 2 +- Source/GPGUnArmor.m | 233 +++++++++++++++++++++++++------------------- 2 files changed, 133 insertions(+), 102 deletions(-) diff --git a/Source/GPGUnArmor.h b/Source/GPGUnArmor.h index de14120..2c0167a 100644 --- a/Source/GPGUnArmor.h +++ b/Source/GPGUnArmor.h @@ -8,7 +8,7 @@ GPGStream *stream; // Cache - NSData *cacheData; + NSMutableData *cacheData; const UInt8 *cacheBytes; NSUInteger cacheIndex; NSUInteger cacheEnd; diff --git a/Source/GPGUnArmor.m b/Source/GPGUnArmor.m index 069d5e3..0bed60e 100644 --- a/Source/GPGUnArmor.m +++ b/Source/GPGUnArmor.m @@ -3,6 +3,7 @@ #import "GPGMemoryStream.h" static const NSUInteger cacheSize = 1000; +static const NSUInteger cacheReserve = 2; // Allow to read more bytes after the real buffer. See -getByte: typedef enum { stateSearchBegin = 0, @@ -20,21 +21,23 @@ stateFinish } parsingState; +typedef enum { + charTypeNormal = 0, + charTypeWhitespace, + charTypeNewline +} charaterType; @interface GPGUnArmor () @property (nonatomic, readwrite, strong) NSError *error; @property (nonatomic, readwrite, strong) NSData *clearText; @property (nonatomic, readwrite, strong) NSData *data; - -@property (nonatomic, strong) NSData *cacheData; @end @implementation GPGUnArmor @synthesize error, clearText, data, eof; -@synthesize cacheData; #pragma Public methods @@ -268,23 +271,21 @@ - (parsingState)searchClearText { NSInteger newlineCount = 0; while ((byte = [self nextByte]) >= 0) { - switch (byte) { - case '\n': + NSInteger type = [self characterType:byte]; + switch (type) { + case charTypeWhitespace: + break; + case charTypeNewline: newlineCount++; if (newlineCount == 2) { // The clear-text comes after 2 new lines. return stateParseClearText; } - case '\r': - case ' ': - case '\t': - case 0: break; default: newlineCount = 0; break; } - } return stateEOF; @@ -308,13 +309,13 @@ - (parsingState)parseClearText { [tempClearData appendBytes:&theByte length:1]; if (dashes == -1) { - if (byte == '\n') { + if ([self characterType:byte] == charTypeNewline) { dashes = 0; } } else if (dashes < 5) { if (byte == '-') { dashes++; - } else if (byte == '\n') { + } else if ([self characterType:byte] == charTypeNewline) { dashes = 0; } else { dashes = -1; @@ -334,7 +335,7 @@ - (parsingState)parseClearText { } } else { beginMarkIndex = 0; - if (byte == '\n') { + if ([self characterType:byte] == charTypeNewline) { dashes = 0; } else { dashes = -1; @@ -357,13 +358,9 @@ - (parsingState)searchSeperator { NSInteger byte; while ((byte = [self nextByte]) >= 0) { - switch (byte) { - case '\n': - case '\r': - case ' ': - case '\t': - case 0: - return stateSearchBase64; + NSInteger type = [self characterType:byte]; + if (type >= 1) { + return stateSearchBase64; } } @@ -380,13 +377,12 @@ - (parsingState)searchBase64 { NSInteger byte; while ((byte = [self nextByte]) >= 0) { + NSInteger type = [self characterType:byte]; + if (type >= 1) { + continue; + } + switch (byte) { - case '\n': - case '\r': - case ' ': - case '\t': - case 0: - break; case 'g'...'z': case '0'...'9': case '+': @@ -422,6 +418,19 @@ - (parsingState)parseBase64 { while ((byte = [self nextByte]) >= 0) { + NSInteger type = [self characterType:byte]; + switch (type) { + case charTypeWhitespace: + continue; + case charTypeNewline: + if (alternativeStart == 0) { + alternativeStart = base64Data.length; + preferAlternative = isLineInvalid; + isLineInvalid = NO; + } + continue; + } + switch (byte) { case 'a'...'z': case 'A'...'Z': @@ -430,18 +439,6 @@ - (parsingState)parseBase64 { case '/': [base64Data appendBytes:&byte length:1]; break; - case '\n': - if (alternativeStart == 0) { - alternativeStart = base64Data.length; - preferAlternative = isLineInvalid; - isLineInvalid = NO; - } - break; - case '\r': - case ' ': - case '\t': - case 0: - break; case '-': return stateParseEnd; case '=': @@ -471,48 +468,41 @@ - (parsingState)parseCRC { while ((byte = [self nextByte]) >= 0) { if (crcLength == -1) { - switch (byte) { - case '\n': - case '\r': - case ' ': - case '\t': - case 0: - break; - case '=': - equalsAdded++; - if (equalsAdded == 2) { - crcLength = 0; - } - [base64Data appendBytes:"=" length:1]; - break; - case 'a'...'z': - case 'A'...'Z': - case '0'...'9': - case '+': - case '/': - if (lastByte != '=') { + if ([self characterType:byte] == charTypeNormal) { + switch (byte) { + case '=': + equalsAdded++; + if (equalsAdded == 2) { + crcLength = 0; + } + [base64Data appendBytes:"=" length:1]; + break; + case 'a'...'z': + case 'A'...'Z': + case '0'...'9': + case '+': + case '/': + if (lastByte != '=') { + return stateSearchSeperator; + } + crcBytes[0] = (UInt8)byte; + crcLength = 1; + break; + case '-': + equalsAdded++; + [base64Data appendBytes:"=" length:1]; + return stateParseEnd; + default: return stateSearchSeperator; - } - crcBytes[0] = (UInt8)byte; - crcLength = 1; - break; - case '-': - equalsAdded++; - [base64Data appendBytes:"=" length:1]; - return stateParseEnd; - default: - return stateSearchSeperator; - break; + break; + } } lastByte = (UInt8)byte; } else if (crcLength < 4) { + if ([self characterType:byte] >= 1) { + return stateSearchBase64; + } switch (byte) { - case '\n': - case '\r': - case ' ': - case '\t': - case 0: - return stateSearchBase64; case 'a'...'z': case 'A'...'Z': case '0'...'9': @@ -526,14 +516,8 @@ - (parsingState)parseCRC { break; } lastByte = (UInt8)byte; - } else { + } else if ([self characterType:byte] == charTypeNormal) { switch (byte) { - case '\n': - case '\r': - case ' ': - case '\t': - case 0: - break; case '-': if (crcLength == 4) { haveCRC = YES; @@ -576,15 +560,10 @@ - (parsingState)parseEnd { } else { haveCRC = NO; endMarkIndex = 0; - switch (byte) { - case '\n': - case '\r': - case ' ': - case '\t': - case 0: - return stateSearchBase64; - default: - return stateSearchSeperator; + if ([self characterType:byte] == charTypeNormal) { + return stateSearchSeperator; + } else { + return stateSearchBase64; } } } @@ -915,18 +894,55 @@ - (BOOL)isDataBase64EncodedPGP:(NSData *)theData { } +- (charaterType)characterType:(NSInteger)byte { + + switch (byte) { + case '\r': + case ' ': + case '\t': + case 0: + return charTypeWhitespace; + case '\n': + return charTypeNewline; + case 0xE2: { // Possible an unicode separator. + byte = [self getByte:0]; + if (byte != 0x80) { + return charTypeNormal; // Not an separator; + } + + byte = [self getByte:1]; + if (byte != 0xA8 && byte != 0xA9) { + return charTypeNormal; // Not an separator; + } + + [self nextByte]; // Consume the whole multi-byte caracter. + [self nextByte]; + + return charTypeNewline; + } + default: + return charTypeNormal; + } + +} + - (NSInteger)nextByte { - if (cacheIndex == cacheSize) { - cacheIndex = 0; - self.cacheData = [stream readDataOfLength:cacheSize]; + if (cacheIndex >= cacheSize) { + NSData *tempData = [stream readDataOfLength:cacheSize]; + NSUInteger tempDataLength = tempData.length; - NSUInteger cacheDataLength = cacheData.length; - if (cacheDataLength < cacheSize) { - cacheEnd = cacheDataLength; + if (cacheIndex == NSUIntegerMax) { + cacheIndex = 2; + } else { + [cacheData replaceBytesInRange:NSMakeRange(0, cacheReserve) withBytes:cacheBytes+cacheSize]; + cacheIndex = 0; } + [cacheData replaceBytesInRange:NSMakeRange(cacheReserve, tempDataLength) withBytes:tempData.bytes]; - cacheBytes = cacheData.bytes; + if (tempDataLength < cacheSize) { + cacheEnd = tempDataLength; + } } if (cacheIndex == cacheEnd) { return -1; @@ -936,6 +952,7 @@ - (NSInteger)nextByte { cacheIndex++; streamOffset++; + //TODO: Handle Unicode line seperators! switch (byte) { case '\n': invalidCharInLine = NO; @@ -959,6 +976,19 @@ - (NSInteger)nextByte { return byte; } +- (NSInteger)getByte:(NSUInteger)offset { + NSAssert(offset < cacheReserve, @"offset greater than cacheReserve!"); + + NSUInteger index = cacheIndex + offset; + if (index >= cacheEnd) { + return -1; + } + + UInt8 byte = cacheBytes[index]; + return byte; +} + + #pragma init, dealloc, etc. @@ -975,9 +1005,10 @@ - (instancetype)initWithGPGStream:(GPGStream *)theStream { stream = [theStream retain]; streamOffset = stream.offset; cacheEnd = NSUIntegerMax; - cacheIndex = cacheSize; + cacheIndex = NSUIntegerMax; base64Data = [[NSMutableData alloc] init]; - + cacheData = [[NSMutableData alloc] initWithLength:cacheSize + cacheReserve]; + cacheBytes = cacheData.mutableBytes; return self; } @@ -985,7 +1016,7 @@ - (instancetype)initWithGPGStream:(GPGStream *)theStream { - (void)dealloc { [stream release]; [base64Data release]; - self.cacheData = nil; + [cacheData release]; self.data = nil; self.clearText = nil; self.error = nil;