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 void client(int fd) { gnutls_session_t session; int ret; char buffer[MAX_BUF + 1]; gnutls_anon_client_credentials_t anoncred; unsigned char seq[8]; uint32_t useq; memset(buffer, 0, sizeof(buffer)); /* Need to enable anonymous KX specifically. */ /* gnutls_global_set_audit_log_function (tls_audit_log_func); */ global_init(); if (debug) { gnutls_global_set_log_function(client_log_func); gnutls_global_set_log_level(2); } gnutls_anon_allocate_client_credentials(&anoncred); /* Initialize TLS session */ gnutls_init(&session, GNUTLS_CLIENT | GNUTLS_DATAGRAM); gnutls_dtls_set_timeouts(session, 50 * 1000, 600 * 1000); gnutls_heartbeat_enable(session, GNUTLS_HB_PEER_ALLOWED_TO_SEND); gnutls_dtls_set_mtu(session, 1500); /* Use default priorities */ gnutls_priority_set_direct(session, "NONE:+VERS-DTLS1.0:+CIPHER-ALL:+MAC-ALL:+SIGN-ALL:+COMP-ALL:+ANON-ECDH:+CURVE-ALL", NULL); /* put the anonymous credentials to the current session */ gnutls_credentials_set(session, GNUTLS_CRD_ANON, anoncred); gnutls_transport_set_int(session, fd); /* Perform the TLS handshake */ do { ret = gnutls_handshake(session); } while (ret < 0 && gnutls_error_is_fatal(ret) == 0); if (ret < 0) { fail("client: Handshake failed\n"); gnutls_perror(ret); exit(1); } else { if (debug) success("client: Handshake was completed\n"); } gnutls_record_send(session, buffer, 1); if (debug) success("client: DTLS version is: %s\n", gnutls_protocol_get_name (gnutls_protocol_get_version(session))); do { ret = gnutls_record_recv_seq(session, buffer, sizeof(buffer), seq); if (ret > 0) { useq = seq[7] | (seq[6] << 8) | (seq[5] << 16) | (seq[4] << 24); if (debug) success("received %u\n", (unsigned int)useq); if (recv_msg_seq[current] == -1) { fail("received message sequence differs\n"); terminate(); } if (((uint32_t)recv_msg_seq[current]) != useq) { fail("received message sequence differs (current: %u, got: %u, expected: %u)\n", (unsigned)current, (unsigned)useq, (unsigned)recv_msg_seq[current]); terminate(); } current++; } } while ((ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED || ret > 0)); gnutls_bye(session, GNUTLS_SHUT_WR); close(fd); gnutls_deinit(session); gnutls_anon_free_client_credentials(anoncred); gnutls_global_deinit(); }
void udp_server(const char* name, int port, int mtu) { int sock, ret; struct sockaddr_in cli_addr; socklen_t cli_addr_size; char buffer[MAX_BUFFER]; priv_data_st priv; gnutls_session_t session; gnutls_datum_t cookie_key; gnutls_dtls_prestate_st prestate; unsigned char sequence[8]; ret = gnutls_key_generate(&cookie_key, GNUTLS_COOKIE_KEY_SIZE); if (ret < 0) { fprintf(stderr, "Cannot generate key\n"); exit(1); } ret = listen_socket (name, port, SOCK_DGRAM); if (ret < 0) { fprintf(stderr, "Cannot listen\n"); exit (1); } for (;;) { printf("Waiting for connection...\n"); sock = wait_for_connection(); if (sock < 0) continue; cli_addr_size = sizeof(cli_addr); ret = recvfrom(sock, buffer, sizeof(buffer), MSG_PEEK, (struct sockaddr*)&cli_addr, &cli_addr_size); if (ret > 0) { memset(&prestate, 0, sizeof(prestate)); ret = gnutls_dtls_cookie_verify(&cookie_key, &cli_addr, sizeof(cli_addr), buffer, ret, &prestate); if (ret < 0) /* cookie not valid */ { priv_data_st s; memset(&s,0,sizeof(s)); s.fd = sock; s.cli_addr = (void*)&cli_addr; s.cli_addr_size = sizeof(cli_addr); printf("Sending hello verify request to %s\n", human_addr ((struct sockaddr *) &cli_addr, sizeof(cli_addr), buffer, sizeof(buffer))); gnutls_dtls_cookie_send(&cookie_key, &cli_addr, sizeof(cli_addr), &prestate, (gnutls_transport_ptr_t)&s, push_func); /* discard peeked data*/ recvfrom(sock, buffer, sizeof(buffer), 0, (struct sockaddr*)&cli_addr, &cli_addr_size); continue; } printf ("Accepted connection from %s\n", human_addr ((struct sockaddr *) &cli_addr, sizeof(cli_addr), buffer, sizeof (buffer))); } else continue; session = initialize_session(1); gnutls_dtls_prestate_set(session, &prestate); if (mtu) gnutls_dtls_set_mtu(session, mtu); priv.session = session; priv.fd = sock; priv.cli_addr = (struct sockaddr *)&cli_addr; priv.cli_addr_size = sizeof(cli_addr); gnutls_transport_set_ptr (session, &priv); gnutls_transport_set_push_function (session, push_func); gnutls_transport_set_pull_function (session, pull_func); gnutls_transport_set_pull_timeout_function (session, pull_timeout_func); do { ret = gnutls_handshake(session); } while(ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED); if (ret < 0) { fprintf(stderr, "Error in handshake(): %s\n", gnutls_strerror(ret)); gnutls_deinit(session); continue; } for(;;) { do { ret = gnutls_record_recv_seq(session, buffer, MAX_BUFFER, sequence); } while(ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED); if (ret == GNUTLS_E_REHANDSHAKE) { fprintf (stderr, "*** Received hello message\n"); do { ret = gnutls_handshake (session); } while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN); if (ret == 0) continue; } if (ret < 0) { fprintf(stderr, "Error in recv(): %s\n", gnutls_strerror(ret)); break; } if (ret == 0) { printf("EOF\n\n"); break; } buffer[ret] = 0; printf("received[%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x]: %s\n", sequence[0], sequence[1], sequence[2], sequence[3], sequence[4], sequence[5], sequence[6], sequence[7], buffer); if (check_command(session, buffer) == 0) { /* reply back */ ret = gnutls_record_send(session, buffer, ret); if (ret < 0) { fprintf(stderr, "Error in send(): %s\n", gnutls_strerror(ret)); break; } } } } gnutls_deinit(session); }
int main (void) { int listen_sd; int sock, ret; struct sockaddr_in sa_serv; struct sockaddr_in cli_addr; socklen_t cli_addr_size; gnutls_session_t session; char buffer[MAX_BUFFER]; priv_data_st priv; gnutls_datum_t cookie_key; gnutls_dtls_prestate_st prestate; int mtu = 1400; unsigned char sequence[8]; /* this must be called once in the program */ gnutls_global_init (); gnutls_certificate_allocate_credentials (&x509_cred); gnutls_certificate_set_x509_trust_file (x509_cred, CAFILE, GNUTLS_X509_FMT_PEM); gnutls_certificate_set_x509_crl_file (x509_cred, CRLFILE, GNUTLS_X509_FMT_PEM); ret = gnutls_certificate_set_x509_key_file (x509_cred, CERTFILE, KEYFILE, GNUTLS_X509_FMT_PEM); if (ret < 0) { printf("No certificate or key were found\n"); exit(1); } generate_dh_params (); gnutls_certificate_set_dh_params (x509_cred, dh_params); gnutls_priority_init (&priority_cache, "PERFORMANCE:-VERS-TLS-ALL:+VERS-DTLS1.0:%SERVER_PRECEDENCE", NULL); gnutls_key_generate (&cookie_key, GNUTLS_COOKIE_KEY_SIZE); /* Socket operations */ listen_sd = socket (AF_INET, SOCK_DGRAM, 0); memset (&sa_serv, '\0', sizeof (sa_serv)); sa_serv.sin_family = AF_INET; sa_serv.sin_addr.s_addr = INADDR_ANY; sa_serv.sin_port = htons (PORT); { /* DTLS requires the IP don't fragment (DF) bit to be set */ #if defined(IP_DONTFRAG) int optval = 1; setsockopt (listen_sd, IPPROTO_IP, IP_DONTFRAG, (const void *) &optval, sizeof (optval)); #elif defined(IP_MTU_DISCOVER) int optval = IP_PMTUDISC_DO; setsockopt(listen_sd, IPPROTO_IP, IP_MTU_DISCOVER, (const void*) &optval, sizeof (optval)); #endif } bind (listen_sd, (struct sockaddr *) &sa_serv, sizeof (sa_serv)); printf ("UDP server ready. Listening to port '%d'.\n\n", PORT); for (;;) { printf ("Waiting for connection...\n"); sock = wait_for_connection (listen_sd); if (sock < 0) continue; cli_addr_size = sizeof (cli_addr); ret = recvfrom (sock, buffer, sizeof (buffer), MSG_PEEK, (struct sockaddr *) &cli_addr, &cli_addr_size); if (ret > 0) { memset (&prestate, 0, sizeof (prestate)); ret = gnutls_dtls_cookie_verify (&cookie_key, &cli_addr, sizeof (cli_addr), buffer, ret, &prestate); if (ret < 0) /* cookie not valid */ { priv_data_st s; memset (&s, 0, sizeof (s)); s.fd = sock; s.cli_addr = (void *) &cli_addr; s.cli_addr_size = sizeof (cli_addr); printf ("Sending hello verify request to %s\n", human_addr ((struct sockaddr *) &cli_addr, sizeof (cli_addr), buffer, sizeof (buffer))); gnutls_dtls_cookie_send (&cookie_key, &cli_addr, sizeof (cli_addr), &prestate, (gnutls_transport_ptr_t) & s, push_func); /* discard peeked data */ recvfrom (sock, buffer, sizeof (buffer), 0, (struct sockaddr *) &cli_addr, &cli_addr_size); usleep (100); continue; } printf ("Accepted connection from %s\n", human_addr ((struct sockaddr *) &cli_addr, sizeof (cli_addr), buffer, sizeof (buffer))); } else continue; session = initialize_tls_session (); gnutls_dtls_prestate_set (session, &prestate); gnutls_dtls_set_mtu (session, mtu); priv.session = session; priv.fd = sock; priv.cli_addr = (struct sockaddr *) &cli_addr; priv.cli_addr_size = sizeof (cli_addr); gnutls_transport_set_ptr (session, &priv); gnutls_transport_set_push_function (session, push_func); gnutls_transport_set_pull_function (session, pull_func); gnutls_transport_set_pull_timeout_function (session, pull_timeout_func); do { ret = gnutls_handshake (session); } while (ret < 0 && gnutls_error_is_fatal (ret) == 0); if (ret < 0) { fprintf (stderr, "Error in handshake(): %s\n", gnutls_strerror (ret)); gnutls_deinit (session); continue; } printf ("- Handshake was completed\n"); for (;;) { do { ret = gnutls_record_recv_seq (session, buffer, MAX_BUFFER, sequence); } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED); if (ret < 0) { fprintf (stderr, "Error in recv(): %s\n", gnutls_strerror (ret)); break; } if (ret == 0) { printf ("EOF\n\n"); break; } buffer[ret] = 0; printf ("received[%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x]: %s\n", sequence[0], sequence[1], sequence[2], sequence[3], sequence[4], sequence[5], sequence[6], sequence[7], buffer); /* reply back */ ret = gnutls_record_send (session, buffer, ret); if (ret < 0) { fprintf (stderr, "Error in send(): %s\n", gnutls_strerror (ret)); break; } } gnutls_bye (session, GNUTLS_SHUT_WR); gnutls_deinit (session); } close (listen_sd); gnutls_certificate_free_credentials (x509_cred); gnutls_priority_deinit (priority_cache); gnutls_global_deinit (); return 0; }