Announce the security fix together with the overflow fix, since the two bugs
are pretty much indistinguishable from a black-box perspective, despite
being due to independent problems in the code.
Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
In an X.509 certificate, a basicConstraints extension where the cA
field (BOOLEAN) is omitted but the pathLenConstraint field (INTEGER )is
present is syntactically valid, but RFC 5280 states that CAs MUST NOT emit
such a certificate.
Historically, since XySSL 0.9 in 2008, if a basicConstraints extension
started with an INTEGER field, we interpreted that field as a cA value. This
was a deliberate change:
> Fixed x509_get_ext() to accept some rare certificates (like
> www.openssl.org:443) which have an INTEGER instead of a BOOLEAN for
> Extension::BasicConstraints::cA.
However, 18 years later, this does not seem to be relevant, and the details
seem to have been lost. Furthermore, major implementations follow RFC 5280
and interpret `SEQUENCE { INTEGER n }` with cA being set to its default
value (FALSE) and pathLenConstraint set to `n`. This means that such a
certificate with n != 0 would be interpreted as a CA certificate in Mbed TLS
but as a leaf certificate elsewhere, which is dangerous.
Since CAs are not supposed to emit such certificates, stop accepting them
altogether.
Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
In test cases for pathLenConstraint parsing in a basicConstraints extension
of an X.509 certificate, use the standard type for the leading cA field,
namely BOOLEAN. The test data was encoding that field as INTEGER, which was
accepted as a deviation from the standard since XySSL 0.9.
Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
It is now unreachable because:
- end_set == end_attr_data is enforced at library/x509_csr.c:236.
- end_exts == end_set is enforced at library/x509_csr.c:248.
- x509_csr_parse_extensions() only returns success if *p == end_exts, enforced
at library/x509_csr.c:188.
So after a successful x509_csr_parse_extensions() call, *p == end_exts ==
end_set == end_attr_data. The condition at line 257 cannot be true.
Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
Don't allow parts of a compound (SEQUENCE or SET) to go beyond the
containing compound.
The inline CSR regression test is derived from the existing "X509 CSR
ASN.1 (OK)" DER test vector. In the extensionRequest attribute, the original
well-formed fragment is:
a029 3027 06092a864886f70d01090e 311a 3018 ...
where 31 1a is the SET containing the Extensions sequence and 30 18 is the
contained Extensions sequence. The malformed test changes only the SET
length byte, from 1a to 19:
a029 3027 06092a864886f70d01090e 3119 3018 ...
The attribute SEQUENCE length and the inner Extensions sequence length are
left unchanged. This makes the SET one byte too short for its containing
attribute, so the parser must reject it with
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH instead of parsing the trailing byte as
data outside the SET.
There is no known security impact, just some risk reduction.
Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
Clarify that the 'sig_algs' set through this function are only enforced
during the key exchange and that 'mbedtls_ssl_conf_cert_profile()' should
instead be used to enforce the same algorithms when verifying certificates.
Signed-off-by: Valerio Setti <vsetti@baylibre.com>
We want to reject small order points for two reasons:
- Those give rise to side channels attacks where the underlying field
arithmetic is not constant time (which our bignum isn't so far),
see the "May the Fourth" paper mentioned in ecp.
- Those force the shared secret to be all-bytes zero, which is bad for
protocols that might require contributory behaviour.
Honest peers will never send low-order points anyway.
While at it, test that we are clipping the input to 255 bits (ie, that
we are unsetting bit 256) as required by the RFC.
Again, honest peers will never send strings with bit 256 set. But the
RFC says to accept such strings anyway, so that's what we do.
Signed-off-by: Manuel Pégourié-Gonnard <manuel.pegourie-gonnard@arm.com>
When parsing the basicConstraints extension, reject junk after the SEQUENCE
inside the extension (which is probably benign), and reject a SEQUENCE that
extends beyond the extension (could be very dangerous).
Add a non-regression test where a certificate that is technically malformed,
but accepted as a leaf certificate by OpenSSL and other X.509
implementations, to be accepted as a CA certificate by Mbed TLS.
Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
The exact value doesn't matter anyway, but since we mention it, it might
as well be correct.
Signed-off-by: Manuel Pégourié-Gonnard <manuel.pegourie-gonnard@arm.com>
Those no longer allocate, so they can no longer return that error. This
was missed in the commit that removed heap allocations.
Signed-off-by: Manuel Pégourié-Gonnard <manuel.pegourie-gonnard@arm.com>
Add comments explaining why 3 passes are enough (except for 224 where 1 is enough).
For p256 and p384, this is a bit different
from some other functions as the carry is signed here.
Rm FIPS reference from the documentation, it's about the implementation.
Signed-off-by: Manuel Pégourié-Gonnard <manuel.pegourie-gonnard@arm.com>
On principle:
- If the code is written with a loop, the compiler can easily unroll the
loop at high optimisation levels; if we unroll the loop in the source,
the compiler is unlikely to roll it up at -Os/-Oz. So loops are more
adaptable.
- All the other functions are using loops, and there's nothing special
about those functions that would justify a different treatement.
Signed-off-by: Manuel Pégourié-Gonnard <manuel.pegourie-gonnard@arm.com>
The comments already explained why the result is in the desired range.
However 2^P521_WIDTH didn't make sense as P521_WIDTH is a number of
limbs no bits, so fix that typo.
Remove the FIPS reference as we're not following it and it doesn't bring
anything useful.
Signed-off-by: Manuel Pégourié-Gonnard <manuel.pegourie-gonnard@arm.com>
The test `if (X_Limbs > P255_WIDTH)` was useless: we know that X_limbs =
2 * P255_WIDTH.
The implementation already had an explicit argument why the result is
in range at the end.
Signed-off-by: Manuel Pégourié-Gonnard <manuel.pegourie-gonnard@arm.com>
The documentation used to say upon return X < N but that's wrong: if we
comment out the final conditional subtract in the test function
ecp_mod_p_generic_raw() then we have p448 cases that fail.
This was probably a typo. The actual guarantee is X < 2^448 < 2 * N.
Slightly optimize the code in the loop: we know that A1 = B0 is 1 limb,
so we don't need to memset() or memcpy() so many limbs.
Signed-off-by: Manuel Pégourié-Gonnard <manuel.pegourie-gonnard@arm.com>
The function-specific comments promised in the last line will follow.
FAST_QUASI_REDUCTION and NIST_QUASI_REDUCTION will be referenced by
specific functions. They're a single word to simplify looking them up.
Signed-off-by: Manuel Pégourié-Gonnard <manuel.pegourie-gonnard@arm.com>