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
6 * This file is part of GnuPG.
8 * This file is free software; you can redistribute it and/or modify
9 * it under the terms of either
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.
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.
21 * or both in parallel, as here.
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.
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/>.
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.
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
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
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.
71 classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int openpgp_hack)
79 KEYDB_SEARCH_DESC dummy_desc;
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
87 memset (desc, 0, sizeof *desc);
89 /* Skip leading and trailing spaces. */
90 for(s = name; *s && spacep (s); s++ )
92 if (s[strlen(s) - 1] == ' ')
95 while (s2[strlen(s2) - 1] == ' ')
96 s2[strlen(s2) - 1] = 0;
102 case 0: /* Empty string is an error. */
103 rc = gpg_error (GPG_ERR_INV_USER_ID);
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;
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. */
124 case '@': /* Part of an email address. */
125 mode = KEYDB_SEARCH_MODE_MAILSUB;
130 case '=': /* Exact compare. */
131 mode = KEYDB_SEARCH_MODE_EXACT;
136 case '*': /* Case insensitive substring search. */
137 mode = KEYDB_SEARCH_MODE_SUBSTR;
142 case '+': /* Compare individual words. Note that this has not
143 yet been implemented in the search code. */
144 mode = KEYDB_SEARCH_MODE_WORDS;
149 case '/': /* Subject's DN. */
151 if (!*s || spacep (s)) /* No DN or prefixed with a space. */
153 rc = gpg_error (GPG_ERR_INV_USER_ID);
157 mode = KEYDB_SEARCH_MODE_SUBJECT;
160 case '#': /* S/N with optional issuer id or just issuer id. */
166 { /* "#/" indicates an issuer's DN. */
168 if (!*s || spacep (s)) /* No DN or prefixed with a space. */
170 rc = gpg_error (GPG_ERR_INV_USER_ID);
174 mode = KEYDB_SEARCH_MODE_ISSUER;
177 { /* Serialnumber + optional issuer ID. */
178 for (si=s; *si && *si != '/'; si++)
180 /* Check for an invalid digit in the serial number. */
181 if (!strchr("01234567890abcdefABCDEF", *si))
183 rc = gpg_error (GPG_ERR_INV_USER_ID);
187 desc->sn = (const unsigned char*)s;
190 mode = KEYDB_SEARCH_MODE_SN;
194 if (!*s || spacep (s)) /* No DN or prefixed with a space. */
196 rc = gpg_error (GPG_ERR_INV_USER_ID);
200 mode = KEYDB_SEARCH_MODE_ISSUER_SN;
206 case ':': /* Unified fingerprint. */
211 se = strchr (++s,':');
214 rc = gpg_error (GPG_ERR_INV_USER_ID);
217 for (i=0,si=s; si < se; si++, i++ )
219 if (!strchr("01234567890abcdefABCDEF", *si))
221 rc = gpg_error (GPG_ERR_INV_USER_ID); /* Invalid digit. */
225 if (i != 32 && i != 40)
227 rc = gpg_error (GPG_ERR_INV_USER_ID); /* Invalid length of fpr. */
230 for (i=0,si=s; si < se; i++, si +=2)
231 desc->u.fpr[i] = hextobyte(si);
235 mode = KEYDB_SEARCH_MODE_FPR;
239 case '&': /* Keygrip*/
241 if (hex2bin (s+1, desc->u.grip, 20) < 0)
243 rc = gpg_error (GPG_ERR_INV_USER_ID); /* Invalid. */
246 mode = KEYDB_SEARCH_MODE_KEYGRIP;
251 if (s[0] == '0' && s[1] == 'x')
257 hexlength = strspn(s, "0123456789abcdefABCDEF");
258 if (hexlength >= 8 && s[hexlength] =='!')
261 hexlength++; /* Just for the following check. */
264 /* Check if a hexadecimal number is terminated by EOS or blank. */
265 if (hexlength && s[hexlength] && !spacep (s+hexlength))
267 if (hexprefix) /* A "0x" prefix without a correct
268 termination is an error. */
270 rc = gpg_error (GPG_ERR_INV_USER_ID);
273 /* The first characters looked like a hex number, but the
274 entire string is not. */
279 hexlength--; /* Remove the bang. */
281 if ((hexlength == 8 && s[hexlength] == 0)
282 || (!hexprefix && hexlength == 9 && *s == '0'))
287 desc->u.kid[1] = strtoul( s, NULL, 16 );
288 mode = KEYDB_SEARCH_MODE_SHORT_KID;
290 else if ((hexlength == 16 && s[hexlength] == 0)
291 || (!hexprefix && hexlength == 17 && *s == '0'))
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;
302 else if ((hexlength == 32 && s[hexlength] == 0)
303 || (!hexprefix && hexlength == 33 && *s == '0'))
305 /* MD5 fingerprint. */
309 memset (desc->u.fpr+16, 0, 4);
310 for (i=0; i < 16; i++, s+=2)
312 int c = hextobyte(s);
315 rc = gpg_error (GPG_ERR_INV_USER_ID);
320 mode = KEYDB_SEARCH_MODE_FPR16;
322 else if ((hexlength == 40 && s[hexlength] == 0)
323 || (!hexprefix && hexlength == 41 && *s == '0'))
325 /* SHA1/RMD160 fingerprint. */
329 for (i=0; i < 20; i++, s+=2)
331 int c = hextobyte(s);
334 rc = gpg_error (GPG_ERR_INV_USER_ID);
339 mode = KEYDB_SEARCH_MODE_FPR20;
343 /* The fingerprint in an X.509 listing is often delimited by
344 colons, so we try to single this case out. */
346 hexlength = strspn (s, ":0123456789abcdefABCDEF");
347 if (hexlength == 59 && (!s[hexlength] || spacep (s+hexlength)))
351 for (i=0; i < 20; i++, s += 3)
353 int c = hextobyte(s);
354 if (c == -1 || (i < 19 && s[2] != ':'))
359 mode = KEYDB_SEARCH_MODE_FPR20;
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
367 8061 5870 F5BA D690 3336 86D0 F2AD 85AC 1E42 B367
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] == ' '))
379 for (i=0; i < 20; i++)
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 == ' ')
401 mode = KEYDB_SEARCH_MODE_FPR20;
404 if (!mode) /* Default to substring search. */
408 mode = KEYDB_SEARCH_MODE_SUBSTR;
413 /* Hex number with a prefix but with a wrong length. */
414 rc = gpg_error (GPG_ERR_INV_USER_ID);