Skip to content

Commit

Permalink
Fix for iOS 8. SAC object is slighty different in iOS8
Browse files Browse the repository at this point in the history
  • Loading branch information
NitinJami committed Oct 10, 2016
1 parent 5db892d commit 79d4d43
Show file tree
Hide file tree
Showing 7 changed files with 23 additions and 11 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,8 @@ To build the tool, Run 'make' in the current directory. The final outcome will b
*Note:* You should also have `ldid` and `dpkg-deb` (can be instaled via Homebrew).

The tool is currently only built for 64-bit architectures. However, it is very easy to build for 32-bit arch as well. Just modify the `ARCH_FLAGS` and `TARGET` in Makefile with corresponding 32-bit arch values.

```
ARCH_FLAGS = -arch armv7s
TARGET = -target armv7s-apple-ios9
```
Binary file modified keychaineditor.deb
Binary file not shown.
2 changes: 1 addition & 1 deletion keychaineditor/DEBIAN/control
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: com.nitin.keychaineditor
Name: Keychain Editor
Version: 2.0
Version: 2.1
Architecture: iphoneos-arm
Description: CLI to dump keychain items including the new access controls. Supports only 64-bit arch.
Homepage: https://github.com/NitinJami/keychaineditor
Expand Down
Binary file modified keychaineditor/usr/local/bin/keychaineditor
Binary file not shown.
Binary file modified keychaineditor32.deb
Binary file not shown.
2 changes: 1 addition & 1 deletion src/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ guard CommandLine.arguments.count >= 2 else {
}

switch CommandLine.arguments[1] {
case "-v": print("KeychainEditor Version = 2.0")
case "-v": print("KeychainEditor Version = 2.1")
case "-f": handleSearch(args: UserDefaults.standard)
case "-e": handleEdit(args: UserDefaults.standard)
case "-d": handleDelete(args: UserDefaults.standard)
Expand Down
25 changes: 16 additions & 9 deletions src/utils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,15 @@ func decodeSecAccessControl(sacObj: Any?) -> String {
var finalDecodedValue: String = String()

// If there is no SecAccessControl object you will get a nil.
// usually, happens when device does not support it or An item is not addedd with SecAccessControl.
// usually, happens when device does not support it or An item is not added
// with SecAccessControl.
if let unwrappedSACObj = sacObj {
var operations = getOperations(unwrappedSACObj as! SecAccessControl).takeUnretainedValue() as! Dictionary<String, Any>
// iOS 8 behaves a bit differently. The SAC object is returned even though
// the device does not support it. SAC contains the AccessibilityConstant.
// Guess it has been refined in iOS9, where SAC only contains any value
// if the device supports it.
// Secondary check to make sure that we have something in SAC.
if let operations = getOperations(unwrappedSACObj as! SecAccessControl)?.takeUnretainedValue() as? Dictionary<String, Any> {
for eachOperation in operations.keys {
switch eachOperation {
case "dacl": return "Default ACL"
Expand All @@ -52,20 +58,21 @@ func decodeSecAccessControl(sacObj: Any?) -> String {
let constraints = operations["od"] as! Dictionary<String, AnyObject>
for eachConstraint in constraints.keys {
switch eachConstraint {
case "cpo": finalDecodedValue += " UserPresence "
case "cup": finalDecodedValue += " DevicePasscode "
case "pkofn": finalDecodedValue += (constraints["pkofn"] as! Int == 1 ? " Or " : " And ")
case "cbio": finalDecodedValue += ((constraints["cbio"]?.count)! == 1 ? " TouchIDAny " : " TouchIDCurrentSet ")
case "cpo": finalDecodedValue += " UserPresence "
case "cup": finalDecodedValue += " DevicePasscode "
case "pkofn": finalDecodedValue += (constraints["pkofn"] as! Int == 1 ? " Or " : " And ")
case "cbio": finalDecodedValue += ((constraints["cbio"]?.count)! == 1 ? " TouchIDAny " : " TouchIDCurrentSet ")
default: break
}
}
case "prp": finalDecodedValue += "ApplicationPassword"
default: break
}
}
return finalDecodedValue
return finalDecodedValue
}
}
return "SecAccessControl Not Applicable"
return "Not Applicable"
}

func determineTypeAndReturnString(value: Any?) -> String {
Expand Down Expand Up @@ -111,7 +118,7 @@ func canonicalizeTypesInReturnedDicts(items: [Dictionary<String, Any>]) -> [Dict
dict["Modification Time"] = determineTypeAndReturnString(value: eachDict[kSecAttrModificationDate as String])
dict["Protection"] = determineTypeAndReturnString(value: eachDict[kSecAttrAccessible as String])
dict["Data"] = determineTypeAndReturnString(value: eachDict[kSecValueData as String])
dict["User Presence"] = decodeSecAccessControl(sacObj: eachDict[kSecAttrAccessControl as String])
dict["AccessControl"] = decodeSecAccessControl(sacObj: eachDict[kSecAttrAccessControl as String])

arrayOfDict.append(dict)
}
Expand Down

0 comments on commit 79d4d43

Please sign in to comment.