1
0
mirror of https://github.com/ipxe/ipxe.git synced 2026-10-24 07:59:35 +03:00

7801 Commits

Author SHA1 Message Date
Michael Brown
719a85cfcc [build] Switch default build architecture to x86_64
Support for 32-bit i386 is gradually fading away across the ecosystem.
It is reasonably common to encounter devices with 64-bit MMIO BARs in
systems that place these BARs above the 32-bit address space.  These
devices cannot be used by a 32-bit build of iPXE.

The default binaries published in both the rolling release and the
tagged releases are already x86_64 rather than i386.  The only
remaining trace of the 32-bit default is the unadorned "bin/" build
directory prefix, which is currently interpreted as being equivalent
to "bin-i386-pcbios/".

Switch the default build architecture from i386 to x86_64.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-10-09 14:17:25 +01:00
Dario Faggioli
d1a6f66d38 [virtio] Fix MSI-X control register offset in legacy mode
In legacy mode when checking if MSI-X is enabled to calculate the
device-specific region offset, the code accesses the base of the MSI-X
capability structure instead of the Message Control register and, if
the Next Pointer value exceeds 0x80, the subsequent check of
PCI_MSIX_CTRL_ENABLE mask incorrectly evaluates to true.

This false positive forces an erroneous 24-byte base offset, shifting
subsequent configuration reads by 4 bytes.  This manifests as a
mangled MAC address during device probe (e.g. 34:56:01:00:ff:ff).

Fix the read offset to target the Message Control register.

Reported-by: Kent Konishi <konishi.kento@fujitsu.com>
Signed-off-by: Dario Faggioli <dfaggioli@suse.com>
Modified-by: Michael Brown <mcb30@ipxe.org>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-10-09 12:22:37 +01:00
Michael Brown
b54689abd6 [cloud] Add utility to perform automated tests of AWS instance types
Add a utility that can be used to perform a fully automated test of a
list of AWS instance types.

Suitable regions and AMIs are identified automatically.  Results are
reported by using iPXE to upload zero-length flag files to an S3
bucket using pre-signed URIs passed in the userdata script.

We use single-instance fleets rather than standalone instances.  This
allows us to specify an expiry time after which any instances will be
terminated automatically, even if the test script itself crashes.

This initial version of the test script verifies the ability to
download a 1MB test file (created by the test itself and placed in the
same S3 bucket), and verifies that the interface survives being closed
and reopened.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-10-08 15:52:23 +01:00
Michael Brown
c2c1abc16a [cloud] Enable digest commands in cloud boot images
The digest commands are useful for performing automated tests, and
cloud boot images are not size-constrained.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-10-08 15:50:49 +01:00
Michael Brown
3e92a8ece0 [cloud] Tag imported AWS images with commit ID
The imported AMI displays its commit ID as part of the startup banner,
but there is currently no sensible way to retrieve this information
without booting the image.

Add a "commit" tag to hold the commit ID from which an imported AMI
was built, to allow automated tests to unambiguously identify the
commit being tested.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-10-08 15:41:05 +01:00
Michael Brown
000a4be30a [build] Remove explicit section declarations for .note.GNU-stack
The .note.GNU-stack section is an irritant that we include only to
silence spurious warnings from the linker.

GNU binutils 2.47 changes the type of this section from "progbits" to
the arguably more correct "note", which causes build failures due to
the existing explicit "progbits" declarations.

Remove the section type declaration, allowing the toolchain to set the
section type to whatever it will later insist upon having.

Reported-by: Russ Kubes <rkubes@users.noreply.github.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-10-08 15:23:15 +01:00
Michael Brown
9178834eda [peerdist] Prefer peers discovered via IPv4
Experiments show that Windows peers will randomly and erroneously fail
retrieval protocol requests made over IPv6, reporting that the block
is not present (by setting SizeOfBlock=0 in the MSG_BLK response).
The exact same request made over IPv4 succeeds 100% of the time.

Record the most recently discovered peer separately for each discovery
socket, and attempt retrieval from the most recently discovered IPv4
peer before attempting retrieval from the most recently discovered
IPv6 peer.  (In theory, an IPv6 address could be reported via the IPv4
discovery socket (or vice versa), but experiments show that Windows
will report only addresses within the discovery socket family.)

