#include "quakedef.h"
#include "crypto.h"
#include "common.h"
+#include "thread.h"
#include "hmac.h"
#include "libcurl.h"
#define qd0_blind_id_util_sha256 d0_blind_id_util_sha256
#define qd0_blind_id_sign_with_private_id_sign d0_blind_id_sign_with_private_id_sign
#define qd0_blind_id_sign_with_private_id_sign_detached d0_blind_id_sign_with_private_id_sign_detached
+#define qd0_blind_id_setmallocfuncs d0_blind_id_setmallocfuncs
+#define qd0_blind_id_setmutexfuncs d0_blind_id_setmutexfuncs
+#define qd0_blind_id_verify_public_id d0_blind_id_verify_public_id
+#define qd0_blind_id_verify_private_id d0_blind_id_verify_private_id
#else
#endif
#define D0_BOOL int
+typedef void *(d0_malloc_t)(size_t len);
+typedef void (d0_free_t)(void *p);
+typedef void *(d0_createmutex_t)(void);
+typedef void (d0_destroymutex_t)(void *);
+typedef int (d0_lockmutex_t)(void *); // zero on success
+typedef int (d0_unlockmutex_t)(void *); // zero on success
+
typedef struct d0_blind_id_s d0_blind_id_t;
typedef D0_BOOL (*d0_fastreject_function) (const d0_blind_id_t *ctx, void *pass);
static D0_EXPORT D0_WARN_UNUSED_RESULT d0_blind_id_t *(*qd0_blind_id_new) (void);
static D0_EXPORT void (*qd0_blind_id_util_sha256) (char *out, const char *in, size_t n);
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);
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);
+static D0_EXPORT void (*qd0_blind_id_setmallocfuncs)(d0_malloc_t *m, d0_free_t *f);
+static D0_EXPORT void (*qd0_blind_id_setmutexfuncs)(d0_createmutex_t *c, d0_destroymutex_t *d, d0_lockmutex_t *l, d0_unlockmutex_t *u);
+static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_verify_public_id)(const d0_blind_id_t *ctx, D0_BOOL *status);
+static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_verify_private_id)(const d0_blind_id_t *ctx);
static dllfunction_t d0_blind_id_funcs[] =
{
{"d0_blind_id_new", (void **) &qd0_blind_id_new},
{"d0_blind_id_util_sha256", (void **) &qd0_blind_id_util_sha256},
{"d0_blind_id_sign_with_private_id_sign", (void **) &qd0_blind_id_sign_with_private_id_sign},
{"d0_blind_id_sign_with_private_id_sign_detached", (void **) &qd0_blind_id_sign_with_private_id_sign_detached},
+ {"d0_blind_id_setmallocfuncs", (void **) &qd0_blind_id_setmallocfuncs},
+ {"d0_blind_id_setmutexfuncs", (void **) &qd0_blind_id_setmutexfuncs},
+ {"d0_blind_id_verify_public_id", (void **) &qd0_blind_id_verify_public_id},
+ {"d0_blind_id_verify_private_id", (void **) &qd0_blind_id_verify_private_id},
{NULL, NULL}
};
// end of d0_blind_id interface
qd0_blind_id_util_sha256((char *) out, (const char *) in, n);
}
-static size_t Crypto_LoadFile(const char *path, char *buf, size_t nmax)
+static size_t Crypto_LoadFile(const char *path, char *buf, size_t nmax, qboolean inuserdir)
{
+ char vabuf[1024];
qfile_t *f = NULL;
fs_offset_t n;
- if(*fs_userdir)
- f = FS_SysOpen(va("%s%s", fs_userdir, path), "rb", false);
- if(!f)
- f = FS_SysOpen(va("%s%s", fs_basedir, path), "rb", false);
+ if(inuserdir)
+ f = FS_SysOpen(va(vabuf, sizeof(vabuf), "%s%s", *fs_userdir ? fs_userdir : fs_basedir, path), "rb", false);
+ else
+ f = FS_SysOpen(va(vabuf, sizeof(vabuf), "%s%s", fs_basedir, path), "rb", false);
if(!f)
return 0;
n = FS_Read(f, buf, nmax);
static d0_blind_id_t *pubkeys[MAX_PUBKEYS];
static char pubkeys_fp64[MAX_PUBKEYS][FP64_SIZE+1];
static qboolean pubkeys_havepriv[MAX_PUBKEYS];
+static qboolean pubkeys_havesig[MAX_PUBKEYS];
static char pubkeys_priv_fp64[MAX_PUBKEYS][FP64_SIZE+1];
static char challenge_append[1400];
static size_t challenge_append_length;
}
CLEAR_CDATA;
memcpy(out, crypto, sizeof(*out));
- memset(crypto, 0, sizeof(crypto));
+ memset(crypto, 0, sizeof(*crypto));
return true;
}
return true;
}
-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
+int Crypto_RetrieveLocalKey(int keyid, char *keyfp, size_t keyfplen, char *idfp, size_t idfplen, qboolean *issigned) // return value: -1 if more to come, +1 if valid, 0 if end of list
{
if(keyid < 0 || keyid >= MAX_PUBKEYS)
return 0;
if(idfp)
if(pubkeys_havepriv[keyid])
strlcpy(idfp, pubkeys_priv_fp64[keyid], keyfplen);
+ if(issigned)
+ *issigned = pubkeys_havesig[keyid];
return 1;
}
// end
challenge_append_length = p - challenge_append;
}
-static void Crypto_LoadKeys(void)
+static qboolean Crypto_SavePubKeyTextFile(int i)
+{
+ qfile_t *f;
+ char vabuf[1024];
+
+ if(!pubkeys_havepriv[i])
+ return false;
+ f = FS_SysOpen(va(vabuf, sizeof(vabuf), "%skey_%d-public-fp%s.txt", *fs_userdir ? fs_userdir : fs_basedir, i, sessionid.string), "w", false);
+ if(!f)
+ return false;
+
+ // we ignore errors for this file, as it's not necessary to have
+ FS_Printf(f, "ID-Fingerprint: %s\n", pubkeys_priv_fp64[i]);
+ FS_Printf(f, "ID-Is-Signed: %s\n", pubkeys_havesig[i] ? "yes" : "no");
+ FS_Printf(f, "ID-Is-For-Key: %s\n", pubkeys_fp64[i]);
+ FS_Printf(f, "\n");
+ FS_Printf(f, "This is a PUBLIC ID file for DarkPlaces.\n");
+ FS_Printf(f, "You are free to share this file or its contents.\n");
+ FS_Printf(f, "\n");
+ FS_Printf(f, "This file will be automatically generated again if deleted.\n");
+ FS_Printf(f, "\n");
+ FS_Printf(f, "However, NEVER share the accompanying SECRET ID file called\n");
+ FS_Printf(f, "key_%d.d0si%s, as doing so would compromise security!\n", i, sessionid.string);
+ FS_Close(f);
+
+ return true;
+}
+
+void Crypto_LoadKeys(void)
{
char buf[8192];
size_t len, len2;
int i;
+ char vabuf[1024];
+
+ if(!d0_blind_id_dll) // don't if we can't
+ return;
+
+ if(crypto_idstring) // already loaded? then not
+ return;
+
+ Host_LockSession(); // we use the session ID here
// load keys
// note: we are just a CLIENT
memset(pubkeys_fp64[i], 0, sizeof(pubkeys_fp64[i]));
memset(pubkeys_priv_fp64[i], 0, sizeof(pubkeys_fp64[i]));
pubkeys_havepriv[i] = false;
- len = Crypto_LoadFile(va("key_%d.d0pk", i), buf, sizeof(buf));
+ pubkeys_havesig[i] = false;
+ len = Crypto_LoadFile(va(vabuf, sizeof(vabuf), "key_%d.d0pk", i), buf, sizeof(buf), false);
if((pubkeys[i] = Crypto_ReadPublicKey(buf, len)))
{
len2 = FP64_SIZE;
if(qd0_blind_id_fingerprint64_public_key(pubkeys[i], pubkeys_fp64[i], &len2)) // keeps final NUL
{
Con_Printf("Loaded public key key_%d.d0pk (fingerprint: %s)\n", i, pubkeys_fp64[i]);
- len = Crypto_LoadFile(va("key_%d.d0si", i), buf, sizeof(buf));
+ len = Crypto_LoadFile(va(vabuf, sizeof(vabuf), "key_%d.d0si%s", i, sessionid.string), buf, sizeof(buf), true);
if(len)
{
if(Crypto_AddPrivateKey(pubkeys[i], buf, len))
len2 = FP64_SIZE;
if(qd0_blind_id_fingerprint64_public_id(pubkeys[i], pubkeys_priv_fp64[i], &len2)) // keeps final NUL
{
- Con_Printf("Loaded private ID key_%d.d0si for key_%d.d0pk (public key fingerprint: %s)\n", i, i, pubkeys_priv_fp64[i]);
- pubkeys_havepriv[i] = true;
- strlcat(crypto_idstring_buf, va(" %s@%s", pubkeys_priv_fp64[i], pubkeys_fp64[i]), sizeof(crypto_idstring_buf));
+ D0_BOOL status = 0;
+
+ 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]);
+
+ // verify the key we just loaded (just in case)
+ if(qd0_blind_id_verify_private_id(pubkeys[i]) && qd0_blind_id_verify_public_id(pubkeys[i], &status))
+ {
+ pubkeys_havepriv[i] = true;
+ strlcat(crypto_idstring_buf, va(vabuf, sizeof(vabuf), " %s@%s", pubkeys_priv_fp64[i], pubkeys_fp64[i]), sizeof(crypto_idstring_buf));
+
+ // verify the key we just got (just in case)
+ if(status)
+ pubkeys_havesig[i] = true;
+ else
+ Con_Printf("NOTE: this ID has not yet been signed!\n");
+
+ Crypto_SavePubKeyTextFile(i);
+ }
+ else
+ {
+ Con_Printf("d0_blind_id_verify_private_id failed, this is not a valid key!\n");
+ qd0_blind_id_free(pubkeys[i]);
+ pubkeys[i] = NULL;
+ }
}
else
{
- // can't really happen
- // but nothing leaked here
+ Con_Printf("d0_blind_id_fingerprint64_public_id failed\n");
+ qd0_blind_id_free(pubkeys[i]);
+ pubkeys[i] = NULL;
}
}
}
static void Crypto_UnloadKeys(void)
{
int i;
+
keygen_i = -1;
for(i = 0; i < MAX_PUBKEYS; ++i)
{
qd0_blind_id_free(pubkeys[i]);
pubkeys[i] = NULL;
pubkeys_havepriv[i] = false;
+ pubkeys_havesig[i] = false;
memset(pubkeys_fp64[i], 0, sizeof(pubkeys_fp64[i]));
memset(pubkeys_priv_fp64[i], 0, sizeof(pubkeys_fp64[i]));
challenge_append_length = 0;
crypto_idstring = NULL;
}
+static mempool_t *cryptomempool;
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+static void *Crypto_d0_malloc(size_t len)
+{
+ return Mem_Alloc(cryptomempool, len);
+}
+
+static void Crypto_d0_free(void *p)
+{
+ Mem_Free(p);
+}
+
+static void *Crypto_d0_createmutex(void)
+{
+ return Thread_CreateMutex();
+}
+
+static void Crypto_d0_destroymutex(void *m)
+{
+ Thread_DestroyMutex(m);
+}
+
+static int Crypto_d0_lockmutex(void *m)
+{
+ return Thread_LockMutex(m);
+}
+
+static int Crypto_d0_unlockmutex(void *m)
+{
+ return Thread_UnlockMutex(m);
+}
+#ifdef __cplusplus
+}
+#endif
+
void Crypto_Shutdown(void)
{
crypto_t *crypto;
Crypto_CloseLibrary();
}
+
+ Mem_FreePool(&cryptomempool);
}
void Crypto_Init(void)
{
+ cryptomempool = Mem_AllocPool("crypto", 0, NULL);
+
if(!Crypto_OpenLibrary())
return;
+ qd0_blind_id_setmallocfuncs(Crypto_d0_malloc, Crypto_d0_free);
+ if (Thread_HasThreads())
+ qd0_blind_id_setmutexfuncs(Crypto_d0_createmutex, Crypto_d0_destroymutex, Crypto_d0_lockmutex, Crypto_d0_unlockmutex);
+
if(!qd0_blind_id_INITIALIZE())
{
Crypto_Rijndael_CloseLibrary();
Crypto_Rijndael_OpenLibrary(); // if this fails, it's uncritical
Crypto_InitHostKeys();
- Crypto_LoadKeys();
}
// end
size_t l[1];
static char buf[8192];
static char buf2[8192];
- size_t bufsize, buf2size;
+ size_t buf2size;
qfile_t *f = NULL;
- d0_blind_id_t *ctx, *ctx2;
D0_BOOL status;
- size_t len2;
+ char vabuf[1024];
+
+ SV_LockThreadMutex();
if(!d0_blind_id_dll)
{
Con_Print("libd0_blind_id DLL not found, this command is inactive.\n");
keygen_i = -1;
+ SV_UnlockThreadMutex();
return;
}
{
Con_Printf("overflow of keygen_i\n");
keygen_i = -1;
+ SV_UnlockThreadMutex();
return;
}
if(keygen_i < 0)
{
Con_Printf("Unexpected response from keygen server:\n");
Com_HexDumpToConsole(buffer, length_received);
+ SV_UnlockThreadMutex();
return;
}
if(!Crypto_ParsePack((const char *) buffer, length_received, FOURCC_D0IR, p, l, 1))
Com_HexDumpToConsole(buffer, length_received);
}
keygen_i = -1;
+ SV_UnlockThreadMutex();
return;
}
if(!qd0_blind_id_finish_private_id_request(pubkeys[keygen_i], p[0], l[0]))
{
Con_Printf("d0_blind_id_finish_private_id_request failed\n");
keygen_i = -1;
+ SV_UnlockThreadMutex();
return;
}
// verify the key we just got (just in case)
- ctx = qd0_blind_id_new();
- if(!ctx)
- {
- Con_Printf("d0_blind_id_new failed\n");
- keygen_i = -1;
- return;
- }
- ctx2 = qd0_blind_id_new();
- if(!ctx2)
- {
- Con_Printf("d0_blind_id_new failed\n");
- qd0_blind_id_free(ctx);
- keygen_i = -1;
- return;
- }
- if(!qd0_blind_id_copy(ctx, pubkeys[keygen_i]))
- {
- Con_Printf("d0_blind_id_copy failed\n");
- qd0_blind_id_free(ctx);
- qd0_blind_id_free(ctx2);
- keygen_i = -1;
- return;
- }
- if(!qd0_blind_id_copy(ctx2, pubkeys[keygen_i]))
- {
- Con_Printf("d0_blind_id_copy failed\n");
- qd0_blind_id_free(ctx);
- qd0_blind_id_free(ctx2);
- keygen_i = -1;
- return;
- }
- bufsize = sizeof(buf);
- if(!qd0_blind_id_authenticate_with_private_id_start(ctx, 1, 1, "hello world", 11, buf, &bufsize))
- {
- Con_Printf("d0_blind_id_authenticate_with_private_id_start failed\n");
- qd0_blind_id_free(ctx);
- qd0_blind_id_free(ctx2);
- keygen_i = -1;
- return;
- }
- buf2size = sizeof(buf2);
- if(!qd0_blind_id_authenticate_with_private_id_challenge(ctx2, 1, 1, buf, bufsize, buf2, &buf2size, &status) || !status)
+ if(!qd0_blind_id_verify_public_id(pubkeys[keygen_i], &status) || !status)
{
- Con_Printf("d0_blind_id_authenticate_with_private_id_challenge failed (server does not have the requested private key)\n");
- qd0_blind_id_free(ctx);
- qd0_blind_id_free(ctx2);
+ Con_Printf("d0_blind_id_verify_public_id failed\n");
keygen_i = -1;
+ SV_UnlockThreadMutex();
return;
}
- bufsize = sizeof(buf);
- if(!qd0_blind_id_authenticate_with_private_id_response(ctx, buf2, buf2size, buf, &bufsize))
- {
- Con_Printf("d0_blind_id_authenticate_with_private_id_response failed\n");
- qd0_blind_id_free(ctx);
- qd0_blind_id_free(ctx2);
- keygen_i = -1;
- return;
- }
- buf2size = sizeof(buf2);
- if(!qd0_blind_id_authenticate_with_private_id_verify(ctx2, buf, bufsize, buf2, &buf2size, &status) || !status)
- {
- Con_Printf("d0_blind_id_authenticate_with_private_id_verify failed (server does not have the requested private key)\n");
- qd0_blind_id_free(ctx);
- qd0_blind_id_free(ctx2);
- keygen_i = -1;
- return;
- }
- qd0_blind_id_free(ctx);
- qd0_blind_id_free(ctx2);
// we have a valid key now!
// make the rest of crypto.c know that
- len2 = FP64_SIZE;
- if(qd0_blind_id_fingerprint64_public_id(pubkeys[keygen_i], pubkeys_priv_fp64[keygen_i], &len2)) // keeps final NUL
- {
- Con_Printf("Received private ID key_%d.d0pk (public key fingerprint: %s)\n", keygen_i, pubkeys_priv_fp64[keygen_i]);
- pubkeys_havepriv[keygen_i] = true;
- strlcat(crypto_idstring_buf, va(" %s@%s", pubkeys_priv_fp64[keygen_i], pubkeys_fp64[keygen_i]), sizeof(crypto_idstring_buf));
- crypto_idstring = crypto_idstring_buf;
- Crypto_BuildChallengeAppend();
- }
+ Con_Printf("Received signature for private ID key_%d.d0pk (public key fingerprint: %s)\n", keygen_i, pubkeys_priv_fp64[keygen_i]);
+ pubkeys_havesig[keygen_i] = true;
+
// write the key to disk
p[0] = buf;
l[0] = sizeof(buf);
{
Con_Printf("d0_blind_id_write_private_id failed\n");
keygen_i = -1;
+ SV_UnlockThreadMutex();
return;
}
if(!(buf2size = Crypto_UnParsePack(buf2, sizeof(buf2), FOURCC_D0SI, p, l, 1)))
{
Con_Printf("Crypto_UnParsePack failed\n");
keygen_i = -1;
+ SV_UnlockThreadMutex();
return;
}
- if(*fs_userdir)
- {
- FS_CreatePath(va("%skey_%d.d0si", fs_userdir, keygen_i));
- f = FS_SysOpen(va("%skey_%d.d0si", fs_userdir, keygen_i), "wb", false);
- }
- if(!f)
- {
- FS_CreatePath(va("%skey_%d.d0si", fs_basedir, keygen_i));
- f = FS_SysOpen(va("%skey_%d.d0si", fs_basedir, keygen_i), "wb", false);
- }
+ FS_CreatePath(va(vabuf, sizeof(vabuf), "%skey_%d.d0si%s", *fs_userdir ? fs_userdir : fs_basedir, keygen_i, sessionid.string));
+ f = FS_SysOpen(va(vabuf, sizeof(vabuf), "%skey_%d.d0si%s", *fs_userdir ? fs_userdir : fs_basedir, keygen_i, sessionid.string), "wb", false);
if(!f)
{
- Con_Printf("Cannot open key_%d.d0si\n", keygen_i);
+ Con_Printf("Cannot open key_%d.d0si%s\n", keygen_i, sessionid.string);
keygen_i = -1;
+ SV_UnlockThreadMutex();
return;
}
FS_Write(f, buf2, buf2size);
FS_Close(f);
- Con_Printf("Saved to key_%d.d0si\n", keygen_i);
+ Crypto_SavePubKeyTextFile(keygen_i);
+
+ Con_Printf("Saved to key_%d.d0si%s\n", keygen_i, sessionid.string);
+
keygen_i = -1;
+ SV_UnlockThreadMutex();
}
static void Crypto_KeyGen_f(void)
size_t l[1];
static char buf[8192];
static char buf2[8192];
+ size_t buf2size;
size_t buf2l, buf2pos;
+ char vabuf[1024];
+ size_t len2;
+ qfile_t *f = NULL;
+
if(!d0_blind_id_dll)
{
Con_Print("libd0_blind_id DLL not found, this command is inactive.\n");
Con_Printf("usage:\n%s id url\n", Cmd_Argv(0));
return;
}
+ SV_LockThreadMutex();
+ Crypto_LoadKeys();
i = atoi(Cmd_Argv(1));
if(!pubkeys[i])
{
Con_Printf("there is no public key %d\n", i);
- return;
- }
- if(pubkeys_havepriv[i])
- {
- Con_Printf("there is already a private key for %d\n", i);
+ SV_UnlockThreadMutex();
return;
}
if(keygen_i >= 0)
{
Con_Printf("there is already a keygen run on the way\n");
+ SV_UnlockThreadMutex();
return;
}
keygen_i = i;
- if(!qd0_blind_id_generate_private_id_start(pubkeys[keygen_i]))
+
+ // how to START the keygenning...
+ if(pubkeys_havepriv[keygen_i])
{
- Con_Printf("d0_blind_id_start failed\n");
- keygen_i = -1;
- return;
+ if(pubkeys_havesig[keygen_i])
+ {
+ Con_Printf("there is already a signed private key for %d\n", i);
+ keygen_i = -1;
+ SV_UnlockThreadMutex();
+ return;
+ }
+ // if we get here, we only need a signature, no new keygen run needed
+ Con_Printf("Only need a signature for an existing key...\n");
+ }
+ else
+ {
+ // we also need a new ID itself
+ if(!qd0_blind_id_generate_private_id_start(pubkeys[keygen_i]))
+ {
+ Con_Printf("d0_blind_id_start failed\n");
+ keygen_i = -1;
+ SV_UnlockThreadMutex();
+ return;
+ }
+ // verify the key we just got (just in case)
+ if(!qd0_blind_id_verify_private_id(pubkeys[keygen_i]))
+ {
+ Con_Printf("d0_blind_id_verify_private_id failed\n");
+ keygen_i = -1;
+ SV_UnlockThreadMutex();
+ return;
+ }
+ // we have a valid key now!
+ // make the rest of crypto.c know that
+ len2 = FP64_SIZE;
+ if(qd0_blind_id_fingerprint64_public_id(pubkeys[keygen_i], pubkeys_priv_fp64[keygen_i], &len2)) // keeps final NUL
+ {
+ Con_Printf("Generated private ID key_%d.d0pk (public key fingerprint: %s)\n", keygen_i, pubkeys_priv_fp64[keygen_i]);
+ pubkeys_havepriv[keygen_i] = true;
+ strlcat(crypto_idstring_buf, va(vabuf, sizeof(vabuf), " %s@%s", pubkeys_priv_fp64[keygen_i], pubkeys_fp64[keygen_i]), sizeof(crypto_idstring_buf));
+ crypto_idstring = crypto_idstring_buf;
+ Crypto_BuildChallengeAppend();
+ }
+ // write the key to disk
+ p[0] = buf;
+ l[0] = sizeof(buf);
+ if(!qd0_blind_id_write_private_id(pubkeys[keygen_i], buf, &l[0]))
+ {
+ Con_Printf("d0_blind_id_write_private_id failed\n");
+ keygen_i = -1;
+ SV_UnlockThreadMutex();
+ return;
+ }
+ if(!(buf2size = Crypto_UnParsePack(buf2, sizeof(buf2), FOURCC_D0SI, p, l, 1)))
+ {
+ Con_Printf("Crypto_UnParsePack failed\n");
+ keygen_i = -1;
+ SV_UnlockThreadMutex();
+ return;
+ }
+
+ FS_CreatePath(va(vabuf, sizeof(vabuf), "%skey_%d.d0si%s", *fs_userdir ? fs_userdir : fs_basedir, keygen_i, sessionid.string));
+ f = FS_SysOpen(va(vabuf, sizeof(vabuf), "%skey_%d.d0si%s", *fs_userdir ? fs_userdir : fs_basedir, keygen_i, sessionid.string), "wb", false);
+ if(!f)
+ {
+ Con_Printf("Cannot open key_%d.d0si%s\n", keygen_i, sessionid.string);
+ keygen_i = -1;
+ SV_UnlockThreadMutex();
+ return;
+ }
+ FS_Write(f, buf2, buf2size);
+ FS_Close(f);
+
+ Crypto_SavePubKeyTextFile(keygen_i);
+
+ Con_Printf("Saved unsigned key to key_%d.d0si%s\n", keygen_i, sessionid.string);
}
p[0] = buf;
l[0] = sizeof(buf);
{
Con_Printf("d0_blind_id_generate_private_id_request failed\n");
keygen_i = -1;
+ SV_UnlockThreadMutex();
return;
}
buf2pos = strlen(Cmd_Argv(2));
{
Con_Printf("Crypto_UnParsePack failed\n");
keygen_i = -1;
+ SV_UnlockThreadMutex();
return;
}
if(!(buf2l = base64_encode((unsigned char *) (buf2 + buf2pos), buf2l, sizeof(buf2) - buf2pos - 1)))
{
Con_Printf("base64_encode failed\n");
keygen_i = -1;
+ SV_UnlockThreadMutex();
return;
}
buf2l += buf2pos;
{
Con_Printf("curl failed\n");
keygen_i = -1;
+ SV_UnlockThreadMutex();
return;
}
- Con_Printf("key generation in progress\n");
+ Con_Printf("Signature generation in progress...\n");
+ SV_UnlockThreadMutex();
}
// end
{
Con_Printf("%2d: public key key_%d.d0pk (fingerprint: %s)\n", i, i, pubkeys_fp64[i]);
if(pubkeys_havepriv[i])
- Con_Printf(" private ID key_%d.d0si (public key fingerprint: %s)\n", i, pubkeys_priv_fp64[i]);
+ {
+ Con_Printf(" private ID key_%d.d0si%s (public key fingerprint: %s)\n", i, sessionid.string, pubkeys_priv_fp64[i]);
+ if(!pubkeys_havesig[i])
+ Con_Printf(" NOTE: this ID has not yet been signed!\n");
+ }
}
}
}
int aeslevel;
D0_BOOL aes;
D0_BOOL status;
+ char infostringvalue[MAX_INPUTLINE];
+ char vabuf[1024];
if(!d0_blind_id_dll)
return CRYPTO_NOMATCH; // no support
int i;
// sorry, we have to verify the challenge here to not reflect network spam
- if (!(s = SearchInfostring(string + 4, "challenge")))
+ if (!(s = InfoString_GetValue(string + 4, "challenge", infostringvalue, sizeof(infostringvalue))))
return CRYPTO_NOMATCH; // will be later accepted if encryption was set up
// validate the challenge
for (i = 0;i < MAX_CHALLENGES;i++)
const char *cnt, *s, *p;
int id;
int clientid = -1, serverid = -1;
- cnt = SearchInfostring(string + 4, "id");
+ cnt = InfoString_GetValue(string + 4, "id", infostringvalue, sizeof(infostringvalue));
id = (cnt ? atoi(cnt) : -1);
- cnt = SearchInfostring(string + 4, "cnt");
+ cnt = InfoString_GetValue(string + 4, "cnt", infostringvalue, sizeof(infostringvalue));
if(!cnt)
return CRYPTO_DISCARD; // pre-challenge: rather be silent
GetUntilNul(&data_in, &len_in);
if(!strcmp(cnt, "0"))
{
int i;
- if (!(s = SearchInfostring(string + 4, "challenge")))
+ if (!(s = InfoString_GetValue(string + 4, "challenge", infostringvalue, sizeof(infostringvalue))))
return CRYPTO_DISCARD; // pre-challenge: rather be silent
// validate the challenge
for (i = 0;i < MAX_CHALLENGES;i++)
if (i == MAX_CHALLENGES) // challenge mismatch is silent
return CRYPTO_DISCARD; // pre-challenge: rather be silent
- if (!(s = SearchInfostring(string + 4, "aeslevel")))
+ if (!(s = InfoString_GetValue(string + 4, "aeslevel", infostringvalue, sizeof(infostringvalue))))
aeslevel = 0; // not supported
else
aeslevel = bound(0, atoi(s), 3);
CLEAR_CDATA;
return Crypto_ServerError(data_out, len_out, "d0_blind_id_copy failed", "Internal error");
}
- PutWithNul(&data_out_p, len_out, va("d0pk\\cnt\\1\\id\\%d\\aes\\%d", CDATA->cdata_id, crypto->use_aes));
+ PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\1\\id\\%d\\aes\\%d", CDATA->cdata_id, crypto->use_aes));
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
{
CLEAR_CDATA;
CLEAR_CDATA;
return Crypto_ServerError(data_out, len_out, "d0_blind_id_copy failed", "Internal error");
}
- PutWithNul(&data_out_p, len_out, va("d0pk\\cnt\\5\\id\\%d\\aes\\%d", CDATA->cdata_id, crypto->use_aes));
+ PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\5\\id\\%d\\aes\\%d", CDATA->cdata_id, crypto->use_aes));
if(!qd0_blind_id_authenticate_with_private_id_challenge(CDATA->id, true, false, data_in, len_in, data_out_p, len_out, &status))
{
CLEAR_CDATA;
return CRYPTO_NOMATCH; // pre-challenge, rather be silent
if(id >= 0)
if(CDATA->cdata_id != id)
- return Crypto_SoftServerError(data_out, len_out, va("Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
+ return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
if(CDATA->next_step != 2)
- return Crypto_SoftServerError(data_out, len_out, va("Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
+ return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
- PutWithNul(&data_out_p, len_out, va("d0pk\\cnt\\3\\id\\%d", CDATA->cdata_id));
+ PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\3\\id\\%d", CDATA->cdata_id));
if(!qd0_blind_id_authenticate_with_private_id_response(CDATA->id, data_in, len_in, data_out_p, len_out))
{
CLEAR_CDATA;
return CRYPTO_NOMATCH; // pre-challenge, rather be silent
if(id >= 0)
if(CDATA->cdata_id != id)
- return Crypto_SoftServerError(data_out, len_out, va("Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
+ return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
if(CDATA->next_step != 4)
- return Crypto_SoftServerError(data_out, len_out, va("Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
- PutWithNul(&data_out_p, len_out, va("d0pk\\cnt\\5\\id\\%d", CDATA->cdata_id));
+ return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
+ PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\5\\id\\%d", CDATA->cdata_id));
if(!qd0_blind_id_authenticate_with_private_id_challenge(CDATA->id, true, false, data_in, len_in, data_out_p, len_out, &status))
{
CLEAR_CDATA;
return CRYPTO_NOMATCH; // pre-challenge, rather be silent
if(id >= 0)
if(CDATA->cdata_id != id)
- return Crypto_SoftServerError(data_out, len_out, va("Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
+ return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
if(CDATA->next_step != 6)
- return Crypto_SoftServerError(data_out, len_out, va("Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
+ return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
if(!qd0_blind_id_authenticate_with_private_id_verify(CDATA->id, data_in, len_in, msgbuf, &msgbuflen, &status))
{
const char *cnt;
qboolean do_time = false;
qboolean do_reject = false;
+ char infostringvalue[MAX_INPUTLINE];
if(crypto_servercpupercent.value > 0 || crypto_servercpumaxtime.value > 0)
if(len_in > 5 && !memcmp(data_in, "d0pk\\", 5))
{
do_time = true;
- cnt = SearchInfostring(data_in + 4, "cnt");
+ cnt = InfoString_GetValue(data_in + 4, "cnt", infostringvalue, sizeof(infostringvalue));
if(cnt)
if(!strcmp(cnt, "0"))
do_reject = true;
*len_out = 0;
return CRYPTO_DISCARD;
}
- t = Sys_DoubleTime();
+ t = Sys_DirtyTime();
}
ret = Crypto_ServerParsePacket_Internal(data_in, len_in, data_out, len_out, peeraddress);
if(do_time)
{
- t = Sys_DoubleTime() - t;
+ t = Sys_DirtyTime() - t;if (t < 0.0) t = 0.0; // dirtytime can step backwards
if(crypto_servercpudebug.integer)
Con_Printf("crypto: accumulator was %.1f ms, used %.1f ms for crypto, ", crypto_servercpu_accumulator * 1000, t * 1000);
crypto_servercpu_accumulator -= t;
D0_BOOL aes;
char *data_out_p = data_out;
D0_BOOL status;
+ char infostringvalue[MAX_INPUTLINE];
+ char vabuf[1024];
if(!d0_blind_id_dll)
return CRYPTO_NOMATCH; // no support
{
int wantserverid = -1;
Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, NULL, 0, NULL);
- if(!crypto || !crypto->authenticated)
+ if(!crypto || !crypto->authenticated) // we ALSO get here if we are using an encrypted connection, so let's rule this out
{
if(wantserverid >= 0)
return Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though a host key is present");
}
return CRYPTO_NOMATCH;
}
- else if (len_in >= 1 && string[0] == 'j' && cls.connect_trying && d0_rijndael_dll && crypto_aeslevel.integer >= 3)
+ else if (len_in >= 1 && string[0] == 'j' && cls.connect_trying && d0_rijndael_dll)
{
int wantserverid = -1;
Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, NULL, 0, NULL);
- if(!crypto || !crypto->authenticated)
+ //if(!crypto || !crypto->authenticated)
+ {
+ if(wantserverid >= 0)
+ return Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though a host key is present");
+ if(crypto_aeslevel.integer >= 3)
+ return Crypto_ClientError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)");
+ }
+ return CRYPTO_NOMATCH;
+ }
+ else if (len_in >= 5 && BuffLittleLong((unsigned char *) string) == ((int)NETFLAG_CTL | (int)len_in))
+ {
+ int wantserverid = -1;
+
+ // these three are harmless
+ if(string[4] == CCREP_SERVER_INFO)
+ return CRYPTO_NOMATCH;
+ if(string[4] == CCREP_PLAYER_INFO)
+ return CRYPTO_NOMATCH;
+ if(string[4] == CCREP_RULE_INFO)
+ return CRYPTO_NOMATCH;
+
+ Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, NULL, 0, NULL);
+ //if(!crypto || !crypto->authenticated)
{
if(wantserverid >= 0)
return Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though a host key is present");
}
else if (len_in >= 13 && !memcmp(string, "infoResponse\x0A", 13))
{
- s = SearchInfostring(string + 13, "d0_blind_id");
+ s = InfoString_GetValue(string + 13, "d0_blind_id", infostringvalue, sizeof(infostringvalue));
if(s)
Crypto_StoreHostKey(peeraddress, s, true);
return CRYPTO_NOMATCH;
save = *p;
* (char *) p = 0; // cut off the string there
}
- s = SearchInfostring(string + 15, "d0_blind_id");
+ s = InfoString_GetValue(string + 15, "d0_blind_id", infostringvalue, sizeof(infostringvalue));
if(s)
Crypto_StoreHostKey(peeraddress, s, true);
if(p)
int clientid = -1, serverid = -1, wantserverid = -1;
qboolean server_can_auth = true;
char wantserver_idfp[FP64_SIZE+1];
- int wantserver_aeslevel;
+ int wantserver_aeslevel = 0;
// if we have a stored host key for the server, assume serverid to already be selected!
// (the loop will refuse to overwrite this one then)
// build outgoing message
// append regular stuff
- PutWithNul(&data_out_p, len_out, va("d0pk\\cnt\\0\\id\\%d\\aeslevel\\%d\\challenge\\%s", CDATA->cdata_id, d0_rijndael_dll ? crypto_aeslevel.integer : 0, challenge));
+ 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));
PutWithNul(&data_out_p, len_out, serverid >= 0 ? pubkeys_fp64[serverid] : "");
PutWithNul(&data_out_p, len_out, clientid >= 0 ? pubkeys_fp64[clientid] : "");
{
const char *cnt;
int id;
- cnt = SearchInfostring(string + 4, "id");
+ cnt = InfoString_GetValue(string + 4, "id", infostringvalue, sizeof(infostringvalue));
id = (cnt ? atoi(cnt) : -1);
- cnt = SearchInfostring(string + 4, "cnt");
+ cnt = InfoString_GetValue(string + 4, "cnt", infostringvalue, sizeof(infostringvalue));
if(!cnt)
return Crypto_ClientError(data_out, len_out, "d0pk\\ message without cnt");
GetUntilNul(&data_in, &len_in);
{
if(id >= 0)
if(CDATA->cdata_id != id)
- return Crypto_SoftServerError(data_out, len_out, va("Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
+ return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
if(CDATA->next_step != 1)
- return Crypto_SoftClientError(data_out, len_out, va("Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
+ return Crypto_SoftClientError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
cls.connect_nextsendtime = max(cls.connect_nextsendtime, realtime + 1); // prevent "hammering"
- if((s = SearchInfostring(string + 4, "aes")))
+ if((s = InfoString_GetValue(string + 4, "aes", infostringvalue, sizeof(infostringvalue))))
aes = atoi(s);
else
aes = false;
}
crypto->use_aes = aes != 0;
- PutWithNul(&data_out_p, len_out, va("d0pk\\cnt\\2\\id\\%d", CDATA->cdata_id));
+ PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\2\\id\\%d", CDATA->cdata_id));
if(!qd0_blind_id_authenticate_with_private_id_challenge(CDATA->id, true, false, data_in, len_in, data_out_p, len_out, &status))
{
CLEAR_CDATA;
if(id >= 0)
if(CDATA->cdata_id != id)
- return Crypto_SoftServerError(data_out, len_out, va("Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
+ return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
if(CDATA->next_step != 3)
- return Crypto_SoftClientError(data_out, len_out, va("Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
+ return Crypto_SoftClientError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
cls.connect_nextsendtime = max(cls.connect_nextsendtime, realtime + 1); // prevent "hammering"
}
// cache the server key
- Crypto_StoreHostKey(&cls.connect_address, va("%d %s@%s", crypto->use_aes ? 1 : 0, crypto->server_idfp, pubkeys_fp64[CDATA->s]), false);
+ 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);
if(CDATA->c >= 0)
{
// client will auth next
- PutWithNul(&data_out_p, len_out, va("d0pk\\cnt\\4\\id\\%d", CDATA->cdata_id));
+ PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\4\\id\\%d", CDATA->cdata_id));
if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->c]))
{
CLEAR_CDATA;
if(id >= 0)
if(CDATA->cdata_id != id)
- return Crypto_SoftServerError(data_out, len_out, va("Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
+ return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
if(CDATA->next_step != 5)
- return Crypto_SoftClientError(data_out, len_out, va("Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
+ return Crypto_SoftClientError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
cls.connect_nextsendtime = max(cls.connect_nextsendtime, realtime + 1); // prevent "hammering"
if(CDATA->s < 0) // only if server didn't auth
{
- if((s = SearchInfostring(string + 4, "aes")))
+ if((s = InfoString_GetValue(string + 4, "aes", infostringvalue, sizeof(infostringvalue))))
aes = atoi(s);
else
aes = false;
crypto->use_aes = aes != 0;
}
- PutWithNul(&data_out_p, len_out, va("d0pk\\cnt\\6\\id\\%d", CDATA->cdata_id));
+ PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\6\\id\\%d", CDATA->cdata_id));
if(!qd0_blind_id_authenticate_with_private_id_response(CDATA->id, data_in, len_in, data_out_p, len_out))
{
CLEAR_CDATA;