?? ssl.c
字號:
printf ("%s\n", cipher_name); printf ("\n"); SSL_free (ssl); SSL_CTX_free (ctx);}/* * The OpenSSL library has a notion of preference in TLS * ciphers. Higher preference == more secure. * Return the highest preference cipher. */voidget_highest_preference_tls_cipher (char *buf, int size){ SSL_CTX *ctx; SSL *ssl; const char *cipher_name; ctx = SSL_CTX_new (TLSv1_method ()); if (!ctx) msg (M_SSLERR, "Cannot create SSL_CTX object"); ssl = SSL_new (ctx); if (!ssl) msg (M_SSLERR, "Cannot create SSL object"); cipher_name = SSL_get_cipher_list (ssl, 0); strncpynt (buf, cipher_name, size); SSL_free (ssl); SSL_CTX_free (ctx);}/* * Map internal constants to ascii names. */static const char *state_name (int state){ switch (state) { case S_UNDEF: return "S_UNDEF"; case S_INITIAL: return "S_INITIAL"; case S_PRE_START: return "S_PRE_START"; case S_START: return "S_START"; case S_SENT_KEY: return "S_SENT_KEY"; case S_GOT_KEY: return "S_GOT_KEY"; case S_ACTIVE: return "S_ACTIVE"; case S_ERROR: return "S_ERROR"; default: return "S_???"; }}static const char *packet_opcode_name (int op){ switch (op) { case P_CONTROL_HARD_RESET_CLIENT_V1: return "P_CONTROL_HARD_RESET_CLIENT_V1"; case P_CONTROL_HARD_RESET_SERVER_V1: return "P_CONTROL_HARD_RESET_SERVER_V1"; case P_CONTROL_SOFT_RESET_V1: return "P_CONTROL_SOFT_RESET_V1"; case P_CONTROL_V1: return "P_CONTROL_V1"; case P_ACK_V1: return "P_ACK_V1"; case P_DATA_V1: return "P_DATA_V1"; default: return "P_???"; }}static const char *session_index_name (int index){ switch (index) { case TM_ACTIVE: return "TM_ACTIVE"; case TM_UNTRUSTED: return "TM_UNTRUSTED"; case TM_LAME_DUCK: return "TM_LAME_DUCK"; default: return "TM_???"; }}/* * For debugging. */static const char *print_key_id (struct tls_multi *multi){ int i; struct buffer out = alloc_buf_gc (256); for (i = 0; i < KEY_SCAN_SIZE; ++i) { struct key_state *ks = multi->key_scan[i]; buf_printf (&out, " [key#%d state=%s id=%d sid=%s]", i, state_name (ks->state), ks->key_id, session_id_print (&ks->session_id_remote)); } return out.data;}/* * OpenVPN's interface to SSL/TLS authentication, * encryption, and decryption is exclusively * through "memory BIOs". */static BIO *getbio (BIO_METHOD * type, const char *desc){ BIO *ret; ret = BIO_new (type); if (!ret) msg (M_SSLERR, "Error creating %s BIO", desc); return ret;}/* * Write to an OpenSSL BIO in non-blocking mode. */static intbio_write (BIO * bio, struct buffer *buf, const char *desc){ int i; int ret = 0; ASSERT (buf->len >= 0); if (buf->len) { /* * Free the L_TLS lock prior to calling BIO routines * so that foreground thread can still call * tls_pre_decrypt or tls_pre_encrypt, * allowing tunnel packet forwarding to continue. */#ifdef BIO_DEBUG bio_debug_data ("write", bio, BPTR (buf), BLEN (buf), desc);#endif mutex_unlock (L_TLS); i = BIO_write (bio, BPTR (buf), BLEN (buf)); mutex_lock (L_TLS); if (i < 0) { if (BIO_should_retry (bio)) { ; } else { msg (D_TLS_ERRORS | M_SSL, "TLS ERROR: BIO write %s error", desc); ret = -1; } } else if (i != buf->len) { msg (D_TLS_ERRORS | M_SSL, "TLS ERROR: BIO write %s incomplete %d/%d", desc, i, buf->len); ret = -1; } else { /* successful write */ msg (D_HANDSHAKE_VERBOSE, "BIO write %s %d bytes", desc, i); memset (BPTR (buf), 0, BLEN (buf)); /* erase data just written */ buf->len = 0; ret = 1; } } return ret;}/* * Read from an OpenSSL BIO in non-blocking mode. */static intbio_read (BIO * bio, struct buffer *buf, int maxlen, const char *desc){ int i; int ret = 0; ASSERT (buf->len >= 0); if (buf->len) { ; } else { int len = buf_forward_capacity (buf); if (maxlen < len) len = maxlen; /* * Free the L_TLS lock prior to calling BIO routines * so that foreground thread can still call * tls_pre_decrypt or tls_pre_encrypt, * allowing tunnel packet forwarding to continue. * * BIO_read brackets most of the serious RSA * key negotiation number crunching. */ mutex_unlock (L_TLS); i = BIO_read (bio, BPTR (buf), len); mutex_lock (L_TLS);#ifdef BIO_DEBUG bio_debug_data ("read", bio, BPTR (buf), i, desc);#endif if (i < 0) { if (BIO_should_retry (bio)) { ; } else { msg (D_TLS_ERRORS | M_SSL, "TLS_ERROR: BIO read %s error", desc); buf->len = 0; ret = -1; } } else if (!i) { buf->len = 0; } else { /* successful read */ msg (D_HANDSHAKE_VERBOSE, "BIO read %s %d bytes", desc, i); buf->len = i; ret = 1; } } return ret;}/* * Inline functions for reading from and writing * to BIOs. */static inline intkey_state_write_plaintext (struct key_state *ks, struct buffer *buf){ return bio_write (ks->ssl_bio, buf, "tls_write_plaintext");}static inline intkey_state_write_ciphertext (struct key_state *ks, struct buffer *buf){ return bio_write (ks->ct_in, buf, "tls_write_ciphertext");}static inline intkey_state_read_plaintext (struct key_state *ks, struct buffer *buf, int maxlen){ return bio_read (ks->ssl_bio, buf, maxlen, "tls_read_plaintext");}static inline intkey_state_read_ciphertext (struct key_state *ks, struct buffer *buf, int maxlen){ return bio_read (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, time_t current){ /* * 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"); 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 buffers */ ks->plaintext_read_buf = alloc_buf (BUF_SIZE (&session->opt->frame)); ks->plaintext_write_buf = alloc_buf (BUF_SIZE (&session->opt->frame)); ks->ack_write_buf = alloc_buf (BUF_SIZE (&session->opt->frame)); reliable_init (&ks->send_reliable, BUF_SIZE (&session->opt->frame), EXTRA_FRAME (&session->opt->frame)); reliable_init (&ks->rec_reliable, BUF_SIZE (&session->opt->frame), EXTRA_FRAME (&session->opt->frame)); reliable_set_timeout (&ks->send_reliable, session->opt->packet_timeout);}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); reliable_free (&ks->send_reliable); reliable_free (&ks->rec_reliable); 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 retiring key. */static voidtls_session_init (struct tls_multi *multi, struct tls_session *session){ msg (D_TLS_DEBUG, "tls_session_init: entry"); CLEAR (*session); session->opt = &multi->opt; while (!session_id_defined(&session->session_id)) session_id_random (&session->session_id); session->initial_opcode = session->opt->server ? P_CONTROL_HARD_RESET_SERVER_V1 : P_CONTROL_HARD_RESET_CLIENT_V1; /* Initialize control channel authentication parameters */ session->tls_auth = session->opt->tls_auth; tls_session_set_self_referential_pointers(session); key_state_init (session, &session->key[KS_PRIMARY], time (NULL)); msg (D_TLS_DEBUG, "tls_session_init: new session object, sid=%s", session_id_print (&session->session_id));}static voidtls_session_free (struct tls_session *session, bool clear){ int i; for (i = 0; i < KS_SIZE; ++i) key_state_free (&session->key[i], false); if (clear) CLEAR (*session);}static voidmove_session(struct tls_multi* multi, int dest, int src, bool reinit_src){ msg (D_TLS_DEBUG_LOW, "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, "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, "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 (time_t* earliest, int seconds_from_now) { if (seconds_from_now > 0 && (seconds_from_now < *earliest || !*earliest)) *earliest = seconds_from_now;}/* * 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, time_t* wakeup, time_t current){ const struct key_state* lame = &session->key[KS_LAME_DUCK]; if (lame->state >= S_INITIAL) { ASSERT (lame->must_die); /* a lame duck key must always have an expiration */ if (current < lame->must_die) { compute_earliest_wakeup (wakeup, lame->must_die - current); return false; } else return true; } else if (lame->state == S_ERROR) return true; else return false;}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -