diff options
Diffstat (limited to 'tls-srv.c')
-rw-r--r-- | tls-srv.c | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/tls-srv.c b/tls-srv.c new file mode 100644 index 000000000..c6636d60a --- /dev/null +++ b/tls-srv.c @@ -0,0 +1,146 @@ +/* This example code is placed in the public domain. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <netinet/in.h> +#include <string.h> +#include <unistd.h> +#include <gnutls/gnutls.h> +#include <assert.h> + +#define CAFILE "ca-cert.pem" +#define KEYFILE "server-key.pem" +#define CERTFILE "server-cert.pem" +#define CRLFILE "crl.pem" + +#define CHECK(x) assert((x) >= 0) +#define LOOP_CHECK(rval, cmd) \ + do \ + { \ + rval = cmd; \ + } while (rval == GNUTLS_E_AGAIN || rval == GNUTLS_E_INTERRUPTED) + +#define MAX_BUF 16 +#define PORT 5556 /* listen to 5556 port */ + +int main(void) +{ + int listen_sd; + int sd, ret; + gnutls_certificate_credentials_t x509_cred; + gnutls_priority_t priority_cache; + struct sockaddr_in sa_serv; + struct sockaddr_in sa_cli; + socklen_t client_len; + char topbuf[512]; + gnutls_session_t session; + char buffer[MAX_BUF + 1]; + int optval = 1; + + /* for backwards compatibility with gnutls < 3.3.0 */ + CHECK(gnutls_global_init()); + + CHECK(gnutls_certificate_allocate_credentials(&x509_cred)); + CHECK(gnutls_certificate_set_x509_crl_file(x509_cred, CRLFILE, GNUTLS_X509_FMT_PEM)); + CHECK(gnutls_certificate_set_x509_key_file(x509_cred, CERTFILE, KEYFILE, GNUTLS_X509_FMT_PEM)); + CHECK(gnutls_certificate_set_x509_trust_file(x509_cred, CAFILE, GNUTLS_X509_FMT_PEM)); + CHECK(gnutls_priority_init(&priority_cache, NULL, NULL)); + +#if GNUTLS_VERSION_NUMBER >= 0x030506 + /* only available since GnuTLS 3.5.6, on previous versions see + * gnutls_certificate_set_dh_params(). */ + gnutls_certificate_set_known_dh_params(x509_cred, GNUTLS_SEC_PARAM_HIGH); +#endif + + /* Socket operations */ + listen_sd = socket(AF_INET, SOCK_STREAM, 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); /* Server Port number */ + + setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR, (void *)&optval, sizeof(int)); + bind(listen_sd, (struct sockaddr *)&sa_serv, sizeof(sa_serv)); + listen(listen_sd, 1024); + + printf("Server ready. Listening to port '%d'.\n", PORT); + + client_len = sizeof(sa_cli); + for (;;) + { + CHECK(gnutls_init(&session, GNUTLS_SERVER)); + CHECK(gnutls_priority_set(session, priority_cache)); + CHECK(gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred)); + gnutls_session_set_verify_cert(session, NULL, 0); + gnutls_certificate_server_set_request(session, GNUTLS_CERT_REQUIRE); + gnutls_certificate_send_x509_rdn_sequence(session, 1); + gnutls_handshake_set_timeout(session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT); + + sd = accept(listen_sd, (struct sockaddr *)&sa_cli, &client_len); + + printf("- connection from %s, port %d\n", + inet_ntop(AF_INET, &sa_cli.sin_addr, topbuf, sizeof(topbuf)), + ntohs(sa_cli.sin_port)); + + gnutls_transport_set_int(session, sd); + + LOOP_CHECK(ret, gnutls_handshake(session)); + if (ret < 0) + { + close(sd); + gnutls_deinit(session); + fprintf(stderr, "*** Handshake has failed (%s)\n", gnutls_strerror(ret)); + continue; + } + printf("- Handshake was completed\n"); + + for (;;) + { + LOOP_CHECK(ret, gnutls_record_recv(session, buffer, MAX_BUF)); + + if (ret == 0) + { + printf("- Peer has closed the GnuTLS connection\n"); + break; + } + else if (ret < 0 && gnutls_error_is_fatal(ret) == 0) + { + fprintf(stderr, "*** Warning: %s\n", gnutls_strerror(ret)); + } + else if (ret < 0) + { + fprintf(stderr, + "\n*** Received corrupted " + "data(%d). Closing the connection.\n", + ret); + break; + } + else if (ret > 0 && ret < MAX_BUF - 1) + { + buffer[ret] = '$'; + CHECK(gnutls_record_send(session, buffer, ret + 1)); + } + } + LOOP_CHECK(ret, gnutls_bye(session, GNUTLS_SHUT_WR)); + + close(sd); + gnutls_deinit(session); + } + close(listen_sd); + + gnutls_certificate_free_credentials(x509_cred); + gnutls_priority_deinit(priority_cache); + + gnutls_global_deinit(); + + return 0; +} |