Fix coverity defects
[platform/core/security/cert-svc.git] / src / vcore / Certificate.cpp
1 /*
2  * Copyright (c) 2016 - 2017 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       Certificate class implementation
21  */
22
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <unistd.h>
26
27 #include <cstdio>
28 #include <memory>
29 #include <iomanip>
30
31 #include <openssl/pem.h>
32 #include <openssl/x509.h>
33 #include <openssl/x509v3.h>
34 #include <openssl/objects.h>
35
36 #include <dpl/log/log.h>
37
38 #include "vcore/Base64.h"
39 #include "vcore/TimeConversion.h"
40
41 #include "vcore/Certificate.h"
42
43 namespace {
44
45 typedef std::unique_ptr<X509, std::function<void(X509 *)>> ScopedX509;
46 typedef std::unique_ptr<FILE, std::function<int(FILE *)>> ScopedFile;
47
48 } // namespace anonymous
49
50 namespace ValidationCore {
51
52 Certificate::Certificate(X509 *cert)
53 {
54         if (cert == NULL)
55                 VcoreThrowMsg(Certificate::Exception::WrongParamError,
56                                           "Input X509 shouldn't be NULL.");
57
58         m_x509 = X509_dup(cert);
59
60         if (m_x509 == NULL)
61                 VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
62                                           "Internal Openssl error in d2i_X509 function.");
63 }
64
65 Certificate::Certificate(const std::string &data,
66                                                  Certificate::FormType form)
67 {
68         if (data.size() == 0)
69                 VcoreThrowMsg(Certificate::Exception::WrongParamError,
70                                           "Input data shouldn't be empty");
71
72         int size;
73         const unsigned char *ptr;
74         std::string tmp = data;
75
76         // transform to DER format
77         if (FORM_BASE64 == form) {
78                 try {
79                         Base64Decoder base64;
80                         base64.reset();
81                         base64.append(data);
82
83                         if (!base64.finalize()) {
84                                 LogWarning("Error during decoding");
85                         }
86
87                         tmp = base64.get();
88                 } catch (const Base64Decoder::Exception::Base &e) {
89                         LogError("Exception in Certificate constructor : " << e.DumpToString());
90                         VcoreThrowMsg(Certificate::Exception::Base64Error, "Failed to Base64Decoder");
91                 }
92         }
93
94         ptr = reinterpret_cast<const unsigned char *>(tmp.c_str());
95         size = static_cast<int>(tmp.size());
96         m_x509 = d2i_X509(NULL, &ptr, size);
97
98         if (!m_x509)
99                 VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
100                                           "Internal Openssl error in d2i_X509 function.");
101 }
102
103 static int getFileSize(const std::string &location, off_t &size)
104 {
105         struct stat status;
106         int ret = stat(location.c_str(), &status);
107         size = status.st_size;
108         return ret;
109 }
110
111 CertificatePtr Certificate::createFromFile(const std::string &location)
112 {
113         FILE *fp = NULL;
114         X509 *x509 = NULL;
115         fp = fopen(location.c_str(), "rb");
116
117         if (fp == NULL)
118                 VcoreThrowMsg(Certificate::Exception::WrongParamError,
119                                           "File cannot be opened : " << location);
120
121         ScopedFile filePtr(fp, fclose);
122         x509 = PEM_read_X509(fp, NULL, NULL, NULL);
123
124         if (x509 == NULL) {
125                 rewind(fp);
126                 x509 = PEM_read_X509_AUX(fp, NULL, NULL, NULL);
127         }
128
129         if (x509 != NULL) {
130                 ScopedX509 x509Ptr(x509, X509_free);
131                 return CertificatePtr(new Certificate(x509));
132         }
133
134         off_t filesize = 0;
135         if(getFileSize(location, filesize) != 0)
136                 VcoreThrowMsg(Certificate::Exception::WrongParamError,
137                                         "Fail to get file size. : " << location);
138         if (filesize == 0)
139                 VcoreThrowMsg(Certificate::Exception::WrongParamError,
140                                           "File content is empty : " << location);
141
142         std::unique_ptr<unsigned char[]> content(new unsigned char[filesize + 1]);
143         if (content == NULL)
144                 VcoreThrowMsg(Certificate::Exception::InternalError,
145                                           "Fail to allocate memory.");
146
147         memset(content.get(), 0x00, filesize + 1);
148         rewind(fp);
149
150         if (fread(content.get(), sizeof(unsigned char), filesize, fp) != static_cast<size_t>(filesize))
151                 VcoreThrowMsg(Certificate::Exception::InternalError,
152                                           "file read failed. wrong size : " << location);
153
154         content[filesize] = '\0';
155         const unsigned char *ptr = reinterpret_cast<const unsigned char *>(content.get());
156         x509 = d2i_X509(NULL, &ptr, filesize);
157
158         if (x509 == NULL)
159                 VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
160                                           "Internal Openssl error in d2i_X509 function.");
161
162         return CertificatePtr(new Certificate(x509));
163 }
164
165 Certificate::~Certificate()
166 {
167         X509_free(m_x509);
168 }
169
170 X509 *Certificate::getX509(void) const
171 {
172         return m_x509;
173 }
174
175 std::string Certificate::getDER(void) const
176 {
177         unsigned char *rawDer = NULL;
178         int size = i2d_X509(m_x509, &rawDer);
179
180         if (!rawDer || size <= 0)
181                 VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
182                                           "i2d_X509 failed");
183
184         std::string output(reinterpret_cast<char *>(rawDer), size);
185         OPENSSL_free(rawDer);
186         return output;
187 }
188
189 std::string Certificate::getBase64(void) const
190 {
191         Base64Encoder base64;
192
193         try {
194                 base64.reset();
195                 base64.append(getDER());
196                 base64.finalize();
197         } catch (const Base64Encoder::Exception::Base &e) {
198                 LogError("Exception in Certificate getBase64 : " << e.DumpToString());
199                 VcoreThrowMsg(Certificate::Exception::Base64Error, "Failed to Base64Encoder");
200         }
201
202         return base64.get();
203 }
204
205 bool Certificate::isSignedBy(const CertificatePtr &parent) const
206 {
207         if (!parent) {
208                 LogDebug("Invalid certificate parameter.");
209                 return false;
210         }
211
212         return 0 == X509_NAME_cmp(X509_get_subject_name(parent->m_x509),
213                                                           X509_get_issuer_name(m_x509));
214 }
215
216 Certificate::Fingerprint Certificate::getFingerprint(
217         Certificate::FingerprintType type) const
218 {
219         unsigned int fingerprintlength = EVP_MAX_MD_SIZE;
220         unsigned char fingerprint[EVP_MAX_MD_SIZE];
221         Fingerprint raw;
222
223         if (type == FINGERPRINT_MD5) {
224                 if (!X509_digest(m_x509, EVP_md5(), fingerprint, &fingerprintlength))
225                         VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
226                                                   "MD5 digest counting failed!");
227         }
228
229         if (type == FINGERPRINT_SHA1) {
230                 if (!X509_digest(m_x509, EVP_sha1(), fingerprint, &fingerprintlength))
231                         VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
232                                                   "SHA1 digest counting failed");
233         }
234
235         raw.resize(fingerprintlength); // improve performance
236         std::copy(fingerprint, fingerprint + fingerprintlength, raw.begin());
237         return raw;
238 }
239
240 X509_NAME *Certificate::getX509Name(FieldType type) const
241 {
242         X509_NAME *name = NULL;
243
244         switch (type) {
245         case FIELD_ISSUER:
246                 name = X509_get_issuer_name(m_x509);
247                 break;
248
249         case FIELD_SUBJECT:
250                 name = X509_get_subject_name(m_x509);
251                 break;
252
253         default:
254                 VcoreThrowMsg(Certificate::Exception::WrongParamError,
255                                           "Invalid field type param. type : " << type);
256         }
257
258         if (!name)
259                 VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
260                                           "Error during x509 name extraction.");
261
262         return name;
263 }
264
265 std::string Certificate::getOneLine(FieldType type) const
266 {
267         X509_NAME *name = getX509Name(type);
268         static const int MAXB = 1024;
269         char buffer[MAXB] = {0, };
270         X509_NAME_oneline(name, buffer, MAXB);
271         return std::string(buffer);
272 }
273
274 std::string Certificate::getField(FieldType type, int fieldNid) const
275 {
276         X509_NAME *subjectName = getX509Name(type);
277         X509_NAME_ENTRY *subjectEntry = NULL;
278         std::string output;
279         int entryCount = X509_NAME_entry_count(subjectName);
280
281         for (int i = 0; i < entryCount; ++i) {
282                 subjectEntry = X509_NAME_get_entry(subjectName,
283                                                                                    i);
284
285                 if (!subjectEntry) {
286                         continue;
287                 }
288
289                 int nid = OBJ_obj2nid(
290                                           static_cast<ASN1_OBJECT *>(
291                                                   X509_NAME_ENTRY_get_object(subjectEntry)));
292
293                 if (nid != fieldNid) {
294                         continue;
295                 }
296
297                 ASN1_STRING *pASN1Str = subjectEntry->value;
298                 unsigned char *pData = NULL;
299                 int nLength = ASN1_STRING_to_UTF8(&pData,
300                                                                                   pASN1Str);
301
302                 if (nLength < 0)
303                         VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
304                                                   "Reading field error.");
305
306                 if (!pData) {
307                         output = std::string();
308                 } else {
309                         output = std::string(reinterpret_cast<char *>(pData), nLength);
310                         OPENSSL_free(pData);
311                 }
312         }
313
314         return output;
315 }
316
317 std::string Certificate::getCommonName(FieldType type) const
318 {
319         return getField(type, NID_commonName);
320 }
321
322 std::string Certificate::getCountryName(FieldType type) const
323 {
324         return getField(type, NID_countryName);
325 }
326
327 std::string Certificate::getStateOrProvinceName(FieldType type) const
328 {
329         return getField(type, NID_stateOrProvinceName);
330 }
331
332 std::string Certificate::getLocalityName(FieldType type) const
333 {
334         return getField(type, NID_localityName);
335 }
336
337 std::string Certificate::getOrganizationName(FieldType type) const
338 {
339         return getField(type, NID_organizationName);
340 }
341
342 std::string Certificate::getOrganizationalUnitName(FieldType type) const
343 {
344         return getField(type, NID_organizationalUnitName);
345 }
346
347 std::string Certificate::getEmailAddres(FieldType type) const
348 {
349         return getField(type, NID_pkcs9_emailAddress);
350 }
351
352 std::string Certificate::getNameHash(FieldType type) const
353 {
354         unsigned long ulNameHash;
355         char buf[9] = {0};
356
357         if (type == FIELD_SUBJECT)
358                 ulNameHash = X509_subject_name_hash(m_x509);
359         else
360                 ulNameHash = X509_issuer_name_hash(m_x509);
361
362         snprintf(buf, 9, "%08lx", ulNameHash);
363         return std::string(buf);
364 }
365
366 std::string Certificate::getUID(FieldType type) const
367 {
368         ASN1_BIT_STRING *uid = NULL;
369
370         if (type == FIELD_SUBJECT)
371                 uid = m_x509->cert_info->subjectUID;
372         else
373                 uid = m_x509->cert_info->issuerUID;
374
375         if (uid->data == NULL)
376                 return std::string();
377
378         char *temp = new char[uid->length + 1];
379
380         if(temp == NULL) {
381                 LogError("Fail to allocate memory.");
382                 return std::string();
383         }
384
385         memcpy(temp, uid->data, uid->length);
386         temp[uid->length] = 0;
387         std::string uidStr(temp);
388         delete []temp;
389         return uidStr;
390 }
391
392 std::string Certificate::getOCSPURL() const
393 {
394         // TODO verify this code
395         std::string retValue;
396         AUTHORITY_INFO_ACCESS *aia = static_cast<AUTHORITY_INFO_ACCESS *>(
397                                                                          X509_get_ext_d2i(m_x509,
398                                                                                          NID_info_access,
399                                                                                          NULL,
400                                                                                          NULL));
401
402         // no AIA extension in the cert
403         if (NULL == aia) {
404                 return retValue;
405         }
406
407         int count = sk_ACCESS_DESCRIPTION_num(aia);
408
409         for (int i = 0; i < count; ++i) {
410                 ACCESS_DESCRIPTION *ad = sk_ACCESS_DESCRIPTION_value(aia, i);
411
412                 if (OBJ_obj2nid(ad->method) == NID_ad_OCSP &&
413                                 ad->location->type == GEN_URI) {
414                         void *data = ASN1_STRING_data(ad->location->d.ia5);
415
416                         if (!data)
417                                 retValue = std::string();
418                         else
419                                 retValue = std::string(static_cast<char *>(data));
420
421                         break;
422                 }
423         }
424
425         sk_ACCESS_DESCRIPTION_free(aia);
426         return retValue;
427 }
428
429 Certificate::AltNameSet Certificate::getAlternativeName(int type) const
430 {
431         AltNameSet set;
432         GENERAL_NAME *namePart = NULL;
433         STACK_OF(GENERAL_NAME)* san =
434                 static_cast<STACK_OF(GENERAL_NAME) *>(
435                         X509_get_ext_d2i(m_x509, NID_subject_alt_name, NULL, NULL));
436
437         while (sk_GENERAL_NAME_num(san) > 0) {
438                 if ((namePart = sk_GENERAL_NAME_pop(san)) == NULL)
439                         VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
440                                                   "openssl sk_GENERAL_NAME_pop err.");
441
442                 if (type == namePart->type) {
443                         char *temp;
444
445                         switch (type) {
446                         case GEN_DNS:
447                                 temp = reinterpret_cast<char *>(ASN1_STRING_data(namePart->d.dNSName));
448                                 break;
449
450                         case GEN_URI:
451                                 temp = reinterpret_cast<char *>(ASN1_STRING_data(namePart->d.uniformResourceIdentifier));
452                                 break;
453
454                         default:
455                                 VcoreThrowMsg(Certificate::Exception::WrongParamError,
456                                                           "Not support alt name type : " << type);
457                         }
458
459                         if (!temp) {
460                                 set.insert(std::string());
461                         } else {
462                                 set.insert(std::string(temp));
463                                 LogDebug("FOUND AltName: " << temp);
464                         }
465                 } else {
466                         LogDebug("FOUND GEN TYPE ID: " << namePart->type);
467                 }
468         }
469
470         return set;
471 }
472
473 Certificate::AltNameSet Certificate::getAlternativeNameDNS() const
474 {
475         return getAlternativeName(GEN_DNS);
476 }
477
478 Certificate::AltNameSet Certificate::getAlternativeNameURI() const
479 {
480         return getAlternativeName(GEN_URI);
481 }
482
483 ASN1_TIME *Certificate::getNotAfterTime() const
484 {
485         auto timeafter = X509_get_notAfter(m_x509);
486
487         if (!timeafter)
488                 VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
489                                           "Reading Not After error.");
490
491         LogDebug("Get notAfter ASN1_TIME : " <<
492                          reinterpret_cast<char *>(timeafter->data));
493         return timeafter;
494 }
495
496 ASN1_TIME *Certificate::getNotBeforeTime() const
497 {
498         auto timebefore = X509_get_notBefore(m_x509);
499
500         if (!timebefore)
501                 VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
502                                           "Reading Not Before error.");
503
504         LogDebug("Get notBefore ASN1_TIME : " <<
505                          reinterpret_cast<char *>(timebefore->data));
506         return timebefore;
507 }
508
509 time_t Certificate::getNotAfter() const
510 {
511         auto time = getNotAfterTime();
512         time_t output;
513
514         if (asn1TimeToTimeT(time, &output) == 0)
515                 VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
516                                           "Converting ASN1_time to time_t error.");
517
518         return output;
519 }
520
521 time_t Certificate::getNotBefore() const
522 {
523         auto time = getNotBeforeTime();
524         time_t output;
525
526         if (asn1TimeToTimeT(time, &output) == 0)
527                 VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
528                                           "Converting ASN1_time to time_t error.");
529
530         return output;
531 }
532
533 bool Certificate::isRootCert()
534 {
535         // based on that root certificate has the same subject as issuer name
536         return isSignedBy(this->shared_from_this());
537 }
538
539 long Certificate::getVersion() const
540 {
541         return X509_get_version(m_x509);
542 }
543
544 std::string Certificate::getSerialNumberString() const
545 {
546         ASN1_INTEGER *ai = X509_get_serialNumber(m_x509);
547
548         if (!ai)
549                 VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
550                                           "Error in X509_get_serialNumber");
551
552         std::stringstream stream;
553         stream << std::hex << std::setfill('0');
554
555         if (ai->type == V_ASN1_NEG_INTEGER) {
556                 stream << "(Negetive) ";
557         }
558
559         for (int i = 0; i < ai->length; ++i) {
560                 stream << std::setw(2) << (int)ai->data[i] << ":";
561         }
562
563         std::string data = stream.str();
564
565         if (!data.empty()) {
566                 data.erase(--data.end());
567         }
568
569         return data;
570 }
571
572 std::string Certificate::getKeyUsageString() const
573 {
574         // Extensions were defined in RFC 3280
575         const char *usage[] = {
576                 "digitalSignature",
577                 "nonRepudiation",
578                 "keyEncipherment",
579                 "dataEncipherment",
580                 "keyAgreement",
581                 "keyCertSign",
582                 "cRLSign",
583                 "encipherOnly",
584                 "decipherOnly"
585         };
586         int crit = -1;
587         int idx = -1;
588         ASN1_BIT_STRING *keyUsage = (ASN1_BIT_STRING *)
589                                                                 X509_get_ext_d2i(m_x509, NID_key_usage, &crit, &idx);
590         std::stringstream stream;
591
592         for (int i = 0; i < 9; ++i) {
593                 if (ASN1_BIT_STRING_get_bit(keyUsage, i)) {
594                         stream << usage[i] << ",";
595                 }
596         }
597
598         std::string result = stream.str();
599
600         if (!result.empty()) {
601                 result.erase(--result.end());
602         }
603
604         return result;
605 }
606
607 std::string Certificate::getSignatureAlgorithmString() const
608 {
609         std::unique_ptr<BIO, std::function<int(BIO *)>>
610                         b(BIO_new(BIO_s_mem()), BIO_free);
611
612         if (!b.get())
613                 VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
614                                           "Error in BIO_new");
615
616         if (i2a_ASN1_OBJECT(b.get(), m_x509->cert_info->signature->algorithm) < 0)
617                 VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
618                                           "Error in i2a_ASN1_OBJECT");
619
620         BUF_MEM *bptr = 0;
621         BIO_get_mem_ptr(b.get(), &bptr);
622
623         if (bptr == 0)
624                 VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
625                                           "Error in BIO_get_mem_ptr");
626
627         std::string result(bptr->data, bptr->length);
628         return result;
629 }
630
631 std::string Certificate::getPublicKeyString() const
632 {
633         std::unique_ptr<BIO, std::function<int(BIO *)>>
634                         b(BIO_new(BIO_s_mem()), BIO_free);
635
636         if (!b.get())
637                 VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
638                                           "Error in BIO_new");
639
640         EVP_PKEY *pkey = X509_get_pubkey(m_x509);
641
642         if (!pkey)
643                 VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
644                                           "Error in X509_get_pubkey");
645
646         EVP_PKEY_print_public(b.get(), pkey, 16, NULL);
647         EVP_PKEY_free(pkey);
648         BUF_MEM *bptr = 0;
649         BIO_get_mem_ptr(b.get(), &bptr);
650
651         if (bptr == 0)
652                 VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
653                                           "Error in BIO_get_mem_ptr");
654
655         std::string result(bptr->data, bptr->length);
656         return result;
657 }
658
659 void Certificate::getPublicKeyDER(unsigned char **pubkey, size_t *len) const
660 {
661         if (pubkey == NULL || len == NULL)
662                 VcoreThrowMsg(Certificate::Exception::WrongParamError, "Wrong parameter");
663
664         EVP_PKEY *pkey = X509_get_pubkey(m_x509);
665         unsigned char *_pubkey = NULL;
666         int _len = i2d_PUBKEY(pkey, &_pubkey);
667         EVP_PKEY_free(pkey);
668
669         if (_pubkey == NULL || _len == 0)
670                 VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
671                                           "Error in i2d_PUBKEY");
672
673         *pubkey = _pubkey;
674         *len = static_cast<size_t>(_len);
675 }
676
677 std::string Certificate::getPublicKeyAlgoString() const
678 {
679         return std::string(static_cast<const char *>(
680                                                    OBJ_nid2ln(OBJ_obj2nid(m_x509->cert_info->key->algor->algorithm))));
681 }
682
683 int Certificate::isCA() const
684 {
685         return X509_check_ca(m_x509);
686 }
687
688 std::string Certificate::FingerprintToColonHex(
689         const Certificate::Fingerprint &fingerprint)
690 {
691         std::string outString;
692         char buff[8];
693
694         for (size_t i = 0; i < fingerprint.size(); ++i) {
695                 snprintf(buff,
696                                  sizeof(buff),
697                                  "%02X:",
698                                  static_cast<unsigned int>(fingerprint[i]));
699                 outString += buff;
700         }
701
702         // remove trailing ":"
703         outString.erase(outString.end() - 1);
704         return outString;
705 }
706
707 } //  namespace ValidationCore