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