diff options
author | Repo Admin <nobody@gnupg.org> | 2003-08-05 19:11:04 +0200 |
---|---|---|
committer | Repo Admin <nobody@gnupg.org> | 2003-08-05 19:11:04 +0200 |
commit | 9ca4830a5b8392bc7bb01211407c876fd40b49d4 (patch) | |
tree | 5b5eb60b48cea2f86d01b8d9a458a2fa4fc0a2b2 /sm/keylist.c | |
parent | minor changes to make make distcheck happy (diff) | |
download | gnupg2-9ca4830a5b8392bc7bb01211407c876fd40b49d4.tar.xz gnupg2-9ca4830a5b8392bc7bb01211407c876fd40b49d4.zip |
This commit was manufactured by cvs2svn to create branch
'GNUPG-1-9-BRANCH'.
Diffstat (limited to 'sm/keylist.c')
-rw-r--r-- | sm/keylist.c | 617 |
1 files changed, 617 insertions, 0 deletions
diff --git a/sm/keylist.c b/sm/keylist.c new file mode 100644 index 000000000..634bda292 --- /dev/null +++ b/sm/keylist.c @@ -0,0 +1,617 @@ +/* keylist.c + * Copyright (C) 1998, 1999, 2000, 2001, 2003 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GnuPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <time.h> +#include <assert.h> + +#include "gpgsm.h" + +#include <gcrypt.h> +#include <ksba.h> + +#include "keydb.h" +#include "i18n.h" + +struct list_external_parm_s { + FILE *fp; + int print_header; + int with_colons; + int with_chain; +}; + + + +static void +print_key_data (KsbaCert cert, FILE *fp) +{ +#if 0 + int n = pk ? pubkey_get_npkey( pk->pubkey_algo ) : 0; + int i; + + for(i=0; i < n; i++ ) + { + fprintf (fp, "pkd:%d:%u:", i, mpi_get_nbits( pk->pkey[i] ) ); + mpi_print(stdout, pk->pkey[i], 1 ); + putchar(':'); + putchar('\n'); + } +#endif +} + +static void +print_capabilities (KsbaCert cert, FILE *fp) +{ + KsbaError err; + unsigned int use; + + err = ksba_cert_get_key_usage (cert, &use); + if (err == KSBA_No_Data) + { + putc ('e', fp); + putc ('s', fp); + putc ('c', fp); + putc ('E', fp); + putc ('S', fp); + putc ('C', fp); + return; + } + if (err) + { + log_error (_("error getting key usage information: %s\n"), + ksba_strerror (err)); + return; + } + + if ((use & (KSBA_KEYUSAGE_KEY_ENCIPHERMENT|KSBA_KEYUSAGE_DATA_ENCIPHERMENT))) + putc ('e', fp); + if ((use & (KSBA_KEYUSAGE_DIGITAL_SIGNATURE|KSBA_KEYUSAGE_NON_REPUDIATION))) + putc ('s', fp); + if ((use & KSBA_KEYUSAGE_KEY_CERT_SIGN)) + putc ('c', fp); + if ((use & (KSBA_KEYUSAGE_KEY_ENCIPHERMENT|KSBA_KEYUSAGE_DATA_ENCIPHERMENT))) + putc ('E', fp); + if ((use & (KSBA_KEYUSAGE_DIGITAL_SIGNATURE|KSBA_KEYUSAGE_NON_REPUDIATION))) + putc ('S', fp); + if ((use & KSBA_KEYUSAGE_KEY_CERT_SIGN)) + putc ('C', fp); +} + + +static void +print_time (time_t t, FILE *fp) +{ + if (!t) + ; + else if ( t == (time_t)(-1) ) + putc ('?', fp); + else + fprintf (fp, "%lu", (unsigned long)t); +} + + +/* return an allocated string with the email address extracted from a + DN */ +static char * +email_kludge (const char *name) +{ + const unsigned char *p; + unsigned char *buf; + int n; + + if (strncmp (name, "1.2.840.113549.1.9.1=#", 22)) + return NULL; + /* This looks pretty much like an email address in the subject's DN + we use this to add an additional user ID entry. This way, + openSSL generated keys get a nicer and usable listing */ + name += 22; + for (n=0, p=name; hexdigitp (p) && hexdigitp (p+1); p +=2, n++) + ; + if (*p != '#' || !n) + return NULL; + buf = xtrymalloc (n+3); + if (!buf) + return NULL; /* oops, out of core */ + *buf = '<'; + for (n=1, p=name; *p != '#'; p +=2, n++) + buf[n] = xtoi_2 (p); + buf[n++] = '>'; + buf[n] = 0; + return buf; +} + + + + +/* List one certificate in colon mode */ +static void +list_cert_colon (KsbaCert cert, FILE *fp, int have_secret) +{ + int idx, trustletter = 0; + char *p; + KsbaSexp sexp; + char *fpr; + + fputs (have_secret? "crs:":"crt:", fp); + trustletter = 0; +#if 0 + if (is_not_valid (cert)) + putc ('i', fp); + else if ( is_revoked (cert) ) + putc ('r', fp); + else if ( has_expired (cert)) + putcr ('e', fp); + else +#endif + { + trustletter = '?'; /*get_validity_info ( pk, NULL );*/ + putc (trustletter, fp); + } + + fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1); + fprintf (fp, ":%u:%d:%s:", + /*keylen_of_cert (cert)*/1024, + /* pubkey_algo_of_cert (cert)*/1, + fpr+24); + + /* we assume --fixed-list-mode for gpgsm */ + print_time ( ksba_cert_get_validity (cert, 0), fp); + putc (':', fp); + print_time ( ksba_cert_get_validity (cert, 1), fp); + putc (':', fp); + /* field 8, serial number: */ + if ((sexp = ksba_cert_get_serial (cert))) + { + int len; + const unsigned char *s = sexp; + + if (*s == '(') + { + s++; + for (len=0; *s && *s != ':' && digitp (s); s++) + len = len*10 + atoi_1 (s); + if (*s == ':') + for (s++; len; len--, s++) + fprintf (fp,"%02X", *s); + } + xfree (sexp); + } + putc (':', fp); + /* field 9, ownertrust - not used here */ + putc (':', fp); + /* field 10, old user ID - we use it here for the issuer DN */ + if ((p = ksba_cert_get_issuer (cert,0))) + { + print_sanitized_string (fp, p, ':'); + xfree (p); + } + putc (':', fp); + /* field 11, signature class - not used */ + putc (':', fp); + /* field 12, capabilities: */ + print_capabilities (cert, fp); + putc (':', fp); + putc ('\n', fp); + + /* FPR record */ + fprintf (fp, "fpr:::::::::%s:::", fpr); + xfree (fpr); fpr = NULL; + /* print chaining ID (field 13)*/ + { + KsbaCert next; + + if (!gpgsm_walk_cert_chain (cert, &next)) + { + p = gpgsm_get_fingerprint_hexstring (next, GCRY_MD_SHA1); + fputs (p, fp); + xfree (p); + ksba_cert_release (next); + } + } + putc (':', fp); + putc ('\n', fp); + + + if (opt.with_key_data) + { + if ( (p = gpgsm_get_keygrip_hexstring (cert))) + { + fprintf (fp, "grp:::::::::%s:\n", p); + xfree (p); + } + print_key_data (cert, fp); + } + + for (idx=0; (p = ksba_cert_get_subject (cert,idx)); idx++) + { + fprintf (fp, "uid:%c::::::::", trustletter); + print_sanitized_string (fp, p, ':'); + putc (':', fp); + putc (':', fp); + putc ('\n', fp); + if (!idx) + { + /* It would be better to get the faked email address from + the keydb. But as long as we don't have a way to pass + the meta data back, we just check it the same way as the + code used to create the keybox meta data does */ + char *pp = email_kludge (p); + if (pp) + { + fprintf (fp, "uid:%c::::::::", trustletter); + print_sanitized_string (fp, pp, ':'); + putc (':', fp); + putc (':', fp); + putc ('\n', fp); + xfree (pp); + } + } + xfree (p); + } +} + + +/* List one certificate in standard mode */ +static void +list_cert_std (KsbaCert cert, FILE *fp, int have_secret) +{ + KsbaError kerr; + KsbaSexp sexp; + char *dn; + time_t t; + int idx; + int is_ca, chainlen; + unsigned int kusage; + char *string, *p; + + sexp = ksba_cert_get_serial (cert); + fputs ("Serial number: ", fp); + gpgsm_print_serial (fp, sexp); + ksba_free (sexp); + putc ('\n', fp); + + dn = ksba_cert_get_issuer (cert, 0); + fputs (" Issuer: ", fp); + gpgsm_print_name (fp, dn); + ksba_free (dn); + putc ('\n', fp); + for (idx=1; (dn = ksba_cert_get_issuer (cert, idx)); idx++) + { + fputs (" aka: ", fp); + gpgsm_print_name (fp, dn); + ksba_free (dn); + putc ('\n', fp); + } + + dn = ksba_cert_get_subject (cert, 0); + fputs (" Subject: ", fp); + gpgsm_print_name (fp, dn); + ksba_free (dn); + putc ('\n', fp); + for (idx=1; (dn = ksba_cert_get_subject (cert, idx)); idx++) + { + fputs (" aka: ", fp); + gpgsm_print_name (fp, dn); + ksba_free (dn); + putc ('\n', fp); + } + + t = ksba_cert_get_validity (cert, 0); + fputs (" validity: ", fp); + gpgsm_print_time (fp, t); + fputs (" through ", fp); + t = ksba_cert_get_validity (cert, 1); + gpgsm_print_time (fp, t); + putc ('\n', fp); + + kerr = ksba_cert_get_key_usage (cert, &kusage); + if (kerr != KSBA_No_Data) + { + fputs (" key usage:", fp); + if (kerr) + fprintf (fp, " [error: %s]", ksba_strerror (kerr)); + else + { + if ( (kusage & KSBA_KEYUSAGE_DIGITAL_SIGNATURE)) + fputs (" digitalSignature", fp); + if ( (kusage & KSBA_KEYUSAGE_NON_REPUDIATION)) + fputs (" nonRepudiation", fp); + if ( (kusage & KSBA_KEYUSAGE_KEY_ENCIPHERMENT)) + fputs (" keyEncipherment", fp); + if ( (kusage & KSBA_KEYUSAGE_DATA_ENCIPHERMENT)) + fputs (" dataEncipherment", fp); + if ( (kusage & KSBA_KEYUSAGE_KEY_AGREEMENT)) + fputs (" keyAgreement", fp); + if ( (kusage & KSBA_KEYUSAGE_KEY_CERT_SIGN)) + fputs (" certSign", fp); + if ( (kusage & KSBA_KEYUSAGE_CRL_SIGN)) + fputs (" crlSign", fp); + if ( (kusage & KSBA_KEYUSAGE_ENCIPHER_ONLY)) + fputs (" encipherOnly", fp); + if ( (kusage & KSBA_KEYUSAGE_DECIPHER_ONLY)) + fputs (" decipherOnly", fp); + } + putc ('\n', fp); + } + + kerr = ksba_cert_get_cert_policies (cert, &string); + if (kerr != KSBA_No_Data) + { + fputs (" policies: ", fp); + if (kerr) + fprintf (fp, "[error: %s]", ksba_strerror (kerr)); + else + { + for (p=string; *p; p++) + { + if (*p == '\n') + *p = ','; + } + print_sanitized_string (fp, string, 0); + xfree (string); + } + putc ('\n', fp); + } + + kerr = ksba_cert_is_ca (cert, &is_ca, &chainlen); + if (kerr || is_ca) + { + fputs (" chain length: ", fp); + if (kerr) + fprintf (fp, "[error: %s]", ksba_strerror (kerr)); + else if (chainlen == -1) + fputs ("unlimited", fp); + else + fprintf (fp, "%d", chainlen); + putc ('\n', fp); + } + + + dn = gpgsm_get_fingerprint_string (cert, 0); + fprintf (fp, " fingerprint: %s\n", dn?dn:"error"); + xfree (dn); +} + +/* Same as standard mode mode list all certifying certts too */ +static void +list_cert_chain (KsbaCert cert, FILE *fp) +{ + KsbaCert next = NULL; + + list_cert_std (cert, fp, 0); + ksba_cert_ref (cert); + while (!gpgsm_walk_cert_chain (cert, &next)) + { + ksba_cert_release (cert); + fputs ("Certified by\n", fp); + list_cert_std (next, fp, 0); + cert = next; + } + ksba_cert_release (cert); + putc ('\n', fp); +} + + + +/* List all internal keys or just the key given as NAMES. + */ +static void +list_internal_keys (CTRL ctrl, STRLIST names, FILE *fp, unsigned int mode) +{ + KEYDB_HANDLE hd; + KEYDB_SEARCH_DESC *desc = NULL; + STRLIST sl; + int ndesc; + KsbaCert cert = NULL; + int rc=0; + const char *lastresname, *resname; + int have_secret; + + hd = keydb_new (0); + if (!hd) + { + log_error ("keydb_new failed\n"); + goto leave; + } + + if (!names) + ndesc = 1; + else + { + for (sl=names, ndesc=0; sl; sl = sl->next, ndesc++) + ; + } + + desc = xtrycalloc (ndesc, sizeof *desc); + if (!ndesc) + { + log_error ("out of core\n"); + goto leave; + } + + if (!names) + desc[0].mode = KEYDB_SEARCH_MODE_FIRST; + else + { + for (ndesc=0, sl=names; sl; sl = sl->next) + { + rc = keydb_classify_name (sl->d, desc+ndesc); + if (rc) + { + log_error ("key `%s' not found: %s\n", + sl->d, gpg_strerror (rc)); + rc = 0; + } + else + ndesc++; + } + + } + + /* it would be nice to see which of the given users did actually + match one in the keyring. To implement this we need to have a + found flag for each entry in desc and to set this we must check + all those entries after a match to mark all matched one - + currently we stop at the first match. To do this we need an + extra flag to enable this feature so */ + + lastresname = NULL; + while (!(rc = keydb_search (hd, desc, ndesc))) + { + if (!names) + desc[0].mode = KEYDB_SEARCH_MODE_NEXT; + + rc = keydb_get_cert (hd, &cert); + if (rc) + { + log_error ("keydb_get_cert failed: %s\n", gpg_strerror (rc)); + goto leave; + } + + resname = keydb_get_resource_name (hd); + + if (lastresname != resname ) + { + int i; + + if (ctrl->no_server) + { + fprintf (fp, "%s\n", resname ); + for (i=strlen(resname); i; i-- ) + putchar('-'); + putc ('\n', fp); + lastresname = resname; + } + } + + have_secret = 0; + if (mode) + { + char *p = gpgsm_get_keygrip_hexstring (cert); + if (p) + { + if (!gpgsm_agent_havekey (p)) + have_secret = 1; + xfree (p); + } + } + + if (!mode + || ((mode & 1) && !have_secret) + || ((mode & 2) && have_secret) ) + { + if (ctrl->with_colons) + list_cert_colon (cert, fp, have_secret); + else if (ctrl->with_chain) + list_cert_chain (cert, fp); + else + { + list_cert_std (cert, fp, have_secret); + putc ('\n', fp); + } + } + ksba_cert_release (cert); + cert = NULL; + } + if (rc && rc != -1) + log_error ("keydb_search failed: %s\n", gpg_strerror (rc)); + + leave: + ksba_cert_release (cert); + xfree (desc); + keydb_release (hd); +} + + + +static void +list_external_cb (void *cb_value, KsbaCert cert) +{ + struct list_external_parm_s *parm = cb_value; + + if (keydb_store_cert (cert, 1, NULL)) + log_error ("error storing certificate as ephemeral\n"); + + if (parm->print_header) + { + const char *resname = "[external keys]"; + int i; + + fprintf (parm->fp, "%s\n", resname ); + for (i=strlen(resname); i; i-- ) + putchar('-'); + putc ('\n', parm->fp); + parm->print_header = 0; + } + + if (parm->with_colons) + list_cert_colon (cert, parm->fp, 0); + else if (parm->with_chain) + list_cert_chain (cert, parm->fp); + else + { + list_cert_std (cert, parm->fp, 0); + putc ('\n', parm->fp); + } +} + + +/* List external keys similar to internal one. Note: mode does not + make sense here because it would be unwise to list external secret + keys */ +static void +list_external_keys (CTRL ctrl, STRLIST names, FILE *fp) +{ + int rc; + struct list_external_parm_s parm; + + parm.fp = fp; + parm.print_header = ctrl->no_server; + parm.with_colons = ctrl->with_colons; + parm.with_chain = ctrl->with_chain; + + rc = gpgsm_dirmngr_lookup (ctrl, names, list_external_cb, &parm); + if (rc) + log_error ("listing external keys failed: %s\n", gpg_strerror (rc)); +} + +/* List all keys or just the key given as NAMES. + MODE controls the operation mode: + Bit 0-2: + 0 = list all public keys but don't flag secret ones + 1 = list only public keys + 2 = list only secret keys + 3 = list secret and public keys + Bit 6: list internal keys + Bit 7: list external keys + */ +void +gpgsm_list_keys (CTRL ctrl, STRLIST names, FILE *fp, unsigned int mode) +{ + if ((mode & (1<<6))) + list_internal_keys (ctrl, names, fp, (mode & 3)); + if ((mode & (1<<7))) + list_external_keys (ctrl, names, fp); +} |