[krbdev.mit.edu #8642] etype-info conflated for initial, final reply key enctype
etype-info (PA-ETYPE-INFO and its successor PA-ETYPE-INFO2) may
appear in a preauth error (PREAUTH_REQUIRED,
MORE_PREAUTH_DATA_REQUIRED, or PREAUTH_FAILED). RFC 4120 sections
188.8.131.52 and 184.108.40.206 only talk about etype-info as it pertains to
encrypted timestamp. RFC 6113 section 2.1 indicates that the client
uses etype-info to produce the initial reply key (or a set of them).
etype-info may also appear in an AS-REP. RFC 4120 only talks about
this usage as it pertains to string-to-key operations used to compute
the AS-REP enc-part decryption key. RFC 4120 restricts AS-REP etype-
info to at most one entry which must match the enc-part of the AS-
REP. RFC 6113 does not discuss this usage of etype-info. The most
reasonable interpretation of the two specs is that AS-REP etype-info
pertains the final reply key.
The initial and final reply keys differ when a preauth mech replaces
the reply key. PKINIT is one such mechanism. As PKINIT makes no use
of the initial reply key, the final reply key may have a different
enctype from the initial reply key, or there might not even be an
initial reply key if the client principal entry has no keys. Our
PKINIT server code picks the first valid enctype in the client's
request list for the final reply key.
There are several concerning behaviors here:
1. The KDC may or may not include etype-info with a PKINIT AS-REP.
If it does, it includes salt information for the client's long-term
key (chosen according to the request enctype list as filtered by the
KDC's permitted_enctypes list), but the enctype of the final reply
key. This is clearly a nonsensical combination, although the
mismatched salt information is harmless as the client will not
perform any string-to-key operation. If the client has no long-term
keys (or none which match the request and permitted_enctype list),
the KDC will send no etype-info. Sending no etype-info would
probably be the ideal behavior for a PKINIT AS-REP whether or not the
client has long-term keys, except for #3 below.
2. Each time the client reads a padata list, whether in a preauth
error or an AS-REP, it looks for etype-info and extracts an enctype,
salt, and s2kparams into the init_creds context; those values are
used those for the clpreauth get_as_key() or get_etype() callbacks.
If a hypothetical future preauth mech first needs access to the
initial reply key or its enctype when processing the AS-REP, it could
erroneously use etype-info describing the final reply key.
3. The PKINIT client code uses the get_etype() callback to determine
the enctype of the final reply key, as clpreauth modules have no
access to the enctype of the AS-REP enc-part. If the KDC sent etype-
info in the AS-REP, that ought to work, assuming the KDC conforms to
RFC 4120 in the content of that element. If the KDC sent no etype-
info in the AS-REP but did send etype-info in the PREAUTH_REQUIRED
error, get_etype() will return the enctype from the earlier etype-
info, which is for the client's long-term key and could easily be
wrong. If the KDC never sent etype-info at all (such as when the
client principal has no long-term key), get_etype() will return the
first requested enctype, which is probably correct but isn't
guaranteed to be.