mirror of
git://git.gnupg.org/gnupg.git
synced 2025-07-02 22:46:30 +02:00
We have reached a state where we are able to import certs and
check the certification path.
This commit is contained in:
parent
6dec3847d8
commit
90d060c199
25 changed files with 2486 additions and 731 deletions
|
@ -25,134 +25,417 @@
|
|||
|
||||
#include "keybox-defs.h"
|
||||
|
||||
static ulong
|
||||
get32 (const byte *buffer)
|
||||
{
|
||||
ulong a;
|
||||
a = *buffer << 24;
|
||||
a |= buffer[1] << 16;
|
||||
a |= buffer[2] << 8;
|
||||
a |= buffer[3];
|
||||
return a;
|
||||
}
|
||||
|
||||
/****************
|
||||
* Check whether the given fingerprint (20 bytes) is in the
|
||||
* given keyblob. fpr is always 20 bytes.
|
||||
* Return: 0 = found
|
||||
* -1 = not found
|
||||
other = error (fixme: do not always reurn gpgerr_general)
|
||||
static ulong
|
||||
get16 (const byte *buffer)
|
||||
{
|
||||
ulong a;
|
||||
a = *buffer << 8;
|
||||
a |= buffer[1];
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int
|
||||
blob_get_type (KEYBOXBLOB blob)
|
||||
{
|
||||
const unsigned char *buffer;
|
||||
size_t length;
|
||||
|
||||
buffer = _keybox_get_blob_image (blob, &length);
|
||||
if (length < 40)
|
||||
return -1; /* blob too short */
|
||||
|
||||
return buffer[4];
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
blob_cmp_sn (KEYBOXBLOB blob, const unsigned char *sn)
|
||||
{
|
||||
size_t snlen;
|
||||
const unsigned char *buffer;
|
||||
size_t length;
|
||||
size_t pos, off;
|
||||
size_t nkeys, keyinfolen;
|
||||
size_t nserial;
|
||||
|
||||
snlen = (sn[0] << 24) | (sn[1] << 16) | (sn[2] << 8) | sn[3];
|
||||
sn += 4;
|
||||
|
||||
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*/
|
||||
nserial = get16 (buffer+pos);
|
||||
off = pos + 2;
|
||||
if (off+nserial > length)
|
||||
return 0; /* out of bounds */
|
||||
|
||||
return nserial == snlen && !memcmp (buffer+off, sn, snlen);
|
||||
}
|
||||
|
||||
static int
|
||||
blob_cmp_name (KEYBOXBLOB blob, int idx, const char *name, size_t namelen)
|
||||
{
|
||||
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;
|
||||
if (pos+2 > length)
|
||||
return 0; /* out of bounds */
|
||||
|
||||
/*serial*/
|
||||
nserial = get16 (buffer+pos);
|
||||
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 > 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 < 2)
|
||||
return 0; /* empty name or 0 not stored */
|
||||
len--;
|
||||
|
||||
return len == namelen && !memcmp (buffer+off, name, len);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
The has_foo functions are used as helpers for search
|
||||
*/
|
||||
#if 0
|
||||
static int
|
||||
has_short_kid (KEYBOXBLOB blob, u32 kid)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
has_long_kid (KEYBOXBLOB blob, u32 *kid)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
has_fingerprint (KEYBOXBLOB blob, const unsigned char *fpr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
has_issuer (KEYBOXBLOB blob, const char *name)
|
||||
{
|
||||
size_t namelen;
|
||||
|
||||
return_val_if_fail (name, 0);
|
||||
|
||||
if (blob_get_type (blob) != BLOBTYPE_X509)
|
||||
return 0;
|
||||
|
||||
namelen = strlen (name);
|
||||
return blob_cmp_name (blob, 0 /* issuer */, name, namelen);
|
||||
}
|
||||
|
||||
static int
|
||||
has_issuer_sn (KEYBOXBLOB blob, const char *name, const unsigned char *sn)
|
||||
{
|
||||
size_t namelen;
|
||||
|
||||
return_val_if_fail (name, 0);
|
||||
return_val_if_fail (sn, 0);
|
||||
|
||||
if (blob_get_type (blob) != BLOBTYPE_X509)
|
||||
return 0;
|
||||
|
||||
namelen = strlen (name);
|
||||
|
||||
return (blob_cmp_sn (blob, sn)
|
||||
&& blob_cmp_name (blob, 0 /* issuer */, name, namelen));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
The search API
|
||||
|
||||
*/
|
||||
|
||||
int
|
||||
keybox_search_reset (KEYBOX_HANDLE hd)
|
||||
{
|
||||
if (!hd)
|
||||
return KEYBOX_Invalid_Value;
|
||||
|
||||
if (hd->found.blob)
|
||||
{
|
||||
_keybox_release_blob (hd->found.blob);
|
||||
hd->found.blob = NULL;
|
||||
}
|
||||
|
||||
if (hd->fp)
|
||||
{
|
||||
fclose (hd->fp);
|
||||
hd->fp = NULL;
|
||||
}
|
||||
hd->error = 0;
|
||||
hd->eof = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc)
|
||||
{
|
||||
int rc;
|
||||
size_t n;
|
||||
int need_words, any_skip;
|
||||
KEYBOXBLOB blob = NULL;
|
||||
|
||||
if (!hd)
|
||||
return KEYBOX_Invalid_Value;
|
||||
|
||||
/* clear last found result */
|
||||
if (hd->found.blob)
|
||||
{
|
||||
_keybox_release_blob (hd->found.blob);
|
||||
hd->found.blob = NULL;
|
||||
}
|
||||
|
||||
if (hd->error)
|
||||
return hd->error; /* still in error state */
|
||||
if (hd->eof)
|
||||
return -1; /* still EOF */
|
||||
|
||||
/* figure out what information we need */
|
||||
need_words = any_skip = 0;
|
||||
for (n=0; n < ndesc; n++)
|
||||
{
|
||||
switch (desc[n].mode)
|
||||
{
|
||||
case KEYDB_SEARCH_MODE_WORDS:
|
||||
need_words = 1;
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_FIRST:
|
||||
/* always restart the search in this mode */
|
||||
keybox_search_reset (hd);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (desc[n].skipfnc)
|
||||
any_skip = 1;
|
||||
}
|
||||
|
||||
if (!hd->fp)
|
||||
{
|
||||
hd->fp = fopen (hd->kb->fname, "rb");
|
||||
if (!hd->fp)
|
||||
return (hd->error = KEYBOX_File_Open_Error);
|
||||
}
|
||||
|
||||
|
||||
for (;;)
|
||||
{
|
||||
_keybox_release_blob (blob); blob = NULL;
|
||||
rc = _keybox_read_blob (&blob, hd->fp);
|
||||
if (rc)
|
||||
break;
|
||||
|
||||
for (n=0; n < ndesc; n++)
|
||||
{
|
||||
switch (desc[n].mode)
|
||||
{
|
||||
case KEYDB_SEARCH_MODE_NONE:
|
||||
never_reached ();
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_EXACT:
|
||||
case KEYDB_SEARCH_MODE_SUBSTR:
|
||||
case KEYDB_SEARCH_MODE_MAIL:
|
||||
case KEYDB_SEARCH_MODE_MAILSUB:
|
||||
case KEYDB_SEARCH_MODE_MAILEND:
|
||||
case KEYDB_SEARCH_MODE_WORDS:
|
||||
never_reached (); /* not yet implemented */
|
||||
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, desc[n].sn))
|
||||
goto found;
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_SHORT_KID:
|
||||
/* if (has_short_kid (blob, desc[n].u.kid[1])) */
|
||||
/* goto found; */
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_LONG_KID:
|
||||
/* if (has_long_kid (blob, desc[n].u.kid)) */
|
||||
/* goto found; */
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_FPR:
|
||||
if (has_fingerprint (blob, desc[n].u.fpr))
|
||||
goto found;
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_FIRST:
|
||||
goto found;
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_NEXT:
|
||||
goto found;
|
||||
break;
|
||||
default:
|
||||
rc = KEYBOX_Invalid_Value;
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
found:
|
||||
for (n=any_skip?0:ndesc; n < ndesc; n++)
|
||||
{
|
||||
/* if (desc[n].skipfnc */
|
||||
/* && desc[n].skipfnc (desc[n].skipfncvalue, aki)) */
|
||||
/* break; */
|
||||
}
|
||||
if (n == ndesc)
|
||||
break; /* got it */
|
||||
}
|
||||
|
||||
if (!rc)
|
||||
{
|
||||
hd->found.blob = blob;
|
||||
}
|
||||
else if (rc == -1)
|
||||
{
|
||||
_keybox_release_blob (blob);
|
||||
hd->eof = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
_keybox_release_blob (blob);
|
||||
hd->error = rc;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Functions to return a certificate or a keyblock. To be used after
|
||||
a successful search operation.
|
||||
*/
|
||||
#ifdef KEYBOX_WITH_X509
|
||||
/*
|
||||
Return the last found cert. Caller must free it.
|
||||
*/
|
||||
int
|
||||
keybox_blob_has_fpr ( KEYBOXBLOB blob, const byte *fpr )
|
||||
keybox_get_cert (KEYBOX_HANDLE hd, KsbaCert *r_cert)
|
||||
{
|
||||
ulong n, nkeys, keyinfolen;
|
||||
const byte *p, *pend;
|
||||
byte *buffer = blob->blob;
|
||||
size_t buflen = blob->bloblen;
|
||||
const unsigned char *buffer;
|
||||
size_t length;
|
||||
size_t cert_off, cert_len;
|
||||
KsbaReader reader = NULL;
|
||||
KsbaCert cert = NULL;
|
||||
int rc;
|
||||
|
||||
if ( buflen < 40 )
|
||||
return GPGERR_GENERAL; /* blob too short */
|
||||
n = get32( buffer );
|
||||
if ( n > buflen )
|
||||
return GPGERR_GENERAL; /* blob larger than announced length */
|
||||
buflen = n; /* ignore trailing stuff */
|
||||
pend = buffer + n - 1;
|
||||
if (!hd)
|
||||
return KEYBOX_Invalid_Value;
|
||||
if (!hd->found.blob)
|
||||
return KEYBOX_Nothing_Found;
|
||||
|
||||
if ( buffer[4] != 2 )
|
||||
return GPGERR_GENERAL; /* invalid blob type */
|
||||
if ( buffer[5] != 1 )
|
||||
return GPGERR_GENERAL; /* invalid blob format version */
|
||||
if (blob_get_type (hd->found.blob) != BLOBTYPE_X509)
|
||||
return KEYBOX_Wrong_Blob_Type;
|
||||
|
||||
nkeys = get16( buffer + 16 );
|
||||
keyinfolen = get16( buffer + 18 );
|
||||
p = buffer + 20;
|
||||
for(n=0; n < nkeys; n++, p += keyinfolen ) {
|
||||
if ( p+20 > pend )
|
||||
return GPGERR_GENERAL; /* blob shorter than required */
|
||||
if (!memcmp ( p, fpr, 20 ) )
|
||||
return 0; /* found */
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
buffer = _keybox_get_blob_image (hd->found.blob, &length);
|
||||
if (length < 40)
|
||||
return KEYBOX_Blob_Too_Short;
|
||||
cert_off = get32 (buffer+8);
|
||||
cert_len = get32 (buffer+12);
|
||||
if (cert_off+cert_len > length)
|
||||
return KEYBOX_Blob_Too_Short;
|
||||
|
||||
/****************
|
||||
* Check whether the given keyID (20 bytes) is in the
|
||||
* given keyblob.
|
||||
* Return: 0 = found
|
||||
* -1 = not found
|
||||
other = error (fixme: do not always return gpgerr_general)
|
||||
*/
|
||||
int
|
||||
keybox_blob_has_kid ( KEYBOXBLOB blob, const byte *keyidbuf, size_t keyidlen )
|
||||
{
|
||||
ulong n, nkeys, keyinfolen, off;
|
||||
const byte *p, *pend;
|
||||
byte *buffer = blob->blob;
|
||||
size_t buflen = blob->bloblen;
|
||||
|
||||
if ( buflen < 40 )
|
||||
return GPGERR_GENERAL; /* blob too short */
|
||||
n = get32( buffer );
|
||||
if ( n > buflen )
|
||||
return GPGERR_GENERAL; /* blob larger than announced length */
|
||||
buflen = n; /* ignore trailing stuff */
|
||||
pend = buffer + n - 1;
|
||||
|
||||
if ( buffer[4] != 2 )
|
||||
return GPGERR_GENERAL; /* invalid blob type */
|
||||
if ( buffer[5] != 1 )
|
||||
return GPGERR_GENERAL; /* invalid blob format version */
|
||||
|
||||
nkeys = get16( buffer + 16 );
|
||||
keyinfolen = get16( buffer + 18 );
|
||||
p = buffer + 20;
|
||||
for(n=0; n < nkeys; n++, p += keyinfolen ) {
|
||||
if ( p+24 > pend )
|
||||
return GPGERR_GENERAL; /* blob shorter than required */
|
||||
off = get32 ( p + 20 );
|
||||
if (keyidlen < 8 ) /* actually keyidlen may either be 4 or 8 */
|
||||
off +=4;
|
||||
if ( off+keyidlen > buflen )
|
||||
return GPGERR_GENERAL; /* offset out of bounds */
|
||||
if ( !memcmp ( buffer+off, keyidbuf, keyidlen ) )
|
||||
return 0; /* found */
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
keybox_blob_has_uid ( KEYBOXBLOB blob,
|
||||
int (*cmp)(const byte *, size_t, void *), void *opaque )
|
||||
{
|
||||
ulong n, nuids, uidinfolen, off, len;
|
||||
const byte *p, *pend;
|
||||
byte *buffer = blob->blob;
|
||||
size_t buflen = blob->bloblen;
|
||||
|
||||
if ( buflen < 40 )
|
||||
return GPGERR_GENERAL; /* blob too short */
|
||||
n = get32( buffer );
|
||||
if ( n > buflen )
|
||||
return GPGERR_GENERAL; /* blob larger than announced length */
|
||||
buflen = n; /* ignore trailing stuff */
|
||||
pend = buffer + n - 1;
|
||||
|
||||
if ( buffer[4] != 2 )
|
||||
return GPGERR_GENERAL; /* invalid blob type */
|
||||
if ( buffer[5] != 1 )
|
||||
return GPGERR_GENERAL; /* invalid blob format version */
|
||||
|
||||
p = buffer + 20 + get16( buffer + 16 ) * get16( buffer + 18 );
|
||||
if ( p+4 > pend )
|
||||
return GPGERR_GENERAL; /* blob shorter than required */
|
||||
|
||||
nuids = get16( p ); p+= 2;
|
||||
uidinfolen = get16( p ); p+=2;
|
||||
for(n=0; n < nuids; n++, p += uidinfolen ) {
|
||||
if ( p+8 > pend )
|
||||
return GPGERR_GENERAL; /* blob shorter than required */
|
||||
off = get32 ( p );
|
||||
len = get32 ( p + 4 );
|
||||
if ( off+len > buflen )
|
||||
return GPGERR_GENERAL; /* offset out of bounds */
|
||||
if ( (*cmp) ( buffer+off, len, opaque ) )
|
||||
return 0; /* found */
|
||||
reader = ksba_reader_new ();
|
||||
if (!reader)
|
||||
return KEYBOX_Out_Of_Core;
|
||||
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 KEYBOX_General_Error;
|
||||
}
|
||||
|
||||
return -1;
|
||||
cert = ksba_cert_new ();
|
||||
if (!cert)
|
||||
{
|
||||
ksba_reader_release (reader);
|
||||
return KEYBOX_Out_Of_Core;
|
||||
}
|
||||
|
||||
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 KEYBOX_General_Error;
|
||||
}
|
||||
|
||||
*r_cert = cert;
|
||||
ksba_reader_release (reader);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#endif /*KEYBOX_WITH_X509*/
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue