]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - include/modules/ssl.h
Expand searching in m_httpd_stats, add global handling of GET parameters (#1566)
[user/henk/code/inspircd.git] / include / modules / ssl.h
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
5  *   Copyright (C) 2006 Craig Edwards <craigedwards@brainbox.cc>
6  *
7  * This file is part of InspIRCd.  InspIRCd is free software: you can
8  * redistribute it and/or modify it under the terms of the GNU General Public
9  * License as published by the Free Software Foundation, version 2.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
14  * details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20
21 #pragma once
22
23 #include <string>
24 #include "iohook.h"
25
26 /** ssl_cert is a class which abstracts SSL certificate
27  * and key information.
28  *
29  * Because gnutls and openssl represent key information in
30  * wildly different ways, this class allows it to be accessed
31  * in a unified manner. These classes are attached to ssl-
32  * connected local users using SSLCertExt
33  */
34 class ssl_cert : public refcountbase
35 {
36  public:
37         std::string dn;
38         std::string issuer;
39         std::string error;
40         std::string fingerprint;
41         bool trusted, invalid, unknownsigner, revoked;
42
43         ssl_cert() : trusted(false), invalid(true), unknownsigner(true), revoked(false) {}
44
45         /** Get certificate distinguished name
46          * @return Certificate DN
47          */
48         const std::string& GetDN()
49         {
50                 return dn;
51         }
52
53         /** Get Certificate issuer
54          * @return Certificate issuer
55          */
56         const std::string& GetIssuer()
57         {
58                 return issuer;
59         }
60
61         /** Get error string if an error has occured
62          * @return The error associated with this users certificate,
63          * or an empty string if there is no error.
64          */
65         const std::string& GetError()
66         {
67                 return error;
68         }
69
70         /** Get key fingerprint.
71          * @return The key fingerprint as a hex string.
72          */
73         const std::string& GetFingerprint()
74         {
75                 return fingerprint;
76         }
77
78         /** Get trust status
79          * @return True if this is a trusted certificate
80          * (the certificate chain validates)
81          */
82         bool IsTrusted()
83         {
84                 return trusted;
85         }
86
87         /** Get validity status
88          * @return True if the certificate itself is
89          * correctly formed.
90          */
91         bool IsInvalid()
92         {
93                 return invalid;
94         }
95
96         /** Get signer status
97          * @return True if the certificate appears to be
98          * self-signed.
99          */
100         bool IsUnknownSigner()
101         {
102                 return unknownsigner;
103         }
104
105         /** Get revokation status.
106          * @return True if the certificate is revoked.
107          * Note that this only works properly for GnuTLS
108          * right now.
109          */
110         bool IsRevoked()
111         {
112                 return revoked;
113         }
114
115         /** Get certificate usability
116         * @return True if the certificate is not expired nor revoked
117         */
118         bool IsUsable()
119         {
120                 return !invalid && !revoked && error.empty();
121         }
122
123         /** Get CA trust status
124         * @return True if the certificate is issued by a CA
125         * and valid.
126         */
127         bool IsCAVerified()
128         {
129                 return IsUsable() && trusted && !unknownsigner;
130         }
131
132         std::string GetMetaLine()
133         {
134                 std::stringstream value;
135                 bool hasError = !error.empty();
136                 value << (IsInvalid() ? "v" : "V") << (IsTrusted() ? "T" : "t") << (IsRevoked() ? "R" : "r")
137                         << (IsUnknownSigner() ? "s" : "S") << (hasError ? "E" : "e") << " ";
138                 if (hasError)
139                         value << GetError();
140                 else
141                         value << GetFingerprint() << " " << GetDN() << " " << GetIssuer();
142                 return value.str();
143         }
144 };
145
146 class SSLIOHook : public IOHook
147 {
148  protected:
149         /** Peer SSL certificate, set by the SSL module
150          */
151         reference<ssl_cert> certificate;
152
153         /** Reduce elements in a send queue by appending later elements to the first element until there are no more
154          * elements to append or a desired length is reached
155          * @param sendq SendQ to work on
156          * @param targetsize Target size of the front element
157          */
158         static void FlattenSendQueue(StreamSocket::SendQueue& sendq, size_t targetsize)
159         {
160                 if ((sendq.size() <= 1) || (sendq.front().length() >= targetsize))
161                         return;
162
163                 // Avoid multiple repeated SSL encryption invocations
164                 // This adds a single copy of the queue, but avoids
165                 // much more overhead in terms of system calls invoked
166                 // by an IOHook.
167                 std::string tmp;
168                 tmp.reserve(std::min(targetsize, sendq.bytes())+1);
169                 do
170                 {
171                         tmp.append(sendq.front());
172                         sendq.pop_front();
173                 }
174                 while (!sendq.empty() && tmp.length() < targetsize);
175                 sendq.push_front(tmp);
176         }
177
178  public:
179         static SSLIOHook* IsSSL(StreamSocket* sock)
180         {
181                 IOHook* const iohook = sock->GetIOHook();
182                 if ((iohook) && ((iohook->prov->type == IOHookProvider::IOH_SSL)))
183                         return static_cast<SSLIOHook*>(iohook);
184                 return NULL;
185         }
186
187         SSLIOHook(IOHookProvider* hookprov)
188                 : IOHook(hookprov)
189         {
190         }
191
192         /**
193          * Get the certificate sent by this peer
194          * @return The SSL certificate sent by the peer, NULL if no cert was sent
195          */
196         ssl_cert* GetCertificate() const
197         {
198                 return certificate;
199         }
200
201         /**
202          * Get the fingerprint of the peer's certificate
203          * @return The fingerprint of the SSL client certificate sent by the peer,
204          * empty if no cert was sent
205          */
206         std::string GetFingerprint() const
207         {
208                 ssl_cert* cert = GetCertificate();
209                 if (cert && cert->IsUsable())
210                         return cert->GetFingerprint();
211                 return "";
212         }
213
214         /**
215          * Get the ciphersuite negotiated with the peer
216          * @param out String where the ciphersuite string will be appended to
217          */
218         virtual void GetCiphersuite(std::string& out) const = 0;
219
220
221         /** Retrieves the name of the SSL connection which is sent via SNI.
222          * @param out String that the server name will be appended to.
223          * returns True if the server name was retrieved; otherwise, false.
224          */
225         virtual bool GetServerName(std::string& out) const = 0;
226 };
227
228 /** Helper functions for obtaining SSL client certificates and key fingerprints
229  * from StreamSockets
230  */
231 class SSLClientCert
232 {
233  public:
234         /**
235          * Get the client certificate from a socket
236          * @param sock The socket to get the certificate from, the socket does not have to use SSL
237          * @return The SSL client certificate information, NULL if the peer is not using SSL
238          */
239         static ssl_cert* GetCertificate(StreamSocket* sock)
240         {
241                 SSLIOHook* ssliohook = SSLIOHook::IsSSL(sock);
242                 if (!ssliohook)
243                         return NULL;
244
245                 return ssliohook->GetCertificate();
246         }
247
248         /**
249          * Get the fingerprint of a client certificate from a socket
250          * @param sock The socket to get the certificate fingerprint from, the
251          * socket does not have to use SSL
252          * @return The key fingerprint from the SSL certificate sent by the peer,
253          * empty if no cert was sent or the peer is not using SSL
254          */
255         static std::string GetFingerprint(StreamSocket* sock)
256         {
257                 ssl_cert* cert = SSLClientCert::GetCertificate(sock);
258                 if (cert)
259                         return cert->GetFingerprint();
260                 return "";
261         }
262 };
263
264 class UserCertificateAPIBase : public DataProvider
265 {
266  public:
267         UserCertificateAPIBase(Module* parent)
268                 : DataProvider(parent, "m_sslinfo_api")
269         {
270         }
271
272         /** Get the SSL certificate of a user
273          * @param user The user whose certificate to get, user may be remote
274          * @return The SSL certificate of the user or NULL if the user is not using SSL
275          */
276         virtual ssl_cert* GetCertificate(User* user) = 0;
277
278         /** Set the SSL certificate of a user.
279          * @param user The user whose certificate to set.
280          * @param cert The SSL certificate to set for the user.
281          */
282         virtual void SetCertificate(User* user, ssl_cert* cert) = 0;
283
284         /** Get the key fingerprint from a user's certificate
285          * @param user The user whose key fingerprint to get, user may be remote
286          * @return The key fingerprint from the user's SSL certificate or an empty string
287          * if the user is not using SSL or did not provide a client certificate
288          */
289         std::string GetFingerprint(User* user)
290         {
291                 ssl_cert* cert = GetCertificate(user);
292                 if (cert)
293                         return cert->GetFingerprint();
294                 return "";
295         }
296 };
297
298 /** API implemented by m_sslinfo that allows modules to retrive the SSL certificate
299  * information of local and remote users. It can also be used to find out whether a
300  * user is using SSL or not.
301  */
302 class UserCertificateAPI : public dynamic_reference<UserCertificateAPIBase>
303 {
304  public:
305         UserCertificateAPI(Module* parent)
306                 : dynamic_reference<UserCertificateAPIBase>(parent, "m_sslinfo_api")
307         {
308         }
309 };