diff options
author | Werner Koch <wk@gnupg.org> | 2020-09-10 13:05:17 +0200 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 2020-09-10 13:05:17 +0200 |
commit | ed6ebb696e4063dc664d7ee74fc492025881c459 (patch) | |
tree | 0cfe048023a2a390802bbde31f35a2ac247158cf /sm | |
parent | keyboxd: Add basic support for X.509. (diff) | |
download | gnupg2-ed6ebb696e4063dc664d7ee74fc492025881c459.tar.xz gnupg2-ed6ebb696e4063dc664d7ee74fc492025881c459.zip |
sm: Implement initial support for keyboxd.
* sm/gpgsm.h (MAX_FINGERPRINT_LEN): New.
* sm/keydb.c (struct keydb_local_s): Change definition of
search_result.
(keydb_get_cert): Implement keyboxd mode.
(keydb_get_flags): Temporary hack for keyboxd mode. Needs to be
fixed.
(struct store_parm_s, store_inq_cb): New.
(keydb_insert_cert): Implement keyboxd mode.
(keydb_locate_writable): Make static.
(keydb_search_reset): Implement keyboxd mode.
(search_status_cb): New.
(keydb_search): Implement keyboxd mode. Replace return code -1 by
GPG_ERR_NOT_FOUND.
(keydb_set_cert_flags): Replace return code -1 by GPG_ERR_NOT_FOUND.
* sm/keylist.c (list_cert_colon): Adjust for replacement of -1 by
GPG_ERR_NOT_FOUND.
(list_internal_keys): Ditto.
* sm/sign.c (add_certificate_list): Ditto.
* sm/certchain.c (find_up_search_by_keyid): Ditto.
(find_up_external, find_up, find_up_dirmngr): Ditto.
(gpgsm_walk_cert_chain): Ditto.
(get_regtp_ca_info): Ditto.
* sm/certlist.c (gpgsm_add_to_certlist): Ditto.
(gpgsm_find_cert): Ditto.
* sm/delete.c (delete_one): Ditto.
* sm/export.c (gpgsm_export): Ditto.
(gpgsm_p12_export): Ditto.
* sm/import.c (gpgsm_import_files): Ditto.
--
Note that keyboxd is not yet able to handle the ephemeral flag. This
needs fixing here and in keyboxd. Delete et al. is also not yet
implemented. A basic key listing works, though.
Signed-off-by: Werner Koch <wk@gnupg.org>
Diffstat (limited to 'sm')
-rw-r--r-- | sm/certchain.c | 62 | ||||
-rw-r--r-- | sm/certlist.c | 12 | ||||
-rw-r--r-- | sm/delete.c | 4 | ||||
-rw-r--r-- | sm/export.c | 4 | ||||
-rw-r--r-- | sm/gpgsm.h | 12 | ||||
-rw-r--r-- | sm/import.c | 2 | ||||
-rw-r--r-- | sm/keydb.c | 367 | ||||
-rw-r--r-- | sm/keydb.h | 3 | ||||
-rw-r--r-- | sm/keylist.c | 5 | ||||
-rw-r--r-- | sm/sign.c | 2 |
10 files changed, 382 insertions, 91 deletions
diff --git a/sm/certchain.c b/sm/certchain.c index 53bdea612..d4047fd53 100644 --- a/sm/certchain.c +++ b/sm/certchain.c @@ -440,7 +440,7 @@ check_cert_policy (ksba_cert_t cert, int listmode, estream_t fplist) /* Helper function for find_up. This resets the key handle and search for an issuer ISSUER with a subjectKeyIdentifier of KEYID. Returns - 0 on success or -1 when not found. */ + 0 on success or GPG_ERR_NOT_FOUND when not found. */ static int find_up_search_by_keyid (ctrl_t ctrl, KEYDB_HANDLE kh, const char *issuer, ksba_sexp_t keyid) @@ -460,7 +460,7 @@ find_up_search_by_keyid (ctrl_t ctrl, KEYDB_HANDLE kh, if (rc) { log_error ("keydb_get_cert() failed: rc=%d\n", rc); - rc = -1; + rc = gpg_error (GPG_ERR_NOT_FOUND); goto leave; } xfree (subj); @@ -475,7 +475,7 @@ find_up_search_by_keyid (ctrl_t ctrl, KEYDB_HANDLE kh, if (rc) { log_error ("keydb_get_validity() failed: rc=%d\n", rc); - rc = -1; + rc = gpg_error (GPG_ERR_NOT_FOUND); goto leave; } @@ -544,7 +544,7 @@ find_up_search_by_keyid (ctrl_t ctrl, KEYDB_HANDLE kh, if (rc) { log_error ("keydb_get_validity() failed: rc=%d\n", rc); - rc = -1; + rc = gpg_error (GPG_ERR_NOT_FOUND); goto leave; } if (*not_after && strcmp (ctrl->current_time, not_after) > 0 ) @@ -558,7 +558,7 @@ find_up_search_by_keyid (ctrl_t ctrl, KEYDB_HANDLE kh, if (rc) { log_error ("keydb_search_fpr() failed: rc=%d\n", rc); - rc = -1; + rc = gpg_error (GPG_ERR_NOT_FOUND); goto leave; } /* Ready. The NE_FOUND_CERT is available via keydb_get_cert. */ @@ -569,7 +569,7 @@ find_up_search_by_keyid (ctrl_t ctrl, KEYDB_HANDLE kh, ksba_cert_release (ne_found_cert); ksba_cert_release (cert); xfree (subj); - return rc? -1:0; + return rc? gpg_error (GPG_ERR_NOT_FOUND) : 0; } @@ -646,10 +646,10 @@ find_up_external (ctrl_t ctrl, KEYDB_HANDLE kh, if (rc) { log_error ("external key lookup failed: %s\n", gpg_strerror (rc)); - rc = -1; + rc = gpg_error (GPG_ERR_NOT_FOUND); } else if (!find_up_store_certs_parm.count) - rc = -1; + rc = gpg_err_code (rc) == GPG_ERR_NOT_FOUND; else { int old; @@ -818,7 +818,8 @@ find_up_dirmngr (ctrl_t ctrl, KEYDB_HANDLE kh, if (rc && !opt.quiet) log_info (_("dirmngr cache-only key lookup failed: %s\n"), gpg_strerror (rc)); - return (!rc && find_up_store_certs_parm.count)? 0 : -1; + return ((!rc && find_up_store_certs_parm.count) + ? 0 : gpg_error (GPG_ERR_NOT_FOUND)); } @@ -828,7 +829,7 @@ find_up_dirmngr (ctrl_t ctrl, KEYDB_HANDLE kh, FIND_NEXT is true, the function shall return the next possible issuer. The certificate itself is not directly returned but a keydb_get_cert on the keydb context KH will return it. Returns 0 - on success, -1 if not found or an error code. */ + on success, GPG_ERR_NOT_FOUND if not found or another error code. */ static int find_up (ctrl_t ctrl, KEYDB_HANDLE kh, ksba_cert_t cert, const char *issuer, int find_next) @@ -857,13 +858,13 @@ find_up (ctrl_t ctrl, KEYDB_HANDLE kh, into the ephemeral DB and let the code below do the actual retrieve. Thus there is no error checking. Skipped in find_next mode as usual. */ - if (rc == -1 && !find_next) + if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND && !find_next) find_up_dirmngr (ctrl, kh, authidno, s, 0); /* In case of an error try the ephemeral DB. We can't do that in find_next mode because we can't keep the search state then. */ - if (rc == -1 && !find_next) + if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND && !find_next) { int old = keydb_set_ephemeral (kh, 1); if (!old) @@ -877,11 +878,11 @@ find_up (ctrl_t ctrl, KEYDB_HANDLE kh, } keydb_set_ephemeral (kh, old); } - if (rc) - rc = -1; /* Need to make sure to have this error code. */ + if (rc) /* Need to make sure to have this error code. */ + rc = gpg_error (GPG_ERR_NOT_FOUND); } - if (rc == -1 && keyid && !find_next) + if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND && keyid && !find_next) { /* Not found by AKI.issuer_sn. Lets try the AKI.ki instead. Loop over all certificates with that issuer as @@ -900,13 +901,13 @@ find_up (ctrl_t ctrl, KEYDB_HANDLE kh, log_debug (" found via authid and keyid (ephem)\n"); keydb_set_ephemeral (kh, old); } - if (rc) - rc = -1; /* Need to make sure to have this error code. */ + if (rc) /* Need to make sure to have this error code. */ + rc = gpg_error (GPG_ERR_NOT_FOUND); } /* If we still didn't found it, try to find it via the subject from the dirmngr-cache. */ - if (rc == -1 && !find_next) + if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND && !find_next) { if (!find_up_dirmngr (ctrl, kh, NULL, issuer, 1)) { @@ -920,15 +921,16 @@ find_up (ctrl_t ctrl, KEYDB_HANDLE kh, } keydb_set_ephemeral (kh, old); } - if (rc) - rc = -1; /* Need to make sure to have this error code. */ + if (rc) /* Need to make sure to have this error code. */ + rc = gpg_error (GPG_ERR_NOT_FOUND); if (!rc && DBG_X509) log_debug (" found via authid and issuer from dirmngr cache\n"); } /* If we still didn't found it, try an external lookup. */ - if (rc == -1 && !find_next && !ctrl->offline) + if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND + && !find_next && !ctrl->offline) { /* We allow AIA also if CRLs are enabled; both can be used * as a web bug so it does not make sense to not use AIA if @@ -952,9 +954,9 @@ find_up (ctrl_t ctrl, KEYDB_HANDLE kh, /* Print a note so that the user does not feel too helpless when an issuer certificate was found and gpgsm prints BAD signature because it is not the correct one. */ - if (rc == -1 && opt.quiet) + if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND && opt.quiet) ; - else if (rc == -1) + else if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND) { log_info ("%sissuer certificate ", find_next?"next ":""); if (keyid) @@ -982,7 +984,7 @@ find_up (ctrl_t ctrl, KEYDB_HANDLE kh, if (rc) /* Not found via authorithyKeyIdentifier, try regular issuer name. */ rc = keydb_search_subject (ctrl, kh, issuer); - if (rc == -1 && !find_next) + if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND && !find_next) { int old; @@ -1004,7 +1006,7 @@ find_up (ctrl_t ctrl, KEYDB_HANDLE kh, } /* Still not found. If enabled, try an external lookup. */ - if (rc == -1 && !find_next && !ctrl->offline) + if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND && !find_next && !ctrl->offline) { if ((opt.auto_issuer_key_retrieve || !opt.no_crl_check) && !find_up_via_auth_info_access (ctrl, kh, cert)) @@ -1026,8 +1028,8 @@ find_up (ctrl_t ctrl, KEYDB_HANDLE kh, /* Return the next certificate up in the chain starting at START. - Returns -1 when there are no more certificates. */ -int + Returns GPG_ERR_NOT_FOUND when there are no more certificates. */ +gpg_error_t gpgsm_walk_cert_chain (ctrl_t ctrl, ksba_cert_t start, ksba_cert_t *r_next) { int rc = 0; @@ -1060,7 +1062,7 @@ gpgsm_walk_cert_chain (ctrl_t ctrl, ksba_cert_t start, ksba_cert_t *r_next) if (is_root_cert (start, issuer, subject)) { - rc = -1; /* we are at the root */ + rc = gpg_error (GPG_ERR_NOT_FOUND); /* we are at the root */ goto leave; } @@ -1069,7 +1071,7 @@ gpgsm_walk_cert_chain (ctrl_t ctrl, ksba_cert_t start, ksba_cert_t *r_next) { /* It is quite common not to have a certificate, so better don't print an error here. */ - if (rc != -1 && opt.verbose > 1) + if (gpg_err_code (rc) != GPG_ERR_NOT_FOUND && opt.verbose > 1) log_error ("failed to find issuer's certificate: rc=%d\n", rc); rc = gpg_error (GPG_ERR_MISSING_ISSUER_CERT); goto leave; @@ -2340,7 +2342,7 @@ get_regtp_ca_info (ctrl_t ctrl, ksba_cert_t cert, int *chainlen) cert = next; } ksba_cert_release (cert); - if (rc != -1 || !depth || depth == DIM(array) ) + if (gpg_err_code (rc) != GPG_ERR_NOT_FOUND || !depth || depth == DIM(array) ) { /* We did not reached the root. */ goto leave; diff --git a/sm/certlist.c b/sm/certlist.c index d18fce62c..61125acba 100644 --- a/sm/certlist.c +++ b/sm/certlist.c @@ -376,7 +376,7 @@ gpgsm_add_to_certlist (ctrl_t ctrl, const char *name, int secret, next_ambigious: rc = keydb_search (ctrl, kh, &desc, 1); - if (rc == -1) + if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND) rc = 0; else if (!rc) { @@ -450,7 +450,7 @@ gpgsm_add_to_certlist (ctrl_t ctrl, const char *name, int secret, { certlist_t cl = xtrycalloc (1, sizeof *cl); if (!cl) - rc = out_of_core (); + rc = gpg_error_from_syserror (); else { cl->cert = cert; cert = NULL; @@ -465,7 +465,8 @@ gpgsm_add_to_certlist (ctrl_t ctrl, const char *name, int secret, keydb_release (kh); ksba_cert_release (cert); - return rc == -1? gpg_error (GPG_ERR_NO_PUBKEY): rc; + return (gpg_err_code (rc) == GPG_ERR_NOT_FOUND + ? gpg_error (GPG_ERR_NO_PUBKEY): rc); } @@ -549,7 +550,7 @@ gpgsm_find_cert (ctrl_t ctrl, } next_ambiguous: rc = keydb_search (ctrl, kh, &desc, 1); - if (rc == -1) + if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND) rc = 0; else { @@ -603,5 +604,6 @@ gpgsm_find_cert (ctrl_t ctrl, } keydb_release (kh); - return rc == -1? gpg_error (GPG_ERR_NO_PUBKEY): rc; + return (gpg_err_code (rc) == GPG_ERR_NOT_FOUND? + gpg_error (GPG_ERR_NO_PUBKEY): rc); } diff --git a/sm/delete.c b/sm/delete.c index 00840a4de..511ffb9b2 100644 --- a/sm/delete.c +++ b/sm/delete.c @@ -80,7 +80,7 @@ delete_one (ctrl_t ctrl, const char *username) next_ambigious: rc = keydb_search (ctrl, kh, &desc, 1); - if (rc == -1) + if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND) rc = 0; else if (!rc) { @@ -104,7 +104,7 @@ delete_one (ctrl_t ctrl, const char *username) } if (rc) { - if (rc == -1) + if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND) rc = gpg_error (GPG_ERR_NO_PUBKEY); log_error (_("certificate '%s' not found: %s\n"), username, gpg_strerror (rc)); diff --git a/sm/export.c b/sm/export.c index bba24f0b1..32f04565f 100644 --- a/sm/export.c +++ b/sm/export.c @@ -295,7 +295,7 @@ gpgsm_export (ctrl_t ctrl, strlist_t names, estream_t stream) ksba_cert_release (cert); cert = NULL; } - if (rc && rc != -1) + if (rc && gpg_err_code (rc) != GPG_ERR_NOT_FOUND) log_error ("keydb_search failed: %s\n", gpg_strerror (rc)); else if (b64writer) { @@ -389,7 +389,7 @@ gpgsm_p12_export (ctrl_t ctrl, const char *name, estream_t stream, int rawmode) } err = gpg_error (GPG_ERR_AMBIGUOUS_NAME); } - else if (err == -1 || gpg_err_code (err) == GPG_ERR_EOF) + else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND) err = 0; if (err) { diff --git a/sm/gpgsm.h b/sm/gpgsm.h index 05f06d17b..e96f15743 100644 --- a/sm/gpgsm.h +++ b/sm/gpgsm.h @@ -36,8 +36,14 @@ #include "../common/ksba-io-support.h" #include "../common/compliance.h" +/* The maximum length of a binary fingerprints. This is used to + * provide a static buffer and will be increased if we need to support + * longer fingerprints. */ +#define MAX_FINGERPRINT_LEN 32 + +/* The maximum length of a binary digest. */ +#define MAX_DIGEST_LEN 64 /* Fits for SHA-512 */ -#define MAX_DIGEST_LEN 64 struct keyserver_spec { @@ -353,8 +359,8 @@ int gpgsm_create_cms_signature (ctrl_t ctrl, #define VALIDATE_FLAG_CHAIN_MODEL 2 #define VALIDATE_FLAG_STEED 4 -int gpgsm_walk_cert_chain (ctrl_t ctrl, - ksba_cert_t start, ksba_cert_t *r_next); +gpg_error_t gpgsm_walk_cert_chain (ctrl_t ctrl, + ksba_cert_t start, ksba_cert_t *r_next); int gpgsm_is_root_cert (ksba_cert_t cert); int gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime, diff --git a/sm/import.c b/sm/import.c index 988d127d1..8e5634182 100644 --- a/sm/import.c +++ b/sm/import.c @@ -550,7 +550,7 @@ gpgsm_import_files (ctrl_t ctrl, int nfiles, char **files, int fd = of (*files); rc = import_one (ctrl, &stats, fd); close (fd); - if (rc == -1) + if (rc == -1/* legacy*/ || gpg_err_code (rc) == GPG_ERR_NOT_FOUND) rc = 0; } } diff --git a/sm/keydb.c b/sm/keydb.c index d7525bd76..47f8a0bce 100644 --- a/sm/keydb.c +++ b/sm/keydb.c @@ -68,7 +68,10 @@ struct keydb_local_s /* I/O buffer with the last search result or NULL. Used if * D-lines are used to convey the keyblocks. */ - iobuf_t search_result; + struct { + char *buf; + size_t len; + } search_result; /* This flag set while an operation is running on this context. */ unsigned int is_active : 1; @@ -931,15 +934,11 @@ keydb_pop_found_state (KEYDB_HANDLE hd) -/* - Return the last found object. Caller must free it. The returned - keyblock has the kbode flag bit 0 set for the node with the public - key used to locate the keyblock or flag bit 1 set for the user ID - node. */ +/* Return the last found certificate. Caller must free it. */ int keydb_get_cert (KEYDB_HANDLE hd, ksba_cert_t *r_cert) { - int rc = 0; + int err = 0; if (!hd) return gpg_error (GPG_ERR_INV_VALUE); @@ -949,31 +948,62 @@ keydb_get_cert (KEYDB_HANDLE hd, ksba_cert_t *r_cert) if (hd->use_keyboxd) { - /* FIXME */ + ksba_cert_t cert; + + /* Fixme: We should clear that also in non-keyboxd mode but we + * did not in the past and thus all code should be checked + * whether this is okay. If we run into error in keyboxd mode, + * this is a not as severe because keyboxd is currently + * experimental. */ + *r_cert = NULL; + + if (!hd->kbl->search_result.buf || !hd->kbl->search_result.len) + { + err = gpg_error (GPG_ERR_VALUE_NOT_FOUND); + goto leave; + } + err = ksba_cert_new (&cert); + if (err) + goto leave; + err = ksba_cert_init_from_mem (cert, + hd->kbl->search_result.buf, + hd->kbl->search_result.len); + if (err) + { + ksba_cert_release (cert); + goto leave; + } + xfree (hd->kbl->search_result.buf); + hd->kbl->search_result.buf = NULL; + hd->kbl->search_result.len = 0; + *r_cert = cert; goto leave; } if ( hd->found < 0 || hd->found >= hd->used) { - rc = -1; /* nothing found */ + /* Fixme: It would be better to use GPG_ERR_VALUE_NOT_FOUND here + * but for now we use NOT_FOUND because that is our standard + * replacement for the formerly used (-1). */ + err = gpg_error (GPG_ERR_NOT_FOUND); /* nothing found */ goto leave; } - rc = GPG_ERR_BUG; + err = GPG_ERR_BUG; switch (hd->active[hd->found].type) { case KEYDB_RESOURCE_TYPE_NONE: - rc = gpg_error (GPG_ERR_GENERAL); /* oops */ + err = gpg_error (GPG_ERR_GENERAL); /* oops */ break; case KEYDB_RESOURCE_TYPE_KEYBOX: - rc = keybox_get_cert (hd->active[hd->found].u.kr, r_cert); + err = keybox_get_cert (hd->active[hd->found].u.kr, r_cert); break; } leave: if (DBG_CLOCK) - log_clock ("%s: leave (rc=%d)\n", __func__, rc); - return rc; + log_clock ("%s: leave (rc=%d)\n", __func__, err); + return err; } @@ -995,6 +1025,8 @@ keydb_get_flags (KEYDB_HANDLE hd, int which, int idx, unsigned int *value) if (hd->use_keyboxd) { /* FIXME */ + *value = 0; + err = 0; goto leave; } @@ -1073,6 +1105,36 @@ keydb_set_flags (KEYDB_HANDLE hd, int which, int idx, unsigned int value) return err; } + + +/* Communication object for Keyboxd STORE commands. */ +struct store_parm_s +{ + assuan_context_t ctx; + const void *data; /* The certificate in X.509 binary format. */ + size_t datalen; /* The length of DATA. */ +}; + + +/* Handle the inquiries from the STORE command. */ +static gpg_error_t +store_inq_cb (void *opaque, const char *line) +{ + struct store_parm_s *parm = opaque; + gpg_error_t err = 0; + + if (has_leading_keyword (line, "BLOB")) + { + if (parm->data) + err = assuan_send_data (parm->ctx, parm->data, parm->datalen); + } + else + return gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE); + + return err; +} + + /* * Insert a new Certificate into one of the resources. */ @@ -1094,7 +1156,20 @@ keydb_insert_cert (KEYDB_HANDLE hd, ksba_cert_t cert) if (hd->use_keyboxd) { - /* FIXME */ + struct store_parm_s parm; + + parm.ctx = hd->kbl->ctx; + parm.data = ksba_cert_get_image (cert, &parm.datalen); + if (!parm.data) + { + log_debug ("broken ksba cert object\n"); + err = gpg_error (GPG_ERR_GENERAL); + goto leave; + } + err = assuan_transact (hd->kbl->ctx, "STORE --insert", + NULL, NULL, + store_inq_cb, &parm, + NULL, NULL); goto leave; } @@ -1246,7 +1321,7 @@ keydb_delete (KEYDB_HANDLE hd) * operation (which is only relevant for inserts) will be done on this * resource. */ -int +static gpg_error_t keydb_locate_writable (KEYDB_HANDLE hd, const char *reserved) { int rc; @@ -1277,7 +1352,7 @@ keydb_locate_writable (KEYDB_HANDLE hd, const char *reserved) } } - return -1; + return gpg_error (GPG_ERR_NOT_FOUND); } /* @@ -1328,11 +1403,16 @@ keydb_search_reset (KEYDB_HANDLE hd) hd->found = -1; if (hd->use_keyboxd) { - /* FIXME */ - } + /* All we need is to tell search that a reset is pending. Note that + * keydb_new sets this flag as well. To comply with the + * specification of keydb_delete_keyblock we also need to clear the + * ubid flag so that after a reset a delete can't be performed. */ + hd->kbl->need_search_reset = 1; + hd->last_ubid_valid = 0; + } else { - /* and reset all resources */ + /* Reset all resources */ for (i=0; !err && i < hd->used; i++) { switch (hd->active[i].type) @@ -1404,15 +1484,59 @@ keydb_search_desc_dump (struct keydb_search_desc *desc) } -/* - * Search through all keydb resources, starting at the current position, - * for a keyblock which contains one of the keys described in the DESC array. - */ -int + +/* Status callback for SEARCH and NEXT operaions. */ +static gpg_error_t +search_status_cb (void *opaque, const char *line) +{ + KEYDB_HANDLE hd = opaque; + gpg_error_t err = 0; + const char *s; + + if ((s = has_leading_keyword (line, "PUBKEY_INFO"))) + { + if (atoi (s) != PUBKEY_TYPE_X509) + err = gpg_error (GPG_ERR_WRONG_BLOB_TYPE); + else + { + hd->last_ubid_valid = 0; + while (*s && !spacep (s)) + s++; + if (hex2fixedbuf (s, hd->last_ubid, sizeof hd->last_ubid)) + hd->last_ubid_valid = 1; + else + err = gpg_error (GPG_ERR_INV_VALUE); + } + } + + return err; +} + +/* Search through all keydb resources, starting at the current + * position, for a keyblock which contains one of the keys described + * in the DESC array. In keyboxd mode the search is instead delegated + * to the keyboxd. + * + * DESC is an array of search terms with NDESC entries. The search + * terms are or'd together. That is, the next entry in the DB that + * matches any of the descriptions will be returned. + * + * Note: this function resumes searching where the last search left + * off (i.e., at the current file position). If you want to search + * from the start of the database, then you need to first call + * keydb_search_reset(). + * + * If no key matches the search description, the error code + * GPG_ERR_NOT_FOUND is retruned. If there was a match, 0 is + * returned. If an error occurred, that error code is returned. + * + * The returned key is considered to be selected and the certificate + * can be detched via keydb_get_cert. */ +gpg_error_t keydb_search (ctrl_t ctrl, KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc, size_t ndesc) { - int rc = -1; + gpg_error_t err = gpg_error (GPG_ERR_EOF); unsigned long skipped; int i; @@ -1442,11 +1566,164 @@ keydb_search (ctrl_t ctrl, KEYDB_HANDLE hd, if (hd->use_keyboxd) { - /* FIXME */ + char line[ASSUAN_LINELENGTH]; + + /* Clear the result objects. */ + if (hd->kbl->search_result.buf) + { + xfree (hd->kbl->search_result.buf); + hd->kbl->search_result.buf = NULL; + hd->kbl->search_result.len = 0; + } + + /* Check whether this is a NEXT search. */ + if (!hd->kbl->need_search_reset) + { + /* A reset was not requested thus continue the search. The + * keyboxd keeps the context of the search and thus the NEXT + * operates on the last search pattern. This is the way how + * we always used the keydb functions. In theory we were + * able to modify the search pattern between searches but + * that is not anymore supported by keyboxd and a cursory + * check does not show that we actually made use of that + * misfeature. */ + snprintf (line, sizeof line, "NEXT --x509"); + goto do_search; + } + + hd->kbl->need_search_reset = 0; + + if (!ndesc) + { + err = gpg_error (GPG_ERR_INV_ARG); + goto leave; + } + + /* FIXME: Implement --multi */ + switch (desc->mode) + { + case KEYDB_SEARCH_MODE_EXACT: + snprintf (line, sizeof line, "SEARCH --x509 =%s", desc[0].u.name); + break; + + case KEYDB_SEARCH_MODE_SUBSTR: + snprintf (line, sizeof line, "SEARCH --x509 *%s", desc[0].u.name); + break; + + case KEYDB_SEARCH_MODE_MAIL: + snprintf (line, sizeof line, "SEARCH --x509 <%s", desc[0].u.name); + break; + + case KEYDB_SEARCH_MODE_MAILSUB: + snprintf (line, sizeof line, "SEARCH --x509 @%s", desc[0].u.name); + break; + + case KEYDB_SEARCH_MODE_MAILEND: + snprintf (line, sizeof line, "SEARCH --x509 .%s", desc[0].u.name); + break; + + case KEYDB_SEARCH_MODE_WORDS: + snprintf (line, sizeof line, "SEARCH --x509 +%s", desc[0].u.name); + break; + + case KEYDB_SEARCH_MODE_SHORT_KID: + snprintf (line, sizeof line, "SEARCH --x509 0x%08lX", + (ulong)desc->u.kid[1]); + break; + + case KEYDB_SEARCH_MODE_LONG_KID: + snprintf (line, sizeof line, "SEARCH --x509 0x%08lX%08lX", + (ulong)desc->u.kid[0], (ulong)desc->u.kid[1]); + break; + + case KEYDB_SEARCH_MODE_FPR: + { + unsigned char hexfpr[MAX_FINGERPRINT_LEN * 2 + 1]; + log_assert (desc[0].fprlen <= MAX_FINGERPRINT_LEN); + bin2hex (desc[0].u.fpr, desc[0].fprlen, hexfpr); + snprintf (line, sizeof line, "SEARCH --x509 0x%s", hexfpr); + } + break; + + case KEYDB_SEARCH_MODE_ISSUER: + snprintf (line, sizeof line, "SEARCH --x509 #/%s", desc[0].u.name); + break; + + case KEYDB_SEARCH_MODE_ISSUER_SN: + if (desc[0].snhex) + snprintf (line, sizeof line, "SEARCH --x509 #%.*s/%s", + (int)desc[0].snlen, desc[0].sn, desc[0].u.name); + else + { + char *hexsn = bin2hex (desc[0].sn, desc[0].snlen, NULL); + if (!hexsn) + { + err = gpg_error_from_syserror (); + goto leave; + } + snprintf (line, sizeof line, "SEARCH --x509 #%s/%s", + hexsn, desc[0].u.name); + xfree (hexsn); + } + break; + + case KEYDB_SEARCH_MODE_SN: + snprintf (line, sizeof line, "SEARCH --x509 #%s", desc[0].u.name); + break; + + case KEYDB_SEARCH_MODE_SUBJECT: + snprintf (line, sizeof line, "SEARCH --x509 /%s", desc[0].u.name); + break; + + case KEYDB_SEARCH_MODE_KEYGRIP: + { + unsigned char hexgrip[KEYGRIP_LEN * 2 + 1]; + bin2hex (desc[0].u.grip, KEYGRIP_LEN, hexgrip); + snprintf (line, sizeof line, "SEARCH --x509 &%s", hexgrip); + } + break; + + case KEYDB_SEARCH_MODE_UBID: + { + unsigned char hexubid[UBID_LEN * 2 + 1]; + bin2hex (desc[0].u.ubid, UBID_LEN, hexubid); + snprintf (line, sizeof line, "SEARCH --x509 ^%s", hexubid); + } + break; + + case KEYDB_SEARCH_MODE_FIRST: + snprintf (line, sizeof line, "SEARCH --x509"); + break; + + case KEYDB_SEARCH_MODE_NEXT: + log_debug ("%s: mode next - we should not get to here!\n", __func__); + snprintf (line, sizeof line, "NEXT --x509"); + break; + + default: + err = gpg_error (GPG_ERR_INV_ARG); + goto leave; + } + + do_search: + hd->last_ubid_valid = 0; + /* To avoid silent truncation we error out on a too long line. */ + if (strlen (line) + 5 >= sizeof line) + err = gpg_error (GPG_ERR_ASS_LINE_TOO_LONG); + else + err = kbx_client_data_cmd (hd->kbl->kcd, line, search_status_cb, hd); + if (!err && !(err = kbx_client_data_wait (hd->kbl->kcd, + &hd->kbl->search_result.buf, + &hd->kbl->search_result.len))) + { + /* if (hd->last_ubid_valid) */ + /* log_printhex (hd->last_ubid, 20, "found UBID:"); */ + } + } - else + else /* Local keyring search. */ { - while ((rc == -1 || gpg_err_code (rc) == GPG_ERR_EOF) + while (gpg_err_code (err) == GPG_ERR_EOF && hd->current >= 0 && hd->current < hd->used) { switch (hd->active[hd->current].type) @@ -1455,9 +1732,11 @@ keydb_search (ctrl_t ctrl, KEYDB_HANDLE hd, BUG(); /* we should never see it here */ break; case KEYDB_RESOURCE_TYPE_KEYBOX: - rc = keybox_search (hd->active[hd->current].u.kr, desc, ndesc, - KEYBOX_BLOBTYPE_X509, - NULL, &skipped); + err = keybox_search (hd->active[hd->current].u.kr, desc, ndesc, + KEYBOX_BLOBTYPE_X509, + NULL, &skipped); + if (err == -1) /* Map legacy code. */ + err = gpg_error (GPG_ERR_EOF); break; } @@ -1466,21 +1745,25 @@ keydb_search (ctrl_t ctrl, KEYDB_HANDLE hd, __func__, hd->active[hd->current].type==KEYDB_RESOURCE_TYPE_KEYBOX ? "keybox" : "unknown type", - hd->current, hd->used, - rc == -1 ? "EOF" : gpg_strerror (rc)); + hd->current, hd->used, gpg_strerror (err)); - if (rc == -1 || gpg_err_code (rc) == GPG_ERR_EOF) + if (gpg_err_code (err) == GPG_ERR_EOF) { /* EOF -> switch to next resource */ hd->current++; } - else if (!rc) + else if (!err) hd->found = hd->current; } } + leave: + /* The NOTHING_FOUND error is triggered by a NEXT command. */ + if (gpg_err_code (err) == GPG_ERR_EOF + || gpg_err_code (err) == GPG_ERR_NOTHING_FOUND) + err = gpg_error (GPG_ERR_NOT_FOUND); if (DBG_CLOCK) - log_clock ("%s: leave (rc=%d)\n", __func__, rc); - return rc; + log_clock ("%s: leave (%s)\n", __func__, gpg_strerror (err)); + return err; } @@ -1621,7 +1904,7 @@ keydb_store_cert (ctrl_t ctrl, ksba_cert_t cert, int ephemeral, int *existed) } rc = keydb_search_fpr (ctrl, kh, fpr); - if (rc != -1) + if (gpg_err_code (rc) != GPG_ERR_NOT_FOUND) { keydb_release (kh); if (!rc) @@ -1715,9 +1998,7 @@ keydb_set_cert_flags (ctrl_t ctrl, ksba_cert_t cert, int ephemeral, err = keydb_search_fpr (ctrl, kh, fpr); if (err) { - if (err == -1) - err = gpg_error (GPG_ERR_NOT_FOUND); - else + if (gpg_err_code (err) != gpg_error (GPG_ERR_NOT_FOUND)) log_error (_("problem re-searching certificate: %s\n"), gpg_strerror (err)); keydb_release (kh); @@ -1836,7 +2117,7 @@ keydb_clear_some_cert_flags (ctrl_t ctrl, strlist_t names) } } } - if (rc && rc != -1) + if (rc && gpg_err_code (rc) != GPG_ERR_NOT_FOUND) log_error ("keydb_search failed: %s\n", gpg_strerror (rc)); leave: diff --git a/sm/keydb.h b/sm/keydb.h index 0f6e3818f..2725cadc6 100644 --- a/sm/keydb.h +++ b/sm/keydb.h @@ -52,11 +52,10 @@ gpg_error_t keydb_update_cert (KEYDB_HANDLE hd, ksba_cert_t cert); gpg_error_t keydb_delete (KEYDB_HANDLE hd); -int keydb_locate_writable (KEYDB_HANDLE hd, const char *reserved); void keydb_rebuild_caches (void); gpg_error_t keydb_search_reset (KEYDB_HANDLE hd); -int keydb_search (ctrl_t ctrl, KEYDB_HANDLE hd, +gpg_error_t keydb_search (ctrl_t ctrl, KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc, size_t ndesc); int keydb_search_first (ctrl_t ctrl, KEYDB_HANDLE hd); int keydb_search_next (ctrl_t ctrl, KEYDB_HANDLE hd); diff --git a/sm/keylist.c b/sm/keylist.c index 3b0c74f55..6558d68d2 100644 --- a/sm/keylist.c +++ b/sm/keylist.c @@ -452,8 +452,9 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity, chain_id = chain_id_buffer; ksba_cert_release (next); } - else if (rc == -1) /* We have reached the root certificate. */ + else if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND) { + /* We have reached the root certificate. */ chain_id = fpr; is_root = 1; } @@ -1603,7 +1604,7 @@ list_internal_keys (ctrl_t ctrl, strlist_t names, estream_t fp, lastcert = cert; cert = NULL; } - if (gpg_err_code (rc) == GPG_ERR_EOF || rc == -1 ) + if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND) rc = 0; if (rc) log_error ("keydb_search failed: %s\n", gpg_strerror (rc)); @@ -291,7 +291,7 @@ add_certificate_list (ctrl_t ctrl, ksba_cms_t cms, ksba_cert_t cert) } ksba_cert_release (cert); - return rc == -1? 0: rc; + return gpg_err_code (rc) == GPG_ERR_NOT_FOUND? 0 : rc; ksba_failure: ksba_cert_release (cert); |