Skip to content

Instantly share code, notes, and snippets.

@juantrias
Last active April 27, 2017 14:50
Show Gist options
  • Select an option

  • Save juantrias/193c94e0fc10ded628fd5c8df5ad3b71 to your computer and use it in GitHub Desktop.

Select an option

Save juantrias/193c94e0fc10ded628fd5c8df5ad3b71 to your computer and use it in GitHub Desktop.
Valet extension to support kSecUseAuthenticationContext https://github.com/square/Valet/issues/104
#import <Foundation/Foundation.h>
@interface AuthContextSecureEnclaveKeychain : NSObject
- (instancetype)initWithIdentifier:(NSString *)identifier userPrompt:(NSString *)userPrompt;
- (NSString *)stringForKey:(NSString *)key;
- (BOOL)setString:(NSString *)string forKey:(NSString *)key;
- (void)removeObjectForKey:(NSString *)key;
- (void)invalidateAuthentication;
- (BOOL)checkValidAuthenticationUsingKey:(NSString *)key;
@end
#import "AuthContextSecureEnclaveKeychain.h"
#import <LocalAuthentication/LocalAuthentication.h>
#import <Valet/Valet.h>
#import "VALSecureEnclaveValet+AuthenticationContext.h"
@interface AuthContextSecureEnclaveKeychain ()
@property(nonatomic, strong) VALSecureEnclaveValet *valet;
@property(nonatomic, strong) LAContext *context;
@property(nonatomic, copy) NSString *userPrompt;
@end
@implementation AuthContextSecureEnclaveKeychain
- (instancetype)initWithIdentifier:(NSString *)identifier userPrompt:(NSString *)userPrompt {
self = [super init];
if (self) {
self.valet = [[VALSecureEnclaveValet alloc] initWithIdentifier:identifier accessControl:VALAccessControlTouchIDCurrentFingerprintSet];
self.context = [LAContext new];
self.userPrompt = userPrompt;
}
return self;
}
- (BOOL)setString:(NSString *)string forKey:(NSString *)key {
return [self.valet setString:string forKey:key];
}
- (NSString *)stringForKey:(NSString *)key {
return [self.valet stringForKey:key userPrompt:self.userPrompt authenticationContext:self.context userCancelled:NULL];
}
- (void)removeObjectForKey:(NSString *)key {
[self.valet removeObjectForKey:key];
}
- (void)invalidateAuthentication {
[self.context invalidate];
self.context = [LAContext new];
}
- (BOOL)checkValidAuthenticationUsingKey:(NSString *)key {
BOOL keyExists = [self.valet containsObjectForKey:key];
if (!keyExists) {
[self invalidateAuthentication];
}
return keyExists;
}
@end
#import <Foundation/Foundation.h>
#import <Valet/Valet.h>
@class LAContext;
@interface VALSecureEnclaveValet (AuthenticationContext)
- (NSString *)stringForKey:(NSString *)key userPrompt:(NSString *)userPrompt authenticationContext:(LAContext *)authenticationContext userCancelled:(BOOL *)userCancelled;
@end
#import "VALSecureEnclaveValet+AuthenticationContext.h"
#import <LocalAuthentication/LocalAuthentication.h>
#import "VALValet_Protected.h"
@implementation VALSecureEnclaveValet (AuthenticationContext)
- (nullable NSString *)stringForKey:(nonnull NSString *)key userPrompt:(nullable NSString *)userPrompt
authenticationContext:(nullable LAContext *)authenticationContext userCancelled:(nullable inout BOOL *)userCancelled {
NSMutableDictionary *options = [NSMutableDictionary dictionary];
if (authenticationContext) {
options[(id) kSecUseAuthenticationContext] = authenticationContext;
}
NSDictionary *userPromptOptions = [self prv_optionsDictionaryForUserPrompt:userPrompt];
if (userPromptOptions) {
[options addEntriesFromDictionary:userPromptOptions];
}
OSStatus status = errSecSuccess;
NSString *const stringForKey = [self stringForKey:key options:[options copy] status:&status];
if (userCancelled != NULL) {
*userCancelled = (status == errSecUserCanceled || status == errSecAuthFailed);
}
return stringForKey;
}
- (nullable NSDictionary *)prv_optionsDictionaryForUserPrompt:(nullable NSString *)userPrompt {
if (userPrompt.length == 0) {
return nil;
} else {
return @{(__bridge id) kSecUseOperationPrompt: userPrompt};
}
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment