2 * Copyright (c) 2016 - 2017 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 Certificate.cpp
18 * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com)
20 * @brief Certificate class implementation
23 #include <sys/types.h>
31 #include <openssl/pem.h>
32 #include <openssl/x509.h>
33 #include <openssl/x509v3.h>
34 #include <openssl/objects.h>
36 #include <dpl/log/log.h>
38 #include "vcore/Base64.h"
39 #include "vcore/TimeConversion.h"
41 #include "vcore/Certificate.h"
45 typedef std::unique_ptr<X509, std::function<void(X509 *)>> ScopedX509;
46 typedef std::unique_ptr<FILE, std::function<int(FILE *)>> ScopedFile;
48 } // namespace anonymous
50 namespace ValidationCore {
52 Certificate::Certificate(X509 *cert)
55 VcoreThrowMsg(Certificate::Exception::WrongParamError,
56 "Input X509 shouldn't be NULL.");
58 m_x509 = X509_dup(cert);
61 VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
62 "Internal Openssl error in d2i_X509 function.");
65 Certificate::Certificate(const std::string &data,
66 Certificate::FormType form)
69 VcoreThrowMsg(Certificate::Exception::WrongParamError,
70 "Input data shouldn't be empty");
73 const unsigned char *ptr;
74 std::string tmp = data;
76 // transform to DER format
77 if (FORM_BASE64 == form) {
83 if (!base64.finalize()) {
84 LogWarning("Error during decoding");
88 } catch (const Base64Decoder::Exception::Base &e) {
89 LogError("Exception in Certificate constructor : " << e.DumpToString());
90 VcoreThrowMsg(Certificate::Exception::Base64Error, "Failed to Base64Decoder");
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);
99 VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
100 "Internal Openssl error in d2i_X509 function.");
103 static int getFileSize(const std::string &location, off_t &size)
106 int ret = stat(location.c_str(), &status);
107 size = status.st_size;
111 CertificatePtr Certificate::createFromFile(const std::string &location)
115 fp = fopen(location.c_str(), "rb");
118 VcoreThrowMsg(Certificate::Exception::WrongParamError,
119 "File cannot be opened : " << location);
121 ScopedFile filePtr(fp, fclose);
122 x509 = PEM_read_X509(fp, NULL, NULL, NULL);
126 x509 = PEM_read_X509_AUX(fp, NULL, NULL, NULL);
130 ScopedX509 x509Ptr(x509, X509_free);
131 return CertificatePtr(new Certificate(x509));
135 if(getFileSize(location, filesize) != 0)
136 VcoreThrowMsg(Certificate::Exception::WrongParamError,
137 "Fail to get file size. : " << location);
139 VcoreThrowMsg(Certificate::Exception::WrongParamError,
140 "File content is empty : " << location);
142 std::unique_ptr<unsigned char[]> content(new unsigned char[filesize + 1]);
144 VcoreThrowMsg(Certificate::Exception::InternalError,
145 "Fail to allocate memory.");
147 memset(content.get(), 0x00, filesize + 1);
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);
154 content[filesize] = '\0';
155 const unsigned char *ptr = reinterpret_cast<const unsigned char *>(content.get());
156 x509 = d2i_X509(NULL, &ptr, filesize);
159 VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
160 "Internal Openssl error in d2i_X509 function.");
162 return CertificatePtr(new Certificate(x509));
165 Certificate::~Certificate()
170 X509 *Certificate::getX509(void) const
175 std::string Certificate::getDER(void) const
177 unsigned char *rawDer = NULL;
178 int size = i2d_X509(m_x509, &rawDer);
180 if (!rawDer || size <= 0)
181 VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
184 std::string output(reinterpret_cast<char *>(rawDer), size);
185 OPENSSL_free(rawDer);
189 std::string Certificate::getBase64(void) const
191 Base64Encoder base64;
195 base64.append(getDER());
197 } catch (const Base64Encoder::Exception::Base &e) {
198 LogError("Exception in Certificate getBase64 : " << e.DumpToString());
199 VcoreThrowMsg(Certificate::Exception::Base64Error, "Failed to Base64Encoder");
205 bool Certificate::isSignedBy(const CertificatePtr &parent) const
208 LogDebug("Invalid certificate parameter.");
212 return 0 == X509_NAME_cmp(X509_get_subject_name(parent->m_x509),
213 X509_get_issuer_name(m_x509));
216 Certificate::Fingerprint Certificate::getFingerprint(
217 Certificate::FingerprintType type) const
219 unsigned int fingerprintlength = EVP_MAX_MD_SIZE;
220 unsigned char fingerprint[EVP_MAX_MD_SIZE];
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!");
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");
235 raw.resize(fingerprintlength); // improve performance
236 std::copy(fingerprint, fingerprint + fingerprintlength, raw.begin());
240 X509_NAME *Certificate::getX509Name(FieldType type) const
242 X509_NAME *name = NULL;
246 name = X509_get_issuer_name(m_x509);
250 name = X509_get_subject_name(m_x509);
254 VcoreThrowMsg(Certificate::Exception::WrongParamError,
255 "Invalid field type param. type : " << type);
259 VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
260 "Error during x509 name extraction.");
265 std::string Certificate::getOneLine(FieldType type) const
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);
274 std::string Certificate::getField(FieldType type, int fieldNid) const
276 X509_NAME *subjectName = getX509Name(type);
277 X509_NAME_ENTRY *subjectEntry = NULL;
279 int entryCount = X509_NAME_entry_count(subjectName);
281 for (int i = 0; i < entryCount; ++i) {
282 subjectEntry = X509_NAME_get_entry(subjectName,
289 int nid = OBJ_obj2nid(
290 static_cast<ASN1_OBJECT *>(
291 X509_NAME_ENTRY_get_object(subjectEntry)));
293 if (nid != fieldNid) {
297 ASN1_STRING *pASN1Str = subjectEntry->value;
298 unsigned char *pData = NULL;
299 int nLength = ASN1_STRING_to_UTF8(&pData,
303 VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
304 "Reading field error.");
307 output = std::string();
309 output = std::string(reinterpret_cast<char *>(pData), nLength);
317 std::string Certificate::getCommonName(FieldType type) const
319 return getField(type, NID_commonName);
322 std::string Certificate::getCountryName(FieldType type) const
324 return getField(type, NID_countryName);
327 std::string Certificate::getStateOrProvinceName(FieldType type) const
329 return getField(type, NID_stateOrProvinceName);
332 std::string Certificate::getLocalityName(FieldType type) const
334 return getField(type, NID_localityName);
337 std::string Certificate::getOrganizationName(FieldType type) const
339 return getField(type, NID_organizationName);
342 std::string Certificate::getOrganizationalUnitName(FieldType type) const
344 return getField(type, NID_organizationalUnitName);
347 std::string Certificate::getEmailAddres(FieldType type) const
349 return getField(type, NID_pkcs9_emailAddress);
352 std::string Certificate::getNameHash(FieldType type) const
354 unsigned long ulNameHash;
357 if (type == FIELD_SUBJECT)
358 ulNameHash = X509_subject_name_hash(m_x509);
360 ulNameHash = X509_issuer_name_hash(m_x509);
362 snprintf(buf, 9, "%08lx", ulNameHash);
363 return std::string(buf);
366 std::string Certificate::getUID(FieldType type) const
368 ASN1_BIT_STRING *uid = NULL;
370 if (type == FIELD_SUBJECT)
371 uid = m_x509->cert_info->subjectUID;
373 uid = m_x509->cert_info->issuerUID;
375 if (uid->data == NULL)
376 return std::string();
378 char *temp = new char[uid->length + 1];
381 LogError("Fail to allocate memory.");
382 return std::string();
385 memcpy(temp, uid->data, uid->length);
386 temp[uid->length] = 0;
387 std::string uidStr(temp);
392 std::string Certificate::getOCSPURL() const
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,
402 // no AIA extension in the cert
407 int count = sk_ACCESS_DESCRIPTION_num(aia);
409 for (int i = 0; i < count; ++i) {
410 ACCESS_DESCRIPTION *ad = sk_ACCESS_DESCRIPTION_value(aia, i);
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);
417 retValue = std::string();
419 retValue = std::string(static_cast<char *>(data));
425 sk_ACCESS_DESCRIPTION_free(aia);
429 Certificate::AltNameSet Certificate::getAlternativeName(int type) const
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));
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.");
442 if (type == namePart->type) {
447 temp = reinterpret_cast<char *>(ASN1_STRING_data(namePart->d.dNSName));
451 temp = reinterpret_cast<char *>(ASN1_STRING_data(namePart->d.uniformResourceIdentifier));
455 VcoreThrowMsg(Certificate::Exception::WrongParamError,
456 "Not support alt name type : " << type);
460 set.insert(std::string());
462 set.insert(std::string(temp));
463 LogDebug("FOUND AltName: " << temp);
466 LogDebug("FOUND GEN TYPE ID: " << namePart->type);
473 Certificate::AltNameSet Certificate::getAlternativeNameDNS() const
475 return getAlternativeName(GEN_DNS);
478 Certificate::AltNameSet Certificate::getAlternativeNameURI() const
480 return getAlternativeName(GEN_URI);
483 ASN1_TIME *Certificate::getNotAfterTime() const
485 auto timeafter = X509_get_notAfter(m_x509);
488 VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
489 "Reading Not After error.");
491 LogDebug("Get notAfter ASN1_TIME : " <<
492 reinterpret_cast<char *>(timeafter->data));
496 ASN1_TIME *Certificate::getNotBeforeTime() const
498 auto timebefore = X509_get_notBefore(m_x509);
501 VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
502 "Reading Not Before error.");
504 LogDebug("Get notBefore ASN1_TIME : " <<
505 reinterpret_cast<char *>(timebefore->data));
509 time_t Certificate::getNotAfter() const
511 auto time = getNotAfterTime();
514 if (asn1TimeToTimeT(time, &output) == 0)
515 VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
516 "Converting ASN1_time to time_t error.");
521 time_t Certificate::getNotBefore() const
523 auto time = getNotBeforeTime();
526 if (asn1TimeToTimeT(time, &output) == 0)
527 VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
528 "Converting ASN1_time to time_t error.");
533 bool Certificate::isRootCert()
535 // based on that root certificate has the same subject as issuer name
536 return isSignedBy(this->shared_from_this());
539 long Certificate::getVersion() const
541 return X509_get_version(m_x509);
544 std::string Certificate::getSerialNumberString() const
546 ASN1_INTEGER *ai = X509_get_serialNumber(m_x509);
549 VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
550 "Error in X509_get_serialNumber");
552 std::stringstream stream;
553 stream << std::hex << std::setfill('0');
555 if (ai->type == V_ASN1_NEG_INTEGER) {
556 stream << "(Negetive) ";
559 for (int i = 0; i < ai->length; ++i) {
560 stream << std::setw(2) << (int)ai->data[i] << ":";
563 std::string data = stream.str();
566 data.erase(--data.end());
572 std::string Certificate::getKeyUsageString() const
574 // Extensions were defined in RFC 3280
575 const char *usage[] = {
588 ASN1_BIT_STRING *keyUsage = (ASN1_BIT_STRING *)
589 X509_get_ext_d2i(m_x509, NID_key_usage, &crit, &idx);
590 std::stringstream stream;
592 for (int i = 0; i < 9; ++i) {
593 if (ASN1_BIT_STRING_get_bit(keyUsage, i)) {
594 stream << usage[i] << ",";
598 std::string result = stream.str();
600 if (!result.empty()) {
601 result.erase(--result.end());
607 std::string Certificate::getSignatureAlgorithmString() const
609 std::unique_ptr<BIO, std::function<int(BIO *)>>
610 b(BIO_new(BIO_s_mem()), BIO_free);
613 VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
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");
621 BIO_get_mem_ptr(b.get(), &bptr);
624 VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
625 "Error in BIO_get_mem_ptr");
627 std::string result(bptr->data, bptr->length);
631 std::string Certificate::getPublicKeyString() const
633 std::unique_ptr<BIO, std::function<int(BIO *)>>
634 b(BIO_new(BIO_s_mem()), BIO_free);
637 VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
640 EVP_PKEY *pkey = X509_get_pubkey(m_x509);
643 VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
644 "Error in X509_get_pubkey");
646 EVP_PKEY_print_public(b.get(), pkey, 16, NULL);
649 BIO_get_mem_ptr(b.get(), &bptr);
652 VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
653 "Error in BIO_get_mem_ptr");
655 std::string result(bptr->data, bptr->length);
659 void Certificate::getPublicKeyDER(unsigned char **pubkey, size_t *len) const
661 if (pubkey == NULL || len == NULL)
662 VcoreThrowMsg(Certificate::Exception::WrongParamError, "Wrong parameter");
664 EVP_PKEY *pkey = X509_get_pubkey(m_x509);
665 unsigned char *_pubkey = NULL;
666 int _len = i2d_PUBKEY(pkey, &_pubkey);
669 if (_pubkey == NULL || _len == 0)
670 VcoreThrowMsg(Certificate::Exception::OpensslInternalError,
671 "Error in i2d_PUBKEY");
674 *len = static_cast<size_t>(_len);
677 std::string Certificate::getPublicKeyAlgoString() const
679 return std::string(static_cast<const char *>(
680 OBJ_nid2ln(OBJ_obj2nid(m_x509->cert_info->key->algor->algorithm))));
683 int Certificate::isCA() const
685 return X509_check_ca(m_x509);
688 std::string Certificate::FingerprintToColonHex(
689 const Certificate::Fingerprint &fingerprint)
691 std::string outString;
694 for (size_t i = 0; i < fingerprint.size(); ++i) {
698 static_cast<unsigned int>(fingerprint[i]));
702 // remove trailing ":"
703 outString.erase(outString.end() - 1);
707 } // namespace ValidationCore