📄 gnu_tls_funcs.c
字号:
/**
* TLS implementation using GNUTLS.
*
* Licensed under a dual GPL/BSD license. (See LICENSE file for more info.)
*
* \file gnu_tls_funcs.c
*
* \author chris@open1x.org
*
* $Id: gnu_tls_funcs.c,v 1.1.2.23 2007/04/20 18:35:54 chessing Exp $
* $Date: 2007/04/20 18:35:54 $
* $Log: gnu_tls_funcs.c,v $
* Revision 1.1.2.23 2007/04/20 18:35:54 chessing
* Work on the debug/trace output. Added a WHOLE BUNCH of new debug levels. Fixed a couple of small bugs, and cleaned out some cruft.
*
* Revision 1.1.2.22 2007/02/07 07:17:40 chessing
* Updated my e-mail address in all source files. Replaced strcpy() with a safer version. Updated Strncpy() to be a little safer.
*
**/
#ifdef USE_GNUTLS
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#ifdef WINDOWS
#include <winsock2.h>
#endif
#include "../../profile.h"
#include "../../eap_sm.h"
#include "eaptls.h"
#include "tls_funcs.h"
#include "../../xsup_common.h"
#include "../../xsup_err.h"
#include "../../xsup_debug.h"
#include "../../frame_structs.h"
static uint8_t inited = 0;
//#warning Add gnutls_alert code.
/**********************************************************************
*
* This callback function is used by GNU-TLS to put data in our buffer
* that we will need to send out. Other functions are responsible for
* actually sending the data. This function just queues it.
*
**********************************************************************/
ssize_t tls_funcs_push(gnutls_transport_ptr_t ptr,
const void *buf, size_t bufsiz)
{
struct tls_vars *mytls_vars;
mytls_vars = (struct tls_vars *)ptr;
mytls_vars->tlsoutdata = realloc(mytls_vars->tlsoutdata,
mytls_vars->tlsoutsize + bufsiz);
memcpy((uint8_t *)&mytls_vars->tlsoutdata[mytls_vars->tlsoutsize],
buf, bufsiz);
mytls_vars->tlsoutsize += bufsiz;
debug_printf(DEBUG_TLS_CORE, "There are now %d byte(s) in the waiting "
"buffer.\n", mytls_vars->tlsoutsize);
debug_printf(DEBUG_TLS_CORE, "Buffer dump (%d) : \n",
mytls_vars->tlsoutsize);
debug_hex_dump(DEBUG_TLS_CORE, mytls_vars->tlsoutdata,
mytls_vars->tlsoutsize);
return bufsiz;
}
/***********************************************************************
*
* This callback function is used by GNU-TLS to take data from our buffer
* and process it. Other functions are responsible for filling the buffer.
* This function just sends it to GNU-TLS.
*
***********************************************************************/
ssize_t tls_funcs_pull(gnutls_transport_ptr_t ptr,
void *buf, size_t bufsiz)
{
struct tls_vars *mytls_vars = NULL;
ssize_t retsize = 0;
mytls_vars = (struct tls_vars *)ptr;
debug_printf(DEBUG_TLS_CORE, "Total data in memory : %d byte(s)\n",
mytls_vars->tlsinsize);
// If we don't have anything to send, ask GNU-TLS to wait.
if (mytls_vars->tlsindata == NULL)
{
errno = EWOULDBLOCK;
return -1;
}
// Otherwise, return "bufsiz" (or less) worth of data.
if (mytls_vars->tlsinsize <= bufsiz)
{
// We can send everything we have.
memcpy((uint8_t *)buf, mytls_vars->tlsindata, mytls_vars->tlsinsize);
mytls_vars->tlsinptr = mytls_vars->tlsinsize;
retsize = mytls_vars->tlsinsize;
debug_printf(DEBUG_TLS_CORE, "Returned complete packet of %d byte(s) to"
" GNU-TLS.\n", retsize);
}
else
{
// Send a chunk.
retsize = (mytls_vars->tlsinsize - mytls_vars->tlsinptr);
if (retsize > bufsiz) retsize = bufsiz;
memcpy((uint8_t *)buf,
(uint8_t *)&mytls_vars->tlsindata[mytls_vars->tlsinptr],
retsize);
mytls_vars->tlsinptr += retsize;
debug_printf(DEBUG_TLS_CORE, "Returned a fragment of %d byte(s) to "
"GNU-TLS.\n", retsize);
}
if (mytls_vars->tlsinptr >= mytls_vars->tlsinsize)
{
debug_printf(DEBUG_TLS_CORE, "Finished with this data chunk. "
"Freeing.\n");
FREE(mytls_vars->tlsindata);
mytls_vars->tlsinptr = 0;
mytls_vars->tlsinsize = 0;
}
return retsize;
}
/***********************************************************************
*
* This callback function is used by GNU-TLS to allow us to do something
* with it's log data. The verbosity of the log data is configured in
* tls_funcs_init().
*
***********************************************************************/
void tls_log(int level, const char *logline)
{
debug_printf(DEBUG_NORMAL, "GNUTLS Log : %s\n", logline);
}
/***********************************************************************
*
* Do whatever we need to do in order to set up GNU-TLS and get it to the
* point that we can use it to authenticate.
*
***********************************************************************/
int tls_funcs_init(struct tls_vars *mytls_vars)
{
int err = 0;
int allowed_protos[3] = { GNUTLS_TLS1_0, GNUTLS_TLS1_1, 0};
int allowed_certs[2] = { GNUTLS_CRT_X509, 0 };
if (!xsup_assert((mytls_vars != NULL), "mytls_vars != NULL", FALSE))
return XEGENERROR;
debug_printf(DEBUG_TLS_CORE, "(TLS Engine : GNU) Initing\n");
//#warning Find a better way to handle this!
if (inited == 0)
{
debug_printf(DEBUG_TLS_CORE, "(TLS Engine) Doing global init!\n");
if (gnutls_global_init() != 0)
{
debug_printf(DEBUG_NORMAL, "Couldn't initialize GNU-TLS global state!\n");
return XEGENERROR;
}
gnutls_global_set_log_function(tls_log);
if (debug_getlevel() == DEBUG_TLS_CORE)
{
gnutls_global_set_log_level(10); // Maximum logging.
}
}
//#warning Session resume here!
if (mytls_vars->session != NULL)
{
// Clear any active sessions so we can start again.
debug_printf(DEBUG_TLS_CORE, "(TLS Engine) Cleaning up old session "
"data.\n");
gnutls_deinit(mytls_vars->session);
mytls_vars->handshake_done = FALSE;
}
if (gnutls_init(&mytls_vars->session, GNUTLS_CLIENT) != 0)
{
debug_printf(DEBUG_NORMAL, "Couldn't initialize the GNU-TLS library!\n");
return XEGENERROR;
}
err = gnutls_set_default_priority(mytls_vars->session);
if (err != 0)
{
debug_printf(DEBUG_NORMAL, "Using default priorities. : %s\n",
gnutls_strerror(err));
return XEGENERROR;
}
err = gnutls_certificate_type_set_priority(mytls_vars->session,
allowed_certs);
if (err != 0)
{
debug_printf(DEBUG_NORMAL, "Setting certificate type priorities : %s\n",
gnutls_strerror(err));
return XEGENERROR;
}
err = gnutls_protocol_set_priority(mytls_vars->session, allowed_protos);
if (err != 0)
{
debug_printf(DEBUG_NORMAL, "Setting allowed protocols : %s\n",
gnutls_strerror(err));
return XEGENERROR;
}
gnutls_transport_set_push_function(mytls_vars->session, tls_funcs_push);
gnutls_transport_set_pull_function(mytls_vars->session, tls_funcs_pull);
gnutls_transport_set_ptr(mytls_vars->session,
(gnutls_transport_ptr) mytls_vars);
err = gnutls_certificate_allocate_credentials(&mytls_vars->creds);
if (err != 0)
{
debug_printf(DEBUG_NORMAL, "Allocating credentials : %s\n",
gnutls_strerror(err));
return XEGENERROR;
}
return XENONE;
}
/*************************************************************************
*
* Load any root certificates that the user would want to use. Note :
* This functions differently than the older OpenSSL method.
*
*************************************************************************/
int tls_funcs_load_root_certs(struct tls_vars *mytls_vars,
char *root_cert, char *root_dir,
char *crl_dir)
{
int err = 0;
if (!xsup_assert((mytls_vars != NULL), "mytls_vars != NULL", FALSE))
return XEGENERROR;
//#warning Fix these!
if (root_dir != NULL)
{
debug_printf(DEBUG_NORMAL, "Certificate directories aren't supported "
"yet!\n");
// Continue in case a root_cert is also set.
}
if (crl_dir != NULL)
{
debug_printf(DEBUG_NORMAL, "CRL directories aren't supported yet!\n");
// Use gnutls_certificate_set_x509_crl_file()
// Continue, because this is non-fatal.
}
if (root_cert == NULL)
{
debug_printf(DEBUG_NORMAL, "You *MUST* specify a root CA "
"certificate!\n");
return XEGENERROR;
}
if (mytls_vars->creds == NULL)
{
debug_printf(DEBUG_NORMAL, "Couldn't allocate credentials.\n");
return XEGENERROR;
}
err = gnutls_certificate_set_x509_trust_file(mytls_vars->creds, root_cert,
GNUTLS_X509_FMT_PEM);
if (err < 1)
{
debug_printf(DEBUG_TLS_CORE, "Non-fatal error loading certificate (%d) "
": %s -- Trying to load as DER.\n", err,
gnutls_strerror(err));
// It may be a DER certificate. So try that instead.
err = gnutls_certificate_set_x509_trust_file(mytls_vars->creds,
root_cert,
GNUTLS_X509_FMT_DER);
if (err < 1)
{
debug_printf(DEBUG_NORMAL, "Error loading root CA certificate!\n");
return XEGENERROR;
}
}
return XENONE;
}
//#warning Need to add loading of random data functions.
/************************************************************************
*
* Load a user certificate in to GNU-TLS so that it can be used for
* authentication.
*
************************************************************************/
int tls_funcs_load_user_cert(struct tls_vars *mytls_vars, char *user_cert,
char *user_key, char *userpass)
{
gnutls_x509_privkey key;
uint8_t *certbuf;
FILE *fp;
size_t size;
gnutls_datum cert;
if (!xsup_assert((mytls_vars != NULL), "mytls_vars != NULL", FALSE))
return XEGENERROR;
if (user_cert == NULL)
{
debug_printf(DEBUG_NORMAL, "No user certificate to load!\n");
return XEGENERROR;
}
if (user_key == NULL)
{
debug_printf(DEBUG_NORMAL, "No user key file to load!\n");
return XEGENERROR;
}
if (userpass == NULL)
{
debug_printf(DEBUG_NORMAL, "No password provided!\n");
return XEGENERROR;
}
//#warning Need to import the user certificate.
gnutls_x509_privkey_init(&key);
certbuf = Malloc(64 * 1024);
if (certbuf == NULL)
{
debug_printf(DEBUG_NORMAL, "Couldn't allocate memory to store "
"user certificate.\n");
return XEMALLOC;
}
// Open the certificate key file.
fp = fopen(user_key, "r");
if (fp == NULL)
{
debug_printf(DEBUG_NORMAL, "Couldn't open file '%s'.\n");
return XEGENERROR;
}
size = fread(certbuf, 1, (64 * 1024)-1, fp);
if (ferror(fp) != 0)
{
debug_printf(DEBUG_NORMAL, "File read error at %s:%d!\n", __FUNCTION__,
__LINE__);
return XEGENERROR;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -