870eb4095efdef7410cec95387b66aa1fd686cb5
[platform/core/security/pubkey-pinning.git] / test / gnutls_test.cpp
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 /*
17  * @file        gnutls_sample.cpp
18  * @author      Kyungwook Tak (k.tak@samsung.com)
19  * @version     1.0
20  * @brief       tpkp_gnutls unit test.
21  */
22 #include <iostream>
23 #include <vector>
24 #include <string>
25 #include <thread>
26
27 #include <unistd.h>
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <netdb.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
33
34 #include <gnutls/gnutls.h>
35 #include <tpkp_gnutls.h>
36 #include <boost/test/unit_test.hpp>
37
38 namespace {
39
40 struct DataSet {
41         gnutls_session_t session;
42         gnutls_certificate_credentials_t cred;
43         int sockfd;
44 };
45
46 static std::vector<std::string> s_urlList = {
47         "www.google.com",
48         "www.youtube.com",
49         "www.spideroak.com",
50         "www.facebook.com",
51         "www.dropbox.com",
52         "www.twitter.com",
53         "www.hackerrank.com", /* no pinned data exist */
54         "www.algospot.com"    /* no pinned data exist */
55 };
56
57 void connectWithUrl(const std::string &url, int &sockfd)
58 {
59         struct addrinfo *result;
60         struct addrinfo hints;
61         memset(&hints, 0x00, sizeof(struct addrinfo));
62         hints.ai_family = AF_UNSPEC;
63         hints.ai_socktype = SOCK_STREAM;
64         hints.ai_flags = AI_CANONNAME;
65
66         int s = getaddrinfo(url.c_str(), "https", &hints, &result);
67         BOOST_REQUIRE_MESSAGE(s == 0, "getaddrinfo err code: " << s << " desc: " << gai_strerror(s));
68
69         struct addrinfo *rp;
70         for (rp = result; rp != nullptr; rp = rp->ai_next) {
71                 sockfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
72                 if (sockfd == -1)
73                         continue;
74
75                 if (connect(sockfd, rp->ai_addr, rp->ai_addrlen) != -1) {
76                         char *ipaddr = inet_ntoa(*((struct in_addr *)rp->ai_addr));
77                         break;
78                 }
79
80                 close(sockfd);
81         }
82
83         BOOST_REQUIRE_MESSAGE(rp != nullptr, "Could not connect on url: " << url);
84
85         std::cout << "url[" << url << "] canonname[" << result->ai_canonname << "] connected!" << std::endl;
86
87         freeaddrinfo(result);
88 }
89
90 inline gnutls_certificate_credentials_t makeDefaultCred(gnutls_certificate_verify_function *verify_callback)
91 {
92         gnutls_certificate_credentials_t cred;
93
94         int ret = gnutls_certificate_allocate_credentials(&cred);
95         BOOST_REQUIRE_MESSAGE(
96                 ret == GNUTLS_E_SUCCESS,
97                 "Failed to gnutls_certificate_allocate_credentials: " << gnutls_strerror(ret));
98
99         ret = gnutls_certificate_set_x509_trust_file(cred, "/etc/ssl/ca-bundle.pem", GNUTLS_X509_FMT_PEM);
100         BOOST_REQUIRE_MESSAGE(
101                 ret > 0,
102                 "Failed to gnutls_certificate_set_x509_trust_file ret: " << ret);
103
104         gnutls_certificate_set_verify_function(cred, verify_callback);
105
106         return cred;
107 }
108
109 DataSet makeDefaultSession(const std::string &url)
110 {
111         DataSet data;
112
113         data.cred = makeDefaultCred(&tpkp_gnutls_verify_callback);
114
115         int ret = gnutls_init(&data.session, GNUTLS_CLIENT);
116         BOOST_REQUIRE_MESSAGE(
117                 ret == GNUTLS_E_SUCCESS,
118                 "Failed to gnutls init session: " << gnutls_strerror(ret));
119
120         ret = gnutls_set_default_priority(data.session);
121         BOOST_REQUIRE_MESSAGE(
122                 ret == GNUTLS_E_SUCCESS,
123                 "Failed to set default priority on session: " << gnutls_strerror(ret));
124
125         ret = gnutls_credentials_set(data.session, GNUTLS_CRD_CERTIFICATE, data.cred);
126         BOOST_REQUIRE_MESSAGE(
127                 ret == GNUTLS_E_SUCCESS,
128                 "Failed to gnutls_credentials_set: " << gnutls_strerror(ret));
129
130         connectWithUrl(url, data.sockfd);
131
132         BOOST_REQUIRE_MESSAGE(
133                 tpkp_gnutls_set_url_data(url.c_str()) == TPKP_E_NONE,
134                 "Failed to tpkp_gnutls_set_url_data.");
135
136         gnutls_transport_set_int(data.session, data.sockfd);
137         gnutls_handshake_set_timeout(data.session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
138
139         return data;
140 }
141
142 DataSet makeSessionWithoutPinning(const std::string &url)
143 {
144         DataSet data;
145
146         int ret = gnutls_certificate_allocate_credentials(&data.cred);
147         BOOST_REQUIRE_MESSAGE(
148                 ret == GNUTLS_E_SUCCESS,
149                 "Failed to gnutls_certificate_allocate_credentials: " << gnutls_strerror(ret));
150
151         ret = gnutls_init(&data.session, GNUTLS_CLIENT);
152         BOOST_REQUIRE_MESSAGE(
153                 ret == GNUTLS_E_SUCCESS,
154                 "Failed to gnutls init session: " << gnutls_strerror(ret));
155
156         ret = gnutls_set_default_priority(data.session);
157         BOOST_REQUIRE_MESSAGE(
158                 ret == GNUTLS_E_SUCCESS,
159                 "Failed to set default priority on session: " << gnutls_strerror(ret));
160
161         ret = gnutls_credentials_set(data.session, GNUTLS_CRD_CERTIFICATE, data.cred);
162         BOOST_REQUIRE_MESSAGE(
163                 ret == GNUTLS_E_SUCCESS,
164                 "Failed to gnutls_credentials_set: " << gnutls_strerror(ret));
165
166         connectWithUrl(url, data.sockfd);
167
168         gnutls_transport_set_int(data.session, data.sockfd);
169         gnutls_handshake_set_timeout(data.session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
170
171         return data;
172 }
173
174 DataSet makeDefaultSessionGlobal(const std::string &url)
175 {
176         int ret = gnutls_global_init();
177         BOOST_REQUIRE_MESSAGE(
178                 ret == GNUTLS_E_SUCCESS,
179                 "Failed to gnutls global init: " << gnutls_strerror(ret));
180
181         return makeDefaultSession(url);
182 }
183
184 void performHandshake(DataSet &data)
185 {
186         int ret;
187         do {
188                 ret = gnutls_handshake(data.session);
189         } while (ret != GNUTLS_E_SUCCESS && gnutls_error_is_fatal(ret) == 0);
190
191         BOOST_REQUIRE_MESSAGE(
192                 ret == GNUTLS_E_SUCCESS,
193                 "Handshake failed! err code: " << ret << " desc: " << gnutls_strerror(ret));
194 }
195
196 void cleanup(DataSet &data)
197 {
198         gnutls_bye(data.session, GNUTLS_SHUT_RDWR);
199         close(data.sockfd);
200         gnutls_certificate_free_credentials(data.cred);
201         gnutls_deinit(data.session);
202
203         tpkp_gnutls_cleanup();
204 }
205
206 void cleanupGlobal(DataSet &data)
207 {
208         cleanup(data);
209         gnutls_global_deinit();
210 }
211
212 void perform(const std::string &url)
213 {
214         DataSet data = makeDefaultSession(url);
215         performHandshake(data);
216         cleanup(data);
217 }
218
219 void performWithoutPinning(const std::string &url)
220 {
221         DataSet data = makeSessionWithoutPinning(url);
222         performHandshake(data);
223         cleanup(data);
224 }
225
226 }
227
228 BOOST_AUTO_TEST_SUITE(TPKP_GNUTLS_TEST)
229
230 BOOST_AUTO_TEST_CASE(T00101_positive_1)
231 {
232         gnutls_global_init();
233
234         perform(s_urlList[0]);
235
236         gnutls_global_deinit();
237 }
238
239 BOOST_AUTO_TEST_CASE(T00102_positive_2)
240 {
241         gnutls_global_init();
242
243         perform(s_urlList[1]);
244
245         gnutls_global_deinit();
246 }
247
248 BOOST_AUTO_TEST_CASE(T00103_positive_3)
249 {
250         gnutls_global_init();
251
252         perform(s_urlList[2]);
253
254         gnutls_global_deinit();
255 }
256
257 BOOST_AUTO_TEST_CASE(T00104_positive_4)
258 {
259         gnutls_global_init();
260
261         perform(s_urlList[3]);
262
263         gnutls_global_deinit();
264 }
265
266 BOOST_AUTO_TEST_CASE(T00105_positive_5)
267 {
268         gnutls_global_init();
269
270         perform(s_urlList[4]);
271
272         gnutls_global_deinit();
273 }
274
275 BOOST_AUTO_TEST_CASE(T00106_positive_6)
276 {
277         gnutls_global_init();
278
279         perform(s_urlList[5]);
280
281         gnutls_global_deinit();
282 }
283
284 BOOST_AUTO_TEST_CASE(T00107_positive_7)
285 {
286         gnutls_global_init();
287
288         perform(s_urlList[6]);
289
290         gnutls_global_deinit();
291 }
292
293 BOOST_AUTO_TEST_CASE(T00108_positive_8)
294 {
295         gnutls_global_init();
296
297         perform(s_urlList[7]);
298
299         gnutls_global_deinit();
300 }
301
302 BOOST_AUTO_TEST_CASE(T00109_positive_all_single_thread)
303 {
304         gnutls_global_init();
305
306         for (const auto &url : s_urlList)
307                 perform(url);
308
309         gnutls_global_deinit();
310 }
311
312 BOOST_AUTO_TEST_CASE(T00110_positive_all_single_thread_without_pinning)
313 {
314         gnutls_global_init();
315
316         for (const auto &url : s_urlList)
317                 performWithoutPinning(url);
318
319         gnutls_global_deinit();
320 }
321
322 BOOST_AUTO_TEST_SUITE_END()