?? ssl.c
字號:
err: mutex_unlock_static (L_SCRIPT); return 0; /* Reject connection */}intget_max_tls_verify_id (struct tls_multi* multi){ if (multi) return multi->session[TM_ACTIVE].verify_maxlevel; else return 0;}const char *tls_common_name (struct tls_multi* multi, bool null){ const char *ret = NULL; if (multi) ret = multi->session[TM_ACTIVE].common_name; if (ret) return ret; else if (null) return NULL; else return "UNDEF";}/* * Print debugging information on SSL/TLS session negotiation. */static voidinfo_callback (INFO_CALLBACK_SSL_CONST SSL * s, int where, int ret){ if (where & SSL_CB_LOOP) { msg (D_HANDSHAKE_VERBOSE, "SSL state (%s): %s", where & SSL_ST_CONNECT ? "connect" : where & SSL_ST_ACCEPT ? "accept" : "undefined", SSL_state_string_long (s)); } else if (where & SSL_CB_ALERT) { msg (D_HANDSHAKE_VERBOSE, "SSL alert (%s): %s: %s", where & SSL_CB_READ ? "read" : "write", SSL_alert_type_string_long (ret), SSL_alert_desc_string_long (ret)); }}/* * Initialize SSL context. * All files are in PEM format. */SSL_CTX *init_ssl (bool server, const char *ca_file, const char *dh_file, const char *cert_file, const char *priv_key_file, const char *cipher_list){ SSL_CTX *ctx; DH *dh; BIO *bio; if (server) { ctx = SSL_CTX_new (TLSv1_server_method ()); if (ctx == NULL) msg (M_SSLERR, "SSL_CTX_new TLSv1_server_method"); SSL_CTX_set_tmp_rsa_callback (ctx, tmp_rsa_cb); /* Get Diffie Hellman Parameters */ if (!(bio = BIO_new_file (dh_file, "r"))) msg (M_SSLERR, "Cannot open %s for DH parameters", dh_file); dh = PEM_read_bio_DHparams (bio, NULL, NULL, NULL); BIO_free (bio); if (!dh) msg (M_SSLERR, "Cannot load DH parameters from %s", dh_file); if (!SSL_CTX_set_tmp_dh (ctx, dh)) msg (M_SSLERR, "SSL_CTX_set_tmp_dh"); msg (D_TLS_DEBUG_LOW, "Diffie-Hellman initialized with %d bit key", 8 * DH_size (dh)); DH_free (dh); } else /* if client */ { ctx = SSL_CTX_new (TLSv1_client_method ()); if (ctx == NULL) msg (M_SSLERR, "SSL_CTX_new TLSv1_client_method"); } /* Set SSL options */ SSL_CTX_set_session_cache_mode (ctx, SSL_SESS_CACHE_OFF); SSL_CTX_set_options (ctx, SSL_OP_SINGLE_DH_USE); /* Set callback for getting password from user to decrypt private key */ SSL_CTX_set_default_passwd_cb (ctx, pem_password_callback); /* Load Certificate */ if (!SSL_CTX_use_certificate_file (ctx, cert_file, SSL_FILETYPE_PEM)) msg (M_SSLERR, "Cannot load certificate file %s", cert_file); /* Load Private Key */ if (!SSL_CTX_use_PrivateKey_file (ctx, priv_key_file, SSL_FILETYPE_PEM)) msg (M_SSLERR, "Cannot load private key file %s", priv_key_file); warn_if_group_others_accessible (priv_key_file); /* Check Private Key */ if (!SSL_CTX_check_private_key (ctx)) msg (M_SSLERR, "Private key does not match the certificate"); /* Load CA file for verifying peer supplied certificate */ if (!SSL_CTX_load_verify_locations (ctx, ca_file, NULL)) msg (M_SSLERR, "Cannot load CA certificate file %s (SSL_CTX_load_verify_locations)", ca_file); /* Load names of CAs from file and use it as a client CA list */ { STACK_OF(X509_NAME) *cert_names; cert_names = SSL_load_client_CA_file (ca_file); if (!cert_names) msg (M_SSLERR, "Cannot load CA certificate file %s (SSL_load_client_CA_file)", ca_file); SSL_CTX_set_client_CA_list (ctx, cert_names); } /* Enable the use of certificate chains */ if (!SSL_CTX_use_certificate_chain_file (ctx, cert_file)) msg (M_SSLERR, "Cannot load certificate chain file %s (SSL_use_certificate_chain_file)", cert_file); /* Require peer certificate verification */ SSL_CTX_set_verify (ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_callback); /* Connection information callback */ SSL_CTX_set_info_callback (ctx, info_callback); /* Allowable ciphers */ if (cipher_list) { if (!SSL_CTX_set_cipher_list (ctx, cipher_list)) msg (M_SSLERR, "Problem with cipher list: %s", cipher_list); } return ctx;}/* * Print a one line summary of SSL/TLS session handshake. */static voidprint_details (SSL * c_ssl, const char *prefix){ SSL_CIPHER *ciph; X509 *cert; char s1[256]; char s2[256]; s1[0] = s2[0] = 0; ciph = SSL_get_current_cipher (c_ssl); openvpn_snprintf (s1, sizeof (s1), "%s %s, cipher %s %s", prefix, SSL_get_version (c_ssl), SSL_CIPHER_get_version (ciph), SSL_CIPHER_get_name (ciph)); cert = SSL_get_peer_certificate (c_ssl); if (cert != NULL) { EVP_PKEY *pkey = X509_get_pubkey (cert); if (pkey != NULL) { if (pkey->type == EVP_PKEY_RSA && pkey->pkey.rsa != NULL && pkey->pkey.rsa->n != NULL) { openvpn_snprintf (s2, sizeof (s2), ", %d bit RSA", BN_num_bits (pkey->pkey.rsa->n)); } else if (pkey->type == EVP_PKEY_DSA && pkey->pkey.dsa != NULL && pkey->pkey.dsa->p != NULL) { openvpn_snprintf (s2, sizeof (s2), ", %d bit DSA", BN_num_bits (pkey->pkey.dsa->p)); } EVP_PKEY_free (pkey); } X509_free (cert); } /* The SSL API does not allow us to look at temporary RSA/DH keys, * otherwise we should print their lengths too */ msg (D_HANDSHAKE, "%s%s", s1, s2);}/* * Show the TLS ciphers that are available for us to use * in the OpenSSL library. */voidshow_available_tls_ciphers (){ SSL_CTX *ctx; SSL *ssl; const char *cipher_name; int priority = 0; 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"); printf ("Available TLS Ciphers,\n"); printf ("listed in order of preference:\n\n"); while ((cipher_name = SSL_get_cipher_list (ssl, priority++))) 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_NORMAL: return "S_NORMAL"; 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_HARD_RESET_CLIENT_V2: return "P_CONTROL_HARD_RESET_CLIENT_V2"; case P_CONTROL_HARD_RESET_SERVER_V2: return "P_CONTROL_HARD_RESET_SERVER_V2"; 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, struct gc_arena *gc){ int i; struct buffer out = alloc_buf_gc (256, gc); 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, gc)); } return BSTR (&out);}/* * Given a key_method, return true if op * represents the required form of hard_reset. * * If key_method = 0, return true if any * form of hard reset is used. */static boolis_hard_reset (int op, int key_method){ if (!key_method || key_method == 1) if (op == P_CONTROL_HARD_RESET_CLIENT_V1 || op == P_CONTROL_HARD_RESET_SERVER_V1) return true; if (!key_method || key_method >= 2) if (op == P_CONTROL_HARD_RESET_CLIENT_V2 || op == P_CONTROL_HARD_RESET_SERVER_V2) return true; return false;}/* * 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 (struct tls_multi* multi, 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 (multi->mutex); i = BIO_write (bio, BPTR (buf), BLEN (buf)); //mutex_lock (multi->mutex); 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 (struct tls_multi* multi, 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 (multi->mutex); i = BIO_read (bio, BPTR (buf), len); //mutex_lock (multi->mutex);#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 tls_multi *multi, struct key_state *ks, struct buffer *buf){ return bio_write (multi, ks->ssl_bio, buf, "tls_write_plaintext");}static inline intkey_state_write_ciphertext (struct tls_multi *multi, struct key_state *ks, struct buffer *buf){ return bio_write (multi, ks->ct_in, buf, "tls_write_ciphertext");}static inline intkey_state_read_plaintext (struct tls_multi *multi, struct key_state *ks, struct buffer *buf, int maxlen){ return bio_read (multi, ks->ssl_bio, buf, maxlen, "tls_read_plaintext");}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -