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