Add support for server side ssl connections.

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@18055 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
CaS 2003-11-05 18:26:09 +00:00
parent ccf66c5058
commit 61cf6fa9e9
4 changed files with 184 additions and 37 deletions

View file

@ -1,3 +1,8 @@
2003-11-05 18:26 Richard Frith-Macdonald <rfm@gnu.org>
* SSL/GSSSLHandle.m: Add support for server end handles.
* Source/NSFileHandle.m: New -sslAccept method for servers.
2003-11-05 14:49 Alexander Malmberg <alexander@malmberg.org> 2003-11-05 14:49 Alexander Malmberg <alexander@malmberg.org>
* Source/NSSerializer.m (serializeToInfo): Only save a string as * Source/NSSerializer.m (serializeToInfo): Only save a string as

View file

@ -148,14 +148,19 @@ GS_EXPORT NSString * const NSFileHandleOperationException;
/* /*
* Where OpenSSL is available, you can use the subclass returned by +sslClass * Where OpenSSL is available, you can use the subclass returned by +sslClass
* to handle SSL connections. * to handle SSL connections.
* The -sslAccept method is used to do SSL handlshake and start an
* encrypted session on a channel where the connection was initiated
* from the far end.
* The -sslConnect method is used to do SSL handlshake and start an * The -sslConnect method is used to do SSL handlshake and start an
* encrypted session. * encrypted session on a channel where the connection was initiated
* from the near end..
* The -sslDisconnect method is used to end the encrypted session. * The -sslDisconnect method is used to end the encrypted session.
* The -sslSetCertificate:privateKey:PEMpasswd: method is used to * The -sslSetCertificate:privateKey:PEMpasswd: method is used to
* establish a client certificate before starting an encrypted session. * establish a client certificate before starting an encrypted session.
*/ */
@interface NSFileHandle (GNUstepOpenSSL) @interface NSFileHandle (GNUstepOpenSSL)
+ (Class) sslClass; + (Class) sslClass;
- (BOOL) sslAccept;
- (BOOL) sslConnect; - (BOOL) sslConnect;
- (void) sslDisconnect; - (void) sslDisconnect;
- (void) sslSetCertificate: (NSString*)certFile - (void) sslSetCertificate: (NSString*)certFile

View file

@ -48,6 +48,8 @@
while it is an Objective-C reserved keyword. */ while it is an Objective-C reserved keyword. */
#define id id_x_ #define id id_x_
#include <openssl/ssl.h> #include <openssl/ssl.h>
#include <openssl/rand.h>
#include <openssl/err.h>
#undef id #undef id
#include <GSConfig.h> #include <GSConfig.h>
@ -81,12 +83,53 @@
#endif #endif
#include <errno.h> #include <errno.h>
static NSString*
sslError(int err, int e)
{
NSString *str;
SSL_load_error_strings();
switch (err)
{
case SSL_ERROR_NONE:
str = @"No error: really helpful";
break;
case SSL_ERROR_ZERO_RETURN:
str = @"Zero Return error";
break;
case SSL_ERROR_WANT_READ:
str = @"Want Read Error";
break;
case SSL_ERROR_WANT_WRITE:
str = @"Want Write Error";
break;
case SSL_ERROR_WANT_X509_LOOKUP:
str = @"Want X509 Lookup Error";
break;
case SSL_ERROR_SYSCALL:
str = [NSString stringWithFormat: @"Syscall error %d - %s",
e, GSLastErrorStr(e)];
break;
case SSL_ERROR_SSL:
str = @"SSL Error: really helpful";
break;
default:
str = @"Standard system error: really helpful";
break;
}
return str;
}
@interface GSSSLHandle : GSFileHandle <GCFinalization> @interface GSSSLHandle : GSFileHandle <GCFinalization>
{ {
SSL_CTX *ctx; SSL_CTX *ctx;
SSL *ssl; SSL *ssl;
BOOL connected; BOOL connected;
} }
- (BOOL) sslAccept;
- (BOOL) sslConnect; - (BOOL) sslConnect;
- (void) sslDisconnect; - (void) sslDisconnect;
- (void) sslSetCertificate: (NSString*)certFile - (void) sslSetCertificate: (NSString*)certFile
@ -100,6 +143,18 @@
if (self == [GSSSLHandle class]) if (self == [GSSSLHandle class])
{ {
SSL_library_init(); SSL_library_init();
/*
* If there is no /dev/urandom for ssl to use, we must seed the
* random number generator ourselves.
*/
if (![[NSFileManager defaultManager] fileExistsAtPath: @"/dev/urandom"])
{
const char *inf;
inf = [[[NSProcessInfo processInfo] globallyUniqueString] UTF8String];
RAND_seed(inf, strlen(inf));
}
} }
} }
@ -124,6 +179,89 @@
return [super read: buf length: len]; return [super read: buf length: len];
} }
- (BOOL) sslAccept
{
int ret;
int err;
NSRunLoop *loop;
if (connected == YES)
{
return YES; /* Already connected. */
}
if (isStandardFile == YES)
{
NSLog(@"Attempt to make ssl connection to a standard file");
return NO;
}
/*
* Ensure we have a context and handle to connect with.
*/
if (ctx == 0)
{
ctx = SSL_CTX_new(SSLv23_server_method());
}
if (ssl == 0)
{
ssl = SSL_new(ctx);
}
loop = [NSRunLoop currentRunLoop];
ret = SSL_set_fd(ssl, descriptor);
if (ret == 1)
{
[loop runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]];
ret = SSL_accept(ssl);
}
if (ret != 1)
{
int e = errno;
NSDate *final;
NSDate *when;
NSTimeInterval last = 0.0;
NSTimeInterval limit = 0.1;
final = [[NSDate alloc] initWithTimeIntervalSinceNow: 20.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];
ret = SSL_accept(ssl);
if (ret != 1)
{
e = errno;
err = SSL_get_error(ssl, ret);
}
else
{
err = SSL_ERROR_NONE;
}
}
RELEASE(when);
RELEASE(final);
if (err != SSL_ERROR_NONE)
{
NSString *str = sslError(err, e);
NSLog(@"unable to accept SSL connection from %@:%@ - %@",
address, service, str);
ERR_print_errors_fp(stderr);
return NO;
}
}
connected = YES;
return YES;
}
- (BOOL) sslConnect - (BOOL) sslConnect
{ {
int ret; int ret;
@ -152,10 +290,13 @@
ssl = SSL_new(ctx); ssl = SSL_new(ctx);
} }
ret = SSL_set_fd(ssl, descriptor);
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]];
ret = SSL_connect(ssl); ret = SSL_connect(ssl);
}
if (ret != 1) if (ret != 1)
{ {
int e = errno; int e = errno;
@ -192,38 +333,11 @@
RELEASE(final); RELEASE(final);
if (err != SSL_ERROR_NONE) if (err != SSL_ERROR_NONE)
{ {
NSString *str; NSString *str = sslError(err, e);
switch (err)
{
case SSL_ERROR_NONE:
str = @"No error: really helpful";
break;
case SSL_ERROR_ZERO_RETURN:
str = @"Zero Return error";
break;
case SSL_ERROR_WANT_READ:
str = @"Want Read Error";
break;
case SSL_ERROR_WANT_WRITE:
str = @"Want Write Error";
break;
case SSL_ERROR_WANT_X509_LOOKUP:
str = @"Want X509 Lookup Error";
break;
case SSL_ERROR_SYSCALL:
str = [NSString stringWithFormat: @"Syscall error %d - %s",
e, GSLastErrorStr(e)];
break;
case SSL_ERROR_SSL:
str = @"SSL Error: really helpful";
break;
default:
str = @"Standard system error: really helpful";
break;
}
NSLog(@"unable to make SSL connection to %@:%@ - %@", NSLog(@"unable to make SSL connection to %@:%@ - %@",
address, service, str); address, service, str);
ERR_print_errors_fp(stderr);
return NO; return NO;
} }
} }
@ -255,6 +369,8 @@
privateKey: (NSString*)privateKey privateKey: (NSString*)privateKey
PEMpasswd: (NSString*)PEMpasswd PEMpasswd: (NSString*)PEMpasswd
{ {
int ret;
if (isStandardFile == YES) if (isStandardFile == YES)
{ {
NSLog(@"Attempt to set ssl certificate for a standard file"); NSLog(@"Attempt to set ssl certificate for a standard file");
@ -265,19 +381,32 @@
*/ */
if (ctx == 0) if (ctx == 0)
{ {
ctx = SSL_CTX_new(SSLv23_client_method()); ctx = SSL_CTX_new(SSLv23_method());
} }
if ([PEMpasswd length] > 0) if ([PEMpasswd length] > 0)
{ {
SSL_CTX_set_default_passwd_cb_userdata(ctx, (char*)[PEMpasswd cString]); SSL_CTX_set_default_passwd_cb_userdata(ctx,
(char*)[PEMpasswd UTF8String]);
} }
if ([certFile length] > 0) if ([certFile length] > 0)
{ {
SSL_CTX_use_certificate_file(ctx, [certFile cString], X509_FILETYPE_PEM); ret = SSL_CTX_use_certificate_file(ctx, [certFile UTF8String],
X509_FILETYPE_PEM);
if (ret != 1)
{
NSLog(@"Failed to set certificate file to %@ - %@",
certFile, sslError(ERR_get_error(), errno));
}
} }
if ([privateKey length] > 0) if ([privateKey length] > 0)
{ {
SSL_CTX_use_PrivateKey_file(ctx, [privateKey cString], X509_FILETYPE_PEM); ret = SSL_CTX_use_PrivateKey_file(ctx, [privateKey UTF8String],
X509_FILETYPE_PEM);
if (ret != 1)
{
NSLog(@"Failed to set private key file to %@ - %@",
privateKey, sslError(ERR_get_error(), errno));
}
} }
} }

View file

@ -617,6 +617,14 @@ NSString * const NSFileHandleOperationException
return NSFileHandle_ssl_class; return NSFileHandle_ssl_class;
} }
/**
* Establishes an SSL connection from the system that the handle is talking to.
*/
- (BOOL) sslAccept
{
return NO;
}
/** /**
* Establishes an SSL connection to the system that the handle is talking to. * Establishes an SSL connection to the system that the handle is talking to.
*/ */