diff --git a/examples/server/server.c b/examples/server/server.c index cca853a14d..2a0ffc7e77 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -532,7 +532,7 @@ int ServerEchoData(SSL* ssl, int clientfd, int echoData, int block, return 0; } -static void ServerRead(WOLFSSL* ssl, char* input, int inputLen) +static void ServerRead(WOLFSSL* ssl, char* input, int inputLen, byte inLine) { int ret, err; char buffer[WOLFSSL_MAX_ERROR_SZ]; @@ -540,7 +540,19 @@ static void ServerRead(WOLFSSL* ssl, char* input, int inputLen) /* Read data */ do { err = 0; /* reset error */ - ret = SSL_read(ssl, input, inputLen); + if (inLine) { + byte largeBuffer[4096]; + byte* outputPtr = NULL; + + ret = wolfSSL_read_inline(ssl, largeBuffer, sizeof(largeBuffer), + (void**)&outputPtr, inputLen); + if (ret > 0) { + XMEMCPY(input, outputPtr, ret); + } + } + else { + ret = SSL_read(ssl, input, inputLen); + } if (ret < 0) { err = SSL_get_error(ssl, ret); @@ -621,7 +633,8 @@ static void ServerRead(WOLFSSL* ssl, char* input, int inputLen) } } -static void ServerWrite(WOLFSSL* ssl, const char* output, int outputLen) +static void ServerWrite(WOLFSSL* ssl, const char* output, int outputLen, + byte inLine) { int ret, err; int len; @@ -636,7 +649,16 @@ static void ServerWrite(WOLFSSL* ssl, const char* output, int outputLen) do { err = 0; /* reset error */ - ret = SSL_write(ssl, output, len); + if (inLine) { + byte largeBuffer[4096]; + + XMEMCPY(largeBuffer, output, outputLen); + ret = wolfSSL_write_inline(ssl, largeBuffer, outputLen, + sizeof(largeBuffer)); + } + else { + ret = SSL_write(ssl, output, len); + } if (ret <= 0) { err = SSL_get_error(ssl, 0); @@ -807,7 +829,7 @@ static void SetKeyShare(WOLFSSL* ssl, int onlyKeyShare, int useX25519, /* 4. add the same message into Japanese section */ /* (will be translated later) */ /* 5. add printf() into suitable position of Usage() */ -static const char* server_usage_msg[][65] = { +static const char* server_usage_msg[][66] = { /* English */ { " NOTE: All files relative to wolfSSL home dir\n", /* 0 */ @@ -980,10 +1002,12 @@ static const char* server_usage_msg[][65] = { "--altPrivKey Generate alternative signature with this key.\n", /* 65 */ #endif + "--inline-io Does encrypt and decrypt inline with\n" + " wolfSSL_write and wolfSSL_read.\n", /* 66 */ "\n" "For simpler wolfSSL TLS server examples, visit\n" "https://github.com/wolfSSL/wolfssl-examples/tree/master/tls\n", - /* 66 */ + /* 67 */ NULL, }, #ifndef NO_MULTIBYTE_PRINT @@ -1174,11 +1198,13 @@ static const char* server_usage_msg[][65] = { "--altPrivKey Generate alternative signature with this key.\n", /* 65 */ #endif + "--inline-io Does encrypt and decrypt inline with\n" + " wolfSSL_write and wolfSSL_read.\n", /* 66 */ "\n" "より簡単なwolfSSL TSL クライアントの例については" "下記にアクセスしてください\n" "https://github.com/wolfSSL/wolfssl-examples/tree/master/tls\n", - /* 66 */ + /* 67 */ NULL, }, #endif @@ -1457,6 +1483,7 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) #ifdef WOLFSSL_DUAL_ALG_CERTS { "altPrivKey", 1, 267}, #endif + { "inline-io", 0, 268}, { 0, 0, 0 } }; #endif @@ -1626,6 +1653,7 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) char* altPrivKey = NULL; int exitWithRet = 0; int loadCertKeyIntoSSLObj = 0; + byte inLineIO = 0; #ifdef HAVE_ENCRYPT_THEN_MAC int disallowETM = 0; @@ -2351,6 +2379,10 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) break; #endif + case 268: + inLineIO = 1; + break; + case -1: default: Usage(); @@ -3620,7 +3652,7 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) #endif if (echoData == 0 && throughput == 0) { - ServerRead(ssl, input, sizeof(input)-1); + ServerRead(ssl, input, sizeof(input)-1, inLineIO); err = SSL_get_error(ssl, 0); } @@ -3739,11 +3771,11 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) write_msg = kHttpServerMsg; write_msg_sz = (int)XSTRLEN(kHttpServerMsg); } - ServerWrite(ssl, write_msg, write_msg_sz); + ServerWrite(ssl, write_msg, write_msg_sz, inLineIO); #ifdef WOLFSSL_TLS13 if (updateKeysIVs || postHandAuth) - ServerRead(ssl, input, sizeof(input)-1); + ServerRead(ssl, input, sizeof(input)-1, 0); #endif } else if (err == 0 || err == WOLFSSL_ERROR_ZERO_RETURN) { diff --git a/src/internal.c b/src/internal.c index cc6c666af2..2153e14ed0 100644 --- a/src/internal.c +++ b/src/internal.c @@ -10532,8 +10532,11 @@ static int wolfSSLReceive(WOLFSSL* ssl, byte* buf, word32 sz) void ShrinkOutputBuffer(WOLFSSL* ssl) { WOLFSSL_MSG("Shrinking output buffer"); - XFREE(ssl->buffers.outputBuffer.buffer - ssl->buffers.outputBuffer.offset, - ssl->heap, DYNAMIC_TYPE_OUT_BUFFER); + + if (ssl->buffers.outputBuffer.dynamicFlag != WOLFSSL_EXTERNAL_IO_BUFFER) { + XFREE(ssl->buffers.outputBuffer.buffer - + ssl->buffers.outputBuffer.offset, ssl->heap, DYNAMIC_TYPE_OUT_BUFFER); + } ssl->buffers.outputBuffer.buffer = ssl->buffers.outputBuffer.staticBuffer; ssl->buffers.outputBuffer.bufferSize = STATIC_BUFFER_LEN; ssl->buffers.outputBuffer.dynamicFlag = 0; @@ -10563,10 +10566,12 @@ void ShrinkInputBuffer(WOLFSSL* ssl, int forcedFree) usedLength); } - ForceZero(ssl->buffers.inputBuffer.buffer, - ssl->buffers.inputBuffer.length); - XFREE(ssl->buffers.inputBuffer.buffer - ssl->buffers.inputBuffer.offset, - ssl->heap, DYNAMIC_TYPE_IN_BUFFER); + if (ssl->buffers.inputBuffer.dynamicFlag != WOLFSSL_EXTERNAL_IO_BUFFER) { + ForceZero(ssl->buffers.inputBuffer.buffer, + ssl->buffers.inputBuffer.length); + XFREE(ssl->buffers.inputBuffer.buffer - ssl->buffers.inputBuffer.offset, + ssl->heap, DYNAMIC_TYPE_IN_BUFFER); + } ssl->buffers.inputBuffer.buffer = ssl->buffers.inputBuffer.staticBuffer; ssl->buffers.inputBuffer.bufferSize = STATIC_BUFFER_LEN; ssl->buffers.inputBuffer.dynamicFlag = 0; @@ -10678,6 +10683,41 @@ byte* GetOutputBuffer(WOLFSSL* ssl) } +/* sets the output buffer from an externally provided buffer */ +int SetOutputBuffer(WOLFSSL* ssl, byte* buf, int bufSz) +{ + if (ssl == NULL || buf == NULL) { + return BAD_FUNC_ARG; + } + + /* data waiting to be sent, don't overwrite it */ + if (ssl->buffers.outputBuffer.length > 0) { + return WANT_WRITE; + } + + ssl->buffers.outputBuffer.dynamicFlag = WOLFSSL_EXTERNAL_IO_BUFFER; + ssl->buffers.outputBuffer.buffer = buf; + ssl->buffers.outputBuffer.bufferSize = bufSz; + + return WOLFSSL_SUCCESS; +} + + +/* sets the input buffer from an externally provided buffer */ +int SetInputBuffer(WOLFSSL* ssl, byte* buf, int bufSz) +{ + if (ssl == NULL || buf == NULL) { + return BAD_FUNC_ARG; + } + + ssl->buffers.inputBuffer.dynamicFlag = WOLFSSL_EXTERNAL_IO_BUFFER; + ssl->buffers.inputBuffer.buffer = buf; + ssl->buffers.inputBuffer.bufferSize = bufSz; + + return WOLFSSL_SUCCESS; +} + + /* Grow the output buffer */ static WC_INLINE int GrowOutputBuffer(WOLFSSL* ssl, int size) { @@ -10700,6 +10740,11 @@ static WC_INLINE int GrowOutputBuffer(WOLFSSL* ssl, int size) align *= 2; #endif + if (ssl->buffers.outputBuffer.dynamicFlag == WOLFSSL_EXTERNAL_IO_BUFFER) { + WOLFSSL_MSG("External output buffer provided was too small"); + return BAD_FUNC_ARG; + } + if (! WC_SAFE_SUM_WORD32(ssl->buffers.outputBuffer.idx, ssl->buffers.outputBuffer.length, newSz)) return BUFFER_E; @@ -10781,6 +10826,11 @@ int GrowInputBuffer(WOLFSSL* ssl, int size, int usedLength) return BAD_FUNC_ARG; } + if (ssl->buffers.inputBuffer.dynamicFlag == WOLFSSL_EXTERNAL_IO_BUFFER) { + WOLFSSL_MSG("External input buffer provided was too small"); + return BAD_FUNC_ARG; + } + tmp = (byte*)XMALLOC(size + usedLength + align, ssl->heap, DYNAMIC_TYPE_IN_BUFFER); WOLFSSL_MSG("growing input buffer"); @@ -22706,6 +22756,12 @@ int BuildMessage(WOLFSSL* ssl, byte* output, int outSz, const byte* input, } #endif + /* move plan text data out of record headers way */ + if (ssl->buffers.outputBuffer.dynamicFlag == + WOLFSSL_EXTERNAL_IO_BUFFER) { + XMEMMOVE(output + args->headerSz + args->ivSz, input, inSz); + } + args->size = (word16)(args->sz - args->headerSz); /* include mac and digest */ AddRecordHeader(output, args->size, (byte)type, ssl, epochOrder); @@ -22715,7 +22771,10 @@ int BuildMessage(WOLFSSL* ssl, byte* output, int outSz, const byte* input, min(args->ivSz, MAX_IV_SZ)); args->idx += min(args->ivSz, MAX_IV_SZ); } - XMEMCPY(output + args->idx, input, inSz); + if (ssl->buffers.outputBuffer.dynamicFlag != + WOLFSSL_EXTERNAL_IO_BUFFER) { + XMEMCPY(output + args->idx, input, inSz); + } args->idx += inSz; ssl->options.buildMsgState = BUILD_MSG_HASH; @@ -24628,7 +24687,7 @@ int SendData(WOLFSSL* ssl, const void* data, int sz) } /* process input data */ -int ReceiveData(WOLFSSL* ssl, byte* output, int sz, int peek) +int ReceiveData(WOLFSSL* ssl, byte** output, int sz, int peek) { int size; @@ -24775,7 +24834,12 @@ int ReceiveData(WOLFSSL* ssl, byte* output, int sz, int peek) size = min(sz, (int)ssl->buffers.clearOutputBuffer.length); - XMEMCPY(output, ssl->buffers.clearOutputBuffer.buffer, size); + if (ssl->buffers.inputBuffer.dynamicFlag == WOLFSSL_EXTERNAL_IO_BUFFER) { + *output = ssl->buffers.clearOutputBuffer.buffer; + } + else { + XMEMCPY(*output, ssl->buffers.clearOutputBuffer.buffer, size); + } if (peek == 0) { ssl->buffers.clearOutputBuffer.length -= size; diff --git a/src/ssl.c b/src/ssl.c index fde2addb1b..178f336407 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -2846,7 +2846,54 @@ int wolfSSL_write(WOLFSSL* ssl, const void* data, int sz) return ret; } -static int wolfSSL_read_internal(WOLFSSL* ssl, void* data, int sz, int peek) + +/* does encryption and creation of TLS packet inline on buffer 'data' + * can only handle one fragment at a time */ +int wolfSSL_write_inline(WOLFSSL* ssl, const void* data, int dataSz, int maxSz) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_write_inline"); + + if (ssl == NULL || data == NULL || dataSz < 0) + return BAD_FUNC_ARG; + + /* only support a single TLS fragment */ + if (wolfSSL_GetMaxFragSize(ssl, dataSz) > dataSz) + return BAD_FUNC_ARG; + +#ifdef WOLFSSL_QUIC + if (WOLFSSL_IS_QUIC(ssl)) { + WOLFSSL_MSG("SSL_write() on QUIC not allowed"); + return BAD_FUNC_ARG; + } +#endif + +#ifdef HAVE_ERRNO_H + errno = 0; +#endif + + if (SetOutputBuffer(ssl, (byte*)data, maxSz) != WOLFSSL_SUCCESS) { + return WOLFSSL_FAILURE; + } + +#ifdef OPENSSL_EXTRA + if (ssl->CBIS != NULL) { + ssl->CBIS(ssl, SSL_CB_WRITE, WOLFSSL_SUCCESS); + ssl->cbmode = SSL_CB_WRITE; + } +#endif + ret = SendData(ssl, data, dataSz); + + WOLFSSL_LEAVE("wolfSSL_write_inline", ret); + + if (ret < 0) + return WOLFSSL_FATAL_ERROR; + else + return ret; +} + +static int wolfSSL_read_internal(WOLFSSL* ssl, void** data, int sz, int peek) { int ret; @@ -2855,6 +2902,10 @@ static int wolfSSL_read_internal(WOLFSSL* ssl, void* data, int sz, int peek) if (ssl == NULL || data == NULL || sz < 0) return BAD_FUNC_ARG; + if (ssl->buffers.inputBuffer.dynamicFlag != WOLFSSL_EXTERNAL_IO_BUFFER && + *data == NULL) + return BAD_FUNC_ARG; + #ifdef WOLFSSL_QUIC if (WOLFSSL_IS_QUIC(ssl)) { WOLFSSL_MSG("SSL_read() on QUIC not allowed"); @@ -2896,7 +2947,7 @@ static int wolfSSL_read_internal(WOLFSSL* ssl, void* data, int sz, int peek) errno = 0; #endif - ret = ReceiveData(ssl, (byte*)data, sz, peek); + ret = ReceiveData(ssl, (byte**)data, sz, peek); #ifdef HAVE_WRITE_DUP if (ssl->dupWrite) { @@ -2929,7 +2980,7 @@ int wolfSSL_peek(WOLFSSL* ssl, void* data, int sz) { WOLFSSL_ENTER("wolfSSL_peek"); - return wolfSSL_read_internal(ssl, data, sz, TRUE); + return wolfSSL_read_internal(ssl, &data, sz, TRUE); } @@ -2947,7 +2998,39 @@ int wolfSSL_read(WOLFSSL* ssl, void* data, int sz) ssl->cbmode = SSL_CB_READ; } #endif - return wolfSSL_read_internal(ssl, data, sz, FALSE); + return wolfSSL_read_internal(ssl, &data, sz, FALSE); +} + + +/* 'buf' is the full buffer available when reading data from the peer + * 'data' pointer gets pointed to the location of 'buf' where the data has been + * decrypted on success + * + * returns the amount of clear text data available on success and negative + * values on failure + */ +int wolfSSL_read_inline(WOLFSSL* ssl, void* buf, int bufSz, void** data, + int dataSz) +{ + WOLFSSL_ENTER("wolfSSL_read"); + + #ifdef OPENSSL_EXTRA + if (ssl == NULL) { + return BAD_FUNC_ARG; + } + if (ssl->CBIS != NULL) { + ssl->CBIS(ssl, SSL_CB_READ, WOLFSSL_SUCCESS); + ssl->cbmode = SSL_CB_READ; + } + #endif + + /* ShrinkInputBuffer will reset the internal buffer back to the static + * buffer and does not zero out or free 'buf' */ + if (SetInputBuffer(ssl, (byte*)buf, bufSz) != WOLFSSL_SUCCESS) { + return WOLFSSL_FAILURE; + } + + return wolfSSL_read_internal(ssl, data, dataSz, FALSE); } @@ -2962,7 +3045,7 @@ int wolfSSL_mcast_read(WOLFSSL* ssl, word16* id, void* data, int sz) if (ssl == NULL) return BAD_FUNC_ARG; - ret = wolfSSL_read_internal(ssl, data, sz, FALSE); + ret = wolfSSL_read_internal(ssl, &data, sz, FALSE); if (ssl->options.dtls && ssl->options.haveMcast && id != NULL) *id = ssl->keys.curPeerId; return ret; diff --git a/src/tls13.c b/src/tls13.c index 585b02958a..39336ef0d9 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -14647,7 +14647,7 @@ int wolfSSL_read_early_data(WOLFSSL* ssl, void* data, int sz, int* outSz) return WOLFSSL_FATAL_ERROR; } if (ssl->options.handShakeState == SERVER_FINISHED_COMPLETE) { - ret = ReceiveData(ssl, (byte*)data, sz, FALSE); + ret = ReceiveData(ssl, (byte**)&data, sz, FALSE); if (ret > 0) *outSz = ret; if (ssl->error == ZERO_RETURN) { diff --git a/wolfssl/internal.h b/wolfssl/internal.h index dea087739b..7ab139fbac 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -2342,13 +2342,15 @@ enum { #define STATIC_BUFFER_LEN RECORD_HEADER_SZ #endif +#define WOLFSSL_DYNMAIC_IO_BUFFER 1 +#define WOLFSSL_EXTERNAL_IO_BUFFER 2 typedef struct { ALIGN16 byte staticBuffer[STATIC_BUFFER_LEN]; byte* buffer; /* place holder for static or dynamic buffer */ word32 length; /* total buffer length used */ word32 idx; /* idx to part of length already consumed */ word32 bufferSize; /* current buffer size */ - byte dynamicFlag; /* dynamic memory currently in use */ + byte dynamicFlag; /* dynamic(1) or external(2) memory currently in use */ byte offset; /* alignment offset attempt */ } bufferStatic; @@ -6244,7 +6246,7 @@ WOLFSSL_LOCAL int SendHelloRequest(WOLFSSL* ssl); WOLFSSL_LOCAL int SendCertificateStatus(WOLFSSL* ssl); WOLFSSL_LOCAL int SendServerKeyExchange(WOLFSSL* ssl); WOLFSSL_LOCAL int SendBuffered(WOLFSSL* ssl); -WOLFSSL_LOCAL int ReceiveData(WOLFSSL* ssl, byte* output, int sz, int peek); +WOLFSSL_LOCAL int ReceiveData(WOLFSSL* ssl, byte** output, int sz, int peek); WOLFSSL_LOCAL int SendFinished(WOLFSSL* ssl); WOLFSSL_LOCAL int RetrySendAlert(WOLFSSL* ssl); WOLFSSL_LOCAL int SendAlert(WOLFSSL* ssl, int severity, int type); @@ -6273,6 +6275,8 @@ WOLFSSL_LOCAL void FreeHandshakeResources(WOLFSSL* ssl); WOLFSSL_LOCAL void ShrinkInputBuffer(WOLFSSL* ssl, int forcedFree); WOLFSSL_LOCAL void ShrinkOutputBuffer(WOLFSSL* ssl); WOLFSSL_LOCAL byte* GetOutputBuffer(WOLFSSL* ssl); +WOLFSSL_LOCAL int SetOutputBuffer(WOLFSSL* ssl, byte* buf, int bufSz); +WOLFSSL_LOCAL int SetInputBuffer(WOLFSSL* ssl, byte* buf, int bufSz); WOLFSSL_LOCAL int CipherRequires(byte first, byte second, int requirement); WOLFSSL_LOCAL int VerifyClientSuite(word16 havePSK, byte cipherSuite0, diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index d5efa358fd..f5800bfb9c 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -1185,6 +1185,10 @@ WOLFSSL_ABI WOLFSSL_API int wolfSSL_connect(WOLFSSL* ssl); WOLFSSL_ABI WOLFSSL_API int wolfSSL_write( WOLFSSL* ssl, const void* data, int sz); WOLFSSL_ABI WOLFSSL_API int wolfSSL_read(WOLFSSL* ssl, void* data, int sz); +WOLFSSL_API int wolfSSL_write_inline( WOLFSSL* ssl, const void* data, + int dataSz, int maxSz); +WOLFSSL_API int wolfSSL_read_inline(WOLFSSL* ssl, void* buf, int bufSz, + void** data, int dataSz); WOLFSSL_API int wolfSSL_peek(WOLFSSL* ssl, void* data, int sz); WOLFSSL_ABI WOLFSSL_API int wolfSSL_accept(WOLFSSL* ssl); WOLFSSL_API int wolfSSL_CTX_mutual_auth(WOLFSSL_CTX* ctx, int req);