1/*
2 * Copyright (C) 2014 Samsung Electronics. All rights reserved.
3 * Copyright (C) 2014 University of Szeged. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24 * THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "config.h"
28
29#include "UnitTestUtils/EWK2UnitTestBase.h"
30#include "UnitTestUtils/EWK2UnitTestServer.h"
31
32using namespace EWK2UnitTest;
33
34extern EWK2UnitTestEnvironment* environment;
35
36static const char indexHTMLString[] =
37    "<html>"
38    "<head><title>EFLWebKit2 SSL test</title></head>"
39    "<body></body></html>";
40
41static bool finishTest = false;
42static constexpr double testTimeoutSeconds = 2.0;
43
44WTF::CString httpUri;
45
46#define STRINGIFY2(x) #x
47#define STRINGIFY(x) STRINGIFY2(x)
48
49static const gchar certificate_data[] = STRINGIFY(-----BEGIN RSA PRIVATE KEY-----
50MIICXQIBAAKBgQCmcXbusrr8zQr8snIb0OVQibVfgv7zPjh/5xdcrKOejJzp3epA
51AF4TITeFR9vzWIwkmkcRoY+IbQNhh7kefGUYD47bvVamJMtq5cGYVs0HngT+KTMa
52NGH/G44KkFIOaz/b5d/JNKONrlqwxqXS+m6IY4l/E1Ff25ZjND5TaEvI1wIDAQAB
53AoGBAIcDv4A9h6UOBv2ZGyspNvsv2erSblGOhXJrWO4aNNemJJspIp4sLiPCbDE3
54a1po17XRWBkbPz1hgL6axDXQnoeo++ebfrvRSed+Fys4+6SvuSrPOv6PmWTBT/Wa
55GpO+tv48JUNxC/Dy8ROixBXOViuIBEFq3NfVH4HU3+RG20NhAkEA1L3RAhdfPkLI
5682luSOYE3Eq44lICb/yZi+JEihwSeZTJKdZHwYD8KVCjOtjGrOmyEyvThrcIACQz
57JLEreVh33wJBAMhJm9pzJJNkIyBgiXA66FAwbhdDzSTPx0OBjoVWoj6u7jzGvIFT
58Cn1aiTBYzzsiMCaCx+W3e6pK/DcvHSwKrgkCQHZMcxwBmSHLC2lnmD8LQWqqVnLr
59fZV+VnfVw501DQT0uoP8NvygWBg1Uf9YKepfLXnBpidEQjup5ZKivnUEv+sCQA8N
606VcMHI2vkyxV1T7ITrnoSf4ZrIu9yl56mHnRPzSy9VlAHt8hnMI7UeB+bGUndrMO
61VXQgzHzKUhbbxbePvfECQQDTtkOuhJyKDfHCxLDcwNpi+T6OWTEfCw/cq9ZWDbA7
62yCX81pQxfZkfMIS1YFIOGHovK0rMMTraCe+iDNYtVz/L
63-----END RSA PRIVATE KEY-----
64-----BEGIN CERTIFICATE-----
65MIIB9zCCAWACCQDjWWTeC6BQvTANBgkqhkiG9w0BAQQFADBAMQswCQYDVQQGEwJB
66VTETMBEGA1UECBMKU29tZS1TdGF0ZTEcMBoGA1UEChMTV2ViS2l0IExheW91dCBU
67ZXN0czAeFw0wNzA3MTMxMjUxMzJaFw03MTA1MTMwNjIzMTZaMEAxCzAJBgNVBAYT
68AkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMRwwGgYDVQQKExNXZWJLaXQgTGF5b3V0
69IFRlc3RzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCmcXbusrr8zQr8snIb
700OVQibVfgv7zPjh/5xdcrKOejJzp3epAAF4TITeFR9vzWIwkmkcRoY+IbQNhh7ke
71fGUYD47bvVamJMtq5cGYVs0HngT+KTMaNGH/G44KkFIOaz/b5d/JNKONrlqwxqXS
72+m6IY4l/E1Ff25ZjND5TaEvI1wIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAAfbUbgD
7301O8DoZA02c1MUMbMHRPSb/qdok2pyWoCPa/BSaOIaNPePc8auPRbrS2XsVWSMft
74CTXiXmrK2Xx1+fJuZLAp0CUng4De4cDH5c8nvlocYmXo+1x53S9DfD0KPryjBRI7
759LnJq2ysHAUawiqFXlwBag6mXawD8YjzcYat
76-----END CERTIFICATE-----);
77
78class EWK2SSLTest : public EWK2UnitTestBase {
79public:
80
81    static void onLoadProvisionalFailedFail(void* userData, Evas_Object*, void* eventInfo)
82    {
83        finishTest = true;
84        // The test passes if an SSL error occurs.
85        ASSERT_TRUE(ewk_error_code_get(static_cast<Ewk_Error*>(eventInfo)) == SOUP_STATUS_SSL_FAILED);
86    }
87
88    static void onLoadFinishedFail(void* userData, Evas_Object*, void*)
89    {
90        bool* isFinished = static_cast<bool*>(userData);
91        if (isFinished) {
92            finishTest = true;
93            // The test fails if the page is loaded.
94            FAIL();
95        }
96    }
97
98    static void onLoadProvisionalFailedIgnore(void* userData, Evas_Object*, void* eventInfo)
99    {
100        finishTest = true;
101        if (ewk_error_code_get(static_cast<Ewk_Error*>(eventInfo)) == SOUP_STATUS_SSL_FAILED)
102            // The test fails if an SSL error occurs.
103            FAIL();
104    }
105
106    static void onLoadFinishedIgnore(void* userData, Evas_Object*, void*)
107    {
108        bool* isFinished = static_cast<bool*>(userData);
109        finishTest = true;
110        // The test passes if the page is loaded.
111        ASSERT_TRUE(isFinished);
112    }
113
114    static void serverCallbackBadCertPageLoadTest(SoupServer*, SoupMessage* message, const char* path, GHashTable*, SoupClientContext*, void*)
115    {
116        if (message->method != SOUP_METHOD_GET) {
117            soup_message_set_status(message, SOUP_STATUS_NOT_IMPLEMENTED);
118            return;
119        }
120
121        if (!strcmp(path, "/index.html")) {
122            soup_message_set_status(message, SOUP_STATUS_OK);
123            soup_message_body_append(message->response_body, SOUP_MEMORY_COPY, indexHTMLString, strlen(indexHTMLString));
124        } else
125            soup_message_set_status(message, SOUP_STATUS_NOT_FOUND);
126
127        soup_message_body_complete(message->response_body);
128    }
129
130    static void serverCallbackBadCertRedirectHttps(SoupServer*, SoupMessage* message, const char* path, GHashTable*, SoupClientContext*, void*)
131    {
132        if (message->method != SOUP_METHOD_GET) {
133            soup_message_set_status(message, SOUP_STATUS_NOT_IMPLEMENTED);
134            return;
135        }
136
137        soup_message_set_redirect(message, SOUP_STATUS_MOVED_PERMANENTLY, httpUri.data());
138    }
139
140    static void serverCallbackBadCertRedirectHttp(SoupServer*, SoupMessage* message, const char* path, GHashTable*, SoupClientContext*, void*)
141    {
142        if (message->method != SOUP_METHOD_GET) {
143            soup_message_set_status(message, SOUP_STATUS_NOT_IMPLEMENTED);
144            return;
145        }
146
147        if (!strcmp(path, "/index.html")) {
148            soup_message_set_status(message, SOUP_STATUS_OK);
149            soup_message_body_append(message->response_body, SOUP_MEMORY_COPY, indexHTMLString, strlen(indexHTMLString));
150        } else
151            soup_message_set_status(message, SOUP_STATUS_NOT_FOUND);
152    }
153};
154
155static GTlsCertificate* getCertificate()
156{
157    GError** gerror;
158    GTlsCertificate* certificate = g_tls_certificate_new_from_pem(
159        certificate_data, sizeof(certificate_data), gerror);
160
161    if (!certificate)
162        fprintf(stderr, "Unable to create certificate from PEM\n");
163
164    return certificate;
165}
166
167TEST_F(EWK2SSLTest, ewk_ssl_set_tls_error_policy_ignore)
168{
169    Ewk_Context* context = ewk_view_context_get(webView());
170
171    ewk_context_tls_error_policy_set(context, EWK_TLS_ERROR_POLICY_IGNORE);
172
173    ASSERT_TRUE(ewk_context_tls_error_policy_get(context) == EWK_TLS_ERROR_POLICY_IGNORE);
174}
175
176TEST_F(EWK2SSLTest, ewk_ssl_set_tls_error_policy_fail)
177{
178    Ewk_Context* context = ewk_view_context_get(webView());
179
180    ewk_context_tls_error_policy_set(context, EWK_TLS_ERROR_POLICY_FAIL);
181
182    ASSERT_TRUE(ewk_context_tls_error_policy_get(context) == EWK_TLS_ERROR_POLICY_FAIL);
183}
184
185TEST_F(EWK2SSLTest, ewk_ssl_bad_cert_page_load_test_policy_ignore)
186{
187    finishTest = false;
188
189    Ewk_Context* context = ewk_view_context_get(webView());
190    ewk_context_tls_error_policy_set(context, EWK_TLS_ERROR_POLICY_IGNORE);
191
192    GTlsCertificate* TLSCertificate = getCertificate();
193
194    if (!TLSCertificate)
195        FAIL();
196
197    std::unique_ptr<EWK2UnitTestServer> httpsServer = std::make_unique<EWK2UnitTestServer>(TLSCertificate);
198    httpsServer->run(serverCallbackBadCertPageLoadTest);
199
200    Ewk_Error* error = nullptr;
201    evas_object_smart_callback_add(webView(), "load,provisional,failed", onLoadProvisionalFailedIgnore, &error);
202
203    bool isFinished = false;
204    evas_object_smart_callback_add(webView(), "load,finished", onLoadFinishedIgnore, &isFinished);
205
206    ewk_view_url_set(webView(), httpsServer->getURLForPath("/index.html").data());
207
208    waitUntilTrue(finishTest, testTimeoutSeconds);
209}
210
211TEST_F(EWK2SSLTest, ewk_ssl_bad_cert_page_load_test_policy_fail)
212{
213    finishTest = false;
214
215    Ewk_Context* context = ewk_view_context_get(webView());
216    ewk_context_tls_error_policy_set(context, EWK_TLS_ERROR_POLICY_FAIL);
217
218    GTlsCertificate* TLSCertificate = getCertificate();
219
220    if (!TLSCertificate)
221        FAIL();
222
223    std::unique_ptr<EWK2UnitTestServer> httpsServer = std::make_unique<EWK2UnitTestServer>(TLSCertificate);
224    httpsServer->run(serverCallbackBadCertPageLoadTest);
225
226    Ewk_Error* error = nullptr;
227    evas_object_smart_callback_add(webView(), "load,provisional,failed", onLoadProvisionalFailedFail, &error);
228
229    bool isFinished = false;
230    evas_object_smart_callback_add(webView(), "load,finished", onLoadFinishedFail, &isFinished);
231
232    ewk_view_url_set(webView(), httpsServer->getURLForPath("/index.html").data());
233
234    waitUntilTrue(finishTest, testTimeoutSeconds);
235}
236
237TEST_F(EWK2SSLTest, ewk_ssl_bad_cert_redirect_https_to_http)
238{
239    finishTest = false;
240
241    Ewk_Context* context = ewk_view_context_get(webView());
242    ewk_context_tls_error_policy_set(context, EWK_TLS_ERROR_POLICY_FAIL);
243
244    GTlsCertificate* TLSCertificate = getCertificate();
245
246    if (!TLSCertificate)
247        FAIL();
248
249    std::unique_ptr<EWK2UnitTestServer> httpsServer = std::make_unique<EWK2UnitTestServer>(TLSCertificate);
250    httpsServer->run(serverCallbackBadCertRedirectHttps);
251    std::unique_ptr<EWK2UnitTestServer> httpServer = std::make_unique<EWK2UnitTestServer>();
252    httpServer->run(serverCallbackBadCertRedirectHttp);
253
254    Ewk_Error* error = nullptr;
255    evas_object_smart_callback_add(webView(), "load,provisional,failed", onLoadProvisionalFailedFail, &error);
256
257    bool isFinished = false;
258    evas_object_smart_callback_add(webView(), "load,finished", onLoadFinishedFail, &isFinished);
259
260    httpUri = httpServer->getURLForPath("/index.html");
261    ewk_view_url_set(webView(), httpsServer->getURLForPath("/index.html").data());
262
263    waitUntilTrue(finishTest, testTimeoutSeconds);
264}
265