Exemple #1
0
static void
stub_compress(struct buffer *buf, struct buffer work,
              struct compress_context *compctx,
              const struct frame *frame)
{
    if (buf->len <= 0)
    {
        return;
    }
    if (compctx->flags & COMP_F_SWAP)
    {
        uint8_t *head = BPTR(buf);
        uint8_t *tail  = BEND(buf);
        ASSERT(buf_safe(buf, 1));
        ++buf->len;

        /* move head byte of payload to tail */
        *tail = *head;
        *head = NO_COMPRESS_BYTE_SWAP;
    }
    else
    {
        uint8_t *header = buf_prepend(buf, 1);
        *header = NO_COMPRESS_BYTE;
    }
}
Exemple #2
0
static void
lz4v2_compress(struct buffer *buf, struct buffer work,
               struct compress_context *compctx,
               const struct frame *frame)
{
    bool compressed;
    if (buf->len <= 0)
    {
        return;
    }

    compressed = do_lz4_compress(buf, &work, compctx, frame);

    /* On Error just return */
    if (buf->len == 0)
    {
        return;
    }

    /* did compression save us anything?  Include 2 byte compression header
     * in calculation */
    if (compressed && work.len + 2 < buf->len)
    {
        ASSERT(buf_prepend(&work, 2));
        uint8_t *head = BPTR(&work);
        head[0] = COMP_ALGV2_INDICATOR_BYTE;
        head[1] = COMP_ALGV2_LZ4_BYTE;
        *buf = work;
    }
    else
    {
        compv2_escape_data_ifneeded(buf);
    }
}
Exemple #3
0
/* In the v2 compression schemes, an uncompressed packet has
 * has no opcode in front, unless the first byte is 0x50. In this
 * case the packet needs to be escaped */
void
compv2_escape_data_ifneeded (struct buffer *buf)
{
    uint8_t *head = BPTR (buf);
    if (head[0] != COMP_ALGV2_INDICATOR_BYTE)
	return;

    /* Header is 0x50 */
    ASSERT(buf_prepend(buf, 2));

    head = BPTR (buf);
    head[0] = COMP_ALGV2_INDICATOR_BYTE;
    head[1] = COMP_ALGV2_UNCOMPRESSED;
}
Exemple #4
0
/*
 * Return a buffer for write that is a subset of another buffer
 */
