mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-23 09:04:13 +00:00
backport ssh handshake fixes
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/branches/stable@33536 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
58fcd277a0
commit
246d565f13
4 changed files with 177 additions and 190 deletions
|
@ -1,3 +1,12 @@
|
|||
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 chain with intermediate
|
||||
certificate authorities. Simplify handshake using common routine for
|
||||
non-blocking handshake attempt.
|
||||
|
||||
2011-07-11 12:36 David Chisnall <theraven@gna.org>
|
||||
|
||||
* Source/NSNumber.m: [NSNumber -init] should not
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 %@ - %@",
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in a new issue