Index: platforms/Mac OS/plugins/SqueakSSL/sqMacSSL.c
===================================================================
--- platforms/Mac OS/plugins/SqueakSSL/sqMacSSL.c	(revision 3308)
+++ platforms/Mac OS/plugins/SqueakSSL/sqMacSSL.c	(working copy)
@@ -1,9 +1,9 @@
 /* sqMacSSL.c: SqueakSSL implementation based on Mac OSX Security Services */
 #include "sq.h"
 #include "SqueakSSL.h"
+#include <string.h>
 
-#include <Security/Security.h>
-#include <Security/SecCertificate.h>
+#import <Security/Security.h>
 
 typedef struct sqSSL {
 	int state;
@@ -12,6 +12,7 @@
 
 	char *certName;
 	char *peerName;
+    char *serverName;
 
 	
 	SSLContextRef ctx;
@@ -43,13 +44,13 @@
 	sqSSL *ssl = (sqSSL*) connection;
 	size_t sz = *dataLength;
 
-	if(ssl->loglevel) 
+	if (ssl->loglevel) 
 		printf("SqueakSSLRead: Requesting %d bytes, having %d bytes\n", 
 			   (int)sz, ssl->dataLen);
-	if(ssl->dataLen < sz) sz = ssl->dataLen;
+	if (ssl->dataLen < sz) sz = ssl->dataLen;
 	memcpy(data, ssl->dataBuf, sz);
 	/* Did we have enough data? */
-	if(sz == *dataLength) {
+	if (sz == *dataLength) {
 		/* Adjust read buffer */
 		memmove(ssl->dataBuf, ssl->dataBuf+sz, ssl->dataLen - sz);
 		ssl->dataLen -= sz;
@@ -67,14 +68,14 @@
 	sqSSL *ssl = (sqSSL*) connection;
 	size_t sz = ssl->outMax - ssl->outLen;
 	
-	if(ssl->loglevel) 
+	if (ssl->loglevel) 
 		printf("SqueakSSLWrite: Writing %d bytes, having %d free\n", 
 			   (int)*dataLength, (int)sz);
-	if(sz == 0) {
+	if (sz == 0) {
 		*dataLength = 0;
 		return errSSLWouldBlock;
 	}
-	if(*dataLength < sz) sz = *dataLength;
+	if (*dataLength < sz) sz = *dataLength;
 	memcpy(ssl->outBuf + ssl->outLen, data, sz);
 	ssl->outLen += sz;
 	*dataLength = sz;
@@ -85,6 +86,15 @@
 /********************************************************************/
 /********************************************************************/
 
+#if !(MAC_OS_X_VERSION_MAX_ALLOWED >= 1070)
+/* strnlen, as in the popular GNU exension to libc */
+static size_t strnlen (const char const* str, size_t max) {
+    const char* end = memchr (str, 0, max);
+    return end ? (size_t)(end - str) : max;
+}
+#endif
+
+
 /* sslFromHandle: Maps a handle to an SSL */
 static sqSSL *sslFromHandle(sqInt handle) {
 	return handle < handleMax ? handleBuf[handle] : NULL;
@@ -95,53 +105,71 @@
 int sqSetupSSL(sqSSL *ssl, int isServer) {
 	OSStatus status;
 
-	if(ssl->loglevel) printf("sqSetupSSL: Setting up new context\n");
+
+	if (ssl->loglevel) printf("sqSetupSSL: Setting up new context\n");
 	/* Create the new context */
-	status = SSLNewContext(isServer, &ssl->ctx);
-	if(status) {
-		if(ssl->loglevel) printf("SSLNewContext failed: code = %d\n", (int)status);
-		return 0;
-	}
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
+    status = SSLCreateContext(isServer ?  kSSLServerSide : kSSLClientSide, &ssl->ctx);
+    if (status != noErr) {
+        if (ssl->loglevel) printf("SSLCreateContext failed: code = %d\n", (int)status);
+        return 0;
+    }
+#else
+    status = SSLNewContext(isServer, &ssl->ctx);
+    if (status != noErr) {
+        if (ssl->loglevel) printf("SSLNewContext failed: code = %d\n", (int)status);
+        return 0;
+    }
+#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
+
 	/* Set the connection ref */
 	status = SSLSetConnection(ssl->ctx, ssl);
-	if(status) {
-		if(ssl->loglevel) printf("SSLSetConnection failed: code = %d\n", (int)status);
+	if (status != noErr) {
+		if (ssl->loglevel) printf("SSLSetConnection failed: code = %d\n", (int)status);
 		return 0;
 	}
 	
 	/* Set up the read/write functions */
 	status = SSLSetIOFuncs(ssl->ctx,SqueakSSLRead, SqueakSSLWrite);
-	if(status) {
-		if(ssl->loglevel) printf("SSLSetIOFuncs failed: code = %d\n", (int)status);
+	if (status != noErr) {
+		if (ssl->loglevel) printf("SSLSetIOFuncs failed: code = %d\n", (int)status);
 		return 0;
 	}
 
-	/* Enable desired protocols */
-	status = SSLSetProtocolVersionEnabled(ssl->ctx, kSSLProtocol2, false);
-	if(status) {
-		if(ssl->loglevel) printf("SSLSetProtocolVersionEnabled failed: code = %d\n", (int)status);
-		return 0;
-	}
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
+    /* At least TLS 1 */
+    status = SSLSetProtocolVersionMin(ssl->ctx, kTLSProtocol1);
+    if (status != noErr) {
+        if (ssl->loglevel) printf("SSLSetProtocolVersionMin failed: code = %d\n", (int)status);
+        return 0;
+    }
+#else
+    /* Prefer TLS 1 */
+    status = SSLSetProtocolVersionEnabled(ssl->ctx, kTLSProtocol1, true);
+    if (status != noErr) {
+        if (ssl->loglevel) printf("SSLSetProtocolVersionEnabled failed: code = %d\n", (int)status);
+        return 0;
+    }
+#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
 
-	status = SSLSetProtocolVersionEnabled(ssl->ctx, kSSLProtocol3, true);
-	if(status) {
-		if(ssl->loglevel) printf("SSLSetProtocolVersionEnabled failed: code = %d\n", (int)status);
-		return 0;
-	}
 
-	status = SSLSetProtocolVersionEnabled(ssl->ctx, kTLSProtocol1, true);
-	if(status) {
-		if(ssl->loglevel) printf("SSLSetProtocolVersionEnabled failed: code = %d\n", (int)status);
-		return 0;
-	}
-	/* Disable cert verification since we do that ourselves */
+    /* Disable cert verification since we do that ourselves */
 	status = SSLSetEnableCertVerify(ssl->ctx, false);
-	if(status) {
-		if(ssl->loglevel) printf("SSLSetEnableCertVerify failed: code = %d\n", (int)status);
+	if (status != noErr) {
+		if (ssl->loglevel) printf("SSLSetEnableCertVerify failed: code = %d\n", (int)status);
 		return 0;
 	}
 
-	return 1;
+    if (ssl->serverName) {
+        /* Try for SNI */
+        status = SSLSetPeerDomainName(ssl->ctx, ssl->serverName, strnlen(ssl->serverName, 254));
+        if (status != noErr) {
+            if (ssl->loglevel) printf("SSLSetPeerDomainName failed: code = %d\n", (int)status);
+            return 0;
+        }
+    }
+
+    return 1;
 }
 
 /********************************************************************/
@@ -162,9 +190,9 @@
 
 	/* Find a free handle */
 	for(handle = 1; handle < handleMax; handle++)
-		if(handleBuf[handle] == NULL) break;
+		if (handleBuf[handle] == NULL) break;
 
-	if(handle >= handleMax) {
+	if (handle >= handleMax) {
 		int i, delta = 100;
 		/* Resize the handle buffer */
 		handleBuf = realloc(handleBuf, (handleMax+delta)*sizeof(void*));
@@ -183,11 +211,20 @@
 */
 sqInt sqDestroySSL(sqInt handle) {
 	sqSSL *ssl = sslFromHandle(handle);
-	if(ssl == NULL) return 0;
+	if (ssl == NULL) return 0;
 
-	if(ssl->certName) free(ssl->certName);
-	if(ssl->peerName) free(ssl->peerName);
+    if (ssl->ctx) {
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
+        CFRelease(ssl->ctx);
+#else
+        SSLDisposeContext(ssl->ctx);
+#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
+    }
 
+    if (ssl->certName) free(ssl->certName);
+	if (ssl->peerName) free(ssl->peerName);
+    if (ssl->serverName) free(ssl->serverName);
+
 	free(ssl);
 	handleBuf[handle] = NULL;
 	return 1;
@@ -206,10 +243,10 @@
 	OSStatus status;
 	sqSSL *ssl = sslFromHandle(handle);
 
-	if(ssl->loglevel) printf("sqConnectSSL: %x\n", (int)ssl);
+	if (ssl->loglevel) printf("sqConnectSSL: %x\n", (int)ssl);
 
 	/* Verify state of session */
-	if(ssl == NULL || (ssl->state != SQSSL_UNUSED && ssl->state != SQSSL_CONNECTING)) {
+	if (ssl == NULL || (ssl->state != SQSSL_UNUSED && ssl->state != SQSSL_CONNECTING)) {
 		return SQSSL_INVALID_STATE;
 	}
 
@@ -218,31 +255,31 @@
 	ssl->outLen = 0;
 	ssl->outMax = dstLen;
 
-	if(ssl->dataLen + srcLen > ssl->dataMax) {
+	if (ssl->dataLen + srcLen > ssl->dataMax) {
 		/* resize the data buffer */
 		ssl->dataMax += (srcLen < 4096) ? (4096) : (srcLen+1024);
 		ssl->dataBuf = realloc(ssl->dataBuf, ssl->dataMax);
-		if(!ssl->dataBuf) return SQSSL_OUT_OF_MEMORY;
+		if (!ssl->dataBuf) return SQSSL_OUT_OF_MEMORY;
 	}
-	if(ssl->loglevel) printf("sqConnectSSL: input token %d bytes\n", srcLen);
+	if (ssl->loglevel) printf("sqConnectSSL: input token %d bytes\n", srcLen);
 	memcpy(ssl->dataBuf + ssl->dataLen, srcBuf, srcLen);
 	ssl->dataLen += srcLen;
 
 	/* Establish initial connection */
-	if(ssl->state == SQSSL_UNUSED) {
+	if (ssl->state == SQSSL_UNUSED) {
 		ssl->state = SQSSL_CONNECTING;
-		if(ssl->loglevel) printf("sqConnectSSL: Setting up SSL\n");
-		if(!sqSetupSSL(ssl, 0)) return SQSSL_GENERIC_ERROR;
+		if (ssl->loglevel) printf("sqConnectSSL: Setting up SSL\n");
+		if (!sqSetupSSL(ssl, 0)) return SQSSL_GENERIC_ERROR;
 	}
 
 	status = SSLHandshake(ssl->ctx);
-	if(status == errSSLWouldBlock) {
+	if (status == errSSLWouldBlock) {
 		/* Return token to caller */
-		if(ssl->loglevel) printf("sqConnectSSL: Produced %d token bytes\n", ssl->outLen);
+		if (ssl->loglevel) printf("sqConnectSSL: Produced %d token bytes\n", ssl->outLen);
 		return ssl->outLen ? ssl->outLen : SQSSL_NEED_MORE_DATA;
 	}
-	if(status != noErr) {
-		if(ssl->loglevel) printf("sqConnectSSL: SSLHandshake returned %d\n", (int)status);
+	if (status != noErr) {
+		if (ssl->loglevel) printf("sqConnectSSL: SSLHandshake returned %d\n", (int)status);
 		return SQSSL_GENERIC_ERROR;
 	}
 	/* We are connected. Verify the cert. */
@@ -251,13 +288,13 @@
 
 	/* Extract the peer name from the cert */
 	status = SSLCopyPeerCertificates(ssl->ctx, &ssl->certs);
-	if(status == noErr) {
-		if(CFArrayGetCount(ssl->certs) > 0) {
+	if (status == noErr) {
+		if (CFArrayGetCount(ssl->certs) > 0) {
 			char peerName[256];
 			CFStringRef cfName;
 			SecCertificateRef cert = (SecCertificateRef) CFArrayGetValueAtIndex(ssl->certs, 0);
 			status = SecCertificateCopyCommonName(cert, &cfName);
-			if(status == noErr) {
+			if (status == noErr) {
 				CFStringGetCString(cfName, peerName, sizeof(peerName), kCFStringEncodingUTF8);
 				ssl->peerName = strdup(peerName);
 				CFRelease(cfName);
@@ -281,7 +318,7 @@
 	sqSSL *ssl = sslFromHandle(handle);
 
 	/* Verify state of session */
-	if(ssl == NULL || (ssl->state != SQSSL_UNUSED && ssl->state != SQSSL_ACCEPTING)) {
+	if (ssl == NULL || (ssl->state != SQSSL_UNUSED && ssl->state != SQSSL_ACCEPTING)) {
 		return SQSSL_INVALID_STATE;
 	}
 
@@ -290,31 +327,31 @@
 	ssl->outLen = 0;
 	ssl->outMax = dstLen;
 	
-	if(ssl->dataLen + srcLen > ssl->dataMax) {
+	if (ssl->dataLen + srcLen > ssl->dataMax) {
 		/* resize the data buffer */
 		ssl->dataMax += (srcLen < 4096) ? (4096) : (srcLen+1024);
 		ssl->dataBuf = realloc(ssl->dataBuf, ssl->dataMax);
-		if(!ssl->dataBuf) return SQSSL_OUT_OF_MEMORY;
+		if (!ssl->dataBuf) return SQSSL_OUT_OF_MEMORY;
 	}
-	if(ssl->loglevel) printf("sqConnectSSL: input token %d bytes\n", srcLen);
+	if (ssl->loglevel) printf("sqConnectSSL: input token %d bytes\n", srcLen);
 	memcpy(ssl->dataBuf + ssl->dataLen, srcBuf, srcLen);
 	ssl->dataLen += srcLen;
 	
 	/* Establish initial connection */
-	if(ssl->state == SQSSL_UNUSED) {
+	if (ssl->state == SQSSL_UNUSED) {
 		ssl->state = SQSSL_ACCEPTING;
-		if(ssl->loglevel) printf("sqAcceptSSL: Setting up SSL\n");
-		if(!sqSetupSSL(ssl, 1)) return SQSSL_GENERIC_ERROR;
-		if(ssl->loglevel) printf("sqAcceptSSL: setting accept state\n");
+		if (ssl->loglevel) printf("sqAcceptSSL: Setting up SSL\n");
+		if (!sqSetupSSL(ssl, 1)) return SQSSL_GENERIC_ERROR;
+		if (ssl->loglevel) printf("sqAcceptSSL: setting accept state\n");
 	}
 
 	status = SSLHandshake(ssl->ctx);
-	if(status == errSSLWouldBlock) {
+	if (status == errSSLWouldBlock) {
 		/* Return token to caller */
 		return ssl->outLen ? ssl->outLen : SQSSL_NEED_MORE_DATA;
 	}
-	if(status != noErr) {
-		if(ssl->loglevel) printf("sqConnectSSL: SSLHandshake returned %d\n", (int)status);
+	if (status != noErr) {
+		if (ssl->loglevel) printf("sqConnectSSL: SSLHandshake returned %d\n", (int)status);
 		return SQSSL_GENERIC_ERROR;
 	}
 	/* We are connected. Verify the cert. */
@@ -336,19 +373,19 @@
 	OSStatus status;
 	sqSSL *ssl = sslFromHandle(handle);
 
-	if(ssl == NULL || ssl->state != SQSSL_CONNECTED) return SQSSL_INVALID_STATE;
+	if (ssl == NULL || ssl->state != SQSSL_CONNECTED) return SQSSL_INVALID_STATE;
 
 	/* Set up the output buffer */
 	ssl->outBuf = dstBuf;
 	ssl->outLen = 0;
 	ssl->outMax = dstLen;
 	
-	if(ssl->loglevel) printf("sqEncryptSSL: Encrypting %d bytes\n", srcLen);
+	if (ssl->loglevel) printf("sqEncryptSSL: Encrypting %d bytes\n", srcLen);
 
 	status = SSLWrite(ssl->ctx, srcBuf, srcLen, &nbytes);
-	if(nbytes != srcLen) return SQSSL_GENERIC_ERROR;
-		if(status == errSSLWouldBlock || status == noErr) return ssl->outLen;
-	if(ssl->loglevel) printf("sqDecryptSSL: SSLWrite returned %d\n", (int)status);
+	if (nbytes != srcLen) return SQSSL_GENERIC_ERROR;
+		if (status == errSSLWouldBlock || status == noErr) return ssl->outLen;
+	if (ssl->loglevel) printf("sqDecryptSSL: SSLWrite returned %d\n", (int)status);
 	return SQSSL_GENERIC_ERROR;
 }
 
@@ -366,23 +403,23 @@
 	OSStatus status;
 	sqSSL *ssl = sslFromHandle(handle);
 
-	if(ssl == NULL || ssl->state != SQSSL_CONNECTED) return SQSSL_INVALID_STATE;
+	if (ssl == NULL || ssl->state != SQSSL_CONNECTED) return SQSSL_INVALID_STATE;
 
-	if(ssl->dataLen + srcLen > ssl->dataMax) {
+	if (ssl->dataLen + srcLen > ssl->dataMax) {
 		/* resize the read buffer */
 		ssl->dataMax += (srcLen < 4096) ? (4096) : (srcLen+1024);
 		ssl->dataBuf = realloc(ssl->dataBuf, ssl->dataMax);
-		if(!ssl->dataBuf) return SQSSL_OUT_OF_MEMORY;
+		if (!ssl->dataBuf) return SQSSL_OUT_OF_MEMORY;
 	}
-	if(ssl->loglevel) printf("sqDecryptSSL: Input data %d bytes\n", srcLen);
+	if (ssl->loglevel) printf("sqDecryptSSL: Input data %d bytes\n", srcLen);
 	memcpy(ssl->dataBuf + ssl->dataLen, srcBuf, srcLen);
 	ssl->dataLen += srcLen;
 	
-	if(ssl->loglevel) printf("sqDecryptSSL: Decrypting %d bytes\n", ssl->dataLen);
+	if (ssl->loglevel) printf("sqDecryptSSL: Decrypting %d bytes\n", ssl->dataLen);
 
 	status = SSLRead(ssl->ctx, dstBuf, dstLen, &nbytes);
-	if(status == errSSLWouldBlock || status == noErr) return nbytes;
-	if(ssl->loglevel) printf("sqDecryptSSL: SSLRead returned %d\n", (int)status);
+	if (status == errSSLWouldBlock || status == noErr) return nbytes;
+	if (ssl->loglevel) printf("sqDecryptSSL: SSLRead returned %d\n", (int)status);
 	return SQSSL_GENERIC_ERROR;
 }
 
@@ -395,12 +432,13 @@
 char* sqGetStringPropertySSL(sqInt handle, int propID) {
 	sqSSL *ssl = sslFromHandle(handle);
 
-	if(ssl == NULL) return NULL;
+	if (ssl == NULL) return NULL;
 	switch(propID) {
-		case SQSSL_PROP_PEERNAME:  return ssl->peerName;
-		case SQSSL_PROP_CERTNAME:  return ssl->certName;
-		default:
-			if(ssl->loglevel) printf("sqGetStringPropertySSL: Unknown property ID %d\n", propID);
+		case SQSSL_PROP_PEERNAME:   return ssl->peerName;
+		case SQSSL_PROP_CERTNAME:   return ssl->certName;
+        case SQSSL_PROP_SERVERNAME: return ssl->serverName;
+        default:
+			if (ssl->loglevel) printf("sqGetStringPropertySSL: Unknown property ID %d\n", propID);
 			return NULL;
 	}
 	return NULL;
@@ -418,19 +456,27 @@
 	sqSSL *ssl = sslFromHandle(handle);
 	char *property = NULL;
 
-	if(ssl == NULL) return 0;
+	if (ssl == NULL) return 0;
 
-	if(propLen) {
-	  property = calloc(1, propLen+1);
-	  memcpy(property, propName, propLen);
-	};
+	if (propLen) {
+        property = malloc(propLen + 1);
+        memcpy(property, propName, propLen);
+        property[propLen] = '\0';
+    }
 
-	if(ssl->loglevel) printf("sqSetStringPropertySSL(%d): %s\n", propID, property);
+    if (ssl->loglevel) printf("sqSetStringPropertySSL(%d): %s\n", propID, property);
 
 	switch(propID) {
-		case SQSSL_PROP_CERTNAME: ssl->certName = property; break;
-		default: 
-			if(ssl->loglevel) printf("sqSetStringPropertySSL: Unknown property ID %d\n", propID);
+		case SQSSL_PROP_CERTNAME:
+            if (ssl->certName) free(ssl->certName);
+            ssl->certName = property;
+            break;
+        case SQSSL_PROP_SERVERNAME:
+            if (ssl->serverName) free(ssl->serverName);
+            ssl->serverName = property;
+            break;
+        default:
+			if (ssl->loglevel) printf("sqSetStringPropertySSL: Unknown property ID %d\n", propID);
 			return 0;
 	}
 	return 1;
@@ -445,14 +491,14 @@
 int sqGetIntPropertySSL(sqInt handle, int propID) {
 	sqSSL *ssl = sslFromHandle(handle);
 
-	if(ssl == NULL) return 0;
+	if (ssl == NULL) return 0;
 	switch(propID) {
 		case SQSSL_PROP_SSLSTATE: return ssl->state;
 		case SQSSL_PROP_CERTSTATE: return ssl->certFlags;
 		case SQSSL_PROP_VERSION: return 1;
 		case SQSSL_PROP_LOGLEVEL: return ssl->loglevel;
 		default:
-			if(ssl->loglevel) printf("sqGetIntPropertySSL: Unknown property ID %d\n", propID);
+			if (ssl->loglevel) printf("sqGetIntPropertySSL: Unknown property ID %d\n", propID);
 			return 0;
 	}
 	return 0;
@@ -467,12 +513,12 @@
 */
 sqInt sqSetIntPropertySSL(sqInt handle, sqInt propID, sqInt propValue) {
 	sqSSL *ssl = sslFromHandle(handle);
-	if(ssl == NULL) return 0;
+	if (ssl == NULL) return 0;
 
 	switch(propID) {
 		case SQSSL_PROP_LOGLEVEL: ssl->loglevel = propValue; break;
 		default:
-			if(ssl->loglevel) printf("sqSetIntPropertySSL: Unknown property ID %d\n", propID);
+			if (ssl->loglevel) printf("sqSetIntPropertySSL: Unknown property ID %d\n", propID);
 			return 0;
 	}
 	return 1;
