Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F22947718
userids.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
13 KB
Subscribers
None
userids.c
View Options
/* userids.c - Utility functions for user ids.
* Copyright (C) 2001, 2003, 2004, 2006,
* 2009 Free Software Foundation, Inc.
* Copyright (C) 2015 g10 Code GmbH
*
* This file is part of GnuPG.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of either
*
* - the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 3 of the License, or (at
* your option) any later version.
*
* or
*
* - the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* or both in parallel, as here.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <https://www.gnu.org/licenses/>.
*/
#include
<config.h>
#include
<stdio.h>
#include
<stdlib.h>
#include
<string.h>
#include
"util.h"
#include
"userids.h"
/* Parse the user-id NAME and build a search description for it.
* Returns 0 on success or an error code. DESC may be NULL to merely
* check the validity of a user-id.
*
* Some used rules:
* - If the username starts with 8,9,16 or 17 hex-digits (the first one
* must be in the range 0..9), this is considered a keyid; depending
* on the length a short or complete one.
* - If the username starts with 32,33,40 or 41 hex-digits (the first one
* must be in the range 0..9), this is considered a fingerprint.
* - If the username starts with a left angle, we assume it is a complete
* email address and look only at this part.
* - If the username starts with a colon we assume it is a unified
* key specfification.
* - If the username starts with a '.', we assume it is the ending
* part of an email address
* - If the username starts with an '@', we assume it is a part of an
* email address
* - If the userid start with an '=' an exact compare is done.
* - If the userid starts with a '*' a case insensitive substring search is
* done (This is the default).
* - If the userid starts with a '+' we will compare individual words
* and a match requires that all the words are in the userid.
* Words are delimited by white space or "()<>[]{}.@-+_,;/&!"
* (note that you can't search for these characters). Compare
* is not case sensitive.
* - If the userid starts with a '&' a 40 hex digits keygrip is expected.
*/
gpg_error_t
classify_user_id
(
const
char
*
name
,
KEYDB_SEARCH_DESC
*
desc
,
int
openpgp_hack
)
{
const
char
*
s
;
char
*
s2
=
NULL
;
int
rc
=
0
;
int
hexprefix
=
0
;
int
hexlength
;
int
mode
=
0
;
KEYDB_SEARCH_DESC
dummy_desc
;
if
(
!
desc
)
desc
=
&
dummy_desc
;
/* Clear the structure so that the mode field is set to zero unless
we set it to the correct value right at the end of this
function. */
memset
(
desc
,
0
,
sizeof
*
desc
);
/* Skip leading and trailing spaces. */
for
(
s
=
name
;
*
s
&&
spacep
(
s
);
s
++
)
;
if
(
*
s
&&
spacep
(
s
+
strlen
(
s
)
-
1
))
{
s2
=
xtrystrdup
(
s
);
if
(
!
s2
)
{
rc
=
gpg_error_from_syserror
();
goto
out
;
}
trim_trailing_spaces
(
s2
);
s
=
s2
;
}
switch
(
*
s
)
{
case
0
:
/* Empty string is an error. */
rc
=
gpg_error
(
GPG_ERR_INV_USER_ID
);
goto
out
;
case
'.'
:
/* An email address, compare from end. Note that this
has not yet been implemented in the search code. */
mode
=
KEYDB_SEARCH_MODE_MAILEND
;
s
++
;
desc
->
u
.
name
=
s
;
break
;
case
'<'
:
/* An email address. */
mode
=
KEYDB_SEARCH_MODE_MAIL
;
/* FIXME: The keyring code in g10 assumes that the mail name is
prefixed with an '<'. However the keybox code used for sm/
assumes it has been removed. For now we use this simple hack
to overcome the problem. */
if
(
!
openpgp_hack
)
s
++
;
desc
->
u
.
name
=
s
;
break
;
case
'@'
:
/* Part of an email address. */
mode
=
KEYDB_SEARCH_MODE_MAILSUB
;
s
++
;
desc
->
u
.
name
=
s
;
break
;
case
'='
:
/* Exact compare. */
mode
=
KEYDB_SEARCH_MODE_EXACT
;
s
++
;
desc
->
u
.
name
=
s
;
break
;
case
'*'
:
/* Case insensitive substring search. */
mode
=
KEYDB_SEARCH_MODE_SUBSTR
;
s
++
;
desc
->
u
.
name
=
s
;
break
;
case
'+'
:
/* Compare individual words. Note that this has not
yet been implemented in the search code. */
mode
=
KEYDB_SEARCH_MODE_WORDS
;
s
++
;
desc
->
u
.
name
=
s
;
break
;
case
'/'
:
/* Subject's DN. */
s
++
;
if
(
!*
s
||
spacep
(
s
))
/* No DN or prefixed with a space. */
{
rc
=
gpg_error
(
GPG_ERR_INV_USER_ID
);
goto
out
;
}
desc
->
u
.
name
=
s
;
mode
=
KEYDB_SEARCH_MODE_SUBJECT
;
break
;
case
'#'
:
/* S/N with optional issuer id or just issuer id. */
{
const
char
*
si
;
s
++
;
if
(
*
s
==
'/'
)
{
/* "#/" indicates an issuer's DN. */
s
++
;
if
(
!*
s
||
spacep
(
s
))
/* No DN or prefixed with a space. */
{
rc
=
gpg_error
(
GPG_ERR_INV_USER_ID
);
goto
out
;
}
desc
->
u
.
name
=
s
;
mode
=
KEYDB_SEARCH_MODE_ISSUER
;
}
else
{
/* Serialnumber + optional issuer ID. */
for
(
si
=
s
;
*
si
&&
*
si
!=
'/'
;
si
++
)
{
/* Check for an invalid digit in the serial number. */
if
(
!
strchr
(
"01234567890abcdefABCDEF"
,
*
si
))
{
rc
=
gpg_error
(
GPG_ERR_INV_USER_ID
);
goto
out
;
}
}
desc
->
sn
=
(
const
unsigned
char
*
)
s
;
desc
->
snlen
=
-1
;
if
(
!*
si
)
mode
=
KEYDB_SEARCH_MODE_SN
;
else
{
s
=
si
+
1
;
if
(
!*
s
||
spacep
(
s
))
/* No DN or prefixed with a space. */
{
rc
=
gpg_error
(
GPG_ERR_INV_USER_ID
);
goto
out
;
}
desc
->
u
.
name
=
s
;
mode
=
KEYDB_SEARCH_MODE_ISSUER_SN
;
}
}
}
break
;
case
':'
:
/* Unified fingerprint. */
{
const
char
*
se
,
*
si
;
int
i
;
se
=
strchr
(
++
s
,
':'
);
if
(
!
se
)
{
rc
=
gpg_error
(
GPG_ERR_INV_USER_ID
);
goto
out
;
}
for
(
i
=
0
,
si
=
s
;
si
<
se
;
si
++
,
i
++
)
{
if
(
!
strchr
(
"01234567890abcdefABCDEF"
,
*
si
))
{
rc
=
gpg_error
(
GPG_ERR_INV_USER_ID
);
/* Invalid digit. */
goto
out
;
}
}
if
(
i
!=
32
&&
i
!=
40
)
{
rc
=
gpg_error
(
GPG_ERR_INV_USER_ID
);
/* Invalid length of fpr. */
goto
out
;
}
for
(
i
=
0
,
si
=
s
;
si
<
se
;
i
++
,
si
+=
2
)
desc
->
u
.
fpr
[
i
]
=
hextobyte
(
si
);
for
(;
i
<
20
;
i
++
)
desc
->
u
.
fpr
[
i
]
=
0
;
mode
=
KEYDB_SEARCH_MODE_FPR
;
}
break
;
case
'&'
:
/* Keygrip*/
{
if
(
hex2bin
(
s
+
1
,
desc
->
u
.
grip
,
20
)
<
0
)
{
rc
=
gpg_error
(
GPG_ERR_INV_USER_ID
);
/* Invalid. */
goto
out
;
}
mode
=
KEYDB_SEARCH_MODE_KEYGRIP
;
}
break
;
default
:
if
(
s
[
0
]
==
'0'
&&
s
[
1
]
==
'x'
)
{
hexprefix
=
1
;
s
+=
2
;
}
hexlength
=
strspn
(
s
,
"0123456789abcdefABCDEF"
);
if
(
hexlength
>=
8
&&
s
[
hexlength
]
==
'!'
)
{
desc
->
exact
=
1
;
hexlength
++
;
/* Just for the following check. */
}
/* Check if a hexadecimal number is terminated by EOS or blank. */
if
(
hexlength
&&
s
[
hexlength
]
&&
!
spacep
(
s
+
hexlength
))
{
if
(
hexprefix
)
/* A "0x" prefix without a correct
termination is an error. */
{
rc
=
gpg_error
(
GPG_ERR_INV_USER_ID
);
goto
out
;
}
/* The first characters looked like a hex number, but the
entire string is not. */
hexlength
=
0
;
}
if
(
desc
->
exact
)
hexlength
--
;
/* Remove the bang. */
if
((
hexlength
==
8
&&
(
s
[
hexlength
]
==
0
||
(
s
[
hexlength
]
==
'!'
&&
s
[
hexlength
+
1
]
==
0
)))
||
(
!
hexprefix
&&
hexlength
==
9
&&
*
s
==
'0'
))
{
/* Short keyid. */
if
(
hexlength
==
9
)
s
++
;
desc
->
u
.
kid
[
1
]
=
strtoul
(
s
,
NULL
,
16
);
mode
=
KEYDB_SEARCH_MODE_SHORT_KID
;
}
else
if
((
hexlength
==
16
&&
(
s
[
hexlength
]
==
0
||
(
s
[
hexlength
]
==
'!'
&&
s
[
hexlength
+
1
]
==
0
)))
||
(
!
hexprefix
&&
hexlength
==
17
&&
*
s
==
'0'
))
{
/* Long keyid. */
char
buf
[
9
];
if
(
hexlength
==
17
)
s
++
;
mem2str
(
buf
,
s
,
9
);
desc
->
u
.
kid
[
0
]
=
strtoul
(
buf
,
NULL
,
16
);
desc
->
u
.
kid
[
1
]
=
strtoul
(
s
+
8
,
NULL
,
16
);
mode
=
KEYDB_SEARCH_MODE_LONG_KID
;
}
else
if
((
hexlength
==
32
&&
(
s
[
hexlength
]
==
0
||
(
s
[
hexlength
]
==
'!'
&&
s
[
hexlength
+
1
]
==
0
)))
||
(
!
hexprefix
&&
hexlength
==
33
&&
*
s
==
'0'
))
{
/* MD5 fingerprint. */
int
i
;
if
(
hexlength
==
33
)
s
++
;
memset
(
desc
->
u
.
fpr
+
16
,
0
,
4
);
for
(
i
=
0
;
i
<
16
;
i
++
,
s
+=
2
)
{
int
c
=
hextobyte
(
s
);
if
(
c
==
-1
)
{
rc
=
gpg_error
(
GPG_ERR_INV_USER_ID
);
goto
out
;
}
desc
->
u
.
fpr
[
i
]
=
c
;
}
mode
=
KEYDB_SEARCH_MODE_FPR16
;
}
else
if
((
hexlength
==
40
&&
(
s
[
hexlength
]
==
0
||
(
s
[
hexlength
]
==
'!'
&&
s
[
hexlength
+
1
]
==
0
)))
||
(
!
hexprefix
&&
hexlength
==
41
&&
*
s
==
'0'
))
{
/* SHA1/RMD160 fingerprint. */
int
i
;
if
(
hexlength
==
41
)
s
++
;
for
(
i
=
0
;
i
<
20
;
i
++
,
s
+=
2
)
{
int
c
=
hextobyte
(
s
);
if
(
c
==
-1
)
{
rc
=
gpg_error
(
GPG_ERR_INV_USER_ID
);
goto
out
;
}
desc
->
u
.
fpr
[
i
]
=
c
;
}
mode
=
KEYDB_SEARCH_MODE_FPR20
;
}
else
if
(
!
hexprefix
)
{
/* The fingerprint of an X.509 listing is often delimited by
* colons, so we try to single this case out. Note that the
* OpenPGP bang suffix is not supported here. */
desc
->
exact
=
0
;
mode
=
0
;
hexlength
=
strspn
(
s
,
":0123456789abcdefABCDEF"
);
if
(
hexlength
==
59
&&
(
!
s
[
hexlength
]
||
spacep
(
s
+
hexlength
)))
{
int
i
;
for
(
i
=
0
;
i
<
20
;
i
++
,
s
+=
3
)
{
int
c
=
hextobyte
(
s
);
if
(
c
==
-1
||
(
i
<
19
&&
s
[
2
]
!=
':'
))
break
;
desc
->
u
.
fpr
[
i
]
=
c
;
}
if
(
i
==
20
)
mode
=
KEYDB_SEARCH_MODE_FPR20
;
}
if
(
!
mode
)
{
/* Still not found. Now check for a space separated
OpenPGP v4 fingerprint like:
8061 5870 F5BA D690 3336 86D0 F2AD 85AC 1E42 B367
or
8061 5870 F5BA D690 3336 86D0 F2AD 85AC 1E42 B367
*/
hexlength
=
strspn
(
s
,
" 0123456789abcdefABCDEF"
);
if
(
s
[
hexlength
]
&&
s
[
hexlength
]
!=
' '
)
hexlength
=
0
;
/* Followed by non-space. */
while
(
hexlength
&&
s
[
hexlength
-1
]
==
' '
)
hexlength
--
;
/* Trim trailing spaces. */
if
((
hexlength
==
49
||
hexlength
==
50
)
&&
(
!
s
[
hexlength
]
||
s
[
hexlength
]
==
' '
))
{
int
i
,
c
;
for
(
i
=
0
;
i
<
20
;
i
++
)
{
if
(
i
&&
!
(
i
%
2
))
{
if
(
*
s
!=
' '
)
break
;
s
++
;
/* Skip the double space in the middle but
don't require it to help copying
fingerprints from sources which fold
multiple space to one. */
if
(
i
==
10
&&
*
s
==
' '
)
s
++
;
}
c
=
hextobyte
(
s
);
if
(
c
==
-1
)
break
;
desc
->
u
.
fpr
[
i
]
=
c
;
s
+=
2
;
}
if
(
i
==
20
)
mode
=
KEYDB_SEARCH_MODE_FPR20
;
}
}
if
(
!
mode
)
/* Default to substring search. */
{
desc
->
u
.
name
=
s
;
mode
=
KEYDB_SEARCH_MODE_SUBSTR
;
}
}
else
{
/* Hex number with a prefix but with a wrong length. */
rc
=
gpg_error
(
GPG_ERR_INV_USER_ID
);
goto
out
;
}
}
desc
->
mode
=
mode
;
out
:
xfree
(
s2
);
return
rc
;
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Sat, May 10, 8:28 AM (1 d, 11 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
9f/7c/cbd9c1e8d09cc3fc277a64d242c9
Attached To
rG GnuPG
Event Timeline
Log In to Comment