Problem using NSURLConnection and server trust authentication challenge - iphone

Good day to everybody,
I'm working on a singleton that should manage the download of contents through the internet, I know that exist ASIHttp request and that is an excellent lib, but I have my own reasons for not using it.
The class works pretty fine except for one thing: I'm trying to deal with the public folder of my MobileMe account without success. I uploaded a file inside it and trying to download using my class.
Reading some questions on stackOF and reading docs I came up into that code, but it seems to do not work:
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
{
if([protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
{
NSLog(#"SERVER TRUST AUTH");
return YES;
}
else if([protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodHTTPBasic])
{
NSLog(#"HTTP BASIC AUTH");
return YES;
}
NSLog(#"NO AUTH");
return NO;
}
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
NSLog(#"Authetication");
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
{
NSLog(#"Trust Challange");
SecTrustResultType trustResultType;
OSStatus err=SecTrustEvaluate(challenge.protectionSpace.serverTrust, &trustResultType);
NSLog(#"SecTrustResult %lu %ld",trustResultType,err);
if (trustResultType == kSecTrustResultProceed || trustResultType == kSecTrustResultConfirm || trustResultType == kSecTrustResultUnspecified) {
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
}
else{
[challenge.sender cancelAuthenticationChallenge:challenge];
}
// [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}
else if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodHTTPBasic])
{
NSLog(#"HTTP Challenge");
NSURLCredential *credential = [[NSURLCredential alloc] initWithUser:#"user" password:#"pass" persistence:NSURLCredentialPersistenceForSession];
[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
[credential release];
}
else{
[[challenge sender]cancelAuthenticationChallenge:challenge];
}
}
Now I'm stuck because from the log I can see that the evaluate function return a result of 4 that corresponds to a kSecTrustResultUnspecified but nothing is working even if I say to the challenge sender to continueWithoutCredentialForAuthenticationChallenge.
The url of the file is : https://public.me.com/XXXX/Objective.zip (link removed)the zip is the ObjectiveZip library that I also implemented in my class.
Any suggestion?

Related

Pair with a bluetooth peripheral using ios 5

I am developing a proximity sensing application using bluetooth technology 4.0. I am able to discover the devices. But I am not able to pair with them. Nor can i call [peripheral readRssi] method. The way I want to achieve this is that if the central scans for say 10 devices and after finding those many, it should stop the scan and then pair the devices and then constantly read the RSSI values.
My piece of code.
- (void) centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
BOOL (^test)(id obj, NSUInteger idx, BOOL *stop);
test = ^ (id obj, NSUInteger idx, BOOL *stop) {
if([[[obj peripheral] name] compare:peripheral.name] == NSOrderedSame)
return YES;
return NO;
};
PeripheralCell* cell;
NSUInteger t=[peripherals indexOfObjectPassingTest:test];
if(t!= NSNotFound)
{
cell=[peripherals objectAtIndex:t];
cell.peripheral=peripheral;
cell.rssi=RSSI;
//NSLog(#"%#",RSSI);
[scanResultTableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:t inSection:0]] withRowAnimation:UITableViewRowAnimationNone];
}
else{
cell=[[PeripheralCell alloc] init];
[peripherals addObject: cell];
[myPeripheral addObject: peripheral];
cell.peripheral=peripheral;
cell.rssi=RSSI;
NSLog(#"UUID===%#",[peripheral UUID]);
[scanResultTableView insertRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:[peripherals count]-1 inSection:0]] withRowAnimation:UITableViewRowAnimationNone];
if([myPeripheral count]==3)
{
[manager stopScan];
for(CBPeripheral *p in myPeripheral)
{
[manager connectPeripheral:p options:nil]; //this calls didConnectPeripheral but gets disconnected after some time
[p readRssi]; //this does not work even after connecting
}
}
}
}
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
//self.cBReady = false;
switch (central.state) {
case CBCentralManagerStatePoweredOff:
NSLog(#"CoreBluetooth BLE hardware is powered off");
break;
case CBCentralManagerStatePoweredOn:
NSLog(#"CoreBluetooth BLE hardware is powered on and ready");
//self.cBReady = true;
break;
case CBCentralManagerStateResetting:
NSLog(#"CoreBluetooth BLE hardware is resetting");
break;
case CBCentralManagerStateUnauthorized:
NSLog(#"CoreBluetooth BLE state is unauthorized");
break;
case CBCentralManagerStateUnknown:
NSLog(#"CoreBluetooth BLE state is unknown");
break;
case CBCentralManagerStateUnsupported:
NSLog(#"CoreBluetooth BLE hardware is unsupported on this platform");
break;
default:
break;
}
}
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
NSLog(#"connected peripheral");
}
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error;
{
NSLog(#"peripheral disconnected");
}
- (void)peripheralDidUpdateRSSI:(CBPeripheral *)peripheral error:(NSError *)error
{
NSLog(#"updated rssi");
}
how can i pair the devices...
After much searching and trail and error I found out that my code is correct. I just had to remove the devices from the ipad's Setting.
Goto Settings > General > Bluetooth > Devices.
Select the device by clicking the accessory indicator. In the next screen just click on "Forget this Device".
Running the application again solved my problem.

GCDAsyncSocket - Read stream never completes

I am playing with GCDAsyncSocket (MRC / iOS5.1) for a while, especially with "large" files (5 - 10 mb). Unfortunately sometimes the read stream is never completed (e.g. it gets stuck) just a few bytes at the end of the stream; the didReadPartialDataOfLength: stops giving me information and the didReadData is not fired at all.
Here's some of my code (for both writing / reading examples the connection between the host and client have been established)
WRITING
#define kHeadTag 0
#define kDataTag 1
typedef struct {
NSUInteger size;
} head_t;
-(void)sendData:(NSData *)__data {
_sendData = [__data retain];
head_t header;
header.size = __data.length;
[_socket writeData:[NSData dataWithBytes:&header
length:sizeof(header)]
withTimeout:-1
tag:kHeadTag];
}
-(void)socket:(GCDAsyncSocket *)sock
didWriteDataWithTag:(long)tag {
if (tag == kHeadTag) {
[sock writeData:_sendData withTimeout:-1 tag:kDataTag];
[_sendData release];
_sendData = nil;
}
}
READING
-(void)socket:(GCDAsyncSocket *)sock
didReadData:(NSData *)data
withTag:(long)tag {
switch (tag) {
// ------------------------------------- HEAD
case kHeadTag:{
head_t head;
[data getBytes:&head length:sizeof(head)];
_readHead = head;
NSLog(#"Received header (total size = %i bytes)", head.size);
[sock readDataToLength:head.size
withTimeout:-1
tag:kDataTag];
}
break;
// ------------------------------------- BODY
case kDataTag: {
NSLog(#"Data received with %i bytes", data.length);
[sock readDataToLength:sizeof(head_t) withTimeout:-1 tag:kHeadTag];
}
break;
}
};
-(void)socket:(GCDAsyncSocket *)sock
didReadPartialDataOfLength:(NSUInteger)partialLength
tag:(long)tag {
if (tag == kDataTag) {
NSLog(#"Data read with %i bytes", partialLength);
}
};
I hope this is enough code to see what I'm doing wrong or maybe this is a bad practice for writing/reading large chunks of data.
I added
[self.partnerSocket writeData:[GCDAsyncSocket CRLFData] withTimeout:-1 tag:0];
at the end of sendData: method, and it works fine for me. You just have to append separator chars at the end of the data.
I can transfer around 48MB of file from one iDevice to other iDevice

How to import a SSL certificate into my Application's keychain

I want to import a SSL certificate into my Application's keychain. I got a sample project from apple and I tested it. I am sure that technically it can be done. But my question is that, what kind of approach should I use while asking the client to install the certificate. I thought about the following options,
->Prompting the user to install the credentials at the application launch.
->Maintaining a settings page to control the credentials.
As my application totally depends upon web services I cannot proceed without the credentials. Please post your suggestions.
Ask your certificate provider for a link to download the certificate. Just Download and Store the certificate in your resources folder.
The below set of code snippets will do the work for you. Please post comments if you don't understand the below.
SecIdentityRef identity = NULL;
SecTrustRef trust = NULL;
NSData *PKCS12Data = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"test_iphone_services" ofType:#"p12"]];
//Calling the method
[Child extractIdentity:&identity andTrust:&trust fromPKCS12Data:PKCS12Data]
+ (BOOL)extractIdentity:(SecIdentityRef *)outIdentity andTrust:(SecTrustRef*)outTrust fromPKCS12Data:(NSData *)inPKCS12Data
{
OSStatus securityError = errSecSuccess;
//testtest is the passsword for the certificate.
NSDictionary *optionsDictionary = [NSDictionary dictionaryWithObject:#"testtest" forKey:(id)kSecImportExportPassphrase];
CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
securityError = SecPKCS12Import((CFDataRef)inPKCS12Data,(CFDictionaryRef)optionsDictionary,&items);
if (securityError == 0) {
CFDictionaryRef myIdentityAndTrust = 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;
} else {
NSLog(#"Failed with error code %d",(int)securityError);
return NO;
}
return YES;
}
#pragma mark - NSURLConnection Delegate Methods
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodClientCertificate];
}
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
NSLog(#"trust %#", trust);
NSURLCredential *credential;
NSURLCredentialPersistence persistence;
persistence = NSURLCredentialPersistencePermanent;
credential = [NSURLCredential credentialWithIdentity:identity certificates:nil persistence:persistence];
NSLog(#"credential %#", credential);
[challenge.sender useCredential:credential forAuthenticationChallenge:challenge];
}

in app purchase non consumable product

I have written the following code.
But when i execute this code, i got log, which shows "no products available".
I am unable to find the reason.
-(void)viewDidLoad {
[super viewDidLoad];
if ([SKPaymentQueue canMakePayments])
{
SKProductsRequest *productsRequest=[[SKProductsRequest alloc]initWithProductIdentifiers:[NSSet setWithObject:#"com.cmp.name.prdt"]];
productsRequest.delegate=self;
[productsRequest start];
}
else {
NSLog(#"Parental Control are enabled");
}
}
-(IBAction)btnpurchase
{
NSString* isPurchased = [[NSUserDefaults standardUserDefaults] stringForKey:#"com.cmp.name.prdt"];
if ([#"purchased" compare:isPurchased]==NSOrderedSame)
{
///do some task
}
else
{
SKPayment * payment=[SKPayment paymentWithProductIdentifier:#"com.cmp.name.prdt"];
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
}
-(void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
SKProduct *validProduct=nil;
int count=[response.products count];
if (count>0) {
validProduct=[response.products objectAtIndex:0];
}
else if(!validProduct)
{
NSLog(#"no products available");
}
}
-(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
for (SKPaymentTransaction *transaaction in transactions)
{
switch (transaaction.transactionState)
{
case SKPaymentTransactionStatePurchasing:
break;
case SKPaymentTransactionStatePurchased:
[[SKPaymentQueue defaultQueue]finishTransaction:transaaction];
[[NSUserDefaults standardUserDefaults] setObject:#"purchased" forKey:#"com.cmp.name.prdt"];
[[NSUserDefaults standardUserDefaults] synchronize];
break;
case SKPaymentTransactionStateRestored:
[[SKPaymentQueue defaultQueue]finishTransaction:transaaction];
break;
case SKPaymentTransactionStateFailed:
if (transaaction.error.code!=SKErrorPaymentCancelled) {
NSLog(#"Error encountered");
}
[[SKPaymentQueue defaultQueue] finishTransaction:transaaction];
break;
default:
break;
}
}
}
Could anyone help me out in this?
You can try out with following piece of code
//PRODUCT REQUEST DELEGATE METHOD
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
NSLog(#"The product request didReceiveResponse :%#",[response description]);
NSLog(#"The products are :%#",[response.products description]);
NSLog(#"The invalidProductIdentifiers are:%#",[response.invalidProductIdentifiers description]);
NSArray *products=response.products;
for(SKProduct *currentProduct in products){
NSLog(#"THE Product price is :%#",currentProduct.price);
NSLog(#"THE Product description is :%#",currentProduct.localizedDescription);
NSLog(#"THE Product title is :%#",currentProduct.localizedTitle);
NSLog(#"THE Product's product identifier is :%#",currentProduct.productIdentifier);
}
}
THIS WILL LOG THE PRODUCT DETAILS REGISTERED ON iTUNES CONNECT IN CONSOLE WINDOW
Unfortunately, Apple does not respond with any useful information about why your purchases do not show up. I would go through this checklist. In my apps, things didn't work for a few days, then the suddenly started working. Be sure your financial info is correct.

NSURLConnection SSL HTTP Basic Auth

I am unable to get a url request to do both ssl urls and basic authentication. I did check the other related questions and they dont seem to work
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
// NSLog(#"We are checking protection Space!");
if([protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
{
NSLog(#"Can Auth Secure Requestes!");
return YES;
}
else if([protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodHTTPBasic])
{
NSLog(#"Can Auth Basic Requestes!");
return YES;
//return NO;
}
NSLog(#"Cannot Auth!");
return NO;
}
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge: (NSURLAuthenticationChallenge *)challenge {
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
{
NSLog(#"Trust Challenge Requested!");
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
[challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}
else if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodHTTPBasic])
{
NSLog(#"HTTP Auth Challenge Requested!");
NSURLCredential *credential = [[NSURLCredential alloc] initWithUser:#"user" password:#"pass" persistence:NSURLCredentialPersistenceForSession];
[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
[credential release];
}
Can't seem to figure out what im doing wrong here. The Connection description says Secure Connection Failed. I have tried with simply ssl and no basic it works fine. I have also tried without ssl and basic and it works fine.
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
if([protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
{
return YES;
}
else
{
if([protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodHTTPBasic])
{
return YES;
}
}
return NO;
}
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge: (NSURLAuthenticationChallenge *)challenge {
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
{
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
[challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}
else
{
if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodHTTPBasic])
{
NSURLCredential *creden = [[NSURLCredential alloc] initWithUser:#"USERNAME" password:#"PASSWORD" persistence:NSURLCredentialPersistenceForSession];
[[challenge sender] useCredential:creden forAuthenticationChallenge:challenge];
[creden release];
}
else
{
[[challenge sender]cancelAuthenticationChallenge:challenge];
}
}
}
It works fine actually, the problem had to do with the SSL certificate.
I think the accepted answer may end up incorrectly trusting invalid server certificates, as it doesn't validate the server trust.
Apple's documentation for NSURLCredential credentialForTrust: indicates that you should actually validate the server trust before you use it:
Before creating a server trust credential, it is the responsibility of the delegate of an NSURLConnection object or an NSURLDownload object to evaluate the trust. Do this by calling SecTrustEvaluate, passing it the trust obtained from the serverTrust method of the server’s NSURLProtectionSpace object. If the trust is invalid, the authentication challenge should be cancelled with cancelAuthenticationChallenge:.
Apple's documentation for NSURLAuthenticationChallenge also indicates how a challenge's proposedCredential should be taken into account.
Taking this into account would yield (ARC) code something like this:
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge: (NSURLAuthenticationChallenge *)challenge
{
if (challenge.proposedCredential)
{
if (challenge.previousFailureCount == 0)
{
[challenge.sender useCredential:challenge.proposedCredential forAuthenticationChallenge:challenge];
}
else
{
// The server has rejected the proposed credential, and
// you should use that credential to populate a password
// or certificate chooser dialog, then provide a new credential.
// You can create password-based credentials by calling the
// credentialWithUser:password:persistence: method or create
// certificate-based credentials with the
NSLog(#"Need to add code here to create new credential...");
}
}
else if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
{
NSLog(#"Trust Challenge Requested!");
// As per NSURLCredential class reference, verify the server trust...
SecTrustResultType trustResult = kSecTrustResultInvalid;
const OSStatus status = SecTrustEvaluate(challenge.protectionSpace.serverTrust, &trustResult);
if (noErr == status &&
(
kSecTrustResultProceed == trustResult ||
// https://developer.apple.com/library/mac/qa/qa1360/_index.html
kSecTrustResultUnspecified == trustResult
)
)
{
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
[challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}
else
{
NSLog(#"Failed to verify server trust, cancelling...");
[challenge.sender cancelAuthenticationChallenge:challenge];
}
}
else if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodHTTPBasic])
{
NSLog(#"HTTP Auth Challenge Requested!");
NSURLCredential *credential = [[NSURLCredential alloc] initWithUser:#"user" password:#"pass" persistence:NSURLCredentialPersistenceForSession];
[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
}
}