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