Crypto: handle properly whether the a server key is signed or not.
authordivverent <divverent@d7cf8633-e32d-0410-b094-e92efae38249>
Mon, 9 Feb 2015 11:06:06 +0000 (11:06 +0000)
committerdivverent <divverent@d7cf8633-e32d-0410-b094-e92efae38249>
Mon, 9 Feb 2015 11:06:06 +0000 (11:06 +0000)
Provide information about client key being signed or not to QC.

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@12161 d7cf8633-e32d-0410-b094-e92efae38249

crypto.c
crypto.h
dpdefs/csprogsdefs.qc
dpdefs/dpextensions.qc
dpdefs/menudefs.qc
mvm_cmds.c
netconn.c
prvm_offsets.h
sv_main.c

index 8428c67..6398803 100644 (file)
--- a/crypto.c
+++ b/crypto.c
@@ -489,6 +489,7 @@ typedef struct
        char challenge[2048];
        char wantserver_idfp[FP64_SIZE+1];
        qboolean wantserver_aes;
+       qboolean wantserver_issigned;
        int cdata_id;
 }
 crypto_data_t;
@@ -556,6 +557,7 @@ typedef struct crypto_storedhostkey_s
        int keyid;
        char idfp[FP64_SIZE+1];
        int aeslevel;
+       qboolean issigned;
 }
 crypto_storedhostkey_t;
 static crypto_storedhostkey_t *crypto_storedhostkey_hashtable[CRYPTO_HOSTKEY_HASHSIZE];
@@ -612,6 +614,7 @@ static void Crypto_StoreHostKey(lhnetaddress_t *peeraddress, const char *keystri
        int keyid;
        char idfp[FP64_SIZE+1];
        int aeslevel;
+       qboolean issigned;
 
        if(!d0_blind_id_dll)
                return;
@@ -626,10 +629,12 @@ static void Crypto_StoreHostKey(lhnetaddress_t *peeraddress, const char *keystri
                ++keystring;
 
        keyid = -1;
+       issigned = false;
        while(*keystring && keyid < 0)
        {
                // id@key
                const char *idstart, *idend, *keystart, *keyend;
+               qboolean thisissigned = true;
                ++keystring; // skip the space
                idstart = keystring;
                while(*keystring && *keystring != ' ' && *keystring != '@')
@@ -643,14 +648,23 @@ static void Crypto_StoreHostKey(lhnetaddress_t *peeraddress, const char *keystri
                        ++keystring;
                keyend = keystring;
 
+               if (keystart[0] == '~')
+               {
+                       thisissigned = false;
+                       ++keystart;
+               }
+
                if(idend - idstart == FP64_SIZE && keyend - keystart == FP64_SIZE)
                {
-                       for(keyid = MAX_PUBKEYS - 1; keyid >= 0; --keyid)
-                               if(pubkeys[keyid])
-                                       if(!memcmp(pubkeys_fp64[keyid], keystart, FP64_SIZE))
+                       int thiskeyid;
+                       for(thiskeyid = MAX_PUBKEYS - 1; thiskeyid >= 0; --thiskeyid)
+                               if(pubkeys[thiskeyid])
+                                       if(!memcmp(pubkeys_fp64[thiskeyid], keystart, FP64_SIZE))
                                        {
                                                memcpy(idfp, idstart, FP64_SIZE);
                                                idfp[FP64_SIZE] = 0;
+                                               keyid = thiskeyid;
+                                               issigned = thisissigned;
                                                break;
                                        }
                        // If this failed, keyid will be -1.
@@ -672,8 +686,11 @@ static void Crypto_StoreHostKey(lhnetaddress_t *peeraddress, const char *keystri
                                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);
                        if(hk->aeslevel > aeslevel)
                                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);
+                       if(hk->issigned > issigned)
+                               Con_Printf("Server %s tried to reduce signature status, not accepted. Connecting to it will fail. To accept, do crypto_hostkey_clear %s\n", buf, buf);
                }
                hk->aeslevel = max(aeslevel, hk->aeslevel);
+               hk->issigned = issigned;
                return;
        }
 
@@ -684,10 +701,11 @@ static void Crypto_StoreHostKey(lhnetaddress_t *peeraddress, const char *keystri
        memcpy(hk->idfp, idfp, FP64_SIZE+1);
        hk->next = crypto_storedhostkey_hashtable[hashindex];
        hk->aeslevel = aeslevel;
+       hk->issigned = issigned;
        crypto_storedhostkey_hashtable[hashindex] = hk;
 }
 
-qboolean Crypto_RetrieveHostKey(lhnetaddress_t *peeraddress, int *keyid, char *keyfp, size_t keyfplen, char *idfp, size_t idfplen, int *aeslevel)
+qboolean Crypto_RetrieveHostKey(lhnetaddress_t *peeraddress, int *keyid, char *keyfp, size_t keyfplen, char *idfp, size_t idfplen, int *aeslevel, qboolean *issigned)
 {
        char buf[128];
        int hashindex;
@@ -711,6 +729,8 @@ qboolean Crypto_RetrieveHostKey(lhnetaddress_t *peeraddress, int *keyid, char *k
                strlcpy(idfp, hk->idfp, idfplen);
        if(aeslevel)
                *aeslevel = hk->aeslevel;
+       if(issigned)
+               *issigned = hk->issigned;
 
        return true;
 }
@@ -793,6 +813,19 @@ static qboolean Crypto_SavePubKeyTextFile(int i)
        return true;
 }
 
+static void Crypto_BuildIdString(void)
+{
+       int i;
+       char vabuf[1024];
+
+       crypto_idstring = NULL;
+       dpsnprintf(crypto_idstring_buf, sizeof(crypto_idstring_buf), "%d", d0_rijndael_dll ? crypto_aeslevel.integer : 0);
+       for (i = 0; i < MAX_PUBKEYS; ++i)
+               if (pubkeys[i])
+                       strlcat(crypto_idstring_buf, va(vabuf, sizeof(vabuf), " %s@%s%s", pubkeys_priv_fp64[i], pubkeys_havesig[i] ? "" : "~", pubkeys_fp64[i]), sizeof(crypto_idstring_buf));
+       crypto_idstring = crypto_idstring_buf;
+}
+
 void Crypto_LoadKeys(void)
 {
        char buf[8192];
@@ -814,8 +847,6 @@ void Crypto_LoadKeys(void)
        //   PUBLIC KEYS to accept (including modulus)
        //   PRIVATE KEY of user
 
-       crypto_idstring = NULL;
-       dpsnprintf(crypto_idstring_buf, sizeof(crypto_idstring_buf), "%d", d0_rijndael_dll ? crypto_aeslevel.integer : 0);
        for(i = 0; i < MAX_PUBKEYS; ++i)
        {
                memset(pubkeys_fp64[i], 0, sizeof(pubkeys_fp64[i]));
@@ -845,12 +876,10 @@ void Crypto_LoadKeys(void)
                                                        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));
+                                                               pubkeys_havesig[i] = status;
 
                                                                // verify the key we just got (just in case)
-                                                               if(status)
-                                                                       pubkeys_havesig[i] = true;
-                                                               else
+                                                               if(!status)
                                                                        Con_Printf("NOTE: this ID has not yet been signed!\n");
 
                                                                Crypto_SavePubKeyTextFile(i);
@@ -879,9 +908,9 @@ void Crypto_LoadKeys(void)
                        }
                }
        }
-       crypto_idstring = crypto_idstring_buf;
 
        keygen_i = -1;
+       Crypto_BuildIdString();
        Crypto_BuildChallengeAppend();
 
        // find a good prefix length for all the keys we know (yes, algorithm is not perfect yet, may yield too long prefix length)
@@ -1153,6 +1182,8 @@ static void Crypto_KeyGen_Finished(int code, size_t length_received, unsigned ch
 
        Con_Printf("Saved to key_%d.d0si%s\n", keygen_i, sessionid.string);
 
+       Crypto_BuildIdString();
+
        keygen_i = -1;
        SV_UnlockThreadMutex();
 }
@@ -1802,6 +1833,7 @@ static int Crypto_ServerParsePacket_Internal(const char *data_in, size_t len_in,
                                // I am the server, and my key is ok... so let's set server_keyfp and server_idfp
                                strlcpy(crypto->server_keyfp, pubkeys_fp64[CDATA->s], sizeof(crypto->server_keyfp));
                                strlcpy(crypto->server_idfp, pubkeys_priv_fp64[CDATA->s], sizeof(crypto->server_idfp));
+                               crypto->server_issigned = pubkeys_havesig[CDATA->s];
 
                                if(!CDATA->id)
                                        CDATA->id = qd0_blind_id_new();
@@ -1942,10 +1974,9 @@ static int Crypto_ServerParsePacket_Internal(const char *data_in, size_t len_in,
                                CLEAR_CDATA;
                                return Crypto_ServerError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_verify failed (authentication error)", "Authentication error");
                        }
-                       if(status)
-                               strlcpy(crypto->client_keyfp, pubkeys_fp64[CDATA->c], sizeof(crypto->client_keyfp));
-                       else
-                               crypto->client_keyfp[0] = 0;
+                       strlcpy(crypto->client_keyfp, pubkeys_fp64[CDATA->c], sizeof(crypto->client_keyfp));
+                       crypto->client_issigned = status;
+
                        memset(crypto->client_idfp, 0, sizeof(crypto->client_idfp));
                        fpbuflen = FP64_SIZE;
                        if(!qd0_blind_id_fingerprint64_public_id(CDATA->id, crypto->client_idfp, &fpbuflen))
@@ -2068,7 +2099,7 @@ int Crypto_ClientParsePacket(const char *data_in, size_t len_in, char *data_out,
        if (len_in == 6 && !memcmp(string, "accept", 6) && cls.connect_trying && d0_rijndael_dll)
        {
                int wantserverid = -1;
-               Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, NULL, 0, NULL);
+               Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, NULL, 0, NULL, NULL);
                if(!crypto || !crypto->authenticated) // we ALSO get here if we are using an encrypted connection, so let's rule this out
                {
                        if(wantserverid >= 0)
@@ -2081,7 +2112,7 @@ int Crypto_ClientParsePacket(const char *data_in, size_t len_in, char *data_out,
        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);
+               Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, NULL, 0, NULL, NULL);
                //if(!crypto || !crypto->authenticated)
                {
                        if(wantserverid >= 0)
@@ -2103,7 +2134,7 @@ int Crypto_ClientParsePacket(const char *data_in, size_t len_in, char *data_out,
                if(string[4] == CCREP_RULE_INFO)
                        return CRYPTO_NOMATCH;
 
-               Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, NULL, 0, NULL);
+               Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, NULL, 0, NULL, NULL);
                //if(!crypto || !crypto->authenticated)
                {
                        if(wantserverid >= 0)
@@ -2152,11 +2183,12 @@ int Crypto_ClientParsePacket(const char *data_in, size_t len_in, char *data_out,
                qboolean server_can_auth = true;
                char wantserver_idfp[FP64_SIZE+1];
                int wantserver_aeslevel = 0;
+               qboolean wantserver_issigned = false;
 
                // 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)
                wantserver_idfp[0] = 0;
-               Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, wantserver_idfp, sizeof(wantserver_idfp), &wantserver_aeslevel);
+               Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, wantserver_idfp, sizeof(wantserver_idfp), &wantserver_aeslevel, &wantserver_issigned);
                // requirement: wantserver_idfp is a full ID if wantserverid set
 
                // if we leave, we have to consider the connection
@@ -2262,6 +2294,7 @@ int Crypto_ClientParsePacket(const char *data_in, size_t len_in, char *data_out,
                        crypto->server_keyfp[0] = 0;
                        crypto->server_idfp[0] = 0;
                        memcpy(CDATA->wantserver_idfp, wantserver_idfp, sizeof(crypto->server_idfp));
+                       CDATA->wantserver_issigned = wantserver_issigned;
 
                        if(CDATA->wantserver_idfp[0]) // if we know a host key, honor its encryption setting
                        switch(bound(0, d0_rijndael_dll ? crypto_aeslevel.integer : 0, 3))
@@ -2296,6 +2329,7 @@ int Crypto_ClientParsePacket(const char *data_in, size_t len_in, char *data_out,
                                // I am the client, and my key is ok... so let's set client_keyfp and client_idfp
                                strlcpy(crypto->client_keyfp, pubkeys_fp64[CDATA->c], sizeof(crypto->client_keyfp));
                                strlcpy(crypto->client_idfp, pubkeys_priv_fp64[CDATA->c], sizeof(crypto->client_idfp));
+                               crypto->client_issigned = pubkeys_havesig[CDATA->c];
                        }
 
                        if(serverid >= 0)
@@ -2428,10 +2462,15 @@ int Crypto_ClientParsePacket(const char *data_in, size_t len_in, char *data_out,
                                CLEAR_CDATA;
                                return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_verify failed (server authentication error)");
                        }
-                       if(status)
-                               strlcpy(crypto->server_keyfp, pubkeys_fp64[CDATA->s], sizeof(crypto->server_keyfp));
-                       else
-                               crypto->server_keyfp[0] = 0;
+
+                       strlcpy(crypto->server_keyfp, pubkeys_fp64[CDATA->s], sizeof(crypto->server_keyfp));
+                       if (!status && CDATA->wantserver_issigned)
+                       {
+                               CLEAR_CDATA;
+                               return Crypto_ClientError(data_out, len_out, "Stored host key requires a valid signature, but server did not provide any");
+                       }
+                       crypto->server_issigned = status;
+
                        memset(crypto->server_idfp, 0, sizeof(crypto->server_idfp));
                        fpbuflen = FP64_SIZE;
                        if(!qd0_blind_id_fingerprint64_public_id(CDATA->id, crypto->server_idfp, &fpbuflen))
index 106e5a9..0a2d486 100644 (file)
--- a/crypto.h
+++ b/crypto.h
@@ -20,9 +20,11 @@ typedef struct
 {
        unsigned char dhkey[DHKEY_SIZE]; // shared key, not NUL terminated
        char client_idfp[FP64_SIZE+1];
-       char client_keyfp[FP64_SIZE+1]; // NULL if signature fail
+       char client_keyfp[FP64_SIZE+1];
+       qboolean client_issigned;
        char server_idfp[FP64_SIZE+1];
-       char server_keyfp[FP64_SIZE+1]; // NULL if signature fail
+       char server_keyfp[FP64_SIZE+1];
+       qboolean server_issigned;
        qboolean authenticated;
        qboolean use_aes;
        void *data;
@@ -53,7 +55,7 @@ const char *Crypto_GetInfoResponseDataString(void);
 
 // retrieves a host key for an address (can be exposed to menuqc, or used by the engine to look up stored keys e.g. for server bookmarking)
 // pointers may be NULL
-qboolean Crypto_RetrieveHostKey(lhnetaddress_t *peeraddress, int *keyid, char *keyfp, size_t keyfplen, char *idfp, size_t idfplen, int *aeslevel);
+qboolean Crypto_RetrieveHostKey(lhnetaddress_t *peeraddress, int *keyid, char *keyfp, size_t keyfplen, char *idfp, size_t idfplen, int *aeslevel, qboolean *issigned);
 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
 
 size_t Crypto_SignData(const void *data, size_t datasize, int keyid, void *signed_data, size_t signed_size);
index 1dc73a1..18a8920 100644 (file)
@@ -194,7 +194,7 @@ const float VF_DRAWCROSSHAIR        = 21;   //(float)
 const float VF_CL_VIEWANGLES   = 33;   //(vector)
 const float VF_CL_VIEWANGLES_X = 34;   //(float)
 const float VF_CL_VIEWANGLES_Y = 35;   //(float)
-const float VF_CL_VIEWANGLES_Z = 36;   //(float) 
+const float VF_CL_VIEWANGLES_Z = 36;   //(float)
 
 const float VF_PERSPECTIVE      = 200;
 
@@ -291,7 +291,7 @@ const float TE_EXPLOSION2                                   = 12;
        const float TE_EXPLOSIONQUAD                            = 70;
        const float TE_SPIKEQUAD                                        = 58;
        const float TE_SUPERSPIKEQUAD                           = 59;
-       
+
 // PFlags for Dynamic Lights
 const float PFLAGS_NOSHADOW                                    = 1;
 const float PFLAGS_CORONA                                      = 2;
@@ -447,6 +447,7 @@ string(float ccase, float calpha, float cnum, string s, ...) strconv = #224;
 string(float chars, string s, ...) strpad = #225;
 string(string info, string key, string value, ...) infoadd = #226;
 string(string info, string key) infoget = #227;
+float(string s1, string s2) strcmp = #228;
 float(string s1, string s2, float len) strncmp = #228;
 float(string s1, string s2) strcasecmp = #229;
 float(string s1, string s2, float len) strncasecmp = #230;
@@ -656,11 +657,11 @@ float PARTICLE_BEAM = 3;
 float particle_type; // one of PT_
 float particle_blendmode; // one of PBLEND_ values
 float particle_orientation; // one of PARTICLE_ values
-vector particle_color1; 
+vector particle_color1;
 vector particle_color2;
 float particle_tex; // number of chunk in particlefont
 float particle_size;
-float particle_sizeincrease; 
+float particle_sizeincrease;
 float particle_alpha;
 float particle_alphafade;
 float particle_time;
@@ -692,10 +693,10 @@ float(vector org, vector vel) spawnparticle = #527; // returns 0 when failed, 1
 float(vector org, vector vel, float theme) quickparticle = #527; // not reading globals, just theme, returns 0 when failed, 1 when spawned
 float(vector org, vector vel, float delay, float collisiondelay) delayedparticle = #528;
 float(vector org, vector vel, float delay, float collisiondelay, float theme) quickdelayedparticle = #528;
-// description: this builtin provides an easy and flexible way to spawn particles, 
-// it is not created as replace for DP_SV_POINTPARTICLES but as an addition to it. 
+// description: this builtin provides an easy and flexible way to spawn particles,
+// it is not created as replace for DP_SV_POINTPARTICLES but as an addition to it.
 // With this extension you can create a specific particles like rain particles, or entity particles
-// notes: 
+// notes:
 // 1) 0 is default particle template, it could be changed
 // 2) color vectors could have value 0-255 of each component
 // restrictions: max themes could be between 4 and 2048
@@ -805,7 +806,7 @@ vector(float entitynum, float fldnum) getentityvec = #504;
 //darkplaces implementation: Blub\0
 //console commands:
 //  loadfont fontname fontmaps size1 size2 ...
-//   A font can simply be gfx/tgafile (freetype fonts doent need extension), 
+//   A font can simply be gfx/tgafile (freetype fonts doent need extension),
 //   or alternatively you can specify multiple fonts and faces
 //   Like this: gfx/vera-sans:2,gfx/fallback:1
 //   to load face 2 of the font gfx/vera-sans and use face 1
@@ -834,7 +835,7 @@ float FONT_USER6 = 14;     // 'user6', userdefined fonts
 float FONT_USER7 = 15;     // 'user7' slot, userdefined fonts
 //builtin definitions:
 float findfont(string s) = #356; // find font by fontname and return it's index
-float loadfont(string fontname, string fontmaps, string sizes, float slot, float fix_scale, float fix_voffset) = #357; 
+float loadfont(string fontname, string fontmaps, string sizes, float slot, float fix_scale, float fix_voffset) = #357;
 // loads font immediately so stringwidth() function can be used just after builtin call
 // returns a font slotnum (which is used to set drawfont to)
 // first 3 parms are identical to "loadfont" console command ones
@@ -865,7 +866,7 @@ float stringwidth_menu(string text, float allowColorCodes, vector size) = #468;
 //   r_font_postprocess_shadow_y X  : font outline shadow y shift amount, applied during outlining
 //   r_font_postprocess_shadow_z X  : font outline shadow z shift amount, applied during blurring
 //description: engine support for truetype/freetype fonts
-//so .AFM+.PFB/.OTF/.TTF files could be stuffed as fontmaps in loadfont() 
+//so .AFM+.PFB/.OTF/.TTF files could be stuffed as fontmaps in loadfont()
 //(console command version will support them as well)
 
 //DP_CSQC_BINDMAPS
@@ -896,7 +897,7 @@ float(string url, float id, string content_type, string delim, float buf, float
 //constant definitions:
 const float VF_MAINVIEW         = 400;
 //use setproperty(VF_MAINVIEW, 1); before calling R_RenderView for the render
-//that shall become the "main" view, which is e.g. used by PRYDON_CLIENTCURSOR 
+//that shall become the "main" view, which is e.g. used by PRYDON_CLIENTCURSOR
 //this flag is set for the first scene, and not cleared by R_ClearScene
 //this flag is automatically cleared by R_RenderView
 //so when not using this extension, the first view rendered is the main view
index c8ceac3..07142e9 100644 (file)
@@ -2428,6 +2428,7 @@ string(float ccase, float calpha, float cnum, string s, ...) strconv = #224; //
 string(float chars, string s, ...) strpad = #225; // pad string with spaces to a specified length, < 0 = left padding, > 0 = right padding
 string(string info, string key, string value, ...) infoadd = #226; // sets or adds a key/value pair to an infostring - note: forbidden characters are \ and "
 string(string info, string key) infoget = #227; // gets a key/value pair in an infostring, returns value or null if not found
+float(string s1, string s2) strcmp = #228; // compare two strings
 float(string s1, string s2, float len) strncmp = #228; // compare two strings up to the specified number of characters, if their length differs and is within the specified limit the result will be negative, otherwise it is the difference in value of their first non-matching character.
 float(string s1, string s2) strcasecmp = #229; // compare two strings with case-insensitive matching, characters a-z are considered equivalent to the matching A-Z character, no other differences, and this does not consider special characters equal even if they look similar
 float(string s1, string s2, float len) strncasecmp = #230; // same as strcasecmp but with a length limit, see strncmp
@@ -2559,9 +2560,10 @@ void coverage() = #642;  // Reports a coverage event. The engine counts for each
 //idea: divVerent
 //darkplaces implementation: divVerent
 //field definitions: (SVQC)
-.string crypto_keyfp; // fingerprint of CA key the player used to authenticate, or string_null if not verified
-.string crypto_mykeyfp; // fingerprint of CA key the server used to authenticate to the player, or string_null if not verified
+.string crypto_keyfp; // fingerprint of CA key the player used to authenticate
+.string crypto_mykeyfp; // fingerprint of CA key the server used to authenticate to the player
 .string crypto_idfp; // fingerprint of ID used by the player entity, or string_null if not identified
+.float crypto_idfp_signed; // set if the player's ID has been signed
 .string crypto_encryptmethod; // the string "AES128" if encrypting, and string_null if plaintext
 .string crypto_signmethod; // the string "HMAC-SHA256" if signing, and string_null if plaintext
 // there is no field crypto_myidfp, as that info contains no additional information the QC may have a use for
index cb7ef55..8caab4a 100644 (file)
@@ -354,6 +354,7 @@ float(string key) stringtokeynum = #341;
 //field definitions: (MENUQC)
 string(string serveraddress) crypto_getkeyfp = #633; // retrieves the cached host key's CA fingerprint of a server given by IP address
 string(string serveraddress) crypto_getidfp = #634; // retrieves the cached host key fingerprint of a server given by IP address
+float(string serveraddress) crypto_getidstatus = #643; // retrieves the cached host key's key status. See below for CRYPTO_IDSTATUS_ defines.
 string(string serveraddress) crypto_getencryptlevel = #635; // 0 if never encrypting, 1 supported, 2 requested, 3 required, appended by list of allowed methods in order of preference ("AES128"), preceded by a space each
 string(float i) crypto_getmykeyfp = #636; // retrieves the CA key fingerprint of a given CA slot, or "" if slot is unused but more to come, or string_null if end of list
 string(float i) crypto_getmyidfp = #637; // retrieves the ID fingerprint of a given CA slot, or "" if slot is unused but more to come, or string_null if end of list
@@ -401,6 +402,7 @@ string(float ccase, float calpha, float cnum, string s, ...) strconv = #224;
 string(float chars, string s, ...) strpad = #225;
 string(string info, string key, string value, ...) infoadd = #226;
 string(string info, string key) infoget = #227;
+float(string s1, string s2) strcmp = #228;
 float(string s1, string s2, float len) strncmp = #228;
 float(string s1, string s2) strcasecmp = #229;
 float(string s1, string s2, float len) strncasecmp = #230;
index d44d22c..ace22bf 100644 (file)
@@ -809,7 +809,7 @@ static void VM_M_crypto_getkeyfp(prvm_prog_t *prog)
        s = PRVM_G_STRING( OFS_PARM0 );
        VM_CheckEmptyString( prog, s );
 
-       if(LHNETADDRESS_FromString(&addr, s, 26000) && Crypto_RetrieveHostKey(&addr, NULL, keyfp, sizeof(keyfp), NULL, 0, NULL))
+       if(LHNETADDRESS_FromString(&addr, s, 26000) && Crypto_RetrieveHostKey(&addr, NULL, keyfp, sizeof(keyfp), NULL, 0, NULL, NULL))
                PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( prog, keyfp );
        else
                PRVM_G_INT( OFS_RETURN ) = OFS_NULL;
@@ -825,11 +825,27 @@ static void VM_M_crypto_getidfp(prvm_prog_t *prog)
        s = PRVM_G_STRING( OFS_PARM0 );
        VM_CheckEmptyString( prog, s );
 
-       if(LHNETADDRESS_FromString(&addr, s, 26000) && Crypto_RetrieveHostKey(&addr, NULL, NULL, 0, idfp, sizeof(idfp), NULL))
+       if(LHNETADDRESS_FromString(&addr, s, 26000) && Crypto_RetrieveHostKey(&addr, NULL, NULL, 0, idfp, sizeof(idfp), NULL, NULL))
                PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( prog, idfp );
        else
                PRVM_G_INT( OFS_RETURN ) = OFS_NULL;
 }
+static void VM_M_crypto_getidstatus(prvm_prog_t *prog)
+{
+       lhnetaddress_t addr;
+       const char *s;
+       qboolean issigned;
+
+       VM_SAFEPARMCOUNT(1,VM_M_crypto_getidstatus);
+
+       s = PRVM_G_STRING( OFS_PARM0 );
+       VM_CheckEmptyString( prog, s );
+
+       if(LHNETADDRESS_FromString(&addr, s, 26000) && Crypto_RetrieveHostKey(&addr, NULL, NULL, 0, NULL, 0, NULL, &issigned))
+               PRVM_G_FLOAT( OFS_RETURN ) = issigned ? 2 : 1;
+       else
+               PRVM_G_FLOAT( OFS_RETURN ) = 0;
+}
 static void VM_M_crypto_getencryptlevel(prvm_prog_t *prog)
 {
        lhnetaddress_t addr;
@@ -842,7 +858,7 @@ static void VM_M_crypto_getencryptlevel(prvm_prog_t *prog)
        s = PRVM_G_STRING( OFS_PARM0 );
        VM_CheckEmptyString( prog, s );
 
-       if(LHNETADDRESS_FromString(&addr, s, 26000) && Crypto_RetrieveHostKey(&addr, NULL, NULL, 0, NULL, 0, &aeslevel))
+       if(LHNETADDRESS_FromString(&addr, s, 26000) && Crypto_RetrieveHostKey(&addr, NULL, NULL, 0, NULL, 0, &aeslevel, NULL))
                PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString(prog, aeslevel ? va(vabuf, sizeof(vabuf), "%d AES128", aeslevel) : "0");
        else
                PRVM_G_INT( OFS_RETURN ) = OFS_NULL;
@@ -1585,6 +1601,7 @@ VM_digest_hex,                                            // #639
 NULL,                                                  // #640
 VM_M_crypto_getmyidstatus,                             // #641 float(float i) crypto_getmyidstatus
 VM_coverage,                                           // #642
+VM_M_crypto_getidstatus,                               // #643 float(string addr) crypto_getidstatus
 NULL
 };
 
index b4ef314..abf8e31 100755 (executable)
--- a/netconn.c
+++ b/netconn.c
@@ -445,7 +445,7 @@ static void ServerList_ViewList_Insert( serverlist_entry_t *entry )
                                break;
                        }
                }
-               if(Crypto_RetrieveHostKey(&addr, 0, NULL, 0, idfp, sizeof(idfp), NULL))
+               if(Crypto_RetrieveHostKey(&addr, 0, NULL, 0, idfp, sizeof(idfp), NULL, NULL))
                {
                        for(i = 0; i < nFavorites_idfp; ++i)
                        {
@@ -1521,12 +1521,14 @@ static void NetConn_ConnectionEstablished(lhnetsocket_t *mysocket, lhnetaddress_
        if(cls.crypto.authenticated)
        {
                Crypto_FinishInstance(crypto, &cls.crypto);
-               Con_Printf("%s connection to %s has been established: server is %s@%.*s, I am %.*s@%.*s\n",
+               Con_Printf("%s connection to %s has been established: server is %s@%s%.*s, I am %.*s@%s%.*s\n",
                                crypto->use_aes ? "Encrypted" : "Authenticated",
                                cls.netcon->address,
                                crypto->server_idfp[0] ? crypto->server_idfp : "-",
+                               (crypto->server_issigned || !crypto->server_keyfp[0]) ? "" : "~",
                                crypto_keyfp_recommended_length, crypto->server_keyfp[0] ? crypto->server_keyfp : "-",
                                crypto_keyfp_recommended_length, crypto->client_idfp[0] ? crypto->client_idfp : "-",
+                               (crypto->client_issigned || !crypto->client_keyfp[0]) ? "" : "~",
                                crypto_keyfp_recommended_length, crypto->client_keyfp[0] ? crypto->client_keyfp : "-"
                                );
        }
@@ -2987,12 +2989,14 @@ static int NetConn_ServerParsePacket(lhnetsocket_t *mysocket, unsigned char *dat
                                // no need to check challenge
                                if(crypto_developer.integer)
                                {
-                                       Con_Printf("%s connection to %s is being established: client is %s@%.*s, I am %.*s@%.*s\n",
+                                       Con_Printf("%s connection to %s is being established: client is %s@%s%.*s, I am %.*s@%s%.*s\n",
                                                        crypto->use_aes ? "Encrypted" : "Authenticated",
                                                        addressstring2,
                                                        crypto->client_idfp[0] ? crypto->client_idfp : "-",
+                                                       (crypto->client_issigned || !crypto->client_keyfp[0]) ? "" : "~",
                                                        crypto_keyfp_recommended_length, crypto->client_keyfp[0] ? crypto->client_keyfp : "-",
                                                        crypto_keyfp_recommended_length, crypto->server_idfp[0] ? crypto->server_idfp : "-",
+                                                       (crypto->server_issigned || !crypto->server_keyfp[0]) ? "" : "~",
                                                        crypto_keyfp_recommended_length, crypto->server_keyfp[0] ? crypto->server_keyfp : "-"
                                                  );
                                }
index fcb57ad..1563a05 100644 (file)
@@ -262,6 +262,7 @@ PRVM_DECLARE_field(colormod)
 PRVM_DECLARE_field(contentstransition)
 PRVM_DECLARE_field(crypto_encryptmethod)
 PRVM_DECLARE_field(crypto_idfp)
+PRVM_DECLARE_field(crypto_idfp_signed)
 PRVM_DECLARE_field(crypto_keyfp)
 PRVM_DECLARE_field(crypto_mykeyfp)
 PRVM_DECLARE_field(crypto_signmethod)
@@ -736,6 +737,7 @@ PRVM_DECLARE_serverfieldstring(classname)
 PRVM_DECLARE_serverfieldstring(clientstatus)
 PRVM_DECLARE_serverfieldstring(crypto_encryptmethod)
 PRVM_DECLARE_serverfieldstring(crypto_idfp)
+PRVM_DECLARE_serverfieldfloat(crypto_idfp_signed)
 PRVM_DECLARE_serverfieldstring(crypto_keyfp)
 PRVM_DECLARE_serverfieldstring(crypto_mykeyfp)
 PRVM_DECLARE_serverfieldstring(crypto_signmethod)
index 17a171d..a5eed88 100644 (file)
--- a/sv_main.c
+++ b/sv_main.c
@@ -1085,12 +1085,14 @@ void SV_ConnectClient (int clientnum, netconn_t *netconnection)
 
        if(client->netconnection && client->netconnection->crypto.authenticated)
        {
-               Con_Printf("%s connection to %s has been established: client is %s@%.*s, I am %.*s@%.*s\n",
+               Con_Printf("%s connection to %s has been established: client is %s@%s%.*s, I am %.*s@%s%.*s\n",
                                client->netconnection->crypto.use_aes ? "Encrypted" : "Authenticated",
                                client->netconnection->address,
                                client->netconnection->crypto.client_idfp[0] ? client->netconnection->crypto.client_idfp : "-",
+                               (client->netconnection->crypto.client_issigned || !client->netconnection->crypto.client_keyfp[0]) ? "" : "~",
                                crypto_keyfp_recommended_length, client->netconnection->crypto.client_keyfp[0] ? client->netconnection->crypto.client_keyfp : "-",
                                crypto_keyfp_recommended_length, client->netconnection->crypto.server_idfp[0] ? client->netconnection->crypto.server_idfp : "-",
+                               (client->netconnection->crypto.server_issigned || !client->netconnection->crypto.server_keyfp[0]) ? "" : "~",
                                crypto_keyfp_recommended_length, client->netconnection->crypto.server_keyfp[0] ? client->netconnection->crypto.server_keyfp : "-"
                                );
        }
@@ -3599,6 +3601,7 @@ static void SVVM_init_edict(prvm_prog_t *prog, prvm_edict_t *e)
                        PRVM_serveredictstring(e, crypto_idfp) = PRVM_SetEngineString(prog, svs.clients[num].netconnection->crypto.client_idfp);
                else
                        PRVM_serveredictstring(e, crypto_idfp) = 0;
+               PRVM_serveredictfloat(e, crypto_idfp_signed) = (svs.clients[num].netconnection != NULL && svs.clients[num].netconnection->crypto.authenticated && svs.clients[num].netconnection->crypto.client_issigned);
                if(svs.clients[num].netconnection != NULL && svs.clients[num].netconnection->crypto.authenticated && svs.clients[num].netconnection->crypto.client_keyfp[0])
                        PRVM_serveredictstring(e, crypto_keyfp) = PRVM_SetEngineString(prog, svs.clients[num].netconnection->crypto.client_keyfp);
                else