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"
30 #include "net/http/transport_security_state.h"
31 #include "net/http/transport_security_state_static.h"
33 #include "tpkp_parser.h"
38 inline size_t _arraySize(const T &t)
40 return sizeof(t) / sizeof(*t);
43 } // anonymous namespace
47 Exception::Exception(tpkp_e code, const std::string &message)
52 const char *Exception::what(void) const noexcept
54 return m_message.c_str();
57 tpkp_e Exception::code(void) const noexcept
62 tpkp_e ExceptionSafe(const std::function<void()> &func)
67 } catch (const Exception &e) {
68 SLOGE("Exception: %s", e.what());
70 } catch (const std::bad_alloc &e) {
71 SLOGE("bad_alloc std exception: %s", e.what());
73 } catch (const std::exception &e) {
74 SLOGE("std exception: %s", e.what());
75 return TPKP_E_STD_EXCEPTION;
77 SLOGE("Unhandled exception occured!");
78 return TPKP_E_INTERNAL;
86 explicit Impl(const std::string &url);
88 void addPubkeyHash(HashAlgo algo, const RawBuffer &hashBuf);
89 bool checkPubkeyPins(void);
94 net::PreloadResult m_preloaded;
95 HashValueVector m_hashes;
97 bool LoadPreloadedPins(void);
98 bool HashesIntersect(const char *const *hashesArr);
100 class HashValuesEqual {
102 explicit HashValuesEqual(const char *chash);
103 bool operator()(const HashValue &other) const;
109 Context::Impl::Impl(const std::string &url)
111 m_host = Parser::extractHostname(url);
113 SLOGD("HPKP ready to check on host[%s]", m_host.c_str());
116 if (!m_preloaded.has_pins) {
117 SLOGD("no pins on static pubkey list.");
122 Context::Impl::~Impl() {}
124 void Context::Impl::addPubkeyHash(HashAlgo algo, const RawBuffer &hashBuf)
126 m_hashes.emplace_back(algo, hashBuf);
129 bool Context::Impl::checkPubkeyPins(void)
132 SLOGD("no pins on static pubkey list.");
136 const Pinset &pinset = kPinsets[m_preloaded.pinset_id];
138 if (HashesIntersect(pinset.rejected_pins)) {
139 SLOGE("pubkey is in rejected pin!");
143 if (!HashesIntersect(pinset.accepted_pins)) {
144 SLOGE("pubkey cannot be found in accepted pins!");
148 SLOGD("pubkey is pinned one!");
153 bool Context::Impl::hasPins(void)
155 return m_preloaded.has_pins;
158 bool Context::Impl::LoadPreloadedPins(void)
160 m_preloaded.has_pins = false;
161 if (!net::DecodeHSTSPreload(m_host, &m_preloaded))
164 size_t arrsize = _arraySize(kPinsets);
165 if (m_preloaded.pinset_id >= static_cast<uint32>(arrsize))
171 bool Context::Impl::HashesIntersect(const char *const *hashesArr)
176 for (; *hashesArr != nullptr; hashesArr++) {
180 HashValuesEqual{*hashesArr}) != m_hashes.end()) {
181 SLOGD("hash intersect found!");
189 Context::Impl::HashValuesEqual::HashValuesEqual(const char *chash) : m_chash(chash) {}
191 bool Context::Impl::HashValuesEqual::operator()(const HashValue &other) const
193 size_t len = other.hash.size();
196 * hash from decode preloaded value is base64 encoded,
197 * so it can be get length by strlen.
199 if (strlen(m_chash) != len)
202 for (size_t i = 0; i < len; i++) {
203 if (m_chash[i] != other.hash[i])
210 Context::Context(const std::string &url) : pImpl(new Impl{url}) {}
211 Context::~Context() {}
213 void Context::addPubkeyHash(HashAlgo algo, const RawBuffer &hashBuf)
215 SLOGD("add public key hash of algo[%d]", algo);
216 pImpl->addPubkeyHash(algo, hashBuf);
219 bool Context::checkPubkeyPins(void)
221 return pImpl->checkPubkeyPins();
224 bool Context::hasPins(void)
226 return pImpl->hasPins();