// // VMime library (http://www.vmime.org) // Copyright (C) 2002-2005 Vincent Richard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of // the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // General Public License for more details. // // You should have received a copy of the GNU General Public License along // with this program; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // // Linking this library statically or dynamically with other modules is making // a combined work based on this library. Thus, the terms and conditions of // the GNU General Public License cover the whole combination. // #include #include #include #include "vmime/security/cert/X509Certificate.hpp" namespace vmime { namespace security { namespace cert { #ifndef VMIME_BUILDING_DOC struct X509CertificateInternalData { X509CertificateInternalData() { gnutls_x509_crt_init(&cert); } ~X509CertificateInternalData() { gnutls_x509_crt_deinit(cert); } gnutls_x509_crt cert; }; #endif // VMIME_BUILDING_DOC X509Certificate::X509Certificate() : m_data(new X509CertificateInternalData) { } X509Certificate::X509Certificate(const X509Certificate&) : certificate(), m_data(NULL) { // Not used } X509Certificate::~X509Certificate() { delete m_data; } // static ref X509Certificate::import(utility::inputStream& is) { byteArray bytes; utility::stream::value_type chunk[4096]; while (!is.eof()) { const int len = is.read(chunk, sizeof(chunk)); bytes.insert(bytes.end(), chunk, chunk + len); } return import(&bytes[0], bytes.size()); } // static ref X509Certificate::import (const byte* data, const unsigned int length) { ref cert = vmime::create (); gnutls_datum buffer; buffer.data = const_cast (data); buffer.size = length; // Try DER format if (gnutls_x509_crt_import(cert->m_data->cert, &buffer, GNUTLS_X509_FMT_DER) >= 0) return cert; // Try PEM format if (gnutls_x509_crt_import(cert->m_data->cert, &buffer, GNUTLS_X509_FMT_PEM) >= 0) return cert; return NULL; } void X509Certificate::write (utility::outputStream& os, const Format format) const { size_t dataSize = 0; gnutls_x509_crt_fmt fmt = GNUTLS_X509_FMT_DER; switch (format) { case FORMAT_DER: fmt = GNUTLS_X509_FMT_DER; break; case FORMAT_PEM: fmt = GNUTLS_X509_FMT_PEM; break; } gnutls_x509_crt_export(m_data->cert, fmt, NULL, &dataSize); byte* data = new byte[dataSize]; gnutls_x509_crt_export(m_data->cert, fmt, data, &dataSize); try { os.write(reinterpret_cast (data), dataSize); } catch (...) { delete [] data; throw; } } const byteArray X509Certificate::getSerialNumber() const { char serial[64]; size_t serialSize = sizeof(serial); gnutls_x509_crt_get_serial(m_data->cert, serial, &serialSize); return byteArray(serial, serial + serialSize); } const bool X509Certificate::checkIssuer (ref issuer) const { return (gnutls_x509_crt_check_issuer (m_data->cert, issuer->m_data->cert) >= 1); } const bool X509Certificate::verify(ref caCert) const { unsigned int verify = 0; const int res = gnutls_x509_crt_verify (m_data->cert, &(caCert->m_data->cert), 1, GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT, &verify); return (res == 0 && verify == 0); } const datetime X509Certificate::getActivationDate() const { const time_t t = gnutls_x509_crt_get_activation_time(m_data->cert); return datetime(t); } const datetime X509Certificate::getExpirationDate() const { const time_t t = gnutls_x509_crt_get_expiration_time(m_data->cert); return datetime(t); } const byteArray X509Certificate::getFingerprint(const DigestAlgorithm algo) const { gnutls_digest_algorithm galgo; switch (algo) { case DIGEST_MD5: galgo = GNUTLS_DIG_MD5; break; default: case DIGEST_SHA1: galgo = GNUTLS_DIG_SHA; break; } size_t bufferSize = 0; gnutls_x509_crt_get_fingerprint (m_data->cert, galgo, NULL, &bufferSize); byte* buffer = new byte[bufferSize]; if (gnutls_x509_crt_get_fingerprint (m_data->cert, galgo, buffer, &bufferSize) == 0) { byteArray res; res.insert(res.end(), buffer, buffer + bufferSize); delete [] buffer; return res; } delete [] buffer; return byteArray(); } const byteArray X509Certificate::getEncoded() const { byteArray bytes; utility::outputStreamByteArrayAdapter os(bytes); write(os, FORMAT_DER); return bytes; } const string X509Certificate::getType() const { return "X.509"; } const int X509Certificate::getVersion() const { return gnutls_x509_crt_get_version(m_data->cert); } const bool X509Certificate::equals(ref other) const { ref otherX509 = other.dynamicCast (); if (!otherX509) return false; const byteArray fp1 = getFingerprint(DIGEST_MD5); const byteArray fp2 = otherX509->getFingerprint(DIGEST_MD5); return fp1 == fp2; } } // cert } // security } // vmime