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  * - If the userid starts with a '^' followed by 40 hex digits it describes
69  *   a Unique-Blob-ID (UBID) which is the hash of keyblob or certificate as
70  *   stored in the database.  This is used in the IPC of the keyboxd.
71  */
72 
73 gpg_error_t
classify_user_id(const char * name,KEYDB_SEARCH_DESC * desc,int openpgp_hack)74 classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack)
75 {
76   const char *s;
77   char *s2 = NULL;
78   int rc = 0;
79   int hexprefix = 0;
80   int hexlength;
81   int mode = 0;
82   KEYDB_SEARCH_DESC dummy_desc;
83 
84   if (!desc)
85     desc = &dummy_desc;
86 
87   /* Clear the structure so that the mode field is set to zero unless
88      we set it to the correct value right at the end of this
89      function. */
90   memset (desc, 0, sizeof *desc);
91 
92   /* Skip leading and trailing spaces.  */
93   for(s = name; *s && spacep (s); s++ )
94     ;
95   if (*s && spacep (s + strlen(s) - 1))
96     {
97       s2 = xtrystrdup (s);
98       if (!s2)
99         {
100           rc = gpg_error_from_syserror ();
101           goto out;
102         }
103       trim_trailing_spaces (s2);
104       s = s2;
105     }
106 
107   switch (*s)
108     {
109     case 0:  /* Empty string is an error.  */
110       rc = gpg_error (GPG_ERR_INV_USER_ID);
111       goto out;
112 
113     case '.': /* An email address, compare from end.  Note that this
114                  has not yet been implemented in the search code.  */
115       mode = KEYDB_SEARCH_MODE_MAILEND;
116       s++;
117       desc->u.name = s;
118       desc->name_used = 1;
119       break;
120 
121     case '<': /* An email address.  */
122       mode = KEYDB_SEARCH_MODE_MAIL;
123       /* FIXME: The keyring code in g10 assumes that the mail name is
124          prefixed with an '<'.  However the keybox code used for sm/
125          assumes it has been removed.  For now we use this simple hack
126          to overcome the problem.  */
127       if (!openpgp_hack)
128         s++;
129       desc->u.name = s;
130       desc->name_used = 1;
131       break;
132 
133     case '@':  /* Part of an email address.  */
134       mode = KEYDB_SEARCH_MODE_MAILSUB;
135       s++;
136       desc->u.name = s;
137       desc->name_used = 1;
138       break;
139 
140     case '=':  /* Exact compare.  */
141       mode = KEYDB_SEARCH_MODE_EXACT;
142       s++;
143       desc->u.name = s;
144       desc->name_used = 1;
145       break;
146 
147     case '*':  /* Case insensitive substring search.  */
148       mode = KEYDB_SEARCH_MODE_SUBSTR;
149       s++;
150       desc->u.name = s;
151       desc->name_used = 1;
152       break;
153 
154     case '+':  /* Compare individual words.  Note that this has not
155                   yet been implemented in the search code.  */
156       mode = KEYDB_SEARCH_MODE_WORDS;
157       s++;
158       desc->u.name = s;
159       desc->name_used = 1;
160       break;
161 
162     case '/': /* Subject's DN.  */
163       s++;
164       if (!*s || spacep (s)) /* No DN or prefixed with a space.  */
165         {
166           rc = gpg_error (GPG_ERR_INV_USER_ID);
167           goto out;
168         }
169       desc->u.name = s;
170       desc->name_used = 1;
171       mode = KEYDB_SEARCH_MODE_SUBJECT;
172       break;
173 
174     case '#': /* S/N with optional issuer id or just issuer id.  */
175       {
176         const char *si;
177 
178         s++;
179         if ( *s == '/')
180           { /* "#/" indicates an issuer's DN.  */
181             s++;
182             if (!*s || spacep (s)) /* No DN or prefixed with a space.  */
183               {
184                 rc = gpg_error (GPG_ERR_INV_USER_ID);
185                 goto out;
186               }
187             desc->u.name = s;
188             desc->name_used = 1;
189             mode = KEYDB_SEARCH_MODE_ISSUER;
190           }
191         else
192           { /* Serialnumber + optional issuer ID.  */
193             for (si=s; *si && *si != '/'; si++)
194               {
195                  /* Check for an invalid digit in the serial number. */
196                 if (!strchr("01234567890abcdefABCDEF", *si))
197                   {
198                     rc = gpg_error (GPG_ERR_INV_USER_ID);
199                     goto out;
200                   }
201               }
202             desc->sn = (const unsigned char*)s;
203             desc->snlen = si - s;
204             desc->snhex = 1;
205             if (!*si)
206               mode = KEYDB_SEARCH_MODE_SN;
207             else
208               {
209                 s = si+1;
210                 if (!*s || spacep (s))  /* No DN or prefixed with a space.  */
211                   {
212                     rc = gpg_error (GPG_ERR_INV_USER_ID);
213                     goto out;
214                   }
215                 desc->u.name = s;
216                 desc->name_used = 1;
217                 mode = KEYDB_SEARCH_MODE_ISSUER_SN;
218               }
219           }
220       }
221       break;
222 
223     case ':': /* Unified fingerprint. */
224       {
225         const char *se, *si;
226         int i;
227 
228         se = strchr (++s,':');
229         if (!se)
230           {
231             rc = gpg_error (GPG_ERR_INV_USER_ID);
232             goto out;
233           }
234         for (i=0,si=s; si < se; si++, i++ )
235           {
236             if (!strchr("01234567890abcdefABCDEF", *si))
237               {
238                 rc = gpg_error (GPG_ERR_INV_USER_ID); /* Invalid digit.  */
239                 goto out;
240               }
241           }
242         if (i != 32 && i != 40 && i != 64)
243           {
244             rc = gpg_error (GPG_ERR_INV_USER_ID); /* Invalid length of fpr.  */
245             goto out;
246           }
247         for (i=0,si=s; si < se; i++, si +=2)
248           desc->u.fpr[i] = hextobyte(si);
249         desc->fprlen = i;
250         for (; i < 32; i++)
251           desc->u.fpr[i]= 0;
252         mode = KEYDB_SEARCH_MODE_FPR;
253       }
254       break;
255 
256     case '&': /* Keygrip*/
257       {
258         if (hex2bin (s+1, desc->u.grip, 20) < 0)
259           {
260             rc = gpg_error (GPG_ERR_INV_USER_ID); /* Invalid. */
261             goto out;
262           }
263         mode = KEYDB_SEARCH_MODE_KEYGRIP;
264       }
265       break;
266 
267     case '^': /* UBID */
268       {
269         if (hex2bin (s+1, desc->u.ubid, UBID_LEN) < 0)
270           {
271             rc = gpg_error (GPG_ERR_INV_USER_ID); /* Invalid. */
272             goto out;
273           }
274         mode = KEYDB_SEARCH_MODE_UBID;
275       }
276       break;
277 
278     default:
279       if (s[0] == '0' && s[1] == 'x')
280         {
281           hexprefix = 1;
282           s += 2;
283         }
284 
285       hexlength = strspn(s, "0123456789abcdefABCDEF");
286       if (hexlength >= 8 && s[hexlength] =='!')
287         {
288           desc->exact = 1;
289           hexlength++; /* Just for the following check.  */
290         }
291 
292       /* Check if a hexadecimal number is terminated by EOS or blank.  */
293       if (hexlength && s[hexlength] && !spacep (s+hexlength))
294         {
295           if (hexprefix) /* A "0x" prefix without a correct
296                             termination is an error.  */
297             {
298               rc = gpg_error (GPG_ERR_INV_USER_ID);
299               goto out;
300             }
301           /* The first characters looked like a hex number, but the
302              entire string is not.  */
303           hexlength = 0;
304         }
305 
306       if (desc->exact)
307         hexlength--; /* Remove the bang.  */
308 
309       if ((hexlength == 8
310            && (s[hexlength] == 0
311                || (s[hexlength] == '!' && s[hexlength + 1] == 0)))
312           || (!hexprefix && hexlength == 9 && *s == '0'))
313         {
314           /* Short keyid.  */
315           if (hexlength == 9)
316             s++;
317           desc->u.kid[1] = strtoul( s, NULL, 16 );
318           mode = KEYDB_SEARCH_MODE_SHORT_KID;
319         }
320       else if ((hexlength == 16
321                 && (s[hexlength] == 0
322                     || (s[hexlength] == '!' && s[hexlength + 1] == 0)))
323                || (!hexprefix && hexlength == 17 && *s == '0'))
324         {
325           /* Long keyid.  */
326           char buf[9];
327           if (hexlength == 17)
328             s++;
329           mem2str (buf, s, 9);
330           desc->u.kid[0] = strtoul (buf, NULL, 16);
331           desc->u.kid[1] = strtoul (s+8, NULL, 16);
332           mode = KEYDB_SEARCH_MODE_LONG_KID;
333         }
334       else if ((hexlength == 32
335                 && (s[hexlength] == 0
336                     || (s[hexlength] == '!' && s[hexlength + 1] == 0)))
337                || (!hexprefix && hexlength == 33 && *s == '0'))
338         {
339           /* MD5 fingerprint.  */
340           int i;
341           if (hexlength == 33)
342             s++;
343           memset (desc->u.fpr+16, 0, 4);
344           for (i=0; i < 16; i++, s+=2)
345             {
346               int c = hextobyte(s);
347               if (c == -1)
348                 {
349                   rc = gpg_error (GPG_ERR_INV_USER_ID);
350                   goto out;
351                 }
352               desc->u.fpr[i] = c;
353             }
354           desc->fprlen = 16;
355           for (; i < 32; i++)
356             desc->u.fpr[i]= 0;
357           mode = KEYDB_SEARCH_MODE_FPR;
358         }
359       else if ((hexlength == 40
360                 && (s[hexlength] == 0
361                     || (s[hexlength] == '!' && s[hexlength + 1] == 0)))
362                || (!hexprefix && hexlength == 41 && *s == '0'))
363         {
364           /* SHA1 fingerprint.  */
365           int i;
366           if (hexlength == 41)
367             s++;
368           for (i=0; i < 20; i++, s+=2)
369             {
370               int c = hextobyte(s);
371               if (c == -1)
372                 {
373                   rc = gpg_error (GPG_ERR_INV_USER_ID);
374                   goto out;
375                 }
376               desc->u.fpr[i] = c;
377             }
378           desc->fprlen = 20;
379           for (; i < 32; i++)
380             desc->u.fpr[i]= 0;
381           mode = KEYDB_SEARCH_MODE_FPR;
382         }
383       else if ((hexlength == 64
384                 && (s[hexlength] == 0
385                     || (s[hexlength] == '!' && s[hexlength + 1] == 0)))
386                || (!hexprefix && hexlength == 65 && *s == '0'))
387         {
388           /* SHA256 fingerprint.  */
389           int i;
390           if (hexlength == 65)
391             s++;
392           for (i=0; i < 32; i++, s+=2)
393             {
394               int c = hextobyte(s);
395               if (c == -1)
396                 {
397                   rc = gpg_error (GPG_ERR_INV_USER_ID);
398                   goto out;
399                 }
400               desc->u.fpr[i] = c;
401             }
402           desc->fprlen = 32;
403           mode = KEYDB_SEARCH_MODE_FPR;
404         }
405       else if (!hexprefix)
406         {
407           /* The fingerprint of an X.509 listing is often delimited by
408            * colons, so we try to single this case out.  Note that the
409            * OpenPGP bang suffix is not supported here.  */
410           desc->exact = 0;
411           mode = 0;
412           hexlength = strspn (s, ":0123456789abcdefABCDEF");
413           if (hexlength == 59 && (!s[hexlength] || spacep (s+hexlength)))
414             {
415               int i;
416 
417               for (i=0; i < 20; i++, s += 3)
418                 {
419                   int c = hextobyte(s);
420                   if (c == -1 || (i < 19 && s[2] != ':'))
421                     break;
422                   desc->u.fpr[i] = c;
423                 }
424               if (i == 20)
425                 {
426                   desc->fprlen = 20;
427                   mode = KEYDB_SEARCH_MODE_FPR;
428                 }
429               for (; i < 32; i++)
430                 desc->u.fpr[i]= 0;
431             }
432           if (!mode)
433             {
434               /* Still not found.  Now check for a space separated
435                * OpenPGP v4 fingerprint like:
436                *   8061 5870 F5BA D690 3336  86D0 F2AD 85AC 1E42 B367
437                * or
438                *   8061 5870 F5BA D690 3336 86D0 F2AD 85AC 1E42 B367
439                * FIXME: Support OpenPGP v5 fingerprint
440                */
441               hexlength = strspn (s, " 0123456789abcdefABCDEF");
442               if (s[hexlength] && s[hexlength] != ' ')
443                 hexlength = 0; /* Followed by non-space.  */
444               while (hexlength && s[hexlength-1] == ' ')
445                 hexlength--;   /* Trim trailing spaces.  */
446               if ((hexlength == 49 || hexlength == 50)
447                   && (!s[hexlength] || s[hexlength] == ' '))
448                 {
449                   int i, c;
450 
451                   for (i=0; i < 20; i++)
452                     {
453                       if (i && !(i % 2))
454                         {
455                           if (*s != ' ')
456                             break;
457                           s++;
458                           /* Skip the double space in the middle but
459                              don't require it to help copying
460                              fingerprints from sources which fold
461                              multiple space to one.  */
462                           if (i == 10 && *s == ' ')
463                             s++;
464                         }
465 
466                       c = hextobyte(s);
467                       if (c == -1)
468                         break;
469                       desc->u.fpr[i] = c;
470                       s += 2;
471                     }
472                   if (i == 20)
473                     {
474                       desc->fprlen = 20;
475                       mode = KEYDB_SEARCH_MODE_FPR;
476                     }
477                   for (; i < 32; i++)
478                     desc->u.fpr[i]= 0;
479                 }
480             }
481           if (!mode) /* Default to substring search.  */
482             {
483               desc->u.name = s;
484               desc->name_used = 1;
485               mode = KEYDB_SEARCH_MODE_SUBSTR;
486             }
487         }
488       else
489 	{
490           /* Hex number with a prefix but with a wrong length.  */
491           rc = gpg_error (GPG_ERR_INV_USER_ID);
492           goto out;
493         }
494     }
495 
496   desc->mode = mode;
497  out:
498   xfree (s2);
499   return rc;
500 }
501