Hello,
I try to add a CA SSL certificate with GCDAsyncSocket.
First, I generate a CA certificate like this:
openssl genrsa -out myCA.key 2048
openssl req -x509 -new -key myCA.key -out myCA.cer -days 365 -subj /CN="My CA"
If I install on an iPhone/iPad my own CA certificate (myCA.cer), this following code works:
- (void)socket:(GCDAsyncSocket *)sender didConnectToHost:(NSString *)host port:(UInt16)port
{
SecIdentityRef identityRef = nil;
NSString *identityPath = [[NSBundle mainBundle] pathForResource:@"client" ofType:@"p12"];
NSData *PKCS12Data = [NSData dataWithContentsOfFile:identityPath];
CFDataRef inPKCS12Data = (__bridge CFDataRef)PKCS12Data;
CFStringRef password = CFSTR("passwd");
const void *keys[] = { kSecImportExportPassphrase };
const void *values[] = { password };
CFDictionaryRef options = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
OSStatus securityError = SecPKCS12Import(inPKCS12Data, options, &items);
CFRelease(options);
CFRelease(password);
if (securityError == errSecSuccess) {
NSLog(@"Success opening p12 KaliTouch certificate. Items: %ld", CFArrayGetCount(items));
CFDictionaryRef identityDict = CFArrayGetValueAtIndex(items, 0);
identityRef = (SecIdentityRef)CFDictionaryGetValue(identityDict, kSecImportItemIdentity);
} else {
NSLog(@"Error opening Certificate.");
}
NSArray *certs = [[NSArray alloc] initWithObjects:(__bridge id)identityRef, nil];
NSMutableDictionary *settings = [NSMutableDictionary dictionaryWithCapacity:3];
[settings setObject:[NSNumber numberWithInteger:2] forKey:GCDAsyncSocketSSLProtocolVersionMin];
[settings setObject:[NSNumber numberWithInteger:2] forKey:GCDAsyncSocketSSLProtocolVersionMax];
[settings setObject:certs forKey:GCDAsyncSocketSSLCertificates];
[socket startTLS:settings];
}
But I would like to use my CA certificate directly into my code, like:
- (void)socket:(GCDAsyncSocket *)sender didConnectToHost:(NSString *)host port:(UInt16)port
{
NSString *certificatePath = [[NSBundle mainBundle] pathForResource:@"myCA" ofType:@"der"];
NSData *certData = [[NSData alloc] initWithContentsOfFile:certificatePath];
CFDataRef certDataRef = (__bridge CFDataRef)certData;
SecCertificateRef caRef = SecCertificateCreateWithData(NULL, certDataRef);
NSLog(@"%@", SecCertificateCopySubjectSummary(caRef));
SecIdentityRef identityRef = nil;
NSString *identityPath = [[NSBundle mainBundle] pathForResource:@"client" ofType:@"p12"];
NSData *PKCS12Data = [NSData dataWithContentsOfFile:identityPath];
CFDataRef inPKCS12Data = (__bridge CFDataRef)PKCS12Data;
CFStringRef password = CFSTR("passwd");
const void *keys[] = { kSecImportExportPassphrase };
const void *values[] = { password };
CFDictionaryRef options = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
OSStatus securityError = SecPKCS12Import(inPKCS12Data, options, &items);
CFRelease(options);
CFRelease(password);
if (securityError == errSecSuccess) {
NSLog(@"Success opening p12 KaliTouch certificate. Items: %ld", CFArrayGetCount(items));
CFDictionaryRef identityDict = CFArrayGetValueAtIndex(items, 0);
identityRef = (SecIdentityRef)CFDictionaryGetValue(identityDict, kSecImportItemIdentity);
} else {
NSLog(@"Error opening Certificate.");
}
NSArray *certs = [[NSArray alloc] initWithObjects:(__bridge id)identityRef, (__bridge id)caRef, nil];
NSMutableDictionary *settings = [NSMutableDictionary dictionaryWithCapacity:3];
[settings setObject:[NSNumber numberWithInteger:2] forKey:GCDAsyncSocketSSLProtocolVersionMin];
[settings setObject:[NSNumber numberWithInteger:2] forKey:GCDAsyncSocketSSLProtocolVersionMax];
[settings setObject:certs forKey:GCDAsyncSocketSSLCertificates];
[socket startTLS:settings];
}
This code will produce this error:
Error Domain=kCFStreamErrorDomainSSL Code=-9807 "The operation couldn’t be completed. (kCFStreamErrorDomainSSL error -9807.)" UserInfo=0x174269f80 {NSLocalizedRecoverySuggestion=Error code definition can be found in Apple's SecureTransport.h}
Error code 9807 means:
errSSLXCertChainInvalid: Invalid certificate chain.
errSSLXCertChainInvalid—The peer has an invalid certificate chain; for example, signature verification within the chain failed, or no certificates were found.
The error comes obviously from this block:
NSString *certificatePath = [[NSBundle mainBundle] pathForResource:@"myCA" ofType:@"der"];
NSData *certData = [[NSData alloc] initWithContentsOfFile:certificatePath];
CFDataRef certDataRef = (__bridge CFDataRef)certData;
SecCertificateRef caRef = SecCertificateCreateWithData(NULL, certDataRef);
NSLog(@"%@", SecCertificateCopySubjectSummary(caRef));
The file myCA.der is generated with this command:
openssl x509 -outform der -in myCA.cer -out myCA.der
I can't figure out if there is a problem with the file myCA.der (since the manual installation of myCA.cer works) or a problem into the code dealing with it.
How can I make it works?
Thanks,
Sylvain