diff --git a/.github/workflows/nginx.yml b/.github/workflows/nginx.yml index cc67610f2b..b480be4947 100644 --- a/.github/workflows/nginx.yml +++ b/.github/workflows/nginx.yml @@ -12,6 +12,10 @@ concurrency: cancel-in-progress: true # END OF COMMON SECTION +# clang has better sanitizer support +env: + CC: clang + jobs: build_wolfssl: name: Build wolfSSL @@ -31,7 +35,8 @@ jobs: uses: wolfSSL/actions-build-autotools-project@v1 with: path: wolfssl - configure: --enable-nginx ${{ env.wolf_debug_flags }} + configure: >- + --enable-nginx --enable-curve25519 --enable-ed25519 ${{ env.wolf_debug_flags }} install: true - name: tar build-dir @@ -50,6 +55,41 @@ jobs: matrix: include: # in general we want to pass all tests that match *ssl* + - ref: 1.28.1 + test-ref: 0fccfcef1278263416043e0bbb3e0116b84026e4 + # Following tests pass with sanitizer on + sanitize-ok: >- + h2_ssl_proxy_cache.t h2_ssl.t h2_ssl_variables.t + h2_ssl_verify_client.t mail_imap_ssl.t mail_ssl_session_reuse.t + mail_ssl.t proxy_ssl_certificate_cache.t + proxy_ssl_certificate_empty.t proxy_ssl_certificate.t + proxy_ssl_certificate_vars.t proxy_ssl_name.t ssl_cache_reload.t + ssl_certificate_aux.t ssl_certificate_cache.t + ssl_certificate_chain.t ssl_certificates.t ssl_certificate.t + ssl_client_escaped_cert.t ssl_crl.t ssl_curve.t ssl_ocsp.t + ssl_password_file.t ssl_proxy_upgrade.t ssl_reject_handshake.t + ssl_session_reuse.t ssl_session_ticket_key.t ssl_sni_protocols.t + ssl_sni_reneg.t ssl_sni_sessions.t ssl_sni.t ssl_stapling.t ssl.t + ssl_verify_client.t ssl_verify_client_trusted.t ssl_verify_depth.t + stream_proxy_ssl_certificate_cache.t stream_proxy_ssl_certificate.t + stream_proxy_ssl_certificate_vars.t + stream_proxy_ssl_name_complex.t stream_proxy_ssl_name.t + stream_ssl_alpn.t stream_ssl_certificate_cache.t + stream_ssl_certificate.t stream_ssl_ocsp.t stream_ssl_preread_alpn.t + stream_ssl_preread_protocol.t stream_ssl_preread.t + stream_ssl_reject_handshake.t stream_ssl_session_reuse.t + stream_ssl_sni_protocols.t stream_ssl_stapling.t stream_ssl.t + stream_ssl_variables.t stream_ssl_verify_client.t + stream_upstream_zone_ssl.t upstream_zone_ssl.t + uwsgi_ssl_certificate.t uwsgi_ssl_certificate_vars.t + # Following tests do not pass with sanitizer on (with OpenSSL too) + sanitize-not-ok: >- + grpc_ssl.t h2_proxy_request_buffering_ssl.t h2_proxy_ssl.t + proxy_request_buffering_ssl.t proxy_ssl_conf_command.t + proxy_ssl_keepalive.t proxy_ssl.t proxy_ssl_verify.t ssl_cache.t + stream_proxy_protocol_ssl.t stream_proxy_ssl_conf_command.t + stream_proxy_ssl.t stream_proxy_ssl_verify.t + - ref: 1.25.0 test-ref: 5b2894ea1afd01a26c589ce11f310df118e42592 # Following tests pass with sanitizer on @@ -120,35 +160,26 @@ jobs: - name: untar build-dir run: tar -xf build-dir.tgz - - name: Install dependencies - run: | - sudo cpan -iT Proc::Find + - name: Openssl version + run: openssl version -a - # Locking in the version of SSLeay used with testing - - name: Download and install Net::SSLeay 1.94 manually - run: | - curl -LO https://www.cpan.org/modules/by-module/Net/CHRISN/Net-SSLeay-1.94.tar.gz - tar -xzf Net-SSLeay-1.94.tar.gz - cd Net-SSLeay-1.94 - perl Makefile.PL - make - sudo make install + - name: Setup Perl environment + uses: shogo82148/actions-setup-perl@v1 + with: + perl-version: '5.38.2' # SSL version 2.091 changes '' return to undef causing test case to fail. # Locking in the test version to use as 2.090 - - name: Download and install IO::Socket::SSL 2.090 manually + - name: Install dependencies run: | - curl -LO https://www.cpan.org/modules/by-module/IO/IO-Socket-SSL-2.090.tar.gz - tar -xzf IO-Socket-SSL-2.090.tar.gz - cd IO-Socket-SSL-2.090 - perl Makefile.PL - make - sudo make install + cpanm --notest Proc::Find Net::SSLeay@1.94 IO::Socket::SSL@2.090 - name: Checkout wolfssl-nginx uses: actions/checkout@v4 with: - repository: wolfssl/wolfssl-nginx +# TODO fix this + repository: julek-wolfssl/wolfssl-nginx + ref: 1.28.0 path: wolfssl-nginx - name: Checkout nginx @@ -211,17 +242,14 @@ jobs: run: | echo "nginx_c_flags=-O0" >> $GITHUB_ENV - - name: workaround high-entropy ASLR - # not needed after either an update to llvm or runner is done - run: sudo sysctl vm.mmap_rnd_bits=28 - - name: Build nginx with sanitizer working-directory: nginx run: | ./auto/configure --with-wolfssl=$GITHUB_WORKSPACE/build-dir --with-http_ssl_module \ --with-stream --with-stream_ssl_module --with-stream_ssl_preread_module \ --with-http_v2_module --with-mail --with-mail_ssl_module \ - --with-cc-opt='-fsanitize=address -DNGX_DEBUG_PALLOC=1 -g3 ${{ env.nginx_c_flags }}' \ + --with-cc-opt='-fsanitize=address -DNGX_DEBUG_PALLOC=1 -g3 \ + ${{ env.nginx_c_flags }}' \ --with-ld-opt='-fsanitize=address ${{ env.nginx_c_flags }}' make -j @@ -229,19 +257,16 @@ jobs: working-directory: nginx run: ldd objs/nginx | grep wolfssl - - if: ${{ runner.debug }} - name: Run nginx-tests with sanitizer (debug) + - name: Create LSAN suppression file working-directory: nginx-tests run: | - LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$GITHUB_WORKSPACE/build-dir/lib \ - TMPDIR=$GITHUB_WORKSPACE TEST_NGINX_VERBOSE=y TEST_NGINX_CATLOG=y \ - TEST_NGINX_BINARY=../nginx/objs/nginx prove -v ${{ matrix.sanitize-ok }} + echo "leak:ngx_worker_process_init" > lsan.supp - if: ${{ !runner.debug }} name: Run nginx-tests with sanitizer working-directory: nginx-tests run: | LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$GITHUB_WORKSPACE/build-dir/lib \ + LSAN_OPTIONS=suppressions=$GITHUB_WORKSPACE/nginx-tests/lsan.supp \ TMPDIR=$GITHUB_WORKSPACE TEST_NGINX_BINARY=../nginx/objs/nginx \ prove ${{ matrix.sanitize-ok }} - diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index af5a97f080..b9b908fa5a 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -357,6 +357,7 @@ NO_ASM NO_ASN_OLD_TYPE_NAMES NO_CAMELLIA_CBC NO_CERT +NO_CERT_IN_TICKET NO_CIPHER_SUITE_ALIASES NO_CLIENT_CACHE NO_CLOCK_SPEEDUP diff --git a/configure.ac b/configure.ac index e248005e0b..9e15f32ad1 100644 --- a/configure.ac +++ b/configure.ac @@ -2652,7 +2652,8 @@ if test "$ENABLED_LIBWEBSOCKETS" = "yes" || test "$ENABLED_OPENVPN" = "yes" || \ test "$ENABLED_OPENRESTY" = "yes" || test "$ENABLED_RSYSLOG" = "yes" || \ test "$ENABLED_KRB" = "yes" || test "$ENABLED_CHRONY" = "yes" || \ test "$ENABLED_FFMPEG" = "yes" || test "$ENABLED_STRONGSWAN" = "yes" || \ - test "$ENABLED_OPENLDAP" = "yes" || test "x$ENABLED_MOSQUITTO" = "xyes" || test "$ENABLED_HITCH" = "yes" + test "$ENABLED_OPENLDAP" = "yes" || test "x$ENABLED_MOSQUITTO" = "xyes" || \ + test "$ENABLED_HITCH" = "yes" || test "$ENABLED_NGINX" = "yes" then ENABLED_OPENSSLALL="yes" fi diff --git a/src/bio.c b/src/bio.c index 8321dabbd3..f9e8140620 100644 --- a/src/bio.c +++ b/src/bio.c @@ -1938,6 +1938,8 @@ int wolfSSL_BIO_get_len(WOLFSSL_BIO *bio) len = BAD_FUNC_ARG; if (len == 0) { len = wolfssl_file_len(file, &memSz); + if (len == WC_NO_ERR_TRACE(WOLFSSL_BAD_FILETYPE)) + len = 0; } if (len == 0) { len = (int)memSz; diff --git a/src/crl.c b/src/crl.c index 85cd71b365..003b439065 100644 --- a/src/crl.c +++ b/src/crl.c @@ -1128,6 +1128,28 @@ WOLFSSL_X509_CRL* wolfSSL_X509_CRL_dup(const WOLFSSL_X509_CRL* crl) return ret; } +#ifdef OPENSSL_ALL +int wolfSSL_X509_CRL_up_ref(WOLFSSL_X509_CRL* crl) +{ + int ret; + + if (crl == NULL) + return WOLFSSL_FAILURE; + + wolfSSL_RefInc(&crl->ref, &ret); +#ifdef WOLFSSL_REFCNT_ERROR_RETURN + if (ret != 0) { + WOLFSSL_MSG("Failed to lock x509 mutex"); + return WOLFSSL_FAILURE; + } +#else + (void)ret; +#endif + + return WOLFSSL_SUCCESS; +} +#endif + /* returns WOLFSSL_SUCCESS on success. Does not take ownership of newcrl */ int wolfSSL_X509_STORE_add_crl(WOLFSSL_X509_STORE *store, WOLFSSL_X509_CRL *newcrl) { diff --git a/src/dtls.c b/src/dtls.c index dff1ffab3a..1028f9b115 100644 --- a/src/dtls.c +++ b/src/dtls.c @@ -403,8 +403,9 @@ static int TlsTicketIsValid(const WOLFSSL* ssl, WolfSSL_ConstVector exts, if (!IsAtLeastTLSv1_3(it->pv)) *resume = TRUE; } - if (it != NULL) - ForceZero(it, sizeof(InternalTicket)); + /* `it` points into tempTicket on successful decryption so clearing it will + * also satisfy the WOLFSSL_CHECK_MEM_ZERO check. */ + ForceZero(tempTicket, SESSION_TICKET_LEN); return 0; } #endif /* HAVE_SESSION_TICKET */ diff --git a/src/internal.c b/src/internal.c index 74f59faff9..dbbc5e5709 100644 --- a/src/internal.c +++ b/src/internal.c @@ -12190,12 +12190,16 @@ static int GetRecordHeader(WOLFSSL* ssl, word32* inOutIdx, /* record layer length check */ #ifdef HAVE_MAX_FRAGMENT - if (*size > (ssl->max_fragment + MAX_COMP_EXTRA + MAX_MSG_EXTRA)) { + if (*size > (ssl->max_fragment + MAX_MSG_EXTRA + + (ssl->options.usingCompression ? MAX_COMP_EXTRA : 0))) { + WOLFSSL_MSG_EX("Record length %d exceeds max fragment size", *size); WOLFSSL_ERROR_VERBOSE(LENGTH_ERROR); return LENGTH_ERROR; } #else - if (*size > (MAX_RECORD_SIZE + MAX_COMP_EXTRA + MAX_MSG_EXTRA)) { + if (*size > (MAX_RECORD_SIZE + MAX_MSG_EXTRA + + (ssl->options.usingCompression ? MAX_COMP_EXTRA : 0))) { + WOLFSSL_MSG_EX("Record length %d exceeds max record size", *size); WOLFSSL_ERROR_VERBOSE(LENGTH_ERROR); return LENGTH_ERROR; } @@ -38811,9 +38815,15 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) int error; word32 itHash = 0; byte zeros[WOLFSSL_TICKET_MAC_SZ]; /* biggest cmp size */ + int internalTicketSz; + byte* mac; +#if defined(OPENSSL_ALL) && defined(KEEP_PEER_CERT) && \ + !defined(NO_CERT_IN_TICKET) + word16 peerCertSz = 0; +#endif + WOLFSSL_ASSERT_GE(sizeof(ssl->session->staticTicket), WOLFSSL_TICKET_ENC_SZ); WOLFSSL_ASSERT_SIZEOF_GE(ssl->session->staticTicket, *et); - WOLFSSL_ASSERT_SIZEOF_GE(et->enc_ticket, *it); if (ssl->session->ticket != ssl->session->staticTicket) { /* Always use the static ticket buffer */ @@ -38829,7 +38839,7 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) if (ssl->error != WC_NO_ERR_TRACE(WC_PENDING_E)) #endif { - XMEMSET(et, 0, sizeof(*et)); + XMEMSET(ssl->session->ticket, 0, SESSION_TICKET_LEN); } /* build internal */ @@ -38893,6 +38903,55 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) XMEMCPY(it->sessionCtx, ssl->sessionCtx, ID_LEN); #endif +#if defined(OPENSSL_ALL) && defined(KEEP_PEER_CERT) && \ + !defined(NO_CERT_IN_TICKET) + /* Store peer certificate in ticket for session resumption. + * Try ssl->peerCert first, then ssl->session->chain as fallback. + * Skip for DTLS to keep ticket size small for MTU constraints. */ + if (ssl->options.dtls) { + c16toa(0, it->peerCertLen); + peerCertSz = 0; + } + else { + const byte* certDer = NULL; + word32 certDerSz = 0; + + if (ssl->peerCert.derCert != NULL && + ssl->peerCert.derCert->length > 0) { + /* Use current peer certificate */ + certDer = ssl->peerCert.derCert->buffer; + certDerSz = ssl->peerCert.derCert->length; + } +#ifdef SESSION_CERTS + else if (ssl->session->chain.count > 0) { + /* Use peer certificate from session chain */ + certDer = ssl->session->chain.certs[0].buffer; + certDerSz = ssl->session->chain.certs[0].length; + } +#endif + + if (certDer != NULL && certDerSz > 0 && + certDerSz <= MAX_TICKET_PEER_CERT_SZ && +#ifdef HAVE_MAX_FRAGMENT + /* We don't support fragmentation in + * SendTls13NewSessionTicket yet. */ + (!IsAtLeastTLSv1_3(ssl->version) || + ssl->max_fragment == MAX_RECORD_SIZE) +#endif + ) { + c16toa((word16)certDerSz, it->peerCertLen); + XMEMCPY(it->peerCert, certDer, certDerSz); + peerCertSz = (word16)certDerSz; + } + else { + if (certDerSz > MAX_TICKET_PEER_CERT_SZ) + WOLFSSL_MSG("Peer cert too large for ticket, skipping"); + c16toa(0, it->peerCertLen); + peerCertSz = 0; + } + } +#endif + #ifdef WOLFSSL_TICKET_HAVE_ID { const byte* id = NULL; @@ -38905,6 +38964,16 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) } #endif + /* Calculate actual internal ticket size */ +#if defined(OPENSSL_ALL) && defined(KEEP_PEER_CERT) && \ + !defined(NO_CERT_IN_TICKET) + internalTicketSz = (int)(WOLFSSL_INTERNAL_TICKET_BASE_SZ + peerCertSz); +#else + internalTicketSz = (int)WOLFSSL_INTERNAL_TICKET_BASE_SZ; +#endif + /* MAC is placed after the encrypted data */ + mac = et->enc_ticket + WOLFSSL_TICKET_ENC_SZ; + /* encrypt */ encLen = WOLFSSL_TICKET_ENC_SZ; /* max size user can use */ if (ssl->ctx->ticketEncCb == NULL @@ -38921,10 +38990,10 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) ret = BAD_TICKET_ENCRYPT; } else { - itHash = HashObject((byte*)it, sizeof(*it), &error); + itHash = HashObject((byte*)it, (word32)internalTicketSz, &error); if (error == 0) { - ret = ssl->ctx->ticketEncCb(ssl, et->key_name, et->iv, et->mac, - 1, et->enc_ticket, WOLFSSL_INTERNAL_TICKET_LEN, &encLen, + ret = ssl->ctx->ticketEncCb(ssl, et->key_name, et->iv, mac, + 1, et->enc_ticket, internalTicketSz, &encLen, SSL_TICKET_CTX(ssl)); } else { @@ -38939,7 +39008,7 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) #endif goto error; } - if (encLen < (int)WOLFSSL_INTERNAL_TICKET_LEN || + if (encLen < internalTicketSz || encLen > (int)WOLFSSL_TICKET_ENC_SZ) { WOLFSSL_MSG("Bad user ticket encrypt size"); ret = BAD_TICKET_KEY_CB_SZ; @@ -38948,7 +39017,8 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) /* sanity checks on encrypt callback */ /* internal ticket can't be the same if encrypted */ - if (itHash == HashObject((byte*)it, sizeof(*it), &error) || error != 0) + if (itHash == HashObject((byte*)it, (word32)internalTicketSz, &error) || + error != 0) { WOLFSSL_MSG("User ticket encrypt didn't encrypt or hash failed"); ret = BAD_TICKET_ENCRYPT; @@ -38972,7 +39042,7 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) } /* mac */ - if (XMEMCMP(et->mac, zeros, WOLFSSL_TICKET_MAC_SZ) == 0) { + if (XMEMCMP(mac, zeros, WOLFSSL_TICKET_MAC_SZ) == 0) { WOLFSSL_MSG("User ticket encrypt didn't set mac"); ret = BAD_TICKET_ENCRYPT; goto error; @@ -38982,7 +39052,7 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) c16toa((word16)encLen, et->enc_len); if (encLen < (int)WOLFSSL_TICKET_ENC_SZ) { /* move mac up since whole enc buffer not used */ - XMEMMOVE(et->enc_ticket + encLen, et->mac, + XMEMMOVE(et->enc_ticket + encLen, mac, WOLFSSL_TICKET_MAC_SZ); } ssl->session->ticketLen = @@ -38992,11 +39062,12 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) error: #ifdef WOLFSSL_CHECK_MEM_ZERO /* Ticket has sensitive data in it now. */ - wc_MemZero_Add("Create Ticket internal", it, sizeof(InternalTicket)); + wc_MemZero_Add("Create Ticket internal", it, + WOLFSSL_INTERNAL_TICKET_MAX_SZ); #endif - ForceZero(it, sizeof(*it)); + ForceZero(it, WOLFSSL_INTERNAL_TICKET_MAX_SZ); #ifdef WOLFSSL_CHECK_MEM_ZERO - wc_MemZero_Check(it, sizeof(InternalTicket)); + wc_MemZero_Check(it, WOLFSSL_INTERNAL_TICKET_MAX_SZ); #endif WOLFSSL_ERROR_VERBOSE(ret); return ret; @@ -39047,7 +39118,7 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) } else { /* Callback uses ssl without const but for DTLS, it really shouldn't - * modify its state. */ + * modify its state. MAC is located after encrypted data. */ ret = ssl->ctx->ticketEncCb((WOLFSSL*)ssl, et->key_name, et->iv, et->enc_ticket + inLen, 0, et->enc_ticket, inLen, &outLen, @@ -39272,6 +39343,49 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) ato16(it->namedGroup, &ssl->session->namedGroup); #endif } + +#if defined(OPENSSL_ALL) && defined(KEEP_PEER_CERT) && \ + !defined(NO_CERT_IN_TICKET) + /* Restore peer certificate from ticket to session chain and peerCert */ + { + word16 peerCertLen = 0; + ato16(it->peerCertLen, &peerCertLen); + + if (peerCertLen > 0 && peerCertLen <= MAX_TICKET_PEER_CERT_SZ) { +#ifdef SESSION_CERTS + /* Clear existing chain and add the peer certificate */ + ssl->session->chain.count = 0; + AddSessionCertToChain(&ssl->session->chain, + it->peerCert, peerCertLen); +#endif + /* Also decode into ssl->peerCert for direct access */ + { + int ret; + DecodedCert* dCert; + + dCert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), ssl->heap, + DYNAMIC_TYPE_DCERT); + if (dCert != NULL) { + InitDecodedCert(dCert, it->peerCert, peerCertLen, ssl->heap); + ret = ParseCertRelative(dCert, CERT_TYPE, 0, NULL, NULL); + if (ret == 0) { + FreeX509(&ssl->peerCert); + InitX509(&ssl->peerCert, 0, ssl->heap); + ret = CopyDecodedToX509(&ssl->peerCert, dCert); + if (ret != 0) { + /* Failed to copy - clear peerCert */ + FreeX509(&ssl->peerCert); + InitX509(&ssl->peerCert, 0, ssl->heap); + } + } + FreeDecodedCert(dCert); + XFREE(dCert, ssl->heap, DYNAMIC_TYPE_DCERT); + } + } + } + } +#endif + ssl->version.minor = it->pv.minor; } @@ -39316,6 +39430,23 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) #ifdef OPENSSL_EXTRA it->sessionCtxSz = sess->sessionCtxSz; XMEMCPY(it->sessionCtx, sess->sessionCtx, sess->sessionCtxSz); +#endif +#if defined(OPENSSL_ALL) && defined(KEEP_PEER_CERT) && \ + defined(SESSION_CERTS) && !defined(NO_CERT_IN_TICKET) + /* Store peer certificate from session chain */ + if (sess->chain.count > 0) { + word32 certLen = sess->chain.certs[0].length; + if (certLen <= MAX_TICKET_PEER_CERT_SZ) { + c16toa((word16)certLen, it->peerCertLen); + XMEMCPY(it->peerCert, sess->chain.certs[0].buffer, certLen); + } + else { + c16toa(0, it->peerCertLen); + } + } + else { + c16toa(0, it->peerCertLen); + } #endif } @@ -39386,9 +39517,10 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) byte* tmp; WOLFSSL_MSG("Found session matching the session id" " found in the ticket"); - /* Allocate and populate an InternalTicket */ + /* Allocate and populate an InternalTicket. Need max size + * because PopulateInternalTicketFromSession may write peer cert */ #ifdef WOLFSSL_NO_REALLOC - tmp = (byte*)XMALLOC(sizeof(InternalTicket), ssl->heap, + tmp = (byte*)XMALLOC(WOLFSSL_INTERNAL_TICKET_MAX_SZ, ssl->heap, DYNAMIC_TYPE_TLSX); if (tmp != NULL && psk->identity != NULL) { @@ -39397,13 +39529,13 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) psk->identity = NULL; } #else - tmp = (byte*)XREALLOC(psk->identity, sizeof(InternalTicket), + tmp = (byte*)XREALLOC(psk->identity, WOLFSSL_INTERNAL_TICKET_MAX_SZ, ssl->heap, DYNAMIC_TYPE_TLSX); #endif if (tmp != NULL) { - XMEMSET(tmp, 0, sizeof(InternalTicket)); + XMEMSET(tmp, 0, WOLFSSL_INTERNAL_TICKET_MAX_SZ); psk->identity = tmp; - psk->identityLen = sizeof(InternalTicket); + psk->identityLen = WOLFSSL_INTERNAL_TICKET_MAX_SZ; psk->it = (InternalTicket*)tmp; PopulateInternalTicketFromSession(sess, psk->it); decryptRet = WOLFSSL_TICKET_RET_OK; @@ -39438,8 +39570,8 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) } #ifdef WOLFSSL_CHECK_MEM_ZERO /* Internal ticket successfully decrypted. */ - wc_MemZero_Add("Do Client Ticket internal", psk->it, - sizeof(InternalTicket)); + wc_MemZero_Add("Do Client Ticket internal", psk->identity, + psk->identityLen); #endif ret = DoClientTicketCheckVersion(ssl, psk->it); @@ -39447,7 +39579,7 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) psk->decryptRet = PSK_DECRYPT_FAIL; ForceZero(psk->identity, psk->identityLen); #ifdef WOLFSSL_CHECK_MEM_ZERO - wc_MemZero_Check(psk->it, sizeof(InternalTicket)); + wc_MemZero_Check(psk->it, psk->identityLen); #endif WOLFSSL_LEAVE("DoClientTicket_ex", ret); return ret; @@ -39464,7 +39596,13 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) int ret; InternalTicket* it = NULL; #ifdef WOLFSSL_TLS13 - InternalTicket staticIt; + /* Static buffer for stateful tickets - need max size for peer cert */ + #ifdef WOLFSSL_SMALL_STACK + byte* staticItBuf = NULL; + #else + byte staticItBuf[WOLFSSL_INTERNAL_TICKET_MAX_SZ]; + #endif + InternalTicket* staticIt = NULL; const WOLFSSL_SESSION* sess = NULL; psk_sess_free_cb_ctx freeCtx; @@ -39496,18 +39634,27 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) * stateless tickets are much longer. */ sess = GetSesionFromCacheOrExt(ssl, input, &freeCtx); if (sess != NULL) { - it = &staticIt; - XMEMSET(it, 0, sizeof(InternalTicket)); + #ifdef WOLFSSL_SMALL_STACK + staticItBuf = (byte*)XMALLOC(WOLFSSL_INTERNAL_TICKET_MAX_SZ, + ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (staticItBuf == NULL) { + decryptRet = WOLFSSL_TICKET_RET_FATAL; + goto cleanup; + } + #endif + staticIt = (InternalTicket*)staticItBuf; + it = staticIt; + XMEMSET(it, 0, WOLFSSL_INTERNAL_TICKET_MAX_SZ); PopulateInternalTicketFromSession(sess, it); decryptRet = WOLFSSL_TICKET_RET_OK; } } else #endif - if (len >= sizeof(*it)) + if (len >= WOLFSSL_INTERNAL_TICKET_LEN + WOLFSSL_TICKET_FIXED_SZ) decryptRet = DoDecryptTicket(ssl, input, len, &it); else - WOLFSSL_MSG("Ticket is smaller than InternalTicket. Rejecting."); + WOLFSSL_MSG("Ticket is smaller than minimum size. Rejecting."); if (decryptRet != WOLFSSL_TICKET_RET_OK && @@ -39516,8 +39663,10 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) goto cleanup; } #ifdef WOLFSSL_CHECK_MEM_ZERO - /* Internal ticket successfully decrypted. */ - wc_MemZero_Add("Do Client Ticket internal", it, sizeof(InternalTicket)); + /* Internal ticket successfully decrypted. Zero at least the minimum + * internal ticket size (contains master secret). */ + wc_MemZero_Add("Do Client Ticket internal", it, + WOLFSSL_INTERNAL_TICKET_LEN); #endif ret = DoClientTicketCheckVersion(ssl, it); @@ -39530,12 +39679,19 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) cleanup: if (it != NULL) { - ForceZero(it, sizeof(*it)); + /* Zero the minimum internal ticket size. The it pointer points into + * the input buffer which may be smaller than MAX_SZ. We use the + * minimum length (WOLFSSL_INTERNAL_TICKET_LEN) which is guaranteed + * to fit and contains the sensitive master secret. */ + ForceZero(it, WOLFSSL_INTERNAL_TICKET_LEN); #ifdef WOLFSSL_CHECK_MEM_ZERO - wc_MemZero_Check(it, sizeof(InternalTicket)); + wc_MemZero_Check(it, WOLFSSL_INTERNAL_TICKET_LEN); #endif } #ifdef WOLFSSL_TLS13 + #ifdef WOLFSSL_SMALL_STACK + XFREE(staticItBuf, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + #endif if (sess != NULL) FreeSessionFromCacheOrExt(ssl, sess, &freeCtx); #endif @@ -39551,10 +39707,7 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) psk->decryptRet = PSK_DECRYPT_NONE; ForceZero(psk->identity, psk->identityLen); #ifdef WOLFSSL_CHECK_MEM_ZERO - /* We want to check the InternalTicket area since that is what - * we registered in DoClientTicket_ex */ - wc_MemZero_Check((((ExternalTicket*)psk->identity)->enc_ticket), - sizeof(InternalTicket)); + wc_MemZero_Check(psk->identity, psk->identityLen); #endif } } @@ -39570,6 +39723,7 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) int sendSz; word32 length = SESSION_HINT_SZ + LENGTH_SZ; word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + word32 headerSz = 0; WOLFSSL_START(WC_FUNC_TICKET_SEND); WOLFSSL_ENTER("SendTicket"); @@ -39596,20 +39750,13 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) idx += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; #endif } + headerSz = idx; - if (IsEncryptionOn(ssl, 1) && ssl->options.handShakeDone) - sendSz += cipherExtraData(ssl); - - /* Set this in case CheckAvailableSize returns a WANT_WRITE so that state - * is not advanced yet */ - ssl->options.buildingMsg = 1; - - /* check for available size */ - if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) - return ret; + output = (byte*)XMALLOC(sendSz, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (output == NULL) + return MEMORY_E; /* get output buffer */ - output = GetOutputBuffer(ssl); AddHeaders(output, length, session_ticket, ssl); /* hint */ @@ -39624,45 +39771,9 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) XMEMCPY(output + idx, ssl->session->ticket, ssl->session->ticketLen); idx += ssl->session->ticketLen; - if (IsEncryptionOn(ssl, 1) && ssl->options.handShakeDone) { - byte* input; - int inputSz = (int)idx; /* build msg adds rec hdr */ - int recordHeaderSz = RECORD_HEADER_SZ; - - if (ssl->options.dtls) - recordHeaderSz += DTLS_RECORD_EXTRA; - inputSz -= recordHeaderSz; - input = (byte*)XMALLOC(inputSz, ssl->heap, DYNAMIC_TYPE_IN_BUFFER); - if (input == NULL) - return MEMORY_E; - - XMEMCPY(input, output + recordHeaderSz, inputSz); - sendSz = BuildMessage(ssl, output, sendSz, input, inputSz, - handshake, 1, 0, 0, CUR_ORDER); - XFREE(input, ssl->heap, DYNAMIC_TYPE_IN_BUFFER); - - if (sendSz < 0) - return sendSz; - } - else { - #ifdef WOLFSSL_DTLS - if (ssl->options.dtls) { - if ((ret = DtlsMsgPoolSave(ssl, output, (word32)sendSz, session_ticket)) != 0) - return ret; - - DtlsSEQIncrement(ssl, CUR_ORDER); - } - #endif - ret = HashOutput(ssl, output, sendSz, 0); - if (ret != 0) - return ret; - } - - ssl->buffers.outputBuffer.length += sendSz; - ssl->options.buildingMsg = 0; - - if (!ssl->options.groupMessages) - ret = SendBuffered(ssl); + ret = SendHandshakeMsg(ssl, output, idx - headerSz, session_ticket, + "Session Ticket"); + XFREE(output, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); WOLFSSL_LEAVE("SendTicket", ret); WOLFSSL_END(WC_FUNC_TICKET_SEND); @@ -40160,7 +40271,8 @@ static int DefTicketEncCb(WOLFSSL* ssl, byte key_name[WOLFSSL_TICKET_NAME_SZ], WOLFSSL_ENTER("DefTicketEncCb"); - if ((!enc) && (inLen != WOLFSSL_INTERNAL_TICKET_LEN)) { + /* For decryption, check minimum internal ticket size */ + if ((!enc) && (inLen < (int)WOLFSSL_INTERNAL_TICKET_LEN)) { return BUFFER_E; } diff --git a/src/ssl.c b/src/ssl.c index ff0a4eb0e5..194439a3b4 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -12127,7 +12127,8 @@ int wolfSSL_set_compression(WOLFSSL* ssl) if (ssl->buffers.weOwnKey) { WOLFSSL_MSG("Unloading key"); - ForceZero(ssl->buffers.key->buffer, ssl->buffers.key->length); + if (ssl->buffers.key != NULL && ssl->buffers.key->buffer != NULL) + ForceZero(ssl->buffers.key->buffer, ssl->buffers.key->length); FreeDer(&ssl->buffers.key); #ifdef WOLFSSL_BLIND_PRIVATE_KEY FreeDer(&ssl->buffers.keyMask); @@ -12138,7 +12139,8 @@ int wolfSSL_set_compression(WOLFSSL* ssl) #ifdef WOLFSSL_DUAL_ALG_CERTS if (ssl->buffers.weOwnAltKey) { WOLFSSL_MSG("Unloading alt key"); - ForceZero(ssl->buffers.altKey->buffer, ssl->buffers.altKey->length); + if (ssl->buffers.altKey != NULL && ssl->buffers.altKey->buffer != NULL) + ForceZero(ssl->buffers.altKey->buffer, ssl->buffers.altKey->length); FreeDer(&ssl->buffers.altKey); #ifdef WOLFSSL_BLIND_PRIVATE_KEY FreeDer(&ssl->buffers.altKeyMask); @@ -14989,6 +14991,22 @@ WOLFSSL_X509* wolfSSL_get_certificate(WOLFSSL* ssl) if (ssl->buffers.weOwnCert) { if (ssl->ourCert == NULL) { + /* Check if ctx has ourCert set - if so, use it instead of creating + * a new X509. This maintains pointer compatibility with + * applications (like nginx OCSP stapling) that use the X509 pointer + * from SSL_CTX_use_certificate as a lookup key. */ + if (ssl->ctx != NULL && ssl->ctx->ourCert != NULL) { + /* Compare cert buffers to make sure they are the same */ + if (ssl->buffers.certificate == NULL || + ssl->buffers.certificate->buffer == NULL || + (ssl->buffers.certificate->length == + ssl->ctx->certificate->length && + XMEMCMP(ssl->buffers.certificate->buffer, + ssl->ctx->certificate->buffer, + ssl->buffers.certificate->length) == 0)) { + return ssl->ctx->ourCert; + } + } if (ssl->buffers.certificate == NULL) { WOLFSSL_MSG("Certificate buffer not set!"); return NULL; @@ -21032,6 +21050,8 @@ WOLFSSL_CTX* wolfSSL_set_SSL_CTX(WOLFSSL* ssl, WOLFSSL_CTX* ctx) ssl->buffers.weOwnKey = 1; } else { + if (ssl->buffers.key != NULL && ssl->buffers.weOwnKey) + FreeDer(&ssl->buffers.key); ssl->buffers.key = ctx->privateKey; } #else diff --git a/src/ssl_misc.c b/src/ssl_misc.c index ced4570fbc..ccc02b5cfa 100644 --- a/src/ssl_misc.c +++ b/src/ssl_misc.c @@ -230,7 +230,13 @@ static int wolfssl_file_len(XFILE fp, long* fileSz) /* Get file offset at end of file. */ curr = (long)XFTELL(fp); if (curr < 0) { - ret = WOLFSSL_BAD_FILE; + if (errno == ESPIPE) { + WOLFSSL_ERROR_MSG("wolfssl_file_len: file is a pipe"); + *fileSz = 0; + ret = WOLFSSL_BAD_FILETYPE; + } + else + ret = WOLFSSL_BAD_FILE; } } /* Move to end of file. */ diff --git a/src/ssl_sk.c b/src/ssl_sk.c index 9696a820aa..877c068aa0 100644 --- a/src/ssl_sk.c +++ b/src/ssl_sk.c @@ -404,6 +404,17 @@ static int wolfssl_sk_dup_data(WOLFSSL_STACK* dst, WOLFSSL_STACK* src) break; } break; + case STACK_TYPE_X509_CRL: + if (src->data.crl == NULL) { + break; + } + dst->data.crl = wolfSSL_X509_CRL_dup(src->data.crl); + if (dst->data.crl == NULL) { + WOLFSSL_MSG("wolfSSL_X509_CRL_dup error"); + err = 1; + break; + } + break; case STACK_TYPE_X509_OBJ: #if defined(OPENSSL_ALL) if (src->data.x509_obj == NULL) { @@ -431,7 +442,6 @@ static int wolfssl_sk_dup_data(WOLFSSL_STACK* dst, WOLFSSL_STACK* src) case STACK_TYPE_BY_DIR_entry: case STACK_TYPE_BY_DIR_hash: case STACK_TYPE_DIST_POINT: - case STACK_TYPE_X509_CRL: case STACK_TYPE_GENERAL_SUBTREE: default: WOLFSSL_MSG("Unsupported stack type"); @@ -444,7 +454,8 @@ static int wolfssl_sk_dup_data(WOLFSSL_STACK* dst, WOLFSSL_STACK* src) /* Duplicate the stack of nodes. * - * TODO: OpenSSL does a shallow copy but we have wolfSSL_shallow_sk_dup(). + * OpenSSL does a shallow copy but we map to wolfSSL_shallow_sk_dup() + * when we want a shallow copy. * * Data is copied/duplicated - deep copy. * diff --git a/src/tls.c b/src/tls.c index 7d7dcea86c..c1e50b67ae 100644 --- a/src/tls.c +++ b/src/tls.c @@ -11595,8 +11595,10 @@ int TLSX_PreSharedKey_Parse_ClientHello(TLSX** extensions, const byte* input, ato16(input + idx, &identityLen); idx += OPAQUE16_LEN; if (len < OPAQUE16_LEN + identityLen + OPAQUE32_LEN || - identityLen > MAX_PSK_ID_LEN) + identityLen > MAX_PSK_ID_LEN) { + fprintf(stderr, "PSK identity length error %d\n", identityLen); return BUFFER_E; + } /* Cache identity pointer. */ identity = input + idx; idx += identityLen; diff --git a/src/x509.c b/src/x509.c index 291cd37ba2..5e2ccd24e5 100644 --- a/src/x509.c +++ b/src/x509.c @@ -35,6 +35,8 @@ #include #endif +#define MAX_BIO_READ_BUFFER (MAX_X509_SIZE * 16) + #if defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA) unsigned int wolfSSL_X509_get_extension_flags(WOLFSSL_X509* x509) { @@ -4646,6 +4648,14 @@ WOLFSSL_STACK* wolfSSL_sk_X509_CRL_new(void) return s; } +WOLFSSL_STACK* wolfSSL_sk_X509_CRL_new_null(void) +{ + WOLFSSL_STACK* s = wolfSSL_sk_new_null(); + if (s != NULL) + s->type = STACK_TYPE_X509_CRL; + return s; +} + void wolfSSL_sk_X509_CRL_pop_free(WOLF_STACK_OF(WOLFSSL_X509_CRL)* sk, void (*f) (WOLFSSL_X509_CRL*)) { @@ -6030,14 +6040,25 @@ static WOLFSSL_X509* loadX509orX509REQFromBuffer( /* ready to be decoded. */ if (der != NULL && der->buffer != NULL) { WC_DECLARE_VAR(cert, DecodedCert, 1, 0); + /* For TRUSTED_CERT_TYPE, the DER buffer contains the certificate + * followed by auxiliary trust info. ParseCertRelative expects CERT_TYPE + * and will parse only the certificate portion, ignoring the rest. */ + int parseType = (type == TRUSTED_CERT_TYPE) ? CERT_TYPE : type; WC_ALLOC_VAR_EX(cert, DecodedCert, 1, NULL, DYNAMIC_TYPE_DCERT, ret=MEMORY_ERROR); if (WC_VAR_OK(cert)) { InitDecodedCert(cert, der->buffer, der->length, NULL); - ret = ParseCertRelative(cert, type, 0, NULL, NULL); + ret = ParseCertRelative(cert, parseType, 0, NULL, NULL); if (ret == 0) { + /* For TRUSTED_CERT_TYPE, truncate the DER buffer to exclude + * auxiliary trust data. ParseCertRelative sets srcIdx to the + * end of the certificate, so we adjust cert->maxIdx accordingly. */ + if (type == TRUSTED_CERT_TYPE && cert->srcIdx < cert->maxIdx) { + cert->maxIdx = cert->srcIdx; + } + x509 = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), NULL, DYNAMIC_TYPE_X509); if (x509 != NULL) { @@ -12542,22 +12563,23 @@ static WOLFSSL_X509 *loadX509orX509REQFromPemBio(WOLFSSL_BIO *bp, int pemSz; long i = 0, l, footerSz; const char* footer = NULL; + int streaming = 0; /* Flag to indicate if source is streaming (FIFO) */ + const char* altFooter = NULL; + long altFooterSz = 0; WOLFSSL_ENTER("loadX509orX509REQFromPemBio"); - if (bp == NULL || (type != CERT_TYPE && type != CERTREQ_TYPE)) { + if (bp == NULL || (type != CERT_TYPE && type != CERTREQ_TYPE && + type != TRUSTED_CERT_TYPE)) { WOLFSSL_LEAVE("wolfSSL_PEM_read_bio_X509", BAD_FUNC_ARG); return NULL; } if ((l = wolfSSL_BIO_get_len(bp)) <= 0) { - /* No certificate in buffer */ -#if defined (WOLFSSL_HAPROXY) - WOLFSSL_ERROR(PEM_R_NO_START_LINE); -#else - WOLFSSL_ERROR(ASN_NO_PEM_HEADER); -#endif - return NULL; + /* No certificate size available - could be FIFO or other streaming + * source. Use MAX_X509_SIZE as initial buffer, will resize if needed. */ + l = MAX_X509_SIZE; + streaming = 1; } pemSz = (int)l; @@ -12573,27 +12595,79 @@ static WOLFSSL_X509 *loadX509orX509REQFromPemBio(WOLFSSL_BIO *bp, } footerSz = (long)XSTRLEN(footer); + /* For TRUSTED_CERT_TYPE, also prepare to check for regular CERT footer + * as the file might contain regular certificates instead of TRUSTED + * format */ + if (type == TRUSTED_CERT_TYPE) { + wc_PemGetHeaderFooter(CERT_TYPE, NULL, &altFooter); + if (altFooter != NULL) { + altFooterSz = (long)XSTRLEN(altFooter); + } + } + /* TODO: Inefficient * reading in one byte at a time until see the footer */ while ((l = wolfSSL_BIO_read(bp, (char *)&pem[i], 1)) == 1) { + int foundFooter = 0; i++; - if (i > footerSz && XMEMCMP((char *)&pem[i-footerSz], footer, - footerSz) == 0) { - if (wolfSSL_BIO_read(bp, (char *)&pem[i], 1) == 1) { + /* Check if buffer is full and we're reading from streaming source */ + if (i >= pemSz && streaming) { + /* Double the buffer size for streaming sources */ + int newSz = pemSz * 2; + unsigned char* newPem; + + /* Sanity check: don't grow beyond reasonable limit */ + if (newSz > MAX_BIO_READ_BUFFER) { + WOLFSSL_MSG("PEM data too large for streaming source"); + XFREE(pem, 0, DYNAMIC_TYPE_PEM); + return NULL; + } + + newPem = (unsigned char*)XREALLOC(pem, newSz, 0, DYNAMIC_TYPE_PEM); + if (newPem == NULL) { + WOLFSSL_MSG("Failed to resize PEM buffer"); + XFREE(pem, 0, DYNAMIC_TYPE_PEM); + return NULL; + } + + pem = newPem; + pemSz = newSz; + } + else if (i > pemSz) { + /* Buffer full for non-streaming source - this shouldn't happen */ + break; + } + + /* Check for the expected footer OR alternate footer (for + * TRUSTED_CERT_TYPE) */ + if (i > footerSz && + XMEMCMP((char *)&pem[i-footerSz], footer, footerSz) == 0) { + foundFooter = 1; + } + else if (i > altFooterSz && altFooter != NULL && + XMEMCMP((char *)&pem[i-altFooterSz], altFooter, altFooterSz) == 0) { + foundFooter = 1; + } + + if (foundFooter) { + if (i < pemSz && wolfSSL_BIO_read(bp, (char *)&pem[i], 1) == 1) { /* attempt to read newline following footer */ i++; - if (pem[i-1] == '\r') { + if (i < pemSz && pem[i-1] == '\r') { /* found \r , Windows line ending is \r\n so try to read one * more byte for \n, ignoring return value */ - (void)wolfSSL_BIO_read(bp, (char *)&pem[i++], 1); + if (i < pemSz) { + (void)wolfSSL_BIO_read(bp, (char *)&pem[i++], 1); + } } } break; } } - if (l == 0) + if (l == 0 && i == 0) { WOLFSSL_ERROR(ASN_NO_PEM_HEADER); + } if (i > pemSz) { WOLFSSL_MSG("Error parsing PEM"); } @@ -12605,6 +12679,12 @@ static WOLFSSL_X509 *loadX509orX509REQFromPemBio(WOLFSSL_BIO *bp, CERTREQ_TYPE, cb, u); else #endif + /* Use TRUSTED_CERT_TYPE if input was TRUSTED CERTIFICATE format, + * otherwise use CERT_TYPE for regular certificates */ + if (type == TRUSTED_CERT_TYPE) + x509 = loadX509orX509REQFromBuffer(pem, pemSz, WOLFSSL_FILETYPE_PEM, + TRUSTED_CERT_TYPE, cb, u); + else x509 = loadX509orX509REQFromBuffer(pem, pemSz, WOLFSSL_FILETYPE_PEM, CERT_TYPE, cb, u); } @@ -12625,6 +12705,85 @@ static WOLFSSL_X509 *loadX509orX509REQFromPemBio(WOLFSSL_BIO *bp, } +static unsigned char* ReadPemFromBioToBuffer(WOLFSSL_BIO *bp, int *pemSz) +{ + unsigned char* pem = NULL; + + WOLFSSL_ENTER("ReadPemFromBioToBuffer"); + + if (bp == NULL || pemSz == NULL) { + WOLFSSL_LEAVE("ReadPemFromBioToBuffer", BAD_FUNC_ARG); + return NULL; + } + + if ((*pemSz = wolfSSL_BIO_get_len(bp)) <= 0) { + /* No certificate size available - could be FIFO or other streaming + * source. Use MAX_X509_SIZE as initial buffer, read in loop. */ + int totalRead = 0; + int readSz; + + *pemSz = MAX_X509_SIZE; + pem = (unsigned char*)XMALLOC(*pemSz, 0, DYNAMIC_TYPE_PEM); + if (pem == NULL) { + return NULL; + } + + /* Read from streaming source until EOF or buffer full */ + while ((readSz = wolfSSL_BIO_read(bp, pem + totalRead, + *pemSz - totalRead)) > 0) { + totalRead += readSz; + + /* If buffer is full, try to grow it */ + if (totalRead >= *pemSz) { + int newSz = *pemSz * 2; + unsigned char* newPem; + + /* Sanity check */ + if (newSz > MAX_BIO_READ_BUFFER) { + WOLFSSL_MSG("PEM data too large for streaming source"); + XFREE(pem, NULL, DYNAMIC_TYPE_PEM); + return NULL; + } + + newPem = (unsigned char*)XREALLOC(pem, newSz, 0, + DYNAMIC_TYPE_PEM); + if (newPem == NULL) { + XFREE(pem, NULL, DYNAMIC_TYPE_PEM); + return NULL; + } + pem = newPem; + *pemSz = newSz; + } + } + + *pemSz = totalRead; + if (*pemSz <= 0) { + XFREE(pem, NULL, DYNAMIC_TYPE_PEM); + return NULL; + } + } + else { + /* Known size - allocate and read */ + pem = (unsigned char*)XMALLOC(*pemSz, 0, DYNAMIC_TYPE_PEM); + if (pem == NULL) { + return NULL; + } + + XMEMSET(pem, 0, *pemSz); + + *pemSz = wolfSSL_BIO_read(bp, pem, *pemSz); + if (*pemSz <= 0) { + XFREE(pem, NULL, DYNAMIC_TYPE_PEM); + return NULL; + } + } + + WOLFSSL_LEAVE("ReadPemFromBioToBuffer", 0); + return pem; +} + + + #if defined(WOLFSSL_ACERT) WOLFSSL_X509_ACERT *wolfSSL_PEM_read_bio_X509_ACERT(WOLFSSL_BIO *bp, WOLFSSL_X509_ACERT **x, @@ -12639,29 +12798,14 @@ static WOLFSSL_X509 *loadX509orX509REQFromPemBio(WOLFSSL_BIO *bp, WOLFSSL_ENTER("wolfSSL_PEM_read_bio_X509_ACERT"); if (bp == NULL) { - WOLFSSL_LEAVE("wolfSSL_PEM_read_bio_X509_ACERT", BAD_FUNC_ARG); - return NULL; - } - - if ((pemSz = wolfSSL_BIO_get_len(bp)) <= 0) { - /* No certificate in buffer */ - WOLFSSL_ERROR(ASN_NO_PEM_HEADER); return NULL; } - pem = (unsigned char*)XMALLOC(pemSz, 0, DYNAMIC_TYPE_PEM); - + pem = ReadPemFromBioToBuffer(bp, &pemSz); if (pem == NULL) { return NULL; } - XMEMSET(pem, 0, pemSz); - - if (wolfSSL_BIO_read(bp, pem, pemSz) != pemSz) { - XFREE(pem, NULL, DYNAMIC_TYPE_PEM); - return NULL; - } - x509 = wolfSSL_X509_ACERT_load_certificate_buffer(pem, pemSz, WOLFSSL_FILETYPE_PEM); @@ -12699,14 +12843,15 @@ static WOLFSSL_X509 *loadX509orX509REQFromPemBio(WOLFSSL_BIO *bp, WOLFSSL_X509 **x, wc_pem_password_cb *cb, void *u) { - WOLFSSL_ENTER("wolfSSL_PEM_read_bio_X509"); + WOLFSSL_ENTER("wolfSSL_PEM_read_bio_X509_AUX"); /* AUX info is; trusted/rejected uses, friendly name, private key id, * and potentially a stack of "other" info. wolfSSL does not store * friendly name or private key id yet in WOLFSSL_X509 for human * readability and does not support extra trusted/rejected uses for - * root CA. */ - return wolfSSL_PEM_read_bio_X509(bp, x, cb, u); + * root CA. Use TRUSTED_CERT_TYPE to properly parse TRUSTED CERTIFICATE + * format and strip auxiliary data. */ + return loadX509orX509REQFromPemBio(bp, x, cb, u, TRUSTED_CERT_TYPE); } #ifdef WOLFSSL_CERT_REQ @@ -12759,21 +12904,14 @@ WOLFSSL_X509 *wolfSSL_PEM_read_bio_X509_REQ(WOLFSSL_BIO *bp, WOLFSSL_X509 **x, { #if defined(WOLFSSL_PEM_TO_DER) && defined(HAVE_CRL) unsigned char* pem = NULL; - int pemSz; - int derSz; + int pemSz = 0; + int derSz = 0; DerBuffer* der = NULL; WOLFSSL_X509_CRL* crl = NULL; - if ((pemSz = wolfSSL_BIO_get_len(bp)) <= 0) { - goto err; - } - - pem = (unsigned char*)XMALLOC(pemSz, 0, DYNAMIC_TYPE_PEM); - if (pem == NULL) { - goto err; - } + WOLFSSL_ENTER("wolfSSL_PEM_read_bio_X509_CRL"); - if (wolfSSL_BIO_read(bp, pem, pemSz) != pemSz) { + if ((pem = ReadPemFromBioToBuffer(bp, &pemSz)) == NULL) { goto err; } @@ -12786,6 +12924,9 @@ WOLFSSL_X509 *wolfSSL_PEM_read_bio_X509_REQ(WOLFSSL_BIO *bp, WOLFSSL_X509 **x, } err: + if (pemSz == 0) { + WOLFSSL_ERROR(ASN_NO_PEM_HEADER); + } XFREE(pem, 0, DYNAMIC_TYPE_PEM); if (der != NULL) { FreeDer(&der); @@ -14986,37 +15127,36 @@ int wolfSSL_X509_NAME_digest(const WOLFSSL_X509_NAME *name, void wolfSSL_X509_email_free(WOLF_STACK_OF(WOLFSSL_STRING) *sk) { - WOLFSSL_STACK *curr; - - while (sk != NULL) { - curr = sk; - sk = sk->next; - - XFREE(curr, NULL, DYNAMIC_TYPE_OPENSSL); - } + wolfSSL_sk_pop_free(sk, NULL); } WOLF_STACK_OF(WOLFSSL_STRING) *wolfSSL_X509_get1_ocsp(WOLFSSL_X509 *x) { WOLFSSL_STACK* list = NULL; - char* url; + WOLFSSL_STRING url = NULL; if (x == NULL || x->authInfoSz == 0) return NULL; - list = (WOLFSSL_STACK*)XMALLOC(sizeof(WOLFSSL_STACK) + x->authInfoSz + 1, - NULL, DYNAMIC_TYPE_OPENSSL); + list = wolfSSL_sk_WOLFSSL_STRING_new(); if (list == NULL) return NULL; - url = (char*)list; - url += sizeof(WOLFSSL_STACK); + url = (WOLFSSL_STRING)XMALLOC(x->authInfoSz + 1, NULL, + DYNAMIC_TYPE_OPENSSL); + if (url == NULL) { + wolfSSL_sk_WOLFSSL_STRING_free(list); + return NULL; + } + XMEMCPY(url, x->authInfo, x->authInfoSz); url[x->authInfoSz] = '\0'; - list->data.string = url; - list->next = NULL; - list->num = 1; + if (wolfSSL_sk_push(list, url) <= 0) { + XFREE(url, NULL, DYNAMIC_TYPE_OPENSSL); + wolfSSL_sk_WOLFSSL_STRING_free(list); + return NULL; + } return list; } diff --git a/tests/test-maxfrag-dtls.conf b/tests/test-maxfrag-dtls.conf index 67aef1776e..f41419ed0c 100644 --- a/tests/test-maxfrag-dtls.conf +++ b/tests/test-maxfrag-dtls.conf @@ -202,14 +202,3 @@ -v 3 -l ECDHE-RSA-AES256-GCM-SHA384 -F 6 - -# server DTLSv1.2 DHE-RSA-AES256-GCM-SHA384 --u --v 3 --l DHE-RSA-AES256-GCM-SHA384 - -# client DTLSv1.2 DHE-RSA-AES256-GCM-SHA384 --u --v 3 --l DHE-RSA-AES256-GCM-SHA384 --F 6 diff --git a/tests/test-maxfrag.conf b/tests/test-maxfrag.conf index 32cdfe2047..2253ab3c58 100644 --- a/tests/test-maxfrag.conf +++ b/tests/test-maxfrag.conf @@ -169,15 +169,6 @@ -l ECDHE-RSA-AES256-GCM-SHA384 -F 6 -# server TLSv1.2 DHE-RSA-AES256-GCM-SHA384 --v 3 --l DHE-RSA-AES256-GCM-SHA384 - -# client TLSv1.2 DHE-RSA-AES256-GCM-SHA384 --v 3 --l DHE-RSA-AES256-GCM-SHA384 --F 6 - # server TLSv1.2 DHE-RSA-AES256-GCM-SHA384 -v 3 -l DHE-RSA-AES256-GCM-SHA384 diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 4ea0743ce6..4fcbcaabc6 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -24065,8 +24065,6 @@ static int DecodeCertInternal(DecodedCert* cert, int verify, int* criticalExt, cert->extensionsSz = (int)GetASNItem_Length( dataASN[X509CERTASN_IDX_TBS_EXT], cert->source); cert->extensionsIdx = dataASN[X509CERTASN_IDX_TBS_EXT].offset; - /* Advance past extensions. */ - cert->srcIdx = dataASN[X509CERTASN_IDX_SIGALGO_SEQ].offset; } } @@ -27398,6 +27396,27 @@ int PemToDer(const unsigned char* buff, long longSz, int type, footer = END_X509_CRL; } #endif + else if (type == CERT_TYPE + || type == CA_TYPE + || type == CHAIN_CERT_TYPE + || type == TRUSTED_PEER_TYPE) { + if (header == BEGIN_CERT) { + header = BEGIN_TRUSTED_CERT; + footer = END_TRUSTED_CERT; + } + else { + break; + } + } + else if (type == TRUSTED_CERT_TYPE) { + if (header == BEGIN_TRUSTED_CERT) { + header = BEGIN_CERT; + footer = END_CERT; + } + else { + break; + } + } else { break; } diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index a14991294d..1bb2700247 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -20574,7 +20574,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t random_bank_test(void) #ifdef WC_DRBG_BANKREF WC_ALLOC_VAR_EX(rng, WC_RNG, 1, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER, - return WC_TEST_RET_ENC_EC(MEMORY_E)); + ERROR_OUT(WC_TEST_RET_ENC_EC(MEMORY_E), out)); XMEMSET(rng, 0, sizeof(*rng)); #endif diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 59fb268aef..a9a6af42c0 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1279,16 +1279,6 @@ enum { #endif #endif /* NO_DH */ -#ifndef MAX_PSK_ID_LEN - /* max psk identity/hint supported */ - #if defined(WOLFSSL_TLS13) - /* OpenSSL has a 1472 byte session ticket */ - #define MAX_PSK_ID_LEN 1536 - #else - #define MAX_PSK_ID_LEN 128 - #endif -#endif - #ifndef MAX_PSK_KEY_LEN #define MAX_PSK_KEY_LEN 64 #endif @@ -2038,6 +2028,7 @@ WOLFSSL_LOCAL int NamedGroupIsPqcHybrid(int group); #define MAX_ENCRYPT_SZ ENCRYPT_LEN #define WOLFSSL_ASSERT_EQ(x, y) wc_static_assert((x) == (y)) +#define WOLFSSL_ASSERT_GE(x, y) wc_static_assert((x) >= (y)) #define WOLFSSL_ASSERT_SIZEOF_GE(x, y) wc_static_assert(sizeof(x) >= sizeof(y)) @@ -3447,6 +3438,11 @@ WOLFSSL_LOCAL int TLSX_AddEmptyRenegotiationInfo(TLSX** extensions, void* heap); #endif /* HAVE_SECURE_RENEGOTIATION */ #ifdef HAVE_SESSION_TICKET +/* Max peer cert size for ticket: 2KB is reasonable for most RSA/ECC certs */ +#ifndef MAX_TICKET_PEER_CERT_SZ +#define MAX_TICKET_PEER_CERT_SZ 2048 +#endif + /* Our ticket format. All members need to be a byte or array of byte to * avoid alignment issues */ typedef struct InternalTicket { @@ -3472,21 +3468,40 @@ typedef struct InternalTicket { byte sessionCtxSz; /* sessionCtx length */ byte sessionCtx[ID_LEN]; /* app specific context id */ #endif /* OPENSSL_EXTRA */ +#if defined(OPENSSL_ALL) && defined(KEEP_PEER_CERT) && \ + !defined(NO_CERT_IN_TICKET) + byte peerCertLen[OPAQUE16_LEN]; /* peer cert length */ + byte peerCert[]; /* peer certificate DER - variable length */ +#endif } InternalTicket; +/* Base size of InternalTicket without the variable-length peerCert field */ +#define WOLFSSL_INTERNAL_TICKET_BASE_SZ (sizeof(InternalTicket)) + +/* Minimum internal ticket length (no peer cert) */ #ifndef WOLFSSL_TICKET_ENC_CBC_HMAC - #define WOLFSSL_INTERNAL_TICKET_LEN sizeof(InternalTicket) + #define WOLFSSL_INTERNAL_TICKET_LEN WOLFSSL_INTERNAL_TICKET_BASE_SZ #else #define WOLFSSL_INTERNAL_TICKET_LEN \ - (((sizeof(InternalTicket) + 15) / 16) * 16) + (((WOLFSSL_INTERNAL_TICKET_BASE_SZ + 15) / 16) * 16) +#endif + +/* Maximum internal ticket length (with max peer cert) */ +#if defined(OPENSSL_ALL) && defined(KEEP_PEER_CERT) && \ + !defined(NO_CERT_IN_TICKET) + #define WOLFSSL_INTERNAL_TICKET_MAX_SZ \ + (WOLFSSL_INTERNAL_TICKET_BASE_SZ + MAX_TICKET_PEER_CERT_SZ) +#else + #define WOLFSSL_INTERNAL_TICKET_MAX_SZ WOLFSSL_INTERNAL_TICKET_BASE_SZ #endif #ifndef WOLFSSL_TICKET_EXTRA_PADDING_SZ #define WOLFSSL_TICKET_EXTRA_PADDING_SZ 32 #endif +/* Maximum encrypted ticket size */ #define WOLFSSL_TICKET_ENC_SZ \ - (sizeof(InternalTicket) + WOLFSSL_TICKET_EXTRA_PADDING_SZ) + (WOLFSSL_INTERNAL_TICKET_MAX_SZ + WOLFSSL_TICKET_EXTRA_PADDING_SZ) /* RFC 5077 defines this for session tickets. All members need to be a byte or * array of byte to avoid alignment issues */ @@ -3494,14 +3509,18 @@ typedef struct ExternalTicket { byte key_name[WOLFSSL_TICKET_NAME_SZ]; /* key context name - 16 */ byte iv[WOLFSSL_TICKET_IV_SZ]; /* this ticket's iv - 16 */ byte enc_len[OPAQUE16_LEN]; /* encrypted length - 2 */ - byte enc_ticket[WOLFSSL_TICKET_ENC_SZ]; - /* encrypted internal ticket */ - byte mac[WOLFSSL_TICKET_MAC_SZ]; /* total mac - 32 */ + byte enc_ticket[]; /* encrypted ticket - var length + * + total mac - 32 */ } ExternalTicket; -/* Cast to int to reduce amount of casts in code */ -#define SESSION_TICKET_LEN ((int)sizeof(ExternalTicket)) -#define WOLFSSL_TICKET_FIXED_SZ (SESSION_TICKET_LEN - WOLFSSL_TICKET_ENC_SZ) +/* Fixed portion of external ticket (key_name + iv + enc_len) */ +#define WOLFSSL_TICKET_FIXED_SZ \ + (WOLFSSL_TICKET_NAME_SZ + WOLFSSL_TICKET_IV_SZ + OPAQUE16_LEN + \ + WOLFSSL_TICKET_MAC_SZ) + +/* Maximum session ticket length */ +#define SESSION_TICKET_LEN \ + ((int)(WOLFSSL_TICKET_FIXED_SZ + WOLFSSL_TICKET_ENC_SZ)) typedef struct SessionTicket { word32 lifetime; @@ -3543,6 +3562,20 @@ WOLFSSL_LOCAL void TLSX_SessionTicket_Free(SessionTicket* ticket, void* heap); #endif /* HAVE_SESSION_TICKET */ +#ifndef MAX_PSK_ID_LEN + /* max psk identity/hint supported */ + #if defined(WOLFSSL_TLS13) + #ifdef SESSION_TICKET_LEN + #define MAX_PSK_ID_LEN SESSION_TICKET_LEN + #else + /* Previous value. Use as fallback for when tickets are disabled. */ + #define MAX_PSK_ID_LEN 1536 + #endif + #else + #define MAX_PSK_ID_LEN 128 + #endif +#endif + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) int TLSX_EncryptThenMac_Respond(WOLFSSL* ssl); #endif @@ -6376,12 +6409,20 @@ struct SystemCryptoPolicy { * for the caller to find so we clear the last error. */ #if defined(OPENSSL_EXTRA) && defined(WOLFSSL_HAVE_ERROR_QUEUE) -#define CLEAR_ASN_NO_PEM_HEADER_ERROR(err) \ - (err) = wolfSSL_ERR_peek_last_error(); \ - if (wolfSSL_ERR_GET_LIB(err) == WOLFSSL_ERR_LIB_PEM && \ - wolfSSL_ERR_GET_REASON(err) == -WOLFSSL_PEM_R_NO_START_LINE_E) { \ - wc_RemoveErrorNode(-1); \ - } +#define CLEAR_ASN_NO_PEM_HEADER_ERROR(err) \ +do { \ + (err) = wolfSSL_ERR_peek_last_error(); \ + if (wolfSSL_ERR_GET_LIB(err) == WOLFSSL_ERR_LIB_PEM && \ + wolfSSL_ERR_GET_REASON(err) == -WOLFSSL_PEM_R_NO_START_LINE_E) { \ + unsigned long peekErr; \ + do { \ + wc_RemoveErrorNode(-1); \ + peekErr = wolfSSL_ERR_peek_last_error(); \ + } while (wolfSSL_ERR_GET_LIB(peekErr) == WOLFSSL_ERR_LIB_PEM && \ + wolfSSL_ERR_GET_REASON(peekErr) == \ + -WOLFSSL_PEM_R_NO_START_LINE_E); \ + } \ +} while(0) #else #define CLEAR_ASN_NO_PEM_HEADER_ERROR(err) (void)(err); #endif diff --git a/wolfssl/openssl/ssl.h b/wolfssl/openssl/ssl.h index 5b8175564e..5d4f7b51fc 100644 --- a/wolfssl/openssl/ssl.h +++ b/wolfssl/openssl/ssl.h @@ -617,16 +617,18 @@ typedef STACK_OF(ACCESS_DESCRIPTION) AUTHORITY_INFO_ACCESS; #define sk_X509_push wolfSSL_sk_X509_push #define sk_X509_pop wolfSSL_sk_X509_pop #define sk_X509_pop_free wolfSSL_sk_X509_pop_free -#define sk_X509_dup wolfSSL_sk_dup +#define sk_X509_dup wolfSSL_shallow_sk_dup #define sk_X509_free wolfSSL_sk_X509_free #define X509_chain_up_ref wolfSSL_X509_chain_up_ref #define sk_X509_CRL_new wolfSSL_sk_X509_CRL_new +#define sk_X509_CRL_new_null wolfSSL_sk_X509_CRL_new_null #define sk_X509_CRL_pop_free wolfSSL_sk_X509_CRL_pop_free #define sk_X509_CRL_free wolfSSL_sk_X509_CRL_free #define sk_X509_CRL_push wolfSSL_sk_X509_CRL_push #define sk_X509_CRL_value wolfSSL_sk_X509_CRL_value #define sk_X509_CRL_num wolfSSL_sk_X509_CRL_num +#define sk_X509_CRL_dup wolfSSL_shallow_sk_dup #define sk_X509_OBJECT_new wolfSSL_sk_X509_OBJECT_new #define sk_X509_OBJECT_free wolfSSL_sk_X509_OBJECT_free @@ -807,6 +809,7 @@ wolfSSL_X509_STORE_set_verify_cb((WOLFSSL_X509_STORE *)(s), (WOLFSSL_X509_STORE_ #define PEM_read_X509_CRL wolfSSL_PEM_read_X509_CRL #define X509_CRL_dup wolfSSL_X509_CRL_dup +#define X509_CRL_up_ref wolfSSL_X509_CRL_up_ref #define X509_CRL_free wolfSSL_X509_CRL_free #define X509_CRL_get_lastUpdate wolfSSL_X509_CRL_get_lastUpdate #define X509_CRL_get0_lastUpdate wolfSSL_X509_CRL_get_lastUpdate @@ -1312,7 +1315,7 @@ typedef WOLFSSL_SRTP_PROTECTION_PROFILE SRTP_PROTECTION_PROFILE; #define sk_SSL_COMP_zero wolfSSL_sk_SSL_COMP_zero #define sk_SSL_CIPHER_value wolfSSL_sk_SSL_CIPHER_value #endif /* OPENSSL_ALL || WOLFSSL_HAPROXY */ -#define sk_SSL_CIPHER_dup wolfSSL_sk_dup +#define sk_SSL_CIPHER_dup wolfSSL_shallow_sk_dup #define sk_SSL_CIPHER_free wolfSSL_sk_SSL_CIPHER_free #define sk_SSL_CIPHER_find wolfSSL_sk_SSL_CIPHER_find diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 08989907c3..c6c3c1914b 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -1947,6 +1947,7 @@ WOLFSSL_API WOLFSSL_X509* wolfSSL_sk_X509_pop(WOLF_STACK_OF(WOLFSSL_X509)* sk); WOLFSSL_API void wolfSSL_sk_X509_free(WOLF_STACK_OF(WOLFSSL_X509)* sk); WOLFSSL_API WOLFSSL_STACK* wolfSSL_sk_X509_CRL_new(void); +WOLFSSL_API WOLFSSL_STACK* wolfSSL_sk_X509_CRL_new_null(void); WOLFSSL_API void wolfSSL_sk_X509_CRL_pop_free(WOLF_STACK_OF(WOLFSSL_X509_CRL)* sk, void (*f) (WOLFSSL_X509_CRL*)); WOLFSSL_API void wolfSSL_sk_X509_CRL_free(WOLF_STACK_OF(WOLFSSL_X509_CRL)* sk); @@ -3481,6 +3482,7 @@ WOLFSSL_API int wolfSSL_X509_REVOKED_get_serial_number(RevokedCert* rev, #endif #if defined(HAVE_CRL) && (defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL)) WOLFSSL_API WOLFSSL_X509_CRL* wolfSSL_X509_CRL_dup(const WOLFSSL_X509_CRL* crl); +WOLFSSL_API int wolfSSL_X509_CRL_up_ref(WOLFSSL_X509_CRL* crl); WOLFSSL_API void wolfSSL_X509_CRL_free(WOLFSSL_X509_CRL *crl); #endif