Extend use of gnutls to older APIs so we don't need both gnutls and openssl

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@35595 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-MacDonald 2012-09-23 12:26:28 +00:00
parent 2927b474b5
commit 2539f6207c
5 changed files with 398 additions and 311 deletions

View file

@ -1,3 +1,14 @@
2012-09-24 Richard Frith-Macdonald <rfm@gnu.org>
* Headers/Foundation/NSFileHandle.h: deprecate old method for setting
certificate and add new one.
* SSL/GSSSLHandle.m: Support new method and move generic code to
NSFileHandle.m
* Source/GSSocketStream.m: Implement NSFileHandle SSL/TLS support
using GNUTLS.
* Source/NSFileHandle.m: Some ssl/tls restructuring, use GNUTLS if
available.
2012-09-23 Niels Grewe <niels.grewe@halbordnung.de>
* Source/GSSocketStream.m: Expose GSFileHandle ivars for compilation

View file

@ -231,32 +231,87 @@ GS_EXPORT NSString * const NSFileHandleOperationException;
* to allow another incoming connection <em>before</em> you perform an
* -sslAccept on a connection you have just accepted.
*/
@interface NSFileHandle (GNUstepOpenSSL)
@interface NSFileHandle (GNUstepTLS)
/** Returns the class to handle ssl enabled connections.
*/
+ (Class) sslClass;
/** Repeatedly attempt an incoming handshake for up to 30 seconds or until
* the handshake completes.
*/
- (BOOL) sslAccept;
/** Repeatedly attempt an outgoing handshake for up to 30 seconds or until
* the handshake completes.
*/
- (BOOL) sslConnect;
/** <override-dummy />
* Shuts down the SSL connection to the system that the handle is talking to.
*/
- (void) sslDisconnect;
/** Make a non-blocking handshake attempt. Calls to this method should be
/** <override-dummy />
* 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.
* establishing a connection or not.<br />
* The default implementation simply returns YES and sets result to NO.<br />
* This is implemented by an SSL handling subclass to perform real work.
*/
- (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.
/** Deprecated ... use -sslSetOptions: instead
*/
- (void) sslSetCertificate: (NSString*)certFile
privateKey: (NSString*)privateKey
PEMpasswd: (NSString*)PEMpasswd;
/** <override-dummy />
* Sets options to be used to configure this channel before the handshake.<br />
* Returns nil on success, or an error message if some options could not
* be set.<br />>
* Expects key value pairs with the follwiing names/meanings:
* <deflist>
* <term>GSTLSCertificateFileKey</term>
* <desc>The path to a PEM encoded certificate used to identify this end
* of the connection. This option <em>must</em> be set for handing an
* incoming connection, but is optional for outgoing connections.<br />
* This must be used in conjunction with GSTLSPrivateKeyFileKey.
* </desc>
* <term>GSTLSPrivateKeyFileKey</term>
* <desc>The path to a PEM encoded key used to unlock the certificate
* file for the connection. The key in the file may or may not be
* encrypted, but if it is encrypted you must specify
* GSTLSPrivateKeyPasswordKey.
* </desc>
* <term>GSTLSPrivateKeyPasswordKey</term>
* <desc>A string to be used as the password to decrypt a key which was
* specified using GSTLSKeyPassword.
* </desc>
* </deflist>
*/
- (NSString*) sslSetOptions: (NSDictionary*)options;
@end
/** Dictionary key for the path to a PEM encoded certificate used
* to identify this end of a connection.
*/
GS_EXPORT NSString * const GSTLSCertificateFileKey;
/** Dictionary key for the path to a PEM encoded private key used
* to unlock the certificate used by this end of a connection.
*/
GS_EXPORT NSString * const GSTLSPrivateKeyFileKey;
/** Dictionary key for the password used to decrypt the key file used
* to unlock the certificate used by this end of a connection.
*/
GS_EXPORT NSString * const GSTLSPrivateKeyPasswordKey;
// GNUstep Notification names.
/**

View file

@ -177,13 +177,9 @@ threadid_function()
BOOL connected;
}
- (BOOL) sslAccept;
- (BOOL) sslConnect;
- (void) sslDisconnect;
- (BOOL) sslHandshakeEstablished: (BOOL*)result outgoing: (BOOL)isOutgoing;
- (void) sslSetCertificate: (NSString*)certFile
privateKey: (NSString*)privateKey
PEMpasswd: (NSString*)PEMpasswd;
- (NSString*) sslSetOptions: (NSDictionary*)options;
@end
static BOOL permitSSLv2 = NO;
@ -263,104 +259,6 @@ static NSString *cipherList = nil;
return [super read: buf length: len];
}
- (BOOL) sslAccept
{
BOOL result = NO;
if (YES == isStandardFile)
{
NSLog(@"Attempt to make ssl connection to a standard file");
return NO;
}
if (NO == [self sslHandshakeEstablished: &result outgoing: NO])
{
NSRunLoop *loop;
IF_NO_GC([self retain];) // Don't get destroyed during runloop
loop = [NSRunLoop currentRunLoop];
[loop runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]];
if (NO == [self sslHandshakeEstablished: &result outgoing: 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);
}
DESTROY(self);
}
return result;
}
- (BOOL) sslConnect
{
BOOL result = NO;
if (YES == isStandardFile)
{
NSLog(@"Attempt to make ssl connection to a standard file");
return NO;
}
if (NO == [self sslHandshakeEstablished: &result outgoing: YES])
{
NSRunLoop *loop;
IF_NO_GC([self retain];) // Don't get destroyed during runloop
loop = [NSRunLoop currentRunLoop];
[loop runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]];
if (NO == [self sslHandshakeEstablished: &result outgoing: YES])
{
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);
}
DESTROY(self);
}
return result;
}
- (void) sslDisconnect
{
if (ssl != 0)
@ -460,17 +358,22 @@ static NSString *cipherList = nil;
return YES;
}
- (void) sslSetCertificate: (NSString*)certFile
privateKey: (NSString*)privateKey
PEMpasswd: (NSString*)PEMpasswd
- (NSString*) sslSetOptions: (NSDictionary*)options
{
int ret;
NSString *certFile;
NSString *privateKey;
NSString *PEMpasswd;
int ret;
certFile = [options objectForKey: GSTLSCertificateFileKey];
privateKey = [options objectForKey: GSTLSPrivateKeyFileKey];
PEMpasswd = [options objectForKey: GSTLSPrivateKeyPasswordKey];
if (isStandardFile == YES)
{
NSLog(@"Attempt to set ssl certificate for a standard file");
return;
return @"Attempt to set ssl certificate for a standard file";
}
/*
* Ensure we have a context to set the certificate for.
*/
@ -498,6 +401,7 @@ static NSString *cipherList = nil;
{
NSLog(@"Failed to set certificate file to %@ - %@",
certFile, sslError(ERR_get_error()));
return @"Failed to set certificate file";
}
}
if ([privateKey length] > 0)
@ -508,8 +412,10 @@ static NSString *cipherList = nil;
{
NSLog(@"Failed to set private key file to %@ - %@",
privateKey, sslError(ERR_get_error()));
return @"Failed to set key file";
}
}
return nil;
}
- (NSInteger) write: (const void*)buf length: (NSUInteger)len

