New functions to compute an ssh style fingerprint.
[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  *
5  * This file is part of GnuPG.
6  *
7  * GnuPG is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * GnuPG is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 /* This file implements a few utility functions useful when working
22    with canonical encrypted S-expresions (i.e. not the S-exprssion
23    objects from libgcrypt).  */
24
25 #include <config.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include "util.h"
31 #include "userids.h"
32
33
34 /* Parse the user-id NAME and build a search description for it.
35  * Returns 0 on succdess or an error code.  DESC may be NULL to merely
36  * check the validity of a user-id.
37  *
38  * Some used rules:
39  * - If the username starts with 8,9,16 or 17 hex-digits (the first one
40  *   must be in the range 0..9), this is considered a keyid; depending
41  *   on the length a short or complete one.
42  * - If the username starts with 32,33,40 or 41 hex-digits (the first one
43  *   must be in the range 0..9), this is considered a fingerprint.
44  * - If the username starts with a left angle, we assume it is a complete
45  *   email address and look only at this part.
46  * - If the username starts with a colon we assume it is a unified
47  *   key specfification.
48  * - If the username starts with a '.', we assume it is the ending
49  *   part of an email address
50  * - If the username starts with an '@', we assume it is a part of an
51  *   email address
52  * - If the userid start with an '=' an exact compare is done.
53  * - If the userid starts with a '*' a case insensitive substring search is
54  *   done (This is the default).
55  * - If the userid starts with a '+' we will compare individual words
56  *   and a match requires that all the words are in the userid.
57  *   Words are delimited by white space or "()<>[]{}.@-+_,;/&!"
58  *   (note that you can't search for these characters). Compare
59  *   is not case sensitive.
60  * - If the userid starts with a '&' a 40 hex digits keygrip is expected.
61  */
62
63 gpg_error_t
64 classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack)
65 {
66   const char *s;
67   int hexprefix = 0;
68   int hexlength;
69   int mode = 0;
70   KEYDB_SEARCH_DESC dummy_desc;
71
72   if (!desc)
73     desc = &dummy_desc;
74
75   /* Clear the structure so that the mode field is set to zero unless
76      we set it to the correct value right at the end of this
77      function. */
78   memset (desc, 0, sizeof *desc);
79
80   /* Skip leading spaces.  */
81   for(s = name; *s && spacep (s); s++ )
82     ;
83
84   switch (*s)
85     {
86     case 0:  /* Empty string is an error.  */
87       return gpg_error (GPG_ERR_INV_USER_ID);
88
89     case '.': /* An email address, compare from end.  Note that this
90                  has not yet been implemented in the search code.  */
91       mode = KEYDB_SEARCH_MODE_MAILEND;
92       s++;
93       desc->u.name = s;
94       break;
95
96     case '<': /* An email address.  */
97       mode = KEYDB_SEARCH_MODE_MAIL;
98       /* FIXME: The keyring code in g10 assumes that the mail name is
99          prefixed with an '<'.  However the keybox code used for sm/
100          assumes it has been removed.  For now we use this simple hack
101          to overcome the problem.  */
102       if (!openpgp_hack)
103         s++;
104       desc->u.name = s;
105       break;
106
107     case '@':  /* Part of an email address.  */
108       mode = KEYDB_SEARCH_MODE_MAILSUB;
109       s++;
110       desc->u.name = s;
111       break;
112
113     case '=':  /* Exact compare.  */
114       mode = KEYDB_SEARCH_MODE_EXACT;
115       s++;
116       desc->u.name = s;
117       break;
118
119     case '*':  /* Case insensitive substring search.  */
120       mode = KEYDB_SEARCH_MODE_SUBSTR;
121       s++;
122       desc->u.name = s;
123       break;
124
125     case '+':  /* Compare individual words.  Note that this has not
126                   yet been implemented in the search code.  */
127       mode = KEYDB_SEARCH_MODE_WORDS;
128       s++;
129       desc->u.name = s;
130       break;
131
132     case '/': /* Subject's DN.  */
133       s++;
134       if (!*s || spacep (s)) /* No DN or prefixed with a space.  */
135         return gpg_error (GPG_ERR_INV_USER_ID);
136       desc->u.name = s;
137       mode = KEYDB_SEARCH_MODE_SUBJECT;
138       break;
139
140     case '#': /* S/N with optional issuer id or just issuer id.  */
141       {
142         const char *si;
143
144         s++;
145         if ( *s == '/')
146           { /* "#/" indicates an issuer's DN.  */
147             s++;
148             if (!*s || spacep (s)) /* No DN or prefixed with a space.  */
149               return gpg_error (GPG_ERR_INV_USER_ID);
150             desc->u.name = s;
151             mode = KEYDB_SEARCH_MODE_ISSUER;
152           }
153         else
154           { /* Serialnumber + optional issuer ID.  */
155             for (si=s; *si && *si != '/'; si++)
156               {
157                  /* Check for an invalid digit in the serial number. */
158                 if (!strchr("01234567890abcdefABCDEF", *si))
159                   return gpg_error (GPG_ERR_INV_USER_ID);
160               }
161             desc->sn = (const unsigned char*)s;
162             desc->snlen = -1;
163             if (!*si)
164               mode = KEYDB_SEARCH_MODE_SN;
165             else
166               {
167                 s = si+1;
168                 if (!*s || spacep (s))  /* No DN or prefixed with a space.  */
169                   return gpg_error (GPG_ERR_INV_USER_ID);
170                 desc->u.name = s;
171                 mode = KEYDB_SEARCH_MODE_ISSUER_SN;
172               }
173           }
174       }
175       break;
176
177     case ':': /* Unified fingerprint. */
178       {
179         const char *se, *si;
180         int i;
181
182         se = strchr (++s,':');
183         if (!se)
184           return gpg_error (GPG_ERR_INV_USER_ID);
185         for (i=0,si=s; si < se; si++, i++ )
186           {
187             if (!strchr("01234567890abcdefABCDEF", *si))
188               return gpg_error (GPG_ERR_INV_USER_ID); /* Invalid digit.  */
189           }
190         if (i != 32 && i != 40)
191           return gpg_error (GPG_ERR_INV_USER_ID); /* Invalid length of fpr.  */
192         for (i=0,si=s; si < se; i++, si +=2)
193           desc->u.fpr[i] = hextobyte(si);
194         for (; i < 20; i++)
195           desc->u.fpr[i]= 0;
196         s = se + 1;
197         mode = KEYDB_SEARCH_MODE_FPR;
198       }
199       break;
200
201     case '&': /* Keygrip*/
202       {
203         if (hex2bin (s+1, desc->u.grip, 20) < 0)
204           return gpg_error (GPG_ERR_INV_USER_ID); /* Invalid. */
205         mode = KEYDB_SEARCH_MODE_KEYGRIP;
206       }
207       break;
208
209     default:
210       if (s[0] == '0' && s[1] == 'x')
211         {
212           hexprefix = 1;
213           s += 2;
214         }
215
216       hexlength = strspn(s, "0123456789abcdefABCDEF");
217       if (hexlength >= 8 && s[hexlength] =='!')
218         {
219           desc->exact = 1;
220           hexlength++; /* Just for the following check.  */
221         }
222
223       /* Check if a hexadecimal number is terminated by EOS or blank.  */
224       if (hexlength && s[hexlength] && !spacep (s+hexlength))
225         {
226           if (hexprefix) /* A "0x" prefix without a correct
227                             termination is an error.  */
228             return gpg_error (GPG_ERR_INV_USER_ID);
229           /* The first characters looked like a hex number, but the
230              entire string is not.  */
231           hexlength = 0;
232         }
233
234       if (desc->exact)
235         hexlength--; /* Remove the bang.  */
236
237       if (hexlength == 8
238           || (!hexprefix && hexlength == 9 && *s == '0'))
239         {
240           /* Short keyid.  */
241           if (hexlength == 9)
242             s++;
243           desc->u.kid[1] = strtoul( s, NULL, 16 );
244           mode = KEYDB_SEARCH_MODE_SHORT_KID;
245         }
246       else if (hexlength == 16
247                || (!hexprefix && hexlength == 17 && *s == '0'))
248         {
249           /* Long keyid.  */
250           char buf[9];
251           if (hexlength == 17)
252             s++;
253           mem2str (buf, s, 9);
254           desc->u.kid[0] = strtoul (buf, NULL, 16);
255           desc->u.kid[1] = strtoul (s+8, NULL, 16);
256           mode = KEYDB_SEARCH_MODE_LONG_KID;
257         }
258       else if (hexlength == 32
259                || (!hexprefix && hexlength == 33 && *s == '0'))
260         {
261           /* MD5 fingerprint.  */
262           int i;
263           if (hexlength == 33)
264             s++;
265           memset (desc->u.fpr+16, 0, 4);
266           for (i=0; i < 16; i++, s+=2)
267             {
268               int c = hextobyte(s);
269               if (c == -1)
270                 return gpg_error (GPG_ERR_INV_USER_ID);
271               desc->u.fpr[i] = c;
272             }
273           mode = KEYDB_SEARCH_MODE_FPR16;
274         }
275       else if (hexlength == 40
276                || (!hexprefix && hexlength == 41 && *s == '0'))
277         {
278           /* SHA1/RMD160 fingerprint.  */
279           int i;
280           if (hexlength == 41)
281             s++;
282           for (i=0; i < 20; i++, s+=2)
283             {
284               int c = hextobyte(s);
285               if (c == -1)
286                 return gpg_error (GPG_ERR_INV_USER_ID);
287               desc->u.fpr[i] = c;
288             }
289           mode = KEYDB_SEARCH_MODE_FPR20;
290         }
291       else if (!hexprefix)
292         {
293           /* The fingerprint in an X.509 listing is often delimited by
294              colons, so we try to single this case out. */
295           mode = 0;
296           hexlength = strspn (s, ":0123456789abcdefABCDEF");
297           if (hexlength == 59 && (!s[hexlength] || spacep (s+hexlength)))
298             {
299               int i;
300
301               for (i=0; i < 20; i++, s += 3)
302                 {
303                   int c = hextobyte(s);
304                   if (c == -1 || (i < 19 && s[2] != ':'))
305                     break;
306                   desc->u.fpr[i] = c;
307                 }
308               if (i == 20)
309                 mode = KEYDB_SEARCH_MODE_FPR20;
310             }
311           if (!mode) /* Default to substring search.  */
312             {
313               desc->exact = 0;
314               desc->u.name = s;
315               mode = KEYDB_SEARCH_MODE_SUBSTR;
316             }
317         }
318       else
319         {
320           /* Hex number with a prefix but with a wrong length.  */
321           return gpg_error (GPG_ERR_INV_USER_ID);
322         }
323     }
324
325   desc->mode = mode;
326   return 0;
327 }