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