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")
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)
)
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)
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)
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.
%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
%_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
%if 0%{?pubkey_pinning_test_build}
%files test
%_bindir/tpkp-internal-test
+%_bindir/tpkp-internal-test-popup
%endif
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})
INSTALL(TARGETS ${TARGET_TPKP_COMMON_LIB} DESTINATION ${LIB_INSTALL_DIR})
INSTALL(FILES include/tpkp_error.h DESTINATION ${INCLUDEDIR}/tpkp/common)
+
+ADD_SUBDIRECTORY(ui)
class EXPORT_API ClientCache {
public:
+ enum class Decision : int {
+ UNKNOWN,
+ ALLOWED,
+ DENIED
+ };
+
ClientCache();
virtual ~ClientCache();
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;
};
}
--- /dev/null
+/*
+ * 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;
+
+};
+
+}
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
#include <sys/syscall.h>
#include <unistd.h>
+#include "tpkp_parser.h"
#include "tpkp_logger.h"
namespace {
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;
+}
+
}
#include "net/http/transport_security_state_static.h"
#include "tpkp_parser.h"
+#include "ui/popup_runner.h"
namespace {
bool LoadPreloadedPins(void);
bool HashesIntersect(const char *const *hashesArr);
+ bool askUser(void);
class HashValuesEqual {
public:
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!");
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() {}
--- /dev/null
+ADD_SUBDIRECTORY(popup-bin)
+ADD_SUBDIRECTORY(po)
--- /dev/null
+/*
+ * 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();
+}
+
+}
+}
--- /dev/null
+# 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})
--- /dev/null
+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"
--- /dev/null
+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"
--- /dev/null
+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"
--- /dev/null
+# 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)
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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.
+//
namespace {
+using Decision = TPKP::ClientCache::Decision;
+
TPKP::ClientCache g_cache;
inline CURLcode err_tpkp_to_curle(tpkp_e err) noexcept
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());
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!");
});
namespace {
+using Decision = TPKP::ClientCache::Decision;
+
TPKP::ClientCache g_cache;
inline int err_tpkp_to_gnutlse(tpkp_e err) noexcept
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());
}
}
- 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!");
});
--- /dev/null
+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}
+ )
--- /dev/null
+[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
--- /dev/null
+[Socket]
+ListenStream=/tmp/.tpkp-ui-backend.sock
+SocketMode=0777
+Service=pubkey-pinning-popup.service
+
+[Install]
+WantedBy=sockets.target
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)
* 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.
--- /dev/null
+/*
+ * 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()
--- /dev/null
+/*
+ * 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)