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