]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
ivgen: Allow reusing the same message ID twice in sequential IV gen
authorMartin Willi <martin@revosec.ch>
Tue, 2 Jun 2015 12:08:42 +0000 (14:08 +0200)
committerTobias Brunner <tobias@strongswan.org>
Fri, 5 Jun 2015 11:44:42 +0000 (13:44 +0200)
We use the message ID and fragment number as IV generator. As IKEv2 uses
distinct message ID counters for actively and passively initiated exchanges,
each IV would be used twice. As we explicitly reject such message IDs since
d0ed1079, original-responder initiated exchanges fail with counter mode ciphers.

This commit separates IV space in two halves for sequential IVs, and
automatically assigns once reused sequence numbers to the second half.

Fixes #980.

src/libstrongswan/crypto/iv/iv_gen_seq.c

index 4de13744d92a94b1dff6b5c0b247577fcf854d0c..9f99c51920bdf2d939d9d715f18adf092a128b8b 100644 (file)
@@ -19,6 +19,7 @@
  * Magic value for the initial IV state
  */
 #define SEQ_IV_INIT_STATE (~(u_int64_t)0)
+#define SEQ_IV_HIGH_MASK (1ULL << 63)
 
 typedef struct private_iv_gen_t private_iv_gen_t;
 
@@ -33,9 +34,14 @@ struct private_iv_gen_t {
        iv_gen_t public;
 
        /**
-        * Previously passed sequence number to enforce uniqueness
+        * Previously passed sequence number in lower space to enforce uniqueness
         */
-       u_int64_t prev;
+       u_int64_t prevl;
+
+       /**
+        * Previously passed sequence number in upper space to enforce uniqueness
+        */
+       u_int64_t prevh;
 
        /**
         * Salt to mask counter
@@ -57,15 +63,26 @@ METHOD(iv_gen_t, get_iv, bool,
        {
                return FALSE;
        }
-       if (this->prev != SEQ_IV_INIT_STATE && seq <= this->prev)
+       if (this->prevl != SEQ_IV_INIT_STATE && seq <= this->prevl)
        {
-               return FALSE;
+               seq |= SEQ_IV_HIGH_MASK;
+               if (this->prevh != SEQ_IV_INIT_STATE && seq <= this->prevh)
+               {
+                       return FALSE;
+               }
        }
-       if (seq == SEQ_IV_INIT_STATE)
+       if ((seq | SEQ_IV_HIGH_MASK) == SEQ_IV_INIT_STATE)
        {
                return FALSE;
        }
-       this->prev = seq;
+       if (seq & SEQ_IV_HIGH_MASK)
+       {
+               this->prevh = seq;
+       }
+       else
+       {
+               this->prevl = seq;
+       }
        if (len > sizeof(u_int64_t))
        {
                len = sizeof(u_int64_t);
@@ -107,7 +124,8 @@ iv_gen_t *iv_gen_seq_create()
                        .allocate_iv = _allocate_iv,
                        .destroy = _destroy,
                },
-               .prev = SEQ_IV_INIT_STATE,
+               .prevl = SEQ_IV_INIT_STATE,
+               .prevh = SEQ_IV_INIT_STATE,
        );
 
        rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);