|
|
@@ -1,2303 +0,0 @@
|
|
|
-/* keydb.c - Key database routines
|
|
|
- * Copyright (C) 2002, 2003, 2007 Timo Schulz
|
|
|
- *
|
|
|
- * This file is part of OpenCDK.
|
|
|
- *
|
|
|
- * OpenCDK 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.
|
|
|
- *
|
|
|
- * OpenCDK 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.
|
|
|
- */
|
|
|
-#ifdef HAVE_CONFIG_H
|
|
|
-# include <config.h>
|
|
|
-#endif
|
|
|
-#include <sys/stat.h>
|
|
|
-#include <stdio.h>
|
|
|
-#include <stdlib.h>
|
|
|
-#include <string.h>
|
|
|
-#include <time.h>
|
|
|
-#include <ctype.h>
|
|
|
-
|
|
|
-#include "opencdk.h"
|
|
|
-#include "main.h"
|
|
|
-#include "packet.h"
|
|
|
-#include "filters.h"
|
|
|
-#include "stream.h"
|
|
|
-
|
|
|
-
|
|
|
-#define KEYID_CMP(a, b) ((a[0]) == (b[0]) && (a[1]) == (b[1]))
|
|
|
-#define KEYDB_CACHE_ENTRIES 8
|
|
|
-
|
|
|
-
|
|
|
-/* Internal key index structure. */
|
|
|
-struct key_idx_s
|
|
|
-{
|
|
|
- off_t offset;
|
|
|
- u32 keyid[2];
|
|
|
- byte fpr[KEY_FPR_LEN];
|
|
|
-};
|
|
|
-typedef struct key_idx_s *key_idx_t;
|
|
|
-
|
|
|
-
|
|
|
-/* Internal handle for the search operation. */
|
|
|
-struct cdk_dbsearch_s
|
|
|
-{
|
|
|
- union
|
|
|
- {
|
|
|
- char *pattern; /* A search is performed by pattern. */
|
|
|
- u32 keyid[2]; /* A search by keyid. */
|
|
|
- byte fpr[KEY_FPR_LEN]; /* A search by fingerprint. */
|
|
|
- } u;
|
|
|
- int type;
|
|
|
-};
|
|
|
-typedef struct cdk_dbsearch_s *cdk_dbsearch_t;
|
|
|
-
|
|
|
-/* Internal key cache to associate a key with an file offset. */
|
|
|
-struct key_table_s
|
|
|
-{
|
|
|
- struct key_table_s *next;
|
|
|
- off_t offset;
|
|
|
- cdk_dbsearch_t desc;
|
|
|
-};
|
|
|
-typedef struct key_table_s *key_table_t;
|
|
|
-
|
|
|
-/* Internal key database handle. */
|
|
|
-struct cdk_keydb_hd_s
|
|
|
-{
|
|
|
- int type; /* type of the key db handle. */
|
|
|
- int fp_ref; /* 1=means it is a reference and shall not be closed. */
|
|
|
- cdk_stream_t fp;
|
|
|
- cdk_stream_t idx;
|
|
|
- cdk_dbsearch_t dbs;
|
|
|
- char *name; /* name of the underlying file or NULL. */
|
|
|
- char *idx_name; /* name of the index file or NULL. */
|
|
|
- struct key_table_s *cache;
|
|
|
- size_t ncache;
|
|
|
- unsigned int secret:1; /* contain secret keys. */
|
|
|
- unsigned int isopen:1; /* the underlying stream is opened. */
|
|
|
- unsigned int no_cache:1; /* disable the index cache. */
|
|
|
- unsigned int search:1; /* handle is in search mode. */
|
|
|
-
|
|
|
- /* structure to store some stats about the keydb. */
|
|
|
- struct
|
|
|
- {
|
|
|
- size_t new_keys; /* amount of new keys that were imported. */
|
|
|
- } stats;
|
|
|
-};
|
|
|
-
|
|
|
-
|
|
|
-static void keydb_cache_free (key_table_t cache);
|
|
|
-static int keydb_search_copy (cdk_dbsearch_t * r_dst, cdk_dbsearch_t src);
|
|
|
-static void keydb_search_free (cdk_dbsearch_t dbs);
|
|
|
-static int classify_data (const byte * buf, size_t len);
|
|
|
-static cdk_kbnode_t find_selfsig_node (cdk_kbnode_t key, cdk_pkt_pubkey_t pk);
|
|
|
-
|
|
|
-
|
|
|
-static char *
|
|
|
-keydb_idx_mkname (const char *file)
|
|
|
-{
|
|
|
- char *fname, *fmt;
|
|
|
-
|
|
|
- fmt = "%s.idx";
|
|
|
- fname = cdk_calloc (1, strlen (file) + strlen (fmt) + 1);
|
|
|
- if (!fname)
|
|
|
- return NULL;
|
|
|
- sprintf (fname, fmt, file);
|
|
|
- return fname;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/* This functions builds an index of the keyring into a separate file
|
|
|
- with the name keyring.ext.idx. It contains the offset of all public-
|
|
|
- and public subkeys. The format of the file is:
|
|
|
- --------
|
|
|
- 4 octets offset of the packet
|
|
|
- 8 octets keyid
|
|
|
- 20 octets fingerprint
|
|
|
- --------
|
|
|
- We store the keyid and the fingerprint due to the fact we can't get
|
|
|
- the keyid from a v3 fingerprint directly.
|
|
|
-*/
|
|
|
-static cdk_error_t
|
|
|
-keydb_idx_build (const char *file)
|
|
|
-{
|
|
|
- cdk_packet_t pkt;
|
|
|
- cdk_stream_t inp, out = NULL;
|
|
|
- byte buf[4 + 8 + KEY_FPR_LEN];
|
|
|
- char *idx_name;
|
|
|
- u32 keyid[2];
|
|
|
- cdk_error_t rc;
|
|
|
-
|
|
|
- if (!file)
|
|
|
- return CDK_Inv_Value;
|
|
|
-
|
|
|
- rc = cdk_stream_open (file, &inp);
|
|
|
- if (rc)
|
|
|
- return rc;
|
|
|
-
|
|
|
- idx_name = keydb_idx_mkname (file);
|
|
|
- if (!idx_name)
|
|
|
- {
|
|
|
- cdk_stream_close (inp);
|
|
|
- return CDK_Out_Of_Core;
|
|
|
- }
|
|
|
- rc = cdk_stream_create (idx_name, &out);
|
|
|
- cdk_free (idx_name);
|
|
|
- if (rc)
|
|
|
- {
|
|
|
- cdk_stream_close (inp);
|
|
|
- return rc;
|
|
|
- }
|
|
|
-
|
|
|
- cdk_pkt_new (&pkt);
|
|
|
- while (!cdk_stream_eof (inp))
|
|
|
- {
|
|
|
- off_t pos = cdk_stream_tell (inp);
|
|
|
-
|
|
|
- rc = cdk_pkt_read (inp, pkt);
|
|
|
- if (rc)
|
|
|
- {
|
|
|
- _cdk_log_debug ("index build failed packet off=%lu\n", pos);
|
|
|
- /* FIXME: The index is incomplete */
|
|
|
- break;
|
|
|
- }
|
|
|
- if (pkt->pkttype == CDK_PKT_PUBLIC_KEY ||
|
|
|
- pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY)
|
|
|
- {
|
|
|
- _cdk_u32tobuf (pos, buf);
|
|
|
- cdk_pk_get_keyid (pkt->pkt.public_key, keyid);
|
|
|
- _cdk_u32tobuf (keyid[0], buf + 4);
|
|
|
- _cdk_u32tobuf (keyid[1], buf + 8);
|
|
|
- cdk_pk_get_fingerprint (pkt->pkt.public_key, buf + 12);
|
|
|
- cdk_stream_write (out, buf, 4 + 8 + KEY_FPR_LEN);
|
|
|
- }
|
|
|
- cdk_pkt_free (pkt);
|
|
|
- }
|
|
|
-
|
|
|
- cdk_pkt_release (pkt);
|
|
|
-
|
|
|
- cdk_stream_close (out);
|
|
|
- cdk_stream_close (inp);
|
|
|
- return rc;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/**
|
|
|
- * cdk_keydb_idx_rebuild:
|
|
|
- * @hd: key database handle
|
|
|
- *
|
|
|
- * Rebuild the key index files for the given key database.
|
|
|
- **/
|
|
|
-cdk_error_t
|
|
|
-cdk_keydb_idx_rebuild (cdk_keydb_hd_t db)
|
|
|
-{
|
|
|
- struct stat stbuf;
|
|
|
- char *tmp_idx_name;
|
|
|
- cdk_error_t rc;
|
|
|
- int err;
|
|
|
-
|
|
|
- if (!db || !db->name)
|
|
|
- return CDK_Inv_Value;
|
|
|
- if (db->secret)
|
|
|
- return 0;
|
|
|
-
|
|
|
- tmp_idx_name = keydb_idx_mkname (db->name);
|
|
|
- if (!tmp_idx_name)
|
|
|
- return CDK_Out_Of_Core;
|
|
|
- err = stat (tmp_idx_name, &stbuf);
|
|
|
- cdk_free (tmp_idx_name);
|
|
|
- /* This function expects an existing index which can be rebuild,
|
|
|
- if no index exists we do not build one and just return. */
|
|
|
- if (err)
|
|
|
- return 0;
|
|
|
-
|
|
|
- cdk_stream_close (db->idx);
|
|
|
- db->idx = NULL;
|
|
|
- if (!db->idx_name)
|
|
|
- {
|
|
|
- db->idx_name = keydb_idx_mkname (db->name);
|
|
|
- if (!db->idx_name)
|
|
|
- return CDK_Out_Of_Core;
|
|
|
- }
|
|
|
- rc = keydb_idx_build (db->name);
|
|
|
- if (!rc)
|
|
|
- rc = cdk_stream_open (db->idx_name, &db->idx);
|
|
|
- return rc;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-static cdk_error_t
|
|
|
-keydb_idx_parse (cdk_stream_t inp, key_idx_t * r_idx)
|
|
|
-{
|
|
|
- key_idx_t idx;
|
|
|
- byte buf[4];
|
|
|
-
|
|
|
- if (!inp || !r_idx)
|
|
|
- return CDK_Inv_Value;
|
|
|
-
|
|
|
- idx = cdk_calloc (1, sizeof *idx);
|
|
|
- if (!idx)
|
|
|
- return CDK_Out_Of_Core;
|
|
|
-
|
|
|
- while (!cdk_stream_eof (inp))
|
|
|
- {
|
|
|
- if (cdk_stream_read (inp, buf, 4) == CDK_EOF)
|
|
|
- break;
|
|
|
- idx->offset = _cdk_buftou32 (buf);
|
|
|
- cdk_stream_read (inp, buf, 4);
|
|
|
- idx->keyid[0] = _cdk_buftou32 (buf);
|
|
|
- cdk_stream_read (inp, buf, 4);
|
|
|
- idx->keyid[1] = _cdk_buftou32 (buf);
|
|
|
- cdk_stream_read (inp, idx->fpr, KEY_FPR_LEN);
|
|
|
- break;
|
|
|
- }
|
|
|
- *r_idx = idx;
|
|
|
- return cdk_stream_eof (inp) ? CDK_EOF : 0;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-static cdk_error_t
|
|
|
-keydb_idx_search (cdk_stream_t inp, u32 * keyid, const byte * fpr,
|
|
|
- off_t * r_off)
|
|
|
-{
|
|
|
- key_idx_t idx;
|
|
|
-
|
|
|
- if (!inp || !r_off)
|
|
|
- return CDK_Inv_Value;
|
|
|
- if ((keyid && fpr) || (!keyid && !fpr))
|
|
|
- return CDK_Inv_Mode;
|
|
|
-
|
|
|
- /* We need an initialize the offset var with a value
|
|
|
- because it might be possible the returned offset will
|
|
|
- be 0 and then we cannot differ between the begin and an EOF. */
|
|
|
- *r_off = 0xFFFFFFFF;
|
|
|
- cdk_stream_seek (inp, 0);
|
|
|
- while (keydb_idx_parse (inp, &idx) != CDK_EOF)
|
|
|
- {
|
|
|
- if (keyid && KEYID_CMP (keyid, idx->keyid))
|
|
|
- {
|
|
|
- *r_off = idx->offset;
|
|
|
- break;
|
|
|
- }
|
|
|
- else if (fpr && !memcmp (idx->fpr, fpr, KEY_FPR_LEN))
|
|
|
- {
|
|
|
- *r_off = idx->offset;
|
|
|
- break;
|
|
|
- }
|
|
|
- cdk_free (idx);
|
|
|
- idx = NULL;
|
|
|
- }
|
|
|
- cdk_free (idx);
|
|
|
- return *r_off != 0xFFFFFFFF ? 0 : CDK_EOF;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/**
|
|
|
- * cdk_keydb_new_from_mem:
|
|
|
- * @r_hd: The keydb output handle.
|
|
|
- * @data: The raw key data.
|
|
|
- * @datlen: The length of the raw data.
|
|
|
- *
|
|
|
- * Create a new keyring db handle from the contents of a buffer.
|
|
|
- */
|
|
|
-cdk_error_t
|
|
|
-cdk_keydb_new_from_mem (cdk_keydb_hd_t * r_db, int secret,
|
|
|
- const void *data, size_t datlen)
|
|
|
-{
|
|
|
- cdk_keydb_hd_t db;
|
|
|
- cdk_error_t rc;
|
|
|
-
|
|
|
- if (!r_db)
|
|
|
- return CDK_Inv_Value;
|
|
|
- *r_db = NULL;
|
|
|
- db = calloc (1, sizeof *db);
|
|
|
- rc = cdk_stream_tmp_from_mem (data, datlen, &db->fp);
|
|
|
- if (!db->fp)
|
|
|
- {
|
|
|
- cdk_free (db);
|
|
|
- return rc;
|
|
|
- }
|
|
|
- if (cdk_armor_filter_use (db->fp))
|
|
|
- cdk_stream_set_armor_flag (db->fp, 0);
|
|
|
- db->type = CDK_DBTYPE_DATA;
|
|
|
- db->secret = secret;
|
|
|
- *r_db = db;
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/**
|
|
|
- * cdk_keydb_new_from_stream:
|
|
|
- * @r_hd: the output keydb handle
|
|
|
- * @secret: does the stream contain secret key data
|
|
|
- * @in: the input stream to use
|
|
|
- *
|
|
|
- * This function creates a new keydb handle based on the given
|
|
|
- * stream. The stream is not closed in cdk_keydb_free() and it
|
|
|
- * is up to the caller to close it. No decoding is done.
|
|
|
- */
|
|
|
-cdk_error_t
|
|
|
-cdk_keydb_new_from_stream (cdk_keydb_hd_t * r_hd, int secret, cdk_stream_t in)
|
|
|
-{
|
|
|
- cdk_keydb_hd_t hd;
|
|
|
-
|
|
|
- if (!r_hd)
|
|
|
- return CDK_Inv_Value;
|
|
|
- *r_hd = NULL;
|
|
|
-
|
|
|
- hd = calloc (1, sizeof *hd);
|
|
|
- hd->fp = in;
|
|
|
- hd->fp_ref = 1;
|
|
|
- hd->type = CDK_DBTYPE_STREAM;
|
|
|
- hd->secret = secret;
|
|
|
- *r_hd = hd;
|
|
|
-
|
|
|
- /* We do not push any filters and thus we expect that the format
|
|
|
- of the stream has the format the user wanted. */
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-cdk_error_t
|
|
|
-cdk_keydb_new_from_file (cdk_keydb_hd_t * r_hd, int secret, const char *fname)
|
|
|
-{
|
|
|
- cdk_keydb_hd_t hd;
|
|
|
-
|
|
|
- if (!r_hd)
|
|
|
- return CDK_Inv_Value;
|
|
|
- *r_hd = NULL;
|
|
|
- hd = calloc (1, sizeof *hd);
|
|
|
- hd->name = cdk_strdup (fname);
|
|
|
- if (!hd->name)
|
|
|
- {
|
|
|
- cdk_free (hd);
|
|
|
- return CDK_Out_Of_Core;
|
|
|
- }
|
|
|
- hd->type = secret ? CDK_DBTYPE_SK_KEYRING : CDK_DBTYPE_PK_KEYRING;
|
|
|
- hd->secret = secret;
|
|
|
- *r_hd = hd;
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-/**
|
|
|
- * cdk_keydb_new:
|
|
|
- * @r_hd: handle to store the new keydb object
|
|
|
- * @type: type of the keyring
|
|
|
- * @data: data which depends on the keyring type
|
|
|
- * @count: length of the data
|
|
|
- *
|
|
|
- * Create a new keydb object
|
|
|
- **/
|
|
|
-cdk_error_t
|
|
|
-cdk_keydb_new (cdk_keydb_hd_t * r_hd, int type, void *data, size_t count)
|
|
|
-{
|
|
|
- switch (type)
|
|
|
- {
|
|
|
- case CDK_DBTYPE_PK_KEYRING:
|
|
|
- case CDK_DBTYPE_SK_KEYRING:
|
|
|
- return cdk_keydb_new_from_file (r_hd, type == CDK_DBTYPE_SK_KEYRING,
|
|
|
- (const char *) data);
|
|
|
-
|
|
|
- case CDK_DBTYPE_DATA:
|
|
|
- return cdk_keydb_new_from_mem (r_hd, 0, data, count);
|
|
|
-
|
|
|
- case CDK_DBTYPE_STREAM:
|
|
|
- return cdk_keydb_new_from_stream (r_hd, 0, (cdk_stream_t) data);
|
|
|
-
|
|
|
- default:
|
|
|
- return CDK_Inv_Mode;
|
|
|
- }
|
|
|
- return CDK_Inv_Mode;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/**
|
|
|
- * cdk_keydb_free:
|
|
|
- * @hd: the keydb object
|
|
|
- *
|
|
|
- * Free the keydb object.
|
|
|
- **/
|
|
|
-void
|
|
|
-cdk_keydb_free (cdk_keydb_hd_t hd)
|
|
|
-{
|
|
|
- if (!hd)
|
|
|
- return;
|
|
|
-
|
|
|
- if (hd->name)
|
|
|
- {
|
|
|
- cdk_free (hd->name);
|
|
|
- hd->name = NULL;
|
|
|
- }
|
|
|
-
|
|
|
- if (hd->fp && !hd->fp_ref)
|
|
|
- {
|
|
|
- cdk_stream_close (hd->fp);
|
|
|
- hd->fp = NULL;
|
|
|
- }
|
|
|
-
|
|
|
- if (hd->idx)
|
|
|
- {
|
|
|
- cdk_stream_close (hd->idx);
|
|
|
- hd->idx = NULL;
|
|
|
- }
|
|
|
-
|
|
|
- hd->isopen = 0;
|
|
|
- hd->no_cache = 0;
|
|
|
- hd->secret = 0;
|
|
|
- keydb_cache_free (hd->cache);
|
|
|
- hd->cache = NULL;
|
|
|
- keydb_search_free (hd->dbs);
|
|
|
- hd->dbs = NULL;
|
|
|
- cdk_free (hd);
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-cdk_error_t
|
|
|
-_cdk_keydb_open (cdk_keydb_hd_t hd, cdk_stream_t * ret_kr)
|
|
|
-{
|
|
|
- cdk_error_t rc, ec;
|
|
|
-
|
|
|
- if (!hd || !ret_kr)
|
|
|
- return CDK_Inv_Value;
|
|
|
-
|
|
|
- rc = 0;
|
|
|
- if ((hd->type == CDK_DBTYPE_DATA || hd->type == CDK_DBTYPE_STREAM)
|
|
|
- && hd->fp)
|
|
|
- cdk_stream_seek (hd->fp, 0);
|
|
|
- else if (hd->type == CDK_DBTYPE_PK_KEYRING ||
|
|
|
- hd->type == CDK_DBTYPE_SK_KEYRING)
|
|
|
- {
|
|
|
- if (!hd->isopen && hd->name)
|
|
|
- {
|
|
|
- rc = cdk_stream_open (hd->name, &hd->fp);
|
|
|
- if (rc)
|
|
|
- goto leave;
|
|
|
- if (cdk_armor_filter_use (hd->fp))
|
|
|
- cdk_stream_set_armor_flag (hd->fp, 0);
|
|
|
- hd->isopen = 1;
|
|
|
- /* We disable the index cache for smaller keyrings. */
|
|
|
- if (cdk_stream_get_length (hd->fp) < 524288)
|
|
|
- {
|
|
|
- hd->no_cache = 1;
|
|
|
- goto leave;
|
|
|
- }
|
|
|
- cdk_free (hd->idx_name);
|
|
|
- hd->idx_name = keydb_idx_mkname (hd->name);
|
|
|
- if (!hd->idx_name)
|
|
|
- {
|
|
|
- rc = CDK_Out_Of_Core;
|
|
|
- goto leave;
|
|
|
- }
|
|
|
- ec = cdk_stream_open (hd->idx_name, &hd->idx);
|
|
|
- if (ec && !hd->secret)
|
|
|
- {
|
|
|
- rc = keydb_idx_build (hd->name);
|
|
|
- if (!rc)
|
|
|
- rc = cdk_stream_open (hd->idx_name, &hd->idx);
|
|
|
- if (!rc)
|
|
|
- _cdk_log_debug ("create key index table\n");
|
|
|
- else
|
|
|
- {
|
|
|
- /* This is no real error, it just means we can't create
|
|
|
- the index at the given directory. maybe we've no write
|
|
|
- access. in this case, we simply disable the index. */
|
|
|
- _cdk_log_debug ("disable key index table err=%d\n", rc);
|
|
|
- rc = 0;
|
|
|
- hd->no_cache = 1;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- /* We use the cache to search keys, so we always rewind the
|
|
|
- STREAM. Except when the _NEXT search mode is used because
|
|
|
- this mode is an enumeration and no seeking is needed. */
|
|
|
- if (!hd->search ||
|
|
|
- (hd->search && hd->dbs->type != CDK_DBSEARCH_NEXT))
|
|
|
- cdk_stream_seek (hd->fp, 0);
|
|
|
- }
|
|
|
- }
|
|
|
- else
|
|
|
- return CDK_Inv_Mode;
|
|
|
-
|
|
|
-leave:
|
|
|
- if (rc)
|
|
|
- {
|
|
|
- cdk_stream_close (hd->fp);
|
|
|
- hd->fp = NULL;
|
|
|
- }
|
|
|
- *ret_kr = hd->fp;
|
|
|
- return rc;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-static int
|
|
|
-find_by_keyid (cdk_kbnode_t knode, cdk_dbsearch_t ks)
|
|
|
-{
|
|
|
- cdk_kbnode_t node;
|
|
|
- u32 keyid[2];
|
|
|
-
|
|
|
- for (node = knode; node; node = node->next)
|
|
|
- {
|
|
|
- if (node->pkt->pkttype == CDK_PKT_PUBLIC_KEY ||
|
|
|
- node->pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY ||
|
|
|
- node->pkt->pkttype == CDK_PKT_SECRET_KEY ||
|
|
|
- node->pkt->pkttype == CDK_PKT_SECRET_SUBKEY)
|
|
|
- {
|
|
|
- _cdk_pkt_get_keyid (node->pkt, keyid);
|
|
|
- switch (ks->type)
|
|
|
- {
|
|
|
- case CDK_DBSEARCH_SHORT_KEYID:
|
|
|
- if (keyid[1] == ks->u.keyid[1])
|
|
|
- return 1;
|
|
|
- break;
|
|
|
-
|
|
|
- case CDK_DBSEARCH_KEYID:
|
|
|
- if (KEYID_CMP (keyid, ks->u.keyid))
|
|
|
- return 1;
|
|
|
- break;
|
|
|
-
|
|
|
- default:
|
|
|
- _cdk_log_debug ("find_by_keyid: invalid mode = %d\n", ks->type);
|
|
|
- return 0;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-static int
|
|
|
-find_by_fpr (cdk_kbnode_t knode, cdk_dbsearch_t ks)
|
|
|
-{
|
|
|
- cdk_kbnode_t node;
|
|
|
- byte fpr[KEY_FPR_LEN];
|
|
|
-
|
|
|
- if (ks->type != CDK_DBSEARCH_FPR)
|
|
|
- return 0;
|
|
|
-
|
|
|
- for (node = knode; node; node = node->next)
|
|
|
- {
|
|
|
- if (node->pkt->pkttype == CDK_PKT_PUBLIC_KEY ||
|
|
|
- node->pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY ||
|
|
|
- node->pkt->pkttype == CDK_PKT_SECRET_KEY ||
|
|
|
- node->pkt->pkttype == CDK_PKT_SECRET_SUBKEY)
|
|
|
- {
|
|
|
- _cdk_pkt_get_fingerprint (node->pkt, fpr);
|
|
|
- if (!memcmp (ks->u.fpr, fpr, KEY_FPR_LEN))
|
|
|
- return 1;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-static int
|
|
|
-find_by_pattern (cdk_kbnode_t knode, cdk_dbsearch_t ks)
|
|
|
-{
|
|
|
- cdk_kbnode_t node;
|
|
|
- size_t uidlen;
|
|
|
- char *name;
|
|
|
-
|
|
|
- for (node = knode; node; node = node->next)
|
|
|
- {
|
|
|
- if (node->pkt->pkttype != CDK_PKT_USER_ID)
|
|
|
- continue;
|
|
|
- if (node->pkt->pkt.user_id->attrib_img != NULL)
|
|
|
- continue; /* Skip attribute packets. */
|
|
|
- uidlen = node->pkt->pkt.user_id->len;
|
|
|
- name = node->pkt->pkt.user_id->name;
|
|
|
- switch (ks->type)
|
|
|
- {
|
|
|
- case CDK_DBSEARCH_EXACT:
|
|
|
- if (name &&
|
|
|
- (strlen (ks->u.pattern) == uidlen &&
|
|
|
- !strncmp (ks->u.pattern, name, uidlen)))
|
|
|
- return 1;
|
|
|
- break;
|
|
|
-
|
|
|
- case CDK_DBSEARCH_SUBSTR:
|
|
|
- if (uidlen > 65536)
|
|
|
- break;
|
|
|
- if (name && strlen (ks->u.pattern) > uidlen)
|
|
|
- break;
|
|
|
- if (name && _cdk_memistr (name, uidlen, ks->u.pattern))
|
|
|
- return 1;
|
|
|
- break;
|
|
|
-
|
|
|
- default: /* Invalid mode */
|
|
|
- return 0;
|
|
|
- }
|
|
|
- }
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-static void
|
|
|
-keydb_search_free (cdk_dbsearch_t dbs)
|
|
|
-{
|
|
|
- if (!dbs)
|
|
|
- return;
|
|
|
- if (dbs->type == CDK_DBSEARCH_EXACT || dbs->type == CDK_DBSEARCH_SUBSTR)
|
|
|
- cdk_free (dbs->u.pattern);
|
|
|
- dbs->type = 0;
|
|
|
- cdk_free (dbs);
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-static void
|
|
|
-keydb_cache_free (key_table_t cache)
|
|
|
-{
|
|
|
- key_table_t c2;
|
|
|
-
|
|
|
- while (cache)
|
|
|
- {
|
|
|
- c2 = cache->next;
|
|
|
- cache->offset = 0;
|
|
|
- keydb_search_free (cache->desc);
|
|
|
- cdk_free (cache);
|
|
|
- cache = c2;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-static key_table_t
|
|
|
-keydb_cache_find (key_table_t cache, cdk_dbsearch_t desc)
|
|
|
-{
|
|
|
- key_table_t t;
|
|
|
-
|
|
|
- for (t = cache; t; t = t->next)
|
|
|
- {
|
|
|
- if (t->desc->type != desc->type)
|
|
|
- continue;
|
|
|
- switch (t->desc->type)
|
|
|
- {
|
|
|
- case CDK_DBSEARCH_SHORT_KEYID:
|
|
|
- case CDK_DBSEARCH_KEYID:
|
|
|
- if (KEYID_CMP (t->desc->u.keyid, desc->u.keyid))
|
|
|
- return t;
|
|
|
- break;
|
|
|
-
|
|
|
- case CDK_DBSEARCH_EXACT:
|
|
|
- if (strlen (t->desc->u.pattern) == strlen (desc->u.pattern) &&
|
|
|
- !strcmp (t->desc->u.pattern, desc->u.pattern))
|
|
|
- return t;
|
|
|
- break;
|
|
|
-
|
|
|
- case CDK_DBSEARCH_SUBSTR:
|
|
|
- if (strstr (t->desc->u.pattern, desc->u.pattern))
|
|
|
- return t;
|
|
|
- break;
|
|
|
-
|
|
|
- case CDK_DBSEARCH_FPR:
|
|
|
- if (!memcmp (t->desc->u.fpr, desc->u.fpr, KEY_FPR_LEN))
|
|
|
- return t;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return NULL;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-static cdk_error_t
|
|
|
-keydb_cache_add (cdk_keydb_hd_t hd, cdk_dbsearch_t dbs, off_t offset)
|
|
|
-{
|
|
|
- key_table_t k;
|
|
|
-
|
|
|
- if (!hd)
|
|
|
- return CDK_Inv_Value;
|
|
|
-
|
|
|
- if (hd->ncache > KEYDB_CACHE_ENTRIES)
|
|
|
- return 0; /* FIXME: we should replace the last entry. */
|
|
|
- k = cdk_calloc (1, sizeof *k);
|
|
|
- if (!k)
|
|
|
- return CDK_Out_Of_Core;
|
|
|
- k->offset = offset;
|
|
|
- keydb_search_copy (&k->desc, dbs);
|
|
|
- k->next = hd->cache;
|
|
|
- hd->cache = k;
|
|
|
- hd->ncache++;
|
|
|
- _cdk_log_debug ("cache: add entry off=%d type=%d\n", offset, dbs->type);
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-static cdk_error_t
|
|
|
-keydb_search_copy (cdk_dbsearch_t * r_dst, cdk_dbsearch_t src)
|
|
|
-{
|
|
|
- cdk_dbsearch_t dst;
|
|
|
-
|
|
|
- if (!r_dst || !src)
|
|
|
- return CDK_Inv_Value;
|
|
|
-
|
|
|
- *r_dst = NULL;
|
|
|
- dst = cdk_calloc (1, sizeof *dst);
|
|
|
- if (!dst)
|
|
|
- return CDK_Out_Of_Core;
|
|
|
- dst->type = src->type;
|
|
|
- switch (src->type)
|
|
|
- {
|
|
|
- case CDK_DBSEARCH_EXACT:
|
|
|
- case CDK_DBSEARCH_SUBSTR:
|
|
|
- dst->u.pattern = cdk_strdup (src->u.pattern);
|
|
|
- if (!dst->u.pattern)
|
|
|
- return CDK_Out_Of_Core;
|
|
|
- break;
|
|
|
-
|
|
|
- case CDK_DBSEARCH_SHORT_KEYID:
|
|
|
- case CDK_DBSEARCH_KEYID:
|
|
|
- dst->u.keyid[0] = src->u.keyid[0];
|
|
|
- dst->u.keyid[1] = src->u.keyid[1];
|
|
|
- break;
|
|
|
-
|
|
|
- case CDK_DBSEARCH_FPR:
|
|
|
- memcpy (dst->u.fpr, src->u.fpr, KEY_FPR_LEN);
|
|
|
- break;
|
|
|
- }
|
|
|
- *r_dst = dst;
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/**
|
|
|
- * cdk_keydb_search_start:
|
|
|
- * @db: key database handle
|
|
|
- * @type: specifies the search type
|
|
|
- * @desc: description which depends on the type
|
|
|
- *
|
|
|
- * Create a new keydb search object.
|
|
|
- **/
|
|
|
-cdk_error_t
|
|
|
-cdk_keydb_search_start (cdk_keydb_hd_t db, int type, void *desc)
|
|
|
-{
|
|
|
- cdk_dbsearch_t dbs;
|
|
|
- u32 *keyid;
|
|
|
- char *p, tmp[3];
|
|
|
- int i;
|
|
|
-
|
|
|
- if (!db)
|
|
|
- return CDK_Inv_Value;
|
|
|
- if (type != CDK_DBSEARCH_NEXT && !desc)
|
|
|
- return CDK_Inv_Mode;
|
|
|
-
|
|
|
- dbs = cdk_calloc (1, sizeof *dbs);
|
|
|
- if (!dbs)
|
|
|
- return CDK_Out_Of_Core;
|
|
|
- dbs->type = type;
|
|
|
- switch (type)
|
|
|
- {
|
|
|
- case CDK_DBSEARCH_EXACT:
|
|
|
- case CDK_DBSEARCH_SUBSTR:
|
|
|
- cdk_free (dbs->u.pattern);
|
|
|
- dbs->u.pattern = cdk_strdup (desc);
|
|
|
- if (!dbs->u.pattern)
|
|
|
- {
|
|
|
- cdk_free (dbs);
|
|
|
- return CDK_Out_Of_Core;
|
|
|
- }
|
|
|
- break;
|
|
|
-
|
|
|
- case CDK_DBSEARCH_SHORT_KEYID:
|
|
|
- keyid = desc;
|
|
|
- dbs->u.keyid[1] = keyid[0];
|
|
|
- break;
|
|
|
-
|
|
|
- case CDK_DBSEARCH_KEYID:
|
|
|
- keyid = desc;
|
|
|
- dbs->u.keyid[0] = keyid[0];
|
|
|
- dbs->u.keyid[1] = keyid[1];
|
|
|
- break;
|
|
|
-
|
|
|
- case CDK_DBSEARCH_FPR:
|
|
|
- memcpy (dbs->u.fpr, desc, KEY_FPR_LEN);
|
|
|
- break;
|
|
|
-
|
|
|
- case CDK_DBSEARCH_NEXT:
|
|
|
- break;
|
|
|
-
|
|
|
- case CDK_DBSEARCH_AUTO:
|
|
|
- /* Override the type with the actual db search type. */
|
|
|
- dbs->type = classify_data (desc, strlen (desc));
|
|
|
- switch (dbs->type)
|
|
|
- {
|
|
|
- case CDK_DBSEARCH_SUBSTR:
|
|
|
- case CDK_DBSEARCH_EXACT:
|
|
|
- cdk_free (dbs->u.pattern);
|
|
|
- p = dbs->u.pattern = cdk_strdup (desc);
|
|
|
- if (!p)
|
|
|
- {
|
|
|
- cdk_free (dbs);
|
|
|
- return CDK_Out_Of_Core;
|
|
|
- }
|
|
|
- break;
|
|
|
-
|
|
|
- case CDK_DBSEARCH_SHORT_KEYID:
|
|
|
- case CDK_DBSEARCH_KEYID:
|
|
|
- p = desc;
|
|
|
- if (!strncmp (p, "0x", 2))
|
|
|
- p += 2;
|
|
|
- if (strlen (p) == 8)
|
|
|
- {
|
|
|
- dbs->u.keyid[0] = 0;
|
|
|
- dbs->u.keyid[1] = strtoul (p, NULL, 16);
|
|
|
- }
|
|
|
- else if (strlen (p) == 16)
|
|
|
- {
|
|
|
- dbs->u.keyid[0] = strtoul (p, NULL, 16);
|
|
|
- dbs->u.keyid[1] = strtoul (p + 8, NULL, 16);
|
|
|
- }
|
|
|
- else
|
|
|
- { /* Invalid key ID object. */
|
|
|
- cdk_free (dbs);
|
|
|
- return CDK_Inv_Mode;
|
|
|
- }
|
|
|
- break;
|
|
|
-
|
|
|
- case CDK_DBSEARCH_FPR:
|
|
|
- p = desc;
|
|
|
- if (strlen (p) != 2 * KEY_FPR_LEN)
|
|
|
- {
|
|
|
- cdk_free (dbs);
|
|
|
- return CDK_Inv_Mode;
|
|
|
- }
|
|
|
- for (i = 0; i < KEY_FPR_LEN; i++)
|
|
|
- {
|
|
|
- tmp[0] = p[2 * i];
|
|
|
- tmp[1] = p[2 * i + 1];
|
|
|
- tmp[2] = 0x00;
|
|
|
- dbs->u.fpr[i] = strtoul (tmp, NULL, 16);
|
|
|
- }
|
|
|
- break;
|
|
|
- }
|
|
|
- break;
|
|
|
-
|
|
|
- default:
|
|
|
- cdk_free (dbs);
|
|
|
- _cdk_log_debug ("cdk_keydb_search_start: invalid mode = %d\n", type);
|
|
|
- return CDK_Inv_Mode;
|
|
|
- }
|
|
|
-
|
|
|
- keydb_search_free (db->dbs);
|
|
|
- db->dbs = dbs;
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-static cdk_error_t
|
|
|
-keydb_pos_from_cache (cdk_keydb_hd_t hd, cdk_dbsearch_t ks,
|
|
|
- int *r_cache_hit, off_t * r_off)
|
|
|
-{
|
|
|
- key_table_t c;
|
|
|
-
|
|
|
- if (!hd || !r_cache_hit || !r_off)
|
|
|
- return CDK_Inv_Value;
|
|
|
-
|
|
|
- /* Reset the values. */
|
|
|
- *r_cache_hit = 0;
|
|
|
- *r_off = 0;
|
|
|
-
|
|
|
- c = keydb_cache_find (hd->cache, ks);
|
|
|
- if (c != NULL)
|
|
|
- {
|
|
|
- _cdk_log_debug ("cache: found entry in cache.\n");
|
|
|
- *r_cache_hit = 1;
|
|
|
- *r_off = c->offset;
|
|
|
- return 0;
|
|
|
- }
|
|
|
-
|
|
|
- /* No index cache available so we just return here. */
|
|
|
- if (!hd->idx)
|
|
|
- return 0;
|
|
|
-
|
|
|
- if (hd->idx)
|
|
|
- {
|
|
|
- if (ks->type == CDK_DBSEARCH_KEYID)
|
|
|
- {
|
|
|
- if (keydb_idx_search (hd->idx, ks->u.keyid, NULL, r_off))
|
|
|
- return CDK_Error_No_Key;
|
|
|
- _cdk_log_debug ("cache: found keyid entry in idx table.\n");
|
|
|
- *r_cache_hit = 1;
|
|
|
- }
|
|
|
- else if (ks->type == CDK_DBSEARCH_FPR)
|
|
|
- {
|
|
|
- if (keydb_idx_search (hd->idx, NULL, ks->u.fpr, r_off))
|
|
|
- return CDK_Error_No_Key;
|
|
|
- _cdk_log_debug ("cache: found fpr entry in idx table.\n");
|
|
|
- *r_cache_hit = 1;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/**
|
|
|
- * cdk_keydb_search:
|
|
|
- * @hd: the keydb object
|
|
|
- * @ks: the keydb search object
|
|
|
- * @ret_key: kbnode object to store the key
|
|
|
- *
|
|
|
- * Search for a key in the given keyring. The search mode is handled
|
|
|
- * via @ks. If the key was found, @ret_key contains the key data.
|
|
|
- **/
|
|
|
-cdk_error_t
|
|
|
-cdk_keydb_search (cdk_keydb_hd_t hd, cdk_kbnode_t * ret_key)
|
|
|
-{
|
|
|
- cdk_stream_t kr;
|
|
|
- cdk_kbnode_t knode;
|
|
|
- cdk_dbsearch_t ks;
|
|
|
- cdk_error_t rc = 0;
|
|
|
- off_t pos = 0, off = 0;
|
|
|
- int key_found = 0, cache_hit = 0;
|
|
|
-
|
|
|
- if (!hd || !ret_key)
|
|
|
- return CDK_Inv_Value;
|
|
|
-
|
|
|
- *ret_key = NULL;
|
|
|
- kr = NULL;
|
|
|
- hd->search = 1;
|
|
|
- rc = _cdk_keydb_open (hd, &kr);
|
|
|
- if (rc)
|
|
|
- return rc;
|
|
|
-
|
|
|
- if (!hd->no_cache)
|
|
|
- {
|
|
|
- /* It is possible the index is not up-to-date and thus we do
|
|
|
- not find the requesed key. In this case, we reset cache hit
|
|
|
- and continue our normal search procedure. */
|
|
|
- rc = keydb_pos_from_cache (hd, hd->dbs, &cache_hit, &off);
|
|
|
- if (rc)
|
|
|
- cache_hit = 0;
|
|
|
- }
|
|
|
-
|
|
|
- knode = NULL;
|
|
|
- ks = hd->dbs;
|
|
|
- while (!key_found && !rc)
|
|
|
- {
|
|
|
- if (cache_hit && ks->type != CDK_DBSEARCH_NEXT)
|
|
|
- cdk_stream_seek (kr, off);
|
|
|
- pos = cdk_stream_tell (kr);
|
|
|
- rc = cdk_keydb_get_keyblock (kr, &knode);
|
|
|
- if (rc)
|
|
|
- {
|
|
|
- if (rc == CDK_EOF)
|
|
|
- break;
|
|
|
- else
|
|
|
- return rc;
|
|
|
- }
|
|
|
-
|
|
|
- switch (ks->type)
|
|
|
- {
|
|
|
- case CDK_DBSEARCH_SHORT_KEYID:
|
|
|
- case CDK_DBSEARCH_KEYID:
|
|
|
- key_found = find_by_keyid (knode, ks);
|
|
|
- break;
|
|
|
-
|
|
|
- case CDK_DBSEARCH_FPR:
|
|
|
- key_found = find_by_fpr (knode, ks);
|
|
|
- break;
|
|
|
-
|
|
|
- case CDK_DBSEARCH_EXACT:
|
|
|
- case CDK_DBSEARCH_SUBSTR:
|
|
|
- key_found = find_by_pattern (knode, ks);
|
|
|
- break;
|
|
|
-
|
|
|
- case CDK_DBSEARCH_NEXT:
|
|
|
- key_found = knode ? 1 : 0;
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- if (key_found)
|
|
|
- {
|
|
|
- if (!keydb_cache_find (hd->cache, ks))
|
|
|
- keydb_cache_add (hd, ks, pos);
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- cdk_kbnode_release (knode);
|
|
|
- knode = NULL;
|
|
|
- }
|
|
|
-
|
|
|
- hd->search = 0;
|
|
|
- if (key_found && rc == CDK_EOF)
|
|
|
- rc = 0;
|
|
|
- else if (rc == CDK_EOF && !key_found)
|
|
|
- rc = CDK_Error_No_Key;
|
|
|
- *ret_key = key_found ? knode : NULL;
|
|
|
- return rc;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-cdk_error_t
|
|
|
-cdk_keydb_get_bykeyid (cdk_keydb_hd_t hd, u32 * keyid, cdk_kbnode_t * ret_key)
|
|
|
-{
|
|
|
- cdk_error_t rc;
|
|
|
-
|
|
|
- if (!hd || !keyid || !ret_key)
|
|
|
- return CDK_Inv_Value;
|
|
|
-
|
|
|
- rc = cdk_keydb_search_start (hd, CDK_DBSEARCH_KEYID, keyid);
|
|
|
- if (!rc)
|
|
|
- rc = cdk_keydb_search (hd, ret_key);
|
|
|
- return rc;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-cdk_error_t
|
|
|
-cdk_keydb_get_byfpr (cdk_keydb_hd_t hd, const byte * fpr,
|
|
|
- cdk_kbnode_t * r_key)
|
|
|
-{
|
|
|
- cdk_error_t rc;
|
|
|
-
|
|
|
- if (!hd || !fpr || !r_key)
|
|
|
- return CDK_Inv_Value;
|
|
|
-
|
|
|
- rc = cdk_keydb_search_start (hd, CDK_DBSEARCH_FPR, (byte *) fpr);
|
|
|
- if (!rc)
|
|
|
- rc = cdk_keydb_search (hd, r_key);
|
|
|
- return rc;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-cdk_error_t
|
|
|
-cdk_keydb_get_bypattern (cdk_keydb_hd_t hd, const char *patt,
|
|
|
- cdk_kbnode_t * ret_key)
|
|
|
-{
|
|
|
- cdk_error_t rc;
|
|
|
-
|
|
|
- if (!hd || !patt || !ret_key)
|
|
|
- return CDK_Inv_Value;
|
|
|
-
|
|
|
- rc = cdk_keydb_search_start (hd, CDK_DBSEARCH_SUBSTR, (char *) patt);
|
|
|
- if (!rc)
|
|
|
- rc = cdk_keydb_search (hd, ret_key);
|
|
|
- return rc;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-static int
|
|
|
-keydb_check_key (cdk_packet_t pkt)
|
|
|
-{
|
|
|
- cdk_pkt_pubkey_t pk;
|
|
|
- int is_sk, valid;
|
|
|
-
|
|
|
- if (pkt->pkttype == CDK_PKT_PUBLIC_KEY ||
|
|
|
- pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY)
|
|
|
- {
|
|
|
- pk = pkt->pkt.public_key;
|
|
|
- is_sk = 0;
|
|
|
- }
|
|
|
- else if (pkt->pkttype == CDK_PKT_SECRET_KEY ||
|
|
|
- pkt->pkttype == CDK_PKT_SECRET_SUBKEY)
|
|
|
- {
|
|
|
- pk = pkt->pkt.secret_key->pk;
|
|
|
- is_sk = 1;
|
|
|
- }
|
|
|
- else /* No key object. */
|
|
|
- return 0;
|
|
|
- valid = !pk->is_revoked && !pk->has_expired;
|
|
|
- if (is_sk)
|
|
|
- return valid;
|
|
|
- return valid && !pk->is_invalid;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/* Find the first kbnode with the requested packet type
|
|
|
- that represents a valid key. */
|
|
|
-static cdk_kbnode_t
|
|
|
-kbnode_find_valid (cdk_kbnode_t root, int pkttype)
|
|
|
-{
|
|
|
- cdk_kbnode_t n;
|
|
|
-
|
|
|
- for (n = root; n; n = n->next)
|
|
|
- {
|
|
|
- if (n->pkt->pkttype != pkttype)
|
|
|
- continue;
|
|
|
- if (keydb_check_key (n->pkt))
|
|
|
- return n;
|
|
|
- }
|
|
|
-
|
|
|
- return NULL;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-static cdk_kbnode_t
|
|
|
-keydb_find_byusage (cdk_kbnode_t root, int req_usage, int is_pk)
|
|
|
-{
|
|
|
- cdk_kbnode_t node, key;
|
|
|
- int req_type;
|
|
|
- long timestamp;
|
|
|
-
|
|
|
- req_type = is_pk ? CDK_PKT_PUBLIC_KEY : CDK_PKT_SECRET_KEY;
|
|
|
- if (!req_usage)
|
|
|
- return kbnode_find_valid (root, req_type);
|
|
|
-
|
|
|
- node = cdk_kbnode_find (root, req_type);
|
|
|
- if (node && !keydb_check_key (node->pkt))
|
|
|
- return NULL;
|
|
|
-
|
|
|
- key = NULL;
|
|
|
- timestamp = 0;
|
|
|
- /* We iteratre over the all nodes and search for keys or
|
|
|
- subkeys which match the usage and which are not invalid.
|
|
|
- A timestamp is used to figure out the newest valid key. */
|
|
|
- for (node = root; node; node = node->next)
|
|
|
- {
|
|
|
- if (is_pk && (node->pkt->pkttype == CDK_PKT_PUBLIC_KEY ||
|
|
|
- node->pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY)
|
|
|
- && keydb_check_key (node->pkt)
|
|
|
- && (node->pkt->pkt.public_key->pubkey_usage & req_usage))
|
|
|
- {
|
|
|
- if (node->pkt->pkt.public_key->timestamp > timestamp)
|
|
|
- key = node;
|
|
|
- }
|
|
|
- if (!is_pk && (node->pkt->pkttype == CDK_PKT_SECRET_KEY ||
|
|
|
- node->pkt->pkttype == CDK_PKT_SECRET_SUBKEY)
|
|
|
- && keydb_check_key (node->pkt)
|
|
|
- && (node->pkt->pkt.secret_key->pk->pubkey_usage & req_usage))
|
|
|
- {
|
|
|
- if (node->pkt->pkt.secret_key->pk->timestamp > timestamp)
|
|
|
- key = node;
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
- return key;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-static cdk_kbnode_t
|
|
|
-keydb_find_bykeyid (cdk_kbnode_t root, const u32 * keyid, int search_mode)
|
|
|
-{
|
|
|
- cdk_kbnode_t node;
|
|
|
- u32 kid[2];
|
|
|
-
|
|
|
- for (node = root; node; node = node->next)
|
|
|
- {
|
|
|
- if (!_cdk_pkt_get_keyid (node->pkt, kid))
|
|
|
- continue;
|
|
|
- if (search_mode == CDK_DBSEARCH_SHORT_KEYID && kid[1] == keyid[1])
|
|
|
- return node;
|
|
|
- else if (kid[0] == keyid[0] && kid[1] == keyid[1])
|
|
|
- return node;
|
|
|
- }
|
|
|
- return NULL;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-cdk_error_t
|
|
|
-_cdk_keydb_get_sk_byusage (cdk_keydb_hd_t hd, const char *name,
|
|
|
- cdk_seckey_t * ret_sk, int usage)
|
|
|
-{
|
|
|
- cdk_kbnode_t knode = NULL;
|
|
|
- cdk_kbnode_t node, sk_node, pk_node;
|
|
|
- cdk_pkt_seckey_t sk;
|
|
|
- cdk_error_t rc;
|
|
|
- const char *s;
|
|
|
- int pkttype;
|
|
|
-
|
|
|
- if (!ret_sk || !usage)
|
|
|
- return CDK_Inv_Value;
|
|
|
- if (!hd)
|
|
|
- return CDK_Error_No_Keyring;
|
|
|
-
|
|
|
- *ret_sk = NULL;
|
|
|
- rc = cdk_keydb_search_start (hd, CDK_DBSEARCH_AUTO, (char *) name);
|
|
|
- if (rc)
|
|
|
- return rc;
|
|
|
-
|
|
|
- rc = cdk_keydb_search (hd, &knode);
|
|
|
- if (rc)
|
|
|
- return rc;
|
|
|
-
|
|
|
- sk_node = keydb_find_byusage (knode, usage, 0);
|
|
|
- if (!sk_node)
|
|
|
- {
|
|
|
- cdk_kbnode_release (knode);
|
|
|
- return CDK_Unusable_Key;
|
|
|
- }
|
|
|
-
|
|
|
- /* We clone the node with the secret key to avoid that the
|
|
|
- packet will be released. */
|
|
|
- _cdk_kbnode_clone (sk_node);
|
|
|
- sk = sk_node->pkt->pkt.secret_key;
|
|
|
-
|
|
|
- for (node = knode; node; node = node->next)
|
|
|
- {
|
|
|
- if (node->pkt->pkttype == CDK_PKT_USER_ID)
|
|
|
- {
|
|
|
- s = node->pkt->pkt.user_id->name;
|
|
|
- if (sk && !sk->pk->uid && _cdk_memistr (s, strlen (s), name))
|
|
|
- {
|
|
|
- _cdk_copy_userid (&sk->pk->uid, node->pkt->pkt.user_id);
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /* To find the self signature, we need the primary public key because
|
|
|
- the selected secret key might be different from the primary key. */
|
|
|
- pk_node = cdk_kbnode_find (knode, CDK_PKT_SECRET_KEY);
|
|
|
- if (!pk_node)
|
|
|
- {
|
|
|
- cdk_kbnode_release (knode);
|
|
|
- return CDK_Unusable_Key;
|
|
|
- }
|
|
|
- node = find_selfsig_node (knode, pk_node->pkt->pkt.secret_key->pk);
|
|
|
- if (sk->pk->uid && node)
|
|
|
- _cdk_copy_signature (&sk->pk->uid->selfsig, node->pkt->pkt.signature);
|
|
|
-
|
|
|
- /* We only release the outer packet. */
|
|
|
- _cdk_pkt_detach_free (sk_node->pkt, &pkttype, (void *) &sk);
|
|
|
- cdk_kbnode_release (knode);
|
|
|
- *ret_sk = sk;
|
|
|
- return rc;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-cdk_error_t
|
|
|
-_cdk_keydb_get_pk_byusage (cdk_keydb_hd_t hd, const char *name,
|
|
|
- cdk_pubkey_t * ret_pk, int usage)
|
|
|
-{
|
|
|
- cdk_kbnode_t knode, node, pk_node;
|
|
|
- cdk_pkt_pubkey_t pk;
|
|
|
- const char *s;
|
|
|
- cdk_error_t rc;
|
|
|
-
|
|
|
- if (!ret_pk || !usage)
|
|
|
- return CDK_Inv_Value;
|
|
|
- if (!hd)
|
|
|
- return CDK_Error_No_Keyring;
|
|
|
-
|
|
|
- *ret_pk = NULL;
|
|
|
- rc = cdk_keydb_search_start (hd, CDK_DBSEARCH_AUTO, (char *) name);
|
|
|
- if (!rc)
|
|
|
- rc = cdk_keydb_search (hd, &knode);
|
|
|
- if (rc)
|
|
|
- return rc;
|
|
|
-
|
|
|
- node = keydb_find_byusage (knode, usage, 1);
|
|
|
- if (!node)
|
|
|
- {
|
|
|
- cdk_kbnode_release (knode);
|
|
|
- return CDK_Unusable_Key;
|
|
|
- }
|
|
|
-
|
|
|
- pk = NULL;
|
|
|
- _cdk_copy_pubkey (&pk, node->pkt->pkt.public_key);
|
|
|
- for (node = knode; node; node = node->next)
|
|
|
- {
|
|
|
- if (node->pkt->pkttype == CDK_PKT_USER_ID)
|
|
|
- {
|
|
|
- s = node->pkt->pkt.user_id->name;
|
|
|
- if (pk && !pk->uid && _cdk_memistr (s, strlen (s), name))
|
|
|
- {
|
|
|
- _cdk_copy_userid (&pk->uid, node->pkt->pkt.user_id);
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /* Same as in the sk code, the selected key can be a sub key
|
|
|
- and thus we need the primary key to find the self sig. */
|
|
|
- pk_node = cdk_kbnode_find (knode, CDK_PKT_PUBLIC_KEY);
|
|
|
- if (!pk_node)
|
|
|
- {
|
|
|
- cdk_kbnode_release (knode);
|
|
|
- return CDK_Unusable_Key;
|
|
|
- }
|
|
|
- node = find_selfsig_node (knode, pk_node->pkt->pkt.public_key);
|
|
|
- if (pk->uid && node)
|
|
|
- _cdk_copy_signature (&pk->uid->selfsig, node->pkt->pkt.signature);
|
|
|
- cdk_kbnode_release (knode);
|
|
|
-
|
|
|
- *ret_pk = pk;
|
|
|
- return rc;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/**
|
|
|
- * cdk_keydb_get_pk:
|
|
|
- * @hd: key db handle
|
|
|
- * @keyid: keyid of the key
|
|
|
- * @r_pk: the allocated public key
|
|
|
- *
|
|
|
- * Perform a key database search by keyid and return the raw public
|
|
|
- * key without any signatures or user id's.
|
|
|
- **/
|
|
|
-cdk_error_t
|
|
|
-cdk_keydb_get_pk (cdk_keydb_hd_t hd, u32 * keyid, cdk_pubkey_t * r_pk)
|
|
|
-{
|
|
|
- cdk_kbnode_t knode = NULL, node;
|
|
|
- cdk_pubkey_t pk;
|
|
|
- cdk_error_t rc;
|
|
|
- size_t s_type;
|
|
|
- int pkttype;
|
|
|
-
|
|
|
- if (!keyid || !r_pk)
|
|
|
- return CDK_Inv_Value;
|
|
|
- if (!hd)
|
|
|
- return CDK_Error_No_Keyring;
|
|
|
-
|
|
|
- *r_pk = NULL;
|
|
|
- s_type = !keyid[0] ? CDK_DBSEARCH_SHORT_KEYID : CDK_DBSEARCH_KEYID;
|
|
|
- rc = cdk_keydb_search_start (hd, s_type, keyid);
|
|
|
- if (rc)
|
|
|
- return rc;
|
|
|
- rc = cdk_keydb_search (hd, &knode);
|
|
|
- if (rc)
|
|
|
- return rc;
|
|
|
-
|
|
|
- node = keydb_find_bykeyid (knode, keyid, s_type);
|
|
|
- if (!node)
|
|
|
- {
|
|
|
- cdk_kbnode_release (knode);
|
|
|
- return CDK_Error_No_Key;
|
|
|
- }
|
|
|
-
|
|
|
- /* See comment in cdk_keydb_get_sk() */
|
|
|
- _cdk_pkt_detach_free (node->pkt, &pkttype, (void *) &pk);
|
|
|
- *r_pk = pk;
|
|
|
- _cdk_kbnode_clone (node);
|
|
|
- cdk_kbnode_release (knode);
|
|
|
-
|
|
|
- return rc;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/**
|
|
|
- * cdk_keydb_get_sk:
|
|
|
- * @hd: key db handle
|
|
|
- * @keyid: the keyid of the key
|
|
|
- * @ret_sk: the allocated secret key
|
|
|
- *
|
|
|
- * Perform a key database search by keyid and return
|
|
|
- * only the raw secret key without the additional nodes,
|
|
|
- * like the user id or the signatures.
|
|
|
- **/
|
|
|
-cdk_error_t
|
|
|
-cdk_keydb_get_sk (cdk_keydb_hd_t hd, u32 * keyid, cdk_seckey_t * ret_sk)
|
|
|
-{
|
|
|
- cdk_kbnode_t snode, node;
|
|
|
- cdk_seckey_t sk;
|
|
|
- cdk_error_t rc;
|
|
|
- int pkttype;
|
|
|
-
|
|
|
- if (!keyid || !ret_sk)
|
|
|
- return CDK_Inv_Value;
|
|
|
- if (!hd)
|
|
|
- return CDK_Error_No_Keyring;
|
|
|
-
|
|
|
- *ret_sk = NULL;
|
|
|
- rc = cdk_keydb_get_bykeyid (hd, keyid, &snode);
|
|
|
- if (rc)
|
|
|
- return rc;
|
|
|
-
|
|
|
- node = keydb_find_bykeyid (snode, keyid, CDK_DBSEARCH_KEYID);
|
|
|
- if (!node)
|
|
|
- {
|
|
|
- cdk_kbnode_release (snode);
|
|
|
- return CDK_Error_No_Key;
|
|
|
- }
|
|
|
-
|
|
|
- /* We need to release the packet itself but not its contents
|
|
|
- and thus we detach the openpgp packet and release the structure. */
|
|
|
- _cdk_pkt_detach_free (node->pkt, &pkttype, (void *) &sk);
|
|
|
- _cdk_kbnode_clone (node);
|
|
|
- cdk_kbnode_release (snode);
|
|
|
-
|
|
|
- *ret_sk = sk;
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-static int
|
|
|
-is_selfsig (cdk_kbnode_t node, const u32 * keyid)
|
|
|
-{
|
|
|
- cdk_pkt_signature_t sig;
|
|
|
-
|
|
|
- if (node->pkt->pkttype != CDK_PKT_SIGNATURE)
|
|
|
- return 0;
|
|
|
- sig = node->pkt->pkt.signature;
|
|
|
- if ((sig->sig_class >= 0x10 && sig->sig_class <= 0x13) &&
|
|
|
- sig->keyid[0] == keyid[0] && sig->keyid[1] == keyid[1])
|
|
|
- return 1;
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/* Find the newest self signature for the public key @pk
|
|
|
- and return the signature node. */
|
|
|
-static cdk_kbnode_t
|
|
|
-find_selfsig_node (cdk_kbnode_t key, cdk_pkt_pubkey_t pk)
|
|
|
-{
|
|
|
- cdk_kbnode_t n, sig;
|
|
|
- unsigned int ts;
|
|
|
- u32 keyid[2];
|
|
|
-
|
|
|
- cdk_pk_get_keyid (pk, keyid);
|
|
|
- sig = NULL;
|
|
|
- ts = 0;
|
|
|
- for (n = key; n; n = n->next)
|
|
|
- {
|
|
|
- if (is_selfsig (n, keyid) && n->pkt->pkt.signature->timestamp > ts)
|
|
|
- {
|
|
|
- ts = n->pkt->pkt.signature->timestamp;
|
|
|
- sig = n;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return sig;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-static cdk_error_t
|
|
|
-keydb_merge_selfsig (cdk_kbnode_t key, u32 * keyid)
|
|
|
-{
|
|
|
- cdk_kbnode_t node, kbnode, unode;
|
|
|
- cdk_subpkt_t s = NULL;
|
|
|
- cdk_pkt_signature_t sig = NULL;
|
|
|
- cdk_pkt_userid_t uid = NULL;
|
|
|
- const byte *symalg = NULL, *hashalg = NULL, *compalg = NULL;
|
|
|
- size_t nsymalg = 0, nhashalg = 0, ncompalg = 0, n = 0;
|
|
|
- size_t key_usage = 0, key_expire = 0;
|
|
|
-
|
|
|
- if (!key)
|
|
|
- return CDK_Inv_Value;
|
|
|
-
|
|
|
- for (node = key; node; node = node->next)
|
|
|
- {
|
|
|
- if (!is_selfsig (node, keyid))
|
|
|
- continue;
|
|
|
- unode = cdk_kbnode_find_prev (key, node, CDK_PKT_USER_ID);
|
|
|
- if (!unode)
|
|
|
- return CDK_Error_No_Key;
|
|
|
- uid = unode->pkt->pkt.user_id;
|
|
|
- sig = node->pkt->pkt.signature;
|
|
|
- s = cdk_subpkt_find (sig->hashed, CDK_SIGSUBPKT_PRIMARY_UID);
|
|
|
- if (s)
|
|
|
- uid->is_primary = 1;
|
|
|
- s = cdk_subpkt_find (sig->hashed, CDK_SIGSUBPKT_FEATURES);
|
|
|
- if (s && s->size == 1 && s->d[0] & 0x01)
|
|
|
- uid->mdc_feature = 1;
|
|
|
- s = cdk_subpkt_find (sig->hashed, CDK_SIGSUBPKT_KEY_EXPIRE);
|
|
|
- if (s && s->size == 4)
|
|
|
- key_expire = _cdk_buftou32 (s->d);
|
|
|
- s = cdk_subpkt_find (sig->hashed, CDK_SIGSUBPKT_KEY_FLAGS);
|
|
|
- if (s)
|
|
|
- {
|
|
|
- if (s->d[0] & 0x03) /* cert + sign data */
|
|
|
- key_usage |= CDK_KEY_USG_SIGN;
|
|
|
- if (s->d[0] & 0x0C) /* encrypt comm. + storage */
|
|
|
- key_usage |= CDK_KEY_USG_ENCR;
|
|
|
- if (s->d[0] & 0x20)
|
|
|
- key_usage |= CDK_KEY_USG_AUTH;
|
|
|
- }
|
|
|
- s = cdk_subpkt_find (sig->hashed, CDK_SIGSUBPKT_PREFS_SYM);
|
|
|
- if (s)
|
|
|
- {
|
|
|
- symalg = s->d;
|
|
|
- nsymalg = s->size;
|
|
|
- n += s->size + 1;
|
|
|
- }
|
|
|
- s = cdk_subpkt_find (sig->hashed, CDK_SIGSUBPKT_PREFS_HASH);
|
|
|
- if (s)
|
|
|
- {
|
|
|
- hashalg = s->d;
|
|
|
- nhashalg = s->size;
|
|
|
- n += s->size + 1;
|
|
|
- }
|
|
|
- s = cdk_subpkt_find (sig->hashed, CDK_SIGSUBPKT_PREFS_ZIP);
|
|
|
- if (s)
|
|
|
- {
|
|
|
- compalg = s->d;
|
|
|
- ncompalg = s->size;
|
|
|
- n += s->size + 1;
|
|
|
- }
|
|
|
- if (uid->prefs != NULL)
|
|
|
- cdk_free (uid->prefs);
|
|
|
- if (!n || !hashalg || !compalg || !symalg)
|
|
|
- uid->prefs = NULL;
|
|
|
- else
|
|
|
- {
|
|
|
- uid->prefs = cdk_calloc (1, sizeof (*uid->prefs) * (n + 1));
|
|
|
- if (!uid->prefs)
|
|
|
- return CDK_Out_Of_Core;
|
|
|
- n = 0;
|
|
|
- for (; nsymalg; nsymalg--, n++)
|
|
|
- {
|
|
|
- uid->prefs[n].type = CDK_PREFTYPE_SYM;
|
|
|
- uid->prefs[n].value = *symalg++;
|
|
|
- }
|
|
|
- for (; nhashalg; nhashalg--, n++)
|
|
|
- {
|
|
|
- uid->prefs[n].type = CDK_PREFTYPE_HASH;
|
|
|
- uid->prefs[n].value = *hashalg++;
|
|
|
- }
|
|
|
- for (; ncompalg; ncompalg--, n++)
|
|
|
- {
|
|
|
- uid->prefs[n].type = CDK_PREFTYPE_ZIP;
|
|
|
- uid->prefs[n].value = *compalg++;
|
|
|
- }
|
|
|
-
|
|
|
- uid->prefs[n].type = CDK_PREFTYPE_NONE; /* end of list marker */
|
|
|
- uid->prefs[n].value = 0;
|
|
|
- uid->prefs_size = n;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /* Now we add the extracted information to the primary key. */
|
|
|
- kbnode = cdk_kbnode_find (key, CDK_PKT_PUBLIC_KEY);
|
|
|
- if (kbnode)
|
|
|
- {
|
|
|
- cdk_pkt_pubkey_t pk = kbnode->pkt->pkt.public_key;
|
|
|
- if (uid && uid->prefs && n)
|
|
|
- {
|
|
|
- if (pk->prefs != NULL)
|
|
|
- cdk_free (pk->prefs);
|
|
|
- pk->prefs = _cdk_copy_prefs (uid->prefs);
|
|
|
- pk->prefs_size = n;
|
|
|
- }
|
|
|
- if (key_expire)
|
|
|
- {
|
|
|
- pk->expiredate = pk->timestamp + key_expire;
|
|
|
- pk->has_expired = pk->expiredate > (u32) time (NULL) ? 0 : 1;
|
|
|
- }
|
|
|
-
|
|
|
- if (key_usage)
|
|
|
- pk->pubkey_usage = key_usage;
|
|
|
- pk->is_invalid = 0;
|
|
|
- }
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-static cdk_error_t
|
|
|
-keydb_parse_allsigs (cdk_kbnode_t knode, cdk_keydb_hd_t hd, int check)
|
|
|
-{
|
|
|
- cdk_kbnode_t node, kb;
|
|
|
- cdk_pkt_signature_t sig;
|
|
|
- cdk_pkt_pubkey_t pk;
|
|
|
- cdk_subpkt_t s = NULL;
|
|
|
- u32 expiredate = 0, curtime = (u32) time (NULL);
|
|
|
- u32 keyid[2];
|
|
|
-
|
|
|
- if (!knode)
|
|
|
- return CDK_Inv_Value;
|
|
|
- if (check && !hd)
|
|
|
- return CDK_Inv_Mode;
|
|
|
-
|
|
|
- kb = cdk_kbnode_find (knode, CDK_PKT_SECRET_KEY);
|
|
|
- if (kb)
|
|
|
- return 0;
|
|
|
-
|
|
|
- /* Reset */
|
|
|
- for (node = knode; node; node = node->next)
|
|
|
- {
|
|
|
- if (node->pkt->pkttype == CDK_PKT_USER_ID)
|
|
|
- node->pkt->pkt.user_id->is_revoked = 0;
|
|
|
- else if (node->pkt->pkttype == CDK_PKT_PUBLIC_KEY ||
|
|
|
- node->pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY)
|
|
|
- node->pkt->pkt.public_key->is_revoked = 0;
|
|
|
- }
|
|
|
-
|
|
|
- kb = cdk_kbnode_find (knode, CDK_PKT_PUBLIC_KEY);
|
|
|
- if (!kb)
|
|
|
- return CDK_Wrong_Format;
|
|
|
- cdk_pk_get_keyid (kb->pkt->pkt.public_key, keyid);
|
|
|
-
|
|
|
- for (node = knode; node; node = node->next)
|
|
|
- {
|
|
|
- if (node->pkt->pkttype == CDK_PKT_SIGNATURE)
|
|
|
- {
|
|
|
- sig = node->pkt->pkt.signature;
|
|
|
- /* Revocation certificates for primary keys */
|
|
|
- if (sig->sig_class == 0x20)
|
|
|
- {
|
|
|
- kb = cdk_kbnode_find_prev (knode, node, CDK_PKT_PUBLIC_KEY);
|
|
|
- if (kb)
|
|
|
- {
|
|
|
- kb->pkt->pkt.public_key->is_revoked = 1;
|
|
|
- if (check)
|
|
|
- _cdk_pk_check_sig (hd, kb, node, NULL);
|
|
|
- }
|
|
|
- else
|
|
|
- return CDK_Error_No_Key;
|
|
|
- }
|
|
|
- /* Revocation certificates for subkeys */
|
|
|
- else if (sig->sig_class == 0x28)
|
|
|
- {
|
|
|
- kb = cdk_kbnode_find_prev (knode, node, CDK_PKT_PUBLIC_SUBKEY);
|
|
|
- if (kb)
|
|
|
- {
|
|
|
- kb->pkt->pkt.public_key->is_revoked = 1;
|
|
|
- if (check)
|
|
|
- _cdk_pk_check_sig (hd, kb, node, NULL);
|
|
|
- }
|
|
|
- else
|
|
|
- return CDK_Error_No_Key;
|
|
|
- }
|
|
|
- /* Revocation certifcates for user ID's */
|
|
|
- else if (sig->sig_class == 0x30)
|
|
|
- {
|
|
|
- if (sig->keyid[0] != keyid[0] || sig->keyid[1] != keyid[1])
|
|
|
- continue; /* revokes an earlier signature, no userID. */
|
|
|
- kb = cdk_kbnode_find_prev (knode, node, CDK_PKT_USER_ID);
|
|
|
- if (kb)
|
|
|
- {
|
|
|
- kb->pkt->pkt.user_id->is_revoked = 1;
|
|
|
- if (check)
|
|
|
- _cdk_pk_check_sig (hd, kb, node, NULL);
|
|
|
- }
|
|
|
- else
|
|
|
- return CDK_Error_No_Key;
|
|
|
- }
|
|
|
- /* Direct certificates for primary keys */
|
|
|
- else if (sig->sig_class == 0x1F)
|
|
|
- {
|
|
|
- kb = cdk_kbnode_find_prev (knode, node, CDK_PKT_PUBLIC_KEY);
|
|
|
- if (kb)
|
|
|
- {
|
|
|
- pk = kb->pkt->pkt.public_key;
|
|
|
- pk->is_invalid = 0;
|
|
|
- s = cdk_subpkt_find (node->pkt->pkt.signature->hashed,
|
|
|
- CDK_SIGSUBPKT_KEY_EXPIRE);
|
|
|
- if (s)
|
|
|
- {
|
|
|
- expiredate = _cdk_buftou32 (s->d);
|
|
|
- pk->expiredate = pk->timestamp + expiredate;
|
|
|
- pk->has_expired = pk->expiredate > curtime ? 0 : 1;
|
|
|
- }
|
|
|
- if (check)
|
|
|
- _cdk_pk_check_sig (hd, kb, node, NULL);
|
|
|
- }
|
|
|
- else
|
|
|
- return CDK_Error_No_Key;
|
|
|
- }
|
|
|
- /* Direct certificates for subkeys */
|
|
|
- else if (sig->sig_class == 0x18)
|
|
|
- {
|
|
|
- kb = cdk_kbnode_find_prev (knode, node, CDK_PKT_PUBLIC_SUBKEY);
|
|
|
- if (kb)
|
|
|
- {
|
|
|
- pk = kb->pkt->pkt.public_key;
|
|
|
- pk->is_invalid = 0;
|
|
|
- s = cdk_subpkt_find (node->pkt->pkt.signature->hashed,
|
|
|
- CDK_SIGSUBPKT_KEY_EXPIRE);
|
|
|
- if (s)
|
|
|
- {
|
|
|
- expiredate = _cdk_buftou32 (s->d);
|
|
|
- pk->expiredate = pk->timestamp + expiredate;
|
|
|
- pk->has_expired = pk->expiredate > curtime ? 0 : 1;
|
|
|
- }
|
|
|
- if (check)
|
|
|
- _cdk_pk_check_sig (hd, kb, node, NULL);
|
|
|
- }
|
|
|
- else
|
|
|
- return CDK_Error_No_Key;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- node = cdk_kbnode_find (knode, CDK_PKT_PUBLIC_KEY);
|
|
|
- if (node && node->pkt->pkt.public_key->version == 3)
|
|
|
- {
|
|
|
- /* v3 public keys have no additonal signatures for the key directly.
|
|
|
- we say the key is valid when we have at least a self signature. */
|
|
|
- pk = node->pkt->pkt.public_key;
|
|
|
- for (node = knode; node; node = node->next)
|
|
|
- {
|
|
|
- if (is_selfsig (node, keyid))
|
|
|
- {
|
|
|
- pk->is_invalid = 0;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- if (node && (node->pkt->pkt.public_key->is_revoked ||
|
|
|
- node->pkt->pkt.public_key->has_expired))
|
|
|
- {
|
|
|
- /* If the primary key has been revoked, mark all subkeys as invalid
|
|
|
- because without a primary key they are not useable */
|
|
|
- for (node = knode; node; node = node->next)
|
|
|
- {
|
|
|
- if (node->pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY)
|
|
|
- node->pkt->pkt.public_key->is_invalid = 1;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-cdk_error_t
|
|
|
-cdk_keydb_get_keyblock (cdk_stream_t inp, cdk_kbnode_t * r_knode)
|
|
|
-{
|
|
|
- cdk_packet_t pkt;
|
|
|
- cdk_kbnode_t knode, node;
|
|
|
- cdk_desig_revoker_t revkeys;
|
|
|
- cdk_error_t rc;
|
|
|
- u32 keyid[2], main_keyid[2];
|
|
|
- off_t old_off;
|
|
|
- int key_seen, got_key;
|
|
|
-
|
|
|
- if (!inp || !r_knode)
|
|
|
- return CDK_Inv_Value;
|
|
|
-
|
|
|
- /* Reset all values. */
|
|
|
- keyid[0] = keyid[1] = 0;
|
|
|
- main_keyid[0] = main_keyid[1] = 0;
|
|
|
- revkeys = NULL;
|
|
|
- knode = NULL;
|
|
|
- key_seen = got_key = 0;
|
|
|
-
|
|
|
- *r_knode = NULL;
|
|
|
- rc = CDK_EOF;
|
|
|
- while (!cdk_stream_eof (inp))
|
|
|
- {
|
|
|
- cdk_pkt_new (&pkt);
|
|
|
- old_off = cdk_stream_tell (inp);
|
|
|
- rc = cdk_pkt_read (inp, pkt);
|
|
|
- if (rc)
|
|
|
- {
|
|
|
- cdk_pkt_release (pkt);
|
|
|
- if (rc == CDK_EOF)
|
|
|
- break;
|
|
|
- else
|
|
|
- { /* Release all packets we reached so far. */
|
|
|
- _cdk_log_debug ("keydb_get_keyblock: error %d\n", rc);
|
|
|
- cdk_kbnode_release (knode);
|
|
|
- return rc;
|
|
|
- }
|
|
|
- }
|
|
|
- if (pkt->pkttype == CDK_PKT_PUBLIC_KEY ||
|
|
|
- pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY ||
|
|
|
- pkt->pkttype == CDK_PKT_SECRET_KEY ||
|
|
|
- pkt->pkttype == CDK_PKT_SECRET_SUBKEY)
|
|
|
- {
|
|
|
- if (key_seen && (pkt->pkttype == CDK_PKT_PUBLIC_KEY ||
|
|
|
- pkt->pkttype == CDK_PKT_SECRET_KEY))
|
|
|
- {
|
|
|
- /* The next key starts here so set the file pointer
|
|
|
- and leave the loop. */
|
|
|
- cdk_stream_seek (inp, old_off);
|
|
|
- cdk_pkt_release (pkt);
|
|
|
- break;
|
|
|
- }
|
|
|
- if (pkt->pkttype == CDK_PKT_PUBLIC_KEY ||
|
|
|
- pkt->pkttype == CDK_PKT_SECRET_KEY)
|
|
|
- {
|
|
|
- _cdk_pkt_get_keyid (pkt, main_keyid);
|
|
|
- key_seen = 1;
|
|
|
- }
|
|
|
- else if (pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY ||
|
|
|
- pkt->pkttype == CDK_PKT_SECRET_SUBKEY)
|
|
|
- {
|
|
|
- if (pkt->pkttype == CDK_PKT_PUBLIC_SUBKEY)
|
|
|
- {
|
|
|
- pkt->pkt.public_key->main_keyid[0] = main_keyid[0];
|
|
|
- pkt->pkt.public_key->main_keyid[1] = main_keyid[1];
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- pkt->pkt.secret_key->main_keyid[0] = main_keyid[0];
|
|
|
- pkt->pkt.secret_key->main_keyid[1] = main_keyid[1];
|
|
|
- }
|
|
|
- }
|
|
|
- /* We save this for the signature */
|
|
|
- _cdk_pkt_get_keyid (pkt, keyid);
|
|
|
- got_key = 1;
|
|
|
- }
|
|
|
- else if (pkt->pkttype == CDK_PKT_USER_ID)
|
|
|
- ;
|
|
|
- else if (pkt->pkttype == CDK_PKT_SIGNATURE)
|
|
|
- {
|
|
|
- pkt->pkt.signature->key[0] = keyid[0];
|
|
|
- pkt->pkt.signature->key[1] = keyid[1];
|
|
|
- if (pkt->pkt.signature->sig_class == 0x1F &&
|
|
|
- pkt->pkt.signature->revkeys)
|
|
|
- revkeys = pkt->pkt.signature->revkeys;
|
|
|
- }
|
|
|
- node = cdk_kbnode_new (pkt);
|
|
|
- if (!knode)
|
|
|
- knode = node;
|
|
|
- else
|
|
|
- _cdk_kbnode_add (knode, node);
|
|
|
- }
|
|
|
-
|
|
|
- if (got_key)
|
|
|
- {
|
|
|
- keydb_merge_selfsig (knode, main_keyid);
|
|
|
- rc = keydb_parse_allsigs (knode, NULL, 0);
|
|
|
- if (revkeys)
|
|
|
- {
|
|
|
- node = cdk_kbnode_find (knode, CDK_PKT_PUBLIC_KEY);
|
|
|
- if (node)
|
|
|
- node->pkt->pkt.public_key->revkeys = revkeys;
|
|
|
- }
|
|
|
- }
|
|
|
- else
|
|
|
- cdk_kbnode_release (knode);
|
|
|
- *r_knode = got_key ? knode : NULL;
|
|
|
-
|
|
|
- /* It is possible that we are in an EOF condition after we
|
|
|
- successfully read a keyblock. For example if the requested
|
|
|
- key is the last in the file. */
|
|
|
- if (rc == CDK_EOF && got_key)
|
|
|
- rc = 0;
|
|
|
- return rc;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/* Return the type of the given data. In case it cannot be classified,
|
|
|
- a substring search will be performed. */
|
|
|
-static int
|
|
|
-classify_data (const byte * buf, size_t len)
|
|
|
-{
|
|
|
- int type;
|
|
|
- int i;
|
|
|
-
|
|
|
- if (buf[0] == '0' && (buf[1] == 'x' || buf[1] == 'X'))
|
|
|
- { /* Skip hex prefix. */
|
|
|
- buf += 2;
|
|
|
- len -= 2;
|
|
|
- }
|
|
|
-
|
|
|
- /* The length of the data does not match either a keyid or a fingerprint. */
|
|
|
- if (len != 8 && len != 16 && len != 40)
|
|
|
- return CDK_DBSEARCH_SUBSTR;
|
|
|
-
|
|
|
- for (i = 0; i < len; i++)
|
|
|
- {
|
|
|
- if (!isxdigit (buf[i]))
|
|
|
- return CDK_DBSEARCH_SUBSTR;
|
|
|
- }
|
|
|
- if (i != len)
|
|
|
- return CDK_DBSEARCH_SUBSTR;
|
|
|
- switch (len)
|
|
|
- {
|
|
|
- case 8:
|
|
|
- type = CDK_DBSEARCH_SHORT_KEYID;
|
|
|
- break;
|
|
|
- case 16:
|
|
|
- type = CDK_DBSEARCH_KEYID;
|
|
|
- break;
|
|
|
- case 40:
|
|
|
- type = CDK_DBSEARCH_FPR;
|
|
|
- break;
|
|
|
- default:
|
|
|
- type = CDK_DBSEARCH_SUBSTR;
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- return type;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/**
|
|
|
- * cdk_keydb_export:
|
|
|
- * @hd: the keydb handle
|
|
|
- * @out: the output stream
|
|
|
- * @remusr: the list of key pattern to export
|
|
|
- *
|
|
|
- * Export a list of keys to the given output stream.
|
|
|
- * Use string list with names for pattering searching.
|
|
|
- * This procedure strips local signatures.
|
|
|
- **/
|
|
|
-cdk_error_t
|
|
|
-cdk_keydb_export (cdk_keydb_hd_t hd, cdk_stream_t out, cdk_strlist_t remusr)
|
|
|
-{
|
|
|
- cdk_kbnode_t knode, node;
|
|
|
- cdk_strlist_t r;
|
|
|
- cdk_error_t rc;
|
|
|
- int old_ctb;
|
|
|
-
|
|
|
- for (r = remusr; r; r = r->next)
|
|
|
- {
|
|
|
- rc = cdk_keydb_search_start (hd, CDK_DBSEARCH_AUTO, r->d);
|
|
|
- if (rc)
|
|
|
- return rc;
|
|
|
- rc = cdk_keydb_search (hd, &knode);
|
|
|
- if (rc)
|
|
|
- return rc;
|
|
|
- node = cdk_kbnode_find (knode, CDK_PKT_PUBLIC_KEY);
|
|
|
- if (!node)
|
|
|
- return CDK_Error_No_Key;
|
|
|
-
|
|
|
- /* If the key is a version 3 key, use the old packet
|
|
|
- format for the output. */
|
|
|
- if (node->pkt->pkt.public_key->version == 3)
|
|
|
- old_ctb = 1;
|
|
|
- else
|
|
|
- old_ctb = 0;
|
|
|
-
|
|
|
- for (node = knode; node; node = node->next)
|
|
|
- {
|
|
|
- /* No specified format; skip them */
|
|
|
- if (node->pkt->pkttype == CDK_PKT_RING_TRUST)
|
|
|
- continue;
|
|
|
- /* We never export local signed signatures */
|
|
|
- if (node->pkt->pkttype == CDK_PKT_SIGNATURE &&
|
|
|
- !node->pkt->pkt.signature->flags.exportable)
|
|
|
- continue;
|
|
|
- /* Filter out invalid signatures */
|
|
|
- if (node->pkt->pkttype == CDK_PKT_SIGNATURE &&
|
|
|
- !KEY_CAN_SIGN (node->pkt->pkt.signature->pubkey_algo))
|
|
|
- continue;
|
|
|
-
|
|
|
- /* Adjust the ctb flag if needed. */
|
|
|
- node->pkt->old_ctb = old_ctb;
|
|
|
- rc = cdk_pkt_write (out, node->pkt);
|
|
|
- if (rc)
|
|
|
- {
|
|
|
- cdk_kbnode_release (knode);
|
|
|
- return rc;
|
|
|
- }
|
|
|
- }
|
|
|
- cdk_kbnode_release (knode);
|
|
|
- knode = NULL;
|
|
|
- }
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-static cdk_packet_t
|
|
|
-find_key_packet (cdk_kbnode_t knode, int *r_is_sk)
|
|
|
-{
|
|
|
- cdk_packet_t pkt;
|
|
|
-
|
|
|
- pkt = cdk_kbnode_find_packet (knode, CDK_PKT_PUBLIC_KEY);
|
|
|
- if (!pkt)
|
|
|
- {
|
|
|
- pkt = cdk_kbnode_find_packet (knode, CDK_PKT_SECRET_KEY);
|
|
|
- if (r_is_sk)
|
|
|
- *r_is_sk = pkt ? 1 : 0;
|
|
|
- }
|
|
|
- return pkt;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/* Return 1 if the is allowd in a key node. */
|
|
|
-static int
|
|
|
-is_key_node (cdk_kbnode_t node)
|
|
|
-{
|
|
|
- switch (node->pkt->pkttype)
|
|
|
- {
|
|
|
- case CDK_PKT_SIGNATURE:
|
|
|
- case CDK_PKT_SECRET_KEY:
|
|
|
- case CDK_PKT_PUBLIC_KEY:
|
|
|
- case CDK_PKT_SECRET_SUBKEY:
|
|
|
- case CDK_PKT_PUBLIC_SUBKEY:
|
|
|
- case CDK_PKT_USER_ID:
|
|
|
- case CDK_PKT_ATTRIBUTE:
|
|
|
- return 1;
|
|
|
-
|
|
|
- default:
|
|
|
- return 0;
|
|
|
- }
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-cdk_error_t
|
|
|
-cdk_keydb_import (cdk_keydb_hd_t hd, cdk_kbnode_t knode)
|
|
|
-{
|
|
|
- cdk_kbnode_t node, chk;
|
|
|
- cdk_packet_t pkt;
|
|
|
- cdk_stream_t out;
|
|
|
- cdk_error_t rc;
|
|
|
- u32 keyid[2];
|
|
|
-
|
|
|
- if (!hd || !knode)
|
|
|
- return CDK_Inv_Value;
|
|
|
-
|
|
|
- pkt = find_key_packet (knode, NULL);
|
|
|
- if (!pkt)
|
|
|
- return CDK_Inv_Packet;
|
|
|
-
|
|
|
- _cdk_pkt_get_keyid (pkt, keyid);
|
|
|
- chk = NULL;
|
|
|
- cdk_keydb_get_bykeyid (hd, keyid, &chk);
|
|
|
- if (chk)
|
|
|
- { /* FIXME: search for new signatures */
|
|
|
- cdk_kbnode_release (chk);
|
|
|
- return 0;
|
|
|
- }
|
|
|
-
|
|
|
- /* We append data to the stream so we need to close
|
|
|
- the stream here to re-open it later. */
|
|
|
- if (hd->fp)
|
|
|
- {
|
|
|
- cdk_stream_close (hd->fp);
|
|
|
- hd->fp = NULL;
|
|
|
- }
|
|
|
-
|
|
|
- rc = _cdk_stream_append (hd->name, &out);
|
|
|
- if (rc)
|
|
|
- return rc;
|
|
|
-
|
|
|
- for (node = knode; node; node = node->next)
|
|
|
- {
|
|
|
- if (node->pkt->pkttype == CDK_PKT_RING_TRUST)
|
|
|
- continue; /* No uniformed syntax for this packet */
|
|
|
- if (node->pkt->pkttype == CDK_PKT_SIGNATURE &&
|
|
|
- !node->pkt->pkt.signature->flags.exportable)
|
|
|
- {
|
|
|
- _cdk_log_debug ("key db import: skip local signature\n");
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- if (!is_key_node (node))
|
|
|
- {
|
|
|
- _cdk_log_debug ("key db import: skip invalid node of type %d\n",
|
|
|
- node->pkt->pkttype);
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- rc = cdk_pkt_write (out, node->pkt);
|
|
|
- if (rc)
|
|
|
- {
|
|
|
- cdk_stream_close (out);
|
|
|
- return rc;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- cdk_stream_close (out);
|
|
|
- if (!hd->no_cache)
|
|
|
- cdk_keydb_idx_rebuild (hd);
|
|
|
- hd->stats.new_keys++;
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-cdk_error_t
|
|
|
-_cdk_keydb_check_userid (cdk_keydb_hd_t hd, u32 * keyid, const char *id)
|
|
|
-{
|
|
|
- cdk_kbnode_t knode = NULL, unode = NULL;
|
|
|
- cdk_error_t rc;
|
|
|
- int check;
|
|
|
-
|
|
|
- if (!hd)
|
|
|
- return CDK_Inv_Value;
|
|
|
-
|
|
|
- rc = cdk_keydb_search_start (hd, CDK_DBSEARCH_KEYID, keyid);
|
|
|
- if (rc)
|
|
|
- return rc;
|
|
|
- rc = cdk_keydb_search (hd, &knode);
|
|
|
- if (rc)
|
|
|
- return rc;
|
|
|
-
|
|
|
- rc = cdk_keydb_search_start (hd, CDK_DBSEARCH_EXACT, (char *) id);
|
|
|
- if (!rc)
|
|
|
- rc = cdk_keydb_search (hd, &unode);
|
|
|
- if (rc)
|
|
|
- {
|
|
|
- cdk_kbnode_release (knode);
|
|
|
- return rc;
|
|
|
- }
|
|
|
-
|
|
|
- check = 0;
|
|
|
- cdk_keydb_search_start (hd, CDK_DBSEARCH_KEYID, keyid);
|
|
|
- if (unode && find_by_keyid (unode, hd->dbs))
|
|
|
- check++;
|
|
|
- cdk_kbnode_release (unode);
|
|
|
-
|
|
|
- cdk_keydb_search_start (hd, CDK_DBSEARCH_EXACT, (char *) id);
|
|
|
- if (knode && find_by_pattern (knode, hd->dbs))
|
|
|
- check++;
|
|
|
- cdk_kbnode_release (knode);
|
|
|
-
|
|
|
- return check == 2 ? 0 : CDK_Inv_Value;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/**
|
|
|
- * cdk_keydb_check_sk:
|
|
|
- * @hd: the key db handle
|
|
|
- * @keyid: the 64-bit keyid
|
|
|
- *
|
|
|
- * Check if a secret key with the given key ID is available
|
|
|
- * in the key database.
|
|
|
- **/
|
|
|
-cdk_error_t
|
|
|
-cdk_keydb_check_sk (cdk_keydb_hd_t hd, u32 * keyid)
|
|
|
-{
|
|
|
- cdk_stream_t db;
|
|
|
- cdk_packet_t pkt;
|
|
|
- cdk_error_t rc;
|
|
|
- u32 kid[2];
|
|
|
-
|
|
|
- if (!hd || !keyid)
|
|
|
- return CDK_Inv_Value;
|
|
|
- if (!hd->secret)
|
|
|
- return CDK_Inv_Mode;
|
|
|
-
|
|
|
- rc = _cdk_keydb_open (hd, &db);
|
|
|
- if (rc)
|
|
|
- return rc;
|
|
|
- cdk_pkt_new (&pkt);
|
|
|
- while (!cdk_pkt_read (db, pkt))
|
|
|
- {
|
|
|
- if (pkt->pkttype != CDK_PKT_SECRET_KEY &&
|
|
|
- pkt->pkttype != CDK_PKT_SECRET_SUBKEY)
|
|
|
- {
|
|
|
- cdk_pkt_free (pkt);
|
|
|
- continue;
|
|
|
- }
|
|
|
- cdk_sk_get_keyid (pkt->pkt.secret_key, kid);
|
|
|
- if (KEYID_CMP (kid, keyid))
|
|
|
- {
|
|
|
- cdk_pkt_release (pkt);
|
|
|
- return 0;
|
|
|
- }
|
|
|
- cdk_pkt_free (pkt);
|
|
|
- }
|
|
|
- cdk_pkt_release (pkt);
|
|
|
- return CDK_Error_No_Key;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/**
|
|
|
- * cdk_listkey_start:
|
|
|
- * @r_ctx: pointer to store the new context
|
|
|
- * @db: the key database handle
|
|
|
- * @patt: string pattern
|
|
|
- * @fpatt: recipients from a stringlist to show
|
|
|
- *
|
|
|
- * Prepare a key listing with the given parameters. Two modes are supported.
|
|
|
- * The first mode uses string pattern to determine if the key should be
|
|
|
- * returned or not. The other mode uses a string list to request the key
|
|
|
- * which should be listed.
|
|
|
- **/
|
|
|
-cdk_error_t
|
|
|
-cdk_listkey_start (cdk_listkey_t * r_ctx, cdk_keydb_hd_t db,
|
|
|
- const char *patt, cdk_strlist_t fpatt)
|
|
|
-{
|
|
|
- cdk_listkey_t ctx;
|
|
|
- cdk_stream_t inp;
|
|
|
- cdk_error_t rc;
|
|
|
-
|
|
|
- if (!r_ctx || !db)
|
|
|
- return CDK_Inv_Value;
|
|
|
- if ((patt && fpatt) || (!patt && !fpatt))
|
|
|
- return CDK_Inv_Mode;
|
|
|
- rc = _cdk_keydb_open (db, &inp);
|
|
|
- if (rc)
|
|
|
- return rc;
|
|
|
- ctx = cdk_calloc (1, sizeof *ctx);
|
|
|
- if (!ctx)
|
|
|
- return CDK_Out_Of_Core;
|
|
|
- ctx->db = db;
|
|
|
- ctx->inp = inp;
|
|
|
- if (patt)
|
|
|
- {
|
|
|
- ctx->u.patt = cdk_strdup (patt);
|
|
|
- if (!ctx->u.patt)
|
|
|
- return CDK_Out_Of_Core;
|
|
|
- }
|
|
|
- else if (fpatt)
|
|
|
- {
|
|
|
- cdk_strlist_t l;
|
|
|
- for (l = fpatt; l; l = l->next)
|
|
|
- cdk_strlist_add (&ctx->u.fpatt, l->d);
|
|
|
- }
|
|
|
- ctx->type = patt ? 1 : 0;
|
|
|
- ctx->init = 1;
|
|
|
- *r_ctx = ctx;
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/**
|
|
|
- * cdk_listkey_close:
|
|
|
- * @ctx: the list key context
|
|
|
- *
|
|
|
- * Free the list key context.
|
|
|
- **/
|
|
|
-void
|
|
|
-cdk_listkey_close (cdk_listkey_t ctx)
|
|
|
-{
|
|
|
- if (!ctx)
|
|
|
- return;
|
|
|
-
|
|
|
- if (ctx->type)
|
|
|
- cdk_free (ctx->u.patt);
|
|
|
- else
|
|
|
- cdk_strlist_free (ctx->u.fpatt);
|
|
|
- cdk_free (ctx);
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/**
|
|
|
- * cdk_listkey_next:
|
|
|
- * @ctx: list key context
|
|
|
- * @r_key: the pointer to the new key node object
|
|
|
- *
|
|
|
- * Retrieve the next key from the pattern of the key list context.
|
|
|
- **/
|
|
|
-cdk_error_t
|
|
|
-cdk_listkey_next (cdk_listkey_t ctx, cdk_kbnode_t * ret_key)
|
|
|
-{
|
|
|
- if (!ctx || !ret_key)
|
|
|
- return CDK_Inv_Value;
|
|
|
- if (!ctx->init)
|
|
|
- return CDK_Inv_Mode;
|
|
|
-
|
|
|
- if (ctx->type && ctx->u.patt[0] == '*')
|
|
|
- return cdk_keydb_get_keyblock (ctx->inp, ret_key);
|
|
|
- else if (ctx->type)
|
|
|
- {
|
|
|
- cdk_kbnode_t node;
|
|
|
- struct cdk_dbsearch_s ks;
|
|
|
- cdk_error_t rc;
|
|
|
-
|
|
|
- for (;;)
|
|
|
- {
|
|
|
- rc = cdk_keydb_get_keyblock (ctx->inp, &node);
|
|
|
- if (rc)
|
|
|
- return rc;
|
|
|
- memset (&ks, 0, sizeof (ks));
|
|
|
- ks.type = CDK_DBSEARCH_SUBSTR;
|
|
|
- ks.u.pattern = ctx->u.patt;
|
|
|
- if (find_by_pattern (node, &ks))
|
|
|
- {
|
|
|
- *ret_key = node;
|
|
|
- return 0;
|
|
|
- }
|
|
|
- cdk_kbnode_release (node);
|
|
|
- node = NULL;
|
|
|
- }
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- if (!ctx->t)
|
|
|
- ctx->t = ctx->u.fpatt;
|
|
|
- else if (ctx->t->next)
|
|
|
- ctx->t = ctx->t->next;
|
|
|
- else
|
|
|
- return CDK_EOF;
|
|
|
- return cdk_keydb_get_bypattern (ctx->db, ctx->t->d, ret_key);
|
|
|
- }
|
|
|
- return CDK_General_Error;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-int
|
|
|
-_cdk_keydb_is_secret (cdk_keydb_hd_t db)
|
|
|
-{
|
|
|
- return db->secret;
|
|
|
-}
|