2 * Copyright (c) 2011 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)
23 #include <openssl/pem.h>
24 #include <openssl/x509.h>
28 #include <cert-svc/cinstance.h>
29 #include <cert-svc/ccert.h>
30 #include <cert-svc/cprimitives.h>
32 #include <dpl/binary_queue.h>
33 #include <dpl/foreach.h>
34 #include <dpl/log/log.h>
35 #include <vcore/Base64.h>
37 #include <vcore/CertificateCollection.h>
41 using namespace ValidationCore;
43 inline std::string toBinaryString(int data)
45 char buffer[sizeof(int)];
46 memcpy(buffer, &data, sizeof(int));
47 return std::string(buffer, sizeof(int));
50 CertificatePtr getCertFromStore(X509_NAME *subject)
53 LogError("Invalid input!");
54 return CertificatePtr();
57 CertSvcInstance instance;
58 if (certsvc_instance_new(&instance) != CERTSVC_SUCCESS) {
59 LogError("Failed to make instance");
60 return CertificatePtr();
64 X509_NAME_oneline(subject, buffer, 1024);
66 LogDebug("Search certificate with subject: " << buffer);
67 CertSvcCertificateList certList;
68 int result = certsvc_certificate_search(instance, CERTSVC_SUBJECT, buffer, &certList);
69 if (result != CERTSVC_SUCCESS) {
70 LogError("Error during certificate search. result : " << result);
71 certsvc_instance_free(instance);
72 return CertificatePtr();
76 result = certsvc_certificate_list_get_length(certList, &listSize);
77 if (result != CERTSVC_SUCCESS || listSize <= 0) {
78 LogError("Error in certsvc_certificate_list_get_length. result : " << result);
79 certsvc_instance_free(instance);
80 return CertificatePtr();
83 CertSvcCertificate cert;
84 result = certsvc_certificate_list_get_one(certList, 0, &cert);
85 if (result != CERTSVC_SUCCESS) {
86 LogError("Failed to get cert from cert list. result : " << result);
87 certsvc_certificate_list_all_free(certList);
88 certsvc_instance_free(instance);
89 return CertificatePtr();
92 X509 *pCertX509 = NULL;
93 result = certsvc_certificate_dup_x509(cert, &pCertX509);
94 certsvc_certificate_list_all_free(certList);
95 certsvc_instance_free(instance);
97 if (result != CERTSVC_SUCCESS || !pCertX509) {
98 LogError("Error during certificate dup x509. result : " << result);
99 return CertificatePtr();
102 CertificatePtr parentCert(new Certificate(pCertX509));
103 X509_free(pCertX509);
109 namespace ValidationCore {
111 CertificateCollection::CertificateCollection()
112 : m_collectionStatus(COLLECTION_UNSORTED)
115 void CertificateCollection::clear(void)
117 m_collectionStatus = COLLECTION_UNSORTED;
121 void CertificateCollection::load(const CertificateList &certList)
123 m_collectionStatus = COLLECTION_UNSORTED;
124 std::copy(certList.begin(),
126 std::back_inserter(m_certList));
129 bool CertificateCollection::load(const std::string &buffer)
131 Base64Decoder base64;
133 base64.append(buffer);
134 if (!base64.finalize()) {
135 LogWarning("Error during chain decoding");
138 std::string binaryData = base64.get();
140 VcoreDPL::BinaryQueue queue;
141 queue.AppendCopy(binaryData.c_str(), binaryData.size());
144 queue.FlattenConsume(&certNum, sizeof(int));
146 CertificateList list;
147 CertificatePtr certPtr;
149 for (int i = 0; i < certNum; ++i) {
151 queue.FlattenConsume(&certSize, sizeof(int));
152 std::vector<char> rawDERCert;
153 rawDERCert.resize(certSize);
154 queue.FlattenConsume(&rawDERCert[0], certSize);
156 list.push_back(CertificatePtr(new Certificate(std::string(
158 rawDERCert.end()))));
159 } VcoreCatch (Certificate::Exception::Base) {
160 LogWarning("Error during certificate creation.");
164 LogDebug("Loading certificate. Certificate common name: " << list.back()->getCommonName());
170 std::string CertificateCollection::toBase64String() const
172 std::ostringstream output;
173 int certNum = m_certList.size();
174 output << toBinaryString(certNum);
175 FOREACH(i, m_certList){
176 std::string derCert = (*i)->getDER();
177 output << toBinaryString(derCert.size());
180 Base64Encoder base64;
182 base64.append(output.str());
187 CertificateList CertificateCollection::getCertificateList() const
192 bool CertificateCollection::isChain() const
194 if (COLLECTION_SORTED != m_collectionStatus)
195 VcoreThrowMsg(CertificateCollection::Exception::WrongUsage,
196 "You must sort certificate first");
198 return (COLLECTION_SORTED == m_collectionStatus) ? true : false;
201 bool CertificateCollection::sort()
203 if (COLLECTION_UNSORTED == m_collectionStatus) {
206 return (COLLECTION_SORTED == m_collectionStatus) ? true : false;
209 CertificateList CertificateCollection::getChain() const
211 if (COLLECTION_SORTED != m_collectionStatus)
212 VcoreThrowMsg(CertificateCollection::Exception::WrongUsage,
213 "You must sort certificates first");
218 void CertificateCollection::sortCollection()
220 // sorting is not necessary
221 if (m_certList.empty()) {
222 m_collectionStatus = COLLECTION_SORTED;
226 CertificateList sorted;
227 std::map<std::string, CertificatePtr> subTransl;
228 std::map<std::string, CertificatePtr> issTransl;
230 // Sort all certificate by subject
231 for (auto it = m_certList.begin(); it != m_certList.end(); ++it) {
232 subTransl.insert(std::make_pair((*it)->getOneLine(), (*it)));
234 // We need one start certificate
235 sorted.push_back(subTransl.begin()->second);
236 subTransl.erase(subTransl.begin());
238 // Get the issuer from front certificate and find certificate with this subject in subTransl.
239 // Add this certificate to the front.
240 while (!subTransl.empty()) {
241 std::string issuer = sorted.back()->getOneLine(Certificate::FIELD_ISSUER);
242 auto it = subTransl.find(issuer);
243 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);
260 if (it == issTransl.end()) {
263 sorted.push_front(it->second);
267 if (!issTransl.empty()) {
268 LogWarning("Certificates don't form a valid chain.");
269 m_collectionStatus = COLLECTION_CHAIN_BROKEN;
273 m_collectionStatus = COLLECTION_SORTED;
278 * Precondition : cert list sorted and has more than one cert
280 bool CertificateCollection::completeCertificateChain()
282 CertificatePtr last = m_certList.back();
283 if (last->isSignedBy(last))
286 /* TODO Add getIssuerName function to Certificate.h */
287 CertificatePtr parent = getCertFromStore(X509_get_issuer_name(last->getX509()));
292 m_certList.push_back(parent);
293 if (!parent->isSignedBy(parent))
299 size_t CertificateCollection::size() const {
300 return m_certList.size();
303 bool CertificateCollection::empty() const {
304 return m_certList.empty();
307 CertificateCollection::const_iterator CertificateCollection::begin() const {
308 return m_certList.begin();
311 CertificateCollection::const_iterator CertificateCollection::end() const {
312 return m_certList.end();
315 CertificatePtr CertificateCollection::back() const {
316 return m_certList.back();
319 } // namespace ValidationCore