📄 gnu_tls_funcs.c
字号:
fclose(fp);
cert.data = certbuf;
cert.size = size;
if (gnutls_x509_privkey_import(key, &cert, GNUTLS_X509_FMT_PEM) != 0)
{
debug_printf(DEBUG_TLS_CORE, "Couldn't load certificate as PEM! (With"
" no password.) Trying DER.\n");
if (gnutls_x509_privkey_import(key, &cert, GNUTLS_X509_FMT_DER) != 0)
{
debug_printf(DEBUG_TLS_CORE, "Couldn't load certificate as DER! "
"(With no password.) Trying PEM with password.\n");
if (gnutls_x509_privkey_import_pkcs8(key, &cert,
GNUTLS_X509_FMT_PEM, userpass,
0) != 0)
{
debug_printf(DEBUG_TLS_CORE, "Couldn't load certificate as PEM"
" with password! Trying DER with password!\n");
if (gnutls_x509_privkey_import_pkcs8(key, &cert,
GNUTLS_X509_FMT_DER,
userpass, 0) != 0)
{
debug_printf(DEBUG_TLS_CORE, "Couldn't load certificate as "
"encrypted DER with password! Trying as "
"unencrypted DER with password!\n");
if (gnutls_x509_privkey_import_pkcs8(key, &cert,
GNUTLS_X509_FMT_DER,
userpass,
GNUTLS_PKCS_PLAIN) != 0)
{
debug_printf(DEBUG_TLS_CORE, "Couldn't load certficate"
" in any way we know of! Your certificate"
" is either incorrect, or has issues.\n");
return XEGENERROR;
}
}
}
}
}
//#warning Need to set a flag so that we can clean up the privkey import when we shut down.
return XENONE;
}
/**********************************************************************
*
* This function is called when we recieve a start request (0x20) from
* the server. It should finalize credentials, and begin the handshake.
*
**********************************************************************/
int gnutls_funcs_do_start(struct tls_vars *mytls_vars)
{
int err = 0;
err = gnutls_credentials_set(mytls_vars->session, GNUTLS_CRD_CERTIFICATE,
mytls_vars->creds);
if (err != 0)
{
debug_printf(DEBUG_NORMAL, "Couldn't enable credentials. Error was : "
"%s\n", gnutls_strerror(err));
return XEGENERROR;
}
err = gnutls_handshake(mytls_vars->session);
if ((err != 0) && (err != GNUTLS_E_AGAIN))
{
debug_printf(DEBUG_NORMAL, "Couldn't start handshake! Error was (%d): "
"%s\n", err, gnutls_strerror(err));
return XEGENERROR;
}
return XENONE;
}
/*************************************************************************
*
* Verify that the common name field of a certificate matches a user defined
* value. If exact == TRUE, then it must match exactly. Otherwise, it
* must only contain the substring specified by the user.
*
*************************************************************************/
uint8_t tls_funcs_check_cn(char *cn, char *tomatch, uint8_t exact)
{
if (exact == TRUE)
{
// Check for an exact match.
if (strcmp(cn, tomatch) == 0) return TRUE;
}
else
{
//#warning We should do some additional checks to be sure the substring is at the tail end of the string. Otherwise a search for "monkey.com" would also match "monkey.com.com" or similar.
// Check for a substring match.
if (strstr(cn, tomatch) != NULL) return TRUE;
}
return FALSE;
}
/*************************************************************************
*
* Do a bunch of different checks against the certificate chain that we
* have.
*
*************************************************************************/
int verify_certificate(gnutls_session_t session, char *common_name,
uint8_t exact_match)
{
unsigned int status;
const gnutls_datum_t *cert_list;
int cert_list_size, ret, retval = XENONE;
gnutls_x509_crt_t cert;
char dnsname[256];
size_t dnsnamesize;
/* This verification function uses the trusted CAs in the credentials
* structure. So you must have installed one or more CA certificates.
*/
ret = gnutls_certificate_verify_peers2 (session, &status);
if (ret < 0)
{
debug_printf(DEBUG_NORMAL, "Error checking certificate!\n");
debug_printf(DEBUG_NORMAL, "Error was (%d) : %s\n", ret,
gnutls_strerror(ret));
return XEGENERROR;
}
if (status & GNUTLS_CERT_INVALID)
debug_printf(DEBUG_NORMAL, "The certificate is not trusted.\n");
if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
debug_printf(DEBUG_NORMAL, "The certificate hasn't got a known issuer.\n");
if (status & GNUTLS_CERT_REVOKED)
debug_printf(DEBUG_NORMAL, "The certificate has been revoked.\n");
if (status != 0)
{
debug_printf(DEBUG_NORMAL, "Certificate checks failed!\n");
return XEGENERROR;
}
/* Up to here the process is the same for X.509 certificates and
* OpenPGP keys. From now on X.509 certificates are assumed. This can
* be easily extended to work with openpgp keys as well.
*/
if (gnutls_certificate_type_get (session) != GNUTLS_CRT_X509)
{
debug_printf(DEBUG_NORMAL, "Certificate is not a valid x.509 "
"certificate!\n");
return XEGENERROR;
}
if (gnutls_x509_crt_init (&cert) < 0)
{
debug_printf (DEBUG_NORMAL, "Error initializing certificate "
"structures.\n");
retval = XEGENERROR;
goto deinit;
}
cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
if (cert_list == NULL)
{
debug_printf (DEBUG_NORMAL, "The server didn't send us any "
"certificates.\n");
retval = XEGENERROR;
goto deinit;
}
/* This is not a real world example, since we only check the first
* certificate in the given chain.
*/
if (gnutls_x509_crt_import (cert, &cert_list[0], GNUTLS_X509_FMT_DER) < 0)
{
debug_printf (DEBUG_NORMAL, "Error parsing certificate.\n");
retval = XEGENERROR;
goto deinit;
}
/* Beware here we do not check for errors.
*/
if (gnutls_x509_crt_get_expiration_time (cert) < time (0))
{
debug_printf (DEBUG_NORMAL, "The certificate has expired!\n");
retval = XEGENERROR;
goto deinit;
}
if (gnutls_x509_crt_get_activation_time (cert) > time (0))
{
debug_printf (DEBUG_NORMAL, "The certificate is not yet activated!\n");
retval = XEGENERROR;
goto deinit;
}
dnsnamesize = sizeof(dnsname);
if (gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0,
0, dnsname, &dnsnamesize) < 0)
{
debug_printf(DEBUG_NORMAL, "Couldn't find a common name field in the "
"certificate!\n");
retval = XEGENERROR;
goto deinit;
}
debug_printf(DEBUG_TLS_CORE, "CN = %s\n", dnsname);
if (common_name != NULL)
{
// We need to do a match.
if (tls_funcs_check_cn(dnsname, common_name, exact_match) != TRUE)
{
if (exact_match == TRUE)
{
debug_printf(DEBUG_NORMAL, "The certificate's common name did "
"not match! You asked that the certificate's CN "
"match '%s' exactly. But, the certificate's CN "
"was '%s'.\n", common_name, dnsname);
}
else
{
debug_printf(DEBUG_NORMAL, "The certificate's common name did "
"not match! You asked that the certificate's CN "
"contain '%s'. But, the certificate's CN was "
"'%s'.\n", common_name, dnsname);
}
retval = XEGENERROR;
goto deinit;
}
}
deinit:
gnutls_x509_crt_deinit (cert);
return retval;
}
/************************************************************************
*
* This function is called to process packets that aren't start packets.
*
************************************************************************/
uint8_t gnutls_funcs_process_other(struct tls_vars *mytls_vars,
uint8_t *eappacket)
{
uint8_t *cur = NULL;
uint32_t resp_size, packet_size;
struct eap_header *eaphdr;
int err = 0;
uint8_t temp;
if (!xsup_assert((mytls_vars != NULL), "mytls_vars != NULL", FALSE))
return EAP_FAIL;
if (!xsup_assert((eappacket != NULL), "eappacket != NULL", FALSE))
return EAP_FAIL;
// Assume we aren't going to send an ACK, until we actually decide we are.
mytls_vars->send_ack = FALSE;
eaphdr = (struct eap_header *)eappacket;
packet_size = ntohs(eaphdr->eap_length);
// First, process the byte that follows the EAP header.
cur = (uint8_t *)&eappacket[sizeof(struct eap_header)];
packet_size -= sizeof(struct eap_header);
temp = cur[0];
if ((temp == EAPTLS_ACK) && (packet_size <= (sizeof(struct eap_header)+1)))
{
debug_printf(DEBUG_TLS_CORE, "Got an ACK. (Packet size = %d)\n",
packet_size);
return CONT;
}
cur++;
packet_size--;
if (temp & EAPTLS_LENGTH_INCL)
{
// Grab out the total size of the response.
memcpy(&resp_size, cur, sizeof(uint32_t));
resp_size = ntohl(resp_size);
debug_printf(DEBUG_TLS_CORE, "Expecting %d byte(s) worth of response."
"\n", resp_size);
mytls_vars->tlsinsize = resp_size;
packet_size -= 4;
cur += 4;
}
debug_printf(DEBUG_TLS_CORE, "Copying (%d) : \n", packet_size);
debug_hex_dump(DEBUG_TLS_CORE, cur, packet_size);
// If there are more fragments coming, our response should be an ACK.
if (temp & EAPTLS_MORE_FRAGS) mytls_vars->send_ack = TRUE;
mytls_vars->tlsindata = realloc(mytls_vars->tlsindata,
(mytls_vars->tlsinptr + packet_size));
if (mytls_vars->tlsindata == NULL)
{
debug_printf(DEBUG_NORMAL, "There was an error getting enough memory "
"to hold the packet fragment.\n");
return EAP_FAIL;
}
memcpy((uint8_t *)&mytls_vars->tlsindata[mytls_vars->tlsinptr],
cur, packet_size);
debug_printf(DEBUG_TLS_CORE, "Copied %d byte(s) to our buffer.\n",
packet_size);
mytls_vars->tlsinptr += packet_size;
if (mytls_vars->send_ack == FALSE)
{
if (mytls_vars->tlsinptr != mytls_vars->tlsinsize)
{
debug_printf(DEBUG_NORMAL, "The data we got was not the same size "
"as the data we were expecting! (Current offset %d, "
"expected offset %d.)\n", mytls_vars->tlsinptr,
mytls_vars->tlsinsize);
// We should have already freed our buffer before now, so just
// clear these values.
mytls_vars->tlsinptr = 0;
mytls_vars->tlsinsize = 0;
return XEGENERROR;
}
mytls_vars->tlsinptr = 0;
err = gnutls_handshake(mytls_vars->session);
if ((err != 0) && (err != GNUTLS_E_AGAIN))
{
debug_printf(DEBUG_NORMAL, "Couldn't continue handshake! Error was "
"(%d): %s\n", err, gnutls_strerror(err));
return XEGENERROR;
}
if (err == 0)
{
// The handshake is complete.
mytls_vars->handshake_done = TRUE;
if (mytls_vars->verify_cert == TRUE)
{
if (verify_certificate(mytls_vars->session, mytls_vars->cncheck,
mytls_vars->cnexact) != XENONE)
{
return XEGENERROR;
}
}
}
}
return XENONE;
}
/**************************************************************************
*
* This function processes the packets, and decides if it is a start, or
* another type of packet. It then calls the appropriate handler function.
*
***************************************************************************/
uint8_t tls_funcs_process(struct tls_vars *mytls_vars, uint8_t *eappacket)
{
if (eappacket[sizeof(struct eap_header)] == EAPTLS_START)
{
gnutls_funcs_do_start(mytls_vars);
return CONT;
}
else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -