TouchID with KeyChain - Enter Passcode screen appears malformed (Swift) - ios

I am having a hard time with this one:
Our app uses TouchID to retrieve secrets from the KeyChain that are used to authenticate to a WebApp in a WKWebView. All is fine when the user successfully authenticates with TouchID.
The problem arises when the user fails TouchID and then taps on "Enter Passcode" to authenticate via device passcode instead. I noticed that the screen that gets presented is plain white, and the passcode text-box does not show a value for the last character entered until it is masked, creating a strange user experience. This seems like a bug to me, unless I am somehow missing a configuration requirement.
// global arguments for the touchId keychain queries
let kSecClassValue = NSString(format: kSecClass)
let kSecAttrAccountValue = NSString(format: kSecAttrAccount)
let kSecValueDataValue = NSString(format: kSecValueData)
let kSecClassGenericPasswordValue = NSString(format: kSecClassGenericPassword)
let kSecAttrServiceValue = NSString(format: kSecAttrService)
let kSecMatchLimitValue = NSString(format: kSecMatchLimit)
let kSecReturnDataValue = NSString(format: kSecReturnData)
let kSecMatchLimitOneValue = NSString(format: kSecMatchLimitOne)
let kSecAttrAccessControlValue = NSString(format: kSecAttrAccessControl)
let kSecUseOperationPromptValue = NSString(format: kSecUseOperationPrompt)
// set access control
let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault,
kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, .UserPresence, nil)
// Instantiate a new default keychain query
// Tell the query to return a result
// Limit our results to one item
var keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPasswordValue, service, userAccount, kCFBooleanTrue, kSecMatchLimitOneValue, "Place your finger to authenticate.", accessControl.takeUnretainedValue()], forKeys: [kSecClassValue, kSecAttrServiceValue, kSecAttrAccountValue, kSecReturnDataValue, kSecMatchLimitValue, kSecUseOperationPromptValue, kSecAttrAccessControlValue])
var dataTypeRef :Unmanaged<AnyObject>?
// Search for the keychain item
touchIdStatusCode = SecItemCopyMatching(keychainQuery, &dataTypeRef)
Here is the generated keychainQuery dictionary:
{
"accc" = "<SecAccessControlRef: 0x170621140>";
"acct" = “MY_ACCOUNT”;
"class" = genp;
"m_Limit" = "m_LimitOne";
"r_Data" = 1;
"svce" = “MY_SERVICE”;
"u_OpPrompt" = "Place your finger to authenticate.";
}
This behavior exists on the latest iOS version (8.4). Here is the screen I was referring to:
My question is: Am I somehow causing the screen to be broken by the way I am invoking TouchID? Or is this perfectly normal for this scenario?
Thanks, and sorry for the lengthy post!

The issue described is a bug that was confirmed by Apple engineers. It still exists as of iOS 9.0.2.

Related

iOS VPN auto disconnected after sometime

I'm working on a VPN application, VPN working fine but after 15-20 minutes, its automatically disconnected.
Here is configuration I'm using
let vpnProtocol = NEVPNProtocolIKEv2()
vpnProtocol.username = CredentialsManager.shared.accessToken
vpnProtocol.localIdentifier = CredentialsManager.shared.accessToken
print("VPN Connecting to \(self.region.name ?? "Error! Must be a valid region name!")")
if let region = self.region {
f
vpnProtocol.serverAddress = region.serverAddress
vpnProtocol.remoteIdentifier = region.serverAddress
}
let encodedIdentifier = "Secret Password".data(using: .utf8)!
let item = [kSecClass: kSecClassGenericPassword,
kSecAttrGeneric: encodedIdentifier,
kSecAttrAccount: encodedIdentifier,
kSecMatchLimit: kSecMatchLimitOne,
kSecReturnPersistentRef: kCFBooleanTrue as Any,
kSecAttrService: "XYZ"] as [CFString : Any]
var passwordReference: CFTypeRef?
SecItemCopyMatching(item as CFDictionary, &passwordReference)
vpnProtocol.passwordReference = passwordReference as? Data
vpnProtocol.authenticationMethod = .none
vpnProtocol.useExtendedAuthentication = true
vpnProtocol.ikeSecurityAssociationParameters.encryptionAlgorithm =
.algorithmAES256GCM
vpnProtocol.ikeSecurityAssociationParameters.integrityAlgorithm = .SHA384
vpnProtocol.ikeSecurityAssociationParameters.diffieHellmanGroup = .group14
vpnProtocol.childSecurityAssociationParameters.encryptionAlgorithm = .algorithmAES256GCM
vpnProtocol.childSecurityAssociationParameters.integrityAlgorithm = .SHA384
vpnProtocol.childSecurityAssociationParameters.diffieHellmanGroup = .group14
vpnProtocol.disconnectOnSleep = false
self.vpnManager.protocolConfiguration = vpnProtocol
let connectRule = NEOnDemandRuleConnect()
connectRule.interfaceTypeMatch = .any
self.vpnManager.onDemandRules = [connectRule]
self.vpnManager.isOnDemandEnabled = self.connectOnDemand
self.vpnManager.localizedDescription = "XYZ VPN"
self.vpnManager.isEnabled = true
Please help me out, how to identify problem that causing auto disconnect.
change your VPN protocol with this: NEVPNProtocolIPSec
maybe it will help you.
You have configured "connect on demand", so it will connect back automatically when you will access resource next time. That is how VPN on iOS works, it will always close connection on idle.

