From 32bf163633413394ef5e4ba338000991af5000df Mon Sep 17 00:00:00 2001 From: Jacob Barthelmeh Date: Wed, 29 Mar 2017 15:50:14 -0600 Subject: [PATCH] update base64 WOLFSSL_BIO encoding and checking session context ID --- src/bio.c | 39 +++++++++++--- src/internal.c | 6 +++ src/ssl.c | 61 +++++++++++++++++++++- tests/api.c | 123 ++++++++++++++++++++++++++++++++++++++++++--- wolfssl/internal.h | 8 +++ 5 files changed, 219 insertions(+), 18 deletions(-) diff --git a/src/bio.c b/src/bio.c index 1a19f586f..392899438 100644 --- a/src/bio.c +++ b/src/bio.c @@ -134,6 +134,7 @@ int wolfSSL_BIO_read(WOLFSSL_BIO* bio, void* buf, int len) { int ret = 0; WOLFSSL_BIO* front = bio; + int sz = 0; WOLFSSL_ENTER("wolfSSL_BIO_read"); @@ -144,8 +145,8 @@ int wolfSSL_BIO_read(WOLFSSL_BIO* bio, void* buf, int len) while (bio != NULL && ret >= 0) { /* formating data */ - if (bio->type == WOLFSSL_BIO_BASE64 && ret > 0) { - ret = wolfSSL_BIO_BASE64_read(bio, buf, len); + if (bio->type == WOLFSSL_BIO_BASE64 && ret > 0 && sz > 0) { + ret = wolfSSL_BIO_BASE64_read(bio, buf, sz); } /* write BIOs */ @@ -172,6 +173,10 @@ int wolfSSL_BIO_read(WOLFSSL_BIO* bio, void* buf, int len) break; /* at front of list so be done */ } + if (ret > 0) { + sz = ret; /* adjust size for formating */ + } + /* previous WOLFSSL_BIO in list working towards head of list */ bio = bio->prev; } @@ -183,33 +188,47 @@ int wolfSSL_BIO_read(WOLFSSL_BIO* bio, void* buf, int len) static int wolfSSL_BIO_BASE64_write(WOLFSSL_BIO* bio, const void* data, word32 inLen, byte* out, word32* outLen) { + byte* tmp = NULL; + int ret = 0; + WOLFSSL_ENTER("wolfSSL_BIO_BASE64_write"); #if defined(WOLFSSL_BASE64_ENCODE) + tmp = (byte*)XMALLOC(*outLen, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (tmp == NULL) { + return SSL_FATAL_ERROR; + } + if ((bio->flags & WOLFSSL_BIO_FLAG_BASE64_NO_NL) == WOLFSSL_BIO_FLAG_BASE64_NO_NL) { if (Base64_Encode_NoNl((const byte*)data, inLen, - out, outLen) < 0) { - return SSL_FATAL_ERROR; + tmp, outLen) < 0) { + ret = SSL_FATAL_ERROR; } } else { if (Base64_Encode((const byte*)data, inLen, - out, outLen) < 0) { - return SSL_FATAL_ERROR; + tmp, outLen) < 0) { + ret = SSL_FATAL_ERROR; } } - return (int)*outLen; + if (ret != SSL_FATAL_ERROR) { + ret = (int)*outLen; + XMEMCPY(out, tmp, *outLen); + + } + XFREE(tmp, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); #else (void)bio; (void)data; (void)inLen; (void)out; (void)outLen; + (void)tmp; WOLFSSL_MSG("BASE64 encoding not compiled in"); - return 0; #endif + return ret; } @@ -362,6 +381,10 @@ int wolfSSL_BIO_write(WOLFSSL_BIO* bio, const void* data, int len) WOLFSSL_MSG("Memory error"); ret = SSL_FATAL_ERROR; } + /* since frmt already existed then data should point to knew + formated buffer */ + data = frmt; + len = frmtSz; frmtSz = sz; } #endif /* defined(WOLFSSL_BASE64_ENCODE) */ diff --git a/src/internal.c b/src/internal.c index efddc7549..374c57c4b 100644 --- a/src/internal.c +++ b/src/internal.c @@ -4355,6 +4355,12 @@ int InitSSL(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup) ssl->alert_history.last_tx.code = -1; ssl->alert_history.last_tx.level = -1; +#ifdef OPENSSL_EXTRA + /* copy over application session context ID */ + ssl->sessionCtxSz = ctx->sessionCtxSz; + XMEMCPY(ssl->sessionCtx, ctx->sessionCtx, ctx->sessionCtxSz); +#endif + InitCiphers(ssl); InitCipherSpecs(&ssl->specs); diff --git a/src/ssl.c b/src/ssl.c index d5d8245ce..4e811547b 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -10143,6 +10143,17 @@ int SetSession(WOLFSSL* ssl, WOLFSSL_SESSION* session) if (ssl->options.sessionCacheOff) return WOLFSSL_FAILURE; +#ifdef OPENSSL_EXTRA + /* check for application context id */ + if (ssl->sessionCtxSz > 0) { + if (XMEMCMP(ssl->sessionCtx, session->sessionCtx, ssl->sessionCtxSz)) { + /* context id did not match! */ + WOLFSSL_MSG("Session context did not match"); + return SSL_FAILURE; + } + } +#endif /* OPENSSL_EXTRA */ + if (LowResTimer() < (session->bornOn + session->timeout)) { int ret = GetDeepCopySession(ssl, session); if (ret == WOLFSSL_SUCCESS) { @@ -10251,6 +10262,14 @@ int AddSession(WOLFSSL* ssl) XMEMCPY(session->sessionID, ssl->arrays->sessionID, ID_LEN); session->sessionIDSz = ssl->arrays->sessionIDSz; +#ifdef OPENSSL_EXTRA + /* If using compatibilty layer then check for and copy over session context + * id. */ + if (ssl->sessionCtxSz > 0 && ssl->sessionCtxSz < ID_LEN) { + XMEMCPY(session->sessionCtx, ssl->sessionCtx, ssl->sessionCtxSz); + } +#endif + session->timeout = ssl->timeout; session->bornOn = LowResTimer(); @@ -14292,8 +14311,16 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD *md) #endif - /* @TODO storing app session context id, now needs to tie in with InitSSL_CTX - * and with handshake. */ + /* Storing app session context id, this value is inherited by WOLFSSL + * objects created from WOLFSSL_CTX. Any session that is imported with a + * different session context id will be rejected. + * + * ctx structure to set context in + * sid_ctx value of context to set + * sid_ctx_len length of sid_ctx buffer + * + * Returns SSL_SUCCESS in success case and SSL_FAILURE when failing + */ int wolfSSL_CTX_set_session_id_context(WOLFSSL_CTX* ctx, const unsigned char* sid_ctx, unsigned int sid_ctx_len) @@ -14305,6 +14332,8 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD *md) return SSL_FAILURE; } XMEMCPY(ctx->sessionCtx, sid_ctx, sid_ctx_len); + ctx->sessionCtxSz = sid_ctx_len; + return SSL_SUCCESS; } @@ -19805,6 +19834,10 @@ int wolfSSL_i2d_SSL_SESSION(WOLFSSL_SESSION* sess, unsigned char** p) #endif unsigned char *data; + if (sess == NULL) { + return BAD_FUNC_ARG; + } + /* bornOn | timeout | sessionID len | sessionID | masterSecret | haveEMS */ size += OPAQUE32_LEN + OPAQUE32_LEN + OPAQUE8_LEN + sess->sessionIDSz + SECRET_LEN + OPAQUE8_LEN; @@ -19824,6 +19857,10 @@ int wolfSSL_i2d_SSL_SESSION(WOLFSSL_SESSION* sess, unsigned char** p) /* ticket len | ticket */ size += OPAQUE16_LEN + sess->ticketLen; #endif +#ifdef OPENSSL_EXTRA + /* session context ID len | session context ID */ + size += OPAQUE8_LEN + sess->sessionCtxSz; +#endif if (p != NULL) { if (*p == NULL) @@ -19862,6 +19899,11 @@ int wolfSSL_i2d_SSL_SESSION(WOLFSSL_SESSION* sess, unsigned char** p) c16toa(sess->ticketLen, data + idx); idx += OPAQUE16_LEN; XMEMCPY(data + idx, sess->ticket, sess->ticketLen); idx += sess->ticketLen; +#endif +#ifdef OPENSSL_EXTRA + data[idx++] = sess->sessionCtxSz; + XMEMCPY(data + idx, sess->sessionCtx, sess->sessionCtxSz); + idx += sess->sessionCtxSz; #endif } #endif @@ -20008,6 +20050,21 @@ WOLFSSL_SESSION* wolfSSL_d2i_SSL_SESSION(WOLFSSL_SESSION** sess, goto end; } XMEMCPY(s->ticket, data + idx, s->ticketLen); idx += s->ticketLen; +#endif +#ifdef OPENSSL_EXTRA + /* byte for length of session context ID */ + if (i - idx < OPAQUE8_LEN) { + ret = BUFFER_ERROR; + goto end; + } + s->sessionCtxSz = data[idx++]; + + /* app session context ID */ + if (i - idx < s->sessionCtxSz) { + ret = BUFFER_ERROR; + goto end; + } + XMEMCPY(s->sessionCtx, data + idx, s->sessionCtxSz); idx += s->sessionCtxSz; #endif (void)idx; diff --git a/tests/api.c b/tests/api.c index 5f1784cbd..72e979360 100644 --- a/tests/api.c +++ b/tests/api.c @@ -15546,13 +15546,13 @@ static void test_wolfSSL_BIO_gets(void) static void test_wolfSSL_BIO_write(void) { - #if defined(OPENSSL_EXTRA) + #if defined(OPENSSL_EXTRA) && defined(WOLFSSL_BASE64_ENCODE) BIO* bio; BIO* bio64; BIO* ptr; int sz; char msg[] = "conversion test"; - char out[25]; + char out[40]; char expected[] = "Y29udmVyc2lvbiB0ZXN0AA==\n"; printf(testingFmt, "BIO_write()"); @@ -15569,6 +15569,13 @@ static void test_wolfSSL_BIO_write(void) AssertIntEQ((sz = BIO_read(ptr, out, sz)), 25); AssertIntEQ(XMEMCMP(out, expected, sz), 0); + /* write then read should return the same message */ + AssertIntEQ(BIO_write(bio, msg, sizeof(msg)), 25); + sz = sizeof(out); + XMEMSET(out, 0, sz); + AssertIntEQ(BIO_read(bio, out, sz), 16); + AssertIntEQ(XMEMCMP(out, msg, sizeof(msg)), 0); + /* now try encoding with no line ending */ BIO_set_flags(bio64, BIO_FLAG_BASE64_NO_NL); AssertIntEQ(BIO_write(bio, msg, sizeof(msg)), 24); @@ -15582,11 +15589,11 @@ static void test_wolfSSL_BIO_write(void) /* test with more than one bio64 in list */ AssertNotNull(bio64 = BIO_new(BIO_f_base64())); - AssertNotNull(bio = BIO_push(bio64, BIO_new(BIO_f_base64()))); - AssertNotNull(bio = BIO_push(bio, BIO_new(BIO_s_mem()))); + AssertNotNull(bio = BIO_push(BIO_new(BIO_f_base64()), bio64)); + AssertNotNull(BIO_push(bio64, BIO_new(BIO_s_mem()))); /* now should convert to base64(x2) when stored and then decode with read */ - AssertIntEQ(BIO_write(bio, msg, sizeof(msg)), 25); + AssertIntEQ(BIO_write(bio, msg, sizeof(msg)), 37); BIO_flush(bio); sz = sizeof(out); XMEMSET(out, 0, sz); @@ -15600,10 +15607,110 @@ static void test_wolfSSL_BIO_write(void) static void test_wolfSSL_SESSION(void) { - #if defined(OPENSSL_EXTRA) - printf(testingFmt, "no_op_functions()"); +#if defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && \ + !defined(NO_RSA) && defined(HAVE_EXT_CACHE) && \ + defined(HAVE_IO_TESTS_DEPENDENCIES) + + WOLFSSL* ssl; + WOLFSSL_CTX* ctx; + WOLFSSL_SESSION* sess; + const unsigned char context[] = "user app context"; + unsigned char* sessDer = NULL; + unsigned char* ptr = NULL; + unsigned int contextSz = (unsigned int)sizeof(context); + int ret, err, sockfd, sz; + tcp_ready ready; + func_args server_args; + THREAD_TYPE serverThread; + + printf(testingFmt, "wolfSSL_SESSION()"); + AssertNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method())); + + AssertTrue(wolfSSL_CTX_use_certificate_file(ctx, cliCertFile, SSL_FILETYPE_PEM)); + AssertTrue(wolfSSL_CTX_use_PrivateKey_file(ctx, cliKeyFile, SSL_FILETYPE_PEM)); + AssertIntEQ(wolfSSL_CTX_load_verify_locations(ctx, caCertFile, 0), SSL_SUCCESS); + wolfSSL_CTX_set_default_passwd_cb(ctx, PasswordCallBack); + + + XMEMSET(&server_args, 0, sizeof(func_args)); +#ifdef WOLFSSL_TIRTOS + fdOpenSession(Task_self()); +#endif + + StartTCP(); + InitTcpReady(&ready); + +#if defined(USE_WINDOWS_API) + /* use RNG to get random port if using windows */ + ready.port = GetRandomPort(); +#endif + + server_args.signal = &ready; + start_thread(test_server_nofail, &server_args, &serverThread); + wait_tcp_ready(&server_args); + + /* client connection */ + ssl = wolfSSL_new(ctx); + tcp_connect(&sockfd, wolfSSLIP, ready.port, 0, 0, ssl); + AssertIntEQ(wolfSSL_set_fd(ssl, sockfd), SSL_SUCCESS); + + do { +#ifdef WOLFSSL_ASYNC_CRYPT + if (err == WC_PENDING_E) { + ret = wolfSSL_AsyncPoll(ssl, WOLF_POLL_FLAG_CHECK_HW); + if (ret < 0) { break; } else if (ret == 0) { continue; } + } +#endif + + err = 0; /* Reset error */ + ret = wolfSSL_connect(ssl); + if (ret != SSL_SUCCESS) { + err = wolfSSL_get_error(ssl, 0); + } + } while (ret != SSL_SUCCESS && err == WC_PENDING_E); + AssertIntEQ(ret, SSL_SUCCESS); + sess = wolfSSL_get_session(ssl); + wolfSSL_shutdown(ssl); + wolfSSL_free(ssl); + + join_thread(serverThread); + + FreeTcpReady(&ready); + +#ifdef WOLFSSL_TIRTOS + fdOpenSession(Task_self()); +#endif + + /* get session from DER and update the timeout */ + AssertIntEQ(wolfSSL_i2d_SSL_SESSION(NULL, &sessDer), BAD_FUNC_ARG); + AssertIntGT((sz = wolfSSL_i2d_SSL_SESSION(sess, &sessDer)), 0); + wolfSSL_SESSION_free(sess); + ptr = sessDer; + AssertNull(sess = wolfSSL_d2i_SSL_SESSION(NULL, NULL, sz)); + AssertNotNull(sess = wolfSSL_d2i_SSL_SESSION(NULL, + (const unsigned char**)&ptr, sz)); + XFREE(sessDer, NULL, DYNAMIC_TYPE_OPENSSL); + AssertIntGT(wolfSSL_SESSION_get_time(sess), 0); + AssertIntEQ(wolfSSL_SSL_SESSION_set_timeout(sess, 500), SSL_SUCCESS); + + /* successful set session test */ + AssertNotNull(ssl = wolfSSL_new(ctx)); + AssertIntEQ(wolfSSL_set_session(ssl, sess), SSL_SUCCESS); + wolfSSL_free(ssl); + + /* fail case with miss match session context IDs (use compatibility API) */ + AssertIntEQ(SSL_CTX_set_session_id_context(NULL, context, contextSz), + SSL_FAILURE); + AssertIntEQ(SSL_CTX_set_session_id_context(ctx, context, contextSz), + SSL_SUCCESS); + AssertNotNull(ssl = wolfSSL_new(ctx)); + AssertIntEQ(wolfSSL_set_session(ssl, sess), SSL_FAILURE); + wolfSSL_free(ssl); + + wolfSSL_SESSION_free(sess); + wolfSSL_CTX_free(ctx); printf(resultFmt, passed); - #endif +#endif } diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 8186491fe..ef783af1c 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -2682,6 +2682,10 @@ struct WOLFSSL_SESSION { word16 idLen; /* serverID length */ byte serverID[SERVER_ID_LEN]; /* for easier client lookup */ #endif +#ifdef OPENSSL_EXTRA + byte sessionCtxSz; /* sessionCtx length */ + byte sessionCtx[ID_LEN]; /* app specific context id */ +#endif #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK) #ifdef WOLFSSL_TLS13 byte namedGroup; @@ -2694,6 +2698,8 @@ struct WOLFSSL_SESSION { #ifdef WOLFSSL_EARLY_DATA word32 maxEarlyDataSz; #endif +#endif +#ifdef HAVE_SESSION_TICKET byte* ticket; word16 ticketLen; byte staticTicket[SESSION_TICKET_LEN]; @@ -3319,8 +3325,10 @@ struct WOLFSSL { CallbackInfoState* CBIS; /* used to get info about SSL state */ WOLFSSL_BIO* biord; /* socket bio read to free/close */ WOLFSSL_BIO* biowr; /* socket bio write to free/close */ + byte sessionCtx[ID_LEN]; /* app session context ID */ unsigned long peerVerifyRet; byte readAhead; + byte sessionCtxSz; /* size of sessionCtx stored */ #ifdef HAVE_PK_CALLBACKS void* loggingCtx; /* logging callback argument */ #endif