]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
Change openvpn_encrypt() to append to work buffer only
authorSteffan Karger <steffan@karger.me>
Sun, 7 Feb 2016 19:47:14 +0000 (20:47 +0100)
committerGert Doering <gert@greenie.muc.de>
Tue, 9 Feb 2016 08:15:07 +0000 (09:15 +0100)
Preparation for AEAD cipher modes, which also have to authenticate the
opcode and peer-id of packets.  To supply that information to
openvpn_encrypt(), I want to simply write those to the work buffer
before calling openvpn_encrypt().  That however requires that
openvpn_encrypt() never prepends something to the work buffer.

Signed-off-by: Steffan Karger <steffan@karger.me>
Acked-by: Arne Schwabe <arne@rfc2549.org>
Message-Id: <1454874438-5081-7-git-send-email-steffan@karger.me>
URL: http://article.gmane.org/gmane.network.openvpn.devel/11074
Signed-off-by: Gert Doering <gert@greenie.muc.de>
src/openvpn/crypto.c

index db52182688be67c2689f164cc9d44f21f6ab6bfc..e92125e748d73b7d6bae9b4b6badc21b3e7cf1b2 100644 (file)
@@ -93,6 +93,8 @@ openvpn_encrypt (struct buffer *buf, struct buffer work,
   if (buf->len > 0 && opt)
     {
       const struct key_ctx *ctx = &opt->key_ctx_bi.encrypt;
+      uint8_t *mac_out = NULL;
+      const uint8_t *hmac_start = NULL;
 
       /* Do Encrypt from buf -> work */
       if (ctx->cipher)
@@ -102,6 +104,17 @@ openvpn_encrypt (struct buffer *buf, struct buffer work,
          const cipher_kt_t *cipher_kt = cipher_ctx_get_cipher_kt (ctx->cipher);
          int outlen;
 
+         /* initialize work buffer with FRAME_HEADROOM bytes of prepend capacity */
+         ASSERT (buf_init (&work, FRAME_HEADROOM (frame)));
+
+         /* Reserve space for HMAC */
+         if (ctx->hmac)
+           {
+             mac_out = buf_write_alloc (&work, hmac_ctx_size(ctx->hmac));
+             ASSERT (mac_out);
+             hmac_start = BEND(&work);
+           }
+
          if (cipher_kt_mode_cbc(cipher_kt))
            {
              CLEAR (iv_buf);
@@ -137,12 +150,12 @@ openvpn_encrypt (struct buffer *buf, struct buffer work,
              ASSERT (0);
            }
 
-         /* initialize work buffer with FRAME_HEADROOM bytes of prepend capacity */
-         ASSERT (buf_init (&work, FRAME_HEADROOM (frame)));
-
          /* set the IV pseudo-randomly */
          if (opt->flags & CO_USE_IV)
-           dmsg (D_PACKET_CONTENT, "ENCRYPT IV: %s", format_hex (iv_buf, iv_size, 0, &gc));
+            {
+              ASSERT (buf_write(&work, iv_buf, iv_size));
+              dmsg (D_PACKET_CONTENT, "ENCRYPT IV: %s", format_hex (iv_buf, iv_size, 0, &gc));
+            }
 
          dmsg (D_PACKET_CONTENT, "ENCRYPT FROM: %s",
               format_hex (BPTR (buf), BLEN (buf), 80, &gc));
@@ -165,27 +178,16 @@ openvpn_encrypt (struct buffer *buf, struct buffer work,
            }
 
          /* Encrypt packet ID, payload */
-         ASSERT (cipher_ctx_update (ctx->cipher, BPTR (&work), &outlen, BPTR (buf), BLEN (buf)));
+         ASSERT (cipher_ctx_update (ctx->cipher, BEND (&work), &outlen, BPTR (buf), BLEN (buf)));
          ASSERT (buf_inc_len(&work, outlen));
 
          /* Flush the encryption buffer */
-         ASSERT (cipher_ctx_final(ctx->cipher, BPTR (&work) + outlen, &outlen));
+         ASSERT (cipher_ctx_final(ctx->cipher, BEND (&work), &outlen));
          ASSERT (buf_inc_len(&work, outlen));
 
          /* For all CBC mode ciphers, check the last block is complete */
          ASSERT (cipher_kt_mode (cipher_kt) != OPENVPN_MODE_CBC ||
              outlen == iv_size);
-
-         /* prepend the IV to the ciphertext */
-         if (opt->flags & CO_USE_IV)
-           {
-             uint8_t *output = buf_prepend (&work, iv_size);
-             ASSERT (output);
-             memcpy (output, iv_buf, iv_size);
-           }
-
-         dmsg (D_PACKET_CONTENT, "ENCRYPT TO: %s",
-              format_hex (BPTR (&work), BLEN (&work), 80, &gc));
        }
       else                             /* No Encryption */
        {
@@ -195,22 +197,29 @@ openvpn_encrypt (struct buffer *buf, struct buffer work,
              packet_id_alloc_outgoing (&opt->packet_id.send, &pin, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM));
              ASSERT (packet_id_write (&pin, buf, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM), true));
            }
+         if (ctx->hmac)
+           {
+             hmac_start = BPTR(buf);
+             ASSERT (mac_out = buf_prepend (buf, hmac_ctx_size(ctx->hmac)));
+           }
+         buf_write_prepend(buf, BPTR(&work), BLEN(&work));
          work = *buf;
        }
 
       /* HMAC the ciphertext (or plaintext if !cipher) */
       if (ctx->hmac)
        {
-         uint8_t *output = NULL;
-
          hmac_ctx_reset (ctx->hmac);
-         hmac_ctx_update (ctx->hmac, BPTR(&work), BLEN(&work));
-         output = buf_prepend (&work, hmac_ctx_size(ctx->hmac));
-         ASSERT (output);
-         hmac_ctx_final (ctx->hmac, output);
+         hmac_ctx_update (ctx->hmac, hmac_start, BEND(&work) - hmac_start);
+         hmac_ctx_final (ctx->hmac, mac_out);
+         dmsg (D_PACKET_CONTENT, "ENCRYPT HMAC: %s",
+             format_hex (mac_out, hmac_ctx_size(ctx->hmac), 80, &gc));
        }
 
       *buf = work;
+
+      dmsg (D_PACKET_CONTENT, "ENCRYPT TO: %s",
+         format_hex (BPTR (&work), BLEN (&work), 80, &gc));
     }
 
   gc_free (&gc);