Generate popup message when pubkey mismatched 83/59483/8
authorKyungwook Tak <k.tak@samsung.com>
Mon, 15 Feb 2016 06:08:20 +0000 (15:08 +0900)
committerKyungwook Tak <k.tak@samsung.com>
Tue, 23 Feb 2016 11:54:49 +0000 (20:54 +0900)
Change-Id: Ie0496d0884e35b10e3e6bdd1320c1571d904288f
Signed-off-by: Kyungwook Tak <k.tak@samsung.com>
30 files changed:
CMakeLists.txt
packaging/pubkey-pinning.spec
src/common/CMakeLists.txt
src/common/include/tpkp_client_cache.h
src/common/include/ui/connection.h [new file with mode: 0644]
src/common/include/ui/popup_common.h [new file with mode: 0644]
src/common/include/ui/popup_runner.h [new file with mode: 0644]
src/common/include/ui/serialization.h [new file with mode: 0644]
src/common/src/tpkp_client_cache.cpp
src/common/src/tpkp_common.cpp
src/common/ui/CMakeLists.txt [new file with mode: 0644]
src/common/ui/connection.cpp [new file with mode: 0644]
src/common/ui/po/CMakeLists.txt [new file with mode: 0644]
src/common/ui/po/en.po [new file with mode: 0644]
src/common/ui/po/en_GB.po [new file with mode: 0644]
src/common/ui/po/en_US.po [new file with mode: 0644]
src/common/ui/popup-bin/CMakeLists.txt [new file with mode: 0644]
src/common/ui/popup-bin/popup.cpp [new file with mode: 0644]
src/common/ui/popup_common.cpp [new file with mode: 0644]
src/common/ui/popup_runner.cpp [new file with mode: 0644]
src/common/ui/serialization.cpp [new file with mode: 0644]
src/curl/tpkp_curl.cpp
src/gnutls/tpkp_gnutls.cpp
systemd/CMakeLists.txt [new file with mode: 0644]
systemd/pubkey-pinning-popup.service.in [new file with mode: 0644]
systemd/pubkey-pinning-popup.socket [new file with mode: 0644]
test/CMakeLists.txt
test/curl_test.cpp
test/popup_runner_test.cpp [new file with mode: 0644]
test/popup_test_main.cpp [new file with mode: 0644]

index 18937c3..fa2510f 100644 (file)
@@ -42,6 +42,8 @@ ADD_DEFINITIONS("-DBUILD_TYPE_DEBUG")
 ADD_DEFINITIONS("-DDPL_LOGS_ENABLED")
 ENDIF (CMAKE_BUILD_TYPE MATCHES "DEBUG")
 
+ADD_DEFINITIONS("-DPROJECT_NAME=\"${PROJECT_NAME}\"")
+
 # compiler warning flags
 ADD_DEFINITIONS("-Wall")
 ADD_DEFINITIONS("-Wextra")
@@ -50,6 +52,7 @@ ADD_DEFINITIONS("-Werror")
 SET(TARGET_TPKP_COMMON_LIB "tpkp-common")
 SET(TARGET_TPKP_CURL_LIB "tpkp-curl")
 SET(TARGET_TPKP_GNUTLS_LIB "tpkp-gnutls")
+SET(TARGET_TPKP_POPUP "tpkp-popup")
 
 CONFIGURE_FILE(tpkp-curl.pc.in tpkp-curl.pc @ONLY)
 CONFIGURE_FILE(tpkp-gnutls.pc.in tpkp-gnutls.pc @ONLY)
@@ -62,8 +65,10 @@ INSTALL(
        )
 
 ADD_SUBDIRECTORY(src)
+ADD_SUBDIRECTORY(systemd)
 
 IF (DEFINED PUBKEY_PINNING_TEST_BUILD)
 SET(TARGET_TPKP_TEST "tpkp-internal-test")
+SET(TARGET_TPKP_POPUP_TEST "tpkp-internal-test-popup")
 ADD_SUBDIRECTORY(test)
 ENDIF (DEFINED PUBKEY_PINNING_TEST_BUILD)
index 4445d3a..4b79d77 100644 (file)
@@ -8,7 +8,13 @@ Group:      Security/Libraries
 License:    Apache-2.0 and BSD-2.0 and MPL-1.1
 Source0:    %name-%version.tar.gz
 Source1:    %name.manifest
+Requires(post): /sbin/ldconfig
+Requires(post): /usr/bin/systemctl
+Requires(postun): /sbin/ldconfig
+Requires(postun): /usr/bin/systemctl
+Requires(preun): /usr/bin/systemctl
 BuildRequires: cmake
+BuildRequires: gettext-tools
 BuildRequires: pkgconfig(glib-2.0)
 BuildRequires: pkgconfig(dlog)
 BuildRequires: pkgconfig(libxml-2.0)
@@ -16,6 +22,10 @@ BuildRequires: pkgconfig(libiri)
 BuildRequires: pkgconfig(libcurl)
 BuildRequires: pkgconfig(gnutls)
 BuildRequires: pkgconfig(openssl)
+BuildRequires: pkgconfig(elementary)
+BuildRequires: pkgconfig(libsystemd-daemon)
+BuildRequires: pkgconfig(vconf)
+%{?systemd_requires}
 
 %description
 Https Public Key Pinning for Tizen platform system framework.
@@ -60,17 +70,37 @@ export LDFLAGS+="-Wl,--rpath=%_prefix/lib"
 %if 0%{?pubkey_pinning_test_build}
         -DPUBKEY_PINNING_TEST_BUILD=1    \
 %endif
-        -DCMAKE_VERBOSE_MAKEFILE=ON
+        -DCMAKE_VERBOSE_MAKEFILE=ON \
+        -DSYSTEMD_UNIT_DIR=%_unitdir_user
 
 make %{?_smp_mflags}
 
 %install
 %make_install
-
-%post -p /sbin/ldconfig
-%postun -p /sbin/ldconfig
-
-%files
+mkdir -p %buildroot%_unitdir_user/default.target.wants
+mkdir -p %buildroot%_unitdir_user/sockets.target.wants
+ln -sf ../%name-popup.service %buildroot%_unitdir_user/default.target.wants/%name-popup.service
+ln -sf ../%name-popup.socket %buildroot%_unitdir_user/sockets.target.wants/%name-popup.socket
+%find_lang %{name}
+
+%post
+/sbin/ldconfig
+systemctl daemon-reload
+if [ $1 == 1 ]; then
+    systemctl restart %name-popup.service
+fi
+
+%preun
+if [ $1 == 0 ]; then
+    systemctl stop %name-popup.service
+    systemctl disable %name-popup
+fi
+
+%postun
+/sbin/ldconfig
+systemctl daemon-reload
+
+%files -f %{name}.lang
 %manifest %name.manifest
 %license LICENSE
 %license LICENSE.BSD-3-Clause
@@ -78,6 +108,11 @@ make %{?_smp_mflags}
 %_libdir/libtpkp-common.so.*
 %_libdir/libtpkp-curl.so.*
 %_libdir/libtpkp-gnutls.so.*
+%_unitdir_user/%name-popup.service
+%_unitdir_user/%name-popup.socket
+%_unitdir_user/default.target.wants/%name-popup.service
+%_unitdir_user/sockets.target.wants/%name-popup.socket
+%_bindir/tpkp-popup
 
 %files devel
 %_includedir/tpkp/common/tpkp_error.h
@@ -92,4 +127,5 @@ make %{?_smp_mflags}
 %if 0%{?pubkey_pinning_test_build}
 %files test
 %_bindir/tpkp-internal-test
+%_bindir/tpkp-internal-test-popup
 %endif
index aa4853e..bf68943 100644 (file)
@@ -37,6 +37,10 @@ SET(TPKP_COMMON_SRCS
        src/tpkp_common.cpp
        src/tpkp_parser.cpp
        src/tpkp_client_cache.cpp
+       ui/popup_common.cpp
+       ui/popup_runner.cpp
+       ui/serialization.cpp
+       ui/connection.cpp
        )
 
 ADD_LIBRARY(${TARGET_TPKP_COMMON_LIB} SHARED ${TPKP_COMMON_SRCS})
@@ -52,3 +56,5 @@ TARGET_LINK_LIBRARIES(${TARGET_TPKP_COMMON_LIB} ${TPKP_COMMON_DEP_LIBRARIES})
 
 INSTALL(TARGETS ${TARGET_TPKP_COMMON_LIB} DESTINATION ${LIB_INSTALL_DIR})
 INSTALL(FILES include/tpkp_error.h DESTINATION ${INCLUDEDIR}/tpkp/common)
