2 * @file sipe-tls-tester.c
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:
45 * You can add <host>[:<port>] to connect to a server on another machine
56 #include <sys/types.h>
57 #include <sys/socket.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"
72 gboolean
sipe_backend_debug_enabled(void)
77 void sipe_backend_debug_literal(sipe_debug_level level
,
80 printf("DEBUG(%d): %s\n", level
, msg
);
83 void sipe_backend_debug(sipe_debug_level level
,
88 gchar
*newformat
= g_strdup_printf("DEBUG(%d): %s\n", level
, format
);
91 vprintf(newformat
, ap
);
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
)
113 static guchar
*read_tls_record(int fd
,
116 GSList
*fragments
= NULL
;
117 guchar
*merged
= NULL
;
119 static gchar buffer
[10000];
122 struct pollfd fds
[] = {
126 struct record
*record
;
129 result
= poll(fds
, 1, 500 /* [milliseconds] */);
131 printf("poll failed: %s\n", strerror(errno
));
136 printf("timeout.\n");
139 printf("reading done.\n");
144 result
= read(fd
, buffer
, sizeof(buffer
));
146 printf("read failed: %s\n", strerror(errno
));
150 printf("server closed connection: %s\n",
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
);
160 fragments
= g_slist_append(fragments
, record
);
164 GSList
*elem
= fragments
;
167 printf("received a total of %" G_GSIZE_FORMAT
" bytes.\n",
170 p
= merged
= g_malloc(length
);
173 struct record
*record
= elem
->data
;
175 memcpy(p
, record
->msg
, record
->length
);
183 printf("can't allocate %" G_GSIZE_FORMAT
" bytes.\n",
187 g_slist_free(fragments
);
194 static void tls_handshake(struct sipe_tls_state
*state
,
197 gboolean success
= FALSE
;
199 printf("TLS handshake starting...\n");
201 /* generate next handshake message */
202 while (sipe_tls_next(state
)) {
205 /* handshake completed? */
206 if (!state
->out_buffer
) {
211 /* send buffer to server */
212 sent
= write(fd
, state
->out_buffer
, state
->out_length
);
214 printf("write to server failed: %s\n",
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
);
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");
234 printf("TLS handshake %s.\n", success
? "SUCCESSFUL" : "FAILED");
238 static int tls_connect(const gchar
*param
)
240 gchar
**parts
= g_strsplit(param
, ":", 2);
244 const gchar
*host
= parts
[0];
245 const gchar
*port
= parts
[1] ? parts
[1] : "443";
246 struct addrinfo hints
;
247 struct addrinfo
*result
;
250 printf("TLS connect to host '%s', port %s...\n",
253 memset(&hints
, 0, sizeof(struct addrinfo
));
254 hints
.ai_family
= AF_UNSPEC
;
255 hints
.ai_socktype
= SOCK_STREAM
;
257 hints
.ai_protocol
= 0;
258 status
= getaddrinfo(host
, port
, &hints
, &result
);
263 for (rp
= result
; rp
!= NULL
; rp
= rp
->ai_next
) {
264 int sock
= socket(rp
->ai_family
,
268 if (sock
< 0) continue;
272 rp
->ai_addrlen
) >= 0) {
274 printf("connected to host '%s', port %s.\n",
279 fprintf(stderr
, "failed to connect: %s\n",
284 freeaddrinfo(result
);
287 fprintf(stderr
, "couldn't connect to host '%s'!\n",
291 fprintf(stderr
, "couldn't find host '%s': %s\n",
292 host
, gai_strerror(status
));
295 fprintf(stderr
, "corrupted host[:port] '%s'!\n", param
);
302 int main(int argc
, char *argv
[])
304 struct sipe_cert_crypto
*scc
;
306 sipe_crypto_init(FALSE
);
309 scc
= sipe_cert_crypto_init();
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
);
321 printf("SIPE TLS initialized.\n");
323 fd
= tls_connect((argc
> 1) ? argv
[1] : "localhost:8443");
325 tls_handshake(state
, fd
);
329 sipe_tls_free(state
);
332 sipe_cert_crypto_destroy(certificate
);
333 sipe_cert_crypto_free(scc
);
335 sipe_crypto_shutdown();