Subject: [IPsec] Some comments on draft-tjhai-ipsecme-hybrid-qske-ikev2-02

From: "Valery Smyslov" <[email-masked]>
Date: Wed, 31 Oct 2018 16:55:23 +0300

Hi,

here are some comments on -02 QSKE draft to stimulate further discussion.

1. Nonces. 

    The draft specifies that each additional key exchange performed 
    over IKE_AUX includes new nonces. My question - why nonces exchanged
    during IKE_SA_INIT cannot be used instead? Is it critical for security?
    I have no problem with exchanging new nonces in each IKE_AUX, 
    my concern is that while performing authentication only the nonces
    exchanged in IKE_SA_INIT are covered by the signature. For example
    for initiator:

    InitiatorSignedOctets = RealMessage1 | NonceRData | MACedIDForI

    where NonceRData is the content of the responder's nonce from IKE_SA_INIT.
    Currently IKE_AUX draft doesn't redefine this, except that it adds initiator's 
    IKE_AUX content into the calculation. Is it OK, or should we modify AUTH payload 
    calculation in case QSKE is used? In particular - include all the peer's
    nonces from IKE_AUX exchanges in NonceRData?

2. QSKE negotiation. 

   I still think that we can use the existing negotiation mechanism instead of 
   defining an additional one. I don't think we should consider the argument 
   that now there are buggy implementations out there, since we're 
   developing a long term solution.

    How it can be done with existing mechanism. 

    First approach, classical: we define new transform types as follows:

    Transform Type 6: QSKE of type 1 (say lattice based)
    Transform Type 7: QSKE of type 2 (say isogeny based)
    Transform Type 8: QSKE of type 3 (say code based)
    etc.

    In this case list of Transform IDs for each new Transform Type will be different - only relevant
    algorithms must be included. In addition some QSKE Transform IDs with a small public key 
    (regardless of type) will also be added to the list of possible Transform IDs for Transform Type 4.

    With this approach there's no strict mapping from QSKE to IKE_AUX, actually all the 
    selected QSKE can be put together into single IKE_AUX exchange or can be performed
    one after one in a series of IKE_AUX exchanges. The latter seems more natural
   and is in line with current QSKE draft. Note, that KE from Transform Type 4 will
    always be performed in IKE_SA_INIT. If QSKEs are performed in a series of IKE_AUX, 
   the order of them is not defined explicitly. Either we decide that the order is not imported
   (if it is OK from security PoV), or the order will be implicitly defined by the order
   of new Transform Types (6 and up) in initiator's proposal (there is no requirement in RFC 7296 that
   responder keep the order of Transform Types in a response).

   This approach has a potential problem: if more types of QSKE appear this will require to add 
   new Transform Types. Since old implementations are unaware of these types (even if they are
   aware of Types 6, 7, 8 etc), policy need to be written in such a way, 
   that proposals are doubled - one with new types and one without them.
   This will increase the size of SA payload. This problem can be dealt with
    if we define spare Transform Types beforehand - so as the same time
    as Transform Types 6-8 are defined for known types of QSKE,
    we can define also Transform Types 9, 10, 11 and so on (how many is enough?)
    for yet unknown types of QSKE (populated only with NONE Transform ID for now). 
    With this "hack" all new implementations will know what these transforms are
    and won't reject proposals with them.

   Another problem with this approach is that if we want to express policy
   "perform single QSKE of any type" then the number of proposals would
    grow, since initiator has to include all the new Transform Types
   in each proposal including NONE Transform ID in all but one Transform Type,
   different in each proposal.

   For these reasons I think a different approach is more convenient: we define 
    new transform types as follows:

    Transform Type 6: Additional QSKE performed in 1st IKE_AUX
    Transform Type 7: Additional QSKE performed in 2nd IKE_AUX
    Transform Type 8: Additional QSKE performed in 3rd IKE_AUX
    etc. (How many do we want to combine?)

    The same list of possible Transform IDs representing QSKE methods will be defined 
    for each of these new Transform Types. In addition these QSKE Transform IDs 
    (or some of them with a small enough public key) will also be added to the list
    of possible Transform IDs for Transform Type 4.

   This approach is flexible enough to define various policies:
   - don't use QSKE
   - use a single QSKE (in addition to classical KE)
   - use combination of no less than two (three, etc) QSKEs

    The SA payload may still grow if you want to restrict which QSKE methods 
    can be combined with which ones.

   Comparing to the separate negotiation mechanism proposed in the draft:
   - it seems that using SA Proposals is clearer than separate mechanism
   - in case of complex policies the size of SA payload may grow, so the size
     of IKE_SA_INIT request may be larger than with the draft's negotiation
     mechanism. I still hope that we can avoid the necessity of complex
     policies, but if this is a concern, we may consider the draft
     draft-smyslov-ipsecme-ikev2-compact-04 "Compact Format of IKEv2 Payloads",
     which allows to substantially reduce the size of SA payload.

    Any thoughts?

3. CREATE_CHILD_SA

    The draft currently is silent about using QSKE in CREATE_CHILD_SA exchange. 
    However it seems that QSKE methods must also be supported in this
    exchange (at least for IKE SA rekeying). IKE_AUX is specifically designed
    to be used between IKE_SA_INIT and IKE_AUTH, so either we must
    modify CREATE_CHILD_SA to allow multiple KE payloads or define
    some new exchange. My concern is that sending all QSKE payloads
    in one message may result in a very large number of fragments, that would
    potentially decrease protocol reliability on a lossy networks (if any single 
    fragment is lost all fragments must be resent). With IKE_AUX QSKE 
    are performed one by one, so the number of fragments will be less.
    If this is a concern, then some mechanisms need to be defined
    that allow to perform QSKE one by one even in CREATE_CHILD_SA.
    For example, perform a series of INFORMATIONAL exchanges
    linked to CREATE_CHILD_SA to complete QS key exchange:

   Initiator                         Responder
   -------------------------------------------------------------------
   HDR, SK {SA, Ni, KEi} -->
                                <--  HDR, SK {SA, Nr, KEr, N(ExchangeID1)}

    since initiator proposed and responder agreed upon that
    one or more QSKE need to be performed, the new SA is not
    created at this point, instead the responder returns some
    Exchange ID in a new notification (this Exchange ID allows
    to link INFORMATIONAL exchanges with the CREATE_CHILD_SA
    and with subsequent INFORMATIONAL). Then initiator starts 
    series of INFORMATIONAL exchanges (one by one) to complete 
    key exchange with QS methods:

   Initiator                         Responder
   -------------------------------------------------------------------
   HDR, SK { N(ExchangeID1), N1i, QSKe1i,} -->
                                <--  HDR, SK { N1r, QSKe1r, N(ExchangeID2)}

   HDR, SK { N(ExchangeID2), N2i, QSKe2i,} -->
                                <--  HDR, SK { N2r, QSKe2r, N(ExchangeID3)}

   HDR, SK { N(ExchangeID3), N3i, QSKe3i,} -->
                                <--  HDR, SK { N3r, QSKe3r}

    At this point all key are exchanged, so the SA is created.

   Any ideas?

Regards,
Valery.

---

From: "Scott Fluhrer (sfluhrer)" <[email-masked]>
Date: Wed, 31 Oct 2018 16:16:02 +0000

> -----Original Message-----
> From: Valery Smyslov <[email-masked]>
> Sent: Wednesday, October 31, 2018 9:55 AM
> To: IPsecME WG <[email-masked]>
> Cc: [email-masked]
> Subject: Some comments on draft-tjhai-ipsecme-hybrid-qske-ikev2-02
> 
> Hi,
> 

No, it is not.  Instead, we were (mostly) reusing the format of the CREATE_CHILD_SA request; as that request already had nonces, we saw no specific reason to remove them.

>     nonces from IKE_AUX exchanges in NonceRData?

Your draft includes the hash (collision resistant PRF, actually) of the aux messages in the AUX_I, which is included in the data which is signed.  Because the nonces are included in computing the AUX_I messages, we are protected; there is no specific need to include those nonces separately.

>     (regardless of type) will also be added to the list of possible Transform IDs

Minor comment on the last bit about making small public key transforms all type 4; because (with your proposal) the responder can't accept more than one type 4 transform, that would mean that you couldn't bundle (say) Curve25519 and SIKE (which is a small postquantum key exchange).

I would claim that is something that we would want to allow people to negotiate (as SIKE isn't necessarily well trusted, and so it would be plausible that someone would like to negotiate Curve25519 as well).

>    responder keep the order of Transform Types in a response).

My issue with this general idea is backwards compatibility; if we issue a transform of type 5 to an old IKEv2 system, it may reject the entire exchange with an "unrecognized transform type" error (and yes, there are real systems that behave this way).

And, it could be argued that such an IKEv2 implementation would be compliant; section 3.3.3 of RFC7296 would appear to forbid any transform types other than 1-4 in an IKE negotiation.

>     of possible Transform IDs for Transform Type 4.

Why not make them all a possible transform id for type 4?  After all, there are scenarios where fragmentation is not an issue (e.g. TCP encaps)

>      which allows to substantially reduce the size of SA payload.

Now, one thing that had been bothering me with our proposal is that there is no way to include attributes along with the transform id.  Now, the existing DH/ECDH transforms do not have any attributes defined; however some of the NIST submissions have a large number of variations (Round2 had 30 different ones), and while we could make each variation a different transform id (which is effectively what we did with DH and ECDH; there really is only one DH algorithm; the exact transform id selected which parameters were used with that algorithm), however it's not clear if that's the approach we want to mandate with the newer postquantum transforms.

>     The draft currently is silent about using QSKE in CREATE_CHILD_SA

Or, more specifically, using more than one keying mechanism; you can use any single KE for a CREATE_CHILD_SA, either conventional or postquantum.

Actually, I believe that there is some weasel working saying "you can get this effect by negotiating several child SA's in succession"; however, I can certainly understand it if the working group decided that was not acceptable...

>     linked to CREATE_CHILD_SA to complete QS key exchange:

I suspect you'll need to be more explicit about having something tying the multiple messages together.  After all, there can be several of these exchanges going on simultaneously; it would be good to be explicit.

---

From: Tero Kivinen <[email-masked]>
Date: Thu, 1 Nov 2018 01:03:51 +0200

Scott Fluhrer (sfluhrer) writes:
> My issue with this general idea is backwards compatibility; if we
> issue a transform of type 5 to an old IKEv2 system, it may reject
> the entire exchange with an "unrecognized transform type" error (and
> yes, there are real systems that behave this way).

That implementation is broken, and needs to be fixed. 

> And, it could be argued that such an IKEv2 implementation would be
> compliant; section 3.3.3 of RFC7296 would appear to forbid any
> transform types other than 1-4 in an IKE negotiation.

That is not true. Section 3.3.3 lists mandatory types, and those
optional types, which are included in that RFC. It does NOT list any
of the future optional types.

In section 3.3.6 this is explained very clearly:

   If the responder receives a proposal that contains a Transform Type
   it does not understand, or a proposal that is missing a mandatory
   Transform Type, it MUST consider this proposal unacceptable; however,
   other proposals in the same SA payload are processed as usual.
   Similarly, if the responder receives a transform that it does not
   understand, or one that contains a Transform Attribute it does not
   understand, it MUST consider this transform unacceptable; other
   transforms with the same Transform Type are processed as usual.  This
   allows new Transform Types and Transform Attributes to be defined in
   the future.

I.e., the intention is that if there is transform type you do not
understand you skip whole proposal, but STILL PROCESS rest of the
proposals normally, i.e., this allows backward compatiblity.

