OASIS Mailing List ArchivesView the OASIS mailing list archive below
or browse/search using MarkMail.


Help: OASIS Mailing Lists Help | MarkMail Help

pkcs11 message

[Date Prev] | [Thread Prev] | [Thread Next] | [Date Next] -- [Date Index] | [Thread Index] | [List Home]

Subject: Re: [pkcs11] HKDF

On 10/30/2018 08:36 AM, Tony Cox wrote:

Hi Folks,

Is there any interest in adding HKDF (RFC5869)? If so, I'll add it to our next agenda.


OK looking into this, I think there are some questions we need to answer as a committee. This may be more complex than we thought.

First some background:


HKDF (RFC 5869) has two stages which can be executed separately or one into the other.:

  1. Extract - takes a salt and mixes it with the source key to create a new key. Salt is used. If No slot is provided a salt of zeros the length of the underlying HMAC is used.
  2. Expand - takes either the Export key or the original key and mixes it with some optional Info to create a new key of arbitrary size.

The NSS vendor specific mechanism implements 4 derive mechanism, where the underlying HMAC is part of the mechanism (SHA1, SHA256, SHA384, SHA512). They have the following struct:

typedef struct {
    CK_BOOL bExtract;
    CK_BOOL bExpand;
    CK_BYTE_PTRÂ pSalt;
    CK_ULONG ulSalt;
    CK_BYTE_PTR pInfo;
    CK_ULONG ulInfoLen;

The Salt is only used if bExtract is set to true. if No salt is provided, a salt of all zeros the length of the underlying HMAC.

pInfo is only used if bExpand is set. It can be a zero length string.

Either or both bExtract and bExpand can be set to true. At least one of them must be.

The NSS vendor specific mechanism does not create any new CKK_ key types nor does it enforce any key types as input to the hkdf.

TLS usage

TLS only ever uses HKDF in either extract or expand mode, never both in the same operation.

TLS uses HKDF expand to generate keys, IV, and key dependent secrets passed back to the application. The info used in the expand consists of the target object length, a label (with it's length), and the current handshake hashes. Each TLS usage has it's own unique label, so the actual usage could be known to the underlying PKCS #11 module.

TLS uses extract mode to create the TLS 1.3 equivalent of the master secret called 'the current secret':

  1. The current secret is generated from a previous resumptionMasterSecret and no hash. If the resumptionMasterSecret is NULL it's replaced with a fixed key of all zeros, the length of the underlying HMAC function.
  2. A new current secret key is generated from a KEA generated key plus a salt which is the result of a expand of the previous current secret key with a label of "tls13 derived".
  3. A new current secret key is generated from a zero key (like case 1) plus a salt which is the result of a expand of the previous current secret key with a label of "tls13 derived".

Issues with the NSS Vendor mechanism

1. The use of multiple mechanism for each HMAC is not really desirable. I propose we add a new CK_MECHANISM_TYPE parameter to the CK_HMAC_PARAMS which specifies the underlying HMAC.

2. The HKDF key type should be specified. Either CKK_HKDF, or CKK_XXXX_HMAC. I think the former is preferable, particularly if we collapse to a single mechanism.

3. A KeyGen mechanism should be specified. There is at least one case in NSS where we create such a key by hand by importing the output of GetRandom!

4. There are cases in tls where the output of the HKDF (in particular the expand output) is not used for keys, but things like IVs. This requires the application to do the derive and then try to export the key. In FIPS mode this does not work, tls 1.3 currently doesn't work in FIPS mode in NSS as a result. We need a way to use the HKDF to produce just data, not a new key. Tokens which implement very strict key management could use the label to determine if it should allow the raw bytes to be exported to prevent an 'attacker' from using this interface to 'extract' operating keys in the TLS connection. The details of this interface need to be decided.

5. The salt in the extract case is a particular issue. If we use the new interface postulated in 4. The issue is that means in the tls extract use case 3, the user has all the information it needs outside the token in order to generate all the additional TLS keys since the salt if effectively the only unique thing in that derive.

6. Need a way to specify the zero key in the derive (either as a keyGen mechanism, or as a CK_INVALID_HANDLE).

Now, the Questions that need to be answered

  1. Should we use CKK_HKDF or CKK_XXXX_HMAC (I think this determines whether we should collapse the HKDF derive to a single or multiple mechanism)?
  2. If we collapse, should we specify the underlying HMAC as CKM_XXX_HMAC or CKM_XXX mechanisms (that is the HMAC or the underlying hash)?
  3. How should we provide a way to use the HKDF to get data rather then a key?
    1. Add a data return field to the struct and derive a dummy key (triggered by either a flag in the struct or a separate mechanism).
    2. Use the sign interface to derive the data.
      1. If we do this do we need a separate struct and split pInfo into pLabel and pData where pData is passed as the data input in C_Sign interface.
      2. Do we want a separate mechanism.
  4. How do we handle the salt case?
    1. Provide a handle in the param struct to specify a key that holds the salt.
    2. Just use the HKDF data interface in 2 and deal with the key leaks
    3. Other?
  5. How do we handle the zero key?
    1. Add a parameter to key gen that specifies the generated key is really a zero key.
    2. Accept CK_INVALID_HANDLE in C_Derive and define that to mean use a zero key internally generated.
    3. Create a new Mechanism that specifically generates a CKK_HKDF key with zeros.

After looking at this, my current thinking is:

  2. CKM_XXXX (underlying hash, but I'm mostly agnostic here, though).
  3. B - I rather dislike the 'fake key' interface, though we do have it in the old SSL key derive case.
    1. yes - the alternative is we always pass a zero data to C_Sign, which is doable, just weird to me.
    2. yes - this changes for me if we decide not to go with a separate struct.
  4. A - I think this simple change will allow complete tls key separate for those tokens that want to implement that feature. It would also match the existing internal NSS ssl api.
  5. B - I think A could be dangerous. If someone tries to generate a key and gets the parameters wrong they would wind up with a zero key. C is a real option for me as well. B means the application doesn't have to look up the underlying HMAC key length, the token would do it.

[Date Prev] | [Thread Prev] | [Thread Next] | [Date Next] -- [Date Index] | [Thread Index] | [List Home]