Esempio n. 1
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. 2
0
/*
 * If raw tunnel packet is IPv4, return true and increment
 * buffer offset to start of IP header.
 */
bool
is_ipv4 (int tunnel_type, struct buffer *buf)
{
  int offset;
  const struct openvpn_iphdr *ih;

  verify_align_4 (buf);
  if (tunnel_type == DEV_TYPE_TUN)
    {
      if (BLEN (buf) < (int) sizeof (struct openvpn_iphdr))
	return false;
      offset = 0;
    }
  else if (tunnel_type == DEV_TYPE_TAP)
    {
      const struct openvpn_ethhdr *eh;
      if (BLEN (buf) < (int)(sizeof (struct openvpn_ethhdr)
	  + sizeof (struct openvpn_iphdr)))
	return false;
      eh = (const struct openvpn_ethhdr *) BPTR (buf);
      if (ntohs (eh->proto) != OPENVPN_ETH_P_IPV4)
	return false;
      offset = sizeof (struct openvpn_ethhdr);
    }
  else
    return false;

  ih = (const struct openvpn_iphdr *) (BPTR (buf) + offset);

  if (OPENVPN_IPH_GET_VER (ih->version_len) == 4)
    return buf_advance (buf, offset);
  else
    return false;
}
Esempio n. 3
0
static void
stub_decompress(struct buffer *buf, struct buffer work,
                struct compress_context *compctx,
                const struct frame *frame)
{
    uint8_t c;
    if (buf->len <= 0)
    {
        return;
    }
    if (compctx->flags & COMP_F_SWAP)
    {
        uint8_t *head = BPTR(buf);
        c = *head;
        --buf->len;
        *head = *BEND(buf);
        if (c != NO_COMPRESS_BYTE_SWAP)
        {
            dmsg(D_COMP_ERRORS, "Bad compression stub (swap) decompression header byte: %d", c);
            buf->len = 0;
        }
    }
    else
    {
        c = *BPTR(buf);
        ASSERT(buf_advance(buf, 1));
        if (c != NO_COMPRESS_BYTE)
        {
            dmsg(D_COMP_ERRORS, "Bad compression stub decompression header byte: %d", c);
            buf->len = 0;
        }
    }
}
Esempio n. 4
0
/*
 * Lower MSS on TCP SYN packets to fix MTU
 * problems which arise from protocol
 * encapsulation.
 */
void
mss_fixup (struct buffer *buf, int maxmss)
{
  const struct openvpn_iphdr *pip;
  int hlen;

  if (BLEN (buf) < (int) sizeof (struct openvpn_iphdr))
    return;
  
  verify_align_4 (buf);
  pip = (struct openvpn_iphdr *) BPTR (buf);

  hlen = OPENVPN_IPH_GET_LEN (pip->version_len);

  if (pip->protocol == OPENVPN_IPPROTO_TCP
      && ntohs (pip->tot_len) == BLEN (buf)
      && (ntohs (pip->frag_off) & OPENVPN_IP_OFFMASK) == 0
      && hlen <= BLEN (buf)
      && BLEN (buf) - hlen
         >= (int) sizeof (struct openvpn_tcphdr))
    {
      struct buffer newbuf = *buf;
      if (buf_advance (&newbuf, hlen))
	{
	  struct openvpn_tcphdr *tc = (struct openvpn_tcphdr *) BPTR (&newbuf);
	  if (tc->flags & OPENVPN_TCPH_SYN_MASK)
	    mss_fixup_dowork (&newbuf, (uint16_t) maxmss);
	}
    }
}
Esempio n. 5
0
/*
 * Act on received restart message from server
 */
