Skip to content

Instantly share code, notes, and snippets.

@xslim
Last active June 25, 2020 00:30
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save xslim/5030506 to your computer and use it in GitHub Desktop.
Save xslim/5030506 to your computer and use it in GitHub Desktop.
Cert stuff
#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_;
}
//
//
// 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