Clear the most recently discovered peer when the discovery socket is
closed, since this is now a natural point at which to do so.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-10-08 14:37:35 +01:00
Michael Brown
e5abb335ce [peerdist] Avoid stack allocation for peer retrieval URIs
The peer location strings (i.e. the peer address for HTTP POST, or the
base URI for HTTP GET or local filesystem) are theoretically unbounded
in size.  Allocate these on the heap rather than on the stack.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-10-08 14:28:34 +01:00
Michael Brown
3b29aa5d6d [peerdist] Split peer and local filesystem cache download profilers
Separate the profilers used to record retrieval protocol downloads
using HTTP POST (i.e. downloads from a real peer, or from a hosted
cache server) from retrieval protocol downloads using HTTP GET or
equivalent (i.e. most likely coming from a local filesystem cache).

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-10-08 12:23:16 +01:00
Michael Brown
11910d30d1 [peerdist] Elide most discovery attempts
In theory, a PeerDist client should perform discovery for each
segment, and then attempt retrieval from any discovered peers.

In practice, the segment sizes chosen by the origin server are much
too small for this theoretically correct approach to be viable.  With
the typically observed PeerDist v2 segment size of around 64kB, the
total time to retrieve a segment from a peer on a gigabit LAN is
around 0.6ms.  This is almost two orders of magnitude less than the
average peer discovery response delay of ~30ms recommended by the
MS-PCCRD specification.  This peer discovery response delay becomes
the dominant limiting factor in the overall download speed.

If a peer is already known to have one segment of a file, then there
is an extremely high probability that it will have other segments of
the same file.  We therefore optimistically attempt to retrieve a new
segment from whichever peer happens to have most recently responded to
a discovery request for any other segment, while simultaneously
sending out a discovery request for the new segment.  This allows the
overall download to progress without being limited by the peer
discovery response delay.

This introduces a new problem: we end up sending out a large volume of
discovery requests that will end up being ignored because the segment
has already been fully retrieved before any peer sends a discovery
response.  Each discovery attempt generates around 1-10 network
packets (depending on the number of peers): this would be negligible
for sensibly sized segments of around 2MB but represents an increase
in traffic of up to 25% for the absurdly small 64kB segments typically
observed from a PeerDist v2 server.

Discovery requests are multicast XML documents, and impose a
non-negligible processing burden on each listening peer.  With a 64kB
segment size, the amount of processing required to parse and respond
to a discovery request vastly exceeds the amount of processing
required to just send the segment via the retrieval protocol.

Fix by adding a delay before sending the initial discovery request for
each new segment, in order to elide the sending of almost all
discovery requests.

When discovery is redundant (i.e. when we will have optimistically
retrieved the whole segment before any discovery responses might
arrive), this initial delay is long enough to allow the pending
discovery request to be cancelled before it is ever sent.

