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:
rfm 2011-07-12 11:40:15 +00:00
parent 853f52049b
commit 6264555674
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> 2011-07-11 14:31 David Chisnall <theraven@gna.org>
* libs/base/trunk/Source/NSAutoreleasePool.m, * Source/NSAutoreleasePool.m,
libs/base/trunk/Source/NSThread.m: Lazily initialize POSIX Source/NSThread.m: Lazily initialize POSIX
threads, matching OS X behaviour and stopping us from crashing threads, matching OS X behaviour and stopping us from crashing
when calling autorelease from a thread that was not previously when calling autorelease from a thread that was not previously
registered explicitly (yuck!) registered explicitly (yuck!)
@ -13,7 +22,7 @@
2011-07-11 12:36 David Chisnall <theraven@gna.org> 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 destroy itself when called as [super init]. This behaviour was
breaking anything that subclassed NSNumber in user code (e.g. breaking anything that subclassed NSNumber in user code (e.g.
PyObjC). PyObjC).
@ -53,7 +62,7 @@
2011-07-04 11:31 David Chisnall <theraven@gna.org> 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 Switch the order of the reference count and the zone so that the
reference count (in reference counted mode) is always immediately in reference count (in reference counted mode) is always immediately in
front of the object. Please test this!! front of the object. Please test this!!
@ -66,11 +75,11 @@
2011-06-30 14:44 David Chisnall <theraven@gna.org> 2011-06-30 14:44 David Chisnall <theraven@gna.org>
* libs/base/trunk/Headers/Foundation/NSArray.h, * Headers/Foundation/NSArray.h,
libs/base/trunk/Headers/Foundation/NSProxy.h, Headers/Foundation/NSProxy.h,
libs/base/trunk/Headers/GNUstepBase/GSVersionMacros.h, Headers/GNUstepBase/GSVersionMacros.h,
libs/base/trunk/Headers/GNUstepBase/preface.h.in, Headers/GNUstepBase/preface.h.in,
libs/base/trunk/Source/NSProxy.m: Rewrote NSProxy's -retain / Source/NSProxy.m: Rewrote NSProxy's -retain /
-release to be the same as NSObject, not its own ad-hoc thing. -release to be the same as NSObject, not its own ad-hoc thing.
Added declaration of __bridge for use in non-ARC mode. Added declaration of __bridge for use in non-ARC mode.
@ -81,25 +90,25 @@
2011-06-29 15:21 David Chisnall <theraven@gna.org> 2011-06-29 15:21 David Chisnall <theraven@gna.org>
* libs/base/trunk/Headers/Foundation/NSNotification.h, * Headers/Foundation/NSNotification.h,
libs/base/trunk/Headers/Foundation/NSZone.h, Headers/Foundation/NSZone.h,
libs/base/trunk/Headers/GNUstepBase/preface.h.in, Headers/GNUstepBase/preface.h.in,
libs/base/trunk/Tools/make_strings/make_strings.m: More ARC Tools/make_strings/make_strings.m: More ARC
fixes. We don't want to be using __strong void* in ARC mode (it 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). only makes sense in GC mode and is invalid in ARC mode).
2011-06-29 13:13 David Chisnall <theraven@gna.org> 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. automatically zeroing __weak references when using ARC.
2011-06-29 11:50 David Chisnall <theraven@gna.org> 2011-06-29 11:50 David Chisnall <theraven@gna.org>
* libs/base/trunk/Headers/Foundation/NSAutoreleasePool.h, * Headers/Foundation/NSAutoreleasePool.h,
libs/base/trunk/Headers/Foundation/NSEnumerator.h, Headers/Foundation/NSEnumerator.h,
libs/base/trunk/Headers/Foundation/NSException.h, Headers/Foundation/NSException.h,
libs/base/trunk/Headers/Foundation/NSZone.h, Headers/Foundation/NSZone.h,
libs/base/trunk/Headers/GNUstepBase/preface.h.in: Headers/GNUstepBase/preface.h.in:
ARC-compatibility tweaks in the headers. ARC will not track ARC-compatibility tweaks in the headers. ARC will not track
objects inside structures and rejects code that uses object types objects inside structures and rejects code that uses object types
that are not __unsafe_unretained qualified inside structures. that are not __unsafe_unretained qualified inside structures.

View file

@ -236,6 +236,22 @@ GS_EXPORT NSString * const NSFileHandleOperationException;
- (BOOL) sslAccept; - (BOOL) sslAccept;
- (BOOL) sslConnect; - (BOOL) sslConnect;
- (void) sslDisconnect; - (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 - (void) sslSetCertificate: (NSString*)certFile
privateKey: (NSString*)privateKey privateKey: (NSString*)privateKey
PEMpasswd: (NSString*)PEMpasswd; PEMpasswd: (NSString*)PEMpasswd;

View file

@ -156,6 +156,7 @@ threadid_function()
- (BOOL) sslAccept; - (BOOL) sslAccept;
- (BOOL) sslConnect; - (BOOL) sslConnect;
- (void) sslDisconnect; - (void) sslDisconnect;
- (BOOL) sslHandshakeEstablished: (BOOL*)result outgoing: (BOOL)isOutgoing;
- (void) sslSetCertificate: (NSString*)certFile - (void) sslSetCertificate: (NSString*)certFile
privateKey: (NSString*)privateKey privateKey: (NSString*)privateKey
PEMpasswd: (NSString*)PEMpasswd; PEMpasswd: (NSString*)PEMpasswd;
@ -236,53 +237,21 @@ static BOOL permitSSLv2 = NO;
- (BOOL) sslAccept - (BOOL) sslAccept
{ {
int ret; BOOL result = NO;
int err;
NSRunLoop *loop;
if (connected == YES) if (YES == isStandardFile)
{
return YES; /* Already connected. */
}
if (isStandardFile == YES)
{ {
NSLog(@"Attempt to make ssl connection to a standard file"); NSLog(@"Attempt to make ssl connection to a standard file");
return NO; 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 IF_NO_GC([self retain];) // Don't get destroyed during runloop
loop = [NSRunLoop currentRunLoop]; loop = [NSRunLoop currentRunLoop];
ret = SSL_set_fd(ssl, descriptor);
if (ret == 1)
{
[loop runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]]; [loop runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]];
if (ssl == 0) if (NO == [self sslHandshakeEstablished: &result outgoing: NO])
{
DESTROY(self);
return NO;
}
ret = SSL_accept(ssl);
}
if (ret != 1)
{ {
NSDate *final; NSDate *final;
NSDate *when; NSDate *when;
@ -292,104 +261,46 @@ static BOOL permitSSLv2 = NO;
final = [[NSDate alloc] initWithTimeIntervalSinceNow: 30.0]; final = [[NSDate alloc] initWithTimeIntervalSinceNow: 30.0];
when = [NSDate alloc]; when = [NSDate alloc];
err = SSL_get_error(ssl, ret); while (NO == [self sslHandshakeEstablished: &result outgoing: NO]
while ((err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE)
&& [final timeIntervalSinceNow] > 0.0) && [final timeIntervalSinceNow] > 0.0)
{ {
NSTimeInterval tmp = limit; NSTimeInterval tmp = limit;
limit += last; limit += last;
last = tmp; last = tmp;
if (limit > 0.5)
{
limit = 0.1;
last = 0.1;
}
when = [when initWithTimeIntervalSinceNow: limit]; when = [when initWithTimeIntervalSinceNow: limit];
[loop runUntilDate: when]; [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(when);
RELEASE(final); 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); DESTROY(self);
return NO;
} }
} return result;
connected = YES;
DESTROY(self);
return YES;
} }
- (BOOL) sslConnect - (BOOL) sslConnect
{ {
int ret; BOOL result = NO;
int err;
NSRunLoop *loop;
if (connected == YES) if (YES == isStandardFile)
{
return YES; /* Already connected. */
}
if (isStandardFile == YES)
{ {
NSLog(@"Attempt to make ssl connection to a standard file"); NSLog(@"Attempt to make ssl connection to a standard file");
return NO; 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 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]; loop = [NSRunLoop currentRunLoop];
ret = SSL_set_fd(ssl, descriptor);
if (ret == 1)
{
[loop runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]]; [loop runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]];
if (ssl == 0) if (NO == [self sslHandshakeEstablished: &result outgoing: YES])
{
DESTROY(self);
return NO;
}
ret = SSL_connect(ssl);
}
if (ret != 1)
{ {
NSDate *final; NSDate *final;
NSDate *when; NSDate *when;
@ -399,52 +310,27 @@ static BOOL permitSSLv2 = NO;
final = [[NSDate alloc] initWithTimeIntervalSinceNow: 30.0]; final = [[NSDate alloc] initWithTimeIntervalSinceNow: 30.0];
when = [NSDate alloc]; when = [NSDate alloc];
err = SSL_get_error(ssl, ret); while (NO == [self sslHandshakeEstablished: &result outgoing: YES]
while ((err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE)
&& [final timeIntervalSinceNow] > 0.0) && [final timeIntervalSinceNow] > 0.0)
{ {
NSTimeInterval tmp = limit; NSTimeInterval tmp = limit;
limit += last; limit += last;
last = tmp; last = tmp;
if (limit > 0.5)
{
limit = 0.1;
last = 0.1;
}
when = [when initWithTimeIntervalSinceNow: limit]; when = [when initWithTimeIntervalSinceNow: limit];
[loop runUntilDate: when]; [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(when);
RELEASE(final); 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); DESTROY(self);
return NO;
} }
} return result;
connected = YES;
DESTROY(self);
return YES;
} }
- (void) sslDisconnect - (void) sslDisconnect
@ -467,6 +353,75 @@ static BOOL permitSSLv2 = NO;
connected = 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 - (void) sslSetCertificate: (NSString*)certFile
privateKey: (NSString*)privateKey privateKey: (NSString*)privateKey
PEMpasswd: (NSString*)PEMpasswd PEMpasswd: (NSString*)PEMpasswd
@ -496,8 +451,7 @@ static BOOL permitSSLv2 = NO;
} }
if ([certFile length] > 0) if ([certFile length] > 0)
{ {
ret = SSL_CTX_use_certificate_file(ctx, [certFile UTF8String], ret = SSL_CTX_use_certificate_chain_file(ctx, [certFile UTF8String]);
X509_FILETYPE_PEM);
if (ret != 1) if (ret != 1)
{ {
NSLog(@"Failed to set certificate file to %@ - %@", NSLog(@"Failed to set certificate file to %@ - %@",

View file

@ -728,7 +728,7 @@ NSString * const NSFileHandleOperationException
/** <override-dummy /> /** <override-dummy />
* Establishes an SSL connection from the system that the handle * Establishes an SSL connection from the system that the handle
* is talking to.<br /> * 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. * The default implementation just returns NO.
*/ */
- (BOOL) sslAccept - (BOOL) sslAccept
@ -739,7 +739,7 @@ NSString * const NSFileHandleOperationException
/** <override-dummy /> /** <override-dummy />
* Establishes an SSL connection to the system that the handle * Establishes an SSL connection to the system that the handle
* is talking to.<br /> * 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. * The default implementation just returns NO.
*/ */
- (BOOL) sslConnect - (BOOL) sslConnect
@ -755,7 +755,14 @@ NSString * const NSFileHandleOperationException
} }
/** <override-dummy /> /** <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. * at the opposite end of the network connection.
*/ */
- (void) sslSetCertificate: (NSString*)certFile - (void) sslSetCertificate: (NSString*)certFile
@ -763,5 +770,6 @@ NSString * const NSFileHandleOperationException
PEMpasswd: (NSString*)PEMpasswd PEMpasswd: (NSString*)PEMpasswd
{ {
} }
@end @end

View file

@ -757,7 +757,7 @@ if (aValue >= -1 && aValue <= 12)\
return [self stringValue]; 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 * providing a real value. Yes, this seems weird, but it is actually what
* happens on OS X. * happens on OS X.
*/ */

View file

@ -331,7 +331,7 @@ GSCurrentThread(void)
{ {
assert(GSRegisterCurrentThread() && @"Failed to register thread"); assert(GSRegisterCurrentThread() && @"Failed to register thread");
thr = pthread_getspecific(thread_object_key); thr = pthread_getspecific(thread_object_key);
if ((defaultThread == nil) && IS_MAIN_PTHREAD) if ((nil == defaultThread) && IS_MAIN_PTHREAD)
{ {
defaultThread = [thr retain]; defaultThread = [thr retain];
} }