#pragma once
-#include <map>
#include <string>
#include "iohook.h"
return revoked;
}
+ /** Get certificate usability
+ * @return True if the certificate is not expired nor revoked
+ */
+ bool IsUsable()
+ {
+ return !invalid && !revoked && error.empty();
+ }
+
+ /** Get CA trust status
+ * @return True if the certificate is issued by a CA
+ * and valid.
+ */
bool IsCAVerified()
{
- return trusted && !invalid && !revoked && !unknownsigner && error.empty();
+ return IsUsable() && trusted && !unknownsigner;
}
std::string GetMetaLine()
class SSLIOHook : public IOHook
{
+ protected:
+ /** Peer SSL certificate, set by the SSL module
+ */
+ reference<ssl_cert> certificate;
+
+ /** Reduce elements in a send queue by appending later elements to the first element until there are no more
+ * elements to append or a desired length is reached
+ * @param sendq SendQ to work on
+ * @param targetsize Target size of the front element
+ */
+ static void FlattenSendQueue(StreamSocket::SendQueue& sendq, size_t targetsize)
+ {
+ if ((sendq.size() <= 1) || (sendq.front().length() >= targetsize))
+ return;
+
+ // Avoid multiple repeated SSL encryption invocations
+ // This adds a single copy of the queue, but avoids
+ // much more overhead in terms of system calls invoked
+ // by an IOHook.
+ std::string tmp;
+ tmp.reserve(std::min(targetsize, sendq.bytes())+1);
+ do
+ {
+ tmp.append(sendq.front());
+ sendq.pop_front();
+ }
+ while (!sendq.empty() && tmp.length() < targetsize);
+ sendq.push_front(tmp);
+ }
+
public:
- SSLIOHook(Module* mod, const std::string& Name)
- : IOHook(mod, Name, IOHook::IOH_SSL)
+ static SSLIOHook* IsSSL(StreamSocket* sock)
+ {
+ IOHook* const iohook = sock->GetIOHook();
+ if ((iohook) && ((iohook->prov->type == IOHookProvider::IOH_SSL)))
+ return static_cast<SSLIOHook*>(iohook);
+ return NULL;
+ }
+
+ SSLIOHook(IOHookProvider* hookprov)
+ : IOHook(hookprov)
{
}
/**
- * Get the client certificate from a socket
- * @param sock The socket to get the certificate from, must be using this IOHook
- * @return The SSL client certificate information
+ * Get the certificate sent by this peer
+ * @return The SSL certificate sent by the peer, NULL if no cert was sent
*/
- virtual ssl_cert* GetCertificate(StreamSocket* sock) = 0;
+ ssl_cert* GetCertificate() const
+ {
+ if (certificate && certificate->IsUsable())
+ return certificate;
+ return NULL;
+ }
/**
- * Get the fingerprint of a client certificate from a socket
- * @param sock The socket to get the certificate fingerprint from, must be using this IOHook
+ * Get the fingerprint of the peer's certificate
* @return The fingerprint of the SSL client certificate sent by the peer,
* empty if no cert was sent
*/
- std::string GetFingerprint(StreamSocket* sock)
+ std::string GetFingerprint() const
{
- ssl_cert* cert = GetCertificate(sock);
+ ssl_cert* cert = GetCertificate();
if (cert)
return cert->GetFingerprint();
return "";
}
+
+ /**
+ * Get the ciphersuite negotiated with the peer
+ * @param out String where the ciphersuite string will be appended to
+ */
+ virtual void GetCiphersuite(std::string& out) const = 0;
+
+
+ /** Retrieves the name of the SSL connection which is sent via SNI.
+ * @param out String that the server name will be appended to.
+ * returns True if the server name was retrieved; otherwise, false.
+ */
+ virtual bool GetServerName(std::string& out) const = 0;
};
/** Helper functions for obtaining SSL client certificates and key fingerprints
*/
static ssl_cert* GetCertificate(StreamSocket* sock)
{
- IOHook* iohook = sock->GetIOHook();
- if ((!iohook) || (iohook->type != IOHook::IOH_SSL))
+ SSLIOHook* ssliohook = SSLIOHook::IsSSL(sock);
+ if (!ssliohook)
return NULL;
- SSLIOHook* ssliohook = static_cast<SSLIOHook*>(iohook);
- return ssliohook->GetCertificate(sock);
+ return ssliohook->GetCertificate();
}
/**
}
};
-/** Get certificate from a user (requires m_sslinfo) */
-struct UserCertificateRequest : public Request
+class UserCertificateAPIBase : public DataProvider
{
- User* const user;
- ssl_cert* cert;
-
- UserCertificateRequest(User* u, Module* Me, Module* info = ServerInstance->Modules->Find("m_sslinfo.so"))
- : Request(Me, info, "GET_USER_CERT"), user(u), cert(NULL)
+ public:
+ UserCertificateAPIBase(Module* parent)
+ : DataProvider(parent, "m_sslinfo_api")
{
- Send();
}
- std::string GetFingerprint()
+ /** Get the SSL certificate of a user
+ * @param user The user whose certificate to get, user may be remote
+ * @return The SSL certificate of the user or NULL if the user is not using SSL
+ */
+ virtual ssl_cert* GetCertificate(User* user) = 0;
+
+ /** Get the key fingerprint from a user's certificate
+ * @param user The user whose key fingerprint to get, user may be remote
+ * @return The key fingerprint from the user's SSL certificate or an empty string
+ * if the user is not using SSL or did not provide a client certificate
+ */
+ std::string GetFingerprint(User* user)
{
+ ssl_cert* cert = GetCertificate(user);
if (cert)
return cert->GetFingerprint();
return "";
}
};
+
+/** API implemented by m_sslinfo that allows modules to retrive the SSL certificate
+ * information of local and remote users. It can also be used to find out whether a
+ * user is using SSL or not.
+ */
+class UserCertificateAPI : public dynamic_reference<UserCertificateAPIBase>
+{
+ public:
+ UserCertificateAPI(Module* parent)
+ : dynamic_reference<UserCertificateAPIBase>(parent, "m_sslinfo_api")
+ {
+ }
+};