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