2014-08-03 08:46:42 +02:00
|
|
|
/*
|
|
|
|
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/>.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
2015-02-08 16:28:04 +01:00
|
|
|
#include <stdlib.h>
|
2015-04-10 17:14:55 +02:00
|
|
|
#include <errno.h>
|
2014-08-03 08:46:42 +02:00
|
|
|
|
|
|
|
#include <gnutls/gnutls.h>
|
2016-03-12 22:30:12 +01:00
|
|
|
#include <gnutls/dtls.h>
|
2014-08-03 08:46:42 +02:00
|
|
|
|
2018-03-03 17:42:28 +01:00
|
|
|
#include "mbag.h"
|
2018-03-02 00:12:38 +01:00
|
|
|
#include "dtls_common.h"
|
2015-02-08 16:28:04 +01:00
|
|
|
#include "dtls_gnutls.h"
|
|
|
|
|
|
|
|
#include "conn.h"
|
2015-04-10 17:52:01 +02:00
|
|
|
#include "log.h"
|
2015-04-11 19:00:51 +02:00
|
|
|
#include "dbg.h"
|
2015-02-08 16:28:04 +01:00
|
|
|
#include "cw_util.h"
|
2015-04-11 19:00:51 +02:00
|
|
|
#include "timer.h"
|
2014-08-03 08:46:42 +02:00
|
|
|
|
|
|
|
int dtls_gnutls_init()
|
|
|
|
{
|
2015-04-11 19:00:51 +02:00
|
|
|
cw_dbg(DBG_INFO,"Init SSL library - using GnuTLS %s",gnutls_check_version(NULL));
|
2014-08-03 08:46:42 +02:00
|
|
|
gnutls_global_init();
|
|
|
|
return 1;
|
|
|
|
}
|
2015-02-08 16:28:04 +01:00
|
|
|
|
2015-02-08 21:07:55 +01:00
|
|
|
int dtls_gnutls_shutdown(struct conn *conn)
|
|
|
|
{
|
|
|
|
/* implement it */
|
|
|
|
return 1;
|
|
|
|
}
|
2015-02-08 16:28:04 +01:00
|
|
|
|
|
|
|
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;
|
2015-04-12 10:19:02 +02:00
|
|
|
errno=ECONNRESET;
|
2015-02-08 16:28:04 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int dtls_gnutls_read(struct conn * conn, uint8_t *buffer, int len)
|
|
|
|
{
|
2015-03-09 23:51:13 +01:00
|
|
|
uint8_t seq[8];
|
|
|
|
|
2015-02-08 16:28:04 +01:00
|
|
|
struct dtls_gnutls_data * d = conn->dtls_data;
|
2015-03-09 23:51:13 +01:00
|
|
|
int rc = gnutls_record_recv_seq(d->session,buffer,len,seq);
|
2015-02-08 16:28:04 +01:00
|
|
|
|
2015-04-10 17:14:55 +02:00
|
|
|
if (rc==0) {
|
|
|
|
errno = ECONNRESET;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( rc == GNUTLS_E_AGAIN ){
|
|
|
|
errno = EAGAIN;
|
|
|
|
return -1;
|
|
|
|
}
|
2015-02-08 16:28:04 +01:00
|
|
|
|
|
|
|
if ( rc < 0 ){
|
|
|
|
cw_log(LOG_ERR, "DTLS - read error: %s", gnutls_strerror(rc));
|
|
|
|
conn->dtls_error=1;
|
2015-04-12 10:19:02 +02:00
|
|
|
errno=ECONNRESET;
|
2015-02-08 16:28:04 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-03-12 16:12:36 +01:00
|
|
|
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)
|
|
|
|
{
|
|
|
|
if (!cw_dbg_is_level(DBG_DTLS_DETAIL))
|
|
|
|
return;
|
|
|
|
|
|
|
|
switch (level){
|
|
|
|
case 2:
|
|
|
|
case 6:
|
|
|
|
case 4:
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
char buf[2048];
|
|
|
|
strcpy(buf,str);
|
|
|
|
char *c = strchr(buf,'\n');
|
|
|
|
*c=0;
|
|
|
|
cw_dbg(DBG_DTLS_DETAIL,"%s",buf);
|
|
|
|
}
|
|
|
|
|
2015-02-08 21:07:55 +01:00
|
|
|
struct dtls_gnutls_data *dtls_gnutls_data_create(struct conn *conn,int config)
|
2015-02-08 16:28:04 +01:00
|
|
|
{
|
|
|
|
struct dtls_gnutls_data *d = malloc(sizeof(struct dtls_gnutls_data));
|
|
|
|
if (!d)
|
|
|
|
return 0;
|
|
|
|
|
2016-03-12 16:12:36 +01:00
|
|
|
gnutls_global_set_log_level(10);
|
|
|
|
gnutls_global_set_log_function(dtls_log_cb);
|
|
|
|
|
2015-02-08 16:28:04 +01:00
|
|
|
gnutls_certificate_allocate_credentials(&d->x509_cred);
|
|
|
|
|
|
|
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
/* Set credentials */
|
|
|
|
|
2016-03-05 08:47:47 +01:00
|
|
|
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;
|
|
|
|
}
|
2015-02-08 16:28:04 +01:00
|
|
|
}
|
|
|
|
|
2015-03-09 23:51:13 +01:00
|
|
|
|
|
|
|
|
|
|
|
int bits;
|
2015-04-30 08:36:40 +02:00
|
|
|
#if GNUTLS_VERSION_NUMBER >= 0x030100
|
2015-03-09 23:51:13 +01:00
|
|
|
bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, GNUTLS_SEC_PARAM_INSECURE);
|
2015-04-30 18:58:56 +02:00
|
|
|
#else
|
2015-04-30 08:36:40 +02:00
|
|
|
bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, GNUTLS_SEC_PARAM_WEAK);
|
|
|
|
#endif
|
2015-03-09 23:51:13 +01:00
|
|
|
/* 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);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2015-02-08 16:28:04 +01:00
|
|
|
/* Set ciphers */
|
|
|
|
const char *errpos;
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-02-08 21:07:55 +01:00
|
|
|
rc = gnutls_init(&d->session, config);
|
2015-02-08 16:28:04 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2016-03-12 16:12:36 +01:00
|
|
|
gnutls_certificate_set_verify_function(d->x509_cred,verify_cert);
|
|
|
|
|
2015-02-08 16:28:04 +01:00
|
|
|
|
|
|
|
gnutls_transport_set_pull_function(d->session, dtls_gnutls_bio_read);
|
|
|
|
gnutls_transport_set_push_function(d->session, dtls_gnutls_bio_write);
|
2015-02-08 21:07:55 +01:00
|
|
|
gnutls_transport_set_pull_timeout_function(d->session, dtls_gnutls_bio_wait);
|
2015-02-08 16:28:04 +01:00
|
|
|
|
2016-03-12 22:30:12 +01:00
|
|
|
|
|
|
|
#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);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2015-02-08 16:28:04 +01:00
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
|
|
|
|