Esempio n. 1
0
void
test_crypto (const struct crypto_options *co, struct frame* frame)
{
  int i, j;
  struct gc_arena gc = gc_new ();
  struct buffer src = alloc_buf_gc (TUN_MTU_SIZE (frame), &gc);
  struct buffer work = alloc_buf_gc (BUF_SIZE (frame), &gc);
  struct buffer encrypt_workspace = alloc_buf_gc (BUF_SIZE (frame), &gc);
  struct buffer decrypt_workspace = alloc_buf_gc (BUF_SIZE (frame), &gc);
  struct buffer buf = clear_buf();

  /* init work */
  ASSERT (buf_init (&work, FRAME_HEADROOM (frame)));

  msg (M_INFO, "Entering " PACKAGE_NAME " crypto self-test mode.");
  for (i = 1; i <= TUN_MTU_SIZE (frame); ++i)
    {
      update_time ();

      msg (M_INFO, "TESTING ENCRYPT/DECRYPT of packet length=%d", i);

      /*
       * Load src with random data.
       */
      ASSERT (buf_init (&src, 0));
      ASSERT (i <= src.capacity);
      src.len = i;
      ASSERT (rand_bytes (BPTR (&src), BLEN (&src)));

      /* copy source to input buf */
      buf = work;
      memcpy (buf_write_alloc (&buf, BLEN (&src)), BPTR (&src), BLEN (&src));

      /* encrypt */
      openvpn_encrypt (&buf, encrypt_workspace, co, frame);

      /* decrypt */
      openvpn_decrypt (&buf, decrypt_workspace, co, frame);

      /* compare */
      if (buf.len != src.len)
	msg (M_FATAL, "SELF TEST FAILED, src.len=%d buf.len=%d", src.len, buf.len);
      for (j = 0; j < i; ++j)
	{
	  const uint8_t in = *(BPTR (&src) + j);
	  const uint8_t out = *(BPTR (&buf) + j);
	  if (in != out)
	    msg (M_FATAL, "SELF TEST FAILED, pos=%d in=%d out=%d", j, in, out);
	}
    }
  msg (M_INFO, PACKAGE_NAME " crypto self-test mode SUCCEEDED.");
  gc_free (&gc);
}
Esempio n. 2
0
void
read_incoming_tun (struct context *c)
{
  /*
   * Setup for read() call on TUN/TAP device.
   */
  /*ASSERT (!c->c2.to_link.len);*/

  perf_push (PERF_READ_IN_TUN);

  c->c2.buf = c->c2.buffers->read_tun_buf;
#ifdef TUN_PASS_BUFFER
  read_tun_buffered (c->c1.tuntap, &c->c2.buf, MAX_RW_SIZE_TUN (&c->c2.frame));
#else
  ASSERT (buf_init (&c->c2.buf, FRAME_HEADROOM (&c->c2.frame)));
  ASSERT (buf_safe (&c->c2.buf, MAX_RW_SIZE_TUN (&c->c2.frame)));
  c->c2.buf.len = read_tun (c->c1.tuntap, BPTR (&c->c2.buf), MAX_RW_SIZE_TUN (&c->c2.frame));
#endif

#ifdef PACKET_TRUNCATION_CHECK
  ipv4_packet_size_verify (BPTR (&c->c2.buf),
			   BLEN (&c->c2.buf),
			   TUNNEL_TYPE (c->c1.tuntap),
			   "READ_TUN",
			   &c->c2.n_trunc_tun_read);
#endif

  /* Was TUN/TAP interface stopped? */
  if (tuntap_stop (c->c2.buf.len))
    {
      register_signal (c, SIGTERM, "tun-stop");
      msg (M_INFO, "TUN/TAP interface has been stopped, exiting");
      perf_pop ();
      return;		  
    }

  /* Was TUN/TAP I/O operation aborted? */
  if (tuntap_abort(c->c2.buf.len))
  {
     register_signal(c, SIGHUP, "tun-abort");
     c->persist.restart_sleep_seconds = 10;
     msg(M_INFO, "TUN/TAP I/O operation aborted, restarting");
     perf_pop();
     return;
  }

  /* Check the status return from read() */
  check_status (c->c2.buf.len, "read from TUN/TAP", NULL, c->c1.tuntap);

  perf_pop ();
}
Esempio n. 3
0
static void
lzo_decompress(struct buffer *buf, struct buffer work,
               struct compress_context *compctx,
               const struct frame *frame)
{
    lzo_uint zlen = EXPANDED_SIZE(frame);
    int err;
    uint8_t c;          /* flag indicating whether or not our peer compressed */

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

    ASSERT(buf_init(&work, FRAME_HEADROOM(frame)));

    c = *BPTR(buf);
    ASSERT(buf_advance(buf, 1));

    if (c == LZO_COMPRESS_BYTE) /* packet was compressed */
    {
        ASSERT(buf_safe(&work, zlen));
        err = LZO_DECOMPRESS(BPTR(buf), BLEN(buf), BPTR(&work), &zlen,
                             compctx->wu.lzo.wmem);
        if (err != LZO_E_OK)
        {
            dmsg(D_COMP_ERRORS, "LZO decompression error: %d", err);
            buf->len = 0;
            return;
        }

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

        dmsg(D_COMP, "LZO decompress %d -> %d", buf->len, work.len);
        compctx->pre_decompress += buf->len;
        compctx->post_decompress += work.len;

        *buf = work;
    }
    else if (c == NO_COMPRESS_BYTE)     /* packet was not compressed */
    {
    }
    else
    {
        dmsg(D_COMP_ERRORS, "Bad LZO decompression header byte: %d", c);
        buf->len = 0;
    }
}
Esempio n. 4
0
static void
lz4v2_decompress(struct buffer *buf, struct buffer work,
                 struct compress_context *compctx,
                 const struct frame *frame)
{
    size_t zlen_max = EXPANDED_SIZE(frame);
    uint8_t c;          /* flag indicating whether or not our peer compressed */

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

    ASSERT(buf_init(&work, FRAME_HEADROOM(frame)));

    /* do unframing/swap (assumes buf->len > 0) */
    uint8_t *head = BPTR(buf);
    c = *head;

    /* Not compressed */
    if (c != COMP_ALGV2_INDICATOR_BYTE)
    {
        return;
    }

    /* Packet to short to make sense */
    if (buf->len <= 1)
    {
        buf->len = 0;
        return;
    }

    c = head[1];
    if (c == COMP_ALGV2_LZ4_BYTE) /* packet was compressed */
    {
        buf_advance(buf,2);
        do_lz4_decompress(zlen_max, &work, buf, compctx);
    }
    else if (c == COMP_ALGV2_UNCOMPRESSED_BYTE)
    {
        buf_advance(buf,2);
    }
    else
    {
        dmsg(D_COMP_ERRORS, "Bad LZ4v2 decompression header byte: %d", c);
        buf->len = 0;
    }
}
Esempio n. 5
0
static bool
do_lz4_compress(struct buffer *buf,
                struct buffer *work,
                struct compress_context *compctx,
                const struct frame *frame)
{
    /*
     * In order to attempt compression, length must be at least COMPRESS_THRESHOLD.
     */
    if (buf->len >= COMPRESS_THRESHOLD)
    {
        const size_t ps = PAYLOAD_SIZE(frame);
        int zlen_max = ps + COMP_EXTRA_BUFFER(ps);
        int zlen;

        ASSERT(buf_init(work, FRAME_HEADROOM(frame)));
        ASSERT(buf_safe(work, zlen_max));

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

        zlen = LZ4_compress_limitedOutput((const char *)BPTR(buf), (char *)BPTR(work), BLEN(buf), zlen_max );

        if (zlen <= 0)
        {
            dmsg(D_COMP_ERRORS, "LZ4 compression error");
            buf->len = 0;
            return false;
        }

        ASSERT(buf_safe(work, zlen));
        work->len = zlen;


        dmsg(D_COMP, "LZ4 compress %d -> %d", buf->len, work->len);
        compctx->pre_compress += buf->len;
        compctx->post_compress += work->len;
        return true;
    }
    return false;
}
Esempio n. 6
0
static void
lz4_decompress(struct buffer *buf, struct buffer work,
               struct compress_context *compctx,
               const struct frame *frame)
{
    size_t zlen_max = EXPANDED_SIZE(frame);
    uint8_t c;          /* flag indicating whether or not our peer compressed */

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

    ASSERT(buf_init(&work, FRAME_HEADROOM(frame)));

    /* do unframing/swap (assumes buf->len > 0) */
    {
        uint8_t *head = BPTR(buf);
        c = *head;
        --buf->len;
        *head = *BEND(buf);
    }

    if (c == LZ4_COMPRESS_BYTE) /* packet was compressed */
    {
        do_lz4_decompress(zlen_max, &work, buf, compctx);
    }
    else if (c == NO_COMPRESS_BYTE_SWAP) /* packet was not compressed */
    {
    }
    else
    {
        dmsg(D_COMP_ERRORS, "Bad LZ4 decompression header byte: %d", c);
        buf->len = 0;
    }
}
Esempio n. 7
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;
    }
}
Esempio n. 8
0
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;
}
Esempio n. 9
0
void
check_send_occ_msg_dowork (struct context *c)
{
  bool doit = false;

  c->c2.buf = c->c2.buffers->aux_buf;
  ASSERT (buf_init (&c->c2.buf, FRAME_HEADROOM (&c->c2.frame)));
  ASSERT (buf_safe (&c->c2.buf, MAX_RW_SIZE_TUN (&c->c2.frame)));
  ASSERT (buf_write (&c->c2.buf, occ_magic, OCC_STRING_SIZE));

  switch (c->c2.occ_op)
    {
    case OCC_REQUEST:
      if (!buf_write_u8 (&c->c2.buf, OCC_REQUEST))
	break;
      dmsg (D_PACKET_CONTENT, "SENT OCC_REQUEST");
      doit = true;
      break;

    case OCC_REPLY:
      if (!c->c2.options_string_local)
	break;
      if (!buf_write_u8 (&c->c2.buf, OCC_REPLY))
	break;
      if (!buf_write (&c->c2.buf, c->c2.options_string_local,
		      strlen (c->c2.options_string_local) + 1))
	break;
      dmsg (D_PACKET_CONTENT, "SENT OCC_REPLY");
      doit = true;
      break;

    case OCC_MTU_REQUEST:
      if (!buf_write_u8 (&c->c2.buf, OCC_MTU_REQUEST))
	break;
      dmsg (D_PACKET_CONTENT, "SENT OCC_MTU_REQUEST");
      doit = true;
      break;

    case OCC_MTU_REPLY:
      if (!buf_write_u8 (&c->c2.buf, OCC_MTU_REPLY))
	break;
      if (!buf_write_u16 (&c->c2.buf, c->c2.max_recv_size_local))
	break;
      if (!buf_write_u16 (&c->c2.buf, c->c2.max_send_size_local))
	break;
      dmsg (D_PACKET_CONTENT, "SENT OCC_MTU_REPLY");
      doit = true;
      break;

    case OCC_MTU_LOAD_REQUEST:
      if (!buf_write_u8 (&c->c2.buf, OCC_MTU_LOAD_REQUEST))
	break;
      if (!buf_write_u16 (&c->c2.buf, c->c2.occ_mtu_load_size))
	break;
      dmsg (D_PACKET_CONTENT, "SENT OCC_MTU_LOAD_REQUEST");
      doit = true;
      break;

    case OCC_MTU_LOAD:
      {
	int need_to_add;

	if (!buf_write_u8 (&c->c2.buf, OCC_MTU_LOAD))
	  break;
	need_to_add = min_int (c->c2.occ_mtu_load_size, EXPANDED_SIZE (&c->c2.frame))
			       - OCC_STRING_SIZE
			       - sizeof (uint8_t)
	                       - EXTRA_FRAME (&c->c2.frame);

	while (need_to_add > 0)
	  {
	    /*
	     * Fill the load test packet with pseudo-random bytes.
	     */
	    if (!buf_write_u8 (&c->c2.buf, get_random () & 0xFF))
	      break;
	    --need_to_add;
	  }
	dmsg (D_PACKET_CONTENT, "SENT OCC_MTU_LOAD min_int(%d-%d-%d-%d,%d) size=%d",
	     c->c2.occ_mtu_load_size,
	     OCC_STRING_SIZE,
	      (int) sizeof (uint8_t),
	     EXTRA_FRAME (&c->c2.frame),
	     MAX_RW_SIZE_TUN (&c->c2.frame),
	     BLEN (&c->c2.buf));
	doit = true;
      }
      break;

    case OCC_EXIT:
      if (!buf_write_u8 (&c->c2.buf, OCC_EXIT))
	break;
      dmsg (D_PACKET_CONTENT, "SENT OCC_EXIT");
      doit = true;
      break;
    }

  if (doit)
    {
      /*
       * We will treat the packet like any other outgoing packet,
       * compress, encrypt, sign, etc.
       */
      encrypt_sign (c, true);
    }

  c->c2.occ_op = -1;
}
Esempio n. 10
-1
/*
 * Should we ping the remote?
 */
void
check_ping_send_dowork (struct context *c)
{
  c->c2.buf = c->c2.buffers->aux_buf;
  ASSERT (buf_init (&c->c2.buf, FRAME_HEADROOM (&c->c2.frame)));
  ASSERT (buf_safe (&c->c2.buf, MAX_RW_SIZE_TUN (&c->c2.frame)));
  ASSERT (buf_write (&c->c2.buf, ping_string, sizeof (ping_string)));

  /*
   * We will treat the ping like any other outgoing packet,
   * encrypt, sign, etc.
   */
  encrypt_sign (c, true);
  dmsg (D_PING, "SENT PING");
}