80df3800e0e705a4de4c7daf37114c05190ff9d8
[platform/core/security/cert-svc.git] / vcore / src / vcore / CertificateCollection.cpp
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 /*
17  * @file        CertificateCollection.cpp
18  * @author      Bartlomiej Grzelewski (b.grzelewski@samsung.com)
19  * @version     0.1
20  * @brief
21  */
22
23 #include <openssl/pem.h>
24 #include <openssl/x509.h>
25
26 #include <algorithm>
27
28 #include <cert-svc/cinstance.h>
29 #include <cert-svc/ccert.h>
30 #include <cert-svc/cprimitives.h>
31
32 #include <dpl/binary_queue.h>
33 #include <dpl/foreach.h>
34 #include <dpl/log/log.h>
35 #include <vcore/Base64.h>
36
37 #include <vcore/CertificateCollection.h>
38
39 namespace {
40
41 using namespace ValidationCore;
42
43 inline std::string toBinaryString(int data)
44 {
45     char buffer[sizeof(int)];
46     memcpy(buffer, &data, sizeof(int));
47     return std::string(buffer, sizeof(int));
48 }
49
50 CertificatePtr getCertFromStore(X509_NAME *subject)
51 {
52     if (!subject) {
53         LogError("Invalid input!");
54         return CertificatePtr();
55     }
56
57     CertSvcInstance instance;
58     if (certsvc_instance_new(&instance) != CERTSVC_SUCCESS) {
59         LogError("Failed to make instance");
60                 return CertificatePtr();
61     }
62
63     char buffer[1024];
64     X509_NAME_oneline(subject, buffer, 1024);
65
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();
73     }
74
75         size_t listSize = 0;
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();
81         }
82
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();
90         }
91
92         X509 *pCertX509 = NULL;
93         result = certsvc_certificate_dup_x509(cert, &pCertX509);
94         certsvc_certificate_list_all_free(certList);
95         certsvc_instance_free(instance);
96
97     if (result != CERTSVC_SUCCESS || !pCertX509) {
98         LogError("Error during certificate dup x509. result : " << result);
99         return CertificatePtr();
100     }
101
102     CertificatePtr parentCert(new Certificate(pCertX509));
103     X509_free(pCertX509);
104
105     return parentCert;
106 }
107 } // namespace
108
109 namespace ValidationCore {
110
111 CertificateCollection::CertificateCollection()
112   : m_collectionStatus(COLLECTION_UNSORTED)
113 {}
114
115 void CertificateCollection::clear(void)
116 {
117     m_collectionStatus = COLLECTION_UNSORTED;
118     m_certList.clear();
119 }
120
121 void CertificateCollection::load(const CertificateList &certList)
122 {
123     m_collectionStatus = COLLECTION_UNSORTED;
124     std::copy(certList.begin(),
125               certList.end(),
126               std::back_inserter(m_certList));
127 }
128
129 bool CertificateCollection::load(const std::string &buffer)
130 {
131     Base64Decoder base64;
132     base64.reset();
133     base64.append(buffer);
134     if (!base64.finalize()) {
135         LogWarning("Error during chain decoding");
136         return false;
137     }
138     std::string binaryData = base64.get();
139
140     VcoreDPL::BinaryQueue queue;
141     queue.AppendCopy(binaryData.c_str(), binaryData.size());
142
143     int certNum;
144     queue.FlattenConsume(&certNum, sizeof(int));
145
146     CertificateList list;
147     CertificatePtr certPtr;
148
149     for (int i = 0; i < certNum; ++i) {
150         int certSize;
151         queue.FlattenConsume(&certSize, sizeof(int));
152         std::vector<char> rawDERCert;
153         rawDERCert.resize(certSize);
154         queue.FlattenConsume(&rawDERCert[0], certSize);
155         VcoreTry {
156             list.push_back(CertificatePtr(new Certificate(std::string(
157                 rawDERCert.begin(),
158                 rawDERCert.end()))));
159         } VcoreCatch (Certificate::Exception::Base) {
160             LogWarning("Error during certificate creation.");
161             return false;
162         }
163
164         LogDebug("Loading certificate. Certificate common name: " << list.back()->getCommonName());
165     }
166     load(list);
167     return true;
168 }
169
170 std::string CertificateCollection::toBase64String() const
171 {
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());
178         output << derCert;
179     }
180     Base64Encoder base64;
181     base64.reset();
182     base64.append(output.str());
183     base64.finalize();
184     return base64.get();
185 }
186
187 CertificateList CertificateCollection::getCertificateList() const
188 {
189     return m_certList;
190 }
191
192 bool CertificateCollection::isChain() const
193 {
194     if (COLLECTION_SORTED != m_collectionStatus)
195         VcoreThrowMsg(CertificateCollection::Exception::WrongUsage,
196                       "You must sort certificate first");
197
198     return (COLLECTION_SORTED == m_collectionStatus) ? true : false;
199 }
200
201 bool CertificateCollection::sort()
202 {
203     if (COLLECTION_UNSORTED == m_collectionStatus) {
204         sortCollection();
205     }
206     return (COLLECTION_SORTED == m_collectionStatus) ? true : false;
207 }
208
209 CertificateList CertificateCollection::getChain() const
210 {
211     if (COLLECTION_SORTED != m_collectionStatus)
212         VcoreThrowMsg(CertificateCollection::Exception::WrongUsage,
213                       "You must sort certificates first");
214
215     return m_certList;
216 }
217
218 void CertificateCollection::sortCollection()
219 {
220     // sorting is not necessary
221     if (m_certList.empty()) {
222         m_collectionStatus = COLLECTION_SORTED;
223         return;
224     }
225
226     CertificateList sorted;
227     std::map<std::string, CertificatePtr> subTransl;
228     std::map<std::string, CertificatePtr> issTransl;
229
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)));
233     }
234     // We need one start certificate
235     sorted.push_back(subTransl.begin()->second);
236     subTransl.erase(subTransl.begin());
237
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()) {
244             break;
245         }
246         sorted.push_back(it->second);
247         subTransl.erase(it);
248     }
249
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));
253     }
254
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()) {
261             break;
262         }
263         sorted.push_front(it->second);
264         issTransl.erase(it);
265     }
266
267     if (!issTransl.empty()) {
268         LogWarning("Certificates don't form a valid chain.");
269         m_collectionStatus = COLLECTION_CHAIN_BROKEN;
270         return;
271     }
272
273     m_collectionStatus = COLLECTION_SORTED;
274     m_certList = sorted;
275 }
276
277 /*
278  *  Precondition : cert list sorted and has more than one cert
279  */
280 bool CertificateCollection::completeCertificateChain()
281 {
282     CertificatePtr last = m_certList.back();
283     if (last->isSignedBy(last))
284         return true;
285
286     /* TODO Add getIssuerName function to Certificate.h */
287     CertificatePtr parent = getCertFromStore(X509_get_issuer_name(last->getX509()));
288
289     if (!parent.get())
290         return false;
291
292     m_certList.push_back(parent);
293     if (!parent->isSignedBy(parent))
294         return false;
295
296     return true;
297 }
298
299 size_t CertificateCollection::size() const {
300     return m_certList.size();
301 }
302
303 bool CertificateCollection::empty() const {
304     return m_certList.empty();
305 }
306
307 CertificateCollection::const_iterator CertificateCollection::begin() const {
308     return m_certList.begin();
309 }
310
311 CertificateCollection::const_iterator CertificateCollection::end() const {
312     return m_certList.end();
313 }
314
315 CertificatePtr CertificateCollection::back() const {
316     return m_certList.back();
317 }
318
319 } // namespace ValidationCore
320