View file

@ -395,8 +395,160 @@ static struct gcry_thread_cbs gcry_threads_other = {
gcry_mutex_unlock
};
static void
GSTLSLog(int level, const char *msg)
{
NSLog(@"%s", msg);
}
@interface GNUTLSDHParams : NSObject
static NSString *cipherList = nil;
static gnutls_anon_client_credentials_t anoncred;
/* This function will verify the peer's certificate, and check
* if the hostname matches, as well as the activation, expiration dates.
*/
static int
_verify_certificate_callback (gnutls_session_t session)
{
unsigned int status;
const gnutls_datum_t *cert_list;
unsigned int cert_list_size;
int ret;
gnutls_x509_crt_t cert;
const char *hostname;
/* read hostname */
hostname = gnutls_session_get_ptr (session);
/* This verification function uses the trusted CAs in the credentials
* structure. So you must have installed one or more CA certificates.
*/
ret = gnutls_certificate_verify_peers2 (session, &status);
if (ret < 0)
{
printf ("Error\n");
return GNUTLS_E_CERTIFICATE_ERROR;
}
if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
printf ("The certificate hasn't got a known issuer.\n");
if (status & GNUTLS_CERT_REVOKED)
printf ("The certificate has been revoked.\n");
/*
if (status & GNUTLS_CERT_EXPIRED)
printf ("The certificate has expired\n");
if (status & GNUTLS_CERT_NOT_ACTIVATED)
printf ("The certificate is not yet activated\n");
*/
if (status & GNUTLS_CERT_INVALID)
{
printf ("The certificate is not trusted.\n");
return GNUTLS_E_CERTIFICATE_ERROR;
}
/* Up to here the process is the same for X.509 certificates and
* OpenPGP keys. From now on X.509 certificates are assumed. This can
* be easily extended to work with openpgp keys as well.
*/
if (gnutls_certificate_type_get (session) != GNUTLS_CRT_X509)
return GNUTLS_E_CERTIFICATE_ERROR;
if (gnutls_x509_crt_init (&cert) < 0)
{
printf ("error in initialization\n");
return GNUTLS_E_CERTIFICATE_ERROR;
}
cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
if (cert_list == NULL)
{
printf ("No certificate was found!\n");
return GNUTLS_E_CERTIFICATE_ERROR;
}
if (gnutls_x509_crt_import (cert, &cert_list[0], GNUTLS_X509_FMT_DER) < 0)
{
printf ("error parsing certificate\n");
return GNUTLS_E_CERTIFICATE_ERROR;
}
if (!gnutls_x509_crt_check_hostname (cert, hostname))
{
printf ("The certificate's owner does not match hostname '%s'\n",
hostname);
return GNUTLS_E_CERTIFICATE_ERROR;
}
gnutls_x509_crt_deinit (cert);
/* notify gnutls to continue handshake normally */
return 0;
}
NSString * const GSTLSCertificateFileKey = @"GSTLSCertificateFileKey";
NSString * const GSTLSPrivateKeyFileKey = @"GSTLSPrivateKeyFile";
NSString * const GSTLSPrivateKeyPasswordKey = @"GSTLSPrivateKeyPassword";
/* This class is used to ensure that the GNUTLS system is initialised
* and thread-safe.
*/
@interface GNUTLSObject : NSObject
@end
@implementation GNUTLSObject
+ (void) _defaultsChanged: (NSNotification*)n
{
cipherList
= [[NSUserDefaults standardUserDefaults] stringForKey: @"GSCipherList"];
}
+ (void) initialize
{
if ([GNUTLSObject class] == self)
{
static BOOL beenHere = NO;
if (beenHere == NO)
{
NSUserDefaults *defs;
beenHere = YES;
defs = [NSUserDefaults standardUserDefaults];
cipherList = [defs stringForKey: @"GSCipherList"];
[[NSNotificationCenter defaultCenter]
addObserver: self
selector: @selector(_defaultsChanged:)
name: NSUserDefaultsDidChangeNotification
object: nil];
/* Make gcrypt thread-safe
*/
gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_other);
/* Initialise gnutls
*/
gnutls_global_init ();
/* Allocate global credential information for anonymous tls
*/
gnutls_anon_allocate_client_credentials (&anoncred);
/* Enable gnutls logging via NSLog
*/
gnutls_global_set_log_function (GSTLSLog);
}
}
}
@end
@interface GNUTLSDHParams : GNUTLSObject
{
gnutls_dh_params_t params;
}
@ -478,7 +630,7 @@ static GNUTLSDHParams *current = nil;
/* Manage certificate lists (for servers and clients) and also provide
* DH params.
*/
@interface GNUTLSCertificateList : NSObject
@interface GNUTLSCertificateList : GNUTLSObject
{
NSDate *when;
NSString *path;
@ -618,7 +770,7 @@ static NSMutableDictionary *certificateListCache = nil;
@end
@interface GNUTLSPrivateKey : NSObject
@interface GNUTLSPrivateKey : GNUTLSObject
{
NSDate *when;
NSString *path;
@ -879,58 +1031,11 @@ GSTLSPush(gnutls_transport_ptr_t handle, const void *buffer, size_t len)
return result;
}
static void
GSTLSLog(int level, const char *msg)
{
NSLog(@"%s", msg);
}
static NSString *cipherList = nil;
static gnutls_anon_client_credentials_t anoncred;
@implementation GSTLS
+ (void) _defaultsChanged: (NSNotification*)n
{
cipherList
= [[NSUserDefaults standardUserDefaults] stringForKey: @"GSCipherList"];
}
+ (void) initialize
{
static BOOL beenHere = NO;
if (beenHere == NO)
{
NSUserDefaults *defs;
beenHere = YES;
defs = [NSUserDefaults standardUserDefaults];
cipherList = [defs stringForKey: @"GSCipherList"];
[[NSNotificationCenter defaultCenter]
addObserver: self
selector: @selector(_defaultsChanged:)
name: NSUserDefaultsDidChangeNotification
object: nil];
/* Make gcrypt thread-safe
*/
gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_other);
/* Initialise gnutls
*/
gnutls_global_init ();
/* Allocate global credential information for anonymous tls
*/
gnutls_anon_allocate_client_credentials (&anoncred);
/* Enable gnutls logging via NSLog
*/
gnutls_global_set_log_function (GSTLSLog);
}
[GNUTLSObject class];
}
+ (void) tryInput: (GSSocketInputStream*)i output: (GSSocketOutputStream*)o
@ -1113,7 +1218,8 @@ static gnutls_anon_client_credentials_t anoncred;
0 };
gnutls_protocol_set_priority (session, proto_prio);
#else
gnutls_priority_set_direct(session, "NORMAL:-VERS-SSL3.0:+VERS-TLS-ALL", NULL);
gnutls_priority_set_direct(session,
"NORMAL:-VERS-SSL3.0:+VERS-TLS-ALL", NULL);
#endif
}
if ([proto isEqualToString: NSStreamSocketSecurityLevelSSLv3] == YES)
@ -1124,7 +1230,8 @@ static gnutls_anon_client_credentials_t anoncred;
0 };
gnutls_protocol_set_priority (session, proto_prio);
#else
gnutls_priority_set_direct(session, "NORMAL:-VERS-TLS-ALL:+VERS-SSL3.0", NULL);
gnutls_priority_set_direct(session,
"NORMAL:-VERS-TLS-ALL:+VERS-SSL3.0", NULL);
#endif
}
@ -1240,13 +1347,9 @@ static gnutls_anon_client_credentials_t anoncred;
BOOL outgoing; // handshake direction
BOOL setup; // have set certificate
}
- (BOOL) sslAccept;
- (BOOL) sslConnect;
- (void) sslDisconnect;
- (BOOL) sslHandshakeEstablished: (BOOL*)result outgoing: (BOOL)isOutgoing;
- (void) sslSetCertificate: (NSString*)certFile
privateKey: (NSString*)privateKey
PEMpasswd: (NSString*)PEMpasswd;
- (NSString*) sslSetOptions: (NSDictionary*)options;
@end
@ -1326,94 +1429,6 @@ GSTLSHandlePush(gnutls_transport_ptr_t handle, const void *buffer, size_t len)
return [super read: buf length: len];
}
- (BOOL) sslAccept
{
BOOL result = NO;
if (NO == [self sslHandshakeEstablished: &result outgoing: NO])
{
NSRunLoop *loop;
IF_NO_GC([self retain];) // Don't get destroyed during runloop
loop = [NSRunLoop currentRunLoop];
[loop runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]];
if (NO == [self sslHandshakeEstablished: &result outgoing: 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);
}
DESTROY(self);
}
return result;
}
- (BOOL) sslConnect
{
BOOL result = NO;
if (NO == [self sslHandshakeEstablished: &result outgoing: YES])
{
NSRunLoop *loop;
IF_NO_GC([self retain];) // Don't get destroyed during runloop
loop = [NSRunLoop currentRunLoop];
[loop runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]];
if (NO == [self sslHandshakeEstablished: &result outgoing: YES])
{
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);
}
DESTROY(self);
}
return result;
}
- (void) sslDisconnect
{
if (YES == active || YES == handshake)
@ -1552,29 +1567,33 @@ GSTLSHandlePush(gnutls_transport_ptr_t handle, const void *buffer, size_t len)
return YES;
}
- (void) sslSetCertificate: (NSString*)certFile
privateKey: (NSString*)privateKey
PEMpasswd: (NSString*)PEMpasswd
- (NSString*) sslSetOptions: (NSDictionary*)options
{
if (isStandardFile == YES)
{
NSLog(@"Attempt to set ssl certificate for a standard file");
return;
return @"Attempt to set ssl options for a standard file";
}
if (NO == setup)
{
NSString *certFile;
NSString *privateKey;
NSString *PEMpasswd;
GNUTLSPrivateKey *key = nil;
GNUTLSCertificateList *list = nil;
int ret;
certFile = [options objectForKey: GSTLSCertificateFileKey];
privateKey = [options objectForKey: GSTLSPrivateKeyFileKey];
PEMpasswd = [options objectForKey: GSTLSPrivateKeyPasswordKey];
if (nil != privateKey)
{
key = [GNUTLSPrivateKey keyFromFile: privateKey
withPassword: PEMpasswd];
if (nil == key)
{
return;
return @"Unable to load key file";
}
}
@ -1583,7 +1602,7 @@ GSTLSHandlePush(gnutls_transport_ptr_t handle, const void *buffer, size_t len)
list = [GNUTLSCertificateList listFromFile: certFile];
if (nil == list)
{
return;
return @"Unable to load certificate file";
}
}
@ -1611,7 +1630,9 @@ GSTLSHandlePush(gnutls_transport_ptr_t handle, const void *buffer, size_t len)
[list certificateList], [list count], [key key]);
if (ret < 0)
{
gnutls_perror(ret);
return [NSString stringWithFormat:
@"Unable to set certificate for session: %s",
gnutls_strerror(ret)];
}
else if (NO == outgoing)
{
@ -1628,6 +1649,7 @@ GSTLSHandlePush(gnutls_transport_ptr_t handle, const void *buffer, size_t len)
#endif
}
return nil;
}
- (NSInteger) write: (const void*)buf length: (NSUInteger)len

