diff --git a/ChangeLog b/ChangeLog index 75974663d..99a6f8259 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,16 @@ +2011-07-12 Richard Frith-Macdonald + + * Source/NSFileHandle.m: + * SSL/GSSSLHandle.m: + * Headers/Foundation/NSFileHandle.h: + Fixup to let certificate information contain a chaing with intermediate + certificate authorities. Simplify handshake using common routine for + non-blocking handshake attempt. + 2011-07-11 14:31 David Chisnall - * libs/base/trunk/Source/NSAutoreleasePool.m, - libs/base/trunk/Source/NSThread.m: Lazily initialize POSIX + * Source/NSAutoreleasePool.m, + Source/NSThread.m: Lazily initialize POSIX threads, matching OS X behaviour and stopping us from crashing when calling autorelease from a thread that was not previously registered explicitly (yuck!) @@ -13,7 +22,7 @@ 2011-07-11 12:36 David Chisnall - * libs/base/trunk/Source/NSNumber.m: [NSNumber -init] should not + * Source/NSNumber.m: [NSNumber -init] should not destroy itself when called as [super init]. This behaviour was breaking anything that subclassed NSNumber in user code (e.g. PyObjC). @@ -53,7 +62,7 @@ 2011-07-04 11:31 David Chisnall - * libs/base/trunk/Source/NSObject.m: + * Source/NSObject.m: Switch the order of the reference count and the zone so that the reference count (in reference counted mode) is always immediately in front of the object. Please test this!! @@ -66,11 +75,11 @@ 2011-06-30 14:44 David Chisnall - * libs/base/trunk/Headers/Foundation/NSArray.h, - libs/base/trunk/Headers/Foundation/NSProxy.h, - libs/base/trunk/Headers/GNUstepBase/GSVersionMacros.h, - libs/base/trunk/Headers/GNUstepBase/preface.h.in, - libs/base/trunk/Source/NSProxy.m: Rewrote NSProxy's -retain / + * Headers/Foundation/NSArray.h, + Headers/Foundation/NSProxy.h, + Headers/GNUstepBase/GSVersionMacros.h, + Headers/GNUstepBase/preface.h.in, + Source/NSProxy.m: Rewrote NSProxy's -retain / -release to be the same as NSObject, not its own ad-hoc thing. Added declaration of __bridge for use in non-ARC mode. @@ -81,25 +90,25 @@ 2011-06-29 15:21 David Chisnall - * libs/base/trunk/Headers/Foundation/NSNotification.h, - libs/base/trunk/Headers/Foundation/NSZone.h, - libs/base/trunk/Headers/GNUstepBase/preface.h.in, - libs/base/trunk/Tools/make_strings/make_strings.m: More ARC + * Headers/Foundation/NSNotification.h, + Headers/Foundation/NSZone.h, + Headers/GNUstepBase/preface.h.in, + Tools/make_strings/make_strings.m: More ARC fixes. We don't want to be using __strong void* in ARC mode (it only makes sense in GC mode and is invalid in ARC mode). 2011-06-29 13:13 David Chisnall - * libs/base/trunk/Source/NSObject.m: Add support to NSObject for + * Source/NSObject.m: Add support to NSObject for automatically zeroing __weak references when using ARC. 2011-06-29 11:50 David Chisnall - * libs/base/trunk/Headers/Foundation/NSAutoreleasePool.h, - libs/base/trunk/Headers/Foundation/NSEnumerator.h, - libs/base/trunk/Headers/Foundation/NSException.h, - libs/base/trunk/Headers/Foundation/NSZone.h, - libs/base/trunk/Headers/GNUstepBase/preface.h.in: + * Headers/Foundation/NSAutoreleasePool.h, + Headers/Foundation/NSEnumerator.h, + Headers/Foundation/NSException.h, + Headers/Foundation/NSZone.h, + Headers/GNUstepBase/preface.h.in: ARC-compatibility tweaks in the headers. ARC will not track objects inside structures and rejects code that uses object types that are not __unsafe_unretained qualified inside structures. diff --git a/Headers/Foundation/NSFileHandle.h b/Headers/Foundation/NSFileHandle.h index 93ba7e790..8e2c8f0cb 100644 --- a/Headers/Foundation/NSFileHandle.h +++ b/Headers/Foundation/NSFileHandle.h @@ -236,6 +236,22 @@ GS_EXPORT NSString * const NSFileHandleOperationException; - (BOOL) sslAccept; - (BOOL) sslConnect; - (void) sslDisconnect; +/** Make a non-blocking handshake attempt. Calls to this method should be + * repeated until the method returns YES indicating that the handshake + * completed. If the method returns YES indicating completion of the + * handshake, the result indicates whether the handshake succeeded in + * establishing a connection or not. + */ +- (BOOL) sslHandshakeEstablished: (BOOL*)result outgoing: (BOOL)isOutgoing; +/** Sets certification data for the SSL connection.
+ * The value of certFile is the path to a file containing a PEM encoded + * certificate for this host (optionally followed by other PEM encoded + * certificates in a chain leading to a root certificate authority).
+ * The value of privatekey is the path of a file containing a PEM encoded key + * used to establish handshakes using the host certificate.
+ * The value of PEMpasswd is a string used as the password to access the + * content of the key file. + */ - (void) sslSetCertificate: (NSString*)certFile privateKey: (NSString*)privateKey PEMpasswd: (NSString*)PEMpasswd; diff --git a/SSL/GSSSLHandle.m b/SSL/GSSSLHandle.m index 2852b6c29..5bf7cd4cc 100644 --- a/SSL/GSSSLHandle.m +++ b/SSL/GSSSLHandle.m @@ -156,6 +156,7 @@ threadid_function() - (BOOL) sslAccept; - (BOOL) sslConnect; - (void) sslDisconnect; +- (BOOL) sslHandshakeEstablished: (BOOL*)result outgoing: (BOOL)isOutgoing; - (void) sslSetCertificate: (NSString*)certFile privateKey: (NSString*)privateKey PEMpasswd: (NSString*)PEMpasswd; @@ -236,215 +237,100 @@ static BOOL permitSSLv2 = NO; - (BOOL) sslAccept { - int ret; - int err; - NSRunLoop *loop; + BOOL result = NO; - if (connected == YES) - { - return YES; /* Already connected. */ - } - if (isStandardFile == YES) + if (YES == isStandardFile) { NSLog(@"Attempt to make ssl connection to a standard file"); return NO; } + if (NO == [self sslHandshakeEstablished: &result outgoing: NO]) + { + NSRunLoop *loop; - /* - * Ensure we have a context and handle to connect with. - */ - if (ctx == 0) - { - ctx = SSL_CTX_new(SSLv23_server_method()); - if (permitSSLv2 == NO) - { - SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2); - } - } - if (ssl == 0) - { - ssl = SSL_new(ctx); - } - /* - * Set non-blocking so accept won't hang if remote end goes wrong. - */ - [self setNonBlocking: YES]; - IF_NO_GC([self retain];) // Don't get destroyed during runloop - loop = [NSRunLoop currentRunLoop]; - ret = SSL_set_fd(ssl, descriptor); - if (ret == 1) - { + IF_NO_GC([self retain];) // Don't get destroyed during runloop + loop = [NSRunLoop currentRunLoop]; [loop runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]]; - if (ssl == 0) + if (NO == [self sslHandshakeEstablished: &result outgoing: NO]) { - DESTROY(self); - return NO; + NSDate *final; + NSDate *when; + NSTimeInterval last = 0.0; + NSTimeInterval limit = 0.1; + + final = [[NSDate alloc] initWithTimeIntervalSinceNow: 30.0]; + when = [NSDate alloc]; + + while (NO == [self sslHandshakeEstablished: &result outgoing: NO] + && [final timeIntervalSinceNow] > 0.0) + { + NSTimeInterval tmp = limit; + + limit += last; + last = tmp; + if (limit > 0.5) + { + limit = 0.1; + last = 0.1; + } + when = [when initWithTimeIntervalSinceNow: limit]; + [loop runUntilDate: when]; + } + RELEASE(when); + RELEASE(final); } - ret = SSL_accept(ssl); + DESTROY(self); } - if (ret != 1) - { - NSDate *final; - NSDate *when; - NSTimeInterval last = 0.0; - NSTimeInterval limit = 0.1; - - final = [[NSDate alloc] initWithTimeIntervalSinceNow: 30.0]; - when = [NSDate alloc]; - - err = SSL_get_error(ssl, ret); - while ((err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) - && [final timeIntervalSinceNow] > 0.0) - { - NSTimeInterval tmp = limit; - - limit += last; - last = tmp; - when = [when initWithTimeIntervalSinceNow: limit]; - [loop runUntilDate: when]; - if (ssl == 0) - { - RELEASE(when); - RELEASE(final); - DESTROY(self); - return NO; - } - ret = SSL_accept(ssl); - if (ret != 1) - { - err = SSL_get_error(ssl, ret); - } - else - { - err = SSL_ERROR_NONE; - } - } - RELEASE(when); - RELEASE(final); - if (err != SSL_ERROR_NONE) - { - if (err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_WRITE - && (err != SSL_ERROR_SYSCALL || errno != 0)) - { - /* - * Some other error ... not just a timeout or disconnect - */ - NSWarnLog(@"unable to accept SSL connection from %@:%@ - %@", - address, service, sslError(err)); - } - DESTROY(self); - return NO; - } - } - connected = YES; - DESTROY(self); - return YES; + return result; } - (BOOL) sslConnect { - int ret; - int err; - NSRunLoop *loop; + BOOL result = NO; - if (connected == YES) - { - return YES; /* Already connected. */ - } - if (isStandardFile == YES) + if (YES == isStandardFile) { NSLog(@"Attempt to make ssl connection to a standard file"); return NO; } + if (NO == [self sslHandshakeEstablished: &result outgoing: YES]) + { + NSRunLoop *loop; - /* - * Ensure we have a context and handle to connect with. - */ - if (ctx == 0) - { - ctx = SSL_CTX_new(SSLv23_client_method()); - if (permitSSLv2 == NO) - { - SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2); - } - } - if (ssl == 0) - { - ssl = SSL_new(ctx); - } - IF_NO_GC([self retain];) // Don't get destroyed during runloop - /* - * Set non-blocking so accept won't hang if remote end goes wrong. - */ - [self setNonBlocking: YES]; - loop = [NSRunLoop currentRunLoop]; - ret = SSL_set_fd(ssl, descriptor); - if (ret == 1) - { + IF_NO_GC([self retain];) // Don't get destroyed during runloop + loop = [NSRunLoop currentRunLoop]; [loop runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]]; - if (ssl == 0) + if (NO == [self sslHandshakeEstablished: &result outgoing: YES]) { - DESTROY(self); - return NO; + NSDate *final; + NSDate *when; + NSTimeInterval last = 0.0; + NSTimeInterval limit = 0.1; + + final = [[NSDate alloc] initWithTimeIntervalSinceNow: 30.0]; + when = [NSDate alloc]; + + while (NO == [self sslHandshakeEstablished: &result outgoing: YES] + && [final timeIntervalSinceNow] > 0.0) + { + NSTimeInterval tmp = limit; + + limit += last; + last = tmp; + if (limit > 0.5) + { + limit = 0.1; + last = 0.1; + } + when = [when initWithTimeIntervalSinceNow: limit]; + [loop runUntilDate: when]; + } + RELEASE(when); + RELEASE(final); } - ret = SSL_connect(ssl); + DESTROY(self); } - if (ret != 1) - { - NSDate *final; - NSDate *when; - NSTimeInterval last = 0.0; - NSTimeInterval limit = 0.1; - - final = [[NSDate alloc] initWithTimeIntervalSinceNow: 30.0]; - when = [NSDate alloc]; - - err = SSL_get_error(ssl, ret); - while ((err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) - && [final timeIntervalSinceNow] > 0.0) - { - NSTimeInterval tmp = limit; - - limit += last; - last = tmp; - when = [when initWithTimeIntervalSinceNow: limit]; - [loop runUntilDate: when]; - if (ssl == 0) - { - RELEASE(when); - RELEASE(final); - DESTROY(self); - return NO; - } - ret = SSL_connect(ssl); - if (ret != 1) - { - err = SSL_get_error(ssl, ret); - } - else - { - err = SSL_ERROR_NONE; - } - } - RELEASE(when); - RELEASE(final); - if (err != SSL_ERROR_NONE) - { - if (err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_WRITE) - { - /* - * Some other error ... not just a timeout or disconnect - */ - NSLog(@"unable to make SSL connection to %@:%@ - %@", - address, service, sslError(err)); - } - DESTROY(self); - return NO; - } - } - connected = YES; - DESTROY(self); - return YES; + return result; } - (void) sslDisconnect @@ -467,6 +353,75 @@ static BOOL permitSSLv2 = NO; connected = NO; } +- (BOOL) sslHandshakeEstablished: (BOOL*)result outgoing: (BOOL)isOutgoing +{ + int ret; + int err; + + NSAssert(0 != result, NSInvalidArgumentException); + + if (YES == connected) + { + return YES; /* Already connected. */ + } + if (YES == isStandardFile) + { + NSLog(@"Attempt to perform ssl handshake with a standard file"); + return NO; + } + + /* + * Ensure we have a context and handle to connect with. + */ + if (ctx == 0) + { + ctx = SSL_CTX_new(SSLv23_client_method()); + if (permitSSLv2 == NO) + { + SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2); + } + } + if (ssl == 0) + { + ssl = SSL_new(ctx); + } + + /* + * Set non-blocking so accept won't hang if remote end goes wrong. + */ + [self setNonBlocking: YES]; + ret = SSL_set_fd(ssl, descriptor); + if (1 == ret) + { + if (YES == isOutgoing) + { + ret = SSL_connect(ssl); + } + else + { + ret = SSL_accept(ssl); + } + } + if (1 == ret) + { + connected = YES; + *result = YES; + } + else + { + err = SSL_get_error(ssl, ret); + if (SSL_ERROR_WANT_READ == err || SSL_ERROR_WANT_WRITE == err) + { + return NO; + } + + NSLog(@"unable to make SSL connection to %@:%@ - %@", + address, service, sslError(err)); + *result = NO; + } + return YES; +} + - (void) sslSetCertificate: (NSString*)certFile privateKey: (NSString*)privateKey PEMpasswd: (NSString*)PEMpasswd @@ -496,8 +451,7 @@ static BOOL permitSSLv2 = NO; } if ([certFile length] > 0) { - ret = SSL_CTX_use_certificate_file(ctx, [certFile UTF8String], - X509_FILETYPE_PEM); + ret = SSL_CTX_use_certificate_chain_file(ctx, [certFile UTF8String]); if (ret != 1) { NSLog(@"Failed to set certificate file to %@ - %@", diff --git a/Source/NSFileHandle.m b/Source/NSFileHandle.m index c0b1dfba2..379219e4a 100644 --- a/Source/NSFileHandle.m +++ b/Source/NSFileHandle.m @@ -728,7 +728,7 @@ NSString * const NSFileHandleOperationException /** * Establishes an SSL connection from the system that the handle * is talking to.
- * This is implented by an SSL handling subclass.
+ * This is implemented by an SSL handling subclass.
* The default implementation just returns NO. */ - (BOOL) sslAccept @@ -739,7 +739,7 @@ NSString * const NSFileHandleOperationException /** * Establishes an SSL connection to the system that the handle * is talking to.
- * This is implented by an SSL handling subclass.
+ * This is implemented by an SSL handling subclass.
* The default implementation just returns NO. */ - (BOOL) sslConnect @@ -755,7 +755,14 @@ NSString * const NSFileHandleOperationException } /** - * Sets the certificate to be used to identify this process to the server + */ +- (BOOL) sslHandshakeEstablished: (BOOL*)result outgoing: (BOOL)isOutgoing; +{ + return NO; +} + +/** + * Sets the certificate chain to be used to identify this process to the server * at the opposite end of the network connection. */ - (void) sslSetCertificate: (NSString*)certFile @@ -763,5 +770,6 @@ NSString * const NSFileHandleOperationException PEMpasswd: (NSString*)PEMpasswd { } + @end diff --git a/Source/NSNumber.m b/Source/NSNumber.m index 1cb73cb07..7f13287d3 100644 --- a/Source/NSNumber.m +++ b/Source/NSNumber.m @@ -757,7 +757,7 @@ if (aValue >= -1 && aValue <= 12)\ return [self stringValue]; } -/* Return nil for an NSNumber that is allocated and initalized without +/* Return nil for an NSNumber that is allocated and initialized without * providing a real value. Yes, this seems weird, but it is actually what * happens on OS X. */ diff --git a/Source/NSThread.m b/Source/NSThread.m index f0c92f5f4..e642fdb1b 100644 --- a/Source/NSThread.m +++ b/Source/NSThread.m @@ -331,7 +331,7 @@ GSCurrentThread(void) { assert(GSRegisterCurrentThread() && @"Failed to register thread"); thr = pthread_getspecific(thread_object_key); - if ((defaultThread == nil) && IS_MAIN_PTHREAD) + if ((nil == defaultThread) && IS_MAIN_PTHREAD) { defaultThread = [thr retain]; }