?? ssl.c
字號:
/* Recieve Key */ buf = &ks->plaintext_read_buf; if (buf->len && ((ks->state == S_SENT_KEY && !session->opt->server) || (ks->state == S_START && session->opt->server))) { int status; struct key key; status = read_key (&key, &session->opt->key_type, buf); if (status == -1) { msg (D_TLS_ERRORS, "TLS Error: Error reading data channel key from plaintext buffer"); goto error; } if (!check_key (&key, &session->opt->key_type)) { msg (D_TLS_ERRORS, "TLS Error: Bad decrypting key received from peer"); goto error; } ASSERT (buf->len > 0); if (!session->opt->disable_occ && strncmp (BPTR (buf), session->opt->options, buf->len)) { msg (D_TLS_ERRORS, "TLS Error: Local ('%s') and Remote ('%s') options are incompatible", session->opt->options, BPTR (buf)); status = 0; } buf_clear (buf); if (status == 1) { init_key_ctx (&ks->key.decrypt, &key, &session->opt->key_type, DO_DECRYPT, "Data Channel Decrypt"); } CLEAR (key); if (status == 0) goto error; state_change = true; msg (D_TLS_DEBUG, "Rec Key"); ks->state = S_GOT_KEY; } /* Write outgoing plaintext to TLS object */ buf = &ks->plaintext_write_buf; if (buf->len) { int status = key_state_write_plaintext (ks, buf); if (status == -1) { msg (D_TLS_ERRORS, "TLS ERROR: Outgoing Plaintext -> TLS object write error"); goto error; } if (status == 1) { state_change = true; msg (D_TLS_DEBUG, "Outgoing Plaintext -> TLS"); } } /* Outgoing Ciphertext to reliable buffer */ if (ks->state >= S_START) { buf = reliable_get_buf (&ks->send_reliable); if (buf) { int status = key_state_read_ciphertext (ks, buf, MTU_SIZE (&multi->opt.frame)); if (status == -1) { msg (D_TLS_ERRORS, "TLS Error: Ciphertext -> reliable UDP transport read error"); goto error; } if (status == 1) { reliable_mark_active_outgoing (&ks->send_reliable, buf, P_CONTROL_V1); state_change = true; msg (D_TLS_DEBUG, "Outgoing Ciphertext -> Reliable"); } } } } else /* state is ACTIVE */ { /* 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, "Post-Active Dedicated ACK -> UDP"); break; } } mutex_cycle (L_TLS); } while (state_change); current = time (NULL); /* When should we wake up again? */ { if (ks->state >= S_INITIAL && ks->state < S_ACTIVE) { compute_earliest_wakeup (wakeup, reliable_send_timeout (&ks->send_reliable, current)); if (ks->must_negotiate) compute_earliest_wakeup (wakeup, ks->must_negotiate - current); } if (ks->established && session->opt->renegotiate_seconds) compute_earliest_wakeup (wakeup, ks->established + session->opt->renegotiate_seconds - current); if (*wakeup) msg (D_TLS_DEBUG, "tls_process: timeout set to %d", *wakeup); return generated_output; }error: ks->state = S_ERROR; msg (D_TLS_ERRORS, "TLS Error: TLS handshake failed"); return false;}#undef ks#undef ks_lame/* * Called at the top of the event loop in openvpn.c. * * Basically decides if we should call tls_process for * the active or untrusted sessions. */booltls_multi_process (struct tls_multi *multi, struct buffer *to_udp, struct sockaddr_in *to_udp_addr, struct udp_socket *to_udp_socket, time_t * wakeup, time_t current){ int i; bool generated_output = false; mutex_lock (L_TLS); /* * Process each session object having state of S_INITIAL or greater, * and which has a defined remote IP addr. */ for (i = 0; i < TM_SIZE; ++i) { struct tls_session *session = &multi->session[i]; struct key_state *ks = &session->key[KS_PRIMARY]; struct key_state *ks_lame = &session->key[KS_LAME_DUCK]; /* set initial remote address */ if (i == TM_ACTIVE && ks->state == S_INITIAL && addr_defined (&to_udp_socket->addr->actual)) ks->remote_addr = to_udp_socket->addr->actual; msg (D_TLS_DEBUG, "tls_multi_process: i=%d state=%s, mysid=%s, stored-sid=%s, stored-ip=%s", i, state_name (ks->state), session_id_print (&session->session_id), session_id_print (&ks->session_id_remote), print_sockaddr (&ks->remote_addr)); if (ks->state >= S_INITIAL && addr_defined (&ks->remote_addr)) { current = time (NULL); if (tls_process (multi, session, to_udp, to_udp_addr, to_udp_socket, wakeup, current)) generated_output = true; /* * If tls_process hits an error: * (1) If the session has an unexpired lame duck key, preserve it. * (2) Reinitialize the session. */ if (ks->state == S_ERROR) { if (i == TM_ACTIVE && ks_lame->state == S_ACTIVE) move_session(multi, TM_LAME_DUCK, TM_ACTIVE, true); else reset_session (multi, session); } } mutex_cycle (L_TLS); } current = time (NULL); /* * If lame duck session expires, kill it. */ if (lame_duck_must_die (&multi->session[TM_LAME_DUCK], wakeup, current)) { tls_session_free(&multi->session[TM_LAME_DUCK], true); msg (D_TLS_DEBUG_LOW, "tls_multi_process: killed expiring key"); } /* * If untrusted session achieves TLS authentication, * move it to active session, usurping any prior session. */ if (DECRYPT_KEY_ENABLED (multi, &multi->session[TM_UNTRUSTED].key[KS_PRIMARY])) { move_session(multi, TM_ACTIVE, TM_UNTRUSTED, true); msg (D_TLS_DEBUG_LOW, "tls_multi_process: untrusted session promoted to trusted"); } mutex_unlock (L_TLS); return generated_output;}/* * When OpenVPN is built in pthread-mode, thread_func * will periodically call tls_multi_process. */#ifdef USE_PTHREAD/* * Main thread <-> TLS thread communication * errors are fatal if they are of these types. */static inline boollocal_sock_fatal (){ return errno == ENOTCONN || errno == ECONNREFUSED;}/* * This routine is the TLS work thread. */static void *thread_func (void *arg){ const int gc_level = gc_new_level (); const struct thread_parms parm = *(struct thread_parms*) arg; fd_set reads; time_t current; bool fatal;#if 0 /* * Under Linux, Posix threads appear to inherit mlockall state * from parent. This is good news, since mlockall will fail * if we restart after having downgraded privileges with * --user or group. */ if (parm.mlock) /* should we disable paging? */ do_mlockall (true); #endif /* change thread priority if requested */ set_nice (parm.nice); /* event loop */ current = time (NULL); while (true) { int stat; time_t wakeup; struct tt_ret ret; struct buffer buf; /* * Call tls_multi_process repeatedly as long * as it has data to forward to the UDP port. */ do { CLEAR (ret); CLEAR (buf); wakeup = TLS_MULTI_REFRESH; /* maximum timeout */ /* do one TLS process pass */ if (tls_multi_process (parm.multi, &buf, &ret.to_udp_addr, parm.udp_socket, &wakeup, current)) { /* make a fresh copy of buf in ret */ ret.to_udp = clone_buf(&buf); /* send buffer to foreground where it will be forwarded to remote */ stat = write (parm.sd, &ret, sizeof (ret)); fatal = local_sock_fatal(); check_status (stat, "write to foreground"); if (fatal) goto exit; } } while (ret.to_udp.len); /* do a quick garbage collect */ gc_collect (gc_level); /* wait on select */ { struct timeval tv; tv.tv_sec = wakeup; tv.tv_usec = 0; FD_ZERO (&reads); FD_SET (parm.sd, &reads); stat = select (parm.sd + 1, &reads, NULL, NULL, &tv); } /* update current time */ current = time (NULL); /* received a message from foreground */ check_status (stat, "select"); /* timeout? */ if (!stat) continue; /* process message from foreground */ if (stat > 0 && FD_ISSET (parm.sd, &reads)) { struct tt_cmd tc; stat = read (parm.sd, &tc, sizeof (tc)); fatal = local_sock_fatal(); check_status (stat, "read from foreground"); if (stat == sizeof (tc)) { if (tc.cmd == TTCMD_PROCESS) ; else if (tc.cmd == TTCMD_EXIT) break; else msg (D_TLS_DEBUG, "TLS_THREAD: Unknown TTCMD code: %d", tc.cmd); } else if (fatal) break; } } exit: close (parm.sd); gc_free_level (gc_level); return NULL;}/* * Send a command to TLS thread. */static inttls_thread_send_command (int sd, int cmd){ struct tt_cmd tc; int stat; bool fatal; tc.cmd = cmd; stat = write (sd, &tc, sizeof (tc)); fatal = local_sock_fatal(); check_status (stat, "write command to tls thread"); if (stat == sizeof (tc)) return 1; else if (fatal) return -1; else return 0;}/* * Create the TLS thread. */inttls_thread_create (struct tls_multi *multi, struct udp_socket *udp_socket, int nice, bool mlock){ struct thread_parms *tp = (struct thread_parms *) malloc (sizeof (struct thread_parms)); int sd[2]; ASSERT (tp); tp->multi = multi; tp->udp_socket = udp_socket; tp->nice = nice; tp->mlock = mlock; /* * Make a socket for foreground and background threads * to communicate. The background thread will set its * end to blocking, while the foreground will set its * end to non-blocking. */ if (socketpair (PF_UNIX, SOCK_DGRAM, 0, sd) == -1) msg (M_ERR, "socketpair call failed"); set_nonblock (sd[0]); tp->sd = sd[1]; work_thread_create (thread_func, (void*)tp); return sd[0];}/* * Send a command to TLS thread telling it to cycle * through tls_multi_process() as long as there * is data to process. */inttls_thread_process (int sd){ return tls_thread_send_command (sd, TTCMD_PROCESS);}/* * Close the TLS thread */voidtls_thread_close (int sd){ if (sd) { struct tt_ret ttr; tls_thread_send_command (sd, TTCMD_EXIT); work_thread_join (); /* free any unprocessed buffers sent from background to foreground */ while (tls_thread_rec_buf (sd, &ttr, false) == 1) { free_buf (&ttr.to_udp); } close (sd); }}/* * Receive an object from the TLS thread which * normally contains a buffer to be sent to * the remote peer over the UDP port. * * Return: * 1 if ok * 0 if non-fatal error * -1 if fatal error */inttls_thread_rec_buf (int sd, struct tt_ret* ttr, bool do_check_status){ int stat; bool fatal; stat = read (sd, ttr, sizeof (*ttr)); fatal = local_sock_fatal(); if (do_check_status) check_status (stat, "read buffer from tls thread"); if (stat == sizeof (*ttr)) return 1; else if (fatal) return -1; else return 0;}#endif/* * Pre and post-process the encryption & decryption buffers in order * to implement a multiplexed TLS channel over the UDP port. *//* * * When we are in TLS mode, this is the first routine which sees * an incoming packet. * * If it's a data packet, we set opt so that our caller can * decrypt it. We also give our caller the appropriate decryption key. * * If it's a control packet, we authenticate it and process it, * possibly creating a new tls_session if it represents the * first packet of a new session. For control packets, we will * also zero the size of *buf so that our caller ignores the * packet on our return. * * Note that openvpn only allows one active session at a time, * so a new session (once authenticated) will always usurp * an old session. * * Return true if input was an authenticated control channel * packet. * * If we are running in TLS thread mode, all public routines
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -