Subject: comments on ikev2 05 (editorial)

From: Hugo Krawczyk <[email-masked]>
Date: Tue, 4 Mar 2003 01:44:42 +0200 (IST)

Here is a list of (mostly) editorial changes to ikev2-05 that I suggest 
for the next revision of the document. 
It includes several of the more significant editorial comments on version 04 
included in a message from Jan 23rd (message under the subject: "some comments 
on ikev2 04") and not reflected in 05.
Comments are numbered and text from the current draft is marked with >>>. 

(1) Section 1.2:

In section "1.2 The Initial Exchange" the role of keys SKa and SKe is explained.
In contrast there is no reference to SK_d which appears without earlier explanation 
in section 1.3. I suggest to explicitly mention and explain the value SK_d at 
the end of 1.2. Something like:
"In addition to the keys SKe and SKa derived from the DH value for protection of the
initial exchange, also a key SKd is derived and used for derivation of further keying
material (for CHILD-SAs)." 
I also suggest to add an explicit pointer in section 1.2 to section 2.15 where the
field AUTH is specified.

(2) Section 2.2, page 13: the text says:

>>>   can be very different. There is no ambiguity in the messages,
>>>   however, because each the (I)nitiator and (R)eply bits in the message

I guess that (R)eply should be replaced with (R)esponder.

(3) Section 2.6, page 18: typo

>>>   An IKE implementation SHOULD implement its responder cookie
>>>   generation is such a way as to not require any saved state to

is->in

(4) In same page you define Cookie as:

>>>      Cookie = <SecretVersionNumber> | Hash(IPi | SPIi | <secret>)

I suggested to add Ni inside the Hash. This has no extra cost and improves protection
against DoS. Specifically, with this addition an attacker that
sees message 2 sent from R to I but did not see the corresponding message
1 from I to R cannot use this cookie since it does not know Ni. With
your specification, the attacker can use this cookie in a DoS attack by
forging I's source IP address (IPi) in its response (i.e. posing as I in
message 3) without need to see (or generate) the original first message from I.

