* configure.ac: Require libksba 0.9.11.

sm/
* call-dirmngr.c (inq_certificate): Add new inquire SENDCERT_SKI.
* certlist.c (gpgsm_find_cert): Add new arg KEYID and implement
this filter.  Changed all callers.

* certchain.c (find_up_search_by_keyid): New helper.
(find_up): Also try using the AKI.keyIdentifier.
(find_up_external): Ditto.
This commit is contained in:
Werner Koch 2005-04-18 10:44:46 +00:00
parent 00853b8a1a
commit eff62d82bf
17 changed files with 302 additions and 41 deletions

View File

@ -1,3 +1,7 @@
2005-04-15 Werner Koch <wk@g10code.com>
* configure.ac: Require libksba 0.9.11.
2005-04-15 Marcus Brinkmann <marcus@g10code.de>
* configure.ac: Check for /usr/bin/shred and define SHRED.

9
NEWS
View File

@ -1,6 +1,13 @@
Noteworthy changes in version 1.9.16
-------------------------------------------------
* gpg-agent does now support the ssh-agent protocol and thus allows
to use the pinentry as well as the OpenPGP smartcard with ssh.
* New tool gpg-connect-agent as a genereal client for the gpg-agent.
* New tool symcryptrun as a wrapper for certain encryption tools.
Noteworthy changes in version 1.9.15 (2005-01-13)
-------------------------------------------------
@ -226,7 +233,7 @@ Noteworthy changes in version 1.9.0 (2003-08-05)
development branch.
Copyright 2002, 2003, 2004 Free Software Foundation, Inc.
Copyright 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
This file is free software; as a special exception the author gives
unlimited permission to copy and/or distribute it, with or without

8
README
View File

@ -399,7 +399,7 @@ modes for gpgsm, here is the entire list of ways to specify a key:
+Heinrich Heine duesseldorf
* [NEW] Exact match by subject's DN
* Exact match by subject's DN
This is indicated by a leading slash, directly followed by the
rfc2253 encoded DN of the subject. Note that you can't use the
@ -411,7 +411,7 @@ modes for gpgsm, here is the entire list of ways to specify a key:
/CN=Heinrich Heine,O=Poets,L=Paris,C=FR
* [NEW] Excact match by issuer's DN
* Excact match by issuer's DN
This is indicated by a leading hash mark, directly followed by a
slash and then directly followed by the rfc2253 encoded DN of the
@ -422,10 +422,10 @@ modes for gpgsm, here is the entire list of ways to specify a key:
#/CN=Root Cert,O=Poets,L=Paris,C=FR
* [NEW] Exact match by serial number and subject's DN
* Exact match by serial number and issuer's DN
This is indicated by a hash mark, followed by the hexadecmal
representation of the serial number, the followed by a slahs and
representation of the serial number, the followed by a slash and
the RFC2253 encoded DN of the issuer. See note above.
Example:

4
TODO
View File

@ -1,5 +1,9 @@
-*- outline -*-
* IMPORTANT
Check that openpty and pty.h are available and build symcryptrun only
then. Run shred on the temporary files.
* src/base64
** Make parsing more robust

View File

