1 // TODO key loading, generating, saving
10 void *crypto_mutex = NULL;
12 cvar_t crypto_developer = {CVAR_SAVE, "crypto_developer", "0", "print extra info about crypto handshake"};
13 cvar_t crypto_servercpupercent = {CVAR_SAVE, "crypto_servercpupercent", "10", "allowed crypto CPU load in percent for server operation (0 = no limit, faster)"};
14 cvar_t crypto_servercpumaxtime = {CVAR_SAVE, "crypto_servercpumaxtime", "0.01", "maximum allowed crypto CPU time per frame (0 = no limit)"};
15 cvar_t crypto_servercpudebug = {CVAR_SAVE, "crypto_servercpudebug", "0", "print statistics about time usage by crypto"};
16 static double crypto_servercpu_accumulator = 0;
17 static double crypto_servercpu_lastrealtime = 0;
18 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)"};
19 int crypto_keyfp_recommended_length;
20 static const char *crypto_idstring = NULL;
21 static char crypto_idstring_buf[512];
23 #define PROTOCOL_D0_BLIND_ID FOURCC_D0PK
24 #define PROTOCOL_VLEN (('v' << 0) | ('l' << 8) | ('e' << 16) | ('n' << 24))
26 // BEGIN stuff shared with crypto-keygen-standalone
27 #define FOURCC_D0PK (('d' << 0) | ('0' << 8) | ('p' << 16) | ('k' << 24))
28 #define FOURCC_D0SK (('d' << 0) | ('0' << 8) | ('s' << 16) | ('k' << 24))
29 #define FOURCC_D0PI (('d' << 0) | ('0' << 8) | ('p' << 16) | ('i' << 24))
30 #define FOURCC_D0SI (('d' << 0) | ('0' << 8) | ('s' << 16) | ('i' << 24))
31 #define FOURCC_D0IQ (('d' << 0) | ('0' << 8) | ('i' << 16) | ('q' << 24))
32 #define FOURCC_D0IR (('d' << 0) | ('0' << 8) | ('i' << 16) | ('r' << 24))
33 #define FOURCC_D0ER (('d' << 0) | ('0' << 8) | ('e' << 16) | ('r' << 24))
34 #define FOURCC_D0IC (('d' << 0) | ('0' << 8) | ('i' << 16) | ('c' << 24))
36 static unsigned long Crypto_LittleLong(const char *data)
39 ((unsigned char) data[0]) |
40 (((unsigned char) data[1]) << 8) |
41 (((unsigned char) data[2]) << 16) |
42 (((unsigned char) data[3]) << 24);
45 static void Crypto_UnLittleLong(char *data, unsigned long l)
48 data[1] = (l >> 8) & 0xFF;
49 data[2] = (l >> 16) & 0xFF;
50 data[3] = (l >> 24) & 0xFF;
53 static size_t Crypto_ParsePack(const char *buf, size_t len, unsigned long header, const char **lumps, size_t *lumpsize, size_t nlumps)
62 if(Crypto_LittleLong(buf) != header)
66 for(i = 0; i < nlumps; ++i)
70 lumpsize[i] = Crypto_LittleLong(&buf[pos]);
72 if(pos + lumpsize[i] > len)
80 static size_t Crypto_UnParsePack(char *buf, size_t len, unsigned long header, const char *const *lumps, const size_t *lumpsize, size_t nlumps)
89 Crypto_UnLittleLong(buf, header);
92 for(i = 0; i < nlumps; ++i)
94 if(pos + 4 + lumpsize[i] > len)
96 Crypto_UnLittleLong(&buf[pos], lumpsize[i]);
98 memcpy(&buf[pos], lumps[i], lumpsize[i]);
103 // END stuff shared with xonotic-keygen
109 #include <d0_blind_id/d0_blind_id.h>
111 #define d0_blind_id_dll 1
112 #define Crypto_OpenLibrary() true
113 #define Crypto_CloseLibrary()
115 #define qd0_blind_id_new d0_blind_id_new
116 #define qd0_blind_id_free d0_blind_id_free
117 //#define qd0_blind_id_clear d0_blind_id_clear
118 #define qd0_blind_id_copy d0_blind_id_copy
119 //#define qd0_blind_id_generate_private_key d0_blind_id_generate_private_key
120 //#define qd0_blind_id_generate_private_key_fastreject d0_blind_id_generate_private_key_fastreject
121 //#define qd0_blind_id_read_private_key d0_blind_id_read_private_key
122 #define qd0_blind_id_read_public_key d0_blind_id_read_public_key
123 //#define qd0_blind_id_write_private_key d0_blind_id_write_private_key
124 //#define qd0_blind_id_write_public_key d0_blind_id_write_public_key
125 #define qd0_blind_id_fingerprint64_public_key d0_blind_id_fingerprint64_public_key
126 //#define qd0_blind_id_generate_private_id_modulus d0_blind_id_generate_private_id_modulus
127 #define qd0_blind_id_read_private_id_modulus d0_blind_id_read_private_id_modulus
128 //#define qd0_blind_id_write_private_id_modulus d0_blind_id_write_private_id_modulus
129 #define qd0_blind_id_generate_private_id_start d0_blind_id_generate_private_id_start
130 #define qd0_blind_id_generate_private_id_request d0_blind_id_generate_private_id_request
131 //#define qd0_blind_id_answer_private_id_request d0_blind_id_answer_private_id_request
132 #define qd0_blind_id_finish_private_id_request d0_blind_id_finish_private_id_request
133 //#define qd0_blind_id_read_private_id_request_camouflage d0_blind_id_read_private_id_request_camouflage
134 //#define qd0_blind_id_write_private_id_request_camouflage d0_blind_id_write_private_id_request_camouflage
135 #define qd0_blind_id_read_private_id d0_blind_id_read_private_id
136 //#define qd0_blind_id_read_public_id d0_blind_id_read_public_id
137 #define qd0_blind_id_write_private_id d0_blind_id_write_private_id
138 //#define qd0_blind_id_write_public_id d0_blind_id_write_public_id
139 #define qd0_blind_id_authenticate_with_private_id_start d0_blind_id_authenticate_with_private_id_start
140 #define qd0_blind_id_authenticate_with_private_id_challenge d0_blind_id_authenticate_with_private_id_challenge
141 #define qd0_blind_id_authenticate_with_private_id_response d0_blind_id_authenticate_with_private_id_response
142 #define qd0_blind_id_authenticate_with_private_id_verify d0_blind_id_authenticate_with_private_id_verify
143 #define qd0_blind_id_fingerprint64_public_id d0_blind_id_fingerprint64_public_id
144 #define qd0_blind_id_sessionkey_public_id d0_blind_id_sessionkey_public_id
145 #define qd0_blind_id_INITIALIZE d0_blind_id_INITIALIZE
146 #define qd0_blind_id_SHUTDOWN d0_blind_id_SHUTDOWN
147 #define qd0_blind_id_util_sha256 d0_blind_id_util_sha256
148 #define qd0_blind_id_sign_with_private_id_sign d0_blind_id_sign_with_private_id_sign
149 #define qd0_blind_id_sign_with_private_id_sign_detached d0_blind_id_sign_with_private_id_sign_detached
153 // d0_blind_id interface
156 #define D0_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
158 #define D0_WARN_UNUSED_RESULT
162 typedef struct d0_blind_id_s d0_blind_id_t;
163 typedef D0_BOOL (*d0_fastreject_function) (const d0_blind_id_t *ctx, void *pass);
164 static D0_EXPORT D0_WARN_UNUSED_RESULT d0_blind_id_t *(*qd0_blind_id_new) (void);
165 static D0_EXPORT void (*qd0_blind_id_free) (d0_blind_id_t *a);
166 //static D0_EXPORT void (*qd0_blind_id_clear) (d0_blind_id_t *ctx);
167 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_copy) (d0_blind_id_t *ctx, const d0_blind_id_t *src);
168 //static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_generate_private_key) (d0_blind_id_t *ctx, int k);
169 //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);
170 //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);
171 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);
172 //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);
173 //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);
174 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);
175 //static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_generate_private_id_modulus) (d0_blind_id_t *ctx);
176 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);
177 //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);
178 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_generate_private_id_start) (d0_blind_id_t *ctx);
179 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);
180 //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);
181 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);
182 //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);
183 //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);
184 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);
185 //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);
186 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);
187 //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);
188 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);
189 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);
190 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);
191 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);
192 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);
193 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
194 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_INITIALIZE) (void);
195 static D0_EXPORT void (*qd0_blind_id_SHUTDOWN) (void);
196 static D0_EXPORT void (*qd0_blind_id_util_sha256) (char *out, const char *in, size_t n);
197 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);
198 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);
199 static dllfunction_t d0_blind_id_funcs[] =
201 {"d0_blind_id_new", (void **) &qd0_blind_id_new},
202 {"d0_blind_id_free", (void **) &qd0_blind_id_free},
203 //{"d0_blind_id_clear", (void **) &qd0_blind_id_clear},
204 {"d0_blind_id_copy", (void **) &qd0_blind_id_copy},
205 //{"d0_blind_id_generate_private_key", (void **) &qd0_blind_id_generate_private_key},
206 //{"d0_blind_id_generate_private_key_fastreject", (void **) &qd0_blind_id_generate_private_key_fastreject},
207 //{"d0_blind_id_read_private_key", (void **) &qd0_blind_id_read_private_key},
208 {"d0_blind_id_read_public_key", (void **) &qd0_blind_id_read_public_key},
209 //{"d0_blind_id_write_private_key", (void **) &qd0_blind_id_write_private_key},
210 //{"d0_blind_id_write_public_key", (void **) &qd0_blind_id_write_public_key},
211 {"d0_blind_id_fingerprint64_public_key", (void **) &qd0_blind_id_fingerprint64_public_key},
212 //{"d0_blind_id_generate_private_id_modulus", (void **) &qd0_blind_id_generate_private_id_modulus},
213 {"d0_blind_id_read_private_id_modulus", (void **) &qd0_blind_id_read_private_id_modulus},
214 //{"d0_blind_id_write_private_id_modulus", (void **) &qd0_blind_id_write_private_id_modulus},
215 {"d0_blind_id_generate_private_id_start", (void **) &qd0_blind_id_generate_private_id_start},
216 {"d0_blind_id_generate_private_id_request", (void **) &qd0_blind_id_generate_private_id_request},
217 //{"d0_blind_id_answer_private_id_request", (void **) &qd0_blind_id_answer_private_id_request},
218 {"d0_blind_id_finish_private_id_request", (void **) &qd0_blind_id_finish_private_id_request},
219 //{"d0_blind_id_read_private_id_request_camouflage", (void **) &qd0_blind_id_read_private_id_request_camouflage},
220 //{"d0_blind_id_write_private_id_request_camouflage", (void **) &qd0_blind_id_write_private_id_request_camouflage},
221 {"d0_blind_id_read_private_id", (void **) &qd0_blind_id_read_private_id},
222 //{"d0_blind_id_read_public_id", (void **) &qd0_blind_id_read_public_id},
223 {"d0_blind_id_write_private_id", (void **) &qd0_blind_id_write_private_id},
224 //{"d0_blind_id_write_public_id", (void **) &qd0_blind_id_write_public_id},
225 {"d0_blind_id_authenticate_with_private_id_start", (void **) &qd0_blind_id_authenticate_with_private_id_start},
226 {"d0_blind_id_authenticate_with_private_id_challenge", (void **) &qd0_blind_id_authenticate_with_private_id_challenge},
227 {"d0_blind_id_authenticate_with_private_id_response", (void **) &qd0_blind_id_authenticate_with_private_id_response},
228 {"d0_blind_id_authenticate_with_private_id_verify", (void **) &qd0_blind_id_authenticate_with_private_id_verify},
229 {"d0_blind_id_fingerprint64_public_id", (void **) &qd0_blind_id_fingerprint64_public_id},
230 {"d0_blind_id_sessionkey_public_id", (void **) &qd0_blind_id_sessionkey_public_id},
231 {"d0_blind_id_INITIALIZE", (void **) &qd0_blind_id_INITIALIZE},
232 {"d0_blind_id_SHUTDOWN", (void **) &qd0_blind_id_SHUTDOWN},
233 {"d0_blind_id_util_sha256", (void **) &qd0_blind_id_util_sha256},
234 {"d0_blind_id_sign_with_private_id_sign", (void **) &qd0_blind_id_sign_with_private_id_sign},
235 {"d0_blind_id_sign_with_private_id_sign_detached", (void **) &qd0_blind_id_sign_with_private_id_sign_detached},
238 // end of d0_blind_id interface
240 static dllhandle_t d0_blind_id_dll = NULL;
241 static qboolean Crypto_OpenLibrary (void)
243 const char* dllnames [] =
246 "libd0_blind_id-0.dll",
247 #elif defined(MACOSX)
248 "libd0_blind_id.0.dylib",
250 "libd0_blind_id.so.0",
251 "libd0_blind_id.so", // FreeBSD
261 return Sys_LoadLibrary (dllnames, &d0_blind_id_dll, d0_blind_id_funcs);
264 static void Crypto_CloseLibrary (void)
266 Sys_UnloadLibrary (&d0_blind_id_dll);
271 #ifdef CRYPTO_RIJNDAEL_STATIC
273 #include <d0_blind_id/d0_rijndael.h>
275 #define d0_rijndael_dll 1
276 #define Crypto_Rijndael_OpenLibrary() true
277 #define Crypto_Rijndael_CloseLibrary()
279 #define qd0_rijndael_setup_encrypt d0_rijndael_setup_encrypt
280 #define qd0_rijndael_setup_decrypt d0_rijndael_setup_decrypt
281 #define qd0_rijndael_encrypt d0_rijndael_encrypt
282 #define qd0_rijndael_decrypt d0_rijndael_decrypt
286 // no need to do the #define dance here, as the upper part declares out macros either way
288 D0_EXPORT int (*qd0_rijndael_setup_encrypt) (unsigned long *rk, const unsigned char *key,
290 D0_EXPORT int (*qd0_rijndael_setup_decrypt) (unsigned long *rk, const unsigned char *key,
292 D0_EXPORT void (*qd0_rijndael_encrypt) (const unsigned long *rk, int nrounds,
293 const unsigned char plaintext[16], unsigned char ciphertext[16]);
294 D0_EXPORT void (*qd0_rijndael_decrypt) (const unsigned long *rk, int nrounds,
295 const unsigned char ciphertext[16], unsigned char plaintext[16]);
296 #define D0_RIJNDAEL_KEYLENGTH(keybits) ((keybits)/8)
297 #define D0_RIJNDAEL_RKLENGTH(keybits) ((keybits)/8+28)
298 #define D0_RIJNDAEL_NROUNDS(keybits) ((keybits)/32+6)
299 static dllfunction_t d0_rijndael_funcs[] =
301 {"d0_rijndael_setup_decrypt", (void **) &qd0_rijndael_setup_decrypt},
302 {"d0_rijndael_setup_encrypt", (void **) &qd0_rijndael_setup_encrypt},
303 {"d0_rijndael_decrypt", (void **) &qd0_rijndael_decrypt},
304 {"d0_rijndael_encrypt", (void **) &qd0_rijndael_encrypt},
307 // end of d0_blind_id interface
309 static dllhandle_t d0_rijndael_dll = NULL;
310 static qboolean Crypto_Rijndael_OpenLibrary (void)
312 const char* dllnames [] =
315 "libd0_rijndael-0.dll",
316 #elif defined(MACOSX)
317 "libd0_rijndael.0.dylib",
319 "libd0_rijndael.so.0",
320 "libd0_rijndael.so", // FreeBSD
330 return Sys_LoadLibrary (dllnames, &d0_rijndael_dll, d0_rijndael_funcs);
333 static void Crypto_Rijndael_CloseLibrary (void)
335 Sys_UnloadLibrary (&d0_rijndael_dll);
341 void sha256(unsigned char *out, const unsigned char *in, int n)
343 qd0_blind_id_util_sha256((char *) out, (const char *) in, n);
346 static size_t Crypto_LoadFile(const char *path, char *buf, size_t nmax)
352 f = FS_SysOpen(va(vabuf, sizeof(vabuf), "%s%s", fs_userdir, path), "rb", false);
354 f = FS_SysOpen(va(vabuf, sizeof(vabuf), "%s%s", fs_basedir, path), "rb", false);
357 n = FS_Read(f, buf, nmax);
364 static qboolean PutWithNul(char **data, size_t *len, const char *str)
366 // invariant: data points to insertion point
367 size_t l = strlen(str);
370 memcpy(*data, str, l+1);
376 static const char *GetUntilNul(const char **data, size_t *len)
378 // invariant: data points to next character to take
379 const char *data_save = *data;
392 p = (const char *) memchr(*data, 0, *len);
393 if(!p) // no terminating NUL
406 return (const char *) data_save;
413 static d0_blind_id_t *Crypto_ReadPublicKey(char *buf, size_t len)
415 d0_blind_id_t *pk = NULL;
418 if(Crypto_ParsePack(buf, len, FOURCC_D0PK, p, l, 2))
420 pk = qd0_blind_id_new();
422 if(qd0_blind_id_read_public_key(pk, p[0], l[0]))
423 if(qd0_blind_id_read_private_id_modulus(pk, p[1], l[1]))
427 qd0_blind_id_free(pk);
432 static qboolean Crypto_AddPrivateKey(d0_blind_id_t *pk, char *buf, size_t len)
436 if(Crypto_ParsePack(buf, len, FOURCC_D0SI, p, l, 1))
438 if(qd0_blind_id_read_private_id(pk, p[0], l[0]))
444 #define MAX_PUBKEYS 16
445 static d0_blind_id_t *pubkeys[MAX_PUBKEYS];
446 static char pubkeys_fp64[MAX_PUBKEYS][FP64_SIZE+1];
447 static qboolean pubkeys_havepriv[MAX_PUBKEYS];
448 static char pubkeys_priv_fp64[MAX_PUBKEYS][FP64_SIZE+1];
449 static char challenge_append[1400];
450 static size_t challenge_append_length;
452 static int keygen_i = -1;
453 static char keygen_buf[8192];
455 #define MAX_CRYPTOCONNECTS 16
456 #define CRYPTOCONNECT_NONE 0
457 #define CRYPTOCONNECT_PRECONNECT 1
458 #define CRYPTOCONNECT_CONNECT 2
459 #define CRYPTOCONNECT_RECONNECT 3
460 #define CRYPTOCONNECT_DUPLICATE 4
461 typedef struct server_cryptoconnect_s
464 lhnetaddress_t address;
468 server_cryptoconnect_t;
469 static server_cryptoconnect_t cryptoconnects[MAX_CRYPTOCONNECTS];
471 static int cdata_id = 0;
477 char challenge[2048];
478 char wantserver_idfp[FP64_SIZE+1];
479 qboolean wantserver_aes;
484 // crypto specific helpers
485 #define CDATA ((crypto_data_t *) crypto->data)
486 #define MAKE_CDATA if(!crypto->data) crypto->data = Z_Malloc(sizeof(crypto_data_t))
487 #define CLEAR_CDATA if(crypto->data) { if(CDATA->id) qd0_blind_id_free(CDATA->id); Z_Free(crypto->data); } crypto->data = NULL
489 static crypto_t *Crypto_ServerFindInstance(lhnetaddress_t *peeraddress, qboolean allow_create)
495 return NULL; // no support
497 for(i = 0; i < MAX_CRYPTOCONNECTS; ++i)
498 if(LHNETADDRESS_Compare(peeraddress, &cryptoconnects[i].address))
500 if(i < MAX_CRYPTOCONNECTS && (allow_create || cryptoconnects[i].crypto.data))
502 crypto = &cryptoconnects[i].crypto;
503 cryptoconnects[i].lasttime = realtime;
509 for(i = 1; i < MAX_CRYPTOCONNECTS; ++i)
510 if(cryptoconnects[i].lasttime < cryptoconnects[best].lasttime)
512 crypto = &cryptoconnects[best].crypto;
513 cryptoconnects[best].lasttime = realtime;
514 memcpy(&cryptoconnects[best].address, peeraddress, sizeof(cryptoconnects[best].address));
519 qboolean Crypto_ServerFinishInstance(crypto_t *out, crypto_t *crypto)
521 // no check needed here (returned pointers are only used in prefilled fields)
522 if(!crypto || !crypto->authenticated)
524 Con_Printf("Passed an invalid crypto connect instance\n");
525 memset(out, 0, sizeof(*out));
529 memcpy(out, crypto, sizeof(*out));
530 memset(crypto, 0, sizeof(crypto));
534 crypto_t *Crypto_ServerGetInstance(lhnetaddress_t *peeraddress)
536 // no check needed here (returned pointers are only used in prefilled fields)
537 return Crypto_ServerFindInstance(peeraddress, false);
540 typedef struct crypto_storedhostkey_s
542 struct crypto_storedhostkey_s *next;
545 char idfp[FP64_SIZE+1];
548 crypto_storedhostkey_t;
549 static crypto_storedhostkey_t *crypto_storedhostkey_hashtable[CRYPTO_HOSTKEY_HASHSIZE];
551 static void Crypto_InitHostKeys(void)
554 for(i = 0; i < CRYPTO_HOSTKEY_HASHSIZE; ++i)
555 crypto_storedhostkey_hashtable[i] = NULL;
558 static void Crypto_ClearHostKeys(void)
561 crypto_storedhostkey_t *hk, *hkn;
562 for(i = 0; i < CRYPTO_HOSTKEY_HASHSIZE; ++i)
564 for(hk = crypto_storedhostkey_hashtable[i]; hk; hk = hkn)
569 crypto_storedhostkey_hashtable[i] = NULL;
573 static qboolean Crypto_ClearHostKey(lhnetaddress_t *peeraddress)
577 crypto_storedhostkey_t **hkp;
578 qboolean found = false;
580 LHNETADDRESS_ToString(peeraddress, buf, sizeof(buf), 1);
581 hashindex = CRC_Block((const unsigned char *) buf, strlen(buf)) % CRYPTO_HOSTKEY_HASHSIZE;
582 for(hkp = &crypto_storedhostkey_hashtable[hashindex]; *hkp && LHNETADDRESS_Compare(&((*hkp)->addr), peeraddress); hkp = &((*hkp)->next));
586 crypto_storedhostkey_t *hk = *hkp;
595 static void Crypto_StoreHostKey(lhnetaddress_t *peeraddress, const char *keystring, qboolean complain)
599 crypto_storedhostkey_t *hk;
601 char idfp[FP64_SIZE+1];
607 // syntax of keystring:
608 // aeslevel id@key id@key ...
612 aeslevel = bound(0, *keystring - '0', 3);
613 while(*keystring && *keystring != ' ')
617 while(*keystring && keyid < 0)
620 const char *idstart, *idend, *keystart, *keyend;
621 ++keystring; // skip the space
623 while(*keystring && *keystring != ' ' && *keystring != '@')
629 keystart = keystring;
630 while(*keystring && *keystring != ' ')
634 if(idend - idstart == FP64_SIZE && keyend - keystart == FP64_SIZE)
636 for(keyid = 0; keyid < MAX_PUBKEYS; ++keyid)
638 if(!memcmp(pubkeys_fp64[keyid], keystart, FP64_SIZE))
640 memcpy(idfp, idstart, FP64_SIZE);
644 if(keyid >= MAX_PUBKEYS)
652 LHNETADDRESS_ToString(peeraddress, buf, sizeof(buf), 1);
653 hashindex = CRC_Block((const unsigned char *) buf, strlen(buf)) % CRYPTO_HOSTKEY_HASHSIZE;
654 for(hk = crypto_storedhostkey_hashtable[hashindex]; hk && LHNETADDRESS_Compare(&hk->addr, peeraddress); hk = hk->next);
660 if(hk->keyid != keyid || memcmp(hk->idfp, idfp, FP64_SIZE+1))
661 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);
662 if(hk->aeslevel > aeslevel)
663 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);
665 hk->aeslevel = max(aeslevel, hk->aeslevel);
669 // great, we did NOT have it yet
670 hk = (crypto_storedhostkey_t *) Z_Malloc(sizeof(*hk));
671 memcpy(&hk->addr, peeraddress, sizeof(hk->addr));
673 memcpy(hk->idfp, idfp, FP64_SIZE+1);
674 hk->next = crypto_storedhostkey_hashtable[hashindex];
675 hk->aeslevel = aeslevel;
676 crypto_storedhostkey_hashtable[hashindex] = hk;
679 qboolean Crypto_RetrieveHostKey(lhnetaddress_t *peeraddress, int *keyid, char *keyfp, size_t keyfplen, char *idfp, size_t idfplen, int *aeslevel)
683 crypto_storedhostkey_t *hk;
688 LHNETADDRESS_ToString(peeraddress, buf, sizeof(buf), 1);
689 hashindex = CRC_Block((const unsigned char *) buf, strlen(buf)) % CRYPTO_HOSTKEY_HASHSIZE;
690 for(hk = crypto_storedhostkey_hashtable[hashindex]; hk && LHNETADDRESS_Compare(&hk->addr, peeraddress); hk = hk->next);
698 strlcpy(keyfp, pubkeys_fp64[hk->keyid], keyfplen);
700 strlcpy(idfp, hk->idfp, idfplen);
702 *aeslevel = hk->aeslevel;
706 int Crypto_RetrieveLocalKey(int keyid, char *keyfp, size_t keyfplen, char *idfp, size_t idfplen) // return value: -1 if more to come, +1 if valid, 0 if end of list
708 if(keyid < 0 || keyid >= MAX_PUBKEYS)
717 strlcpy(keyfp, pubkeys_fp64[keyid], keyfplen);
719 if(pubkeys_havepriv[keyid])
720 strlcpy(idfp, pubkeys_priv_fp64[keyid], keyfplen);
725 // init/shutdown code
726 static void Crypto_BuildChallengeAppend(void)
728 char *p, *lengthptr, *startptr;
731 p = challenge_append;
732 n = sizeof(challenge_append);
733 Crypto_UnLittleLong(p, PROTOCOL_VLEN);
737 Crypto_UnLittleLong(p, 0);
740 Crypto_UnLittleLong(p, PROTOCOL_D0_BLIND_ID);
744 for(i = 0; i < MAX_PUBKEYS; ++i)
745 if(pubkeys_havepriv[i])
746 PutWithNul(&p, &n, pubkeys_fp64[i]);
747 PutWithNul(&p, &n, "");
748 for(i = 0; i < MAX_PUBKEYS; ++i)
749 if(!pubkeys_havepriv[i] && pubkeys[i])
750 PutWithNul(&p, &n, pubkeys_fp64[i]);
751 Crypto_UnLittleLong(lengthptr, p - startptr);
752 challenge_append_length = p - challenge_append;
755 static void Crypto_LoadKeys(void)
763 // note: we are just a CLIENT
765 // PUBLIC KEYS to accept (including modulus)
766 // PRIVATE KEY of user
768 crypto_idstring = NULL;
769 dpsnprintf(crypto_idstring_buf, sizeof(crypto_idstring_buf), "%d", d0_rijndael_dll ? crypto_aeslevel.integer : 0);
770 for(i = 0; i < MAX_PUBKEYS; ++i)
772 memset(pubkeys_fp64[i], 0, sizeof(pubkeys_fp64[i]));
773 memset(pubkeys_priv_fp64[i], 0, sizeof(pubkeys_fp64[i]));
774 pubkeys_havepriv[i] = false;
775 len = Crypto_LoadFile(va(vabuf, sizeof(vabuf), "key_%d.d0pk", i), buf, sizeof(buf));
776 if((pubkeys[i] = Crypto_ReadPublicKey(buf, len)))
779 if(qd0_blind_id_fingerprint64_public_key(pubkeys[i], pubkeys_fp64[i], &len2)) // keeps final NUL
781 Con_Printf("Loaded public key key_%d.d0pk (fingerprint: %s)\n", i, pubkeys_fp64[i]);
782 len = Crypto_LoadFile(va(vabuf, sizeof(vabuf), "key_%d.d0si", i), buf, sizeof(buf));
785 if(Crypto_AddPrivateKey(pubkeys[i], buf, len))
788 if(qd0_blind_id_fingerprint64_public_id(pubkeys[i], pubkeys_priv_fp64[i], &len2)) // keeps final NUL
790 Con_Printf("Loaded private ID key_%d.d0si for key_%d.d0pk (public key fingerprint: %s)\n", i, i, pubkeys_priv_fp64[i]);
791 pubkeys_havepriv[i] = true;
792 strlcat(crypto_idstring_buf, va(vabuf, sizeof(vabuf), " %s@%s", pubkeys_priv_fp64[i], pubkeys_fp64[i]), sizeof(crypto_idstring_buf));
796 // can't really happen
797 // but nothing leaked here
804 // can't really happen
805 qd0_blind_id_free(pubkeys[i]);
810 crypto_idstring = crypto_idstring_buf;
813 Crypto_BuildChallengeAppend();
815 // find a good prefix length for all the keys we know (yes, algorithm is not perfect yet, may yield too long prefix length)
816 crypto_keyfp_recommended_length = 0;
817 memset(buf+256, 0, MAX_PUBKEYS + MAX_PUBKEYS);
818 while(crypto_keyfp_recommended_length < FP64_SIZE)
821 for(i = 0; i < MAX_PUBKEYS; ++i)
825 ++buf[(unsigned char) pubkeys_fp64[i][crypto_keyfp_recommended_length]];
826 if(pubkeys_havepriv[i])
827 if(!buf[256 + MAX_PUBKEYS + i])
828 ++buf[(unsigned char) pubkeys_priv_fp64[i][crypto_keyfp_recommended_length]];
830 for(i = 0; i < MAX_PUBKEYS; ++i)
834 if(buf[(unsigned char) pubkeys_fp64[i][crypto_keyfp_recommended_length]] < 2)
836 if(pubkeys_havepriv[i])
837 if(!buf[256 + MAX_PUBKEYS + i])
838 if(buf[(unsigned char) pubkeys_priv_fp64[i][crypto_keyfp_recommended_length]] < 2)
839 buf[256 + MAX_PUBKEYS + i] = 1;
841 ++crypto_keyfp_recommended_length;
842 for(i = 0; i < MAX_PUBKEYS; ++i)
847 if(pubkeys_havepriv[i])
848 if(!buf[256 + MAX_PUBKEYS + i])
854 if(crypto_keyfp_recommended_length < 7)
855 crypto_keyfp_recommended_length = 7;
858 static void Crypto_UnloadKeys(void)
862 for(i = 0; i < MAX_PUBKEYS; ++i)
865 qd0_blind_id_free(pubkeys[i]);
867 pubkeys_havepriv[i] = false;
868 memset(pubkeys_fp64[i], 0, sizeof(pubkeys_fp64[i]));
869 memset(pubkeys_priv_fp64[i], 0, sizeof(pubkeys_fp64[i]));
870 challenge_append_length = 0;
872 crypto_idstring = NULL;
875 void Crypto_Shutdown(void)
881 Thread_DestroyMutex(crypto_mutex);
884 Crypto_Rijndael_CloseLibrary();
889 for(i = 0; i < MAX_CRYPTOCONNECTS; ++i)
891 crypto = &cryptoconnects[i].crypto;
894 memset(cryptoconnects, 0, sizeof(cryptoconnects));
895 crypto = &cls.crypto;
900 qd0_blind_id_SHUTDOWN();
902 Crypto_CloseLibrary();
906 void Crypto_Init(void)
908 if(!Crypto_OpenLibrary())
911 if (Thread_HasThreads())
912 crypto_mutex = Thread_CreateMutex();
914 if(!qd0_blind_id_INITIALIZE())
916 Crypto_Rijndael_CloseLibrary();
917 Crypto_CloseLibrary();
918 Con_Printf("libd0_blind_id initialization FAILED, cryptography support has been disabled\n");
922 Crypto_Rijndael_OpenLibrary(); // if this fails, it's uncritical
924 Crypto_InitHostKeys();
929 qboolean Crypto_Available(void)
937 static void Crypto_KeyGen_Finished(int code, size_t length_received, unsigned char *buffer, void *cbdata)
941 static char buf[8192];
942 static char buf2[8192];
943 size_t bufsize, buf2size;
945 d0_blind_id_t *ctx, *ctx2;
950 if (crypto_mutex) Thread_LockMutex(crypto_mutex);
954 Con_Print("libd0_blind_id DLL not found, this command is inactive.\n");
956 if (crypto_mutex) Thread_UnlockMutex(crypto_mutex);
960 if(keygen_i >= MAX_PUBKEYS || !pubkeys[keygen_i])
962 Con_Printf("overflow of keygen_i\n");
964 if (crypto_mutex) Thread_UnlockMutex(crypto_mutex);
969 Con_Printf("Unexpected response from keygen server:\n");
970 Com_HexDumpToConsole(buffer, length_received);
971 if (crypto_mutex) Thread_UnlockMutex(crypto_mutex);
974 if(!Crypto_ParsePack((const char *) buffer, length_received, FOURCC_D0IR, p, l, 1))
976 if(length_received >= 5 && Crypto_LittleLong((const char *) buffer) == FOURCC_D0ER)
978 Con_Printf("Error response from keygen server: %.*s\n", (int)(length_received - 5), buffer + 5);
982 Con_Printf("Invalid response from keygen server:\n");
983 Com_HexDumpToConsole(buffer, length_received);
986 if (crypto_mutex) Thread_UnlockMutex(crypto_mutex);
989 if(!qd0_blind_id_finish_private_id_request(pubkeys[keygen_i], p[0], l[0]))
991 Con_Printf("d0_blind_id_finish_private_id_request failed\n");
993 if (crypto_mutex) Thread_UnlockMutex(crypto_mutex);
997 // verify the key we just got (just in case)
998 ctx = qd0_blind_id_new();
1001 Con_Printf("d0_blind_id_new failed\n");
1003 if (crypto_mutex) Thread_UnlockMutex(crypto_mutex);
1006 ctx2 = qd0_blind_id_new();
1009 Con_Printf("d0_blind_id_new failed\n");
1010 qd0_blind_id_free(ctx);
1012 if (crypto_mutex) Thread_UnlockMutex(crypto_mutex);
1015 if(!qd0_blind_id_copy(ctx, pubkeys[keygen_i]))
1017 Con_Printf("d0_blind_id_copy failed\n");
1018 qd0_blind_id_free(ctx);
1019 qd0_blind_id_free(ctx2);
1021 if (crypto_mutex) Thread_UnlockMutex(crypto_mutex);
1024 if(!qd0_blind_id_copy(ctx2, pubkeys[keygen_i]))
1026 Con_Printf("d0_blind_id_copy failed\n");
1027 qd0_blind_id_free(ctx);
1028 qd0_blind_id_free(ctx2);
1030 if (crypto_mutex) Thread_UnlockMutex(crypto_mutex);
1033 bufsize = sizeof(buf);
1034 if(!qd0_blind_id_authenticate_with_private_id_start(ctx, 1, 1, "hello world", 11, buf, &bufsize))
1036 Con_Printf("d0_blind_id_authenticate_with_private_id_start failed\n");
1037 qd0_blind_id_free(ctx);
1038 qd0_blind_id_free(ctx2);
1040 if (crypto_mutex) Thread_UnlockMutex(crypto_mutex);
1043 buf2size = sizeof(buf2);
1044 if(!qd0_blind_id_authenticate_with_private_id_challenge(ctx2, 1, 1, buf, bufsize, buf2, &buf2size, &status) || !status)
1046 Con_Printf("d0_blind_id_authenticate_with_private_id_challenge failed (server does not have the requested private key)\n");
1047 qd0_blind_id_free(ctx);
1048 qd0_blind_id_free(ctx2);
1050 if (crypto_mutex) Thread_UnlockMutex(crypto_mutex);
1053 bufsize = sizeof(buf);
1054 if(!qd0_blind_id_authenticate_with_private_id_response(ctx, buf2, buf2size, buf, &bufsize))
1056 Con_Printf("d0_blind_id_authenticate_with_private_id_response failed\n");
1057 qd0_blind_id_free(ctx);
1058 qd0_blind_id_free(ctx2);
1060 if (crypto_mutex) Thread_UnlockMutex(crypto_mutex);
1063 buf2size = sizeof(buf2);
1064 if(!qd0_blind_id_authenticate_with_private_id_verify(ctx2, buf, bufsize, buf2, &buf2size, &status) || !status)
1066 Con_Printf("d0_blind_id_authenticate_with_private_id_verify failed (server does not have the requested private key)\n");
1067 qd0_blind_id_free(ctx);
1068 qd0_blind_id_free(ctx2);
1070 if (crypto_mutex) Thread_UnlockMutex(crypto_mutex);
1073 qd0_blind_id_free(ctx);
1074 qd0_blind_id_free(ctx2);
1076 // we have a valid key now!
1077 // make the rest of crypto.c know that
1079 if(qd0_blind_id_fingerprint64_public_id(pubkeys[keygen_i], pubkeys_priv_fp64[keygen_i], &len2)) // keeps final NUL
1081 Con_Printf("Received private ID key_%d.d0pk (public key fingerprint: %s)\n", keygen_i, pubkeys_priv_fp64[keygen_i]);
1082 pubkeys_havepriv[keygen_i] = true;
1083 strlcat(crypto_idstring_buf, va(vabuf, sizeof(vabuf), " %s@%s", pubkeys_priv_fp64[keygen_i], pubkeys_fp64[keygen_i]), sizeof(crypto_idstring_buf));
1084 crypto_idstring = crypto_idstring_buf;
1085 Crypto_BuildChallengeAppend();
1087 // write the key to disk
1090 if(!qd0_blind_id_write_private_id(pubkeys[keygen_i], buf, &l[0]))
1092 Con_Printf("d0_blind_id_write_private_id failed\n");
1094 if (crypto_mutex) Thread_UnlockMutex(crypto_mutex);
1097 if(!(buf2size = Crypto_UnParsePack(buf2, sizeof(buf2), FOURCC_D0SI, p, l, 1)))
1099 Con_Printf("Crypto_UnParsePack failed\n");
1101 if (crypto_mutex) Thread_UnlockMutex(crypto_mutex);
1107 FS_CreatePath(va(vabuf, sizeof(vabuf), "%skey_%d.d0si", fs_userdir, keygen_i));
1108 f = FS_SysOpen(va(vabuf, sizeof(vabuf), "%skey_%d.d0si", fs_userdir, keygen_i), "wb", false);
1112 FS_CreatePath(va(vabuf, sizeof(vabuf), "%skey_%d.d0si", fs_basedir, keygen_i));
1113 f = FS_SysOpen(va(vabuf, sizeof(vabuf), "%skey_%d.d0si", fs_basedir, keygen_i), "wb", false);
1117 Con_Printf("Cannot open key_%d.d0si\n", keygen_i);
1119 if (crypto_mutex) Thread_UnlockMutex(crypto_mutex);
1122 FS_Write(f, buf2, buf2size);
1125 Con_Printf("Saved to key_%d.d0si\n", keygen_i);
1127 if (crypto_mutex) Thread_UnlockMutex(crypto_mutex);
1130 static void Crypto_KeyGen_f(void)
1135 static char buf[8192];
1136 static char buf2[8192];
1137 size_t buf2l, buf2pos;
1138 if(!d0_blind_id_dll)
1140 Con_Print("libd0_blind_id DLL not found, this command is inactive.\n");
1145 Con_Printf("usage:\n%s id url\n", Cmd_Argv(0));
1148 if (crypto_mutex) Thread_LockMutex(crypto_mutex);
1149 i = atoi(Cmd_Argv(1));
1152 Con_Printf("there is no public key %d\n", i);
1153 if (crypto_mutex) Thread_UnlockMutex(crypto_mutex);
1156 if(pubkeys_havepriv[i])
1158 Con_Printf("there is already a private key for %d\n", i);
1159 if (crypto_mutex) Thread_UnlockMutex(crypto_mutex);
1164 Con_Printf("there is already a keygen run on the way\n");
1165 if (crypto_mutex) Thread_UnlockMutex(crypto_mutex);
1169 if(!qd0_blind_id_generate_private_id_start(pubkeys[keygen_i]))
1171 Con_Printf("d0_blind_id_start failed\n");
1173 if (crypto_mutex) Thread_UnlockMutex(crypto_mutex);
1178 if(!qd0_blind_id_generate_private_id_request(pubkeys[keygen_i], buf, &l[0]))
1180 Con_Printf("d0_blind_id_generate_private_id_request failed\n");
1182 if (crypto_mutex) Thread_UnlockMutex(crypto_mutex);
1185 buf2pos = strlen(Cmd_Argv(2));
1186 memcpy(buf2, Cmd_Argv(2), buf2pos);
1187 if(!(buf2l = Crypto_UnParsePack(buf2 + buf2pos, sizeof(buf2) - buf2pos - 1, FOURCC_D0IQ, p, l, 1)))
1189 Con_Printf("Crypto_UnParsePack failed\n");
1191 if (crypto_mutex) Thread_UnlockMutex(crypto_mutex);
1194 if(!(buf2l = base64_encode((unsigned char *) (buf2 + buf2pos), buf2l, sizeof(buf2) - buf2pos - 1)))
1196 Con_Printf("base64_encode failed\n");
1198 if (crypto_mutex) Thread_UnlockMutex(crypto_mutex);
1203 if(!Curl_Begin_ToMemory(buf2, 0, (unsigned char *) keygen_buf, sizeof(keygen_buf), Crypto_KeyGen_Finished, NULL))
1205 Con_Printf("curl failed\n");
1207 if (crypto_mutex) Thread_UnlockMutex(crypto_mutex);
1210 Con_Printf("key generation in progress\n");
1211 if (crypto_mutex) Thread_UnlockMutex(crypto_mutex);
1216 static void Crypto_Reload_f(void)
1218 Crypto_ClearHostKeys();
1219 Crypto_UnloadKeys();
1223 static void Crypto_Keys_f(void)
1226 if(!d0_blind_id_dll)
1228 Con_Print("libd0_blind_id DLL not found, this command is inactive.\n");
1231 for(i = 0; i < MAX_PUBKEYS; ++i)
1235 Con_Printf("%2d: public key key_%d.d0pk (fingerprint: %s)\n", i, i, pubkeys_fp64[i]);
1236 if(pubkeys_havepriv[i])
1237 Con_Printf(" private ID key_%d.d0si (public key fingerprint: %s)\n", i, pubkeys_priv_fp64[i]);
1242 static void Crypto_HostKeys_f(void)
1245 crypto_storedhostkey_t *hk;
1248 if(!d0_blind_id_dll)
1250 Con_Print("libd0_blind_id DLL not found, this command is inactive.\n");
1253 for(i = 0; i < CRYPTO_HOSTKEY_HASHSIZE; ++i)
1255 for(hk = crypto_storedhostkey_hashtable[i]; hk; hk = hk->next)
1257 LHNETADDRESS_ToString(&hk->addr, buf, sizeof(buf), 1);
1258 Con_Printf("%d %s@%.*s %s\n",
1261 crypto_keyfp_recommended_length, pubkeys_fp64[hk->keyid],
1267 static void Crypto_HostKey_Clear_f(void)
1269 lhnetaddress_t addr;
1272 if(!d0_blind_id_dll)
1274 Con_Print("libd0_blind_id DLL not found, this command is inactive.\n");
1278 for(i = 1; i < Cmd_Argc(); ++i)
1280 LHNETADDRESS_FromString(&addr, Cmd_Argv(i), 26000);
1281 if(Crypto_ClearHostKey(&addr))
1283 Con_Printf("cleared host key for %s\n", Cmd_Argv(i));
1288 void Crypto_Init_Commands(void)
1292 Cmd_AddCommand("crypto_reload", Crypto_Reload_f, "reloads cryptographic keys");
1293 Cmd_AddCommand("crypto_keygen", Crypto_KeyGen_f, "generates and saves a cryptographic key");
1294 Cmd_AddCommand("crypto_keys", Crypto_Keys_f, "lists the loaded keys");
1295 Cmd_AddCommand("crypto_hostkeys", Crypto_HostKeys_f, "lists the cached host keys");
1296 Cmd_AddCommand("crypto_hostkey_clear", Crypto_HostKey_Clear_f, "clears a cached host key");
1297 Cvar_RegisterVariable(&crypto_developer);
1299 Cvar_RegisterVariable(&crypto_aeslevel);
1301 crypto_aeslevel.integer = 0; // make sure
1302 Cvar_RegisterVariable(&crypto_servercpupercent);
1303 Cvar_RegisterVariable(&crypto_servercpumaxtime);
1304 Cvar_RegisterVariable(&crypto_servercpudebug);
1310 static void aescpy(unsigned char *key, const unsigned char *iv, unsigned char *dst, const unsigned char *src, size_t len)
1312 const unsigned char *xorpos = iv;
1313 unsigned char xorbuf[16];
1314 unsigned long rk[D0_RIJNDAEL_RKLENGTH(DHKEY_SIZE * 8)];
1316 qd0_rijndael_setup_encrypt(rk, key, DHKEY_SIZE * 8);
1319 for(i = 0; i < 16; ++i)
1320 xorbuf[i] = src[i] ^ xorpos[i];
1321 qd0_rijndael_encrypt(rk, D0_RIJNDAEL_NROUNDS(DHKEY_SIZE * 8), xorbuf, dst);
1329 for(i = 0; i < len; ++i)
1330 xorbuf[i] = src[i] ^ xorpos[i];
1332 xorbuf[i] = xorpos[i];
1333 qd0_rijndael_encrypt(rk, D0_RIJNDAEL_NROUNDS(DHKEY_SIZE * 8), xorbuf, dst);
1336 static void seacpy(unsigned char *key, const unsigned char *iv, unsigned char *dst, const unsigned char *src, size_t len)
1338 const unsigned char *xorpos = iv;
1339 unsigned char xorbuf[16];
1340 unsigned long rk[D0_RIJNDAEL_RKLENGTH(DHKEY_SIZE * 8)];
1342 qd0_rijndael_setup_decrypt(rk, key, DHKEY_SIZE * 8);
1345 qd0_rijndael_decrypt(rk, D0_RIJNDAEL_NROUNDS(DHKEY_SIZE * 8), src, xorbuf);
1346 for(i = 0; i < 16; ++i)
1347 dst[i] = xorbuf[i] ^ xorpos[i];
1355 qd0_rijndael_decrypt(rk, D0_RIJNDAEL_NROUNDS(DHKEY_SIZE * 8), src, xorbuf);
1356 for(i = 0; i < len; ++i)
1357 dst[i] = xorbuf[i] ^ xorpos[i];
1361 // NOTE: we MUST avoid the following begins of the packet:
1362 // 1. 0xFF, 0xFF, 0xFF, 0xFF
1363 // 2. 0x80, 0x00, length/256, length%256
1364 // this luckily does NOT affect AES mode, where the first byte always is in the range from 0x00 to 0x0F
1365 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)
1367 unsigned char h[32];
1369 if(crypto->authenticated)
1373 // AES packet = 1 byte length overhead, 15 bytes from HMAC-SHA-256, data, 0..15 bytes padding
1374 // 15 bytes HMAC-SHA-256 (112bit) suffice as the attacker can't do more than forge a random-looking packet
1375 // HMAC is needed to not leak information about packet content
1376 if(developer_networking.integer)
1378 Con_Print("To be encrypted:\n");
1379 Com_HexDumpToConsole((const unsigned char *) data_src, len_src);
1381 if(len_src + 32 > len || !HMAC_SHA256_32BYTES(h, (const unsigned char *) data_src, len_src, crypto->dhkey, DHKEY_SIZE))
1383 Con_Printf("Crypto_EncryptPacket failed (not enough space: %d bytes in, %d bytes out)\n", (int) len_src, (int) len);
1386 *len_dst = ((len_src + 15) / 16) * 16 + 16; // add 16 for HMAC, then round to 16-size for AES
1387 ((unsigned char *) data_dst)[0] = *len_dst - len_src;
1388 memcpy(((unsigned char *) data_dst)+1, h, 15);
1389 aescpy(crypto->dhkey, (const unsigned char *) data_dst, ((unsigned char *) data_dst) + 16, (const unsigned char *) data_src, len_src);
1394 // HMAC packet = 16 bytes HMAC-SHA-256 (truncated to 128 bits), data
1395 if(len_src + 16 > len || !HMAC_SHA256_32BYTES(h, (const unsigned char *) data_src, len_src, crypto->dhkey, DHKEY_SIZE))
1397 Con_Printf("Crypto_EncryptPacket failed (not enough space: %d bytes in, %d bytes out)\n", (int) len_src, (int) len);
1400 *len_dst = len_src + 16;
1401 memcpy(data_dst, h, 16);
1402 memcpy(((unsigned char *) data_dst) + 16, (unsigned char *) data_src, len_src);
1404 // handle the "avoid" conditions:
1405 i = BuffBigLong((unsigned char *) data_dst);
1407 (i == (int)0xFFFFFFFF) // avoid QW control packet
1409 (i == (int)0x80000000 + (int)*len_dst) // avoid NQ control packet
1411 *(unsigned char *)data_dst ^= 0x80; // this will ALWAYS fix it
1422 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)
1424 unsigned char h[32];
1427 // silently handle non-crypto packets
1428 i = BuffBigLong((unsigned char *) data_src);
1430 (i == (int)0xFFFFFFFF) // avoid QW control packet
1432 (i == (int)0x80000000 + (int)len_src) // avoid NQ control packet
1436 if(crypto->authenticated)
1440 if(len_src < 16 || ((len_src - 16) % 16))
1442 Con_Printf("Crypto_DecryptPacket failed (not enough space: %d bytes in, %d bytes out)\n", (int) len_src, (int) len);
1445 *len_dst = len_src - ((unsigned char *) data_src)[0];
1446 if(len < *len_dst || *len_dst > len_src - 16)
1448 Con_Printf("Crypto_DecryptPacket failed (not enough space: %d bytes in, %d->%d bytes out)\n", (int) len_src, (int) *len_dst, (int) len);
1451 seacpy(crypto->dhkey, (unsigned char *) data_src, (unsigned char *) data_dst, ((const unsigned char *) data_src) + 16, *len_dst);
1453 if(!HMAC_SHA256_32BYTES(h, (const unsigned char *) data_dst, *len_dst, crypto->dhkey, DHKEY_SIZE))
1455 Con_Printf("HMAC fail\n");
1458 if(memcmp(((const unsigned char *) data_src)+1, h, 15)) // ignore first byte, used for length
1460 Con_Printf("HMAC mismatch\n");
1463 if(developer_networking.integer)
1465 Con_Print("Decrypted:\n");
1466 Com_HexDumpToConsole((const unsigned char *) data_dst, *len_dst);
1468 return data_dst; // no need to copy
1474 Con_Printf("Crypto_DecryptPacket failed (not enough space: %d bytes in, %d bytes out)\n", (int) len_src, (int) len);
1477 *len_dst = len_src - 16;
1480 Con_Printf("Crypto_DecryptPacket failed (not enough space: %d bytes in, %d->%d bytes out)\n", (int) len_src, (int) *len_dst, (int) len);
1483 //memcpy(data_dst, data_src + 16, *len_dst);
1484 if(!HMAC_SHA256_32BYTES(h, ((const unsigned char *) data_src) + 16, *len_dst, crypto->dhkey, DHKEY_SIZE))
1486 Con_Printf("HMAC fail\n");
1487 Com_HexDumpToConsole((const unsigned char *) data_src, len_src);
1491 if(memcmp((const unsigned char *) data_src, h, 16)) // ignore first byte, used for length
1493 // undo the "avoid conditions"
1495 (i == (int)0x7FFFFFFF) // avoided QW control packet
1497 (i == (int)0x00000000 + (int)len_src) // avoided NQ control packet
1500 // do the avoidance on the hash too
1502 if(memcmp((const unsigned char *) data_src, h, 16)) // ignore first byte, used for length
1504 Con_Printf("HMAC mismatch\n");
1505 Com_HexDumpToConsole((const unsigned char *) data_src, len_src);
1511 Con_Printf("HMAC mismatch\n");
1512 Com_HexDumpToConsole((const unsigned char *) data_src, len_src);
1516 return ((const unsigned char *) data_src) + 16; // no need to copy, so data_dst is not used
1527 const char *Crypto_GetInfoResponseDataString(void)
1529 crypto_idstring_buf[0] = '0' + crypto_aeslevel.integer;
1530 return crypto_idstring;
1534 qboolean Crypto_ServerAppendToChallenge(const char *data_in, size_t len_in, char *data_out, size_t *len_out, size_t maxlen_out)
1536 // cheap op, all is precomputed
1537 if(!d0_blind_id_dll)
1538 return false; // no support
1540 if(maxlen_out <= *len_out + challenge_append_length)
1542 memcpy(data_out + *len_out, challenge_append, challenge_append_length);
1543 *len_out += challenge_append_length;
1547 static int Crypto_ServerError(char *data_out, size_t *len_out, const char *msg, const char *msg_client)
1551 Con_DPrintf("rejecting client: %s\n", msg);
1553 dpsnprintf(data_out, *len_out, "reject %s", msg_client);
1554 *len_out = strlen(data_out);
1555 return CRYPTO_DISCARD;
1558 static int Crypto_SoftServerError(char *data_out, size_t *len_out, const char *msg)
1561 Con_DPrintf("%s\n", msg);
1562 return CRYPTO_DISCARD;
1565 static int Crypto_ServerParsePacket_Internal(const char *data_in, size_t len_in, char *data_out, size_t *len_out, lhnetaddress_t *peeraddress)
1567 // if "connect": reject if in the middle of crypto handshake
1568 crypto_t *crypto = NULL;
1569 char *data_out_p = data_out;
1570 const char *string = data_in;
1574 char infostringvalue[MAX_INPUTLINE];
1577 if(!d0_blind_id_dll)
1578 return CRYPTO_NOMATCH; // no support
1580 if (len_in > 8 && !memcmp(string, "connect\\", 8) && d0_rijndael_dll && crypto_aeslevel.integer >= 3)
1584 // sorry, we have to verify the challenge here to not reflect network spam
1586 if (!(s = InfoString_GetValue(string + 4, "challenge", infostringvalue, sizeof(infostringvalue))))
1587 return CRYPTO_NOMATCH; // will be later accepted if encryption was set up
1588 // validate the challenge
1589 for (i = 0;i < MAX_CHALLENGES;i++)
1590 if(challenge[i].time > 0)
1591 if (!LHNETADDRESS_Compare(peeraddress, &challenge[i].address) && !strcmp(challenge[i].string, s))
1593 // if the challenge is not recognized, drop the packet
1594 if (i == MAX_CHALLENGES) // challenge mismatch is silent
1595 return CRYPTO_DISCARD; // pre-challenge: rather be silent
1597 crypto = Crypto_ServerFindInstance(peeraddress, false);
1598 if(!crypto || !crypto->authenticated)
1599 return Crypto_ServerError(data_out, len_out, "This server requires authentication and encryption to be supported by your client", NULL);
1601 else if(len_in > 5 && !memcmp(string, "d0pk\\", 5) && ((LHNETADDRESS_GetAddressType(peeraddress) == LHNETADDRESSTYPE_LOOP) || sv_public.integer > -3))
1603 const char *cnt, *s, *p;
1605 int clientid = -1, serverid = -1;
1606 cnt = InfoString_GetValue(string + 4, "id", infostringvalue, sizeof(infostringvalue));
1607 id = (cnt ? atoi(cnt) : -1);
1608 cnt = InfoString_GetValue(string + 4, "cnt", infostringvalue, sizeof(infostringvalue));
1610 return CRYPTO_DISCARD; // pre-challenge: rather be silent
1611 GetUntilNul(&data_in, &len_in);
1613 return CRYPTO_DISCARD; // pre-challenge: rather be silent
1614 if(!strcmp(cnt, "0"))
1617 if (!(s = InfoString_GetValue(string + 4, "challenge", infostringvalue, sizeof(infostringvalue))))
1618 return CRYPTO_DISCARD; // pre-challenge: rather be silent
1619 // validate the challenge
1620 for (i = 0;i < MAX_CHALLENGES;i++)
1621 if(challenge[i].time > 0)
1622 if (!LHNETADDRESS_Compare(peeraddress, &challenge[i].address) && !strcmp(challenge[i].string, s))
1624 // if the challenge is not recognized, drop the packet
1625 if (i == MAX_CHALLENGES) // challenge mismatch is silent
1626 return CRYPTO_DISCARD; // pre-challenge: rather be silent
1628 if (!(s = InfoString_GetValue(string + 4, "aeslevel", infostringvalue, sizeof(infostringvalue))))
1629 aeslevel = 0; // not supported
1631 aeslevel = bound(0, atoi(s), 3);
1632 switch(bound(0, d0_rijndael_dll ? crypto_aeslevel.integer : 0, 3))
1634 default: // dummy, never happens, but to make gcc happy...
1637 return Crypto_ServerError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)", NULL);
1641 aes = (aeslevel >= 2);
1644 aes = (aeslevel >= 1);
1648 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);
1653 p = GetUntilNul(&data_in, &len_in);
1656 for(i = 0; i < MAX_PUBKEYS; ++i)
1659 if(!strcmp(p, pubkeys_fp64[i]))
1660 if(pubkeys_havepriv[i])
1665 return Crypto_ServerError(data_out, len_out, "Invalid server key", NULL);
1667 p = GetUntilNul(&data_in, &len_in);
1670 for(i = 0; i < MAX_PUBKEYS; ++i)
1673 if(!strcmp(p, pubkeys_fp64[i]))
1678 return Crypto_ServerError(data_out, len_out, "Invalid client key", NULL);
1681 crypto = Crypto_ServerFindInstance(peeraddress, true);
1683 return Crypto_ServerError(data_out, len_out, "Could not create a crypto connect instance", NULL);
1685 CDATA->cdata_id = id;
1686 CDATA->s = serverid;
1687 CDATA->c = clientid;
1688 memset(crypto->dhkey, 0, sizeof(crypto->dhkey));
1689 CDATA->challenge[0] = 0;
1690 crypto->client_keyfp[0] = 0;
1691 crypto->client_idfp[0] = 0;
1692 crypto->server_keyfp[0] = 0;
1693 crypto->server_idfp[0] = 0;
1694 crypto->use_aes = aes != 0;
1698 // I am the server, and my key is ok... so let's set server_keyfp and server_idfp
1699 strlcpy(crypto->server_keyfp, pubkeys_fp64[CDATA->s], sizeof(crypto->server_keyfp));
1700 strlcpy(crypto->server_idfp, pubkeys_priv_fp64[CDATA->s], sizeof(crypto->server_idfp));
1703 CDATA->id = qd0_blind_id_new();
1707 return Crypto_ServerError(data_out, len_out, "d0_blind_id_new failed", "Internal error");
1709 if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->s]))
1712 return Crypto_ServerError(data_out, len_out, "d0_blind_id_copy failed", "Internal error");
1714 PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\1\\id\\%d\\aes\\%d", CDATA->cdata_id, crypto->use_aes));
1715 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
1718 return Crypto_ServerError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_start failed", "Internal error");
1720 CDATA->next_step = 2;
1721 data_out_p += *len_out;
1722 *len_out = data_out_p - data_out;
1723 return CRYPTO_DISCARD;
1725 else if(CDATA->c >= 0)
1728 CDATA->id = qd0_blind_id_new();
1732 return Crypto_ServerError(data_out, len_out, "d0_blind_id_new failed", "Internal error");
1734 if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->c]))
1737 return Crypto_ServerError(data_out, len_out, "d0_blind_id_copy failed", "Internal error");
1739 PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\5\\id\\%d\\aes\\%d", CDATA->cdata_id, crypto->use_aes));
1740 if(!qd0_blind_id_authenticate_with_private_id_challenge(CDATA->id, true, false, data_in, len_in, data_out_p, len_out, &status))
1743 return Crypto_ServerError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_challenge failed", "Internal error");
1745 CDATA->next_step = 6;
1746 data_out_p += *len_out;
1747 *len_out = data_out_p - data_out;
1748 return CRYPTO_DISCARD;
1753 return Crypto_ServerError(data_out, len_out, "Missing client and server key", NULL);
1756 else if(!strcmp(cnt, "2"))
1759 crypto = Crypto_ServerFindInstance(peeraddress, false);
1761 return CRYPTO_NOMATCH; // pre-challenge, rather be silent
1763 if(CDATA->cdata_id != id)
1764 return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
1765 if(CDATA->next_step != 2)
1766 return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
1768 PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\3\\id\\%d", CDATA->cdata_id));
1769 if(!qd0_blind_id_authenticate_with_private_id_response(CDATA->id, data_in, len_in, data_out_p, len_out))
1772 return Crypto_ServerError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_response failed", "Internal error");
1774 fpbuflen = DHKEY_SIZE;
1775 if(!qd0_blind_id_sessionkey_public_id(CDATA->id, (char *) crypto->dhkey, &fpbuflen))
1778 return Crypto_ServerError(data_out, len_out, "d0_blind_id_sessionkey_public_id failed", "Internal error");
1782 if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->c]))
1785 return Crypto_ServerError(data_out, len_out, "d0_blind_id_copy failed", "Internal error");
1787 CDATA->next_step = 4;
1791 // session key is FINISHED (no server part is to be expected)! By this, all keys are set up
1792 crypto->authenticated = true;
1793 CDATA->next_step = 0;
1795 data_out_p += *len_out;
1796 *len_out = data_out_p - data_out;
1797 return CRYPTO_DISCARD;
1799 else if(!strcmp(cnt, "4"))
1801 crypto = Crypto_ServerFindInstance(peeraddress, false);
1803 return CRYPTO_NOMATCH; // pre-challenge, rather be silent
1805 if(CDATA->cdata_id != id)
1806 return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
1807 if(CDATA->next_step != 4)
1808 return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
1809 PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\5\\id\\%d", CDATA->cdata_id));
1810 if(!qd0_blind_id_authenticate_with_private_id_challenge(CDATA->id, true, false, data_in, len_in, data_out_p, len_out, &status))
1813 return Crypto_ServerError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_challenge failed", "Internal error");
1815 CDATA->next_step = 6;
1816 data_out_p += *len_out;
1817 *len_out = data_out_p - data_out;
1818 return CRYPTO_DISCARD;
1820 else if(!strcmp(cnt, "6"))
1822 static char msgbuf[32];
1823 size_t msgbuflen = sizeof(msgbuf);
1826 unsigned char dhkey[DHKEY_SIZE];
1827 crypto = Crypto_ServerFindInstance(peeraddress, false);
1829 return CRYPTO_NOMATCH; // pre-challenge, rather be silent
1831 if(CDATA->cdata_id != id)
1832 return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
1833 if(CDATA->next_step != 6)
1834 return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
1836 if(!qd0_blind_id_authenticate_with_private_id_verify(CDATA->id, data_in, len_in, msgbuf, &msgbuflen, &status))
1839 return Crypto_ServerError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_verify failed (authentication error)", "Authentication error");
1842 strlcpy(crypto->client_keyfp, pubkeys_fp64[CDATA->c], sizeof(crypto->client_keyfp));
1844 crypto->client_keyfp[0] = 0;
1845 memset(crypto->client_idfp, 0, sizeof(crypto->client_idfp));
1846 fpbuflen = FP64_SIZE;
1847 if(!qd0_blind_id_fingerprint64_public_id(CDATA->id, crypto->client_idfp, &fpbuflen))
1850 return Crypto_ServerError(data_out, len_out, "d0_blind_id_fingerprint64_public_id failed", "Internal error");
1852 fpbuflen = DHKEY_SIZE;
1853 if(!qd0_blind_id_sessionkey_public_id(CDATA->id, (char *) dhkey, &fpbuflen))
1856 return Crypto_ServerError(data_out, len_out, "d0_blind_id_sessionkey_public_id failed", "Internal error");
1858 // XOR the two DH keys together to make one
1859 for(i = 0; i < DHKEY_SIZE; ++i)
1860 crypto->dhkey[i] ^= dhkey[i];
1862 // session key is FINISHED (no server part is to be expected)! By this, all keys are set up
1863 crypto->authenticated = true;
1864 CDATA->next_step = 0;
1865 // send a challenge-less challenge
1866 PutWithNul(&data_out_p, len_out, "challenge ");
1867 *len_out = data_out_p - data_out;
1868 --*len_out; // remove NUL terminator
1869 return CRYPTO_MATCH;
1871 return CRYPTO_NOMATCH; // pre-challenge, rather be silent
1873 return CRYPTO_NOMATCH;
1876 int Crypto_ServerParsePacket(const char *data_in, size_t len_in, char *data_out, size_t *len_out, lhnetaddress_t *peeraddress)
1880 static double complain_time = 0;
1882 qboolean do_time = false;
1883 qboolean do_reject = false;
1884 char infostringvalue[MAX_INPUTLINE];
1885 if(crypto_servercpupercent.value > 0 || crypto_servercpumaxtime.value > 0)
1886 if(len_in > 5 && !memcmp(data_in, "d0pk\\", 5))
1889 cnt = InfoString_GetValue(data_in + 4, "cnt", infostringvalue, sizeof(infostringvalue));
1891 if(!strcmp(cnt, "0"))
1896 // check if we may perform crypto...
1897 if(crypto_servercpupercent.value > 0)
1899 crypto_servercpu_accumulator += (realtime - crypto_servercpu_lastrealtime) * crypto_servercpupercent.value * 0.01;
1900 if(crypto_servercpumaxtime.value)
1901 if(crypto_servercpu_accumulator > crypto_servercpumaxtime.value)
1902 crypto_servercpu_accumulator = crypto_servercpumaxtime.value;
1906 if(crypto_servercpumaxtime.value > 0)
1907 if(realtime != crypto_servercpu_lastrealtime)
1908 crypto_servercpu_accumulator = crypto_servercpumaxtime.value;
1910 crypto_servercpu_lastrealtime = realtime;
1911 if(do_reject && crypto_servercpu_accumulator < 0)
1913 if(realtime > complain_time + 5)
1914 Con_Printf("crypto: cannot perform requested crypto operations; denial service attack or crypto_servercpupercent/crypto_servercpumaxtime are too low\n");
1916 return CRYPTO_DISCARD;
1918 t = Sys_DirtyTime();
1920 ret = Crypto_ServerParsePacket_Internal(data_in, len_in, data_out, len_out, peeraddress);
1923 t = Sys_DirtyTime() - t;if (t < 0.0) t = 0.0; // dirtytime can step backwards
1924 if(crypto_servercpudebug.integer)
1925 Con_Printf("crypto: accumulator was %.1f ms, used %.1f ms for crypto, ", crypto_servercpu_accumulator * 1000, t * 1000);
1926 crypto_servercpu_accumulator -= t;
1927 if(crypto_servercpudebug.integer)
1928 Con_Printf("is %.1f ms\n", crypto_servercpu_accumulator * 1000);
1933 static int Crypto_ClientError(char *data_out, size_t *len_out, const char *msg)
1935 dpsnprintf(data_out, *len_out, "reject %s", msg);
1936 *len_out = strlen(data_out);
1937 return CRYPTO_REPLACE;
1940 static int Crypto_SoftClientError(char *data_out, size_t *len_out, const char *msg)
1943 Con_Printf("%s\n", msg);
1944 return CRYPTO_DISCARD;
1947 int Crypto_ClientParsePacket(const char *data_in, size_t len_in, char *data_out, size_t *len_out, lhnetaddress_t *peeraddress)
1949 crypto_t *crypto = &cls.crypto;
1950 const char *string = data_in;
1953 char *data_out_p = data_out;
1955 char infostringvalue[MAX_INPUTLINE];
1958 if(!d0_blind_id_dll)
1959 return CRYPTO_NOMATCH; // no support
1961 // if "challenge": verify challenge, and discard message, send next crypto protocol message instead
1962 // otherwise, just handle actual protocol messages
1964 if (len_in == 6 && !memcmp(string, "accept", 6) && cls.connect_trying && d0_rijndael_dll)
1966 int wantserverid = -1;
1967 Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, NULL, 0, NULL);
1968 if(!crypto || !crypto->authenticated)
1970 if(wantserverid >= 0)
1971 return Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though a host key is present");
1972 if(crypto_aeslevel.integer >= 3)
1973 return Crypto_ClientError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)");
1975 return CRYPTO_NOMATCH;
1977 else if (len_in >= 1 && string[0] == 'j' && cls.connect_trying && d0_rijndael_dll && crypto_aeslevel.integer >= 3)
1979 int wantserverid = -1;
1980 Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, NULL, 0, NULL);
1981 if(!crypto || !crypto->authenticated)
1983 if(wantserverid >= 0)
1984 return Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though a host key is present");
1985 if(crypto_aeslevel.integer >= 3)
1986 return Crypto_ClientError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)");
1988 return CRYPTO_NOMATCH;
1990 else if (len_in >= 13 && !memcmp(string, "infoResponse\x0A", 13))
1992 s = InfoString_GetValue(string + 13, "d0_blind_id", infostringvalue, sizeof(infostringvalue));
1994 Crypto_StoreHostKey(peeraddress, s, true);
1995 return CRYPTO_NOMATCH;
1997 else if (len_in >= 15 && !memcmp(string, "statusResponse\x0A", 15))
2001 p = strchr(string + 15, '\n');
2005 * (char *) p = 0; // cut off the string there
2007 s = InfoString_GetValue(string + 15, "d0_blind_id", infostringvalue, sizeof(infostringvalue));
2009 Crypto_StoreHostKey(peeraddress, s, true);
2012 * (char *) p = save;
2013 // invoking those nasal demons again (do not run this on the DS9k)
2015 return CRYPTO_NOMATCH;
2017 else if(len_in > 10 && !memcmp(string, "challenge ", 10) && cls.connect_trying)
2019 const char *vlen_blind_id_ptr = NULL;
2020 size_t len_blind_id_ptr = 0;
2022 const char *challenge = data_in + 10;
2025 int clientid = -1, serverid = -1, wantserverid = -1;
2026 qboolean server_can_auth = true;
2027 char wantserver_idfp[FP64_SIZE+1];
2028 int wantserver_aeslevel;
2030 // if we have a stored host key for the server, assume serverid to already be selected!
2031 // (the loop will refuse to overwrite this one then)
2032 wantserver_idfp[0] = 0;
2033 Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, wantserver_idfp, sizeof(wantserver_idfp), &wantserver_aeslevel);
2034 // requirement: wantserver_idfp is a full ID if wantserverid set
2036 // if we leave, we have to consider the connection
2037 // unauthenticated; NOTE: this may be faked by a clever
2038 // attacker to force an unauthenticated connection; so we have
2039 // a safeguard check in place when encryption is required too
2040 // in place, or when authentication is required by the server
2041 crypto->authenticated = false;
2043 GetUntilNul(&data_in, &len_in);
2045 return (wantserverid >= 0) ? Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though a host key is present") :
2046 (d0_rijndael_dll && crypto_aeslevel.integer >= 3) ? Crypto_ServerError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)", NULL) :
2049 // FTEQW extension protocol
2052 k = Crypto_LittleLong(data_in);
2053 v = Crypto_LittleLong(data_in + 4);
2061 k = Crypto_LittleLong(data_in);
2066 case PROTOCOL_D0_BLIND_ID:
2067 vlen_blind_id_ptr = data_in;
2068 len_blind_id_ptr = v;
2080 if(!vlen_blind_id_ptr)
2081 return (wantserverid >= 0) ? Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though authentication is required") :
2082 (d0_rijndael_dll && crypto_aeslevel.integer >= 3) ? Crypto_ServerError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)", NULL) :
2085 data_in = vlen_blind_id_ptr;
2086 len_in = len_blind_id_ptr;
2088 // parse fingerprints
2089 // once we found a fingerprint we can auth to (ANY), select it as clientfp
2090 // once we found a fingerprint in the first list that we know, select it as serverfp
2094 p = GetUntilNul(&data_in, &len_in);
2099 if(!server_can_auth)
2100 break; // other protocol message may follow
2101 server_can_auth = false;
2106 for(i = 0; i < MAX_PUBKEYS; ++i)
2109 if(!strcmp(p, pubkeys_fp64[i]))
2111 if(pubkeys_havepriv[i])
2116 if(wantserverid < 0 || i == wantserverid)
2120 if(clientid >= 0 && serverid >= 0)
2124 // if stored host key is not found:
2125 if(wantserverid >= 0 && serverid < 0)
2126 return Crypto_ClientError(data_out, len_out, "Server CA does not match stored host key, refusing to connect");
2128 if(serverid >= 0 || clientid >= 0)
2130 // TODO at this point, fill clientside crypto struct!
2132 CDATA->cdata_id = ++cdata_id;
2133 CDATA->s = serverid;
2134 CDATA->c = clientid;
2135 memset(crypto->dhkey, 0, sizeof(crypto->dhkey));
2136 strlcpy(CDATA->challenge, challenge, sizeof(CDATA->challenge));
2137 crypto->client_keyfp[0] = 0;
2138 crypto->client_idfp[0] = 0;
2139 crypto->server_keyfp[0] = 0;
2140 crypto->server_idfp[0] = 0;
2141 memcpy(CDATA->wantserver_idfp, wantserver_idfp, sizeof(crypto->server_idfp));
2143 if(CDATA->wantserver_idfp[0]) // if we know a host key, honor its encryption setting
2144 switch(bound(0, d0_rijndael_dll ? crypto_aeslevel.integer : 0, 3))
2146 default: // dummy, never happens, but to make gcc happy...
2148 if(wantserver_aeslevel >= 3)
2149 return Crypto_ServerError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)", NULL);
2150 CDATA->wantserver_aes = false;
2153 CDATA->wantserver_aes = (wantserver_aeslevel >= 2);
2156 CDATA->wantserver_aes = (wantserver_aeslevel >= 1);
2159 if(wantserver_aeslevel <= 0)
2160 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);
2161 CDATA->wantserver_aes = true;
2165 // build outgoing message
2166 // append regular stuff
2167 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));
2168 PutWithNul(&data_out_p, len_out, serverid >= 0 ? pubkeys_fp64[serverid] : "");
2169 PutWithNul(&data_out_p, len_out, clientid >= 0 ? pubkeys_fp64[clientid] : "");
2173 // I am the client, and my key is ok... so let's set client_keyfp and client_idfp
2174 strlcpy(crypto->client_keyfp, pubkeys_fp64[CDATA->c], sizeof(crypto->client_keyfp));
2175 strlcpy(crypto->client_idfp, pubkeys_priv_fp64[CDATA->c], sizeof(crypto->client_idfp));
2181 CDATA->id = qd0_blind_id_new();
2185 return Crypto_ClientError(data_out, len_out, "d0_blind_id_new failed");
2187 if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->s]))
2190 return Crypto_ClientError(data_out, len_out, "d0_blind_id_copy failed");
2192 CDATA->next_step = 1;
2193 *len_out = data_out_p - data_out;
2195 else if(clientid >= 0)
2197 // skip over server auth, perform client auth only
2199 CDATA->id = qd0_blind_id_new();
2203 return Crypto_ClientError(data_out, len_out, "d0_blind_id_new failed");
2205 if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->c]))
2208 return Crypto_ClientError(data_out, len_out, "d0_blind_id_copy failed");
2210 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
2213 return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_start failed");
2215 CDATA->next_step = 5;
2216 data_out_p += *len_out;
2217 *len_out = data_out_p - data_out;
2220 *len_out = data_out_p - data_out;
2222 return CRYPTO_DISCARD;
2226 if(wantserver_idfp[0]) // if we know a host key, honor its encryption setting
2227 if(wantserver_aeslevel >= 3)
2228 return Crypto_ClientError(data_out, len_out, "Server insists on encryption, but neither can authenticate to the other");
2229 return (d0_rijndael_dll && crypto_aeslevel.integer >= 3) ? Crypto_ServerError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)", NULL) :
2233 else if(len_in > 5 && !memcmp(string, "d0pk\\", 5) && cls.connect_trying)
2237 cnt = InfoString_GetValue(string + 4, "id", infostringvalue, sizeof(infostringvalue));
2238 id = (cnt ? atoi(cnt) : -1);
2239 cnt = InfoString_GetValue(string + 4, "cnt", infostringvalue, sizeof(infostringvalue));
2241 return Crypto_ClientError(data_out, len_out, "d0pk\\ message without cnt");
2242 GetUntilNul(&data_in, &len_in);
2244 return Crypto_ClientError(data_out, len_out, "d0pk\\ message without attachment");
2246 if(!strcmp(cnt, "1"))
2249 if(CDATA->cdata_id != id)
2250 return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
2251 if(CDATA->next_step != 1)
2252 return Crypto_SoftClientError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
2254 cls.connect_nextsendtime = max(cls.connect_nextsendtime, realtime + 1); // prevent "hammering"
2256 if((s = InfoString_GetValue(string + 4, "aes", infostringvalue, sizeof(infostringvalue))))
2260 // we CANNOT toggle the AES status any more!
2261 // as the server already decided
2262 if(CDATA->wantserver_idfp[0]) // if we know a host key, honor its encryption setting
2263 if(!aes && CDATA->wantserver_aes)
2266 return Crypto_ClientError(data_out, len_out, "Stored host key requires encryption, but server did not enable encryption");
2268 if(aes && (!d0_rijndael_dll || crypto_aeslevel.integer <= 0))
2271 return Crypto_ClientError(data_out, len_out, "Server insists on encryption too hard");
2273 if(!aes && (d0_rijndael_dll && crypto_aeslevel.integer >= 3))
2276 return Crypto_ClientError(data_out, len_out, "Server insists on plaintext too hard");
2278 crypto->use_aes = aes != 0;
2280 PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\2\\id\\%d", CDATA->cdata_id));
2281 if(!qd0_blind_id_authenticate_with_private_id_challenge(CDATA->id, true, false, data_in, len_in, data_out_p, len_out, &status))
2284 return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_challenge failed");
2286 CDATA->next_step = 3;
2287 data_out_p += *len_out;
2288 *len_out = data_out_p - data_out;
2289 return CRYPTO_DISCARD;
2291 else if(!strcmp(cnt, "3"))
2293 static char msgbuf[32];
2294 size_t msgbuflen = sizeof(msgbuf);
2298 if(CDATA->cdata_id != id)
2299 return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
2300 if(CDATA->next_step != 3)
2301 return Crypto_SoftClientError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
2303 cls.connect_nextsendtime = max(cls.connect_nextsendtime, realtime + 1); // prevent "hammering"
2305 if(!qd0_blind_id_authenticate_with_private_id_verify(CDATA->id, data_in, len_in, msgbuf, &msgbuflen, &status))
2308 return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_verify failed (server authentication error)");
2311 strlcpy(crypto->server_keyfp, pubkeys_fp64[CDATA->s], sizeof(crypto->server_keyfp));
2313 crypto->server_keyfp[0] = 0;
2314 memset(crypto->server_idfp, 0, sizeof(crypto->server_idfp));
2315 fpbuflen = FP64_SIZE;
2316 if(!qd0_blind_id_fingerprint64_public_id(CDATA->id, crypto->server_idfp, &fpbuflen))
2319 return Crypto_ClientError(data_out, len_out, "d0_blind_id_fingerprint64_public_id failed");
2321 if(CDATA->wantserver_idfp[0])
2322 if(memcmp(CDATA->wantserver_idfp, crypto->server_idfp, sizeof(crypto->server_idfp)))
2325 return Crypto_ClientError(data_out, len_out, "Server ID does not match stored host key, refusing to connect");
2327 fpbuflen = DHKEY_SIZE;
2328 if(!qd0_blind_id_sessionkey_public_id(CDATA->id, (char *) crypto->dhkey, &fpbuflen))
2331 return Crypto_ClientError(data_out, len_out, "d0_blind_id_sessionkey_public_id failed");
2334 // cache the server key
2335 Crypto_StoreHostKey(&cls.connect_address, va(vabuf, sizeof(vabuf), "%d %s@%s", crypto->use_aes ? 1 : 0, crypto->server_idfp, pubkeys_fp64[CDATA->s]), false);
2339 // client will auth next
2340 PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\4\\id\\%d", CDATA->cdata_id));
2341 if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->c]))
2344 return Crypto_ClientError(data_out, len_out, "d0_blind_id_copy failed");
2346 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
2349 return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_start failed");
2351 CDATA->next_step = 5;
2352 data_out_p += *len_out;
2353 *len_out = data_out_p - data_out;
2354 return CRYPTO_DISCARD;
2358 // session key is FINISHED (no server part is to be expected)! By this, all keys are set up
2359 crypto->authenticated = true;
2360 CDATA->next_step = 0;
2361 // assume we got the empty challenge to finish the protocol
2362 PutWithNul(&data_out_p, len_out, "challenge ");
2363 *len_out = data_out_p - data_out;
2364 --*len_out; // remove NUL terminator
2365 return CRYPTO_REPLACE;
2368 else if(!strcmp(cnt, "5"))
2371 unsigned char dhkey[DHKEY_SIZE];
2375 if(CDATA->cdata_id != id)
2376 return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
2377 if(CDATA->next_step != 5)
2378 return Crypto_SoftClientError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
2380 cls.connect_nextsendtime = max(cls.connect_nextsendtime, realtime + 1); // prevent "hammering"
2382 if(CDATA->s < 0) // only if server didn't auth
2384 if((s = InfoString_GetValue(string + 4, "aes", infostringvalue, sizeof(infostringvalue))))
2388 if(CDATA->wantserver_idfp[0]) // if we know a host key, honor its encryption setting
2389 if(!aes && CDATA->wantserver_aes)
2392 return Crypto_ClientError(data_out, len_out, "Stored host key requires encryption, but server did not enable encryption");
2394 if(aes && (!d0_rijndael_dll || crypto_aeslevel.integer <= 0))
2397 return Crypto_ClientError(data_out, len_out, "Server insists on encryption too hard");
2399 if(!aes && (d0_rijndael_dll && crypto_aeslevel.integer >= 3))
2402 return Crypto_ClientError(data_out, len_out, "Server insists on plaintext too hard");
2404 crypto->use_aes = aes != 0;
2407 PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\6\\id\\%d", CDATA->cdata_id));
2408 if(!qd0_blind_id_authenticate_with_private_id_response(CDATA->id, data_in, len_in, data_out_p, len_out))
2411 return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_response failed");
2413 fpbuflen = DHKEY_SIZE;
2414 if(!qd0_blind_id_sessionkey_public_id(CDATA->id, (char *) dhkey, &fpbuflen))
2417 return Crypto_ClientError(data_out, len_out, "d0_blind_id_sessionkey_public_id failed");
2419 // XOR the two DH keys together to make one
2420 for(i = 0; i < DHKEY_SIZE; ++i)
2421 crypto->dhkey[i] ^= dhkey[i];
2422 // session key is FINISHED! By this, all keys are set up
2423 crypto->authenticated = true;
2424 CDATA->next_step = 0;
2425 data_out_p += *len_out;
2426 *len_out = data_out_p - data_out;
2427 return CRYPTO_DISCARD;
2429 return Crypto_SoftClientError(data_out, len_out, "Got unknown d0_blind_id message from server");
2432 return CRYPTO_NOMATCH;
2435 size_t Crypto_SignData(const void *data, size_t datasize, int keyid, void *signed_data, size_t signed_size)
2437 if(keyid < 0 || keyid >= MAX_PUBKEYS)
2439 if(!pubkeys_havepriv[keyid])
2441 if(qd0_blind_id_sign_with_private_id_sign(pubkeys[keyid], true, false, (const char *)data, datasize, (char *)signed_data, &signed_size))
2446 size_t Crypto_SignDataDetached(const void *data, size_t datasize, int keyid, void *signed_data, size_t signed_size)
2448 if(keyid < 0 || keyid >= MAX_PUBKEYS)
2450 if(!pubkeys_havepriv[keyid])
2452 if(qd0_blind_id_sign_with_private_id_sign_detached(pubkeys[keyid], true, false, (const char *)data, datasize, (char *)signed_data, &signed_size))