summaryrefslogtreecommitdiffstats
path: root/doc/examples/ex-serv-psk.c
diff options
context:
space:
mode:
Diffstat (limited to 'doc/examples/ex-serv-psk.c')
-rw-r--r--doc/examples/ex-serv-psk.c203
1 files changed, 203 insertions, 0 deletions
diff --git a/doc/examples/ex-serv-psk.c b/doc/examples/ex-serv-psk.c
new file mode 100644
index 0000000..b6d5d11
--- /dev/null
+++ b/doc/examples/ex-serv-psk.c
@@ -0,0 +1,203 @@
+/* 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>
+
+#define KEYFILE "key.pem"
+#define CERTFILE "cert.pem"
+#define CAFILE "/etc/ssl/certs/ca-certificates.crt"
+#define CRLFILE "crl.pem"
+
+#define LOOP_CHECK(rval, cmd) \
+ do { \
+ rval = cmd; \
+ } while(rval == GNUTLS_E_AGAIN || rval == GNUTLS_E_INTERRUPTED)
+
+/* This is a sample TLS echo server, supporting X.509 and PSK
+ authentication.
+ */
+
+#define SOCKET_ERR(err,s) if(err==-1) {perror(s);return(1);}
+#define MAX_BUF 1024
+#define PORT 5556 /* listen to 5556 port */
+
+static int
+pskfunc(gnutls_session_t session, const char *username,
+ gnutls_datum_t * key)
+{
+ printf("psk: username %s\n", username);
+ key->data = gnutls_malloc(4);
+ key->data[0] = 0xDE;
+ key->data[1] = 0xAD;
+ key->data[2] = 0xBE;
+ key->data[3] = 0xEF;
+ key->size = 4;
+ return 0;
+}
+
+int main(void)
+{
+ int err, listen_sd;
+ int sd, ret;
+ struct sockaddr_in sa_serv;
+ struct sockaddr_in sa_cli;
+ socklen_t client_len;
+ char topbuf[512];
+ gnutls_session_t session;
+ gnutls_certificate_credentials_t x509_cred;
+ gnutls_psk_server_credentials_t psk_cred;
+ gnutls_priority_t priority_cache;
+ char buffer[MAX_BUF + 1];
+ int optval = 1;
+ int kx;
+
+ if (gnutls_check_version("3.1.4") == NULL) {
+ fprintf(stderr, "GnuTLS 3.1.4 or later is required for this example\n");
+ exit(1);
+ }
+
+ /* for backwards compatibility with gnutls < 3.3.0 */
+ 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);
+
+ gnutls_certificate_set_x509_key_file(x509_cred, CERTFILE, KEYFILE,
+ GNUTLS_X509_FMT_PEM);
+
+ gnutls_psk_allocate_server_credentials(&psk_cred);
+ gnutls_psk_set_server_credentials_function(psk_cred, pskfunc);
+
+ /* pre-3.6.3 equivalent:
+ * gnutls_priority_init(&priority_cache,
+ * "NORMAL:+PSK:+ECDHE-PSK:+DHE-PSK",
+ * NULL);
+ */
+ gnutls_priority_init2(&priority_cache,
+ "+ECDHE-PSK:+DHE-PSK:+PSK",
+ NULL, GNUTLS_PRIORITY_INIT_DEF_APPEND);
+
+ gnutls_certificate_set_known_dh_params(x509_cred, GNUTLS_SEC_PARAM_MEDIUM);
+
+ /* Socket operations
+ */
+ listen_sd = socket(AF_INET, SOCK_STREAM, 0);
+ SOCKET_ERR(listen_sd, "socket");
+
+ 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));
+
+ err =
+ bind(listen_sd, (struct sockaddr *) &sa_serv, sizeof(sa_serv));
+ SOCKET_ERR(err, "bind");
+ err = listen(listen_sd, 1024);
+ SOCKET_ERR(err, "listen");
+
+ printf("Server ready. Listening to port '%d'.\n\n", PORT);
+
+ client_len = sizeof(sa_cli);
+ for (;;) {
+ gnutls_init(&session, GNUTLS_SERVER);
+ gnutls_priority_set(session, priority_cache);
+ gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
+ x509_cred);
+ gnutls_credentials_set(session, GNUTLS_CRD_PSK, psk_cred);
+
+ /* request client certificate if any.
+ */
+ gnutls_certificate_server_set_request(session,
+ GNUTLS_CERT_REQUEST);
+
+ 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\n",
+ gnutls_strerror(ret));
+ continue;
+ }
+ printf("- Handshake was completed\n");
+
+ kx = gnutls_kx_get(session);
+ if (kx == GNUTLS_KX_PSK || kx == GNUTLS_KX_DHE_PSK ||
+ kx == GNUTLS_KX_ECDHE_PSK) {
+ printf("- User %s was connected\n",
+ gnutls_psk_server_get_username(session));
+ }
+
+ /* see the Getting peer's information example */
+ /* print_info(session); */
+
+ for (;;) {
+ LOOP_CHECK(ret, gnutls_record_recv(session, buffer, MAX_BUF));
+
+ if (ret == 0) {
+ printf
+ ("\n- 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\n",
+ ret);
+ break;
+ } else if (ret > 0) {
+ /* echo data back to the client
+ */
+ gnutls_record_send(session, buffer, ret);
+ }
+ }
+ printf("\n");
+ /* do not wait for the peer to close the connection.
+ */
+ LOOP_CHECK(ret, gnutls_bye(session, GNUTLS_SHUT_WR));
+
+ close(sd);
+ gnutls_deinit(session);
+
+ }
+ close(listen_sd);
+
+ gnutls_certificate_free_credentials(x509_cred);
+ gnutls_psk_free_server_credentials(psk_cred);
+
+ gnutls_priority_deinit(priority_cache);
+
+ gnutls_global_deinit();
+
+ return 0;
+
+}