-
-
Save bikram990/d705dc184bd0c52f0223328562223fed to your computer and use it in GitHub Desktop.
Cert stuff
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma mark - NSURLConnection methods | |
/* | |
- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)connection { | |
return NO; | |
} | |
*/ | |
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace { | |
//NSLog(@"can auth"); | |
if ([[protectionSpace authenticationMethod] isEqualToString:NSURLAuthenticationMethodServerTrust]) { | |
NSArray *certificates = [self.secUtil getTrustedCertificatesFromDisk]; | |
BOOL trustedResult = [self.secUtil getTrustResult:protectionSpace certificates:(CFArrayRef)certificates]; | |
return trustedResult; //if NO, then server is untrusted | |
} | |
else if ([[protectionSpace authenticationMethod] isEqualToString:NSURLAuthenticationMethodClientCertificate]) { | |
return YES; //always YES, because server already checked for trust | |
} | |
return NO; | |
} | |
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge | |
{ | |
SecIdentityRef identity = NULL; | |
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { | |
SecTrustResultType trustResult = 0; | |
SecTrustRef serverTrust = NULL; | |
serverTrust = [[challenge protectionSpace] serverTrust]; | |
OSStatus err = [self.secUtil evaluateServerTrust:&trustResult challenge:challenge identity:&identity serverTrust:&serverTrust]; | |
if (err == noErr) { | |
//NSLog(@"NSURLAuthenticationMethodServerTrust"); | |
NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust]; | |
[challenge.sender useCredential:credential forAuthenticationChallenge:challenge]; | |
} | |
} else if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodClientCertificate]) { | |
identity = self.secUtil.currentIdentity; | |
if (identity) { | |
//NSLog(@"NSURLAuthenticationMethodClientCertificate"); | |
NSURLCredential *credential = [NSURLCredential credentialWithIdentity:identity | |
certificates:nil | |
persistence:NSURLCredentialPersistenceNone]; | |
[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge]; | |
} | |
} | |
} | |
- (SecurityUtilities *)secUtil { | |
if (!secUtil_) { | |
secUtil_ = [[SecurityUtilities alloc] init]; | |
secUtil_.certificatesPath = self.certificatesPath; | |
} | |
return secUtil_; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// | |
// Created by Taras Kalapun | |
// | |
#import "SecurityUtilities.h" | |
#import "NSString+Extension.h" | |
#import "NSData+Base64.h" | |
@implementation SecurityUtilities | |
@synthesize certificatesPath, currentIdentity, currentTrust; | |
- (void)dealloc { | |
self.certificatesPath = nil; | |
[super dealloc]; | |
} | |
- (BOOL)useCertificateWithName:(NSString *)name password:(NSString *)password { | |
return [self useCertificateWithName:name password:password path:self.certificatesPath]; | |
} | |
- (BOOL)useCertificateWithName:(NSString *)name password:(NSString *)password path:(NSString *)path | |
{ | |
name = [name stringByAppendingPathExtension:@"p12"]; | |
if (path) { | |
name = [path stringByAppendingPathComponent:name]; | |
} | |
if (!name || !password) return NO; | |
if ([password length] < 1) return NO; | |
NSString *certificatePath = name; | |
SecIdentityRef identityRef = NULL; | |
SecTrustRef trustRef = NULL; | |
BOOL isExtractOk = [self extractIdentity:&identityRef andTrust:&trustRef fromCertificate:certificatePath withPassword:password]; | |
self.currentIdentity = identityRef; | |
self.currentTrust = trustRef; | |
return isExtractOk; | |
} | |
- (NSData *)decryptAESData:(NSData *)encryptedData { | |
SecIdentityRef identity = self.currentIdentity; | |
return [self decryptData:encryptedData withIdentity:identity]; | |
} | |
- (NSData *)encryptPBEWithMD5AndDESData:(NSData *)inData password:(NSString *)password { | |
return [self encodePBEWithMD5AndDESData:inData password:password direction:1]; | |
} | |
- (NSData *)decryptPBEWithMD5AndDESData:(NSData *)inData password:(NSString *)password { | |
return [self encodePBEWithMD5AndDESData:inData password:password direction:0]; | |
} | |
#pragma mark - Certificate methods | |
- (NSString *)getDesktopCertificateCN:(NSString *)certificateName password:(NSString *)password | |
{ | |
NSString *desktopName = nil; | |
//NSString *certName = @"desktop"; | |
// NSString *password = @"1cc0ss"; | |
NSString *path = [self.certificatesPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.p12", certificateName]]; | |
NSData *desktopCertData = [NSData dataWithContentsOfFile:path]; | |
//const void *keys[] = { kSecImportExportPassphrase }; | |
//const void *values[] = { (CFStringRef)password }; | |
CFDictionaryRef optionsDictionary = (CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys:password, kSecImportExportPassphrase, nil];//CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL); | |
CFArrayRef items = NULL;//CFArrayCreate(NULL, 0, 0, NULL); | |
OSStatus securityError = SecPKCS12Import((CFDataRef)desktopCertData, optionsDictionary, &items); | |
if (securityError != noErr) { | |
NSLog(@"error while getting desktop certificate"); | |
} | |
NSArray *certItems = (NSArray *)items; | |
SecCertificateRef desktopCert = (SecCertificateRef)[[[certItems objectAtIndex:0] objectForKey:@"chain"] objectAtIndex:0]; | |
CFStringRef name = SecCertificateCopySubjectSummary(desktopCert); | |
desktopName = (NSString *)name; | |
CFRelease(items); | |
//CFRelease(optionsDictionary); | |
return [desktopName autorelease]; | |
} | |
- (NSArray *)certificateNames | |
{ | |
NSFileManager *manager = [NSFileManager defaultManager]; | |
NSArray *files = [manager contentsOfDirectoryAtPath:self.certificatesPath error:nil]; | |
NSArray *p12Files = [files filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"self ENDSWITH '.p12'"]]; | |
NSMutableArray *array = [NSMutableArray array]; | |
for (int i = 0; i < [p12Files count]; i++) | |
{ | |
NSString *str = [p12Files objectAtIndex:i]; | |
str = [str stringByReplacingOccurrencesOfString:@".p12" withString:@""]; | |
if(![str isEqualToString:@"desktop"]) | |
{ | |
[array addObject:str]; | |
} | |
} | |
return array; | |
} | |
- (NSArray *)certificateNamesFilteredByUserNames:(NSArray *)receivedUserNames | |
{ | |
NSMutableArray *names = [[NSMutableArray alloc] init]; | |
for (NSString *userName in receivedUserNames) { | |
NSString *path = [self.certificatesPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.p12", userName]]; | |
//NSLog(@"path %@", path); | |
BOOL isFileExists = [[NSFileManager defaultManager] fileExistsAtPath:path]; | |
if (isFileExists) { | |
[names addObject:userName]; | |
} | |
} | |
return [names autorelease]; | |
} | |
- (BOOL)extractIdentity:(SecIdentityRef *)outIdentity andTrust:(SecTrustRef *)outTrust fromCertificate:(NSString *)certificatePath withPassword:(NSString *)password | |
{ | |
NSData *PKCS12Data = [NSData dataWithContentsOfFile:certificatePath]; | |
if (!PKCS12Data) return NO; | |
return [self extractIdentity:outIdentity andTrust:outTrust fromPKCS12Data:PKCS12Data withPassword:password]; | |
} | |
- (BOOL)extractIdentity:(SecIdentityRef *)outIdentity andTrust:(SecTrustRef *)outTrust fromPKCS12Data:(NSData *)PKCS12Data withPassword:(NSString *)password | |
{ | |
OSStatus securityError = errSecSuccess; | |
//const void *keys[] = { kSecImportExportPassphrase }; | |
//const void *values[] = { (CFStringRef)password }; | |
//CFDataRef inPKCS12Data = (CFDataRef)PKCS12Data; | |
CFDictionaryRef optionsDictionary = (CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys:password, kSecImportExportPassphrase, nil]; //CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL); | |
CFArrayRef items = NULL; | |
//NSArray *items = nil;//CFArrayCreate(NULL, 0, 0, NULL); | |
securityError = SecPKCS12Import((CFDataRef)PKCS12Data, optionsDictionary, &items); | |
BOOL isOK = NO; | |
if (securityError == 0) { | |
// CFDictionaryRef myIdentityAndTrust = (CFDictionaryRef)([items objectAtIndex:0]); //CFArrayGetValueAtIndex (items, 0); | |
// const void *tempIdentity = NULL; | |
// tempIdentity = CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemIdentity); | |
// *outIdentity = (SecIdentityRef)tempIdentity; | |
// const void *tempTrust = NULL; | |
// tempTrust = CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemTrust); | |
// *outTrust = (SecTrustRef)tempTrust; | |
for (NSDictionary * itemDict in (id) items) { | |
assert([itemDict isKindOfClass:[NSDictionary class]]); | |
*outIdentity = (SecIdentityRef) [itemDict objectForKey:(NSString *) kSecImportItemIdentity]; | |
//assert(myIdentity != NULL); | |
} | |
isOK = YES; | |
} else { | |
NSLog(@"Failed with error code %d", (int)securityError); | |
NSAssert(securityError, @"error while extracting identity"); | |
} | |
//CFRelease(optionsDictionary); | |
//[(NSArray*)items autorelease]; | |
return isOK; | |
} | |
- (SecKeyRef)getPrivateKeyFromIdentity:(SecIdentityRef)identity | |
{ | |
SecKeyRef privateKeyFromIdentity = NULL; | |
SecIdentityCopyPrivateKey(identity,&privateKeyFromIdentity); | |
return privateKeyFromIdentity; | |
} | |
- (SecKeyRef)getPublicKeyFromCertificate:(NSString *)certificatePath withPassword:(NSString *)password { | |
NSData *myCertData = [NSData dataWithContentsOfFile:certificatePath]; | |
SecTrustRef trust1 = NULL; | |
SecIdentityRef identity = NULL; | |
OSStatus status = [self extractIdentity:&identity andTrust:&trust1 fromPKCS12Data:myCertData withPassword:password]; | |
if(status) { | |
NSLog(@"error while getting public key"); | |
} | |
// Get the certificate from the identity. | |
SecCertificateRef myReturnedCertificate = NULL; | |
status = SecIdentityCopyCertificate (identity, | |
&myReturnedCertificate); | |
if(status) { | |
NSLog(@"error while getting public key"); | |
} | |
SecCertificateRef certArray[1] = { myReturnedCertificate }; | |
CFArrayRef myCerts = CFArrayCreate( | |
NULL, (void *)certArray, | |
1, NULL); | |
SecPolicyRef policy = SecPolicyCreateBasicX509(); | |
SecTrustRef trust = NULL; | |
SecTrustCreateWithCertificates(myCerts, policy, &trust); | |
SecTrustResultType trustResult; | |
SecTrustEvaluate(trust, &trustResult); | |
SecKeyRef pub_key_leaf = SecTrustCopyPublicKey(trust); | |
[(NSMutableArray *)myCerts autorelease]; | |
return pub_key_leaf; | |
} | |
- (NSArray *)getTrustedCertificatesFromDisk { | |
NSString *trustCertPath = [self.certificatesPath stringByAppendingPathComponent:@"trusted.cer"]; | |
NSData *certData = [[[NSData alloc] initWithContentsOfFile:trustCertPath] autorelease]; | |
SecCertificateRef trustedCertificate = SecCertificateCreateWithData(kCFAllocatorDefault, (CFDataRef)certData); | |
assert(trustedCertificate != NULL); | |
NSArray *certificates = [NSArray arrayWithObject:(id)trustedCertificate];//(NSArray*)CFArrayCreate(kCFAllocatorDefault, (const void **) &trustedCertificate, 1, NULL); | |
CFRelease(trustedCertificate); | |
return certificates; | |
} | |
- (BOOL)getTrustResult:(NSURLProtectionSpace *)protectionSpace certificates:(CFArrayRef)certificates { | |
SecTrustRef trust; | |
OSStatus err; | |
SecTrustResultType trustResult; | |
BOOL trusted; | |
trust = [protectionSpace serverTrust]; | |
assert(trust != NULL); | |
err = SecTrustEvaluate(trust, &trustResult); | |
trusted = (err == noErr) && ((trustResult == kSecTrustResultProceed) || (trustResult == kSecTrustResultUnspecified)); | |
if (!trusted) { | |
err = SecTrustSetAnchorCertificates(trust, certificates); | |
if (err == noErr) { | |
err = SecTrustEvaluate(trust, &trustResult); | |
} | |
trusted = (err == noErr) && ((trustResult == kSecTrustResultProceed) || (trustResult == kSecTrustResultUnspecified)); | |
} | |
if (trusted) { | |
return YES; //server cert trusted | |
} else { | |
return NO; //server cert untrusted | |
} | |
} | |
- (NSArray *)createCertificatefromData:(CFDataRef)certificateData { | |
SecCertificateRef trustedCert = SecCertificateCreateWithData(kCFAllocatorDefault, certificateData); | |
assert(trustedCert != NULL); | |
NSArray *certificates = (NSArray*) CFArrayCreate(kCFAllocatorDefault, (const void **) &trustedCert, 1, NULL); | |
return [certificates autorelease]; | |
} | |
- (SecIdentityRef)createIdentityFromCertificate:(NSString *)certificatePath password:(NSString *)password { | |
SecIdentityRef identity = NULL; | |
SecTrustRef desktopTrust = NULL; | |
NSData *PKCS12Data = [NSData dataWithContentsOfFile:certificatePath]; | |
if (PKCS12Data) | |
{ | |
BOOL res = [self extractIdentity:&identity andTrust:&desktopTrust fromPKCS12Data:PKCS12Data withPassword:password]; | |
if (res == NO) { | |
NSLog(@"error while creating identity"); | |
} | |
} | |
return identity; | |
} | |
- (SecCertificateRef)certificateForIdentity:(SecIdentityRef)identity { | |
SecCertificateRef certificate = NULL; | |
OSStatus status = SecIdentityCopyCertificate (identity, &certificate); | |
if (status != noErr) { | |
NSLog(@"some error happend while creating identity; status code-> %@", status); | |
} | |
return certificate; | |
} | |
- (NSData *)decryptData:(NSData *)keyBase64Data withIdentity:(SecIdentityRef)identity { | |
OSStatus sanityCheck = noErr; | |
size_t cipherBufferSize = 0; | |
size_t keyBufferSize = 0; | |
uint8_t * keyBuffer = NULL; | |
SecKeyRef privateKey = [self getPrivateKeyFromIdentity:identity]; | |
// Calculate the buffer sizes | |
cipherBufferSize = SecKeyGetBlockSize(privateKey); | |
keyBufferSize = [keyBase64Data length]; | |
// Allocate buffer space | |
keyBuffer = malloc(keyBufferSize * sizeof(uint8_t)); | |
memset((void *)keyBuffer, 0x0, keyBufferSize); | |
// Decrypt using the private key | |
sanityCheck = SecKeyDecrypt(privateKey, | |
kSecPaddingPKCS1, | |
(const uint8_t *) [keyBase64Data bytes], | |
cipherBufferSize, | |
keyBuffer, | |
&keyBufferSize | |
); | |
if (sanityCheck != noErr) { | |
NSLog(@"some error happend whyle decrypting data"); | |
} | |
NSData *decryptedData = [NSData dataWithBytes:(const void *)keyBuffer length:(NSUInteger)keyBufferSize]; | |
free(keyBuffer); | |
// TODO: Test if we need release here | |
CFRelease(privateKey); | |
//NSLog(@"decrypted key: %@", [decryptedData stringWithHexBytes]); | |
return decryptedData; | |
} | |
/* | |
- (NSData *)encryptData:(NSData *)data withIdentity:(SecIdentityRef)identity { | |
OSStatus sanityCheck = noErr; | |
size_t cipherBufferSize = 0; | |
size_t keyBufferSize = 0; | |
uint8_t * keyBuffer = NULL; | |
SecKeyRef publicKey = self.publicKey; | |
// Calculate the buffer sizes | |
cipherBufferSize = SecKeyGetBlockSize(publicKey); | |
keyBufferSize = [data length]; | |
// Allocate buffer space | |
keyBuffer = malloc(keyBufferSize * sizeof(uint8_t)); | |
memset((void *)keyBuffer, 0x0, keyBufferSize); | |
// Encrypt using the private key | |
sanityCheck = SecKeyEncrypt(publicKey, | |
kSecPaddingPKCS1, | |
(const uint8_t *) [data bytes], | |
cipherBufferSize, | |
keyBuffer, | |
&keyBufferSize | |
); | |
if (sanityCheck != noErr) { | |
NSLog(@"error while encryption"); | |
} | |
NSData *encryptedData = [NSData dataWithBytes:(const void *)keyBuffer length:(NSUInteger)keyBufferSize]; | |
free(keyBuffer); | |
CFRelease(publicKey); | |
return encryptedData; | |
} | |
*/ | |
- (OSStatus)evaluateServerTrust:(SecTrustResultType *)trustResult | |
challenge:(NSURLAuthenticationChallenge *)challenge | |
identity:(SecIdentityRef *)identity | |
serverTrust:(SecTrustRef *)serverTrust | |
{ | |
*identity = self.currentIdentity; | |
//*serverTrust = self.currentTrust; | |
if (!identity || !serverTrust) return errSecParam; | |
/* | |
NSString *certificatePath = [self.certificatesPath stringByAppendingPathComponent:@"desktop.p12"]; | |
BOOL res = [self extractIdentity:identity andTrust:serverTrust fromCertificate:certificatePath withPassword:@"1cc0ss"]; | |
*/ | |
SecCertificateRef myReturnedCertificate = NULL; | |
OSStatus status = SecIdentityCopyCertificate(*identity, &myReturnedCertificate); | |
if (status != noErr) { | |
NSLog(@"some error happend while copying certificate from "); | |
} | |
OSStatus err = noErr; | |
CFArrayRef anchorCertificates = CFArrayCreate(kCFAllocatorDefault, (const void **) &myReturnedCertificate, 1, NULL); | |
//unknown behaviour, while testing everything worked | |
[(NSArray *)anchorCertificates autorelease]; | |
err = SecTrustSetAnchorCertificates(*serverTrust, anchorCertificates); | |
if (err) | |
{ | |
} | |
err = SecTrustEvaluate(*serverTrust, trustResult); | |
if (err != noErr) { | |
NSLog(@"some error while evaluate server trust"); | |
} | |
return err; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment