actube/src/cw/dtls_gnutls.c

242 lines
5.0 KiB
C
Raw Normal View History

/*
This file is part of libcapwap.
libcapwap is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
libcapwap is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <errno.h>
#include <gnutls/gnutls.h>
#include <gnutls/dtls.h>
#include "dtls_common.h"
#include "dtls_gnutls.h"
#include "conn.h"
#include "log.h"
#include "dbg.h"
#include "cw_util.h"
#include "timer.h"
int dtls_gnutls_init()
{
cw_dbg(DBG_INFO,"Init SSL library - using GnuTLS %s",gnutls_check_version(NULL));
gnutls_global_init();
return 1;
}
int dtls_gnutls_shutdown(struct conn *conn)
{
/* implement it */
return 1;
}
void dtls_gnutls_data_destroy(struct dtls_gnutls_data *d)
{
free(d);
}
int dtls_gnutls_write(struct conn * conn, const uint8_t *buffer, int len)
{
struct dtls_gnutls_data * d = conn->dtls_data;
int rc = gnutls_record_send(d->session,buffer,len);
if ( rc < 0 ){
cw_log(LOG_ERR, "DTLS - write error: %s", gnutls_strerror(rc));
conn->dtls_error=1;
errno=ECONNRESET;
return -1;
}
return rc;
}
int dtls_gnutls_read(struct conn * conn, uint8_t *buffer, int len)
{
uint8_t seq[8];
struct dtls_gnutls_data * d = conn->dtls_data;
int rc = gnutls_record_recv_seq(d->session,buffer,len,seq);
if (rc==0) {
errno = ECONNRESET;
return -1;
}
if ( rc == GNUTLS_E_AGAIN ){
errno = EAGAIN;
return -1;
}
if ( rc < 0 ){
cw_log(LOG_ERR, "DTLS - read error: %s", gnutls_strerror(rc));
conn->dtls_error=1;
errno=ECONNRESET;
return -1;
}
return rc;
}
static int verify_cert(gnutls_session_t sess)
{
cw_dbg(DBG_DTLS,"Verify cert");
return 0;
}
static void dtls_log_cb(int level, const char * str)
{
char buf[2048];
char *c;
if (!cw_dbg_is_level(DBG_DTLS_DETAIL))
return;
switch (level){
case 2:
case 6:
case 4:
return;
}
strcpy(buf,str);
c = strchr(buf,'\n');
*c=0;
cw_dbg(DBG_DTLS_DETAIL,"%s",buf);
}
struct dtls_gnutls_data *dtls_gnutls_data_create(struct conn *conn,int config)
{
const char *errpos;
int rc;
int bits;
struct dtls_gnutls_data *d = malloc(sizeof(struct dtls_gnutls_data));
if (!d)
return 0;
gnutls_global_set_log_level(10);
gnutls_global_set_log_function(dtls_log_cb);
gnutls_certificate_allocate_credentials(&d->x509_cred);
/* Set credentials */
if (conn->dtls_cert_file && conn->dtls_key_file){
rc = gnutls_certificate_set_x509_key_file(d->x509_cred, conn->dtls_cert_file,
conn->dtls_key_file, GNUTLS_X509_FMT_PEM);
if (rc < 0) {
cw_log(LOG_ERR, "DTLS - Can't set cert/key: %s", gnutls_strerror(rc));
dtls_gnutls_data_destroy(d);
return 0;
}
}
#if GNUTLS_VERSION_NUMBER >= 0x030100
bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, GNUTLS_SEC_PARAM_INSECURE);
#else
bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, GNUTLS_SEC_PARAM_WEAK);
#endif
/* Generate Diffie-Hellman parameters - for use with DHE
* kx algorithms. When short bit length is used, it might
* be wise to regenerate parameters often.
*/
gnutls_dh_params_init(&d->dh_params);
gnutls_dh_params_generate2(d->dh_params, bits);
gnutls_certificate_set_dh_params(d->x509_cred, d->dh_params);
/* Set ciphers */
rc = gnutls_priority_init(&d->priority_cache, conn->dtls_cipher, &errpos);
if (rc < 0) {
cw_log(LOG_ERR, "DTLS - Can't init ciphers '%s' at '%s' : %s", conn->dtls_cipher,
errpos, gnutls_strerror(rc));
dtls_gnutls_data_destroy(d);
return 0;
}
rc = gnutls_init(&d->session, config);
if (rc < 0) {
cw_log(LOG_ERR, "DTLS - Can't init session: %s", gnutls_strerror(rc));
dtls_gnutls_data_destroy(d);
return 0;
}
gnutls_transport_set_ptr(d->session, conn);
rc = gnutls_priority_set(d->session, d->priority_cache);
if (rc < 0) {
cw_log(LOG_ERR, "DTLS - Can't set priority: %s", gnutls_strerror(rc));
dtls_gnutls_data_destroy(d);
return 0;
}
rc = gnutls_credentials_set(d->session, GNUTLS_CRD_CERTIFICATE, d->x509_cred);
if (rc < 0) {
cw_log(LOG_ERR, "DTLS - Can't set credentials: %s", gnutls_strerror(rc));
dtls_gnutls_data_destroy(d);
return 0;
}
gnutls_certificate_set_verify_function(d->x509_cred,verify_cert);
gnutls_transport_set_pull_function(d->session, dtls_gnutls_bio_read);
gnutls_transport_set_push_function(d->session, dtls_gnutls_bio_write);
gnutls_transport_set_pull_timeout_function(d->session, dtls_gnutls_bio_wait);
#if GNUTLS_VERSION_NUMBER >= 0x030100
gnutls_handshake_set_timeout(d->session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
gnutls_dtls_set_data_mtu(d->session, conn->dtls_mtu);
#endif
gnutls_dtls_set_mtu(d->session, conn->dtls_mtu);
return d;
}