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