void
server_pushed_signal(struct context *c, const struct buffer *buffer, const bool restart, const int adv)
{
    if (c->options.pull)
    {
        struct buffer buf = *buffer;
        const char *m = "";
        if (buf_advance(&buf, adv) && buf_read_u8(&buf) == ',' && BLEN(&buf))
        {
            m = BSTR(&buf);
        }

        /* preserve cached passwords? */
        /* advance to next server? */
        {
            bool purge = true;

            if (m[0] == '[')
            {
                int i;
                for (i = 1; m[i] != '\0' && m[i] != ']'; ++i)
                {
                    if (m[i] == 'P')
                    {
                        purge = false;
                    }
                    else if (m[i] == 'N')
                    {
                        /* next server? */
                        c->options.no_advance = false;
                    }
                }
            }
            if (purge)
            {
                ssl_purge_auth(true);
            }
        }

        if (restart)
        {
            msg(D_STREAM_ERRORS, "Connection reset command was pushed by server ('%s')", m);
            c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- server-pushed connection reset */
            c->sig->signal_text = "server-pushed-connection-reset";
        }
        else
        {
            msg(D_STREAM_ERRORS, "Halt command was pushed by server ('%s')", m);
            c->sig->signal_received = SIGTERM; /* SOFT-SIGTERM -- server-pushed halt */
            c->sig->signal_text = "server-pushed-halt";
        }
#ifdef ENABLE_MANAGEMENT
        if (management)
        {
            management_notify(management, "info", c->sig->signal_text, m);
        }
#endif
    }
}
Esempio n. 6
0
unsigned int
mroute_extract_addr_ether(struct mroute_addr *src,
                          struct mroute_addr *dest,
                          struct mroute_addr *esrc,
                          struct mroute_addr *edest,
                          const struct buffer *buf)
{
    unsigned int ret = 0;
    if (BLEN(buf) >= (int) sizeof(struct openvpn_ethhdr))
    {
        const struct openvpn_ethhdr *eth = (const struct openvpn_ethhdr *) BPTR(buf);
        if (src)
        {
            src->type = MR_ADDR_ETHER;
            src->netbits = 0;
            src->len = 6;
            memcpy(src->eth_addr, eth->source, sizeof(dest->eth_addr));
        }
        if (dest)
        {
            dest->type = MR_ADDR_ETHER;
            dest->netbits = 0;
            dest->len = 6;
            memcpy(dest->eth_addr, eth->dest, sizeof(dest->eth_addr));

            /* ethernet broadcast/multicast packet? */
            if (is_mac_mcast_addr(eth->dest))
            {
                ret |= MROUTE_EXTRACT_BCAST;
            }
        }

        ret |= MROUTE_EXTRACT_SUCCEEDED;

#ifdef ENABLE_PF
        if (esrc || edest)
        {
            struct buffer b = *buf;
            if (buf_advance(&b, sizeof(struct openvpn_ethhdr)))
            {
                switch (ntohs(eth->proto))
                {
                    case OPENVPN_ETH_P_IPV4:
                        ret |= (mroute_extract_addr_ip(esrc, edest, &b) << MROUTE_SEC_SHIFT);
                        break;

                    case OPENVPN_ETH_P_ARP:
                        ret |= (mroute_extract_addr_arp(esrc, edest, &b) << MROUTE_SEC_SHIFT);
                        break;
                }
            }
        }
#endif
    }
    return ret;
}
Esempio n. 7
0
/*
 * If raw tunnel packet is IPv<X>, return true and increment
 * buffer offset to start of IP header.
 */
static
bool
is_ipv_X( int tunnel_type, struct buffer *buf, int ip_ver )
{
    int offset;
    const struct openvpn_iphdr *ih;

    verify_align_4(buf);
    if (tunnel_type == DEV_TYPE_TUN)
    {
    	//tun类型,不包含以太头
        if (BLEN(buf) < (int) sizeof(struct openvpn_iphdr))
        {
            return false;
        }
        offset = 0;
    }
    else if (tunnel_type == DEV_TYPE_TAP)
    {
    	//tap类型,包含以太头
        const struct openvpn_ethhdr *eh;
        if (BLEN(buf) < (int)(sizeof(struct openvpn_ethhdr)
                              + sizeof(struct openvpn_iphdr)))
        {
            return false;
        }
        eh = (const struct openvpn_ethhdr *) BPTR(buf);
        if (ntohs(eh->proto) != (ip_ver == 6 ? OPENVPN_ETH_P_IPV6 : OPENVPN_ETH_P_IPV4))
        {
        	//非指定协议,返回false
            return false;
        }
        offset = sizeof(struct openvpn_ethhdr);
    }
    else
    {
        return false;
    }

    //指向ip头部
    ih = (const struct openvpn_iphdr *) (BPTR(buf) + offset);

    /* IP version is stored in the same bits for IPv4 or IPv6 header */
    if (OPENVPN_IPH_GET_VER(ih->version_len) == ip_ver)
    {
    	//为对应ip协议,使buf指向对应的ip头部
        return buf_advance(buf, offset);
    }
    else
    {
    	//非对应的ip协议,返回false
        return false;
    }
}
Esempio n. 8
0
void
buffer_list_advance (struct buffer_list *ol, int n)
{
  if (ol->head)
    {
      struct buffer *buf = &ol->head->buf;
      ASSERT (buf_advance (buf, n));
      if (!BLEN (buf))
	buffer_list_pop (ol);
    }
}
Esempio n. 9
0
bool
buf_string_compare_advance (struct buffer *src, const char *match)
{
  if (buf_string_match_head_str (src, match))
    {
      buf_advance (src, strlen (match));
      return true;
    }
  else
    return false;
}
Esempio n. 10
0
/* undo effect of socks_preprocess_outgoing_link */
static inline void
link_socket_write_post_size_adjust (int *size,
				    int size_delta,
				    struct buffer *buf)
{
  if (size_delta > 0 && *size > size_delta)
    {
      *size -= size_delta;
      if (!buf_advance (buf, size_delta))
	*size = 0;
    }
}
Esempio n. 11
0
/*
 * Auth username/password
 *
 * Client received an authentication failed message from server.
 * Runs on client.
 */
void
receive_auth_failed(struct context *c, const struct buffer *buffer)
{
    msg(M_VERB0, "AUTH: Received control message: %s", BSTR(buffer));
    c->options.no_advance = true;

    if (c->options.pull)
    {
        switch (auth_retry_get())
        {
            case AR_NONE:
                c->sig->signal_received = SIGTERM; /* SOFT-SIGTERM -- Auth failure error */
                break;

            case AR_INTERACT:
                ssl_purge_auth(false);

            case AR_NOINTERACT:
                c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- Auth failure error */
                break;

            default:
                ASSERT(0);
        }
        c->sig->signal_text = "auth-failure";
#ifdef ENABLE_MANAGEMENT
        if (management)
        {
            const char *reason = NULL;
            struct buffer buf = *buffer;
            if (buf_string_compare_advance(&buf, "AUTH_FAILED,") && BLEN(&buf))
            {
                reason = BSTR(&buf);
            }
            management_auth_failure(management, UP_TYPE_AUTH, reason);
        }
#endif
        /*
         * Save the dynamic-challenge text even when management is defined
         */
        {
#ifdef ENABLE_CLIENT_CR
            struct buffer buf = *buffer;
            if (buf_string_match_head_str(&buf, "AUTH_FAILED,CRV1:") && BLEN(&buf))
            {
                buf_advance(&buf, 12); /* Length of "AUTH_FAILED," substring */
                ssl_put_auth_challenge(BSTR(&buf));
            }
#endif
        }
    }
}
Esempio n. 12
0
static void
stubv2_decompress(struct buffer *buf, struct buffer work,
                  struct compress_context *compctx,
                  const struct frame *frame)
{
    if (buf->len <= 0)
    {
        return;
    }

    uint8_t *head = BPTR(buf);

    /* no compression or packet to short*/
    if (head[0] != COMP_ALGV2_INDICATOR_BYTE)
    {
        return;
    }

    /* compression header (0x50) is present */
    buf_advance(buf, 1);

    /* Packet buffer too short (only 1 byte) */
    if (buf->len <= 0)
    {
        return;
    }

    head = BPTR(buf);
    buf_advance(buf, 1);

    if (head[0] != COMP_ALGV2_UNCOMPRESSED_BYTE)
    {
        dmsg(D_COMP_ERRORS, "Bad compression stubv2 decompression header byte: %d", *head);
        buf->len = 0;
        return;
    }
}
Esempio n. 13
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. 14
0
File: proto.c Progetto: jmadhav/lib
/*
 * If raw tunnel packet is IPv4, return true and increment
 * buffer offset to start of IP header.
 */
