Skip Menu |
 

Subject: Prevent fallback from SPAKE to encrypted timestamp
Download (untitled) / with headers
text/plain 1.3KiB
The SPAKE draft security considerations states "Client
implementations SHOULD assume that encrypted timestamp and encrypted
challenge are unlikely to succeed if SPAKE pre-authentication fails
in the second pass and no second factor was used." Otherwise, when
an incorrect password is used with SPAKE, the client unnecessarily
offers a dictionary-attackable ciphertext to the network.

The SPAKE module should set a flag when it sends a single-factor
response, probably via a new callback. The encrypted timestamp and
encrypted challenge modules should check this flag and error out.

To be determined:

* What should the callback name be?

* Should it also affect SAM-2? SAM-2 begins with a dictionary-
attackable ciphertext from the KDC, so it probably doesn't help for
us to suppress it.

* It also doesn't seem right to fall back from a two-factor SPAKE
attempt to encrypted timestamp. Falling back to single-factor SPAKE
would be strictly better (but not trivial to engineer); failing out
entirely seems maybe more appropriate. In general, if we get as far
as using credentials to send a request in one preauth mechanism,
falling back to another seems questionable; for instance, PKINIT
rejections manifesting as password requests has never been a great
user experience. So we might give thought to a more general fallback
suppression mechanism.
Download (untitled) / with headers
text/plain 2.4KiB
Some thoughts on preauth fallback in various specific scenarios:

* If the client attempts optimistic encrypted timestamp (or
challenge), and fails, trying again with the correct etype-info
(presented with PREAUTH_FAILED, or obtained with an unauthenticated
request) might succeed, although if the password was wrong, there
could be two increments on the lockout counter. The current preauth
framework resets the list of failed preauth mechanisms after
optimistic preauth fails in order to support cases like this.

* If the client attempts optimistic SPAKE and it fails, trying again
with the same user input won't help, since the initial SPAKE support
message doesn't require any guesses. So the reset behavior mentioned
above is purely detrimental when applied to client optimistic SPAKE.

* If the KDC offers PKINIT and something else (like encrypted
timestamp, or SPAKE, or both), and the client doesn't have any PKINIT
configuration, falling back to the other things is crucial, as this
could easily just be a client principal that uses PKINIT (or, less
commonly, a client principal that can do either PKINIT or password
auth, and this device doesn't have the client cert so we should do
password auth).

* On the other hand, if the client has PKINIT configuration and it's
wrong enough that no request can be generated, erroring out with a
message about the misconfiguration might be a better user experience
than trying something else. It's hard to reliably make a good
decision here as erroring out effectively locks the client out of
authenticating when it otherwise might be able to.

* If the client actually makes a PKINIT request and gets a KDC
failure, erroring out seems more likely to be useful than trying
something else like password auth, although there might be
exceptions.

* A 1FA-authenticated SPAKE request should not be followed with an
encrypted timestamp request (the point of this ticket).

* If we're going to follow up actual failed attempts at
preauthenticating (as distinct from, say, PKINIT having no client
configuration, or SPAKE failing due to group/factor negotiation) with
attempts using other mechanisms, following up 2FA SPAKE with 1FA
SPAKE or a different factor type makes just as much sense, although
our preauth framework won't currently allow it.

* If we're not going to follow up failed attempts with other
mechanisms, it might be nice to have a way to skip a preauth mech so
that we try the next one (e.g. to skip PKINIT so we can try password
auth).
From: ghudson@mit.edu
Subject: git commit
Download (untitled) / with headers
text/plain 1.5KiB

Restrict pre-authentication fallback cases

Add a new callback disable_fallback() and call it from each clpreauth
module when it generates a client message using credentials to
authenticate. (For SPAKE, this is the message responding to a
challenge; for all other current mechanisms, it is the first and only
client message.) If disable_fallback() is called, do not try another
mechanism after a KDC error.

Remove k5_reset_preauth_types_tried() and its call sites, so that
preauth mechanisms which are tried optimistically will no longer be
retried after a failure.

https://github.com/krb5/krb5/commit/7a24a088c16d326127dd2b29084d4ca085c70d10
Author: Greg Hudson <ghudson@mit.edu>
Commit: 7a24a088c16d326127dd2b29084d4ca085c70d10
Branch: master
src/include/krb5/clpreauth_plugin.h | 14 +++++
src/lib/krb5/krb/get_in_tkt.c | 21 +++-----
src/lib/krb5/krb/init_creds_ctx.h | 1 +
src/lib/krb5/krb/int-proto.h | 3 -
src/lib/krb5/krb/preauth2.c | 23 +++-----
src/lib/krb5/krb/preauth_ec.c | 1 +
src/lib/krb5/krb/preauth_encts.c | 2 +
src/lib/krb5/krb/preauth_otp.c | 4 ++
src/lib/krb5/krb/preauth_sam2.c | 1 +
src/plugins/preauth/pkinit/pkinit_clnt.c | 1 +
src/plugins/preauth/spake/spake_client.c | 4 ++
src/plugins/preauth/test/cltest.c | 11 ++++
src/tests/t_preauth.py | 88 ++++++++++++++++++++++++++----
src/tests/t_spake.py | 9 +---
14 files changed, 134 insertions(+), 49 deletions(-)