How to add a CA SSL certificate in iOs with kCFStreamSSLCertificates?

1,148 views
Skip to first unread message

Sylvain LG

unread,
Feb 26, 2015, 7:02:13 AM2/26/15
to cocoaasy...@googlegroups.com
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
Reply all
Reply to author
Forward
0 new messages