📄 ossl_tls_funcs.c
字号:
/**
* EAPTLS (RFC 2716) Function implementations
*
* Licensed under a dual GPL/BSD license. (See LICENSE file for more info.)
*
* \file ossl_tls_funcs.c
*
* \author chris@open1x.org
*
* $Id: ossl_tls_funcs.c,v 1.1.2.53 2008/02/04 19:46:50 chessing Exp $
* $Date: 2008/02/04 19:46:50 $
*/
#ifndef USE_GNUTLS
#ifdef WINDOWS
#define OPENSSL_NO_ENGINE
#include <windows.h>
#endif
#include <stdio.h>
#include <string.h>
#include <openssl/ssl.h>
#ifndef WINDOWS
/* For some reason, including this file on windows right now will cause the compiler to fail.
Since it generally isn't used, we will disable it on Windows for now. */
#include <openssl/engine.h>
#endif
#include <openssl/ui.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#include <openssl/hmac.h>
#include <openssl/md5.h>
#include <openssl/bio.h>
#ifndef WINDOWS
#include <netinet/in.h>
#include <inttypes.h>
#include <unistd.h>
#endif
#include <string.h>
#include "../../../lib/libxsupconfig/xsupconfig_structs.h"
#include "../../xsup_common.h"
#include "../../../lib/libxsupconfig/xsupconfig.h"
#include "../../context.h"
#include "../../eap_sm.h"
#include "../../eap_types/tls/eaptls.h"
#include "tls_funcs.h"
#include "../../xsup_debug.h"
#include "../../xsup_err.h"
#include "../../frame_structs.h"
#include "../../ipc_events.h"
#include "../../ipc_events_index.h"
#ifdef USE_EFENCE
#include <efence.h>
#endif
// In OpenSSL 0.9.8 we need to explicitly include the SHA header.
#ifndef SHA_DIGEST_LENGTH
#include <openssl/sha.h>
#endif
// If it *STILL* isn't around, then just define it.
#ifndef SHA_DIGEST_LENGTH
#define SHA_DIGEST_LENGTH 20
#endif
int engine_load_dynamic_opensc(struct smartcard *sc);
void set_smartcard_pin(char *pin);
UI_METHOD *UI_noninteractive(void);
/************************************************************************
*
* Get the common name field from a certificate for later processing.
*
************************************************************************/
char *get_cert_common_name(SSL *ssl_ctx)
{
char *commonName = NULL;
X509 *server_cert;
TRACE
if (!xsup_assert((ssl_ctx != NULL), "ssl_ctx != NULL", FALSE))
return NULL;
// Get our certificate.
server_cert = SSL_get_peer_certificate(ssl_ctx);
if (!server_cert) return NULL;
commonName = (char *)Malloc(512);
if (commonName == NULL)
{
debug_printf(DEBUG_NORMAL, "Couldn't allocate memory to hold the common name!\n");
ipc_events_malloc_failed(NULL);
return NULL;
}
if (X509_NAME_get_text_by_NID(X509_get_subject_name(server_cert),
NID_commonName, commonName, 512) < 0)
{
debug_printf(DEBUG_NORMAL, "Couldn't extract common name from server certificate!\n");
return NULL;
}
debug_printf(DEBUG_TLS_CORE, "Extracted common name of %s\n",commonName);
return commonName;
}
/************************************************************************
*
* Process an error condition and display some information about it.
*
************************************************************************/
void tls_funcs_process_error()
{
unsigned long err;
TRACE
err = ERR_get_error();
if (err != 0)
{
debug_printf(DEBUG_NORMAL, "OpenSSL Error -- %s\n",
ERR_error_string(err, NULL));
debug_printf(DEBUG_NORMAL, "Library : %s\n", ERR_lib_error_string(err));
debug_printf(DEBUG_NORMAL, "Function : %s\n", ERR_func_error_string(err));
debug_printf(DEBUG_NORMAL, "Reason : %s\n", ERR_reason_error_string(err));
}
}
/************************************************************************
*
* Determine if we have any data pending. If we do, return the number of
* bytes that are pending.
*
************************************************************************/
uint32_t tls_funcs_data_pending(struct tls_vars *mytls_vars)
{
uint32_t retsize;
if (!xsup_assert((mytls_vars != NULL), "mytls_vars != NULL", FALSE))
return 0;
if (queue_get_size(&mytls_vars->tlsoutqueue, &retsize) < 0)
return 0; // Something was wrong, so we can't have anything more to send.
return retsize;
}
/************************************************************************
*
* Do some standard checks to be sure our certificate is valid.
*
************************************************************************/
static int ssl_verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
{
char buf[256];
X509 *err_cert;
int err, depth;
TRACE
if (!xsup_assert((ctx != NULL), "ctx != NULL", FALSE))
return XEMALLOC;
err_cert = X509_STORE_CTX_get_current_cert(ctx);
err = X509_STORE_CTX_get_error(ctx);
depth = X509_STORE_CTX_get_error_depth(ctx);
X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256);
debug_printf(DEBUG_TLS_CORE, " --- SSL_verify : depth %d\n", depth);
if (!preverify_ok)
{
debug_printf(DEBUG_TLS_CORE, " --- SSL_verify error : num=%d:%s:depth=%d:%s\n",
err, X509_verify_cert_error_string(err), depth, buf);
// Ignore the self signed certificate error, from OpenSSL.
if (err == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) preverify_ok = 1;
}
debug_printf(DEBUG_TLS_CORE, "preverify_ok = %d\n", preverify_ok);
return preverify_ok;
}
/***********************************************************************
*
* Initialize the Open SC smart card handler.
*
***********************************************************************/
#ifndef WINDOWS
int tls_funcs_load_engine(struct tls_vars *mytls_vars, struct smartcard *sc)
{
if(!engine_load_dynamic_opensc(sc))
{
debug_printf(DEBUG_NORMAL, "OpenSC Engine will be unavailable!\n");
return XEGENERROR;
}
debug_printf(DEBUG_NORMAL, "Using Engine with ID \"%s\"\n",
sc->engine_id);
mytls_vars->engine = ENGINE_by_id(sc->engine_id);
if (!mytls_vars->engine)
{
debug_printf(DEBUG_NORMAL, "Engine not available!\n");
return XETLSINIT;
}
/* Now everything that can be done without having a smartcard plugged in
* is done. The next step is initializing the Engine.
* This step should probably be done in some place where it can be
* retried if it fails.
*/
if (!ENGINE_init(mytls_vars->engine))
{
debug_printf(DEBUG_NORMAL, "Can't initialize OpenSC Engine! "
"Is the smartcard plugged in?\n");
/* If we get this error there's probably no smartcard connected -
* we should be able to retry the call to ENGINE_init() */
return XETLSINIT;
}
return XENONE;
}
#endif // WINDOWS
/***********************************************************************
*
* Configure the cipher suites to only do TLS_DH_anon_WITH_AES_128_CBC_SHA
* this is use with EAP-FAST to provide unauthenticated provisioning.
*
***********************************************************************/
int tls_funcs_set_anon_dh_aes(struct tls_vars *mytls_vars)
{
if (!xsup_assert((mytls_vars != NULL), "mytls_vars != NULL", FALSE))
return -1;
if (!xsup_assert((mytls_vars->ssl != NULL), "mytls_vars->ssl != NULL",
FALSE))
return -1;
if (SSL_set_cipher_list(mytls_vars->ssl, "ADH-AES128-SHA") != 1)
{
// The cipher type wasn't allowed. (Probably not compiled in.)
debug_printf(DEBUG_NORMAL, "Anonymous cipher ADH-AES128-SHA was not "
"available! It is possible that your OpenSSL was not "
"compiled with support for it!\n");
return -1;
}
return 0;
}
/***********************************************************************
*
* Allocate memory, and set up structures needed to complete a TLS
* based authentication.
*
***********************************************************************/
int tls_funcs_init(struct tls_vars *mytls_vars, uint8_t eaptype)
{
TRACE
if (!xsup_assert((mytls_vars != NULL), "mytls_vars != NULL", FALSE))
return XETLSINIT;
// XXX Need to move the global init pieces here. (OpenSSL init stuff.) Once we
// finish making the changes to allow GNU-TLS as an option.
if (mytls_vars->ssl)
{
SSL_shutdown(mytls_vars->ssl);
SSL_free(mytls_vars->ssl);
mytls_vars->ssl = NULL;
}
if (mytls_vars->ctx != NULL)
{
SSL_CTX_free(mytls_vars->ctx);
mytls_vars->ctx = NULL;
}
mytls_vars->ctx = SSL_CTX_new(TLSv1_method());
if (mytls_vars->ctx == NULL)
{
debug_printf(DEBUG_NORMAL, "Couldn't initialize OpenSSL TLS library!\n");
tls_funcs_process_error();
ipc_events_malloc_failed(NULL);
return XETLSINIT;
}
mytls_vars->method_in_use = eaptype;
return XENONE;
}
/*************************************************************************
*
* Allocate a new context for OpenSSL.
*
**************************************************************************/
int tls_funcs_build_new_session(struct tls_vars *mytls_vars)
{
TRACE
if (!xsup_assert((mytls_vars != NULL), "mytls_vars != NULL", FALSE))
return XEMALLOC;
if (mytls_vars->ssl)
{
SSL_shutdown(mytls_vars->ssl);
}
if (mytls_vars->ssl)
{
SSL_free(mytls_vars->ssl);
mytls_vars->ssl = NULL;
}
if (mytls_vars->ctx == NULL)
{
debug_printf(DEBUG_NORMAL, "The SSL context is NULL. (This shouldn't happen.) Working around it.\n");
if (tls_funcs_init(mytls_vars, mytls_vars->method_in_use) != XENONE) return XETLSSTARTFAIL;
}
mytls_vars->ssl = SSL_new(mytls_vars->ctx);
if (!mytls_vars->ssl)
{
debug_printf(DEBUG_NORMAL, "Couldn't create SSL object!\n");
tls_funcs_process_error();
return XETLSSTARTFAIL;
}
return XENONE;
}
/*************************************************************************
*
* Handle processing of a start packet.
*
**************************************************************************/
int ossl_funcs_do_start(struct tls_vars *mytls_vars)
{
SSL_SESSION *sess = NULL;
unsigned long err;
int counter, resval = XENONE;
int mode = 0, ressize = 0;
uint8_t *tempdata = NULL;
TRACE
if (!xsup_assert((mytls_vars != NULL), "mytls_vars != NULL", FALSE))
return XEMALLOC;
debug_printf(DEBUG_TLS_CORE, "Got TLS Start!\n");
mytls_vars->resuming = 0;
if ((mytls_vars->ssl == NULL) || (mytls_vars->resume != RES_YES))
{
resval = tls_funcs_build_new_session(mytls_vars);
if (resval != XENONE)
{
debug_printf(DEBUG_NORMAL, "Error building a new session!\n");
return resval;
}
} else {
// We already established a connection, so we probably we need to
// resume the session.
if (mytls_vars->resume == RES_YES)
{
sess = SSL_get_session(mytls_vars->ssl);
if (!sess)
{
debug_printf(DEBUG_TLS_CORE, "Couldn't get session information!"
" We won't try to resume this session!\n");
mytls_vars->resuming = 0;
// Clear the old session data.
SSL_free(mytls_vars->ssl);
// Set up a new session.
resval = tls_funcs_build_new_session(mytls_vars);
if (resval != XENONE) return resval;
} else {
debug_printf(DEBUG_TLS_CORE, "Got session information, trying "
"to resume session!\n");
mytls_vars->resuming = 1;
// We don't want to send an alert to the other end.. So do a
// quiet shutdown. This violates the TLS standard, but it is
// needed to avoid confusing the other end of the connection
// when we want to do a reconnect!
SSL_set_quiet_shutdown(mytls_vars->ssl, 1);
// Now, close off our old session.
err = 0;
counter = 0;
SSL_shutdown(mytls_vars->ssl);
while ((err == 0) && (counter < 60))
{
err = SSL_shutdown(mytls_vars->ssl);
if (err == 0)
{
#ifndef WINDOWS
sleep(1);
#else
Sleep(1000);
#endif
counter++;
}
}
if (err < 0)
{
debug_printf(DEBUG_NORMAL, "Error trying to shut down SSL "
"context data.\n");
tls_funcs_process_error();
}
}
}
}
mytls_vars->ssl_in = BIO_new(BIO_s_mem());
if (!mytls_vars->ssl_in)
{
debug_printf(DEBUG_NORMAL, "Couldn't create ssl_in!\n");
tls_funcs_process_error();
ipc_events_malloc_failed(NULL);
return XETLSSTARTFAIL;
}
if (BIO_reset(mytls_vars->ssl_in) < 1)
{
debug_printf(DEBUG_NORMAL, "Error : %s:%d\n", __FUNCTION__, __LINE__);
tls_funcs_process_error();
}
mytls_vars->ssl_out = BIO_new(BIO_s_mem());
if (!mytls_vars->ssl_out)
{
debug_printf(DEBUG_NORMAL, "Couldn't create ssl_out!\n");
tls_funcs_process_error();
ipc_events_malloc_failed(NULL);
return XETLSSTARTFAIL;
}
if (BIO_reset(mytls_vars->ssl_out) < 0)
{
debug_printf(DEBUG_NORMAL, "Error : %s:%d\n", __FUNCTION__, __LINE__);
tls_funcs_process_error();
}
if (sess != NULL)
{
// If we have session information, we need to use it to resume the
// session.
debug_printf(DEBUG_TLS_CORE, "Attempting to resume session...\n");
if (SSL_set_session(mytls_vars->ssl, sess) <= 0)
{
debug_printf(DEBUG_NORMAL, "There was an error attempting to resume "
"the session!\n");
tls_funcs_process_error();
}
}
SSL_set_bio(mytls_vars->ssl, mytls_vars->ssl_in, mytls_vars->ssl_out);
// Set this to SSL_VERIFY_NONE if we don't want to do anything with a failed
// verification.
if (mytls_vars->verify_cert == TRUE)
{
mode = SSL_VERIFY_PEER;
}
else
{
mode = SSL_VERIFY_NONE;
}
SSL_set_verify(mytls_vars->ssl, mode, ssl_verify_callback);
err = SSL_connect(mytls_vars->ssl);
if (err < 0)
{
debug_printf(DEBUG_NORMAL, "Couldn't start handshake! Error was %d.\n",
err);
err = SSL_get_error(mytls_vars->ssl, err);
debug_printf(DEBUG_NORMAL, "Error : %d\n", err);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -