简体   繁体   中英

How to send a client SSL certificate to server by using CFStream in my iOS app?

We have a WebSocket security server working on SSL. We hope to put a client SSL certificate in our iOS client, in order to ensure the security when communicating with server.

Because we are using WebSocket, in iOS client, we use SocketRocket (Objective-C WebSocket client library) to implement WebSocket communication.

The problem is I have no idea on how to send my client SSL certificate to server.

I can set the properties of CFStream, like kCFStreamPropertySocketSecurityLevel . But I don't know how it works. And I can't find any docs about certificate in CFStream.

I know that when we need to connect to a HTTPS server, we can use didReceiveAuthenticationChallenge in NSURLConnection. But And as I know, there wasn't a counterpart in CFStream.

Could someone have any ideas?

After a lot of study and trying, I can answer myself now. Also hope it'll be useful for you.

Actually, what I need is implementing client SSL authentication by using CFStream. So I need to do these:

  1. Put PKCS #12 file in my app bundle
  2. Read this file as NSData to pkcsData
  3. Use method SecPKCS12Import to import pkcsData
  4. Get identity and cert from the data you imported above, and generate a certificates array
  5. Set the array to key kCFStreamSSLCertificates in kCFStreamPropertySSLSettings of your CFWriteStreamRef

Sample code below:

  // Read .p12 file
  NSString *path = [[NSBundle mainBundle] pathForResource:@"client" ofType:@"p12"];
  NSData *pkcs12data = [[NSData alloc] initWithContentsOfFile:path];

  // Import .p12 data
  CFArrayRef keyref = NULL;
  OSStatus sanityChesk = SecPKCS12Import((__bridge CFDataRef)pkcs12data,
                                         (__bridge CFDictionaryRef)[NSDictionary
                                                                    dictionaryWithObject:@"123456"
                                                                    forKey:(__bridge id)kSecImportExportPassphrase],
                                         &keyref);
  if (sanityChesk != noErr) {
    NSLog(@"Error while importing pkcs12 [%ld]", sanityChesk);
  } else
    NSLog(@"Success opening p12 certificate.");

  // Identity
  CFDictionaryRef identityDict = CFArrayGetValueAtIndex(keyref, 0);
  SecIdentityRef identityRef = (SecIdentityRef)CFDictionaryGetValue(identityDict,
                                                                    kSecImportItemIdentity);

  // Cert
  SecCertificateRef cert = NULL;
  OSStatus status = SecIdentityCopyCertificate(identityRef, &cert);
  if (status)
    NSLog(@"SecIdentityCopyCertificate failed.");

  // the certificates array, containing the identity then the root certificate
  NSArray *myCerts = [[NSArray alloc] initWithObjects:(__bridge id)identityRef, (__bridge id)cert, nil];

  //
  [SSLOptions setObject:[NSNumber numberWithBool:YES] forKey:(NSString *)kCFStreamSSLAllowsExpiredRoots];
  [SSLOptions setObject:[NSNumber numberWithBool:YES] forKey:(NSString *)kCFStreamSSLAllowsExpiredCertificates];
  [SSLOptions setObject:[NSNumber numberWithBool:YES] forKey:(NSString *)kCFStreamSSLAllowsAnyRoot];
  [SSLOptions setObject:[NSNumber numberWithBool:NO] forKey:(NSString *)kCFStreamSSLValidatesCertificateChain];
  [SSLOptions setObject:@"test.domain.com:443" forKey:(NSString *)kCFStreamSSLPeerName];
  [SSLOptions setObject:(NSString *)kCFStreamSocketSecurityLevelNegotiatedSSL forKey:(NSString*)kCFStreamSSLLevel];
  [SSLOptions setObject:(NSString *)kCFStreamSocketSecurityLevelNegotiatedSSL forKey:(NSString*)kCFStreamPropertySocketSecurityLevel];
  [SSLOptions setObject:myCerts forKey:(NSString *)kCFStreamSSLCertificates];
  [SSLOptions setObject:[NSNumber numberWithBool:NO] forKey:(NSString *)kCFStreamSSLIsServer];

  [_outputStream setProperty:SSLOptions
                        forKey:(__bridge id)kCFStreamPropertySSLSettings];

Because I use SocketRocket, I've added these code in my own fork: https://github.com/nickcheng/SocketRocket

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM