Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F22947647
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
80 KB
Subscribers
None
View Options
diff --git a/kbx/ChangeLog b/kbx/ChangeLog
index b41305e3f..715acbdcf 100644
--- a/kbx/ChangeLog
+++ b/kbx/ChangeLog
@@ -1,76 +1,87 @@
+2002-06-19 Werner Koch <wk@gnupg.org>
+
+ * keybox-init.c (keybox_set_ephemeral): New.
+ * keybox-blob.c (create_blob_header): Store epheermal flag.
+ (_keybox_create_x509_blob): Pass epheermal flag on.
+ * keybox-update.c (keybox_insert_cert): Ditto.
+ * keybox-search.c (blob_get_blob_flags): New.
+ (keybox_search): Ignore ephemeral blobs when not in ephemeral mode.
+
+ * keybox-dump.c (_keybox_dump_blob): Print blob flags as strings.
+
2002-02-25 Werner Koch <wk@gnupg.org>
* keybox-search.c (blob_cmp_mail): Use case-insensitive compare
because mail addresses are in general case insensitive (well
RFC2822 allows for case sensitive mailbox parts, but this is in
general considired a Bad Thing). Add additional substr parameter
to allow for substring matches within the mail address. Change
all callers to pass this along.
(blob_cmp_name): Likewise but do the case-insensitive search only
in sub string mode.
(keybox_search): Implement MAILSUB and SUBSTR mode.
2002-01-21 Werner Koch <wk@gnupg.org>
* keybox-search.c (keybox_search): Allow KEYDB_SEARCH_MODE_FPR20.
2002-01-15 Werner Koch <wk@gnupg.org>
* keybox-search.c (blob_cmp_fpr): New.
(has_fingerprint): Implemented;
2001-12-20 Werner Koch <wk@gnupg.org>
* keybox-blob.c (_keybox_create_x509_blob): Skip the leading
parenthesis of the serial number's S-exp.
(_keybox_create_x509_blob): And fixed length calculation.
(create_blob_header): Don't add an offset when writing the serial.
2001-12-18 Werner Koch <wk@gnupg.org>
* Makefile.am (AM_CPPFLAGS): Add flags for libksba
* keybox-blob.c (_keybox_create_x509_blob): Use
gcry_sexp_canon_len to get the length of the serial number.
(_keybox_release_blob): Need to use a new serialbuf to free the memory.
2001-12-17 Werner Koch <wk@gnupg.org>
* keybox-search.c: Changed the way the serial number is
represented.
2001-12-15 Werner Koch <wk@gnupg.org>
* keybox-search.c (blob_cmp_name): There is no terminating 0 stored
for the uid; fixed length compare.
2001-12-14 Werner Koch <wk@gnupg.org>
* keybox-blob.c (x509_email_kludge): New.
(_keybox_create_x509_blob): Insert an extra email address if the
subject's DN has an email part.
* keybox-defs.h: Added the xtoi_2 and digitp macros.
2001-12-13 Werner Koch <wk@gnupg.org>
* keybox-search.c (blob_cmp_name): Kludge to allow searching for
more than one name.
(has_subject_or_alt): New.
(blob_cmp_mail): New.
(has_mail): New.
(keybox_search): Implemented exact search and exact mail search.
* kbx/keybox-blob.c (_keybox_create_x509_blob): Insert alternate
names.
Copyright 2001 g10 Code GmbH
This file is free software; as a special exception the author gives
unlimited permission to copy and/or distribute it, with or without
modifications, as long as this notice is preserved.
This file is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
\ No newline at end of file
diff --git a/kbx/keybox-blob.c b/kbx/keybox-blob.c
index 2c80a10ad..34e2c9712 100644
--- a/kbx/keybox-blob.c
+++ b/kbx/keybox-blob.c
@@ -1,997 +1,998 @@
/* keybox-blob.c - KBX Blob handling
- * Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+ * Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (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
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
/* The keybox data formats
The KeyBox uses an augmented OpenPGP/X.509 key format. This makes
random access to a keyblock/Certificate easier and also gives the
opportunity to store additional information (e.g. the fingerprint)
along with the key. All integers are stored in network byte order,
offsets are counted from the beginning of the Blob.
The first record of a plain KBX file has a special format:
u32 length of the first record
byte Blob type (1)
byte version number (1)
byte reserved
byte reserved
u32 magic 'KBXf'
byte pgp_marginals used for validity calculation of this file
byte pgp_completes ditto.
byte pgp_cert_depth ditto.
The OpenPGP and X.509 blob are verry similiar, things which are
X.509 specific are noted like [X.509: xxx]
u32 length of this blob (including these 4 bytes)
byte Blob type (2) [X509: 3]
byte version number of this blob type (1)
u16 Blob flags
bit 0 = contains secret key material
+ bit 1 = ephemeral blob (e.g. used while quering external resources)
u32 offset to the OpenPGP keyblock or X509 DER encoded certificate
- u32 ant its length
+ u32 and its length
u16 number of keys (at least 1!) [X509: always 1]
u16 size of additional key information
n times:
b20 The keys fingerprint
(fingerprints are always 20 bytes, MD5 left padded with zeroes)
u32 offset to the n-th key's keyID (a keyID is always 8 byte)
or 0 if not known which is the case opnly for X509.
u16 special key flags
bit 0 =
u16 reserved
u16 size of serialnumber(may be zero)
n u16 (see above) bytes of serial number
u16 number of user IDs
u16 size of additional user ID information
n times:
u32 offset to the n-th user ID
u32 length of this user ID.
u16 special user ID flags.
bit 0 =
byte validity
byte reserved
[For X509, the first user ID is the ISsuer, the second the subject
and the others are subjectAltNames]
u16 number of signatures
u16 size of signature information (4)
u32 expiration time of signature with some special values:
0x00000000 = not checked
0x00000001 = missing key
0x00000002 = bad signature
0x10000000 = valid and expires at some date in 1978.
0xffffffff = valid and does not expire
u8 assigned ownertrust [X509: no used]
u8 all_validity [X509: no used]
u16 reserved
u32 recheck_after
u32 Newest timestamp in the keyblock (useful for KS syncronsiation?)
u32 Blob created at
u32 size of reserved space (not including this field)
reserved space
Here we might want to put other data
Here comes the keyblock
maybe we put a signature here later.
b16 MD5 checksum (useful for KS syncronisation), we might also want to use
a mac here.
b4 resevered
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <gcrypt.h>
#ifdef KEYBOX_WITH_OPENPGP
/* include stuff to parse the packets */
#endif
#ifdef KEYBOX_WITH_X509
#include <ksba.h>
#endif
#include "keybox-defs.h"
/* special values of the signature status */
#define SF_NONE(a) ( !(a) )
#define SF_NOKEY(a) ((a) & (1<<0))
#define SF_BAD(a) ((a) & (1<<1))
#define SF_VALID(a) ((a) & (1<<29))
struct membuf {
size_t len;
size_t size;
char *buf;
int out_of_core;
};
/* #if MAX_FINGERPRINT_LEN < 20 */
/* #error fingerprints are 20 bytes */
/* #endif */
struct keyboxblob_key {
char fpr[20];
u32 off_kid;
ulong off_kid_addr;
u16 flags;
};
struct keyboxblob_uid {
ulong off_addr;
char *name; /* used only with x509 */
u32 len;
u16 flags;
byte validity;
};
struct keyid_list {
struct keyid_list *next;
int seqno;
byte kid[8];
};
struct fixup_list {
struct fixup_list *next;
u32 off;
u32 val;
};
struct keyboxblob {
byte *blob;
size_t bloblen;
/* stuff used only by keybox_create_blob */
unsigned char *serialbuf;
const unsigned char *serial;
size_t seriallen;
int nkeys;
struct keyboxblob_key *keys;
int nuids;
struct keyboxblob_uid *uids;
int nsigs;
u32 *sigs;
struct fixup_list *fixups;
int fixup_out_of_core;
struct keyid_list *temp_kids;
struct membuf bufbuf; /* temporary store for the blob */
struct membuf *buf;
};
/* A simple implemnation of a dynamic buffer. Use init_membuf() to
create a buffer, put_membuf to append bytes and get_membuf to
release and return the buffer. Allocation errors are detected but
only returned at the final get_membuf(), this helps not to clutter
the code with out of core checks. */
static void
init_membuf (struct membuf *mb, int initiallen)
{
mb->len = 0;
mb->size = initiallen;
mb->out_of_core = 0;
mb->buf = xtrymalloc (initiallen);
if (!mb->buf)
mb->out_of_core = 1;
}
static void
put_membuf (struct membuf *mb, const void *buf, size_t len)
{
if (mb->out_of_core)
return;
if (mb->len + len >= mb->size)
{
char *p;
mb->size += len + 1024;
p = xtryrealloc (mb->buf, mb->size);
if (!p)
{
mb->out_of_core = 1;
return;
}
mb->buf = p;
}
memcpy (mb->buf + mb->len, buf, len);
mb->len += len;
}
static void *
get_membuf (struct membuf *mb, size_t *len)
{
char *p;
if (mb->out_of_core)
{
xfree (mb->buf);
mb->buf = NULL;
return NULL;
}
p = mb->buf;
*len = mb->len;
mb->buf = NULL;
mb->out_of_core = 1; /* don't allow a reuse */
return p;
}
static void
put8 (struct membuf *mb, byte a )
{
put_membuf (mb, &a, 1);
}
static void
put16 (struct membuf *mb, u16 a )
{
unsigned char tmp[2];
tmp[0] = a>>8;
tmp[1] = a;
put_membuf (mb, tmp, 2);
}
static void
put32 (struct membuf *mb, u32 a )
{
unsigned char tmp[4];
tmp[0] = a>>24;
tmp[1] = a>>16;
tmp[2] = a>>8;
tmp[3] = a;
put_membuf (mb, tmp, 4);
}
/* Store a value in the fixup list */
static void
add_fixup (KEYBOXBLOB blob, u32 off, u32 val)
{
struct fixup_list *fl;
if (blob->fixup_out_of_core)
return;
fl = xtrycalloc(1, sizeof *fl);
if (!fl)
blob->fixup_out_of_core = 1;
else
{
fl->off = off;
fl->val = val;
fl->next = blob->fixups;
blob->fixups = fl;
}
}
/*
Some wrappers
*/
static u32
make_timestamp (void)
{
return time(NULL);
}
#ifdef KEYBOX_WITH_OPENPGP
/*
OpenPGP specific stuff
*/
/*
We must store the keyid at some place because we can't calculate the
offset yet. This is only used for v3 keyIDs. Function returns an
index value for later fixup or -1 for out of core. The value must be
a non-zero value */
static int
pgp_temp_store_kid (KEYBOXBLOB blob, PKT_public_key *pk)
{
struct keyid_list *k, *r;
k = xtrymalloc (sizeof *k);
if (!k)
return -1;
k->kid[0] = pk->keyid[0] >> 24 ;
k->kid[1] = pk->keyid[0] >> 16 ;
k->kid[2] = pk->keyid[0] >> 8 ;
k->kid[3] = pk->keyid[0] ;
k->kid[4] = pk->keyid[0] >> 24 ;
k->kid[5] = pk->keyid[0] >> 16 ;
k->kid[6] = pk->keyid[0] >> 8 ;
k->kid[7] = pk->keyid[0] ;
k->seqno = 0;
k->next = blob->temp_kids;
blob->temp_kids = k;
for (r=k; r; r = r->next)
k->seqno++;
return k->seqno;
}
static int
pgp_create_key_part (KEYBOXBLOB blob, KBNODE keyblock)
{
KBNODE node;
size_t fprlen;
int n;
for (n=0, node = keyblock; node; node = node->next)
{
if ( node->pkt->pkttype == PKT_PUBLIC_KEY
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
{
PKT_public_key *pk = node->pkt->pkt.public_key;
char tmp[20];
fingerprint_from_pk (pk, tmp , &fprlen);
memcpy (blob->keys[n].fpr, tmp, 20);
if ( fprlen != 20 ) /*v3 fpr - shift right and fill with zeroes*/
{
assert (fprlen == 16);
memmove (blob->keys[n].fpr+4, blob->keys[n].fpr, 16);
memset (blob->keys[n].fpr, 0, 4);
blob->keys[n].off_kid = pgp_temp_store_kid (blob, pk);
}
else
{
blob->keys[n].off_kid = 0; /* will be fixed up later */
}
blob->keys[n].flags = 0;
n++;
}
else if ( node->pkt->pkttype == PKT_SECRET_KEY
|| node->pkt->pkttype == PKT_SECRET_SUBKEY )
{
never_reached (); /* actually not yet implemented */
}
}
assert (n == blob->nkeys);
return 0;
}
static int
pgp_create_uid_part (KEYBOXBLOB blob, KBNODE keyblock)
{
KBNODE node;
int n;
for (n=0, node = keyblock; node; node = node->next)
{
if (node->pkt->pkttype == PKT_USER_ID)
{
PKT_user_id *u = node->pkt->pkt.user_id;
blob->uids[n].len = u->len;
blob->uids[n].flags = 0;
blob->uids[n].validity = 0;
n++;
}
}
assert (n == blob->nuids);
return 0;
}
static int
pgp_create_sig_part (KEYBOXBLOB blob, KBNODE keyblock)
{
KBNODE node;
int n;
for (n=0, node = keyblock; node; node = node->next)
{
if (node->pkt->pkttype == PKT_SIGNATURE)
{
PKT_signature *sig = node->pkt->pkt.signature;
blob->sigs[n] = 0; /* FIXME: check the signature here */
n++;
}
}
assert( n == blob->nsigs );
return 0;
}
static int
pgp_create_blob_keyblock (KEYBOXBLOB blob, KBNODE keyblock)
{
struct membuf *a = blob->buf;
KBNODE node;
int rc;
int n;
u32 kbstart = a->len;
add_fixup (blob, kbstart);
for (n = 0, node = keyblock; node; node = node->next)
{
rc = build_packet ( a, node->pkt );
if ( rc ) {
gpg_log_error ("build_packet(%d) for keyboxblob failed: %s\n",
node->pkt->pkttype, gpg_errstr(rc) );
return GPGERR_WRITE_FILE;
}
if ( node->pkt->pkttype == PKT_USER_ID )
{
PKT_user_id *u = node->pkt->pkt.user_id;
/* build_packet has set the offset of the name into u ;
* now we can do the fixup */
add_fixup (blob, blob->uids[n].off_addr, u->stored_at);
n++;
}
}
assert (n == blob->nuids);
add_fixup (blob, a->len - kbstart);
return 0;
}
#endif /*KEYBOX_WITH_OPENPGP*/
#ifdef KEYBOX_WITH_X509
/*
X.509 specific stuff
*/
/* Write the raw certificate out */
static int
x509_create_blob_cert (KEYBOXBLOB blob, KsbaCert cert)
{
struct membuf *a = blob->buf;
const unsigned char *image;
size_t length;
u32 kbstart = a->len;
/* Store our offset for later fixup */
add_fixup (blob, 8, kbstart);
image = ksba_cert_get_image (cert, &length);
if (!image)
return KEYBOX_General_Error;
put_membuf (a, image, length);
add_fixup (blob, 12, a->len - kbstart);
return 0;
}
#endif /*KEYBOX_WITH_X509*/
/* Write a stored keyID out to the buffer */
static void
write_stored_kid (KEYBOXBLOB blob, int seqno)
{
struct keyid_list *r;
for ( r = blob->temp_kids; r; r = r->next )
{
if (r->seqno == seqno )
{
put_membuf (blob->buf, r->kid, 8);
return;
}
}
never_reached ();
}
/* Release a list of key IDs */
static void
release_kid_list (struct keyid_list *kl)
{
struct keyid_list *r, *r2;
for ( r = kl; r; r = r2 )
{
r2 = r->next;
xfree (r);
}
}
static int
-create_blob_header (KEYBOXBLOB blob, int blobtype)
+create_blob_header (KEYBOXBLOB blob, int blobtype, int as_ephemeral)
{
struct membuf *a = blob->buf;
int i;
put32 ( a, 0 ); /* blob length, needs fixup */
put8 ( a, blobtype);
put8 ( a, 1 ); /* blob type version */
- put16 ( a, 0 ); /* blob flags */
+ put16 ( a, as_ephemeral? 2:0 ); /* blob flags */
put32 ( a, 0 ); /* offset to the raw data, needs fixup */
put32 ( a, 0 ); /* length of the raw data, needs fixup */
put16 ( a, blob->nkeys );
put16 ( a, 20 + 4 + 2 + 2 ); /* size of key info */
for ( i=0; i < blob->nkeys; i++ )
{
put_membuf (a, blob->keys[i].fpr, 20);
blob->keys[i].off_kid_addr = a->len;
put32 ( a, 0 ); /* offset to keyid, fixed up later */
put16 ( a, blob->keys[i].flags );
put16 ( a, 0 ); /* reserved */
}
put16 (a, blob->seriallen); /*fixme: check that it fits into 16 bits*/
if (blob->serial)
put_membuf (a, blob->serial, blob->seriallen);
put16 ( a, blob->nuids );
put16 ( a, 4 + 4 + 2 + 1 + 1 ); /* size of uid info */
for (i=0; i < blob->nuids; i++)
{
blob->uids[i].off_addr = a->len;
put32 ( a, 0 ); /* offset to userid, fixed up later */
put32 ( a, blob->uids[i].len );
put16 ( a, blob->uids[i].flags );
put8 ( a, 0 ); /* validity */
put8 ( a, 0 ); /* reserved */
}
put16 ( a, blob->nsigs );
put16 ( a, 4 ); /* size of sig info */
for (i=0; i < blob->nsigs; i++)
{
put32 ( a, blob->sigs[i]);
}
put8 ( a, 0 ); /* assigned ownertrust */
put8 ( a, 0 ); /* validity of all user IDs */
put16 ( a, 0 ); /* reserved */
put32 ( a, 0 ); /* time of next recheck */
put32 ( a, 0 ); /* newest timestamp (none) */
put32 ( a, make_timestamp() ); /* creation time */
put32 ( a, 0 ); /* size of reserved space */
/* reserved space (which is currently of size 0) */
/* space where we write keyIDs and and other stuff so that the
pointers can actually point to somewhere */
if (blobtype == BLOBTYPE_PGP)
{
/* We need to store the keyids for all pgp v3 keys because those key
IDs are not part of the fingerprint. While we are doing that, we
fixup all the keyID offsets */
for (i=0; i < blob->nkeys; i++ )
{
if (blob->keys[i].off_kid)
{ /* this is a v3 one */
add_fixup (blob, blob->keys[i].off_kid_addr, a->len);
write_stored_kid (blob, blob->keys[i].off_kid);
}
else
{ /* the better v4 key IDs - just store an offset 8 bytes back */
add_fixup (blob, blob->keys[i].off_kid_addr,
blob->keys[i].off_kid_addr - 8);
}
}
}
if (blobtype == BLOBTYPE_X509)
{
/* We don't want to point to ASN.1 encoded UserIDs (DNs) but to
the utf-8 string represenation of them */
for (i=0; i < blob->nuids; i++ )
{
if (blob->uids[i].name)
{ /* this is a v3 one */
add_fixup (blob, blob->uids[i].off_addr, a->len);
put_membuf (blob->buf, blob->uids[i].name, blob->uids[i].len);
}
}
}
return 0;
}
static int
create_blob_trailer (KEYBOXBLOB blob)
{
return 0;
}
static int
create_blob_finish (KEYBOXBLOB blob)
{
struct membuf *a = blob->buf;
byte *p;
char *pp;
int i;
size_t n;
/* write a placeholder for the checksum */
for (i = 0; i < 16; i++ )
put32 (a, 0); /* Hmmm: why put32() ?? */
/* get the memory area */
p = get_membuf (a, &n);
if (!p)
return KEYBOX_Out_Of_Core;
assert (n >= 20);
/* fixup the length */
add_fixup (blob, 0, n);
/* do the fixups */
if (blob->fixup_out_of_core)
return KEYBOX_Out_Of_Core;
{
struct fixup_list *fl;
for (fl = blob->fixups; fl; fl = fl->next)
{
assert (fl->off+4 <= n);
p[fl->off+0] = fl->val >> 24;
p[fl->off+1] = fl->val >> 16;
p[fl->off+2] = fl->val >> 8;
p[fl->off+3] = fl->val;
}
}
/* calculate and store the MD5 checksum */
gcry_md_hash_buffer (GCRY_MD_MD5, p + n - 16, p, n - 16);
pp = xtrymalloc (n);
if ( !pp )
return KEYBOX_Out_Of_Core;
memcpy (pp , p, n);
blob->blob = pp;
blob->bloblen = n;
return 0;
}
#ifdef KEYBOX_WITH_OPENPGP
int
-_keybox_create_pgp_blob (KEYBOXBLOB *r_blob, KBNODE keyblock)
+_keybox_create_pgp_blob (KEYBOXBLOB *r_blob, KBNODE keyblock, int as_ephemeral)
{
int rc = 0;
KBNODE node;
KEYBOXBLOB blob;
*r_blob = NULL;
blob = xtrycalloc (1, sizeof *blob);
if( !blob )
return KEYBOX_Out_Of_Core;
/* fixme: Do some sanity checks on the keyblock */
/* count userids and keys so that we can allocate the arrays */
for (node = keyblock; node; node = node->next)
{
switch (node->pkt->pkttype)
{
case PKT_PUBLIC_KEY:
case PKT_SECRET_KEY:
case PKT_PUBLIC_SUBKEY:
case PKT_SECRET_SUBKEY: blob->nkeys++; break;
case PKT_USER_ID: blob->nuids++; break;
case PKT_SIGNATURE: blob->nsigs++; break;
default: break;
}
}
blob->keys = xtrycalloc (blob->nkeys, sizeof *blob->keys );
blob->uids = xtrycalloc (blob->nuids, sizeof *blob->uids );
blob->sigs = xtrycalloc (blob->nsigs, sizeof *blob->sigs );
if (!blob->keys || !blob->uids || !blob->sigs)
{
rc = KEYBOX_Out_Of_Core;
goto leave;
}
rc = pgp_create_key_part ( blob, keyblock );
if (rc)
goto leave;
rc = pgp_create_uid_part ( blob, keyblock );
if (rc)
goto leave;
rc = pgp_create_sig_part ( blob, keyblock );
if (rc)
goto leave;
init_membuf (&blob->bufbuf, 1024);
blob->buf = &blob->bufbuf;
- rc = create_blob_header (blob, BLOBTYPE_OPENPGP);
+ rc = create_blob_header (blob, BLOBTYPE_OPENPGP, as_ephemeral);
if (rc)
goto leave;
rc = pgp_create_blob_keyblock (blob, keyblock);
if (rc)
goto leave;
rc = create_blob_trailer (blob);
if (rc)
goto leave;
rc = create_blob_finish ( blob );
if (rc)
goto leave;
leave:
release_kid_list (blob->temp_kids);
blob->temp_kids = NULL;
if (rc)
{
keybox_release_blob (blob);
*r_blob = NULL;
}
else
{
*r_blob = blob;
}
return rc;
}
#endif /*KEYBOX_WITH_OPENPGP*/
#ifdef KEYBOX_WITH_X509
/* return an allocated string with the email address extracted from a
DN */
static char *
x509_email_kludge (const char *name)
{
const unsigned char *p;
unsigned char *buf;
int n;
if (strncmp (name, "1.2.840.113549.1.9.1=#", 22))
return NULL;
/* This looks pretty much like an email address in the subject's DN
we use this to add an additional user ID entry. This way,
openSSL generated keys get a nicer and usable listing */
name += 22;
for (n=0, p=name; hexdigitp (p) && hexdigitp (p+1); p +=2, n++)
;
if (*p != '#' || !n)
return NULL;
buf = xtrymalloc (n+3);
if (!buf)
return NULL; /* oops, out of core */
*buf = '<';
for (n=1, p=name; *p != '#'; p +=2, n++)
buf[n] = xtoi_2 (p);
buf[n++] = '>';
buf[n] = 0;
return buf;
}
/* Note: We should move calculation of the digest into libksba and
remove that parameter */
int
_keybox_create_x509_blob (KEYBOXBLOB *r_blob, KsbaCert cert,
- unsigned char *sha1_digest)
+ unsigned char *sha1_digest, int as_ephemeral)
{
int i, rc = 0;
KEYBOXBLOB blob;
unsigned char *p;
unsigned char **names = NULL;
size_t max_names;
*r_blob = NULL;
blob = xtrycalloc (1, sizeof *blob);
if( !blob )
return KEYBOX_Out_Of_Core;
p = ksba_cert_get_serial (cert);
if (p)
{
size_t n, len;
n = gcry_sexp_canon_len (p, 0, NULL, NULL);
if (n < 2)
{
xfree (p);
return KEYBOX_General_Error;
}
blob->serialbuf = p;
p++; n--; /* skip '(' */
for (len=0; n && *p && *p != ':' && digitp (p); n--, p++)
len = len*10 + atoi_1 (p);
if (*p != ':')
{
xfree (blob->serialbuf);
blob->serialbuf = NULL;
return KEYBOX_General_Error;
}
p++;
blob->serial = p;
blob->seriallen = len;
}
blob->nkeys = 1;
/* create list of names */
blob->nuids = 0;
max_names = 100;
names = xtrymalloc (max_names * sizeof *names);
if (!names)
{
rc = KEYBOX_Out_Of_Core;
goto leave;
}
p = ksba_cert_get_issuer (cert, 0);
if (!p)
{
rc = KEYBOX_Missing_Value;
goto leave;
}
names[blob->nuids++] = p;
for (i=0; (p = ksba_cert_get_subject (cert, i)); i++)
{
if (blob->nuids >= max_names)
{
unsigned char **tmp;
max_names += 100;
tmp = xtryrealloc (names, max_names * sizeof *names);
if (!tmp)
{
rc = KEYBOX_Out_Of_Core;
goto leave;
}
}
names[blob->nuids++] = p;
if (!i && (p=x509_email_kludge (p)))
names[blob->nuids++] = p; /* due to !i we don't need to check bounds*/
}
/* space for signature information */
blob->nsigs = 1;
blob->keys = xtrycalloc (blob->nkeys, sizeof *blob->keys );
blob->uids = xtrycalloc (blob->nuids, sizeof *blob->uids );
blob->sigs = xtrycalloc (blob->nsigs, sizeof *blob->sigs );
if (!blob->keys || !blob->uids || !blob->sigs)
{
rc = KEYBOX_Out_Of_Core;
goto leave;
}
memcpy (blob->keys[0].fpr, sha1_digest, 20);
blob->keys[0].off_kid = 0; /* We don't have keyids */
blob->keys[0].flags = 0;
/* issuer and subject names */
for (i=0; i < blob->nuids; i++)
{
blob->uids[i].name = names[i];
blob->uids[i].len = strlen(names[i]);
names[i] = NULL;
blob->uids[i].flags = 0;
blob->uids[i].validity = 0;
}
xfree (names);
names = NULL;
/* signatures */
blob->sigs[0] = 0; /* not yet checked */
/* Create a temporary buffer for further processing */
init_membuf (&blob->bufbuf, 1024);
blob->buf = &blob->bufbuf;
/* write out what we already have */
- rc = create_blob_header (blob, BLOBTYPE_X509);
+ rc = create_blob_header (blob, BLOBTYPE_X509, as_ephemeral);
if (rc)
goto leave;
rc = x509_create_blob_cert (blob, cert);
if (rc)
goto leave;
rc = create_blob_trailer (blob);
if (rc)
goto leave;
rc = create_blob_finish ( blob );
if (rc)
goto leave;
leave:
release_kid_list (blob->temp_kids);
blob->temp_kids = NULL;
if (blob && names)
{
for (i=0; i < blob->nuids; i++)
xfree (names[i]);
}
xfree (names);
if (rc)
{
_keybox_release_blob (blob);
*r_blob = NULL;
}
else
{
*r_blob = blob;
}
return rc;
}
#endif /*KEYBOX_WITH_X509*/
int
_keybox_new_blob (KEYBOXBLOB *r_blob, char *image, size_t imagelen)
{
KEYBOXBLOB blob;
*r_blob = NULL;
blob = xtrycalloc (1, sizeof *blob);
if (!blob)
return KEYBOX_Out_Of_Core;
blob->blob = image;
blob->bloblen = imagelen;
*r_blob = blob;
return 0;
}
void
_keybox_release_blob (KEYBOXBLOB blob)
{
int i;
if (!blob)
return;
/* hmmm: release membuf here?*/
xfree (blob->keys );
xfree (blob->serialbuf);
for (i=0; i < blob->nuids; i++)
xfree (blob->uids[i].name);
xfree (blob->uids );
xfree (blob->sigs );
xfree (blob->blob );
xfree (blob );
}
const char *
_keybox_get_blob_image ( KEYBOXBLOB blob, size_t *n )
{
*n = blob->bloblen;
return blob->blob;
}
diff --git a/kbx/keybox-defs.h b/kbx/keybox-defs.h
index 8b5b91b54..978bb229e 100644
--- a/kbx/keybox-defs.h
+++ b/kbx/keybox-defs.h
@@ -1,175 +1,176 @@
/* keybox-defs.h - interal Keybox defintions
* Copyright (C) 2001 Free Software Foundation, Inc.
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (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
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef KEYBOX_DEFS_H
#define KEYBOX_DEFS_H 1
#include <sys/types.h> /* off_t */
#include "keybox.h"
#ifndef HAVE_BYTE_TYPEDEF
typedef unsigned char byte; /* fixme */
#endif
#ifndef HAVE_U16_TYPEDEF
typedef unsigned short u16; /* fixme */
#endif
#ifndef HAVE_U32_TYPEDEF
typedef unsigned int u32; /* fixme */
#endif
enum {
BLOBTYPE_HEADER = 1,
BLOBTYPE_PGP = 2,
BLOBTYPE_X509 = 3
};
typedef struct keyboxblob *KEYBOXBLOB;
typedef struct keybox_name *KB_NAME;
typedef struct keybox_name const * CONST_KB_NAME;
struct keybox_name {
struct keybox_name *next;
int secret;
/*DOTLOCK lockhd;*/
int is_locked;
int did_full_scan;
char fname[1];
};
struct keybox_handle {
CONST_KB_NAME kb;
int secret; /* this is for a secret keybox */
FILE *fp;
int eof;
int error;
+ int ephemeral;
struct {
KEYBOXBLOB blob;
off_t offset;
size_t pk_no;
size_t uid_no;
unsigned int n_packets; /*used for delete and update*/
} found;
struct {
char *name;
char *pattern;
} word_match;
};
/* Don't know whether this is needed: */
/* static struct { */
/* const char *homedir; */
/* int dry_run; */
/* int quiet; */
/* int verbose; */
/* int preserve_permissions; */
/* } keybox_opt; */
/*-- keybox-blob.c --*/
#ifdef KEYBOX_WITH_OPENPGP
/* fixme */
#endif /*KEYBOX_WITH_OPENPGP*/
#ifdef KEYBOX_WITH_X509
int _keybox_create_x509_blob (KEYBOXBLOB *r_blob, KsbaCert cert,
- unsigned char *sha1_digest);
+ unsigned char *sha1_digest, int as_ephemeral);
#endif /*KEYBOX_WITH_X509*/
int _keybox_new_blob (KEYBOXBLOB *r_blob, char *image, size_t imagelen);
void _keybox_release_blob (KEYBOXBLOB blob);
const char *_keybox_get_blob_image (KEYBOXBLOB blob, size_t *n);
/*-- keybox-file.c --*/
int _keybox_read_blob (KEYBOXBLOB *r_blob, FILE *fp);
int _keybox_write_blob (KEYBOXBLOB blob, FILE *fp);
/*-- keybox-dump.c --*/
int _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp);
int _keybox_dump_file (const char *filename, FILE *outfp);
/*-- keybox-util.c --*/
void *_keybox_malloc (size_t n);
void *_keybox_calloc (size_t n, size_t m);
void *_keybox_realloc (void *p, size_t n);
void _keybox_free (void *p);
#define xtrymalloc(a) _keybox_malloc ((a))
#define xtrycalloc(a,b) _keybox_calloc ((a),(b))
#define xtryrealloc(a,b) _keybox_realloc((a),(b))
#define xfree(a) _keybox_free ((a))
#define DIM(v) (sizeof(v)/sizeof((v)[0]))
#define DIMof(type,member) DIM(((type *)0)->member)
#ifndef STR
#define STR(v) #v
#endif
#define STR2(v) STR(v)
/*
a couple of handy macros
*/
#define return_if_fail(expr) do { \
if (!(expr)) { \
fprintf (stderr, "%s:%d: assertion `%s' failed\n", \
__FILE__, __LINE__, #expr ); \
return; \
} } while (0)
#define return_null_if_fail(expr) do { \
if (!(expr)) { \
fprintf (stderr, "%s:%d: assertion `%s' failed\n", \
__FILE__, __LINE__, #expr ); \
return NULL; \
} } while (0)
#define return_val_if_fail(expr,val) do { \
if (!(expr)) { \
fprintf (stderr, "%s:%d: assertion `%s' failed\n", \
__FILE__, __LINE__, #expr ); \
return (val); \
} } while (0)
#define never_reached() do { \
fprintf (stderr, "%s:%d: oops; should never get here\n", \
__FILE__, __LINE__ ); \
} while (0)
/* some macros to replace ctype ones and avoid locale problems */
#define digitp(p) (*(p) >= '0' && *(p) <= '9')
#define hexdigitp(a) (digitp (a) \
|| (*(a) >= 'A' && *(a) <= 'F') \
|| (*(a) >= 'a' && *(a) <= 'f'))
/* the atoi macros assume that the buffer has only valid digits */
#define atoi_1(p) (*(p) - '0' )
#define atoi_2(p) ((atoi_1(p) * 10) + atoi_1((p)+1))
#define atoi_4(p) ((atoi_2(p) * 100) + atoi_2((p)+2))
#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))
#endif /*KEYBOX_DEFS_H*/
diff --git a/kbx/keybox-dump.c b/kbx/keybox-dump.c
index d84ae7349..530b4647f 100644
--- a/kbx/keybox-dump.c
+++ b/kbx/keybox-dump.c
@@ -1,322 +1,342 @@
/* keybox-dump.c - Debug helpers
* Copyright (C) 2001 Free Software Foundation, Inc.
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (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
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#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;
}
static ulong
get16 (const byte *buffer)
{
ulong a;
a = *buffer << 8;
a |= buffer[1];
return a;
}
void
print_string (FILE *fp, const byte *p, size_t n, int delim)
{
for ( ; n; n--, p++ )
{
if (*p < 0x20 || (*p >= 0x7f && *p < 0xa0) || *p == delim)
{
putc('\\', fp);
if( *p == '\n' )
putc('n', fp);
else if( *p == '\r' )
putc('r', fp);
else if( *p == '\f' )
putc('f', fp);
else if( *p == '\v' )
putc('v', fp);
else if( *p == '\b' )
putc('b', fp);
else if( !*p )
putc('0', fp);
else
fprintf(fp, "x%02x", *p );
}
else
putc(*p, fp);
}
}
static int
dump_header_blob (const byte *buffer, size_t length, FILE *fp)
{
fprintf (fp, "Version: %d\n", buffer[5]);
if ( memcmp (buffer+8, "KBXf", 4))
fprintf (fp, "[Error: invalid magic number]\n");
return 0;
}
/* Dump one block to FP */
int
_keybox_dump_blob (KEYBOXBLOB blob, FILE *fp)
{
const byte *buffer;
size_t length;
int type;
ulong n, nkeys, keyinfolen;
ulong nuids, uidinfolen;
ulong nsigs, siginfolen;
ulong rawdata_off, rawdata_len;
ulong nserial;
const byte *p;
buffer = _keybox_get_blob_image (blob, &length);
if (length < 40)
{
fprintf (fp, "[blob too short]\n");
return -1;
}
n = get32( buffer );
if (n > length)
fprintf (fp, "[blob larger than length - output truncated]\n");
else
length = n; /* ignore the rest */
fprintf (fp, "Length: %lu\n", n );
type = buffer[4];
switch (type)
{
case BLOBTYPE_HEADER:
fprintf (fp, "Type: Header\n");
return dump_header_blob (buffer, length, fp);
case BLOBTYPE_PGP:
fprintf (fp, "Type: OpenPGP\n");
break;
case BLOBTYPE_X509:
fprintf (fp, "Type: X.509\n");
break;
default:
fprintf (fp, "Type: %d\n", type);
fprintf (fp, "[can't dump this blob type]\n");
return 0;
}
fprintf (fp, "Version: %d\n", buffer[5]);
n = get16 (buffer + 6);
- fprintf( fp, "Blob-Flags: %04lX\n", n);
-
+ fprintf( fp, "Blob-Flags: %04lX", n);
+ if (n)
+ {
+ int any = 0;
+
+ fputs (" (", fp);
+ if ((n & 1))
+ {
+ fputs ("secret", fp);
+ any++;
+ }
+ if ((n & 2))
+ {
+ if (any)
+ putc (',', fp);
+ fputs ("ephemeral", fp);
+ any++;
+ }
+ putc (')', fp);
+ }
+ putc ('\n', fp);
+
rawdata_off = get32 (buffer + 8);
rawdata_len = get32 (buffer + 12);
fprintf( fp, "Data-Offset: %lu\n", rawdata_off );
fprintf( fp, "Data-Length: %lu\n", rawdata_len );
nkeys = get16 (buffer + 16);
fprintf (fp, "Key-Count: %lu\n", nkeys );
if (!nkeys)
fprintf (fp, "[Error: no keys]\n");
if (nkeys > 1 && type == BLOBTYPE_X509)
fprintf (fp, "[Error: only one key allowed for X509]\n");
keyinfolen = get16 (buffer + 18 );
fprintf (fp, "Key-Info-Length: %lu\n", keyinfolen);
/* fixme: check bounds */
p = buffer + 20;
for (n=0; n < nkeys; n++, p += keyinfolen)
{
int i;
ulong kidoff, kflags;
fprintf (fp, "Key-Fpr[%lu]: ", n );
for (i=0; i < 20; i++ )
fprintf (fp, "%02X", p[i]);
kidoff = get32 (p + 20);
fprintf (fp, "\nKey-Kid-Off[%lu]: %lu\n", n, kidoff );
fprintf (fp, "Key-Kid[%lu]: ", n );
/* fixme: check bounds */
for (i=0; i < 8; i++ )
fprintf (fp, "%02X", buffer[kidoff+i] );
kflags = get16 (p + 24 );
fprintf( fp, "\nKey-Flags[%lu]: %04lX\n", n, kflags);
}
/* serial number */
fputs ("Serial-No: ", fp);
nserial = get16 (p);
p += 2;
if (!nserial)
fputs ("none", fp);
else
{
for (; nserial; nserial--, p++)
fprintf (fp, "%02X", *p);
}
putc ('\n', fp);
/* user IDs */
nuids = get16 (p);
fprintf (fp, "Uid-Count: %lu\n", nuids );
uidinfolen = get16 (p + 2);
fprintf (fp, "Uid-Info-Length: %lu\n", uidinfolen);
/* fixme: check bounds */
p += 4;
for (n=0; n < nuids; n++, p += uidinfolen)
{
ulong uidoff, uidlen, uflags;
uidoff = get32( p );
uidlen = get32( p+4 );
if (type == BLOBTYPE_X509 && !n)
{
fprintf (fp, "Issuer-Off: %lu\n", uidoff );
fprintf (fp, "Issuer-Len: %lu\n", uidlen );
fprintf (fp, "Issuer: \"");
}
else if (type == BLOBTYPE_X509 && n == 1)
{
fprintf (fp, "Subject-Off: %lu\n", uidoff );
fprintf (fp, "Subject-Len: %lu\n", uidlen );
fprintf (fp, "Subject: \"");
}
else
{
fprintf (fp, "Uid-Off[%lu]: %lu\n", n, uidoff );
fprintf (fp, "Uid-Len[%lu]: %lu\n", n, uidlen );
fprintf (fp, "Uid[%lu]: \"", n );
}
print_string (fp, buffer+uidoff, uidlen, '\"');
fputs ("\"\n", fp);
uflags = get16 (p + 8);
if (type == BLOBTYPE_X509 && !n)
{
fprintf (fp, "Issuer-Flags: %04lX\n", uflags );
fprintf (fp, "Issuer-Validity: %d\n", p[10] );
}
else if (type == BLOBTYPE_X509 && n == 1)
{
fprintf (fp, "Subject-Flags: %04lX\n", uflags );
fprintf (fp, "Subject-Validity: %d\n", p[10] );
}
else
{
fprintf (fp, "Uid-Flags[%lu]: %04lX\n", n, uflags );
fprintf (fp, "Uid-Validity[%lu]: %d\n", n, p[10] );
}
}
nsigs = get16 (p);
fprintf (fp, "Sig-Count: %lu\n", nsigs );
siginfolen = get16 (p + 2);
fprintf (fp, "Sig-Info-Length: %lu\n", siginfolen );
/* fixme: check bounds */
p += 4;
for (n=0; n < nsigs; n++, p += siginfolen)
{
ulong sflags;
sflags = get32 (p);
fprintf (fp, "Sig-Expire[%lu]: ", n );
if (!sflags)
fputs ("[not checked]", fp);
else if (sflags == 1 )
fputs ("[missing key]", fp);
else if (sflags == 2 )
fputs ("[bad signature]", fp);
else if (sflags < 0x10000000)
fprintf (fp, "[bad flag %0lx]", sflags);
else if (sflags == 0xffffffff)
fputs ("0", fp );
else
fputs ("a time"/*strtimestamp( sflags )*/, fp );
putc ('\n', fp );
}
fprintf (fp, "Ownertrust: %d\n", p[0] );
fprintf (fp, "All-Validity: %d\n", p[1] );
p += 4;
n = get32 (p); p += 4;
fprintf (fp, "Recheck-After: %s\n", /*n? strtimestamp(n) :*/ "0" );
n = get32 (p ); p += 4;
fprintf( fp, "Latest-Timestamp: %s\n", "0"/*strtimestamp(n)*/ );
n = get32 (p ); p += 4;
fprintf (fp, "Created-At: %s\n", "0"/*strtimestamp(n)*/ );
n = get32 (p ); p += 4;
fprintf (fp, "Reserved-Space: %lu\n", n );
/* check that the keyblock is at the correct offset and other bounds */
/*fprintf (fp, "Blob-Checksum: [MD5-hash]\n");*/
return 0;
}
int
_keybox_dump_file (const char *filename, FILE *outfp)
{
FILE *fp;
KEYBOXBLOB blob;
int rc;
unsigned long count = 0;
if (!filename)
{
filename = "-";
fp = stdin;
}
else
fp = fopen (filename, "rb");
if (!fp)
{
fprintf (outfp, "can't open `%s': %s\n", filename, strerror(errno));
return KEYBOX_File_Error;
}
while ( !(rc = _keybox_read_blob (&blob, fp)) )
{
fprintf (outfp, "BEGIN-RECORD: %lu\n", count );
_keybox_dump_blob (blob, outfp);
_keybox_release_blob (blob);
fprintf (outfp, "END-RECORD\n");
count++;
}
if (rc == -1)
rc = 0;
if (rc)
fprintf (outfp, "error reading `%s': %s\n", filename,
rc == KEYBOX_Read_Error? keybox_strerror(rc):strerror (errno));
if (fp != stdin)
fclose (fp);
return rc;
}
diff --git a/kbx/keybox-file.c b/kbx/keybox-file.c
index 715d3fbe2..79a2e1719 100644
--- a/kbx/keybox-file.c
+++ b/kbx/keybox-file.c
@@ -1,85 +1,86 @@
/* keybox-file.c - file oeprations
* Copyright (C) 2001 Free Software Foundation, Inc.
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (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
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "keybox-defs.h"
-/* Read a block at the current postion ant return it in r_blocb. r_blob may be NULL sto simply skip the current block */
+/* Read a block at the current postion and return it in r_blob.
+ r_blob may be NULL to simply skip the current block */
int
_keybox_read_blob (KEYBOXBLOB *r_blob, FILE *fp)
{
char *image;
size_t imagelen = 0;
int c1, c2, c3, c4;
int rc;
*r_blob = NULL;
if ((c1 = getc (fp)) == EOF
|| (c2 = getc (fp)) == EOF
|| (c3 = getc (fp)) == EOF
|| (c4 = getc (fp)) == EOF ) {
if ( c1 == EOF && !ferror (fp) )
return -1; /* eof */
return KEYBOX_Read_Error;
}
imagelen = (c1 << 24) | (c2 << 16) | (c3 << 8 ) | c4;
if (imagelen > 500000) /* sanity check */
return KEYBOX_Blob_Too_Large;
if (imagelen < 4)
return KEYBOX_Blob_Too_Short;
image = xtrymalloc (imagelen);
if (!image)
return KEYBOX_Out_Of_Core;
image[0] = c1; image[1] = c2; image[2] = c3; image[3] = c4;
if (fread (image+4, imagelen-4, 1, fp) != 1)
{
xfree (image);
return KEYBOX_Read_Error;
}
rc = r_blob? _keybox_new_blob (r_blob, image, imagelen) : 0;
if (rc || !r_blob)
xfree (image);
return rc;
}
/* Write the block to the current file position */
int
_keybox_write_blob (KEYBOXBLOB blob, FILE *fp)
{
const char *image;
size_t length;
image = _keybox_get_blob_image (blob, &length);
if (fwrite (image, length, 1, fp) != 1)
{
return KEYBOX_Write_Error;
}
return 0;
}
diff --git a/kbx/keybox-init.c b/kbx/keybox-init.c
index 1a4a587b9..b1d279999 100644
--- a/kbx/keybox-init.c
+++ b/kbx/keybox-init.c
@@ -1,120 +1,127 @@
/* keybox-init.c - Initalization of the library
* Copyright (C) 2001 Free Software Foundation, Inc.
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (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
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include "keybox-defs.h"
#define compare_filenames strcmp
static KB_NAME kb_names;
/*
Register a filename for plain keybox files. Returns a pointer to be
used to create a handles etc or NULL to indicate that it has already
been registered */
void *
keybox_register_file (const char *fname, int secret)
{
KB_NAME kr;
for (kr=kb_names; kr; kr = kr->next)
{
if ( !compare_filenames (kr->fname, fname) )
return NULL; /* already registered */
}
kr = xtrymalloc (sizeof *kr + strlen (fname));
if (!kr)
return NULL;
strcpy (kr->fname, fname);
kr->secret = !!secret;
/* kr->lockhd = NULL;*/
kr->is_locked = 0;
kr->did_full_scan = 0;
/* keep a list of all issued pointers */
kr->next = kb_names;
kb_names = kr;
/* create the offset table the first time a function here is used */
/* if (!kb_offtbl) */
/* kb_offtbl = new_offset_hash_table (); */
return kr;
}
int
keybox_is_writable (void *token)
{
KB_NAME r = token;
return r? !access (r->fname, W_OK) : 0;
}
/* Create a new handle for the resource associated with TOKEN. SECRET
is just a cross-check.
The returned handle must be released using keybox_release (). */
KEYBOX_HANDLE
keybox_new (void *token, int secret)
{
KEYBOX_HANDLE hd;
KB_NAME resource = token;
assert (resource && !resource->secret == !secret);
hd = xtrycalloc (1, sizeof *hd);
if (hd)
{
hd->kb = resource;
hd->secret = !!secret;
}
return hd;
}
void
keybox_release (KEYBOX_HANDLE hd)
{
if (!hd)
return;
_keybox_release_blob (hd->found.blob);
xfree (hd->word_match.name);
xfree (hd->word_match.pattern);
xfree (hd);
}
const char *
keybox_get_resource_name (KEYBOX_HANDLE hd)
{
if (!hd || !hd->kb)
return NULL;
return hd->kb->fname;
}
-
+int
+keybox_set_ephemeral (KEYBOX_HANDLE hd, int yes)
+{
+ if (!hd)
+ return KEYBOX_Invalid_Handle;
+ hd->ephemeral = yes;
+ return 0;
+}
diff --git a/kbx/keybox-search.c b/kbx/keybox-search.c
index c7434cd93..e57754344 100644
--- a/kbx/keybox-search.c
+++ b/kbx/keybox-search.c
@@ -1,758 +1,780 @@
/* keybox-search.c - Search operations
- * Copyright (C) 2001 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2002 Free Software Foundation, Inc.
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (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
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "../jnlib/stringhelp.h" /* ascii_xxxx() */
#include "keybox-defs.h"
#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))
struct sn_array_s {
int snlen;
unsigned char *sn;
};
static ulong
get32 (const byte *buffer)
{
ulong a;
a = *buffer << 24;
a |= buffer[1] << 16;
a |= buffer[2] << 8;
a |= buffer[3];
return a;
}
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 unsigned int
+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);
+}
+
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*/
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_fpr (KEYBOXBLOB blob, const unsigned char *fpr)
{
const unsigned char *buffer;
size_t length;
size_t pos, off;
size_t nkeys, keyinfolen;
int idx;
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;
if (pos + keyinfolen*nkeys > length)
return 0; /* out of bounds */
for (idx=0; idx < nkeys; idx++)
{
off = pos + idx*keyinfolen;
if (!memcmp (buffer + off, fpr, 20))
return 1; /* found */
}
return 0; /* not found */
}
static int
blob_cmp_name (KEYBOXBLOB blob, int idx,
const char *name, size_t namelen, int substr)
{
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 < 0)
{ /* compare all names starting with that (negated) index */
idx = -idx;
for ( ;idx < nuids; idx++)
{
size_t mypos = pos;
mypos += idx*uidinfolen;
off = get32 (buffer+mypos);
len = get32 (buffer+mypos+4);
if (off+len > length)
return 0; /* error: better stop here out of bounds */
if (len < 2)
continue; /* empty name or 0 not stored */
len--;
if (substr)
{
if (ascii_memcasemem (buffer+off, len, name, namelen))
return 1; /* found */
}
else
{
if (len == namelen && !memcmp (buffer+off, name, len))
return 1; /* found */
}
}
return 0; /* not found */
}
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)
{
return !!ascii_memcasemem (buffer+off, len, name, namelen);
}
else
{
return len == namelen && !memcmp (buffer+off, name, len);
}
}
}
/* compare all email addresses of the subject. With SUBSTR given as
True a substring search is done in the mail address */
static int
blob_cmp_mail (KEYBOXBLOB blob, const char *name, size_t namelen, int substr)
{
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*/
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 (namelen < 1)
return 0;
for (idx=1 ;idx < nuids; idx++)
{
size_t mypos = pos;
mypos += idx*uidinfolen;
off = get32 (buffer+mypos);
len = get32 (buffer+mypos+4);
if (off+len > length)
return 0; /* error: better stop here out of bounds */
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 */
len--;
if (substr)
{
if (ascii_memcasemem (buffer+off+1, len, name, namelen))
return 1; /* found */
}
else
{
if (len == namelen && !ascii_memcasecmp (buffer+off+1, name, len))
return 1; /* found */
}
}
return 0; /* not found */
}
/*
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 blob_cmp_fpr (blob, fpr);
}
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, 0);
}
static int
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);
if (blob_get_type (blob) != BLOBTYPE_X509)
return 0;
namelen = strlen (name);
return (blob_cmp_sn (blob, sn, snlen)
&& blob_cmp_name (blob, 0 /* issuer */, name, namelen, 0));
}
static int
has_sn (KEYBOXBLOB blob, const unsigned char *sn, int snlen)
{
return_val_if_fail (sn, 0);
if (blob_get_type (blob) != BLOBTYPE_X509)
return 0;
return blob_cmp_sn (blob, sn, snlen);
}
static int
has_subject (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, 1 /* subject */, name, namelen, 0);
}
static int
has_subject_or_alt (KEYBOXBLOB blob, const char *name, int substr)
{
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, -1 /* all subject names*/, name,
namelen, substr);
}
static int
has_mail (KEYBOXBLOB blob, const char *name, int substr)
{
size_t namelen;
return_val_if_fail (name, 0);
if (blob_get_type (blob) != BLOBTYPE_X509)
return 0;
namelen = strlen (name);
if (namelen && name[namelen-1] == '>')
namelen--;
return blob_cmp_mail (blob, name, namelen, substr);
}
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);
}
/*
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;
}
+
+/* Note: When in ephemeral mode the search function does visit all
+ blobs but in standard mode, blobs flagged as ephemeral are ignored. */
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;
struct sn_array_s *sn_array = 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 (desc[n].snlen == -1 && !sn_array)
{
sn_array = xtrycalloc (ndesc, sizeof *sn_array);
if (!sn_array)
return (hd->error = KEYBOX_Out_Of_Core);
}
}
if (!hd->fp)
{
hd->fp = fopen (hd->kb->fname, "rb");
if (!hd->fp)
{
xfree (sn_array);
return (hd->error = KEYBOX_File_Open_Error);
}
}
/* kludge: we need to convert an SN given as hexstring to it's
binary representation - in some cases we are not able to store it
in the search descriptor, because due to its usgae it is not
possible to free allocated memory */
if (sn_array)
{
const unsigned char *s;
int i, odd;
size_t snlen;
for (n=0; n < ndesc; n++)
{
if (!desc[n].sn)
;
else if (desc[n].snlen == -1)
{
unsigned char *sn;
s = desc[n].sn;
for (i=0; *s && *s != '/'; s++, i++)
;
odd = (i & 1);
snlen = (i+1)/2;
sn_array[n].sn = xtrymalloc (snlen);
if (!sn_array[n].sn)
{
release_sn_array (sn_array, n);
return (hd->error = KEYBOX_Out_Of_Core);
}
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)
{
release_sn_array (sn_array, n);
return (hd->error = KEYBOX_Out_Of_Core);
}
sn_array[n].snlen = snlen;
memcpy (sn_array[n].sn, sn, snlen);
}
}
}
for (;;)
{
+ unsigned int blobflags;
+
_keybox_release_blob (blob); blob = NULL;
rc = _keybox_read_blob (&blob, hd->fp);
if (rc)
break;
+ blobflags = blob_get_blob_flags (blob);
+ if (!hd->ephemeral && (blobflags & 2))
+ continue; /* not in ephemeral mode but blob is flagged ephemeral */
+
for (n=0; n < ndesc; n++)
{
switch (desc[n].mode)
{
case KEYDB_SEARCH_MODE_NONE:
never_reached ();
break;
case KEYDB_SEARCH_MODE_EXACT:
if (has_subject_or_alt (blob, desc[n].u.name, 0))
goto found;
break;
case KEYDB_SEARCH_MODE_MAIL:
if (has_mail (blob, desc[n].u.name, 0))
goto found;
break;
case KEYDB_SEARCH_MODE_MAILSUB:
if (has_mail (blob, desc[n].u.name, 1))
goto found;
break;
case KEYDB_SEARCH_MODE_SUBSTR:
if (has_subject_or_alt (blob, desc[n].u.name, 1))
goto found;
break;
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,
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;
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:
case KEYDB_SEARCH_MODE_FPR20:
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;
}
if (sn_array)
release_sn_array (sn_array, ndesc);
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_get_cert (KEYBOX_HANDLE hd, KsbaCert *r_cert)
{
const unsigned char *buffer;
size_t length;
size_t cert_off, cert_len;
KsbaReader reader = NULL;
KsbaCert cert = NULL;
int rc;
if (!hd)
return KEYBOX_Invalid_Value;
if (!hd->found.blob)
return KEYBOX_Nothing_Found;
if (blob_get_type (hd->found.blob) != BLOBTYPE_X509)
return KEYBOX_Wrong_Blob_Type;
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;
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;
}
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*/
diff --git a/kbx/keybox-update.c b/kbx/keybox-update.c
index d49c3d027..96a30b9c1 100644
--- a/kbx/keybox-update.c
+++ b/kbx/keybox-update.c
@@ -1,390 +1,390 @@
/* keybox-update.c - keybox update operations
* Copyright (C) 2001 Free Software Foundation, Inc.
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (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
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include "keybox-defs.h"
#define EXTSEP_S "."
static int
create_tmp_file (const char *template,
char **r_bakfname, char **r_tmpfname, FILE **r_fp)
{
char *bakfname, *tmpfname;
*r_bakfname = NULL;
*r_tmpfname = NULL;
# ifdef USE_ONLY_8DOT3
/* Here is another Windoze bug?:
* you cant rename("pubring.kbx.tmp", "pubring.kbx");
* but rename("pubring.kbx.tmp", "pubring.aaa");
* works. So we replace .kbx by .bak or .tmp
*/
if (strlen (template) > 4
&& !strcmp (template+strlen(template)-4, EXTSEP_S "kbx") )
{
bakfname = xtrymalloc (strlen (template) + 1);
if (!bakfname)
return KEYBOX_Out_Of_Core;
strcpy (bakfname, template);
strcpy (bakfname+strlen(template)-4, EXTSEP_S "bak");
tmpfname = xtrymalloc (strlen (template) + 1);
if (!tmpfname)
{
xfree (bakfname);
return KEYBOX_Out_Of_Core;
}
strcpy (tmpfname,template);
strcpy (tmpfname + strlen (template)-4, EXTSEP_S "tmp");
}
else
{ /* file does not end with kbx; hmmm */
bakfname = xtrymalloc ( strlen (template) + 5);
if (!bakfname)
return KEYBOX_Out_Of_Core;
strcpy (stpcpy (bakfname, template), EXTSEP_S "bak");
tmpfname = xtrymalloc ( strlen (template) + 5);
if (!tmpfname)
{
xfree (bakfname);
return KEYBOX_Out_Of_Core;
}
strcpy (stpcpy (tmpfname, template), EXTSEP_S "tmp");
}
# else /* Posix file names */
bakfname = xtrymalloc (strlen (template) + 2);
if (!bakfname)
return KEYBOX_Out_Of_Core;
strcpy (stpcpy (bakfname,template),"~");
tmpfname = xtrymalloc ( strlen (template) + 5);
if (!tmpfname)
{
xfree (bakfname);
return KEYBOX_Out_Of_Core;
}
strcpy (stpcpy (tmpfname,template), EXTSEP_S "tmp");
# endif /* Posix filename */
*r_fp = fopen (tmpfname, "wb");
if (!*r_fp)
{
xfree (tmpfname);
xfree (bakfname);
return KEYBOX_File_Create_Error;
}
*r_bakfname = bakfname;
*r_tmpfname = tmpfname;
return 0;
}
static int
rename_tmp_file (const char *bakfname, const char *tmpfname,
const char *fname, int secret )
{
int rc=0;
/* restrict the permissions for secret keyboxs */
#ifndef HAVE_DOSISH_SYSTEM
/* if (secret && !opt.preserve_permissions) */
/* { */
/* if (chmod (tmpfname, S_IRUSR | S_IWUSR) ) */
/* { */
/* log_debug ("chmod of `%s' failed: %s\n", */
/* tmpfname, strerror(errno) ); */
/* return KEYBOX_Write_File; */
/* } */
/* } */
#endif
/* fixme: invalidate close caches (not used with stdio)*/
/* iobuf_ioctl (NULL, 2, 0, (char*)tmpfname ); */
/* iobuf_ioctl (NULL, 2, 0, (char*)bakfname ); */
/* iobuf_ioctl (NULL, 2, 0, (char*)fname ); */
/* first make a backup file except for secret keyboxs */
if (!secret)
{
#if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
remove (bakfname);
#endif
if (rename (fname, bakfname) )
{
return KEYBOX_File_Error;
}
}
/* then rename the file */
#if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
remove (fname);
#endif
if (rename (tmpfname, fname) )
{
rc = KEYBOX_File_Error;
if (secret)
{
/* log_info ("WARNING: 2 files with confidential" */
/* " information exists.\n"); */
/* log_info ("%s is the unchanged one\n", fname ); */
/* log_info ("%s is the new one\n", tmpfname ); */
/* log_info ("Please fix this possible security flaw\n"); */
}
return rc;
}
return 0;
}
/* Perform insert/delete/update operation.
mode 1 = insert
2 = delete
3 = update
*/
static int
blob_filecopy (int mode, const char *fname, KEYBOXBLOB blob,
int secret, off_t start_offset, unsigned int n_packets )
{
FILE *fp, *newfp;
int rc=0;
char *bakfname = NULL;
char *tmpfname = NULL;
char buffer[4096];
int nread, nbytes;
/* Open the source file. Because we do a rename, we have to check the
permissions of the file */
if (access (fname, W_OK))
return KEYBOX_Write_Error;
fp = fopen (fname, "rb");
if (mode == 1 && !fp && errno == ENOENT)
{ /* insert mode but file does not exist: create a new keybox file */
newfp = fopen (fname, "wb");
if (!newfp )
{
return KEYBOX_File_Create_Error;
}
rc = _keybox_write_blob (blob, newfp);
if (rc)
{
return rc;
}
if ( fclose (newfp) )
{
return KEYBOX_File_Create_Error;
}
/* if (chmod( fname, S_IRUSR | S_IWUSR )) */
/* { */
/* log_debug ("%s: chmod failed: %s\n", fname, strerror(errno) ); */
/* return KEYBOX_File_Error; */
/* } */
return 0; /* ready */
}
if (!fp)
{
rc = KEYBOX_File_Open_Error;
goto leave;
}
/* create the new file */
rc = create_tmp_file (fname, &bakfname, &tmpfname, &newfp);
if (rc)
{
fclose(fp);
goto leave;
}
/* prepare for insert */
if (mode == 1)
{
/* copy everything to the new file */
while ( (nread = fread (buffer, 1, DIM(buffer), fp)) > 0 )
{
if (fwrite (buffer, nread, 1, newfp) != 1)
{
rc = KEYBOX_Write_Error;
goto leave;
}
}
if (ferror (fp))
{
rc = KEYBOX_Read_Error;
goto leave;
}
}
/* prepare for delete or update */
if ( mode == 2 || mode == 3 )
{
off_t current = 0;
/* copy first part to the new file */
while ( current < start_offset )
{
nbytes = DIM(buffer);
if (current + nbytes > start_offset)
nbytes = start_offset - current;
nread = fread (buffer, 1, nbytes, fp);
if (!fread)
break;
current += nread;
if (fwrite (buffer, nread, 1, newfp) != 1)
{
rc = KEYBOX_Write_Error;
goto leave;
}
}
if (ferror (fp))
{
rc = KEYBOX_Read_Error;
goto leave;
}
/* skip this blob */
rc = _keybox_read_blob (NULL, fp);
if (rc)
return rc;
}
/* Do an insert or update */
if ( mode == 1 || mode == 3 )
{
rc = _keybox_write_blob (blob, newfp);
if (rc)
return rc;
}
/* copy the rest of the packet for an delete or update */
if (mode == 2 || mode == 3)
{
while ( (nread = fread (buffer, 1, DIM(buffer), fp)) > 0 )
{
if (fwrite (buffer, nread, 1, newfp) != 1)
{
rc = KEYBOX_Write_Error;
goto leave;
}
}
if (ferror (fp))
{
rc = KEYBOX_Read_Error;
goto leave;
}
}
/* close both files */
if (fclose(fp))
{
rc = KEYBOX_File_Close_Error;
fclose (newfp);
goto leave;
}
if (fclose(newfp))
{
rc = KEYBOX_File_Close_Error;
goto leave;
}
rc = rename_tmp_file (bakfname, tmpfname, fname, secret);
leave:
xfree(bakfname);
xfree(tmpfname);
return rc;
}
#ifdef KEYBOX_WITH_X509
int
keybox_insert_cert (KEYBOX_HANDLE hd, KsbaCert cert,
unsigned char *sha1_digest)
{
int rc;
const char *fname;
KEYBOXBLOB blob;
if (!hd)
return KEYBOX_Invalid_Handle;
if (!hd->kb)
return KEYBOX_Invalid_Handle;
fname = hd->kb->fname;
if (!fname)
return KEYBOX_Invalid_Handle;
/* close this one otherwise we will mess up the position for a next
search. Fixme: it would be better to adjust the position after
the write opertions. */
if (hd->fp)
{
fclose (hd->fp);
hd->fp = NULL;
}
- rc = _keybox_create_x509_blob (&blob, cert, sha1_digest);
+ rc = _keybox_create_x509_blob (&blob, cert, sha1_digest, hd->ephemeral);
if (!rc)
{
rc = blob_filecopy (1, fname, blob, hd->secret, 0, 0 );
_keybox_release_blob (blob);
/* if (!rc && !hd->secret && kb_offtbl) */
/* { */
/* update_offset_hash_table_from_kb (kb_offtbl, kb, 0); */
/* } */
}
return rc;
}
int
keybox_update_cert (KEYBOX_HANDLE hd, KsbaCert cert,
unsigned char *sha1_digest)
{
return -1;
}
#endif /*KEYBOX_WITH_X509*/
int
keybox_delete (KEYBOX_HANDLE hd)
{
return -1;
}
diff --git a/kbx/keybox.h b/kbx/keybox.h
index fcacc49d3..a763ec837 100644
--- a/kbx/keybox.h
+++ b/kbx/keybox.h
@@ -1,124 +1,125 @@
/* keybox.h - Keybox operations
* Copyright (C) 2001 Free Software Foundation, Inc.
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (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
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef KEYBOX_H
#define KEYBOX_H 1
#ifdef __cplusplus
extern "C" {
#if 0
}
#endif
#endif
#include "keybox-search-desc.h"
#define KEYBOX_WITH_OPENPGP 1
#define KEYBOX_WITH_X509 1
#ifdef KEYBOX_WITH_OPENPGP
# undef KEYBOX_WITH_OPENPGP
/*#include <lib-to-handle-gpg-data-structs.h>*/
#endif
#ifdef KEYBOX_WITH_X509
# include <ksba.h>
#endif
typedef enum {
KEYBOX_No_Error = 0,
KEYBOX_General_Error = 1,
KEYBOX_Out_Of_Core = 2,
KEYBOX_Invalid_Value = 3,
KEYBOX_Timeout = 4,
KEYBOX_Read_Error = 5,
KEYBOX_Write_Error = 6,
KEYBOX_File_Error = 7,
KEYBOX_Blob_Too_Short = 8,
KEYBOX_Blob_Too_Large = 9,
KEYBOX_Invalid_Handle = 10,
KEYBOX_File_Create_Error = 11,
KEYBOX_File_Open_Error = 12,
KEYBOX_File_Close_Error = 13,
KEYBOX_Nothing_Found = 14,
KEYBOX_Wrong_Blob_Type = 15,
KEYBOX_Missing_Value = 16,
} KeyboxError;
typedef struct keybox_handle *KEYBOX_HANDLE;
/*-- keybox-init.c --*/
void *keybox_register_file (const char *fname, int secret);
int keybox_is_writable (void *token);
KEYBOX_HANDLE keybox_new (void *token, int secret);
void keybox_release (KEYBOX_HANDLE hd);
const char *keybox_get_resource_name (KEYBOX_HANDLE hd);
+int keybox_set_ephemeral (KEYBOX_HANDLE hd, int yes);
/*-- keybox-search.c --*/
#ifdef KEYBOX_WITH_X509
int keybox_get_cert (KEYBOX_HANDLE hd, KsbaCert *ret_cert);
#endif /*KEYBOX_WITH_X509*/
int keybox_search_reset (KEYBOX_HANDLE hd);
int keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc);
/*-- keybox-update.c --*/
#ifdef KEYBOX_WITH_X509
int keybox_insert_cert (KEYBOX_HANDLE hd, KsbaCert cert,
unsigned char *sha1_digest);
int keybox_update_cert (KEYBOX_HANDLE hd, KsbaCert cert,
unsigned char *sha1_digest);
#endif /*KEYBOX_WITH_X509*/
int keybox_delete (KEYBOX_HANDLE hd);
/*-- --*/
#if 0
int keybox_lock (KEYBOX_HANDLE hd, int yes);
int keybox_get_keyblock (KEYBOX_HANDLE hd, KBNODE *ret_kb);
int keybox_locate_writable (KEYBOX_HANDLE hd);
int keybox_search_reset (KEYBOX_HANDLE hd);
int keybox_search (KEYBOX_HANDLE hd, KEYDB_SEARCH_DESC *desc, size_t ndesc);
int keybox_rebuild_cache (void *);
#endif
/*-- keybox-util.c --*/
void keybox_set_malloc_hooks ( void *(*new_alloc_func)(size_t n),
void *(*new_realloc_func)(void *p, size_t n),
void (*new_free_func)(void*) );
/*-- keybox-errors.c (built) --*/
const char *keybox_strerror (KeyboxError err);
#ifdef __cplusplus
}
#endif
#endif /*KEYBOX_H*/
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, May 10, 8:26 AM (1 d, 7 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
ef/24/04b1e7711c2162b46476a72a9f0f
Attached To
rG GnuPG
Event Timeline
Log In to Comment