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