+
+ADD_SUBDIRECTORY(ui)
index f1a26a5..e400a67 100644 (file)
@@ -32,6 +32,12 @@ namespace TPKP {
 
 class EXPORT_API ClientCache {
 public:
+       enum class Decision : int {
+               UNKNOWN,
+               ALLOWED,
+               DENIED
+       };
+
        ClientCache();
        virtual ~ClientCache();
 
@@ -41,9 +47,22 @@ public:
        void eraseUrl(void);
        void eraseUrlAll(void);
 
+       /* thread-globally user decision mapped to hostname extracted from url */
+       void setDecision(const std::string &url, Decision decision);
+       Decision getDecision(const std::string &url);
+
 private:
+       struct DecisionStruct {
+               Decision decision;
+               DecisionStruct() : decision(Decision::UNKNOWN) {}
+               DecisionStruct(Decision d) : decision(d) {}
+       };
+
        std::map<pid_t, std::string> m_urls;
        std::mutex m_url_mutex;
+
+       std::map<std::string, DecisionStruct> m_decisions;
+       std::mutex m_decision_mutex;
 };
 
 }
diff --git a/src/common/include/ui/connection.h b/src/common/include/ui/connection.h
new file mode 100644 (file)
index 0000000..587d4cd
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+/*
+ * @file        connection.h
+ * @author      Kyungwook Tak (k.tak@samsung.com)
+ * @version     1.0
+ */
+#pragma once
+
+#include <string>
+
+#include "ui/popup_common.h"
+
+#define TPKP_UI_SOCK_ADDR "/tmp/.tpkp-ui-backend.sock"
+
+namespace TPKP {
+namespace UI {
+
+class SockRaii {
+public:
+       SockRaii();
+       virtual ~SockRaii();
+
+       void connect(const std::string &interface);
+       void disconnect(void);
+       bool isConnected(void) const;
+       int get(void) const;
+       void waitForStreamIn(int timeout);
+
+protected:
+       void connectWrapper(int socket, const std::string &interface);
+       int m_sock;
+};
+
+class ServiceConnection {
+public:
+       ServiceConnection(const std::string &interface, int timeout);
+       virtual ~ServiceConnection();
+
+       void send(const BinaryStream &stream);
+       BinaryStream receive(void);
+
+       void prepareConnection(void);
+       BinaryStream processRequest(const BinaryStream &input);
+
+protected:
+       SockRaii m_socket;
+       std::string m_serviceInterface;
+       int m_timeout;
+
+};
+
+}
+}
diff --git a/src/common/include/ui/popup_common.h b/src/common/include/ui/popup_common.h
new file mode 100644 (file)
index 0000000..42532c5
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+/*
+ * @file        popup_common.h
+ * @author      Kyungwook Tak <k.tak@samsung.com>
+ * @version     1.0
+ */
+#pragma once
+
+#include "ui/serialization.h"
+
+#define EXPORT_API __attribute__((visibility("default")))
+
+namespace TPKP {
+namespace UI {
+
+enum class PopupStatus : int {
+       NO_ERROR,
+       EXIT_ERROR
+};
+
+enum class Response : int {
+       ALLOW,
+       DENY,
+       ERROR
+};
+
+class EXPORT_API BinaryStream : public IStream {
+public:
+       BinaryStream();
+       virtual ~BinaryStream();
+       BinaryStream(BinaryStream &&other);
+       BinaryStream &operator=(BinaryStream &&other);
+
+       virtual void Read(size_t num, void *bytes) override;
+       virtual void Write(size_t num, const void *bytes) override;
+
+       const unsigned char *data() const;
+       size_t size() const;
+
+       template <typename... Args>
+       static BinaryStream Serialize(const Args&... args)
+       {
+               BinaryStream stream;
+               Serializer<Args...>::Serialize(stream, args...);
+               return stream;
+       }
+
+       template <typename... Args>
+       void Deserialize(Args&... args)
+       {
+               Deserializer<Args...>::Deserialize(*this, args...);
+       }
+
+private:
+       std::vector<unsigned char> m_data;
+       size_t m_readPosition;
+};
+
+void sendStream(int fd, const BinaryStream &stream);
+BinaryStream receiveStream(int fd);
+
+} // UI
+} // TPKP
diff --git a/src/common/include/ui/popup_runner.h b/src/common/include/ui/popup_runner.h
new file mode 100644 (file)
index 0000000..39fad73
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+/*
+ * @file        popup_runner.h
+ * @author      Janusz Kozerski <j.kozerski@samsung.com>
+ * @version     1.0
+ */
+#pragma once
+
+#include <string>
+
+#include "ui/popup_common.h"
+
+namespace TPKP {
+namespace UI {
+
+const int TIMEOUT_MS_MIN = 10000;
+const int TIMEOUT_MS_DEFAULT = 60000;
+
+/*
+ * Zero or negative timeout means infinity.
+ * unit    : millisecond
+ * minimum : 10,000 (ms)
+ * default : 60,000 (ms)
+ */
+Response runPopup(const std::string &hostname, int timeout = TIMEOUT_MS_DEFAULT) noexcept;
+
+} // UI
+} // TPKP
diff --git a/src/common/include/ui/serialization.h b/src/common/include/ui/serialization.h
new file mode 100644 (file)
index 0000000..8871061
--- /dev/null
@@ -0,0 +1,478 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+/**
+ * @file    serialization.h
+ * @author  Tomasz Swierczek (t.swierczek@samsung.com)
+ * @version 1.0
+ * @brief   Interfaces and templates used for data serialization.
+ */
+#pragma once
+
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+#include <list>
+#include <map>
+#include <memory>
+
+namespace TPKP {
+namespace UI {
+// Abstract data stream buffer
+class IStream {
+public:
+       virtual void Read(size_t num, void * bytes) = 0;
+       virtual void Write(size_t num, const void * bytes) = 0;
+       virtual ~IStream(){}
+};
+
+// Serializable interface
+class ISerializable {
+public:
+       virtual void Serialize(IStream &) const = 0;
+       virtual ~ISerializable(){}
+};
+
+struct Serialization {
+       static void Serialize(IStream& stream, const ISerializable& object)
+       {
+               object.Serialize(stream);
+       }
+
+       static void Serialize(IStream& stream, const ISerializable* const object)
+       {
+               object->Serialize(stream);
+       }
+
+       static void Serialize(IStream& stream, const char value)
+       {
+               stream.Write(sizeof(value), &value);
+       }
+       static void Serialize(IStream& stream, const char* const value)
+       {
+               stream.Write(sizeof(*value), value);
+       }
+
+       static void Serialize(IStream& stream, const unsigned char value)
+       {
+               stream.Write(sizeof(value), &value);
+       }
+       static void Serialize(IStream& stream, const unsigned char* const value)
+       {
+               stream.Write(sizeof(*value), value);
+       }
+
+       static void Serialize(IStream& stream, const uint32_t value)
+       {
+               stream.Write(sizeof(value), &value);
+       }
+
+       static void Serialize(IStream& stream, const uint32_t* const value)
+       {
+               stream.Write(sizeof(*value), value);
+       }
+
+       static void Serialize(IStream& stream, const int32_t value)
+       {
+               stream.Write(sizeof(value), &value);
+       }
+       static void Serialize(IStream& stream, const int32_t* const value)
+       {
+               stream.Write(sizeof(*value), value);
+       }
+
+       static void Serialize(IStream& stream, const uint64_t value)
+       {
+               stream.Write(sizeof(value), &value);
+       }
+
+       static void Serialize(IStream& stream, const uint64_t* const value)
+       {
+               stream.Write(sizeof(*value), value);
+       }
+
+       static void Serialize(IStream& stream, const int64_t value)
+       {
+               stream.Write(sizeof(value), &value);
+       }
+
+       static void Serialize(IStream& stream, const int64_t* const value)
+       {
+               stream.Write(sizeof(*value), value);
+       }
+
+       static void Serialize(IStream& stream, const bool value)
+       {
+               stream.Write(sizeof(value), &value);
+       }
+
+       static void Serialize(IStream& stream, const bool* const value)
+       {
+               stream.Write(sizeof(*value), value);
+       }
+
+       template <typename T, typename R, typename A>
+       static void Serialize(IStream& stream, const std::basic_string<T,R,A>& str)
+       {
+               int length = str.size();
+               stream.Write(sizeof(length), &length);
+               stream.Write(length*sizeof(T), str.data());
+       }
+
+       template<typename T, typename R, typename A>
+       static void Serialize(IStream& stream, const std::basic_string<T,R,A>* const str)
+       {
+               int length = str->size();
+               stream.Write(sizeof(length), &length);
+               stream.Write(length*sizeof(T), str->data());
+       }
+
+       // STL templates
+
+       template <typename T>
+       static void Serialize(IStream& stream, const std::list<T>& list)
+       {
+               int length = list.size();
+               stream.Write(sizeof(length), &length);
+               for (typename std::list<T>::const_iterator list_iter = list.begin();
+                        list_iter != list.end(); list_iter++)
+               {
+                       Serialize(stream, *list_iter);
+               }
+       }
+       template <typename T>
+       static void Serialize(IStream& stream, const std::list<T>* const list)
+       {
+               Serialize(stream, *list);
+       }
+
+       template <typename A>
+       static void Serialize(IStream& stream, const std::vector<unsigned char, A>& vec)
+       {
+               int length = vec.size();
+               stream.Write(sizeof(length), &length);
+               stream.Write(length, vec.data());
+       }
+
+       template <typename A>
+       static void Serialize(IStream& stream, const std::vector<unsigned char, A>* const vec)
+       {
+               Serialize(stream, *vec);
+       }
+
+       template <typename T, typename A>
+       static void Serialize(IStream& stream, const std::vector<T, A>& vec)
+       {
+               int length = vec.size();
+               stream.Write(sizeof(length), &length);
+               for (const auto &i : vec)
+               {
+                       Serialize(stream, i);
+               }
+       }
+
+       template <typename T, typename A>
+       static void Serialize(IStream& stream, const std::vector<T, A>* const vec)
+       {
+               Serialize(stream, *vec);
+       }
+
+       template <typename A, typename B>
+       static void Serialize(IStream& stream, const std::pair<A, B>& p)
+       {
+               Serialize(stream, p.first);
+               Serialize(stream, p.second);
+       }
+
+       template <typename A, typename B>
+       static void Serialize(IStream& stream, const std::pair<A, B>* const p)
+       {
+               Serialize(stream, *p);
+       }
+
+       template <typename K, typename T>
+       static void Serialize(IStream& stream, const std::map<K, T>& map)
+       {
+               int length = map.size();
+               stream.Write(sizeof(length), &length);
+               typename std::map<K, T>::const_iterator it;
+               for (it = map.begin(); it != map.end(); ++it) {
+                       Serialize(stream, (*it).first);
+                       Serialize(stream, (*it).second);
+               }
+       }
+       template <typename K, typename T>
+       static void Serialize(IStream& stream, const std::map<K, T>* const map)
+       {
+               Serialize(stream, *map);
+       }
+
+       template <typename T>
+       static void Serialize(IStream& stream, const std::unique_ptr<T>& p)
+       {
+               Serialize(stream, *p);
+       }
+
+};
+
+struct Deserialization {
+       template <typename T>
+       static void Deserialize(IStream& stream, T& object)
+       {
+               object = T(stream);
+       }
+
+       template <typename T>
+       static void Deserialize(IStream& stream, T*& object)
+       {
+               object = new T(stream);
+       }
+
+       static void Deserialize(IStream& stream, char& value)
+       {
+               stream.Read(sizeof(value), &value);
+       }
+
+       static void Deserialize(IStream& stream, char*& value)
+       {
+               value = new char;
+               stream.Read(sizeof(*value), value);
+       }
+
+       static void Deserialize(IStream& stream, unsigned char& value)
+       {
+               stream.Read(sizeof(value), &value);
+       }
+
+       static void Deserialize(IStream& stream, unsigned char*& value)
+       {
+               value = new unsigned char;
+               stream.Read(sizeof(*value), value);
+       }
+
+       static void Deserialize(IStream& stream, uint32_t& value)
+       {
+               stream.Read(sizeof(value), &value);
+       }
+
+       static void Deserialize(IStream& stream, uint32_t*& value)
+       {
+               value = new uint32_t;
+               stream.Read(sizeof(*value), value);
+       }
+
+       static void Deserialize(IStream& stream, int32_t& value)
+       {
+               stream.Read(sizeof(value), &value);
+       }
+
+       static void Deserialize(IStream& stream, int32_t*& value)
+       {
+               value = new int32_t;
+               stream.Read(sizeof(*value), value);
+       }
+
+       static void Deserialize(IStream& stream, uint64_t& value)
+       {
+               stream.Read(sizeof(value), &value);
+       }
+
+       static void Deserialize(IStream& stream, uint64_t*& value)
+       {
+               value = new uint64_t;
+               stream.Read(sizeof(*value), value);
+       }
+
+       static void Deserialize(IStream& stream, int64_t& value)
+       {
+               stream.Read(sizeof(value), &value);
+       }
+
+       static void Deserialize(IStream& stream, int64_t*& value)
+       {
+               value = new int64_t;
+               stream.Read(sizeof(*value), value);
+       }
+
+       static void Deserialize(IStream& stream, bool& value)
+       {
+               stream.Read(sizeof(value), &value);
+       }
+
+       static void Deserialize(IStream& stream, bool*& value)
+       {
+               value = new bool;
+               stream.Read(sizeof(*value), value);
+       }
+
+       template <typename T, typename R, typename A>
+       static void Deserialize(IStream& stream, std::basic_string<T,R,A>& str)
+       {
+               int length;
+               stream.Read(sizeof(length), &length);
+               std::vector<T> buf(length);
+               stream.Read(length*sizeof(T), buf.data());
+               str = std::basic_string<T,R,A>(buf.data(), buf.data()+length);
+       }
+
+       template <typename T, typename R, typename A>
+       static void Deserialize(IStream& stream, std::basic_string<T,R,A>*& str)
+       {
+               int length;
+               stream.Read(sizeof(length), &length);
+               std::vector<T> buf(length);
+               stream.Read(length*sizeof(T), buf.data());
+               str = new std::basic_string<T,R,A>(buf.data(), buf.data()+length);
+       }
+
+       // STL templates
+
+       template <typename T>
+       static void Deserialize(IStream& stream, std::list<T>& list)
+       {
+               int length;
+               stream.Read(sizeof(length), &length);
+               for (int i = 0; i < length; ++i) {
+                       T obj;
+                       Deserialize(stream, obj);
+                       list.push_back(std::move(obj));
+               }
+       }
+
+       template <typename T>
+       static void Deserialize(IStream& stream, std::list<T>*& list)
+       {
+               list = new std::list<T>;
+               Deserialize(stream, *list);
+       }
+
+       template <typename A>
+       static void Deserialize(IStream& stream, std::vector<unsigned char, A>& vec)
+       {
+               int length;
+               stream.Read(sizeof(length), &length);
+               vec.resize(length);
+               stream.Read(length, vec.data());
+       }
+
+       template <typename A>
+       static void Deserialize(IStream& stream, std::vector<unsigned char, A>*& vec)
+       {
+               vec = new std::vector<unsigned char,A>;
+               Deserialize(stream, *vec);
+       }
+
+       template <typename T, typename A>
+       static void Deserialize(IStream& stream, std::vector<T,A>& vec)
+       {
+               int length;
+               stream.Read(sizeof(length), &length);
+               for (int i = 0; i < length; ++i) {
+                       T obj;
+                       Deserialize(stream, obj);
+                       vec.push_back(std::move(obj));
+               }
+       }
+
+       template <typename T, typename A>
+       static void Deserialize(IStream& stream, std::vector<T,A>*& vec)
+       {
+               vec = new std::vector<T,A>;
+               Deserialize(stream, *vec);
+       }
+
+       template <typename A, typename B>
+       static void Deserialize(IStream& stream, std::pair<A, B>& p)
+       {
+               Deserialize(stream, p.first);
+               Deserialize(stream, p.second);
+       }
+
+       template <typename A, typename B>
+       static void Deserialize(IStream& stream, std::pair<A, B>*& p)
+       {
+               p = new std::pair<A, B>;
+               Deserialize(stream, *p);
+       }
+
+       template <typename K, typename T>
+       static void Deserialize(IStream& stream, std::map<K, T>& map)
+       {
+               int length;
+               stream.Read(sizeof(length), &length);
+               for (int i = 0; i < length; ++i) {
+                       K key;
+                       T obj;
+                       Deserialize(stream, key);
+                       Deserialize(stream, obj);
+                       map[key] = std::move(obj);
+               }
+       }
+
+       template <typename K, typename T>
+       static void Deserialize(IStream& stream, std::map<K, T>*& map)
+       {
+               map = new std::map<K, T>;
+               Deserialize(stream, *map);
+       }
+};
+
+// generic serialization
+template <typename... Args>
+struct Serializer;
+
+template <typename First, typename... Args>
+struct Serializer<First, Args...> : public Serializer<Args...> {
+       static void Serialize(IStream& stream, const First& f, const Args&... args)
+       {
+               Serialization::Serialize(stream, f);
+               Serializer<Args...>::Serialize(stream, args...);
+       }
+};
+
+// end of recursion
+template <>
+struct Serializer<> {
+       static void Serialize(IStream&)
+       {
+               return;
+       }
+};
+
+// generic deserialization
+template <typename... Args>
+struct Deserializer;
+
+template <typename First, typename... Args>
+struct Deserializer<First, Args...> : public Deserializer<Args...> {
+       static void Deserialize(IStream& stream, First& f, Args&... args)
+       {
+               Deserialization::Deserialize(stream, f);
+               Deserializer<Args...>::Deserialize(stream, args...);
+       }
+};
+
+// end of recursion
+template <>
+struct Deserializer<> {
+       static void Deserialize(IStream&)
+       {
+               return;
+       }
+};
+
+} // UI
+} // TPKP
index a807ac1..b6bce55 100644 (file)
@@ -26,6 +26,7 @@
 #include <sys/syscall.h>
 #include <unistd.h>
 
+#include "tpkp_parser.h"
 #include "tpkp_logger.h"
 
 namespace {
@@ -87,4 +88,27 @@ void ClientCache::eraseUrlAll(void)
        SLOGD("erase all urls saved of client");
 }
 
+void ClientCache::setDecision(const std::string &url, ClientCache::Decision decision)
+{
+       auto hostname = Parser::extractHostname(url);
+
+       {
+               std::lock_guard<std::mutex> lock(m_decision_mutex);
+               m_decisions[hostname] = ClientCache::DecisionStruct(decision);
+       }
+}
+
+ClientCache::Decision ClientCache::getDecision(const std::string &url)
+{
+       ClientCache::Decision decision;
+       auto hostname = Parser::extractHostname(url);
+
+       {
+               std::lock_guard<std::mutex> lock(m_decision_mutex);
+               decision = m_decisions[hostname].decision;
+       }
+
+       return decision;
+}
+
 }
index 0abc3b9..3eb7d2d 100644 (file)
@@ -31,6 +31,7 @@
 #include "net/http/transport_security_state_static.h"
 
 #include "tpkp_parser.h"
+#include "ui/popup_runner.h"
 
 namespace {
 
@@ -96,6 +97,7 @@ private:
 
        bool LoadPreloadedPins(void);
        bool HashesIntersect(const char *const *hashesArr);
+       bool askUser(void);
 
        class HashValuesEqual {
        public:
@@ -137,12 +139,12 @@ bool Context::Impl::checkPubkeyPins(void)
 
        if (HashesIntersect(pinset.rejected_pins)) {
                SLOGE("pubkey is in rejected pin!");
-               return false;
+               return askUser();
        }
 
        if (!HashesIntersect(pinset.accepted_pins)) {
                SLOGE("pubkey cannot be found in accepted pins!");
-               return false;
+               return askUser();
        }
 
        SLOGD("pubkey is pinned one!");
@@ -207,6 +209,23 @@ bool Context::Impl::HashValuesEqual::operator()(const HashValue &other) const
        return true;
 }
 
+bool Context::Impl::askUser(void)
+{
+       TPKP::UI::Response response = TPKP::UI::runPopup(m_host);
+
+       switch (response) {
+       case TPKP::UI::Response::ALLOW:
+               SLOGI("ALLOW returned from tpkp-popup");
+               return true;
+       case TPKP::UI::Response::DENY:
+               SLOGI("DENY returned from tpkp-popup");
+               return false;
+       default:
+               SLOGE("Unknown response returned[%d] from tpkp-popup", static_cast<int>(response));
+               return false;
+       }
+}
+
 Context::Context(const std::string &url) : pImpl(new Impl{url}) {}
 Context::~Context() {}
 
diff --git a/src/common/ui/CMakeLists.txt b/src/common/ui/CMakeLists.txt
new file mode 100644 (file)
index 0000000..8541679
--- /dev/null
@@ -0,0 +1,2 @@
+ADD_SUBDIRECTORY(popup-bin)
+ADD_SUBDIRECTORY(po)
diff --git a/src/common/ui/connection.cpp b/src/common/ui/connection.cpp
new file mode 100644 (file)
index 0000000..9f52c26
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+/*
+ * @file        connection.cpp
+ * @author      Kyungwook Tak (k.tak@samsung.com)
+ * @version     1.0
+ */
+#include "ui/connection.h"
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include "tpkp_common.h"
+#include "tpkp_logger.h"
+#include "tpkp_error.h"
+
+namespace TPKP {
+namespace UI {
+
+SockRaii::SockRaii() : m_sock(-1) {}
+
+SockRaii::~SockRaii()
+{
+       disconnect();
+}
+
+void SockRaii::connect(const std::string &interface)
+{
+       TPKP_CHECK_THROW_EXCEPTION(!interface.empty(),
+               TPKP_E_INTERNAL, "No valid interface address given.");
+
+       int sock = socket(AF_UNIX, SOCK_STREAM, 0);
+
+       SLOGD("make client sock: %d", sock);
+
+       TPKP_CHECK_THROW_EXCEPTION(sock >= 0,
+               TPKP_E_INTERNAL, "Error to create sock");
+
+       connectWrapper(sock, interface);
+
+       disconnect(); /* refresh in case of old socket remained */
+       m_sock = sock;
+}
+
+void SockRaii::connectWrapper(int sock, const std::string &interface)
+{
+       sockaddr_un clientaddr;
+
+       /*
+        * TODO(k.tak): add more error codes (at least internal) to represent
+        *              various error cases
+        */
+       TPKP_CHECK_THROW_EXCEPTION(
+               interface.length() < sizeof(clientaddr.sun_path),
+               TPKP_E_INTERNAL, "Error: interface name[" << interface << "] is too long");
+
+       memset(&clientaddr, 0, sizeof(clientaddr));
+       clientaddr.sun_family = AF_UNIX;
+       strcpy(clientaddr.sun_path, interface.c_str());
+
+       int ret = TEMP_FAILURE_RETRY(::connect(sock, (struct sockaddr *)&clientaddr, SUN_LEN(&clientaddr)));
+
+       const int err = errno;
+       if (ret == -1) {
+               if (err == EACCES)
+                       TPKP_THROW_EXCEPTION(TPKP_E_INTERNAL,
+                               "Access denied to interface: " << interface);
+
+               TPKP_THROW_EXCEPTION(TPKP_E_INTERNAL,
+                       "Error on connect socket. errno: " << err);
+       }
+}
+
+bool SockRaii::isConnected(void) const
+{
+       return m_sock > -1;
+}
+
+void SockRaii::disconnect(void)
+{
+       if (isConnected()) {
+               close(m_sock);
+               SLOGD("close sock[%d] on client", m_sock);
+       }
+
+       m_sock = -1;
+}
+
+void SockRaii::waitForStreamIn(int timeout)
+{
+       int ret;
+
+       pollfd fds[1];
+
+       fds[0].fd = m_sock;
+       fds[0].events = POLLIN;
+
+       while (((ret = poll(fds, 1, timeout)) == -1) && errno == EINTR) {
+               timeout >>= 1;
+               errno = 0;
+       }
+
+       if (ret == 0)
+               TPKP_THROW_EXCEPTION(TPKP_E_INTERNAL, "Poll timeout[" << timeout << "]!!");
+       else if (ret == -1)
+               TPKP_THROW_EXCEPTION(TPKP_E_INTERNAL, "Error in poll! errno: " << errno);
+}
+
+int SockRaii::get(void) const
+{
+       return m_sock;
+}
+
+ServiceConnection::ServiceConnection(const std::string &interface, int timeout)
+       : m_serviceInterface(interface), m_timeout(timeout) {}
+
+ServiceConnection::~ServiceConnection() {}
+
+void ServiceConnection::prepareConnection(void)
+{
+       if (!m_socket.isConnected())
+               m_socket.connect(m_serviceInterface);
+}
+
+void ServiceConnection::send(const BinaryStream &stream)
+{
+       prepareConnection();
+       sendStream(m_socket.get(), stream);
+}
+
+BinaryStream ServiceConnection::receive(void)
+{
+       TPKP_CHECK_THROW_EXCEPTION(m_socket.isConnected(),
+               TPKP_E_INTERNAL, "Not connected!");
+
+       m_socket.waitForStreamIn(m_timeout);
+
+       return receiveStream(m_socket.get());
+}
+
+BinaryStream ServiceConnection::processRequest(const BinaryStream &input)
+{
+       send(input);
+
+       return receive();
+}
+
+}
+}
diff --git a/src/common/ui/po/CMakeLists.txt b/src/common/ui/po/CMakeLists.txt
new file mode 100644 (file)
index 0000000..eedb2ec
--- /dev/null
@@ -0,0 +1,51 @@
+# Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+#
+#    Licensed under the Apache License, Version 2.0 (the "License");
+#    you may not use this file except in compliance with the License.
+#    You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#
+# @file        CMakeLists.txt
+# @author      Adam Malinowski <a.malinowsk2@partner.samsung.com>
+#
+
+SET(POFILES
+       en.po
+       en_GB.po
+       en_US.po
+       )
+
+SET(PREFIX ${CMAKE_INSTALL_PREFIX})
+SET(SHAREDIR "${PREFIX}/share")
+SET(LOCALEDIR "${SHAREDIR}/locale")
+SET(MSGFMT "${PREFIX}/bin/msgfmt")
+
+FOREACH(POFILE ${POFILES})
+       SET(POFILE ${CMAKE_CURRENT_SOURCE_DIR}/${POFILE})
+       MESSAGE("PO: ${POFILE}")
+
+       GET_FILENAME_COMPONENT(ABS_POFILE ${POFILE} ABSOLUTE)
+       GET_FILENAME_COMPONENT(LANG ${ABS_POFILE} NAME_WE)
+
+       SET(MOFILE ${CMAKE_CURRENT_BINARY_DIR}/${LANG}.mo)
+
+       ADD_CUSTOM_COMMAND(
+               OUTPUT ${MOFILE}
+               COMMAND ${MSGFMT} -o ${MOFILE} ${ABS_POFILE}
+               DEPENDS ${ABS_POFILE}
+       )
+
+       INSTALL(FILES ${MOFILE}
+               DESTINATION ${LOCALEDIR}/${LANG}/LC_MESSAGES RENAME ${PROJECT_NAME}.mo)
+
+       SET(MOFILES ${MOFILES} ${MOFILE})
+ENDFOREACH(POFILE)
+
+ADD_CUSTOM_TARGET(po ALL DEPENDS ${MOFILES})
diff --git a/src/common/ui/po/en.po b/src/common/ui/po/en.po
new file mode 100644 (file)
index 0000000..c6b4049
--- /dev/null
@@ -0,0 +1,11 @@
+msgid "SID_TITLE_PUBLIC_KEY_MISMATCHED"
+msgstr "[Warning] Untrusted server host!"
+
+msgid "SID_CONTENT_PUBLIC_KEY_MISMATCHED"
+msgstr "Pinned public key to the host[%s] isn't matched!"
+
+msgid "SID_BTN_ALLOW"
+msgstr "allow"
+
+msgid "SID_BTN_DENY"
+msgstr "deny"
diff --git a/src/common/ui/po/en_GB.po b/src/common/ui/po/en_GB.po
new file mode 100644 (file)
index 0000000..c6b4049
--- /dev/null
@@ -0,0 +1,11 @@
+msgid "SID_TITLE_PUBLIC_KEY_MISMATCHED"
+msgstr "[Warning] Untrusted server host!"
+
+msgid "SID_CONTENT_PUBLIC_KEY_MISMATCHED"
+msgstr "Pinned public key to the host[%s] isn't matched!"
+
+msgid "SID_BTN_ALLOW"
+msgstr "allow"
+
+msgid "SID_BTN_DENY"
+msgstr "deny"
diff --git a/src/common/ui/po/en_US.po b/src/common/ui/po/en_US.po
new file mode 100644 (file)
index 0000000..c6b4049
--- /dev/null
@@ -0,0 +1,11 @@
+msgid "SID_TITLE_PUBLIC_KEY_MISMATCHED"
+msgstr "[Warning] Untrusted server host!"
+
+msgid "SID_CONTENT_PUBLIC_KEY_MISMATCHED"
+msgstr "Pinned public key to the host[%s] isn't matched!"
+
+msgid "SID_BTN_ALLOW"
+msgstr "allow"
+
+msgid "SID_BTN_DENY"
+msgstr "deny"
diff --git a/src/common/ui/popup-bin/CMakeLists.txt b/src/common/ui/popup-bin/CMakeLists.txt
new file mode 100644 (file)
index 0000000..ac25660
--- /dev/null
@@ -0,0 +1,50 @@
+# Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+#
+#    Licensed under the Apache License, Version 2.0 (the "License");
+#    you may not use this file except in compliance with the License.
+#    You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#
+#
+# @file     CMakeLists.txt
+# @author   Janusz Kozerski (j.kozerski@samsung.com)
+# @version  1.0
+#
+PKG_CHECK_MODULES(TPKP_POPUP_DEP
+       REQUIRED
+       elementary
+       libsystemd-daemon
+       vconf
+       )
+
+INCLUDE_DIRECTORIES(
+       ${TPKP_POPUP_DEP_INCLUDE_DIRS}
+       .
+       ${PROJECT_SOURCE_DIR}/src/common/include
+       )
+
+SET(POPUP_SRCS
+       popup.cpp
+       )
+
+SET_SOURCE_FILES_PROPERTIES(${POPUP_SRCS}
+       PROPERTIES
+               COMPILE_FLAGS "-D_GNU_SOURCE -fPIE"
+               LINK_FLAGS "-pie"
+       )
+
+ADD_EXECUTABLE(${TARGET_TPKP_POPUP} ${POPUP_SRCS})
+
+TARGET_LINK_LIBRARIES(${TARGET_TPKP_POPUP}
+       ${TPKP_POPUP_DEP_LIBRARIES}
+       ${TARGET_TPKP_COMMON_LIB}
+       )
+
+INSTALL(TARGETS ${TARGET_TPKP_POPUP} DESTINATION bin)
diff --git a/src/common/ui/popup-bin/popup.cpp b/src/common/ui/popup-bin/popup.cpp
new file mode 100644 (file)
index 0000000..ab9d335
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+/*
+ * @file        popup.cpp
+ * @author      Janusz Kozerski (j.kozerski@samsung.com)
+ * @version     1.0
+ */
+#include <unistd.h>
+#include <vector>
+#include <memory>
+#include <string>
+#include <libintl.h>
+#include <poll.h>
+#include <sys/un.h>
+#include <time.h>
+
+#include <Elementary.h>
+#include <Ecore.h>
+#include <systemd/sd-daemon.h>
+#include <vconf.h>
+
+/*
+ * TODO(k.tak): Separate TPKP::Exception related codes from tpkp_common
+ *              not to include "tpkp_common.h" which have lot of dependencies
+ */
+#include "tpkp_common.h"
+#include "tpkp_logger.h"
+#include "ui/popup_common.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "TPKP_POPUP"
+
+#define TPKP_UI_SOCK_ADDR "/tmp/.tpkp-ui-backend.sock"
+
+using namespace TPKP::UI;
+
+namespace {
+
+struct TpkpPopup {
+       /* inputs */
+       std::string hostname;
+       int timeout;
+
+       /* internal data fields */
+       Evas_Object *win;
+       Evas_Object *popup;
+       Evas_Object *box;
+       Evas_Object *title;
+       Evas_Object *content;
+       Evas_Object *buttonAllow;
+       Evas_Object *buttonDeny;
+
+       /* output */
+       TPKP::UI::Response result;
+
+       TpkpPopup() :
+               hostname(),
+               timeout(-1),
+               win(nullptr),
+               popup(nullptr),
+               box(nullptr),
+               title(nullptr),
+               content(nullptr),
+               buttonAllow(nullptr),
+               buttonDeny(nullptr),
+               result(TPKP::UI::Response::ERROR) {}
+};
+
+struct SockRaii {
+       int sock;
+       SockRaii() : sock(-1) {}
+       SockRaii(int _sock) : sock(_sock) {}
+       ~SockRaii()
+       {
+               if (sock != -1)
+                       close(sock);
+       }
+};
+
+struct ElmRaii {
+       ElmRaii(int argc, char **argv)
+       {
+               SLOGD("elm_init()");
+               elm_init(argc, argv);
+
+               elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
+       }
+
+       virtual ~ElmRaii()
+       {
+               SLOGD("elm_shutdown()");
+               elm_shutdown();
+       }
+};
+
+void answerAllowCb(void *data, Evas_Object * /* obj */, void * /* event_info */)
+{
+       SLOGD("allow answer");
+
+       TPKP_CHECK_THROW_EXCEPTION(data != nullptr,
+               TPKP_E_INTERNAL, "data shouldn't be null on evas callbacks");
+
+       TpkpPopup *pdp = static_cast<TpkpPopup *>(data);
+       pdp->result = Response::ALLOW;
+
+       evas_object_del(pdp->win);
+}
+
+void answerDenyCb(void *data, Evas_Object * /* obj */, void * /* event_info */)
+{
+       SLOGD("deny answer");
+
+       TPKP_CHECK_THROW_EXCEPTION(data != nullptr,
+               TPKP_E_INTERNAL, "data shouldn't be null on evas callbacks");
+
+       TpkpPopup *pdp = static_cast<TpkpPopup *>(data);
+       pdp->result = Response::DENY;
+
+       evas_object_del(pdp->win);
+}
+
+Eina_Bool timeoutCb(void *data)
+{
+       TPKP_CHECK_THROW_EXCEPTION(data != nullptr,
+               TPKP_E_INTERNAL, "data shouldn't be null on timeout callback");
+       TpkpPopup *pdp = static_cast<TpkpPopup *>(data);
+       pdp->result = Response::DENY;
+
+       SLOGI("popup timeout[%d](ms) reached! Let's deny", pdp->timeout);
+
+       evas_object_del(pdp->win);
+
+       return ECORE_CALLBACK_CANCEL;
+}
+
+/*
+ *  popup layout
+ *
+ *               window
+ *  --------------------------------
+ *  |                              |
+ *  |            popup             |
+ *  | ---------------------------- |
+ *  | |    content (description) | |
+ *  | |                          | |
+ *  | |                          | |
+ *  | | -----------  ----------- | |
+ *  | | | button1 |  | button2 | | |
+ *  | | -----------  ----------- | |
+ *  | |                          | |
+ *  | ---------------------------- |
+ *  --------------------------------
+ */
+/* TODO(k.tak): UI layout refinement */
+void showPopup(TpkpPopup *pdp)
+{
+       SLOGD("Start to make popup");
+
+       TPKP_CHECK_THROW_EXCEPTION(pdp != nullptr,
+               TPKP_E_INTERNAL, "pdp shouldn't be null");
+
+       pdp->win = elm_win_add(nullptr, "tpkp popup", ELM_WIN_NOTIFICATION);
+
+       elm_win_autodel_set(pdp->win, EINA_TRUE);
+       elm_win_indicator_opacity_set(pdp->win, ELM_WIN_INDICATOR_TRANSLUCENT);
+       elm_win_alpha_set(pdp->win, true);
+       evas_object_show(pdp->win);
+
+       pdp->popup = elm_popup_add(pdp->win);
+       evas_object_show(pdp->popup);
+
+       pdp->box = elm_box_add(pdp->popup);
+       evas_object_size_hint_weight_set(pdp->box, EVAS_HINT_EXPAND, 0);
+       evas_object_size_hint_align_set(pdp->box, EVAS_HINT_FILL, 0.0);
+       evas_object_show(pdp->box);
+
+       pdp->title = elm_label_add(pdp->popup);
+       elm_object_style_set(pdp->title, "elm.text.title");
+       elm_object_text_set(pdp->title, dgettext(PROJECT_NAME, "SID_TITLE_PUBLIC_KEY_MISMATCHED"));
+       evas_object_show(pdp->title);
+       elm_box_pack_end(pdp->box, pdp->title);
+
+       pdp->content = elm_label_add(pdp->popup);
+       elm_object_style_set(pdp->content, "elm.swallow.content");
+       elm_label_line_wrap_set(pdp->content, ELM_WRAP_MIXED);
+       char *contentFormat = dgettext(PROJECT_NAME, "SID_CONTENT_PUBLIC_KEY_MISMATCHED");
+       char *content = nullptr;
+       if (asprintf(&content, contentFormat, pdp->hostname.c_str()) == -1) {
+               SLOGE("Failed to alloc memory for popup text. Just go for it.");
+               elm_object_text_set(pdp->content, contentFormat);
+       } else {
+               elm_object_text_set(pdp->content, content);
+               free(content);
+       }
+
+       evas_object_size_hint_weight_set(pdp->content, EVAS_HINT_EXPAND, 0.0);
+       evas_object_size_hint_align_set(pdp->content, EVAS_HINT_FILL, EVAS_HINT_FILL);
+       evas_object_show(pdp->content);
+       elm_box_pack_end(pdp->box, pdp->content);
+
+       elm_object_part_content_set(pdp->popup, "default", pdp->box);
+
+       pdp->buttonAllow = elm_button_add(pdp->popup);
+       elm_object_style_set(pdp->buttonAllow, "elm.swallow.content.button1");
+       elm_object_text_set(pdp->buttonAllow, dgettext(PROJECT_NAME, "SID_BTN_ALLOW"));
+       elm_object_part_content_set(pdp->popup, "button1", pdp->buttonAllow);
+       evas_object_smart_callback_add(pdp->buttonAllow, "clicked", answerAllowCb, pdp);
+       evas_object_show(pdp->buttonAllow);
+
+       pdp->buttonDeny = elm_button_add(pdp->popup);
+       elm_object_style_set(pdp->buttonDeny, "elm.swallow.content.button2");
+       elm_object_text_set(pdp->buttonDeny, dgettext(PROJECT_NAME, "SID_BTN_DENY"));
+       elm_object_part_content_set(pdp->popup, "button2  ", pdp->buttonDeny);
+       evas_object_smart_callback_add(pdp->buttonDeny, "clicked", answerDenyCb, pdp);
+       evas_object_show(pdp->buttonDeny);
+
+       if (pdp->timeout > 0) {
+               ecore_timer_add(pdp->timeout / 1000, timeoutCb, pdp);
+       }
+
+       SLOGD("elm_run start");
+       elm_run();
+}
+
+/*
+ *  child receive list
+ *  - std::string hostname
+ */
+void deserialize(TpkpPopup *pdp, BinaryStream &stream)
+{
+       Deserialization::Deserialize(stream, pdp->hostname);
+       Deserialization::Deserialize(stream, pdp->timeout);
+
+       SLOGD("Params from popup_runner: hostname[%s] timeout[%d]",
+               pdp->hostname.c_str(), pdp->timeout);
+}
+
+/*
+ *  child send list
+ *  - TPKP::UI::Response response (int)
+ */
+BinaryStream serialize(TpkpPopup *pdp)
+{
+       BinaryStream stream;
+       Serialization::Serialize(stream, static_cast<int>(pdp->result));
+
+       return stream;
+}
+
+int getSockFromSystemd(void)
+{
+       int n = sd_listen_fds(0);
+
+       for (int fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; ++fd) {
+               if (sd_is_socket_unix(fd, SOCK_STREAM, 1, TPKP_UI_SOCK_ADDR, 0) > 0) {
+                       SLOGD("Get socket from systemd. fd[%d]", fd);
+                       return fd;
+               }
+       }
+       TPKP_THROW_EXCEPTION(TPKP_E_INTERNAL, "Failed to get sock from systemd.");
+}
+
+} // namespace anonymous
+
+int main(int argc, char **argv)
+{
+       SLOGI("tpkp popup backend server start!");
+
+       /* init/shutdown elm automatically */
+       ElmRaii elmRaii(argc, argv);
+
+       setlocale(LC_ALL, vconf_get_str(VCONFKEY_LANGSET));
+
+       try {
+               struct sockaddr_un clientaddr;
+               int client_len = sizeof(clientaddr);
+
+               struct pollfd fds[1];
+               fds[0].fd = getSockFromSystemd();
+               fds[0].events = POLLIN;
+
+               SLOGD("server fd from systemd: %d", fds[0].fd);
+
+               while (true) {
+                       /* non blocking poll */
+                       int ret = poll(fds, 1, 0);
+                       TPKP_CHECK_THROW_EXCEPTION(ret >= 0,
+                               TPKP_E_INTERNAL, "poll() error. errno: " << errno);
+
+                       if (ret == 0) {
+                               SLOGD("tpkp-popup backend service timeout. Let's be deactivated");
+                               return 0;
+                       }
+
+                       /* ready to accept! */
+
+                       memset(&clientaddr, 0, client_len);
+
+                       int clientFd = accept(fds[0].fd, (struct sockaddr *)&clientaddr, (socklen_t *)&client_len);
+                       TPKP_CHECK_THROW_EXCEPTION(clientFd >= 0, TPKP_E_INTERNAL, "Error in func accept()");
+                       SLOGD("client accepted with fd: %d", clientFd);
+
+                       SockRaii clientSock(clientFd);
+
+                       TpkpPopup pd;
+                       TpkpPopup *pdp = &pd;
+
+                       /* receive arguments */
+                       BinaryStream stream = receiveStream(clientFd);
+                       deserialize(pdp, stream);
+
+                       /* get user response */
+                       showPopup(pdp);
+                       SLOGD("pdp->result : %d", static_cast<int>(pdp->result));
+
+                       /* send result */
+                       stream = serialize(pdp);
+                       sendStream(clientFd, stream);
+
+                       SLOGD("tpkp-popup done successfully!");
+               }
+       } catch (const TPKP::Exception &e) {
+               SLOGE("Exception[%d]: %s", e.code(), e.what());
+       } catch (const std::bad_alloc &e) {
+               SLOGE("bad_alloc std exception: %s", e.what());
+       } catch (const std::exception &e) {
+               SLOGE("std exception: %s", e.what());
+       } catch (...) {
+               SLOGE("Unhandled exception occured!");
+       }
+
+       return 0;
+}
diff --git a/src/common/ui/popup_common.cpp b/src/common/ui/popup_common.cpp
new file mode 100644 (file)
index 0000000..4c3dbd7
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+/*
+ * @file        popup_common.cpp
+ * @author      Kyungwook Tak (k.tak@samsung.com)
+ * @version     1.0
+ */
+#include "ui/popup_common.h"
+
+#include <unistd.h>
+#include <errno.h>
+#include <sys/socket.h>
+
+#include "tpkp_common.h"
+#include "tpkp_logger.h"
+
+namespace TPKP {
+namespace UI {
+
+BinaryStream::BinaryStream() : m_readPosition(0) {}
+
+BinaryStream::~BinaryStream() {}
+
+BinaryStream::BinaryStream(BinaryStream &&other) :
+       m_data(std::move(other.m_data)),
+       m_readPosition(other.m_readPosition)
+{
+       other.m_readPosition = other.m_data.size();
+}
+
+BinaryStream &BinaryStream::operator=(BinaryStream &&other)
+{
+       if (this == &other)
+               return *this;
+
+       m_data = std::move(other.m_data);
+       m_readPosition = other.m_readPosition;
+       other.m_readPosition = 0;
+
+       return *this;
+}
+
+void BinaryStream::Read(size_t num, void *bytes)
+{
+       size_t max_size = m_data.size();
+       for (size_t i = 0; i < num; ++i) {
+               if (i + m_readPosition >= max_size)
+                       return;
+               static_cast<unsigned char *>(bytes)[i] = m_data[i + m_readPosition];
+       }
+       m_readPosition += num;
+}
+
+void BinaryStream::Write(size_t num, const void *bytes)
+{
+       for (size_t i = 0; i < num; ++i)
+               m_data.push_back(static_cast<const unsigned char *>(bytes)[i]);
+}
+
+const unsigned char *BinaryStream::data() const
+{
+       return m_data.data();
+}
+
+size_t BinaryStream::size() const
+{
+       return m_data.size();
+}
+
+EXPORT_API
+void sendStream(int fd, const BinaryStream &stream)
+{
+       auto buf = stream.data();
+       auto size = stream.size();
+
+       ssize_t ret;
+       size_t offset = 0;
+       while (offset != size && (ret = send(fd, buf + offset, size - offset, 0)) != 0) {
+               if (ret == -1) {
+                       const int err = errno;
+                       if (err == EINTR)
+                               continue;
+                       else
+                               TPKP_THROW_EXCEPTION(TPKP_E_INTERNAL,
+                                       "write failed with errno: " << err);
+               }
+               offset += ret;
+       }
+
+       SLOGD("send data successfully");
+}
+
+EXPORT_API
+BinaryStream receiveStream(int fd)
+{
+       constexpr size_t size = 1024;
+       char buf[size];
+       ssize_t ret;
+
+       while ((ret = recv(fd, buf, size, 0)) == -1) {
+               if (ret == -1) {
+                       const int err = errno;
+                       if (err == EINTR)
+                               continue;
+                       else
+                               TPKP_THROW_EXCEPTION(TPKP_E_INTERNAL,
+                                       "read failed with errno: " << err);
+               }
+       }
+
+       SLOGD("receive data successfully");
+
+       BinaryStream stream;
+       stream.Write(static_cast<size_t>(ret), static_cast<void *>(buf));
+
+       return stream;
+}
+
+} // UI
+} // TPKP
diff --git a/src/common/ui/popup_runner.cpp b/src/common/ui/popup_runner.cpp
new file mode 100644 (file)
index 0000000..7816406
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+/*
+ * @file        popup_runner.cpp
+ * @author      Kyungwook Tak (k.tak@samsung.com)
+ * @version     1.0
+ */
+#include "ui/popup_runner.h"
+
+#include "tpkp_common.h"
+#include "tpkp_logger.h"
+#include "ui/popup_common.h"
+#include "ui/connection.h"
+
+namespace TPKP {
+namespace UI {
+
+namespace {
+
+struct TpkpPopupParent {
+       /* input */
+       std::string hostname;
+       int timeout;
+
+       /* output */
+       Response response;
+};
+
+/*
+ *  parent send list
+ *  - std::string hostname
+ */
+BinaryStream serialize(TpkpPopupParent *pdp)
+{
+       BinaryStream stream;
+       Serialization::Serialize(stream, pdp->hostname);
+       Serialization::Serialize(stream, pdp->timeout);
+
+       return stream;
+}
+
+/*
+ *  parent receive list
+ *  - TPKP::UI::Response response (int)
+ */
+void deserialize(TpkpPopupParent *pdp, BinaryStream &stream)
+{
+       int responseInt;
+       Deserialization::Deserialize(stream, responseInt);
+       pdp->response = static_cast<Response>(responseInt);
+}
+
+} // anonymous namespace
+
+Response runPopup(const std::string &hostname, int timeout) noexcept
+{
+       try {
+               SLOGD("hostname: %s", hostname.c_str());
+
+               TpkpPopupParent pd;
+               TpkpPopupParent *pdp = &pd;
+
+               pdp->hostname = hostname;
+               pdp->timeout = timeout;
+
+               BinaryStream inStream = serialize(pdp);
+
+               if (timeout <= 0)
+                       timeout = -1;
+               else if (timeout < TIMEOUT_MS_MIN)
+                       timeout = TIMEOUT_MS_MIN;
+
+               ServiceConnection connection(TPKP_UI_SOCK_ADDR, timeout);
+               BinaryStream outStream = connection.processRequest(inStream);
+
+               deserialize(pdp, outStream);
+
+               return pdp->response;
+
+       } catch (const TPKP::Exception &e) {
+               SLOGE("Exception[%d]: %s", e.code(), e.what());
+               return Response::ERROR;
+       } catch (const std::bad_alloc &e) {
+               SLOGE("bad_alloc std exception: %s", e.what());
+               return Response::ERROR;
+       } catch (const std::exception &e) {
+               SLOGE("std exception: %s", e.what());
+               return Response::ERROR;
+       } catch (...) {
+               SLOGE("Unhandled exception occured!");
+               return Response::ERROR;
+       }
+
+       SLOGE("This should not happen!!!");
+       return Response::ERROR;
+}
+
+} // UI
+} // TPKP
diff --git a/src/common/ui/serialization.cpp b/src/common/ui/serialization.cpp
new file mode 100644 (file)
index 0000000..a3c6444
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+/**
+ * @file        serialization.cpp
+ * @author      Tomasz Swierczek (t.swierczek@samsung.com)
+ * @version     1.0
+ * @brief       This file is the implementation file of data serialization.
+ */
+#include "ui/serialization.h"
+
+#include <stddef.h>
+
+//
+// Note:
+//
+// The file here is left blank to enable precompilation
+// of templates in corresponding header file.
+// Do not remove this file.
+//
index 7660712..54a8462 100644 (file)
@@ -33,6 +33,8 @@
 
 namespace {
 
+using Decision = TPKP::ClientCache::Decision;
+
 TPKP::ClientCache g_cache;
 
 inline CURLcode err_tpkp_to_curle(tpkp_e err) noexcept
@@ -102,6 +104,19 @@ int tpkp_curl_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
                TPKP_CHECK_THROW_EXCEPTION(!url.empty(),
                        TPKP_E_NO_URL_DATA, "No url in client cache!!");
 
+               switch (g_cache.getDecision(url)) {
+               case Decision::ALLOWED:
+                       SLOGD("allow decision exist on url[%s]", url.c_str());
+                       return;
+
+               case Decision::DENIED:
+                       TPKP_THROW_EXCEPTION(TPKP_E_PUBKEY_MISMATCH,
+                               "deny decision exist on url: " << url);
+
+               default:
+                       break; /* go ahead to make decision */
+               }
+
                TPKP::Context ctx(url);
                if (!ctx.hasPins()) {
                        SLOGI("Skip. No static pin data for url: %s", url.c_str());
@@ -119,7 +134,12 @@ int tpkp_curl_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
                                TPKP::HashAlgo::SHA1,
                                getPubkeyHash(sk_X509_value(chain, i), TPKP::HashAlgo::SHA1));
 
-               TPKP_CHECK_THROW_EXCEPTION(ctx.checkPubkeyPins(),
+               bool isMatched = ctx.checkPubkeyPins();
+
+               /* update decision cache */
+               g_cache.setDecision(url, isMatched ? Decision::ALLOWED : Decision::DENIED);
+
+               TPKP_CHECK_THROW_EXCEPTION(isMatched,
                        TPKP_E_PUBKEY_MISMATCH, "The pubkey mismatched with pinned data!");
        });
 
index 54132e9..41fbd73 100644 (file)
@@ -35,6 +35,8 @@
 
 namespace {
 
+using Decision = TPKP::ClientCache::Decision;
+
 TPKP::ClientCache g_cache;
 
 inline int err_tpkp_to_gnutlse(tpkp_e err) noexcept
@@ -205,6 +207,19 @@ int tpkp_gnutls_verify_callback(gnutls_session_t session)
                        TPKP_E_NO_URL_DATA,
                        "No url of found in client cache!!");
 
+               switch (g_cache.getDecision(url)) {
+               case Decision::ALLOWED:
+                       SLOGD("allow decision exist on url[%s]", url.c_str());
+                       return;
+
+               case Decision::DENIED:
+                       TPKP_THROW_EXCEPTION(TPKP_E_PUBKEY_MISMATCH,
+                               "deny decision exist on url: " << url);
+
+               default:
+                       break; /* go ahead to make decision */
+               }
+
                TPKP::Context ctx(url);
                if (!ctx.hasPins()) {
                        SLOGI("Skip. No static pin data for url: %s", url.c_str());
@@ -234,7 +249,12 @@ int tpkp_gnutls_verify_callback(gnutls_session_t session)
                        }
                }
 
