Re: [TLS] confirming the room’s consensus: adopt HKDF PRF for TLS 1.3

Hugo Krawczyk <hugo@ee.technion.ac.il> Sun, 26 April 2015 20:28 UTC

Return-Path: <hugokraw@gmail.com>
X-Original-To: tls@ietfa.amsl.com
Delivered-To: tls@ietfa.amsl.com
Received: from localhost (ietfa.amsl.com [127.0.0.1]) by ietfa.amsl.com (Postfix) with ESMTP id BA2951A9006 for <tls@ietfa.amsl.com>; Sun, 26 Apr 2015 13:28:57 -0700 (PDT)
X-Virus-Scanned: amavisd-new at amsl.com
X-Spam-Flag: NO
X-Spam-Score: 0.223
X-Spam-Level:
X-Spam-Status: No, score=0.223 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, FM_FORGED_GMAIL=0.622, FREEMAIL_FROM=0.001, HTML_MESSAGE=0.001, J_CHICKENPOX_12=0.6, J_CHICKENPOX_36=0.6, MIME_8BIT_HEADER=0.3, SPF_PASS=-0.001] autolearn=no
Received: from mail.ietf.org ([4.31.198.44]) by localhost (ietfa.amsl.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id FbuGWHoGY9_X for <tls@ietfa.amsl.com>; Sun, 26 Apr 2015 13:28:54 -0700 (PDT)
Received: from mail-la0-x233.google.com (mail-la0-x233.google.com [IPv6:2a00:1450:4010:c03::233]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ietfa.amsl.com (Postfix) with ESMTPS id 0446D1A8FD5 for <tls@ietf.org>; Sun, 26 Apr 2015 13:28:54 -0700 (PDT)
Received: by lagv1 with SMTP id v1so66758404lag.3 for <tls@ietf.org>; Sun, 26 Apr 2015 13:28:52 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:sender:in-reply-to:references:from:date:message-id :subject:to:cc:content-type; bh=T2q5d2AXYgGmMmxSnAMM6mowVpVrOBpxnV2eRCSvzWs=; b=pSCcRM7tMYVoowzVi0Zbq3qxzqB4YuhMU61ithLgu4yK858biMIi3Pbl9L+0uV4DyI pb9qcsKvb369/cExKfNx9H7bTpyp9z/oMLxLNzfvfAA1XfnFgGNGJczxqY94Don2DPkv cZepD+ZVO/rO0s9ZoFGn7/7fKFncx0pdY2BfrIzmX4OGbjdM5bp+qxXiC0mIU5JWVbV1 z7Qrv41KMSq7/wOPImYN6R9B9Tw+HhAlMW4JqK+Ak5vvA/BtE7DEAv5EP9pF4AUT8L8O rJ4PFwZW0tjtIOzFl5KapfbJmWqBRq+IF2cUq5a23QPJSTb4p68BbCrcFH9R3F812+jz S+8A==
X-Received: by 10.152.28.97 with SMTP id a1mr7456870lah.9.1430080132448; Sun, 26 Apr 2015 13:28:52 -0700 (PDT)
MIME-Version: 1.0
Sender: hugokraw@gmail.com
Received: by 10.25.78.66 with HTTP; Sun, 26 Apr 2015 13:28:21 -0700 (PDT)
In-Reply-To: <553B2D59.3030407@brainhub.org>
References: <4A5C6D8F-6A28-4374-AF1F-3B202738FB1D@ieca.com> <551DDD4E.5070509@nthpermutation.com> <F7F3EB83-FEA2-477C-8810-38C49B71C977@ieca.com> <551E290D.7020207@nthpermutation.com> <55381768.8010402@nthpermutation.com> <CACsn0cm5A50dP4JDKq9R0XdB83hyzPPLQHAMnUcXFb+DCSwV7g@mail.gmail.com> <55392B08.6020304@nthpermutation.com> <CADi0yUPTixoesXkgd=HYe_+ua_+=_UfcDBSndCgdh1usTzNpzQ@mail.gmail.com> <20150425053458.GA28576@LK-Perkele-VII> <553B2D59.3030407@brainhub.org>
From: Hugo Krawczyk <hugo@ee.technion.ac.il>
Date: Sun, 26 Apr 2015 16:28:21 -0400
X-Google-Sender-Auth: uOWxSfuI8dGKD8A_UFnk0VQbGpo
Message-ID: <CADi0yUMMQpHhxhhdkc=JWhN5a2H_PTQj7e5aPzYVJjSKVpFXeg@mail.gmail.com>
To: Andrey Jivsov <crypto@brainhub.org>, Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Content-Type: multipart/alternative; boundary="089e0160b7d44b87dc0514a67aa4"
Archived-At: <http://mailarchive.ietf.org/arch/msg/tls/KpPECwQsb0nJMRislGQik3-0JL8>
Cc: "tls@ietf.org" <tls@ietf.org>
Subject: Re: [TLS] confirming the room’s consensus: adopt HKDF PRF for TLS 1.3
X-BeenThere: tls@ietf.org
X-Mailman-Version: 2.1.15
Precedence: list
List-Id: "This is the mailing list for the Transport Layer Security working group of the IETF." <tls.ietf.org>
List-Unsubscribe: <https://www.ietf.org/mailman/options/tls>, <mailto:tls-request@ietf.org?subject=unsubscribe>
List-Archive: <http://www.ietf.org/mail-archive/web/tls/>
List-Post: <mailto:tls@ietf.org>
List-Help: <mailto:tls-request@ietf.org?subject=help>
List-Subscribe: <https://www.ietf.org/mailman/listinfo/tls>, <mailto:tls-request@ietf.org?subject=subscribe>
X-List-Received-Date: Sun, 26 Apr 2015 20:28:57 -0000

Indeed, HKDF-extract(0, g^xy) is equivalent to ​Hash( opad || Hash( ipad ||
g^xy ) )
but that is only for computing an intermediate key which is then used to
key HKDF-expand for actual key derivation where the input to this
derivation includes the 'info' field (label + digest of handshake messages).

You are right that in the case of Master Secret, the key derivation in TLS
1.2 is more complicated-looking (actually, it is very similar to deriving
Master Secret using full HKDF instead of HKDF_Extract only) but just being
complicated-looking is not a guarantee of additional security (*). A well
structured uniform scheme as HKDF that serves multiple purposes in a single
design is much cleaner and amenable to analysis. Security by obscurity (or
by "complicatity") is never a good idea. And the multi-purpose properties
of HKDF are not just academic advantages, but  a property of HKDF that
serves TLS 1.3 very well, for example to strengthen the application keys by
making them depend on both long-term and ephemeral keying material.

Hugo

(*) Just for fun, if you compare Hash( opad || Hash( ipad || g^xy ) ) to
your preferred
​ ​
Hash(g^xy ^ opad || Hash( (g^xy ^ ipad)
​ ) you can note that if g^xy is longer than the hash block, your security
gets limited to that block length while in the former this is not
necessarily the case. I am not suggesting that this is a practical
advantage of the former, just giving it as an example of why complicating
things do not necessarily help and many times can actually hurt. The more
structural issue here is not to use a non-uniform key, as  g^xy may be, as
a HMAC key directly.​


On Sat, Apr 25, 2015 at 1:59 AM, Andrey Jivsov <crypto@brainhub.org> wrote:

> On 04/24/2015 10:34 PM, Ilari Liusvaara wrote:
>
>> On Fri, Apr 24, 2015 at 05:31:51PM -0400, Hugo Krawczyk wrote:
>>
>>> Here are a few clarifications regarding HKDF and its use in TLS 1.3 in
>>> response
>>> to recent emails (including those under the "HSM-friendly Key
>>> Computation"
>>> thread). I will not touch on anything specific to HSM or PKCS11 since I
>>> know
>>> little about these and the recent exchange on these issues has not
>>> helped me
>>> understanding these things any better (but rather confuse me more).
>>>
>>
>> Actually, for me, that HSM thread actually clarified what the actual
>> requirements
>> are (which lets one minimize distruption).
>>
>>  Let me start with the issue of whether we should be using the
>>> HKDF-Extract and
>>> HKDF-Expand separately or only use HKDF as a single function (which
>>> internally
>>> operates HKDF-Extract and HKDF-Expand). There is an obvious advantage
>>> for the
>>> latter approach (single function) as it deals with HKDF as a black box.
>>> But there are also advantages to calling these two components
>>> separately, and
>>> TLS 1.3 provides some good examples for that. First, HKDF is built to
>>> output as
>>> many keys as needed from a single HKDF operation, but in TLS we are
>>> deriving
>>> multiple keys from the same keying material through separate
>>> applications of the
>>> expand part. In such a case it is more natural to apply extract once and
>>> apply
>>> expand several times (with different info fields!). For example, Master
>>> Secret
>>> is derived using a single Extract operation but it is then used in three
>>> different Expand operations for deriving other keys (application traffic
>>> keys,
>>> export master secret, and resumption master secret). Second, when one
>>> starts with
>>> a strong key then the Extract step can be skipped making it convenient
>>> to be
>>> able to call Expand directly. Third, it is convenient to call Expand
>>> directly as
>>> a PRF for computing the Finished message. Lastly, and not least, it
>>> makes the
>>> key derivation logic more explicit which helps conveying the rationale
>>> of each
>>> operation and helps those analyzing the protocol (now and in the future).
>>>
>>
>> Some models derive even more things out of (handshake) MS, e.g. one model
>> does:
>> - s2c_appMS.
>> - eMS
>> - Unique
>> - c2s_appMS.
>> - rPMS
>>
>>  My recommendation is to keep the Extract and Expand separation for the
>>> moment,
>>> in particular due to the last point, so we can see more clearly the
>>> logic while
>>> still setting the missing details of the protocol. When the whole
>>> picture is
>>> clear we can revisit this point.
>>>
>>> On other issues:
>>>
>>> - This should be obvious but worth repeating: All calls to HKDF-Expand
>>> MUST use
>>>    a non-empty info field binding the derived key(s) to a unique context
>>> (in the
>>>    case of TLS this is usually a label and a cumulative session-hash).
>>>
>>> - It was suggested that the length of derived keys should be part of the
>>> input
>>>    to key expansion. If desired, this length can be entered through the
>>> info
>>>    field of HKDF but I would be very careful not to derive two different
>>> keys
>>>    where the only difference in the 'info' values is the key length. If
>>> the two
>>>    keys happen to be of the same length one would end up with two keys
>>> that are
>>>    identical.
>>>
>>
>> Well, there would still be string input of what the key is (otherwise
>> e.g. rPMS
>> and eMS might up ending being the same, which isn't desirable).
>>
>>  - One of the emails raises the issue of using random salt, as
>>> recommended by RFC
>>>    5869. Note that the RFC recommendation also indicates that the salt
>>> value
>>>    should be something that is authenticated during the protocol, or
>>> otherwise it
>>>    can be selected by the adversary. This authentication needs to happen
>>>    independently of the key being derived using this salt. For example,
>>> one
>>>    should be careful not to incur in a circular logic, e.g. deriving a
>>> key
>>>    mackey=HKDF(salt, info) and then using mackey to authenticate the
>>> salt by
>>>    computing MAC(mackey, salt). This is why the proposed TLS 1.3 key
>>> derivation
>>>    scheme does not use nonces as salt.
>>>
>>
>> With fixed salts, the HKDF extract function is essentially H1(H2(x)),
>> where
>> H1 and H2 are H, but with different (pseudorandom) IVs.
>>
>
> Ilari beat me on this, but I also made this observation. In more details:
>
> According to intended use of HKDF, HKDF-Extract is this:
>
>    HMS = HKDF-Extract( salt=0, IKM=g^xy )
>
> Which is:
>
>    A. HMAC( 0, g^xy ) = Hash( opad || Hash( ipad || g^xy ) ).
>
> The two invocations of the Hash() begin with hashing fixed values, so one
> can re-write the A as
>
>    A1: Hash1( Hash2( g^xy ) ),
>
> which can be rewritten as
>
>    A2: Hash3( g^xy ) =
> ​​
> Hash( opad || Hash( ipad || g^xy ) )
>
> Therefore, HKDF-Extract( 0, g^xy ) should be viewed as deterministic hash
> of g^xy and that's the only contribution of g^xy in HKDF.
>
> For comparison, TLS 1.2 does the following in the first step:
>
>    B.
> ​​
> Hash(g^xy ^ opad || Hash( (g^xy ^ ipad) || "master secret" +
> ClientHello.random + ServerHello.random) ) );
>
> It would be amusing to see a case when A2 is secure, while B is not.
>
>
>> Also, handshake hashes are very hard to control to any significant degree
>> (or
>> invoking HKDF with bad salt is the least of your worries).
>>
>> E.g. Suppose prf-hash is 256-bit MD5-equivalent-security. The handshake
>> security just breaks catastrophically against active attacks (passive
>> attacks
>> are another matter).
>>
>>  - Another issue raised in recent email exchange is the way to merge the
>>>    semi-static value g^xs (where s is the semi-static server's private
>>> key and x
>>>    the ephemeral client's private key) with the ephemeral value g^xy.
>>>
>>
>> "the semi-static server's private key"??? There is no "the key". There's
>> the old
>> semi-static key (which may not be available), and the new semi-static
>> key. And
>> the two may or may not be the same key, and those keys may not even be
>> available.
>>
>> Also, in certain conditions, not mixing in DH result with the old key
>> actually
>> leads to an attack (mixing the new one does not help here).
>>
>> Also, I heard some implementers complaining about mixing the new one, and
>> after
>> calculating the time penalty, I can easily understand (it is pretty
>> sizable).
>>
>>     This is done by first extracting a key from g^xs as
>>> PRK1=HKDF-extract(0,g^xs)
>>>    and then extracting PRK2=HKDF-extract(PRK1,g^xy).
>>>    Here is the logic: PRK1 is extracted from g^xs using HKDF(0,...) as a
>>> random
>>>    oracle as needed in the proof of security. Then PRK2 is derived with
>>> salt=PRK2
>>>    for the following reason. If g^xs is not exposed (the typical case)
>>> then this
>>>    HKDF use only requires treating HKDF(PRK1,...) as a PRF (essentially
>>> the less
>>>    demanding property from HKDF).  If g^xs is revealed by compromise of
>>> the
>>>    server's semi static private key s (after the conclusion of the
>>> handshake, as
>>>    in the forward-secrecy setting), then PRK1 is actually an
>>> authenticated random
>>>    and non-secret salt so you use HKDF as a randomness extractor.
>>>    In other words, each use of HKDF uses the minimal cryptographic
>>> assumption one
>>>    can have depending on the context of derivation.
>>>
>>
>> If it is the new one, it is not properly authenticated (have I mentioned
>> how nasty
>> even capturing the proper assumptions is?).
>>
>>  - Finally, there has been a long discussion related to the derivation of
>>> both
>>>    secret and non-secret material (the latter for IVs). I can't say how
>>> this
>>>    works with HSMs, PKCS11 or other standards, but from the
>>> cryptographic point
>>>    of view doing this "mixed" derivation of secret and non-secret values
>>> is
>>>    not a  problem as long as HMAC is not broken as a PRF.
>>>
>>
>> Well, looks like that problem got sorted out (by getting the "HSM folks"
>> to
>> actually state the actual requirements).
>>
>>
>> -Ilari
>>
>> _______________________________________________
>> TLS mailing list
>> TLS@ietf.org
>> https://www.ietf.org/mailman/listinfo/tls
>>
>>
> _______________________________________________
> TLS mailing list
> TLS@ietf.org
> https://www.ietf.org/mailman/listinfo/tls
>