📄 ssl.c
字号:
static inline intkey_state_read_ciphertext (struct tls_multi *multi, struct key_state *ks, struct buffer *buf, int maxlen){ return bio_read (multi, ks->ct_out, buf, maxlen, "tls_read_ciphertext");}/* * Initialize a key_state. Each key_state corresponds to * a specific SSL/TLS session. */static voidkey_state_init (struct tls_session *session, struct key_state *ks){ update_time (); /* * Build TLS object that reads/writes ciphertext * to/from memory BIOs. */ CLEAR (*ks); ks->ssl = SSL_new (session->opt->ssl_ctx); if (!ks->ssl) msg (M_SSLERR, "SSL_new failed"); /* put session * in ssl object so we can access it from verify callback*/ SSL_set_ex_data (ks->ssl, mydata_index, session); ks->ssl_bio = getbio (BIO_f_ssl (), "ssl_bio"); ks->ct_in = getbio (BIO_s_mem (), "ct_in"); ks->ct_out = getbio (BIO_s_mem (), "ct_out");#ifdef BIO_DEBUG bio_debug_oc ("open ssl_bio", ks->ssl_bio); bio_debug_oc ("open ct_in", ks->ct_in); bio_debug_oc ("open ct_out", ks->ct_out);#endif if (session->opt->server) SSL_set_accept_state (ks->ssl); else SSL_set_connect_state (ks->ssl); SSL_set_bio (ks->ssl, ks->ct_in, ks->ct_out); BIO_set_ssl (ks->ssl_bio, ks->ssl, BIO_NOCLOSE); /* Set control-channel initiation mode */ ks->initial_opcode = session->initial_opcode; session->initial_opcode = P_CONTROL_SOFT_RESET_V1; ks->state = S_INITIAL; ks->key_id = session->key_id; /* * key_id increments to KEY_ID_MASK then recycles back to 1. * This way you know that if key_id is 0, it is the first key. */ ++session->key_id; session->key_id &= P_KEY_ID_MASK; if (!session->key_id) session->key_id = 1; /* allocate key source material object */ ALLOC_OBJ_CLEAR (ks->key_src, struct key_source2); /* allocate reliability objects */ ALLOC_OBJ_CLEAR (ks->send_reliable, struct reliable); ALLOC_OBJ_CLEAR (ks->rec_reliable, struct reliable); ALLOC_OBJ_CLEAR (ks->rec_ack, struct reliable_ack); /* allocate buffers */ ks->plaintext_read_buf = alloc_buf (PLAINTEXT_BUFFER_SIZE); ks->plaintext_write_buf = alloc_buf (PLAINTEXT_BUFFER_SIZE); ks->ack_write_buf = alloc_buf (BUF_SIZE (&session->opt->frame)); reliable_init (ks->send_reliable, BUF_SIZE (&session->opt->frame), FRAME_HEADROOM (&session->opt->frame), TLS_RELIABLE_N_SEND_BUFFERS); reliable_init (ks->rec_reliable, BUF_SIZE (&session->opt->frame), FRAME_HEADROOM (&session->opt->frame), TLS_RELIABLE_N_REC_BUFFERS); reliable_set_timeout (ks->send_reliable, session->opt->packet_timeout); /* init packet ID tracker */ packet_id_init (&ks->packet_id, session->opt->replay_window, session->opt->replay_time);}static voidkey_state_free (struct key_state *ks, bool clear){ ks->state = S_UNDEF; if (ks->ssl) {#ifdef BIO_DEBUG bio_debug_oc ("close ssl_bio", ks->ssl_bio); bio_debug_oc ("close ct_in", ks->ct_in); bio_debug_oc ("close ct_out", ks->ct_out);#endif BIO_free_all(ks->ssl_bio); SSL_free (ks->ssl); } free_key_ctx_bi (&ks->key); free_buf (&ks->plaintext_read_buf); free_buf (&ks->plaintext_write_buf); free_buf (&ks->ack_write_buf); if (ks->send_reliable) { reliable_free (ks->send_reliable); free (ks->send_reliable); } if (ks->rec_reliable) { reliable_free (ks->rec_reliable); free (ks->rec_reliable); } if (ks->rec_ack) free (ks->rec_ack); if (ks->key_src) free (ks->key_src); packet_id_free (&ks->packet_id); if (clear) CLEAR (*ks);}/* * Must be called if we move a tls_session in memory. */static inline void tls_session_set_self_referential_pointers (struct tls_session* session) { session->tls_auth.packet_id = &session->tls_auth_pid;}/* * Initialize a TLS session. A TLS session normally has 2 key_state objects, * one for the current key, and one for the lame duck (i.e. retiring) key. */static voidtls_session_init (struct tls_multi *multi, struct tls_session *session){ struct gc_arena gc = gc_new (); msg (D_TLS_DEBUG, "TLS: tls_session_init: entry"); CLEAR (*session); /* Set options data to point to parent's option structure */ session->opt = &multi->opt; /* Randomize session # if it is 0 */ while (!session_id_defined(&session->session_id)) session_id_random (&session->session_id); /* Are we a TLS server or client? */ ASSERT (session->opt->key_method >= 1); if (session->opt->key_method == 1) { session->initial_opcode = session->opt->server ? P_CONTROL_HARD_RESET_SERVER_V1 : P_CONTROL_HARD_RESET_CLIENT_V1; } else /* session->opt->key_method >= 2 */ { session->initial_opcode = session->opt->server ? P_CONTROL_HARD_RESET_SERVER_V2 : P_CONTROL_HARD_RESET_CLIENT_V2; } /* Initialize control channel authentication parameters */ session->tls_auth = session->opt->tls_auth; /* Set session internal pointers (also called if session object is moved in memory) */ tls_session_set_self_referential_pointers (session); /* initialize packet ID replay window for --tls-auth */ packet_id_init (session->tls_auth.packet_id, session->opt->replay_window, session->opt->replay_time); /* load most recent packet-id to replay protect on --tls-auth */ packet_id_persist_load_obj (session->tls_auth.pid_persist, session->tls_auth.packet_id); key_state_init (session, &session->key[KS_PRIMARY]); msg (D_TLS_DEBUG, "TLS: tls_session_init: new session object, sid=%s", session_id_print (&session->session_id, &gc)); gc_free (&gc);}static voidtls_session_free (struct tls_session *session, bool clear){ int i; if (session->tls_auth.packet_id) packet_id_free (session->tls_auth.packet_id); for (i = 0; i < KS_SIZE; ++i) key_state_free (&session->key[i], false); if (session->common_name) free (session->common_name); if (clear) CLEAR (*session);}static voidmove_session (struct tls_multi* multi, int dest, int src, bool reinit_src){ msg (D_TLS_DEBUG_LOW, "TLS: move_session: dest=%s src=%s reinit_src=%d", session_index_name(dest), session_index_name(src), reinit_src); ASSERT (src != dest); ASSERT (src >= 0 && src < TM_SIZE); ASSERT (dest >= 0 && dest < TM_SIZE); tls_session_free (&multi->session[dest], false); multi->session[dest] = multi->session[src]; tls_session_set_self_referential_pointers (&multi->session[dest]); if (reinit_src) tls_session_init (multi, &multi->session[src]); else CLEAR (multi->session[src]); msg (D_TLS_DEBUG, "TLS: move_session: exit");}static voidreset_session (struct tls_multi *multi, struct tls_session *session){ tls_session_free (session, false); tls_session_init (multi, session);}#if 0/* * Transmit a TLS reset on our untrusted channel. */static voidinitiate_untrusted_session (struct tls_multi *multi, struct sockaddr_in *to){ struct tls_session *session = &multi->session[TM_UNTRUSTED]; struct key_state *ks = &session->key[KS_PRIMARY]; reset_session (multi, session); ks->remote_addr = *to; msg (D_TLS_DEBUG_LOW, "TLS: initiate_untrusted_session: addr=%s", print_sockaddr (to));}#endif/* * Used to determine in how many seconds we should be * called again. */static inline voidcompute_earliest_wakeup (interval_t *earliest, interval_t seconds_from_now) { if (seconds_from_now < *earliest) *earliest = seconds_from_now; if (*earliest < 0) *earliest = 0;}/* * Return true if "lame duck" or retiring key has expired and can * no longer be used. */static inline boollame_duck_must_die (const struct tls_session* session, interval_t *wakeup){ const struct key_state* lame = &session->key[KS_LAME_DUCK]; if (lame->state >= S_INITIAL) { const time_t local_now = now; ASSERT (lame->must_die); /* a lame duck key must always have an expiration */ if (local_now < lame->must_die) { compute_earliest_wakeup (wakeup, lame->must_die - local_now); return false; } else return true; } else if (lame->state == S_ERROR) return true; else return false;}/* * A tls_multi object fully encapsulates OpenVPN's TLS state. * See ssl.h for more comments. */struct tls_multi *tls_multi_init (struct tls_options *tls_options){ struct tls_multi *ret; ALLOC_OBJ_CLEAR (ret, struct tls_multi); /* get command line derived options */ ret->opt = *tls_options; /* set up pointer to HMAC object for TLS packet authentication */ ret->opt.tls_auth.key_ctx_bi = &ret->opt.tls_auth_key; /* set up list of keys to be scanned by data channel encrypt and decrypt routines */ ASSERT (SIZE (ret->key_scan) == 3); ret->key_scan[0] = &ret->session[TM_ACTIVE].key[KS_PRIMARY]; ret->key_scan[1] = &ret->session[TM_ACTIVE].key[KS_LAME_DUCK]; ret->key_scan[2] = &ret->session[TM_LAME_DUCK].key[KS_LAME_DUCK]; return ret;}/* * Finalize our computation of frame sizes. */voidtls_multi_init_finalize (struct tls_multi* multi, const struct frame* frame){ tls_init_control_channel_frame_parameters (frame, &multi->opt.frame); /* initialize the active and untrusted sessions */ tls_session_init (multi, &multi->session[TM_ACTIVE]); if (!multi->opt.single_session) tls_session_init (multi, &multi->session[TM_UNTRUSTED]);}/* * Initialize and finalize a standalone tls-auth verification object. */struct tls_auth_standalone *tls_auth_standalone_init (struct tls_options *tls_options, struct gc_arena *gc){ struct tls_auth_standalone *tas; ALLOC_OBJ_CLEAR_GC (tas, struct tls_auth_standalone, gc); /* set up pointer to HMAC object for TLS packet authentication */ tas->tls_auth_key = tls_options->tls_auth_key; tas->tls_auth_options.key_ctx_bi = &tas->tls_auth_key; tas->tls_auth_options.packet_id_long_form = true; /* get initial frame parms, still need to finalize */ tas->frame = tls_options->frame; return tas;}voidtls_auth_standalone_finalize (struct tls_auth_standalone *tas, const struct frame *frame){ tls_init_control_channel_frame_parameters (frame, &tas->frame);}/* * Set local and remote option compatibility strings. * Used to verify compatibility of local and remote option * sets. */voidtls_multi_init_set_options (struct tls_multi* multi, const char *local, const char *remote){ /* initialize options string */ multi->opt.local_options = local; multi->opt.remote_options = remote;}voidtls_multi_free (struct tls_multi *multi, bool clear){ int i; ASSERT (multi); for (i = 0; i < TM_SIZE; ++i) tls_session_free (&multi->session[i], false); if (clear) CLEAR (*multi); free(multi);}/* * Move a packet authentication HMAC + related fields to or from the front * of the buffer so it can be processed by encrypt/decrypt. *//* * Dependent on hmac size, opcode size, and session_id size. * Will assert if too small. */#define SWAP_BUF_SIZE 256static boolswap_hmac (struct buffer *buf, const struct crypto_options *co, bool incoming){ struct key_ctx *ctx; ASSERT (co); ctx = (incoming ? &co->key_ctx_bi->decrypt : &co->key_ctx_bi->encrypt); ASSERT (ctx->hmac); { /* hmac + packet_id (8 bytes) */ const int hmac_size = HMAC_size (ctx->hmac) + packet_id_size (true); /* opcode + session_id */ const int osid_size = 1 + SID_SIZE; int e1, e2; uint8_t *b = BPTR (buf); uint8_t buf1[SWAP_BUF_SIZE]; uint8_t buf2[SWAP_BUF_SIZE]; if (incoming) { e1 = osid_size; e2 = hmac_size; } else { e1 = hmac_size; e2 = osid_size; } ASSERT (e1 <= SWAP_BUF_SIZE && e2 <= SWAP_BUF_SIZE); if (buf->len >= e1 + e2) { memcpy (buf1, b, e1); memcpy (buf2, b + e1, e2); memcpy (b, buf2, e2); memcpy (b + e2, buf1, e1); return true; } else return false; }}#undef SWAP_BUF_SIZE/* * Write a control channel authentication record. */static voidwrite_control_auth (struct tls_session *session, struct key_state *ks, struct buffer *buf, struct sockaddr_in *to_link_addr, int opcode, int max_ack, bool prepend_ack){ uint8_t *header; struct buffer null = clear_buf (); ASSERT (addr_defined (&ks->remote_addr)); ASSERT (reliable_ack_write (ks->rec_ack, buf, &ks->session_id_remote, max_ack, prepend_ack)); ASSERT (session_id_write_prepend (&session->session_id, buf)); ASSERT (header = buf_prepend (buf, 1)); *header = ks->key_id | (opcode << P_OPCODE_SHIFT); if (session->tls_auth.key_ctx_bi->encrypt.hmac) { /* no encryption, only write hmac */ openvpn_encrypt (buf, null, &session->tls_auth, NULL); ASSERT (swap_hmac (buf, &session->tls_auth, false)); } *to_link_addr = ks->remote_addr;}/* * Read a control channel authentication record. */static boolread_control_auth (struct buffer *buf, const struct crypto_options *co, const struct sockaddr_in *from){ struct gc_arena gc = gc_new (); if (co->key_ctx_bi->decrypt.hmac) { struct buffer null = clear_buf (); /* move the hmac record to the front of the packet */ if (!swap_hmac (buf, co, true)) { msg (D_TLS_ERRORS, "TLS Error: cannot locate HMAC in incoming packet from %s", print_sockaddr (from, &gc)); gc_free (&gc); return false; } /* authenticate only (no decrypt) and remove the hmac record from the head of the buffer */ openvpn_decrypt (buf, null, co, NULL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -