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