2 * A Simple Testing Client
4 * (c) 2007 Martin Mares <mj@ucw.cz>
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>
18 static int port = 8888;
20 static gnutls_certificate_credentials_t cert_cred;
22 #define TLS_CHECK(name) if (err < 0) die(#name " failed: %s", gnutls_strerror(err))
29 msg(L_INFO, "Initializing TLS");
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);
35 die("No CA certificate found");
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);
40 die("Unable to load X509 key file: %s", gnutls_strerror(err));
44 tls_verify_cert(gnutls_session_t s)
46 uns status, num_certs;
48 gnutls_x509_crt_t cert;
49 const gnutls_datum_t *certs;
51 DBG("Verifying peer certificates");
52 err = gnutls_certificate_verify_peers2(s, &status);
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";
62 err = gnutls_x509_crt_init(&cert);
64 return "gnutls_x509_crt_init() failed";
65 certs = gnutls_certificate_get_peers(s, &num_certs);
67 return "No peer certificate found";
68 DBG("Got certificate list with %d peers", num_certs);
70 err = gnutls_x509_crt_import(cert, &certs[0], GNUTLS_X509_FMT_DER);
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 */
76 /* Check certificate purpose */
81 size_t purp_len = sizeof(purp);
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);
88 while (strcmp(purp, GNUTLS_KP_TLS_WWW_SERVER));
95 tls_log_params(gnutls_session_t s)
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 msg(L_DEBUG, "TLS params: proto=%s kx=%s cert=%s comp=%s cipher=%s mac=%s",
104 proto, kx, cert, comp, cipher, mac);
107 int main(int argc UNUSED, char **argv UNUSED)
111 int sk = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
115 msg(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");
124 msg(L_INFO, "Waiting for initial message");
129 if (i >= (int)sizeof(mesg))
130 die("Response too long");
131 int c = read(sk, mesg+i, sizeof(mesg)-i);
133 die("Connection broken");
136 while (mesg[i-1] != '\n');
140 msg(L_INFO, "%s", mesg);
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);
148 msg(L_INFO, "Handshaking");
149 int err = gnutls_handshake(s); TLS_CHECK(gnutls_handshake);
151 const char *cert_err = tls_verify_cert(s);
153 die("Certificate verification failed: %s", cert_err);
155 msg(L_INFO, "Session established");
161 if (!fgets(buf, sizeof(buf), stdin))
163 int len = strlen(buf);
164 err = gnutls_record_send(s, buf, len); TLS_CHECK(gnutls_record_send);
166 while (buf[0] != '\n');
170 err = gnutls_record_recv(s, buf, sizeof(buf)); TLS_CHECK(gnutls_record_recv);
173 msg(L_INFO, "Connection closed");
176 fwrite(buf, 1, err, stdout);
177 for (int i=0; i<err; i++)
179 if (buf[i] == '\n' && last == '\n')
189 gnutls_bye(s, GNUTLS_SHUT_RDWR);