summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--g10/ChangeLog5
-rw-r--r--g10/kbx.h26
-rw-r--r--g10/kbxblob.c562
-rw-r--r--tools/ChangeLog1
4 files changed, 593 insertions, 1 deletions
diff --git a/g10/ChangeLog b/g10/ChangeLog
index 9dfd16b54..21b24880e 100644
--- a/g10/ChangeLog
+++ b/g10/ChangeLog
@@ -1,3 +1,8 @@
+Mon Feb 21 22:43:01 CET 2000 Werner Koch <wk@>
+
+ * kbx.h: New.
+ * kbxblob.c: Started to work on the keybox stuff.
+
Mon Jan 31 16:37:34 CET 2000 Werner Koch <wk@gnupg.de>
* keygen.c (gen_dsa): Modified to work with gcry_pk_genkey.
diff --git a/g10/kbx.h b/g10/kbx.h
new file mode 100644
index 000000000..9e61ebbd0
--- /dev/null
+++ b/g10/kbx.h
@@ -0,0 +1,26 @@
+/* kbx.h - The GnuPG Keybox
+ * Copyright (C) 2000 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 GPG_KBX_H
+#define GPG_KBX_H 1
+
+
+
+#endif /*GPG_KBX_H*/
diff --git a/g10/kbxblob.c b/g10/kbxblob.c
new file mode 100644
index 000000000..cf3bb7a22
--- /dev/null
+++ b/g10/kbxblob.c
@@ -0,0 +1,562 @@
+/* kbxblob.c - KBX Blob handling
+ * Copyright (C) 2000 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
+ *
+ ***********************************************
+ * adler_cksum() is based on the zlib code with these conditions:
+ *
+ * Copyright (C) 1995-1998 Mark Adler
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+
+
+/* The keybox data formats
+
+The KeyBox uses an augmented OpenPGP key format. This makes random
+access to a keyblock 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
+ u32 magic 'KBXf'
+ byte version number (1)
+ b[3] reserved
+ byte marginals used for validity calculation of this file
+ byte completes ditto.
+ byte cert_depth ditto.
+
+The standard KBX Blob looks like this:
+
+ u32 length of this blob (including these 4 bytes)
+ byte version number (1)
+ byte reserved
+ u16 Blob flags
+ bit 0 = contains secret key material
+
+ u32 offset to the OpenPGP keyblock
+ u32 length of the keyblock
+ u16 number of keys (at least 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)
+ u16 special key flags
+ bit 0 =
+ u16 reserved
+ 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
+ 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
+ u8 all_validity
+ u16 reserved
+ u32 recheck_after
+ 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 sigture here later.
+
+ u32 adler checksum
+ *
+ */
+
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <gcrypt.h>
+
+#include "kbx.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))
+
+#if MAX_FINGERPRINT_LEN < 20
+ #error fingerprints are 20 bytes
+#endif
+
+struct kbxblob_key {
+ char fpr[20];
+ u32 off_kid;
+ ulong off_kid_addr; /* where it is stored in the datablock */
+ u16 flags;
+};
+struct kbxblob_uid {
+ u32 off;
+ ulong off_addr; /* where it is stored in the datablock */
+ u32 len;
+ u16 flags;
+ byte validity
+};
+
+struct keyid_list {
+ struct keyid_list *next;
+ int seqno;
+ char kid[8];
+}
+
+struct kbxblob {
+ int nkeys;
+ struct kbxblob_key *keys;
+ int nuids;
+ struct kbxblob_uid *uids;
+ int nsigs;
+ u32 *sigs;
+
+ struct keyid_list *temp_kids;
+} *KBXBLOB;
+
+
+static u32
+adler_cksum ( const byte *buf, size_t len )
+{
+ unsigned long s1 = 1;
+ unsigned long s2 = 0;
+
+ #define X_BASE 65521L /* largest prime smaller than 65536 */
+ #define X_NMAX 5552 /* largest n such that */
+ /* 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+ #define X_DO1(buf,i) {s1 += buf[i]; s2 += s1;}
+ #define X_DO2(buf,i) X_DO1(buf,i); X_DO1(buf,i+1);
+ #define X_DO4(buf,i) X_DO2(buf,i); X_DO2(buf,i+2);
+ #define X_DO8(buf,i) X_DO4(buf,i); X_DO4(buf,i+4);
+ #define X_DO16(buf) X_DO8(buf,0); X_DO8(buf,8);
+ while ( len ) {
+ int k = len < NMAX ? len : NMAX;
+ len -= k;
+ while ( k >= 16 ) {
+ DO16(buf);
+ buf += 16;
+ k -= 16;
+ }
+ if ( k ) {
+ do {
+ s1 += *buf++;
+ s2 += s1;
+ } while ( --k );
+ }
+ s1 %= BASE;
+ s2 %= BASE;
+ }
+ #undef X_BASE
+ #undef X_NMAX
+ #undef X_DO1
+ #undef X_DO2
+ #undef X_DO4
+ #undef X_DO8
+ #undef X_DO16
+ return ( s2 << 16 ) | s1;
+}
+
+
+/* Note: this functions are only used for temportay iobufs and therefore
+ * they can't fail */
+static void
+put8 ( IOBUF out, byte a )
+{
+ iobuf_put ( out, a )
+}
+
+static void
+put16 ( IOBUF out, u16 a )
+{
+ iobuf_put ( out, a>>8 );
+ iobuf_put ( out, a )
+}
+
+static void
+put32 ( IOBUF out, u32 a )
+{
+ iobuf_put (out, a>> 24);
+ iobuf_put (out, a>> 16);
+ iobuf_put (out, a>> 8);
+ iobuf_put (out, a) )
+}
+
+static void
+putn ( IOBUF out, const byte *p, size_t n )
+{
+ for ( ; n; p++, n-- ) {
+ iobuf_put ( out, *p );
+ }
+}
+
+/****************
+ * special version of put 32, which is used to fixup a value at file offset OFF
+ */
+static void
+put32at ( IOBUF out, u32 a, size_t pos )
+{
+ size_t n;
+ byte *p,
+
+ iobuf_flush_temp ( out );
+ p = iobuf_get_temp_buffer( out );
+ n = iobuf_get_temp_length( out );
+ assert( n >= pos+4 );
+ p[0] = a >> 24 ;
+ p[1] = a >> 16 ;
+ p[2] = a >> 8 ;
+ p[3] = a ;
+}
+
+
+/****************
+ * We must store the keyid at some place becuase we can't calculate the
+ * offset yet. This is only used for v3 keyIDs. Function returns an index
+ * value for later fixupd; this must be a non-zero value
+ */
+static int
+temp_store_kid ( KBXBLOB blob, PKT_public_key *pk )
+{
+ struct keyid_list *k, *r;
+
+ k = gcry_xmalloc ( sizeof *k );
+ k->kid = pk->keyid;
+ 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 void
+put_stored_kid( IOBUF a, KBXBLOB blob, int seqno )
+{
+ struct keyid_list *r;
+
+ for ( r = blob->temp_kids; r; r = r->next ) {
+ if( r->seqno == seqno ) {
+ putn ( a, r->kid, 8 );
+ return;
+ }
+ }
+ BUG();
+}
+
+static int
+release_kid_list ( struct keyid_list *kl )
+{
+ struct keyid_list *r, *r2;
+
+ for ( r = blob->temp_kids; r; r = r2 ) {
+ r2 = r->next;
+ gcry_free( r );
+ }
+}
+
+
+static int
+create_key_part( KBXBLOB blob, KBNODE keyblock )
+{
+ KBNODE node;
+ byte fpr[MAX_FINGERPRINT_LEN];
+ 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;
+
+ fingerprint_from_pk( pk, blob->keys[n].fpr, &fprlen );
+ if ( fprlen != 20 ) { /*v3 fpr - shift right and fill with zeroes*/
+ assert( fprlen == 16 );
+ memmove( blob->keys[n]+4, blob->keys[n].fpr, 16);
+ memset( blob->keys[n].fpr, 0, 4 );
+ blob->keys[n].off_kid = 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 ) {
+ BUG(); /* not yet implemented */
+ }
+ }
+ assert( n == blob->nkeys );
+ return 0;
+}
+
+static int
+create_uid_part( KBXBLOB 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].off = 0; /* must calculate this later */
+ 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
+create_sig_part( KBXBLOB 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
+create_blob_header( IOBUF a, KBXBLOB blob )
+{
+ int i;
+
+ put32 ( a, 0 ); /* blob length, needs fixup */
+ put8 ( a, 1 ); /* version number */
+ put8 ( a, 0 ); /* reserved */
+ put16 ( a, 0 ); /* blob flags */
+
+ put32 ( a, 0 ); /* offset to the keyblock, needs fixup */
+ put32 ( a, 0 ); /* length of the keyblock, needs fixup */
+
+ put16 ( a, blob->nkeys );
+ put16 ( a, 20 + 8 + 2 + 2 ); /* size of key info */
+ for ( i=0; i < blob->nkeys; i++ ) {
+ putn ( a, blob->keys[i].fpr, 20 );
+ blob->keys[i].off_kid_addr = iobuf_tell ( out );
+ put32 ( a, 0 ); /* offset to keyid, fixed up later */
+ put16 ( a, blob->keys[i].flags );
+ put16 ( a, 0 ); /* reserved */
+ }
+
+ 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 = iobuf_tell ( out );
+ 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 ); /* size of reserved space */
+ /* reserved space (which is currently 0) */
+
+ /* We need to store the keyids for all 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 */
+ put32at ( a, iobuf_tell(), blob->keys[i].off_kid_addr );
+ put_stored_kid ( a, blob, blob->keys[i].off_kid );
+ }
+ else { /* the better v4 key IDs - just store an offset 8 bytes back */
+ put32at ( a, blob->keys[i].off_kid_addr-8,
+ blob->keys[i].off_kid_addr );
+ }
+ }
+
+
+ return 0;
+}
+
+static int
+create_blob_keyblock( IOBUF a, KBXBLOB blob, KBNODE keyblock )
+{
+ KBNODE node;
+ int rc;
+
+ for ( node = keyblock; node; node = node->next ) {
+ /* we must get some offset into thge keyblock and do some
+ * fixups */
+ rc = build_packet ( fp, node->pkt );
+ if ( rc ) {
+ log_error("build_packet(%d) for kbxblob failed: %s\n",
+ node->pkt->pkttype, gpg_errstr(rc) );
+ return GPGERR_WRITE_FILE;
+ }
+ }
+ return 0;
+}
+
+static int
+create_blob_trailer( IOBUF a, KBXBLOB blob )
+{
+ return 0;
+}
+
+static int
+create_blob_finish( IOBUF a, KBXBLOB blob )
+{
+
+
+ /* fixup the length */
+ /* optionally we could sign the whole stuff at this point */
+ /* write the checksum */
+ return 0;
+}
+
+
+int
+kbx_create_blob ( KBXBLOB *retkbx, KBNODE keyblock )
+{
+ int rc = 0;
+ KBNODE node;
+ struct kbxblob *blob;
+ int nkey, nuid, nsig;
+ IOBUF a = NULL;
+
+ *retkbx = NULL;
+ blob = gcry_calloc (1, sizeof *blob );
+ if( !blob )
+ return GCRYERR_NO_MEM;
+
+ /* 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;
+ }
+ }
+ blob->nkeys = gcry_calloc ( blob->nkeys, sizeof ( blob->keys ) );
+ blob->nuids = gcry_calloc ( blob->nuids, sizeof ( blob->uids ) );
+ blob->nsigs = gcry_calloc ( blob->nsigs, sizeof ( blob->sigs ) );
+ if ( !blob->nkeys || !blob->nuids || !blob->nsigs ) {
+ rc = GCRYERR_NO_MEM;
+ goto leave;
+ }
+
+ rc = create_key_part ( blob, keyblock ),
+ if( rc )
+ goto leave;
+ rc = create_uid_part ( blob, keyblock ),
+ if( rc )
+ goto leave;
+ rc = create_sig_part ( blob, keyblock ),
+ if( rc )
+ goto leave;
+
+ a = iobuf_temp();
+ rc = create_blob_header ( a, blob );
+ if( rc )
+ goto leave;
+ rc = create_blob_keyblock ( a, blob, keyblock );
+ if( rc )
+ goto leave;
+ rc = create_blob_trailer ( a, blob );
+ if( rc )
+ goto leave;
+ rc = create_blob_finish ( a, blob );
+ if( rc )
+ goto leave;
+
+ /* now we take the iobuf and copy it to the output */
+
+ *retkbx = blob;
+
+ failure:
+ if( a )
+ iobuf_cancel( a );
+ release_kid_list( blob->temp_kids );
+ if ( rc ) {
+ gcry_free( blob->nkeys );
+ gcry_free( blob->nuids );
+ gcry_free( blob->nsigs );
+ gcry_free( blob );
+ }
+ return rc;
+}
+
+
diff --git a/tools/ChangeLog b/tools/ChangeLog
index a5566e84b..0227d0721 100644
--- a/tools/ChangeLog
+++ b/tools/ChangeLog
@@ -6,7 +6,6 @@ Mon Jan 31 17:46:35 CET 2000 Werner Koch <wk@>
Thu Jul 8 16:21:27 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
-
* lspgpot: New
Wed Jul 7 13:08:40 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>