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