2 * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 * @file tpkp_common.cpp
18 * @author Kyungwook Tak (k.tak@samsung.com)
20 * @brief Https Public Key Pinning common implementation.
22 #include "tpkp_common.h"
24 #include <sys/syscall.h>
33 #include "net/http/transport_security_state.h"
34 #include "net/http/transport_security_state_static.h"
36 #include "tpkp_parser.h"
41 inline size_t _arraySize(const T &t)
43 return sizeof(t) / sizeof(*t);
46 } // anonymous namespace
52 return syscall(SYS_gettid);
55 Exception::Exception(tpkp_e code, const std::string &message)
60 const char *Exception::what(void) const noexcept
62 return m_message.c_str();
65 tpkp_e Exception::code(void) const noexcept
70 tpkp_e ExceptionSafe(const std::function<void()> &func)
75 } catch (const Exception &e) {
76 SLOGE("Exception: %s", e.what());
78 } catch (const std::bad_alloc &e) {
79 SLOGE("bad_alloc std exception: %s", e.what());
81 } catch (const std::exception &e) {
82 SLOGE("std exception: %s", e.what());
83 return TPKP_E_STD_EXCEPTION;
85 SLOGE("Unhandled exception occured!");
86 return TPKP_E_INTERNAL;
94 explicit Impl(const std::string &url);
96 void addPubkeyHash(HashAlgo algo, const RawBuffer &hashBuf);
97 bool checkPubkeyPins(void);
102 net::PreloadResult m_preloaded;
103 HashValueVector m_hashes;
105 bool LoadPreloadedPins(void);
106 bool HashesIntersect(const char *const *hashesArr);
108 class HashValuesEqual {
110 explicit HashValuesEqual(const char *chash);
111 bool operator()(const HashValue &other) const;
117 Context::Impl::Impl(const std::string &url)
119 m_host = Parser::extractHostname(url);
121 SLOGD("HPKP ready to check on host[%s]", m_host.c_str());
124 if (!m_preloaded.has_pins) {
125 SLOGD("no pins on static pubkey list.");
130 Context::Impl::~Impl() {}
132 void Context::Impl::addPubkeyHash(HashAlgo algo, const RawBuffer &hashBuf)
134 m_hashes.emplace_back(algo, hashBuf);
137 bool Context::Impl::checkPubkeyPins(void)
140 SLOGD("no pins on static pubkey list.");
144 const Pinset &pinset = kPinsets[m_preloaded.pinset_id];
146 if (HashesIntersect(pinset.rejected_pins)) {
147 SLOGE("pubkey is in rejected pin!");
151 if (!HashesIntersect(pinset.accepted_pins)) {
152 SLOGE("pubkey cannot be found in accepted pins!");
156 SLOGD("pubkey is pinned one!");
161 bool Context::Impl::hasPins(void)
163 return m_preloaded.has_pins;
166 bool Context::Impl::LoadPreloadedPins(void)
168 m_preloaded.has_pins = false;
169 if (!net::DecodeHSTSPreload(m_host, &m_preloaded))
172 size_t arrsize = _arraySize(kPinsets);
173 if (m_preloaded.pinset_id >= static_cast<uint32>(arrsize))
179 bool Context::Impl::HashesIntersect(const char *const *hashesArr)
184 for (; *hashesArr != nullptr; hashesArr++) {
188 HashValuesEqual{*hashesArr}) != m_hashes.end()) {
189 SLOGD("hash intersect found!");
197 Context::Impl::HashValuesEqual::HashValuesEqual(const char *chash) : m_chash(chash) {}
199 bool Context::Impl::HashValuesEqual::operator()(const HashValue &other) const
201 size_t len = other.hash.size();
204 * hash from decode preloaded value is base64 encoded,
205 * so it can be get length by strlen.
207 if (strlen(m_chash) != len)
210 for (size_t i = 0; i < len; i++) {
211 if (m_chash[i] != other.hash[i])
218 Context::Context(const std::string &url) : pImpl(new Impl{url}) {}
219 Context::~Context() {}
221 void Context::addPubkeyHash(HashAlgo algo, const RawBuffer &hashBuf)
223 SLOGD("add public key hash of algo[%d]", algo);
224 pImpl->addPubkeyHash(algo, hashBuf);
227 bool Context::checkPubkeyPins(void)
229 return pImpl->checkPubkeyPins();
232 bool Context::hasPins(void)
234 return pImpl->hasPins();