1113 lines
24 KiB
C
1113 lines
24 KiB
C
/*
|
|
******************************************************************************
|
|
* SOURCE FILE
|
|
*
|
|
* Document no: @(#) $ipftps_tls.c$ $RCSfile: ipftps_tls.c,v $ $Revision: 1.4.12.9 $
|
|
* $Source: /home/interpeak/CVSRoot/ipappl/src/ipftps_tls.c,v $
|
|
* $Author: yli10 $
|
|
* $State: Exp $ $Locker: $
|
|
*
|
|
* INTERPEAK_COPYRIGHT_STRING
|
|
* Design and implementation by Howard Xu <Hao.Xu@windriver.com>
|
|
******************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 1 DESCRIPTION
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 2 CONFIGURATION
|
|
****************************************************************************
|
|
*/
|
|
|
|
#include "ipftps_config.h"
|
|
|
|
#define IPCOM_USE_CLIB_PROTO
|
|
#include <ipcom_clib.h>
|
|
#include <ipcom_clib2.h>
|
|
#include <ipcom_err.h>
|
|
#include <ipcom_syslog.h>
|
|
#include <ipcom_sysvar.h>
|
|
|
|
#ifdef IPFTP_TLS
|
|
|
|
#include "ipftps.h"
|
|
#include <openssl/ssl.h>
|
|
|
|
#define IPFTPS_C
|
|
#include "ipftps_h.h"
|
|
|
|
#ifdef IPCOM_USE_KEY_DB
|
|
#define IPFTPS_USE_PRIVACY
|
|
IP_EXTERN Ip_err ipcom_key_db_pkey_import(const char* key_id, const EVP_PKEY* key);
|
|
IP_EXTERN EVP_PKEY* ipcom_key_db_pkey_get(const char* key_id);
|
|
#else
|
|
#warning " IPCOM_USE_KEY_DB is not defined !!"
|
|
#endif
|
|
|
|
|
|
IP_STATIC SSL_CTX *ipftps_tls_ctx = IP_NULL;
|
|
IP_GLOBAL int ipftps_tls_enbale = IP_FALSE;
|
|
|
|
typedef struct FTP_TLS
|
|
{
|
|
SSL *ctrlssl;
|
|
SSL *datassl;
|
|
Ip_bool dataflag;
|
|
Ip_bool ctrlflag;
|
|
Ip_bool ccc;
|
|
}ftp_tls;
|
|
|
|
IP_STATIC DH *get_dh512(void)
|
|
{
|
|
IP_STATIC unsigned char dh512_p[]={
|
|
0xF5,0x2A,0xFF,0x3C,0xE1,0xB1,0x29,0x40,0x18,0x11,0x8D,0x7C,
|
|
0x84,0xA7,0x0A,0x72,0xD6,0x86,0xC4,0x03,0x19,0xC8,0x07,0x29,
|
|
0x7A,0xCA,0x95,0x0C,0xD9,0x96,0x9F,0xAB,0xD0,0x0A,0x50,0x9B,
|
|
0x02,0x46,0xD3,0x08,0x3D,0x66,0xA4,0x5D,0x41,0x9F,0x9C,0x7C,
|
|
0xBD,0x89,0x4B,0x22,0x19,0x26,0xBA,0xAB,0xA2,0x5E,0xC3,0x55,
|
|
0xE9,0x2A,0x05,0x5F,
|
|
};
|
|
IP_STATIC unsigned char dh512_g[]={
|
|
0x02,
|
|
};
|
|
DH *dh;
|
|
|
|
if ((dh=DH_new()) == IP_NULL)
|
|
{
|
|
return IP_NULL;
|
|
}
|
|
dh->p=BN_bin2bn(dh512_p,sizeof(dh512_p),IP_NULL);
|
|
dh->g=BN_bin2bn(dh512_g,sizeof(dh512_g),IP_NULL);
|
|
|
|
if ((dh->p == IP_NULL) || (dh->g == IP_NULL))
|
|
{
|
|
DH_free(dh);
|
|
return IP_NULL;
|
|
}
|
|
return dh;
|
|
}
|
|
|
|
IP_STATIC DH *get_dh1024(void)
|
|
{
|
|
IP_STATIC unsigned char dh1024_p[]={
|
|
0xF4,0x88,0xFD,0x58,0x4E,0x49,0xDB,0xCD,0x20,0xB4,0x9D,0xE4,
|
|
0x91,0x07,0x36,0x6B,0x33,0x6C,0x38,0x0D,0x45,0x1D,0x0F,0x7C,
|
|
0x88,0xB3,0x1C,0x7C,0x5B,0x2D,0x8E,0xF6,0xF3,0xC9,0x23,0xC0,
|
|
0x43,0xF0,0xA5,0x5B,0x18,0x8D,0x8E,0xBB,0x55,0x8C,0xB8,0x5D,
|
|
0x38,0xD3,0x34,0xFD,0x7C,0x17,0x57,0x43,0xA3,0x1D,0x18,0x6C,
|
|
0xDE,0x33,0x21,0x2C,0xB5,0x2A,0xFF,0x3C,0xE1,0xB1,0x29,0x40,
|
|
0x18,0x11,0x8D,0x7C,0x84,0xA7,0x0A,0x72,0xD6,0x86,0xC4,0x03,
|
|
0x19,0xC8,0x07,0x29,0x7A,0xCA,0x95,0x0C,0xD9,0x96,0x9F,0xAB,
|
|
0xD0,0x0A,0x50,0x9B,0x02,0x46,0xD3,0x08,0x3D,0x66,0xA4,0x5D,
|
|
0x41,0x9F,0x9C,0x7C,0xBD,0x89,0x4B,0x22,0x19,0x26,0xBA,0xAB,
|
|
0xA2,0x5E,0xC3,0x55,0xE9,0x2F,0x78,0xC7,
|
|
};
|
|
IP_STATIC unsigned char dh1024_g[]={
|
|
0x02,
|
|
};
|
|
DH *dh;
|
|
|
|
if ((dh=DH_new()) == IP_NULL)
|
|
{
|
|
return IP_NULL;
|
|
}
|
|
|
|
dh->p=BN_bin2bn(dh1024_p,sizeof(dh1024_p),IP_NULL);
|
|
dh->g=BN_bin2bn(dh1024_g,sizeof(dh1024_g),IP_NULL);
|
|
|
|
if ((dh->p == IP_NULL) || (dh->g == IP_NULL))
|
|
{
|
|
DH_free(dh);
|
|
return IP_NULL;
|
|
}
|
|
return dh;
|
|
}
|
|
|
|
IP_STATIC RSA *get_rsa(const unsigned long key_length)
|
|
{
|
|
return RSA_generate_key(key_length, RSA_F4, IP_NULL, IP_NULL);
|
|
}
|
|
|
|
IP_STATIC RSA *ipftps_cb_rsa(SSL * const ctx,
|
|
const int for_export, const int key_length)
|
|
|
|
{
|
|
(void) ctx;
|
|
if (for_export == 0 || key_length >= 1024) {
|
|
return get_rsa(1024);
|
|
}
|
|
return get_rsa(512);
|
|
}
|
|
|
|
IP_STATIC DH *ipftps_cb_dh(SSL * const ctx, const int for_export,
|
|
const int key_length)
|
|
{
|
|
(void) ctx;
|
|
if (for_export == 0 || key_length >= 1024) {
|
|
return get_dh1024();
|
|
}
|
|
return get_dh512();
|
|
}
|
|
|
|
#if 0
|
|
IP_STATIC void ipftps_tls_init_cache(void)
|
|
{
|
|
IP_STATIC const char *tls_ctx_id = "ipftps";
|
|
|
|
SSL_CTX_set_session_cache_mode(ipftps_tls_ctx, SSL_SESS_CACHE_SERVER);
|
|
SSL_CTX_set_session_id_context(ipftps_tls_ctx, (unsigned char *) tls_ctx_id,
|
|
(unsigned int) strlen(tls_ctx_id));
|
|
SSL_CTX_sess_set_cache_size(ipftps_tls_ctx, 10);
|
|
SSL_CTX_set_timeout(ipftps_tls_ctx, 60 * 60L);
|
|
}
|
|
#endif
|
|
|
|
IP_STATIC int ipftps_tls_init_diffie(void)
|
|
{
|
|
DH *dh = IP_NULL;
|
|
BIO *bio = IP_NULL;
|
|
int ret = 0;
|
|
char *file = IP_NULL;
|
|
|
|
file = ipcom_sysvar_get("ipftps.tls.cert_file", IP_NULL, 0);
|
|
if(!file)
|
|
{
|
|
ipcom_printf("ipftps_load_tls_cert: "
|
|
"failed to get ipftps.tls.cert_file sysvar\n");
|
|
return -1;
|
|
}
|
|
|
|
if ((bio = BIO_new_file(file, "r")) == IP_NULL)
|
|
{
|
|
ipcom_printf("ipftps: Can't read [%s]\n", file);
|
|
ret = -1;
|
|
goto END;
|
|
}
|
|
if ((dh = PEM_read_bio_DHparams(bio, IP_NULL, IP_NULL
|
|
#if OPENSSL_VERSION_NUMBER >= 0x00904000L
|
|
, IP_NULL
|
|
#endif
|
|
)) == IP_NULL)
|
|
{
|
|
ret = 1;
|
|
goto END;
|
|
}
|
|
if (SSL_CTX_set_tmp_dh(ipftps_tls_ctx, dh) != 1)
|
|
{
|
|
ipcom_printf("ipftps: Can't set ephemeral keys\n");
|
|
ret = -1;
|
|
}
|
|
|
|
END:
|
|
|
|
ipcom_free(file);
|
|
if (dh != IP_NULL)
|
|
{
|
|
DH_free(dh);
|
|
}
|
|
if (bio != IP_NULL)
|
|
{
|
|
BIO_free(bio);
|
|
}
|
|
if (ret != 0)
|
|
{
|
|
SSL_CTX_set_tmp_dh_callback(ipftps_tls_ctx, ipftps_cb_dh);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipftps_key_db_pkey_save
|
|
*===========================================================================
|
|
*
|
|
* Description:
|
|
* Save private key to Key DB.
|
|
*
|
|
* Parameters:
|
|
* ret The returned value will make sure if saving key to DB is successful.
|
|
* Returns:
|
|
* IPCOM_SUCCESS if success, IPCOM_ERR_FAILED otherwise.
|
|
*/
|
|
IP_STATIC int ipftps_key_db_pkey_save(int *ret)
|
|
{
|
|
BIO* bio = IP_NULL;
|
|
char* file = IP_NULL;
|
|
EVP_PKEY* pkey = IP_NULL;
|
|
char * pfile = IP_NULL;
|
|
|
|
file = ipcom_sysvar_get("ipftps.tls.key_file", IP_NULL, 0);
|
|
|
|
if(!file)
|
|
{
|
|
ipcom_printf("ipftps_load_tls_key : failed to get "
|
|
"ipftps.tls.key_file sysvar");
|
|
*ret = 1;
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
pfile = file;
|
|
|
|
bio = BIO_new(BIO_s_file());
|
|
if(!bio)
|
|
goto cleanup;
|
|
|
|
if(!BIO_read_filename(bio, pfile))
|
|
goto cleanup;
|
|
|
|
pkey = PEM_read_bio_PrivateKey(bio, IP_NULL, IP_NULL, IP_NULL);
|
|
|
|
if (pkey == IP_NULL
|
|
|| (ipcom_key_db_pkey_import("ftpsPrivateKey", pkey) == IPCOM_ERR_FAILED))
|
|
goto cleanup;
|
|
|
|
if(file)
|
|
{
|
|
ipcom_free(file);
|
|
}
|
|
if(bio)
|
|
(void)BIO_free(bio);
|
|
|
|
return IPCOM_SUCCESS;
|
|
cleanup:
|
|
if(file)
|
|
{
|
|
ipcom_free(file);
|
|
}
|
|
if(bio)
|
|
(void)BIO_free(bio);
|
|
|
|
*ret = 1;
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
IP_STATIC int
|
|
ipftps_PEM_read_key_cb(char *buf, int num, int rwflag, void *key)
|
|
{
|
|
int i;
|
|
if (key)
|
|
{
|
|
i = ipcom_strlen(key);
|
|
i = (i > num) ? num : i;
|
|
ipcom_memcpy(buf, key, i);
|
|
*(buf+i) = 0x00;
|
|
return (i);
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipftps_load_tls_key
|
|
*===========================================================================
|
|
*
|
|
* Description:
|
|
* Load private key from configuration.
|
|
*
|
|
* Parameters:
|
|
* option option description
|
|
* Returns:
|
|
* private key struct pointer if success, IP_NULL otherwise.
|
|
*/
|
|
IP_STATIC EVP_PKEY *ipftps_load_tls_key(int option)
|
|
{
|
|
BIO* bio = IP_NULL;
|
|
EVP_PKEY* ret = IP_NULL;
|
|
char* file;
|
|
char* key = IP_NULL;
|
|
char* pfile;
|
|
|
|
#ifdef IPFTPS_USE_PRIVACY
|
|
if((ipcom_sysvar_get_as_int("ipftps.tls.private.enable", 0)==1) && (ipcom_sysvar_get_as_int("ipftps.tls.enable", 0)==1))
|
|
{
|
|
if(option == 0)
|
|
{
|
|
if((ret = ipcom_key_db_pkey_get((const char *)"ftpsPrivateKey"))==IP_NULL)
|
|
{
|
|
ipcom_printf("ipftps_load_tls_key_example : failed to retrieve ");
|
|
}
|
|
return ret;
|
|
}
|
|
else
|
|
file = ipcom_sysvar_get("ipftps.tls.key_file", IP_NULL, 0);
|
|
}else
|
|
#endif
|
|
|
|
file = ipcom_sysvar_get("ipftps.tls.key_file", IP_NULL, 0);
|
|
|
|
if(!file)
|
|
{
|
|
ipcom_printf("ipftps_load_tls_key : failed to get "
|
|
"ipftps.tls.key_file sysvar");
|
|
return IP_NULL;
|
|
}
|
|
|
|
pfile = file;
|
|
|
|
bio = BIO_new(BIO_s_file());
|
|
if(!bio)
|
|
goto cleanup;
|
|
|
|
if(!BIO_read_filename(bio, pfile))
|
|
goto cleanup;
|
|
|
|
key = ipcom_sysvar_get("ipftps.tls.secret.key", IP_NULL, 0);
|
|
|
|
if(key)
|
|
ret = PEM_read_bio_PrivateKey(bio, IP_NULL, ipftps_PEM_read_key_cb, key);
|
|
else
|
|
ret = PEM_read_bio_PrivateKey(bio, IP_NULL, IP_NULL, NULL);
|
|
|
|
cleanup:
|
|
if(file)
|
|
{
|
|
ipcom_free(file);
|
|
}
|
|
if(key)
|
|
{
|
|
ipcom_free(key);
|
|
}
|
|
if(bio)
|
|
(void)BIO_free(bio);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipftps_load_tls_cert
|
|
*===========================================================================
|
|
*
|
|
* Description:
|
|
* Load public key cert from configuration.
|
|
*
|
|
* Parameters: void
|
|
*
|
|
* Returns:
|
|
* Cert struct pointer if success, IP_NULL otherwise.
|
|
*/
|
|
IP_STATIC X509 *ipftps_load_tls_cert()
|
|
{
|
|
BIO* bio;
|
|
X509* ret = IP_NULL;
|
|
char* file;
|
|
char* pfile;
|
|
|
|
file = ipcom_sysvar_get("ipftps.tls.cert_file", IP_NULL, 0);
|
|
if(!file)
|
|
{
|
|
ipcom_printf("ipftps_load_tls_cert: "
|
|
"failed to get ipftps.tls.cert_file sysvar\n");
|
|
return IP_NULL;
|
|
}
|
|
|
|
pfile = file;
|
|
|
|
bio = BIO_new(BIO_s_file());
|
|
if(!bio)
|
|
goto cleanup;
|
|
|
|
if(!BIO_read_filename(bio, pfile) )
|
|
goto cleanup;
|
|
|
|
ret = PEM_read_bio_X509(bio, IP_NULL, IP_NULL, IP_NULL);
|
|
|
|
cleanup:
|
|
if(file)
|
|
{
|
|
ipcom_free(file);
|
|
}
|
|
if(bio)
|
|
(void)BIO_free(bio);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipftps_free_tls
|
|
*===========================================================================
|
|
*
|
|
* Description:
|
|
* Free TLS context for FTP server with TLS.
|
|
*
|
|
* Parameters: void
|
|
*
|
|
* Returns:
|
|
*/
|
|
IP_GLOBAL void ipftps_free_tls(void)
|
|
{
|
|
if (ipftps_tls_ctx != IP_NULL)
|
|
{
|
|
SSL_CTX_free(ipftps_tls_ctx);
|
|
ipftps_tls_ctx = IP_NULL;
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipftps_free_tls_session
|
|
*===========================================================================
|
|
*
|
|
* Description:
|
|
* Free TLS session for FTP server.
|
|
*
|
|
* Parameters:
|
|
* session FTP server session structure.
|
|
* Returns:
|
|
*/
|
|
IP_GLOBAL void ipftps_free_tls_session(Ipftps_session *session)
|
|
{
|
|
if(session->tlsopt != IP_NULL)
|
|
{
|
|
ipcom_free(session->tlsopt);
|
|
session->tlsopt = IP_NULL;
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipftps_init_tls_session
|
|
*===========================================================================
|
|
*
|
|
* Description:
|
|
* Alloc and initialize TLS session for FTP server.
|
|
*
|
|
* Parameters:
|
|
* session FTP server session structure.
|
|
* Returns:
|
|
*/
|
|
IP_GLOBAL int ipftps_init_tls_session(Ipftps_session *session)
|
|
{
|
|
ftp_tls * tls;
|
|
|
|
tls = (ftp_tls *)ipcom_malloc(sizeof(ftp_tls));
|
|
if(tls == IP_NULL)
|
|
{
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
tls->ctrlflag = IP_FALSE;
|
|
tls->ctrlssl = IP_NULL;
|
|
tls->dataflag = IP_FALSE;
|
|
tls->datassl = IP_NULL;
|
|
tls->ccc = IP_FALSE;
|
|
|
|
session->tlsopt = (void *)tls;
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipftps_init_tls
|
|
*===========================================================================
|
|
*
|
|
* Description:
|
|
* Initialize TLS context for FTP server.
|
|
*
|
|
* Parameters:
|
|
* Returns:
|
|
* IPCOM_SUCCESS if success, IPCOM_ERR_FAILED if fail.
|
|
*/
|
|
IP_GLOBAL int ipftps_init_tls(Ipftps_session *session)
|
|
{
|
|
EVP_PKEY *tls_key = IP_NULL;
|
|
X509 *tls_cert = IP_NULL;
|
|
char *strval;
|
|
int ret = 0;
|
|
int ssl_version;
|
|
|
|
if(ipftps_tls_ctx != IP_NULL)
|
|
{
|
|
/* already initialized TLS*/
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
if ((strval = ipcom_sysvar_get("ipftps.tls.enable", IP_NULL, IP_NULL)) == IP_NULL)
|
|
{
|
|
/* There is no sysvar about ftp with tls, so need use common ftp */
|
|
ipftps_tls_enbale = IP_FALSE;
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
ipftps_tls_enbale = ipcom_atoi(strval);
|
|
|
|
if(ipftps_tls_enbale == IP_FALSE)
|
|
{
|
|
ipcom_free(strval);
|
|
/* configuration disable ftp server with tls*/
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
ipcom_free(strval);
|
|
|
|
#ifdef IPFTPS_USE_PRIVACY
|
|
if ((strval = ipcom_sysvar_get("ipftps.tls.private.enable", IP_NULL, IP_NULL)) != IP_NULL)
|
|
{
|
|
if(ipcom_atoi(strval) == IP_TRUE)
|
|
{
|
|
ipftps_key_db_pkey_save(&ret);
|
|
}
|
|
ipcom_free(strval);
|
|
}
|
|
#endif
|
|
|
|
#ifdef _WRS_CONFIG_COMPONENT_IPCRYPTO_OPENSSL_1_0_2
|
|
ssl_version = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3
|
|
| SSL_OP_NO_TLSv1 |SSL_OP_NO_TLSv1_1;
|
|
#else
|
|
ssl_version = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
|
|
#endif
|
|
|
|
ipftps_tls_ctx = SSL_CTX_new(SSLv23_server_method());
|
|
|
|
if(ipftps_tls_ctx == IP_NULL)
|
|
{
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
SSL_CTX_set_options(ipftps_tls_ctx, SSL_OP_ALL | ssl_version);
|
|
tls_key = ipftps_load_tls_key(ret);
|
|
|
|
if(tls_key == IP_NULL)
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
tls_cert = ipftps_load_tls_cert();
|
|
if(tls_cert == IP_NULL)
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
if(X509_check_private_key(tls_cert, tls_key) != 1)
|
|
{
|
|
/*IPCOM_LOG0(ERR, "ipftps_init_tls: X509_check_private_key() failed");*/
|
|
goto error;
|
|
}
|
|
|
|
if(!SSL_CTX_use_PrivateKey(ipftps_tls_ctx, tls_key))
|
|
{
|
|
/*IPCOM_LOG0(ERR, "ipftps_init_tls: SSL_CTX_use_PrivateKey() failed");*/
|
|
goto error;
|
|
}
|
|
|
|
if(!SSL_CTX_use_certificate(ipftps_tls_ctx, tls_cert))
|
|
{
|
|
/*IPCOM_LOG0(ERR, "ipftps_init_tls: SSL_CTX_use_certificate() failed");*/
|
|
goto error;
|
|
}
|
|
|
|
SSL_CTX_set_tmp_rsa_callback(ipftps_tls_ctx, ipftps_cb_rsa);
|
|
|
|
if(ipftps_tls_init_diffie() == -1)
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
/*ipftps_tls_init_cache();*/
|
|
|
|
if(tls_key)
|
|
EVP_PKEY_free(tls_key);
|
|
if(tls_cert)
|
|
X509_free(tls_cert);
|
|
|
|
return IPCOM_SUCCESS;
|
|
error:
|
|
|
|
SSL_CTX_free(ipftps_tls_ctx);
|
|
ipftps_tls_ctx = IP_NULL;
|
|
if(tls_key)
|
|
EVP_PKEY_free(tls_key);
|
|
if(tls_cert)
|
|
X509_free(tls_cert);
|
|
|
|
return IPCOM_ERR_FAILED;
|
|
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipftps_create_new_tls_csession
|
|
*===========================================================================
|
|
*
|
|
* Description:
|
|
* Create a new TLS control session for FTP server.
|
|
*
|
|
* Parameters:
|
|
* session FTP server session structure.
|
|
* Returns:
|
|
* IPCOM_SUCCESS if success, IPCOM_ERR_FAILED if fail.
|
|
*/
|
|
IP_GLOBAL int ipftps_create_new_tls_csession(Ipftps_session *session)
|
|
{
|
|
int ret1,ret2;
|
|
ftp_tls *tls;
|
|
SSL_CIPHER *cipher;
|
|
|
|
tls = (ftp_tls *)(session->tlsopt);
|
|
|
|
if(tls == IP_NULL)
|
|
{
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
if(ipftps_tls_ctx == IP_NULL)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipftps_create_new_tls_csession: ipftps_tls_ctx() is NULL");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
if((tls->ctrlssl = SSL_new(ipftps_tls_ctx)) == IP_NULL)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipftps_create_new_tls_csession: SSL_new() Failed");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
if(SSL_set_fd(tls->ctrlssl, session->csock.fd) != 1)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipftps_create_new_tls_csession: SSL_set_fd() Failed");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
SSL_set_accept_state(tls->ctrlssl);
|
|
|
|
for(;;)
|
|
{
|
|
ret1 = SSL_accept(tls->ctrlssl);
|
|
if(ret1 < 0)
|
|
{
|
|
ret2 = SSL_get_error(tls->ctrlssl,ret1);
|
|
if(ret2 == SSL_ERROR_NONE
|
|
|| ret2 == SSL_ERROR_ZERO_RETURN
|
|
|| ret2 == SSL_ERROR_WANT_READ
|
|
|| ret2 == SSL_ERROR_WANT_WRITE)
|
|
{
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
IPCOM_LOG0(ERR, "ipftps_create_new_tls_csession: SSL_accept() Failed");
|
|
ipftps_tls_shutdown(session, IPFTPS_CTRL_FLAG);
|
|
SSL_free(tls->ctrlssl);
|
|
tls->ctrlssl = IP_NULL;
|
|
goto error;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ((cipher = SSL_get_current_cipher(tls->ctrlssl)) != IP_NULL)
|
|
{
|
|
int alg_bits;
|
|
int bits = SSL_CIPHER_get_bits(cipher, &alg_bits);
|
|
|
|
if (alg_bits < bits)
|
|
{
|
|
bits = alg_bits;
|
|
}
|
|
|
|
if (bits < 40)
|
|
{
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
return IPCOM_SUCCESS;
|
|
error:
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipftps_create_new_tls_dsession
|
|
*===========================================================================
|
|
*
|
|
* Description:
|
|
* Create a new TLS data session for FTP server.
|
|
*
|
|
* Parameters:
|
|
* session FTP server session structure.
|
|
* eno error number will be returned
|
|
* Returns:
|
|
* IPCOM_SUCCESS if success, IPCOM_ERR_FAILED if fail.
|
|
*/
|
|
IP_GLOBAL int ipftps_create_new_tls_dsession(Ipftps_session *session, int *eno)
|
|
{
|
|
int ret1,ret2;
|
|
ftp_tls *tls = (ftp_tls *)(session->tlsopt);
|
|
SSL_CIPHER *cipher;
|
|
|
|
if(tls == IP_NULL)
|
|
{
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
|
|
if(tls->dataflag != IP_TRUE)
|
|
{
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
if(ipftps_tls_ctx == IP_NULL)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipftps_create_new_tls_dsession: ipftps_tls_ctx is NULL");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
if((tls->datassl = SSL_new(ipftps_tls_ctx)) == IP_NULL)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipftps_create_new_tls_dsession: SSL_new() Failed");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
if(SSL_set_fd(tls->datassl, session->dsock.fd) != 1)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipftps_create_new_tls_dsession: SSL_set_fd() Failed");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
SSL_set_accept_state(tls->datassl);
|
|
|
|
for(;;)
|
|
{
|
|
ret1 = SSL_accept(tls->datassl);
|
|
if(ret1 < 0)
|
|
{
|
|
ret2 = SSL_get_error(tls->datassl,ret1);
|
|
if(ret2 == SSL_ERROR_NONE
|
|
|| ret2 == SSL_ERROR_ZERO_RETURN
|
|
|| ret2 == SSL_ERROR_WANT_READ
|
|
|| ret2 == SSL_ERROR_WANT_WRITE)
|
|
{
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
IPCOM_LOG0(ERR, "ipftps_create_new_tls_dsession: SSL_accept() Failed");
|
|
ipftps_tls_shutdown(session,IPFTPS_DATA_FLAG);
|
|
SSL_free(tls->datassl);
|
|
tls->datassl = IP_NULL;
|
|
*eno = ret2;
|
|
goto error;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ((cipher = SSL_get_current_cipher(tls->datassl)) != IP_NULL)
|
|
{
|
|
int alg_bits;
|
|
int bits = SSL_CIPHER_get_bits(cipher, &alg_bits);
|
|
|
|
if (alg_bits < bits)
|
|
{
|
|
bits = alg_bits;
|
|
}
|
|
|
|
if (bits < 40)
|
|
{
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
return IPCOM_SUCCESS;
|
|
error:
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipftps_tls_close_session
|
|
*===========================================================================
|
|
*
|
|
* Description:
|
|
* Close a new TLS session for FTP server.
|
|
*
|
|
* Parameters:
|
|
* session FTP server session structure.
|
|
* option IPFTPS_CTRL_FLAG for control session
|
|
* IPFTPS_DATA_FLAG for data session
|
|
* Returns:
|
|
*/
|
|
IP_GLOBAL void ipftps_tls_close_session(Ipftps_session *session, int option)
|
|
{
|
|
ftp_tls *tls = (ftp_tls *) (session->tlsopt);
|
|
|
|
if(tls == IP_NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
switch(option)
|
|
{
|
|
case IPFTPS_CTRL_FLAG:
|
|
if(tls->ctrlssl != IP_NULL)
|
|
{
|
|
SSL_shutdown(tls->ctrlssl);
|
|
SSL_free(tls->ctrlssl);
|
|
tls->ctrlssl = IP_NULL;
|
|
}
|
|
break;
|
|
case IPFTPS_DATA_FLAG:
|
|
if(tls->datassl != IP_NULL)
|
|
{
|
|
SSL_shutdown(tls->datassl);
|
|
SSL_free(tls->datassl);
|
|
tls->datassl = IP_NULL;
|
|
}
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipftps_tls_send
|
|
*===========================================================================
|
|
*
|
|
* Description:
|
|
* Send a ftp packet by TLS.
|
|
*
|
|
* Parameters:
|
|
* session FTP server session structure.
|
|
* fd Socket fd
|
|
* buf Buffer will be sent
|
|
* buflen The length of buffer
|
|
* Returns:
|
|
* 1 if fail; 0 if success; 2 if don't need TLS
|
|
*/
|
|
IP_GLOBAL int ipftps_tls_send(Ipftps_session *session, Ip_fd fd,char *buf, int buflen)
|
|
{
|
|
ftp_tls *tls = (ftp_tls *)(session->tlsopt);
|
|
|
|
if(tls == IP_NULL)
|
|
{
|
|
return 2;
|
|
}
|
|
|
|
if(fd == session->dsock.fd)
|
|
{
|
|
|
|
if(tls->dataflag == IP_TRUE)
|
|
{
|
|
if(SSL_write(tls->datassl, buf, buflen) != buflen)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
else
|
|
{
|
|
return 2;
|
|
}
|
|
}
|
|
|
|
if(fd == session->csock.fd)
|
|
{
|
|
|
|
if(tls->ctrlflag == IP_TRUE)
|
|
{
|
|
if(SSL_write(tls->ctrlssl, buf, buflen) != buflen)
|
|
{
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return 2;
|
|
}
|
|
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipftps_tls_read
|
|
*===========================================================================
|
|
*
|
|
* Description:
|
|
* Read a ftp packet by TLS.
|
|
*
|
|
* Parameters:
|
|
* session FTP server session structure.
|
|
* fd Socket fd
|
|
* buf Buffer will be for saving ftp packets
|
|
* buflen The length of buffer
|
|
* len Actual returned length
|
|
* Returns:
|
|
* 0 if success; 1 if don't need TLS
|
|
*/
|
|
IP_GLOBAL int ipftps_tls_read(Ipftps_session *session, Ip_fd fd,char *buf, int buflen, int *len)
|
|
{
|
|
ftp_tls *tls = (ftp_tls *)(session->tlsopt);
|
|
|
|
if(tls == IP_NULL)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
if(fd == session->dsock.fd)
|
|
{
|
|
if(tls->dataflag == IP_TRUE)
|
|
{
|
|
*len = SSL_read(tls->datassl, buf, buflen);
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if(fd == session->csock.fd)
|
|
{
|
|
if(tls->ctrlflag == IP_TRUE)
|
|
{
|
|
*len = SSL_read(tls->ctrlssl, buf, buflen);
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipftps_tls_set_flag
|
|
*===========================================================================
|
|
*
|
|
* Description:
|
|
* Set TLS flag for FTP server.
|
|
*
|
|
* Parameters:
|
|
* session FTP server session structure.
|
|
* option IPFTPS_CTRL_FLAG for TLS control session
|
|
* IPFTPS_DATA_FLAG for TLS data session
|
|
* flag IP_TRUE or IP_FALSE
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void ipftps_tls_set_flag(Ipftps_session *session, int option,Ip_bool flag)
|
|
{
|
|
ftp_tls *tls = (ftp_tls *)(session->tlsopt);
|
|
|
|
if(tls == IP_NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(option == IPFTPS_CTRL_FLAG)
|
|
{
|
|
tls->ctrlflag = flag;
|
|
}
|
|
|
|
if(option == IPFTPS_DATA_FLAG)
|
|
{
|
|
tls->dataflag = flag;
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipftps_tls_shutdown
|
|
*===========================================================================
|
|
*
|
|
* Description:
|
|
* shut down a TLS session for FTP server.
|
|
*
|
|
* Parameters:
|
|
* session FTP server session structure.
|
|
* option IPFTPS_CTRL_FLAG for TLS control session
|
|
* IPFTPS_DATA_FLAG for TLS data session
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void ipftps_tls_shutdown(Ipftps_session *session,int option)
|
|
{
|
|
ftp_tls *tls = (ftp_tls *)(session->tlsopt);
|
|
|
|
if(tls == IP_NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
switch(option)
|
|
{
|
|
case IPFTPS_CTRL_FLAG:
|
|
if(tls->ctrlssl != IP_NULL)
|
|
{
|
|
if(SSL_shutdown(tls->ctrlssl) == 0)
|
|
{
|
|
SSL_shutdown(tls->ctrlssl);
|
|
}
|
|
tls->ctrlflag = IP_FALSE;
|
|
}
|
|
break;
|
|
case IPFTPS_DATA_FLAG:
|
|
if(tls->datassl != IP_NULL)
|
|
{
|
|
if(SSL_shutdown(tls->datassl) == 0)
|
|
{
|
|
SSL_shutdown(tls->datassl);
|
|
}
|
|
tls->dataflag = IP_FALSE;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
|
|
IP_GLOBAL void ipftps_tls_set_ccc(Ipftps_session *session, Ip_bool flag)
|
|
{
|
|
ftp_tls *tls = (ftp_tls *)(session->tlsopt);
|
|
|
|
if(tls == IP_NULL)
|
|
{
|
|
return;
|
|
}
|
|
tls->ccc = flag;
|
|
return;
|
|
}
|
|
|
|
IP_GLOBAL Ip_bool ipftps_tls_get_ccc(Ipftps_session *session)
|
|
{
|
|
ftp_tls *tls = (ftp_tls *)(session->tlsopt);
|
|
|
|
if(tls == IP_NULL)
|
|
{
|
|
return IP_FALSE;
|
|
}
|
|
|
|
return (tls->ccc);
|
|
}
|
|
|
|
#endif
|