purple: rename Iface -> Interface in 3.x.x API
[siplcs.git] / src / core / sipe-tls-tester.c
blobe80d715423426b474770f4b1e619eac85864a583
1 /**
2 * @file sipe-tls-tester.c
4 * pidgin-sipe
6 * Copyright (C) 2011-2019 SIPE Project <http://sipe.sourceforge.net/>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 * TLS handshake implementation (sipe-tls.c) tester
26 * Example test setup using OpenSSL:
28 * - Setting up the server certificate:
30 * $ openssl req -new -keyout server.pem -out server.req
31 * $ openssl x509 -req -in server.req -signkey server.pem -out server.cert
33 * - Running the test server in one shell with same parameters used by Lync:
35 * $ openssl s_server -accept 8443 -debug -msg \
36 * -cert server.cert -key server.pem \
37 * -tls1 -verify 0 [ -cipher <c1>[:<c2>...] ]
39 * ciphers: RC4-MD5, RC4-SHA, AES128-SHA, AES256-SHA
41 * - Running the test program in another shell:
43 * $ sipe_tls_tester
45 * You can add <host>[:<port>] to connect to a server on another machine
48 #include <stdlib.h>
49 #include <string.h>
50 #include <stdio.h>
51 #include <stdarg.h>
52 #include <stdint.h>
53 #include <time.h>
54 #include <unistd.h>
55 #include <errno.h>
56 #include <sys/types.h>
57 #include <sys/socket.h>
58 #include <netdb.h>
59 #include <poll.h>
61 #include <glib.h>
63 #include "sipe-common.h" /* coverity[hfa: FALSE] */
64 #include "sipe-backend.h"
65 #include "sipe-cert-crypto.h"
66 #include "sipe-crypt.h"
67 #include "sipe-tls.h"
70 * Stubs
72 gboolean sipe_backend_debug_enabled(void)
74 return(TRUE);
77 void sipe_backend_debug_literal(sipe_debug_level level,
78 const gchar *msg)
80 printf("DEBUG(%d): %s\n", level, msg);
83 void sipe_backend_debug(sipe_debug_level level,
84 const gchar *format,
85 ...)
87 va_list ap;
88 gchar *newformat = g_strdup_printf("DEBUG(%d): %s\n", level, format);
90 va_start(ap, format);
91 vprintf(newformat, ap);
92 va_end(ap);
94 g_free(newformat);
97 /* needed when linking against NSS */
98 void md4sum(const uint8_t *data, uint32_t length, uint8_t *digest);
99 void md4sum(SIPE_UNUSED_PARAMETER const uint8_t *data,
100 SIPE_UNUSED_PARAMETER uint32_t length,
101 SIPE_UNUSED_PARAMETER uint8_t *digest)
106 * Tester code
108 struct record {
109 gsize length;
110 guchar *msg;
113 static guchar *read_tls_record(int fd,
114 gsize *in_length)
116 GSList *fragments = NULL;
117 guchar *merged = NULL;
118 gsize length = 0;
119 static gchar buffer[10000];
121 while (1) {
122 struct pollfd fds[] = {
123 { fd, POLLIN, 0 }
125 int result;
126 struct record *record;
128 /* Read one chunk */
129 result = poll(fds, 1, 500 /* [milliseconds] */);
130 if (result < 0) {
131 printf("poll failed: %s\n", strerror(errno));
132 break;
134 if (result == 0) {
135 if (!fragments) {
136 printf("timeout.\n");
137 continue;
138 } else {
139 printf("reading done.\n");
140 break;
144 result = read(fd, buffer, sizeof(buffer));
145 if (result < 0) {
146 printf("read failed: %s\n", strerror(errno));
147 break;
149 if (result == 0) {
150 printf("server closed connection: %s\n",
151 strerror(errno));
152 break;
155 printf("received %d bytes from server\n", result);
156 record = g_new0(struct record, 1);
157 record->length = result;
158 record->msg = g_memdup(buffer, result);
159 length += result;
160 fragments = g_slist_append(fragments, record);
163 if (fragments) {
164 GSList *elem = fragments;
165 guchar *p;
167 printf("received a total of %" G_GSIZE_FORMAT " bytes.\n",
168 length);
170 p = merged = g_malloc(length);
171 if (merged) {
172 while (elem) {
173 struct record *record = elem->data;
175 memcpy(p, record->msg, record->length);
176 p += record->length;
177 g_free(record->msg);
178 g_free(record);
180 elem = elem->next;
182 } else {
183 printf("can't allocate %" G_GSIZE_FORMAT " bytes.\n",
184 length);
187 g_slist_free(fragments);
190 *in_length = length;
191 return(merged);
194 static void tls_handshake(struct sipe_tls_state *state,
195 int fd)
197 gboolean success = FALSE;
199 printf("TLS handshake starting...\n");
201 /* generate next handshake message */
202 while (sipe_tls_next(state)) {
203 int sent;
205 /* handshake completed? */
206 if (!state->out_buffer) {
207 success = TRUE;
208 break;
211 /* send buffer to server */
212 sent = write(fd, state->out_buffer, state->out_length);
213 if (sent < 0) {
214 printf("write to server failed: %s\n",
215 strerror(errno));
216 break;
217 } else if ((unsigned int) sent < state->out_length) {
218 printf("could only write %d bytes, out of %" G_GSIZE_FORMAT "\n",
219 sent, state->out_length);
220 break;
223 /* message sent, drop buffer */
224 g_free(state->out_buffer);
225 state->out_buffer = NULL;
227 state->in_buffer = read_tls_record(fd, &state->in_length);
228 if (!state->in_buffer) {
229 printf("end of data.\n");
230 break;
234 printf("TLS handshake %s.\n", success ? "SUCCESSFUL" : "FAILED");
238 static int tls_connect(const gchar *param)
240 gchar **parts = g_strsplit(param, ":", 2);
241 int fd = -1;
243 if (parts[0]) {
244 const gchar *host = parts[0];
245 const gchar *port = parts[1] ? parts[1] : "443";
246 struct addrinfo hints;
247 struct addrinfo *result;
248 int status;
250 printf("TLS connect to host '%s', port %s...\n",
251 host, port);
253 memset(&hints, 0, sizeof(struct addrinfo));
254 hints.ai_family = AF_UNSPEC;
255 hints.ai_socktype = SOCK_STREAM;
256 hints.ai_flags = 0;
257 hints.ai_protocol = 0;
258 status = getaddrinfo(host, port, &hints, &result);
260 if (status == 0) {
261 struct addrinfo *rp;
263 for (rp = result; rp != NULL; rp = rp->ai_next) {
264 int sock = socket(rp->ai_family,
265 rp->ai_socktype,
266 rp->ai_protocol);
268 if (sock < 0) continue;
270 if (connect(sock,
271 rp->ai_addr,
272 rp->ai_addrlen) >= 0) {
273 /* connected */
274 printf("connected to host '%s', port %s.\n",
275 host, port);
276 fd = sock;
277 break;
279 fprintf(stderr, "failed to connect: %s\n",
280 strerror(errno));
282 close(sock);
284 freeaddrinfo(result);
286 if (rp == NULL) {
287 fprintf(stderr, "couldn't connect to host '%s'!\n",
288 host);
290 } else {
291 fprintf(stderr, "couldn't find host '%s': %s\n",
292 host, gai_strerror(status));
294 } else {
295 fprintf(stderr, "corrupted host[:port] '%s'!\n", param);
297 g_strfreev(parts);
299 return(fd);
302 int main(int argc, char *argv[])
304 struct sipe_cert_crypto *scc;
306 sipe_crypto_init(FALSE);
307 srand(time(NULL));
309 scc = sipe_cert_crypto_init();
310 if (scc) {
311 gpointer certificate;
312 struct sipe_tls_state *state;
314 printf("SIPE cert crypto backend initialized.\n");
316 certificate = sipe_cert_crypto_test_certificate(scc);
317 state = sipe_tls_start(certificate);
318 if (state) {
319 int fd;
321 printf("SIPE TLS initialized.\n");
323 fd = tls_connect((argc > 1) ? argv[1] : "localhost:8443");
324 if (fd >= 0) {
325 tls_handshake(state, fd);
326 close(fd);
329 sipe_tls_free(state);
332 sipe_cert_crypto_destroy(certificate);
333 sipe_cert_crypto_free(scc);
335 sipe_crypto_shutdown();
337 return(0);
341 Local Variables:
342 mode: c
343 c-file-style: "bsd"
344 indent-tabs-mode: t
345 tab-width: 8
346 End: