2 * Copyright (c) 2016 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 CertificateCollection.cpp
18 * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com)
19 * @author Kyungwook Tak (k.tak@samsung.com)
21 * @brief Handles certificate chain, make it complete and sort
33 #include <openssl/pem.h>
34 #include <openssl/x509.h>
36 #include <cert-svc/cinstance.h>
37 #include <cert-svc/ccert.h>
38 #include <cert-svc/cprimitives.h>
40 #include <dpl/log/log.h>
42 #include "vcore/Base64.h"
44 #include "vcore/CertificateCollection.h"
46 namespace ValidationCore {
50 inline std::string toBinaryString(int data)
52 char buffer[sizeof(int)];
53 memcpy(buffer, &data, sizeof(int));
54 return std::string(buffer, sizeof(int));
57 bool isHashMatchedName(const std::string &name, const std::string &hash)
59 if (name.compare(0, 8, hash) != 0)
65 bool isHashMatchedFile(const std::string &path, const std::string &hash)
67 CertificatePtr certPtr = Certificate::createFromFile(path);
68 std::string name = certPtr->getNameHash(Certificate::FIELD_SUBJECT);
69 return isHashMatchedName(name, hash);
72 struct dirent *readdir(DIR *dirp) {
74 auto ret = ::readdir(dirp);
76 LogWarning("Error read dir.");
80 CertificatePtr searchCert(const std::string &dir, const CertificatePtr &certPtr, bool withHash)
83 std::string hash = certPtr->getNameHash(Certificate::FIELD_ISSUER);
84 std::unique_ptr<DIR, std::function<int(DIR *)>> dp(::opendir(dir.c_str()),
88 LogError("Failed open dir[" << dir << "]");
89 return CertificatePtr();
92 while (auto dirp = ValidationCore::readdir(dp.get())) {
93 if (dirp->d_type == DT_DIR)
96 auto fullPath = dir + "/" + dirp->d_name;
98 if (!isHashMatchedName(dirp->d_name, hash))
101 if (!isHashMatchedFile(fullPath, hash))
105 LogDebug("Found hash matched file! : " << fullPath);
106 auto candidate = Certificate::createFromFile(fullPath);
107 if (candidate->getOneLine().compare(
108 certPtr->getOneLine(Certificate::FIELD_ISSUER)) != 0)
114 LogWarning("cert not found by hash[" << hash << "]");
115 return CertificatePtr();
116 } catch (const Certificate::Exception::Base &e) {
118 CertificateCollection::Exception::CertificateError,
119 "Error in handling certificate : " << e.DumpToString());
120 } catch (const std::exception &e) {
122 CertificateCollection::Exception::InternalError,
123 "std::exception occured : " << e.what());
126 CertificateCollection::Exception::InternalError,
127 "Unknown exception in CertificateCollection.");
131 CertificatePtr getIssuerCertFromStore(const CertificatePtr &certPtr)
133 LogDebug("Start to get issuer from store.");
134 CertificatePtr found = searchCert(TZ_SYS_CA_CERTS_TIZEN, certPtr, false);
136 if (found.get() != NULL) {
137 LogDebug("Found issuer cert in tizen root CA dir");
141 return searchCert(TZ_SYS_CA_CERTS, certPtr, true);
144 } // anonymous namespace
146 CertificateCollection::CertificateCollection()
147 : m_collectionStatus(COLLECTION_UNSORTED)
150 void CertificateCollection::clear(void)
152 m_collectionStatus = COLLECTION_UNSORTED;
156 void CertificateCollection::load(const CertificateList &certList)
158 m_collectionStatus = COLLECTION_UNSORTED;
159 std::copy(certList.begin(),
161 std::back_inserter(m_certList));
164 std::string CertificateCollection::toBase64String() const
166 std::ostringstream output;
167 int certNum = m_certList.size();
168 output << toBinaryString(certNum);
170 for (auto i = m_certList.begin(); i != m_certList.end(); ++i) {
171 std::string derCert = (*i)->getDER();
172 output << toBinaryString(derCert.size());
176 Base64Encoder base64;
178 base64.append(output.str());
183 CertificateList CertificateCollection::getCertificateList() const
188 bool CertificateCollection::isChain() const
190 if (COLLECTION_SORTED != m_collectionStatus)
191 VcoreThrowMsg(CertificateCollection::Exception::WrongUsage,
192 "You must sort certificate first");
194 return (COLLECTION_SORTED == m_collectionStatus) ? true : false;
197 bool CertificateCollection::sort()
199 if (COLLECTION_UNSORTED == m_collectionStatus) {
203 return (COLLECTION_SORTED == m_collectionStatus) ? true : false;
206 CertificateList CertificateCollection::getChain() const
208 if (COLLECTION_SORTED != m_collectionStatus)
209 VcoreThrowMsg(CertificateCollection::Exception::WrongUsage,
210 "You must sort certificates first");
215 void CertificateCollection::sortCollection()
217 // sorting is not necessary
218 if (m_certList.empty()) {
219 m_collectionStatus = COLLECTION_SORTED;
223 CertificateList sorted;
224 std::map<std::string, CertificatePtr> subTransl;
225 std::map<std::string, CertificatePtr> issTransl;
227 // Sort all certificate by subject
228 for (auto it = m_certList.begin(); it != m_certList.end(); ++it) {
229 subTransl.insert(std::make_pair((*it)->getOneLine(), (*it)));
232 // We need one start certificate
233 sorted.push_back(subTransl.begin()->second);
234 subTransl.erase(subTransl.begin());
236 // Get the issuer from front certificate and find certificate with this subject in subTransl.
237 // Add this certificate to the front.
238 while (!subTransl.empty()) {
239 std::string issuer = sorted.back()->getOneLine(Certificate::FIELD_ISSUER);
240 auto it = subTransl.find(issuer);
242 if (it == subTransl.end()) {
246 sorted.push_back(it->second);
250 // Sort all certificates by issuer
251 for (auto it = subTransl.begin(); it != subTransl.end(); ++it) {
252 issTransl.insert(std::make_pair(it->second->getOneLine(Certificate::FIELD_ISSUER), it->second));
255 // Get the subject from last certificate and find certificate with such issuer in issTransl.
256 // Add this certificate at end.
257 while (!issTransl.empty()) {
258 std::string sub = sorted.front()->getOneLine();
259 auto it = issTransl.find(sub);
261 if (it == issTransl.end()) {
265 sorted.push_front(it->second);
269 if (!issTransl.empty()) {
270 LogWarning("Certificates don't form a valid chain.");
271 m_collectionStatus = COLLECTION_CHAIN_BROKEN;
275 m_collectionStatus = COLLECTION_SORTED;
280 * Precondition : cert list sorted and has more than one cert
282 bool CertificateCollection::completeCertificateChain()
284 CertificatePtr last = m_certList.back();
286 if (last->isRootCert())
289 CertificatePtr rootCert = getIssuerCertFromStore(last);
294 if (!rootCert->isRootCert())
297 m_certList.push_back(rootCert);
301 size_t CertificateCollection::size() const
303 return m_certList.size();
306 bool CertificateCollection::empty() const
308 return m_certList.empty();
311 CertificateCollection::const_iterator CertificateCollection::begin() const
313 return m_certList.begin();
316 CertificateCollection::const_iterator CertificateCollection::end() const
318 return m_certList.end();
321 CertificatePtr CertificateCollection::back() const
323 return m_certList.back();
326 } // namespace ValidationCore