I.e., if we have SA payload:

   SA Payload
      |
      +--- Proposal #1 ( Proto ID = IKE(1), SPI size = 0,
      |     |            14 transforms)
      |     |
      |     +-- Transform ENCR ( Name = ENCR_AES_CBC )
      |     |     +-- Attribute ( Key Length = 128 )
      |     +-- Transform ENCR ( Name = ENCR_AES_CBC )
      |     |     +-- Attribute ( Key Length = 192 )
      |     +-- Transform ENCR ( Name = ENCR_AES_CBC )
      |     |     +-- Attribute ( Key Length = 256 )
      |     +-- Transform PRF ( Name = PRF_HMAC_SHA2_256 )
      |     +-- Transform PRF ( Name = PRF_HMAC_SHA2_384 )
      |     +-- Transform PRF ( Name = PRF_HMAC_SHA2_512 )
      |     +-- Transform INTEG ( Name = AUTH_HMAC_SHA2_256_128 )
      |     +-- Transform INTEG ( Name = AUTH_HMAC_SHA2_384_192 )
      |     +-- Transform INTEG ( Name = AUTH_HMAC_SHA2_512_256 )
      |     +-- Transform D-H ( Name = 8192-bit MODP Group )
      |     +-- Transform D-H ( Name = Curve25519 )
      |     +-- Transform D-H ( Name = Curve448 )
      |     +-- Transform QSKE1 ( Name = Foobar )
      |     +-- Transform QSKE1 ( Name = Zappa )
      |
      +--- Proposal #2 ( Proto ID = IKE(1), SPI size = 0,
      |     |            14 transforms)
      |     |
      |     +-- Transform ENCR ( Name = ENCR_AES_CBC )
      |     |     +-- Attribute ( Key Length = 128 )
      |     +-- Transform ENCR ( Name = ENCR_AES_CBC )
      |     |     +-- Attribute ( Key Length = 192 )
      |     +-- Transform ENCR ( Name = ENCR_AES_CBC )
      |     |     +-- Attribute ( Key Length = 256 )
      |     +-- Transform PRF ( Name = PRF_HMAC_SHA2_256 )
      |     +-- Transform PRF ( Name = PRF_HMAC_SHA2_384 )
      |     +-- Transform PRF ( Name = PRF_HMAC_SHA2_512 )
      |     +-- Transform INTEG ( Name = AUTH_HMAC_SHA2_256_128 )
      |     +-- Transform INTEG ( Name = AUTH_HMAC_SHA2_384_192 )
      |     +-- Transform INTEG ( Name = AUTH_HMAC_SHA2_512_256 )
      |     +-- Transform D-H ( Name = 8192-bit MODP Group )
      |     +-- Transform D-H ( Name = Curve25519 )
      |     +-- Transform D-H ( Name = Curve448 )
      |     +-- Transform QSKE1 ( Name = Foobar )
      |     +-- Transform QSKE2 ( Name = Zappa )
      |
      +--- Proposal #3 ( Proto ID = IKE(1), SPI size = 0,
            |            12 transforms)
            |
            +-- Transform ENCR ( Name = ENCR_AES_CBC )
            |     +-- Attribute ( Key Length = 128 )
            +-- Transform ENCR ( Name = ENCR_AES_CBC )
            |     +-- Attribute ( Key Length = 192 )
            +-- Transform ENCR ( Name = ENCR_AES_CBC )
            |     +-- Attribute ( Key Length = 256 )
            +-- Transform PRF ( Name = PRF_HMAC_SHA2_256 )
            +-- Transform PRF ( Name = PRF_HMAC_SHA2_384 )
            +-- Transform PRF ( Name = PRF_HMAC_SHA2_512 )
            +-- Transform INTEG ( Name = AUTH_HMAC_SHA2_256_128 )
            +-- Transform INTEG ( Name = AUTH_HMAC_SHA2_384_192 )
            +-- Transform INTEG ( Name = AUTH_HMAC_SHA2_512_256 )
            +-- Transform D-H ( Name = 8192-bit MODP Group )
            +-- Transform D-H ( Name = Curve25519 )
            +-- Transform D-H ( Name = Curve448 )

Then complient old implementation will ignore proposals 1 and 2, as
they include Transforms they do not understand, and see that proposal
3 has all the things it needs, and nothing extra, and then it will
pick one value for each Transform Type and return that back i.e., it
might return:

      +--- Proposal #3 ( Proto ID = IKE(1), SPI size = 0,
            |            4 transforms)
            |
            +-- Transform ENCR ( Name = ENCR_AES_CBC )
            |     +-- Attribute ( Key Length = 256 )
            +-- Transform PRF ( Name = PRF_HMAC_SHA2_512 )
            +-- Transform INTEG ( Name = AUTH_HMAC_SHA2_512_256 )
            +-- Transform D-H ( Name = Curve448 )

