Nigel Rantor / azure_c_shared_utility

Fork of azure_c_shared_utility by Azure IoT

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers tlsio_wolfssl.c Source File

tlsio_wolfssl.c

00001 // Copyright (c) Microsoft. All rights reserved.
00002 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
00003 
00004 #include <stdlib.h>
00005 #include "wolfssl/ssl.h"
00006 #include "wolfssl/error-ssl.h"
00007 #include <stdio.h>
00008 #include <stdbool.h>
00009 #include <string.h>
00010 #include "azure_c_shared_utility/tlsio.h"
00011 #include "azure_c_shared_utility/tlsio_wolfssl.h"
00012 #include "azure_c_shared_utility/socketio.h"
00013 #include "azure_c_shared_utility/crt_abstractions.h"
00014 #include "azure_c_shared_utility/optimize_size.h"
00015 #include "azure_c_shared_utility/xlogging.h"
00016 #include "azure_c_shared_utility/shared_util_options.h"
00017 
00018 typedef enum TLSIO_STATE_ENUM_TAG
00019 {
00020     TLSIO_STATE_NOT_OPEN,
00021     TLSIO_STATE_OPENING_UNDERLYING_IO,
00022     TLSIO_STATE_IN_HANDSHAKE,
00023     TLSIO_STATE_OPEN,
00024     TLSIO_STATE_CLOSING,
00025     TLSIO_STATE_ERROR
00026 } TLSIO_STATE_ENUM;
00027 
00028 typedef struct TLS_IO_INSTANCE_TAG
00029 {
00030     XIO_HANDLE socket_io;
00031     ON_BYTES_RECEIVED on_bytes_received;
00032     ON_IO_OPEN_COMPLETE on_io_open_complete;
00033     ON_IO_CLOSE_COMPLETE on_io_close_complete;
00034     ON_IO_ERROR on_io_error;
00035     void* on_bytes_received_context;
00036     void* on_io_open_complete_context;
00037     void* on_io_close_complete_context;
00038     void* on_io_error_context;
00039     WOLFSSL* ssl;
00040     WOLFSSL_CTX* ssl_context;
00041     TLSIO_STATE_ENUM tlsio_state;
00042     unsigned char* socket_io_read_bytes;
00043     size_t socket_io_read_byte_count;
00044     ON_SEND_COMPLETE on_send_complete;
00045     void* on_send_complete_callback_context;
00046     char* certificate;
00047     char* x509certificate;
00048     char* x509privatekey;
00049 } TLS_IO_INSTANCE;
00050 
00051 /*this function will clone an option given by name and value*/
00052 static void* tlsio_wolfssl_CloneOption(const char* name, const void* value)
00053 {
00054     void* result;
00055     if ((name == NULL) || (value == NULL))
00056     {
00057         LogError("invalid parameter detected: const char* name=%p, const void* value=%p", name, value);
00058         result = NULL;
00059     }
00060     else
00061     {
00062         if (strcmp(name, "TrustedCerts") == 0)
00063         {
00064             if (mallocAndStrcpy_s((char**)&result, value) != 0)
00065             {
00066                 LogError("unable to mallocAndStrcpy_s TrustedCerts value");
00067                 result = NULL;
00068             }
00069             else
00070             {
00071                 /*return as is*/
00072             }
00073         }
00074         else if (strcmp(name, SU_OPTION_X509_CERT) == 0)
00075         {
00076             if (mallocAndStrcpy_s((char**)&result, value) != 0)
00077             {
00078                 LogError("unable to mallocAndStrcpy_s x509certificate value");
00079                 result = NULL;
00080             }
00081             else
00082             {
00083                 /*return as is*/
00084             }
00085         }
00086         else if (strcmp(name, SU_OPTION_X509_PRIVATE_KEY) == 0)
00087         {
00088             if (mallocAndStrcpy_s((char**)&result, value) != 0)
00089             {
00090                 LogError("unable to mallocAndStrcpy_s x509privatekey value");
00091                 result = NULL;
00092             }
00093             else
00094             {
00095                 /*return as is*/
00096             }
00097         }
00098         else
00099         {
00100             LogError("not handled option : %s", name);
00101             result = NULL;
00102         }
00103     }
00104     return result;
00105 }
00106 
00107 /*this function destroys an option previously created*/
00108 static void tlsio_wolfssl_DestroyOption(const char* name, const void* value)
00109 {
00110     /*since all options for this layer are actually string copies., disposing of one is just calling free*/
00111     if ((name == NULL) || (value == NULL))
00112     {
00113         LogError("invalid parameter detected: const char* name=%p, const void* value=%p", name, value);
00114     }
00115     else
00116     {
00117         if ((strcmp(name, "TrustedCerts") == 0) ||
00118             (strcmp(name, SU_OPTION_X509_CERT) == 0) ||
00119             (strcmp(name, SU_OPTION_X509_PRIVATE_KEY) == 0))
00120         {
00121             free((void*)value);
00122         }
00123         else
00124         {
00125             LogError("not handled option : %s", name);
00126         }
00127     }
00128 }
00129 
00130 static OPTIONHANDLER_HANDLE tlsio_wolfssl_retrieveoptions(CONCRETE_IO_HANDLE tls_io)
00131 {
00132     OPTIONHANDLER_HANDLE result;
00133     if (tls_io == NULL)
00134     {
00135         LogError("NULL tls_io parameter");
00136         result = NULL;
00137     }
00138     else
00139     {
00140         result = OptionHandler_Create(tlsio_wolfssl_CloneOption, tlsio_wolfssl_DestroyOption, tlsio_wolfssl_setoption);
00141         if (result == NULL)
00142         {
00143             LogError("unable to OptionHandler_Create");
00144             /*return as is*/
00145         }
00146         else
00147         {
00148             /*this layer cares about the certificates and the x509 credentials*/
00149             TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)tls_io;
00150             if (
00151                 (tls_io_instance->x509certificate != NULL) &&
00152                 (OptionHandler_AddOption(result, SU_OPTION_X509_CERT, tls_io_instance->x509certificate) != 0)
00153                 )
00154             {
00155                 LogError("unable to save x509certificate option");
00156                 OptionHandler_Destroy(result);
00157                 result = NULL;
00158             }
00159             else if (
00160                 (tls_io_instance->x509privatekey != NULL) &&
00161                 (OptionHandler_AddOption(result, SU_OPTION_X509_PRIVATE_KEY, tls_io_instance->x509privatekey) != 0)
00162                 )
00163             {
00164                 LogError("unable to save x509privatekey option");
00165                 OptionHandler_Destroy(result);
00166                 result = NULL;
00167             }
00168             else if (
00169                 (tls_io_instance->certificate != NULL) &&
00170                 (OptionHandler_AddOption(result, "TrustedCerts", tls_io_instance->certificate) != 0)
00171                 )
00172             {
00173                 LogError("unable to save TrustedCerts option");
00174                 OptionHandler_Destroy(result);
00175                 result = NULL;
00176             }
00177             else
00178             {
00179                 /*all is fine, all interesting options have been saved*/
00180                 /*return as is*/
00181             }
00182         }
00183     }
00184 
00185     return result;
00186 }
00187 
00188 static const IO_INTERFACE_DESCRIPTION tlsio_wolfssl_interface_description =
00189 {
00190     tlsio_wolfssl_retrieveoptions,
00191     tlsio_wolfssl_create,
00192     tlsio_wolfssl_destroy,
00193     tlsio_wolfssl_open,
00194     tlsio_wolfssl_close,
00195     tlsio_wolfssl_send,
00196     tlsio_wolfssl_dowork,
00197     tlsio_wolfssl_setoption
00198 };
00199 
00200 static void indicate_error(TLS_IO_INSTANCE* tls_io_instance)
00201 {
00202     if (tls_io_instance->on_io_error != NULL)
00203     {
00204         tls_io_instance->on_io_error(tls_io_instance->on_io_error_context);
00205     }
00206 }
00207 
00208 static void indicate_open_complete(TLS_IO_INSTANCE* tls_io_instance, IO_OPEN_RESULT open_result)
00209 {
00210     if (tls_io_instance->on_io_open_complete != NULL)
00211     {
00212         tls_io_instance->on_io_open_complete(tls_io_instance->on_io_open_complete_context, open_result);
00213     }
00214 }
00215 
00216 static int decode_ssl_received_bytes(TLS_IO_INSTANCE* tls_io_instance)
00217 {
00218     int result = 0;
00219     unsigned char buffer[64];
00220 
00221     int rcv_bytes = 1;
00222     while (rcv_bytes > 0)
00223     {
00224         rcv_bytes = wolfSSL_read(tls_io_instance->ssl, buffer, sizeof(buffer));
00225         if (rcv_bytes > 0)
00226         {
00227             if (tls_io_instance->on_bytes_received != NULL)
00228             {
00229                 tls_io_instance->on_bytes_received(tls_io_instance->on_bytes_received_context, buffer, rcv_bytes);
00230             }
00231         }
00232     }
00233 
00234     return result;
00235 }
00236 
00237 static void on_underlying_io_open_complete(void* context, IO_OPEN_RESULT open_result)
00238 {
00239     TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)context;
00240 
00241     if (open_result != IO_OPEN_OK)
00242     {
00243         LogError("Underlying IO open failed");
00244         tls_io_instance->tlsio_state = TLSIO_STATE_ERROR;
00245         indicate_open_complete(tls_io_instance, IO_OPEN_ERROR);
00246     }
00247     else
00248     {
00249         int res;
00250         tls_io_instance->tlsio_state = TLSIO_STATE_IN_HANDSHAKE;
00251 
00252         res = wolfSSL_connect(tls_io_instance->ssl);
00253         if (res != SSL_SUCCESS)
00254         {
00255             LogError("WolfSSL connect failed");
00256             indicate_open_complete(tls_io_instance, IO_OPEN_ERROR);
00257             tls_io_instance->tlsio_state = TLSIO_STATE_ERROR;
00258         }
00259     }
00260 }
00261 
00262 static void on_underlying_io_bytes_received(void* context, const unsigned char* buffer, size_t size)
00263 {
00264     TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)context;
00265 
00266     unsigned char* new_socket_io_read_bytes = (unsigned char*)realloc(tls_io_instance->socket_io_read_bytes, tls_io_instance->socket_io_read_byte_count + size);
00267     if (new_socket_io_read_bytes == NULL)
00268     {
00269         LogError("Failed allocating memory for received bytes");
00270         tls_io_instance->tlsio_state = TLSIO_STATE_ERROR;
00271         indicate_error(tls_io_instance);
00272     }
00273     else
00274     {
00275         tls_io_instance->socket_io_read_bytes = new_socket_io_read_bytes;
00276         (void)memcpy(tls_io_instance->socket_io_read_bytes + tls_io_instance->socket_io_read_byte_count, buffer, size);
00277         tls_io_instance->socket_io_read_byte_count += size;
00278     }
00279 }
00280 
00281 static void on_underlying_io_error(void* context)
00282 {
00283     TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)context;
00284 
00285     switch (tls_io_instance->tlsio_state)
00286     {
00287     default:
00288         LogError("Unknown TLS IO WolfSSL state: %d", (int)tls_io_instance->tlsio_state);
00289         break;
00290 
00291     case TLSIO_STATE_NOT_OPEN:
00292     case TLSIO_STATE_ERROR:
00293         break;
00294 
00295     case TLSIO_STATE_OPENING_UNDERLYING_IO:
00296     case TLSIO_STATE_IN_HANDSHAKE:
00297         tls_io_instance->tlsio_state = TLSIO_STATE_ERROR;
00298         indicate_open_complete(tls_io_instance, IO_OPEN_ERROR);
00299         break;
00300 
00301     case TLSIO_STATE_OPEN:
00302         tls_io_instance->tlsio_state = TLSIO_STATE_ERROR;
00303         indicate_error(tls_io_instance);
00304         break;
00305     }
00306 }
00307 
00308 static void on_underlying_io_close_complete(void* context)
00309 {
00310     TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)context;
00311 
00312     if (tls_io_instance->tlsio_state != TLSIO_STATE_CLOSING)
00313     {
00314         LogError("on_underlying_io_close_complete called when not in CLOSING state");
00315     }
00316     else
00317     {
00318         if (tls_io_instance->on_io_close_complete != NULL)
00319         {
00320             tls_io_instance->on_io_close_complete(tls_io_instance->on_io_close_complete_context);
00321         }
00322         tls_io_instance->tlsio_state = TLSIO_STATE_NOT_OPEN;
00323     }
00324 }
00325 
00326 static int on_io_recv(WOLFSSL *ssl, char *buf, int sz, void *context)
00327 {
00328     int result;
00329     TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)context;
00330     unsigned char* new_socket_io_read_bytes;
00331 
00332     (void)ssl;
00333     while (tls_io_instance->socket_io_read_byte_count == 0)
00334     {
00335         xio_dowork(tls_io_instance->socket_io);
00336         if (tls_io_instance->tlsio_state != TLSIO_STATE_IN_HANDSHAKE)
00337         {
00338             break;
00339         }
00340     }
00341 
00342     result = tls_io_instance->socket_io_read_byte_count;
00343     if (result > sz)
00344     {
00345         result = sz;
00346     }
00347 
00348     if (result > 0)
00349     {
00350         (void)memcpy(buf, tls_io_instance->socket_io_read_bytes, result);
00351         (void)memmove(tls_io_instance->socket_io_read_bytes, tls_io_instance->socket_io_read_bytes + result, tls_io_instance->socket_io_read_byte_count - result);
00352         tls_io_instance->socket_io_read_byte_count -= result;
00353         if (tls_io_instance->socket_io_read_byte_count > 0)
00354         {
00355             new_socket_io_read_bytes = (unsigned char*)realloc(tls_io_instance->socket_io_read_bytes, tls_io_instance->socket_io_read_byte_count);
00356             if (new_socket_io_read_bytes != NULL)
00357             {
00358                 tls_io_instance->socket_io_read_bytes = new_socket_io_read_bytes;
00359             }
00360         }
00361         else
00362         {
00363             free(tls_io_instance->socket_io_read_bytes);
00364             tls_io_instance->socket_io_read_bytes = NULL;
00365         }
00366     }
00367 
00368     if ((result == 0) && (tls_io_instance->tlsio_state == TLSIO_STATE_OPEN))
00369     {
00370         result = WOLFSSL_CBIO_ERR_WANT_READ;
00371     }
00372     else if ((result == 0) && tls_io_instance->tlsio_state == TLSIO_STATE_CLOSING)
00373     {
00374         result = WOLFSSL_CBIO_ERR_CONN_CLOSE;
00375     }
00376 
00377     return result;
00378 }
00379 
00380 static int on_io_send(WOLFSSL *ssl, char *buf, int sz, void *context)
00381 {
00382     int result;
00383     TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)context;
00384 
00385     (void)ssl;
00386     if (xio_send(tls_io_instance->socket_io, buf, sz, tls_io_instance->on_send_complete, tls_io_instance->on_send_complete_callback_context) != 0)
00387     {
00388         LogError("Failed sending bytes through underlying IO");
00389         tls_io_instance->tlsio_state = TLSIO_STATE_ERROR;
00390         indicate_error(tls_io_instance);
00391         result = 0;
00392     }
00393     else
00394     {
00395         result = sz;
00396     }
00397 
00398     return result;
00399 }
00400 
00401 static int on_handshake_done(WOLFSSL* ssl, void* context)
00402 {
00403     TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)context;
00404     (void)ssl;
00405     if (tls_io_instance->tlsio_state != TLSIO_STATE_IN_HANDSHAKE)
00406     {
00407         LogInfo("on_handshake_done called when not in IN_HANDSHAKE state");
00408     }
00409     else
00410     {
00411         tls_io_instance->tlsio_state = TLSIO_STATE_OPEN;
00412         indicate_open_complete(tls_io_instance, IO_OPEN_OK);
00413     }
00414 
00415     return 0;
00416 }
00417 
00418 static int add_certificate_to_store(TLS_IO_INSTANCE* tls_io_instance)
00419 {
00420     int result;
00421     if (tls_io_instance->certificate != NULL)
00422     {
00423         int res = wolfSSL_CTX_load_verify_buffer(tls_io_instance->ssl_context, (const unsigned char*)tls_io_instance->certificate, strlen(tls_io_instance->certificate), SSL_FILETYPE_PEM);
00424         if (res != SSL_SUCCESS)
00425         {
00426             LogError("wolfSSL_CTX_load_verify_buffer failed");
00427             result = __FAILURE__;
00428         }
00429         else
00430         {
00431             result = 0;
00432         }
00433     }
00434     else
00435     {
00436         result = 0;
00437     }
00438     return result;
00439 }
00440 
00441 static int x509_wolfssl_add_credentials(WOLFSSL* ssl, char* x509certificate, char* x509privatekey) {
00442 
00443     int result;
00444 
00445     if (wolfSSL_use_certificate_chain_buffer(ssl, (unsigned char*)x509certificate, strlen(x509certificate)) != SSL_SUCCESS)
00446     {
00447         LogError("unable to load x509 client certificate");
00448         result = __FAILURE__;
00449     }
00450     else if (wolfSSL_use_PrivateKey_buffer(ssl, (unsigned char*)x509privatekey, strlen(x509privatekey), SSL_FILETYPE_PEM) != SSL_SUCCESS)
00451     {
00452         LogError("unable to load x509 client private key");
00453         result = __FAILURE__;
00454     }
00455 #ifdef HAVE_SECURE_RENEGOTIATION
00456     else if (wolfSSL_UseSecureRenegotiation(ssl) != SSL_SUCCESS)
00457     {
00458         LogError("unable to enable secure renegotiation");
00459         result = __FAILURE__;
00460     }
00461 #endif 
00462     else
00463     {
00464         result = 0;
00465     }
00466     return result;
00467 }
00468 
00469 static void destroy_wolfssl_instance(TLS_IO_INSTANCE* tls_io_instance)
00470 {
00471     wolfSSL_free(tls_io_instance->ssl);
00472 }
00473 
00474 static int create_wolfssl_instance(TLS_IO_INSTANCE* tls_io_instance)
00475 {
00476     int result;
00477 
00478     if (add_certificate_to_store(tls_io_instance) != 0)
00479     {
00480         LogError("Failed to add certificates to store");
00481         result = __FAILURE__;
00482     }
00483     else
00484     {
00485         tls_io_instance->ssl = wolfSSL_new(tls_io_instance->ssl_context);
00486         if (tls_io_instance->ssl == NULL)
00487         {
00488             LogError("Failed to add certificates to store");
00489             result = __FAILURE__;
00490         }
00491         /*x509 authentication can only be build before underlying connection is realized*/
00492         else if ((tls_io_instance->x509certificate != NULL) &&
00493             (tls_io_instance->x509privatekey != NULL) &&
00494             (x509_wolfssl_add_credentials(tls_io_instance->ssl, tls_io_instance->x509certificate, tls_io_instance->x509privatekey) != 0))
00495         {
00496             destroy_wolfssl_instance(tls_io_instance);
00497             LogError("unable to use x509 authentication");
00498             result = __FAILURE__;
00499         }
00500         else
00501         {
00502             tls_io_instance->socket_io_read_bytes = NULL;
00503             tls_io_instance->socket_io_read_byte_count = 0;
00504             tls_io_instance->on_send_complete = NULL;
00505             tls_io_instance->on_send_complete_callback_context = NULL;
00506 
00507             wolfSSL_set_using_nonblock(tls_io_instance->ssl, 1);
00508             wolfSSL_SetIOSend(tls_io_instance->ssl_context, on_io_send);
00509             wolfSSL_SetIORecv(tls_io_instance->ssl_context, on_io_recv);
00510             wolfSSL_SetHsDoneCb(tls_io_instance->ssl, on_handshake_done, tls_io_instance);
00511             wolfSSL_SetIOWriteCtx(tls_io_instance->ssl, tls_io_instance);
00512             wolfSSL_SetIOReadCtx(tls_io_instance->ssl, tls_io_instance);
00513 
00514             tls_io_instance->tlsio_state = TLSIO_STATE_NOT_OPEN;
00515             result = 0;
00516         }
00517     }
00518 
00519     return result;
00520 }
00521 
00522 int tlsio_wolfssl_init(void)
00523 {
00524     (void)wolfSSL_library_init();
00525     wolfSSL_load_error_strings();
00526 
00527     return 0;
00528 }
00529 
00530 void tlsio_wolfssl_deinit(void)
00531 {
00532 }
00533  
00534 CONCRETE_IO_HANDLE tlsio_wolfssl_create(void* io_create_parameters)
00535 {
00536     TLS_IO_INSTANCE* result;
00537 
00538     if (io_create_parameters == NULL)
00539     {
00540         LogError("NULL io_create_parameters");
00541         result = NULL;
00542     }
00543     else
00544     {
00545         TLSIO_CONFIG* tls_io_config = io_create_parameters;
00546 
00547         result = (TLS_IO_INSTANCE*)malloc(sizeof(TLS_IO_INSTANCE));
00548         if (result == NULL)
00549         {
00550             LogError("Failed allocating memory for the TLS IO instance.");
00551         }
00552         else
00553         {
00554             (void)memset(result, 0, sizeof(TLS_IO_INSTANCE));
00555 
00556             result->socket_io_read_bytes = 0;
00557             result->socket_io_read_byte_count = 0;
00558             result->socket_io = NULL;
00559 
00560             result->ssl = NULL;
00561             result->certificate = NULL;
00562             result->x509certificate = NULL;
00563             result->x509privatekey = NULL;
00564 
00565             result->on_bytes_received = NULL;
00566             result->on_bytes_received_context = NULL;
00567 
00568             result->on_io_open_complete = NULL;
00569             result->on_io_open_complete_context = NULL;
00570 
00571             result->on_io_close_complete = NULL;
00572             result->on_io_close_complete_context = NULL;
00573 
00574             result->on_io_error = NULL;
00575             result->on_io_error_context = NULL;
00576 
00577             result->tlsio_state = TLSIO_STATE_NOT_OPEN;
00578 
00579             result->ssl_context = wolfSSL_CTX_new(wolfTLSv1_2_client_method());
00580             if (result->ssl_context == NULL)
00581             {
00582                 LogError("Cannot create the wolfSSL context");
00583                 free(result);
00584                 result = NULL;
00585             }
00586             else
00587             {
00588                 const IO_INTERFACE_DESCRIPTION* underlying_io_interface;
00589                 void* io_interface_parameters;
00590 
00591                 if (tls_io_config->underlying_io_interface != NULL)
00592                 {
00593                     underlying_io_interface = tls_io_config->underlying_io_interface;
00594                     io_interface_parameters = tls_io_config->underlying_io_parameters;
00595                 }
00596                 else
00597                 {
00598                     SOCKETIO_CONFIG socketio_config;
00599 
00600                     socketio_config.hostname = tls_io_config->hostname;
00601                     socketio_config.port = tls_io_config->port;
00602                     socketio_config.accepted_socket = NULL;
00603 
00604                     underlying_io_interface = socketio_get_interface_description();
00605                     io_interface_parameters = &socketio_config;
00606                 }
00607 
00608                 if (underlying_io_interface == NULL)
00609                 {
00610                     LogError("Failed getting socket IO interface description.");
00611                     wolfSSL_CTX_free(result->ssl_context);
00612                     free(result);
00613                     result = NULL;
00614                 }
00615                 else
00616                 {
00617                     result->socket_io = xio_create(underlying_io_interface, io_interface_parameters);
00618                     if (result->socket_io == NULL)
00619                     {
00620                         LogError("Failure connecting to underlying socket_io");
00621                         wolfSSL_CTX_free(result->ssl_context);
00622                         free(result);
00623                         result = NULL;
00624                     }
00625                 }
00626             }
00627         }
00628     }
00629 
00630     return result;
00631 }
00632 
00633 void tlsio_wolfssl_destroy(CONCRETE_IO_HANDLE tls_io)
00634 {
00635     if (tls_io != NULL)
00636     {
00637         TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)tls_io;
00638         if (tls_io_instance->socket_io_read_bytes != NULL)
00639         {
00640             free(tls_io_instance->socket_io_read_bytes);
00641         }
00642 
00643         if (tls_io_instance->certificate != NULL)
00644         {
00645             free(tls_io_instance->certificate);
00646         }
00647         if (tls_io_instance->x509certificate != NULL)
00648         {
00649             free(tls_io_instance->x509certificate);
00650         }
00651         if (tls_io_instance->x509privatekey != NULL)
00652         {
00653             free(tls_io_instance->x509privatekey);
00654         }
00655 
00656         wolfSSL_CTX_free(tls_io_instance->ssl_context);
00657         xio_destroy(tls_io_instance->socket_io);
00658         free(tls_io);
00659     }
00660 }
00661 
00662 int tlsio_wolfssl_open(CONCRETE_IO_HANDLE tls_io, ON_IO_OPEN_COMPLETE on_io_open_complete, void* on_io_open_complete_context, ON_BYTES_RECEIVED on_bytes_received, void* on_bytes_received_context, ON_IO_ERROR on_io_error, void* on_io_error_context)
00663 {
00664     int result;
00665 
00666     if (tls_io == NULL)
00667     {
00668         LogError("NULL tls_io instance");
00669         result = __FAILURE__;
00670     }
00671     else
00672     {
00673         TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)tls_io;
00674 
00675         if (tls_io_instance->tlsio_state != TLSIO_STATE_NOT_OPEN)
00676         {
00677             LogError("Invalid state encountered.");
00678             result = __FAILURE__;
00679         }
00680         else
00681         {
00682             tls_io_instance->on_bytes_received = on_bytes_received;
00683             tls_io_instance->on_bytes_received_context = on_bytes_received_context;
00684 
00685             tls_io_instance->on_io_open_complete = on_io_open_complete;
00686             tls_io_instance->on_io_open_complete_context = on_io_open_complete_context;
00687 
00688             tls_io_instance->on_io_error = on_io_error;
00689             tls_io_instance->on_io_error_context = on_io_error_context;
00690 
00691             tls_io_instance->tlsio_state = TLSIO_STATE_OPENING_UNDERLYING_IO;
00692 
00693             if (create_wolfssl_instance(tls_io_instance) != 0)
00694             {
00695                 LogError("Cannot create wolfssl instance.");
00696                 tls_io_instance->tlsio_state = TLSIO_STATE_NOT_OPEN;
00697                 result = __FAILURE__;
00698             }
00699             else if (xio_open(tls_io_instance->socket_io, on_underlying_io_open_complete, tls_io_instance, on_underlying_io_bytes_received, tls_io_instance, on_underlying_io_error, tls_io_instance) != 0)
00700             {
00701                 LogError("Cannot open the underlying IO.");
00702                 tls_io_instance->tlsio_state = TLSIO_STATE_NOT_OPEN;
00703                 result = __FAILURE__;
00704             }
00705             else
00706             {
00707                 // The state can get changed in the on_underlying_io_open_complete
00708                 if (tls_io_instance->tlsio_state != TLSIO_STATE_OPEN)
00709                 {
00710                     LogError("Failed to connect to server.  The certificates may not be correct.");
00711                     result = __FAILURE__;
00712                 }
00713                 else
00714                 {
00715                     result = 0;
00716                 }
00717             }
00718         }
00719     }
00720 
00721     return result;
00722 }
00723 
00724 int tlsio_wolfssl_close(CONCRETE_IO_HANDLE tls_io, ON_IO_CLOSE_COMPLETE on_io_close_complete, void* callback_context)
00725 {
00726     int result = 0;
00727 
00728     if (tls_io == NULL)
00729     {
00730         LogError("NULL tls_io handle.");
00731         result = __FAILURE__;
00732     }
00733     else
00734     {
00735         TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)tls_io;
00736 
00737         if ((tls_io_instance->tlsio_state == TLSIO_STATE_NOT_OPEN) ||
00738             (tls_io_instance->tlsio_state == TLSIO_STATE_CLOSING))
00739         {
00740             LogError("Close called while not open.");
00741             result = __FAILURE__;
00742         }
00743         else
00744         {
00745             tls_io_instance->tlsio_state = TLSIO_STATE_CLOSING;
00746             tls_io_instance->on_io_close_complete = on_io_close_complete;
00747             tls_io_instance->on_io_close_complete_context = callback_context;
00748 
00749             if (xio_close(tls_io_instance->socket_io, on_underlying_io_close_complete, tls_io_instance) != 0)
00750             {
00751                 LogError("xio_close failed.");
00752                 result = __FAILURE__;
00753             }
00754             else
00755             {
00756                 destroy_wolfssl_instance(tls_io_instance);
00757                 result = 0;
00758             }
00759         }
00760     }
00761 
00762     return result;
00763 }
00764 
00765 int tlsio_wolfssl_send(CONCRETE_IO_HANDLE tls_io, const void* buffer, size_t size, ON_SEND_COMPLETE on_send_complete, void* callback_context)
00766 {
00767     int result;
00768 
00769     if (tls_io == NULL)
00770     {
00771         LogError("NULL tls_io handle");
00772         result = __FAILURE__;
00773     }
00774     else
00775     {
00776         TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)tls_io;
00777 
00778         if (tls_io_instance->tlsio_state != TLSIO_STATE_OPEN)
00779         {
00780             LogError("send called while not open");
00781             result = __FAILURE__;
00782         }
00783         else
00784         {
00785             tls_io_instance->on_send_complete = on_send_complete;
00786             tls_io_instance->on_send_complete_callback_context = callback_context;
00787 
00788             int res = wolfSSL_write(tls_io_instance->ssl, buffer, size);
00789             if ((res < 0) || ((size_t)res != size)) // Best way I can think of to safely compare an int to a size_t
00790             {
00791                 LogError("Error writing data through WolfSSL");
00792                 result = __FAILURE__;
00793             }
00794             else
00795             {
00796                 result = 0;
00797             }
00798         }
00799     }
00800 
00801     return result;
00802 }
00803 
00804 void tlsio_wolfssl_dowork(CONCRETE_IO_HANDLE tls_io)
00805 {
00806     if (tls_io == NULL)
00807     {
00808         LogError("NULL tls_io");
00809     }
00810     else
00811     {
00812         TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)tls_io;
00813 
00814         if ((tls_io_instance->tlsio_state != TLSIO_STATE_NOT_OPEN) &&
00815             (tls_io_instance->tlsio_state != TLSIO_STATE_ERROR))
00816         {
00817             decode_ssl_received_bytes(tls_io_instance);
00818             xio_dowork(tls_io_instance->socket_io);
00819         }
00820     }
00821 }
00822 
00823 const IO_INTERFACE_DESCRIPTION* tlsio_wolfssl_get_interface_description(void)
00824 {
00825     return &tlsio_wolfssl_interface_description;
00826 }
00827 
00828 static int process_option(char** destination, const char* name, const char* value)
00829 {
00830     int result;
00831     if (*destination != NULL)
00832     {
00833         free(*destination);
00834         *destination = NULL;
00835     }
00836     if (mallocAndStrcpy_s(destination, value) != 0)
00837     {
00838         LogError("unable to process option %s",name);
00839         result = __FAILURE__;
00840     }
00841     else
00842     {
00843         result = 0;
00844     }
00845     return result;
00846 }
00847 
00848 int tlsio_wolfssl_setoption(CONCRETE_IO_HANDLE tls_io, const char* optionName, const void* value)
00849 {
00850     int result;
00851 
00852     if (tls_io == NULL || optionName == NULL)
00853     {
00854         LogError("Bad arguments, tls_io = %p, optionName = %p", tls_io, optionName);
00855         result = __FAILURE__;
00856     }
00857     else
00858     {
00859         TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)tls_io;
00860 
00861         if (strcmp("TrustedCerts", optionName) == 0)
00862         {
00863             result  = process_option(&tls_io_instance->certificate, optionName, value);
00864         }
00865         else if (strcmp(SU_OPTION_X509_CERT, optionName) == 0)
00866         {
00867             result = process_option(&tls_io_instance->x509certificate, optionName, value);
00868         }
00869         else if (strcmp(SU_OPTION_X509_PRIVATE_KEY, optionName) == 0)
00870         {
00871             result = process_option(&tls_io_instance->x509privatekey, optionName, value);
00872         }
00873         else
00874         {
00875             if (tls_io_instance->socket_io == NULL)
00876             {
00877                 LogError("NULL underlying IO handle");
00878                 result = __FAILURE__;
00879             }
00880             else
00881             {
00882                 result = xio_setoption(tls_io_instance->socket_io, optionName, value);
00883             }
00884         }
00885     }
00886 
00887     return result;
00888 }