Refactor log system
[platform/core/security/cert-svc.git] / vcore / src / vcore / Certificate.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        Certificate.cpp
18  * @author      Bartlomiej Grzelewski (b.grzelewski@samsung.com)
19  * @version     1.0
20  * @brief
21  */
22 #include <vcore/Certificate.h>
23
24 #include <memory>
25 #include <sstream>
26 #include <iomanip>
27
28 #include <openssl/x509v3.h>
29 #include <openssl/bn.h>
30
31 #include <dpl/assert.h>
32 #include <dpl/log/log.h>
33
34 #include <vcore/Base64.h>
35 #include <vcore/TimeConversion.h>
36
37 namespace ValidationCore {
38
39 Certificate::Certificate(X509 *cert)
40 {
41     Assert(cert);
42     m_x509 = X509_dup(cert);
43     if (!m_x509)
44         VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
45                       "Internal Openssl error in d2i_X509 function.");
46 }
47
48 Certificate::Certificate(cert_svc_mem_buff &buffer)
49 {
50     Assert(buffer.data);
51     const unsigned char *ptr = buffer.data;
52     m_x509 = d2i_X509(NULL, &ptr, buffer.size);
53     if (!m_x509)
54         VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
55                       "Internal Openssl error in d2i_X509 function.");
56 }
57
58 Certificate::Certificate(const std::string &der,
59                          Certificate::FormType form)
60 {
61     Assert(der.size());
62
63     int size;
64     const unsigned char *ptr;
65     std::string tmp;
66
67     if (FORM_BASE64 == form) {
68         Base64Decoder base64;
69         base64.reset();
70         base64.append(der);
71         if (!base64.finalize()) {
72             LogWarning("Error during decoding");
73         }
74         tmp = base64.get();
75         ptr = reinterpret_cast<const unsigned char*>(tmp.c_str());
76         size = static_cast<int>(tmp.size());
77     } else {
78         ptr = reinterpret_cast<const unsigned char*>(der.c_str());
79         size = static_cast<int>(der.size());
80     }
81
82     m_x509 = d2i_X509(NULL, &ptr, size);
83     if (!m_x509)
84         VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
85                       "Internal Openssl error in d2i_X509 function.");
86 }
87
88 Certificate::~Certificate()
89 {
90     X509_free(m_x509);
91 }
92
93 X509* Certificate::getX509(void) const
94 {
95     return m_x509;
96 }
97
98 std::string Certificate::getDER(void) const
99 {
100     unsigned char *rawDer = NULL;
101     int size = i2d_X509(m_x509, &rawDer);
102     if (!rawDer || size <= 0)
103         VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
104                       "i2d_X509 failed");
105
106     std::string output(reinterpret_cast<char*>(rawDer), size);
107     OPENSSL_free(rawDer);
108     return output;
109 }
110
111 std::string Certificate::getBase64(void) const
112 {
113     Base64Encoder base64;
114     base64.reset();
115     base64.append(getDER());
116     base64.finalize();
117     return base64.get();
118 }
119
120 bool Certificate::isSignedBy(const CertificatePtr &parent) const
121 {
122     if (!parent) {
123         LogDebug("Invalid certificate parameter.");
124         return false;
125     }
126     return 0 == X509_NAME_cmp(X509_get_subject_name(parent->m_x509),
127                               X509_get_issuer_name(m_x509));
128 }
129
130 Certificate::Fingerprint Certificate::getFingerprint(
131         Certificate::FingerprintType type) const
132 {
133     unsigned int fingerprintlength = EVP_MAX_MD_SIZE;
134     unsigned char fingerprint[EVP_MAX_MD_SIZE];
135     Fingerprint raw;
136
137     if (type == FINGERPRINT_MD5) {
138         if (!X509_digest(m_x509, EVP_md5(), fingerprint, &fingerprintlength))
139             VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
140                           "MD5 digest counting failed!");
141     }
142
143     if (type == FINGERPRINT_SHA1) {
144         if (!X509_digest(m_x509, EVP_sha1(), fingerprint, &fingerprintlength))
145             VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
146                           "SHA1 digest counting failed");
147     }
148
149     raw.resize(fingerprintlength); // improve performance
150     std::copy(fingerprint, fingerprint + fingerprintlength, raw.begin());
151
152     return raw;
153 }
154
155 X509_NAME *Certificate::getX509Name(FieldType type) const
156 {
157     X509_NAME *name = NULL;
158
159     switch (type) {
160     case FIELD_ISSUER:
161         name = X509_get_issuer_name(m_x509);
162         break;
163     case FIELD_SUBJECT:
164         name = X509_get_subject_name(m_x509);
165         break;
166     default:
167         Assert("Invalid field type.");
168     }
169
170     if (!name)
171         VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
172                       "Error during x509 name extraction.");
173
174     return name;
175 }
176
177 std::string Certificate::getOneLine(FieldType type) const
178 {
179     X509_NAME *name = getX509Name(type);
180     static const int MAXB = 1024;
181     char buffer[MAXB] = {0, };
182     X509_NAME_oneline(name, buffer, MAXB);
183
184     return std::string(buffer);
185 }
186
187 std::string Certificate::getField(FieldType type, int fieldNid) const
188 {
189     X509_NAME *subjectName = getX509Name(type);
190     X509_NAME_ENTRY *subjectEntry = NULL;
191     std::string output;
192     int entryCount = X509_NAME_entry_count(subjectName);
193
194     for (int i = 0; i < entryCount; ++i) {
195         subjectEntry = X509_NAME_get_entry(subjectName,
196                                            i);
197
198         if (!subjectEntry) {
199             continue;
200         }
201
202         int nid = OBJ_obj2nid(
203             static_cast<ASN1_OBJECT*>(
204                     X509_NAME_ENTRY_get_object(subjectEntry)));
205
206         if (nid != fieldNid) {
207             continue;
208         }
209
210         ASN1_STRING* pASN1Str = subjectEntry->value;
211
212         unsigned char* pData = NULL;
213         int nLength = ASN1_STRING_to_UTF8(&pData,
214                                           pASN1Str);
215
216         if (nLength < 0)
217             VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
218                           "Reading field error.");
219
220         if (!pData) {
221             output = std::string();
222         }
223         else {
224             output = std::string(reinterpret_cast<char*>(pData), nLength);
225             OPENSSL_free(pData);
226         }
227     }
228
229     return output;
230 }
231
232 std::string Certificate::getCommonName(FieldType type) const
233 {
234     return getField(type, NID_commonName);
235 }
236
237 std::string Certificate::getCountryName(FieldType type) const
238 {
239     return getField(type, NID_countryName);
240 }
241
242 std::string Certificate::getStateOrProvinceName(FieldType type) const
243 {
244     return getField(type, NID_stateOrProvinceName);
245 }
246
247 std::string Certificate::getLocalityName(FieldType type) const
248 {
249     return getField(type, NID_localityName);
250 }
251
252 std::string Certificate::getOrganizationName(FieldType type) const
253 {
254     return getField(type, NID_organizationName);
255 }
256
257 std::string Certificate::getOrganizationalUnitName(FieldType type) const
258 {
259     return getField(type, NID_organizationalUnitName);
260 }
261
262 std::string Certificate::getEmailAddres(FieldType type) const
263 {
264     return getField(type, NID_pkcs9_emailAddress);
265 }
266
267 std::string Certificate::getOCSPURL() const
268 {
269     // TODO verify this code
270     std::string retValue;
271     AUTHORITY_INFO_ACCESS *aia = static_cast<AUTHORITY_INFO_ACCESS*>(
272             X509_get_ext_d2i(m_x509,
273                              NID_info_access,
274                              NULL,
275                              NULL));
276
277     // no AIA extension in the cert
278     if (NULL == aia) {
279         return retValue;
280     }
281
282     int count = sk_ACCESS_DESCRIPTION_num(aia);
283
284     for (int i = 0; i < count; ++i) {
285         ACCESS_DESCRIPTION* ad = sk_ACCESS_DESCRIPTION_value(aia, i);
286
287         if (OBJ_obj2nid(ad->method) == NID_ad_OCSP &&
288             ad->location->type == GEN_URI)
289         {
290             void *data = ASN1_STRING_data(ad->location->d.ia5);
291             if (!data)
292                 retValue = std::string();
293             else
294                 retValue = std::string(static_cast<char *>(data));
295             break;
296         }
297     }
298     sk_ACCESS_DESCRIPTION_free(aia);
299     return retValue;
300 }
301
302 Certificate::AltNameSet Certificate::getAlternativeNameDNS() const
303 {
304     AltNameSet set;
305
306     GENERAL_NAME *namePart = NULL;
307
308     STACK_OF(GENERAL_NAME)* san =
309         static_cast<STACK_OF(GENERAL_NAME)*>(
310             X509_get_ext_d2i(m_x509,NID_subject_alt_name,NULL,NULL));
311
312     while (sk_GENERAL_NAME_num(san) > 0) {
313         namePart = sk_GENERAL_NAME_pop(san);
314         if (GEN_DNS == namePart->type) {
315             char *temp = reinterpret_cast<char *>(ASN1_STRING_data(namePart->d.dNSName));
316             if (!temp) {
317                 set.insert(std::string());
318             }
319             else {
320                 set.insert(std::string(temp));
321                 LogDebug("FOUND GEN_DNS: " << temp);
322             }
323         } else {
324             LogDebug("FOUND GEN TYPE ID: " << namePart->type);
325         }
326     }
327     return set;
328 }
329
330 time_t Certificate::getNotAfter() const
331 {
332     ASN1_TIME *time = X509_get_notAfter(m_x509);
333     if (!time)
334         VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
335                       "Reading Not After error.");
336
337     time_t output;
338     if (asn1TimeToTimeT(time, &output))
339         VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
340                       "Converting ASN1_time to time_t error.");
341
342     return output;
343 }
344
345 time_t Certificate::getNotBefore() const
346 {
347     ASN1_TIME *time = X509_get_notBefore(m_x509);
348     if (!time)
349         VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
350                       "Reading Not Before error.");
351
352     time_t output;
353     if (asn1TimeToTimeT(time, &output))
354         VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
355                       "Converting ASN1_time to time_t error.");
356
357     return output;
358 }
359
360 ASN1_TIME* Certificate::getNotAfterTime() const
361 {
362     ASN1_TIME *timeafter = X509_get_notAfter(m_x509);
363     if (!timeafter)
364         VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
365                       "Reading Not After error.");
366
367     return timeafter;
368 }
369
370 ASN1_TIME* Certificate::getNotBeforeTime() const
371 {
372     ASN1_TIME *timebefore = X509_get_notBefore(m_x509);
373     if (!timebefore)
374         VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
375                       "Reading Not Before error.");
376
377     return timebefore;
378 }
379
380 bool Certificate::isRootCert()
381 {
382     // based on that root certificate has the same subject as issuer name
383     return isSignedBy(this->shared_from_this());
384 }
385
386 #ifdef TIZEN_FEATURE_CERT_SVC_OCSP_CRL
387 std::list<std::string>
388 Certificate::getCrlUris() const
389 {
390     std::list<std::string> result;
391
392     STACK_OF(DIST_POINT)* distPoints =
393         static_cast<STACK_OF(DIST_POINT)*>(
394             X509_get_ext_d2i(
395                 getX509(),
396                 NID_crl_distribution_points,
397                 NULL,
398                 NULL));
399     if (!distPoints) {
400         LogDebug("No distribution points in certificate.");
401         return result;
402     }
403
404     int count = sk_DIST_POINT_num(distPoints);
405     for (int i = 0; i < count; ++i) {
406         DIST_POINT* point = sk_DIST_POINT_value(distPoints, i);
407         if (!point) {
408             LogError("Failed to get distribution point.");
409             continue;
410         }
411         if (point->distpoint != NULL &&
412             point->distpoint->name.fullname != NULL)
413         {
414             int countName =
415                 sk_GENERAL_NAME_num(point->distpoint->name.fullname);
416             for (int j = 0; j < countName; ++j) {
417                 GENERAL_NAME* name = sk_GENERAL_NAME_value(
418                         point->distpoint->name.fullname, j);
419                 if (name != NULL && GEN_URI == name->type) {
420                     char *crlUri =
421                     reinterpret_cast<char*>(name->d.ia5->data);
422                     if (!crlUri) {
423                         LogError("Failed to get URI.");
424                         continue;
425                     }
426                     result.push_back(crlUri);
427                 }
428             }
429         }
430     }
431     sk_DIST_POINT_pop_free(distPoints, DIST_POINT_free);
432     return result;
433 }
434 #endif
435
436 long Certificate::getVersion() const
437 {
438     return X509_get_version(m_x509);
439 }
440
441 std::string Certificate::getSerialNumberString() const
442 {
443     ASN1_INTEGER *ai = X509_get_serialNumber(m_x509);
444     if (!ai)
445         VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
446                       "Error in X509_get_serialNumber");
447
448     std::stringstream stream;
449     stream << std::hex << std::setfill('0');
450     if (ai->type == V_ASN1_NEG_INTEGER) {
451         stream << "(Negetive) ";
452     }
453     for (int i=0; i<ai->length; ++i) {
454         stream << std::setw(2) << (int)ai->data[i] << ":";
455     }
456     std::string data = stream.str();
457     if (!data.empty()) {
458         data.erase(--data.end());
459     }
460
461     return data;
462 }
463
464 std::string Certificate::getKeyUsageString() const
465 {
466     // Extensions were defined in RFC 3280
467     const char *usage[] = {
468         "digitalSignature",
469         "nonRepudiation",
470         "keyEncipherment",
471         "dataEncipherment",
472         "keyAgreement",
473         "keyCertSign",
474         "cRLSign",
475         "encipherOnly",
476         "decipherOnly"
477     };
478     int crit = -1;
479     int idx = -1;
480     ASN1_BIT_STRING *keyUsage = (ASN1_BIT_STRING*)
481         X509_get_ext_d2i(m_x509, NID_key_usage, &crit, &idx);
482
483     std::stringstream stream;
484     for(int i=0; i<9; ++i) {
485         if (ASN1_BIT_STRING_get_bit(keyUsage, i)) {
486             stream << usage[i] << ",";
487         }
488     }
489     std::string result = stream.str();
490     if (!result.empty()) {
491         result.erase(--result.end());
492     }
493
494     return result;
495 }
496
497 std::string Certificate::getSignatureAlgorithmString() const
498 {
499     std::unique_ptr<BIO, std::function<int(BIO*)>>
500         b(BIO_new(BIO_s_mem()),BIO_free);
501
502     if (!b.get())
503         VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
504                       "Error in BIO_new");
505
506     if (i2a_ASN1_OBJECT(b.get(), m_x509->cert_info->signature->algorithm) < 0)
507         VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
508                       "Error in i2a_ASN1_OBJECT");
509
510     BUF_MEM *bptr = 0;
511     BIO_get_mem_ptr(b.get(), &bptr);
512     if (bptr == 0)
513         VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
514                       "Error in BIO_get_mem_ptr");
515
516     std::string result(bptr->data, bptr->length);
517
518     return result;
519 }
520
521 std::string Certificate::getPublicKeyString() const
522 {
523     std::unique_ptr<BIO, std::function<int(BIO*)>>
524         b(BIO_new(BIO_s_mem()),BIO_free);
525
526     if (!b.get())
527         VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
528                       "Error in BIO_new");
529
530     EVP_PKEY *pkey = X509_get_pubkey(m_x509);
531     if (!pkey)
532         VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
533                       "Error in X509_get_pubkey");
534
535     EVP_PKEY_print_public(b.get(), pkey, 16, NULL);
536     EVP_PKEY_free(pkey);
537
538     BUF_MEM *bptr = 0;
539     BIO_get_mem_ptr(b.get(), &bptr);
540     if (bptr == 0)
541         VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
542                       "Error in BIO_get_mem_ptr");
543
544     std::string result(bptr->data, bptr->length);
545
546     return result;
547 }
548
549 int Certificate::isCA() const
550 {
551     return X509_check_ca(m_x509);
552 }
553
554 std::string Certificate::FingerprintToColonHex(
555         const Certificate::Fingerprint &fingerprint)
556 {
557     std::string outString;
558     char buff[8];
559
560     for (size_t i = 0; i < fingerprint.size(); ++i) {
561         snprintf(buff,
562                  sizeof(buff),
563                  "%02X:",
564                  static_cast<unsigned int>(fingerprint[i]));
565         outString += buff;
566     }
567
568     // remove trailing ":"
569     outString.erase(outString.end() - 1);
570     return outString;
571 }
572
573 } //  namespace ValidationCore