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