2 Copyright (C) 2010-2015 Rudolf Polzer (divVerent)
3 Copyright (C) 2010-2020 Ashley Rose Hale (LadyHavoc)
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 See the GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 cvar_t crypto_developer = {CF_CLIENT | CF_SERVER | CF_ARCHIVE, "crypto_developer", "0", "print extra info about crypto handshake"};
31 cvar_t crypto_aeslevel = {CF_CLIENT | CF_SERVER | CF_ARCHIVE, "crypto_aeslevel", "1", "whether to support AES encryption in authenticated connections (0 = no, 1 = supported, 2 = requested, 3 = required)"};
33 cvar_t crypto_servercpupercent = {CF_CLIENT | CF_SERVER | CF_ARCHIVE, "crypto_servercpupercent", "10", "allowed crypto CPU load in percent for server operation (0 = no limit, faster)"};
34 cvar_t crypto_servercpumaxtime = {CF_CLIENT | CF_SERVER | CF_ARCHIVE, "crypto_servercpumaxtime", "0.01", "maximum allowed crypto CPU time per frame (0 = no limit)"};
35 cvar_t crypto_servercpudebug = {CF_CLIENT | CF_SERVER | CF_ARCHIVE, "crypto_servercpudebug", "0", "print statistics about time usage by crypto"};
36 static double crypto_servercpu_accumulator = 0;
37 static double crypto_servercpu_lastrealtime = 0;
39 extern cvar_t net_sourceaddresscheck;
41 int crypto_keyfp_recommended_length;
42 static const char *crypto_idstring = NULL;
43 static char crypto_idstring_buf[512];
46 #define PROTOCOL_D0_BLIND_ID FOURCC_D0PK
47 #define PROTOCOL_VLEN (('v' << 0) | ('l' << 8) | ('e' << 16) | ('n' << 24))
49 // BEGIN stuff shared with crypto-keygen-standalone
50 #define FOURCC_D0PK (('d' << 0) | ('0' << 8) | ('p' << 16) | ('k' << 24))
51 #define FOURCC_D0SK (('d' << 0) | ('0' << 8) | ('s' << 16) | ('k' << 24))
52 #define FOURCC_D0PI (('d' << 0) | ('0' << 8) | ('p' << 16) | ('i' << 24))
53 #define FOURCC_D0SI (('d' << 0) | ('0' << 8) | ('s' << 16) | ('i' << 24))
54 #define FOURCC_D0IQ (('d' << 0) | ('0' << 8) | ('i' << 16) | ('q' << 24))
55 #define FOURCC_D0IR (('d' << 0) | ('0' << 8) | ('i' << 16) | ('r' << 24))
56 #define FOURCC_D0ER (('d' << 0) | ('0' << 8) | ('e' << 16) | ('r' << 24))
57 #define FOURCC_D0IC (('d' << 0) | ('0' << 8) | ('i' << 16) | ('c' << 24))
59 static unsigned long Crypto_LittleLong(const char *data)
62 ((unsigned char) data[0]) |
63 (((unsigned char) data[1]) << 8) |
64 (((unsigned char) data[2]) << 16) |
65 (((unsigned char) data[3]) << 24);
68 static void Crypto_UnLittleLong(char *data, unsigned long l)
71 data[1] = (l >> 8) & 0xFF;
72 data[2] = (l >> 16) & 0xFF;
73 data[3] = (l >> 24) & 0xFF;
76 static size_t Crypto_ParsePack(const char *buf, size_t len, unsigned long header, const char **lumps, size_t *lumpsize, size_t nlumps)
85 if(Crypto_LittleLong(buf) != header)
89 for(i = 0; i < nlumps; ++i)
93 lumpsize[i] = Crypto_LittleLong(&buf[pos]);
95 if(pos + lumpsize[i] > len)
103 static size_t Crypto_UnParsePack(char *buf, size_t len, unsigned long header, const char *const *lumps, const size_t *lumpsize, size_t nlumps)
112 Crypto_UnLittleLong(buf, header);
115 for(i = 0; i < nlumps; ++i)
117 if(pos + 4 + lumpsize[i] > len)
119 Crypto_UnLittleLong(&buf[pos], (unsigned long)lumpsize[i]);
121 memcpy(&buf[pos], lumps[i], lumpsize[i]);
126 // END stuff shared with xonotic-keygen
130 #ifdef LINK_TO_CRYPTO
132 #include <d0_blind_id/d0_blind_id.h>
134 #define d0_blind_id_dll 1
135 #define Crypto_OpenLibrary() true
136 #define Crypto_CloseLibrary()
138 #define qd0_blind_id_new d0_blind_id_new
139 #define qd0_blind_id_free d0_blind_id_free
140 //#define qd0_blind_id_clear d0_blind_id_clear
141 #define qd0_blind_id_copy d0_blind_id_copy
142 //#define qd0_blind_id_generate_private_key d0_blind_id_generate_private_key
143 //#define qd0_blind_id_generate_private_key_fastreject d0_blind_id_generate_private_key_fastreject
144 //#define qd0_blind_id_read_private_key d0_blind_id_read_private_key
145 #define qd0_blind_id_read_public_key d0_blind_id_read_public_key
146 //#define qd0_blind_id_write_private_key d0_blind_id_write_private_key
147 //#define qd0_blind_id_write_public_key d0_blind_id_write_public_key
148 #define qd0_blind_id_fingerprint64_public_key d0_blind_id_fingerprint64_public_key
149 //#define qd0_blind_id_generate_private_id_modulus d0_blind_id_generate_private_id_modulus
150 #define qd0_blind_id_read_private_id_modulus d0_blind_id_read_private_id_modulus
151 //#define qd0_blind_id_write_private_id_modulus d0_blind_id_write_private_id_modulus
152 #define qd0_blind_id_generate_private_id_start d0_blind_id_generate_private_id_start
153 #define qd0_blind_id_generate_private_id_request d0_blind_id_generate_private_id_request
154 //#define qd0_blind_id_answer_private_id_request d0_blind_id_answer_private_id_request
155 #define qd0_blind_id_finish_private_id_request d0_blind_id_finish_private_id_request
156 //#define qd0_blind_id_read_private_id_request_camouflage d0_blind_id_read_private_id_request_camouflage
157 //#define qd0_blind_id_write_private_id_request_camouflage d0_blind_id_write_private_id_request_camouflage
158 #define qd0_blind_id_read_private_id d0_blind_id_read_private_id
159 //#define qd0_blind_id_read_public_id d0_blind_id_read_public_id
160 #define qd0_blind_id_write_private_id d0_blind_id_write_private_id
161 //#define qd0_blind_id_write_public_id d0_blind_id_write_public_id
162 #define qd0_blind_id_authenticate_with_private_id_start d0_blind_id_authenticate_with_private_id_start
163 #define qd0_blind_id_authenticate_with_private_id_challenge d0_blind_id_authenticate_with_private_id_challenge
164 #define qd0_blind_id_authenticate_with_private_id_response d0_blind_id_authenticate_with_private_id_response
165 #define qd0_blind_id_authenticate_with_private_id_verify d0_blind_id_authenticate_with_private_id_verify
166 #define qd0_blind_id_fingerprint64_public_id d0_blind_id_fingerprint64_public_id
167 #define qd0_blind_id_sessionkey_public_id d0_blind_id_sessionkey_public_id
168 #define qd0_blind_id_INITIALIZE d0_blind_id_INITIALIZE
169 #define qd0_blind_id_SHUTDOWN d0_blind_id_SHUTDOWN
170 #define qd0_blind_id_util_sha256 d0_blind_id_util_sha256
171 #define qd0_blind_id_sign_with_private_id_sign d0_blind_id_sign_with_private_id_sign
172 #define qd0_blind_id_sign_with_private_id_sign_detached d0_blind_id_sign_with_private_id_sign_detached
173 #define qd0_blind_id_setmallocfuncs d0_blind_id_setmallocfuncs
174 #define qd0_blind_id_setmutexfuncs d0_blind_id_setmutexfuncs
175 #define qd0_blind_id_verify_public_id d0_blind_id_verify_public_id
176 #define qd0_blind_id_verify_private_id d0_blind_id_verify_private_id
180 // d0_blind_id interface
182 #if defined (__GNUC__) || (__clang__) || (__TINYC__)
183 #define D0_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
185 #define D0_WARN_UNUSED_RESULT
189 typedef void *(d0_malloc_t)(size_t len);
190 typedef void (d0_free_t)(void *p);
191 typedef void *(d0_createmutex_t)(void);
192 typedef void (d0_destroymutex_t)(void *);
193 typedef int (d0_lockmutex_t)(void *); // zero on success
194 typedef int (d0_unlockmutex_t)(void *); // zero on success
196 typedef struct d0_blind_id_s d0_blind_id_t;
197 typedef D0_BOOL (*d0_fastreject_function) (const d0_blind_id_t *ctx, void *pass);
198 static D0_EXPORT D0_WARN_UNUSED_RESULT d0_blind_id_t *(*qd0_blind_id_new) (void);
199 static D0_EXPORT void (*qd0_blind_id_free) (d0_blind_id_t *a);
200 //static D0_EXPORT void (*qd0_blind_id_clear) (d0_blind_id_t *ctx);
201 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_copy) (d0_blind_id_t *ctx, const d0_blind_id_t *src);
202 //static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_generate_private_key) (d0_blind_id_t *ctx, int k);
203 //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);
204 //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);
205 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);
206 //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);
207 //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);
208 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);
209 //static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_generate_private_id_modulus) (d0_blind_id_t *ctx);
210 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);
211 //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);
212 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_generate_private_id_start) (d0_blind_id_t *ctx);
213 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);
214 //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);
215 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);
216 //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);
217 //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);
218 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);
219 //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);
220 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);
221 //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);
222 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);
223 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);
224 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);
225 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);
226 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);
227 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
228 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_INITIALIZE) (void);
229 static D0_EXPORT void (*qd0_blind_id_SHUTDOWN) (void);
230 static D0_EXPORT void (*qd0_blind_id_util_sha256) (char *out, const char *in, size_t n);
231 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);
232 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);
233 static D0_EXPORT void (*qd0_blind_id_setmallocfuncs)(d0_malloc_t *m, d0_free_t *f);
234 static D0_EXPORT void (*qd0_blind_id_setmutexfuncs)(d0_createmutex_t *c, d0_destroymutex_t *d, d0_lockmutex_t *l, d0_unlockmutex_t *u);
235 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_verify_public_id)(const d0_blind_id_t *ctx, D0_BOOL *status);
236 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_verify_private_id)(const d0_blind_id_t *ctx);
237 static dllfunction_t d0_blind_id_funcs[] =
239 {"d0_blind_id_new", (void **) &qd0_blind_id_new},
240 {"d0_blind_id_free", (void **) &qd0_blind_id_free},
241 //{"d0_blind_id_clear", (void **) &qd0_blind_id_clear},
242 {"d0_blind_id_copy", (void **) &qd0_blind_id_copy},
243 //{"d0_blind_id_generate_private_key", (void **) &qd0_blind_id_generate_private_key},
244 //{"d0_blind_id_generate_private_key_fastreject", (void **) &qd0_blind_id_generate_private_key_fastreject},
245 //{"d0_blind_id_read_private_key", (void **) &qd0_blind_id_read_private_key},
246 {"d0_blind_id_read_public_key", (void **) &qd0_blind_id_read_public_key},
247 //{"d0_blind_id_write_private_key", (void **) &qd0_blind_id_write_private_key},
248 //{"d0_blind_id_write_public_key", (void **) &qd0_blind_id_write_public_key},
249 {"d0_blind_id_fingerprint64_public_key", (void **) &qd0_blind_id_fingerprint64_public_key},
250 //{"d0_blind_id_generate_private_id_modulus", (void **) &qd0_blind_id_generate_private_id_modulus},
251 {"d0_blind_id_read_private_id_modulus", (void **) &qd0_blind_id_read_private_id_modulus},
252 //{"d0_blind_id_write_private_id_modulus", (void **) &qd0_blind_id_write_private_id_modulus},
253 {"d0_blind_id_generate_private_id_start", (void **) &qd0_blind_id_generate_private_id_start},
254 {"d0_blind_id_generate_private_id_request", (void **) &qd0_blind_id_generate_private_id_request},
255 //{"d0_blind_id_answer_private_id_request", (void **) &qd0_blind_id_answer_private_id_request},
256 {"d0_blind_id_finish_private_id_request", (void **) &qd0_blind_id_finish_private_id_request},
257 //{"d0_blind_id_read_private_id_request_camouflage", (void **) &qd0_blind_id_read_private_id_request_camouflage},
258 //{"d0_blind_id_write_private_id_request_camouflage", (void **) &qd0_blind_id_write_private_id_request_camouflage},
259 {"d0_blind_id_read_private_id", (void **) &qd0_blind_id_read_private_id},
260 //{"d0_blind_id_read_public_id", (void **) &qd0_blind_id_read_public_id},
261 {"d0_blind_id_write_private_id", (void **) &qd0_blind_id_write_private_id},
262 //{"d0_blind_id_write_public_id", (void **) &qd0_blind_id_write_public_id},
263 {"d0_blind_id_authenticate_with_private_id_start", (void **) &qd0_blind_id_authenticate_with_private_id_start},
264 {"d0_blind_id_authenticate_with_private_id_challenge", (void **) &qd0_blind_id_authenticate_with_private_id_challenge},
265 {"d0_blind_id_authenticate_with_private_id_response", (void **) &qd0_blind_id_authenticate_with_private_id_response},
266 {"d0_blind_id_authenticate_with_private_id_verify", (void **) &qd0_blind_id_authenticate_with_private_id_verify},
267 {"d0_blind_id_fingerprint64_public_id", (void **) &qd0_blind_id_fingerprint64_public_id},
268 {"d0_blind_id_sessionkey_public_id", (void **) &qd0_blind_id_sessionkey_public_id},
269 {"d0_blind_id_INITIALIZE", (void **) &qd0_blind_id_INITIALIZE},
270 {"d0_blind_id_SHUTDOWN", (void **) &qd0_blind_id_SHUTDOWN},
271 {"d0_blind_id_util_sha256", (void **) &qd0_blind_id_util_sha256},
272 {"d0_blind_id_sign_with_private_id_sign", (void **) &qd0_blind_id_sign_with_private_id_sign},
273 {"d0_blind_id_sign_with_private_id_sign_detached", (void **) &qd0_blind_id_sign_with_private_id_sign_detached},
274 {"d0_blind_id_setmallocfuncs", (void **) &qd0_blind_id_setmallocfuncs},
275 {"d0_blind_id_setmutexfuncs", (void **) &qd0_blind_id_setmutexfuncs},
276 {"d0_blind_id_verify_public_id", (void **) &qd0_blind_id_verify_public_id},
277 {"d0_blind_id_verify_private_id", (void **) &qd0_blind_id_verify_private_id},
280 // end of d0_blind_id interface
282 static dllhandle_t d0_blind_id_dll = NULL;
283 static qbool Crypto_OpenLibrary (void)
285 const char* dllnames [] =
288 "libd0_blind_id-0.dll",
289 #elif defined(MACOSX)
290 "libd0_blind_id.0.dylib",
292 "libd0_blind_id.so.0",
293 "libd0_blind_id.so", // FreeBSD
303 return Sys_LoadDependency (dllnames, &d0_blind_id_dll, d0_blind_id_funcs);
306 static void Crypto_CloseLibrary (void)
308 Sys_FreeLibrary (&d0_blind_id_dll);
313 #ifdef LINK_TO_CRYPTO_RIJNDAEL
315 #include <d0_blind_id/d0_rijndael.h>
317 #define d0_rijndael_dll 1
318 #define Crypto_Rijndael_OpenLibrary() true
319 #define Crypto_Rijndael_CloseLibrary()
321 #define qd0_rijndael_setup_encrypt d0_rijndael_setup_encrypt
322 #define qd0_rijndael_setup_decrypt d0_rijndael_setup_decrypt
323 #define qd0_rijndael_encrypt d0_rijndael_encrypt
324 #define qd0_rijndael_decrypt d0_rijndael_decrypt
328 // no need to do the #define dance here, as the upper part declares out macros either way
330 D0_EXPORT int (*qd0_rijndael_setup_encrypt) (unsigned long *rk, const unsigned char *key,
332 D0_EXPORT int (*qd0_rijndael_setup_decrypt) (unsigned long *rk, const unsigned char *key,
334 D0_EXPORT void (*qd0_rijndael_encrypt) (const unsigned long *rk, int nrounds,
335 const unsigned char plaintext[16], unsigned char ciphertext[16]);
336 D0_EXPORT void (*qd0_rijndael_decrypt) (const unsigned long *rk, int nrounds,
337 const unsigned char ciphertext[16], unsigned char plaintext[16]);
338 #define D0_RIJNDAEL_KEYLENGTH(keybits) ((keybits)/8)
339 #define D0_RIJNDAEL_RKLENGTH(keybits) ((keybits)/8+28)
340 #define D0_RIJNDAEL_NROUNDS(keybits) ((keybits)/32+6)
341 static dllfunction_t d0_rijndael_funcs[] =
343 {"d0_rijndael_setup_decrypt", (void **) &qd0_rijndael_setup_decrypt},
344 {"d0_rijndael_setup_encrypt", (void **) &qd0_rijndael_setup_encrypt},
345 {"d0_rijndael_decrypt", (void **) &qd0_rijndael_decrypt},
346 {"d0_rijndael_encrypt", (void **) &qd0_rijndael_encrypt},
349 // end of d0_blind_id interface
351 static dllhandle_t d0_rijndael_dll = NULL;
352 static qbool Crypto_Rijndael_OpenLibrary (void)
354 const char* dllnames [] =
357 "libd0_rijndael-0.dll",
358 #elif defined(MACOSX)
359 "libd0_rijndael.0.dylib",
361 "libd0_rijndael.so.0",
362 "libd0_rijndael.so", // FreeBSD
372 return Sys_LoadDependency (dllnames, &d0_rijndael_dll, d0_rijndael_funcs);
375 static void Crypto_Rijndael_CloseLibrary (void)
377 Sys_FreeLibrary (&d0_rijndael_dll);
383 void sha256(unsigned char *out, const unsigned char *in, int n)
385 qd0_blind_id_util_sha256((char *) out, (const char *) in, n);
388 static size_t Crypto_LoadFile(const char *path, char *buf, size_t nmax, qbool inuserdir)
394 f = FS_SysOpen(va(vabuf, sizeof(vabuf), "%s%s", *fs_userdir ? fs_userdir : fs_basedir, path), "rb", false);
396 f = FS_SysOpen(va(vabuf, sizeof(vabuf), "%s%s", fs_basedir, path), "rb", false);
399 n = FS_Read(f, buf, nmax);
406 static qbool PutWithNul(char **data, size_t *len, const char *str)
408 // invariant: data points to insertion point
409 size_t l = strlen(str);
412 memcpy(*data, str, l+1);
418 static const char *GetUntilNul(const char **data, size_t *len)
420 // invariant: data points to next character to take
421 const char *data_save = *data;
434 p = (const char *) memchr(*data, 0, *len);
435 if(!p) // no terminating NUL
446 return (const char *) data_save;
450 static d0_blind_id_t *Crypto_ReadPublicKey(char *buf, size_t len)
452 d0_blind_id_t *pk = NULL;
455 if(Crypto_ParsePack(buf, len, FOURCC_D0PK, p, l, 2))
457 pk = qd0_blind_id_new();
459 if(qd0_blind_id_read_public_key(pk, p[0], l[0]))
460 if(qd0_blind_id_read_private_id_modulus(pk, p[1], l[1]))
464 qd0_blind_id_free(pk);
469 static qbool Crypto_AddPrivateKey(d0_blind_id_t *pk, char *buf, size_t len)
473 if(Crypto_ParsePack(buf, len, FOURCC_D0SI, p, l, 1))
475 if(qd0_blind_id_read_private_id(pk, p[0], l[0]))
481 #define MAX_PUBKEYS 16
482 static d0_blind_id_t *pubkeys[MAX_PUBKEYS];
483 static char pubkeys_fp64[MAX_PUBKEYS][FP64_SIZE+1];
484 static qbool pubkeys_havepriv[MAX_PUBKEYS];
485 static qbool pubkeys_havesig[MAX_PUBKEYS];
486 static char pubkeys_priv_fp64[MAX_PUBKEYS][FP64_SIZE+1];
487 static char challenge_append[1400];
488 static size_t challenge_append_length;
490 static int keygen_i = -1;
491 static char keygen_buf[8192];
493 #define MAX_CRYPTOCONNECTS 16
494 #define CRYPTOCONNECT_NONE 0
495 #define CRYPTOCONNECT_PRECONNECT 1
496 #define CRYPTOCONNECT_CONNECT 2
497 #define CRYPTOCONNECT_RECONNECT 3
498 #define CRYPTOCONNECT_DUPLICATE 4
499 typedef struct server_cryptoconnect_s
502 lhnetaddress_t address;
506 server_cryptoconnect_t;
507 static server_cryptoconnect_t cryptoconnects[MAX_CRYPTOCONNECTS];
509 static int cdata_id = 0;
515 char challenge[2048];
516 char wantserver_idfp[FP64_SIZE+1];
517 qbool wantserver_aes;
518 qbool wantserver_issigned;
523 // crypto specific helpers
524 #define CDATA ((crypto_data_t *) crypto->data)
525 #define MAKE_CDATA if(!crypto->data) crypto->data = Z_Malloc(sizeof(crypto_data_t))
526 #define CLEAR_CDATA if(crypto->data) { if(CDATA->id) qd0_blind_id_free(CDATA->id); Z_Free(crypto->data); } crypto->data = NULL
528 static crypto_t *Crypto_ServerFindInstance(lhnetaddress_t *peeraddress, qbool allow_create)
534 return NULL; // no support
536 for(i = 0; i < MAX_CRYPTOCONNECTS; ++i)
537 if(LHNETADDRESS_Compare(peeraddress, &cryptoconnects[i].address))
539 if(i < MAX_CRYPTOCONNECTS && (allow_create || cryptoconnects[i].crypto.data))
541 crypto = &cryptoconnects[i].crypto;
542 cryptoconnects[i].lasttime = host.realtime;
548 for(i = 1; i < MAX_CRYPTOCONNECTS; ++i)
549 if(cryptoconnects[i].lasttime < cryptoconnects[best].lasttime)
551 crypto = &cryptoconnects[best].crypto;
552 cryptoconnects[best].lasttime = host.realtime;
553 memcpy(&cryptoconnects[best].address, peeraddress, sizeof(cryptoconnects[best].address));
558 qbool Crypto_FinishInstance(crypto_t *out, crypto_t *crypto)
560 // no check needed here (returned pointers are only used in prefilled fields)
561 if(!crypto || !crypto->authenticated)
563 Con_Printf("Passed an invalid crypto connect instance\n");
564 memset(out, 0, sizeof(*out));
568 memcpy(out, crypto, sizeof(*out));
569 memset(crypto, 0, sizeof(*crypto));
573 crypto_t *Crypto_ServerGetInstance(lhnetaddress_t *peeraddress)
575 // no check needed here (returned pointers are only used in prefilled fields)
576 return Crypto_ServerFindInstance(peeraddress, false);
579 typedef struct crypto_storedhostkey_s
581 struct crypto_storedhostkey_s *next;
584 char idfp[FP64_SIZE+1];
588 crypto_storedhostkey_t;
589 static crypto_storedhostkey_t *crypto_storedhostkey_hashtable[CRYPTO_HOSTKEY_HASHSIZE];
591 static void Crypto_InitHostKeys(void)
594 for(i = 0; i < CRYPTO_HOSTKEY_HASHSIZE; ++i)
595 crypto_storedhostkey_hashtable[i] = NULL;
598 static void Crypto_ClearHostKeys(void)
601 crypto_storedhostkey_t *hk, *hkn;
602 for(i = 0; i < CRYPTO_HOSTKEY_HASHSIZE; ++i)
604 for(hk = crypto_storedhostkey_hashtable[i]; hk; hk = hkn)
609 crypto_storedhostkey_hashtable[i] = NULL;
613 static qbool Crypto_ClearHostKey(lhnetaddress_t *peeraddress)
617 crypto_storedhostkey_t **hkp;
620 LHNETADDRESS_ToString(peeraddress, buf, sizeof(buf), 1);
621 hashindex = CRC_Block((const unsigned char *) buf, strlen(buf)) % CRYPTO_HOSTKEY_HASHSIZE;
622 for(hkp = &crypto_storedhostkey_hashtable[hashindex]; *hkp && LHNETADDRESS_Compare(&((*hkp)->addr), peeraddress); hkp = &((*hkp)->next));
626 crypto_storedhostkey_t *hk = *hkp;
635 static void Crypto_StoreHostKey(lhnetaddress_t *peeraddress, const char *keystring, qbool complain)
639 crypto_storedhostkey_t *hk;
641 char idfp[FP64_SIZE+1];
648 // syntax of keystring:
649 // aeslevel id@key id@key ...
653 aeslevel = bound(0, *keystring - '0', 3);
654 while(*keystring && *keystring != ' ')
659 while(*keystring && keyid < 0)
662 const char *idstart, *idend, *keystart, *keyend;
663 qbool thisissigned = true;
664 ++keystring; // skip the space
666 while(*keystring && *keystring != ' ' && *keystring != '@')
672 keystart = keystring;
673 while(*keystring && *keystring != ' ')
677 if (keystart[0] == '~')
679 thisissigned = false;
683 if(idend - idstart == FP64_SIZE && keyend - keystart == FP64_SIZE)
686 for(thiskeyid = MAX_PUBKEYS - 1; thiskeyid >= 0; --thiskeyid)
687 if(pubkeys[thiskeyid])
688 if(!memcmp(pubkeys_fp64[thiskeyid], keystart, FP64_SIZE))
690 memcpy(idfp, idstart, FP64_SIZE);
693 issigned = thisissigned;
696 // If this failed, keyid will be -1.
703 LHNETADDRESS_ToString(peeraddress, buf, sizeof(buf), 1);
704 hashindex = CRC_Block((const unsigned char *) buf, strlen(buf)) % CRYPTO_HOSTKEY_HASHSIZE;
705 for(hk = crypto_storedhostkey_hashtable[hashindex]; hk && LHNETADDRESS_Compare(&hk->addr, peeraddress); hk = hk->next);
711 if(hk->keyid != keyid || memcmp(hk->idfp, idfp, FP64_SIZE+1))
712 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);
713 if(hk->aeslevel > aeslevel)
714 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);
715 if(hk->issigned > issigned)
716 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);
718 hk->aeslevel = max(aeslevel, hk->aeslevel);
719 hk->issigned = issigned;
723 // great, we did NOT have it yet
724 hk = (crypto_storedhostkey_t *) Z_Malloc(sizeof(*hk));
725 memcpy(&hk->addr, peeraddress, sizeof(hk->addr));
727 memcpy(hk->idfp, idfp, FP64_SIZE+1);
728 hk->next = crypto_storedhostkey_hashtable[hashindex];
729 hk->aeslevel = aeslevel;
730 hk->issigned = issigned;
731 crypto_storedhostkey_hashtable[hashindex] = hk;
734 qbool Crypto_RetrieveHostKey(lhnetaddress_t *peeraddress, int *keyid, char *keyfp, size_t keyfplen, char *idfp, size_t idfplen, int *aeslevel, qbool *issigned)
738 crypto_storedhostkey_t *hk;
743 LHNETADDRESS_ToString(peeraddress, buf, sizeof(buf), 1);
744 hashindex = CRC_Block((const unsigned char *) buf, strlen(buf)) % CRYPTO_HOSTKEY_HASHSIZE;
745 for(hk = crypto_storedhostkey_hashtable[hashindex]; hk && LHNETADDRESS_Compare(&hk->addr, peeraddress); hk = hk->next);
753 dp_strlcpy(keyfp, pubkeys_fp64[hk->keyid], keyfplen);
755 dp_strlcpy(idfp, hk->idfp, idfplen);
757 *aeslevel = hk->aeslevel;
759 *issigned = hk->issigned;
763 int Crypto_RetrieveLocalKey(int keyid, char *keyfp, size_t keyfplen, char *idfp, size_t idfplen, qbool *issigned) // return value: -1 if more to come, +1 if valid, 0 if end of list
765 if(keyid < 0 || keyid >= MAX_PUBKEYS)
774 dp_strlcpy(keyfp, pubkeys_fp64[keyid], keyfplen);
776 if(pubkeys_havepriv[keyid])
777 dp_strlcpy(idfp, pubkeys_priv_fp64[keyid], idfplen);
779 *issigned = pubkeys_havesig[keyid];
784 // init/shutdown code
785 static void Crypto_BuildChallengeAppend(void)
787 char *p, *lengthptr, *startptr;
790 p = challenge_append;
791 n = sizeof(challenge_append);
792 Crypto_UnLittleLong(p, PROTOCOL_VLEN);
796 Crypto_UnLittleLong(p, 0);
799 Crypto_UnLittleLong(p, PROTOCOL_D0_BLIND_ID);
803 for(i = 0; i < MAX_PUBKEYS; ++i)
804 if(pubkeys_havepriv[i])
805 PutWithNul(&p, &n, pubkeys_fp64[i]);
806 PutWithNul(&p, &n, "");
807 for(i = 0; i < MAX_PUBKEYS; ++i)
808 if(!pubkeys_havepriv[i] && pubkeys[i])
809 PutWithNul(&p, &n, pubkeys_fp64[i]);
810 Crypto_UnLittleLong(lengthptr, p - startptr);
811 challenge_append_length = p - challenge_append;
814 static qbool Crypto_SavePubKeyTextFile(int i)
819 if(!pubkeys_havepriv[i])
821 f = FS_SysOpen(va(vabuf, sizeof(vabuf), "%skey_%d-public-fp%s.txt", *fs_userdir ? fs_userdir : fs_basedir, i, sessionid.string), "w", false);
825 // we ignore errors for this file, as it's not necessary to have
826 FS_Printf(f, "ID-Fingerprint: %s\n", pubkeys_priv_fp64[i]);
827 FS_Printf(f, "ID-Is-Signed: %s\n", pubkeys_havesig[i] ? "yes" : "no");
828 FS_Printf(f, "ID-Is-For-Key: %s\n", pubkeys_fp64[i]);
830 FS_Printf(f, "This is a PUBLIC ID file for DarkPlaces.\n");
831 FS_Printf(f, "You are free to share this file or its contents.\n");
833 FS_Printf(f, "This file will be automatically generated again if deleted.\n");
835 FS_Printf(f, "However, NEVER share the accompanying SECRET ID file called\n");
836 FS_Printf(f, "key_%d.d0si%s, as doing so would compromise security!\n", i, sessionid.string);
842 static void Crypto_BuildIdString(void)
847 crypto_idstring = NULL;
848 dpsnprintf(crypto_idstring_buf, sizeof(crypto_idstring_buf), "%d", d0_rijndael_dll ? crypto_aeslevel.integer : 0);
849 for (i = 0; i < MAX_PUBKEYS; ++i)
851 dp_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));
852 crypto_idstring = crypto_idstring_buf;
855 void Crypto_LoadKeys(void)
862 if(!d0_blind_id_dll) // don't if we can't
865 if(crypto_idstring) // already loaded? then not
868 Host_LockSession(); // we use the session ID here
871 // note: we are just a CLIENT
873 // PUBLIC KEYS to accept (including modulus)
874 // PRIVATE KEY of user
876 for(i = 0; i < MAX_PUBKEYS; ++i)
878 memset(pubkeys_fp64[i], 0, sizeof(pubkeys_fp64[i]));
879 memset(pubkeys_priv_fp64[i], 0, sizeof(pubkeys_fp64[i]));
880 pubkeys_havepriv[i] = false;
881 pubkeys_havesig[i] = false;
882 len = Crypto_LoadFile(va(vabuf, sizeof(vabuf), "key_%d.d0pk", i), buf, sizeof(buf), false);
883 if((pubkeys[i] = Crypto_ReadPublicKey(buf, len)))
886 if(qd0_blind_id_fingerprint64_public_key(pubkeys[i], pubkeys_fp64[i], &len2)) // keeps final NUL
888 Con_Printf("Loaded public key key_%d.d0pk (fingerprint: %s)\n", i, pubkeys_fp64[i]);
889 len = Crypto_LoadFile(va(vabuf, sizeof(vabuf), "key_%d.d0si%s", i, sessionid.string), buf, sizeof(buf), true);
892 if(Crypto_AddPrivateKey(pubkeys[i], buf, len))
895 if(qd0_blind_id_fingerprint64_public_id(pubkeys[i], pubkeys_priv_fp64[i], &len2)) // keeps final NUL
899 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]);
901 // verify the key we just loaded (just in case)
902 if(qd0_blind_id_verify_private_id(pubkeys[i]) && qd0_blind_id_verify_public_id(pubkeys[i], &status))
904 pubkeys_havepriv[i] = true;
905 pubkeys_havesig[i] = status;
907 // verify the key we just got (just in case)
909 Con_Printf("NOTE: this ID has not yet been signed!\n");
911 Crypto_SavePubKeyTextFile(i);
915 Con_Printf("d0_blind_id_verify_private_id failed, this is not a valid key!\n");
916 qd0_blind_id_free(pubkeys[i]);
922 Con_Printf("d0_blind_id_fingerprint64_public_id failed\n");
923 qd0_blind_id_free(pubkeys[i]);
931 // can't really happen
932 qd0_blind_id_free(pubkeys[i]);
939 Crypto_BuildIdString();
940 Crypto_BuildChallengeAppend();
942 // find a good prefix length for all the keys we know (yes, algorithm is not perfect yet, may yield too long prefix length)
943 crypto_keyfp_recommended_length = 0;
944 memset(buf+256, 0, MAX_PUBKEYS + MAX_PUBKEYS);
945 while(crypto_keyfp_recommended_length < FP64_SIZE)
948 for(i = 0; i < MAX_PUBKEYS; ++i)
952 ++buf[(unsigned char) pubkeys_fp64[i][crypto_keyfp_recommended_length]];
953 if(pubkeys_havepriv[i])
954 if(!buf[256 + MAX_PUBKEYS + i])
955 ++buf[(unsigned char) pubkeys_priv_fp64[i][crypto_keyfp_recommended_length]];
957 for(i = 0; i < MAX_PUBKEYS; ++i)
961 if(buf[(unsigned char) pubkeys_fp64[i][crypto_keyfp_recommended_length]] < 2)
963 if(pubkeys_havepriv[i])
964 if(!buf[256 + MAX_PUBKEYS + i])
965 if(buf[(unsigned char) pubkeys_priv_fp64[i][crypto_keyfp_recommended_length]] < 2)
966 buf[256 + MAX_PUBKEYS + i] = 1;
968 ++crypto_keyfp_recommended_length;
969 for(i = 0; i < MAX_PUBKEYS; ++i)
974 if(pubkeys_havepriv[i])
975 if(!buf[256 + MAX_PUBKEYS + i])
981 if(crypto_keyfp_recommended_length < 7)
982 crypto_keyfp_recommended_length = 7;
985 static void Crypto_UnloadKeys(void)
990 for(i = 0; i < MAX_PUBKEYS; ++i)
993 qd0_blind_id_free(pubkeys[i]);
995 pubkeys_havepriv[i] = false;
996 pubkeys_havesig[i] = false;
997 memset(pubkeys_fp64[i], 0, sizeof(pubkeys_fp64[i]));
998 memset(pubkeys_priv_fp64[i], 0, sizeof(pubkeys_fp64[i]));
999 challenge_append_length = 0;
1001 crypto_idstring = NULL;
1004 static mempool_t *cryptomempool;
1010 static void *Crypto_d0_malloc(size_t len)
1012 return Mem_Alloc(cryptomempool, len);
1015 static void Crypto_d0_free(void *p)
1020 static void *Crypto_d0_createmutex(void)
1022 return Thread_CreateMutex();
1025 static void Crypto_d0_destroymutex(void *m)
1027 Thread_DestroyMutex(m);
1030 static int Crypto_d0_lockmutex(void *m)
1032 return Thread_LockMutex(m);
1035 static int Crypto_d0_unlockmutex(void *m)
1037 return Thread_UnlockMutex(m);
1043 void Crypto_Shutdown(void)
1048 Crypto_Rijndael_CloseLibrary();
1053 for(i = 0; i < MAX_CRYPTOCONNECTS; ++i)
1055 crypto = &cryptoconnects[i].crypto;
1058 memset(cryptoconnects, 0, sizeof(cryptoconnects));
1059 crypto = &cls.crypto;
1062 Crypto_UnloadKeys();
1064 qd0_blind_id_SHUTDOWN();
1066 Crypto_CloseLibrary();
1069 Mem_FreePool(&cryptomempool);
1072 void Crypto_Init(void)
1074 cryptomempool = Mem_AllocPool("crypto", 0, NULL);
1076 if(!Crypto_OpenLibrary())
1079 qd0_blind_id_setmallocfuncs(Crypto_d0_malloc, Crypto_d0_free);
1080 if (Thread_HasThreads())
1081 qd0_blind_id_setmutexfuncs(Crypto_d0_createmutex, Crypto_d0_destroymutex, Crypto_d0_lockmutex, Crypto_d0_unlockmutex);
1083 if(!qd0_blind_id_INITIALIZE())
1085 Crypto_Rijndael_CloseLibrary();
1086 Crypto_CloseLibrary();
1087 Con_Printf("libd0_blind_id initialization FAILED, cryptography support has been disabled\n");
1091 (void) Crypto_Rijndael_OpenLibrary(); // if this fails, it's uncritical
1093 Crypto_InitHostKeys();
1097 qbool Crypto_Available(void)
1099 if(!d0_blind_id_dll)
1105 static void Crypto_KeyGen_Finished(int code, size_t length_received, unsigned char *buffer, void *cbdata)
1109 static char buf[8192];
1110 static char buf2[8192];
1116 SV_LockThreadMutex();
1118 if(!d0_blind_id_dll)
1120 Con_Print("libd0_blind_id DLL not found, this command is inactive.\n");
1122 SV_UnlockThreadMutex();
1128 Con_Printf("Unexpected response from keygen server:\n");
1129 Com_HexDumpToConsole(buffer, (int)length_received);
1130 SV_UnlockThreadMutex();
1133 if(keygen_i >= MAX_PUBKEYS || !pubkeys[keygen_i])
1135 Con_Printf("overflow of keygen_i\n");
1137 SV_UnlockThreadMutex();
1140 if(!Crypto_ParsePack((const char *) buffer, length_received, FOURCC_D0IR, p, l, 1))
1142 if(length_received >= 5 && Crypto_LittleLong((const char *) buffer) == FOURCC_D0ER)
1144 Con_Printf(CON_ERROR "Error response from keygen server: %.*s\n", (int)(length_received - 5), buffer + 5);
1148 Con_Printf(CON_ERROR "Invalid response from keygen server:\n");
1149 Com_HexDumpToConsole(buffer, (int)length_received);
1152 SV_UnlockThreadMutex();
1155 if(!qd0_blind_id_finish_private_id_request(pubkeys[keygen_i], p[0], l[0]))
1157 Con_Printf("d0_blind_id_finish_private_id_request failed\n");
1159 SV_UnlockThreadMutex();
1163 // verify the key we just got (just in case)
1164 if(!qd0_blind_id_verify_public_id(pubkeys[keygen_i], &status) || !status)
1166 Con_Printf("d0_blind_id_verify_public_id failed\n");
1168 SV_UnlockThreadMutex();
1172 // we have a valid key now!
1173 // make the rest of crypto.c know that
1174 Con_Printf("Received signature for private ID key_%d.d0pk (public key fingerprint: %s)\n", keygen_i, pubkeys_priv_fp64[keygen_i]);
1175 pubkeys_havesig[keygen_i] = true;
1177 // write the key to disk
1180 if(!qd0_blind_id_write_private_id(pubkeys[keygen_i], buf, &l[0]))
1182 Con_Printf("d0_blind_id_write_private_id failed\n");
1184 SV_UnlockThreadMutex();
1187 if(!(buf2size = Crypto_UnParsePack(buf2, sizeof(buf2), FOURCC_D0SI, p, l, 1)))
1189 Con_Printf("Crypto_UnParsePack failed\n");
1191 SV_UnlockThreadMutex();
1195 FS_CreatePath(va(vabuf, sizeof(vabuf), "%skey_%d.d0si%s", *fs_userdir ? fs_userdir : fs_basedir, keygen_i, sessionid.string));
1196 f = FS_SysOpen(va(vabuf, sizeof(vabuf), "%skey_%d.d0si%s", *fs_userdir ? fs_userdir : fs_basedir, keygen_i, sessionid.string), "wb", false);
1199 Con_Printf("Cannot open key_%d.d0si%s\n", keygen_i, sessionid.string);
1201 SV_UnlockThreadMutex();
1204 FS_Write(f, buf2, buf2size);
1207 Crypto_SavePubKeyTextFile(keygen_i);
1209 Con_Printf("Saved to key_%d.d0si%s\n", keygen_i, sessionid.string);
1211 Crypto_BuildIdString();
1214 SV_UnlockThreadMutex();
1217 static void Crypto_KeyGen_f(cmd_state_t *cmd)
1222 static char buf[8192];
1223 static char buf2[8192];
1225 size_t buf2l, buf2pos;
1230 if(!d0_blind_id_dll)
1232 Con_Print("libd0_blind_id DLL not found, this command is inactive.\n");
1235 if(Cmd_Argc(cmd) != 3)
1237 Con_Printf("usage:\n%s id url\n", Cmd_Argv(cmd, 0));
1240 SV_LockThreadMutex();
1242 i = atoi(Cmd_Argv(cmd, 1));
1245 Con_Printf("there is no public key %d\n", i);
1246 SV_UnlockThreadMutex();
1251 Con_Printf("there is already a keygen run on the way\n");
1252 SV_UnlockThreadMutex();
1257 // how to START the keygenning...
1258 if(pubkeys_havepriv[keygen_i])
1260 if(pubkeys_havesig[keygen_i])
1262 Con_Printf("there is already a signed private key for %d\n", i);
1264 SV_UnlockThreadMutex();
1267 // if we get here, we only need a signature, no new keygen run needed
1268 Con_Printf("Only need a signature for an existing key...\n");
1272 // we also need a new ID itself
1273 if(!qd0_blind_id_generate_private_id_start(pubkeys[keygen_i]))
1275 Con_Printf("d0_blind_id_start failed\n");
1277 SV_UnlockThreadMutex();
1280 // verify the key we just got (just in case)
1281 if(!qd0_blind_id_verify_private_id(pubkeys[keygen_i]))
1283 Con_Printf("d0_blind_id_verify_private_id failed\n");
1285 SV_UnlockThreadMutex();
1288 // we have a valid key now!
1289 // make the rest of crypto.c know that
1291 if(qd0_blind_id_fingerprint64_public_id(pubkeys[keygen_i], pubkeys_priv_fp64[keygen_i], &len2)) // keeps final NUL
1293 Con_Printf("Generated private ID key_%d.d0pk (public key fingerprint: %s)\n", keygen_i, pubkeys_priv_fp64[keygen_i]);
1294 pubkeys_havepriv[keygen_i] = true;
1295 dp_strlcat(crypto_idstring_buf, va(vabuf, sizeof(vabuf), " %s@%s", pubkeys_priv_fp64[keygen_i], pubkeys_fp64[keygen_i]), sizeof(crypto_idstring_buf));
1296 crypto_idstring = crypto_idstring_buf;
1297 Crypto_BuildChallengeAppend();
1299 // write the key to disk
1302 if(!qd0_blind_id_write_private_id(pubkeys[keygen_i], buf, &l[0]))
1304 Con_Printf("d0_blind_id_write_private_id failed\n");
1306 SV_UnlockThreadMutex();
1309 if(!(buf2size = Crypto_UnParsePack(buf2, sizeof(buf2), FOURCC_D0SI, p, l, 1)))
1311 Con_Printf("Crypto_UnParsePack failed\n");
1313 SV_UnlockThreadMutex();
1317 FS_CreatePath(va(vabuf, sizeof(vabuf), "%skey_%d.d0si%s", *fs_userdir ? fs_userdir : fs_basedir, keygen_i, sessionid.string));
1318 f = FS_SysOpen(va(vabuf, sizeof(vabuf), "%skey_%d.d0si%s", *fs_userdir ? fs_userdir : fs_basedir, keygen_i, sessionid.string), "wb", false);
1321 Con_Printf("Cannot open key_%d.d0si%s\n", keygen_i, sessionid.string);
1323 SV_UnlockThreadMutex();
1326 FS_Write(f, buf2, buf2size);
1329 Crypto_SavePubKeyTextFile(keygen_i);
1331 Con_Printf("Saved unsigned key to key_%d.d0si%s\n", keygen_i, sessionid.string);
1335 if(!qd0_blind_id_generate_private_id_request(pubkeys[keygen_i], buf, &l[0]))
1337 Con_Printf("d0_blind_id_generate_private_id_request failed\n");
1339 SV_UnlockThreadMutex();
1342 buf2pos = strlen(Cmd_Argv(cmd, 2));
1343 memcpy(buf2, Cmd_Argv(cmd, 2), buf2pos);
1344 if(!(buf2l = Crypto_UnParsePack(buf2 + buf2pos, sizeof(buf2) - buf2pos - 1, FOURCC_D0IQ, p, l, 1)))
1346 Con_Printf("Crypto_UnParsePack failed\n");
1348 SV_UnlockThreadMutex();
1351 if(!(buf2l = base64_encode((unsigned char *) (buf2 + buf2pos), buf2l, sizeof(buf2) - buf2pos - 1)))
1353 Con_Printf("base64_encode failed\n");
1355 SV_UnlockThreadMutex();
1360 if(!Curl_Begin_ToMemory(buf2, 0, (unsigned char *) keygen_buf, sizeof(keygen_buf), Crypto_KeyGen_Finished, NULL))
1362 Con_Printf("curl failed\n");
1364 SV_UnlockThreadMutex();
1367 Con_Printf("Signature generation in progress...\n");
1368 SV_UnlockThreadMutex();
1373 static void Crypto_Reload_f(cmd_state_t *cmd)
1375 Crypto_ClearHostKeys();
1376 Crypto_UnloadKeys();
1380 static void Crypto_Keys_f(cmd_state_t *cmd)
1383 if(!d0_blind_id_dll)
1385 Con_Print("libd0_blind_id DLL not found, this command is inactive.\n");
1388 for(i = 0; i < MAX_PUBKEYS; ++i)
1392 Con_Printf("%2d: public key key_%d.d0pk (fingerprint: %s)\n", i, i, pubkeys_fp64[i]);
1393 if(pubkeys_havepriv[i])
1395 Con_Printf(" private ID key_%d.d0si%s (public key fingerprint: %s)\n", i, sessionid.string, pubkeys_priv_fp64[i]);
1396 if(!pubkeys_havesig[i])
1397 Con_Printf(" NOTE: this ID has not yet been signed!\n");
1403 static void Crypto_HostKeys_f(cmd_state_t *cmd)
1406 crypto_storedhostkey_t *hk;
1409 if(!d0_blind_id_dll)
1411 Con_Print("libd0_blind_id DLL not found, this command is inactive.\n");
1414 for(i = 0; i < CRYPTO_HOSTKEY_HASHSIZE; ++i)
1416 for(hk = crypto_storedhostkey_hashtable[i]; hk; hk = hk->next)
1418 LHNETADDRESS_ToString(&hk->addr, buf, sizeof(buf), 1);
1419 Con_Printf("%d %s@%.*s %s\n",
1422 crypto_keyfp_recommended_length, pubkeys_fp64[hk->keyid],
1428 static void Crypto_HostKey_Clear_f(cmd_state_t *cmd)
1430 lhnetaddress_t addr;
1433 if(!d0_blind_id_dll)
1435 Con_Print("libd0_blind_id DLL not found, this command is inactive.\n");
1439 for(i = 1; i < Cmd_Argc(cmd); ++i)
1441 LHNETADDRESS_FromString(&addr, Cmd_Argv(cmd, i), 26000);
1442 if(Crypto_ClearHostKey(&addr))
1444 Con_Printf("cleared host key for %s\n", Cmd_Argv(cmd, i));
1449 void Crypto_Init_Commands(void)
1453 Cmd_AddCommand(CF_SHARED, "crypto_reload", Crypto_Reload_f, "reloads cryptographic keys");
1454 Cmd_AddCommand(CF_SHARED, "crypto_keygen", Crypto_KeyGen_f, "generates and saves a cryptographic key");
1455 Cmd_AddCommand(CF_SHARED, "crypto_keys", Crypto_Keys_f, "lists the loaded keys");
1456 Cmd_AddCommand(CF_SHARED, "crypto_hostkeys", Crypto_HostKeys_f, "lists the cached host keys");
1457 Cmd_AddCommand(CF_SHARED, "crypto_hostkey_clear", Crypto_HostKey_Clear_f, "clears a cached host key");
1459 Cvar_RegisterVariable(&crypto_developer);
1461 Cvar_RegisterVariable(&crypto_aeslevel);
1463 crypto_aeslevel.integer = 0; // make sure
1464 Cvar_RegisterVariable(&crypto_servercpupercent);
1465 Cvar_RegisterVariable(&crypto_servercpumaxtime);
1466 Cvar_RegisterVariable(&crypto_servercpudebug);
1472 static void aescpy(unsigned char *key, const unsigned char *iv, unsigned char *dst, const unsigned char *src, size_t len)
1474 const unsigned char *xorpos = iv;
1475 unsigned char xorbuf[16];
1476 unsigned long rk[D0_RIJNDAEL_RKLENGTH(DHKEY_SIZE * 8)];
1478 qd0_rijndael_setup_encrypt(rk, key, DHKEY_SIZE * 8);
1481 for(i = 0; i < 16; ++i)
1482 xorbuf[i] = src[i] ^ xorpos[i];
1483 qd0_rijndael_encrypt(rk, D0_RIJNDAEL_NROUNDS(DHKEY_SIZE * 8), xorbuf, dst);
1491 for(i = 0; i < len; ++i)
1492 xorbuf[i] = src[i] ^ xorpos[i];
1494 xorbuf[i] = xorpos[i];
1495 qd0_rijndael_encrypt(rk, D0_RIJNDAEL_NROUNDS(DHKEY_SIZE * 8), xorbuf, dst);
1498 static void seacpy(unsigned char *key, const unsigned char *iv, unsigned char *dst, const unsigned char *src, size_t len)
1500 const unsigned char *xorpos = iv;
1501 unsigned char xorbuf[16];
1502 unsigned long rk[D0_RIJNDAEL_RKLENGTH(DHKEY_SIZE * 8)];
1504 qd0_rijndael_setup_decrypt(rk, key, DHKEY_SIZE * 8);
1507 qd0_rijndael_decrypt(rk, D0_RIJNDAEL_NROUNDS(DHKEY_SIZE * 8), src, xorbuf);
1508 for(i = 0; i < 16; ++i)
1509 dst[i] = xorbuf[i] ^ xorpos[i];
1517 qd0_rijndael_decrypt(rk, D0_RIJNDAEL_NROUNDS(DHKEY_SIZE * 8), src, xorbuf);
1518 for(i = 0; i < len; ++i)
1519 dst[i] = xorbuf[i] ^ xorpos[i];
1523 // NOTE: we MUST avoid the following begins of the packet:
1524 // 1. 0xFF, 0xFF, 0xFF, 0xFF
1525 // 2. 0x80, 0x00, length/256, length%256
1526 // this luckily does NOT affect AES mode, where the first byte always is in the range from 0x00 to 0x0F
1527 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)
1529 unsigned char h[32];
1531 if(crypto->authenticated)
1535 // AES packet = 1 byte length overhead, 15 bytes from HMAC-SHA-256, data, 0..15 bytes padding
1536 // 15 bytes HMAC-SHA-256 (112bit) suffice as the attacker can't do more than forge a random-looking packet
1537 // HMAC is needed to not leak information about packet content
1538 if(developer_networking.integer)
1540 Con_Print("To be encrypted:\n");
1541 Com_HexDumpToConsole((const unsigned char *) data_src, (int)len_src);
1543 if(len_src + 32 > len || !HMAC_SHA256_32BYTES(h, (const unsigned char *) data_src, (int)len_src, crypto->dhkey, DHKEY_SIZE))
1545 Con_Printf("Crypto_EncryptPacket failed (not enough space: %d bytes in, %d bytes out)\n", (int) len_src, (int) len);
1548 *len_dst = ((len_src + 15) / 16) * 16 + 16; // add 16 for HMAC, then round to 16-size for AES
1549 ((unsigned char *) data_dst)[0] = (unsigned char)(*len_dst - len_src);
1550 memcpy(((unsigned char *) data_dst)+1, h, 15);
1551 aescpy(crypto->dhkey, (const unsigned char *) data_dst, ((unsigned char *) data_dst) + 16, (const unsigned char *) data_src, len_src);
1556 // HMAC packet = 16 bytes HMAC-SHA-256 (truncated to 128 bits), data
1557 if(len_src + 16 > len || !HMAC_SHA256_32BYTES(h, (const unsigned char *) data_src, (int)len_src, crypto->dhkey, DHKEY_SIZE))
1559 Con_Printf("Crypto_EncryptPacket failed (not enough space: %d bytes in, %d bytes out)\n", (int) len_src, (int) len);
1562 *len_dst = len_src + 16;
1563 memcpy(data_dst, h, 16);
1564 memcpy(((unsigned char *) data_dst) + 16, (unsigned char *) data_src, len_src);
1566 // handle the "avoid" conditions:
1567 i = BuffBigLong((unsigned char *) data_dst);
1569 (i == (int)0xFFFFFFFF) // avoid QW control packet
1571 (i == (int)0x80000000 + (int)*len_dst) // avoid NQ control packet
1573 *(unsigned char *)data_dst ^= 0x80; // this will ALWAYS fix it
1584 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)
1586 unsigned char h[32];
1589 // silently handle non-crypto packets
1590 i = BuffBigLong((unsigned char *) data_src);
1592 (i == (int)0xFFFFFFFF) // avoid QW control packet
1594 (i == (int)0x80000000 + (int)len_src) // avoid NQ control packet
1598 if(crypto->authenticated)
1602 if(len_src < 16 || ((len_src - 16) % 16))
1604 Con_Printf("Crypto_DecryptPacket failed (not enough space: %d bytes in, %d bytes out)\n", (int) len_src, (int) len);
1607 *len_dst = len_src - ((unsigned char *) data_src)[0];
1608 if(len < *len_dst || *len_dst > len_src - 16)
1610 Con_Printf("Crypto_DecryptPacket failed (not enough space: %d bytes in, %d->%d bytes out)\n", (int) len_src, (int) *len_dst, (int) len);
1613 seacpy(crypto->dhkey, (unsigned char *) data_src, (unsigned char *) data_dst, ((const unsigned char *) data_src) + 16, *len_dst);
1615 if(!HMAC_SHA256_32BYTES(h, (const unsigned char *) data_dst, (int)*len_dst, crypto->dhkey, DHKEY_SIZE))
1617 Con_Printf("HMAC fail\n");
1620 if(memcmp(((const unsigned char *) data_src)+1, h, 15)) // ignore first byte, used for length
1622 Con_Printf("HMAC mismatch\n");
1625 if(developer_networking.integer)
1627 Con_Print("Decrypted:\n");
1628 Com_HexDumpToConsole((const unsigned char *) data_dst, (int)*len_dst);
1630 return data_dst; // no need to copy
1636 Con_Printf("Crypto_DecryptPacket failed (not enough space: %d bytes in, %d bytes out)\n", (int) len_src, (int) len);
1639 *len_dst = len_src - 16;
1642 Con_Printf("Crypto_DecryptPacket failed (not enough space: %d bytes in, %d->%d bytes out)\n", (int) len_src, (int) *len_dst, (int) len);
1645 //memcpy(data_dst, data_src + 16, *len_dst);
1646 if(!HMAC_SHA256_32BYTES(h, ((const unsigned char *) data_src) + 16, (int)*len_dst, crypto->dhkey, DHKEY_SIZE))
1648 Con_Printf("HMAC fail\n");
1649 Com_HexDumpToConsole((const unsigned char *) data_src, (int)len_src);
1653 if(memcmp((const unsigned char *) data_src, h, 16)) // ignore first byte, used for length
1655 // undo the "avoid conditions"
1657 (i == (int)0x7FFFFFFF) // avoided QW control packet
1659 (i == (int)0x00000000 + (int)len_src) // avoided NQ control packet
1662 // do the avoidance on the hash too
1664 if(memcmp((const unsigned char *) data_src, h, 16)) // ignore first byte, used for length
1666 Con_Printf("HMAC mismatch\n");
1667 Com_HexDumpToConsole((const unsigned char *) data_src, (int)len_src);
1673 Con_Printf("HMAC mismatch\n");
1674 Com_HexDumpToConsole((const unsigned char *) data_src, (int)len_src);
1678 return ((const unsigned char *) data_src) + 16; // no need to copy, so data_dst is not used
1689 const char *Crypto_GetInfoResponseDataString(void)
1691 crypto_idstring_buf[0] = '0' + crypto_aeslevel.integer;
1692 return crypto_idstring;
1696 qbool Crypto_ServerAppendToChallenge(const char *data_in, size_t len_in, char *data_out, size_t *len_out, size_t maxlen_out)
1698 // cheap op, all is precomputed
1699 if(!d0_blind_id_dll)
1700 return false; // no support
1702 if(maxlen_out <= *len_out + challenge_append_length)
1704 memcpy(data_out + *len_out, challenge_append, challenge_append_length);
1705 *len_out += challenge_append_length;
1709 static int Crypto_ServerError(char *data_out, size_t *len_out, const char *msg, const char *msg_client)
1713 Con_DPrintf("rejecting client: %s\n", msg);
1715 dpsnprintf(data_out, *len_out, "reject %s", msg_client);
1716 *len_out = strlen(data_out);
1717 return CRYPTO_DISCARD;
1720 static int Crypto_SoftServerError(char *data_out, size_t *len_out, const char *msg)
1723 Con_DPrintf("%s\n", msg);
1724 return CRYPTO_DISCARD;
1727 static int Crypto_ServerParsePacket_Internal(const char *data_in, size_t len_in, char *data_out, size_t *len_out, lhnetaddress_t *peeraddress)
1729 // if "connect": reject if in the middle of crypto handshake
1730 crypto_t *crypto = NULL;
1731 char *data_out_p = data_out;
1732 const char *string = data_in;
1736 char infostringvalue[MAX_INPUTLINE];
1739 if(!d0_blind_id_dll)
1740 return CRYPTO_NOMATCH; // no support
1742 if (len_in > 8 && !memcmp(string, "connect\\", 8) && d0_rijndael_dll && crypto_aeslevel.integer >= 3)
1745 // sorry, we have to verify the challenge here to not reflect network spam
1747 if (!InfoString_GetValue(string + 4, "challenge", infostringvalue, sizeof(infostringvalue)))
1748 return CRYPTO_NOMATCH; // will be later accepted if encryption was set up
1749 // validate the challenge
1750 for (i = 0;i < MAX_CHALLENGES;i++)
1751 if(challenges[i].time > 0)
1752 if (!LHNETADDRESS_Compare(peeraddress, &challenges[i].address) && !strcmp(challenges[i].string, infostringvalue))
1754 // if the challenge is not recognized, drop the packet
1755 if (i == MAX_CHALLENGES) // challenge mismatch is silent
1756 return Crypto_SoftServerError(data_out, len_out, "missing challenge in connect");
1758 crypto = Crypto_ServerFindInstance(peeraddress, false);
1759 if(!crypto || !crypto->authenticated)
1760 return Crypto_ServerError(data_out, len_out, "This server requires authentication and encryption to be supported by your client", NULL);
1762 else if(len_in > 5 && !memcmp(string, "d0pk\\", 5) && ((LHNETADDRESS_GetAddressType(peeraddress) == LHNETADDRESSTYPE_LOOP) || sv_public.integer > -3))
1764 const char *cnt, *p;
1766 int clientid = -1, serverid = -1;
1767 id = (InfoString_GetValue(string + 4, "id", infostringvalue, sizeof(infostringvalue)) ? atoi(infostringvalue) : -1);
1768 cnt = (InfoString_GetValue(string + 4, "cnt", infostringvalue, sizeof(infostringvalue)) ? infostringvalue : NULL);
1770 return Crypto_SoftServerError(data_out, len_out, "missing cnt in d0pk");
1771 GetUntilNul(&data_in, &len_in);
1773 return Crypto_SoftServerError(data_out, len_out, "missing appended data in d0pk");
1774 if(!strcmp(cnt, "0"))
1777 if (!InfoString_GetValue(string + 4, "challenge", infostringvalue, sizeof(infostringvalue)))
1778 return Crypto_SoftServerError(data_out, len_out, "missing challenge in d0pk\\0");
1779 // validate the challenge
1780 for (i = 0;i < MAX_CHALLENGES;i++)
1781 if(challenges[i].time > 0)
1782 if (!LHNETADDRESS_Compare(peeraddress, &challenges[i].address) && !strcmp(challenges[i].string, infostringvalue))
1784 // if the challenge is not recognized, drop the packet
1785 if (i == MAX_CHALLENGES)
1786 return Crypto_SoftServerError(data_out, len_out, "invalid challenge in d0pk\\0");
1788 if (!InfoString_GetValue(string + 4, "aeslevel", infostringvalue, sizeof(infostringvalue)))
1789 aeslevel = 0; // not supported
1791 aeslevel = bound(0, atoi(infostringvalue), 3);
1792 switch(bound(0, d0_rijndael_dll ? crypto_aeslevel.integer : 0, 3))
1794 default: // dummy, never happens, but to make gcc happy...
1797 return Crypto_ServerError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)", NULL);
1801 aes = (aeslevel >= 2);
1804 aes = (aeslevel >= 1);
1808 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);
1813 p = GetUntilNul(&data_in, &len_in);
1816 // Find the highest numbered matching key for p.
1817 for(i = 0; i < MAX_PUBKEYS; ++i)
1820 if(!strcmp(p, pubkeys_fp64[i]))
1821 if(pubkeys_havepriv[i])
1825 return Crypto_ServerError(data_out, len_out, "Invalid server key", NULL);
1827 p = GetUntilNul(&data_in, &len_in);
1830 // Find the highest numbered matching key for p.
1831 for(i = 0; i < MAX_PUBKEYS; ++i)
1834 if(!strcmp(p, pubkeys_fp64[i]))
1838 return Crypto_ServerError(data_out, len_out, "Invalid client key", NULL);
1841 crypto = Crypto_ServerFindInstance(peeraddress, true);
1843 return Crypto_ServerError(data_out, len_out, "Could not create a crypto connect instance", NULL);
1845 CDATA->cdata_id = id;
1846 CDATA->s = serverid;
1847 CDATA->c = clientid;
1848 memset(crypto->dhkey, 0, sizeof(crypto->dhkey));
1849 CDATA->challenge[0] = 0;
1850 crypto->client_keyfp[0] = 0;
1851 crypto->client_idfp[0] = 0;
1852 crypto->server_keyfp[0] = 0;
1853 crypto->server_idfp[0] = 0;
1854 crypto->use_aes = aes != 0;
1858 // I am the server, and my key is ok... so let's set server_keyfp and server_idfp
1859 dp_strlcpy(crypto->server_keyfp, pubkeys_fp64[CDATA->s], sizeof(crypto->server_keyfp));
1860 dp_strlcpy(crypto->server_idfp, pubkeys_priv_fp64[CDATA->s], sizeof(crypto->server_idfp));
1861 crypto->server_issigned = pubkeys_havesig[CDATA->s];
1864 CDATA->id = qd0_blind_id_new();
1868 return Crypto_ServerError(data_out, len_out, "d0_blind_id_new failed", "Internal error");
1870 if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->s]))
1873 return Crypto_ServerError(data_out, len_out, "d0_blind_id_copy failed", "Internal error");
1875 PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\1\\id\\%d\\aes\\%d", CDATA->cdata_id, crypto->use_aes));
1876 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
1879 return Crypto_ServerError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_start failed", "Internal error");
1881 CDATA->next_step = 2;
1882 data_out_p += *len_out;
1883 *len_out = data_out_p - data_out;
1884 return CRYPTO_DISCARD;
1886 else if(CDATA->c >= 0)
1889 CDATA->id = qd0_blind_id_new();
1893 return Crypto_ServerError(data_out, len_out, "d0_blind_id_new failed", "Internal error");
1895 if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->c]))
1898 return Crypto_ServerError(data_out, len_out, "d0_blind_id_copy failed", "Internal error");
1900 PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\5\\id\\%d\\aes\\%d", CDATA->cdata_id, crypto->use_aes));
1901 if(!qd0_blind_id_authenticate_with_private_id_challenge(CDATA->id, true, false, data_in, len_in, data_out_p, len_out, &status))
1904 return Crypto_ServerError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_challenge failed", "Internal error");
1906 CDATA->next_step = 6;
1907 data_out_p += *len_out;
1908 *len_out = data_out_p - data_out;
1909 return CRYPTO_DISCARD;
1914 return Crypto_ServerError(data_out, len_out, "Missing client and server key", NULL);
1917 else if(!strcmp(cnt, "2"))
1920 crypto = Crypto_ServerFindInstance(peeraddress, false);
1922 return CRYPTO_NOMATCH; // pre-challenge, rather be silent
1924 if(CDATA->cdata_id != id)
1925 return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
1926 if(CDATA->next_step != 2)
1927 return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
1929 PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\3\\id\\%d", CDATA->cdata_id));
1930 if(!qd0_blind_id_authenticate_with_private_id_response(CDATA->id, data_in, len_in, data_out_p, len_out))
1933 return Crypto_ServerError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_response failed", "Internal error");
1935 fpbuflen = DHKEY_SIZE;
1936 if(!qd0_blind_id_sessionkey_public_id(CDATA->id, (char *) crypto->dhkey, &fpbuflen))
1939 return Crypto_ServerError(data_out, len_out, "d0_blind_id_sessionkey_public_id failed", "Internal error");
1943 if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->c]))
1946 return Crypto_ServerError(data_out, len_out, "d0_blind_id_copy failed", "Internal error");
1948 CDATA->next_step = 4;
1952 // session key is FINISHED (no server part is to be expected)! By this, all keys are set up
1953 crypto->authenticated = true;
1954 CDATA->next_step = 0;
1956 data_out_p += *len_out;
1957 *len_out = data_out_p - data_out;
1958 return CRYPTO_DISCARD;
1960 else if(!strcmp(cnt, "4"))
1962 crypto = Crypto_ServerFindInstance(peeraddress, false);
1964 return CRYPTO_NOMATCH; // pre-challenge, rather be silent
1966 if(CDATA->cdata_id != id)
1967 return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
1968 if(CDATA->next_step != 4)
1969 return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
1970 PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\5\\id\\%d", CDATA->cdata_id));
1971 if(!qd0_blind_id_authenticate_with_private_id_challenge(CDATA->id, true, false, data_in, len_in, data_out_p, len_out, &status))
1974 return Crypto_ServerError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_challenge failed", "Internal error");
1976 CDATA->next_step = 6;
1977 data_out_p += *len_out;
1978 *len_out = data_out_p - data_out;
1979 return CRYPTO_DISCARD;
1981 else if(!strcmp(cnt, "6"))
1983 static char msgbuf[32];
1984 size_t msgbuflen = sizeof(msgbuf);
1987 unsigned char dhkey[DHKEY_SIZE];
1988 crypto = Crypto_ServerFindInstance(peeraddress, false);
1990 return CRYPTO_NOMATCH; // pre-challenge, rather be silent
1992 if(CDATA->cdata_id != id)
1993 return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
1994 if(CDATA->next_step != 6)
1995 return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
1997 if(!qd0_blind_id_authenticate_with_private_id_verify(CDATA->id, data_in, len_in, msgbuf, &msgbuflen, &status))
2000 return Crypto_ServerError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_verify failed (authentication error)", "Authentication error");
2002 dp_strlcpy(crypto->client_keyfp, pubkeys_fp64[CDATA->c], sizeof(crypto->client_keyfp));
2003 crypto->client_issigned = status;
2005 memset(crypto->client_idfp, 0, sizeof(crypto->client_idfp));
2006 fpbuflen = FP64_SIZE;
2007 if(!qd0_blind_id_fingerprint64_public_id(CDATA->id, crypto->client_idfp, &fpbuflen))
2010 return Crypto_ServerError(data_out, len_out, "d0_blind_id_fingerprint64_public_id failed", "Internal error");
2012 fpbuflen = DHKEY_SIZE;
2013 if(!qd0_blind_id_sessionkey_public_id(CDATA->id, (char *) dhkey, &fpbuflen))
2016 return Crypto_ServerError(data_out, len_out, "d0_blind_id_sessionkey_public_id failed", "Internal error");
2018 // XOR the two DH keys together to make one
2019 for(i = 0; i < DHKEY_SIZE; ++i)
2020 crypto->dhkey[i] ^= dhkey[i];
2022 // session key is FINISHED (no server part is to be expected)! By this, all keys are set up
2023 crypto->authenticated = true;
2024 CDATA->next_step = 0;
2025 // send a challenge-less challenge
2026 PutWithNul(&data_out_p, len_out, "challenge ");
2027 *len_out = data_out_p - data_out;
2028 --*len_out; // remove NUL terminator
2029 return CRYPTO_MATCH;
2031 return CRYPTO_NOMATCH; // pre-challenge, rather be silent
2033 return CRYPTO_NOMATCH;
2036 int Crypto_ServerParsePacket(const char *data_in, size_t len_in, char *data_out, size_t *len_out, lhnetaddress_t *peeraddress)
2040 static double complain_time = 0;
2042 qbool do_time = false;
2043 qbool do_reject = false;
2044 char infostringvalue[MAX_INPUTLINE];
2045 if(crypto_servercpupercent.value > 0 || crypto_servercpumaxtime.value > 0)
2046 if(len_in > 5 && !memcmp(data_in, "d0pk\\", 5))
2049 cnt = (InfoString_GetValue(data_in + 4, "cnt", infostringvalue, sizeof(infostringvalue)) ? infostringvalue : NULL);
2051 if(!strcmp(cnt, "0"))
2056 // check if we may perform crypto...
2057 if(crypto_servercpupercent.value > 0)
2059 crypto_servercpu_accumulator += (host.realtime - crypto_servercpu_lastrealtime) * crypto_servercpupercent.value * 0.01;
2060 if(crypto_servercpumaxtime.value)
2061 if(crypto_servercpu_accumulator > crypto_servercpumaxtime.value)
2062 crypto_servercpu_accumulator = crypto_servercpumaxtime.value;
2066 if(crypto_servercpumaxtime.value > 0)
2067 if(host.realtime != crypto_servercpu_lastrealtime)
2068 crypto_servercpu_accumulator = crypto_servercpumaxtime.value;
2070 crypto_servercpu_lastrealtime = host.realtime;
2071 if(do_reject && crypto_servercpu_accumulator < 0)
2073 if(host.realtime > complain_time + 5)
2074 Con_Printf("crypto: cannot perform requested crypto operations; denial service attack or crypto_servercpupercent/crypto_servercpumaxtime are too low\n");
2076 return CRYPTO_DISCARD;
2078 t = Sys_DirtyTime();
2080 ret = Crypto_ServerParsePacket_Internal(data_in, len_in, data_out, len_out, peeraddress);
2083 t = Sys_DirtyTime() - t;if (t < 0.0) t = 0.0; // dirtytime can step backwards
2084 if(crypto_servercpudebug.integer)
2085 Con_Printf("crypto: accumulator was %.1f ms, used %.1f ms for crypto, ", crypto_servercpu_accumulator * 1000, t * 1000);
2086 crypto_servercpu_accumulator -= t;
2087 if(crypto_servercpudebug.integer)
2088 Con_Printf("is %.1f ms\n", crypto_servercpu_accumulator * 1000);
2093 static int Crypto_ClientError(char *data_out, size_t *len_out, const char *msg)
2095 dpsnprintf(data_out, *len_out, "reject %s", msg);
2096 *len_out = strlen(data_out);
2097 return CRYPTO_REPLACE;
2100 static int Crypto_SoftClientError(char *data_out, size_t *len_out, const char *msg)
2103 Con_DPrintf("%s\n", msg);
2104 return CRYPTO_DISCARD;
2107 int Crypto_ClientParsePacket(const char *data_in, size_t len_in, char *data_out, size_t *len_out, lhnetaddress_t *peeraddress, const char *peeraddressstring)
2109 crypto_t *crypto = &cls.crypto;
2110 const char *string = data_in;
2112 char *data_out_p = data_out;
2114 char infostringvalue[MAX_INPUTLINE];
2117 if(!d0_blind_id_dll)
2118 return CRYPTO_NOMATCH; // no support
2120 // if "challenge": verify challenge, and discard message, send next crypto protocol message instead
2121 // otherwise, just handle actual protocol messages
2123 if (len_in == 6 && !memcmp(string, "accept", 6) && cls.connect_trying && d0_rijndael_dll)
2125 int wantserverid = -1;
2126 Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, NULL, 0, NULL, NULL);
2127 if(!crypto || !crypto->authenticated) // we ALSO get here if we are using an encrypted connection, so let's rule this out
2129 if(wantserverid >= 0)
2130 return Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though a host key is present");
2131 if(crypto_aeslevel.integer >= 3)
2132 return Crypto_ClientError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)");
2134 return CRYPTO_NOMATCH;
2136 else if (len_in >= 1 && string[0] == 'j' && cls.connect_trying && d0_rijndael_dll)
2138 int wantserverid = -1;
2139 Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, NULL, 0, NULL, NULL);
2140 //if(!crypto || !crypto->authenticated)
2142 if(wantserverid >= 0)
2143 return Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though a host key is present");
2144 if(crypto_aeslevel.integer >= 3)
2145 return Crypto_ClientError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)");
2147 return CRYPTO_NOMATCH;
2149 else if (len_in >= 5 && BuffLittleLong((unsigned char *) string) == ((int)NETFLAG_CTL | (int)len_in))
2151 int wantserverid = -1;
2153 // these three are harmless
2154 if((unsigned char) string[4] == CCREP_SERVER_INFO)
2155 return CRYPTO_NOMATCH;
2156 if((unsigned char) string[4] == CCREP_PLAYER_INFO)
2157 return CRYPTO_NOMATCH;
2158 if((unsigned char) string[4] == CCREP_RULE_INFO)
2159 return CRYPTO_NOMATCH;
2161 Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, NULL, 0, NULL, NULL);
2162 //if(!crypto || !crypto->authenticated)
2164 if(wantserverid >= 0)
2165 return Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though a host key is present");
2166 if(crypto_aeslevel.integer >= 3)
2167 return Crypto_ClientError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)");
2169 return CRYPTO_NOMATCH;
2171 else if (len_in >= 13 && !memcmp(string, "infoResponse\x0A", 13))
2173 if(InfoString_GetValue(string + 13, "d0_blind_id", infostringvalue, sizeof(infostringvalue)))
2174 Crypto_StoreHostKey(peeraddress, infostringvalue, true);
2175 return CRYPTO_NOMATCH;
2177 else if (len_in >= 15 && !memcmp(string, "statusResponse\x0A", 15))
2181 p = strchr(string + 15, '\n');
2185 * (char *) p = 0; // cut off the string there
2187 if(InfoString_GetValue(string + 15, "d0_blind_id", infostringvalue, sizeof(infostringvalue)))
2188 Crypto_StoreHostKey(peeraddress, infostringvalue, true);
2191 * (char *) p = save;
2192 // invoking those nasal demons again (do not run this on the DS9k)
2194 return CRYPTO_NOMATCH;
2196 else if(len_in > 10 && !memcmp(string, "challenge ", 10) && cls.connect_trying)
2198 const char *vlen_blind_id_ptr = NULL;
2199 size_t len_blind_id_ptr = 0;
2201 const char *challenge = data_in + 10;
2204 int clientid = -1, serverid = -1, wantserverid = -1;
2205 qbool server_can_auth = true;
2206 char wantserver_idfp[FP64_SIZE+1];
2207 int wantserver_aeslevel = 0;
2208 qbool wantserver_issigned = false;
2210 // 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.
2211 if (net_sourceaddresscheck.integer && LHNETADDRESS_Compare(peeraddress, &cls.connect_address))
2215 dpsnprintf(warn_msg, sizeof(warn_msg), "ignoring challenge message from wrong server %s", peeraddressstring);
2216 return Crypto_SoftClientError(data_out, len_out, warn_msg);
2219 // if we have a stored host key for the server, assume serverid to already be selected!
2220 // (the loop will refuse to overwrite this one then)
2221 wantserver_idfp[0] = 0;
2222 Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, wantserver_idfp, sizeof(wantserver_idfp), &wantserver_aeslevel, &wantserver_issigned);
2223 // requirement: wantserver_idfp is a full ID if wantserverid set
2225 // if we leave, we have to consider the connection
2226 // unauthenticated; NOTE: this may be faked by a clever
2227 // attacker to force an unauthenticated connection; so we have
2228 // a safeguard check in place when encryption is required too
2229 // in place, or when authentication is required by the server
2230 crypto->authenticated = false;
2232 GetUntilNul(&data_in, &len_in);
2234 return (wantserverid >= 0) ? Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though a host key is present") :
2235 (d0_rijndael_dll && crypto_aeslevel.integer >= 3) ? Crypto_ClientError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)") :
2238 // FTEQW extension protocol
2241 k = Crypto_LittleLong(data_in);
2242 v = Crypto_LittleLong(data_in + 4);
2250 k = Crypto_LittleLong(data_in);
2255 case PROTOCOL_D0_BLIND_ID:
2256 vlen_blind_id_ptr = data_in;
2257 len_blind_id_ptr = v;
2269 if(!vlen_blind_id_ptr)
2270 return (wantserverid >= 0) ? Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though authentication is required") :
2271 (d0_rijndael_dll && crypto_aeslevel.integer >= 3) ? Crypto_ClientError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)") :
2274 data_in = vlen_blind_id_ptr;
2275 len_in = len_blind_id_ptr;
2277 // parse fingerprints
2278 // once we found a fingerprint we can auth to (ANY), select it as clientfp
2279 // once we found a fingerprint in the first list that we know, select it as serverfp
2283 p = GetUntilNul(&data_in, &len_in);
2288 if(!server_can_auth)
2289 break; // other protocol message may follow
2290 server_can_auth = false;
2295 // Find the highest numbered matching key for p.
2296 for(i = 0; i < MAX_PUBKEYS; ++i)
2299 if(!strcmp(p, pubkeys_fp64[i]))
2301 if(pubkeys_havepriv[i])
2304 if(wantserverid < 0 || i == wantserverid)
2308 // Not breaking, as higher keys in the list always have priority.
2311 // if stored host key is not found:
2312 if(wantserverid >= 0 && serverid < 0)
2313 return Crypto_ClientError(data_out, len_out, "Server CA does not match stored host key, refusing to connect");
2315 if(serverid >= 0 || clientid >= 0)
2318 CDATA->cdata_id = ++cdata_id;
2319 CDATA->s = serverid;
2320 CDATA->c = clientid;
2321 memset(crypto->dhkey, 0, sizeof(crypto->dhkey));
2322 dp_strlcpy(CDATA->challenge, challenge, sizeof(CDATA->challenge));
2323 crypto->client_keyfp[0] = 0;
2324 crypto->client_idfp[0] = 0;
2325 crypto->server_keyfp[0] = 0;
2326 crypto->server_idfp[0] = 0;
2327 memcpy(CDATA->wantserver_idfp, wantserver_idfp, sizeof(crypto->server_idfp));
2328 CDATA->wantserver_issigned = wantserver_issigned;
2330 if(CDATA->wantserver_idfp[0]) // if we know a host key, honor its encryption setting
2331 switch(bound(0, d0_rijndael_dll ? crypto_aeslevel.integer : 0, 3))
2333 default: // dummy, never happens, but to make gcc happy...
2335 if(wantserver_aeslevel >= 3)
2336 return Crypto_ClientError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)");
2337 CDATA->wantserver_aes = false;
2340 CDATA->wantserver_aes = (wantserver_aeslevel >= 2);
2343 CDATA->wantserver_aes = (wantserver_aeslevel >= 1);
2346 if(wantserver_aeslevel <= 0)
2347 return Crypto_ClientError(data_out, len_out, "This server requires encryption to be supported (crypto_aeslevel >= 1, and d0_rijndael library must be present)");
2348 CDATA->wantserver_aes = true;
2352 // build outgoing message
2353 // append regular stuff
2354 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));
2355 PutWithNul(&data_out_p, len_out, serverid >= 0 ? pubkeys_fp64[serverid] : "");
2356 PutWithNul(&data_out_p, len_out, clientid >= 0 ? pubkeys_fp64[clientid] : "");
2360 // I am the client, and my key is ok... so let's set client_keyfp and client_idfp
2361 dp_strlcpy(crypto->client_keyfp, pubkeys_fp64[CDATA->c], sizeof(crypto->client_keyfp));
2362 dp_strlcpy(crypto->client_idfp, pubkeys_priv_fp64[CDATA->c], sizeof(crypto->client_idfp));
2363 crypto->client_issigned = pubkeys_havesig[CDATA->c];
2369 CDATA->id = qd0_blind_id_new();
2373 return Crypto_ClientError(data_out, len_out, "d0_blind_id_new failed");
2375 if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->s]))
2378 return Crypto_ClientError(data_out, len_out, "d0_blind_id_copy failed");
2380 CDATA->next_step = 1;
2381 *len_out = data_out_p - data_out;
2383 else // if(clientid >= 0) // guaranteed by condition one level outside
2385 // skip over server auth, perform client auth only
2387 CDATA->id = qd0_blind_id_new();
2391 return Crypto_ClientError(data_out, len_out, "d0_blind_id_new failed");
2393 if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->c]))
2396 return Crypto_ClientError(data_out, len_out, "d0_blind_id_copy failed");
2398 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
2401 return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_start failed");
2403 CDATA->next_step = 5;
2404 data_out_p += *len_out;
2405 *len_out = data_out_p - data_out;
2407 return CRYPTO_DISCARD;
2411 if(wantserver_idfp[0]) // if we know a host key, honor its encryption setting
2412 if(wantserver_aeslevel >= 3)
2413 return Crypto_ClientError(data_out, len_out, "Server insists on encryption, but neither can authenticate to the other");
2414 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)") :
2418 else if(len_in > 5 && !memcmp(string, "d0pk\\", 5) && cls.connect_trying)
2423 // 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.
2424 if (net_sourceaddresscheck.integer && LHNETADDRESS_Compare(peeraddress, &cls.connect_address))
2428 dpsnprintf(warn_msg, sizeof(warn_msg), "ignoring d0pk\\ message from wrong server %s", peeraddressstring);
2429 return Crypto_SoftClientError(data_out, len_out, warn_msg);
2432 id = (InfoString_GetValue(string + 4, "id", infostringvalue, sizeof(infostringvalue)) ? atoi(infostringvalue) : -1);
2433 cnt = (InfoString_GetValue(string + 4, "cnt", infostringvalue, sizeof(infostringvalue)) ? infostringvalue : NULL);
2435 return Crypto_ClientError(data_out, len_out, "d0pk\\ message without cnt");
2436 GetUntilNul(&data_in, &len_in);
2438 return Crypto_ClientError(data_out, len_out, "d0pk\\ message without attachment");
2440 if(!strcmp(cnt, "1"))
2443 if(CDATA->cdata_id != id)
2444 return Crypto_SoftClientError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
2445 if(CDATA->next_step != 1)
2446 return Crypto_SoftClientError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
2448 cls.connect_nextsendtime = max(cls.connect_nextsendtime, host.realtime + 1); // prevent "hammering"
2450 if(InfoString_GetValue(string + 4, "aes", infostringvalue, sizeof(infostringvalue)))
2451 aes = atoi(infostringvalue);
2454 // we CANNOT toggle the AES status any more!
2455 // as the server already decided
2456 if(CDATA->wantserver_idfp[0]) // if we know a host key, honor its encryption setting
2457 if(!aes && CDATA->wantserver_aes)
2460 return Crypto_ClientError(data_out, len_out, "Stored host key requires encryption, but server did not enable encryption");
2462 if(aes && (!d0_rijndael_dll || crypto_aeslevel.integer <= 0))
2465 return Crypto_ClientError(data_out, len_out, "Server insists on encryption too hard");
2467 if(!aes && (d0_rijndael_dll && crypto_aeslevel.integer >= 3))
2470 return Crypto_ClientError(data_out, len_out, "Server insists on plaintext too hard");
2472 crypto->use_aes = aes != 0;
2474 PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\2\\id\\%d", CDATA->cdata_id));
2475 if(!qd0_blind_id_authenticate_with_private_id_challenge(CDATA->id, true, false, data_in, len_in, data_out_p, len_out, &status))
2478 return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_challenge failed");
2480 CDATA->next_step = 3;
2481 data_out_p += *len_out;
2482 *len_out = data_out_p - data_out;
2483 return CRYPTO_DISCARD;
2485 else if(!strcmp(cnt, "3"))
2487 static char msgbuf[32];
2488 size_t msgbuflen = sizeof(msgbuf);
2492 if(CDATA->cdata_id != id)
2493 return Crypto_SoftClientError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
2494 if(CDATA->next_step != 3)
2495 return Crypto_SoftClientError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
2497 cls.connect_nextsendtime = max(cls.connect_nextsendtime, host.realtime + 1); // prevent "hammering"
2499 if(!qd0_blind_id_authenticate_with_private_id_verify(CDATA->id, data_in, len_in, msgbuf, &msgbuflen, &status))
2502 return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_verify failed (server authentication error)");
2505 dp_strlcpy(crypto->server_keyfp, pubkeys_fp64[CDATA->s], sizeof(crypto->server_keyfp));
2506 if (!status && CDATA->wantserver_issigned)
2509 return Crypto_ClientError(data_out, len_out, "Stored host key requires a valid signature, but server did not provide any");
2511 crypto->server_issigned = status;
2513 memset(crypto->server_idfp, 0, sizeof(crypto->server_idfp));
2514 fpbuflen = FP64_SIZE;
2515 if(!qd0_blind_id_fingerprint64_public_id(CDATA->id, crypto->server_idfp, &fpbuflen))
2518 return Crypto_ClientError(data_out, len_out, "d0_blind_id_fingerprint64_public_id failed");
2520 if(CDATA->wantserver_idfp[0])
2521 if(memcmp(CDATA->wantserver_idfp, crypto->server_idfp, sizeof(crypto->server_idfp)))
2524 return Crypto_ClientError(data_out, len_out, "Server ID does not match stored host key, refusing to connect");
2526 fpbuflen = DHKEY_SIZE;
2527 if(!qd0_blind_id_sessionkey_public_id(CDATA->id, (char *) crypto->dhkey, &fpbuflen))
2530 return Crypto_ClientError(data_out, len_out, "d0_blind_id_sessionkey_public_id failed");
2533 // cache the server key
2534 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);
2538 // client will auth next
2539 PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\4\\id\\%d", CDATA->cdata_id));
2540 if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->c]))
2543 return Crypto_ClientError(data_out, len_out, "d0_blind_id_copy failed");
2545 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
2548 return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_start failed");
2550 CDATA->next_step = 5;
2551 data_out_p += *len_out;
2552 *len_out = data_out_p - data_out;
2553 return CRYPTO_DISCARD;
2557 // session key is FINISHED (no server part is to be expected)! By this, all keys are set up
2558 crypto->authenticated = true;
2559 CDATA->next_step = 0;
2560 // assume we got the empty challenge to finish the protocol
2561 PutWithNul(&data_out_p, len_out, "challenge ");
2562 *len_out = data_out_p - data_out;
2563 --*len_out; // remove NUL terminator
2564 return CRYPTO_REPLACE;
2567 else if(!strcmp(cnt, "5"))
2570 unsigned char dhkey[DHKEY_SIZE];
2574 if(CDATA->cdata_id != id)
2575 return Crypto_SoftClientError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
2576 if(CDATA->next_step != 5)
2577 return Crypto_SoftClientError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
2579 cls.connect_nextsendtime = max(cls.connect_nextsendtime, host.realtime + 1); // prevent "hammering"
2581 if(CDATA->s < 0) // only if server didn't auth
2583 if(InfoString_GetValue(string + 4, "aes", infostringvalue, sizeof(infostringvalue)))
2584 aes = atoi(infostringvalue);
2587 if(CDATA->wantserver_idfp[0]) // if we know a host key, honor its encryption setting
2588 if(!aes && CDATA->wantserver_aes)
2591 return Crypto_ClientError(data_out, len_out, "Stored host key requires encryption, but server did not enable encryption");
2593 if(aes && (!d0_rijndael_dll || crypto_aeslevel.integer <= 0))
2596 return Crypto_ClientError(data_out, len_out, "Server insists on encryption too hard");
2598 if(!aes && (d0_rijndael_dll && crypto_aeslevel.integer >= 3))
2601 return Crypto_ClientError(data_out, len_out, "Server insists on plaintext too hard");
2603 crypto->use_aes = aes != 0;
2606 PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\6\\id\\%d", CDATA->cdata_id));
2607 if(!qd0_blind_id_authenticate_with_private_id_response(CDATA->id, data_in, len_in, data_out_p, len_out))
2610 return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_response failed");
2612 fpbuflen = DHKEY_SIZE;
2613 if(!qd0_blind_id_sessionkey_public_id(CDATA->id, (char *) dhkey, &fpbuflen))
2616 return Crypto_ClientError(data_out, len_out, "d0_blind_id_sessionkey_public_id failed");
2618 // XOR the two DH keys together to make one
2619 for(i = 0; i < DHKEY_SIZE; ++i)
2620 crypto->dhkey[i] ^= dhkey[i];
2621 // session key is FINISHED! By this, all keys are set up
2622 crypto->authenticated = true;
2623 CDATA->next_step = 0;
2624 data_out_p += *len_out;
2625 *len_out = data_out_p - data_out;
2626 return CRYPTO_DISCARD;
2628 return Crypto_SoftClientError(data_out, len_out, "Got unknown d0_blind_id message from server");
2631 return CRYPTO_NOMATCH;
2634 size_t Crypto_SignData(const void *data, size_t datasize, int keyid, void *signed_data, size_t signed_size)
2636 if(keyid < 0 || keyid >= MAX_PUBKEYS)
2638 if(!pubkeys_havepriv[keyid])
2640 if(qd0_blind_id_sign_with_private_id_sign(pubkeys[keyid], true, false, (const char *)data, datasize, (char *)signed_data, &signed_size))
2645 size_t Crypto_SignDataDetached(const void *data, size_t datasize, int keyid, void *signed_data, size_t signed_size)
2647 if(keyid < 0 || keyid >= MAX_PUBKEYS)
2649 if(!pubkeys_havepriv[keyid])
2651 if(qd0_blind_id_sign_with_private_id_sign_detached(pubkeys[keyid], true, false, (const char *)data, datasize, (char *)signed_data, &signed_size))