SSL with CFStreams
SSL with CFStreams
- Subject: SSL with CFStreams
- From: David Riggle <email@hidden>
- Date: Wed, 20 Jun 2007 15:27:52 -0700
I'm a total SSL noob. I searched the archives, I looked for sample
code, I even attended the networking lab at WWDC, but I still can't
get SSL to work properly. Maybe someone here can help me with the
dark arts.
I have a peer-to-peer photo sharing app. I'm using AsyncSocket,
which is a wrapper for CFStream. I want to use SSL simply for
encryption. Here's my "client" code to initiate a connection.
-(BOOL)onSocketWillConnect:(AsyncSocket *)sock
{
NSDictionary *sslProperties = [NSDictionary
dictionaryWithObjectsAndKeys:
(NSString *)kCFStreamSocketSecurityLevelNegotiatedSSL,
kCFStreamSSLLevel,
kCFBooleanTrue, kCFStreamSSLAllowsAnyRoot,
kCFBooleanFalse, kCFStreamSSLValidatesCertificateChain,
kCFNull, kCFStreamSSLPeerName,
kCFBooleanFalse, kCFStreamSSLIsServer,
nil];
CFReadStreamSetProperty([sock getCFReadStream],
kCFStreamPropertySSLSettings, sslProperties);
CFWriteStreamSetProperty([sock getCFWriteStream],
kCFStreamPropertySSLSettings, sslProperties);
return YES;
}
Here is my "server" side code.
-(BOOL)onSocketWillConnect:(AsyncSocket *)sock
{
SecKeychainRef keychainRef = nil;
SecIdentitySearchRef searchRef = nil;
SecIdentityRef mySSLIdentity = nil;
OSStatus err;
err = SecKeychainCopyDefault(&keychainRef);
if (err != noErr) goto error;
err = SecIdentitySearchCreate(keychainRef, CSSM_KEYUSE_DECRYPT,
&searchRef);
if (err != noErr) goto error;
err = SecIdentitySearchCopyNext(searchRef, &mySSLIdentity);
if (err == errSecItemNotFound) {
// create a certificate of our own
[SSLUtilities addSelfSignedCertToKeychain:keychainRef];
CFRelease(searchRef);
err = SecIdentitySearchCreate(keychainRef, CSSM_KEYUSE_DECRYPT,
&searchRef);
if (err != noErr) goto error;
err = SecIdentitySearchCopyNext(searchRef, &mySSLIdentity);
}
if (err != noErr) goto error;
CFArrayRef ca = CFArrayCreate(NULL, (const void **)&mySSLIdentity,
1, NULL);
NSDictionary *sslProperties = [NSDictionary
dictionaryWithObjectsAndKeys:
(NSString *)kCFStreamSocketSecurityLevelNegotiatedSSL,
kCFStreamSSLLevel,
kCFBooleanTrue, kCFStreamSSLAllowsAnyRoot,
kCFBooleanFalse, kCFStreamSSLValidatesCertificateChain,
kCFNull, kCFStreamSSLPeerName,
ca, kCFStreamSSLCertificates,
kCFBooleanTrue, kCFStreamSSLIsServer,
nil];
CFReadStreamSetProperty([sock getCFReadStream],
kCFStreamPropertySSLSettings, sslProperties);
CFWriteStreamSetProperty([sock getCFWriteStream],
kCFStreamPropertySSLSettings, sslProperties);
CFRelease(ca);
error:
if (keychainRef != nil) CFRelease(keychainRef);
if (searchRef != nil) CFRelease(searchRef);
if (mySSLIdentity != nil) CFRelease(mySSLIdentity);
return YES;
}
+ (void)addSelfSignedCertToKeychain:(SecKeychainRef)keychain
{
// create a path to a temp file
NSString *tmpPath = [NSTemporaryDirectory()
stringByAppendingPathComponent:@"tmpCert.pem"];
if (tmpPath == nil) return;
// launch openssl to create the certificate
NSTask *openSSLProcess = [[NSTask alloc] init];
[openSSLProcess setLaunchPath:@"/usr/bin/openssl"];
[openSSLProcess setArguments:[NSArray arrayWithObjects:
@"req", @"-x509", @"-nodes", @"-days", @"3650",
@"-subj", @"/C=US/ST=California/L=Los Altos/CN=com.myapp.test",
@"-newkey", @"rsa:1024", @"-keyout", tmpPath, @"-out", tmpPath,
@"-passin", @"pass:passphrase", nil]];
[openSSLProcess launch];
[openSSLProcess waitUntilExit];
int status = [openSSLProcess terminationStatus];
[openSSLProcess release];
if (status != 0) {
NSLog(@"openSSL task failed.");
return;
}
// add certificate to keychain
SecExternalFormat format = kSecFormatPEMSequence;
SecExternalItemType type = kSecItemTypeAggregate;
SecKeyImportExportParameters params;
memset(¶ms, 0, sizeof(params));
params.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
params.passphrase = CFSTR("passphrase");
params.keyUsage = CSSM_KEYUSE_DECRYPT;
params.keyAttributes = CSSM_KEYATTR_EXTRACTABLE |
CSSM_KEYATTR_PERMANENT;
OSStatus err = SecKeychainItemImport(
(CFDataRef) [NSData dataWithContentsOfFile:tmpPath],
(CFStringRef) tmpPath,
&format,
&type,
0,
¶ms,
keychain,
NULL);
if (err != noErr) {
NSLog(@"SecKeychainItemImport returned %d.", err);
}
[[NSFileManager defaultManager] removeFileAtPath:tmpPath handler:nil];
}
This code works on Tiger. However, on Leopard, I get a warning
dialog about my app wanting to use the iChat item in my keychain. I
guess SecIdentitySearch is finding the iChat identity and I'm going
with that. How do I restrict SecIdentitySearch to find only my self-
signed identity? Is that the right thing to do?
Maybe I'm making this overly complicated. Is there an easier way to
add SSL encryption to my CFStream? A Leopard-only solution would be
fine. Thanks!
Dave
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Macnetworkprog mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden