LCOV - code coverage report
Current view: top level - common - userids.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 77 199 38.7 %
Date: 2016-11-29 15:00:56 Functions: 1 1 100.0 %

          Line data    Source code
       1             : /* userids.c - Utility functions for user ids.
       2             :  * Copyright (C) 2001, 2003, 2004, 2006,
       3             :  *               2009 Free Software Foundation, Inc.
       4             :  * Copyright (C) 2015  g10 Code GmbH
       5             :  *
       6             :  * This file is part of GnuPG.
       7             :  *
       8             :  * This file is free software; you can redistribute it and/or modify
       9             :  * it under the terms of either
      10             :  *
      11             :  *   - the GNU Lesser General Public License as published by the Free
      12             :  *     Software Foundation; either version 3 of the License, or (at
      13             :  *     your option) any later version.
      14             :  *
      15             :  * or
      16             :  *
      17             :  *   - the GNU General Public License as published by the Free
      18             :  *     Software Foundation; either version 2 of the License, or (at
      19             :  *     your option) any later version.
      20             :  *
      21             :  * or both in parallel, as here.
      22             :  *
      23             :  * This file is distributed in the hope that it will be useful,
      24             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      25             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      26             :  * GNU General Public License for more details.
      27             :  *
      28             :  * You should have received a copy of the GNU General Public License
      29             :  * along with this program; if not, see <https://www.gnu.org/licenses/>.
      30             :  */
      31             : 
      32             : #include <config.h>
      33             : #include <stdio.h>
      34             : #include <stdlib.h>
      35             : #include <string.h>
      36             : 
      37             : #include "util.h"
      38             : #include "userids.h"
      39             : 
      40             : 
      41             : /* Parse the user-id NAME and build a search description for it.
      42             :  * Returns 0 on success or an error code.  DESC may be NULL to merely
      43             :  * check the validity of a user-id.
      44             :  *
      45             :  * Some used rules:
      46             :  * - If the username starts with 8,9,16 or 17 hex-digits (the first one
      47             :  *   must be in the range 0..9), this is considered a keyid; depending
      48             :  *   on the length a short or complete one.
      49             :  * - If the username starts with 32,33,40 or 41 hex-digits (the first one
      50             :  *   must be in the range 0..9), this is considered a fingerprint.
      51             :  * - If the username starts with a left angle, we assume it is a complete
      52             :  *   email address and look only at this part.
      53             :  * - If the username starts with a colon we assume it is a unified
      54             :  *   key specfification.
      55             :  * - If the username starts with a '.', we assume it is the ending
      56             :  *   part of an email address
      57             :  * - If the username starts with an '@', we assume it is a part of an
      58             :  *   email address
      59             :  * - If the userid start with an '=' an exact compare is done.
      60             :  * - If the userid starts with a '*' a case insensitive substring search is
      61             :  *   done (This is the default).
      62             :  * - If the userid starts with a '+' we will compare individual words
      63             :  *   and a match requires that all the words are in the userid.
      64             :  *   Words are delimited by white space or "()<>[]{}.@-+_,;/&!"
      65             :  *   (note that you can't search for these characters). Compare
      66             :  *   is not case sensitive.
      67             :  * - If the userid starts with a '&' a 40 hex digits keygrip is expected.
      68             :  */
      69             : 
      70             : gpg_error_t
      71         622 : classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack)
      72             : {
      73             :   const char *s;
      74         622 :   char *s2 = NULL;
      75         622 :   int rc = 0;
      76         622 :   int hexprefix = 0;
      77             :   int hexlength;
      78         622 :   int mode = 0;
      79             :   KEYDB_SEARCH_DESC dummy_desc;
      80             : 
      81         622 :   if (!desc)
      82           0 :     desc = &dummy_desc;
      83             : 
      84             :   /* Clear the structure so that the mode field is set to zero unless
      85             :      we set it to the correct value right at the end of this
      86             :      function. */
      87         622 :   memset (desc, 0, sizeof *desc);
      88             : 
      89             :   /* Skip leading and trailing spaces.  */
      90         622 :   for(s = name; *s && spacep (s); s++ )
      91             :     ;
      92         622 :   if (*s && spacep (s + strlen(s) - 1))
      93             :     {
      94           0 :       s2 = xtrystrdup (s);
      95           0 :       if (!s2)
      96             :         {
      97           0 :           rc = gpg_error_from_syserror ();
      98           0 :           goto out;
      99             :         }
     100           0 :       trim_trailing_spaces (s2);
     101           0 :       s = s2;
     102             :     }
     103             : 
     104         622 :   switch (*s)
     105             :     {
     106             :     case 0:  /* Empty string is an error.  */
     107           0 :       rc = gpg_error (GPG_ERR_INV_USER_ID);
     108           0 :       goto out;
     109             : 
     110             :     case '.': /* An email address, compare from end.  Note that this
     111             :                  has not yet been implemented in the search code.  */
     112           0 :       mode = KEYDB_SEARCH_MODE_MAILEND;
     113           0 :       s++;
     114           0 :       desc->u.name = s;
     115           0 :       break;
     116             : 
     117             :     case '<': /* An email address.  */
     118           0 :       mode = KEYDB_SEARCH_MODE_MAIL;
     119             :       /* FIXME: The keyring code in g10 assumes that the mail name is
     120             :          prefixed with an '<'.  However the keybox code used for sm/
     121             :          assumes it has been removed.  For now we use this simple hack
     122             :          to overcome the problem.  */
     123           0 :       if (!openpgp_hack)
     124           0 :         s++;
     125           0 :       desc->u.name = s;
     126           0 :       break;
     127             : 
     128             :     case '@':  /* Part of an email address.  */
     129           0 :       mode = KEYDB_SEARCH_MODE_MAILSUB;
     130           0 :       s++;
     131           0 :       desc->u.name = s;
     132           0 :       break;
     133             : 
     134             :     case '=':  /* Exact compare.  */
     135           8 :       mode = KEYDB_SEARCH_MODE_EXACT;
     136           8 :       s++;
     137           8 :       desc->u.name = s;
     138           8 :       break;
     139             : 
     140             :     case '*':  /* Case insensitive substring search.  */
     141           0 :       mode = KEYDB_SEARCH_MODE_SUBSTR;
     142           0 :       s++;
     143           0 :       desc->u.name = s;
     144           0 :       break;
     145             : 
     146             :     case '+':  /* Compare individual words.  Note that this has not
     147             :                   yet been implemented in the search code.  */
     148           0 :       mode = KEYDB_SEARCH_MODE_WORDS;
     149           0 :       s++;
     150           0 :       desc->u.name = s;
     151           0 :       break;
     152             : 
     153             :     case '/': /* Subject's DN.  */
     154           0 :       s++;
     155           0 :       if (!*s || spacep (s)) /* No DN or prefixed with a space.  */
     156             :         {
     157           0 :           rc = gpg_error (GPG_ERR_INV_USER_ID);
     158           0 :           goto out;
     159             :         }
     160           0 :       desc->u.name = s;
     161           0 :       mode = KEYDB_SEARCH_MODE_SUBJECT;
     162           0 :       break;
     163             : 
     164             :     case '#': /* S/N with optional issuer id or just issuer id.  */
     165             :       {
     166             :         const char *si;
     167             : 
     168           0 :         s++;
     169           0 :         if ( *s == '/')
     170             :           { /* "#/" indicates an issuer's DN.  */
     171           0 :             s++;
     172           0 :             if (!*s || spacep (s)) /* No DN or prefixed with a space.  */
     173             :               {
     174           0 :                 rc = gpg_error (GPG_ERR_INV_USER_ID);
     175           0 :                 goto out;
     176             :               }
     177           0 :             desc->u.name = s;
     178           0 :             mode = KEYDB_SEARCH_MODE_ISSUER;
     179             :           }
     180             :         else
     181             :           { /* Serialnumber + optional issuer ID.  */
     182           0 :             for (si=s; *si && *si != '/'; si++)
     183             :               {
     184             :                  /* Check for an invalid digit in the serial number. */
     185           0 :                 if (!strchr("01234567890abcdefABCDEF", *si))
     186             :                   {
     187           0 :                     rc = gpg_error (GPG_ERR_INV_USER_ID);
     188           0 :                     goto out;
     189             :                   }
     190             :               }
     191           0 :             desc->sn = (const unsigned char*)s;
     192           0 :             desc->snlen = -1;
     193           0 :             if (!*si)
     194           0 :               mode = KEYDB_SEARCH_MODE_SN;
     195             :             else
     196             :               {
     197           0 :                 s = si+1;
     198           0 :                 if (!*s || spacep (s))  /* No DN or prefixed with a space.  */
     199             :                   {
     200           0 :                     rc = gpg_error (GPG_ERR_INV_USER_ID);
     201           0 :                     goto out;
     202             :                   }
     203           0 :                 desc->u.name = s;
     204           0 :                 mode = KEYDB_SEARCH_MODE_ISSUER_SN;
     205             :               }
     206             :           }
     207             :       }
     208           0 :       break;
     209             : 
     210             :     case ':': /* Unified fingerprint. */
     211             :       {
     212             :         const char *se, *si;
     213             :         int i;
     214             : 
     215           0 :         se = strchr (++s,':');
     216           0 :         if (!se)
     217             :           {
     218           0 :             rc = gpg_error (GPG_ERR_INV_USER_ID);
     219           0 :             goto out;
     220             :           }
     221           0 :         for (i=0,si=s; si < se; si++, i++ )
     222             :           {
     223           0 :             if (!strchr("01234567890abcdefABCDEF", *si))
     224             :               {
     225           0 :                 rc = gpg_error (GPG_ERR_INV_USER_ID); /* Invalid digit.  */
     226           0 :                 goto out;
     227             :               }
     228             :           }
     229           0 :         if (i != 32 && i != 40)
     230             :           {
     231           0 :             rc = gpg_error (GPG_ERR_INV_USER_ID); /* Invalid length of fpr.  */
     232           0 :             goto out;
     233             :           }
     234           0 :         for (i=0,si=s; si < se; i++, si +=2)
     235           0 :           desc->u.fpr[i] = hextobyte(si);
     236           0 :         for (; i < 20; i++)
     237           0 :           desc->u.fpr[i]= 0;
     238           0 :         mode = KEYDB_SEARCH_MODE_FPR;
     239             :       }
     240           0 :       break;
     241             : 
     242             :     case '&': /* Keygrip*/
     243             :       {
     244           0 :         if (hex2bin (s+1, desc->u.grip, 20) < 0)
     245             :           {
     246           0 :             rc = gpg_error (GPG_ERR_INV_USER_ID); /* Invalid. */
     247           0 :             goto out;
     248             :           }
     249           0 :         mode = KEYDB_SEARCH_MODE_KEYGRIP;
     250             :       }
     251           0 :       break;
     252             : 
     253             :     default:
     254         614 :       if (s[0] == '0' && s[1] == 'x')
     255             :         {
     256          95 :           hexprefix = 1;
     257          95 :           s += 2;
     258             :         }
     259             : 
     260         614 :       hexlength = strspn(s, "0123456789abcdefABCDEF");
     261         614 :       if (hexlength >= 8 && s[hexlength] =='!')
     262             :         {
     263           3 :           desc->exact = 1;
     264           3 :           hexlength++; /* Just for the following check.  */
     265             :         }
     266             : 
     267             :       /* Check if a hexadecimal number is terminated by EOS or blank.  */
     268         614 :       if (hexlength && s[hexlength] && !spacep (s+hexlength))
     269             :         {
     270          32 :           if (hexprefix) /* A "0x" prefix without a correct
     271             :                             termination is an error.  */
     272             :             {
     273           0 :               rc = gpg_error (GPG_ERR_INV_USER_ID);
     274           0 :               goto out;
     275             :             }
     276             :           /* The first characters looked like a hex number, but the
     277             :              entire string is not.  */
     278          32 :           hexlength = 0;
     279             :         }
     280             : 
     281         614 :       if (desc->exact)
     282           3 :         hexlength--; /* Remove the bang.  */
     283             : 
     284         614 :       if ((hexlength == 8
     285         243 :            && (s[hexlength] == 0
     286           3 :                || (s[hexlength] == '!' && s[hexlength + 1] == 0)))
     287         371 :           || (!hexprefix && hexlength == 9 && *s == '0'))
     288             :         {
     289             :           /* Short keyid.  */
     290         243 :           if (hexlength == 9)
     291           0 :             s++;
     292         243 :           desc->u.kid[1] = strtoul( s, NULL, 16 );
     293         243 :           mode = KEYDB_SEARCH_MODE_SHORT_KID;
     294             :         }
     295         371 :       else if ((hexlength == 16
     296           0 :                 && (s[hexlength] == 0
     297           0 :                     || (s[hexlength] == '!' && s[hexlength + 1] == 0)))
     298         371 :                || (!hexprefix && hexlength == 17 && *s == '0'))
     299           0 :         {
     300             :           /* Long keyid.  */
     301             :           char buf[9];
     302           0 :           if (hexlength == 17)
     303           0 :             s++;
     304           0 :           mem2str (buf, s, 9);
     305           0 :           desc->u.kid[0] = strtoul (buf, NULL, 16);
     306           0 :           desc->u.kid[1] = strtoul (s+8, NULL, 16);
     307           0 :           mode = KEYDB_SEARCH_MODE_LONG_KID;
     308             :         }
     309         371 :       else if ((hexlength == 32
     310           0 :                 && (s[hexlength] == 0
     311           0 :                     || (s[hexlength] == '!' && s[hexlength + 1] == 0)))
     312         371 :                || (!hexprefix && hexlength == 33 && *s == '0'))
     313           0 :         {
     314             :           /* MD5 fingerprint.  */
     315             :           int i;
     316           0 :           if (hexlength == 33)
     317           0 :             s++;
     318           0 :           memset (desc->u.fpr+16, 0, 4);
     319           0 :           for (i=0; i < 16; i++, s+=2)
     320             :             {
     321           0 :               int c = hextobyte(s);
     322           0 :               if (c == -1)
     323             :                 {
     324           0 :                   rc = gpg_error (GPG_ERR_INV_USER_ID);
     325           0 :                   goto out;
     326             :                 }
     327           0 :               desc->u.fpr[i] = c;
     328             :             }
     329           0 :           mode = KEYDB_SEARCH_MODE_FPR16;
     330             :         }
     331         371 :       else if ((hexlength == 40
     332         191 :                 && (s[hexlength] == 0
     333           0 :                     || (s[hexlength] == '!' && s[hexlength + 1] == 0)))
     334         180 :                || (!hexprefix && hexlength == 41 && *s == '0'))
     335         191 :         {
     336             :           /* SHA1/RMD160 fingerprint.  */
     337             :           int i;
     338         191 :           if (hexlength == 41)
     339           0 :             s++;
     340        4011 :           for (i=0; i < 20; i++, s+=2)
     341             :             {
     342        3820 :               int c = hextobyte(s);
     343        3820 :               if (c == -1)
     344             :                 {
     345           0 :                   rc = gpg_error (GPG_ERR_INV_USER_ID);
     346           0 :                   goto out;
     347             :                 }
     348        3820 :               desc->u.fpr[i] = c;
     349             :             }
     350         191 :           mode = KEYDB_SEARCH_MODE_FPR20;
     351             :         }
     352         180 :       else if (!hexprefix)
     353             :         {
     354             :           /* The fingerprint in an X.509 listing is often delimited by
     355             :              colons, so we try to single this case out. */
     356         180 :           mode = 0;
     357         180 :           hexlength = strspn (s, ":0123456789abcdefABCDEF");
     358         180 :           if (hexlength == 59 && (!s[hexlength] || spacep (s+hexlength)))
     359             :             {
     360             :               int i;
     361             : 
     362           0 :               for (i=0; i < 20; i++, s += 3)
     363             :                 {
     364           0 :                   int c = hextobyte(s);
     365           0 :                   if (c == -1 || (i < 19 && s[2] != ':'))
     366             :                     break;
     367           0 :                   desc->u.fpr[i] = c;
     368             :                 }
     369           0 :               if (i == 20)
     370           0 :                 mode = KEYDB_SEARCH_MODE_FPR20;
     371             :             }
     372         180 :           if (!mode)
     373             :             {
     374             :               /* Still not found.  Now check for a space separated
     375             :                  OpenPGP v4 fingerprint like:
     376             :                    8061 5870 F5BA D690 3336  86D0 F2AD 85AC 1E42 B367
     377             :                  or
     378             :                    8061 5870 F5BA D690 3336 86D0 F2AD 85AC 1E42 B367
     379             :                */
     380         180 :               hexlength = strspn (s, " 0123456789abcdefABCDEF");
     381         180 :               if (s[hexlength] && s[hexlength] != ' ')
     382         177 :                 hexlength = 0; /* Followed by non-space.  */
     383         360 :               while (hexlength && s[hexlength-1] == ' ')
     384           0 :                 hexlength--;   /* Trim trailing spaces.  */
     385         180 :               if ((hexlength == 49 || hexlength == 50)
     386           3 :                   && (!s[hexlength] || s[hexlength] == ' '))
     387             :                 {
     388             :                   int i, c;
     389             : 
     390          63 :                   for (i=0; i < 20; i++)
     391             :                     {
     392          60 :                       if (i && !(i % 2))
     393             :                         {
     394          27 :                           if (*s != ' ')
     395           0 :                             break;
     396          27 :                           s++;
     397             :                           /* Skip the double space in the middle but
     398             :                              don't require it to help copying
     399             :                              fingerprints from sources which fold
     400             :                              multiple space to one.  */
     401          27 :                           if (i == 10 && *s == ' ')
     402           3 :                             s++;
     403             :                         }
     404             : 
     405          60 :                       c = hextobyte(s);
     406          60 :                       if (c == -1)
     407           0 :                         break;
     408          60 :                       desc->u.fpr[i] = c;
     409          60 :                       s += 2;
     410             :                     }
     411           3 :                   if (i == 20)
     412           3 :                     mode = KEYDB_SEARCH_MODE_FPR20;
     413             :                 }
     414             :             }
     415         180 :           if (!mode) /* Default to substring search.  */
     416             :             {
     417         177 :               desc->exact = 0;
     418         177 :               desc->u.name = s;
     419         177 :               mode = KEYDB_SEARCH_MODE_SUBSTR;
     420             :             }
     421             :         }
     422             :       else
     423             :         {
     424             :           /* Hex number with a prefix but with a wrong length.  */
     425           0 :           rc = gpg_error (GPG_ERR_INV_USER_ID);
     426           0 :           goto out;
     427             :         }
     428             :     }
     429             : 
     430         622 :   desc->mode = mode;
     431             :  out:
     432         622 :   xfree (s2);
     433         622 :   return rc;
     434             : }

Generated by: LCOV version 1.11