Commits

Tuukka Norri  committed 68a11dd

More work on SSL support
- Added a stub for async connections.
- A delegate of BXDatabaseContext can now decide what to do with untrusted certificates.
- Fixed previously coded methods related to certificate handling.
- Fixed a couple of typos in file names.

  • Participants
  • Parent commits 75a5f06
  • Branches PGTS

Comments (0)

Files changed (11)

File Framework/Framework.xcodeproj/project.pbxproj

 		530323C5088062270024E7EF /* NDRunLoopMessenger.h in Headers */ = {isa = PBXBuildFile; fileRef = 530323C3088062270024E7EF /* NDRunLoopMessenger.h */; };
 		530323C6088062270024E7EF /* NDRunLoopMessenger.m in Sources */ = {isa = PBXBuildFile; fileRef = 530323C4088062270024E7EF /* NDRunLoopMessenger.m */; };
 		531266140B68E28100637EDA /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 531266130B68E28100637EDA /* Security.framework */; };
-		5312665D0B68F23C00637EDA /* PGTSSertificateVerificationDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 5312665B0B68F23C00637EDA /* PGTSSertificateVerificationDelegate.h */; };
-		5312665E0B68F23C00637EDA /* PGTSSertificateVerificationDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 5312665C0B68F23C00637EDA /* PGTSSertificateVerificationDelegate.m */; };
+		5312665D0B68F23C00637EDA /* PGTSCertificateVerificationDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 5312665B0B68F23C00637EDA /* PGTSCertificateVerificationDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		5312665E0B68F23C00637EDA /* PGTSCertificateVerificationDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 5312665C0B68F23C00637EDA /* PGTSCertificateVerificationDelegate.m */; };
 		531746A7095C07E00098D3D5 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0867D69BFE84028FC02AAC07 /* Foundation.framework */; };
 		53298DE00B3307A800DE7CC8 /* PGTSRoleDescription.h in Headers */ = {isa = PBXBuildFile; fileRef = 53298DDE0B3307A800DE7CC8 /* PGTSRoleDescription.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		53298DE10B3307A800DE7CC8 /* PGTSRoleDescription.m in Sources */ = {isa = PBXBuildFile; fileRef = 53298DDF0B3307A800DE7CC8 /* PGTSRoleDescription.m */; };
 		53BA50990880501E00BFAFB5 /* PGTS.h in Headers */ = {isa = PBXBuildFile; fileRef = 53BA4FF508804EA000BFAFB5 /* PGTS.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		53BEBC5B08805EDE00EF494D /* PGTS_Prefix.pch in Headers */ = {isa = PBXBuildFile; fileRef = 32DBCF5E0370ADEE00C91783 /* PGTS_Prefix.pch */; };
 		53D0441D0B4C1E0300DB9308 /* libLog4Cocoa.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 53D044160B4C1DFD00DB9308 /* libLog4Cocoa.a */; };
+		53D0D01F0B6F4ED000D2D101 /* libssl.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 53F4F5100A370F16004913AF /* libssl.dylib */; };
+		53D0D0200B6F4ED000D2D101 /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 53A422880981B84C003C3A24 /* libcrypto.dylib */; };
+		53D0D0590B6F515100D2D101 /* PGTSCertificateVerificationDelegateProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 53D0D0580B6F515100D2D101 /* PGTSCertificateVerificationDelegateProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		53D72FE70A51A4B6000E47A7 /* libTSDataTypes.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 531B02680A51A1EA006AEF08 /* libTSDataTypes.a */; };
 		53D72FF30A51A5CB000E47A7 /* libTSDataTypes.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 531B02680A51A1EA006AEF08 /* libTSDataTypes.a */; };
 		53D9B38A08B5256700ADB959 /* PGTSAbstractClassInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 53D9B38808B5256700ADB959 /* PGTSAbstractClassInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		530323C4088062270024E7EF /* NDRunLoopMessenger.m */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.objc; name = NDRunLoopMessenger.m; path = Contrib/NDRunLoopMessenger.m; sourceTree = "<group>"; };
 		5304E3FC09575374004D0C0F /* TSDataTypes.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = TSDataTypes.xcodeproj; path = ../Dependencies/TSDataTypes/TSDataTypes.xcodeproj; sourceTree = SOURCE_ROOT; };
 		531266130B68E28100637EDA /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = /System/Library/Frameworks/Security.framework; sourceTree = "<absolute>"; };
-		5312665B0B68F23C00637EDA /* PGTSSertificateVerificationDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PGTSSertificateVerificationDelegate.h; path = Sources/PGTSSertificateVerificationDelegate.h; sourceTree = "<group>"; };
-		5312665C0B68F23C00637EDA /* PGTSSertificateVerificationDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PGTSSertificateVerificationDelegate.m; path = Sources/PGTSSertificateVerificationDelegate.m; sourceTree = "<group>"; };
+		5312665B0B68F23C00637EDA /* PGTSCertificateVerificationDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PGTSCertificateVerificationDelegate.h; path = Sources/PGTSCertificateVerificationDelegate.h; sourceTree = "<group>"; };
+		5312665C0B68F23C00637EDA /* PGTSCertificateVerificationDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PGTSCertificateVerificationDelegate.m; path = Sources/PGTSCertificateVerificationDelegate.m; sourceTree = "<group>"; };
 		5325EAD70A1B2EF600FEA842 /* postgresql */ = {isa = PBXFileReference; lastKnownFileType = folder; name = postgresql; path = "PGTS-PostgreSQL/postgresql"; sourceTree = BUILT_PRODUCTS_DIR; };
 		53298DDE0B3307A800DE7CC8 /* PGTSRoleDescription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PGTSRoleDescription.h; path = Sources/PGTSRoleDescription.h; sourceTree = "<group>"; };
 		53298DDF0B3307A800DE7CC8 /* PGTSRoleDescription.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PGTSRoleDescription.m; path = Sources/PGTSRoleDescription.m; sourceTree = "<group>"; };
 		53BA503708804F9A00BFAFB5 /* PGTS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = PGTS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		53BA503E08804FBC00BFAFB5 /* psql */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; name = psql; path = "PGTS-PostgreSQL/universal/bin/psql"; sourceTree = BUILT_PRODUCTS_DIR; };
 		53C1DF760B4BD4AB007947D8 /* Log4Cocoa.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Log4Cocoa.xcodeproj; path = Contrib/Log4Cocoa/Log4Cocoa.xcodeproj; sourceTree = "<group>"; };
+		53D0D0580B6F515100D2D101 /* PGTSCertificateVerificationDelegateProtocol.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 4; name = PGTSCertificateVerificationDelegateProtocol.h; path = Sources/PGTSCertificateVerificationDelegateProtocol.h; sourceTree = "<group>"; };
 		53D9B38808B5256700ADB959 /* PGTSAbstractClassInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PGTSAbstractClassInfo.h; path = Sources/PGTSAbstractClassInfo.h; sourceTree = "<group>"; };
 		53D9B38908B5256700ADB959 /* PGTSAbstractClassInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PGTSAbstractClassInfo.m; path = Sources/PGTSAbstractClassInfo.m; sourceTree = "<group>"; };
 		53D9B4C608B5492C00ADB959 /* PGTSTypeInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PGTSTypeInfo.h; path = Sources/PGTSTypeInfo.h; sourceTree = "<group>"; };
 				53594D1C0B13711300378707 /* libpq.a in Frameworks */,
 				53D0441D0B4C1E0300DB9308 /* libLog4Cocoa.a in Frameworks */,
 				531266140B68E28100637EDA /* Security.framework in Frameworks */,
+				53D0D01F0B6F4ED000D2D101 /* libssl.dylib in Frameworks */,
+				53D0D0200B6F4ED000D2D101 /* libcrypto.dylib in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 				53BA4FDB08804EA000BFAFB5 /* PGTSAdditions.m */,
 				536B892D0A518E4A00379C00 /* PGTSExceptions.h */,
 				536B892E0A518E4A00379C00 /* PGTSExceptions.m */,
-				5312665B0B68F23C00637EDA /* PGTSSertificateVerificationDelegate.h */,
-				5312665C0B68F23C00637EDA /* PGTSSertificateVerificationDelegate.m */,
+				53D0D0580B6F515100D2D101 /* PGTSCertificateVerificationDelegateProtocol.h */,
+				5312665B0B68F23C00637EDA /* PGTSCertificateVerificationDelegate.h */,
+				5312665C0B68F23C00637EDA /* PGTSCertificateVerificationDelegate.m */,
 			);
 			name = Other;
 			sourceTree = "<group>";
 				53298DE00B3307A800DE7CC8 /* PGTSRoleDescription.h in Headers */,
 				53298DF20B330B6F00DE7CC8 /* PGTSAbstractObjectDescription.h in Headers */,
 				53298E0F0B330EFB00DE7CC8 /* PGTSACLItem.h in Headers */,
-				5312665D0B68F23C00637EDA /* PGTSSertificateVerificationDelegate.h in Headers */,
+				5312665D0B68F23C00637EDA /* PGTSCertificateVerificationDelegate.h in Headers */,
+				53D0D0590B6F515100D2D101 /* PGTSCertificateVerificationDelegateProtocol.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 				53298DE10B3307A800DE7CC8 /* PGTSRoleDescription.m in Sources */,
 				53298DF30B330B6F00DE7CC8 /* PGTSAbstractObjectDescription.m in Sources */,
 				53298E100B330EFB00DE7CC8 /* PGTSACLItem.m in Sources */,
-				5312665E0B68F23C00637EDA /* PGTSSertificateVerificationDelegate.m in Sources */,
+				5312665E0B68F23C00637EDA /* PGTSCertificateVerificationDelegate.m in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

File Framework/Sources/PGTS.h

 #import <PGTS/PGTSModificationNotifier.h>
 #import <PGTS/PGTSLockNotifier.h>
 #import <PGTS/PGTSExceptions.h>
+#import <PGTS/PGTSCertificateVerificationDelegate.h>
 
 #import <PGTS/PGTSAbstractInfo.h>
 #import <PGTS/PGTSAbstractClassInfo.h>

File Framework/Sources/PGTSCertificateVerificationDelegate.h

+//
+// PGTSCertificateVerificationDelegate.h
+// BaseTen
+//
+// Copyright (C) 2006 Marko Karppinen & Co. LLC.
+//
+// Before using this software, please review the available licensing options
+// by visiting http://www.karppinen.fi/baseten/licensing/ or by contacting
+// us at sales@karppinen.fi. Without an additional license, this software
+// may be distributed only in compliance with the GNU General Public License.
+//
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License, version 2.0,
+// as published by the Free Software Foundation.
+//
+// This program 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 General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+// $Id$
+//
+
+#import <Foundation/Foundation.h>
+#import <PGTS/PGTSCertificateVerificationDelegateProtocol.h>
+#import <Security/Security.h>
+#import <openssl/ssl.h>
+
+
+@interface PGTSCertificateVerificationDelegate : NSObject <PGTSCertificateVerificationDelegate>
+{
+	NSMutableArray* mPolicies;
+}
+
+- (CSSM_CERT_TYPE) x509Version: (X509 *) x509Cert;
+- (SecTrustRef) copyTrustFromOpenSSLCertificates: (X509_STORE_CTX *) x509_ctx;
+- (SecCertificateRef) copyCertificateFromX509: (X509 *) opensslCert bioOutput: (BIO *) bioOutput;
+- (NSArray *) policies;
+
+@end

File Framework/Sources/PGTSCertificateVerificationDelegate.m

+//
+// PGTSCertificateVerificationDelegate.m
+// BaseTen
+//
+// Copyright (C) 2006 Marko Karppinen & Co. LLC.
+//
+// Before using this software, please review the available licensing options
+// by visiting http://www.karppinen.fi/baseten/licensing/ or by contacting
+// us at sales@karppinen.fi. Without an additional license, this software
+// may be distributed only in compliance with the GNU General Public License.
+//
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License, version 2.0,
+// as published by the Free Software Foundation.
+//
+// This program 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 General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+// $Id: PGTSFunctions.m 101 2007-01-23 16:25:46Z tuukka.norri@karppinen.fi $
+//
+
+#import "PGTSCertificateVerificationDelegate.h"
+#import <Security/Security.h>
+#import <openssl/ssl.h>
+
+#define SafeCFRelease( CF_VAL ) ( NULL != CF_VAL ? CFRelease( CF_VAL ) : NULL )
+
+@implementation PGTSCertificateVerificationDelegate
+
+- (id) init
+{
+	if ((self = [super init]))
+	{
+	}
+	return self;
+}
+
+- (void) dealloc
+{
+	[mPolicies release];
+	[super dealloc];
+}
+
+/**
+ * Get the X.509 certificate from OpenSSL, encode it in DER format and let Security framework parse it again.
+ * This way, we can use the Keychain to verify the certificate, since a CA trusted by the OS or the user
+ * might have signed it or the user could have stored the certificate earlier. The preverification result
+ * is ignored because it rejects certificates from CAs unknown to OpenSSL. 
+ */ 
+- (BOOL) PGTSAllowSSLConnection: (void *) x509_ctx preverifyStatus: (int) preverifyStatus
+{
+	BOOL rval = NO;
+	SecTrustResultType result = kSecTrustResultInvalid;
+	SecTrustRef trust = [self copyTrustFromOpenSSLCertificates: (X509_STORE_CTX *) x509_ctx];
+	OSStatus status = SecTrustEvaluate (trust, &result);
+	if (noErr == status && kSecTrustResultProceed == result)
+		rval = YES;
+
+	SafeCFRelease (trust);
+	return rval;
+}
+
+- (CSSM_CERT_TYPE) x509Version: (X509 *) x509Cert
+{
+	CSSM_CERT_TYPE rval = CSSM_CERT_X_509v3;
+	switch (X509_get_version (x509Cert))
+	{
+		case 1:
+			rval = CSSM_CERT_X_509v1;
+			break;
+		case 2:
+			rval = CSSM_CERT_X_509v2;
+			break;
+		case 3:
+		default:
+			break;
+	}
+	return rval;
+}
+
+/**
+ * To verify a certificate, we need to
+ * create a trust. To create a trust, we need to find search policies.
+ */
+- (SecTrustRef) copyTrustFromOpenSSLCertificates: (X509_STORE_CTX *) x509_ctx
+{
+	BIO* bioOutput = BIO_new (BIO_s_mem ());
+	
+	int count = M_sk_num (x509_ctx->untrusted);
+	NSMutableArray* certs = [NSMutableArray arrayWithCapacity: count + 1];
+	SecCertificateRef serverCert = [self copyCertificateFromX509: x509_ctx->cert bioOutput: bioOutput];
+	CFArrayAppendValue ((CFMutableArrayRef) certs, serverCert);
+	SafeCFRelease (serverCert);
+	
+	for (int i = 0; i < count; i++)
+	{
+		SecCertificateRef chainCert = [self copyCertificateFromX509: (X509 *) M_sk_value (x509_ctx->untrusted, i)
+														  bioOutput: bioOutput];
+		CFArrayAppendValue ((CFMutableArrayRef) certs, chainCert);
+		SafeCFRelease (chainCert);
+	}
+	
+	SecTrustRef trust = NULL;
+	OSStatus status = SecTrustCreateWithCertificates ((CFArrayRef) certs, [self policies], &trust);
+	status = noErr;
+	
+	BIO_free (bioOutput);
+	return trust;
+}
+
+- (SecCertificateRef) copyCertificateFromX509: (X509 *) opensslCert bioOutput: (BIO *) bioOutput
+{
+	SecCertificateRef cert = NULL;
+	BIO_reset (bioOutput);
+	if (i2d_X509_bio (bioOutput, opensslCert))
+	{
+		BUF_MEM* bioBuffer = NULL;
+		BIO_get_mem_ptr (bioOutput, &bioBuffer);
+		CSSM_DATA* cssmCert = alloca (sizeof (CSSM_DATA));
+		cssmCert->Data = (uint8 *) bioBuffer->data;
+		cssmCert->Length = bioBuffer->length;
+		
+		OSStatus status = SecCertificateCreateFromData (cssmCert, [self x509Version: opensslCert], CSSM_CERT_ENCODING_DER, &cert);
+		status = noErr;
+	}
+	return cert;
+}
+	
+/**
+ * To find search policies, we need to create
+ * a search criteria. To create a search criteria, we need to give the criteria creation function some constants.
+ */
+- (NSArray *) policies
+{
+	if (nil == mPolicies)
+	{
+		OSStatus status = noErr;
+	
+		mPolicies = [[NSMutableArray alloc] init];
+		int i = 0;
+		const CSSM_OID* currentOidPtr = NULL;
+		const CSSM_OID* oidPtrs [] = {&CSSMOID_APPLE_TP_SSL, &CSSMOID_APPLE_TP_REVOCATION_CRL, NULL};
+		while (NULL != (currentOidPtr = oidPtrs [i]))
+		{
+			SecPolicySearchRef criteria = NULL;
+			SecPolicyRef policy = NULL;
+			status = SecPolicySearchCreate (CSSM_CERT_X_509v3, currentOidPtr, NULL, &criteria);
+			while (noErr == SecPolicySearchCopyNext (criteria, &policy))
+			{
+				CFArrayAppendValue ((CFMutableArrayRef) mPolicies, policy);
+				SafeCFRelease (policy);
+			}
+			SafeCFRelease (criteria);
+			i++;
+		}
+	}
+	return mPolicies;
+}
+
+@end

File Framework/Sources/PGTSCertificateVerificationDelegateProtocol.h

+//
+// PGTSCertificateVerificationDelegateProtocol.h
+// BaseTen
+//
+// Copyright (C) 2006 Marko Karppinen & Co. LLC.
+//
+// Before using this software, please review the available licensing options
+// by visiting http://www.karppinen.fi/baseten/licensing/ or by contacting
+// us at sales@karppinen.fi. Without an additional license, this software
+// may be distributed only in compliance with the GNU General Public License.
+//
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License, version 2.0,
+// as published by the Free Software Foundation.
+//
+// This program 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 General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+// $Id$
+//
+
+@protocol PGTSCertificateVerificationDelegate
+/** 
+ * Should the SSL connection be allowed or not.
+ * This might not be called from the main thread.
+ */
+- (BOOL) PGTSAllowSSLConnection: (void *) sslStruct preverifyStatus: (int) preverifyStatus;
+@end
+

File Framework/Sources/PGTSConnection.h

 @class PGTSDatabaseInfo;
 @class TSObjectTagDictionary;
 @protocol PGTSConnectionDelegate;
+@protocol PGTSCertificateVerificationDelegate;
 
 
 @interface PGTSConnection : NSObject 
     NSMutableDictionary* deserializationDictionary;
     NSString* initialCommands;
 
+	volatile ConnStatusType connectionStatus;
+    struct timeval timeout;
+	
+	id <PGTSCertificateVerificationDelegate> certificateVerificationDelegate;
+
 	BOOL connectsAutomatically;
     BOOL reconnectsAutomatically;
     BOOL overlooksFailedQueries;
     BOOL delegateProcessesNotices;
-
-	volatile ConnStatusType connectionStatus;
-    struct timeval timeout;
-
+	
     volatile BOOL logsQueries;
 	volatile BOOL shouldContinueThread;
     volatile BOOL threadRunning;
 
 - (void) setLogsQueries: (BOOL) aBool;
 - (BOOL) logsQueries;
+
+- (id <PGTSCertificateVerificationDelegate>) certificateVerificationDelegate;
+- (void) setCertificateVerificationDelegate: (id <PGTSCertificateVerificationDelegate>) anObject;
 @end
 
 

File Framework/Sources/PGTSConnection.m

 #import "PGTSConnectionDelegate.h"
 #import "PGTSFunctions.h"
 #import "PGTSDatabaseInfo.h"
+#import "PGTSCertificateVerificationDelegate.h"
 #import <TSDataTypes/TSDataTypes.h>
 #import <Log4Cocoa/Log4Cocoa.h>
 
 /** \endcond */
 
 
+static id <PGTSCertificateVerificationDelegate> defaultCertDelegate = nil;
+
 /**
  * Return the result of the given accessor as an NSString
  * Handles returned NULL values safely
 		tooLate = YES;
 		//This should have been the +initialize method from the start.
 		PGTSInit ();
+		defaultCertDelegate = [[PGTSCertificateVerificationDelegate alloc] init];
 	}
 }
 
         failedToSendQuery = NO;
         initialCommands = nil;
         //databaseInfo is set after the connection has been made
+		certificateVerificationDelegate = defaultCertDelegate;
         
         exceptionTable = 0;
         [self setDelegate: nil];        
 {
     return logsQueries;
 }
+
+- (id <PGTSCertificateVerificationDelegate>) certificateVerificationDelegate
+{
+	return certificateVerificationDelegate;
+}
+
+- (void) setCertificateVerificationDelegate: (id <PGTSCertificateVerificationDelegate>) anObject
+{
+	certificateVerificationDelegate = anObject;
+	if (nil == certificateVerificationDelegate)
+		certificateVerificationDelegate = defaultCertDelegate;
+}
 @end
 
 

File Framework/Sources/PGTSConnectionPrivate.m

 
 static int sslConnectionExIndex = -1;
 
-extern int PGTSVerifySSLSertificate (int preverify_ok, X509_STORE_CTX* x509_ctx);
+extern int PGTSVerifySSLCertificate (int preverify_ok, X509_STORE_CTX* x509_ctx);
 
 static NSNotification* 
 PGTSExtractPgNotification (id anObject, PGnotify* pgNotification)
 				sslSetUp = YES;
 				SSL* ssl = PQgetssl (connection);
 				NSAssert (NULL != ssl, @"Expected ssl struct not to be NULL.");
-				SSL_set_verify (ssl, SSL_VERIFY_PEER, &PGTSVerifySSLSertificate);
+				SSL_set_verify (ssl, SSL_VERIFY_PEER, &PGTSVerifySSLCertificate);
 				SSL_set_ex_data (ssl, PGTSSSLConnectionExIndex(), self);
 			}
 #endif

File Framework/Sources/PGTSFunctions.m

 #import "PGTSConstants.h"
 #import "PGTSConnectionDelegate.h"
 #import "PGTSConnectionPrivate.h"
+#import "PGTSCertificateVerificationDelegate.h"
 
 
 void 
     return lockOperation;
 }
 
-
-inline CSSM_CERT_TYPE
-x509Version (X509* x509Cert)
-{
-	CSSM_CERT_TYPE rval = CSSM_CERT_X_509v3;
-	switch (X509_get_version (x509Cert))
-	{
-		case 1:
-			rval = CSSM_CERT_X_509v1;
-			break;
-		case 2:
-			rval = CSSM_CERT_X_509v2;
-			break;
-		case 3:
-		default:
-			break;
-	}
-	return rval;
-}
-
-inline SecCertificateRef
-SecCertificateFromX509 (X509* opensslCert, BIO* bioOutput)
-{
-	SecCertificateRef cert = NULL;
-	if (i2d_X509_bio (bioOutput, opensslCert))
-	{
-		BUF_MEM* bioBuffer = NULL;
-		BIO_get_mem_ptr (bioOutput, &bioBuffer);
-		
-		OSStatus status = SecCertificateCreateFromData ((void *) bioBuffer->data, x509Version (opensslCert), CSSM_CERT_ENCODING_DER, &cert);
-		status = noErr;
-	}
-	return cert;
-}
-
 /**
  * \internal
  * Verify an X.509 certificate.
- * Get the X.509 certificate from OpenSSL, encode it in DER format and let Security framework parse it again.
- * This way, we can use the Keychain to verify the certificate, since a CA trusted by the OS or the user
- * might have signed it or the user could have stored the certificate earlier. The preverification result
- * is ignored because it rejects certificates from CAs unknown to OpenSSL. 
  */
 int
-PGTSVerifySSLSertificate (int preverify_ok, void* x509_ctx)
+PGTSVerifySSLCertificate (int preverify_ok, void* x509_ctx)
 {
-	return preverify_ok;
-#if 0 
-	int rval = 0;
+	//FIXME: this function should have a run loop, if possible, and run it until the result has been received.
+	//This way, we can use ordinary Cocoa sheets.
 	SSL* ssl = X509_STORE_CTX_get_ex_data ((X509_STORE_CTX *) x509_ctx, SSL_get_ex_data_X509_STORE_CTX_idx ());
 	PGTSConnection* connection = SSL_get_ex_data (ssl, PGTSSSLConnectionExIndex ());
-	
-	//FIXME: move these into the delegate object and make the API such that X509 structure can also be used
-	//when verifying.
-	BIO* bioOutput = BIO_new (BIO_s_mem ());
-	
-	int count = M_sk_num (x509_ctx->untrusted);
-	NSMutableArray* certs = [NSMutableArray arrayWithCapacity: count + 1];
-	SecCertificateRef serverCert = CertificateFromX509 (x509_ctx->cert, bioOutput);
-	[certs addObject: serverCert];
-	
-	for (int i = 0; i < count; i++)
-	{
-		BIO_reset (bioOutput);
-		SecCertificateRef chainCert = CertificateFromX509 (M_sk_value (x509_ctx->untrusted, i));
-		[certs addObject: chainCert];
-	}
-	
-	SecTrustRef trust = NULL;
-	OSStatus status = SecTrustCreateWithCertificates (certs,<#CFTypeRef policies#>, &trust);
-
-	BIO_free (bioOutput);
+	int rval = (YES == [[connection certificateVerificationDelegate] PGTSAllowSSLConnection: x509_ctx preverifyStatus: preverify_ok]);
 	return rval;
-#endif
 }

File Framework/Sources/PGTSSertificateVerificationDelegate.h

-//
-// PGTSSertificateVerificationDelegate.h
-// BaseTen
-//
-// Copyright (C) 2006 Marko Karppinen & Co. LLC.
-//
-// Before using this software, please review the available licensing options
-// by visiting http://www.karppinen.fi/baseten/licensing/ or by contacting
-// us at sales@karppinen.fi. Without an additional license, this software
-// may be distributed only in compliance with the GNU General Public License.
-//
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License, version 2.0,
-// as published by the Free Software Foundation.
-//
-// This program 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 General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-//
-// $Id$
-//
-
-#import <Foundation/Foundation.h>
-
-@interface PGTSSertificateVerificationDelegate : NSObject 
-{
-	NSMutableArray* mPolicies;
-}
-
-@end

File Framework/Sources/PGTSSertificateVerificationDelegate.m

-//
-// PGTSSertificateVerificationDelegate.m
-// BaseTen
-//
-// Copyright (C) 2006 Marko Karppinen & Co. LLC.
-//
-// Before using this software, please review the available licensing options
-// by visiting http://www.karppinen.fi/baseten/licensing/ or by contacting
-// us at sales@karppinen.fi. Without an additional license, this software
-// may be distributed only in compliance with the GNU General Public License.
-//
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License, version 2.0,
-// as published by the Free Software Foundation.
-//
-// This program 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 General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-//
-// $Id: PGTSFunctions.m 101 2007-01-23 16:25:46Z tuukka.norri@karppinen.fi $
-//
-
-#import "PGTSSertificateVerificationDelegate.h"
-#import <Security/Security.h>
-
-
-@implementation PGTSSertificateVerificationDelegate
-
-- (id) init
-{
-	return nil;
-}
-
-- (void) dealloc
-{
-	[mPolicies release];
-	[super dealloc];
-}
-
-/*
- * To verify a certificate, we need to
- * create a trust. To create a trust, we need to find search policies. To find search policies, we need to create
- * a search criteria. To create a search criteria, we need to give the criteria creation function some constants.
- */
-- (NSArray *) policies
-{
-	if (nil == mPolicies)
-	{
-		//FIXME: this doesn't compile :(
-#if 0
-		OSStatus status = noErr;
-	
-		mPolicies = [[NSMutableArray alloc] init];
-		int i = 0;
-		CSSM_OID currentOid;
-		CSSM_OID* oids = {CSSMOID_APPLE_TP_SSL, CSSMOID_APPLE_TP_REVOCATION_CRL, NULL};
-		while (NULL != (currentOid = oids [i]))
-		{
-			SecPolicySearchRef criteria = NULL;
-			SecPolicyRef policy = NULL;
-			status = SecPolicySearchCreate (CSSM_CERT_X_509v3, currentOid, NULL, &criteria);
-			while (noErr == SecPolicySearchCopyNext (criteria, &policy))
-			{
-				[policies addObject: policy];
-				CFRelease (policy);
-			}
-			CFRelease (criteria);
-		}
-#endif
-	}
-	return mPolicies;
-}
-
-@end