diff --git a/.github/workflows/socat.yml b/.github/workflows/socat.yml new file mode 100644 index 0000000000..98c612d840 --- /dev/null +++ b/.github/workflows/socat.yml @@ -0,0 +1,76 @@ +name: socat Tests + +# START OF COMMON SECTION +on: + push: + branches: [ 'master', 'main', 'release/**' ] + pull_request: + branches: [ '*' ] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true +# END OF COMMON SECTION + +jobs: + build_wolfssl: + name: Build wolfSSL + runs-on: ubuntu-latest + timeout-minutes: 4 + steps: + - name: Build wolfSSL + uses: wolfSSL/actions-build-autotools-project@v1 + with: + path: wolfssl + configure: --enable-maxfragment --enable-opensslall --enable-opensslextra --enable-dtls --enable-oldtls --enable-tlsv10 --enable-ipv6 'CPPFLAGS=-DWOLFSSL_NO_DTLS_SIZE_CHECK -DOPENSSL_COMPATIBLE_DEFAULTS' + install: true + + - name: Upload built lib + uses: actions/upload-artifact@v4 + with: + name: wolf-install-socat + path: build-dir + retention-days: 3 + + + socat_check: + strategy: + fail-fast: false + runs-on: ubuntu-latest + # This should be a safe limit for the tests to run. + timeout-minutes: 30 + needs: build_wolfssl + steps: + - name: Install prereqs + run: + sudo apt-get install build-essential autoconf libtool pkg-config clang libc++-dev + + - name: Download lib + uses: actions/download-artifact@v4 + with: + name: wolf-install-socat + path: build-dir + + - name: Download socat + run: curl -O http://www.dest-unreach.org/socat/download/socat-1.8.0.0.tar.gz && tar xvf socat-1.8.0.0.tar.gz + + - name: Checkout OSP + uses: actions/checkout@v4 + with: + repository: wolfssl/osp + path: osp + + - name: Build socat + working-directory: ./socat-1.8.0.0 + run: | + patch -p1 < ../osp/socat/1.8.0.0/socat-1.8.0.0.patch + autoreconf -vfi + ./configure --with-wolfssl=$GITHUB_WORKSPACE/build-dir + make + + - name: Run socat tests + working-directory: ./socat-1.8.0.0 + run: | + export LD_LIBRARY_PATH=$GITHUB_WORKSPACE/build-dir/lib:$LD_LIBRARY_PATH + export SHELL=/bin/bash + SOCAT=$GITHUB_WORKSPACE/socat-1.8.0.0/socat ./test.sh -t 0.5 --expect-fail 146,216,309,310,386,399,402,459,460,467,468,478,492,528,530 diff --git a/src/ssl.c b/src/ssl.c index 6d2cb27f29..fde2addb1b 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -14961,6 +14961,17 @@ int wolfSSL_COMP_add_compression_method(int method, void* data) } #endif +#ifndef NO_WOLFSSL_STUB +const char* wolfSSL_COMP_get_name(const void* comp) +{ + static const char ret[] = "not supported"; + + (void)comp; + WOLFSSL_STUB("wolfSSL_COMP_get_name"); + return ret; +} +#endif + /* wolfSSL_set_dynlock_create_callback * CRYPTO_set_dynlock_create_callback has been deprecated since openSSL 1.0.1. * This function exists for compatibility purposes because wolfSSL satisfies diff --git a/src/ssl_sess.c b/src/ssl_sess.c index 23b595be8b..0a5da2f9b8 100644 --- a/src/ssl_sess.c +++ b/src/ssl_sess.c @@ -747,6 +747,20 @@ long wolfSSL_CTX_set_session_cache_mode(WOLFSSL_CTX* ctx, long mode) } #ifdef OPENSSL_EXTRA +#ifdef HAVE_MAX_FRAGMENT +/* return the max fragment size set when handshake was negotiated */ +unsigned char wolfSSL_SESSION_get_max_fragment_length(WOLFSSL_SESSION* session) +{ + session = ClientSessionToSession(session); + if (session == NULL) { + return 0; + } + + return session->mfl; +} +#endif + + /* Get the session cache mode for CTX * * ctx WOLFSSL_CTX struct to get cache mode from diff --git a/src/tls.c b/src/tls.c index c653eee41c..558afea0d4 100644 --- a/src/tls.c +++ b/src/tls.c @@ -2997,6 +2997,9 @@ static int TLSX_MFL_Parse(WOLFSSL* ssl, const byte* input, word16 length, WOLFSSL_ERROR_VERBOSE(UNKNOWN_MAX_FRAG_LEN_E); return UNKNOWN_MAX_FRAG_LEN_E; } + if (ssl->session != NULL) { + ssl->session->mfl = *input; + } #ifndef NO_WOLFSSL_SERVER if (isRequest) { diff --git a/src/x509.c b/src/x509.c index e711e1c5a2..d09d104c19 100644 --- a/src/x509.c +++ b/src/x509.c @@ -13051,6 +13051,7 @@ static int wolfSSL_EscapeString_RFC2253(char* in, word32 inSz, * RFC22523 currently implemented. * XN_FLAG_DN_REV - print name reversed. Automatically done by * XN_FLAG_RFC2253. + * XN_FLAG_SPC_EQ - spaces before and after '=' character * * Returns WOLFSSL_SUCCESS (1) on success, WOLFSSL_FAILURE (0) on failure. */ @@ -13058,6 +13059,8 @@ int wolfSSL_X509_NAME_print_ex(WOLFSSL_BIO* bio, WOLFSSL_X509_NAME* name, int indent, unsigned long flags) { int i, count = 0, nameStrSz = 0, escapeSz = 0; + int eqSpace = 0; + char eqStr[4]; char* tmp = NULL; char* nameStr = NULL; const char *buf = NULL; @@ -13070,6 +13073,15 @@ int wolfSSL_X509_NAME_print_ex(WOLFSSL_BIO* bio, WOLFSSL_X509_NAME* name, if ((name == NULL) || (name->sz == 0) || (bio == NULL)) return WOLFSSL_FAILURE; + XMEMSET(eqStr, 0, sizeof(eqStr)); + if (flags & XN_FLAG_SPC_EQ) { + eqSpace = 2; + XSTRNCPY(eqStr, " = ", 4); + } + else { + XSTRNCPY(eqStr, "=", 4); + } + for (i = 0; i < indent; i++) { if (wolfSSL_BIO_write(bio, " ", 1) != 1) return WOLFSSL_FAILURE; @@ -13114,14 +13126,15 @@ int wolfSSL_X509_NAME_print_ex(WOLFSSL_BIO* bio, WOLFSSL_X509_NAME* name, if (len == 0 || buf == NULL) return WOLFSSL_FAILURE; - tmpSz = nameStrSz + len + 4; /* + 4 for '=', comma space and '\0'*/ + /* + 4 for '=', comma space and '\0'*/ + tmpSz = nameStrSz + len + 4 + eqSpace; tmp = (char*)XMALLOC(tmpSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (tmp == NULL) { return WOLFSSL_FAILURE; } if (i < count - 1) { - if (XSNPRINTF(tmp, (size_t)tmpSz, "%s=%s, ", buf, nameStr) + if (XSNPRINTF(tmp, (size_t)tmpSz, "%s%s%s, ", buf, eqStr, nameStr) >= tmpSz) { WOLFSSL_MSG("buffer overrun"); @@ -13129,17 +13142,17 @@ int wolfSSL_X509_NAME_print_ex(WOLFSSL_BIO* bio, WOLFSSL_X509_NAME* name, return WOLFSSL_FAILURE; } - tmpSz = len + nameStrSz + 3; /* 3 for '=', comma space */ + tmpSz = len + nameStrSz + 3 + eqSpace; /* 3 for '=', comma space */ } else { - if (XSNPRINTF(tmp, (size_t)tmpSz, "%s=%s", buf, nameStr) + if (XSNPRINTF(tmp, (size_t)tmpSz, "%s%s%s", buf, eqStr, nameStr) >= tmpSz) { WOLFSSL_MSG("buffer overrun"); XFREE(tmp, NULL, DYNAMIC_TYPE_TMP_BUFFER); return WOLFSSL_FAILURE; } - tmpSz = len + nameStrSz + 1; /* 1 for '=' */ + tmpSz = len + nameStrSz + 1 + eqSpace; /* 1 for '=' */ if (bio->type != WOLFSSL_BIO_FILE && bio->type != WOLFSSL_BIO_MEMORY) ++tmpSz; /* include the terminating null when not writing to a * file. diff --git a/tests/api.c b/tests/api.c index 2d433527c6..b42f5c9ebd 100644 --- a/tests/api.c +++ b/tests/api.c @@ -11311,6 +11311,31 @@ static int test_wolfSSL_UseMaxFragment(void) wolfSSL_free(ssl); wolfSSL_CTX_free(ctx); + +#if defined(OPENSSL_EXTRA) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) + /* check negotiated max fragment size */ + { + WOLFSSL *ssl_c = NULL; + WOLFSSL *ssl_s = NULL; + struct test_memio_ctx test_ctx; + WOLFSSL_CTX *ctx_c = NULL; + WOLFSSL_CTX *ctx_s = NULL; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0); + ExpectIntEQ(wolfSSL_UseMaxFragment(ssl_c, WOLFSSL_MFL_2_8), + WOLFSSL_SUCCESS); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectIntEQ(SSL_SESSION_get_max_fragment_length( + wolfSSL_get_session(ssl_c)), WOLFSSL_MFL_2_8); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + } +#endif #endif /* !NO_WOLFSSL_CLIENT || !NO_WOLFSSL_SERVER */ #endif return EXPECT_RESULT(); @@ -35030,6 +35055,7 @@ static int test_wolfSSL_X509_NAME_print_ex(void) X509_NAME* name = NULL; const char* expNormal = "C=US, CN=wolfssl.com"; + const char* expEqSpace = "C = US, CN = wolfssl.com"; const char* expReverse = "CN=wolfssl.com, C=US"; const char* expNotEscaped = "C= US,+\"\\ , CN=#wolfssl.com<>;"; @@ -35087,6 +35113,17 @@ static int test_wolfSSL_X509_NAME_print_ex(void) BIO_free(membio); membio = NULL; + /* Test with XN_FLAG_ONELINE which should enable XN_FLAG_SPC_EQ for + spaces aroun '=' */ + ExpectNotNull(membio = BIO_new(BIO_s_mem())); + ExpectIntEQ(X509_NAME_print_ex(membio, name, 0, XN_FLAG_ONELINE), + WOLFSSL_SUCCESS); + ExpectIntGE((memSz = BIO_get_mem_data(membio, &mem)), 0); + ExpectIntEQ(memSz, XSTRLEN(expEqSpace)); + ExpectIntEQ(XSTRNCMP((char*)mem, expEqSpace, XSTRLEN(expEqSpace)), 0); + BIO_free(membio); + membio = NULL; + /* Test flags: XN_FLAG_RFC2253 - should be reversed */ ExpectNotNull(membio = BIO_new(BIO_s_mem())); ExpectIntEQ(X509_NAME_print_ex(membio, name, 0, @@ -49863,6 +49900,7 @@ static int test_wolfSSL_CTX_sess_set_remove_cb(void) /* Both should have been allocated */ ExpectIntEQ(clientSessRemCountMalloc, 1); ExpectIntEQ(serverSessRemCountMalloc, 1); + /* This should not be called yet. Session wasn't evicted from cache yet. */ ExpectIntEQ(clientSessRemCountFree, 0); #if (defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET)) || \ @@ -49889,7 +49927,6 @@ static int test_wolfSSL_CTX_sess_set_remove_cb(void) ExpectIntEQ(SSL_CTX_remove_session(serverSessCtx, serverSess), 0); ExpectNull(SSL_SESSION_get_ex_data(serverSess, serverSessRemIdx)); ExpectIntEQ(serverSessRemCountFree, 1); - /* Need to free the references that we kept */ SSL_CTX_free(serverSessCtx); SSL_SESSION_free(serverSess); @@ -65220,8 +65257,15 @@ static int test_stubs_are_stubs(void) CHECKZERO_RET(wolfSSL_CTX_sess_misses, ctx, ctxN); CHECKZERO_RET(wolfSSL_CTX_sess_timeouts, ctx, ctxN); + /* when implemented this should take WOLFSSL object insted, right now + * always returns 0 */ + ExpectIntEQ(SSL_get_current_expansion(NULL), 0); + wolfSSL_CTX_free(ctx); ctx = NULL; + + ExpectStrEQ(SSL_COMP_get_name(NULL), "not supported"); + ExpectIntEQ(SSL_get_current_expansion(), 0); #endif /* OPENSSL_EXTRA && !NO_WOLFSSL_STUB && (!NO_WOLFSSL_CLIENT || * !NO_WOLFSSL_SERVER) */ return EXPECT_RESULT(); @@ -69055,6 +69099,7 @@ static int test_wolfSSL_dtls_stateless_maxfrag(void) /* CH without cookie shouldn't change state */ ExpectIntEQ(ssl_s->max_fragment, max_fragment); ExpectIntNE(test_ctx.c_len, 0); + /* consume HRR from buffer */ test_ctx.c_len = 0; ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 57a246d301..dea087739b 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -4474,6 +4474,10 @@ struct WOLFSSL_SESSION { #endif #ifdef HAVE_EX_DATA WOLFSSL_CRYPTO_EX_DATA ex_data; +#endif +#ifdef HAVE_MAX_FRAGMENT + byte mfl; /* max fragment length negotiated i.e. + * WOLFSSL_MFL_2_8 (6) */ #endif byte isSetup:1; }; diff --git a/wolfssl/openssl/ssl.h b/wolfssl/openssl/ssl.h index 94f97ecf27..0fbf621b7d 100644 --- a/wolfssl/openssl/ssl.h +++ b/wolfssl/openssl/ssl.h @@ -367,6 +367,8 @@ typedef STACK_OF(ACCESS_DESCRIPTION) AUTHORITY_INFO_ACCESS; #define SSL_SESSION_dup wolfSSL_SESSION_dup #define SSL_SESSION_free wolfSSL_SESSION_free #define SSL_SESSION_set_cipher wolfSSL_SESSION_set_cipher +#define SSL_SESSION_get_max_fragment_length \ + wolfSSL_SESSION_get_max_fragment_length #define SSL_is_init_finished wolfSSL_is_init_finished #define SSL_SESSION_set1_id wolfSSL_SESSION_set1_id @@ -834,6 +836,10 @@ wolfSSL_X509_STORE_set_verify_cb((WOLFSSL_X509_STORE *)(s), (WOLFSSL_X509_STORE_ #define COMP_rle wolfSSL_COMP_rle #define SSL_COMP_add_compression_method wolfSSL_COMP_add_compression_method +#define SSL_get_current_compression(ssl) 0 +#define SSL_get_current_expansion(ssl) 0 +#define SSL_COMP_get_name wolfSSL_COMP_get_name + #define SSL_get_ex_new_index wolfSSL_get_ex_new_index #define RSA_get_ex_new_index wolfSSL_get_ex_new_index @@ -1227,6 +1233,7 @@ typedef WOLFSSL_SRTP_PROTECTION_PROFILE SRTP_PROTECTION_PROFILE; #define TLSEXT_STATUSTYPE_ocsp 1 +#define TLSEXT_max_fragment_length_DISABLED WOLFSSL_MFL_DISABLED #define TLSEXT_max_fragment_length_512 WOLFSSL_MFL_2_9 #define TLSEXT_max_fragment_length_1024 WOLFSSL_MFL_2_10 #define TLSEXT_max_fragment_length_2048 WOLFSSL_MFL_2_11 diff --git a/wolfssl/openssl/x509.h b/wolfssl/openssl/x509.h index a603ce681f..9afb8e01c1 100644 --- a/wolfssl/openssl/x509.h +++ b/wolfssl/openssl/x509.h @@ -50,7 +50,6 @@ #define X509_FLAG_NO_IDS (1UL << 12) #define XN_FLAG_FN_SN 0 -#define XN_FLAG_ONELINE 0 #define XN_FLAG_COMPAT 0 #define XN_FLAG_RFC2253 1 #define XN_FLAG_SEP_COMMA_PLUS (1 << 16) @@ -68,6 +67,7 @@ #define XN_FLAG_FN_ALIGN (1 << 25) #define XN_FLAG_MULTILINE 0xFFFF +#define XN_FLAG_ONELINE (XN_FLAG_SEP_CPLUS_SPC | XN_FLAG_SPC_EQ | XN_FLAG_FN_SN) /* * All of these aren't actually used in wolfSSL. Some are included to diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index eb5e9a8afc..d5efa358fd 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -1682,6 +1682,11 @@ WOLFSSL_API int wolfSSL_set_session_id_context(WOLFSSL* ssl, const unsigned cha WOLFSSL_API void wolfSSL_set_connect_state(WOLFSSL* ssl); WOLFSSL_API void wolfSSL_set_accept_state(WOLFSSL* ssl); WOLFSSL_API int wolfSSL_session_reused(WOLFSSL* ssl); +#ifdef OPENSSL_EXTRA +/* using unsigned char instead of uint8_t here to avoid stdint include */ +WOLFSSL_API unsigned char wolfSSL_SESSION_get_max_fragment_length( + WOLFSSL_SESSION* session); +#endif WOLFSSL_API int wolfSSL_SESSION_up_ref(WOLFSSL_SESSION* session); WOLFSSL_API WOLFSSL_SESSION* wolfSSL_SESSION_dup(WOLFSSL_SESSION* session); WOLFSSL_API WOLFSSL_SESSION* wolfSSL_SESSION_new(void); @@ -3917,6 +3922,7 @@ WOLFSSL_API int wolfSSL_ALPN_FreePeerProtocol(WOLFSSL* ssl, char **list); /* Fragment lengths */ enum { + WOLFSSL_MFL_DISABLED = 0, WOLFSSL_MFL_2_9 = 1, /* 512 bytes */ WOLFSSL_MFL_2_10 = 2, /* 1024 bytes */ WOLFSSL_MFL_2_11 = 3, /* 2048 bytes */ @@ -5201,6 +5207,7 @@ WOLFSSL_API int wolfSSL_i2a_ASN1_OBJECT(WOLFSSL_BIO *bp, WOLFSSL_ASN1_OBJECT *a) WOLFSSL_API int wolfSSL_i2d_ASN1_OBJECT(WOLFSSL_ASN1_OBJECT *a, unsigned char **pp); WOLFSSL_API void SSL_CTX_set_tmp_dh_callback(WOLFSSL_CTX *ctx, WOLFSSL_DH *(*dh) (WOLFSSL *ssl, int is_export, int keylength)); WOLFSSL_API WOLF_STACK_OF(SSL_COMP) *SSL_COMP_get_compression_methods(void); +WOLFSSL_API const char* wolfSSL_COMP_get_name(const void* comp); WOLFSSL_API int wolfSSL_X509_STORE_load_locations(WOLFSSL_X509_STORE *str, const char *file, const char *dir); WOLFSSL_API int wolfSSL_X509_STORE_add_crl(WOLFSSL_X509_STORE *ctx, WOLFSSL_X509_CRL *x); WOLFSSL_API int wolfSSL_sk_SSL_CIPHER_num(const WOLF_STACK_OF(WOLFSSL_CIPHER)* p);