[Vm-dev] [commit][2709] add plugin support code
commits at squeakvm.org
commits at squeakvm.org
Fri Mar 22 14:14:27 UTC 2013
Revision: 2709
Author: piumarta
Date: 2013-03-22 07:14:27 -0700 (Fri, 22 Mar 2013)
Log Message:
-----------
add plugin support code
Added Paths:
-----------
trunk/platforms/unix/plugins/SqueakSSL/
trunk/platforms/unix/plugins/SqueakSSL/config.cmake
trunk/platforms/unix/plugins/SqueakSSL/sqUnixOpenSSL.c
Added: trunk/platforms/unix/plugins/SqueakSSL/config.cmake
===================================================================
--- trunk/platforms/unix/plugins/SqueakSSL/config.cmake (rev 0)
+++ trunk/platforms/unix/plugins/SqueakSSL/config.cmake 2013-03-22 14:14:27 UTC (rev 2709)
@@ -0,0 +1 @@
+PLUGIN_REQUIRE_PACKAGE (OPENSSL openssl)
Added: trunk/platforms/unix/plugins/SqueakSSL/sqUnixOpenSSL.c
===================================================================
--- trunk/platforms/unix/plugins/SqueakSSL/sqUnixOpenSSL.c (rev 0)
+++ trunk/platforms/unix/plugins/SqueakSSL/sqUnixOpenSSL.c 2013-03-22 14:14:27 UTC (rev 2709)
@@ -0,0 +1,443 @@
+#include "sq.h"
+#include "SqueakSSL.h"
+
+#include "openssl/ssl.h"
+#include "openssl/err.h"
+
+typedef struct sqSSL {
+ int state;
+ int certFlags;
+ int loglevel;
+
+ char *certName;
+ char *peerName;
+
+ SSL_METHOD *method;
+ SSL_CTX *ctx;
+ SSL *ssl;
+ BIO *bioRead;
+ BIO *bioWrite;
+} sqSSL;
+
+
+static sqSSL **handleBuf = NULL;
+static sqInt handleMax = 0;
+
+/********************************************************************/
+/********************************************************************/
+/********************************************************************/
+
+/* sslFromHandle: Maps a handle to an SSL */
+static sqSSL *sslFromHandle(sqInt handle) {
+ return handle < handleMax ? handleBuf[handle] : NULL;
+}
+
+/* sqCopyBioSSL: Copies data from a BIO into an out buffer */
+sqInt sqCopyBioSSL(sqSSL *ssl, BIO *bio, char *dstBuf, sqInt dstLen) {
+ int nbytes = BIO_ctrl_pending(bio);
+
+ if(ssl->loglevel) printf("sqCopyBioSSL: %d bytes pending; buffer size %d\n",
+ nbytes, dstLen);
+ if(nbytes > dstLen) return -1;
+ return BIO_read(bio, dstBuf, dstLen);
+}
+
+/* sqSetupSSL: Common SSL setup tasks */
+sqInt sqSetupSSL(sqSSL *ssl, int server) {
+
+ /* Fixme. Needs to use specified version */
+ if(ssl->loglevel) printf("sqSetupSSL: setting method\n");
+ ssl->method = SSLv23_method();
+ if(ssl->loglevel) printf("sqSetupSSL: Creating context\n");
+ ssl->ctx = SSL_CTX_new(ssl->method);
+
+ if(!ssl->ctx) ERR_print_errors_fp(stdout);
+
+ if(ssl->loglevel) printf("sqSetupSSL: setting cipher list\n");
+ SSL_CTX_set_cipher_list(ssl->ctx, "!ADH:HIGH:MEDIUM:@STRENGTH");
+
+ /* if a cert is provided, use it */
+ if(ssl->certName) {
+ if(ssl->loglevel) printf("sqSetupSSL: Using cert file %s\n", ssl->certName);
+ if(SSL_CTX_use_certificate_file(ssl->ctx, ssl->certName, SSL_FILETYPE_PEM)<=0)
+ ERR_print_errors_fp(stderr);
+
+ if(SSL_CTX_use_PrivateKey_file(ssl->ctx, ssl->certName, SSL_FILETYPE_PEM)<=0)
+ ERR_print_errors_fp(stderr);
+ }
+
+ /* Set up trusted CA */
+ if(ssl->loglevel) printf("sqSetupSSL: No root CA given; using default verify paths\n");
+ if(SSL_CTX_set_default_verify_paths(ssl->ctx) <=0)
+ ERR_print_errors_fp(stderr);
+
+ if(ssl->loglevel) printf("sqSetupSSL: Creating SSL\n");
+ ssl->ssl = SSL_new(ssl->ctx);
+ if(ssl->loglevel) printf("sqSetupSSL: setting bios\n");
+ SSL_set_bio(ssl->ssl, ssl->bioRead, ssl->bioWrite);
+ return 1;
+}
+/********************************************************************/
+/********************************************************************/
+/********************************************************************/
+
+/* sqCreateSSL: Creates a new SSL instance.
+ Arguments: None.
+ Returns: SSL handle.
+*/
+sqInt sqCreateSSL(void) {
+ sqInt handle = 0;
+ sqSSL *ssl = NULL;
+
+ SSL_library_init();
+ SSL_load_error_strings();
+
+ ssl = calloc(1, sizeof(sqSSL));
+ ssl->bioRead = BIO_new(BIO_s_mem());
+ ssl->bioWrite = BIO_new(BIO_s_mem());
+ BIO_set_close(ssl->bioRead, BIO_CLOSE);
+ BIO_set_close(ssl->bioWrite, BIO_CLOSE);
+
+ /* Find a free handle */
+ for(handle = 1; handle < handleMax; handle++)
+ if(handleBuf[handle] == NULL) break;
+
+ if(handle >= handleMax) {
+ int i, delta = 100;
+ /* Resize the handle buffer */
+ handleBuf = realloc(handleBuf, (handleMax+delta)*sizeof(void*));
+ for(i = handleMax; i < handleMax+delta; i++)
+ handleBuf[i] = NULL;
+ handleMax += delta;
+ }
+ handleBuf[handle] = ssl;
+ return handle;
+}
+
+/* sqDestroySSL: Destroys an SSL instance.
+ Arguments:
+ handle - the SSL handle
+ Returns: Non-zero if successful.
+*/
+sqInt sqDestroySSL(sqInt handle) {
+ sqSSL *ssl = sslFromHandle(handle);
+ if(ssl == NULL) return 0;
+
+ if(ssl->ctx) SSL_CTX_free(ssl->ctx);
+ if(ssl->ssl) SSL_free(ssl->ssl);
+
+ if(ssl->certName) free(ssl->certName);
+ if(ssl->peerName) free(ssl->peerName);
+
+ free(ssl);
+ handleBuf[handle] = NULL;
+ return 1;
+}
+
+/* sqConnectSSL: Start/continue an SSL client handshake.
+ Arguments:
+ handle - the SSL handle
+ srcBuf - the input token sent by the remote peer
+ srcLen - the size of the input token
+ dstBuf - the output buffer for a new token
+ dstLen - the size of the output buffer
+ Returns: The size of the output token or an error code.
+*/
+sqInt sqConnectSSL(sqInt handle, char* srcBuf, sqInt srcLen, char *dstBuf, sqInt dstLen) {
+ int result, n;
+ char peerName[256];
+ X509 *cert;
+ sqSSL *ssl = sslFromHandle(handle);
+
+ if(ssl->loglevel) printf("sqConnectSSL: %x\n", (int)ssl);
+
+ /* Verify state of session */
+ if(ssl == NULL || (ssl->state != SQSSL_UNUSED && ssl->state != SQSSL_CONNECTING)) {
+ return SQSSL_INVALID_STATE;
+ }
+
+ /* Establish initial connection */
+ if(ssl->state == SQSSL_UNUSED) {
+ ssl->state = SQSSL_CONNECTING;
+ if(ssl->loglevel) print("sqConnectSSL: Setting up SSL\n");
+ if(!sqSetupSSL(ssl, 0)) return SQSSL_GENERIC_ERROR;
+ if(ssl->loglevel) print("sqConnectSSL: Setting connect state\n");
+ SSL_set_connect_state(ssl->ssl);
+ }
+
+ if(ssl->loglevel) printf("sqConnectSSL: BIO_write %d bytes\n", srcLen);
+
+ n = BIO_write(ssl->bioRead, srcBuf, srcLen);
+
+ if(n < srcLen) {
+ if(ssl->loglevel) printf("sqConnectSSL: BIO too small for input\n");
+ return SQSSL_GENERIC_ERROR;
+ }
+ if(n < 0) {
+ if(ssl->loglevel) printf("sqConnectSSL: BIO_write failed\n");
+ return SQSSL_GENERIC_ERROR;
+ }
+ if(ssl->loglevel) printf("sqConnectSSL: SSL_connect\n");
+ result = SSL_connect(ssl->ssl);
+ if(result <= 0) {
+ int error = SSL_get_error(ssl->ssl, result);
+ if(error != SSL_ERROR_WANT_READ) {
+ if(ssl->loglevel) printf("sqConnectSSL: SSL_connect failed\n");
+ ERR_print_errors_fp(stdout);
+ return -1;
+ }
+ if(ssl->loglevel) printf("sqConnectSSL: sqCopyBioSSL\n");
+ return sqCopyBioSSL(ssl, ssl->bioWrite, dstBuf, dstLen);
+ }
+
+ /* We are connected. Verify the cert. */
+ ssl->state = SQSSL_CONNECTED;
+
+ if(ssl->loglevel) printf("sqConnectSSL: SSL_get_peer_certificate\n");
+ cert = SSL_get_peer_certificate(ssl->ssl);
+ if(ssl->loglevel) printf("sqConnectSSL: cert = %x\n", (int)cert);
+ /* Fail if no cert received. */
+ if(cert) {
+ X509_NAME_get_text_by_NID(X509_get_subject_name(cert),
+ NID_commonName, peerName,
+ sizeof(peerName));
+ if(ssl->loglevel) printf("sqConnectSSL: peerName = %s\n", peerName);
+ ssl->peerName = strdup(peerName);
+ X509_free(cert);
+
+ /* Check the result of verification */
+ result = SSL_get_verify_result(ssl->ssl);
+ if(ssl->loglevel) printf("sqConnectSSL: SSL_get_verify_result = %d\n", result);
+ /* FIXME: Figure out the actual failure reason */
+ ssl->certFlags = result ? SQSSL_OTHER_ISSUE : SQSSL_OK;
+ } else {
+ ssl->certFlags = SQSSL_NO_CERTIFICATE;
+ }
+ return 0;
+}
+
+/* sqAcceptSSL: Start/continue an SSL server handshake.
+ Arguments:
+ handle - the SSL handle
+ srcBuf - the input token sent by the remote peer
+ srcLen - the size of the input token
+ dstBuf - the output buffer for a new token
+ dstLen - the size of the output buffer
+ Returns: The size of the output token or an error code.
+*/
+sqInt sqAcceptSSL(sqInt handle, char* srcBuf, sqInt srcLen, char *dstBuf, sqInt dstLen) {
+ int result, n;
+ char peerName[256];
+ X509 *cert;
+ sqSSL *ssl = sslFromHandle(handle);
+
+ /* Verify state of session */
+ if(ssl == NULL || (ssl->state != SQSSL_UNUSED && ssl->state != SQSSL_ACCEPTING)) {
+ return SQSSL_INVALID_STATE;
+ }
+
+ /* Establish initial connection */
+ 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");
+ SSL_set_accept_state(ssl->ssl);
+ }
+
+ if(ssl->loglevel) printf("sqAcceptSSL: BIO_write %d bytes\n", srcLen);
+
+ n = BIO_write(ssl->bioRead, srcBuf, srcLen);
+
+ if(n < srcLen) {
+ if(ssl->loglevel) printf("sqAcceptSSL: BIO_write wrote less than expected\n");
+ return SQSSL_GENERIC_ERROR;
+ }
+ if(n < 0) {
+ if(ssl->loglevel) printf("sqAcceptSSL: BIO_write failed\n");
+ return SQSSL_GENERIC_ERROR;
+ }
+
+ if(ssl->loglevel) printf("sqAcceptSSL: SSL_accept\n");
+ result = SSL_accept(ssl->ssl);
+
+ if(result <= 0) {
+ int count = 0;
+ int error = SSL_get_error(ssl->ssl, result);
+ if(error != SSL_ERROR_WANT_READ) {
+ if(ssl->loglevel) printf("sqAcceptSSL: SSL_accept failed\n");
+ ERR_print_errors_fp(stdout);
+ return SQSSL_GENERIC_ERROR;
+ }
+ if(ssl->loglevel) printf("sqAcceptSSL: sqCopyBioSSL\n");
+ count = sqCopyBioSSL(ssl, ssl->bioWrite, dstBuf, dstLen);
+ return count ? count : SQSSL_NEED_MORE_DATA;
+ }
+
+ /* We are connected. Verify the cert. */
+ ssl->state = SQSSL_CONNECTED;
+
+ if(ssl->loglevel) printf("sqAcceptSSL: SSL_get_peer_certificate\n");
+ cert = SSL_get_peer_certificate(ssl->ssl);
+ if(ssl->loglevel) printf("sqAcceptSSL: cert = %x\n", (int)cert);
+
+ if(cert) {
+ X509_NAME_get_text_by_NID(X509_get_subject_name(cert),
+ NID_commonName, peerName,
+ sizeof(peerName));
+ if(ssl->loglevel) printf("sqAcceptSSL: peerName = %s\n", peerName);
+ ssl->peerName = strdup(peerName);
+ X509_free(cert);
+
+ /* Check the result of verification */
+ result = SSL_get_verify_result(ssl->ssl);
+ if(ssl->loglevel) printf("sqAcceptSSL: SSL_get_verify_result = %d\n", result);
+ /* FIXME: Figure out the actual failure reason */
+ ssl->certFlags = result ? SQSSL_OTHER_ISSUE : SQSSL_OK;
+ } else {
+ ssl->certFlags = SQSSL_NO_CERTIFICATE;
+ }
+ return sqCopyBioSSL(ssl, ssl->bioWrite, dstBuf, dstLen);
+}
+
+/* sqEncryptSSL: Encrypt data for SSL transmission.
+ Arguments:
+ handle - the SSL handle
+ srcBuf - the unencrypted input data
+ srcLen - the size of the input data
+ dstBuf - the output buffer for the encrypted contents
+ dstLen - the size of the output buffer
+ Returns: The size of the output generated or an error code.
+*/
+sqInt sqEncryptSSL(sqInt handle, char* srcBuf, sqInt srcLen, char *dstBuf, sqInt dstLen) {
+ int nbytes;
+ sqSSL *ssl = sslFromHandle(handle);
+
+ if(ssl == NULL || ssl->state != SQSSL_CONNECTED) return SQSSL_INVALID_STATE;
+
+ if(ssl->loglevel) printf("sqEncryptSSL: Encrypting %d bytes\n", srcLen);
+
+ nbytes = SSL_write(ssl->ssl, srcBuf, srcLen);
+ if(nbytes != srcLen) return SQSSL_GENERIC_ERROR;
+ return sqCopyBioSSL(ssl, ssl->bioWrite, dstBuf, dstLen);
+}
+
+/* sqDecryptSSL: Decrypt data for SSL transmission.
+ Arguments:
+ handle - the SSL handle
+ srcBuf - the encrypted input data
+ srcLen - the size of the input data
+ dstBuf - the output buffer for the decrypted contents
+ dstLen - the size of the output buffer
+ Returns: The size of the output generated or an error code.
+*/
+sqInt sqDecryptSSL(sqInt handle, char* srcBuf, sqInt srcLen, char *dstBuf, sqInt dstLen) {
+ int nbytes;
+ sqSSL *ssl = sslFromHandle(handle);
+
+ if(ssl == NULL || ssl->state != SQSSL_CONNECTED) return SQSSL_INVALID_STATE;
+
+ nbytes = BIO_write(ssl->bioRead, srcBuf, srcLen);
+ if(nbytes != srcLen) return SQSSL_GENERIC_ERROR;
+ nbytes = SSL_read(ssl->ssl, dstBuf, dstLen);
+ if(nbytes <= 0) {
+ int error = SSL_get_error(ssl->ssl, nbytes);
+ if(error != SSL_ERROR_WANT_READ && error != SSL_ERROR_ZERO_RETURN) {
+ return SQSSL_GENERIC_ERROR;
+ }
+ nbytes = 0;
+ }
+ return nbytes;
+}
+
+/* sqGetStringPropertySSL: Retrieve a string property from SSL.
+ Arguments:
+ handle - the ssl handle
+ propID - the property id to retrieve
+ Returns: The string value of the property.
+*/
+char* sqGetStringPropertySSL(sqInt handle, int propID) {
+ sqSSL *ssl = sslFromHandle(handle);
+
+ 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);
+ return NULL;
+ }
+ return NULL;
+}
+
+/* sqSetStringPropertySSL: Set a string property in SSL.
+ Arguments:
+ handle - the ssl handle
+ propID - the property id to retrieve
+ propName - the property string
+ propLen - the length of the property string
+ Returns: Non-zero if successful.
+*/
+sqInt sqSetStringPropertySSL(sqInt handle, int propID, char *propName, sqInt propLen) {
+ sqSSL *ssl = sslFromHandle(handle);
+ char *property = NULL;
+
+ if(ssl == NULL) return 0;
+
+ if(propLen) {
+ property = calloc(1, propLen+1);
+ memcpy(property, propName, propLen);
+ };
+
+ 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);
+ return 0;
+ }
+ return 1;
+}
+
+/* sqGetIntPropertySSL: Retrieve an integer property from SSL.
+ Arguments:
+ handle - the ssl handle
+ propID - the property id to retrieve
+ Returns: The integer value of the property.
+*/
+int sqGetIntPropertySSL(sqInt handle, int propID) {
+ sqSSL *ssl = sslFromHandle(handle);
+
+ 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);
+ return 0;
+ }
+ return 0;
+}
+
+/* sqSetIntPropertySSL: Set an integer property in SSL.
+ Arguments:
+ handle - the ssl handle
+ propID - the property id to retrieve
+ propValue - the property value
+ Returns: Non-zero if successful.
+*/
+sqInt sqSetIntPropertySSL(sqInt handle, sqInt propID, sqInt propValue) {
+ sqSSL *ssl = sslFromHandle(handle);
+ 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);
+ return 0;
+ }
+ return 1;
+}
More information about the Vm-dev
mailing list