]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_spanningtree/hmac.cpp
Create StreamSocket for IO hooking implementation
[user/henk/code/inspircd.git] / src / modules / m_spanningtree / hmac.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2009 InspIRCd Development Team
6  * See: http://wiki.inspircd.org/Credits
7  *
8  * This program is free but copyrighted software; see
9  *            the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 #include "inspircd.h"
15 #include "socket.h"
16 #include "xline.h"
17 #include "../transport.h"
18 #include "../m_hash.h"
19 #include "socketengine.h"
20
21 #include "main.h"
22 #include "utils.h"
23 #include "treeserver.h"
24 #include "link.h"
25 #include "treesocket.h"
26 #include "resolvers.h"
27 #include "handshaketimer.h"
28
29 /* $ModDep: m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h m_hash.h */
30
31 const std::string& TreeSocket::GetOurChallenge()
32 {
33         return this->ourchallenge;
34 }
35
36 void TreeSocket::SetOurChallenge(const std::string &c)
37 {
38         this->ourchallenge = c;
39 }
40
41 const std::string& TreeSocket::GetTheirChallenge()
42 {
43         return this->theirchallenge;
44 }
45
46 void TreeSocket::SetTheirChallenge(const std::string &c)
47 {
48         this->theirchallenge = c;
49 }
50
51 std::string TreeSocket::MakePass(const std::string &password, const std::string &challenge)
52 {
53         /* This is a simple (maybe a bit hacky?) HMAC algorithm, thanks to jilles for
54          * suggesting the use of HMAC to secure the password against various attacks.
55          *
56          * Note: If m_sha256.so is not loaded, we MUST fall back to plaintext with no
57          *       HMAC challenge/response.
58          */
59         Module* sha256 = ServerInstance->Modules->Find("m_sha256.so");
60         if (Utils->ChallengeResponse && sha256 && !challenge.empty())
61         {
62                 /* XXX: This is how HMAC is supposed to be done:
63                  *
64                  * sha256( (pass xor 0x5c) + sha256((pass xor 0x36) + m) )
65                  *
66                  * Note that we are encoding the hex hash, not the binary
67                  * output of the hash which is slightly different to standard.
68                  *
69                  * 5c and 36 were chosen as part of the HMAC standard, because they
70                  * flip the bits in a way likely to strengthen the function.
71                  */
72                 std::string hmac1, hmac2;
73
74                 for (size_t n = 0; n < password.length(); n++)
75                 {
76                         hmac1 += static_cast<char>(password[n] ^ 0x5C);
77                         hmac2 += static_cast<char>(password[n] ^ 0x36);
78                 }
79
80                 hmac2 += challenge;
81                 HashResetRequest(Utils->Creator, sha256).Send();
82                 hmac2 = HashSumRequest(Utils->Creator, sha256, hmac2).Send();
83
84                 HashResetRequest(Utils->Creator, sha256).Send();
85                 std::string hmac = hmac1 + hmac2;
86                 hmac = HashSumRequest(Utils->Creator, sha256, hmac).Send();
87
88                 return "HMAC-SHA256:"+ hmac;
89         }
90         else if (!challenge.empty() && !sha256)
91                 ServerInstance->Logs->Log("m_spanningtree",DEFAULT,"Not authenticating to server using SHA256/HMAC because we don't have m_sha256 loaded!");
92
93         return password;
94 }
95
96 std::string TreeSocket::RandString(unsigned int ilength)
97 {
98         char* randombuf = new char[ilength+1];
99         std::string out;
100 #ifndef WINDOWS
101         int f = open("/dev/urandom", O_RDONLY, 0);
102
103         if (f >= 0)
104         {
105                 if (read(f, randombuf, ilength) < (int)ilength)
106                         ServerInstance->Logs->Log("m_spanningtree", DEFAULT, "Entropy source has gone predictable (did not return enough data)");
107                 close(f);
108         }
109         else
110 #endif
111         {
112                 for (unsigned int i = 0; i < ilength; i++)
113                         randombuf[i] = rand();
114         }
115
116         for (unsigned int i = 0; i < ilength; i++)
117         {
118                 char randchar = static_cast<char>(0x3F + (randombuf[i] & 0x3F));
119                 out += randchar;
120         }
121
122         delete[] randombuf;
123         return out;
124 }
125
126 bool TreeSocket::ComparePass(const Link& link, const std::string &theirs)
127 {
128         this->auth_fingerprint = !link.Fingerprint.empty();
129         this->auth_challenge = !ourchallenge.empty() && !theirchallenge.empty();
130
131         std::string fp;
132         if (GetIOHook())
133         {
134                 BufferedSocketCertificateRequest req(this, Utils->Creator, GetIOHook());
135                 req.Send();
136                 if (req.cert)
137                 {
138                         fp = req.cert->GetFingerprint();
139                         ServerInstance->Logs->Log("m_spanningtree", DEFAULT, std::string("Server SSL fingerprint ") + fp);
140                 }
141         }
142
143         if (auth_fingerprint)
144         {
145                 /* Require fingerprint to exist and match */
146                 if (link.Fingerprint != fp)
147                 {
148                         ServerInstance->SNO->WriteToSnoMask('l',"Invalid SSL fingerprint on link %s: need '%s' got '%s'", 
149                                 link.Name.c_str(), link.Fingerprint.c_str(), fp.c_str());
150                         return false;
151                 }
152         }
153
154         if (auth_challenge)
155         {
156                 std::string our_hmac = MakePass(link.RecvPass, ourchallenge);
157
158                 /* Straight string compare of hashes */
159                 return our_hmac == theirs;
160         }
161
162         /* Straight string compare of plaintext */
163         return link.RecvPass == theirs;
164 }