/* allocate a buffer for socket or tun layer */ void alloc_buf_sock_tun (struct buffer *buf, const struct frame *frame, const bool tuntap_buffer, const unsigned int align_mask) { /* allocate buffer for overlapped I/O */ *buf = alloc_buf (BUF_SIZE (frame)); ASSERT (buf_init (buf, FRAME_HEADROOM_ADJ (frame, align_mask))); buf->len = tuntap_buffer ? MAX_RW_SIZE_TUN (frame) : MAX_RW_SIZE_LINK (frame); ASSERT (buf_safe (buf, 0)); }
void read_incoming_link (struct context *c) { /* * Set up for recvfrom call to read datagram * sent to our TCP/UDP port. */ int status; /*ASSERT (!c->c2.to_tun.len);*/ perf_push (PERF_READ_IN_LINK); c->c2.buf = c->c2.buffers->read_link_buf; ASSERT (buf_init (&c->c2.buf, FRAME_HEADROOM_ADJ (&c->c2.frame, FRAME_HEADROOM_MARKER_READ_LINK))); status = link_socket_read (c->c2.link_socket, &c->c2.buf, MAX_RW_SIZE_LINK (&c->c2.frame), &c->c2.from); if (socket_connection_reset (c->c2.link_socket, status)) { #if PORT_SHARE if (port_share && socket_foreign_protocol_detected (c->c2.link_socket)) { const struct buffer *fbuf = socket_foreign_protocol_head (c->c2.link_socket); const int sd = socket_foreign_protocol_sd (c->c2.link_socket); port_share_redirect (port_share, fbuf, sd); register_signal (c, SIGTERM, "port-share-redirect"); } else #endif { /* received a disconnect from a connection-oriented protocol */ if (c->options.inetd) { register_signal (c, SIGTERM, "connection-reset-inetd"); msg (D_STREAM_ERRORS, "Connection reset, inetd/xinetd exit [%d]", status); } else { #ifdef ENABLE_OCC if (event_timeout_defined(&c->c2.explicit_exit_notification_interval)) { msg (D_STREAM_ERRORS, "Connection reset during exit notification period, ignoring [%d]", status); openvpn_sleep(1); } else #endif { register_signal (c, SIGUSR1, "connection-reset"); /* SOFT-SIGUSR1 -- TCP connection reset */ msg (D_STREAM_ERRORS, "Connection reset, restarting [%d]", status); } } } perf_pop (); return; } /* check recvfrom status */ check_status (status, "read", c->c2.link_socket, NULL); #ifdef ENABLE_SOCKS /* Remove socks header if applicable */ socks_postprocess_incoming_link (c); #endif perf_pop (); }
/* * 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; }