mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
kbx: Add first version of STORE command to keyboxd.
* kbx/Makefile.am (keyboxd_CFLAGS): -DKEYBOX_WITH_X509. (keyboxd_LDADD): Add libksba. * kbx/kbxserver.c (cmd_store): New. * kbx/frontend.c (kbxd_store): New. * kbx/backend-support.c (is_x509_blob): New. (be_fingerprint_from_blob): New. * kbx/backend-kbx.c (be_kbx_seek): Add args FPR and FPRLEN. (be_kbx_insert): New. Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
parent
61765136cf
commit
c7293a4d12
@ -81,10 +81,10 @@ keyboxd_SOURCES = \
|
||||
backend-kbx.c \
|
||||
$(common_sources)
|
||||
|
||||
keyboxd_CFLAGS = $(AM_CFLAGS) $(LIBASSUAN_CFLAGS) $(NPTH_CFLAGS) \
|
||||
$(INCICONV)
|
||||
keyboxd_CFLAGS = $(AM_CFLAGS) -DKEYBOX_WITH_X509=1 \
|
||||
$(LIBASSUAN_CFLAGS) $(NPTH_CFLAGS) $(INCICONV)
|
||||
keyboxd_LDADD = $(commonpth_libs) \
|
||||
$(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) $(NPTH_LIBS) \
|
||||
$(KSBA_LIBS) $(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) $(NPTH_LIBS) \
|
||||
$(GPG_ERROR_LIBS) $(LIBINTL) $(NETLIBS) $(LIBICONV) \
|
||||
$(resource_objs)
|
||||
keyboxd_LDFLAGS = $(extra_bin_ldflags)
|
||||
|
@ -288,13 +288,15 @@ be_kbx_search (ctrl_t ctrl, backend_handle_t backend_hd, db_request_t request,
|
||||
}
|
||||
|
||||
|
||||
/* Seek in the keybox to the given UBID. BACKEND_HD is the handle for
|
||||
* this backend and REQUEST is the current database request object.
|
||||
* This does a dummy read so that the next search operation starts
|
||||
* right after that UBID. */
|
||||
/* Seek in the keybox to the given UBID (if UBID is not NULL) or to
|
||||
* the primary fingerprint specified by (FPR,FPRLEN). BACKEND_HD is
|
||||
* the handle for this backend and REQUEST is the current database
|
||||
* request object. This does a dummy read so that the next search
|
||||
* operation starts right after that UBID. */
|
||||
gpg_error_t
|
||||
be_kbx_seek (ctrl_t ctrl, backend_handle_t backend_hd,
|
||||
db_request_t request, unsigned char *ubid)
|
||||
db_request_t request, const unsigned char *ubid,
|
||||
const unsigned char *fpr, unsigned int fprlen)
|
||||
{
|
||||
gpg_error_t err;
|
||||
db_request_part_t part;
|
||||
@ -308,8 +310,19 @@ be_kbx_seek (ctrl_t ctrl, backend_handle_t backend_hd,
|
||||
log_assert (request);
|
||||
|
||||
memset (&desc, 0, sizeof desc);
|
||||
desc.mode = KEYDB_SEARCH_MODE_UBID;
|
||||
memcpy (desc.u.ubid, ubid, 20);
|
||||
if (ubid)
|
||||
{
|
||||
desc.mode = KEYDB_SEARCH_MODE_FPR;
|
||||
memcpy (desc.u.ubid, ubid, 20);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fprlen > sizeof desc.u.fpr)
|
||||
return gpg_error (GPG_ERR_TOO_LARGE);
|
||||
desc.mode = KEYDB_SEARCH_MODE_FPR;
|
||||
memcpy (desc.u.fpr, fpr, fprlen);
|
||||
desc.fprlen = fprlen;
|
||||
}
|
||||
|
||||
/* Find the specific request part or allocate it. */
|
||||
err = be_find_request_part (backend_hd, request, &part);
|
||||
@ -326,3 +339,50 @@ be_kbx_seek (ctrl_t ctrl, backend_handle_t backend_hd,
|
||||
leave:
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* Insert (BLOB,BLOBLEN) into the keybox. BACKEND_HD is the handle
|
||||
* for this backend and REQUEST is the current database request
|
||||
* object. */
|
||||
gpg_error_t
|
||||
be_kbx_insert (ctrl_t ctrl, backend_handle_t backend_hd,
|
||||
db_request_t request, enum pubkey_types pktype,
|
||||
const void *blob, size_t bloblen)
|
||||
{
|
||||
gpg_error_t err;
|
||||
db_request_part_t part;
|
||||
ksba_cert_t cert = NULL;
|
||||
|
||||
(void)ctrl;
|
||||
|
||||
log_assert (backend_hd && backend_hd->db_type == DB_TYPE_KBX);
|
||||
log_assert (request);
|
||||
|
||||
/* Find the specific request part or allocate it. */
|
||||
err = be_find_request_part (backend_hd, request, &part);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
if (pktype == PUBKEY_TYPE_OPGP)
|
||||
err = keybox_insert_keyblock (part->kbx_hd, blob, bloblen);
|
||||
else if (pktype == PUBKEY_TYPE_X509)
|
||||
{
|
||||
unsigned char sha1[20];
|
||||
|
||||
err = ksba_cert_new (&cert);
|
||||
if (err)
|
||||
goto leave;
|
||||
err = ksba_cert_init_from_mem (cert, blob, bloblen);
|
||||
if (err)
|
||||
goto leave;
|
||||
gcry_md_hash_buffer (GCRY_MD_SHA1, sha1, blob, bloblen);
|
||||
|
||||
err = keybox_insert_cert (part->kbx_hd, cert, sha1);
|
||||
}
|
||||
else
|
||||
err = gpg_error (GPG_ERR_WRONG_BLOB_TYPE);
|
||||
|
||||
leave:
|
||||
ksba_cert_release (cert);
|
||||
return err;
|
||||
}
|
||||
|
@ -27,8 +27,9 @@
|
||||
#include "keyboxd.h"
|
||||
#include "../common/i18n.h"
|
||||
#include "../common/asshelp.h"
|
||||
#include "../common/tlv.h"
|
||||
#include "backend.h"
|
||||
#include "keybox.h"
|
||||
#include "keybox-defs.h"
|
||||
|
||||
|
||||
/* Common definition part of all backend handle. All definitions of
|
||||
@ -169,3 +170,107 @@ be_return_pubkey (ctrl_t ctrl, const void *buffer, size_t buflen,
|
||||
leave:
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Return true if (BLOB/BLOBLEN) seems to be an X509 certificate. */
|
||||
static int
|
||||
is_x509_blob (const unsigned char *blob, size_t bloblen)
|
||||
{
|
||||
const unsigned char *p;
|
||||
size_t n, objlen, hdrlen;
|
||||
int class, tag, cons, ndef;
|
||||
|
||||
/* An X.509 certificate can be identified by this DER encoding:
|
||||
*
|
||||
* 30 82 05 B8 30 82 04 A0 A0 03 02 01 02 02 07 15 46 A0 BF 30 07 39
|
||||
* ----------- +++++++++++ ----- ++++++++ --------------------------
|
||||
* SEQUENCE SEQUENCE [0] INTEGER INTEGER
|
||||
* (tbs) (version) (s/n)
|
||||
*
|
||||
*/
|
||||
|
||||
p = blob;
|
||||
n = bloblen;
|
||||
if (parse_ber_header (&p, &n, &class, &tag, &cons, &ndef, &objlen, &hdrlen))
|
||||
return 0; /* Not a proper BER object. */
|
||||
if (!(class == CLASS_UNIVERSAL && tag == TAG_SEQUENCE && cons))
|
||||
return 0; /* Does not start with a sequence. */
|
||||
|
||||
if (parse_ber_header (&p, &n, &class, &tag, &cons, &ndef, &objlen, &hdrlen))
|
||||
return 0; /* Not a proper BER object. */
|
||||
if (!(class == CLASS_UNIVERSAL && tag == TAG_SEQUENCE && cons))
|
||||
return 0; /* No TBS sequence. */
|
||||
if (n < 7 || objlen < 7)
|
||||
return 0; /* Too short: [0], version and min. s/n required. */
|
||||
|
||||
if (parse_ber_header (&p, &n, &class, &tag, &cons, &ndef, &objlen, &hdrlen))
|
||||
return 0; /* Not a proper BER object. */
|
||||
if (!(class == CLASS_CONTEXT && tag == 0 && cons))
|
||||
return 0; /* No context tag. */
|
||||
|
||||
if (parse_ber_header (&p, &n, &class, &tag, &cons, &ndef, &objlen, &hdrlen))
|
||||
return 0; /* Not a proper BER object. */
|
||||
|
||||
if (!(class == CLASS_UNIVERSAL && tag == TAG_INTEGER
|
||||
&& !cons && objlen == 1 && n && (*p == 1 || *p == 2)))
|
||||
return 0; /* Unknown X.509 version. */
|
||||
p++; /* Skip version number. */
|
||||
n--;
|
||||
|
||||
if (parse_ber_header (&p, &n, &class, &tag, &cons, &ndef, &objlen, &hdrlen))
|
||||
return 0; /* Not a proper BER object. */
|
||||
if (!(class == CLASS_UNIVERSAL && tag == TAG_INTEGER && !cons))
|
||||
return 0; /* No s/n. */
|
||||
|
||||
return 1; /* Looks like an X.509 certificate. */
|
||||
}
|
||||
|
||||
|
||||
/* Return the public key type and the (primary) fingerprint for
|
||||
* (BLOB,BLOBLEN). R_FPR must point to a buffer of at least 32 bytes,
|
||||
* it received the fi gerprint on success with the length of that
|
||||
* fingerprint stored at R_FPRLEN. R_PKTYPE receives the public key
|
||||
* type. */
|
||||
gpg_error_t
|
||||
be_fingerprint_from_blob (const void *blob, size_t bloblen,
|
||||
enum pubkey_types *r_pktype,
|
||||
char *r_fpr, unsigned int *r_fprlen)
|
||||
{
|
||||
gpg_error_t err;
|
||||
|
||||
if (is_x509_blob (blob, bloblen))
|
||||
{
|
||||
/* Although libksba has a dedicated function to compute the
|
||||
* fingerprint we compute it here directly because we know that
|
||||
* we have the entire certificate here (we checked the start of
|
||||
* the blob and assume that the length is also okay). */
|
||||
*r_pktype = PUBKEY_TYPE_X509;
|
||||
gcry_md_hash_buffer (GCRY_MD_SHA1, r_fpr, blob, bloblen);
|
||||
*r_fprlen = 20;
|
||||
|
||||
err = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct _keybox_openpgp_info info;
|
||||
|
||||
err = _keybox_parse_openpgp (blob, bloblen, NULL, &info);
|
||||
if (err)
|
||||
{
|
||||
log_info ("error parsing OpenPGP blob: %s\n", gpg_strerror (err));
|
||||
err = gpg_error (GPG_ERR_WRONG_BLOB_TYPE);
|
||||
}
|
||||
else
|
||||
{
|
||||
*r_pktype = PUBKEY_TYPE_OPGP;
|
||||
log_assert (info.primary.fprlen <= 32);
|
||||
memcpy (r_fpr, info.primary.fpr, info.primary.fprlen);
|
||||
*r_fprlen = info.primary.fprlen;
|
||||
|
||||
_keybox_destroy_openpgp_info (&info);
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -106,6 +106,9 @@ gpg_error_t be_find_request_part (backend_handle_t backend_hd,
|
||||
gpg_error_t be_return_pubkey (ctrl_t ctrl, const void *buffer, size_t buflen,
|
||||
enum pubkey_types pubkey_type,
|
||||
const unsigned char *ubid);
|
||||
gpg_error_t be_fingerprint_from_blob (const void *blob, size_t bloblen,
|
||||
enum pubkey_types *r_pktype,
|
||||
char *r_fpr, unsigned int *r_fprlen);
|
||||
|
||||
|
||||
/*-- backend-cache.c --*/
|
||||
@ -134,7 +137,11 @@ gpg_error_t be_kbx_search (ctrl_t ctrl, backend_handle_t hd,
|
||||
db_request_t request,
|
||||
KEYDB_SEARCH_DESC *desc, unsigned int ndesc);
|
||||
gpg_error_t be_kbx_seek (ctrl_t ctrl, backend_handle_t backend_hd,
|
||||
db_request_t request, unsigned char *ubid);
|
||||
db_request_t request, const unsigned char *ubid,
|
||||
const unsigned char *fpr, unsigned int fprlen);
|
||||
gpg_error_t be_kbx_insert (ctrl_t ctrl, backend_handle_t backend_hd,
|
||||
db_request_t request, enum pubkey_types pktype,
|
||||
const void *blob, size_t bloblen);
|
||||
|
||||
|
||||
#endif /*KBX_BACKEND_H*/
|
||||
|
@ -58,12 +58,12 @@ take_read_lock (ctrl_t ctrl)
|
||||
|
||||
|
||||
/* Take a lock for reading and writing the databases. */
|
||||
/* static void */
|
||||
/* take_read_write_lock (ctrl_t ctrl) */
|
||||
/* { */
|
||||
/* /\* FIXME *\/ */
|
||||
/* (void)ctrl; */
|
||||
/* } */
|
||||
static void
|
||||
take_read_write_lock (ctrl_t ctrl)
|
||||
{
|
||||
/* FIXME */
|
||||
(void)ctrl;
|
||||
}
|
||||
|
||||
|
||||
/* Release a lock. It is valid to call this even if no lock has been
|
||||
@ -339,7 +339,7 @@ kbxd_search (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, unsigned int ndesc,
|
||||
{
|
||||
/* We need to set the startpoint for the search. */
|
||||
err = be_kbx_seek (ctrl, db->backend_handle, request,
|
||||
request->last_cached_ubid);
|
||||
request->last_cached_ubid, NULL, 0);
|
||||
if (err)
|
||||
{
|
||||
log_debug ("%s: seeking %s to an UBID failed: %s\n",
|
||||
@ -383,3 +383,83 @@ kbxd_search (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, unsigned int ndesc,
|
||||
log_clock ("%s: leave (%s)", __func__, err? "not found" : "found");
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Store; that is insert or update the key (BLOB,BLOBLEN). If
|
||||
* ONLY_UPDATE is set the key must exist. */
|
||||
gpg_error_t
|
||||
kbxd_store (ctrl_t ctrl, const void *blob, size_t bloblen, int only_update)
|
||||
{
|
||||
gpg_error_t err;
|
||||
db_request_t request;
|
||||
unsigned int dbidx;
|
||||
db_desc_t db;
|
||||
char fpr[32];
|
||||
unsigned int fprlen;
|
||||
enum pubkey_types pktype;
|
||||
int insert = 0;
|
||||
|
||||
if (DBG_CLOCK)
|
||||
log_clock ("%s: enter", __func__);
|
||||
|
||||
take_read_write_lock (ctrl);
|
||||
|
||||
/* Allocate a handle object if none exists for this context. */
|
||||
if (!ctrl->opgp_req)
|
||||
{
|
||||
ctrl->opgp_req = xtrycalloc (1, sizeof *ctrl->opgp_req);
|
||||
if (!ctrl->opgp_req)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
request = ctrl->opgp_req;
|
||||
|
||||
/* Check whether to insert or update. */
|
||||
err = be_fingerprint_from_blob (blob, bloblen, &pktype, fpr, &fprlen);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
/* FIXME: We force the use of the KBX backend. */
|
||||
for (dbidx=0; dbidx < no_of_databases; dbidx++)
|
||||
if (databases[dbidx].db_type == DB_TYPE_KBX)
|
||||
break;
|
||||
if (!(dbidx < no_of_databases))
|
||||
{
|
||||
err = gpg_error (GPG_ERR_NOT_INITIALIZED);
|
||||
goto leave;
|
||||
}
|
||||
db = databases + dbidx;
|
||||
|
||||
err = be_kbx_seek (ctrl, db->backend_handle, request, NULL, fpr, fprlen);
|
||||
if (!err)
|
||||
; /* Found - need to update. */
|
||||
else if (gpg_err_code (err) == GPG_ERR_EOF)
|
||||
insert = 1; /* Not found - need to insert. */
|
||||
else
|
||||
{
|
||||
log_debug ("%s: searching fingerprint failed: %s\n",
|
||||
__func__, gpg_strerror (err));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if (insert)
|
||||
{
|
||||
err = be_kbx_insert (ctrl, db->backend_handle, request,
|
||||
pktype, blob, bloblen);
|
||||
}
|
||||
else if (only_update)
|
||||
err = gpg_error (GPG_ERR_DUP_KEY);
|
||||
else /* Update. */
|
||||
{
|
||||
err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
leave:
|
||||
release_lock (ctrl);
|
||||
if (DBG_CLOCK)
|
||||
log_clock ("%s: leave", __func__);
|
||||
return err;
|
||||
}
|
||||
|
@ -31,6 +31,8 @@ void kbxd_release_session_info (ctrl_t ctrl);
|
||||
gpg_error_t kbxd_search (ctrl_t ctrl,
|
||||
KEYDB_SEARCH_DESC *desc, unsigned int ndesc,
|
||||
int reset);
|
||||
gpg_error_t kbxd_store (ctrl_t ctrl, const void *blob, size_t bloblen,
|
||||
int only_update);
|
||||
|
||||
|
||||
#endif /*KBX_FRONTEND_H*/
|
||||
|
@ -465,6 +465,55 @@ cmd_next (assuan_context_t ctx, char *line)
|
||||
}
|
||||
|
||||
|
||||
static const char hlp_store[] =
|
||||
"STORE [--update]\n"
|
||||
"\n"
|
||||
"Insert a key into the database. Whether to insert or update\n"
|
||||
"the key is decided by looking at the primary key's fingerprint.\n"
|
||||
"With option --update the key must already exist. The actual key\n"
|
||||
"material is requested by this function using\n"
|
||||
" INQUIRE BLOB";
|
||||
static gpg_error_t
|
||||
cmd_store (assuan_context_t ctx, char *line)
|
||||
{
|
||||
ctrl_t ctrl = assuan_get_pointer (ctx);
|
||||
int opt_update;
|
||||
gpg_error_t err;
|
||||
unsigned char *value = NULL;
|
||||
size_t valuelen;
|
||||
|
||||
opt_update = has_option (line, "--update");
|
||||
line = skip_options (line);
|
||||
if (*line)
|
||||
{
|
||||
err = set_error (GPG_ERR_INV_ARG, "no args expected");
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* Ask for the key material. */
|
||||
err = assuan_inquire (ctx, "BLOB", &value, &valuelen, 0);
|
||||
if (err)
|
||||
{
|
||||
log_error (_("assuan_inquire failed: %s\n"), gpg_strerror (err));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if (!valuelen) /* No data received. */
|
||||
{
|
||||
err = gpg_error (GPG_ERR_MISSING_VALUE);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
err = kbxd_store (ctrl, value, valuelen, opt_update);
|
||||
|
||||
|
||||
leave:
|
||||
xfree (value);
|
||||
return leave_cmd (ctx, err);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static const char hlp_getinfo[] =
|
||||
"GETINFO <what>\n"
|
||||
@ -584,6 +633,7 @@ register_commands (assuan_context_t ctx)
|
||||
} table[] = {
|
||||
{ "SEARCH", cmd_search, hlp_search },
|
||||
{ "NEXT", cmd_next, hlp_next },
|
||||
{ "STORE", cmd_store, hlp_store },
|
||||
{ "GETINFO", cmd_getinfo, hlp_getinfo },
|
||||
{ "OUTPUT", NULL, hlp_output },
|
||||
{ "KILLKEYBOXD",cmd_killkeyboxd,hlp_killkeyboxd },
|
||||
|
@ -667,7 +667,7 @@ _keybox_destroy_openpgp_info (keybox_openpgp_info_t info)
|
||||
struct _keybox_openpgp_key_info *k, *k2;
|
||||
struct _keybox_openpgp_uid_info *u, *u2;
|
||||
|
||||
assert (!info->primary.next);
|
||||
log_assert (!info->primary.next);
|
||||
for (k=info->subkeys.next; k; k = k2)
|
||||
{
|
||||
k2 = k->next;
|
||||
|
Loading…
x
Reference in New Issue
Block a user