Sign any message with the user’s private key and verify the signature on Ethereum

I'm trying to explore Ethereum and creating a app which let user sign message and validate the message.
I'm using web3swift framework for this and what I have tried so far is as follows -
let web3Rinkeby = Web3.InfuraRinkebyWeb3()
let msgStr = "This is my first Ethereum App";
let data = msgStr.data(using: .utf8)
let signMsg = web3Rinkeby.wallet.signPersonalMessage(data!, account: address);
print(signMsg);
but I'm not sure if this is right and how to validate any message as well. Please help.
Seems, that you didn't specify exact address.
Here is an example:
let web3Rinkeby = Web3.InfuraRinkebyWeb3()
///
let keystore = try! EthereumKeystoreV3(password: "")
let keystoreManager = KeystoreManager([keystore!])
web3Rinkeby.addKeystoreManager(keystoreManager)
let address = keystoreManager.addresses![0]
///
let msgStr = "This is my first Ethereum App";
let data = msgStr.data(using: .utf8)
let signMsg = web3Rinkeby.wallet.signPersonalMessage(data!, account: address);
print(signMsg);
Here is an example, how to sign transactions in the tests of the project:

The purpose Swift URL Components in iMessage Apps?

I am brand new to iMessage App development. Looking at some examples, it looks like the way information is transferred from the sender to the recipient with iMessage Apps is via URLComponents.
Is this the only way to send information on iMessage Apps?
I am unfamiliar with URLComponents in swift, does the actual URL even matter?
Thanks!!
MSMessage's url property is where you can store your custom data.
You can use iMessageDataKit library for storing key-value pairs in MSMessage objects. It makes setting and getting data really easy like:
let message: MSMessage = MSMessage()
message.md.set(value: 7, forKey: "user_id")
message.md.set(value: "john", forKey: "username")
message.md.set(values: ["joy", "smile"], forKey: "tags")
print(message.md.integer(forKey: "user_id")!)
print(message.md.string(forKey: "username")!)
print(message.md.values(forKey: "tags")!)
(Disclaimer: I'm the author of iMessageDataKit)
You can use it w/ native swift as well:
let layout = MSMessageTemplateLayout()
var components = URLComponents()
let caption = URLQueryItem(name: "caption", value: self.melody)
let decodedMelody = URLQueryItem(name: "melody", value: self.melody)
components.queryItems = [caption, decodedMelody]
let message = MSMessage(session: session ?? MSSession())
layout.image = self.screenImage.image
layout.caption = "Melody built with haptic and vibro."
layout.subcaption = "sent via iVibrio"
message.summaryText = "something summary"
message.url = components.url!
message.layout = layout
Here's my complete example how to send data and image via iMessage application

PKPaymentAuthorizationViewController(paymentRequest: requestObject) is returning nil

I am facing a problem in initilizing PKPaymentAuthorizationViewController returning nil in one of the device.
The device region is set to UK and I have added a UK issued card in the Apple Wallet.
The PKPaymentRequest is configured as following:
let request = PKPaymentRequest()
request.merchantIdentifier = "mymerchantid"
request.supportedNetworks = [PKPaymentNetworkVisa, PKPaymentNetworkMasterCard, PKPaymentNetworkAmex]
request.merchantCapabilities = PKMerchantCapability.Capability3DS
request.countryCode = "US"
request.currencyCode = "USD"
let price: <NSDecimalNumber>
let item : PKPaymentSummaryItem = PKPaymentSummaryItem(label: "amount", amount: price, type: .Pending)
request.paymentSummaryItems = [
item
]
let paymentAuthorizationVC = PKPaymentAuthorizationViewController(paymentRequest: request) // Returning Nil
if PKPaymentAuthorizationViewController.canMakePaymentsUsingNetworks(SupportedPaymentNetworks) // Returns true
Device: iPhone 6
OS: 10.2.2
Note: Same Card is onboared in another device for the same App its working fine.
Tried as mentioned in the below link and few other blogs- no luck
Apple pay PKPaymentauthorizationViewController always returning nil when loaded with Payment request
Looking for suggestions.
I had this same problem and the cause was using a Discover card for testing when it's not included as a supported payment network. Make sure that you are passing in all the credit card types that your user base will possibly use.
Try changing this line:
request.supportedNetworks = [PKPaymentNetworkVisa, PKPaymentNetworkMasterCard, PKPaymentNetworkAmex]
To the following:
request.supportedNetworks = [PKPaymentNetworkVisa, PKPaymentNetworkMasterCard, PKPaymentNetworkAmex, PKPaymentNetwork.discover]
In Swift3, The declaration for PKPaymentAuthorizationViewController init() is not defined as optional, even though it does return nil when it fails.

Adding item to keychain using Swift

I'm trying to add an item to the iOS keychain using Swift but can't figure out how to type cast properly. From WWDC 2013 session 709, given the following Objective-C code:
NSData *secret = [#"top secret" dataWithEncoding:NSUTF8StringEncoding];
NSDictionary *query = #{
(id)kSecClass: (id)kSecClassGenericPassword,
(id)kSecAttrService: #"myservice",
(id)kSecAttrAccount: #"account name here",
(id)kSecValueData: secret,
};
OSStatus = SecItemAdd((CFDictionaryRef)query, NULL);
Attempting to do it in Swift as follows:
var secret: NSData = "Top Secret".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
var query: NSDictionary = [
kSecClass: kSecClassGenericPassword,
kSecAttrService: "MyService",
kSecAttrAccount: "Some account",
kSecValueData: secret
]
yields the error "Cannot convert the expression's type 'Dictionary' to 'DictionaryLiteralConvertible'.
Another approach I took was to use Swift and the - setObject:forKey: method on a Dictionary to add kSecClassGenericPassword with the key kSecClass.
In Objective-C:
NSMutableDictionary *searchDictionary = [NSMutableDictionary dictionary];
[searchDictionary setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];
In the Objective-C code, the CFTypeRef of the various keychain item class keys are bridged over using id. In the Swift documentation it's mentioned that Swift imports id as AnyObject. However when I attempted to downcast kSecClass as AnyObject for the method, I get the error that "Type 'AnyObject' does not conform to NSCopying.
Any help, whether it's a direct answer or some guidance about how to interact with Core Foundation types would be appreciated.
EDIT 2
This solution is no longer valid as of Xcode 6 Beta 2. If you are using Beta 1 the code below may work.
var secret: NSData = "Top Secret".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
let query = NSDictionary(objects: [kSecClassGenericPassword, "MyService", "Some account", secret], forKeys: [kSecClass,kSecAttrService, kSecAttrAccount, kSecValueData])
OSStatus status = SecItemAdd(query as CFDictionaryRef, NULL)
To use Keychain Item Attribute keys as dictionary keys you have to unwrap them by using either takeRetainedValue or takeUnretainedValue (as appropriate). Then you can cast them to NSCopying. This is because they are CFTypeRefs in the header, which aren't all copyable.
As of Xcode 6 Beta 2 however, this causes Xcode to crash.
You simply need to downcast the literal:
let dict = ["hi": "Pasan"] as NSDictionary
Now dict is an NSDictionary. To make a mutable one, it's very similar to Objective-C:
let mDict = dict.mutableCopy() as NSMutableDictionary
mDict["hola"] = "Ben"
In the xcode 6.0.1 you must do this!!
let kSecClassValue = NSString(format: kSecClass)
let kSecAttrAccountValue = NSString(format: kSecAttrAccount)
let kSecValueDataValue = NSString(format: kSecValueData)
let kSecClassGenericPasswordValue = NSString(format: kSecClassGenericPassword)
let kSecAttrServiceValue = NSString(format: kSecAttrService)
let kSecMatchLimitValue = NSString(format: kSecMatchLimit)
let kSecReturnDataValue = NSString(format: kSecReturnData)
let kSecMatchLimitOneValue = NSString(format: kSecMatchLimitOne)
Perhaps things have improved since. On Xcode 7 beta 4, no casting seems to be necessary except when dealing with the result AnyObject?. Specifically, the following seems to work:
var query : [NSString : AnyObject] = [
kSecClass : kSecClassGenericPassword,
kSecAttrService : "MyAwesomeService",
kSecReturnAttributes : true, // return dictionary in result parameter
kSecReturnData : true // include the password value
]
var result : AnyObject?
let err = SecItemCopyMatching(query, &result)
if (err == errSecSuccess) {
// on success cast the result to a dictionary and extract the
// username and password from the dictionary.
if let result = result as ? [NSString : AnyObject],
let username = result[kSecAttrAccount] as? String,
let passdata = result[kSecValueData] as? NSData,
let password = NSString(data:passdata, encoding:NSUTF8StringEncoding) as? String {
return (username, password)
}
} else if (status == errSecItemNotFound) {
return nil;
} else {
// probably a program error,
// print and lookup err code (e.g., -50 = bad parameter)
}
To add a key if it was missing:
var query : [NSString : AnyObject] = [
kSecClass : kSecClassGenericPassword,
kSecAttrService : "MyAwesomeService",
kSecAttrLabel : "MyAwesomeService Password",
kSecAttrAccount : username,
kSecValueData : password.dataUsingEncoding(NSUTF8StringEncoding)!
]
let result = SecItemAdd(query, nil)
// check that result is errSecSuccess, etc...
A few things to point out: your initial problem might have been that str.dataUsingEncoding returns an Optional. Adding '!' or better yet, using an if let to handle nil return, would likely make your code work. Printing out the error code and looking it up in the docs will help a lot in isolating the problem (I was getting err -50 = bad parameter, until I noticed a problem with my kSecClass, nothing to do with data types or casts!).
This seemed to work fine or at least compiler didn't have kittens - UNTESTED beyond that
var secret: NSData = "Top Secret".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
var array1 = NSArray(objects:"\(kSecClassGenericPassword)", "MyService", "Some account", secret)
var array2 = NSArray(objects:"\(kSecClass)","\(kSecAttrService)", "\(kSecAttrAccount)","\(kSecValueData)")
let query = NSDictionary(objects: array1, forKeys: array2)
println(query)
let status = SecItemAdd(query as CFDictionaryRef, nil)
Seems to work fine in Beta 2
In order to get this to work, you need to access the retained values of the keychain constants instead. For example:
let kSecClassValue = kSecClass.takeRetainedValue() as NSString
let kSecAttrAccountValue = kSecAttrAccount.takeRetainedValue() as NSString
let kSecValueDataValue = kSecValueData.takeRetainedValue() as NSString
let kSecClassGenericPasswordValue = kSecClassGenericPassword.takeRetainedValue() as NSString
let kSecAttrServiceValue = kSecAttrService.takeRetainedValue() as NSString
let kSecMatchLimitValue = kSecMatchLimit.takeRetainedValue() as NSString
let kSecReturnDataValue = kSecReturnData.takeRetainedValue() as NSString
let kSecMatchLimitOneValue = kSecMatchLimitOne.takeRetainedValue() as NSString
You can then reference the values in the MSMutableDictionary like so:
var keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPasswordValue, service, userAccount, kCFBooleanTrue, kSecMatchLimitOneValue], forKeys: [kSecClassValue, kSecAttrServiceValue, kSecAttrAccountValue, kSecReturnDataValue, kSecMatchLimitValue])
I wrote a blog post about it at:
http://rshelby.com/2014/08/using-swift-to-save-and-query-ios-keychain-in-xcode-beta-4/
Hope this helps!
rshelby
Swift 3
let kSecClassKey = String(kSecClass)
let kSecAttrAccountKey = String(kSecAttrAccount)
let kSecValueDataKey = String(kSecValueData)
let kSecClassGenericPasswordKey = String(kSecClassGenericPassword)
let kSecAttrServiceKey = String(kSecAttrService)
let kSecMatchLimitKey = String(kSecMatchLimit)
let kSecReturnDataKey = String(kSecReturnData)
let kSecMatchLimitOneKey = String(kSecMatchLimitOne)
you can also do it inside the dictionary itself alá:
var query: [String: Any] = [
String(kSecClass): kSecClassGenericPassword,
String(kSecAttrService): "MyService",
String(kSecAttrAccount): "Some account",
String(kSecValueData): secret
]
however, this is more expensive for the compiler, even more so since you're probably using the query in multiple places.
more convenient to use the cocoa pods SSKeychain
+ (NSArray *)allAccounts;
+ (NSArray *)accountsForService:(NSString *)serviceName;
+ (NSString *)passwordForService:(NSString *)serviceName account:(NSString *)account;
+ (BOOL)deletePasswordForService:(NSString *)serviceName account:(NSString *)account;
+ (BOOL)setPassword:(NSString *)password forService:(NSString *)serviceName account:(NSString *)account;

Resources