]> mj.ucw.cz Git - moe.git/blob - submit/connect.c
Added command-line clients for remote submit and status.
[moe.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   log(L_INFO, "Waiting for initial message");
125   byte msg[256];
126   int i = 0;
127   do
128     {
129       if (i >= (int)sizeof(msg))
130         die("Response too long");
131       int c = read(sk, msg+i, sizeof(msg)-i);
132       if (c <= 0)
133         die("Connection broken");
134       i += c;
135     }
136   while (msg[i-1] != '\n');
137   msg[i-1] = 0;
138   if (msg[0] != '+')
139     die("%s", msg);
140   log(L_INFO, "%s", msg);
141
142   gnutls_session_t s;
143   gnutls_init(&s, GNUTLS_CLIENT);
144   gnutls_set_default_priority(s);
145   gnutls_credentials_set(s, GNUTLS_CRD_CERTIFICATE, cert_cred);
146   gnutls_transport_set_ptr(s, (gnutls_transport_ptr_t) sk);
147
148   log(L_INFO, "Handshaking");
149   int err = gnutls_handshake(s); TLS_CHECK(gnutls_handshake);
150   tls_log_params(s);
151   const char *cert_err = tls_verify_cert(s);
152   if (cert_err)
153     die("Certificate verification failed: %s", cert_err);
154
155   log(L_INFO, "Session established");
156   for (;;)
157     {
158       byte buf[1024];
159       do
160         {
161           if (!fgets(buf, sizeof(buf), stdin))
162             goto done;
163           int len = strlen(buf);
164           err = gnutls_record_send(s, buf, len); TLS_CHECK(gnutls_record_send);
165         }
166       while (buf[0] != '\n');
167       int last = 0;
168       for (;;)
169         {
170           err = gnutls_record_recv(s, buf, sizeof(buf)); TLS_CHECK(gnutls_record_recv);
171           if (!err)
172             {
173               log(L_INFO, "Connection closed");
174               break;
175             }
176           fwrite(buf, 1, err, stdout);
177           for (int i=0; i<err; i++)
178             {
179               if (buf[i] == '\n' && last == '\n')
180                 goto next;
181               last = buf[i];
182             }
183         }
184 next:
185       fflush(stdout);
186     }
187
188 done:
189   gnutls_bye(s, GNUTLS_SHUT_RDWR);
190   close(sk);
191   gnutls_deinit(s);
192
193   return 0;
194 }