DarkPlaces
Game engine based on the Quake 1 engine by id Software, developed by LadyHavoc
 
crypto.h File Reference
#include <stddef.h>
#include "qtypes.h"
+ Include dependency graph for crypto.h:
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  crypto_t
 

Macros

#define CRYPTO_DISCARD   2
 
#define CRYPTO_HEADERSIZE   31
 
#define CRYPTO_MATCH   1
 
#define CRYPTO_NOMATCH   0
 
#define CRYPTO_REPLACE   3
 
#define DHKEY_SIZE   16
 
#define ENCRYPTION_REQUIRED   (crypto_aeslevel.integer >= 3)
 
#define FP64_SIZE   44
 

Functions

qbool Crypto_Available (void)
 
int Crypto_ClientParsePacket (const char *data_in, size_t len_in, char *data_out, size_t *len_out, lhnetaddress_t *peeraddress, const char *peeraddressstring)
 
const voidCrypto_DecryptPacket (crypto_t *crypto, const void *data_src, size_t len_src, void *data_dst, size_t *len_dst, size_t len)
 
const voidCrypto_EncryptPacket (crypto_t *crypto, const void *data_src, size_t len_src, void *data_dst, size_t *len_dst, size_t len)
 
qbool Crypto_FinishInstance (crypto_t *out, crypto_t *in)
 
const char * Crypto_GetInfoResponseDataString (void)
 
void Crypto_Init (void)
 
void Crypto_Init_Commands (void)
 
void Crypto_LoadKeys (void)
 
qbool Crypto_RetrieveHostKey (struct lhnetaddress_s *peeraddress, int *keyid, char *keyfp, size_t keyfplen, char *idfp, size_t idfplen, int *aeslevel, qbool *issigned)
 
int Crypto_RetrieveLocalKey (int keyid, char *keyfp, size_t keyfplen, char *idfp, size_t idfplen, qbool *issigned)
 
qbool Crypto_ServerAppendToChallenge (const char *data_in, size_t len_in, char *data_out, size_t *len_out, size_t maxlen)
 
crypto_tCrypto_ServerGetInstance (struct lhnetaddress_s *peeraddress)
 
int Crypto_ServerParsePacket (const char *data_in, size_t len_in, char *data_out, size_t *len_out, lhnetaddress_t *peeraddress)
 
void Crypto_Shutdown (void)
 
size_t Crypto_SignData (const void *data, size_t datasize, int keyid, void *signed_data, size_t signed_size)
 
size_t Crypto_SignDataDetached (const void *data, size_t datasize, int keyid, void *signed_data, size_t signed_size)
 
void sha256 (unsigned char *out, const unsigned char *in, int n)
 

Variables

struct cvar_s crypto_aeslevel
 
struct cvar_s crypto_developer
 
int crypto_keyfp_recommended_length
 

Macro Definition Documentation

◆ CRYPTO_DISCARD

◆ CRYPTO_HEADERSIZE

#define CRYPTO_HEADERSIZE   31

◆ CRYPTO_MATCH

#define CRYPTO_MATCH   1

◆ CRYPTO_NOMATCH

#define CRYPTO_NOMATCH   0

◆ CRYPTO_REPLACE

#define CRYPTO_REPLACE   3

◆ DHKEY_SIZE

#define DHKEY_SIZE   16

◆ ENCRYPTION_REQUIRED

#define ENCRYPTION_REQUIRED   (crypto_aeslevel.integer >= 3)

Definition at line 30 of file crypto.h.

Referenced by NetConn_ClientParsePacket(), and NetConn_ServerParsePacket().

◆ FP64_SIZE

Function Documentation

◆ Crypto_Available()

qbool Crypto_Available ( void )

Definition at line 1097 of file crypto.c.

1098{
1099 if(!d0_blind_id_dll)
1100 return false;
1101 return true;
1102}
static dllhandle_t d0_blind_id_dll
Definition crypto.c:282

References d0_blind_id_dll.

Referenced by checkextension(), and VM_digest_hex().

◆ Crypto_ClientParsePacket()

int Crypto_ClientParsePacket ( const char * data_in,
size_t len_in,
char * data_out,
size_t * len_out,
lhnetaddress_t * peeraddress,
const char * peeraddressstring )

Definition at line 2107 of file crypto.c.

2108{
2109 crypto_t *crypto = &cls.crypto;
2110 const char *string = data_in;
2111 D0_BOOL aes;
2112 char *data_out_p = data_out;
2113 D0_BOOL status;
2114 char infostringvalue[MAX_INPUTLINE];
2115 char vabuf[1024];
2116
2117 if(!d0_blind_id_dll)
2118 return CRYPTO_NOMATCH; // no support
2119
2120 // if "challenge": verify challenge, and discard message, send next crypto protocol message instead
2121 // otherwise, just handle actual protocol messages
2122
2123 if (len_in == 6 && !memcmp(string, "accept", 6) && cls.connect_trying && d0_rijndael_dll)
2124 {
2125 int wantserverid = -1;
2126 Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, NULL, 0, NULL, NULL);
2127 if(!crypto || !crypto->authenticated) // we ALSO get here if we are using an encrypted connection, so let's rule this out
2128 {
2129 if(wantserverid >= 0)
2130 return Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though a host key is present");
2131 if(crypto_aeslevel.integer >= 3)
2132 return Crypto_ClientError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)");
2133 }
2134 return CRYPTO_NOMATCH;
2135 }
2136 else if (len_in >= 1 && string[0] == 'j' && cls.connect_trying && d0_rijndael_dll)
2137 {
2138 int wantserverid = -1;
2139 Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, NULL, 0, NULL, NULL);
2140 //if(!crypto || !crypto->authenticated)
2141 {
2142 if(wantserverid >= 0)
2143 return Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though a host key is present");
2144 if(crypto_aeslevel.integer >= 3)
2145 return Crypto_ClientError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)");
2146 }
2147 return CRYPTO_NOMATCH;
2148 }
2149 else if (len_in >= 5 && BuffLittleLong((unsigned char *) string) == ((int)NETFLAG_CTL | (int)len_in))
2150 {
2151 int wantserverid = -1;
2152
2153 // these three are harmless
2154 if((unsigned char) string[4] == CCREP_SERVER_INFO)
2155 return CRYPTO_NOMATCH;
2156 if((unsigned char) string[4] == CCREP_PLAYER_INFO)
2157 return CRYPTO_NOMATCH;
2158 if((unsigned char) string[4] == CCREP_RULE_INFO)
2159 return CRYPTO_NOMATCH;
2160
2161 Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, NULL, 0, NULL, NULL);
2162 //if(!crypto || !crypto->authenticated)
2163 {
2164 if(wantserverid >= 0)
2165 return Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though a host key is present");
2166 if(crypto_aeslevel.integer >= 3)
2167 return Crypto_ClientError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)");
2168 }
2169 return CRYPTO_NOMATCH;
2170 }
2171 else if (len_in >= 13 && !memcmp(string, "infoResponse\x0A", 13))
2172 {
2173 if(InfoString_GetValue(string + 13, "d0_blind_id", infostringvalue, sizeof(infostringvalue)))
2174 Crypto_StoreHostKey(peeraddress, infostringvalue, true);
2175 return CRYPTO_NOMATCH;
2176 }
2177 else if (len_in >= 15 && !memcmp(string, "statusResponse\x0A", 15))
2178 {
2179 char save = 0;
2180 const char *p;
2181 p = strchr(string + 15, '\n');
2182 if(p)
2183 {
2184 save = *p;
2185 * (char *) p = 0; // cut off the string there
2186 }
2187 if(InfoString_GetValue(string + 15, "d0_blind_id", infostringvalue, sizeof(infostringvalue)))
2188 Crypto_StoreHostKey(peeraddress, infostringvalue, true);
2189 if(p)
2190 {
2191 * (char *) p = save;
2192 // invoking those nasal demons again (do not run this on the DS9k)
2193 }
2194 return CRYPTO_NOMATCH;
2195 }
2196 else if(len_in > 10 && !memcmp(string, "challenge ", 10) && cls.connect_trying)
2197 {
2198 const char *vlen_blind_id_ptr = NULL;
2199 size_t len_blind_id_ptr = 0;
2200 unsigned long k, v;
2201 const char *challenge = data_in + 10;
2202 const char *p;
2203 int i;
2204 int clientid = -1, serverid = -1, wantserverid = -1;
2205 qbool server_can_auth = true;
2206 char wantserver_idfp[FP64_SIZE+1];
2207 int wantserver_aeslevel = 0;
2208 qbool wantserver_issigned = false;
2209
2210 // Must check the source IP here, if we want to prevent other servers' replies from falsely advancing the crypto state, preventing successful connect to the real server.
2212 {
2213 char warn_msg[128];
2214
2215 dpsnprintf(warn_msg, sizeof(warn_msg), "ignoring challenge message from wrong server %s", peeraddressstring);
2216 return Crypto_SoftClientError(data_out, len_out, warn_msg);
2217 }
2218
2219 // if we have a stored host key for the server, assume serverid to already be selected!
2220 // (the loop will refuse to overwrite this one then)
2221 wantserver_idfp[0] = 0;
2222 Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, wantserver_idfp, sizeof(wantserver_idfp), &wantserver_aeslevel, &wantserver_issigned);
2223 // requirement: wantserver_idfp is a full ID if wantserverid set
2224
2225 // if we leave, we have to consider the connection
2226 // unauthenticated; NOTE: this may be faked by a clever
2227 // attacker to force an unauthenticated connection; so we have
2228 // a safeguard check in place when encryption is required too
2229 // in place, or when authentication is required by the server
2230 crypto->authenticated = false;
2231
2232 GetUntilNul(&data_in, &len_in);
2233 if(!data_in)
2234 return (wantserverid >= 0) ? Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though a host key is present") :
2235 (d0_rijndael_dll && crypto_aeslevel.integer >= 3) ? Crypto_ClientError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)") :
2237
2238 // FTEQW extension protocol
2239 while(len_in >= 8)
2240 {
2241 k = Crypto_LittleLong(data_in);
2242 v = Crypto_LittleLong(data_in + 4);
2243 data_in += 8;
2244 len_in -= 8;
2245 switch(k)
2246 {
2247 case PROTOCOL_VLEN:
2248 if(len_in >= 4 + v)
2249 {
2250 k = Crypto_LittleLong(data_in);
2251 data_in += 4;
2252 len_in -= 4;
2253 switch(k)
2254 {
2256 vlen_blind_id_ptr = data_in;
2257 len_blind_id_ptr = v;
2258 break;
2259 }
2260 data_in += v;
2261 len_in -= v;
2262 }
2263 break;
2264 default:
2265 break;
2266 }
2267 }
2268
2269 if(!vlen_blind_id_ptr)
2270 return (wantserverid >= 0) ? Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though authentication is required") :
2271 (d0_rijndael_dll && crypto_aeslevel.integer >= 3) ? Crypto_ClientError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)") :
2273
2274 data_in = vlen_blind_id_ptr;
2275 len_in = len_blind_id_ptr;
2276
2277 // parse fingerprints
2278 // once we found a fingerprint we can auth to (ANY), select it as clientfp
2279 // once we found a fingerprint in the first list that we know, select it as serverfp
2280
2281 for(;;)
2282 {
2283 p = GetUntilNul(&data_in, &len_in);
2284 if(!p)
2285 break;
2286 if(!*p)
2287 {
2288 if(!server_can_auth)
2289 break; // other protocol message may follow
2290 server_can_auth = false;
2291 if(clientid >= 0)
2292 break;
2293 continue;
2294 }
2295 // Find the highest numbered matching key for p.
2296 for(i = 0; i < MAX_PUBKEYS; ++i)
2297 {
2298 if(pubkeys[i])
2299 if(!strcmp(p, pubkeys_fp64[i]))
2300 {
2301 if(pubkeys_havepriv[i])
2302 clientid = i;
2303 if(server_can_auth)
2304 if(wantserverid < 0 || i == wantserverid)
2305 serverid = i;
2306 }
2307 }
2308 // Not breaking, as higher keys in the list always have priority.
2309 }
2310
2311 // if stored host key is not found:
2312 if(wantserverid >= 0 && serverid < 0)
2313 return Crypto_ClientError(data_out, len_out, "Server CA does not match stored host key, refusing to connect");
2314
2315 if(serverid >= 0 || clientid >= 0)
2316 {
2317 MAKE_CDATA;
2318 CDATA->cdata_id = ++cdata_id;
2319 CDATA->s = serverid;
2320 CDATA->c = clientid;
2321 memset(crypto->dhkey, 0, sizeof(crypto->dhkey));
2322 dp_strlcpy(CDATA->challenge, challenge, sizeof(CDATA->challenge));
2323 crypto->client_keyfp[0] = 0;
2324 crypto->client_idfp[0] = 0;
2325 crypto->server_keyfp[0] = 0;
2326 crypto->server_idfp[0] = 0;
2327 memcpy(CDATA->wantserver_idfp, wantserver_idfp, sizeof(crypto->server_idfp));
2328 CDATA->wantserver_issigned = wantserver_issigned;
2329
2330 if(CDATA->wantserver_idfp[0]) // if we know a host key, honor its encryption setting
2331 switch(bound(0, d0_rijndael_dll ? crypto_aeslevel.integer : 0, 3))
2332 {
2333 default: // dummy, never happens, but to make gcc happy...
2334 case 0:
2335 if(wantserver_aeslevel >= 3)
2336 return Crypto_ClientError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)");
2337 CDATA->wantserver_aes = false;
2338 break;
2339 case 1:
2340 CDATA->wantserver_aes = (wantserver_aeslevel >= 2);
2341 break;
2342 case 2:
2343 CDATA->wantserver_aes = (wantserver_aeslevel >= 1);
2344 break;
2345 case 3:
2346 if(wantserver_aeslevel <= 0)
2347 return Crypto_ClientError(data_out, len_out, "This server requires encryption to be supported (crypto_aeslevel >= 1, and d0_rijndael library must be present)");
2348 CDATA->wantserver_aes = true;
2349 break;
2350 }
2351
2352 // build outgoing message
2353 // append regular stuff
2354 PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\0\\id\\%d\\aeslevel\\%d\\challenge\\%s", CDATA->cdata_id, d0_rijndael_dll ? crypto_aeslevel.integer : 0, challenge));
2355 PutWithNul(&data_out_p, len_out, serverid >= 0 ? pubkeys_fp64[serverid] : "");
2356 PutWithNul(&data_out_p, len_out, clientid >= 0 ? pubkeys_fp64[clientid] : "");
2357
2358 if(clientid >= 0)
2359 {
2360 // I am the client, and my key is ok... so let's set client_keyfp and client_idfp
2361 dp_strlcpy(crypto->client_keyfp, pubkeys_fp64[CDATA->c], sizeof(crypto->client_keyfp));
2362 dp_strlcpy(crypto->client_idfp, pubkeys_priv_fp64[CDATA->c], sizeof(crypto->client_idfp));
2364 }
2365
2366 if(serverid >= 0)
2367 {
2368 if(!CDATA->id)
2369 CDATA->id = qd0_blind_id_new();
2370 if(!CDATA->id)
2371 {
2373 return Crypto_ClientError(data_out, len_out, "d0_blind_id_new failed");
2374 }
2375 if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->s]))
2376 {
2378 return Crypto_ClientError(data_out, len_out, "d0_blind_id_copy failed");
2379 }
2380 CDATA->next_step = 1;
2381 *len_out = data_out_p - data_out;
2382 }
2383 else // if(clientid >= 0) // guaranteed by condition one level outside
2384 {
2385 // skip over server auth, perform client auth only
2386 if(!CDATA->id)
2387 CDATA->id = qd0_blind_id_new();
2388 if(!CDATA->id)
2389 {
2391 return Crypto_ClientError(data_out, len_out, "d0_blind_id_new failed");
2392 }
2393 if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->c]))
2394 {
2396 return Crypto_ClientError(data_out, len_out, "d0_blind_id_copy failed");
2397 }
2398 if(!qd0_blind_id_authenticate_with_private_id_start(CDATA->id, true, false, "XONOTIC", 8, data_out_p, len_out)) // len_out receives used size by this op
2399 {
2401 return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_start failed");
2402 }
2403 CDATA->next_step = 5;
2404 data_out_p += *len_out;
2405 *len_out = data_out_p - data_out;
2406 }
2407 return CRYPTO_DISCARD;
2408 }
2409 else
2410 {
2411 if(wantserver_idfp[0]) // if we know a host key, honor its encryption setting
2412 if(wantserver_aeslevel >= 3)
2413 return Crypto_ClientError(data_out, len_out, "Server insists on encryption, but neither can authenticate to the other");
2414 return (d0_rijndael_dll && crypto_aeslevel.integer >= 3) ? Crypto_ClientError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)") :
2416 }
2417 }
2418 else if(len_in > 5 && !memcmp(string, "d0pk\\", 5) && cls.connect_trying)
2419 {
2420 const char *cnt;
2421 int id;
2422
2423 // Must check the source IP here, if we want to prevent other servers' replies from falsely advancing the crypto state, preventing successful connect to the real server.
2425 {
2426 char warn_msg[128];
2427
2428 dpsnprintf(warn_msg, sizeof(warn_msg), "ignoring d0pk\\ message from wrong server %s", peeraddressstring);
2429 return Crypto_SoftClientError(data_out, len_out, warn_msg);
2430 }
2431
2432 id = (InfoString_GetValue(string + 4, "id", infostringvalue, sizeof(infostringvalue)) ? atoi(infostringvalue) : -1);
2433 cnt = (InfoString_GetValue(string + 4, "cnt", infostringvalue, sizeof(infostringvalue)) ? infostringvalue : NULL);
2434 if(!cnt)
2435 return Crypto_ClientError(data_out, len_out, "d0pk\\ message without cnt");
2436 GetUntilNul(&data_in, &len_in);
2437 if(!data_in)
2438 return Crypto_ClientError(data_out, len_out, "d0pk\\ message without attachment");
2439
2440 if(!strcmp(cnt, "1"))
2441 {
2442 if(id >= 0)
2443 if(CDATA->cdata_id != id)
2444 return Crypto_SoftClientError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
2445 if(CDATA->next_step != 1)
2446 return Crypto_SoftClientError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
2447
2448 cls.connect_nextsendtime = max(cls.connect_nextsendtime, host.realtime + 1); // prevent "hammering"
2449
2450 if(InfoString_GetValue(string + 4, "aes", infostringvalue, sizeof(infostringvalue)))
2451 aes = atoi(infostringvalue);
2452 else
2453 aes = false;
2454 // we CANNOT toggle the AES status any more!
2455 // as the server already decided
2456 if(CDATA->wantserver_idfp[0]) // if we know a host key, honor its encryption setting
2457 if(!aes && CDATA->wantserver_aes)
2458 {
2460 return Crypto_ClientError(data_out, len_out, "Stored host key requires encryption, but server did not enable encryption");
2461 }
2462 if(aes && (!d0_rijndael_dll || crypto_aeslevel.integer <= 0))
2463 {
2465 return Crypto_ClientError(data_out, len_out, "Server insists on encryption too hard");
2466 }
2467 if(!aes && (d0_rijndael_dll && crypto_aeslevel.integer >= 3))
2468 {
2470 return Crypto_ClientError(data_out, len_out, "Server insists on plaintext too hard");
2471 }
2472 crypto->use_aes = aes != 0;
2473
2474 PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\2\\id\\%d", CDATA->cdata_id));
2475 if(!qd0_blind_id_authenticate_with_private_id_challenge(CDATA->id, true, false, data_in, len_in, data_out_p, len_out, &status))
2476 {
2478 return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_challenge failed");
2479 }
2480 CDATA->next_step = 3;
2481 data_out_p += *len_out;
2482 *len_out = data_out_p - data_out;
2483 return CRYPTO_DISCARD;
2484 }
2485 else if(!strcmp(cnt, "3"))
2486 {
2487 static char msgbuf[32];
2488 size_t msgbuflen = sizeof(msgbuf);
2489 size_t fpbuflen;
2490
2491 if(id >= 0)
2492 if(CDATA->cdata_id != id)
2493 return Crypto_SoftClientError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
2494 if(CDATA->next_step != 3)
2495 return Crypto_SoftClientError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
2496
2497 cls.connect_nextsendtime = max(cls.connect_nextsendtime, host.realtime + 1); // prevent "hammering"
2498
2499 if(!qd0_blind_id_authenticate_with_private_id_verify(CDATA->id, data_in, len_in, msgbuf, &msgbuflen, &status))
2500 {
2502 return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_verify failed (server authentication error)");
2503 }
2504
2505 dp_strlcpy(crypto->server_keyfp, pubkeys_fp64[CDATA->s], sizeof(crypto->server_keyfp));
2506 if (!status && CDATA->wantserver_issigned)
2507 {
2509 return Crypto_ClientError(data_out, len_out, "Stored host key requires a valid signature, but server did not provide any");
2510 }
2511 crypto->server_issigned = status;
2512
2513 memset(crypto->server_idfp, 0, sizeof(crypto->server_idfp));
2514 fpbuflen = FP64_SIZE;
2515 if(!qd0_blind_id_fingerprint64_public_id(CDATA->id, crypto->server_idfp, &fpbuflen))
2516 {
2518 return Crypto_ClientError(data_out, len_out, "d0_blind_id_fingerprint64_public_id failed");
2519 }
2520 if(CDATA->wantserver_idfp[0])
2521 if(memcmp(CDATA->wantserver_idfp, crypto->server_idfp, sizeof(crypto->server_idfp)))
2522 {
2524 return Crypto_ClientError(data_out, len_out, "Server ID does not match stored host key, refusing to connect");
2525 }
2526 fpbuflen = DHKEY_SIZE;
2527 if(!qd0_blind_id_sessionkey_public_id(CDATA->id, (char *) crypto->dhkey, &fpbuflen))
2528 {
2530 return Crypto_ClientError(data_out, len_out, "d0_blind_id_sessionkey_public_id failed");
2531 }
2532
2533 // cache the server key
2534 Crypto_StoreHostKey(&cls.connect_address, va(vabuf, sizeof(vabuf), "%d %s@%s%s", crypto->use_aes ? 1 : 0, crypto->server_idfp, crypto->server_issigned ? "" : "~", pubkeys_fp64[CDATA->s]), false);
2535
2536 if(CDATA->c >= 0)
2537 {
2538 // client will auth next
2539 PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\4\\id\\%d", CDATA->cdata_id));
2540 if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->c]))
2541 {
2543 return Crypto_ClientError(data_out, len_out, "d0_blind_id_copy failed");
2544 }
2545 if(!qd0_blind_id_authenticate_with_private_id_start(CDATA->id, true, false, "XONOTIC", 8, data_out_p, len_out)) // len_out receives used size by this op
2546 {
2548 return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_start failed");
2549 }
2550 CDATA->next_step = 5;
2551 data_out_p += *len_out;
2552 *len_out = data_out_p - data_out;
2553 return CRYPTO_DISCARD;
2554 }
2555 else
2556 {
2557 // session key is FINISHED (no server part is to be expected)! By this, all keys are set up
2558 crypto->authenticated = true;
2559 CDATA->next_step = 0;
2560 // assume we got the empty challenge to finish the protocol
2561 PutWithNul(&data_out_p, len_out, "challenge ");
2562 *len_out = data_out_p - data_out;
2563 --*len_out; // remove NUL terminator
2564 return CRYPTO_REPLACE;
2565 }
2566 }
2567 else if(!strcmp(cnt, "5"))
2568 {
2569 size_t fpbuflen;
2570 unsigned char dhkey[DHKEY_SIZE];
2571 int i;
2572
2573 if(id >= 0)
2574 if(CDATA->cdata_id != id)
2575 return Crypto_SoftClientError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
2576 if(CDATA->next_step != 5)
2577 return Crypto_SoftClientError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
2578
2579 cls.connect_nextsendtime = max(cls.connect_nextsendtime, host.realtime + 1); // prevent "hammering"
2580
2581 if(CDATA->s < 0) // only if server didn't auth
2582 {
2583 if(InfoString_GetValue(string + 4, "aes", infostringvalue, sizeof(infostringvalue)))
2584 aes = atoi(infostringvalue);
2585 else
2586 aes = false;
2587 if(CDATA->wantserver_idfp[0]) // if we know a host key, honor its encryption setting
2588 if(!aes && CDATA->wantserver_aes)
2589 {
2591 return Crypto_ClientError(data_out, len_out, "Stored host key requires encryption, but server did not enable encryption");
2592 }
2593 if(aes && (!d0_rijndael_dll || crypto_aeslevel.integer <= 0))
2594 {
2596 return Crypto_ClientError(data_out, len_out, "Server insists on encryption too hard");
2597 }
2598 if(!aes && (d0_rijndael_dll && crypto_aeslevel.integer >= 3))
2599 {
2601 return Crypto_ClientError(data_out, len_out, "Server insists on plaintext too hard");
2602 }
2603 crypto->use_aes = aes != 0;
2604 }
2605
2606 PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\6\\id\\%d", CDATA->cdata_id));
2607 if(!qd0_blind_id_authenticate_with_private_id_response(CDATA->id, data_in, len_in, data_out_p, len_out))
2608 {
2610 return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_response failed");
2611 }
2612 fpbuflen = DHKEY_SIZE;
2613 if(!qd0_blind_id_sessionkey_public_id(CDATA->id, (char *) dhkey, &fpbuflen))
2614 {
2616 return Crypto_ClientError(data_out, len_out, "d0_blind_id_sessionkey_public_id failed");
2617 }
2618 // XOR the two DH keys together to make one
2619 for(i = 0; i < DHKEY_SIZE; ++i)
2620 crypto->dhkey[i] ^= dhkey[i];
2621 // session key is FINISHED! By this, all keys are set up
2622 crypto->authenticated = true;
2623 CDATA->next_step = 0;
2624 data_out_p += *len_out;
2625 *len_out = data_out_p - data_out;
2626 return CRYPTO_DISCARD;
2627 }
2628 return Crypto_SoftClientError(data_out, len_out, "Got unknown d0_blind_id message from server");
2629 }
2630
2631 return CRYPTO_NOMATCH;
2632}
client_static_t cls
Definition cl_main.c:116
size_t InfoString_GetValue(const char *buffer, const char *key, char *value, size_t valuesize)
Returns the number of bytes written to *value excluding the \0 terminator.
int BuffLittleLong(const unsigned char *buffer)
Extract a little endian 32bit int from the given buffer.
Definition com_msg.c:71
char * va(char *buf, size_t buflen, const char *format,...)
Definition common.c:972
int dpsnprintf(char *buffer, size_t buffersize, const char *format,...)
Returns the number of printed characters, excluding the final '\0' or returns -1 if the buffer isn't ...
Definition common.c:997
#define dp_strlcpy(dst, src, dsize)
Definition common.h:303
static int cdata_id
Definition crypto.c:509
static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL(* qd0_blind_id_authenticate_with_private_id_challenge)(d0_blind_id_t *ctx, D0_BOOL is_first, D0_BOOL recv_modulus, const char *inbuf, size_t inbuflen, char *outbuf, size_t *outbuflen, D0_BOOL *status)
Definition crypto.c:223
#define PROTOCOL_VLEN
Definition crypto.c:47
#define D0_BOOL
Definition crypto.c:187
static D0_EXPORT D0_WARN_UNUSED_RESULT d0_blind_id_t *(* qd0_blind_id_new)(void)
Definition crypto.c:198
#define PROTOCOL_D0_BLIND_ID
Definition crypto.c:46
static char pubkeys_priv_fp64[MAX_PUBKEYS][FP64_SIZE+1]
Definition crypto.c:486
qbool Crypto_RetrieveHostKey(lhnetaddress_t *peeraddress, int *keyid, char *keyfp, size_t keyfplen, char *idfp, size_t idfplen, int *aeslevel, qbool *issigned)
Definition crypto.c:734
static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL(* qd0_blind_id_sessionkey_public_id)(const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
Definition crypto.c:227
static qbool PutWithNul(char **data, size_t *len, const char *str)
Definition crypto.c:406
#define CDATA
Definition crypto.c:524
#define MAX_PUBKEYS
Definition crypto.c:481
static int Crypto_ClientError(char *data_out, size_t *len_out, const char *msg)
Definition crypto.c:2093
static qbool pubkeys_havesig[MAX_PUBKEYS]
Definition crypto.c:485
static qbool pubkeys_havepriv[MAX_PUBKEYS]
Definition crypto.c:484
static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL(* qd0_blind_id_fingerprint64_public_id)(const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
Definition crypto.c:226
#define MAKE_CDATA
Definition crypto.c:525
static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL(* qd0_blind_id_authenticate_with_private_id_start)(d0_blind_id_t *ctx, D0_BOOL is_first, D0_BOOL send_modulus, const char *message, size_t msglen, char *outbuf, size_t *outbuflen)
Definition crypto.c:222
cvar_t crypto_aeslevel
Definition crypto.c:31
static char pubkeys_fp64[MAX_PUBKEYS][FP64_SIZE+1]
Definition crypto.c:483
static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL(* qd0_blind_id_authenticate_with_private_id_response)(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen, char *outbuf, size_t *outbuflen)
Definition crypto.c:224
static void Crypto_StoreHostKey(lhnetaddress_t *peeraddress, const char *keystring, qbool complain)
Definition crypto.c:635
static unsigned long Crypto_LittleLong(const char *data)
Definition crypto.c:59
static dllhandle_t d0_rijndael_dll
Definition crypto.c:351
static int Crypto_SoftClientError(char *data_out, size_t *len_out, const char *msg)
Definition crypto.c:2100
static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL(* qd0_blind_id_copy)(d0_blind_id_t *ctx, const d0_blind_id_t *src)
Definition crypto.c:201
static d0_blind_id_t * pubkeys[MAX_PUBKEYS]
Definition crypto.c:482
#define CLEAR_CDATA
Definition crypto.c:526
cvar_t net_sourceaddresscheck
Definition netconn.c:87
static const char * GetUntilNul(const char **data, size_t *len)
Definition crypto.c:418
static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL(* qd0_blind_id_authenticate_with_private_id_verify)(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen, char *msg, size_t *msglen, D0_BOOL *status)
Definition crypto.c:225
#define CRYPTO_DISCARD
Definition crypto.h:66
#define FP64_SIZE
Definition crypto.h:38
#define CRYPTO_REPLACE
Definition crypto.h:67
#define CRYPTO_NOMATCH
Definition crypto.h:64
#define DHKEY_SIZE
Definition crypto.h:39
GLenum GLuint id
Definition glquake.h:657
const GLdouble * v
Definition glquake.h:762
host_static_t host
Definition host.c:41
int LHNETADDRESS_Compare(const lhnetaddress_t *vaddress1, const lhnetaddress_t *vaddress2)
Definition lhnet.c:665
#define max(A, B)
Definition mathlib.h:38
#define bound(min, num, max)
Definition mathlib.h:34
#define CCREP_SERVER_INFO
Definition netconn.h:127
#define NETFLAG_CTL
Definition netconn.h:44
#define CCREP_PLAYER_INFO
Definition netconn.h:128
#define CCREP_RULE_INFO
Definition netconn.h:129
int i
#define MAX_INPUTLINE
maximum size of console commandline, QuakeC strings, and many other text processing buffers
Definition qdefs.h:94
#define NULL
Definition qtypes.h:12
bool qbool
Definition qtypes.h:9
qbool connect_trying
Definition client.h:609
crypto_t crypto
Definition client.h:680
double connect_nextsendtime
Definition client.h:611
lhnetaddress_t connect_address
Definition client.h:613
char server_keyfp[FP64_SIZE+1]
Definition crypto.h:48
qbool server_issigned
Definition crypto.h:49
char client_idfp[FP64_SIZE+1]
Definition crypto.h:44
unsigned char dhkey[DHKEY_SIZE]
Definition crypto.h:43
char client_keyfp[FP64_SIZE+1]
Definition crypto.h:45
qbool authenticated
Definition crypto.h:50
qbool client_issigned
Definition crypto.h:46
char server_idfp[FP64_SIZE+1]
Definition crypto.h:47
qbool use_aes
Definition crypto.h:51
int integer
Definition cvar.h:73
double realtime
the accumulated mainloop time since application started (with filtering), without any slowmo or clamp...
Definition host.h:46

References crypto_t::authenticated, bound, BuffLittleLong(), CCREP_PLAYER_INFO, CCREP_RULE_INFO, CCREP_SERVER_INFO, CDATA, cdata_id, CLEAR_CDATA, crypto_t::client_idfp, crypto_t::client_issigned, crypto_t::client_keyfp, cls, client_static_t::connect_address, client_static_t::connect_nextsendtime, client_static_t::connect_trying, client_static_t::crypto, crypto_aeslevel, Crypto_ClientError(), CRYPTO_DISCARD, Crypto_LittleLong(), CRYPTO_NOMATCH, CRYPTO_REPLACE, Crypto_RetrieveHostKey(), Crypto_SoftClientError(), Crypto_StoreHostKey(), d0_blind_id_dll, D0_BOOL, d0_rijndael_dll, crypto_t::dhkey, DHKEY_SIZE, dp_strlcpy, dpsnprintf(), FP64_SIZE, GetUntilNul(), host, i, id, InfoString_GetValue(), cvar_t::integer, LHNETADDRESS_Compare(), MAKE_CDATA, max, MAX_INPUTLINE, MAX_PUBKEYS, net_sourceaddresscheck, NETFLAG_CTL, NULL, PROTOCOL_D0_BLIND_ID, PROTOCOL_VLEN, pubkeys, pubkeys_fp64, pubkeys_havepriv, pubkeys_havesig, pubkeys_priv_fp64, PutWithNul(), qd0_blind_id_authenticate_with_private_id_challenge, qd0_blind_id_authenticate_with_private_id_response, qd0_blind_id_authenticate_with_private_id_start, qd0_blind_id_authenticate_with_private_id_verify, qd0_blind_id_copy, qd0_blind_id_fingerprint64_public_id, qd0_blind_id_new, qd0_blind_id_sessionkey_public_id, host_static_t::realtime, crypto_t::server_idfp, crypto_t::server_issigned, crypto_t::server_keyfp, crypto_t::use_aes, v, and va().

Referenced by NetConn_ClientParsePacket().

◆ Crypto_DecryptPacket()

const void * Crypto_DecryptPacket ( crypto_t * crypto,
const void * data_src,
size_t len_src,
void * data_dst,
size_t * len_dst,
size_t len )

Definition at line 1584 of file crypto.c.

1585{
1586 unsigned char h[32];
1587 int i;
1588
1589 // silently handle non-crypto packets
1590 i = BuffBigLong((unsigned char *) data_src);
1591 if(
1592 (i == (int)0xFFFFFFFF) // avoid QW control packet
1593 ||
1594 (i == (int)0x80000000 + (int)len_src) // avoid NQ control packet
1595 )
1596 return NULL;
1597
1598 if(crypto->authenticated)
1599 {
1600 if(crypto->use_aes)
1601 {
1602 if(len_src < 16 || ((len_src - 16) % 16))
1603 {
1604 Con_Printf("Crypto_DecryptPacket failed (not enough space: %d bytes in, %d bytes out)\n", (int) len_src, (int) len);
1605 return NULL;
1606 }
1607 *len_dst = len_src - ((unsigned char *) data_src)[0];
1608 if(len < *len_dst || *len_dst > len_src - 16)
1609 {
1610 Con_Printf("Crypto_DecryptPacket failed (not enough space: %d bytes in, %d->%d bytes out)\n", (int) len_src, (int) *len_dst, (int) len);
1611 return NULL;
1612 }
1613 seacpy(crypto->dhkey, (unsigned char *) data_src, (unsigned char *) data_dst, ((const unsigned char *) data_src) + 16, *len_dst);
1614 // IV dst src len
1615 if(!HMAC_SHA256_32BYTES(h, (const unsigned char *) data_dst, (int)*len_dst, crypto->dhkey, DHKEY_SIZE))
1616 {
1617 Con_Printf("HMAC fail\n");
1618 return NULL;
1619 }
1620 if(memcmp(((const unsigned char *) data_src)+1, h, 15)) // ignore first byte, used for length
1621 {
1622 Con_Printf("HMAC mismatch\n");
1623 return NULL;
1624 }
1626 {
1627 Con_Print("Decrypted:\n");
1628 Com_HexDumpToConsole((const unsigned char *) data_dst, (int)*len_dst);
1629 }
1630 return data_dst; // no need to copy
1631 }
1632 else
1633 {
1634 if(len_src < 16)
1635 {
1636 Con_Printf("Crypto_DecryptPacket failed (not enough space: %d bytes in, %d bytes out)\n", (int) len_src, (int) len);
1637 return NULL;
1638 }
1639 *len_dst = len_src - 16;
1640 if(len < *len_dst)
1641 {
1642 Con_Printf("Crypto_DecryptPacket failed (not enough space: %d bytes in, %d->%d bytes out)\n", (int) len_src, (int) *len_dst, (int) len);
1643 return NULL;
1644 }
1645 //memcpy(data_dst, data_src + 16, *len_dst);
1646 if(!HMAC_SHA256_32BYTES(h, ((const unsigned char *) data_src) + 16, (int)*len_dst, crypto->dhkey, DHKEY_SIZE))
1647 {
1648 Con_Printf("HMAC fail\n");
1649 Com_HexDumpToConsole((const unsigned char *) data_src, (int)len_src);
1650 return NULL;
1651 }
1652
1653 if(memcmp((const unsigned char *) data_src, h, 16)) // ignore first byte, used for length
1654 {
1655 // undo the "avoid conditions"
1656 if(
1657 (i == (int)0x7FFFFFFF) // avoided QW control packet
1658 ||
1659 (i == (int)0x00000000 + (int)len_src) // avoided NQ control packet
1660 )
1661 {
1662 // do the avoidance on the hash too
1663 h[0] ^= 0x80;
1664 if(memcmp((const unsigned char *) data_src, h, 16)) // ignore first byte, used for length
1665 {
1666 Con_Printf("HMAC mismatch\n");
1667 Com_HexDumpToConsole((const unsigned char *) data_src, (int)len_src);
1668 return NULL;
1669 }
1670 }
1671 else
1672 {
1673 Con_Printf("HMAC mismatch\n");
1674 Com_HexDumpToConsole((const unsigned char *) data_src, (int)len_src);
1675 return NULL;
1676 }
1677 }
1678 return ((const unsigned char *) data_src) + 16; // no need to copy, so data_dst is not used
1679 }
1680 }
1681 else
1682 {
1683 *len_dst = len_src;
1684 return data_src;
1685 }
1686}
int BuffBigLong(const unsigned char *buffer)
Extract a big endian 32bit int from the given buffer.
Definition com_msg.c:49
void Com_HexDumpToConsole(const unsigned char *data, int size)
Definition common.c:82
void Con_Print(const char *msg)
Prints to all appropriate console targets, and adds timestamps.
Definition console.c:1504
void Con_Printf(const char *fmt,...)
Prints to all appropriate console targets.
Definition console.c:1514
static void seacpy(unsigned char *key, const unsigned char *iv, unsigned char *dst, const unsigned char *src, size_t len)
Definition crypto.c:1498
#define HMAC_SHA256_32BYTES(out, in, n, key, k)
Definition hmac.h:15
cvar_t developer_networking
Definition netconn.c:89

References crypto_t::authenticated, BuffBigLong(), Com_HexDumpToConsole(), Con_Print(), Con_Printf(), developer_networking, crypto_t::dhkey, DHKEY_SIZE, HMAC_SHA256_32BYTES, i, cvar_t::integer, NULL, seacpy(), and crypto_t::use_aes.

Referenced by NetConn_ReceivedMessage().

◆ Crypto_EncryptPacket()

const void * Crypto_EncryptPacket ( crypto_t * crypto,
const void * data_src,
size_t len_src,
void * data_dst,
size_t * len_dst,
size_t len )

Definition at line 1527 of file crypto.c.

1528{
1529 unsigned char h[32];
1530 int i;
1531 if(crypto->authenticated)
1532 {
1533 if(crypto->use_aes)
1534 {
1535 // AES packet = 1 byte length overhead, 15 bytes from HMAC-SHA-256, data, 0..15 bytes padding
1536 // 15 bytes HMAC-SHA-256 (112bit) suffice as the attacker can't do more than forge a random-looking packet
1537 // HMAC is needed to not leak information about packet content
1539 {
1540 Con_Print("To be encrypted:\n");
1541 Com_HexDumpToConsole((const unsigned char *) data_src, (int)len_src);
1542 }
1543 if(len_src + 32 > len || !HMAC_SHA256_32BYTES(h, (const unsigned char *) data_src, (int)len_src, crypto->dhkey, DHKEY_SIZE))
1544 {
1545 Con_Printf("Crypto_EncryptPacket failed (not enough space: %d bytes in, %d bytes out)\n", (int) len_src, (int) len);
1546 return NULL;
1547 }
1548 *len_dst = ((len_src + 15) / 16) * 16 + 16; // add 16 for HMAC, then round to 16-size for AES
1549 ((unsigned char *) data_dst)[0] = (unsigned char)(*len_dst - len_src);
1550 memcpy(((unsigned char *) data_dst)+1, h, 15);
1551 aescpy(crypto->dhkey, (const unsigned char *) data_dst, ((unsigned char *) data_dst) + 16, (const unsigned char *) data_src, len_src);
1552 // IV dst src len
1553 }
1554 else
1555 {
1556 // HMAC packet = 16 bytes HMAC-SHA-256 (truncated to 128 bits), data
1557 if(len_src + 16 > len || !HMAC_SHA256_32BYTES(h, (const unsigned char *) data_src, (int)len_src, crypto->dhkey, DHKEY_SIZE))
1558 {
1559 Con_Printf("Crypto_EncryptPacket failed (not enough space: %d bytes in, %d bytes out)\n", (int) len_src, (int) len);
1560 return NULL;
1561 }
1562 *len_dst = len_src + 16;
1563 memcpy(data_dst, h, 16);
1564 memcpy(((unsigned char *) data_dst) + 16, (unsigned char *) data_src, len_src);
1565
1566 // handle the "avoid" conditions:
1567 i = BuffBigLong((unsigned char *) data_dst);
1568 if(
1569 (i == (int)0xFFFFFFFF) // avoid QW control packet
1570 ||
1571 (i == (int)0x80000000 + (int)*len_dst) // avoid NQ control packet
1572 )
1573 *(unsigned char *)data_dst ^= 0x80; // this will ALWAYS fix it
1574 }
1575 return data_dst;
1576 }
1577 else
1578 {
1579 *len_dst = len_src;
1580 return data_src;
1581 }
1582}
static void aescpy(unsigned char *key, const unsigned char *iv, unsigned char *dst, const unsigned char *src, size_t len)
Definition crypto.c:1472

References aescpy(), crypto_t::authenticated, BuffBigLong(), Com_HexDumpToConsole(), Con_Print(), Con_Printf(), developer_networking, crypto_t::dhkey, DHKEY_SIZE, HMAC_SHA256_32BYTES, i, cvar_t::integer, NULL, and crypto_t::use_aes.

Referenced by NetConn_ReceivedMessage(), and NetConn_SendUnreliableMessage().

◆ Crypto_FinishInstance()

qbool Crypto_FinishInstance ( crypto_t * out,
crypto_t * in )

Definition at line 558 of file crypto.c.

559{
560 // no check needed here (returned pointers are only used in prefilled fields)
561 if(!crypto || !crypto->authenticated)
562 {
563 Con_Printf("Passed an invalid crypto connect instance\n");
564 memset(out, 0, sizeof(*out));
565 return false;
566 }
568 memcpy(out, crypto, sizeof(*out));
569 memset(crypto, 0, sizeof(*crypto));
570 return true;
571}

References crypto_t::authenticated, CLEAR_CDATA, and Con_Printf().

Referenced by NetConn_ConnectionEstablished(), and NetConn_ServerParsePacket().

◆ Crypto_GetInfoResponseDataString()

const char * Crypto_GetInfoResponseDataString ( void )

Definition at line 1689 of file crypto.c.

1690{
1692 return crypto_idstring;
1693}
static char crypto_idstring_buf[512]
Definition crypto.c:43
static const char * crypto_idstring
Definition crypto.c:42

References crypto_aeslevel, crypto_idstring, crypto_idstring_buf, and cvar_t::integer.

Referenced by NetConn_BuildStatusResponse().

◆ Crypto_Init()

void Crypto_Init ( void )

Definition at line 1072 of file crypto.c.

1073{
1074 cryptomempool = Mem_AllocPool("crypto", 0, NULL);
1075
1076 if(!Crypto_OpenLibrary())
1077 return;
1078
1080 if (Thread_HasThreads())
1082
1084 {
1087 Con_Printf("libd0_blind_id initialization FAILED, cryptography support has been disabled\n");
1088 return;
1089 }
1090
1091 (void) Crypto_Rijndael_OpenLibrary(); // if this fails, it's uncritical
1092
1094}
static void Crypto_d0_free(void *p)
Definition crypto.c:1015
static void Crypto_d0_destroymutex(void *m)
Definition crypto.c:1025
static int Crypto_d0_lockmutex(void *m)
Definition crypto.c:1030
static mempool_t * cryptomempool
Definition crypto.c:1004
static void Crypto_InitHostKeys(void)
Definition crypto.c:591
static D0_EXPORT void(* qd0_blind_id_setmallocfuncs)(d0_malloc_t *m, d0_free_t *f)
Definition crypto.c:233
static qbool Crypto_OpenLibrary(void)
Definition crypto.c:283
static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL(* qd0_blind_id_INITIALIZE)(void)
Definition crypto.c:228
static qbool Crypto_Rijndael_OpenLibrary(void)
Definition crypto.c:352
static void Crypto_Rijndael_CloseLibrary(void)
Definition crypto.c:375
static int Crypto_d0_unlockmutex(void *m)
Definition crypto.c:1035
static void Crypto_CloseLibrary(void)
Definition crypto.c:306
static void * Crypto_d0_malloc(size_t len)
Definition crypto.c:1010
static void * Crypto_d0_createmutex(void)
Definition crypto.c:1020
static D0_EXPORT void(* qd0_blind_id_setmutexfuncs)(d0_createmutex_t *c, d0_destroymutex_t *d, d0_lockmutex_t *l, d0_unlockmutex_t *u)
Definition crypto.c:234
void() predraw
qbool Thread_HasThreads(void)
Definition thread_null.c:13
#define Mem_AllocPool(name, flags, parent)
Definition zone.h:104

References Con_Printf(), Crypto_CloseLibrary(), Crypto_d0_createmutex(), Crypto_d0_destroymutex(), Crypto_d0_free(), Crypto_d0_lockmutex(), Crypto_d0_malloc(), Crypto_d0_unlockmutex(), Crypto_InitHostKeys(), Crypto_OpenLibrary(), Crypto_Rijndael_CloseLibrary(), Crypto_Rijndael_OpenLibrary(), cryptomempool, Mem_AllocPool, NULL, qd0_blind_id_INITIALIZE, qd0_blind_id_setmallocfuncs, qd0_blind_id_setmutexfuncs, Thread_HasThreads(), and void().

Referenced by Host_Init().

◆ Crypto_Init_Commands()

void Crypto_Init_Commands ( void )

Definition at line 1449 of file crypto.c.

1450{
1451 if(d0_blind_id_dll)
1452 {
1453 Cmd_AddCommand(CF_SHARED, "crypto_reload", Crypto_Reload_f, "reloads cryptographic keys");
1454 Cmd_AddCommand(CF_SHARED, "crypto_keygen", Crypto_KeyGen_f, "generates and saves a cryptographic key");
1455 Cmd_AddCommand(CF_SHARED, "crypto_keys", Crypto_Keys_f, "lists the loaded keys");
1456 Cmd_AddCommand(CF_SHARED, "crypto_hostkeys", Crypto_HostKeys_f, "lists the cached host keys");
1457 Cmd_AddCommand(CF_SHARED, "crypto_hostkey_clear", Crypto_HostKey_Clear_f, "clears a cached host key");
1458
1460 if(d0_rijndael_dll)
1462 else
1463 crypto_aeslevel.integer = 0; // make sure
1467 }
1468}
void Cmd_AddCommand(unsigned flags, const char *cmd_name, xcommand_t function, const char *description)
called by the init functions of other parts of the program to register commands and functions to call...
Definition cmd.c:1661
#define CF_SHARED
Definition cmd.h:67
static void Crypto_Reload_f(cmd_state_t *cmd)
Definition crypto.c:1373
cvar_t crypto_servercpupercent
Definition crypto.c:33
cvar_t crypto_developer
Definition crypto.c:30
cvar_t crypto_servercpumaxtime
Definition crypto.c:34
cvar_t crypto_servercpudebug
Definition crypto.c:35
static void Crypto_HostKeys_f(cmd_state_t *cmd)
Definition crypto.c:1403
static void Crypto_KeyGen_f(cmd_state_t *cmd)
Definition crypto.c:1217
static void Crypto_HostKey_Clear_f(cmd_state_t *cmd)
Definition crypto.c:1428
static void Crypto_Keys_f(cmd_state_t *cmd)
Definition crypto.c:1380
void Cvar_RegisterVariable(cvar_t *variable)
registers a cvar that already has the name, string, and optionally the archive elements set.
Definition cvar.c:599

References CF_SHARED, Cmd_AddCommand(), crypto_aeslevel, crypto_developer, Crypto_HostKey_Clear_f(), Crypto_HostKeys_f(), Crypto_KeyGen_f(), Crypto_Keys_f(), Crypto_Reload_f(), crypto_servercpudebug, crypto_servercpumaxtime, crypto_servercpupercent, Cvar_RegisterVariable(), d0_blind_id_dll, d0_rijndael_dll, and cvar_t::integer.

Referenced by Host_Init().

◆ Crypto_LoadKeys()

void Crypto_LoadKeys ( void )

Definition at line 855 of file crypto.c.

856{
857 char buf[8192];
858 size_t len, len2;
859 int i;
860 char vabuf[1024];
861
862 if(!d0_blind_id_dll) // don't if we can't
863 return;
864
865 if(crypto_idstring) // already loaded? then not
866 return;
867
868 Host_LockSession(); // we use the session ID here
869
870 // load keys
871 // note: we are just a CLIENT
872 // so we load:
873 // PUBLIC KEYS to accept (including modulus)
874 // PRIVATE KEY of user
875
876 for(i = 0; i < MAX_PUBKEYS; ++i)
877 {
878 memset(pubkeys_fp64[i], 0, sizeof(pubkeys_fp64[i]));
879 memset(pubkeys_priv_fp64[i], 0, sizeof(pubkeys_fp64[i]));
880 pubkeys_havepriv[i] = false;
881 pubkeys_havesig[i] = false;
882 len = Crypto_LoadFile(va(vabuf, sizeof(vabuf), "key_%d.d0pk", i), buf, sizeof(buf), false);
883 if((pubkeys[i] = Crypto_ReadPublicKey(buf, len)))
884 {
885 len2 = FP64_SIZE;
886 if(qd0_blind_id_fingerprint64_public_key(pubkeys[i], pubkeys_fp64[i], &len2)) // keeps final NUL
887 {
888 Con_Printf("Loaded public key key_%d.d0pk (fingerprint: %s)\n", i, pubkeys_fp64[i]);
889 len = Crypto_LoadFile(va(vabuf, sizeof(vabuf), "key_%d.d0si%s", i, sessionid.string), buf, sizeof(buf), true);
890 if(len)
891 {
893 {
894 len2 = FP64_SIZE;
895 if(qd0_blind_id_fingerprint64_public_id(pubkeys[i], pubkeys_priv_fp64[i], &len2)) // keeps final NUL
896 {
897 D0_BOOL status = 0;
898
899 Con_Printf("Loaded private ID key_%d.d0si%s for key_%d.d0pk (public key fingerprint: %s)\n", i, sessionid.string, i, pubkeys_priv_fp64[i]);
900
901 // verify the key we just loaded (just in case)
903 {
904 pubkeys_havepriv[i] = true;
905 pubkeys_havesig[i] = status;
906
907 // verify the key we just got (just in case)
908 if(!status)
909 Con_Printf("NOTE: this ID has not yet been signed!\n");
910
912 }
913 else
914 {
915 Con_Printf("d0_blind_id_verify_private_id failed, this is not a valid key!\n");
917 pubkeys[i] = NULL;
918 }
919 }
920 else
921 {
922 Con_Printf("d0_blind_id_fingerprint64_public_id failed\n");
924 pubkeys[i] = NULL;
925 }
926 }
927 }
928 }
929 else
930 {
931 // can't really happen
933 pubkeys[i] = NULL;
934 }
935 }
936 }
937
938 keygen_i = -1;
941
942 // find a good prefix length for all the keys we know (yes, algorithm is not perfect yet, may yield too long prefix length)
944 memset(buf+256, 0, MAX_PUBKEYS + MAX_PUBKEYS);
946 {
947 memset(buf, 0, 256);
948 for(i = 0; i < MAX_PUBKEYS; ++i)
949 if(pubkeys[i])
950 {
951 if(!buf[256 + i])
954 if(!buf[256 + MAX_PUBKEYS + i])
956 }
957 for(i = 0; i < MAX_PUBKEYS; ++i)
958 if(pubkeys[i])
959 {
960 if(!buf[256 + i])
961 if(buf[(unsigned char) pubkeys_fp64[i][crypto_keyfp_recommended_length]] < 2)
962 buf[256 + i] = 1;
964 if(!buf[256 + MAX_PUBKEYS + i])
965 if(buf[(unsigned char) pubkeys_priv_fp64[i][crypto_keyfp_recommended_length]] < 2)
966 buf[256 + MAX_PUBKEYS + i] = 1;
967 }
969 for(i = 0; i < MAX_PUBKEYS; ++i)
970 if(pubkeys[i])
971 {
972 if(!buf[256 + i])
973 break;
975 if(!buf[256 + MAX_PUBKEYS + i])
976 break;
977 }
978 if(i >= MAX_PUBKEYS)
979 break;
980 }
983}
static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL(* qd0_blind_id_verify_public_id)(const d0_blind_id_t *ctx, D0_BOOL *status)
Definition crypto.c:235
int crypto_keyfp_recommended_length
Definition crypto.c:41
static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL(* qd0_blind_id_fingerprint64_public_key)(const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
Definition crypto.c:208
static d0_blind_id_t * Crypto_ReadPublicKey(char *buf, size_t len)
Definition crypto.c:450
static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL(* qd0_blind_id_verify_private_id)(const d0_blind_id_t *ctx)
Definition crypto.c:236
static D0_EXPORT void(* qd0_blind_id_free)(d0_blind_id_t *a)
Definition crypto.c:199
static size_t Crypto_LoadFile(const char *path, char *buf, size_t nmax, qbool inuserdir)
Definition crypto.c:388
static void Crypto_BuildIdString(void)
Definition crypto.c:842
static qbool Crypto_SavePubKeyTextFile(int i)
Definition crypto.c:814
static qbool Crypto_AddPrivateKey(d0_blind_id_t *pk, char *buf, size_t len)
Definition crypto.c:469
static int keygen_i
Definition crypto.c:490
static void Crypto_BuildChallengeAppend(void)
Definition crypto.c:785
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition glquake.h:657
void Host_LockSession(void)
Definition host.c:330
cvar_t sessionid
Definition host.c:58
const char * string
Definition cvar.h:71

References buf, Con_Printf(), Crypto_AddPrivateKey(), Crypto_BuildChallengeAppend(), Crypto_BuildIdString(), crypto_idstring, crypto_keyfp_recommended_length, Crypto_LoadFile(), Crypto_ReadPublicKey(), Crypto_SavePubKeyTextFile(), d0_blind_id_dll, D0_BOOL, FP64_SIZE, Host_LockSession(), i, keygen_i, MAX_PUBKEYS, NULL, pubkeys, pubkeys_fp64, pubkeys_havepriv, pubkeys_havesig, pubkeys_priv_fp64, qd0_blind_id_fingerprint64_public_id, qd0_blind_id_fingerprint64_public_key, qd0_blind_id_free, qd0_blind_id_verify_private_id, qd0_blind_id_verify_public_id, sessionid, cvar_t::string, and va().

Referenced by Crypto_KeyGen_f(), Crypto_Reload_f(), NetConn_OpenClientPorts(), NetConn_OpenServerPorts(), and PRVM_Prog_Load().

◆ Crypto_RetrieveHostKey()

qbool Crypto_RetrieveHostKey ( struct lhnetaddress_s * peeraddress,
int * keyid,
char * keyfp,
size_t keyfplen,
char * idfp,
size_t idfplen,
int * aeslevel,
qbool * issigned )

◆ Crypto_RetrieveLocalKey()

int Crypto_RetrieveLocalKey ( int keyid,
char * keyfp,
size_t keyfplen,
char * idfp,
size_t idfplen,
qbool * issigned )

Definition at line 763 of file crypto.c.

764{
765 if(keyid < 0 || keyid >= MAX_PUBKEYS)
766 return 0;
767 if(keyfp)
768 *keyfp = 0;
769 if(idfp)
770 *idfp = 0;
771 if(!pubkeys[keyid])
772 return -1;
773 if(keyfp)
774 dp_strlcpy(keyfp, pubkeys_fp64[keyid], keyfplen);
775 if(idfp)
776 if(pubkeys_havepriv[keyid])
777 dp_strlcpy(idfp, pubkeys_priv_fp64[keyid], idfplen);
778 if(issigned)
779 *issigned = pubkeys_havesig[keyid];
780 return 1;
781}

References dp_strlcpy, MAX_PUBKEYS, pubkeys, pubkeys_fp64, pubkeys_havepriv, pubkeys_havesig, and pubkeys_priv_fp64.

Referenced by VM_M_crypto_getmyidfp(), VM_M_crypto_getmyidstatus(), and VM_M_crypto_getmykeyfp().

◆ Crypto_ServerAppendToChallenge()

qbool Crypto_ServerAppendToChallenge ( const char * data_in,
size_t len_in,
char * data_out,
size_t * len_out,
size_t maxlen )

Definition at line 1696 of file crypto.c.

1697{
1698 // cheap op, all is precomputed
1699 if(!d0_blind_id_dll)
1700 return false; // no support
1701 // append challenge
1702 if(maxlen_out <= *len_out + challenge_append_length)
1703 return false;
1704 memcpy(data_out + *len_out, challenge_append, challenge_append_length);
1705 *len_out += challenge_append_length;
1706 return false;
1707}
static char challenge_append[1400]
Definition crypto.c:487
static size_t challenge_append_length
Definition crypto.c:488

References challenge_append, challenge_append_length, and d0_blind_id_dll.

Referenced by NetConn_ServerParsePacket().

◆ Crypto_ServerGetInstance()

crypto_t * Crypto_ServerGetInstance ( struct lhnetaddress_s * peeraddress)

◆ Crypto_ServerParsePacket()

int Crypto_ServerParsePacket ( const char * data_in,
size_t len_in,
char * data_out,
size_t * len_out,
lhnetaddress_t * peeraddress )

Definition at line 2036 of file crypto.c.

2037{
2038 int ret;
2039 double t = 0;
2040 static double complain_time = 0;
2041 const char *cnt;
2042 qbool do_time = false;
2043 qbool do_reject = false;
2044 char infostringvalue[MAX_INPUTLINE];
2046 if(len_in > 5 && !memcmp(data_in, "d0pk\\", 5))
2047 {
2048 do_time = true;
2049 cnt = (InfoString_GetValue(data_in + 4, "cnt", infostringvalue, sizeof(infostringvalue)) ? infostringvalue : NULL);
2050 if(cnt)
2051 if(!strcmp(cnt, "0"))
2052 do_reject = true;
2053 }
2054 if(do_time)
2055 {
2056 // check if we may perform crypto...
2058 {
2063 }
2064 else
2065 {
2069 }
2071 if(do_reject && crypto_servercpu_accumulator < 0)
2072 {
2073 if(host.realtime > complain_time + 5)
2074 Con_Printf("crypto: cannot perform requested crypto operations; denial service attack or crypto_servercpupercent/crypto_servercpumaxtime are too low\n");
2075 *len_out = 0;
2076 return CRYPTO_DISCARD;
2077 }
2078 t = Sys_DirtyTime();
2079 }
2080 ret = Crypto_ServerParsePacket_Internal(data_in, len_in, data_out, len_out, peeraddress);
2081 if(do_time)
2082 {
2083 t = Sys_DirtyTime() - t;if (t < 0.0) t = 0.0; // dirtytime can step backwards
2085 Con_Printf("crypto: accumulator was %.1f ms, used %.1f ms for crypto, ", crypto_servercpu_accumulator * 1000, t * 1000);
2088 Con_Printf("is %.1f ms\n", crypto_servercpu_accumulator * 1000);
2089 }
2090 return ret;
2091}
static double crypto_servercpu_accumulator
Definition crypto.c:36
static double crypto_servercpu_lastrealtime
Definition crypto.c:37
static int Crypto_ServerParsePacket_Internal(const char *data_in, size_t len_in, char *data_out, size_t *len_out, lhnetaddress_t *peeraddress)
Definition crypto.c:1727
return ret
float value
Definition cvar.h:74
double Sys_DirtyTime(void)
Definition sys_shared.c:417

References Con_Printf(), CRYPTO_DISCARD, crypto_servercpu_accumulator, crypto_servercpu_lastrealtime, crypto_servercpudebug, crypto_servercpumaxtime, crypto_servercpupercent, Crypto_ServerParsePacket_Internal(), host, InfoString_GetValue(), cvar_t::integer, MAX_INPUTLINE, NULL, host_static_t::realtime, ret, Sys_DirtyTime(), and cvar_t::value.

Referenced by NetConn_ServerParsePacket().

◆ Crypto_Shutdown()

void Crypto_Shutdown ( void )

Definition at line 1043 of file crypto.c.

1044{
1045 crypto_t *crypto;
1046 int i;
1047
1049
1050 if(d0_blind_id_dll)
1051 {
1052 // free memory
1053 for(i = 0; i < MAX_CRYPTOCONNECTS; ++i)
1054 {
1055 crypto = &cryptoconnects[i].crypto;
1057 }
1058 memset(cryptoconnects, 0, sizeof(cryptoconnects));
1059 crypto = &cls.crypto;
1061
1063
1065
1067 }
1068
1070}
#define MAX_CRYPTOCONNECTS
Definition crypto.c:493
static D0_EXPORT void(* qd0_blind_id_SHUTDOWN)(void)
Definition crypto.c:229
static server_cryptoconnect_t cryptoconnects[MAX_CRYPTOCONNECTS]
Definition crypto.c:507
static void Crypto_UnloadKeys(void)
Definition crypto.c:985
#define Mem_FreePool(pool)
Definition zone.h:105

References CLEAR_CDATA, cls, client_static_t::crypto, server_cryptoconnect_t::crypto, Crypto_CloseLibrary(), Crypto_Rijndael_CloseLibrary(), Crypto_UnloadKeys(), cryptoconnects, cryptomempool, d0_blind_id_dll, i, MAX_CRYPTOCONNECTS, Mem_FreePool, and qd0_blind_id_SHUTDOWN.

Referenced by Host_Shutdown().

◆ Crypto_SignData()

size_t Crypto_SignData ( const void * data,
size_t datasize,
int keyid,
void * signed_data,
size_t signed_size )

Definition at line 2634 of file crypto.c.

2635{
2636 if(keyid < 0 || keyid >= MAX_PUBKEYS)
2637 return 0;
2638 if(!pubkeys_havepriv[keyid])
2639 return 0;
2640 if(qd0_blind_id_sign_with_private_id_sign(pubkeys[keyid], true, false, (const char *)data, datasize, (char *)signed_data, &signed_size))
2641 return signed_size;
2642 return 0;
2643}
static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL(* qd0_blind_id_sign_with_private_id_sign)(d0_blind_id_t *ctx, D0_BOOL is_first, D0_BOOL send_modulus, const char *message, size_t msglen, char *outbuf, size_t *outbuflen)
Definition crypto.c:231
GLsizeiptr const GLvoid * data
Definition glquake.h:639

References data, MAX_PUBKEYS, pubkeys, pubkeys_havepriv, and qd0_blind_id_sign_with_private_id_sign.

◆ Crypto_SignDataDetached()

size_t Crypto_SignDataDetached ( const void * data,
size_t datasize,
int keyid,
void * signed_data,
size_t signed_size )

Definition at line 2645 of file crypto.c.

2646{
2647 if(keyid < 0 || keyid >= MAX_PUBKEYS)
2648 return 0;
2649 if(!pubkeys_havepriv[keyid])
2650 return 0;
2651 if(qd0_blind_id_sign_with_private_id_sign_detached(pubkeys[keyid], true, false, (const char *)data, datasize, (char *)signed_data, &signed_size))
2652 return signed_size;
2653 return 0;
2654}
static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL(* qd0_blind_id_sign_with_private_id_sign_detached)(d0_blind_id_t *ctx, D0_BOOL is_first, D0_BOOL send_modulus, const char *message, size_t msglen, char *outbuf, size_t *outbuflen)
Definition crypto.c:232

References data, MAX_PUBKEYS, pubkeys, pubkeys_havepriv, and qd0_blind_id_sign_with_private_id_sign_detached.

Referenced by VM_uri_get().

◆ sha256()

void sha256 ( unsigned char * out,
const unsigned char * in,
int n )

Definition at line 383 of file crypto.c.

384{
385 qd0_blind_id_util_sha256((char *) out, (const char *) in, n);
386}
static D0_EXPORT void(* qd0_blind_id_util_sha256)(char *out, const char *in, size_t n)
Definition crypto.c:230
#define n(x, y)

References n, and qd0_blind_id_util_sha256.

Referenced by VM_digest_hex().

Variable Documentation

◆ crypto_aeslevel

struct cvar_s crypto_aeslevel
extern

Definition at line 31 of file crypto.c.

31{CF_CLIENT | CF_SERVER | CF_ARCHIVE, "crypto_aeslevel", "1", "whether to support AES encryption in authenticated connections (0 = no, 1 = supported, 2 = requested, 3 = required)"};
#define CF_SERVER
cvar/command that only the server can change/execute
Definition cmd.h:49
#define CF_CLIENT
cvar/command that only the client can change/execute
Definition cmd.h:48
#define CF_ARCHIVE
cvar should have its set value saved to config.cfg and persist across sessions
Definition cmd.h:53

Referenced by Crypto_BuildIdString(), Crypto_ClientParsePacket(), Crypto_GetInfoResponseDataString(), Crypto_Init_Commands(), and Crypto_ServerParsePacket_Internal().

◆ crypto_developer

struct cvar_s crypto_developer
extern

Definition at line 30 of file crypto.c.

30{CF_CLIENT | CF_SERVER | CF_ARCHIVE, "crypto_developer", "0", "print extra info about crypto handshake"};

Referenced by Crypto_Init_Commands(), and NetConn_ServerParsePacket().

◆ crypto_keyfp_recommended_length

int crypto_keyfp_recommended_length
extern