When discovery is genuinely valuable (i.e. when our optimistic
assumption that the most recently discovered peer also has the new
segment turns out to be incorrect), this initial delay still allows
plenty of time for discovery to take place before we time out and
attempt an origin server request.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-10-08 11:56:18 +01:00
Michael Brown
a5b4808625 [http] Avoid stack allocation for "user:password" string
The temporary "user:password" string constructed for HTTP Basic
authentication is theoretically unbounded in size.  Allocate this on
the heap rather than on the stack.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-10-08 11:24:54 +01:00
Michael Brown
bf16ea6014 [peerdist] Profile discovery attempts
Profile the overall duration of each discovery attempt and the time
until the first peer response, to provide some visibility into the
overall discovery behaviour.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-10-07 17:42:02 +01:00
Michael Brown
9441e24e9e [peerdist] Add some timing jitter to discovery attempts
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-10-07 17:41:33 +01:00
Michael Brown
e4c4826b5d [peerdist] Count number of discovery replies received
The emptiness or otherwise of the list of peers has not been a
meaningful test for whether or not discovery replies were received
ever since commit 9b6ad2d ("[peerdist] Assume that most recently
discovered peer can be reused").

Record the number of discovery replies received, and use this as the
test when deciding whether or not to reduce the discovery timeout.

Ignore any errors arising when reporting a discovered peer: the return
status from peerdisc_discovered() is relevant only when adding the
hosted cache server (since if a hosted cached server is defined then
no discovery will ever take place).

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-10-07 17:35:34 +01:00
Michael Brown
333316ba1d [peerdist] Split retrieval protocol and raw block download profilers
Separate the profilers used to record retrieval protocol downloads
from the profilers used to record raw block downloads from the origin
server.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-10-07 16:19:00 +01:00
Michael Brown
8865571f70 [http] Include a zero request content length when applicable
We currently send a Content-Length request header only when the
content length is non-zero.  This breaks some use cases for a PUT
request, such as uploading a zero-length file to AWS S3.

Fix by choosing whether or not to include a Content-Length request
header based on the request method.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-10-05 15:33:23 +01:00
David Yeske
6262f1081f [build] Add FreeBSD syslinux mbr.bin search path
Modified-by: Michael Brown <mcb30@ipxe.org>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-10-01 13:24:19 +01:00
Michael Brown
0e98032adb [efi] Place debug directory within .rodata section
Some strict PE parsers will refuse a debug directory that lies within
the file headers (rather than within a defined section), and will fail
to load the binary.

Place the debug directory at the start of the .rodata section for
iPXE, and at the start of the .data section for wimboot.

The debug directory irritatingly includes an RVA and a file offset,
neither of which can be calculated by the linker.  Update these fields
at the time of running elf2efi, after having calculated the file
offsets for each section.

Debugged-by: Kansu Dincer <kdincer@microsoft.com>
Debugged-by: Christian Nilsson <nikize@gmail.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-09-29 15:18:31 +01:00
Michael Brown
629e28b56c [peerdist] Allow for retrieving blocks from a local filesystem cache
The MS-PCCRR specification defines an HTTP POST request/response pair
for retrieving an encrypted block from a peer (with the decryption
keys provided separately via the content information).

The HTTP POST request parameters serve only to identify the block: the
actual response body is effectively a static encrypted blob.

Define an additional (non-standard) retrieval protocol in which the
block is identified solely using the request URI, with the response
being the same content that would be returned as the HTTP POST
response body.  This allows for encrypted blocks to be retrieved from
a static source such as AWS S3 or a local FAT filesystem, without
requiring a peer that can understand the retrieval protocol HTTP POST
request format.

Define the static request URI format as:

   <base>/xx/xxyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy-b.blk

where

   - `xxyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy` is the segment ID (HoHoDK)
     as a lower-case hexadecimal string

   - `xx` is the first two characters (i.e. the first byte) of the
     segment ID

   - `b` is the block index within the segment (which will always
     be zero when using MS-PCCRC version 2 content information), as
     an unpadded decimal string

   - the extension `.blk` represents a block file

This path format is designed to allow for efficient storage in a local
FAT filesystem (by limiting both the number of directories and the
number of entries within each directory).

Allow a base cache directory to be specified via the ${peerpath}
setting, e.g.

    set peerpath file:/peercache

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-09-27 17:41:57 +01:00
Michael Brown
744cdb451e [tls] Add support for TLS version 1.3 HelloRetryRequest
When the server does not want to use the key exchange algorithm
offered in our ClientHello, it may respond with a HelloRetryRequest
that specifies a new key exchange algorithm.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-09-22 22:37:11 +01:00
Michael Brown
f35f5977c6 [tls] Refuse to change selected protocol version or cipher suite
Handling a TLS version 1.3 HelloRetryRequest will require processing
two ServerHello messages, the second of which must not reset the
running transcript digest (and is not permitted to change the selected
cipher suite).

Move the responsibility for setting the protocol version alongside the
responsibility for setting the cipher suite in tls_select_cipher(),
and refuse to change either protocol version or cipher suite if they
have already been selected.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-09-22 22:36:54 +01:00
Michael Brown
b49d049249 [tls] Record verification length separately from cipher suite
For a renegotiation, we currently rely on the previously selected
cipher suite to determine the length of the verification data.  This
is the only context in which the recorded cipher suite does not
represent the selected cipher suite for the current connection.

Record the verification length separately as part of the verification
data structure, allowing the selected cipher suite to be cleared when
restarting the connection so that it unambiguously represents the
currently selected cipher suite at all times.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-09-22 18:41:41 +01:00
Michael Brown
23d6038c7a [tls] Generalise mechanism for duplicating a TLS cursor
Generalise the mechanism used for storing a session ticket to allow
for storing copies of arbitrary TLS cursors.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-09-22 16:30:59 +01:00
Michael Brown
d2a9fbe7b9 [tls] Always use zfree() rather than free()
TLS currently uses free() instead of zfree() where the memory being
freed contains no secrets.  The cost of using zfree() everywhere is
negligible (no code size increase, and used only in non-fast-path
operations), and avoids the need to reason about whether or not the
memory contains secrets.

Switch to using zfree() unconditionally throughout the TLS code.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-09-22 16:30:59 +01:00
Michael Brown
4aabb077ef [crypto] Add support for the TLS "message_hash" synthetic record
On receiving a HelloRetryRequest, the running transcript hash gets
replaced with a synthetic message of type "message_hash" containing
the current value of the running transcript hash (which at that point
covers only the initial ClientHello).

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-09-22 16:30:56 +01:00
Michael Brown
21d972d741 [crypto] Check length before decrypting data
Using a CBC-mode cipher with a length that is not a multiple of the
block size will cause an uncontrollable out-of-bounds write of the
entire address space, resulting in a guaranteed crash.  There is no
way to cause the CBC cipher to return before overwriting the entire
address space with pseudorandom data, and so this could only be used
as a denial-of-service attack.

Almost all cipher call sites already validate the length against the
block size.  Add the relevant checks to the two call sites that do not
already do so.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-09-22 12:10:48 +01:00
Michael Brown
0367d09926 [test] Ensure that all TLS structure descriptor mappings are valid
Constructing exhaustive standalone tests for all TLS structures is
time-consuming and of limited value, since there would be no guarantee
that the construction logic used in the test case matched the
construction logic matched in the real TLS protocol engine.

We already exercise each failure path that can be triggered by genuine
runtime errors (e.g. malformed received data, or transmit data that is
too large to fit within the relevant length field).  This leaves
untested the other major class of errors: an invalid structure
descriptor mapping (e.g. a missing field description) that would
render the structure impossible to parse or build.

Exercise the parser and builder for every structure type by creating
an all-zero descriptor (which is always permitted), sizing and
building the empty structure, and then parsing that structure.  This
ensures that the parser and builder are both satisfied that the
descriptor mapping is valid, since the validity of the mapping is
independent of the data being built or parsed.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-09-22 10:35:08 +01:00
Michael Brown
2b6bd7660b [tls] Remove redundant null pointer check
The recorded key exchange group is selected at initialisation and can
never be set to NULL, in the same way that the cipher suite can never
be set to NULL (and is therefore not checked at the points of use).

Remove the redundant null pointer check, since it simply serves to
confuse readers of the code.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-09-22 10:15:01 +01:00
Michael Brown
1037cf358f [tls] Allow session to be saved multiple times
TLS version 1.3 defers the NewSessionTicket until after the handshake
has completed, and allows the server to send multiple NewSessionTicket
messages (e.g. to refresh short-lived tickets).

The default session ID generated in tls_save() will currently end up
with the same value on each invocation.  While session IDs are unused
in TLS version 1.3, this could lead to confusing debug messages and
packet captures.

Add a function tls_random() to generate random nonces using the
channel ephemeral secret, a label, and a 64-bit counter, and this
function to generate unique session IDs.

Non-sequential record IVs are also generated using channel ephemeral
secrets.  Simplify this code by using tls_random() instead of a direct
call to channel_ephemeral().

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-09-21 23:02:04 +01:00
Michael Brown
194306d457 [crypto] Ignore any data digested before TLS key schedule is started
The initial ClientHello is sent and digested before the key schedule
has been started (since the digest algorithm is not known until the
ServerHello arrives).

A server that sends a premature ServerHello with an all-zero nonce
before the ClientHello is sent can currently cause the key schedule's
"nonced" flag to become set.  The flag will be reset when the key
schedule is started and so this is unclean but harmless.

Fix by ignoring any data that arrives before the digest algorithm has
been set (i.e. before the key schedule has been started), since the
null digest algorithm cannot meaningfully incorporate anything into a
running transcript digest.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-09-21 18:16:19 +01:00
Michael Brown
ed4a9b2e67 [tls] Clear any saved state when saving a new session
If the server switches from providing stateless session tickets to
providing stateful session IDs, then we will currently end up with a
stored session that retains the old session ticket along with the new
session ID.  (This behaviour has been observed when connecting to an
Apache server that requires per-directory client authentication or
per-directory cipher suites: the server originally provides a
stateless session ticket but then, after renegotiation to request the
client certificate, provides a stateful session ID instead.)

Reset both the session ID and the session ticket whenever a new
session is saved (i.e. if the server provides either a new session ID
or a new session ticket), so that we do not retain stale credentials.

If no new session ID is provided, then create a new random session ID
(rather than leaving the session with an empty session ID) since we
rely on the echoed non-empty session ID to determine whether or not
the server is choosing to resume, even for stateless sessions.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-09-21 17:48:06 +01:00
Michael Brown
b36e8472d4 [tls] Use standalone TLS data structure builder
Define structure descriptors and mappings for every data structure
currently sent by the TLS protocol engine, and use the standalone data
structure builder to remove a large amount of open-coded layout and
assembly logic.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-09-21 00:23:03 +01:00
Michael Brown
2e549711c2 [tls] Use server certificate's own public key algorithm for verification
For TLS version 1.1 (without explicit signature hash algorithm
identifiers), we currently use the cipher suite's public key algorithm
when verifying the ServerKeyExchange signature.  This is indirectly
guaranteed to match the server certificate's own public key algorithm.

Use the server certificate's own public key algorithm directly, to be
consistent with the behaviour for client certificates.  The signed
certificate is, by definition, the authoritative source for its own
choice of public key algorithm.

This leaves the public key algorithm aspect of the cipher suite as
being unused outside of debug messages.  We do not enforce the
specification that the certificate's public key algorithm must match
the cipher suite's public key algorithm (if any) because doing so
serves no cryptographic purpose.  For TLS version 1.2 and later, the
explicit signature hash algorithm identifiers override the cipher
suite, and in TLS version 1.3 the whole concept of a public key
algorithm is removed from the scope of the cipher suite.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-09-20 20:33:15 +01:00
Michael Brown
69c5cbea77 [tls] Use client certificate's own public key algorithm for signing
Mirroring commit cbdb572 ("[crypto] Use certificate's own public key
algorithm for key matching"), the client CertificateVerify is also
currently constructed using the certificate's signature algorithm
(i.e. the public key algorithm of the issuer's key) rather than the
certificate's own public key algorithm.

Fix by using the certificate's own public key algorithm.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-09-20 15:11:50 +01:00
Michael Brown
76f7b88f93 [crypto] Allow for signable MD5 or SHA-1 digests with TLS version 1.1
For TLS version 1.1, non-RSA signed digests use SHA-1 instead of
MD5+SHA1.  Commit f095adb ("[tls] Use SHA-1 for TLS version 1.1 ECDSA
signatures") selected the correct digest algorithm for both server and
client authentication.

However, the key schedule currently refuses to generate client
CertificateVerify digests for any digest algorithm other than
MD5+SHA1, on the basis that only the MD5+SHA1 running transcript
digest value is available.

An MD5+SHA1 digest value is just the concatenation of an MD5 digest
value with a SHA-1 digest value, and so the SHA-1 digest value can be
provided for use with ECDSA client certificates.

Fix by special-casing the SHA-1 (and MD5) algorithms when generating a
signable digest value from the TLS version 1.1 key schedule.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-09-20 14:39:41 +01:00
Michael Brown
cbdb57278d [crypto] Use certificate's own public key algorithm for key matching
When finding the certificate corresponding to a private key, the match
is currently performed using the certificate's signature algorithm
(i.e. the public key algorithm of the issuer's key) rather than the
certificate's own public key algorithm.  This breaks key matching for
heterogenous certificate chains (e.g. an ECDSA client certificate
issued by an RSA intermediate certificate).

Fix by using the certificate's own public key algorithm.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-09-20 14:39:41 +01:00
Michael Brown
cff60d28d6 [build] Allow for non-RSA private keys
Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-09-20 14:39:41 +01:00
Michael Brown
b4d9949db1 [tls] Propagate sizing errors to containing data structures
The existing ad hoc code that builds TLS data structures generally
performs a single length calculation and a single allocation, and if
the allocation succeeds then the data structure will be filled in with
no possible further errors arising.

Allow this pattern to be replicated when using the generic builder, by
ensuring that an error in calculating the length of a contained data
structure (e.g. an extension) will automatically propagate that error
to the calculation of the length of the containing structure (e.g. a
ClientHello that contains the extension).

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-09-20 14:39:41 +01:00
Michael Brown
65450656e5 [tls] Add a standalone TLS data structure builder
Provide a generic builder that can construct an arbitrary TLS data
structure based upon the same descriptors and binary-encoded mappings
as used for the generic parser.

The design allows for the caller to either provide data in advance or
to write through the descriptor pointers after building the data
structure.  For example: this will allow the public key within a
ClientHello to be populated in situ within the key_share extension,
rather than requiring the caller to allocate and populate a temporary
buffer before building the ClientHello.

This necessitates removing the "const" from all pointers within the
descriptors, which is a worthwhile tradeoff for the sake of avoiding a
large number of temporary allocations.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-09-19 12:48:31 +01:00
Michael Brown
05fa853241 [tls] Allow for an empty list of extensions of interest
The binary encoding used by the TLS data structure parser currently
cannot correctly express the concept of an extensions field unless
there is at least one extension of interest.  An extensions field that
has zero extensions of interest ends up being encoded as just a
standard variable-length field.

This effectively makes any such extensions fields non-optional, since
the test for optionality can only detect fields with a non-zero number
of extensions of interest.  (This is a somewhat hypothetical issue,
since the only optional extension fields are found in ClientHello and
ServerHello, both of which have extensions of interest.)

Adjust the encoding to allow extensions fields to be identified even
if there are no extensions of interest therein.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-09-18 22:52:19 +01:00
Michael Brown
42826fa9d9 [build] Allow MD5+SHA1 algorithm to be discarded at link time
All symbol references to the MD5+SHA1 algorithm will be eliminated if
TLS_VERSION_MIN is set to a version greater than TLS version 1.1.

However, the dummy RSA digestInfo prefix is retained since it is a
linker table entry.  This dummy prefix object holds a pointer to the
MD5+SHA1 algorithm and so prevents it from being garbage collected by
the linker.

Remove the dummy empty RSA digestInfo prefix and instead allow a
digest to be encoded without any prefix for the MD5+SHA1 digest
algorithm.

Use a custom test to allow the MD5+SHA1 algorithm to be identified
without using a symbol reference to md5_sha1_algorithm, since even a
weak reference would suffice to cause the symbol to be retained once
some other object drags it in to the build, and this is essentially
guaranteed to happen: tlskey_md5_sha1 drags in md5_sha1_algorithm,
which causes any existing weak references to be promoted to strong
references, and those strong references remain even if tlskey_md5_sha1
is later garbage collected.

The custom test uses a one-byte sentinel in .bss to give us a unique
value to place in digest->priv: this can then be used to identify
MD5+SHA1 without any symbol reference to md5_sha1_algorithm.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-09-18 19:24:00 +01:00
Michael Brown
f095adbed2 [tls] Use SHA-1 for TLS version 1.1 ECDSA signatures
We currently use the MD5+SHA1 algorithm for all signatures when using
TLS version 1.1.  This is incorrect for ECDSA (or for any non-RSA
public-key algorithm): these should instead use SHA-1.

Fix by using SHA-1 for any non-RSA public-key algorithm for TLS
version 1.1.

Provide a weak rsa_algorithm symbol to use in the comparison, to avoid
unconditionally dragging in RSA support.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-09-18 16:38:24 +01:00
Michael Brown
6deb51d66c [tls] Avoid dragging in MD5+SHA1 algorithm unconditionally
Use a version check to gate the selection of md5_sha1_algorithm as the
signature digest algorithm, since this can be optimised out at build
time if the minimum version has been configured to be higher than TLS
version 1.1.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-09-18 16:17:15 +01:00
Michael Brown
8402079a17 [tls] Use standalone TLS data structure parser
Use the standalone data structure parser to remove a large amount of
open-coded parsing and bounds checking logic.

We retain the simple open-coded check for the handshake data structure
itself, since tls_new_handshake() needs to be able to treat partially
received data as valid (and defer processing until enough data is
available to cover a complete handshake).

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-09-18 15:02:38 +01:00
Michael Brown
89cfb681a4 [tls] Add a standalone TLS data structure parser
iPXE originally supported only TLS version 1.0, which uses mostly
fixed-size data structures and required only a few mostly simple
bounds checks.

Over the years, the amount of open-coded parsing and bounds checking
code has grown gradually to the point that it comprises a substantial
portion of the overall TLS implementation.  This makes the code
difficult to read, and requires careful review to ensure that all of
the different parsing and bounds checking code is correct.

Define an abstraction for decomposing the component parts of a TLS
data structure into a descriptor structure comprising a sequence of
field data pointers and lengths, along with an efficient binary
encoding that can describe the mapping between the decomposition and
the raw data structure.

Provide a generic parser that can interpret the binary-encoded mapping
and populate the descriptor structure, along with mappings for every
data structure currently interpreted by the TLS protocol engine.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-09-18 15:01:14 +01:00
Michael Brown
1135b79660 [tls] Fix building with TLS_VERSION_MAX set to TLS version 1.1
Commit 356bb14 ("[tls] Detect version downgrade attacks") introduced a
build failure under -Werror and -Wtype-limits when TLS_VERSION_MAX is
set to TLS_VERSION_TLS_1_1 due to the constructed test that checks if
an unsigned integer is less than zero.

Downgrade attack detection is impossible anyway when the maximum
version offered is TLS version 1.1, and so this always-false test is
perfectly correct: the desired outcome is that the downgrade detection
is optimised out at build time.

Fix the build error by adjusting the comparison to be performed using
signed integers to avoid the -Wtype-limits check.  Add a separate
check that the maximum version is higher than TLS_VERSION_TLS_1_1 to
ensure that the whole downgrade detection code block is optimised out
as dead code if it cannot ever be reached.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-09-18 15:01:12 +01:00
Michael Brown
01081fd911 [libc] Set return type for byte-swapping macros regardless of endianness
When the byte-swapping macros are no-ops (i.e. when they match the
platform's native endianness), the type of the parameter is used
directly as the type of the expression.  This can result in the type
of the expression differing between little-endian and big-endian
platforms.

Fix by including a cast within the no-op variants, so that the type of
the expression is consistent across all platforms.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-09-18 12:52:57 +01:00
Michael Brown
7cd92e01d6 [tls] Handle TLS version 1.3 client Finished
The TLS version 1.3 client Finished is somewhat messy to handle: its
verify_data must be calculated with the key schedule still holding the
client handshake traffic secret, the application traffic secret must
be calculated before the client Finished is added to the transcript
digest, and the application traffic keys must be activated only after
sending the client Finished.  Since the action of sending the client
Finished also adds the client Finished to the transcript digest, this
necessitates an awkward sequence of events.  (A cleaner protocol
design might have chosen to derive the client application traffic
secret from the transcript digest up to and including the client
Finished.)

Perform the various necessary contortions to construct the client
Finished and to transition to using the application traffic secrets.

With this commit, TLS version 1.3 is functional for the first time.
It is not yet enabled by default, since there are still some missing
features such as session resumption.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-09-14 22:47:45 +01:00
Michael Brown
267445294a [tls] Do not schedule sending of unused records in TLS version 1.3
The ClientKeyExchange record does not exist in TLS version 1.3 (since
key exchange happens instead via ClientHello).

The Change Cipher record does not exist in TLS version 1.3, at least
not in the form of something that can be transmitted via the normal
active cipher.

Skip scheduling both of these records for transmission.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-09-14 22:42:55 +01:00
Michael Brown
ba64f5d2fb [tls] Ignore TLS version 1.3 NewSessionTicket
Session resumption in TLS version 1.3 is structurally different from
TLS version 1.2, and will not initially be supported.

Ignore any NewSessionTicket records for now, since they will otherwise
cause the connection to be aborted.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2026-09-14 22:34:44 +01:00