@ -1741,6 +1741,7 @@ ssh_handler_request_identities (ctrl_t ctrl,
/* Prepare buffer stream. */
#warning Huh, sleep? why that? Anyway, this should be pth_sleep
sleep (5);
key_directory = NULL;

View File

@ -1,3 +1,8 @@
2005-04-17 Werner Koch <wk@g10code.com>
* sexputil.c (cmp_simple_canon_sexp): New.
(make_simple_sexp_from_hexstr): New.
2005-04-07 Werner Koch <wk@g10code.com>
* sexputil.c: New.

View File

@ -61,3 +61,81 @@ keygrip_from_canon_sexp (const unsigned char *key, size_t keylen,
return err;
}
/* Compare two simple S-expressions like "(3:foo)". Returns 0 if they
are identical or !0 if they are not. Not that this function can't
be used for sorting. */
int
cmp_simple_canon_sexp (const unsigned char *a, const unsigned char *b)
{
unsigned long n1, n2;
char *endp;
if (!a && !b)
return 0; /* Both are NULL, they are identical. */
if (!a || !b)
return 1; /* One is NULL, they are not identical. */
if (*a != '(' || *b != '(')
log_bug ("invalid S-exp in cmp_simple_canon_sexp\n");
a++;
n1 = strtoul (a, &endp, 10);
a = endp;
b++;
n2 = strtoul (b, &endp, 10);
b = endp;
if (*a != ':' || *b != ':' )
log_bug ("invalid S-exp in cmp_simple_canon_sexp\n");
if (n1 != n2)
return 1; /* Not the same. */
for (a++, b++; n1; n1--, a++, b++)
if (*a != *b)
return 1; /* Not the same. */
return 0;
}
/* Create a simple S-expression from the hex string at LIBNE. Returns
a newly allocated buffer with that canonical encoded S-expression
or NULL in case of an error. On return the number of characters
scanned in LINE will be stored at NSCANNED. This fucntions stops
converting at the first character not representing a hexdigit. Odd
numbers of hex digits are allowed; a leading zero is then
assumed. If no characters have been found, NULL is returned.*/
unsigned char *
make_simple_sexp_from_hexstr (const char *line, size_t *nscanned)
{
size_t n, len;
const char *s;
unsigned char *buf;
unsigned char *p;
char numbuf[50];
for (n=0, s=line; hexdigitp (s); s++, n++)
;
if (nscanned)
*nscanned = n;
if (!n)
return NULL;
len = ((n+1) & ~0x01)/2;
sprintf (numbuf, "(%u:", (unsigned int)len);
buf = xtrymalloc (strlen (numbuf) + len + 1 + 1);
if (!buf)
return NULL;
p = stpcpy (buf, numbuf);
s = line;
if ((n&1))
{
*p++ = xtoi_1 (s);
s++;
n--;
}
for (; n > 1; n -=2, s += 2)
*p++ = xtoi_2 (s);
*p++ = ')';
*p = 0; /* (Not really neaded.) */
return buf;
}

View File

@ -123,6 +123,9 @@ gpg_error_t b64enc_finish (struct b64state *state);
/*-- sexputil.c */
gpg_error_t keygrip_from_canon_sexp (const unsigned char *key, size_t keylen,
unsigned char *grip);
int cmp_simple_canon_sexp (const unsigned char *a, const unsigned char *b);
unsigned char *make_simple_sexp_from_hexstr (const char *line,
size_t *nscanned);
/*-- homedir. c --*/
const char *default_homedir (void);

View File

@ -36,7 +36,7 @@ NEED_LIBGCRYPT_VERSION=1.1.94
NEED_LIBASSUAN_VERSION=0.6.9
NEED_KSBA_VERSION=0.9.7
NEED_KSBA_VERSION=0.9.11
NEED_OPENSC_VERSION=0.8.0

View File

@ -1,3 +1,18 @@
2005-04-17 Werner Koch <wk@g10code.com>
* call-dirmngr.c (inq_certificate): Add new inquire SENDCERT_SKI.
* certlist.c (gpgsm_find_cert): Add new arg KEYID and implement
this filter. Changed all callers.
* certchain.c (find_up_search_by_keyid): New helper.
(find_up): Also try using the AKI.keyIdentifier.
(find_up_external): Ditto.
2005-04-15 Werner Koch <wk@g10code.com>
* keylist.c (list_cert_raw): Print the subjectKeyIdentifier as
well as the keyIdentifier part of the authorityKeyIdentifier.
2005-03-31 Werner Koch <wk@g10code.com>
* call-dirmngr.c (start_dirmngr): Use PATHSEP_C instead of ':'.

View File

@ -1,5 +1,5 @@
/* call-dirmngr.c - communication with the dromngr
* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
* Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -266,11 +266,25 @@ inq_certificate (void *opaque, const char *line)
const unsigned char *der;
size_t derlen;
int issuer_mode = 0;
ksba_sexp_t ski = NULL;
if (!strncmp (line, "SENDCERT", 8) && (line[8] == ' ' || !line[8]))
{
line += 8;
}
else if (!strncmp (line, "SENDCERT_SKI", 12) && (line[12]==' ' || !line[12]))
{
size_t n;
/* Send a certificate where a sourceKeyidentifier is included. */
line += 12;
while (*line == ' ')
line++;
ski = make_simple_sexp_from_hexstr (line, &n);
line += n;
while (*line == ' ')
line++;
}
else if (!strncmp (line, "SENDISSUERCERT", 14)
&& (line[14] == ' ' || !line[14]))
{
@ -304,7 +318,7 @@ inq_certificate (void *opaque, const char *line)
ksba_cert_t cert;
err = gpgsm_find_cert (line, &cert);
err = gpgsm_find_cert (line, ski, &cert);
if (err)
{
log_error ("certificate not found: %s\n", gpg_strerror (err));
@ -321,6 +335,7 @@ inq_certificate (void *opaque, const char *line)
}
}
xfree (ski);
return rc;
}
@ -717,7 +732,7 @@ run_command_inq_cb (void *opaque, const char *line)
if (!*line)
return ASSUAN_Inquire_Error;
err = gpgsm_find_cert (line, &cert);
err = gpgsm_find_cert (line, NULL, &cert);
if (err)
{
log_error ("certificate not found: %s\n", gpg_strerror (err));

View File

@ -266,6 +266,42 @@ check_cert_policy (ksba_cert_t cert, int listmode, FILE *fplist)
}
/* Helper fucntion for find_up. This resets the key handle and search
for an issuer ISSUER with a subjectKeyIdentifier of KEYID. Returns
0 obn success or -1 when not found. */
static int
find_up_search_by_keyid (KEYDB_HANDLE kh,
const char *issuer, ksba_sexp_t keyid)
{
int rc;
ksba_cert_t cert = NULL;
ksba_sexp_t subj = NULL;
keydb_search_reset (kh);
while (!(rc = keydb_search_subject (kh, issuer)))
{
ksba_cert_release (cert); cert = NULL;
rc = keydb_get_cert (kh, &cert);
if (rc)
{
log_error ("keydb_get_cert() failed: rc=%d\n", rc);
rc = -1;
break;
}
xfree (subj);
if (!ksba_cert_get_subj_key_id (cert, NULL, &subj))
{
if (!cmp_simple_canon_sexp (keyid, subj))
break; /* Found matching cert. */
}
}
ksba_cert_release (cert);
xfree (subj);
return rc? -1:0;
}
static void
find_up_store_certs_cb (void *cb_value, ksba_cert_t cert)
{
@ -275,13 +311,13 @@ find_up_store_certs_cb (void *cb_value, ksba_cert_t cert)
}
/* Helper for find_up(). Locate the certificate for ISSUER using an
external lookup. KH is the keydb context we are currently using.
On success 0 is returned and the certificate may be retrieved from
the keydb using keydb_get_cert().*/
the keydb using keydb_get_cert(). KEYID is the keyIdentifier from
the AKI or NULL. */
static int
find_up_external (KEYDB_HANDLE kh, const char *issuer)
find_up_external (KEYDB_HANDLE kh, const char *issuer, ksba_sexp_t keyid)
{
int rc;
strlist_t names = NULL;
@ -324,8 +360,13 @@ find_up_external (KEYDB_HANDLE kh, const char *issuer)
/* The issuers are currently stored in the ephemeral key DB, so
we temporary switch to ephemeral mode. */
old = keydb_set_ephemeral (kh, 1);
keydb_search_reset (kh);
rc = keydb_search_subject (kh, issuer);
if (keyid)
rc = find_up_search_by_keyid (kh, issuer, keyid);
else
{
keydb_search_reset (kh);
rc = keydb_search_subject (kh, issuer);
}
keydb_set_ephemeral (kh, old);
}
return rc;
@ -343,9 +384,10 @@ find_up (KEYDB_HANDLE kh, ksba_cert_t cert, const char *issuer, int find_next)
{
ksba_name_t authid;
ksba_sexp_t authidno;
ksba_sexp_t keyid;
int rc = -1;
if (!ksba_cert_get_auth_key_id (cert, NULL, &authid, &authidno))
if (!ksba_cert_get_auth_key_id (cert, &keyid, &authid, &authidno))
{
const char *s = ksba_name_enum (authid, 0);
if (s && *authidno)
@ -369,28 +411,57 @@ find_up (KEYDB_HANDLE kh, ksba_cert_t cert, const char *issuer, int find_next)
keydb_set_ephemeral (kh, old);
}
/* If we didn't found it, try an external lookup. */
if (rc == -1 && opt.auto_issuer_key_retrieve && !find_next)
rc = find_up_external (kh, issuer);
}
if (rc == -1 && keyid && !find_next)
{
/* Not found by AIK.issuer_sn. Lets try the AIY.ki
instead. Loop over all certificates with that issuer as
subject and stop for the one with a matching
subjectKeyIdentifier. */
rc = find_up_search_by_keyid (kh, issuer, keyid);
if (rc)
{
int old = keydb_set_ephemeral (kh, 1);
if (!old)
rc = find_up_search_by_keyid (kh, issuer, keyid);
keydb_set_ephemeral (kh, old);
}
if (rc)
rc = -1; /* Need to make sure to have this error code. */
}
/* If we still didn't found it, try an external lookup. */
if (rc == -1 && opt.auto_issuer_key_retrieve && !find_next)
rc = find_up_external (kh, issuer, keyid);
/* 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)
{
log_info ("%sissuer certificate (#", find_next?"next ":"");
gpgsm_dump_serial (authidno);
log_printf ("/");
gpgsm_dump_string (s);
log_printf (") not found using authorityKeyIdentifier\n");
log_info ("%sissuer certificate ", find_next?"next ":"");
if (keyid)
{
log_printf ("{");
gpgsm_dump_serial (keyid);
log_printf ("} ");
}
if (authidno)
{
log_printf ("(#");
gpgsm_dump_serial (authidno);
log_printf ("/");
gpgsm_dump_string (s);
log_printf (") ");
}
log_printf ("not found using authorityKeyIdentifier\n");
}
else if (rc)
log_error ("failed to find authorityKeyIdentifier: rc=%d\n", rc);
xfree (keyid);
ksba_name_release (authid);
xfree (authidno);
/* Fixme: There is no way to do an external lookup with
serial+issuer. */
}
if (rc) /* Not found via authorithyKeyIdentifier, try regular issuer name. */
@ -409,7 +480,7 @@ find_up (KEYDB_HANDLE kh, ksba_cert_t cert, const char *issuer, int find_next)
/* Still not found. If enabled, try an external lookup. */
if (rc == -1 && opt.auto_issuer_key_retrieve && !find_next)
rc = find_up_external (kh, issuer);
rc = find_up_external (kh, issuer, NULL);
return rc;
}
@ -468,7 +539,7 @@ gpgsm_walk_cert_chain (ksba_cert_t start, ksba_cert_t *r_next)
rc = keydb_get_cert (kh, r_next);
if (rc)
{
log_error ("failed to get cert: rc=%d\n", rc);
log_error ("keydb_get_cert() failed: rc=%d\n", rc);
rc = gpg_error (GPG_ERR_GENERAL);
}
@ -791,7 +862,7 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime,
rc = keydb_get_cert (kh, &issuer_cert);
if (rc)
{
log_error ("failed to get cert: rc=%d\n", rc);
log_error ("keydb_get_cert() failed: rc=%d\n", rc);
rc = gpg_error (GPG_ERR_GENERAL);
goto leave;
}
@ -818,6 +889,8 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime,
might have been used. This is required because some
CAs are reusing the issuer and subject DN for new
root certificates. */
/* FIXME: Do this only if we don't have an
AKI.keyIdentifier */
rc = find_up (kh, subject_cert, issuer, 1);
if (!rc)
{
@ -1008,7 +1081,7 @@ gpgsm_basic_cert_check (ksba_cert_t cert)
rc = keydb_get_cert (kh, &issuer_cert);
if (rc)
{
log_error ("failed to get cert: rc=%d\n", rc);
log_error ("keydb_get_cert() failed: rc=%d\n", rc);
rc = gpg_error (GPG_ERR_GENERAL);
goto leave;
}

View File

@ -75,6 +75,7 @@ gpgsm_print_serial (FILE *fp, ksba_const_sexp_t p)
}
/* Dump the serial number or any other simple S-expression. */
void
gpgsm_dump_serial (ksba_const_sexp_t p)
{

View File

@ -1,5 +1,5 @@
/* certlist.c - build list of certificates
* Copyright (C) 2001, 2003, 2004 Free Software Foundation, Inc.
* Copyright (C) 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -412,9 +412,11 @@ gpgsm_release_certlist (CERTLIST list)
/* Like gpgsm_add_to_certlist, but look only for one certificate. No
chain validation is done */
chain validation is done. If KEYID is not NULL it is take as an
additional filter value which must match the
subjectKeyIdentifier. */
int
gpgsm_find_cert (const char *name, ksba_cert_t *r_cert)
gpgsm_find_cert (const char *name, ksba_sexp_t keyid, ksba_cert_t *r_cert)
{
int rc;
KEYDB_SEARCH_DESC desc;
@ -429,10 +431,38 @@ gpgsm_find_cert (const char *name, ksba_cert_t *r_cert)
rc = gpg_error (GPG_ERR_ENOMEM);
else
{
nextone:
rc = keydb_search (kh, &desc, 1);
if (!rc)
rc = keydb_get_cert (kh, r_cert);
if (!rc)
{
rc = keydb_get_cert (kh, r_cert);
if (!rc && keyid)
{
ksba_sexp_t subj;
rc = ksba_cert_get_subj_key_id (*r_cert, NULL, &subj);
if (!rc)
{
if (cmp_simple_canon_sexp (keyid, subj))
{
xfree (subj);
goto nextone;
}
xfree (subj);
/* Okay: Here we know that the certificate's
subjectKeyIdentifier matches the requested
one. */
}
else if (gpg_err_code (rc) == GPG_ERR_NO_DATA)
goto nextone;
}
}
/* If we don't have the KEYID filter we need to check for
ambigious search results. Note, that it is somehwat
reasonable to assume that a specification of a KEYID
won't lead to ambiguous names. */
if (!rc && !keyid)
{
rc = keydb_search (kh, &desc, 1);
if (rc == -1)

View File

@ -1566,7 +1566,7 @@ main ( int argc, char **argv)
ksba_cert_t cert = NULL;
char *grip = NULL;
rc = gpgsm_find_cert (*argv, &cert);
rc = gpgsm_find_cert (*argv, NULL, &cert);
if (rc)
;
else if (!(grip = gpgsm_get_keygrip_hexstring (cert)))

View File

@ -252,7 +252,7 @@ int gpgsm_add_cert_to_certlist (ctrl_t ctrl, ksba_cert_t cert,
int gpgsm_add_to_certlist (ctrl_t ctrl, const char *name, int secret,
certlist_t *listaddr, int is_encrypt_to);
void gpgsm_release_certlist (certlist_t list);
int gpgsm_find_cert (const char *name, ksba_cert_t *r_cert);
int gpgsm_find_cert (const char *name, ksba_sexp_t keyid, ksba_cert_t *r_cert);
/*-- keylist.c --*/
gpg_error_t gpgsm_list_keys (ctrl_t ctrl, STRLIST names,

View File

@ -1,6 +1,6 @@
/* keylist.c
/* keylist.c - Print certificates in various formats.
* Copyright (C) 1998, 1999, 2000, 2001, 2003,
* 2004 Free Software Foundation, Inc.
* 2004, 2005 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -122,7 +122,7 @@ static struct {
{ "1.3.6.1.5.5.7.1.11", "subjectInfoAccess" },
/* X.509 id-ce */
{ "2.5.29.14", "subjectKeyIdentifier"},
{ "2.5.29.14", "subjectKeyIdentifier", 1},
{ "2.5.29.15", "keyUsage", 1 },
{ "2.5.29.16", "privateKeyUsagePeriod" },
{ "2.5.29.17", "subjectAltName", 1 },
@ -512,7 +512,7 @@ list_cert_raw (ctrl_t ctrl, KEYDB_HANDLE hd,
{
gpg_error_t err;
size_t off, len;
ksba_sexp_t sexp;
ksba_sexp_t sexp, keyid;
char *dn;
ksba_isotime_t t;
int idx, i;
@ -588,9 +588,27 @@ list_cert_raw (ctrl_t ctrl, KEYDB_HANDLE hd,
fprintf (fp, " keyType: %u bit %s\n", nbits, algoname? algoname:"?");
}
/* subjectKeyIdentifier */
fputs (" subjKeyId: ", fp);
err = ksba_cert_get_subj_key_id (cert, NULL, &keyid);
if (!err || gpg_err_code (err) == GPG_ERR_NO_DATA)
{
if (gpg_err_code (err) == GPG_ERR_NO_DATA)
fputs ("[none]\n", fp);
else
{
gpgsm_print_serial (fp, keyid);
ksba_free (keyid);
putc ('\n', fp);
}
}
else
fputs ("[?]\n", fp);
/* authorityKeyIdentifier */
fputs (" authKeyId: ", fp);
err = ksba_cert_get_auth_key_id (cert, NULL, &name, &sexp);
err = ksba_cert_get_auth_key_id (cert, &keyid, &name, &sexp);
if (!err || gpg_err_code (err) == GPG_ERR_NO_DATA)
{
if (gpg_err_code (err) == GPG_ERR_NO_DATA || !name)
@ -603,6 +621,13 @@ list_cert_raw (ctrl_t ctrl, KEYDB_HANDLE hd,
print_names_raw (fp, -15, name);
ksba_name_release (name);
}
if (keyid)
{
fputs (" authKeyId.ki: ", fp);
gpgsm_print_serial (fp, keyid);
ksba_free (keyid);
putc ('\n', fp);
}
}
else
fputs ("[?]\n", fp);