static bool remove_env_item(const char *str, const bool do_free, struct env_item **list) { struct env_item *current, *prev; ASSERT(str); ASSERT(list); for (current = *list, prev = NULL; current != NULL; current = current->next) { if (env_string_equal(current->string, str)) { if (prev) { prev->next = current->next; } else { *list = current->next; } if (do_free) { secure_memzero(current->string, strlen(current->string)); free(current->string); free(current); } return true; } prev = current; } return false; }
void * xalloc (size_t size) { void * ptr; ptr = (void *) malloc (size); if (ptr == NULL) die (1, "No more memory."); secure_memzero ((char *) ptr, size); return ptr; }
void purge_user_pass(struct user_pass *up, const bool force) { const bool nocache = up->nocache; static bool warn_shown = false; if (nocache || force) { secure_memzero(up, sizeof(*up)); up->nocache = nocache; } /* * don't show warning if the pass has been replaced by a token: this is an * artificial "auth-nocache" */ else if (!warn_shown && (!up->tokenized)) { msg(M_WARN, "WARNING: this configuration may cache passwords in memory -- use the auth-nocache option to prevent this"); warn_shown = true; } }
void tls_crypt_v2_init_server_key(struct key_ctx *key_ctx, bool encrypt, const char *key_file, const char *key_inline) { struct key srv_key; struct buffer srv_key_buf; buf_set_write(&srv_key_buf, (void *)&srv_key, sizeof(srv_key)); if (!read_pem_key_file(&srv_key_buf, tls_crypt_v2_srv_pem_name, key_file, key_inline)) { msg(M_FATAL, "ERROR: invalid tls-crypt-v2 server key format"); } struct key_type kt = tls_crypt_kt(); if (!kt.cipher || !kt.digest) { msg(M_FATAL, "ERROR: --tls-crypt-v2 not supported"); } init_key_ctx(key_ctx, &srv_key, &kt, encrypt, "tls-crypt-v2 server key"); secure_memzero(&srv_key, sizeof(srv_key)); }
void tls_crypt_v2_init_client_key(struct key_ctx_bi *key, struct buffer *wkc_buf, const char *key_file, const char *key_inline) { struct buffer client_key = alloc_buf(TLS_CRYPT_V2_CLIENT_KEY_LEN + TLS_CRYPT_V2_MAX_WKC_LEN); if (!read_pem_key_file(&client_key, tls_crypt_v2_cli_pem_name, key_file, key_inline)) { msg(M_FATAL, "ERROR: invalid tls-crypt-v2 client key format"); } struct key2 key2; if (!buf_read(&client_key, &key2.keys, sizeof(key2.keys))) { msg(M_FATAL, "ERROR: not enough data in tls-crypt-v2 client key"); } tls_crypt_v2_load_client_key(key, &key2, false); secure_memzero(&key2, sizeof(key2)); *wkc_buf = client_key; }
void tls_crypt_v2_write_client_key_file(const char *filename, const char *b64_metadata, const char *server_key_file, const char *server_key_inline) { struct gc_arena gc = gc_new(); struct key_ctx server_key = { 0 }; struct buffer client_key_pem = { 0 }; struct buffer dst = alloc_buf_gc(TLS_CRYPT_V2_CLIENT_KEY_LEN + TLS_CRYPT_V2_MAX_WKC_LEN, &gc); struct key2 client_key = { 2 }; if (!rand_bytes((void *)client_key.keys, sizeof(client_key.keys))) { msg(M_FATAL, "ERROR: could not generate random key"); goto cleanup; } ASSERT(buf_write(&dst, client_key.keys, sizeof(client_key.keys))); struct buffer metadata = alloc_buf_gc(TLS_CRYPT_V2_MAX_METADATA_LEN, &gc); if (b64_metadata) { if (TLS_CRYPT_V2_MAX_B64_METADATA_LEN < strlen(b64_metadata)) { msg(M_FATAL, "ERROR: metadata too long (%d bytes, max %u bytes)", (int)strlen(b64_metadata), TLS_CRYPT_V2_MAX_B64_METADATA_LEN); } ASSERT(buf_write(&metadata, &TLS_CRYPT_METADATA_TYPE_USER, 1)); int decoded_len = openvpn_base64_decode(b64_metadata, BPTR(&metadata), BCAP(&metadata)); if (decoded_len < 0) { msg(M_FATAL, "ERROR: failed to base64 decode provided metadata"); goto cleanup; } ASSERT(buf_inc_len(&metadata, decoded_len)); } else { int64_t timestamp = htonll((uint64_t)now); ASSERT(buf_write(&metadata, &TLS_CRYPT_METADATA_TYPE_TIMESTAMP, 1)); ASSERT(buf_write(&metadata, ×tamp, sizeof(timestamp))); } tls_crypt_v2_init_server_key(&server_key, true, server_key_file, server_key_inline); if (!tls_crypt_v2_wrap_client_key(&dst, &client_key, &metadata, &server_key, &gc)) { msg(M_FATAL, "ERROR: could not wrap generated client key"); goto cleanup; } /* PEM-encode Kc || WKc */ if (!crypto_pem_encode(tls_crypt_v2_cli_pem_name, &client_key_pem, &dst, &gc)) { msg(M_FATAL, "ERROR: could not PEM-encode client key"); goto cleanup; } if (!buffer_write_file(filename, &client_key_pem)) { msg(M_FATAL, "ERROR: could not write client key file"); goto cleanup; } /* Sanity check: load client key (as "client") */ struct key_ctx_bi test_client_key; struct buffer test_wrapped_client_key; msg(D_GENKEY, "Testing client-side key loading..."); tls_crypt_v2_init_client_key(&test_client_key, &test_wrapped_client_key, filename, NULL); free_key_ctx_bi(&test_client_key); /* Sanity check: unwrap and load client key (as "server") */ struct buffer test_metadata = alloc_buf_gc(TLS_CRYPT_V2_MAX_METADATA_LEN, &gc); struct key2 test_client_key2 = { 0 }; free_key_ctx(&server_key); tls_crypt_v2_init_server_key(&server_key, false, server_key_file, server_key_inline); msg(D_GENKEY, "Testing server-side key loading..."); ASSERT(tls_crypt_v2_unwrap_client_key(&test_client_key2, &test_metadata, test_wrapped_client_key, &server_key)); secure_memzero(&test_client_key2, sizeof(test_client_key2)); free_buf(&test_wrapped_client_key); cleanup: secure_memzero(&client_key, sizeof(client_key)); free_key_ctx(&server_key); buf_clear(&client_key_pem); buf_clear(&dst); gc_free(&gc); }
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; }
/** Frees the cipher state */ static void salsa20_free(fastd_cipher_state_t *state) { if (state) { secure_memzero(state, sizeof(*state)); free(state); } }
/** Frees the state used by this GHASH implementation */ void fastd_ghash_pclmulqdq_free(fastd_mac_state_t *state) { if (state) { secure_memzero(state, sizeof(*state)); free(state); } }