4 * (c) 2007 Martin Mares <mj@ucw.cz>
13 #include <sys/socket.h>
14 #include <arpa/inet.h>
15 #include <netinet/in.h>
16 #include <gnutls/gnutls.h>
17 #include <gnutls/x509.h>
19 static int port = 8888;
21 static gnutls_certificate_credentials_t cert_cred;
22 static gnutls_dh_params_t dh_params;
25 #define TLS_CHECK(name) if (err < 0) die(#name " failed: %s", gnutls_strerror(err))
32 log(L_INFO, "Initializing TLS");
34 err = gnutls_certificate_allocate_credentials(&cert_cred);
35 TLS_CHECK(gnutls_certificate_allocate_credentials);
36 err = gnutls_certificate_set_x509_trust_file(cert_cred, "ca-cert.pem", GNUTLS_X509_FMT_PEM);
38 die("No CA certificate found");
40 die("Unable to load X509 trust file: %s", gnutls_strerror(err));
41 err = gnutls_certificate_set_x509_key_file(cert_cred, "server-cert.pem", "server-key.pem", GNUTLS_X509_FMT_PEM);
43 die("Unable to load X509 key file: %s", gnutls_strerror(err));
45 log(L_INFO, "Setting up DH parameters");
46 err = gnutls_dh_params_init(&dh_params); TLS_CHECK(gnutls_dh_params_init);
47 err = gnutls_dh_params_generate2(dh_params, DH_BITS); TLS_CHECK(gnutls_dh_params_generate2);
48 gnutls_certificate_set_dh_params(cert_cred, dh_params);
51 static gnutls_session_t
52 tls_new_session(int sk)
57 err = gnutls_init(&s, GNUTLS_SERVER); TLS_CHECK(gnutls_init);
58 err = gnutls_set_default_priority(s); TLS_CHECK(gnutls_set_default_priority); // FIXME
59 gnutls_credentials_set(s, GNUTLS_CRD_CERTIFICATE, cert_cred);
60 gnutls_certificate_server_set_request(s, GNUTLS_CERT_REQUEST);
61 gnutls_dh_set_prime_bits(s, DH_BITS);
62 gnutls_transport_set_ptr(s, (gnutls_transport_ptr_t) sk);
67 tls_verify_cert(gnutls_session_t s)
69 uns status, num_certs;
71 gnutls_x509_crt_t cert;
72 const gnutls_datum_t *certs;
74 DBG("Verifying peer certificates");
75 err = gnutls_certificate_verify_peers2(s, &status);
77 return gnutls_strerror(err);
78 DBG("Verify status: %04x", status);
79 if (status & GNUTLS_CERT_INVALID)
80 return "Certificate is invalid";
81 /* XXX: We do not handle revokation. */
82 if (gnutls_certificate_type_get(s) != GNUTLS_CRT_X509)
83 return "Certificate is not X509";
85 err = gnutls_x509_crt_init(&cert);
87 return "gnutls_x509_crt_init() failed";
88 certs = gnutls_certificate_get_peers(s, &num_certs);
90 return "No peer certificate found";
91 DBG("Got certificate list with %d peers", num_certs);
93 err = gnutls_x509_crt_import(cert, &certs[0], GNUTLS_X509_FMT_DER);
95 return "Cannot import certificate";
96 /* XXX: We do not check expiration and activation since the keys are generated for a single contest only anyway. */
99 size_t dn_len = sizeof(dn);
100 err = gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0, dn, &dn_len);
102 return "Cannot retrieve common name";
103 log(L_INFO, "Cert CN: %s", dn);
105 /* Check certificate purpose */
110 size_t purp_len = sizeof(purp);
112 err = gnutls_x509_crt_get_key_purpose_oid(cert, purpi++, purp, &purp_len, &crit);
113 if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
114 return "Not a client certificate";
115 TLS_CHECK(gnutls_x509_crt_get_key_purpose_oid);
117 while (strcmp(purp, GNUTLS_KP_TLS_WWW_CLIENT));
124 tls_log_params(gnutls_session_t s)
126 const char *proto = gnutls_protocol_get_name(gnutls_protocol_get_version(s));
127 const char *kx = gnutls_kx_get_name(gnutls_kx_get(s));
128 const char *cert = gnutls_certificate_type_get_name(gnutls_certificate_type_get(s));
129 const char *comp = gnutls_compression_get_name(gnutls_compression_get(s));
130 const char *cipher = gnutls_cipher_get_name(gnutls_cipher_get(s));
131 const char *mac = gnutls_mac_get_name(gnutls_mac_get(s));
132 log(L_DEBUG, "TLS params: proto=%s kx=%s cert=%s comp=%s cipher=%s mac=%s",
133 proto, kx, cert, comp, cipher, mac);
136 int main(int argc UNUSED, char **argv UNUSED)
140 int sk = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
144 if (setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0)
145 die("setsockopt(SO_REUSEADDR): %m");
147 struct sockaddr_in sa;
148 bzero(&sa, sizeof(sa));
149 sa.sin_family = AF_INET;
150 sa.sin_addr.s_addr = INADDR_ANY;
151 sa.sin_port = htons(port);
152 if (bind(sk, (struct sockaddr *) &sa, sizeof(sa)) < 0)
153 die("Cannot bind to port %d: %m", port);
154 if (listen(sk, 1024) < 0)
155 die("Cannot listen on port %d: %m", port);
156 log(L_INFO, "Listening on port %d", port);
160 struct sockaddr_in sa2;
161 int sa2len = sizeof(sa2);
162 int sk2 = accept(sk, (struct sockaddr *) &sa2, &sa2len);
166 byte ipbuf[INET_ADDRSTRLEN];
167 inet_ntop(AF_INET, &sa2.sin_addr, ipbuf, sizeof(ipbuf));
168 log(L_INFO, "Connection from %s port %d", ipbuf, ntohs(sa2.sin_port));
170 gnutls_session_t sess = tls_new_session(sk2);
171 int err = gnutls_handshake(sess);
174 log(L_ERROR_R, "Handshake failed: %s", gnutls_strerror(err));
177 tls_log_params(sess);
179 const char *cert_err = tls_verify_cert(sess);
182 log(L_ERROR_R, "Certificate verification failed: %s", cert_err);
189 int ret = gnutls_record_recv(sess, buf, sizeof(buf));
192 log(L_ERROR_R, "Connection broken: %s", gnutls_strerror(ret));
197 log(L_INFO, "Client closed connection");
200 log(L_DEBUG, "Received %d bytes", ret);
201 gnutls_record_send(sess, buf, ret);
204 gnutls_bye(sess, GNUTLS_SHUT_WR);