ssh handshake improvements and consmetic tweaks

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@33535 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-MacDonald 2011-07-12 11:40:15 +00:00
parent a64f21744d
commit 497cb2af93
6 changed files with 198 additions and 211 deletions

View file

@ -1,7 +1,16 @@
2011-07-12 Richard Frith-Macdonald <rfm@gnu.org>
* 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 <theraven@gna.org>
* 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 <theraven@gna.org>
* 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 <theraven@gna.org>
* 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 <theraven@gna.org>
* 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 <theraven@gna.org>
* 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 <theraven@gna.org>
* 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 <theraven@gna.org>
* 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.

View file

@ -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.<br />
* 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).<br />
* The value of privatekey is the path of a file containing a PEM encoded key
* used to establish handshakes using the host certificate.<br />
* 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;

View file

@ -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 %@ - %@",

View file

@ -728,7 +728,7 @@ NSString * const NSFileHandleOperationException
/** <override-dummy />
* Establishes an SSL connection from the system that the handle
* is talking to.<br />
* This is implented by an SSL handling subclass.<br />
* This is implemented by an SSL handling subclass.<br />
* The default implementation just returns NO.
*/
- (BOOL) sslAccept
@ -739,7 +739,7 @@ NSString * const NSFileHandleOperationException
/** <override-dummy />
* Establishes an SSL connection to the system that the handle
* is talking to.<br />
* This is implented by an SSL handling subclass.<br />
* This is implemented by an SSL handling subclass.<br />
* The default implementation just returns NO.
*/
- (BOOL) sslConnect
@ -755,7 +755,14 @@ NSString * const NSFileHandleOperationException
}
/** <override-dummy />
* Sets the certificate to be used to identify this process to the server
*/
- (BOOL) sslHandshakeEstablished: (BOOL*)result outgoing: (BOOL)isOutgoing;
{
return NO;
}
/** <override-dummy />
* 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

View file

@ -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.
*/

View file

@ -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];
}