-               TPKP_CHECK_THROW_EXCEPTION(ctx.checkPubkeyPins(),
+               bool isMatched = ctx.checkPubkeyPins();
+
+               /* update decision cache */
+               g_cache.setDecision(url, isMatched ? Decision::ALLOWED : Decision::DENIED);
+
+               TPKP_CHECK_THROW_EXCEPTION(isMatched,
                        TPKP_E_PUBKEY_MISMATCH, "THe pubkey mismatched with pinned data!");
        });
 
diff --git a/systemd/CMakeLists.txt b/systemd/CMakeLists.txt
new file mode 100644 (file)
index 0000000..249b1ee
--- /dev/null
@@ -0,0 +1,9 @@
+CONFIGURE_FILE(pubkey-pinning-popup.service.in pubkey-pinning-popup.service @ONLY)
+
+INSTALL(
+       FILES
+               pubkey-pinning-popup.service
+               pubkey-pinning-popup.socket
+       DESTINATION
+               ${SYSTEMD_UNIT_DIR}
+       )
diff --git a/systemd/pubkey-pinning-popup.service.in b/systemd/pubkey-pinning-popup.service.in
new file mode 100644 (file)
index 0000000..ece317c
--- /dev/null
@@ -0,0 +1,11 @@
+[Unit]
+Description=TPKP(Tizen Public Key Pinning) popup service
+
+[Service]
+ExecStart=/usr/bin/tpkp-popup
+Type=simple
+EnvironmentFile=/run/tizen-system-env
+Sockets=pubkey-pinning-popup.socket
+
+[Install]
+WantedBy=default.target
diff --git a/systemd/pubkey-pinning-popup.socket b/systemd/pubkey-pinning-popup.socket
new file mode 100644 (file)
index 0000000..9afc063
--- /dev/null
@@ -0,0 +1,7 @@
+[Socket]
+ListenStream=/tmp/.tpkp-ui-backend.sock
+SocketMode=0777
+Service=pubkey-pinning-popup.service
+
+[Install]
+WantedBy=sockets.target
index a9c32d3..98e8c56 100644 (file)
@@ -50,4 +50,42 @@ TARGET_LINK_LIBRARIES(${TARGET_TPKP_TEST}
        boost_unit_test_framework
        )
 
