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