diff options
Diffstat (limited to 'sm')
-rw-r--r-- | sm/call-agent.c | 37 | ||||
-rw-r--r-- | sm/certlist.c | 60 | ||||
-rw-r--r-- | sm/certreqgen-ui.c | 26 | ||||
-rw-r--r-- | sm/decrypt.c | 14 | ||||
-rw-r--r-- | sm/delete.c | 5 | ||||
-rw-r--r-- | sm/gpgsm.c | 31 | ||||
-rw-r--r-- | sm/gpgsm.h | 21 | ||||
-rw-r--r-- | sm/keydb.c | 328 | ||||
-rw-r--r-- | sm/keydb.h | 6 | ||||
-rw-r--r-- | sm/keylist.c | 2 | ||||
-rw-r--r-- | sm/server.c | 4 | ||||
-rw-r--r-- | sm/sign.c | 124 |
12 files changed, 517 insertions, 141 deletions
diff --git a/sm/call-agent.c b/sm/call-agent.c index 4f2b83f56..b37c2e53d 100644 --- a/sm/call-agent.c +++ b/sm/call-agent.c @@ -409,19 +409,19 @@ gpgsm_scd_pksign (ctrl_t ctrl, const char *keyid, const char *desc, { case GCRY_PK_RSA: rc = gcry_sexp_build (&sig, NULL, "(sig-val(rsa(s%b)))", - sigbuflen, sigbuf); + (int)sigbuflen, sigbuf); break; case GCRY_PK_ECC: rc = gcry_sexp_build (&sig, NULL, "(sig-val(ecdsa(r%b)(s%b)))", - sigbuflen/2, sigbuf, - sigbuflen/2, sigbuf + sigbuflen/2); + (int)sigbuflen/2, sigbuf, + (int)sigbuflen/2, sigbuf + sigbuflen/2); break; case GCRY_PK_EDDSA: rc = gcry_sexp_build (&sig, NULL, "(sig-val(eddsa(r%b)(s%b)))", - sigbuflen/2, sigbuf, - sigbuflen/2, sigbuf + sigbuflen/2); + (int)sigbuflen/2, sigbuf, + (int)sigbuflen/2, sigbuf + sigbuflen/2); break; default: @@ -785,9 +785,9 @@ scd_keypairinfo_status_cb (void *opaque, const char *line) { sl = append_to_strlist (listaddr, line); p = sl->d; - /* Make sure that we only have two tokes so that future - extensions of the format won't change the format expected by - the caller. */ + /* Make sure that we only have two tokens so that future + * extensions of the format won't change the format expected by + * the caller. */ while (*p && !spacep (p)) p++; if (*p) @@ -796,7 +796,22 @@ scd_keypairinfo_status_cb (void *opaque, const char *line) p++; while (*p && !spacep (p)) p++; - *p = 0; + if (*p) + { + *p++ = 0; + while (spacep (p)) + p++; + while (*p && !spacep (p)) + { + switch (*p++) + { + case 'c': sl->flags |= GCRY_PK_USAGE_CERT; break; + case 's': sl->flags |= GCRY_PK_USAGE_SIGN; break; + case 'e': sl->flags |= GCRY_PK_USAGE_ENCR; break; + case 'a': sl->flags |= GCRY_PK_USAGE_AUTH; break; + } + } + } } } @@ -806,7 +821,7 @@ scd_keypairinfo_status_cb (void *opaque, const char *line) /* Call the agent to read the keypairinfo lines of the current card. The list is returned as a string made up of the keygrip, a space - and the keyid. */ + and the keyid. The flags of the string carry the usage bits. */ int gpgsm_agent_scd_keypairinfo (ctrl_t ctrl, strlist_t *r_list) { @@ -821,7 +836,7 @@ gpgsm_agent_scd_keypairinfo (ctrl_t ctrl, strlist_t *r_list) inq_parm.ctrl = ctrl; inq_parm.ctx = agent_ctx; - rc = assuan_transact (agent_ctx, "SCD LEARN --force", + rc = assuan_transact (agent_ctx, "SCD LEARN --keypairinfo", NULL, NULL, default_inq_cb, &inq_parm, scd_keypairinfo_status_cb, &list); diff --git a/sm/certlist.c b/sm/certlist.c index 12a492518..b3d113bfd 100644 --- a/sm/certlist.c +++ b/sm/certlist.c @@ -48,7 +48,7 @@ static const char oid_kp_ocspSigning[] = "1.3.6.1.5.5.7.3.9"; debugging). MODE 4 is for certificate signing, MODE for COSP response signing. */ static int -cert_usage_p (ksba_cert_t cert, int mode) +cert_usage_p (ksba_cert_t cert, int mode, int silent) { gpg_error_t err; unsigned int use; @@ -118,7 +118,7 @@ cert_usage_p (ksba_cert_t cert, int mode) if (gpg_err_code (err) == GPG_ERR_NO_DATA) { err = 0; - if (opt.verbose && mode < 2) + if (opt.verbose && mode < 2 && !silent) log_info (_("no key usage specified - assuming all usages\n")); use = ~0; } @@ -139,8 +139,9 @@ cert_usage_p (ksba_cert_t cert, int mode) { if ((use & (KSBA_KEYUSAGE_KEY_CERT_SIGN))) return 0; - log_info (_("certificate should not have " - "been used for certification\n")); + if (!silent) + log_info (_("certificate should not have " + "been used for certification\n")); return gpg_error (GPG_ERR_WRONG_KEY_USAGE); } @@ -151,8 +152,9 @@ cert_usage_p (ksba_cert_t cert, int mode) || (use & (KSBA_KEYUSAGE_KEY_CERT_SIGN |KSBA_KEYUSAGE_CRL_SIGN)))) return 0; - log_info (_("certificate should not have " - "been used for OCSP response signing\n")); + if (!silent) + log_info (_("certificate should not have " + "been used for OCSP response signing\n")); return gpg_error (GPG_ERR_WRONG_KEY_USAGE); } @@ -162,19 +164,22 @@ cert_usage_p (ksba_cert_t cert, int mode) ) return 0; - log_info (mode==3? _("certificate should not have been used for encryption\n"): - mode==2? _("certificate should not have been used for signing\n"): - mode==1? _("certificate is not usable for encryption\n"): - _("certificate is not usable for signing\n")); + if (!silent) + log_info + (mode==3? _("certificate should not have been used for encryption\n"): + mode==2? _("certificate should not have been used for signing\n"): + mode==1? _("certificate is not usable for encryption\n"): + /**/ _("certificate is not usable for signing\n")); + return gpg_error (GPG_ERR_WRONG_KEY_USAGE); } /* Return 0 if the cert is usable for signing */ int -gpgsm_cert_use_sign_p (ksba_cert_t cert) +gpgsm_cert_use_sign_p (ksba_cert_t cert, int silent) { - return cert_usage_p (cert, 0); + return cert_usage_p (cert, 0, silent); } @@ -182,31 +187,31 @@ gpgsm_cert_use_sign_p (ksba_cert_t cert) int gpgsm_cert_use_encrypt_p (ksba_cert_t cert) { - return cert_usage_p (cert, 1); + return cert_usage_p (cert, 1, 0); } int gpgsm_cert_use_verify_p (ksba_cert_t cert) { - return cert_usage_p (cert, 2); + return cert_usage_p (cert, 2, 0); } int gpgsm_cert_use_decrypt_p (ksba_cert_t cert) { - return cert_usage_p (cert, 3); + return cert_usage_p (cert, 3, 0); } int gpgsm_cert_use_cert_p (ksba_cert_t cert) { - return cert_usage_p (cert, 4); + return cert_usage_p (cert, 4, 0); } int gpgsm_cert_use_ocsp_p (ksba_cert_t cert) { - return cert_usage_p (cert, 5); + return cert_usage_p (cert, 5, 0); } @@ -341,25 +346,20 @@ gpgsm_add_to_certlist (ctrl_t ctrl, const char *name, int secret, first_subject = ksba_cert_get_subject (cert, 0); first_issuer = ksba_cert_get_issuer (cert, 0); } - rc = secret? gpgsm_cert_use_sign_p (cert) + rc = secret? gpgsm_cert_use_sign_p (cert, 0) : gpgsm_cert_use_encrypt_p (cert); if (gpg_err_code (rc) == GPG_ERR_WRONG_KEY_USAGE) { /* There might be another certificate with the correct usage, so we try again */ - if (!wrong_usage) - { /* save the first match */ - wrong_usage = rc; - ksba_cert_release (cert); - cert = NULL; - goto get_next; - } - else if (same_subject_issuer (first_subject, first_issuer, - cert)) + if (!wrong_usage + || same_subject_issuer (first_subject, first_issuer,cert)) { - wrong_usage = rc; + if (!wrong_usage) + wrong_usage = rc; /* save error of the first match */ ksba_cert_release (cert); cert = NULL; + log_info (_("looking for another certificate\n")); goto get_next; } else @@ -403,8 +403,8 @@ gpgsm_add_to_certlist (ctrl_t ctrl, const char *name, int secret, first_issuer, cert2) && ((gpg_err_code ( - secret? gpgsm_cert_use_sign_p (cert2) - : gpgsm_cert_use_encrypt_p (cert2) + secret? gpgsm_cert_use_sign_p (cert2,0) + : gpgsm_cert_use_encrypt_p (cert2) ) ) == GPG_ERR_WRONG_KEY_USAGE)); if (tmp) diff --git a/sm/certreqgen-ui.c b/sm/certreqgen-ui.c index 70e5739e8..ae9ec35d0 100644 --- a/sm/certreqgen-ui.c +++ b/sm/certreqgen-ui.c @@ -249,6 +249,7 @@ gpgsm_gencertreq_tty (ctrl_t ctrl, estream_t output_stream) gcry_sexp_t s_pkey; char *algostr = NULL; const char *keyref; + int any = 0; keyref = strchr (sl->d, ' '); if (keyref) @@ -257,12 +258,33 @@ gpgsm_gencertreq_tty (ctrl_t ctrl, estream_t output_stream) if (!gpgsm_agent_readkey (ctrl, 1, keyref, &pkey)) { if (!gcry_sexp_new (&s_pkey, pkey, 0, 0)) - algostr = pubkey_algo_string (s_pkey); + algostr = pubkey_algo_string (s_pkey, NULL); gcry_sexp_release (s_pkey); } xfree (pkey); } - tty_printf (" (%d) %s %s\n", count, sl->d, algostr); + tty_printf (" (%d) %s %s", count, sl->d, algostr); + if ((sl->flags & GCRY_PK_USAGE_CERT)) + { + tty_printf ("%scert", any?",":" ("); + any = 1; + } + if ((sl->flags & GCRY_PK_USAGE_SIGN)) + { + tty_printf ("%ssign", any?",":" ("); + any = 1; + } + if ((sl->flags & GCRY_PK_USAGE_AUTH)) + { + tty_printf ("%sauth", any?",":" ("); + any = 1; + } + if ((sl->flags & GCRY_PK_USAGE_ENCR)) + { + tty_printf ("%sencr", any?",":" ("); + any = 1; + } + tty_printf ("%s\n", any?")":""); xfree (algostr); } xfree (answer); diff --git a/sm/decrypt.c b/sm/decrypt.c index b0ab63f00..ec9800840 100644 --- a/sm/decrypt.c +++ b/sm/decrypt.c @@ -397,16 +397,17 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, estream_t out_fp) char *hexkeygrip = NULL; char *desc = NULL; char kidbuf[16+1]; + int tmp_rc; *kidbuf = 0; - rc = ksba_cms_get_issuer_serial (cms, recp, &issuer, &serial); - if (rc == -1 && recp) + tmp_rc = ksba_cms_get_issuer_serial (cms, recp, &issuer, &serial); + if (tmp_rc == -1 && recp) break; /* no more recipients */ audit_log_i (ctrl->audit, AUDIT_NEW_RECP, recp); - if (rc) + if (tmp_rc) log_error ("recp %d - error getting info: %s\n", - recp, gpg_strerror (rc)); + recp, gpg_strerror (tmp_rc)); else { ksba_cert_t cert = NULL; @@ -569,7 +570,7 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, estream_t out_fp) audit_log_i (ctrl->audit, AUDIT_NEW_RECP, recp); if (tmp_rc) log_error ("recp %d - error getting info: %s\n", - recp, gpg_strerror (rc)); + recp, gpg_strerror (tmp_rc)); else { char *tmpstr = gpgsm_format_sn_issuer (serial, issuer); @@ -583,7 +584,8 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, estream_t out_fp) if (!any_key) { - rc = gpg_error (GPG_ERR_NO_SECKEY); + if (!rc) + rc = gpg_error (GPG_ERR_NO_SECKEY); goto leave; } } diff --git a/sm/delete.c b/sm/delete.c index f359cc595..b370406de 100644 --- a/sm/delete.c +++ b/sm/delete.c @@ -113,7 +113,8 @@ delete_one (ctrl_t ctrl, const char *username) goto leave; } - /* We need to search again to get back to the right position. */ + /* We need to search again to get back to the right position. Neo + * that the lock is kept until the KH is released. */ rc = keydb_lock (kh); if (rc) { @@ -132,7 +133,7 @@ delete_one (ctrl_t ctrl, const char *username) goto leave; } - rc = keydb_delete (kh, duplicates ? 0 : 1); + rc = keydb_delete (kh); if (rc) goto leave; if (opt.verbose) diff --git a/sm/gpgsm.c b/sm/gpgsm.c index 2f9e5bfd2..f5837079d 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -192,6 +192,8 @@ enum cmd_and_opt_values { oNoRandomSeedFile, oNoCommonCertsImport, oIgnoreCertExtension, + oAuthenticode, + oAttribute, oNoAutostart }; @@ -402,6 +404,8 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_s_n (oNoCommonCertsImport, "no-common-certs-import", "@"), ARGPARSE_s_s (oIgnoreCertExtension, "ignore-cert-extension", "@"), ARGPARSE_s_n (oNoAutostart, "no-autostart", "@"), + ARGPARSE_s_n (oAuthenticode, "authenticode", "@"), + ARGPARSE_s_s (oAttribute, "attribute", "@"), /* Command aliases. */ ARGPARSE_c (aListKeys, "list-key", "@"), @@ -426,6 +430,8 @@ static struct debug_flags_s debug_flags [] = { DBG_MEMSTAT_VALUE, "memstat" }, { DBG_HASHING_VALUE, "hashing" }, { DBG_IPC_VALUE , "ipc" }, + { DBG_CLOCK_VALUE , "clock" }, + { DBG_LOOKUP_VALUE , "lookup" }, { 0, NULL } }; @@ -1283,8 +1289,12 @@ main ( int argc, char **argv) case oDebugNoChainValidation: opt.no_chain_validation = 1; break; case oDebugIgnoreExpiration: opt.ignore_expiration = 1; break; - case oStatusFD: ctrl.status_fd = pargs.r.ret_int; break; - case oLoggerFD: log_set_fd (pargs.r.ret_int ); break; + case oStatusFD: + ctrl.status_fd = translate_sys2libc_fd_int (pargs.r.ret_int, 1); + break; + case oLoggerFD: + log_set_fd (translate_sys2libc_fd_int (pargs.r.ret_int, 1)); + break; case oWithMD5Fingerprint: opt.with_md5_fingerprint=1; /*fall through*/ case oWithFingerprint: @@ -1456,6 +1466,12 @@ main ( int argc, char **argv) add_to_strlist (&opt.ignored_cert_extensions, pargs.r.ret_str); break; + case oAuthenticode: opt.authenticode = 1; break; + + case oAttribute: + add_to_strlist (&opt.attributes, pargs.r.ret_str); + break; + case oNoAutostart: opt.autostart = 0; break; case oCompliance: @@ -1738,6 +1754,8 @@ main ( int argc, char **argv) if (!do_not_setup_keys) { + int errcount = log_get_errorcount (0); + for (sl = locusr; sl ; sl = sl->next) { int rc = gpgsm_add_to_certlist (&ctrl, sl->d, 1, &signerlist, 0); @@ -1766,6 +1784,15 @@ main ( int argc, char **argv) if ((sl->flags & 1)) do_add_recipient (&ctrl, sl->d, &recplist, 1, recp_required); } + + /* We do not require a recipient for decryption but because + * recipients and signers are always checked and log_error is + * sometimes used (for failed signing keys or due to a failed + * CRL checking) that would have bumbed up the error counter. + * We clear the counter in the decryption case because there is + * no reason to force decryption to fail. */ + if (cmd == aDecrypt && !errcount) + log_get_errorcount (1); /* clear counter */ } if (log_get_errorcount(0)) diff --git a/sm/gpgsm.h b/sm/gpgsm.h index 7a5e4917d..65fff853a 100644 --- a/sm/gpgsm.h +++ b/sm/gpgsm.h @@ -149,6 +149,21 @@ struct strlist_t ignored_cert_extensions; enum gnupg_compliance_mode compliance; + + /* Enable creation of authenticode signatures. */ + int authenticode; + + /* A list of extra attributes put into a signed data object. For a + * signed each attribute each string has the format: + * <oid>:s:<hex_or_filename> + * and for an unsigned attribute + * <oid>:u:<hex_or_filename> + * The OID is in the usual dotted decimal for. The HEX_OR_FILENAME + * is either a list of hex digits or a filename with the DER encoded + * value. A filename is detected by the presence of a slash in the + * HEX_OR_FILENAME. The actual value needs to be encoded as a SET OF + * attribute values. */ + strlist_t attributes; } opt; /* Debug values and macros. */ @@ -160,6 +175,8 @@ struct #define DBG_MEMSTAT_VALUE 128 /* show memory statistics */ #define DBG_HASHING_VALUE 512 /* debug hashing operations */ #define DBG_IPC_VALUE 1024 /* debug assuan communication */ +#define DBG_CLOCK_VALUE 4096 +#define DBG_LOOKUP_VALUE 8192 /* debug the key lookup */ #define DBG_X509 (opt.debug & DBG_X509_VALUE) #define DBG_CRYPTO (opt.debug & DBG_CRYPTO_VALUE) @@ -167,6 +184,8 @@ struct #define DBG_CACHE (opt.debug & DBG_CACHE_VALUE) #define DBG_HASHING (opt.debug & DBG_HASHING_VALUE) #define DBG_IPC (opt.debug & DBG_IPC_VALUE) +#define DBG_CLOCK (opt.debug & DBG_CLOCK_VALUE) +#define DBG_LOOKUP (opt.debug & DBG_LOOKUP_VALUE) /* Forward declaration for an object defined in server.c */ struct server_local_s; @@ -318,7 +337,7 @@ int gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, int gpgsm_basic_cert_check (ctrl_t ctrl, ksba_cert_t cert); /*-- certlist.c --*/ -int gpgsm_cert_use_sign_p (ksba_cert_t cert); +int gpgsm_cert_use_sign_p (ksba_cert_t cert, int silent); int gpgsm_cert_use_encrypt_p (ksba_cert_t cert); int gpgsm_cert_use_verify_p (ksba_cert_t cert); int gpgsm_cert_use_decrypt_p (ksba_cert_t cert); diff --git a/sm/keydb.c b/sm/keydb.c index f66a5766d..53e3cf887 100644 --- a/sm/keydb.c +++ b/sm/keydb.c @@ -23,7 +23,6 @@ #include <stdlib.h> #include <string.h> #include <errno.h> -#include <assert.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> @@ -47,7 +46,6 @@ struct resource_item { KEYBOX_HANDLE kr; } u; void *token; - dotlock_t lockhandle; }; static struct resource_item all_resources[MAX_KEYDB_RESOURCES]; @@ -58,7 +56,14 @@ static int any_registered; struct keydb_handle { + + /* If this flag is set the resources is locked. */ int locked; + + /* If this flag is set a lock will only be released by + * keydb_release. */ + int keep_lock; + int found; int saved_found; int current; @@ -346,26 +351,20 @@ keydb_add_resource (ctrl_t ctrl, const char *url, int force, int *auto_created) err = gpg_error (GPG_ERR_RESOURCE_LIMIT); else { + KEYBOX_HANDLE kbxhd; + all_resources[used_resources].type = rt; all_resources[used_resources].u.kr = NULL; /* Not used here */ all_resources[used_resources].token = token; - all_resources[used_resources].lockhandle - = dotlock_create (filename, 0); - if (!all_resources[used_resources].lockhandle) - log_fatal ( _("can't create lock for '%s'\n"), filename); - - /* Do a compress run if needed and the file is not locked. */ - if (!dotlock_take (all_resources[used_resources].lockhandle, 0)) + /* Do a compress run if needed and the keybox is not locked. */ + kbxhd = keybox_new_x509 (token, 0); + if (kbxhd) { - KEYBOX_HANDLE kbxhd = keybox_new_x509 (token, 0); - - if (kbxhd) - { - keybox_compress (kbxhd); - keybox_release (kbxhd); - } - dotlock_release (all_resources[used_resources].lockhandle); + if (!keybox_lock (kbxhd, 1, 0)) + keybox_compress (kbxhd); + + keybox_release (kbxhd); } used_resources++; @@ -401,11 +400,14 @@ keydb_new (void) KEYDB_HANDLE hd; int i, j; + if (DBG_CLOCK) + log_clock ("%s: enter\n", __func__); + hd = xcalloc (1, sizeof *hd); hd->found = -1; hd->saved_found = -1; - assert (used_resources <= MAX_KEYDB_RESOURCES); + log_assert (used_resources <= MAX_KEYDB_RESOURCES); for (i=j=0; i < used_resources; i++) { switch (all_resources[i].type) @@ -415,7 +417,6 @@ keydb_new (void) case KEYDB_RESOURCE_TYPE_KEYBOX: hd->active[j].type = all_resources[i].type; hd->active[j].token = all_resources[i].token; - hd->active[j].lockhandle = all_resources[i].lockhandle; hd->active[j].u.kr = keybox_new_x509 (all_resources[i].token, 0); if (!hd->active[j].u.kr) { @@ -429,6 +430,8 @@ keydb_new (void) hd->used = j; active_handles++; + if (DBG_CLOCK) + log_clock ("%s: leave (hd=%p)\n", __func__, hd); return hd; } @@ -439,9 +442,14 @@ keydb_release (KEYDB_HANDLE hd) if (!hd) return; - assert (active_handles > 0); + + if (DBG_CLOCK) + log_clock ("%s: enter (hd=%p)\n", __func__, hd); + + log_assert (active_handles > 0); active_handles--; + hd->keep_lock = 0; unlock_all (hd); for (i=0; i < hd->used; i++) { @@ -455,7 +463,9 @@ keydb_release (KEYDB_HANDLE hd) } } - xfree (hd); + xfree (hd); + if (DBG_CLOCK) + log_clock ("%s: leave\n", __func__); } @@ -526,17 +536,26 @@ keydb_set_ephemeral (KEYDB_HANDLE hd, int yes) /* If the keyring has not yet been locked, lock it now. This - operation is required before any update operation; it is optional - for an insert operation. The lock is released with - keydb_released. */ + * operation is required before any update operation; it is optional + * for an insert operation. The lock is kept until a keydb_release so + * that internal unlock_all calls have no effect. */ gpg_error_t keydb_lock (KEYDB_HANDLE hd) { + gpg_error_t err; + if (!hd) return gpg_error (GPG_ERR_INV_HANDLE); - if (hd->locked) - return 0; /* Already locked. */ - return lock_all (hd); + + if (DBG_CLOCK) + log_clock ("%s: enter (hd=%p)\n", __func__, hd); + err = lock_all (hd); + if (!err) + hd->keep_lock = 1; + + if (DBG_CLOCK) + log_clock ("%s: leave (err=%s)\n", __func__, gpg_strerror (err)); + return err; } @@ -556,8 +575,7 @@ lock_all (KEYDB_HANDLE hd) case KEYDB_RESOURCE_TYPE_NONE: break; case KEYDB_RESOURCE_TYPE_KEYBOX: - if (hd->active[i].lockhandle) - rc = dotlock_take (hd->active[i].lockhandle, -1); + rc = keybox_lock (hd->active[i].u.kr, 1, -1); break; } if (rc) @@ -566,7 +584,7 @@ lock_all (KEYDB_HANDLE hd) if (rc) { - /* revert the already set locks */ + /* Revert the already set locks. */ for (i--; i >= 0; i--) { switch (hd->active[i].type) @@ -574,8 +592,7 @@ lock_all (KEYDB_HANDLE hd) case KEYDB_RESOURCE_TYPE_NONE: break; case KEYDB_RESOURCE_TYPE_KEYBOX: - if (hd->active[i].lockhandle) - dotlock_release (hd->active[i].lockhandle); + keybox_lock (hd->active[i].u.kr, 0, 0); break; } } @@ -583,10 +600,7 @@ lock_all (KEYDB_HANDLE hd) else hd->locked = 1; - /* make_dotlock () does not yet guarantee that errno is set, thus - we can't rely on the error reason and will simply use - EACCES. */ - return rc? gpg_error (GPG_ERR_EACCES) : 0; + return rc; } static void @@ -594,7 +608,7 @@ unlock_all (KEYDB_HANDLE hd) { int i; - if (!hd->locked) + if (!hd->locked || hd->keep_lock) return; for (i=hd->used-1; i >= 0; i--) @@ -604,8 +618,7 @@ unlock_all (KEYDB_HANDLE hd) case KEYDB_RESOURCE_TYPE_NONE: break; case KEYDB_RESOURCE_TYPE_KEYBOX: - if (hd->active[i].lockhandle) - dotlock_release (hd->active[i].lockhandle); + keybox_lock (hd->active[i].u.kr, 0, 0); break; } } @@ -638,6 +651,8 @@ keydb_push_found_state (KEYDB_HANDLE hd) hd->saved_found = hd->found; hd->found = -1; + if (DBG_CLOCK) + log_clock ("%s: done (hd=%p)\n", __func__, hd); } @@ -661,6 +676,8 @@ keydb_pop_found_state (KEYDB_HANDLE hd) keybox_pop_found_state (hd->active[hd->found].u.kr); break; } + if (DBG_CLOCK) + log_clock ("%s: done (hd=%p)\n", __func__, hd); } @@ -678,9 +695,16 @@ keydb_get_cert (KEYDB_HANDLE hd, ksba_cert_t *r_cert) if (!hd) return gpg_error (GPG_ERR_INV_VALUE); + if (DBG_CLOCK) + log_clock ("%s: enter (hd=%p)\n", __func__, hd); + if ( hd->found < 0 || hd->found >= hd->used) - return -1; /* nothing found */ + { + rc = -1; /* nothing found */ + goto leave; + } + rc = GPG_ERR_BUG; switch (hd->active[hd->found].type) { case KEYDB_RESOURCE_TYPE_NONE: @@ -691,9 +715,13 @@ keydb_get_cert (KEYDB_HANDLE hd, ksba_cert_t *r_cert) break; } + leave: + if (DBG_CLOCK) + log_clock ("%s: leave (rc=%d)\n", __func__, rc); return rc; } + /* Return a flag of the last found object. WHICH is the flag requested; it should be one of the KEYBOX_FLAG_ values. If the operation is successful, the flag value will be stored at the address given by @@ -701,14 +729,21 @@ keydb_get_cert (KEYDB_HANDLE hd, ksba_cert_t *r_cert) gpg_error_t keydb_get_flags (KEYDB_HANDLE hd, int which, int idx, unsigned int *value) { - int err = 0; + gpg_error_t err; if (!hd) return gpg_error (GPG_ERR_INV_VALUE); + if (DBG_CLOCK) + log_clock ("%s: enter (hd=%p)\n", __func__, hd); + if ( hd->found < 0 || hd->found >= hd->used) - return gpg_error (GPG_ERR_NOTHING_FOUND); + { + err = gpg_error (GPG_ERR_NOTHING_FOUND); + goto leave; + } + err = gpg_error (GPG_ERR_BUG); switch (hd->active[hd->found].type) { case KEYDB_RESOURCE_TYPE_NONE: @@ -719,9 +754,13 @@ keydb_get_flags (KEYDB_HANDLE hd, int which, int idx, unsigned int *value) break; } + leave: + if (DBG_CLOCK) + log_clock ("%s: leave (err=%s)\n", __func__, gpg_strerror (err)); return err; } + /* Set a flag of the last found object. WHICH is the flag to be set; it should be one of the KEYBOX_FLAG_ values. If the operation is successful, the flag value will be stored in the keybox. Note, @@ -731,16 +770,25 @@ keydb_get_flags (KEYDB_HANDLE hd, int which, int idx, unsigned int *value) gpg_error_t keydb_set_flags (KEYDB_HANDLE hd, int which, int idx, unsigned int value) { - int err = 0; + gpg_error_t err = 0; if (!hd) return gpg_error (GPG_ERR_INV_VALUE); + if (DBG_CLOCK) + log_clock ("%s: enter (hd=%p)\n", __func__, hd); + if ( hd->found < 0 || hd->found >= hd->used) - return gpg_error (GPG_ERR_NOTHING_FOUND); + { + err = gpg_error (GPG_ERR_NOTHING_FOUND); + goto leave; + } if (!hd->locked) - return gpg_error (GPG_ERR_NOT_LOCKED); + { + err = gpg_error (GPG_ERR_NOT_LOCKED); + goto leave; + } switch (hd->active[hd->found].type) { @@ -752,16 +800,19 @@ keydb_set_flags (KEYDB_HANDLE hd, int which, int idx, unsigned int value) break; } + leave: + if (DBG_CLOCK) + log_clock ("%s: leave (err=%s)\n", __func__, gpg_strerror (err)); return err; } /* * Insert a new Certificate into one of the resources. */ -int +gpg_error_t keydb_insert_cert (KEYDB_HANDLE hd, ksba_cert_t cert) { - int rc = -1; + gpg_error_t err; int idx; unsigned char digest[20]; @@ -771,104 +822,136 @@ keydb_insert_cert (KEYDB_HANDLE hd, ksba_cert_t cert) if (opt.dry_run) return 0; + if (DBG_CLOCK) + log_clock ("%s: enter (hd=%p)\n", __func__, hd); + if ( hd->found >= 0 && hd->found < hd->used) idx = hd->found; else if ( hd->current >= 0 && hd->current < hd->used) idx = hd->current; else - return gpg_error (GPG_ERR_GENERAL); + { + err = gpg_error (GPG_ERR_GENERAL); + goto leave; + } if (!hd->locked) - return gpg_error (GPG_ERR_NOT_LOCKED); + { + err = gpg_error (GPG_ERR_NOT_LOCKED); + goto leave; + } gpgsm_get_fingerprint (cert, GCRY_MD_SHA1, digest, NULL); /* kludge*/ + err = gpg_error (GPG_ERR_BUG); switch (hd->active[idx].type) { case KEYDB_RESOURCE_TYPE_NONE: - rc = gpg_error (GPG_ERR_GENERAL); + err = gpg_error (GPG_ERR_GENERAL); break; case KEYDB_RESOURCE_TYPE_KEYBOX: - rc = keybox_insert_cert (hd->active[idx].u.kr, cert, digest); + err = keybox_insert_cert (hd->active[idx].u.kr, cert, digest); break; } unlock_all (hd); - return rc; + + leave: + if (DBG_CLOCK) + log_clock ("%s: leave (err=%s)\n", __func__, gpg_strerror (err)); + return err; } /* Update the current keyblock with KB. */ -int +/* Note: This function is currently not called. */ +gpg_error_t keydb_update_cert (KEYDB_HANDLE hd, ksba_cert_t cert) { - int rc = 0; + gpg_error_t err; unsigned char digest[20]; if (!hd) return gpg_error (GPG_ERR_INV_VALUE); if ( hd->found < 0 || hd->found >= hd->used) - return -1; /* nothing found */ + return gpg_error (GPG_ERR_NOT_FOUND); if (opt.dry_run) return 0; - rc = lock_all (hd); - if (rc) - return rc; + if (DBG_CLOCK) + log_clock ("%s: enter (hd=%p)\n", __func__, hd); + + err = lock_all (hd); + if (err) + goto leave; gpgsm_get_fingerprint (cert, GCRY_MD_SHA1, digest, NULL); /* kludge*/ + err = gpg_error (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_update_cert (hd->active[hd->found].u.kr, cert, digest); + err = keybox_update_cert (hd->active[hd->found].u.kr, cert, digest); break; } unlock_all (hd); - return rc; + leave: + if (DBG_CLOCK) + log_clock ("%s: leave (err=%s)\n", __func__, gpg_strerror (err)); + return err; } /* * The current keyblock or cert will be deleted. */ -int -keydb_delete (KEYDB_HANDLE hd, int unlock) +gpg_error_t +keydb_delete (KEYDB_HANDLE hd) { - int rc = -1; + gpg_error_t err; if (!hd) return gpg_error (GPG_ERR_INV_VALUE); if ( hd->found < 0 || hd->found >= hd->used) - return -1; /* nothing found */ + return gpg_error (GPG_ERR_NOT_FOUND); - if( opt.dry_run ) + if (opt.dry_run) return 0; + if (DBG_CLOCK) + log_clock ("%s: enter (hd=%p)\n", __func__, hd); + if (!hd->locked) - return gpg_error (GPG_ERR_NOT_LOCKED); + { + err = gpg_error (GPG_ERR_NOT_LOCKED); + goto leave; + } + err = gpg_error (GPG_ERR_BUG); switch (hd->active[hd->found].type) { case KEYDB_RESOURCE_TYPE_NONE: - rc = gpg_error (GPG_ERR_GENERAL); + err = gpg_error (GPG_ERR_GENERAL); break; case KEYDB_RESOURCE_TYPE_KEYBOX: - rc = keybox_delete (hd->active[hd->found].u.kr); + err = keybox_delete (hd->active[hd->found].u.kr); break; } - if (unlock) - unlock_all (hd); - return rc; + unlock_all (hd); + + leave: + if (DBG_CLOCK) + log_clock ("%s: leave (err=%s)\n", __func__, gpg_strerror (err)); + return err; } @@ -941,29 +1024,92 @@ keydb_rebuild_caches (void) gpg_error_t keydb_search_reset (KEYDB_HANDLE hd) { + gpg_error_t err = 0; int i; - gpg_error_t rc = 0; if (!hd) return gpg_error (GPG_ERR_INV_VALUE); + if (DBG_CLOCK) + log_clock ("%s: enter (hd=%p)\n", __func__, hd); + hd->current = 0; hd->found = -1; /* and reset all resources */ - for (i=0; !rc && i < hd->used; i++) + for (i=0; !err && i < hd->used; i++) { switch (hd->active[i].type) { case KEYDB_RESOURCE_TYPE_NONE: break; case KEYDB_RESOURCE_TYPE_KEYBOX: - rc = keybox_search_reset (hd->active[i].u.kr); + err = keybox_search_reset (hd->active[i].u.kr); break; } } - return rc; + + if (DBG_CLOCK) + log_clock ("%s: leave (err=%s)\n", __func__, gpg_strerror (err)); + return err; } + +char * +keydb_search_desc_dump (struct keydb_search_desc *desc) +{ + char *fpr; + char *result; + + switch (desc->mode) + { + case KEYDB_SEARCH_MODE_EXACT: + return xasprintf ("EXACT: '%s'", desc->u.name); + case KEYDB_SEARCH_MODE_SUBSTR: + return xasprintf ("SUBSTR: '%s'", desc->u.name); + case KEYDB_SEARCH_MODE_MAIL: + return xasprintf ("MAIL: '%s'", desc->u.name); + case KEYDB_SEARCH_MODE_MAILSUB: + return xasprintf ("MAILSUB: '%s'", desc->u.name); + case KEYDB_SEARCH_MODE_MAILEND: + return xasprintf ("MAILEND: '%s'", desc->u.name); + case KEYDB_SEARCH_MODE_WORDS: + return xasprintf ("WORDS: '%s'", desc->u.name); + case KEYDB_SEARCH_MODE_SHORT_KID: + return xasprintf ("SHORT_KID: '%08lX'", (ulong)desc->u.kid[1]); + case KEYDB_SEARCH_MODE_LONG_KID: + return xasprintf ("LONG_KID: '%08lX%08lX'", + (ulong)desc->u.kid[0], (ulong)desc->u.kid[1]); + case KEYDB_SEARCH_MODE_FPR: + fpr = bin2hexcolon (desc->u.fpr, desc->fprlen, NULL); + result = xasprintf ("FPR%02d: '%s'", desc->fprlen, fpr); + xfree (fpr); + return result; + case KEYDB_SEARCH_MODE_ISSUER: + return xasprintf ("ISSUER: '%s'", desc->u.name); + case KEYDB_SEARCH_MODE_ISSUER_SN: + return xasprintf ("ISSUER_SN: '%*s'", + (int) (desc->snlen == -1 + ? strlen (desc->sn) : desc->snlen), + desc->sn); + case KEYDB_SEARCH_MODE_SN: + return xasprintf ("SN: '%*s'", + (int) (desc->snlen == -1 + ? strlen (desc->sn) : desc->snlen), + desc->sn); + case KEYDB_SEARCH_MODE_SUBJECT: + return xasprintf ("SUBJECT: '%s'", desc->u.name); + case KEYDB_SEARCH_MODE_KEYGRIP: + return xasprintf ("KEYGRIP: %s", desc->u.grip); + case KEYDB_SEARCH_MODE_FIRST: + return xasprintf ("FIRST"); + case KEYDB_SEARCH_MODE_NEXT: + return xasprintf ("NEXT"); + default: + return xasprintf ("Bad search mode (%d)", desc->mode); + } +} + + /* * Search through all keydb resources, starting at the current position, * for a keyblock which contains one of the keys described in the DESC array. @@ -974,6 +1120,7 @@ keydb_search (ctrl_t ctrl, KEYDB_HANDLE hd, { int rc = -1; unsigned long skipped; + int i; if (!hd) return gpg_error (GPG_ERR_INV_VALUE); @@ -985,7 +1132,22 @@ keydb_search (ctrl_t ctrl, KEYDB_HANDLE hd, return gpg_error (GPG_ERR_NOT_FOUND); } - while (rc == -1 && hd->current >= 0 && hd->current < hd->used) + if (DBG_CLOCK) + log_clock ("%s: enter (hd=%p)\n", __func__, hd); + + if (DBG_LOOKUP) + { + log_debug ("%s: %zd search description(s):\n", __func__, ndesc); + for (i = 0; i < ndesc; i ++) + { + char *t = keydb_search_desc_dump (&desc[i]); + log_debug ("%s: %d: %s\n", __func__, i, t); + xfree (t); + } + } + + while ((rc == -1 || gpg_err_code (rc) == GPG_ERR_EOF) + && hd->current >= 0 && hd->current < hd->used) { switch (hd->active[hd->current].type) { @@ -998,6 +1160,15 @@ keydb_search (ctrl_t ctrl, KEYDB_HANDLE hd, NULL, &skipped); break; } + + if (DBG_LOOKUP) + log_debug ("%s: searched %s (resource %d of %d) => %s\n", + __func__, + hd->active[hd->current].type == KEYDB_RESOURCE_TYPE_KEYBOX + ? "keybox" : "unknown type", + hd->current, hd->used, + rc == -1 ? "EOF" : gpg_strerror (rc)); + if (rc == -1 || gpg_err_code (rc) == GPG_ERR_EOF) { /* EOF -> switch to next resource */ hd->current++; @@ -1006,6 +1177,9 @@ keydb_search (ctrl_t ctrl, KEYDB_HANDLE hd, hd->found = hd->current; } + + if (DBG_CLOCK) + log_clock ("%s: leave (rc=%d)\n", __func__, rc); return rc; } diff --git a/sm/keydb.h b/sm/keydb.h index 623462553..1ab94a2c2 100644 --- a/sm/keydb.h +++ b/sm/keydb.h @@ -46,10 +46,10 @@ gpg_error_t keydb_set_flags (KEYDB_HANDLE hd, int which, int idx, void keydb_push_found_state (KEYDB_HANDLE hd); void keydb_pop_found_state (KEYDB_HANDLE hd); int keydb_get_cert (KEYDB_HANDLE hd, ksba_cert_t *r_cert); -int keydb_insert_cert (KEYDB_HANDLE hd, ksba_cert_t cert); -int keydb_update_cert (KEYDB_HANDLE hd, ksba_cert_t cert); +gpg_error_t keydb_insert_cert (KEYDB_HANDLE hd, ksba_cert_t cert); +gpg_error_t keydb_update_cert (KEYDB_HANDLE hd, ksba_cert_t cert); -int keydb_delete (KEYDB_HANDLE hd, int unlock); +gpg_error_t keydb_delete (KEYDB_HANDLE hd); int keydb_locate_writable (KEYDB_HANDLE hd, const char *reserved); void keydb_rebuild_caches (void); diff --git a/sm/keylist.c b/sm/keylist.c index e242310be..4eecb8720 100644 --- a/sm/keylist.c +++ b/sm/keylist.c @@ -1373,6 +1373,8 @@ list_cert_std (ctrl_t ctrl, ksba_cert_t cert, estream_t fp, int have_secret, else es_fprintf (fp, " [certificate is bad: %s]\n", gpg_strerror (err)); } + if (opt.debug) + es_fflush (fp); } diff --git a/sm/server.c b/sm/server.c index 98505e26d..77ec07fc0 100644 --- a/sm/server.c +++ b/sm/server.c @@ -1162,14 +1162,14 @@ cmd_getinfo (assuan_context_t ctx, char *line) { cmdopt = line; if (!command_has_option (cmd, cmdopt)) - rc = gpg_error (GPG_ERR_GENERAL); + rc = gpg_error (GPG_ERR_FALSE); } } } } else if (!strcmp (line, "offline")) { - rc = ctrl->offline? 0 : gpg_error (GPG_ERR_GENERAL); + rc = ctrl->offline? 0 : gpg_error (GPG_ERR_FALSE); } else rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT"); @@ -161,7 +161,7 @@ gpgsm_get_default_cert (ctrl_t ctrl, ksba_cert_t *r_cert) return rc; } - if (!gpgsm_cert_use_sign_p (cert)) + if (!gpgsm_cert_use_sign_p (cert, 1)) { p = gpgsm_get_keygrip_hexstring (cert); if (p) @@ -302,6 +302,99 @@ add_certificate_list (ctrl_t ctrl, ksba_cms_t cms, ksba_cert_t cert) } +#if KSBA_VERSION_NUMBER >= 0x010400 && 0 /* 1.4.0 */ +static gpg_error_t +add_signed_attribute (ksba_cms_t cms, const char *attrstr) +{ + gpg_error_t err; + char **fields = NULL; + const char *s; + int i; + unsigned char *der = NULL; + size_t derlen; + + fields = strtokenize (attrstr, ":"); + if (!fields) + { + err = gpg_error_from_syserror (); + log_error ("strtokenize failed: %s\n", gpg_strerror (err)); + goto leave; + } + + for (i=0; fields[i]; i++) + ; + if (i != 3) + { + err = gpg_error (GPG_ERR_SYNTAX); + log_error ("invalid attribute specification '%s': %s\n", + attrstr, i < 3 ? "not enough fields":"too many fields"); + goto leave; + } + if (!ascii_strcasecmp (fields[1], "u")) + { + err = 0; + goto leave; /* Skip unsigned attruibutes. */ + } + if (ascii_strcasecmp (fields[1], "s")) + { + err = gpg_error (GPG_ERR_SYNTAX); + log_error ("invalid attribute specification '%s': %s\n", + attrstr, "type is not 's' or 'u'"); + goto leave; + } + /* Check that the OID is valid. */ + err = ksba_oid_from_str (fields[0], &der, &derlen); + if (err) + { + log_error ("invalid attribute specification '%s': %s\n", + attrstr, gpg_strerror (err)); + goto leave; + } + xfree (der); + der = NULL; + + if (strchr (fields[2], '/')) + { + /* FIXME: read from file. */ + } + else /* Directly given in hex. */ + { + for (i=0, s = fields[2]; hexdigitp (s); s++, i++) + ; + if (*s || !i || (i&1)) + { + log_error ("invalid attribute specification '%s': %s\n", + attrstr, "invalid hex encoding of the data"); + err = gpg_error (GPG_ERR_SYNTAX); + goto leave; + } + der = xtrystrdup (fields[2]); + if (!der) + { + err = gpg_error_from_syserror (); + log_error ("malloc failed: %s\n", gpg_strerror (err)); + goto leave; + } + for (s=fields[2], derlen=0; s[0] && s[1]; s += 2) + der[derlen++] = xtoi_2 (s); + } + + /* Store the data in the CMS object for all signers. */ + err = ksba_cms_add_attribute (cms, -1, fields[0], 0, der, derlen); + if (err) + { + log_error ("invalid attribute specification '%s': %s\n", + attrstr, gpg_strerror (err)); + goto leave; + } + + leave: + xfree (der); + xfree (fields); + return err; +} +#endif /*ksba >= 1.4.0 */ + /* Perform a sign operation. @@ -377,10 +470,17 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, goto leave; } - /* We are going to create signed data with data as encap. content */ + /* We are going to create signed data with data as encap. content. + * In authenticode mode we use spcIndirectDataContext instead. */ err = ksba_cms_set_content_type (cms, 0, KSBA_CT_SIGNED_DATA); if (!err) - err = ksba_cms_set_content_type (cms, 1, KSBA_CT_DATA); + err = ksba_cms_set_content_type + (cms, 1, +#if KSBA_VERSION_NUMBER >= 0x010400 && 0 + opt.authenticode? KSBA_CT_SPC_IND_DATA_CTX : +#endif + KSBA_CT_DATA + ); if (err) { log_debug ("ksba_cms_set_content_type failed: %s\n", @@ -404,7 +504,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, /* Although we don't check for ambiguous specification we will check that the signer's certificate is usable and valid. */ - rc = gpgsm_cert_use_sign_p (cert); + rc = gpgsm_cert_use_sign_p (cert, 0); if (!rc) rc = gpgsm_validate_chain (ctrl, cert, "", NULL, 0, NULL, 0, NULL); if (rc) @@ -513,7 +613,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, /* Gather certificates of signers and store them in the CMS object. */ for (cl=signerlist; cl; cl = cl->next) { - rc = gpgsm_cert_use_sign_p (cl->cert); + rc = gpgsm_cert_use_sign_p (cl->cert, 0); if (rc) goto leave; @@ -643,6 +743,20 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist, } } + /* We can add signed attributes only when build against libksba 1.4. */ +#if KSBA_VERSION_NUMBER >= 0x010400 && 0 /* 1.4.0 */ + { + strlist_t sl; + + for (sl = opt.attributes; sl; sl = sl->next) + if ((err = add_signed_attribute (cms, sl->d))) + goto leave; + } +#else + log_info ("Note: option --attribute is ignored by this version\n"); +#endif /*ksba >= 1.4.0 */ + + /* We need to write at least a minimal list of our capabilities to try to convince some MUAs to use 3DES and not the crippled RC2. Our list is: |