>>>   where <secret> is a randomly generated secret known only to the
>>>   responder and periodically changed. <SecretVersionNumber> should be
>>>   changed whenever <secret> is regenerated.  The cookie can be
>>>   recomputed when the IKE_SA_INIT arrives the second time and compared
>>>   to the cookie in the received message. If it matches, the responder
>>>   knows that SPIr was generated since the last change to <secret> and
>>>   that IPi must be the same as the source address it saw the first
>>>   time. Incorporating SPIi into the calculation assures that if
>>>   multiple IKE-SAs are being set up in parallel they will all get
>>>   different cookies (assuming the initiator chooses unique SPIi's).
>>>
>>>   If a new value for <secret> is chosen while there are connections in
>>>   the process of being initialized, an IKE_SA_INIT might be returned
>>>
>>>
>>>IKEv2                                                          [Page 18]
>>>
>>>
>>>INTERNET DRAFT                                             February 2003
>>>
>>>
>>>   with other than the current <SecretVersionNumber>.  The responder in
>>>   that case MAY reject the message by sending another response with a
>>>   new cookie or it MAY keep the old value of <secret> around for a
>>>   short time and accept cookies computed from either one.  The
>>>   responder SHOULD NOT accept cookies indefinitely after <secret> is
>>>   changed, since that would defeat part of the denial of service
>>>   protection.

(5) Add:
"This means that the responder should change the value <secret> frequently, 
especially if under attack"
Another option is to include a counter (or timestamp) under 
Hash and accept only cookies with the counter value in certain window.

(6) Section 2.10 Page 22:

>>>2.10 Nonces
>>>
>>>   The IKE_SA_INIT messages each contain a nonce. These nonces are used
>>>   as inputs to cryptographic functions.  The CREATE_CHILD_SA request
>>>   and the CREATE_CHILD_SA response also contain nonces. These nonces
>>>   are used to add freshness to the key derivation technique used to
>>>   obtain keys for CHILD-SAs. Nonces used in IKEv2 MUST therefore be
>>>   randomly chosen and of size at least equal to the key size of the
>>>   strongest cryptographic algorithm used.

This may be confusing. For example, the strongest key may be 2048 bits. 
The point is not in matching size but strength. 
Moreover, in no case it makes sense to use nonces longer than 128 bits. 
Actually 64 bits are usually sufficient (assuming you do not use the same 
SK_d value in more than 2^30 SA-CHILD's).

(7) Section 2.13 Page 24:

>>>   In the context of the IKE-SA, three cryptographic algorithms are
>>>   negotiated: an encryption algorithm, a Diffie-Hellman group, and a
>>>   pseudo-random function (prf). The pseudo-random function is used both
>>>   for integrity protection of the IKE payloads and for the construction
>>>   of keying material for all of the cryptographic algorithms used in
>>>   both the IKE-SA and the CHILD-SAs.

In the suites there are two different algorithms negotiated: prf and integrity 
protection. You should clarify Which one is used for the integrity protection 
in SK{}. I am not sure what's the intention in the current text.

>>>   We assume that each cryptographic algorithm accepts a fixed size key,
>>>   and that any randomly chosen value of that fixed size can serve as an
>>>   appropriate key. For functions that accept a variable length key, a
>>>   fixed key size MUST be specified as part of the cryptographic suite
>>>   negotiated.  For prf functions based on HMAC, the fixed key size is
>>>   the size of the output of the HMAC.

(8) change last line to:
   "the length of the output of the underlying hash function."
(That is more precise than the "output of the HMAC" which 
may actually be different than the length of the hash output.)

(9) Section 2.14 page 25:

>>>   subsequent exchanges.  SKEYSEED and its derivatives are computed as
>>>   follows:
>>>
>>>       SKEYSEED = prf(Ni | Nr, g^ir)

What happens if Ni|Nr is longer than the prf key? You should specify that the
values concatenated above are Ni and Nr each truncated (if necessary) to half the 
length of the prf key. (This is particularly relevant to prf's based on block 
ciphers, e.g. AES-CBC-MAC.)

>>>       {SK_d, SK_ai, SK_ar, SK_ei, SK_er}
>>>                 = prf+ (SKEYSEED, g^ir | Ni | Nr | SPIi | SPIr )

delete g^ir from this computation (and the text referring to g^ir below)
Also note that there is no real need to put Ni|Nr here since they were already used
in the derivation of SKEYSEED. That is, you can leave SPIi|SPIr as the only input to 
prf+.

>>>   (indicating that the quantities SK_d, SK_ai, SK_ar, SK_ei, and SK_er
>>>   are taken in order from the generated bits of the prf+).  g^ir is the
>>>   shared secret from the ephemeral Diffie-Hellman exchange.  g^ir is
>>>   represented as a string of octets in big endian order padded with
>>>   zeros if necessary to make it the length of the modulus. Ni and Nr
>>>   are the nonces, stripped of any headers.
>>>
>>>   The two directions of flow use different keys. The keys used to
>>>   protect messages from the original initiator are SK_ai and SK_ei. The
>>>   keys used to protect messages in the other direction are SK_ar and
>>>   SK_er. Each algorithm takes a fixed number of bits of keying
>>>   material, which is specified as part of the algorithm.  For integrity
>>>   algorithms based on HMAC, the key size is always equal to the length
>>>   of the underlying hash function.

change last line to:
"of the output of the underlying hash function."

(10)  Section 2.15

>>>2.15 Authentication of the IKE-SA
>>>
>>>   When not using extended authentication (see section 2.16), the peers
>>>   are authenticated by having each sign (or MAC using a shared secret
>>>   as the key) a block of data. For the responder, the octets to be
>>>   signed start with the first octet of the first SPI in the header of
>>>   the second message and end with the last octet of the last payload in
>>>   the second message.  Appended to this (for purposes of computing the
>>>   signature) is the initiator's nonce Ni (just the value, not the
>>>   payload containing it) and the contents of the responder's ID payload

change "the contents of the responder's ID payload" to
"the value prf(SK_ar,IDr') where IDr' represents the responder's ID payload
(excluding fixed header)."

>>>   (excluding fixed header).  Similarly, the initiator signs the first
>>>   message, starting with the first octet of the first SPI in the header
>>>   and ending with the last octet of the last payload. Appended to this
>>>   (for purposes of computing the signature) is the responder's nonce Nr
>>>   and the initiator's ID payload (excluding fixed header).  It is
>>>

Same change as above

(11) Then in the same section you specify:

>>>   In the case of a pre-shared key, the AUTH value is computed as:
>>>
>>>      AUTH = prf(Shared Secret | "Key Pad for IKEv2", <message bytes>)
>>>
>>>   where the string "Key Pad for IKEv2" is ASCII encoded and not null
>>>   terminated. The shared secret can be variable length. The pad string
>>>   is added so that if the shared secret is derived from a password,
>>>   this exchange will not compromise use of the same password in other
>>>   protocols.  As noted above, deriving the shared secret from a
>>>   password is not secure.  This construction is used because it is
>>>   anticipated that people will do it anyway.
>>>

As I noted in a previous message this pad does not give anything.
It does not hurt either except for giving a false feeling of security.
If I am confused and you have an argument why this pad helps please explain to me.
The only way this can help against another protocol it that protocol uses the same prf
with the same <message bytes>.
And, again, if you still want to add the pad, it should be concatenated to the input not
to the keyL that is

      AUTH = prf(Shared Secret, "Key Pad for IKEv2" | <message bytes>)

(12) In page 28, sec 2.17:

>>>   For CREATE_CHILD_SA exchanges with PFS the keying material is defined
>>>   as:
>>>
>>>      KEYMAT = prf+(SK_d, g^ir (ph2) | Ni | Nr )
>>>

delete g^ir from this computation (and the text referring to g^ir below)

>>>
>>>   where g^ir (ph2) is the shared secret from the ephemeral Diffie-
>>>   Hellman exchange of this CREATE_CHILD_SA exchange (represented as an
>>>   octet string in big endian order padded with zeros if necessary to
>>>   make it the length of the modulus),
>>>
>>>   A single CHILD-SA negotiation may result in multiple security
>>>   associations. ESP and AH SAs exist in pairs (one in each direction),
>>>   and four SAs could be created in a single CHILD-SA negotiation if a
>>>   combination of ESP and AH is being negotiated.  KEYMAT is generated
>>>   as described in section 2.13.
>>>

(13) erase last sentence, seems to be a left over from previous text.

(14) Section 2.18 page 29

>>>
>>>
>>>   IKE-SA as follows:
>>>
>>>       SKEYSEED = prf(SK_d (old), [g^ir (ph2)] | Ni | Nr)
>>>
>>>   where g^ir (ph2) is the shared secret from the ephemeral Diffie-
>>>   Hellman exchange of this CREATE_CHILD_SA exchange (represented as an
>>>   octet string in big endian order padded with zeros if necessary to
>>>   make it the length of the modulus) and Ni and Nr are the two nonces
>>>   stripped of any headers.

Here g^ir is ok!
Also, I'd suggest that since "ph2" stands for "phase 2" a term not used in ikev2 may be
you should change ph2 to "(new)". 

(15) Page 38: Section 3.1

>>>      o  Message ID (4 octets) - Message identifier used to control
>>>         retransmission of lost packets and matching of requests and
>>>         responses. See section 2.2.

It is important to say (here and even better in section 1.3) that the 
Message ID has an essential security role, namely, avoiding replay attacks 
in CHILD-SA establishment.

(16) In sec 5 (security considerations) page 71:

>>>
>>>   themselves.  There is nothing in IKE which prohibits using stronger
>>>   groups nor is there anything which will dilute the strength obtained
>>>   from stronger groups. In fact, the extensible framework of IKE

This is inaccurate. The key derivation (via its prf) and the actual algorithms
negotiated for ipsec may dilute this strength if they are weaker than the strength of
the DH groups (note that it may make sense to use stronger DH groups than prf or
other crypto algorithms if one suspects that cryptanalysis of DH may advance faster than
cryptanalysis of these other algorithms, e.g. in the case of EC groups).
This is the case if you include g^ir only for deriving SKEYSEED (as I suggest) and
also if g^ir is included in the derivation under prf+ as done in version 05.

>>>   encourages the definition of more groups; use of elliptical curve
>>>   groups may greatly increase strength using much smaller numbers.
>>>
>>>   It is assumed that the Diffie-Hellman exponents in this exchange are
>>>   erased from memory after use. In particular, these exponents MUST NOT
>>>   be derived from long-lived secrets like the seed to a pseudo-random
>>>   generator that is not erased after use.
>>>
>>>   The security of this protocol is critically dependent on the
>>>   randomness of the Diffie-Hellman exponents, which should be generated
>>>   by a strong random or properly seeded pseudo-random source (see
>>>   RFC1715). While the protocol was designed to be secure even if the
>>>   Nonces and other values specified as random are not strongly random,

(17) I do not know what "not strongly random" means. We assume that Ni,Nr are random
and then they should be "stronly pseudo-random", not less than the DH exponents.

>>>   they should similarly be generated from a strong random source as
>>>   part of a conservative design.
>>>

---

From: Francis Dupont <[email-masked]>
Date: Tue, 04 Mar 2003 11:54:52 +0100

In your previous mail you wrote:

   
   
=> no, the (I)nitiator bit is for the original initiator (it is used to
recognize its SPI in SPIi | SPIr), the (R)eply bit is about the current
exchange (it is used to know if the message is a request or a reply, this
information is needed to interpret the sequence number, aka message ID).

Regards

[email-masked]

---

From: [email-masked]
Date: Tue, 11 Mar 2003 22:43:59 -0500

> on ikev2 04") and not reflected in 05.

Sorry to have somehow missed these changes last time around, and thank you
for the careful review. I've incorporated your comments except as noted
below:

> length of the prf key. (This is particularly relevant to prf's basedon
block
> ciphers, e.g. AES-CBC-MAC.)

I'm not comfortable with this change. When the prf is HMAC, which accepts
an arbitrary length key, there is no problem. I'm concerned that truncating
the nonces makes the protocol more fragile in the case where an
implementation fails to choose the nonces adequately randomly. I added: "If
the prf does not accept variable length key, its specification for use with
IKEv2 must include a procedure for deriving its required fixed length key
from a variable length key".

I'll start a new string asking the AES-CBC MAC advocates how they
want to handle this.

>       AUTH = prf(Shared Secret, "Key Pad for IKEv2" | <message bytes>)

I added the following explanatory text:

The pad string is added so that if the shared secret is derived from a
password, the IKE implementation need not store the password in cleartext,
but rather can store a one way transformation of it that could not be used
as a password equivalent for protocols other than IKEv2.

Adding the key pad as a prefix to the message bytes does not in general
give the same security benefit.

If you still don't understand the goal, I can try to elaborate more. If you
do understand but think it does not provide the promised benefit, please
explain.

          --Charlie

Opinions expressed may not even be mine by the time you read them, and
certainly don't reflect those of any other entity (legal or otherwise).

---

From: Hugo Krawczyk <[email-masked]>
Date: Tue, 18 Mar 2003 04:16:44 +0200 (IST)

> do understand but think it does not provide the promised benefit, please

Yes. I now understand.
However, this is too much of HMAC-centric thinking.
In your above proposal you are assuming an arbitrary key-length prf,
which is not the general case as discussed in realtion to the Ni|Nr
issue (to which I answered separately).

Here, there is a (mathematically) cleaner way to achieve what you want.
Assuming that SharedSecret is suitable as key to a prf, then you can 
define AuthSecret = prf(SharedSecret, "Key Pad for IKEv2")
and AUTH = prf(AuthSecret, <message bytes>).

Note that in this way you make it clear that it suffices to keep the value
AuthSecret in memory (rather than Shared Secret) for authentication
(thus achieveing the password protection you intended)

Hugo

---

From: [email-masked]
Date: Tue, 18 Mar 2003 19:29:37 -0500

This is also related to prf functions with fixed length keys. I had
proposed that the AUTH payload be computed as:

which won't work if the prf has a fixed size key. Hugo proposed the
alternative encoding:

AuthSecret = prf( prf(Shared Secret, "Key Pad for IKEv2") , <message
bytes>)

and using that encoding whether or not the prf takes a fixed size key
(presumably with Shared Secret padded or truncated as necessary to match
the fixed key size).

I'm happy with that. Any objections?

          --Charlie

---

From: Hugo Krawczyk <[email-masked]>
Date: Wed, 19 Mar 2003 05:44:04 +0200 (IST)

just to point to a small (but possibly confusing) typo:

On Tue, 18 Mar 2003 [email-masked] wrote:

> AuthSecret = prf( prf(Shared Secret, "Key Pad for IKEv2") , <message bytes>)
  ^^^^^^^^^^
  this should be AUTH

Also, Charlie, I suggest that you explain in the text that an
implementation only needs to use (or keep in memory) the value 
prf(Shared Secret, "Key Pad for IKEv2"), thus avoiding the need to
store the user's password atthe server/gateway.

Hugo