]> jfr.im git - irc/quakenet/newserv.git/blame - chanserv/chanservcrypto.c
CHANSERV: better batcher error handling for expired accounts/accounts with no email.
[irc/quakenet/newserv.git] / chanserv / chanservcrypto.c
CommitLineData
0ba70e7b 1#include <stdio.h>
cd561842 2#include <strings.h>
0ba70e7b
CP
3
4#include "chanserv.h"
5#include "../core/error.h"
30a66d6c 6#include "../core/config.h"
0ba70e7b 7#include "../lib/prng.h"
b7a95f03
CP
8#include "../lib/sha1.h"
9#include "../lib/sha2.h"
10#include "../lib/md5.h"
11#include "../lib/hmac.h"
0ba70e7b 12
30a66d6c 13static prngctx rng;
bc6c8fbe 14static sstring *secret, *codesecret, *ticketsecret;
0ba70e7b 15
30a66d6c
CP
16static sstring *combinesecret(char *str) {
17 SHA256_CTX ctx;
18 unsigned char digest[32];
19 char hexbuf[sizeof(digest) * 2 + 1];
20
21 SHA256_Init(&ctx);
22 SHA256_Update(&ctx, (unsigned char *)secret->content, secret->length);
23 SHA256_Update(&ctx, (unsigned char *)":", 1);
24 SHA256_Update(&ctx, (unsigned char *)str, strlen(str));
25 SHA256_Final(digest, &ctx);
26
27 SHA256_Init(&ctx);
28 SHA256_Update(&ctx, digest, sizeof(digest));
29 SHA256_Final(digest, &ctx);
30 hmac_printhex(digest, hexbuf, sizeof(digest));
31
32 return getsstring(hexbuf, strlen(hexbuf));
33}
34
0ba70e7b
CP
35void chanservcryptoinit(void) {
36 int ret;
37
38 FILE *e = fopen(ENTROPYSOURCE, "rb");
39 if(!e) {
40 Error("chanserv",ERR_STOP,"Unable to open entropy source.");
41 /* shouldn't be running now... */
42 }
43
44 ret = fread(rng.randrsl, 1, sizeof(rng.randrsl), e);
45 fclose(e);
46
47 if(ret != sizeof(rng.randrsl)) {
48 Error("chanserv",ERR_STOP,"Unable to read entropy.");
49 /* shouldn't be running now... */
50 }
51
52 prnginit(&rng, 1);
30a66d6c
CP
53
54 secret=getcopyconfigitem("chanserv","secret","",128);
55 if(!secret || !secret->content || !secret->content[0]) {
56 unsigned char buf[32];
57 char hexbuf[sizeof(buf) * 2 + 1];
beb29b55 58 freesstring(secret);
30a66d6c
CP
59 Error("chanserv",ERR_WARNING,"Shared secret not set, generating a random string...");
60
61 cs_getrandbytes(buf, 32);
62 hmac_printhex(buf, hexbuf, sizeof(buf));
63 secret=getsstring(hexbuf, strlen(hexbuf));
64 }
65 codesecret=combinesecret("codegenerator");
bc6c8fbe
CP
66
67 ticketsecret=getcopyconfigitem("chanserv","ticketsecret","",256);
10a1d974 68 if(!ticketsecret || !ticketsecret->content[0]) {
bc6c8fbe
CP
69 Error("chanserv",ERR_WARNING,"Ticket secret not set, ticketauth disabled.");
70 freesstring(ticketsecret);
71 ticketsecret = NULL;
72 }
30a66d6c
CP
73}
74
75
76void chanservcryptofree(void) {
77 freesstring(secret);
78 freesstring(codesecret);
bc6c8fbe 79 freesstring(ticketsecret);
0ba70e7b
CP
80}
81
82ub4 cs_getrandint(void) {
83 return prng(&rng);
84}
85
86void cs_getrandbytes(unsigned char *buf, size_t bytes) {
45770ae6 87 for(;bytes>0;bytes-=4,buf+=4) {
0ba70e7b 88 ub4 b = cs_getrandint();
45770ae6 89 memcpy(buf, &b, 4);
0ba70e7b
CP
90 }
91}
b7a95f03
CP
92
93const char *cs_cralgorithmlist(void) {
3da2567a 94 return "HMAC-MD5 HMAC-SHA-1 HMAC-SHA-256 LEGACY-MD5";
b7a95f03
CP
95}
96
97int crsha1(char *username, const char *password, const char *challenge, const char *response) {
98 char buf[1024];
99
100 SHA1_CTX ctx;
101 unsigned char digest[20];
102 char hexbuf[sizeof(digest) * 2 + 1];
103 hmacsha1 hmac;
104
105 /* not sure how this helps but the RFC says to do it... */
106 SHA1Init(&ctx);
107 SHA1Update(&ctx, (unsigned char *)password, strlen(password));
108 SHA1Final(digest, &ctx);
109
110 snprintf(buf, sizeof(buf), "%s:%s", username, hmac_printhex(digest, hexbuf, sizeof(digest)));
111
112 SHA1Init(&ctx);
113 SHA1Update(&ctx, (unsigned char *)buf, strlen(buf));
114 SHA1Final(digest, &ctx);
115
116 hmacsha1_init(&hmac, (unsigned char *)hmac_printhex(digest, hexbuf, sizeof(digest)), sizeof(digest) * 2);
117 hmacsha1_update(&hmac, (unsigned char *)challenge, strlen(challenge));
118 hmacsha1_final(&hmac, digest);
119
120 hmac_printhex(digest, hexbuf, sizeof(digest));
121
0bd91417 122 if(!hmac_strcmp(hmac_printhex(digest, hexbuf, sizeof(digest)), response))
b7a95f03
CP
123 return 1;
124
125 return 0;
126}
127
128int crsha256(char *username, const char *password, const char *challenge, const char *response) {
129 char buf[1024];
130
131 SHA256_CTX ctx;
132 unsigned char digest[32];
133 char hexbuf[sizeof(digest) * 2 + 1];
134 hmacsha256 hmac;
135
136 /* not sure how this helps but the RFC says to do it... */
137 SHA256_Init(&ctx);
138 SHA256_Update(&ctx, (unsigned char *)password, strlen(password));
139 SHA256_Final(digest, &ctx);
140
141 snprintf(buf, sizeof(buf), "%s:%s", username, hmac_printhex(digest, hexbuf, sizeof(digest)));
142
143 SHA256_Init(&ctx);
144 SHA256_Update(&ctx, (unsigned char *)buf, strlen(buf));
145 SHA256_Final(digest, &ctx);
146
147 hmacsha256_init(&hmac, (unsigned char *)hmac_printhex(digest, hexbuf, sizeof(digest)), sizeof(digest) * 2);
148 hmacsha256_update(&hmac, (unsigned char *)challenge, strlen(challenge));
149 hmacsha256_final(&hmac, digest);
150
0bd91417 151 if(!hmac_strcmp(hmac_printhex(digest, hexbuf, sizeof(digest)), response))
b7a95f03
CP
152 return 1;
153
154 return 0;
155}
156
157int crmd5(char *username, const char *password, const char *challenge, const char *response) {
158 char buf[1024];
159
160 MD5Context ctx;
161 unsigned char digest[16];
162 char hexbuf[sizeof(digest) * 2 + 1];
163 hmacmd5 hmac;
164
165 /* not sure how this helps but the RFC says to do it... */
166 MD5Init(&ctx);
167 MD5Update(&ctx, (unsigned char *)password, strlen(password));
168 MD5Final(digest, &ctx);
169
170 snprintf(buf, sizeof(buf), "%s:%s", username, hmac_printhex(digest, hexbuf, sizeof(digest)));
171
172 MD5Init(&ctx);
173 MD5Update(&ctx, (unsigned char *)buf, strlen(buf));
174 MD5Final(digest, &ctx);
175
176 hmacmd5_init(&hmac, (unsigned char *)hmac_printhex(digest, hexbuf, sizeof(digest)), sizeof(digest) * 2);
177 hmacmd5_update(&hmac, (unsigned char *)challenge, strlen(challenge));
178 hmacmd5_final(&hmac, digest);
179
0bd91417 180 if(!hmac_strcmp(hmac_printhex(digest, hexbuf, sizeof(digest)), response))
b7a95f03
CP
181 return 1;
182
183 return 0;
184}
185
3da2567a
CP
186int crlegacymd5(char *username, const char *password, const char *challenge, const char *response) {
187 MD5Context ctx;
188 unsigned char digest[16];
189 char hexbuf[sizeof(digest) * 2 + 1];
190
191 MD5Init(&ctx);
192 MD5Update(&ctx, (unsigned char *)password, strlen(password));
193 MD5Update(&ctx, (unsigned char *)" ", 1);
194 MD5Update(&ctx, (unsigned char *)challenge, strlen(challenge));
195 MD5Final(digest, &ctx);
196
0bd91417 197 if(!hmac_strcmp(hmac_printhex(digest, hexbuf, sizeof(digest)), response))
3da2567a
CP
198 return 1;
199
200 return 0;
201}
202
b7a95f03
CP
203CRAlgorithm cs_cralgorithm(const char *algorithm) {
204 if(!strcasecmp(algorithm, "hmac-sha-1"))
205 return crsha1;
206
207 if(!strcasecmp(algorithm, "hmac-sha-256"))
208 return crsha256;
209
210 if(!strcasecmp(algorithm, "hmac-md5"))
211 return crmd5;
212
3da2567a
CP
213 if(!strcasecmp(algorithm, "legacy-md5"))
214 return crlegacymd5;
215
b7a95f03
CP
216 return 0;
217}
218
219char *cs_calcchallenge(const unsigned char *entropy) {
220 unsigned char buf[20];
221 static char hexbuf[sizeof(buf) * 2 + 1];
222 SHA1_CTX ctx;
223
224 SHA1Init(&ctx);
225 /* we can maybe add a salt here in the future */
226 SHA1Update(&ctx, entropy, ENTROPYLEN);
227 SHA1Final(buf, &ctx);
228
3da2567a 229 hmac_printhex(buf, hexbuf, 16);
b7a95f03
CP
230
231 return hexbuf;
232}
721cc8ce
CP
233
234int cs_checkhashpass(const char *username, const char *password, const char *junk, const char *hash) {
235 MD5Context ctx;
236 unsigned char digest[16];
237 char hexbuf[sizeof(digest) * 2 + 1], buf[512];
238
239 snprintf(buf, sizeof(buf), "%s %s%s%s", username, password, junk?" ":"", junk?junk:"");
240
241 MD5Init(&ctx);
242 MD5Update(&ctx, (unsigned char *)buf, strlen(buf));
243 MD5Final(digest, &ctx);
244
0bd91417 245 if(hmac_strcmp(hash, hmac_printhex(digest, hexbuf, sizeof(digest))))
721cc8ce
CP
246 return 0;
247
248 return 1;
249}
30a66d6c
CP
250
251char *csc_generateresetcode(time_t lockuntil, char *username) {
252 unsigned char digest[32];
253 static char hexbuf[sizeof(digest) * 2 + 1];
254 hmacsha256 hmac;
255 SHA256_CTX ctx;
256 char buf[1024];
257
258 snprintf(buf, sizeof(buf), "%s:%lu", username, lockuntil);
259
260 SHA256_Init(&ctx);
261 SHA256_Update(&ctx, (unsigned char *)buf, strlen(buf));
262 SHA256_Final(digest, &ctx);
263
264 hmac_printhex(digest, hexbuf, sizeof(digest));
265
266 hmacsha256_init(&hmac, (unsigned char *)codesecret->content, codesecret->length);
267 hmacsha256_update(&hmac, (unsigned char *)hexbuf, strlen(hexbuf));
268 hmacsha256_final(&hmac, digest);
269
270 hmac_printhex(digest, hexbuf, sizeof(digest));
271
272 return hexbuf;
273}
bc6c8fbe
CP
274
275int csc_verifyqticket(char *data, char *digest) {
276 hmacsha256 hmac;
277 unsigned char digestbuf[32];
f8b79cff 278 char hexbuf[sizeof(digestbuf) * 2 + 1];
bc6c8fbe
CP
279
280 if(!ticketsecret)
281 return -1;
282
283 hmacsha256_init(&hmac, (unsigned char *)ticketsecret->content, ticketsecret->length);
284 hmacsha256_update(&hmac, (unsigned char *)data, strlen(data));
285 hmacsha256_final(&hmac, digestbuf);
286
287 hmac_printhex(digestbuf, hexbuf, sizeof(digestbuf));
288
0bd91417 289 if(!hmac_strcmp(hexbuf, digest))
bc6c8fbe
CP
290 return 0;
291
292 return 1;
293}