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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
When a certificate chain is provided, the TLS version 1.3 server
Finished provides the point at which we can start validating the
certificate chain, equivalent to the ServerHelloDone in TLS version
1.2 and earlier.
The TLS version 1.3 server Finished also provides a convenient point
at which we can calculate the master secret, and defines the point at
which we must schedule the receive cipher to transition to using the
application traffic key.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The ServerHello provides the earliest point at which the handshake
traffic keys can be generated, and the defined point at which the
receive cipher must transition to using the handshake traffic key.
We do not intend to support sending early data, and so this also
provides a convenient point at which to transition the tranmit cipher
to using the handshake traffic key.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
There are several point within the TLS version 1.3 handshake sequence
at which a handshake message handler needs to transition one or both
ciphers to a new traffic phase, but the new cipher keys cannot be
calculated by the key schedule until the triggering handshake message
has been added to the transcript digest.
Handshake messages are added to the transcript digest only after the
message handler returns, to accommodate the fact that the transcript
digest algorithm cannot be known until the initial ServerHello has
been processed.
Allow a new traffic phase to be recorded in the cipher specification,
which will be activated after the handshake message handlers have
returned.
Changing traffic phase requires changing the cipher in use, and so is
permitted only for the last handshake message in a handshake record.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The format of the signature found within a CertificateVerify is
identical to the format of the signature within a ServerKeyExchange.
Abstract out the logic for verifying a ServerKeyExchange and use it to
verify the signature for both ServerKeyExchange and CertificateVerify.
Note that a CertificateVerify that is erroneously received under TLS
version 1.2 will always fail verification because the key schedule is
not able to generate a signable digest for the server endpoint.
A ServerKeyExchange that is erroneously received under TLS version 1.3
will fail validation because the TLS version 1.3 cipher suites provide
no way to parse the ServerKeyExchange parameters. (An interestingly
deviant server that chooses to negotiate TLS version 1.3 with a TLS
version 1.2 cipher suite would be able to send a ServerKeyExchange
with a valid signature and have that key contribute accumulatively to
the key schedule: this would not conform to the protocol, but does not
actually weaken any of the security properties required to establish
the secure channel.)
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The TLS version 1.3 Certificate record includes a certificate request
context and an arbitrary list of extensions, both of which we ignore.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
TLS version 1.3 masquerades as TLS version 1.2 on the wire for the
benefit of badly engineered firewalls and other intermediate devices
that attempt to inspect the protocol stream.
Once a non-plaintext cipher is in use, all records masquerade as
application data, with the unencrypted record comprising the real
record content followed by the real type byte and an arbitrary amount
of zero padding.
Extract the inner plaintext on receive, and create the simplest
possible inner plaintext (with no zero padding) on transmit.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The TLS version check already optimises down to a compile-time
constant if the specified version is guaranteed by the configured
minimum supported version.
Extend this check to also take into account the configured maximum
supported version.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
TLS version 1.3 allows unencrypted Change Cipher records to be sent
after switching to use the handshake traffic keys. This is an ugly
protocol hack to work around badly implemented firewalls of the kind
beloved by large organisations.
Ignore and discard any such records, which would otherwise cause
decryption failures.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The authentication header used for TLS version 1.3 no longer includes
the sequence number, since the use of sequential initialisation
vectors renders it redundant.
Skip authenticating this portion of the authentication header for TLS
version 1.3 or later.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The CBC ciphers require a fully unpredictable initialisation vector,
which we currently generate as a channel ephemeral secret. The GCM
ciphers require only a unique initialisation vector: there is no
requirement for it also to be unpredictable. The content of the
record IV portion of the IV is a free choice of the sender, and we
currently use an unpredictable value for both CBC and GCM.
TLS version 1.3 removes the record IV portion for GCM ciphers, instead
constructing the IV by XORing the sequence number into the end of the
fixed IV.
Define the concept of a sequential initialisation vector as meaning
that the sequence number is XORed into the end of the overall
initialisation vector (which may be either the fixed IV or the record
IV portion), with no per-record unpredictable value required. This
allows us to represent the mechanism required for TLS version 1.3, and
avoid the unnecessary cost of generating a channel ephemeral secret
for a GCM cipher under TLS version 1.2.
On the receive side, the XORed portion may be overwritten by the real
record IV, since the sender's choice is always definitive for the
contents of the record IV.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
TLS version 1.3 masquerades as TLS version 1.2 on the wire for the
benefit of badly engineered firewalls and other intermediate devices
that attempt to inspect the protocol stream.
Limit the maximum version in transmitted record headers to be TLS
version 1.2. (Continue to accept any version in received record
headers, since this value has never had any significance.)
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The cipher specifications are currently modelled as an active cipher
specification that corresponds to the cipher currently in use by the
secure channel abstraction, and a pending cipher specification that
corresponds to the cipher that will be swapped in after the next
ChangeCipherSpec.
This design reflects the wording of RFC 2246 through to RFC 5246:
"there are always four connection states outstanding: the current read
and write states, and the pending read and write states".
This model does not map well to TLS version 1.3, with its multiple
phases of traffic secrets and somewhat idiosyncratic choices of
transcript boundaries. The client Finished message is a particular
problem: the client application traffic secret must be calculated
after constructing the client Finished verify_data but before adding
the client Finished to the transcript digest (i.e. before encrypting
it with the client handshake traffic keys). This is an irritating
asymmetry with the server application traffic secret, which may be
calculated cleanly after the server Finished message has been added to
the transcript digest.
Switch to a model in which only the active cipher specification
exists, and always corresponds to the cipher currently in use by the
secure channel abstraction.
Move the record sequence number to become part of the cipher
specification, so that the sequence number reset logic can be shared
between the transmit and receive paths.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
RFC 8446 defines the key_share extension as a mechanism for ephemeral
key exchange (replacing ServerKeyExchange and ClientKeyExchange).
Add support for sharing a key in our ClientHello and for parsing the
shared key from a ServerHello. Construct the ClientHello on the heap
rather than on the stack, since the shared key values may be large
(e.g. for FFDHE4096).
Select the most preferred named group for sending the initial shared
key. (We do not yet handle a HelloRetryRequest: if the server chooses
a different named group then we will record this group but do not yet
support sending the second ClientHello.)
We do not explicitly reject a key share extension received from a
server that negotiated TLS version 1.2 or lower. Any such key will be
successfully used to establish a shared secret (and so the secure
channel will become keyed), but there is no way for this shared secret
to subsequently be successfully bound to the server's identity: a
ServerKeyExchange would replace the shared secret (since the TLS
version 1.2 key schedule is not accumulative), and a CertificateVerify
would fail to generate a signable digest.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The TLS version 1.3 ClientHello includes a key_share extension whose
value will depend upon the selected key exchange named group. The
incorporation of the initial ClientHello into the selected handshake
digest must therefore be done before the named group is potentially
modified.
Move responsibility for adding the initial ClientHello to the
transcript digest from tls_new_server_hello() to tls_select_cipher(),
so that this can be done before updating the selected named group.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
RFC 8446 redefines the session ID within a TLS version 1.3 ServerHello
as being a field that must always echo the session ID from ClientHello
(and no longer indicates that session resumption is taking place), as
a workaround for badly engineered middleware boxes.
Skip ID-based session resumption if the negotiated version is TLS
version 1.3 or later, and instead abort the connection if the session
ID is not echoed verbatim (as per the RFC).
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The signable digest value is used to bind the server identity to the
shared secret, and so the digest must be computed over the parameters
used to establish the shared secret.
For both endpoints in TLS version 1.3 and for the client endpoint in
TLS version 1.2, the digest is computed over the running transcript
hash and so already includes the parameters used to establish the
shared secret.
For the server endpoint in TLS version 1.2, the digest is computed
over only the client and server random bytes plus any additional data
passed in by the caller, and so this additional data must include the
parameters used to establish the shared secret.
The signable digest value for the server endpoint is currently
computed only in response to a ServerKeyExchange record, in which case
the additional data correctly contains the parameters from that record
that were used to establish the shared secret.
Adding support for TLS version 1.3 will necessitate adding the ability
to parse a received CertificateVerify record, which will attempt to
construct a signable digest value with no additional data.
Require additional data to be provided when constructing a signable
digest value for the server endpoint using the TLS version 1.2 key
schedule, to prevent a CertificateVerify from potentially being used
to verify a digest that was not computed over the parameters used to
establish the shared secret.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The signable digest value is used to bind the server identity to the
shared secret, and so the digest must be computed over the parameters
used to establish the shared secret in order to be meaningful.
The secure channel will refuse to bind the peer identity on the basis
of a verified signable digest if the channel does not already contain
key material derived from a shared secret.
A signable digest that was erroneously constructed before a shared
secret was applied is therefore guaranteed to be unusable for binding
the channel, provided that the caller uses a sensible sequence of
operations (i.e. constructs the signable digest and then immediately
attempts to use it to bind the peer identity).
Strengthen this guarantee further by refusing to generate a signable
digest value unless the key schedule already contains key material.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
RFC 8446 defines a mechanism that allows (but does not guarantee) the
detection of version downgrade attacks, based on magic signature
values placed within the ServerHello random bytes. The magic
signature will be present if the server supports any version higher
than the negotiated version, and so may be present if the server
supports a higher version than we are offering.
The last byte of the magic signature is non-constant and is defined to
match the server's negotiated protocol version, encoded as a delta
from the value 0x0302 representing TLS version 1.1 (or lower). Since
the server random bytes are always used in the construction of
verify_data (even in older versions of TLS without the extended master
secret), this encoding of the negotiated version cannot be forged by
an attacker.
If the version that is negotiated is lower than the version that we
offered (i.e. if a downgrade attack could possibly be happening), then
check for the range of magic signatures that could indicate a
downgrade attack, and terminate the connection if applicable.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
RFC 8446 caps the version number field in ClientHello and ServerHello
to represent at most TLS version 1.2, as a workaround for badly
engineered servers and middleware boxes. The actual protocol version
is instead negotiated via the supported_versions extension.
Send the list of supported versions in the ClientHello, and parse the
selected version from the supported_version extenion if present in the
ServerHello.
Signed-off-by: Michael Brown <mcb30@ipxe.org>