On 11/29/2017 8:38 AM, Jamil Nimeh wrote:


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.

I'm tempted to say that this case (where you don't know what the productions will be before the init) doesn't exist.   This degenerate case is simply a keyed PRNG and could probably be handled by deriveBytes(int length).

If you really want to produce keys from a keyed PRNG where the key objects are not a mixin then support both deriveKey() and deriveKey(params), but have the second throw a RuntimeException if you call it with a KDF initialized with a set of production params.



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.

See my other email.  This only works if the context field is formatted in a way that the KDF can parse it.  If the context field is opaque - none of this works.

Let me give you an example case:

SP800-108 counter based KDF with L of 32 bits (equal to 32 or 0x20) and counter of 32 bits.  Label is [BE EF CA FE].  Context is [01 03 10 00 00 10].

I'm producing a  AES Key  and an IV.   Does the calling sequence give the provider any information about how many keys and IVs are being produced or how much key stream to assign to each?

How about - Same underlying KDF, but the context is {{key (01), aes (03), 16 bytes}, {iv (0), generic (0), 16 bytes} which the provider reads and translates into [01 03 10 00 00 10] and calculates L from the sums of the lengths.  The same key stream is produced in both of these cases, but in the second case the key production has enforceable policy because the calling sequence provides non-opaque information.



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.

HKDF-Expand-Label (the TLS1.3 KDF) actually does mostly the right thing.  The length and type (e.g. "iv" "key" "traffic upd" etc) are part of the mixins for each key assignment.  A policy aware provider can enforce appropriateness on the assignment of that key stream to an appropriate object.  It's not as clean (or as general) as I would like, but it's a vast improvement on TLS1.2 and before.

I hope to get IPSec KDFs fixed at some point as well.

Later, Mike


Reply via email to