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