View file

@ -703,74 +703,167 @@ NSString * const NSFileHandleOperationException
@end
@implementation NSFileHandle (GNUstepOpenSSL)
@implementation NSFileHandle (GNUstepTLS)
/**
* returns the concrete class used to implement SSL connections.
* returns the concrete class used to implement SSL/TLS connections.
*/
+ (Class) sslClass
{
if (NSFileHandle_ssl_class == 0)
if (0 == NSFileHandle_ssl_class)
{
NSString *path;
NSBundle *bundle;
NSFileHandle_ssl_class = NSClassFromString(@"GSTLSHandle");
path = [[NSBundle bundleForClass: [NSObject class]] bundlePath];
path = [path stringByAppendingPathComponent: @"SSL.bundle"];
if (0 == NSFileHandle_ssl_class)
{
NSString *path;
NSBundle *bundle;
bundle = [NSBundle bundleWithPath: path];
NSFileHandle_ssl_class = [bundle principalClass];
if (NSFileHandle_ssl_class == 0 && bundle != nil)
{
NSLog(@"Failed to load principal class from bundle (%@)", path);
}
path = [[NSBundle bundleForClass: [NSObject class]] bundlePath];
path = [path stringByAppendingPathComponent: @"SSL.bundle"];
bundle = [NSBundle bundleWithPath: path];
NSFileHandle_ssl_class = [bundle principalClass];
if (NSFileHandle_ssl_class == 0 && bundle != nil)
{
NSLog(@"Failed to load principal class from bundle (%@)", path);
}
}
}
return NSFileHandle_ssl_class;
}
/** <override-dummy />
* Establishes an SSL connection from the system that the handle
* is talking to.<br />
* This is implemented by an SSL handling subclass.<br />
* The default implementation just returns NO.
*/
- (BOOL) sslAccept
{
return NO;
BOOL result = NO;
if (NO == [self sslHandshakeEstablished: &result outgoing: NO])
{
NSRunLoop *loop;
IF_NO_GC([self retain];) // Don't get destroyed during runloop
loop = [NSRunLoop currentRunLoop];
[loop runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]];
if (NO == [self sslHandshakeEstablished: &result outgoing: 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);
}
DESTROY(self);
}
return result;
}
/** <override-dummy />
* Establishes an SSL connection to the system that the handle
* is talking to.<br />
* This is implemented by an SSL handling subclass.<br />
* The default implementation just returns NO.
*/
- (BOOL) sslConnect
{
return NO;
BOOL result = NO;
if (NO == [self sslHandshakeEstablished: &result outgoing: YES])
{
NSRunLoop *loop;
IF_NO_GC([self retain];) // Don't get destroyed during runloop
loop = [NSRunLoop currentRunLoop];
[loop runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]];
if (NO == [self sslHandshakeEstablished: &result outgoing: YES])
{
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);
}
DESTROY(self);
}
return result;
}
/** <override-dummy />
* Shuts down the SSL connection to the system that the handle is talking to.
*/
- (void) sslDisconnect
{
return;
}
/** <override-dummy />
*/
- (BOOL) sslHandshakeEstablished: (BOOL*)result outgoing: (BOOL)isOutgoing
{
return NO;
if (0 != result)
{
*result = NO;
}
return YES;
}
/** <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
privateKey: (NSString*)privateKey
PEMpasswd: (NSString*)PEMpasswd
{
NSMutableDictionary *opts;
NSString *err;
opts = [NSMutableDictionary dictionaryWithCapacity: 3];
if (nil != certFile)
{
[opts setObject: certFile forKey: GSTLSCertificateFileKey];
}
if (nil != privateKey)
{
[opts setObject: privateKey forKey: GSTLSPrivateKeyFileKey];
}
if (nil != PEMpasswd)
{
[opts setObject: PEMpasswd forKey: GSTLSPrivateKeyPasswordKey];
}
err = [self sslSetOptions: opts];
if (nil != err)
{
NSLog(@"%@", err);
}
}
- (NSString*) sslSetOptions: (NSDictionary*)options
{
return nil;
}
@end