2003-06-05 09:14:21 +02:00
|
|
|
|
/* keybox-search.c - Search operations
|
2013-01-07 21:14:52 +01:00
|
|
|
|
* Copyright (C) 2001, 2002, 2003, 2004, 2012,
|
|
|
|
|
* 2013 Free Software Foundation, Inc.
|
2003-06-05 09:14:21 +02:00
|
|
|
|
*
|
|
|
|
|
* This file is part of GnuPG.
|
|
|
|
|
*
|
|
|
|
|
* GnuPG is free software; you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
2007-07-04 21:49:40 +02:00
|
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
2003-06-05 09:14:21 +02:00
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* GnuPG 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
|
2016-11-05 12:02:19 +01:00
|
|
|
|
* along with this program; if not, see <https://www.gnu.org/licenses/>.
|
2003-06-05 09:14:21 +02:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
|
|
#include "keybox-defs.h"
|
2006-10-20 13:38:48 +02:00
|
|
|
|
#include <gcrypt.h>
|
2017-03-07 12:21:23 +01:00
|
|
|
|
#include "../common/host2net.h"
|
|
|
|
|
#include "../common/mbox-util.h"
|
2004-02-02 18:09:35 +01:00
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
|
|
|
|
|
*(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
|
|
|
|
|
#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
|
|
|
|
|
|
2004-02-02 18:09:35 +01:00
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
struct sn_array_s {
|
|
|
|
|
int snlen;
|
|
|
|
|
unsigned char *sn;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2015-02-11 10:27:57 +01:00
|
|
|
|
#define get32(a) buf32_to_ulong ((a))
|
|
|
|
|
#define get16(a) buf16_to_ulong ((a))
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
|
|
|
|
|
2004-04-26 10:09:25 +02:00
|
|
|
|
static inline unsigned int
|
2003-06-05 09:14:21 +02:00
|
|
|
|
blob_get_blob_flags (KEYBOXBLOB blob)
|
|
|
|
|
{
|
|
|
|
|
const unsigned char *buffer;
|
|
|
|
|
size_t length;
|
|
|
|
|
|
|
|
|
|
buffer = _keybox_get_blob_image (blob, &length);
|
|
|
|
|
if (length < 8)
|
|
|
|
|
return 0; /* oops */
|
|
|
|
|
|
|
|
|
|
return get16 (buffer + 6);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-01-19 14:58:06 +01:00
|
|
|
|
/* Return the first keyid from the blob. Returns true if
|
|
|
|
|
available. */
|
2015-01-16 16:56:35 +01:00
|
|
|
|
static int
|
2015-01-19 14:58:06 +01:00
|
|
|
|
blob_get_first_keyid (KEYBOXBLOB blob, u32 *kid)
|
2015-01-16 16:56:35 +01:00
|
|
|
|
{
|
|
|
|
|
const unsigned char *buffer;
|
2015-01-19 14:58:06 +01:00
|
|
|
|
size_t length, nkeys, keyinfolen;
|
2019-03-14 08:54:59 +01:00
|
|
|
|
int fpr32;
|
2015-01-16 16:56:35 +01:00
|
|
|
|
|
|
|
|
|
buffer = _keybox_get_blob_image (blob, &length);
|
|
|
|
|
if (length < 48)
|
|
|
|
|
return 0; /* blob too short */
|
2019-03-14 08:54:59 +01:00
|
|
|
|
fpr32 = buffer[5] == 2;
|
|
|
|
|
if (fpr32 && length < 56)
|
|
|
|
|
return 0; /* blob to short */
|
2015-01-16 16:56:35 +01:00
|
|
|
|
|
2015-01-19 14:58:06 +01:00
|
|
|
|
nkeys = get16 (buffer + 16);
|
2015-01-16 16:56:35 +01:00
|
|
|
|
keyinfolen = get16 (buffer + 18);
|
2019-03-14 08:54:59 +01:00
|
|
|
|
if (!nkeys || keyinfolen < (fpr32?56:28))
|
2015-01-16 16:56:35 +01:00
|
|
|
|
return 0; /* invalid blob */
|
|
|
|
|
|
2019-03-14 08:54:59 +01:00
|
|
|
|
if (fpr32 && (get16 (buffer + 20 + 32) & 0x80))
|
|
|
|
|
{
|
|
|
|
|
/* 32 byte fingerprint. */
|
|
|
|
|
kid[0] = get32 (buffer + 20);
|
|
|
|
|
kid[1] = get32 (buffer + 20 + 4);
|
|
|
|
|
}
|
|
|
|
|
else /* 20 byte fingerprint. */
|
|
|
|
|
{
|
|
|
|
|
kid[0] = get32 (buffer + 20 + 12);
|
|
|
|
|
kid[1] = get32 (buffer + 20 + 16);
|
|
|
|
|
}
|
2015-01-16 16:56:35 +01:00
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2004-02-02 18:09:35 +01:00
|
|
|
|
/* Return information on the flag WHAT within the blob BUFFER,LENGTH.
|
|
|
|
|
Return the offset and the length (in bytes) of the flag in
|
|
|
|
|
FLAGOFF,FLAG_SIZE. */
|
|
|
|
|
gpg_err_code_t
|
|
|
|
|
_keybox_get_flag_location (const unsigned char *buffer, size_t length,
|
|
|
|
|
int what, size_t *flag_off, size_t *flag_size)
|
|
|
|
|
{
|
|
|
|
|
size_t pos;
|
|
|
|
|
size_t nkeys, keyinfolen;
|
|
|
|
|
size_t nuids, uidinfolen;
|
|
|
|
|
size_t nserial;
|
2012-12-28 17:17:56 +01:00
|
|
|
|
size_t nsigs, siginfolen, siginfooff;
|
2004-02-02 18:09:35 +01:00
|
|
|
|
|
|
|
|
|
switch (what)
|
|
|
|
|
{
|
|
|
|
|
case KEYBOX_FLAG_BLOB:
|
|
|
|
|
if (length < 8)
|
|
|
|
|
return GPG_ERR_INV_OBJ;
|
|
|
|
|
*flag_off = 6;
|
|
|
|
|
*flag_size = 2;
|
|
|
|
|
break;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2004-02-02 18:09:35 +01:00
|
|
|
|
case KEYBOX_FLAG_OWNERTRUST:
|
2004-04-26 10:09:25 +02:00
|
|
|
|
case KEYBOX_FLAG_VALIDITY:
|
|
|
|
|
case KEYBOX_FLAG_CREATED_AT:
|
2012-12-28 17:17:56 +01:00
|
|
|
|
case KEYBOX_FLAG_SIG_INFO:
|
2004-02-02 18:09:35 +01:00
|
|
|
|
if (length < 20)
|
|
|
|
|
return GPG_ERR_INV_OBJ;
|
|
|
|
|
/* Key info. */
|
|
|
|
|
nkeys = get16 (buffer + 16);
|
|
|
|
|
keyinfolen = get16 (buffer + 18 );
|
|
|
|
|
if (keyinfolen < 28)
|
|
|
|
|
return GPG_ERR_INV_OBJ;
|
|
|
|
|
pos = 20 + keyinfolen*nkeys;
|
|
|
|
|
if (pos+2 > length)
|
|
|
|
|
return GPG_ERR_INV_OBJ; /* Out of bounds. */
|
|
|
|
|
/* Serial number. */
|
2011-02-04 12:57:53 +01:00
|
|
|
|
nserial = get16 (buffer+pos);
|
2004-02-02 18:09:35 +01:00
|
|
|
|
pos += 2 + nserial;
|
|
|
|
|
if (pos+4 > length)
|
|
|
|
|
return GPG_ERR_INV_OBJ; /* Out of bounds. */
|
|
|
|
|
/* User IDs. */
|
|
|
|
|
nuids = get16 (buffer + pos); pos += 2;
|
|
|
|
|
uidinfolen = get16 (buffer + pos); pos += 2;
|
|
|
|
|
if (uidinfolen < 12 )
|
2011-02-04 12:57:53 +01:00
|
|
|
|
return GPG_ERR_INV_OBJ;
|
2004-02-02 18:09:35 +01:00
|
|
|
|
pos += uidinfolen*nuids;
|
|
|
|
|
if (pos+4 > length)
|
|
|
|
|
return GPG_ERR_INV_OBJ ; /* Out of bounds. */
|
|
|
|
|
/* Signature info. */
|
2012-12-28 17:17:56 +01:00
|
|
|
|
siginfooff = pos;
|
2004-02-02 18:09:35 +01:00
|
|
|
|
nsigs = get16 (buffer + pos); pos += 2;
|
|
|
|
|
siginfolen = get16 (buffer + pos); pos += 2;
|
|
|
|
|
if (siginfolen < 4 )
|
2011-02-04 12:57:53 +01:00
|
|
|
|
return GPG_ERR_INV_OBJ;
|
2004-02-02 18:09:35 +01:00
|
|
|
|
pos += siginfolen*nsigs;
|
|
|
|
|
if (pos+1+1+2+4+4+4+4 > length)
|
|
|
|
|
return GPG_ERR_INV_OBJ ; /* Out of bounds. */
|
|
|
|
|
*flag_size = 1;
|
|
|
|
|
*flag_off = pos;
|
2004-04-26 10:09:25 +02:00
|
|
|
|
switch (what)
|
|
|
|
|
{
|
|
|
|
|
case KEYBOX_FLAG_VALIDITY:
|
|
|
|
|
*flag_off += 1;
|
|
|
|
|
break;
|
|
|
|
|
case KEYBOX_FLAG_CREATED_AT:
|
|
|
|
|
*flag_size = 4;
|
|
|
|
|
*flag_off += 1+2+4+4+4;
|
|
|
|
|
break;
|
2012-12-28 17:17:56 +01:00
|
|
|
|
case KEYBOX_FLAG_SIG_INFO:
|
|
|
|
|
*flag_size = siginfolen * nsigs;
|
|
|
|
|
*flag_off = siginfooff;
|
|
|
|
|
break;
|
2004-04-26 10:09:25 +02:00
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2004-02-02 18:09:35 +01:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return GPG_ERR_INV_FLAG;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2004-04-26 10:09:25 +02:00
|
|
|
|
|
|
|
|
|
|
2015-10-27 22:09:43 +01:00
|
|
|
|
/* Return one of the flags WHAT in VALUE from the blob BUFFER of
|
2004-02-02 18:09:35 +01:00
|
|
|
|
LENGTH bytes. Return 0 on success or an raw error code. */
|
|
|
|
|
static gpg_err_code_t
|
|
|
|
|
get_flag_from_image (const unsigned char *buffer, size_t length,
|
|
|
|
|
int what, unsigned int *value)
|
|
|
|
|
{
|
|
|
|
|
gpg_err_code_t ec;
|
|
|
|
|
size_t pos, size;
|
|
|
|
|
|
|
|
|
|
*value = 0;
|
|
|
|
|
ec = _keybox_get_flag_location (buffer, length, what, &pos, &size);
|
|
|
|
|
if (!ec)
|
|
|
|
|
switch (size)
|
|
|
|
|
{
|
|
|
|
|
case 1: *value = buffer[pos]; break;
|
|
|
|
|
case 2: *value = get16 (buffer + pos); break;
|
|
|
|
|
case 4: *value = get32 (buffer + pos); break;
|
|
|
|
|
default: ec = GPG_ERR_BUG; break;
|
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2004-02-02 18:09:35 +01:00
|
|
|
|
return ec;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
static int
|
|
|
|
|
blob_cmp_sn (KEYBOXBLOB blob, const unsigned char *sn, int snlen)
|
|
|
|
|
{
|
|
|
|
|
const unsigned char *buffer;
|
|
|
|
|
size_t length;
|
|
|
|
|
size_t pos, off;
|
|
|
|
|
size_t nkeys, keyinfolen;
|
|
|
|
|
size_t nserial;
|
|
|
|
|
|
|
|
|
|
buffer = _keybox_get_blob_image (blob, &length);
|
|
|
|
|
if (length < 40)
|
|
|
|
|
return 0; /* blob too short */
|
|
|
|
|
|
|
|
|
|
/*keys*/
|
|
|
|
|
nkeys = get16 (buffer + 16);
|
|
|
|
|
keyinfolen = get16 (buffer + 18 );
|
|
|
|
|
if (keyinfolen < 28)
|
|
|
|
|
return 0; /* invalid blob */
|
|
|
|
|
pos = 20 + keyinfolen*nkeys;
|
|
|
|
|
if (pos+2 > length)
|
|
|
|
|
return 0; /* out of bounds */
|
|
|
|
|
|
|
|
|
|
/*serial*/
|
2011-02-04 12:57:53 +01:00
|
|
|
|
nserial = get16 (buffer+pos);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
off = pos + 2;
|
|
|
|
|
if (off+nserial > length)
|
|
|
|
|
return 0; /* out of bounds */
|
|
|
|
|
|
|
|
|
|
return nserial == snlen && !memcmp (buffer+off, sn, snlen);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-01-07 21:14:52 +01:00
|
|
|
|
/* Returns 0 if not found or the number of the key which was found.
|
|
|
|
|
For X.509 this is always 1, for OpenPGP this is 1 for the primary
|
|
|
|
|
key and 2 and more for the subkeys. */
|
2003-06-05 09:14:21 +02:00
|
|
|
|
static int
|
2019-03-14 08:54:59 +01:00
|
|
|
|
blob_cmp_fpr (KEYBOXBLOB blob, const unsigned char *fpr, unsigned int fprlen)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
const unsigned char *buffer;
|
|
|
|
|
size_t length;
|
|
|
|
|
size_t pos, off;
|
|
|
|
|
size_t nkeys, keyinfolen;
|
2019-03-14 08:54:59 +01:00
|
|
|
|
int idx, fpr32, storedfprlen;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
|
|
|
|
buffer = _keybox_get_blob_image (blob, &length);
|
|
|
|
|
if (length < 40)
|
|
|
|
|
return 0; /* blob too short */
|
2019-03-14 08:54:59 +01:00
|
|
|
|
fpr32 = buffer[5] == 2;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
|
|
|
|
/*keys*/
|
|
|
|
|
nkeys = get16 (buffer + 16);
|
|
|
|
|
keyinfolen = get16 (buffer + 18 );
|
2019-03-14 08:54:59 +01:00
|
|
|
|
if (keyinfolen < (fpr32?56:28))
|
2003-06-05 09:14:21 +02:00
|
|
|
|
return 0; /* invalid blob */
|
|
|
|
|
pos = 20;
|
2018-02-15 11:17:28 +01:00
|
|
|
|
if (pos + (uint64_t)keyinfolen*nkeys > (uint64_t)length)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
return 0; /* out of bounds */
|
|
|
|
|
|
|
|
|
|
for (idx=0; idx < nkeys; idx++)
|
|
|
|
|
{
|
|
|
|
|
off = pos + idx*keyinfolen;
|
2019-03-14 08:54:59 +01:00
|
|
|
|
if (fpr32)
|
|
|
|
|
storedfprlen = (get16 (buffer + off + 32) & 0x80)? 32:20;
|
|
|
|
|
else
|
|
|
|
|
storedfprlen = 20;
|
|
|
|
|
if (storedfprlen == fprlen
|
|
|
|
|
&& !memcmp (buffer + off, fpr, storedfprlen))
|
2013-01-07 21:14:52 +01:00
|
|
|
|
return idx+1; /* found */
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
return 0; /* not found */
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-14 08:54:59 +01:00
|
|
|
|
|
2024-04-08 20:32:47 +02:00
|
|
|
|
/* Helper for has_short_kid and has_long_kid. This function is called
|
|
|
|
|
* with FPROFF 12 and FPRLEN 4 or with FPROFF 12 and FPRLEN 8. */
|
2003-06-05 09:14:21 +02:00
|
|
|
|
static int
|
|
|
|
|
blob_cmp_fpr_part (KEYBOXBLOB blob, const unsigned char *fpr,
|
|
|
|
|
int fproff, int fprlen)
|
|
|
|
|
{
|
|
|
|
|
const unsigned char *buffer;
|
|
|
|
|
size_t length;
|
|
|
|
|
size_t pos, off;
|
|
|
|
|
size_t nkeys, keyinfolen;
|
2024-04-08 20:32:47 +02:00
|
|
|
|
int idx;
|
|
|
|
|
int fpr32; /* Set if this blob stores all fingerprints as 32 bytes. */
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
|
|
|
|
buffer = _keybox_get_blob_image (blob, &length);
|
|
|
|
|
if (length < 40)
|
|
|
|
|
return 0; /* blob too short */
|
2019-03-14 08:54:59 +01:00
|
|
|
|
fpr32 = buffer[5] == 2;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
|
|
|
|
/*keys*/
|
|
|
|
|
nkeys = get16 (buffer + 16);
|
|
|
|
|
keyinfolen = get16 (buffer + 18 );
|
2019-03-14 08:54:59 +01:00
|
|
|
|
if (keyinfolen < (fpr32?56:28))
|
2003-06-05 09:14:21 +02:00
|
|
|
|
return 0; /* invalid blob */
|
|
|
|
|
pos = 20;
|
2018-02-15 11:17:28 +01:00
|
|
|
|
if (pos + (uint64_t)keyinfolen*nkeys > (uint64_t)length)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
return 0; /* out of bounds */
|
|
|
|
|
|
|
|
|
|
for (idx=0; idx < nkeys; idx++)
|
|
|
|
|
{
|
|
|
|
|
off = pos + idx*keyinfolen;
|
2024-04-08 20:32:47 +02:00
|
|
|
|
if (!fpr32)
|
|
|
|
|
{
|
|
|
|
|
/* Blob has only 20 fingerprints - use the FPROFF. */
|
|
|
|
|
if (!memcmp (buffer + off + fproff, fpr, fprlen))
|
|
|
|
|
return idx+1; /* found */
|
|
|
|
|
}
|
|
|
|
|
else if ((buffer[off + 32 + 1] & 0x80))
|
|
|
|
|
{
|
|
|
|
|
/* This (sub)key has a 32 byte fpr -> use 0 as offset. */
|
|
|
|
|
if (!memcmp (buffer + off, fpr, fprlen))
|
|
|
|
|
return idx+1; /* found */
|
|
|
|
|
}
|
2019-03-14 08:54:59 +01:00
|
|
|
|
else
|
2024-04-08 20:32:47 +02:00
|
|
|
|
{
|
|
|
|
|
/* This (sub)key has a 20 byte fpr -> use the FPROFF */
|
|
|
|
|
if (!memcmp (buffer + off + fproff, fpr, fprlen))
|
|
|
|
|
return idx+1; /* found */
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
return 0; /* not found */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2019-11-28 09:39:35 +01:00
|
|
|
|
/* Returns true if found. */
|
|
|
|
|
static int
|
|
|
|
|
blob_cmp_ubid (KEYBOXBLOB blob, const unsigned char *ubid)
|
|
|
|
|
{
|
|
|
|
|
const unsigned char *buffer;
|
|
|
|
|
size_t length;
|
|
|
|
|
size_t pos;
|
|
|
|
|
size_t nkeys, keyinfolen;
|
|
|
|
|
int fpr32;
|
|
|
|
|
|
|
|
|
|
buffer = _keybox_get_blob_image (blob, &length);
|
|
|
|
|
if (length < 40)
|
|
|
|
|
return 0; /* blob too short */
|
|
|
|
|
fpr32 = buffer[5] == 2;
|
|
|
|
|
|
|
|
|
|
/*keys*/
|
|
|
|
|
nkeys = get16 (buffer + 16);
|
|
|
|
|
keyinfolen = get16 (buffer + 18 );
|
|
|
|
|
if (!nkeys || keyinfolen < (fpr32?56:28))
|
|
|
|
|
return 0; /* invalid blob */
|
|
|
|
|
pos = 20;
|
|
|
|
|
if (pos + (uint64_t)keyinfolen*nkeys > (uint64_t)length)
|
|
|
|
|
return 0; /* out of bounds */
|
|
|
|
|
|
|
|
|
|
if (!memcmp (buffer + pos, ubid, UBID_LEN))
|
|
|
|
|
return 1; /* found */
|
|
|
|
|
return 0; /* not found */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
static int
|
|
|
|
|
blob_cmp_name (KEYBOXBLOB blob, int idx,
|
2013-01-07 15:41:10 +01:00
|
|
|
|
const char *name, size_t namelen, int substr, int x509)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
const unsigned char *buffer;
|
|
|
|
|
size_t length;
|
|
|
|
|
size_t pos, off, len;
|
|
|
|
|
size_t nkeys, keyinfolen;
|
|
|
|
|
size_t nuids, uidinfolen;
|
|
|
|
|
size_t nserial;
|
|
|
|
|
|
|
|
|
|
buffer = _keybox_get_blob_image (blob, &length);
|
|
|
|
|
if (length < 40)
|
|
|
|
|
return 0; /* blob too short */
|
|
|
|
|
|
|
|
|
|
/*keys*/
|
|
|
|
|
nkeys = get16 (buffer + 16);
|
|
|
|
|
keyinfolen = get16 (buffer + 18 );
|
|
|
|
|
if (keyinfolen < 28)
|
|
|
|
|
return 0; /* invalid blob */
|
|
|
|
|
pos = 20 + keyinfolen*nkeys;
|
2018-02-15 11:17:28 +01:00
|
|
|
|
if ((uint64_t)pos+2 > (uint64_t)length)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
return 0; /* out of bounds */
|
|
|
|
|
|
|
|
|
|
/*serial*/
|
2011-02-04 12:57:53 +01:00
|
|
|
|
nserial = get16 (buffer+pos);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
pos += 2 + nserial;
|
|
|
|
|
if (pos+4 > length)
|
|
|
|
|
return 0; /* out of bounds */
|
|
|
|
|
|
|
|
|
|
/* user ids*/
|
|
|
|
|
nuids = get16 (buffer + pos); pos += 2;
|
|
|
|
|
uidinfolen = get16 (buffer + pos); pos += 2;
|
|
|
|
|
if (uidinfolen < 12 /* should add a: || nuidinfolen > MAX_UIDINFOLEN */)
|
|
|
|
|
return 0; /* invalid blob */
|
|
|
|
|
if (pos + uidinfolen*nuids > length)
|
|
|
|
|
return 0; /* out of bounds */
|
|
|
|
|
|
|
|
|
|
if (idx < 0)
|
2013-01-07 15:41:10 +01:00
|
|
|
|
{ /* Compare all names. Note that for X.509 we start with index 1
|
|
|
|
|
so to skip the issuer at index 0. */
|
|
|
|
|
for (idx = !!x509; idx < nuids; idx++)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
size_t mypos = pos;
|
|
|
|
|
|
|
|
|
|
mypos += idx*uidinfolen;
|
|
|
|
|
off = get32 (buffer+mypos);
|
|
|
|
|
len = get32 (buffer+mypos+4);
|
2018-02-15 11:17:28 +01:00
|
|
|
|
if ((uint64_t)off+(uint64_t)len > (uint64_t)length)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
return 0; /* error: better stop here out of bounds */
|
|
|
|
|
if (len < 1)
|
|
|
|
|
continue; /* empty name */
|
|
|
|
|
if (substr)
|
|
|
|
|
{
|
|
|
|
|
if (ascii_memcasemem (buffer+off, len, name, namelen))
|
2013-01-07 21:14:52 +01:00
|
|
|
|
return idx+1; /* found */
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (len == namelen && !memcmp (buffer+off, name, len))
|
2013-01-07 21:14:52 +01:00
|
|
|
|
return idx+1; /* found */
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (idx > nuids)
|
|
|
|
|
return 0; /* no user ID with that idx */
|
|
|
|
|
pos += idx*uidinfolen;
|
|
|
|
|
off = get32 (buffer+pos);
|
|
|
|
|
len = get32 (buffer+pos+4);
|
|
|
|
|
if (off+len > length)
|
|
|
|
|
return 0; /* out of bounds */
|
|
|
|
|
if (len < 1)
|
|
|
|
|
return 0; /* empty name */
|
|
|
|
|
|
|
|
|
|
if (substr)
|
|
|
|
|
{
|
2013-01-07 21:14:52 +01:00
|
|
|
|
if (ascii_memcasemem (buffer+off, len, name, namelen))
|
|
|
|
|
return idx+1; /* found */
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2013-01-07 21:14:52 +01:00
|
|
|
|
if (len == namelen && !memcmp (buffer+off, name, len))
|
|
|
|
|
return idx+1; /* found */
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2013-01-07 21:14:52 +01:00
|
|
|
|
return 0; /* not found */
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-01-07 15:41:10 +01:00
|
|
|
|
/* Compare all email addresses of the subject. With SUBSTR given as
|
2015-03-20 13:29:20 +01:00
|
|
|
|
True a substring search is done in the mail address. The X509 flag
|
|
|
|
|
indicated whether the search is done on an X.509 blob. */
|
2003-06-05 09:14:21 +02:00
|
|
|
|
static int
|
2013-01-07 15:41:10 +01:00
|
|
|
|
blob_cmp_mail (KEYBOXBLOB blob, const char *name, size_t namelen, int substr,
|
|
|
|
|
int x509)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
const unsigned char *buffer;
|
|
|
|
|
size_t length;
|
|
|
|
|
size_t pos, off, len;
|
|
|
|
|
size_t nkeys, keyinfolen;
|
|
|
|
|
size_t nuids, uidinfolen;
|
|
|
|
|
size_t nserial;
|
|
|
|
|
int idx;
|
|
|
|
|
|
|
|
|
|
/* fixme: this code is common to blob_cmp_mail */
|
|
|
|
|
buffer = _keybox_get_blob_image (blob, &length);
|
|
|
|
|
if (length < 40)
|
|
|
|
|
return 0; /* blob too short */
|
|
|
|
|
|
|
|
|
|
/*keys*/
|
|
|
|
|
nkeys = get16 (buffer + 16);
|
|
|
|
|
keyinfolen = get16 (buffer + 18 );
|
|
|
|
|
if (keyinfolen < 28)
|
|
|
|
|
return 0; /* invalid blob */
|
|
|
|
|
pos = 20 + keyinfolen*nkeys;
|
|
|
|
|
if (pos+2 > length)
|
|
|
|
|
return 0; /* out of bounds */
|
|
|
|
|
|
|
|
|
|
/*serial*/
|
2011-02-04 12:57:53 +01:00
|
|
|
|
nserial = get16 (buffer+pos);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
pos += 2 + nserial;
|
|
|
|
|
if (pos+4 > length)
|
|
|
|
|
return 0; /* out of bounds */
|
|
|
|
|
|
|
|
|
|
/* user ids*/
|
|
|
|
|
nuids = get16 (buffer + pos); pos += 2;
|
|
|
|
|
uidinfolen = get16 (buffer + pos); pos += 2;
|
|
|
|
|
if (uidinfolen < 12 /* should add a: || nuidinfolen > MAX_UIDINFOLEN */)
|
|
|
|
|
return 0; /* invalid blob */
|
|
|
|
|
if (pos + uidinfolen*nuids > length)
|
|
|
|
|
return 0; /* out of bounds */
|
|
|
|
|
|
|
|
|
|
if (namelen < 1)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2015-11-16 12:41:46 +01:00
|
|
|
|
/* Note that for X.509 we start at index 1 because index 0 is used
|
2013-01-07 15:41:10 +01:00
|
|
|
|
for the issuer name. */
|
|
|
|
|
for (idx=!!x509 ;idx < nuids; idx++)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
size_t mypos = pos;
|
2015-03-20 15:43:32 +01:00
|
|
|
|
size_t mylen;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
mypos += idx*uidinfolen;
|
|
|
|
|
off = get32 (buffer+mypos);
|
|
|
|
|
len = get32 (buffer+mypos+4);
|
2018-02-15 11:17:28 +01:00
|
|
|
|
if ((uint64_t)off+(uint64_t)len > (uint64_t)length)
|
2015-03-20 13:29:20 +01:00
|
|
|
|
return 0; /* error: better stop here - out of bounds */
|
|
|
|
|
if (x509)
|
2013-01-07 15:41:10 +01:00
|
|
|
|
{
|
2015-03-20 13:29:20 +01:00
|
|
|
|
if (len < 2 || buffer[off] != '<')
|
|
|
|
|
continue; /* empty name or trailing 0 not stored */
|
|
|
|
|
len--; /* one back */
|
|
|
|
|
if ( len < 3 || buffer[off+len] != '>')
|
|
|
|
|
continue; /* not a proper email address */
|
|
|
|
|
off++;
|
|
|
|
|
len--;
|
|
|
|
|
}
|
|
|
|
|
else /* OpenPGP. */
|
|
|
|
|
{
|
|
|
|
|
/* We need to forward to the mailbox part. */
|
2015-03-20 15:43:32 +01:00
|
|
|
|
mypos = off;
|
|
|
|
|
mylen = len;
|
2015-03-20 13:29:20 +01:00
|
|
|
|
for ( ; len && buffer[off] != '<'; len--, off++)
|
2013-01-07 15:41:10 +01:00
|
|
|
|
;
|
2015-03-20 13:29:20 +01:00
|
|
|
|
if (len < 2 || buffer[off] != '<')
|
2015-03-20 15:43:32 +01:00
|
|
|
|
{
|
|
|
|
|
/* Mailbox not explicitly given or too short. Restore
|
|
|
|
|
OFF and LEN and check whether the entire string
|
|
|
|
|
resembles a mailbox without the angle brackets. */
|
|
|
|
|
off = mypos;
|
|
|
|
|
len = mylen;
|
|
|
|
|
if (!is_valid_mailbox_mem (buffer+off, len))
|
|
|
|
|
continue; /* Not a mail address. */
|
|
|
|
|
}
|
|
|
|
|
else /* Seems to be standard user id with mail address. */
|
|
|
|
|
{
|
|
|
|
|
off++; /* Point to first char of the mail address. */
|
|
|
|
|
len--;
|
|
|
|
|
/* Search closing '>'. */
|
|
|
|
|
for (mypos=off; len && buffer[mypos] != '>'; len--, mypos++)
|
|
|
|
|
;
|
|
|
|
|
if (!len || buffer[mypos] != '>' || off == mypos)
|
|
|
|
|
continue; /* Not a proper mail address. */
|
|
|
|
|
len = mypos - off;
|
|
|
|
|
}
|
2015-03-20 13:29:20 +01:00
|
|
|
|
|
2013-01-07 15:41:10 +01:00
|
|
|
|
}
|
2015-03-20 13:29:20 +01:00
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
if (substr)
|
|
|
|
|
{
|
2015-03-20 13:29:20 +01:00
|
|
|
|
if (ascii_memcasemem (buffer+off, len, name, namelen))
|
2013-01-07 21:14:52 +01:00
|
|
|
|
return idx+1; /* found */
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2015-03-20 13:29:20 +01:00
|
|
|
|
if (len == namelen && !ascii_memcasecmp (buffer+off, name, len))
|
2013-01-07 21:14:52 +01:00
|
|
|
|
return idx+1; /* found */
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0; /* not found */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2019-01-29 19:52:08 +01:00
|
|
|
|
/* Return true if the key in BLOB matches the 20 bytes keygrip GRIP.
|
|
|
|
|
* We don't have the keygrips as meta data, thus we need to parse the
|
|
|
|
|
* certificate. Fixme: We might want to return proper error codes
|
|
|
|
|
* instead of failing a search for invalid certificates etc. */
|
|
|
|
|
static int
|
|
|
|
|
blob_openpgp_has_grip (KEYBOXBLOB blob, const unsigned char *grip)
|
|
|
|
|
{
|
|
|
|
|
int rc = 0;
|
|
|
|
|
const unsigned char *buffer;
|
|
|
|
|
size_t length;
|
|
|
|
|
size_t cert_off, cert_len;
|
|
|
|
|
struct _keybox_openpgp_info info;
|
|
|
|
|
struct _keybox_openpgp_key_info *k;
|
|
|
|
|
|
|
|
|
|
buffer = _keybox_get_blob_image (blob, &length);
|
|
|
|
|
if (length < 40)
|
|
|
|
|
return 0; /* Too short. */
|
|
|
|
|
cert_off = get32 (buffer+8);
|
|
|
|
|
cert_len = get32 (buffer+12);
|
|
|
|
|
if ((uint64_t)cert_off+(uint64_t)cert_len > (uint64_t)length)
|
|
|
|
|
return 0; /* Too short. */
|
|
|
|
|
|
|
|
|
|
if (_keybox_parse_openpgp (buffer + cert_off, cert_len, NULL, &info))
|
|
|
|
|
return 0; /* Parse error. */
|
|
|
|
|
|
|
|
|
|
if (!memcmp (info.primary.grip, grip, 20))
|
|
|
|
|
{
|
|
|
|
|
rc = 1;
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (info.nsubkeys)
|
|
|
|
|
{
|
|
|
|
|
k = &info.subkeys;
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
if (!memcmp (k->grip, grip, 20))
|
|
|
|
|
{
|
|
|
|
|
rc = 1;
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
k = k->next;
|
|
|
|
|
}
|
|
|
|
|
while (k);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
leave:
|
|
|
|
|
_keybox_destroy_openpgp_info (&info);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2006-10-20 13:38:48 +02:00
|
|
|
|
#ifdef KEYBOX_WITH_X509
|
|
|
|
|
/* Return true if the key in BLOB matches the 20 bytes keygrip GRIP.
|
2009-03-06 18:31:27 +01:00
|
|
|
|
We don't have the keygrips as meta data, thus we need to parse the
|
2008-04-01 17:08:57 +02:00
|
|
|
|
certificate. Fixme: We might want to return proper error codes
|
2006-10-20 13:38:48 +02:00
|
|
|
|
instead of failing a search for invalid certificates etc. */
|
|
|
|
|
static int
|
|
|
|
|
blob_x509_has_grip (KEYBOXBLOB blob, const unsigned char *grip)
|
|
|
|
|
{
|
|
|
|
|
int rc;
|
|
|
|
|
const unsigned char *buffer;
|
|
|
|
|
size_t length;
|
|
|
|
|
size_t cert_off, cert_len;
|
|
|
|
|
ksba_reader_t reader = NULL;
|
|
|
|
|
ksba_cert_t cert = NULL;
|
|
|
|
|
ksba_sexp_t p = NULL;
|
|
|
|
|
gcry_sexp_t s_pkey;
|
|
|
|
|
unsigned char array[20];
|
|
|
|
|
unsigned char *rcp;
|
|
|
|
|
size_t n;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2006-10-20 13:38:48 +02:00
|
|
|
|
buffer = _keybox_get_blob_image (blob, &length);
|
|
|
|
|
if (length < 40)
|
|
|
|
|
return 0; /* Too short. */
|
|
|
|
|
cert_off = get32 (buffer+8);
|
|
|
|
|
cert_len = get32 (buffer+12);
|
2018-02-15 11:17:28 +01:00
|
|
|
|
if ((uint64_t)cert_off+(uint64_t)cert_len > (uint64_t)length)
|
2006-10-20 13:38:48 +02:00
|
|
|
|
return 0; /* Too short. */
|
|
|
|
|
|
|
|
|
|
rc = ksba_reader_new (&reader);
|
|
|
|
|
if (rc)
|
|
|
|
|
return 0; /* Problem with ksba. */
|
|
|
|
|
rc = ksba_reader_set_mem (reader, buffer+cert_off, cert_len);
|
|
|
|
|
if (rc)
|
|
|
|
|
goto failed;
|
|
|
|
|
rc = ksba_cert_new (&cert);
|
|
|
|
|
if (rc)
|
|
|
|
|
goto failed;
|
|
|
|
|
rc = ksba_cert_read_der (cert, reader);
|
|
|
|
|
if (rc)
|
|
|
|
|
goto failed;
|
|
|
|
|
p = ksba_cert_get_public_key (cert);
|
|
|
|
|
if (!p)
|
|
|
|
|
goto failed;
|
|
|
|
|
n = gcry_sexp_canon_len (p, 0, NULL, NULL);
|
|
|
|
|
if (!n)
|
|
|
|
|
goto failed;
|
|
|
|
|
rc = gcry_sexp_sscan (&s_pkey, NULL, (char*)p, n);
|
|
|
|
|
if (rc)
|
|
|
|
|
{
|
|
|
|
|
gcry_sexp_release (s_pkey);
|
|
|
|
|
goto failed;
|
|
|
|
|
}
|
|
|
|
|
rcp = gcry_pk_get_keygrip (s_pkey, array);
|
|
|
|
|
gcry_sexp_release (s_pkey);
|
|
|
|
|
if (!rcp)
|
|
|
|
|
goto failed; /* Can't calculate keygrip. */
|
|
|
|
|
|
|
|
|
|
xfree (p);
|
|
|
|
|
ksba_cert_release (cert);
|
|
|
|
|
ksba_reader_release (reader);
|
|
|
|
|
return !memcmp (array, grip, 20);
|
|
|
|
|
failed:
|
|
|
|
|
xfree (p);
|
|
|
|
|
ksba_cert_release (cert);
|
|
|
|
|
ksba_reader_release (reader);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
#endif /*KEYBOX_WITH_X509*/
|
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2011-02-04 12:57:53 +01:00
|
|
|
|
The has_foo functions are used as helpers for search
|
2003-06-05 09:14:21 +02:00
|
|
|
|
*/
|
2004-04-26 10:09:25 +02:00
|
|
|
|
static inline int
|
2009-12-08 17:30:33 +01:00
|
|
|
|
has_short_kid (KEYBOXBLOB blob, u32 lkid)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2020-08-06 12:24:49 +02:00
|
|
|
|
size_t length;
|
2009-12-08 17:30:33 +01:00
|
|
|
|
unsigned char buf[4];
|
2020-08-06 12:24:49 +02:00
|
|
|
|
|
2024-04-08 20:32:47 +02:00
|
|
|
|
_keybox_get_blob_image (blob, &length);
|
2020-08-06 12:24:49 +02:00
|
|
|
|
if (length < 48)
|
|
|
|
|
return 0; /* blob too short */
|
|
|
|
|
|
2009-12-08 17:30:33 +01:00
|
|
|
|
buf[0] = lkid >> 24;
|
|
|
|
|
buf[1] = lkid >> 16;
|
|
|
|
|
buf[2] = lkid >> 8;
|
|
|
|
|
buf[3] = lkid;
|
2020-08-06 12:24:49 +02:00
|
|
|
|
|
2024-04-08 20:32:47 +02:00
|
|
|
|
return blob_cmp_fpr_part (blob, buf, 16, 4);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2004-04-26 10:09:25 +02:00
|
|
|
|
static inline int
|
2009-12-08 17:30:33 +01:00
|
|
|
|
has_long_kid (KEYBOXBLOB blob, u32 mkid, u32 lkid)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2020-08-06 12:24:49 +02:00
|
|
|
|
size_t length;
|
2009-12-08 17:30:33 +01:00
|
|
|
|
unsigned char buf[8];
|
2020-08-06 12:24:49 +02:00
|
|
|
|
|
2024-04-08 20:32:47 +02:00
|
|
|
|
_keybox_get_blob_image (blob, &length);
|
2020-08-06 12:24:49 +02:00
|
|
|
|
if (length < 48)
|
|
|
|
|
return 0; /* blob too short */
|
|
|
|
|
|
2009-12-08 17:30:33 +01:00
|
|
|
|
buf[0] = mkid >> 24;
|
|
|
|
|
buf[1] = mkid >> 16;
|
|
|
|
|
buf[2] = mkid >> 8;
|
|
|
|
|
buf[3] = mkid;
|
|
|
|
|
buf[4] = lkid >> 24;
|
|
|
|
|
buf[5] = lkid >> 16;
|
|
|
|
|
buf[6] = lkid >> 8;
|
|
|
|
|
buf[7] = lkid;
|
2020-08-06 12:24:49 +02:00
|
|
|
|
|
2024-04-08 20:32:47 +02:00
|
|
|
|
return blob_cmp_fpr_part (blob, buf, 12, 8);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2004-04-26 10:09:25 +02:00
|
|
|
|
static inline int
|
2019-03-14 08:54:59 +01:00
|
|
|
|
has_fingerprint (KEYBOXBLOB blob, const unsigned char *fpr, unsigned int fprlen)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2019-03-14 08:54:59 +01:00
|
|
|
|
return blob_cmp_fpr (blob, fpr, fprlen);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2006-10-20 13:38:48 +02:00
|
|
|
|
static inline int
|
|
|
|
|
has_keygrip (KEYBOXBLOB blob, const unsigned char *grip)
|
|
|
|
|
{
|
2019-01-29 19:52:08 +01:00
|
|
|
|
if (blob_get_type (blob) == KEYBOX_BLOBTYPE_PGP)
|
|
|
|
|
return blob_openpgp_has_grip (blob, grip);
|
2006-10-20 13:38:48 +02:00
|
|
|
|
#ifdef KEYBOX_WITH_X509
|
2014-10-31 12:15:34 +01:00
|
|
|
|
if (blob_get_type (blob) == KEYBOX_BLOBTYPE_X509)
|
2006-10-20 13:38:48 +02:00
|
|
|
|
return blob_x509_has_grip (blob, grip);
|
|
|
|
|
#endif
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-28 09:39:35 +01:00
|
|
|
|
|
|
|
|
|
/* The UBID is the primary fingerprint. For OpenPGP v5 keys only the
|
|
|
|
|
* leftmost 20 bytes (UBID_LEN) are used. */
|
2019-09-27 09:24:58 +02:00
|
|
|
|
static inline int
|
|
|
|
|
has_ubid (KEYBOXBLOB blob, const unsigned char *ubid)
|
|
|
|
|
{
|
2019-11-28 09:39:35 +01:00
|
|
|
|
return blob_cmp_ubid (blob, ubid);
|
2019-09-27 09:24:58 +02:00
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2019-11-28 09:39:35 +01:00
|
|
|
|
|
2004-04-26 10:09:25 +02:00
|
|
|
|
static inline int
|
2003-06-05 09:14:21 +02:00
|
|
|
|
has_issuer (KEYBOXBLOB blob, const char *name)
|
|
|
|
|
{
|
|
|
|
|
size_t namelen;
|
|
|
|
|
|
|
|
|
|
return_val_if_fail (name, 0);
|
|
|
|
|
|
2014-10-31 12:15:34 +01:00
|
|
|
|
if (blob_get_type (blob) != KEYBOX_BLOBTYPE_X509)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
namelen = strlen (name);
|
2013-01-07 15:41:10 +01:00
|
|
|
|
return blob_cmp_name (blob, 0 /* issuer */, name, namelen, 0, 1);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2004-04-26 10:09:25 +02:00
|
|
|
|
static inline int
|
2003-06-05 09:14:21 +02:00
|
|
|
|
has_issuer_sn (KEYBOXBLOB blob, const char *name,
|
|
|
|
|
const unsigned char *sn, int snlen)
|
|
|
|
|
{
|
|
|
|
|
size_t namelen;
|
|
|
|
|
|
|
|
|
|
return_val_if_fail (name, 0);
|
|
|
|
|
return_val_if_fail (sn, 0);
|
|
|
|
|
|
2014-10-31 12:15:34 +01:00
|
|
|
|
if (blob_get_type (blob) != KEYBOX_BLOBTYPE_X509)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
namelen = strlen (name);
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
return (blob_cmp_sn (blob, sn, snlen)
|
2013-01-07 15:41:10 +01:00
|
|
|
|
&& blob_cmp_name (blob, 0 /* issuer */, name, namelen, 0, 1));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2004-04-26 10:09:25 +02:00
|
|
|
|
static inline int
|
2003-06-05 09:14:21 +02:00
|
|
|
|
has_sn (KEYBOXBLOB blob, const unsigned char *sn, int snlen)
|
|
|
|
|
{
|
|
|
|
|
return_val_if_fail (sn, 0);
|
|
|
|
|
|
2014-10-31 12:15:34 +01:00
|
|
|
|
if (blob_get_type (blob) != KEYBOX_BLOBTYPE_X509)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
return 0;
|
|
|
|
|
return blob_cmp_sn (blob, sn, snlen);
|
|
|
|
|
}
|
|
|
|
|
|
2004-04-26 10:09:25 +02:00
|
|
|
|
static inline int
|
2003-06-05 09:14:21 +02:00
|
|
|
|
has_subject (KEYBOXBLOB blob, const char *name)
|
|
|
|
|
{
|
|
|
|
|
size_t namelen;
|
|
|
|
|
|
|
|
|
|
return_val_if_fail (name, 0);
|
|
|
|
|
|
2014-10-31 12:15:34 +01:00
|
|
|
|
if (blob_get_type (blob) != KEYBOX_BLOBTYPE_X509)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
namelen = strlen (name);
|
2013-01-07 15:41:10 +01:00
|
|
|
|
return blob_cmp_name (blob, 1 /* subject */, name, namelen, 0, 1);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2013-01-07 15:41:10 +01:00
|
|
|
|
|
2004-04-26 10:09:25 +02:00
|
|
|
|
static inline int
|
2013-01-07 15:41:10 +01:00
|
|
|
|
has_username (KEYBOXBLOB blob, const char *name, int substr)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
size_t namelen;
|
2013-01-07 15:41:10 +01:00
|
|
|
|
int btype;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
|
|
|
|
return_val_if_fail (name, 0);
|
|
|
|
|
|
2013-01-07 15:41:10 +01:00
|
|
|
|
btype = blob_get_type (blob);
|
2014-10-31 12:15:34 +01:00
|
|
|
|
if (btype != KEYBOX_BLOBTYPE_PGP && btype != KEYBOX_BLOBTYPE_X509)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
namelen = strlen (name);
|
2013-01-07 15:41:10 +01:00
|
|
|
|
return blob_cmp_name (blob, -1 /* all subject/user names */, name,
|
2014-10-31 12:15:34 +01:00
|
|
|
|
namelen, substr, (btype == KEYBOX_BLOBTYPE_X509));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2004-04-26 10:09:25 +02:00
|
|
|
|
static inline int
|
2003-06-05 09:14:21 +02:00
|
|
|
|
has_mail (KEYBOXBLOB blob, const char *name, int substr)
|
|
|
|
|
{
|
|
|
|
|
size_t namelen;
|
2013-01-07 15:41:10 +01:00
|
|
|
|
int btype;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
|
|
|
|
return_val_if_fail (name, 0);
|
|
|
|
|
|
2013-01-07 15:41:10 +01:00
|
|
|
|
btype = blob_get_type (blob);
|
2014-10-31 12:15:34 +01:00
|
|
|
|
if (btype != KEYBOX_BLOBTYPE_PGP && btype != KEYBOX_BLOBTYPE_X509)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
return 0;
|
|
|
|
|
|
2014-10-31 12:15:34 +01:00
|
|
|
|
if (btype == KEYBOX_BLOBTYPE_PGP && *name == '<')
|
2013-01-07 15:41:10 +01:00
|
|
|
|
name++; /* Hack to remove the leading '<' for gpg. */
|
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
namelen = strlen (name);
|
|
|
|
|
if (namelen && name[namelen-1] == '>')
|
|
|
|
|
namelen--;
|
2014-10-31 12:15:34 +01:00
|
|
|
|
return blob_cmp_mail (blob, name, namelen, substr,
|
|
|
|
|
(btype == KEYBOX_BLOBTYPE_X509));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
release_sn_array (struct sn_array_s *array, size_t size)
|
|
|
|
|
{
|
|
|
|
|
size_t n;
|
|
|
|
|
|
|
|
|
|
for (n=0; n < size; n++)
|
|
|
|
|
xfree (array[n].sn);
|
|
|
|
|
xfree (array);
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-01 11:10:47 +02:00
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
|
|
|
|
/*
|
2023-05-05 11:37:44 +02:00
|
|
|
|
*
|
|
|
|
|
* The search API
|
|
|
|
|
*
|
|
|
|
|
*/
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2016-01-13 15:08:42 +01:00
|
|
|
|
gpg_error_t
|
2003-06-05 09:14:21 +02:00
|
|
|
|
keybox_search_reset (KEYBOX_HANDLE hd)
|
|
|
|
|
{
|
|
|
|
|
if (!hd)
|
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
|
|
|
|
|
|
|
|
|
if (hd->found.blob)
|
|
|
|
|
{
|
|
|
|
|
_keybox_release_blob (hd->found.blob);
|
|
|
|
|
hd->found.blob = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (hd->fp)
|
|
|
|
|
{
|
2020-10-20 11:52:16 +02:00
|
|
|
|
if (es_fseeko (hd->fp, 0, SEEK_SET))
|
2017-03-31 20:44:05 +02:00
|
|
|
|
{
|
|
|
|
|
/* Ooops. Seek did not work. Close so that the search will
|
|
|
|
|
* open the file again. */
|
2023-05-05 11:37:44 +02:00
|
|
|
|
_keybox_ll_close (hd->fp);
|
2017-03-31 20:44:05 +02:00
|
|
|
|
hd->fp = NULL;
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
hd->error = 0;
|
|
|
|
|
hd->eof = 0;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
return 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Note: When in ephemeral mode the search function does visit all
|
2014-10-09 21:01:49 +02:00
|
|
|
|
blobs but in standard mode, blobs flagged as ephemeral are ignored.
|
2014-10-31 12:15:34 +01:00
|
|
|
|
If WANT_BLOBTYPE is not 0 only blobs of this type are considered.
|
2014-10-09 21:01:49 +02:00
|
|
|
|
The value at R_SKIPPED is updated by the number of skipped long
|
|
|
|
|
records (counts PGP and X.509). */
|
2016-01-13 15:08:42 +01:00
|
|
|
|
gpg_error_t
|
2014-05-14 16:32:49 +02:00
|
|
|
|
keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc,
|
2014-10-31 12:15:34 +01:00
|
|
|
|
keybox_blobtype_t want_blobtype,
|
2014-10-09 21:01:49 +02:00
|
|
|
|
size_t *r_descindex, unsigned long *r_skipped)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2016-01-13 15:08:42 +01:00
|
|
|
|
gpg_error_t rc;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
size_t n;
|
|
|
|
|
int need_words, any_skip;
|
|
|
|
|
KEYBOXBLOB blob = NULL;
|
|
|
|
|
struct sn_array_s *sn_array = NULL;
|
2013-01-07 21:14:52 +01:00
|
|
|
|
int pk_no, uid_no;
|
2019-05-14 19:05:58 +02:00
|
|
|
|
off_t lastfoundoff;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
|
|
|
|
if (!hd)
|
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
|
|
|
|
|
Spelling cleanup.
No functional changes, just fixing minor spelling issues.
---
Most of these were identified from the command line by running:
codespell \
--ignore-words-list fpr,stati,keyserver,keyservers,asign,cas,iff,ifset \
--skip '*.po,ChangeLog*,help.*.txt,*.jpg,*.eps,*.pdf,*.png,*.gpg,*.asc' \
doc g13 g10 kbx agent artwork scd tests tools am common dirmngr sm \
NEWS README README.maint TODO
Signed-off-by: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
2020-02-18 15:34:42 +01:00
|
|
|
|
/* Clear last found result but record the offset of the last found
|
2019-05-14 19:05:58 +02:00
|
|
|
|
* blob which we may need later. */
|
2003-06-05 09:14:21 +02:00
|
|
|
|
if (hd->found.blob)
|
|
|
|
|
{
|
2019-05-14 19:05:58 +02:00
|
|
|
|
lastfoundoff = _keybox_get_blob_fileoffset (hd->found.blob);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
_keybox_release_blob (hd->found.blob);
|
|
|
|
|
hd->found.blob = NULL;
|
|
|
|
|
}
|
2019-05-14 19:05:58 +02:00
|
|
|
|
else
|
|
|
|
|
lastfoundoff = 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if (hd->error)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
return hd->error; /* still in error state */
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if (hd->eof)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
return -1; /* still EOF */
|
|
|
|
|
|
|
|
|
|
/* figure out what information we need */
|
|
|
|
|
need_words = any_skip = 0;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
for (n=0; n < ndesc; n++)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2011-02-04 12:57:53 +01:00
|
|
|
|
switch (desc[n].mode)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2011-02-04 12:57:53 +01:00
|
|
|
|
case KEYDB_SEARCH_MODE_WORDS:
|
2003-06-05 09:14:21 +02:00
|
|
|
|
need_words = 1;
|
|
|
|
|
break;
|
|
|
|
|
case KEYDB_SEARCH_MODE_FIRST:
|
|
|
|
|
/* always restart the search in this mode */
|
|
|
|
|
keybox_search_reset (hd);
|
2019-05-14 19:05:58 +02:00
|
|
|
|
lastfoundoff = 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
if (desc[n].skipfnc)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
any_skip = 1;
|
2020-09-08 10:05:08 +02:00
|
|
|
|
if (desc[n].snhex && !sn_array)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
sn_array = xtrycalloc (ndesc, sizeof *sn_array);
|
|
|
|
|
if (!sn_array)
|
2008-05-06 16:03:36 +02:00
|
|
|
|
return (hd->error = gpg_error_from_syserror ());
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-06-24 16:03:09 +02:00
|
|
|
|
(void)need_words; /* Not yet implemented. */
|
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
if (!hd->fp)
|
|
|
|
|
{
|
2023-05-05 11:37:44 +02:00
|
|
|
|
rc = _keybox_ll_open (&hd->fp, hd->kb->fname, 0);
|
2017-04-01 11:10:47 +02:00
|
|
|
|
if (rc)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
xfree (sn_array);
|
2017-04-01 11:10:47 +02:00
|
|
|
|
return rc;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2019-05-14 19:05:58 +02:00
|
|
|
|
/* log_debug ("%s: re-opened file\n", __func__); */
|
2019-05-16 13:57:04 +02:00
|
|
|
|
if (ndesc && desc[0].mode != KEYDB_SEARCH_MODE_FIRST && lastfoundoff)
|
2019-05-14 19:05:58 +02:00
|
|
|
|
{
|
2019-05-16 13:57:04 +02:00
|
|
|
|
/* Search mode is not first and the last search operation
|
2019-05-14 19:05:58 +02:00
|
|
|
|
* returned a blob which also was not the first one. We now
|
|
|
|
|
* need to skip over that blob and hope that the file has
|
|
|
|
|
* not changed. */
|
2020-10-20 11:52:16 +02:00
|
|
|
|
if (es_fseeko (hd->fp, lastfoundoff, SEEK_SET))
|
2019-05-14 19:05:58 +02:00
|
|
|
|
{
|
|
|
|
|
rc = gpg_error_from_syserror ();
|
|
|
|
|
log_debug ("%s: seeking to last found offset failed: %s\n",
|
|
|
|
|
__func__, gpg_strerror (rc));
|
|
|
|
|
xfree (sn_array);
|
|
|
|
|
return gpg_error (GPG_ERR_NOTHING_FOUND);
|
|
|
|
|
}
|
|
|
|
|
/* log_debug ("%s: re-opened file and sought to last offset\n", */
|
|
|
|
|
/* __func__); */
|
|
|
|
|
rc = _keybox_read_blob (NULL, hd->fp, NULL);
|
|
|
|
|
if (rc)
|
|
|
|
|
{
|
|
|
|
|
log_debug ("%s: skipping last found blob failed: %s\n",
|
|
|
|
|
__func__, gpg_strerror (rc));
|
|
|
|
|
xfree (sn_array);
|
|
|
|
|
return gpg_error (GPG_ERR_NOTHING_FOUND);
|
|
|
|
|
}
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2008-04-01 17:08:57 +02:00
|
|
|
|
/* Kludge: We need to convert an SN given as hexstring to its binary
|
|
|
|
|
representation - in some cases we are not able to store it in the
|
|
|
|
|
search descriptor, because due to the way we use it, it is not
|
|
|
|
|
possible to free allocated memory. */
|
2003-06-05 09:14:21 +02:00
|
|
|
|
if (sn_array)
|
|
|
|
|
{
|
|
|
|
|
const unsigned char *s;
|
|
|
|
|
int i, odd;
|
|
|
|
|
size_t snlen;
|
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
for (n=0; n < ndesc; n++)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
if (!desc[n].sn)
|
|
|
|
|
;
|
2020-09-08 10:05:08 +02:00
|
|
|
|
else if (desc[n].snhex)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
unsigned char *sn;
|
|
|
|
|
|
|
|
|
|
s = desc[n].sn;
|
2020-09-08 10:05:08 +02:00
|
|
|
|
for (i=0; *s && *s != '/' && i < desc[n].snlen; s++, i++)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
;
|
|
|
|
|
odd = (i & 1);
|
|
|
|
|
snlen = (i+1)/2;
|
|
|
|
|
sn_array[n].sn = xtrymalloc (snlen);
|
|
|
|
|
if (!sn_array[n].sn)
|
|
|
|
|
{
|
2008-05-06 16:03:36 +02:00
|
|
|
|
hd->error = gpg_error_from_syserror ();
|
2003-06-05 09:14:21 +02:00
|
|
|
|
release_sn_array (sn_array, n);
|
|
|
|
|
return hd->error;
|
|
|
|
|
}
|
|
|
|
|
sn_array[n].snlen = snlen;
|
|
|
|
|
sn = sn_array[n].sn;
|
|
|
|
|
s = desc[n].sn;
|
|
|
|
|
if (odd)
|
|
|
|
|
{
|
|
|
|
|
*sn++ = xtoi_1 (s);
|
|
|
|
|
s++;
|
|
|
|
|
}
|
|
|
|
|
for (; *s && *s != '/'; s += 2)
|
|
|
|
|
*sn++ = xtoi_2 (s);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
const unsigned char *sn;
|
|
|
|
|
|
|
|
|
|
sn = desc[n].sn;
|
|
|
|
|
snlen = desc[n].snlen;
|
|
|
|
|
sn_array[n].sn = xtrymalloc (snlen);
|
|
|
|
|
if (!sn_array[n].sn)
|
|
|
|
|
{
|
2008-05-06 16:03:36 +02:00
|
|
|
|
hd->error = gpg_error_from_syserror ();
|
2003-06-05 09:14:21 +02:00
|
|
|
|
release_sn_array (sn_array, n);
|
|
|
|
|
return hd->error;
|
|
|
|
|
}
|
|
|
|
|
sn_array[n].snlen = snlen;
|
|
|
|
|
memcpy (sn_array[n].sn, sn, snlen);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-01-07 21:14:52 +01:00
|
|
|
|
pk_no = uid_no = 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
for (;;)
|
|
|
|
|
{
|
|
|
|
|
unsigned int blobflags;
|
2014-10-31 12:15:34 +01:00
|
|
|
|
int blobtype;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
|
|
|
|
_keybox_release_blob (blob); blob = NULL;
|
2017-04-01 11:10:47 +02:00
|
|
|
|
rc = _keybox_read_blob (&blob, hd->fp, NULL);
|
2014-10-09 21:01:49 +02:00
|
|
|
|
if (gpg_err_code (rc) == GPG_ERR_TOO_LARGE
|
|
|
|
|
&& gpg_err_source (rc) == GPG_ERR_SOURCE_KEYBOX)
|
|
|
|
|
{
|
|
|
|
|
++*r_skipped;
|
|
|
|
|
continue; /* Skip too large records. */
|
|
|
|
|
}
|
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
if (rc)
|
|
|
|
|
break;
|
|
|
|
|
|
2014-10-31 12:15:34 +01:00
|
|
|
|
blobtype = blob_get_type (blob);
|
|
|
|
|
if (blobtype == KEYBOX_BLOBTYPE_HEADER)
|
|
|
|
|
continue;
|
|
|
|
|
if (want_blobtype && blobtype != want_blobtype)
|
2004-04-26 10:09:25 +02:00
|
|
|
|
continue;
|
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
blobflags = blob_get_blob_flags (blob);
|
|
|
|
|
if (!hd->ephemeral && (blobflags & 2))
|
2007-03-20 17:57:40 +01:00
|
|
|
|
continue; /* Not in ephemeral mode but blob is flagged ephemeral. */
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2011-02-04 12:57:53 +01:00
|
|
|
|
for (n=0; n < ndesc; n++)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
switch (desc[n].mode)
|
|
|
|
|
{
|
2011-02-04 12:57:53 +01:00
|
|
|
|
case KEYDB_SEARCH_MODE_NONE:
|
2003-06-05 09:14:21 +02:00
|
|
|
|
never_reached ();
|
|
|
|
|
break;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
case KEYDB_SEARCH_MODE_EXACT:
|
2013-01-07 21:14:52 +01:00
|
|
|
|
uid_no = has_username (blob, desc[n].u.name, 0);
|
|
|
|
|
if (uid_no)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
goto found;
|
|
|
|
|
break;
|
|
|
|
|
case KEYDB_SEARCH_MODE_MAIL:
|
2013-01-07 21:14:52 +01:00
|
|
|
|
uid_no = has_mail (blob, desc[n].u.name, 0);
|
|
|
|
|
if (uid_no)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
goto found;
|
|
|
|
|
break;
|
|
|
|
|
case KEYDB_SEARCH_MODE_MAILSUB:
|
2013-01-07 21:14:52 +01:00
|
|
|
|
uid_no = has_mail (blob, desc[n].u.name, 1);
|
|
|
|
|
if (uid_no)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
goto found;
|
|
|
|
|
break;
|
|
|
|
|
case KEYDB_SEARCH_MODE_SUBSTR:
|
2013-01-07 21:14:52 +01:00
|
|
|
|
uid_no = has_username (blob, desc[n].u.name, 1);
|
|
|
|
|
if (uid_no)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
goto found;
|
|
|
|
|
break;
|
|
|
|
|
case KEYDB_SEARCH_MODE_MAILEND:
|
2011-02-04 12:57:53 +01:00
|
|
|
|
case KEYDB_SEARCH_MODE_WORDS:
|
2014-11-07 18:42:37 +01:00
|
|
|
|
/* not yet implemented */
|
2003-06-05 09:14:21 +02:00
|
|
|
|
break;
|
|
|
|
|
case KEYDB_SEARCH_MODE_ISSUER:
|
|
|
|
|
if (has_issuer (blob, desc[n].u.name))
|
|
|
|
|
goto found;
|
|
|
|
|
break;
|
|
|
|
|
case KEYDB_SEARCH_MODE_ISSUER_SN:
|
|
|
|
|
if (has_issuer_sn (blob, desc[n].u.name,
|
|
|
|
|
sn_array? sn_array[n].sn : desc[n].sn,
|
|
|
|
|
sn_array? sn_array[n].snlen : desc[n].snlen))
|
|
|
|
|
goto found;
|
|
|
|
|
break;
|
|
|
|
|
case KEYDB_SEARCH_MODE_SN:
|
|
|
|
|
if (has_sn (blob, sn_array? sn_array[n].sn : desc[n].sn,
|
|
|
|
|
sn_array? sn_array[n].snlen : desc[n].snlen))
|
|
|
|
|
goto found;
|
|
|
|
|
break;
|
|
|
|
|
case KEYDB_SEARCH_MODE_SUBJECT:
|
|
|
|
|
if (has_subject (blob, desc[n].u.name))
|
|
|
|
|
goto found;
|
|
|
|
|
break;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
case KEYDB_SEARCH_MODE_SHORT_KID:
|
2013-01-07 21:14:52 +01:00
|
|
|
|
pk_no = has_short_kid (blob, desc[n].u.kid[1]);
|
|
|
|
|
if (pk_no)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
goto found;
|
|
|
|
|
break;
|
|
|
|
|
case KEYDB_SEARCH_MODE_LONG_KID:
|
2013-01-07 21:14:52 +01:00
|
|
|
|
pk_no = has_long_kid (blob, desc[n].u.kid[0], desc[n].u.kid[1]);
|
|
|
|
|
if (pk_no)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
goto found;
|
|
|
|
|
break;
|
2019-03-14 08:54:59 +01:00
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
case KEYDB_SEARCH_MODE_FPR:
|
2019-03-14 08:54:59 +01:00
|
|
|
|
pk_no = has_fingerprint (blob, desc[n].u.fpr, desc[n].fprlen);
|
|
|
|
|
if (pk_no)
|
|
|
|
|
goto found;
|
|
|
|
|
break;
|
|
|
|
|
|
2006-10-20 13:38:48 +02:00
|
|
|
|
case KEYDB_SEARCH_MODE_KEYGRIP:
|
|
|
|
|
if (has_keygrip (blob, desc[n].u.grip))
|
|
|
|
|
goto found;
|
|
|
|
|
break;
|
2019-09-27 09:24:58 +02:00
|
|
|
|
case KEYDB_SEARCH_MODE_UBID:
|
|
|
|
|
if (has_ubid (blob, desc[n].u.ubid))
|
|
|
|
|
goto found;
|
|
|
|
|
break;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
case KEYDB_SEARCH_MODE_FIRST:
|
2003-06-05 09:14:21 +02:00
|
|
|
|
goto found;
|
|
|
|
|
break;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
case KEYDB_SEARCH_MODE_NEXT:
|
2003-06-05 09:14:21 +02:00
|
|
|
|
goto found;
|
|
|
|
|
break;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
default:
|
2003-06-05 09:14:21 +02:00
|
|
|
|
rc = gpg_error (GPG_ERR_INV_VALUE);
|
|
|
|
|
goto found;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
continue;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
found:
|
2014-05-14 16:32:49 +02:00
|
|
|
|
/* Record which DESC we matched on. Note this value is only
|
|
|
|
|
meaningful if this function returns with no errors. */
|
|
|
|
|
if(r_descindex)
|
|
|
|
|
*r_descindex = n;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
for (n=any_skip?0:ndesc; n < ndesc; n++)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2015-01-16 16:56:35 +01:00
|
|
|
|
u32 kid[2];
|
|
|
|
|
|
|
|
|
|
if (desc[n].skipfnc
|
2015-01-19 14:58:06 +01:00
|
|
|
|
&& blob_get_first_keyid (blob, kid)
|
2015-09-14 11:27:43 +02:00
|
|
|
|
&& desc[n].skipfnc (desc[n].skipfncvalue, kid, uid_no))
|
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
if (n == ndesc)
|
|
|
|
|
break; /* got it */
|
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
if (!rc)
|
|
|
|
|
{
|
|
|
|
|
hd->found.blob = blob;
|
2013-01-07 21:14:52 +01:00
|
|
|
|
hd->found.pk_no = pk_no;
|
|
|
|
|
hd->found.uid_no = uid_no;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2016-01-13 15:08:42 +01:00
|
|
|
|
else if (rc == -1 || gpg_err_code (rc) == GPG_ERR_EOF)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
_keybox_release_blob (blob);
|
|
|
|
|
hd->eof = 1;
|
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
else
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
_keybox_release_blob (blob);
|
|
|
|
|
hd->error = rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sn_array)
|
|
|
|
|
release_sn_array (sn_array, ndesc);
|
|
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2019-11-28 09:39:35 +01:00
|
|
|
|
* Functions to return a certificate or a keyblock. To be used after
|
|
|
|
|
* a successful search operation.
|
|
|
|
|
*/
|
2012-12-28 14:03:16 +01:00
|
|
|
|
|
2019-08-06 16:07:33 +02:00
|
|
|
|
/* Return the raw data from the last found blob. Caller must release
|
|
|
|
|
* the value stored at R_BUFFER. If called with NULL for R_BUFFER
|
|
|
|
|
* only the needed length for the buffer and the public key type is
|
2019-11-28 09:39:35 +01:00
|
|
|
|
* returned. R_PUBKEY_TYPE and R_UBID can be used to return these
|
|
|
|
|
* attributes. */
|
2019-08-06 16:07:33 +02:00
|
|
|
|
gpg_error_t
|
|
|
|
|
keybox_get_data (KEYBOX_HANDLE hd, void **r_buffer, size_t *r_length,
|
2019-11-28 09:39:35 +01:00
|
|
|
|
enum pubkey_types *r_pubkey_type, unsigned char *r_ubid)
|
2019-08-06 16:07:33 +02:00
|
|
|
|
{
|
|
|
|
|
const unsigned char *buffer;
|
|
|
|
|
size_t length;
|
|
|
|
|
size_t image_off, image_len;
|
|
|
|
|
|
|
|
|
|
if (r_buffer)
|
|
|
|
|
*r_buffer = NULL;
|
|
|
|
|
if (r_length)
|
|
|
|
|
*r_length = 0;
|
|
|
|
|
if (r_pubkey_type)
|
|
|
|
|
*r_pubkey_type = PUBKEY_TYPE_UNKNOWN;
|
|
|
|
|
|
|
|
|
|
if (!hd)
|
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
|
|
|
|
if (!hd->found.blob)
|
|
|
|
|
return gpg_error (GPG_ERR_NOTHING_FOUND);
|
|
|
|
|
|
|
|
|
|
switch (blob_get_type (hd->found.blob))
|
|
|
|
|
{
|
|
|
|
|
case KEYBOX_BLOBTYPE_PGP:
|
|
|
|
|
if (r_pubkey_type)
|
|
|
|
|
*r_pubkey_type = PUBKEY_TYPE_OPGP;
|
|
|
|
|
break;
|
|
|
|
|
case KEYBOX_BLOBTYPE_X509:
|
|
|
|
|
if (r_pubkey_type)
|
|
|
|
|
*r_pubkey_type = PUBKEY_TYPE_X509;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return gpg_error (GPG_ERR_WRONG_BLOB_TYPE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
buffer = _keybox_get_blob_image (hd->found.blob, &length);
|
|
|
|
|
if (length < 40)
|
|
|
|
|
return gpg_error (GPG_ERR_TOO_SHORT);
|
|
|
|
|
image_off = get32 (buffer+8);
|
|
|
|
|
image_len = get32 (buffer+12);
|
|
|
|
|
if ((uint64_t)image_off+(uint64_t)image_len > (uint64_t)length)
|
|
|
|
|
return gpg_error (GPG_ERR_TOO_SHORT);
|
|
|
|
|
|
2019-11-28 09:39:35 +01:00
|
|
|
|
if (r_ubid)
|
|
|
|
|
{
|
|
|
|
|
size_t keyinfolen;
|
|
|
|
|
|
|
|
|
|
/* We do a quick but sufficient consistency check. For the full
|
|
|
|
|
* check see blob_cmp_ubid. */
|
|
|
|
|
if (!get16 (buffer + 16) /* No keys. */
|
|
|
|
|
|| (keyinfolen = get16 (buffer + 18)) < 28
|
|
|
|
|
|| (20 + (uint64_t)keyinfolen) > (uint64_t)length)
|
|
|
|
|
return gpg_error (GPG_ERR_TOO_SHORT);
|
|
|
|
|
|
|
|
|
|
memcpy (r_ubid, buffer + 20, UBID_LEN);
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-06 16:07:33 +02:00
|
|
|
|
if (r_length)
|
|
|
|
|
*r_length = image_len;
|
|
|
|
|
if (r_buffer)
|
|
|
|
|
{
|
|
|
|
|
*r_buffer = xtrymalloc (image_len);
|
|
|
|
|
if (!*r_buffer)
|
|
|
|
|
return gpg_error_from_syserror ();
|
|
|
|
|
memcpy (*r_buffer, buffer + image_off, image_len);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-28 14:03:16 +01:00
|
|
|
|
|
|
|
|
|
/* Return the last found keyblock. Returns 0 on success and stores a
|
2018-10-24 21:56:18 +02:00
|
|
|
|
* new iobuf at R_IOBUF. R_UID_NO and R_PK_NO are used to return the
|
2019-08-06 16:07:33 +02:00
|
|
|
|
* index of the key or user id which matched the search criteria; if
|
|
|
|
|
* not known they are set to 0. */
|
2012-12-28 14:03:16 +01:00
|
|
|
|
gpg_error_t
|
2013-01-07 21:14:52 +01:00
|
|
|
|
keybox_get_keyblock (KEYBOX_HANDLE hd, iobuf_t *r_iobuf,
|
2017-03-30 15:18:45 +02:00
|
|
|
|
int *r_pk_no, int *r_uid_no)
|
2012-12-28 14:03:16 +01:00
|
|
|
|
{
|
2012-12-28 17:17:56 +01:00
|
|
|
|
gpg_error_t err;
|
2017-03-30 15:18:45 +02:00
|
|
|
|
const unsigned char *buffer;
|
2012-12-28 14:03:16 +01:00
|
|
|
|
size_t length;
|
|
|
|
|
size_t image_off, image_len;
|
2012-12-28 17:17:56 +01:00
|
|
|
|
size_t siginfo_off, siginfo_len;
|
2012-12-28 14:03:16 +01:00
|
|
|
|
|
|
|
|
|
*r_iobuf = NULL;
|
|
|
|
|
|
|
|
|
|
if (!hd)
|
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
|
|
|
|
if (!hd->found.blob)
|
|
|
|
|
return gpg_error (GPG_ERR_NOTHING_FOUND);
|
|
|
|
|
|
2014-10-31 12:15:34 +01:00
|
|
|
|
if (blob_get_type (hd->found.blob) != KEYBOX_BLOBTYPE_PGP)
|
2012-12-28 14:03:16 +01:00
|
|
|
|
return gpg_error (GPG_ERR_WRONG_BLOB_TYPE);
|
|
|
|
|
|
|
|
|
|
buffer = _keybox_get_blob_image (hd->found.blob, &length);
|
|
|
|
|
if (length < 40)
|
|
|
|
|
return gpg_error (GPG_ERR_TOO_SHORT);
|
|
|
|
|
image_off = get32 (buffer+8);
|
|
|
|
|
image_len = get32 (buffer+12);
|
2018-02-15 11:17:28 +01:00
|
|
|
|
if ((uint64_t)image_off+(uint64_t)image_len > (uint64_t)length)
|
2012-12-28 14:03:16 +01:00
|
|
|
|
return gpg_error (GPG_ERR_TOO_SHORT);
|
|
|
|
|
|
2012-12-28 17:17:56 +01:00
|
|
|
|
err = _keybox_get_flag_location (buffer, length, KEYBOX_FLAG_SIG_INFO,
|
|
|
|
|
&siginfo_off, &siginfo_len);
|
|
|
|
|
if (err)
|
|
|
|
|
return err;
|
|
|
|
|
|
2013-01-07 21:14:52 +01:00
|
|
|
|
*r_pk_no = hd->found.pk_no;
|
|
|
|
|
*r_uid_no = hd->found.uid_no;
|
2012-12-28 14:03:16 +01:00
|
|
|
|
*r_iobuf = iobuf_temp_with_content (buffer+image_off, image_len);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
#ifdef KEYBOX_WITH_X509
|
|
|
|
|
/*
|
|
|
|
|
Return the last found cert. Caller must free it.
|
|
|
|
|
*/
|
|
|
|
|
int
|
2003-12-17 13:27:21 +01:00
|
|
|
|
keybox_get_cert (KEYBOX_HANDLE hd, ksba_cert_t *r_cert)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
const unsigned char *buffer;
|
|
|
|
|
size_t length;
|
|
|
|
|
size_t cert_off, cert_len;
|
2003-12-17 13:27:21 +01:00
|
|
|
|
ksba_reader_t reader = NULL;
|
|
|
|
|
ksba_cert_t cert = NULL;
|
2024-09-27 15:50:46 +02:00
|
|
|
|
unsigned int blobflags;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
if (!hd)
|
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
|
|
|
|
if (!hd->found.blob)
|
|
|
|
|
return gpg_error (GPG_ERR_NOTHING_FOUND);
|
|
|
|
|
|
2014-10-31 12:15:34 +01:00
|
|
|
|
if (blob_get_type (hd->found.blob) != KEYBOX_BLOBTYPE_X509)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
return gpg_error (GPG_ERR_WRONG_BLOB_TYPE);
|
|
|
|
|
|
|
|
|
|
buffer = _keybox_get_blob_image (hd->found.blob, &length);
|
|
|
|
|
if (length < 40)
|
|
|
|
|
return gpg_error (GPG_ERR_TOO_SHORT);
|
|
|
|
|
cert_off = get32 (buffer+8);
|
|
|
|
|
cert_len = get32 (buffer+12);
|
2018-02-15 11:17:28 +01:00
|
|
|
|
if ((uint64_t)cert_off+(uint64_t)cert_len > (uint64_t)length)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
return gpg_error (GPG_ERR_TOO_SHORT);
|
|
|
|
|
|
2003-11-12 16:17:44 +01:00
|
|
|
|
rc = ksba_reader_new (&reader);
|
|
|
|
|
if (rc)
|
|
|
|
|
return rc;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
rc = ksba_reader_set_mem (reader, buffer+cert_off, cert_len);
|
|
|
|
|
if (rc)
|
|
|
|
|
{
|
|
|
|
|
ksba_reader_release (reader);
|
|
|
|
|
/* fixme: need to map the error codes */
|
|
|
|
|
return gpg_error (GPG_ERR_GENERAL);
|
|
|
|
|
}
|
|
|
|
|
|
2003-11-12 16:17:44 +01:00
|
|
|
|
rc = ksba_cert_new (&cert);
|
|
|
|
|
if (rc)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
ksba_reader_release (reader);
|
2003-11-12 16:17:44 +01:00
|
|
|
|
return rc;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rc = ksba_cert_read_der (cert, reader);
|
|
|
|
|
if (rc)
|
|
|
|
|
{
|
|
|
|
|
ksba_cert_release (cert);
|
|
|
|
|
ksba_reader_release (reader);
|
|
|
|
|
/* fixme: need to map the error codes */
|
|
|
|
|
return gpg_error (GPG_ERR_GENERAL);
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-27 15:50:46 +02:00
|
|
|
|
rc = get_flag_from_image (buffer, length, KEYBOX_FLAG_BLOB, &blobflags);
|
|
|
|
|
if (!rc)
|
|
|
|
|
rc = ksba_cert_set_user_data (cert, "keydb.blobflags",
|
|
|
|
|
&blobflags, sizeof blobflags);
|
|
|
|
|
if (rc)
|
|
|
|
|
{
|
|
|
|
|
ksba_cert_release (cert);
|
|
|
|
|
ksba_reader_release (reader);
|
|
|
|
|
return gpg_error (rc);
|
|
|
|
|
}
|
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
*r_cert = cert;
|
|
|
|
|
ksba_reader_release (reader);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif /*KEYBOX_WITH_X509*/
|
2004-02-02 18:09:35 +01:00
|
|
|
|
|
2004-04-26 10:09:25 +02:00
|
|
|
|
/* Return the flags named WHAT at the address of VALUE. IDX is used
|
2004-02-02 18:09:35 +01:00
|
|
|
|
only for certain flags and should be 0 if not required. */
|
|
|
|
|
int
|
|
|
|
|
keybox_get_flags (KEYBOX_HANDLE hd, int what, int idx, unsigned int *value)
|
|
|
|
|
{
|
|
|
|
|
const unsigned char *buffer;
|
|
|
|
|
size_t length;
|
|
|
|
|
gpg_err_code_t ec;
|
|
|
|
|
|
2008-10-20 15:53:23 +02:00
|
|
|
|
(void)idx; /* Not yet used. */
|
|
|
|
|
|
2004-02-02 18:09:35 +01:00
|
|
|
|
if (!hd)
|
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
|
|
|
|
if (!hd->found.blob)
|
|
|
|
|
return gpg_error (GPG_ERR_NOTHING_FOUND);
|
|
|
|
|
|
|
|
|
|
buffer = _keybox_get_blob_image (hd->found.blob, &length);
|
|
|
|
|
ec = get_flag_from_image (buffer, length, what, value);
|
|
|
|
|
return ec? gpg_error (ec):0;
|
|
|
|
|
}
|
2015-12-15 12:21:30 +01:00
|
|
|
|
|
|
|
|
|
off_t
|
|
|
|
|
keybox_offset (KEYBOX_HANDLE hd)
|
|
|
|
|
{
|
|
|
|
|
if (!hd->fp)
|
|
|
|
|
return 0;
|
2020-10-20 11:52:16 +02:00
|
|
|
|
return es_ftello (hd->fp);
|
2015-12-15 12:21:30 +01:00
|
|
|
|
}
|
2015-12-15 13:09:27 +01:00
|
|
|
|
|
|
|
|
|
gpg_error_t
|
|
|
|
|
keybox_seek (KEYBOX_HANDLE hd, off_t offset)
|
|
|
|
|
{
|
2017-04-01 11:10:47 +02:00
|
|
|
|
gpg_error_t err;
|
2015-12-15 13:09:27 +01:00
|
|
|
|
|
|
|
|
|
if (hd->error)
|
|
|
|
|
return hd->error; /* still in error state */
|
|
|
|
|
|
|
|
|
|
if (! hd->fp)
|
|
|
|
|
{
|
2017-04-01 11:10:47 +02:00
|
|
|
|
if (!offset)
|
2015-12-15 13:09:27 +01:00
|
|
|
|
{
|
2017-04-01 11:10:47 +02:00
|
|
|
|
/* No need to open the file. An unopened file is effectively at
|
|
|
|
|
offset 0. */
|
|
|
|
|
return 0;
|
2015-12-15 13:09:27 +01:00
|
|
|
|
}
|
2017-04-01 11:10:47 +02:00
|
|
|
|
|
2023-05-05 11:37:44 +02:00
|
|
|
|
err = _keybox_ll_open (&hd->fp, hd->kb->fname, 0);
|
2017-04-01 11:10:47 +02:00
|
|
|
|
if (err)
|
|
|
|
|
return err;
|
2015-12-15 13:09:27 +01:00
|
|
|
|
}
|
|
|
|
|
|
2020-10-20 11:52:16 +02:00
|
|
|
|
err = es_fseeko (hd->fp, offset, SEEK_SET);
|
2015-12-15 13:09:27 +01:00
|
|
|
|
hd->error = gpg_error_from_errno (err);
|
|
|
|
|
|
|
|
|
|
return hd->error;
|
|
|
|
|
}
|