📄 ssl.c
字号:
if (!buf->len) { msg (D_TLS_ERRORS, "TLS Error: incoming packet authentication failed from %s", print_sockaddr (from, &gc)); gc_free (&gc); return false; } } /* advance buffer pointer past opcode & session_id since our caller already read it */ buf_advance (buf, SID_SIZE + 1); gc_free (&gc); return true;}/* * For debugging, print contents of key_source2 structure. */static voidkey_source_print (const struct key_source *k, const char *prefix){ struct gc_arena gc = gc_new (); msg (D_SHOW_KEY_SOURCE, "%s pre_master: %s", prefix, format_hex (k->pre_master, sizeof (k->pre_master), 0, &gc)); msg (D_SHOW_KEY_SOURCE, "%s random1: %s", prefix, format_hex (k->random1, sizeof (k->random1), 0, &gc)); msg (D_SHOW_KEY_SOURCE, "%s random2: %s", prefix, format_hex (k->random2, sizeof (k->random2), 0, &gc)); gc_free (&gc);}static voidkey_source2_print (const struct key_source2 *k){ key_source_print (&k->client, "Client"); key_source_print (&k->server, "Server");}/* * Use the TLS PRF function for generating data channel keys. * This code is taken from the OpenSSL library. * * TLS generates keys as such: * * master_secret[48] = PRF(pre_master_secret[48], "master secret", * ClientHello.random[32] + ServerHello.random[32]) * * key_block[] = PRF(SecurityParameters.master_secret[48], * "key expansion", * SecurityParameters.server_random[32] + * SecurityParameters.client_random[32]); * * Notes: * * (1) key_block contains a full set of 4 keys. * (2) The pre-master secret is generated by the client. */static voidtls1_P_hash(const EVP_MD *md, const uint8_t *sec, int sec_len, const uint8_t *seed, int seed_len, uint8_t *out, int olen){ struct gc_arena gc = gc_new (); int chunk,n; unsigned int j; HMAC_CTX ctx; HMAC_CTX ctx_tmp; uint8_t A1[EVP_MAX_MD_SIZE]; unsigned int A1_len; const int olen_orig = olen; const uint8_t *out_orig = out; msg (D_SHOW_KEY_SOURCE, "tls1_P_hash sec: %s", format_hex (sec, sec_len, 0, &gc)); msg (D_SHOW_KEY_SOURCE, "tls1_P_hash seed: %s", format_hex (seed, seed_len, 0, &gc)); chunk=EVP_MD_size(md); HMAC_CTX_init(&ctx); HMAC_CTX_init(&ctx_tmp); HMAC_Init_ex(&ctx,sec,sec_len,md, NULL); HMAC_Init_ex(&ctx_tmp,sec,sec_len,md, NULL); HMAC_Update(&ctx,seed,seed_len); HMAC_Final(&ctx,A1,&A1_len); n=0; for (;;) { HMAC_Init_ex(&ctx,NULL,0,NULL,NULL); /* re-init */ HMAC_Init_ex(&ctx_tmp,NULL,0,NULL,NULL); /* re-init */ HMAC_Update(&ctx,A1,A1_len); HMAC_Update(&ctx_tmp,A1,A1_len); HMAC_Update(&ctx,seed,seed_len); if (olen > chunk) { HMAC_Final(&ctx,out,&j); out+=j; olen-=j; HMAC_Final(&ctx_tmp,A1,&A1_len); /* calc the next A1 value */ } else /* last one */ { HMAC_Final(&ctx,A1,&A1_len); memcpy(out,A1,olen); break; } } HMAC_CTX_cleanup(&ctx); HMAC_CTX_cleanup(&ctx_tmp); CLEAR (A1); msg (D_SHOW_KEY_SOURCE, "tls1_P_hash out: %s", format_hex (out_orig, olen_orig, 0, &gc)); gc_free (&gc);}static voidtls1_PRF(uint8_t *label, int label_len, const uint8_t *sec, int slen, uint8_t *out1, int olen){ struct gc_arena gc = gc_new (); const EVP_MD *md5 = EVP_md5(); const EVP_MD *sha1 = EVP_sha1(); int len,i; const uint8_t *S1,*S2; uint8_t *out2; out2 = (uint8_t *) gc_malloc (olen, false, &gc); len=slen/2; S1=sec; S2= &(sec[len]); len+=(slen&1); /* add for odd, make longer */ tls1_P_hash(md5 ,S1,len,label,label_len,out1,olen); tls1_P_hash(sha1,S2,len,label,label_len,out2,olen); for (i=0; i<olen; i++) out1[i]^=out2[i]; memset (out2, 0, olen); msg (D_SHOW_KEY_SOURCE, "tls1_PRF out[%d]: %s", olen, format_hex (out1, olen, 0, &gc)); gc_free (&gc);}static voidopenvpn_PRF (const uint8_t *secret, int secret_len, const char *label, const uint8_t *client_seed, int client_seed_len, const uint8_t *server_seed, int server_seed_len, const struct session_id *client_sid, const struct session_id *server_sid, uint8_t *output, int output_len){ /* concatenate seed components */ struct buffer seed = alloc_buf (strlen (label) + client_seed_len + server_seed_len + SID_SIZE * 2); ASSERT (buf_write (&seed, label, strlen (label))); ASSERT (buf_write (&seed, client_seed, client_seed_len)); ASSERT (buf_write (&seed, server_seed, server_seed_len)); if (client_sid) ASSERT (buf_write (&seed, client_sid->id, SID_SIZE)); if (server_sid) ASSERT (buf_write (&seed, server_sid->id, SID_SIZE)); /* compute PRF */ tls1_PRF (BPTR(&seed), BLEN(&seed), secret, secret_len, output, output_len); buf_clear (&seed); free_buf (&seed);}/* * Using source entropy from local and remote hosts, mix into * master key. */static boolgenerate_key_expansion (struct key_ctx_bi *key, const struct key_type *key_type, const struct key_source2 *key_src, const struct session_id *client_sid, const struct session_id *server_sid, bool server){ uint8_t master[48]; struct key2 key2; bool ret = false; int i; CLEAR (master); CLEAR (key2); /* debugging print of source key material */ key_source2_print (key_src); /* compute master secret */ openvpn_PRF (key_src->client.pre_master, sizeof(key_src->client.pre_master), KEY_EXPANSION_ID " master secret", key_src->client.random1, sizeof(key_src->client.random1), key_src->server.random1, sizeof(key_src->server.random1), NULL, NULL, master, sizeof(master)); /* compute key expansion */ openvpn_PRF (master, sizeof(master), KEY_EXPANSION_ID " key expansion", key_src->client.random2, sizeof(key_src->client.random2), key_src->server.random2, sizeof(key_src->server.random2), client_sid, server_sid, (uint8_t*)key2.keys, sizeof(key2.keys)); key2.n = 2; key2_print (&key2, key_type, "Master Encrypt", "Master Decrypt"); /* check for weak keys */ for (i = 0; i < 2; ++i) { fixup_key (&key2.keys[i], key_type); if (!check_key (&key2.keys[i], key_type)) { msg (D_TLS_ERRORS, "TLS Error: Bad dynamic key generated"); goto exit; } } /* Initialize OpenSSL key contexts */ ASSERT (server == true || server == false); init_key_ctx (&key->encrypt, &key2.keys[(int)server], key_type, DO_ENCRYPT, "Data Channel Encrypt"); init_key_ctx (&key->decrypt, &key2.keys[1-(int)server], key_type, DO_DECRYPT, "Data Channel Decrypt"); ret = true; exit: CLEAR (master); CLEAR (key2); return ret;}static voidrandom_bytes_to_buf (struct buffer *buf, uint8_t *out, int outlen){ if (!RAND_bytes (out, outlen)) msg (M_FATAL, "ERROR: Random number generator cannot obtain entropy for key generation [SSL]"); ASSERT (buf_write (buf, out, outlen));}static voidkey_source2_randomize_write (struct key_source2 *k2, struct buffer *buf, bool server){ struct key_source *k = &k2->client; if (server) k = &k2->server; CLEAR (*k); if (!server) random_bytes_to_buf (buf, k->pre_master, sizeof (k->pre_master)); random_bytes_to_buf (buf, k->random1, sizeof (k->random1)); random_bytes_to_buf (buf, k->random2, sizeof (k->random2));}static intkey_source2_read (struct key_source2 *k2, struct buffer *buf, bool server){ struct key_source *k = &k2->client; if (!server) k = &k2->server; CLEAR (*k); if (server) { if (!buf_read (buf, k->pre_master, sizeof (k->pre_master))) return 0; } if (!buf_read (buf, k->random1, sizeof (k->random1))) return 0; if (!buf_read (buf, k->random2, sizeof (k->random2))) return 0; return 1;}/* * 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){ ks->must_die = now + session->opt->transition_window; /* remaining lifetime of old key */ key_state_free (ks_lame, false); *ks_lame = *ks; key_state_init (session, ks); 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. * * Return value is true if we have placed a packet in *to_link which we * want to send to our peer. */static booltls_process (struct tls_multi *multi, struct tls_session *session, struct buffer *to_link, struct sockaddr_in *to_link_addr, struct link_socket_info *to_link_socket_info, interval_t *wakeup){ struct gc_arena gc = gc_new (); struct buffer *buf; bool state_change = false; bool active = 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 && now >= 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: soft reset sec=%d bytes=%d/%d pkts=%d/%d", (int)(ks->established + session->opt->renegotiate_seconds - now), ks->n_bytes, session->opt->renegotiate_bytes, ks->n_packets, session->opt->renegotiate_packets); key_state_soft_reset (session); } /* Kill lame duck key transition_window seconds after primary key negotiation */ if (lame_duck_must_die (session, wakeup)) { key_state_free (ks_lame, true); msg (D_TLS_DEBUG_LOW, "TLS: tls_process: killed expiring key"); } //mutex_cycle (multi->mutex); do { update_time (); msg (D_TLS_DEBUG, "TLS: tls_process: chg=%d ks=%s lame=%s to_link->len=%d wakeup=%d", state_change, state_name (ks->state), state_name (ks_lame->state), to_link->len, *wakeup); state_change = false; /* * TLS activity is finished once we get to S_ACTIVE, * though we will still process acknowledgements. * * CHANGED with 2.0 -> now we may send tunnel configuration * info over the control channel. */ if (true) { /* Initial handshake */ if (ks->state == S_INITIAL) { buf = reliable_get_buf_output_sequenced (ks->send_reliable); if (buf) { ks->must_negotiate = now + session->opt->handshake_window; /* null buffer */ reliable_mark_active_outgoing (ks->send_reliable, buf, ks->initial_opcode); INCR_GENERATED; ks->state = S_PRE_START; state_change = true; msg (D_TLS_DEBUG, "TLS: Initial Handshake, sid=%s", session_id_print (&session->session_id, &gc)); } } /* Are we timed out on receive? */ if (now >= ks->must_negotiate) { if (ks->state < S_ACTIVE) { msg (D_TLS_ERRORS, "TLS Error: TLS key negotiation failed to occur within %d seconds", session->opt->handshake_window); goto error; } else /* assume that ks->state == S_ACTIVE */ { msg (D_TLS_DEBUG_MED, "STATE S_NORMAL"); ks->state = S_NORMAL; ks->must_negotiate = 0; } } /* Wait for Initial Handshake ACK */ if (ks->state == S_PRE_START && FULL_SYNC) { ks->state = S_START; state_change = true; msg (D_TLS_DEBUG_MED, "STATE 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 = now; msg (D_TLS_DEBUG_MED, "STATE S_ACTIVE"); if (check_debug_level (D_HANDSHAKE)) print_details (ks->ssl, "Control Channel:"); state_change = true; ks->state = S_ACTIVE; INCR_SUCCESS; /* Set outgoing address for data channel packets */ link_socket_set_outgoing_addr (NULL, to_link_socket_info, &ks->remote_addr, session->common_name);#ifdef MEASURE_TLS_HANDSHAKE_STATS show_tls_performance_stats();#endif }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -