void MatchGraph::UNPAIR (long oldbase, long oldmate) { long e, newbase, u; #ifdef DEBUG printf("Unpair oldbase, oldmate=%d %d\n",oldbase, oldmate); #endif UNLINK (oldbase); newbase = BMATE (oldmate); if (newbase != oldbase) { LINK [(int)oldbase] = -DUMMYEDGE; REMATCH (newbase, MATE[(int)oldbase]); if (f == LASTEDGE[1]) LINK[(int)secondmate] = -LASTEDGE[2]; else LINK[(int)secondmate] = -LASTEDGE[1]; } e = LINK[(int)oldmate]; u = BEND (OPPEDGE (e)); if (u == newbase) { POINTER (newbase, oldmate, e); return; } LINK[BMATE (u)] = -e; do { e = -LINK[(int)u]; v = BMATE (u); POINTER (u, v, -LINK[(int)v]); u = BEND (e); } while (u != newbase); e = OPPEDGE (e); POINTER (newbase, oldmate, e); }
static bool tls_crypt_v2_wrap_client_key(struct buffer *wkc, const struct key2 *src_key, const struct buffer *src_metadata, struct key_ctx *server_key, struct gc_arena *gc) { cipher_ctx_t *cipher_ctx = server_key->cipher; struct buffer work = alloc_buf_gc(TLS_CRYPT_V2_MAX_WKC_LEN + cipher_ctx_block_size(cipher_ctx), gc); /* Calculate auth tag and synthetic IV */ uint8_t *tag = buf_write_alloc(&work, TLS_CRYPT_TAG_SIZE); if (!tag) { msg(M_WARN, "ERROR: could not write tag"); return false; } uint16_t net_len = htons(sizeof(src_key->keys) + BLEN(src_metadata) + TLS_CRYPT_V2_TAG_SIZE + sizeof(uint16_t)); hmac_ctx_t *hmac_ctx = server_key->hmac; hmac_ctx_reset(hmac_ctx); hmac_ctx_update(hmac_ctx, (void *)&net_len, sizeof(net_len)); hmac_ctx_update(hmac_ctx, (void *)src_key->keys, sizeof(src_key->keys)); hmac_ctx_update(hmac_ctx, BPTR(src_metadata), BLEN(src_metadata)); hmac_ctx_final(hmac_ctx, tag); dmsg(D_CRYPTO_DEBUG, "TLS-CRYPT WRAP TAG: %s", format_hex(tag, TLS_CRYPT_TAG_SIZE, 0, gc)); /* Use the 128 most significant bits of the tag as IV */ ASSERT(cipher_ctx_reset(cipher_ctx, tag)); /* Overflow check (OpenSSL requires an extra block in the dst buffer) */ if (buf_forward_capacity(&work) < (sizeof(src_key->keys) + BLEN(src_metadata) + sizeof(net_len) + cipher_ctx_block_size(cipher_ctx))) { msg(M_WARN, "ERROR: could not crypt: insufficient space in dst"); return false; } /* Encrypt */ int outlen = 0; ASSERT(cipher_ctx_update(cipher_ctx, BEND(&work), &outlen, (void *)src_key->keys, sizeof(src_key->keys))); ASSERT(buf_inc_len(&work, outlen)); ASSERT(cipher_ctx_update(cipher_ctx, BEND(&work), &outlen, BPTR(src_metadata), BLEN(src_metadata))); ASSERT(buf_inc_len(&work, outlen)); ASSERT(cipher_ctx_final(cipher_ctx, BEND(&work), &outlen)); ASSERT(buf_inc_len(&work, outlen)); ASSERT(buf_write(&work, &net_len, sizeof(net_len))); return buf_copy(wkc, &work); }
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; } } }
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; } }
void MatchGraph::UNPAIR_ALL () { long u; for (v=1; v <= U; ++v) { if (BASE[(int)v] != v || LASTVTX[(int)v] == v) continue; nextu = v; NEXTVTX[(int)LASTVTX[(int)nextu]] = DUMMYVERTEX; while (1) { u = nextu; nextu = NEXTVTX[(int)nextu]; UNLINK (u); if (LASTVTX[(int)u] != u) { f = (LASTEDGE[2] == OPPEDGE(e)) ? LASTEDGE[1] : LASTEDGE[2]; NEXTVTX[(int)LASTVTX[(int)BEND(f)]] = u; } newbase = BMATE (BMATE(u)); if (newbase != DUMMYVERTEX && newbase != u) { LINK[(int)u] = -DUMMYEDGE; REMATCH (newbase, MATE[(int)u]); } while (LASTVTX[(int)nextu] == nextu && nextu != DUMMYVERTEX) nextu = NEXTVTX[(int)nextu]; if (LASTVTX[(int)nextu] == nextu && nextu == DUMMYVERTEX) break; } } }
void MatchGraph::SET_MATCH_BOUNDS () { long del; for (v=1; v <= U; ++v) { if (LINK[(int)v] < 0 || BASE[(int)v] != v) { NEXT_D[(int)v] = LAST_D; continue; } LINK[(int)v] = -LINK[(int)v]; i = v; while (i != DUMMYVERTEX) { Y[(int)i] -= DELTA; i = NEXTVTX[(int)i]; } f = MATE[(int)v]; if (f != DUMMYEDGE) { i = BEND(f); del = SLACK(f); while (i != DUMMYVERTEX) { Y[(int)i] -= del; i = NEXTVTX[(int)i]; } } NEXT_D[(int)v] = LAST_D; } }
void MatchGraph::REMATCH (long firstmate, long e) { #ifdef DEBUG printf("Rematch firstmate=%d e=%d-%d\n",firstmate, END[OPPEDGE(e)], END[e]); #endif MATE[(int)firstmate] = e; nexte = -LINK[(int)firstmate]; while (nexte != DUMMYEDGE) { e = nexte; f = OPPEDGE (e); firstmate = BEND (e); secondmate = BEND (f); nexte = -LINK[(int)firstmate]; LINK[(int)firstmate] = -MATE[(int)secondmate]; LINK[(int)secondmate] = -MATE[(int)firstmate]; MATE[(int)firstmate] = f; MATE[(int)secondmate] = e; } }
/* updateWts: * Iterate over edges in a cell, adjust weights as necessary. * It always updates the bent edges belonging to a cell. * A horizontal/vertical edge is updated only if the edge traversed * is bent, or if it is the traversed edge. */ void updateWts (sgraph* g, cell* cp, sedge* ep) { int i; sedge* e; int isBend = BEND(g,ep); int hsz = CHANSZ (cp->bb.UR.y - cp->bb.LL.y); int vsz = CHANSZ (cp->bb.UR.x - cp->bb.LL.x); int minsz = MIN(hsz, vsz); /* Bend edges are added first */ for (i = 0; i < cp->nedges; i++) { e = cp->edges[i]; if (!BEND(g,e)) break; updateWt (cp, e, minsz); } for (; i < cp->nedges; i++) { e = cp->edges[i]; if (isBend || (e == ep)) updateWt (cp, e, (HORZ(g,e)?hsz:vsz)); } }
bool buf_puts(struct buffer *buf, const char *str) { int ret = false; uint8_t *ptr = BEND (buf); int cap = buf_forward_capacity (buf); if (cap > 0) { strncpynt ((char *)ptr,str, cap); *(buf->data + buf->capacity - 1) = 0; /* windows vsnprintf needs this */ buf->len += (int) strlen ((char *)ptr); ret = true; } return ret; }
/* * printf append to a buffer with overflow check */ void buf_printf (struct buffer *buf, const char *format, ...) { if (buf_defined (buf)) { va_list arglist; uint8_t *ptr = BEND (buf); int cap = buf_forward_capacity (buf); if (cap > 0) { va_start (arglist, format); vsnprintf ((char *)ptr, cap, format, arglist); va_end (arglist); *(buf->data + buf->capacity - 1) = 0; /* windows vsnprintf needs this */ buf->len += (int) strlen ((char *)ptr); } } }
static void lz4_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 do_lz4_compress sets buf len to zero, just return */ if (buf->len == 0) { return; } /* did compression save us anything? */ { uint8_t comp_head_byte = NO_COMPRESS_BYTE_SWAP; if (compressed && work.len < buf->len) { *buf = work; comp_head_byte = LZ4_COMPRESS_BYTE; } { 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 = comp_head_byte; } } }
/* * printf append to a buffer with overflow check */ bool buf_printf (struct buffer *buf, const char *format, ...) { int ret = false; if (buf_defined (buf)) { va_list arglist; uint8_t *ptr = BEND (buf); int cap = buf_forward_capacity (buf); if (cap > 0) { int stat; va_start (arglist, format); stat = vsnprintf ((char *)ptr, cap, format, arglist); va_end (arglist); *(buf->data + buf->capacity - 1) = 0; /* windows vsnprintf needs this */ buf->len += (int) strlen ((char *)ptr); if (stat >= 0 && stat < cap) ret = true; } } return ret; }
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; } }
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_wrap(const struct buffer *src, struct buffer *dst, struct crypto_options *opt) { const struct key_ctx *ctx = &opt->key_ctx_bi.encrypt; struct gc_arena gc; /* IV, packet-ID and implicit IV required for this mode. */ ASSERT(ctx->cipher); ASSERT(ctx->hmac); ASSERT(packet_id_initialized(&opt->packet_id)); ASSERT(hmac_ctx_size(ctx->hmac) == 256/8); gc_init(&gc); dmsg(D_PACKET_CONTENT, "TLS-CRYPT WRAP FROM: %s", format_hex(BPTR(src), BLEN(src), 80, &gc)); /* Get packet ID */ if (!packet_id_write(&opt->packet_id.send, dst, true, false)) { msg(D_CRYPT_ERRORS, "TLS-CRYPT ERROR: packet ID roll over."); goto err; } dmsg(D_PACKET_CONTENT, "TLS-CRYPT WRAP AD: %s", format_hex(BPTR(dst), BLEN(dst), 0, &gc)); /* Buffer overflow check */ if (!buf_safe(dst, BLEN(src) + TLS_CRYPT_BLOCK_SIZE + TLS_CRYPT_TAG_SIZE)) { msg(D_CRYPT_ERRORS, "TLS-CRYPT WRAP: buffer size error, " "sc=%d so=%d sl=%d dc=%d do=%d dl=%d", src->capacity, src->offset, src->len, dst->capacity, dst->offset, dst->len); goto err; } /* Calculate auth tag and synthetic IV */ { uint8_t *tag = NULL; hmac_ctx_reset(ctx->hmac); hmac_ctx_update(ctx->hmac, BPTR(dst), BLEN(dst)); hmac_ctx_update(ctx->hmac, BPTR(src), BLEN(src)); ASSERT(tag = buf_write_alloc(dst, TLS_CRYPT_TAG_SIZE)); hmac_ctx_final(ctx->hmac, tag); dmsg(D_PACKET_CONTENT, "TLS-CRYPT WRAP TAG: %s", format_hex(tag, TLS_CRYPT_TAG_SIZE, 0, &gc)); /* Use the 128 most significant bits of the tag as IV */ ASSERT(cipher_ctx_reset(ctx->cipher, tag)); } /* Encrypt src */ { int outlen = 0; ASSERT(cipher_ctx_update(ctx->cipher, BEND(dst), &outlen, BPTR(src), BLEN(src))); ASSERT(buf_inc_len(dst, outlen)); ASSERT(cipher_ctx_final(ctx->cipher, BPTR(dst), &outlen)); ASSERT(buf_inc_len(dst, outlen)); } dmsg(D_PACKET_CONTENT, "TLS-CRYPT WRAP TO: %s", format_hex(BPTR(dst), BLEN(dst), 80, &gc)); gc_free(&gc); return true; err: crypto_clear_error(); dst->len = 0; gc_free(&gc); return false; }