From 15423428edff9cc7efbc5a09e753c54f1f90e793 Mon Sep 17 00:00:00 2001 From: toddouska Date: Mon, 20 Mar 2017 15:08:34 -0700 Subject: [PATCH 1/2] add wolfSSL_write_dup(), creates write_only WOLFSSL to allow concurrent access --- configure.ac | 14 ++ examples/echoserver/echoserver.c | 22 +++- src/internal.c | 190 +++++++++++++++++---------- src/ssl.c | 212 ++++++++++++++++++++++++++++++- wolfssl/error-ssl.h | 2 + wolfssl/internal.h | 25 +++- wolfssl/ssl.h | 1 + wolfssl/wolfcrypt/settings.h | 6 + wolfssl/wolfcrypt/types.h | 3 +- 9 files changed, 400 insertions(+), 75 deletions(-) diff --git a/configure.ac b/configure.ac index 12e6fed6f..56a163324 100644 --- a/configure.ac +++ b/configure.ac @@ -476,6 +476,19 @@ then fi +# Write duplicate WOLFSSL object +AC_ARG_ENABLE([writedup], + [ --enable-writedup Enable write duplication of WOLFSSL objects (default: disabled)], + [ ENABLED_WRITEDUP=$enableval ], + [ ENABLED_WRITEDUP=no ] + ) + +if test "$ENABLED_WRITEDUP" = "yes" +then + AM_CFLAGS="$AM_CFLAGS -DHAVE_WRITE_DUP" +fi + + # Atomic User Record Layer AC_ARG_ENABLE([atomicuser], [ --enable-atomicuser Enable Atomic User Record Layer (default: disabled)], @@ -3480,6 +3493,7 @@ echo " * Async Crypto: $ENABLED_ASYNCCRYPT" echo " * Cavium: $ENABLED_CAVIUM" echo " * ARM ASM: $ENABLED_ARMASM" echo " * AES Key Wrap: $ENABLED_AESKEYWRAP" +echo " * Write duplicate: $ENABLED_WRITEDUP" echo "" echo "---" diff --git a/examples/echoserver/echoserver.c b/examples/echoserver/echoserver.c index 432525806..4aef80a76 100644 --- a/examples/echoserver/echoserver.c +++ b/examples/echoserver/echoserver.c @@ -241,7 +241,8 @@ THREAD_RETURN CYASSL_THREAD echoserver_test(void* args) SignalReady(args, port); while (!shutDown) { - CYASSL* ssl = 0; + CYASSL* ssl = NULL; + CYASSL* write_ssl = NULL; /* may have separate w/ HAVE_WRITE_DUP */ char command[SVR_COMMAND_SIZE+1]; int echoSz = 0; int clientfd; @@ -308,6 +309,18 @@ THREAD_RETURN CYASSL_THREAD echoserver_test(void* args) showPeer(ssl); #endif +#ifdef HAVE_WRITE_DUP + write_ssl = wolfSSL_write_dup(ssl); + if (write_ssl == NULL) { + printf("wolfSSL_write_dup failed\n"); + CyaSSL_free(ssl); + CloseSocket(clientfd); + continue; + } +#else + write_ssl = ssl; +#endif + while ( (echoSz = CyaSSL_read(ssl, command, sizeof(command)-1)) > 0) { if (firstRead == 1) { @@ -354,7 +367,7 @@ THREAD_RETURN CYASSL_THREAD echoserver_test(void* args) strncpy(&command[echoSz], footer, sizeof(footer)); echoSz += (int)sizeof(footer); - if (CyaSSL_write(ssl, command, echoSz) != echoSz) + if (CyaSSL_write(write_ssl, command, echoSz) != echoSz) err_sys("SSL_write failed"); break; } @@ -364,11 +377,14 @@ THREAD_RETURN CYASSL_THREAD echoserver_test(void* args) fputs(command, fout); #endif - if (CyaSSL_write(ssl, command, echoSz) != echoSz) + if (CyaSSL_write(write_ssl, command, echoSz) != echoSz) err_sys("SSL_write failed"); } #ifndef CYASSL_DTLS CyaSSL_shutdown(ssl); +#endif +#ifdef HAVE_WRITE_DUP + CyaSSL_free(write_ssl); #endif CyaSSL_free(ssl); CloseSocket(clientfd); diff --git a/src/internal.c b/src/internal.c index 6e0275f73..8e3e81cb5 100644 --- a/src/internal.c +++ b/src/internal.c @@ -3187,8 +3187,14 @@ int DhAgree(WOLFSSL* ssl, /* This function inherits a WOLFSSL_CTX's fields into an SSL object. It is used during initialization and to switch an ssl's CTX with wolfSSL_Set_SSL_CTX. Requires ssl->suites alloc and ssl-arrays with PSK + unless writeDup is on. + + ssl object to initialize + ctx parent factory + writeDup flag indicating this is a write dup only + SSL_SUCCESS return value on success */ -int SetSSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx) +int SetSSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup) { byte havePSK = 0; byte haveAnon = 0; @@ -3196,13 +3202,16 @@ int SetSSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx) byte haveRSA = 0; (void) haveAnon; /* Squash unused var warnings */ - if(!ssl || !ctx || ssl->suites == NULL) + if (!ssl || !ctx) + return BAD_FUNC_ARG; + + if (ssl->suites == NULL && !writeDup) return BAD_FUNC_ARG; newSSL = ssl->ctx == NULL; /* Assign after null check */ #ifndef NO_PSK - if (ctx->server_hint[0] && ssl->arrays == NULL) { + if (ctx->server_hint[0] && ssl->arrays == NULL && !writeDup) { return BAD_FUNC_ARG; /* needed for copy below */ } #endif @@ -3307,41 +3316,45 @@ int SetSSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx) ssl->devId = ctx->devId; #endif + if (writeDup == 0) { + #ifndef NO_PSK - if (ctx->server_hint[0]) { /* set in CTX */ - XSTRNCPY(ssl->arrays->server_hint, ctx->server_hint, MAX_PSK_ID_LEN); - ssl->arrays->server_hint[MAX_PSK_ID_LEN - 1] = '\0'; - } + if (ctx->server_hint[0]) { /* set in CTX */ + XSTRNCPY(ssl->arrays->server_hint, ctx->server_hint,MAX_PSK_ID_LEN); + ssl->arrays->server_hint[MAX_PSK_ID_LEN - 1] = '\0'; + } #endif /* NO_PSK */ - if (ctx->suites) - *ssl->suites = *ctx->suites; - else - XMEMSET(ssl->suites, 0, sizeof(Suites)); + if (ctx->suites) + *ssl->suites = *ctx->suites; + else + XMEMSET(ssl->suites, 0, sizeof(Suites)); - /* make sure server has DH parms, and add PSK if there, add NTRU too */ - if (ssl->options.side == WOLFSSL_SERVER_END) - InitSuites(ssl->suites, ssl->version, haveRSA, havePSK, + /* make sure server has DH parms, and add PSK if there, add NTRU too */ + if (ssl->options.side == WOLFSSL_SERVER_END) + InitSuites(ssl->suites, ssl->version, haveRSA, havePSK, ssl->options.haveDH, ssl->options.haveNTRU, ssl->options.haveECDSAsig, ssl->options.haveECC, ssl->options.haveStaticECC, ssl->options.side); - else - InitSuites(ssl->suites, ssl->version, haveRSA, havePSK, TRUE, + else + InitSuites(ssl->suites, ssl->version, haveRSA, havePSK, TRUE, ssl->options.haveNTRU, ssl->options.haveECDSAsig, ssl->options.haveECC, ssl->options.haveStaticECC, ssl->options.side); #if !defined(NO_CERTS) && !defined(WOLFSSL_SESSION_EXPORT) - /* make sure server has cert and key unless using PSK or Anon - * This should be true even if just switching ssl ctx */ - if (ssl->options.side == WOLFSSL_SERVER_END && !havePSK && !haveAnon) - if (!ssl->buffers.certificate || !ssl->buffers.certificate->buffer || - !ssl->buffers.key || !ssl->buffers.key->buffer) { - WOLFSSL_MSG("Server missing certificate and/or private key"); - return NO_PRIVATE_KEY; - } + /* make sure server has cert and key unless using PSK or Anon + * This should be true even if just switching ssl ctx */ + if (ssl->options.side == WOLFSSL_SERVER_END && !havePSK && !haveAnon) + if (!ssl->buffers.certificate || !ssl->buffers.certificate->buffer + || !ssl->buffers.key || !ssl->buffers.key->buffer) { + WOLFSSL_MSG("Server missing certificate and/or private key"); + return NO_PRIVATE_KEY; + } #endif + } /* writeDup check */ + #ifdef WOLFSSL_SESSION_EXPORT #ifdef WOLFSSL_DTLS ssl->dtls_export = ctx->dtls_export; /* export function for session */ @@ -3358,8 +3371,13 @@ int SetSSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx) /* init everything to 0, NULL, default values before calling anything that may fail so that destructor has a "good" state to cleanup + + ssl object to initialize + ctx parent factory + writeDup flag indicating this is a write dup only + 0 on success */ -int InitSSL(WOLFSSL* ssl, WOLFSSL_CTX* ctx) +int InitSSL(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup) { int ret; @@ -3542,30 +3560,65 @@ int InitSSL(WOLFSSL* ssl, WOLFSSL_CTX* ctx) /* all done with init, now can return errors, call other stuff */ - /* arrays */ - ssl->arrays = (Arrays*)XMALLOC(sizeof(Arrays), ssl->heap, + if (!writeDup) { + /* arrays */ + ssl->arrays = (Arrays*)XMALLOC(sizeof(Arrays), ssl->heap, DYNAMIC_TYPE_ARRAYS); - if (ssl->arrays == NULL) { - WOLFSSL_MSG("Arrays Memory error"); - return MEMORY_E; - } - XMEMSET(ssl->arrays, 0, sizeof(Arrays)); + if (ssl->arrays == NULL) { + WOLFSSL_MSG("Arrays Memory error"); + return MEMORY_E; + } + XMEMSET(ssl->arrays, 0, sizeof(Arrays)); - /* suites */ - ssl->suites = (Suites*)XMALLOC(sizeof(Suites), ssl->heap, + /* suites */ + ssl->suites = (Suites*)XMALLOC(sizeof(Suites), ssl->heap, DYNAMIC_TYPE_SUITES); - if (ssl->suites == NULL) { - WOLFSSL_MSG("Suites Memory error"); - return MEMORY_E; + if (ssl->suites == NULL) { + WOLFSSL_MSG("Suites Memory error"); + return MEMORY_E; + } } /* Initialize SSL with the appropriate fields from it's ctx */ - /* requires valid arrays and suites */ - if((ret = SetSSL_CTX(ssl, ctx)) != SSL_SUCCESS) + /* requires valid arrays and suites unless writeDup ing */ + if ((ret = SetSSL_CTX(ssl, ctx, writeDup)) != SSL_SUCCESS) return ret; ssl->options.dtls = ssl->version.major == DTLS_MAJOR; +#ifdef SINGLE_THREADED + ssl->rng = ctx->rng; /* CTX may have one, if so use it */ +#endif + + if (ssl->rng == NULL) { + /* RNG */ + ssl->rng = (WC_RNG*)XMALLOC(sizeof(WC_RNG), ssl->heap,DYNAMIC_TYPE_RNG); + if (ssl->rng == NULL) { + WOLFSSL_MSG("RNG Memory error"); + return MEMORY_E; + } + XMEMSET(ssl->rng, 0, sizeof(WC_RNG)); + ssl->options.weOwnRng = 1; + + /* FIPS RNG API does not accept a heap hint */ +#ifndef HAVE_FIPS + if ( (ret = wc_InitRng_ex(ssl->rng, ssl->heap)) != 0) { + WOLFSSL_MSG("RNG Init error"); + return ret; + } +#else + if ( (ret = wc_InitRng(ssl->rng)) != 0) { + WOLFSSL_MSG("RNG Init error"); + return ret; + } +#endif + } + + if (writeDup) { + /* all done */ + return 0; + } + /* hsHashes */ ssl->hsHashes = (HS_Hashes*)XMALLOC(sizeof(HS_Hashes), ssl->heap, DYNAMIC_TYPE_HASHES); @@ -3604,34 +3657,6 @@ int InitSSL(WOLFSSL* ssl, WOLFSSL_CTX* ctx) } #endif -#ifdef SINGLE_THREADED - ssl->rng = ctx->rng; /* CTX may have one, if so use it */ -#endif - - if (ssl->rng == NULL) { - /* RNG */ - ssl->rng = (WC_RNG*)XMALLOC(sizeof(WC_RNG), ssl->heap,DYNAMIC_TYPE_RNG); - if (ssl->rng == NULL) { - WOLFSSL_MSG("RNG Memory error"); - return MEMORY_E; - } - XMEMSET(ssl->rng, 0, sizeof(WC_RNG)); - ssl->options.weOwnRng = 1; - - /* FIPS RNG API does not accept a heap hint */ -#ifndef HAVE_FIPS - if ( (ret = wc_InitRng_ex(ssl->rng, ssl->heap)) != 0) { - WOLFSSL_MSG("RNG Init error"); - return ret; - } -#else - if ( (ret = wc_InitRng(ssl->rng)) != 0) { - WOLFSSL_MSG("RNG Init error"); - return ret; - } -#endif - } - #if defined(WOLFSSL_DTLS) && !defined(NO_WOLFSSL_SERVER) if (ssl->options.dtls && ssl->options.side == WOLFSSL_SERVER_END) { ret = wolfSSL_DTLS_SetCookieSecret(ssl, NULL, 0); @@ -3842,6 +3867,11 @@ void SSL_ResourceFree(WOLFSSL* ssl) #ifdef HAVE_EXT_CACHE wolfSSL_SESSION_free(ssl->extSession); #endif +#ifdef HAVE_WRITE_DUP + if (ssl->dupWrite) { + FreeWriteDup(ssl); + } +#endif #ifdef WOLFSSL_STATIC_MEMORY /* check if using fixed io buffers and free them */ @@ -11588,6 +11618,26 @@ int SendAlert(WOLFSSL* ssl, int severity, int type) int outputSz; int dtlsExtra = 0; +#ifdef HAVE_WRITE_DUP + if (ssl->dupWrite && ssl->dupSide == READ_DUP_SIDE) { + int notifyErr = 0; + + WOLFSSL_MSG("Read dup side cannot write alerts, notifying sibling"); + + if (type == close_notify) { + notifyErr = ZERO_RETURN; + } else if (severity == alert_fatal) { + notifyErr = FATAL_ERROR; + } + + if (notifyErr != 0) { + return NotifyWriteSide(ssl, notifyErr); + } + + return 0; + } +#endif + /* if sendalert is called again for nonblocking */ if (ssl->options.sendAlertState != 0) { ret = SendBuffered(ssl); @@ -12024,6 +12074,12 @@ const char* wolfSSL_ERR_reason_error_string(unsigned long e) case DECODE_E: return "Decode handshake message error"; + case WRITE_DUP_READ_E: + return "Write dup write side can't read error"; + + case WRITE_DUP_WRITE_E: + return "Write dup read side can't write error"; + default : return "unknown error number"; } diff --git a/src/ssl.c b/src/ssl.c index 2d5fb50a5..ff391513e 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -372,7 +372,7 @@ WOLFSSL* wolfSSL_new(WOLFSSL_CTX* ctx) ssl = (WOLFSSL*) XMALLOC(sizeof(WOLFSSL), ctx->heap, DYNAMIC_TYPE_SSL); if (ssl) - if ( (ret = InitSSL(ssl, ctx)) < 0) { + if ( (ret = InitSSL(ssl, ctx, 0)) < 0) { FreeSSL(ssl, ctx->heap); ssl = 0; } @@ -390,6 +390,162 @@ void wolfSSL_free(WOLFSSL* ssl) WOLFSSL_LEAVE("SSL_free", 0); } + +#ifdef HAVE_WRITE_DUP + +/* + * Release resources around WriteDup object + * + * ssl WOLFSSL object + * + * no return, destruction so make best attempt +*/ +void FreeWriteDup(WOLFSSL* ssl) +{ + int doFree = 0; + + WOLFSSL_ENTER("FreeWriteDup"); + + if (ssl->dupWrite) { + if (wc_LockMutex(&ssl->dupWrite->dupMutex) == 0) { + ssl->dupWrite->dupCount--; + if (ssl->dupWrite->dupCount == 0) { + doFree = 1; + } else { + WOLFSSL_MSG("WriteDup count not zero, no full free"); + } + wc_UnLockMutex(&ssl->dupWrite->dupMutex); + } + } + + if (doFree) { + WOLFSSL_MSG("Doing WriteDup full free, count to zero"); + wc_FreeMutex(&ssl->dupWrite->dupMutex); + XFREE(ssl->dupWrite, ssl->heap, DYNAMIC_TYPE_WRITEDUP); + } +} + + +/* + * duplicate existing ssl members into dup needed for writing + * + * dup write only WOLFSSL + * ssl exisiting WOLFSSL + * + * 0 on success +*/ +static int DupSSL(WOLFSSL* dup, WOLFSSL* ssl) +{ + /* shared dupWrite setup */ + ssl->dupWrite = (WriteDup*)XMALLOC(sizeof(WriteDup), ssl->heap, + DYNAMIC_TYPE_WRITEDUP); + if (ssl->dupWrite == NULL) { + return MEMORY_E; + } + XMEMSET(ssl->dupWrite, 0, sizeof(WriteDup)); + + if (wc_InitMutex(&ssl->dupWrite->dupMutex) != 0) { + XFREE(ssl->dupWrite, ssl->heap, DYNAMIC_TYPE_WRITEDUP); + ssl->dupWrite = NULL; + return BAD_MUTEX_E; + } + ssl->dupWrite->dupCount = 2; /* both sides have a count to start */ + dup->dupWrite = ssl->dupWrite ; /* each side uses */ + + /* copy write parts over to dup writer */ + XMEMCPY(&dup->specs, &ssl->specs, sizeof(CipherSpecs)); + XMEMCPY(&dup->options, &ssl->options, sizeof(Options)); + XMEMCPY(&dup->keys, &ssl->keys, sizeof(Keys)); + XMEMCPY(&dup->encrypt, &ssl->encrypt, sizeof(Ciphers)); + /* dup side now owns encrypt/write ciphers */ + XMEMSET(&ssl->encrypt, 0, sizeof(Ciphers)); + + dup->IOCB_WriteCtx = ssl->IOCB_WriteCtx; + dup->wfd = ssl->wfd; + dup->wflags = ssl->wflags; + dup->hmac = ssl->hmac; +#ifdef HAVE_TRUNCATED_HMAC + dup->truncated_hmac = ssl->truncated_hmac; +#endif + + /* unique side dup setup */ + dup->dupSide = WRITE_DUP_SIDE; + ssl->dupSide = READ_DUP_SIDE; + + return 0; +} + + +/* + * duplicate a WOLFSSL object post handshake for writing only + * turn exisitng object into read only. Allows concurrent access from two + * different threads. + * + * ssl exisiting WOLFSSL object + * + * return dup'd WOLFSSL object on success +*/ +WOLFSSL* wolfSSL_write_dup(WOLFSSL* ssl) +{ + WOLFSSL* dup = NULL; + int ret = 0; + + (void)ret; + WOLFSSL_ENTER("wolfSSL_write_dup"); + + if (ssl == NULL) { + return ssl; + } + + if (ssl->options.handShakeDone == 0) { + WOLFSSL_MSG("wolfSSL_write_dup called before handshake complete"); + return NULL; + } + + dup = (WOLFSSL*) XMALLOC(sizeof(WOLFSSL), ssl->ctx->heap, DYNAMIC_TYPE_SSL); + if (dup) { + if ( (ret = InitSSL(dup, ssl->ctx, 1)) < 0) { + FreeSSL(dup, ssl->ctx->heap); + dup = NULL; + } else if ( (ret = DupSSL(dup, ssl) < 0)) { + FreeSSL(dup, ssl->ctx->heap); + dup = NULL; + } + } + + WOLFSSL_LEAVE("wolfSSL_write_dup", ret); + + return dup; +} + + +/* + * Notify write dup side of fatal error or close notify + * + * ssl WOLFSSL object + * err Notify err + * + * 0 on success +*/ +int NotifyWriteSide(WOLFSSL* ssl, int err) +{ + int ret; + + WOLFSSL_ENTER("NotifyWriteSide"); + + ret = wc_LockMutex(&ssl->dupWrite->dupMutex); + if (ret == 0) { + ssl->dupWrite->dupErr = err; + ret = wc_UnLockMutex(&ssl->dupWrite->dupMutex); + } + + return ret; +} + + +#endif /* HAVE_WRITE_DUP */ + + #ifdef HAVE_POLY1305 /* set if to use old poly 1 for yes 0 to use new poly */ int wolfSSL_use_old_poly(WOLFSSL* ssl, int value) @@ -1114,6 +1270,36 @@ int wolfSSL_write(WOLFSSL* ssl, const void* data, int sz) if (ssl == NULL || data == NULL || sz < 0) return BAD_FUNC_ARG; +#ifdef HAVE_WRITE_DUP + { /* local variable scope */ + int dupErr = 0; /* local copy */ + + ret = 0; + + if (ssl->dupWrite && ssl->dupSide == READ_DUP_SIDE) { + WOLFSSL_MSG("Read dup side cannot write"); + return WRITE_DUP_WRITE_E; + } + if (ssl->dupWrite) { + if (wc_LockMutex(&ssl->dupWrite->dupMutex) != 0) { + return BAD_MUTEX_E; + } + dupErr = ssl->dupWrite->dupErr; + ret = wc_UnLockMutex(&ssl->dupWrite->dupMutex); + } + + if (ret != 0) { + ssl->error = ret; /* high priority fatal error */ + return SSL_FATAL_ERROR; + } + if (dupErr != 0) { + WOLFSSL_MSG("Write dup error from other side"); + ssl->error = dupErr; + return SSL_FATAL_ERROR; + } + } +#endif + #ifdef HAVE_ERRNO_H errno = 0; #endif @@ -1138,6 +1324,13 @@ static int wolfSSL_read_internal(WOLFSSL* ssl, void* data, int sz, int peek) if (ssl == NULL || data == NULL || sz < 0) return BAD_FUNC_ARG; +#ifdef HAVE_WRITE_DUP + if (ssl->dupWrite && ssl->dupSide == WRITE_DUP_SIDE) { + WOLFSSL_MSG("Write dup side cannot read"); + return WRITE_DUP_READ_E; + } +#endif + #ifdef HAVE_ERRNO_H errno = 0; #endif @@ -1158,6 +1351,21 @@ static int wolfSSL_read_internal(WOLFSSL* ssl, void* data, int sz, int peek) #endif ret = ReceiveData(ssl, (byte*)data, sz, peek); +#ifdef HAVE_WRITE_DUP + if (ssl->dupWrite) { + if (ssl->error != 0 && ssl->error != WANT_READ && + ssl->error != WC_PENDING_E) { + int notifyErr; + + WOLFSSL_MSG("Notifying write side of fatal read error"); + notifyErr = NotifyWriteSide(ssl, ssl->error); + if (notifyErr < 0) { + ret = ssl->error = notifyErr; + } + } + } +#endif + WOLFSSL_LEAVE("wolfSSL_read_internal()", ret); if (ret < 0) @@ -22603,7 +22811,7 @@ const char * wolfSSL_get_servername(WOLFSSL* ssl, byte type) WOLFSSL_CTX* wolfSSL_set_SSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx) { - if (ssl && ctx && SetSSL_CTX(ssl, ctx) == SSL_SUCCESS) + if (ssl && ctx && SetSSL_CTX(ssl, ctx, 0) == SSL_SUCCESS) return ssl->ctx; return NULL; } diff --git a/wolfssl/error-ssl.h b/wolfssl/error-ssl.h index 236e4dfb7..941c379c5 100644 --- a/wolfssl/error-ssl.h +++ b/wolfssl/error-ssl.h @@ -153,6 +153,8 @@ enum wolfSSL_ErrorCodes { DTLS_POOL_SZ_E = -415, /* exceeded DTLS pool size */ DECODE_E = -416, /* decode handshake message error */ HTTP_TIMEOUT = -417, /* HTTP timeout for OCSP or CRL req */ + WRITE_DUP_READ_E = -418, /* Write dup write side can't read */ + WRITE_DUP_WRITE_E = -419, /* Write dup read side can't write */ /* add strings to wolfSSL_ERR_reason_error_string in internal.c !!!!! */ /* begin negotiation parameter errors */ diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 23db8760f..fac820f73 100755 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -2754,6 +2754,22 @@ typedef struct HS_Hashes { } HS_Hashes; +#ifdef HAVE_WRITE_DUP + + #define WRITE_DUP_SIDE 1 + #define READ_DUP_SIDE 2 + + typedef struct WriteDup { + wolfSSL_Mutex dupMutex; /* reference count mutex */ + int dupCount; /* reference count */ + int dupErr; /* under dupMutex, pass to other side */ + } WriteDup; + + WOLFSSL_LOCAL void FreeWriteDup(WOLFSSL* ssl); + WOLFSSL_LOCAL int NotifyWriteSide(WOLFSSL* ssl, int err); +#endif /* HAVE_WRITE_DUP */ + + /* wolfSSL ssl type */ struct WOLFSSL { WOLFSSL_CTX* ctx; @@ -2766,6 +2782,11 @@ struct WOLFSSL { void* verifyCbCtx; /* cert verify callback user ctx*/ VerifyCallback verifyCallback; /* cert verification callback */ void* heap; /* for user overrides */ +#ifdef HAVE_WRITE_DUP + WriteDup* dupWrite; /* valid pointer indicates ON */ + /* side that decrements dupCount to zero frees overall structure */ + byte dupSide; /* write side or read side */ +#endif #ifdef WOLFSSL_STATIC_MEMORY WOLFSSL_HEAP_HINT heap_hint; #endif @@ -2967,9 +2988,9 @@ struct WOLFSSL { WOLFSSL_LOCAL -int SetSSL_CTX(WOLFSSL*, WOLFSSL_CTX*); +int SetSSL_CTX(WOLFSSL*, WOLFSSL_CTX*, int); WOLFSSL_LOCAL -int InitSSL(WOLFSSL*, WOLFSSL_CTX*); +int InitSSL(WOLFSSL*, WOLFSSL_CTX*, int); WOLFSSL_LOCAL void FreeSSL(WOLFSSL*, void* heap); WOLFSSL_API void SSL_ResourceFree(WOLFSSL*); /* Micrium uses */ diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 6e8bd8068..dcdfa6254 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -369,6 +369,7 @@ WOLFSSL_API int wolfSSL_use_RSAPrivateKey_file(WOLFSSL*, const char*, int); WOLFSSL_API WOLFSSL_CTX* wolfSSL_CTX_new(WOLFSSL_METHOD*); WOLFSSL_API WOLFSSL* wolfSSL_new(WOLFSSL_CTX*); +WOLFSSL_API WOLFSSL* wolfSSL_write_dup(WOLFSSL*); WOLFSSL_API int wolfSSL_set_fd (WOLFSSL*, int); WOLFSSL_API int wolfSSL_set_write_fd (WOLFSSL*, int); WOLFSSL_API int wolfSSL_set_read_fd (WOLFSSL*, int); diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index 4cf535103..3e5d914ae 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -1230,6 +1230,12 @@ static char *fgets(char *buff, int sz, FILE *fp) #endif #endif +/* write dup cannot be used with secure renegotiation because write dup + * make write side write only and read side read only */ +#if defined(HAVE_WRITE_DUP) && defined(HAVE_SECURE_RENEGOTIATION) + #error "WRITE DUP and SECURE RENEGOTIATION cannot both be on" +#endif + #ifdef WOLFSSL_SGX #define WOLFCRYPT_ONLY /* limitation until IO resolved */ #define SINGLE_THREADED diff --git a/wolfssl/wolfcrypt/types.h b/wolfssl/wolfcrypt/types.h index 5e405dd21..127cf94ac 100644 --- a/wolfssl/wolfcrypt/types.h +++ b/wolfssl/wolfcrypt/types.h @@ -343,7 +343,8 @@ DYNAMIC_TYPE_MUTEX = 59, DYNAMIC_TYPE_PKCS7 = 60, DYNAMIC_TYPE_ASN1 = 61, - DYNAMIC_TYPE_LOG = 62 + DYNAMIC_TYPE_LOG = 62, + DYNAMIC_TYPE_WRITEDUP = 63 }; /* max error buffer string size */ From cd358bd2abd85442e2c2513829b511a26f7c23d9 Mon Sep 17 00:00:00 2001 From: toddouska Date: Mon, 3 Apr 2017 15:58:33 -0700 Subject: [PATCH 2/2] protect against multiple write dups --- src/ssl.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/ssl.c b/src/ssl.c index ff391513e..6258259eb 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -502,6 +502,11 @@ WOLFSSL* wolfSSL_write_dup(WOLFSSL* ssl) return NULL; } + if (ssl->dupWrite) { + WOLFSSL_MSG("wolfSSL_write_dup already called once"); + return NULL; + } + dup = (WOLFSSL*) XMALLOC(sizeof(WOLFSSL), ssl->ctx->heap, DYNAMIC_TYPE_SSL); if (dup) { if ( (ret = InitSSL(dup, ssl->ctx, 1)) < 0) {