Conversation
randombit
left a comment
There was a problem hiding this comment.
LGTM. Still a few CI failures which I assume are missing cases but once CI is green good to merge
|
The assertion in the coverage build job seems like a bug, actually. There are a few BoGo tests that send a prefix string to the TLS server under test. E.g. BoGo test botan/src/lib/tls/tls12/tls_record.cpp Lines 361 to 368 in 1522871 The TLS channel then catches this exception and proceeds to sending a TLS alert in response. botan/src/lib/tls/tls12/tls_channel_impl_12.cpp Lines 573 to 577 in 1522871 But now, the botan/src/lib/tls/tls12/tls_channel_impl_12.cpp Lines 548 to 552 in 1522871 I see two possible fixes:
But is it actually legal for a TLS server to send a TLS alert as their first flight? |
7787d67 to
9c70d9d
Compare
At least for Botan's (D)TLS 1.2 implementation it doesn't seem to be legal for the TLS server to send messages before it successfully received a Client Hello. Only after that do we know whether we speak TLS or DTLS. Hence, let's just not send TLS alerts in the very early error case described above: 9c70d9d |
|
|
||
| DSA_PublicKey::DSA_PublicKey(const AlgorithmIdentifier& alg_id, | ||
| const std::vector<uint8_t>& key_bits) : | ||
| DL_Scheme_PublicKey(alg_id, key_bits, DL_Group_Format::ANSI_X9_57) | ||
| { | ||
| BOTAN_ARG_CHECK(group_q().bytes() > 0, "Q parameter must be set for DSA"); | ||
| } | ||
|
|
||
|
|
||
| DSA_PublicKey::DSA_PublicKey(const DL_Group& grp, const BigInt& y1) | ||
| { | ||
| m_group = grp; | ||
| m_y = y1; | ||
|
|
||
| BOTAN_ARG_CHECK(grp.q_bytes() > 0, "Q parameter must be set for DSA"); | ||
| } |
There was a problem hiding this comment.
That is suppose to fix asserts in PK_Verifier for a DSA public key in the cert corpus/fuzzer. I left the assert untouched and instead introduce sanity checks at construction time of the DSA public key.
@randombit I could use a little help with this, as I'm not sure whether other things should also be validated here.
By the way: The currently still failing assert in the pkcs8 fuzzer is related to a DSA private key:
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGABRT
* frame #0: 0x00007ff81db8e00e libsystem_kernel.dylib`__pthread_kill + 10
frame #1: 0x00007ff81dbc41ff libsystem_pthread.dylib`pthread_kill + 263
frame #2: 0x00007ff81db0fd24 libsystem_c.dylib`abort + 123
frame #3: 0x00000001009a9778 pkcs8`Botan::assertion_failure(char const*, char const*, char const*, char const*, int) + 696
frame #4: 0x000000010048ed39 pkcs8`Botan::Montgomery_Exponentation_State::exponentiation(Botan::BigInt const&, unsigned long) const + 1001
frame #5: 0x000000010048fc46 pkcs8`Botan::monty_execute(Botan::Montgomery_Exponentation_State const&, Botan::BigInt const&, unsigned long) + 22
frame #6: 0x0000000100651218 pkcs8`Botan::DL_Group_Data::power_g_p(Botan::BigInt const&, unsigned long) const + 72
frame #7: 0x000000010065127b pkcs8`Botan::DL_Group::power_g_p(Botan::BigInt const&, unsigned long) const + 59
frame #8: 0x0000000100660e4f pkcs8`Botan::DSA_PrivateKey::DSA_PrivateKey(Botan::AlgorithmIdentifier const&, std::__1::vector<unsigned char, Botan::secure_allocator<unsigned char> > const&) + 767
frame #9: 0x000000010080913c pkcs8`std::__1::__unique_if<Botan::DSA_PrivateKey>::__unique_single std::__1::make_unique<Botan::DSA_PrivateKey, Botan::AlgorithmIdentifier const&, std::__1::vector<unsigned char, Botan::secure_allocator<unsigned char> > const&>(Botan::AlgorithmIdentifier const&, std::__1::vector<unsigned char, Botan::secure_allocator<unsigned char> > const&) + 76
frame #10: 0x000000010080851b pkcs8`Botan::load_private_key(Botan::AlgorithmIdentifier const&, std::__1::vector<unsigned char, Botan::secure_allocator<unsigned char> > const&) + 1003
frame #11: 0x000000010083fe17 pkcs8`Botan::PKCS8::(anonymous namespace)::load_key(Botan::DataSource&, std::__1::function<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > ()> const&, bool) + 471
frame #12: 0x0000000100840587 pkcs8`Botan::PKCS8::load_key(Botan::DataSource&) + 231
frame #13: 0x0000000100002c8f pkcs8`fuzz(unsigned char const*, unsigned long) + 255
frame #14: 0x0000000100002b8a pkcs8`LLVMFuzzerTestOneInput + 26
frame #15: 0x0000000100003483 pkcs8`(anonymous namespace)::fuzz_files(char**) + 899
frame #16: 0x0000000100002eb7 pkcs8`main + 231
frame #17: 0x0000000101df551e dyld`start + 462
There was a problem hiding this comment.
I think this assert would trigger if you load a DSA key with a secret key that is greater than the group order.
This likely affects other key types as well.
I think we need to rethink key validation somewhat. Right now all validation is dumped on check_key, because some of the checks (testing primality and ECC point validity) are expensive. But most are simple range checks and could be cheaply done during construction or deserialization.
This is resolved with 1735f95 right?
Codecov Report
@@ Coverage Diff @@
## master #2980 +/- ##
==========================================
- Coverage 92.58% 92.52% -0.07%
==========================================
Files 596 577 -19
Lines 69779 66792 -2987
Branches 6617 6400 -217
==========================================
- Hits 64608 61801 -2807
+ Misses 5138 4958 -180
Partials 33 33
Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here. |
src/lib/pubkey/dsa/dsa.cpp
Outdated
| const secure_vector<uint8_t>& key_bits) : | ||
| DL_Scheme_PrivateKey(alg_id, key_bits, DL_Group_Format::ANSI_X9_57) | ||
| { | ||
| BOTAN_ARG_CHECK(m_x.bits() <= m_group.q_bits(), "x must not be larger than q"); |
There was a problem hiding this comment.
I have a hunch that this check should better be constant time, because:
botan/src/lib/math/numbertheory/monty_exp.cpp
Lines 102 to 105 in 1522871
... some guidance on how to do that would be appreciated.
There was a problem hiding this comment.
I think this is safe enough to not be constant time in this context. bits itself is constant time, and if we reject that means the key itself is just manifest invalid. So there is no real info leak.
We should check x <= q though rather than just the bit size, since x == q would be accepted, but isn't a valid DSA key.
randombit
left a comment
There was a problem hiding this comment.
LGTM, modulo changing DSA key check to use value instead of bit length.
1735f95 to
efcc70b
Compare
| DL_Scheme_PrivateKey(alg_id, key_bits, DL_Group_Format::ANSI_X9_57) | ||
| { | ||
| BOTAN_ARG_CHECK(m_x > 0, "x must be greater than zero"); | ||
| BOTAN_ARG_CHECK(m_x < m_group.get_q(), "x must not be larger than q"); |
There was a problem hiding this comment.
I added a check that x > 0 because the failing fuzzer test (pkcs8) caused negative numbers to be passed into this constructor.
On that note: I feel that DL_Group should also validate that it is always instantiated with positive numbers, no?
There was a problem hiding this comment.
On that note: I feel that DL_Group should also validate that it is always instantiated with positive numbers, no?
It should. I think if p or q is zero or negative that will cause Modular_Reducer to throw an exception. I don't think g would be caught. Also we are not checking other invariants like g < p
There was a problem hiding this comment.
Nevertheless, I propose this is something for a follow-up PR. I wanted to keep this to the minimum to just start enforcing assertions in the first place.
We cannot send alerts over a connection that fails even before a readable Client Hello was received. In that case we cannot determine whether the client speaks TLS or DTLS, hence, we cannot generate a valid TLS alert record.
efcc70b to
5f8bca9
Compare
|
I rebased to master to let the CI run once again after this was stale for more than a month. Once that comes back clean, I'll merge. |
As discussed, this adds
./configure.py --terminate-on-assertscausing the library tostd::abortwhen an assertion is not met.The code base seems to use
BOTAN_ASSERT*in some places whereBOTAN_ARG_CHECKorBOTAN_STATE_CHECKwould be more appropriate. Hence, I enabled the new option for the coverage CI run in the hope to catch most of them.