-INSTALL(TARGETS ${TARGET_TPKP_TEST} DESTINATION bin)
+# run popup test
+PKG_CHECK_MODULES(TEST_TPKP_POPUP_DEP
+       REQUIRED
+       dlog
+       )
+
+INCLUDE_DIRECTORIES(
+       SYSTEM
+       ${TEST_TPKP_POPUP_DEP_INCLUDE_DIRS}
+       ${PROJECT_SOURCE_DIR}/src/common/include
+       ${PROJECT_SOURCE_DIR}/src/common
+       )
+
+SET(TEST_POPUP_SRCS
+       ${PROJECT_SOURCE_DIR}/src/common/url/url_constants.cc
+       ${PROJECT_SOURCE_DIR}/src/common/url/url_util.cc
+       ${PROJECT_SOURCE_DIR}/src/common/url/url_parse.cc
+       ${PROJECT_SOURCE_DIR}/src/common/url/url_parse_file.cc
+       ${PROJECT_SOURCE_DIR}/src/common/net/http/transport_security_state.cpp
+       ${PROJECT_SOURCE_DIR}/src/common/src/tpkp_common.cpp
+       ${PROJECT_SOURCE_DIR}/src/common/src/tpkp_parser.cpp
+       ${PROJECT_SOURCE_DIR}/src/common/ui/popup_runner.cpp
+       ${PROJECT_SOURCE_DIR}/src/common/ui/popup_common.cpp
+       ${PROJECT_SOURCE_DIR}/src/common/ui/serialization.cpp
+       ${PROJECT_SOURCE_DIR}/src/common/ui/connection.cpp
+       colour_log_formatter.cpp
+       colors.cpp
+       popup_test_main.cpp
+       popup_runner_test.cpp
+       )
+
+ADD_EXECUTABLE(${TARGET_TPKP_POPUP_TEST} ${TEST_POPUP_SRCS})
+
+TARGET_LINK_LIBRARIES(${TARGET_TPKP_POPUP_TEST}
+       ${TEST_TPKP_POPUP_DEP_LIBRARIES}
+       boost_unit_test_framework
+       )
+
+INSTALL(TARGETS ${TARGET_TPKP_TEST} ${TARGET_TPKP_POPUP_TEST} DESTINATION bin)
index 2c52c49..53e257b 100644 (file)
@@ -14,7 +14,7 @@
  *    limitations under the License.
  */
 /*
- * @file        libcurl_sample.cpp
+ * @file        curl_test.cpp
  * @author      Kyungwook Tak (k.tak@samsung.com)
  * @version     1.0
  * @brief       tpkp_curl unit test.
diff --git a/test/popup_runner_test.cpp b/test/popup_runner_test.cpp
new file mode 100644 (file)
index 0000000..cd54573
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+/*
+ * @file        popup_runner_test.cpp
+ * @author      Kyungwook Tak (k.tak@samsung.com)
+ * @version     1.0
+ * @brief       popup runner and popup user service communication test
+ */
+#include "ui/popup_runner.h"
+
+#include <iostream>
+
+#include <boost/test/unit_test.hpp>
+
+BOOST_AUTO_TEST_SUITE(TPKP_POPUP_RUNNER_TEST)
+
+BOOST_AUTO_TEST_CASE(T00101_positive)
+{
+       TPKP::UI::Response response = TPKP::UI::runPopup("test_hostname");
+       switch (response) {
+       case TPKP::UI::Response::ALLOW:
+               std::cout << "###################################################" << std::endl;
+               std::cout << "##############                        #############" << std::endl;
+               std::cout << "##############  ALLOW BUTTON PRESSED  #############" << std::endl;
+               std::cout << "##############                        #############" << std::endl;
+               std::cout << "###################################################" << std::endl;
+               break;
+       case TPKP::UI::Response::DENY:
+               std::cout << "###################################################" << std::endl;
+               std::cout << "##############                        #############" << std::endl;
+               std::cout << "##############  DENY BUTTON PRESSED   #############" << std::endl;
+               std::cout << "##############                        #############" << std::endl;
+               std::cout << "###################################################" << std::endl;
+               break;
+       default:
+               std::cerr << "###################################################" << std::endl;
+               std::cerr << "##############                        #############" << std::endl;
+               std::cerr << "##############  UNKNOWN    RESPONSE   #############" << std::endl;
+               std::cerr << "##############                        #############" << std::endl;
+               std::cerr << "###################################################" << std::endl;
+               break;
+       }
+
+       BOOST_REQUIRE_MESSAGE(
+               response != TPKP::UI::Response::ERROR,
+               "Unknown response from popup user service!");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/popup_test_main.cpp b/test/popup_test_main.cpp
new file mode 100644 (file)
index 0000000..21b2e4e
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ *  Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+/*
+ * @file       popup_test_main.cpp
+ * @author     Kyungwook Tak (k.tak@samsung.com)
+ * @version    1.0
+ * @brief      pubkey-pinning popup test main of boost test framework.
+ */
+#define BOOST_TEST_MODULE TPKP_INTERNAL_TEST
+#include <boost/test/unit_test.hpp>
+#include <boost/test/unit_test_log.hpp>
+#include <boost/test/results_reporter.hpp>
+
+#include "colour_log_formatter.h"
+
+struct TestConfig {
+       TestConfig()
+       {
+               boost::unit_test::unit_test_log.set_threshold_level(boost::unit_test::log_test_units);
+               boost::unit_test::results_reporter::set_level(boost::unit_test::SHORT_REPORT);
+               boost::unit_test::unit_test_log.set_formatter(new TPKP::colour_log_formatter);
+       }
+};
+
+BOOST_GLOBAL_FIXTURE(TestConfig)