Hi,
I'm implementing a web server with CFNetworking (through AsyncSocket) and SSL. It all works great, except for one problem. The first time (per launch) a client connects, a long delay occurs and my app locks up with a beachball. The delay usually lasts between 20-30 seconds. To add to the confusion, it does not seem to happen when the client is Safari.
If I pause or sample my app during the delay, it seems to be doing some cryptography fanciness. The stack log mentions things like "SSLGenServerDHParamsAndKey" and "BN_generate_prime". I understand that cryptography involves heavy math, but half a minute seems a bit much for a 2.8 GHz iMac. :-)
I'm using a self-signed certificate, if that has any relevance. Find a stack trace and some code below.
If anyone has a clue about how to solve this, please let me know. Any pointer in the right direction is very welcome. Thanks!
Tomas Franzén Lighthead Software
Here's a typical sample from when the app is grinding with the beachball:
Call graph: 6919 Thread_2903 6919 start 6919 main 6919 NSApplicationMain 6919 -[NSApplication run] 6919 -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] 6919 _DPSNextEvent 6919 BlockUntilNextEventMatchingListInMode 6919 ReceiveNextEventCommon 6919 RunCurrentEventLoopInMode 6919 CFRunLoopRunInMode 6919 CFRunLoopRunSpecific 6919 __CFSocketPerformV0 6919 __CFSocketDoCallback 6919 _SocketCallBack 6919 _PerformSecurityHandshake_NoLock 6919 SSLHandshake 6919 SSLHandshakeProceed 6919 SSLProcessProtocolMessage 6919 SSL2ProcessMessage 6919 SSL3ReceiveSSL2ClientHello 6919 SSLAdvanceHandshake 6919 SSLPrepareAndQueueMessage 6919 SSLEncodeServerKeyExchange 6919 SSLGenServerDHParamsAndKey 6919 pthread_once 6919 SSLInitServerDHParams 6919 CSSM_GenerateAlgorithmParams 6919 cssm_GenerateAlgorithmParams(long, unsigned long long, cssm_context const*, unsigned int, cssm_data*, unsigned int*, cssm_context_attribute**) 6919 Security::CSPFullPluginSession::GenerateAlgorithmParams(unsigned long long, Security::Context const&, unsigned int, Security::CssmData&, unsigned int&, cssm_context_attribute*&) 6919 DHKeyPairGenContext::generate(Security::Context const&, unsigned int, Security::CssmData&, unsigned int&, Security::Context::Attr*&) 6919 DHKeyPairGenContext::dhGenParams(unsigned int, unsigned int, int, NSS_DHParameter&, SecNssCoder&) 6919 DH_generate_parameters 6919 BN_generate_prime 5611 BN_is_prime_fasttest 5599 BN_mod_exp_mont 5579 BN_mod_mul_montgomery 3472 BN_from_montgomery 3255 bn_mul_add_words 3255 bn_mul_add_words
And here's the code I use for setting up SSL:
-(BOOL)onSocketWillConnect:(AsyncSocket *)sock { SecIdentityRef ident = [self identity]; NSArray *ca = [NSArray arrayWithObject:ident];
NSDictionary *sslProperties = [NSDictionary dictionaryWithObjectsAndKeys: (NSString *)kCFStreamSocketSecurityLevelNegotiatedSSL, kCFStreamSSLLevel, kCFBooleanTrue, kCFStreamSSLAllowsExpiredCertificates, kCFBooleanTrue, kCFStreamSSLAllowsExpiredRoots, kCFBooleanTrue, kCFStreamSSLAllowsAnyRoot, kCFBooleanFalse, kCFStreamSSLValidatesCertificateChain, kCFNull, kCFStreamSSLPeerName, ca, kCFStreamSSLCertificates, kCFBooleanTrue, kCFStreamSSLIsServer, nil];
CFReadStreamSetProperty([sock getCFReadStream], kCFStreamPropertySSLSettings, sslProperties); CFWriteStreamSetProperty([sock getCFWriteStream], kCFStreamPropertySSLSettings, sslProperties); return YES; } |