An RSA signature value (or encrypted message value) is a congruence
class modulo the field prime, and so adding a multiple of the field
prime does not logically change the validity of the signature (or the
content of the encrypted message).
However, RFC 8017 states that both the decryption primitive (section
5.1.2) and the verification primitive (section 5.2.2) should reject
non-canonical input values (i.e. any value that is not strictly less
than the field prime), and some public test vector sets check for this
rejection.
Treat any signature value or encrypted message value that is equal to
or greater than the field prime as being invalid.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
RSA PKCS#1 requires a minimum of eight non-zero padding bytes for
encryption. This limit is currently enforced when encrypting but not
validated when decrypting.
The only existing code path that can currently lead to RSA decryption
is CMS decryption, which can use RSA to decrypt the cipher key. With
underlength PKCS#1 padding (and hence an overlength plaintext), the
decrypted cipher key would be rejected by the immediately following
call to cipher_setkey().
Add the missing padding length check as part of RSA decryption, and
add a test case (imported from Project Wycheproof) to ensure that this
check remains in place in future.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Some public RSA and ECDSA test vector sets provide only the private or
public half of the key pair, and reuse the same key for multiple tests
within the set.
Allow public-key tests to omit either half of the key pair, and to
therefore perform separate tests for encryption, decryption, signature
generation, and signature verification.
The existing RSA and ECDSA tests (which all include a full key pair)
are unchanged by this reorganisation.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The Project Wycheproof RSA and ECDSA tests define the key as a
property of the test group rather than of the individual test case.
Allow test groups to have stable identifiers and to participate in
generating the source code for the test definitions.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The schema and test counts are currently validated only at the point
of attempting to generate source code. Promote these checks to become
standard validators.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
A zero-length IV is not permitted by the NIST GCM specification, since
it would lead to leaking the authentication key.
The only existing code path that can currently lead to the use of a
GCM cipher with a zero-length initialisation vector is CMS decryption.
Modifying a CMS encrypted message to include a zero-length IV would
leak information required to obtain the authentication key into the
transient decrypted image, but this transient image would then fail
the GCM authentication tag check and so the decrypted plaintext would
be immediately overwritten (with the re-encrypted ciphertext).
Improve robustness by rejecting a zero-length initialisation vector
for a GCM cipher, and add a test case to ensure that this rejection
remains in place in future.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Some public HKDF test vectors provide only the expected output key
material, without specifying the expected pseudorandom key used to
generate the output key material.
Allow HKDF tests to omit the expected pseudorandom key, so that we can
use these public test vectors without needing to synthesize an
expected pseudorandom key value.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Some public HMAC test vectors provide expected output digest values
that are shorter than the digest size.
Allow HMAC tests to provide expected output digest values of any
non-zero length up to and including the digest size, so that we can
use these public test vectors without needing to synthesize the
remainder of the output digest value.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Move per-algorithm parameters (such as the key sizes for key exchange
algorithms) to the test file level of the data structure, thereby
avoiding the need to create three classes (test file, test group, and
test case) for every per-algorithm specialisation.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Project Wycheproof (https://github.com/C2SP/wycheproof) provides test
vectors designed to exercise cryptographic algorithms with corner
cases that are not covered by the standard known-answer tests such as
those provided by NIST or in RFCs.
Create an import tool to read the applicable subset of the Project
Wycheproof key exchange test vectors and generate the corresponding
iPXE key exchange test cases, and create a wrapper for running the
resulting tests within iPXE.
The full imported test set is extremely large and slow to run. We
deliberately choose not to included these tests within the standard
per-commit test suite, since this would substantially delay all test
runs for no significant benefit.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
A duplicate ServerHelloDone could cause the server validation pending
operation to be incremented twice but only decremented once, leaving
the total pending operation count above zero and thereby causing any
future "sync" command with no timeout to wait indefinitely.
Fix by rejecting ServerHelloDone if validation is already pending.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
We currently protect against a consumer that erroneously uses values
generated from the ephemeral master secret after closing a previously
opened channel, by deliberately replacing the ephemeral master secret
rather than zeroing it when the channel is closed.
Extend this concept to protect against a consumer that erroneously
uses the ciphers after closing a previously opened channel (or that
erroneously uses the ciphers from a channel that failed to open
successfully), by using the dead ciphers by default and by enabling
the plaintext (null) ciphers when and only when the channel has been
successfully opened.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Certificate chains are reference-counted structures, and both the TLS
connection and the validator hold a reference to the same certificate
chain while validation is in progress. The TLS connection will not
mutate the chain during this time: if a second (illegal) Certificate
record were to arrive then it would drop its reference to the existing
chain (leaving the validator as the sole possessor) before creating a
new chain to hold the received certificates.
The validator currently holds two pointers that could be invalidated
if a future code change were to cause the chain to be externally
mutatated while validation is in progress:
- a pointer to the current certificate (for OCSP or cross-signed
downloads) that does not hold its own reference and relies upon
the chain's reference to keep the certificate pointer valid
- a pointer to the current link within the certificate chain
Guard against this class of potential future code changes by promoting
the certificate pointer to hold its own reference to the certificate
so that it is guaranteed to remain valid, deleting the stored pointer
to the current link completely, and adding a function x509_link() that
is used to locate the certificate link by traversing the chain.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Document the deliberate absence of enforced handshake record ordering,
and update data structure comments to clarify which pointer fields are
allowed to have NULL values.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Following the example of commit 8ef91dd ("[tls] Make certificate
sending visibly safe at point of use"), add runtime checks in the
functions that consume the server certificate chain so that the safety
guarantee becomes immediately visible, and to avoid potential future
bugs.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Sending a client certificate chain and its corresponding certificate
verification will be triggered only if we actually have these items to
send, and so the pointer dereferences within those functions are safe.
However, this safety guarantee is not visible at the point of use.
Add runtime checks in those functions so that the safety guarantee
becomes immediately visible, and to avoid potential future bugs.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The transmit and receive ciphers are now owned by the secure channel.
We assert at the point of use that the cipher algorithm used by the
secure channel matches the algorithm in the currently active cipher
specification's cipher suite, but this does not guard against future
code changes that could accidentally leave these out of sync, and
thereby end up passing an incorrectly sized context to the cipher.
Fix by treating the secure channel as having the definitive record of
the current cipher algorithm, and treating the algorithm specified in
the cipher suite as being used only as a parameter for initialising
the transmit or receive pipe via the secure channel.
This matches the way that we treat the key schedule as having the
definitive record of the current handshake digest algorithm, with the
algorithm specified in the cipher suite being used only as a parameter
for initialising the key schedule.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Use a dedicated parser function for unexpected ServerKeyExchange
records, to create an invariant that the parser function field always
has a non-NULL value.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The DHE and ECDHE ServerKeyExchange parsers will always return the
identified key exchange algorithm in the parsed parameters. The
default key exchange algorithm is therefore never used for these key
exchange mechanisms.
Set the default key exchange algorithm for DHE and ECDHE to be the
null key exchange algorithm (which will always fail operations), and
also set this as the in-use key exchange algorithm when a TLS
connection is first initialised.
This creates an invariant that the TLS connection always has a valid
key exchange algorithm pointer even if that pointer does not yet
represent the algorithm being used, matching the usage pattern for the
TLS connection's cipher suite and reducing the opportunities for
potential future NULL pointer dereferences.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Enforce the invariant that all pointer fields have non-NULL values in
all cipher suites by refusing to ever select a cipher suite that fails
this invariant check.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
A cipher suite's handshake digest algorithm is used only once that
cipher suite has been selected. The null cipher suite can never be
explicitly selected, and so its handshake digest algorithm can never
be used and is currently left as a NULL pointer.
Set the null cipher suite's handshake digest algorithm to be the null
digest algorithm, to create an invariant that all pointer fields have
non-NULL values in all cipher suites.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The AEAD cipher suites all have a zero MAC length, since message
authentication is provided by the AEAD cipher itself and the MAC
digest algorithm is never used.
Avoid an unnecessary and unused stack allocation (for the MAC digest
output value) by switching these cipher suites to use the null digest
algorithm instead.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Since commit 72db146 ("[tls] Split received records over multiple I/O
buffers"), receive record processing has worked by allocating an I/O
buffer list with exactly enough combined tailroom to hold the incoming
record.
A zero-length record is not permitted by the protocol (and is
impossible when a non-plaintext cipher is in use due to the extra
space reserved at the start of the buffer list to accommodate the IV),
but would currently result in an empty I/O buffer list.
Fix by ensuring that at least one buffer is always allocated even for
a zero total length.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The TLS implementation has become too complex to reason about safely,
and needs to be split up into smaller and well-defined units before
adding any further complexity (e.g. to support TLS version 1.3).
Use the standalone secure channel implementation to ensure that the
connection can be used for encrypted communication with a trusted
peer, with the secure channel operations being provided by the
standalone TLS key schedule implementation.
The TLS implementation is now just a protocol engine, and is no longer
responsible for policy decisions on whether or not the connection is
secure. The TLS code delegates this decision to the underlying secure
channel, by refusing to transmit or receive application data unless
the secure channel has successfully been marked as established.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The TLS implementation has become too complex to reason about safely,
and needs to be split up into smaller and well-defined units before
adding any further complexity (e.g. to support TLS version 1.3).
Define an abstraction of a TLS key schedule responsible for performing
all cryptographic calculations required by the TLS protocol. Three
implementations of this abstraction are provided:
- a TLS version 1.3 key schedule using HKDF
- a TLS version 1.2 key schedule using PRF based on P_Hash()
- a TLS version 1.0/1.1 key schedule using PRF based on
P_MD5()+P_SHA1()
Test cases are included for the HKDF key schedule using the example
known-working handshake traces provided in RFC 8448, and for the
earlier key schedules using manually constructed dummy minimal tests
(with non-functional handshake records) that at least guard against
future regressions.
The separation of concerns will allow the TLS code to become merely a
(still fairly complex) protocol engine, with the responsibility for
all cryptographic calculations being delegated to the key schedule
implementation.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The TLS implementation has become too complex to reason about safely,
and needs to be split up into smaller and well-defined units before
adding any further complexity (e.g. to support TLS version 1.3).
Define a generic concept of a secure channel as comprising a pair of
ciphers (one for transmit, one for receive) together with the
cryptographic state required to establish that these ciphers may be
used for encrypted communication with a trusted peer.
The secure channel model is loosely constructed as a generalisation of
TLS minus the protocol specifics, and covers all the expected patterns
of operation for TLS versions 1.1 to 1.3 (including classic RSA key
transport with no forward secrecy, ephemeral key exchange via either
ClientKeyExchange and ServerKeyExchange or via key_share extensions in
ClientHello and ServerHello, and session resumption via either session
IDs, session tickets, or pre-shared keys).
The separation of concerns will allow the TLS code to become merely a
(still fairly complex) protocol engine, with the responsibility for
ensuring the security of the connection being delegated to the secure
channel implementation.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Define structures to hold session IDs and session tickets, and use
these within the TLS session and connection structures.
Redefine the session ID embedded within the connection structure as
representing the new session ID (if provided), with the existing
session ID now read directly from the session structure. This reduces
confusion by matching the semantics of the session ticket.
Centralise functions for saving and resuming sessions, to separate
this logic from the protocol parsing code.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Reduce hidden state by making the key exchange algorithm an explicitly
parsed parameter from the ServerKeyExchange record, and storing it
only for the purpose of defining which key exchange algorithm should
be used when sending a ClientKeyExchange.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
In preparation for delegating the separate but related concepts of a
secure channel and a TLS key schedule, split these into separate data
structures.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Restructure the key exchange abstractions to provide a single method
to parse the suite-specific ServerKeyParams structure, with the
signature verification subsequently performed by the caller.
Reduce the suite-specific variation for ClientKeyExchange to a single
parameter that specifies the length of the initial length field, since
this is the only substantive difference between the various mechanisms
as far as the ClientKeyExchange record format is concerned.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Using a cipher or digest algorithm before initialising its context is
not expected to produce any meaningful results, but is expected to be
a safe operation.
The AES context includes the number of rounds, since this varies based
on the key size. If an uninitialised context is used to perform AES
encryption or decryption, then the code may read beyond the end of the
round key arrays within the context.
This out-of-bounds read is currently reachable only via the use of an
allocated and zeroed but as yet unkeyed TLS cipher context. The
invalid number of rounds can therefore only ever be zero, which will
result in the number of intermediate rounds being calculated as -2,
which will cause an out-of-bounds read of approximately 64GB of data
(or multiple reads of the full 4GB of a 32-bit address space).
Reading this much address space will almost certainly crash the
system: either by hitting an unmapped page (if paging is enabled), or
by hitting an MMIO region. In the extremely unlikely event that the
system survives the 64GB read, the decrypted record will immediately
be rejected by TLS for failing to produce a correct authentication tag
or MAC. There is no viable way that this could be used to extract
confidential information: it could only be used as a denial-of-service
attack.
Fix by ensuring that the number of intermediate rounds is always
calculated as a safe value that cannot overflow the bounds of the
round key arrays. (The chosen form of the calculation also happens to
ensure that the number of intermediate rounds is always odd, matching
the documented requirement for this to be the case.)
Signed-off-by: Michael Brown <mcb30@ipxe.org>
For x86, GCC will assume that any inline assembly instruction clobbers
the condition code and so it is not necessary to explicitly include
"cc" within the clobber list.
For ARM (both 32-bit and 64-bit), GCC will assume that the condition
code is preserved unless explicitly clobbered. Most ARM instructions
preserve the condition code by default, and most inline assembly
blocks that modify the condition code already correctly include "cc"
in the clobber list (or as an output operand).
Review all ARM inline assembly and fix the few instances where "cc" is
required but is currently missing from the clobber list.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
For x86, GCC will assume that any inline assembly instruction clobbers
the condition code and so it is not necessary to explicitly include
"cc" within the clobber list.
For s390x, GCC will assume that the condition code is preserved unless
explicitly clobbered. It is extremely rare for GCC to emit code that
actually relies upon this behaviour, but it has been observed to
happen within a series of memcpy() calls with condition-dependent
source addresses.
Fix by adding "cc" to the clobber list on all inline assembly blocks
where the condition code is not guaranteed to be preserved.
It would be possible to use "=@cc" as an output constraint to obtain
the carry result from bigint_add() and bigint_subtract(), but the
instructions generated by GCC to extract the condition code end up
being larger than the single "alcr"/"slbr" that we currently use to
obtain the carry result.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Choose to model key transport as a key exchange algorithm that is
incapable of generating public keys and where the public key size is
zero (implying that the shared secret must be communicated via a means
other than key exchange).
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Passing the invalid length returned from a failed call to dns_copy()
in to dns_question() will cause the latter to fail safely, but via a
path that is not obviously safe at first glance.
Check the return value from dns_copy() at the point of use, to reduce
future review noise.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The calculation of the number of zero padding bits required to ensure
that relaxed Montgomery multiplication produces a result in the chosen
range is incorrect: the requirement is k=m^2 rather than k=m.
This makes no difference to the code: for both P-256 and P-384, adding
any zero padding bits will cause an extra big integer element to be
used. This extra element provides 32 (or 64) zero padding bits, which
is many more than are required to ensure that relaxed Montgomery
multiplication produces a result in the chosen range.
Fix the calculation, and update the comments to match.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The security proof for HKDF requires each HMAC hash within the
iteration to be computed over distinct input values. The 8-bit
counter values (ranging from 0x01 to 0xff) provide this formal
guarantee as long as the overall output length is no more than 255
hash blocks.
Even if the counter is allowed to wrap, output is vanishingly unlikely
to repeat since each block's input value also includes the output from
the previous block. However, this is not a formal guarantee.
RFC 5869 mentions the output length constraint only in passing and in
parentheses. HKDF is intended to be used to produce small quantities
of key material, and so no realistic consumer will ever exceed the
output length constraint (which is almost 8kB for SHA-256).
There is no point in making this a runtime check. Doing so would
require every hkdf_expand() call site to include a completely
unnecessary error handling code path, for no real benefit.
Add an assertion to indicate that we are aware of the constraint, and
to reduce future review noise.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
The MSB in the scalar multiple is implicitly clamped to zero since the
ladder-based curve point multiplication loop ignores this bit anyway.
However, the missing explicit clamp may confuse reviewers of the code.
Add the explicit clamp to reduce future review noise.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Step 3 of the x25519 modular multiplication has a marginally tighter
upper bound than is currently claimed by the comments, due to an
arithmetic error caused by the number 19 occurring too often when
writing about this field prime.
Correct the comments to minimise future confusion. There is no change
required to the code: the overall bound on the step 3 result remains
as previously stated.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Some public key exchange test vector sets provide only the expected
shared secret as an output, without specifying the expected public key
derived from the private key.
Allow key exchange tests to omit the expected public key, so that we
can use these public test vectors without needing to synthesize an
expected public key value.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Key transport, as required for the classic TLS static RSA pre-master
secret, may be modelled as a key exchange algorithm where the public
key size is zero and the shared secret is constructed unilaterally (to
then be transported via an encrypted channel).
Add a null key exchange algorithm that will fail all key exchange
operations. The algorithm may be used as a placeholder for consumers
that do not wish to risk forgetting to check for a NULL algorithm
pointer value, and the methods may be used as stubs by algorithms that
do not implement all of the possible key exchange operations (such as
key transport algorithms).
Signed-off-by: Michael Brown <mcb30@ipxe.org>