]> icculus.org git repositories - divverent/darkplaces.git/blob - crypto.c
playvideo: cl_video_keepaspectratio == 2 will do clip instead of stretch, added simpl...
[divverent/darkplaces.git] / crypto.c
1 // TODO key loading, generating, saving
2 #include "quakedef.h"
3 #include "crypto.h"
4 #include "common.h"
5
6 #include "hmac.h"
7 #include "libcurl.h"
8
9 cvar_t crypto_developer = {CVAR_SAVE, "crypto_developer", "0", "print extra info about crypto handshake"};
10 cvar_t crypto_servercpupercent = {CVAR_SAVE, "crypto_servercpupercent", "10", "allowed crypto CPU load in percent for server operation (0 = no limit, faster)"};
11 cvar_t crypto_servercpumaxtime = {CVAR_SAVE, "crypto_servercpumaxtime", "0.01", "maximum allowed crypto CPU time per frame (0 = no limit)"};
12 cvar_t crypto_servercpudebug = {CVAR_SAVE, "crypto_servercpudebug", "0", "print statistics about time usage by crypto"};
13 static double crypto_servercpu_accumulator = 0;
14 static double crypto_servercpu_lastrealtime = 0;
15 cvar_t crypto_aeslevel = {CVAR_SAVE, "crypto_aeslevel", "1", "whether to support AES encryption in authenticated connections (0 = no, 1 = supported, 2 = requested, 3 = required)"};
16 int crypto_keyfp_recommended_length;
17 static const char *crypto_idstring = NULL;
18 static char crypto_idstring_buf[512];
19
20 #define PROTOCOL_D0_BLIND_ID FOURCC_D0PK
21 #define PROTOCOL_VLEN (('v' << 0) | ('l' << 8) | ('e' << 16) | ('n' << 24))
22
23 // BEGIN stuff shared with crypto-keygen-standalone
24 #define FOURCC_D0PK (('d' << 0) | ('0' << 8) | ('p' << 16) | ('k' << 24))
25 #define FOURCC_D0SK (('d' << 0) | ('0' << 8) | ('s' << 16) | ('k' << 24))
26 #define FOURCC_D0PI (('d' << 0) | ('0' << 8) | ('p' << 16) | ('i' << 24))
27 #define FOURCC_D0SI (('d' << 0) | ('0' << 8) | ('s' << 16) | ('i' << 24))
28 #define FOURCC_D0IQ (('d' << 0) | ('0' << 8) | ('i' << 16) | ('q' << 24))
29 #define FOURCC_D0IR (('d' << 0) | ('0' << 8) | ('i' << 16) | ('r' << 24))
30 #define FOURCC_D0ER (('d' << 0) | ('0' << 8) | ('e' << 16) | ('r' << 24))
31 #define FOURCC_D0IC (('d' << 0) | ('0' << 8) | ('i' << 16) | ('c' << 24))
32
33 static unsigned long Crypto_LittleLong(const char *data)
34 {
35         return
36                 ((unsigned char) data[0]) |
37                 (((unsigned char) data[1]) << 8) |
38                 (((unsigned char) data[2]) << 16) |
39                 (((unsigned char) data[3]) << 24);
40 }
41
42 static void Crypto_UnLittleLong(char *data, unsigned long l)
43 {
44         data[0] = l & 0xFF;
45         data[1] = (l >> 8) & 0xFF;
46         data[2] = (l >> 16) & 0xFF;
47         data[3] = (l >> 24) & 0xFF;
48 }
49
50 static size_t Crypto_ParsePack(const char *buf, size_t len, unsigned long header, const char **lumps, size_t *lumpsize, size_t nlumps)
51 {
52         size_t i;
53         size_t pos;
54         pos = 0;
55         if(header)
56         {
57                 if(len < 4)
58                         return 0;
59                 if(Crypto_LittleLong(buf) != header)
60                         return 0;
61                 pos += 4;
62         }
63         for(i = 0; i < nlumps; ++i)
64         {
65                 if(pos + 4 > len)
66                         return 0;
67                 lumpsize[i] = Crypto_LittleLong(&buf[pos]);
68                 pos += 4;
69                 if(pos + lumpsize[i] > len)
70                         return 0;
71                 lumps[i] = &buf[pos];
72                 pos += lumpsize[i];
73         }
74         return pos;
75 }
76
77 static size_t Crypto_UnParsePack(char *buf, size_t len, unsigned long header, const char *const *lumps, const size_t *lumpsize, size_t nlumps)
78 {
79         size_t i;
80         size_t pos;
81         pos = 0;
82         if(header)
83         {
84                 if(len < 4)
85                         return 0;
86                 Crypto_UnLittleLong(buf, header);
87                 pos += 4;
88         }
89         for(i = 0; i < nlumps; ++i)
90         {
91                 if(pos + 4 + lumpsize[i] > len)
92                         return 0;
93                 Crypto_UnLittleLong(&buf[pos], lumpsize[i]);
94                 pos += 4;
95                 memcpy(&buf[pos], lumps[i], lumpsize[i]);
96                 pos += lumpsize[i];
97         }
98         return pos;
99 }
100 // END stuff shared with xonotic-keygen
101
102 #define USE_AES
103
104 #ifdef CRYPTO_STATIC
105
106 #include <d0_blind_id/d0_blind_id.h>
107
108 #define d0_blind_id_dll 1
109 #define Crypto_OpenLibrary() true
110 #define Crypto_CloseLibrary()
111
112 #define qd0_blind_id_new d0_blind_id_new
113 #define qd0_blind_id_free d0_blind_id_free
114 //#define qd0_blind_id_clear d0_blind_id_clear
115 #define qd0_blind_id_copy d0_blind_id_copy
116 //#define qd0_blind_id_generate_private_key d0_blind_id_generate_private_key
117 //#define qd0_blind_id_generate_private_key_fastreject d0_blind_id_generate_private_key_fastreject
118 //#define qd0_blind_id_read_private_key d0_blind_id_read_private_key
119 #define qd0_blind_id_read_public_key d0_blind_id_read_public_key
120 //#define qd0_blind_id_write_private_key d0_blind_id_write_private_key
121 //#define qd0_blind_id_write_public_key d0_blind_id_write_public_key
122 #define qd0_blind_id_fingerprint64_public_key d0_blind_id_fingerprint64_public_key
123 //#define qd0_blind_id_generate_private_id_modulus d0_blind_id_generate_private_id_modulus
124 #define qd0_blind_id_read_private_id_modulus d0_blind_id_read_private_id_modulus
125 //#define qd0_blind_id_write_private_id_modulus d0_blind_id_write_private_id_modulus
126 #define qd0_blind_id_generate_private_id_start d0_blind_id_generate_private_id_start
127 #define qd0_blind_id_generate_private_id_request d0_blind_id_generate_private_id_request
128 //#define qd0_blind_id_answer_private_id_request d0_blind_id_answer_private_id_request
129 #define qd0_blind_id_finish_private_id_request d0_blind_id_finish_private_id_request
130 //#define qd0_blind_id_read_private_id_request_camouflage d0_blind_id_read_private_id_request_camouflage
131 //#define qd0_blind_id_write_private_id_request_camouflage d0_blind_id_write_private_id_request_camouflage
132 #define qd0_blind_id_read_private_id d0_blind_id_read_private_id
133 //#define qd0_blind_id_read_public_id d0_blind_id_read_public_id
134 #define qd0_blind_id_write_private_id d0_blind_id_write_private_id
135 //#define qd0_blind_id_write_public_id d0_blind_id_write_public_id
136 #define qd0_blind_id_authenticate_with_private_id_start d0_blind_id_authenticate_with_private_id_start
137 #define qd0_blind_id_authenticate_with_private_id_challenge d0_blind_id_authenticate_with_private_id_challenge
138 #define qd0_blind_id_authenticate_with_private_id_response d0_blind_id_authenticate_with_private_id_response
139 #define qd0_blind_id_authenticate_with_private_id_verify d0_blind_id_authenticate_with_private_id_verify
140 #define qd0_blind_id_fingerprint64_public_id d0_blind_id_fingerprint64_public_id
141 #define qd0_blind_id_sessionkey_public_id d0_blind_id_sessionkey_public_id
142 #define qd0_blind_id_INITIALIZE d0_blind_id_INITIALIZE
143 #define qd0_blind_id_SHUTDOWN d0_blind_id_SHUTDOWN
144 #define qd0_blind_id_util_sha256 d0_blind_id_util_sha256
145
146 #else
147
148 // d0_blind_id interface
149 #define D0_EXPORT
150 #ifdef __GNUC__
151 #define D0_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
152 #else
153 #define D0_WARN_UNUSED_RESULT
154 #endif
155 #define D0_BOOL int
156
157 typedef struct d0_blind_id_s d0_blind_id_t;
158 typedef D0_BOOL (*d0_fastreject_function) (const d0_blind_id_t *ctx, void *pass);
159 static D0_EXPORT D0_WARN_UNUSED_RESULT d0_blind_id_t *(*qd0_blind_id_new) (void);
160 static D0_EXPORT void (*qd0_blind_id_free) (d0_blind_id_t *a);
161 //static D0_EXPORT void (*qd0_blind_id_clear) (d0_blind_id_t *ctx);
162 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_copy) (d0_blind_id_t *ctx, const d0_blind_id_t *src);
163 //static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_generate_private_key) (d0_blind_id_t *ctx, int k);
164 //static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_generate_private_key_fastreject) (d0_blind_id_t *ctx, int k, d0_fastreject_function reject, void *pass);
165 //static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_read_private_key) (d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen);
166 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_read_public_key) (d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen);
167 //static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_write_private_key) (const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen);
168 //static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_write_public_key) (const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen);
169 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_fingerprint64_public_key) (const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen);
170 //static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_generate_private_id_modulus) (d0_blind_id_t *ctx);
171 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_read_private_id_modulus) (d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen);
172 //static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_write_private_id_modulus) (const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen);
173 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_generate_private_id_start) (d0_blind_id_t *ctx);
174 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_generate_private_id_request) (d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen);
175 //static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_answer_private_id_request) (const d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen, char *outbuf, size_t *outbuflen);
176 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_finish_private_id_request) (d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen);
177 //static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_read_private_id_request_camouflage) (d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen);
178 //static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_write_private_id_request_camouflage) (const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen);
179 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_read_private_id) (d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen);
180 //static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_read_public_id) (d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen);
181 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_write_private_id) (const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen);
182 //static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_write_public_id) (const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen);
183 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_authenticate_with_private_id_start) (d0_blind_id_t *ctx, D0_BOOL is_first, D0_BOOL send_modulus, const char *message, size_t msglen, char *outbuf, size_t *outbuflen);
184 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_authenticate_with_private_id_challenge) (d0_blind_id_t *ctx, D0_BOOL is_first, D0_BOOL recv_modulus, const char *inbuf, size_t inbuflen, char *outbuf, size_t *outbuflen, D0_BOOL *status);
185 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_authenticate_with_private_id_response) (d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen, char *outbuf, size_t *outbuflen);
186 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_authenticate_with_private_id_verify) (d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen, char *msg, size_t *msglen, D0_BOOL *status);
187 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_fingerprint64_public_id) (const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen);
188 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_sessionkey_public_id) (const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen); // can only be done after successful key exchange, this performs a modpow; key length is limited by SHA_DIGESTSIZE for now; also ONLY valid after successful d0_blind_id_authenticate_with_private_id_verify/d0_blind_id_fingerprint64_public_id
189 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_INITIALIZE) (void);
190 static D0_EXPORT void (*qd0_blind_id_SHUTDOWN) (void);
191 static D0_EXPORT void (*qd0_blind_id_util_sha256) (char *out, const char *in, size_t n);
192 static dllfunction_t d0_blind_id_funcs[] =
193 {
194         {"d0_blind_id_new", (void **) &qd0_blind_id_new},
195         {"d0_blind_id_free", (void **) &qd0_blind_id_free},
196         //{"d0_blind_id_clear", (void **) &qd0_blind_id_clear},
197         {"d0_blind_id_copy", (void **) &qd0_blind_id_copy},
198         //{"d0_blind_id_generate_private_key", (void **) &qd0_blind_id_generate_private_key},
199         //{"d0_blind_id_generate_private_key_fastreject", (void **) &qd0_blind_id_generate_private_key_fastreject},
200         //{"d0_blind_id_read_private_key", (void **) &qd0_blind_id_read_private_key},
201         {"d0_blind_id_read_public_key", (void **) &qd0_blind_id_read_public_key},
202         //{"d0_blind_id_write_private_key", (void **) &qd0_blind_id_write_private_key},
203         //{"d0_blind_id_write_public_key", (void **) &qd0_blind_id_write_public_key},
204         {"d0_blind_id_fingerprint64_public_key", (void **) &qd0_blind_id_fingerprint64_public_key},
205         //{"d0_blind_id_generate_private_id_modulus", (void **) &qd0_blind_id_generate_private_id_modulus},
206         {"d0_blind_id_read_private_id_modulus", (void **) &qd0_blind_id_read_private_id_modulus},
207         //{"d0_blind_id_write_private_id_modulus", (void **) &qd0_blind_id_write_private_id_modulus},
208         {"d0_blind_id_generate_private_id_start", (void **) &qd0_blind_id_generate_private_id_start},
209         {"d0_blind_id_generate_private_id_request", (void **) &qd0_blind_id_generate_private_id_request},
210         //{"d0_blind_id_answer_private_id_request", (void **) &qd0_blind_id_answer_private_id_request},
211         {"d0_blind_id_finish_private_id_request", (void **) &qd0_blind_id_finish_private_id_request},
212         //{"d0_blind_id_read_private_id_request_camouflage", (void **) &qd0_blind_id_read_private_id_request_camouflage},
213         //{"d0_blind_id_write_private_id_request_camouflage", (void **) &qd0_blind_id_write_private_id_request_camouflage},
214         {"d0_blind_id_read_private_id", (void **) &qd0_blind_id_read_private_id},
215         //{"d0_blind_id_read_public_id", (void **) &qd0_blind_id_read_public_id},
216         {"d0_blind_id_write_private_id", (void **) &qd0_blind_id_write_private_id},
217         //{"d0_blind_id_write_public_id", (void **) &qd0_blind_id_write_public_id},
218         {"d0_blind_id_authenticate_with_private_id_start", (void **) &qd0_blind_id_authenticate_with_private_id_start},
219         {"d0_blind_id_authenticate_with_private_id_challenge", (void **) &qd0_blind_id_authenticate_with_private_id_challenge},
220         {"d0_blind_id_authenticate_with_private_id_response", (void **) &qd0_blind_id_authenticate_with_private_id_response},
221         {"d0_blind_id_authenticate_with_private_id_verify", (void **) &qd0_blind_id_authenticate_with_private_id_verify},
222         {"d0_blind_id_fingerprint64_public_id", (void **) &qd0_blind_id_fingerprint64_public_id},
223         {"d0_blind_id_sessionkey_public_id", (void **) &qd0_blind_id_sessionkey_public_id},
224         {"d0_blind_id_INITIALIZE", (void **) &qd0_blind_id_INITIALIZE},
225         {"d0_blind_id_SHUTDOWN", (void **) &qd0_blind_id_SHUTDOWN},
226         {"d0_blind_id_util_sha256", (void **) &qd0_blind_id_util_sha256},
227         {NULL, NULL}
228 };
229 // end of d0_blind_id interface
230
231 static dllhandle_t d0_blind_id_dll = NULL;
232 static qboolean Crypto_OpenLibrary (void)
233 {
234         const char* dllnames [] =
235         {
236 #if defined(WIN32)
237                 "libd0_blind_id-0.dll",
238 #elif defined(MACOSX)
239                 "libd0_blind_id.0.dylib",
240 #else
241                 "libd0_blind_id.so.0",
242                 "libd0_blind_id.so", // FreeBSD
243 #endif
244                 NULL
245         };
246
247         // Already loaded?
248         if (d0_blind_id_dll)
249                 return true;
250
251         // Load the DLL
252         return Sys_LoadLibrary (dllnames, &d0_blind_id_dll, d0_blind_id_funcs);
253 }
254
255 static void Crypto_CloseLibrary (void)
256 {
257         Sys_UnloadLibrary (&d0_blind_id_dll);
258 }
259
260 #endif
261
262 #ifdef CRYPTO_RIJNDAEL_STATIC
263
264 #include <d0_blind_id/d0_rijndael.h>
265
266 #define d0_rijndael_dll 1
267 #define Crypto_Rijndael_OpenLibrary() true
268 #define Crypto_Rijndael_CloseLibrary()
269
270 #define qd0_rijndael_setup_encrypt d0_rijndael_setup_encrypt
271 #define qd0_rijndael_setup_decrypt d0_rijndael_setup_decrypt
272 #define qd0_rijndael_encrypt d0_rijndael_encrypt
273 #define qd0_rijndael_decrypt d0_rijndael_decrypt
274
275 #else
276
277 // no need to do the #define dance here, as the upper part declares out macros either way
278
279 D0_EXPORT int (*qd0_rijndael_setup_encrypt) (unsigned long *rk, const unsigned char *key,
280   int keybits);
281 D0_EXPORT int (*qd0_rijndael_setup_decrypt) (unsigned long *rk, const unsigned char *key,
282   int keybits);
283 D0_EXPORT void (*qd0_rijndael_encrypt) (const unsigned long *rk, int nrounds,
284   const unsigned char plaintext[16], unsigned char ciphertext[16]);
285 D0_EXPORT void (*qd0_rijndael_decrypt) (const unsigned long *rk, int nrounds,
286   const unsigned char ciphertext[16], unsigned char plaintext[16]);
287 #define D0_RIJNDAEL_KEYLENGTH(keybits) ((keybits)/8)
288 #define D0_RIJNDAEL_RKLENGTH(keybits)  ((keybits)/8+28)
289 #define D0_RIJNDAEL_NROUNDS(keybits)   ((keybits)/32+6)
290 static dllfunction_t d0_rijndael_funcs[] =
291 {
292         {"d0_rijndael_setup_decrypt", (void **) &qd0_rijndael_setup_decrypt},
293         {"d0_rijndael_setup_encrypt", (void **) &qd0_rijndael_setup_encrypt},
294         {"d0_rijndael_decrypt", (void **) &qd0_rijndael_decrypt},
295         {"d0_rijndael_encrypt", (void **) &qd0_rijndael_encrypt},
296         {NULL, NULL}
297 };
298 // end of d0_blind_id interface
299
300 static dllhandle_t d0_rijndael_dll = NULL;
301 static qboolean Crypto_Rijndael_OpenLibrary (void)
302 {
303         const char* dllnames [] =
304         {
305 #if defined(WIN32)
306                 "libd0_rijndael-0.dll",
307 #elif defined(MACOSX)
308                 "libd0_rijndael.0.dylib",
309 #else
310                 "libd0_rijndael.so.0",
311                 "libd0_rijndael.so", // FreeBSD
312 #endif
313                 NULL
314         };
315
316         // Already loaded?
317         if (d0_rijndael_dll)
318                 return true;
319
320         // Load the DLL
321         return Sys_LoadLibrary (dllnames, &d0_rijndael_dll, d0_rijndael_funcs);
322 }
323
324 static void Crypto_Rijndael_CloseLibrary (void)
325 {
326         Sys_UnloadLibrary (&d0_rijndael_dll);
327 }
328
329 #endif
330
331 // various helpers
332 void sha256(unsigned char *out, const unsigned char *in, int n)
333 {
334         qd0_blind_id_util_sha256((char *) out, (const char *) in, n);
335 }
336
337 static size_t Crypto_LoadFile(const char *path, char *buf, size_t nmax)
338 {
339         qfile_t *f = NULL;
340         fs_offset_t n;
341         if(*fs_userdir)
342                 f = FS_SysOpen(va("%s%s", fs_userdir, path), "rb", false);
343         if(!f)
344                 f = FS_SysOpen(va("%s%s", fs_basedir, path), "rb", false);
345         if(!f)
346                 return 0;
347         n = FS_Read(f, buf, nmax);
348         if(n < 0)
349                 n = 0;
350         FS_Close(f);
351         return (size_t) n;
352 }
353
354 static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
355 static void base64_3to4(const unsigned char *in, unsigned char *out, int bytes)
356 {
357         unsigned char i0 = (bytes > 0) ? in[0] : 0;
358         unsigned char i1 = (bytes > 1) ? in[1] : 0;
359         unsigned char i2 = (bytes > 2) ? in[2] : 0;
360         unsigned char o0 = base64[i0 >> 2];
361         unsigned char o1 = base64[((i0 << 4) | (i1 >> 4)) & 077];
362         unsigned char o2 = base64[((i1 << 2) | (i2 >> 6)) & 077];
363         unsigned char o3 = base64[i2 & 077];
364         out[0] = (bytes > 0) ? o0 : '?';
365         out[1] = (bytes > 0) ? o1 : '?';
366         out[2] = (bytes > 1) ? o2 : '=';
367         out[3] = (bytes > 2) ? o3 : '=';
368 }
369
370 size_t base64_encode(unsigned char *buf, size_t buflen, size_t outbuflen)
371 {
372         size_t blocks, i;
373         // expand the out-buffer
374         blocks = (buflen + 2) / 3;
375         if(blocks*4 > outbuflen)
376                 return 0;
377         for(i = blocks; i > 0; )
378         {
379                 --i;
380                 base64_3to4(buf + 3*i, buf + 4*i, buflen - 3*i);
381         }
382         return blocks * 4;
383 }
384
385 static qboolean PutWithNul(char **data, size_t *len, const char *str)
386 {
387         // invariant: data points to insertion point
388         size_t l = strlen(str);
389         if(l >= *len)
390                 return false;
391         memcpy(*data, str, l+1);
392         *data += l+1;
393         *len -= l+1;
394         return true;
395 }
396
397 static const char *GetUntilNul(const char **data, size_t *len)
398 {
399         // invariant: data points to next character to take
400         const char *data_save = *data;
401         size_t n;
402         const char *p;
403
404         if(!*data)
405                 return NULL;
406
407         if(!*len)
408         {
409                 *data = NULL;
410                 return NULL;
411         }
412
413         p = (const char *) memchr(*data, 0, *len);
414         if(!p) // no terminating NUL
415         {
416                 *data = NULL;
417                 *len = 0;
418                 return NULL;
419         }
420         else
421         {
422                 n = (p - *data) + 1;
423                 *len -= n;
424                 *data += n;
425                 if(*len == 0)
426                         *data = NULL;
427                 return (const char *) data_save;
428         }
429         *data = NULL;
430         return NULL;
431 }
432
433 // d0pk reading
434 static d0_blind_id_t *Crypto_ReadPublicKey(char *buf, size_t len)
435 {
436         d0_blind_id_t *pk = NULL;
437         const char *p[2];
438         size_t l[2];
439         if(Crypto_ParsePack(buf, len, FOURCC_D0PK, p, l, 2))
440         {
441                 pk = qd0_blind_id_new();
442                 if(pk)
443                         if(qd0_blind_id_read_public_key(pk, p[0], l[0]))
444                                 if(qd0_blind_id_read_private_id_modulus(pk, p[1], l[1]))
445                                         return pk;
446         }
447         if(pk)
448                 qd0_blind_id_free(pk);
449         return NULL;
450 }
451
452 // d0si reading
453 static qboolean Crypto_AddPrivateKey(d0_blind_id_t *pk, char *buf, size_t len)
454 {
455         const char *p[1];
456         size_t l[1];
457         if(Crypto_ParsePack(buf, len, FOURCC_D0SI, p, l, 1))
458         {
459                 if(qd0_blind_id_read_private_id(pk, p[0], l[0]))
460                         return true;
461         }
462         return false;
463 }
464
465 #define MAX_PUBKEYS 16
466 static d0_blind_id_t *pubkeys[MAX_PUBKEYS];
467 static char pubkeys_fp64[MAX_PUBKEYS][FP64_SIZE+1];
468 static qboolean pubkeys_havepriv[MAX_PUBKEYS];
469 static char pubkeys_priv_fp64[MAX_PUBKEYS][FP64_SIZE+1];
470 static char challenge_append[1400];
471 static size_t challenge_append_length;
472
473 static int keygen_i = -1;
474 static char keygen_buf[8192];
475
476 #define MAX_CRYPTOCONNECTS 16
477 #define CRYPTOCONNECT_NONE 0
478 #define CRYPTOCONNECT_PRECONNECT 1
479 #define CRYPTOCONNECT_CONNECT 2
480 #define CRYPTOCONNECT_RECONNECT 3
481 #define CRYPTOCONNECT_DUPLICATE 4
482 typedef struct server_cryptoconnect_s
483 {
484         double lasttime;
485         lhnetaddress_t address;
486         crypto_t crypto;
487         int next_step;
488 }
489 server_cryptoconnect_t;
490 static server_cryptoconnect_t cryptoconnects[MAX_CRYPTOCONNECTS];
491
492 static int cdata_id = 0;
493 typedef struct
494 {
495         d0_blind_id_t *id;
496         int s, c;
497         int next_step;
498         char challenge[2048];
499         char wantserver_idfp[FP64_SIZE+1];
500         qboolean wantserver_aes;
501         int cdata_id;
502 }
503 crypto_data_t;
504
505 // crypto specific helpers
506 #define CDATA ((crypto_data_t *) crypto->data)
507 #define MAKE_CDATA if(!crypto->data) crypto->data = Z_Malloc(sizeof(crypto_data_t))
508 #define CLEAR_CDATA if(crypto->data) { if(CDATA->id) qd0_blind_id_free(CDATA->id); Z_Free(crypto->data); } crypto->data = NULL
509
510 static crypto_t *Crypto_ServerFindInstance(lhnetaddress_t *peeraddress, qboolean allow_create)
511 {
512         crypto_t *crypto; 
513         int i, best;
514
515         if(!d0_blind_id_dll)
516                 return NULL; // no support
517
518         for(i = 0; i < MAX_CRYPTOCONNECTS; ++i)
519                 if(LHNETADDRESS_Compare(peeraddress, &cryptoconnects[i].address))
520                         break;
521         if(i < MAX_CRYPTOCONNECTS && (allow_create || cryptoconnects[i].crypto.data))
522         {
523                 crypto = &cryptoconnects[i].crypto;
524                 cryptoconnects[i].lasttime = realtime;
525                 return crypto;
526         }
527         if(!allow_create)
528                 return NULL;
529         best = 0;
530         for(i = 1; i < MAX_CRYPTOCONNECTS; ++i)
531                 if(cryptoconnects[i].lasttime < cryptoconnects[best].lasttime)
532                         best = i;
533         crypto = &cryptoconnects[best].crypto;
534         cryptoconnects[best].lasttime = realtime;
535         memcpy(&cryptoconnects[best].address, peeraddress, sizeof(cryptoconnects[best].address));
536         CLEAR_CDATA;
537         return crypto;
538 }
539
540 qboolean Crypto_ServerFinishInstance(crypto_t *out, crypto_t *crypto)
541 {
542         // no check needed here (returned pointers are only used in prefilled fields)
543         if(!crypto || !crypto->authenticated)
544         {
545                 Con_Printf("Passed an invalid crypto connect instance\n");
546                 memset(out, 0, sizeof(*out));
547                 return false;
548         }
549         CLEAR_CDATA;
550         memcpy(out, crypto, sizeof(*out));
551         memset(crypto, 0, sizeof(crypto));
552         return true;
553 }
554
555 crypto_t *Crypto_ServerGetInstance(lhnetaddress_t *peeraddress)
556 {
557         // no check needed here (returned pointers are only used in prefilled fields)
558         return Crypto_ServerFindInstance(peeraddress, false);
559 }
560
561 typedef struct crypto_storedhostkey_s
562 {
563         struct crypto_storedhostkey_s *next;
564         lhnetaddress_t addr;
565         int keyid;
566         char idfp[FP64_SIZE+1];
567         int aeslevel;
568 }
569 crypto_storedhostkey_t;
570 static crypto_storedhostkey_t *crypto_storedhostkey_hashtable[CRYPTO_HOSTKEY_HASHSIZE];
571
572 static void Crypto_InitHostKeys(void)
573 {
574         int i;
575         for(i = 0; i < CRYPTO_HOSTKEY_HASHSIZE; ++i)
576                 crypto_storedhostkey_hashtable[i] = NULL;
577 }
578
579 static void Crypto_ClearHostKeys(void)
580 {
581         int i;
582         crypto_storedhostkey_t *hk, *hkn;
583         for(i = 0; i < CRYPTO_HOSTKEY_HASHSIZE; ++i)
584         {
585                 for(hk = crypto_storedhostkey_hashtable[i]; hk; hk = hkn)
586                 {
587                         hkn = hk->next;
588                         Z_Free(hk);
589                 }
590                 crypto_storedhostkey_hashtable[i] = NULL;
591         }
592 }
593
594 static qboolean Crypto_ClearHostKey(lhnetaddress_t *peeraddress)
595 {
596         char buf[128];
597         int hashindex;
598         crypto_storedhostkey_t **hkp;
599         qboolean found = false;
600
601         LHNETADDRESS_ToString(peeraddress, buf, sizeof(buf), 1);
602         hashindex = CRC_Block((const unsigned char *) buf, strlen(buf)) % CRYPTO_HOSTKEY_HASHSIZE;
603         for(hkp = &crypto_storedhostkey_hashtable[hashindex]; *hkp && LHNETADDRESS_Compare(&((*hkp)->addr), peeraddress); hkp = &((*hkp)->next));
604
605         if(*hkp)
606         {
607                 crypto_storedhostkey_t *hk = *hkp;
608                 *hkp = hk->next;
609                 Z_Free(hk);
610                 found = true;
611         }
612
613         return found;
614 }
615
616 static void Crypto_StoreHostKey(lhnetaddress_t *peeraddress, const char *keystring, qboolean complain)
617 {
618         char buf[128];
619         int hashindex;
620         crypto_storedhostkey_t *hk;
621         int keyid;
622         char idfp[FP64_SIZE+1];
623         int aeslevel;
624
625         if(!d0_blind_id_dll)
626                 return;
627         
628         // syntax of keystring:
629         // aeslevel id@key id@key ...
630
631         if(!*keystring)
632                 return;
633         aeslevel = bound(0, *keystring - '0', 3);
634         while(*keystring && *keystring != ' ')
635                 ++keystring;
636
637         keyid = -1;
638         while(*keystring && keyid < 0)
639         {
640                 // id@key
641                 const char *idstart, *idend, *keystart, *keyend;
642                 ++keystring; // skip the space
643                 idstart = keystring;
644                 while(*keystring && *keystring != ' ' && *keystring != '@')
645                         ++keystring;
646                 idend = keystring;
647                 if(!*keystring)
648                         break;
649                 ++keystring;
650                 keystart = keystring;
651                 while(*keystring && *keystring != ' ')
652                         ++keystring;
653                 keyend = keystring;
654
655                 if(idend - idstart == FP64_SIZE && keyend - keystart == FP64_SIZE)
656                 {
657                         for(keyid = 0; keyid < MAX_PUBKEYS; ++keyid)
658                                 if(pubkeys[keyid])
659                                         if(!memcmp(pubkeys_fp64[keyid], keystart, FP64_SIZE))
660                                         {
661                                                 memcpy(idfp, idstart, FP64_SIZE);
662                                                 idfp[FP64_SIZE] = 0;
663                                                 break;
664                                         }
665                         if(keyid >= MAX_PUBKEYS)
666                                 keyid = -1;
667                 }
668         }
669
670         if(keyid < 0)
671                 return;
672
673         LHNETADDRESS_ToString(peeraddress, buf, sizeof(buf), 1);
674         hashindex = CRC_Block((const unsigned char *) buf, strlen(buf)) % CRYPTO_HOSTKEY_HASHSIZE;
675         for(hk = crypto_storedhostkey_hashtable[hashindex]; hk && LHNETADDRESS_Compare(&hk->addr, peeraddress); hk = hk->next);
676
677         if(hk)
678         {
679                 if(complain)
680                 {
681                         if(hk->keyid != keyid || memcmp(hk->idfp, idfp, FP64_SIZE+1))
682                                 Con_Printf("Server %s tried to change the host key to a value not in the host cache. Connecting to it will fail. To accept the new host key, do crypto_hostkey_clear %s\n", buf, buf);
683                         if(hk->aeslevel > aeslevel)
684                                 Con_Printf("Server %s tried to reduce encryption status, not accepted. Connecting to it will fail. To accept, do crypto_hostkey_clear %s\n", buf, buf);
685                 }
686                 hk->aeslevel = max(aeslevel, hk->aeslevel);
687                 return;
688         }
689
690         // great, we did NOT have it yet
691         hk = (crypto_storedhostkey_t *) Z_Malloc(sizeof(*hk));
692         memcpy(&hk->addr, peeraddress, sizeof(hk->addr));
693         hk->keyid = keyid;
694         memcpy(hk->idfp, idfp, FP64_SIZE+1);
695         hk->next = crypto_storedhostkey_hashtable[hashindex];
696         hk->aeslevel = aeslevel;
697         crypto_storedhostkey_hashtable[hashindex] = hk;
698 }
699
700 qboolean Crypto_RetrieveHostKey(lhnetaddress_t *peeraddress, int *keyid, char *keyfp, size_t keyfplen, char *idfp, size_t idfplen, int *aeslevel)
701 {
702         char buf[128];
703         int hashindex;
704         crypto_storedhostkey_t *hk;
705
706         if(!d0_blind_id_dll)
707                 return false;
708
709         LHNETADDRESS_ToString(peeraddress, buf, sizeof(buf), 1);
710         hashindex = CRC_Block((const unsigned char *) buf, strlen(buf)) % CRYPTO_HOSTKEY_HASHSIZE;
711         for(hk = crypto_storedhostkey_hashtable[hashindex]; hk && LHNETADDRESS_Compare(&hk->addr, peeraddress); hk = hk->next);
712
713         if(!hk)
714                 return false;
715
716         if(keyid)
717                 *keyid = hk->keyid;
718         if(keyfp)
719                 strlcpy(keyfp, pubkeys_fp64[hk->keyid], keyfplen);
720         if(idfp)
721                 strlcpy(idfp, hk->idfp, idfplen);
722         if(aeslevel)
723                 *aeslevel = hk->aeslevel;
724
725         return true;
726 }
727 int Crypto_RetrieveLocalKey(int keyid, char *keyfp, size_t keyfplen, char *idfp, size_t idfplen) // return value: -1 if more to come, +1 if valid, 0 if end of list
728 {
729         if(keyid < 0 || keyid > MAX_PUBKEYS)
730                 return 0;
731         if(keyfp)
732                 *keyfp = 0;
733         if(idfp)
734                 *idfp = 0;
735         if(!pubkeys[keyid])
736                 return -1;
737         if(keyfp)
738                 strlcpy(keyfp, pubkeys_fp64[keyid], keyfplen);
739         if(idfp)
740                 if(pubkeys_havepriv[keyid])
741                         strlcpy(idfp, pubkeys_priv_fp64[keyid], keyfplen);
742         return 1;
743 }
744 // end
745
746 // init/shutdown code
747 static void Crypto_BuildChallengeAppend(void)
748 {
749         char *p, *lengthptr, *startptr;
750         size_t n;
751         int i;
752         p = challenge_append;
753         n = sizeof(challenge_append);
754         Crypto_UnLittleLong(p, PROTOCOL_VLEN);
755         p += 4;
756         n -= 4;
757         lengthptr = p;
758         Crypto_UnLittleLong(p, 0);
759         p += 4;
760         n -= 4;
761         Crypto_UnLittleLong(p, PROTOCOL_D0_BLIND_ID);
762         p += 4;
763         n -= 4;
764         startptr = p;
765         for(i = 0; i < MAX_PUBKEYS; ++i)
766                 if(pubkeys_havepriv[i])
767                         PutWithNul(&p, &n, pubkeys_fp64[i]);
768         PutWithNul(&p, &n, "");
769         for(i = 0; i < MAX_PUBKEYS; ++i)
770                 if(!pubkeys_havepriv[i] && pubkeys[i])
771                         PutWithNul(&p, &n, pubkeys_fp64[i]);
772         Crypto_UnLittleLong(lengthptr, p - startptr);
773         challenge_append_length = p - challenge_append;
774 }
775
776 static void Crypto_LoadKeys(void)
777 {
778         char buf[8192];
779         size_t len, len2;
780         int i;
781
782         // load keys
783         // note: we are just a CLIENT
784         // so we load:
785         //   PUBLIC KEYS to accept (including modulus)
786         //   PRIVATE KEY of user
787
788         crypto_idstring = NULL;
789         dpsnprintf(crypto_idstring_buf, sizeof(crypto_idstring_buf), "%d", d0_rijndael_dll ? crypto_aeslevel.integer : 0);
790         for(i = 0; i < MAX_PUBKEYS; ++i)
791         {
792                 memset(pubkeys_fp64[i], 0, sizeof(pubkeys_fp64[i]));
793                 memset(pubkeys_priv_fp64[i], 0, sizeof(pubkeys_fp64[i]));
794                 pubkeys_havepriv[i] = false;
795                 len = Crypto_LoadFile(va("key_%d.d0pk", i), buf, sizeof(buf));
796                 if((pubkeys[i] = Crypto_ReadPublicKey(buf, len)))
797                 {
798                         len2 = FP64_SIZE;
799                         if(qd0_blind_id_fingerprint64_public_key(pubkeys[i], pubkeys_fp64[i], &len2)) // keeps final NUL
800                         {
801                                 Con_Printf("Loaded public key key_%d.d0pk (fingerprint: %s)\n", i, pubkeys_fp64[i]);
802                                 len = Crypto_LoadFile(va("key_%d.d0si", i), buf, sizeof(buf));
803                                 if(len)
804                                 {
805                                         if(Crypto_AddPrivateKey(pubkeys[i], buf, len))
806                                         {
807                                                 len2 = FP64_SIZE;
808                                                 if(qd0_blind_id_fingerprint64_public_id(pubkeys[i], pubkeys_priv_fp64[i], &len2)) // keeps final NUL
809                                                 {
810                                                         Con_Printf("Loaded private ID key_%d.d0si for key_%d.d0pk (fingerprint: %s)\n", i, i, pubkeys_priv_fp64[i]);
811                                                         pubkeys_havepriv[i] = true;
812                                                         strlcat(crypto_idstring_buf, va(" %s@%s", pubkeys_priv_fp64[i], pubkeys_fp64[i]), sizeof(crypto_idstring_buf));
813                                                 }
814                                                 else
815                                                 {
816                                                         // can't really happen
817                                                         // but nothing leaked here
818                                                 }
819                                         }
820                                 }
821                         }
822                         else
823                         {
824                                 // can't really happen
825                                 qd0_blind_id_free(pubkeys[i]);
826                                 pubkeys[i] = NULL;
827                         }
828                 }
829         }
830         crypto_idstring = crypto_idstring_buf;
831
832         keygen_i = -1;
833         Crypto_BuildChallengeAppend();
834
835         // find a good prefix length for all the keys we know (yes, algorithm is not perfect yet, may yield too long prefix length)
836         crypto_keyfp_recommended_length = 0;
837         memset(buf+256, 0, MAX_PUBKEYS + MAX_PUBKEYS);
838         while(crypto_keyfp_recommended_length < FP64_SIZE)
839         {
840                 memset(buf, 0, 256);
841                 for(i = 0; i < MAX_PUBKEYS; ++i)
842                         if(pubkeys[i])
843                         {
844                                 if(!buf[256 + i])
845                                         ++buf[(unsigned char) pubkeys_fp64[i][crypto_keyfp_recommended_length]];
846                                 if(pubkeys_havepriv[i])
847                                         if(!buf[256 + MAX_PUBKEYS + i])
848                                                 ++buf[(unsigned char) pubkeys_priv_fp64[i][crypto_keyfp_recommended_length]];
849                         }
850                 for(i = 0; i < MAX_PUBKEYS; ++i)
851                         if(pubkeys[i])
852                         {
853                                 if(!buf[256 + i])
854                                         if(buf[(unsigned char) pubkeys_fp64[i][crypto_keyfp_recommended_length]] < 2)
855                                                 buf[256 + i] = 1;
856                                 if(pubkeys_havepriv[i])
857                                         if(!buf[256 + MAX_PUBKEYS + i])
858                                                 if(buf[(unsigned char) pubkeys_priv_fp64[i][crypto_keyfp_recommended_length]] < 2)
859                                                         buf[256 + MAX_PUBKEYS + i] = 1;
860                         }
861                 ++crypto_keyfp_recommended_length;
862                 for(i = 0; i < MAX_PUBKEYS; ++i)
863                         if(pubkeys[i])
864                         {
865                                 if(!buf[256 + i])
866                                         break;
867                                 if(pubkeys_havepriv[i])
868                                         if(!buf[256 + MAX_PUBKEYS + i])
869                                                 break;
870                         }
871                 if(i >= MAX_PUBKEYS)
872                         break;
873         }
874         if(crypto_keyfp_recommended_length < 7)
875                 crypto_keyfp_recommended_length = 7;
876 }
877
878 static void Crypto_UnloadKeys(void)
879 {
880         int i;
881         keygen_i = -1;
882         for(i = 0; i < MAX_PUBKEYS; ++i)
883         {
884                 if(pubkeys[i])
885                         qd0_blind_id_free(pubkeys[i]);
886                 pubkeys[i] = NULL;
887                 pubkeys_havepriv[i] = false;
888                 memset(pubkeys_fp64[i], 0, sizeof(pubkeys_fp64[i]));
889                 memset(pubkeys_priv_fp64[i], 0, sizeof(pubkeys_fp64[i]));
890                 challenge_append_length = 0;
891         }
892         crypto_idstring = NULL;
893 }
894
895 void Crypto_Shutdown(void)
896 {
897         crypto_t *crypto;
898         int i;
899
900         Crypto_Rijndael_CloseLibrary();
901
902         if(d0_blind_id_dll)
903         {
904                 // free memory
905                 for(i = 0; i < MAX_CRYPTOCONNECTS; ++i)
906                 {
907                         crypto = &cryptoconnects[i].crypto;
908                         CLEAR_CDATA;
909                 }
910                 memset(cryptoconnects, 0, sizeof(cryptoconnects));
911                 crypto = &cls.crypto;
912                 CLEAR_CDATA;
913
914                 Crypto_UnloadKeys();
915
916                 qd0_blind_id_SHUTDOWN();
917
918                 Crypto_CloseLibrary();
919         }
920 }
921
922 void Crypto_Init(void)
923 {
924         if(!Crypto_OpenLibrary())
925                 return;
926
927         if(!qd0_blind_id_INITIALIZE())
928         {
929                 Crypto_Rijndael_CloseLibrary();
930                 Crypto_CloseLibrary();
931                 Con_Printf("libd0_blind_id initialization FAILED, cryptography support has been disabled\n");
932                 return;
933         }
934
935         Crypto_Rijndael_OpenLibrary(); // if this fails, it's uncritical
936
937         Crypto_InitHostKeys();
938         Crypto_LoadKeys();
939 }
940 // end
941
942 // keygen code
943 static void Crypto_KeyGen_Finished(int code, size_t length_received, unsigned char *buffer, void *cbdata)
944 {
945         const char *p[1];
946         size_t l[1];
947         static char buf[8192];
948         static char buf2[8192];
949         size_t bufsize, buf2size;
950         qfile_t *f = NULL;
951         d0_blind_id_t *ctx, *ctx2;
952         D0_BOOL status;
953         size_t len2;
954
955         if(!d0_blind_id_dll)
956         {
957                 Con_Print("libd0_blind_id DLL not found, this command is inactive.\n");
958                 keygen_i = -1;
959                 return;
960         }
961
962         if(keygen_i >= MAX_PUBKEYS || !pubkeys[keygen_i])
963         {
964                 Con_Printf("overflow of keygen_i\n");
965                 keygen_i = -1;
966                 return;
967         }
968         if(keygen_i < 0)
969         {
970                 Con_Printf("Unexpected response from keygen server:\n");
971                 Com_HexDumpToConsole(buffer, length_received);
972                 return;
973         }
974         if(!Crypto_ParsePack((const char *) buffer, length_received, FOURCC_D0IR, p, l, 1))
975         {
976                 if(length_received >= 5 && Crypto_LittleLong((const char *) buffer) == FOURCC_D0ER)
977                 {
978                         Con_Printf("Error response from keygen server: %.*s\n", (int)(length_received - 5), buffer + 5);
979                 }
980                 else
981                 {
982                         Con_Printf("Invalid response from keygen server:\n");
983                         Com_HexDumpToConsole(buffer, length_received);
984                 }
985                 keygen_i = -1;
986                 return;
987         }
988         if(!qd0_blind_id_finish_private_id_request(pubkeys[keygen_i], p[0], l[0]))
989         {
990                 Con_Printf("d0_blind_id_finish_private_id_request failed\n");
991                 keygen_i = -1;
992                 return;
993         }
994
995         // verify the key we just got (just in case)
996         ctx = qd0_blind_id_new();
997         if(!ctx)
998         {
999                 Con_Printf("d0_blind_id_new failed\n");
1000                 keygen_i = -1;
1001                 return;
1002         }
1003         ctx2 = qd0_blind_id_new();
1004         if(!ctx2)
1005         {
1006                 Con_Printf("d0_blind_id_new failed\n");
1007                 qd0_blind_id_free(ctx);
1008                 keygen_i = -1;
1009                 return;
1010         }
1011         if(!qd0_blind_id_copy(ctx, pubkeys[keygen_i]))
1012         {
1013                 Con_Printf("d0_blind_id_copy failed\n");
1014                 qd0_blind_id_free(ctx);
1015                 qd0_blind_id_free(ctx2);
1016                 keygen_i = -1;
1017                 return;
1018         }
1019         if(!qd0_blind_id_copy(ctx2, pubkeys[keygen_i]))
1020         {
1021                 Con_Printf("d0_blind_id_copy failed\n");
1022                 qd0_blind_id_free(ctx);
1023                 qd0_blind_id_free(ctx2);
1024                 keygen_i = -1;
1025                 return;
1026         }
1027         bufsize = sizeof(buf);
1028         if(!qd0_blind_id_authenticate_with_private_id_start(ctx, 1, 1, "hello world", 11, buf, &bufsize))
1029         {
1030                 Con_Printf("d0_blind_id_authenticate_with_private_id_start failed\n");
1031                 qd0_blind_id_free(ctx);
1032                 qd0_blind_id_free(ctx2);
1033                 keygen_i = -1;
1034                 return;
1035         }
1036         buf2size = sizeof(buf2);
1037         if(!qd0_blind_id_authenticate_with_private_id_challenge(ctx2, 1, 1, buf, bufsize, buf2, &buf2size, &status) || !status)
1038         {
1039                 Con_Printf("d0_blind_id_authenticate_with_private_id_challenge failed (server does not have the requested private key)\n");
1040                 qd0_blind_id_free(ctx);
1041                 qd0_blind_id_free(ctx2);
1042                 keygen_i = -1;
1043                 return;
1044         }
1045         bufsize = sizeof(buf);
1046         if(!qd0_blind_id_authenticate_with_private_id_response(ctx, buf2, buf2size, buf, &bufsize))
1047         {
1048                 Con_Printf("d0_blind_id_authenticate_with_private_id_response failed\n");
1049                 qd0_blind_id_free(ctx);
1050                 qd0_blind_id_free(ctx2);
1051                 keygen_i = -1;
1052                 return;
1053         }
1054         buf2size = sizeof(buf2);
1055         if(!qd0_blind_id_authenticate_with_private_id_verify(ctx2, buf, bufsize, buf2, &buf2size, &status) || !status)
1056         {
1057                 Con_Printf("d0_blind_id_authenticate_with_private_id_verify failed (server does not have the requested private key)\n");
1058                 qd0_blind_id_free(ctx);
1059                 qd0_blind_id_free(ctx2);
1060                 keygen_i = -1;
1061                 return;
1062         }
1063         qd0_blind_id_free(ctx);
1064         qd0_blind_id_free(ctx2);
1065
1066         // we have a valid key now!
1067         // make the rest of crypto.c know that
1068         len2 = FP64_SIZE;
1069         if(qd0_blind_id_fingerprint64_public_id(pubkeys[keygen_i], pubkeys_priv_fp64[keygen_i], &len2)) // keeps final NUL
1070         {
1071                 Con_Printf("Received private ID key_%d.d0pk (fingerprint: %s)\n", keygen_i, pubkeys_priv_fp64[keygen_i]);
1072                 pubkeys_havepriv[keygen_i] = true;
1073                 strlcat(crypto_idstring_buf, va(" %s@%s", pubkeys_priv_fp64[keygen_i], pubkeys_fp64[keygen_i]), sizeof(crypto_idstring_buf));
1074                 crypto_idstring = crypto_idstring_buf;
1075                 Crypto_BuildChallengeAppend();
1076         }
1077         // write the key to disk
1078         p[0] = buf;
1079         l[0] = sizeof(buf);
1080         if(!qd0_blind_id_write_private_id(pubkeys[keygen_i], buf, &l[0]))
1081         {
1082                 Con_Printf("d0_blind_id_write_private_id failed\n");
1083                 keygen_i = -1;
1084                 return;
1085         }
1086         if(!(buf2size = Crypto_UnParsePack(buf2, sizeof(buf2), FOURCC_D0SI, p, l, 1)))
1087         {
1088                 Con_Printf("Crypto_UnParsePack failed\n");
1089                 keygen_i = -1;
1090                 return;
1091         }
1092
1093         if(*fs_userdir)
1094         {
1095                 FS_CreatePath(va("%skey_%d.d0si", fs_userdir, keygen_i));
1096                 f = FS_SysOpen(va("%skey_%d.d0si", fs_userdir, keygen_i), "wb", false);
1097         }
1098         if(!f)
1099         {
1100                 FS_CreatePath(va("%skey_%d.d0si", fs_basedir, keygen_i));
1101                 f = FS_SysOpen(va("%skey_%d.d0si", fs_basedir, keygen_i), "wb", false);
1102         }
1103         if(!f)
1104         {
1105                 Con_Printf("Cannot open key_%d.d0si\n", keygen_i);
1106                 keygen_i = -1;
1107                 return;
1108         }
1109         FS_Write(f, buf2, buf2size);
1110         FS_Close(f);
1111
1112         Con_Printf("Saved to key_%d.d0si\n", keygen_i);
1113         keygen_i = -1;
1114 }
1115
1116 static void Crypto_KeyGen_f(void)
1117 {
1118         int i;
1119         const char *p[1];
1120         size_t l[1];
1121         static char buf[8192];
1122         static char buf2[8192];
1123         size_t buf2l, buf2pos;
1124         if(!d0_blind_id_dll)
1125         {
1126                 Con_Print("libd0_blind_id DLL not found, this command is inactive.\n");
1127                 return;
1128         }
1129         if(Cmd_Argc() != 3)
1130         {
1131                 Con_Printf("usage:\n%s id url\n", Cmd_Argv(0));
1132                 return;
1133         }
1134         i = atoi(Cmd_Argv(1));
1135         if(!pubkeys[i])
1136         {
1137                 Con_Printf("there is no public key %d\n", i);
1138                 return;
1139         }
1140         if(pubkeys_havepriv[i])
1141         {
1142                 Con_Printf("there is already a private key for %d\n", i);
1143                 return;
1144         }
1145         if(keygen_i >= 0)
1146         {
1147                 Con_Printf("there is already a keygen run on the way\n");
1148                 return;
1149         }
1150         keygen_i = i;
1151         if(!qd0_blind_id_generate_private_id_start(pubkeys[keygen_i]))
1152         {
1153                 Con_Printf("d0_blind_id_start failed\n");
1154                 keygen_i = -1;
1155                 return;
1156         }
1157         p[0] = buf;
1158         l[0] = sizeof(buf);
1159         if(!qd0_blind_id_generate_private_id_request(pubkeys[keygen_i], buf, &l[0]))
1160         {
1161                 Con_Printf("d0_blind_id_generate_private_id_request failed\n");
1162                 keygen_i = -1;
1163                 return;
1164         }
1165         buf2pos = strlen(Cmd_Argv(2));
1166         memcpy(buf2, Cmd_Argv(2), buf2pos);
1167         if(!(buf2l = Crypto_UnParsePack(buf2 + buf2pos, sizeof(buf2) - buf2pos - 1, FOURCC_D0IQ, p, l, 1)))
1168         {
1169                 Con_Printf("Crypto_UnParsePack failed\n");
1170                 keygen_i = -1;
1171                 return;
1172         }
1173         if(!(buf2l = base64_encode((unsigned char *) (buf2 + buf2pos), buf2l, sizeof(buf2) - buf2pos - 1)))
1174         {
1175                 Con_Printf("base64_encode failed\n");
1176                 keygen_i = -1;
1177                 return;
1178         }
1179         buf2l += buf2pos;
1180         buf[buf2l] = 0;
1181         if(!Curl_Begin_ToMemory(buf2, 0, (unsigned char *) keygen_buf, sizeof(keygen_buf), Crypto_KeyGen_Finished, NULL))
1182         {
1183                 Con_Printf("curl failed\n");
1184                 keygen_i = -1;
1185                 return;
1186         }
1187         Con_Printf("key generation in progress\n");
1188 }
1189 // end
1190
1191 // console commands
1192 static void Crypto_Reload_f(void)
1193 {
1194         Crypto_ClearHostKeys();
1195         Crypto_UnloadKeys();
1196         Crypto_LoadKeys();
1197 }
1198
1199 static void Crypto_Keys_f(void)
1200 {
1201         int i;
1202         if(!d0_blind_id_dll)
1203         {
1204                 Con_Print("libd0_blind_id DLL not found, this command is inactive.\n");
1205                 return;
1206         }
1207         for(i = 0; i < MAX_PUBKEYS; ++i)
1208         {
1209                 if(pubkeys[i])
1210                 {
1211                         Con_Printf("%2d: public key key_%d.d0pk (fingerprint: %s)\n", i, i, pubkeys_fp64[i]);
1212                         if(pubkeys_havepriv[i])
1213                                 Con_Printf("   private key key_%d.d0si (fingerprint: %s)\n", i, pubkeys_priv_fp64[i]);
1214                 }
1215         }
1216 }
1217
1218 static void Crypto_HostKeys_f(void)
1219 {
1220         int i;
1221         crypto_storedhostkey_t *hk;
1222         char buf[128];
1223
1224         if(!d0_blind_id_dll)
1225         {
1226                 Con_Print("libd0_blind_id DLL not found, this command is inactive.\n");
1227                 return;
1228         }
1229         for(i = 0; i < CRYPTO_HOSTKEY_HASHSIZE; ++i)
1230         {
1231                 for(hk = crypto_storedhostkey_hashtable[i]; hk; hk = hk->next)
1232                 {
1233                         LHNETADDRESS_ToString(&hk->addr, buf, sizeof(buf), 1);
1234                         Con_Printf("%d %s@%.*s %s\n",
1235                                         hk->aeslevel,
1236                                         hk->idfp,
1237                                         crypto_keyfp_recommended_length, pubkeys_fp64[hk->keyid],
1238                                         buf);
1239                 }
1240         }
1241 }
1242
1243 static void Crypto_HostKey_Clear_f(void)
1244 {
1245         lhnetaddress_t addr;
1246         int i;
1247
1248         if(!d0_blind_id_dll)
1249         {
1250                 Con_Print("libd0_blind_id DLL not found, this command is inactive.\n");
1251                 return;
1252         }
1253
1254         for(i = 1; i < Cmd_Argc(); ++i)
1255         {
1256                 LHNETADDRESS_FromString(&addr, Cmd_Argv(i), 26000);
1257                 if(Crypto_ClearHostKey(&addr))
1258                 {
1259                         Con_Printf("cleared host key for %s\n", Cmd_Argv(i));
1260                 }
1261         }
1262 }
1263
1264 void Crypto_Init_Commands(void)
1265 {
1266         if(d0_blind_id_dll)
1267         {
1268                 Cmd_AddCommand("crypto_reload", Crypto_Reload_f, "reloads cryptographic keys");
1269                 Cmd_AddCommand("crypto_keygen", Crypto_KeyGen_f, "generates and saves a cryptographic key");
1270                 Cmd_AddCommand("crypto_keys", Crypto_Keys_f, "lists the loaded keys");
1271                 Cmd_AddCommand("crypto_hostkeys", Crypto_HostKeys_f, "lists the cached host keys");
1272                 Cmd_AddCommand("crypto_hostkey_clear", Crypto_HostKey_Clear_f, "clears a cached host key");
1273                 Cvar_RegisterVariable(&crypto_developer);
1274                 if(d0_rijndael_dll)
1275                         Cvar_RegisterVariable(&crypto_aeslevel);
1276                 else
1277                         crypto_aeslevel.integer = 0; // make sure
1278                 Cvar_RegisterVariable(&crypto_servercpupercent);
1279                 Cvar_RegisterVariable(&crypto_servercpumaxtime);
1280                 Cvar_RegisterVariable(&crypto_servercpudebug);
1281         }
1282 }
1283 // end
1284
1285 // AES encryption
1286 static void aescpy(unsigned char *key, const unsigned char *iv, unsigned char *dst, const unsigned char *src, size_t len)
1287 {
1288         const unsigned char *xorpos = iv;
1289         unsigned char xorbuf[16];
1290         unsigned long rk[D0_RIJNDAEL_RKLENGTH(DHKEY_SIZE * 8)];
1291         size_t i;
1292         qd0_rijndael_setup_encrypt(rk, key, DHKEY_SIZE * 8);
1293         while(len > 16)
1294         {
1295                 for(i = 0; i < 16; ++i)
1296                         xorbuf[i] = src[i] ^ xorpos[i];
1297                 qd0_rijndael_encrypt(rk, D0_RIJNDAEL_NROUNDS(DHKEY_SIZE * 8), xorbuf, dst);
1298                 xorpos = dst;
1299                 len -= 16;
1300                 src += 16;
1301                 dst += 16;
1302         }
1303         if(len > 0)
1304         {
1305                 for(i = 0; i < len; ++i)
1306                         xorbuf[i] = src[i] ^ xorpos[i];
1307                 for(; i < 16; ++i)
1308                         xorbuf[i] = xorpos[i];
1309                 qd0_rijndael_encrypt(rk, D0_RIJNDAEL_NROUNDS(DHKEY_SIZE * 8), xorbuf, dst);
1310         }
1311 }
1312 static void seacpy(unsigned char *key, const unsigned char *iv, unsigned char *dst, const unsigned char *src, size_t len)
1313 {
1314         const unsigned char *xorpos = iv;
1315         unsigned char xorbuf[16];
1316         unsigned long rk[D0_RIJNDAEL_RKLENGTH(DHKEY_SIZE * 8)];
1317         size_t i;
1318         qd0_rijndael_setup_decrypt(rk, key, DHKEY_SIZE * 8);
1319         while(len > 16)
1320         {
1321                 qd0_rijndael_decrypt(rk, D0_RIJNDAEL_NROUNDS(DHKEY_SIZE * 8), src, xorbuf);
1322                 for(i = 0; i < 16; ++i)
1323                         dst[i] = xorbuf[i] ^ xorpos[i];
1324                 xorpos = src;
1325                 len -= 16;
1326                 src += 16;
1327                 dst += 16;
1328         }
1329         if(len > 0)
1330         {
1331                 qd0_rijndael_decrypt(rk, D0_RIJNDAEL_NROUNDS(DHKEY_SIZE * 8), src, xorbuf);
1332                 for(i = 0; i < len; ++i)
1333                         dst[i] = xorbuf[i] ^ xorpos[i];
1334         }
1335 }
1336
1337 const void *Crypto_EncryptPacket(crypto_t *crypto, const void *data_src, size_t len_src, void *data_dst, size_t *len_dst, size_t len)
1338 {
1339         unsigned char h[32];
1340         if(crypto->authenticated)
1341         {
1342                 if(crypto->use_aes)
1343                 {
1344                         // AES packet = 1 byte length overhead, 15 bytes from HMAC-SHA-256, data, 0..15 bytes padding
1345                         // 15 bytes HMAC-SHA-256 (112bit) suffice as the attacker can't do more than forge a random-looking packet
1346                         // HMAC is needed to not leak information about packet content
1347                         if(developer_networking.integer)
1348                         {
1349                                 Con_Print("To be encrypted:\n");
1350                                 Com_HexDumpToConsole((const unsigned char *) data_src, len_src);
1351                         }
1352                         if(len_src + 32 > len || !HMAC_SHA256_32BYTES(h, (const unsigned char *) data_src, len_src, crypto->dhkey, DHKEY_SIZE))
1353                         {
1354                                 Con_Printf("Crypto_EncryptPacket failed (not enough space: %d bytes in, %d bytes out)\n", (int) len_src, (int) len);
1355                                 return NULL;
1356                         }
1357                         *len_dst = ((len_src + 15) / 16) * 16 + 16; // add 16 for HMAC, then round to 16-size for AES
1358                         ((unsigned char *) data_dst)[0] = *len_dst - len_src;
1359                         memcpy(((unsigned char *) data_dst)+1, h, 15);
1360                         aescpy(crypto->dhkey, (const unsigned char *) data_dst, ((unsigned char *) data_dst) + 16, (const unsigned char *) data_src, len_src);
1361                         //                    IV                                dst                                src                               len
1362                 }
1363                 else
1364                 {
1365                         // HMAC packet = 16 bytes HMAC-SHA-256 (truncated to 128 bits), data
1366                         if(len_src + 16 > len || !HMAC_SHA256_32BYTES(h, (const unsigned char *) data_src, len_src, crypto->dhkey, DHKEY_SIZE))
1367                         {
1368                                 Con_Printf("Crypto_EncryptPacket failed (not enough space: %d bytes in, %d bytes out)\n", (int) len_src, (int) len);
1369                                 return NULL;
1370                         }
1371                         *len_dst = len_src + 16;
1372                         memcpy(data_dst, h, 16);
1373                         memcpy(((unsigned char *) data_dst) + 16, (unsigned char *) data_src, len_src);
1374                 }
1375                 return data_dst;
1376         }
1377         else
1378         {
1379                 *len_dst = len_src;
1380                 return data_src;
1381         }
1382 }
1383
1384 const void *Crypto_DecryptPacket(crypto_t *crypto, const void *data_src, size_t len_src, void *data_dst, size_t *len_dst, size_t len)
1385 {
1386         unsigned char h[32];
1387         if(crypto->authenticated)
1388         {
1389                 if(crypto->use_aes)
1390                 {
1391                         if(len_src < 16 || ((len_src - 16) % 16))
1392                         {
1393                                 Con_Printf("Crypto_DecryptPacket failed (not enough space: %d bytes in, %d bytes out)\n", (int) len_src, (int) len);
1394                                 return NULL;
1395                         }
1396                         *len_dst = len_src - ((unsigned char *) data_src)[0];
1397                         if(len < *len_dst || *len_dst > len_src - 16)
1398                         {
1399                                 Con_Printf("Crypto_DecryptPacket failed (not enough space: %d bytes in, %d->%d bytes out)\n", (int) len_src, (int) *len_dst, (int) len);
1400                                 return NULL;
1401                         }
1402                         seacpy(crypto->dhkey, (unsigned char *) data_src, (unsigned char *) data_dst, ((const unsigned char *) data_src) + 16, *len_dst);
1403                         //                    IV                          dst                         src                                      len
1404                         if(!HMAC_SHA256_32BYTES(h, (const unsigned char *) data_dst, *len_dst, crypto->dhkey, DHKEY_SIZE))
1405                         {
1406                                 Con_Printf("HMAC fail\n");
1407                                 return NULL;
1408                         }
1409                         if(memcmp(((const unsigned char *) data_src)+1, h, 15)) // ignore first byte, used for length
1410                         {
1411                                 Con_Printf("HMAC mismatch\n");
1412                                 return NULL;
1413                         }
1414                         if(developer_networking.integer)
1415                         {
1416                                 Con_Print("Decrypted:\n");
1417                                 Com_HexDumpToConsole((const unsigned char *) data_dst, *len_dst);
1418                         }
1419                         return data_dst; // no need to copy
1420                 }
1421                 else
1422                 {
1423                         if(len_src < 16)
1424                         {
1425                                 Con_Printf("Crypto_DecryptPacket failed (not enough space: %d bytes in, %d bytes out)\n", (int) len_src, (int) len);
1426                                 return NULL;
1427                         }
1428                         *len_dst = len_src - 16;
1429                         if(len < *len_dst)
1430                         {
1431                                 Con_Printf("Crypto_DecryptPacket failed (not enough space: %d bytes in, %d->%d bytes out)\n", (int) len_src, (int) *len_dst, (int) len);
1432                                 return NULL;
1433                         }
1434                         //memcpy(data_dst, data_src + 16, *len_dst);
1435                         if(!HMAC_SHA256_32BYTES(h, ((const unsigned char *) data_src) + 16, *len_dst, crypto->dhkey, DHKEY_SIZE))
1436                         {
1437                                 Con_Printf("HMAC fail\n");
1438                                 Com_HexDumpToConsole((const unsigned char *) data_src, len_src);
1439                                 return NULL;
1440                         }
1441                         if(memcmp((const unsigned char *) data_src, h, 16)) // ignore first byte, used for length
1442                         {
1443                                 Con_Printf("HMAC mismatch\n");
1444                                 Com_HexDumpToConsole((const unsigned char *) data_src, len_src);
1445                                 return NULL;
1446                         }
1447                         return ((const unsigned char *) data_src) + 16; // no need to copy, so data_dst is not used
1448                 }
1449         }
1450         else
1451         {
1452                 *len_dst = len_src;
1453                 return data_src;
1454         }
1455 }
1456 // end
1457
1458 const char *Crypto_GetInfoResponseDataString(void)
1459 {
1460         crypto_idstring_buf[0] = '0' + crypto_aeslevel.integer;
1461         return crypto_idstring;
1462 }
1463
1464 // network protocol
1465 qboolean Crypto_ServerAppendToChallenge(const char *data_in, size_t len_in, char *data_out, size_t *len_out, size_t maxlen_out)
1466 {
1467         // cheap op, all is precomputed
1468         if(!d0_blind_id_dll)
1469                 return false; // no support
1470         // append challenge
1471         if(maxlen_out <= *len_out + challenge_append_length)
1472                 return false;
1473         memcpy(data_out + *len_out, challenge_append, challenge_append_length);
1474         *len_out += challenge_append_length;
1475         return false;
1476 }
1477
1478 static int Crypto_ServerError(char *data_out, size_t *len_out, const char *msg, const char *msg_client)
1479 {
1480         if(!msg_client)
1481                 msg_client = msg;
1482         Con_DPrintf("rejecting client: %s\n", msg);
1483         if(*msg_client)
1484                 dpsnprintf(data_out, *len_out, "reject %s", msg_client);
1485         *len_out = strlen(data_out);
1486         return CRYPTO_DISCARD;
1487 }
1488
1489 static int Crypto_SoftServerError(char *data_out, size_t *len_out, const char *msg)
1490 {
1491         *len_out = 0;
1492         Con_DPrintf("%s\n", msg);
1493         return CRYPTO_DISCARD;
1494 }
1495
1496 static int Crypto_ServerParsePacket_Internal(const char *data_in, size_t len_in, char *data_out, size_t *len_out, lhnetaddress_t *peeraddress)
1497 {
1498         // if "connect": reject if in the middle of crypto handshake
1499         crypto_t *crypto = NULL;
1500         char *data_out_p = data_out;
1501         const char *string = data_in;
1502         int aeslevel;
1503         D0_BOOL aes;
1504         D0_BOOL status;
1505
1506         if(!d0_blind_id_dll)
1507                 return CRYPTO_NOMATCH; // no support
1508
1509         if (len_in > 8 && !memcmp(string, "connect\\", 8) && d0_rijndael_dll && crypto_aeslevel.integer >= 3)
1510         {
1511                 const char *s;
1512                 int i;
1513                 // sorry, we have to verify the challenge here to not reflect network spam
1514
1515                 if (!(s = SearchInfostring(string + 4, "challenge")))
1516                         return CRYPTO_NOMATCH; // will be later accepted if encryption was set up
1517                 // validate the challenge
1518                 for (i = 0;i < MAX_CHALLENGES;i++)
1519                         if(challenge[i].time > 0)
1520                                 if (!LHNETADDRESS_Compare(peeraddress, &challenge[i].address) && !strcmp(challenge[i].string, s))
1521                                         break;
1522                 // if the challenge is not recognized, drop the packet
1523                 if (i == MAX_CHALLENGES) // challenge mismatch is silent
1524                         return CRYPTO_DISCARD; // pre-challenge: rather be silent
1525
1526                 crypto = Crypto_ServerFindInstance(peeraddress, false);
1527                 if(!crypto || !crypto->authenticated)
1528                         return Crypto_ServerError(data_out, len_out, "This server requires authentication and encryption to be supported by your client", NULL);
1529         }
1530         else if(len_in > 5 && !memcmp(string, "d0pk\\", 5) && ((LHNETADDRESS_GetAddressType(peeraddress) == LHNETADDRESSTYPE_LOOP) || sv_public.integer > -3))
1531         {
1532                 const char *cnt, *s, *p;
1533                 int id;
1534                 int clientid = -1, serverid = -1;
1535                 cnt = SearchInfostring(string + 4, "id");
1536                 id = (cnt ? atoi(cnt) : -1);
1537                 cnt = SearchInfostring(string + 4, "cnt");
1538                 if(!cnt)
1539                         return CRYPTO_DISCARD; // pre-challenge: rather be silent
1540                 GetUntilNul(&data_in, &len_in);
1541                 if(!data_in)
1542                         return CRYPTO_DISCARD; // pre-challenge: rather be silent
1543                 if(!strcmp(cnt, "0"))
1544                 {
1545                         int i;
1546                         if (!(s = SearchInfostring(string + 4, "challenge")))
1547                                 return CRYPTO_DISCARD; // pre-challenge: rather be silent
1548                         // validate the challenge
1549                         for (i = 0;i < MAX_CHALLENGES;i++)
1550                                 if(challenge[i].time > 0)
1551                                         if (!LHNETADDRESS_Compare(peeraddress, &challenge[i].address) && !strcmp(challenge[i].string, s))
1552                                                 break;
1553                         // if the challenge is not recognized, drop the packet
1554                         if (i == MAX_CHALLENGES) // challenge mismatch is silent
1555                                 return CRYPTO_DISCARD; // pre-challenge: rather be silent
1556
1557                         if (!(s = SearchInfostring(string + 4, "aeslevel")))
1558                                 aeslevel = 0; // not supported
1559                         else
1560                                 aeslevel = bound(0, atoi(s), 3);
1561                         switch(bound(0, d0_rijndael_dll ? crypto_aeslevel.integer : 0, 3))
1562                         {
1563                                 default: // dummy, never happens, but to make gcc happy...
1564                                 case 0:
1565                                         if(aeslevel >= 3)
1566                                                 return Crypto_ServerError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)", NULL);
1567                                         aes = false;
1568                                         break;
1569                                 case 1:
1570                                         aes = (aeslevel >= 2);
1571                                         break;
1572                                 case 2:
1573                                         aes = (aeslevel >= 1);
1574                                         break;
1575                                 case 3:
1576                                         if(aeslevel <= 0)
1577                                                 return Crypto_ServerError(data_out, len_out, "This server requires encryption to be supported (crypto_aeslevel >= 1, and d0_rijndael library must be present)", NULL);
1578                                         aes = true;
1579                                         break;
1580                         }
1581
1582                         p = GetUntilNul(&data_in, &len_in);
1583                         if(p && *p)
1584                         {
1585                                 for(i = 0; i < MAX_PUBKEYS; ++i)
1586                                 {
1587                                         if(pubkeys[i])
1588                                                 if(!strcmp(p, pubkeys_fp64[i]))
1589                                                         if(pubkeys_havepriv[i])
1590                                                                 if(serverid < 0)
1591                                                                         serverid = i;
1592                                 }
1593                                 if(serverid < 0)
1594                                         return Crypto_ServerError(data_out, len_out, "Invalid server key", NULL);
1595                         }
1596                         p = GetUntilNul(&data_in, &len_in);
1597                         if(p && *p)
1598                         {
1599                                 for(i = 0; i < MAX_PUBKEYS; ++i)
1600                                 {
1601                                         if(pubkeys[i])
1602                                                 if(!strcmp(p, pubkeys_fp64[i]))
1603                                                         if(clientid < 0)
1604                                                                 clientid = i;
1605                                 }
1606                                 if(clientid < 0)
1607                                         return Crypto_ServerError(data_out, len_out, "Invalid client key", NULL);
1608                         }
1609
1610                         crypto = Crypto_ServerFindInstance(peeraddress, true);
1611                         if(!crypto)
1612                                 return Crypto_ServerError(data_out, len_out, "Could not create a crypto connect instance", NULL);
1613                         MAKE_CDATA;
1614                         CDATA->cdata_id = id;
1615                         CDATA->s = serverid;
1616                         CDATA->c = clientid;
1617                         memset(crypto->dhkey, 0, sizeof(crypto->dhkey));
1618                         CDATA->challenge[0] = 0;
1619                         crypto->client_keyfp[0] = 0;
1620                         crypto->client_idfp[0] = 0;
1621                         crypto->server_keyfp[0] = 0;
1622                         crypto->server_idfp[0] = 0;
1623                         crypto->use_aes = aes != 0;
1624
1625                         if(CDATA->s >= 0)
1626                         {
1627                                 // I am the server, and my key is ok... so let's set server_keyfp and server_idfp
1628                                 strlcpy(crypto->server_keyfp, pubkeys_fp64[CDATA->s], sizeof(crypto->server_keyfp));
1629                                 strlcpy(crypto->server_idfp, pubkeys_priv_fp64[CDATA->s], sizeof(crypto->server_idfp));
1630
1631                                 if(!CDATA->id)
1632                                         CDATA->id = qd0_blind_id_new();
1633                                 if(!CDATA->id)
1634                                 {
1635                                         CLEAR_CDATA;
1636                                         return Crypto_ServerError(data_out, len_out, "d0_blind_id_new failed", "Internal error");
1637                                 }
1638                                 if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->s]))
1639                                 {
1640                                         CLEAR_CDATA;
1641                                         return Crypto_ServerError(data_out, len_out, "d0_blind_id_copy failed", "Internal error");
1642                                 }
1643                                 PutWithNul(&data_out_p, len_out, va("d0pk\\cnt\\1\\id\\%d\\aes\\%d", CDATA->cdata_id, crypto->use_aes));
1644                                 if(!qd0_blind_id_authenticate_with_private_id_start(CDATA->id, true, false, "XONOTIC", 8, data_out_p, len_out)) // len_out receives used size by this op
1645                                 {
1646                                         CLEAR_CDATA;
1647                                         return Crypto_ServerError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_start failed", "Internal error");
1648                                 }
1649                                 CDATA->next_step = 2;
1650                                 data_out_p += *len_out;
1651                                 *len_out = data_out_p - data_out;
1652                                 return CRYPTO_DISCARD;
1653                         }
1654                         else if(CDATA->c >= 0)
1655                         {
1656                                 if(!CDATA->id)
1657                                         CDATA->id = qd0_blind_id_new();
1658                                 if(!CDATA->id)
1659                                 {
1660                                         CLEAR_CDATA;
1661                                         return Crypto_ServerError(data_out, len_out, "d0_blind_id_new failed", "Internal error");
1662                                 }
1663                                 if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->c]))
1664                                 {
1665                                         CLEAR_CDATA;
1666                                         return Crypto_ServerError(data_out, len_out, "d0_blind_id_copy failed", "Internal error");
1667                                 }
1668                                 PutWithNul(&data_out_p, len_out, va("d0pk\\cnt\\5\\id\\%d\\aes\\%d", CDATA->cdata_id, crypto->use_aes));
1669                                 if(!qd0_blind_id_authenticate_with_private_id_challenge(CDATA->id, true, false, data_in, len_in, data_out_p, len_out, &status))
1670                                 {
1671                                         CLEAR_CDATA;
1672                                         return Crypto_ServerError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_challenge failed", "Internal error");
1673                                 }
1674                                 CDATA->next_step = 6;
1675                                 data_out_p += *len_out;
1676                                 *len_out = data_out_p - data_out;
1677                                 return CRYPTO_DISCARD;
1678                         }
1679                         else
1680                         {
1681                                 CLEAR_CDATA;
1682                                 return Crypto_ServerError(data_out, len_out, "Missing client and server key", NULL);
1683                         }
1684                 }
1685                 else if(!strcmp(cnt, "2"))
1686                 {
1687                         size_t fpbuflen;
1688                         crypto = Crypto_ServerFindInstance(peeraddress, false);
1689                         if(!crypto)
1690                                 return CRYPTO_NOMATCH; // pre-challenge, rather be silent
1691                         if(id >= 0)
1692                                 if(CDATA->cdata_id != id)
1693                                         return Crypto_SoftServerError(data_out, len_out, va("Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
1694                         if(CDATA->next_step != 2)
1695                                 return Crypto_SoftServerError(data_out, len_out, va("Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
1696
1697                         PutWithNul(&data_out_p, len_out, va("d0pk\\cnt\\3\\id\\%d", CDATA->cdata_id));
1698                         if(!qd0_blind_id_authenticate_with_private_id_response(CDATA->id, data_in, len_in, data_out_p, len_out))
1699                         {
1700                                 CLEAR_CDATA;
1701                                 return Crypto_ServerError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_response failed", "Internal error");
1702                         }
1703                         fpbuflen = DHKEY_SIZE;
1704                         if(!qd0_blind_id_sessionkey_public_id(CDATA->id, (char *) crypto->dhkey, &fpbuflen))
1705                         {
1706                                 CLEAR_CDATA;
1707                                 return Crypto_ServerError(data_out, len_out, "d0_blind_id_sessionkey_public_id failed", "Internal error");
1708                         }
1709                         if(CDATA->c >= 0)
1710                         {
1711                                 if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->c]))
1712                                 {
1713                                         CLEAR_CDATA;
1714                                         return Crypto_ServerError(data_out, len_out, "d0_blind_id_copy failed", "Internal error");
1715                                 }
1716                                 CDATA->next_step = 4;
1717                         }
1718                         else
1719                         {
1720                                 // session key is FINISHED (no server part is to be expected)! By this, all keys are set up
1721                                 crypto->authenticated = true;
1722                                 CDATA->next_step = 0;
1723                         }
1724                         data_out_p += *len_out;
1725                         *len_out = data_out_p - data_out;
1726                         return CRYPTO_DISCARD;
1727                 }
1728                 else if(!strcmp(cnt, "4"))
1729                 {
1730                         crypto = Crypto_ServerFindInstance(peeraddress, false);
1731                         if(!crypto)
1732                                 return CRYPTO_NOMATCH; // pre-challenge, rather be silent
1733                         if(id >= 0)
1734                                 if(CDATA->cdata_id != id)
1735                                         return Crypto_SoftServerError(data_out, len_out, va("Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
1736                         if(CDATA->next_step != 4)
1737                                 return Crypto_SoftServerError(data_out, len_out, va("Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
1738                         PutWithNul(&data_out_p, len_out, va("d0pk\\cnt\\5\\id\\%d", CDATA->cdata_id));
1739                         if(!qd0_blind_id_authenticate_with_private_id_challenge(CDATA->id, true, false, data_in, len_in, data_out_p, len_out, &status))
1740                         {
1741                                 CLEAR_CDATA;
1742                                 return Crypto_ServerError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_challenge failed", "Internal error");
1743                         }
1744                         CDATA->next_step = 6;
1745                         data_out_p += *len_out;
1746                         *len_out = data_out_p - data_out;
1747                         return CRYPTO_DISCARD;
1748                 }
1749                 else if(!strcmp(cnt, "6"))
1750                 {
1751                         static char msgbuf[32];
1752                         size_t msgbuflen = sizeof(msgbuf);
1753                         size_t fpbuflen;
1754                         int i;
1755                         unsigned char dhkey[DHKEY_SIZE];
1756                         crypto = Crypto_ServerFindInstance(peeraddress, false);
1757                         if(!crypto)
1758                                 return CRYPTO_NOMATCH; // pre-challenge, rather be silent
1759                         if(id >= 0)
1760                                 if(CDATA->cdata_id != id)
1761                                         return Crypto_SoftServerError(data_out, len_out, va("Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
1762                         if(CDATA->next_step != 6)
1763                                 return Crypto_SoftServerError(data_out, len_out, va("Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
1764
1765                         if(!qd0_blind_id_authenticate_with_private_id_verify(CDATA->id, data_in, len_in, msgbuf, &msgbuflen, &status))
1766                         {
1767                                 CLEAR_CDATA;
1768                                 return Crypto_ServerError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_verify failed (authentication error)", "Authentication error");
1769                         }
1770                         if(status)
1771                                 strlcpy(crypto->client_keyfp, pubkeys_fp64[CDATA->c], sizeof(crypto->client_keyfp));
1772                         else
1773                                 crypto->client_keyfp[0] = 0;
1774                         memset(crypto->client_idfp, 0, sizeof(crypto->client_idfp));
1775                         fpbuflen = FP64_SIZE;
1776                         if(!qd0_blind_id_fingerprint64_public_id(CDATA->id, crypto->client_idfp, &fpbuflen))
1777                         {
1778                                 CLEAR_CDATA;
1779                                 return Crypto_ServerError(data_out, len_out, "d0_blind_id_fingerprint64_public_id failed", "Internal error");
1780                         }
1781                         fpbuflen = DHKEY_SIZE;
1782                         if(!qd0_blind_id_sessionkey_public_id(CDATA->id, (char *) dhkey, &fpbuflen))
1783                         {
1784                                 CLEAR_CDATA;
1785                                 return Crypto_ServerError(data_out, len_out, "d0_blind_id_sessionkey_public_id failed", "Internal error");
1786                         }
1787                         // XOR the two DH keys together to make one
1788                         for(i = 0; i < DHKEY_SIZE; ++i)
1789                                 crypto->dhkey[i] ^= dhkey[i];
1790
1791                         // session key is FINISHED (no server part is to be expected)! By this, all keys are set up
1792                         crypto->authenticated = true;
1793                         CDATA->next_step = 0;
1794                         // send a challenge-less challenge
1795                         PutWithNul(&data_out_p, len_out, "challenge ");
1796                         *len_out = data_out_p - data_out;
1797                         --*len_out; // remove NUL terminator
1798                         return CRYPTO_MATCH;
1799                 }
1800                 return CRYPTO_NOMATCH; // pre-challenge, rather be silent
1801         }
1802         return CRYPTO_NOMATCH;
1803 }
1804
1805 int Crypto_ServerParsePacket(const char *data_in, size_t len_in, char *data_out, size_t *len_out, lhnetaddress_t *peeraddress)
1806 {
1807         int ret;
1808         double t = 0;
1809         static double complain_time = 0;
1810         const char *cnt;
1811         qboolean do_time = false;
1812         qboolean do_reject = false;
1813         if(crypto_servercpupercent.value > 0 || crypto_servercpumaxtime.value > 0)
1814                 if(len_in > 5 && !memcmp(data_in, "d0pk\\", 5))
1815                 {
1816                         do_time = true;
1817                         cnt = SearchInfostring(data_in + 4, "cnt");
1818                         if(cnt)
1819                                 if(!strcmp(cnt, "0"))
1820                                         do_reject = true;
1821                 }
1822         if(do_time)
1823         {
1824                 // check if we may perform crypto...
1825                 if(crypto_servercpupercent.value > 0)
1826                 {
1827                         crypto_servercpu_accumulator += (realtime - crypto_servercpu_lastrealtime) * crypto_servercpupercent.value * 0.01;
1828                         if(crypto_servercpumaxtime.value)
1829                                 if(crypto_servercpu_accumulator > crypto_servercpumaxtime.value)
1830                                         crypto_servercpu_accumulator = crypto_servercpumaxtime.value;
1831                 }
1832                 else
1833                 {
1834                         if(crypto_servercpumaxtime.value > 0)
1835                                 if(realtime != crypto_servercpu_lastrealtime)
1836                                         crypto_servercpu_accumulator = crypto_servercpumaxtime.value;
1837                 }
1838                 crypto_servercpu_lastrealtime = realtime;
1839                 if(do_reject && crypto_servercpu_accumulator < 0)
1840                 {
1841                         if(realtime > complain_time + 5)
1842                                 Con_Printf("crypto: cannot perform requested crypto operations; denial service attack or crypto_servercpupercent/crypto_servercpumaxtime are too low\n");
1843                         *len_out = 0;
1844                         return CRYPTO_DISCARD;
1845                 }
1846                 t = Sys_DoubleTime();
1847         }
1848         ret = Crypto_ServerParsePacket_Internal(data_in, len_in, data_out, len_out, peeraddress);
1849         if(do_time)
1850         {
1851                 t = Sys_DoubleTime() - t;
1852                 if(crypto_servercpudebug.integer)
1853                         Con_Printf("crypto: accumulator was %.1f ms, used %.1f ms for crypto, ", crypto_servercpu_accumulator * 1000, t * 1000);
1854                 crypto_servercpu_accumulator -= t;
1855                 if(crypto_servercpudebug.integer)
1856                         Con_Printf("is %.1f ms\n", crypto_servercpu_accumulator * 1000);
1857         }
1858         return ret;
1859 }
1860
1861 static int Crypto_ClientError(char *data_out, size_t *len_out, const char *msg)
1862 {
1863         dpsnprintf(data_out, *len_out, "reject %s", msg);
1864         *len_out = strlen(data_out);
1865         return CRYPTO_REPLACE;
1866 }
1867
1868 static int Crypto_SoftClientError(char *data_out, size_t *len_out, const char *msg)
1869 {
1870         *len_out = 0;
1871         Con_Printf("%s\n", msg);
1872         return CRYPTO_DISCARD;
1873 }
1874
1875 int Crypto_ClientParsePacket(const char *data_in, size_t len_in, char *data_out, size_t *len_out, lhnetaddress_t *peeraddress)
1876 {
1877         crypto_t *crypto = &cls.crypto;
1878         const char *string = data_in;
1879         const char *s;
1880         D0_BOOL aes;
1881         char *data_out_p = data_out;
1882         D0_BOOL status;
1883
1884         if(!d0_blind_id_dll)
1885                 return CRYPTO_NOMATCH; // no support
1886
1887         // if "challenge": verify challenge, and discard message, send next crypto protocol message instead
1888         // otherwise, just handle actual protocol messages
1889
1890         if (len_in == 6 && !memcmp(string, "accept", 6) && cls.connect_trying && d0_rijndael_dll)
1891         {
1892                 int wantserverid = -1;
1893                 Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, NULL, 0, NULL);
1894                 if(!crypto || !crypto->authenticated)
1895                 {
1896                         if(wantserverid >= 0)
1897                                 return Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though a host key is present");
1898                         if(crypto_aeslevel.integer >= 3)
1899                                 return Crypto_ClientError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)");
1900                 }
1901                 return CRYPTO_NOMATCH;
1902         }
1903         else if (len_in >= 1 && string[0] == 'j' && cls.connect_trying && d0_rijndael_dll && crypto_aeslevel.integer >= 3)
1904         {
1905                 int wantserverid = -1;
1906                 Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, NULL, 0, NULL);
1907                 if(!crypto || !crypto->authenticated)
1908                 {
1909                         if(wantserverid >= 0)
1910                                 return Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though a host key is present");
1911                         if(crypto_aeslevel.integer >= 3)
1912                                 return Crypto_ClientError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)");
1913                 }
1914                 return CRYPTO_NOMATCH;
1915         }
1916         else if (len_in >= 13 && !memcmp(string, "infoResponse\x0A", 13))
1917         {
1918                 s = SearchInfostring(string + 13, "d0_blind_id");
1919                 if(s)
1920                         Crypto_StoreHostKey(peeraddress, s, true);
1921                 return CRYPTO_NOMATCH;
1922         }
1923         else if (len_in >= 15 && !memcmp(string, "statusResponse\x0A", 15))
1924         {
1925                 char save = 0;
1926                 const char *p;
1927                 p = strchr(string + 15, '\n');
1928                 if(p)
1929                 {
1930                         save = *p;
1931                         * (char *) p = 0; // cut off the string there
1932                 }
1933                 s = SearchInfostring(string + 15, "d0_blind_id");
1934                 if(s)
1935                         Crypto_StoreHostKey(peeraddress, s, true);
1936                 if(p)
1937                 {
1938                         * (char *) p = save;
1939                         // invoking those nasal demons again (do not run this on the DS9k)
1940                 }
1941                 return CRYPTO_NOMATCH;
1942         }
1943         else if(len_in > 10 && !memcmp(string, "challenge ", 10) && cls.connect_trying)
1944         {
1945                 const char *vlen_blind_id_ptr = NULL;
1946                 size_t len_blind_id_ptr = 0;
1947                 unsigned long k, v;
1948                 const char *challenge = data_in + 10;
1949                 const char *p;
1950                 int i;
1951                 int clientid = -1, serverid = -1, wantserverid = -1;
1952                 qboolean server_can_auth = true;
1953                 char wantserver_idfp[FP64_SIZE+1];
1954                 int wantserver_aeslevel;
1955
1956                 // if we have a stored host key for the server, assume serverid to already be selected!
1957                 // (the loop will refuse to overwrite this one then)
1958                 wantserver_idfp[0] = 0;
1959                 Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, wantserver_idfp, sizeof(wantserver_idfp), &wantserver_aeslevel);
1960                 // requirement: wantserver_idfp is a full ID if wantserverid set
1961
1962                 // if we leave, we have to consider the connection
1963                 // unauthenticated; NOTE: this may be faked by a clever
1964                 // attacker to force an unauthenticated connection; so we have
1965                 // a safeguard check in place when encryption is required too
1966                 // in place, or when authentication is required by the server
1967                 crypto->authenticated = false;
1968
1969                 GetUntilNul(&data_in, &len_in);
1970                 if(!data_in)
1971                         return (wantserverid >= 0) ? Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though a host key is present") :
1972                                 (d0_rijndael_dll && crypto_aeslevel.integer >= 3) ? Crypto_ServerError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)", NULL) :
1973                                 CRYPTO_NOMATCH;
1974
1975                 // FTEQW extension protocol
1976                 while(len_in >= 8)
1977                 {
1978                         k = Crypto_LittleLong(data_in);
1979                         v = Crypto_LittleLong(data_in + 4);
1980                         data_in += 8;
1981                         len_in -= 8;
1982                         switch(k)
1983                         {
1984                                 case PROTOCOL_VLEN:
1985                                         if(len_in >= 4 + v)
1986                                         {
1987                                                 k = Crypto_LittleLong(data_in);
1988                                                 data_in += 4;
1989                                                 len_in -= 4;
1990                                                 switch(k)
1991                                                 {
1992                                                         case PROTOCOL_D0_BLIND_ID:
1993                                                                 vlen_blind_id_ptr = data_in;
1994                                                                 len_blind_id_ptr = v;
1995                                                                 break;
1996                                                 }
1997                                                 data_in += v;
1998                                                 len_in -= v;
1999                                         }
2000                                         break;
2001                                 default:
2002                                         break;
2003                         }
2004                 }
2005
2006                 if(!vlen_blind_id_ptr)
2007                         return (wantserverid >= 0) ? Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though authentication is required") :
2008                                 (d0_rijndael_dll && crypto_aeslevel.integer >= 3) ? Crypto_ServerError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)", NULL) :
2009                                 CRYPTO_NOMATCH;
2010
2011                 data_in = vlen_blind_id_ptr;
2012                 len_in = len_blind_id_ptr;
2013
2014                 // parse fingerprints
2015                 //   once we found a fingerprint we can auth to (ANY), select it as clientfp
2016                 //   once we found a fingerprint in the first list that we know, select it as serverfp
2017
2018                 for(;;)
2019                 {
2020                         p = GetUntilNul(&data_in, &len_in);
2021                         if(!p)
2022                                 break;
2023                         if(!*p)
2024                         {
2025                                 if(!server_can_auth)
2026                                         break; // other protocol message may follow
2027                                 server_can_auth = false;
2028                                 if(clientid >= 0)
2029                                         break;
2030                                 continue;
2031                         }
2032                         for(i = 0; i < MAX_PUBKEYS; ++i)
2033                         {
2034                                 if(pubkeys[i])
2035                                 if(!strcmp(p, pubkeys_fp64[i]))
2036                                 {
2037                                         if(pubkeys_havepriv[i])
2038                                                 if(clientid < 0)
2039                                                         clientid = i;
2040                                         if(server_can_auth)
2041                                                 if(serverid < 0)
2042                                                         if(wantserverid < 0 || i == wantserverid)
2043                                                                 serverid = i;
2044                                 }
2045                         }
2046                         if(clientid >= 0 && serverid >= 0)
2047                                 break;
2048                 }
2049
2050                 // if stored host key is not found:
2051                 if(wantserverid >= 0 && serverid < 0)
2052                         return Crypto_ClientError(data_out, len_out, "Server CA does not match stored host key, refusing to connect");
2053
2054                 if(serverid >= 0 || clientid >= 0)
2055                 {
2056                         // TODO at this point, fill clientside crypto struct!
2057                         MAKE_CDATA;
2058                         CDATA->cdata_id = ++cdata_id;
2059                         CDATA->s = serverid;
2060                         CDATA->c = clientid;
2061                         memset(crypto->dhkey, 0, sizeof(crypto->dhkey));
2062                         strlcpy(CDATA->challenge, challenge, sizeof(CDATA->challenge));
2063                         crypto->client_keyfp[0] = 0;
2064                         crypto->client_idfp[0] = 0;
2065                         crypto->server_keyfp[0] = 0;
2066                         crypto->server_idfp[0] = 0;
2067                         memcpy(CDATA->wantserver_idfp, wantserver_idfp, sizeof(crypto->server_idfp));
2068
2069                         if(CDATA->wantserver_idfp[0]) // if we know a host key, honor its encryption setting
2070                         switch(bound(0, d0_rijndael_dll ? crypto_aeslevel.integer : 0, 3))
2071                         {
2072                                 default: // dummy, never happens, but to make gcc happy...
2073                                 case 0:
2074                                         if(wantserver_aeslevel >= 3)
2075                                                 return Crypto_ServerError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)", NULL);
2076                                         CDATA->wantserver_aes = false;
2077                                         break;
2078                                 case 1:
2079                                         CDATA->wantserver_aes = (wantserver_aeslevel >= 2);
2080                                         break;
2081                                 case 2:
2082                                         CDATA->wantserver_aes = (wantserver_aeslevel >= 1);
2083                                         break;
2084                                 case 3:
2085                                         if(wantserver_aeslevel <= 0)
2086                                                 return Crypto_ServerError(data_out, len_out, "This server requires encryption to be supported (crypto_aeslevel >= 1, and d0_rijndael library must be present)", NULL);
2087                                         CDATA->wantserver_aes = true;
2088                                         break;
2089                         }
2090
2091                         // build outgoing message
2092                         // append regular stuff
2093                         PutWithNul(&data_out_p, len_out, va("d0pk\\cnt\\0\\id\\%d\\aeslevel\\%d\\challenge\\%s", CDATA->cdata_id, d0_rijndael_dll ? crypto_aeslevel.integer : 0, challenge));
2094                         PutWithNul(&data_out_p, len_out, serverid >= 0 ? pubkeys_fp64[serverid] : "");
2095                         PutWithNul(&data_out_p, len_out, clientid >= 0 ? pubkeys_fp64[clientid] : "");
2096
2097                         if(clientid >= 0)
2098                         {
2099                                 // I am the client, and my key is ok... so let's set client_keyfp and client_idfp
2100                                 strlcpy(crypto->client_keyfp, pubkeys_fp64[CDATA->c], sizeof(crypto->client_keyfp));
2101                                 strlcpy(crypto->client_idfp, pubkeys_priv_fp64[CDATA->c], sizeof(crypto->client_idfp));
2102                         }
2103
2104                         if(serverid >= 0)
2105                         {
2106                                 if(!CDATA->id)
2107                                         CDATA->id = qd0_blind_id_new();
2108                                 if(!CDATA->id)
2109                                 {
2110                                         CLEAR_CDATA;
2111                                         return Crypto_ClientError(data_out, len_out, "d0_blind_id_new failed");
2112                                 }
2113                                 if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->s]))
2114                                 {
2115                                         CLEAR_CDATA;
2116                                         return Crypto_ClientError(data_out, len_out, "d0_blind_id_copy failed");
2117                                 }
2118                                 CDATA->next_step = 1;
2119                                 *len_out = data_out_p - data_out;
2120                         }
2121                         else if(clientid >= 0)
2122                         {
2123                                 // skip over server auth, perform client auth only
2124                                 if(!CDATA->id)
2125                                         CDATA->id = qd0_blind_id_new();
2126                                 if(!CDATA->id)
2127                                 {
2128                                         CLEAR_CDATA;
2129                                         return Crypto_ClientError(data_out, len_out, "d0_blind_id_new failed");
2130                                 }
2131                                 if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->c]))
2132                                 {
2133                                         CLEAR_CDATA;
2134                                         return Crypto_ClientError(data_out, len_out, "d0_blind_id_copy failed");
2135                                 }
2136                                 if(!qd0_blind_id_authenticate_with_private_id_start(CDATA->id, true, false, "XONOTIC", 8, data_out_p, len_out)) // len_out receives used size by this op
2137                                 {
2138                                         CLEAR_CDATA;
2139                                         return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_start failed");
2140                                 }
2141                                 CDATA->next_step = 5;
2142                                 data_out_p += *len_out;
2143                                 *len_out = data_out_p - data_out;
2144                         }
2145                         else
2146                                 *len_out = data_out_p - data_out;
2147
2148                         return CRYPTO_DISCARD;
2149                 }
2150                 else
2151                 {
2152                         if(wantserver_idfp[0]) // if we know a host key, honor its encryption setting
2153                         if(wantserver_aeslevel >= 3)
2154                                 return Crypto_ClientError(data_out, len_out, "Server insists on encryption, but neither can authenticate to the other");
2155                         return (d0_rijndael_dll && crypto_aeslevel.integer >= 3) ? Crypto_ServerError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)", NULL) :
2156                                 CRYPTO_NOMATCH;
2157                 }
2158         }
2159         else if(len_in > 5 && !memcmp(string, "d0pk\\", 5) && cls.connect_trying)
2160         {
2161                 const char *cnt;
2162                 int id;
2163                 cnt = SearchInfostring(string + 4, "id");
2164                 id = (cnt ? atoi(cnt) : -1);
2165                 cnt = SearchInfostring(string + 4, "cnt");
2166                 if(!cnt)
2167                         return Crypto_ClientError(data_out, len_out, "d0pk\\ message without cnt");
2168                 GetUntilNul(&data_in, &len_in);
2169                 if(!data_in)
2170                         return Crypto_ClientError(data_out, len_out, "d0pk\\ message without attachment");
2171
2172                 if(!strcmp(cnt, "1"))
2173                 {
2174                         if(id >= 0)
2175                                 if(CDATA->cdata_id != id)
2176                                         return Crypto_SoftServerError(data_out, len_out, va("Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
2177                         if(CDATA->next_step != 1)
2178                                 return Crypto_SoftClientError(data_out, len_out, va("Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
2179
2180                         cls.connect_nextsendtime = max(cls.connect_nextsendtime, realtime + 1); // prevent "hammering"
2181
2182                         if((s = SearchInfostring(string + 4, "aes")))
2183                                 aes = atoi(s);
2184                         else
2185                                 aes = false;
2186                         // we CANNOT toggle the AES status any more!
2187                         // as the server already decided
2188                         if(CDATA->wantserver_idfp[0]) // if we know a host key, honor its encryption setting
2189                         if(!aes && CDATA->wantserver_aes)
2190                         {
2191                                 CLEAR_CDATA;
2192                                 return Crypto_ClientError(data_out, len_out, "Stored host key requires encryption, but server did not enable encryption");
2193                         }
2194                         if(aes && (!d0_rijndael_dll || crypto_aeslevel.integer <= 0))
2195                         {
2196                                 CLEAR_CDATA;
2197                                 return Crypto_ClientError(data_out, len_out, "Server insists on encryption too hard");
2198                         }
2199                         if(!aes && (d0_rijndael_dll && crypto_aeslevel.integer >= 3))
2200                         {
2201                                 CLEAR_CDATA;
2202                                 return Crypto_ClientError(data_out, len_out, "Server insists on plaintext too hard");
2203                         }
2204                         crypto->use_aes = aes != 0;
2205
2206                         PutWithNul(&data_out_p, len_out, va("d0pk\\cnt\\2\\id\\%d", CDATA->cdata_id));
2207                         if(!qd0_blind_id_authenticate_with_private_id_challenge(CDATA->id, true, false, data_in, len_in, data_out_p, len_out, &status))
2208                         {
2209                                 CLEAR_CDATA;
2210                                 return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_challenge failed");
2211                         }
2212                         CDATA->next_step = 3;
2213                         data_out_p += *len_out;
2214                         *len_out = data_out_p - data_out;
2215                         return CRYPTO_DISCARD;
2216                 }
2217                 else if(!strcmp(cnt, "3"))
2218                 {
2219                         static char msgbuf[32];
2220                         size_t msgbuflen = sizeof(msgbuf);
2221                         size_t fpbuflen;
2222
2223                         if(id >= 0)
2224                                 if(CDATA->cdata_id != id)
2225                                         return Crypto_SoftServerError(data_out, len_out, va("Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
2226                         if(CDATA->next_step != 3)
2227                                 return Crypto_SoftClientError(data_out, len_out, va("Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
2228
2229                         cls.connect_nextsendtime = max(cls.connect_nextsendtime, realtime + 1); // prevent "hammering"
2230
2231                         if(!qd0_blind_id_authenticate_with_private_id_verify(CDATA->id, data_in, len_in, msgbuf, &msgbuflen, &status))
2232                         {
2233                                 CLEAR_CDATA;
2234                                 return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_verify failed (server authentication error)");
2235                         }
2236                         if(status)
2237                                 strlcpy(crypto->server_keyfp, pubkeys_fp64[CDATA->s], sizeof(crypto->server_keyfp));
2238                         else
2239                                 crypto->server_keyfp[0] = 0;
2240                         memset(crypto->server_idfp, 0, sizeof(crypto->server_idfp));
2241                         fpbuflen = FP64_SIZE;
2242                         if(!qd0_blind_id_fingerprint64_public_id(CDATA->id, crypto->server_idfp, &fpbuflen))
2243                         {
2244                                 CLEAR_CDATA;
2245                                 return Crypto_ClientError(data_out, len_out, "d0_blind_id_fingerprint64_public_id failed");
2246                         }
2247                         if(CDATA->wantserver_idfp[0])
2248                         if(memcmp(CDATA->wantserver_idfp, crypto->server_idfp, sizeof(crypto->server_idfp)))
2249                         {
2250                                 CLEAR_CDATA;
2251                                 return Crypto_ClientError(data_out, len_out, "Server ID does not match stored host key, refusing to connect");
2252                         }
2253                         fpbuflen = DHKEY_SIZE;
2254                         if(!qd0_blind_id_sessionkey_public_id(CDATA->id, (char *) crypto->dhkey, &fpbuflen))
2255                         {
2256                                 CLEAR_CDATA;
2257                                 return Crypto_ClientError(data_out, len_out, "d0_blind_id_sessionkey_public_id failed");
2258                         }
2259
2260                         // cache the server key
2261                         Crypto_StoreHostKey(&cls.connect_address, va("%d %s@%s", crypto->use_aes ? 1 : 0, crypto->server_idfp, pubkeys_fp64[CDATA->s]), false);
2262
2263                         if(CDATA->c >= 0)
2264                         {
2265                                 // client will auth next
2266                                 PutWithNul(&data_out_p, len_out, va("d0pk\\cnt\\4\\id\\%d", CDATA->cdata_id));
2267                                 if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->c]))
2268                                 {
2269                                         CLEAR_CDATA;
2270                                         return Crypto_ClientError(data_out, len_out, "d0_blind_id_copy failed");
2271                                 }
2272                                 if(!qd0_blind_id_authenticate_with_private_id_start(CDATA->id, true, false, "XONOTIC", 8, data_out_p, len_out)) // len_out receives used size by this op
2273                                 {
2274                                         CLEAR_CDATA;
2275                                         return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_start failed");
2276                                 }
2277                                 CDATA->next_step = 5;
2278                                 data_out_p += *len_out;
2279                                 *len_out = data_out_p - data_out;
2280                                 return CRYPTO_DISCARD;
2281                         }
2282                         else
2283                         {
2284                                 // session key is FINISHED (no server part is to be expected)! By this, all keys are set up
2285                                 crypto->authenticated = true;
2286                                 CDATA->next_step = 0;
2287                                 // assume we got the empty challenge to finish the protocol
2288                                 PutWithNul(&data_out_p, len_out, "challenge ");
2289                                 *len_out = data_out_p - data_out;
2290                                 --*len_out; // remove NUL terminator
2291                                 return CRYPTO_REPLACE;
2292                         }
2293                 }
2294                 else if(!strcmp(cnt, "5"))
2295                 {
2296                         size_t fpbuflen;
2297                         unsigned char dhkey[DHKEY_SIZE];
2298                         int i;
2299
2300                         if(id >= 0)
2301                                 if(CDATA->cdata_id != id)
2302                                         return Crypto_SoftServerError(data_out, len_out, va("Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
2303                         if(CDATA->next_step != 5)
2304                                 return Crypto_SoftClientError(data_out, len_out, va("Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
2305
2306                         cls.connect_nextsendtime = max(cls.connect_nextsendtime, realtime + 1); // prevent "hammering"
2307
2308                         if(CDATA->s < 0) // only if server didn't auth
2309                         {
2310                                 if((s = SearchInfostring(string + 4, "aes")))
2311                                         aes = atoi(s);
2312                                 else
2313                                         aes = false;
2314                                 if(CDATA->wantserver_idfp[0]) // if we know a host key, honor its encryption setting
2315                                 if(!aes && CDATA->wantserver_aes)
2316                                 {
2317                                         CLEAR_CDATA;
2318                                         return Crypto_ClientError(data_out, len_out, "Stored host key requires encryption, but server did not enable encryption");
2319                                 }
2320                                 if(aes && (!d0_rijndael_dll || crypto_aeslevel.integer <= 0))
2321                                 {
2322                                         CLEAR_CDATA;
2323                                         return Crypto_ClientError(data_out, len_out, "Server insists on encryption too hard");
2324                                 }
2325                                 if(!aes && (d0_rijndael_dll && crypto_aeslevel.integer >= 3))
2326                                 {
2327                                         CLEAR_CDATA;
2328                                         return Crypto_ClientError(data_out, len_out, "Server insists on plaintext too hard");
2329                                 }
2330                                 crypto->use_aes = aes != 0;
2331                         }
2332
2333                         PutWithNul(&data_out_p, len_out, va("d0pk\\cnt\\6\\id\\%d", CDATA->cdata_id));
2334                         if(!qd0_blind_id_authenticate_with_private_id_response(CDATA->id, data_in, len_in, data_out_p, len_out))
2335                         {
2336                                 CLEAR_CDATA;
2337                                 return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_response failed");
2338                         }
2339                         fpbuflen = DHKEY_SIZE;
2340                         if(!qd0_blind_id_sessionkey_public_id(CDATA->id, (char *) dhkey, &fpbuflen))
2341                         {
2342                                 CLEAR_CDATA;
2343                                 return Crypto_ClientError(data_out, len_out, "d0_blind_id_sessionkey_public_id failed");
2344                         }
2345                         // XOR the two DH keys together to make one
2346                         for(i = 0; i < DHKEY_SIZE; ++i)
2347                                 crypto->dhkey[i] ^= dhkey[i];
2348                         // session key is FINISHED! By this, all keys are set up
2349                         crypto->authenticated = true;
2350                         CDATA->next_step = 0;
2351                         data_out_p += *len_out;
2352                         *len_out = data_out_p - data_out;
2353                         return CRYPTO_DISCARD;
2354                 }
2355                 return Crypto_SoftClientError(data_out, len_out, "Got unknown d0_blind_id message from server");
2356         }
2357
2358         return CRYPTO_NOMATCH;
2359 }