On 11/28/2017 9:34 AM, Michael StJohns wrote:
On 11/28/2017 1:04 AM, Jamil Nimeh wrote:
Hi Mike, I know I said you made arguments in favor of specifying the
keys up front in init, but I'm still really uncomfortable with this.
It's been bothering me all day. Comments below:
Before I get to those:
1) Do you know of any protocol using a KDF where the key production
information is not known before you'd need to call the .init()?
I honestly don't. I think it's safe to say you probably don't need a
KDF instance until you know at least the first object you want out of
it. But for the protocols I know of all the objects are known once a
cipher suite or proposal is agreed upon.
2) If you do, couldn't you simply provide an empty or null list of key
derivation spec's to .init()?
You could, but that would end up necessitating two models of operation.
One where we give a list up front of all objects and call derive
actions with no parameters, and a second model where you specify nothing
and then provide object specs one-by-one. Each one has pros and cons,
but trying to support both models I think would make the API even more
confusing.
3) If you're doing a multiobject production from a single call to
.init() do you expect in all cases to NOT include the production data
as mixins?
In all cases? I can't honestly say that. For the protocols I know of,
the individual object attributes (like length) are not mixins. But you
later go on to say that you know of a couple protocols where they do.
If we have real-world scenarios where individual object lengths or other
attributes really affect the keystream then I guess we need to take that
into account.
My problem is that I have use cases where ALL of my key production
information is used as mixins to the key stream. Now I could provide
a List<DerivationParameterSpec> as part of the KDF init algorithm
parameter spec (kdfParams), but that means that I have to provide a
different APS for each different key schedule (consider TLS1.3s
various calls). If you take out the List<DerivationParameterSpec> out
of the .init() I'll end up having to do that and probably having to
accept null values for the deriveKey calls.
More in line.
On 11/27/2017 10:09 AM, Michael StJohns wrote:
On 11/27/2017 1:03 AM, Jamil Nimeh wrote:
HKDF and SP800-108 only deal with the creation of the key stream and
ignore the issues with assigning the key stream to cryptographic
objects. In the TLS version of HDKF, the L value is mandatory and
only a single object is assigned per init/call to the KDF. An HSM
can look at the HKDF label information and set the appropriate
policies for the assigned cryptographic object (because if any of
the label data changes, the entire key stream changes). That's not
the case for the raw HKDF nor for any KDF that allows for multiple
objects to be extracted out of a single key stream. Hence the
per-component length values.
So enforce a no-zero-length key policy in your provider code. You
probably can't affect the internals of the HSM, but you should be
able to prevent it in the provider code. I can't get away from the
feeling that this could be dealt with in other ways besides
specifying all this up-front.
The best way to understand this is to look at the PKCS11 TLS1.2 and
before KDF stuff. The key production schedule was for an encryption
key, an integrity key and two IVs, all from the same key stream. It
turns out that NOTHING the HSM could do could prevent the extraction
of key material because changing the boundaries between each object
did not change the key stream. In the TLS case (and IPSec for that
matter), it's a simple matter to move confidential key material into
non-confidential IVs. However, even if you limit the production to
only confidential items, you still have a problem in that using the
same key material for different algorithms (e.g. using part of an AES
key as a single DES key) can lead to vulnerabilities.
TLS 1.3 fixed this problem by only doing single key productions for
each call to the KDF (and by adding the length of the production to
the mixins). Because of this, an HSM can look at the mixin data and
"do the right thing" with respect to policy. If TLS1.3 had kept the
multiple object production model, they would have included the
per-object lengths in the KDF mixin data.
The HSM can do the right thing because the bits it can depend upon (in
the TLS 1.3 case the label and the length) are included in the mixin
and not simply as part of the added on key creation stuff. Without
this, there is nothing an HSM can do for enforcement because changing
these inputs wouldn't change the key stream.
Ideally, there should be a complete object spec for each object to
be generated that is part of the mixins (label and context) for any
KDF. That allows an HSM to rely upon the object spec when setting
policy controls for each generated object - and incidentally allows
for a KDF to generate both public and non-public data in a secure way.
Between different generations of keystreams do you expect to have
different sets of policy controls? The KDF API has no way for you to
set those things so I would assume those would be pretty static, or
at least controlled outside the KDF API. If so, why is the KDF API
concerning itself with how some HSM sets its policy on objects it makes?
If I call a KDF with the same key but with different key productions,
I *want* the key stream to be different. If I call it with the same
key but with same key productions, I *want* it to be the same. Say I
call the KDF to produce two objects - an AES key of length 16 bytes
and a HMAC-SHA256 key of also length 16 bytes. If I then call the
same kdf with the same key to produce two AES keys of length 16 bytes
(same overall length of the key stream, but different objects), I
would *really* like it if the second object did not have the same key
bytes as the HMAC-SHA256 key of the first call. The only way I can
ensure this is to provide mixins that cause the entire key stream to
change if anything changes in the key production data.
With the KDFs I know of I don't see how you're going to pull that off.
If you call HKDF with the same key, same salt, same info, you're going
to create the same keystream, no matter how you choose to segment it or
what kinds of objects you wish to assign them to. I guess in your
implementation of a KDF you can choose to go through the DPS objects and
mix their attributes in.
I had been working on the model that kdfParams provides the mixins
(salt, context info, iteration count, whatever the KDF needs to make a
keystream). That was based on how the KDFs I know of function. Even TLS
1.3 keys can be done via HDKF in this manner by just adding those label
and length properties to the context info field. But if you want your
implementation to draw it from the DPS, I guess you could do that. It
just seems like two providers providing the same algorithm would come to
different answers.
If the mixins include policy hints (key type, key length, label, etc)
then the HSM can rely upon those and set policy accordingly for the
objects.
I think I alluded to that up above with TLS 1.3 key derivation using
HKDF. The kdfParams APS for an HKDF-Expand operation would provide
context specific info in the form of an HkdfLabel. You'd have the
key-specific info you're talking about already as part of the mixin.
You don't need to get it from the DPS directly.
So as long as you allow for the specification of all of the
production objects as part of the .init() I'm good. A given KDF
might not require this - but I can't see any way of fixing the
current KDFs to work in HSMs without something like this.
As far as your (5) scenario goes, I can see how you can twiddle the
lengths to get the keystream output with zero-length keys and large
IV buffers. But that scenario really glosses over what should be a
big hurdle and a major access control issue that stands outside the
KDF API: That the attacker shouldn't have access to the input
keying material in the first place. Protect the input keying
material properly and their attack cannot be done.
Let me give you an example. I'm running an embedded HSM - to
protect TLS keys and to do all of the crypto. An attacker
compromises the TLS server and now has access to the HSM. No
problem - I'm going to notice if the attacker starts extraditing
large amounts of data from the server (e.g. copies of the TLS in the
clear but possibly reencrypted data stream) so this isn't a threat
or is it? Smart attacker does an extraction attack on the TLS 1.2
and before KDF and turns all of the key stream material into IV
material and exports it from the HSM. The attacker now has the much
smaller key material so he can send a few messages with those keys
and allow for the passive external interception of the traffic and
decryption thereof without the risk of detection of all that traffic
being sent. Alternately, I can place the key material in a picture
via steganography and publish it as part of the server data.
"If the attacker compromises a TLS server" is the part that gets
me...we're using external software bugs/security holes as a
justification to make the KDF API in ways that I think are less clear
to the consumer, to cover one class of providers (HSMs).
This isn't a bug in the HSM - its a bug in thinking about how KDFs
work/should work. There are three parts to a KDF - extraction of
entropy from the master secret, expansion of that entropy into a key
stream and finally, assignment of that key stream to cryptographic
objects. HKDF and SP800-108 talk about the first two, but don't
consider the implications of the third. Because of this, neither
TLS1.2 nor IPSec provide a KDF with secure key production.
When I referred to "bug" I wasn't talking about the HSM, I was referring
to the server that could be compromised, but no matter. I'm not sure
there's any KDF API out there that talks about the third class. Seems
like they're all concerned with providing the first two. I had
envisioned our KDF API providing equivalent functionality.
The idea is to protect extraction of the key material from an HSM
_*even from authorized users of that key material*_.
That may well be a goal for the HSM, to be solved by the HSM or the
provider that front-ends it. I do not see that as something to be
solved by the KDF API.
It has to be solved by the KDF API because the only way this works is
if the mixin data for all the productions is included prior to
producing the first object.
KDFs don't currently do this well. Adding the overall length and
per component length stuff as well as a per component spec to the
data used to derive the key stream means that 1) changes to any of
those change the entire key stream, 2) the per component spec data
may be used by the security module policy engine to enforce
restrictions and 3) because of (1) and (2) calling the KDF a second
time gets me exactly the same objects rather than just the same key
stream. The last isn't very important in a software based security
domain, but turns out to have real implications for policy enforcing
security modules.
But there aren't KDFs that take individual component lengths as
inputs, so alterations to individual key component lengths don't
change the keystream (unless someone decides to write a KDF that
does, but none that I've seen do). With the way the KDF API is
taking shape, there's no enforcement that you get the same objects -
none of that is locked to the instance. It can change between
inits. If you reinitialize with the same key and KDF parameters,
whether you specify all objects up front or one at a time in derive
calls you can still ask for a different set of output objects. And
changing lengths on various objects won't matter because HKDF,
Counter-mode KDF, Feedback-mode KDF...none of those care a whit about
individual component lengths. All they care about is the total
length of the keystream (and HKDF only cares about that to make sure
it's not more than 255 * Hmac length).
Yes but.
TLS1.3 will be NOT be an HKDF KDF instantiation, it will be a TLS1.3
KDF instantiation (which uses the HDKF function internally) that will
limit production to a single object per init and with a known set of
labels and using L as a mixin. Because that's how TLS13 dealt with
the problem.
AND - there are KDFs that take individual components lengths as inputs
- in at least two proprietary protocols that I know of. Mostly though,
with the trend to AEAD algorithms most of the protocols are tending to
move to a single production per init. (since they don't need both an
integrity and confidentiality key nor an IV per se)
This gets worse when you realize that the KDF key is under it all
either a HASH HMAC or CMAC key and all of those algorithms produce
public data. Ideally you need a way of preventing a KDF key from
calling the raw HASH/HMAC/CMAC functions directly (and vice versa).
I don't see how we'd prevent this in software. If I've got a key as
input to a KDF (a SecretKey) there's no way to prevent it being used
by anything else that takes a SecretKey. If you need to prevent that
in hardware then that seems like a concern for your provider or the
HSM itself.
If I tag a key as MasterSecret (where MasterSecret is not a
subinterface of SecretKey, but is of Key) and use MasterSecret instead
of Key in .init().....
The HSM (and the JVM) would both identify functions that can be used
with that key and keep others away.
This is what I was talking about with cryptographic type safety in my
last email - the idea that the Key objects be as strongly typed as
possible to prevent them from being used inappropriately or in ways
that mathematically bypass security. Take a KDF with a PRF of
CMAC-AES-128. The KDF is meant to produce secret data (a key stream
for the production of keys), but a CMAC-AES-128 is meant to produce
public data (an integrity tag over a set of data). Given that KDF
algorithm is simply a wrapper to the PRF to allow for the production
of multiple blocks of data, then its trivial - if you have access to
*use* the KDF key - to use it with the CMAC function to extract the
key stream.
In the HSM I can *somewhat* combat this by (in PKCS11) attributing the
key, but how do get those attributes on the key in the first place if
I'm using a Java front end?
In software this isn't a big thing as the confidential key material
and the public CMAC integrity tag are both in the same software
domain. But over the years we've tried to do the right thing (see
javax.security.auth.Destroyable for example) by thinking about
security past the limitations of what we can get in software.
For KDFs I'd add a jaxa.crypto.MasterSecret interface extending
Key,Destroyable (and pretty much a clone of SecretKey) a
javax.crypto.spec.MasterSecretSpec implementing KeySpec and
MasterSecret (and a clone of SecretKeySpec) to tag these secret keys
as for use only with a KDF.
Mike