From: Alan T. DeKok Date: Wed, 11 May 2011 12:25:16 +0000 (+0200) Subject: Move more functions to global namespace X-Git-Tag: release_3_0_0_beta0~853 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a3f08dcb15462f089ee6d3331f9875bd4c58bdf7;p=thirdparty%2Ffreeradius-server.git Move more functions to global namespace --- diff --git a/src/include/tls.h b/src/include/tls.h index 2c69bbcc2ca..ef568636cc0 100644 --- a/src/include/tls.h +++ b/src/include/tls.h @@ -299,8 +299,16 @@ fr_tls_server_conf_t *tls_server_conf_parse(CONF_SECTION *cs); fr_tls_server_conf_t *tls_client_conf_parse(CONF_SECTION *cs); void tls_server_conf_free(fr_tls_server_conf_t *conf); int tls_handshake_recv(REQUEST *, tls_session_t *ssn); -int tls_handshake_send(REQUEST *,tls_session_t *ssn); -void tls_session_information(tls_session_t *tls_session); +int tls_handshake_send(REQUEST *, tls_session_t *ssn); +void tls_session_information(tls_session_t *ssn); + +/* + * Low-level TLS stuff + */ +int tls_success(tls_session_t *ssn, REQUEST *request); +void tls_fail(tls_session_t *ssn); +fr_tls_status_t tls_ack_handler(tls_session_t *tls_session, REQUEST *request); +fr_tls_status_t tls_application_data(tls_session_t *ssn, REQUEST *request); /* Session */ void session_free(void *ssn); @@ -356,6 +364,7 @@ struct fr_tls_server_conf_t { char *verify_tmp_dir; char *verify_client_cert_cmd; + int require_client_cert; #ifdef HAVE_OPENSSL_OCSP_H /* diff --git a/src/main/tls.c b/src/main/tls.c index b34036e1320..ce01f3f5443 100644 --- a/src/main/tls.c +++ b/src/main/tls.c @@ -736,6 +736,8 @@ static CONF_PARSER tls_server_config[] = { offsetof(fr_tls_server_conf_t, check_cert_issuer), NULL, NULL}, { "make_cert_command", PW_TYPE_STRING_PTR, offsetof(fr_tls_server_conf_t, make_cert_command), NULL, NULL}, + { "require_client_cert", PW_TYPE_BOOLEAN, + offsetof(fr_tls_server_conf_t, require_client_cert), NULL, NULL }, { "cache", PW_TYPE_SUBSECTION, 0, NULL, (const void *) cache_config }, @@ -1076,7 +1078,6 @@ int cbtls_verify(int ok, X509_STORE_CTX *ctx) char cn_str[1024]; char buf[64]; X509 *client_cert; - X509 *issuer_cert; SSL *ssl; int err, depth, lookup; fr_tls_server_conf_t *conf; @@ -1820,4 +1821,235 @@ fr_tls_server_conf_t *tls_client_conf_parse(CONF_SECTION *cs) return conf; } +int tls_success(tls_session_t *ssn, REQUEST *request) +{ + VALUE_PAIR *vp, *vps = NULL; + fr_tls_server_conf_t *conf; + + conf = (fr_tls_server_conf_t *)SSL_get_ex_data(ssn->ssl, FR_TLS_EX_INDEX_CONF); + rad_assert(conf != NULL); + + /* + * If there's no session resumption, delete the entry + * from the cache. This means either it's disabled + * globally for this SSL context, OR we were told to + * disable it for this user. + * + * This also means you can't turn it on just for one + * user. + */ + if ((!ssn->allow_session_resumption) || + (((vp = pairfind(request->config_items, 1127, 0)) != NULL) && + (vp->vp_integer == 0))) { + SSL_CTX_remove_session(ssn->ctx, + ssn->ssl->session); + ssn->allow_session_resumption = 0; + + /* + * If we're in a resumed session and it's + * not allowed, + */ + if (SSL_session_reused(ssn->ssl)) { + RDEBUG("FAIL: Forcibly stopping session resumption as it is not allowed."); + return -1; + } + + /* + * Else resumption IS allowed, so we store the + * user data in the cache. + */ + } else if (!SSL_session_reused(ssn->ssl)) { + RDEBUG2("Saving response in the cache"); + + vp = paircopy2(request->reply->vps, PW_USER_NAME, 0); + if (vp) pairadd(&vps, vp); + + vp = paircopy2(request->packet->vps, PW_STRIPPED_USER_NAME, 0); + if (vp) pairadd(&vps, vp); + + vp = paircopy2(request->reply->vps, PW_CACHED_SESSION_POLICY, 0); + if (vp) pairadd(&vps, vp); + + if (vps) { + SSL_SESSION_set_ex_data(ssn->ssl->session, + FR_TLS_EX_INDEX_VPS, vps); + } else { + RDEBUG2("WARNING: No information to cache: session caching will be disabled for this session."); + SSL_CTX_remove_session(ssn->ctx, + ssn->ssl->session); + } + + /* + * Else the session WAS allowed. Copy the cached + * reply. + */ + } else { + + vp = SSL_SESSION_get_ex_data(ssn->ssl->session, + FR_TLS_EX_INDEX_VPS); + if (!vp) { + RDEBUG("WARNING: No information in cached session!"); + return -1; + + } else { + RDEBUG("Adding cached attributes to the reply:"); + debug_pair_list(vp); + pairadd(&request->reply->vps, paircopy(vp)); + + /* + * Mark the request as resumed. + */ + vp = pairmake("EAP-Session-Resumed", "1", T_OP_SET); + if (vp) pairadd(&request->packet->vps, vp); + } + } + + return 0; +} + + +void tls_fail(tls_session_t *ssn) +{ + /* + * Force the session to NOT be cached. + */ + SSL_CTX_remove_session(ssn->ctx, ssn->ssl->session); +} + +fr_tls_status_t tls_application_data(tls_session_t *ssn, + REQUEST *request) + +{ + int err; + + /* + * Decrypt the complete record. + */ + err = BIO_write(ssn->into_ssl, ssn->dirty_in.data, + ssn->dirty_in.used); + if (err != (int) ssn->dirty_in.used) { + record_init(&ssn->dirty_in); + RDEBUG("Failed writing %d to SSL BIO: %d", + ssn->dirty_in.used, err); + return FR_TLS_FAIL; + } + + /* + * Clear the dirty buffer now that we are done with it + * and init the clean_out buffer to store decrypted data + */ + record_init(&ssn->dirty_in); + record_init(&ssn->clean_out); + + /* + * Read (and decrypt) the tunneled data from the + * SSL session, and put it into the decrypted + * data buffer. + */ + err = SSL_read(ssn->ssl, ssn->clean_out.data, + sizeof(ssn->clean_out.data)); + + if (err < 0) { + int code; + + RDEBUG("SSL_read Error"); + + code = SSL_get_error(ssn->ssl, err); + switch (code) { + case SSL_ERROR_WANT_READ: + return FR_TLS_MORE_FRAGMENTS; + DEBUG("Error in fragmentation logic: SSL_WANT_READ"); + break; + + case SSL_ERROR_WANT_WRITE: + DEBUG("Error in fragmentation logic: SSL_WANT_WRITE"); + break; + + default: + DEBUG("Error in fragmentation logic: ?"); + + /* + * FIXME: Call int_ssl_check? + */ + break; + } + return FR_TLS_FAIL; + } + + if (err == 0) { + RDEBUG("WARNING: No data inside of the tunnel."); + } + + /* + * Passed all checks, successfully decrypted data + */ + ssn->clean_out.used = err; + + return FR_TLS_OK; +} + + +/* + * Acknowledge received is for one of the following messages sent earlier + * 1. Handshake completed Message, so now send, EAP-Success + * 2. Alert Message, now send, EAP-Failure + * 3. Fragment Message, now send, next Fragment + */ +fr_tls_status_t tls_ack_handler(tls_session_t *ssn, REQUEST *request) +{ + RDEBUG2("Received TLS ACK"); + + if (ssn == NULL){ + radlog_request(L_ERR, 0, request, "FAIL: Unexpected ACK received. Could not obtain session information."); + return FR_TLS_INVALID; + } + if (ssn->info.initialized == 0) { + RDEBUG("No SSL info available. Waiting for more SSL data."); + return FR_TLS_REQUEST; + } + if ((ssn->info.content_type == handshake) && + (ssn->info.origin == 0)) { + radlog_request(L_ERR, 0, request, "FAIL: ACK without earlier message."); + return FR_TLS_INVALID; + } + + switch (ssn->info.content_type) { + case alert: + RDEBUG2("ACK alert"); + return FR_TLS_FAIL; + + case handshake: + if ((ssn->info.handshake_type == finished) && + (ssn->dirty_out.used == 0)) { + RDEBUG2("ACK handshake is finished"); + + /* + * From now on all the content is + * application data set it here as nobody else + * sets it. + */ + ssn->info.content_type = application_data; + return FR_TLS_SUCCESS; + } /* else more data to send */ + + RDEBUG2("ACK handshake fragment handler"); + /* Fragmentation handler, send next fragment */ + return FR_TLS_REQUEST; + + case application_data: + RDEBUG2("ACK handshake fragment handler in application data"); + return FR_TLS_REQUEST; + + /* + * For the rest of the conditions, switch over + * to the default section below. + */ + default: + RDEBUG2("ACK default"); + radlog_request(L_ERR, 0, request, "Invalid ACK received: %d", + ssn->info.content_type); + return FR_TLS_INVALID; + } +} + #endif /* WITH_TLS */ diff --git a/src/modules/rlm_eap/libeap/eap_tls.c b/src/modules/rlm_eap/libeap/eap_tls.c index e322da69300..a54a929790e 100644 --- a/src/modules/rlm_eap/libeap/eap_tls.c +++ b/src/modules/rlm_eap/libeap/eap_tls.c @@ -105,7 +105,6 @@ int eaptls_start(EAP_DS *eap_ds, int peap_flag) int eaptls_success(EAP_HANDLER *handler, int peap_flag) { EAPTLS_PACKET reply; - VALUE_PAIR *vp, *vps = NULL; REQUEST *request = handler->request; tls_session_t *tls_session = handler->opaque; @@ -116,79 +115,7 @@ int eaptls_success(EAP_HANDLER *handler, int peap_flag) reply.data = NULL; reply.dlen = 0; - /* - * If there's no session resumption, delete the entry - * from the cache. This means either it's disabled - * globally for this SSL context, OR we were told to - * disable it for this user. - * - * This also means you can't turn it on just for one - * user. - */ - if ((!tls_session->allow_session_resumption) || - (((vp = pairfind(request->config_items, 1127, 0)) != NULL) && - (vp->vp_integer == 0))) { - SSL_CTX_remove_session(tls_session->ctx, - tls_session->ssl->session); - tls_session->allow_session_resumption = 0; - - /* - * If we're in a resumed session and it's - * not allowed, - */ - if (SSL_session_reused(tls_session->ssl)) { - RDEBUG("FAIL: Forcibly stopping session resumption as it is not allowed."); - return eaptls_fail(handler, peap_flag); - } - - /* - * Else resumption IS allowed, so we store the - * user data in the cache. - */ - } else if (!SSL_session_reused(tls_session->ssl)) { - RDEBUG2("Saving response in the cache"); - - vp = paircopy2(request->reply->vps, PW_USER_NAME, 0); - if (vp) pairadd(&vps, vp); - - vp = paircopy2(request->packet->vps, PW_STRIPPED_USER_NAME, 0); - if (vp) pairadd(&vps, vp); - - vp = paircopy2(request->reply->vps, PW_CACHED_SESSION_POLICY, 0); - if (vp) pairadd(&vps, vp); - - if (vps) { - SSL_SESSION_set_ex_data(tls_session->ssl->session, - FR_TLS_EX_INDEX_VPS, vps); - } else { - RDEBUG2("WARNING: No information to cache: session caching will be disabled for this session."); - SSL_CTX_remove_session(tls_session->ctx, - tls_session->ssl->session); - } - - /* - * Else the session WAS allowed. Copy the cached - * reply. - */ - } else { - - vp = SSL_SESSION_get_ex_data(tls_session->ssl->session, - FR_TLS_EX_INDEX_VPS); - if (!vp) { - RDEBUG("WARNING: No information in cached session!"); - return eaptls_fail(handler, peap_flag); - } else { - RDEBUG("Adding cached attributes to the reply:"); - debug_pair_list(vp); - pairadd(&request->reply->vps, paircopy(vp)); - - /* - * Mark the request as resumed. - */ - vp = pairmake("EAP-Session-Resumed", "1", T_OP_SET); - if (vp) pairadd(&request->packet->vps, vp); - } - } + tls_success(tls_session, request); /* * Call compose AFTER checking for cached data. @@ -307,71 +234,6 @@ int eaptls_request(EAP_DS *eap_ds, tls_session_t *ssn) return 1; } -/* - * Acknowledge received is for one of the following messages sent earlier - * 1. Handshake completed Message, so now send, EAP-Success - * 2. Alert Message, now send, EAP-Failure - * 3. Fragment Message, now send, next Fragment - */ -static fr_tls_status_t eaptls_ack_handler(EAP_HANDLER *handler) -{ - tls_session_t *tls_session; - REQUEST *request = handler->request; - - tls_session = (tls_session_t *)handler->opaque; - if (tls_session == NULL){ - radlog_request(L_ERR, 0, request, "FAIL: Unexpected ACK received. Could not obtain session information."); - return FR_TLS_FAIL; - } - if (tls_session->info.initialized == 0) { - RDEBUG("No SSL info available. Waiting for more SSL data."); - return FR_TLS_REQUEST; - } - if ((tls_session->info.content_type == handshake) && - (tls_session->info.origin == 0)) { - radlog_request(L_ERR, 0, request, "FAIL: ACK without earlier message."); - return FR_TLS_FAIL; - } - - switch (tls_session->info.content_type) { - case alert: - RDEBUG2("ACK alert"); - eaptls_fail(handler, tls_session->peap_flag); - return FR_TLS_FAIL; - - case handshake: - if ((tls_session->info.handshake_type == finished) && - (tls_session->dirty_out.used == 0)) { - RDEBUG2("ACK handshake is finished"); - - /* - * From now on all the content is - * application data set it here as nobody else - * sets it. - */ - tls_session->info.content_type = application_data; - return FR_TLS_SUCCESS; - } /* else more data to send */ - - RDEBUG2("ACK handshake fragment handler"); - /* Fragmentation handler, send next fragment */ - return FR_TLS_REQUEST; - - case application_data: - RDEBUG2("ACK handshake fragment handler in application data"); - return FR_TLS_REQUEST; - - /* - * For the rest of the conditions, switch over - * to the default section below. - */ - default: - RDEBUG2("ACK default"); - radlog_request(L_ERR, 0, request, "Invalid ACK received: %d", - tls_session->info.content_type); - return FR_TLS_FAIL; - } -} /* * Similarly, when the EAP server receives an EAP-Response with @@ -449,25 +311,17 @@ static fr_tls_status_t eaptls_verify(EAP_HANDLER *handler) ((eap_ds->response->length == EAP_HEADER_LEN + 2) && ((eaptls_packet->flags & 0xc0) == 0x00))) { -#if 0 - /* - * Un-comment this for TLS inside of TTLS/PEAP - */ - RDEBUG2("Received EAP-TLS ACK message"); - return eaptls_ack_handler(handler); -#else if (prev_eap_ds && (prev_eap_ds->request->id == eap_ds->response->id)) { /* * Run the ACK handler directly from here. */ RDEBUG2("Received TLS ACK"); - return eaptls_ack_handler(handler); + return tls_ack_handler(handler->opaque, request); } else { radlog_request(L_ERR, 0, request, "Received Invalid TLS ACK"); return FR_TLS_INVALID; } -#endif } /* @@ -930,8 +784,6 @@ fr_tls_status_t eaptls_process(EAP_HANDLER *handler) * The TLS data will be in the tls_session structure. */ if (SSL_is_init_finished(tls_session->ssl)) { - int err; - /* * The initialization may be finished, but if * there more fragments coming, then send ACK, @@ -951,55 +803,7 @@ fr_tls_status_t eaptls_process(EAP_HANDLER *handler) goto done; } - /* - * Decrypt the complete record. - */ - BIO_write(tls_session->into_ssl, tls_session->dirty_in.data, - tls_session->dirty_in.used); - - /* - * Clear the dirty buffer now that we are done with it - * and init the clean_out buffer to store decrypted data - */ - (tls_session->record_init)(&tls_session->dirty_in); - (tls_session->record_init)(&tls_session->clean_out); - - /* - * Read (and decrypt) the tunneled data from the - * SSL session, and put it into the decrypted - * data buffer. - */ - err = SSL_read(tls_session->ssl, tls_session->clean_out.data, - sizeof(tls_session->clean_out.data)); - - if (err < 0) { - RDEBUG("SSL_read Error"); - - switch (SSL_get_error(tls_session->ssl, err)) { - case SSL_ERROR_WANT_READ: - case SSL_ERROR_WANT_WRITE: - RDEBUG("Error in fragmentation logic"); - break; - default: - /* - * FIXME: Call int_ssl_check? - */ - break; - } - status = FR_TLS_FAIL; - goto done; - } - - if (err == 0) { - RDEBUG("WARNING: No data inside of the tunnel."); - } - - /* - * Passed all checks, successfully decrypted data - */ - tls_session->clean_out.used = err; - - status = FR_TLS_OK; + status = tls_application_data(tls_session, request); goto done; } diff --git a/src/modules/rlm_eap/libeap/eap_tls.h b/src/modules/rlm_eap/libeap/eap_tls.h index a1c41106b40..6b434f054ca 100644 --- a/src/modules/rlm_eap/libeap/eap_tls.h +++ b/src/modules/rlm_eap/libeap/eap_tls.h @@ -51,6 +51,7 @@ RCSIDH(eap_tls_h, "$Id$") #include #endif +#include #include #include "eap.h"