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; } }
/* * 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; }
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; } } }
/* * 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); } } }
/* * 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 } }
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; }
/* * 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; } }
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); } }
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; }
/* 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; } }
/* * 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 } } }
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; } }
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; } }
/* * 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; }
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; }
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; }
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; }
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; }
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 */ }
/* * 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; }