bool
is_ipv4 (int tunnel_type, struct buffer *buf)
{
  int offset;
  const struct openvpn_iphdr *ih;

  verify_align_4 (buf);
  if (tunnel_type == DEV_TYPE_TUN)
    {
      if (BLEN (buf) < (int) sizeof (struct openvpn_iphdr))
	return false;
      offset = 0;
    }
  else if (tunnel_type == DEV_TYPE_TAP)
    {
      const struct openvpn_ethhdr *eh;
      if (BLEN (buf) < (int)(sizeof (struct openvpn_ethhdr)
	  + sizeof (struct openvpn_iphdr)))
	return false;
      eh = (const struct openvpn_ethhdr *) BPTR (buf);
      if (ntohs (eh->proto) != OPENVPN_ETH_P_IPV4)
	return false;
      offset = sizeof (struct openvpn_ethhdr);
    }
  else
    return false;

  ih = (const struct openvpn_iphdr *) (BPTR (buf) + offset);

  if (OPENVPN_IPH_GET_VER (ih->version_len) == 4)
  {	
	 /* struct	in_addr x,y;
	  x.s_addr = ih->saddr;
	  y.s_addr = ih->daddr;
	  
    printf("\n src=%s,dest=%s", inet_ntoa(x),inet_ntoa(y));*/
	  return buf_advance (buf, offset);
  }  
  else
    return false;
}
Esempio n. 15
0
static int
proxy_connection_io_send (struct proxy_connection *pc, int *bytes_sent)
{
  const socket_descriptor_t sd = pc->counterpart->sd;
  const int status = send (sd, BPTR(&pc->buf), BLEN(&pc->buf), MSG_NOSIGNAL);

  if (status < 0)
    {
      const int e = errno;
      return (e == EAGAIN) ? IOSTAT_EAGAIN_ON_WRITE : IOSTAT_WRITE_ERROR;
    }
  else
    {
      *bytes_sent += status;
      if (status != pc->buf.len)
	{
	  dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: partial write[%d], tried=%d got=%d", (int)sd, pc->buf.len, status);
	  buf_advance (&pc->buf, status);
	  return IOSTAT_EAGAIN_ON_WRITE;
	}
      else
	{
	  dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: wrote[%d] %d", (int)sd, status);
	  pc->buf.len = 0;
	  pc->buf.offset = 0;
	}
    }

  /* realloc send buffer after initial send */
  if (pc->buffer_initial)
    {
      free_buf (&pc->buf);
      pc->buf = alloc_buf (PROXY_CONNECTION_BUFFER_SIZE);
      pc->buffer_initial = false;
    }
  return IOSTAT_GOOD;
}
Esempio n. 16
0
bool
tls_crypt_v2_extract_client_key(struct buffer *buf,
                                struct tls_wrap_ctx *ctx,
                                const struct tls_options *opt)
{
    if (!ctx->tls_crypt_v2_server_key.cipher)
    {
        msg(D_TLS_ERRORS,
            "Client wants tls-crypt-v2, but no server key present.");
        return false;
    }

    msg(D_HANDSHAKE, "Control Channel: using tls-crypt-v2 key");

    struct buffer wrapped_client_key = *buf;
    uint16_t net_len = 0;

    if (BLEN(&wrapped_client_key) < sizeof(net_len))
    {
        msg(D_TLS_ERRORS, "failed to read length");
    }
    memcpy(&net_len, BEND(&wrapped_client_key) - sizeof(net_len),
           sizeof(net_len));

    size_t wkc_len = ntohs(net_len);
    if (!buf_advance(&wrapped_client_key, BLEN(&wrapped_client_key) - wkc_len))
    {
        msg(D_TLS_ERRORS, "Can not locate tls-crypt-v2 client key");
        return false;
    }

    struct key2 client_key = { 0 };
    ctx->tls_crypt_v2_metadata = alloc_buf(TLS_CRYPT_V2_MAX_METADATA_LEN);
    if (!tls_crypt_v2_unwrap_client_key(&client_key,
                                        &ctx->tls_crypt_v2_metadata,
                                        wrapped_client_key,
                                        &ctx->tls_crypt_v2_server_key))
    {
        msg(D_TLS_ERRORS, "Can not unwrap tls-crypt-v2 client key");
        secure_memzero(&client_key, sizeof(client_key));
        return false;
    }

    /* Load the decrypted key */
    ctx->mode = TLS_WRAP_CRYPT;
    ctx->cleanup_key_ctx = true;
    ctx->opt.flags |= CO_PACKET_ID_LONG_FORM;
    memset(&ctx->opt.key_ctx_bi, 0, sizeof(ctx->opt.key_ctx_bi));
    tls_crypt_v2_load_client_key(&ctx->opt.key_ctx_bi, &client_key, true);
    secure_memzero(&client_key, sizeof(client_key));

    /* Remove client key from buffer so tls-crypt code can unwrap message */
    ASSERT(buf_inc_len(buf, -(BLEN(&wrapped_client_key))));

    if (opt && opt->tls_crypt_v2_verify_script)
    {
        return tls_crypt_v2_verify_metadata(ctx, opt);
    }

    return true;
}
Esempio n. 17
0
static bool
tls_crypt_v2_unwrap_client_key(struct key2 *client_key, struct buffer *metadata,
                               struct buffer wrapped_client_key,
                               struct key_ctx *server_key)
{
    const char *error_prefix = __func__;
    bool ret = false;
    struct gc_arena gc = gc_new();
    /* The crypto API requires one extra cipher block of buffer head room when
     * decrypting, which nicely matches the tag size of WKc.  So
     * TLS_CRYPT_V2_MAX_WKC_LEN is always large enough for the plaintext. */
    uint8_t plaintext_buf_data[TLS_CRYPT_V2_MAX_WKC_LEN] = { 0 };
    struct buffer plaintext = { 0 };

    dmsg(D_TLS_DEBUG_MED, "%s: unwrapping client key (len=%d): %s", __func__,
         BLEN(&wrapped_client_key), format_hex(BPTR(&wrapped_client_key),
                                               BLEN(&wrapped_client_key),
                                               0, &gc));

    if (TLS_CRYPT_V2_MAX_WKC_LEN < BLEN(&wrapped_client_key))
    {
        CRYPT_ERROR("wrapped client key too big");
    }

    /* Decrypt client key and metadata */
    uint16_t net_len = 0;
    const uint8_t *tag = BPTR(&wrapped_client_key);

    if (BLEN(&wrapped_client_key) < sizeof(net_len))
    {
        CRYPT_ERROR("failed to read length");
    }
    memcpy(&net_len, BEND(&wrapped_client_key) - sizeof(net_len),
           sizeof(net_len));

    if (ntohs(net_len) != BLEN(&wrapped_client_key))
    {
        dmsg(D_TLS_DEBUG_LOW, "%s: net_len=%u, BLEN=%i", __func__,
             ntohs(net_len), BLEN(&wrapped_client_key));
        CRYPT_ERROR("invalid length");
    }

    buf_inc_len(&wrapped_client_key, -(int)sizeof(net_len));

    if (!buf_advance(&wrapped_client_key, TLS_CRYPT_TAG_SIZE))
    {
        CRYPT_ERROR("failed to read tag");
    }

    if (!cipher_ctx_reset(server_key->cipher, tag))
    {
        CRYPT_ERROR("failed to initialize IV");
    }
    buf_set_write(&plaintext, plaintext_buf_data, sizeof(plaintext_buf_data));
    int outlen = 0;
    if (!cipher_ctx_update(server_key->cipher, BPTR(&plaintext), &outlen,
                           BPTR(&wrapped_client_key),
                           BLEN(&wrapped_client_key)))
    {
        CRYPT_ERROR("could not decrypt client key");
    }
    ASSERT(buf_inc_len(&plaintext, outlen));

    if (!cipher_ctx_final(server_key->cipher, BEND(&plaintext), &outlen))
    {
        CRYPT_ERROR("cipher final failed");
    }
    ASSERT(buf_inc_len(&plaintext, outlen));

    /* Check authentication */
    uint8_t tag_check[TLS_CRYPT_TAG_SIZE] = { 0 };
    hmac_ctx_reset(server_key->hmac);
    hmac_ctx_update(server_key->hmac, (void *)&net_len, sizeof(net_len));
    hmac_ctx_update(server_key->hmac, BPTR(&plaintext),
                    BLEN(&plaintext));
    hmac_ctx_final(server_key->hmac, tag_check);

    if (memcmp_constant_time(tag, tag_check, sizeof(tag_check)))
    {
        dmsg(D_CRYPTO_DEBUG, "tag      : %s",
             format_hex(tag, sizeof(tag_check), 0, &gc));
        dmsg(D_CRYPTO_DEBUG, "tag_check: %s",
             format_hex(tag_check, sizeof(tag_check), 0, &gc));
        CRYPT_ERROR("client key authentication error");
    }

    if (buf_len(&plaintext) < sizeof(client_key->keys))
    {
        CRYPT_ERROR("failed to read client key");
    }
    memcpy(&client_key->keys, BPTR(&plaintext), sizeof(client_key->keys));
    ASSERT(buf_advance(&plaintext, sizeof(client_key->keys)));

    if (!buf_copy(metadata, &plaintext))
    {
        CRYPT_ERROR("metadata too large for supplied buffer");
    }

    ret = true;
error_exit:
    if (!ret)
    {
        secure_memzero(client_key, sizeof(*client_key));
    }
    buf_clear(&plaintext);
    gc_free(&gc);
    return ret;
}
Esempio n. 18
0
bool
tls_crypt_unwrap(const struct buffer *src, struct buffer *dst,
                 struct crypto_options *opt)
{
    static const char error_prefix[] = "tls-crypt unwrap error";
    const struct key_ctx *ctx = &opt->key_ctx_bi.decrypt;
    struct gc_arena gc;

    gc_init(&gc);

    ASSERT(opt);
    ASSERT(src->len > 0);
    ASSERT(ctx->cipher);
    ASSERT(packet_id_initialized(&opt->packet_id)
           || (opt->flags & CO_IGNORE_PACKET_ID));

    dmsg(D_PACKET_CONTENT, "TLS-CRYPT UNWRAP FROM: %s",
         format_hex(BPTR(src), BLEN(src), 80, &gc));

    if (buf_len(src) < TLS_CRYPT_OFF_CT)
    {
        CRYPT_ERROR("packet too short");
    }

    /* Decrypt cipher text */
    {
        int outlen = 0;

        /* Buffer overflow check (should never fail) */
        if (!buf_safe(dst, BLEN(src) - TLS_CRYPT_OFF_CT + TLS_CRYPT_BLOCK_SIZE))
        {
            CRYPT_ERROR("potential buffer overflow");
        }

        if (!cipher_ctx_reset(ctx->cipher, BPTR(src) + TLS_CRYPT_OFF_TAG))
        {
            CRYPT_ERROR("cipher reset failed");
        }
        if (!cipher_ctx_update(ctx->cipher, BPTR(dst), &outlen,
                               BPTR(src) + TLS_CRYPT_OFF_CT, BLEN(src) - TLS_CRYPT_OFF_CT))
        {
            CRYPT_ERROR("cipher update failed");
        }
        ASSERT(buf_inc_len(dst, outlen));
        if (!cipher_ctx_final(ctx->cipher, BPTR(dst), &outlen))
        {
            CRYPT_ERROR("cipher final failed");
        }
        ASSERT(buf_inc_len(dst, outlen));
    }

    /* Check authentication */
    {
        const uint8_t *tag = BPTR(src) + TLS_CRYPT_OFF_TAG;
        uint8_t tag_check[TLS_CRYPT_TAG_SIZE] = { 0 };

        dmsg(D_PACKET_CONTENT, "TLS-CRYPT UNWRAP AD: %s",
             format_hex(BPTR(src), TLS_CRYPT_OFF_TAG, 0, &gc));
        dmsg(D_PACKET_CONTENT, "TLS-CRYPT UNWRAP TO: %s",
             format_hex(BPTR(dst), BLEN(dst), 80, &gc));

        hmac_ctx_reset(ctx->hmac);
        hmac_ctx_update(ctx->hmac, BPTR(src), TLS_CRYPT_OFF_TAG);
        hmac_ctx_update(ctx->hmac, BPTR(dst), BLEN(dst));
        hmac_ctx_final(ctx->hmac, tag_check);

        if (memcmp_constant_time(tag, tag_check, sizeof(tag_check)))
        {
            dmsg(D_CRYPTO_DEBUG, "tag      : %s",
                 format_hex(tag, sizeof(tag_check), 0, &gc));
            dmsg(D_CRYPTO_DEBUG, "tag_check: %s",
                 format_hex(tag_check, sizeof(tag_check), 0, &gc));
            CRYPT_ERROR("packet authentication failed");
        }
    }

    /* Check replay */
    if (!(opt->flags & CO_IGNORE_PACKET_ID))
    {
        struct packet_id_net pin;
        struct buffer tmp = *src;
        ASSERT(buf_advance(&tmp, TLS_CRYPT_OFF_PID));
        ASSERT(packet_id_read(&pin, &tmp, true));
        if (!crypto_check_replay(opt, &pin, error_prefix, &gc))
        {
            CRYPT_ERROR("packet replay");
        }
    }

    gc_free(&gc);
    return true;

error_exit:
    crypto_clear_error();
    dst->len = 0;
    gc_free(&gc);
    return false;
}
Esempio n. 19
0
void
process_received_occ_msg (struct context *c)
{
  ASSERT (buf_advance (&c->c2.buf, OCC_STRING_SIZE));
  switch (buf_read_u8 (&c->c2.buf))
    {
    case OCC_REQUEST:
      dmsg (D_PACKET_CONTENT, "RECEIVED OCC_REQUEST");
      c->c2.occ_op = OCC_REPLY;
      break;

    case OCC_MTU_REQUEST:
      dmsg (D_PACKET_CONTENT, "RECEIVED OCC_MTU_REQUEST");
      c->c2.occ_op = OCC_MTU_REPLY;
      break;

    case OCC_MTU_LOAD_REQUEST:
      dmsg (D_PACKET_CONTENT, "RECEIVED OCC_MTU_LOAD_REQUEST");
      c->c2.occ_mtu_load_size = buf_read_u16 (&c->c2.buf);
      if (c->c2.occ_mtu_load_size >= 0)
	c->c2.occ_op = OCC_MTU_LOAD;
      break;

    case OCC_REPLY:
      dmsg (D_PACKET_CONTENT, "RECEIVED OCC_REPLY");
      if (c->options.occ && !TLS_MODE (c) && c->c2.options_string_remote)
	{
	  if (!options_cmp_equal_safe ((char *) BPTR (&c->c2.buf),
				       c->c2.options_string_remote,
				       c->c2.buf.len))
	    {
	      options_warning_safe ((char *) BPTR (&c->c2.buf),
				    c->c2.options_string_remote,
				    c->c2.buf.len);
	    }
	}
      event_timeout_clear (&c->c2.occ_interval);
      break;

    case OCC_MTU_REPLY:
      dmsg (D_PACKET_CONTENT, "RECEIVED OCC_MTU_REPLY");
      c->c2.max_recv_size_remote = buf_read_u16 (&c->c2.buf);
      c->c2.max_send_size_remote = buf_read_u16 (&c->c2.buf);
      if (c->options.mtu_test
	  && c->c2.max_recv_size_remote > 0
	  && c->c2.max_send_size_remote > 0)
	{
	  msg (M_INFO, "NOTE: Empirical MTU test completed [Tried,Actual] local->remote=[%d,%d] remote->local=[%d,%d]",
	       c->c2.max_send_size_local,
	       c->c2.max_recv_size_remote,
	       c->c2.max_send_size_remote,
	       c->c2.max_recv_size_local);
	  if (!c->options.fragment
	      && c->options.proto == PROTO_UDPv4
	      && c->c2.max_send_size_local > TUN_MTU_MIN
	      && (c->c2.max_recv_size_remote < c->c2.max_send_size_local
		  || c->c2.max_recv_size_local < c->c2.max_send_size_remote))
	    msg (M_INFO, "NOTE: This connection is unable to accomodate a UDP packet size of %d. Consider using --fragment or --mssfix options as a workaround.",
		 c->c2.max_send_size_local);
	}
      event_timeout_clear (&c->c2.occ_mtu_load_test_interval);
      break;

    case OCC_EXIT:
      dmsg (D_PACKET_CONTENT, "RECEIVED OCC_EXIT");
      c->sig->signal_received = SIGTERM;
      c->sig->signal_text = "remote-exit";
      break;
    }
  c->c2.buf.len = 0; /* don't pass packet on */
}
Esempio n. 20
0
/*
 * If (opt->flags & CO_USE_IV) is not NULL, we will read an IV from the packet.
 *
 * Set buf->len to 0 and return false on decrypt error.
 *
 * On success, buf is set to point to plaintext, true
 * is returned.
 */
bool
openvpn_decrypt (struct buffer *buf, struct buffer work,
		 const struct crypto_options *opt,
		 const struct frame* frame)
{
  static const char error_prefix[] = "Authenticate/Decrypt packet error";
  struct gc_arena gc;
  gc_init (&gc);

  if (buf->len > 0 && opt->key_ctx_bi)
    {
      struct key_ctx *ctx = &opt->key_ctx_bi->decrypt;
      struct packet_id_net pin;
      bool have_pin = false;

      /* Verify the HMAC */
      if (ctx->hmac)
	{
	  int hmac_len;
	  uint8_t local_hmac[MAX_HMAC_KEY_LENGTH]; /* HMAC of ciphertext computed locally */

	  hmac_ctx_reset(ctx->hmac);

	  /* Assume the length of the input HMAC */
	  hmac_len = hmac_ctx_size (ctx->hmac);

	  /* Authentication fails if insufficient data in packet for HMAC */
	  if (buf->len < hmac_len)
	    CRYPT_ERROR ("missing authentication info");

	  hmac_ctx_update (ctx->hmac, BPTR (buf) + hmac_len, BLEN (buf) - hmac_len);
	  hmac_ctx_final (ctx->hmac, local_hmac);

	  /* Compare locally computed HMAC with packet HMAC */
	  if (memcmp_constant_time (local_hmac, BPTR (buf), hmac_len))
	    CRYPT_ERROR ("packet HMAC authentication failed");

	  ASSERT (buf_advance (buf, hmac_len));
	}

      /* Decrypt packet ID + payload */

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

	  /* initialize work buffer with FRAME_HEADROOM bytes of prepend capacity */
	  ASSERT (buf_init (&work, FRAME_HEADROOM_ADJ (frame, FRAME_HEADROOM_MARKER_DECRYPT)));

	  /* use IV if user requested it */
	  CLEAR (iv_buf);
	  if (opt->flags & CO_USE_IV)
	    {
	      if (buf->len < iv_size)
		CRYPT_ERROR ("missing IV info");
	      memcpy (iv_buf, BPTR (buf), iv_size);
	      ASSERT (buf_advance (buf, iv_size));
	    }

	  /* show the IV's initial state */
	  if (opt->flags & CO_USE_IV)
	    dmsg (D_PACKET_CONTENT, "DECRYPT IV: %s", format_hex (iv_buf, iv_size, 0, &gc));

	  if (buf->len < 1)
	    CRYPT_ERROR ("missing payload");

	  /* ctx->cipher was already initialized with key & keylen */
	  if (!cipher_ctx_reset (ctx->cipher, iv_buf))
	    CRYPT_ERROR ("cipher init failed");

	  /* Buffer overflow check (should never happen) */
	  if (!buf_safe (&work, buf->len + cipher_ctx_block_size(ctx->cipher)))
	    CRYPT_ERROR ("potential buffer overflow");

	  /* Decrypt packet ID, payload */
	  if (!cipher_ctx_update (ctx->cipher, BPTR (&work), &outlen, BPTR (buf), BLEN (buf)))
	    CRYPT_ERROR ("cipher update failed");
	  ASSERT (buf_inc_len(&work, outlen));

	  /* Flush the decryption buffer */
	  if (!cipher_ctx_final (ctx->cipher, BPTR (&work) + outlen, &outlen))
	    CRYPT_ERROR ("cipher final failed");
	  ASSERT (buf_inc_len(&work, outlen));

	  dmsg (D_PACKET_CONTENT, "DECRYPT TO: %s",
	       format_hex (BPTR (&work), BLEN (&work), 80, &gc));

	  /* Get packet ID from plaintext buffer or IV, depending on cipher mode */
	  {
	    if (cipher_kt_mode_cbc(cipher_kt))
	      {
		if (opt->packet_id)
		  {
		    if (!packet_id_read (&pin, &work, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM)))
		      CRYPT_ERROR ("error reading CBC packet-id");
		    have_pin = true;
		  }
	      }
	    else if (cipher_kt_mode_ofb_cfb(cipher_kt))
	      {
		struct buffer b;

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

		buf_set_read (&b, iv_buf, iv_size);
		if (!packet_id_read (&pin, &b, true))
		  CRYPT_ERROR ("error reading CFB/OFB packet-id");
		have_pin = true;
	      }
	    else /* We only support CBC, CFB, or OFB modes right now */
	      {
		ASSERT (0);
	      }
	  }
	}
      else
	{
	  work = *buf;
	  if (opt->packet_id)
	    {
	      if (!packet_id_read (&pin, &work, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM)))
		CRYPT_ERROR ("error reading packet-id");
	      have_pin = !BOOL_CAST (opt->flags & CO_IGNORE_PACKET_ID);
	    }
	}
      
      if (have_pin)
	{
	  packet_id_reap_test (&opt->packet_id->rec);
	  if (packet_id_test (&opt->packet_id->rec, &pin))
	    {
	      packet_id_add (&opt->packet_id->rec, &pin);
	      if (opt->pid_persist && (opt->flags & CO_PACKET_ID_LONG_FORM))
		packet_id_persist_save_obj (opt->pid_persist, opt->packet_id);
	    }
	  else
	    {
	      if (!(opt->flags & CO_MUTE_REPLAY_WARNINGS))
	      msg (D_REPLAY_ERRORS, "%s: bad packet ID (may be a replay): %s -- see the man page entry for --no-replay and --replay-window for more info or silence this warning with --mute-replay-warnings",
		   error_prefix, packet_id_net_print (&pin, true, &gc));
	      goto error_exit;
	    }
	}
      *buf = work;
    }

  gc_free (&gc);
  return true;

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