If you have implementation that do support QSKE algorithm "Zappa", but
not "Foobar", then it will ignore the Proposal 2, as proposal 2 has
QSKE1 transform ID of "Foobar" which it does not support (and as that
has both QSKE1 and QSKE2, so it must pick one value from both. So it
would then pick proposal 1 and return:

      +--- Proposal #1 ( Proto ID = IKE(1), SPI size = 0,
            |            5 transforms)
            |
            +-- Transform ENCR ( Name = ENCR_AES_CBC )
            |     +-- Attribute ( Key Length = 256 )
            +-- Transform PRF ( Name = PRF_HMAC_SHA2_512 )
            +-- Transform INTEG ( Name = AUTH_HMAC_SHA2_512_256 )
            +-- Transform D-H ( Name = Curve448 )
            +-- Transform QSKE1 ( Name = Zappa )

Implementation which supports both "Foobar" and "Zappa", can either do
one of them by picking proposal #1, and selecting the one it wants to
do in QSKE1, or it can also pick proposal #2 and do both "Foobar" and
"Zappa", and Foobar will be done as QSKE1 and Zappa is done as QSKE2:

      +--- Proposal #6 ( Proto ID = IKE(1), SPI size = 0,
            |            6 transforms)
            |
            +-- Transform ENCR ( Name = ENCR_AES_CBC )
            |     +-- Attribute ( Key Length = 256 )
            +-- Transform PRF ( Name = PRF_HMAC_SHA2_512 )
            +-- Transform INTEG ( Name = AUTH_HMAC_SHA2_512_256 )
            +-- Transform D-H ( Name = Curve448 )
            +-- Transform QSKE1 ( Name = Foobar )
            +-- Transform QSKE2 ( Name = Zappa )

> >    For these reasons I think a different approach is more
> > convenient: we define new transform types as follows:
> > 
> >     The same list of possible Transform IDs representing QSKE
> > methods will be defined for each of these new Transform Types. In
> > addition these QSKE Transform IDs (or some of them with a small
> > enough public key) will also be added to the list of possible
> > Transform IDs for Transform Type 4.
> 
> Why not make them all a possible transform id for type 4? After all,
> there are scenarios where fragmentation is not an issue (e.g. TCP
> encaps)

If all of them are Transform Type 4, i.e. D-H, then responder MUST
pick exactly one that is the only one to be used. Responder is not
allowed return more than one Transform ID for each Transform Type
there is in proposal. 

> Now, one thing that had been bothering me with our proposal is that
> there is no way to include attributes along with the transform id.
> Now, the existing DH/ECDH transforms do not have any attributes
> defined; however some of the NIST submissions have a large number of
> variations (Round2 had 30 different ones), and while we could make
> each variation a different transform id (which is effectively what
> we did with DH and ECDH; there really is only one DH algorithm; the
> exact transform id selected which parameters were used with that
> algorithm), however it's not clear if that's the approach we want to
> mandate with the newer postquantum transforms.

Each Transform ID can also have arbitrary number of attributes inside,
and the as you can have multiple entries with same Transform Type, but
either different Transform ID or different Attributes inside, the
responder can pick exactly one of the Transform Type of that type, and
include all attributes unmodified.

Currently we only have Key Length attribute, but lets say we later
define "Key Rounds" attribute, then we could have Transform Type ENCR
with following proposals:

  +-- Transform ENCR ( Name = ENCR_FOO )
  |     +-- Attribute ( Key Length = 128 )
  |	+-- Attribute ( Key Rounds = 16 )
  +-- Transform ENCR ( Name = ENCR_FOO )
  |     +-- Attribute ( Key Length = 256 )
  |	+-- Attribute ( Key Rounds = 32 )
  +-- Transform ENCR ( Name = ENCR_AES_CBC )
        +-- Attribute ( Key Length = 256 )

And now responder can return any of the 3 proposed ENCR transforms,
i.e.:

  +-- Transform ENCR ( Name = ENCR_FOO )
        +-- Attribute ( Key Length = 128 )
   	+-- Attribute ( Key Rounds = 16 )

or

  +-- Transform ENCR ( Name = ENCR_FOO )
        +-- Attribute ( Key Length = 256 )
   	+-- Attribute ( Key Rounds = 32 )

or

  +-- Transform ENCR ( Name = ENCR_AES_CBC )
        +-- Attribute ( Key Length = 256 )

but nothing else. It cannot modify the attributes in any way. 
-- 
[email-masked]