1 /*-
2  * SSLsplit - transparent SSL/TLS interception
3  * https://www.roe.ch/SSLsplit
4  *
5  * Copyright (c) 2009-2019, Daniel Roethlisberger <daniel@roe.ch>.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are met:
10  * 1. Redistributions of source code must retain the above copyright notice,
11  *    this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright notice,
13  *    this list of conditions and the following disclaimer in the documentation
14  *    and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "ssl.h"
30 #include "cachemgr.h"
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <string.h>
36 #include <netinet/in.h>
37 #include <time.h>
38 
39 #include <check.h>
40 
41 #if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20501000L
42 #define TMP_SESS_FILE "extra/pki/session-libressl-2.5.0.pem"
43 #else
44 #define TMP_SESS_FILE "extra/pki/session.pem"
45 #endif
46 
47 static SSL_SESSION *
ssl_session_from_file(const char * filename)48 ssl_session_from_file(const char *filename)
49 {
50 	SSL_SESSION *sess;
51 	FILE *f;
52 
53 	f = fopen(filename, "r");
54 	if (!f)
55 		return NULL;
56 	sess = PEM_read_SSL_SESSION(f, NULL, NULL, NULL);
57 	fclose(f);
58 	/* to avoid having to regenerate the session, just bump its time */
59 	SSL_SESSION_set_time(sess, time(NULL) - 1);
60 	return sess;
61 }
62 
63 static struct sockaddr_storage addr;
64 static socklen_t addrlen;
65 static char sni[] = "daniel.roe.ch";
66 
67 static void
cachemgr_setup(void)68 cachemgr_setup(void)
69 {
70 	if ((ssl_init() == -1) || (cachemgr_preinit() == -1))
71 		exit(EXIT_FAILURE);
72 	addrlen = sizeof(struct sockaddr_in);
73 	memset(&addr, 0, addrlen);
74 	addr.ss_family = AF_INET;
75 }
76 
77 static void
cachemgr_teardown(void)78 cachemgr_teardown(void)
79 {
80 	cachemgr_fini();
81 	ssl_fini();
82 }
83 
START_TEST(cache_dsess_01)84 START_TEST(cache_dsess_01)
85 {
86 	SSL_SESSION *s1, *s2;
87 
88 	s1 = ssl_session_from_file(TMP_SESS_FILE);
89 	fail_unless(!!s1, "creating session failed");
90 	fail_unless(ssl_session_is_valid(s1), "session invalid");
91 
92 	cachemgr_dsess_set((struct sockaddr*)&addr, addrlen, sni, s1);
93 	s2 = cachemgr_dsess_get((struct sockaddr*)&addr, addrlen, sni);
94 	fail_unless(!!s2, "cache returned no session");
95 	fail_unless(s2 != s1, "cache returned same pointer");
96 	SSL_SESSION_free(s1);
97 	SSL_SESSION_free(s2);
98 }
99 END_TEST
100 
START_TEST(cache_dsess_02)101 START_TEST(cache_dsess_02)
102 {
103 	SSL_SESSION *s1, *s2;
104 
105 	s1 = ssl_session_from_file(TMP_SESS_FILE);
106 	fail_unless(!!s1, "creating session failed");
107 	fail_unless(ssl_session_is_valid(s1), "session invalid");
108 
109 	s2 = cachemgr_dsess_get((struct sockaddr*)&addr, addrlen, sni);
110 	fail_unless(s2 == NULL, "session was already in empty cache");
111 	SSL_SESSION_free(s1);
112 }
113 END_TEST
114 
START_TEST(cache_dsess_03)115 START_TEST(cache_dsess_03)
116 {
117 	SSL_SESSION *s1, *s2;
118 
119 	s1 = ssl_session_from_file(TMP_SESS_FILE);
120 	fail_unless(!!s1, "creating session failed");
121 	fail_unless(ssl_session_is_valid(s1), "session invalid");
122 
123 	cachemgr_dsess_set((struct sockaddr*)&addr, addrlen, sni, s1);
124 	cachemgr_dsess_del((struct sockaddr*)&addr, addrlen, sni);
125 	s2 = cachemgr_dsess_get((struct sockaddr*)&addr, addrlen, sni);
126 	fail_unless(s2 == NULL, "cache returned deleted session");
127 	SSL_SESSION_free(s1);
128 }
129 END_TEST
130 
131 #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
START_TEST(cache_dsess_04)132 START_TEST(cache_dsess_04)
133 {
134 	SSL_SESSION *s1, *s2;
135 
136 	s1 = ssl_session_from_file(TMP_SESS_FILE);
137 	fail_unless(!!s1, "creating session failed");
138 	fail_unless(ssl_session_is_valid(s1), "session invalid");
139 
140 	fail_unless(s1->references == 1, "refcount != 1");
141 	cachemgr_dsess_set((struct sockaddr*)&addr, addrlen, sni, s1);
142 	fail_unless(s1->references == 1, "refcount != 1");
143 	s2 = cachemgr_dsess_get((struct sockaddr*)&addr, addrlen, sni);
144 	fail_unless(s1->references == 1, "refcount != 1");
145 	fail_unless(!!s2, "cache returned no session");
146 	fail_unless(s2->references == 1, "refcount != 1");
147 	cachemgr_dsess_set((struct sockaddr*)&addr, addrlen, sni, s1);
148 	fail_unless(s1->references == 1, "refcount != 1");
149 	cachemgr_dsess_del((struct sockaddr*)&addr, addrlen, sni);
150 	fail_unless(s1->references == 1, "refcount != 1");
151 	cachemgr_dsess_set((struct sockaddr*)&addr, addrlen, sni, s1);
152 	fail_unless(s1->references == 1, "refcount != 1");
153 	SSL_SESSION_free(s1);
154 	SSL_SESSION_free(s2);
155 }
156 END_TEST
157 #endif
158 
159 Suite *
cachedsess_suite(void)160 cachedsess_suite(void)
161 {
162 	Suite *s;
163 	TCase *tc;
164 
165 	s = suite_create("cachedsess");
166 
167 	tc = tcase_create("cache_dsess");
168 	tcase_add_checked_fixture(tc, cachemgr_setup, cachemgr_teardown);
169 	tcase_add_test(tc, cache_dsess_01);
170 	tcase_add_test(tc, cache_dsess_02);
171 	tcase_add_test(tc, cache_dsess_03);
172 #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
173 	tcase_add_test(tc, cache_dsess_04);
174 #endif
175 	suite_add_tcase(s, tc);
176 
177 	return s;
178 }
179 
180 /* vim: set noet ft=c: */
181