?? ssl.c
字號:
/* * 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 udp_socket *udp_socket){ struct tls_multi *ret; ret = (struct tls_multi *) malloc (sizeof (struct tls_multi)); ASSERT (ret); CLEAR (*ret); /* 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]); tls_session_init (multi, &multi->session[TM_UNTRUSTED]);}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/* * A simple traffic shaper for the control channel, to prevent * it from hogging the bandwidth during key exchanges. * * Return true if okay to send. * If not, return false and set *wakeup. * * Never limit the rate unless we have an active lame duck key * which will not be expiring any time soon. */static bool transmit_rate_limiter(struct tls_session* session, time_t* wakeup, time_t current){ const struct key_state *lame = &session->key[KS_LAME_DUCK]; const struct key_state *pri = &session->key[KS_PRIMARY]; /* transmit one packet every freq seconds */ const int freq = 2; /* rough estimate of how many bytes still to transmit */ const int estimated_bytes = 20000; /* worst-case estimated finish at this rate */ time_t finish = current + ((freq * estimated_bytes) / MTU_SIZE (&session->opt->frame)); if (check_debug_level (D_TLS_DEBUG)) { if (lame->must_die) msg (D_TLS_DEBUG, "TLS XMIT FINISH ESTIMATE = lame->must_die %d seconds", lame->must_die - finish); if (pri->must_negotiate) msg (D_TLS_DEBUG, "TLS XMIT FINISH ESTIMATE = pri->must_negotiate %d seconds", pri->must_negotiate - finish); } if (freq && lame->state == S_ACTIVE && finish < lame->must_die && finish < pri->must_negotiate) { if (current >= session->limit_next) { session->limit_next = current + freq; return true; } else { compute_earliest_wakeup (wakeup, session->limit_next - current); return false; } } return true;}/* * 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_udp_addr, int opcode, int max_ack, bool prepend_ack, time_t current){ 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, current); ASSERT (swap_hmac (buf, &session->tls_auth, false)); } *to_udp_addr = ks->remote_addr;}/* * Read a control channel authentication record. */static boolread_control_auth (struct buffer *buf, struct crypto_options *co, struct sockaddr_in *from, time_t current){ 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)); return false; } /* authenticate only (no decrypt) and remove the hmac record from the head of the buffer */ openvpn_decrypt (buf, null, co, NULL, current); if (!buf->len) { msg (D_TLS_ERRORS, "TLS Error: incoming packet authentication failed from %s", print_sockaddr (from)); return false; } } /* advance buffer pointer past opcode & session_id since our caller already read it */ buf_advance (buf, SID_SIZE + 1); return true;}/* * Macros for key_state_soft_reset & tls_process */#define ks (&session->key[KS_PRIMARY]) /* primary key */#define ks_lame (&session->key[KS_LAME_DUCK]) /* retiring key *//* true if no in/out acknowledgements pending */#define FULL_SYNC \ (reliable_empty(&ks->send_reliable) && reliable_ack_empty(&ks->rec_ack))/* * Move the active key to the lame duck key and reinitialize the * active key. */static voidkey_state_soft_reset (struct tls_session *session, time_t current){ ks->must_die = current + session->opt->transition_window; /* remaining lifetime of old key */ key_state_free (ks_lame, false); *ks_lame = *ks; key_state_init (session, ks, current); ks->session_id_remote = ks_lame->session_id_remote; ks->remote_addr = ks_lame->remote_addr;}/* * This is the primary routine for processing TLS stuff inside the * the main event loop (see openvpn.c). When this routine exits * with non-error status, it will set *wakeup to the number of seconds * when it wants to be called again, or 0 if it doesn't care. * * Return value is true if we have placed a packet in *to_udp which we * want to send to our peer. */static booltls_process (struct tls_multi *multi, struct tls_session *session, struct buffer *to_udp, struct sockaddr_in *to_udp_addr, struct udp_socket *to_udp_socket, time_t * wakeup, time_t current){ struct buffer *buf; bool state_change = false; bool generated_output = false; /* Make sure we were initialized and that we're not in an error state */ ASSERT (ks->state != S_UNDEF); ASSERT (ks->state != S_ERROR); ASSERT (session_id_defined (&session->session_id)); /* Should we trigger a soft reset? -- new key, keeps old key for a while */ if (ks->state == S_ACTIVE && ((session->opt->renegotiate_seconds && current >= ks->established + session->opt->renegotiate_seconds) || (session->opt->renegotiate_bytes && ks->n_bytes >= session->opt->renegotiate_bytes) || (session->opt->renegotiate_packets && ks->n_packets >= session->opt->renegotiate_packets) || (packet_id_close_to_wrapping (&ks->packet_id.send)))) { msg (D_TLS_DEBUG_LOW, "tls_process: soft reset sec=%d bytes=%d/%d pkts=%d/%d", (int) ks->established + session->opt->renegotiate_seconds - current, ks->n_bytes, session->opt->renegotiate_bytes, ks->n_packets, session->opt->renegotiate_packets); key_state_soft_reset (session, current); } /* Kill lame duck key transition_window seconds after primary key negotiation */ if (lame_duck_must_die (session, wakeup, current)) { key_state_free (ks_lame, true); msg (D_TLS_DEBUG_LOW, "tls_process: killed expiring key"); } mutex_cycle (L_TLS); do { current = time (NULL); msg (D_TLS_DEBUG, "tls_process: chg=%d ks=%s lame=%s", state_change, state_name (ks->state), state_name (ks_lame->state)); state_change = false; /* * TLS activity is finished once we get to S_ACTIVE, * though we will still process acknowledgements. */ if (ks->state < S_ACTIVE) { /* Initial handshake */ if (ks->state == S_INITIAL) { buf = reliable_get_buf (&ks->send_reliable); if (buf) { ks->must_negotiate = current + session->opt->handshake_window; /* null buffer */ reliable_mark_active_outgoing (&ks->send_reliable, buf, ks->initial_opcode); ks->state = S_PRE_START; state_change = true; msg (D_TLS_DEBUG, "Initial Handshake, sid=%s", session_id_print (&session->session_id)); } } /* Are we timed out on receive? */ if (current >= ks->must_negotiate) { msg (D_TLS_ERRORS, "TLS Error: TLS key negotiation failed to occur within %d seconds", session->opt->handshake_window); goto error; } /* Wait for Initial Handshake ACK */ if (ks->state == S_PRE_START && FULL_SYNC) { ks->state = S_START; state_change = true; msg (D_TLS_DEBUG, "Transitioned to S_START"); } /* Wait for ACK */ if (((ks->state == S_GOT_KEY && !session->opt->server) || (ks->state == S_SENT_KEY && session->opt->server))) { if (FULL_SYNC) { ks->established = current; msg (D_TLS_DEBUG, "Transition to S_ACTIVE"); if (check_debug_level (D_HANDSHAKE)) print_details (ks->ssl, "Control Channel:"); state_change = true; ks->state = S_ACTIVE; /* Set outgoing address for data channel packets */ udp_socket_set_outgoing_addr (NULL, to_udp_socket, &ks->remote_addr); } } /* Reliable buffer to outgoing UDP (send up to CONTROL_SEND_ACK_MAX ACKs for previously received packets) */ if (!to_udp->len && reliable_can_send (&ks->send_reliable, current)) { if (transmit_rate_limiter(session, wakeup, current)) { int opcode; struct buffer b; buf = reliable_send (&ks->send_reliable, &opcode, current); ASSERT (buf); b = *buf; write_control_auth (session, ks, &b, to_udp_addr, opcode, CONTROL_SEND_ACK_MAX, true, current); *to_udp = b; generated_output = true; state_change = true; msg (D_TLS_DEBUG, "Reliable -> UDP"); break; } } /* Send 1 or more ACKs (each received control packet gets one ACK) */ if (!to_udp->len && !reliable_ack_empty (&ks->rec_ack)) { buf = &ks->ack_write_buf; ASSERT (buf_init (buf, EXTRA_FRAME (&multi->opt.frame))); write_control_auth (session, ks, buf, to_udp_addr, P_ACK_V1, RELIABLE_ACK_SIZE, false, current); *to_udp = *buf; generated_output = true; state_change = true; msg (D_TLS_DEBUG, "Dedicated ACK -> UDP"); break; } /* Write incoming ciphertext to TLS object */ buf = reliable_get_buf_sequenced (&ks->rec_reliable); if (buf) { int status = 0; if (buf->len) { status = key_state_write_ciphertext (ks, buf); if (status == -1) { msg (D_TLS_ERRORS, "TLS Error: Incoming Ciphertext -> TLS object write error"); goto error; } } else { status = 1; } if (status == 1) { reliable_mark_deleted (&ks->rec_reliable, buf, true); state_change = true; msg (D_TLS_DEBUG, "Incoming Ciphertext -> TLS"); } } /* Read incoming plaintext from TLS object */ buf = &ks->plaintext_read_buf; if (!buf->len) { int status; ASSERT (buf_init (buf, EXTRA_FRAME (&multi->opt.frame))); status = key_state_read_plaintext (ks, buf, MTU_SIZE (&multi->opt.frame)); current = time (NULL); if (status == -1) { msg (D_TLS_ERRORS, "TLS Error: TLS object -> incoming plaintext read error"); goto error; } if (status == 1) { state_change = true; msg (D_TLS_DEBUG, "TLS -> Incoming Plaintext"); } } /* Send Key */ buf = &ks->plaintext_write_buf; if (!buf->len && ((ks->state == S_START && !session->opt->server) || (ks->state == S_GOT_KEY && session->opt->server))) { struct key key; ASSERT (buf_init (buf, EXTRA_FRAME (&multi->opt.frame))); generate_key_random (&key, &session->opt->key_type); if (!check_key (&key, &session->opt->key_type)) { msg (D_TLS_ERRORS, "TLS Error: Bad encrypting key generated"); goto error; } write_key (&key, &session->opt->key_type, buf); init_key_ctx (&ks->key.encrypt, &key, &session->opt->key_type, DO_ENCRYPT, "Data Channel Encrypt"); CLEAR (key); ASSERT (buf_write (buf, session->opt->options, strlen (session->opt->options) + 1)); state_change = true; msg (D_TLS_DEBUG, "Send Key"); ks->state = S_SENT_KEY; }
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -