mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-23 09:04:13 +00:00
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:
parent
2927b474b5
commit
2539f6207c
5 changed files with 398 additions and 311 deletions
11
ChangeLog
11
ChangeLog
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue