📄 tls.c
字号:
/* * tls.c * * Version: $Id: tls.c,v 1.7 2003/07/04 20:10:08 aland Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Copyright 2001 hereUare Communications, Inc. <raghud@hereuare.com> */#include "eap_tls.h"/* * TODO: Check for the type of key exchange * like conf->dh_key */int load_dh_params(SSL_CTX *ctx, char *file){ DH *dh = NULL; BIO *bio; if ((bio = BIO_new_file(file, "r")) == NULL) { radlog(L_ERR, "rlm_eap_tls: Unable to open DH file - %s", file); return -1; } dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); BIO_free(bio); if (SSL_CTX_set_tmp_dh(ctx, dh) < 0) { radlog(L_ERR, "rlm_eap_tls: Unable to set DH parameters"); DH_free(dh); return -1; } DH_free(dh); return 0;}int generate_eph_rsa_key(SSL_CTX *ctx){ RSA *rsa; rsa = RSA_generate_key(512, RSA_F4, NULL, NULL); if (!SSL_CTX_set_tmp_rsa(ctx, rsa)) { radlog(L_ERR, "rlm_eap_tls: Couldn't set RSA key"); return -1; } RSA_free(rsa); return 0;}/* * Create Global context SSL and use it in every new session * # Load the trusted CAs * # Load the Private key & the certificate * # Set the Context options & Verify options */SSL_CTX *init_tls_ctx(EAP_TLS_CONF *conf){ SSL_METHOD *meth; SSL_CTX *ctx; int verify_mode = 0; int ctx_options = 0; int type; /* * Add all the default ciphers and message digests * Create our context */ SSL_library_init(); SSL_load_error_strings(); meth = TLSv1_method(); ctx = SSL_CTX_new(meth); /* * Identify the type of certificates that needs to be loaded */ if (conf->file_type) { type = SSL_FILETYPE_PEM; } else { type = SSL_FILETYPE_ASN1; } /* Load the CAs we trust */ if (!(SSL_CTX_load_verify_locations(ctx, conf->ca_file, conf->ca_path)) || (!SSL_CTX_set_default_verify_paths(ctx))) { ERR_print_errors_fp(stderr); radlog(L_ERR, "rlm_eap_tls: Error reading Trusted root CA list"); return NULL; } SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(conf->ca_file)); /* * Set the password to load private key */ if (conf->private_key_password) { SSL_CTX_set_default_passwd_cb_userdata(ctx, conf->private_key_password); SSL_CTX_set_default_passwd_cb(ctx, cbtls_password); } /* Load our keys and certificates*/ if (!(SSL_CTX_use_certificate_file(ctx, conf->certificate_file, type))) { ERR_print_errors_fp(stderr); radlog(L_ERR, "rlm_eap_tls: Error reading certificate file"); return NULL; } if (!(SSL_CTX_use_PrivateKey_file(ctx, conf->private_key_file, type))) { ERR_print_errors_fp(stderr); radlog(L_ERR, "rlm_eap_tls: Error reading private key file"); return NULL; } /* * Check if the loaded private key is the right one */ if (!SSL_CTX_check_private_key(ctx)) { radlog(L_ERR, "rlm_eap_tls: Private key does not match the certificate public key"); return NULL; } /* * Set ctx_options */ ctx_options |= SSL_OP_NO_SSLv2; ctx_options |= SSL_OP_NO_SSLv3; /* SSL_OP_SINGLE_DH_USE must be used in order to prevent small subgroup attacks and forward secrecy. Always using SSL_OP_SINGLE_DH_USE has an impact on the computer time needed during negotiation, but it is not very large. */ ctx_options |= SSL_OP_SINGLE_DH_USE; SSL_CTX_set_options(ctx, ctx_options); /* * TODO: Set the RSA & DH SSL_CTX_set_tmp_rsa_callback(ctx, cbtls_rsa); SSL_CTX_set_tmp_dh_callback(ctx, cbtls_dh); */ /* * set the message callback to identify the type of message. * For every new session, there can be a different callback argument SSL_CTX_set_msg_callback(ctx, cbtls_msg); */ /* Set Info callback */ SSL_CTX_set_info_callback(ctx, cbtls_info); /* * Set verify modes * Always verify the peer certificate */ verify_mode |= SSL_VERIFY_PEER; verify_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; verify_mode |= SSL_VERIFY_CLIENT_ONCE; SSL_CTX_set_verify(ctx, verify_mode, cbtls_verify); if (conf->verify_depth) { SSL_CTX_set_verify_depth(ctx, conf->verify_depth); } /* Load randomness */ if (!(RAND_load_file(conf->random_file, 1024*1024))) { ERR_print_errors_fp(stderr); radlog(L_ERR, "rlm_eap_tls: Error loading randomness"); return NULL; } return ctx;}tls_session_t *new_tls_session(eap_tls_t *eaptls){ tls_session_t *state = NULL; SSL *new_tls = NULL; int verify_mode = 0; if ((new_tls = SSL_new(eaptls->ctx)) == NULL) { radlog(L_ERR, "rlm_eap_tls: Error creating new SSL"); ERR_print_errors_fp(stderr); return NULL; } /* We use the SSL's "app_data" to indicate a call-back */ SSL_set_app_data(new_tls, NULL); state = (tls_session_t *)malloc(sizeof(tls_session_t)); session_init(state); state->ssl = new_tls; /* * Create & hook the BIOs to handle the dirty side of the SSL * This is *very important* as we want to handle the transmission part. * Now the only IO interface that SSL is aware of, is our defined BIO buffers. */ state->into_ssl = BIO_new(BIO_s_mem()); state->from_ssl = BIO_new(BIO_s_mem()); SSL_set_bio(state->ssl, state->into_ssl, state->from_ssl); /* * Add the message callback to identify * what type of message/handshake is passed */ SSL_set_msg_callback(new_tls, cbtls_msg); SSL_set_msg_callback_arg(new_tls, state); SSL_set_info_callback(new_tls, cbtls_info); /* Always verify the peer certificate */ verify_mode |= SSL_VERIFY_PEER; verify_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; verify_mode |= SSL_VERIFY_CLIENT_ONCE; SSL_set_verify(state->ssl, verify_mode, cbtls_verify); /* In Server mode we only accept. */ SSL_set_accept_state(state->ssl); return state;}static void int_ssl_check(SSL *s, int ret){ int e; ERR_print_errors_fp(stderr); e = SSL_get_error(s, ret); radlog(L_ERR, " Error code is ..... %d\n", e); switch(e) { /* These seem to be harmless and already "dealt with" by our * non-blocking environment. NB: "ZERO_RETURN" is the clean * "error" indicating a successfully closed SSL tunnel. We let * this happen because our IO loop should not appear to have * broken on this condition - and outside the IO loop, the * "shutdown" state is checked. */ case SSL_ERROR_NONE: case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_X509_LOOKUP: case SSL_ERROR_ZERO_RETURN: radlog(L_ERR, " SSL Error ..... %d\n", e); return; /* These seem to be indications of a genuine error that should * result in the SSL tunnel being regarded as "dead". */ case SSL_ERROR_SYSCALL: case SSL_ERROR_SSL: radlog(L_ERR, " Error in SSL ..... %d\n", e); SSL_set_app_data(s, (char *)1); return; default: break; } radlog(L_ERR, "Unknown Error ..... %d\n", e); /* For any other errors that (a) exist, and (b) crop up - we need to * interpret what to do with them - so "politely inform" the caller that * the code needs updating here. */ abort();}/* * We are the server, we always get the dirty data * (Handshake data is also considered as dirty data) * During handshake, since SSL API handles itself, * After clean-up, dirty_out will be filled with * the data required for handshaking. So we check * if dirty_out is empty then we simply send it back. * As of now, if handshake is successful, then it is EAP-Success * or else EAP-failure should be sent * * Fill the Bio with the dirty data to clean it * Get the cleaned data from SSL, if it is not Handshake data */int tls_handshake_recv(tls_session_t *ssn){ int err; BIO_write(ssn->into_ssl, ssn->dirty_in.data, ssn->dirty_in.used); err = SSL_read(ssn->ssl, ssn->clean_out.data, MAX_RECORD_SIZE); if (err > 0) { ssn->clean_out.used = err; } else { radlog(L_INFO, "rlm_eap_tls: SSL_read Error"); int_ssl_check(ssn->ssl, err); } /* Some Extra STATE information for easy debugging */ /* if (SSL_is_init_finished(ssn->ssl)) { printf("SSL Connection Established\n"); } if (SSL_in_init(ssn->ssl)) { printf("In SSL Handshake Phase\n"); } if (SSL_in_before(ssn->ssl)) { printf("Before SSL Handshake Phase\n"); } if (SSL_in_accept_init(ssn->ssl)) { printf("In SSL Accept mode \n"); } if (SSL_in_connect_init(ssn->ssl)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -