2002-06-30 09:43:21 +00:00
|
|
|
/** Implementation for GSSSLHandle for GNUStep
|
2001-12-04 14:59:09 +00:00
|
|
|
Copyright (C) 1997-1999 Free Software Foundation, Inc.
|
|
|
|
|
|
|
|
Written by: Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
|
|
|
Date: 1997
|
|
|
|
|
|
|
|
This file is part of the GNUstep Base Library.
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Library General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Library General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Library General Public
|
|
|
|
License along with this library; if not, write to the Free
|
|
|
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
2003-07-31 23:49:32 +00:00
|
|
|
#include "config.h"
|
2001-12-04 14:59:09 +00:00
|
|
|
|
2002-03-06 15:02:42 +00:00
|
|
|
#if defined(__WIN32__) || defined(_WIN32) || defined(__MS_WIN32__)
|
|
|
|
#ifndef __WIN32__
|
|
|
|
#define __WIN32__
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef __MINGW32__
|
|
|
|
#ifndef __MINGW__
|
|
|
|
#define __MINGW__
|
|
|
|
#endif
|
|
|
|
#ifndef __WIN32__
|
|
|
|
#define __WIN32__
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(__WIN32__)
|
|
|
|
#include <windows.h>
|
|
|
|
#define GNUSTEP_BASE_SOCKET_MESSAGE (WM_USER + 1)
|
|
|
|
#endif
|
|
|
|
|
2001-12-04 14:59:09 +00:00
|
|
|
/* Because openssl uses `id' as variable name sometime,
|
|
|
|
while it is an Objective-C reserved keyword. */
|
|
|
|
#define id id_x_
|
|
|
|
#include <openssl/ssl.h>
|
2003-11-05 18:26:09 +00:00
|
|
|
#include <openssl/rand.h>
|
|
|
|
#include <openssl/err.h>
|
2001-12-04 14:59:09 +00:00
|
|
|
#undef id
|
|
|
|
|
2002-03-08 06:57:03 +00:00
|
|
|
#include <GSConfig.h>
|
2002-03-06 15:02:42 +00:00
|
|
|
#include <Foundation/Foundation.h>
|
|
|
|
|
2003-07-31 23:49:32 +00:00
|
|
|
#include <GNUstepBase/GSFileHandle.h>
|
2001-12-04 14:59:09 +00:00
|
|
|
|
|
|
|
#if defined(__MINGW__)
|
2002-02-26 09:43:04 +00:00
|
|
|
#include <winsock2.h>
|
2001-12-04 14:59:09 +00:00
|
|
|
#else
|
|
|
|
#include <time.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#endif /* __MINGW__ */
|
|
|
|
|
|
|
|
#include <sys/file.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/fcntl.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#ifdef __svr4__
|
|
|
|
#include <sys/filio.h>
|
|
|
|
#endif
|
|
|
|
#include <netdb.h>
|
|
|
|
#include <string.h>
|
2002-05-02 21:22:06 +00:00
|
|
|
#ifdef HAVE_UNISTD_H
|
2001-12-04 14:59:09 +00:00
|
|
|
#include <unistd.h>
|
2002-02-20 06:42:05 +00:00
|
|
|
#endif
|
2001-12-04 14:59:09 +00:00
|
|
|
#include <errno.h>
|
|
|
|
|
2003-11-05 18:26:09 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-06-30 09:43:21 +00:00
|
|
|
@interface GSSSLHandle : GSFileHandle <GCFinalization>
|
2001-12-04 14:59:09 +00:00
|
|
|
{
|
|
|
|
SSL_CTX *ctx;
|
|
|
|
SSL *ssl;
|
|
|
|
BOOL connected;
|
|
|
|
}
|
2003-11-05 18:26:09 +00:00
|
|
|
|
|
|
|
- (BOOL) sslAccept;
|
2001-12-04 14:59:09 +00:00
|
|
|
- (BOOL) sslConnect;
|
|
|
|
- (void) sslDisconnect;
|
|
|
|
- (void) sslSetCertificate: (NSString*)certFile
|
|
|
|
privateKey: (NSString*)privateKey
|
|
|
|
PEMpasswd: (NSString*)PEMpasswd;
|
|
|
|
@end
|
|
|
|
|
2002-06-30 09:43:21 +00:00
|
|
|
@implementation GSSSLHandle
|
2001-12-04 14:59:09 +00:00
|
|
|
+ (void) initialize
|
|
|
|
{
|
2002-06-30 09:43:21 +00:00
|
|
|
if (self == [GSSSLHandle class])
|
2001-12-04 14:59:09 +00:00
|
|
|
{
|
|
|
|
SSL_library_init();
|
2003-11-05 18:26:09 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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));
|
|
|
|
}
|
2001-12-04 14:59:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) closeFile
|
|
|
|
{
|
|
|
|
[self sslDisconnect];
|
|
|
|
[super closeFile];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) gcFinalize
|
|
|
|
{
|
|
|
|
[self sslDisconnect];
|
|
|
|
[super gcFinalize];
|
|
|
|
}
|
|
|
|
|
2002-09-29 09:47:43 +00:00
|
|
|
- (int) read: (void*)buf length: (int)len
|
2001-12-04 14:59:09 +00:00
|
|
|
{
|
2002-09-29 09:47:43 +00:00
|
|
|
if (connected)
|
2001-12-04 14:59:09 +00:00
|
|
|
{
|
2002-09-29 09:47:43 +00:00
|
|
|
return SSL_read(ssl, buf, len);
|
2001-12-04 14:59:09 +00:00
|
|
|
}
|
2002-09-29 09:47:43 +00:00
|
|
|
return [super read: buf length: len];
|
2001-12-04 14:59:09 +00:00
|
|
|
}
|
|
|
|
|
2003-11-05 18:26:09 +00:00
|
|
|
- (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;
|
|
|
|
}
|
|
|
|
|
2001-12-04 14:59:09 +00:00
|
|
|
- (BOOL) sslConnect
|
|
|
|
{
|
|
|
|
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_client_method());
|
|
|
|
}
|
|
|
|
if (ssl == 0)
|
|
|
|
{
|
|
|
|
ssl = SSL_new(ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
loop = [NSRunLoop currentRunLoop];
|
2003-11-05 18:26:09 +00:00
|
|
|
ret = SSL_set_fd(ssl, descriptor);
|
|
|
|
if (ret == 1)
|
|
|
|
{
|
|
|
|
[loop runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]];
|
|
|
|
ret = SSL_connect(ssl);
|
|
|
|
}
|
2001-12-04 14:59:09 +00:00
|
|
|
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_connect(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)
|
|
|
|
{
|
2003-11-05 18:26:09 +00:00
|
|
|
NSString *str = sslError(err, e);
|
2001-12-04 14:59:09 +00:00
|
|
|
|
|
|
|
NSLog(@"unable to make SSL connection to %@:%@ - %@",
|
|
|
|
address, service, str);
|
2003-11-05 18:26:09 +00:00
|
|
|
ERR_print_errors_fp(stderr);
|
2001-12-04 14:59:09 +00:00
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
connected = YES;
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) sslDisconnect
|
|
|
|
{
|
|
|
|
if (ssl != 0)
|
|
|
|
{
|
|
|
|
if (connected == YES)
|
|
|
|
{
|
|
|
|
SSL_shutdown(ssl);
|
|
|
|
}
|
|
|
|
SSL_clear(ssl);
|
|
|
|
SSL_free(ssl);
|
|
|
|
ssl = 0;
|
|
|
|
}
|
|
|
|
if (ctx != 0)
|
|
|
|
{
|
|
|
|
SSL_CTX_free(ctx);
|
|
|
|
ctx = 0;
|
|
|
|
}
|
|
|
|
connected = NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) sslSetCertificate: (NSString*)certFile
|
|
|
|
privateKey: (NSString*)privateKey
|
|
|
|
PEMpasswd: (NSString*)PEMpasswd
|
|
|
|
{
|
2003-11-05 18:26:09 +00:00
|
|
|
int ret;
|
|
|
|
|
2001-12-04 14:59:09 +00:00
|
|
|
if (isStandardFile == YES)
|
|
|
|
{
|
|
|
|
NSLog(@"Attempt to set ssl certificate for a standard file");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Ensure we have a context to set the certificate for.
|
|
|
|
*/
|
|
|
|
if (ctx == 0)
|
|
|
|
{
|
2003-11-05 18:26:09 +00:00
|
|
|
ctx = SSL_CTX_new(SSLv23_method());
|
2001-12-04 14:59:09 +00:00
|
|
|
}
|
|
|
|
if ([PEMpasswd length] > 0)
|
|
|
|
{
|
2003-11-05 18:26:09 +00:00
|
|
|
SSL_CTX_set_default_passwd_cb_userdata(ctx,
|
|
|
|
(char*)[PEMpasswd UTF8String]);
|
2001-12-04 14:59:09 +00:00
|
|
|
}
|
|
|
|
if ([certFile length] > 0)
|
|
|
|
{
|
2003-11-05 18:26:09 +00:00
|
|
|
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));
|
|
|
|
}
|
2001-12-04 14:59:09 +00:00
|
|
|
}
|
|
|
|
if ([privateKey length] > 0)
|
|
|
|
{
|
2003-11-05 18:26:09 +00:00
|
|
|
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));
|
|
|
|
}
|
2001-12-04 14:59:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-09-29 09:47:43 +00:00
|
|
|
- (int) write: (const void*)buf length: (int)len
|
2001-12-04 14:59:09 +00:00
|
|
|
{
|
2002-09-29 09:47:43 +00:00
|
|
|
if (connected)
|
2001-12-04 14:59:09 +00:00
|
|
|
{
|
2002-09-29 09:47:43 +00:00
|
|
|
return SSL_write(ssl, buf, len);
|
2001-12-04 14:59:09 +00:00
|
|
|
}
|
2002-09-29 09:47:43 +00:00
|
|
|
return [super write: buf length: len];
|
2001-12-04 14:59:09 +00:00
|
|
|
}
|
2002-09-29 09:47:43 +00:00
|
|
|
|
2001-12-04 14:59:09 +00:00
|
|
|
@end
|
|
|
|
|