9 cvar_t crypto_developer = {CVAR_SAVE, "crypto_developer", "0", "print extra info about crypto handshake"};
10 cvar_t crypto_aeslevel = {CVAR_SAVE, "crypto_aeslevel", "1", "whether to support AES encryption in authenticated connections (0 = no, 1 = supported, 2 = requested, 3 = required)"};
12 cvar_t crypto_servercpupercent = {CVAR_SAVE, "crypto_servercpupercent", "10", "allowed crypto CPU load in percent for server operation (0 = no limit, faster)"};
13 cvar_t crypto_servercpumaxtime = {CVAR_SAVE, "crypto_servercpumaxtime", "0.01", "maximum allowed crypto CPU time per frame (0 = no limit)"};
14 cvar_t crypto_servercpudebug = {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;
18 extern cvar_t net_sourceaddresscheck;
20 int crypto_keyfp_recommended_length;
21 static const char *crypto_idstring = NULL;
22 static char crypto_idstring_buf[512];
25 #define PROTOCOL_D0_BLIND_ID FOURCC_D0PK
26 #define PROTOCOL_VLEN (('v' << 0) | ('l' << 8) | ('e' << 16) | ('n' << 24))
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))
38 static unsigned long Crypto_LittleLong(const char *data)
41 ((unsigned char) data[0]) |
42 (((unsigned char) data[1]) << 8) |
43 (((unsigned char) data[2]) << 16) |
44 (((unsigned char) data[3]) << 24);
47 static void Crypto_UnLittleLong(char *data, unsigned long l)
50 data[1] = (l >> 8) & 0xFF;
51 data[2] = (l >> 16) & 0xFF;
52 data[3] = (l >> 24) & 0xFF;
55 static size_t Crypto_ParsePack(const char *buf, size_t len, unsigned long header, const char **lumps, size_t *lumpsize, size_t nlumps)
64 if(Crypto_LittleLong(buf) != header)
68 for(i = 0; i < nlumps; ++i)
72 lumpsize[i] = Crypto_LittleLong(&buf[pos]);
74 if(pos + lumpsize[i] > len)
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)
91 Crypto_UnLittleLong(buf, header);
94 for(i = 0; i < nlumps; ++i)
96 if(pos + 4 + lumpsize[i] > len)
98 Crypto_UnLittleLong(&buf[pos], (unsigned long)lumpsize[i]);
100 memcpy(&buf[pos], lumps[i], lumpsize[i]);
105 // END stuff shared with xonotic-keygen
109 #ifdef LINK_TO_CRYPTO
111 #include <d0_blind_id/d0_blind_id.h>
113 #define d0_blind_id_dll 1
114 #define Crypto_OpenLibrary() true
115 #define Crypto_CloseLibrary()
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
159 // d0_blind_id interface
162 #define D0_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
164 #define D0_WARN_UNUSED_RESULT
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
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[] =
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},
259 // end of d0_blind_id interface
261 static dllhandle_t d0_blind_id_dll = NULL;
262 static qboolean Crypto_OpenLibrary (void)
264 const char* dllnames [] =
267 "libd0_blind_id-0.dll",
268 #elif defined(MACOSX)
269 "libd0_blind_id.0.dylib",
271 "libd0_blind_id.so.0",
272 "libd0_blind_id.so", // FreeBSD
282 return Sys_LoadLibrary (dllnames, &d0_blind_id_dll, d0_blind_id_funcs);
285 static void Crypto_CloseLibrary (void)
287 Sys_UnloadLibrary (&d0_blind_id_dll);
292 #ifdef LINK_TO_CRYPTO_RIJNDAEL
294 #include <d0_blind_id/d0_rijndael.h>
296 #define d0_rijndael_dll 1
297 #define Crypto_Rijndael_OpenLibrary() true
298 #define Crypto_Rijndael_CloseLibrary()
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
307 // no need to do the #define dance here, as the upper part declares out macros either way
309 D0_EXPORT int (*qd0_rijndael_setup_encrypt) (unsigned long *rk, const unsigned char *key,
311 D0_EXPORT int (*qd0_rijndael_setup_decrypt) (unsigned long *rk, const unsigned char *key,
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[] =
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},
328 // end of d0_blind_id interface
330 static dllhandle_t d0_rijndael_dll = NULL;
331 static qboolean Crypto_Rijndael_OpenLibrary (void)
333 const char* dllnames [] =
336 "libd0_rijndael-0.dll",
337 #elif defined(MACOSX)
338 "libd0_rijndael.0.dylib",
340 "libd0_rijndael.so.0",
341 "libd0_rijndael.so", // FreeBSD
351 return Sys_LoadLibrary (dllnames, &d0_rijndael_dll, d0_rijndael_funcs);
354 static void Crypto_Rijndael_CloseLibrary (void)
356 Sys_UnloadLibrary (&d0_rijndael_dll);
362 void sha256(unsigned char *out, const unsigned char *in, int n)
364 qd0_blind_id_util_sha256((char *) out, (const char *) in, n);
367 static size_t Crypto_LoadFile(const char *path, char *buf, size_t nmax, qboolean inuserdir)
373 f = FS_SysOpen(va(vabuf, sizeof(vabuf), "%s%s", *fs_userdir ? fs_userdir : fs_basedir, path), "rb", false);
375 f = FS_SysOpen(va(vabuf, sizeof(vabuf), "%s%s", fs_basedir, path), "rb", false);
378 n = FS_Read(f, buf, nmax);
385 static qboolean PutWithNul(char **data, size_t *len, const char *str)
387 // invariant: data points to insertion point
388 size_t l = strlen(str);
391 memcpy(*data, str, l+1);
397 static const char *GetUntilNul(const char **data, size_t *len)
399 // invariant: data points to next character to take
400 const char *data_save = *data;
413 p = (const char *) memchr(*data, 0, *len);
414 if(!p) // no terminating NUL
425 return (const char *) data_save;
429 static d0_blind_id_t *Crypto_ReadPublicKey(char *buf, size_t len)
431 d0_blind_id_t *pk = NULL;
434 if(Crypto_ParsePack(buf, len, FOURCC_D0PK, p, l, 2))
436 pk = qd0_blind_id_new();
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]))
443 qd0_blind_id_free(pk);
448 static qboolean Crypto_AddPrivateKey(d0_blind_id_t *pk, char *buf, size_t len)
452 if(Crypto_ParsePack(buf, len, FOURCC_D0SI, p, l, 1))
454 if(qd0_blind_id_read_private_id(pk, p[0], l[0]))
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;
469 static int keygen_i = -1;
470 static char keygen_buf[8192];
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
481 lhnetaddress_t address;
485 server_cryptoconnect_t;
486 static server_cryptoconnect_t cryptoconnects[MAX_CRYPTOCONNECTS];
488 static int cdata_id = 0;
494 char challenge[2048];
495 char wantserver_idfp[FP64_SIZE+1];
496 qboolean wantserver_aes;
497 qboolean wantserver_issigned;
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
507 static crypto_t *Crypto_ServerFindInstance(lhnetaddress_t *peeraddress, qboolean allow_create)
513 return NULL; // no support
515 for(i = 0; i < MAX_CRYPTOCONNECTS; ++i)
516 if(LHNETADDRESS_Compare(peeraddress, &cryptoconnects[i].address))
518 if(i < MAX_CRYPTOCONNECTS && (allow_create || cryptoconnects[i].crypto.data))
520 crypto = &cryptoconnects[i].crypto;
521 cryptoconnects[i].lasttime = realtime;
527 for(i = 1; i < MAX_CRYPTOCONNECTS; ++i)
528 if(cryptoconnects[i].lasttime < cryptoconnects[best].lasttime)
530 crypto = &cryptoconnects[best].crypto;
531 cryptoconnects[best].lasttime = realtime;
532 memcpy(&cryptoconnects[best].address, peeraddress, sizeof(cryptoconnects[best].address));
537 qboolean Crypto_FinishInstance(crypto_t *out, crypto_t *crypto)
539 // no check needed here (returned pointers are only used in prefilled fields)
540 if(!crypto || !crypto->authenticated)
542 Con_Printf("Passed an invalid crypto connect instance\n");
543 memset(out, 0, sizeof(*out));
547 memcpy(out, crypto, sizeof(*out));
548 memset(crypto, 0, sizeof(*crypto));
552 crypto_t *Crypto_ServerGetInstance(lhnetaddress_t *peeraddress)
554 // no check needed here (returned pointers are only used in prefilled fields)
555 return Crypto_ServerFindInstance(peeraddress, false);
558 typedef struct crypto_storedhostkey_s
560 struct crypto_storedhostkey_s *next;
563 char idfp[FP64_SIZE+1];
567 crypto_storedhostkey_t;
568 static crypto_storedhostkey_t *crypto_storedhostkey_hashtable[CRYPTO_HOSTKEY_HASHSIZE];
570 static void Crypto_InitHostKeys(void)
573 for(i = 0; i < CRYPTO_HOSTKEY_HASHSIZE; ++i)
574 crypto_storedhostkey_hashtable[i] = NULL;
577 static void Crypto_ClearHostKeys(void)
580 crypto_storedhostkey_t *hk, *hkn;
581 for(i = 0; i < CRYPTO_HOSTKEY_HASHSIZE; ++i)
583 for(hk = crypto_storedhostkey_hashtable[i]; hk; hk = hkn)
588 crypto_storedhostkey_hashtable[i] = NULL;
592 static qboolean Crypto_ClearHostKey(lhnetaddress_t *peeraddress)
596 crypto_storedhostkey_t **hkp;
597 qboolean found = false;
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));
605 crypto_storedhostkey_t *hk = *hkp;
614 static void Crypto_StoreHostKey(lhnetaddress_t *peeraddress, const char *keystring, qboolean complain)
618 crypto_storedhostkey_t *hk;
620 char idfp[FP64_SIZE+1];
627 // syntax of keystring:
628 // aeslevel id@key id@key ...
632 aeslevel = bound(0, *keystring - '0', 3);
633 while(*keystring && *keystring != ' ')
638 while(*keystring && keyid < 0)
641 const char *idstart, *idend, *keystart, *keyend;
642 qboolean thisissigned = true;
643 ++keystring; // skip the space
645 while(*keystring && *keystring != ' ' && *keystring != '@')
651 keystart = keystring;
652 while(*keystring && *keystring != ' ')
656 if (keystart[0] == '~')
658 thisissigned = false;
662 if(idend - idstart == FP64_SIZE && keyend - keystart == FP64_SIZE)
665 for(thiskeyid = MAX_PUBKEYS - 1; thiskeyid >= 0; --thiskeyid)
666 if(pubkeys[thiskeyid])
667 if(!memcmp(pubkeys_fp64[thiskeyid], keystart, FP64_SIZE))
669 memcpy(idfp, idstart, FP64_SIZE);
672 issigned = thisissigned;
675 // If this failed, keyid will be -1.
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);
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);
697 hk->aeslevel = max(aeslevel, hk->aeslevel);
698 hk->issigned = issigned;
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));
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;
713 qboolean Crypto_RetrieveHostKey(lhnetaddress_t *peeraddress, int *keyid, char *keyfp, size_t keyfplen, char *idfp, size_t idfplen, int *aeslevel, qboolean *issigned)
717 crypto_storedhostkey_t *hk;
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);
732 strlcpy(keyfp, pubkeys_fp64[hk->keyid], keyfplen);
734 strlcpy(idfp, hk->idfp, idfplen);
736 *aeslevel = hk->aeslevel;
738 *issigned = hk->issigned;
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
744 if(keyid < 0 || keyid >= MAX_PUBKEYS)
753 strlcpy(keyfp, pubkeys_fp64[keyid], keyfplen);
755 if(pubkeys_havepriv[keyid])
756 strlcpy(idfp, pubkeys_priv_fp64[keyid], idfplen);
758 *issigned = pubkeys_havesig[keyid];
763 // init/shutdown code
764 static void Crypto_BuildChallengeAppend(void)
766 char *p, *lengthptr, *startptr;
769 p = challenge_append;
770 n = sizeof(challenge_append);
771 Crypto_UnLittleLong(p, PROTOCOL_VLEN);
775 Crypto_UnLittleLong(p, 0);
778 Crypto_UnLittleLong(p, PROTOCOL_D0_BLIND_ID);
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;
793 static qboolean Crypto_SavePubKeyTextFile(int i)
798 if(!pubkeys_havepriv[i])
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);
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]);
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");
812 FS_Printf(f, "This file will be automatically generated again if deleted.\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);
821 static void Crypto_BuildIdString(void)
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)
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;
834 void Crypto_LoadKeys(void)
841 if(!d0_blind_id_dll) // don't if we can't
844 if(crypto_idstring) // already loaded? then not
847 Host_LockSession(); // we use the session ID here
850 // note: we are just a CLIENT
852 // PUBLIC KEYS to accept (including modulus)
853 // PRIVATE KEY of user
855 for(i = 0; i < MAX_PUBKEYS; ++i)
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)))
865 if(qd0_blind_id_fingerprint64_public_key(pubkeys[i], pubkeys_fp64[i], &len2)) // keeps final NUL
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);
871 if(Crypto_AddPrivateKey(pubkeys[i], buf, len))
874 if(qd0_blind_id_fingerprint64_public_id(pubkeys[i], pubkeys_priv_fp64[i], &len2)) // keeps final NUL
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]);
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))
883 pubkeys_havepriv[i] = true;
884 pubkeys_havesig[i] = status;
886 // verify the key we just got (just in case)
888 Con_Printf("NOTE: this ID has not yet been signed!\n");
890 Crypto_SavePubKeyTextFile(i);
894 Con_Printf("d0_blind_id_verify_private_id failed, this is not a valid key!\n");
895 qd0_blind_id_free(pubkeys[i]);
901 Con_Printf("d0_blind_id_fingerprint64_public_id failed\n");
902 qd0_blind_id_free(pubkeys[i]);
910 // can't really happen
911 qd0_blind_id_free(pubkeys[i]);
918 Crypto_BuildIdString();
919 Crypto_BuildChallengeAppend();
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)
927 for(i = 0; i < MAX_PUBKEYS; ++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]];
936 for(i = 0; i < MAX_PUBKEYS; ++i)
940 if(buf[(unsigned char) pubkeys_fp64[i][crypto_keyfp_recommended_length]] < 2)
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;
947 ++crypto_keyfp_recommended_length;
948 for(i = 0; i < MAX_PUBKEYS; ++i)
953 if(pubkeys_havepriv[i])
954 if(!buf[256 + MAX_PUBKEYS + i])
960 if(crypto_keyfp_recommended_length < 7)
961 crypto_keyfp_recommended_length = 7;
964 static void Crypto_UnloadKeys(void)
969 for(i = 0; i < MAX_PUBKEYS; ++i)
972 qd0_blind_id_free(pubkeys[i]);
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;
980 crypto_idstring = NULL;
983 static mempool_t *cryptomempool;
989 static void *Crypto_d0_malloc(size_t len)
991 return Mem_Alloc(cryptomempool, len);
994 static void Crypto_d0_free(void *p)
999 static void *Crypto_d0_createmutex(void)
1001 return Thread_CreateMutex();
1004 static void Crypto_d0_destroymutex(void *m)
1006 Thread_DestroyMutex(m);
1009 static int Crypto_d0_lockmutex(void *m)
1011 return Thread_LockMutex(m);
1014 static int Crypto_d0_unlockmutex(void *m)
1016 return Thread_UnlockMutex(m);
1022 void Crypto_Shutdown(void)
1027 Crypto_Rijndael_CloseLibrary();
1032 for(i = 0; i < MAX_CRYPTOCONNECTS; ++i)
1034 crypto = &cryptoconnects[i].crypto;
1037 memset(cryptoconnects, 0, sizeof(cryptoconnects));
1038 crypto = &cls.crypto;
1041 Crypto_UnloadKeys();
1043 qd0_blind_id_SHUTDOWN();
1045 Crypto_CloseLibrary();
1048 Mem_FreePool(&cryptomempool);
1051 void Crypto_Init(void)
1053 cryptomempool = Mem_AllocPool("crypto", 0, NULL);
1055 if(!Crypto_OpenLibrary())
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);
1062 if(!qd0_blind_id_INITIALIZE())
1064 Crypto_Rijndael_CloseLibrary();
1065 Crypto_CloseLibrary();
1066 Con_Printf("libd0_blind_id initialization FAILED, cryptography support has been disabled\n");
1070 (void) Crypto_Rijndael_OpenLibrary(); // if this fails, it's uncritical
1072 Crypto_InitHostKeys();
1076 qboolean Crypto_Available(void)
1078 if(!d0_blind_id_dll)
1084 static void Crypto_KeyGen_Finished(int code, size_t length_received, unsigned char *buffer, void *cbdata)
1088 static char buf[8192];
1089 static char buf2[8192];
1095 SV_LockThreadMutex();
1097 if(!d0_blind_id_dll)
1099 Con_Print("libd0_blind_id DLL not found, this command is inactive.\n");
1101 SV_UnlockThreadMutex();
1107 Con_Printf("Unexpected response from keygen server:\n");
1108 Com_HexDumpToConsole(buffer, (int)length_received);
1109 SV_UnlockThreadMutex();
1112 if(keygen_i >= MAX_PUBKEYS || !pubkeys[keygen_i])
1114 Con_Printf("overflow of keygen_i\n");
1116 SV_UnlockThreadMutex();
1119 if(!Crypto_ParsePack((const char *) buffer, length_received, FOURCC_D0IR, p, l, 1))
1121 if(length_received >= 5 && Crypto_LittleLong((const char *) buffer) == FOURCC_D0ER)
1123 Con_Printf("Error response from keygen server: %.*s\n", (int)(length_received - 5), buffer + 5);
1127 Con_Printf("Invalid response from keygen server:\n");
1128 Com_HexDumpToConsole(buffer, (int)length_received);
1131 SV_UnlockThreadMutex();
1134 if(!qd0_blind_id_finish_private_id_request(pubkeys[keygen_i], p[0], l[0]))
1136 Con_Printf("d0_blind_id_finish_private_id_request failed\n");
1138 SV_UnlockThreadMutex();
1142 // verify the key we just got (just in case)
1143 if(!qd0_blind_id_verify_public_id(pubkeys[keygen_i], &status) || !status)
1145 Con_Printf("d0_blind_id_verify_public_id failed\n");
1147 SV_UnlockThreadMutex();
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;
1156 // write the key to disk
1159 if(!qd0_blind_id_write_private_id(pubkeys[keygen_i], buf, &l[0]))
1161 Con_Printf("d0_blind_id_write_private_id failed\n");
1163 SV_UnlockThreadMutex();
1166 if(!(buf2size = Crypto_UnParsePack(buf2, sizeof(buf2), FOURCC_D0SI, p, l, 1)))
1168 Con_Printf("Crypto_UnParsePack failed\n");
1170 SV_UnlockThreadMutex();
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);
1178 Con_Printf("Cannot open key_%d.d0si%s\n", keygen_i, sessionid.string);
1180 SV_UnlockThreadMutex();
1183 FS_Write(f, buf2, buf2size);
1186 Crypto_SavePubKeyTextFile(keygen_i);
1188 Con_Printf("Saved to key_%d.d0si%s\n", keygen_i, sessionid.string);
1190 Crypto_BuildIdString();
1193 SV_UnlockThreadMutex();
1196 static void Crypto_KeyGen_f(void)
1201 static char buf[8192];
1202 static char buf2[8192];
1204 size_t buf2l, buf2pos;
1209 if(!d0_blind_id_dll)
1211 Con_Print("libd0_blind_id DLL not found, this command is inactive.\n");
1216 Con_Printf("usage:\n%s id url\n", Cmd_Argv(0));
1219 SV_LockThreadMutex();
1221 i = atoi(Cmd_Argv(1));
1224 Con_Printf("there is no public key %d\n", i);
1225 SV_UnlockThreadMutex();
1230 Con_Printf("there is already a keygen run on the way\n");
1231 SV_UnlockThreadMutex();
1236 // how to START the keygenning...
1237 if(pubkeys_havepriv[keygen_i])
1239 if(pubkeys_havesig[keygen_i])
1241 Con_Printf("there is already a signed private key for %d\n", i);
1243 SV_UnlockThreadMutex();
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");
1251 // we also need a new ID itself
1252 if(!qd0_blind_id_generate_private_id_start(pubkeys[keygen_i]))
1254 Con_Printf("d0_blind_id_start failed\n");
1256 SV_UnlockThreadMutex();
1259 // verify the key we just got (just in case)
1260 if(!qd0_blind_id_verify_private_id(pubkeys[keygen_i]))
1262 Con_Printf("d0_blind_id_verify_private_id failed\n");
1264 SV_UnlockThreadMutex();
1267 // we have a valid key now!
1268 // make the rest of crypto.c know that
1270 if(qd0_blind_id_fingerprint64_public_id(pubkeys[keygen_i], pubkeys_priv_fp64[keygen_i], &len2)) // keeps final NUL
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();
1278 // write the key to disk
1281 if(!qd0_blind_id_write_private_id(pubkeys[keygen_i], buf, &l[0]))
1283 Con_Printf("d0_blind_id_write_private_id failed\n");
1285 SV_UnlockThreadMutex();
1288 if(!(buf2size = Crypto_UnParsePack(buf2, sizeof(buf2), FOURCC_D0SI, p, l, 1)))
1290 Con_Printf("Crypto_UnParsePack failed\n");
1292 SV_UnlockThreadMutex();
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);
1300 Con_Printf("Cannot open key_%d.d0si%s\n", keygen_i, sessionid.string);
1302 SV_UnlockThreadMutex();
1305 FS_Write(f, buf2, buf2size);
1308 Crypto_SavePubKeyTextFile(keygen_i);
1310 Con_Printf("Saved unsigned key to key_%d.d0si%s\n", keygen_i, sessionid.string);
1314 if(!qd0_blind_id_generate_private_id_request(pubkeys[keygen_i], buf, &l[0]))
1316 Con_Printf("d0_blind_id_generate_private_id_request failed\n");
1318 SV_UnlockThreadMutex();
1321 buf2pos = strlen(Cmd_Argv(2));
1322 memcpy(buf2, Cmd_Argv(2), buf2pos);
1323 if(!(buf2l = Crypto_UnParsePack(buf2 + buf2pos, sizeof(buf2) - buf2pos - 1, FOURCC_D0IQ, p, l, 1)))
1325 Con_Printf("Crypto_UnParsePack failed\n");
1327 SV_UnlockThreadMutex();
1330 if(!(buf2l = base64_encode((unsigned char *) (buf2 + buf2pos), buf2l, sizeof(buf2) - buf2pos - 1)))
1332 Con_Printf("base64_encode failed\n");
1334 SV_UnlockThreadMutex();
1339 if(!Curl_Begin_ToMemory(buf2, 0, (unsigned char *) keygen_buf, sizeof(keygen_buf), Crypto_KeyGen_Finished, NULL))
1341 Con_Printf("curl failed\n");
1343 SV_UnlockThreadMutex();
1346 Con_Printf("Signature generation in progress...\n");
1347 SV_UnlockThreadMutex();
1352 static void Crypto_Reload_f(void)
1354 Crypto_ClearHostKeys();
1355 Crypto_UnloadKeys();
1359 static void Crypto_Keys_f(void)
1362 if(!d0_blind_id_dll)
1364 Con_Print("libd0_blind_id DLL not found, this command is inactive.\n");
1367 for(i = 0; i < MAX_PUBKEYS; ++i)
1371 Con_Printf("%2d: public key key_%d.d0pk (fingerprint: %s)\n", i, i, pubkeys_fp64[i]);
1372 if(pubkeys_havepriv[i])
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");
1382 static void Crypto_HostKeys_f(void)
1385 crypto_storedhostkey_t *hk;
1388 if(!d0_blind_id_dll)
1390 Con_Print("libd0_blind_id DLL not found, this command is inactive.\n");
1393 for(i = 0; i < CRYPTO_HOSTKEY_HASHSIZE; ++i)
1395 for(hk = crypto_storedhostkey_hashtable[i]; hk; hk = hk->next)
1397 LHNETADDRESS_ToString(&hk->addr, buf, sizeof(buf), 1);
1398 Con_Printf("%d %s@%.*s %s\n",
1401 crypto_keyfp_recommended_length, pubkeys_fp64[hk->keyid],
1407 static void Crypto_HostKey_Clear_f(void)
1409 lhnetaddress_t addr;
1412 if(!d0_blind_id_dll)
1414 Con_Print("libd0_blind_id DLL not found, this command is inactive.\n");
1418 for(i = 1; i < Cmd_Argc(); ++i)
1420 LHNETADDRESS_FromString(&addr, Cmd_Argv(i), 26000);
1421 if(Crypto_ClearHostKey(&addr))
1423 Con_Printf("cleared host key for %s\n", Cmd_Argv(i));
1428 void Crypto_Init_Commands(void)
1432 Cmd_AddCommand("crypto_reload", Crypto_Reload_f, "reloads cryptographic keys");
1433 Cmd_AddCommand("crypto_keygen", Crypto_KeyGen_f, "generates and saves a cryptographic key");
1434 Cmd_AddCommand("crypto_keys", Crypto_Keys_f, "lists the loaded keys");
1435 Cmd_AddCommand("crypto_hostkeys", Crypto_HostKeys_f, "lists the cached host keys");
1436 Cmd_AddCommand("crypto_hostkey_clear", Crypto_HostKey_Clear_f, "clears a cached host key");
1437 Cvar_RegisterVariable(&crypto_developer);
1439 Cvar_RegisterVariable(&crypto_aeslevel);
1441 crypto_aeslevel.integer = 0; // make sure
1442 Cvar_RegisterVariable(&crypto_servercpupercent);
1443 Cvar_RegisterVariable(&crypto_servercpumaxtime);
1444 Cvar_RegisterVariable(&crypto_servercpudebug);
1450 static void aescpy(unsigned char *key, const unsigned char *iv, unsigned char *dst, const unsigned char *src, size_t len)
1452 const unsigned char *xorpos = iv;
1453 unsigned char xorbuf[16];
1454 unsigned long rk[D0_RIJNDAEL_RKLENGTH(DHKEY_SIZE * 8)];
1456 qd0_rijndael_setup_encrypt(rk, key, DHKEY_SIZE * 8);
1459 for(i = 0; i < 16; ++i)
1460 xorbuf[i] = src[i] ^ xorpos[i];
1461 qd0_rijndael_encrypt(rk, D0_RIJNDAEL_NROUNDS(DHKEY_SIZE * 8), xorbuf, dst);
1469 for(i = 0; i < len; ++i)
1470 xorbuf[i] = src[i] ^ xorpos[i];
1472 xorbuf[i] = xorpos[i];
1473 qd0_rijndael_encrypt(rk, D0_RIJNDAEL_NROUNDS(DHKEY_SIZE * 8), xorbuf, dst);
1476 static void seacpy(unsigned char *key, const unsigned char *iv, unsigned char *dst, const unsigned char *src, size_t len)
1478 const unsigned char *xorpos = iv;
1479 unsigned char xorbuf[16];
1480 unsigned long rk[D0_RIJNDAEL_RKLENGTH(DHKEY_SIZE * 8)];
1482 qd0_rijndael_setup_decrypt(rk, key, DHKEY_SIZE * 8);
1485 qd0_rijndael_decrypt(rk, D0_RIJNDAEL_NROUNDS(DHKEY_SIZE * 8), src, xorbuf);
1486 for(i = 0; i < 16; ++i)
1487 dst[i] = xorbuf[i] ^ xorpos[i];
1495 qd0_rijndael_decrypt(rk, D0_RIJNDAEL_NROUNDS(DHKEY_SIZE * 8), src, xorbuf);
1496 for(i = 0; i < len; ++i)
1497 dst[i] = xorbuf[i] ^ xorpos[i];
1501 // NOTE: we MUST avoid the following begins of the packet:
1502 // 1. 0xFF, 0xFF, 0xFF, 0xFF
1503 // 2. 0x80, 0x00, length/256, length%256
1504 // this luckily does NOT affect AES mode, where the first byte always is in the range from 0x00 to 0x0F
1505 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)
1507 unsigned char h[32];
1509 if(crypto->authenticated)
1513 // AES packet = 1 byte length overhead, 15 bytes from HMAC-SHA-256, data, 0..15 bytes padding
1514 // 15 bytes HMAC-SHA-256 (112bit) suffice as the attacker can't do more than forge a random-looking packet
1515 // HMAC is needed to not leak information about packet content
1516 if(developer_networking.integer)
1518 Con_Print("To be encrypted:\n");
1519 Com_HexDumpToConsole((const unsigned char *) data_src, (int)len_src);
1521 if(len_src + 32 > len || !HMAC_SHA256_32BYTES(h, (const unsigned char *) data_src, (int)len_src, crypto->dhkey, DHKEY_SIZE))
1523 Con_Printf("Crypto_EncryptPacket failed (not enough space: %d bytes in, %d bytes out)\n", (int) len_src, (int) len);
1526 *len_dst = ((len_src + 15) / 16) * 16 + 16; // add 16 for HMAC, then round to 16-size for AES
1527 ((unsigned char *) data_dst)[0] = (unsigned char)(*len_dst - len_src);
1528 memcpy(((unsigned char *) data_dst)+1, h, 15);
1529 aescpy(crypto->dhkey, (const unsigned char *) data_dst, ((unsigned char *) data_dst) + 16, (const unsigned char *) data_src, len_src);
1534 // HMAC packet = 16 bytes HMAC-SHA-256 (truncated to 128 bits), data
1535 if(len_src + 16 > len || !HMAC_SHA256_32BYTES(h, (const unsigned char *) data_src, (int)len_src, crypto->dhkey, DHKEY_SIZE))
1537 Con_Printf("Crypto_EncryptPacket failed (not enough space: %d bytes in, %d bytes out)\n", (int) len_src, (int) len);
1540 *len_dst = len_src + 16;
1541 memcpy(data_dst, h, 16);
1542 memcpy(((unsigned char *) data_dst) + 16, (unsigned char *) data_src, len_src);
1544 // handle the "avoid" conditions:
1545 i = BuffBigLong((unsigned char *) data_dst);
1547 (i == (int)0xFFFFFFFF) // avoid QW control packet
1549 (i == (int)0x80000000 + (int)*len_dst) // avoid NQ control packet
1551 *(unsigned char *)data_dst ^= 0x80; // this will ALWAYS fix it
1562 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)
1564 unsigned char h[32];
1567 // silently handle non-crypto packets
1568 i = BuffBigLong((unsigned char *) data_src);
1570 (i == (int)0xFFFFFFFF) // avoid QW control packet
1572 (i == (int)0x80000000 + (int)len_src) // avoid NQ control packet
1576 if(crypto->authenticated)
1580 if(len_src < 16 || ((len_src - 16) % 16))
1582 Con_Printf("Crypto_DecryptPacket failed (not enough space: %d bytes in, %d bytes out)\n", (int) len_src, (int) len);
1585 *len_dst = len_src - ((unsigned char *) data_src)[0];
1586 if(len < *len_dst || *len_dst > len_src - 16)
1588 Con_Printf("Crypto_DecryptPacket failed (not enough space: %d bytes in, %d->%d bytes out)\n", (int) len_src, (int) *len_dst, (int) len);
1591 seacpy(crypto->dhkey, (unsigned char *) data_src, (unsigned char *) data_dst, ((const unsigned char *) data_src) + 16, *len_dst);
1593 if(!HMAC_SHA256_32BYTES(h, (const unsigned char *) data_dst, (int)*len_dst, crypto->dhkey, DHKEY_SIZE))
1595 Con_Printf("HMAC fail\n");
1598 if(memcmp(((const unsigned char *) data_src)+1, h, 15)) // ignore first byte, used for length
1600 Con_Printf("HMAC mismatch\n");
1603 if(developer_networking.integer)
1605 Con_Print("Decrypted:\n");
1606 Com_HexDumpToConsole((const unsigned char *) data_dst, (int)*len_dst);
1608 return data_dst; // no need to copy
1614 Con_Printf("Crypto_DecryptPacket failed (not enough space: %d bytes in, %d bytes out)\n", (int) len_src, (int) len);
1617 *len_dst = len_src - 16;
1620 Con_Printf("Crypto_DecryptPacket failed (not enough space: %d bytes in, %d->%d bytes out)\n", (int) len_src, (int) *len_dst, (int) len);
1623 //memcpy(data_dst, data_src + 16, *len_dst);
1624 if(!HMAC_SHA256_32BYTES(h, ((const unsigned char *) data_src) + 16, (int)*len_dst, crypto->dhkey, DHKEY_SIZE))
1626 Con_Printf("HMAC fail\n");
1627 Com_HexDumpToConsole((const unsigned char *) data_src, (int)len_src);
1631 if(memcmp((const unsigned char *) data_src, h, 16)) // ignore first byte, used for length
1633 // undo the "avoid conditions"
1635 (i == (int)0x7FFFFFFF) // avoided QW control packet
1637 (i == (int)0x00000000 + (int)len_src) // avoided NQ control packet
1640 // do the avoidance on the hash too
1642 if(memcmp((const unsigned char *) data_src, h, 16)) // ignore first byte, used for length
1644 Con_Printf("HMAC mismatch\n");
1645 Com_HexDumpToConsole((const unsigned char *) data_src, (int)len_src);
1651 Con_Printf("HMAC mismatch\n");
1652 Com_HexDumpToConsole((const unsigned char *) data_src, (int)len_src);
1656 return ((const unsigned char *) data_src) + 16; // no need to copy, so data_dst is not used
1667 const char *Crypto_GetInfoResponseDataString(void)
1669 crypto_idstring_buf[0] = '0' + crypto_aeslevel.integer;
1670 return crypto_idstring;
1674 qboolean Crypto_ServerAppendToChallenge(const char *data_in, size_t len_in, char *data_out, size_t *len_out, size_t maxlen_out)
1676 // cheap op, all is precomputed
1677 if(!d0_blind_id_dll)
1678 return false; // no support
1680 if(maxlen_out <= *len_out + challenge_append_length)
1682 memcpy(data_out + *len_out, challenge_append, challenge_append_length);
1683 *len_out += challenge_append_length;
1687 static int Crypto_ServerError(char *data_out, size_t *len_out, const char *msg, const char *msg_client)
1691 Con_DPrintf("rejecting client: %s\n", msg);
1693 dpsnprintf(data_out, *len_out, "reject %s", msg_client);
1694 *len_out = strlen(data_out);
1695 return CRYPTO_DISCARD;
1698 static int Crypto_SoftServerError(char *data_out, size_t *len_out, const char *msg)
1701 Con_DPrintf("%s\n", msg);
1702 return CRYPTO_DISCARD;
1705 static int Crypto_ServerParsePacket_Internal(const char *data_in, size_t len_in, char *data_out, size_t *len_out, lhnetaddress_t *peeraddress)
1707 // if "connect": reject if in the middle of crypto handshake
1708 crypto_t *crypto = NULL;
1709 char *data_out_p = data_out;
1710 const char *string = data_in;
1714 char infostringvalue[MAX_INPUTLINE];
1717 if(!d0_blind_id_dll)
1718 return CRYPTO_NOMATCH; // no support
1720 if (len_in > 8 && !memcmp(string, "connect\\", 8) && d0_rijndael_dll && crypto_aeslevel.integer >= 3)
1724 // sorry, we have to verify the challenge here to not reflect network spam
1726 if (!(s = InfoString_GetValue(string + 4, "challenge", infostringvalue, sizeof(infostringvalue))))
1727 return CRYPTO_NOMATCH; // will be later accepted if encryption was set up
1728 // validate the challenge
1729 for (i = 0;i < MAX_CHALLENGES;i++)
1730 if(challenges[i].time > 0)
1731 if (!LHNETADDRESS_Compare(peeraddress, &challenges[i].address) && !strcmp(challenges[i].string, s))
1733 // if the challenge is not recognized, drop the packet
1734 if (i == MAX_CHALLENGES) // challenge mismatch is silent
1735 return Crypto_SoftServerError(data_out, len_out, "missing challenge in connect");
1737 crypto = Crypto_ServerFindInstance(peeraddress, false);
1738 if(!crypto || !crypto->authenticated)
1739 return Crypto_ServerError(data_out, len_out, "This server requires authentication and encryption to be supported by your client", NULL);
1741 else if(len_in > 5 && !memcmp(string, "d0pk\\", 5) && ((LHNETADDRESS_GetAddressType(peeraddress) == LHNETADDRESSTYPE_LOOP) || sv_public.integer > -3))
1743 const char *cnt, *s, *p;
1745 int clientid = -1, serverid = -1;
1746 cnt = InfoString_GetValue(string + 4, "id", infostringvalue, sizeof(infostringvalue));
1747 id = (cnt ? atoi(cnt) : -1);
1748 cnt = InfoString_GetValue(string + 4, "cnt", infostringvalue, sizeof(infostringvalue));
1750 return Crypto_SoftServerError(data_out, len_out, "missing cnt in d0pk");
1751 GetUntilNul(&data_in, &len_in);
1753 return Crypto_SoftServerError(data_out, len_out, "missing appended data in d0pk");
1754 if(!strcmp(cnt, "0"))
1757 if (!(s = InfoString_GetValue(string + 4, "challenge", infostringvalue, sizeof(infostringvalue))))
1758 return Crypto_SoftServerError(data_out, len_out, "missing challenge in d0pk\\0");
1759 // validate the challenge
1760 for (i = 0;i < MAX_CHALLENGES;i++)
1761 if(challenges[i].time > 0)
1762 if (!LHNETADDRESS_Compare(peeraddress, &challenges[i].address) && !strcmp(challenges[i].string, s))
1764 // if the challenge is not recognized, drop the packet
1765 if (i == MAX_CHALLENGES)
1766 return Crypto_SoftServerError(data_out, len_out, "invalid challenge in d0pk\\0");
1768 if (!(s = InfoString_GetValue(string + 4, "aeslevel", infostringvalue, sizeof(infostringvalue))))
1769 aeslevel = 0; // not supported
1771 aeslevel = bound(0, atoi(s), 3);
1772 switch(bound(0, d0_rijndael_dll ? crypto_aeslevel.integer : 0, 3))
1774 default: // dummy, never happens, but to make gcc happy...
1777 return Crypto_ServerError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)", NULL);
1781 aes = (aeslevel >= 2);
1784 aes = (aeslevel >= 1);
1788 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);
1793 p = GetUntilNul(&data_in, &len_in);
1796 // Find the highest numbered matching key for p.
1797 for(i = 0; i < MAX_PUBKEYS; ++i)
1800 if(!strcmp(p, pubkeys_fp64[i]))
1801 if(pubkeys_havepriv[i])
1805 return Crypto_ServerError(data_out, len_out, "Invalid server key", NULL);
1807 p = GetUntilNul(&data_in, &len_in);
1810 // Find the highest numbered matching key for p.
1811 for(i = 0; i < MAX_PUBKEYS; ++i)
1814 if(!strcmp(p, pubkeys_fp64[i]))
1818 return Crypto_ServerError(data_out, len_out, "Invalid client key", NULL);
1821 crypto = Crypto_ServerFindInstance(peeraddress, true);
1823 return Crypto_ServerError(data_out, len_out, "Could not create a crypto connect instance", NULL);
1825 CDATA->cdata_id = id;
1826 CDATA->s = serverid;
1827 CDATA->c = clientid;
1828 memset(crypto->dhkey, 0, sizeof(crypto->dhkey));
1829 CDATA->challenge[0] = 0;
1830 crypto->client_keyfp[0] = 0;
1831 crypto->client_idfp[0] = 0;
1832 crypto->server_keyfp[0] = 0;
1833 crypto->server_idfp[0] = 0;
1834 crypto->use_aes = aes != 0;
1838 // I am the server, and my key is ok... so let's set server_keyfp and server_idfp
1839 strlcpy(crypto->server_keyfp, pubkeys_fp64[CDATA->s], sizeof(crypto->server_keyfp));
1840 strlcpy(crypto->server_idfp, pubkeys_priv_fp64[CDATA->s], sizeof(crypto->server_idfp));
1841 crypto->server_issigned = pubkeys_havesig[CDATA->s];
1844 CDATA->id = qd0_blind_id_new();
1848 return Crypto_ServerError(data_out, len_out, "d0_blind_id_new failed", "Internal error");
1850 if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->s]))
1853 return Crypto_ServerError(data_out, len_out, "d0_blind_id_copy failed", "Internal error");
1855 PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\1\\id\\%d\\aes\\%d", CDATA->cdata_id, crypto->use_aes));
1856 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
1859 return Crypto_ServerError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_start failed", "Internal error");
1861 CDATA->next_step = 2;
1862 data_out_p += *len_out;
1863 *len_out = data_out_p - data_out;
1864 return CRYPTO_DISCARD;
1866 else if(CDATA->c >= 0)
1869 CDATA->id = qd0_blind_id_new();
1873 return Crypto_ServerError(data_out, len_out, "d0_blind_id_new failed", "Internal error");
1875 if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->c]))
1878 return Crypto_ServerError(data_out, len_out, "d0_blind_id_copy failed", "Internal error");
1880 PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\5\\id\\%d\\aes\\%d", CDATA->cdata_id, crypto->use_aes));
1881 if(!qd0_blind_id_authenticate_with_private_id_challenge(CDATA->id, true, false, data_in, len_in, data_out_p, len_out, &status))
1884 return Crypto_ServerError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_challenge failed", "Internal error");
1886 CDATA->next_step = 6;
1887 data_out_p += *len_out;
1888 *len_out = data_out_p - data_out;
1889 return CRYPTO_DISCARD;
1894 return Crypto_ServerError(data_out, len_out, "Missing client and server key", NULL);
1897 else if(!strcmp(cnt, "2"))
1900 crypto = Crypto_ServerFindInstance(peeraddress, false);
1902 return CRYPTO_NOMATCH; // pre-challenge, rather be silent
1904 if(CDATA->cdata_id != id)
1905 return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
1906 if(CDATA->next_step != 2)
1907 return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
1909 PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\3\\id\\%d", CDATA->cdata_id));
1910 if(!qd0_blind_id_authenticate_with_private_id_response(CDATA->id, data_in, len_in, data_out_p, len_out))
1913 return Crypto_ServerError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_response failed", "Internal error");
1915 fpbuflen = DHKEY_SIZE;
1916 if(!qd0_blind_id_sessionkey_public_id(CDATA->id, (char *) crypto->dhkey, &fpbuflen))
1919 return Crypto_ServerError(data_out, len_out, "d0_blind_id_sessionkey_public_id failed", "Internal error");
1923 if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->c]))
1926 return Crypto_ServerError(data_out, len_out, "d0_blind_id_copy failed", "Internal error");
1928 CDATA->next_step = 4;
1932 // session key is FINISHED (no server part is to be expected)! By this, all keys are set up
1933 crypto->authenticated = true;
1934 CDATA->next_step = 0;
1936 data_out_p += *len_out;
1937 *len_out = data_out_p - data_out;
1938 return CRYPTO_DISCARD;
1940 else if(!strcmp(cnt, "4"))
1942 crypto = Crypto_ServerFindInstance(peeraddress, false);
1944 return CRYPTO_NOMATCH; // pre-challenge, rather be silent
1946 if(CDATA->cdata_id != id)
1947 return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
1948 if(CDATA->next_step != 4)
1949 return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
1950 PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\5\\id\\%d", CDATA->cdata_id));
1951 if(!qd0_blind_id_authenticate_with_private_id_challenge(CDATA->id, true, false, data_in, len_in, data_out_p, len_out, &status))
1954 return Crypto_ServerError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_challenge failed", "Internal error");
1956 CDATA->next_step = 6;
1957 data_out_p += *len_out;
1958 *len_out = data_out_p - data_out;
1959 return CRYPTO_DISCARD;
1961 else if(!strcmp(cnt, "6"))
1963 static char msgbuf[32];
1964 size_t msgbuflen = sizeof(msgbuf);
1967 unsigned char dhkey[DHKEY_SIZE];
1968 crypto = Crypto_ServerFindInstance(peeraddress, false);
1970 return CRYPTO_NOMATCH; // pre-challenge, rather be silent
1972 if(CDATA->cdata_id != id)
1973 return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
1974 if(CDATA->next_step != 6)
1975 return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
1977 if(!qd0_blind_id_authenticate_with_private_id_verify(CDATA->id, data_in, len_in, msgbuf, &msgbuflen, &status))
1980 return Crypto_ServerError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_verify failed (authentication error)", "Authentication error");
1982 strlcpy(crypto->client_keyfp, pubkeys_fp64[CDATA->c], sizeof(crypto->client_keyfp));
1983 crypto->client_issigned = status;
1985 memset(crypto->client_idfp, 0, sizeof(crypto->client_idfp));
1986 fpbuflen = FP64_SIZE;
1987 if(!qd0_blind_id_fingerprint64_public_id(CDATA->id, crypto->client_idfp, &fpbuflen))
1990 return Crypto_ServerError(data_out, len_out, "d0_blind_id_fingerprint64_public_id failed", "Internal error");
1992 fpbuflen = DHKEY_SIZE;
1993 if(!qd0_blind_id_sessionkey_public_id(CDATA->id, (char *) dhkey, &fpbuflen))
1996 return Crypto_ServerError(data_out, len_out, "d0_blind_id_sessionkey_public_id failed", "Internal error");
1998 // XOR the two DH keys together to make one
1999 for(i = 0; i < DHKEY_SIZE; ++i)
2000 crypto->dhkey[i] ^= dhkey[i];
2002 // session key is FINISHED (no server part is to be expected)! By this, all keys are set up
2003 crypto->authenticated = true;
2004 CDATA->next_step = 0;
2005 // send a challenge-less challenge
2006 PutWithNul(&data_out_p, len_out, "challenge ");
2007 *len_out = data_out_p - data_out;
2008 --*len_out; // remove NUL terminator
2009 return CRYPTO_MATCH;
2011 return CRYPTO_NOMATCH; // pre-challenge, rather be silent
2013 return CRYPTO_NOMATCH;
2016 int Crypto_ServerParsePacket(const char *data_in, size_t len_in, char *data_out, size_t *len_out, lhnetaddress_t *peeraddress)
2020 static double complain_time = 0;
2022 qboolean do_time = false;
2023 qboolean do_reject = false;
2024 char infostringvalue[MAX_INPUTLINE];
2025 if(crypto_servercpupercent.value > 0 || crypto_servercpumaxtime.value > 0)
2026 if(len_in > 5 && !memcmp(data_in, "d0pk\\", 5))
2029 cnt = InfoString_GetValue(data_in + 4, "cnt", infostringvalue, sizeof(infostringvalue));
2031 if(!strcmp(cnt, "0"))
2036 // check if we may perform crypto...
2037 if(crypto_servercpupercent.value > 0)
2039 crypto_servercpu_accumulator += (realtime - crypto_servercpu_lastrealtime) * crypto_servercpupercent.value * 0.01;
2040 if(crypto_servercpumaxtime.value)
2041 if(crypto_servercpu_accumulator > crypto_servercpumaxtime.value)
2042 crypto_servercpu_accumulator = crypto_servercpumaxtime.value;
2046 if(crypto_servercpumaxtime.value > 0)
2047 if(realtime != crypto_servercpu_lastrealtime)
2048 crypto_servercpu_accumulator = crypto_servercpumaxtime.value;
2050 crypto_servercpu_lastrealtime = realtime;
2051 if(do_reject && crypto_servercpu_accumulator < 0)
2053 if(realtime > complain_time + 5)
2054 Con_Printf("crypto: cannot perform requested crypto operations; denial service attack or crypto_servercpupercent/crypto_servercpumaxtime are too low\n");
2056 return CRYPTO_DISCARD;
2058 t = Sys_DirtyTime();
2060 ret = Crypto_ServerParsePacket_Internal(data_in, len_in, data_out, len_out, peeraddress);
2063 t = Sys_DirtyTime() - t;if (t < 0.0) t = 0.0; // dirtytime can step backwards
2064 if(crypto_servercpudebug.integer)
2065 Con_Printf("crypto: accumulator was %.1f ms, used %.1f ms for crypto, ", crypto_servercpu_accumulator * 1000, t * 1000);
2066 crypto_servercpu_accumulator -= t;
2067 if(crypto_servercpudebug.integer)
2068 Con_Printf("is %.1f ms\n", crypto_servercpu_accumulator * 1000);
2073 static int Crypto_ClientError(char *data_out, size_t *len_out, const char *msg)
2075 dpsnprintf(data_out, *len_out, "reject %s", msg);
2076 *len_out = strlen(data_out);
2077 return CRYPTO_REPLACE;
2080 static int Crypto_SoftClientError(char *data_out, size_t *len_out, const char *msg)
2083 Con_DPrintf("%s\n", msg);
2084 return CRYPTO_DISCARD;
2087 int Crypto_ClientParsePacket(const char *data_in, size_t len_in, char *data_out, size_t *len_out, lhnetaddress_t *peeraddress)
2089 crypto_t *crypto = &cls.crypto;
2090 const char *string = data_in;
2093 char *data_out_p = data_out;
2095 char infostringvalue[MAX_INPUTLINE];
2098 if(!d0_blind_id_dll)
2099 return CRYPTO_NOMATCH; // no support
2101 // if "challenge": verify challenge, and discard message, send next crypto protocol message instead
2102 // otherwise, just handle actual protocol messages
2104 if (len_in == 6 && !memcmp(string, "accept", 6) && cls.connect_trying && d0_rijndael_dll)
2106 int wantserverid = -1;
2107 Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, NULL, 0, NULL, NULL);
2108 if(!crypto || !crypto->authenticated) // we ALSO get here if we are using an encrypted connection, so let's rule this out
2110 if(wantserverid >= 0)
2111 return Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though a host key is present");
2112 if(crypto_aeslevel.integer >= 3)
2113 return Crypto_ClientError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)");
2115 return CRYPTO_NOMATCH;
2117 else if (len_in >= 1 && string[0] == 'j' && cls.connect_trying && d0_rijndael_dll)
2119 int wantserverid = -1;
2120 Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, NULL, 0, NULL, NULL);
2121 //if(!crypto || !crypto->authenticated)
2123 if(wantserverid >= 0)
2124 return Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though a host key is present");
2125 if(crypto_aeslevel.integer >= 3)
2126 return Crypto_ClientError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)");
2128 return CRYPTO_NOMATCH;
2130 else if (len_in >= 5 && BuffLittleLong((unsigned char *) string) == ((int)NETFLAG_CTL | (int)len_in))
2132 int wantserverid = -1;
2134 // these three are harmless
2135 if((unsigned char) string[4] == CCREP_SERVER_INFO)
2136 return CRYPTO_NOMATCH;
2137 if((unsigned char) string[4] == CCREP_PLAYER_INFO)
2138 return CRYPTO_NOMATCH;
2139 if((unsigned char) string[4] == CCREP_RULE_INFO)
2140 return CRYPTO_NOMATCH;
2142 Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, NULL, 0, NULL, NULL);
2143 //if(!crypto || !crypto->authenticated)
2145 if(wantserverid >= 0)
2146 return Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though a host key is present");
2147 if(crypto_aeslevel.integer >= 3)
2148 return Crypto_ClientError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)");
2150 return CRYPTO_NOMATCH;
2152 else if (len_in >= 13 && !memcmp(string, "infoResponse\x0A", 13))
2154 s = InfoString_GetValue(string + 13, "d0_blind_id", infostringvalue, sizeof(infostringvalue));
2156 Crypto_StoreHostKey(peeraddress, s, true);
2157 return CRYPTO_NOMATCH;
2159 else if (len_in >= 15 && !memcmp(string, "statusResponse\x0A", 15))
2163 p = strchr(string + 15, '\n');
2167 * (char *) p = 0; // cut off the string there
2169 s = InfoString_GetValue(string + 15, "d0_blind_id", infostringvalue, sizeof(infostringvalue));
2171 Crypto_StoreHostKey(peeraddress, s, true);
2174 * (char *) p = save;
2175 // invoking those nasal demons again (do not run this on the DS9k)
2177 return CRYPTO_NOMATCH;
2179 else if(len_in > 10 && !memcmp(string, "challenge ", 10) && cls.connect_trying)
2181 const char *vlen_blind_id_ptr = NULL;
2182 size_t len_blind_id_ptr = 0;
2184 const char *challenge = data_in + 10;
2187 int clientid = -1, serverid = -1, wantserverid = -1;
2188 qboolean server_can_auth = true;
2189 char wantserver_idfp[FP64_SIZE+1];
2190 int wantserver_aeslevel = 0;
2191 qboolean wantserver_issigned = false;
2193 // 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.
2194 if (net_sourceaddresscheck.integer && LHNETADDRESS_Compare(peeraddress, &cls.connect_address))
2195 return Crypto_SoftClientError(data_out, len_out, "challenge message from wrong server");
2197 // if we have a stored host key for the server, assume serverid to already be selected!
2198 // (the loop will refuse to overwrite this one then)
2199 wantserver_idfp[0] = 0;
2200 Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, wantserver_idfp, sizeof(wantserver_idfp), &wantserver_aeslevel, &wantserver_issigned);
2201 // requirement: wantserver_idfp is a full ID if wantserverid set
2203 // if we leave, we have to consider the connection
2204 // unauthenticated; NOTE: this may be faked by a clever
2205 // attacker to force an unauthenticated connection; so we have
2206 // a safeguard check in place when encryption is required too
2207 // in place, or when authentication is required by the server
2208 crypto->authenticated = false;
2210 GetUntilNul(&data_in, &len_in);
2212 return (wantserverid >= 0) ? Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though a host key is present") :
2213 (d0_rijndael_dll && crypto_aeslevel.integer >= 3) ? Crypto_ClientError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)") :
2216 // FTEQW extension protocol
2219 k = Crypto_LittleLong(data_in);
2220 v = Crypto_LittleLong(data_in + 4);
2228 k = Crypto_LittleLong(data_in);
2233 case PROTOCOL_D0_BLIND_ID:
2234 vlen_blind_id_ptr = data_in;
2235 len_blind_id_ptr = v;
2247 if(!vlen_blind_id_ptr)
2248 return (wantserverid >= 0) ? Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though authentication is required") :
2249 (d0_rijndael_dll && crypto_aeslevel.integer >= 3) ? Crypto_ClientError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)") :
2252 data_in = vlen_blind_id_ptr;
2253 len_in = len_blind_id_ptr;
2255 // parse fingerprints
2256 // once we found a fingerprint we can auth to (ANY), select it as clientfp
2257 // once we found a fingerprint in the first list that we know, select it as serverfp
2261 p = GetUntilNul(&data_in, &len_in);
2266 if(!server_can_auth)
2267 break; // other protocol message may follow
2268 server_can_auth = false;
2273 // Find the highest numbered matching key for p.
2274 for(i = 0; i < MAX_PUBKEYS; ++i)
2277 if(!strcmp(p, pubkeys_fp64[i]))
2279 if(pubkeys_havepriv[i])
2282 if(wantserverid < 0 || i == wantserverid)
2286 // Not breaking, as higher keys in the list always have priority.
2289 // if stored host key is not found:
2290 if(wantserverid >= 0 && serverid < 0)
2291 return Crypto_ClientError(data_out, len_out, "Server CA does not match stored host key, refusing to connect");
2293 if(serverid >= 0 || clientid >= 0)
2296 CDATA->cdata_id = ++cdata_id;
2297 CDATA->s = serverid;
2298 CDATA->c = clientid;
2299 memset(crypto->dhkey, 0, sizeof(crypto->dhkey));
2300 strlcpy(CDATA->challenge, challenge, sizeof(CDATA->challenge));
2301 crypto->client_keyfp[0] = 0;
2302 crypto->client_idfp[0] = 0;
2303 crypto->server_keyfp[0] = 0;
2304 crypto->server_idfp[0] = 0;
2305 memcpy(CDATA->wantserver_idfp, wantserver_idfp, sizeof(crypto->server_idfp));
2306 CDATA->wantserver_issigned = wantserver_issigned;
2308 if(CDATA->wantserver_idfp[0]) // if we know a host key, honor its encryption setting
2309 switch(bound(0, d0_rijndael_dll ? crypto_aeslevel.integer : 0, 3))
2311 default: // dummy, never happens, but to make gcc happy...
2313 if(wantserver_aeslevel >= 3)
2314 return Crypto_ClientError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)");
2315 CDATA->wantserver_aes = false;
2318 CDATA->wantserver_aes = (wantserver_aeslevel >= 2);
2321 CDATA->wantserver_aes = (wantserver_aeslevel >= 1);
2324 if(wantserver_aeslevel <= 0)
2325 return Crypto_ClientError(data_out, len_out, "This server requires encryption to be supported (crypto_aeslevel >= 1, and d0_rijndael library must be present)");
2326 CDATA->wantserver_aes = true;
2330 // build outgoing message
2331 // append regular stuff
2332 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));
2333 PutWithNul(&data_out_p, len_out, serverid >= 0 ? pubkeys_fp64[serverid] : "");
2334 PutWithNul(&data_out_p, len_out, clientid >= 0 ? pubkeys_fp64[clientid] : "");
2338 // I am the client, and my key is ok... so let's set client_keyfp and client_idfp
2339 strlcpy(crypto->client_keyfp, pubkeys_fp64[CDATA->c], sizeof(crypto->client_keyfp));
2340 strlcpy(crypto->client_idfp, pubkeys_priv_fp64[CDATA->c], sizeof(crypto->client_idfp));
2341 crypto->client_issigned = pubkeys_havesig[CDATA->c];
2347 CDATA->id = qd0_blind_id_new();
2351 return Crypto_ClientError(data_out, len_out, "d0_blind_id_new failed");
2353 if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->s]))
2356 return Crypto_ClientError(data_out, len_out, "d0_blind_id_copy failed");
2358 CDATA->next_step = 1;
2359 *len_out = data_out_p - data_out;
2361 else // if(clientid >= 0) // guaranteed by condition one level outside
2363 // skip over server auth, perform client auth only
2365 CDATA->id = qd0_blind_id_new();
2369 return Crypto_ClientError(data_out, len_out, "d0_blind_id_new failed");
2371 if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->c]))
2374 return Crypto_ClientError(data_out, len_out, "d0_blind_id_copy failed");
2376 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
2379 return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_start failed");
2381 CDATA->next_step = 5;
2382 data_out_p += *len_out;
2383 *len_out = data_out_p - data_out;
2385 return CRYPTO_DISCARD;
2389 if(wantserver_idfp[0]) // if we know a host key, honor its encryption setting
2390 if(wantserver_aeslevel >= 3)
2391 return Crypto_ClientError(data_out, len_out, "Server insists on encryption, but neither can authenticate to the other");
2392 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)") :
2396 else if(len_in > 5 && !memcmp(string, "d0pk\\", 5) && cls.connect_trying)
2401 // 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.
2402 if (net_sourceaddresscheck.integer && LHNETADDRESS_Compare(peeraddress, &cls.connect_address))
2403 return Crypto_SoftClientError(data_out, len_out, "d0pk\\ message from wrong server");
2405 cnt = InfoString_GetValue(string + 4, "id", infostringvalue, sizeof(infostringvalue));
2406 id = (cnt ? atoi(cnt) : -1);
2407 cnt = InfoString_GetValue(string + 4, "cnt", infostringvalue, sizeof(infostringvalue));
2409 return Crypto_ClientError(data_out, len_out, "d0pk\\ message without cnt");
2410 GetUntilNul(&data_in, &len_in);
2412 return Crypto_ClientError(data_out, len_out, "d0pk\\ message without attachment");
2414 if(!strcmp(cnt, "1"))
2417 if(CDATA->cdata_id != id)
2418 return Crypto_SoftClientError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
2419 if(CDATA->next_step != 1)
2420 return Crypto_SoftClientError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
2422 cls.connect_nextsendtime = max(cls.connect_nextsendtime, realtime + 1); // prevent "hammering"
2424 if((s = InfoString_GetValue(string + 4, "aes", infostringvalue, sizeof(infostringvalue))))
2428 // we CANNOT toggle the AES status any more!
2429 // as the server already decided
2430 if(CDATA->wantserver_idfp[0]) // if we know a host key, honor its encryption setting
2431 if(!aes && CDATA->wantserver_aes)
2434 return Crypto_ClientError(data_out, len_out, "Stored host key requires encryption, but server did not enable encryption");
2436 if(aes && (!d0_rijndael_dll || crypto_aeslevel.integer <= 0))
2439 return Crypto_ClientError(data_out, len_out, "Server insists on encryption too hard");
2441 if(!aes && (d0_rijndael_dll && crypto_aeslevel.integer >= 3))
2444 return Crypto_ClientError(data_out, len_out, "Server insists on plaintext too hard");
2446 crypto->use_aes = aes != 0;
2448 PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\2\\id\\%d", CDATA->cdata_id));
2449 if(!qd0_blind_id_authenticate_with_private_id_challenge(CDATA->id, true, false, data_in, len_in, data_out_p, len_out, &status))
2452 return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_challenge failed");
2454 CDATA->next_step = 3;
2455 data_out_p += *len_out;
2456 *len_out = data_out_p - data_out;
2457 return CRYPTO_DISCARD;
2459 else if(!strcmp(cnt, "3"))
2461 static char msgbuf[32];
2462 size_t msgbuflen = sizeof(msgbuf);
2466 if(CDATA->cdata_id != id)
2467 return Crypto_SoftClientError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
2468 if(CDATA->next_step != 3)
2469 return Crypto_SoftClientError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
2471 cls.connect_nextsendtime = max(cls.connect_nextsendtime, realtime + 1); // prevent "hammering"
2473 if(!qd0_blind_id_authenticate_with_private_id_verify(CDATA->id, data_in, len_in, msgbuf, &msgbuflen, &status))
2476 return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_verify failed (server authentication error)");
2479 strlcpy(crypto->server_keyfp, pubkeys_fp64[CDATA->s], sizeof(crypto->server_keyfp));
2480 if (!status && CDATA->wantserver_issigned)
2483 return Crypto_ClientError(data_out, len_out, "Stored host key requires a valid signature, but server did not provide any");
2485 crypto->server_issigned = status;
2487 memset(crypto->server_idfp, 0, sizeof(crypto->server_idfp));
2488 fpbuflen = FP64_SIZE;
2489 if(!qd0_blind_id_fingerprint64_public_id(CDATA->id, crypto->server_idfp, &fpbuflen))
2492 return Crypto_ClientError(data_out, len_out, "d0_blind_id_fingerprint64_public_id failed");
2494 if(CDATA->wantserver_idfp[0])
2495 if(memcmp(CDATA->wantserver_idfp, crypto->server_idfp, sizeof(crypto->server_idfp)))
2498 return Crypto_ClientError(data_out, len_out, "Server ID does not match stored host key, refusing to connect");
2500 fpbuflen = DHKEY_SIZE;
2501 if(!qd0_blind_id_sessionkey_public_id(CDATA->id, (char *) crypto->dhkey, &fpbuflen))
2504 return Crypto_ClientError(data_out, len_out, "d0_blind_id_sessionkey_public_id failed");
2507 // cache the server key
2508 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);
2512 // client will auth next
2513 PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\4\\id\\%d", CDATA->cdata_id));
2514 if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->c]))
2517 return Crypto_ClientError(data_out, len_out, "d0_blind_id_copy failed");
2519 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
2522 return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_start failed");
2524 CDATA->next_step = 5;
2525 data_out_p += *len_out;
2526 *len_out = data_out_p - data_out;
2527 return CRYPTO_DISCARD;
2531 // session key is FINISHED (no server part is to be expected)! By this, all keys are set up
2532 crypto->authenticated = true;
2533 CDATA->next_step = 0;
2534 // assume we got the empty challenge to finish the protocol
2535 PutWithNul(&data_out_p, len_out, "challenge ");
2536 *len_out = data_out_p - data_out;
2537 --*len_out; // remove NUL terminator
2538 return CRYPTO_REPLACE;
2541 else if(!strcmp(cnt, "5"))
2544 unsigned char dhkey[DHKEY_SIZE];
2548 if(CDATA->cdata_id != id)
2549 return Crypto_SoftClientError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
2550 if(CDATA->next_step != 5)
2551 return Crypto_SoftClientError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
2553 cls.connect_nextsendtime = max(cls.connect_nextsendtime, realtime + 1); // prevent "hammering"
2555 if(CDATA->s < 0) // only if server didn't auth
2557 if((s = InfoString_GetValue(string + 4, "aes", infostringvalue, sizeof(infostringvalue))))
2561 if(CDATA->wantserver_idfp[0]) // if we know a host key, honor its encryption setting
2562 if(!aes && CDATA->wantserver_aes)
2565 return Crypto_ClientError(data_out, len_out, "Stored host key requires encryption, but server did not enable encryption");
2567 if(aes && (!d0_rijndael_dll || crypto_aeslevel.integer <= 0))
2570 return Crypto_ClientError(data_out, len_out, "Server insists on encryption too hard");
2572 if(!aes && (d0_rijndael_dll && crypto_aeslevel.integer >= 3))
2575 return Crypto_ClientError(data_out, len_out, "Server insists on plaintext too hard");
2577 crypto->use_aes = aes != 0;
2580 PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\6\\id\\%d", CDATA->cdata_id));
2581 if(!qd0_blind_id_authenticate_with_private_id_response(CDATA->id, data_in, len_in, data_out_p, len_out))
2584 return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_response failed");
2586 fpbuflen = DHKEY_SIZE;
2587 if(!qd0_blind_id_sessionkey_public_id(CDATA->id, (char *) dhkey, &fpbuflen))
2590 return Crypto_ClientError(data_out, len_out, "d0_blind_id_sessionkey_public_id failed");
2592 // XOR the two DH keys together to make one
2593 for(i = 0; i < DHKEY_SIZE; ++i)
2594 crypto->dhkey[i] ^= dhkey[i];
2595 // session key is FINISHED! By this, all keys are set up
2596 crypto->authenticated = true;
2597 CDATA->next_step = 0;
2598 data_out_p += *len_out;
2599 *len_out = data_out_p - data_out;
2600 return CRYPTO_DISCARD;
2602 return Crypto_SoftClientError(data_out, len_out, "Got unknown d0_blind_id message from server");
2605 return CRYPTO_NOMATCH;
2608 size_t Crypto_SignData(const void *data, size_t datasize, int keyid, void *signed_data, size_t signed_size)
2610 if(keyid < 0 || keyid >= MAX_PUBKEYS)
2612 if(!pubkeys_havepriv[keyid])
2614 if(qd0_blind_id_sign_with_private_id_sign(pubkeys[keyid], true, false, (const char *)data, datasize, (char *)signed_data, &signed_size))
2619 size_t Crypto_SignDataDetached(const void *data, size_t datasize, int keyid, void *signed_data, size_t signed_size)
2621 if(keyid < 0 || keyid >= MAX_PUBKEYS)
2623 if(!pubkeys_havepriv[keyid])
2625 if(qd0_blind_id_sign_with_private_id_sign_detached(pubkeys[keyid], true, false, (const char *)data, datasize, (char *)signed_data, &signed_size))