diff --git a/src/vmime/security/cert/X509Certificate.hpp b/src/vmime/security/cert/X509Certificate.hpp index 215a86cf..90e26d1f 100644 --- a/src/vmime/security/cert/X509Certificate.hpp +++ b/src/vmime/security/cert/X509Certificate.hpp @@ -101,6 +101,13 @@ public: */ virtual const byteArray getSerialNumber() const = 0; + /** Returns the distinguished name of the issuer of this certificate. + * Eg. "C=US,O=VeriSign\, Inc.,OU=Class 1 Public Primary Certification Authority" + * + * @return distinguished name of the certificate issuer, as a string + */ + const string getIssuerString() const; + /** Checks if this certificate has the given issuer. * * @param issuer certificate of a possible issuer @@ -119,9 +126,13 @@ public: /** Verify certificate's subject name against the given hostname. * * @param hostname DNS name of the server + * @param nonMatchingNames if not NULL, will contain the names that do + * not match the identities in the certificate * @return true if the match is successful, false otherwise */ - virtual bool verifyHostName(const string& hostname) const = 0; + virtual bool verifyHostName + (const string& hostname, + std::vector * nonMatchingNames = NULL) const = 0; /** Gets the expiration date of this certificate. This is the date * at which this certificate will not be valid anymore. diff --git a/src/vmime/security/cert/gnutls/X509Certificate_GnuTLS.cpp b/src/vmime/security/cert/gnutls/X509Certificate_GnuTLS.cpp index f96ddddb..9e32b3dd 100644 --- a/src/vmime/security/cert/gnutls/X509Certificate_GnuTLS.cpp +++ b/src/vmime/security/cert/gnutls/X509Certificate_GnuTLS.cpp @@ -187,9 +187,36 @@ bool X509Certificate_GnuTLS::verify(shared_ptr caCert_) } -bool X509Certificate_GnuTLS::verifyHostName(const string& hostname) const +bool X509Certificate_GnuTLS::verifyHostName + (const string& hostname, std::vector * nonMatchingNames) const { - return gnutls_x509_crt_check_hostname(m_data->cert, hostname.c_str()) != 0; + if (gnutls_x509_crt_check_hostname(m_data->cert, hostname.c_str()) != 0) + return true; + + if (nonMatchingNames) + { + const int MAX_CN = 256; + const char* OID_X520_COMMON_NAME = "2.5.4.3"; + + char dnsName[MAX_CN]; + size_t dnsNameLength; + + dnsNameLength = sizeof(dnsName); + + if (gnutls_x509_crt_get_dn_by_oid(m_data->cert, OID_X520_COMMON_NAME, 0, 0, dnsName, &dnsNameLength) >= 0) + nonMatchingNames->push_back(dnsName); + + for (int i = 0, ret = 0 ; ret >= 0 ; ++i) + { + dnsNameLength = sizeof(dnsName); + ret = gnutls_x509_crt_get_subject_alt_name(m_data->cert, i, dnsName, &dnsNameLength, NULL); + + if (ret == GNUTLS_SAN_DNSNAME) + nonMatchingNames->push_back(dnsName); + } + } + + return false; } @@ -255,6 +282,18 @@ const byteArray X509Certificate_GnuTLS::getEncoded() const } +const string X509Certificate_GnuTLS::getIssuerString() const +{ + char buffer[4096]; + size_t bufferSize = sizeof(buffer); + + if (gnutls_x509_crt_get_issuer_dn(m_data->cert, buffer, &bufferSize) != GNUTLS_E_SUCCESS) + return ""; + + return buffer; +} + + const string X509Certificate_GnuTLS::getType() const { return "X.509"; diff --git a/src/vmime/security/cert/gnutls/X509Certificate_GnuTLS.hpp b/src/vmime/security/cert/gnutls/X509Certificate_GnuTLS.hpp index 76ee6d4d..d7d72338 100644 --- a/src/vmime/security/cert/gnutls/X509Certificate_GnuTLS.hpp +++ b/src/vmime/security/cert/gnutls/X509Certificate_GnuTLS.hpp @@ -56,11 +56,14 @@ public: const byteArray getSerialNumber() const; + const string getIssuerString() const; bool checkIssuer(shared_ptr issuer) const; bool verify(shared_ptr caCert) const; - bool verifyHostName(const string& hostname) const; + bool verifyHostName + (const string& hostname, + std::vector * nonMatchingNames = NULL) const; const datetime getExpirationDate() const; const datetime getActivationDate() const; diff --git a/src/vmime/security/cert/openssl/X509Certificate_OpenSSL.cpp b/src/vmime/security/cert/openssl/X509Certificate_OpenSSL.cpp index 5f81b2bf..737bcb2e 100644 --- a/src/vmime/security/cert/openssl/X509Certificate_OpenSSL.cpp +++ b/src/vmime/security/cert/openssl/X509Certificate_OpenSSL.cpp @@ -362,7 +362,8 @@ bool X509Certificate_OpenSSL::cnMatch(const char* cnBuf, const char* host) } -bool X509Certificate_OpenSSL::verifyHostName(const string& hostname) const +bool X509Certificate_OpenSSL::verifyHostName + (const string& hostname, std::vector * nonMatchingNames) const { // First, check subject common name against hostname char CNBuffer[1024]; @@ -374,6 +375,9 @@ bool X509Certificate_OpenSSL::verifyHostName(const string& hostname) const { if (cnMatch(CNBuffer, hostname.c_str())) return true; + + if (nonMatchingNames) + nonMatchingNames->push_back(CNBuffer); } // Now, look in subject alternative names @@ -422,6 +426,9 @@ bool X509Certificate_OpenSSL::verifyHostName(const string& hostname) const { return true; } + + if (nonMatchingNames) + nonMatchingNames->push_back(cnf->value); } } } @@ -538,6 +545,22 @@ const byteArray X509Certificate_OpenSSL::getEncoded() const } +const string X509Certificate_OpenSSL::getIssuerString() const +{ + // Get issuer for this cert + BIO* out = BIO_new(BIO_s_mem()); + X509_NAME_print_ex(out, X509_get_issuer_name(m_data->cert), 0, XN_FLAG_RFC2253); + + unsigned char* issuer; + const int n = BIO_get_mem_data(out, &issuer); + + vmime::string name(reinterpret_cast (issuer), n); + BIO_free(out); + + return name; +} + + const string X509Certificate_OpenSSL::getType() const { return "X.509"; diff --git a/src/vmime/security/cert/openssl/X509Certificate_OpenSSL.hpp b/src/vmime/security/cert/openssl/X509Certificate_OpenSSL.hpp index bddb4b6c..dbb1b03c 100644 --- a/src/vmime/security/cert/openssl/X509Certificate_OpenSSL.hpp +++ b/src/vmime/security/cert/openssl/X509Certificate_OpenSSL.hpp @@ -59,11 +59,14 @@ public: const byteArray getSerialNumber() const; + const string getIssuerString() const; bool checkIssuer(shared_ptr issuer) const; bool verify(shared_ptr caCert) const; - bool verifyHostName(const string& hostname) const; + bool verifyHostName + (const string& hostname, + std::vector * nonMatchingNames = NULL) const; const datetime getExpirationDate() const; const datetime getActivationDate() const;