Commit 81879065 authored by Joel Rennich's avatar Joel Rennich

Keychain updates

parent d1934c30
......@@ -89,5 +89,44 @@ extension String {
return cleanString //.addingPercentEncoding(withAllowedCharacters: .alphanumerics)
}
}
extension Data {
init?(fromHexEncodedString string: String) {
// Convert 0 ... 9, a ... f, A ...F to their decimal value,
// return nil for all other input characters
func decodeNibble(u: UInt16) -> UInt8? {
switch(u) {
case 0x30 ... 0x39:
return UInt8(u - 0x30)
case 0x41 ... 0x46:
return UInt8(u - 0x41 + 10)
case 0x61 ... 0x66:
return UInt8(u - 0x61 + 10)
default:
return nil
}
}
self.init(capacity: string.utf16.count/2)
var even = true
var byte: UInt8 = 0
for c in string.utf16 {
guard let val = decodeNibble(u: c) else { return nil }
if even {
byte = val << 4
} else {
byte += val
self.append(byte)
}
even = !even
}
guard even else { return nil }
}
func hexEncodedString() -> String {
return map { String(format: "%02hhx", $0) }.joined()
}
}
......@@ -305,7 +305,6 @@ class KeychainUtil {
if account != "" && account != "<<NONE>>" && account != "<<ANY>>" {
itemSearch[kSecAttrAccount as String] = (item.value as! String).variableSwap() as AnyObject
} else {
// remove the account attribute if it's in there
itemSearch.removeValue(forKey: kSecAttrAccount as String)
}
......@@ -338,11 +337,11 @@ class KeychainUtil {
SecKeychainSetUserInteractionAllowed(false)
let account = entry["acct"] as! String
let itemName = entry["labl"] as! String
var myKeychainItem: SecKeychainItem?
let account = entry["acct"] as? String ?? ""
let itemName = entry["labl"] as? String ?? ""
let myKeychainItem = entry["v_Ref"] as! SecKeychainItem
myErr = SecKeychainFindGenericPassword(nil, UInt32(itemName.count), itemName, UInt32(account.count), account, &passLength, &passPtr, &myKeychainItem)
myErr = SecKeychainFindGenericPassword(nil, UInt32(itemName.count), itemName, UInt32(account.count), account, &passLength, &passPtr, nil)
SecKeychainSetUserInteractionAllowed(true)
......@@ -353,41 +352,62 @@ class KeychainUtil {
myLogger.logit(.debug, message: "Adjusting ACL of keychain item \(itemName) : \(account)")
myErr = SecKeychainItemCopyAccess(myKeychainItem!, &itemAccess)
myErr = SecKeychainItemCopyAccess(myKeychainItem, &itemAccess)
myErr = SecTrustedApplicationCreateFromPath( nil, &secApp)
// DECRYPT ACL
myACLs = SecAccessCopyMatchingACLList(itemAccess!, kSecACLAuthorizationDecrypt)
SecAccessCopyACLList(itemAccess!, &myACLs)
var appList: CFArray? = nil
var desc: CFString? = nil
var newacl: AnyObject? = nil
var prompt = SecKeychainPromptSelector()
for acl in myACLs as! Array<SecACL> {
SecACLCopyContents(acl, &appList, &desc, &prompt)
let authArray = SecACLCopyAuthorizations(acl)
newacl = acl
if !(authArray as! [String]).contains("ACLAuthorizationPartitionID") {
continue
}
if appList != nil {
var newAppList = appList as! [SecTrustedApplication]
newAppList.append(secApp!)
// adding NoMAD to the ACL app list
myErr = SecACLSetContents(acl, newAppList as CFArray, desc!, SecKeychainPromptSelector.init(rawValue: 0))
} else {
let newAppList : [SecTrustedApplication] = [
secApp!
]
myErr = SecACLSetContents(acl, newAppList as CFArray, desc!, SecKeychainPromptSelector.init(rawValue: 0))
// pull in the description that's really a functional plist <sigh>
let rawData = Data.init(fromHexEncodedString: desc! as String)
var format: PropertyListSerialization.PropertyListFormat = .xml
var propertyListObject = try? PropertyListSerialization.propertyList(from: rawData!, options: [], format: &format) as! [ String: [String]]
// add in the team ID that NoMAD is signed with if it doesn't already exist
if !(propertyListObject!["Partitions"]?.contains("teamid:AAPZK3CB24"))! {
propertyListObject!["Partitions"]?.append("teamid:AAPZK3CB24")
}
if defaults.bool(forKey: Preferences.keychainItemsDebug) {
myLogger.logit(.debug, message: String(describing: propertyListObject))
}
// now serialize it back into a plist
var xmlObject = try? PropertyListSerialization.data(fromPropertyList: propertyListObject, format: format, options: 0)
// Hi Rick, how's things?
myErr = SecKeychainItemSetAccessWithPassword(entry as! SecKeychainItem, itemAccess!, UInt32(newPassword.count), newPassword)
myErr = SecKeychainItemSetAccessWithPassword(myKeychainItem, itemAccess!, UInt32(newPassword.count), newPassword)
// now that all ACLs has been adjusted, we can update the item
myErr = SecItemUpdate(itemSearch as CFDictionary, attrToUpdate as CFDictionary)
// now add NoMAD and the original apps back into the property object
myErr = SecACLSetContents(acl, appList, xmlObject!.hexEncodedString() as CFString, prompt)
// smack it again to set the ACL
myErr = SecKeychainItemSetAccessWithPassword(myKeychainItem, itemAccess!, UInt32(newPassword.count), newPassword)
}
if myErr != 0 {
......@@ -398,11 +418,7 @@ class KeychainUtil {
myLogger.logit(.debug, message: "Keychain item \(itemName) : \(account) is available via ACLs.")
}
}
// now that all ACLs are checked, we can update all the items
myErr = SecItemUpdate(itemSearch as CFDictionary, attrToUpdate as CFDictionary)
if myErr == 0 {
myLogger.logit(.debug, message: "Updated password for service: \(item.key)")
} else {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment