]> mj.ucw.cz Git - eval.git/blob - submit/connect.c
7f5709ea2616b7d5ee1992143418e8ee953ae85f
[eval.git] / submit / connect.c
1 /*
2  *  A Simple Testing Client
3  *
4  *  (c) 2007 Martin Mares <mj@ucw.cz>
5  */
6
7 #include "lib/lib.h"
8
9 #include <stdio.h>
10 #include <string.h>
11 #include <unistd.h>
12 #include <sys/socket.h>
13 #include <arpa/inet.h>
14 #include <netinet/in.h>
15 #include <gnutls/gnutls.h>
16 #include <gnutls/x509.h>
17
18 static int port = 8888;
19
20 static gnutls_certificate_credentials_t cert_cred;
21
22 #define TLS_CHECK(name) if (err < 0) die(#name " failed: %s", gnutls_strerror(err))
23
24 static void
25 tls_init(void)
26 {
27   int err;
28
29   log(L_INFO, "Initializing TLS");
30   gnutls_global_init();
31   err = gnutls_certificate_allocate_credentials(&cert_cred);
32   TLS_CHECK(gnutls_certificate_allocate_credentials);
33   err = gnutls_certificate_set_x509_trust_file(cert_cred, "ca-cert.pem", GNUTLS_X509_FMT_PEM);
34   if (!err)
35     die("No CA certificate found");
36   if (err < 0)
37     die("Unable to load X509 trust file: %s", gnutls_strerror(err));
38   err = gnutls_certificate_set_x509_key_file(cert_cred, "client-cert.pem", "client-key.pem", GNUTLS_X509_FMT_PEM);
39   if (err < 0)
40     die("Unable to load X509 key file: %s", gnutls_strerror(err));
41 }
42
43 static const char *
44 tls_verify_cert(gnutls_session_t s)
45 {
46   uns status, num_certs;
47   int err;
48   gnutls_x509_crt_t cert;
49   const gnutls_datum_t *certs;
50
51   DBG("Verifying peer certificates");
52   err = gnutls_certificate_verify_peers2(s, &status);
53   if (err < 0)
54     return gnutls_strerror(err);
55   DBG("Verify status: %04x", status);
56   if (status & GNUTLS_CERT_INVALID)
57     return "Certificate is invalid";
58   /* XXX: We do not handle revokation. */
59   if (gnutls_certificate_type_get(s) != GNUTLS_CRT_X509)
60     return "Certificate is not X509";
61
62   err = gnutls_x509_crt_init(&cert);
63   if (err < 0)
64     return "gnutls_x509_crt_init() failed";
65   certs = gnutls_certificate_get_peers(s, &num_certs);
66   if (!certs)
67     return "No peer certificate found";
68   DBG("Got certificate list with %d peers", num_certs);
69
70   err = gnutls_x509_crt_import(cert, &certs[0], GNUTLS_X509_FMT_DER);
71   if (err < 0)
72     return "Cannot import certificate";
73   /* XXX: We do not check expiration and activation since the keys are generated for a single contest only anyway. */
74   /* XXX: Neither we check host name */
75
76   /* Check certificate purpose */
77   byte purp[256];
78   int purpi = 0;
79   do
80     {
81       size_t purp_len = sizeof(purp);
82       uns crit;
83       err = gnutls_x509_crt_get_key_purpose_oid(cert, purpi++, purp, &purp_len, &crit);
84       if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
85         return "Not a client certificate";
86       TLS_CHECK(gnutls_x509_crt_get_key_purpose_oid);
87     }
88   while (strcmp(purp, GNUTLS_KP_TLS_WWW_SERVER));
89
90   DBG("Verified OK");
91   return NULL;
92 }
93
94 static void
95 tls_log_params(gnutls_session_t s)
96 {
97   const char *proto = gnutls_protocol_get_name(gnutls_protocol_get_version(s));
98   const char *kx = gnutls_kx_get_name(gnutls_kx_get(s));
99   const char *cert = gnutls_certificate_type_get_name(gnutls_certificate_type_get(s));
100   const char *comp = gnutls_compression_get_name(gnutls_compression_get(s));
101   const char *cipher = gnutls_cipher_get_name(gnutls_cipher_get(s));
102   const char *mac = gnutls_mac_get_name(gnutls_mac_get(s));
103   log(L_DEBUG, "TLS params: proto=%s kx=%s cert=%s comp=%s cipher=%s mac=%s",
104     proto, kx, cert, comp, cipher, mac);
105 }
106
107 int main(int argc UNUSED, char **argv UNUSED)
108 {
109   tls_init();
110
111   int sk = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
112   if (sk < 0)
113     die("socket: %m");
114
115   log(L_INFO, "Connecting to port %d", port);
116   struct sockaddr_in sa;
117   bzero(&sa, sizeof(sa));
118   sa.sin_family = AF_INET;
119   sa.sin_addr.s_addr = htonl(0x7f000001);
120   sa.sin_port = htons(port);
121   if (connect(sk, (struct sockaddr *) &sa, sizeof(sa)) < 0)
122     die("Cannot connect: %m");
123
124   gnutls_session_t s;
125   gnutls_init(&s, GNUTLS_CLIENT);
126   gnutls_set_default_priority(s);
127   gnutls_credentials_set(s, GNUTLS_CRD_CERTIFICATE, cert_cred);
128   gnutls_transport_set_ptr(s, (gnutls_transport_ptr_t) sk);
129
130   log(L_INFO, "Handshaking");
131   int err = gnutls_handshake(s); TLS_CHECK(gnutls_handshake);
132   tls_log_params(s);
133   const char *cert_err = tls_verify_cert(s);
134   if (cert_err)
135     die("Certificate verification failed: %s", cert_err);
136
137   log(L_INFO, "Session established");
138   for (;;)
139     {
140       byte buf[1024];
141       if (!fgets(buf, sizeof(buf), stdin))
142         break;
143       int len = strlen(buf);
144       err = gnutls_record_send(s, buf, len); TLS_CHECK(gnutls_record_send);
145       err = gnutls_record_recv(s, buf, len); TLS_CHECK(gnutls_record_recv);
146       if (!err)
147         {
148           log(L_INFO, "Connection closed");
149           break;
150         }
151       fwrite(buf, 1, err, stdout);
152       fflush(stdout);
153     }
154
155   gnutls_bye(s, GNUTLS_SHUT_RDWR);
156   close(sk);
157   gnutls_deinit(s);
158
159   return 0;
160 }