1 // TODO key loading, generating, saving
9 cvar_t crypto_developer = {CVAR_SAVE, "crypto_developer", "0", "print extra info about crypto handshake"};
10 cvar_t crypto_servercpupercent = {CVAR_SAVE, "crypto_servercpupercent", "10", "allowed crypto CPU load in percent for server operation (0 = no limit, faster)"};
11 cvar_t crypto_servercpumaxtime = {CVAR_SAVE, "crypto_servercpumaxtime", "0.01", "maximum allowed crypto CPU time per frame (0 = no limit)"};
12 cvar_t crypto_servercpudebug = {CVAR_SAVE, "crypto_servercpudebug", "0", "print statistics about time usage by crypto"};
13 static double crypto_servercpu_accumulator = 0;
14 static double crypto_servercpu_lastrealtime = 0;
15 cvar_t crypto_aeslevel = {CVAR_SAVE, "crypto_aeslevel", "1", "whether to support AES encryption in authenticated connections (0 = no, 1 = supported, 2 = requested, 3 = required)"};
16 int crypto_keyfp_recommended_length;
17 static const char *crypto_idstring = NULL;
18 static char crypto_idstring_buf[512];
20 #define PROTOCOL_D0_BLIND_ID FOURCC_D0PK
21 #define PROTOCOL_VLEN (('v' << 0) | ('l' << 8) | ('e' << 16) | ('n' << 24))
23 // BEGIN stuff shared with crypto-keygen-standalone
24 #define FOURCC_D0PK (('d' << 0) | ('0' << 8) | ('p' << 16) | ('k' << 24))
25 #define FOURCC_D0SK (('d' << 0) | ('0' << 8) | ('s' << 16) | ('k' << 24))
26 #define FOURCC_D0PI (('d' << 0) | ('0' << 8) | ('p' << 16) | ('i' << 24))
27 #define FOURCC_D0SI (('d' << 0) | ('0' << 8) | ('s' << 16) | ('i' << 24))
28 #define FOURCC_D0IQ (('d' << 0) | ('0' << 8) | ('i' << 16) | ('q' << 24))
29 #define FOURCC_D0IR (('d' << 0) | ('0' << 8) | ('i' << 16) | ('r' << 24))
30 #define FOURCC_D0ER (('d' << 0) | ('0' << 8) | ('e' << 16) | ('r' << 24))
31 #define FOURCC_D0IC (('d' << 0) | ('0' << 8) | ('i' << 16) | ('c' << 24))
33 static unsigned long Crypto_LittleLong(const char *data)
36 ((unsigned char) data[0]) |
37 (((unsigned char) data[1]) << 8) |
38 (((unsigned char) data[2]) << 16) |
39 (((unsigned char) data[3]) << 24);
42 static void Crypto_UnLittleLong(char *data, unsigned long l)
45 data[1] = (l >> 8) & 0xFF;
46 data[2] = (l >> 16) & 0xFF;
47 data[3] = (l >> 24) & 0xFF;
50 static size_t Crypto_ParsePack(const char *buf, size_t len, unsigned long header, const char **lumps, size_t *lumpsize, size_t nlumps)
59 if(Crypto_LittleLong(buf) != header)
63 for(i = 0; i < nlumps; ++i)
67 lumpsize[i] = Crypto_LittleLong(&buf[pos]);
69 if(pos + lumpsize[i] > len)
77 static size_t Crypto_UnParsePack(char *buf, size_t len, unsigned long header, const char *const *lumps, const size_t *lumpsize, size_t nlumps)
86 Crypto_UnLittleLong(buf, header);
89 for(i = 0; i < nlumps; ++i)
91 if(pos + 4 + lumpsize[i] > len)
93 Crypto_UnLittleLong(&buf[pos], lumpsize[i]);
95 memcpy(&buf[pos], lumps[i], lumpsize[i]);
100 // END stuff shared with xonotic-keygen
106 #include <d0_blind_id/d0_blind_id.h>
108 #define d0_blind_id_dll 1
109 #define Crypto_OpenLibrary() true
110 #define Crypto_CloseLibrary()
112 #define qd0_blind_id_new d0_blind_id_new
113 #define qd0_blind_id_free d0_blind_id_free
114 //#define qd0_blind_id_clear d0_blind_id_clear
115 #define qd0_blind_id_copy d0_blind_id_copy
116 //#define qd0_blind_id_generate_private_key d0_blind_id_generate_private_key
117 //#define qd0_blind_id_generate_private_key_fastreject d0_blind_id_generate_private_key_fastreject
118 //#define qd0_blind_id_read_private_key d0_blind_id_read_private_key
119 #define qd0_blind_id_read_public_key d0_blind_id_read_public_key
120 //#define qd0_blind_id_write_private_key d0_blind_id_write_private_key
121 //#define qd0_blind_id_write_public_key d0_blind_id_write_public_key
122 #define qd0_blind_id_fingerprint64_public_key d0_blind_id_fingerprint64_public_key
123 //#define qd0_blind_id_generate_private_id_modulus d0_blind_id_generate_private_id_modulus
124 #define qd0_blind_id_read_private_id_modulus d0_blind_id_read_private_id_modulus
125 //#define qd0_blind_id_write_private_id_modulus d0_blind_id_write_private_id_modulus
126 #define qd0_blind_id_generate_private_id_start d0_blind_id_generate_private_id_start
127 #define qd0_blind_id_generate_private_id_request d0_blind_id_generate_private_id_request
128 //#define qd0_blind_id_answer_private_id_request d0_blind_id_answer_private_id_request
129 #define qd0_blind_id_finish_private_id_request d0_blind_id_finish_private_id_request
130 //#define qd0_blind_id_read_private_id_request_camouflage d0_blind_id_read_private_id_request_camouflage
131 //#define qd0_blind_id_write_private_id_request_camouflage d0_blind_id_write_private_id_request_camouflage
132 #define qd0_blind_id_read_private_id d0_blind_id_read_private_id
133 //#define qd0_blind_id_read_public_id d0_blind_id_read_public_id
134 #define qd0_blind_id_write_private_id d0_blind_id_write_private_id
135 //#define qd0_blind_id_write_public_id d0_blind_id_write_public_id
136 #define qd0_blind_id_authenticate_with_private_id_start d0_blind_id_authenticate_with_private_id_start
137 #define qd0_blind_id_authenticate_with_private_id_challenge d0_blind_id_authenticate_with_private_id_challenge
138 #define qd0_blind_id_authenticate_with_private_id_response d0_blind_id_authenticate_with_private_id_response
139 #define qd0_blind_id_authenticate_with_private_id_verify d0_blind_id_authenticate_with_private_id_verify
140 #define qd0_blind_id_fingerprint64_public_id d0_blind_id_fingerprint64_public_id
141 #define qd0_blind_id_sessionkey_public_id d0_blind_id_sessionkey_public_id
142 #define qd0_blind_id_INITIALIZE d0_blind_id_INITIALIZE
143 #define qd0_blind_id_SHUTDOWN d0_blind_id_SHUTDOWN
144 #define qd0_blind_id_util_sha256 d0_blind_id_util_sha256
148 // d0_blind_id interface
151 #define D0_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
153 #define D0_WARN_UNUSED_RESULT
157 typedef struct d0_blind_id_s d0_blind_id_t;
158 typedef D0_BOOL (*d0_fastreject_function) (const d0_blind_id_t *ctx, void *pass);
159 static D0_EXPORT D0_WARN_UNUSED_RESULT d0_blind_id_t *(*qd0_blind_id_new) (void);
160 static D0_EXPORT void (*qd0_blind_id_free) (d0_blind_id_t *a);
161 //static D0_EXPORT void (*qd0_blind_id_clear) (d0_blind_id_t *ctx);
162 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_copy) (d0_blind_id_t *ctx, const d0_blind_id_t *src);
163 //static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_generate_private_key) (d0_blind_id_t *ctx, int k);
164 //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);
165 //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);
166 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);
167 //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);
168 //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);
169 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);
170 //static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_generate_private_id_modulus) (d0_blind_id_t *ctx);
171 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);
172 //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);
173 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_generate_private_id_start) (d0_blind_id_t *ctx);
174 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);
175 //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);
176 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);
177 //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);
178 //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);
179 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);
180 //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);
181 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);
182 //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);
183 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);
184 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);
185 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);
186 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);
187 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);
188 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
189 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_INITIALIZE) (void);
190 static D0_EXPORT void (*qd0_blind_id_SHUTDOWN) (void);
191 static D0_EXPORT void (*qd0_blind_id_util_sha256) (char *out, const char *in, size_t n);
192 static dllfunction_t d0_blind_id_funcs[] =
194 {"d0_blind_id_new", (void **) &qd0_blind_id_new},
195 {"d0_blind_id_free", (void **) &qd0_blind_id_free},
196 //{"d0_blind_id_clear", (void **) &qd0_blind_id_clear},
197 {"d0_blind_id_copy", (void **) &qd0_blind_id_copy},
198 //{"d0_blind_id_generate_private_key", (void **) &qd0_blind_id_generate_private_key},
199 //{"d0_blind_id_generate_private_key_fastreject", (void **) &qd0_blind_id_generate_private_key_fastreject},
200 //{"d0_blind_id_read_private_key", (void **) &qd0_blind_id_read_private_key},
201 {"d0_blind_id_read_public_key", (void **) &qd0_blind_id_read_public_key},
202 //{"d0_blind_id_write_private_key", (void **) &qd0_blind_id_write_private_key},
203 //{"d0_blind_id_write_public_key", (void **) &qd0_blind_id_write_public_key},
204 {"d0_blind_id_fingerprint64_public_key", (void **) &qd0_blind_id_fingerprint64_public_key},
205 //{"d0_blind_id_generate_private_id_modulus", (void **) &qd0_blind_id_generate_private_id_modulus},
206 {"d0_blind_id_read_private_id_modulus", (void **) &qd0_blind_id_read_private_id_modulus},
207 //{"d0_blind_id_write_private_id_modulus", (void **) &qd0_blind_id_write_private_id_modulus},
208 {"d0_blind_id_generate_private_id_start", (void **) &qd0_blind_id_generate_private_id_start},
209 {"d0_blind_id_generate_private_id_request", (void **) &qd0_blind_id_generate_private_id_request},
210 //{"d0_blind_id_answer_private_id_request", (void **) &qd0_blind_id_answer_private_id_request},
211 {"d0_blind_id_finish_private_id_request", (void **) &qd0_blind_id_finish_private_id_request},
212 //{"d0_blind_id_read_private_id_request_camouflage", (void **) &qd0_blind_id_read_private_id_request_camouflage},
213 //{"d0_blind_id_write_private_id_request_camouflage", (void **) &qd0_blind_id_write_private_id_request_camouflage},
214 {"d0_blind_id_read_private_id", (void **) &qd0_blind_id_read_private_id},
215 //{"d0_blind_id_read_public_id", (void **) &qd0_blind_id_read_public_id},
216 {"d0_blind_id_write_private_id", (void **) &qd0_blind_id_write_private_id},
217 //{"d0_blind_id_write_public_id", (void **) &qd0_blind_id_write_public_id},
218 {"d0_blind_id_authenticate_with_private_id_start", (void **) &qd0_blind_id_authenticate_with_private_id_start},
219 {"d0_blind_id_authenticate_with_private_id_challenge", (void **) &qd0_blind_id_authenticate_with_private_id_challenge},
220 {"d0_blind_id_authenticate_with_private_id_response", (void **) &qd0_blind_id_authenticate_with_private_id_response},
221 {"d0_blind_id_authenticate_with_private_id_verify", (void **) &qd0_blind_id_authenticate_with_private_id_verify},
222 {"d0_blind_id_fingerprint64_public_id", (void **) &qd0_blind_id_fingerprint64_public_id},
223 {"d0_blind_id_sessionkey_public_id", (void **) &qd0_blind_id_sessionkey_public_id},
224 {"d0_blind_id_INITIALIZE", (void **) &qd0_blind_id_INITIALIZE},
225 {"d0_blind_id_SHUTDOWN", (void **) &qd0_blind_id_SHUTDOWN},
226 {"d0_blind_id_util_sha256", (void **) &qd0_blind_id_util_sha256},
229 // end of d0_blind_id interface
231 static dllhandle_t d0_blind_id_dll = NULL;
232 static qboolean Crypto_OpenLibrary (void)
234 const char* dllnames [] =
237 "libd0_blind_id-0.dll",
238 #elif defined(MACOSX)
239 "libd0_blind_id.0.dylib",
241 "libd0_blind_id.so.0",
242 "libd0_blind_id.so", // FreeBSD
252 return Sys_LoadLibrary (dllnames, &d0_blind_id_dll, d0_blind_id_funcs);
255 static void Crypto_CloseLibrary (void)
257 Sys_UnloadLibrary (&d0_blind_id_dll);
262 #ifdef CRYPTO_RIJNDAEL_STATIC
264 #include <d0_blind_id/d0_rijndael.h>
266 #define d0_rijndael_dll 1
267 #define Crypto_Rijndael_OpenLibrary() true
268 #define Crypto_Rijndael_CloseLibrary()
270 #define qd0_rijndael_setup_encrypt d0_rijndael_setup_encrypt
271 #define qd0_rijndael_setup_decrypt d0_rijndael_setup_decrypt
272 #define qd0_rijndael_encrypt d0_rijndael_encrypt
273 #define qd0_rijndael_decrypt d0_rijndael_decrypt
277 // no need to do the #define dance here, as the upper part declares out macros either way
279 D0_EXPORT int (*qd0_rijndael_setup_encrypt) (unsigned long *rk, const unsigned char *key,
281 D0_EXPORT int (*qd0_rijndael_setup_decrypt) (unsigned long *rk, const unsigned char *key,
283 D0_EXPORT void (*qd0_rijndael_encrypt) (const unsigned long *rk, int nrounds,
284 const unsigned char plaintext[16], unsigned char ciphertext[16]);
285 D0_EXPORT void (*qd0_rijndael_decrypt) (const unsigned long *rk, int nrounds,
286 const unsigned char ciphertext[16], unsigned char plaintext[16]);
287 #define D0_RIJNDAEL_KEYLENGTH(keybits) ((keybits)/8)
288 #define D0_RIJNDAEL_RKLENGTH(keybits) ((keybits)/8+28)
289 #define D0_RIJNDAEL_NROUNDS(keybits) ((keybits)/32+6)
290 static dllfunction_t d0_rijndael_funcs[] =
292 {"d0_rijndael_setup_decrypt", (void **) &qd0_rijndael_setup_decrypt},
293 {"d0_rijndael_setup_encrypt", (void **) &qd0_rijndael_setup_encrypt},
294 {"d0_rijndael_decrypt", (void **) &qd0_rijndael_decrypt},
295 {"d0_rijndael_encrypt", (void **) &qd0_rijndael_encrypt},
298 // end of d0_blind_id interface
300 static dllhandle_t d0_rijndael_dll = NULL;
301 static qboolean Crypto_Rijndael_OpenLibrary (void)
303 const char* dllnames [] =
306 "libd0_rijndael-0.dll",
307 #elif defined(MACOSX)
308 "libd0_rijndael.0.dylib",
310 "libd0_rijndael.so.0",
311 "libd0_rijndael.so", // FreeBSD
321 return Sys_LoadLibrary (dllnames, &d0_rijndael_dll, d0_rijndael_funcs);
324 static void Crypto_Rijndael_CloseLibrary (void)
326 Sys_UnloadLibrary (&d0_rijndael_dll);
332 void sha256(unsigned char *out, const unsigned char *in, int n)
334 qd0_blind_id_util_sha256((char *) out, (const char *) in, n);
337 static size_t Crypto_LoadFile(const char *path, char *buf, size_t nmax)
342 f = FS_SysOpen(va("%s%s", fs_userdir, path), "rb", false);
344 f = FS_SysOpen(va("%s%s", fs_basedir, path), "rb", false);
347 n = FS_Read(f, buf, nmax);
354 static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
355 static void base64_3to4(const unsigned char *in, unsigned char *out, int bytes)
357 unsigned char i0 = (bytes > 0) ? in[0] : 0;
358 unsigned char i1 = (bytes > 1) ? in[1] : 0;
359 unsigned char i2 = (bytes > 2) ? in[2] : 0;
360 unsigned char o0 = base64[i0 >> 2];
361 unsigned char o1 = base64[((i0 << 4) | (i1 >> 4)) & 077];
362 unsigned char o2 = base64[((i1 << 2) | (i2 >> 6)) & 077];
363 unsigned char o3 = base64[i2 & 077];
364 out[0] = (bytes > 0) ? o0 : '?';
365 out[1] = (bytes > 0) ? o1 : '?';
366 out[2] = (bytes > 1) ? o2 : '=';
367 out[3] = (bytes > 2) ? o3 : '=';
370 size_t base64_encode(unsigned char *buf, size_t buflen, size_t outbuflen)
373 // expand the out-buffer
374 blocks = (buflen + 2) / 3;
375 if(blocks*4 > outbuflen)
377 for(i = blocks; i > 0; )
380 base64_3to4(buf + 3*i, buf + 4*i, buflen - 3*i);
385 static qboolean PutWithNul(char **data, size_t *len, const char *str)
387 // invariant: data points to insertion point
388 size_t l = strlen(str);
391 memcpy(*data, str, l+1);
397 static const char *GetUntilNul(const char **data, size_t *len)
399 // invariant: data points to next character to take
400 const char *data_save = *data;
413 p = (const char *) memchr(*data, 0, *len);
414 if(!p) // no terminating NUL
427 return (const char *) data_save;
434 static d0_blind_id_t *Crypto_ReadPublicKey(char *buf, size_t len)
436 d0_blind_id_t *pk = NULL;
439 if(Crypto_ParsePack(buf, len, FOURCC_D0PK, p, l, 2))
441 pk = qd0_blind_id_new();
443 if(qd0_blind_id_read_public_key(pk, p[0], l[0]))
444 if(qd0_blind_id_read_private_id_modulus(pk, p[1], l[1]))
448 qd0_blind_id_free(pk);
453 static qboolean Crypto_AddPrivateKey(d0_blind_id_t *pk, char *buf, size_t len)
457 if(Crypto_ParsePack(buf, len, FOURCC_D0SI, p, l, 1))
459 if(qd0_blind_id_read_private_id(pk, p[0], l[0]))
465 #define MAX_PUBKEYS 16
466 static d0_blind_id_t *pubkeys[MAX_PUBKEYS];
467 static char pubkeys_fp64[MAX_PUBKEYS][FP64_SIZE+1];
468 static qboolean pubkeys_havepriv[MAX_PUBKEYS];
469 static char pubkeys_priv_fp64[MAX_PUBKEYS][FP64_SIZE+1];
470 static char challenge_append[1400];
471 static size_t challenge_append_length;
473 static int keygen_i = -1;
474 static char keygen_buf[8192];
476 #define MAX_CRYPTOCONNECTS 16
477 #define CRYPTOCONNECT_NONE 0
478 #define CRYPTOCONNECT_PRECONNECT 1
479 #define CRYPTOCONNECT_CONNECT 2
480 #define CRYPTOCONNECT_RECONNECT 3
481 #define CRYPTOCONNECT_DUPLICATE 4
482 typedef struct server_cryptoconnect_s
485 lhnetaddress_t address;
489 server_cryptoconnect_t;
490 static server_cryptoconnect_t cryptoconnects[MAX_CRYPTOCONNECTS];
492 static int cdata_id = 0;
498 char challenge[2048];
499 char wantserver_idfp[FP64_SIZE+1];
500 qboolean wantserver_aes;
505 // crypto specific helpers
506 #define CDATA ((crypto_data_t *) crypto->data)
507 #define MAKE_CDATA if(!crypto->data) crypto->data = Z_Malloc(sizeof(crypto_data_t))
508 #define CLEAR_CDATA if(crypto->data) { if(CDATA->id) qd0_blind_id_free(CDATA->id); Z_Free(crypto->data); } crypto->data = NULL
510 static crypto_t *Crypto_ServerFindInstance(lhnetaddress_t *peeraddress, qboolean allow_create)
516 return NULL; // no support
518 for(i = 0; i < MAX_CRYPTOCONNECTS; ++i)
519 if(LHNETADDRESS_Compare(peeraddress, &cryptoconnects[i].address))
521 if(i < MAX_CRYPTOCONNECTS && (allow_create || cryptoconnects[i].crypto.data))
523 crypto = &cryptoconnects[i].crypto;
524 cryptoconnects[i].lasttime = realtime;
530 for(i = 1; i < MAX_CRYPTOCONNECTS; ++i)
531 if(cryptoconnects[i].lasttime < cryptoconnects[best].lasttime)
533 crypto = &cryptoconnects[best].crypto;
534 cryptoconnects[best].lasttime = realtime;
535 memcpy(&cryptoconnects[best].address, peeraddress, sizeof(cryptoconnects[best].address));
540 qboolean Crypto_ServerFinishInstance(crypto_t *out, crypto_t *crypto)
542 // no check needed here (returned pointers are only used in prefilled fields)
543 if(!crypto || !crypto->authenticated)
545 Con_Printf("Passed an invalid crypto connect instance\n");
546 memset(out, 0, sizeof(*out));
550 memcpy(out, crypto, sizeof(*out));
551 memset(crypto, 0, sizeof(crypto));
555 crypto_t *Crypto_ServerGetInstance(lhnetaddress_t *peeraddress)
557 // no check needed here (returned pointers are only used in prefilled fields)
558 return Crypto_ServerFindInstance(peeraddress, false);
561 typedef struct crypto_storedhostkey_s
563 struct crypto_storedhostkey_s *next;
566 char idfp[FP64_SIZE+1];
569 crypto_storedhostkey_t;
570 static crypto_storedhostkey_t *crypto_storedhostkey_hashtable[CRYPTO_HOSTKEY_HASHSIZE];
572 static void Crypto_InitHostKeys(void)
575 for(i = 0; i < CRYPTO_HOSTKEY_HASHSIZE; ++i)
576 crypto_storedhostkey_hashtable[i] = NULL;
579 static void Crypto_ClearHostKeys(void)
582 crypto_storedhostkey_t *hk, *hkn;
583 for(i = 0; i < CRYPTO_HOSTKEY_HASHSIZE; ++i)
585 for(hk = crypto_storedhostkey_hashtable[i]; hk; hk = hkn)
590 crypto_storedhostkey_hashtable[i] = NULL;
594 static qboolean Crypto_ClearHostKey(lhnetaddress_t *peeraddress)
598 crypto_storedhostkey_t **hkp;
599 qboolean found = false;
601 LHNETADDRESS_ToString(peeraddress, buf, sizeof(buf), 1);
602 hashindex = CRC_Block((const unsigned char *) buf, strlen(buf)) % CRYPTO_HOSTKEY_HASHSIZE;
603 for(hkp = &crypto_storedhostkey_hashtable[hashindex]; *hkp && LHNETADDRESS_Compare(&((*hkp)->addr), peeraddress); hkp = &((*hkp)->next));
607 crypto_storedhostkey_t *hk = *hkp;
616 static void Crypto_StoreHostKey(lhnetaddress_t *peeraddress, const char *keystring, qboolean complain)
620 crypto_storedhostkey_t *hk;
622 char idfp[FP64_SIZE+1];
628 // syntax of keystring:
629 // aeslevel id@key id@key ...
633 aeslevel = bound(0, *keystring - '0', 3);
634 while(*keystring && *keystring != ' ')
638 while(*keystring && keyid < 0)
641 const char *idstart, *idend, *keystart, *keyend;
642 ++keystring; // skip the space
644 while(*keystring && *keystring != ' ' && *keystring != '@')
650 keystart = keystring;
651 while(*keystring && *keystring != ' ')
655 if(idend - idstart == FP64_SIZE && keyend - keystart == FP64_SIZE)
657 for(keyid = 0; keyid < MAX_PUBKEYS; ++keyid)
659 if(!memcmp(pubkeys_fp64[keyid], keystart, FP64_SIZE))
661 memcpy(idfp, idstart, FP64_SIZE);
665 if(keyid >= MAX_PUBKEYS)
673 LHNETADDRESS_ToString(peeraddress, buf, sizeof(buf), 1);
674 hashindex = CRC_Block((const unsigned char *) buf, strlen(buf)) % CRYPTO_HOSTKEY_HASHSIZE;
675 for(hk = crypto_storedhostkey_hashtable[hashindex]; hk && LHNETADDRESS_Compare(&hk->addr, peeraddress); hk = hk->next);
681 if(hk->keyid != keyid || memcmp(hk->idfp, idfp, FP64_SIZE+1))
682 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);
683 if(hk->aeslevel > aeslevel)
684 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);
686 hk->aeslevel = max(aeslevel, hk->aeslevel);
690 // great, we did NOT have it yet
691 hk = (crypto_storedhostkey_t *) Z_Malloc(sizeof(*hk));
692 memcpy(&hk->addr, peeraddress, sizeof(hk->addr));
694 memcpy(hk->idfp, idfp, FP64_SIZE+1);
695 hk->next = crypto_storedhostkey_hashtable[hashindex];
696 hk->aeslevel = aeslevel;
697 crypto_storedhostkey_hashtable[hashindex] = hk;
700 qboolean Crypto_RetrieveHostKey(lhnetaddress_t *peeraddress, int *keyid, char *keyfp, size_t keyfplen, char *idfp, size_t idfplen, int *aeslevel)
704 crypto_storedhostkey_t *hk;
709 LHNETADDRESS_ToString(peeraddress, buf, sizeof(buf), 1);
710 hashindex = CRC_Block((const unsigned char *) buf, strlen(buf)) % CRYPTO_HOSTKEY_HASHSIZE;
711 for(hk = crypto_storedhostkey_hashtable[hashindex]; hk && LHNETADDRESS_Compare(&hk->addr, peeraddress); hk = hk->next);
719 strlcpy(keyfp, pubkeys_fp64[hk->keyid], keyfplen);
721 strlcpy(idfp, hk->idfp, idfplen);
723 *aeslevel = hk->aeslevel;
727 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
729 if(keyid < 0 || keyid > MAX_PUBKEYS)
738 strlcpy(keyfp, pubkeys_fp64[keyid], keyfplen);
740 if(pubkeys_havepriv[keyid])
741 strlcpy(idfp, pubkeys_priv_fp64[keyid], keyfplen);
746 // init/shutdown code
747 static void Crypto_BuildChallengeAppend(void)
749 char *p, *lengthptr, *startptr;
752 p = challenge_append;
753 n = sizeof(challenge_append);
754 Crypto_UnLittleLong(p, PROTOCOL_VLEN);
758 Crypto_UnLittleLong(p, 0);
761 Crypto_UnLittleLong(p, PROTOCOL_D0_BLIND_ID);
765 for(i = 0; i < MAX_PUBKEYS; ++i)
766 if(pubkeys_havepriv[i])
767 PutWithNul(&p, &n, pubkeys_fp64[i]);
768 PutWithNul(&p, &n, "");
769 for(i = 0; i < MAX_PUBKEYS; ++i)
770 if(!pubkeys_havepriv[i] && pubkeys[i])
771 PutWithNul(&p, &n, pubkeys_fp64[i]);
772 Crypto_UnLittleLong(lengthptr, p - startptr);
773 challenge_append_length = p - challenge_append;
776 static void Crypto_LoadKeys(void)
783 // note: we are just a CLIENT
785 // PUBLIC KEYS to accept (including modulus)
786 // PRIVATE KEY of user
788 crypto_idstring = NULL;
789 dpsnprintf(crypto_idstring_buf, sizeof(crypto_idstring_buf), "%d", d0_rijndael_dll ? crypto_aeslevel.integer : 0);
790 for(i = 0; i < MAX_PUBKEYS; ++i)
792 memset(pubkeys_fp64[i], 0, sizeof(pubkeys_fp64[i]));
793 memset(pubkeys_priv_fp64[i], 0, sizeof(pubkeys_fp64[i]));
794 pubkeys_havepriv[i] = false;
795 len = Crypto_LoadFile(va("key_%d.d0pk", i), buf, sizeof(buf));
796 if((pubkeys[i] = Crypto_ReadPublicKey(buf, len)))
799 if(qd0_blind_id_fingerprint64_public_key(pubkeys[i], pubkeys_fp64[i], &len2)) // keeps final NUL
801 Con_Printf("Loaded public key key_%d.d0pk (fingerprint: %s)\n", i, pubkeys_fp64[i]);
802 len = Crypto_LoadFile(va("key_%d.d0si", i), buf, sizeof(buf));
805 if(Crypto_AddPrivateKey(pubkeys[i], buf, len))
808 if(qd0_blind_id_fingerprint64_public_id(pubkeys[i], pubkeys_priv_fp64[i], &len2)) // keeps final NUL
810 Con_Printf("Loaded private ID key_%d.d0si for key_%d.d0pk (fingerprint: %s)\n", i, i, pubkeys_priv_fp64[i]);
811 pubkeys_havepriv[i] = true;
812 strlcat(crypto_idstring_buf, va(" %s@%s", pubkeys_priv_fp64[i], pubkeys_fp64[i]), sizeof(crypto_idstring_buf));
816 // can't really happen
817 // but nothing leaked here
824 // can't really happen
825 qd0_blind_id_free(pubkeys[i]);
830 crypto_idstring = crypto_idstring_buf;
833 Crypto_BuildChallengeAppend();
835 // find a good prefix length for all the keys we know (yes, algorithm is not perfect yet, may yield too long prefix length)
836 crypto_keyfp_recommended_length = 0;
837 memset(buf+256, 0, MAX_PUBKEYS + MAX_PUBKEYS);
838 while(crypto_keyfp_recommended_length < FP64_SIZE)
841 for(i = 0; i < MAX_PUBKEYS; ++i)
845 ++buf[(unsigned char) pubkeys_fp64[i][crypto_keyfp_recommended_length]];
846 if(pubkeys_havepriv[i])
847 if(!buf[256 + MAX_PUBKEYS + i])
848 ++buf[(unsigned char) pubkeys_priv_fp64[i][crypto_keyfp_recommended_length]];
850 for(i = 0; i < MAX_PUBKEYS; ++i)
854 if(buf[(unsigned char) pubkeys_fp64[i][crypto_keyfp_recommended_length]] < 2)
856 if(pubkeys_havepriv[i])
857 if(!buf[256 + MAX_PUBKEYS + i])
858 if(buf[(unsigned char) pubkeys_priv_fp64[i][crypto_keyfp_recommended_length]] < 2)
859 buf[256 + MAX_PUBKEYS + i] = 1;
861 ++crypto_keyfp_recommended_length;
862 for(i = 0; i < MAX_PUBKEYS; ++i)
867 if(pubkeys_havepriv[i])
868 if(!buf[256 + MAX_PUBKEYS + i])
874 if(crypto_keyfp_recommended_length < 7)
875 crypto_keyfp_recommended_length = 7;
878 static void Crypto_UnloadKeys(void)
882 for(i = 0; i < MAX_PUBKEYS; ++i)
885 qd0_blind_id_free(pubkeys[i]);
887 pubkeys_havepriv[i] = false;
888 memset(pubkeys_fp64[i], 0, sizeof(pubkeys_fp64[i]));
889 memset(pubkeys_priv_fp64[i], 0, sizeof(pubkeys_fp64[i]));
890 challenge_append_length = 0;
892 crypto_idstring = NULL;
895 void Crypto_Shutdown(void)
900 Crypto_Rijndael_CloseLibrary();
905 for(i = 0; i < MAX_CRYPTOCONNECTS; ++i)
907 crypto = &cryptoconnects[i].crypto;
910 memset(cryptoconnects, 0, sizeof(cryptoconnects));
911 crypto = &cls.crypto;
916 qd0_blind_id_SHUTDOWN();
918 Crypto_CloseLibrary();
922 void Crypto_Init(void)
924 if(!Crypto_OpenLibrary())
927 if(!qd0_blind_id_INITIALIZE())
929 Crypto_Rijndael_CloseLibrary();
930 Crypto_CloseLibrary();
931 Con_Printf("libd0_blind_id initialization FAILED, cryptography support has been disabled\n");
935 Crypto_Rijndael_OpenLibrary(); // if this fails, it's uncritical
937 Crypto_InitHostKeys();
943 static void Crypto_KeyGen_Finished(int code, size_t length_received, unsigned char *buffer, void *cbdata)
947 static char buf[8192];
948 static char buf2[8192];
949 size_t bufsize, buf2size;
951 d0_blind_id_t *ctx, *ctx2;
957 Con_Print("libd0_blind_id DLL not found, this command is inactive.\n");
962 if(keygen_i >= MAX_PUBKEYS || !pubkeys[keygen_i])
964 Con_Printf("overflow of keygen_i\n");
970 Con_Printf("Unexpected response from keygen server:\n");
971 Com_HexDumpToConsole(buffer, length_received);
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);
988 if(!qd0_blind_id_finish_private_id_request(pubkeys[keygen_i], p[0], l[0]))
990 Con_Printf("d0_blind_id_finish_private_id_request failed\n");
995 // verify the key we just got (just in case)
996 ctx = qd0_blind_id_new();
999 Con_Printf("d0_blind_id_new failed\n");
1003 ctx2 = qd0_blind_id_new();
1006 Con_Printf("d0_blind_id_new failed\n");
1007 qd0_blind_id_free(ctx);
1011 if(!qd0_blind_id_copy(ctx, pubkeys[keygen_i]))
1013 Con_Printf("d0_blind_id_copy failed\n");
1014 qd0_blind_id_free(ctx);
1015 qd0_blind_id_free(ctx2);
1019 if(!qd0_blind_id_copy(ctx2, pubkeys[keygen_i]))
1021 Con_Printf("d0_blind_id_copy failed\n");
1022 qd0_blind_id_free(ctx);
1023 qd0_blind_id_free(ctx2);
1027 bufsize = sizeof(buf);
1028 if(!qd0_blind_id_authenticate_with_private_id_start(ctx, 1, 1, "hello world", 11, buf, &bufsize))
1030 Con_Printf("d0_blind_id_authenticate_with_private_id_start failed\n");
1031 qd0_blind_id_free(ctx);
1032 qd0_blind_id_free(ctx2);
1036 buf2size = sizeof(buf2);
1037 if(!qd0_blind_id_authenticate_with_private_id_challenge(ctx2, 1, 1, buf, bufsize, buf2, &buf2size, &status) || !status)
1039 Con_Printf("d0_blind_id_authenticate_with_private_id_challenge failed (server does not have the requested private key)\n");
1040 qd0_blind_id_free(ctx);
1041 qd0_blind_id_free(ctx2);
1045 bufsize = sizeof(buf);
1046 if(!qd0_blind_id_authenticate_with_private_id_response(ctx, buf2, buf2size, buf, &bufsize))
1048 Con_Printf("d0_blind_id_authenticate_with_private_id_response failed\n");
1049 qd0_blind_id_free(ctx);
1050 qd0_blind_id_free(ctx2);
1054 buf2size = sizeof(buf2);
1055 if(!qd0_blind_id_authenticate_with_private_id_verify(ctx2, buf, bufsize, buf2, &buf2size, &status) || !status)
1057 Con_Printf("d0_blind_id_authenticate_with_private_id_verify failed (server does not have the requested private key)\n");
1058 qd0_blind_id_free(ctx);
1059 qd0_blind_id_free(ctx2);
1063 qd0_blind_id_free(ctx);
1064 qd0_blind_id_free(ctx2);
1066 // we have a valid key now!
1067 // make the rest of crypto.c know that
1069 if(qd0_blind_id_fingerprint64_public_id(pubkeys[keygen_i], pubkeys_priv_fp64[keygen_i], &len2)) // keeps final NUL
1071 Con_Printf("Received private ID key_%d.d0pk (fingerprint: %s)\n", keygen_i, pubkeys_priv_fp64[keygen_i]);
1072 pubkeys_havepriv[keygen_i] = true;
1073 strlcat(crypto_idstring_buf, va(" %s@%s", pubkeys_priv_fp64[keygen_i], pubkeys_fp64[keygen_i]), sizeof(crypto_idstring_buf));
1074 crypto_idstring = crypto_idstring_buf;
1075 Crypto_BuildChallengeAppend();
1077 // write the key to disk
1080 if(!qd0_blind_id_write_private_id(pubkeys[keygen_i], buf, &l[0]))
1082 Con_Printf("d0_blind_id_write_private_id failed\n");
1086 if(!(buf2size = Crypto_UnParsePack(buf2, sizeof(buf2), FOURCC_D0SI, p, l, 1)))
1088 Con_Printf("Crypto_UnParsePack failed\n");
1095 FS_CreatePath(va("%skey_%d.d0si", fs_userdir, keygen_i));
1096 f = FS_SysOpen(va("%skey_%d.d0si", fs_userdir, keygen_i), "wb", false);
1100 FS_CreatePath(va("%skey_%d.d0si", fs_basedir, keygen_i));
1101 f = FS_SysOpen(va("%skey_%d.d0si", fs_basedir, keygen_i), "wb", false);
1105 Con_Printf("Cannot open key_%d.d0si\n", keygen_i);
1109 FS_Write(f, buf2, buf2size);
1112 Con_Printf("Saved to key_%d.d0si\n", keygen_i);
1116 static void Crypto_KeyGen_f(void)
1121 static char buf[8192];
1122 static char buf2[8192];
1123 size_t buf2l, buf2pos;
1124 if(!d0_blind_id_dll)
1126 Con_Print("libd0_blind_id DLL not found, this command is inactive.\n");
1131 Con_Printf("usage:\n%s id url\n", Cmd_Argv(0));
1134 i = atoi(Cmd_Argv(1));
1137 Con_Printf("there is no public key %d\n", i);
1140 if(pubkeys_havepriv[i])
1142 Con_Printf("there is already a private key for %d\n", i);
1147 Con_Printf("there is already a keygen run on the way\n");
1151 if(!qd0_blind_id_generate_private_id_start(pubkeys[keygen_i]))
1153 Con_Printf("d0_blind_id_start failed\n");
1159 if(!qd0_blind_id_generate_private_id_request(pubkeys[keygen_i], buf, &l[0]))
1161 Con_Printf("d0_blind_id_generate_private_id_request failed\n");
1165 buf2pos = strlen(Cmd_Argv(2));
1166 memcpy(buf2, Cmd_Argv(2), buf2pos);
1167 if(!(buf2l = Crypto_UnParsePack(buf2 + buf2pos, sizeof(buf2) - buf2pos - 1, FOURCC_D0IQ, p, l, 1)))
1169 Con_Printf("Crypto_UnParsePack failed\n");
1173 if(!(buf2l = base64_encode((unsigned char *) (buf2 + buf2pos), buf2l, sizeof(buf2) - buf2pos - 1)))
1175 Con_Printf("base64_encode failed\n");
1181 if(!Curl_Begin_ToMemory(buf2, 0, (unsigned char *) keygen_buf, sizeof(keygen_buf), Crypto_KeyGen_Finished, NULL))
1183 Con_Printf("curl failed\n");
1187 Con_Printf("key generation in progress\n");
1192 static void Crypto_Reload_f(void)
1194 Crypto_ClearHostKeys();
1195 Crypto_UnloadKeys();
1199 static void Crypto_Keys_f(void)
1202 if(!d0_blind_id_dll)
1204 Con_Print("libd0_blind_id DLL not found, this command is inactive.\n");
1207 for(i = 0; i < MAX_PUBKEYS; ++i)
1211 Con_Printf("%2d: public key key_%d.d0pk (fingerprint: %s)\n", i, i, pubkeys_fp64[i]);
1212 if(pubkeys_havepriv[i])
1213 Con_Printf(" private key key_%d.d0si (fingerprint: %s)\n", i, pubkeys_priv_fp64[i]);
1218 static void Crypto_HostKeys_f(void)
1221 crypto_storedhostkey_t *hk;
1224 if(!d0_blind_id_dll)
1226 Con_Print("libd0_blind_id DLL not found, this command is inactive.\n");
1229 for(i = 0; i < CRYPTO_HOSTKEY_HASHSIZE; ++i)
1231 for(hk = crypto_storedhostkey_hashtable[i]; hk; hk = hk->next)
1233 LHNETADDRESS_ToString(&hk->addr, buf, sizeof(buf), 1);
1234 Con_Printf("%d %s@%.*s %s\n",
1237 crypto_keyfp_recommended_length, pubkeys_fp64[hk->keyid],
1243 static void Crypto_HostKey_Clear_f(void)
1245 lhnetaddress_t addr;
1248 if(!d0_blind_id_dll)
1250 Con_Print("libd0_blind_id DLL not found, this command is inactive.\n");
1254 for(i = 1; i < Cmd_Argc(); ++i)
1256 LHNETADDRESS_FromString(&addr, Cmd_Argv(i), 26000);
1257 if(Crypto_ClearHostKey(&addr))
1259 Con_Printf("cleared host key for %s\n", Cmd_Argv(i));
1264 void Crypto_Init_Commands(void)
1268 Cmd_AddCommand("crypto_reload", Crypto_Reload_f, "reloads cryptographic keys");
1269 Cmd_AddCommand("crypto_keygen", Crypto_KeyGen_f, "generates and saves a cryptographic key");
1270 Cmd_AddCommand("crypto_keys", Crypto_Keys_f, "lists the loaded keys");
1271 Cmd_AddCommand("crypto_hostkeys", Crypto_HostKeys_f, "lists the cached host keys");
1272 Cmd_AddCommand("crypto_hostkey_clear", Crypto_HostKey_Clear_f, "clears a cached host key");
1273 Cvar_RegisterVariable(&crypto_developer);
1275 Cvar_RegisterVariable(&crypto_aeslevel);
1277 crypto_aeslevel.integer = 0; // make sure
1278 Cvar_RegisterVariable(&crypto_servercpupercent);
1279 Cvar_RegisterVariable(&crypto_servercpumaxtime);
1280 Cvar_RegisterVariable(&crypto_servercpudebug);
1286 static void aescpy(unsigned char *key, const unsigned char *iv, unsigned char *dst, const unsigned char *src, size_t len)
1288 const unsigned char *xorpos = iv;
1289 unsigned char xorbuf[16];
1290 unsigned long rk[D0_RIJNDAEL_RKLENGTH(DHKEY_SIZE * 8)];
1292 qd0_rijndael_setup_encrypt(rk, key, DHKEY_SIZE * 8);
1295 for(i = 0; i < 16; ++i)
1296 xorbuf[i] = src[i] ^ xorpos[i];
1297 qd0_rijndael_encrypt(rk, D0_RIJNDAEL_NROUNDS(DHKEY_SIZE * 8), xorbuf, dst);
1305 for(i = 0; i < len; ++i)
1306 xorbuf[i] = src[i] ^ xorpos[i];
1308 xorbuf[i] = xorpos[i];
1309 qd0_rijndael_encrypt(rk, D0_RIJNDAEL_NROUNDS(DHKEY_SIZE * 8), xorbuf, dst);
1312 static void seacpy(unsigned char *key, const unsigned char *iv, unsigned char *dst, const unsigned char *src, size_t len)
1314 const unsigned char *xorpos = iv;
1315 unsigned char xorbuf[16];
1316 unsigned long rk[D0_RIJNDAEL_RKLENGTH(DHKEY_SIZE * 8)];
1318 qd0_rijndael_setup_decrypt(rk, key, DHKEY_SIZE * 8);
1321 qd0_rijndael_decrypt(rk, D0_RIJNDAEL_NROUNDS(DHKEY_SIZE * 8), src, xorbuf);
1322 for(i = 0; i < 16; ++i)
1323 dst[i] = xorbuf[i] ^ xorpos[i];
1331 qd0_rijndael_decrypt(rk, D0_RIJNDAEL_NROUNDS(DHKEY_SIZE * 8), src, xorbuf);
1332 for(i = 0; i < len; ++i)
1333 dst[i] = xorbuf[i] ^ xorpos[i];
1337 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)
1339 unsigned char h[32];
1340 if(crypto->authenticated)
1344 // AES packet = 1 byte length overhead, 15 bytes from HMAC-SHA-256, data, 0..15 bytes padding
1345 // 15 bytes HMAC-SHA-256 (112bit) suffice as the attacker can't do more than forge a random-looking packet
1346 // HMAC is needed to not leak information about packet content
1347 if(developer_networking.integer)
1349 Con_Print("To be encrypted:\n");
1350 Com_HexDumpToConsole((const unsigned char *) data_src, len_src);
1352 if(len_src + 32 > len || !HMAC_SHA256_32BYTES(h, (const unsigned char *) data_src, len_src, crypto->dhkey, DHKEY_SIZE))
1354 Con_Printf("Crypto_EncryptPacket failed (not enough space: %d bytes in, %d bytes out)\n", (int) len_src, (int) len);
1357 *len_dst = ((len_src + 15) / 16) * 16 + 16; // add 16 for HMAC, then round to 16-size for AES
1358 ((unsigned char *) data_dst)[0] = *len_dst - len_src;
1359 memcpy(((unsigned char *) data_dst)+1, h, 15);
1360 aescpy(crypto->dhkey, (const unsigned char *) data_dst, ((unsigned char *) data_dst) + 16, (const unsigned char *) data_src, len_src);
1365 // HMAC packet = 16 bytes HMAC-SHA-256 (truncated to 128 bits), data
1366 if(len_src + 16 > len || !HMAC_SHA256_32BYTES(h, (const unsigned char *) data_src, len_src, crypto->dhkey, DHKEY_SIZE))
1368 Con_Printf("Crypto_EncryptPacket failed (not enough space: %d bytes in, %d bytes out)\n", (int) len_src, (int) len);
1371 *len_dst = len_src + 16;
1372 memcpy(data_dst, h, 16);
1373 memcpy(((unsigned char *) data_dst) + 16, (unsigned char *) data_src, len_src);
1384 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)
1386 unsigned char h[32];
1387 if(crypto->authenticated)
1391 if(len_src < 16 || ((len_src - 16) % 16))
1393 Con_Printf("Crypto_DecryptPacket failed (not enough space: %d bytes in, %d bytes out)\n", (int) len_src, (int) len);
1396 *len_dst = len_src - ((unsigned char *) data_src)[0];
1397 if(len < *len_dst || *len_dst > len_src - 16)
1399 Con_Printf("Crypto_DecryptPacket failed (not enough space: %d bytes in, %d->%d bytes out)\n", (int) len_src, (int) *len_dst, (int) len);
1402 seacpy(crypto->dhkey, (unsigned char *) data_src, (unsigned char *) data_dst, ((const unsigned char *) data_src) + 16, *len_dst);
1404 if(!HMAC_SHA256_32BYTES(h, (const unsigned char *) data_dst, *len_dst, crypto->dhkey, DHKEY_SIZE))
1406 Con_Printf("HMAC fail\n");
1409 if(memcmp(((const unsigned char *) data_src)+1, h, 15)) // ignore first byte, used for length
1411 Con_Printf("HMAC mismatch\n");
1414 if(developer_networking.integer)
1416 Con_Print("Decrypted:\n");
1417 Com_HexDumpToConsole((const unsigned char *) data_dst, *len_dst);
1419 return data_dst; // no need to copy
1425 Con_Printf("Crypto_DecryptPacket failed (not enough space: %d bytes in, %d bytes out)\n", (int) len_src, (int) len);
1428 *len_dst = len_src - 16;
1431 Con_Printf("Crypto_DecryptPacket failed (not enough space: %d bytes in, %d->%d bytes out)\n", (int) len_src, (int) *len_dst, (int) len);
1434 //memcpy(data_dst, data_src + 16, *len_dst);
1435 if(!HMAC_SHA256_32BYTES(h, ((const unsigned char *) data_src) + 16, *len_dst, crypto->dhkey, DHKEY_SIZE))
1437 Con_Printf("HMAC fail\n");
1438 Com_HexDumpToConsole((const unsigned char *) data_src, len_src);
1441 if(memcmp((const unsigned char *) data_src, h, 16)) // ignore first byte, used for length
1443 Con_Printf("HMAC mismatch\n");
1444 Com_HexDumpToConsole((const unsigned char *) data_src, len_src);
1447 return ((const unsigned char *) data_src) + 16; // no need to copy, so data_dst is not used
1458 const char *Crypto_GetInfoResponseDataString(void)
1460 crypto_idstring_buf[0] = '0' + crypto_aeslevel.integer;
1461 return crypto_idstring;
1465 qboolean Crypto_ServerAppendToChallenge(const char *data_in, size_t len_in, char *data_out, size_t *len_out, size_t maxlen_out)
1467 // cheap op, all is precomputed
1468 if(!d0_blind_id_dll)
1469 return false; // no support
1471 if(maxlen_out <= *len_out + challenge_append_length)
1473 memcpy(data_out + *len_out, challenge_append, challenge_append_length);
1474 *len_out += challenge_append_length;
1478 static int Crypto_ServerError(char *data_out, size_t *len_out, const char *msg, const char *msg_client)
1482 Con_DPrintf("rejecting client: %s\n", msg);
1484 dpsnprintf(data_out, *len_out, "reject %s", msg_client);
1485 *len_out = strlen(data_out);
1486 return CRYPTO_DISCARD;
1489 static int Crypto_SoftServerError(char *data_out, size_t *len_out, const char *msg)
1492 Con_DPrintf("%s\n", msg);
1493 return CRYPTO_DISCARD;
1496 static int Crypto_ServerParsePacket_Internal(const char *data_in, size_t len_in, char *data_out, size_t *len_out, lhnetaddress_t *peeraddress)
1498 // if "connect": reject if in the middle of crypto handshake
1499 crypto_t *crypto = NULL;
1500 char *data_out_p = data_out;
1501 const char *string = data_in;
1506 if(!d0_blind_id_dll)
1507 return CRYPTO_NOMATCH; // no support
1509 if (len_in > 8 && !memcmp(string, "connect\\", 8) && d0_rijndael_dll && crypto_aeslevel.integer >= 3)
1513 // sorry, we have to verify the challenge here to not reflect network spam
1515 if (!(s = SearchInfostring(string + 4, "challenge")))
1516 return CRYPTO_NOMATCH; // will be later accepted if encryption was set up
1517 // validate the challenge
1518 for (i = 0;i < MAX_CHALLENGES;i++)
1519 if(challenge[i].time > 0)
1520 if (!LHNETADDRESS_Compare(peeraddress, &challenge[i].address) && !strcmp(challenge[i].string, s))
1522 // if the challenge is not recognized, drop the packet
1523 if (i == MAX_CHALLENGES) // challenge mismatch is silent
1524 return CRYPTO_DISCARD; // pre-challenge: rather be silent
1526 crypto = Crypto_ServerFindInstance(peeraddress, false);
1527 if(!crypto || !crypto->authenticated)
1528 return Crypto_ServerError(data_out, len_out, "This server requires authentication and encryption to be supported by your client", NULL);
1530 else if(len_in > 5 && !memcmp(string, "d0pk\\", 5) && ((LHNETADDRESS_GetAddressType(peeraddress) == LHNETADDRESSTYPE_LOOP) || sv_public.integer > -3))
1532 const char *cnt, *s, *p;
1534 int clientid = -1, serverid = -1;
1535 cnt = SearchInfostring(string + 4, "id");
1536 id = (cnt ? atoi(cnt) : -1);
1537 cnt = SearchInfostring(string + 4, "cnt");
1539 return CRYPTO_DISCARD; // pre-challenge: rather be silent
1540 GetUntilNul(&data_in, &len_in);
1542 return CRYPTO_DISCARD; // pre-challenge: rather be silent
1543 if(!strcmp(cnt, "0"))
1546 if (!(s = SearchInfostring(string + 4, "challenge")))
1547 return CRYPTO_DISCARD; // pre-challenge: rather be silent
1548 // validate the challenge
1549 for (i = 0;i < MAX_CHALLENGES;i++)
1550 if(challenge[i].time > 0)
1551 if (!LHNETADDRESS_Compare(peeraddress, &challenge[i].address) && !strcmp(challenge[i].string, s))
1553 // if the challenge is not recognized, drop the packet
1554 if (i == MAX_CHALLENGES) // challenge mismatch is silent
1555 return CRYPTO_DISCARD; // pre-challenge: rather be silent
1557 if (!(s = SearchInfostring(string + 4, "aeslevel")))
1558 aeslevel = 0; // not supported
1560 aeslevel = bound(0, atoi(s), 3);
1561 switch(bound(0, d0_rijndael_dll ? crypto_aeslevel.integer : 0, 3))
1563 default: // dummy, never happens, but to make gcc happy...
1566 return Crypto_ServerError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)", NULL);
1570 aes = (aeslevel >= 2);
1573 aes = (aeslevel >= 1);
1577 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);
1582 p = GetUntilNul(&data_in, &len_in);
1585 for(i = 0; i < MAX_PUBKEYS; ++i)
1588 if(!strcmp(p, pubkeys_fp64[i]))
1589 if(pubkeys_havepriv[i])
1594 return Crypto_ServerError(data_out, len_out, "Invalid server key", NULL);
1596 p = GetUntilNul(&data_in, &len_in);
1599 for(i = 0; i < MAX_PUBKEYS; ++i)
1602 if(!strcmp(p, pubkeys_fp64[i]))
1607 return Crypto_ServerError(data_out, len_out, "Invalid client key", NULL);
1610 crypto = Crypto_ServerFindInstance(peeraddress, true);
1612 return Crypto_ServerError(data_out, len_out, "Could not create a crypto connect instance", NULL);
1614 CDATA->cdata_id = id;
1615 CDATA->s = serverid;
1616 CDATA->c = clientid;
1617 memset(crypto->dhkey, 0, sizeof(crypto->dhkey));
1618 CDATA->challenge[0] = 0;
1619 crypto->client_keyfp[0] = 0;
1620 crypto->client_idfp[0] = 0;
1621 crypto->server_keyfp[0] = 0;
1622 crypto->server_idfp[0] = 0;
1623 crypto->use_aes = aes != 0;
1627 // I am the server, and my key is ok... so let's set server_keyfp and server_idfp
1628 strlcpy(crypto->server_keyfp, pubkeys_fp64[CDATA->s], sizeof(crypto->server_keyfp));
1629 strlcpy(crypto->server_idfp, pubkeys_priv_fp64[CDATA->s], sizeof(crypto->server_idfp));
1632 CDATA->id = qd0_blind_id_new();
1636 return Crypto_ServerError(data_out, len_out, "d0_blind_id_new failed", "Internal error");
1638 if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->s]))
1641 return Crypto_ServerError(data_out, len_out, "d0_blind_id_copy failed", "Internal error");
1643 PutWithNul(&data_out_p, len_out, va("d0pk\\cnt\\1\\id\\%d\\aes\\%d", CDATA->cdata_id, crypto->use_aes));
1644 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
1647 return Crypto_ServerError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_start failed", "Internal error");
1649 CDATA->next_step = 2;
1650 data_out_p += *len_out;
1651 *len_out = data_out_p - data_out;
1652 return CRYPTO_DISCARD;
1654 else if(CDATA->c >= 0)
1657 CDATA->id = qd0_blind_id_new();
1661 return Crypto_ServerError(data_out, len_out, "d0_blind_id_new failed", "Internal error");
1663 if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->c]))
1666 return Crypto_ServerError(data_out, len_out, "d0_blind_id_copy failed", "Internal error");
1668 PutWithNul(&data_out_p, len_out, va("d0pk\\cnt\\5\\id\\%d\\aes\\%d", CDATA->cdata_id, crypto->use_aes));
1669 if(!qd0_blind_id_authenticate_with_private_id_challenge(CDATA->id, true, false, data_in, len_in, data_out_p, len_out, &status))
1672 return Crypto_ServerError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_challenge failed", "Internal error");
1674 CDATA->next_step = 6;
1675 data_out_p += *len_out;
1676 *len_out = data_out_p - data_out;
1677 return CRYPTO_DISCARD;
1682 return Crypto_ServerError(data_out, len_out, "Missing client and server key", NULL);
1685 else if(!strcmp(cnt, "2"))
1688 crypto = Crypto_ServerFindInstance(peeraddress, false);
1690 return CRYPTO_NOMATCH; // pre-challenge, rather be silent
1692 if(CDATA->cdata_id != id)
1693 return Crypto_SoftServerError(data_out, len_out, va("Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
1694 if(CDATA->next_step != 2)
1695 return Crypto_SoftServerError(data_out, len_out, va("Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
1697 PutWithNul(&data_out_p, len_out, va("d0pk\\cnt\\3\\id\\%d", CDATA->cdata_id));
1698 if(!qd0_blind_id_authenticate_with_private_id_response(CDATA->id, data_in, len_in, data_out_p, len_out))
1701 return Crypto_ServerError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_response failed", "Internal error");
1703 fpbuflen = DHKEY_SIZE;
1704 if(!qd0_blind_id_sessionkey_public_id(CDATA->id, (char *) crypto->dhkey, &fpbuflen))
1707 return Crypto_ServerError(data_out, len_out, "d0_blind_id_sessionkey_public_id failed", "Internal error");
1711 if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->c]))
1714 return Crypto_ServerError(data_out, len_out, "d0_blind_id_copy failed", "Internal error");
1716 CDATA->next_step = 4;
1720 // session key is FINISHED (no server part is to be expected)! By this, all keys are set up
1721 crypto->authenticated = true;
1722 CDATA->next_step = 0;
1724 data_out_p += *len_out;
1725 *len_out = data_out_p - data_out;
1726 return CRYPTO_DISCARD;
1728 else if(!strcmp(cnt, "4"))
1730 crypto = Crypto_ServerFindInstance(peeraddress, false);
1732 return CRYPTO_NOMATCH; // pre-challenge, rather be silent
1734 if(CDATA->cdata_id != id)
1735 return Crypto_SoftServerError(data_out, len_out, va("Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
1736 if(CDATA->next_step != 4)
1737 return Crypto_SoftServerError(data_out, len_out, va("Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
1738 PutWithNul(&data_out_p, len_out, va("d0pk\\cnt\\5\\id\\%d", CDATA->cdata_id));
1739 if(!qd0_blind_id_authenticate_with_private_id_challenge(CDATA->id, true, false, data_in, len_in, data_out_p, len_out, &status))
1742 return Crypto_ServerError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_challenge failed", "Internal error");
1744 CDATA->next_step = 6;
1745 data_out_p += *len_out;
1746 *len_out = data_out_p - data_out;
1747 return CRYPTO_DISCARD;
1749 else if(!strcmp(cnt, "6"))
1751 static char msgbuf[32];
1752 size_t msgbuflen = sizeof(msgbuf);
1755 unsigned char dhkey[DHKEY_SIZE];
1756 crypto = Crypto_ServerFindInstance(peeraddress, false);
1758 return CRYPTO_NOMATCH; // pre-challenge, rather be silent
1760 if(CDATA->cdata_id != id)
1761 return Crypto_SoftServerError(data_out, len_out, va("Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
1762 if(CDATA->next_step != 6)
1763 return Crypto_SoftServerError(data_out, len_out, va("Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
1765 if(!qd0_blind_id_authenticate_with_private_id_verify(CDATA->id, data_in, len_in, msgbuf, &msgbuflen, &status))
1768 return Crypto_ServerError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_verify failed (authentication error)", "Authentication error");
1771 strlcpy(crypto->client_keyfp, pubkeys_fp64[CDATA->c], sizeof(crypto->client_keyfp));
1773 crypto->client_keyfp[0] = 0;
1774 memset(crypto->client_idfp, 0, sizeof(crypto->client_idfp));
1775 fpbuflen = FP64_SIZE;
1776 if(!qd0_blind_id_fingerprint64_public_id(CDATA->id, crypto->client_idfp, &fpbuflen))
1779 return Crypto_ServerError(data_out, len_out, "d0_blind_id_fingerprint64_public_id failed", "Internal error");
1781 fpbuflen = DHKEY_SIZE;
1782 if(!qd0_blind_id_sessionkey_public_id(CDATA->id, (char *) dhkey, &fpbuflen))
1785 return Crypto_ServerError(data_out, len_out, "d0_blind_id_sessionkey_public_id failed", "Internal error");
1787 // XOR the two DH keys together to make one
1788 for(i = 0; i < DHKEY_SIZE; ++i)
1789 crypto->dhkey[i] ^= dhkey[i];
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;
1794 // send a challenge-less challenge
1795 PutWithNul(&data_out_p, len_out, "challenge ");
1796 *len_out = data_out_p - data_out;
1797 --*len_out; // remove NUL terminator
1798 return CRYPTO_MATCH;
1800 return CRYPTO_NOMATCH; // pre-challenge, rather be silent
1802 return CRYPTO_NOMATCH;
1805 int Crypto_ServerParsePacket(const char *data_in, size_t len_in, char *data_out, size_t *len_out, lhnetaddress_t *peeraddress)
1809 static double complain_time = 0;
1811 qboolean do_time = false;
1812 qboolean do_reject = false;
1813 if(crypto_servercpupercent.value > 0 || crypto_servercpumaxtime.value > 0)
1814 if(len_in > 5 && !memcmp(data_in, "d0pk\\", 5))
1817 cnt = SearchInfostring(data_in + 4, "cnt");
1819 if(!strcmp(cnt, "0"))
1824 // check if we may perform crypto...
1825 if(crypto_servercpupercent.value > 0)
1827 crypto_servercpu_accumulator += (realtime - crypto_servercpu_lastrealtime) * crypto_servercpupercent.value * 0.01;
1828 if(crypto_servercpumaxtime.value)
1829 if(crypto_servercpu_accumulator > crypto_servercpumaxtime.value)
1830 crypto_servercpu_accumulator = crypto_servercpumaxtime.value;
1834 if(crypto_servercpumaxtime.value > 0)
1835 if(realtime != crypto_servercpu_lastrealtime)
1836 crypto_servercpu_accumulator = crypto_servercpumaxtime.value;
1838 crypto_servercpu_lastrealtime = realtime;
1839 if(do_reject && crypto_servercpu_accumulator < 0)
1841 if(realtime > complain_time + 5)
1842 Con_Printf("crypto: cannot perform requested crypto operations; denial service attack or crypto_servercpupercent/crypto_servercpumaxtime are too low\n");
1844 return CRYPTO_DISCARD;
1846 t = Sys_DoubleTime();
1848 ret = Crypto_ServerParsePacket_Internal(data_in, len_in, data_out, len_out, peeraddress);
1851 t = Sys_DoubleTime() - t;
1852 if(crypto_servercpudebug.integer)
1853 Con_Printf("crypto: accumulator was %.1f ms, used %.1f ms for crypto, ", crypto_servercpu_accumulator * 1000, t * 1000);
1854 crypto_servercpu_accumulator -= t;
1855 if(crypto_servercpudebug.integer)
1856 Con_Printf("is %.1f ms\n", crypto_servercpu_accumulator * 1000);
1861 static int Crypto_ClientError(char *data_out, size_t *len_out, const char *msg)
1863 dpsnprintf(data_out, *len_out, "reject %s", msg);
1864 *len_out = strlen(data_out);
1865 return CRYPTO_REPLACE;
1868 static int Crypto_SoftClientError(char *data_out, size_t *len_out, const char *msg)
1871 Con_Printf("%s\n", msg);
1872 return CRYPTO_DISCARD;
1875 int Crypto_ClientParsePacket(const char *data_in, size_t len_in, char *data_out, size_t *len_out, lhnetaddress_t *peeraddress)
1877 crypto_t *crypto = &cls.crypto;
1878 const char *string = data_in;
1881 char *data_out_p = data_out;
1884 if(!d0_blind_id_dll)
1885 return CRYPTO_NOMATCH; // no support
1887 // if "challenge": verify challenge, and discard message, send next crypto protocol message instead
1888 // otherwise, just handle actual protocol messages
1890 if (len_in == 6 && !memcmp(string, "accept", 6) && cls.connect_trying && d0_rijndael_dll)
1892 int wantserverid = -1;
1893 Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, NULL, 0, NULL);
1894 if(!crypto || !crypto->authenticated)
1896 if(wantserverid >= 0)
1897 return Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though a host key is present");
1898 if(crypto_aeslevel.integer >= 3)
1899 return Crypto_ClientError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)");
1901 return CRYPTO_NOMATCH;
1903 else if (len_in >= 1 && string[0] == 'j' && cls.connect_trying && d0_rijndael_dll && crypto_aeslevel.integer >= 3)
1905 int wantserverid = -1;
1906 Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, NULL, 0, NULL);
1907 if(!crypto || !crypto->authenticated)
1909 if(wantserverid >= 0)
1910 return Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though a host key is present");
1911 if(crypto_aeslevel.integer >= 3)
1912 return Crypto_ClientError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)");
1914 return CRYPTO_NOMATCH;
1916 else if (len_in >= 13 && !memcmp(string, "infoResponse\x0A", 13))
1918 s = SearchInfostring(string + 13, "d0_blind_id");
1920 Crypto_StoreHostKey(peeraddress, s, true);
1921 return CRYPTO_NOMATCH;
1923 else if (len_in >= 15 && !memcmp(string, "statusResponse\x0A", 15))
1927 p = strchr(string + 15, '\n');
1931 * (char *) p = 0; // cut off the string there
1933 s = SearchInfostring(string + 15, "d0_blind_id");
1935 Crypto_StoreHostKey(peeraddress, s, true);
1938 * (char *) p = save;
1939 // invoking those nasal demons again (do not run this on the DS9k)
1941 return CRYPTO_NOMATCH;
1943 else if(len_in > 10 && !memcmp(string, "challenge ", 10) && cls.connect_trying)
1945 const char *vlen_blind_id_ptr = NULL;
1946 size_t len_blind_id_ptr = 0;
1948 const char *challenge = data_in + 10;
1951 int clientid = -1, serverid = -1, wantserverid = -1;
1952 qboolean server_can_auth = true;
1953 char wantserver_idfp[FP64_SIZE+1];
1954 int wantserver_aeslevel;
1956 // if we have a stored host key for the server, assume serverid to already be selected!
1957 // (the loop will refuse to overwrite this one then)
1958 wantserver_idfp[0] = 0;
1959 Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, wantserver_idfp, sizeof(wantserver_idfp), &wantserver_aeslevel);
1960 // requirement: wantserver_idfp is a full ID if wantserverid set
1962 // if we leave, we have to consider the connection
1963 // unauthenticated; NOTE: this may be faked by a clever
1964 // attacker to force an unauthenticated connection; so we have
1965 // a safeguard check in place when encryption is required too
1966 // in place, or when authentication is required by the server
1967 crypto->authenticated = false;
1969 GetUntilNul(&data_in, &len_in);
1971 return (wantserverid >= 0) ? Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though a host key is present") :
1972 (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) :
1975 // FTEQW extension protocol
1978 k = Crypto_LittleLong(data_in);
1979 v = Crypto_LittleLong(data_in + 4);
1987 k = Crypto_LittleLong(data_in);
1992 case PROTOCOL_D0_BLIND_ID:
1993 vlen_blind_id_ptr = data_in;
1994 len_blind_id_ptr = v;
2006 if(!vlen_blind_id_ptr)
2007 return (wantserverid >= 0) ? Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though authentication is required") :
2008 (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) :
2011 data_in = vlen_blind_id_ptr;
2012 len_in = len_blind_id_ptr;
2014 // parse fingerprints
2015 // once we found a fingerprint we can auth to (ANY), select it as clientfp
2016 // once we found a fingerprint in the first list that we know, select it as serverfp
2020 p = GetUntilNul(&data_in, &len_in);
2025 if(!server_can_auth)
2026 break; // other protocol message may follow
2027 server_can_auth = false;
2032 for(i = 0; i < MAX_PUBKEYS; ++i)
2035 if(!strcmp(p, pubkeys_fp64[i]))
2037 if(pubkeys_havepriv[i])
2042 if(wantserverid < 0 || i == wantserverid)
2046 if(clientid >= 0 && serverid >= 0)
2050 // if stored host key is not found:
2051 if(wantserverid >= 0 && serverid < 0)
2052 return Crypto_ClientError(data_out, len_out, "Server CA does not match stored host key, refusing to connect");
2054 if(serverid >= 0 || clientid >= 0)
2056 // TODO at this point, fill clientside crypto struct!
2058 CDATA->cdata_id = ++cdata_id;
2059 CDATA->s = serverid;
2060 CDATA->c = clientid;
2061 memset(crypto->dhkey, 0, sizeof(crypto->dhkey));
2062 strlcpy(CDATA->challenge, challenge, sizeof(CDATA->challenge));
2063 crypto->client_keyfp[0] = 0;
2064 crypto->client_idfp[0] = 0;
2065 crypto->server_keyfp[0] = 0;
2066 crypto->server_idfp[0] = 0;
2067 memcpy(CDATA->wantserver_idfp, wantserver_idfp, sizeof(crypto->server_idfp));
2069 if(CDATA->wantserver_idfp[0]) // if we know a host key, honor its encryption setting
2070 switch(bound(0, d0_rijndael_dll ? crypto_aeslevel.integer : 0, 3))
2072 default: // dummy, never happens, but to make gcc happy...
2074 if(wantserver_aeslevel >= 3)
2075 return Crypto_ServerError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)", NULL);
2076 CDATA->wantserver_aes = false;
2079 CDATA->wantserver_aes = (wantserver_aeslevel >= 2);
2082 CDATA->wantserver_aes = (wantserver_aeslevel >= 1);
2085 if(wantserver_aeslevel <= 0)
2086 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);
2087 CDATA->wantserver_aes = true;
2091 // build outgoing message
2092 // append regular stuff
2093 PutWithNul(&data_out_p, len_out, va("d0pk\\cnt\\0\\id\\%d\\aeslevel\\%d\\challenge\\%s", CDATA->cdata_id, d0_rijndael_dll ? crypto_aeslevel.integer : 0, challenge));
2094 PutWithNul(&data_out_p, len_out, serverid >= 0 ? pubkeys_fp64[serverid] : "");
2095 PutWithNul(&data_out_p, len_out, clientid >= 0 ? pubkeys_fp64[clientid] : "");
2099 // I am the client, and my key is ok... so let's set client_keyfp and client_idfp
2100 strlcpy(crypto->client_keyfp, pubkeys_fp64[CDATA->c], sizeof(crypto->client_keyfp));
2101 strlcpy(crypto->client_idfp, pubkeys_priv_fp64[CDATA->c], sizeof(crypto->client_idfp));
2107 CDATA->id = qd0_blind_id_new();
2111 return Crypto_ClientError(data_out, len_out, "d0_blind_id_new failed");
2113 if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->s]))
2116 return Crypto_ClientError(data_out, len_out, "d0_blind_id_copy failed");
2118 CDATA->next_step = 1;
2119 *len_out = data_out_p - data_out;
2121 else if(clientid >= 0)
2123 // skip over server auth, perform client auth only
2125 CDATA->id = qd0_blind_id_new();
2129 return Crypto_ClientError(data_out, len_out, "d0_blind_id_new failed");
2131 if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->c]))
2134 return Crypto_ClientError(data_out, len_out, "d0_blind_id_copy failed");
2136 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
2139 return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_start failed");
2141 CDATA->next_step = 5;
2142 data_out_p += *len_out;
2143 *len_out = data_out_p - data_out;
2146 *len_out = data_out_p - data_out;
2148 return CRYPTO_DISCARD;
2152 if(wantserver_idfp[0]) // if we know a host key, honor its encryption setting
2153 if(wantserver_aeslevel >= 3)
2154 return Crypto_ClientError(data_out, len_out, "Server insists on encryption, but neither can authenticate to the other");
2155 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) :
2159 else if(len_in > 5 && !memcmp(string, "d0pk\\", 5) && cls.connect_trying)
2163 cnt = SearchInfostring(string + 4, "id");
2164 id = (cnt ? atoi(cnt) : -1);
2165 cnt = SearchInfostring(string + 4, "cnt");
2167 return Crypto_ClientError(data_out, len_out, "d0pk\\ message without cnt");
2168 GetUntilNul(&data_in, &len_in);
2170 return Crypto_ClientError(data_out, len_out, "d0pk\\ message without attachment");
2172 if(!strcmp(cnt, "1"))
2175 if(CDATA->cdata_id != id)
2176 return Crypto_SoftServerError(data_out, len_out, va("Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
2177 if(CDATA->next_step != 1)
2178 return Crypto_SoftClientError(data_out, len_out, va("Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
2180 cls.connect_nextsendtime = max(cls.connect_nextsendtime, realtime + 1); // prevent "hammering"
2182 if((s = SearchInfostring(string + 4, "aes")))
2186 // we CANNOT toggle the AES status any more!
2187 // as the server already decided
2188 if(CDATA->wantserver_idfp[0]) // if we know a host key, honor its encryption setting
2189 if(!aes && CDATA->wantserver_aes)
2192 return Crypto_ClientError(data_out, len_out, "Stored host key requires encryption, but server did not enable encryption");
2194 if(aes && (!d0_rijndael_dll || crypto_aeslevel.integer <= 0))
2197 return Crypto_ClientError(data_out, len_out, "Server insists on encryption too hard");
2199 if(!aes && (d0_rijndael_dll && crypto_aeslevel.integer >= 3))
2202 return Crypto_ClientError(data_out, len_out, "Server insists on plaintext too hard");
2204 crypto->use_aes = aes != 0;
2206 PutWithNul(&data_out_p, len_out, va("d0pk\\cnt\\2\\id\\%d", CDATA->cdata_id));
2207 if(!qd0_blind_id_authenticate_with_private_id_challenge(CDATA->id, true, false, data_in, len_in, data_out_p, len_out, &status))
2210 return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_challenge failed");
2212 CDATA->next_step = 3;
2213 data_out_p += *len_out;
2214 *len_out = data_out_p - data_out;
2215 return CRYPTO_DISCARD;
2217 else if(!strcmp(cnt, "3"))
2219 static char msgbuf[32];
2220 size_t msgbuflen = sizeof(msgbuf);
2224 if(CDATA->cdata_id != id)
2225 return Crypto_SoftServerError(data_out, len_out, va("Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
2226 if(CDATA->next_step != 3)
2227 return Crypto_SoftClientError(data_out, len_out, va("Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
2229 cls.connect_nextsendtime = max(cls.connect_nextsendtime, realtime + 1); // prevent "hammering"
2231 if(!qd0_blind_id_authenticate_with_private_id_verify(CDATA->id, data_in, len_in, msgbuf, &msgbuflen, &status))
2234 return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_verify failed (server authentication error)");
2237 strlcpy(crypto->server_keyfp, pubkeys_fp64[CDATA->s], sizeof(crypto->server_keyfp));
2239 crypto->server_keyfp[0] = 0;
2240 memset(crypto->server_idfp, 0, sizeof(crypto->server_idfp));
2241 fpbuflen = FP64_SIZE;
2242 if(!qd0_blind_id_fingerprint64_public_id(CDATA->id, crypto->server_idfp, &fpbuflen))
2245 return Crypto_ClientError(data_out, len_out, "d0_blind_id_fingerprint64_public_id failed");
2247 if(CDATA->wantserver_idfp[0])
2248 if(memcmp(CDATA->wantserver_idfp, crypto->server_idfp, sizeof(crypto->server_idfp)))
2251 return Crypto_ClientError(data_out, len_out, "Server ID does not match stored host key, refusing to connect");
2253 fpbuflen = DHKEY_SIZE;
2254 if(!qd0_blind_id_sessionkey_public_id(CDATA->id, (char *) crypto->dhkey, &fpbuflen))
2257 return Crypto_ClientError(data_out, len_out, "d0_blind_id_sessionkey_public_id failed");
2260 // cache the server key
2261 Crypto_StoreHostKey(&cls.connect_address, va("%d %s@%s", crypto->use_aes ? 1 : 0, crypto->server_idfp, pubkeys_fp64[CDATA->s]), false);
2265 // client will auth next
2266 PutWithNul(&data_out_p, len_out, va("d0pk\\cnt\\4\\id\\%d", CDATA->cdata_id));
2267 if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->c]))
2270 return Crypto_ClientError(data_out, len_out, "d0_blind_id_copy failed");
2272 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
2275 return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_start failed");
2277 CDATA->next_step = 5;
2278 data_out_p += *len_out;
2279 *len_out = data_out_p - data_out;
2280 return CRYPTO_DISCARD;
2284 // session key is FINISHED (no server part is to be expected)! By this, all keys are set up
2285 crypto->authenticated = true;
2286 CDATA->next_step = 0;
2287 // assume we got the empty challenge to finish the protocol
2288 PutWithNul(&data_out_p, len_out, "challenge ");
2289 *len_out = data_out_p - data_out;
2290 --*len_out; // remove NUL terminator
2291 return CRYPTO_REPLACE;
2294 else if(!strcmp(cnt, "5"))
2297 unsigned char dhkey[DHKEY_SIZE];
2301 if(CDATA->cdata_id != id)
2302 return Crypto_SoftServerError(data_out, len_out, va("Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
2303 if(CDATA->next_step != 5)
2304 return Crypto_SoftClientError(data_out, len_out, va("Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
2306 cls.connect_nextsendtime = max(cls.connect_nextsendtime, realtime + 1); // prevent "hammering"
2308 if(CDATA->s < 0) // only if server didn't auth
2310 if((s = SearchInfostring(string + 4, "aes")))
2314 if(CDATA->wantserver_idfp[0]) // if we know a host key, honor its encryption setting
2315 if(!aes && CDATA->wantserver_aes)
2318 return Crypto_ClientError(data_out, len_out, "Stored host key requires encryption, but server did not enable encryption");
2320 if(aes && (!d0_rijndael_dll || crypto_aeslevel.integer <= 0))
2323 return Crypto_ClientError(data_out, len_out, "Server insists on encryption too hard");
2325 if(!aes && (d0_rijndael_dll && crypto_aeslevel.integer >= 3))
2328 return Crypto_ClientError(data_out, len_out, "Server insists on plaintext too hard");
2330 crypto->use_aes = aes != 0;
2333 PutWithNul(&data_out_p, len_out, va("d0pk\\cnt\\6\\id\\%d", CDATA->cdata_id));
2334 if(!qd0_blind_id_authenticate_with_private_id_response(CDATA->id, data_in, len_in, data_out_p, len_out))
2337 return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_response failed");
2339 fpbuflen = DHKEY_SIZE;
2340 if(!qd0_blind_id_sessionkey_public_id(CDATA->id, (char *) dhkey, &fpbuflen))
2343 return Crypto_ClientError(data_out, len_out, "d0_blind_id_sessionkey_public_id failed");
2345 // XOR the two DH keys together to make one
2346 for(i = 0; i < DHKEY_SIZE; ++i)
2347 crypto->dhkey[i] ^= dhkey[i];
2348 // session key is FINISHED! By this, all keys are set up
2349 crypto->authenticated = true;
2350 CDATA->next_step = 0;
2351 data_out_p += *len_out;
2352 *len_out = data_out_p - data_out;
2353 return CRYPTO_DISCARD;
2355 return Crypto_SoftClientError(data_out, len_out, "Got unknown d0_blind_id message from server");
2358 return CRYPTO_NOMATCH;