Files
m241Neelima/components/ip_net2-6.9/ipeap/src/ipeap_common_tls.c
T
2026-07-30 11:19:44 +05:30

556 lines
17 KiB
C

/*
******************************************************************************
* INTERPEAK SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipeap_common_tls.c,v $ $Revision: 1.6.10.2 $
* $Source: /home/interpeak/CVSRoot/ipeap/src/ipeap_common_tls.c,v $
* $Author: jli7 $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
* Design and implementation by Roger Boden <roger@interpeak.se>
******************************************************************************
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
*/
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
#include "ipeap_config.h"
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#include "ipeap_common_tls.h"
#include <ipcom_type.h>
#include <ipcom_cstyle.h>
#include "ipeap.h"
#include "ipeap_h.h"
#include <openssl/err.h>
/*
****************************************************************************
* 4 DEFINES
****************************************************************************
*/
/*
****************************************************************************
* 5 TYPES
****************************************************************************
*/
/*
****************************************************************************
* 6 EXTERN PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
/*
****************************************************************************
* 9 STATIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipeap_tls_suppl_ctx_free
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC void
ipeap_tls_suppl_ctx_free(Ipeap_tls_suppl_ctx *ctx)
{
if(!ctx)
return;
if(ctx->ssl_ctx)
SSL_CTX_free(ctx->ssl_ctx);
if(ctx->ssl)
SSL_free(ctx->ssl);
ipcom_memset(ctx, 0, sizeof(Ipeap_tls_suppl_ctx));
ipcom_free(ctx);
}
/*
*===========================================================================
* ipeap_tls_suppl_setup_ssl
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_err
ipeap_tls_suppl_setup_ssl(Ipeap_tls_suppl_ctx *ctx)
{
ctx->ssl = SSL_new(ctx->ssl_ctx);
if(!ctx->ssl)
{
IPCOM_LOG0(ERR, "ipeap_tls_suppl_setup_ssl :: SSL_new() failed");
return IPCOM_ERR_FAILED;
}
SSL_set_connect_state(ctx->ssl);
(void)SSL_set_options(ctx->ssl, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_SINGLE_DH_USE);
ctx->in_bio = BIO_new(BIO_s_mem());
ctx->out_bio = BIO_new(BIO_s_mem());
if(!ctx->in_bio || !ctx->out_bio)
{
if(ctx->in_bio)
(void)BIO_free(ctx->in_bio);
if(ctx->out_bio)
(void)BIO_free(ctx->out_bio);
IPCOM_LOG0(ERR, "ipeap_tls_suppl_setup_ssl :: BIO_s_mem() failed");
return IPCOM_ERR_FAILED;
}
SSL_set_bio(ctx->ssl, ctx->in_bio, ctx->out_bio);
return IPCOM_SUCCESS;
}
/*
****************************************************************************
* 10 GLOBAL FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipeap_common_tls_ctx_new
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ipeap_tls_suppl_ctx*
ipeap_common_tls_ctx_new(void)
{
Ipeap_tls_suppl_ctx *tls_suppl_ctx = IP_NULL;
EVP_PKEY *tls_key = IP_NULL;
X509 *tls_cert = IP_NULL;
tls_suppl_ctx = ipcom_malloc(sizeof(Ipeap_tls_suppl_ctx));
if(!tls_suppl_ctx)
return IP_NULL;
ipcom_memset(tls_suppl_ctx, 0, sizeof(Ipeap_tls_suppl_ctx));
tls_suppl_ctx->ssl_ctx = SSL_CTX_new(TLSv1_client_method());
if(!tls_suppl_ctx->ssl_ctx)
{
IPCOM_LOG0(ERR, "ipeap_tls_suppl_init :: SSL_CTX_new() failed");
goto error;
}
/* Load server key */
tls_key = ipeap_load_tls_key();
if(tls_key)
{
/* load server cert */
tls_cert = ipeap_load_tls_cert();
if(tls_cert)
{
/* Check that key and cert match */
if(X509_check_private_key(tls_cert, tls_key) != 1)
{
IPCOM_LOG0(ERR, "ipeap_tls_suppl_init :: X509_check_private_key() failed");
goto error;
}
if(!SSL_CTX_use_PrivateKey(tls_suppl_ctx->ssl_ctx, tls_key))
{
IPCOM_LOG0(ERR, "ipeap_tls_suppl_init :: SSL_CTX_use_PrivateKey() failed");
goto error;
}
if(!SSL_CTX_use_certificate(tls_suppl_ctx->ssl_ctx, tls_cert))
{
IPCOM_LOG0(ERR, "ipeap_tls_suppl_init :: SSL_CTX_use_certificate() failed");
goto error;
}
}
else
{
IPCOM_LOG0(WARNING, "No TLS X509 certificate loaded by ipwebs_load_tls_cert()");
}
}
else
{
IPCOM_LOG0(WARNING, "No TLS key loaded by ipeap_load_tls_key()");
}
if(tls_key)
EVP_PKEY_free(tls_key);
if(tls_cert)
X509_free(tls_cert);
/* Load CA certificates */
if(ipeap_load_ca_certs(tls_suppl_ctx->ssl_ctx->cert_store) == IPCOM_SUCCESS)
SSL_CTX_set_verify(tls_suppl_ctx->ssl_ctx, SSL_VERIFY_PEER, ipeap_tls_cert_verify);
else
{
IPCOM_LOG0(WARNING, "No TLS trusted certs loaded by ipeap_load_ca_certs(). Peer certificate validation turned off");
}
if(ipeap_tls_suppl_setup_ssl(tls_suppl_ctx) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipeap_tls_suppl_init :: ipeap_tls_suppl_setup_ssl() failed");
goto error;
}
return tls_suppl_ctx;
error:
ipeap_tls_suppl_ctx_free(tls_suppl_ctx);
if(tls_key)
EVP_PKEY_free(tls_key);
if(tls_cert)
X509_free(tls_cert);
return IP_NULL;
}
/*
*===========================================================================
* ipeap_common_tls_handle_frag_and_handshake
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipeap_common_tls_handle_frag_and_handshake(Ipeap_ctx *ctx, Ipeap_tls_suppl_ctx *tls_suppl_ctx, Ipeap_pkt *in_pkt, Ipeap_pkt *out_pkt)
{
Ipeap_tls_msg *msg;
int msg_len;
int rc;
int ssl_rc;
msg = IPEAP_PKT2TLSMSG(in_pkt);
ip_assert(msg->code == IPEAP_MSG_REQUEST);
/* Are we sending a fragmented packet? */
if(tls_suppl_ctx->frag_tot_len > 0)
return ipeap_common_tls_make_out_frag_pkt(tls_suppl_ctx, out_pkt, IPEAP_MSG_RESPONSE, msg->id, ctx->meth_id);
/* Write received data to SSL's input BIO */
if(msg->flags & IPEAP_TLS_FLAG_LEN_INCL)
msg_len = IP_GET_NTOHS(&msg->length) - 10; /* Remove header length*/
else
msg_len = IP_GET_NTOHS(&msg->length) - 6; /* Remove header length*/
if(msg_len > 0)
{
if(msg->flags & IPEAP_TLS_FLAG_LEN_INCL)
rc = BIO_write(tls_suppl_ctx->in_bio, msg->u.len_present.data, msg_len);
else
rc = BIO_write(tls_suppl_ctx->in_bio, msg->u.data, msg_len);
if(rc != msg_len)
{
IPCOM_LOG3(ERR, "%sFailed to write EAP fragment to SSL BIO, rc: %d, msg_len: %d",
ctx->syslog_prefix, rc, msg_len);
return IPCOM_ERR_FAILED;
}
}
/* If this is a fragmented packet, wait for remaining fragments to arrive */
if(msg->flags & IPEAP_TLS_FLAG_MORE_FRAG)
{
rc = ipeap_tls_pkt_set_header(out_pkt, IPEAP_PKT_RESPONSE, msg->id, 6, ctx->meth_id, 0);
out_pkt->end += 6;
if(rc != IPCOM_SUCCESS)
return rc;
return IPEAP_PENDING_SEND_OUT_PKT;
}
/* TODO: It should be possible to reset existing SSL context */
if(SSL_get_state(tls_suppl_ctx->ssl) == SSL_ST_OK)
{
if(msg->flags & IPEAP_TLS_FLAG_START)
{
IPCOM_LOG1(INFO, "%sRenegotiating SSL", ctx->syslog_prefix);
SSL_free(tls_suppl_ctx->ssl);
if(ipeap_tls_suppl_setup_ssl(tls_suppl_ctx) != IPCOM_SUCCESS)
{
IPCOM_LOG1(ERR, "%sipeap_tls_suppl_setup_ssl() failed", ctx->syslog_prefix);
return IPCOM_ERR_FAILED;
}
ctx->state = IPEAP_STATE_HANDSHAKE;
}
else
/* TLS handshake completed => we have received application data over the TLS connection */
return IPEAP_TLS_DATA_AVAILABLE;
}
ssl_rc = SSL_do_handshake(tls_suppl_ctx->ssl);
if(ssl_rc == 1)
{
IPCOM_LOG1(INFO, "%sTLS handshake successfully completed", ctx->syslog_prefix);
return IPEAP_TLS_HANDSHAKE_COMPLETE;
}
if(ssl_rc <= 0 && SSL_get_error(tls_suppl_ctx->ssl, ssl_rc) == SSL_ERROR_WANT_READ)
rc = ipeap_common_tls_make_out_frag_pkt(tls_suppl_ctx, out_pkt, IPEAP_MSG_RESPONSE, msg->id, ctx->meth_id);
else
{
IPCOM_LOG3(ERR, "%sTLS handshake failed, SSL_get_error(): %d, %s",
ctx->syslog_prefix, SSL_get_error(tls_suppl_ctx->ssl, ssl_rc),
ERR_error_string(ERR_get_error(), IP_NULL));
if(BIO_pending(tls_suppl_ctx->out_bio) > 0)
/* There is data in the out_bio, most likely an SSL alert. Send it to peer */
rc = ipeap_common_tls_make_out_frag_pkt(tls_suppl_ctx, out_pkt, IPEAP_MSG_RESPONSE, msg->id, ctx->meth_id);
else
{
/* No SSL data to send, make an empty ack packet */
rc = ipeap_tls_pkt_set_header(out_pkt, IPEAP_PKT_RESPONSE, msg->id, 6, ctx->meth_id, 0);
out_pkt->end += 6;
rc = IPEAP_PENDING_SEND_OUT_PKT;
}
}
ERR_clear_error();
ERR_remove_state(0);
return rc;
}
/*
*===========================================================================
* ipeap_tls_pkt_set_header
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipeap_tls_pkt_set_header(Ipeap_pkt *pkt, Ip_u8 code, Ip_u8 id, Ip_u16 len, Ip_u8 type, Ip_u8 flags)
{
Ip_err rc;
Ipeap_tls_msg* msg;
rc = ipeap_pkt_set_header(pkt, code, id, len, type);
if(rc != IPCOM_SUCCESS)
return rc;
msg = IPEAP_PKT2TLSMSG(pkt);
msg->flags = flags;
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipeap_common_tls_make_out_frag_pkt
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipeap_common_tls_make_out_frag_pkt(Ipeap_tls_suppl_ctx *ctx, Ipeap_pkt *pkt, Ip_u8 code, Ip_u8 id, Ip_u8 meth_id)
{
Ipeap_tls_msg* msg;
int bytes_left_to_send;
int tls_data_len;
Ip_u8 *out_buf;
Ip_err rc;
Ip_u8 flags = 0;
int header_size = 6;
msg = IPEAP_PKT2TLSMSG(pkt);
bytes_left_to_send = (int)BIO_ctrl_pending(ctx->out_bio);
if(bytes_left_to_send > IPEAP_MTU && ctx->frag_tot_len == 0)
{
/* This message must be fragmented and this is the first fragment */
ctx->frag_tot_len = bytes_left_to_send;
}
if(bytes_left_to_send > IPEAP_MTU)
flags |= IPEAP_TLS_FLAG_MORE_FRAG;
if(ctx->frag_tot_len != 0)
{
flags |= IPEAP_TLS_FLAG_LEN_INCL;
header_size = 10;
IP_SET_HTONL(msg->u.len_present.len, ctx->frag_tot_len);
out_buf = msg->u.len_present.data;
}
else
out_buf = msg->u.data;
tls_data_len = IP_MIN(bytes_left_to_send, IPEAP_MTU-header_size);
tls_data_len = IP_MIN(tls_data_len, IPEAP_PKT_GET_SPACE_LEFT(pkt));
if(BIO_read(ctx->out_bio, out_buf, tls_data_len) != tls_data_len)
{
IPCOM_LOG1(ERR, "ipeap_common_tls_make_out_frag_pkt :: failed to read %d bytes from out_bio", tls_data_len);
return IPCOM_ERR_FAILED;
}
rc = ipeap_tls_pkt_set_header(pkt, code, id, (Ip_u16)(tls_data_len+header_size), meth_id, flags);
if(rc != IPCOM_SUCCESS)
return rc;
if(flags & IPEAP_TLS_FLAG_LEN_INCL)
IP_SET_HTONL(msg->u.len_present.len, ctx->frag_tot_len);
if(BIO_ctrl_pending(ctx->out_bio) == 0)
ctx->frag_tot_len = 0; /* This is the last fragment, reset frag_tot_len */
pkt->end += header_size + tls_data_len; /* Add header and payload to length */
return IPEAP_PENDING_SEND_OUT_PKT;
}
/*
*===========================================================================
* ipeap_common_tls_ctx_free
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL void
ipeap_common_tls_ctx_free(Ipeap_tls_suppl_ctx *tls_suppl_ctx)
{
if(tls_suppl_ctx->ssl)
SSL_free(tls_suppl_ctx->ssl);
if(tls_suppl_ctx->ssl_ctx)
SSL_CTX_free(tls_suppl_ctx->ssl_ctx);
ipcom_free(tls_suppl_ctx);
ERR_clear_error();
ERR_remove_state(0);
}
/*
*===========================================================================
* ipeap_tls_common_generate_key
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipeap_tls_common_generate_key(Ipeap_tls_suppl_ctx *tls_suppl_ctx, const char* label, Ip_u8* key, int key_len)
{
Ip_u8 tmp_buf[2*SSL3_RANDOM_SIZE+40];
Ip_u8* tmp_out;
ip_assert(tls_suppl_ctx);
ip_assert(ipcom_strlen(label) < 40);
tmp_out = ipcom_malloc((Ip_size_t)key_len);
if(!tmp_out)
return IPCOM_ERR_FAILED;
ipcom_memcpy(tmp_buf, label, ipcom_strlen(label));
ipcom_memcpy(tmp_buf+ipcom_strlen(label), tls_suppl_ctx->ssl->s3->client_random, SSL3_RANDOM_SIZE);
ipcom_memcpy(tmp_buf+ipcom_strlen(label)+SSL3_RANDOM_SIZE, tls_suppl_ctx->ssl->s3->server_random, SSL3_RANDOM_SIZE);
#ifdef _WRS_CONFIG_COMPONENT_IPCRYPTO_OPENSSL_1_0_2
ipssl_tls1_PRF(TLS1_PRF,
tmp_buf, (int)ipcom_strlen(label)+2*SSL3_RANDOM_SIZE,
NULL, 0, NULL, 0, NULL, 0, NULL, 0,
tls_suppl_ctx->ssl->session->master_key, tls_suppl_ctx->ssl->session->master_key_length,
key, tmp_out, key_len);
#else
ipssl_tls1_PRF(EVP_md5(), EVP_sha1(),
tmp_buf, (int)ipcom_strlen(label)+2*SSL3_RANDOM_SIZE,
tls_suppl_ctx->ssl->session->master_key, tls_suppl_ctx->ssl->session->master_key_length,
key, tmp_out, key_len);
#endif
ipcom_free(tmp_out);
return IPCOM_SUCCESS;
}
IP_GLOBAL Ip_err
ipeap_tls_common_generate_session_id(Ipeap_tls_suppl_ctx *tls_suppl_ctx,Ip_u8 eap_type,Ip_u8 *session_id,Ip_u32 *session_id_len)
{
if (*session_id_len < IPEAP_TLS_SESSION_ID_LEN)
{
IPCOM_LOG3(ERR, "ipeap_tls_common_generate_session_id - not enough buffer is available to hold "
"the Session_Id for 0x%x , (%d wanted), (%d given )",eap_type,IPEAP_TLS_SESSION_ID_LEN , *session_id_len );
return IPCOM_ERR_INVALID_ARG;
}
if(eap_type!=IPEAP_TYPE_TLS && eap_type!= IPEAP_TYPE_TTLS && eap_type!=IPEAP_TYPE_PEAP)
{
IPCOM_LOG1(ERR, "ipeap_tls_common_generate_session_id - not a valid EAP TYPE 0x%x",eap_type);
return IPCOM_ERR_INVALID_ARG;
}
ipcom_memset(session_id, 0,*session_id_len);
session_id[0] = eap_type;
session_id += 1;
ipcom_memcpy(session_id, tls_suppl_ctx->ssl->s3->client_random, SSL3_RANDOM_SIZE);
ipcom_memcpy(session_id+SSL3_RANDOM_SIZE, tls_suppl_ctx->ssl->s3->server_random, SSL3_RANDOM_SIZE);
*session_id_len = IPEAP_TLS_SESSION_ID_LEN;
return IPCOM_SUCCESS;
}
/*
****************************************************************************
* 11 PUBLIC FUNCTIONS
****************************************************************************
*/
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/