struct buffer
buf_sub (struct buffer *buf, int size, bool prepend)
{
  struct buffer ret;
  uint8_t *data;

  CLEAR (ret);
  data = prepend ? buf_prepend (buf, size) : buf_write_alloc (buf, size);
  if (data)
    {
      ret.capacity = size;
      ret.data = data;
    }
  return ret;
}
Exemple #5
0
static void
lzo_compress(struct buffer *buf, struct buffer work,
             struct compress_context *compctx,
             const struct frame *frame)
{
    lzo_uint zlen = 0;
    int err;
    bool compressed = false;

    if (buf->len <= 0)
    {
        return;
    }

    /*
     * In order to attempt compression, length must be at least COMPRESS_THRESHOLD,
     * and our adaptive level must give the OK.
     */
    if (buf->len >= COMPRESS_THRESHOLD && lzo_compression_enabled(compctx))
    {
        const size_t ps = PAYLOAD_SIZE(frame);
        ASSERT(buf_init(&work, FRAME_HEADROOM(frame)));
        ASSERT(buf_safe(&work, ps + COMP_EXTRA_BUFFER(ps)));

        if (buf->len > ps)
        {
            dmsg(D_COMP_ERRORS, "LZO compression buffer overflow");
            buf->len = 0;
            return;
        }

        err = LZO_COMPRESS(BPTR(buf), BLEN(buf), BPTR(&work), &zlen, compctx->wu.lzo.wmem);
        if (err != LZO_E_OK)
        {
            dmsg(D_COMP_ERRORS, "LZO compression error: %d", err);
            buf->len = 0;
            return;
        }

        ASSERT(buf_safe(&work, zlen));
        work.len = zlen;
        compressed = true;

        dmsg(D_COMP, "LZO compress %d -> %d", buf->len, work.len);
        compctx->pre_compress += buf->len;
        compctx->post_compress += work.len;

        /* tell adaptive level about our success or lack thereof in getting any size reduction */
        if (compctx->flags & COMP_F_ADAPTIVE)
        {
            lzo_adaptive_compress_data(&compctx->wu.lzo.ac, buf->len, work.len);
        }
    }

    /* did compression save us anything ? */
    if (compressed && work.len < buf->len)
    {
        uint8_t *header = buf_prepend(&work, 1);
        *header = LZO_COMPRESS_BYTE;
        *buf = work;
    }
    else
    {
        uint8_t *header = buf_prepend(buf, 1);
        *header = NO_COMPRESS_BYTE;
    }
}
void
openvpn_encrypt (struct buffer *buf, struct buffer work,
		 const struct crypto_options *opt,
		 const struct frame* frame)
{
  struct gc_arena gc;
  gc_init (&gc);

  if (buf->len > 0 && opt->key_ctx_bi)
    {
      struct key_ctx *ctx = &opt->key_ctx_bi->encrypt;

      /* Do Encrypt from buf -> work */
      if (ctx->cipher)
	{
	  uint8_t iv_buf[OPENVPN_MAX_IV_LENGTH];
	  const int iv_size = cipher_ctx_iv_length (ctx->cipher);
	  const cipher_kt_t *cipher_kt = cipher_ctx_get_cipher_kt (ctx->cipher);
	  int outlen;

	  if (cipher_kt_mode_cbc(cipher_kt))
	    {
	      CLEAR (iv_buf);

	      /* generate pseudo-random IV */
	      if (opt->flags & CO_USE_IV)
		prng_bytes (iv_buf, iv_size);

	      /* Put packet ID in plaintext buffer or IV, depending on cipher mode */
	      if (opt->packet_id)
		{
		  struct packet_id_net pin;
		  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));
		}
	    }
	  else if (cipher_kt_mode_ofb_cfb(cipher_kt))
	    {
	      struct packet_id_net pin;
	      struct buffer b;

	      ASSERT (opt->flags & CO_USE_IV);    /* IV and packet-ID required */
	      ASSERT (opt->packet_id); /*  for this mode. */

	      packet_id_alloc_outgoing (&opt->packet_id->send, &pin, true);
	      memset (iv_buf, 0, iv_size);
	      buf_set_write (&b, iv_buf, iv_size);
	      ASSERT (packet_id_write (&pin, &b, true, false));
	    }
	  else /* We only support CBC, CFB, or OFB modes right now */
	    {
	      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));

	  dmsg (D_PACKET_CONTENT, "ENCRYPT FROM: %s",
	       format_hex (BPTR (buf), BLEN (buf), 80, &gc));

	  /* cipher_ctx was already initialized with key & keylen */
	  ASSERT (cipher_ctx_reset(ctx->cipher, iv_buf));

	  /* Buffer overflow check */
	  if (!buf_safe (&work, buf->len + cipher_ctx_block_size(ctx->cipher)))
	    {
	      msg (D_CRYPT_ERRORS, "ENCRYPT: buffer size error, bc=%d bo=%d bl=%d wc=%d wo=%d wl=%d cbs=%d",
		   buf->capacity,
		   buf->offset,
		   buf->len,
		   work.capacity,
		   work.offset,
		   work.len,
		   cipher_ctx_block_size (ctx->cipher));
	      goto err;
	    }

	  /* Encrypt packet ID, payload */
	  ASSERT (cipher_ctx_update (ctx->cipher, BPTR (&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 (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 */
	{
	  if (opt->packet_id)
	    {
	      struct packet_id_net pin;
	      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));
	    }
	  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);
	}

      *buf = work;
    }

  gc_free (&gc);
  return;

err:
  crypto_clear_error();
  buf->len = 0;
  gc_free (&gc);
  return;
}