int dtls_try_handshake(struct openconnect_info *vpninfo) { int err = gnutls_handshake(vpninfo->dtls_ssl); if (!err) { #ifdef HAVE_GNUTLS_DTLS_SET_DATA_MTU /* Make sure GnuTLS's idea of the MTU is sufficient to take a full VPN MTU (with 1-byte header) in a data record. */ err = gnutls_dtls_set_data_mtu(vpninfo->dtls_ssl, vpninfo->ip_info.mtu + 1); if (err) { vpn_progress(vpninfo, PRG_ERR, _("Failed to set DTLS MTU: %s\n"), gnutls_strerror(err)); goto error; } #else /* If we don't have gnutls_dtls_set_data_mtu() then make sure we leave enough headroom by adding the worst-case overhead. We only support AES128-CBC and DES-CBC3-SHA anyway, so working out the worst case isn't hard. */ gnutls_dtls_set_mtu(vpninfo->dtls_ssl, vpninfo->ip_info.mtu + 1 /* packet + header */ + 13 /* DTLS header */ + 20 /* biggest supported MAC (SHA1) */ + 16 /* biggest supported IV (AES-128) */ + 16 /* max padding */); #endif vpninfo->dtls_state = DTLS_CONNECTED; vpn_progress(vpninfo, PRG_INFO, _("Established DTLS connection (using GnuTLS). Ciphersuite %s.\n"), vpninfo->dtls_cipher); vpninfo->dtls_times.last_rekey = vpninfo->dtls_times.last_rx = vpninfo->dtls_times.last_tx = time(NULL); /* XXX: For OpenSSL we explicitly prevent retransmits here. */ return 0; } if (err == GNUTLS_E_AGAIN) { if (time(NULL) < vpninfo->new_dtls_started + 12) return 0; vpn_progress(vpninfo, PRG_DEBUG, _("DTLS handshake timed out\n")); } vpn_progress(vpninfo, PRG_ERR, _("DTLS handshake failed: %s\n"), gnutls_strerror(err)); error: dtls_close(vpninfo); vpninfo->dtls_state = DTLS_SLEEPING; time(&vpninfo->new_dtls_started); return -EINVAL; }
struct dtls_gnutls_data *dtls_gnutls_data_create(struct conn *conn,int config) { const char *errpos; int rc; gnutls_datum_t key; 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); 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_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_LEGACY); /*#endif*/ /* 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_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_priority_set_direct(d->session,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_credentials_set(d->session, GNUTLS_CRD_CERTIFICATE, d->x509_cred); if (rc < 0) { cw_log(LOG_ERR, "DTLS - Can't set x.509 credentials: %s", gnutls_strerror(rc)); dtls_gnutls_data_destroy(d); return 0; } gnutls_certificate_set_verify_function(d->x509_cred,verify_cert); gnutls_session_set_ptr(d->session, conn); gnutls_transport_set_ptr(d->session, conn); 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; }
int dtls_try_handshake(struct openconnect_info *vpninfo) { int err = gnutls_handshake(vpninfo->new_dtls_ssl); if (!err) { #ifdef HAVE_GNUTLS_DTLS_SET_DATA_MTU /* Make sure GnuTLS's idea of the MTU is sufficient to take a full VPN MTU (with 1-byte header) in a data record. */ err = gnutls_dtls_set_data_mtu(vpninfo->new_dtls_ssl, vpninfo->ip_info.mtu + 1); if (err) { vpn_progress(vpninfo, PRG_ERR, _("Failed to set DTLS MTU: %s\n"), gnutls_strerror(err)); goto error; } #else /* If we don't have gnutls_dtls_set_data_mtu() then make sure we leave enough headroom by adding the worst-case overhead. We only support AES128-CBC and DES-CBC3-SHA anyway, so working out the worst case isn't hard. */ gnutls_dtls_set_mtu(vpninfo->new_dtls_ssl, vpninfo->ip_info.mtu + 1 /* packet + header */ + 13 /* DTLS header */ + 20 /* biggest supported MAC (SHA1) */ + 16 /* biggest supported IV (AES-128) */ + 16 /* max padding */); #endif vpn_progress(vpninfo, PRG_INFO, _("Established DTLS connection (using GnuTLS)\n")); dtls_close(vpninfo, 0); vpninfo->dtls_ssl = vpninfo->new_dtls_ssl; vpninfo->dtls_fd = vpninfo->new_dtls_fd; vpninfo->new_dtls_ssl = NULL; vpninfo->new_dtls_fd = -1; vpninfo->dtls_times.last_rx = vpninfo->dtls_times.last_tx = time(NULL); /* XXX: For OpenSSL we explicitly prevent retransmits here. */ return 0; } if (err == GNUTLS_E_AGAIN) { if (time(NULL) < vpninfo->new_dtls_started + 5) return 0; vpn_progress(vpninfo, PRG_TRACE, _("DTLS handshake timed out\n")); } vpn_progress(vpninfo, PRG_ERR, _("DTLS handshake failed: %s\n"), gnutls_strerror(err)); error: /* Kill both the new (failed) connection and the old one too. The only time there'll be a valid existing session is when it was a rekey, and in that case it's time for the old one to die. */ dtls_close(vpninfo, 1); time(&vpninfo->new_dtls_started); return -EINVAL; }