mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-10 03:50:50 +02:00
Merge pull request #10149 from julek-wolfssl/refactor-middle-padding
Refactor record padding handling to eliminate middle padding pattern
This commit is contained in:
@@ -138,6 +138,13 @@ jobs:
|
||||
# This should be a safe limit for the tests to run.
|
||||
timeout-minutes: 14
|
||||
steps:
|
||||
# tlslite-ng is consumed by scripts/multi-msg-record.test (run from
|
||||
# `make check`); without it that test is SKIPped.
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- run: pip install tlslite-ng
|
||||
|
||||
- name: Build and test wolfSSL
|
||||
uses: wolfSSL/actions-build-autotools-project@v1
|
||||
with:
|
||||
@@ -182,6 +189,13 @@ jobs:
|
||||
# This should be a safe limit for the tests to run.
|
||||
timeout-minutes: 14
|
||||
steps:
|
||||
# tlslite-ng is consumed by scripts/multi-msg-record.test (run from
|
||||
# `make check`); without it that test is SKIPped.
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- run: pip install tlslite-ng
|
||||
|
||||
- name: Build and test wolfSSL
|
||||
uses: wolfSSL/actions-build-autotools-project@v1
|
||||
with:
|
||||
@@ -208,6 +222,13 @@ jobs:
|
||||
# This should be a safe limit for the tests to run.
|
||||
timeout-minutes: 14
|
||||
steps:
|
||||
# tlslite-ng is consumed by scripts/multi-msg-record.test (run from
|
||||
# `make check`); without it that test is SKIPped.
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- run: pip install tlslite-ng
|
||||
|
||||
- name: Build and test wolfSSL
|
||||
uses: wolfSSL/actions-build-autotools-project@v1
|
||||
with:
|
||||
@@ -270,6 +291,12 @@ jobs:
|
||||
timeout-minutes: 14
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
# tlslite-ng is consumed by scripts/multi-msg-record.test (run from
|
||||
# `make check`); without it that test is SKIPped.
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- run: pip install tlslite-ng
|
||||
- run: ./autogen.sh
|
||||
- name: user_settings_all.h with compatibility layer
|
||||
run: |
|
||||
|
||||
@@ -200,6 +200,7 @@ tracefile.txt
|
||||
*.bak
|
||||
*.dummy
|
||||
*.xcworkspace
|
||||
workspace.pid*/
|
||||
xcuserdata
|
||||
compile
|
||||
NTRU_algorithm/
|
||||
|
||||
@@ -106,9 +106,22 @@ endif
|
||||
dist_noinst_SCRIPTS+= scripts/unit.test
|
||||
noinst_SCRIPTS+= scripts/unit.test.in
|
||||
|
||||
# multi-msg-record.test drives the wolfSSL example client against a
|
||||
# Python (tlslite-ng) peer to verify parsing of TLS records that carry
|
||||
# multiple handshake messages. The script probes the client binary
|
||||
# at runtime for TLS 1.2, TLS 1.3 and secure-renegotiation support
|
||||
# and skips phases that are not compiled in. The whole test exits 77
|
||||
# (SKIP) if python3 or tlslite-ng is missing or if nothing is
|
||||
# runnable.
|
||||
dist_noinst_SCRIPTS+= scripts/multi-msg-record.test
|
||||
|
||||
endif
|
||||
endif
|
||||
|
||||
# The Python half of multi-msg-record.test always ships in tarballs so
|
||||
# the wrapper can find it on the installed side.
|
||||
EXTRA_DIST+= scripts/multi-msg-record.py
|
||||
|
||||
dist_noinst_SCRIPTS+= scripts/pem.test
|
||||
|
||||
EXTRA_DIST += scripts/sniffer-static-rsa.pcap \
|
||||
|
||||
Executable
+655
@@ -0,0 +1,655 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# multi-msg-record.py
|
||||
#
|
||||
# Python half of scripts/multi-msg-record.test (the bash wrapper handles
|
||||
# NETWORK_UNSHARE_HELPER / AM_BWRAPPED and the python3 availability
|
||||
# check, then execs this script).
|
||||
#
|
||||
# Tests that wolfSSL correctly processes TLS records containing multiple
|
||||
# handshake messages packed into a single record.
|
||||
#
|
||||
# Uses tlslite-ng as the TLS peer to craft multi-message records:
|
||||
#
|
||||
# TLS 1.2 – Each connection tests TWO code paths back-to-back:
|
||||
# 1. Initial handshake: RecordMergingSocket rewrites separate
|
||||
# plaintext ServerHello + Certificate + ServerKeyExchange +
|
||||
# ServerHelloDone records into one multi-message TLS
|
||||
# record before forwarding to the wolfSSL client.
|
||||
# 2. Renegotiation on the same connection: tlslite-ng is
|
||||
# monkey-patched to coalesce SH+Cert+SKE+SHD into ONE
|
||||
# encrypted handshake record (exercises the
|
||||
# curSize -= padSz CBC-padding path and the AEAD path).
|
||||
#
|
||||
# TLS 1.3 – tlslite-ng's _queue_message / _queue_flush mechanism already
|
||||
# coalesces EncryptedExtensions + Certificate + CertificateVerify
|
||||
# + Finished into a single encrypted record. The test verifies
|
||||
# that wolfSSL parses this correctly.
|
||||
#
|
||||
# Multiple cipher suites are tested for both protocol versions.
|
||||
#
|
||||
# Requirements: python3, tlslite-ng (pip install tlslite-ng)
|
||||
|
||||
import socket
|
||||
import struct
|
||||
import subprocess
|
||||
import os
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
import types
|
||||
|
||||
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
WOLFSSL_DIR = os.path.dirname(SCRIPT_DIR)
|
||||
WOLF_CLIENT = os.path.join(WOLFSSL_DIR, "examples", "client", "client")
|
||||
CERT_DIR = os.path.join(WOLFSSL_DIR, "certs")
|
||||
|
||||
# CA cert path passed to the wolfSSL client via -A. Set in main() after
|
||||
# detect_wolf_features() determines whether the build accepts PEM or DER.
|
||||
WOLF_CA_CERT = os.path.join(CERT_DIR, "ca-cert.pem")
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Bypass a strict tlslite-ng validation that rejects wolfSSL's ClientHello
|
||||
# when the client advertises FFDHE groups in a TLS-1.3-only hello.
|
||||
# This must happen before importing TLSConnection.
|
||||
#
|
||||
# If tlslite-ng isn't installed we exit 77 so automake marks the test
|
||||
# SKIPped instead of FAILed.
|
||||
# ---------------------------------------------------------------------------
|
||||
try:
|
||||
import tlslite.tlsconnection # noqa: E402
|
||||
import tlslite.recordlayer # noqa: E402
|
||||
tlslite.tlsconnection.TLS_1_3_FORBIDDEN_GROUPS = frozenset()
|
||||
|
||||
from tlslite import ( # noqa: E402
|
||||
TLSConnection, HandshakeSettings, X509CertChain, parsePEMKey,
|
||||
)
|
||||
from tlslite.constants import ContentType # noqa: E402
|
||||
from tlslite.extensions import RenegotiationInfoExtension # noqa: E402
|
||||
from tlslite.constants import ExtensionType # noqa: E402
|
||||
from tlslite.messages import HelloMessage, Message as TLSMessage # noqa: E402
|
||||
except ImportError as e:
|
||||
sys.stdout.write(
|
||||
"tlslite-ng not installed ({}); skipping multi-msg-record test\n"
|
||||
" (install with: pip install tlslite-ng)\n".format(e))
|
||||
sys.exit(77)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
HS_NAMES = {
|
||||
2: "SH", 4: "NST", 8: "EE", 11: "Cert", 12: "SKE",
|
||||
13: "CR", 14: "SHD", 15: "CV", 16: "CKE", 20: "Fin",
|
||||
}
|
||||
|
||||
PASS_COUNT = 0
|
||||
FAIL_COUNT = 0
|
||||
SKIP_COUNT = 0
|
||||
|
||||
|
||||
def passed(label):
|
||||
global PASS_COUNT
|
||||
PASS_COUNT += 1
|
||||
print(f" PASS: {label}")
|
||||
|
||||
|
||||
def failed(label):
|
||||
global FAIL_COUNT
|
||||
FAIL_COUNT += 1
|
||||
print(f" FAIL: {label}")
|
||||
|
||||
|
||||
def skipped(label):
|
||||
global SKIP_COUNT
|
||||
SKIP_COUNT += 1
|
||||
print(f" SKIP: {label}")
|
||||
|
||||
|
||||
def detect_wolf_features():
|
||||
"""Probe the wolfSSL client binary to find which features are
|
||||
compiled in. Used to decide which test phases to run.
|
||||
|
||||
Returns dict with keys: tls12 (bool), tls13 (bool),
|
||||
secure_reneg (bool), rsa (bool), ciphers (set[str]), ca_cert (str).
|
||||
"""
|
||||
feats = {"tls12": False, "tls13": False, "secure_reneg": False,
|
||||
"rsa": True,
|
||||
"ciphers": set(),
|
||||
"ca_cert": os.path.join(CERT_DIR, "ca-cert.pem")}
|
||||
|
||||
# ./client -V -> e.g. "3:4:d(downgrade):e(either):"
|
||||
try:
|
||||
r = subprocess.run([WOLF_CLIENT, "-V"],
|
||||
capture_output=True, timeout=5)
|
||||
parts = r.stdout.decode("utf-8", errors="replace").strip().split(":")
|
||||
feats["tls12"] = "3" in parts
|
||||
feats["tls13"] = "4" in parts
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# ./client -? -> help text includes "-R" only when
|
||||
# HAVE_SECURE_RENEGOTIATION is defined. The default -A path
|
||||
# ("ca-cert.pem" vs "ca-cert.der") also tells us which CA file
|
||||
# format the build can load. The RSA key-size line reports
|
||||
# "RSA not supported" when NO_RSA is defined.
|
||||
try:
|
||||
r = subprocess.run([WOLF_CLIENT, "-?"],
|
||||
capture_output=True, timeout=5)
|
||||
htxt = r.stdout.decode("utf-8", errors="replace")
|
||||
feats["secure_reneg"] = ("Allow Secure Renegotiation" in htxt)
|
||||
if "ca-cert.der" in htxt and "ca-cert.pem" not in htxt:
|
||||
feats["ca_cert"] = os.path.join(CERT_DIR, "ca-cert.der")
|
||||
if "RSA not supported" in htxt:
|
||||
feats["rsa"] = False
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# ./client -e -> colon-separated list of supported cipher suites.
|
||||
try:
|
||||
r = subprocess.run([WOLF_CLIENT, "-e"],
|
||||
capture_output=True, timeout=5)
|
||||
ctxt = r.stdout.decode("utf-8", errors="replace").strip()
|
||||
feats["ciphers"] = {c for c in ctxt.split(":") if c}
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return feats
|
||||
|
||||
|
||||
def _load_chain(cert_file):
|
||||
with open(cert_file) as f:
|
||||
chain = X509CertChain()
|
||||
chain.parsePemList(f.read())
|
||||
return chain
|
||||
|
||||
|
||||
def _load_key(key_file):
|
||||
with open(key_file) as f:
|
||||
return parsePEMKey(f.read(), private=True)
|
||||
|
||||
|
||||
def _parse_hs_types(data):
|
||||
"""Parse handshake message types from raw handshake content."""
|
||||
msgs = []
|
||||
off = 0
|
||||
while off + 4 <= len(data):
|
||||
ht = data[off]
|
||||
hl = struct.unpack("!I", b"\x00" + bytes(data[off + 1 : off + 4]))[0]
|
||||
msgs.append(HS_NAMES.get(ht, f"T{ht}"))
|
||||
off += 4 + hl
|
||||
return msgs
|
||||
|
||||
|
||||
def _get_free_port():
|
||||
"""Get an available TCP port."""
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
||||
s.bind(("127.0.0.1", 0))
|
||||
return s.getsockname()[1]
|
||||
|
||||
|
||||
def _listen_socket():
|
||||
"""Bind a listening TCP socket on localhost with the standard test timeout."""
|
||||
port = _get_free_port()
|
||||
srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
srv.bind(("127.0.0.1", port))
|
||||
srv.listen(1)
|
||||
srv.settimeout(15)
|
||||
return srv, port
|
||||
|
||||
|
||||
def _run_wolf_client(port, version, cipher, extra=()):
|
||||
"""Invoke the wolfSSL example client against 127.0.0.1:port.
|
||||
|
||||
WOLF_CA_CERT is PEM or DER depending on the build (NO_CODING /
|
||||
OPENSSL_EXTRA builds don't both support PEM).
|
||||
"""
|
||||
cmd = [WOLF_CLIENT, "-h", "127.0.0.1", "-p", str(port),
|
||||
"-v", version, "-A", WOLF_CA_CERT,
|
||||
"-g", *extra]
|
||||
if cipher:
|
||||
cmd.extend(["-l", cipher])
|
||||
return subprocess.run(cmd, capture_output=True, timeout=15)
|
||||
|
||||
|
||||
class _SendRecordTrace:
|
||||
"""Context manager that wraps RecordLayer.sendRecord to log every record."""
|
||||
|
||||
def __init__(self):
|
||||
self.log = []
|
||||
self._orig = None
|
||||
|
||||
def __enter__(self):
|
||||
self._orig = tlslite.recordlayer.RecordLayer.sendRecord
|
||||
log = self.log
|
||||
orig = self._orig
|
||||
|
||||
def wrapper(self_rl, msg):
|
||||
data = msg.write()
|
||||
ct = msg.contentType
|
||||
encrypted = bool(self_rl._writeState
|
||||
and self_rl._writeState.encContext)
|
||||
hs_msgs = []
|
||||
if ct == ContentType.handshake:
|
||||
hs_msgs = _parse_hs_types(data)
|
||||
log.append((ct, encrypted, len(data), hs_msgs))
|
||||
yield from orig(self_rl, msg)
|
||||
|
||||
tlslite.recordlayer.RecordLayer.sendRecord = wrapper
|
||||
return self.log
|
||||
|
||||
def __exit__(self, *exc):
|
||||
tlslite.recordlayer.RecordLayer.sendRecord = self._orig
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# RecordMergingSocket (TLS 1.2 plaintext record merging)
|
||||
# ---------------------------------------------------------------------------
|
||||
class RecordMergingSocket:
|
||||
"""Socket wrapper that rewrites consecutive TLS handshake records into
|
||||
a single multi-message record. Only merges plaintext records that
|
||||
precede ChangeCipherSpec."""
|
||||
|
||||
def __init__(self, sock):
|
||||
self._sock = sock
|
||||
self._pending = bytearray()
|
||||
self._ver = 0x0303
|
||||
self._after_ccs = False
|
||||
self.merged_msgs = [] # [(n_msgs, [names], size)]
|
||||
|
||||
def _flush(self):
|
||||
if not self._pending:
|
||||
return
|
||||
msgs = _parse_hs_types(self._pending)
|
||||
n = len(msgs)
|
||||
hdr = struct.pack("!BHH", 22, self._ver, len(self._pending))
|
||||
self._sock.sendall(hdr + bytes(self._pending))
|
||||
self.merged_msgs.append((n, msgs, len(self._pending)))
|
||||
self._pending = bytearray()
|
||||
|
||||
# Called by BufferedSocket (one record per call, or multiple from flush)
|
||||
def _process(self, data):
|
||||
data = bytearray(data)
|
||||
off = 0
|
||||
while off + 5 <= len(data):
|
||||
ct = data[off]
|
||||
ver = struct.unpack("!H", data[off + 1 : off + 3])[0]
|
||||
rlen = struct.unpack("!H", data[off + 3 : off + 5])[0]
|
||||
if off + 5 + rlen > len(data):
|
||||
break
|
||||
payload = data[off + 5 : off + 5 + rlen]
|
||||
if not self._after_ccs and ct == 22:
|
||||
self._pending.extend(payload)
|
||||
self._ver = ver
|
||||
else:
|
||||
if ct == 20:
|
||||
self._after_ccs = True
|
||||
self._flush()
|
||||
self._sock.sendall(bytes(data[off : off + 5 + rlen]))
|
||||
off += 5 + rlen
|
||||
|
||||
def send(self, data):
|
||||
self._process(data)
|
||||
return len(data)
|
||||
|
||||
def sendall(self, data):
|
||||
self._process(data)
|
||||
|
||||
def recv(self, bufsize):
|
||||
self._flush()
|
||||
return self._sock.recv(bufsize)
|
||||
|
||||
def __getattr__(self, name):
|
||||
return getattr(self._sock, name)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Test runners
|
||||
# ---------------------------------------------------------------------------
|
||||
def run_tls12_test(cipher_wolf, cert_chain, priv_key, label,
|
||||
do_reneg=True):
|
||||
"""TLS 1.2 test – one connection optionally exercises two code paths:
|
||||
|
||||
Phase 1 (plaintext grouping, initial handshake):
|
||||
RecordMergingSocket rewrites separate plaintext ServerHello,
|
||||
Certificate, ServerKeyExchange and ServerHelloDone records into
|
||||
one multi-message TLS record before delivery to wolfSSL.
|
||||
|
||||
Phase 2 (encrypted grouping, renegotiation on same connection):
|
||||
tlslite-ng server is monkey-patched to coalesce SH+Cert+SKE+SHD
|
||||
into a single encrypted handshake record inside the renegotiation
|
||||
(exercises wolfSSL's encrypted multi-message parsing including
|
||||
curSize -= padSz for CBC padding).
|
||||
|
||||
Phase 2 is skipped when do_reneg=False (e.g. the wolfSSL client was
|
||||
built without HAVE_SECURE_RENEGOTIATION).
|
||||
"""
|
||||
srv, port = _listen_socket()
|
||||
|
||||
result = {"ok": False, "error": ""}
|
||||
msock_ref = [None]
|
||||
trace_log = []
|
||||
reneg_active = [False]
|
||||
verify_data = {'client': None, 'server': None}
|
||||
|
||||
# --- monkey-patches (used only during this connection) ----------------
|
||||
orig_calc_key = tlslite.tlsconnection.calc_key
|
||||
|
||||
def capturing_calc_key(*args, **kwargs):
|
||||
res = orig_calc_key(*args, **kwargs)
|
||||
lbl = args[3] if len(args) > 3 else kwargs.get('label', b'')
|
||||
if lbl == b"client finished" and verify_data['client'] is None:
|
||||
verify_data['client'] = bytearray(res)
|
||||
elif lbl == b"server finished" and verify_data['server'] is None:
|
||||
verify_data['server'] = bytearray(res)
|
||||
return res
|
||||
|
||||
orig_getExt = HelloMessage.getExtension
|
||||
|
||||
def patched_getExt(self, ext_type):
|
||||
ext = orig_getExt(self, ext_type)
|
||||
if (ext_type == ExtensionType.renegotiation_info
|
||||
and ext is not None and reneg_active[0]):
|
||||
ext._internal_value = bytearray(0)
|
||||
return ext
|
||||
|
||||
orig_rie_create = RenegotiationInfoExtension.create
|
||||
|
||||
def patched_rie_create(self, data):
|
||||
if reneg_active[0] and data == bytearray(0):
|
||||
combined = (bytearray(verify_data['client'])
|
||||
+ bytearray(verify_data['server']))
|
||||
return orig_rie_create(self, combined)
|
||||
return orig_rie_create(self, data)
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
def server():
|
||||
try:
|
||||
tlslite.tlsconnection.calc_key = capturing_calc_key
|
||||
HelloMessage.getExtension = patched_getExt
|
||||
RenegotiationInfoExtension.create = patched_rie_create
|
||||
|
||||
conn, _ = srv.accept()
|
||||
conn.settimeout(15)
|
||||
msock = RecordMergingSocket(conn)
|
||||
msock_ref[0] = msock
|
||||
tls = TLSConnection(msock)
|
||||
settings = HandshakeSettings()
|
||||
settings.minVersion = (3, 3)
|
||||
settings.maxVersion = (3, 3)
|
||||
|
||||
# ---------- Phase 1: initial handshake (plaintext grouping) ----
|
||||
tls.handshakeServer(certChain=cert_chain, privateKey=priv_key,
|
||||
settings=settings)
|
||||
tlslite.tlsconnection.calc_key = orig_calc_key
|
||||
|
||||
data = tls.recv(4096)
|
||||
|
||||
if do_reneg:
|
||||
# ---------- Phase 2: trigger + run renegotiation ----------
|
||||
hr = TLSMessage(ContentType.handshake,
|
||||
bytearray([0, 0, 0, 0]))
|
||||
for _ in tls._sendMsg(hr, randomizeFirstBlock=False,
|
||||
update_hashes=False):
|
||||
pass
|
||||
|
||||
# Bypass tlslite-ng renegotiation guards
|
||||
tls.closed = True
|
||||
tls.session = None
|
||||
reneg_active[0] = True
|
||||
|
||||
# Coalesce handshake messages into ONE encrypted TLS record
|
||||
def coalescing_sendMsgs(self, msgs):
|
||||
for msg in msgs:
|
||||
self._queue_message(msg)
|
||||
yield from self._queue_flush()
|
||||
tls._sendMsgs = types.MethodType(coalescing_sendMsgs, tls)
|
||||
|
||||
with _SendRecordTrace() as log:
|
||||
tls.handshakeServer(certChain=cert_chain,
|
||||
privateKey=priv_key,
|
||||
settings=settings)
|
||||
reneg_active[0] = False
|
||||
trace_log.extend(log)
|
||||
|
||||
if data:
|
||||
tls.send(data)
|
||||
tls.close()
|
||||
result["ok"] = True
|
||||
except Exception as e:
|
||||
import traceback
|
||||
result["error"] = traceback.format_exc()
|
||||
finally:
|
||||
tlslite.tlsconnection.calc_key = orig_calc_key
|
||||
HelloMessage.getExtension = orig_getExt
|
||||
RenegotiationInfoExtension.create = orig_rie_create
|
||||
reneg_active[0] = False
|
||||
srv.close()
|
||||
|
||||
st = threading.Thread(target=server, daemon=True)
|
||||
st.start()
|
||||
time.sleep(0.1)
|
||||
|
||||
proc = _run_wolf_client(port, "3", cipher_wolf,
|
||||
extra=("-R",) if do_reneg else ())
|
||||
st.join(timeout=5)
|
||||
|
||||
if proc.returncode != 0 or not result["ok"]:
|
||||
err = (result["error"]
|
||||
or proc.stderr.decode("utf-8", errors="replace")[:400])
|
||||
failed(f"{label}: connection failed ({err})")
|
||||
return False
|
||||
|
||||
ok = True
|
||||
|
||||
# Phase 1 verification: plaintext multi-message record
|
||||
msock = msock_ref[0]
|
||||
has_pt_grouped = False
|
||||
for n, msgs, sz in (msock.merged_msgs if msock else []):
|
||||
if n > 1:
|
||||
has_pt_grouped = True
|
||||
passed(f"{label} [plaintext]: {n} msgs "
|
||||
f"[{'+'.join(msgs)}] in one record ({sz} bytes)")
|
||||
if not has_pt_grouped:
|
||||
failed(f"{label} [plaintext]: no multi-message record detected")
|
||||
ok = False
|
||||
|
||||
# Phase 2 verification: encrypted multi-message record (renego)
|
||||
if do_reneg:
|
||||
has_enc_grouped = False
|
||||
for ct, enc, sz, msgs in trace_log:
|
||||
if ct == ContentType.handshake and enc and len(msgs) > 1:
|
||||
has_enc_grouped = True
|
||||
passed(f"{label} [encrypted]: {len(msgs)} msgs "
|
||||
f"[{'+'.join(msgs)}] in one record ({sz} bytes)")
|
||||
if not has_enc_grouped:
|
||||
failed(f"{label} [encrypted]: no multi-message "
|
||||
f"encrypted record")
|
||||
ok = False
|
||||
|
||||
return ok
|
||||
|
||||
|
||||
def run_tls13_test(cipher_wolf, cert_chain, priv_key, label):
|
||||
"""TLS 1.3: verify tlslite-ng sends multi-msg encrypted record and
|
||||
wolfSSL client processes it."""
|
||||
srv, port = _listen_socket()
|
||||
|
||||
result = {"ok": False, "error": ""}
|
||||
|
||||
def server():
|
||||
try:
|
||||
conn, _ = srv.accept()
|
||||
conn.settimeout(15)
|
||||
tls = TLSConnection(conn)
|
||||
settings = HandshakeSettings()
|
||||
settings.minVersion = (3, 4)
|
||||
settings.maxVersion = (3, 4)
|
||||
tls.handshakeServer(certChain=cert_chain, privateKey=priv_key,
|
||||
settings=settings)
|
||||
data = tls.recv(4096)
|
||||
if data:
|
||||
tls.send(data)
|
||||
tls.close()
|
||||
result["ok"] = True
|
||||
except Exception as e:
|
||||
result["error"] = str(e)
|
||||
finally:
|
||||
srv.close()
|
||||
|
||||
with _SendRecordTrace() as log:
|
||||
st = threading.Thread(target=server, daemon=True)
|
||||
st.start()
|
||||
time.sleep(0.1)
|
||||
|
||||
proc = _run_wolf_client(port, "4", cipher_wolf)
|
||||
st.join(timeout=5)
|
||||
|
||||
if proc.returncode != 0 or not result["ok"]:
|
||||
err = result["error"] or proc.stderr.decode("utf-8", errors="replace")[:200]
|
||||
failed(f"{label}: handshake failed ({err})")
|
||||
return False
|
||||
|
||||
# Check that at least one encrypted handshake record has multiple messages
|
||||
has_multi = False
|
||||
for ct, enc, sz, msgs in log:
|
||||
if ct == ContentType.handshake and enc and len(msgs) > 1:
|
||||
has_multi = True
|
||||
passed(f"{label}: {len(msgs)} encrypted msgs "
|
||||
f"[{'+'.join(msgs)}] in one record ({sz} bytes)")
|
||||
if not has_multi:
|
||||
failed(f"{label}: no multi-message encrypted records")
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Main
|
||||
# ---------------------------------------------------------------------------
|
||||
def main():
|
||||
if not os.path.isfile(WOLF_CLIENT):
|
||||
print(f"ERROR: wolfSSL client not found: {WOLF_CLIENT}")
|
||||
print(" Build wolfSSL first (./configure && make)")
|
||||
sys.exit(1)
|
||||
|
||||
# Probe the client to see which features are compiled in so each
|
||||
# phase of the test is only run when it can succeed.
|
||||
feats = detect_wolf_features()
|
||||
global WOLF_CA_CERT
|
||||
WOLF_CA_CERT = feats["ca_cert"]
|
||||
|
||||
print("=" * 60)
|
||||
print(" Multi-Message TLS Record Test")
|
||||
print("=" * 60)
|
||||
print(f" wolfSSL features: TLS1.2={feats['tls12']} "
|
||||
f"TLS1.3={feats['tls13']} "
|
||||
f"secure_reneg={feats['secure_reneg']} "
|
||||
f"rsa={feats['rsa']}")
|
||||
|
||||
# The test certs are RSA; skip the whole test when the wolfSSL build
|
||||
# has no RSA support (the client can't load or verify them).
|
||||
if not feats["rsa"]:
|
||||
print("\n wolfSSL built without RSA; skipping multi-msg-record "
|
||||
"test (RSA test certs cannot be verified).")
|
||||
sys.exit(77)
|
||||
|
||||
# Load certificate / key pairs
|
||||
rsa_chain = _load_chain(os.path.join(CERT_DIR, "server-cert.pem"))
|
||||
rsa_key = _load_key(os.path.join(CERT_DIR, "server-key.pem"))
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# TLS 1.2 – plaintext (initial HS) + optional encrypted (renegotiation)
|
||||
# multi-message records, same connection per cipher suite.
|
||||
# ------------------------------------------------------------------
|
||||
tls12_suites = [
|
||||
# (wolfSSL cipher name, description)
|
||||
(None, "default negotiated"),
|
||||
# AEAD (GCM)
|
||||
("ECDHE-RSA-AES128-GCM-SHA256", "ECDHE-RSA AES128-GCM"),
|
||||
("ECDHE-RSA-AES256-GCM-SHA384", "ECDHE-RSA AES256-GCM"),
|
||||
("DHE-RSA-AES128-GCM-SHA256", "DHE-RSA AES128-GCM"),
|
||||
("DHE-RSA-AES256-GCM-SHA384", "DHE-RSA AES256-GCM"),
|
||||
# CBC + HMAC (exercises padding path)
|
||||
("ECDHE-RSA-AES128-SHA256", "ECDHE-RSA AES128-CBC-SHA256"),
|
||||
("ECDHE-RSA-AES256-SHA384", "ECDHE-RSA AES256-CBC-SHA384"),
|
||||
("DHE-RSA-AES128-SHA256", "DHE-RSA AES128-CBC-SHA256"),
|
||||
("DHE-RSA-AES256-SHA256", "DHE-RSA AES256-CBC-SHA256"),
|
||||
# AEAD (ChaCha20-Poly1305)
|
||||
("ECDHE-RSA-CHACHA20-POLY1305", "ECDHE-RSA CHACHA20-POLY1305"),
|
||||
("DHE-RSA-CHACHA20-POLY1305", "DHE-RSA CHACHA20-POLY1305"),
|
||||
]
|
||||
|
||||
if feats["tls12"]:
|
||||
if feats["secure_reneg"]:
|
||||
print("\n--- TLS 1.2: plaintext + encrypted multi-message "
|
||||
"records ---")
|
||||
print(" Each connection verifies BOTH code paths:")
|
||||
print(" * initial handshake -> plaintext SH+Cert+SKE+SHD")
|
||||
print(" * renegotiation -> encrypted SH+Cert+SKE+SHD")
|
||||
else:
|
||||
print("\n--- TLS 1.2: plaintext multi-message records ---")
|
||||
print(" wolfSSL built without HAVE_SECURE_RENEGOTIATION;")
|
||||
print(" skipping the encrypted (renegotiation) half.")
|
||||
print(" Covers multiple key-exchanges, ciphers and MAC "
|
||||
"families.\n")
|
||||
|
||||
for cipher, desc in tls12_suites:
|
||||
if cipher and cipher not in feats["ciphers"]:
|
||||
skipped(f"TLS1.2 {desc} - cipher not in wolfSSL build")
|
||||
continue
|
||||
run_tls12_test(cipher, rsa_chain, rsa_key,
|
||||
f"TLS1.2 {desc}",
|
||||
do_reneg=feats["secure_reneg"])
|
||||
if not feats["secure_reneg"]:
|
||||
skipped("TLS1.2 encrypted multi-msg record "
|
||||
"(requires HAVE_SECURE_RENEGOTIATION)")
|
||||
else:
|
||||
skipped(f"TLS 1.2 tests ({len(tls12_suites)} suites) - "
|
||||
"wolfSSL built without TLS 1.2")
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# TLS 1.3 – encrypted multi-message records
|
||||
# ------------------------------------------------------------------
|
||||
tls13_suites = [
|
||||
# (wolfSSL cipher name, description)
|
||||
(None, "default negotiated"),
|
||||
("TLS13-AES128-GCM-SHA256", "AES-128-GCM"),
|
||||
("TLS13-AES256-GCM-SHA384", "AES-256-GCM"),
|
||||
("TLS13-CHACHA20-POLY1305-SHA256", "CHACHA20-POLY1305"),
|
||||
]
|
||||
|
||||
if feats["tls13"]:
|
||||
print("\n--- TLS 1.3: encrypted multi-message records ---")
|
||||
print(" Server sends EE+Cert+CV+Fin in a single encrypted "
|
||||
"record;")
|
||||
print(" wolfSSL client must decrypt and parse.\n")
|
||||
|
||||
for cipher, desc in tls13_suites:
|
||||
if cipher and cipher not in feats["ciphers"]:
|
||||
skipped(f"TLS1.3 {desc} - cipher not in wolfSSL build")
|
||||
continue
|
||||
run_tls13_test(cipher, rsa_chain, rsa_key,
|
||||
f"TLS1.3 {desc}")
|
||||
else:
|
||||
skipped(f"TLS 1.3 tests ({len(tls13_suites)} suites) - "
|
||||
"wolfSSL built without TLS 1.3")
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Summary
|
||||
# ------------------------------------------------------------------
|
||||
print()
|
||||
print("=" * 60)
|
||||
print(f" Results: {PASS_COUNT} passed, {FAIL_COUNT} failed, "
|
||||
f"{SKIP_COUNT} skipped")
|
||||
print("=" * 60)
|
||||
|
||||
# If nothing at all could run, signal SKIP (exit 77) so automake
|
||||
# records the test as skipped rather than passed-with-nothing.
|
||||
if PASS_COUNT == 0 and FAIL_COUNT == 0:
|
||||
sys.exit(77)
|
||||
|
||||
return FAIL_COUNT == 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(0 if main() else 1)
|
||||
Executable
+37
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# multi-msg-record.test
|
||||
#
|
||||
# Wrapper around scripts/multi-msg-record.py, invoked by automake via
|
||||
# `make check`. Verifies that the wolfSSL client correctly processes
|
||||
# TLS records that carry multiple handshake messages in a single record
|
||||
# (TLS 1.2 plaintext + renegotiation, and TLS 1.3 encrypted flight).
|
||||
#
|
||||
# The test is SKIPped (exit 77) when python3 or tlslite-ng is not
|
||||
# installed.
|
||||
#
|
||||
|
||||
# if we can, isolate the network namespace to eliminate port collisions.
|
||||
if [[ -n "$NETWORK_UNSHARE_HELPER" ]]; then
|
||||
if [[ -z "$NETWORK_UNSHARE_HELPER_CALLED" ]]; then
|
||||
export NETWORK_UNSHARE_HELPER_CALLED=yes
|
||||
exec "$NETWORK_UNSHARE_HELPER" "$0" "$@" || exit $?
|
||||
fi
|
||||
elif [ "${AM_BWRAPPED-}" != "yes" ]; then
|
||||
bwrap_path="$(command -v bwrap)"
|
||||
if [ -n "$bwrap_path" ]; then
|
||||
export AM_BWRAPPED=yes
|
||||
exec "$bwrap_path" --unshare-net --dev-bind / / "$0" "$@"
|
||||
fi
|
||||
unset AM_BWRAPPED
|
||||
fi
|
||||
|
||||
# Locate python3 - skip (exit 77) if unavailable.
|
||||
PYTHON="$(command -v python3)"
|
||||
if [ -z "$PYTHON" ]; then
|
||||
echo "python3 not found, skipping multi-msg-record test"
|
||||
exit 77
|
||||
fi
|
||||
|
||||
SCRIPT_DIR="$(cd -- "$(dirname -- "$0")" && pwd)"
|
||||
exec "$PYTHON" "$SCRIPT_DIR/multi-msg-record.py" "$@"
|
||||
@@ -219,9 +219,9 @@ port4=$(get_first_free_port $((port3 + 1))) # OCSP responder: root-ca
|
||||
port5=$(get_first_free_port $((port4 + 1))) # TLS server
|
||||
|
||||
# Responder 1: intermediate1-ca (server1=valid, server2=revoked)
|
||||
log1=$(mktemp /tmp/ocsp_resp1.XXXXXX)
|
||||
log1=$(mktemp "${TMPDIR:-/tmp}/ocsp_resp1.XXXXXX")
|
||||
resp_logs="$resp_logs $log1"
|
||||
ready1=$(mktemp /tmp/ocsp_ready1.XXXXXX)
|
||||
ready1=$(mktemp "${TMPDIR:-/tmp}/ocsp_ready1.XXXXXX")
|
||||
ready_files="$ready_files $ready1"
|
||||
$OCSP_RESPONDER -p $port1 -v -R "$ready1" \
|
||||
-c $OCSP_DIR/intermediate1-ca-cert.pem \
|
||||
@@ -232,9 +232,9 @@ pid1=$!
|
||||
resp_pids="$resp_pids $pid1"
|
||||
|
||||
# Responder 2: intermediate2-ca (server3=valid, server4=revoked)
|
||||
log2=$(mktemp /tmp/ocsp_resp2.XXXXXX)
|
||||
log2=$(mktemp "${TMPDIR:-/tmp}/ocsp_resp2.XXXXXX")
|
||||
resp_logs="$resp_logs $log2"
|
||||
ready2=$(mktemp /tmp/ocsp_ready2.XXXXXX)
|
||||
ready2=$(mktemp "${TMPDIR:-/tmp}/ocsp_ready2.XXXXXX")
|
||||
ready_files="$ready_files $ready2"
|
||||
$OCSP_RESPONDER -p $port2 -v -R "$ready2" \
|
||||
-c $OCSP_DIR/intermediate2-ca-cert.pem \
|
||||
@@ -245,9 +245,9 @@ pid2=$!
|
||||
resp_pids="$resp_pids $pid2"
|
||||
|
||||
# Responder 3: intermediate3-ca (server5=valid)
|
||||
log3=$(mktemp /tmp/ocsp_resp3.XXXXXX)
|
||||
log3=$(mktemp "${TMPDIR:-/tmp}/ocsp_resp3.XXXXXX")
|
||||
resp_logs="$resp_logs $log3"
|
||||
ready3=$(mktemp /tmp/ocsp_ready3.XXXXXX)
|
||||
ready3=$(mktemp "${TMPDIR:-/tmp}/ocsp_ready3.XXXXXX")
|
||||
ready_files="$ready_files $ready3"
|
||||
$OCSP_RESPONDER -p $port3 -v -R "$ready3" \
|
||||
-c $OCSP_DIR/intermediate3-ca-cert.pem \
|
||||
@@ -258,9 +258,9 @@ pid3=$!
|
||||
resp_pids="$resp_pids $pid3"
|
||||
|
||||
# Responder 4: root-ca (intermediate CAs: 1=valid, 2=valid, 3=revoked)
|
||||
log4=$(mktemp /tmp/ocsp_resp4.XXXXXX)
|
||||
log4=$(mktemp "${TMPDIR:-/tmp}/ocsp_resp4.XXXXXX")
|
||||
resp_logs="$resp_logs $log4"
|
||||
ready4=$(mktemp /tmp/ocsp_ready4.XXXXXX)
|
||||
ready4=$(mktemp "${TMPDIR:-/tmp}/ocsp_ready4.XXXXXX")
|
||||
ready_files="$ready_files $ready4"
|
||||
$OCSP_RESPONDER -p $port4 -v -R "$ready4" \
|
||||
-c $OCSP_DIR/root-ca-cert.pem \
|
||||
@@ -271,9 +271,9 @@ pid4=$!
|
||||
resp_pids="$resp_pids $pid4"
|
||||
|
||||
# Responder 5: authorized responder (delegated OCSP signer with id-kp-OCSPSigning)
|
||||
log5=$(mktemp /tmp/ocsp_resp5.XXXXXX)
|
||||
log5=$(mktemp "${TMPDIR:-/tmp}/ocsp_resp5.XXXXXX")
|
||||
resp_logs="$resp_logs $log5"
|
||||
ready5=$(mktemp /tmp/ocsp_ready5.XXXXXX)
|
||||
ready5=$(mktemp "${TMPDIR:-/tmp}/ocsp_ready5.XXXXXX")
|
||||
ready_files="$ready_files $ready5"
|
||||
$OCSP_RESPONDER -p $port5 -v -R "$ready5" \
|
||||
-c $OCSP_DIR/root-ca-cert.pem \
|
||||
|
||||
@@ -341,7 +341,9 @@ server=login.live.com
|
||||
#ca=certs/external/DigiCertGlobalRootCA.pem
|
||||
ca=./certs/external/ca_collection.pem
|
||||
|
||||
if [[ "$V4V6" == "4" ]]; then
|
||||
if [[ -z "${WOLFSSL_EXTERNAL_TEST-}" || "$WOLFSSL_EXTERNAL_TEST" == "0" ]]; then
|
||||
echo "Skipping OCSP test on $server (set WOLFSSL_EXTERNAL_TEST=1 to run)"
|
||||
elif [[ "$V4V6" == "4" ]]; then
|
||||
retry_with_backoff 3 ./examples/client/client -C -h "$server" -p 443 -A "$ca" -g -W 1
|
||||
RESULT=$?
|
||||
[ $RESULT -ne 0 ] && echo -e "\n\nClient connection failed" && exit 1
|
||||
|
||||
+3
-3
@@ -1904,7 +1904,7 @@ static int _Dtls13HandshakeRecv(WOLFSSL* ssl, byte* input, word32 size,
|
||||
#endif /* WOLFSSL_DEBUG_TLS */
|
||||
|
||||
/* ignore the message */
|
||||
*processedSize = idx + fragLength + ssl->keys.padSz;
|
||||
*processedSize = idx + fragLength;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1938,7 +1938,7 @@ static int _Dtls13HandshakeRecv(WOLFSSL* ssl, byte* input, word32 size,
|
||||
WOLFSSL_MSG("DTLS1.3 not accepting fragmented plaintext message");
|
||||
#endif /* WOLFSSL_DEBUG_TLS */
|
||||
/* ignore the message */
|
||||
*processedSize = idx + fragLength + ssl->keys.padSz;
|
||||
*processedSize = idx + fragLength;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1966,7 +1966,7 @@ static int _Dtls13HandshakeRecv(WOLFSSL* ssl, byte* input, word32 size,
|
||||
return DTLS_TOO_MANY_FRAGMENTS_E;
|
||||
}
|
||||
|
||||
*processedSize = idx + fragLength + ssl->keys.padSz;
|
||||
*processedSize = idx + fragLength;
|
||||
if (Dtls13NextMessageComplete(ssl))
|
||||
return Dtls13ProcessBufferedMessages(ssl);
|
||||
|
||||
|
||||
+82
-159
@@ -11905,10 +11905,7 @@ int MsgCheckEncryption(WOLFSSL* ssl, byte type, byte encrypted)
|
||||
|
||||
static WC_INLINE int isLastMsg(const WOLFSSL* ssl, word32 msgSz)
|
||||
{
|
||||
word32 extra = 0;
|
||||
if (IsEncryptionOn(ssl, 0))
|
||||
extra = ssl->keys.padSz;
|
||||
return (ssl->buffers.inputBuffer.idx - ssl->curStartIdx) + msgSz + extra
|
||||
return (ssl->buffers.inputBuffer.idx - ssl->curStartIdx) + msgSz
|
||||
== ssl->curSize;
|
||||
}
|
||||
|
||||
@@ -17698,9 +17695,6 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
||||
ssl->options.serverState = SERVER_CERT_COMPLETE;
|
||||
}
|
||||
|
||||
if (IsEncryptionOn(ssl, 0))
|
||||
args->idx += ssl->keys.padSz;
|
||||
|
||||
/* Advance state and proceed */
|
||||
ssl->options.asyncState = TLS_ASYNC_END;
|
||||
} /* case TLS_ASYNC_FINALIZE */
|
||||
@@ -17964,12 +17958,6 @@ static int DoCertificateStatus(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
||||
SendAlert(ssl, alert_fatal, bad_certificate_status_response);
|
||||
}
|
||||
|
||||
if (IsEncryptionOn(ssl, 0)) {
|
||||
if (*inOutIdx + ssl->keys.padSz > size)
|
||||
return BUFFER_E;
|
||||
*inOutIdx += ssl->keys.padSz;
|
||||
}
|
||||
|
||||
WOLFSSL_LEAVE("DoCertificateStatus", ret);
|
||||
WOLFSSL_END(WC_FUNC_CERTIFICATE_STATUS_DO);
|
||||
|
||||
@@ -17984,10 +17972,9 @@ static int DoCertificateStatus(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
||||
|
||||
#if !defined(NO_TLS) && !defined(WOLFSSL_NO_TLS12)
|
||||
|
||||
static int DoHelloRequest(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
word32 size, word32 totalSz)
|
||||
static int DoHelloRequest(WOLFSSL* ssl, word32 size)
|
||||
{
|
||||
(void)input;
|
||||
(void)size;
|
||||
|
||||
WOLFSSL_START(WC_FUNC_HELLO_REQUEST_DO);
|
||||
WOLFSSL_ENTER("DoHelloRequest");
|
||||
@@ -17995,17 +17982,6 @@ static int DoHelloRequest(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
if (size) /* must be 0 */
|
||||
return BUFFER_ERROR;
|
||||
|
||||
if (IsEncryptionOn(ssl, 0)) {
|
||||
/* If size == totalSz then we are in DtlsMsgDrain so no need to worry
|
||||
* about padding */
|
||||
/* access beyond input + size should be checked against totalSz */
|
||||
if (size != totalSz &&
|
||||
*inOutIdx + ssl->keys.padSz > totalSz)
|
||||
return BUFFER_E;
|
||||
|
||||
*inOutIdx += ssl->keys.padSz;
|
||||
}
|
||||
|
||||
if (ssl->options.side == WOLFSSL_SERVER_END) {
|
||||
SendAlert(ssl, alert_fatal, unexpected_message); /* try */
|
||||
WOLFSSL_ERROR_VERBOSE(FATAL_ERROR);
|
||||
@@ -18040,7 +18016,7 @@ int DoFinished(WOLFSSL* ssl, const byte* input, word32* inOutIdx, word32 size,
|
||||
* If size == totalSz then we are in DtlsMsgDrain so no need to worry about
|
||||
* padding */
|
||||
if (size != totalSz) {
|
||||
if (*inOutIdx + size + ssl->keys.padSz > totalSz)
|
||||
if (*inOutIdx + size > totalSz)
|
||||
return BUFFER_E;
|
||||
}
|
||||
|
||||
@@ -18083,8 +18059,7 @@ int DoFinished(WOLFSSL* ssl, const byte* input, word32* inOutIdx, word32 size,
|
||||
}
|
||||
#endif
|
||||
|
||||
/* force input exhaustion at ProcessReply consuming padSz */
|
||||
*inOutIdx += size + ssl->keys.padSz;
|
||||
*inOutIdx += size;
|
||||
|
||||
if (ssl->options.side == WOLFSSL_CLIENT_END) {
|
||||
ssl->options.serverState = SERVER_FINISHED_COMPLETE;
|
||||
@@ -18737,8 +18712,7 @@ int DoHandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
||||
return INCOMPLETE_DATA;
|
||||
}
|
||||
|
||||
expectedIdx = *inOutIdx + size +
|
||||
(ssl->keys.encryptionOn ? ssl->keys.padSz : 0);
|
||||
expectedIdx = *inOutIdx + size;
|
||||
|
||||
#if !defined(NO_WOLFSSL_SERVER) && \
|
||||
defined(HAVE_SECURE_RENEGOTIATION) && \
|
||||
@@ -18903,21 +18877,13 @@ int DoHandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
||||
|
||||
case hello_request:
|
||||
WOLFSSL_MSG("processing hello request");
|
||||
ret = DoHelloRequest(ssl, input, inOutIdx, size, totalSz);
|
||||
ret = DoHelloRequest(ssl, size);
|
||||
break;
|
||||
|
||||
#ifndef NO_WOLFSSL_CLIENT
|
||||
case hello_verify_request:
|
||||
WOLFSSL_MSG("processing hello verify request");
|
||||
ret = DoHelloVerifyRequest(ssl, input,inOutIdx, size);
|
||||
if (IsEncryptionOn(ssl, 0)) {
|
||||
/* access beyond input + size should be checked against totalSz
|
||||
*/
|
||||
if (*inOutIdx + ssl->keys.padSz > totalSz)
|
||||
return BUFFER_E;
|
||||
|
||||
*inOutIdx += ssl->keys.padSz;
|
||||
}
|
||||
break;
|
||||
|
||||
case server_hello:
|
||||
@@ -18989,8 +18955,6 @@ int DoHandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
||||
AddLateName("ServerHelloDone", &ssl->timeoutInfo);
|
||||
#endif
|
||||
ssl->options.serverState = SERVER_HELLODONE_COMPLETE;
|
||||
if (IsEncryptionOn(ssl, 0))
|
||||
*inOutIdx += ssl->keys.padSz;
|
||||
break;
|
||||
|
||||
case finished:
|
||||
@@ -19022,16 +18986,6 @@ int DoHandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* If size == totalSz then we are in DtlsMsgDrain so no need to worry
|
||||
* about padding */
|
||||
if (IsEncryptionOn(ssl, 0)) {
|
||||
/* access beyond input + size should be checked against totalSz
|
||||
*/
|
||||
if (size != totalSz &&
|
||||
*inOutIdx + ssl->keys.padSz > totalSz)
|
||||
return BUFFER_E;
|
||||
*inOutIdx += ssl->keys.padSz;
|
||||
}
|
||||
break;
|
||||
|
||||
case client_key_exchange:
|
||||
@@ -19132,7 +19086,11 @@ static int DoHandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
||||
return DoHandShakeMsgType(ssl, input, inOutIdx, type, size, totalSz);
|
||||
}
|
||||
|
||||
inputLength = ssl->buffers.inputBuffer.length - *inOutIdx;
|
||||
/* totalSz is now curStartIdx + curSize (content-only, padSz already
|
||||
* subtracted in ProcessReply). */
|
||||
if (*inOutIdx > totalSz)
|
||||
return BUFFER_ERROR;
|
||||
inputLength = totalSz - *inOutIdx;
|
||||
|
||||
/* If there is a pending fragmented handshake message,
|
||||
* pending message size will be non-zero. */
|
||||
@@ -19893,11 +19851,6 @@ static int DoDtlsHandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
||||
input + *inOutIdx, size, type,
|
||||
fragOffset, fragSz, ssl->heap);
|
||||
*inOutIdx += fragSz;
|
||||
if (*inOutIdx + ssl->keys.padSz > totalSz) {
|
||||
WOLFSSL_ERROR(BUFFER_E);
|
||||
return BUFFER_E;
|
||||
}
|
||||
*inOutIdx += ssl->keys.padSz;
|
||||
ret = 0;
|
||||
#ifndef WOLFSSL_DTLS_RESEND_ONLY_TIMEOUT
|
||||
/* If we receive an out of order last flight msg then retransmit */
|
||||
@@ -19936,10 +19889,6 @@ static int DoDtlsHandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
||||
/* Already saw this message and processed it. It can be ignored. */
|
||||
WOLFSSL_MSG("Already saw this message and processed it");
|
||||
*inOutIdx += fragSz;
|
||||
if (*inOutIdx + ssl->keys.padSz > totalSz) {
|
||||
WOLFSSL_ERROR(BUFFER_E);
|
||||
return BUFFER_E;
|
||||
}
|
||||
#ifndef WOLFSSL_DTLS_RESEND_ONLY_TIMEOUT
|
||||
if (IsDtlsNotSctpMode(ssl) &&
|
||||
VerifyForDtlsMsgPoolSend(ssl, type, fragOffset)) {
|
||||
@@ -19947,7 +19896,6 @@ static int DoDtlsHandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
||||
ret = DtlsMsgPoolSend(ssl, 0);
|
||||
}
|
||||
#endif
|
||||
*inOutIdx += ssl->keys.padSz;
|
||||
}
|
||||
else if (fragSz < size) {
|
||||
/* Since this branch is in order, but fragmented, dtls_rx_msg_list will
|
||||
@@ -19971,11 +19919,6 @@ static int DoDtlsHandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
||||
input + *inOutIdx, size, type,
|
||||
fragOffset, fragSz, ssl->heap);
|
||||
*inOutIdx += fragSz;
|
||||
if (*inOutIdx + ssl->keys.padSz > totalSz) {
|
||||
WOLFSSL_ERROR(BUFFER_E);
|
||||
return BUFFER_E;
|
||||
}
|
||||
*inOutIdx += ssl->keys.padSz;
|
||||
ret = 0;
|
||||
if (ssl->dtls_rx_msg_list != NULL && ssl->dtls_rx_msg_list->ready)
|
||||
ret = DtlsMsgDrain(ssl);
|
||||
@@ -19992,9 +19935,9 @@ static int DoDtlsHandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
||||
WOLFSSL_ERROR(BUFFER_ERROR);
|
||||
return BUFFER_ERROR;
|
||||
}
|
||||
if (idx + fragSz + ssl->keys.padSz > totalSz)
|
||||
if (idx + fragSz > totalSz)
|
||||
return BUFFER_E;
|
||||
*inOutIdx = idx + fragSz + ssl->keys.padSz;
|
||||
*inOutIdx = idx + fragSz;
|
||||
/* In async mode always store the message and process it with
|
||||
* DtlsMsgDrain because in case of a WC_PENDING_E it will be
|
||||
* easier this way. */
|
||||
@@ -22147,7 +22090,7 @@ int DoApplicationData(WOLFSSL* ssl, byte* input, word32* inOutIdx, int sniff)
|
||||
}
|
||||
#endif
|
||||
|
||||
dataSz = (int)(msgSz - ssl->keys.padSz);
|
||||
dataSz = (int)msgSz;
|
||||
if (dataSz < 0) {
|
||||
WOLFSSL_MSG("App data buffer error, malicious input?");
|
||||
if (sniff == NO_SNIFF) {
|
||||
@@ -22202,8 +22145,6 @@ int DoApplicationData(WOLFSSL* ssl, byte* input, word32* inOutIdx, int sniff)
|
||||
ssl->buffers.clearOutputBuffer.length = (unsigned int)dataSz;
|
||||
}
|
||||
|
||||
idx += ssl->keys.padSz;
|
||||
|
||||
#ifdef HAVE_LIBZ
|
||||
/* decompress could be bigger, overwrite after verify */
|
||||
if (ssl->options.usingCompression)
|
||||
@@ -22494,9 +22435,6 @@ static int DoAlert(WOLFSSL* ssl, byte* input, word32* inOutIdx, int* type)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (IsEncryptionOn(ssl, 0))
|
||||
dataSz -= ssl->keys.padSz;
|
||||
|
||||
/* make sure can read the message */
|
||||
if (dataSz != ALERT_SIZE) {
|
||||
#ifdef WOLFSSL_EXTRA_ALERTS
|
||||
@@ -22565,9 +22503,6 @@ static int DoAlert(WOLFSSL* ssl, byte* input, word32* inOutIdx, int* type)
|
||||
WOLFSSL_ERROR(*type);
|
||||
}
|
||||
}
|
||||
if (IsEncryptionOn(ssl, 0))
|
||||
*inOutIdx += ssl->keys.padSz;
|
||||
|
||||
return level;
|
||||
}
|
||||
|
||||
@@ -23575,6 +23510,14 @@ default:
|
||||
|
||||
}
|
||||
|
||||
/* Reduce curSize to content only, excluding padding/MAC overhead.
|
||||
* padSz is accounted for once at the end of record processing. */
|
||||
if (IsEncryptionOn(ssl, 0)) {
|
||||
if (ssl->keys.padSz > ssl->curSize)
|
||||
return BUFFER_E;
|
||||
ssl->curSize -= (word16)ssl->keys.padSz;
|
||||
}
|
||||
|
||||
/* in case > 1 msg per record */
|
||||
ssl->curStartIdx = ssl->buffers.inputBuffer.idx;
|
||||
|
||||
@@ -23592,7 +23535,8 @@ default:
|
||||
WOLFSSL_MSG("Dropping DTLS record outside receiving "
|
||||
"window");
|
||||
ssl->options.processReply = doProcessInit;
|
||||
ssl->buffers.inputBuffer.idx += ssl->curSize;
|
||||
ssl->buffers.inputBuffer.idx += ssl->curSize
|
||||
+ ssl->keys.padSz;
|
||||
if (ssl->buffers.inputBuffer.idx >
|
||||
ssl->buffers.inputBuffer.length)
|
||||
return BUFFER_E;
|
||||
@@ -23632,7 +23576,7 @@ default:
|
||||
}
|
||||
#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY)
|
||||
if (IsEncryptionOn(ssl, 0) && ssl->options.startedETMRead) {
|
||||
if ((ssl->curSize - ssl->keys.padSz > MAX_PLAINTEXT_SZ)
|
||||
if ((ssl->curSize > MAX_PLAINTEXT_SZ)
|
||||
#ifdef WOLFSSL_ASYNC_CRYPT
|
||||
&& ssl->buffers.inputBuffer.length !=
|
||||
ssl->buffers.inputBuffer.idx
|
||||
@@ -23650,7 +23594,7 @@ default:
|
||||
#endif
|
||||
/* TLS13 plaintext limit is checked earlier before decryption */
|
||||
if (!IsAtLeastTLSv1_3(ssl->version)
|
||||
&& ssl->curSize - ssl->keys.padSz > MAX_PLAINTEXT_SZ
|
||||
&& ssl->curSize > MAX_PLAINTEXT_SZ
|
||||
#ifdef WOLFSSL_ASYNC_CRYPT
|
||||
&& ssl->buffers.inputBuffer.length !=
|
||||
ssl->buffers.inputBuffer.idx
|
||||
@@ -23676,7 +23620,7 @@ default:
|
||||
ret = DoDtlsHandShakeMsg(ssl,
|
||||
ssl->buffers.inputBuffer.buffer,
|
||||
&ssl->buffers.inputBuffer.idx,
|
||||
ssl->buffers.inputBuffer.length);
|
||||
ssl->curStartIdx + ssl->curSize);
|
||||
if (ret == 0 ||
|
||||
ret == WC_NO_ERR_TRACE(WC_PENDING_E)) {
|
||||
/* Reset timeout as we have received a valid
|
||||
@@ -23696,7 +23640,7 @@ default:
|
||||
ret = Dtls13HandshakeRecv(ssl,
|
||||
ssl->buffers.inputBuffer.buffer,
|
||||
&ssl->buffers.inputBuffer.idx,
|
||||
ssl->buffers.inputBuffer.length);
|
||||
ssl->curStartIdx + ssl->curSize);
|
||||
#ifdef WOLFSSL_EARLY_DATA
|
||||
if (ret == 0 &&
|
||||
ssl->options.side == WOLFSSL_SERVER_END &&
|
||||
@@ -23707,8 +23651,12 @@ default:
|
||||
exit */
|
||||
ssl->earlyData = no_early_data;
|
||||
ssl->options.processReply = doProcessInit;
|
||||
if (ssl->options.clientInEarlyData)
|
||||
if (ssl->options.clientInEarlyData) {
|
||||
if (IsEncryptionOn(ssl, 0))
|
||||
ssl->buffers.inputBuffer.idx +=
|
||||
ssl->keys.padSz;
|
||||
return APP_DATA_READY;
|
||||
}
|
||||
}
|
||||
#endif /* WOLFSSL_EARLY_DATA */
|
||||
if (ret == 0 ||
|
||||
@@ -23729,7 +23677,7 @@ default:
|
||||
ret = DoHandShakeMsg(ssl,
|
||||
ssl->buffers.inputBuffer.buffer,
|
||||
&ssl->buffers.inputBuffer.idx,
|
||||
ssl->buffers.inputBuffer.length);
|
||||
ssl->curStartIdx + ssl->curSize);
|
||||
if (ret != 0) {
|
||||
if (SendFatalAlertOnly(ssl, ret) ==
|
||||
WC_NO_ERR_TRACE(SOCKET_ERROR_E))
|
||||
@@ -23745,7 +23693,7 @@ default:
|
||||
ret = DoTls13HandShakeMsg(ssl,
|
||||
ssl->buffers.inputBuffer.buffer,
|
||||
&ssl->buffers.inputBuffer.idx,
|
||||
ssl->buffers.inputBuffer.length);
|
||||
ssl->curStartIdx + ssl->curSize);
|
||||
#ifdef WOLFSSL_EARLY_DATA
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
@@ -23754,8 +23702,12 @@ default:
|
||||
ssl->options.handShakeState == HANDSHAKE_DONE) {
|
||||
ssl->earlyData = no_early_data;
|
||||
ssl->options.processReply = doProcessInit;
|
||||
if (ssl->options.clientInEarlyData)
|
||||
if (ssl->options.clientInEarlyData) {
|
||||
if (IsEncryptionOn(ssl, 0))
|
||||
ssl->buffers.inputBuffer.idx +=
|
||||
ssl->keys.padSz;
|
||||
return APP_DATA_READY;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
@@ -23855,11 +23807,6 @@ default:
|
||||
return LENGTH_ERROR;
|
||||
}
|
||||
|
||||
if (IsEncryptionOn(ssl, 0) && ssl->options.handShakeDone) {
|
||||
ssl->buffers.inputBuffer.idx += ssl->keys.padSz;
|
||||
ssl->curSize -= (word16)ssl->keys.padSz;
|
||||
}
|
||||
|
||||
if (ssl->curSize != 1) {
|
||||
WOLFSSL_MSG("Malicious or corrupted ChangeCipher msg");
|
||||
WOLFSSL_ERROR_VERBOSE(LENGTH_ERROR);
|
||||
@@ -24023,11 +23970,10 @@ default:
|
||||
word32 processedSize = 0;
|
||||
ret = DoDtls13Ack(ssl, ssl->buffers.inputBuffer.buffer +
|
||||
ssl->buffers.inputBuffer.idx,
|
||||
ssl->buffers.inputBuffer.length -
|
||||
ssl->buffers.inputBuffer.idx -
|
||||
ssl->keys.padSz, &processedSize);
|
||||
ssl->curStartIdx + ssl->curSize -
|
||||
ssl->buffers.inputBuffer.idx,
|
||||
&processedSize);
|
||||
ssl->buffers.inputBuffer.idx += processedSize;
|
||||
ssl->buffers.inputBuffer.idx += ssl->keys.padSz;
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
break;
|
||||
@@ -24041,53 +23987,44 @@ default:
|
||||
|
||||
ssl->options.processReply = doProcessInit;
|
||||
|
||||
/* input exhausted */
|
||||
if (ssl->buffers.inputBuffer.idx >= ssl->buffers.inputBuffer.length
|
||||
#ifdef WOLFSSL_DTLS
|
||||
|| (ssl->options.dtls &&
|
||||
/* If app data was processed then return now to avoid
|
||||
* dropping any app data. */
|
||||
(ssl->curRL.type == application_data ||
|
||||
/* client: if we processed a finished message, return to
|
||||
* allow higher layers to establish the crypto
|
||||
* parameters of the connection. The remaining data
|
||||
* may be app data that we would drop without the
|
||||
* crypto setup. */
|
||||
(ssl->options.side == WOLFSSL_CLIENT_END &&
|
||||
ssl->options.serverState == SERVER_FINISHED_COMPLETE &&
|
||||
ssl->options.handShakeState != HANDSHAKE_DONE)))
|
||||
#endif
|
||||
) {
|
||||
/* Shrink input buffer when we successfully finish record
|
||||
* processing */
|
||||
if ((ret == 0) && ssl->buffers.inputBuffer.dynamicFlag)
|
||||
ShrinkInputBuffer(ssl, NO_FORCED_FREE);
|
||||
return ret;
|
||||
}
|
||||
/* more messages per record */
|
||||
else if ((ssl->buffers.inputBuffer.idx - ssl->curStartIdx)
|
||||
if ((ssl->buffers.inputBuffer.idx - ssl->curStartIdx)
|
||||
< ssl->curSize) {
|
||||
WOLFSSL_MSG("More messages in record");
|
||||
|
||||
ssl->options.processReply = runProcessingOneMessage;
|
||||
|
||||
if (IsEncryptionOn(ssl, 0)) {
|
||||
/* With encryption on, we advance the index by the value
|
||||
* of ssl->keys.padSz. Since padding only appears once, we
|
||||
* only can do this at the end of record parsing. We have to
|
||||
* reset the index to the start of the next message here. */
|
||||
if (ssl->buffers.inputBuffer.idx >= ssl->keys.padSz) {
|
||||
ssl->buffers.inputBuffer.idx -= ssl->keys.padSz;
|
||||
}
|
||||
else {
|
||||
WOLFSSL_MSG("\tBuffer advanced not enough error");
|
||||
WOLFSSL_ERROR_VERBOSE(FATAL_ERROR);
|
||||
return FATAL_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* more records */
|
||||
else {
|
||||
/* Done with this record. Advance past padding/MAC. */
|
||||
if (IsEncryptionOn(ssl, 0))
|
||||
ssl->buffers.inputBuffer.idx += ssl->keys.padSz;
|
||||
|
||||
/* input exhausted */
|
||||
if (ssl->buffers.inputBuffer.idx >=
|
||||
ssl->buffers.inputBuffer.length
|
||||
#ifdef WOLFSSL_DTLS
|
||||
|| (ssl->options.dtls &&
|
||||
/* If app data was processed then return now to avoid
|
||||
* dropping any app data. */
|
||||
(ssl->curRL.type == application_data ||
|
||||
/* client: if we processed a finished message, return
|
||||
* to allow higher layers to establish the
|
||||
* crypto parameters of the connection. The
|
||||
* remaining data may be app data that we would
|
||||
* drop without the crypto setup. */
|
||||
(ssl->options.side == WOLFSSL_CLIENT_END &&
|
||||
ssl->options.serverState ==
|
||||
SERVER_FINISHED_COMPLETE &&
|
||||
ssl->options.handShakeState != HANDSHAKE_DONE)))
|
||||
#endif
|
||||
) {
|
||||
/* Shrink input buffer when we successfully finish record
|
||||
* processing */
|
||||
if ((ret == 0) && ssl->buffers.inputBuffer.dynamicFlag)
|
||||
ShrinkInputBuffer(ssl, NO_FORCED_FREE);
|
||||
return ret;
|
||||
}
|
||||
/* more records */
|
||||
WOLFSSL_MSG("More records in input");
|
||||
}
|
||||
#ifdef WOLFSSL_ASYNC_CRYPT
|
||||
@@ -24102,10 +24039,14 @@ default:
|
||||
if (ret == WC_NO_ERR_TRACE(APP_DATA_READY))
|
||||
return ret;
|
||||
#endif
|
||||
/* It is safe to shrink the input buffer here now. local vars will
|
||||
* be reset to the new starting value. */
|
||||
if (ret == 0 && ssl->buffers.inputBuffer.dynamicFlag)
|
||||
/* It is safe to shrink the input buffer here now, but only
|
||||
* when done with the current record. During multi-message
|
||||
* record processing, shrinking would invalidate curStartIdx
|
||||
* and curSize. */
|
||||
if (ssl->options.processReply != runProcessingOneMessage
|
||||
&& ret == 0 && ssl->buffers.inputBuffer.dynamicFlag) {
|
||||
ShrinkInputBuffer(ssl, NO_FORCED_FREE);
|
||||
}
|
||||
continue;
|
||||
default:
|
||||
WOLFSSL_MSG("Bad process input state, programming error");
|
||||
@@ -32166,9 +32107,6 @@ static void MakePSKPreMasterSecret(Arrays* arrays, byte use_psk_key)
|
||||
|
||||
ssl->options.serverState = SERVER_HELLO_COMPLETE;
|
||||
|
||||
if (IsEncryptionOn(ssl, 0))
|
||||
*inOutIdx += ssl->keys.padSz;
|
||||
|
||||
#ifdef HAVE_SECRET_CALLBACK
|
||||
if (ssl->sessionSecretCb != NULL
|
||||
#ifdef HAVE_SESSION_TICKET
|
||||
@@ -32500,9 +32438,6 @@ static void MakePSKPreMasterSecret(Arrays* arrays, byte use_psk_key)
|
||||
ssl->options.sendVerify = SEND_BLANK_CERT;
|
||||
}
|
||||
|
||||
if (IsEncryptionOn(ssl, 0))
|
||||
*inOutIdx += ssl->keys.padSz;
|
||||
|
||||
WOLFSSL_LEAVE("DoCertificateRequest", 0);
|
||||
WOLFSSL_END(WC_FUNC_CERTIFICATE_REQUEST_DO);
|
||||
|
||||
@@ -33742,9 +33677,6 @@ static int DoServerKeyExchange(WOLFSSL* ssl, const byte* input,
|
||||
|
||||
case TLS_ASYNC_FINALIZE:
|
||||
{
|
||||
if (IsEncryptionOn(ssl, 0))
|
||||
args->idx += ssl->keys.padSz;
|
||||
|
||||
/* Advance state and proceed */
|
||||
ssl->options.asyncState = TLS_ASYNC_END;
|
||||
} /* case TLS_ASYNC_FINALIZE */
|
||||
@@ -35512,9 +35444,6 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
#endif
|
||||
}
|
||||
|
||||
if (IsEncryptionOn(ssl, 0))
|
||||
*inOutIdx += ssl->keys.padSz;
|
||||
|
||||
ssl->expect_session_ticket = 0;
|
||||
|
||||
return 0;
|
||||
@@ -39343,9 +39272,6 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
|
||||
|
||||
case TLS_ASYNC_FINALIZE:
|
||||
{
|
||||
if (IsEncryptionOn(ssl, 0))
|
||||
args->idx += ssl->keys.padSz;
|
||||
|
||||
ssl->options.havePeerVerify = 1;
|
||||
|
||||
/* Set final index */
|
||||
@@ -42428,9 +42354,6 @@ static int DefTicketEncCb(WOLFSSL* ssl, byte key_name[WOLFSSL_TICKET_NAME_SZ],
|
||||
|
||||
case TLS_ASYNC_FINALIZE:
|
||||
{
|
||||
if (IsEncryptionOn(ssl, 0))
|
||||
args->idx += ssl->keys.padSz;
|
||||
|
||||
ret = MakeMasterSecret(ssl);
|
||||
|
||||
/* Check for error */
|
||||
|
||||
+10
-24
@@ -6019,9 +6019,6 @@ static int DoTls13EncryptedExtensions(WOLFSSL* ssl, const byte* input,
|
||||
/* Move index to byte after message. */
|
||||
*inOutIdx = i + totalExtSz;
|
||||
|
||||
/* Always encrypted. */
|
||||
*inOutIdx += ssl->keys.padSz;
|
||||
|
||||
#ifdef WOLFSSL_EARLY_DATA
|
||||
if (ssl->earlyData != no_early_data) {
|
||||
TLSX* ext = TLSX_Find(ssl->extensions, TLSX_EARLY_DATA);
|
||||
@@ -6165,9 +6162,6 @@ static int DoTls13CertificateRequest(WOLFSSL* ssl, const byte* input,
|
||||
#endif
|
||||
}
|
||||
|
||||
/* This message is always encrypted so add encryption padding. */
|
||||
*inOutIdx += ssl->keys.padSz;
|
||||
|
||||
#ifdef WOLFSSL_POST_HANDSHAKE_AUTH
|
||||
{
|
||||
/* CertReqCtx has one byte at end for context value.
|
||||
@@ -11636,9 +11630,6 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input,
|
||||
args->idx += args->sz;
|
||||
*inOutIdx = args->idx;
|
||||
|
||||
/* Encryption is always on: add padding */
|
||||
*inOutIdx += ssl->keys.padSz;
|
||||
|
||||
/* Advance state and proceed */
|
||||
ssl->options.asyncState = TLS_ASYNC_END;
|
||||
|
||||
@@ -11836,8 +11827,7 @@ int DoTls13Finished(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
}
|
||||
}
|
||||
|
||||
/* Force input exhaustion at ProcessReply by consuming padSz. */
|
||||
*inOutIdx += size + ssl->keys.padSz;
|
||||
*inOutIdx += size;
|
||||
|
||||
#ifndef NO_WOLFSSL_SERVER
|
||||
if (ssl->options.side == WOLFSSL_SERVER_END &&
|
||||
@@ -12290,8 +12280,6 @@ static int DoTls13KeyUpdate(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||
|
||||
/* Move index to byte after message. */
|
||||
*inOutIdx += totalSz;
|
||||
/* Always encrypted. */
|
||||
*inOutIdx += ssl->keys.padSz;
|
||||
|
||||
/* Future traffic uses new decryption keys. */
|
||||
if ((ret = DeriveTls13Keys(ssl, update_traffic_key, DECRYPT_SIDE_ONLY, 1))
|
||||
@@ -12442,9 +12430,6 @@ static int DoTls13EndOfEarlyData(WOLFSSL* ssl, const byte* input,
|
||||
|
||||
ssl->earlyData = done_early_data;
|
||||
|
||||
/* Always encrypted. */
|
||||
*inOutIdx += ssl->keys.padSz;
|
||||
|
||||
ret = SetKeysSide(ssl, DECRYPT_SIDE_ONLY);
|
||||
|
||||
WOLFSSL_LEAVE("DoTls13EndOfEarlyData", ret);
|
||||
@@ -12616,9 +12601,6 @@ static int DoTls13NewSessionTicket(WOLFSSL* ssl, const byte* input,
|
||||
AddSession(ssl);
|
||||
#endif
|
||||
|
||||
/* Always encrypted. */
|
||||
*inOutIdx += ssl->keys.padSz;
|
||||
|
||||
ssl->expect_session_ticket = 0;
|
||||
#else
|
||||
(void)ssl;
|
||||
@@ -12626,7 +12608,7 @@ static int DoTls13NewSessionTicket(WOLFSSL* ssl, const byte* input,
|
||||
|
||||
WOLFSSL_ENTER("DoTls13NewSessionTicket");
|
||||
|
||||
*inOutIdx += size + ssl->keys.padSz;
|
||||
*inOutIdx += size;
|
||||
#endif /* HAVE_SESSION_TICKET */
|
||||
|
||||
WOLFSSL_LEAVE("DoTls13NewSessionTicket", 0);
|
||||
@@ -13969,7 +13951,11 @@ int DoTls13HandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
||||
totalSz);
|
||||
}
|
||||
|
||||
inputLength = ssl->buffers.inputBuffer.length - *inOutIdx - ssl->keys.padSz;
|
||||
/* totalSz is now curStartIdx + curSize (content-only, padSz already
|
||||
* subtracted in ProcessReply). */
|
||||
if (*inOutIdx > totalSz)
|
||||
return BUFFER_ERROR;
|
||||
inputLength = totalSz - *inOutIdx;
|
||||
|
||||
/* If there is a pending fragmented handshake message,
|
||||
* pending message size will be non-zero. */
|
||||
@@ -14011,7 +13997,7 @@ int DoTls13HandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
||||
input + *inOutIdx - HANDSHAKE_HEADER_SZ,
|
||||
inputLength);
|
||||
ssl->arrays->pendingMsgOffset = inputLength;
|
||||
*inOutIdx += inputLength + ssl->keys.padSz - HANDSHAKE_HEADER_SZ;
|
||||
*inOutIdx += inputLength - HANDSHAKE_HEADER_SZ;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -14035,7 +14021,7 @@ int DoTls13HandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
||||
XMEMCPY(ssl->arrays->pendingMsg + ssl->arrays->pendingMsgOffset,
|
||||
input + *inOutIdx, inputLength);
|
||||
ssl->arrays->pendingMsgOffset += inputLength;
|
||||
*inOutIdx += inputLength + ssl->keys.padSz;
|
||||
*inOutIdx += inputLength;
|
||||
|
||||
if (ssl->arrays->pendingMsgOffset == ssl->arrays->pendingMsgSz)
|
||||
{
|
||||
@@ -14050,7 +14036,7 @@ int DoTls13HandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
||||
ret == WC_NO_ERR_TRACE(OCSP_WANT_READ)) {
|
||||
/* setup to process fragment again */
|
||||
ssl->arrays->pendingMsgOffset -= inputLength;
|
||||
*inOutIdx -= inputLength + ssl->keys.padSz;
|
||||
*inOutIdx -= inputLength;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user