Hi,

Feature-ack, and overall looks good. But some nits to tackle.

On 24-10-2018 12:06, Arne Schwabe wrote:
> This commit introduces the allow-compression option that allow
> changing the new default to the previous default or to a stricter
> version.
> 
> Warning are not generated in the post option check
> (options_postprocess_mutate) since these warnings should also be shown
> on pushed options.
> 
> Patch V2: fix spelling and grammer (thanks tincantech), also fix
>    uncompressiable to incompressible in three other instances in the
>    source code
> 
> Patch V3: fix overlong lines. Do not allow compression to be pushed
> ---
>  doc/openvpn.8          |  44 ++++++++++++++----
>  src/openvpn/comp-lz4.c |   3 +-
>  src/openvpn/comp.c     |   2 +-
>  src/openvpn/comp.h     |  16 +++++--
>  src/openvpn/lzo.c      |   2 +-
>  src/openvpn/mtu.h      |   2 +-
>  src/openvpn/options.c  | 101 ++++++++++++++++++++++++++++++++++++-----
>  7 files changed, 143 insertions(+), 27 deletions(-)
> 
> diff --git a/doc/openvpn.8 b/doc/openvpn.8
> index d40dcf43..ac923f51 100644
> --- a/doc/openvpn.8
> +++ b/doc/openvpn.8
> @@ -2545,26 +2545,54 @@ Enable a compression algorithm.
>  
>  The
>  .B algorithm
> -parameter may be "lzo", "lz4", or empty.  LZO and LZ4
> -are different compression algorithms, with LZ4 generally
> +parameter may be "lzo", "lz4", "lz4\-v2", "stub", "stub\-v2" or empty.
> +LZO and LZ4 are different compression algorithms, with LZ4 generally
>  offering the best performance with least CPU usage.
>  For backwards compatibility with OpenVPN versions before v2.4, use "lzo"
>  (which is identical to the older option "\-\-comp\-lzo yes").
>  
> +The "lz4\-v2" and "stub\-v2" variants implement a better framing that does 
> not add
> +overhead when packets cannot be compressed. All other variants always add 
> one extra
> +framing byte compared to no compression framing.
> +
>  If the
>  .B algorithm
> -parameter is empty, compression will be turned off, but the packet
> -framing for compression will still be enabled, allowing a different
> -setting to be pushed later.
> +parameter is "stub", "stub\-v2", or empty, compression will be turned off, 
> but
> +the packet framing for compression will still be enabled, allowing a 
> different
> +setting to be pushed later. Additionally, "stub" and "stub\-v2" will disable
> +announcing lzo and lz4 compression support via "IV_" variables to the server.
> +
>  
>  .B Security Considerations
>  
>  Compression and encryption is a tricky combination.  If an attacker knows or 
> is
>  able to control (parts of) the plaintext of packets that contain secrets, the
>  attacker might be able to extract the secret if compression is enabled.  See
> -e.g. the CRIME and BREACH attacks on TLS which also leverage compression to
> -break encryption.  If you are not entirely sure that the above does not apply
> -to your traffic, you are advised to *not* enable compression.
> +e.g. the CRIME and BREACH attacks on TLS and VORACLE on VPNs which also 
> leverage
> +compression to break encryption.  If you are not entirely sure that the 
> above does
> +not apply to your traffic, you are advised to *not* enable compression.
> +
> +.\"*********************************************************
> +.TP
> +.B \-\-allow\-compression [mode]
> +As described in
> +\.B \-\-compress
> +option, compression is potentially dangerous option. This option allows
> +controlling the behaviour of OpenVPN when compression is used and allowed.
> +.B mode
> +may be "yes", "no", or "asym" (default).
> +
> +With allow\-compression set to "no", OpenVPN will refuse any non stub
> +compression. With "yes" OpenVPN will send and receive compressed packets.
> +With "asym", the default, OpenVPN will only decompress (downlink) packets but
> +not compress (uplink) packets. This also allows migrating to disable 
> compression
> +when changing both server and client configurations to remove compression at 
> the
> +same time is not a feasible option.
> +
> +The default of asym has been chosen to maximise compatibility with existing
> +configuration while at the same time phasing out compression in existing
> +deployment by disabling compression on the uplink, effectively completely 
> disabling
> +compression if both client and server are upgraded.
>  
>  .\"*********************************************************
>  .TP
> diff --git a/src/openvpn/comp-lz4.c b/src/openvpn/comp-lz4.c
> index f52fdbfb..fa23e5a5 100644
> --- a/src/openvpn/comp-lz4.c
> +++ b/src/openvpn/comp-lz4.c
> @@ -70,8 +70,9 @@ do_lz4_compress(struct buffer *buf,
>  {
>      /*
>       * In order to attempt compression, length must be at least 
> COMPRESS_THRESHOLD.
> +     * and asymmetric compression must be disabled
>       */
> -    if (buf->len >= COMPRESS_THRESHOLD)
> +    if (buf->len >= COMPRESS_THRESHOLD && (compctx->flags & COMP_F_NO_ASYM))
>      {
>          const size_t ps = PAYLOAD_SIZE(frame);
>          int zlen_max = ps + COMP_EXTRA_BUFFER(ps);
> diff --git a/src/openvpn/comp.c b/src/openvpn/comp.c
> index a9459133..9b131137 100644
> --- a/src/openvpn/comp.c
> +++ b/src/openvpn/comp.c
> @@ -127,7 +127,7 @@ void
>  comp_add_to_extra_buffer(struct frame *frame)
>  {
>      /* Leave room for compression buffer to expand in worst case scenario
> -     * where data is totally uncompressible */
> +     * where data is totally incompressible */
>      frame_add_to_extra_buffer(frame, 
> COMP_EXTRA_BUFFER(EXPANDED_SIZE(frame)));
>  }
>  
> diff --git a/src/openvpn/comp.h b/src/openvpn/comp.h
> index 0dadd1e6..a1a19ed1 100644
> --- a/src/openvpn/comp.h
> +++ b/src/openvpn/comp.h
> @@ -52,10 +52,12 @@
>   */
>  
>  /* Compression flags */
> -#define COMP_F_ADAPTIVE   (1<<0) /* COMP_ALG_LZO only */
> -#define COMP_F_ASYM       (1<<1) /* only downlink is compressed, not uplink 
> */
> -#define COMP_F_SWAP       (1<<2) /* initial command byte is swapped with 
> last byte in buffer to preserve payload alignment */
> +#define COMP_F_ADAPTIVE             (1<<0) /* COMP_ALG_LZO only */
> +#define COMP_F_NO_ASYM              (1<<1) /* not only downlink is 
> compressed but also uplink */

Negative names confuse me. How about COMP_F_ALLOW_COMPRESS?

> +#define COMP_F_SWAP                 (1<<2) /* initial command byte is 
> swapped with last byte in buffer to preserve payload alignment */
>  #define COMP_F_ADVERTISE_STUBS_ONLY (1<<3) /* tell server that we only 
> support compression stubs */
> +#define COMP_F_ALLOW_STUB_ONLY      (1<<4) /* Only accept stub compression, 
> even with COMP_F_ADVERTISE_STUBS_ONLY
> +                                            * we still accept other 
> compressions to be pushed */
>  
>  
>  /*
> @@ -188,6 +190,14 @@ comp_enabled(const struct compress_options *info)
>      return info->alg != COMP_ALG_UNDEF;
>  }
>  
> +static inline bool
> +comp_non_stub_enabled (const struct compress_options *info)

There should be no space between function name and (

> +{
> +    return info->alg != COMP_ALGV2_UNCOMPRESSED &&
> +        info->alg != COMP_ALG_STUB &&
> +        info->alg != COMP_ALG_UNDEF;
> +}
> +
>  static inline bool
>  comp_unswapped_prefix(const struct compress_options *info)
>  {
> diff --git a/src/openvpn/lzo.c b/src/openvpn/lzo.c
> index e3be6adf..61bf0c12 100644
> --- a/src/openvpn/lzo.c
> +++ b/src/openvpn/lzo.c
> @@ -123,7 +123,7 @@ lzo_compress_uninit(struct compress_context *compctx)
>  static inline bool
>  lzo_compression_enabled(struct compress_context *compctx)
>  {
> -    if (compctx->flags & COMP_F_ASYM)
> +    if (!(compctx->flags & COMP_F_NO_ASYM))
>      {
>          return false;
>      }
> diff --git a/src/openvpn/mtu.h b/src/openvpn/mtu.h
> index cfa8d2f7..549c319b 100644
> --- a/src/openvpn/mtu.h
> +++ b/src/openvpn/mtu.h
> @@ -45,7 +45,7 @@
>   *      ifconfig $1 10.1.0.2 pointopoint 10.1.0.1 mtu 1450
>   *
>   *    Compression overflow bytes is the worst-case size expansion that would 
> be
> - *    expected if we tried to compress mtu + extra_frame bytes of 
> uncompressible data.
> + *    expected if we tried to compress mtu + extra_frame bytes of 
> incompressible data.
>   */
>  
>  /*
> diff --git a/src/openvpn/options.c b/src/openvpn/options.c
> index 46c8d53d..cdc27100 100644
> --- a/src/openvpn/options.c
> +++ b/src/openvpn/options.c
> @@ -351,9 +351,10 @@ static const char usage_message[] =
>  #endif
>  #if defined(USE_COMP)
>      "--compress alg  : Use compression algorithm alg\n"
> +    "--allow-compression: Specify wether compression should be allowed\n"

Typo: whether.

>  #if defined(ENABLE_LZO)
>      "--comp-lzo      : Use LZO compression -- may add up to 1 byte per\n"
> -    "                  packet for uncompressible data.\n"
> +    "                  packet for incompressible data.\n"
>      "--comp-noadapt  : Don't use adaptive compression when --comp-lzo\n"
>      "                  is specified.\n"
>  #endif
> @@ -4901,6 +4902,22 @@ set_user_script(struct options *options,
>  #endif
>  }
>  
> +static void show_compression_warning(struct compress_options *info)
> +{
> +    if (comp_non_stub_enabled(info))
> +    {
> +        /*
> +         * Check if already displayed the strong warning and enabled full
> +         * compression
> +         */
> +        if (!(info->flags & COMP_F_NO_ASYM))
> +        {
> +            msg(M_WARN, "WARNING:  Compression enabled, Compression has been 
> "
> +                "used in the past to break encryption. Enabling 
> decompression "
> +                "of received packet only. Sent packets are not compressed.");
> +        }
> +    }
> +}
>  
>  static void
>  add_option(struct options *options,
> @@ -7322,29 +7339,78 @@ add_option(struct options *options,
>      }
>  #endif
>  #if defined(USE_COMP)
> +    else if (streq(p[0], "allow-compression") && p[1] && !p[2])
> +    {
> +        VERIFY_PERMISSION(OPT_P_GENERAL);
> +
> +        if (streq(p[1], "no"))
> +        {
> +            options->comp.flags =
> +                COMP_F_ALLOW_STUB_ONLY|COMP_F_ADVERTISE_STUBS_ONLY;
> +            if (comp_non_stub_enabled(&options->comp))
> +            {
> +                msg(msglevel, "'--allow-compression no' conflicts with "
> +                    " enabling compression");
> +            }

Should this check not be moved to the postprocess checks? This will now
only trigger is comp was first set, and allow-compression later in the
config, not the other way around.

> +        }
> +        else if (options->comp.flags & COMP_F_ALLOW_STUB_ONLY)
> +        {
> +            msg(msglevel, "Cannot set allow-compression to '%s' "
> +                "after set to 'no'", p[1]);
> +            goto err;
> +        }
> +        else if (streq(p[1], "asym"))
> +        {
> +            options->comp.flags &= ~COMP_F_NO_ASYM;
> +        }
> +        else if (streq(p[1], "yes"))
> +        {
> +            msg(M_WARN, "WARNING: Compression enabled, Compression has been"
> +                "used in the past to break encryption. "
> +                "Allowing compression allows attacks that break encryption. "
> +                "Using '--allow-compression yes' is strongly discouraged for 
> "
> +                "common usage. "
> +                "See --compress in the manual page for more information");
> +            options->comp.flags |= COMP_F_NO_ASYM;
> +        }
> +        else
> +        {
> +          msg(msglevel, "bad allow-compression option: %s -- "
> +              "must be 'yes', 'no', or 'asym'", p[1]);
> +          goto err;

Indenting looks off.

> +        }
> +    }
>      else if (streq(p[0], "comp-lzo") && !p[2])
>      {
>          VERIFY_PERMISSION(OPT_P_COMP);
>  
> +        /* All lzo variants do not use swap */
> +        options->comp.flags &= ~COMP_F_SWAP;
>  #if defined(ENABLE_LZO)
>          if (p[1] && streq(p[1], "no"))
>  #endif
>          {
>              options->comp.alg = COMP_ALG_STUB;
> -            options->comp.flags = 0;
> +            options->comp.flags &= ~COMP_F_ADAPTIVE;
>          }
>  #if defined(ENABLE_LZO)
> +        else if (options->comp.flags & COMP_F_ALLOW_STUB_ONLY)
> +        {
> +            msg(msglevel, "Cannot set comp-lzo to '%s', "
> +                "allow-compression is set to 'no'", p[1]);
> +            goto err;
> +        }
>          else if (p[1])
>          {
>              if (streq(p[1], "yes"))
>              {
>                  options->comp.alg = COMP_ALG_LZO;
> -                options->comp.flags = 0;
> +                options->comp.flags &= ~COMP_F_ADAPTIVE;
>              }
>              else if (streq(p[1], "adaptive"))
>              {
>                  options->comp.alg = COMP_ALG_LZO;
> -                options->comp.flags = COMP_F_ADAPTIVE;
> +                options->comp.flags |= COMP_F_ADAPTIVE;
>              }
>              else
>              {
> @@ -7355,12 +7421,17 @@ add_option(struct options *options,
>          else
>          {
>              options->comp.alg = COMP_ALG_LZO;
> -            options->comp.flags = COMP_F_ADAPTIVE;
> +            options->comp.flags |= COMP_F_ADAPTIVE;
>          }
> +        show_compression_warning(&options->comp);
>  #endif /* if defined(ENABLE_LZO) */
>      }
>      else if (streq(p[0], "comp-noadapt") && !p[1])
>      {
> +        /*
> +         * We do not need to check here if we allow compression since
> +         * it only modifies a flag if compression is enabled
> +         */
>          VERIFY_PERMISSION(OPT_P_COMP);
>          options->comp.flags &= ~COMP_F_ADAPTIVE;
>      }
> @@ -7372,30 +7443,35 @@ add_option(struct options *options,
>              if (streq(p[1], "stub"))
>              {
>                  options->comp.alg = COMP_ALG_STUB;
> -                options->comp.flags = 
> (COMP_F_SWAP|COMP_F_ADVERTISE_STUBS_ONLY);
> +                options->comp.flags |= 
> (COMP_F_SWAP|COMP_F_ADVERTISE_STUBS_ONLY);
>              }
>              else if (streq(p[1], "stub-v2"))
>              {
>                  options->comp.alg = COMP_ALGV2_UNCOMPRESSED;
> -                options->comp.flags = COMP_F_ADVERTISE_STUBS_ONLY;
> +                options->comp.flags |= COMP_F_ADVERTISE_STUBS_ONLY;
> +            }
> +            else if (options->comp.flags & COMP_F_ALLOW_STUB_ONLY)
> +            {
> +              msg(msglevel, "Cannot set compress to '%s', "
> +                            "allow-compression is set to 'no'", p[1]);
> +              goto err;
>              }
>  #if defined(ENABLE_LZO)
>              else if (streq(p[1], "lzo"))
>              {
>                  options->comp.alg = COMP_ALG_LZO;
> -                options->comp.flags = 0;
> +                options->comp.flags &= ~(COMP_F_ADAPTIVE | COMP_F_SWAP);
>              }
>  #endif
>  #if defined(ENABLE_LZ4)
>              else if (streq(p[1], "lz4"))
>              {
>                  options->comp.alg = COMP_ALG_LZ4;
> -                options->comp.flags = COMP_F_SWAP;
> +                options->comp.flags |= COMP_F_SWAP;
>              }
>              else if (streq(p[1], "lz4-v2"))
>              {
>                  options->comp.alg = COMP_ALGV2_LZ4;
> -                options->comp.flags = 0;
>              }
>  #endif
>              else
> @@ -7407,8 +7483,9 @@ add_option(struct options *options,
>          else
>          {
>              options->comp.alg = COMP_ALG_STUB;
> -            options->comp.flags = COMP_F_SWAP;
> +            options->comp.flags |= COMP_F_SWAP;
>          }
> +      show_compression_warning(&options->comp);

Indenting?

>      }
>  #endif /* USE_COMP */
>      else if (streq(p[0], "show-ciphers") && !p[1])
> @@ -8313,4 +8390,4 @@ add_option(struct options *options,
>      }
>  err:
>      gc_free(&gc);
> -}
> +}
> \ No newline at end of file
> 

Unneeded change.

-Steffan


_______________________________________________
Openvpn-devel mailing list
Openvpn-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/openvpn-devel

Reply via email to