From 9ca4830a5b8392bc7bb01211407c876fd40b49d4 Mon Sep 17 00:00:00 2001 From: Repo Admin Date: Tue, 5 Aug 2003 17:11:04 +0000 Subject: This commit was manufactured by cvs2svn to create branch 'GNUPG-1-9-BRANCH'. --- scd/app-openpgp.c | 1482 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1482 insertions(+) create mode 100644 scd/app-openpgp.c (limited to 'scd/app-openpgp.c') diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c new file mode 100644 index 000000000..09a19699d --- /dev/null +++ b/scd/app-openpgp.c @@ -0,0 +1,1482 @@ +/* app-openpgp.c - The OpenPGP card application. + * Copyright (C) 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 +#include +#include +#include +#include +#include + +#include "scdaemon.h" +#include "app-common.h" +#include "iso7816.h" + + + +static struct { + int tag; + int constructed; + int get_from; /* Constructed DO with this DO or 0 for direct access. */ + int binary; + char *desc; +} data_objects[] = { + { 0x005E, 0, 0, 1, "Login Data" }, + { 0x5F50, 0, 0, 0, "URL" }, + { 0x0065, 1, 0, 1, "Cardholder Related Data"}, + { 0x005B, 0, 0x65, 0, "Name" }, + { 0x5F2D, 0, 0x65, 0, "Language preferences" }, + { 0x5F35, 0, 0x65, 0, "Sex" }, + { 0x006E, 1, 0, 1, "Application Related Data" }, + { 0x004F, 0, 0x6E, 1, "AID" }, + { 0x0073, 1, 0, 1, "Discretionary Data Objects" }, + { 0x0047, 0, 0x6E, 1, "Card Capabilities" }, + { 0x00C0, 0, 0x6E, 1, "Extended Card Capabilities" }, + { 0x00C1, 0, 0x6E, 1, "Algorithm Attributes Signature" }, + { 0x00C2, 0, 0x6E, 1, "Algorithm Attributes Decryption" }, + { 0x00C3, 0, 0x6E, 1, "Algorithm Attributes Authentication" }, + { 0x00C4, 0, 0x6E, 1, "CHV Status Bytes" }, + { 0x00C5, 0, 0x6E, 1, "Fingerprints" }, + { 0x00C6, 0, 0x6E, 1, "CA Fingerprints" }, + { 0x007A, 1, 0, 1, "Security Support Template" }, + { 0x0093, 0, 0x7A, 1, "Digital Signature Counter" }, + { 0 } +}; + + +static unsigned long get_sig_counter (APP app); + + +/* Locate a TLV encoded data object in BUFFER of LENGTH and + return a pointer to value as well as its length in NBYTES. Return + NULL if it was not found. Note, that the function does not check + whether the value fits into the provided buffer. + + FIXME: Move this to an extra file, it is mostly duplicated from card.c. +*/ +static const unsigned char * +find_tlv (const unsigned char *buffer, size_t length, + int tag, size_t *nbytes, int nestlevel) +{ + const unsigned char *s = buffer; + size_t n = length; + size_t len; + int this_tag; + int composite; + + for (;;) + { + buffer = s; + if (n < 2) + return NULL; /* buffer definitely too short for tag and length. */ + if (!*s || *s == 0xff) + { /* Skip optional filler between TLV objects. */ + s++; + n--; + continue; + } + composite = !!(*s & 0x20); + if ((*s & 0x1f) == 0x1f) + { /* more tag bytes to follow */ + s++; + n--; + if (n < 2) + return NULL; /* buffer definitely too short for tag and length. */ + if ((*s & 0x1f) == 0x1f) + return NULL; /* We support only up to 2 bytes. */ + this_tag = (s[-1] << 8) | (s[0] & 0x7f); + } + else + this_tag = s[0]; + len = s[1]; + s += 2; n -= 2; + if (len < 0x80) + ; + else if (len == 0x81) + { /* One byte length follows. */ + if (!n) + return NULL; /* we expected 1 more bytes with the length. */ + len = s[0]; + s++; n--; + } + else if (len == 0x82) + { /* Two byte length follows. */ + if (n < 2) + return NULL; /* we expected 2 more bytes with the length. */ + len = (s[0] << 8) | s[1]; + s += 2; n -= 2; + } + else + return NULL; /* APDU limit is 65535, thus it does not make + sense to assume longer length fields. */ + + if (composite && nestlevel < 100) + { /* Dive into this composite DO after checking for too deep + nesting. */ + const unsigned char *tmp_s; + size_t tmp_len; + + tmp_s = find_tlv (s, len, tag, &tmp_len, nestlevel+1); + if (tmp_s) + { + *nbytes = tmp_len; + return tmp_s; + } + } + + if (this_tag == tag) + { + *nbytes = len; + return s; + } + if (len > n) + return NULL; /* buffer too short to skip to the next tag. */ + s += len; n -= len; + } +} + + +/* Get the DO identified by TAG from the card in SLOT and return a + buffer with its content in RESULT and NBYTES. The return value is + NULL if not found or a pointer which must be used to release the + buffer holding value. */ +static void * +get_one_do (int slot, int tag, unsigned char **result, size_t *nbytes) +{ + int rc, i; + unsigned char *buffer; + size_t buflen; + unsigned char *value; + size_t valuelen; + + *result = NULL; + *nbytes = 0; + for (i=0; data_objects[i].tag && data_objects[i].tag != tag; i++) + ; + + value = NULL; + rc = -1; + if (data_objects[i].tag && data_objects[i].get_from) + { + rc = iso7816_get_data (slot, data_objects[i].get_from, + &buffer, &buflen); + if (!rc) + { + const unsigned char *s; + + s = find_tlv (buffer, buflen, tag, &valuelen, 0); + if (!s) + value = NULL; /* not found */ + else if (valuelen > buflen - (s - buffer)) + { + log_error ("warning: constructed DO too short\n"); + value = NULL; + xfree (buffer); buffer = NULL; + } + else + value = buffer + (s - buffer); + } + } + + if (!value) /* Not in a constructed DO, try simple. */ + { + rc = iso7816_get_data (slot, tag, &buffer, &buflen); + if (!rc) + { + value = buffer; + valuelen = buflen; + } + } + + if (!rc) + { + *nbytes = valuelen; + *result = value; + return buffer; + } + return NULL; +} + +#if 0 /* not used */ +static void +dump_one_do (int slot, int tag) +{ + int rc, i; + unsigned char *buffer; + size_t buflen; + const char *desc; + int binary; + const unsigned char *value; + size_t valuelen; + + for (i=0; data_objects[i].tag && data_objects[i].tag != tag; i++) + ; + desc = data_objects[i].tag? data_objects[i].desc : "?"; + binary = data_objects[i].tag? data_objects[i].binary : 1; + + value = NULL; + rc = -1; + if (data_objects[i].tag && data_objects[i].get_from) + { + rc = iso7816_get_data (slot, data_objects[i].get_from, + &buffer, &buflen); + if (!rc) + { + value = find_tlv (buffer, buflen, tag, &valuelen, 0); + if (!value) + ; /* not found */ + else if (valuelen > buflen - (value - buffer)) + { + log_error ("warning: constructed DO too short\n"); + value = NULL; + xfree (buffer); buffer = NULL; + } + } + } + + if (!value) /* Not in a constructed DO, try simple. */ + { + rc = iso7816_get_data (slot, tag, &buffer, &buflen); + if (!rc) + { + value = buffer; + valuelen = buflen; + } + } + if (rc == 0x6a88) + log_info ("DO `%s' not available\n", desc); + else if (rc) + log_info ("DO `%s' not available (rc=%04X)\n", desc, rc); + else + { + if (binary) + { + log_info ("DO `%s': ", desc); + log_printhex ("", value, valuelen); + } + else + log_info ("DO `%s': `%.*s'\n", + desc, (int)valuelen, value); /* FIXME: sanitize */ + xfree (buffer); + } +} +#endif /*not used*/ + + +static void +dump_all_do (int slot) +{ + int rc, i, j; + unsigned char *buffer; + size_t buflen; + + for (i=0; data_objects[i].tag; i++) + { + if (data_objects[i].get_from) + continue; + + rc = iso7816_get_data (slot, data_objects[i].tag, &buffer, &buflen); + if (rc == 0x6a88) + ; + else if (rc) + log_info ("DO `%s' not available (rc=%04X)\n", + data_objects[i].desc, rc); + else + { + if (data_objects[i].binary) + { + log_info ("DO `%s': ", data_objects[i].desc); + log_printhex ("", buffer, buflen); + } + else + log_info ("DO `%s': `%.*s'\n", + data_objects[i].desc, + (int)buflen, buffer); /* FIXME: sanitize */ + } + + if (data_objects[i].constructed) + { + for (j=0; data_objects[j].tag; j++) + { + const unsigned char *value; + size_t valuelen; + + if (j==i || data_objects[i].tag != data_objects[j].get_from) + continue; + value = find_tlv (buffer, buflen, + data_objects[j].tag, &valuelen, 0); + if (!value) + ; /* not found */ + else if (valuelen > buflen - (value - buffer)) + log_error ("warning: constructed DO too short\n"); + else + { + if (data_objects[j].binary) + { + log_info ("DO `%s': ", data_objects[j].desc); + log_printhex ("", value, valuelen); + } + else + log_info ("DO `%s': `%.*s'\n", + data_objects[j].desc, + (int)valuelen, value); /* FIXME: sanitize */ + } + } + } + xfree (buffer); buffer = NULL; + } +} + + +/* Count the number of bits, assuming the A represents an unsigned big + integer of length LEN bytes. */ +static unsigned int +count_bits (const unsigned char *a, size_t len) +{ + unsigned int n = len * 8; + int i; + + for (; len && !*a; len--, a++, n -=8) + ; + if (len) + { + for (i=7; i && !(*a & (1<> 8; /* 2 byte length header */ + *p++ = n; + *p++ = 4; /* key packet version */ + *p++ = timestamp >> 24; + *p++ = timestamp >> 16; + *p++ = timestamp >> 8; + *p++ = timestamp; + *p++ = 1; /* RSA */ + nbits = count_bits (m, mlen); + *p++ = nbits >> 8; + *p++ = nbits; + memcpy (p, m, mlen); p += mlen; + nbits = count_bits (e, elen); + *p++ = nbits >> 8; + *p++ = nbits; + memcpy (p, e, elen); p += elen; + + log_printhex ("fprbuf:", buffer, n+3); + gcry_md_hash_buffer (GCRY_MD_SHA1, fpr, buffer, n+3); + + xfree (buffer); + + rc = iso7816_put_data (slot, (card_version > 0x0007? 0xC7 : 0xC6) + + keynumber, fpr, 20); + if (rc) + log_error ("failed to store the fingerprint: rc=%04X\n", rc); + + return rc; +} + + +static void +send_fpr_if_not_null (CTRL ctrl, const char *keyword, + int number, const unsigned char *fpr) +{ + int i; + char buf[41]; + char numbuf[25]; + + for (i=0; i < 20 && !fpr[i]; i++) + ; + if (i==20) + return; /* All zero. */ + for (i=0; i< 20; i++) + sprintf (buf+2*i, "%02X", fpr[i]); + if (number == -1) + *numbuf = 0; /* Don't print the key number */ + else + sprintf (numbuf, "%d", number); + send_status_info (ctrl, keyword, + numbuf, (size_t)strlen(numbuf), + buf, (size_t)strlen (buf), NULL, 0); +} + +static void +send_key_data (CTRL ctrl, const char *name, + const unsigned char *a, size_t alen) +{ + char *p, *buf = xmalloc (alen*2+1); + + for (p=buf; alen; a++, alen--, p += 2) + sprintf (p, "%02X", *a); + + send_status_info (ctrl, "KEY-DATA", + name, (size_t)strlen(name), + buf, (size_t)strlen (buf), + NULL, 0); + xfree (buf); +} + + + +static int +do_learn_status (APP app, CTRL ctrl) +{ + void *relptr; + unsigned char *value; + size_t valuelen; + int i; + + relptr = get_one_do (app->slot, 0x005B, &value, &valuelen); + if (relptr) + { + send_status_info (ctrl, "DISP-NAME", value, valuelen, NULL, 0); + xfree (relptr); + } + relptr = get_one_do (app->slot, 0x5F2D, &value, &valuelen); + if (relptr) + { + send_status_info (ctrl, "DISP-LANG", value, valuelen, NULL, 0); + xfree (relptr); + } + relptr = get_one_do (app->slot, 0x5F35, &value, &valuelen); + if (relptr) + { + send_status_info (ctrl, "DISP-SEX", value, valuelen, NULL, 0); + xfree (relptr); + } + relptr = get_one_do (app->slot, 0x5F50, &value, &valuelen); + if (relptr) + { + send_status_info (ctrl, "PUBKEY-URL", value, valuelen, NULL, 0); + xfree (relptr); + } + relptr = get_one_do (app->slot, 0x005E, &value, &valuelen); + if (relptr) + { + send_status_info (ctrl, "LOGIN-DATA", value, valuelen, NULL, 0); + xfree (relptr); + } + + relptr = get_one_do (app->slot, 0x00C5, &value, &valuelen); + if (relptr && valuelen >= 60) + { + for (i=0; i < 3; i++) + send_fpr_if_not_null (ctrl, "KEY-FPR", i+1, value+i*20); + } + xfree (relptr); + relptr = get_one_do (app->slot, 0x00C6, &value, &valuelen); + if (relptr && valuelen >= 60) + { + for (i=0; i < 3; i++) + send_fpr_if_not_null (ctrl, "CA-FPR", i+1, value+i*20); + } + xfree (relptr); + relptr = get_one_do (app->slot, 0x00C4, &value, &valuelen); + if (relptr) + { + char numbuf[7*23]; + + for (i=0,*numbuf=0; i < valuelen && i < 7; i++) + sprintf (numbuf+strlen (numbuf), " %d", value[i]); + send_status_info (ctrl, "CHV-STATUS", numbuf, strlen (numbuf), NULL, 0); + xfree (relptr); + } + + { + unsigned long ul = get_sig_counter (app); + char numbuf[23]; + + sprintf (numbuf, "%lu", ul); + send_status_info (ctrl, "SIG-COUNTER", numbuf, strlen (numbuf), NULL, 0); + } + return 0; +} + + +/* Handle the SETATTR operation. All arguments are already basically + checked. */ +static int +do_setattr (APP app, const char *name, + int (*pincb)(void*, const char *, char **), + void *pincb_arg, + const unsigned char *value, size_t valuelen) +{ + gpg_error_t rc; + int idx; + static struct { + const char *name; + int tag; + } table[] = { + { "DISP-NAME", 0x005B }, + { "LOGIN-DATA", 0x005E }, + { "DISP-LANG", 0x5F2D }, + { "DISP-SEX", 0x5F35 }, + { "PUBKEY-URL", 0x5F50 }, + { "CHV-STATUS-1", 0x00C4 }, + { "CA-FPR-1", 0x00CA }, + { "CA-FPR-2", 0x00CB }, + { "CA-FPR-3", 0x00CC }, + { NULL, 0 } + }; + + + for (idx=0; table[idx].name && strcmp (table[idx].name, name); idx++) + ; + if (!table[idx].name) + return gpg_error (GPG_ERR_INV_NAME); + + if (!app->did_chv3) + { + char *pinvalue; + + rc = pincb (pincb_arg, "Admin PIN (CHV3)", + &pinvalue); +/* pinvalue = xstrdup ("12345678"); */ +/* rc = 0; */ + if (rc) + { + log_info ("PIN callback returned error: %s\n", gpg_strerror (rc)); + return rc; + } + + rc = iso7816_verify (app->slot, 0x83, pinvalue, strlen (pinvalue)); + xfree (pinvalue); + if (rc) + { + log_error ("verify CHV3 failed\n"); + rc = gpg_error (GPG_ERR_GENERAL); + return rc; + } + app->did_chv3 = 1; + } + + rc = iso7816_put_data (app->slot, table[idx].tag, value, valuelen); + if (rc) + log_error ("failed to set `%s': %s\n", table[idx].name, gpg_strerror (rc)); + /* FIXME: If this fails we should *once* try again after + doing a verify command, so that in case of a problem with + tracking the verify operation we have a fallback. */ + + return rc; +} + +/* Handle the PASSWD command. */ +static int +do_change_pin (APP app, CTRL ctrl, const char *chvnostr, int reset_mode, + int (*pincb)(void*, const char *, char **), + void *pincb_arg) +{ + int rc = 0; + int chvno = atoi (chvnostr); + char *pinvalue; + + if (reset_mode && chvno == 3) + { + rc = gpg_error (GPG_ERR_INV_ID); + goto leave; + } + else if (reset_mode || chvno == 3) + { + rc = pincb (pincb_arg, "Admin PIN", &pinvalue); + if (rc) + { + log_error ("error getting PIN: %s\n", gpg_strerror (rc)); + goto leave; + } + rc = iso7816_verify (app->slot, 0x83, pinvalue, strlen (pinvalue)); + xfree (pinvalue); + if (rc) + { + log_error ("verify CHV3 failed: rc=%04X\n", rc); + goto leave; + } + } + else if (chvno == 1) + { + rc = pincb (pincb_arg, "Signature PIN", &pinvalue); + if (rc) + { + log_error ("error getting PIN: %s\n", gpg_strerror (rc)); + goto leave; + } + rc = iso7816_verify (app->slot, 0x81, pinvalue, strlen (pinvalue)); + xfree (pinvalue); + if (rc) + { + log_error ("verify CHV1 failed: rc=%04X\n", rc); + goto leave; + } + } + else if (chvno == 2) + { + rc = pincb (pincb_arg, "Decryption PIN", &pinvalue); + if (rc) + { + log_error ("error getting PIN: %s\n", gpg_strerror (rc)); + goto leave; + } + rc = iso7816_verify (app->slot, 0x82, pinvalue, strlen (pinvalue)); + xfree (pinvalue); + if (rc) + { + log_error ("verify CHV2 failed: rc=%04X\n", rc); + goto leave; + } + } + else + { + rc = gpg_error (GPG_ERR_INV_ID); + goto leave; + } + + + rc = pincb (pincb_arg, chvno == 1? "New Signature PIN" : + chvno == 2? "New Decryption PIN" : + chvno == 3? "New Admin PIN" : "?", &pinvalue); + if (rc) + { + log_error ("error getting new PIN: %s\n", gpg_strerror (rc)); + goto leave; + } + + if (reset_mode) + rc = iso7816_reset_retry_counter (app->slot, 0x80 + chvno, + pinvalue, strlen (pinvalue)); + else + rc = iso7816_change_reference_data (app->slot, 0x80 + chvno, + NULL, 0, + pinvalue, strlen (pinvalue)); + xfree (pinvalue); + + + leave: + return rc; +} + + + +/* Handle the GENKEY command. */ +static int +do_genkey (APP app, CTRL ctrl, const char *keynostr, unsigned int flags, + int (*pincb)(void*, const char *, char **), + void *pincb_arg) +{ + int rc; + int i; + char numbuf[30]; + unsigned char fprbuf[20]; + const unsigned char *fpr; + const unsigned char *keydata, *m, *e; + unsigned char *buffer; + size_t buflen, keydatalen, n, mlen, elen; + time_t created_at; + int keyno = atoi (keynostr); + int force = (flags & 1); + time_t start_at; + + if (keyno < 1 || keyno > 3) + return gpg_error (GPG_ERR_INV_ID); + keyno--; + + rc = iso7816_get_data (app->slot, 0x006E, &buffer, &buflen); + if (rc) + { + log_error ("error reading application data\n"); + return gpg_error (GPG_ERR_GENERAL); + } + fpr = find_tlv (buffer, buflen, 0x00C5, &n, 0); + if (!fpr || n != 60) + { + rc = gpg_error (GPG_ERR_GENERAL); + log_error ("error reading fingerprint DO\n"); + goto leave; + } + fpr += 20*keyno; + for (i=0; i < 20 && !fpr[i]; i++) + ; + if (i!=20 && !force) + { + rc = gpg_error (GPG_ERR_EEXIST); + log_error ("key already exists\n"); + goto leave; + } + else if (i!=20) + log_info ("existing key will be replaced\n"); + else + log_info ("generating new key\n"); + + { + char *pinvalue; + rc = pincb (pincb_arg, "Admin PIN", &pinvalue); + if (rc) + { + log_error ("error getting PIN: %s\n", gpg_strerror (rc)); + return rc; + } + rc = iso7816_verify (app->slot, 0x83, pinvalue, strlen (pinvalue)); + xfree (pinvalue); + } + if (rc) + { + log_error ("verify CHV3 failed: rc=%04X\n", rc); + goto leave; + } + + xfree (buffer); buffer = NULL; +#if 1 + log_info ("please wait while key is being generated ...\n"); + start_at = time (NULL); + rc = iso7816_generate_keypair +#else +#warning key generation temporary replaced by reading an existing key. + rc = iso7816_read_public_key +#endif + (app->slot, + keyno == 0? "\xB6" : + keyno == 1? "\xB8" : "\xA4", + 2, + &buffer, &buflen); + if (rc) + { + rc = gpg_error (GPG_ERR_CARD); + log_error ("generating key failed\n"); + goto leave; + } + log_info ("key generation completed (%d seconds)\n", + (int)(time (NULL) - start_at)); + keydata = find_tlv (buffer, buflen, 0x7F49, &keydatalen, 0); + if (!keydata) + { + rc = gpg_error (GPG_ERR_CARD); + log_error ("response does not contain the public key data\n"); + goto leave; + } + + m = find_tlv (keydata, keydatalen, 0x0081, &mlen, 0); + if (!m) + { + rc = gpg_error (GPG_ERR_CARD); + log_error ("response does not contain the RSA modulus\n"); + goto leave; + } +/* log_printhex ("RSA n:", m, mlen); */ + send_key_data (ctrl, "n", m, mlen); + + e = find_tlv (keydata, keydatalen, 0x0082, &elen, 0); + if (!e) + { + rc = gpg_error (GPG_ERR_CARD); + log_error ("response does not contain the RSA public exponent\n"); + goto leave; + } +/* log_printhex ("RSA e:", e, elen); */ + send_key_data (ctrl, "e", e, elen); + + created_at = gnupg_get_time (); + sprintf (numbuf, "%lu", (unsigned long)created_at); + send_status_info (ctrl, "KEY-CREATED-AT", + numbuf, (size_t)strlen(numbuf), NULL, 0); + + rc = store_fpr (app->slot, keyno, (u32)created_at, + m, mlen, e, elen, fprbuf, app->card_version); + if (rc) + goto leave; + send_fpr_if_not_null (ctrl, "KEY-FPR", -1, fprbuf); + + + leave: + xfree (buffer); + return rc; +} + + +static unsigned long +get_sig_counter (APP app) +{ + void *relptr; + unsigned char *value; + size_t valuelen; + unsigned long ul; + + relptr = get_one_do (app->slot, 0x0093, &value, &valuelen); + if (!relptr) + return 0; + if (valuelen == 3 ) + ul = (value[0] << 16) | (value[1] << 8) | value[2]; + else + { + log_error ("invalid structure of OpenPGP card (DO 0x93)\n"); + ul = 0; + } + xfree (relptr); + return ul; +} + +static int +compare_fingerprint (APP app, int keyno, unsigned char *sha1fpr) +{ + const unsigned char *fpr; + unsigned char *buffer; + size_t buflen, n; + int rc, i; + + assert (keyno >= 1 && keyno <= 3); + + rc = iso7816_get_data (app->slot, 0x006E, &buffer, &buflen); + if (rc) + { + log_error ("error reading application data\n"); + return gpg_error (GPG_ERR_GENERAL); + } + fpr = find_tlv (buffer, buflen, 0x00C5, &n, 0); + if (!fpr || n != 60) + { + xfree (buffer); + log_error ("error reading fingerprint DO\n"); + return gpg_error (GPG_ERR_GENERAL); + } + fpr += (keyno-1)*20; + for (i=0; i < 20; i++) + if (sha1fpr[i] != fpr[i]) + { + xfree (buffer); + return gpg_error (GPG_ERR_WRONG_SECKEY); + } + xfree (buffer); + return 0; +} + + + +/* Compute a digital signature on INDATA which is expected to be the + raw message digest. For this application the KEYIDSTR consists of + the serialnumber and the fingerprint delimited by a slash. + + Note that this fucntion may return the error code + GPG_ERR_WRONG_CARD to indicate that the card currently present does + not match the one required for the requested action (e.g. the + serial number does not match). */ +static int +do_sign (APP app, const char *keyidstr, int hashalgo, + int (*pincb)(void*, const char *, char **), + void *pincb_arg, + const void *indata, size_t indatalen, + unsigned char **outdata, size_t *outdatalen ) +{ + static unsigned char sha1_prefix[15] = /* Object ID is 1.3.14.3.2.26 */ + { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, + 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 }; + static unsigned char rmd160_prefix[15] = /* Object ID is 1.3.36.3.2.1 */ + { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x24, 0x03, + 0x02, 0x01, 0x05, 0x00, 0x04, 0x14 }; + int rc; + unsigned char data[35]; + unsigned char tmp_sn[20]; /* actually 16 but we use it also for the fpr. */ + const char *s; + int n; + const char *fpr = NULL; + unsigned long sigcount; + + if (!keyidstr || !*keyidstr) + return gpg_error (GPG_ERR_INV_VALUE); + if (indatalen != 20) + return gpg_error (GPG_ERR_INV_VALUE); + + /* Check whether an OpenPGP card of any version has been requested. */ + if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12)) + return gpg_error (GPG_ERR_INV_ID); + + for (s=keyidstr, n=0; hexdigitp (s); s++, n++) + ; + if (n != 32) + return gpg_error (GPG_ERR_INV_ID); + else if (!*s) + ; /* no fingerprint given: we allow this for now. */ + else if (*s == '/') + fpr = s + 1; + else + return gpg_error (GPG_ERR_INV_ID); + + for (s=keyidstr, n=0; n < 16; s += 2, n++) + tmp_sn[n] = xtoi_2 (s); + + if (app->serialnolen != 16) + return gpg_error (GPG_ERR_INV_CARD); + if (memcmp (app->serialno, tmp_sn, 16)) + return gpg_error (GPG_ERR_WRONG_CARD); + + /* If a fingerprint has been specified check it against the one on + the card. This is allows for a meaningful error message in case + the key on the card has been replaced but the shadow information + known to gpg was not updated. If there is no fingerprint, gpg + will detect a bogus signature anyway due to the + verify-after-signing feature. */ + if (fpr) + { + for (s=fpr, n=0; hexdigitp (s); s++, n++) + ; + if (n != 40) + return gpg_error (GPG_ERR_INV_ID); + else if (!*s) + ; /* okay */ + else + return gpg_error (GPG_ERR_INV_ID); + + for (s=fpr, n=0; n < 20; s += 2, n++) + tmp_sn[n] = xtoi_2 (s); + rc = compare_fingerprint (app, 1, tmp_sn); + if (rc) + return rc; + } + + if (hashalgo == GCRY_MD_SHA1) + memcpy (data, sha1_prefix, 15); + else if (hashalgo == GCRY_MD_RMD160) + memcpy (data, rmd160_prefix, 15); + else + return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); + memcpy (data+15, indata, indatalen); + + sigcount = get_sig_counter (app); + log_info ("signatures created so far: %lu\n", sigcount); + + /* FIXME: Check whether we are really required to enter the PIN for + each signature. There is a DO for this. */ + if (!app->did_chv1 || 1) + { + char *pinvalue; + + { + char *prompt; + if (asprintf (&prompt, "Signature PIN [sigs done: %lu]", sigcount) < 0) + return gpg_error_from_errno (errno); + rc = pincb (pincb_arg, prompt, &pinvalue); + free (prompt); + } +/* pinvalue = xstrdup ("123456"); */ +/* rc = 0; */ + if (rc) + { + log_info ("PIN callback returned error: %s\n", gpg_strerror (rc)); + return rc; + } + + rc = iso7816_verify (app->slot, 0x81, pinvalue, strlen (pinvalue)); + xfree (pinvalue); + if (rc) + { + log_error ("verify CHV1 failed\n"); + rc = gpg_error (GPG_ERR_GENERAL); + return rc; + } + app->did_chv1 = 1; + } + + rc = iso7816_compute_ds (app->slot, data, 35, outdata, outdatalen); + return rc; +} + +/* Compute a digital signature using the INTERNAL AUTHENTICATE command + on INDATA which is expected to be the raw message digest. For this + application the KEYIDSTR consists of the serialnumber and the + fingerprint delimited by a slash. + + Note that this fucntion may return the error code + GPG_ERR_WRONG_CARD to indicate that the card currently present does + not match the one required for the requested action (e.g. the + serial number does not match). */ +static int +do_auth (APP app, const char *keyidstr, + int (*pincb)(void*, const char *, char **), + void *pincb_arg, + const void *indata, size_t indatalen, + unsigned char **outdata, size_t *outdatalen ) +{ + int rc; + unsigned char tmp_sn[20]; /* actually 16 but we use it also for the fpr. */ + const char *s; + int n; + const char *fpr = NULL; + + if (!keyidstr || !*keyidstr) + return gpg_error (GPG_ERR_INV_VALUE); + if (indatalen > 50) /* For a 1024 bit key. */ + return gpg_error (GPG_ERR_INV_VALUE); + + /* Check whether an OpenPGP card of any version has been requested. */ + if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12)) + return gpg_error (GPG_ERR_INV_ID); + + for (s=keyidstr, n=0; hexdigitp (s); s++, n++) + ; + if (n != 32) + return gpg_error (GPG_ERR_INV_ID); + else if (!*s) + ; /* no fingerprint given: we allow this for now. */ + else if (*s == '/') + fpr = s + 1; + else + return gpg_error (GPG_ERR_INV_ID); + + for (s=keyidstr, n=0; n < 16; s += 2, n++) + tmp_sn[n] = xtoi_2 (s); + + if (app->serialnolen != 16) + return gpg_error (GPG_ERR_INV_CARD); + if (memcmp (app->serialno, tmp_sn, 16)) + return gpg_error (GPG_ERR_WRONG_CARD); + + /* If a fingerprint has been specified check it against the one on + the card. This is allows for a meaningful error message in case + the key on the card has been replaced but the shadow information + known to gpg was not updated. If there is no fingerprint, gpg + will detect a bogus signature anyway due to the + verify-after-signing feature. */ + if (fpr) + { + for (s=fpr, n=0; hexdigitp (s); s++, n++) + ; + if (n != 40) + return gpg_error (GPG_ERR_INV_ID); + else if (!*s) + ; /* okay */ + else + return gpg_error (GPG_ERR_INV_ID); + + for (s=fpr, n=0; n < 20; s += 2, n++) + tmp_sn[n] = xtoi_2 (s); + rc = compare_fingerprint (app, 3, tmp_sn); + if (rc) + return rc; + } + + if (!app->did_chv2) + { + char *pinvalue; + + rc = pincb (pincb_arg, "Authentication/Decryption PIN", &pinvalue); + if (rc) + { + log_info ("PIN callback returned error: %s\n", gpg_strerror (rc)); + return rc; + } + + rc = iso7816_verify (app->slot, 0x82, pinvalue, strlen (pinvalue)); + xfree (pinvalue); + if (rc) + { + log_error ("verify CHV2 failed\n"); + rc = gpg_error (GPG_ERR_GENERAL); + return rc; + } + app->did_chv2 = 1; + } + + rc = iso7816_internal_authenticate (app->slot, indata, indatalen, + outdata, outdatalen); + return rc; +} + + +static int +do_decipher (APP app, const char *keyidstr, + int (pincb)(void*, const char *, char **), + void *pincb_arg, + const void *indata, size_t indatalen, + unsigned char **outdata, size_t *outdatalen ) +{ + int rc; + unsigned char tmp_sn[20]; /* actually 16 but we use it also for the fpr. */ + const char *s; + int n; + const char *fpr = NULL; + + if (!keyidstr || !*keyidstr || !indatalen) + return gpg_error (GPG_ERR_INV_VALUE); + + /* Check whether an OpenPGP card of any version has been requested. */ + if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12)) + return gpg_error (GPG_ERR_INV_ID); + + for (s=keyidstr, n=0; hexdigitp (s); s++, n++) + ; + if (n != 32) + return gpg_error (GPG_ERR_INV_ID); + else if (!*s) + ; /* no fingerprint given: we allow this for now. */ + else if (*s == '/') + fpr = s + 1; + else + return gpg_error (GPG_ERR_INV_ID); + + for (s=keyidstr, n=0; n < 16; s += 2, n++) + tmp_sn[n] = xtoi_2 (s); + + if (app->serialnolen != 16) + return gpg_error (GPG_ERR_INV_CARD); + if (memcmp (app->serialno, tmp_sn, 16)) + return gpg_error (GPG_ERR_WRONG_CARD); + + /* If a fingerprint has been specified check it against the one on + the card. This is allows for a meaningful error message in case + the key on the card has been replaced but the shadow information + known to gpg was not updated. If there is no fingerprint, the + decryption will won't produce the right plaintext anyway. */ + if (fpr) + { + for (s=fpr, n=0; hexdigitp (s); s++, n++) + ; + if (n != 40) + return gpg_error (GPG_ERR_INV_ID); + else if (!*s) + ; /* okay */ + else + return gpg_error (GPG_ERR_INV_ID); + + for (s=fpr, n=0; n < 20; s += 2, n++) + tmp_sn[n] = xtoi_2 (s); + rc = compare_fingerprint (app, 2, tmp_sn); + if (rc) + return rc; + } + + if (!app->did_chv2) + { + char *pinvalue; + + rc = pincb (pincb_arg, "Decryption PIN", &pinvalue); +/* pinvalue = xstrdup ("123456"); */ +/* rc = 0; */ + if (rc) + { + log_info ("PIN callback returned error: %s\n", gpg_strerror (rc)); + return rc; + } + + rc = iso7816_verify (app->slot, 0x82, pinvalue, strlen (pinvalue)); + xfree (pinvalue); + if (rc) + { + log_error ("verify CHV2 failed\n"); + rc = gpg_error (GPG_ERR_GENERAL); + return rc; + } + app->did_chv2 = 1; + } + + rc = iso7816_decipher (app->slot, indata, indatalen, outdata, outdatalen); + return rc; +} + + + + +/* Select the OpenPGP application on the card in SLOT. This function + must be used before any other OpenPGP application functions. */ +int +app_select_openpgp (APP app, unsigned char **sn, size_t *snlen) +{ + static char const aid[] = { 0xD2, 0x76, 0x00, 0x01, 0x24, 0x01 }; + int slot = app->slot; + int rc; + unsigned char *buffer; + size_t buflen; + + rc = iso7816_select_application (slot, aid, sizeof aid); + if (!rc) + { + /* fixme: get the full AID and check that the version is okay + with us. */ + rc = iso7816_get_data (slot, 0x004F, &buffer, &buflen); + if (rc) + goto leave; + if (opt.verbose) + { + log_info ("got AID: "); + log_printhex ("", buffer, buflen); + } + + if (sn) + { + *sn = buffer; + *snlen = buflen; + app->card_version = buffer[6] << 8; + app->card_version |= buffer[7]; + } + else + xfree (buffer); + + if (opt.verbose > 1) + dump_all_do (slot); + + app->fnc.learn_status = do_learn_status; + app->fnc.setattr = do_setattr; + app->fnc.genkey = do_genkey; + app->fnc.sign = do_sign; + app->fnc.auth = do_auth; + app->fnc.decipher = do_decipher; + app->fnc.change_pin = do_change_pin; + } + +leave: + return rc; +} + + + +/* This function is a hack to retrieve essential information about the + card to be displayed by simple tools. It mostly resembles what the + LEARN command returns. All parameters return allocated strings or + buffers or NULL if the data object is not available. All returned + values are sanitized. */ +int +app_openpgp_cardinfo (APP app, + char **serialno, + char **disp_name, + char **pubkey_url, + unsigned char **fpr1, + unsigned char **fpr2, + unsigned char **fpr3) +{ + int rc; + void *relptr; + unsigned char *value; + size_t valuelen; + + if (serialno) + { + time_t dummy; + + *serialno = NULL; + rc = app_get_serial_and_stamp (app, serialno, &dummy); + if (rc) + { + log_error ("error getting serial number: %s\n", gpg_strerror (rc)); + return rc; + } + } + + if (disp_name) + { + *disp_name = NULL; + relptr = get_one_do (app->slot, 0x005B, &value, &valuelen); + if (relptr) + { + *disp_name = make_printable_string (value, valuelen, 0); + xfree (relptr); + } + } + + if (pubkey_url) + { + *pubkey_url = NULL; + relptr = get_one_do (app->slot, 0x5F50, &value, &valuelen); + if (relptr) + { + *pubkey_url = make_printable_string (value, valuelen, 0); + xfree (relptr); + } + } + + if (fpr1) + *fpr1 = NULL; + if (fpr2) + *fpr2 = NULL; + if (fpr3) + *fpr3 = NULL; + relptr = get_one_do (app->slot, 0x00C5, &value, &valuelen); + if (relptr && valuelen >= 60) + { + if (fpr1) + { + *fpr1 = xmalloc (20); + memcpy (*fpr1, value + 0, 20); + } + if (fpr2) + { + *fpr2 = xmalloc (20); + memcpy (*fpr2, value + 20, 20); + } + if (fpr3) + { + *fpr3 = xmalloc (20); + memcpy (*fpr3, value + 40, 20); + } + } + xfree (relptr); + + return 0; +} + + + +/* This function is currently only used by the sc-copykeys program to + store a key on the smartcard. APP ist the application handle, + KEYNO is the number of the key and PINCB, PINCB_ARG are used to ask + for the SO PIN. TEMPLATE and TEMPLATE_LEN describe a buffer with + the key template to store. CREATED_AT is the timestamp used to + create the fingerprint. M, MLEN is the RSA modulus and E, ELEN the + RSA public exponent. This function silently overwrites an existing + key.*/ +int +app_openpgp_storekey (APP app, int keyno, + unsigned char *template, size_t template_len, + time_t created_at, + const unsigned char *m, size_t mlen, + const unsigned char *e, size_t elen, + int (*pincb)(void*, const char *, char **), + void *pincb_arg) +{ + int rc; + unsigned char fprbuf[20]; + + if (keyno < 1 || keyno > 3) + return gpg_error (GPG_ERR_INV_ID); + keyno--; + + { + char *pinvalue; + rc = pincb (pincb_arg, "Admin PIN", &pinvalue); + if (rc) + { + log_error ("error getting PIN: %s\n", gpg_strerror (rc)); + return rc; + } + rc = iso7816_verify (app->slot, 0x83, pinvalue, strlen (pinvalue)); + xfree (pinvalue); + } + if (rc) + { + log_error ("verify CHV3 failed: rc=%04X\n", rc); + goto leave; + } + + rc = iso7816_put_data (app->slot, + (app->card_version > 0x0007? 0xE0 : 0xE9) + keyno, + template, template_len); + if (rc) + { + log_error ("failed to store the key: rc=%04X\n", rc); + rc = gpg_error (GPG_ERR_CARD); + goto leave; + } + +/* log_printhex ("RSA n:", m, mlen); */ +/* log_printhex ("RSA e:", e, elen); */ + + rc = store_fpr (app->slot, keyno, (u32)created_at, + m, mlen, e, elen, fprbuf, app->card_version); + + leave: + return rc; +} + + +/* Utility function for external tools: Read the public RSA key at + KEYNO and return modulus and exponent in (M,MLEN) and (E,ELEN). */ +int +app_openpgp_readkey (APP app, int keyno, unsigned char **m, size_t *mlen, + unsigned char **e, size_t *elen) +{ + int rc; + const unsigned char *keydata, *a; + unsigned char *buffer; + size_t buflen, keydatalen, alen; + + *m = NULL; + *e = NULL; + + if (keyno < 1 || keyno > 3) + return gpg_error (GPG_ERR_INV_ID); + keyno--; + + rc = iso7816_read_public_key(app->slot, + keyno == 0? "\xB6" : + keyno == 1? "\xB8" : "\xA4", + 2, + &buffer, &buflen); + if (rc) + { + rc = gpg_error (GPG_ERR_CARD); + log_error ("reading key failed\n"); + goto leave; + } + + keydata = find_tlv (buffer, buflen, 0x7F49, &keydatalen, 0); + if (!keydata) + { + log_error ("response does not contain the public key data\n"); + rc = gpg_error (GPG_ERR_CARD); + goto leave; + } + + a = find_tlv (keydata, keydatalen, 0x0081, &alen, 0); + if (!a) + { + log_error ("response does not contain the RSA modulus\n"); + rc = gpg_error (GPG_ERR_CARD); + goto leave; + } + *mlen = alen; + *m = xmalloc (alen); + memcpy (*m, a, alen); + + a = find_tlv (keydata, keydatalen, 0x0082, &alen, 0); + if (!e) + { + log_error ("response does not contain the RSA public exponent\n"); + rc = gpg_error (GPG_ERR_CARD); + goto leave; + } + *elen = alen; + *e = xmalloc (alen); + memcpy (*e, a, alen); + + leave: + xfree (buffer); + if (rc) + { + xfree (*m); *m = NULL; + xfree (*e); *e = NULL; + } + return rc; +} -- cgit From 1bcf8ef9dea1a9b171c27ef48cadb79df6201e33 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 5 Aug 2003 17:11:04 +0000 Subject: Cleanups, fixes and PC/SC support --- ChangeLog | 4 + NEWS | 10 ++ README | 38 ++++- TODO | 3 + configure.ac | 4 +- doc/scdaemon.texi | 4 + g10/ChangeLog | 20 +++ g10/Makefile.am | 17 +- g10/g10.c | 107 ++----------- g10/pkglue.c | 37 ++++- g10/pkglue.h | 1 + g10/seckey-cert.c | 15 +- g10/status.c | 226 +-------------------------- g10/status.h | 4 - scd/ChangeLog | 22 +++ scd/apdu.c | 426 +++++++++++++++++++++++++++++++++++++++++++-------- scd/apdu.h | 3 +- scd/app-common.h | 1 + scd/app-openpgp.c | 135 ++++------------ scd/app.c | 13 +- scd/sc-copykeys.c | 8 +- scd/sc-investigate.c | 8 +- scd/scdaemon.c | 12 +- scd/scdaemon.h | 1 + 24 files changed, 600 insertions(+), 519 deletions(-) (limited to 'scd/app-openpgp.c') diff --git a/ChangeLog b/ChangeLog index b846f27a7..83e9cba0c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2003-08-05 Werner Koch + + * configure.ac (GNUPG_DEFAULT_HONMEDIR): Changed back to ~/.gnupg. + 2003-07-31 Werner Koch * Makefile.am (DISTCLEANFILES): Add g10defs.h diff --git a/NEWS b/NEWS index 794ad11f1..9e6b9f1af 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,16 @@ Noteworthy changes in version 1.9.0 (unreleased) ------------------------------------------------ + * gpg has been renamed to gpg2 and gpgv to gpgv2. This is a + temporary solution to allow co-existing with stable gpg versions. + + * The default config file is ~/.gnupg/gpg.conf-1.9.0 if it exists. + + * Removed the -k, -kv and -kvv commands. -k is now an alias to + --list-keys. New command -K as alias for --list-secret-keys. + + * Removed --run-as-shm-coprocess feature. + * gpg does now also use libgcrypt, libgpg-error is required. * New gpgsm commands --call-dirmngr and --call-protect-tool. diff --git a/README b/README index 7aea069b3..8dea9dbb9 100644 --- a/README +++ b/README @@ -34,6 +34,21 @@ gpgsm: prepended before each block. +gpg2: +----- + +--card-status + + Show information pertaining smartcards implementing the OpenPGP + application. + +--change-pin + + Offers a menu to change the PIN of OpenPGP smartcards and to reset + the retry counters. + + + OPTIONS ======= @@ -139,6 +154,22 @@ gpg-agent: lockups in case of bugs. +scdaemon: +-------- + +--ctapi-driver + + The default for Scdaemon is to use the PC/SC API currently provided + by libpcsclite.so. As an alternative the ctAPI can be used by + specify this option with the appropriate driver name + (e.g. libtowitoko.so). + +--reader-port + + This specifies the port of the chipcard reader. For PC/SC this is + currently ignored and the first PC/SC reader is used. For the + ctAPI, a number must be specified (the default is 32768 for the + first USB port). @@ -174,10 +205,15 @@ gpg.conf Options for gpg. Note that old versions of gpg use the filename `options' instead of `gpg.conf'. +gpg.conf-1.9.x + + Options for gpg; tried before gpg.conf + + policies.txt A list of allowed CA policies. This file should give the - object identifiers of the policies line by line. emptry lines + object identifiers of the policies line by line. Empty lines and lines startung with a hash mark are ignored. ++++++++++ diff --git a/TODO b/TODO index 431f2a2ea..c9b2d18ff 100644 --- a/TODO +++ b/TODO @@ -55,5 +55,8 @@ might want to have an agent context for each service request * sm/export.c ** Return an error code or a status info per user ID. +* scd/apdu.c +** We need close_reader functionality + * ALL ** Return IMPORT_OK status. diff --git a/configure.ac b/configure.ac index 9d8aef9ee..060f31d97 100644 --- a/configure.ac +++ b/configure.ac @@ -224,7 +224,7 @@ AH_BOTTOM([ #ifdef HAVE_DRIVE_LETTERS #define GNUPG_DEFAULT_HOMEDIR "c:/gnupg" #else -#define GNUPG_DEFAULT_HOMEDIR "~/.gnupg2" +#define GNUPG_DEFAULT_HOMEDIR "~/.gnupg" #endif #define GNUPG_PRIVATE_KEYS_DIR "private-keys-v1.d" @@ -966,7 +966,7 @@ cat >g10defs.tmp < + + * Makefile.am (install-data-local): Dropped check for the ancient + gpgm tool. + (bin_PROGRAMS): Renamed gpg to gpg2 and gpgv to gpgv2. This is so + that it won't conflict with the current stable version of gpg. + + * pkglue.c (pk_check_secret_key): New. + * seckey-cert.c (do_check): Reenable this test here again. + + * g10.c (main): Add command -K as an alias for + --list-secret-keys. Command "-k" is now an alias to --list-keys. + Remove special treatment of -kv and -kvv. + (set_cmd): Ditto. + (main): Strip a "-cvs" suffix when testing for a version specific + config file. + + * status.h, status.c, g10.c [USE_SHM_COPROCESSING]: Removed. This + is not any longer available. + 2003-07-29 Werner Koch * g10.c (main): Add secmem features and set the random seed file. diff --git a/g10/Makefile.am b/g10/Makefile.am index d6984941e..59213d04b 100644 --- a/g10/Makefile.am +++ b/g10/Makefile.am @@ -31,8 +31,7 @@ AM_CFLAGS = -DGNUPG_LIBEXECDIR="\"$(libexecdir)\"" endif needed_libs = ../common/libcommon.a ../jnlib/libjnlib.a -#noinst_PROGRAMS = gpgd -bin_PROGRAMS = gpg gpgv +bin_PROGRAMS = gpg2 gpgv2 common_source = \ global.h gpg.h \ @@ -65,7 +64,7 @@ common_source = \ keylist.c \ pkglue.c pkglue.h -gpg_SOURCES = g10.c \ +gpg2_SOURCES = g10.c \ $(common_source) \ pkclist.c \ skclist.c \ @@ -99,7 +98,7 @@ gpg_SOURCES = g10.c \ card-util.c \ exec.c exec.h -gpgv_SOURCES = gpgv.c \ +gpgv2_SOURCES = gpgv.c \ $(common_source) \ verify.c @@ -111,8 +110,8 @@ gpgv_SOURCES = gpgv.c \ # $(common_source) LDADD = $(needed_libs) @INTLLIBS@ @CAPLIBS@ @ZLIBS@ -gpg_LDADD = $(LIBGCRYPT_LIBS) $(LDADD) -lassuan -lgpg-error -gpgv_LDADD = $(LIBGCRYPT_LIBS) $(LDADD) -lassuan -lgpg-error +gpg2_LDADD = $(LIBGCRYPT_LIBS) $(LDADD) -lassuan -lgpg-error +gpgv2_LDADD = $(LIBGCRYPT_LIBS) $(LDADD) -lassuan -lgpg-error $(PROGRAMS): $(needed_libs) @@ -120,8 +119,4 @@ install-data-local: $(mkinstalldirs) $(DESTDIR)$(pkgdatadir) $(INSTALL_DATA) $(srcdir)/options.skel \ $(DESTDIR)$(pkgdatadir)/options.skel - @set -e;\ - if test -f $(DESTDIR)$(bindir)/gpgm ; then \ - echo "removing obsolete gpgm binary" ; \ - rm $(DESTDIR)$(bindir)/gpgm ; \ - fi + diff --git a/g10/g10.c b/g10/g10.c index f89556184..aef76992b 100644 --- a/g10/g10.c +++ b/g10/g10.c @@ -61,7 +61,8 @@ enum cmd_and_opt_values { aNull = 0, aEncr = 'e', aEncrFiles, oInteractive = 'i', - oKOption = 'k', + aListKeys = 'k', + aListSecretKeys = 'K', oDryRun = 'n', oOutput = 'o', oQuiet = 'q', @@ -93,15 +94,11 @@ enum cmd_and_opt_values { aNull = 0, aDeleteKeys, aDeleteSecretKeys, aDeleteSecretAndPublicKeys, - aKMode, - aKModeC, aImport, aFastImport, aVerify, aVerifyFiles, - aListKeys, aListSigs, - aListSecretKeys, aSendKeys, aRecvKeys, aSearchKeys, @@ -213,7 +210,6 @@ enum cmd_and_opt_values { aNull = 0, oTrustModel, oForceOwnertrust, oEmuChecksumBug, - oRunAsShmCP, oSetFilename, oForYourEyesOnly, oNoForYourEyesOnly, @@ -514,7 +510,6 @@ static ARGPARSE_OPTS opts[] = { /* Not yet used */ /* { aListTrustPath, "list-trust-path",0, "@"}, */ { aPipeMode, "pipemode", 0, "@" }, - { oKOption, NULL, 0, "@"}, { oPasswdFD, "passphrase-fd",1, "@" }, #ifdef __riscos__ { oPasswdFile, "passphrase-file",2, "@" }, @@ -549,7 +544,6 @@ static ARGPARSE_OPTS opts[] = { { oTrustModel, "trust-model", 2, "@"}, { oForceOwnertrust, "force-ownertrust", 2, "@"}, { oEmuChecksumBug, "emulate-checksum-bug", 0, "@"}, - { oRunAsShmCP, "run-as-shm-coprocess", 4, "@" }, { oSetFilename, "set-filename", 2, "@" }, { oForYourEyesOnly, "for-your-eyes-only", 0, "@" }, { oNoForYourEyesOnly, "no-for-your-eyes-only", 0, "@" }, @@ -879,8 +873,6 @@ set_cmd( enum cmd_and_opt_values *ret_cmd, enum cmd_and_opt_values new_cmd ) cmd = aSignSym; else if( cmd == aSym && new_cmd == aSign ) cmd = aSignSym; - else if( cmd == aKMode && new_cmd == aSym ) - cmd = aKModeC; else if( ( cmd == aSign && new_cmd == aClearsign ) || ( cmd == aClearsign && new_cmd == aSign ) ) cmd = aClearsign; @@ -1167,9 +1159,6 @@ main( int argc, char **argv ) int pwfd = -1; int with_fpr = 0; /* make an option out of --fingerprint */ int any_explicit_recipient = 0; -#ifdef USE_SHM_COPROCESSING - ulong requested_shm_size=0; -#endif #ifdef __riscos__ riscos_global_defaults(); @@ -1276,19 +1265,6 @@ main( int argc, char **argv ) opt.strict=0; log_set_strict(0); } -#ifdef USE_SHM_COPROCESSING - else if( pargs.r_opt == oRunAsShmCP ) { - /* does not make sense in a options file, we do it here, - * so that we are the able to drop setuid as soon as possible */ - opt.shm_coprocess = 1; - requested_shm_size = pargs.r.ret_ulong; - } - else if ( pargs.r_opt == oStatusFD ) { - /* this is needed to ensure that the status-fd filedescriptor is - * initialized when init_shm_coprocessing() is called */ - set_status_fd( iobuf_translate_file_handle (pargs.r.ret_int, 1) ); - } -#endif } #ifdef HAVE_DOSISH_SYSTEM @@ -1301,11 +1277,7 @@ main( int argc, char **argv ) set_homedir (buf); } #endif -#ifdef USE_SHM_COPROCESSING - if( opt.shm_coprocess ) { - init_shm_coprocessing(requested_shm_size, 1 ); - } -#endif + /* Initialize the secure memory. */ gcry_control (GCRYCTL_INIT_SECMEM, 32768, 0); maybe_setuid = 0; @@ -1318,9 +1290,14 @@ main( int argc, char **argv ) if( default_config ) { - /* Try for a version specific config file first */ + /* Try for a version specific config file first but strip our + usual cvs suffix. That suffix indicates that it is not yet + the given version but we already want this config file. */ configname = make_filename(opt.homedir, "gpg" EXTSEP_S "conf-" SAFE_VERSION, NULL ); + if (!strcmp (configname + strlen (configname) - 4, "-cvs")) + configname[strlen (configname)-4] = 0; + if(access(configname,R_OK)) { xfree (configname); @@ -1458,7 +1435,6 @@ main( int argc, char **argv ) case oInteractive: opt.interactive = 1; break; case oVerbose: g10_opt_verbose++; opt.verbose++; opt.list_sigs=1; break; - case oKOption: set_cmd( &cmd, aKMode ); break; case oBatch: opt.batch = 1; nogreeting = 1; break; case oUseAgent: @@ -1631,17 +1607,6 @@ main( int argc, char **argv ) case oGnuPG: opt.compliance = CO_GNUPG; break; case oEmuMDEncodeBug: opt.emulate_bugs |= EMUBUG_MDENCODE; break; case oCompressSigs: opt.compress_sigs = 1; break; - case oRunAsShmCP: -#ifndef __riscos__ -# ifndef USE_SHM_COPROCESSING - /* not possible in the option file, - * but we print the warning here anyway */ - log_error("shared memory coprocessing is not available\n"); -# endif -#else /* __riscos__ */ - riscos_not_implemented("run-as-shm-coprocess"); -#endif /* __riscos__ */ - break; case oSetFilename: opt.set_filename = pargs.r.ret_str; break; case oForYourEyesOnly: eyes_only = 1; break; case oNoForYourEyesOnly: eyes_only = 0; break; @@ -2276,21 +2241,6 @@ main( int argc, char **argv ) set_cmd( &cmd, aListKeys); } - if( cmd == aKMode || cmd == aKModeC ) { /* kludge to be compatible to pgp */ - if( cmd == aKModeC ) { - opt.fingerprint = 1; - cmd = aKMode; - } - opt.list_sigs = 0; - if( opt.verbose > 2 ) - opt.check_sigs++; - if( opt.verbose > 1 ) - opt.list_sigs++; - - opt.verbose = opt.verbose > 1; - g10_opt_verbose = opt.verbose; - } - /* Compression algorithm 0 means no compression at all */ if( opt.def_compress_algo == 0) opt.compress = 0; @@ -2302,12 +2252,11 @@ main( int argc, char **argv ) if( opt.verbose > 1 ) set_packet_list_mode(1); - /* Add the keyrings, but not for some special commands and not in - case of "-kvv userid keyring". Also avoid adding the secret - keyring for a couple of commands to avoid unneeded access in - case the secrings are stored on a floppy */ - if( cmd != aDeArmor && cmd != aEnArmor - && !(cmd == aKMode && argc == 2 ) ) + /* Add the keyrings, but not for some special commands. Also + avoid adding the secret keyring for a couple of commands to + avoid unneeded access in case the secrings are stored on a + floppy */ + if( cmd != aDeArmor && cmd != aEnArmor ) { if (cmd != aCheckKeys && cmd != aListSigs && cmd != aListKeys && cmd != aVerify && cmd != aVerifyFiles @@ -2544,34 +2493,6 @@ main( int argc, char **argv ) free_strlist(sl); break; - case aKMode: /* list keyring -- NOTE: This will be removed soon */ - if( argc < 2 ) { /* -kv [userid] */ - sl = NULL; - if (argc && **argv) - add_to_strlist2( &sl, *argv, utf8_strings ); - public_key_list( sl ); - free_strlist(sl); - } - else if( argc == 2 ) { /* -kv userid keyring */ - if( access( argv[1], R_OK ) ) { - log_error(_("can't open %s: %s\n"), - print_fname_stdin(argv[1]), strerror(errno)); - } - else { - /* add keyring (default keyrings are not registered in this - * special case */ - keydb_add_resource( argv[1], 0, 0 ); - sl = NULL; - if (**argv) - add_to_strlist2( &sl, *argv, utf8_strings ); - public_key_list( sl ); - free_strlist(sl); - } - } - else - wrong_args(_("-k[v][v][v][c] [user-id] [keyring]") ); - break; - case aKeygen: /* generate a key */ if( opt.batch ) { if( argc > 1 ) diff --git a/g10/pkglue.c b/g10/pkglue.c index 7920a5223..015aaf9ff 100644 --- a/g10/pkglue.c +++ b/g10/pkglue.c @@ -287,8 +287,39 @@ pk_decrypt (int algo, gcry_mpi_t * result, gcry_mpi_t * data, } +/* Check whether SKEY is a suitable secret key. */ +int +pk_check_secret_key (int algo, gcry_mpi_t *skey) +{ + gcry_sexp_t s_skey; + int rc; + if (algo == GCRY_PK_DSA) + { + rc = gcry_sexp_build (&s_skey, NULL, + "(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))", + skey[0], skey[1], skey[2], skey[3], skey[4]); + } + else if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E) + { + rc = gcry_sexp_build (&s_skey, NULL, + "(private-key(elg(p%m)(g%m)(y%m)(x%m)))", + skey[0], skey[1], skey[2], skey[3]); + } + else if (algo == GCRY_PK_RSA) + { + rc = gcry_sexp_build (&s_skey, NULL, + "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))", + skey[0], skey[1], skey[2], skey[3], skey[4], + skey[5]); + } + else + return GPG_ERR_PUBKEY_ALGO; - - - + if (!rc) + { + rc = gcry_pk_testkey (s_skey); + gcry_sexp_release (s_skey); + } + return rc; +} diff --git a/g10/pkglue.h b/g10/pkglue.h index 3065d66aa..43b82785b 100644 --- a/g10/pkglue.h +++ b/g10/pkglue.h @@ -29,6 +29,7 @@ int pk_encrypt (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *pkey); int pk_decrypt (int algo, gcry_mpi_t *result, gcry_mpi_t *data, gcry_mpi_t *skey); +int pk_check_secret_key (int algo, gcry_mpi_t *skey); #endif /*GNUPG_G10_PKGLUE_H*/ diff --git a/g10/seckey-cert.c b/g10/seckey-cert.c index 5a7db4c97..5b0238240 100644 --- a/g10/seckey-cert.c +++ b/g10/seckey-cert.c @@ -215,14 +215,13 @@ do_check( PKT_secret_key *sk, const char *tryagain_text, int mode, return gpg_error (GPG_ERR_BAD_PASSPHRASE); } /* the checksum may fail, so we also check the key itself */ -#warning fixme - we need to reenable this -/* res = pubkey_check_secret_key( sk->pubkey_algo, sk->skey ); */ -/* if( res ) { */ -/* copy_secret_key( sk, save_sk ); */ -/* passphrase_clear_cache ( keyid, sk->pubkey_algo ); */ -/* free_secret_key( save_sk ); */ -/* return gpg_error (GPG_ERR_BAD_PASSPHRASE); */ -/* } */ + res = pk_check_secret_key (sk->pubkey_algo, sk->skey); + if (res) { + copy_secret_key( sk, save_sk ); + passphrase_clear_cache ( keyid, sk->pubkey_algo ); + free_secret_key( save_sk ); + return gpg_error (GPG_ERR_BAD_PASSPHRASE); + } free_secret_key( save_sk ); sk->is_protected = 0; } diff --git a/g10/status.c b/g10/status.c index 432ec575c..4414b33e9 100644 --- a/g10/status.c +++ b/g10/status.c @@ -1,5 +1,6 @@ /* status.c - * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000, 2001, 2002, + * 2003 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -25,21 +26,6 @@ #include #include #include -#ifdef USE_SHM_COPROCESSING -#ifdef USE_CAPABILITIES -#include -#endif -#ifdef HAVE_SYS_IPC_H -#include -#include -#endif -#ifdef HAVE_SYS_SHM_H -#include -#endif -#if defined(HAVE_MLOCK) -#include -#endif -#endif #include "gpg.h" #include "util.h" @@ -56,13 +42,6 @@ static FILE *statusfp; -#ifdef USE_SHM_COPROCESSING - static int shm_id = -1; - static volatile char *shm_area; - static size_t shm_size; - static int shm_is_locked; -#endif /*USE_SHM_COPROCESSING*/ - static void progress_cb (void *ctx, const char *what, int printchar, int current, int total) @@ -291,179 +270,6 @@ write_status_buffer ( int no, const char *buffer, size_t len, int wrap ) -#ifdef USE_SHM_COPROCESSING - -#ifndef IPC_RMID_DEFERRED_RELEASE -static void -remove_shmid( void ) -{ - if( shm_id != -1 ) { - shmctl ( shm_id, IPC_RMID, 0); - shm_id = -1; - } -} -#endif - -void -init_shm_coprocessing ( ulong requested_shm_size, int lock_mem ) -{ - char buf[100]; - struct shmid_ds shmds; - -#ifndef IPC_RMID_DEFERRED_RELEASE - atexit( remove_shmid ); -#endif - requested_shm_size = (requested_shm_size + 4095) & ~4095; - if ( requested_shm_size > 2 * 4096 ) - log_fatal("too much shared memory requested; only 8k are allowed\n"); - shm_size = 4096 /* one page for us */ + requested_shm_size; - - shm_id = shmget( IPC_PRIVATE, shm_size, IPC_CREAT | 0700 ); - if ( shm_id == -1 ) - log_fatal("can't get %uk of shared memory: %s\n", - (unsigned)shm_size/1024, strerror(errno)); - -#if !defined(IPC_HAVE_SHM_LOCK) \ - && defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK) - /* part of the old code which uses mlock */ - shm_area = shmat( shm_id, 0, 0 ); - if ( shm_area == (char*)-1 ) - log_fatal("can't attach %uk shared memory: %s\n", - (unsigned)shm_size/1024, strerror(errno)); - log_debug("mapped %uk shared memory at %p, id=%d\n", - (unsigned)shm_size/1024, shm_area, shm_id ); - if( lock_mem ) { -#ifdef USE_CAPABILITIES - cap_set_proc( cap_from_text("cap_ipc_lock+ep") ); -#endif - /* (need the cast for Solaris with Sun's workshop compilers) */ - if ( mlock ( (char*)shm_area, shm_size) ) - log_info("locking shared memory %d failed: %s\n", - shm_id, strerror(errno)); - else - shm_is_locked = 1; -#ifdef USE_CAPABILITIES - cap_set_proc( cap_from_text("cap_ipc_lock+p") ); -#endif - } - -#ifdef IPC_RMID_DEFERRED_RELEASE - if( shmctl( shm_id, IPC_RMID, 0) ) - log_fatal("shmctl IPC_RMDID of %d failed: %s\n", - shm_id, strerror(errno)); -#endif - - if( shmctl( shm_id, IPC_STAT, &shmds ) ) - log_fatal("shmctl IPC_STAT of %d failed: %s\n", - shm_id, strerror(errno)); - if( shmds.shm_perm.uid != getuid() ) { - shmds.shm_perm.uid = getuid(); - if( shmctl( shm_id, IPC_SET, &shmds ) ) - log_fatal("shmctl IPC_SET of %d failed: %s\n", - shm_id, strerror(errno)); - } - -#else /* this is the new code which handles the changes in the SHM - * semantics introduced with Linux 2.4. The changes is that we - * now change the permissions and then attach to the memory. - */ - - if( lock_mem ) { -#ifdef USE_CAPABILITIES - cap_set_proc( cap_from_text("cap_ipc_lock+ep") ); -#endif -#ifdef IPC_HAVE_SHM_LOCK - if ( shmctl (shm_id, SHM_LOCK, 0) ) - log_info("locking shared memory %d failed: %s\n", - shm_id, strerror(errno)); - else - shm_is_locked = 1; -#else - log_info("Locking shared memory %d failed: No way to do it\n", shm_id ); -#endif -#ifdef USE_CAPABILITIES - cap_set_proc( cap_from_text("cap_ipc_lock+p") ); -#endif - } - - if( shmctl( shm_id, IPC_STAT, &shmds ) ) - log_fatal("shmctl IPC_STAT of %d failed: %s\n", - shm_id, strerror(errno)); - if( shmds.shm_perm.uid != getuid() ) { - shmds.shm_perm.uid = getuid(); - if( shmctl( shm_id, IPC_SET, &shmds ) ) - log_fatal("shmctl IPC_SET of %d failed: %s\n", - shm_id, strerror(errno)); - } - - shm_area = shmat( shm_id, 0, 0 ); - if ( shm_area == (char*)-1 ) - log_fatal("can't attach %uk shared memory: %s\n", - (unsigned)shm_size/1024, strerror(errno)); - log_debug("mapped %uk shared memory at %p, id=%d\n", - (unsigned)shm_size/1024, shm_area, shm_id ); - -#ifdef IPC_RMID_DEFERRED_RELEASE - if( shmctl( shm_id, IPC_RMID, 0) ) - log_fatal("shmctl IPC_RMDID of %d failed: %s\n", - shm_id, strerror(errno)); -#endif - -#endif - /* write info; Protocol version, id, size, locked size */ - sprintf( buf, "pv=1 pid=%d shmid=%d sz=%u lz=%u", (int)getpid(), - shm_id, (unsigned)shm_size, shm_is_locked? (unsigned)shm_size:0 ); - write_status_text( STATUS_SHM_INFO, buf ); -} - -/**************** - * Request a string from client - * If bool, returns static string on true (do not free) or NULL for false - */ -static char * -do_shm_get( const char *keyword, int hidden, int bool ) -{ - size_t n; - byte *p; - char *string; - - if( !shm_area ) - BUG(); - - shm_area[0] = 0; /* msb of length of control block */ - shm_area[1] = 32; /* and lsb */ - shm_area[2] = 1; /* indicate that we are waiting on a reply */ - shm_area[3] = 0; /* clear data available flag */ - - write_status_text( bool? STATUS_SHM_GET_BOOL : - hidden? STATUS_SHM_GET_HIDDEN : STATUS_SHM_GET, keyword ); - - do { - pause_on_sigusr(1); - if( shm_area[0] || shm_area[1] != 32 || shm_area[2] != 1 ) - log_fatal("client modified shm control block - abort\n"); - } while( !shm_area[3] ); - shm_area[2] = 0; /* reset request flag */ - p = (byte*)shm_area+32; - n = p[0] << 8 | p[1]; - p += 2; - if( n+32+2+1 > 4095 ) - log_fatal("client returns too large data (%u bytes)\n", (unsigned)n ); - - if( bool ) - return p[0]? "" : NULL; - - string = hidden? xmalloc_secure ( n+1 ) : xmalloc ( n+1 ); - memcpy(string, p, n ); - string[n] = 0; /* make sure it is a string */ - if( hidden ) /* invalidate the memory */ - memset( p, 0, n ); - - return string; -} - -#endif /* USE_SHM_COPROCESSING */ - static int myread(int fd, void *buf, size_t count) { @@ -541,10 +347,6 @@ cpr_enabled() { if( opt.command_fd != -1 ) return 1; -#ifdef USE_SHM_COPROCESSING - if( opt.shm_coprocess ) - return 1; -#endif return 0; } @@ -555,10 +357,6 @@ cpr_get_no_help( const char *keyword, const char *prompt ) if( opt.command_fd != -1 ) return do_get_from_fd ( keyword, 0, 0 ); -#ifdef USE_SHM_COPROCESSING - if( opt.shm_coprocess ) - return do_shm_get( keyword, 0, 0 ); -#endif for(;;) { p = tty_get( prompt ); return p; @@ -572,10 +370,6 @@ cpr_get( const char *keyword, const char *prompt ) if( opt.command_fd != -1 ) return do_get_from_fd ( keyword, 0, 0 ); -#ifdef USE_SHM_COPROCESSING - if( opt.shm_coprocess ) - return do_shm_get( keyword, 0, 0 ); -#endif for(;;) { p = tty_get( prompt ); if( *p=='?' && !p[1] && !(keyword && !*keyword)) { @@ -608,10 +402,6 @@ cpr_get_hidden( const char *keyword, const char *prompt ) if( opt.command_fd != -1 ) return do_get_from_fd ( keyword, 1, 0 ); -#ifdef USE_SHM_COPROCESSING - if( opt.shm_coprocess ) - return do_shm_get( keyword, 1, 0 ); -#endif for(;;) { p = tty_get_hidden( prompt ); if( *p == '?' && !p[1] ) { @@ -628,10 +418,6 @@ cpr_kill_prompt(void) { if( opt.command_fd != -1 ) return; -#ifdef USE_SHM_COPROCESSING - if( opt.shm_coprocess ) - return; -#endif tty_kill_prompt(); return; } @@ -644,10 +430,6 @@ cpr_get_answer_is_yes( const char *keyword, const char *prompt ) if( opt.command_fd != -1 ) return !!do_get_from_fd ( keyword, 0, 1 ); -#ifdef USE_SHM_COPROCESSING - if( opt.shm_coprocess ) - return !!do_shm_get( keyword, 0, 1 ); -#endif for(;;) { p = tty_get( prompt ); trim_spaces(p); /* it is okay to do this here */ @@ -672,10 +454,6 @@ cpr_get_answer_yes_no_quit( const char *keyword, const char *prompt ) if( opt.command_fd != -1 ) return !!do_get_from_fd ( keyword, 0, 1 ); -#ifdef USE_SHM_COPROCESSING - if( opt.shm_coprocess ) - return !!do_shm_get( keyword, 0, 1 ); -#endif for(;;) { p = tty_get( prompt ); trim_spaces(p); /* it is okay to do this here */ diff --git a/g10/status.h b/g10/status.h index 44a7d6d32..4a0bcd45b 100644 --- a/g10/status.h +++ b/g10/status.h @@ -110,10 +110,6 @@ void write_status_buffer ( int no, void write_status_text_and_buffer ( int no, const char *text, const char *buffer, size_t len, int wrap ); -#ifdef USE_SHM_COPROCESSING - void init_shm_coprocessing ( ulong requested_shm_size, int lock_mem ); -#endif /*USE_SHM_COPROCESSING*/ - int cpr_enabled(void); char *cpr_get( const char *keyword, const char *prompt ); char *cpr_get_no_help( const char *keyword, const char *prompt ); diff --git a/scd/ChangeLog b/scd/ChangeLog index ad4b0518c..ae2e6ce6e 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,25 @@ +2003-08-05 Werner Koch + + * app-openpgp.c (dump_all_do): Don't analyze constructed DOs after + an error. + +2003-08-04 Werner Koch + + * app.c (app_set_default_reader_port): New. + (select_application): Use it here. + * scdaemon.c (main): and here. + * sc-copykeys.c: --reader-port does now take a string. + * sc-investigate.c, scdaemon.c: Ditto. + * apdu.c (apdu_open_reader): Ditto. Load pcsclite if no ctapi + driver is configured. Always include code for ctapi. + (new_reader_slot): Don't test for already used ports and remove + port arg. + (open_pcsc_reader, pcsc_send_apdu, pcsc_error_string): New. + (apdu_send_le): Changed RC to long to cope with PC/SC. + + * scdaemon.c, scdaemon.h: New option --ctapi-driver. + * sc-investigate.c, sc-copykeys.c: Ditto. + 2003-07-31 Werner Koch * Makefile.am (scdaemon_LDADD): Added INTLLIBS. diff --git a/scd/apdu.c b/scd/apdu.c index 6fec584b9..60de5b953 100644 --- a/scd/apdu.c +++ b/scd/apdu.c @@ -29,8 +29,6 @@ #include "scdaemon.h" #include "apdu.h" -#define HAVE_CTAPI 1 - #define MAX_READER 4 /* Number of readers we support concurrently. */ #define CARD_CONNECT_TIMEOUT 1 /* Number of seconds to wait for insertion of the card (1 = don't wait). */ @@ -40,7 +38,13 @@ /* A global table to keep track of active readers. */ static struct { int used; /* True if slot is used. */ - unsigned short port; /* port number0 = unused, 1 - dev/tty */ + unsigned short port; /* Port number: 0 = unused, 1 - dev/tty */ + int is_ctapi; /* This is a ctAPI driver. */ + struct { + unsigned long context; + unsigned long card; + unsigned long protocol; + } pcsc; int status; unsigned char atr[33]; size_t atrlen; @@ -55,6 +59,61 @@ static char (*CT_data) (unsigned short ctn, unsigned char *dad, unsigned char *rsp); static char (*CT_close) (unsigned short ctn); +/* PC/SC constants and function pointer. */ +#define PCSC_SCOPE_USER 0 +#define PCSC_SCOPE_TERMINAL 1 +#define PCSC_SCOPE_SYSTEM 2 +#define PCSC_SCOPE_GLOBAL 3 + +#define PCSC_PROTOCOL_T0 1 +#define PCSC_PROTOCOL_T1 2 +#define PCSC_PROTOCOL_RAW 4 + +#define PCSC_SHARE_EXCLUSIVE 1 +#define PCSC_SHARE_SHARED 2 +#define PCSC_SHARE_DIRECT 3 + +#define PCSC_LEAVE_CARD 0 +#define PCSC_RESET_CARD 1 +#define PCSC_UNPOWER_CARD 2 +#define PCSC_EJECT_CARD 3 + +struct pcsc_io_request_s { + unsigned long protocol; + unsigned long pci_len; +}; + +typedef struct pcsc_io_request_s *pcsc_io_request_t; + +long (*pcsc_establish_context) (unsigned long scope, + const void *reserved1, + const void *reserved2, + unsigned long *r_context); +long (*pcsc_release_context) (unsigned long context); +long (*pcsc_list_readers) (unsigned long context, const char *groups, + char *readers, unsigned long *readerslen); +long (*pcsc_connect) (unsigned long context, + const char *reader, + unsigned long share_mode, + unsigned long preferred_protocols, + unsigned long *r_card, + unsigned long *r_active_protocol); +long (*pcsc_disconnect) (unsigned long card, unsigned long disposition); +long (*pcsc_status) (unsigned long card, + char *reader, unsigned long *readerlen, + unsigned long *r_state, unsigned long *r_protocol, + unsigned char *atr, unsigned long *atrlen); +long (*pcsc_begin_transaction) (unsigned long card); +long (*pcsc_end_transaction) (unsigned long card); +long (*pcsc_transmit) (unsigned long card, + const pcsc_io_request_t send_pci, + const unsigned char *send_buffer, + unsigned long send_len, + pcsc_io_request_t recv_pci, + unsigned char *recv_buffer, + unsigned long *recv_len); +long (*pcsc_set_timeout) (unsigned long context, unsigned long timeout); + @@ -64,28 +123,16 @@ static char (*CT_close) (unsigned short ctn); */ -/* Find an unused reader slot for PORT and put it into the reader +/* Find an unused reader slot for PORTSTR and put it into the reader table. Return -1 on error or the index into the reader table. */ static int -new_reader_slot (int port) +new_reader_slot (void) { int i, reader = -1; - if (port < 0 || port > 0xffff) - { - log_error ("new_reader_slot: invalid port %d requested\n", port); - return -1; - } - for (i=0; i < MAX_READER; i++) { - if (reader_table[i].used && reader_table[i].port == port) - { - log_error ("new_reader_slot: requested port %d already in use\n", - reader); - return -1; - } - else if (!reader_table[i].used && reader == -1) + if (!reader_table[i].used && reader == -1) reader = i; } if (reader == -1) @@ -94,7 +141,7 @@ new_reader_slot (int port) return -1; } reader_table[reader].used = 1; - reader_table[reader].port = port; + reader_table[reader].is_ctapi = 0; return reader; } @@ -102,11 +149,25 @@ new_reader_slot (int port) static void dump_reader_status (int reader) { - log_info ("reader %d: %s\n", reader, - reader_table[reader].status == 1? "Processor ICC present" : - reader_table[reader].status == 0? "Memory ICC present" : - "ICC not present" ); - + if (reader_table[reader].is_ctapi) + { + log_info ("reader slot %d: %s\n", reader, + reader_table[reader].status == 1? "Processor ICC present" : + reader_table[reader].status == 0? "Memory ICC present" : + "ICC not present" ); + } + else + { + log_info ("reader slot %d: active protocol:", reader); + if ((reader_table[reader].pcsc.protocol & PCSC_PROTOCOL_T0)) + log_printf (" T0"); + else if ((reader_table[reader].pcsc.protocol & PCSC_PROTOCOL_T1)) + log_printf (" T1"); + else if ((reader_table[reader].pcsc.protocol & PCSC_PROTOCOL_RAW)) + log_printf (" raw"); + log_printf ("\n"); + } + if (reader_table[reader].status != -1) { log_info ("reader %d: ATR=", reader); @@ -117,13 +178,12 @@ dump_reader_status (int reader) -#ifdef HAVE_CTAPI /* ct API Interface */ static const char * -ct_error_string (int err) +ct_error_string (long err) { switch (err) { @@ -150,7 +210,7 @@ ct_activate_card (int reader) unsigned short buflen; if (count) - sleep (1); /* FIXME: we should use a more reliable timer. */ + ; /* FIXME: we should use a more reliable timer than sleep. */ /* Check whether card has been inserted. */ dad[0] = 1; /* Destination address: CT. */ @@ -221,9 +281,15 @@ open_ct_reader (int port) { int rc, reader; - reader = new_reader_slot (port); + if (port < 0 || port > 0xffff) + { + log_error ("open_ct_reader: invalid port %d requested\n", port); + return -1; + } + reader = new_reader_slot (); if (reader == -1) return reader; + reader_table[reader].port = port; rc = CT_init (reader, (unsigned short)port); if (rc) @@ -241,6 +307,7 @@ open_ct_reader (int port) return -1; } + reader_table[reader].is_ctapi = 1; dump_reader_status (reader); return reader; } @@ -271,16 +338,205 @@ ct_send_apdu (int slot, unsigned char *apdu, size_t apdulen, } -#endif /*HAVE_CTAPI*/ - -#ifdef HAVE_PCSC +static const char * +pcsc_error_string (long err) +{ + const char *s; + + if (!err) + return "okay"; + if ((err & 0x80100000) != 0x80100000) + return "invalid PC/SC error code"; + err &= 0xffff; + switch (err) + { + case 0x0002: s = "cancelled"; break; + case 0x000e: s = "can't dispose"; break; + case 0x0008: s = "insufficient buffer"; break; + case 0x0015: s = "invalid ATR"; break; + case 0x0003: s = "invalid handle"; break; + case 0x0004: s = "invalid parameter"; break; + case 0x0005: s = "invalid target"; break; + case 0x0011: s = "invalid value"; break; + case 0x0006: s = "no memory"; break; + case 0x0013: s = "comm error"; break; + case 0x0001: s = "internal error"; break; + case 0x0014: s = "unknown error"; break; + case 0x0007: s = "waited too long"; break; + case 0x0009: s = "unknown reader"; break; + case 0x000a: s = "timeout"; break; + case 0x000b: s = "sharing violation"; break; + case 0x000c: s = "no smartcard"; break; + case 0x000d: s = "unknown card"; break; + case 0x000f: s = "proto mismatch"; break; + case 0x0010: s = "not ready"; break; + case 0x0012: s = "system cancelled"; break; + case 0x0016: s = "not transacted"; break; + case 0x0017: s = "reader unavailable"; break; + case 0x0065: s = "unsupported card"; break; + case 0x0066: s = "unresponsive card"; break; + case 0x0067: s = "unpowered card"; break; + case 0x0068: s = "reset card"; break; + case 0x0069: s = "removed card"; break; + case 0x006a: s = "inserted card"; break; + case 0x001f: s = "unsupported feature"; break; + case 0x0019: s = "PCI too small"; break; + case 0x001a: s = "reader unsupported"; break; + case 0x001b: s = "duplicate reader"; break; + case 0x001c: s = "card unsupported"; break; + case 0x001d: s = "no service"; break; + case 0x001e: s = "service stopped"; break; + default: s = "unknown PC/SC error code"; break; + } + return s; +} + /* PC/SC Interface */ +static int +open_pcsc_reader (const char *portstr) +{ + long err; + int slot; + char *list = NULL; + unsigned long nreader, listlen, atrlen; + char *p; + unsigned long card_state, card_protocol; + + slot = new_reader_slot (); + if (slot == -1) + return -1; + + err = pcsc_establish_context (PCSC_SCOPE_SYSTEM, NULL, NULL, + &reader_table[slot].pcsc.context); + if (err) + { + log_error ("pcsc_establish_context failed: %s (0x%lx)\n", + pcsc_error_string (err), err); + reader_table[slot].used = 0; + return -1; + } + + err = pcsc_list_readers (reader_table[slot].pcsc.context, + NULL, NULL, &nreader); + if (!err) + { + list = xtrymalloc (nreader+1); /* Better add 1 for safety reasons. */ + if (!list) + { + log_error ("error allocating memory for reader list\n"); + pcsc_release_context (reader_table[slot].pcsc.context); + reader_table[slot].used = 0; + return -1; + } + err = pcsc_list_readers (reader_table[slot].pcsc.context, + NULL, list, &nreader); + } + if (err) + { + log_error ("pcsc_list_readers failed: %s (0x%lx)\n", + pcsc_error_string (err), err); + pcsc_release_context (reader_table[slot].pcsc.context); + reader_table[slot].used = 0; + xfree (list); + return -1; + } + + listlen = nreader; + p = list; + while (nreader) + { + if (!*p && !p[1]) + break; + log_info ("detected reader `%s'\n", p); + if (nreader < (strlen (p)+1)) + { + log_error ("invalid response from pcsc_list_readers\n"); + break; + } + nreader -= strlen (p)+1; + p += strlen (p) + 1; + } + + err = pcsc_connect (reader_table[slot].pcsc.context, + portstr? portstr : list, + PCSC_SHARE_EXCLUSIVE, + PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1, + &reader_table[slot].pcsc.card, + &reader_table[slot].pcsc.protocol); + if (err) + { + log_error ("pcsc_connect failed: %s (0x%lx)\n", + pcsc_error_string (err), err); + pcsc_release_context (reader_table[slot].pcsc.context); + reader_table[slot].used = 0; + xfree (list); + return -1; + } + + atrlen = 32; + /* (We need to pass a dummy buffer. We use LIST because it ought to + be large enough.) */ + err = pcsc_status (reader_table[slot].pcsc.card, + list, &listlen, + &card_state, &card_protocol, + reader_table[slot].atr, &atrlen); + xfree (list); + if (err) + { + log_error ("pcsc_status failed: %s (0x%lx)\n", + pcsc_error_string (err), err); + pcsc_release_context (reader_table[slot].pcsc.context); + reader_table[slot].used = 0; + return -1; + } + if (atrlen >= DIM (reader_table[0].atr)) + log_bug ("ATR returned by pcsc_status is too large\n"); + reader_table[slot].atrlen = atrlen; +/* log_debug ("state from pcsc_status: 0x%lx\n", card_state); */ +/* log_debug ("protocol from pcsc_status: 0x%lx\n", card_protocol); */ + + dump_reader_status (slot); + return slot; +} + + +/* Actually send the APDU of length APDULEN to SLOT and return a + maximum of *BUFLEN data in BUFFER, the actual returned size will be + set to BUFLEN. Returns: CT API error code. */ +static int +pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen, + unsigned char *buffer, size_t *buflen) +{ + long err; + struct pcsc_io_request_s send_pci; + unsigned long recv_len; + + if (DBG_CARD_IO) + log_printhex (" CT_data:", apdu, apdulen); + + if ((reader_table[slot].pcsc.protocol & PCSC_PROTOCOL_T1)) + send_pci.protocol = PCSC_PROTOCOL_T1; + else + send_pci.protocol = PCSC_PROTOCOL_T0; + send_pci.pci_len = sizeof send_pci; + recv_len = *buflen; + err = pcsc_transmit (reader_table[slot].pcsc.card, + &send_pci, apdu, apdulen, + NULL, buffer, &recv_len); + *buflen = recv_len; + if (err) + log_error ("pcsc_transmit failed: %s (0x%lx)\n", + pcsc_error_string (err), err); + + return err? -1:0; +} + + -#endif /*HAVE_PCSC*/ /* @@ -288,35 +544,86 @@ ct_send_apdu (int slot, unsigned char *apdu, size_t apdulen, */ /* Open the reader and return an internal slot number or -1 on - error. */ + error. If PORTSTR is NULL we default to a suitable port (for ctAPI: + the first USB reader. For PCSC/ the first listed reader. */ int -apdu_open_reader (int port) +apdu_open_reader (const char *portstr) { - static int ct_api_loaded; + static int pcsc_api_loaded, ct_api_loaded; + + if (opt.ctapi_driver && *opt.ctapi_driver) + { + int port = portstr? atoi (portstr) : 32768; + + if (!ct_api_loaded) + { + void *handle; + + handle = dlopen (opt.ctapi_driver, RTLD_LAZY); + if (!handle) + { + log_error ("apdu_open_reader: failed to open driver: %s", + dlerror ()); + return -1; + } + CT_init = dlsym (handle, "CT_init"); + CT_data = dlsym (handle, "CT_data"); + CT_close = dlsym (handle, "CT_close"); + if (!CT_init || !CT_data || !CT_close) + { + log_error ("apdu_open_reader: invalid ctAPI driver\n"); + dlclose (handle); + return -1; + } + ct_api_loaded = 1; + } + return open_ct_reader (port); + } - if (!ct_api_loaded) + + /* No ctAPI configured, so lets try the PC/SC API */ + if (!pcsc_api_loaded) { void *handle; - handle = dlopen ("libtowitoko.so", RTLD_LAZY); + handle = dlopen ("libpcsclite.so", RTLD_LAZY); if (!handle) { log_error ("apdu_open_reader: failed to open driver: %s", dlerror ()); return -1; } - CT_init = dlsym (handle, "CT_init"); - CT_data = dlsym (handle, "CT_data"); - CT_close = dlsym (handle, "CT_close"); - if (!CT_init || !CT_data || !CT_close) + + pcsc_establish_context = dlsym (handle, "SCardEstablishContext"); + pcsc_release_context = dlsym (handle, "SCardReleaseContext"); + pcsc_list_readers = dlsym (handle, "SCardListReaders"); + pcsc_connect = dlsym (handle, "SCardConnect"); + pcsc_disconnect = dlsym (handle, "SCardDisconnect"); + pcsc_status = dlsym (handle, "SCardStatus"); + pcsc_begin_transaction = dlsym (handle, "SCardBeginTransaction"); + pcsc_end_transaction = dlsym (handle, "SCardEndTransaction"); + pcsc_transmit = dlsym (handle, "SCardTransmit"); + pcsc_set_timeout = dlsym (handle, "SCardSetTimeout"); + + if (!pcsc_establish_context + || !pcsc_release_context + || !pcsc_list_readers + || !pcsc_connect + || !pcsc_disconnect + || !pcsc_status + || !pcsc_begin_transaction + || !pcsc_end_transaction + || !pcsc_transmit + || !pcsc_set_timeout) { - log_error ("apdu_open_reader: invalid driver\n"); + log_error ("apdu_open_reader: invalid PC/SC driver\n"); dlclose (handle); return -1; } - ct_api_loaded = 1; + pcsc_api_loaded = 1; } - return open_ct_reader (port); + + return open_pcsc_reader (portstr); } @@ -338,15 +645,14 @@ apdu_get_atr (int slot, size_t *atrlen) static const char * -error_string (int slot, int rc) +error_string (int slot, long rc) { -#ifdef HAVE_CTAPI - return ct_error_string (rc); -#elif defined(HAVE_PCSC) - return "?"; -#else - return "?"; -#endif + if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used ) + return "[invalid slot]"; + if (reader_table[slot].is_ctapi) + return ct_error_string (rc); + else + return pcsc_error_string (rc); } @@ -355,13 +661,12 @@ static int send_apdu (int slot, unsigned char *apdu, size_t apdulen, unsigned char *buffer, size_t *buflen) { -#ifdef HAVE_CTAPI - return ct_send_apdu (slot, apdu, apdulen, buffer, buflen); -#elif defined(HAVE_PCSC) - return SW_HOST_NO_DRIVER; -#else - return SW_HOST_NO_DRIVER; -#endif + if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used ) + return SW_HOST_NO_DRIVER; + if (reader_table[slot].is_ctapi) + return ct_send_apdu (slot, apdu, apdulen, buffer, buflen); + else + return pcsc_send_apdu (slot, apdu, apdulen, buffer, buflen); } /* Send an APDU to the card in SLOT. The APDU is created from all @@ -382,7 +687,8 @@ apdu_send_le(int slot, int class, int ins, int p0, int p1, size_t resultlen = 256; unsigned char apdu[5+256+1]; size_t apdulen; - int rc, sw; + int sw; + long rc; /* we need a long here due to PC/SC. */ if (DBG_CARD_IO) log_debug ("send apdu: c=%02X i=%02X p0=%02X p1=%02X lc=%d le=%d\n", diff --git a/scd/apdu.h b/scd/apdu.h index 44166a3fe..6e4244ba0 100644 --- a/scd/apdu.h +++ b/scd/apdu.h @@ -47,12 +47,13 @@ enum { between errnos on a failed malloc. */ SW_HOST_INV_VALUE = 0x10002, SW_HOST_INCOMPLETE_CARD_RESPONSE = 0x10003, + SW_HOST_NO_DRIVER = 0x10004 }; /* Note , that apdu_open_reader returns no status word but -1 on error. */ -int apdu_open_reader (int port); +int apdu_open_reader (const char *portstr); unsigned char *apdu_get_atr (int slot, size_t *atrlen); diff --git a/scd/app-common.h b/scd/app-common.h index 282f82715..1243ca3ec 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -69,6 +69,7 @@ struct app_ctx_s { }; /*-- app.c --*/ +void app_set_default_reader_port (const char *portstr); APP select_application (void); int app_get_serial_and_stamp (APP app, char **serial, time_t *stamp); int app_write_learn_status (APP app, CTRL ctrl); diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 09a19699d..7f6114292 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -214,71 +214,6 @@ get_one_do (int slot, int tag, unsigned char **result, size_t *nbytes) return NULL; } -#if 0 /* not used */ -static void -dump_one_do (int slot, int tag) -{ - int rc, i; - unsigned char *buffer; - size_t buflen; - const char *desc; - int binary; - const unsigned char *value; - size_t valuelen; - - for (i=0; data_objects[i].tag && data_objects[i].tag != tag; i++) - ; - desc = data_objects[i].tag? data_objects[i].desc : "?"; - binary = data_objects[i].tag? data_objects[i].binary : 1; - - value = NULL; - rc = -1; - if (data_objects[i].tag && data_objects[i].get_from) - { - rc = iso7816_get_data (slot, data_objects[i].get_from, - &buffer, &buflen); - if (!rc) - { - value = find_tlv (buffer, buflen, tag, &valuelen, 0); - if (!value) - ; /* not found */ - else if (valuelen > buflen - (value - buffer)) - { - log_error ("warning: constructed DO too short\n"); - value = NULL; - xfree (buffer); buffer = NULL; - } - } - } - - if (!value) /* Not in a constructed DO, try simple. */ - { - rc = iso7816_get_data (slot, tag, &buffer, &buflen); - if (!rc) - { - value = buffer; - valuelen = buflen; - } - } - if (rc == 0x6a88) - log_info ("DO `%s' not available\n", desc); - else if (rc) - log_info ("DO `%s' not available (rc=%04X)\n", desc, rc); - else - { - if (binary) - { - log_info ("DO `%s': ", desc); - log_printhex ("", value, valuelen); - } - else - log_info ("DO `%s': `%.*s'\n", - desc, (int)valuelen, value); /* FIXME: sanitize */ - xfree (buffer); - } -} -#endif /*not used*/ - static void dump_all_do (int slot) @@ -293,11 +228,11 @@ dump_all_do (int slot) continue; rc = iso7816_get_data (slot, data_objects[i].tag, &buffer, &buflen); - if (rc == 0x6a88) + if (gpg_error (rc) == GPG_ERR_NO_OBJ) ; else if (rc) - log_info ("DO `%s' not available (rc=%04X)\n", - data_objects[i].desc, rc); + log_info ("DO `%s' not available: %s\n", + data_objects[i].desc, gpg_strerror (rc)); else { if (data_objects[i].binary) @@ -309,34 +244,34 @@ dump_all_do (int slot) log_info ("DO `%s': `%.*s'\n", data_objects[i].desc, (int)buflen, buffer); /* FIXME: sanitize */ - } - if (data_objects[i].constructed) - { - for (j=0; data_objects[j].tag; j++) + if (data_objects[i].constructed) { - const unsigned char *value; - size_t valuelen; - - if (j==i || data_objects[i].tag != data_objects[j].get_from) - continue; - value = find_tlv (buffer, buflen, - data_objects[j].tag, &valuelen, 0); - if (!value) - ; /* not found */ - else if (valuelen > buflen - (value - buffer)) - log_error ("warning: constructed DO too short\n"); - else + for (j=0; data_objects[j].tag; j++) { - if (data_objects[j].binary) + const unsigned char *value; + size_t valuelen; + + if (j==i || data_objects[i].tag != data_objects[j].get_from) + continue; + value = find_tlv (buffer, buflen, + data_objects[j].tag, &valuelen, 0); + if (!value) + ; /* not found */ + else if (valuelen > buflen - (value - buffer)) + log_error ("warning: constructed DO too short\n"); + else { - log_info ("DO `%s': ", data_objects[j].desc); - log_printhex ("", value, valuelen); + if (data_objects[j].binary) + { + log_info ("DO `%s': ", data_objects[j].desc); + log_printhex ("", value, valuelen); + } + else + log_info ("DO `%s': `%.*s'\n", + data_objects[j].desc, + (int)valuelen, value); /* FIXME: sanitize */ } - else - log_info ("DO `%s': `%.*s'\n", - data_objects[j].desc, - (int)valuelen, value); /* FIXME: sanitize */ } } } @@ -410,7 +345,7 @@ store_fpr (int slot, int keynumber, u32 timestamp, rc = iso7816_put_data (slot, (card_version > 0x0007? 0xC7 : 0xC6) + keynumber, fpr, 20); if (rc) - log_error ("failed to store the fingerprint: rc=%04X\n", rc); + log_error ("failed to store the fingerprint: %s\n",gpg_strerror (rc)); return rc; } @@ -582,7 +517,7 @@ do_setattr (APP app, const char *name, xfree (pinvalue); if (rc) { - log_error ("verify CHV3 failed\n"); + log_error ("verify CHV3 failed: %s\n", gpg_strerror (rc)); rc = gpg_error (GPG_ERR_GENERAL); return rc; } @@ -626,7 +561,7 @@ do_change_pin (APP app, CTRL ctrl, const char *chvnostr, int reset_mode, xfree (pinvalue); if (rc) { - log_error ("verify CHV3 failed: rc=%04X\n", rc); + log_error ("verify CHV3 failed: rc=%s\n", gpg_strerror (rc)); goto leave; } } @@ -642,7 +577,7 @@ do_change_pin (APP app, CTRL ctrl, const char *chvnostr, int reset_mode, xfree (pinvalue); if (rc) { - log_error ("verify CHV1 failed: rc=%04X\n", rc); + log_error ("verify CHV1 failed: rc=%s\n", gpg_strerror (rc)); goto leave; } } @@ -658,7 +593,7 @@ do_change_pin (APP app, CTRL ctrl, const char *chvnostr, int reset_mode, xfree (pinvalue); if (rc) { - log_error ("verify CHV2 failed: rc=%04X\n", rc); + log_error ("verify CHV2 failed: rc=%s\n", gpg_strerror (rc)); goto leave; } } @@ -757,7 +692,7 @@ do_genkey (APP app, CTRL ctrl, const char *keynostr, unsigned int flags, } if (rc) { - log_error ("verify CHV3 failed: rc=%04X\n", rc); + log_error ("verify CHV3 failed: rc=%s\n", gpg_strerror (rc)); goto leave; } @@ -1224,8 +1159,6 @@ app_select_openpgp (APP app, unsigned char **sn, size_t *snlen) rc = iso7816_select_application (slot, aid, sizeof aid); if (!rc) { - /* fixme: get the full AID and check that the version is okay - with us. */ rc = iso7816_get_data (slot, 0x004F, &buffer, &buflen); if (rc) goto leave; @@ -1386,7 +1319,7 @@ app_openpgp_storekey (APP app, int keyno, } if (rc) { - log_error ("verify CHV3 failed: rc=%04X\n", rc); + log_error ("verify CHV3 failed: rc=%s\n", gpg_strerror (rc)); goto leave; } @@ -1395,7 +1328,7 @@ app_openpgp_storekey (APP app, int keyno, template, template_len); if (rc) { - log_error ("failed to store the key: rc=%04X\n", rc); + log_error ("failed to store the key: rc=%s\n", gpg_strerror (rc)); rc = gpg_error (GPG_ERR_CARD); goto leave; } diff --git a/scd/app.c b/scd/app.c index 7a85df336..04b421b55 100644 --- a/scd/app.c +++ b/scd/app.c @@ -30,17 +30,26 @@ #include "apdu.h" #include "iso7816.h" +static char *default_reader_port; + +void +app_set_default_reader_port (const char *portstr) +{ + xfree (default_reader_port); + default_reader_port = portstr? xstrdup (portstr): NULL; +} + + /* The select the best fitting application and return a context. Returns NULL if no application was found or no card is present. */ APP select_application (void) { - int reader_port = 32768; /* First USB reader. */ int slot; int rc; APP app; - slot = apdu_open_reader (reader_port); + slot = apdu_open_reader (default_reader_port); if (slot == -1) { log_error ("card reader not available\n"); diff --git a/scd/sc-copykeys.c b/scd/sc-copykeys.c index 9caf39a8a..b56b88590 100644 --- a/scd/sc-copykeys.c +++ b/scd/sc-copykeys.c @@ -44,6 +44,7 @@ enum cmd_and_opt_values { oVerbose = 'v', oReaderPort = 500, + octapiDriver, oDebug, oDebugAll, @@ -55,7 +56,8 @@ static ARGPARSE_OPTS opts[] = { { 301, NULL, 0, "@Options:\n " }, { oVerbose, "verbose", 0, "verbose" }, - { oReaderPort, "reader-port", 1, "|N|connect to reader at port N"}, + { oReaderPort, "reader-port", 2, "|N|connect to reader at port N"}, + { octapiDriver, "ctapi-driver", 2, "NAME|use NAME as ctAPI driver"}, { oDebug, "debug" ,4|16, "set debugging flags"}, { oDebugAll, "debug-all" ,0, "enable full debugging"}, {0} @@ -115,7 +117,7 @@ main (int argc, char **argv ) { ARGPARSE_ARGS pargs; int slot, rc; - int reader_port = 32768; /* First USB reader. */ + const char *reader_port = NULL; struct app_ctx_s appbuf; memset (&appbuf, 0, sizeof appbuf); @@ -146,6 +148,8 @@ main (int argc, char **argv ) case oVerbose: opt.verbose++; break; case oDebug: opt.debug |= pargs.r.ret_ulong; break; case oDebugAll: opt.debug = ~0; break; + case oReaderPort: reader_port = pargs.r.ret_str; break; + case octapiDriver: opt.ctapi_driver = pargs.r.ret_str; break; default : pargs.err = 2; break; } } diff --git a/scd/sc-investigate.c b/scd/sc-investigate.c index e8f0eb83c..ecd385690 100644 --- a/scd/sc-investigate.c +++ b/scd/sc-investigate.c @@ -39,6 +39,7 @@ enum cmd_and_opt_values { oVerbose = 'v', oReaderPort = 500, + octapiDriver, oDebug, oDebugAll, @@ -52,7 +53,8 @@ static ARGPARSE_OPTS opts[] = { { 301, NULL, 0, "@Options:\n " }, { oVerbose, "verbose", 0, "verbose" }, - { oReaderPort, "reader-port", 1, "|N|connect to reader at port N"}, + { oReaderPort, "reader-port", 2, "|N|connect to reader at port N"}, + { octapiDriver, "ctapi-driver", 2, "NAME|use NAME as ctAPI driver"}, { oDebug, "debug" ,4|16, "set debugging flags"}, { oDebugAll, "debug-all" ,0, "enable full debugging"}, { oGenRandom, "gen-random", 4, "|N|generate N bytes of random"}, @@ -108,7 +110,7 @@ main (int argc, char **argv ) { ARGPARSE_ARGS pargs; int slot, rc; - int reader_port = 32768; /* First USB reader. */ + const char *reader_port = NULL; struct app_ctx_s appbuf; unsigned long gen_random = 0; @@ -139,6 +141,8 @@ main (int argc, char **argv ) case oVerbose: opt.verbose++; break; case oDebug: opt.debug |= pargs.r.ret_ulong; break; case oDebugAll: opt.debug = ~0; break; + case oReaderPort: reader_port = pargs.r.ret_str; break; + case octapiDriver: opt.ctapi_driver = pargs.r.ret_str; break; case oGenRandom: gen_random = pargs.r.ret_ulong; break; default : pargs.err = 2; break; } diff --git a/scd/scdaemon.c b/scd/scdaemon.c index 8e0ef37c9..11952615d 100644 --- a/scd/scdaemon.c +++ b/scd/scdaemon.c @@ -43,7 +43,7 @@ #include "i18n.h" #include "sysutils.h" - +#include "app-common.h" enum cmd_and_opt_values @@ -69,6 +69,7 @@ enum cmd_and_opt_values oDaemon, oBatch, oReaderPort, + octapiDriver, aTest }; @@ -91,8 +92,8 @@ static ARGPARSE_OPTS opts[] = { { oDebugSC, "debug-sc", 1, N_("|N|set OpenSC debug level to N")}, { oNoDetach, "no-detach" ,0, N_("do not detach from the console")}, { oLogFile, "log-file" ,2, N_("use a log file for the server")}, - { oReaderPort, "reader-port", 1, N_("|N|connect to reader at port N")}, - + { oReaderPort, "reader-port", 2, N_("|N|connect to reader at port N")}, + { octapiDriver, "ctapi-driver", 2, N_("NAME|use NAME as ctAPI driver")}, {0} }; @@ -230,7 +231,6 @@ main (int argc, char **argv ) int csh_style = 0; char *logfile = NULL; int debug_wait = 0; - int reader_port = 32768; /* First USB reader. */ set_strusage (my_strusage); gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN); @@ -299,6 +299,7 @@ main (int argc, char **argv ) if (default_config) configname = make_filename (opt.homedir, "scdaemon.conf", NULL ); + argc = orig_argc; argv = orig_argv; @@ -365,7 +366,8 @@ main (int argc, char **argv ) case oServer: pipe_server = 1; break; case oDaemon: is_daemon = 1; break; - case oReaderPort: reader_port = pargs.r.ret_int; break; + case oReaderPort: app_set_default_reader_port (pargs.r.ret_str); break; + case octapiDriver: opt.ctapi_driver = pargs.r.ret_str; break; default : pargs.err = configfp? 1:2; break; } diff --git a/scd/scdaemon.h b/scd/scdaemon.h index b21e19f8c..bdc4c21b3 100644 --- a/scd/scdaemon.h +++ b/scd/scdaemon.h @@ -53,6 +53,7 @@ struct { int dry_run; /* don't change any persistent data */ int batch; /* batch mode */ const char *homedir; /* configuration directory name */ + const char *ctapi_driver; /* Library to access the ctAPI. */ } opt; -- cgit From 3af881581faf505df3b40d5c8bff6bc0aaa125c5 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 30 Sep 2003 13:22:33 +0000 Subject: Minor fixes --- g10/ChangeLog | 4 ++++ g10/sign.c | 38 +------------------------------------- scd/ChangeLog | 4 ++++ scd/app-openpgp.c | 2 +- 4 files changed, 10 insertions(+), 38 deletions(-) (limited to 'scd/app-openpgp.c') diff --git a/g10/ChangeLog b/g10/ChangeLog index f91bc6bcc..f8120230f 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,7 @@ +2003-09-27 Werner Koch + + * sign.c (do_sign): Removed disabled testcode. + 2003-09-26 Timo Schulz * card_status (card_status): Do not use fputs since the fp diff --git a/g10/sign.c b/g10/sign.c index 640e36fe0..cd7615c00 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -307,43 +307,7 @@ do_sign( PKT_secret_key *sk, PKT_signature *sig, sig->digest_algo = digest_algo; sig->digest_start[0] = dp[0]; sig->digest_start[1] = dp[1]; -#if 0 - if (sk->is_protected && sk->protect.s2k.mode == 1002 && !sk->is_primary) - { /* Temporary hack to test tey auth command. */ - char *rbuf; - size_t rbuflen; - char *snbuf; - char *tmpbuf; - size_t tmp_n; - - frame = encode_md_value( sk->pubkey_algo, md, - digest_algo, mpi_get_nbits(sk->skey[0]), 0 ); - if (!frame) - return GPG_ERR_GENERAL; - - if (gcry_mpi_aprint (GCRYMPI_FMT_USG, (void **)&tmpbuf, &tmp_n, frame )) - BUG (); - for (; tmp_n && *tmpbuf; tmp_n--, tmpbuf++) - ; - assert (tmp_n); - tmp_n--; - tmpbuf++; - - snbuf = serialno_and_fpr_from_sk (sk->protect.iv, sk->protect.ivlen, sk); - rc = agent_scd_pksign (snbuf, 0, - tmpbuf, tmp_n, - &rbuf, &rbuflen); - xfree (snbuf); - if (!rc) - { - if (gcry_mpi_scan (&sig->data[0], GCRYMPI_FMT_USG, - rbuf, rbuflen, NULL )) - BUG (); - } - } - else -#endif - if (sk->is_protected && sk->protect.s2k.mode == 1002) + if (sk->is_protected && sk->protect.s2k.mode == 1002) { /* FIXME: Note that we do only support RSA for now. */ char *rbuf; size_t rbuflen; diff --git a/scd/ChangeLog b/scd/ChangeLog index e8c4cc88b..a55707ad2 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,7 @@ +2003-09-28 Werner Koch + + * app-openpgp.c (dump_all_do): Use gpg_err_code and not gpg_error. + 2003-09-19 Werner Koch * ccid-driver.c (parse_ccid_descriptor): New. diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 7f6114292..7a49edfe5 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -228,7 +228,7 @@ dump_all_do (int slot) continue; rc = iso7816_get_data (slot, data_objects[i].tag, &buffer, &buflen); - if (gpg_error (rc) == GPG_ERR_NO_OBJ) + if (gpg_err_code (rc) == GPG_ERR_NO_OBJ) ; else if (rc) log_info ("DO `%s' not available: %s\n", -- cgit From 59a61b3c93f6a109f1e1bfe94fd0ab4a28169a9e Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 30 Sep 2003 17:35:05 +0000 Subject: * command.c (cmd_getattr): New command GETATTR. * app.c (app_setattr): New. (do_getattr): New. (do_learn_status): Reimplemented in terms of do_getattr. * app-openpgp.c (do_change_pin): Make sure CVH1 and CHV2 are always synced. (verify_chv2, verify_chv3): New. Factored out common code. (do_setattr, do_sign, do_auth, do_decipher): Change the names of the prompts to match that we have only 2 different PINs. (app_select_openpgp): Check whether the card enforced CHV1. (convert_sig_counter_value): New. Factor out code from get_sig_counter. --- scd/ChangeLog | 16 ++ scd/app-common.h | 3 + scd/app-openpgp.c | 483 ++++++++++++++++++++++++++++-------------------------- scd/app.c | 13 ++ scd/command.c | 36 ++++ 5 files changed, 321 insertions(+), 230 deletions(-) (limited to 'scd/app-openpgp.c') diff --git a/scd/ChangeLog b/scd/ChangeLog index a55707ad2..4363888c6 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,19 @@ +2003-09-30 Werner Koch + + * command.c (cmd_getattr): New command GETATTR. + * app.c (app_setattr): New. + (do_getattr): New. + (do_learn_status): Reimplemented in terms of do_getattr. + + * app-openpgp.c (do_change_pin): Make sure CVH1 and CHV2 are + always synced. + (verify_chv2, verify_chv3): New. Factored out common code. + (do_setattr, do_sign, do_auth, do_decipher): Change the names of + the prompts to match that we have only 2 different PINs. + (app_select_openpgp): Check whether the card enforced CHV1. + (convert_sig_counter_value): New. Factor out code from + get_sig_counter. + 2003-09-28 Werner Koch * app-openpgp.c (dump_all_do): Use gpg_err_code and not gpg_error. diff --git a/scd/app-common.h b/scd/app-common.h index 1243ca3ec..e4b9d2f6c 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -31,10 +31,12 @@ struct app_ctx_s { size_t serialnolen; /* Length in octets of serialnumber. */ unsigned int card_version; int did_chv1; + int force_chv1; /* True if the card does not cache CHV1. */ int did_chv2; int did_chv3; struct { int (*learn_status) (APP app, CTRL ctrl); + int (*getattr) (APP app, CTRL ctrl, const char *name); int (*setattr) (APP app, const char *name, int (*pincb)(void*, const char *, char **), void *pincb_arg, @@ -73,6 +75,7 @@ void app_set_default_reader_port (const char *portstr); APP select_application (void); int app_get_serial_and_stamp (APP app, char **serial, time_t *stamp); int app_write_learn_status (APP app, CTRL ctrl); +int app_getattr (APP app, CTRL ctrl, const char *name); int app_setattr (APP app, const char *name, int (*pincb)(void*, const char *, char **), void *pincb_arg, diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 7a49edfe5..3a312696b 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -61,6 +61,8 @@ static struct { }; +static unsigned long convert_sig_counter_value (const unsigned char *value, + size_t valuelen); static unsigned long get_sig_counter (APP app); @@ -390,80 +392,165 @@ send_key_data (CTRL ctrl, const char *name, xfree (buf); } - - -static int -do_learn_status (APP app, CTRL ctrl) +/* Implement the GETATTR command. This is similar to the LEARN + command but returns just one value via the status interface. */ +static int +do_getattr (APP app, CTRL ctrl, const char *name) { + static struct { + const char *name; + int tag; + int special; + } table[] = { + { "DISP-NAME", 0x005B }, + { "LOGIN-DATA", 0x005E }, + { "DISP-LANG", 0x5F2D }, + { "DISP-SEX", 0x5F35 }, + { "PUBKEY-URL", 0x5F50 }, + { "KEY-FPR", 0x00C5, 3 }, + { "CA-FPR", 0x00C6, 3 }, + { "CHV-STATUS", 0x00C4, 1 }, + { "SIG-COUNTER", 0x0093, 2 }, + { NULL, 0 } + }; + int idx, i; void *relptr; unsigned char *value; size_t valuelen; - int i; - relptr = get_one_do (app->slot, 0x005B, &value, &valuelen); - if (relptr) - { - send_status_info (ctrl, "DISP-NAME", value, valuelen, NULL, 0); - xfree (relptr); - } - relptr = get_one_do (app->slot, 0x5F2D, &value, &valuelen); - if (relptr) - { - send_status_info (ctrl, "DISP-LANG", value, valuelen, NULL, 0); - xfree (relptr); - } - relptr = get_one_do (app->slot, 0x5F35, &value, &valuelen); - if (relptr) - { - send_status_info (ctrl, "DISP-SEX", value, valuelen, NULL, 0); - xfree (relptr); - } - relptr = get_one_do (app->slot, 0x5F50, &value, &valuelen); - if (relptr) - { - send_status_info (ctrl, "PUBKEY-URL", value, valuelen, NULL, 0); - xfree (relptr); - } - relptr = get_one_do (app->slot, 0x005E, &value, &valuelen); + for (idx=0; table[idx].name && strcmp (table[idx].name, name); idx++) + ; + if (!table[idx].name) + return gpg_error (GPG_ERR_INV_NAME); + + relptr = get_one_do (app->slot, table[idx].tag, &value, &valuelen); if (relptr) { - send_status_info (ctrl, "LOGIN-DATA", value, valuelen, NULL, 0); + if (table[idx].special == 1) + { + char numbuf[7*23]; + + for (i=0,*numbuf=0; i < valuelen && i < 7; i++) + sprintf (numbuf+strlen (numbuf), " %d", value[i]); + send_status_info (ctrl, table[idx].name, + numbuf, strlen (numbuf), NULL, 0); + } + else if (table[idx].special == 2) + { + char numbuf[50]; + + sprintf (numbuf, "%lu", convert_sig_counter_value (value, valuelen)); + send_status_info (ctrl, table[idx].name, + numbuf, strlen (numbuf), NULL, 0); + } + else if (table[idx].special == 3) + { + if (valuelen >= 60) + for (i=0; i < 3; i++) + send_fpr_if_not_null (ctrl, "KEY-FPR", i+1, value+i*20); + } + else + send_status_info (ctrl, table[idx].name, value, valuelen, NULL, 0); + xfree (relptr); } + return 0; +} - relptr = get_one_do (app->slot, 0x00C5, &value, &valuelen); - if (relptr && valuelen >= 60) - { - for (i=0; i < 3; i++) - send_fpr_if_not_null (ctrl, "KEY-FPR", i+1, value+i*20); - } - xfree (relptr); - relptr = get_one_do (app->slot, 0x00C6, &value, &valuelen); - if (relptr && valuelen >= 60) - { - for (i=0; i < 3; i++) - send_fpr_if_not_null (ctrl, "CA-FPR", i+1, value+i*20); - } - xfree (relptr); - relptr = get_one_do (app->slot, 0x00C4, &value, &valuelen); - if (relptr) + +static int +do_learn_status (APP app, CTRL ctrl) +{ + do_getattr (app, ctrl, "DISP-NAME"); + do_getattr (app, ctrl, "DISP-LANG"); + do_getattr (app, ctrl, "DISP-SEX"); + do_getattr (app, ctrl, "PUBKEY-URL"); + do_getattr (app, ctrl, "LOGIN-DATA"); + do_getattr (app, ctrl, "KEY-FPR"); + do_getattr (app, ctrl, "CA-FPR"); + do_getattr (app, ctrl, "CHV-STATUS"); + do_getattr (app, ctrl, "SIG-COUNTER"); + + return 0; +} + + +/* Verify CHV2 if required. Depending on the configuration of the + card CHV1 will also be verified. */ +static int +verify_chv2 (APP app, + int (*pincb)(void*, const char *, char **), + void *pincb_arg) +{ + int rc = 0; + + if (!app->did_chv2) { - char numbuf[7*23]; + char *pinvalue; - for (i=0,*numbuf=0; i < valuelen && i < 7; i++) - sprintf (numbuf+strlen (numbuf), " %d", value[i]); - send_status_info (ctrl, "CHV-STATUS", numbuf, strlen (numbuf), NULL, 0); - xfree (relptr); + rc = pincb (pincb_arg, "PIN", &pinvalue); + if (rc) + { + log_info ("PIN callback returned error: %s\n", gpg_strerror (rc)); + return rc; + } + + rc = iso7816_verify (app->slot, 0x82, pinvalue, strlen (pinvalue)); + if (rc) + { + log_error ("verify CHV2 failed: %s\n", gpg_strerror (rc)); + xfree (pinvalue); + return rc; + } + app->did_chv2 = 1; + + if (!app->did_chv1 && !app->force_chv1) + { + rc = iso7816_verify (app->slot, 0x81, pinvalue, strlen (pinvalue)); + if (gpg_err_code (rc) == GPG_ERR_BAD_PIN) + rc = gpg_error (GPG_ERR_PIN_NOT_SYNCED); + if (rc) + { + log_error ("verify CHV1 failed: %s\n", gpg_strerror (rc)); + xfree (pinvalue); + return rc; + } + app->did_chv1 = 1; + } + xfree (pinvalue); } + return rc; +} - { - unsigned long ul = get_sig_counter (app); - char numbuf[23]; +/* Verify CHV3 if required. */ +static int +verify_chv3 (APP app, + int (*pincb)(void*, const char *, char **), + void *pincb_arg) +{ + int rc = 0; - sprintf (numbuf, "%lu", ul); - send_status_info (ctrl, "SIG-COUNTER", numbuf, strlen (numbuf), NULL, 0); - } - return 0; + if (!app->did_chv3) + { + char *pinvalue; + + rc = pincb (pincb_arg, "Admin PIN", &pinvalue); + if (rc) + { + log_info ("PIN callback returned error: %s\n", gpg_strerror (rc)); + return rc; + } + + rc = iso7816_verify (app->slot, 0x83, pinvalue, strlen (pinvalue)); + xfree (pinvalue); + if (rc) + { + log_error ("verify CHV3 failed: %s\n", gpg_strerror (rc)); + return rc; + } + app->did_chv3 = 1; + } + return rc; } @@ -499,41 +586,18 @@ do_setattr (APP app, const char *name, if (!table[idx].name) return gpg_error (GPG_ERR_INV_NAME); - if (!app->did_chv3) - { - char *pinvalue; - - rc = pincb (pincb_arg, "Admin PIN (CHV3)", - &pinvalue); -/* pinvalue = xstrdup ("12345678"); */ -/* rc = 0; */ - if (rc) - { - log_info ("PIN callback returned error: %s\n", gpg_strerror (rc)); - return rc; - } - - rc = iso7816_verify (app->slot, 0x83, pinvalue, strlen (pinvalue)); - xfree (pinvalue); - if (rc) - { - log_error ("verify CHV3 failed: %s\n", gpg_strerror (rc)); - rc = gpg_error (GPG_ERR_GENERAL); - return rc; - } - app->did_chv3 = 1; - } + rc = verify_chv3 (app, pincb, pincb_arg); + if (rc) + return rc; rc = iso7816_put_data (app->slot, table[idx].tag, value, valuelen); if (rc) log_error ("failed to set `%s': %s\n", table[idx].name, gpg_strerror (rc)); - /* FIXME: If this fails we should *once* try again after - doing a verify command, so that in case of a problem with - tracking the verify operation we have a fallback. */ return rc; } + /* Handle the PASSWD command. */ static int do_change_pin (APP app, CTRL ctrl, const char *chvnostr, int reset_mode, @@ -551,51 +615,25 @@ do_change_pin (APP app, CTRL ctrl, const char *chvnostr, int reset_mode, } else if (reset_mode || chvno == 3) { - rc = pincb (pincb_arg, "Admin PIN", &pinvalue); - if (rc) - { - log_error ("error getting PIN: %s\n", gpg_strerror (rc)); - goto leave; - } - rc = iso7816_verify (app->slot, 0x83, pinvalue, strlen (pinvalue)); - xfree (pinvalue); - if (rc) - { - log_error ("verify CHV3 failed: rc=%s\n", gpg_strerror (rc)); - goto leave; - } - } - else if (chvno == 1) - { - rc = pincb (pincb_arg, "Signature PIN", &pinvalue); + /* we always require that the PIN is entered. */ + app->did_chv3 = 0; + rc = verify_chv3 (app, pincb, pincb_arg); if (rc) - { - log_error ("error getting PIN: %s\n", gpg_strerror (rc)); - goto leave; - } - rc = iso7816_verify (app->slot, 0x81, pinvalue, strlen (pinvalue)); - xfree (pinvalue); - if (rc) - { - log_error ("verify CHV1 failed: rc=%s\n", gpg_strerror (rc)); - goto leave; - } + goto leave; } - else if (chvno == 2) + else if (chvno == 1 || chvno == 2) { - rc = pincb (pincb_arg, "Decryption PIN", &pinvalue); + /* CHV1 and CVH2 should always have the same value, thus we + enforce it here. */ + int save_force = app->force_chv1; + + app->force_chv1 = 0; + app->did_chv1 = 0; + app->did_chv2 = 0; + rc = verify_chv2 (app, pincb, pincb_arg); + app->force_chv1 = save_force; if (rc) - { - log_error ("error getting PIN: %s\n", gpg_strerror (rc)); - goto leave; - } - rc = iso7816_verify (app->slot, 0x82, pinvalue, strlen (pinvalue)); - xfree (pinvalue); - if (rc) - { - log_error ("verify CHV2 failed: rc=%s\n", gpg_strerror (rc)); - goto leave; - } + goto leave; } else { @@ -603,10 +641,12 @@ do_change_pin (APP app, CTRL ctrl, const char *chvnostr, int reset_mode, goto leave; } - - rc = pincb (pincb_arg, chvno == 1? "New Signature PIN" : - chvno == 2? "New Decryption PIN" : - chvno == 3? "New Admin PIN" : "?", &pinvalue); + if (chvno == 3) + app->did_chv3 = 0; + else + app->did_chv1 = app->did_chv2 = 0; + + rc = pincb (pincb_arg, chvno == 3? "New Admin PIN" : "New PIN", &pinvalue); if (rc) { log_error ("error getting new PIN: %s\n", gpg_strerror (rc)); @@ -614,12 +654,27 @@ do_change_pin (APP app, CTRL ctrl, const char *chvnostr, int reset_mode, } if (reset_mode) - rc = iso7816_reset_retry_counter (app->slot, 0x80 + chvno, - pinvalue, strlen (pinvalue)); - else - rc = iso7816_change_reference_data (app->slot, 0x80 + chvno, - NULL, 0, + { + rc = iso7816_reset_retry_counter (app->slot, 0x81, pinvalue, strlen (pinvalue)); + if (!rc) + rc = iso7816_reset_retry_counter (app->slot, 0x82, + pinvalue, strlen (pinvalue)); + } + else + { + if (chvno == 1 || chvno == 2) + { + rc = iso7816_change_reference_data (app->slot, 0x81, NULL, 0, + pinvalue, strlen (pinvalue)); + if (!rc) + rc = iso7816_change_reference_data (app->slot, 0x82, NULL, 0, + pinvalue, strlen (pinvalue)); + } + else + rc = iso7816_change_reference_data (app->slot, 0x80 + chvno, NULL, 0, + pinvalue, strlen (pinvalue)); + } xfree (pinvalue); @@ -679,22 +734,10 @@ do_genkey (APP app, CTRL ctrl, const char *keynostr, unsigned int flags, else log_info ("generating new key\n"); - { - char *pinvalue; - rc = pincb (pincb_arg, "Admin PIN", &pinvalue); - if (rc) - { - log_error ("error getting PIN: %s\n", gpg_strerror (rc)); - return rc; - } - rc = iso7816_verify (app->slot, 0x83, pinvalue, strlen (pinvalue)); - xfree (pinvalue); - } + + rc = verify_chv3 (app, pincb, pincb_arg); if (rc) - { - log_error ("verify CHV3 failed: rc=%s\n", gpg_strerror (rc)); - goto leave; - } + goto leave; xfree (buffer); buffer = NULL; #if 1 @@ -765,16 +808,10 @@ do_genkey (APP app, CTRL ctrl, const char *keynostr, unsigned int flags, static unsigned long -get_sig_counter (APP app) +convert_sig_counter_value (const unsigned char *value, size_t valuelen) { - void *relptr; - unsigned char *value; - size_t valuelen; unsigned long ul; - relptr = get_one_do (app->slot, 0x0093, &value, &valuelen); - if (!relptr) - return 0; if (valuelen == 3 ) ul = (value[0] << 16) | (value[1] << 8) | value[2]; else @@ -782,6 +819,21 @@ get_sig_counter (APP app) log_error ("invalid structure of OpenPGP card (DO 0x93)\n"); ul = 0; } + return ul; +} + +static unsigned long +get_sig_counter (APP app) +{ + void *relptr; + unsigned char *value; + size_t valuelen; + unsigned long ul; + + relptr = get_one_do (app->slot, 0x0093, &value, &valuelen); + if (!relptr) + return 0; + ul = convert_sig_counter_value (value, valuelen); xfree (relptr); return ul; } @@ -914,21 +966,17 @@ do_sign (APP app, const char *keyidstr, int hashalgo, sigcount = get_sig_counter (app); log_info ("signatures created so far: %lu\n", sigcount); - /* FIXME: Check whether we are really required to enter the PIN for - each signature. There is a DO for this. */ - if (!app->did_chv1 || 1) + if (!app->did_chv1 || app->force_chv1 ) { char *pinvalue; { char *prompt; - if (asprintf (&prompt, "Signature PIN [sigs done: %lu]", sigcount) < 0) + if (asprintf (&prompt, "PIN [sigs done: %lu]", sigcount) < 0) return gpg_error_from_errno (errno); rc = pincb (pincb_arg, prompt, &pinvalue); free (prompt); } -/* pinvalue = xstrdup ("123456"); */ -/* rc = 0; */ if (rc) { log_info ("PIN callback returned error: %s\n", gpg_strerror (rc)); @@ -936,14 +984,28 @@ do_sign (APP app, const char *keyidstr, int hashalgo, } rc = iso7816_verify (app->slot, 0x81, pinvalue, strlen (pinvalue)); - xfree (pinvalue); if (rc) { log_error ("verify CHV1 failed\n"); - rc = gpg_error (GPG_ERR_GENERAL); + xfree (pinvalue); return rc; } app->did_chv1 = 1; + if (!app->did_chv2) + { + /* We should also verify CHV2. */ + rc = iso7816_verify (app->slot, 0x82, pinvalue, strlen (pinvalue)); + if (gpg_err_code (rc) == GPG_ERR_BAD_PIN) + rc = gpg_error (GPG_ERR_PIN_NOT_SYNCED); + if (rc) + { + log_error ("verify CHV2 failed\n"); + xfree (pinvalue); + return rc; + } + app->did_chv2 = 1; + } + xfree (pinvalue); } rc = iso7816_compute_ds (app->slot, data, 35, outdata, outdatalen); @@ -1024,30 +1086,10 @@ do_auth (APP app, const char *keyidstr, return rc; } - if (!app->did_chv2) - { - char *pinvalue; - - rc = pincb (pincb_arg, "Authentication/Decryption PIN", &pinvalue); - if (rc) - { - log_info ("PIN callback returned error: %s\n", gpg_strerror (rc)); - return rc; - } - - rc = iso7816_verify (app->slot, 0x82, pinvalue, strlen (pinvalue)); - xfree (pinvalue); - if (rc) - { - log_error ("verify CHV2 failed\n"); - rc = gpg_error (GPG_ERR_GENERAL); - return rc; - } - app->did_chv2 = 1; - } - - rc = iso7816_internal_authenticate (app->slot, indata, indatalen, - outdata, outdatalen); + rc = verify_chv2 (app, pincb, pincb_arg); + if (!rc) + rc = iso7816_internal_authenticate (app->slot, indata, indatalen, + outdata, outdatalen); return rc; } @@ -1114,31 +1156,9 @@ do_decipher (APP app, const char *keyidstr, return rc; } - if (!app->did_chv2) - { - char *pinvalue; - - rc = pincb (pincb_arg, "Decryption PIN", &pinvalue); -/* pinvalue = xstrdup ("123456"); */ -/* rc = 0; */ - if (rc) - { - log_info ("PIN callback returned error: %s\n", gpg_strerror (rc)); - return rc; - } - - rc = iso7816_verify (app->slot, 0x82, pinvalue, strlen (pinvalue)); - xfree (pinvalue); - if (rc) - { - log_error ("verify CHV2 failed\n"); - rc = gpg_error (GPG_ERR_GENERAL); - return rc; - } - app->did_chv2 = 1; - } - - rc = iso7816_decipher (app->slot, indata, indatalen, outdata, outdatalen); + rc = verify_chv2 (app, pincb, pincb_arg); + if (!rc) + rc = iso7816_decipher (app->slot, indata, indatalen, outdata, outdatalen); return rc; } @@ -1155,10 +1175,15 @@ app_select_openpgp (APP app, unsigned char **sn, size_t *snlen) int rc; unsigned char *buffer; size_t buflen; + void *relptr; rc = iso7816_select_application (slot, aid, sizeof aid); if (!rc) { + app->did_chv1 = 0; + app->did_chv2 = 0; + app->did_chv3 = 0; + rc = iso7816_get_data (slot, 0x004F, &buffer, &buflen); if (rc) goto leave; @@ -1178,10 +1203,20 @@ app_select_openpgp (APP app, unsigned char **sn, size_t *snlen) else xfree (buffer); + relptr = get_one_do (app->slot, 0x00C4, &buffer, &buflen); + if (!relptr) + { + log_error ("can't access CHV Status Bytes - invalid OpenPGP card?\n"); + goto leave; + } + app->force_chv1 = (buflen && *buffer == 0); + xfree (relptr); + if (opt.verbose > 1) dump_all_do (slot); app->fnc.learn_status = do_learn_status; + app->fnc.getattr = do_getattr; app->fnc.setattr = do_setattr; app->fnc.genkey = do_genkey; app->fnc.sign = do_sign; @@ -1306,22 +1341,10 @@ app_openpgp_storekey (APP app, int keyno, return gpg_error (GPG_ERR_INV_ID); keyno--; - { - char *pinvalue; - rc = pincb (pincb_arg, "Admin PIN", &pinvalue); - if (rc) - { - log_error ("error getting PIN: %s\n", gpg_strerror (rc)); - return rc; - } - rc = iso7816_verify (app->slot, 0x83, pinvalue, strlen (pinvalue)); - xfree (pinvalue); - } + rc = verify_chv3 (app, pincb, pincb_arg); if (rc) - { - log_error ("verify CHV3 failed: rc=%s\n", gpg_strerror (rc)); - goto leave; - } + goto leave; + rc = iso7816_put_data (app->slot, (app->card_version > 0x0007? 0xE0 : 0xE9) + keyno, diff --git a/scd/app.c b/scd/app.c index fa5df8a72..5b0340b89 100644 --- a/scd/app.c +++ b/scd/app.c @@ -125,6 +125,19 @@ app_write_learn_status (APP app, CTRL ctrl) } +/* Perform a GETATTR operation. */ +int +app_getattr (APP app, CTRL ctrl, const char *name) +{ + if (!app || !name || !*name) + return gpg_error (GPG_ERR_INV_VALUE); + if (!app->initialized) + return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); + if (!app->fnc.getattr) + return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); + return app->fnc.getattr (app, ctrl, name); +} + /* Perform a SETATTR operation. */ int app_setattr (APP app, const char *name, diff --git a/scd/command.c b/scd/command.c index 9f242bfab..fc5efa708 100644 --- a/scd/command.c +++ b/scd/command.c @@ -702,6 +702,41 @@ cmd_pkdecrypt (ASSUAN_CONTEXT ctx, char *line) } +/* GETATTR + + This command is used to retrieve data from a smartcard. The + allowed names depend on the currently selected smartcard + application. NAME must be percent and '+' escaped. The value is + returned through status message, see the LESRN command for details. + + However, the current implementation assumes that Name is not escaped; + this works as long as noone uses arbitrary escaping. + +*/ +static int +cmd_getattr (ASSUAN_CONTEXT ctx, char *line) +{ + CTRL ctrl = assuan_get_pointer (ctx); + int rc; + char *keyword; + + if ((rc = open_card (ctrl))) + return rc; + + keyword = line; + for (; *line && !spacep (line); line++) + ; + if (*line) + *line++ = 0; + + /* (We ignore any garbage for now.) */ + + rc = app_getattr (ctrl->app_ctx, ctrl, keyword); + + return map_to_assuan_status (rc); +} + + /* SETATTR This command is used to store data on a a smartcard. The allowed @@ -908,6 +943,7 @@ register_commands (ASSUAN_CONTEXT ctx) { "PKDECRYPT", cmd_pkdecrypt }, { "INPUT", NULL }, { "OUTPUT", NULL }, + { "GETATTR", cmd_getattr }, { "SETATTR", cmd_setattr }, { "GENKEY", cmd_genkey }, { "RANDOM", cmd_random }, -- cgit From f194ebc782424053896734699c2fc70b5ff0f14a Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 2 Oct 2003 10:27:34 +0000 Subject: Fixes to make inclusion of card raleted source files into 1.3 easier. --- ChangeLog | 4 ++++ configure.ac | 5 +++++ g10/ChangeLog | 6 +++++- g10/card-util.c | 6 ++++++ scd/ChangeLog | 11 +++++++++++ scd/apdu.c | 13 +++++++++++++ scd/app-common.h | 6 ++++++ scd/app-openpgp.c | 18 ++++++++++++++++-- scd/ccid-driver.c | 13 ++++++++++--- scd/iso7816.c | 20 ++++++++++++++++---- scd/iso7816.h | 4 ++++ 11 files changed, 96 insertions(+), 10 deletions(-) (limited to 'scd/app-openpgp.c') diff --git a/ChangeLog b/ChangeLog index ce3d76967..d2e219c90 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2003-10-01 Werner Koch + + * configure.ac (AH_BOTTOM): Define GNUPG_MAJOR_VERSION. + 2003-09-23 Werner Koch Merged most of David Shaw's changes in 1.3 since 2003-06-03. diff --git a/configure.ac b/configure.ac index 23baee44a..12ff0d703 100644 --- a/configure.ac +++ b/configure.ac @@ -238,6 +238,11 @@ AH_BOTTOM([ /* Tell libgcrypt not to use its own libgpg-error implementation. */ #define USE_LIBGPG_ERROR 1 +/* This is the major version number of GnuPG so that + source included files can test for this. Note, that\ + we use 2 here even for GnuPG 1.9.x. */ +#define GNUPG_MAJOR_VERSION 2 + #include "g10defs.h" ]) diff --git a/g10/ChangeLog b/g10/ChangeLog index 0e0e715fc..563c71eee 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,7 @@ +2003-10-01 Werner Koch + + * card-util.c: Tweaked to use this source also under 1.3. + 2003-09-30 Werner Koch * keylist.c (print_card_serialno): New. @@ -407,7 +411,7 @@ * card-util.c (card_status): New. * call-agent.c (learn_status_cb): Parse more information. - * keylist.c (print_pubkey_info): Add FP arg for optinal printing + * keylist.c (print_pubkey_info): Add FP arg for optional printing to a stream. Changed all callers. 2003-07-23 Werner Koch diff --git a/g10/card-util.c b/g10/card-util.c index 1028cd373..70518e9ce 100644 --- a/g10/card-util.c +++ b/g10/card-util.c @@ -25,14 +25,20 @@ #include #include +#if GNUPG_MAJOR_VERSION != 1 #include "gpg.h" +#endif #include "util.h" #include "i18n.h" #include "ttyio.h" #include "status.h" #include "options.h" #include "main.h" +#if GNUPG_MAJOR_VERSION == 1 +#include "cardglue.h" +#else #include "call-agent.h" +#endif #define CONTROL_D ('D' - 'A' + 1) diff --git a/scd/ChangeLog b/scd/ChangeLog index 4363888c6..f090e34c0 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,14 @@ +2003-10-01 Werner Koch + + * ccid-driver.c: Detect GnuPG 1.3 and include appropriate files. + * apdu.c: Ditto. + * app-openpgp.c: Ditto. + * iso7816.c: Ditto. + (generate_keypair): Renamed to .. + (do_generate_keypair): .. this. + * app-common.h [GNUPG_MAJOR_VERSION]: New. + * iso7816.h [GNUPG_MAJOR_VERSION]: Include cardglue.h + 2003-09-30 Werner Koch * command.c (cmd_getattr): New command GETATTR. diff --git a/scd/apdu.c b/scd/apdu.c index d5f64c6d8..d5b93de6e 100644 --- a/scd/apdu.c +++ b/scd/apdu.c @@ -28,7 +28,20 @@ # include #endif +#if GNUPG_MAJOR_VERSION == 1 +/* This is used with GnuPG version < 1.9. The code has been source + copied from the current GnuPG >= 1.9 and is maintained over + there. */ +#include "options.h" +#include "errors.h" +#include "memory.h" +#include "util.h" +#include "i18n.h" +#include "cardglue.h" +#else /* GNUPG_MAJOR_VERSION != 1 */ #include "scdaemon.h" +#endif /* GNUPG_MAJOR_VERSION != 1 */ + #include "apdu.h" #include "dynload.h" #include "ccid-driver.h" diff --git a/scd/app-common.h b/scd/app-common.h index e4b9d2f6c..33f23127b 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -70,6 +70,10 @@ struct app_ctx_s { }; +#if GNUPG_MAJOR_VERSION == 1 +int app_select_openpgp (APP app, unsigned char **sn, size_t *snlen); +int app_get_serial_and_stamp (APP app, char **serial, time_t *stamp); +#else /*-- app.c --*/ void app_set_default_reader_port (const char *portstr); APP select_application (void); @@ -124,6 +128,8 @@ int app_openpgp_storekey (APP app, int keyno, int app_openpgp_readkey (APP app, int keyno, unsigned char **m, size_t *mlen, unsigned char **e, size_t *elen); +#endif + #endif /*GNUPG_SCD_APP_COMMON_H*/ diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 3a312696b..e8fe19ea1 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -24,10 +24,24 @@ #include #include #include - +#include + +#if GNUPG_MAJOR_VERSION == 1 +/* This is used with GnuPG version < 1.9. The code has been source + copied from the current GnuPG >= 1.9 and is maintained over + there. */ +#include "options.h" +#include "errors.h" +#include "memory.h" +#include "util.h" +#include "i18n.h" +#include "cardglue.h" +#else /* GNUPG_MAJOR_VERSION != 1 */ #include "scdaemon.h" -#include "app-common.h" +#endif /* GNUPG_MAJOR_VERSION != 1 */ + #include "iso7816.h" +#include "app-common.h" diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c index e0b48f880..b4fbc0b21 100644 --- a/scd/ccid-driver.c +++ b/scd/ccid-driver.c @@ -87,9 +87,16 @@ #define DRVNAME "ccid-driver: " -#ifdef GNUPG_DEFAULT_SCDAEMON /* This source is used within the - gnupg>=1.9 source tree. */ -# include "scdaemon.h" +#ifdef GNUPG_MAJOR_VERSION /* This source is used within GnuPG. */ + +# if GNUPG_MAJOR_VERSION == 1 /* GnuPG Version is < 1.9. */ +# include "options.h" +# include "util.h" +# include "memory.h" +# include "cardglue.h" +# else /* This is the modularized GnuPG 1.9 or later. */ +# include "scdaemon.h" +# endif # define DEBUGOUT(t) do { if (DBG_CARD_IO) \ log_debug (DRVNAME t); } while (0) diff --git a/scd/iso7816.c b/scd/iso7816.c index 2b06103ef..f4aa18c6f 100644 --- a/scd/iso7816.c +++ b/scd/iso7816.c @@ -24,10 +24,22 @@ #include #include +#if GNUPG_MAJOR_VERSION == 1 +/* This is used with GnuPG version < 1.9. The code has been source + copied from the current GnuPG >= 1.9 and is maintained over + there. */ +#include "options.h" +#include "errors.h" +#include "memory.h" +#include "util.h" +#include "i18n.h" +#else /* GNUPG_MAJOR_VERSION != 1 */ #include "scdaemon.h" +#endif /* GNUPG_MAJOR_VERSION != 1 */ + #include "iso7816.h" #include "apdu.h" -#include "dynload.h" + #define CMD_SELECT_FILE 0xA4 #define CMD_VERIFY 0x20 @@ -290,7 +302,7 @@ iso7816_internal_authenticate (int slot, static gpg_error_t -generate_keypair (int slot, int readonly, +do_generate_keypair (int slot, int readonly, const unsigned char *data, size_t datalen, unsigned char **result, size_t *resultlen) { @@ -321,7 +333,7 @@ iso7816_generate_keypair (int slot, const unsigned char *data, size_t datalen, unsigned char **result, size_t *resultlen) { - return generate_keypair (slot, 0, data, datalen, result, resultlen); + return do_generate_keypair (slot, 0, data, datalen, result, resultlen); } @@ -330,7 +342,7 @@ iso7816_read_public_key (int slot, const unsigned char *data, size_t datalen, unsigned char **result, size_t *resultlen) { - return generate_keypair (slot, 1, data, datalen, result, resultlen); + return do_generate_keypair (slot, 1, data, datalen, result, resultlen); } diff --git a/scd/iso7816.h b/scd/iso7816.h index d7e77a101..26b8d6aba 100644 --- a/scd/iso7816.h +++ b/scd/iso7816.h @@ -21,6 +21,10 @@ #ifndef ISO7816_H #define ISO7816_H +#if GNUPG_MAJOR_VERSION == 1 +#include "cardglue.h" +#endif + gpg_error_t iso7816_select_application (int slot, const char *aid, size_t aidlen); gpg_error_t iso7816_verify (int slot, -- cgit From 30342b06efcc779b9222513d8dbfb85436ab624c Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 8 Oct 2003 10:46:58 +0000 Subject: * call-agent.c (agent_scd_getattr): Don't clear the passed info structure, so that it can indeed be updated. * card-util.c (fpr_is_zero): New. (generate_card_keys): New. (card_edit): New command "generate". * keygen.c (generate_keypair): New arg CARD_SERIALNO, removed call to check_smartcard. (check_smartcard,show_smartcard): Removed. (show_sha1_fpr,fpr_is_zero): Removed. * app-openpgp.c (do_getattr): Support SERIALNO and AID. --- NEWS | 5 ++ README | 4 ++ TODO | 1 + g10/ChangeLog | 13 ++++ g10/call-agent.c | 1 - g10/card-util.c | 88 ++++++++++++++++++++++++- g10/g10.c | 4 +- g10/keygen.c | 192 +++++------------------------------------------------- g10/main.h | 2 +- scd/ChangeLog | 4 ++ scd/app-openpgp.c | 25 +++++++ 11 files changed, 158 insertions(+), 181 deletions(-) (limited to 'scd/app-openpgp.c') diff --git a/NEWS b/NEWS index 558a5e8ac..b708d44cf 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,11 @@ Noteworthy changes in version 1.9.2 (unreleased) ------------------------------------------------ + * On card key generation is no longer done using the --gen-key + command but from the menu provided by the new --card-edit command. + + * PINs are now properly cached and there are only 2 PINs visible. + The 3rd PIN (CHV2) is internally syncronized with the regular PIN. Noteworthy changes in version 1.9.1 (2003-09-06) diff --git a/README b/README index 8dea9dbb9..60b613362 100644 --- a/README +++ b/README @@ -47,6 +47,10 @@ gpg2: Offers a menu to change the PIN of OpenPGP smartcards and to reset the retry counters. +--card-edit + + Offers a menu to change any data object on the card and to generate + the keys. OPTIONS diff --git a/TODO b/TODO index 11b887b9e..e8aa872a1 100644 --- a/TODO +++ b/TODO @@ -33,6 +33,7 @@ might want to have an agent context for each service request * sm/gpgsm.c ** Support --output ** mark all unimplemented commands and options. +** Print a hint when of MD2 is the cause for a problem. * sm/keydb.c ** Check file permissions diff --git a/g10/ChangeLog b/g10/ChangeLog index 563c71eee..cb5a8ad64 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,16 @@ +2003-10-08 Werner Koch + + * call-agent.c (agent_scd_getattr): Don't clear the passed info + structure, so that it can indeed be updated. + + * card-util.c (fpr_is_zero): New. + (generate_card_keys): New. + (card_edit): New command "generate". + * keygen.c (generate_keypair): New arg CARD_SERIALNO, removed call + to check_smartcard. + (check_smartcard,show_smartcard): Removed. + (show_sha1_fpr,fpr_is_zero): Removed. + 2003-10-01 Werner Koch * card-util.c: Tweaked to use this source also under 1.3. diff --git a/g10/call-agent.c b/g10/call-agent.c index f07c01f2a..c6c8faaec 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -600,7 +600,6 @@ agent_scd_getattr (const char *name, struct agent_card_info_s *info) if (rc) return rc; - memset (info, 0, sizeof *info); rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, learn_status_cb, info); diff --git a/g10/card-util.c b/g10/card-util.c index 70518e9ce..669927707 100644 --- a/g10/card-util.c +++ b/g10/card-util.c @@ -241,6 +241,17 @@ print_isoname (FILE *fp, const char *text, const char *tag, const char *name) tty_fprintf (fp, "\n"); } +/* Return true if the SHA1 fingerprint FPR consists only of zeroes. */ +static int +fpr_is_zero (const char *fpr) +{ + int i; + + for (i=0; i < 20 && !fpr[i]; i++) + ; + return (i == 20); +} + /* Print all available information about the current card. */ void @@ -569,6 +580,76 @@ toggle_forcesig (void) } +static void +generate_card_keys (void) +{ + struct agent_card_info_s info; + int rc; + int forced_chv1; + + memset (&info, 0, sizeof info); + rc = agent_scd_getattr ("KEY-FPR", &info); + if (!rc) + rc = agent_scd_getattr ("SERIALNO", &info); + if (!rc) + rc = agent_scd_getattr ("CHV-STATUS", &info); + if (!rc) + rc = agent_scd_getattr ("DISP-NAME", &info); + if (rc) + { + log_error ("error getting current key info: %s\n", gpg_strerror (rc)); + return; + } + if ( (info.fpr1valid && !fpr_is_zero (info.fpr1)) + || (info.fpr2valid && !fpr_is_zero (info.fpr2)) + || (info.fpr3valid && !fpr_is_zero (info.fpr3))) + { + tty_printf ("\n"); + log_info ("NOTE: keys are already stored on the card!\n"); + tty_printf ("\n"); + if ( !cpr_get_answer_is_yes( "cardedit.genkeys.replace_keys", + _("Replace existing keys? "))) + { + agent_release_card_info (&info); + return; + } + } + else if (!info.disp_name || !*info.disp_name) + { + tty_printf ("\n"); + tty_printf (_("Please note that the factory settings of the PINs are\n" + " PIN = \"%s\" Admin PIN = \"%s\"\n" + "You should change them using the command --change-pin\n"), + "123456", "12345678"); + tty_printf ("\n"); + } + + forced_chv1 = !info.chv1_cached; + if (forced_chv1) + { /* Switch of the forced mode so that during key generation we + don't get bothered with PIN queries for each + self-signature. */ + rc = agent_scd_setattr ("CHV-STATUS-1", "\x01", 1); + if (rc) + { + log_error ("error clearing forced signature PIN flag: %s\n", + gpg_strerror (rc)); + return; + } + } + generate_keypair (NULL, info.serialno); + agent_release_card_info (&info); + if (forced_chv1) + { /* Switch back to forced state. */ + rc = agent_scd_setattr ("CHV-STATUS-1", "", 1); + if (rc) + { + log_error ("error setting forced signature PIN flag: %s\n", + gpg_strerror (rc)); + return; + } + } +} /* Menu to edit all user changeable values on an OpenPGP card. Only Key creation is not handled here. */ @@ -579,7 +660,7 @@ card_edit (STRLIST commands) cmdNOP = 0, cmdQUIT, cmdHELP, cmdLIST, cmdDEBUG, cmdNAME, cmdURL, cmdLOGIN, cmdLANG, cmdSEX, - cmdFORCESIG, + cmdFORCESIG, cmdGENERATE, cmdINVCMD }; @@ -601,6 +682,7 @@ card_edit (STRLIST commands) { N_("lang") , cmdLANG , N_("change the language preferences") }, { N_("sex") , cmdSEX , N_("change card holder's sex") }, { N_("forcesig"), cmdFORCESIG, N_("toggle the signature force PIN flag") }, + { N_("generate"), cmdGENERATE, N_("generate new keys") }, { NULL, cmdINVCMD } }; @@ -725,6 +807,10 @@ card_edit (STRLIST commands) toggle_forcesig (); break; + case cmdGENERATE: + generate_card_keys (); + break; + case cmdQUIT: goto leave; diff --git a/g10/g10.c b/g10/g10.c index cdd10d845..984e50d9c 100644 --- a/g10/g10.c +++ b/g10/g10.c @@ -2555,12 +2555,12 @@ main( int argc, char **argv ) if( opt.batch ) { if( argc > 1 ) wrong_args("--gen-key [parameterfile]"); - generate_keypair( argc? *argv : NULL ); + generate_keypair( argc? *argv : NULL, NULL ); } else { if( argc ) wrong_args("--gen-key"); - generate_keypair(NULL); + generate_keypair(NULL, NULL); } break; diff --git a/g10/keygen.c b/g10/keygen.c index 38e9115b3..935cff330 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -117,7 +117,6 @@ static int mdc_available,ks_modify; static void do_generate_keypair( struct para_data_s *para, struct output_control_s *outctrl, int card); static int write_keyblock( iobuf_t out, KBNODE node ); -static int check_smartcard (char **); static int gen_card_key (int algo, int keyno, KBNODE pub_root, KBNODE sec_root, u32 expireval, struct para_data_s *para); @@ -2219,11 +2218,12 @@ read_parameter_file( const char *fname ) /**************** - * Generate a keypair - * (fname is only used in batch mode) + * Generate a keypair (fname is only used in batch mode) If + * CARD_SERIALNO is not NULL the fucntion will create the keys on an + * OpenPGP Card. */ void -generate_keypair( const char *fname ) +generate_keypair( const char *fname, const char *card_serialno ) { unsigned int nbits; char *uid = NULL; @@ -2232,42 +2232,34 @@ generate_keypair( const char *fname ) int algo; unsigned int use; int both = 0; - int card = 0; u32 expire; struct para_data_s *para = NULL; struct para_data_s *r; struct output_control_s outctrl; - char *serialno = NULL; memset (&outctrl, 0, sizeof (outctrl)); - if (opt.batch) + if (opt.batch && card_serialno) { - read_parameter_file( fname ); + /* We don't yet support unattended key generation. */ + log_error (_("sorry, can't do this in batch mode\n")); return; } - do + if (opt.batch) { - xfree (serialno); serialno = NULL; - card = check_smartcard (&serialno); - if (card < 0) - return; + read_parameter_file( fname ); + return; } - while (card > 1); - if (serialno) + if (card_serialno) { - r = xcalloc (1, sizeof *r + strlen (serialno) ); + r = xcalloc (1, sizeof *r + strlen (card_serialno) ); r->key = pSERIALNO; - strcpy( r->u.value, serialno); + strcpy( r->u.value, card_serialno); r->next = para; para = r; - xfree (serialno); serialno = NULL; - } - if (card) - { algo = PUBKEY_ALGO_RSA; r = xcalloc (1, sizeof *r + 20 ); @@ -2388,7 +2380,7 @@ generate_keypair( const char *fname ) r->next = para; para = r; - dek = card? NULL : ask_passphrase( &s2k ); + dek = card_serialno? NULL : ask_passphrase( &s2k ); if (dek) { r = xcalloc (1, sizeof *r ); @@ -2403,7 +2395,7 @@ generate_keypair( const char *fname ) para = r; } - proc_parameter_file (para, "[internal]", &outctrl, card); + proc_parameter_file (para, "[internal]", &outctrl, !!card_serialno); release_parameter_list (para); } @@ -2719,7 +2711,7 @@ do_generate_keypair (struct para_data_s *para, release_kbnode (pub_root); release_kbnode (sec_root); if (sk && !card) /* The unprotected secret key unless we have */ - free_secret_key (sk); /* shallow copy in card mode. */ + free_secret_key (sk); /* a shallow copy in card mode. */ } @@ -2848,158 +2840,6 @@ write_keyblock( iobuf_t out, KBNODE node ) } -static void -show_sha1_fpr (const unsigned char *fpr) -{ - int i; - - if (fpr) - { - for (i=0; i < 20 ; i+=2, fpr += 2 ) - { - if (i == 10 ) - tty_printf (" "); - tty_printf (" %02X%02X", *fpr, fpr[1]); - } - } - else - tty_printf (" [none]"); - tty_printf ("\n"); -} - -static void -show_smartcard (struct agent_card_info_s *info) -{ - PKT_public_key *pk = xcalloc (1, sizeof *pk); - - /* FIXME: Sanitize what we show. */ - tty_printf ("Name of cardholder: %s\n", - info->disp_name && *info->disp_name? info->disp_name - : "[not set]"); - tty_printf ("URL of public key : %s\n", - info->pubkey_url && *info->pubkey_url? info->pubkey_url - : "[not set]"); - tty_printf ("Signature key ....:"); - show_sha1_fpr (info->fpr1valid? info->fpr1:NULL); - tty_printf ("Encryption key....:"); - show_sha1_fpr (info->fpr2valid? info->fpr2:NULL); - tty_printf ("Authentication key:"); - show_sha1_fpr (info->fpr3valid? info->fpr3:NULL); - - if (info->fpr1valid && !get_pubkey_byfprint (pk, info->fpr1, 20)) - print_pubkey_info (NULL, pk); - - free_public_key( pk ); -} - -/* Return true if the SHA1 fingerprint FPR consists only of zeroes. */ -static int -fpr_is_zero (const char *fpr) -{ - int i; - - for (i=0; i < 20 && !fpr[i]; i++) - ; - return (i == 20); -} - -/* Check whether a smartcatrd is available and alow to select it as - the target for key generation. - - Return values: -1 = Quit generation - 0 = No smartcard - 1 = Generate keypair -*/ -static int -check_smartcard (char **r_serialno) -{ - struct agent_card_info_s info; - int rc; - - rc = agent_learn (&info); - if (rc) - { - tty_printf (_("OpenPGP card not available: %s\n"), - gpg_strerror (rc)); - return 0; - } - - tty_printf (_("OpenPGP card no. %s detected\n"), - info.serialno? info.serialno : "[none]"); - - - for (;;) - { - char *answer; - int reread = 0; - - tty_printf ("\n"); - show_smartcard (&info); - - tty_printf ("\n" - "K - generate all keys\n" - "Q - quit\n" - "\n"); - - answer = cpr_get("keygen.smartcard.menu",_("Your selection? ")); - cpr_kill_prompt(); - if (strlen (answer) != 1) - continue; - - rc = 0; - if ( *answer == 'K' || *answer == 'k') - { - if ( (info.fpr1valid && !fpr_is_zero (info.fpr1)) - || (info.fpr2valid && !fpr_is_zero (info.fpr2)) - || (info.fpr3valid && !fpr_is_zero (info.fpr3))) - { - tty_printf ("\n"); - log_error ("WARNING: key does already exists!\n"); - tty_printf ("\n"); - if ( cpr_get_answer_is_yes( "keygen.card.replace_key", - _("Replace existing key? "))) - { - rc = 1; - break; - } - } - else - { - rc = 1; - break; - } - } - else if ( *answer == 'q' || *answer == 'Q') - { - rc = -1; - break; - } - - if (reread) - { - agent_release_card_info (&info); - rc = agent_learn (&info); - if (rc) - { - tty_printf (_("OpenPGP card not anymore available: %s\n"), - gpg_strerror (rc)); - g10_exit (1); - } - reread = 0; - } - } - - if (r_serialno && rc > 0) - { - *r_serialno = info.serialno; - info.serialno = NULL; - } - agent_release_card_info (&info); - - return rc; -} - - static int gen_card_key (int algo, int keyno, KBNODE pub_root, KBNODE sec_root, diff --git a/g10/main.h b/g10/main.h index 76562fa91..d00044c9f 100644 --- a/g10/main.h +++ b/g10/main.h @@ -165,7 +165,7 @@ void show_basic_key_info (KBNODE keyblock); /*-- keygen.c --*/ u32 ask_expire_interval(int object); u32 ask_expiredate(void); -void generate_keypair( const char *fname ); +void generate_keypair( const char *fname, const char *card_serialno ); int keygen_set_std_prefs (const char *string,int personal); PKT_user_id *keygen_get_std_prefs (void); int keygen_add_key_expire( PKT_signature *sig, void *opaque ); diff --git a/scd/ChangeLog b/scd/ChangeLog index f090e34c0..86068b245 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,7 @@ +2003-10-08 Werner Koch + + * app-openpgp.c (do_getattr): Support SERIALNO and AID. + 2003-10-01 Werner Koch * ccid-driver.c: Detect GnuPG 1.3 and include appropriate files. diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index e8fe19ea1..174d2e974 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -425,6 +425,8 @@ do_getattr (APP app, CTRL ctrl, const char *name) { "CA-FPR", 0x00C6, 3 }, { "CHV-STATUS", 0x00C4, 1 }, { "SIG-COUNTER", 0x0093, 2 }, + { "SERIALNO", 0x004F, -1 }, + { "AID", 0x004F }, { NULL, 0 } }; int idx, i; @@ -437,6 +439,29 @@ do_getattr (APP app, CTRL ctrl, const char *name) if (!table[idx].name) return gpg_error (GPG_ERR_INV_NAME); + if (table[idx].special == -1) + { + /* The serial number is very special. We could have used the + AID DO to retrieve it, but we have it already in the app + context and the stanmp argument is required anyway which we + can't by other means. The AID DO is available anyway but not + hex formatted. */ + char *serial; + time_t stamp; + char tmp[50]; + + if (!app_get_serial_and_stamp (app, &serial, &stamp)) + { + sprintf (tmp, "%lu", (unsigned long)stamp); + send_status_info (ctrl, "SERIALNO", + serial, strlen (serial), + tmp, strlen (tmp), + NULL, 0); + xfree (serial); + } + return 0; + } + relptr = get_one_do (app->slot, table[idx].tag, &value, &valuelen); if (relptr) { -- cgit From 21be16dba911a3ebe530e37f3479690798cc8a01 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 21 Oct 2003 17:12:50 +0000 Subject: * command.c (cmd_checkpin): New. (register_commands): Add command CHECKPIN. * app.c (app_check_pin): New. * app-openpgp.c (check_against_given_fingerprint): New. Factored out that code elsewhere. (do_check_pin): New. --- scd/ChangeLog | 17 +++++++ scd/apdu.c | 137 ++++++++++++++++++++++++++++++++++++++++-------------- scd/apdu.h | 1 + scd/app-common.h | 6 +++ scd/app-openpgp.c | 137 ++++++++++++++++++++++++++++++++++-------------------- scd/app.c | 23 +++++++++ scd/ccid-driver.c | 61 ++++++++++++++++++++---- scd/ccid-driver.h | 1 + scd/command.c | 36 ++++++++++++++ 9 files changed, 324 insertions(+), 95 deletions(-) (limited to 'scd/app-openpgp.c') diff --git a/scd/ChangeLog b/scd/ChangeLog index f8ce674b8..40a928895 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,20 @@ +2003-10-20 Werner Koch + + * command.c (cmd_checkpin): New. + (register_commands): Add command CHECKPIN. + * app.c (app_check_pin): New. + * app-openpgp.c (check_against_given_fingerprint): New. Factored + out that code elsewhere. + (do_check_pin): New. + +2003-10-10 Werner Koch + + * ccid-driver.c (ccid_close_reader): New. + + * apdu.c (close_ccid_reader, close_ct_reader, close_csc_reader) + (close_osc_reader, apdu_close_reader): New. Not all are properly + implemented yet. + 2003-10-09 Werner Koch * ccid-driver.c (ccid_transceive): Add T=1 chaining for sending. diff --git a/scd/apdu.c b/scd/apdu.c index d5b93de6e..2b17ef53b 100644 --- a/scd/apdu.c +++ b/scd/apdu.c @@ -51,6 +51,13 @@ insertion of the card (1 = don't wait). */ +#ifdef _WIN32 +#define DLSTDCALL __stdcall +#else +#define DLSTDCALL +#endif + + /* A structure to collect information pertaining to one reader slot. */ struct reader_table_s { @@ -84,12 +91,12 @@ static struct reader_table_s reader_table[MAX_READER]; /* ct API function pointer. */ -static char (*CT_init) (unsigned short ctn, unsigned short Pn); -static char (*CT_data) (unsigned short ctn, unsigned char *dad, - unsigned char *sad, unsigned short lc, - unsigned char *cmd, unsigned short *lr, - unsigned char *rsp); -static char (*CT_close) (unsigned short ctn); +static char (* DLSTDCALL CT_init) (unsigned short ctn, unsigned short Pn); +static char (* DLSTDCALL CT_data) (unsigned short ctn, unsigned char *dad, + unsigned char *sad, unsigned short lc, + unsigned char *cmd, unsigned short *lr, + unsigned char *rsp); +static char (* DLSTDCALL CT_close) (unsigned short ctn); /* PC/SC constants and function pointer. */ #define PCSC_SCOPE_USER 0 @@ -117,34 +124,38 @@ struct pcsc_io_request_s { typedef struct pcsc_io_request_s *pcsc_io_request_t; -long (*pcsc_establish_context) (unsigned long scope, - const void *reserved1, - const void *reserved2, - unsigned long *r_context); -long (*pcsc_release_context) (unsigned long context); -long (*pcsc_list_readers) (unsigned long context, const char *groups, - char *readers, unsigned long *readerslen); -long (*pcsc_connect) (unsigned long context, - const char *reader, - unsigned long share_mode, - unsigned long preferred_protocols, - unsigned long *r_card, - unsigned long *r_active_protocol); -long (*pcsc_disconnect) (unsigned long card, unsigned long disposition); -long (*pcsc_status) (unsigned long card, - char *reader, unsigned long *readerlen, - unsigned long *r_state, unsigned long *r_protocol, - unsigned char *atr, unsigned long *atrlen); -long (*pcsc_begin_transaction) (unsigned long card); -long (*pcsc_end_transaction) (unsigned long card); -long (*pcsc_transmit) (unsigned long card, - const pcsc_io_request_t send_pci, - const unsigned char *send_buffer, - unsigned long send_len, - pcsc_io_request_t recv_pci, - unsigned char *recv_buffer, - unsigned long *recv_len); -long (*pcsc_set_timeout) (unsigned long context, unsigned long timeout); +long (* DLSTDCALL pcsc_establish_context) (unsigned long scope, + const void *reserved1, + const void *reserved2, + unsigned long *r_context); +long (* DLSTDCALL pcsc_release_context) (unsigned long context); +long (* DLSTDCALL pcsc_list_readers) (unsigned long context, + const char *groups, + char *readers, unsigned long*readerslen); +long (* DLSTDCALL pcsc_connect) (unsigned long context, + const char *reader, + unsigned long share_mode, + unsigned long preferred_protocols, + unsigned long *r_card, + unsigned long *r_active_protocol); +long (* DLSTDCALL pcsc_disconnect) (unsigned long card, + unsigned long disposition); +long (* DLSTDCALL pcsc_status) (unsigned long card, + char *reader, unsigned long *readerlen, + unsigned long *r_state, + unsigned long *r_protocol, + unsigned char *atr, unsigned long *atrlen); +long (* DLSTDCALL pcsc_begin_transaction) (unsigned long card); +long (* DLSTDCALL pcsc_end_transaction) (unsigned long card); +long (* DLSTDCALL pcsc_transmit) (unsigned long card, + const pcsc_io_request_t send_pci, + const unsigned char *send_buffer, + unsigned long send_len, + pcsc_io_request_t recv_pci, + unsigned char *recv_buffer, + unsigned long *recv_len); +long (* DLSTDCALL pcsc_set_timeout) (unsigned long context, + unsigned long timeout); @@ -347,6 +358,14 @@ open_ct_reader (int port) return reader; } +static int +close_ct_reader (int slot) +{ + /* FIXME: Implement. */ + reader_table[slot].used = 0; + return 0; +} + /* Actually send the APDU of length APDULEN to SLOT and return a maximum of *BUFLEN data in BUFFER, the actual retruned size will be @@ -570,6 +589,17 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen, return err? -1:0; /* FIXME: Return appropriate error code. */ } +static int +close_pcsc_reader (int slot) +{ + /* FIXME: Implement. */ + reader_table[slot].used = 0; + return 0; +} + + + + #ifdef HAVE_LIBUSB /* @@ -609,6 +639,15 @@ open_ccid_reader (void) return slot; } +static int +close_ccid_reader (int slot) +{ + ccid_close_reader (reader_table[slot].ccid.handle); + reader_table[slot].used = 0; + return 0; +} + + /* Actually send the APDU of length APDULEN to SLOT and return a maximum of *BUFLEN data in BUFFER, the actual returned size will be @@ -738,6 +777,16 @@ open_osc_reader (int portno) } +static int +close_osc_reader (int slot) +{ + /* FIXME: Implement. */ + reader_table[slot].used = 0; + return 0; +} + + + /* Actually send the APDU of length APDULEN to SLOT and return a maximum of *BUFLEN data in BUFFER, the actual returned size will be set to BUFLEN. Returns: OpenSC error code. */ @@ -940,6 +989,26 @@ apdu_open_reader (const char *portstr) } +int +apdu_close_reader (int slot) +{ + if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used ) + return SW_HOST_NO_DRIVER; + if (reader_table[slot].is_ctapi) + return close_ct_reader (slot); +#ifdef HAVE_LIBUSB + else if (reader_table[slot].is_ccid) + return close_ccid_reader (slot); +#endif +#ifdef HAVE_OPENSC + else if (reader_table[slot].is_osc) + return close_osc_reader (slot); +#endif + else + return close_pcsc_reader (slot); +} + + unsigned char * apdu_get_atr (int slot, size_t *atrlen) { diff --git a/scd/apdu.h b/scd/apdu.h index 6e4244ba0..21e2b9840 100644 --- a/scd/apdu.h +++ b/scd/apdu.h @@ -54,6 +54,7 @@ enum { /* Note , that apdu_open_reader returns no status word but -1 on error. */ int apdu_open_reader (const char *portstr); +int apdu_close_reader (int slot); unsigned char *apdu_get_atr (int slot, size_t *atrlen); diff --git a/scd/app-common.h b/scd/app-common.h index 33f23127b..de1e02cac 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -65,6 +65,9 @@ struct app_ctx_s { const char *chvnostr, int reset_mode, int (*pincb)(void*, const char *, char **), void *pincb_arg); + int (*check_pin) (APP app, const char *keyidstr, + int (pincb)(void*, const char *, char **), + void *pincb_arg); } fnc; @@ -106,6 +109,9 @@ int app_get_challenge (APP app, size_t nbytes, unsigned char *buffer); int app_change_pin (APP app, CTRL ctrl, const char *chvnostr, int reset_mode, int (*pincb)(void*, const char *, char **), void *pincb_arg); +int app_check_pin (APP app, const char *keyidstr, + int (*pincb)(void*, const char *, char **), + void *pincb_arg); /*-- app-openpgp.c --*/ diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 174d2e974..07abf9bfb 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -912,6 +912,33 @@ compare_fingerprint (APP app, int keyno, unsigned char *sha1fpr) } + /* If a fingerprint has been specified check it against the one on + the card. This is allows for a meaningful error message in case + the key on the card has been replaced but the shadow information + known to gpg was not updated. If there is no fingerprint we + assume that this is okay. */ +static int +check_against_given_fingerprint (APP app, const char *fpr, int keyno) +{ + unsigned char tmp[20]; + const char *s; + int n; + + for (s=fpr, n=0; hexdigitp (s); s++, n++) + ; + if (n != 40) + return gpg_error (GPG_ERR_INV_ID); + else if (!*s) + ; /* okay */ + else + return gpg_error (GPG_ERR_INV_ID); + + for (s=fpr, n=0; n < 20; s += 2, n++) + tmp[n] = xtoi_2 (s); + return compare_fingerprint (app, keyno, tmp); +} + + /* Compute a digital signature on INDATA which is expected to be the raw message digest. For this application the KEYIDSTR consists of @@ -976,23 +1003,9 @@ do_sign (APP app, const char *keyidstr, int hashalgo, known to gpg was not updated. If there is no fingerprint, gpg will detect a bogus signature anyway due to the verify-after-signing feature. */ - if (fpr) - { - for (s=fpr, n=0; hexdigitp (s); s++, n++) - ; - if (n != 40) - return gpg_error (GPG_ERR_INV_ID); - else if (!*s) - ; /* okay */ - else - return gpg_error (GPG_ERR_INV_ID); - - for (s=fpr, n=0; n < 20; s += 2, n++) - tmp_sn[n] = xtoi_2 (s); - rc = compare_fingerprint (app, 1, tmp_sn); - if (rc) - return rc; - } + rc = fpr? check_against_given_fingerprint (app, fpr, 1) : 0; + if (rc) + return rc; if (hashalgo == GCRY_MD_SHA1) memcpy (data, sha1_prefix, 15); @@ -1107,23 +1120,9 @@ do_auth (APP app, const char *keyidstr, known to gpg was not updated. If there is no fingerprint, gpg will detect a bogus signature anyway due to the verify-after-signing feature. */ - if (fpr) - { - for (s=fpr, n=0; hexdigitp (s); s++, n++) - ; - if (n != 40) - return gpg_error (GPG_ERR_INV_ID); - else if (!*s) - ; /* okay */ - else - return gpg_error (GPG_ERR_INV_ID); - - for (s=fpr, n=0; n < 20; s += 2, n++) - tmp_sn[n] = xtoi_2 (s); - rc = compare_fingerprint (app, 3, tmp_sn); - if (rc) - return rc; - } + rc = fpr? check_against_given_fingerprint (app, fpr, 3) : 0; + if (rc) + return rc; rc = verify_chv2 (app, pincb, pincb_arg); if (!rc) @@ -1177,23 +1176,9 @@ do_decipher (APP app, const char *keyidstr, the key on the card has been replaced but the shadow information known to gpg was not updated. If there is no fingerprint, the decryption will won't produce the right plaintext anyway. */ - if (fpr) - { - for (s=fpr, n=0; hexdigitp (s); s++, n++) - ; - if (n != 40) - return gpg_error (GPG_ERR_INV_ID); - else if (!*s) - ; /* okay */ - else - return gpg_error (GPG_ERR_INV_ID); - - for (s=fpr, n=0; n < 20; s += 2, n++) - tmp_sn[n] = xtoi_2 (s); - rc = compare_fingerprint (app, 2, tmp_sn); - if (rc) - return rc; - } + rc = fpr? check_against_given_fingerprint (app, fpr, 2) : 0; + if (rc) + return rc; rc = verify_chv2 (app, pincb, pincb_arg); if (!rc) @@ -1202,6 +1187,55 @@ do_decipher (APP app, const char *keyidstr, } +/* Perform a simple verify operation for CHV1 and CHV2, so that + further operations won't ask for CHV2 and it is possible to do a + cheap check on the PIN: If there is something wrong with the PIN + entry system, only the regular CHV will get blocked and not the + dangerous CHV3. KEYIDSTR is the usual card's serial number; an + optional fingerprint part will be ignored. */ +static int +do_check_pin (APP app, const char *keyidstr, + int (pincb)(void*, const char *, char **), + void *pincb_arg) +{ + unsigned char tmp_sn[20]; + const char *s; + int n; + + if (!keyidstr || !*keyidstr) + return gpg_error (GPG_ERR_INV_VALUE); + + /* Check whether an OpenPGP card of any version has been requested. */ + if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12)) + return gpg_error (GPG_ERR_INV_ID); + + for (s=keyidstr, n=0; hexdigitp (s); s++, n++) + ; + if (n != 32) + return gpg_error (GPG_ERR_INV_ID); + else if (!*s) + ; /* No fingerprint given: we allow this for now. */ + else if (*s == '/') + ; /* We ignore a fingerprint. */ + else + return gpg_error (GPG_ERR_INV_ID); + + for (s=keyidstr, n=0; n < 16; s += 2, n++) + tmp_sn[n] = xtoi_2 (s); + + if (app->serialnolen != 16) + return gpg_error (GPG_ERR_INV_CARD); + if (memcmp (app->serialno, tmp_sn, 16)) + return gpg_error (GPG_ERR_WRONG_CARD); + /* Yes, there is a race conditions: The user might pull the card + right here and we won't notice that. However this is not a + problem and the check above is merely for a graceful failure + between operations. */ + + return verify_chv2 (app, pincb, pincb_arg); +} + + /* Select the OpenPGP application on the card in SLOT. This function @@ -1262,6 +1296,7 @@ app_select_openpgp (APP app, unsigned char **sn, size_t *snlen) app->fnc.auth = do_auth; app->fnc.decipher = do_decipher; app->fnc.change_pin = do_change_pin; + app->fnc.check_pin = do_check_pin; } leave: diff --git a/scd/app.c b/scd/app.c index 5b0340b89..1f142ea32 100644 --- a/scd/app.c +++ b/scd/app.c @@ -295,6 +295,29 @@ app_change_pin (APP app, CTRL ctrl, const char *chvnostr, int reset_mode, } +/* Perform a VERIFY operation without doing anything lese. This may + be used to initialze a the PION cache for long lasting other + operations. Its use is highly application dependent. */ +int +app_check_pin (APP app, const char *keyidstr, + int (*pincb)(void*, const char *, char **), + void *pincb_arg) +{ + int rc; + + if (!app || !keyidstr || !*keyidstr || !pincb) + return gpg_error (GPG_ERR_INV_VALUE); + if (!app->initialized) + return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); + if (!app->fnc.check_pin) + return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); + rc = app->fnc.check_pin (app, keyidstr, pincb, pincb_arg); + if (opt.verbose) + log_info ("operation check_pin result: %s\n", gpg_strerror (rc)); + return rc; +} + + diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c index 35f0329db..f14600cc2 100644 --- a/scd/ccid-driver.c +++ b/scd/ccid-driver.c @@ -174,6 +174,12 @@ struct ccid_driver_s { }; +static int bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen); +static int bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length, + size_t *nread, int expected_type, int seqno); + + + /* Convert a little endian stored 4 byte value into an unsigned integer. */ static unsigned int @@ -182,6 +188,16 @@ convert_le_u32 (const unsigned char *buf) return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); } +static void +set_msg_len (unsigned char *msg, unsigned int length) +{ + msg[1] = length; + msg[2] = length >> 8; + msg[3] = length >> 16; + msg[4] = length >> 24; +} + + /* Parse a CCID descriptor, optionally print all available features @@ -482,22 +498,47 @@ ccid_open_reader (ccid_driver_t *handle, int readerno) } -/* Return False if a card is present and powered. */ -int -ccid_check_card_presence (ccid_driver_t handle) +/* Close the reader HANDLE. */ +int +ccid_close_reader (ccid_driver_t handle) { + if (!handle || !handle->idev) + return 0; - return -1; + { + int rc; + unsigned char msg[100]; + size_t msglen; + unsigned char seqno; + + msg[0] = PC_to_RDR_IccPowerOff; + msg[5] = 0; /* slot */ + msg[6] = seqno = handle->seqno++; + msg[7] = 0; /* RFU */ + msg[8] = 0; /* RFU */ + msg[9] = 0; /* RFU */ + set_msg_len (msg, 0); + msglen = 10; + + rc = bulk_out (handle, msg, msglen); + if (!rc) + bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus, seqno); + } + + usb_release_interface (handle->idev, 0); + usb_close (handle->idev); + handle->idev = NULL; + free (handle); + return 0; } -static void -set_msg_len (unsigned char *msg, unsigned int length) +/* Return False if a card is present and powered. */ +int +ccid_check_card_presence (ccid_driver_t handle) { - msg[1] = length; - msg[2] = length >> 8; - msg[3] = length >> 16; - msg[4] = length >> 24; + + return -1; } diff --git a/scd/ccid-driver.h b/scd/ccid-driver.h index 4d12d88c2..e33be55d9 100644 --- a/scd/ccid-driver.h +++ b/scd/ccid-driver.h @@ -60,6 +60,7 @@ struct ccid_driver_s; typedef struct ccid_driver_s *ccid_driver_t; int ccid_open_reader (ccid_driver_t *handle, int readerno); +int ccid_close_reader (ccid_driver_t handle); int ccid_get_atr (ccid_driver_t handle, unsigned char *atr, size_t maxatrlen, size_t *atrlen); int ccid_transceive (ccid_driver_t handle, diff --git a/scd/command.c b/scd/command.c index fc5efa708..8808b10e9 100644 --- a/scd/command.c +++ b/scd/command.c @@ -923,6 +923,41 @@ cmd_passwd (ASSUAN_CONTEXT ctx, char *line) } +/* CHECKPIN + + */ +static int +cmd_checkpin (ASSUAN_CONTEXT ctx, char *line) +{ + CTRL ctrl = assuan_get_pointer (ctx); + int rc; + char *keyidstr; + + if ((rc = open_card (ctrl))) + return rc; + + if (!ctrl->app_ctx) + return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); + + /* We have to use a copy of the key ID because the function may use + the pin_cb which in turn uses the assuan line buffer and thus + overwriting the original line with the keyid. */ + keyidstr = xtrystrdup (line); + if (!keyidstr) + return ASSUAN_Out_Of_Core; + + rc = app_check_pin (ctrl->app_ctx, + keyidstr, + pin_cb, ctx); + xfree (keyidstr); + if (rc) + log_error ("app_check_pin failed: %s\n", gpg_strerror (rc)); + + return map_to_assuan_status (rc); +} + + + /* Tell the assuan library about our commands */ @@ -948,6 +983,7 @@ register_commands (ASSUAN_CONTEXT ctx) { "GENKEY", cmd_genkey }, { "RANDOM", cmd_random }, { "PASSWD", cmd_passwd }, + { "CHECKPIN", cmd_checkpin }, { NULL } }; int i, rc; -- cgit From 7134af9fdb194ae8291775fed78cd1a82eaaa41b Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 1 Dec 2003 10:54:09 +0000 Subject: * scdaemon.c, scdaemon.h: New options --allow-admin and --deny-admin. * app-openpgp.c (verify_chv3): Check it here. --- scd/ChangeLog | 5 +++++ scd/app-openpgp.c | 6 ++++++ scd/scdaemon.c | 9 +++++++-- scd/scdaemon.h | 2 ++ 4 files changed, 20 insertions(+), 2 deletions(-) (limited to 'scd/app-openpgp.c') diff --git a/scd/ChangeLog b/scd/ChangeLog index cccd3b669..873691f63 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,8 @@ +2003-11-17 Werner Koch + + * scdaemon.c, scdaemon.h: New options --allow-admin and --deny-admin. + * app-openpgp.c (verify_chv3): Check it here. + 2003-11-12 Werner Koch Adjusted for API changes in Libksba. diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 07abf9bfb..6b4a2f7ef 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -569,6 +569,12 @@ verify_chv3 (APP app, { int rc = 0; + if (!opt.allow_admin) + { + log_info ("access to admin commands is not configured\n"); + return gpg_error (GPG_ERR_EACCES); + } + if (!app->did_chv3) { char *pinvalue; diff --git a/scd/scdaemon.c b/scd/scdaemon.c index 89be04ab5..a3100988b 100644 --- a/scd/scdaemon.c +++ b/scd/scdaemon.c @@ -73,6 +73,8 @@ enum cmd_and_opt_values opcscDriver, oDisableCCID, oDisableOpenSC, + oAllowAdmin, + oDenyAdmin, aTest }; @@ -112,8 +114,8 @@ static ARGPARSE_OPTS opts[] = { "@" #endif /* end --disable-opensc */}, - - + { oAllowAdmin, "allow-admin", 0, N_("allow the use of admin card commands")}, + { oDenyAdmin, "deny-admin", 0, "@" }, {0} }; @@ -397,6 +399,9 @@ main (int argc, char **argv ) case oDisableCCID: opt.disable_ccid = 1; break; case oDisableOpenSC: opt.disable_opensc = 1; break; + case oAllowAdmin: opt.allow_admin = 1; break; + case oDenyAdmin: opt.allow_admin = 0; break; + default : pargs.err = configfp? 1:2; break; } } diff --git a/scd/scdaemon.h b/scd/scdaemon.h index 43c3189b3..e13377af7 100644 --- a/scd/scdaemon.h +++ b/scd/scdaemon.h @@ -57,6 +57,8 @@ struct { const char *pcsc_driver; /* Library to access the PC/SC system. */ int disable_opensc; /* Disable the use of the OpenSC framework. */ int disable_ccid; /* Disable the use of the internal CCID driver. */ + int allow_admin; /* Allow the use of admin commands for certain + cards. */ } opt; -- cgit From 28db0fabb4edf65ad1c5bec061c19c9922be9b23 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 23 Dec 2003 10:25:24 +0000 Subject: * apdu.c (apdu_send_le): Send a get_response with the indicated length and not the 64 bytes we used for testing. * app-openpgp.c (verify_chv2, verify_chv3, do_sign): Check the minimum length of the passphrase, so that we don't need to decrement the retry counter. --- scd/ChangeLog | 9 +++++++++ scd/apdu.c | 2 +- scd/app-openpgp.c | 21 +++++++++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) (limited to 'scd/app-openpgp.c') diff --git a/scd/ChangeLog b/scd/ChangeLog index 60b5f8eb9..0862d356b 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,12 @@ +2003-12-19 Werner Koch + + * apdu.c (apdu_send_le): Send a get_response with the indicated + length and not the 64 bytes we used for testing. + + * app-openpgp.c (verify_chv2, verify_chv3, do_sign): Check the + minimum length of the passphrase, so that we don't need to + decrement the retry counter. + 2003-12-17 Werner Koch * card-p15.c (p15_enum_keypairs): Replaced KRC by RC. diff --git a/scd/apdu.c b/scd/apdu.c index 27304c8b5..02038b65c 100644 --- a/scd/apdu.c +++ b/scd/apdu.c @@ -1207,7 +1207,7 @@ apdu_send_le(int slot, int class, int ins, int p0, int p1, apdu[apdulen++] = 0xC0; apdu[apdulen++] = 0; apdu[apdulen++] = 0; - apdu[apdulen++] = 64; /* that is 256 bytes for Le */ + apdu[apdulen++] = len; memset (apdu+apdulen, 0, sizeof (apdu) - apdulen); rc = send_apdu (slot, apdu, apdulen, result, &resultlen); if (rc || resultlen < 2) diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 6b4a2f7ef..8f9a303fe 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -534,6 +534,13 @@ verify_chv2 (APP app, return rc; } + if (strlen (pinvalue) < 6) + { + log_error ("prassphrase (CHV2) is too short; minimum length is 6\n"); + xfree (pinvalue); + return gpg_error (GPG_ERR_BAD_PIN); + } + rc = iso7816_verify (app->slot, 0x82, pinvalue, strlen (pinvalue)); if (rc) { @@ -586,6 +593,13 @@ verify_chv3 (APP app, return rc; } + if (strlen (pinvalue) < 6) + { + log_error ("prassphrase (CHV3) is too short; minimum length is 6\n"); + xfree (pinvalue); + return gpg_error (GPG_ERR_BAD_PIN); + } + rc = iso7816_verify (app->slot, 0x83, pinvalue, strlen (pinvalue)); xfree (pinvalue); if (rc) @@ -1041,6 +1055,13 @@ do_sign (APP app, const char *keyidstr, int hashalgo, return rc; } + if (strlen (pinvalue) < 6) + { + log_error ("prassphrase (CHV1) is too short; minimum length is 6\n"); + xfree (pinvalue); + return gpg_error (GPG_ERR_BAD_PIN); + } + rc = iso7816_verify (app->slot, 0x81, pinvalue, strlen (pinvalue)); if (rc) { -- cgit From eb24d8b751750cf96cb200f80b45ed3806648883 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 27 Jan 2004 16:40:42 +0000 Subject: Some minor bug fixes, new test utilities and started support for other smartcard applications. --- ChangeLog | 4 + README | 4 +- TODO | 1 + agent/ChangeLog | 6 +- agent/Makefile.am | 3 +- agent/sexp-parse.h | 99 ---- common/ChangeLog | 6 + common/Makefile.am | 1 + common/sexp-parse.h | 99 ++++ common/util.h | 3 +- configure.ac | 2 +- scd/ChangeLog | 65 +++ scd/Makefile.am | 24 +- scd/apdu.c | 2 +- scd/apdu.h | 5 +- scd/app-common.h | 70 +-- scd/app-dinsig.c | 129 ++++++ scd/app-nks.c | 388 ++++++++++++++++ scd/app-openpgp.c | 139 ++---- scd/app.c | 131 ++++-- scd/card.c | 6 +- scd/ccid-driver.c | 9 +- scd/command.c | 127 ++++-- scd/iso7816.c | 192 +++++++- scd/iso7816.h | 8 + scd/sc-copykeys.c | 2 +- scd/sc-investigate.c | 480 ++++++++++++++++++-- scd/scdaemon.c | 4 +- scd/scdaemon.h | 3 + scd/tlv.c | 219 +++++++++ scd/tlv.h | 84 ++++ tools/gpgparsemail.c | 705 ++++++++++++++++++++++++++++ tools/rfc822parse.c | 1235 ++++++++++++++++++++++++++++++++++++++++++++++++++ tools/rfc822parse.h | 79 ++++ 34 files changed, 3959 insertions(+), 375 deletions(-) delete mode 100644 agent/sexp-parse.h create mode 100644 common/sexp-parse.h create mode 100644 scd/app-dinsig.c create mode 100644 scd/app-nks.c create mode 100644 scd/tlv.c create mode 100644 scd/tlv.h create mode 100644 tools/gpgparsemail.c create mode 100644 tools/rfc822parse.c create mode 100644 tools/rfc822parse.h (limited to 'scd/app-openpgp.c') diff --git a/ChangeLog b/ChangeLog index 0752eec64..84abc4dee 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2004-01-24 Werner Koch + + * configure.ac: Now requires libassuan 0.6.3. + 2003-12-23 Werner Koch Released 1.9.3. diff --git a/README b/README index 42099d6f6..84fc8967b 100644 --- a/README +++ b/README @@ -138,8 +138,8 @@ gpgsm: --with-key-data - Displays extra information with the --list-keys commands. Especiall - a line tagged "grp" si printed which tells you the keygrip of a + Displays extra information with the --list-keys commands. Especially + a line tagged "grp" is printed which tells you the keygrip of a key. This is string is for example used as the filename of the secret key. diff --git a/TODO b/TODO index 12fd998aa..621b278ba 100644 --- a/TODO +++ b/TODO @@ -52,6 +52,7 @@ might want to have an agent context for each service request * agent/protect-tool.c ** Export and import certificates along with the secret key. ** Make it more comfortable; i.e. copy files to the correct place. +** BUG? --p12-export seems to work only with unprotected keys * Move pkcs-1 encoding into libgcrypt. diff --git a/agent/ChangeLog b/agent/ChangeLog index bd009ecbe..57f9214f6 100644 --- a/agent/ChangeLog +++ b/agent/ChangeLog @@ -1,3 +1,7 @@ +2004-01-27 Werner Koch + + * sexp-parse.h: Moved to ../common. + 2004-01-24 Werner Koch * call-scd.c (atfork_cb): New. @@ -437,7 +441,7 @@ * protect.c (agent_get_shadow_info): New. * protect.c (snext,sskip,smatch): Moved to - * sexp-parse.h: new file. + * sexp-parse.h: New file. * divert-scd.c: New. 2002-02-27 Werner Koch diff --git a/agent/Makefile.am b/agent/Makefile.am index 400aa2fd2..65af03368 100644 --- a/agent/Makefile.am +++ b/agent/Makefile.am @@ -41,8 +41,7 @@ gpg_agent_SOURCES = \ trustlist.c \ divert-scd.c \ call-scd.c \ - learncard.c \ - sexp-parse.h + learncard.c gpg_agent_LDADD = ../jnlib/libjnlib.a ../common/libcommon.a \ diff --git a/agent/sexp-parse.h b/agent/sexp-parse.h deleted file mode 100644 index 89aa7210f..000000000 --- a/agent/sexp-parse.h +++ /dev/null @@ -1,99 +0,0 @@ -/* sexp-parse.h - S-Exp helper functions - * Copyright (C) 2002, 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 - */ - -#ifndef SEXP_PARSE_H -#define SEXP_PARSE_H - -#include - -/* Return the length of the next S-Exp part and update the pointer to - the first data byte. 0 is returned on error */ -static inline size_t -snext (unsigned char const **buf) -{ - const unsigned char *s; - int n; - - s = *buf; - for (n=0; *s && *s != ':' && (*s >= '0' && *s <= '9'); s++) - n = n*10 + (*s - '0'); - if (!n || *s != ':') - return 0; /* we don't allow empty lengths */ - *buf = s+1; - return n; -} - -/* Skip over the S-Expression BUF points to and update BUF to point to - the chacter right behind. DEPTH gives the initial number of open - lists and may be passed as a positive number to skip over the - remainder of an S-Expression if the current position is somewhere - in an S-Expression. The function may return an error code if it - encounters an impossible conditions */ -static inline gpg_error_t -sskip (unsigned char const **buf, int *depth) -{ - const unsigned char *s = *buf; - size_t n; - int d = *depth; - - while (d > 0) - { - if (*s == '(') - { - d++; - s++; - } - else if (*s == ')') - { - d--; - s++; - } - else - { - if (!d) - return gpg_error (GPG_ERR_INV_SEXP); - n = snext (&s); - if (!n) - return gpg_error (GPG_ERR_INV_SEXP); - s += n; - } - } - *buf = s; - *depth = d; - return 0; -} - - -/* Check whether the the string at the address BUF points to matches - the token. Return true on match and update BUF to point behind the - token. Return false and dont update tha buffer if it does not - match. */ -static inline int -smatch (unsigned char const **buf, size_t buflen, const char *token) -{ - size_t toklen = strlen (token); - - if (buflen != toklen || memcmp (*buf, token, toklen)) - return 0; - *buf += toklen; - return 1; -} - -#endif /*SEXP_PARSE_H*/ diff --git a/common/ChangeLog b/common/ChangeLog index 1b454fa13..8e5c615d9 100644 --- a/common/ChangeLog +++ b/common/ChangeLog @@ -1,3 +1,9 @@ +2004-01-27 Werner Koch + + * sexp-parse.h: New; moved from../agent. + + * util.h (xtoi_4): New. + 2003-12-23 Werner Koch * maperror.c (map_assuan_err): Prepared for a new error code. diff --git a/common/Makefile.am b/common/Makefile.am index 79dedca34..770ed12d6 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -29,6 +29,7 @@ AM_CPPFLAGS = $(LIBGCRYPT_CFLAGS) $(KSBA_CFLAGS) libcommon_a_SOURCES = \ util.h i18n.h \ errors.h \ + sexp-parse.h \ maperror.c \ sysutils.c sysutils.h \ gettime.c \ diff --git a/common/sexp-parse.h b/common/sexp-parse.h new file mode 100644 index 000000000..89aa7210f --- /dev/null +++ b/common/sexp-parse.h @@ -0,0 +1,99 @@ +/* sexp-parse.h - S-Exp helper functions + * Copyright (C) 2002, 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 + */ + +#ifndef SEXP_PARSE_H +#define SEXP_PARSE_H + +#include + +/* Return the length of the next S-Exp part and update the pointer to + the first data byte. 0 is returned on error */ +static inline size_t +snext (unsigned char const **buf) +{ + const unsigned char *s; + int n; + + s = *buf; + for (n=0; *s && *s != ':' && (*s >= '0' && *s <= '9'); s++) + n = n*10 + (*s - '0'); + if (!n || *s != ':') + return 0; /* we don't allow empty lengths */ + *buf = s+1; + return n; +} + +/* Skip over the S-Expression BUF points to and update BUF to point to + the chacter right behind. DEPTH gives the initial number of open + lists and may be passed as a positive number to skip over the + remainder of an S-Expression if the current position is somewhere + in an S-Expression. The function may return an error code if it + encounters an impossible conditions */ +static inline gpg_error_t +sskip (unsigned char const **buf, int *depth) +{ + const unsigned char *s = *buf; + size_t n; + int d = *depth; + + while (d > 0) + { + if (*s == '(') + { + d++; + s++; + } + else if (*s == ')') + { + d--; + s++; + } + else + { + if (!d) + return gpg_error (GPG_ERR_INV_SEXP); + n = snext (&s); + if (!n) + return gpg_error (GPG_ERR_INV_SEXP); + s += n; + } + } + *buf = s; + *depth = d; + return 0; +} + + +/* Check whether the the string at the address BUF points to matches + the token. Return true on match and update BUF to point behind the + token. Return false and dont update tha buffer if it does not + match. */ +static inline int +smatch (unsigned char const **buf, size_t buflen, const char *token) +{ + size_t toklen = strlen (token); + + if (buflen != toklen || memcmp (*buf, token, toklen)) + return 0; + *buf += toklen; + return 1; +} + +#endif /*SEXP_PARSE_H*/ diff --git a/common/util.h b/common/util.h index 80a1d01a6..7e134e846 100644 --- a/common/util.h +++ b/common/util.h @@ -134,13 +134,14 @@ int asprintf (char **result, const char *format, ...) JNLIB_GCC_A_PRINTF(2,3); \v, but works for the purposes used here. */ #define ascii_isspace(a) ((a)==' ' || (a)=='\n' || (a)=='\r' || (a)=='\t') -/* the atoi macros assume that the buffer has only valid digits */ +/* The atoi macros assume that the buffer has only valid digits. */ #define atoi_1(p) (*(p) - '0' ) #define atoi_2(p) ((atoi_1(p) * 10) + atoi_1((p)+1)) #define atoi_4(p) ((atoi_2(p) * 100) + atoi_2((p)+2)) #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \ *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10)) #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1)) +#define xtoi_4(p) ((xtoi_2(p) * 256) + xtoi_2((p)+2)) diff --git a/configure.ac b/configure.ac index b0c8f2379..cd0486f4b 100644 --- a/configure.ac +++ b/configure.ac @@ -31,7 +31,7 @@ AC_INIT(gnupg, 1.9.4-cvs, gnupg-devel@gnupg.org) development_version=yes NEED_GPG_ERROR_VERSION=0.6 NEED_LIBGCRYPT_VERSION=1.1.91 -NEED_LIBASSUAN_VERSION=0.6.2 +NEED_LIBASSUAN_VERSION=0.6.3 NEED_KSBA_VERSION=0.9.1 NEED_OPENSC_VERSION=0.8.0 diff --git a/scd/ChangeLog b/scd/ChangeLog index 0862d356b..3a6a6aea4 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,68 @@ +2004-01-27 Werner Koch + + * command.c (cmd_readcert, cmd_readkey): Work on a copy of LINE. + + * app-common.h (app_ctx_s): Added readcert field. + * app.c (app_readcert): New. + * tlv.c (parse_ber_header): Added; taken from libksba. + +2004-01-26 Werner Koch + + * card.c (map_sc_err): Use SCD as the error source. + + * command.c (open_card): ADD arg NAME to allow requesting a + specific application. Changed all callers. + (cmd_serialno): Allow optional argument to select the desired + application. + + * app-nks.c: New. + + * scdaemon.h (opt): Add READER_PORT. + * scdaemon.c (main): Set it here. + * app.c (app_set_default_reader_port): Removed. + (select_application): Add NAME arg and figure out a + default serial number from the GDO. Add SLOT arg and remove all + reader management. + (release_application): New. + (app_write_learn_status): Output an APPTYPE status line. + * command.c (open_card): Adapt for select_application change. + * app-openpgp.c (app_select_openpgp): Removed SN and SNLEN args + and set it directly. Changed all callers. + +2004-01-25 Werner Koch + + * iso7816.c (iso7816_select_application): P1 kludge for OpenPGP + card. + * app-openpgp.c (find_tlv): Factor out this function to .. + * tlv.c, tlv.h: .. new. + + * scdaemon.h: Introduced app_t and ctrl_t as the new types for APP + and CTRL. + +2004-01-21 Werner Koch + + * apdu.c (apdu_send_le): Treat SW_EOF_REACHED as a warning. + +2004-01-20 Werner Koch + + * iso7816.c (iso7816_read_binary): New. + (iso7816_select_file): New. + (iso7816_list_directory): New. + + * sc-investigate.c: Add option -i. + (select_app, read_line, interactive_shell): New. + +2004-01-16 Werner Koch + + * apdu.h: Add SW_FILE_NOT_FOUND. + * iso7816.c (map_sw): Map it to GPG_ERR_ENOENT. + * iso7816.c (iso7816_select_file): New. + + * app-dinsig.c: New file w/o any real code yet. + * Makefile.am (scdaemon_SOURCES,sc_investigate_SOURCES): Add file. + + * sc-investigate.c: Add option --disable-ccid. + 2003-12-19 Werner Koch * apdu.c (apdu_send_le): Send a get_response with the indicated diff --git a/scd/Makefile.am b/scd/Makefile.am index a2ecd3a81..c8bf3d0de 100644 --- a/scd/Makefile.am +++ b/scd/Makefile.am @@ -26,6 +26,8 @@ bin_PROGRAMS = scdaemon sc-investigate sc-copykeys AM_CPPFLAGS = -I$(top_srcdir)/common $(OPENSC_CFLAGS) $(LIBGCRYPT_CFLAGS) \ $(KSBA_CFLAGS) $(LIBASSUAN_CFLAGS) +card_apps = app-openpgp.c app-nks.c app-dinsig.c + scdaemon_SOURCES = \ scdaemon.c scdaemon.h \ command.c card.c \ @@ -34,8 +36,9 @@ scdaemon_SOURCES = \ apdu.c apdu.h \ ccid-driver.c ccid-driver.h \ iso7816.c iso7816.h \ - app.c app-common.h \ - app-openpgp.c + tlv.c tlv.h \ + app.c app-common.h $(card_apps) + scdaemon_LDADD = ../jnlib/libjnlib.a ../common/libcommon.a \ $(OPENSC_LIBS) $(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(LIBASSUAN_LIBS) \ @@ -46,9 +49,9 @@ sc_investigate_SOURCES = \ apdu.c apdu.h \ ccid-driver.c ccid-driver.h \ iso7816.c iso7816.h \ - app.c app-common.h \ - app-openpgp.c \ - atr.c atr.h + tlv.c tlv.h \ + atr.c atr.h \ + app.c app-common.h $(card_apps) sc_investigate_LDADD = \ ../jnlib/libjnlib.a ../common/libcommon.a \ @@ -61,17 +64,12 @@ sc_copykeys_SOURCES = \ apdu.c apdu.h \ ccid-driver.c ccid-driver.h \ iso7816.c iso7816.h \ - app.c app-common.h \ - app-openpgp.c \ - atr.c atr.h + tlv.c tlv.h \ + atr.c atr.h \ + app.c app-common.h $(card_apps) sc_copykeys_LDADD = \ ../jnlib/libjnlib.a ../common/libcommon.a \ ../common/libsimple-pwquery.a \ $(OPENSC_LIBS) $(LIBGCRYPT_LIBS) $(LIBUSB_LIBS) \ -lgpg-error @INTLLIBS@ -ldl - - - - - diff --git a/scd/apdu.c b/scd/apdu.c index 02038b65c..e5295f566 100644 --- a/scd/apdu.c +++ b/scd/apdu.c @@ -1168,7 +1168,7 @@ apdu_send_le(int slot, int class, int ins, int p0, int p1, log_printhex (" dump: ", result, resultlen); } - if (sw == SW_SUCCESS) + if (sw == SW_SUCCESS || sw == SW_EOF_REACHED) { if (retbuf) { diff --git a/scd/apdu.h b/scd/apdu.h index 21e2b9840..fd7634f13 100644 --- a/scd/apdu.h +++ b/scd/apdu.h @@ -27,13 +27,16 @@ enum { SW_MORE_DATA = 0x6100, /* Note: that the low byte must be masked of.*/ + SW_EOF_REACHED = 0x6282, SW_EEPROM_FAILURE = 0x6581, SW_WRONG_LENGTH = 0x6700, SW_CHV_WRONG = 0x6982, SW_CHV_BLOCKED = 0x6983, SW_USE_CONDITIONS = 0x6985, - SW_NOT_SUPPORTED = 0x6a81, SW_BAD_PARAMETER = 0x6a80, /* (in the data field) */ + SW_NOT_SUPPORTED = 0x6a81, + SW_FILE_NOT_FOUND = 0x6a82, + SW_RECORD_NOT_FOUND = 0x6a83, SW_REF_NOT_FOUND = 0x6a88, SW_BAD_P0_P1 = 0x6b00, SW_INS_NOT_SUP = 0x6d00, diff --git a/scd/app-common.h b/scd/app-common.h index de1e02cac..cda17700f 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -29,43 +29,46 @@ struct app_ctx_s { int slot; /* Used reader. */ unsigned char *serialno; /* Serialnumber in raw form, allocated. */ size_t serialnolen; /* Length in octets of serialnumber. */ + const char *apptype; unsigned int card_version; int did_chv1; int force_chv1; /* True if the card does not cache CHV1. */ int did_chv2; int did_chv3; struct { - int (*learn_status) (APP app, CTRL ctrl); - int (*getattr) (APP app, CTRL ctrl, const char *name); - int (*setattr) (APP app, const char *name, + int (*learn_status) (app_t app, ctrl_t ctrl); + int (*readcert) (app_t app, const char *certid, + unsigned char **cert, size_t *certlen); + int (*getattr) (app_t app, ctrl_t ctrl, const char *name); + int (*setattr) (app_t app, const char *name, int (*pincb)(void*, const char *, char **), void *pincb_arg, const unsigned char *value, size_t valuelen); - int (*sign) (APP app, + int (*sign) (app_t app, const char *keyidstr, int hashalgo, int (pincb)(void*, const char *, char **), void *pincb_arg, const void *indata, size_t indatalen, unsigned char **outdata, size_t *outdatalen ); - int (*auth) (APP app, const char *keyidstr, + int (*auth) (app_t app, const char *keyidstr, int (*pincb)(void*, const char *, char **), void *pincb_arg, const void *indata, size_t indatalen, unsigned char **outdata, size_t *outdatalen); - int (*decipher) (APP app, const char *keyidstr, + int (*decipher) (app_t app, const char *keyidstr, int (pincb)(void*, const char *, char **), void *pincb_arg, const void *indata, size_t indatalen, unsigned char **outdata, size_t *outdatalen); - int (*genkey) (APP app, CTRL ctrl, + int (*genkey) (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags, int (*pincb)(void*, const char *, char **), void *pincb_arg); - int (*change_pin) (APP app, CTRL ctrl, + int (*change_pin) (app_t app, ctrl_t ctrl, const char *chvnostr, int reset_mode, int (*pincb)(void*, const char *, char **), void *pincb_arg); - int (*check_pin) (APP app, const char *keyidstr, + int (*check_pin) (app_t app, const char *keyidstr, int (pincb)(void*, const char *, char **), void *pincb_arg); } fnc; @@ -74,66 +77,77 @@ struct app_ctx_s { }; #if GNUPG_MAJOR_VERSION == 1 -int app_select_openpgp (APP app, unsigned char **sn, size_t *snlen); -int app_get_serial_and_stamp (APP app, char **serial, time_t *stamp); +int app_select_openpgp (app_t app); +int app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp); #else /*-- app.c --*/ -void app_set_default_reader_port (const char *portstr); -APP select_application (void); -int app_get_serial_and_stamp (APP app, char **serial, time_t *stamp); -int app_write_learn_status (APP app, CTRL ctrl); -int app_getattr (APP app, CTRL ctrl, const char *name); -int app_setattr (APP app, const char *name, +app_t select_application (ctrl_t ctrl, int slot, const char *name); +void release_application (app_t app); +int app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp); +int app_write_learn_status (app_t app, ctrl_t ctrl); +int app_readcert (app_t app, const char *certid, + unsigned char **cert, size_t *certlen); +int app_getattr (app_t app, ctrl_t ctrl, const char *name); +int app_setattr (app_t app, const char *name, int (*pincb)(void*, const char *, char **), void *pincb_arg, const unsigned char *value, size_t valuelen); -int app_sign (APP app, const char *keyidstr, int hashalgo, +int app_sign (app_t app, const char *keyidstr, int hashalgo, int (pincb)(void*, const char *, char **), void *pincb_arg, const void *indata, size_t indatalen, unsigned char **outdata, size_t *outdatalen ); -int app_auth (APP app, const char *keyidstr, +int app_auth (app_t app, const char *keyidstr, int (*pincb)(void*, const char *, char **), void *pincb_arg, const void *indata, size_t indatalen, unsigned char **outdata, size_t *outdatalen); -int app_decipher (APP app, const char *keyidstr, +int app_decipher (app_t app, const char *keyidstr, int (pincb)(void*, const char *, char **), void *pincb_arg, const void *indata, size_t indatalen, unsigned char **outdata, size_t *outdatalen ); -int app_genkey (APP app, CTRL ctrl, const char *keynostr, unsigned int flags, +int app_genkey (app_t app, ctrl_t ctrl, + const char *keynostr, unsigned int flags, int (*pincb)(void*, const char *, char **), void *pincb_arg); -int app_get_challenge (APP app, size_t nbytes, unsigned char *buffer); -int app_change_pin (APP app, CTRL ctrl, const char *chvnostr, int reset_mode, +int app_get_challenge (app_t app, size_t nbytes, unsigned char *buffer); +int app_change_pin (app_t app, ctrl_t ctrl, + const char *chvnostr, int reset_mode, int (*pincb)(void*, const char *, char **), void *pincb_arg); -int app_check_pin (APP app, const char *keyidstr, +int app_check_pin (app_t app, const char *keyidstr, int (*pincb)(void*, const char *, char **), void *pincb_arg); /*-- app-openpgp.c --*/ -int app_select_openpgp (APP app, unsigned char **sn, size_t *snlen); +int app_select_openpgp (app_t app); -int app_openpgp_cardinfo (APP app, +int app_openpgp_cardinfo (app_t app, char **serialno, char **disp_name, char **pubkey_url, unsigned char **fpr1, unsigned char **fpr2, unsigned char **fpr3); -int app_openpgp_storekey (APP app, int keyno, +int app_openpgp_storekey (app_t app, int keyno, unsigned char *template, size_t template_len, time_t created_at, const unsigned char *m, size_t mlen, const unsigned char *e, size_t elen, int (*pincb)(void*, const char *, char **), void *pincb_arg); -int app_openpgp_readkey (APP app, int keyno, +int app_openpgp_readkey (app_t app, int keyno, unsigned char **m, size_t *mlen, unsigned char **e, size_t *elen); +/*-- app-nks.c --*/ +int app_select_nks (app_t app); + +/*-- app-dinsig.c --*/ +int app_select_dinsig (app_t app); + + #endif diff --git a/scd/app-dinsig.c b/scd/app-dinsig.c new file mode 100644 index 000000000..4b5b517eb --- /dev/null +++ b/scd/app-dinsig.c @@ -0,0 +1,129 @@ +/* app-dinsig.c - The DINSIG (DIN V 66291-1) card application. + * Copyright (C) 2004 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 + */ + + +/* The German signature law and its bylaw (SigG and SigV) is currently + used with an interface specification described in DIN V 66291-1. + The AID to be used is: 'D27600006601'. + + The file IDs for certificates utilize the generic format: + Cxyz + C being the hex digit 'C' (12). + x being the service indicator: + '0' := SigG conform digital signature. + '1' := entity authentication. + '2' := key encipherment. + '3' := data encipherment. + '4' := key agreement. + other values are reserved for future use. + y being the security environment number using '0' for cards + not supporting a SE number. + z being the certificate type: + '0' := C.CH (base certificate of card holder) or C.ICC. + '1' .. '7' := C.CH (business or professional certificate + of card holder. + '8' .. 'D' := C.CA (certificate of a CA issue by the Root-CA). + 'E' := C.RCA (self certified certificate of the Root-CA). + 'F' := reserved. + + The file IDs used by default are: + '1F00' EF.SSD (security service descriptor). [o,o] + '2F02' EF.GDO (global data objects) [m,m] + 'A000' EF.PROT (signature log). Cyclic file with 20 records of 53 byte. + Read and update after user authentication. [o,o] + 'B000' EF.PK.RCA.DS (public keys of Root-CA). Size is 512b or size + of keys. [m (unless a 'C00E' is present),m] + 'B001' EF.PK.CA.DS (public keys of CAs). Size is 512b or size + of keys. [o,o] + 'C00n' EF.C.CH.DS (digital signature certificate of card holder) + with n := 0 .. 7. Size is 2k or size of cert. Read and + update allowed after user authentication. [m,m] + 'C00m' EF.C.CA.DS (digital signature certificate of CA) + with m := 8 .. E. Size is 1k or size of cert. Read always + allowed, update after user authentication. [o,o] + 'C100' EF.C.ICC.AUT (AUT certificate of ICC) [o,m] + 'C108' EF.C.CA.AUT (AUT certificate of CA) [o,m] + 'D000' EF.DM (display message) [-,m] + + The letters in brackets indicate optional or mandatory files: The + first for card terminals under full control and the second for + "business" card terminals. + + FIXME: Needs a lot more explanation. + +*/ + + + + +#include +#include +#include +#include +#include +#include +#include + +#include "scdaemon.h" + +#include "iso7816.h" +#include "app-common.h" + + + +static int +do_learn_status (APP app, CTRL ctrl) +{ + return 0; +} + + + + + +/* Select the DINSIG application on the card in SLOT. This function + must be used before any other DINSIG application functions. */ +int +app_select_dinsig (APP app) +{ + static char const aid[] = { 0xD2, 0x76, 0x00, 0x00, 0x66, 0x01 }; + int slot = app->slot; + int rc; + + rc = iso7816_select_application (slot, aid, sizeof aid); + if (!rc) + { + app->apptype = "DINSIG"; + + app->fnc.learn_status = do_learn_status; + app->fnc.getattr = NULL; + app->fnc.setattr = NULL; + app->fnc.genkey = NULL; + app->fnc.sign = NULL; + app->fnc.auth = NULL; + app->fnc.decipher = NULL; + app->fnc.change_pin = NULL; + app->fnc.check_pin = NULL; + } + + return rc; +} + + diff --git a/scd/app-nks.c b/scd/app-nks.c new file mode 100644 index 000000000..0a04f7511 --- /dev/null +++ b/scd/app-nks.c @@ -0,0 +1,388 @@ +/* app-nks.c - The Telesec NKS 2.0 card application. + * Copyright (C) 2004 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 +#include +#include +#include +#include +#include +#include + +#include "scdaemon.h" + +#include "iso7816.h" +#include "app-common.h" +#include "tlv.h" + +static struct { + int fid; /* File ID. */ + int certtype; /* Type of certificate or 0 if it is not a certificate. */ + int iskeypair; /* If true has the FID of the correspoding certificate. */ +} filelist[] = { + { 0x4531, 0, 0xC000 }, + { 0xC000, 101 }, + { 0x4331, 100 }, + { 0x4332, 100 }, + { 0xB000, 110 }, + { 0x45B1, 0, 0xC200 }, + { 0xC200, 101 }, + { 0x43B1, 100 }, + { 0x43B2, 100 }, + { 0, 0 } +}; + + + +/* Given the slot and the File Id FID, return the length of the + certificate contained in that file. Returns 0 if the file does not + exists or does not contain a certificate. */ +static size_t +get_length_of_cert (int slot, int fid) +{ + gpg_error_t err; + unsigned char *buffer; + const unsigned char *p; + size_t buflen, n; + int class, tag, constructed, ndef; + size_t objlen, hdrlen; + + err = iso7816_select_file (slot, fid, 0, NULL, NULL); + if (err) + { + log_info ("error selecting FID 0x%04X: %s\n", fid, gpg_strerror (err)); + return 0; + } + + err = iso7816_read_binary (slot, 0, 32, &buffer, &buflen); + if (err) + { + log_info ("error reading certificate from FID 0x%04X: %s\n", + fid, gpg_strerror (err)); + return 0; + } + + if (!buflen || *buffer == 0xff) + { + log_info ("no certificate contained in FID 0x%04X\n", fid); + xfree (buffer); + return 0; + } + + p = buffer; + n = buflen; + err = parse_ber_header (&p, &n, &class, &tag, &constructed, + &ndef, &objlen, &hdrlen); + if (err) + { + log_info ("error parsing certificate in FID 0x%04X: %s\n", + fid, gpg_strerror (err)); + xfree (buffer); + return 0; + } + + /* All certificates should commence with a SEQUENCE expect fro the + special ROOT CA which are enclosed in a SET. */ + if ( !(class == CLASS_UNIVERSAL && constructed + && (tag == TAG_SEQUENCE || tag == TAG_SET))) + { + log_info ("contents of FID 0x%04X does not look like a certificate\n", + fid); + return 0; + } + + return objlen + hdrlen; +} + + + +/* Read the file with FID, assume it contains a public key and return + its keygrip in the caller provided 41 byte buffer R_GRIPSTR. */ +static gpg_error_t +keygripstr_from_pk_file (int slot, int fid, char *r_gripstr) +{ + gpg_error_t err; + unsigned char grip[20]; + unsigned char *buffer[2]; + size_t buflen[2]; + gcry_sexp_t sexp; + int i; + + err = iso7816_select_file (slot, fid, 0, NULL, NULL); + if (err) + return err; + err = iso7816_read_record (slot, 1, 1, &buffer[0], &buflen[0]); + if (err) + return err; + err = iso7816_read_record (slot, 2, 1, &buffer[1], &buflen[1]); + if (err) + { + xfree (buffer[0]); + return err; + } + + for (i=0; i < 2; i++) + { + /* Check that the value appears like an integer encoded as + Simple-TLV. We don't check the tag because the tests cards I + have use 1 for both, the modulus and the exponent - the + example in the documentation gives 2 for the exponent. */ + if (buflen[i] < 3) + err = gpg_error (GPG_ERR_TOO_SHORT); + else if (buffer[i][1] != buflen[i]-2 ) + err = gpg_error (GPG_ERR_INV_OBJ); + } + + if (!err) + err = gcry_sexp_build (&sexp, NULL, + "(public-key (rsa (n %b) (e %b)))", + (int)buflen[0]-2, buffer[0]+2, + (int)buflen[1]-2, buffer[1]+2); + + xfree (buffer[0]); + xfree (buffer[1]); + if (err) + return err; + + if (!gcry_pk_get_keygrip (sexp, grip)) + { + err = gpg_error (GPG_ERR_INTERNAL); /* i.e. RSA not supported by + libgcrypt. */ + } + else + { + for (i=0; i < 20; i++) + sprintf (r_gripstr+i*2, "%02X", grip[i]); + } + gcry_sexp_release (sexp); + return err; +} + + + +static int +do_learn_status (APP app, CTRL ctrl) +{ + gpg_error_t err; + char ct_buf[100], id_buf[100]; + int i; + + /* Output information about all useful objects. */ + for (i=0; filelist[i].fid; i++) + { + if (filelist[i].certtype) + { + size_t len = get_length_of_cert (app->slot, filelist[i].fid); + + if (len) + { + /* FIXME: We should store the length in the application's + context so that a following readcert does only need to + read that many bytes. */ + sprintf (ct_buf, "%d", filelist[i].certtype); + sprintf (id_buf, "NKS-DF01.%04X", filelist[i].fid); + send_status_info (ctrl, "CERTINFO", + ct_buf, strlen (ct_buf), + id_buf, strlen (id_buf), + NULL, (size_t)0); + } + } + else if (filelist[i].iskeypair) + { + char gripstr[40+1]; + + err = keygripstr_from_pk_file (app->slot, filelist[i].fid, gripstr); + if (err) + log_error ("can't get keygrip from FID 0x%04X: %s\n", + filelist[i].fid, gpg_strerror (err)); + else + { + sprintf (id_buf, "NKS-DF01.%04X", filelist[i].fid); + send_status_info (ctrl, "KEYPAIRINFO", + gripstr, 40, + id_buf, strlen (id_buf), + NULL, (size_t)0); + } + } + } + + return 0; +} + + + + +/* Read the certificate with id CERTID (as returned by learn_status in + the CERTINFO status lines) and return it in the freshly allocated + buffer put into CERT and the length of the certificate put into + CERTLEN. */ +static int +do_readcert (app_t app, const char *certid, + unsigned char **cert, size_t *certlen) +{ + int i, fid; + gpg_error_t err; + unsigned char *buffer; + const unsigned char *p; + size_t buflen, n; + int class, tag, constructed, ndef; + size_t totobjlen, objlen, hdrlen; + int rootca = 0; + + *cert = NULL; + *certlen = 0; + if (strncmp (certid, "NKS-DF01.", 9) ) + return gpg_error (GPG_ERR_INV_ID); + certid += 9; + if (!hexdigitp (certid) || !hexdigitp (certid+1) + || !hexdigitp (certid+2) || !hexdigitp (certid+3) + || certid[4]) + return gpg_error (GPG_ERR_INV_ID); + fid = xtoi_4 (certid); + for (i=0; filelist[i].fid; i++) + if ((filelist[i].certtype || filelist[i].iskeypair) + && filelist[i].fid == fid) + break; + if (!filelist[i].fid) + return gpg_error (GPG_ERR_NOT_FOUND); + + /* If the requested objects is a plain public key, redirect it to + the corresponding certificate. The whole system is a bit messy + becuase we sometime use the key directly or let the caller + retrieve the key from the certificate. The valid point behind + that is to support not-yet stored certificates. */ + if (filelist[i].iskeypair) + fid = filelist[i].iskeypair; + + + /* Read the entire file. fixme: This could be optimized by first + reading the header to figure out how long the certificate + actually is. */ + err = iso7816_select_file (app->slot, fid, 0, NULL, NULL); + if (err) + { + log_error ("error selecting FID 0x%04X: %s\n", fid, gpg_strerror (err)); + return err; + } + + err = iso7816_read_binary (app->slot, 0, 0, &buffer, &buflen); + if (err) + { + log_error ("error reading certificate from FID 0x%04X: %s\n", + fid, gpg_strerror (err)); + return err; + } + + if (!buflen || *buffer == 0xff) + { + log_info ("no certificate contained in FID 0x%04X\n", fid); + err = gpg_error (GPG_ERR_NOT_FOUND); + goto leave; + } + + /* Now figure something out about the object. */ + p = buffer; + n = buflen; + err = parse_ber_header (&p, &n, &class, &tag, &constructed, + &ndef, &objlen, &hdrlen); + if (err) + goto leave; + if ( class == CLASS_UNIVERSAL && tag == TAG_SEQUENCE && constructed ) + ; + else if ( class == CLASS_UNIVERSAL && tag == TAG_SET && constructed ) + rootca = 1; + else + return gpg_error (GPG_ERR_INV_OBJ); + totobjlen = objlen + hdrlen; + assert (totobjlen <= buflen); + + err = parse_ber_header (&p, &n, &class, &tag, &constructed, + &ndef, &objlen, &hdrlen); + if (err) + goto leave; + + if (rootca) + ; + else if (class == CLASS_UNIVERSAL && tag == TAG_OBJECT_ID && !constructed) + { + const unsigned char *save_p; + + /* The certificate seems to be contained in a userCertificate + container. Skip this and assume the following sequence is + the certificate. */ + if (n < objlen) + { + err = gpg_error (GPG_ERR_INV_OBJ); + goto leave; + } + p += objlen; + n -= objlen; + save_p = p; + err = parse_ber_header (&p, &n, &class, &tag, &constructed, + &ndef, &objlen, &hdrlen); + if (err) + goto leave; + if ( !(class == CLASS_UNIVERSAL && tag == TAG_SEQUENCE && constructed) ) + return gpg_error (GPG_ERR_INV_OBJ); + totobjlen = objlen + hdrlen; + assert (save_p + totobjlen <= buffer + buflen); + memmove (buffer, save_p, totobjlen); + } + + *cert = buffer; + buffer = NULL; + *certlen = totobjlen; + + leave: + xfree (buffer); + return err; +} + + + +/* Select the NKS 2.0 application on the card in SLOT. */ +int +app_select_nks (APP app) +{ + static char const aid[] = { 0xD2, 0x76, 0x00, 0x00, 0x03, 0x01, 0x02 }; + int slot = app->slot; + int rc; + + rc = iso7816_select_application (slot, aid, sizeof aid); + if (!rc) + { + app->apptype = "NKS"; + + app->fnc.learn_status = do_learn_status; + app->fnc.readcert = do_readcert; + app->fnc.getattr = NULL; + app->fnc.setattr = NULL; + app->fnc.genkey = NULL; + app->fnc.sign = NULL; + app->fnc.auth = NULL; + app->fnc.decipher = NULL; + app->fnc.change_pin = NULL; + app->fnc.check_pin = NULL; + } + + return rc; +} + + diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 8f9a303fe..75e3e299e 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -1,5 +1,5 @@ /* app-openpgp.c - The OpenPGP card application. - * Copyright (C) 2003 Free Software Foundation, Inc. + * Copyright (C) 2003, 2004 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -42,7 +42,7 @@ #include "iso7816.h" #include "app-common.h" - +#include "tlv.h" static struct { @@ -80,94 +80,6 @@ static unsigned long convert_sig_counter_value (const unsigned char *value, static unsigned long get_sig_counter (APP app); -/* Locate a TLV encoded data object in BUFFER of LENGTH and - return a pointer to value as well as its length in NBYTES. Return - NULL if it was not found. Note, that the function does not check - whether the value fits into the provided buffer. - - FIXME: Move this to an extra file, it is mostly duplicated from card.c. -*/ -static const unsigned char * -find_tlv (const unsigned char *buffer, size_t length, - int tag, size_t *nbytes, int nestlevel) -{ - const unsigned char *s = buffer; - size_t n = length; - size_t len; - int this_tag; - int composite; - - for (;;) - { - buffer = s; - if (n < 2) - return NULL; /* buffer definitely too short for tag and length. */ - if (!*s || *s == 0xff) - { /* Skip optional filler between TLV objects. */ - s++; - n--; - continue; - } - composite = !!(*s & 0x20); - if ((*s & 0x1f) == 0x1f) - { /* more tag bytes to follow */ - s++; - n--; - if (n < 2) - return NULL; /* buffer definitely too short for tag and length. */ - if ((*s & 0x1f) == 0x1f) - return NULL; /* We support only up to 2 bytes. */ - this_tag = (s[-1] << 8) | (s[0] & 0x7f); - } - else - this_tag = s[0]; - len = s[1]; - s += 2; n -= 2; - if (len < 0x80) - ; - else if (len == 0x81) - { /* One byte length follows. */ - if (!n) - return NULL; /* we expected 1 more bytes with the length. */ - len = s[0]; - s++; n--; - } - else if (len == 0x82) - { /* Two byte length follows. */ - if (n < 2) - return NULL; /* we expected 2 more bytes with the length. */ - len = (s[0] << 8) | s[1]; - s += 2; n -= 2; - } - else - return NULL; /* APDU limit is 65535, thus it does not make - sense to assume longer length fields. */ - - if (composite && nestlevel < 100) - { /* Dive into this composite DO after checking for too deep - nesting. */ - const unsigned char *tmp_s; - size_t tmp_len; - - tmp_s = find_tlv (s, len, tag, &tmp_len, nestlevel+1); - if (tmp_s) - { - *nbytes = tmp_len; - return tmp_s; - } - } - - if (this_tag == tag) - { - *nbytes = len; - return s; - } - if (len > n) - return NULL; /* buffer too short to skip to the next tag. */ - s += len; n -= len; - } -} - /* Get the DO identified by TAG from the card in SLOT and return a buffer with its content in RESULT and NBYTES. The return value is @@ -197,7 +109,7 @@ get_one_do (int slot, int tag, unsigned char **result, size_t *nbytes) { const unsigned char *s; - s = find_tlv (buffer, buflen, tag, &valuelen, 0); + s = find_tlv (buffer, buflen, tag, &valuelen); if (!s) value = NULL; /* not found */ else if (valuelen > buflen - (s - buffer)) @@ -271,7 +183,7 @@ dump_all_do (int slot) if (j==i || data_objects[i].tag != data_objects[j].get_from) continue; value = find_tlv (buffer, buflen, - data_objects[j].tag, &valuelen, 0); + data_objects[j].tag, &valuelen); if (!value) ; /* not found */ else if (valuelen > buflen - (value - buffer)) @@ -443,7 +355,7 @@ do_getattr (APP app, CTRL ctrl, const char *name) { /* The serial number is very special. We could have used the AID DO to retrieve it, but we have it already in the app - context and the stanmp argument is required anyway which we + context and the stamp argument is required anyway which we can't by other means. The AID DO is available anyway but not hex formatted. */ char *serial; @@ -772,7 +684,7 @@ do_genkey (APP app, CTRL ctrl, const char *keynostr, unsigned int flags, log_error ("error reading application data\n"); return gpg_error (GPG_ERR_GENERAL); } - fpr = find_tlv (buffer, buflen, 0x00C5, &n, 0); + fpr = find_tlv (buffer, buflen, 0x00C5, &n); if (!fpr || n != 60) { rc = gpg_error (GPG_ERR_GENERAL); @@ -820,7 +732,7 @@ do_genkey (APP app, CTRL ctrl, const char *keynostr, unsigned int flags, } log_info ("key generation completed (%d seconds)\n", (int)(time (NULL) - start_at)); - keydata = find_tlv (buffer, buflen, 0x7F49, &keydatalen, 0); + keydata = find_tlv (buffer, buflen, 0x7F49, &keydatalen); if (!keydata) { rc = gpg_error (GPG_ERR_CARD); @@ -828,7 +740,7 @@ do_genkey (APP app, CTRL ctrl, const char *keynostr, unsigned int flags, goto leave; } - m = find_tlv (keydata, keydatalen, 0x0081, &mlen, 0); + m = find_tlv (keydata, keydatalen, 0x0081, &mlen); if (!m) { rc = gpg_error (GPG_ERR_CARD); @@ -838,7 +750,7 @@ do_genkey (APP app, CTRL ctrl, const char *keynostr, unsigned int flags, /* log_printhex ("RSA n:", m, mlen); */ send_key_data (ctrl, "n", m, mlen); - e = find_tlv (keydata, keydatalen, 0x0082, &elen, 0); + e = find_tlv (keydata, keydatalen, 0x0082, &elen); if (!e) { rc = gpg_error (GPG_ERR_CARD); @@ -913,7 +825,7 @@ compare_fingerprint (APP app, int keyno, unsigned char *sha1fpr) log_error ("error reading application data\n"); return gpg_error (GPG_ERR_GENERAL); } - fpr = find_tlv (buffer, buflen, 0x00C5, &n, 0); + fpr = find_tlv (buffer, buflen, 0x00C5, &n); if (!fpr || n != 60) { xfree (buffer); @@ -1268,7 +1180,7 @@ do_check_pin (APP app, const char *keyidstr, /* Select the OpenPGP application on the card in SLOT. This function must be used before any other OpenPGP application functions. */ int -app_select_openpgp (APP app, unsigned char **sn, size_t *snlen) +app_select_openpgp (APP app) { static char const aid[] = { 0xD2, 0x76, 0x00, 0x01, 0x24, 0x01 }; int slot = app->slot; @@ -1280,10 +1192,17 @@ app_select_openpgp (APP app, unsigned char **sn, size_t *snlen) rc = iso7816_select_application (slot, aid, sizeof aid); if (!rc) { + app->apptype = "OPENPGP"; + app->did_chv1 = 0; app->did_chv2 = 0; app->did_chv3 = 0; + /* The OpenPGP card returns the serial number as part of the + AID; because we prefer to use OpenPGP serial numbers, we + repalce a possibly already set one from a EF.GDO with this + one. Note, that for current OpenPGP cards, no EF.GDO exists + and thus it won't matter at all. */ rc = iso7816_get_data (slot, 0x004F, &buffer, &buflen); if (rc) goto leave; @@ -1293,15 +1212,12 @@ app_select_openpgp (APP app, unsigned char **sn, size_t *snlen) log_printhex ("", buffer, buflen); } - if (sn) - { - *sn = buffer; - *snlen = buflen; - app->card_version = buffer[6] << 8; - app->card_version |= buffer[7]; - } - else - xfree (buffer); + app->card_version = buffer[6] << 8; + app->card_version |= buffer[7]; + xfree (app->serialno); + app->serialno = buffer; + app->serialnolen = buflen; + buffer = NULL; relptr = get_one_do (app->slot, 0x00C4, &buffer, &buflen); if (!relptr) @@ -1316,6 +1232,7 @@ app_select_openpgp (APP app, unsigned char **sn, size_t *snlen) dump_all_do (slot); app->fnc.learn_status = do_learn_status; + app->fnc.readcert = NULL; app->fnc.getattr = do_getattr; app->fnc.setattr = do_setattr; app->fnc.genkey = do_genkey; @@ -1498,7 +1415,7 @@ app_openpgp_readkey (APP app, int keyno, unsigned char **m, size_t *mlen, goto leave; } - keydata = find_tlv (buffer, buflen, 0x7F49, &keydatalen, 0); + keydata = find_tlv (buffer, buflen, 0x7F49, &keydatalen); if (!keydata) { log_error ("response does not contain the public key data\n"); @@ -1506,7 +1423,7 @@ app_openpgp_readkey (APP app, int keyno, unsigned char **m, size_t *mlen, goto leave; } - a = find_tlv (keydata, keydatalen, 0x0081, &alen, 0); + a = find_tlv (keydata, keydatalen, 0x0081, &alen); if (!a) { log_error ("response does not contain the RSA modulus\n"); @@ -1517,7 +1434,7 @@ app_openpgp_readkey (APP app, int keyno, unsigned char **m, size_t *mlen, *m = xmalloc (alen); memcpy (*m, a, alen); - a = find_tlv (keydata, keydatalen, 0x0082, &alen, 0); + a = find_tlv (keydata, keydatalen, 0x0082, &alen); if (!e) { log_error ("response does not contain the RSA public exponent\n"); diff --git a/scd/app.c b/scd/app.c index 1f142ea32..6ac18272b 100644 --- a/scd/app.c +++ b/scd/app.c @@ -29,49 +29,78 @@ #include "app-common.h" #include "apdu.h" #include "iso7816.h" -#include "dynload.h" +#include "tlv.h" -static char *default_reader_port; -void -app_set_default_reader_port (const char *portstr) -{ - xfree (default_reader_port); - default_reader_port = portstr? xstrdup (portstr): NULL; -} - - -/* The select the best fitting application and return a context. - Returns NULL if no application was found or no card is present. */ +/* If called with NAME as NULL, select the best fitting application + and return a context; otherwise select the application with NAME + and return a context. SLOT identifies the reader device. Returns + NULL if no application was found or no card is present. */ APP -select_application (void) +select_application (ctrl_t ctrl, int slot, const char *name) { - int slot; int rc; APP app; - - slot = apdu_open_reader (default_reader_port); - if (slot == -1) - { - log_error ("card reader not available\n"); - return NULL; - } + unsigned char *result = NULL; + size_t resultlen; app = xtrycalloc (1, sizeof *app); if (!app) { rc = out_of_core (); log_info ("error allocating context: %s\n", gpg_strerror (rc)); - /*apdu_close_reader (slot);*/ return NULL; } - app->slot = slot; - rc = app_select_openpgp (app, &app->serialno, &app->serialnolen); + + /* Fixme: We should now first check whether a card is at all + present. */ + + /* Try to read the GDO file first to get a default serial number. */ + rc = iso7816_select_file (slot, 0x3F00, 1, NULL, NULL); + if (!rc) + rc = iso7816_select_file (slot, 0x2F02, 0, NULL, NULL); + if (!rc) + rc = iso7816_read_binary (slot, 0, 0, &result, &resultlen); + if (!rc) + { + size_t n; + const unsigned char *p; + + p = find_tlv (result, resultlen, 0x5A, &n); + if (p && n && n >= (resultlen - (p - result))) + { + /* The GDO file is pretty short, thus we simply reuse it for + storing the serial number. */ + memmove (result, p, n); + app->serialno = result; + app->serialnolen = n; + } + else + xfree (result); + result = NULL; + } + + + rc = gpg_error (GPG_ERR_NOT_FOUND); + + if (!name || !strcmp (name, "openpgp")) + rc = app_select_openpgp (app); + if (rc && (!name || !strcmp (name, "nks"))) + rc = app_select_nks (app); + if (rc && (!name || !strcmp (name, "dinsig"))) + rc = app_select_dinsig (app); + if (rc && name) + rc = gpg_error (GPG_ERR_NOT_SUPPORTED); + if (rc) { -/* apdu_close_reader (slot); */ - log_info ("selecting openpgp failed: %s\n", gpg_strerror (rc)); + if (name) + log_info ("can't select application `%s': %s\n", + name, gpg_strerror (rc)); + else + log_info ("no supported card application found: %s\n", + gpg_strerror (rc)); xfree (app); return NULL; } @@ -81,23 +110,36 @@ select_application (void) } +void +release_application (app_t app) +{ + if (!app) + return; + + xfree (app->serialno); + xfree (app); +} + + /* Retrieve the serial number and the time of the last update of the card. The serial number is returned as a malloced string (hex encoded) in SERIAL and the time of update is returned in STAMP. If no update time is available the returned value is 0. Caller must - free SERIAL unless the function returns an error. */ + free SERIAL unless the function returns an error. If STAMP is not + of interest, NULL may be passed. */ int -app_get_serial_and_stamp (APP app, char **serial, time_t *stamp) +app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp) { unsigned char *buf, *p; int i; - if (!app || !serial || !stamp) + if (!app || !serial) return gpg_error (GPG_ERR_INV_VALUE); *serial = NULL; - *stamp = 0; /* not available */ + if (stamp) + *stamp = 0; /* not available */ buf = xtrymalloc (app->serialnolen * 2 + 1); if (!buf) @@ -121,10 +163,34 @@ app_write_learn_status (APP app, CTRL ctrl) return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); if (!app->fnc.learn_status) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); + + if (app->apptype) + send_status_info (ctrl, "APPTYPE", + app->apptype, strlen (app->apptype), NULL, 0); + return app->fnc.learn_status (app, ctrl); } +/* Read the certificate with id CERTID (as returned by learn_status in + the CERTINFO status lines) and return it in the freshly allocated + buffer put into CERT and the length of the certificate put into + CERTLEN. */ +int +app_readcert (app_t app, const char *certid, + unsigned char **cert, size_t *certlen) +{ + if (!app) + return gpg_error (GPG_ERR_INV_VALUE); + if (!app->initialized) + return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); + if (!app->fnc.readcert) + return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); + + return app->fnc.readcert (app, certid, cert, certlen); +} + + /* Perform a GETATTR operation. */ int app_getattr (APP app, CTRL ctrl, const char *name) @@ -317,8 +383,3 @@ app_check_pin (APP app, const char *keyidstr, return rc; } - - - - - diff --git a/scd/card.c b/scd/card.c index 95149074d..53c89f3a4 100644 --- a/scd/card.c +++ b/scd/card.c @@ -53,7 +53,10 @@ map_sc_err (int rc) #endif default: e = GPG_ERR_CARD; break; } - return gpg_err_make (GPG_ERR_SOURCE_UNKNOWN, e); + /* It does not make much sense to further distingusih the error + source between OpenSC and SCD. Thus we use SCD as source + here. */ + return gpg_err_make (GPG_ERR_SOURCE_SCD, e); } /* Get the keygrip from CERT, return 0 on success */ @@ -462,6 +465,7 @@ card_enum_keypairs (CARD card, int idx, 100 := Regular X.509 cert 101 := Trusted X.509 cert 102 := Useful X.509 cert + 110 := Root CA cert (DINSIG) */ int card_enum_certs (CARD card, int idx, char **certid, int *certtype) diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c index 936672cc6..f910722eb 100644 --- a/scd/ccid-driver.c +++ b/scd/ccid-driver.c @@ -98,6 +98,11 @@ # include "scdaemon.h" # endif +/* Disable all debgging output for now. */ +#undef DBG_CARD_IO +#define DBG_CARD_IO 0 + + # define DEBUGOUT(t) do { if (DBG_CARD_IO) \ log_debug (DRVNAME t); } while (0) # define DEBUGOUT_1(t,a) do { if (DBG_CARD_IO) \ @@ -944,7 +949,9 @@ ccid_transceive (ccid_driver_t handle, { if (n > maxresplen) { - DEBUGOUT ("provided buffer too short for received data\n"); + DEBUGOUT_2 ("provided buffer too short for received data " + "(%u/%u)\n", + (unsigned int)n, (unsigned int)maxresplen); return -1; } diff --git a/scd/command.c b/scd/command.c index bc3132a0b..9e571f228 100644 --- a/scd/command.c +++ b/scd/command.c @@ -1,5 +1,5 @@ /* command.c - SCdaemon command handler - * Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. + * Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -31,6 +31,7 @@ #include "scdaemon.h" #include #include "app-common.h" +#include "apdu.h" /* Required for apdu_*_reader (). */ /* maximum length aloowed as a PIN; used for INQUIRE NEEDPIN */ #define MAXLEN_PIN 100 @@ -90,17 +91,34 @@ option_handler (ASSUAN_CONTEXT ctx, const char *key, const char *value) function returns an Assuan error, so don't map the error a second time */ static AssuanError -open_card (CTRL ctrl) +open_card (CTRL ctrl, const char *apptype) { + int slot; + if (ctrl->app_ctx) return 0; /* Already initialized for one specific application. */ if (ctrl->card_ctx) return 0; /* Already initialized using a card context. */ - ctrl->app_ctx = select_application (); + slot = apdu_open_reader (opt.reader_port); + if (slot != -1) + { + ctrl->app_ctx = select_application (ctrl, slot, apptype); + if (!ctrl->app_ctx) + apdu_close_reader (slot); + } if (!ctrl->app_ctx) { /* No application found - fall back to old mode. */ - int rc = card_open (&ctrl->card_ctx); + /* Note that we should rework the old code to use the + application paradigma too. */ + int rc; + + /* If an APPTYPE was requested and it is not pkcs#15, we return + an error here. */ + if (apptype && !(!strcmp (apptype, "P15") || !strcmp (apptype, "p15"))) + rc = gpg_error (GPG_ERR_NOT_SUPPORTED); + else + rc = card_open (&ctrl->card_ctx); if (rc) return map_to_assuan_status (rc); } @@ -143,11 +161,17 @@ percent_plus_unescape (unsigned char *string) -/* SERIALNO +/* SERIALNO [APPTYPE] Return the serial number of the card using a status reponse. This functon should be used to check for the presence of a card. + If APPTYPE is given, an application of that type is selected and an + error is returned if the application is not supported or available. + The default is to auto-select the application using a hardwired + preference system. Note, that a future extension to this function + may allow to specify a list and order of applications to try. + This function is special in that it can be used to reset the card. Most other functions will return an error when a card change has been detected and the use of this function is therefore required. @@ -165,7 +189,7 @@ cmd_serialno (ASSUAN_CONTEXT ctx, char *line) char *serial; time_t stamp; - if ((rc = open_card (ctrl))) + if ((rc = open_card (ctrl, *line? line:NULL))) return rc; if (ctrl->app_ctx) @@ -223,6 +247,7 @@ cmd_serialno (ASSUAN_CONTEXT ctx, char *line) 100 := Regular X.509 cert 101 := Trusted X.509 cert 102 := Useful X.509 cert + 110 := Root CA cert (DINSIG) For certain cards, more information will be returned: @@ -240,7 +265,7 @@ cmd_serialno (ASSUAN_CONTEXT ctx, char *line) S DISP-NAME The name of the card holder as stored on the card; percent - aescaping takes place, spaces are encoded as '+' + escaping takes place, spaces are encoded as '+' S PUBKEY-URL @@ -254,7 +279,7 @@ cmd_learn (ASSUAN_CONTEXT ctx, char *line) int rc = 0; int idx; - if ((rc = open_card (ctrl))) + if ((rc = open_card (ctrl, NULL))) return rc; /* Unless the force option is used we try a shortcut by identifying @@ -305,10 +330,15 @@ cmd_learn (ASSUAN_CONTEXT ctx, char *line) free (serial_and_stamp); } - /* Return information about the certificates. */ - if (ctrl->app_ctx) - rc = -1; /* This information is not yet available for applications. */ - for (idx=0; !rc; idx++) + /* If we are using the modern application paradigma, let the + application print out its collection of useful status + information. */ + if (!rc && ctrl->app_ctx) + rc = app_write_learn_status (ctrl->app_ctx, ctrl); + + /* Return information about the certificates. FIXME: Move this into + an app-p15.c*/ + for (idx=0; !rc && !ctrl->app_ctx; idx++) { char *certid; int certtype; @@ -333,11 +363,9 @@ cmd_learn (ASSUAN_CONTEXT ctx, char *line) if (rc == -1) rc = 0; - - /* Return information about the keys. */ - if (ctrl->app_ctx) - rc = -1; /* This information is not yet available for applications. */ - for (idx=0; !rc; idx++) + /* Return information about the keys. FIXME: Move this into an + app-p15.c */ + for (idx=0; !rc && !ctrl->app_ctx; idx++) { unsigned char keygrip[20]; char *keyid; @@ -346,7 +374,7 @@ cmd_learn (ASSUAN_CONTEXT ctx, char *line) rc = card_enum_keypairs (ctrl->card_ctx, idx, keygrip, &keyid); if (gpg_err_code (rc) == GPG_ERR_MISSING_CERT && keyid) { - /* this does happen with an incomplete personalized + /* This does happen with an incomplete personalized card; i.e. during the time we have stored the key on the card but not stored the certificate; probably becuase it has not yet been received back from the CA. Note that we @@ -383,10 +411,6 @@ cmd_learn (ASSUAN_CONTEXT ctx, char *line) if (rc == -1) rc = 0; - if (!rc && ctrl->app_ctx) - rc = app_write_learn_status (ctrl->app_ctx, ctrl); - - return map_to_assuan_status (rc); } @@ -403,17 +427,24 @@ cmd_readcert (ASSUAN_CONTEXT ctx, char *line) unsigned char *cert; size_t ncert; - if ((rc = open_card (ctrl))) + if ((rc = open_card (ctrl, NULL))) return rc; + line = xstrdup (line); /* Need a copy of the line. */ if (ctrl->app_ctx) - return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); - - rc = card_read_cert (ctrl->card_ctx, line, &cert, &ncert); - if (rc) { - log_error ("card_read_cert failed: %s\n", gpg_strerror (rc)); + rc = app_readcert (ctrl->app_ctx, line, &cert, &ncert); + if (rc) + log_error ("app_readcert failed: %s\n", gpg_strerror (rc)); + } + else + { + rc = card_read_cert (ctrl->card_ctx, line, &cert, &ncert); + if (rc) + log_error ("card_read_cert failed: %s\n", gpg_strerror (rc)); } + xfree (line); + line = NULL; if (!rc) { rc = assuan_send_data (ctx, cert, ncert); @@ -440,18 +471,26 @@ cmd_readkey (ASSUAN_CONTEXT ctx, char *line) ksba_cert_t kc = NULL; ksba_sexp_t p; - if ((rc = open_card (ctrl))) + if ((rc = open_card (ctrl, NULL))) return rc; + line = xstrdup (line); /* Need a copy of the line. */ if (ctrl->app_ctx) - return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); - - rc = card_read_cert (ctrl->card_ctx, line, &cert, &ncert); - if (rc) { - log_error ("card_read_cert failed: %s\n", gpg_strerror (rc)); - goto leave; + rc = app_readcert (ctrl->app_ctx, line, &cert, &ncert); + if (rc) + log_error ("app_readcert failed: %s\n", gpg_strerror (rc)); + } + else + { + rc = card_read_cert (ctrl->card_ctx, line, &cert, &ncert); + if (rc) + log_error ("card_read_cert failed: %s\n", gpg_strerror (rc)); } + xfree (line); + line = NULL; + if (rc) + goto leave; rc = ksba_cert_new (&kc); if (rc) @@ -569,7 +608,7 @@ cmd_pksign (ASSUAN_CONTEXT ctx, char *line) size_t outdatalen; char *keyidstr; - if ((rc = open_card (ctrl))) + if ((rc = open_card (ctrl, NULL))) return rc; /* We have to use a copy of the key ID because the function may use @@ -619,7 +658,7 @@ cmd_pkauth (ASSUAN_CONTEXT ctx, char *line) size_t outdatalen; char *keyidstr; - if ((rc = open_card (ctrl))) + if ((rc = open_card (ctrl, NULL))) return rc; if (!ctrl->app_ctx) @@ -665,7 +704,7 @@ cmd_pkdecrypt (ASSUAN_CONTEXT ctx, char *line) size_t outdatalen; char *keyidstr; - if ((rc = open_card (ctrl))) + if ((rc = open_card (ctrl, NULL))) return rc; keyidstr = xtrystrdup (line); @@ -718,7 +757,7 @@ cmd_getattr (ASSUAN_CONTEXT ctx, char *line) int rc; char *keyword; - if ((rc = open_card (ctrl))) + if ((rc = open_card (ctrl, NULL))) return rc; keyword = line; @@ -757,7 +796,7 @@ cmd_setattr (ASSUAN_CONTEXT ctx, char *orig_line) size_t nbytes; char *line, *linebuf; - if ((rc = open_card (ctrl))) + if ((rc = open_card (ctrl, NULL))) return rc; /* We need to use a copy of LINE, because PIN_CB uses the same @@ -823,7 +862,7 @@ cmd_genkey (ASSUAN_CONTEXT ctx, char *line) line++; *line = 0; - if ((rc = open_card (ctrl))) + if ((rc = open_card (ctrl, NULL))) return rc; if (!ctrl->app_ctx) @@ -854,7 +893,7 @@ cmd_random (ASSUAN_CONTEXT ctx, char *line) return set_error (Parameter_Error, "number of requested bytes missing"); nbytes = strtoul (line, NULL, 0); - if ((rc = open_card (ctrl))) + if ((rc = open_card (ctrl, NULL))) return rc; if (!ctrl->app_ctx) @@ -904,7 +943,7 @@ cmd_passwd (ASSUAN_CONTEXT ctx, char *line) line++; *line = 0; - if ((rc = open_card (ctrl))) + if ((rc = open_card (ctrl, NULL))) return rc; if (!ctrl->app_ctx) @@ -931,7 +970,7 @@ cmd_checkpin (ASSUAN_CONTEXT ctx, char *line) int rc; char *keyidstr; - if ((rc = open_card (ctrl))) + if ((rc = open_card (ctrl, NULL))) return rc; if (!ctrl->app_ctx) diff --git a/scd/iso7816.c b/scd/iso7816.c index f4aa18c6f..9a15ce953 100644 --- a/scd/iso7816.c +++ b/scd/iso7816.c @@ -51,6 +51,8 @@ #define CMD_INTERNAL_AUTHENTICATE 0x88 #define CMD_GENERATE_KEYPAIR 0x47 #define CMD_GET_CHALLENGE 0x84 +#define CMD_READ_BINARY 0xB0 +#define CMD_READ_RECORD 0xB2 static gpg_error_t map_sw (int sw) @@ -66,6 +68,8 @@ map_sw (int sw) case SW_USE_CONDITIONS: ec = GPG_ERR_USE_CONDITIONS; break; case SW_NOT_SUPPORTED: ec = GPG_ERR_NOT_SUPPORTED; break; case SW_BAD_PARAMETER: ec = GPG_ERR_INV_VALUE; break; + case SW_FILE_NOT_FOUND: ec = GPG_ERR_ENOENT; break; + case SW_RECORD_NOT_FOUND:ec= GPG_ERR_NOT_FOUND; break; case SW_REF_NOT_FOUND: ec = GPG_ERR_NO_OBJ; break; case SW_BAD_P0_P1: ec = GPG_ERR_INV_VALUE; break; case SW_INS_NOT_SUP: ec = GPG_ERR_CARD; break; @@ -91,18 +95,79 @@ map_sw (int sw) apdu_open_reader (), AID is a buffer of size AIDLEN holding the requested application ID. The function can't be used to enumerate AIDs and won't return the AID on success. The return value is 0 - for okay or GNUPG error code. Note that ISO error codes are + for okay or a GPG error code. Note that ISO error codes are internally mapped. */ gpg_error_t iso7816_select_application (int slot, const char *aid, size_t aidlen) { + static char const openpgp_aid[] = { 0xD2, 0x76, 0x00, 0x01, 0x24, 0x01 }; int sw; + int p1 = 0x0C; /* No FCI to be returned. */ + + if (aidlen == sizeof openpgp_aid + && !memcmp (aid, openpgp_aid, sizeof openpgp_aid)) + p1 = 0; /* The current openpgp cards don't allow 0x0c. */ - sw = apdu_send_simple (slot, 0x00, CMD_SELECT_FILE, 4, 0, aidlen, aid); + sw = apdu_send_simple (slot, 0x00, CMD_SELECT_FILE, 4, p1, aidlen, aid); return map_sw (sw); } +gpg_error_t +iso7816_select_file (int slot, int tag, int is_dir, + unsigned char **result, size_t *resultlen) +{ + int sw, p0, p1; + unsigned char tagbuf[2]; + + tagbuf[0] = (tag >> 8) & 0xff; + tagbuf[1] = tag & 0xff; + + if (result || resultlen) + { + *result = NULL; + *resultlen = 0; + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); + } + else + { + p0 = (tag == 0x3F00)? 0: is_dir? 1:2; + p1 = 0x0c; /* No FC return. */ + sw = apdu_send_simple (slot, 0x00, CMD_SELECT_FILE, + p0, p1, 2, tagbuf ); + return map_sw (sw); + } + + return 0; +} + + +/* This is a private command currently only working for TCOS cards. */ +gpg_error_t +iso7816_list_directory (int slot, int list_dirs, + unsigned char **result, size_t *resultlen) +{ + int sw; + + if (!result || !resultlen) + return gpg_error (GPG_ERR_INV_VALUE); + *result = NULL; + *resultlen = 0; + + sw = apdu_send (slot, 0x80, 0xAA, list_dirs? 1:2, 0, -1, NULL, + result, resultlen); + if (sw != SW_SUCCESS) + { + /* Make sure that pending buffers are released. */ + xfree (*result); + *result = NULL; + *resultlen = 0; + } + return map_sw (sw); +} + + + /* Perform a VERIFY command on SLOT using the card holder verification vector CHVNO with a CHV of lenght CHVLEN. Returns 0 on success. */ gpg_error_t @@ -381,3 +446,126 @@ iso7816_get_challenge (int slot, int length, unsigned char *buffer) return 0; } + +/* Perform a READ BINARY command requesting a maximum of NMAX bytes + from OFFSET. With NMAX = 0 the entire file is read. The result is + stored in a newly allocated buffer at the address passed by RESULT. + Returns the length of this data at the address of RESULTLEN. */ +gpg_error_t +iso7816_read_binary (int slot, size_t offset, size_t nmax, + unsigned char **result, size_t *resultlen) +{ + int sw; + unsigned char *buffer; + size_t bufferlen; + + if (!result || !resultlen) + return gpg_error (GPG_ERR_INV_VALUE); + *result = NULL; + *resultlen = 0; + + /* We can only encode 15 bits in p0,p1 to indicate an offset. Thus + we check for this limit. */ + if (offset > 32767 || nmax > 254) + return gpg_error (GPG_ERR_INV_VALUE); + + do + { + buffer = NULL; + bufferlen = 0; + /* Fixme: Either the ccid driver of the TCOS cards have problems + with an Le of 0. */ + sw = apdu_send_le (slot, 0x00, CMD_READ_BINARY, + ((offset>>8) & 0xff), (offset & 0xff) , -1, NULL, + nmax? nmax : 254, &buffer, &bufferlen); + + if (sw != SW_SUCCESS && sw != SW_EOF_REACHED) + { + /* Make sure that pending buffers are released. */ + xfree (buffer); + xfree (*result); + *result = NULL; + *resultlen = 0; + return map_sw (sw); + } + if (*result) /* Need to extend the buffer. */ + { + unsigned char *p = xtryrealloc (*result, *resultlen + bufferlen); + if (!p) + { + gpg_error_t err = gpg_error_from_errno (errno); + xfree (buffer); + xfree (*result); + *result = NULL; + *resultlen = 0; + return err; + } + *result = p; + memcpy (*result + *resultlen, buffer, bufferlen); + *resultlen += bufferlen; + xfree (buffer); + buffer = NULL; + } + else /* Transfer the buffer into our result. */ + { + *result = buffer; + *resultlen = bufferlen; + } + offset += bufferlen; + if (offset > 32767) + break; /* We simply truncate the result for too large + files. */ + } + while (!nmax && sw != SW_EOF_REACHED); + + return 0; +} + +/* Perform a READ RECORD command. RECNO gives the record number to + read with 0 indicating the current record. RECCOUNT must be 1 (not + all cards support reading of more than one record). The result is + stored in a newly allocated buffer at the address passed by RESULT. + Returns the length of this data at the address of RESULTLEN. */ +gpg_error_t +iso7816_read_record (int slot, int recno, int reccount, + unsigned char **result, size_t *resultlen) +{ + int sw; + unsigned char *buffer; + size_t bufferlen; + + if (!result || !resultlen) + return gpg_error (GPG_ERR_INV_VALUE); + *result = NULL; + *resultlen = 0; + + /* We can only encode 15 bits in p0,p1 to indicate an offset. Thus + we check for this limit. */ + if (recno < 0 || recno > 255 || reccount != 1) + return gpg_error (GPG_ERR_INV_VALUE); + + buffer = NULL; + bufferlen = 0; + /* Fixme: Either the ccid driver of the TCOS cards have problems + with an Le of 0. */ + sw = apdu_send_le (slot, 0x00, CMD_READ_RECORD, + recno, + 0x04, + -1, NULL, + 254, &buffer, &bufferlen); + + if (sw != SW_SUCCESS && sw != SW_EOF_REACHED) + { + /* Make sure that pending buffers are released. */ + xfree (buffer); + xfree (*result); + *result = NULL; + *resultlen = 0; + return map_sw (sw); + } + *result = buffer; + *resultlen = bufferlen; + + return 0; +} + diff --git a/scd/iso7816.h b/scd/iso7816.h index 26b8d6aba..98e688693 100644 --- a/scd/iso7816.h +++ b/scd/iso7816.h @@ -27,6 +27,10 @@ gpg_error_t iso7816_select_application (int slot, const char *aid, size_t aidlen); +gpg_error_t iso7816_select_file (int slot, int tag, int is_dir, + unsigned char **result, size_t *resultlen); +gpg_error_t iso7816_list_directory (int slot, int list_dirs, + unsigned char **result, size_t *resultlen); gpg_error_t iso7816_verify (int slot, int chvno, const char *chv, size_t chvlen); gpg_error_t iso7816_change_reference_data (int slot, int chvno, @@ -56,5 +60,9 @@ gpg_error_t iso7816_read_public_key (int slot, gpg_error_t iso7816_get_challenge (int slot, int length, unsigned char *buffer); +gpg_error_t iso7816_read_binary (int slot, size_t offset, size_t nmax, + unsigned char **result, size_t *resultlen); +gpg_error_t iso7816_read_record (int slot, int recno, int reccount, + unsigned char **result, size_t *resultlen); #endif /*ISO7816_H*/ diff --git a/scd/sc-copykeys.c b/scd/sc-copykeys.c index b56b88590..78cb2acc8 100644 --- a/scd/sc-copykeys.c +++ b/scd/sc-copykeys.c @@ -165,7 +165,7 @@ main (int argc, char **argv ) /* FIXME: Use select_application. */ appbuf.slot = slot; - rc = app_select_openpgp (&appbuf, &appbuf.serialno, &appbuf.serialnolen); + rc = app_select_openpgp (&appbuf); if (rc) { log_error ("selecting openpgp failed: %s\n", gpg_strerror (rc)); diff --git a/scd/sc-investigate.c b/scd/sc-investigate.c index ecd385690..acef86ead 100644 --- a/scd/sc-investigate.c +++ b/scd/sc-investigate.c @@ -24,6 +24,13 @@ #include #include #include +#include +#include + +#ifdef HAVE_READLINE_READLINE_H +#include +#include +#endif #define JNLIB_NEED_LOG_LOGV #include "scdaemon.h" @@ -32,17 +39,25 @@ #include "apdu.h" /* for open_reader */ #include "atr.h" #include "app-common.h" +#include "iso7816.h" #define _(a) (a) +#define CONTROL_D ('D' - 'A' + 1) + enum cmd_and_opt_values -{ oVerbose = 'v', +{ + oInteractive = 'i', + oVerbose = 'v', oReaderPort = 500, octapiDriver, oDebug, oDebugAll, + oDisableCCID, + + oGenRandom, aTest }; @@ -52,15 +67,27 @@ static ARGPARSE_OPTS opts[] = { { 301, NULL, 0, "@Options:\n " }, + { oInteractive, "interactive", 0, "start in interactive explorer mode"}, { oVerbose, "verbose", 0, "verbose" }, { oReaderPort, "reader-port", 2, "|N|connect to reader at port N"}, { octapiDriver, "ctapi-driver", 2, "NAME|use NAME as ctAPI driver"}, + { oDisableCCID, "disable-ccid", 0, +#ifdef HAVE_LIBUSB + "do not use the internal CCID driver" +#else + "@" +#endif + }, { oDebug, "debug" ,4|16, "set debugging flags"}, { oDebugAll, "debug-all" ,0, "enable full debugging"}, { oGenRandom, "gen-random", 4, "|N|generate N bytes of random"}, {0} }; + +static void interactive_shell (int slot); + + static const char * my_strusage (int level) { @@ -111,10 +138,8 @@ main (int argc, char **argv ) ARGPARSE_ARGS pargs; int slot, rc; const char *reader_port = NULL; - struct app_ctx_s appbuf; unsigned long gen_random = 0; - - memset (&appbuf, 0, sizeof appbuf); + int interactive = 0; set_strusage (my_strusage); gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN); @@ -143,7 +168,9 @@ main (int argc, char **argv ) case oDebugAll: opt.debug = ~0; break; case oReaderPort: reader_port = pargs.r.ret_str; break; case octapiDriver: opt.ctapi_driver = pargs.r.ret_str; break; + case oDisableCCID: opt.disable_ccid = 1; break; case oGenRandom: gen_random = pargs.r.ret_ulong; break; + case oInteractive: interactive = 1; break; default : pargs.err = 2; break; } } @@ -151,7 +178,7 @@ main (int argc, char **argv ) exit(2); if (opt.verbose < 2) - opt.verbose = 2; /* hack to let select_openpgp print some info. */ + opt.verbose = 2; /* Hack to let select_openpgp print some info. */ if (argc) usage (1); @@ -167,40 +194,61 @@ main (int argc, char **argv ) log_error ("can't dump ATR: %s\n", gpg_strerror (rc)); } - appbuf.slot = slot; - rc = app_select_openpgp (&appbuf, NULL, NULL); - if (rc) - log_error ("selecting openpgp failed: %s\n", gpg_strerror (rc)); + if (interactive) + interactive_shell (slot); else { - appbuf.initialized = 1; - log_info ("openpgp application selected\n"); + struct app_ctx_s appbuf; - if (gen_random) + /* Fixme: We better use app.c directly. */ + memset (&appbuf, 0, sizeof appbuf); + appbuf.slot = slot; + rc = app_select_openpgp (&appbuf); + if (rc) { - size_t nbytes; - unsigned char *buffer; - - buffer = xmalloc (4096); - do + log_info ("selecting openpgp failed: %s\n", gpg_strerror (rc)); + memset (&appbuf, 0, sizeof appbuf); + appbuf.slot = slot; + rc = app_select_dinsig (&appbuf); + if (rc) + log_info ("selecting dinsig failed: %s\n", gpg_strerror (rc)); + else { - nbytes = gen_random > 4096? 4096 : gen_random; - rc = app_get_challenge (&appbuf, nbytes, buffer); - if (rc) - log_error ("app_get_challenge failed: %s\n",gpg_strerror (rc)); - else + appbuf.initialized = 1; + log_info ("dinsig application selected\n"); + } + } + else + { + appbuf.initialized = 1; + log_info ("openpgp application selected\n"); + + if (gen_random) + { + size_t nbytes; + unsigned char *buffer; + + buffer = xmalloc (4096); + do { - if (fwrite (buffer, nbytes, 1, stdout) != 1) - log_error ("writing to stdout failed: %s\n", - strerror (errno)); - gen_random -= nbytes; + nbytes = gen_random > 4096? 4096 : gen_random; + rc = app_get_challenge (&appbuf, nbytes, buffer); + if (rc) + log_error ("app_get_challenge failed: %s\n",gpg_strerror (rc)); + else + { + if (fwrite (buffer, nbytes, 1, stdout) != 1) + log_error ("writing to stdout failed: %s\n", + strerror (errno)); + gen_random -= nbytes; + } } + while (gen_random && !log_get_errorcount (0)); + xfree (buffer); } - while (gen_random && !log_get_errorcount (0)); - xfree (buffer); } } - + return log_get_errorcount (0)? 2:0; } @@ -211,3 +259,377 @@ send_status_info (CTRL ctrl, const char *keyword, ...) { /* DUMMY */ } + + + +/* Dump BUFFER of length NBYTES in a nicely human readable format. */ +static void +dump_buffer (const unsigned char *buffer, size_t nbytes) +{ + int i; + + while (nbytes) + { + for (i=0; i < 16 && i < nbytes; i++) + printf ("%02X%s ", buffer[i], i==8? " ":""); + for (; i < 16; i++) + printf (" %s ", i==8? " ":""); + putchar (' '); + putchar (' '); + for (i=0; i < 16 && i < nbytes; i++) + if (isprint (buffer[i])) + putchar (buffer[i]); + else + putchar ('.'); + nbytes -= i; + buffer += i; + for (; i < 16; i++) + putchar (' '); + putchar ('\n'); + } +} + + +static void +dump_or_store_buffer (const char *arg, + const unsigned char *buffer, size_t nbytes) +{ + const char *s = strchr (arg, '>'); + int append; + FILE *fp; + + if (!s) + { + dump_buffer (buffer, nbytes); + return; + } + if ((append = (*++s == '>'))) + s++; + fp = fopen (s, append? "ab":"wb"); + if (!fp) + { + log_error ("failed to create `%s': %s\n", s, strerror (errno)); + return; + } + if (nbytes && fwrite (buffer, nbytes, 1, fp) != 1) + log_error ("failed to write to `%s': %s\n", s, strerror (errno)); + if (fclose (fp)) + log_error ("failed to close `%s': %s\n", s, strerror (errno)); +} + + +/* Convert STRING into a a newly allocated buffer and return the + length of the buffer in R_LENGTH. Detect xx:xx:xx... sequence and + unhexify that one. */ +static unsigned char * +pin_to_buffer (const char *string, size_t *r_length) +{ + unsigned char *buffer = xmalloc (strlen (string)+1); + const char *s; + size_t n; + + for (s=string, n=0; *s; s += 3) + { + if (hexdigitp (s) && hexdigitp (s+1) && (s[2]==':'||!s[2])) + { + buffer[n++] = xtoi_2 (s); + if (!s[2]) + break; + } + else + { + memcpy (buffer, string, strlen (string)); + *r_length = strlen (string); + return buffer; + } + } + *r_length = n; + return buffer; +} + + +static char * +read_line (int use_readline, char *prompt) +{ + static char buf[256]; + +#ifdef HAVE_READLINE + if (use_readline) + { + char *line = readline (prompt); + if (line) + trim_spaces (line); + if (line && strlen (line) > 2 ) + add_history (line); + return line; + } +#endif + /* Either we don't have readline or we are not running + interactively */ +#ifndef HAVE_READLINE + printf ("%s", prompt ); +#endif + fflush(stdout); + if (!fgets(buf, sizeof(buf), stdin)) + return NULL; + if (!strlen(buf)) + return NULL; + if (buf[strlen (buf)-1] == '\n') + buf[strlen (buf)-1] = 0; + trim_spaces (buf); + return buf; +} + +/* Run a shell for interactive exploration of the card. */ +static void +interactive_shell (int slot) +{ + enum cmdids + { + cmdNOP = 0, + cmdQUIT, cmdHELP, + cmdSELECT, + cmdCHDIR, + cmdLS, + cmdAPP, + cmdREAD, + cmdREADREC, + cmdDEBUG, + cmdVERIFY, + cmdCHANGEREF, + + cmdINVCMD + }; + static struct + { + const char *name; + enum cmdids id; + const char *desc; + } cmds[] = { + { "quit" , cmdQUIT , "quit this menu" }, + { "q" , cmdQUIT , NULL }, + { "help" , cmdHELP , "show this help" }, + { "?" , cmdHELP , NULL }, + { "debug" , cmdDEBUG, "set debugging flags" }, + { "select" , cmdSELECT, "select file (EF)" }, + { "s" , cmdSELECT, NULL }, + { "chdir" , cmdCHDIR, "change directory (select DF)"}, + { "cd" , cmdCHDIR, NULL }, + { "ls" , cmdLS, "list directory (some cards only)"}, + { "app" , cmdAPP, "select application"}, + { "read" , cmdREAD, "read binary" }, + { "rb" , cmdREAD, NULL }, + { "readrec", cmdREADREC, "read record(s)" }, + { "rr" , cmdREADREC, NULL }, + { "verify" , cmdVERIFY, "verify CHVNO PIN" }, + { "ver" , cmdVERIFY, NULL }, + { "changeref", cmdCHANGEREF, "change reference data" }, + { NULL, cmdINVCMD } + }; + enum cmdids cmd = cmdNOP; + int use_readline = isatty (fileno(stdin)); + char *line; + gpg_error_t err = 0; + unsigned char *result = NULL; + size_t resultlen; + +#ifdef HAVE_READLINE + if (use_readline) + using_history (); +#endif + + for (;;) + { + int arg_number; + const char *arg_string = ""; + const char *arg_next = ""; + char *p; + int i; + + if (err) + printf ("command failed: %s\n", gpg_strerror (err)); + err = 0; + xfree (result); + result = NULL; + + printf ("\n"); + do + { + line = read_line (use_readline, "cmd> "); + } + while ( line && *line == '#' ); + + arg_number = 0; + if (!line || *line == CONTROL_D) + cmd = cmdQUIT; + else if (!*line) + cmd = cmdNOP; + else { + if ((p=strchr (line,' '))) + { + char *endp; + + *p++ = 0; + trim_spaces (line); + trim_spaces (p); + arg_number = strtol (p, &endp, 0); + arg_string = p; + if (endp != p) + { + arg_next = endp; + while ( spacep (arg_next) ) + arg_next++; + } + } + + for (i=0; cmds[i].name; i++ ) + if (!ascii_strcasecmp (line, cmds[i].name )) + break; + + cmd = cmds[i].id; + } + + switch (cmd) + { + case cmdHELP: + for (i=0; cmds[i].name; i++ ) + if (cmds[i].desc) + printf("%-10s %s\n", cmds[i].name, _(cmds[i].desc) ); + break; + + case cmdQUIT: + goto leave; + + case cmdNOP: + break; + + case cmdDEBUG: + if (!*arg_string) + opt.debug = opt.debug? 0 : 2048; + else + opt.debug = arg_number; + break; + + case cmdSELECT: + err = iso7816_select_file (slot, arg_number, 0, NULL, NULL); + break; + + case cmdCHDIR: + err = iso7816_select_file (slot, arg_number, 1, NULL, NULL); + break; + + case cmdLS: + err = iso7816_list_directory (slot, 1, &result, &resultlen); + if (!err || gpg_err_code (err) == GPG_ERR_ENOENT) + err = iso7816_list_directory (slot, 0, &result, &resultlen); + /* FIXME: Do something with RESULT. */ + break; + + case cmdAPP: + { + app_t app; + + app = select_application (NULL, slot, *arg_string? arg_string:NULL); + if (app) + { + char *sn; + + app_get_serial_and_stamp (app, &sn, NULL); + log_info ("application `%s' ready; sn=%s\n", + app->apptype?app->apptype:"?", sn? sn:"[none]"); + release_application (app); + } + } + break; + + case cmdREAD: + err = iso7816_read_binary (slot, 0, 0, &result, &resultlen); + if (!err) + dump_or_store_buffer (arg_string, result, resultlen); + break; + + case cmdREADREC: + if (*arg_string == '*' && (!arg_string[1] || arg_string[1] == ' ')) + { + /* Fixme: Can't write to a file yet. */ + for (i=1, err=0; !err; i++) + { + xfree (result); result = NULL; + err = iso7816_read_record (slot, i, 1, &result, &resultlen); + if (!err) + dump_buffer (result, resultlen); + } + if (gpg_err_code (err) == GPG_ERR_NOT_FOUND) + err = 0; + } + else + { + err = iso7816_read_record (slot, arg_number, 1, + &result, &resultlen); + if (!err) + dump_or_store_buffer (arg_string, result, resultlen); + } + break; + + case cmdVERIFY: + if (arg_number < 0 || arg_number > 255 || (arg_number & 127) > 31) + printf ("error: invalid CHVNO\n"); + else + { + unsigned char *pin; + size_t pinlen; + + pin = pin_to_buffer (arg_next, &pinlen); + err = iso7816_verify (slot, arg_number, pin, pinlen); + xfree (pin); + } + break; + + case cmdCHANGEREF: + { + const char *newpin = arg_next; + + while ( *newpin && !spacep (newpin) ) + newpin++; + while ( spacep (newpin) ) + newpin++; + + if (arg_number < 0 || arg_number > 255 || (arg_number & 127) > 31) + printf ("error: invalid CHVNO\n"); + else if (!*arg_next || !*newpin || newpin == arg_next) + printf ("usage: changeref CHVNO OLDPIN NEWPIN\n"); + else + { + char *oldpin = xstrdup (arg_next); + unsigned char *oldpin_buf, *newpin_buf; + size_t oldpin_len, newpin_len; + + for (p=oldpin; *p && !spacep (p); p++ ) + ; + *p = 0; + oldpin_buf = pin_to_buffer (oldpin, &oldpin_len); + newpin_buf = pin_to_buffer (newpin, &newpin_len); + + err = iso7816_change_reference_data (slot, arg_number, + oldpin_buf, oldpin_len, + newpin_buf, newpin_len); + + xfree (newpin_buf); + xfree (oldpin_buf); + xfree (oldpin); + } + } + break; + + case cmdINVCMD: + default: + printf ("\n"); + printf ("Invalid command (try \"help\")\n"); + break; + } /* End command switch. */ + } /* End of main menu loop. */ + + leave: + ; +} + diff --git a/scd/scdaemon.c b/scd/scdaemon.c index 91ac93227..c6652c8dc 100644 --- a/scd/scdaemon.c +++ b/scd/scdaemon.c @@ -100,7 +100,7 @@ static ARGPARSE_OPTS opts[] = { { oReaderPort, "reader-port", 2, N_("|N|connect to reader at port N")}, { octapiDriver, "ctapi-driver", 2, N_("NAME|use NAME as ct-API driver")}, { opcscDriver, "pcsc-driver", 2, N_("NAME|use NAME as PC/SC driver")}, - { oDisableCCID, "disable-ccidc", 0, + { oDisableCCID, "disable-ccid", 0, #ifdef HAVE_LIBUSB N_("do not use the internal CCID driver") #else @@ -397,7 +397,7 @@ main (int argc, char **argv ) case oServer: pipe_server = 1; break; case oDaemon: is_daemon = 1; break; - case oReaderPort: app_set_default_reader_port (pargs.r.ret_str); break; + case oReaderPort: opt.reader_port = pargs.r.ret_str; break; case octapiDriver: opt.ctapi_driver = pargs.r.ret_str; break; case opcscDriver: opt.pcsc_driver = pargs.r.ret_str; break; case oDisableCCID: opt.disable_ccid = 1; break; diff --git a/scd/scdaemon.h b/scd/scdaemon.h index e13377af7..2bbf271da 100644 --- a/scd/scdaemon.h +++ b/scd/scdaemon.h @@ -55,6 +55,7 @@ struct { const char *homedir; /* configuration directory name */ const char *ctapi_driver; /* Library to access the ctAPI. */ const char *pcsc_driver; /* Library to access the PC/SC system. */ + const char *reader_port; /* NULL or reder port to use. */ int disable_opensc; /* Disable the use of the OpenSC framework. */ int disable_ccid; /* Disable the use of the internal CCID driver. */ int allow_admin; /* Allow the use of admin commands for certain @@ -96,8 +97,10 @@ struct server_control_s { }; typedef struct server_control_s *CTRL; +typedef struct server_control_s *ctrl_t; typedef struct card_ctx_s *CARD; typedef struct app_ctx_s *APP; +typedef struct app_ctx_s *app_t; /*-- scdaemon.c --*/ void scd_exit (int rc); diff --git a/scd/tlv.c b/scd/tlv.c new file mode 100644 index 000000000..dbcd24546 --- /dev/null +++ b/scd/tlv.c @@ -0,0 +1,219 @@ +/* tlv.c - Tag-Length-Value Utilities + * Copyright (C) 2003, 2004 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 + +#include +#include +#include +#include + +#include + +#include "tlv.h" + +static const unsigned char * +do_find_tlv (const unsigned char *buffer, size_t length, + int tag, size_t *nbytes, int nestlevel) +{ + const unsigned char *s = buffer; + size_t n = length; + size_t len; + int this_tag; + int composite; + + for (;;) + { + buffer = s; + if (n < 2) + return NULL; /* Buffer definitely too short for tag and length. */ + if (!*s || *s == 0xff) + { /* Skip optional filler between TLV objects. */ + s++; + n--; + continue; + } + composite = !!(*s & 0x20); + if ((*s & 0x1f) == 0x1f) + { /* more tag bytes to follow */ + s++; + n--; + if (n < 2) + return NULL; /* buffer definitely too short for tag and length. */ + if ((*s & 0x1f) == 0x1f) + return NULL; /* We support only up to 2 bytes. */ + this_tag = (s[-1] << 8) | (s[0] & 0x7f); + } + else + this_tag = s[0]; + len = s[1]; + s += 2; n -= 2; + if (len < 0x80) + ; + else if (len == 0x81) + { /* One byte length follows. */ + if (!n) + return NULL; /* we expected 1 more bytes with the length. */ + len = s[0]; + s++; n--; + } + else if (len == 0x82) + { /* Two byte length follows. */ + if (n < 2) + return NULL; /* We expected 2 more bytes with the length. */ + len = (s[0] << 8) | s[1]; + s += 2; n -= 2; + } + else + return NULL; /* APDU limit is 65535, thus it does not make + sense to assume longer length fields. */ + + if (composite && nestlevel < 100) + { /* Dive into this composite DO after checking for a too deep + nesting. */ + const unsigned char *tmp_s; + size_t tmp_len; + + tmp_s = do_find_tlv (s, len, tag, &tmp_len, nestlevel+1); + if (tmp_s) + { + *nbytes = tmp_len; + return tmp_s; + } + } + + if (this_tag == tag) + { + *nbytes = len; + return s; + } + if (len > n) + return NULL; /* Buffer too short to skip to the next tag. */ + s += len; n -= len; + } +} + + +/* Locate a TLV encoded data object in BUFFER of LENGTH and + return a pointer to value as well as its length in NBYTES. Return + NULL if it was not found. Note, that the function does not check + whether the value fits into the provided buffer. */ +const unsigned char * +find_tlv (const unsigned char *buffer, size_t length, + int tag, size_t *nbytes) +{ + return do_find_tlv (buffer, length, tag, nbytes, 0); +} + + + + +/* ASN.1 BER parser: Parse BUFFER of length SIZE and return the tag + and the length part from the TLV triplet. Update BUFFER and SIZE + on success. */ +gpg_error_t +parse_ber_header (unsigned char const **buffer, size_t *size, + int *r_class, int *r_tag, + int *r_constructed, int *r_ndef, + size_t *r_length, size_t *r_nhdr) +{ + int c; + unsigned long tag; + const unsigned char *buf = *buffer; + size_t length = *size; + + *r_ndef = 0; + *r_length = 0; + *r_nhdr = 0; + + /* Get the tag. */ + if (!length) + return gpg_error (GPG_ERR_EOF); + c = *buf++; length--; ++*r_nhdr; + + *r_class = (c & 0xc0) >> 6; + *r_constructed = !!(c & 0x20); + tag = c & 0x1f; + + if (tag == 0x1f) + { + tag = 0; + do + { + /* Simple check against overflow. We limit our maximim tag + value more than needed but that should not be a problem + because I have nver encountered such large value. We + assume at least 32 bit integers. */ + if (tag > (1 << 24)) + return gpg_error (GPG_ERR_TOO_LARGE); + tag <<= 7; + if (!length) + return gpg_error (GPG_ERR_EOF); + c = *buf++; length--; ++*r_nhdr; + tag |= c & 0x7f; + + } + while (c & 0x80); + } + *r_tag = tag; + + /* Get the length. */ + if (!length) + return gpg_error (GPG_ERR_EOF); + c = *buf++; length--; ++*r_nhdr; + + if ( !(c & 0x80) ) + *r_length = c; + else if (c == 0x80) + *r_ndef = 1; + else if (c == 0xff) + return gpg_error (GPG_ERR_BAD_BER); + else + { + unsigned long len = 0; + int count = c & 0x7f; + + for (; count; count--) + { + /* Simple check against overflow. We limit our maximim + length more than needed but that should not be a problem + because I have never encountered such large value and + well they are managed in memory and thus we would run + into memory problems anyway. We assume at least 32 bit + integers. */ + if (len > (1 << 24)) + return gpg_error (GPG_ERR_TOO_LARGE); + len <<= 8; + if (!length) + return gpg_error (GPG_ERR_EOF); + c = *buf++; length--; ++*r_nhdr; + len |= c & 0xff; + } + *r_length = len; + } + + /* Without this kludge some example certs can't be parsed. */ + if (*r_class == CLASS_UNIVERSAL && !*r_tag) + *r_length = 0; + + *buffer = buf; + *size = length; + return 0; +} diff --git a/scd/tlv.h b/scd/tlv.h new file mode 100644 index 000000000..26a9905f7 --- /dev/null +++ b/scd/tlv.h @@ -0,0 +1,84 @@ +/* tlv.h - Tag-Length-Value Utilities + * Copyright (C) 2004 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 + */ + +#ifndef SCD_TLV_H +#define SCD_TLV_H 1 + + +enum tlv_tag_class { + CLASS_UNIVERSAL = 0, + CLASS_APPLICATION = 1, + CLASS_CONTEXT = 2, + CLASS_PRIVATE =3 +}; + +enum tlv_tag_type { + TAG_NONE = 0, + TAG_BOOLEAN = 1, + TAG_INTEGER = 2, + TAG_BIT_STRING = 3, + TAG_OCTET_STRING = 4, + TAG_NULL = 5, + TAG_OBJECT_ID = 6, + TAG_OBJECT_DESCRIPTOR = 7, + TAG_EXTERNAL = 8, + TAG_REAL = 9, + TAG_ENUMERATED = 10, + TAG_EMBEDDED_PDV = 11, + TAG_UTF8_STRING = 12, + TAG_REALTIVE_OID = 13, + TAG_SEQUENCE = 16, + TAG_SET = 17, + TAG_NUMERIC_STRING = 18, + TAG_PRINTABLE_STRING = 19, + TAG_TELETEX_STRING = 20, + TAG_VIDEOTEX_STRING = 21, + TAG_IA5_STRING = 22, + TAG_UTC_TIME = 23, + TAG_GENERALIZED_TIME = 24, + TAG_GRAPHIC_STRING = 25, + TAG_VISIBLE_STRING = 26, + TAG_GENERAL_STRING = 27, + TAG_UNIVERSAL_STRING = 28, + TAG_CHARACTER_STRING = 29, + TAG_BMP_STRING = 30 +}; + + + +/* Locate a TLV encoded data object in BUFFER of LENGTH and return a + pointer to value as well as its length in NBYTES. Return NULL if + it was not found. Note, that the function does not check whether + the value fits into the provided buffer.*/ +const unsigned char *find_tlv (const unsigned char *buffer, size_t length, + int tag, size_t *nbytes); + + +/* ASN.1 BER parser: Parse BUFFER of length SIZE and return the tag + and the length part from the TLV triplet. Update BUFFER and SIZE + on success. */ +gpg_error_t parse_ber_header (unsigned char const **buffer, size_t *size, + int *r_class, int *r_tag, + int *r_constructed, + int *r_ndef, size_t *r_length, size_t *r_nhdr); + + + +#endif /* SCD_TLV_H */ diff --git a/tools/gpgparsemail.c b/tools/gpgparsemail.c new file mode 100644 index 000000000..956cf18d9 --- /dev/null +++ b/tools/gpgparsemail.c @@ -0,0 +1,705 @@ +/* gpgparsemail.c - Standalone crypto mail parser + * Copyright (C) 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 + */ + + +/* This utility prints an RFC8222, possible MIME structured, message + in an annotated format with the first column having an indicator + for the content of the line.. Several options are available to + scrutinize the message. S/MIME and OpenPGP suuport is included. */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rfc822parse.h" + + +#define PGM "gpgparsemail" + +/* Option flags. */ +static int verbose; +static int debug; +static int opt_crypto; /* Decrypt or verify messages. */ +static int opt_no_header; /* Don't output the header lines. */ + +/* Structure used to communicate with the parser callback. */ +struct parse_info_s { + int show_header; /* Show the header lines. */ + int show_data; /* Show the data lines. */ + unsigned int skip_show; /* Temporary disable above for these + number of lines. */ + int show_data_as_note; /* The next data line should be shown + as a note. */ + int show_boundary; + int nesting_level; + + int gpgsm_mime; /* gpgsm shall be used from S/MIME. */ + char *signing_protocol; + int hashing_level; /* The nesting level we are hashing. */ + int hashing; + FILE *hash_file; + FILE *sig_file; + int verify_now; /* Falg set when all signature data is + available. */ +}; + + +/* Print diagnostic message and exit with failure. */ +static void +die (const char *format, ...) +{ + va_list arg_ptr; + + fflush (stdout); + fprintf (stderr, "%s: ", PGM); + + va_start (arg_ptr, format); + vfprintf (stderr, format, arg_ptr); + va_end (arg_ptr); + putc ('\n', stderr); + + exit (1); +} + + +/* Print diagnostic message. */ +static void +err (const char *format, ...) +{ + va_list arg_ptr; + + fflush (stdout); + fprintf (stderr, "%s: ", PGM); + + va_start (arg_ptr, format); + vfprintf (stderr, format, arg_ptr); + va_end (arg_ptr); + putc ('\n', stderr); +} + +static void * +xmalloc (size_t n) +{ + void *p = malloc (n); + if (!p) + die ("out of core: %s", strerror (errno)); + return p; +} + +/* static void * */ +/* xcalloc (size_t n, size_t m) */ +/* { */ +/* void *p = calloc (n, m); */ +/* if (!p) */ +/* die ("out of core: %s", strerror (errno)); */ +/* return p; */ +/* } */ + +/* static void * */ +/* xrealloc (void *old, size_t n) */ +/* { */ +/* void *p = realloc (old, n); */ +/* if (!p) */ +/* die ("out of core: %s", strerror (errno)); */ +/* return p; */ +/* } */ + +static char * +xstrdup (const char *string) +{ + void *p = malloc (strlen (string)+1); + if (!p) + die ("out of core: %s", strerror (errno)); + strcpy (p, string); + return p; +} + +static char * +stpcpy (char *a,const char *b) +{ + while (*b) + *a++ = *b++; + *a = 0; + + return (char*)a; +} + + +static int +run_gnupg (int smime, int sig_fd, int data_fd, int *close_list) +{ + int rp[2]; + pid_t pid; + int i, c, is_status; + unsigned int pos; + char status_buf[10]; + const char *cmd = smime? "gpgsm":"gpg"; + FILE *fp; + + if (pipe (rp) == -1) + die ("error creating a pipe: %s", strerror (errno)); + + pid = fork (); + if (pid == -1) + die ("error forking process: %s", strerror (errno)); + + if (!pid) + { /* Child. */ + char data_fd_buf[50]; + int fd; + + /* Connect our signature fd to stdin. */ + if (sig_fd != 0) + { + if (dup2 (sig_fd, 0) == -1) + die ("dup2 stdin failed: %s", strerror (errno)); + } + + /* Keep our data fd and format it for gpg/gpgsm use. */ + sprintf (data_fd_buf, "-&%d", data_fd); + + /* Send stdout to the bit bucket. */ + fd = open ("/dev/null", O_WRONLY); + if (fd == -1) + die ("can't open `/dev/null': %s", strerror (errno)); + if (fd != 1) + { + if (dup2 (fd, 1) == -1) + die ("dup2 stderr failed: %s", strerror (errno)); + } + + /* Connect stderr to our pipe. */ + if (rp[1] != 2) + { + if (dup2 (rp[1], 2) == -1) + die ("dup2 stderr failed: %s", strerror (errno)); + } + + /* Close other files. */ + for (i=0; (fd=close_list[i]) != -1; i++) + if (fd > 2 && fd != data_fd) + close (fd); + errno = 0; + + execlp (cmd, cmd, + "--enable-special-filenames", + "--status-fd", "2", + "--assume-base64", + "--verify", + "--", + "-", data_fd_buf, + NULL); + + die ("failed to exec the crypto command: %s", strerror (errno)); + } + + /* Parent. */ + close (rp[1]); + + fp = fdopen (rp[0], "r"); + if (!fp) + die ("can't fdopen pipe for reading: %s", strerror (errno)); + + pos = 0; + is_status = 0; + assert (sizeof status_buf > 9); + while ((c=getc (fp)) != EOF) + { + if (pos < 9) + status_buf[pos] = c; + else + { + if (pos == 9) + { + is_status = !memcmp (status_buf, "[GNUPG:] ", 9); + if (is_status) + fputs ( "c ", stdout); + else if (verbose) + fputs ( "# ", stdout); + fwrite (status_buf, 9, 1, stdout); + } + putchar (c); + } + if (c == '\n') + { + if (verbose && pos < 9) + { + fputs ( "# ", stdout); + fwrite (status_buf, pos+1, 1, stdout); + } + pos = 0; + } + else + pos++; + } + if (pos) + { + if (verbose && pos < 9) + { + fputs ( "# ", stdout); + fwrite (status_buf, pos+1, 1, stdout); + } + putchar ('\n'); + } + fclose (fp); + + while ( (i=waitpid (pid, NULL, 0)) == -1 && errno == EINTR) + ; + if (i == -1) + die ("waiting for child failed: %s", strerror (errno)); + + return 0; +} + + + + +/* Verify the signature in the current temp files. */ +static void +verify_signature (struct parse_info_s *info) +{ + int close_list[10]; + + assert (info->hash_file); + assert (info->sig_file); + rewind (info->hash_file); + rewind (info->sig_file); + +/* printf ("# Begin hashed data\n"); */ +/* while ( (c=getc (info->hash_file)) != EOF) */ +/* putchar (c); */ +/* printf ("# End hashed data signature\n"); */ +/* printf ("# Begin signature\n"); */ +/* while ( (c=getc (info->sig_file)) != EOF) */ +/* putchar (c); */ +/* printf ("# End signature\n"); */ +/* rewind (info->hash_file); */ +/* rewind (info->sig_file); */ + + close_list[0] = -1; + run_gnupg (1, fileno (info->sig_file), fileno (info->hash_file), close_list); +} + + + + + +/* Prepare for a multipart/signed. + FIELD_CTX is the parsed context of the content-type header.*/ +static void +mime_signed_begin (struct parse_info_s *info, rfc822parse_t msg, + rfc822parse_field_t field_ctx) +{ + const char *s; + s = rfc822parse_query_parameter (field_ctx, "protocol", 1); + if (s) + { + printf ("h signed.protocol: %s\n", s); + if (!strcmp (s, "application/pkcs7-signature") + || !strcmp (s, "application/x-pkcs7-signature")) + { + if (info->gpgsm_mime) + err ("note: ignoring nested pkcs7-signature"); + else + { + info->gpgsm_mime = 1; + free (info->signing_protocol); + info->signing_protocol = xstrdup (s); + } + } + else if (verbose) + printf ("# this protocol is not supported\n"); + } +} + + +/* Prepare for a multipart/encrypted. + FIELD_CTX is the parsed context of the content-type header.*/ +static void +mime_encrypted_begin (struct parse_info_s *info, rfc822parse_t msg, + rfc822parse_field_t field_ctx) +{ + const char *s; + s = rfc822parse_query_parameter (field_ctx, "protocol", 0); + if (s) + printf ("h encrypted.protocol: %s\n", s); +} + + + +/* Print the event received by the parser for debugging as comment + line. */ +static void +show_event (rfc822parse_event_t event) +{ + const char *s; + + switch (event) + { + case RFC822PARSE_OPEN: s= "Open"; break; + case RFC822PARSE_CLOSE: s= "Close"; break; + case RFC822PARSE_CANCEL: s= "Cancel"; break; + case RFC822PARSE_T2BODY: s= "T2Body"; break; + case RFC822PARSE_FINISH: s= "Finish"; break; + case RFC822PARSE_RCVD_SEEN: s= "Rcvd_Seen"; break; + case RFC822PARSE_LEVEL_DOWN: s= "Level_Down"; break; + case RFC822PARSE_LEVEL_UP: s= "Level_Up"; break; + case RFC822PARSE_BOUNDARY: s= "Boundary"; break; + case RFC822PARSE_LAST_BOUNDARY: s= "Last_Boundary"; break; + case RFC822PARSE_BEGIN_HEADER: s= "Begin_Header"; break; + case RFC822PARSE_PREAMBLE: s= "Preamble"; break; + case RFC822PARSE_EPILOGUE: s= "Epilogue"; break; + default: s= "[unknown event]"; break; + } + printf ("# *** got RFC822 event %s\n", s); +} + +/* This function is called by the parser to communicate events. This + callback comminucates with the main program using a structure + passed in OPAQUE. Should retrun 0 or set errno and return -1. */ +static int +message_cb (void *opaque, rfc822parse_event_t event, rfc822parse_t msg) +{ + struct parse_info_s *info = opaque; + + if (debug) + show_event (event); + if (event == RFC822PARSE_OPEN) + { + /* Initialize for a new message. */ + info->show_header = 1; + } + else if (event == RFC822PARSE_T2BODY) + { + rfc822parse_field_t ctx; + + ctx = rfc822parse_parse_field (msg, "Content-Type", -1); + if (ctx) + { + const char *s1, *s2; + s1 = rfc822parse_query_media_type (ctx, &s2); + if (s1) + { + printf ("h media: %*s%s %s\n", + info->nesting_level*2, "", s1, s2); + if (info->gpgsm_mime == 3) + { + char *buf = xmalloc (strlen (s1) + strlen (s2) + 2); + strcpy (stpcpy (stpcpy (buf, s1), "/"), s2); + assert (info->signing_protocol); + if (strcmp (buf, info->signing_protocol)) + err ("invalid S/MIME structure; expected `%s', found `%s'", + info->signing_protocol, buf); + else + { + printf ("c begin_signature\n"); + info->gpgsm_mime++; + if (opt_crypto) + { + assert (!info->sig_file); + info->sig_file = tmpfile (); + if (!info->sig_file) + die ("error creating temp file: %s", + strerror (errno)); + } + } + free (buf); + } + else if (!strcmp (s1, "multipart")) + { + if (!strcmp (s2, "signed")) + mime_signed_begin (info, msg, ctx); + else if (!strcmp (s2, "encrypted")) + mime_encrypted_begin (info, msg, ctx); + } + } + else + printf ("h media: %*s none\n", info->nesting_level*2, ""); + + rfc822parse_release_field (ctx); + } + else + printf ("h media: %*stext plain [assumed]\n", + info->nesting_level*2, ""); + info->show_header = 0; + info->show_data = 1; + info->skip_show = 1; + } + else if (event == RFC822PARSE_PREAMBLE) + info->show_data_as_note = 1; + else if (event == RFC822PARSE_LEVEL_DOWN) + { + printf ("b down\n"); + info->nesting_level++; + } + else if (event == RFC822PARSE_LEVEL_UP) + { + printf ("b up\n"); + if (info->nesting_level) + info->nesting_level--; + else + err ("invalid structure (bad nesting level)"); + } + else if (event == RFC822PARSE_BOUNDARY || event == RFC822PARSE_LAST_BOUNDARY) + { + info->show_data = 0; + info->show_boundary = 1; + if (event == RFC822PARSE_BOUNDARY) + { + info->show_header = 1; + info->skip_show = 1; + printf ("b part\n"); + } + else + printf ("b last\n"); + + if (info->gpgsm_mime == 2 && info->nesting_level == info->hashing_level) + { + printf ("c end_hash\n"); + info->gpgsm_mime++; + info->hashing = 0; + } + else if (info->gpgsm_mime == 4) + { + printf ("c end_signature\n"); + info->verify_now = 1; + } + } + else if (event == RFC822PARSE_BEGIN_HEADER) + { + if (info->gpgsm_mime == 1) + { + printf ("c begin_hash\n"); + info->hashing = 1; + info->hashing_level = info->nesting_level; + info->gpgsm_mime++; + + if (opt_crypto) + { + assert (!info->hash_file); + info->hash_file = tmpfile (); + if (!info->hash_file) + die ("failed to create temporary file: %s", strerror (errno)); + } + } + } + + return 0; +} + + +/* Read a message from FP and process it according to the global + options. */ +static void +parse_message (FILE *fp) +{ + char line[5000]; + size_t length; + rfc822parse_t msg; + unsigned int lineno = 0; + int no_cr_reported = 0; + struct parse_info_s info; + + memset (&info, 0, sizeof info); + + msg = rfc822parse_open (message_cb, &info); + if (!msg) + die ("can't open parser: %s", strerror (errno)); + + /* Fixme: We should not use fgets becuase it can't cope with + embedded nul characters. */ + while (fgets (line, sizeof (line), fp)) + { + lineno++; + if (lineno == 1 && !strncmp (line, "From ", 5)) + continue; /* We better ignore a leading From line. */ + + length = strlen (line); + if (length && line[length - 1] == '\n') + line[--length] = 0; + else + err ("line number %u too long or last line not terminated", lineno); + if (length && line[length - 1] == '\r') + line[--length] = 0; + else if (verbose && !no_cr_reported) + { + err ("non canonical ended line detected (line %u)", lineno); + no_cr_reported = 1; + } + + + if (rfc822parse_insert (msg, line, length)) + die ("parser failed: %s", strerror (errno)); + + if (info.hashing) + { + /* Delay hashing of the CR/LF because the last line ending + belongs to the next boundary. */ + if (debug) + printf ("# hashing %s`%s'\n", info.hashing==2?"CR,LF+":"", line); + if (opt_crypto) + { + if (info.hashing == 2) + fputs ("\r\n", info.hash_file); + fputs (line, info.hash_file); + if (ferror (info.hash_file)) + die ("error writing to temporary file: %s", strerror (errno)); + } + + info.hashing = 2; + } + + if (info.sig_file && opt_crypto) + { + if (info.verify_now) + { + verify_signature (&info); + fclose (info.hash_file); + info.hash_file = NULL; + fclose (info.sig_file); + info.sig_file = NULL; + info.gpgsm_mime = 0; + } + else + { + fputs (line, info.sig_file); + fputs ("\r\n", info.sig_file); + if (ferror (info.sig_file)) + die ("error writing to temporary file: %s", strerror (errno)); + } + } + + if (info.show_boundary) + { + if (!opt_no_header) + printf (":%s\n", line); + info.show_boundary = 0; + } + + if (info.skip_show) + info.skip_show--; + else if (info.show_data) + { + if (info.show_data_as_note) + { + if (verbose) + printf ("# DATA: %s\n", line); + info.show_data_as_note = 0; + } + else + printf (" %s\n", line); + } + else if (info.show_header && !opt_no_header) + printf (".%s\n", line); + + } + + rfc822parse_close (msg); +} + + +int +main (int argc, char **argv) +{ + int last_argc = -1; + + if (argc) + { + argc--; argv++; + } + while (argc && last_argc != argc ) + { + last_argc = argc; + if (!strcmp (*argv, "--")) + { + argc--; argv++; + break; + } + else if (!strcmp (*argv, "--help")) + { + puts ( + "Usage: " PGM " [OPTION] [FILE]\n" + "Parse a mail message into an annotated format.\n\n" + " --crypto decrypt or verify messages\n" + " --no-header don't output the header lines\n" + " --verbose enable extra informational output\n" + " --debug enable additional debug output\n" + " --help display this help and exit\n\n" + "With no FILE, or when FILE is -, read standard input.\n\n" + "Report bugs to ."); + exit (0); + } + else if (!strcmp (*argv, "--verbose")) + { + verbose = 1; + argc--; argv++; + } + else if (!strcmp (*argv, "--debug")) + { + verbose = debug = 1; + argc--; argv++; + } + else if (!strcmp (*argv, "--crypto")) + { + opt_crypto = 1; + argc--; argv++; + } + else if (!strcmp (*argv, "--no-header")) + { + opt_no_header = 1; + argc--; argv++; + } + } + + if (argc > 1) + die ("usage: " PGM " [OPTION] [FILE] (try --help for more information)\n"); + + signal (SIGPIPE, SIG_IGN); + + if (argc && strcmp (*argv, "-")) + { + FILE *fp = fopen (*argv, "rb"); + if (!fp) + die ("can't open `%s': %s", *argv, strerror (errno)); + parse_message (fp); + fclose (fp); + } + else + parse_message (stdin); + + return 0; +} + + +/* +Local Variables: +compile-command: "gcc -Wall -g -o gpgparsemail rfc822parse.c gpgparsemail.c" +End: +*/ diff --git a/tools/rfc822parse.c b/tools/rfc822parse.c new file mode 100644 index 000000000..be1cf4a47 --- /dev/null +++ b/tools/rfc822parse.c @@ -0,0 +1,1235 @@ +/* rfc822parse.c - Simple mail and MIME parser + * Copyright (C) 1999, 2000 Werner Koch, Duesseldorf + * Copyright (C) 2003, g10 Code GmbH + * + * This program 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. + * + * This program is 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 + */ + + +/* According to RFC822 binary 0 are allowed at many places. We + * do not handle this correct especially in the field parsing code. It + * should be easy to fix and the API provides a interfcaes which returns + * the length but in addition makes sure that returned strings are always + * ended by a \0. + * + * Furthermore, the case of field names is changed and thus it is not + * always a good idea to use these modified header + * lines (e.g. signatures may break). + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include "rfc822parse.h" + +enum token_type +{ + tSPACE, + tATOM, + tQUOTED, + tDOMAINLIT, + tSPECIAL +}; + +/* For now we directly use our TOKEN as the parse context */ +typedef struct rfc822parse_field_context *TOKEN; +struct rfc822parse_field_context +{ + TOKEN next; + enum token_type type; + struct { + unsigned int cont:1; + unsigned int lowered:1; + } flags; + /*TOKEN owner_pantry; */ + char data[1]; +}; + +struct hdr_line +{ + struct hdr_line *next; + int cont; /* This is a continuation of the previous line. */ + unsigned char line[1]; +}; + +typedef struct hdr_line *HDR_LINE; + + +struct part +{ + struct part *right; /* The next part. */ + struct part *down; /* A contained part. */ + HDR_LINE hdr_lines; /* Header lines os that part. */ + HDR_LINE *hdr_lines_tail; /* Helper for adding lines. */ + char *boundary; /* Only used in the first part. */ +}; +typedef struct part *part_t; + +struct rfc822parse_context +{ + rfc822parse_cb_t callback; + void *callback_value; + int callback_error; + int in_body; + int in_preamble; /* Wether we are before the first boundary. */ + part_t parts; /* The tree of parts. */ + part_t current_part; /* Whom we are processing (points into parts). */ + const char *boundary; /* Current boundary. */ +}; + +static HDR_LINE find_header (rfc822parse_t msg, const char *name, + int which, HDR_LINE * rprev); + + +static size_t +length_sans_trailing_ws (const unsigned char *line, size_t len) +{ + const unsigned char *p, *mark; + size_t n; + + for (mark=NULL, p=line, n=0; n < len; n++, p++) + { + if (strchr (" \t\r\n", *p )) + { + if( !mark ) + mark = p; + } + else + mark = NULL; + } + + if (mark) + return mark - line; + return len; +} + + +static void +lowercase_string (unsigned char *string) +{ + for (; *string; string++) + if (*string >= 'A' && *string <= 'Z') + *string = *string - 'A' + 'a'; +} + +/* Transform a header name into a standard capitalized format; i.e + "Content-Type". Conversion stops at the colon. As usual we don't + use the localized versions of ctype.h. + */ +static void +capitalize_header_name (unsigned char *name) +{ + int first = 1; + + for (; *name && *name != ':'; name++) + if (*name == '-') + first = 1; + else if (first) + { + if (*name >= 'a' && *name <= 'z') + *name = *name - 'a' + 'A'; + first = 0; + } + else if (*name >= 'A' && *name <= 'Z') + *name = *name - 'A' + 'a'; +} + + +static char * +stpcpy (char *a,const char *b) +{ + while (*b) + *a++ = *b++; + *a = 0; + + return (char*)a; +} + + +/* If a callback has been registerd, call it for the event of type + EVENT. */ +static int +do_callback (rfc822parse_t msg, rfc822parse_event_t event) +{ + int rc; + + if (!msg->callback || msg->callback_error) + return 0; + rc = msg->callback (msg->callback_value, event, msg); + if (rc) + msg->callback_error = rc; + return rc; +} + +static part_t +new_part (void) +{ + part_t part; + + part = calloc (1, sizeof *part); + if (part) + { + part->hdr_lines_tail = &part->hdr_lines; + } + return part; +} + + +static void +release_part (part_t part) +{ + part_t tmp; + HDR_LINE hdr, hdr2; + + for (; part; part = tmp) + { + tmp = part->right; + if (part->down) + release_part (part->down); + for (hdr = part->hdr_lines; hdr; hdr = hdr2) + { + hdr2 = hdr->next; + free (hdr); + } + free (part->boundary); + free (part); + } +} + + +static void +release_handle_data (rfc822parse_t msg) +{ + release_part (msg->parts); + msg->parts = NULL; + msg->current_part = NULL; + msg->boundary = NULL; +} + + +/* Create a new parsing context for an entire rfc822 message and + return it. CB and CB_VALUE may be given to callback for certain + events. NULL is returned on error with errno set appropriately. */ +rfc822parse_t +rfc822parse_open (rfc822parse_cb_t cb, void *cb_value) +{ + rfc822parse_t msg = calloc (1, sizeof *msg); + if (msg) + { + msg->parts = msg->current_part = new_part (); + if (!msg->parts) + { + free (msg); + msg = NULL; + } + else + { + msg->callback = cb; + msg->callback_value = cb_value; + if (do_callback (msg, RFC822PARSE_OPEN)) + { + release_handle_data (msg); + free (msg); + msg = NULL; + } + } + } + return msg; +} + + +void +rfc822parse_cancel (rfc822parse_t msg) +{ + if (msg) + { + do_callback (msg, RFC822PARSE_CANCEL); + release_handle_data (msg); + free (msg); + } +} + + +void +rfc822parse_close (rfc822parse_t msg) +{ + if (msg) + { + do_callback (msg, RFC822PARSE_CLOSE); + release_handle_data (msg); + free (msg); + } +} + +static part_t +find_parent (part_t tree, part_t target) +{ + part_t part; + + for (part = tree->down; part; part = part->right) + { + if (part == target) + return tree; /* Found. */ + if (part->down) + { + part_t tmp = find_parent (part, target); + if (tmp) + return tmp; + } + } + return NULL; +} + +static void +set_current_part_to_parent (rfc822parse_t msg) +{ + part_t parent; + + assert (msg->current_part); + parent = find_parent (msg->parts, msg->current_part); + if (!parent) + return; /* Already at the top. */ + +#ifndef NDEBUG + { + part_t part; + for (part = parent->down; part; part = part->right) + if (part == msg->current_part) + break; + assert (part); + } +#endif + msg->current_part = parent; + + parent = find_parent (msg->parts, parent); + msg->boundary = parent? parent->boundary: NULL; +} + + + +/**************** + * We have read in all header lines and are about to receive the body + * part. The delimiter line has already been processed. + * + * FIXME: we's better return an error in case of memory failures. + */ +static int +transition_to_body (rfc822parse_t msg) +{ + rfc822parse_field_t ctx; + int rc; + + rc = do_callback (msg, RFC822PARSE_T2BODY); + if (!rc) + { + /* Store the boundary if we have multipart type. */ + ctx = rfc822parse_parse_field (msg, "Content-Type", -1); + if (ctx) + { + const char *s; + + s = rfc822parse_query_media_type (ctx, NULL); + if (s && !strcmp (s,"multipart")) + { + s = rfc822parse_query_parameter (ctx, "boundary", 0); + if (s) + { + assert (!msg->current_part->boundary); + msg->current_part->boundary = malloc (strlen (s) + 1); + if (msg->current_part->boundary) + { + part_t part; + + strcpy (msg->current_part->boundary, s); + msg->boundary = msg->current_part->boundary; + part = new_part (); + if (!part) + { + int save_errno = errno; + rfc822parse_release_field (ctx); + errno = save_errno; + return -1; + } + rc = do_callback (msg, RFC822PARSE_LEVEL_DOWN); + assert (!msg->current_part->down); + msg->current_part->down = part; + msg->current_part = part; + msg->in_preamble = 1; + } + } + } + rfc822parse_release_field (ctx); + } + } + + return rc; +} + +/* We have just passed a MIME boundary and need to prepare for new part. + headers. */ +static int +transition_to_header (rfc822parse_t msg) +{ + part_t part; + + assert (msg->current_part); + assert (!msg->current_part->right); + + part = new_part (); + if (!part) + return -1; + + msg->current_part->right = part; + msg->current_part = part; + return 0; +} + + +static int +insert_header (rfc822parse_t msg, const unsigned char *line, size_t length) +{ + HDR_LINE hdr; + + assert (msg->current_part); + if (!length) + { + msg->in_body = 1; + return transition_to_body (msg); + } + + if (!msg->current_part->hdr_lines) + do_callback (msg, RFC822PARSE_BEGIN_HEADER); + + length = length_sans_trailing_ws (line, length); + hdr = malloc (sizeof (*hdr) + length); + if (!hdr) + return -1; + hdr->next = NULL; + hdr->cont = (*line == ' ' || *line == '\t'); + memcpy (hdr->line, line, length); + hdr->line[length] = 0; /* Make it a string. */ + + /* Transform a field name into canonical format. */ + if (!hdr->cont && strchr (line, ':')) + capitalize_header_name (hdr->line); + + *msg->current_part->hdr_lines_tail = hdr; + msg->current_part->hdr_lines_tail = &hdr->next; + + /* Lets help the caller to prevent mail loops and issue an event for + * every Received header. */ + if (length >= 9 && !memcmp (line, "Received:", 9)) + do_callback (msg, RFC822PARSE_RCVD_SEEN); + return 0; +} + + +/**************** + * Note: We handle the body transparent to allow binary zeroes in it. + */ +static int +insert_body (rfc822parse_t msg, const unsigned char *line, size_t length) +{ + int rc = 0; + + if (length > 2 && *line == '-' && line[1] == '-' && msg->boundary) + { + size_t blen = strlen (msg->boundary); + + if (length == blen + 2 + && !memcmp (line+2, msg->boundary, blen)) + { + rc = do_callback (msg, RFC822PARSE_BOUNDARY); + msg->in_body = 0; + if (!rc && !msg->in_preamble) + rc = transition_to_header (msg); + msg->in_preamble = 0; + } + else if (length == blen + 4 + && line[length-2] =='-' && line[length-1] == '-' + && !memcmp (line+2, msg->boundary, blen)) + { + rc = do_callback (msg, RFC822PARSE_LAST_BOUNDARY); + msg->boundary = NULL; /* No current boundary anymore. */ + set_current_part_to_parent (msg); + + /* Fixme: The next should acctually be sent right before the + next boundary, so that we can mark the epilogue. */ + if (!rc) + rc = do_callback (msg, RFC822PARSE_LEVEL_UP); + } + } + if (msg->in_preamble && !rc) + rc = do_callback (msg, RFC822PARSE_PREAMBLE); + + return rc; +} + +/* Insert the next line into the parser. Return 0 on success or true + on error with errno set appropriately. */ +int +rfc822parse_insert (rfc822parse_t msg, const unsigned char *line, size_t length) +{ + return (msg->in_body + ? insert_body (msg, line, length) + : insert_header (msg, line, length)); +} + + +/* Tell the parser that we have finished the message. */ +int +rfc822parse_finish (rfc822parse_t msg) +{ + return do_callback (msg, RFC822PARSE_FINISH); +} + + + +/**************** + * Get a copy of a header line. The line is returned as one long + * string with LF to separate the continuation line. Caller must free + * the return buffer. which may be used to enumerate over all lines. + * Wildcards are allowed. This function works on the current headers; + * i.e. the regular mail headers or the MIME headers of the current + * part. + * + * WHICH gives the mode: + * -1 := Take the last occurence + * n := Take the n-th one. + * + * Returns a newly allocated buffer or NULL on error. errno is set in + * case of a memory failure or set to 0 if the requested field is not + * available. + */ +char * +rfc822parse_get_field (rfc822parse_t msg, const char *name, int which) +{ + HDR_LINE h, h2; + char *buf, *p; + size_t n; + + h = find_header (msg, name, which, NULL); + if (!h) + { + errno = 0; + return NULL; /* no such field */ + } + + n = strlen (h->line) + 1; + for (h2 = h->next; h2 && h2->cont; h2 = h2->next) + n += strlen (h2->line) + 1; + + buf = p = malloc (n); + if (buf) + { + p = stpcpy (p, h->line); + *p++ = '\n'; + for (h2 = h->next; h2 && h2->cont; h2 = h2->next) + { + p = stpcpy (p, h2->line); + *p++ = '\n'; + } + p[-1] = 0; + } + return buf; +} + + +/**************** + * Enumerate all header. Caller has to provide the address of a pointer + * which has to be initialzed to NULL, the caller should then never change this + * pointer until he has closed the enumeration by passing again the address + * of the pointer but with msg set to NULL. + * The function returns pointers to all the header lines or NULL when + * all lines have been enumerated or no headers are available. + */ +const char * +rfc822parse_enum_header_lines (rfc822parse_t msg, void **context) +{ + HDR_LINE l; + + if (!msg) /* Close. */ + return NULL; + + if (*context == msg || !msg->current_part) + return NULL; + + l = *context ? (HDR_LINE) *context : msg->current_part->hdr_lines; + + if (l) + { + *context = l->next ? (void *) (l->next) : (void *) msg; + return l->line; + } + *context = msg; /* Mark end of list. */ + return NULL; +} + + + +/**************** + * Find a header field. If the Name does end in an asterisk this is meant + * to be a wildcard. + * + * which -1 : Retrieve the last field + * >0 : Retrieve the n-th field + + * RPREV may be used to return the predecessor of the returned field; + * which may be NULL for the very first one. It has to be initialzed + * to either NULL in which case the search start at the first header line, + * or it may point to a headerline, where the search should start + */ +static HDR_LINE +find_header (rfc822parse_t msg, const char *name, int which, HDR_LINE *rprev) +{ + HDR_LINE hdr, prev = NULL, mark = NULL; + unsigned char *p; + size_t namelen, n; + int found = 0; + int glob = 0; + + if (!msg->current_part) + return NULL; + + namelen = strlen (name); + if (namelen && name[namelen - 1] == '*') + { + namelen--; + glob = 1; + } + + hdr = msg->current_part->hdr_lines; + if (rprev && *rprev) + { + /* spool forward to the requested starting place. + * we cannot simply set this as we have to return + * the previous list element too */ + for (; hdr && hdr != *rprev; prev = hdr, hdr = hdr->next) + ; + } + + for (; hdr; prev = hdr, hdr = hdr->next) + { + if (hdr->cont) + continue; + if (!(p = strchr (hdr->line, ':'))) + continue; /* invalid header, just skip it. */ + n = p - hdr->line; + if (!n) + continue; /* invalid name */ + if ((glob ? (namelen <= n) : (namelen == n)) + && !memcmp (hdr->line, name, namelen)) + { + found++; + if (which == -1) + mark = hdr; + else if (found == which) + { + if (rprev) + *rprev = prev; + return hdr; + } + } + } + if (mark && rprev) + *rprev = prev; + return mark; +} + + + +static const char * +skip_ws (const char *s) +{ + while (*s == ' ' || *s == '\t' || *s == '\r' || *s == '\n') + s++; + return s; +} + + +static void +release_token_list (TOKEN t) +{ + while (t) + { + TOKEN t2 = t->next; + /* fixme: If we have owner_pantry, put the token back to + * this pantry so that it can be reused later */ + free (t); + t = t2; + } +} + + +static TOKEN +new_token (enum token_type type, const char *buf, size_t length) +{ + TOKEN t; + + /* fixme: look through our pantries to find a suitable + * token for reuse */ + t = malloc (sizeof *t + length); + if (t) + { + t->next = NULL; + t->type = type; + memset (&t->flags, 0, sizeof (t->flags)); + t->data[0] = 0; + if (buf) + { + memcpy (t->data, buf, length); + t->data[length] = 0; /* Make sure it is a C string. */ + } + else + t->data[0] = 0; + } + return t; +} + +static TOKEN +append_to_token (TOKEN old, const char *buf, size_t length) +{ + size_t n = strlen (old->data); + TOKEN t; + + t = malloc (sizeof *t + n + length); + if (t) + { + t->next = old->next; + t->type = old->type; + t->flags = old->flags; + memcpy (t->data, old->data, n); + memcpy (t->data + n, buf, length); + t->data[n + length] = 0; + old->next = NULL; + release_token_list (old); + } + return t; +} + + + +/* + Parse a field into tokens as defined by rfc822. + */ +static TOKEN +parse_field (HDR_LINE hdr) +{ + static const char specials[] = "<>@.,;:\\[]\"()"; + static const char specials2[] = "<>@.,;:"; + static const char tspecials[] = "/?=<>@,;:\\[]\"()"; + static const char tspecials2[] = "/?=<>@.,;:"; + static struct + { + const unsigned char *name; + size_t namelen; + } tspecial_header[] = { + { "Content-Type", 12}, + { "Content-Transfer-Encoding", 25}, + { NULL, 0} + }; + const char *delimiters; + const char *delimiters2; + const unsigned char *line, *s, *s2; + size_t n; + int i, invalid = 0; + TOKEN t, tok, *tok_tail; + + errno = 0; + if (!hdr) + return NULL; + + tok = NULL; + tok_tail = &tok; + + line = hdr->line; + if (!(s = strchr (line, ':'))) + return NULL; /* oops */ + + n = s - line; + if (!n) + return NULL; /* oops: invalid name */ + + delimiters = specials; + delimiters2 = specials2; + for (i = 0; tspecial_header[i].name; i++) + { + if (n == tspecial_header[i].namelen + && !memcmp (line, tspecial_header[i].name, n)) + { + delimiters = tspecials; + delimiters2 = tspecials2; + break; + } + } + + s++; /* Move over the colon. */ + for (;;) + { + if (!*s) + { + if (!hdr->next || !hdr->next->cont) + break; + hdr = hdr->next; + s = hdr->line; + } + + if (*s == '(') + { + int level = 1; + int in_quote = 0; + + invalid = 0; + for (s++;; s++) + { + if (!*s) + { + if (!hdr->next || !hdr->next->cont) + break; + hdr = hdr->next; + s = hdr->line; + } + + if (in_quote) + { + if (*s == '\"') + in_quote = 0; + else if (*s == '\\' && s[1]) /* what about continuation? */ + s++; + } + else if (*s == ')') + { + if (!--level) + break; + } + else if (*s == '(') + level++; + else if (*s == '\"') + in_quote = 1; + } + if (!*s) + ; /* Actually this is an error, but we don't care about it. */ + else + s++; + } + else if (*s == '\"' || *s == '[') + { + /* We do not check for non-allowed nesting of domainliterals */ + int term = *s == '\"' ? '\"' : ']'; + invalid = 0; + s++; + t = NULL; + + for (;;) + { + for (s2 = s; *s2; s2++) + { + if (*s2 == term) + break; + else if (*s2 == '\\' && s2[1]) /* what about continuation? */ + s2++; + } + + t = (t + ? append_to_token (t, s, s2 - s) + : new_token (term == '\"'? tQUOTED : tDOMAINLIT, s, s2 - s)); + if (!t) + goto failure; + + if (*s2 || !hdr->next || !hdr->next->cont) + break; + hdr = hdr->next; + s = hdr->line; + } + *tok_tail = t; + tok_tail = &t->next; + s = s2; + if (*s) + s++; /* skip the delimiter */ + } + else if ((s2 = strchr (delimiters2, *s))) + { /* Special characters which are not handled above. */ + invalid = 0; + t = new_token (tSPECIAL, s, 1); + if (!t) + goto failure; + *tok_tail = t; + tok_tail = &t->next; + s++; + } + else if (*s == ' ' || *s == '\t' || *s == '\r' || *s == '\n') + { + invalid = 0; + s = skip_ws (s + 1); + } + else if (*s > 0x20 && !(*s & 128)) + { /* Atom. */ + invalid = 0; + for (s2 = s + 1; *s2 > 0x20 + && !(*s2 & 128) && !strchr (delimiters, *s2); s2++) + ; + t = new_token (tATOM, s, s2 - s); + if (!t) + goto failure; + *tok_tail = t; + tok_tail = &t->next; + s = s2; + } + else + { /* Invalid character. */ + if (!invalid) + { /* For parsing we assume only one space. */ + t = new_token (tSPACE, NULL, 0); + if (!t) + goto failure; + *tok_tail = t; + tok_tail = &t->next; + invalid = 1; + } + s++; + } + } + + return tok; + + failure: + { + int save = errno; + release_token_list (tok); + errno = save; + } + return NULL; +} + + + + +/**************** + * Find and parse a header field. + * WHICH indicates what to do if there are multiple instance of the same + * field (like "Received"); the following value are defined: + * -1 := Take the last occurence + * 0 := Reserved + * n := Take the n-th one. + * Returns a handle for further operations on the parse context of the field + * or NULL if the field was not found. + */ +rfc822parse_field_t +rfc822parse_parse_field (rfc822parse_t msg, const char *name, int which) +{ + HDR_LINE hdr; + + if (!which) + return NULL; + + hdr = find_header (msg, name, which, NULL); + if (!hdr) + return NULL; + return parse_field (hdr); +} + +void +rfc822parse_release_field (rfc822parse_field_t ctx) +{ + if (ctx) + release_token_list (ctx); +} + + + +/**************** + * Check whether T points to a parameter. + * A parameter starts with a semicolon and it is assumed that t + * points to exactly this one. + */ +static int +is_parameter (TOKEN t) +{ + t = t->next; + if (!t || t->type != tATOM) + return 0; + t = t->next; + if (!t || !(t->type == tSPECIAL && t->data[0] == '=')) + return 0; + t = t->next; + if (!t) + return 1; /* We assume that an non existing value is an empty one. */ + return t->type == tQUOTED || t->type == tATOM; +} + +/* + Some header (Content-type) have a special syntax where attribute=value + pairs are used after a leading semicolon. The parse_field code + knows about these fields and changes the parsing to the one defined + in RFC2045. + Returns a pointer to the value which is valid as long as the + parse context is valid; NULL is returned in case that attr is not + defined in the header, a missing value is reppresented by an empty string. + + With LOWER_VALUE set to true, a matching field valuebe be + lowercased. + + Note, that ATTR should be lowercase. + */ +const char * +rfc822parse_query_parameter (rfc822parse_field_t ctx, const char *attr, + int lower_value) +{ + TOKEN t, a; + + for (t = ctx; t; t = t->next) + { + /* skip to the next semicolon */ + for (; t && !(t->type == tSPECIAL && t->data[0] == ';'); t = t->next) + ; + if (!t) + return NULL; + if (is_parameter (t)) + { /* Look closer. */ + a = t->next; /* We know that this is an atom */ + if ( !a->flags.lowered ) + { + lowercase_string (a->data); + a->flags.lowered = 1; + } + if (!strcmp (a->data, attr)) + { /* found */ + t = a->next->next; + /* Either T is now an atom, a quoted string or NULL in + * which case we return an empty string. */ + + if ( lower_value && t && !t->flags.lowered ) + { + lowercase_string (t->data); + t->flags.lowered = 1; + } + return t ? t->data : ""; + } + } + } + return NULL; +} + +/**************** + * This function may be used for the Content-Type header to figure out + * the media type and subtype. Note, that the returned strings are + * guaranteed to be lowercase as required by MIME. + * + * Returns: a pointer to the media type and if subtype is not NULL, + * a pointer to the subtype. + */ +const char * +rfc822parse_query_media_type (rfc822parse_field_t ctx, const char **subtype) +{ + TOKEN t = ctx; + const char *type; + + if (t->type != tATOM) + return NULL; + if (!t->flags.lowered) + { + lowercase_string (t->data); + t->flags.lowered = 1; + } + type = t->data; + t = t->next; + if (!t || t->type != tSPECIAL || t->data[0] != '/') + return NULL; + t = t->next; + if (!t || t->type != tATOM) + return NULL; + + if (subtype) + { + if (!t->flags.lowered) + { + lowercase_string (t->data); + t->flags.lowered = 1; + } + *subtype = t->data; + } + return type; +} + + + + + +#ifdef TESTING + +/* Internal debug function to print the structure of the message. */ +static void +dump_structure (rfc822parse_t msg, part_t part, int indent) +{ + if (!part) + { + printf ("*** Structure of this message:\n"); + part = msg->parts; + } + + for (; part; part = part->right) + { + rfc822parse_field_t ctx; + part_t save_part; /* ugly hack - we should have a function to + get part inforation. */ + const char *s; + + save_part = msg->current_part; + msg->current_part = part; + ctx = rfc822parse_parse_field (msg, "Content-Type", -1); + msg->current_part = save_part; + if (ctx) + { + const char *s1, *s2; + s1 = rfc822parse_query_media_type (ctx, &s2); + if (s1) + printf ("*** %*s %s/%s", indent*2, "", s1, s2); + else + printf ("*** %*s [not found]", indent*2, ""); + + s = rfc822parse_query_parameter (ctx, "boundary", 0); + if (s) + printf (" (boundary=\"%s\")", s); + rfc822parse_release_field (ctx); + } + else + printf ("*** %*s text/plain [assumed]", indent*2, ""); + putchar('\n'); + + if (part->down) + dump_structure (msg, part->down, indent + 1); + } + +} + + + +static void +show_param (rfc822parse_field_t ctx, const char *name) +{ + const char *s; + + if (!ctx) + return; + s = rfc822parse_query_parameter (ctx, name, 0); + if (s) + printf ("*** %s: `%s'\n", name, s); +} + + + +static void +show_event (rfc822parse_event_t event) +{ + const char *s; + + switch (event) + { + case RFC822PARSE_OPEN: s= "Open"; break; + case RFC822PARSE_CLOSE: s= "Close"; break; + case RFC822PARSE_CANCEL: s= "Cancel"; break; + case RFC822PARSE_T2BODY: s= "T2Body"; break; + case RFC822PARSE_FINISH: s= "Finish"; break; + case RFC822PARSE_RCVD_SEEN: s= "Rcvd_Seen"; break; + case RFC822PARSE_BOUNDARY: s= "Boundary"; break; + case RFC822PARSE_LAST_BOUNDARY: s= "Last_Boundary"; break; + default: s= "***invalid event***"; break; + } + printf ("*** got RFC822 event %s\n", s); +} + +static int +msg_cb (void *dummy_arg, rfc822parse_event_t event, rfc822parse_t msg) +{ + show_event (event); + if (event == RFC822PARSE_T2BODY) + { + rfc822parse_field_t ctx; + void *ectx; + const char *line; + + for (ectx=NULL; (line = rfc822parse_enum_header_lines (msg, &ectx)); ) + { + printf ("*** HDR: %s\n", line); + } + rfc822parse_enum_header_lines (NULL, &ectx); /* Close enumerator. */ + + ctx = rfc822parse_parse_field (msg, "Content-Type", -1); + if (ctx) + { + const char *s1, *s2; + s1 = rfc822parse_query_media_type (ctx, &s2); + if (s1) + printf ("*** media: `%s/%s'\n", s1, s2); + else + printf ("*** media: [not found]\n"); + show_param (ctx, "boundary"); + show_param (ctx, "protocol"); + rfc822parse_release_field (ctx); + } + else + printf ("*** media: text/plain [assumed]\n"); + + } + + + return 0; +} + + + +int +main (int argc, char **argv) +{ + char line[5000]; + size_t length; + rfc822parse_t msg; + + msg = rfc822parse_open (msg_cb, NULL); + if (!msg) + abort (); + + while (fgets (line, sizeof (line), stdin)) + { + length = strlen (line); + if (length && line[length - 1] == '\n') + line[--length] = 0; + if (length && line[length - 1] == '\r') + line[--length] = 0; + if (rfc822parse_insert (msg, line, length)) + abort (); + } + + dump_structure (msg, NULL, 0); + + rfc822parse_close (msg); + return 0; +} +#endif + +/* +Local Variables: +compile-command: "gcc -Wall -g -DTESTING -o rfc822parse rfc822parse.c" +End: +*/ diff --git a/tools/rfc822parse.h b/tools/rfc822parse.h new file mode 100644 index 000000000..1293117ac --- /dev/null +++ b/tools/rfc822parse.h @@ -0,0 +1,79 @@ +/* rfc822parse.h - Simple mail and MIME parser + * Copyright (C) 1999 Werner Koch, Duesseldorf + * Copyright (C) 2003, g10 Code GmbH + * + * This program 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. + * + * This program 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 + */ + +#ifndef RFC822PARSE_H +#define RFC822PARSE_H + +struct rfc822parse_context; +typedef struct rfc822parse_context *rfc822parse_t; + +typedef enum + { + RFC822PARSE_OPEN = 1, + RFC822PARSE_CLOSE, + RFC822PARSE_CANCEL, + RFC822PARSE_T2BODY, + RFC822PARSE_FINISH, + RFC822PARSE_RCVD_SEEN, + RFC822PARSE_LEVEL_DOWN, + RFC822PARSE_LEVEL_UP, + RFC822PARSE_BOUNDARY, + RFC822PARSE_LAST_BOUNDARY, + RFC822PARSE_BEGIN_HEADER, + RFC822PARSE_PREAMBLE, + RFC822PARSE_EPILOGUE + } +rfc822parse_event_t; + +struct rfc822parse_field_context; +typedef struct rfc822parse_field_context *rfc822parse_field_t; + + +typedef int (*rfc822parse_cb_t) (void *opaque, + rfc822parse_event_t event, + rfc822parse_t msg); + + +rfc822parse_t rfc822parse_open (rfc822parse_cb_t cb, void *opaque_value); + +void rfc822parse_close (rfc822parse_t msg); + +void rfc822parse_cancel (rfc822parse_t msg); +int rfc822parse_finish (rfc822parse_t msg); + +int rfc822parse_insert (rfc822parse_t msg, + const unsigned char *line, size_t length); + +char *rfc822parse_get_field (rfc822parse_t msg, const char *name, int which); + +const char *rfc822parse_enum_header_lines (rfc822parse_t msg, void **context); + +rfc822parse_field_t rfc822parse_parse_field (rfc822parse_t msg, + const char *name, + int which); + +void rfc822parse_release_field (rfc822parse_field_t field); + +const char *rfc822parse_query_parameter (rfc822parse_field_t ctx, + const char *attr, int lower_value); + +const char *rfc822parse_query_media_type (rfc822parse_field_t ctx, + const char **subtype); + +#endif /*RFC822PARSE_H */ -- cgit From 97958029f67eee3f87ad6da48afc3ac73cbbe27f Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 28 Jan 2004 16:21:57 +0000 Subject: (iso7816_manage_security_env): New. (iso7816_decipher): Add PADIND argument. ** app-nks.c is now functional ** --- scd/ChangeLog | 5 ++ scd/app-nks.c | 199 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- scd/app-openpgp.c | 3 +- scd/iso7816.c | 57 ++++++++++++---- scd/iso7816.h | 4 ++ 5 files changed, 246 insertions(+), 22 deletions(-) (limited to 'scd/app-openpgp.c') diff --git a/scd/ChangeLog b/scd/ChangeLog index 3a6a6aea4..66f48d467 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,8 @@ +2004-01-28 Werner Koch + + * iso7816.c (iso7816_manage_security_env): New. + (iso7816_decipher): Add PADIND argument. + 2004-01-27 Werner Koch * command.c (cmd_readcert, cmd_readkey): Work on a copy of LINE. diff --git a/scd/app-nks.c b/scd/app-nks.c index 0a04f7511..2ceb537a2 100644 --- a/scd/app-nks.c +++ b/scd/app-nks.c @@ -33,16 +33,18 @@ #include "tlv.h" static struct { - int fid; /* File ID. */ - int certtype; /* Type of certificate or 0 if it is not a certificate. */ + int fid; /* File ID. */ + int certtype; /* Type of certificate or 0 if it is not a certificate. */ int iskeypair; /* If true has the FID of the correspoding certificate. */ + int issignkey; /* True if file is a key usable for signing. */ + int isenckey; /* True if file is a key usable for decryption. */ } filelist[] = { - { 0x4531, 0, 0xC000 }, + { 0x4531, 0, 0xC000, 1, 0 }, { 0xC000, 101 }, { 0x4331, 100 }, { 0x4332, 100 }, { 0xB000, 110 }, - { 0x45B1, 0, 0xC200 }, + { 0x45B1, 0, 0xC200, 0, 1 }, { 0xC200, 101 }, { 0x43B1, 100 }, { 0x43B2, 100 }, @@ -356,6 +358,191 @@ do_readcert (app_t app, const char *certid, } +/* Verify the PIN if required. */ +static int +verify_pin (app_t app, + int (pincb)(void*, const char *, char **), + void *pincb_arg) +{ + /* Note that force_chv1 is never set but we do it here anyway so + that other applications may euse this function. For example it + makes sense to set force_chv1 for German signature law cards. + NKS is very similar to the DINSIG draft standard. */ + if (!app->did_chv1 || app->force_chv1 ) + { + char *pinvalue; + int rc; + + rc = pincb (pincb_arg, "PIN", &pinvalue); + if (rc) + { + log_info ("PIN callback returned error: %s\n", gpg_strerror (rc)); + return rc; + } + + /* The follwoing limits are due to TCOS but also defined in the + NKS specs. */ + if (strlen (pinvalue) < 6) + { + log_error ("PIN is too short; minimum length is 6\n"); + xfree (pinvalue); + return gpg_error (GPG_ERR_BAD_PIN); + } + else if (strlen (pinvalue) > 16) + { + log_error ("PIN is too large; maximum length is 16\n"); + xfree (pinvalue); + return gpg_error (GPG_ERR_BAD_PIN); + } + + /* Also it is possible to use a local PIN, we use the gloabl + PIN for this application. */ + rc = iso7816_verify (app->slot, 0, pinvalue, strlen (pinvalue)); + if (rc) + { + log_error ("verify PIN failed\n"); + xfree (pinvalue); + return rc; + } + app->did_chv1 = 1; + xfree (pinvalue); + } + + return 0; +} + + + +/* Create the signature and return the allocated result in OUTDATA. + If a PIN is required the PINCB will be used to ask for the PIN; + that callback should return the PIN in an allocated buffer and + store that in the 3rd argument. */ +static int +do_sign (app_t app, const char *keyidstr, int hashalgo, + int (pincb)(void*, const char *, char **), + void *pincb_arg, + const void *indata, size_t indatalen, + unsigned char **outdata, size_t *outdatalen ) +{ + static unsigned char sha1_prefix[15] = /* Object ID is 1.3.14.3.2.26 */ + { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, + 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 }; + static unsigned char rmd160_prefix[15] = /* Object ID is 1.3.36.3.2.1 */ + { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x24, 0x03, + 0x02, 0x01, 0x05, 0x00, 0x04, 0x14 }; + int rc, i; + int fid; + unsigned char data[35]; /* Must be large enough for a SHA-1 digest + + the largest OID _prefix above. */ + + if (!keyidstr || !*keyidstr) + return gpg_error (GPG_ERR_INV_VALUE); + if (indatalen != 20 && indatalen != 16 && indatalen != 35) + return gpg_error (GPG_ERR_INV_VALUE); + + /* Check that the provided ID is vaid. This is not really needed + but we do it to to enforce correct usage by the caller. */ + if (strncmp (keyidstr, "NKS-DF01.", 9) ) + return gpg_error (GPG_ERR_INV_ID); + keyidstr += 9; + if (!hexdigitp (keyidstr) || !hexdigitp (keyidstr+1) + || !hexdigitp (keyidstr+2) || !hexdigitp (keyidstr+3) + || keyidstr[4]) + return gpg_error (GPG_ERR_INV_ID); + fid = xtoi_4 (keyidstr); + for (i=0; filelist[i].fid; i++) + if (filelist[i].iskeypair && filelist[i].fid == fid) + break; + if (!filelist[i].fid) + return gpg_error (GPG_ERR_NOT_FOUND); + if (!filelist[i].issignkey) + return gpg_error (GPG_ERR_INV_ID); + + /* Prepare the DER object from INDATA. */ + if (indatalen == 35) + { + /* Alright, the caller was so kind to send us an already + prepared DER object. Check that it is waht we want and that + it matches the hash algorithm. */ + if (hashalgo == GCRY_MD_SHA1 && !memcmp (indata, sha1_prefix, 15)) + ; + else if (hashalgo == GCRY_MD_RMD160 && !memcmp (indata, rmd160_prefix,15)) + ; + else + return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); + memcpy (data, indata, indatalen); + } + else + { + if (hashalgo == GCRY_MD_SHA1) + memcpy (data, sha1_prefix, 15); + else if (hashalgo == GCRY_MD_RMD160) + memcpy (data, rmd160_prefix, 15); + else + return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); + memcpy (data+15, indata, indatalen); + } + + rc = verify_pin (app, pincb, pincb_arg); + if (!rc) + rc = iso7816_compute_ds (app->slot, data, 35, outdata, outdatalen); + return rc; +} + + + + +/* Decrypt the data in INDATA and return the allocated result in OUTDATA. + If a PIN is required the PINCB will be used to ask for the PIN; it + should return the PIN in an allocated buffer and put it into PIN. */ +static int +do_decipher (app_t app, const char *keyidstr, + int (pincb)(void*, const char *, char **), + void *pincb_arg, + const void *indata, size_t indatalen, + unsigned char **outdata, size_t *outdatalen ) +{ + static const unsigned char mse_parm[] = { + 0x80, 1, 0x10, /* Select algorithm RSA. */ + 0x84, 1, 0x81 /* Select locak secret key 1 for descryption. */ + }; + int rc, i; + int fid; + + if (!keyidstr || !*keyidstr || !indatalen) + return gpg_error (GPG_ERR_INV_VALUE); + + /* Check that the provided ID is vaid. This is not really needed + but we do it to to enforce correct usage by the caller. */ + if (strncmp (keyidstr, "NKS-DF01.", 9) ) + return gpg_error (GPG_ERR_INV_ID); + keyidstr += 9; + if (!hexdigitp (keyidstr) || !hexdigitp (keyidstr+1) + || !hexdigitp (keyidstr+2) || !hexdigitp (keyidstr+3) + || keyidstr[4]) + return gpg_error (GPG_ERR_INV_ID); + fid = xtoi_4 (keyidstr); + for (i=0; filelist[i].fid; i++) + if (filelist[i].iskeypair && filelist[i].fid == fid) + break; + if (!filelist[i].fid) + return gpg_error (GPG_ERR_NOT_FOUND); + if (!filelist[i].isenckey) + return gpg_error (GPG_ERR_INV_ID); + + /* Do the TCOS specific MSE. */ + rc = iso7816_manage_security_env (app->slot, + 0xC1, 0xB8, + mse_parm, sizeof mse_parm); + if (!rc) + rc = verify_pin (app, pincb, pincb_arg); + if (!rc) + rc = iso7816_decipher (app->slot, indata, indatalen, 0x81, + outdata, outdatalen); + return rc; +} + + /* Select the NKS 2.0 application on the card in SLOT. */ int @@ -375,9 +562,9 @@ app_select_nks (APP app) app->fnc.getattr = NULL; app->fnc.setattr = NULL; app->fnc.genkey = NULL; - app->fnc.sign = NULL; + app->fnc.sign = do_sign; app->fnc.auth = NULL; - app->fnc.decipher = NULL; + app->fnc.decipher = do_decipher; app->fnc.change_pin = NULL; app->fnc.check_pin = NULL; } diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 75e3e299e..021d6a52c 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -1121,7 +1121,8 @@ do_decipher (APP app, const char *keyidstr, rc = verify_chv2 (app, pincb, pincb_arg); if (!rc) - rc = iso7816_decipher (app->slot, indata, indatalen, outdata, outdatalen); + rc = iso7816_decipher (app->slot, indata, indatalen, 0, + outdata, outdatalen); return rc; } diff --git a/scd/iso7816.c b/scd/iso7816.c index 9a15ce953..1ee9b55e7 100644 --- a/scd/iso7816.c +++ b/scd/iso7816.c @@ -1,5 +1,5 @@ /* iso7816.c - ISO 7816 commands - * Copyright (C) 2003 Free Software Foundation, Inc. + * Copyright (C) 2003, 2004 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -47,6 +47,7 @@ #define CMD_RESET_RETRY_COUNTER 0x2C #define CMD_GET_DATA 0xCA #define CMD_PUT_DATA 0xDA +#define CMD_MSE 0x22 #define CMD_PSO 0x2A #define CMD_INTERNAL_AUTHENTICATE 0x88 #define CMD_GENERATE_KEYPAIR 0x47 @@ -270,6 +271,23 @@ iso7816_put_data (int slot, int tag, return map_sw (sw); } +/* Manage Security Environment. This is a weird operation and there + is no easy abstraction for it. Furthermore, some card seem to have + a different interpreation of 7816-8 and thus we resort to let the + caller decide what to do. */ +gpg_error_t +iso7816_manage_security_env (int slot, int p1, int p2, + const unsigned char *data, size_t datalen) +{ + int sw; + + if (p1 < 0 || p1 > 255 || p2 < 0 || p2 > 255 || !data || !datalen) + return gpg_error (GPG_ERR_INV_VALUE); + + sw = apdu_send_simple (slot, 0x00, CMD_MSE, p1, p2, datalen, data); + return map_sw (sw); +} + /* Perform the security operation COMPUTE DIGITAL SIGANTURE. On success 0 is returned and the data is availavle in a newly @@ -301,13 +319,14 @@ iso7816_compute_ds (int slot, const unsigned char *data, size_t datalen, } -/* Perform the security operation DECIPHER. On - success 0 is returned and the plaintext is available in a newly - allocated buffer stored at RESULT with its length stored at - RESULTLEN. */ +/* Perform the security operation DECIPHER. PADIND is the padding + indicator to be used. It should be 0 if no padding is required, a + value of -1 suppresses the padding byte. On success 0 is returned + and the plaintext is available in a newly allocated buffer stored + at RESULT with its length stored at RESULTLEN. */ gpg_error_t iso7816_decipher (int slot, const unsigned char *data, size_t datalen, - unsigned char **result, size_t *resultlen) + int padind, unsigned char **result, size_t *resultlen) { int sw; unsigned char *buf; @@ -317,15 +336,23 @@ iso7816_decipher (int slot, const unsigned char *data, size_t datalen, *result = NULL; *resultlen = 0; - /* We need to prepend the padding indicator. */ - buf = xtrymalloc (datalen + 1); - if (!buf) - return out_of_core (); - *buf = 0; /* Padding indicator. */ - memcpy (buf+1, data, datalen); - sw = apdu_send (slot, 0x00, CMD_PSO, 0x80, 0x86, datalen+1, buf, - result, resultlen); - xfree (buf); + if (padind >= 0) + { + /* We need to prepend the padding indicator. */ + buf = xtrymalloc (datalen + 1); + if (!buf) + return out_of_core (); + *buf = padind; /* Padding indicator. */ + memcpy (buf+1, data, datalen); + sw = apdu_send (slot, 0x00, CMD_PSO, 0x80, 0x86, datalen+1, buf, + result, resultlen); + xfree (buf); + } + else + { + sw = apdu_send (slot, 0x00, CMD_PSO, 0x80, 0x86, datalen, data, + result, resultlen); + } if (sw != SW_SUCCESS) { /* Make sure that pending buffers are released. */ diff --git a/scd/iso7816.h b/scd/iso7816.h index 98e688693..937326b6d 100644 --- a/scd/iso7816.h +++ b/scd/iso7816.h @@ -42,11 +42,15 @@ gpg_error_t iso7816_get_data (int slot, int tag, unsigned char **result, size_t *resultlen); gpg_error_t iso7816_put_data (int slot, int tag, const unsigned char *data, size_t datalen); +gpg_error_t iso7816_manage_security_env (int slot, int p1, int p2, + const unsigned char *data, + size_t datalen); gpg_error_t iso7816_compute_ds (int slot, const unsigned char *data, size_t datalen, unsigned char **result, size_t *resultlen); gpg_error_t iso7816_decipher (int slot, const unsigned char *data, size_t datalen, + int padind, unsigned char **result, size_t *resultlen); gpg_error_t iso7816_internal_authenticate (int slot, const unsigned char *data, size_t datalen, -- cgit From f8d44bc637a4c897fd4448de804ee08ae065e194 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 16 Mar 2004 10:49:37 +0000 Subject: *** empty log message *** --- scd/ChangeLog | 14 +++++ scd/apdu.c | 4 +- scd/app-nks.c | 4 +- scd/app-openpgp.c | 2 +- scd/app.c | 2 +- scd/card-dinsig.c | 4 +- scd/card-p15.c | 12 ++--- scd/card.c | 8 +-- scd/ccid-driver.c | 14 +++-- scd/command.c | 6 +-- scd/iso7816.c | 24 +++++---- scd/iso7816.h | 1 + scd/sc-investigate.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++++--- scd/scdaemon.h | 8 --- 14 files changed, 200 insertions(+), 46 deletions(-) (limited to 'scd/app-openpgp.c') diff --git a/scd/ChangeLog b/scd/ChangeLog index 66ceebd22..a9296cbbb 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,17 @@ +2004-03-11 Werner Koch + + * scdaemon.h (out_of_core): Removed. Replaced callers by standard + gpg_error function. + + * apdu.c, iso7816.c, ccid-driver.c [GNUPG_SCD_MAIN_HEADER]: Allow + to include a header defined by the compiler. This helps us to + reuse the source in other software. + +2004-03-10 Werner Koch + + * iso7816.c (iso7816_read_record): New arg SHORT_EF. Changed all + callers. + 2004-02-18 Werner Koch * sc-investigate.c (main): Setup the used character set. diff --git a/scd/apdu.c b/scd/apdu.c index e5295f566..7843fd566 100644 --- a/scd/apdu.c +++ b/scd/apdu.c @@ -28,7 +28,9 @@ # include #endif -#if GNUPG_MAJOR_VERSION == 1 +#if defined(GNUPG_SCD_MAIN_HEADER) +#include GNUPG_SCD_MAIN_HEADER +#elif GNUPG_MAJOR_VERSION == 1 /* This is used with GnuPG version < 1.9. The code has been source copied from the current GnuPG >= 1.9 and is maintained over there. */ diff --git a/scd/app-nks.c b/scd/app-nks.c index 2ceb537a2..a4b6e3a15 100644 --- a/scd/app-nks.c +++ b/scd/app-nks.c @@ -130,10 +130,10 @@ keygripstr_from_pk_file (int slot, int fid, char *r_gripstr) err = iso7816_select_file (slot, fid, 0, NULL, NULL); if (err) return err; - err = iso7816_read_record (slot, 1, 1, &buffer[0], &buflen[0]); + err = iso7816_read_record (slot, 1, 1, 0, &buffer[0], &buflen[0]); if (err) return err; - err = iso7816_read_record (slot, 2, 1, &buffer[1], &buflen[1]); + err = iso7816_read_record (slot, 2, 1, 0, &buffer[1], &buflen[1]); if (err) { xfree (buffer[0]); diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 021d6a52c..7782b8e1c 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -245,7 +245,7 @@ store_fpr (int slot, int keynumber, u32 timestamp, n = 6 + 2 + mlen + 2 + elen; p = buffer = xtrymalloc (3 + n); if (!buffer) - return out_of_core (); + return gpg_error (gpg_err_code_from_errno (errno)); *p++ = 0x99; /* ctb */ *p++ = n >> 8; /* 2 byte length header */ diff --git a/scd/app.c b/scd/app.c index 6ac18272b..d395fe559 100644 --- a/scd/app.c +++ b/scd/app.c @@ -47,7 +47,7 @@ select_application (ctrl_t ctrl, int slot, const char *name) app = xtrycalloc (1, sizeof *app); if (!app) { - rc = out_of_core (); + rc = gpg_error (gpg_err_code_from_errno (errno)); log_info ("error allocating context: %s\n", gpg_strerror (rc)); return NULL; } diff --git a/scd/card-dinsig.c b/scd/card-dinsig.c index bb070d5f0..df09bfb57 100644 --- a/scd/card-dinsig.c +++ b/scd/card-dinsig.c @@ -141,7 +141,7 @@ dinsig_enum_keypairs (CARD card, int idx, { *keyid = xtrymalloc (17); if (!*keyid) - return out_of_core (); + return gpg_error (gpg_err_code_from_errno (errno)); if (!idx) strcpy (*keyid, "DINSIG-DF01.C000"); else @@ -193,7 +193,7 @@ dinsig_read_cert (CARD card, const char *certidstr, buf = xtrymalloc (file->size); if (!buf) { - gpg_error_t tmperr = out_of_core (); + gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno)); sc_file_free (file); return tmperr; } diff --git a/scd/card-p15.c b/scd/card-p15.c index 239e75045..ae3ef148f 100644 --- a/scd/card-p15.c +++ b/scd/card-p15.c @@ -53,7 +53,7 @@ init_private_data (CARD card) priv = xtrycalloc (1, sizeof *priv); if (!priv) - return out_of_core (); + return gpg_error (gpg_err_code_from_errno (errno)); /* OpenSC (0.7.0) is a bit strange in that the get_objects functions tries to be a bit too clever and implicitly does an enumeration @@ -179,7 +179,7 @@ p15_enum_keypairs (CARD card, int idx, *keyid = p = xtrymalloc (9+pinfo->id.len*2+1); if (!*keyid) - return out_of_core (); + return gpg_error (gpg_err_code_from_errno (errno)); p = stpcpy (p, "P15-5015."); for (i=0; i < pinfo->id.len; i++, p += 2) sprintf (p, "%02X", pinfo->id.value[i]); @@ -217,7 +217,7 @@ p15_enum_certs (CARD card, int idx, char **certid, int *type) *certid = p = xtrymalloc (9+cinfo->id.len*2+1); if (!*certid) - return out_of_core (); + return gpg_error (gpg_err_code_from_errno (errno)); p = stpcpy (p, "P15-5015."); for (i=0; i < cinfo->id.len; i++, p += 2) sprintf (p, "%02X", cinfo->id.value[i]); @@ -304,7 +304,7 @@ p15_read_cert (CARD card, const char *certidstr, *cert = xtrymalloc (certder->data_len); if (!*cert) { - gpg_error_t tmperr = out_of_core (); + gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno)); sc_pkcs15_free_certificate (certder); return tmperr; } @@ -400,7 +400,7 @@ p15_sign (CARD card, const char *keyidstr, int hashalgo, outbuflen = 1024; outbuf = xtrymalloc (outbuflen); if (!outbuf) - return out_of_core (); + return gpg_error (gpg_err_code_from_errno (errno)); rc = sc_pkcs15_compute_signature (card->p15card, keyobj, cryptflags, @@ -462,7 +462,7 @@ p15_decipher (CARD card, const char *keyidstr, outbuflen = indatalen < 256? 256 : indatalen; outbuf = xtrymalloc (outbuflen); if (!outbuf) - return out_of_core (); + return gpg_error (gpg_err_code_from_errno (errno)); rc = sc_pkcs15_decipher (card->p15card, keyobj, 0, diff --git a/scd/card.c b/scd/card.c index 53c89f3a4..8366dcb1c 100644 --- a/scd/card.c +++ b/scd/card.c @@ -108,7 +108,7 @@ card_open (CARD *rcard) card = xtrycalloc (1, sizeof *card); if (!card) - return out_of_core (); + return gpg_error (gpg_err_code_from_errno (errno)); card->reader = 0; rc = sc_establish_context (&card->ctx, "scdaemon"); @@ -275,7 +275,7 @@ find_iccsn (const unsigned char *buffer, size_t length, char **serial) *serial = p = xtrymalloc (2*n+1); if (!*serial) - return out_of_core (); + return gpg_error (gpg_err_code_from_errno (errno)); for (; n; n--, p += 2, s++) sprintf (p, "%02X", *s); *p = 0; @@ -389,7 +389,7 @@ card_get_serial_and_stamp (CARD card, char **serial, time_t *stamp) *serial = NULL; p = xtrymalloc (strlen (efser) + 7); if (!p) - rc = out_of_core (); + rc = gpg_error (gpg_err_code_from_errno (errno)); else { strcpy (p, "FF0100"); @@ -405,7 +405,7 @@ card_get_serial_and_stamp (CARD card, char **serial, time_t *stamp) { xfree (*serial); *serial = NULL; - rc = out_of_core (); + rc = gpg_error (gpg_err_code_from_errno (errno)); } else { diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c index ca5620176..b398e3ce3 100644 --- a/scd/ccid-driver.c +++ b/scd/ccid-driver.c @@ -87,16 +87,24 @@ #define DRVNAME "ccid-driver: " -#ifdef GNUPG_MAJOR_VERSION /* This source is used within GnuPG. */ +/* Depending on how this source is used we either define our error + output to go to stderr or to the jnlib based logging functions. We + use the latter when GNUPG_MAJOR_VERSION is defines or when both, + GNUPG_SCD_MAIN_HEADER and HAVE_JNLIB_LOGGING are defined. +*/ +#if defined(GNUPG_MAJOR_VERSION) \ + || (defined(GNUPG_SCD_MAIN_HEADER) && defined(HAVE_JNLIB_LOGGING)) -# if GNUPG_MAJOR_VERSION == 1 /* GnuPG Version is < 1.9. */ +#if defined(GNUPG_SCD_MAIN_HEADER) +# include GNUPG_SCD_MAIN_HEADER +#elif GNUPG_MAJOR_VERSION == 1 /* GnuPG Version is < 1.9. */ # include "options.h" # include "util.h" # include "memory.h" # include "cardglue.h" # else /* This is the modularized GnuPG 1.9 or later. */ # include "scdaemon.h" -# endif +#endif /* Disable all debugging output for now. */ #undef DBG_CARD_IO diff --git a/scd/command.c b/scd/command.c index d148ddb5a..4746e11b5 100644 --- a/scd/command.c +++ b/scd/command.c @@ -351,7 +351,7 @@ cmd_learn (ASSUAN_CONTEXT ctx, char *line) buf = xtrymalloc (40 + 1 + strlen (certid) + 1); if (!buf) - rc = out_of_core (); + rc = gpg_error (gpg_err_code_from_errno (errno)); else { sprintf (buf, "%d %s", certtype, certid); @@ -389,7 +389,7 @@ cmd_learn (ASSUAN_CONTEXT ctx, char *line) buf = p = xtrymalloc (40 + 1 + strlen (keyid) + 1); if (!buf) - rc = out_of_core (); + rc = gpg_error (gpg_err_code_from_errno (errno)); else { int i; @@ -577,7 +577,7 @@ pin_cb (void *opaque, const char *info, char **retstr) rc = asprintf (&command, "NEEDPIN %s", info); if (rc < 0) - return out_of_core (); + return gpg_error (gpg_err_code_from_errno (errno)); /* FIXME: Write an inquire function which returns the result in secure memory */ diff --git a/scd/iso7816.c b/scd/iso7816.c index 1ee9b55e7..d7d3c126b 100644 --- a/scd/iso7816.c +++ b/scd/iso7816.c @@ -24,7 +24,9 @@ #include #include -#if GNUPG_MAJOR_VERSION == 1 +#if defined(GNUPG_SCD_MAIN_HEADER) +#include GNUPG_SCD_MAIN_HEADER +#elif GNUPG_MAJOR_VERSION == 1 /* This is used with GnuPG version < 1.9. The code has been source copied from the current GnuPG >= 1.9 and is maintained over there. */ @@ -200,7 +202,7 @@ iso7816_change_reference_data (int slot, int chvno, buf = xtrymalloc (oldchvlen + newchvlen); if (!buf) - return out_of_core (); + return gpg_error (gpg_err_code_from_errno (errno)); if (oldchvlen) memcpy (buf, oldchv, oldchvlen); memcpy (buf+oldchvlen, newchv, newchvlen); @@ -341,7 +343,8 @@ iso7816_decipher (int slot, const unsigned char *data, size_t datalen, /* We need to prepend the padding indicator. */ buf = xtrymalloc (datalen + 1); if (!buf) - return out_of_core (); + return gpg_error (gpg_err_code_from_errno (errno)); + *buf = padind; /* Padding indicator. */ memcpy (buf+1, data, datalen); sw = apdu_send (slot, 0x00, CMD_PSO, 0x80, 0x86, datalen+1, buf, @@ -550,11 +553,13 @@ iso7816_read_binary (int slot, size_t offset, size_t nmax, /* Perform a READ RECORD command. RECNO gives the record number to read with 0 indicating the current record. RECCOUNT must be 1 (not - all cards support reading of more than one record). The result is - stored in a newly allocated buffer at the address passed by RESULT. - Returns the length of this data at the address of RESULTLEN. */ + all cards support reading of more than one record). SHORT_EF + should be 0 to read the current EF or contain a short EF. The + result is stored in a newly allocated buffer at the address passed + by RESULT. Returns the length of this data at the address of + RESULTLEN. */ gpg_error_t -iso7816_read_record (int slot, int recno, int reccount, +iso7816_read_record (int slot, int recno, int reccount, int short_ef, unsigned char **result, size_t *resultlen) { int sw; @@ -568,7 +573,8 @@ iso7816_read_record (int slot, int recno, int reccount, /* We can only encode 15 bits in p0,p1 to indicate an offset. Thus we check for this limit. */ - if (recno < 0 || recno > 255 || reccount != 1) + if (recno < 0 || recno > 255 || reccount != 1 + || short_ef < 0 || short_ef > 254 ) return gpg_error (GPG_ERR_INV_VALUE); buffer = NULL; @@ -577,7 +583,7 @@ iso7816_read_record (int slot, int recno, int reccount, with an Le of 0. */ sw = apdu_send_le (slot, 0x00, CMD_READ_RECORD, recno, - 0x04, + short_ef? short_ef : 0x04, -1, NULL, 254, &buffer, &bufferlen); diff --git a/scd/iso7816.h b/scd/iso7816.h index 937326b6d..8f2b150e6 100644 --- a/scd/iso7816.h +++ b/scd/iso7816.h @@ -67,6 +67,7 @@ gpg_error_t iso7816_get_challenge (int slot, gpg_error_t iso7816_read_binary (int slot, size_t offset, size_t nmax, unsigned char **result, size_t *resultlen); gpg_error_t iso7816_read_record (int slot, int recno, int reccount, + int short_ef, unsigned char **result, size_t *resultlen); #endif /*ISO7816_H*/ diff --git a/scd/sc-investigate.c b/scd/sc-investigate.c index 6f8b330b1..3882e1dfd 100644 --- a/scd/sc-investigate.c +++ b/scd/sc-investigate.c @@ -50,8 +50,10 @@ enum cmd_and_opt_values { oInteractive = 'i', oVerbose = 'v', + oQuiet = 'q', oReaderPort = 500, octapiDriver, + oDebug, oDebugAll, @@ -68,6 +70,7 @@ static ARGPARSE_OPTS opts[] = { { 301, NULL, 0, "@Options:\n " }, { oInteractive, "interactive", 0, "start in interactive explorer mode"}, + { oQuiet, "quiet", 0, "quiet" }, { oVerbose, "verbose", 0, "verbose" }, { oReaderPort, "reader-port", 2, "|N|connect to reader at port N"}, { octapiDriver, "ctapi-driver", 2, "NAME|use NAME as ctAPI driver"}, @@ -86,7 +89,7 @@ static ARGPARSE_OPTS opts[] = { static void interactive_shell (int slot); - +static void dump_other_cards (int slot); static const char * my_strusage (int level) @@ -168,6 +171,7 @@ main (int argc, char **argv ) switch (pargs.r_opt) { case oVerbose: opt.verbose++; break; + case oQuiet: opt.quiet++; break; case oDebug: opt.debug |= pargs.r.ret_ulong; break; case oDebugAll: opt.debug = ~0; break; case oReaderPort: reader_port = pargs.r.ret_str; break; @@ -191,7 +195,7 @@ main (int argc, char **argv ) if (slot == -1) exit (1); - if (!gen_random) + if (!gen_random && !opt.quiet) { rc = atr_dump (slot, stdout); if (rc) @@ -210,12 +214,17 @@ main (int argc, char **argv ) rc = app_select_openpgp (&appbuf); if (rc) { - log_info ("selecting openpgp failed: %s\n", gpg_strerror (rc)); + if (!opt.quiet) + log_info ("selecting openpgp failed: %s\n", gpg_strerror (rc)); memset (&appbuf, 0, sizeof appbuf); appbuf.slot = slot; rc = app_select_dinsig (&appbuf); if (rc) - log_info ("selecting dinsig failed: %s\n", gpg_strerror (rc)); + { + if (!opt.quiet) + log_info ("selecting dinsig failed: %s\n", gpg_strerror (rc)); + dump_other_cards (slot); + } else { appbuf.initialized = 1; @@ -398,6 +407,7 @@ interactive_shell (int slot) cmdAPP, cmdREAD, cmdREADREC, + cmdREADSHORTREC, cmdDEBUG, cmdVERIFY, cmdCHANGEREF, @@ -425,6 +435,7 @@ interactive_shell (int slot) { "rb" , cmdREAD, NULL }, { "readrec", cmdREADREC, "read record(s)" }, { "rr" , cmdREADREC, NULL }, + { "rsr" , cmdREADSHORTREC, "readshortrec RECNO SHORT_EF" }, { "verify" , cmdVERIFY, "verify CHVNO PIN" }, { "ver" , cmdVERIFY, NULL }, { "changeref", cmdCHANGEREF, "change reference data" }, @@ -559,7 +570,8 @@ interactive_shell (int slot) for (i=1, err=0; !err; i++) { xfree (result); result = NULL; - err = iso7816_read_record (slot, i, 1, &result, &resultlen); + err = iso7816_read_record (slot, i, 1, 0, + &result, &resultlen); if (!err) dump_buffer (result, resultlen); } @@ -568,13 +580,31 @@ interactive_shell (int slot) } else { - err = iso7816_read_record (slot, arg_number, 1, + err = iso7816_read_record (slot, arg_number, 1, 0, &result, &resultlen); if (!err) dump_or_store_buffer (arg_string, result, resultlen); } break; + case cmdREADSHORTREC: + { + int short_ef; + + short_ef = strtol (arg_next, NULL, 0); + + if (short_ef < 1 || short_ef > 254) + printf ("error: short EF must be between 1 and 254\n"); + else + { + err = iso7816_read_record (slot, arg_number, 1, short_ef, + &result, &resultlen); + if (!err) + dump_or_store_buffer (arg_string, result, resultlen); + } + } + break; + case cmdVERIFY: if (arg_number < 0 || arg_number > 255 || (arg_number & 127) > 31) printf ("error: invalid CHVNO\n"); @@ -637,3 +667,104 @@ interactive_shell (int slot) ; } + + +/* Figure out whether the current card is a German Geldkarte and print + what we know about it. */ +static int +dump_geldkarte (int slot) +{ + unsigned char *r = NULL; + size_t rlen; + const char *t; + + if (iso7816_read_record (slot, 1, 1, 0xbc, &r, &rlen)) + return -1; + /* We require that the record is at least 24 bytes, the first byte + is 0x67 and the filler byte is correct. */ + if (rlen < 24 || *r != 0x67 || r[22]) + return -1; + + /* The short Bankleitzahl consists of 3 bytes at offset 1. */ + switch (r[1]) + { + case 0x21: t = "Oeffentlich-rechtliche oder private Bank"; break; + case 0x22: t = "Privat- oder Geschäftsbank"; break; + case 0x25: t = "Sparkasse"; break; + case 0x26: + case 0x29: t = "Genossenschaftsbank"; break; + default: + xfree (r); + return -1; /* Probably not a Geldkarte. */ + } + + printf ("KBLZ .....: %02X-%02X%02X (%s)\n", r[1], r[2], r[3], t); + printf ("Card-No ..: %02X%02X%02X%02X%02X\n", r[4], r[5], r[6], r[7], r[8]); + +/* Byte 10 enthält im linken Halbbyte eine Prüfziffer, die nach dem */ +/* Verfahren 'Luhn formula for computing modulus 10' über die Ziffern der */ +/* ersten 9 Byte berechnet ist. */ + +/* Das rechte Halbbyte wird zu 'D' gesetzt. */ + +/* Für die Berechnung der Luhn-Prüfziffer sind die folgenden Schritte */ +/* durchzuführen: */ + +/* Schritt 1: Mit der rechtesten Ziffer beginnend ist einschließlich dieser */ +/* Ziffer jede übernächste Ziffer zu verdoppeln (mit 2 multiplizieren). */ + +/* Schritt 2: Die einzelnen Ziffern der Produkte aus Schritt 1 und die bei */ +/* diesen Multiplikationen unberührt gebliebenen Ziffern sind zu addieren. */ + +/* Schritt 3: Das Ergebnis der Addition aus Schritt 2 ist von dem auf die */ +/* nächst höhere Zahl mit der Einerstelle 0 aufgerundeten Ergebnis der */ +/* Addition aus Schritt 2 abzuziehen. Wenn das Ergebnis der Addition aus */ +/* Schritt 2 bereits eine Zahl mit der Einerstelle 0 ergibt (z.B. 30, 40, */ +/* usw.), ist die Prüfziffer 0. */ + +/* Beispiel: Kartennummer ohne Prüfziffer: 992 839 871 */ + +/* 9 9 2 8 3 9 8 7 1 */ + +/* x 2 x 2 x 2 x 2 x 2 Schritt 1 */ + +/* 18 4 6 16 2 */ + +/* 1+8 +9 +4 +8 +6 +9 +1+6 +7 +2 = 61 Schritt 2 */ + +/* 70-61 = 9 Schritt 3 */ + +/* Prüfziffer zu 992 839 871 = 9 */ + + + printf ("Expires at: %02X/%02X\n", r[11], r[10] ); + printf ("Valid from: %02X.%02X.%02X\n", r[14], r[13], r[12]); + printf ("Country ..: %02X%02X\n", r[15], r[16]); + printf ("Currency .: %c%c%c\n", isascii (r[17])? r[17]:' ', + isascii (r[18])? r[18]:' ', isascii (r[19])? r[19]:' '); + printf ("Cur.-Mult : %s\n", + r[20] == 0x01? "0.01": + r[20] == 0x02? "0.1": + r[20] == 0x04? "1": + r[20] == 0x08? "10": + r[20] == 0x10? "100": + r[20] == 0x20? "1000": "?"); + printf ("ZKA ChipID: %02X\n", r[21]); + printf ("OS version: %02X\n", r[23]); + + xfree (r); + return 0; +} + + + +/* Try to figure out the type of teh card and dump its contents. */ +static void +dump_other_cards (int slot) +{ + + if (!dump_geldkarte (slot)) + return; + +} + diff --git a/scd/scdaemon.h b/scd/scdaemon.h index 2bbf271da..098738508 100644 --- a/scd/scdaemon.h +++ b/scd/scdaemon.h @@ -33,14 +33,6 @@ #include "../common/util.h" #include "../common/errors.h" -/* Convenience funcion to be used instead of returning the old - GNUPG_Out_Of_Core. */ -static __inline__ gpg_error_t -out_of_core (void) -{ - return gpg_error (gpg_err_code_from_errno (errno)); -} - #define MAX_DIGEST_LEN 24 -- cgit From e209ea3c39e7110d94e4420513f397d8656a75b7 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 16 Mar 2004 18:59:21 +0000 Subject: * app-dinsig.c: Implemented. Based on app-nks.c and card-dinsig.c * app-nks.c (get_length_of_cert): Removed. * app-help.c: New. (app_help_read_length_of_cert): New. Code taken from above. New optional arg R_CERTOFF. * card-dinsig.c: Removed. * card.c (card_get_serial_and_stamp): Do not bind to the old and never finsiged card-dinsig.c. * iso7816.c (iso7816_read_binary): Allow for an NMAX > 254. --- scd/ChangeLog | 14 +++ scd/Makefile.am | 14 +-- scd/app-common.h | 7 ++ scd/app-dinsig.c | 314 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- scd/app-help.c | 157 +++++++++++++++++++++++++++ scd/app-nks.c | 66 +----------- scd/app-openpgp.c | 2 +- scd/card.c | 2 - scd/iso7816.c | 20 +++- scd/scdaemon.c | 67 +++++++++--- 10 files changed, 561 insertions(+), 102 deletions(-) create mode 100644 scd/app-help.c (limited to 'scd/app-openpgp.c') diff --git a/scd/ChangeLog b/scd/ChangeLog index a9296cbbb..679f867fe 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,17 @@ +2004-03-16 Werner Koch + + * app-dinsig.c: Implemented. Based on app-nks.c and card-dinsig.c + * app-nks.c (get_length_of_cert): Removed. + * app-help.c: New. + (app_help_read_length_of_cert): New. Code taken from above. New + optional arg R_CERTOFF. + + * card-dinsig.c: Removed. + * card.c (card_get_serial_and_stamp): Do not bind to the old and + never finsiged card-dinsig.c. + + * iso7816.c (iso7816_read_binary): Allow for an NMAX > 254. + 2004-03-11 Werner Koch * scdaemon.h (out_of_core): Removed. Replaced callers by standard diff --git a/scd/Makefile.am b/scd/Makefile.am index 89ebf4e05..da59a1997 100644 --- a/scd/Makefile.am +++ b/scd/Makefile.am @@ -34,12 +34,12 @@ scdaemon_SOURCES = \ scdaemon.c scdaemon.h \ command.c card.c \ card-common.h \ - card-p15.c card-dinsig.c \ + card-p15.c \ apdu.c apdu.h \ ccid-driver.c ccid-driver.h \ iso7816.c iso7816.h \ tlv.c tlv.h \ - app.c app-common.h $(card_apps) + app.c app-common.h app-help.c $(card_apps) scdaemon_LDADD = ../jnlib/libjnlib.a ../common/libcommon.a \ @@ -53,12 +53,12 @@ sc_investigate_SOURCES = \ iso7816.c iso7816.h \ tlv.c tlv.h \ atr.c atr.h \ - app.c app-common.h $(card_apps) + app.c app-common.h app-help.c $(card_apps) sc_investigate_LDADD = \ ../jnlib/libjnlib.a ../common/libcommon.a \ - $(OPENSC_LIBS) $(LIBGCRYPT_LIBS) $(LIBUSB_LIBS) @INTLLIBS@ \ - -lgpg-error -ldl + $(OPENSC_LIBS) $(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(LIBUSB_LIBS) \ + @INTLLIBS@ -lgpg-error -ldl sc_copykeys_SOURCES = \ @@ -68,10 +68,10 @@ sc_copykeys_SOURCES = \ iso7816.c iso7816.h \ tlv.c tlv.h \ atr.c atr.h \ - app.c app-common.h $(card_apps) + app.c app-common.h app-help.c $(card_apps) sc_copykeys_LDADD = \ ../jnlib/libjnlib.a ../common/libcommon.a \ ../common/libsimple-pwquery.a \ - $(OPENSC_LIBS) $(LIBGCRYPT_LIBS) $(LIBUSB_LIBS) \ + $(OPENSC_LIBS) $(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(LIBUSB_LIBS) \ -lgpg-error @INTLLIBS@ -ldl diff --git a/scd/app-common.h b/scd/app-common.h index cda17700f..c16a15719 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -21,6 +21,8 @@ #ifndef GNUPG_SCD_APP_COMMON_H #define GNUPG_SCD_APP_COMMON_H +#include + struct app_ctx_s { int initialized; /* The application has been initialied and the function pointers may be used. Note that for @@ -80,6 +82,11 @@ struct app_ctx_s { int app_select_openpgp (app_t app); int app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp); #else +/*-- app-help.c --*/ +gpg_error_t app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip); +size_t app_help_read_length_of_cert (int slot, int fid, size_t *r_certoff); + + /*-- app.c --*/ app_t select_application (ctrl_t ctrl, int slot, const char *name); void release_application (app_t app); diff --git a/scd/app-dinsig.c b/scd/app-dinsig.c index 4b5b517eb..38fbc79ee 100644 --- a/scd/app-dinsig.c +++ b/scd/app-dinsig.c @@ -1,5 +1,5 @@ /* app-dinsig.c - The DINSIG (DIN V 66291-1) card application. - * Copyright (C) 2004 Free Software Foundation, Inc. + * Copyright (C) 2002, 2004 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -65,9 +65,6 @@ The letters in brackets indicate optional or mandatory files: The first for card terminals under full control and the second for "business" card terminals. - - FIXME: Needs a lot more explanation. - */ @@ -85,17 +82,317 @@ #include "iso7816.h" #include "app-common.h" +#include "tlv.h" + + +static int +do_learn_status (app_t app, ctrl_t ctrl) +{ + gpg_error_t err; + char ct_buf[100], id_buf[100]; + char hexkeygrip[41]; + size_t len, certoff; + unsigned char *der; + size_t derlen; + ksba_cert_t cert; + int fid; + + /* Return the certificate of the card holder. */ + fid = 0xC000; + len = app_help_read_length_of_cert (app->slot, fid, &certoff); + if (!len) + return 0; /* Card has not been personalized. */ + + sprintf (ct_buf, "%d", 101); + sprintf (id_buf, "DINSIG.%04X", fid); + send_status_info (ctrl, "CERTINFO", + ct_buf, strlen (ct_buf), + id_buf, strlen (id_buf), + NULL, (size_t)0); + + /* Now we need to read the certificate, so that we can get the + public key out of it. */ + err = iso7816_read_binary (app->slot, certoff, len-certoff, &der, &derlen); + if (err) + { + log_info ("error reading entire certificate from FID 0x%04X: %s\n", + fid, gpg_strerror (err)); + return 0; + } + + err = ksba_cert_new (&cert); + if (err) + { + xfree (der); + return err; + } + err = ksba_cert_init_from_mem (cert, der, derlen); + xfree (der); der = NULL; + if (err) + { + log_error ("failed to parse the certificate at FID 0x%04X: %s\n", + fid, gpg_strerror (err)); + ksba_cert_release (cert); + return err; + } + err = app_help_get_keygrip_string (cert, hexkeygrip); + if (err) + { + log_error ("failed to calculate the keygrip for FID 0x%04X\n", fid); + ksba_cert_release (cert); + return gpg_error (GPG_ERR_CARD); + } + ksba_cert_release (cert); + + sprintf (id_buf, "DINSIG.%04X", fid); + send_status_info (ctrl, "KEYPAIRINFO", + hexkeygrip, 40, + id_buf, strlen (id_buf), + NULL, (size_t)0); + return 0; +} + + +/* Read the certificate with id CERTID (as returned by learn_status in + the CERTINFO status lines) and return it in the freshly allocated + buffer put into CERT and the length of the certificate put into + CERTLEN. + FIXME: This needs some cleanups and caching with do_learn_status. +*/ static int -do_learn_status (APP app, CTRL ctrl) +do_readcert (app_t app, const char *certid, + unsigned char **cert, size_t *certlen) { + int fid; + gpg_error_t err; + unsigned char *buffer; + const unsigned char *p; + size_t buflen, n; + int class, tag, constructed, ndef; + size_t totobjlen, objlen, hdrlen; + int rootca = 0; + + *cert = NULL; + *certlen = 0; + if (strncmp (certid, "DINSIG.", 7) ) + return gpg_error (GPG_ERR_INV_ID); + certid += 7; + if (!hexdigitp (certid) || !hexdigitp (certid+1) + || !hexdigitp (certid+2) || !hexdigitp (certid+3) + || certid[4]) + return gpg_error (GPG_ERR_INV_ID); + fid = xtoi_4 (certid); + if (fid != 0xC000 ) + return gpg_error (GPG_ERR_NOT_FOUND); + + /* Read the entire file. fixme: This could be optimized by first + reading the header to figure out how long the certificate + actually is. */ + err = iso7816_select_file (app->slot, fid, 0, NULL, NULL); + if (err) + { + log_error ("error selecting FID 0x%04X: %s\n", fid, gpg_strerror (err)); + return err; + } + + err = iso7816_read_binary (app->slot, 0, 0, &buffer, &buflen); + if (err) + { + log_error ("error reading certificate from FID 0x%04X: %s\n", + fid, gpg_strerror (err)); + return err; + } + + if (!buflen || *buffer == 0xff) + { + log_info ("no certificate contained in FID 0x%04X\n", fid); + err = gpg_error (GPG_ERR_NOT_FOUND); + goto leave; + } + + /* Now figure something out about the object. */ + p = buffer; + n = buflen; + err = parse_ber_header (&p, &n, &class, &tag, &constructed, + &ndef, &objlen, &hdrlen); + if (err) + goto leave; + if ( class == CLASS_UNIVERSAL && tag == TAG_SEQUENCE && constructed ) + ; + else if ( class == CLASS_UNIVERSAL && tag == TAG_SET && constructed ) + rootca = 1; + else + return gpg_error (GPG_ERR_INV_OBJ); + totobjlen = objlen + hdrlen; + assert (totobjlen <= buflen); + + err = parse_ber_header (&p, &n, &class, &tag, &constructed, + &ndef, &objlen, &hdrlen); + if (err) + goto leave; + + if (rootca) + ; + else if (class == CLASS_UNIVERSAL && tag == TAG_OBJECT_ID && !constructed) + { + const unsigned char *save_p; + + /* The certificate seems to be contained in a userCertificate + container. Skip this and assume the following sequence is + the certificate. */ + if (n < objlen) + { + err = gpg_error (GPG_ERR_INV_OBJ); + goto leave; + } + p += objlen; + n -= objlen; + save_p = p; + err = parse_ber_header (&p, &n, &class, &tag, &constructed, + &ndef, &objlen, &hdrlen); + if (err) + goto leave; + if ( !(class == CLASS_UNIVERSAL && tag == TAG_SEQUENCE && constructed) ) + return gpg_error (GPG_ERR_INV_OBJ); + totobjlen = objlen + hdrlen; + assert (save_p + totobjlen <= buffer + buflen); + memmove (buffer, save_p, totobjlen); + } + + *cert = buffer; + buffer = NULL; + *certlen = totobjlen; + + leave: + xfree (buffer); + return err; +} + + +/* Verify the PIN if required. */ +static int +verify_pin (app_t app, + int (pincb)(void*, const char *, char **), + void *pincb_arg) +{ + if (!app->did_chv1 || app->force_chv1 ) + { + char *pinvalue; + int rc; + + rc = pincb (pincb_arg, "PIN", &pinvalue); + if (rc) + { + log_info ("PIN callback returned error: %s\n", gpg_strerror (rc)); + return rc; + } + + /* We require the PIN to be at least 6 and at max 8 bytes. + According to the specs, this should all be ASCII but we don't + check this. */ + if (strlen (pinvalue) < 6) + { + log_error ("PIN is too short; minimum length is 6\n"); + xfree (pinvalue); + return gpg_error (GPG_ERR_BAD_PIN); + } + else if (strlen (pinvalue) > 8) + { + log_error ("PIN is too large; maximum length is 8\n"); + xfree (pinvalue); + return gpg_error (GPG_ERR_BAD_PIN); + } + + rc = iso7816_verify (app->slot, 0x81, pinvalue, strlen (pinvalue)); + if (rc) + { + log_error ("verify PIN failed\n"); + xfree (pinvalue); + return rc; + } + app->did_chv1 = 1; + xfree (pinvalue); + } + return 0; } +/* Create the signature and return the allocated result in OUTDATA. + If a PIN is required the PINCB will be used to ask for the PIN; + that callback should return the PIN in an allocated buffer and + store that in the 3rd argument. */ +static int +do_sign (app_t app, const char *keyidstr, int hashalgo, + int (pincb)(void*, const char *, char **), + void *pincb_arg, + const void *indata, size_t indatalen, + unsigned char **outdata, size_t *outdatalen ) +{ + static unsigned char sha1_prefix[15] = /* Object ID is 1.3.14.3.2.26 */ + { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, + 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 }; + static unsigned char rmd160_prefix[15] = /* Object ID is 1.3.36.3.2.1 */ + { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x24, 0x03, + 0x02, 0x01, 0x05, 0x00, 0x04, 0x14 }; + int rc; + int fid; + unsigned char data[35]; /* Must be large enough for a SHA-1 digest + + the largest OID _prefix above. */ + + if (!keyidstr || !*keyidstr) + return gpg_error (GPG_ERR_INV_VALUE); + if (indatalen != 20 && indatalen != 16 && indatalen != 35) + return gpg_error (GPG_ERR_INV_VALUE); + + /* Check that the provided ID is vaid. This is not really needed + but we do it to to enforce correct usage by the caller. */ + if (strncmp (keyidstr, "DINSIG.", 7) ) + return gpg_error (GPG_ERR_INV_ID); + keyidstr += 7; + if (!hexdigitp (keyidstr) || !hexdigitp (keyidstr+1) + || !hexdigitp (keyidstr+2) || !hexdigitp (keyidstr+3) + || keyidstr[4]) + return gpg_error (GPG_ERR_INV_ID); + fid = xtoi_4 (keyidstr); + if (fid != 0xC000) + return gpg_error (GPG_ERR_NOT_FOUND); + + /* Prepare the DER object from INDATA. */ + if (indatalen == 35) + { + /* Alright, the caller was so kind to send us an already + prepared DER object. Check that it is what we want and that + it matches the hash algorithm. */ + if (hashalgo == GCRY_MD_SHA1 && !memcmp (indata, sha1_prefix, 15)) + ; + else if (hashalgo == GCRY_MD_RMD160 && !memcmp (indata, rmd160_prefix,15)) + ; + else + return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); + memcpy (data, indata, indatalen); + } + else + { + if (hashalgo == GCRY_MD_SHA1) + memcpy (data, sha1_prefix, 15); + else if (hashalgo == GCRY_MD_RMD160) + memcpy (data, rmd160_prefix, 15); + else + return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); + memcpy (data+15, indata, indatalen); + } + + rc = verify_pin (app, pincb, pincb_arg); + if (!rc) + rc = iso7816_compute_ds (app->slot, data, 35, outdata, outdatalen); + return rc; +} + /* Select the DINSIG application on the card in SLOT. This function @@ -113,17 +410,18 @@ app_select_dinsig (APP app) app->apptype = "DINSIG"; app->fnc.learn_status = do_learn_status; + app->fnc.readcert = do_readcert; app->fnc.getattr = NULL; app->fnc.setattr = NULL; app->fnc.genkey = NULL; - app->fnc.sign = NULL; + app->fnc.sign = do_sign; app->fnc.auth = NULL; app->fnc.decipher = NULL; app->fnc.change_pin = NULL; app->fnc.check_pin = NULL; + + app->force_chv1 = 1; } return rc; } - - diff --git a/scd/app-help.c b/scd/app-help.c new file mode 100644 index 000000000..c6695635f --- /dev/null +++ b/scd/app-help.c @@ -0,0 +1,157 @@ +/* app-help.c - Application helper functions + * Copyright (C) 2004 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 +#include +#include +#include +#include + +#include "scdaemon.h" +#include "app-common.h" +#include "iso7816.h" +#include "tlv.h" + +/* Return the KEYGRIP for the certificate CERT as an hex encoded + string in the user provided buffer HEXKEYGRIP which must be of at + least 41 bytes. */ +gpg_error_t +app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip) +{ + gpg_error_t err; + gcry_sexp_t s_pkey; + ksba_sexp_t p; + size_t n; + unsigned char array[20]; + int i; + + p = ksba_cert_get_public_key (cert); + if (!p) + return gpg_error (GPG_ERR_BUG); + n = gcry_sexp_canon_len (p, 0, NULL, NULL); + if (!n) + return gpg_error (GPG_ERR_INV_SEXP); + err = gcry_sexp_sscan (&s_pkey, NULL, p, n); + xfree (p); + if (err) + return err; /* Can't parse that S-expression. */ + if (!gcry_pk_get_keygrip (s_pkey, array)) + { + gcry_sexp_release (s_pkey); + return gpg_error (GPG_ERR_GENERAL); /* Failed to calculate the keygrip.*/ + } + gcry_sexp_release (s_pkey); + + for (i=0; i < 20; i++) + sprintf (hexkeygrip+i*2, "%02X", array[i]); + + return 0; +} + + + +/* Given the SLOT and the File ID FID, return the length of the + certificate contained in that file. Returns 0 if the file does not + exists or does not contain a certificate. If R_CERTOFF is not + NULL, the length the header will be stored at this address; thus to + parse the X.509 certificate a read should start at that offset. + + On success the file is still selected. +*/ +size_t +app_help_read_length_of_cert (int slot, int fid, size_t *r_certoff) +{ + gpg_error_t err; + unsigned char *buffer; + const unsigned char *p; + size_t buflen, n; + int class, tag, constructed, ndef; + size_t resultlen, objlen, hdrlen; + + err = iso7816_select_file (slot, fid, 0, NULL, NULL); + if (err) + { + log_info ("error selecting FID 0x%04X: %s\n", fid, gpg_strerror (err)); + return 0; + } + + err = iso7816_read_binary (slot, 0, 32, &buffer, &buflen); + if (err) + { + log_info ("error reading certificate from FID 0x%04X: %s\n", + fid, gpg_strerror (err)); + return 0; + } + + if (!buflen || *buffer == 0xff) + { + log_info ("no certificate contained in FID 0x%04X\n", fid); + xfree (buffer); + return 0; + } + + p = buffer; + n = buflen; + err = parse_ber_header (&p, &n, &class, &tag, &constructed, + &ndef, &objlen, &hdrlen); + if (err) + { + log_info ("error parsing certificate in FID 0x%04X: %s\n", + fid, gpg_strerror (err)); + xfree (buffer); + return 0; + } + + /* All certificates should commence with a SEQUENCE except for the + special ROOT CA which are enclosed in a SET. */ + if ( !(class == CLASS_UNIVERSAL && constructed + && (tag == TAG_SEQUENCE || tag == TAG_SET))) + { + log_info ("contents of FID 0x%04X does not look like a certificate\n", + fid); + return 0; + } + + resultlen = objlen + hdrlen; + if (r_certoff) + { + /* The callers want the offset to the actual certificate. */ + *r_certoff = hdrlen; + + err = parse_ber_header (&p, &n, &class, &tag, &constructed, + &ndef, &objlen, &hdrlen); + if (err) + return 0; + + if (class == CLASS_UNIVERSAL && tag == TAG_OBJECT_ID && !constructed) + { + /* The certificate seems to be contained in a + userCertificate container. Assume the following sequence + is the certificate. */ + *r_certoff += hdrlen + objlen; + if (*r_certoff > resultlen) + return 0; /* That should never happen. */ + } + } + + return resultlen; +} + + diff --git a/scd/app-nks.c b/scd/app-nks.c index a4b6e3a15..e69b59879 100644 --- a/scd/app-nks.c +++ b/scd/app-nks.c @@ -53,68 +53,6 @@ static struct { -/* Given the slot and the File Id FID, return the length of the - certificate contained in that file. Returns 0 if the file does not - exists or does not contain a certificate. */ -static size_t -get_length_of_cert (int slot, int fid) -{ - gpg_error_t err; - unsigned char *buffer; - const unsigned char *p; - size_t buflen, n; - int class, tag, constructed, ndef; - size_t objlen, hdrlen; - - err = iso7816_select_file (slot, fid, 0, NULL, NULL); - if (err) - { - log_info ("error selecting FID 0x%04X: %s\n", fid, gpg_strerror (err)); - return 0; - } - - err = iso7816_read_binary (slot, 0, 32, &buffer, &buflen); - if (err) - { - log_info ("error reading certificate from FID 0x%04X: %s\n", - fid, gpg_strerror (err)); - return 0; - } - - if (!buflen || *buffer == 0xff) - { - log_info ("no certificate contained in FID 0x%04X\n", fid); - xfree (buffer); - return 0; - } - - p = buffer; - n = buflen; - err = parse_ber_header (&p, &n, &class, &tag, &constructed, - &ndef, &objlen, &hdrlen); - if (err) - { - log_info ("error parsing certificate in FID 0x%04X: %s\n", - fid, gpg_strerror (err)); - xfree (buffer); - return 0; - } - - /* All certificates should commence with a SEQUENCE expect fro the - special ROOT CA which are enclosed in a SET. */ - if ( !(class == CLASS_UNIVERSAL && constructed - && (tag == TAG_SEQUENCE || tag == TAG_SET))) - { - log_info ("contents of FID 0x%04X does not look like a certificate\n", - fid); - return 0; - } - - return objlen + hdrlen; -} - - - /* Read the file with FID, assume it contains a public key and return its keygrip in the caller provided 41 byte buffer R_GRIPSTR. */ static gpg_error_t @@ -191,8 +129,10 @@ do_learn_status (APP app, CTRL ctrl) { if (filelist[i].certtype) { - size_t len = get_length_of_cert (app->slot, filelist[i].fid); + size_t len; + len = app_help_read_length_of_cert (app->slot, + filelist[i].fid, NULL); if (len) { /* FIXME: We should store the length in the application's diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 7782b8e1c..af5f5a27f 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -1201,7 +1201,7 @@ app_select_openpgp (APP app) /* The OpenPGP card returns the serial number as part of the AID; because we prefer to use OpenPGP serial numbers, we - repalce a possibly already set one from a EF.GDO with this + replace a possibly already set one from a EF.GDO with this one. Note, that for current OpenPGP cards, no EF.GDO exists and thus it won't matter at all. */ rc = iso7816_get_data (slot, 0x004F, &buffer, &buflen); diff --git a/scd/card.c b/scd/card.c index 8366dcb1c..9ec2a52c5 100644 --- a/scd/card.c +++ b/scd/card.c @@ -325,8 +325,6 @@ card_get_serial_and_stamp (CARD card, char **serial, time_t *stamp) } if (card->p15card) card_p15_bind (card); - else - card_dinsig_bind (card); card->fnc.initialized = 1; } diff --git a/scd/iso7816.c b/scd/iso7816.c index d7d3c126b..24361d148 100644 --- a/scd/iso7816.c +++ b/scd/iso7816.c @@ -488,6 +488,8 @@ iso7816_read_binary (int slot, size_t offset, size_t nmax, int sw; unsigned char *buffer; size_t bufferlen; + int read_all = !nmax; + size_t n; if (!result || !resultlen) return gpg_error (GPG_ERR_INV_VALUE); @@ -496,18 +498,22 @@ iso7816_read_binary (int slot, size_t offset, size_t nmax, /* We can only encode 15 bits in p0,p1 to indicate an offset. Thus we check for this limit. */ - if (offset > 32767 || nmax > 254) + if (offset > 32767) return gpg_error (GPG_ERR_INV_VALUE); do { buffer = NULL; bufferlen = 0; - /* Fixme: Either the ccid driver of the TCOS cards have problems + /* Fixme: Either the ccid driver or the TCOS cards have problems with an Le of 0. */ + if (read_all || nmax > 254) + n = 254; + else + n = nmax; sw = apdu_send_le (slot, 0x00, CMD_READ_BINARY, - ((offset>>8) & 0xff), (offset & 0xff) , -1, NULL, - nmax? nmax : 254, &buffer, &bufferlen); + ((offset>>8) & 0xff), (offset & 0xff) , -1, NULL, + n, &buffer, &bufferlen); if (sw != SW_SUCCESS && sw != SW_EOF_REACHED) { @@ -545,8 +551,12 @@ iso7816_read_binary (int slot, size_t offset, size_t nmax, if (offset > 32767) break; /* We simply truncate the result for too large files. */ + if (nmax > bufferlen) + nmax -= bufferlen; + else + nmax = 0; } - while (!nmax && sw != SW_EOF_REACHED); + while ((read_all && sw != SW_EOF_REACHED) || (!read_all && nmax)); return 0; } diff --git a/scd/scdaemon.c b/scd/scdaemon.c index 5665237ca..93746ec35 100644 --- a/scd/scdaemon.c +++ b/scd/scdaemon.c @@ -103,8 +103,8 @@ static ARGPARSE_OPTS opts[] = { { oNoDetach, "no-detach" ,0, N_("do not detach from the console")}, { oLogFile, "log-file" ,2, N_("use a log file for the server")}, { oReaderPort, "reader-port", 2, N_("|N|connect to reader at port N")}, - { octapiDriver, "ctapi-driver", 2, N_("NAME|use NAME as ct-API driver")}, - { opcscDriver, "pcsc-driver", 2, N_("NAME|use NAME as PC/SC driver")}, + { octapiDriver, "ctapi-driver", 2, N_("|NAME|use NAME as ct-API driver")}, + { opcscDriver, "pcsc-driver", 2, N_("|NAME|use NAME as PC/SC driver")}, { oDisableCCID, "disable-ccid", 0, #ifdef HAVE_LIBUSB N_("do not use the internal CCID driver") @@ -126,6 +126,9 @@ static ARGPARSE_OPTS opts[] = { }; +#define DEFAULT_PCSC_DRIVER "libpcsclite.so" + + static volatile int caught_fatal_sig = 0; /* It is possible that we are currently running under setuid permissions */ @@ -302,6 +305,7 @@ main (int argc, char **argv ) char *logfile = NULL; int debug_wait = 0; int gpgconf_list = 0; + const char *config_filename = NULL; set_strusage (my_strusage); gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN); @@ -334,7 +338,7 @@ main (int argc, char **argv ) may_coredump = disable_core_dumps (); /* Set default options. */ - opt.pcsc_driver = "libpcsclite.so"; + opt.pcsc_driver = DEFAULT_PCSC_DRIVER; shell = getenv ("SHELL"); @@ -466,7 +470,8 @@ main (int argc, char **argv ) { fclose( configfp ); configfp = NULL; - xfree(configname); + /* Keep a copy of the config name for use by --gpgconf-list. */ + config_filename = configname; configname = NULL; goto next_pass; } @@ -507,19 +512,49 @@ main (int argc, char **argv ) if (gpgconf_list) { /* List options and default values in the GPG Conf format. */ - char *filename; - filename = make_filename (opt.homedir, "scdaemon.conf", NULL); - printf ("gpgconf-scdaemon.conf:\"%s\n", filename); - xfree (filename); - - printf ("verbose:\n" - "quiet:\n" - "debug-level:none\n" - "log-file:\n" - "force:\n" - "faked-system-time:\n" - "no-greeting:\n"); + /* The following list is taken from gnupg/tools/gpgconf-comp.c. */ + /* Option flags. YOU MUST NOT CHANGE THE NUMBERS OF THE EXISTING + FLAGS, AS THEY ARE PART OF THE EXTERNAL INTERFACE. */ +#define GC_OPT_FLAG_NONE 0UL + /* The RUNTIME flag for an option indicates that the option can be + changed at runtime. */ +#define GC_OPT_FLAG_RUNTIME (1UL << 3) + /* The DEFAULT flag for an option indicates that the option has a + default value. */ +#define GC_OPT_FLAG_DEFAULT (1UL << 4) + /* The DEF_DESC flag for an option indicates that the option has a + default, which is described by the value of the default field. */ +#define GC_OPT_FLAG_DEF_DESC (1UL << 5) + /* The NO_ARG_DESC flag for an option indicates that the argument has + a default, which is described by the value of the ARGDEF field. */ +#define GC_OPT_FLAG_NO_ARG_DESC (1UL << 6) + + printf ("gpgconf-scdaemon.conf:%lu:\"%s\"\n", + GC_OPT_FLAG_DEFAULT, + config_filename?config_filename:"/dev/null"); + + printf ("verbose:%lu:\n" + "quiet:%lu:\n" + "debug-level:%lu:\"none\":\n" + "log-file:%lu:\n", + GC_OPT_FLAG_NONE, + GC_OPT_FLAG_NONE, + GC_OPT_FLAG_DEFAULT, + GC_OPT_FLAG_NONE ); + + printf ("reader-port:%lu:\n", GC_OPT_FLAG_NONE ); + printf ("ctapi-driver:%lu:\n", GC_OPT_FLAG_NONE ); + printf ("pcsc-driver:%lu:\"%s\":\n", + GC_OPT_FLAG_DEFAULT, DEFAULT_PCSC_DRIVER ); +#ifdef HAVE_LIBUSB + printf ("disable-ccid:%lu:\n", GC_OPT_FLAG_NONE ); +#endif +#ifdef HAVE_LIBUSB + printf ("disable-opensc:%lu:\n", GC_OPT_FLAG_NONE ); +#endif + printf ("allow-admin:%lu:\n", GC_OPT_FLAG_NONE ); + scd_exit (0); } -- cgit From 869a2bbad2f76153d953aeaaec5e3f0dd31d82f6 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 26 Apr 2004 18:28:06 +0000 Subject: * app-common.h: New members FNC.DEINIT and APP_LOCAL. * app.c (release_application): Call new deconstructor. * app-openpgp.c (do_deinit): New. (get_cached_data, flush_cache_item, flush_cache_after_error) (flush_cache): New. (get_one_do): Replaced arg SLOT by APP. Make used of cached data. (verify_chv2, verify_chv3): Flush some cache item after error. (do_change_pin): Ditto. (do_sign): Ditto. (do_setattr): Flush cache item. (do_genkey): Flush the entire cache. (compare_fingerprint): Use cached data. --- scd/ChangeLog | 13 +++ scd/app-common.h | 5 +- scd/app-openpgp.c | 244 +++++++++++++++++++++++++++++++++++++++++++++++------- scd/app.c | 6 ++ 4 files changed, 235 insertions(+), 33 deletions(-) (limited to 'scd/app-openpgp.c') diff --git a/scd/ChangeLog b/scd/ChangeLog index 3aea9f08d..1db7a8a62 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,5 +1,18 @@ 2004-04-26 Werner Koch + * app-common.h: New members FNC.DEINIT and APP_LOCAL. + * app.c (release_application): Call new deconstructor. + * app-openpgp.c (do_deinit): New. + (get_cached_data, flush_cache_item, flush_cache_after_error) + (flush_cache): New. + (get_one_do): Replaced arg SLOT by APP. Make used of cached data. + (verify_chv2, verify_chv3): Flush some cache item after error. + (do_change_pin): Ditto. + (do_sign): Ditto. + (do_setattr): Flush cache item. + (do_genkey): Flush the entire cache. + (compare_fingerprint): Use cached data. + * scdaemon.c (main): Do the last change the usual way. This is so that we can easily test for versioned config files above. diff --git a/scd/app-common.h b/scd/app-common.h index c16a15719..6e62bf99d 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -23,6 +23,8 @@ #include +struct app_local_s; /* Defined by all app-*.c. */ + struct app_ctx_s { int initialized; /* The application has been initialied and the function pointers may be used. Note that for @@ -37,7 +39,9 @@ struct app_ctx_s { int force_chv1; /* True if the card does not cache CHV1. */ int did_chv2; int did_chv3; + struct app_local_s *app_local; /* Local to the application. */ struct { + void (*deinit) (app_t app); int (*learn_status) (app_t app, ctrl_t ctrl); int (*readcert) (app_t app, const char *certid, unsigned char **cert, size_t *certlen); @@ -75,7 +79,6 @@ struct app_ctx_s { void *pincb_arg); } fnc; - }; #if GNUPG_MAJOR_VERSION == 1 diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index af5f5a27f..7ecbc6a48 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -50,35 +50,199 @@ static struct { int constructed; int get_from; /* Constructed DO with this DO or 0 for direct access. */ int binary; + int dont_cache; + int flush_on_error; char *desc; } data_objects[] = { - { 0x005E, 0, 0, 1, "Login Data" }, - { 0x5F50, 0, 0, 0, "URL" }, - { 0x0065, 1, 0, 1, "Cardholder Related Data"}, - { 0x005B, 0, 0x65, 0, "Name" }, - { 0x5F2D, 0, 0x65, 0, "Language preferences" }, - { 0x5F35, 0, 0x65, 0, "Sex" }, - { 0x006E, 1, 0, 1, "Application Related Data" }, - { 0x004F, 0, 0x6E, 1, "AID" }, - { 0x0073, 1, 0, 1, "Discretionary Data Objects" }, - { 0x0047, 0, 0x6E, 1, "Card Capabilities" }, - { 0x00C0, 0, 0x6E, 1, "Extended Card Capabilities" }, - { 0x00C1, 0, 0x6E, 1, "Algorithm Attributes Signature" }, - { 0x00C2, 0, 0x6E, 1, "Algorithm Attributes Decryption" }, - { 0x00C3, 0, 0x6E, 1, "Algorithm Attributes Authentication" }, - { 0x00C4, 0, 0x6E, 1, "CHV Status Bytes" }, - { 0x00C5, 0, 0x6E, 1, "Fingerprints" }, - { 0x00C6, 0, 0x6E, 1, "CA Fingerprints" }, - { 0x007A, 1, 0, 1, "Security Support Template" }, - { 0x0093, 0, 0x7A, 1, "Digital Signature Counter" }, + { 0x005E, 0, 0, 1, 0, 0, "Login Data" }, + { 0x5F50, 0, 0, 0, 0, 0, "URL" }, + { 0x0065, 1, 0, 1, 0, 0, "Cardholder Related Data"}, + { 0x005B, 0, 0x65, 0, 0, 0, "Name" }, + { 0x5F2D, 0, 0x65, 0, 0, 0, "Language preferences" }, + { 0x5F35, 0, 0x65, 0, 0, 0, "Sex" }, + { 0x006E, 1, 0, 1, 0, 0, "Application Related Data" }, + { 0x004F, 0, 0x6E, 1, 0, 0, "AID" }, + { 0x0073, 1, 0, 1, 0, 0, "Discretionary Data Objects" }, + { 0x0047, 0, 0x6E, 1, 0, 0, "Card Capabilities" }, + { 0x00C0, 0, 0x6E, 1, 0, 0, "Extended Card Capabilities" }, + { 0x00C1, 0, 0x6E, 1, 0, 0, "Algorithm Attributes Signature" }, + { 0x00C2, 0, 0x6E, 1, 0, 0, "Algorithm Attributes Decryption" }, + { 0x00C3, 0, 0x6E, 1, 0, 0, "Algorithm Attributes Authentication" }, + { 0x00C4, 0, 0x6E, 1, 0, 1, "CHV Status Bytes" }, + { 0x00C5, 0, 0x6E, 1, 0, 0, "Fingerprints" }, + { 0x00C6, 0, 0x6E, 1, 0, 0, "CA Fingerprints" }, + { 0x007A, 1, 0, 1, 0, 0, "Security Support Template" }, + { 0x0093, 0, 0x7A, 1, 1, 0, "Digital Signature Counter" }, { 0 } }; +struct cache_s { + struct cache_s *next; + int tag; + size_t length; + unsigned char data[1]; +}; + +struct app_local_s { + struct cache_s *cache; +}; + + static unsigned long convert_sig_counter_value (const unsigned char *value, size_t valuelen); static unsigned long get_sig_counter (APP app); +/* Deconstructor. */ +static void +do_deinit (app_t app) +{ + if (app && app->app_local) + { + struct cache_s *c, *c2; + + for (c = app->app_local->cache; c; c = c2) + { + c2 = c->next; + xfree (c); + } + xfree (app->app_local); + app->app_local = NULL; + } +} + + +/* Wrapper around iso7816_get_data which first tries to get the data + from the cache. */ +static gpg_error_t +get_cached_data (app_t app, int tag, + unsigned char **result, size_t *resultlen) +{ + gpg_error_t err; + int i; + unsigned char *p; + size_t len; + struct cache_s *c; + + + *result = NULL; + *resultlen = 0; + + if (app->app_local) + { + for (c=app->app_local->cache; c; c = c->next) + if (c->tag == tag) + { + p = xtrymalloc (c->length); + if (!p) + return gpg_error (gpg_err_code_from_errno (errno)); + memcpy (p, c->data, c->length); + *resultlen = c->length; + *result = p; + return 0; + } + } + + err = iso7816_get_data (app->slot, tag, &p, &len); + if (err) + return err; + *result = p; + *resultlen = len; + + /* Check whether we should cache this object. */ + for (i=0; data_objects[i].tag; i++) + if (data_objects[i].tag == tag) + { + if (data_objects[i].dont_cache) + return 0; + break; + } + + /* No, cache it. */ + if (!app->app_local) + app->app_local = xtrycalloc (1, sizeof *app->app_local); + + /* Note that we can safely ignore out of core errors. */ + if (app->app_local) + { + for (c=app->app_local->cache; c; c = c->next) + assert (c->tag != tag); + + c = xtrymalloc (sizeof *c + len); + if (c) + { + memcpy (c->data, p, len); + log_debug (" caching tag %04X\n", tag); + c->length = len; + c->tag = tag; + c->next = app->app_local->cache; + app->app_local->cache = c; + } + } + + return 0; +} + +/* Remove DO at TAG from the cache. */ +static void +flush_cache_item (app_t app, int tag) +{ + struct cache_s *c, *cprev; + int i; + + if (!app->app_local) + return; + + for (c=app->app_local->cache, cprev=NULL; c ; cprev=c, c = c->next) + if (c->tag == tag) + { + if (cprev) + cprev->next = c->next; + else + app->app_local->cache = c->next; + xfree (c); + + for (c=app->app_local->cache; c ; c = c->next) + assert (c->tag != tag); /* Oops: duplicated entry. */ + return; + } + + /* Try again if we have an outer tag. */ + for (i=0; data_objects[i].tag; i++) + if (data_objects[i].tag == tag && data_objects[i].get_from + && data_objects[i].get_from != tag) + flush_cache_item (app, data_objects[i].get_from); +} + +/* Flush all entries from the cache which might be out of sync after + an error. */ +static void +flush_cache_after_error (app_t app) +{ + int i; + + for (i=0; data_objects[i].tag; i++) + if (data_objects[i].flush_on_error) + flush_cache_item (app, data_objects[i].tag); +} + + +/* Flush the entire cache. */ +static void +flush_cache (app_t app) +{ + if (app && app->app_local) + { + struct cache_s *c, *c2; + + for (c = app->app_local->cache; c; c = c2) + { + c2 = c->next; + xfree (c); + } + app->app_local->cache = NULL; + } +} /* Get the DO identified by TAG from the card in SLOT and return a @@ -86,7 +250,7 @@ static unsigned long get_sig_counter (APP app); NULL if not found or a pointer which must be used to release the buffer holding value. */ static void * -get_one_do (int slot, int tag, unsigned char **result, size_t *nbytes) +get_one_do (app_t app, int tag, unsigned char **result, size_t *nbytes) { int rc, i; unsigned char *buffer; @@ -103,8 +267,8 @@ get_one_do (int slot, int tag, unsigned char **result, size_t *nbytes) rc = -1; if (data_objects[i].tag && data_objects[i].get_from) { - rc = iso7816_get_data (slot, data_objects[i].get_from, - &buffer, &buflen); + rc = get_cached_data (app, data_objects[i].get_from, + &buffer, &buflen); if (!rc) { const unsigned char *s; @@ -125,7 +289,7 @@ get_one_do (int slot, int tag, unsigned char **result, size_t *nbytes) if (!value) /* Not in a constructed DO, try simple. */ { - rc = iso7816_get_data (slot, tag, &buffer, &buflen); + rc = get_cached_data (app, tag, &buffer, &buflen); if (!rc) { value = buffer; @@ -374,7 +538,7 @@ do_getattr (APP app, CTRL ctrl, const char *name) return 0; } - relptr = get_one_do (app->slot, table[idx].tag, &value, &valuelen); + relptr = get_one_do (app, table[idx].tag, &value, &valuelen); if (relptr) { if (table[idx].special == 1) @@ -429,7 +593,7 @@ do_learn_status (APP app, CTRL ctrl) /* Verify CHV2 if required. Depending on the configuration of the card CHV1 will also be verified. */ static int -verify_chv2 (APP app, +verify_chv2 (app_t app, int (*pincb)(void*, const char *, char **), void *pincb_arg) { @@ -458,6 +622,7 @@ verify_chv2 (APP app, { log_error ("verify CHV2 failed: %s\n", gpg_strerror (rc)); xfree (pinvalue); + flush_cache_after_error (app); return rc; } app->did_chv2 = 1; @@ -471,6 +636,7 @@ verify_chv2 (APP app, { log_error ("verify CHV1 failed: %s\n", gpg_strerror (rc)); xfree (pinvalue); + flush_cache_after_error (app); return rc; } app->did_chv1 = 1; @@ -517,6 +683,7 @@ verify_chv3 (APP app, if (rc) { log_error ("verify CHV3 failed: %s\n", gpg_strerror (rc)); + flush_cache_after_error (app); return rc; } app->did_chv3 = 1; @@ -561,6 +728,10 @@ do_setattr (APP app, const char *name, if (rc) return rc; + /* Flush the cache before writing it, so that the next get operation + will reread the data from the card and thus get synced in case of + errors (e.g. data truncated by the card). */ + flush_cache_item (app, table[idx].tag); rc = iso7816_put_data (app->slot, table[idx].tag, value, valuelen); if (rc) log_error ("failed to set `%s': %s\n", table[idx].name, gpg_strerror (rc)); @@ -647,7 +818,8 @@ do_change_pin (APP app, CTRL ctrl, const char *chvnostr, int reset_mode, pinvalue, strlen (pinvalue)); } xfree (pinvalue); - + if (rc) + flush_cache_after_error (app); leave: return rc; @@ -678,6 +850,10 @@ do_genkey (APP app, CTRL ctrl, const char *keynostr, unsigned int flags, return gpg_error (GPG_ERR_INV_ID); keyno--; + /* We flush the cache to increase the traffic before a key + generation. This _might_ help a card to gather more entropy. */ + flush_cache (app); + rc = iso7816_get_data (app->slot, 0x006E, &buffer, &buflen); if (rc) { @@ -711,6 +887,7 @@ do_genkey (APP app, CTRL ctrl, const char *keynostr, unsigned int flags, goto leave; xfree (buffer); buffer = NULL; + #if 1 log_info ("please wait while key is being generated ...\n"); start_at = time (NULL); @@ -801,7 +978,7 @@ get_sig_counter (APP app) size_t valuelen; unsigned long ul; - relptr = get_one_do (app->slot, 0x0093, &value, &valuelen); + relptr = get_one_do (app, 0x0093, &value, &valuelen); if (!relptr) return 0; ul = convert_sig_counter_value (value, valuelen); @@ -819,7 +996,7 @@ compare_fingerprint (APP app, int keyno, unsigned char *sha1fpr) assert (keyno >= 1 && keyno <= 3); - rc = iso7816_get_data (app->slot, 0x006E, &buffer, &buflen); + rc = get_cached_data (app, 0x006E, &buffer, &buflen); if (rc) { log_error ("error reading application data\n"); @@ -979,6 +1156,7 @@ do_sign (APP app, const char *keyidstr, int hashalgo, { log_error ("verify CHV1 failed\n"); xfree (pinvalue); + flush_cache_after_error (app); return rc; } app->did_chv1 = 1; @@ -992,6 +1170,7 @@ do_sign (APP app, const char *keyidstr, int hashalgo, { log_error ("verify CHV2 failed\n"); xfree (pinvalue); + flush_cache_after_error (app); return rc; } app->did_chv2 = 1; @@ -1220,7 +1399,7 @@ app_select_openpgp (APP app) app->serialnolen = buflen; buffer = NULL; - relptr = get_one_do (app->slot, 0x00C4, &buffer, &buflen); + relptr = get_one_do (app, 0x00C4, &buffer, &buflen); if (!relptr) { log_error ("can't access CHV Status Bytes - invalid OpenPGP card?\n"); @@ -1232,6 +1411,7 @@ app_select_openpgp (APP app) if (opt.verbose > 1) dump_all_do (slot); + app->fnc.deinit = do_deinit; app->fnc.learn_status = do_learn_status; app->fnc.readcert = NULL; app->fnc.getattr = do_getattr; @@ -1285,7 +1465,7 @@ app_openpgp_cardinfo (APP app, if (disp_name) { *disp_name = NULL; - relptr = get_one_do (app->slot, 0x005B, &value, &valuelen); + relptr = get_one_do (app, 0x005B, &value, &valuelen); if (relptr) { *disp_name = make_printable_string (value, valuelen, 0); @@ -1296,7 +1476,7 @@ app_openpgp_cardinfo (APP app, if (pubkey_url) { *pubkey_url = NULL; - relptr = get_one_do (app->slot, 0x5F50, &value, &valuelen); + relptr = get_one_do (app, 0x5F50, &value, &valuelen); if (relptr) { *pubkey_url = make_printable_string (value, valuelen, 0); @@ -1310,7 +1490,7 @@ app_openpgp_cardinfo (APP app, *fpr2 = NULL; if (fpr3) *fpr3 = NULL; - relptr = get_one_do (app->slot, 0x00C5, &value, &valuelen); + relptr = get_one_do (app, 0x00C5, &value, &valuelen); if (relptr && valuelen >= 60) { if (fpr1) diff --git a/scd/app.c b/scd/app.c index d395fe559..a9a9243eb 100644 --- a/scd/app.c +++ b/scd/app.c @@ -116,6 +116,12 @@ release_application (app_t app) if (!app) return; + if (app->fnc.deinit) + { + app->fnc.deinit (app); + app->fnc.deinit = NULL; + } + xfree (app->serialno); xfree (app); } -- cgit From 4c96cb0683c4ff4e4b8d5ae9c61d555437ad51bd Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 28 Apr 2004 09:00:05 +0000 Subject: * app-common.h: Do not include ksba.h for gnupg 1. --- scd/ChangeLog | 4 ++++ scd/app-common.h | 2 ++ scd/app-openpgp.c | 1 - 3 files changed, 6 insertions(+), 1 deletion(-) (limited to 'scd/app-openpgp.c') diff --git a/scd/ChangeLog b/scd/ChangeLog index 1db7a8a62..2233f223d 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,7 @@ +2004-04-27 Werner Koch + + * app-common.h: Do not include ksba.h for gnupg 1. + 2004-04-26 Werner Koch * app-common.h: New members FNC.DEINIT and APP_LOCAL. diff --git a/scd/app-common.h b/scd/app-common.h index 6e62bf99d..c61bcca60 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -21,7 +21,9 @@ #ifndef GNUPG_SCD_APP_COMMON_H #define GNUPG_SCD_APP_COMMON_H +#if GNUPG_MAJOR_VERSION != 1 #include +#endif struct app_local_s; /* Defined by all app-*.c. */ diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 7ecbc6a48..07420c697 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -172,7 +172,6 @@ get_cached_data (app_t app, int tag, if (c) { memcpy (c->data, p, len); - log_debug (" caching tag %04X\n", tag); c->length = len; c->tag = tag; c->next = app->app_local->cache; -- cgit From 7d486a0969c6efa46f53e76b8746c8c041f527ad Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 29 Apr 2004 17:25:57 +0000 Subject: * app-openpgp.c (do_setattr): Sync FORCE_CHV1. --- scd/ChangeLog | 4 ++++ scd/app-openpgp.c | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'scd/app-openpgp.c') diff --git a/scd/ChangeLog b/scd/ChangeLog index 2233f223d..14dd9c3ff 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,7 @@ +2004-04-28 Werner Koch + + * app-openpgp.c (do_setattr): Sync FORCE_CHV1. + 2004-04-27 Werner Koch * app-common.h: Do not include ksba.h for gnupg 1. diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 07420c697..f40951941 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -704,13 +704,14 @@ do_setattr (APP app, const char *name, static struct { const char *name; int tag; + int special; } table[] = { { "DISP-NAME", 0x005B }, { "LOGIN-DATA", 0x005E }, { "DISP-LANG", 0x5F2D }, { "DISP-SEX", 0x5F35 }, { "PUBKEY-URL", 0x5F50 }, - { "CHV-STATUS-1", 0x00C4 }, + { "CHV-STATUS-1", 0x00C4, 1 }, { "CA-FPR-1", 0x00CA }, { "CA-FPR-2", 0x00CB }, { "CA-FPR-3", 0x00CC }, @@ -735,6 +736,9 @@ do_setattr (APP app, const char *name, if (rc) log_error ("failed to set `%s': %s\n", table[idx].name, gpg_strerror (rc)); + if (table[idx].special == 1) + app->force_chv1 = (valuelen && *value == 0); + return rc; } -- cgit From bcaa520ad6fec10966d2b82e3c52756d69d8764e Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 1 Jul 2004 17:41:33 +0000 Subject: (do_getattr): Fix for sending CA-FPR. --- scd/ChangeLog | 9 +++++++++ scd/app-openpgp.c | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'scd/app-openpgp.c') diff --git a/scd/ChangeLog b/scd/ChangeLog index b06c692f5..1dfafbd5a 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,12 @@ +2004-07-01 Werner Koch + + * app-openpgp.c (do_getattr): Fix for sending CA-FPR. + +2004-06-30 Werner Koch + + * app-openpgp.c (app_openpgp_readkey): Fixed check for valid + exponent. + 2004-06-18 Werner Koch * sc-investigate.c (my_read_line): Renamed from read_line. diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index f40951941..3dc015baa 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -561,7 +561,7 @@ do_getattr (APP app, CTRL ctrl, const char *name) { if (valuelen >= 60) for (i=0; i < 3; i++) - send_fpr_if_not_null (ctrl, "KEY-FPR", i+1, value+i*20); + send_fpr_if_not_null (ctrl, table[idx].name, i+1, value+i*20); } else send_status_info (ctrl, table[idx].name, value, valuelen, NULL, 0); @@ -1619,7 +1619,7 @@ app_openpgp_readkey (APP app, int keyno, unsigned char **m, size_t *mlen, memcpy (*m, a, alen); a = find_tlv (keydata, keydatalen, 0x0082, &alen); - if (!e) + if (!a) { log_error ("response does not contain the RSA public exponent\n"); rc = gpg_error (GPG_ERR_CARD); -- cgit From 9d74d40da1e3b58a994dc3435e6feb07fb1fc420 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 9 Sep 2004 07:28:47 +0000 Subject: * app.c (select_application): Fixed serial number extraction and added the BMI card workaround. (app_munge_serialno): New. * app-openpgp.c (app_select_openpgp): Try munging serialno. --- scd/ChangeLog | 7 +++++++ scd/app-common.h | 4 ++++ scd/app-openpgp.c | 7 +++++++ scd/app.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 74 insertions(+), 3 deletions(-) (limited to 'scd/app-openpgp.c') diff --git a/scd/ChangeLog b/scd/ChangeLog index 80b244ef1..a527b5da5 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,10 @@ +2004-08-20 Werner Koch + + * app.c (select_application): Fixed serial number extraction and + added the BMI card workaround. + (app_munge_serialno): New. + * app-openpgp.c (app_select_openpgp): Try munging serialno. + 2004-08-05 Werner Koch * scdaemon.c (main): New option --disable-application. diff --git a/scd/app-common.h b/scd/app-common.h index c61bcca60..c15f174bf 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -95,6 +95,7 @@ size_t app_help_read_length_of_cert (int slot, int fid, size_t *r_certoff); /*-- app.c --*/ app_t select_application (ctrl_t ctrl, int slot, const char *name); void release_application (app_t app); +int app_munge_serialno (app_t app); int app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp); int app_write_learn_status (app_t app, ctrl_t ctrl); int app_readcert (app_t app, const char *certid, @@ -159,6 +160,9 @@ int app_select_nks (app_t app); /*-- app-dinsig.c --*/ int app_select_dinsig (app_t app); +/*-- app-p15.c --*/ +int app_select_p15 (app_t app); + #endif diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 3dc015baa..67bc336ec 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -1394,6 +1394,13 @@ app_select_openpgp (APP app) log_info ("got AID: "); log_printhex ("", buffer, buflen); } +#if GNUPG_MAJOR_VERSION != 1 + /* A valid OpenPGP card should never need this but well the test + is cheap. */ + rc = app_number_serialno (app); + if (rc) + goto leave; +#endif app->card_version = buffer[6] << 8; app->card_version |= buffer[7]; diff --git a/scd/app.c b/scd/app.c index b3a13f19a..55fb5861e 100644 --- a/scd/app.c +++ b/scd/app.c @@ -1,5 +1,5 @@ /* app.c - Application selection. - * Copyright (C) 2003 Free Software Foundation, Inc. + * Copyright (C) 2003, 2004 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -45,6 +45,7 @@ is_app_allowed (const char *name) return 1; /* yes */ } + /* If called with NAME as NULL, select the best fitting application and return a context; otherwise select the application with NAME and return a context. SLOT identifies the reader device. Returns @@ -81,31 +82,50 @@ select_application (ctrl_t ctrl, int slot, const char *name) const unsigned char *p; p = find_tlv (result, resultlen, 0x5A, &n); - if (p && n && n >= (resultlen - (p - result))) + if (p) + resultlen -= (p-result); + if (p && n > resultlen && n == 0x0d && resultlen+1 == n) + { + /* The object it does not fit into the buffer. This is an + invalid encoding (or the buffer is too short. However, I + have some test cards with such an invalid encoding and + therefore I use this ugly workaround to return something + I can further experiment with. */ + log_debug ("enabling BMI testcard workaround\n"); + n--; + } + + if (p && n <= resultlen) { /* The GDO file is pretty short, thus we simply reuse it for storing the serial number. */ memmove (result, p, n); app->serialno = result; app->serialnolen = n; + rc = app_munge_serialno (app); + if (rc) + goto leave; } else xfree (result); result = NULL; } - + rc = gpg_error (GPG_ERR_NOT_FOUND); if (rc && is_app_allowed ("openpgp") && (!name || !strcmp (name, "openpgp"))) rc = app_select_openpgp (app); if (rc && is_app_allowed ("nks") && (!name || !strcmp (name, "nks"))) rc = app_select_nks (app); +/* if (rc && is_app_allowed ("p12") && (!name || !strcmp (name, "p12"))) */ +/* rc = app_select_p12 (app); */ if (rc && is_app_allowed ("dinsig") && (!name || !strcmp (name, "dinsig"))) rc = app_select_dinsig (app); if (rc && name) rc = gpg_error (GPG_ERR_NOT_SUPPORTED); + leave: if (rc) { if (name) @@ -141,6 +161,39 @@ release_application (app_t app) +/* The serial number may need some cosmetics. Do it here. This + function shall only be called once after a new serial number has + been put into APP->serialno. + + Prefixes we use: + + FF 00 00 = For serial numbers starting with an FF + FF 01 00 = Some german p15 cards return an empty serial number so the + serial number from the EF(TokeInfo is used instead. + + All other serial number not starting with FF are used as they are. +*/ +int +app_munge_serialno (app_t app) +{ + if (app->serialnolen && app->serialno[0] == 0xff) + { + /* The serial number starts with our special prefix. This + requires that we put our default prefix "FF0000" in front. */ + unsigned char *p = xtrymalloc (app->serialnolen + 3); + if (!p) + return gpg_error (gpg_err_code_from_errno (errno)); + memcpy (p, "\xff\0", 3); + memcpy (p+3, app->serialno, app->serialnolen); + app->serialnolen += 3; + xfree (app->serialno); + app->serialno = p; + } + return 0; +} + + + /* Retrieve the serial number and the time of the last update of the card. The serial number is returned as a malloced string (hex encoded) in SERIAL and the time of update is returned in STAMP. If -- cgit From f10040147834bbc5cc75f02b7215f2b45642ecaf Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 20 Sep 2004 18:47:11 +0000 Subject: (show_key_with_all_names): Print the card S/N. * app-openpgp.c (app_select_openpgp): Its app_munge_serialno and not app_number_serialno. --- g10/ChangeLog | 4 ++++ g10/keyedit.c | 21 +++++++++++++++++++++ scd/ChangeLog | 5 +++++ scd/app-openpgp.c | 2 +- sm/ChangeLog | 6 ++++++ sm/certchain.c | 15 ++++++++++++--- 6 files changed, 49 insertions(+), 4 deletions(-) (limited to 'scd/app-openpgp.c') diff --git a/g10/ChangeLog b/g10/ChangeLog index d33dcdc36..b553c1c9f 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,7 @@ +2004-09-20 Werner Koch + + * keyedit.c (show_key_with_all_names): Print the card S/N. + 2004-09-11 Moritz Schulte * openfile.c (copy_options_file): Fixed last commit (added a `+'). diff --git a/g10/keyedit.c b/g10/keyedit.c index 4da174e3c..2f9fccbf5 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -2121,6 +2121,27 @@ show_key_with_all_names( KBNODE keyblock, int only_marked, int with_revoker, datestr_from_sk(sk), expirestr_from_sk(sk) ); tty_printf("\n"); + if (sk->is_protected && sk->protect.s2k.mode == 1002) + { + tty_printf(" "); + tty_printf(_("card-no: ")); + if (sk->protect.ivlen == 16 + && !memcmp (sk->protect.iv, "\xD2\x76\x00\x01\x24\x01", 6)) + { /* This is an OpenPGP card. */ + for (i=8; i < 14; i++) + { + if (i == 10) + tty_printf (" "); + tty_printf ("%02X", sk->protect.iv[i]); + } + } + else + { /* Something is wrong: Print all. */ + for (i=0; i < sk->protect.ivlen; i++) + tty_printf ("%02X", sk->protect.iv[i]); + } + tty_printf ("\n"); + } } else if( with_subkeys && node->pkt->pkttype == PKT_SIGNATURE && node->pkt->pkt.signature->sig_class == 0x28 ) { diff --git a/scd/ChangeLog b/scd/ChangeLog index a527b5da5..e6789fcb2 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,8 @@ +2004-09-11 Werner Koch + + * app-openpgp.c (app_select_openpgp): Its app_munge_serialno and + not app_number_serialno. + 2004-08-20 Werner Koch * app.c (select_application): Fixed serial number extraction and diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 67bc336ec..1617ab888 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -1397,7 +1397,7 @@ app_select_openpgp (APP app) #if GNUPG_MAJOR_VERSION != 1 /* A valid OpenPGP card should never need this but well the test is cheap. */ - rc = app_number_serialno (app); + rc = app_munge_serialno (app); if (rc) goto leave; #endif diff --git a/sm/ChangeLog b/sm/ChangeLog index a8139e2e0..d68759151 100644 --- a/sm/ChangeLog +++ b/sm/ChangeLog @@ -1,3 +1,9 @@ +2004-09-14 Werner Koch + + * certchain.c (gpgsm_validate_chain): Give expired certificates a + higher error precedence and don't bother to check any CRL in that + case. + 2004-08-24 Werner Koch * certlist.c: Fixed typo in ocsp OID. diff --git a/sm/certchain.c b/sm/certchain.c index 2ce247f65..ad30a36e1 100644 --- a/sm/certchain.c +++ b/sm/certchain.c @@ -672,7 +672,12 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime, else if (gpg_err_code (rc) == GPG_ERR_NOT_TRUSTED) { do_list (0, lm, fp, _("root certificate is not marked trusted")); - if (!lm) + /* If we already figured out that the certificate is + expired it does not make much sense to ask the user + whether we wants to trust the root certificate. He + should do this only if the certificate under question + will then be usable. */ + if (!lm && !any_expired) { int rc2; char *fpr = gpgsm_get_fingerprint_string (subject_cert, @@ -707,6 +712,8 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime, /* Check for revocations etc. */ if ((flags & 1)) rc = 0; + else if (any_expired) + ; /* Don't bother to run the expensive CRL check then. */ else rc = is_cert_still_valid (ctrl, lm, fp, subject_cert, subject_cert, @@ -835,6 +842,8 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime, /* Check for revocations etc. */ if ((flags & 1)) rc = 0; + else if (any_expired) + ; /* Don't bother to run the expensive CRL check then. */ else rc = is_cert_still_valid (ctrl, lm, fp, subject_cert, issuer_cert, @@ -866,14 +875,14 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime, the error code to the most critical one */ if (any_revoked) rc = gpg_error (GPG_ERR_CERT_REVOKED); + else if (any_expired) + rc = gpg_error (GPG_ERR_CERT_EXPIRED); else if (any_no_crl) rc = gpg_error (GPG_ERR_NO_CRL_KNOWN); else if (any_crl_too_old) rc = gpg_error (GPG_ERR_CRL_TOO_OLD); else if (any_no_policy_match) rc = gpg_error (GPG_ERR_NO_POLICY_MATCH); - else if (any_expired) - rc = gpg_error (GPG_ERR_CERT_EXPIRED); } leave: -- cgit From f67c66e56f15b83ee8539ef2de563750c6908d9f Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 30 Sep 2004 13:24:33 +0000 Subject: * de.po: Updated. * POTFILES.in: Add more files. * app-openpgp.c (do_sign): Add the error string to the verify failed messages. * keylist.c (list_cert_colon): Make sure that the expired flag has a higher precedence than the invalid flag. --- po/ChangeLog | 6 ++ po/POTFILES.in | 2 + po/de.po | 125 ++++++++++++++++++++++--- scd/ChangeLog | 71 ++++++++++++++ scd/app-openpgp.c | 276 ++++++++++++++++++++++++++++++++++++++---------------- sm/ChangeLog | 5 + sm/keylist.c | 7 +- 7 files changed, 396 insertions(+), 96 deletions(-) (limited to 'scd/app-openpgp.c') diff --git a/po/ChangeLog b/po/ChangeLog index c1bcd81e1..25d7d4595 100644 --- a/po/ChangeLog +++ b/po/ChangeLog @@ -1,3 +1,9 @@ +2004-09-30 Werner Koch + + * de.po: Updated. + + * POTFILES.in: Add more files. + 2004-07-22 Werner Koch * de.po: Updated. diff --git a/po/POTFILES.in b/po/POTFILES.in index ae54716ac..eb4e36c85 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -15,6 +15,8 @@ jnlib/logging.c kbx/kbxutil.c scd/scdaemon.c +scd/sc-investigate.c +scd/app-openpgp.c sm/base64.c sm/call-agent.c diff --git a/po/de.po b/po/de.po index a09f0024d..3c4d90a44 100644 --- a/po/de.po +++ b/po/de.po @@ -10,8 +10,8 @@ msgid "" msgstr "" "Project-Id-Version: gnupg2 1.9.10\n" "Report-Msgid-Bugs-To: translations@gnupg.org\n" -"POT-Creation-Date: 2004-09-29 18:01+0200\n" -"PO-Revision-Date: 2004-09-29 18:10+0200\n" +"POT-Creation-Date: 2004-09-30 15:22+0200\n" +"PO-Revision-Date: 2004-09-30 15:23+0200\n" "Last-Translator: Werner Koch \n" "Language-Team: de\n" "MIME-Version: 1.0\n" @@ -100,12 +100,12 @@ msgid "allow clients to mark keys as \"trusted\"" msgstr "erlaube Aufrufern Schlüssel als \"vertrauenswürdig\" zu markieren" #: agent/gpg-agent.c:195 agent/protect-tool.c:134 scd/scdaemon.c:168 -#: sm/gpgsm.c:485 tools/gpgconf.c:85 +#: scd/sc-investigate.c:113 sm/gpgsm.c:485 tools/gpgconf.c:85 msgid "Please report bugs to <" msgstr "Fehlerberichte bitte an <" #: agent/gpg-agent.c:195 agent/protect-tool.c:134 scd/scdaemon.c:168 -#: sm/gpgsm.c:485 tools/gpgconf.c:85 +#: scd/sc-investigate.c:113 sm/gpgsm.c:485 tools/gpgconf.c:85 msgid ">.\n" msgstr ">.\n" @@ -127,7 +127,7 @@ msgid "invalid debug-level `%s' given\n" msgstr "ungültige Debugebene `%s' angegeben\n" #: agent/gpg-agent.c:446 agent/protect-tool.c:1050 kbx/kbxutil.c:436 -#: scd/scdaemon.c:357 sm/gpgsm.c:731 +#: scd/scdaemon.c:357 scd/sc-investigate.c:181 sm/gpgsm.c:731 #, c-format msgid "libgcrypt is too old (need %s, have %s)\n" msgstr "" @@ -432,6 +432,103 @@ msgstr "" "Bitte die Option `--daemon' nutzen um das Programm im Hintergund " "auszuführen\n" +#: scd/sc-investigate.c:116 +msgid "Usage: sc-investigate [options] (-h for help)\n" +msgstr "Gebrauch: sc-investigate [Optionen] (-h für Hilfe)\n" + +#: scd/sc-investigate.c:118 +msgid "" +"Syntax: sc-investigate [options] [args]]\n" +"Have a look at smartcards\n" +msgstr "" +"Gebrauch: sc-investigate [Optionen] [Argumente]\n" +"Den Inhalt einer Smartcard inspizieren\n" + +#: scd/app-openpgp.c:458 +#, c-format +msgid "failed to store the fingerprint: %s\n" +msgstr "Der Fingerprint kann nicht gespeichert werden: %s\n" + +#: scd/app-openpgp.c:471 +#, c-format +msgid "failed to store the creation date: %s\n" +msgstr "Das Erzeugungsdatum kann nicht gespeichert werden: %s\n" + +#: scd/app-openpgp.c:656 scd/app-openpgp.c:745 +#, c-format +msgid "PIN callback returned error: %s\n" +msgstr "Fehler vom PIN \"callback\": %s\n" + +#: scd/app-openpgp.c:662 scd/app-openpgp.c:751 scd/app-openpgp.c:1236 +#, c-format +msgid "prassphrase (CHV%d) is too short; minimum length is %d\n" +msgstr "Die Passphrase (CHV%d) ist zu kurz; Mindestlänge ist %d\n" + +#: scd/app-openpgp.c:671 scd/app-openpgp.c:685 scd/app-openpgp.c:761 +#: scd/app-openpgp.c:1245 scd/app-openpgp.c:1259 +#, c-format +msgid "verify CHV%d failed: %s\n" +msgstr "Prüfen von CHV%d fehlgeschlagen: %s\n" + +#: scd/app-openpgp.c:708 +msgid "access to admin commands is not configured\n" +msgstr "Zugriff auf Admin Kommandos ist nicht konfiguriert\n" + +#: scd/app-openpgp.c:725 +msgid "error retrieving CHV status from card\n" +msgstr "Fehler beim Holen des CHV Status von der Karte\n" + +#: scd/app-openpgp.c:731 +msgid "card is permanently locked!\n" +msgstr "Die Karte ist dauerhaft gesperrt!\n" + +#: scd/app-openpgp.c:738 +#, c-format +msgid "%d Admin PIN attempts remaining before card is permanently locked\n" +msgstr "" +"Noch %d Admin PIN Versuche möglich bevor die Karte dauerhaft gesperrt wird\n" + +#: scd/app-openpgp.c:742 +msgid "Admin PIN" +msgstr "Admin PIN" + +#: scd/app-openpgp.c:1504 +msgid "can't access CHV Status Bytes - invalid OpenPGP card?\n" +msgstr "" +"Zugriff auf die CHV Status Bytes nicht möglich - ungültige OpenPGP Karte?\n" + +#: scd/app-openpgp.c:1514 +msgid "can't access Extended Capability Flags - invalid OpenPGP card?\n" +msgstr "" +"Zugriff auf die Extended Capability Flags nicht möglich - ungültige OpenPGP " +"Karte?\n" + +#: scd/app-openpgp.c:1584 +#, c-format +msgid "error getting serial number: %s\n" +msgstr "Fehler beim Holen der Seriennummer: %s\n" + +#: scd/app-openpgp.c:1679 +#, c-format +msgid "failed to store the key: %s\n" +msgstr "Fehler beim Speichern des Schlüssels: %s\n" + +#: scd/app-openpgp.c:1721 +msgid "reading the key failed\n" +msgstr "Fehler beim Lesen des Schlüssels: %s\n" + +#: scd/app-openpgp.c:1728 +msgid "response does not contain the public key data\n" +msgstr "Die Antwort enthält keine Public Key Daten\n" + +#: scd/app-openpgp.c:1736 +msgid "response does not contain the RSA modulus\n" +msgstr "Die Antwort enthält keinen RSA Modulus\n" + +#: scd/app-openpgp.c:1747 +msgid "response does not contain the RSA public exponent\n" +msgstr "Die Antwort enthält keinen öffenlichen RSA Exponent\n" + #: sm/base64.c:315 #, c-format msgid "invalid radix64 character %02x skipped\n" @@ -488,7 +585,7 @@ msgstr "[Fehler - Ung msgid "[Error - invalid DN]" msgstr "[Fehler - Ungültiger DN]" -#: sm/certdump.c:652 +#: sm/certdump.c:655 #, c-format msgid "" "Please enter the passphrase to unlock the secret key for:\n" @@ -496,7 +593,7 @@ msgid "" "S/N %s, ID %08lX, created %s" msgstr "" "Bitte geben Sie die Passphrase an, um den \n" -"geheimen Schlüssels von\n" +"geheimen Schlüssel von\n" "\"%s\"\n" "S/N %s, ID %08lX, erzeugt %s\n" "zu entsperren" @@ -999,32 +1096,32 @@ msgstr "Verschl msgid "libksba is too old (need %s, have %s)\n" msgstr "Die Bibliothek Libksba is nicht aktuell (benötige %s, habe %s)\n" -#: sm/gpgsm.c:1182 +#: sm/gpgsm.c:1183 msgid "WARNING: program may create a core file!\n" msgstr "WARNUNG: Programm könnte eine core-dump-Datei schreiben!\n" -#: sm/gpgsm.c:1194 +#: sm/gpgsm.c:1195 msgid "WARNING: running with faked system time: " msgstr "WARNUNG: Ausführung mit gefälschter Systemzeit: " -#: sm/gpgsm.c:1220 +#: sm/gpgsm.c:1221 msgid "selected cipher algorithm is invalid\n" msgstr "Das ausgewählte Verschlüsselungsverfahren ist ungültig\n" -#: sm/gpgsm.c:1228 +#: sm/gpgsm.c:1229 msgid "selected digest algorithm is invalid\n" msgstr "Das ausgewählte Hashverfahren ist ungültig\n" -#: sm/gpgsm.c:1258 +#: sm/gpgsm.c:1259 #, c-format msgid "can't sign using `%s': %s\n" msgstr "Signieren mit `%s' nicht möglich: %s\n" -#: sm/gpgsm.c:1422 +#: sm/gpgsm.c:1423 msgid "this command has not yet been implemented\n" msgstr "Diee Kommando wurde noch nicht implementiert\n" -#: sm/gpgsm.c:1645 sm/gpgsm.c:1678 +#: sm/gpgsm.c:1646 sm/gpgsm.c:1679 #, c-format msgid "can't open `%s': %s\n" msgstr "Datei `%s' kann nicht geöffnet werden: %s\n" diff --git a/scd/ChangeLog b/scd/ChangeLog index e6789fcb2..9640ef6b2 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,74 @@ +2004-09-30 Werner Koch + + * app-openpgp.c (do_sign): Add the error string to the verify + failed messages. + +2004-09-27 Werner Koch + + From gnupg 1.3 + + * app-openpgp.c: Made all strings translatable. + (verify_chv3) [GNUPG_MAJOR_VERSION]: Make opt.allow_admin + available for use in gnupg 2. + (verify_chv3): Reimplemented countdown showing to use only + functions from this module. Flush the CVH status cache on a + successful read. + (get_one_do): Hack to bypass the cache for cards versions > 1.0. + (store_fpr): Store the creation date for card version > 1.0. + + * app-openpgp.c (app_openpgp_storekey): Call flush_cache. + (get_cached_data): Move local data initialization to .. + (app_select_openpgp): .. here. Read some flags for later use. + (do_getattr): New read-only attribute EXTCAP. + + * apdu.c (open_pcsc_reader): Do not print empty reader string. + + * ccid-driver.c (do_close_reader): Factored some code out from ... + (ccid_close_reader): ..here. + (ccid_shutdown_reader): New. + + * apdu.c (apdu_shutdown_reader): New. + (shutdown_ccid_reader): New. + + * apdu.c (open_ccid_reader): New arg PORTSTR. Pass it to + ccid_open_reader. + (apdu_open_reader): Pass portstr to open_ccid_reader. + (apdu_open_reader): No fallback if a full CCID reader id has been + given. + + * ccid-driver.c (ccid_get_reader_list): New. + (ccid_open_reader): Changed API to take a string for the reader. + Removed al the cruft for the libusb development vesion which seems + not to be maintained anymore and there are no packages anyway. + The stable library works just fine. + (struct ccid_reader_id_s): Deleted and replaced everywhere by a + simple string. + (usb_get_string_simple): Removed. + (bulk_in): Do valgrind hack here and not just everywhere. + + * ccid-driver.c (read_device_info): Removed. + (make_reader_id, scan_or_find_devices): New. + (ccid_open_reader): Simplified by make use of the new functions. + (ccid_set_debug_level): New. Changed the macros to make use of + it. It has turned out that it is often useful to enable debugging + at runtime so I added this option. + + From gnupg 1.3 - David Shaw + + * app-openpgp.c (verify_chv3): Show a countdown of how many wrong + admin PINs can be entered before the card is locked. + + * app-openpgp.c (get_cached_data): Avoid mallocing zero since it + breaks us when using --enable-m-guard. + + * ccid-driver.c (usb_get_string_simple): Replacement function to + work with older libusb. + + * ccid-driver.c (read_device_info): Fix segfault when usb device + is not accessible. + (ccid_open_reader): Allow working with an even older version of + libusb (usb_busses global instead of usb_get_busses()). + 2004-09-11 Werner Koch * app-openpgp.c (app_select_openpgp): Its app_munge_serialno and diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 1617ab888..6f9837c90 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -34,12 +34,12 @@ #include "errors.h" #include "memory.h" #include "util.h" -#include "i18n.h" #include "cardglue.h" #else /* GNUPG_MAJOR_VERSION != 1 */ #include "scdaemon.h" #endif /* GNUPG_MAJOR_VERSION != 1 */ +#include "i18n.h" #include "iso7816.h" #include "app-common.h" #include "tlv.h" @@ -52,27 +52,33 @@ static struct { int binary; int dont_cache; int flush_on_error; + int get_immediate_in_v11; /* Enable a hack to bypass the cache of + this data object if it is used in 1.1 + and later versions of the card. This + does not work with composite DO and is + currently only useful for the CHV + status bytes. */ char *desc; } data_objects[] = { - { 0x005E, 0, 0, 1, 0, 0, "Login Data" }, - { 0x5F50, 0, 0, 0, 0, 0, "URL" }, - { 0x0065, 1, 0, 1, 0, 0, "Cardholder Related Data"}, - { 0x005B, 0, 0x65, 0, 0, 0, "Name" }, - { 0x5F2D, 0, 0x65, 0, 0, 0, "Language preferences" }, - { 0x5F35, 0, 0x65, 0, 0, 0, "Sex" }, - { 0x006E, 1, 0, 1, 0, 0, "Application Related Data" }, - { 0x004F, 0, 0x6E, 1, 0, 0, "AID" }, - { 0x0073, 1, 0, 1, 0, 0, "Discretionary Data Objects" }, - { 0x0047, 0, 0x6E, 1, 0, 0, "Card Capabilities" }, - { 0x00C0, 0, 0x6E, 1, 0, 0, "Extended Card Capabilities" }, - { 0x00C1, 0, 0x6E, 1, 0, 0, "Algorithm Attributes Signature" }, - { 0x00C2, 0, 0x6E, 1, 0, 0, "Algorithm Attributes Decryption" }, - { 0x00C3, 0, 0x6E, 1, 0, 0, "Algorithm Attributes Authentication" }, - { 0x00C4, 0, 0x6E, 1, 0, 1, "CHV Status Bytes" }, - { 0x00C5, 0, 0x6E, 1, 0, 0, "Fingerprints" }, - { 0x00C6, 0, 0x6E, 1, 0, 0, "CA Fingerprints" }, - { 0x007A, 1, 0, 1, 0, 0, "Security Support Template" }, - { 0x0093, 0, 0x7A, 1, 1, 0, "Digital Signature Counter" }, + { 0x005E, 0, 0, 1, 0, 0, 0, "Login Data" }, + { 0x5F50, 0, 0, 0, 0, 0, 0, "URL" }, + { 0x0065, 1, 0, 1, 0, 0, 0, "Cardholder Related Data"}, + { 0x005B, 0, 0x65, 0, 0, 0, 0, "Name" }, + { 0x5F2D, 0, 0x65, 0, 0, 0, 0, "Language preferences" }, + { 0x5F35, 0, 0x65, 0, 0, 0, 0, "Sex" }, + { 0x006E, 1, 0, 1, 0, 0, 0, "Application Related Data" }, + { 0x004F, 0, 0x6E, 1, 0, 0, 0, "AID" }, + { 0x0073, 1, 0, 1, 0, 0, 0, "Discretionary Data Objects" }, + { 0x0047, 0, 0x6E, 1, 1, 0, 0, "Card Capabilities" }, + { 0x00C0, 0, 0x6E, 1, 1, 0, 0, "Extended Card Capabilities" }, + { 0x00C1, 0, 0x6E, 1, 1, 0, 0, "Algorithm Attributes Signature" }, + { 0x00C2, 0, 0x6E, 1, 1, 0, 0, "Algorithm Attributes Decryption" }, + { 0x00C3, 0, 0x6E, 1, 1, 0, 0, "Algorithm Attributes Authentication" }, + { 0x00C4, 0, 0x6E, 1, 0, 1, 1, "CHV Status Bytes" }, + { 0x00C5, 0, 0x6E, 1, 0, 0, 0, "Fingerprints" }, + { 0x00C6, 0, 0x6E, 1, 0, 0, 0, "CA Fingerprints" }, + { 0x007A, 1, 0, 1, 0, 0, 0, "Security Support Template" }, + { 0x0093, 0, 0x7A, 1, 1, 0, 0, "Digital Signature Counter" }, { 0 } }; @@ -86,6 +92,13 @@ struct cache_s { struct app_local_s { struct cache_s *cache; + struct + { + unsigned int get_challenge:1; + unsigned int key_import:1; + unsigned int change_force_chv:1; + unsigned int private_dos:1; + } extcap; }; @@ -124,24 +137,26 @@ get_cached_data (app_t app, int tag, size_t len; struct cache_s *c; - *result = NULL; *resultlen = 0; - if (app->app_local) - { - for (c=app->app_local->cache; c; c = c->next) - if (c->tag == tag) + for (c=app->app_local->cache; c; c = c->next) + if (c->tag == tag) + { + if(c->length) { - p = xtrymalloc (c->length); - if (!p) - return gpg_error (gpg_err_code_from_errno (errno)); - memcpy (p, c->data, c->length); - *resultlen = c->length; - *result = p; - return 0; + p = xtrymalloc (c->length); + if (!p) + return gpg_error (gpg_err_code_from_errno (errno)); + memcpy (p, c->data, c->length); + *result = p; } - } + + *resultlen = c->length; + + return 0; + } + err = iso7816_get_data (app->slot, tag, &p, &len); if (err) @@ -159,24 +174,18 @@ get_cached_data (app_t app, int tag, } /* No, cache it. */ - if (!app->app_local) - app->app_local = xtrycalloc (1, sizeof *app->app_local); - /* Note that we can safely ignore out of core errors. */ - if (app->app_local) + for (c=app->app_local->cache; c; c = c->next) + assert (c->tag != tag); + + c = xtrymalloc (sizeof *c + len); + if (c) { - for (c=app->app_local->cache; c; c = c->next) - assert (c->tag != tag); - - c = xtrymalloc (sizeof *c + len); - if (c) - { - memcpy (c->data, p, len); - c->length = len; - c->tag = tag; - c->next = app->app_local->cache; - app->app_local->cache = c; - } + memcpy (c->data, p, len); + c->length = len; + c->tag = tag; + c->next = app->app_local->cache; + app->app_local->cache = c; } return 0; @@ -202,7 +211,9 @@ flush_cache_item (app_t app, int tag) xfree (c); for (c=app->app_local->cache; c ; c = c->next) - assert (c->tag != tag); /* Oops: duplicated entry. */ + { + assert (c->tag != tag); /* Oops: duplicated entry. */ + } return; } @@ -262,6 +273,15 @@ get_one_do (app_t app, int tag, unsigned char **result, size_t *nbytes) for (i=0; data_objects[i].tag && data_objects[i].tag != tag; i++) ; + if (app->card_version > 0x0100 && data_objects[i].get_immediate_in_v11) + { + if( iso7816_get_data (app->slot, tag, &buffer, &buflen)) + return NULL; + *result = buffer; + *nbytes = buflen; + return buffer; + } + value = NULL; rc = -1; if (data_objects[i].tag && data_objects[i].get_from) @@ -428,7 +448,6 @@ store_fpr (int slot, int keynumber, u32 timestamp, *p++ = nbits; memcpy (p, e, elen); p += elen; - log_printhex ("fprbuf:", buffer, n+3); gcry_md_hash_buffer (GCRY_MD_SHA1, fpr, buffer, n+3); xfree (buffer); @@ -436,7 +455,22 @@ store_fpr (int slot, int keynumber, u32 timestamp, rc = iso7816_put_data (slot, (card_version > 0x0007? 0xC7 : 0xC6) + keynumber, fpr, 20); if (rc) - log_error ("failed to store the fingerprint: %s\n",gpg_strerror (rc)); + log_error (_("failed to store the fingerprint: %s\n"),gpg_strerror (rc)); + + if (!rc && card_version > 0x0100) + { + unsigned char buf[4]; + + buf[0] = timestamp >> 24; + buf[1] = timestamp >> 16; + buf[2] = timestamp >> 8; + buf[3] = timestamp; + + rc = iso7816_put_data (slot, 0xCE + keynumber, buf, 4); + if (rc) + log_error (_("failed to store the creation date: %s\n"), + gpg_strerror (rc)); + } return rc; } @@ -502,6 +536,7 @@ do_getattr (APP app, CTRL ctrl, const char *name) { "SIG-COUNTER", 0x0093, 2 }, { "SERIALNO", 0x004F, -1 }, { "AID", 0x004F }, + { "EXTCAP", 0x0000, -2 }, { NULL, 0 } }; int idx, i; @@ -536,6 +571,18 @@ do_getattr (APP app, CTRL ctrl, const char *name) } return 0; } + if (table[idx].special == -2) + { + char tmp[50]; + + sprintf (tmp, "gc=%d ki=%d fc=%d pd=%d", + app->app_local->extcap.get_challenge, + app->app_local->extcap.key_import, + app->app_local->extcap.change_force_chv, + app->app_local->extcap.private_dos); + send_status_info (ctrl, table[idx].name, tmp, strlen (tmp), NULL, 0); + return 0; + } relptr = get_one_do (app, table[idx].tag, &value, &valuelen); if (relptr) @@ -575,6 +622,7 @@ do_getattr (APP app, CTRL ctrl, const char *name) static int do_learn_status (APP app, CTRL ctrl) { + do_getattr (app, ctrl, "EXTCAP"); do_getattr (app, ctrl, "DISP-NAME"); do_getattr (app, ctrl, "DISP-LANG"); do_getattr (app, ctrl, "DISP-SEX"); @@ -605,13 +653,14 @@ verify_chv2 (app_t app, rc = pincb (pincb_arg, "PIN", &pinvalue); if (rc) { - log_info ("PIN callback returned error: %s\n", gpg_strerror (rc)); + log_info (_("PIN callback returned error: %s\n"), gpg_strerror (rc)); return rc; } if (strlen (pinvalue) < 6) { - log_error ("prassphrase (CHV2) is too short; minimum length is 6\n"); + log_error (_("prassphrase (CHV%d) is too short;" + " minimum length is %d\n"), 2, 6); xfree (pinvalue); return gpg_error (GPG_ERR_BAD_PIN); } @@ -619,7 +668,7 @@ verify_chv2 (app_t app, rc = iso7816_verify (app->slot, 0x82, pinvalue, strlen (pinvalue)); if (rc) { - log_error ("verify CHV2 failed: %s\n", gpg_strerror (rc)); + log_error (_("verify CHV%d failed: %s\n"), 2, gpg_strerror (rc)); xfree (pinvalue); flush_cache_after_error (app); return rc; @@ -633,7 +682,7 @@ verify_chv2 (app_t app, rc = gpg_error (GPG_ERR_PIN_NOT_SYNCED); if (rc) { - log_error ("verify CHV1 failed: %s\n", gpg_strerror (rc)); + log_error (_("verify CHV%d failed: %s\n"), 1, gpg_strerror (rc)); xfree (pinvalue); flush_cache_after_error (app); return rc; @@ -653,26 +702,54 @@ verify_chv3 (APP app, { int rc = 0; +#if GNUPG_MAJOR_VERSION != 1 if (!opt.allow_admin) { - log_info ("access to admin commands is not configured\n"); + log_info (_("access to admin commands is not configured\n")); return gpg_error (GPG_ERR_EACCES); } +#endif if (!app->did_chv3) { char *pinvalue; + void *relptr; + unsigned char *value; + size_t valuelen; + int reread_chv_status; + - rc = pincb (pincb_arg, "Admin PIN", &pinvalue); + relptr = get_one_do (app, 0x00C4, &value, &valuelen); + if (!relptr || valuelen < 7) + { + log_error (_("error retrieving CHV status from card\n")); + xfree (relptr); + return gpg_error (GPG_ERR_CARD); + } + if (value[6] == 0) + { + log_info (_("card is permanently locked!\n")); + xfree (relptr); + return gpg_error (GPG_ERR_BAD_PIN); + } + + reread_chv_status = (value[6] < 3); + + log_info(_("%d Admin PIN attempts remaining before card" + " is permanently locked\n"), value[6]); + xfree (relptr); + + rc = pincb (pincb_arg, _("Admin PIN"), &pinvalue); if (rc) { - log_info ("PIN callback returned error: %s\n", gpg_strerror (rc)); + log_info (_("PIN callback returned error: %s\n"), gpg_strerror (rc)); return rc; } if (strlen (pinvalue) < 6) { - log_error ("prassphrase (CHV3) is too short; minimum length is 6\n"); + log_error (_("prassphrase (CHV%d) is too short;" + " minimum length is %d\n"), 3, 6); xfree (pinvalue); return gpg_error (GPG_ERR_BAD_PIN); } @@ -681,11 +758,18 @@ verify_chv3 (APP app, xfree (pinvalue); if (rc) { - log_error ("verify CHV3 failed: %s\n", gpg_strerror (rc)); + log_error (_("verify CHV%d failed: %s\n"), 3, gpg_strerror (rc)); flush_cache_after_error (app); return rc; } app->did_chv3 = 1; + /* If the PIN has been entered wrongly before, we need to flush + the cached value so that the next read correctly reflects the + resetted retry counter. Note that version 1.1 of the specs + allow direct reading of that DO, so that we could actually + flush it in all cases. */ + if (reread_chv_status) + flush_cache_item (app, 0x00C4); } return rc; } @@ -1149,7 +1233,8 @@ do_sign (APP app, const char *keyidstr, int hashalgo, if (strlen (pinvalue) < 6) { - log_error ("prassphrase (CHV1) is too short; minimum length is 6\n"); + log_error (_("prassphrase (CHV%d) is too short;" + " minimum length is %d\n"), 1, 6); xfree (pinvalue); return gpg_error (GPG_ERR_BAD_PIN); } @@ -1157,7 +1242,7 @@ do_sign (APP app, const char *keyidstr, int hashalgo, rc = iso7816_verify (app->slot, 0x81, pinvalue, strlen (pinvalue)); if (rc) { - log_error ("verify CHV1 failed\n"); + log_error (_("verify CHV%d failed: %s\n"), 1, gpg_strerror (rc)); xfree (pinvalue); flush_cache_after_error (app); return rc; @@ -1171,7 +1256,7 @@ do_sign (APP app, const char *keyidstr, int hashalgo, rc = gpg_error (GPG_ERR_PIN_NOT_SYNCED); if (rc) { - log_error ("verify CHV2 failed\n"); + log_error (_("verify CHV%d failed: %s\n"), 2, gpg_strerror (rc)); xfree (pinvalue); flush_cache_after_error (app); return rc; @@ -1375,11 +1460,14 @@ app_select_openpgp (APP app) rc = iso7816_select_application (slot, aid, sizeof aid); if (!rc) { + unsigned int manufacturer; + app->apptype = "OPENPGP"; app->did_chv1 = 0; app->did_chv2 = 0; app->did_chv3 = 0; + app->app_local = NULL; /* The OpenPGP card returns the serial number as part of the AID; because we prefer to use OpenPGP serial numbers, we @@ -1391,33 +1479,57 @@ app_select_openpgp (APP app) goto leave; if (opt.verbose) { - log_info ("got AID: "); + log_info ("AID: "); log_printhex ("", buffer, buflen); } -#if GNUPG_MAJOR_VERSION != 1 - /* A valid OpenPGP card should never need this but well the test - is cheap. */ - rc = app_munge_serialno (app); - if (rc) - goto leave; -#endif app->card_version = buffer[6] << 8; app->card_version |= buffer[7]; + manufacturer = (buffer[8]<<8 | buffer[9]); + xfree (app->serialno); app->serialno = buffer; app->serialnolen = buflen; buffer = NULL; + app->app_local = xtrycalloc (1, sizeof *app->app_local); + if (!app->app_local) + { + rc = gpg_error (gpg_err_code_from_errno (errno)); + goto leave; + } relptr = get_one_do (app, 0x00C4, &buffer, &buflen); if (!relptr) { - log_error ("can't access CHV Status Bytes - invalid OpenPGP card?\n"); + log_error (_("can't access CHV Status Bytes " + "- invalid OpenPGP card?\n")); goto leave; } app->force_chv1 = (buflen && *buffer == 0); xfree (relptr); - + + relptr = get_one_do (app, 0x00C0, &buffer, &buflen); + if (!relptr) + { + log_error (_("can't access Extended Capability Flags - " + "invalid OpenPGP card?\n")); + goto leave; + } + if (buflen) + { + app->app_local->extcap.get_challenge = !!(*buffer & 0x40); + app->app_local->extcap.key_import = !!(*buffer & 0x20); + app->app_local->extcap.change_force_chv = !!(*buffer & 0x10); + app->app_local->extcap.private_dos = !!(*buffer & 0x08); + } + xfree (relptr); + + /* Some of the first cards accidently don't set the + CHANGE_FORCE_CHV bit but allow it anyway. */ + if (app->card_version <= 0x0100 && manufacturer == 1) + app->app_local->extcap.change_force_chv = 1; + + if (opt.verbose > 1) dump_all_do (slot); @@ -1435,6 +1547,8 @@ app_select_openpgp (APP app) } leave: + if (rc) + do_deinit (app); return rc; } @@ -1467,7 +1581,8 @@ app_openpgp_cardinfo (APP app, rc = app_get_serial_and_stamp (app, serialno, &dummy); if (rc) { - log_error ("error getting serial number: %s\n", gpg_strerror (rc)); + log_error (_("error getting serial number: %s\n"), + gpg_strerror (rc)); return rc; } } @@ -1554,13 +1669,14 @@ app_openpgp_storekey (APP app, int keyno, if (rc) goto leave; + flush_cache (app); rc = iso7816_put_data (app->slot, (app->card_version > 0x0007? 0xE0 : 0xE9) + keyno, template, template_len); if (rc) { - log_error ("failed to store the key: rc=%s\n", gpg_strerror (rc)); + log_error (_("failed to store the key: %s\n"), gpg_strerror (rc)); rc = gpg_error (GPG_ERR_CARD); goto leave; } @@ -1602,14 +1718,14 @@ app_openpgp_readkey (APP app, int keyno, unsigned char **m, size_t *mlen, if (rc) { rc = gpg_error (GPG_ERR_CARD); - log_error ("reading key failed\n"); + log_error (_("reading the key failed\n")); goto leave; } keydata = find_tlv (buffer, buflen, 0x7F49, &keydatalen); if (!keydata) { - log_error ("response does not contain the public key data\n"); + log_error (_("response does not contain the public key data\n")); rc = gpg_error (GPG_ERR_CARD); goto leave; } @@ -1617,7 +1733,7 @@ app_openpgp_readkey (APP app, int keyno, unsigned char **m, size_t *mlen, a = find_tlv (keydata, keydatalen, 0x0081, &alen); if (!a) { - log_error ("response does not contain the RSA modulus\n"); + log_error (_("response does not contain the RSA modulus\n")); rc = gpg_error (GPG_ERR_CARD); goto leave; } @@ -1628,7 +1744,7 @@ app_openpgp_readkey (APP app, int keyno, unsigned char **m, size_t *mlen, a = find_tlv (keydata, keydatalen, 0x0082, &alen); if (!a) { - log_error ("response does not contain the RSA public exponent\n"); + log_error (_("response does not contain the RSA public exponent\n")); rc = gpg_error (GPG_ERR_CARD); goto leave; } diff --git a/sm/ChangeLog b/sm/ChangeLog index 2391deb18..28a397182 100644 --- a/sm/ChangeLog +++ b/sm/ChangeLog @@ -1,3 +1,8 @@ +2004-09-30 Werner Koch + + * keylist.c (list_cert_colon): Make sure that the expired flag has + a higher precedence than the invalid flag. + 2004-09-29 Werner Koch * import.c (parse_p12): Write an error status line for bad diff --git a/sm/keylist.c b/sm/keylist.c index 0c8ebd33e..e9985f3ec 100644 --- a/sm/keylist.c +++ b/sm/keylist.c @@ -333,6 +333,9 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity, fputs (have_secret? "crs:":"crt:", fp); + + /* Note: We can't use multiple flags, like "ei", because the + validation check does only return one error. */ truststring[0] = 0; truststring[1] = 0; if ((validity & VALIDITY_REVOKED) @@ -340,8 +343,6 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity, *truststring = 'r'; else if (gpg_err_code (valerr) == GPG_ERR_CERT_EXPIRED) *truststring = 'e'; - else if (valerr) - *truststring = 'i'; else { /* Lets also check whether the certificate under question @@ -354,6 +355,8 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity, && !ksba_cert_get_validity (cert, 1, not_after) && *not_after && strcmp (current_time, not_after) > 0 ) *truststring = 'e'; + else if (valerr) + *truststring = 'i'; } /* Is we have no truststring yet (i.e. the certificate might be -- cgit From e1f3dc1c77fe155b05f106c1711bce1e5b62c9b6 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 14 Oct 2004 09:12:36 +0000 Subject: Added ID keywords because these files are often used in other packages. --- scd/apdu.c | 2 ++ scd/apdu.h | 2 ++ scd/app-common.h | 2 ++ scd/app-openpgp.c | 2 ++ scd/ccid-driver.c | 2 ++ scd/ccid-driver.h | 2 ++ scd/iso7816.c | 13 +++++++++++++ scd/iso7816.h | 4 ++++ 8 files changed, 29 insertions(+) (limited to 'scd/app-openpgp.c') diff --git a/scd/apdu.c b/scd/apdu.c index fceb4f396..0d9ef3d0c 100644 --- a/scd/apdu.c +++ b/scd/apdu.c @@ -16,6 +16,8 @@ * 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 + * + * $Id$ */ #include diff --git a/scd/apdu.h b/scd/apdu.h index f31e42e3d..e0f50b72b 100644 --- a/scd/apdu.h +++ b/scd/apdu.h @@ -16,6 +16,8 @@ * 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 + * + * $Id$ */ #ifndef APDU_H diff --git a/scd/app-common.h b/scd/app-common.h index c15f174bf..f54f6da92 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -16,6 +16,8 @@ * 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 + * + * $Id$ */ #ifndef GNUPG_SCD_APP_COMMON_H diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 6f9837c90..86c907d1d 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -16,6 +16,8 @@ * 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 + * + * $Id$ */ #include diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c index 287a8d87d..0a876f0bc 100644 --- a/scd/ccid-driver.c +++ b/scd/ccid-driver.c @@ -51,6 +51,8 @@ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id$ */ diff --git a/scd/ccid-driver.h b/scd/ccid-driver.h index 9cb23253b..82feed5c9 100644 --- a/scd/ccid-driver.h +++ b/scd/ccid-driver.h @@ -50,6 +50,8 @@ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id$ */ #ifndef CCID_DRIVER_H diff --git a/scd/iso7816.c b/scd/iso7816.c index cbb314eb2..4861466c1 100644 --- a/scd/iso7816.c +++ b/scd/iso7816.c @@ -16,6 +16,8 @@ * 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 + * + * $Id$ */ #include @@ -103,6 +105,17 @@ map_sw (int sw) return gpg_error (ec); } +/* Map a status word from the APDU layer to a gpg-error code. */ +gpg_error_t +iso7816_map_sw (int sw) +{ + /* All APDU functions should return 0x9000 on success but for + historical reasons of the implementation some return 0 to + indicate success. We allow for that here. */ + return sw? map_sw (sw) : 0; +} + + /* This function is specialized version of the SELECT FILE command. SLOT is the card and reader as created for example by apdu_open_reader (), AID is a buffer of size AIDLEN holding the diff --git a/scd/iso7816.h b/scd/iso7816.h index 8f2b150e6..b9ba1800b 100644 --- a/scd/iso7816.h +++ b/scd/iso7816.h @@ -16,6 +16,8 @@ * 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 + * + * $Id$ */ #ifndef ISO7816_H @@ -25,6 +27,8 @@ #include "cardglue.h" #endif +gpg_error_t iso7816_map_sw (int sw); + gpg_error_t iso7816_select_application (int slot, const char *aid, size_t aidlen); gpg_error_t iso7816_select_file (int slot, int tag, int is_dir, -- cgit From 2c31e2f8536487416ea6d5f4fda9e22361086bae Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 14 Oct 2004 13:22:03 +0000 Subject: (parse_login_data): New. (app_select_openpgp): Call it. (do_setattr): Reparse it after change. --- scd/ChangeLog | 6 +++ scd/app-openpgp.c | 135 ++++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 112 insertions(+), 29 deletions(-) (limited to 'scd/app-openpgp.c') diff --git a/scd/ChangeLog b/scd/ChangeLog index 60311e705..7fbc524b3 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,9 @@ +2004-10-14 Werner Koch + + * app-openpgp.c (parse_login_data): New. + (app_select_openpgp): Call it. + (do_setattr): Reparse it after change. + 2004-10-06 Werner Koch * ccid-driver.c (ccid_open_reader): Store the vendor ID. diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 86c907d1d..d6cbe88a6 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -101,6 +101,11 @@ struct app_local_s { unsigned int change_force_chv:1; unsigned int private_dos:1; } extcap; + struct + { + unsigned int no_sync:1; /* Do not sync CHV1 and CHV2 */ + unsigned int def_chv2:1; /* Use 123456 for CHV2. */ + } flags; }; @@ -411,6 +416,75 @@ count_bits (const unsigned char *a, size_t len) return n; } +/* GnuPG makes special use of the login-data DO, this fucntion parses + the login data to store the flags for later use. It may be called + at any time and should be called after changing the login-data DO. + + Everything up to a LF is considered a mailbox or account name. If + the first LF is follewed by DC4 (0x14) control sequence are + expected up to the next LF. Control sequences are separated by FS + (0x28) and consist of key=value pairs. There is one key defined: + + F= + + Were FLAGS is a plain hexadecimal number representing flag values. + The lsb is here the rightmost bit. Defined flags bits are: + + Bit 0 = CHV1 and CHV2 are not syncronized + Bit 1 = CHV2 has been been set to the default PIN of "123456" + (this implies that bit 0 is also set). + +*/ +static void +parse_login_data (app_t app) +{ + unsigned char *buffer, *p; + size_t buflen, len; + void *relptr; + + /* Set defaults. */ + app->app_local->flags.no_sync = 0; + app->app_local->flags.def_chv2 = 0; + + /* Read the DO. */ + relptr = get_one_do (app, 0x005E, &buffer, &buflen); + if (!relptr) + return; /* Ooops. */ + for (; buflen; buflen--, buffer++) + if (*buffer == '\n') + break; + if (buflen < 2 || buffer[1] != '\x14') + return; /* No control sequences. */ + buflen--; + buffer++; + do + { + buflen--; + buffer++; + if (buflen > 1 && *buffer == 'F' && buffer[1] == '=') + { + /* Flags control sequence found. */ + int lastdig = 0; + + /* For now we are only interested in the last digit, so skip + any leading digits but bail out on invalid characters. */ + for (p=buffer+2, len = buflen-2; len && hexdigitp (p); p++, len--) + lastdig = xtoi_1 (p); + if (len && !(*p == '\n' || *p == '\x18')) + goto next; /* Invalid characters in field. */ + app->app_local->flags.no_sync = !!(lastdig & 1); + app->app_local->flags.def_chv2 = (lastdig & 3) == 3; + } + next: + for (; buflen && *buffer != '\x18'; buflen--, buffer++) + if (*buffer == '\n') + buflen = 1; + } + while (buflen); + + xfree (relptr); +} + /* Note, that FPR must be at least 20 bytes. */ static int store_fpr (int slot, int keynumber, u32 timestamp, @@ -479,7 +553,7 @@ store_fpr (int slot, int keynumber, u32 timestamp, static void -send_fpr_if_not_null (CTRL ctrl, const char *keyword, +send_fpr_if_not_null (ctrl_t ctrl, const char *keyword, int number, const unsigned char *fpr) { int i; @@ -502,7 +576,7 @@ send_fpr_if_not_null (CTRL ctrl, const char *keyword, } static void -send_key_data (CTRL ctrl, const char *name, +send_key_data (ctrl_t ctrl, const char *name, const unsigned char *a, size_t alen) { char *p, *buf = xmalloc (alen*2+1); @@ -520,7 +594,7 @@ send_key_data (CTRL ctrl, const char *name, /* Implement the GETATTR command. This is similar to the LEARN command but returns just one value via the status interface. */ static int -do_getattr (APP app, CTRL ctrl, const char *name) +do_getattr (app_t app, ctrl_t ctrl, const char *name) { static struct { const char *name; @@ -622,7 +696,7 @@ do_getattr (APP app, CTRL ctrl, const char *name) static int -do_learn_status (APP app, CTRL ctrl) +do_learn_status (app_t app, ctrl_t ctrl) { do_getattr (app, ctrl, "EXTCAP"); do_getattr (app, ctrl, "DISP-NAME"); @@ -661,7 +735,7 @@ verify_chv2 (app_t app, if (strlen (pinvalue) < 6) { - log_error (_("prassphrase (CHV%d) is too short;" + log_error (_("PIN for CHV%d is too short;" " minimum length is %d\n"), 2, 6); xfree (pinvalue); return gpg_error (GPG_ERR_BAD_PIN); @@ -698,7 +772,7 @@ verify_chv2 (app_t app, /* Verify CHV3 if required. */ static int -verify_chv3 (APP app, +verify_chv3 (app_t app, int (*pincb)(void*, const char *, char **), void *pincb_arg) { @@ -780,7 +854,7 @@ verify_chv3 (APP app, /* Handle the SETATTR operation. All arguments are already basically checked. */ static int -do_setattr (APP app, const char *name, +do_setattr (app_t app, const char *name, int (*pincb)(void*, const char *, char **), void *pincb_arg, const unsigned char *value, size_t valuelen) @@ -793,7 +867,7 @@ do_setattr (APP app, const char *name, int special; } table[] = { { "DISP-NAME", 0x005B }, - { "LOGIN-DATA", 0x005E }, + { "LOGIN-DATA", 0x005E, 2 }, { "DISP-LANG", 0x5F2D }, { "DISP-SEX", 0x5F35 }, { "PUBKEY-URL", 0x5F50 }, @@ -824,6 +898,8 @@ do_setattr (APP app, const char *name, if (table[idx].special == 1) app->force_chv1 = (valuelen && *value == 0); + else if (table[idx].special == 2) + parse_login_data (app); return rc; } @@ -831,7 +907,7 @@ do_setattr (APP app, const char *name, /* Handle the PASSWD command. */ static int -do_change_pin (APP app, CTRL ctrl, const char *chvnostr, int reset_mode, +do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, int reset_mode, int (*pincb)(void*, const char *, char **), void *pincb_arg) { @@ -918,7 +994,7 @@ do_change_pin (APP app, CTRL ctrl, const char *chvnostr, int reset_mode, /* Handle the GENKEY command. */ static int -do_genkey (APP app, CTRL ctrl, const char *keynostr, unsigned int flags, +do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags, int (*pincb)(void*, const char *, char **), void *pincb_arg) { @@ -1060,7 +1136,7 @@ convert_sig_counter_value (const unsigned char *value, size_t valuelen) } static unsigned long -get_sig_counter (APP app) +get_sig_counter (app_t app) { void *relptr; unsigned char *value; @@ -1076,7 +1152,7 @@ get_sig_counter (APP app) } static int -compare_fingerprint (APP app, int keyno, unsigned char *sha1fpr) +compare_fingerprint (app_t app, int keyno, unsigned char *sha1fpr) { const unsigned char *fpr; unsigned char *buffer; @@ -1116,7 +1192,7 @@ compare_fingerprint (APP app, int keyno, unsigned char *sha1fpr) known to gpg was not updated. If there is no fingerprint we assume that this is okay. */ static int -check_against_given_fingerprint (APP app, const char *fpr, int keyno) +check_against_given_fingerprint (app_t app, const char *fpr, int keyno) { unsigned char tmp[20]; const char *s; @@ -1147,7 +1223,7 @@ check_against_given_fingerprint (APP app, const char *fpr, int keyno) not match the one required for the requested action (e.g. the serial number does not match). */ static int -do_sign (APP app, const char *keyidstr, int hashalgo, +do_sign (app_t app, const char *keyidstr, int hashalgo, int (*pincb)(void*, const char *, char **), void *pincb_arg, const void *indata, size_t indatalen, @@ -1222,20 +1298,20 @@ do_sign (APP app, const char *keyidstr, int hashalgo, { char *prompt; - if (asprintf (&prompt, "PIN [sigs done: %lu]", sigcount) < 0) + if (asprintf (&prompt, _("PIN [sigs done: %lu]"), sigcount) < 0) return gpg_error_from_errno (errno); rc = pincb (pincb_arg, prompt, &pinvalue); free (prompt); } if (rc) { - log_info ("PIN callback returned error: %s\n", gpg_strerror (rc)); + log_info (_("PIN callback returned error: %s\n"), gpg_strerror (rc)); return rc; } if (strlen (pinvalue) < 6) { - log_error (_("prassphrase (CHV%d) is too short;" + log_error (_("PIN for CHV%d is too short;" " minimum length is %d\n"), 1, 6); xfree (pinvalue); return gpg_error (GPG_ERR_BAD_PIN); @@ -1282,7 +1358,7 @@ do_sign (APP app, const char *keyidstr, int hashalgo, not match the one required for the requested action (e.g. the serial number does not match). */ static int -do_auth (APP app, const char *keyidstr, +do_auth (app_t app, const char *keyidstr, int (*pincb)(void*, const char *, char **), void *pincb_arg, const void *indata, size_t indatalen, @@ -1341,7 +1417,7 @@ do_auth (APP app, const char *keyidstr, static int -do_decipher (APP app, const char *keyidstr, +do_decipher (app_t app, const char *keyidstr, int (pincb)(void*, const char *, char **), void *pincb_arg, const void *indata, size_t indatalen, @@ -1403,7 +1479,7 @@ do_decipher (APP app, const char *keyidstr, dangerous CHV3. KEYIDSTR is the usual card's serial number; an optional fingerprint part will be ignored. */ static int -do_check_pin (APP app, const char *keyidstr, +do_check_pin (app_t app, const char *keyidstr, int (pincb)(void*, const char *, char **), void *pincb_arg) { @@ -1450,7 +1526,7 @@ do_check_pin (APP app, const char *keyidstr, /* Select the OpenPGP application on the card in SLOT. This function must be used before any other OpenPGP application functions. */ int -app_select_openpgp (APP app) +app_select_openpgp (app_t app) { static char const aid[] = { 0xD2, 0x76, 0x00, 0x01, 0x24, 0x01 }; int slot = app->slot; @@ -1503,8 +1579,8 @@ app_select_openpgp (APP app) relptr = get_one_do (app, 0x00C4, &buffer, &buflen); if (!relptr) { - log_error (_("can't access CHV Status Bytes " - "- invalid OpenPGP card?\n")); + log_error (_("can't access %s - invalid OpenPGP card?\n"), + "CHV Status Bytes"); goto leave; } app->force_chv1 = (buflen && *buffer == 0); @@ -1513,8 +1589,8 @@ app_select_openpgp (APP app) relptr = get_one_do (app, 0x00C0, &buffer, &buflen); if (!relptr) { - log_error (_("can't access Extended Capability Flags - " - "invalid OpenPGP card?\n")); + log_error (_("can't access %s - invalid OpenPGP card?\n"), + "Extended Capability Flags" ); goto leave; } if (buflen) @@ -1531,6 +1607,7 @@ app_select_openpgp (APP app) if (app->card_version <= 0x0100 && manufacturer == 1) app->app_local->extcap.change_force_chv = 1; + parse_login_data (app); if (opt.verbose > 1) dump_all_do (slot); @@ -1562,7 +1639,7 @@ leave: buffers or NULL if the data object is not available. All returned values are sanitized. */ int -app_openpgp_cardinfo (APP app, +app_openpgp_cardinfo (app_t app, char **serialno, char **disp_name, char **pubkey_url, @@ -1644,7 +1721,7 @@ app_openpgp_cardinfo (APP app, /* This function is currently only used by the sc-copykeys program to - store a key on the smartcard. APP ist the application handle, + store a key on the smartcard. app_t ist the application handle, KEYNO is the number of the key and PINCB, PINCB_ARG are used to ask for the SO PIN. TEMPLATE and TEMPLATE_LEN describe a buffer with the key template to store. CREATED_AT is the timestamp used to @@ -1652,7 +1729,7 @@ app_openpgp_cardinfo (APP app, RSA public exponent. This function silently overwrites an existing key.*/ int -app_openpgp_storekey (APP app, int keyno, +app_openpgp_storekey (app_t app, int keyno, unsigned char *template, size_t template_len, time_t created_at, const unsigned char *m, size_t mlen, @@ -1697,7 +1774,7 @@ app_openpgp_storekey (APP app, int keyno, /* Utility function for external tools: Read the public RSA key at KEYNO and return modulus and exponent in (M,MLEN) and (E,ELEN). */ int -app_openpgp_readkey (APP app, int keyno, unsigned char **m, size_t *mlen, +app_openpgp_readkey (app_t app, int keyno, unsigned char **m, size_t *mlen, unsigned char **e, size_t *elen) { int rc; -- cgit From 9aa7d0bc353daa9728bfb69a6e775ddc82075f87 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 22 Oct 2004 09:41:56 +0000 Subject: * app-openpgp.c (do_sign): Replace asprintf by direct allocation. This avoids problems with missing vasprintf implementations in gnupg 1.4. * app-common.h (app_openpgp_storekey: Add prototype. --- scd/ChangeLog | 8 ++++++++ scd/app-common.h | 7 +++++++ scd/app-openpgp.c | 9 +++++++-- 3 files changed, 22 insertions(+), 2 deletions(-) (limited to 'scd/app-openpgp.c') diff --git a/scd/ChangeLog b/scd/ChangeLog index eba39c731..32fbdf9d9 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,11 @@ +2004-10-21 Werner Koch + + * app-openpgp.c (do_sign): Replace asprintf by direct allocation. + This avoids problems with missing vasprintf implementations in + gnupg 1.4. + + * app-common.h (app_openpgp_storekey: Add prototype. + 2004-10-20 Werner Koch * sc-investigate: Removed. diff --git a/scd/app-common.h b/scd/app-common.h index f54f6da92..48bd349f4 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -88,6 +88,13 @@ struct app_ctx_s { #if GNUPG_MAJOR_VERSION == 1 int app_select_openpgp (app_t app); int app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp); +int app_openpgp_storekey (app_t app, int keyno, + unsigned char *template, size_t template_len, + time_t created_at, + const unsigned char *m, size_t mlen, + const unsigned char *e, size_t elen, + int (*pincb)(void*, const char *, char **), + void *pincb_arg); #else /*-- app-help.c --*/ gpg_error_t app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip); diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index d6cbe88a6..f73b4f946 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -824,7 +824,7 @@ verify_chv3 (app_t app, if (strlen (pinvalue) < 6) { - log_error (_("prassphrase (CHV%d) is too short;" + log_error (_("passphrase (CHV%d) is too short;" " minimum length is %d\n"), 3, 6); xfree (pinvalue); return gpg_error (GPG_ERR_BAD_PIN); @@ -1298,10 +1298,15 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, { char *prompt; - if (asprintf (&prompt, _("PIN [sigs done: %lu]"), sigcount) < 0) +#define PROMPTSTRING _("PIN [sigs done: %lu]") + + prompt = malloc (strlen (PROMPTSTRING) + 50); + if (!prompt) return gpg_error_from_errno (errno); + sprintf (prompt, PROMPTSTRING, sigcount); rc = pincb (pincb_arg, prompt, &pinvalue); free (prompt); +#undef PROMPTSTRING } if (rc) { -- cgit From 17c2c406016e51a6ecce5bd139d0c8e81ee07ec8 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 22 Oct 2004 16:03:04 +0000 Subject: Compile fixes. --- ChangeLog | 4 ++ Makefile.am | 3 +- NEWS | 6 ++- g10/ChangeLog | 9 ++++ g10/card-util.c | 30 +++++++++-- g10/g10.c | 8 ++- g10/main.h | 2 +- po/ChangeLog | 4 ++ po/POTFILES.in | 1 - po/de.po | 149 ++++++++++++++++++++++++++++-------------------------- scd/ChangeLog | 5 ++ scd/app-openpgp.c | 6 +-- tools/Makefile.am | 2 +- 13 files changed, 142 insertions(+), 87 deletions(-) (limited to 'scd/app-openpgp.c') diff --git a/ChangeLog b/ChangeLog index 0e83541c8..1a51c9557 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2004-10-22 Werner Koch + + * Makefile.am (AUTOMAKE_OPTIONS): Set option to create bzip2 tarball. + 2004-10-01 Werner Koch Released 1.9.11. diff --git a/Makefile.am b/Makefile.am index 9be193353..08d025abf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,5 +1,5 @@ # Makefile.am - main makefile for NewPG/GnuPG -# Copyright (C) 2001 Free Software Foundation, Inc. +# Copyright (C) 2001, 2004 Free Software Foundation, Inc. # # This file is part of GnuPG. # @@ -20,6 +20,7 @@ ## Process this file with automake to produce Makefile.in ACLOCAL_AMFLAGS = -I m4 +AUTOMAKE_OPTIONS = dist-bzip2 EXTRA_DIST = scripts/config.rpath autogen.sh README.CVS DISTCLEANFILES = g10defs.h diff --git a/NEWS b/NEWS index 9ba9ddac9..b48546877 100644 --- a/NEWS +++ b/NEWS @@ -3,8 +3,10 @@ Noteworthy changes in version 1.9.12 * [scdaemon] Partly rewrote the PC/SC code. - * Removed the sc-investigate tool. It is now in the separate - gscutils package. + * Removed the sc-investigate tool. It is now in a separate package + available at ftp://ftp.g10code.com/g10code/gscutils/ . + + * [gpg-agent] Fixed logging problem. Noteworthy changes in version 1.9.11 (2004-10-01) diff --git a/g10/ChangeLog b/g10/ChangeLog index 36d5e3314..01bbf649d 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,12 @@ +2004-10-22 Werner Koch + + * g10.c (main): Display a bit fat warning that this gpg should not + be used. + + * card-util.c (fetch_url): Disable for gnupg 1.9 + (card_generate_subkey): Ditto. + (card_store_subkey): Ditto. + 2004-09-30 Werner Koch * gpgv.c (i18n_init): Always use LC_ALL. diff --git a/g10/card-util.c b/g10/card-util.c index 1d2e47ea2..1ff57ade5 100644 --- a/g10/card-util.c +++ b/g10/card-util.c @@ -523,6 +523,7 @@ change_url (void) static int fetch_url(void) { +#if GNUPG_MAJOR_VERSION == 1 int rc; struct agent_card_info_s info; @@ -560,6 +561,9 @@ fetch_url(void) log_error("no URL set on card\n"); return rc; +#else + return 0; +#endif } @@ -577,12 +581,14 @@ change_login (const char *args) for (args++; spacep (args); args++) ; fp = fopen (args, "rb"); +#if GNUPG_MAJOR_VERSION == 1 if (fp && is_secured_file (fileno (fp))) { fclose (fp); fp = NULL; errno = EPERM; } +#endif if (!fp) { tty_printf (_("can't open `%s': %s\n"), args, strerror (errno)); @@ -839,6 +845,7 @@ restore_forced_chv1 (int *forced_chv1) } } +#if GNUPG_MAJOR_VERSION == 1 /* Helper for the key generation/edit functions. */ static void show_card_key_info (struct agent_card_info_s *info) @@ -851,8 +858,9 @@ show_card_key_info (struct agent_card_info_s *info) print_sha1_fpr (NULL, info->fpr3valid? info->fpr3:NULL); tty_printf ("\n"); } +#endif - +#if GNUPG_MAJOR_VERSION == 1 /* Helper for the key generation/edit functions. */ static int replace_existing_key_p (struct agent_card_info_s *info, int keyno) @@ -872,7 +880,7 @@ replace_existing_key_p (struct agent_card_info_s *info, int keyno) } return 0; } - +#endif static void @@ -895,10 +903,10 @@ generate_card_keys (const char *serialno) m_free(answer); } #else - /* Does 1.9 have answer_is_yes_no_default() ? */ - want_backup = !(cpr_get_answer_is_yes + want_backup = cpr_get_answer_is_yes ( "cardedit.genkeys.backup_enc", - _("Inhibit off-card backup of encryption key? (y/N) "))); + _("Make off-card backup of encryption key? (Y/n) ")); + /*FIXME: we need answer_is_yes_no_default()*/ #endif if ( (info.fpr1valid && !fpr_is_zero (info.fpr1)) @@ -928,8 +936,12 @@ generate_card_keys (const char *serialno) if (check_pin_for_key_operation (&info, &forced_chv1)) goto leave; +#if GNUPG_MAJOR_VERSION == 1 generate_keypair (NULL, info.serialno, want_backup? opt.homedir:NULL); +#else + generate_keypair (NULL, info.serialno); +#endif leave: agent_release_card_info (&info); @@ -942,6 +954,7 @@ generate_card_keys (const char *serialno) int card_generate_subkey (KBNODE pub_keyblock, KBNODE sec_keyblock) { +#if GNUPG_MAJOR_VERSION == 1 struct agent_card_info_s info; int okay = 0; int forced_chv1 = 0; @@ -988,6 +1001,9 @@ card_generate_subkey (KBNODE pub_keyblock, KBNODE sec_keyblock) agent_release_card_info (&info); restore_forced_chv1 (&forced_chv1); return okay; +#else + return 0; +#endif } @@ -997,6 +1013,7 @@ card_generate_subkey (KBNODE pub_keyblock, KBNODE sec_keyblock) int card_store_subkey (KBNODE node, int use) { +#if GNUPG_MAJOR_VERSION == 1 struct agent_card_info_s info; int okay = 0; int rc; @@ -1117,6 +1134,9 @@ card_store_subkey (KBNODE node, int use) free_secret_key (copied_sk); agent_release_card_info (&info); return okay; +#else + return 0; +#endif } diff --git a/g10/g10.c b/g10/g10.c index 915011026..039074f6b 100644 --- a/g10/g10.c +++ b/g10/g10.c @@ -2038,6 +2038,10 @@ main( int argc, char **argv ) } #endif + log_info ("WARNING: This version of gpg is not very matured and\n"); + log_info ("WARNING: only intended for testing. Please keep using\n"); + log_info ("WARNING: gpg 1.2.x, 1.3.x or 1.4.x for OpenPGP\n"); + /* FIXME: We should use the lggging to a file only in server mode; however we have not yet implemetyed that thus we try to get away with --batch as indication for logging to file required. */ @@ -2926,9 +2930,9 @@ main( int argc, char **argv ) case aChangePIN: if (!argc) - change_pin (0); + change_pin (0,1); else if (argc == 1) - change_pin ( atoi (*argv)); + change_pin ( atoi (*argv), 1); else wrong_args ("--change-pin [no]"); break; diff --git a/g10/main.h b/g10/main.h index 52bfa7659..939d12ded 100644 --- a/g10/main.h +++ b/g10/main.h @@ -259,7 +259,7 @@ int hash_datafiles( MD_HANDLE md, MD_HANDLE md2, void run_in_pipemode (void); /*-- card-util.c --*/ -void change_pin (int no); +void change_pin (int no, int allow_admin); void card_status (FILE *fp, char *serialnobuf, size_t serialnobuflen); void card_edit (STRLIST commands); diff --git a/po/ChangeLog b/po/ChangeLog index f1396acfc..cc20b6227 100644 --- a/po/ChangeLog +++ b/po/ChangeLog @@ -1,3 +1,7 @@ +2004-10-22 Werner Koch + + * POTFILES.in: Removed sc-investigate.c + 2004-10-04 Werner Koch * de.po: Typo fixes. diff --git a/po/POTFILES.in b/po/POTFILES.in index eb4e36c85..9ea9c3fd9 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -15,7 +15,6 @@ jnlib/logging.c kbx/kbxutil.c scd/scdaemon.c -scd/sc-investigate.c scd/app-openpgp.c sm/base64.c diff --git a/po/de.po b/po/de.po index 489164ff6..16d945418 100644 --- a/po/de.po +++ b/po/de.po @@ -10,8 +10,8 @@ msgid "" msgstr "" "Project-Id-Version: gnupg2 1.9.10\n" "Report-Msgid-Bugs-To: translations@gnupg.org\n" -"POT-Creation-Date: 2004-10-01 14:54+0200\n" -"PO-Revision-Date: 2004-10-04 13:48+0200\n" +"POT-Creation-Date: 2004-10-22 15:02+0200\n" +"PO-Revision-Date: 2004-10-22 15:02+0200\n" "Last-Translator: Werner Koch \n" "Language-Team: de\n" "MIME-Version: 1.0\n" @@ -100,12 +100,12 @@ msgid "allow clients to mark keys as \"trusted\"" msgstr "erlaube Aufrufern Schlüssel als \"vertrauenswürdig\" zu markieren" #: agent/gpg-agent.c:195 agent/protect-tool.c:134 scd/scdaemon.c:168 -#: scd/sc-investigate.c:113 sm/gpgsm.c:485 tools/gpgconf.c:85 +#: sm/gpgsm.c:485 tools/gpgconf.c:85 msgid "Please report bugs to <" msgstr "Fehlerberichte bitte an <" #: agent/gpg-agent.c:195 agent/protect-tool.c:134 scd/scdaemon.c:168 -#: scd/sc-investigate.c:113 sm/gpgsm.c:485 tools/gpgconf.c:85 +#: sm/gpgsm.c:485 tools/gpgconf.c:85 msgid ">.\n" msgstr ">.\n" @@ -126,48 +126,48 @@ msgstr "" msgid "invalid debug-level `%s' given\n" msgstr "ungültige Debugebene `%s' angegeben\n" -#: agent/gpg-agent.c:446 agent/protect-tool.c:1050 kbx/kbxutil.c:431 -#: scd/scdaemon.c:357 scd/sc-investigate.c:181 sm/gpgsm.c:726 +#: agent/gpg-agent.c:448 agent/protect-tool.c:1050 kbx/kbxutil.c:431 +#: scd/scdaemon.c:357 sm/gpgsm.c:726 #, c-format msgid "libgcrypt is too old (need %s, have %s)\n" msgstr "" "Die Bibliothek \"libgcrypt\" is zu alt (benötigt wird %s, vorhanden ist %s)\n" -#: agent/gpg-agent.c:519 scd/scdaemon.c:437 sm/gpgsm.c:824 +#: agent/gpg-agent.c:521 scd/scdaemon.c:437 sm/gpgsm.c:824 #, c-format msgid "NOTE: no default option file `%s'\n" msgstr "Notiz: Voreingestellte Konfigurationsdatei `%s' fehlt\n" -#: agent/gpg-agent.c:524 agent/gpg-agent.c:998 scd/scdaemon.c:442 +#: agent/gpg-agent.c:526 agent/gpg-agent.c:1000 scd/scdaemon.c:442 #: sm/gpgsm.c:828 #, c-format msgid "option file `%s': %s\n" msgstr "Konfigurationsdatei `%s': %s\n" -#: agent/gpg-agent.c:532 scd/scdaemon.c:450 sm/gpgsm.c:835 +#: agent/gpg-agent.c:534 scd/scdaemon.c:450 sm/gpgsm.c:835 #, c-format msgid "reading options from `%s'\n" msgstr "Optionen werden aus `%s' gelesen\n" -#: agent/gpg-agent.c:1031 agent/gpg-agent.c:1065 +#: agent/gpg-agent.c:1033 agent/gpg-agent.c:1067 #, c-format msgid "can't create directory `%s': %s\n" msgstr "Das Verzeichniss `%s' kann nicht erstell werden: %s\n" -#: agent/gpg-agent.c:1034 agent/gpg-agent.c:1070 +#: agent/gpg-agent.c:1036 agent/gpg-agent.c:1072 #, c-format msgid "directory `%s' created\n" msgstr "Verzeichniss `%s' wurde erstellt\n" -#: agent/gpg-agent.c:1248 +#: agent/gpg-agent.c:1250 msgid "no gpg-agent running in this session\n" msgstr "Der gpg-agent läuft nicht für diese Session\n" -#: agent/gpg-agent.c:1255 common/simple-pwquery.c:286 sm/call-agent.c:128 +#: agent/gpg-agent.c:1257 common/simple-pwquery.c:286 sm/call-agent.c:128 msgid "malformed GPG_AGENT_INFO environment variable\n" msgstr "Die Variable GPG_AGENT_INFO ist fehlerhaft\n" -#: agent/gpg-agent.c:1267 common/simple-pwquery.c:298 sm/call-agent.c:140 +#: agent/gpg-agent.c:1269 common/simple-pwquery.c:298 sm/call-agent.c:140 #, c-format msgid "gpg-agent protocol version %d is not supported\n" msgstr "Das gpg-agent Protocol %d wird nicht unterstützt\n" @@ -327,7 +327,7 @@ msgstr "Vom Benutzer abgebrochen\n" msgid "problem with the agent\n" msgstr "Problem mit dem Agenten\n" -#: jnlib/logging.c:555 +#: jnlib/logging.c:621 #, c-format msgid "you found a bug ... (%s:%d)\n" msgstr "Sie haben einen Bug (Softwarefehler) gefunden ... (%s:%d)\n" @@ -432,100 +432,87 @@ msgstr "" "Bitte die Option `--daemon' nutzen um das Programm im Hintergund " "auszuführen\n" -#: scd/sc-investigate.c:116 -msgid "Usage: sc-investigate [options] (-h for help)\n" -msgstr "Gebrauch: sc-investigate [Optionen] (-h für Hilfe)\n" - -#: scd/sc-investigate.c:118 -msgid "" -"Syntax: sc-investigate [options] [args]]\n" -"Have a look at smartcards\n" -msgstr "" -"Gebrauch: sc-investigate [Optionen] [Argumente]\n" -"Den Inhalt einer Smartcard inspizieren\n" - -#: scd/app-openpgp.c:458 +#: scd/app-openpgp.c:534 #, c-format msgid "failed to store the fingerprint: %s\n" msgstr "Der Fingerprint kann nicht gespeichert werden: %s\n" -#: scd/app-openpgp.c:471 +#: scd/app-openpgp.c:547 #, c-format msgid "failed to store the creation date: %s\n" msgstr "Das Erzeugungsdatum kann nicht gespeichert werden: %s\n" -#: scd/app-openpgp.c:656 scd/app-openpgp.c:745 +#: scd/app-openpgp.c:732 scd/app-openpgp.c:821 scd/app-openpgp.c:1313 #, c-format msgid "PIN callback returned error: %s\n" msgstr "Fehler vom PIN \"callback\": %s\n" -#: scd/app-openpgp.c:662 scd/app-openpgp.c:751 scd/app-openpgp.c:1236 +#: scd/app-openpgp.c:738 scd/app-openpgp.c:827 scd/app-openpgp.c:1319 #, c-format -msgid "prassphrase (CHV%d) is too short; minimum length is %d\n" -msgstr "Die Passphrase (CHV%d) ist zu kurz; Mindestlänge ist %d\n" +msgid "PIN for CHV%d is too short; minimum length is %d\n" +msgstr "Die PIN für den CHV%d ist zu kurz; Mindestlänge ist %d\n" -#: scd/app-openpgp.c:671 scd/app-openpgp.c:685 scd/app-openpgp.c:761 -#: scd/app-openpgp.c:1245 scd/app-openpgp.c:1259 +#: scd/app-openpgp.c:747 scd/app-openpgp.c:761 scd/app-openpgp.c:837 +#: scd/app-openpgp.c:1328 scd/app-openpgp.c:1342 #, c-format msgid "verify CHV%d failed: %s\n" msgstr "Prüfen von CHV%d fehlgeschlagen: %s\n" -#: scd/app-openpgp.c:708 +#: scd/app-openpgp.c:784 msgid "access to admin commands is not configured\n" msgstr "Zugriff auf Admin Kommandos ist nicht konfiguriert\n" -#: scd/app-openpgp.c:725 +#: scd/app-openpgp.c:801 msgid "error retrieving CHV status from card\n" msgstr "Fehler beim Holen des CHV Status von der Karte\n" -#: scd/app-openpgp.c:731 +#: scd/app-openpgp.c:807 msgid "card is permanently locked!\n" msgstr "Die Karte ist dauerhaft gesperrt!\n" -#: scd/app-openpgp.c:738 +#: scd/app-openpgp.c:814 #, c-format msgid "%d Admin PIN attempts remaining before card is permanently locked\n" msgstr "" "Noch %d Admin PIN Versuche möglich bevor die Karte dauerhaft gesperrt wird\n" -#: scd/app-openpgp.c:742 +#: scd/app-openpgp.c:818 msgid "Admin PIN" msgstr "Admin PIN" -#: scd/app-openpgp.c:1504 -msgid "can't access CHV Status Bytes - invalid OpenPGP card?\n" -msgstr "" -"Zugriff auf die CHV Status Bytes nicht möglich - ungültige OpenPGP Karte?\n" +#: scd/app-openpgp.c:1301 +#, c-format +msgid "PIN [sigs done: %lu]" +msgstr "PIN [erzeugte signaturen: %lu]" -#: scd/app-openpgp.c:1514 -msgid "can't access Extended Capability Flags - invalid OpenPGP card?\n" -msgstr "" -"Zugriff auf die Extended Capability Flags nicht möglich - ungültige OpenPGP " -"Karte?\n" +#: scd/app-openpgp.c:1587 scd/app-openpgp.c:1597 +#, c-format +msgid "can't access %s - invalid OpenPGP card?\n" +msgstr "Zugriff auf %s nicht möglich - ungültige OpenPGP Karte?\n" -#: scd/app-openpgp.c:1584 +#: scd/app-openpgp.c:1668 #, c-format msgid "error getting serial number: %s\n" msgstr "Fehler beim Holen der Seriennummer: %s\n" -#: scd/app-openpgp.c:1679 +#: scd/app-openpgp.c:1763 #, c-format msgid "failed to store the key: %s\n" msgstr "Fehler beim Speichern des Schlüssels: %s\n" -#: scd/app-openpgp.c:1721 +#: scd/app-openpgp.c:1805 msgid "reading the key failed\n" msgstr "Fehler beim Lesen des Schlüssels: %s\n" -#: scd/app-openpgp.c:1728 +#: scd/app-openpgp.c:1812 msgid "response does not contain the public key data\n" msgstr "Die Antwort enthält keine Public Key Daten\n" -#: scd/app-openpgp.c:1736 +#: scd/app-openpgp.c:1820 msgid "response does not contain the RSA modulus\n" msgstr "Die Antwort enthält keinen RSA Modulus\n" -#: scd/app-openpgp.c:1747 +#: scd/app-openpgp.c:1831 msgid "response does not contain the RSA public exponent\n" msgstr "Die Antwort enthält keinen öffenlichen RSA Exponent\n" @@ -664,7 +651,7 @@ msgstr "Der Herausgeber wird von einer externen Stelle gesucht\n" msgid "number of issuers matching: %d\n" msgstr "Anzahl der übereinstimmenden Heruasgeber: %d\n" -#: sm/certchain.c:403 sm/certchain.c:561 sm/certchain.c:921 sm/decrypt.c:260 +#: sm/certchain.c:403 sm/certchain.c:562 sm/certchain.c:922 sm/decrypt.c:260 #: sm/encrypt.c:341 sm/sign.c:324 sm/verify.c:106 msgid "failed to allocated keyDB handle\n" msgstr "Ein keyDB Handle konnte nicht bereitgestellt werden\n" @@ -691,64 +678,64 @@ msgstr "" msgid "checking the CRL failed: %s" msgstr "Die CRL konnte nicht geprüft werden: %s" -#: sm/certchain.c:581 +#: sm/certchain.c:582 msgid "no issuer found in certificate" msgstr "Im Zertifikat ist kein Herausgeber enthalten" -#: sm/certchain.c:594 +#: sm/certchain.c:595 #, c-format msgid "certificate with invalid validity: %s" msgstr "Zertifikat mit unzulässiger Gültigkeit: %s" -#: sm/certchain.c:610 +#: sm/certchain.c:611 msgid "certificate not yet valid" msgstr "Das Zertifikat ist noch nicht gültig" -#: sm/certchain.c:623 +#: sm/certchain.c:624 msgid "certificate has expired" msgstr "Das Zertifikat ist abgelaufen" -#: sm/certchain.c:660 +#: sm/certchain.c:661 msgid "selfsigned certificate has a BAD signature" msgstr "Das eigenbeglaubigte Zertifikat hat eine FALSCHE Signatur" -#: sm/certchain.c:674 +#: sm/certchain.c:675 msgid "root certificate is not marked trusted" msgstr "Das Wurzelzertifikat ist nicht als vertrauenswürdig markiert" -#: sm/certchain.c:685 +#: sm/certchain.c:686 #, c-format msgid "fingerprint=%s\n" msgstr "Fingerprint=%s\n" -#: sm/certchain.c:690 +#: sm/certchain.c:691 msgid "root certificate has now been marked as trusted\n" msgstr "Das Wurzelzertifikat wurde nun als vertrauenswürdig markiert\n" -#: sm/certchain.c:705 +#: sm/certchain.c:706 #, c-format msgid "checking the trust list failed: %s\n" msgstr "Fehler beim Prüfen der vertrauenswürdigen Zertifikate: %s\n" -#: sm/certchain.c:731 sm/import.c:166 +#: sm/certchain.c:732 sm/import.c:166 msgid "certificate chain too long\n" msgstr "Der Zertifikatkette ist zu lang\n" -#: sm/certchain.c:743 +#: sm/certchain.c:744 msgid "issuer certificate not found" msgstr "Herausgeberzertifikat nicht gefunden" -#: sm/certchain.c:776 +#: sm/certchain.c:777 msgid "certificate has a BAD signature" msgstr "Das Zertifikat hat eine FALSCHE Signatur" -#: sm/certchain.c:799 +#: sm/certchain.c:800 msgid "found another possible matching CA certificate - trying again" msgstr "" "Eine anderes möglicherweise passendes CA-Zertifikat gefunden - versuche " "nochmal" -#: sm/certchain.c:822 +#: sm/certchain.c:823 #, c-format msgid "certificate chain longer than allowed by CA (%d)" msgstr "Die Zertifikatkette ist länger als von der CA erlaubt (%d)" @@ -1361,7 +1348,8 @@ msgstr "Optionen zur Einstellung der Konfiguration" msgid "Options useful for debugging" msgstr "Nützliche Optionen zum Debuggen" -#: tools/gpgconf-comp.c:460 +#: tools/gpgconf-comp.c:460 tools/gpgconf-comp.c:537 tools/gpgconf-comp.c:586 +#: tools/gpgconf-comp.c:639 tools/gpgconf-comp.c:715 msgid "|FILE|write server mode logs to FILE" msgstr "|DATEI|Schreibe im Servermodus Logs auf DATEI" @@ -1389,6 +1377,25 @@ msgstr "Konfiguration der zu nutzenden LDAP-Server" msgid "Configuration for OCSP" msgstr "Konfiguration zu OCSP" +#, fuzzy +#~ msgid "passphrase (CHV%d) is too short; minimum length is %d\n" +#~ msgstr "Die Passphrase (CHV%d) ist zu kurz; Mindestlänge ist %d\n" + +#~ msgid "Usage: sc-investigate [options] (-h for help)\n" +#~ msgstr "Gebrauch: sc-investigate [Optionen] (-h für Hilfe)\n" + +#~ msgid "" +#~ "Syntax: sc-investigate [options] [args]]\n" +#~ "Have a look at smartcards\n" +#~ msgstr "" +#~ "Gebrauch: sc-investigate [Optionen] [Argumente]\n" +#~ "Den Inhalt einer Smartcard inspizieren\n" + +#~ msgid "can't access Extended Capability Flags - invalid OpenPGP card?\n" +#~ msgstr "" +#~ "Zugriff auf die Extended Capability Flags nicht möglich - ungültige " +#~ "OpenPGP Karte?\n" + #~ msgid "Enter passphrase:" #~ msgstr "Bitte das Mantra (Passphrase) eingeben:" diff --git a/scd/ChangeLog b/scd/ChangeLog index 32fbdf9d9..660865638 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,8 @@ +2004-10-22 Werner Koch + + * app-openpgp.c (verify_chv3): The minium length for CHV3 is + 8. Changed string to match the other ones. + 2004-10-21 Werner Koch * app-openpgp.c (do_sign): Replace asprintf by direct allocation. diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index f73b4f946..c37308054 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -822,10 +822,10 @@ verify_chv3 (app_t app, return rc; } - if (strlen (pinvalue) < 6) + if (strlen (pinvalue) < 8) { - log_error (_("passphrase (CHV%d) is too short;" - " minimum length is %d\n"), 3, 6); + log_error (_("PIN for CHV%d is too short;" + " minimum length is %d\n"), 3, 8); xfree (pinvalue); return gpg_error (GPG_ERR_BAD_PIN); } diff --git a/tools/Makefile.am b/tools/Makefile.am index 271195c2a..2378df813 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -19,7 +19,7 @@ EXTRA_DIST = Manifest watchgnupg.c \ rfc822parse.c rfc822parse.h gpgparsemail.c \ - addgnupghome + addgnupghome gpgsm-gencert.sh AM_CPPFLAGS = -I$(top_srcdir)/intl -I$(top_srcdir)/common include $(top_srcdir)/am/cmacros.am -- cgit From 625bafa4dacb7f20cc2c11697048ccafbb6c180a Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 3 Feb 2005 13:20:57 +0000 Subject: Forgot to commit the recent fixed to scd and logging - doing it now --- ChangeLog | 5 ++ configure.ac | 6 +- jnlib/ChangeLog | 5 ++ jnlib/logging.c | 41 ++++-------- scd/ChangeLog | 25 +++++++ scd/apdu.c | 12 ++-- scd/app-openpgp.c | 191 ++++++++++++++++++++++++++++++++++++------------------ scd/ccid-driver.c | 4 +- 8 files changed, 188 insertions(+), 101 deletions(-) (limited to 'scd/app-openpgp.c') diff --git a/ChangeLog b/ChangeLog index 237999e8a..f878f60d8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2005-01-17 Werner Koch + + * configure.ac: Make --without-included-regex work as expected. + Fixed FTP location info for some libraries. + 2005-01-13 Werner Koch Released 1.9.15. diff --git a/configure.ac b/configure.ac index 6cfc61193..7462a759e 100644 --- a/configure.ac +++ b/configure.ac @@ -889,7 +889,7 @@ if test "$use_regex" = yes ; then AC_MSG_CHECKING([whether the included regex lib is requested]) AC_ARG_WITH(included-regex, [ --with-included-regex use the included GNU regex library], - [gnupg_cv_included_regex=yes],[gnupg_cv_included_regex=no]) + [gnupg_cv_included_regex="$withval"],[gnupg_cv_included_regex=no]) AC_MSG_RESULT($gnupg_cv_included_regex) if test $gnupg_cv_included_regex = no ; then @@ -1060,7 +1060,7 @@ if test "$have_gpg_error" = "no"; then *** *** You need libgpg-error to build this program. ** This library is for example available at -*** ftp://ftp.gnupg.org/gcrypt/alpha/libgpg-error +*** ftp://ftp.gnupg.org/gcrypt/libgpg-error *** (at least version $NEED_GPG_ERROR_VERSION is required.) ***]]) fi @@ -1070,7 +1070,7 @@ if test "$have_libgcrypt" = "no"; then *** *** You need libgcrypt to build this program. ** This library is for example available at -*** ftp://ftp.gnupg.org/gcrypt/alpha/libgcrypt/ +*** ftp://ftp.gnupg.org/gcrypt/libgcrypt/ *** (at least version $NEED_LIBGCRYPT_VERSION using API $NEED_LIBGCRYPT_API) is required.) ***]]) fi diff --git a/jnlib/ChangeLog b/jnlib/ChangeLog index a879254ae..0c82c8724 100644 --- a/jnlib/ChangeLog +++ b/jnlib/ChangeLog @@ -1,3 +1,8 @@ +2005-01-19 Werner Koch + + * logging.c (fun_writer): Don't fallback to stderr. Print to + stderr only if connected to a tty. + 2004-12-20 Werner Koch * w32-pth.c (do_pth_event_free): The events are hold in a ring diff --git a/jnlib/logging.c b/jnlib/logging.c index 781f03e6d..97a2b9c9e 100644 --- a/jnlib/logging.c +++ b/jnlib/logging.c @@ -1,6 +1,6 @@ /* logging.c - useful logging functions * Copyright (C) 1998, 1999, 2000, 2001, 2003, - * 2004 Free Software Foundation, Inc. + * 2004, 2005 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -20,11 +20,6 @@ */ -/* This file should replace logger.c in the future - for now it is not - * used by GnuPG but by GPA. - * It is a quite simple implemenation but sufficient for most purposes. - */ - #include #include #include @@ -64,23 +59,6 @@ static int force_prefixes; static int missing_lf; static int errorcount; -#if 0 -static void -write2stderr( const char *s ) -{ - write( 2, s, strlen(s) ); -} - - -static void -do_die(int rc, const char *text ) -{ - write2stderr("\nFatal error: "); - write2stderr(text); - write2stderr("\n"); - abort(); -} -#endif int log_get_errorcount (int clear) @@ -150,7 +128,8 @@ fun_writer (void *cookie_arg, const char *buffer, size_t size) cookie->fd = socket (PF_LOCAL, SOCK_STREAM, 0); if (cookie->fd == -1) { - if (!cookie->quiet && !running_detached) + if (!cookie->quiet && !running_detached + && isatty (fileno (stderr))) fprintf (stderr, "failed to create socket for logging: %s\n", strerror(errno)); } @@ -168,7 +147,8 @@ fun_writer (void *cookie_arg, const char *buffer, size_t size) if (connect (cookie->fd, (struct sockaddr *) &addr, addrlen) == -1) { - if (!cookie->quiet && !running_detached) + if (!cookie->quiet && !running_detached + && isatty (fileno (stderr))) fprintf (stderr, "can't connect to `%s': %s\n", cookie->name, strerror(errno)); close (cookie->fd); @@ -180,12 +160,16 @@ fun_writer (void *cookie_arg, const char *buffer, size_t size) { if (!running_detached) { + /* Due to all the problems with apps not running + detahced but beeing caled with stderr closed or + used for a different purposes, it does not make + sense to switch to stderr. We tehrefore disable it. */ if (!cookie->quiet) { - fputs ("switching logging to stderr\n", stderr); + /* fputs ("switching logging to stderr\n", stderr);*/ cookie->quiet = 1; } - cookie->fd = fileno (stderr); + cookie->fd = -1; /*fileno (stderr);*/ } } else /* Connection has been established. */ @@ -199,7 +183,8 @@ fun_writer (void *cookie_arg, const char *buffer, size_t size) if (cookie->fd != -1 && !writen (cookie->fd, buffer, size)) return size; /* Okay. */ - if (!running_detached && cookie->fd != -1) + if (!running_detached && cookie->fd != -1 + && isatty (fileno (stderr))) { if (*cookie->name) fprintf (stderr, "error writing to `%s': %s\n", diff --git a/scd/ChangeLog b/scd/ChangeLog index e85c8d81c..aba75ad54 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,28 @@ +2005-01-26 Werner Koch + + * ccid-driver.c (parse_ccid_descriptor): Need the CSM workaround + also for newer firmware versions. Need to get a list of fixed + firmware versions and use that. + +2005-01-25 Werner Koch + + * apdu.c (apdu_send_le, apdu_send_direct): Fix some compiler + warnings. + + * app-openpgp.c (get_cached_data): New arg GET_IMMEDIATE to bypass + the cache. Changed all callers. + (get_one_do): Bypass the cache if the value would have been read + directly for v1.1 cards.It makes things a bit slower but obnly for + 1.0 cards and there are not that many cards out in the wild. This + is required to fix a caching bug when generating new keys; as a + side effect of the retrieval of the the C4 DO from the 6E DO the + cached fingerprint will get updated to the old value and later + when signing the generated key the checking of the fingerprint + fails becuase it won't match the new one. Thanks to Moritz for + analyzing this problem. + (verify_chv3): Removed the CHV status reread logic because we + won't cache the C4 DO anymore. + 2004-12-28 Werner Koch * ccid-driver.c (find_endpoint): New. diff --git a/scd/apdu.c b/scd/apdu.c index 9120616de..040de1461 100644 --- a/scd/apdu.c +++ b/scd/apdu.c @@ -2721,7 +2721,8 @@ apdu_send_le(int slot, int class, int ins, int p0, int p1, resultlen -= 2; if (DBG_CARD_IO) { - log_debug (" response: sw=%04X datalen=%d\n", sw, resultlen); + log_debug (" response: sw=%04X datalen=%d\n", + sw, (unsigned int)resultlen); if ( !retbuf && (sw == SW_SUCCESS || (sw & 0xff00) == SW_MORE_DATA)) log_printhex (" dump: ", result, resultlen); } @@ -2787,7 +2788,8 @@ apdu_send_le(int slot, int class, int ins, int p0, int p1, resultlen -= 2; if (DBG_CARD_IO) { - log_debug (" more: sw=%04X datalen=%d\n", sw, resultlen); + log_debug (" more: sw=%04X datalen=%d\n", + sw, (unsigned int)resultlen); if (!retbuf && (sw==SW_SUCCESS || (sw&0xff00)==SW_MORE_DATA)) log_printhex (" dump: ", result, resultlen); } @@ -2920,7 +2922,8 @@ apdu_send_direct (int slot, const unsigned char *apdudata, size_t apdudatalen, resultlen -= 2; if (DBG_CARD_IO) { - log_debug (" response: sw=%04X datalen=%d\n", sw, resultlen); + log_debug (" response: sw=%04X datalen=%d\n", + sw, (unsigned int)resultlen); if ( !retbuf && (sw == SW_SUCCESS || (sw & 0xff00) == SW_MORE_DATA)) log_printhex (" dump: ", result, resultlen); } @@ -2972,7 +2975,8 @@ apdu_send_direct (int slot, const unsigned char *apdudata, size_t apdudatalen, resultlen -= 2; if (DBG_CARD_IO) { - log_debug (" more: sw=%04X datalen=%d\n", sw, resultlen); + log_debug (" more: sw=%04X datalen=%d\n", + sw, (unsigned int)resultlen); if (!retbuf && (sw==SW_SUCCESS || (sw&0xff00)==SW_MORE_DATA)) log_printhex (" dump: ", result, resultlen); } diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index c37308054..fca0a98b7 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -1,5 +1,5 @@ /* app-openpgp.c - The OpenPGP card application. - * Copyright (C) 2003, 2004 Free Software Foundation, Inc. + * Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -79,8 +79,13 @@ static struct { { 0x00C4, 0, 0x6E, 1, 0, 1, 1, "CHV Status Bytes" }, { 0x00C5, 0, 0x6E, 1, 0, 0, 0, "Fingerprints" }, { 0x00C6, 0, 0x6E, 1, 0, 0, 0, "CA Fingerprints" }, + { 0x00CD, 0, 0x6E, 1, 0, 0, 0, "Generation time" }, { 0x007A, 1, 0, 1, 0, 0, 0, "Security Support Template" }, { 0x0093, 0, 0x7A, 1, 1, 0, 0, "Digital Signature Counter" }, + { 0x0101, 0, 0, 0, 0, 0, 0, "Private DO 1"}, + { 0x0102, 0, 0, 0, 0, 0, 0, "Private DO 2"}, + { 0x0103, 0, 0, 0, 0, 0, 0, "Private DO 3"}, + { 0x0104, 0, 0, 0, 0, 0, 0, "Private DO 4"}, { 0 } }; @@ -133,10 +138,12 @@ do_deinit (app_t app) /* Wrapper around iso7816_get_data which first tries to get the data - from the cache. */ + from the cache. With GET_IMMEDIATE passed as true, the cache is + bypassed. */ static gpg_error_t get_cached_data (app_t app, int tag, - unsigned char **result, size_t *resultlen) + unsigned char **result, size_t *resultlen, + int get_immediate) { gpg_error_t err; int i; @@ -147,23 +154,25 @@ get_cached_data (app_t app, int tag, *result = NULL; *resultlen = 0; - for (c=app->app_local->cache; c; c = c->next) - if (c->tag == tag) - { - if(c->length) + if (!get_immediate) + { + for (c=app->app_local->cache; c; c = c->next) + if (c->tag == tag) { - p = xtrymalloc (c->length); - if (!p) - return gpg_error (gpg_err_code_from_errno (errno)); - memcpy (p, c->data, c->length); - *result = p; + if(c->length) + { + p = xtrymalloc (c->length); + if (!p) + return gpg_error (gpg_err_code_from_errno (errno)); + memcpy (p, c->data, c->length); + *result = p; + } + + *resultlen = c->length; + + return 0; } - - *resultlen = c->length; - - return 0; - } - + } err = iso7816_get_data (app->slot, tag, &p, &len); if (err) @@ -172,6 +181,9 @@ get_cached_data (app_t app, int tag, *resultlen = len; /* Check whether we should cache this object. */ + if (get_immediate) + return 0; + for (i=0; data_objects[i].tag; i++) if (data_objects[i].tag == tag) { @@ -180,8 +192,7 @@ get_cached_data (app_t app, int tag, break; } - /* No, cache it. */ - + /* Okay, cache it. */ for (c=app->app_local->cache; c; c = c->next) assert (c->tag != tag); @@ -294,7 +305,8 @@ get_one_do (app_t app, int tag, unsigned char **result, size_t *nbytes) if (data_objects[i].tag && data_objects[i].get_from) { rc = get_cached_data (app, data_objects[i].get_from, - &buffer, &buflen); + &buffer, &buflen, + data_objects[i].get_immediate_in_v11); if (!rc) { const unsigned char *s; @@ -315,7 +327,8 @@ get_one_do (app_t app, int tag, unsigned char **result, size_t *nbytes) if (!value) /* Not in a constructed DO, try simple. */ { - rc = get_cached_data (app, tag, &buffer, &buflen); + rc = get_cached_data (app, tag, &buffer, &buflen, + data_objects[i].get_immediate_in_v11); if (!rc) { value = buffer; @@ -421,7 +434,7 @@ count_bits (const unsigned char *a, size_t len) at any time and should be called after changing the login-data DO. Everything up to a LF is considered a mailbox or account name. If - the first LF is follewed by DC4 (0x14) control sequence are + the first LF is followed by DC4 (0x14) control sequence are expected up to the next LF. Control sequences are separated by FS (0x28) and consist of key=value pairs. There is one key defined: @@ -575,6 +588,23 @@ send_fpr_if_not_null (ctrl_t ctrl, const char *keyword, buf, (size_t)strlen (buf), NULL, 0); } +static void +send_fprtime_if_not_null (ctrl_t ctrl, const char *keyword, + int number, const unsigned char *stamp) +{ + char numbuf1[50], numbuf2[50]; + unsigned long value; + + value = (stamp[0] << 24) | (stamp[1]<<16) | (stamp[2]<<8) | stamp[3]; + if (!value) + return; + sprintf (numbuf1, "%d", number); + sprintf (numbuf2, "%lu", value); + send_status_info (ctrl, keyword, + numbuf1, (size_t)strlen(numbuf1), + numbuf2, (size_t)strlen(numbuf2), NULL, 0); +} + static void send_key_data (ctrl_t ctrl, const char *name, const unsigned char *a, size_t alen) @@ -607,12 +637,17 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name) { "DISP-SEX", 0x5F35 }, { "PUBKEY-URL", 0x5F50 }, { "KEY-FPR", 0x00C5, 3 }, + { "KEY-TIME", 0x00CD, 4 }, { "CA-FPR", 0x00C6, 3 }, - { "CHV-STATUS", 0x00C4, 1 }, + { "CHV-STATUS", 0x00C4, 1 }, { "SIG-COUNTER", 0x0093, 2 }, { "SERIALNO", 0x004F, -1 }, { "AID", 0x004F }, { "EXTCAP", 0x0000, -2 }, + { "PRIVATE-DO-1", 0x0101 }, + { "PRIVATE-DO-2", 0x0102 }, + { "PRIVATE-DO-3", 0x0103 }, + { "PRIVATE-DO-4", 0x0104 }, { NULL, 0 } }; int idx, i; @@ -686,6 +721,12 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name) for (i=0; i < 3; i++) send_fpr_if_not_null (ctrl, table[idx].name, i+1, value+i*20); } + else if (table[idx].special == 4) + { + if (valuelen >= 12) + for (i=0; i < 3; i++) + send_fprtime_if_not_null (ctrl, table[idx].name, i+1, value+i*4); + } else send_status_info (ctrl, table[idx].name, value, valuelen, NULL, 0); @@ -705,9 +746,20 @@ do_learn_status (app_t app, ctrl_t ctrl) do_getattr (app, ctrl, "PUBKEY-URL"); do_getattr (app, ctrl, "LOGIN-DATA"); do_getattr (app, ctrl, "KEY-FPR"); + if (app->card_version > 0x0100) + do_getattr (app, ctrl, "KEY-TIME"); do_getattr (app, ctrl, "CA-FPR"); do_getattr (app, ctrl, "CHV-STATUS"); do_getattr (app, ctrl, "SIG-COUNTER"); + if (app->app_local->extcap.private_dos) + { + do_getattr (app, ctrl, "PRIVATE-DO-1"); + do_getattr (app, ctrl, "PRIVATE-DO-2"); + if (app->did_chv2) + do_getattr (app, ctrl, "PRIVATE-DO-3"); + if (app->did_chv3) + do_getattr (app, ctrl, "PRIVATE-DO-4"); + } return 0; } @@ -792,8 +844,6 @@ verify_chv3 (app_t app, void *relptr; unsigned char *value; size_t valuelen; - int reread_chv_status; - relptr = get_one_do (app, 0x00C4, &value, &valuelen); if (!relptr || valuelen < 7) @@ -809,13 +859,14 @@ verify_chv3 (app_t app, return gpg_error (GPG_ERR_BAD_PIN); } - reread_chv_status = (value[6] < 3); - log_info(_("%d Admin PIN attempts remaining before card" " is permanently locked\n"), value[6]); xfree (relptr); - rc = pincb (pincb_arg, _("Admin PIN"), &pinvalue); + /* TRANSLATORS: Do not translate the "|A|" prefix but + keep it at the start of the string. We need this elsewhere + to get some infos on the string. */ + rc = pincb (pincb_arg, _("|A|Admin PIN"), &pinvalue); if (rc) { log_info (_("PIN callback returned error: %s\n"), gpg_strerror (rc)); @@ -839,13 +890,6 @@ verify_chv3 (app_t app, return rc; } app->did_chv3 = 1; - /* If the PIN has been entered wrongly before, we need to flush - the cached value so that the next read correctly reflects the - resetted retry counter. Note that version 1.1 of the specs - allow direct reading of that DO, so that we could actually - flush it in all cases. */ - if (reread_chv_status) - flush_cache_item (app, 0x00C4); } return rc; } @@ -864,17 +908,22 @@ do_setattr (app_t app, const char *name, static struct { const char *name; int tag; + int need_chv; int special; } table[] = { - { "DISP-NAME", 0x005B }, - { "LOGIN-DATA", 0x005E, 2 }, - { "DISP-LANG", 0x5F2D }, - { "DISP-SEX", 0x5F35 }, - { "PUBKEY-URL", 0x5F50 }, - { "CHV-STATUS-1", 0x00C4, 1 }, - { "CA-FPR-1", 0x00CA }, - { "CA-FPR-2", 0x00CB }, - { "CA-FPR-3", 0x00CC }, + { "DISP-NAME", 0x005B, 3 }, + { "LOGIN-DATA", 0x005E, 3, 2 }, + { "DISP-LANG", 0x5F2D, 3 }, + { "DISP-SEX", 0x5F35, 3 }, + { "PUBKEY-URL", 0x5F50, 3 }, + { "CHV-STATUS-1", 0x00C4, 3, 1 }, + { "CA-FPR-1", 0x00CA, 3 }, + { "CA-FPR-2", 0x00CB, 3 }, + { "CA-FPR-3", 0x00CC, 3 }, + { "PRIVATE-DO-1", 0x0101, 2 }, + { "PRIVATE-DO-2", 0x0102, 3 }, + { "PRIVATE-DO-3", 0x0103, 2 }, + { "PRIVATE-DO-4", 0x0104, 3 }, { NULL, 0 } }; @@ -884,7 +933,17 @@ do_setattr (app_t app, const char *name, if (!table[idx].name) return gpg_error (GPG_ERR_INV_NAME); - rc = verify_chv3 (app, pincb, pincb_arg); + switch (table[idx].need_chv) + { + case 2: + rc = verify_chv2 (app, pincb, pincb_arg); + break; + case 3: + rc = verify_chv3 (app, pincb, pincb_arg); + break; + default: + rc = 0; + } if (rc) return rc; @@ -953,10 +1012,14 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, int reset_mode, else app->did_chv1 = app->did_chv2 = 0; - rc = pincb (pincb_arg, chvno == 3? "New Admin PIN" : "New PIN", &pinvalue); + /* Note to translators: Do not translate the "|*|" prefixes but + keep it at the start of the string. We need this elsewhere + to get some infos on the string. */ + rc = pincb (pincb_arg, chvno == 3? _("|AN|New Admin PIN") : _("|N|New PIN"), + &pinvalue); if (rc) { - log_error ("error getting new PIN: %s\n", gpg_strerror (rc)); + log_error (_("error getting new PIN: %s\n"), gpg_strerror (rc)); goto leave; } @@ -1022,14 +1085,14 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags, rc = iso7816_get_data (app->slot, 0x006E, &buffer, &buflen); if (rc) { - log_error ("error reading application data\n"); + log_error (_("error reading application data\n")); return gpg_error (GPG_ERR_GENERAL); } fpr = find_tlv (buffer, buflen, 0x00C5, &n); if (!fpr || n != 60) { rc = gpg_error (GPG_ERR_GENERAL); - log_error ("error reading fingerprint DO\n"); + log_error (_("error reading fingerprint DO\n")); goto leave; } fpr += 20*keyno; @@ -1038,13 +1101,13 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags, if (i!=20 && !force) { rc = gpg_error (GPG_ERR_EEXIST); - log_error ("key already exists\n"); + log_error (_("key already exists\n")); goto leave; } else if (i!=20) - log_info ("existing key will be replaced\n"); + log_info (_("existing key will be replaced\n")); else - log_info ("generating new key\n"); + log_info (_("generating new key\n")); rc = verify_chv3 (app, pincb, pincb_arg); @@ -1054,7 +1117,7 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags, xfree (buffer); buffer = NULL; #if 1 - log_info ("please wait while key is being generated ...\n"); + log_info (_("please wait while key is being generated ...\n")); start_at = time (NULL); rc = iso7816_generate_keypair #else @@ -1069,16 +1132,16 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags, if (rc) { rc = gpg_error (GPG_ERR_CARD); - log_error ("generating key failed\n"); + log_error (_("generating key failed\n")); goto leave; } - log_info ("key generation completed (%d seconds)\n", + log_info (_("key generation completed (%d seconds)\n"), (int)(time (NULL) - start_at)); keydata = find_tlv (buffer, buflen, 0x7F49, &keydatalen); if (!keydata) { rc = gpg_error (GPG_ERR_CARD); - log_error ("response does not contain the public key data\n"); + log_error (_("response does not contain the public key data\n")); goto leave; } @@ -1086,7 +1149,7 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags, if (!m) { rc = gpg_error (GPG_ERR_CARD); - log_error ("response does not contain the RSA modulus\n"); + log_error (_("response does not contain the RSA modulus\n")); goto leave; } /* log_printhex ("RSA n:", m, mlen); */ @@ -1096,7 +1159,7 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags, if (!e) { rc = gpg_error (GPG_ERR_CARD); - log_error ("response does not contain the RSA public exponent\n"); + log_error (_("response does not contain the RSA public exponent\n")); goto leave; } /* log_printhex ("RSA e:", e, elen); */ @@ -1129,7 +1192,7 @@ convert_sig_counter_value (const unsigned char *value, size_t valuelen) ul = (value[0] << 16) | (value[1] << 8) | value[2]; else { - log_error ("invalid structure of OpenPGP card (DO 0x93)\n"); + log_error (_("invalid structure of OpenPGP card (DO 0x93)\n")); ul = 0; } return ul; @@ -1161,17 +1224,17 @@ compare_fingerprint (app_t app, int keyno, unsigned char *sha1fpr) assert (keyno >= 1 && keyno <= 3); - rc = get_cached_data (app, 0x006E, &buffer, &buflen); + rc = get_cached_data (app, 0x006E, &buffer, &buflen, 0); if (rc) { - log_error ("error reading application data\n"); + log_error (_("error reading application data\n")); return gpg_error (GPG_ERR_GENERAL); } fpr = find_tlv (buffer, buflen, 0x00C5, &n); if (!fpr || n != 60) { xfree (buffer); - log_error ("error reading fingerprint DO\n"); + log_error (_("error reading fingerprint DO\n")); return gpg_error (GPG_ERR_GENERAL); } fpr += (keyno-1)*20; @@ -1290,7 +1353,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, memcpy (data+15, indata, indatalen); sigcount = get_sig_counter (app); - log_info ("signatures created so far: %lu\n", sigcount); + log_info (_("signatures created so far: %lu\n"), sigcount); if (!app->did_chv1 || app->force_chv1 ) { diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c index 0694fe762..459060830 100644 --- a/scd/ccid-driver.c +++ b/scd/ccid-driver.c @@ -403,7 +403,7 @@ parse_ccid_descriptor (ccid_driver_t handle, if (buf[49] == 0xff) DEBUGOUT_CONT ("echo\n"); else - DEBUGOUT_1 (" %02X\n", buf[48]); + DEBUGOUT_CONT_1 (" %02X\n", buf[48]); DEBUGOUT ( " wlcdLayout "); if (!buf[50] && !buf[51]) @@ -450,7 +450,7 @@ parse_ccid_descriptor (ccid_driver_t handle, if (handle->id_vendor == VENDOR_SCM /* FIXME: check whether it is the same firmware version for all drivers. */ - && handle->bcd_device < 0x0513 + && handle->bcd_device < 0x0519 && handle->max_ifsd > 48) { DEBUGOUT ("enabling workaround for buggy SCM readers\n"); -- cgit From 8c77433de9a208d6ffb03aa482b6a5fe6bcfd4f3 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 22 Feb 2005 17:29:07 +0000 Subject: * app-openpgp.c (app_local_s): New field PK. (do_deinit, do_genkey, app_openpgp_storekey): Clear it. (get_public_key, send_keypair_info): New. (do_learn_status): Send KEYPAIR info * app-common.h (app_ctx_t): Add function pointer READKEY. * app.c (app_readkey): New. * command.c (cmd_readkey): Use READKEY function if possible. --- scd/ChangeLog | 16 +++- scd/app-common.h | 6 +- scd/app-openpgp.c | 247 +++++++++++++++++++++++++++++++++++++++++++++++++++++- scd/app.c | 26 ++++++ scd/command.c | 34 ++++++-- 5 files changed, 316 insertions(+), 13 deletions(-) (limited to 'scd/app-openpgp.c') diff --git a/scd/ChangeLog b/scd/ChangeLog index aba75ad54..054463d6d 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,14 @@ +2005-02-22 Werner Koch + + * app-openpgp.c (app_local_s): New field PK. + (do_deinit, do_genkey, app_openpgp_storekey): Clear it. + (get_public_key, send_keypair_info): New. + (do_learn_status): Send KEYPAIR info + + * app-common.h (app_ctx_t): Add function pointer READKEY. + * app.c (app_readkey): New. + * command.c (cmd_readkey): Use READKEY function if possible. + 2005-01-26 Werner Koch * ccid-driver.c (parse_ccid_descriptor): Need the CSM workaround @@ -18,7 +29,7 @@ side effect of the retrieval of the the C4 DO from the 6E DO the cached fingerprint will get updated to the old value and later when signing the generated key the checking of the fingerprint - fails becuase it won't match the new one. Thanks to Moritz for + fails because it won't match the new one. Thanks to Moritz for analyzing this problem. (verify_chv3): Removed the CHV status reread logic because we won't cache the C4 DO anymore. @@ -934,7 +945,8 @@ * scdaemon.c scdaemon.h, command.c: New. Based on the code from the gpg-agent. - Copyright 2002 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 diff --git a/scd/app-common.h b/scd/app-common.h index 48bd349f4..ace57d98c 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -1,5 +1,5 @@ /* app-common.h - Common declarations for all card applications - * Copyright (C) 2003 Free Software Foundation, Inc. + * Copyright (C) 2003, 2005 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -49,6 +49,8 @@ struct app_ctx_s { int (*learn_status) (app_t app, ctrl_t ctrl); int (*readcert) (app_t app, const char *certid, unsigned char **cert, size_t *certlen); + int (*readkey) (app_t app, const char *certid, + unsigned char **pk, size_t *pklen); int (*getattr) (app_t app, ctrl_t ctrl, const char *name); int (*setattr) (app_t app, const char *name, int (*pincb)(void*, const char *, char **), @@ -109,6 +111,8 @@ int app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp); int app_write_learn_status (app_t app, ctrl_t ctrl); int app_readcert (app_t app, const char *certid, unsigned char **cert, size_t *certlen); +int app_readkey (app_t app, const char *keyid, + unsigned char **pk, size_t *pklen); int app_getattr (app_t app, ctrl_t ctrl, const char *name); int app_setattr (app_t app, const char *name, int (*pincb)(void*, const char *, char **), diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index fca0a98b7..8d146ba6a 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -90,6 +90,7 @@ static struct { }; +/* One cache item for DOs. */ struct cache_s { struct cache_s *next; int tag; @@ -97,8 +98,20 @@ struct cache_s { unsigned char data[1]; }; + +/* Object with application (i.e. OpenPGP card) specific data. */ struct app_local_s { + /* A linked list with cached DOs. */ struct cache_s *cache; + + /* Keep track of the public keys. */ + struct + { + int read_done; /* True if we have at least tried to read them. */ + gcry_sexp_t key; /* Might be NULL if key is not available. */ + } pk[3]; + + /* Keep track of card capabilities. */ struct { unsigned int get_challenge:1; @@ -106,6 +119,8 @@ struct app_local_s { unsigned int change_force_chv:1; unsigned int private_dos:1; } extcap; + + /* Flags used to control the application. */ struct { unsigned int no_sync:1; /* Do not sync CHV1 and CHV2 */ @@ -114,10 +129,16 @@ struct app_local_s { }; + +/***** Local prototypes *****/ static unsigned long convert_sig_counter_value (const unsigned char *value, size_t valuelen); -static unsigned long get_sig_counter (APP app); +static unsigned long get_sig_counter (app_t app); + + + + /* Deconstructor. */ static void do_deinit (app_t app) @@ -125,12 +146,19 @@ do_deinit (app_t app) if (app && app->app_local) { struct cache_s *c, *c2; + int i; for (c = app->app_local->cache; c; c = c2) { c2 = c->next; xfree (c); } + + for (i=0; i < DIM (app->app_local->pk); i++) + { + gcry_sexp_release (app->app_local->pk[i].key); + app->app_local->pk[i].read_done = 0; + } xfree (app->app_local); app->app_local = NULL; } @@ -736,6 +764,156 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name) } +/* Get the public key for KEYNO and store it as an S-expresion with + the APP handle. On error that field gets cleared. If we already + know about the public key we will just return. Note that this does + not mean a key is available; this is soley indicated by the + presence of the app->app_local->pk[KEYNO-1].key field. + + Note that GnuPG 1.x does not need this and it would be too time + consuming to send it just for the fun of it. */ +#if GNUPG_MAJOR_VERSION > 1 +static gpg_error_t +get_public_key (app_t app, int keyno) +{ + gpg_error_t err = 0; + unsigned char *buffer; + const unsigned char *keydata, *m, *e; + size_t buflen, keydatalen, mlen, elen; + gcry_sexp_t sexp; + + if (keyno < 1 || keyno > 3) + return gpg_error (GPG_ERR_INV_ID); + keyno--; + + /* Already cached? */ + if (app->app_local->pk[keyno].read_done) + return 0; + + gcry_sexp_release (app->app_local->pk[keyno].key); + app->app_local->pk[keyno].key = NULL; + + if (app->card_version > 0x0100) + { + /* We may simply read the public key out of these cards. */ + err = iso7816_read_public_key (app->slot, + keyno == 0? "\xB6" : + keyno == 1? "\xB8" : "\xA4", + 2, + &buffer, &buflen); + if (err) + { + log_error (_("reading public key failed: %s\n"), gpg_strerror (err)); + goto leave; + } + + keydata = find_tlv (buffer, buflen, 0x7F49, &keydatalen); + if (!keydata) + { + err = gpg_error (GPG_ERR_CARD); + log_error (_("response does not contain the public key data\n")); + goto leave; + } + + m = find_tlv (keydata, keydatalen, 0x0081, &mlen); + if (!m) + { + err = gpg_error (GPG_ERR_CARD); + log_error (_("response does not contain the RSA modulus\n")); + goto leave; + } + + e = find_tlv (keydata, keydatalen, 0x0082, &elen); + if (!e) + { + err = gpg_error (GPG_ERR_CARD); + log_error (_("response does not contain the RSA public exponent\n")); + goto leave; + } + + err = gcry_sexp_build (&sexp, NULL, + "(public-key (rsa (n %b) (e %b)))", + (int)mlen, m,(int)elen, e); + + if (err) + { + log_error ("error formatting the key into an S-expression: %s\n", + gpg_strerror (err)); + goto leave; + } + app->app_local->pk[keyno].key = sexp; + + } + else + { + /* Due to a design problem in v1.0 cards we can't get the public + key out of these cards without doing a verify on CHV3. + Clearly that is not an option and thus we try to locate the + key using an external helper. */ + + buffer = NULL; + /* FIXME */ + + } + + leave: + /* Set a flag to indicate that we tried to read the key. */ + app->app_local->pk[keyno].read_done = 1; + + xfree (buffer); + return 0; +} +#endif /* GNUPG_MAJOR_VERSION > 1 */ + + + +/* Send the KEYPAIRINFO back. KEYNO needs to be in the range [1,3]. + This is used by the LEARN command. */ +static gpg_error_t +send_keypair_info (app_t app, ctrl_t ctrl, int keyno) +{ + gpg_error_t err = 0; + /* Note that GnuPG 1.x does not need this and it would be too time + consuming to send it just for the fun of it. */ +#if GNUPG_MAJOR_VERSION > 1 + gcry_sexp_t sexp; + unsigned char grip[20]; + char gripstr[41]; + char idbuf[50]; + int i; + + err = get_public_key (app, keyno); + if (err) + goto leave; + + assert (keyno >= 1 && keyno <= 3); + sexp = app->app_local->pk[keyno-1].key; + if (!sexp) + goto leave; /* No such key. */ + + if (!gcry_pk_get_keygrip (sexp, grip)) + { + err = gpg_error (GPG_ERR_INTERNAL); + goto leave; + } + + for (i=0; i < 20; i++) + sprintf (gripstr+i*2, "%02X", grip[i]); + + sprintf (idbuf, "OPENPGP.%d", keyno); + send_status_info (ctrl, "KEYPAIRINFO", + gripstr, 40, + idbuf, strlen (idbuf), + NULL, (size_t)0); + + leave: +#endif /* GNUPG_MAJOR_VERSION > 1 */ + + return err; +} + + +/* Handle the LEARN command for OpenPGP. */ static int do_learn_status (app_t app, ctrl_t ctrl) { @@ -760,11 +938,63 @@ do_learn_status (app_t app, ctrl_t ctrl) if (app->did_chv3) do_getattr (app, ctrl, "PRIVATE-DO-4"); } + send_keypair_info (app, ctrl, 1); + send_keypair_info (app, ctrl, 2); + send_keypair_info (app, ctrl, 3); + return 0; +} + + +/* Handle the READKEY command for OpenPGP. On success a canonical + encoded S-expression with the public key will get stored at PK and + its length (for assertions) at PKLEN; the caller must release that + buffer. On error PK and PKLEN are not changed and an error code is + returned. */ +static int +do_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen) +{ + gpg_error_t err; + int keyno; + size_t n; + unsigned char *buf; + gcry_sexp_t sexp; + + if (!strcmp (keyid, "OPENPGP.1")) + keyno = 1; + else if (!strcmp (keyid, "OPENPGP.2")) + keyno = 2; + else if (!strcmp (keyid, "OPENPGP.3")) + keyno = 3; + else + return gpg_error (GPG_ERR_INV_ID); + err = get_public_key (app, keyno); + if (err) + return err; + + sexp = app->app_local->pk[keyno-1].key; + if (!sexp) + return gpg_error (GPG_ERR_NO_PUBKEY); + + n = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, NULL, 0); + if (!n) + return gpg_error (GPG_ERR_BUG); + buf = xtrymalloc (n); + if (!buf) + return gpg_error_from_errno (errno); + n = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, buf, n); + if (!n) + { + xfree (buf); + return gpg_error (GPG_ERR_BUG); + } + *pk = buf; + *pklen = n; return 0; } + /* Verify CHV2 if required. Depending on the configuration of the card CHV1 will also be verified. */ static int @@ -1082,6 +1312,11 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags, generation. This _might_ help a card to gather more entropy. */ flush_cache (app); + /* Obviously we need to remove the cached public key. */ + gcry_sexp_release (app->app_local->pk[keyno].key); + app->app_local->pk[keyno].read_done = 0; + + /* Check whether a key already exists. */ rc = iso7816_get_data (app->slot, 0x006E, &buffer, &buflen); if (rc) { @@ -1109,11 +1344,12 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags, else log_info (_("generating new key\n")); - + + /* Prepare for key generation by verifying the ADmin PIN. */ rc = verify_chv3 (app, pincb, pincb_arg); if (rc) goto leave; - + xfree (buffer); buffer = NULL; #if 1 @@ -1682,7 +1918,7 @@ app_select_openpgp (app_t app) app->fnc.deinit = do_deinit; app->fnc.learn_status = do_learn_status; - app->fnc.readcert = NULL; + app->fnc.readkey = do_readkey; app->fnc.getattr = do_getattr; app->fnc.setattr = do_setattr; app->fnc.genkey = do_genkey; @@ -1818,6 +2054,9 @@ app_openpgp_storekey (app_t app, int keyno, flush_cache (app); + gcry_sexp_release (app->app_local->pk[keyno].key); + app->app_local->pk[keyno].read_done = 0; + rc = iso7816_put_data (app->slot, (app->card_version > 0x0007? 0xE0 : 0xE9) + keyno, template, template_len); diff --git a/scd/app.c b/scd/app.c index 55fb5861e..fad4eba55 100644 --- a/scd/app.c +++ b/scd/app.c @@ -263,6 +263,32 @@ app_readcert (app_t app, const char *certid, } +/* Read the key with ID KEYID. On success a canonical encoded + S-expression with the public key will get stored at PK and its + length (for assertions) at PKLEN; the caller must release that + buffer. On error NULL will be stored at PK and PKLEN and an error + code returned. + + This function might not be supported by all applications. */ +int +app_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen) +{ + if (pk) + *pk = NULL; + if (pklen) + *pklen = 0; + + if (!app || !keyid || !pk || !pklen) + return gpg_error (GPG_ERR_INV_VALUE); + if (!app->initialized) + return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); + if (!app->fnc.readkey) + return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); + + return app->fnc.readkey (app, keyid, pk, pklen); +} + + /* Perform a GETATTR operation. */ int app_getattr (APP app, CTRL ctrl, const char *name) diff --git a/scd/command.c b/scd/command.c index b41e7aa16..72f48b2b8 100644 --- a/scd/command.c +++ b/scd/command.c @@ -1,5 +1,5 @@ /* command.c - SCdaemon command handler - * Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + * Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -494,9 +494,9 @@ cmd_readcert (ASSUAN_CONTEXT ctx, char *line) Return the public key for the given cert or key ID as an standard S-Expression. */ static int -cmd_readkey (ASSUAN_CONTEXT ctx, char *line) +cmd_readkey (assuan_context_t ctx, char *line) { - CTRL ctrl = assuan_get_pointer (ctx); + ctrl_t ctrl = assuan_get_pointer (ctx); int rc; unsigned char *cert = NULL; size_t ncert, n; @@ -509,9 +509,31 @@ cmd_readkey (ASSUAN_CONTEXT ctx, char *line) line = xstrdup (line); /* Need a copy of the line. */ if (ctrl->app_ctx) { - rc = app_readcert (ctrl->app_ctx, line, &cert, &ncert); - if (rc) - log_error ("app_readcert failed: %s\n", gpg_strerror (rc)); + unsigned char *pk; + size_t pklen; + + /* If the application supports the READKEY function we use that. + Otherwise we use the old way by extracting it from the + certificate. */ + rc = app_readkey (ctrl->app_ctx, line, &pk, &pklen); + if (!rc) + { /* Yeah, got that key - send it back. */ + rc = assuan_send_data (ctx, pk, pklen); + xfree (pk); + rc = map_assuan_err (rc); + xfree (line); + line = NULL; + goto leave; + } + + if (gpg_err_code (rc) != GPG_ERR_UNSUPPORTED_OPERATION) + log_error ("app_readkey failed: %s\n", gpg_strerror (rc)); + else + { + rc = app_readcert (ctrl->app_ctx, line, &cert, &ncert); + if (rc) + log_error ("app_readcert failed: %s\n", gpg_strerror (rc)); + } } else { -- cgit From 3af261572bdf938f0a2fdde4d9aec82153a7e0e4 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 24 Feb 2005 17:36:11 +0000 Subject: * gpg-agent.c (handle_connections): Need to check for events if select returns with -1. * tools.texi (gpg-connect-agent): New. * app-openpgp.c (get_one_do): Never try to get a non cacheable object from the cache. (get_one_do): Add new arg to return an error code. Changed all callers. (do_getattr): Let it return a proper error code. * app.c (select_application): Return an error code and the application context in an new arg. * command.c (open_card): Adjusted for that. Don't use the fallback if no card is present. Return an error if the card has been removed without a reset. (do_reset, cmd_serialno): Clear that error flag. (TEST_CARD_REMOVAL): New. Use it with all command handlers. * scdaemon.c (ticker_thread): Termintate if a shutdown is pending. * apdu.c: Added some PCSC error codes. (pcsc_error_to_sw): New. (reset_pcsc_reader, pcsc_get_status, pcsc_send_apdu) (open_pcsc_reader): Do proper error code mapping. * gpg-connect-agent.c: New. * Makefile.am: Add it. --- agent/ChangeLog | 5 + agent/gpg-agent.c | 5 + common/simple-pwquery.c | 2 +- common/xreadline.c | 2 +- doc/ChangeLog | 4 + doc/gpg-agent.texi | 14 +- doc/tools.texi | 62 +++++++ scd/ChangeLog | 23 +++ scd/apdu.c | 419 +++++++++++++++++++++++++++------------------- scd/app-common.h | 3 +- scd/app-openpgp.c | 45 +++-- scd/app.c | 28 ++-- scd/command.c | 81 +++++++-- scd/scdaemon.c | 3 +- tests/asschk.c | 4 +- tools/ChangeLog | 5 + tools/Makefile.am | 13 +- tools/gpg-connect-agent.c | 362 +++++++++++++++++++++++++++++++++++++++ 18 files changed, 840 insertions(+), 240 deletions(-) create mode 100644 tools/gpg-connect-agent.c (limited to 'scd/app-openpgp.c') diff --git a/agent/ChangeLog b/agent/ChangeLog index 47ca2debf..775a44489 100644 --- a/agent/ChangeLog +++ b/agent/ChangeLog @@ -1,3 +1,8 @@ +2005-02-24 Werner Koch + + * gpg-agent.c (handle_connections): Need to check for events if + select returns with -1. + 2005-02-23 Werner Koch * command-ssh.c (get_passphrase): Removed. diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c index 338248d1a..113489306 100644 --- a/agent/gpg-agent.c +++ b/agent/gpg-agent.c @@ -1463,6 +1463,11 @@ handle_connections (int listen_fd, int listen_fd_ssh) ret = pth_select_ev (FD_SETSIZE, &read_fdset, NULL, NULL, NULL, ev); if (ret == -1) { + if (pth_event_occurred (ev)) + { + handle_signal (signo); + continue; + } log_error (_("pth_select failed: %s - waiting 1s\n"), strerror (errno)); pth_sleep (1); diff --git a/common/simple-pwquery.c b/common/simple-pwquery.c index 0b70ddecc..37a45816c 100644 --- a/common/simple-pwquery.c +++ b/common/simple-pwquery.c @@ -1,4 +1,4 @@ -/* simple-pwquery.c - A simple password query cleint for gpg-agent +/* simple-pwquery.c - A simple password query client for gpg-agent * Copyright (C) 2002, 2004 Free Software Foundation, Inc. * * This file is part of GnuPG. diff --git a/common/xreadline.c b/common/xreadline.c index 85f0af02e..23aa35269 100644 --- a/common/xreadline.c +++ b/common/xreadline.c @@ -39,7 +39,7 @@ memory was enable and ERRNO is set accordingly. If a line has been truncated, the file pointer is moved forward to - the end of the line so that the next read start with tghe next + the end of the line so that the next read start with the next line. Note that MAX_LENGTH must be re-initialzied in this case.. Note: The returned buffer is allocated with enough extra space to diff --git a/doc/ChangeLog b/doc/ChangeLog index 49e8b026f..07f94f338 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,7 @@ +2005-02-24 Werner Koch + + * tools.texi (gpg-connect-agent): New. + 2005-02-14 Werner Koch * gpgsm.texi (Certificate Management): Document --import. diff --git a/doc/gpg-agent.texi b/doc/gpg-agent.texi index 01b4227c6..17bd59c7a 100644 --- a/doc/gpg-agent.texi +++ b/doc/gpg-agent.texi @@ -326,10 +326,8 @@ Ignore requests to change change the current @sc{tty} respective the X window system's @code{DISPLAY} variable. This is useful to lock the pinentry to pop up at the @sc{tty} or display you started the agent. -@item --ssh-support -@itemx --ssh-support -@opindex ssh-support -@opindex ssh +@item --enable-ssh-support +@opindex enable-ssh-support Enable emulation of the OpenSSH Agent protocol. @@ -350,13 +348,11 @@ Once, a key has been added to the gpg-agent this way, the gpg-agent will be ready to use the key. Note: in case the gpg-agent receives a signature request, the user -might need to be prompted for a passphrased, which is necessary for +might need to be prompted for a passphrase, which is necessary for decrypting the stored key. Since the ssh-agent protocol does not contain a mechanism for telling the agent on which display/terminal it -is running, gpg-agent's --ssh-support switch implies --keep-display -and --keep-tty. This strategy causes the gpg-agent to open a pinentry -on the display or on the terminal, on which it (the gpg-agent) was -started. +is running, gpg-agent's ssh-support will use the TTY or X display where +gpg-agent has been started. @end table diff --git a/doc/tools.texi b/doc/tools.texi index 684975e19..7c963622f 100644 --- a/doc/tools.texi +++ b/doc/tools.texi @@ -13,6 +13,7 @@ GnuPG comes with a couple of smaller tools: * gpgconf:: Modify .gnupg home directories. * gpgsm-gencert.sh:: Generate an X.509 certificate request. * gpg-preset-passphrase:: Put a passphrase into the cache. +* gpg-connect-agent:: Communicate with a running agent. @end menu @c @@ -665,3 +666,64 @@ for other users. + +@c +@c GPG-CONNECT-AGENT +@c +@node gpg-connect-agent +@section Communicate with a runnig agent. + +The @command{gpg-connect-agent} is a utility to communicate with a +running @command{gpg-agent}. It is useful to check out the commands +gpg-agent provides using the Assuan interface. It might also be useful +for scripting simple applications. Inputis expected at stdin and out +put gets printed to stdout. + +It is very similar to running @command{gpg-agent} in server mode; but +here we connect to a running instance. + +@menu +* Invoking gpg-connect-agent:: List of all commands and options. +@end menu + + +@node Invoking gpg-connect-agent +@subsection List of all commands and options. + +@noindent +@command{gpg-connect-agent} is invoked this way: + +@example +gpg-connect-agent [options] +@end example + +@noindent +The following options may be used: + +@table @gnupgtabopt +@item -v +@itemx --verbose +@opindex verbose +Output additional information while running. + +@item -q +@item --quiet +@opindex q +@opindex quiet +Try to be as quiet as possible. + +@item --homedir @var{dir} +@opindex homedir +Set the name of the home directory to @var{dir}. If his option is not +used, the home directory defaults to @file{~/.gnupg}. It is only +recognized when given on the command line. It also overrides any home +directory stated through the environment variable @env{GNUPGHOME} or +(on W32 systems) by means on the Registry entry +@var{HKCU\Software\GNU\GnuPG:HomeDir}. + + +@end table + + + + diff --git a/scd/ChangeLog b/scd/ChangeLog index 054463d6d..c78bd011f 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,26 @@ +2005-02-24 Werner Koch + + * app-openpgp.c (get_one_do): Never try to get a non cacheable + object from the cache. + (get_one_do): Add new arg to return an error code. Changed all + callers. + (do_getattr): Let it return a proper error code. + + * app.c (select_application): Return an error code and the + application context in an new arg. + * command.c (open_card): Adjusted for that. Don't use the + fallback if no card is present. Return an error if the card has + been removed without a reset. + (do_reset, cmd_serialno): Clear that error flag. + (TEST_CARD_REMOVAL): New. Use it with all command handlers. + + * scdaemon.c (ticker_thread): Termintate if a shutdown is pending. + + * apdu.c: Added some PCSC error codes. + (pcsc_error_to_sw): New. + (reset_pcsc_reader, pcsc_get_status, pcsc_send_apdu) + (open_pcsc_reader): Do proper error code mapping. + 2005-02-22 Werner Koch * app-openpgp.c (app_local_s): New field PK. diff --git a/scd/apdu.c b/scd/apdu.c index 040de1461..33b0802c1 100644 --- a/scd/apdu.c +++ b/scd/apdu.c @@ -74,7 +74,7 @@ #endif #endif - + #define MAX_READER 4 /* Number of readers we support concurrently. */ @@ -158,14 +158,14 @@ static char (* DLSTDCALL CT_data) (unsigned short ctn, unsigned char *dad, static char (* DLSTDCALL CT_close) (unsigned short ctn); /* PC/SC constants and function pointer. */ -#define PCSC_SCOPE_USER 0 -#define PCSC_SCOPE_TERMINAL 1 -#define PCSC_SCOPE_SYSTEM 2 -#define PCSC_SCOPE_GLOBAL 3 +#define PCSC_SCOPE_USER 0 +#define PCSC_SCOPE_TERMINAL 1 +#define PCSC_SCOPE_SYSTEM 2 +#define PCSC_SCOPE_GLOBAL 3 -#define PCSC_PROTOCOL_T0 1 -#define PCSC_PROTOCOL_T1 2 -#define PCSC_PROTOCOL_RAW 4 +#define PCSC_PROTOCOL_T0 1 +#define PCSC_PROTOCOL_T1 2 +#define PCSC_PROTOCOL_RAW 4 #define PCSC_SHARE_EXCLUSIVE 1 #define PCSC_SHARE_SHARED 2 @@ -176,7 +176,7 @@ static char (* DLSTDCALL CT_close) (unsigned short ctn); #define PCSC_UNPOWER_CARD 2 #define PCSC_EJECT_CARD 3 -#define PCSC_UNKNOWN 0x0001 +#define PCSC_UNKNOWN 0x0001 #define PCSC_ABSENT 0x0002 /* Card is absent. */ #define PCSC_PRESENT 0x0004 /* Card is present. */ #define PCSC_SWALLOWED 0x0008 /* Card is present and electrical connected. */ @@ -196,10 +196,32 @@ static char (* DLSTDCALL CT_close) (unsigned short ctn); #define PCSC_STATE_INUSE 0x0100 /* Shared mode. */ #define PCSC_STATE_MUTE 0x0200 /* Unresponsive card. */ - -struct pcsc_io_request_s +/* Some PC/SC error codes. */ +#define PCSC_E_CANCELLED 0x80100002 +#define PCSC_E_CANT_DISPOSE 0x8010000E +#define PCSC_E_INSUFFICIENT_BUFFER 0x80100008 +#define PCSC_E_INVALID_ATR 0x80100015 +#define PCSC_E_INVALID_HANDLE 0x80100003 +#define PCSC_E_INVALID_PARAMETER 0x80100004 +#define PCSC_E_INVALID_TARGET 0x80100005 +#define PCSC_E_INVALID_VALUE 0x80100011 +#define PCSC_E_NO_MEMORY 0x80100006 +#define PCSC_E_UNKNOWN_READER 0x80100009 +#define PCSC_E_TIMEOUT 0x8010000A +#define PCSC_E_SHARING_VIOLATION 0x8010000B +#define PCSC_E_NO_SMARTCARD 0x8010000C +#define PCSC_E_UNKNOWN_CARD 0x8010000D +#define PCSC_E_PROTO_MISMATCH 0x8010000F +#define PCSC_E_NOT_READY 0x80100010 +#define PCSC_E_SYSTEM_CANCELLED 0x80100012 +#define PCSC_E_NOT_TRANSACTED 0x80100016 +#define PCSC_E_READER_UNAVAILABLE 0x80100017 +#define PCSC_W_REMOVED_CARD 0x80100069 + + +struct pcsc_io_request_s { - unsigned long protocol; + unsigned long protocol; unsigned long pci_len; }; @@ -262,15 +284,15 @@ long (* DLSTDCALL pcsc_set_timeout) (unsigned long context, -/* +/* Helper */ - + /* Find an unused reader slot for PORTSTR and put it into the reader table. Return -1 on error or the index into the reader table. */ -static int -new_reader_slot (void) +static int +new_reader_slot (void) { int i, reader = -1; @@ -387,8 +409,8 @@ apdu_strerror (int rc) -/* - ct API Interface +/* + ct API Interface */ static const char * @@ -425,9 +447,9 @@ ct_activate_card (int slot) int rc; unsigned char dad[1], sad[1], cmd[11], buf[256]; unsigned short buflen; - + /* Check whether card has been inserted. */ - dad[0] = 1; /* Destination address: CT. */ + dad[0] = 1; /* Destination address: CT. */ sad[0] = 2; /* Source address: Host. */ cmd[0] = 0x20; /* Class byte. */ @@ -446,8 +468,8 @@ ct_activate_card (int slot) return SW_HOST_CARD_IO_ERROR; } - /* Connected, now activate the card. */ - dad[0] = 1; /* Destination address: CT. */ + /* Connected, now activate the card. */ + dad[0] = 1; /* Destination address: CT. */ sad[0] = 2; /* Source address: Host. */ cmd[0] = 0x20; /* Class byte. */ @@ -517,13 +539,13 @@ ct_send_apdu (int slot, unsigned char *apdu, size_t apdulen, int rc; unsigned char dad[1], sad[1]; unsigned short ctbuflen; - + /* If we don't have an ATR, we need to reset the reader first. */ if (!reader_table[slot].atrlen && (rc = reset_ct_reader (slot))) return rc; - dad[0] = 0; /* Destination address: Card. */ + dad[0] = 0; /* Destination address: Card. */ sad[0] = 2; /* Source address: Host. */ ctbuflen = *buflen; if (DBG_CARD_IO) @@ -582,6 +604,10 @@ open_ct_reader (int port) } +/* + PC/SC Interface + */ + #ifdef NEED_PCSC_WRAPPER static int writen (int fd, const void *buf, size_t nbytes) @@ -624,7 +650,7 @@ readn (int fd, void *buf, size_t buflen, size_t *nread) #else n = read (fd, buf, nleft); #endif - if (n < 0 && errno == EINTR) + if (n < 0 && errno == EINTR) continue; if (n < 0) return -1; /* read error. */ @@ -637,7 +663,7 @@ readn (int fd, void *buf, size_t buflen, size_t *nread) *nread = buflen - nleft; /* log_printhex (" readn:", orig_buf, *nread); */ - + return 0; } #endif /*NEED_PCSC_WRAPPER*/ @@ -656,48 +682,73 @@ pcsc_error_string (long err) { case 0x0002: s = "cancelled"; break; case 0x000e: s = "can't dispose"; break; - case 0x0008: s = "insufficient buffer"; break; + case 0x0008: s = "insufficient buffer"; break; case 0x0015: s = "invalid ATR"; break; case 0x0003: s = "invalid handle"; break; - case 0x0004: s = "invalid parameter"; break; + case 0x0004: s = "invalid parameter"; break; case 0x0005: s = "invalid target"; break; - case 0x0011: s = "invalid value"; break; - case 0x0006: s = "no memory"; break; - case 0x0013: s = "comm error"; break; - case 0x0001: s = "internal error"; break; - case 0x0014: s = "unknown error"; break; - case 0x0007: s = "waited too long"; break; + case 0x0011: s = "invalid value"; break; + case 0x0006: s = "no memory"; break; + case 0x0013: s = "comm error"; break; + case 0x0001: s = "internal error"; break; + case 0x0014: s = "unknown error"; break; + case 0x0007: s = "waited too long"; break; case 0x0009: s = "unknown reader"; break; - case 0x000a: s = "timeout"; break; - case 0x000b: s = "sharing violation"; break; + case 0x000a: s = "timeout"; break; + case 0x000b: s = "sharing violation"; break; case 0x000c: s = "no smartcard"; break; - case 0x000d: s = "unknown card"; break; - case 0x000f: s = "proto mismatch"; break; - case 0x0010: s = "not ready"; break; - case 0x0012: s = "system cancelled"; break; + case 0x000d: s = "unknown card"; break; + case 0x000f: s = "proto mismatch"; break; + case 0x0010: s = "not ready"; break; + case 0x0012: s = "system cancelled"; break; case 0x0016: s = "not transacted"; break; - case 0x0017: s = "reader unavailable"; break; - case 0x0065: s = "unsupported card"; break; - case 0x0066: s = "unresponsive card"; break; - case 0x0067: s = "unpowered card"; break; - case 0x0068: s = "reset card"; break; - case 0x0069: s = "removed card"; break; - case 0x006a: s = "inserted card"; break; - case 0x001f: s = "unsupported feature"; break; - case 0x0019: s = "PCI too small"; break; - case 0x001a: s = "reader unsupported"; break; - case 0x001b: s = "duplicate reader"; break; - case 0x001c: s = "card unsupported"; break; - case 0x001d: s = "no service"; break; - case 0x001e: s = "service stopped"; break; + case 0x0017: s = "reader unavailable"; break; + case 0x0065: s = "unsupported card"; break; + case 0x0066: s = "unresponsive card"; break; + case 0x0067: s = "unpowered card"; break; + case 0x0068: s = "reset card"; break; + case 0x0069: s = "removed card"; break; + case 0x006a: s = "inserted card"; break; + case 0x001f: s = "unsupported feature"; break; + case 0x0019: s = "PCI too small"; break; + case 0x001a: s = "reader unsupported"; break; + case 0x001b: s = "duplicate reader"; break; + case 0x001c: s = "card unsupported"; break; + case 0x001d: s = "no service"; break; + case 0x001e: s = "service stopped"; break; default: s = "unknown PC/SC error code"; break; } return s; } -/* - PC/SC Interface - */ +/* Map PC/SC error codes to our special host status words. */ +static int +pcsc_error_to_sw (long ec) +{ + int rc; + + switch (ec) + { + case 0: rc = 0; break; + + case PCSC_E_CANCELLED: rc = SW_HOST_ABORTED; break; + case PCSC_E_NO_MEMORY: rc = SW_HOST_OUT_OF_CORE; break; + case PCSC_E_TIMEOUT: rc = SW_HOST_CARD_IO_ERROR; break; + case PCSC_E_SHARING_VIOLATION: rc = SW_HOST_LOCKING_FAILED; break; + case PCSC_E_NO_SMARTCARD: rc = SW_HOST_NO_CARD; break; + case PCSC_W_REMOVED_CARD: rc = SW_HOST_NO_CARD; break; + + case PCSC_E_INVALID_TARGET: + case PCSC_E_INVALID_VALUE: + case PCSC_E_INVALID_HANDLE: + case PCSC_E_INVALID_PARAMETER: + case PCSC_E_INSUFFICIENT_BUFFER: rc = SW_HOST_INV_VALUE; break; + + default: rc = SW_HOST_GENERAL_ERROR; break; + } + + return rc; +} static void dump_pcsc_reader_status (int slot) @@ -713,6 +764,8 @@ dump_pcsc_reader_status (int slot) } +/* Send an PC/SC reset command and return a status word on error or 0 + on success. */ static int reset_pcsc_reader (int slot) { @@ -722,15 +775,16 @@ reset_pcsc_reader (int slot) size_t len; int i, n; unsigned char msgbuf[9]; + int sw = SW_HOST_CARD_IO_ERROR; slotp = reader_table + slot; - if (slotp->pcsc.req_fd == -1 - || slotp->pcsc.rsp_fd == -1 + if (slotp->pcsc.req_fd == -1 + || slotp->pcsc.rsp_fd == -1 || slotp->pcsc.pid == (pid_t)(-1) ) { log_error ("pcsc_get_status: pcsc-wrapper not running\n"); - return SW_HOST_CARD_IO_ERROR; + return sw; } msgbuf[0] = 0x05; /* RESET command. */ @@ -763,16 +817,23 @@ reset_pcsc_reader (int slot) if (len > DIM (slotp->atr)) { log_error ("PC/SC returned a too large ATR (len=%x)\n", len); + sw = SW_HOST_GENERAL_ERROR; goto command_failed; } err = (msgbuf[5] << 24) | (msgbuf[6] << 16) | (msgbuf[7] << 8 ) | msgbuf[8]; if (err) { - log_error ("PC/SC RESET failed: %s\n", pcsc_error_string (err)); + log_error ("PC/SC RESET failed: %s (0x%lx)\n", + pcsc_error_string (err), err); + /* If the error code is no smart card, we should not considere + this a major error and close the wrapper. */ + sw = pcsc_error_to_sw (err); + if (err == PCSC_E_NO_SMARTCARD) + return sw; goto command_failed; } - /* The open fucntion may return a zero for the ATR length to + /* The open function may return a zero for the ATR length to indicate that no card is present. */ n = len; if (n) @@ -796,7 +857,7 @@ reset_pcsc_reader (int slot) kill (slotp->pcsc.pid, SIGTERM); slotp->pcsc.pid = (pid_t)(-1); slotp->used = 0; - return -1; + return sw; #else /* !NEED_PCSC_WRAPPER */ long err; @@ -827,10 +888,10 @@ reset_pcsc_reader (int slot) log_error ("pcsc_connect failed: %s (0x%lx)\n", pcsc_error_string (err), err); reader_table[slot].pcsc.card = 0; - return SW_HOST_CARD_IO_ERROR; - } + return pcsc_error_to_sw (err); + } + - atrlen = 33; nreader = sizeof reader - 1; err = pcsc_status (reader_table[slot].pcsc.card, @@ -842,7 +903,7 @@ reset_pcsc_reader (int slot) log_error ("pcsc_status failed: %s (0x%lx)\n", pcsc_error_string (err), err); reader_table[slot].atrlen = 0; - return SW_HOST_CARD_IO_ERROR; + return pcsc_error_to_sw (err); } if (atrlen >= DIM (reader_table[0].atr)) log_bug ("ATR returned by pcsc_status is too large\n"); @@ -863,15 +924,16 @@ pcsc_get_status (int slot, unsigned int *status) int i, n; unsigned char msgbuf[9]; unsigned char buffer[12]; + int sw = SW_HOST_CARD_IO_ERROR; slotp = reader_table + slot; - if (slotp->pcsc.req_fd == -1 - || slotp->pcsc.rsp_fd == -1 + if (slotp->pcsc.req_fd == -1 + || slotp->pcsc.rsp_fd == -1 || slotp->pcsc.pid == (pid_t)(-1) ) { log_error ("pcsc_get_status: pcsc-wrapper not running\n"); - return SW_HOST_CARD_IO_ERROR; + return sw; } msgbuf[0] = 0x04; /* STATUS command. */ @@ -906,11 +968,12 @@ pcsc_get_status (int slot, unsigned int *status) { log_error ("pcsc_status failed: %s (0x%lx)\n", pcsc_error_string (err), err); - return SW_HOST_CARD_IO_ERROR; + /* This is a proper error code, so return immediately. */ + return pcsc_error_to_sw (err); } full_len = len; - + n = 8 < len ? 8 : len; if ((i=readn (slotp->pcsc.rsp_fd, buffer, n, &len)) || len != 8) { @@ -935,7 +998,7 @@ pcsc_get_status (int slot, unsigned int *status) } full_len -= n; } - + /* We are lucky: The wrapper already returns the data in the required format. */ *status = buffer[3]; @@ -950,26 +1013,26 @@ pcsc_get_status (int slot, unsigned int *status) kill (slotp->pcsc.pid, SIGTERM); slotp->pcsc.pid = (pid_t)(-1); slotp->used = 0; - return -1; + return sw; #else /*!NEED_PCSC_WRAPPER*/ long err; struct pcsc_readerstate_s rdrstates[1]; - + memset (rdrstates, 0, sizeof *rdrstates); rdrstates[0].reader = reader_table[slot].rdrname; rdrstates[0].current_state = PCSC_STATE_UNAWARE; err = pcsc_get_status_change (reader_table[slot].pcsc.context, 0, rdrstates, 1); - if (err == 0x8010000a) /* Timeout. */ - err = 0; + if (err == PCSC_E_TIMEOUT) + err = 0; /* Timeout is no error error here. */ if (err) { log_error ("pcsc_get_status_change failed: %s (0x%lx)\n", pcsc_error_string (err), err); - return SW_HOST_CARD_IO_ERROR; + return pcsc_error_to_sw (err); } @@ -997,8 +1060,8 @@ pcsc_get_status (int slot, unsigned int *status) if ( (*status & 6) == 6 && !(rdrstates[0].event_state & PCSC_STATE_INUSE) ) *status |= 1; - - return 0; + + return 0; #endif /*!NEED_PCSC_WRAPPER*/ } @@ -1016,6 +1079,7 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen, size_t len, full_len; int i, n; unsigned char msgbuf[9]; + int sw = SW_HOST_CARD_IO_ERROR; if (!reader_table[slot].atrlen && (err = reset_pcsc_reader (slot))) @@ -1026,12 +1090,12 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen, slotp = reader_table + slot; - if (slotp->pcsc.req_fd == -1 - || slotp->pcsc.rsp_fd == -1 + if (slotp->pcsc.req_fd == -1 + || slotp->pcsc.rsp_fd == -1 || slotp->pcsc.pid == (pid_t)(-1) ) { log_error ("pcsc_send_apdu: pcsc-wrapper not running\n"); - return SW_HOST_CARD_IO_ERROR; + return sw; } msgbuf[0] = 0x03; /* TRANSMIT command. */ @@ -1067,11 +1131,11 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen, { log_error ("pcsc_transmit failed: %s (0x%lx)\n", pcsc_error_string (err), err); - return SW_HOST_CARD_IO_ERROR; + return pcsc_error_to_sw (err); } full_len = len; - + n = *buflen < len ? *buflen : len; if ((i=readn (slotp->pcsc.rsp_fd, buffer, n, &len)) || len != n) { @@ -1113,14 +1177,14 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen, kill (slotp->pcsc.pid, SIGTERM); slotp->pcsc.pid = (pid_t)(-1); slotp->used = 0; - return -1; + return sw; #else /*!NEED_PCSC_WRAPPER*/ long err; struct pcsc_io_request_s send_pci; unsigned long recv_len; - + if (!reader_table[slot].atrlen && (err = reset_pcsc_reader (slot))) return err; @@ -1141,8 +1205,8 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen, if (err) log_error ("pcsc_transmit failed: %s (0x%lx)\n", pcsc_error_string (err), err); - - return err? SW_HOST_CARD_IO_ERROR:0; + + return pcsc_error_to_sw (err); #endif /*!NEED_PCSC_WRAPPER*/ } @@ -1159,8 +1223,8 @@ close_pcsc_reader (int slot) slotp = reader_table + slot; - if (slotp->pcsc.req_fd == -1 - || slotp->pcsc.rsp_fd == -1 + if (slotp->pcsc.req_fd == -1 + || slotp->pcsc.rsp_fd == -1 || slotp->pcsc.pid == (pid_t)(-1) ) { log_error ("close_pcsc_reader: pcsc-wrapper not running\n"); @@ -1198,10 +1262,10 @@ close_pcsc_reader (int slot) if (err) log_error ("pcsc_close failed: %s (0x%lx)\n", pcsc_error_string (err), err); - - /* We will the wrapper in any case - errors are merely + + /* We will close the wrapper in any case - errors are merely informational. */ - + command_failed: close (slotp->pcsc.req_fd); close (slotp->pcsc.rsp_fd); @@ -1222,6 +1286,7 @@ close_pcsc_reader (int slot) #endif /*!NEED_PCSC_WRAPPER*/ } +/* Note: It is a pitty that we can't return proper error codes. */ static int open_pcsc_reader (const char *portstr) { @@ -1237,6 +1302,7 @@ open_pcsc_reader (const char *portstr) size_t len; unsigned char msgbuf[9]; int err; + int sw = SW_HOST_CARD_IO_ERROR; slot = new_reader_slot (); if (slot == -1) @@ -1246,7 +1312,7 @@ open_pcsc_reader (const char *portstr) /* Fire up the pcsc wrapper. We don't use any fork/exec code from the common directy but implement it direclty so that this file may still be source copied. */ - + if (pipe (rp) == -1) { log_error ("error creating a pipe: %s\n", strerror (errno)); @@ -1261,7 +1327,7 @@ open_pcsc_reader (const char *portstr) slotp->used = 0; return -1; } - + pid = fork (); if (pid == -1) { @@ -1283,7 +1349,7 @@ open_pcsc_reader (const char *portstr) /* Double fork. */ pid = fork (); if (pid == -1) - _exit (31); + _exit (31); if (pid) _exit (0); /* Immediate exit this parent, so that the child gets cleaned up by the init process. */ @@ -1293,7 +1359,7 @@ open_pcsc_reader (const char *portstr) log_fatal ("dup2 stdin failed: %s\n", strerror (errno)); if (rp[1] != 1 && dup2 (rp[1], 1) == -1) log_fatal ("dup2 stdout failed: %s\n", strerror (errno)); - + /* Send stderr to the bit bucket. */ fd = open ("/dev/null", O_WRONLY); if (fd == -1) @@ -1318,7 +1384,7 @@ open_pcsc_reader (const char *portstr) _exit (31); } - /* + /* === Parent === */ close (wp[0]); @@ -1328,9 +1394,9 @@ open_pcsc_reader (const char *portstr) /* Wait for the intermediate child to terminate. */ #ifdef USE_GNU_PTH -#define WAIT pth_waitpid +#define WAIT pth_waitpid #else -#define WAIT waitpid +#define WAIT waitpid #endif while ( (i=WAIT (pid, NULL, 0)) == -1 && errno == EINTR) ; @@ -1373,6 +1439,7 @@ open_pcsc_reader (const char *portstr) if (err) { log_error ("PC/SC OPEN failed: %s\n", pcsc_error_string (err)); + sw = pcsc_error_to_sw (err); goto command_failed; } @@ -1401,7 +1468,7 @@ open_pcsc_reader (const char *portstr) reader_table[slot].send_apdu_reader = pcsc_send_apdu; reader_table[slot].dump_status_reader = dump_pcsc_reader_status; - dump_reader_status (slot); + dump_reader_status (slot); return slot; command_failed: @@ -1412,7 +1479,9 @@ open_pcsc_reader (const char *portstr) kill (slotp->pcsc.pid, SIGTERM); slotp->pcsc.pid = (pid_t)(-1); slotp->used = 0; + /* There is no way to return SW. */ return -1; + #else /*!NEED_PCSC_WRAPPER */ long err; int slot; @@ -1434,7 +1503,7 @@ open_pcsc_reader (const char *portstr) reader_table[slot].used = 0; return -1; } - + err = pcsc_list_readers (reader_table[slot].pcsc.context, NULL, NULL, &nreader); if (!err) @@ -1445,7 +1514,7 @@ open_pcsc_reader (const char *portstr) log_error ("error allocating memory for reader list\n"); pcsc_release_context (reader_table[slot].pcsc.context); reader_table[slot].used = 0; - return -1; + return -1 /*SW_HOST_OUT_OF_CORE*/; } err = pcsc_list_readers (reader_table[slot].pcsc.context, NULL, list, &nreader); @@ -1457,7 +1526,7 @@ open_pcsc_reader (const char *portstr) pcsc_release_context (reader_table[slot].pcsc.context); reader_table[slot].used = 0; xfree (list); - return -1; + return -1 /*pcsc_error_to_sw (err)*/; } listlen = nreader; @@ -1483,7 +1552,7 @@ open_pcsc_reader (const char *portstr) log_error ("error allocating memory for reader name\n"); pcsc_release_context (reader_table[slot].pcsc.context); reader_table[slot].used = 0; - return -1; + return -1 /*SW_HOST_OUT_OF_CORE*/; } strcpy (reader_table[slot].rdrname, portstr? portstr : list); xfree (list); @@ -1494,7 +1563,7 @@ open_pcsc_reader (const char *portstr) PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1, &reader_table[slot].pcsc.card, &reader_table[slot].pcsc.protocol); - if (err == 0x8010000c) /* No smartcard. */ + if (err == PCSC_E_NO_SMARTCARD) reader_table[slot].pcsc.card = 0; else if (err) { @@ -1505,8 +1574,8 @@ open_pcsc_reader (const char *portstr) reader_table[slot].rdrname = NULL; reader_table[slot].used = 0; xfree (list); - return -1; - } + return -1 /*pcsc_error_to_sw (err)*/; + } reader_table[slot].atrlen = 0; reader_table[slot].last_status = 0; @@ -1544,7 +1613,7 @@ open_pcsc_reader (const char *portstr) /* log_debug ("state from pcsc_status: 0x%lx\n", card_state); */ /* log_debug ("protocol from pcsc_status: 0x%lx\n", card_protocol); */ - dump_reader_status (slot); + dump_reader_status (slot); return slot; #endif /*!NEED_PCSC_WRAPPER */ } @@ -1553,7 +1622,7 @@ open_pcsc_reader (const char *portstr) #ifdef HAVE_LIBUSB -/* +/* Internal CCID driver interface. */ @@ -1570,16 +1639,16 @@ close_ccid_reader (int slot) ccid_close_reader (reader_table[slot].ccid.handle); reader_table[slot].used = 0; return 0; -} - +} + static int shutdown_ccid_reader (int slot) { ccid_shutdown_reader (reader_table[slot].ccid.handle); return 0; -} - +} + static int reset_ccid_reader (int slot) @@ -1596,10 +1665,10 @@ reset_ccid_reader (int slot) assert (sizeof slotp->atr >= sizeof atr); slotp->atrlen = atrlen; memcpy (slotp->atr, atr, atrlen); - dump_reader_status (slot); + dump_reader_status (slot); return 0; -} - +} + static int get_status_ccid (int slot, unsigned int *status) @@ -1615,7 +1684,7 @@ get_status_ccid (int slot, unsigned int *status) *status = 1|2|4; else if (bits == 1) *status = 2; - else + else *status = 0; return 0; @@ -1647,8 +1716,8 @@ send_apdu_ccid (int slot, unsigned char *apdu, size_t apdulen, if (err) log_error ("ccid_transceive failed: (0x%lx)\n", err); - - return err; + + return err; } /* Open the reader and try to read an ATR. */ @@ -1692,7 +1761,7 @@ open_ccid_reader (const char *portstr) reader_table[slot].send_apdu_reader = send_apdu_ccid; reader_table[slot].dump_status_reader = dump_ccid_reader_status; - dump_reader_status (slot); + dump_reader_status (slot); return slot; } @@ -1703,7 +1772,7 @@ open_ccid_reader (const char *portstr) #ifdef HAVE_OPENSC -/* +/* OpenSC Interface. This uses the OpenSC primitives to send APDUs. We need this @@ -1764,7 +1833,7 @@ osc_send_apdu (int slot, unsigned char *apdu, size_t apdulen, if (!apdulen) a.cse = SC_APDU_CASE_1; - else if (apdulen == 1) + else if (apdulen == 1) { a.le = *apdu? *apdu : 256; apdu++; apdulen--; @@ -1784,7 +1853,7 @@ osc_send_apdu (int slot, unsigned char *apdu, size_t apdulen, a.data = data; a.datalen = a.lc; - + if (!apdulen) a.cse = SC_APDU_CASE_3_SHORT; else @@ -1861,7 +1930,7 @@ open_osc_reader (int portno) slotp->used = 0; return -1; } - + /* We want the standard ISO driver. */ /*FIXME: OpenSC does not like "iso7816", so we use EMV for now. */ err = sc_set_card_driver(slotp->osc.ctx, "emv"); @@ -1912,7 +1981,7 @@ open_osc_reader (int portno) reader_table[slot].send_apdu_reader = osc_send_apdu; reader_table[slot].dump_status_reader = NULL; - dump_reader_status (slot); + dump_reader_status (slot); return slot; } @@ -1921,7 +1990,7 @@ open_osc_reader (int portno) #ifdef USE_G10CODE_RAPDU -/* +/* The Remote APDU Interface. This uses the Remote APDU protocol to contact a reader. @@ -1940,9 +2009,9 @@ rapdu_status_to_sw (int status) { case RAPDU_STATUS_SUCCESS: rc = 0; break; - case RAPDU_STATUS_INVCMD: - case RAPDU_STATUS_INVPROT: - case RAPDU_STATUS_INVSEQ: + case RAPDU_STATUS_INVCMD: + case RAPDU_STATUS_INVPROT: + case RAPDU_STATUS_INVSEQ: case RAPDU_STATUS_INVCOOKIE: case RAPDU_STATUS_INVREADER: rc = SW_HOST_INV_VALUE; break; @@ -2007,7 +2076,7 @@ reset_rapdu_reader (int slot) { log_error ("ATR returned by the RAPDU layer is too large\n"); rapdu_msg_release (msg); - return SW_HOST_INV_VALUE; + return SW_HOST_INV_VALUE; } slotp->atrlen = msg->datalen; memcpy (slotp->atr, msg->data, msg->datalen); @@ -2107,12 +2176,12 @@ my_rapdu_send_apdu (int slot, unsigned char *apdu, size_t apdulen, rapdu_msg_release (msg); return sw; } - + if (msg->datalen > maxlen) { log_error ("rapdu response apdu too large\n"); rapdu_msg_release (msg); - return SW_HOST_INV_VALUE; + return SW_HOST_INV_VALUE; } *buflen = msg->datalen; @@ -2196,11 +2265,11 @@ open_rapdu_reader (int portno, reader_table[slot].send_apdu_reader = my_rapdu_send_apdu; reader_table[slot].dump_status_reader = NULL; - dump_reader_status (slot); + dump_reader_status (slot); rapdu_msg_release (msg); return slot; - failure: + failure: rapdu_msg_release (msg); rapdu_release (slotp->rapdu.handle); slotp->used = 0; @@ -2211,7 +2280,7 @@ open_rapdu_reader (int portno, -/* +/* Driver Access */ @@ -2290,7 +2359,7 @@ apdu_open_reader (const char *portstr) return open_osc_reader (port); } -#endif /* HAVE_OPENSC */ +#endif /* HAVE_OPENSC */ if (opt.ctapi_driver && *opt.ctapi_driver) @@ -2300,7 +2369,7 @@ apdu_open_reader (const char *portstr) if (!ct_api_loaded) { void *handle; - + handle = dlopen (opt.ctapi_driver, RTLD_LAZY); if (!handle) { @@ -2322,7 +2391,7 @@ apdu_open_reader (const char *portstr) return open_ct_reader (port); } - + /* No ctAPI configured, so lets try the PC/SC API */ if (!pcsc_api_loaded) { @@ -2371,16 +2440,16 @@ apdu_open_reader (const char *portstr) pcsc_set_timeout = dlsym (handle, "SCardSetTimeout"); if (!pcsc_establish_context - || !pcsc_release_context - || !pcsc_list_readers + || !pcsc_release_context + || !pcsc_list_readers || !pcsc_get_status_change - || !pcsc_connect + || !pcsc_connect || !pcsc_reconnect || !pcsc_disconnect || !pcsc_status || !pcsc_begin_transaction || !pcsc_end_transaction - || !pcsc_transmit + || !pcsc_transmit /* || !pcsc_set_timeout */) { /* Note that set_timeout is currently not used and also not @@ -2388,21 +2457,21 @@ apdu_open_reader (const char *portstr) log_error ("apdu_open_reader: invalid PC/SC driver " "(%d%d%d%d%d%d%d%d%d%d%d%d)\n", !!pcsc_establish_context, - !!pcsc_release_context, - !!pcsc_list_readers, - !!pcsc_get_status_change, - !!pcsc_connect, - !!pcsc_reconnect, + !!pcsc_release_context, + !!pcsc_list_readers, + !!pcsc_get_status_change, + !!pcsc_connect, + !!pcsc_reconnect, !!pcsc_disconnect, !!pcsc_status, !!pcsc_begin_transaction, !!pcsc_end_transaction, - !!pcsc_transmit, + !!pcsc_transmit, !!pcsc_set_timeout ); dlclose (handle); return -1; } -#endif /*!NEED_PCSC_WRAPPER*/ +#endif /*!NEED_PCSC_WRAPPER*/ pcsc_api_loaded = 1; } @@ -2416,7 +2485,7 @@ apdu_open_reader (const char *portstr) only be called once and the slot will not be valid afther this. If PORTSTR is NULL we default to the first availabe port. -*/ +*/ int apdu_open_remote_reader (const char *portstr, const unsigned char *cookie, size_t length, @@ -2436,7 +2505,7 @@ apdu_open_remote_reader (const char *portstr, writefnc, writefnc_value, closefnc, closefnc_value); #else -#ifdef _WIN32 +#ifdef _WIN32 errno = ENOENT; #else errno = ENOSYS; @@ -2489,7 +2558,7 @@ apdu_reset (int slot) if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used ) return SW_HOST_NO_DRIVER; - + if ((sw = lock_slot (slot))) return sw; @@ -2521,7 +2590,7 @@ apdu_activate (int slot) if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used ) return SW_HOST_NO_DRIVER; - + if ((sw = trylock_slot (slot))) return sw; @@ -2550,12 +2619,12 @@ apdu_activate (int slot) } } } - + unlock_slot (slot); return sw; } - + unsigned char * apdu_get_atr (int slot, size_t *atrlen) @@ -2564,7 +2633,7 @@ apdu_get_atr (int slot, size_t *atrlen) if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used ) return NULL; - + buf = xtrymalloc (reader_table[slot].atrlen); if (!buf) return NULL; @@ -2574,7 +2643,7 @@ apdu_get_atr (int slot, size_t *atrlen) } - + /* Retrieve the status for SLOT. The function does only wait for the card to become available if HANG is set to true. On success the bits in STATUS will be set to @@ -2660,7 +2729,7 @@ send_apdu (int slot, unsigned char *apdu, size_t apdulen, returned data. The length of that data will be put into *RETBUFLEN. The caller is reponsible for releasing the buffer even in case of errors. */ -int +int apdu_send_le(int slot, int class, int ins, int p0, int p1, int lc, const char *data, int le, unsigned char **retbuf, size_t *retbuflen) @@ -2682,9 +2751,9 @@ apdu_send_le(int slot, int class, int ins, int p0, int p1, class, ins, p0, p1, lc, le); if (lc != -1 && (lc > 255 || lc < 0)) - return SW_WRONG_LENGTH; + return SW_WRONG_LENGTH; if (le != -1 && (le > 256 || le < 1)) - return SW_WRONG_LENGTH; + return SW_WRONG_LENGTH; if ((!data && lc != -1) || (data && lc == -1)) return SW_HOST_INV_VALUE; @@ -2764,7 +2833,7 @@ apdu_send_le(int slot, int class, int ins, int p0, int p1, do { int len = (sw & 0x00ff); - + if (DBG_CARD_IO) log_debug ("apdu_send_simple(%d): %d more bytes available\n", slot, len); @@ -2773,7 +2842,7 @@ apdu_send_le(int slot, int class, int ins, int p0, int p1, apdu[apdulen++] = 0xC0; apdu[apdulen++] = 0; apdu[apdulen++] = 0; - apdu[apdulen++] = len; + apdu[apdulen++] = len; memset (apdu+apdulen, 0, sizeof (apdu) - apdulen); resultlen = RESULTLEN; rc = send_apdu (slot, apdu, apdulen, result, &resultlen); @@ -2822,7 +2891,7 @@ apdu_send_le(int slot, int class, int ins, int p0, int p1, slot, sw); } while ((sw & 0xff00) == SW_MORE_DATA); - + if (retbuf) { *retbuflen = p - *retbuf; @@ -2836,7 +2905,7 @@ apdu_send_le(int slot, int class, int ins, int p0, int p1, if (DBG_CARD_IO && retbuf && sw == SW_SUCCESS) log_printhex (" dump: ", *retbuf, *retbuflen); - + return sw; #undef RESULTLEN } @@ -2850,11 +2919,11 @@ apdu_send_le(int slot, int class, int ins, int p0, int p1, data. The length of that data will be put into *RETBUFLEN. The caller is reponsible for releasing the buffer even in case of errors. */ -int +int apdu_send (int slot, int class, int ins, int p0, int p1, int lc, const char *data, unsigned char **retbuf, size_t *retbuflen) { - return apdu_send_le (slot, class, ins, p0, p1, lc, data, 256, + return apdu_send_le (slot, class, ins, p0, p1, lc, data, 256, retbuf, retbuflen); } @@ -2864,7 +2933,7 @@ apdu_send (int slot, int class, int ins, int p0, int p1, also be passed as NULL. The return value is the status word or -1 for an invalid SLOT or other non card related error. No data will be returned. */ -int +int apdu_send_simple (int slot, int class, int ins, int p0, int p1, int lc, const char *data) { @@ -2880,7 +2949,7 @@ apdu_send_simple (int slot, int class, int ins, int p0, int p1, the end. The function does not return a regular status word but 0 on success. If the slot is locked, the fucntion returns immediately.*/ -int +int apdu_send_direct (int slot, const unsigned char *apdudata, size_t apdudatalen, int handle_more, unsigned char **retbuf, size_t *retbuflen) @@ -2951,7 +3020,7 @@ apdu_send_direct (int slot, const unsigned char *apdudata, size_t apdudatalen, do { int len = (sw & 0x00ff); - + if (DBG_CARD_IO) log_debug ("apdu_send_direct(%d): %d more bytes available\n", slot, len); @@ -2960,7 +3029,7 @@ apdu_send_direct (int slot, const unsigned char *apdudata, size_t apdudatalen, apdu[apdulen++] = 0xC0; apdu[apdulen++] = 0; apdu[apdulen++] = 0; - apdu[apdulen++] = len; + apdu[apdulen++] = len; memset (apdu+apdulen, 0, sizeof (apdu) - apdulen); resultlen = RESULTLEN; rc = send_apdu (slot, apdu, apdulen, result, &resultlen); @@ -3009,7 +3078,7 @@ apdu_send_direct (int slot, const unsigned char *apdudata, size_t apdudatalen, slot, sw); } while ((sw & 0xff00) == SW_MORE_DATA); - + if (retbuf) { *retbuflen = p - *retbuf; @@ -3045,9 +3114,7 @@ apdu_send_direct (int slot, const unsigned char *apdudata, size_t apdudatalen, if (DBG_CARD_IO && retbuf) log_printhex (" dump: ", *retbuf, *retbuflen); - + return 0; #undef RESULTLEN } - - diff --git a/scd/app-common.h b/scd/app-common.h index ace57d98c..4a2adaa54 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -104,7 +104,8 @@ size_t app_help_read_length_of_cert (int slot, int fid, size_t *r_certoff); /*-- app.c --*/ -app_t select_application (ctrl_t ctrl, int slot, const char *name); +gpg_error_t select_application (ctrl_t ctrl, int slot, const char *name, + app_t *r_app); void release_application (app_t app); int app_munge_serialno (app_t app); int app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp); diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 8d146ba6a..14c802d10 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -306,23 +306,33 @@ flush_cache (app_t app) NULL if not found or a pointer which must be used to release the buffer holding value. */ static void * -get_one_do (app_t app, int tag, unsigned char **result, size_t *nbytes) +get_one_do (app_t app, int tag, unsigned char **result, size_t *nbytes, + int *r_rc) { int rc, i; unsigned char *buffer; size_t buflen; unsigned char *value; size_t valuelen; + int dummyrc; + + if (!r_rc) + r_rc = &dummyrc; *result = NULL; *nbytes = 0; + *r_rc = 0; for (i=0; data_objects[i].tag && data_objects[i].tag != tag; i++) ; if (app->card_version > 0x0100 && data_objects[i].get_immediate_in_v11) { - if( iso7816_get_data (app->slot, tag, &buffer, &buflen)) - return NULL; + rc = iso7816_get_data (app->slot, tag, &buffer, &buflen); + if (rc) + { + *r_rc = rc; + return NULL; + } *result = buffer; *nbytes = buflen; return buffer; @@ -334,7 +344,8 @@ get_one_do (app_t app, int tag, unsigned char **result, size_t *nbytes) { rc = get_cached_data (app, data_objects[i].get_from, &buffer, &buflen, - data_objects[i].get_immediate_in_v11); + (data_objects[i].dont_cache + || data_objects[i].get_immediate_in_v11)); if (!rc) { const unsigned char *s; @@ -356,7 +367,8 @@ get_one_do (app_t app, int tag, unsigned char **result, size_t *nbytes) if (!value) /* Not in a constructed DO, try simple. */ { rc = get_cached_data (app, tag, &buffer, &buflen, - data_objects[i].get_immediate_in_v11); + (data_objects[i].dont_cache + || data_objects[i].get_immediate_in_v11)); if (!rc) { value = buffer; @@ -370,6 +382,7 @@ get_one_do (app_t app, int tag, unsigned char **result, size_t *nbytes) *result = value; return buffer; } + *r_rc = rc; return NULL; } @@ -488,7 +501,7 @@ parse_login_data (app_t app) app->app_local->flags.def_chv2 = 0; /* Read the DO. */ - relptr = get_one_do (app, 0x005E, &buffer, &buflen); + relptr = get_one_do (app, 0x005E, &buffer, &buflen, NULL); if (!relptr) return; /* Ooops. */ for (; buflen; buflen--, buffer++) @@ -678,7 +691,7 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name) { "PRIVATE-DO-4", 0x0104 }, { NULL, 0 } }; - int idx, i; + int idx, i, rc; void *relptr; unsigned char *value; size_t valuelen; @@ -723,7 +736,7 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name) return 0; } - relptr = get_one_do (app, table[idx].tag, &value, &valuelen); + relptr = get_one_do (app, table[idx].tag, &value, &valuelen, &rc); if (relptr) { if (table[idx].special == 1) @@ -760,7 +773,7 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name) xfree (relptr); } - return 0; + return rc; } @@ -1075,7 +1088,7 @@ verify_chv3 (app_t app, unsigned char *value; size_t valuelen; - relptr = get_one_do (app, 0x00C4, &value, &valuelen); + relptr = get_one_do (app, 0x00C4, &value, &valuelen, NULL); if (!relptr || valuelen < 7) { log_error (_("error retrieving CHV status from card\n")); @@ -1442,7 +1455,7 @@ get_sig_counter (app_t app) size_t valuelen; unsigned long ul; - relptr = get_one_do (app, 0x0093, &value, &valuelen); + relptr = get_one_do (app, 0x0093, &value, &valuelen, NULL); if (!relptr) return 0; ul = convert_sig_counter_value (value, valuelen); @@ -1880,7 +1893,7 @@ app_select_openpgp (app_t app) goto leave; } - relptr = get_one_do (app, 0x00C4, &buffer, &buflen); + relptr = get_one_do (app, 0x00C4, &buffer, &buflen, NULL); if (!relptr) { log_error (_("can't access %s - invalid OpenPGP card?\n"), @@ -1890,7 +1903,7 @@ app_select_openpgp (app_t app) app->force_chv1 = (buflen && *buffer == 0); xfree (relptr); - relptr = get_one_do (app, 0x00C0, &buffer, &buflen); + relptr = get_one_do (app, 0x00C0, &buffer, &buflen, NULL); if (!relptr) { log_error (_("can't access %s - invalid OpenPGP card?\n"), @@ -1973,7 +1986,7 @@ app_openpgp_cardinfo (app_t app, if (disp_name) { *disp_name = NULL; - relptr = get_one_do (app, 0x005B, &value, &valuelen); + relptr = get_one_do (app, 0x005B, &value, &valuelen, NULL); if (relptr) { *disp_name = make_printable_string (value, valuelen, 0); @@ -1984,7 +1997,7 @@ app_openpgp_cardinfo (app_t app, if (pubkey_url) { *pubkey_url = NULL; - relptr = get_one_do (app, 0x5F50, &value, &valuelen); + relptr = get_one_do (app, 0x5F50, &value, &valuelen, NULL); if (relptr) { *pubkey_url = make_printable_string (value, valuelen, 0); @@ -1998,7 +2011,7 @@ app_openpgp_cardinfo (app_t app, *fpr2 = NULL; if (fpr3) *fpr3 = NULL; - relptr = get_one_do (app, 0x00C5, &value, &valuelen); + relptr = get_one_do (app, 0x00C5, &value, &valuelen, NULL); if (relptr && valuelen >= 60) { if (fpr1) diff --git a/scd/app.c b/scd/app.c index fad4eba55..857f9e10b 100644 --- a/scd/app.c +++ b/scd/app.c @@ -1,5 +1,5 @@ /* app.c - Application selection. - * Copyright (C) 2003, 2004 Free Software Foundation, Inc. + * Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -49,21 +49,23 @@ is_app_allowed (const char *name) /* If called with NAME as NULL, select the best fitting application and return a context; otherwise select the application with NAME and return a context. SLOT identifies the reader device. Returns - NULL if no application was found or no card is present. */ -APP -select_application (ctrl_t ctrl, int slot, const char *name) + an error code and stores NULL at R_APP if no application was found + or no card is present. */ +gpg_error_t +select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app) { int rc; - APP app; + app_t app; unsigned char *result = NULL; size_t resultlen; + *r_app = NULL; app = xtrycalloc (1, sizeof *app); if (!app) { - rc = gpg_error (gpg_err_code_from_errno (errno)); + rc = gpg_error_from_errno (errno); log_info ("error allocating context: %s\n", gpg_strerror (rc)); - return NULL; + return rc; } app->slot = slot; @@ -75,7 +77,7 @@ select_application (ctrl_t ctrl, int slot, const char *name) if (!rc) rc = iso7816_select_file (slot, 0x2F02, 0, NULL, NULL); if (!rc) - rc = iso7816_read_binary (slot, 0, 0, &result, &resultlen); + rc = iso7816_read_binary (slot, 0, 0, &result, &resultlen); if (!rc) { size_t n; @@ -111,7 +113,12 @@ select_application (ctrl_t ctrl, int slot, const char *name) result = NULL; } + /* For certain error codes, there is no need to try more. */ + if (gpg_err_code (rc) == GPG_ERR_CARD_NOT_PRESENT) + goto leave; + + /* Figure out the application to use. */ rc = gpg_error (GPG_ERR_NOT_FOUND); if (rc && is_app_allowed ("openpgp") && (!name || !strcmp (name, "openpgp"))) @@ -135,11 +142,12 @@ select_application (ctrl_t ctrl, int slot, const char *name) log_info ("no supported card application found: %s\n", gpg_strerror (rc)); xfree (app); - return NULL; + return rc; } app->initialized = 1; - return app; + *r_app = app; + return 0; } diff --git a/scd/command.c b/scd/command.c index 72f48b2b8..a4fb968cf 100644 --- a/scd/command.c +++ b/scd/command.c @@ -45,10 +45,24 @@ static ctrl_t primary_connection; #define set_error(e,t) assuan_set_error (ctx, ASSUAN_ ## e, (t)) + +/* Macro to flag a a removed card. */ +#define TEST_CARD_REMOVAL(c,r) \ + do { \ + int _r = (r); \ + if (gpg_err_code (_r) == GPG_ERR_CARD_NOT_PRESENT \ + || gpg_err_code (_r) == GPG_ERR_CARD_REMOVED) \ + (c)->server_local->card_removed = 1; \ + } while (0) + + /* Data used to associate an Assuan context with local server data */ struct server_local_s { - ASSUAN_CONTEXT assuan_ctx; + assuan_context_t assuan_ctx; int event_signal; /* Or 0 if not used. */ + int card_removed; /* True if the card has been removed and a + reset is required to continue + operation. */ }; @@ -89,6 +103,7 @@ do_reset (ctrl_t ctrl, int do_close) ctrl->reader_slot = -1; } } + ctrl->server_local->card_removed = 0; } @@ -122,11 +137,18 @@ option_handler (ASSUAN_CONTEXT ctx, const char *key, const char *value) /* If the card has not yet been opened, do it. Note that this function returns an Assuan error, so don't map the error a second time */ -static AssuanError +static assuan_error_t open_card (ctrl_t ctrl, const char *apptype) { + gpg_error_t err; int slot; + /* If we ever got a card not present error code, return that. Only + the SERIALNO command and a reset are able to clear from that + state. */ + if (ctrl->server_local->card_removed) + return map_to_assuan_status (gpg_error (GPG_ERR_CARD_REMOVED)); + if (ctrl->app_ctx) return 0; /* Already initialized for one specific application. */ if (ctrl->card_ctx) @@ -137,24 +159,28 @@ open_card (ctrl_t ctrl, const char *apptype) else slot = apdu_open_reader (opt.reader_port); ctrl->reader_slot = slot; - if (slot != -1) - ctrl->app_ctx = select_application (ctrl, slot, apptype); - if (!ctrl->app_ctx) - { /* No application found - fall back to old mode. */ + if (slot == -1) + err = gpg_error (GPG_ERR_CARD); + else + err = select_application (ctrl, slot, apptype, &ctrl->app_ctx); + if (!ctrl->app_ctx + && gpg_err_code (err) != GPG_ERR_CARD_NOT_PRESENT) + { + /* No application found - fall back to old mode. */ /* Note that we should rework the old code to use the application paradigma too. */ - int rc; - /* If an APPTYPE was requested and it is not pkcs#15, we return an error here. */ if (apptype && !(!strcmp (apptype, "P15") || !strcmp (apptype, "p15"))) - rc = gpg_error (GPG_ERR_NOT_SUPPORTED); + err = gpg_error (GPG_ERR_NOT_SUPPORTED); else - rc = card_open (&ctrl->card_ctx); - if (rc) - return map_to_assuan_status (rc); + err = card_open (&ctrl->card_ctx); } - return 0; + + if (gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT) + ctrl->server_local->card_removed = 1; + + return map_to_assuan_status (err); } @@ -215,12 +241,15 @@ percent_plus_unescape (unsigned char *string) static int cmd_serialno (ASSUAN_CONTEXT ctx, char *line) { - CTRL ctrl = assuan_get_pointer (ctx); + ctrl_t ctrl = assuan_get_pointer (ctx); int rc = 0; char *serial_and_stamp; char *serial; time_t stamp; + /* Clear the remove flag so that the open_card is able to reread it. */ + ctrl->server_local->card_removed = 0; + if ((rc = open_card (ctrl, *line? line:NULL))) return rc; @@ -443,6 +472,7 @@ cmd_learn (ASSUAN_CONTEXT ctx, char *line) if (rc == -1) rc = 0; + TEST_CARD_REMOVAL (ctrl, rc); return map_to_assuan_status (rc); } @@ -485,6 +515,7 @@ cmd_readcert (ASSUAN_CONTEXT ctx, char *line) return rc; } + TEST_CARD_REMOVAL (ctrl, rc); return map_to_assuan_status (rc); } @@ -575,6 +606,7 @@ cmd_readkey (assuan_context_t ctx, char *line) leave: ksba_cert_release (kc); xfree (cert); + TEST_CARD_REMOVAL (ctrl, rc); return map_to_assuan_status (rc); } @@ -697,6 +729,7 @@ cmd_pksign (ASSUAN_CONTEXT ctx, char *line) return rc; /* that is already an assuan error code */ } + TEST_CARD_REMOVAL (ctrl, rc); return map_to_assuan_status (rc); } @@ -743,6 +776,7 @@ cmd_pkauth (ASSUAN_CONTEXT ctx, char *line) return rc; /* that is already an assuan error code */ } + TEST_CARD_REMOVAL (ctrl, rc); return map_to_assuan_status (rc); } @@ -789,6 +823,7 @@ cmd_pkdecrypt (ASSUAN_CONTEXT ctx, char *line) return rc; /* that is already an assuan error code */ } + TEST_CARD_REMOVAL (ctrl, rc); return map_to_assuan_status (rc); } @@ -824,6 +859,7 @@ cmd_getattr (ASSUAN_CONTEXT ctx, char *line) rc = app_getattr (ctrl->app_ctx, ctrl, keyword); + TEST_CARD_REMOVAL (ctrl, rc); return map_to_assuan_status (rc); } @@ -871,6 +907,7 @@ cmd_setattr (ASSUAN_CONTEXT ctx, char *orig_line) rc = app_setattr (ctrl->app_ctx, keyword, pin_cb, ctx, line, nbytes); xfree (linebuf); + TEST_CARD_REMOVAL (ctrl, rc); return map_to_assuan_status (rc); } @@ -927,6 +964,8 @@ cmd_genkey (ASSUAN_CONTEXT ctx, char *line) return ASSUAN_Out_Of_Core; rc = app_genkey (ctrl->app_ctx, ctrl, keyno, force? 1:0, pin_cb, ctx); xfree (keyno); + + TEST_CARD_REMOVAL (ctrl, rc); return map_to_assuan_status (rc); } @@ -966,6 +1005,7 @@ cmd_random (ASSUAN_CONTEXT ctx, char *line) } xfree (buffer); + TEST_CARD_REMOVAL (ctrl, rc); return map_to_assuan_status (rc); } @@ -1010,6 +1050,8 @@ cmd_passwd (ASSUAN_CONTEXT ctx, char *line) if (rc) log_error ("command passwd failed: %s\n", gpg_strerror (rc)); xfree (chvnostr); + + TEST_CARD_REMOVAL (ctrl, rc); return map_to_assuan_status (rc); } @@ -1044,6 +1086,7 @@ cmd_checkpin (ASSUAN_CONTEXT ctx, char *line) if (rc) log_error ("app_check_pin failed: %s\n", gpg_strerror (rc)); + TEST_CARD_REMOVAL (ctrl, rc); return map_to_assuan_status (rc); } @@ -1226,7 +1269,9 @@ send_status_info (CTRL ctrl, const char *keyword, ...) } - +/* This fucntion is called by the ticker thread to check for changes + of the reader stati. It updates the reader status files and if + requested by the caller also send a signal to the caller. */ void scd_update_reader_status_file (void) { @@ -1239,10 +1284,10 @@ scd_update_reader_status_file (void) int used; unsigned int status, changed; - /* Note, that we only try to get the status, becuase it does not + /* Note, that we only try to get the status, because it does not make sense to wait here for a operation to complete. If we are - so busy working with the card, delays in the status file updated - are should be acceptable. */ + busy working with a card, delays in the status file update should + be acceptable. */ for (slot=0; (slot < DIM(last) &&!apdu_enum_reader (slot, &used)); slot++) if (used && !apdu_get_status (slot, 0, &status, &changed)) diff --git a/scd/scdaemon.c b/scd/scdaemon.c index 88f393bb1..0fefbd960 100644 --- a/scd/scdaemon.c +++ b/scd/scdaemon.c @@ -936,7 +936,7 @@ ticker_thread (void *dummy_arg) sigs_ev = NULL; #endif - for (;;) + while (!shutdown_pending) { if (!time_ev) { @@ -968,6 +968,7 @@ ticker_thread (void *dummy_arg) } pth_event_free (sigs_ev, PTH_FREE_ALL); + return NULL; } #endif /*USE_GNU_PTH*/ #endif /*!HAVE_OPENSC*/ diff --git a/tests/asschk.c b/tests/asschk.c index 83a8ca5af..59c0d107a 100644 --- a/tests/asschk.c +++ b/tests/asschk.c @@ -59,10 +59,10 @@ Print VALUE. openfile - Open file FILENAME for read access and retrun the file descriptor. + Open file FILENAME for read access and return the file descriptor. createfile - Create file FILENAME, open for write access and retrun the file + Create file FILENAME, open for write access and return the file descriptor. pipeserver diff --git a/tools/ChangeLog b/tools/ChangeLog index 38b9e9cf4..6895198c5 100644 --- a/tools/ChangeLog +++ b/tools/ChangeLog @@ -1,3 +1,8 @@ +2005-02-24 Werner Koch + + * gpg-connect-agent.c: New. + * Makefile.am: Add it. + 2004-12-21 Werner Koch * gpgconf-comp.c (get_config_pathname) [DOSISH]: Detect absolute diff --git a/tools/Makefile.am b/tools/Makefile.am index 112c77e7c..5a56d65ce 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -24,15 +24,13 @@ EXTRA_DIST = Manifest watchgnupg.c \ AM_CPPFLAGS = -I$(top_srcdir)/intl -I$(top_srcdir)/common include $(top_srcdir)/am/cmacros.am -# Note, that we require GPG_ERROR_CFLAGS only because some share header files -# require that file. It is not actually used in gpgconf. -AM_CFLAGS = @GPG_ERROR_CFLAGS@ +AM_CFLAGS = $(GPG_ERROR_CFLAGS) $(LIBASSUAN_CFLAGS) sbin_SCRIPTS = addgnupghome bin_SCRIPTS = gpgsm-gencert.sh -bin_PROGRAMS = gpgconf +bin_PROGRAMS = gpgconf gpg-connect-agent if !HAVE_W32_SYSTEM bin_PROGRAMS += watchgnupg endif @@ -41,4 +39,9 @@ gpgconf_SOURCES = gpgconf.c gpgconf.h gpgconf-comp.c no-libgcrypt.c gpgconf_LDADD = ../jnlib/libjnlib.a ../common/libcommon.a @LIBINTL@ -watchgnupg_SOURCES = watchgnupg.c +watchgnupg_SOURCES = watchgnupg.c + +gpg_connect_agent_SOURCES = gpg-connect-agent.c no-libgcrypt.c +gpg_connect_agent_LDADD = ../jnlib/libjnlib.a ../common/libcommon.a \ + $(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) $(LIBINTL) + diff --git a/tools/gpg-connect-agent.c b/tools/gpg-connect-agent.c new file mode 100644 index 000000000..399a5d369 --- /dev/null +++ b/tools/gpg-connect-agent.c @@ -0,0 +1,362 @@ +/* gpg-connect-agent.c - Tool to connect to the agent. + * Copyright (C) 2005 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 + +#include +#include +#include +#include +#include + +#include "i18n.h" +#include "../common/util.h" +#include "../common/asshelp.h" + + + +/* Constants to identify the commands and options. */ +enum cmd_and_opt_values + { + aNull = 0, + oQuiet = 'q', + oVerbose = 'v', + + oNoVerbose = 500, + oHomedir + + }; + + +/* The list of commands and options. */ +static ARGPARSE_OPTS opts[] = + { + { 301, NULL, 0, N_("@\nOptions:\n ") }, + + { oVerbose, "verbose", 0, N_("verbose") }, + { oQuiet, "quiet", 0, N_("quiet") }, + + /* hidden options */ + { oNoVerbose, "no-verbose", 0, "@"}, + { oHomedir, "homedir", 2, "@" }, + {0} + }; + + +/* We keep all global options in the structure OPT. */ +struct +{ + int verbose; /* Verbosity level. */ + int quiet; /* Be extra quiet. */ + const char *homedir; /* Configuration directory name */ + +} opt; + + +/*-- local prototypes --*/ +static int read_and_print_response (assuan_context_t ctx); +static assuan_context_t start_agent (void); + + + + +/* Print usage information and and provide strings for help. */ +static const char * +my_strusage( int level ) +{ + const char *p; + + switch (level) + { + case 11: p = "gpg-connect-agent (GnuPG)"; + break; + case 13: p = VERSION; break; + case 17: p = PRINTABLE_OS_NAME; break; + case 19: p = _("Please report bugs to <" PACKAGE_BUGREPORT ">.\n"); + break; + case 1: + case 40: p = _("Usage: gpg-connect-agent [options] (-h for help)"); + break; + case 41: + p = _("Syntax: gpg-connect-agent [options]\n" + "Connect to a running agent and send commands\n"); + break; + case 31: p = "\nHome: "; break; + case 32: p = opt.homedir; break; + case 33: p = "\n"; break; + + default: p = NULL; break; + } + return p; +} + + +/* Initialize the gettext system. */ +static void +i18n_init(void) +{ +#ifdef USE_SIMPLE_GETTEXT + set_gettext_file (PACKAGE_GT); +#else +# ifdef ENABLE_NLS + setlocale (LC_ALL, "" ); + bindtextdomain (PACKAGE_GT, LOCALEDIR); + textdomain (PACKAGE_GT); +# endif +#endif +} + + +/* gpg-connect-agent's entry point. */ +int +main (int argc, char **argv) +{ + ARGPARSE_ARGS pargs; + const char *fname; + int no_more_options = 0; + assuan_context_t ctx; + char *line; + size_t linesize; + int rc; + + set_strusage (my_strusage); + log_set_prefix ("gpg-connect-agent", 1); + + i18n_init(); + + opt.homedir = default_homedir (); + + /* Parse the command line. */ + pargs.argc = &argc; + pargs.argv = &argv; + pargs.flags = 1; /* Do not remove the args. */ + while (!no_more_options && optfile_parse (NULL, NULL, NULL, &pargs, opts)) + { + switch (pargs.r_opt) + { + case oQuiet: opt.quiet = 1; break; + case oVerbose: opt.verbose++; break; + case oNoVerbose: opt.verbose = 0; break; + case oHomedir: opt.homedir = pargs.r.ret_str; break; + + default: pargs.err = 2; break; + } + } + + if (log_get_errorcount (0)) + exit (2); + + fname = argc ? *argv : NULL; + + ctx = start_agent (); + line = NULL; + linesize = 0; + for (;;) + { + int n; + size_t maxlength; + + maxlength = 2048; + n = read_line (stdin, &line, &linesize, &maxlength); + if (n < 0) + { + log_error (_("error reading input: %s\n"), strerror (errno)); + exit (1); + } + if (!n) + break; /* EOF */ + if (!maxlength) + { + log_error (_("line too long - skipped\n")); + continue; + } + if (memchr (line, 0, n)) + log_info (_("line shortened due to embedded Nul character\n")); + if (line[n-1] == '\n') + line[n-1] = 0; + rc = assuan_write_line (ctx, line); + if (rc) + { + log_info (_("sending line failed: %s\n"), assuan_strerror (rc) ); + continue; + } + if (*line == '#' || !*line) + continue; /* Don't expect a response for a coment line. */ + + rc = read_and_print_response (ctx); + if (rc) + log_info (_("receiving line failed: %s\n"), assuan_strerror (rc) ); + } + + if (opt.verbose) + log_info ("closing connection to agent\n"); + + return 0; +} + + +/* Read all response lines from server and print them. Returns 0 on + success or an assuan error code. */ +static int +read_and_print_response (assuan_context_t ctx) +{ + char *line; + int linelen; + assuan_error_t rc; + + for (;;) + { + do + { + rc = assuan_read_line (ctx, &line, &linelen); + if (rc) + return rc; + } + while (*line == '#' || !linelen); + + if (linelen >= 1 + && line[0] == 'D' && line[1] == ' ') + { + fwrite (line, linelen, 1, stdout); + putchar ('\n'); + } + else if (linelen >= 1 + && line[0] == 'S' + && (line[1] == '\0' || line[1] == ' ')) + { + fwrite (line, linelen, 1, stdout); + putchar ('\n'); + } + else if (linelen >= 2 + && line[0] == 'O' && line[1] == 'K' + && (line[2] == '\0' || line[2] == ' ')) + { + fwrite (line, linelen, 1, stdout); + putchar ('\n'); + return 0; + } + else if (linelen >= 3 + && line[0] == 'E' && line[1] == 'R' && line[2] == 'R' + && (line[3] == '\0' || line[3] == ' ')) + { + fwrite (line, linelen, 1, stdout); + putchar ('\n'); + return 0; + } + else if (linelen >= 7 + && line[0] == 'I' && line[1] == 'N' && line[2] == 'Q' + && line[3] == 'U' && line[4] == 'I' && line[5] == 'R' + && line[6] == 'E' + && (line[7] == '\0' || line[7] == ' ')) + { + fwrite (line, linelen, 1, stdout); + putchar ('\n'); + return 0; + } + else if (linelen >= 3 + && line[0] == 'E' && line[1] == 'N' && line[2] == 'D' + && (line[3] == '\0' || line[3] == ' ')) + { + fwrite (line, linelen, 1, stdout); + putchar ('\n'); + /* Received from server, thus more responses are expected. */ + } + else + return ASSUAN_Invalid_Response; + } +} + + + + +/* Connect to teh agebnt and send the standard options. */ +static assuan_context_t +start_agent (void) +{ + int rc = 0; + char *infostr, *p; + assuan_context_t ctx; + + infostr = getenv ("GPG_AGENT_INFO"); + if (!infostr || !*infostr) + { + char *sockname; + + /* Check whether we can connect at the standard socket. */ + sockname = make_filename (opt.homedir, "S.gpg-agent", NULL); + rc = assuan_socket_connect (&ctx, sockname, 0); + xfree (sockname); + } + else + { + int prot; + int pid; + + infostr = xstrdup (infostr); + if ( !(p = strchr (infostr, PATHSEP_C)) || p == infostr) + { + log_error (_("malformed GPG_AGENT_INFO environment variable\n")); + xfree (infostr); + exit (1); + } + *p++ = 0; + pid = atoi (p); + while (*p && *p != ':') + p++; + prot = *p? atoi (p+1) : 0; + if (prot != 1) + { + log_error (_("gpg-agent protocol version %d is not supported\n"), + prot); + xfree (infostr); + exit (1); + } + + rc = assuan_socket_connect (&ctx, infostr, pid); + xfree (infostr); + } + + if (rc) + { + log_error ("can't connect to the agent: %s\n", assuan_strerror (rc)); + exit (1); + } + + if (opt.verbose) + log_info ("connection to agent established\n"); + + rc = assuan_transact (ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL); + if (rc) + { + log_error (_("error sending %s command: %s\n"), "RESET", + assuan_strerror (rc)); + exit (1); + } + + rc = send_pinentry_environment (ctx, GPG_ERR_SOURCE_DEFAULT, + NULL, NULL, NULL, NULL, NULL); + if (rc) + { + log_error (_("error sending standard options: %s\n"), gpg_strerror (rc)); + exit (1); + } + + return ctx; +} -- cgit From faef9f929b845dc712c8d705620661b5bc6f6767 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 25 Feb 2005 16:14:55 +0000 Subject: * findkey.c (modify_description): Keep invalid % escapes, so that %0A may pass through. * agent.h (server_control_s): New field USE_AUTH_CALL. * call-scd.c (agent_card_pksign): Make use of it. * command-ssh.c (data_sign): Set the flag. (ssh_send_key_public): New arg OVERRIDE_COMMENT. (card_key_available): Add new arg CARDSN. (ssh_handler_request_identities): Use the card s/n as comment. (sexp_key_extract): Use GCRYMPI_FMT_STD. (data_sign): Ditto. * learncard.c (make_shadow_info): Moved to .. * protect.c (make_shadow_info): .. here. Return NULL on malloc failure. Made global. * agent.h: Add prototype. * xasprintf.c (xtryasprintf): New. * app-openpgp.c (get_public_key): Make sure not to return negative numbers. (do_sign): Allow passing of indata with algorithm prefix. (do_auth): Allow OPENPGP.3 as an alternative ID. * app.c (app_getattr): Return just the S/N but not the timestamp. * no-libgcrypt.c (gcry_strdup): New. --- agent/ChangeLog | 19 ++++++ agent/agent.h | 3 + agent/call-scd.c | 22 ++++--- agent/command-ssh.c | 156 +++++++++++++++++++++++++++++++++++++--------- agent/findkey.c | 15 +++-- agent/keyformat.txt | 4 +- agent/learncard.c | 28 +-------- agent/protect-tool.c | 2 +- agent/protect.c | 37 ++++++++++- common/ChangeLog | 4 ++ common/util.h | 4 ++ common/xasprintf.c | 20 +++++- scd/ChangeLog | 9 +++ scd/app-openpgp.c | 86 +++++++++++++++++++------ scd/app.c | 10 +-- tools/ChangeLog | 4 ++ tools/gpg-connect-agent.c | 47 ++++++++++++-- tools/no-libgcrypt.c | 6 ++ 18 files changed, 368 insertions(+), 108 deletions(-) (limited to 'scd/app-openpgp.c') diff --git a/agent/ChangeLog b/agent/ChangeLog index 118559c64..2138f6674 100644 --- a/agent/ChangeLog +++ b/agent/ChangeLog @@ -1,3 +1,22 @@ +2005-02-25 Werner Koch + + * findkey.c (modify_description): Keep invalid % escapes, so that + %0A may pass through. + + * agent.h (server_control_s): New field USE_AUTH_CALL. + * call-scd.c (agent_card_pksign): Make use of it. + * command-ssh.c (data_sign): Set the flag. + (ssh_send_key_public): New arg OVERRIDE_COMMENT. + (card_key_available): Add new arg CARDSN. + (ssh_handler_request_identities): Use the card s/n as comment. + (sexp_key_extract): Use GCRYMPI_FMT_STD. + (data_sign): Ditto. + + * learncard.c (make_shadow_info): Moved to .. + * protect.c (make_shadow_info): .. here. Return NULL on malloc + failure. Made global. + * agent.h: Add prototype. + 2005-02-24 Werner Koch * call-scd.c (unescape_status_string): New. Actual a copy of diff --git a/agent/agent.h b/agent/agent.h index 39e479e48..e12a02b6e 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -116,6 +116,8 @@ struct server_control_s { char keygrip[20]; int have_keygrip; + int use_auth_call; /* Hack to send the PKAUTH command instead of the + PKSIGN command tro scdaemon. */ }; typedef struct server_control_s *CTRL; typedef struct server_control_s *ctrl_t; @@ -204,6 +206,7 @@ int agent_protect (const unsigned char *plainkey, const char *passphrase, int agent_unprotect (const unsigned char *protectedkey, const char *passphrase, unsigned char **result, size_t *resultlen); int agent_private_key_type (const unsigned char *privatekey); +unsigned char *make_shadow_info (const char *serialno, const char *idstring); int agent_shadow_key (const unsigned char *pubkey, const unsigned char *shadow_info, unsigned char **result); diff --git a/agent/call-scd.c b/agent/call-scd.c index f7d32f7cf..904059291 100644 --- a/agent/call-scd.c +++ b/agent/call-scd.c @@ -225,15 +225,16 @@ start_scd (ctrl_t ctrl) /* Tell the scdaemon that we want him to send us an event signal. But only do this if we are running as a regular sever and not simply as a pipe server. */ - if (ctrl->connection_fd != -1) - { -#ifndef HAVE_W32_SYSTEM - char buf[100]; + /* Fixme: gpg-agent does not use this signal yet. */ +/* if (ctrl->connection_fd != -1) */ +/* { */ +/* #ifndef HAVE_W32_SYSTEM */ +/* char buf[100]; */ - sprintf (buf, "OPTION event-signal=%d", SIGUSR2); - assuan_transact (scd_ctx, buf, NULL, NULL, NULL, NULL, NULL, NULL); -#endif - } +/* sprintf (buf, "OPTION event-signal=%d", SIGUSR2); */ +/* assuan_transact (scd_ctx, buf, NULL, NULL, NULL, NULL, NULL, NULL); */ +/* #endif */ +/* } */ return 0; } @@ -505,7 +506,8 @@ agent_card_pksign (ctrl_t ctrl, inqparm.ctx = scd_ctx; inqparm.getpin_cb = getpin_cb; inqparm.getpin_cb_arg = getpin_cb_arg; - snprintf (line, DIM(line)-1, "PKSIGN %s", keyid); + snprintf (line, DIM(line)-1, + ctrl->use_auth_call? "PKAUTH %s":"PKSIGN %s", keyid); line[DIM(line)-1] = 0; rc = assuan_transact (scd_ctx, line, membuf_data_cb, &data, @@ -518,7 +520,7 @@ agent_card_pksign (ctrl_t ctrl, } sigbuf = get_membuf (&data, &sigbuflen); - /* create an S-expression from it which is formatted like this: + /* Create an S-expression from it which is formatted like this: "(7:sig-val(3:rsa(1:sSIGBUFLEN:SIGBUF)))" */ *r_buflen = 21 + 11 + sigbuflen + 4; *r_buf = xtrymalloc (*r_buflen); diff --git a/agent/command-ssh.c b/agent/command-ssh.c index 2c0d25ef6..ebb44fa74 100644 --- a/agent/command-ssh.c +++ b/agent/command-ssh.c @@ -659,7 +659,9 @@ open_control_file (FILE **r_fp, int append) (i.e. where Pth might switch threads) we need to employ a mutex. */ *r_fp = NULL; - fname = make_filename (opt.homedir, "sshcontrol.txt", NULL); + fname = make_filename (opt.homedir, "sshcontrol", NULL); + /* FIXME: With "a+" we are not able to check whether this will will + be created and thus the blurb needs to be written first. */ fp = fopen (fname, append? "a+":"r"); if (!fp && errno == ENOENT) { @@ -1146,7 +1148,9 @@ sexp_key_extract (gcry_sexp_t sexp, break; } - mpi = gcry_sexp_nth_mpi (value_pair, 1, GCRYMPI_FMT_USG); + /* Note that we need to use STD format; i.e. prepend a 0x00 to + indicate a positive number if the high bit is set. */ + mpi = gcry_sexp_nth_mpi (value_pair, 1, GCRYMPI_FMT_STD); if (! mpi) { err = gpg_error (GPG_ERR_INV_SEXP); @@ -1404,9 +1408,12 @@ ssh_convert_key_to_blob (unsigned char **blob, size_t *blob_size, } -/* Write the public key KEY_PUBLIC to STREAM in SSH key format. */ +/* Write the public key KEY_PUBLIC to STREAM in SSH key format. If + OVERRIDE_COMMENT is not NULL, it will be used instead of the + comment stored in the key. */ static gpg_error_t -ssh_send_key_public (estream_t stream, gcry_sexp_t key_public) +ssh_send_key_public (estream_t stream, gcry_sexp_t key_public, + const char *override_comment) { ssh_key_type_spec_t spec; gcry_mpi_t *mpi_list; @@ -1442,7 +1449,8 @@ ssh_send_key_public (estream_t stream, gcry_sexp_t key_public) if (err) goto out; - err = stream_write_cstring (stream, comment); + err = stream_write_cstring (stream, + override_comment? override_comment : comment); out: @@ -1520,17 +1528,23 @@ key_secret_to_public (gcry_sexp_t *key_public, /* Chec whether a smartcard is available and whether it has a usable key. Store a copy of that key at R_PK and return 0. If no key is - available store NULL at R_PK and return an error code. */ + available store NULL at R_PK and return an error code. If CARDSN + is no NULL, a string with the serial number of the card will be + amalloced and stored there. */ static gpg_error_t -card_key_available (ctrl_t ctrl, gcry_sexp_t *r_pk) +card_key_available (ctrl_t ctrl, gcry_sexp_t *r_pk, char **cardsn) { gpg_error_t err; char *appname; - unsigned char *sbuf; - size_t sbuflen; - gcry_sexp_t pk; + char *serialno = NULL; + unsigned char *pkbuf; + size_t pkbuflen; + gcry_sexp_t s_pk; + unsigned char grip[20]; *r_pk = NULL; + if (cardsn) + *cardsn = NULL; /* First see whether a card is available and whether the application is supported. */ @@ -1538,53 +1552,135 @@ card_key_available (ctrl_t ctrl, gcry_sexp_t *r_pk) if ( gpg_err_code (err) == GPG_ERR_CARD_REMOVED ) { /* Ask for the serial number to reset the card. */ - err = agent_card_serialno (ctrl, &appname); + err = agent_card_serialno (ctrl, &serialno); if (err) { if (opt.verbose) - log_info (_("can't get serial number of card: %s\n"), + log_info (_("error getting serial number of card: %s\n"), gpg_strerror (err)); return err; } - log_info (_("detected card with S/N: %s\n"), appname); - xfree (appname); + log_info (_("detected card with S/N: %s\n"), serialno); err = agent_card_getattr (ctrl, "APPTYPE", &appname); } if (err) { log_error (_("error getting application type of card: %s\n"), gpg_strerror (err)); + xfree (serialno); return err; } if (strcmp (appname, "OPENPGP")) { log_info (_("card application `%s' is not supported\n"), appname); xfree (appname); + xfree (serialno); return gpg_error (GPG_ERR_NOT_SUPPORTED); } xfree (appname); appname = NULL; + /* Get the S/N if we don't have it yet. Use the fast getattr method. */ + if (!serialno && (err = agent_card_getattr (ctrl, "SERIALNO", &serialno)) ) + { + log_error (_("error getting serial number of card: %s\n"), + gpg_strerror (err)); + return err; + } + /* Read the public key. */ - err = agent_card_readkey (ctrl, "OPENPGP.3", &sbuf); + err = agent_card_readkey (ctrl, "OPENPGP.3", &pkbuf); if (err) { if (opt.verbose) log_info (_("no suitable card key found: %s\n"), gpg_strerror (err)); + xfree (serialno); return err; } - sbuflen = gcry_sexp_canon_len (sbuf, 0, NULL, NULL); - err = gcry_sexp_sscan (&pk, NULL, sbuf, sbuflen); - xfree (sbuf); + pkbuflen = gcry_sexp_canon_len (pkbuf, 0, NULL, NULL); + err = gcry_sexp_sscan (&s_pk, NULL, pkbuf, pkbuflen); if (err) { log_error ("failed to build S-Exp from received card key: %s\n", gpg_strerror (err)); + xfree (pkbuf); + xfree (serialno); return err; } - *r_pk = pk; + if ( !gcry_pk_get_keygrip (s_pk, grip) ) + { + log_debug ("error computing keygrip from received card key\n"); + xfree (pkbuf); + gcry_sexp_release (s_pk); + xfree (serialno); + return gpg_error (GPG_ERR_INTERNAL); + } + + if ( agent_key_available (grip) ) + { + /* (Shadow)-key is not available in our key storage. */ + unsigned char *shadow_info; + unsigned char *tmp; + + shadow_info = make_shadow_info (serialno, "OPENPGP.3"); + if (!shadow_info) + { + err = gpg_error_from_errno (errno); + xfree (pkbuf); + gcry_sexp_release (s_pk); + xfree (serialno); + return err; + } + err = agent_shadow_key (pkbuf, shadow_info, &tmp); + xfree (shadow_info); + if (err) + { + log_error (_("shadowing the key failed: %s\n"), gpg_strerror (err)); + xfree (pkbuf); + gcry_sexp_release (s_pk); + xfree (serialno); + return err; + } + xfree (pkbuf); + pkbuf = tmp; + pkbuflen = gcry_sexp_canon_len (pkbuf, 0, NULL, NULL); + assert (pkbuflen); + + err = agent_write_private_key (grip, pkbuf, pkbuflen, 0); + if (err) + { + log_error (_("error writing key: %s\n"), gpg_strerror (err)); + xfree (pkbuf); + gcry_sexp_release (s_pk); + xfree (serialno); + return err; + } + } + + if (cardsn) + { + size_t snlen = strlen (serialno); + + if (snlen == 32 + && !memcmp (serialno, "D27600012401", 12)) /* OpenPGP card. */ + *cardsn = xtryasprintf ("cardno:%.12s", serialno+16); + else /* Something is wrong: Print all. */ + *cardsn = xtryasprintf ("cardno:%s", serialno); + if (!*cardsn) + { + err = gpg_error_from_errno (errno); + xfree (pkbuf); + gcry_sexp_release (s_pk); + xfree (serialno); + return err; + } + } + + xfree (pkbuf); + xfree (serialno); + *r_pk = s_pk; return 0; } @@ -1615,6 +1711,7 @@ ssh_handler_request_identities (ctrl_t ctrl, gpg_error_t ret_err; int ret; FILE *ctrl_fp = NULL; + char *cardsn; /* Prepare buffer stream. */ @@ -1665,13 +1762,14 @@ ssh_handler_request_identities (ctrl_t ctrl, /* First check whether a key is currently available in the card reader - this should be allowed even without being listed in - sshcontrol.txt. */ + sshcontrol. */ - if (!card_key_available (ctrl, &key_public)) + if (!card_key_available (ctrl, &key_public, &cardsn)) { - err = ssh_send_key_public (key_blobs, key_public); + err = ssh_send_key_public (key_blobs, key_public, cardsn); gcry_sexp_release (key_public); key_public = NULL; + xfree (cardsn); if (err) goto out; @@ -1740,7 +1838,7 @@ ssh_handler_request_identities (ctrl_t ctrl, gcry_sexp_release (key_secret); key_secret = NULL; - err = ssh_send_key_public (key_blobs, key_public); + err = ssh_send_key_public (key_blobs, key_public, NULL); if (err) goto out; @@ -1845,9 +1943,11 @@ data_sign (ctrl_t ctrl, ssh_signature_encoder_t sig_encoder, sig_value = NULL; mpis = NULL; + ctrl->use_auth_call = 1; err = agent_pksign_do (ctrl, - _("Please provide the passphrase " - "for the ssh key `%c':"), &signature_sexp, 0); + _("Please enter the passphrase " + "for the ssh key%0A %c"), &signature_sexp, 0); + ctrl->use_auth_call = 0; if (err) goto out; @@ -2189,7 +2289,7 @@ ssh_identity_register (ctrl_t ctrl, gcry_sexp_t key, int ttl) key_grip_raw[sizeof (key_grip_raw) - 1] = 0; /* FIXME: Why?? */ - /* Check whether the key is alread in our key storage. Don't do + /* Check whether the key is already in our key storage. Don't do anything then. */ if ( !agent_key_available (key_grip_raw) ) goto out; /* Yes, key is available. */ @@ -2200,8 +2300,8 @@ ssh_identity_register (ctrl_t ctrl, gcry_sexp_t key, int ttl) goto out; if ( asprintf (&description, - _("Please enter a passphrase to protect%%0A" - "the received secret key%%0A" + _("Please enter a passphrase to protect" + " the received secret key%%0A" " %s%%0A" "within gpg-agent's key storage"), comment ? comment : "?") < 0) diff --git a/agent/findkey.c b/agent/findkey.c index 86a28d511..0b5816bf5 100644 --- a/agent/findkey.c +++ b/agent/findkey.c @@ -166,9 +166,7 @@ modify_description (const char *in, const char *comment, char **result) special = 0; for (i = 0; i < in_len; i++) { - if (in[i] == '%') - special = 1; - else if (special) + if (special) { special = 0; switch (in[i]) @@ -190,10 +188,19 @@ modify_description (const char *in, const char *comment, char **result) out_len += comment_length; break; - default: /* Invalid special sequences are ignored. */ + default: /* Invalid special sequences are kept as they are. */ + if (out) + { + *out++ = '%'; + *out++ = in[i]; + } + else + out_len+=2; break; } } + else if (in[i] == '%') + special = 1; else { if (out) diff --git a/agent/keyformat.txt b/agent/keyformat.txt index 726990315..7bdb94c0e 100644 --- a/agent/keyformat.txt +++ b/agent/keyformat.txt @@ -161,9 +161,9 @@ term secret key because it can be visually be better distinguished from the term public key. [2] The keygrip is a unique identifier for a key pair, it is -independent of any protocol, so that the same key can be ised with +independent of any protocol, so that the same key can be used with different protocols. PKCS-15 calls this a subjectKeyHash; it can be -calculate using Libgcrypt's gcry_pk_get_keygrip(). +calculated using Libgcrypt's gcry_pk_get_keygrip (). [3] Even when canonical representation are required we will show the S-expression here in a more readable representation. diff --git a/agent/learncard.c b/agent/learncard.c index 7dcacee28..72238507f 100644 --- a/agent/learncard.c +++ b/agent/learncard.c @@ -1,5 +1,5 @@ /* learncard.c - Handle the LEARN command - * Copyright (C) 2002, 2003 Free Software Foundation, Inc. + * Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -239,32 +239,6 @@ sinfo_cb (void *opaque, const char *keyword, size_t keywordlen, } -/* Create an S-expression with the shadow info. */ -static unsigned char * -make_shadow_info (const char *serialno, const char *idstring) -{ - const char *s; - unsigned char *info, *p; - char numbuf[21]; - int n; - - for (s=serialno, n=0; *s && s[1]; s += 2) - n++; - - info = p = xtrymalloc (1 + 21 + n - + 21 + strlen (idstring) + 1 + 1); - *p++ = '('; - sprintf (numbuf, "%d:", n); - p = stpcpy (p, numbuf); - for (s=serialno; *s && s[1]; s += 2) - *p++ = xtoi_2 (s); - sprintf (numbuf, "%d:", strlen (idstring)); - p = stpcpy (p, numbuf); - p = stpcpy (p, idstring); - *p++ = ')'; - *p = 0; - return info; -} static int send_cert_back (ctrl_t ctrl, const char *id, void *assuan_context) diff --git a/agent/protect-tool.c b/agent/protect-tool.c index ee0276a43..c21aa0517 100644 --- a/agent/protect-tool.c +++ b/agent/protect-tool.c @@ -110,7 +110,7 @@ static ARGPARSE_OPTS opts[] = { { oPassphrase, "passphrase", 2, "|STRING|use passphrase STRING" }, { oProtect, "protect", 256, "protect a private key"}, { oUnprotect, "unprotect", 256, "unprotect a private key"}, - { oShadow, "shadow", 256, "create a shadow entry for a priblic key"}, + { oShadow, "shadow", 256, "create a shadow entry for a public key"}, { oShowShadowInfo, "show-shadow-info", 256, "return the shadow info"}, { oShowKeygrip, "show-keygrip", 256, "show the \"keygrip\""}, diff --git a/agent/protect.c b/agent/protect.c index cafeb4685..ae3061c77 100644 --- a/agent/protect.c +++ b/agent/protect.c @@ -831,10 +831,43 @@ hash_passphrase (const char *passphrase, int hashalgo, + +/* Create an canonical encoded S-expression with the shadow info from + a card's SERIALNO and the IDSTRING. */ +unsigned char * +make_shadow_info (const char *serialno, const char *idstring) +{ + const char *s; + unsigned char *info, *p; + char numbuf[21]; + int n; + + for (s=serialno, n=0; *s && s[1]; s += 2) + n++; + + info = p = xtrymalloc (1 + 21 + n + + 21 + strlen (idstring) + 1 + 1); + if (!info) + return NULL; + *p++ = '('; + sprintf (numbuf, "%d:", n); + p = stpcpy (p, numbuf); + for (s=serialno; *s && s[1]; s += 2) + *p++ = xtoi_2 (s); + sprintf (numbuf, "%d:", strlen (idstring)); + p = stpcpy (p, numbuf); + p = stpcpy (p, idstring); + *p++ = ')'; + *p = 0; + return info; +} + + + /* Create a shadow key from a public key. We use the shadow protocol "ti-v1" and insert the S-expressionn SHADOW_INFO. The resulting S-expression is returned in an allocated buffer RESULT will point - to. The input parameters are expected to be valid canonilized + to. The input parameters are expected to be valid canonicalized S-expressions */ int agent_shadow_key (const unsigned char *pubkey, @@ -894,7 +927,7 @@ agent_shadow_key (const unsigned char *pubkey, s++; assert (depth == 1); - /* calculate required length by taking in account: the "shadowed-" + /* Calculate required length by taking in account: the "shadowed-" prefix, the "shadowed", "t1-v1" as well as some parenthesis */ n = 12 + pubkey_len + 1 + 3+8 + 2+5 + shadow_info_len + 1; *result = p = xtrymalloc (n); diff --git a/common/ChangeLog b/common/ChangeLog index e323dc148..db0593176 100644 --- a/common/ChangeLog +++ b/common/ChangeLog @@ -1,3 +1,7 @@ +2005-02-25 Werner Koch + + * xasprintf.c (xtryasprintf): New. + 2005-01-26 Moritz Schulte * Makefile.am (libcommon_a_SOURCES): New source files: estream.c, diff --git a/common/util.h b/common/util.h index 4ab55acb4..bbf7241a3 100644 --- a/common/util.h +++ b/common/util.h @@ -131,6 +131,10 @@ const char *default_homedir (void); freed using xfree. This function simply dies on memory failure, thus no extra check is required. */ char *xasprintf (const char *fmt, ...) JNLIB_GCC_A_PRINTF(1,2); +/* Same as asprintf but return an allocated buffer suitable to be + freed using xfree. This function returns NULL on memory failure and + sets errno. */ +char *xtryasprintf (const char *fmt, ...) JNLIB_GCC_A_PRINTF(1,2); const char *print_fname_stdout (const char *s); const char *print_fname_stdin (const char *s); diff --git a/common/xasprintf.c b/common/xasprintf.c index 2c8fafc06..a3b5e27ac 100644 --- a/common/xasprintf.c +++ b/common/xasprintf.c @@ -1,5 +1,5 @@ /* xasprintf.c - * Copyright (C) 2003 Free Software Foundation, Inc. + * Copyright (C) 2003, 2005 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -42,3 +42,21 @@ xasprintf (const char *fmt, ...) free (buf); return p; } + +/* Same as above bit return NULL on memory failure. */ +char * +xtryasprintf (const char *fmt, ...) +{ + int rc; + va_list ap; + char *buf, *p; + + va_start (ap, fmt); + rc = vasprintf (&buf, fmt, ap); + va_end (ap); + if (rc < 0) + return NULL; + p = xtrystrdup (buf); + free (buf); + return p; +} diff --git a/scd/ChangeLog b/scd/ChangeLog index dc394b677..e3b4ae64c 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,12 @@ +2005-02-25 Werner Koch + + * app-openpgp.c (get_public_key): Make sure not to return negative + numbers. + (do_sign): Allow passing of indata with algorithm prefix. + (do_auth): Allow OPENPGP.3 as an alternative ID. + + * app.c (app_getattr): Return just the S/N but not the timestamp. + 2005-02-24 Werner Koch * app.c (app_getattr): Return APPTYPE or SERIALNO type even if the diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 14c802d10..6ebc13704 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -794,6 +794,8 @@ get_public_key (app_t app, int keyno) const unsigned char *keydata, *m, *e; size_t buflen, keydatalen, mlen, elen; gcry_sexp_t sexp; + unsigned char *mbuf = NULL; + unsigned char *ebuf = NULL; if (keyno < 1 || keyno > 3) return gpg_error (GPG_ERR_INV_ID); @@ -835,6 +837,7 @@ get_public_key (app_t app, int keyno) log_error (_("response does not contain the RSA modulus\n")); goto leave; } + e = find_tlv (keydata, keydatalen, 0x0082, &elen); if (!e) @@ -844,10 +847,38 @@ get_public_key (app_t app, int keyno) goto leave; } + /* Prepend numbers with a 0 if needed. */ + if (mlen && (*m & 0x80)) + { + mbuf = xtrymalloc ( mlen + 1); + if (!mbuf) + { + err = gpg_error_from_errno (errno); + goto leave; + } + *mbuf = 0; + memcpy (mbuf+1, m, mlen); + mlen++; + m = mbuf; + } + if (elen && (*e & 0x80)) + { + ebuf = xtrymalloc ( elen + 1); + if (!ebuf) + { + err = gpg_error_from_errno (errno); + goto leave; + } + *ebuf = 0; + memcpy (ebuf+1, e, elen); + elen++; + e = ebuf; + } + + err = gcry_sexp_build (&sexp, NULL, "(public-key (rsa (n %b) (e %b)))", (int)mlen, m,(int)elen, e); - if (err) { log_error ("error formatting the key into an S-expression: %s\n", @@ -874,6 +905,8 @@ get_public_key (app_t app, int keyno) app->app_local->pk[keyno].read_done = 1; xfree (buffer); + xfree (mbuf); + xfree (ebuf); return 0; } #endif /* GNUPG_MAJOR_VERSION > 1 */ @@ -1557,7 +1590,15 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, if (!keyidstr || !*keyidstr) return gpg_error (GPG_ERR_INV_VALUE); - if (indatalen != 20) + if (indatalen == 20) + ; + else if (indatalen == (15 + 20) && hashalgo == GCRY_MD_SHA1 + && !memcmp (indata, sha1_prefix, 15)) + ; + else if (indatalen == (15 + 20) && hashalgo == GCRY_MD_RMD160 + && !memcmp (indata, rmd160_prefix, 15)) + ; + else return gpg_error (GPG_ERR_INV_VALUE); /* Check whether an OpenPGP card of any version has been requested. */ @@ -1668,7 +1709,8 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, /* Compute a digital signature using the INTERNAL AUTHENTICATE command on INDATA which is expected to be the raw message digest. For this application the KEYIDSTR consists of the serialnumber and the - fingerprint delimited by a slash. + fingerprint delimited by a slash. Optionally the id OPENPGP.3 may + be given. Note that this fucntion may return the error code GPG_ERR_WRONG_CARD to indicate that the card currently present does @@ -1693,27 +1735,31 @@ do_auth (app_t app, const char *keyidstr, return gpg_error (GPG_ERR_INV_VALUE); /* Check whether an OpenPGP card of any version has been requested. */ - if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12)) - return gpg_error (GPG_ERR_INV_ID); - - for (s=keyidstr, n=0; hexdigitp (s); s++, n++) + if (!strcmp (keyidstr, "OPENPGP.3")) ; - if (n != 32) + else if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12)) return gpg_error (GPG_ERR_INV_ID); - else if (!*s) - ; /* no fingerprint given: we allow this for now. */ - else if (*s == '/') - fpr = s + 1; else - return gpg_error (GPG_ERR_INV_ID); - - for (s=keyidstr, n=0; n < 16; s += 2, n++) - tmp_sn[n] = xtoi_2 (s); + { + for (s=keyidstr, n=0; hexdigitp (s); s++, n++) + ; + if (n != 32) + return gpg_error (GPG_ERR_INV_ID); + else if (!*s) + ; /* no fingerprint given: we allow this for now. */ + else if (*s == '/') + fpr = s + 1; + else + return gpg_error (GPG_ERR_INV_ID); - if (app->serialnolen != 16) - return gpg_error (GPG_ERR_INV_CARD); - if (memcmp (app->serialno, tmp_sn, 16)) - return gpg_error (GPG_ERR_WRONG_CARD); + for (s=keyidstr, n=0; n < 16; s += 2, n++) + tmp_sn[n] = xtoi_2 (s); + + if (app->serialnolen != 16) + return gpg_error (GPG_ERR_INV_CARD); + if (memcmp (app->serialno, tmp_sn, 16)) + return gpg_error (GPG_ERR_WRONG_CARD); + } /* If a fingerprint has been specified check it against the one on the card. This is allows for a meaningful error message in case diff --git a/scd/app.c b/scd/app.c index 384ee2143..0625dc8ef 100644 --- a/scd/app.c +++ b/scd/app.c @@ -314,7 +314,6 @@ app_getattr (APP app, CTRL ctrl, const char *name) } if (name && !strcmp (name, "SERIALNO")) { - char *serial_and_stamp; char *serial; time_t stamp; int rc; @@ -322,15 +321,8 @@ app_getattr (APP app, CTRL ctrl, const char *name) rc = app_get_serial_and_stamp (app, &serial, &stamp); if (rc) return rc; - rc = asprintf (&serial_and_stamp, "%s %lu", - serial, (unsigned long)stamp); - rc = (rc < 0)? gpg_error_from_errno (errno) : 0; + send_status_info (ctrl, "SERIALNO", serial, strlen (serial), NULL, 0); xfree (serial); - if (rc) - return rc; - send_status_info (ctrl, "SERIALNO", - serial_and_stamp, strlen (serial_and_stamp), NULL, 0); - free (serial_and_stamp); return 0; } diff --git a/tools/ChangeLog b/tools/ChangeLog index 6895198c5..4d520cfca 100644 --- a/tools/ChangeLog +++ b/tools/ChangeLog @@ -1,3 +1,7 @@ +2005-02-25 Werner Koch + + * no-libgcrypt.c (gcry_strdup): New. + 2005-02-24 Werner Koch * gpg-connect-agent.c: New. diff --git a/tools/gpg-connect-agent.c b/tools/gpg-connect-agent.c index 399a5d369..19ff160f0 100644 --- a/tools/gpg-connect-agent.c +++ b/tools/gpg-connect-agent.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include "i18n.h" @@ -40,7 +41,8 @@ enum cmd_and_opt_values oVerbose = 'v', oNoVerbose = 500, - oHomedir + oHomedir, + oHex }; @@ -52,6 +54,7 @@ static ARGPARSE_OPTS opts[] = { oVerbose, "verbose", 0, N_("verbose") }, { oQuiet, "quiet", 0, N_("quiet") }, + { oHex, "hex", 0, N_("print data out hex encoded") }, /* hidden options */ { oNoVerbose, "no-verbose", 0, "@"}, @@ -66,7 +69,7 @@ struct int verbose; /* Verbosity level. */ int quiet; /* Be extra quiet. */ const char *homedir; /* Configuration directory name */ - + int hex; /* Print data lines in hex format. */ } opt; @@ -155,6 +158,7 @@ main (int argc, char **argv) case oVerbose: opt.verbose++; break; case oNoVerbose: opt.verbose = 0; break; case oHomedir: opt.homedir = pargs.r.ret_str; break; + case oHex: opt.hex = 1; break; default: pargs.err = 2; break; } @@ -220,6 +224,7 @@ read_and_print_response (assuan_context_t ctx) char *line; int linelen; assuan_error_t rc; + int i, j; for (;;) { @@ -234,8 +239,42 @@ read_and_print_response (assuan_context_t ctx) if (linelen >= 1 && line[0] == 'D' && line[1] == ' ') { - fwrite (line, linelen, 1, stdout); - putchar ('\n'); + if (opt.hex) + { + for (i=2; i < linelen; ) + { + int save_i = i; + + printf ("D[%04X] ", i-2); + for (j=0; j < 16 ; j++, i++) + { + if (j == 8) + putchar (' '); + if (i < linelen) + printf (" %02X", ((unsigned char*)line)[i]); + else + fputs (" ", stdout); + } + fputs (" ", stdout); + i= save_i; + for (j=0; j < 16; j++, i++) + { + unsigned int c = ((unsigned char*)line)[i]; + if ( i >= linelen ) + putchar (' '); + else if (isascii (c) && isprint (c) && !iscntrl (c)) + putchar (c); + else + putchar ('.'); + } + putchar ('\n'); + } + } + else + { + fwrite (line, linelen, 1, stdout); + putchar ('\n'); + } } else if (linelen >= 1 && line[0] == 'S' diff --git a/tools/no-libgcrypt.c b/tools/no-libgcrypt.c index 0fabec90d..82f6a8bb5 100644 --- a/tools/no-libgcrypt.c +++ b/tools/no-libgcrypt.c @@ -53,6 +53,12 @@ gcry_xmalloc (size_t n) return p; } +char * +gcry_strdup (const char *string) +{ + return malloc (strlen (string)+1); +} + void * gcry_realloc (void *a, size_t n) -- cgit From 94767297091652c233f35769b88019a7f4169970 Mon Sep 17 00:00:00 2001 From: Moritz Schulte Date: Tue, 29 Mar 2005 20:46:18 +0000 Subject: 2005-03-29 Moritz Schulte * app-openpgp.c (retrieve_fpr_from_card): New function. (retrieve_next_token): New function. (retrieve_key_material): New function. (get_public_key): Implement retrival of key through expernal helper (gpg) in case the openpgp card is not cooperative enough. --- scd/ChangeLog | 8 ++ scd/app-openpgp.c | 330 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 324 insertions(+), 14 deletions(-) (limited to 'scd/app-openpgp.c') diff --git a/scd/ChangeLog b/scd/ChangeLog index e3b4ae64c..ca7358406 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,11 @@ +2005-03-29 Moritz Schulte + + * app-openpgp.c (retrieve_fpr_from_card): New function. + (retrieve_next_token): New function. + (retrieve_key_material): New function. + (get_public_key): Implement retrival of key through expernal + helper (gpg) in case the openpgp card is not cooperative enough. + 2005-02-25 Werner Koch * app-openpgp.c (get_public_key): Make sure not to return negative diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 6ebc13704..bae9dde49 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -776,6 +776,263 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name) return rc; } +/* Retrieve the fingerprint from the card inserted in SLOT and write + the according hex representation (40 hex digits plus NUL character) + to FPR. */ +static gpg_error_t +retrieve_fpr_from_card (int slot, char *fpr) +{ + const unsigned char *value; + unsigned char *data; + size_t data_n; + gpg_error_t err; + size_t value_n; + unsigned int i; + + data = NULL; + + err = iso7816_get_data (slot, 0x6E, &data, &data_n); + if (err) + /* FIXME */ + goto out; + + value = find_tlv (data, data_n, 0x00C5, &value_n); + if (! (value + && (! (value_n > (data_n - (value - data)))) + && (value_n >= 60))) /* FIXME: Shouldn't this be "== 60"? */ + { + /* FIXME? */ + err = gpg_error (GPG_ERR_CARD); /* */ + goto out; + } + + /* Copy out third key FPR. */ + for (i = 0; i < 20; i++) + sprintf (fpr + (i * 2), "%02X", (value + (2 * 20))[i]); + + out: + + xfree (data); + + return err; +} + +/* Retrieve the next token from S, using ":" as delimiter. */ +static char * +retrieve_next_token (char *s) +{ + char *p; + + p = strtok (s, ":"); + if (! p) + log_error ("error while extracting token\n"); + + return p; +} + +/* Retrieve the secret key material for the key, whose fingerprint is + FPR, from gpg output, which can be read through the stream FP. The + RSA modulus will be stored in m/mlen, the secret exponent in + e/elen. Return zero on success, one on failure. */ +static int +retrieve_key_material (FILE *fp, const char *fpr, + const unsigned char **m, size_t *mlen, + const unsigned char **e, size_t *elen) +{ + size_t line_size; + ssize_t line_ret; + char *line; + int ret; + int found_key; + char *token; + int pkd_n; + unsigned char *m_new; + unsigned char *e_new; + size_t m_new_n; + size_t e_new_n; + int is_rsa; + gcry_mpi_t mpi; + gcry_error_t err; + size_t max_length; + + line_size = 0; + line = NULL; + found_key = 0; + pkd_n = 0; + m_new = NULL; + e_new = NULL; + mpi = NULL; + ret = 0; + + while (1) + { + /* FIXME? */ + max_length = 1024; + line_ret = read_line (fp, &line, &line_size, &max_length); + if (line_ret < 0) + { + ret = 1; + break; + } + if (! line_ret) + /* EOF. */ + /* FIXME? */ + break; + + token = retrieve_next_token (line); + if (! found_key) + { + /* Key not found yet, search for key entry. */ + if ((! strcmp (token, "pub")) || (! strcmp (token, "sub"))) + { + /* Reached next key entry, parse it. */ + + /* This is the trust level (right, FIXME?). */ + token = retrieve_next_token (NULL); + if (! token) + { + ret = 1; + break; + } + + /* This is the size. */ + token = retrieve_next_token (NULL); + if (! token) + { + ret = 1; + break; + } + + /* This is the algorithm (right, FIXME?). */ + token = retrieve_next_token (NULL); + if (! token) + { + ret = 1; + break; + } + is_rsa = ! strcmp (token, "1"); + + /* This is the fingerprint. */ + token = retrieve_next_token (NULL); + if (! token) + { + ret = 1; + break; + } + + if (! strcmp (token, fpr)) + { + /* Found our key. */ + if (! is_rsa) + { + /* FIXME. */ + ret = 1; + break; + } + found_key = 1; + } + } + } + else + { + if (! strcmp (token, "sub")) + /* Next key entry, break. */ + break; + + if (! strcmp (token, "pkd")) + { + if ((pkd_n == 0) || (pkd_n == 1)) + { + /* This is the pkd index. */ + token = retrieve_next_token (NULL); + if (! token) + { + /* FIXME. */ + ret = 1; + break; + } + + /* This is the pkd size. */ + token = retrieve_next_token (NULL); + if (! token) + { + /* FIXME. */ + ret = 1; + break; + } + + /* This is the pkd mpi. */ + token = retrieve_next_token (NULL); + if (! token) + { + /* FIXME. */ + ret = 1; + break; + } + + err = gcry_mpi_scan (&mpi, GCRYMPI_FMT_HEX, token, 0, NULL); + if (err) + { + log_error ("error while converting pkd %i from hex: %s\n", + pkd_n, gcry_strerror (err)); + ret = 1; + break; + } + + if (pkd_n == 0) + err = gcry_mpi_aprint (GCRYMPI_FMT_STD, + &m_new, &m_new_n, mpi); + else + err = gcry_mpi_aprint (GCRYMPI_FMT_STD, + &e_new, &e_new_n, mpi); + if (err) + { + log_error ("error while converting pkd %i to std: %s\n", + pkd_n, gcry_strerror (err)); + ret = 1; + break; + } + gcry_mpi_release (mpi); + mpi = NULL; + pkd_n++; + } + else + { + /* Too many pkd entries. */ + /* FIXME */ + ret = 1; + break; + } + } + } + } + if (ret) + goto out; + + if (pkd_n < 2) + { + /* Not enough pkds retrieved. */ + ret = 1; + goto out; + } + + *m = m_new; + *mlen = m_new_n; + *e = e_new; + *elen = e_new_n; + + out: + + if (ret) + { + gcry_free (m_new); + gcry_free (e_new); + } + gcry_mpi_release (mpi); + gcry_free (line); + + return ret; +} /* Get the public key for KEYNO and store it as an S-expresion with the APP handle. On error that field gets cleared. If we already @@ -875,30 +1132,75 @@ get_public_key (app_t app, int keyno) e = ebuf; } - - err = gcry_sexp_build (&sexp, NULL, - "(public-key (rsa (n %b) (e %b)))", - (int)mlen, m,(int)elen, e); - if (err) - { - log_error ("error formatting the key into an S-expression: %s\n", - gpg_strerror (err)); - goto leave; - } - app->app_local->pk[keyno].key = sexp; - } else { /* Due to a design problem in v1.0 cards we can't get the public key out of these cards without doing a verify on CHV3. Clearly that is not an option and thus we try to locate the - key using an external helper. */ + key using an external helper. + + The helper we use here is gpg itself, which should know about + the key in any case. */ + + char fpr_long[41]; + char *fpr = fpr_long + 24; + char *command; + FILE *fp; + int ret; + + command = NULL; + + err = retrieve_fpr_from_card (app->slot, fpr_long); + if (err) + { + log_error ("error while retrieving fpr from card: %s\n", + gpg_strerror (err)); + goto leave; + } + + ret = asprintf (&command, + "gpg --list-keys --with-colons --with-key-data '%s'", + fpr_long); + if (ret < 0) + { + err = gpg_error_from_errno (errno); + log_error ("error while creating pipe command " + "for retrieving key: %s\n", gpg_strerror (err)); + goto leave; + } + + fp = popen (command, "r"); + if (! fp) + { + err = gpg_error_from_errno (errno); + log_error ("error while creating pipe: %s\n", gpg_strerror (err)); + goto leave; + } + + ret = retrieve_key_material (fp, fpr, &m, &mlen, &e, &elen); + fclose (fp); + if (ret) + { + /* FIXME? */ + err = gpg_error (GPG_ERR_INTERNAL); + log_error ("error while retrieving key material through pipe\n"); + goto leave; + } buffer = NULL; - /* FIXME */ + } + err = gcry_sexp_build (&sexp, NULL, + "(public-key (rsa (n %b) (e %b)))", + (int)mlen, m,(int)elen, e); + if (err) + { + log_error ("error formatting the key into an S-expression: %s\n", + gpg_strerror (err)); + goto leave; } + app->app_local->pk[keyno].key = sexp; leave: /* Set a flag to indicate that we tried to read the key. */ -- cgit From 6b002f06026b5555aabb84c194e3f4aa1f8692b2 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 11 Apr 2005 16:20:10 +0000 Subject: * app-openpgp.c (do_check_pin): Add hack to allow verification of CHV3. (get_public_key): Don't use gcry functions to create S-expressions. (do_deinit, do_readkey, do_genkey, send_keypair_info): Adjust for above change. --- scd/ChangeLog | 30 ++++++++++++ scd/app-openpgp.c | 144 +++++++++++++++++++++++++++++++++++++----------------- scd/app.c | 2 +- scd/ccid-driver.c | 89 +++++++++++++++++++++++---------- scd/command.c | 66 ++++++++++++++++++------- 5 files changed, 241 insertions(+), 90 deletions(-) (limited to 'scd/app-openpgp.c') diff --git a/scd/ChangeLog b/scd/ChangeLog index ca7358406..f8f8043c1 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,11 @@ +2005-04-07 Werner Koch + + * app-openpgp.c (do_check_pin): Add hack to allow verification of + CHV3. + (get_public_key): Don't use gcry functions to create S-expressions. + (do_deinit, do_readkey, do_genkey, send_keypair_info): Adjust for + above change. + 2005-03-29 Moritz Schulte * app-openpgp.c (retrieve_fpr_from_card): New function. @@ -6,6 +14,19 @@ (get_public_key): Implement retrival of key through expernal helper (gpg) in case the openpgp card is not cooperative enough. +2005-03-16 Werner Koch + + * ccid-driver.c (parse_ccid_descriptor): Make SCM workaround + reader type specific. + (scan_or_find_devices): Do not check the interface subclass in the + SPR532 kludge, as this depends on the firmware version. + (ccid_get_atr): Get the Slot status first. This solves the + problem with readers hanging on recent Linux 2.6.x. + (bulk_in): Add argument TIMEOUT and changed all callers to pass an + appropriate one. Change the standard timeout from 10 to 5 seconds. + (ccid_slot_status): Add a retry code with an initial short timeout. + (do_close_reader): Do an usb_reset before closing the reader. + 2005-02-25 Werner Koch * app-openpgp.c (get_public_key): Make sure not to return negative @@ -42,6 +63,15 @@ (reset_pcsc_reader, pcsc_get_status, pcsc_send_apdu) (open_pcsc_reader): Do proper error code mapping. +2005-03-16 Werner Koch + + * ccid-driver.c (parse_ccid_descriptor): Make SCM workaround + reader type specific. + (scan_or_find_devices): Do not check the interface subclass in the + SPR532 kludge, as this depends on the firmware version. + (ccid_get_atr): Get the Slot status first. This solves the + problem with readers hanging on recent Linux 2.6.x. + 2005-02-22 Werner Koch * app-openpgp.c (app_local_s): New field PK. diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index bae9dde49..1ed057195 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -108,7 +108,14 @@ struct app_local_s { struct { int read_done; /* True if we have at least tried to read them. */ - gcry_sexp_t key; /* Might be NULL if key is not available. */ + unsigned char *key; /* This is a malloced buffer with a canonical + encoded S-expression encoding a public + key. Might be NULL if key is not + available. */ + size_t keylen; /* The length of the above S-expression. Thsi + is usullay only required for corss checks + because the length of an S-expression is + implicitly available. */ } pk[3]; /* Keep track of card capabilities. */ @@ -156,7 +163,7 @@ do_deinit (app_t app) for (i=0; i < DIM (app->app_local->pk); i++) { - gcry_sexp_release (app->app_local->pk[i].key); + xfree (app->app_local->pk[i].key); app->app_local->pk[i].read_done = 0; } xfree (app->app_local); @@ -864,6 +871,10 @@ retrieve_key_material (FILE *fp, const char *fpr, mpi = NULL; ret = 0; +#warning This part should get rewritten for clarity + /* We should use an algorithm similar to the one used by gpgme. + This will reduce the size of the code at least by 50%. [wk] */ + while (1) { /* FIXME? */ @@ -1041,7 +1052,9 @@ retrieve_key_material (FILE *fp, const char *fpr, presence of the app->app_local->pk[KEYNO-1].key field. Note that GnuPG 1.x does not need this and it would be too time - consuming to send it just for the fun of it. */ + consuming to send it just for the fun of it. However, given that we + use the same code in gpg 1.4, we can't use the gcry S-expresion + here but need to open encode it. */ #if GNUPG_MAJOR_VERSION > 1 static gpg_error_t get_public_key (app_t app, int keyno) @@ -1050,9 +1063,10 @@ get_public_key (app_t app, int keyno) unsigned char *buffer; const unsigned char *keydata, *m, *e; size_t buflen, keydatalen, mlen, elen; - gcry_sexp_t sexp; unsigned char *mbuf = NULL; unsigned char *ebuf = NULL; + unsigned char *keybuf = NULL; + unsigned char *keybuf_p; if (keyno < 1 || keyno > 3) return gpg_error (GPG_ERR_INV_ID); @@ -1062,8 +1076,9 @@ get_public_key (app_t app, int keyno) if (app->app_local->pk[keyno].read_done) return 0; - gcry_sexp_release (app->app_local->pk[keyno].key); + xfree (app->app_local->pk[keyno].key); app->app_local->pk[keyno].key = NULL; + app->app_local->pk[keyno].keylen = 0; if (app->card_version > 0x0100) { @@ -1191,16 +1206,29 @@ get_public_key (app_t app, int keyno) buffer = NULL; } - err = gcry_sexp_build (&sexp, NULL, - "(public-key (rsa (n %b) (e %b)))", - (int)mlen, m,(int)elen, e); - if (err) + /* Allocate a buffer to construct the S-expression. */ + /* FIXME: We should provide a generalized S-expression creation + mechanism. */ + keybuf = xtrymalloc (50 + 2*35 + mlen + elen + 1); + if (!keybuf) { - log_error ("error formatting the key into an S-expression: %s\n", - gpg_strerror (err)); + err = gpg_error_from_errno (errno); goto leave; } - app->app_local->pk[keyno].key = sexp; + + sprintf (keybuf, "(10:public-key(3:rsa(1:n%u", (unsigned int) mlen); + keybuf_p = keybuf + strlen (keybuf); + memcpy (keybuf_p, m, mlen); + keybuf_p += mlen; + sprintf (keybuf_p, ")(1:e%u", (unsigned int)elen); + keybuf_p += strlen (keybuf_p); + memcpy (keybuf_p, e, elen); + keybuf_p += elen; + strcpy (keybuf_p, ")))"); + keybuf_p += strlen (keybuf_p); + + app->app_local->pk[keyno].key = keybuf; + app->app_local->pk[keyno].keylen = (keybuf_p - keybuf); leave: /* Set a flag to indicate that we tried to read the key. */ @@ -1224,7 +1252,6 @@ send_keypair_info (app_t app, ctrl_t ctrl, int keyno) /* Note that GnuPG 1.x does not need this and it would be too time consuming to send it just for the fun of it. */ #if GNUPG_MAJOR_VERSION > 1 - gcry_sexp_t sexp; unsigned char grip[20]; char gripstr[41]; char idbuf[50]; @@ -1235,15 +1262,14 @@ send_keypair_info (app_t app, ctrl_t ctrl, int keyno) goto leave; assert (keyno >= 1 && keyno <= 3); - sexp = app->app_local->pk[keyno-1].key; - if (!sexp) - goto leave; /* No such key. */ + if (!app->app_local->pk[keyno-1].key) + goto leave; /* No such key - ignore. */ - if (!gcry_pk_get_keygrip (sexp, grip)) - { - err = gpg_error (GPG_ERR_INTERNAL); - goto leave; - } + err = keygrip_from_canon_sexp (app->app_local->pk[keyno-1].key, + app->app_local->pk[keyno-1].keylen, + grip); + if (err) + goto leave; for (i=0; i < 20; i++) sprintf (gripstr+i*2, "%02X", grip[i]); @@ -1303,9 +1329,7 @@ do_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen) { gpg_error_t err; int keyno; - size_t n; unsigned char *buf; - gcry_sexp_t sexp; if (!strcmp (keyid, "OPENPGP.1")) keyno = 1; @@ -1320,24 +1344,11 @@ do_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen) if (err) return err; - sexp = app->app_local->pk[keyno-1].key; - if (!sexp) - return gpg_error (GPG_ERR_NO_PUBKEY); - - n = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, NULL, 0); - if (!n) - return gpg_error (GPG_ERR_BUG); - buf = xtrymalloc (n); + buf = app->app_local->pk[keyno-1].key; if (!buf) - return gpg_error_from_errno (errno); - n = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, buf, n); - if (!n) - { - xfree (buf); - return gpg_error (GPG_ERR_BUG); - } + return gpg_error (GPG_ERR_NO_PUBKEY); *pk = buf; - *pklen = n; + *pklen = app->app_local->pk[keyno-1].keylen;; return 0; } @@ -1590,7 +1601,7 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, int reset_mode, else app->did_chv1 = app->did_chv2 = 0; - /* Note to translators: Do not translate the "|*|" prefixes but + /* TRANSLATORS: Do not translate the "|*|" prefixes but keep it at the start of the string. We need this elsewhere to get some infos on the string. */ rc = pincb (pincb_arg, chvno == 3? _("|AN|New Admin PIN") : _("|N|New PIN"), @@ -1661,7 +1672,9 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags, flush_cache (app); /* Obviously we need to remove the cached public key. */ - gcry_sexp_release (app->app_local->pk[keyno].key); + xfree (app->app_local->pk[keyno].key); + app->app_local->pk[keyno].key = NULL; + app->app_local->pk[keyno].keylen = 0; app->app_local->pk[keyno].read_done = 0; /* Check whether a key already exists. */ @@ -2142,7 +2155,11 @@ do_decipher (app_t app, const char *keyidstr, cheap check on the PIN: If there is something wrong with the PIN entry system, only the regular CHV will get blocked and not the dangerous CHV3. KEYIDSTR is the usual card's serial number; an - optional fingerprint part will be ignored. */ + optional fingerprint part will be ignored. + + There is a special mode if the keyidstr is "[CHV3]" with + the "[CHV3]" being a literal string: The Admin Pin is checked if + and only if the retry counter is still at 3. */ static int do_check_pin (app_t app, const char *keyidstr, int (pincb)(void*, const char *, char **), @@ -2151,6 +2168,7 @@ do_check_pin (app_t app, const char *keyidstr, unsigned char tmp_sn[20]; const char *s; int n; + int admin_pin = 0; if (!keyidstr || !*keyidstr) return gpg_error (GPG_ERR_INV_VALUE); @@ -2167,6 +2185,8 @@ do_check_pin (app_t app, const char *keyidstr, ; /* No fingerprint given: we allow this for now. */ else if (*s == '/') ; /* We ignore a fingerprint. */ + else if (!strcmp (s, "[CHV3]") ) + admin_pin = 1; else return gpg_error (GPG_ERR_INV_ID); @@ -2177,12 +2197,46 @@ do_check_pin (app_t app, const char *keyidstr, return gpg_error (GPG_ERR_INV_CARD); if (memcmp (app->serialno, tmp_sn, 16)) return gpg_error (GPG_ERR_WRONG_CARD); + /* Yes, there is a race conditions: The user might pull the card right here and we won't notice that. However this is not a problem and the check above is merely for a graceful failure between operations. */ - return verify_chv2 (app, pincb, pincb_arg); + if (admin_pin) + { + void *relptr; + unsigned char *value; + size_t valuelen; + int count; + + relptr = get_one_do (app, 0x00C4, &value, &valuelen, NULL); + if (!relptr || valuelen < 7) + { + log_error (_("error retrieving CHV status from card\n")); + xfree (relptr); + return gpg_error (GPG_ERR_CARD); + } + count = value[6]; + xfree (relptr); + + if (!count) + { + log_info (_("card is permanently locked!\n")); + return gpg_error (GPG_ERR_BAD_PIN); + } + else if (value[6] < 3) + { + log_info (_("verification of Admin PIN is currently prohibited " + "through this command\n")); + return gpg_error (GPG_ERR_GENERAL); + } + + app->did_chv3 = 0; /* Force verification. */ + return verify_chv3 (app, pincb, pincb_arg); + } + else + return verify_chv2 (app, pincb, pincb_arg); } @@ -2415,7 +2469,9 @@ app_openpgp_storekey (app_t app, int keyno, flush_cache (app); - gcry_sexp_release (app->app_local->pk[keyno].key); + xfree (app->app_local->pk[keyno].key); + app->app_local->pk[keyno].key = NULL; + app->app_local->pk[keyno].keylen = 0; app->app_local->pk[keyno].read_done = 0; rc = iso7816_put_data (app->slot, diff --git a/scd/app.c b/scd/app.c index 0625dc8ef..e035e9b89 100644 --- a/scd/app.c +++ b/scd/app.c @@ -489,7 +489,7 @@ app_change_pin (APP app, CTRL ctrl, const char *chvnostr, int reset_mode, /* Perform a VERIFY operation without doing anything lese. This may - be used to initialze a the PION cache for long lasting other + be used to initialze a the PIN cache for long lasting other operations. Its use is highly application dependent. */ int app_check_pin (APP app, const char *keyidstr, diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c index 459060830..13e11e4bc 100644 --- a/scd/ccid-driver.c +++ b/scd/ccid-driver.c @@ -1,5 +1,5 @@ /* ccid-driver.c - USB ChipCardInterfaceDevices driver - * Copyright (C) 2003, 2004 Free Software Foundation, Inc. + * Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. * Written by Werner Koch. * * This file is part of GnuPG. @@ -52,7 +52,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id$ + * $Date$ */ @@ -223,7 +223,7 @@ static unsigned int compute_edc (const unsigned char *data, size_t datalen, int use_crc); static int bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen); static int bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length, - size_t *nread, int expected_type, int seqno); + size_t *nread, int expected_type, int seqno, int timeout); /* Convert a little endian stored 4 byte value into an unsigned integer. */ @@ -446,12 +446,20 @@ parse_ccid_descriptor (ccid_driver_t handle, send a frame of n*wMaxPacketSize back to us. Given that wMaxPacketSize is 64 for these readers we set the IFSD to a value lower than that: - 64 - 10 CCID header - 4 T1frame - 2 reserved = 48 */ + 64 - 10 CCID header - 4 T1frame - 2 reserved = 48 + Product Ids: + 0xe001 - SCR 331 + 0x5111 - SCR 331-DI + 0x5115 - SCR 335 + 0xe003 - SPR 532 + */ if (handle->id_vendor == VENDOR_SCM - /* FIXME: check whether it is the same - firmware version for all drivers. */ - && handle->bcd_device < 0x0519 - && handle->max_ifsd > 48) + && handle->max_ifsd > 48 + && ( (handle->id_product == 0xe001 && handle->bcd_device < 0x0516) + ||(handle->id_product == 0x5111 && handle->bcd_device < 0x0620) + ||(handle->id_product == 0x5115 && handle->bcd_device < 0x0519) + ||(handle->id_product == 0xe003 && handle->bcd_device < 0x0504) + )) { DEBUGOUT ("enabling workaround for buggy SCM readers\n"); handle->max_ifsd = 48; @@ -699,9 +707,7 @@ scan_or_find_devices (int readerno, const char *readerid, && ifcdesc->bInterfaceProtocol == 0) || (ifcdesc->bInterfaceClass == 255 && dev->descriptor.idVendor == 0x04e6 - && dev->descriptor.idProduct == 0xe003 - && ifcdesc->bInterfaceSubClass == 1 - && ifcdesc->bInterfaceProtocol == 1))) + && dev->descriptor.idProduct == 0xe003))) { idev = usb_open (dev); if (!idev) @@ -974,11 +980,13 @@ do_close_reader (ccid_driver_t handle) rc = bulk_out (handle, msg, msglen); if (!rc) - bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus,seqno); + bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus, + seqno, 2000); handle->powered_off = 1; } if (handle->idev) { + usb_reset (handle->idev); usb_release_interface (handle->idev, handle->ifc_no); usb_close (handle->idev); handle->idev = NULL; @@ -1102,10 +1110,10 @@ bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen) BUFFER and return the actual read number if bytes in NREAD. SEQNO is the sequence number used to send the request and EXPECTED_TYPE the type of message we expect. Does checks on the ccid - header. Returns 0 on success. */ + header. TIMEOUT is the timeout value in ms. Returns 0 on success. */ static int bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length, - size_t *nread, int expected_type, int seqno) + size_t *nread, int expected_type, int seqno, int timeout) { int i, rc; size_t msglen; @@ -1117,9 +1125,7 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length, rc = usb_bulk_read (handle->idev, handle->ep_bulk_in, buffer, length, - 10000 /* ms timeout */ ); - /* Fixme: instead of using a 10 second timeout we should better - handle the timeout here and retry if appropriate. */ + timeout); if (rc < 0) { DEBUGOUT_1 ("usb_bulk_read error: %s\n", strerror (errno)); @@ -1175,7 +1181,7 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length, } -/* Note that this fucntion won't return the error codes NO_CARD or +/* Note that this function won't return the error codes NO_CARD or CARD_INACTIVE */ static int send_escape_cmd (ccid_driver_t handle, @@ -1206,7 +1212,8 @@ send_escape_cmd (ccid_driver_t handle, rc = bulk_out (handle, msg, msglen); if (rc) return rc; - rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Escape, seqno); + rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Escape, + seqno, 5000); return rc; } @@ -1276,7 +1283,9 @@ ccid_slot_status (ccid_driver_t handle, int *statusbits) unsigned char msg[100]; size_t msglen; unsigned char seqno; + int retries = 0; + retry: msg[0] = PC_to_RDR_GetSlotStatus; msg[5] = 0; /* slot */ msg[6] = seqno = handle->seqno++; @@ -1288,7 +1297,21 @@ ccid_slot_status (ccid_driver_t handle, int *statusbits) rc = bulk_out (handle, msg, 10); if (rc) return rc; - rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus, seqno); + rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus, + seqno, retries? 1000 : 200); + if (rc == CCID_DRIVER_ERR_CARD_IO_ERROR && retries < 3) + { + if (!retries) + { + fprintf (stderr, "CALLING USB_CLEAR_HALT\n"); + usb_clear_halt (handle->idev, handle->ep_bulk_in); + usb_clear_halt (handle->idev, handle->ep_bulk_out); + } + else + fprintf (stderr, "RETRYING AGIAN\n"); + retries++; + goto retry; + } if (rc && rc != CCID_DRIVER_ERR_NO_CARD && rc != CCID_DRIVER_ERR_CARD_INACTIVE) return rc; @@ -1303,6 +1326,7 @@ ccid_get_atr (ccid_driver_t handle, unsigned char *atr, size_t maxatrlen, size_t *atrlen) { int rc; + int statusbits; unsigned char msg[100]; unsigned char *tpdu; size_t msglen, tpdulen; @@ -1311,6 +1335,15 @@ ccid_get_atr (ccid_driver_t handle, unsigned int edc; int i; + /* First check whether a card is available. */ + rc = ccid_slot_status (handle, &statusbits); + if (rc) + return rc; + if (statusbits == 2) + return CCID_DRIVER_ERR_NO_CARD; + + /* For an inactive and also for an active card, issue the PowerOn + command to get the ATR. */ msg[0] = PC_to_RDR_IccPowerOn; msg[5] = 0; /* slot */ msg[6] = seqno = handle->seqno++; @@ -1323,7 +1356,8 @@ ccid_get_atr (ccid_driver_t handle, rc = bulk_out (handle, msg, msglen); if (rc) return rc; - rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_DataBlock, seqno); + rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_DataBlock, + seqno, 5000); if (rc) return rc; @@ -1367,7 +1401,8 @@ ccid_get_atr (ccid_driver_t handle, if (rc) return rc; /* Note that we ignore the error code on purpose. */ - bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Parameters, seqno); + bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Parameters, + seqno, 5000); handle->t1_ns = 0; handle->t1_nr = 0; @@ -1414,7 +1449,7 @@ ccid_get_atr (ccid_driver_t handle, rc = bulk_in (handle, msg, sizeof msg, &msglen, - RDR_to_PC_DataBlock, seqno); + RDR_to_PC_DataBlock, seqno, 5000); if (rc) return rc; @@ -1510,7 +1545,7 @@ ccid_transceive_apdu_level (ccid_driver_t handle, msg = recv_buffer; rc = bulk_in (handle, msg, sizeof recv_buffer, &msglen, - RDR_to_PC_DataBlock, seqno); + RDR_to_PC_DataBlock, seqno, 5000); if (rc) return rc; @@ -1683,7 +1718,7 @@ ccid_transceive (ccid_driver_t handle, msg = recv_buffer; rc = bulk_in (handle, msg, sizeof recv_buffer, &msglen, - RDR_to_PC_DataBlock, seqno); + RDR_to_PC_DataBlock, seqno, 5000); if (rc) return rc; @@ -1692,7 +1727,7 @@ ccid_transceive (ccid_driver_t handle, if (tpdulen < 4) { - usb_clear_halt (handle->idev, 0x82); + usb_clear_halt (handle->idev, handle->ep_bulk_in); return CCID_DRIVER_ERR_ABORTED; } #ifdef DEBUG_T1 @@ -1960,7 +1995,7 @@ ccid_transceive_secure (ccid_driver_t handle, msg = recv_buffer; rc = bulk_in (handle, msg, sizeof recv_buffer, &msglen, - RDR_to_PC_DataBlock, seqno); + RDR_to_PC_DataBlock, seqno, 5000); if (rc) return rc; diff --git a/scd/command.c b/scd/command.c index 63e3e28e1..ea296b6fb 100644 --- a/scd/command.c +++ b/scd/command.c @@ -108,7 +108,7 @@ do_reset (ctrl_t ctrl, int do_close) static void -reset_notify (ASSUAN_CONTEXT ctx) +reset_notify (assuan_context_t ctx) { CTRL ctrl = assuan_get_pointer (ctx); @@ -117,7 +117,7 @@ reset_notify (ASSUAN_CONTEXT ctx) static int -option_handler (ASSUAN_CONTEXT ctx, const char *key, const char *value) +option_handler (assuan_context_t ctx, const char *key, const char *value) { ctrl_t ctrl = assuan_get_pointer (ctx); @@ -248,6 +248,10 @@ cmd_serialno (assuan_context_t ctx, char *line) time_t stamp; /* Clear the remove flag so that the open_card is able to reread it. */ + + /* FIXME: We can't do that if we are in a locked state. Retrun an + appropriate erro r in that case. IF the card has not been + removed we may very well continue. */ if (ctrl->server_local->card_removed) do_reset (ctrl, 0); @@ -333,9 +337,10 @@ cmd_serialno (assuan_context_t ctx, char *line) The URL to be used for locating the entire public key. + Note, that this function may be even be used on a locked card. */ static int -cmd_learn (ASSUAN_CONTEXT ctx, char *line) +cmd_learn (assuan_context_t ctx, char *line) { CTRL ctrl = assuan_get_pointer (ctx); int rc = 0; @@ -481,9 +486,10 @@ cmd_learn (ASSUAN_CONTEXT ctx, char *line) /* READCERT + Note, that this function may be even be used on a locked card. */ static int -cmd_readcert (ASSUAN_CONTEXT ctx, char *line) +cmd_readcert (assuan_context_t ctx, char *line) { CTRL ctrl = assuan_get_pointer (ctx); int rc; @@ -524,7 +530,10 @@ cmd_readcert (ASSUAN_CONTEXT ctx, char *line) /* READKEY Return the public key for the given cert or key ID as an standard - S-Expression. */ + S-Expression. + + Note, that this function may be even be used on a locked card. + */ static int cmd_readkey (assuan_context_t ctx, char *line) { @@ -619,14 +628,16 @@ cmd_readkey (assuan_context_t ctx, char *line) The client should use this command to tell us the data he want to sign. */ static int -cmd_setdata (ASSUAN_CONTEXT ctx, char *line) +cmd_setdata (assuan_context_t ctx, char *line) { CTRL ctrl = assuan_get_pointer (ctx); int n; char *p; unsigned char *buf; - /* parse the hexstring */ + /* FIXME: If we are locked return an error. */ + + /* Parse the hexstring. */ for (p=line,n=0; hexdigitp (p); p++, n++) ; if (*p) @@ -652,7 +663,7 @@ cmd_setdata (ASSUAN_CONTEXT ctx, char *line) static int pin_cb (void *opaque, const char *info, char **retstr) { - ASSUAN_CONTEXT ctx = opaque; + assuan_context_t ctx = opaque; char *command; int rc; unsigned char *value; @@ -687,7 +698,7 @@ pin_cb (void *opaque, const char *info, char **retstr) */ static int -cmd_pksign (ASSUAN_CONTEXT ctx, char *line) +cmd_pksign (assuan_context_t ctx, char *line) { CTRL ctrl = assuan_get_pointer (ctx); int rc; @@ -695,6 +706,8 @@ cmd_pksign (ASSUAN_CONTEXT ctx, char *line) size_t outdatalen; char *keyidstr; + /* FIXME: If we are locked return an error. */ + if ((rc = open_card (ctrl, NULL))) return rc; @@ -738,7 +751,7 @@ cmd_pksign (ASSUAN_CONTEXT ctx, char *line) */ static int -cmd_pkauth (ASSUAN_CONTEXT ctx, char *line) +cmd_pkauth (assuan_context_t ctx, char *line) { CTRL ctrl = assuan_get_pointer (ctx); int rc; @@ -746,6 +759,8 @@ cmd_pkauth (ASSUAN_CONTEXT ctx, char *line) size_t outdatalen; char *keyidstr; + /* FIXME: If we are locked return an error. */ + if ((rc = open_card (ctrl, NULL))) return rc; @@ -785,7 +800,7 @@ cmd_pkauth (ASSUAN_CONTEXT ctx, char *line) */ static int -cmd_pkdecrypt (ASSUAN_CONTEXT ctx, char *line) +cmd_pkdecrypt (assuan_context_t ctx, char *line) { CTRL ctrl = assuan_get_pointer (ctx); int rc; @@ -793,6 +808,8 @@ cmd_pkdecrypt (ASSUAN_CONTEXT ctx, char *line) size_t outdatalen; char *keyidstr; + /* FIXME: If we are locked return an error. */ + if ((rc = open_card (ctrl, NULL))) return rc; @@ -834,14 +851,15 @@ cmd_pkdecrypt (ASSUAN_CONTEXT ctx, char *line) This command is used to retrieve data from a smartcard. The allowed names depend on the currently selected smartcard application. NAME must be percent and '+' escaped. The value is - returned through status message, see the LESRN command for details. + returned through status message, see the LEARN command for details. However, the current implementation assumes that Name is not escaped; this works as long as noone uses arbitrary escaping. + Note, that this function may even be used on a locked card. */ static int -cmd_getattr (ASSUAN_CONTEXT ctx, char *line) +cmd_getattr (assuan_context_t ctx, char *line) { CTRL ctrl = assuan_get_pointer (ctx); int rc; @@ -858,6 +876,8 @@ cmd_getattr (ASSUAN_CONTEXT ctx, char *line) /* (We ignore any garbage for now.) */ + /* FIXME: Applications should not return sensistive data if the card + is locked. */ rc = app_getattr (ctrl->app_ctx, ctrl, keyword); TEST_CARD_REMOVAL (ctrl, rc); @@ -878,7 +898,7 @@ cmd_getattr (ASSUAN_CONTEXT ctx, char *line) setattr function of the actually used application (app-*.c) for details. */ static int -cmd_setattr (ASSUAN_CONTEXT ctx, char *orig_line) +cmd_setattr (assuan_context_t ctx, char *orig_line) { CTRL ctrl = assuan_get_pointer (ctx); int rc; @@ -887,6 +907,8 @@ cmd_setattr (ASSUAN_CONTEXT ctx, char *orig_line) size_t nbytes; char *line, *linebuf; + /* FIXME: If we are locked return an error. */ + if ((rc = open_card (ctrl, NULL))) return rc; @@ -932,13 +954,15 @@ cmd_setattr (ASSUAN_CONTEXT ctx, char *orig_line) */ static int -cmd_genkey (ASSUAN_CONTEXT ctx, char *line) +cmd_genkey (assuan_context_t ctx, char *line) { CTRL ctrl = assuan_get_pointer (ctx); int rc; char *keyno; int force = has_option (line, "--force"); + /* FIXME: If we are locked return an error. */ + /* Skip over options. */ while ( *line == '-' && line[1] == '-' ) { @@ -974,9 +998,11 @@ cmd_genkey (ASSUAN_CONTEXT ctx, char *line) /* RANDOM Get NBYTES of random from the card and send them back as data. + + Note, that this function may be even be used on a locked card. */ static int -cmd_random (ASSUAN_CONTEXT ctx, char *line) +cmd_random (assuan_context_t ctx, char *line) { CTRL ctrl = assuan_get_pointer (ctx); int rc; @@ -1016,13 +1042,15 @@ cmd_random (ASSUAN_CONTEXT ctx, char *line) Change the PIN or reset thye retry counter of the card holder verfication vector CHVNO. */ static int -cmd_passwd (ASSUAN_CONTEXT ctx, char *line) +cmd_passwd (assuan_context_t ctx, char *line) { CTRL ctrl = assuan_get_pointer (ctx); int rc; char *chvnostr; int reset_mode = has_option (line, "--reset"); + /* FIXME: If we are locked return an error. */ + /* Skip over options. */ while (*line == '-' && line[1] == '-') { @@ -1061,12 +1089,14 @@ cmd_passwd (ASSUAN_CONTEXT ctx, char *line) */ static int -cmd_checkpin (ASSUAN_CONTEXT ctx, char *line) +cmd_checkpin (assuan_context_t ctx, char *line) { CTRL ctrl = assuan_get_pointer (ctx); int rc; char *keyidstr; + /* FIXME: If we are locked return an error. */ + if ((rc = open_card (ctrl, NULL))) return rc; -- cgit From 9f9a18c011cba01c043a50b326b767e19b07019d Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 14 Apr 2005 17:25:43 +0000 Subject: (retrieve_key_material): Rewritten. Return a proper error code. (retrieve_next_token): Removed. (retrieve_fpr_from_card): Rewritten to make use of DO caching and to take the KEYNO as arg. (get_public_key): Renamed variable for clarity. --- scd/ChangeLog | 28 ++++ scd/app-openpgp.c | 392 +++++++++++++++++++----------------------------------- scd/command.c | 361 ++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 446 insertions(+), 335 deletions(-) (limited to 'scd/app-openpgp.c') diff --git a/scd/ChangeLog b/scd/ChangeLog index f8f8043c1..9d246ffca 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,31 @@ +2005-04-14 Werner Koch + + * app-openpgp.c (retrieve_key_material): Rewritten. Return a + proper error code. + (retrieve_next_token): Removed. + (retrieve_fpr_from_card): Rewritten to make use of DO caching and + to take the KEYNO as arg. + (get_public_key): Renamed variable for clarity. + +2005-04-12 Werner Koch + + Basic support for several sessions. + + * command.c (scd_command_handler): Replace the primary_connection + stuff by a real connection list. Release the local context on + exit. + (scd_update_reader_status_file): Update accordingly. Send signal + to all connections who registered an event signal. + (cmd_lock, cmd_unlock, register_commands): New commands LOCK and + UNLOCK. + (cmd_setdata, cmd_pksign, cmd_pkauth, cmd_pkdecrypt, cmd_setattr) + (cmd_genkey, cmd_passwd, cmd_checkpin): Return an error if reader + is locked. + (do_reset): Handle locking. + (open_card): Ditto. Share the reader slot with other sessions. + (get_reader_slot): New. + (update_card_removed): New. Use it in the TEST_CARD_REMOVAL macro. + 2005-04-07 Werner Koch * app-openpgp.c (do_check_pin): Add hack to allow verification of diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 1ed057195..0d80c41a7 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -784,266 +784,149 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name) } /* Retrieve the fingerprint from the card inserted in SLOT and write - the according hex representation (40 hex digits plus NUL character) - to FPR. */ + the according hex representation to FPR. Caller must have provide + a buffer at FPR of least 41 bytes. Returns 0 on success or an + error code. */ +#if GNUPG_MAJOR_VERSION > 1 static gpg_error_t -retrieve_fpr_from_card (int slot, char *fpr) +retrieve_fpr_from_card (app_t app, int keyno, char *fpr) { - const unsigned char *value; - unsigned char *data; - size_t data_n; - gpg_error_t err; - size_t value_n; - unsigned int i; + gpg_error_t err = 0; + void *relptr; + unsigned char *value; + size_t valuelen; + int i; - data = NULL; + assert (keyno >=0 && keyno <= 2); - err = iso7816_get_data (slot, 0x6E, &data, &data_n); - if (err) - /* FIXME */ - goto out; - - value = find_tlv (data, data_n, 0x00C5, &value_n); - if (! (value - && (! (value_n > (data_n - (value - data)))) - && (value_n >= 60))) /* FIXME: Shouldn't this be "== 60"? */ + relptr = get_one_do (app, 0x00C5, &value, &valuelen, NULL); + if (relptr && valuelen >= 60) { - /* FIXME? */ - err = gpg_error (GPG_ERR_CARD); /* */ - goto out; + for (i = 0; i < 20; i++) + sprintf (fpr + (i * 2), "%02X", value[(keyno*20)+i]); } - - /* Copy out third key FPR. */ - for (i = 0; i < 20; i++) - sprintf (fpr + (i * 2), "%02X", (value + (2 * 20))[i]); - - out: - - xfree (data); - + else + err = gpg_error (GPG_ERR_NOT_FOUND); + xfree (relptr); return err; } +#endif /*GNUPG_MAJOR_VERSION > 1*/ -/* Retrieve the next token from S, using ":" as delimiter. */ -static char * -retrieve_next_token (char *s) -{ - char *p; - - p = strtok (s, ":"); - if (! p) - log_error ("error while extracting token\n"); - return p; -} - -/* Retrieve the secret key material for the key, whose fingerprint is - FPR, from gpg output, which can be read through the stream FP. The - RSA modulus will be stored in m/mlen, the secret exponent in - e/elen. Return zero on success, one on failure. */ -static int -retrieve_key_material (FILE *fp, const char *fpr, +/* Retrieve the public key material for the RSA key, whose fingerprint + is FPR, from gpg output, which can be read through the stream FP. + The RSA modulus will be stored at the address of M and MLEN, the + public exponent at E and ELEN. Returns zero on success, an error + code on failure. Caller must release the allocated buffers at M + and E if the function returns success. */ +#if GNUPG_MAJOR_VERSION > 1 +static gpg_error_t +retrieve_key_material (FILE *fp, const char *hexkeyid, const unsigned char **m, size_t *mlen, const unsigned char **e, size_t *elen) { - size_t line_size; - ssize_t line_ret; - char *line; - int ret; - int found_key; - char *token; - int pkd_n; - unsigned char *m_new; - unsigned char *e_new; - size_t m_new_n; - size_t e_new_n; - int is_rsa; - gcry_mpi_t mpi; - gcry_error_t err; - size_t max_length; - - line_size = 0; - line = NULL; - found_key = 0; - pkd_n = 0; - m_new = NULL; - e_new = NULL; - mpi = NULL; - ret = 0; - -#warning This part should get rewritten for clarity - /* We should use an algorithm similar to the one used by gpgme. - This will reduce the size of the code at least by 50%. [wk] */ - - while (1) + gcry_error_t err = 0; + char *line = NULL; /* read_line() buffer. */ + size_t line_size = 0; /* Helper for for read_line. */ + int found_key = 0; /* Helper to find a matching key. */ + unsigned char *m_new = NULL; + unsigned char *e_new = NULL; + size_t m_new_n = 0; + size_t e_new_n = 0; + + /* Loop over all records until we have found the subkey + corresponsing to the fingerprint. Inm general the first record + should be the pub record, but we don't rely on that. Given that + we only need to look at one key, it is sufficient to compare the + keyid so that we don't need to look at "fpr" records. */ + for (;;) { - /* FIXME? */ - max_length = 1024; - line_ret = read_line (fp, &line, &line_size, &max_length); - if (line_ret < 0) - { - ret = 1; - break; - } - if (! line_ret) - /* EOF. */ - /* FIXME? */ - break; + char *p; + char *fields[6]; + int nfields; + size_t max_length; + gcry_mpi_t mpi; + int i; - token = retrieve_next_token (line); - if (! found_key) - { - /* Key not found yet, search for key entry. */ - if ((! strcmp (token, "pub")) || (! strcmp (token, "sub"))) - { - /* Reached next key entry, parse it. */ - - /* This is the trust level (right, FIXME?). */ - token = retrieve_next_token (NULL); - if (! token) - { - ret = 1; - break; - } - - /* This is the size. */ - token = retrieve_next_token (NULL); - if (! token) - { - ret = 1; - break; - } - - /* This is the algorithm (right, FIXME?). */ - token = retrieve_next_token (NULL); - if (! token) - { - ret = 1; - break; - } - is_rsa = ! strcmp (token, "1"); - - /* This is the fingerprint. */ - token = retrieve_next_token (NULL); - if (! token) - { - ret = 1; - break; - } - - if (! strcmp (token, fpr)) - { - /* Found our key. */ - if (! is_rsa) - { - /* FIXME. */ - ret = 1; - break; - } - found_key = 1; - } - } - } - else + max_length = 4096; + i = read_line (fp, &line, &line_size, &max_length); + if (!i) + break; /* EOF. */ + if (i < 0) { - if (! strcmp (token, "sub")) - /* Next key entry, break. */ - break; - - if (! strcmp (token, "pkd")) - { - if ((pkd_n == 0) || (pkd_n == 1)) - { - /* This is the pkd index. */ - token = retrieve_next_token (NULL); - if (! token) - { - /* FIXME. */ - ret = 1; - break; - } - - /* This is the pkd size. */ - token = retrieve_next_token (NULL); - if (! token) - { - /* FIXME. */ - ret = 1; - break; - } - - /* This is the pkd mpi. */ - token = retrieve_next_token (NULL); - if (! token) - { - /* FIXME. */ - ret = 1; - break; - } - - err = gcry_mpi_scan (&mpi, GCRYMPI_FMT_HEX, token, 0, NULL); - if (err) - { - log_error ("error while converting pkd %i from hex: %s\n", - pkd_n, gcry_strerror (err)); - ret = 1; - break; - } - - if (pkd_n == 0) - err = gcry_mpi_aprint (GCRYMPI_FMT_STD, - &m_new, &m_new_n, mpi); - else - err = gcry_mpi_aprint (GCRYMPI_FMT_STD, - &e_new, &e_new_n, mpi); - if (err) - { - log_error ("error while converting pkd %i to std: %s\n", - pkd_n, gcry_strerror (err)); - ret = 1; - break; - } - gcry_mpi_release (mpi); - mpi = NULL; - pkd_n++; - } - else - { - /* Too many pkd entries. */ - /* FIXME */ - ret = 1; - break; - } - } + err = gpg_error_from_errno (errno); + goto leave; /* Error. */ } - } - if (ret) - goto out; - - if (pkd_n < 2) - { - /* Not enough pkds retrieved. */ - ret = 1; - goto out; - } - - *m = m_new; - *mlen = m_new_n; - *e = e_new; - *elen = e_new_n; + if (!max_length) + { + err = gpg_error (GPG_ERR_TRUNCATED); + goto leave; /* Line truncated - we better stop processing. */ + } - out: + /* Parse the line into fields. */ + for (nfields=0, p=line; p && nfields < DIM (fields); nfields++) + { + fields[nfields] = p; + p = strchr (p, ':'); + if (p) + *(p++) = 0; + } + if (!nfields) + continue; /* No fields at all - skip line. */ - if (ret) + if (!found_key) + { + if ( (!strcmp (fields[0], "sub") || !strcmp (fields[0], "pub") ) + && nfields > 4 && !strcmp (fields[4], hexkeyid)) + found_key = 1; + continue; + } + + if ( !strcmp (fields[0], "sub") || !strcmp (fields[0], "pub") ) + break; /* Next key - stop. */ + + if ( strcmp (fields[0], "pkd") ) + continue; /* Not a key data record. */ + i = 0; /* Avoid erroneous compiler warning. */ + if ( nfields < 4 || (i = atoi (fields[1])) < 0 || i > 1 + || (!i && m_new) || (i && e_new)) + { + err = gpg_error (GPG_ERR_GENERAL); + goto leave; /* Error: Invalid key data record or not an RSA key. */ + } + + err = gcry_mpi_scan (&mpi, GCRYMPI_FMT_HEX, fields[3], 0, NULL); + if (err) + mpi = NULL; + else if (!i) + err = gcry_mpi_aprint (GCRYMPI_FMT_STD, &m_new, &m_new_n, mpi); + else + err = gcry_mpi_aprint (GCRYMPI_FMT_STD, &e_new, &e_new_n, mpi); + gcry_mpi_release (mpi); + if (err) + goto leave; + } + + if (m_new && e_new) { - gcry_free (m_new); - gcry_free (e_new); + *m = m_new; + *mlen = m_new_n; + m_new = NULL; + *e = e_new; + *elen = e_new_n; + e_new = NULL; } - gcry_mpi_release (mpi); - gcry_free (line); + else + err = gpg_error (GPG_ERR_GENERAL); - return ret; + leave: + xfree (m_new); + xfree (e_new); + xfree (line); + return err; } +#endif /*GNUPG_MAJOR_VERSION > 1*/ + /* Get the public key for KEYNO and store it as an S-expresion with the APP handle. On error that field gets cleared. If we already @@ -1158,52 +1041,49 @@ get_public_key (app_t app, int keyno) The helper we use here is gpg itself, which should know about the key in any case. */ - char fpr_long[41]; - char *fpr = fpr_long + 24; - char *command; + char fpr[41]; + char *hexkeyid; + char *command = NULL; FILE *fp; int ret; - command = NULL; + buffer = NULL; /* We don't need buffer. */ - err = retrieve_fpr_from_card (app->slot, fpr_long); + err = retrieve_fpr_from_card (app, keyno, fpr); if (err) { log_error ("error while retrieving fpr from card: %s\n", gpg_strerror (err)); goto leave; } + hexkeyid = fpr + 24; ret = asprintf (&command, "gpg --list-keys --with-colons --with-key-data '%s'", - fpr_long); + fpr); if (ret < 0) { err = gpg_error_from_errno (errno); - log_error ("error while creating pipe command " - "for retrieving key: %s\n", gpg_strerror (err)); goto leave; } fp = popen (command, "r"); - if (! fp) + free (command); + if (!fp) { err = gpg_error_from_errno (errno); - log_error ("error while creating pipe: %s\n", gpg_strerror (err)); + log_error ("running gpg failed: %s\n", gpg_strerror (err)); goto leave; } - ret = retrieve_key_material (fp, fpr, &m, &mlen, &e, &elen); + err = retrieve_key_material (fp, hexkeyid, &m, &mlen, &e, &elen); fclose (fp); - if (ret) + if (err) { - /* FIXME? */ - err = gpg_error (GPG_ERR_INTERNAL); - log_error ("error while retrieving key material through pipe\n"); + log_error ("error while retrieving key material through pipe: %s\n", + gpg_strerror (err)); goto leave; } - - buffer = NULL; } /* Allocate a buffer to construct the S-expression. */ @@ -1216,11 +1096,11 @@ get_public_key (app_t app, int keyno) goto leave; } - sprintf (keybuf, "(10:public-key(3:rsa(1:n%u", (unsigned int) mlen); + sprintf (keybuf, "(10:public-key(3:rsa(1:n%u:", (unsigned int) mlen); keybuf_p = keybuf + strlen (keybuf); memcpy (keybuf_p, m, mlen); keybuf_p += mlen; - sprintf (keybuf_p, ")(1:e%u", (unsigned int)elen); + sprintf (keybuf_p, ")(1:e%u:", (unsigned int)elen); keybuf_p += strlen (keybuf_p); memcpy (keybuf_p, e, elen); keybuf_p += elen; diff --git a/scd/command.c b/scd/command.c index ea296b6fb..9881b1be0 100644 --- a/scd/command.c +++ b/scd/command.c @@ -26,6 +26,9 @@ #include #include #include +#ifdef USE_GNU_PTH +# include +#endif #include @@ -38,11 +41,6 @@ #define MAXLEN_PIN 100 -/* We keep track of the primary client using scdaemon. This one will - for example receive signal on card change. */ -static ctrl_t primary_connection; - - #define set_error(e,t) assuan_set_error (ctx, ASSUAN_ ## e, (t)) @@ -52,20 +50,65 @@ static ctrl_t primary_connection; int _r = (r); \ if (gpg_err_code (_r) == GPG_ERR_CARD_NOT_PRESENT \ || gpg_err_code (_r) == GPG_ERR_CARD_REMOVED) \ - (c)->server_local->card_removed = 1; \ + update_card_removed ((c)->reader_slot, 1); \ } while (0) +#define IS_LOCKED(c) \ + (locked_session && locked_session != (c)->server_local \ + && (c)->reader_slot != -1 && locked_session->ctrl_backlink \ + && (c)->reader_slot == locked_session->ctrl_backlink->reader_slot) + -/* Data used to associate an Assuan context with local server data */ +/* Data used to associate an Assuan context with local server data. + This object describes the local properties of one session. */ struct server_local_s { + /* We keep a list of all active sessions with the anchor at + SESSION_LIST (see below). This field is used for linking. */ + struct server_local_s *next_session; + + /* This object is usually assigned to a CTRL object (which is + globally visible). While enumeratin all sessions we sometimes + need to access data of the CTRL object; thus we keep a + backpointer here. */ + ctrl_t ctrl_backlink; + + /* The Assuan context used by this session/server. */ assuan_context_t assuan_ctx; + int event_signal; /* Or 0 if not used. */ - int card_removed; /* True if the card has been removed and a - reset is required to continue - operation. */ + + /* True if the card has been removed and a reset is required to + continue operation. */ + int card_removed; }; +/* To keep track of all running sessions, we link all active server + contexts and the anchor in this variable. */ +static struct server_local_s *session_list; + +/* If a session has been locked we store a link to its server object + in this variable. */ +static struct server_local_s *locked_session; + + + + +/* Update the CARD_REMOVED element of all sessions using the reader + given by SLOT to VALUE */ +static void +update_card_removed (int slot, int value) +{ + struct server_local_s *sl; + + for (sl=session_list; sl; sl = sl->next_session) + if (sl->ctrl_backlink + && sl->ctrl_backlink->reader_slot == slot) + sl->card_removed = value; +} + + + /* Check whether the option NAME appears in LINE */ static int has_option (const char *line, const char *name) @@ -79,10 +122,13 @@ has_option (const char *line, const char *name) /* Reset the card and free the application context. With DO_CLOSE set - to true, close the reader and don't do just a reset. */ + to true and this is the last session with a reference to teh + reader, close the reader and don't do just a reset. */ static void do_reset (ctrl_t ctrl, int do_close) { + int slot = ctrl->reader_slot; + if (ctrl->card_ctx) { card_close (ctrl->card_ctx); @@ -97,20 +143,61 @@ do_reset (ctrl_t ctrl, int do_close) } if (ctrl->reader_slot != -1) { - if (do_close || apdu_reset (ctrl->reader_slot)) + struct server_local_s *sl; + + /* If we are the only session with the reader open we may close + it. If not, do a reset unless the a lock is held on the + reader. */ + for (sl=session_list; sl; sl = sl->next_session) + if (sl != ctrl->server_local + && sl->ctrl_backlink->reader_slot == ctrl->reader_slot) + break; + if (sl) /* There is another session with the reader open. */ + { + if ( IS_LOCKED (ctrl) ) /* If it is locked, release it. */ + ctrl->reader_slot = -1; + else + { + if (do_close) /* Always mark reader unused. */ + ctrl->reader_slot = -1; + else if (apdu_reset (ctrl->reader_slot)) /* Reset only if + not locked */ + { + /* The reset failed. Mark the reader as closed. */ + ctrl->reader_slot = -1; + } + + if (locked_session && ctrl->server_local == locked_session) + { + locked_session = NULL; + log_debug ("implicitly unlocking due to RESET\n"); + } + } + } + else /* No other session has the reader open. */ { - apdu_close_reader (ctrl->reader_slot); - ctrl->reader_slot = -1; + if (do_close || apdu_reset (ctrl->reader_slot)) + { + apdu_close_reader (ctrl->reader_slot); + ctrl->reader_slot = -1; + } + if ( IS_LOCKED (ctrl) ) + { + log_debug ("WARNING: cleaning up stale session lock\n"); + locked_session = NULL; + } } } - ctrl->server_local->card_removed = 0; + + /* Reset card removed flag for the current reader. */ + update_card_removed (slot, 0); } static void reset_notify (assuan_context_t ctx) { - CTRL ctrl = assuan_get_pointer (ctx); + ctrl_t ctrl = assuan_get_pointer (ctx); do_reset (ctrl, 0); } @@ -134,6 +221,27 @@ option_handler (assuan_context_t ctx, const char *key, const char *value) } +/* Return the slot of the current reader or open the reader if no + other sessions are using a reader. Note, that we currently support + only one reader but most of the code (except for this function) + should be able to cope with several readers. */ +static int +get_reader_slot (void) +{ + struct server_local_s *sl; + int slot= -1; + + for (sl=session_list; sl; sl = sl->next_session) + if (sl->ctrl_backlink + && (slot = sl->ctrl_backlink->reader_slot) != -1) + break; + + if (slot == -1) + slot = apdu_open_reader (opt.reader_port); + + return slot; +} + /* If the card has not yet been opened, do it. Note that this function returns an Assuan error, so don't map the error a second time */ @@ -154,10 +262,13 @@ open_card (ctrl_t ctrl, const char *apptype) if (ctrl->card_ctx) return 0; /* Already initialized using a card context. */ + if ( IS_LOCKED (ctrl) ) + return gpg_error (GPG_ERR_EBUSY); + if (ctrl->reader_slot != -1) slot = ctrl->reader_slot; else - slot = apdu_open_reader (opt.reader_port); + slot = get_reader_slot (); ctrl->reader_slot = slot; if (slot == -1) err = gpg_error (GPG_ERR_CARD); @@ -177,9 +288,7 @@ open_card (ctrl_t ctrl, const char *apptype) err = card_open (&ctrl->card_ctx); } - if (gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT) - ctrl->server_local->card_removed = 1; - + TEST_CARD_REMOVAL (ctrl, err); return map_to_assuan_status (err); } @@ -248,12 +357,12 @@ cmd_serialno (assuan_context_t ctx, char *line) time_t stamp; /* Clear the remove flag so that the open_card is able to reread it. */ - - /* FIXME: We can't do that if we are in a locked state. Retrun an - appropriate erro r in that case. IF the card has not been - removed we may very well continue. */ if (ctrl->server_local->card_removed) - do_reset (ctrl, 0); + { + if ( IS_LOCKED (ctrl) ) + return gpg_error (GPG_ERR_EBUSY); + do_reset (ctrl, 0); + } if ((rc = open_card (ctrl, *line? line:NULL))) return rc; @@ -342,7 +451,7 @@ cmd_serialno (assuan_context_t ctx, char *line) static int cmd_learn (assuan_context_t ctx, char *line) { - CTRL ctrl = assuan_get_pointer (ctx); + ctrl_t ctrl = assuan_get_pointer (ctx); int rc = 0; int idx; @@ -491,7 +600,7 @@ cmd_learn (assuan_context_t ctx, char *line) static int cmd_readcert (assuan_context_t ctx, char *line) { - CTRL ctrl = assuan_get_pointer (ctx); + ctrl_t ctrl = assuan_get_pointer (ctx); int rc; unsigned char *cert; size_t ncert; @@ -630,12 +739,13 @@ cmd_readkey (assuan_context_t ctx, char *line) static int cmd_setdata (assuan_context_t ctx, char *line) { - CTRL ctrl = assuan_get_pointer (ctx); + ctrl_t ctrl = assuan_get_pointer (ctx); int n; char *p; unsigned char *buf; - /* FIXME: If we are locked return an error. */ + if (locked_session && locked_session != ctrl->server_local) + return gpg_error (GPG_ERR_EBUSY); /* Parse the hexstring. */ for (p=line,n=0; hexdigitp (p); p++, n++) @@ -700,13 +810,14 @@ pin_cb (void *opaque, const char *info, char **retstr) static int cmd_pksign (assuan_context_t ctx, char *line) { - CTRL ctrl = assuan_get_pointer (ctx); + ctrl_t ctrl = assuan_get_pointer (ctx); int rc; unsigned char *outdata; size_t outdatalen; char *keyidstr; - /* FIXME: If we are locked return an error. */ + if ( IS_LOCKED (ctrl) ) + return gpg_error (GPG_ERR_EBUSY); if ((rc = open_card (ctrl, NULL))) return rc; @@ -753,13 +864,14 @@ cmd_pksign (assuan_context_t ctx, char *line) static int cmd_pkauth (assuan_context_t ctx, char *line) { - CTRL ctrl = assuan_get_pointer (ctx); + ctrl_t ctrl = assuan_get_pointer (ctx); int rc; unsigned char *outdata; size_t outdatalen; char *keyidstr; - /* FIXME: If we are locked return an error. */ + if ( IS_LOCKED (ctrl) ) + return gpg_error (GPG_ERR_EBUSY); if ((rc = open_card (ctrl, NULL))) return rc; @@ -802,13 +914,14 @@ cmd_pkauth (assuan_context_t ctx, char *line) static int cmd_pkdecrypt (assuan_context_t ctx, char *line) { - CTRL ctrl = assuan_get_pointer (ctx); + ctrl_t ctrl = assuan_get_pointer (ctx); int rc; unsigned char *outdata; size_t outdatalen; char *keyidstr; - /* FIXME: If we are locked return an error. */ + if ( IS_LOCKED (ctrl) ) + return gpg_error (GPG_ERR_EBUSY); if ((rc = open_card (ctrl, NULL))) return rc; @@ -861,7 +974,7 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line) static int cmd_getattr (assuan_context_t ctx, char *line) { - CTRL ctrl = assuan_get_pointer (ctx); + ctrl_t ctrl = assuan_get_pointer (ctx); int rc; char *keyword; @@ -900,14 +1013,15 @@ cmd_getattr (assuan_context_t ctx, char *line) static int cmd_setattr (assuan_context_t ctx, char *orig_line) { - CTRL ctrl = assuan_get_pointer (ctx); + ctrl_t ctrl = assuan_get_pointer (ctx); int rc; char *keyword; int keywordlen; size_t nbytes; char *line, *linebuf; - /* FIXME: If we are locked return an error. */ + if ( IS_LOCKED (ctrl) ) + return gpg_error (GPG_ERR_EBUSY); if ((rc = open_card (ctrl, NULL))) return rc; @@ -956,12 +1070,13 @@ cmd_setattr (assuan_context_t ctx, char *orig_line) static int cmd_genkey (assuan_context_t ctx, char *line) { - CTRL ctrl = assuan_get_pointer (ctx); + ctrl_t ctrl = assuan_get_pointer (ctx); int rc; char *keyno; int force = has_option (line, "--force"); - /* FIXME: If we are locked return an error. */ + if ( IS_LOCKED (ctrl) ) + return gpg_error (GPG_ERR_EBUSY); /* Skip over options. */ while ( *line == '-' && line[1] == '-' ) @@ -1004,7 +1119,7 @@ cmd_genkey (assuan_context_t ctx, char *line) static int cmd_random (assuan_context_t ctx, char *line) { - CTRL ctrl = assuan_get_pointer (ctx); + ctrl_t ctrl = assuan_get_pointer (ctx); int rc; size_t nbytes; unsigned char *buffer; @@ -1044,12 +1159,13 @@ cmd_random (assuan_context_t ctx, char *line) static int cmd_passwd (assuan_context_t ctx, char *line) { - CTRL ctrl = assuan_get_pointer (ctx); + ctrl_t ctrl = assuan_get_pointer (ctx); int rc; char *chvnostr; int reset_mode = has_option (line, "--reset"); - /* FIXME: If we are locked return an error. */ + if ( IS_LOCKED (ctrl) ) + return gpg_error (GPG_ERR_EBUSY); /* Skip over options. */ while (*line == '-' && line[1] == '-') @@ -1091,11 +1207,12 @@ cmd_passwd (assuan_context_t ctx, char *line) static int cmd_checkpin (assuan_context_t ctx, char *line) { - CTRL ctrl = assuan_get_pointer (ctx); + ctrl_t ctrl = assuan_get_pointer (ctx); int rc; char *keyidstr; - /* FIXME: If we are locked return an error. */ + if ( IS_LOCKED (ctrl) ) + return gpg_error (GPG_ERR_EBUSY); if ((rc = open_card (ctrl, NULL))) return rc; @@ -1122,15 +1239,83 @@ cmd_checkpin (assuan_context_t ctx, char *line) } +/* LOCK [--wait] + + Grant exclusive card access to this session. Note that there is + no lock counter used and a second lock from the same session will + get ignore. A single unlock (or RESET) unlocks the session. + Return GPG_ERR_EBUSY if another session has locked the reader. + + If the option --wait is given the command will wait until a + lock has been released. + */ +static int +cmd_lock (assuan_context_t ctx, char *line) +{ + ctrl_t ctrl = assuan_get_pointer (ctx); + int rc = 0; + + retry: + if (locked_session) + { + if (locked_session != ctrl->server_local) + rc = gpg_error (GPG_ERR_EBUSY); + } + else + locked_session = ctrl->server_local; + +#ifdef USE_GNU_PTH + if (rc && has_option (line, "--wait")) + { + pth_sleep (1); /* Better implement an event mechanism. However, + for card operations this should be + sufficient. */ + goto retry; + } +#endif /*USE_GNU_PTH*/ + + if (rc) + log_error ("cmd_lock failed: %s\n", gpg_strerror (rc)); + return map_to_assuan_status (rc); +} + + +/* UNLOCK + + Release exclusive card access. + */ +static int +cmd_unlock (assuan_context_t ctx, char *line) +{ + ctrl_t ctrl = assuan_get_pointer (ctx); + int rc = 0; + + if (locked_session) + { + if (locked_session != ctrl->server_local) + rc = gpg_error (GPG_ERR_EBUSY); + else + locked_session = NULL; + } + else + rc = gpg_error (GPG_ERR_NOT_LOCKED); + + if (rc) + log_error ("cmd_unlock failed: %s\n", gpg_strerror (rc)); + return map_to_assuan_status (rc); +} + + + /* Tell the assuan library about our commands */ static int -register_commands (ASSUAN_CONTEXT ctx) +register_commands (assuan_context_t ctx) { static struct { const char *name; - int (*handler)(ASSUAN_CONTEXT, char *line); + int (*handler)(assuan_context_t, char *line); } table[] = { { "SERIALNO", cmd_serialno }, { "LEARN", cmd_learn }, @@ -1148,6 +1333,8 @@ register_commands (ASSUAN_CONTEXT ctx) { "RANDOM", cmd_random }, { "PASSWD", cmd_passwd }, { "CHECKPIN", cmd_checkpin }, + { "LOCK", cmd_lock }, + { "UNLOCK", cmd_unlock }, { NULL } }; int i, rc; @@ -1172,7 +1359,7 @@ void scd_command_handler (int listen_fd) { int rc; - ASSUAN_CONTEXT ctx; + assuan_context_t ctx; struct server_control_s ctrl; memset (&ctrl, 0, sizeof ctrl); @@ -1204,20 +1391,24 @@ scd_command_handler (int listen_fd) scd_exit (2); } assuan_set_pointer (ctx, &ctrl); + + /* Allocate and initialize the server object. Put it into the list + of active sessions. */ ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local); + ctrl.server_local->next_session = session_list; + session_list = ctrl.server_local; + ctrl.server_local->ctrl_backlink = &ctrl; ctrl.server_local->assuan_ctx = ctx; if (DBG_ASSUAN) assuan_set_log_stream (ctx, log_get_stream ()); - /* Store the primary connection's assuan context. */ - if (!primary_connection) - primary_connection = &ctrl; - /* We open the reader right at startup so that the ticker is able to update the status file. */ if (ctrl.reader_slot == -1) - ctrl.reader_slot = apdu_open_reader (opt.reader_port); + { + ctrl.reader_slot = get_reader_slot (); + } /* Command processing loop. */ for (;;) @@ -1241,13 +1432,26 @@ scd_command_handler (int listen_fd) } } - /* The next client will be the primary conenction if this one - terminates. */ - if (primary_connection == &ctrl) - primary_connection = NULL; + /* Cleanup. */ + do_reset (&ctrl, 1); - do_reset (&ctrl, 1); /* Cleanup. */ + /* Release the server object. */ + if (session_list == ctrl.server_local) + session_list = ctrl.server_local->next_session; + else + { + struct server_local_s *sl; + + for (sl=session_list; sl->next_session; sl = sl->next_session) + if (sl->next_session == ctrl.server_local) + break; + if (!sl->next_session) + BUG (); + sl->next_session = ctrl.server_local->next_session; + } + xfree (ctrl.server_local); + /* Release the Assuan context. */ assuan_deinit_server (ctx); } @@ -1256,14 +1460,14 @@ scd_command_handler (int listen_fd) buffers. The variable elements are pairs of (char *, size_t), terminated with a (NULL, 0). */ void -send_status_info (CTRL ctrl, const char *keyword, ...) +send_status_info (ctrl_t ctrl, const char *keyword, ...) { va_list arg_ptr; const unsigned char *value; size_t valuelen; char buf[950], *p; size_t n; - ASSUAN_CONTEXT ctx = ctrl->server_local->assuan_ctx; + assuan_context_t ctx = ctrl->server_local->assuan_ctx; va_start (arg_ptr, keyword); @@ -1299,7 +1503,7 @@ send_status_info (CTRL ctrl, const char *keyword, ...) } -/* This fucntion is called by the ticker thread to check for changes +/* This function is called by the ticker thread to check for changes of the reader stati. It updates the reader status files and if requested by the caller also send a signal to the caller. */ void @@ -1328,6 +1532,7 @@ scd_update_reader_status_file (void) char *fname; char templ[50]; FILE *fp; + struct server_local_s *sl; log_info ("updating status of slot %d to 0x%04X\n", slot, status); @@ -1344,33 +1549,31 @@ scd_update_reader_status_file (void) } xfree (fname); - /* Set the card removed flag. We will set this on any - card change because a reset or SERIALNO request must be - done in any case. */ - if (primary_connection && primary_connection->server_local - && last[slot].any ) - primary_connection->server_local->card_removed = 1; + /* Set the card removed flag for all current sessions. We + will set this on any card change because a reset or + SERIALNO request must be done in any case. */ + if (last[slot].any) + update_card_removed (slot, 1); last[slot].any = 1; last[slot].status = status; last[slot].changed = changed; - /* Send a signal to the primary client, if any. */ - if (primary_connection && primary_connection->server_local - && primary_connection->server_local->assuan_ctx) - { - pid_t pid = assuan_get_pid (primary_connection - ->server_local->assuan_ctx); - int signo = primary_connection->server_local->event_signal; - - log_info ("client pid is %d, sending signal %d\n", pid, signo); + /* Send a signal to all clients who applied for it. */ + for (sl=session_list; sl; sl = sl->next_session) + if (sl->event_signal && sl->assuan_ctx) + { + pid_t pid = assuan_get_pid (sl->assuan_ctx); + int signo = sl->event_signal; + log_info ("client pid is %d, sending signal %d\n", + pid, signo); #ifndef HAVE_W32_SYSTEM - if (pid != (pid_t)(-1) && pid && signo > 0) - kill (pid, signo); + if (pid != (pid_t)(-1) && pid && signo > 0) + kill (pid, signo); #endif - } + } } } } -- cgit From eb3f014b5d57373b9eb7b3430c7afa115e2f871e Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 27 Apr 2005 19:47:53 +0000 Subject: * app-p15.c (micardo_mse): New. (do_sign): Call it. * iso7816.c (iso7816_manage_security_env): Allow passing DATA as NULL to indicate an empty Lc. * tlv.c (find_tlv): Check that a found object fits into the buffer. (find_tlv_unchecked): New as replacement for the old non-checking variant. * app.c (select_application): Keep on using the non-checking variant. * app-openpgp.c (get_one_do, dump_all_do): Ditto. --- scd/ChangeLog | 13 +++++ scd/app-openpgp.c | 6 +-- scd/app-p15.c | 142 ++++++++++++++++++++++++++++++++++++++++++++++++------ scd/app.c | 2 +- scd/iso7816.c | 7 +-- scd/tlv.c | 23 +++++++-- scd/tlv.h | 11 ++++- 7 files changed, 175 insertions(+), 29 deletions(-) (limited to 'scd/app-openpgp.c') diff --git a/scd/ChangeLog b/scd/ChangeLog index 4ce4c656d..d82e92904 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,5 +1,18 @@ 2005-04-27 Werner Koch + * app-p15.c (micardo_mse): New. + (do_sign): Call it. + * iso7816.c (iso7816_manage_security_env): Allow passing DATA as + NULL to indicate an empty Lc. + * tlv.c (find_tlv): Check that a found object fits into the + buffer. + (find_tlv_unchecked): New as replacement for the old non-checking + variant. + * app.c (select_application): Keep on using the non-checking + variant. + * app-openpgp.c (get_one_do, dump_all_do): Ditto. + + Removal of the old OpenSC based code. * app-p15.c: New. Basic support for pkcs15 cards without OpenSC. diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 0d80c41a7..ca0e2501b 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -357,7 +357,7 @@ get_one_do (app_t app, int tag, unsigned char **result, size_t *nbytes, { const unsigned char *s; - s = find_tlv (buffer, buflen, tag, &valuelen); + s = find_tlv_unchecked (buffer, buflen, tag, &valuelen); if (!s) value = NULL; /* not found */ else if (valuelen > buflen - (s - buffer)) @@ -433,8 +433,8 @@ dump_all_do (int slot) if (j==i || data_objects[i].tag != data_objects[j].get_from) continue; - value = find_tlv (buffer, buflen, - data_objects[j].tag, &valuelen); + value = find_tlv_unchecked (buffer, buflen, + data_objects[j].tag, &valuelen); if (!value) ; /* not found */ else if (valuelen > buflen - (value - buffer)) diff --git a/scd/app-p15.c b/scd/app-p15.c index 7a92da10b..d2ed15a59 100644 --- a/scd/app-p15.c +++ b/scd/app-p15.c @@ -59,11 +59,15 @@ static struct "\x90\x00\x66", CARD_TYPE_TCOS }, /* SLE66P */ { 27, "\x3B\xFF\x94\x00\xFF\x80\xB1\xFE\x45\x1F\x03\x00\x68\xD2\x76\x00" - "\x00\x28\xFF\x05\x1E\x31\x80\x00\x90\x00\x23", + "\x00\x28\xFF\x05\x1E\x31\x80\x00\x90\x00\x23", CARD_TYPE_MICARDO }, /* German BMI card */ + { 19, "\x3B\x6F\x00\xFF\x00\x68\xD2\x76\x00\x00\x28\xFF\x05\x1E\x31\x80" + "\x00\x90\x00", + CARD_TYPE_MICARDO }, /* German BMI card (ATR due to reader problem) */ { 26, "\x3B\xFE\x94\x00\xFF\x80\xB1\xFA\x45\x1F\x03\x45\x73\x74\x45\x49" "\x44\x20\x76\x65\x72\x20\x31\x2E\x30\x43", CARD_TYPE_MICARDO }, /* EstEID (Estonian Big Brother card) */ + { 0 } }; @@ -392,7 +396,7 @@ select_and_read_binary (int slot, unsigned short efid, const char *efid_desc, } -/* This function calls select file to read a file suing a complete +/* This function calls select file to read a file using a complete path which may or may not start at the master file (MF). */ static gpg_error_t select_ef_by_path (app_t app, const unsigned short *path, size_t pathlen) @@ -2525,6 +2529,99 @@ do_readcert (app_t app, const char *certid, } +/* Micardo cards require special treatment. This is a helper for the + crypto functions to manage the security environment. We expect that + the key file has already been selected. FID is the one of the + selected key. */ +static gpg_error_t +micardo_mse (app_t app, unsigned short fid) +{ + gpg_error_t err; + int recno; + unsigned short refdata = 0; + int se_num; + unsigned char msebuf[10]; + + /* Read the KeyD file containing extra information on keys. */ + err = iso7816_select_file (app->slot, 0x0013, 0, NULL, NULL); + if (err) + { + log_error ("error reading EF_keyD: %s\n", gpg_strerror (err)); + return err; + } + + for (recno = 1, se_num = -1; ; recno++) + { + unsigned char *buffer; + size_t buflen; + size_t n, nn; + const unsigned char *p, *pp; + + err = iso7816_read_record (app->slot, recno, 1, 0, &buffer, &buflen); + if (gpg_err_code (err) == GPG_ERR_NOT_FOUND) + break; /* ready */ + if (err) + { + log_error ("error reading EF_keyD record: %s\n", + gpg_strerror (err)); + return err; + } + log_printhex ("keyD record:", buffer, buflen); + p = find_tlv (buffer, buflen, 0x83, &n); + if (p && n == 4 && ((p[2]<<8)|p[3]) == fid) + { + refdata = ((p[0]<<8)|p[1]); + /* Locate the SE DO and the there included sec env number. */ + p = find_tlv (buffer, buflen, 0x7b, &n); + if (p && n) + { + pp = find_tlv (p, n, 0x80, &nn); + if (pp && nn == 1) + { + se_num = *pp; + xfree (buffer); + break; /* found. */ + } + } + } + xfree (buffer); + } + if (se_num == -1) + { + log_error ("CRT for keyfile %04hX not found\n", fid); + return gpg_error (GPG_ERR_NOT_FOUND); + } + + + /* Restore the security environment to SE_NUM if needed */ + if (se_num) + { + err = iso7816_manage_security_env (app->slot, 0xf3, se_num, NULL, 0); + if (err) + { + log_error ("restoring SE to %d failed: %s\n", + se_num, gpg_strerror (err)); + return err; + } + } + + /* Set the DST reference data. */ + msebuf[0] = 0x83; + msebuf[1] = 0x03; + msebuf[2] = 0x80; + msebuf[3] = (refdata >> 8); + msebuf[4] = refdata; + err = iso7816_manage_security_env (app->slot, 0x41, 0xb6, msebuf, 5); + if (err) + { + log_error ("setting SE to reference file %04hX failed: %s\n", + refdata, gpg_strerror (err)); + return err; + } + return 0; +} + + /* Handler for the PKSIGN command. @@ -2561,6 +2658,13 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, err = prkdf_object_from_keyidstr (app, keyidstr, &prkdf); if (err) return err; + if (!(prkdf->usageflags.sign || prkdf->usageflags.sign_recover + ||prkdf->usageflags.non_repudiation)) + { + log_error ("key %s may not be used for signing\n", keyidstr); + return gpg_error (GPG_ERR_WRONG_KEY_USAGE); + } + if (!prkdf->authid) { log_error ("no authentication object defined for %s\n", keyidstr); @@ -2597,6 +2701,16 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, return gpg_error (GPG_ERR_INV_CARD); } + /* Select the key file. Note that this may change the security + environment thus we do it before PIN verification. */ + err = select_ef_by_path (app, prkdf->path, prkdf->pathlen); + if (err) + { + log_error ("error selecting file for key %s: %s\n", + keyidstr, gpg_strerror (errno)); + return err; + } + /* Now that we have all the information available, prepare and run the PIN verification.*/ if (1) @@ -2742,7 +2856,6 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, memcpy (data+15, indata, indatalen); } - /* Manage security environment needs to be weaked for certain cards. */ if (app->app_local->card_type == CARD_TYPE_TCOS) { @@ -2751,10 +2864,10 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, } else if (app->app_local->card_type == CARD_TYPE_MICARDO) { - /* Micardo cards are very special in that they need to restore a - security environment using a infomration from a special - file. */ - log_error ("WARNING: support for MICARDO cards is not yet available\n"); + if (!prkdf->pathlen) + err = gpg_error (GPG_ERR_BUG); + else + err = micardo_mse (app, prkdf->path[prkdf->pathlen-1]); } else if (prkdf->key_reference_valid) { @@ -2767,11 +2880,11 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, err = iso7816_manage_security_env (app->slot, 0x41, 0xB6, mse, sizeof mse); - if (err) - { - log_error ("MSE failed: %s\n", gpg_strerror (err)); - return err; - } + } + if (err) + { + log_error ("MSE failed: %s\n", gpg_strerror (err)); + return err; } @@ -2782,9 +2895,6 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, - - - /* Select the PKCS#15 application on the card in SLOT. */ gpg_error_t app_select_p15 (app_t app) @@ -2846,7 +2956,7 @@ app_select_p15 (app_t app) the common APP structure. */ app->app_local->card_type = card_type; - /* Read basic information and check whether this is a real + /* Read basic information and thus check whether this is a real card. */ rc = read_p15_info (app); if (rc) diff --git a/scd/app.c b/scd/app.c index b6d46326b..8e95ef7ef 100644 --- a/scd/app.c +++ b/scd/app.c @@ -83,7 +83,7 @@ select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app) size_t n; const unsigned char *p; - p = find_tlv (result, resultlen, 0x5A, &n); + p = find_tlv_unchecked (result, resultlen, 0x5A, &n); if (p) resultlen -= (p-result); if (p && n > resultlen && n == 0x0d && resultlen+1 == n) diff --git a/scd/iso7816.c b/scd/iso7816.c index 9eff9d3f7..e9dc6541c 100644 --- a/scd/iso7816.c +++ b/scd/iso7816.c @@ -299,10 +299,11 @@ iso7816_manage_security_env (int slot, int p1, int p2, { int sw; - if (p1 < 0 || p1 > 255 || p2 < 0 || p2 > 255 || !data || !datalen) + if (p1 < 0 || p1 > 255 || p2 < 0 || p2 > 255 ) return gpg_error (GPG_ERR_INV_VALUE); - sw = apdu_send_simple (slot, 0x00, CMD_MSE, p1, p2, datalen, data); + sw = apdu_send_simple (slot, 0x00, CMD_MSE, p1, p2, + data? datalen : -1, data); return map_sw (sw); } @@ -605,7 +606,7 @@ iso7816_read_record (int slot, int recno, int reccount, int short_ef, buffer = NULL; bufferlen = 0; - /* Fixme: Either the ccid driver of the TCOS cards have problems + /* Fixme: Either the ccid driver or the TCOS cards have problems with an Le of 0. */ sw = apdu_send_le (slot, 0x00, CMD_READ_RECORD, recno, diff --git a/scd/tlv.c b/scd/tlv.c index 5b9d0d6b9..3a81ea6d9 100644 --- a/scd/tlv.c +++ b/scd/tlv.c @@ -1,5 +1,5 @@ /* tlv.c - Tag-Length-Value Utilities - * Copyright (C) 2003, 2004 Free Software Foundation, Inc. + * Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -113,17 +113,32 @@ do_find_tlv (const unsigned char *buffer, size_t length, /* Locate a TLV encoded data object in BUFFER of LENGTH and return a pointer to value as well as its length in NBYTES. Return - NULL if it was not found. Note, that the function does not check - whether the value fits into the provided buffer. */ + NULL if it was not found or if the object does not fit into the buffer. */ const unsigned char * find_tlv (const unsigned char *buffer, size_t length, int tag, size_t *nbytes) { - return do_find_tlv (buffer, length, tag, nbytes, 0); + const unsigned char *p; + + p = do_find_tlv (buffer, length, tag, nbytes, 0); + if (p && *nbytes > (length - (p-buffer))) + p = NULL; /* Object longer than buffer. */ + return p; } +/* Locate a TLV encoded data object in BUFFER of LENGTH and + return a pointer to value as well as its length in NBYTES. Return + NULL if it was not found. Note, that the function does not check + whether the value fits into the provided buffer. */ +const unsigned char * +find_tlv_unchecked (const unsigned char *buffer, size_t length, + int tag, size_t *nbytes) +{ + return do_find_tlv (buffer, length, tag, nbytes, 0); +} + /* ASN.1 BER parser: Parse BUFFER of length SIZE and return the tag and the length part from the TLV triplet. Update BUFFER and SIZE diff --git a/scd/tlv.h b/scd/tlv.h index 26a9905f7..628580431 100644 --- a/scd/tlv.h +++ b/scd/tlv.h @@ -62,13 +62,20 @@ enum tlv_tag_type { }; +/* Locate a TLV encoded data object in BUFFER of LENGTH and return a + pointer to value as well as its length in NBYTES. Return NULL if + it was not found or if the object does not fit into the buffer. */ +const unsigned char *find_tlv (const unsigned char *buffer, size_t length, + int tag, size_t *nbytes); + /* Locate a TLV encoded data object in BUFFER of LENGTH and return a pointer to value as well as its length in NBYTES. Return NULL if it was not found. Note, that the function does not check whether the value fits into the provided buffer.*/ -const unsigned char *find_tlv (const unsigned char *buffer, size_t length, - int tag, size_t *nbytes); +const unsigned char *find_tlv_unchecked (const unsigned char *buffer, + size_t length, + int tag, size_t *nbytes); /* ASN.1 BER parser: Parse BUFFER of length SIZE and return the tag -- cgit From 4237a9cc7fce3bad2a41b755fdf349a42ddd5ccf Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 18 May 2005 10:48:06 +0000 Subject: Changed the scdaemon to handle concurrent sessions. Adjusted gpg-agent accordingly. Code cleanups. --- ChangeLog | 5 + NEWS | 4 +- TODO | 14 +- agent/ChangeLog | 16 ++ agent/agent.h | 9 + agent/call-scd.c | 397 +++++++++++++++++++++++-------------- agent/command.c | 1 + agent/divert-scd.c | 7 - agent/gpg-agent.c | 96 ++------- configure.ac | 13 +- doc/ChangeLog | 4 + doc/gpg-agent.texi | 5 - doc/tools.texi | 10 + scd/ChangeLog | 36 ++++ scd/apdu.c | 4 + scd/app-common.h | 101 +++++----- scd/app-dinsig.c | 20 +- scd/app-nks.c | 24 +-- scd/app-openpgp.c | 58 +++--- scd/app-p15.c | 8 +- scd/app.c | 341 ++++++++++++++++++++++---------- scd/ccid-driver.c | 9 +- scd/command.c | 43 +++- scd/sc-copykeys.c | 2 +- scd/scdaemon.c | 491 ++++++++++++++++++++++++++++++---------------- scd/scdaemon.h | 3 +- tools/gpg-connect-agent.c | 20 +- 27 files changed, 1095 insertions(+), 646 deletions(-) (limited to 'scd/app-openpgp.c') diff --git a/ChangeLog b/ChangeLog index 4f58b9198..154ae07e9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2005-05-15 Werner Koch + + * configure.ac: Remove option --disable-threads; require the use + of GNU Pth. + 2005-04-27 Werner Koch * configure.ac: Removed OpenSC detection and options. diff --git a/NEWS b/NEWS index 2d43d70ff..c25bbe08e 100644 --- a/NEWS +++ b/NEWS @@ -1,8 +1,10 @@ Noteworthy changes in version 1.9.17 ------------------------------------------------- + * GNU Pth is now a hard requirement. + * [scdaemon] Support for OpenSC has been removed. Instead a new and - starightforward pkcs#15 modules has been written. As of now it + straightforward pkcs#15 modules has been written. As of now it does allows only signing using TCOS cards but we are going to enhance it to match all the old capabilities. diff --git a/TODO b/TODO index 6a0e9b18e..6e8951f03 100644 --- a/TODO +++ b/TODO @@ -35,6 +35,9 @@ might want to have an agent context for each service request to do that while changing gpgsm to allow concurrent operations. ** support the anyPolicy semantic ** Check that we are really following the verification procedures in rfc3280. +** Implement a --card-status command. + This is useful to check whether a card is supported at all. + * sm/keydb.c ** Check file permissions @@ -54,10 +57,6 @@ might want to have an agent context for each service request ** Don't use stdio to return results. ** Support DSA -* agent/divert-scd.c - Remove the agent_reset_scd kludge. We will do this after Scdaemon - has been changed to allow multiple sessions. Currently in progress. - * Move pkcs-1 encoding into libgcrypt. * Use a MAC to protect sensitive files. @@ -90,10 +89,3 @@ might want to have an agent context for each service request This means we can't reread a configuration ** No card status notifications. - -* scd/ -** Release the card after use so that gpg 1.4 is able to access it - This won't be a sufficient change. we need to change gpg 1.4 to make - use of the agent. Work is underway. - - diff --git a/agent/ChangeLog b/agent/ChangeLog index f5dbeb9e3..00f019ddc 100644 --- a/agent/ChangeLog +++ b/agent/ChangeLog @@ -1,3 +1,19 @@ +2005-05-18 Werner Koch + + * divert-scd.c (ask_for_card): Removed the card reset kludge. + +2005-05-17 Werner Koch + + * call-scd.c (unlock_scd): Add new arg CTRL. Changed all callers. + (start_scd): Reoworked to allow for additional connections. + * agent.h (ctrl_t): Add local data for the SCdaemon. + * command.c (start_command_handler): Release SERVER_LOCAL. + + * gpg-agent.c (create_server_socket): Use xmalloc. + (main): Removed option --disable-pth a dummy. Removed non-pth + code path. + (cleanup_sh): Removed. Not needed anymore. + 2005-05-05 Moritz Schulte * command-ssh.c (ssh_key_to_buffer): Rename to ... diff --git a/agent/agent.h b/agent/agent.h index 298b5b142..6ab65eeba 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -99,10 +99,19 @@ struct { #define DBG_ASSUAN (opt.debug & DBG_ASSUAN_VALUE) struct server_local_s; +struct scd_local_s; +/* Collection of data per session (aka connection). */ struct server_control_s { + + /* Private data of the server (command.c). */ struct server_local_s *server_local; + + /* Private data of the SCdaemon (call-scd.c). */ + struct scd_local_s *scd_local; + int connection_fd; /* -1 or an identifier for the current connection. */ + char *display; char *ttyname; char *ttytype; diff --git a/agent/call-scd.c b/agent/call-scd.c index 8373fd46d..58dd412f0 100644 --- a/agent/call-scd.c +++ b/agent/call-scd.c @@ -18,12 +18,6 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -/* Fixme: For now we have serialized all access to the scdaemon which - make sense becuase the scdaemon can't handle concurrent connections - right now. We should however keep a list of connections and lock - just that connection - it migth make sense to implemtn parts of - this in Assuan.*/ - #include #include #include @@ -37,9 +31,7 @@ #ifndef HAVE_W32_SYSTEM #include #endif -#ifdef USE_GNU_PTH -# include -#endif +#include #include "agent.h" #include @@ -50,24 +42,20 @@ #define MAX_OPEN_FDS 20 #endif -static ASSUAN_CONTEXT scd_ctx = NULL; -#ifdef USE_GNU_PTH -static pth_mutex_t scd_lock; -#endif -/* We need to keep track of the connection currently using the SCD. - For a pipe server this is all a NOP because the connection will - always have the connection indicator -1. agent_reset_scd releases - the active connection; i.e. sets it back to -1, so that a new - connection can start using the SCD. If we eventually allow - multiple SCD session we will either make scdaemon multi-threaded or - fork of a new scdaemon and let it see how it can get access to a - reader. -*/ -static int active_connection_fd = -1; -static int active_connection = 0; +/* Definition of module local data of the CTRL structure. */ +struct scd_local_s +{ + assuan_context_t ctx; /* NULL or session context for the SCdaemon + used with this connection. */ + int locked; /* This flag is used to assert proper use of + start_scd and unlock_scd. */ + +}; + /* Callback parameter for learn card */ -struct learn_parm_s { +struct learn_parm_s +{ void (*kpinfo_cb)(void*, const char *); void *kpinfo_cb_arg; void (*certinfo_cb)(void*, const char *); @@ -76,13 +64,39 @@ struct learn_parm_s { void *sinfo_cb_arg; }; -struct inq_needpin_s { - ASSUAN_CONTEXT ctx; +struct inq_needpin_s +{ + assuan_context_t ctx; int (*getpin_cb)(void *, const char *, char*, size_t); void *getpin_cb_arg; }; +/* A Mutex used inside the start_scd function. */ +static pth_mutex_t start_scd_lock; + +/* A malloced string with the name of the socket to be used for + additional connections. May be NULL if not provided by + SCdaemon. */ +static char *socket_name; + +/* The context of the primary connection. This is also used as a flag + to indicate whether the scdaemon has been started. */ +static assuan_context_t primary_scd_ctx; + +/* To allow reuse of the primary connection, the following flag is set + to true if the primary context has been reset and is not in use by + any connection. */ +static int primary_scd_ctx_reusable; + + + +/* Local prototypes. */ +static assuan_error_t membuf_data_cb (void *opaque, + const void *buffer, size_t length); + + + /* This function must be called once to initialize this module. This has to be done before a second thread is spawned. We can't do the @@ -91,27 +105,35 @@ struct inq_needpin_s { void initialize_module_call_scd (void) { -#ifdef USE_GNU_PTH static int initialized; if (!initialized) - if (pth_mutex_init (&scd_lock)) + { + if (!pth_mutex_init (&start_scd_lock)) + log_fatal ("error initializing mutex: %s\n", strerror (errno)); initialized = 1; -#endif /*USE_GNU_PTH*/ + } } +/* The unlock_scd function shall be called after having accessed the + SCD. It is currently not very useful but gives an opportunity to + keep track of connections currently calling SCD. Note that the + "lock" operation is done by the start_scd() function which must be + called and error checked before any SCD operation. CTRL is the + usual connection context and RC the error code to be passed trhough + the function. */ static int -unlock_scd (int rc) +unlock_scd (ctrl_t ctrl, int rc) { -#ifdef USE_GNU_PTH - if (!pth_mutex_release (&scd_lock)) + if (ctrl->scd_local->locked != 1) { - log_error ("failed to release the SCD lock\n"); + log_error ("unlock_scd: invalid lock count (%d)\n", + ctrl->scd_local->locked); if (!rc) rc = gpg_error (GPG_ERR_INTERNAL); } -#endif /*USE_GNU_PTH*/ + ctrl->scd_local->locked = 0; return rc; } @@ -125,68 +147,115 @@ atfork_cb (void *opaque, int where) } -/* Fork off the SCdaemon if this has not already been done. Note that - this fucntion alos locks the daemon. */ +/* Fork off the SCdaemon if this has not already been done. Lock the + daemon and make sure that a proper context has been setup in CTRL. + Thsi fucntion might also lock the daemon, which means that the + caller must call unlock_scd after this fucntion has returned + success and the actual Assuan transaction been done. */ static int start_scd (ctrl_t ctrl) { - int rc; + gpg_error_t err = 0; const char *pgmname; - ASSUAN_CONTEXT ctx; - const char *argv[3]; + assuan_context_t ctx; + const char *argv[4]; int no_close_list[3]; int i; + int rc; if (opt.disable_scdaemon) return gpg_error (GPG_ERR_NOT_SUPPORTED); -#ifdef USE_GNU_PTH - if (!pth_mutex_acquire (&scd_lock, 0, NULL)) + /* If this is the first call for this session, setup the local data + structure. */ + if (!ctrl->scd_local) + { + ctrl->scd_local = xtrycalloc (1, sizeof *ctrl->scd_local); + if (!ctrl->scd_local) + return gpg_error_from_errno (errno); + } + + + /* Assert that the lock count is as expected. */ + if (ctrl->scd_local->locked) { - log_error ("failed to acquire the SCD lock\n"); + log_error ("start_scd: invalid lock count (%d)\n", + ctrl->scd_local->locked); return gpg_error (GPG_ERR_INTERNAL); } -#endif + ctrl->scd_local->locked++; - if (scd_ctx) + /* If we already have a context, we better do a sanity check now to + see whether it has accidently died. This avoids annoying + timeouts and hung connections. */ + if (ctrl->scd_local->ctx) { pid_t pid; - - /* If we are not the connection currently using the SCD, return - an error. */ - if (!active_connection) - { - active_connection_fd = ctrl->connection_fd; - active_connection = 1; - } - else if (ctrl->connection_fd != active_connection_fd) - return unlock_scd (gpg_error (GPG_ERR_CONFLICT)); - - /* Okay, we already started the scdaemon and it is used by us.*/ - - /* We better do a sanity check now to see whether it has - accidently died. */ #ifndef HAVE_W32_SYSTEM - pid = assuan_get_pid (scd_ctx); + pid = assuan_get_pid (ctrl->scd_local->ctx); if (pid != (pid_t)(-1) && pid && ((rc=waitpid (pid, NULL, WNOHANG))==-1 || (rc == pid)) ) { - assuan_disconnect (scd_ctx); - scd_ctx = NULL; + assuan_disconnect (ctrl->scd_local->ctx); + ctrl->scd_local->ctx = NULL; } else #endif - return 0; + return 0; /* Okay, the context is fine. */ + } + + /* We need to protect the lowwing code. */ + if (!pth_mutex_acquire (&start_scd_lock, 0, NULL)) + { + log_error ("failed to acquire the start_scd lock: %s\n", + strerror (errno)); + return gpg_error (GPG_ERR_INTERNAL); + } + + /* Check whether the pipe server has already been started and in + this case either reuse a lingering pipe connection or establish a + new socket based one. */ + if (primary_scd_ctx && primary_scd_ctx_reusable) + { + ctx = primary_scd_ctx; + primary_scd_ctx_reusable = 0; + if (opt.verbose) + log_info ("new connection to SCdaemon established (reusing)\n"); + goto leave; } + if (socket_name) + { + rc = assuan_socket_connect (&ctx, socket_name, 0); + if (rc) + { + log_error ("can't connect to socket `%s': %s\n", + socket_name, assuan_strerror (rc)); + err = gpg_error (GPG_ERR_NO_SCDAEMON); + goto leave; + } + + if (opt.verbose) + log_info ("new connection to SCdaemon established\n"); + goto leave; + } + + if (primary_scd_ctx) + { + log_info ("SCdaemon is running but won't accept further connections\n"); + err = gpg_error (GPG_ERR_NO_SCDAEMON); + goto leave; + } + + /* Nope, it has not been started. Fire it up now. */ if (opt.verbose) log_info ("no running SCdaemon - starting it\n"); if (fflush (NULL)) { - gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno)); + err = gpg_error (gpg_err_code_from_errno (errno)); log_error ("error flushing pending output: %s\n", strerror (errno)); - return unlock_scd (tmperr); + goto leave; } if (!opt.scdaemon_program || !*opt.scdaemon_program) @@ -198,7 +267,8 @@ start_scd (ctrl_t ctrl) argv[0] = pgmname; argv[1] = "--server"; - argv[2] = NULL; + argv[2] = "--multi-server"; + argv[3] = NULL; i=0; if (!opt.running_detached) @@ -216,30 +286,68 @@ start_scd (ctrl_t ctrl) { log_error ("can't connect to the SCdaemon: %s\n", assuan_strerror (rc)); - return unlock_scd (gpg_error (GPG_ERR_NO_SCDAEMON)); + err = gpg_error (GPG_ERR_NO_SCDAEMON); + goto leave; } - scd_ctx = ctx; - active_connection_fd = ctrl->connection_fd; - active_connection = 1; - - if (DBG_ASSUAN) - log_debug ("connection to SCdaemon established\n"); - - /* Tell the scdaemon that we want him to send us an event signal. - But only do this if we are running as a regular sever and not - simply as a pipe server. */ - /* Fixme: gpg-agent does not use this signal yet. */ -/* if (ctrl->connection_fd != -1) */ -/* { */ -/* #ifndef HAVE_W32_SYSTEM */ -/* char buf[100]; */ - -/* sprintf (buf, "OPTION event-signal=%d", SIGUSR2); */ -/* assuan_transact (scd_ctx, buf, NULL, NULL, NULL, NULL, NULL, NULL); */ -/* #endif */ -/* } */ - return 0; + if (opt.verbose) + log_debug ("first connection to SCdaemon established\n"); + + /* Get the name of the additional socket opened by scdaemon. */ + { + membuf_t data; + unsigned char *databuf; + size_t datalen; + + xfree (socket_name); + socket_name = NULL; + init_membuf (&data, 256); + assuan_transact (ctx, "GETINFO socket_name", + membuf_data_cb, &data, NULL, NULL, NULL, NULL); + + databuf = get_membuf (&data, &datalen); + if (databuf && datalen) + { + socket_name = xtrymalloc (datalen + 1); + if (!socket_name) + log_error ("warning: can't store socket name: %s\n", + strerror (errno)); + else + { + memcpy (socket_name, databuf, datalen); + socket_name[datalen] = 0; + if (DBG_ASSUAN) + log_debug ("additional connections at `%s'\n", socket_name); + } + } + xfree (databuf); + } + + /* Tell the scdaemon we want him to send us an event signal. */ +#ifndef HAVE_W32_SYSTEM + { + char buf[100]; + + sprintf (buf, "OPTION event-signal=%d", SIGUSR2); + assuan_transact (ctx, buf, NULL, NULL, NULL, NULL, NULL, NULL); + } +#endif + + primary_scd_ctx = ctx; + primary_scd_ctx_reusable = 0; + + leave: + if (err) + { + unlock_scd (ctrl, err); + } + else + { + ctrl->scd_local->ctx = ctx; + } + if (!pth_mutex_release (&start_scd_lock)) + log_error ("failed to release the start_scd lock: %s\n", strerror (errno)); + return err; } @@ -248,25 +356,28 @@ start_scd (ctrl_t ctrl) int agent_reset_scd (ctrl_t ctrl) { - int rc = 0; - -#ifdef USE_GNU_PTH - if (!pth_mutex_acquire (&scd_lock, 0, NULL)) - { - log_error ("failed to acquire the SCD lock for reset\n"); - return gpg_error (GPG_ERR_INTERNAL); - } -#endif - if (active_connection && active_connection_fd == ctrl->connection_fd) + if (ctrl->scd_local) { - if (scd_ctx) - rc = assuan_transact (scd_ctx, "RESET", NULL, NULL, - NULL, NULL, NULL, NULL); - active_connection_fd = -1; - active_connection = 0; + if (ctrl->scd_local->ctx) + { + /* We can't disconnect the primary context becuase libassuan + does a waitpid on it and thus the system would hang. + Instead we send a reset and keep that connection for + reuse. */ + if (ctrl->scd_local->ctx == primary_scd_ctx) + { + if (!assuan_transact (primary_scd_ctx, "RESET", + NULL, NULL, NULL, NULL, NULL, NULL)) + primary_scd_ctx_reusable = 1; + } + else + assuan_disconnect (ctrl->scd_local->ctx); + } + xfree (ctrl->scd_local); + ctrl->scd_local = NULL; } - return unlock_scd (map_assuan_err (rc)); + return 0; } @@ -360,13 +471,13 @@ agent_card_learn (ctrl_t ctrl, parm.certinfo_cb_arg = certinfo_cb_arg; parm.sinfo_cb = sinfo_cb; parm.sinfo_cb_arg = sinfo_cb_arg; - rc = assuan_transact (scd_ctx, "LEARN --force", + rc = assuan_transact (ctrl->scd_local->ctx, "LEARN --force", NULL, NULL, NULL, NULL, learn_status_cb, &parm); if (rc) - return unlock_scd (map_assuan_err (rc)); + return unlock_scd (ctrl, map_assuan_err (rc)); - return unlock_scd (0); + return unlock_scd (ctrl, 0); } @@ -414,16 +525,16 @@ agent_card_serialno (ctrl_t ctrl, char **r_serialno) if (rc) return rc; - rc = assuan_transact (scd_ctx, "SERIALNO", + rc = assuan_transact (ctrl->scd_local->ctx, "SERIALNO", NULL, NULL, NULL, NULL, get_serialno_cb, &serialno); if (rc) { xfree (serialno); - return unlock_scd (map_assuan_err (rc)); + return unlock_scd (ctrl, map_assuan_err (rc)); } *r_serialno = serialno; - return unlock_scd (0); + return unlock_scd (ctrl, 0); } @@ -495,31 +606,32 @@ agent_card_pksign (ctrl_t ctrl, return rc; if (indatalen*2 + 50 > DIM(line)) - return unlock_scd (gpg_error (GPG_ERR_GENERAL)); + return unlock_scd (ctrl, gpg_error (GPG_ERR_GENERAL)); sprintf (line, "SETDATA "); p = line + strlen (line); for (i=0; i < indatalen ; i++, p += 2 ) sprintf (p, "%02X", indata[i]); - rc = assuan_transact (scd_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); + rc = assuan_transact (ctrl->scd_local->ctx, line, + NULL, NULL, NULL, NULL, NULL, NULL); if (rc) - return unlock_scd (map_assuan_err (rc)); + return unlock_scd (ctrl, map_assuan_err (rc)); init_membuf (&data, 1024); - inqparm.ctx = scd_ctx; + inqparm.ctx = ctrl->scd_local->ctx; inqparm.getpin_cb = getpin_cb; inqparm.getpin_cb_arg = getpin_cb_arg; snprintf (line, DIM(line)-1, ctrl->use_auth_call? "PKAUTH %s":"PKSIGN %s", keyid); line[DIM(line)-1] = 0; - rc = assuan_transact (scd_ctx, line, + rc = assuan_transact (ctrl->scd_local->ctx, line, membuf_data_cb, &data, inq_needpin, &inqparm, NULL, NULL); if (rc) { xfree (get_membuf (&data, &len)); - return unlock_scd (map_assuan_err (rc)); + return unlock_scd (ctrl, map_assuan_err (rc)); } sigbuf = get_membuf (&data, &sigbuflen); @@ -531,7 +643,7 @@ agent_card_pksign (ctrl_t ctrl, { gpg_error_t tmperr = out_of_core (); xfree (*r_buf); - return unlock_scd (tmperr); + return unlock_scd (ctrl, tmperr); } p = stpcpy (*r_buf, "(7:sig-val(3:rsa(1:s" ); sprintf (p, "%u:", (unsigned int)sigbuflen); @@ -542,7 +654,7 @@ agent_card_pksign (ctrl_t ctrl, xfree (sigbuf); assert (gcry_sexp_canon_len (*r_buf, *r_buflen, NULL, NULL)); - return unlock_scd (0); + return unlock_scd (ctrl, 0); } /* Decipher INDATA using the current card. Note that the returned value is */ @@ -567,36 +679,37 @@ agent_card_pkdecrypt (ctrl_t ctrl, /* FIXME: use secure memory where appropriate */ if (indatalen*2 + 50 > DIM(line)) - return unlock_scd (gpg_error (GPG_ERR_GENERAL)); + return unlock_scd (ctrl, gpg_error (GPG_ERR_GENERAL)); sprintf (line, "SETDATA "); p = line + strlen (line); for (i=0; i < indatalen ; i++, p += 2 ) sprintf (p, "%02X", indata[i]); - rc = assuan_transact (scd_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); + rc = assuan_transact (ctrl->scd_local->ctx, line, + NULL, NULL, NULL, NULL, NULL, NULL); if (rc) - return unlock_scd (map_assuan_err (rc)); + return unlock_scd (ctrl, map_assuan_err (rc)); init_membuf (&data, 1024); - inqparm.ctx = scd_ctx; + inqparm.ctx = ctrl->scd_local->ctx; inqparm.getpin_cb = getpin_cb; inqparm.getpin_cb_arg = getpin_cb_arg; snprintf (line, DIM(line)-1, "PKDECRYPT %s", keyid); line[DIM(line)-1] = 0; - rc = assuan_transact (scd_ctx, line, + rc = assuan_transact (ctrl->scd_local->ctx, line, membuf_data_cb, &data, inq_needpin, &inqparm, NULL, NULL); if (rc) { xfree (get_membuf (&data, &len)); - return unlock_scd (map_assuan_err (rc)); + return unlock_scd (ctrl, map_assuan_err (rc)); } *r_buf = get_membuf (&data, r_buflen); if (!*r_buf) - return unlock_scd (gpg_error (GPG_ERR_ENOMEM)); + return unlock_scd (ctrl, gpg_error (GPG_ERR_ENOMEM)); - return unlock_scd (0); + return unlock_scd (ctrl, 0); } @@ -619,20 +732,20 @@ agent_card_readcert (ctrl_t ctrl, init_membuf (&data, 1024); snprintf (line, DIM(line)-1, "READCERT %s", id); line[DIM(line)-1] = 0; - rc = assuan_transact (scd_ctx, line, + rc = assuan_transact (ctrl->scd_local->ctx, line, membuf_data_cb, &data, NULL, NULL, NULL, NULL); if (rc) { xfree (get_membuf (&data, &len)); - return unlock_scd (map_assuan_err (rc)); + return unlock_scd (ctrl, map_assuan_err (rc)); } *r_buf = get_membuf (&data, r_buflen); if (!*r_buf) - return unlock_scd (gpg_error (GPG_ERR_ENOMEM)); + return unlock_scd (ctrl, gpg_error (GPG_ERR_ENOMEM)); - return unlock_scd (0); + return unlock_scd (ctrl, 0); } @@ -655,26 +768,26 @@ agent_card_readkey (ctrl_t ctrl, const char *id, unsigned char **r_buf) init_membuf (&data, 1024); snprintf (line, DIM(line)-1, "READKEY %s", id); line[DIM(line)-1] = 0; - rc = assuan_transact (scd_ctx, line, + rc = assuan_transact (ctrl->scd_local->ctx, line, membuf_data_cb, &data, NULL, NULL, NULL, NULL); if (rc) { xfree (get_membuf (&data, &len)); - return unlock_scd (map_assuan_err (rc)); + return unlock_scd (ctrl, map_assuan_err (rc)); } *r_buf = get_membuf (&data, &buflen); if (!*r_buf) - return unlock_scd (gpg_error (GPG_ERR_ENOMEM)); + return unlock_scd (ctrl, gpg_error (GPG_ERR_ENOMEM)); if (!gcry_sexp_canon_len (*r_buf, buflen, NULL, NULL)) { xfree (*r_buf); *r_buf = NULL; - return unlock_scd (gpg_error (GPG_ERR_INV_VALUE)); + return unlock_scd (ctrl, gpg_error (GPG_ERR_INV_VALUE)); } - return unlock_scd (0); + return unlock_scd (ctrl, 0); } @@ -744,7 +857,7 @@ agent_card_getattr (ctrl_t ctrl, const char *name, char **result) if (err) return err; - err = map_assuan_err (assuan_transact (scd_ctx, line, + err = map_assuan_err (assuan_transact (ctrl->scd_local->ctx, line, NULL, NULL, NULL, NULL, card_getattr_cb, &parm)); if (!err && parm.error) @@ -758,7 +871,7 @@ agent_card_getattr (ctrl_t ctrl, const char *name, char **result) else xfree (parm.data); - return unlock_scd (err); + return unlock_scd (ctrl, err); } @@ -810,19 +923,19 @@ agent_card_scd (ctrl_t ctrl, const char *cmdline, if (rc) return rc; - inqparm.ctx = scd_ctx; + inqparm.ctx = ctrl->scd_local->ctx; inqparm.getpin_cb = getpin_cb; inqparm.getpin_cb_arg = getpin_cb_arg; - rc = assuan_transact (scd_ctx, cmdline, + rc = assuan_transact (ctrl->scd_local->ctx, cmdline, pass_data_thru, assuan_context, inq_needpin, &inqparm, pass_status_thru, assuan_context); if (rc) { - return unlock_scd (map_assuan_err (rc)); + return unlock_scd (ctrl, map_assuan_err (rc)); } - return unlock_scd (0); + return unlock_scd (ctrl, 0); } diff --git a/agent/command.c b/agent/command.c index 997140207..8af159f6d 100644 --- a/agent/command.c +++ b/agent/command.c @@ -1061,5 +1061,6 @@ start_command_handler (int listen_fd, int fd) free (ctrl.lc_ctype); if (ctrl.lc_messages) free (ctrl.lc_messages); + xfree (ctrl.server_local); } diff --git a/agent/divert-scd.c b/agent/divert-scd.c index f2ec2f051..f460ffe0c 100644 --- a/agent/divert-scd.c +++ b/agent/divert-scd.c @@ -108,13 +108,6 @@ ask_for_card (CTRL ctrl, const unsigned char *shadow_info, char **r_kid) if (!rc) { - /* We better reset the SCD now. This is kludge required - because the scdaemon is currently not always able to - detect the presence of a card. With a fully working - scdaemon this would not be required; i.e. the pkcs#15 - support does not require it because OpenSC correclty - detects a present card. */ - agent_reset_scd (ctrl); if (asprintf (&desc, "%s:%%0A%%0A" " \"%.*s\"", diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c index 7c682ada7..4ac995c26 100644 --- a/agent/gpg-agent.c +++ b/agent/gpg-agent.c @@ -37,9 +37,7 @@ #endif /*HAVE_W32_SYSTEM*/ #include #include -#ifdef USE_GNU_PTH -# include -#endif +#include #define JNLIB_NEED_LOG_LOGV #include "agent.h" @@ -83,7 +81,6 @@ enum cmd_and_opt_values oLCctype, oLCmessages, oScdaemonProgram, - oDisablePth, oDefCacheTTL, oMaxCacheTTL, oUseStandardSocket, @@ -120,7 +117,6 @@ static ARGPARSE_OPTS opts[] = { { oNoDetach, "no-detach" ,0, N_("do not detach from the console")}, { oNoGrab, "no-grab" ,0, N_("do not grab keyboard and mouse")}, { oLogFile, "log-file" ,2, N_("use a log file for the server")}, - { oDisablePth, "disable-pth", 0, N_("do not allow multiple connections")}, { oUseStandardSocket, "use-standard-socket", 0, N_("use a standard location for the socket")}, { oNoUseStandardSocket, "no-use-standard-socket", 0, "@"}, @@ -157,7 +153,6 @@ static ARGPARSE_OPTS opts[] = { #define DEFAULT_CACHE_TTL (10*60) /* 10 minutes */ #define MAX_CACHE_TTL (120*60) /* 2 hours */ -static volatile int caught_fatal_sig = 0; /* flag to indicate that a shutdown was requested */ static int shutdown_pending; @@ -190,10 +185,11 @@ static const char *debug_level; static char *current_logfile; /* The handle_tick() function may test whether a parent is still - runing. We record the PID of the parent here or -1 if it should be + running. We record the PID of the parent here or -1 if it should be watched. */ static pid_t parent_pid = (pid_t)(-1); + /* Local prototypes. */ @@ -203,17 +199,15 @@ static char *create_socket_name (int use_standard_socket, static int create_server_socket (int is_standard_name, const char *name); static void create_directories (void); -#ifdef USE_GNU_PTH static void handle_connections (int listen_fd, int listen_fd_ssh); -/* Pth wrapper function definitions. */ -GCRY_THREAD_OPTION_PTH_IMPL; -#endif /*USE_GNU_PTH*/ - static int check_for_running_agent (int); +/* Pth wrapper function definitions. */ +GCRY_THREAD_OPTION_PTH_IMPL; + /* Functions. */ @@ -351,28 +345,6 @@ cleanup (void) } -static RETSIGTYPE -cleanup_sh (int sig) -{ - if (caught_fatal_sig) - raise (sig); - caught_fatal_sig = 1; - - /* gcry_control( GCRYCTL_TERM_SECMEM );*/ - cleanup (); - -#ifndef HAVE_DOSISH_SYSTEM - { /* reset action to default action and raise signal again */ - struct sigaction nact; - nact.sa_handler = SIG_DFL; - sigemptyset( &nact.sa_mask ); - nact.sa_flags = 0; - sigaction( sig, &nact, NULL); - } -#endif - raise( sig ); -} - /* Handle options which are allowed to be reset after program start. Return true when the current option in PARGS could be handled and @@ -462,7 +434,6 @@ main (int argc, char **argv ) int csh_style = 0; char *logfile = NULL; int debug_wait = 0; - int disable_pth = 0; int gpgconf_list = 0; int standard_socket = 0; gpg_error_t err; @@ -481,14 +452,12 @@ main (int argc, char **argv ) /* Libgcrypt requires us to register the threading model first. Note that this will also do the pth_init. */ -#ifdef USE_GNU_PTH err = gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pth); if (err) { log_fatal ("can't register GNU Pth with Libgcrypt: %s\n", gpg_strerror (err)); } -#endif /*USE_GNU_PTH*/ /* Check that the libraries are suitable. Do it here because @@ -634,7 +603,6 @@ main (int argc, char **argv ) case oSh: csh_style = 0; break; case oServer: pipe_server = 1; break; case oDaemon: is_daemon = 1; break; - case oDisablePth: disable_pth = 1; break; case oDisplay: default_display = xstrdup (pargs.r.ret_str); break; case oTTYname: default_ttyname = xstrdup (pargs.r.ret_str); break; @@ -983,45 +951,17 @@ main (int argc, char **argv ) exit (1); } + { + struct sigaction sa; + + sa.sa_handler = SIG_IGN; + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + sigaction (SIGPIPE, &sa, NULL); + } #endif /*!HAVE_W32_SYSTEM*/ - -#ifdef USE_GNU_PTH - if (!disable_pth) - { -#ifndef HAVE_W32_SYSTEM /* FIXME */ - struct sigaction sa; - - sa.sa_handler = SIG_IGN; - sigemptyset (&sa.sa_mask); - sa.sa_flags = 0; - sigaction (SIGPIPE, &sa, NULL); -#endif - handle_connections (fd, opt.ssh_support ? fd_ssh : -1); - } - else -#endif /*!USE_GNU_PTH*/ - /* setup signals */ - { -#ifndef HAVE_W32_SYSTEM /* FIXME */ - struct sigaction oact, nact; - - nact.sa_handler = cleanup_sh; - sigemptyset (&nact.sa_mask); - nact.sa_flags = 0; - - sigaction (SIGHUP, NULL, &oact); - if (oact.sa_handler != SIG_IGN) - sigaction (SIGHUP, &nact, NULL); - sigaction( SIGTERM, NULL, &oact ); - if (oact.sa_handler != SIG_IGN) - sigaction (SIGTERM, &nact, NULL); - nact.sa_handler = SIG_IGN; - sigaction (SIGPIPE, &nact, NULL); - sigaction (SIGINT, &nact, NULL); -#endif - start_command_handler (fd, -1); - } + handle_connections (fd, opt.ssh_support ? fd_ssh : -1); close (fd); } @@ -1127,7 +1067,7 @@ reread_configuration (void) /* Create a name for the socket. With USE_STANDARD_SOCKET given as - true ising STANDARD_NAME in the home directory or if given has + true using STANDARD_NAME in the home directory or if given has false from the mkdir type name TEMPLATE. In the latter case a unique name in a unique new directory will be created. In both cases check for valid characters as well as against a maximum @@ -1195,7 +1135,7 @@ create_server_socket (int is_standard_name, const char *name) agent_exit (2); } - serv_addr = malloc (sizeof (*serv_addr)); /* FIXME. */ + serv_addr = xmalloc (sizeof (*serv_addr)); memset (serv_addr, 0, sizeof *serv_addr); serv_addr->sun_family = AF_UNIX; assert (strlen (name) + 1 < sizeof (serv_addr->sun_path)); @@ -1325,7 +1265,6 @@ create_directories (void) -#ifdef USE_GNU_PTH /* This is the worker for the ticker. It is called every few seconds and may only do fast operations. */ static void @@ -1581,7 +1520,6 @@ handle_connections (int listen_fd, int listen_fd_ssh) cleanup (); log_info (_("%s %s stopped\n"), strusage(11), strusage(13)); } -#endif /*USE_GNU_PTH*/ /* Figure out whether an agent is available and running. Prints an diff --git a/configure.ac b/configure.ac index dee0a9f09..369762b02 100644 --- a/configure.ac +++ b/configure.ac @@ -541,10 +541,6 @@ fi AC_SUBST(PTH_CFLAGS) AC_SUBST(PTH_LIBS) -AC_ARG_ENABLE(threads, - AC_HELP_STRING([--disable-threads],[allow building without Pth support]) - ) - dnl Must check for network library requirements before doing link tests dnl for ldap, for example. If ldap libs are static (or dynamic and without @@ -1106,17 +1102,14 @@ fi if test "$missing_pth" = "yes"; then AC_MSG_NOTICE([[ *** -*** It is strongly suggested to build with support for the +*** It is now required to build with support for the *** GNU Portable Threads Library (Pth). Please install this -*** library first or use --disable-threads to allow building -*** anyway. The library is for example available at +*** library first. The library is for example available at *** ftp://ftp.gnu.org/gnu/pth/ *** On a Debian GNU/Linux system you can install it using *** apt-get install libpth-dev ***]]) - if test "$enable_threads" != "no"; then - die=yes - fi + die=yes fi if test "$die" = "yes"; then diff --git a/doc/ChangeLog b/doc/ChangeLog index b1f5e8037..25840a5b1 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,7 @@ +2005-05-17 Werner Koch + + * gpg-agent.texi (Agent Options): Removed --disable-pth. + 2005-04-27 Werner Koch * tools.texi (symcryptrun): Added. diff --git a/doc/gpg-agent.texi b/doc/gpg-agent.texi index 33c8c148c..fa005c3b7 100644 --- a/doc/gpg-agent.texi +++ b/doc/gpg-agent.texi @@ -253,11 +253,6 @@ should in general not be used to avaoid X-sniffing attacks. Append all logging output to @var{file}. This is very helpful in seeing what the agent actually does. -@item --disable-pth -@opindex disable-pth -Don't allow multiple connections. This option is in general not very -useful. - @anchor{option --allow-mark-trusted} @item --allow-mark-trusted @opindex allow-mark-trusted diff --git a/doc/tools.texi b/doc/tools.texi index 805a17e6c..b2463c351 100644 --- a/doc/tools.texi +++ b/doc/tools.texi @@ -722,6 +722,16 @@ directory stated through the environment variable @env{GNUPGHOME} or (on W32 systems) by means on the Registry entry @var{HKCU\Software\GNU\GnuPG:HomeDir}. + +@item -S +@itemx --raw-socket @var{name} +@opindex S +@opindex raw-socket +Connect to socket @var{name} assuming this is an Assuan style server. +Do not run any special initializations or environment checks. This may +be used to directly connect to any Assuan style socket server. + + @end table @c diff --git a/scd/ChangeLog b/scd/ChangeLog index d82e92904..19bba2bf4 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,39 @@ +2005-05-17 Werner Koch + + * scdaemon.c: Removed non-pth code paths. + (create_socket_name, create_server_socket): New. Taken from + ../agent/gpg-agent. + (cleanup): Changed to adjust for SOCKET_NAME now being malloced. + (ticker_thread): Always use pth_event_occurred; it is again + defined for all decent PTH versions. + (handle_connections): New. Based on the gpg-agent code. + (start_connection_thread): Ditto. + (ticker_thread): Removed. + (cleanup_sh): Removed. + (main): Run the handler for the pipe server in a separate + thread. This replaces the old ticker thread. + (scd_get_socket_name): New. + * command.c (cmd_getinfo): New command GETINFO. + (scd_command_handler): Renamed argument and changed code to use an + already connected FD. + +2005-05-15 Werner Koch + + * app.c, app-common.h, app-nks.c, app-p15.c, app-dinsig.c + * app-openpgp.c: Change most function return types from int to + gpg_error_t. + * command.c (pin_cb): Ditto. + * sc-copykeys.c (pincb): Ditto. + + * app.c (lock_reader, unlock_reader): New. Changed call handler + wrappers to make use of these functions. + +2005-05-07 Werner Koch + + * ccid-driver.c (do_close_reader): Don't do a reset before close. + Some folks reported that it makes the SCR335 hang less often. + Look at the source on how to re-enable it. + 2005-04-27 Werner Koch * app-p15.c (micardo_mse): New. diff --git a/scd/apdu.c b/scd/apdu.c index d23a4adc9..212b9df24 100644 --- a/scd/apdu.c +++ b/scd/apdu.c @@ -20,6 +20,10 @@ * $Id$ */ +/* NOTE: This module is also used by other software, thus the use of + the macro USE_GNU_PTH is mandatory. For GnuPG this macro is + guaranteed to be defined true. */ + #include #include #include diff --git a/scd/app-common.h b/scd/app-common.h index 594f93850..517286c49 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -46,56 +46,56 @@ struct app_ctx_s { struct app_local_s *app_local; /* Local to the application. */ struct { void (*deinit) (app_t app); - int (*learn_status) (app_t app, ctrl_t ctrl); - int (*readcert) (app_t app, const char *certid, + gpg_error_t (*learn_status) (app_t app, ctrl_t ctrl); + gpg_error_t (*readcert) (app_t app, const char *certid, unsigned char **cert, size_t *certlen); - int (*readkey) (app_t app, const char *certid, + gpg_error_t (*readkey) (app_t app, const char *certid, unsigned char **pk, size_t *pklen); - int (*getattr) (app_t app, ctrl_t ctrl, const char *name); - int (*setattr) (app_t app, const char *name, - int (*pincb)(void*, const char *, char **), + gpg_error_t (*getattr) (app_t app, ctrl_t ctrl, const char *name); + gpg_error_t (*setattr) (app_t app, const char *name, + gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg, const unsigned char *value, size_t valuelen); - int (*sign) (app_t app, + gpg_error_t (*sign) (app_t app, const char *keyidstr, int hashalgo, - int (pincb)(void*, const char *, char **), + gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg, const void *indata, size_t indatalen, unsigned char **outdata, size_t *outdatalen ); - int (*auth) (app_t app, const char *keyidstr, - int (*pincb)(void*, const char *, char **), + gpg_error_t (*auth) (app_t app, const char *keyidstr, + gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg, const void *indata, size_t indatalen, unsigned char **outdata, size_t *outdatalen); - int (*decipher) (app_t app, const char *keyidstr, - int (pincb)(void*, const char *, char **), + gpg_error_t (*decipher) (app_t app, const char *keyidstr, + gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg, const void *indata, size_t indatalen, unsigned char **outdata, size_t *outdatalen); - int (*genkey) (app_t app, ctrl_t ctrl, + gpg_error_t (*genkey) (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags, - int (*pincb)(void*, const char *, char **), + gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg); - int (*change_pin) (app_t app, ctrl_t ctrl, + gpg_error_t (*change_pin) (app_t app, ctrl_t ctrl, const char *chvnostr, int reset_mode, - int (*pincb)(void*, const char *, char **), + gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg); - int (*check_pin) (app_t app, const char *keyidstr, - int (pincb)(void*, const char *, char **), + gpg_error_t (*check_pin) (app_t app, const char *keyidstr, + gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg); } fnc; }; #if GNUPG_MAJOR_VERSION == 1 -int app_select_openpgp (app_t app); -int app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp); -int app_openpgp_storekey (app_t app, int keyno, +gpg_error_t app_select_openpgp (app_t app); +gpg_error_t app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp); +gpg_error_t app_openpgp_storekey (app_t app, int keyno, unsigned char *template, size_t template_len, time_t created_at, const unsigned char *m, size_t mlen, const unsigned char *e, size_t elen, - int (*pincb)(void*, const char *, char **), + gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg); #else /*-- app-help.c --*/ @@ -107,72 +107,73 @@ size_t app_help_read_length_of_cert (int slot, int fid, size_t *r_certoff); gpg_error_t select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app); void release_application (app_t app); -int app_munge_serialno (app_t app); -int app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp); -int app_write_learn_status (app_t app, ctrl_t ctrl); -int app_readcert (app_t app, const char *certid, +gpg_error_t app_munge_serialno (app_t app); +gpg_error_t app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp); +gpg_error_t app_write_learn_status (app_t app, ctrl_t ctrl); +gpg_error_t app_readcert (app_t app, const char *certid, unsigned char **cert, size_t *certlen); -int app_readkey (app_t app, const char *keyid, +gpg_error_t app_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen); -int app_getattr (app_t app, ctrl_t ctrl, const char *name); -int app_setattr (app_t app, const char *name, - int (*pincb)(void*, const char *, char **), +gpg_error_t app_getattr (app_t app, ctrl_t ctrl, const char *name); +gpg_error_t app_setattr (app_t app, const char *name, + gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg, const unsigned char *value, size_t valuelen); -int app_sign (app_t app, const char *keyidstr, int hashalgo, - int (pincb)(void*, const char *, char **), +gpg_error_t app_sign (app_t app, const char *keyidstr, int hashalgo, + gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg, const void *indata, size_t indatalen, unsigned char **outdata, size_t *outdatalen ); -int app_auth (app_t app, const char *keyidstr, - int (*pincb)(void*, const char *, char **), +gpg_error_t app_auth (app_t app, const char *keyidstr, + gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg, const void *indata, size_t indatalen, unsigned char **outdata, size_t *outdatalen); -int app_decipher (app_t app, const char *keyidstr, - int (pincb)(void*, const char *, char **), +gpg_error_t app_decipher (app_t app, const char *keyidstr, + gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg, const void *indata, size_t indatalen, unsigned char **outdata, size_t *outdatalen ); -int app_genkey (app_t app, ctrl_t ctrl, +gpg_error_t app_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags, - int (*pincb)(void*, const char *, char **), + gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg); -int app_get_challenge (app_t app, size_t nbytes, unsigned char *buffer); -int app_change_pin (app_t app, ctrl_t ctrl, +gpg_error_t app_get_challenge (app_t app, size_t nbytes, + unsigned char *buffer); +gpg_error_t app_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, int reset_mode, - int (*pincb)(void*, const char *, char **), + gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg); -int app_check_pin (app_t app, const char *keyidstr, - int (*pincb)(void*, const char *, char **), +gpg_error_t app_check_pin (app_t app, const char *keyidstr, + gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg); /*-- app-openpgp.c --*/ -int app_select_openpgp (app_t app); +gpg_error_t app_select_openpgp (app_t app); -int app_openpgp_cardinfo (app_t app, +gpg_error_t app_openpgp_cardinfo (app_t app, char **serialno, char **disp_name, char **pubkey_url, unsigned char **fpr1, unsigned char **fpr2, unsigned char **fpr3); -int app_openpgp_storekey (app_t app, int keyno, +gpg_error_t app_openpgp_storekey (app_t app, int keyno, unsigned char *template, size_t template_len, time_t created_at, const unsigned char *m, size_t mlen, const unsigned char *e, size_t elen, - int (*pincb)(void*, const char *, char **), + gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg); -int app_openpgp_readkey (app_t app, int keyno, +gpg_error_t app_openpgp_readkey (app_t app, int keyno, unsigned char **m, size_t *mlen, unsigned char **e, size_t *elen); /*-- app-nks.c --*/ -int app_select_nks (app_t app); +gpg_error_t app_select_nks (app_t app); /*-- app-dinsig.c --*/ -int app_select_dinsig (app_t app); +gpg_error_t app_select_dinsig (app_t app); /*-- app-p15.c --*/ gpg_error_t app_select_p15 (app_t app); diff --git a/scd/app-dinsig.c b/scd/app-dinsig.c index 38fbc79ee..28b70c466 100644 --- a/scd/app-dinsig.c +++ b/scd/app-dinsig.c @@ -85,7 +85,7 @@ #include "tlv.h" -static int +static gpg_error_t do_learn_status (app_t app, ctrl_t ctrl) { gpg_error_t err; @@ -162,7 +162,7 @@ do_learn_status (app_t app, ctrl_t ctrl) FIXME: This needs some cleanups and caching with do_learn_status. */ -static int +static gpg_error_t do_readcert (app_t app, const char *certid, unsigned char **cert, size_t *certlen) { @@ -273,9 +273,9 @@ do_readcert (app_t app, const char *certid, /* Verify the PIN if required. */ -static int +static gpg_error_t verify_pin (app_t app, - int (pincb)(void*, const char *, char **), + gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg) { if (!app->did_chv1 || app->force_chv1 ) @@ -326,12 +326,12 @@ verify_pin (app_t app, If a PIN is required the PINCB will be used to ask for the PIN; that callback should return the PIN in an allocated buffer and store that in the 3rd argument. */ -static int +static gpg_error_t do_sign (app_t app, const char *keyidstr, int hashalgo, - int (pincb)(void*, const char *, char **), - void *pincb_arg, - const void *indata, size_t indatalen, - unsigned char **outdata, size_t *outdatalen ) + gpg_error_t (*pincb)(void*, const char *, char **), + void *pincb_arg, + const void *indata, size_t indatalen, + unsigned char **outdata, size_t *outdatalen ) { static unsigned char sha1_prefix[15] = /* Object ID is 1.3.14.3.2.26 */ { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, @@ -397,7 +397,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, /* Select the DINSIG application on the card in SLOT. This function must be used before any other DINSIG application functions. */ -int +gpg_error_t app_select_dinsig (APP app) { static char const aid[] = { 0xD2, 0x76, 0x00, 0x00, 0x66, 0x01 }; diff --git a/scd/app-nks.c b/scd/app-nks.c index f14b67972..b6a3037ed 100644 --- a/scd/app-nks.c +++ b/scd/app-nks.c @@ -117,7 +117,7 @@ keygripstr_from_pk_file (int slot, int fid, char *r_gripstr) -static int +static gpg_error_t do_learn_status (APP app, CTRL ctrl) { gpg_error_t err; @@ -175,7 +175,7 @@ do_learn_status (APP app, CTRL ctrl) the CERTINFO status lines) and return it in the freshly allocated buffer put into CERT and the length of the certificate put into CERTLEN. */ -static int +static gpg_error_t do_readcert (app_t app, const char *certid, unsigned char **cert, size_t *certlen) { @@ -299,9 +299,9 @@ do_readcert (app_t app, const char *certid, /* Verify the PIN if required. */ -static int +static gpg_error_t verify_pin (app_t app, - int (pincb)(void*, const char *, char **), + gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg) { /* Note that force_chv1 is never set but we do it here anyway so @@ -357,12 +357,12 @@ verify_pin (app_t app, If a PIN is required the PINCB will be used to ask for the PIN; that callback should return the PIN in an allocated buffer and store that in the 3rd argument. */ -static int +static gpg_error_t do_sign (app_t app, const char *keyidstr, int hashalgo, - int (pincb)(void*, const char *, char **), - void *pincb_arg, - const void *indata, size_t indatalen, - unsigned char **outdata, size_t *outdatalen ) + gpg_error_t (*pincb)(void*, const char *, char **), + void *pincb_arg, + const void *indata, size_t indatalen, + unsigned char **outdata, size_t *outdatalen ) { static unsigned char sha1_prefix[15] = /* Object ID is 1.3.14.3.2.26 */ { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, @@ -435,9 +435,9 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, /* Decrypt the data in INDATA and return the allocated result in OUTDATA. If a PIN is required the PINCB will be used to ask for the PIN; it should return the PIN in an allocated buffer and put it into PIN. */ -static int +static gpg_error_t do_decipher (app_t app, const char *keyidstr, - int (pincb)(void*, const char *, char **), + gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg, const void *indata, size_t indatalen, unsigned char **outdata, size_t *outdatalen ) @@ -485,7 +485,7 @@ do_decipher (app_t app, const char *keyidstr, /* Select the NKS 2.0 application on the card in SLOT. */ -int +gpg_error_t app_select_nks (APP app) { static char const aid[] = { 0xD2, 0x76, 0x00, 0x00, 0x03, 0x01, 0x02 }; diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index ca0e2501b..b8060df03 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -547,7 +547,7 @@ parse_login_data (app_t app) } /* Note, that FPR must be at least 20 bytes. */ -static int +static gpg_error_t store_fpr (int slot, int keynumber, u32 timestamp, const unsigned char *m, size_t mlen, const unsigned char *e, size_t elen, @@ -671,7 +671,7 @@ send_key_data (ctrl_t ctrl, const char *name, /* Implement the GETATTR command. This is similar to the LEARN command but returns just one value via the status interface. */ -static int +static gpg_error_t do_getattr (app_t app, ctrl_t ctrl, const char *name) { static struct { @@ -1168,7 +1168,7 @@ send_keypair_info (app_t app, ctrl_t ctrl, int keyno) /* Handle the LEARN command for OpenPGP. */ -static int +static gpg_error_t do_learn_status (app_t app, ctrl_t ctrl) { do_getattr (app, ctrl, "EXTCAP"); @@ -1204,7 +1204,7 @@ do_learn_status (app_t app, ctrl_t ctrl) its length (for assertions) at PKLEN; the caller must release that buffer. On error PK and PKLEN are not changed and an error code is returned. */ -static int +static gpg_error_t do_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen) { gpg_error_t err; @@ -1236,9 +1236,9 @@ do_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen) /* Verify CHV2 if required. Depending on the configuration of the card CHV1 will also be verified. */ -static int +static gpg_error_t verify_chv2 (app_t app, - int (*pincb)(void*, const char *, char **), + gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg) { int rc = 0; @@ -1292,9 +1292,9 @@ verify_chv2 (app_t app, } /* Verify CHV3 if required. */ -static int +static gpg_error_t verify_chv3 (app_t app, - int (*pincb)(void*, const char *, char **), + gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg) { int rc = 0; @@ -1366,9 +1366,9 @@ verify_chv3 (app_t app, /* Handle the SETATTR operation. All arguments are already basically checked. */ -static int +static gpg_error_t do_setattr (app_t app, const char *name, - int (*pincb)(void*, const char *, char **), + gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg, const unsigned char *value, size_t valuelen) { @@ -1434,9 +1434,9 @@ do_setattr (app_t app, const char *name, /* Handle the PASSWD command. */ -static int +static gpg_error_t do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, int reset_mode, - int (*pincb)(void*, const char *, char **), + gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg) { int rc = 0; @@ -1525,9 +1525,9 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, int reset_mode, /* Handle the GENKEY command. */ -static int +static gpg_error_t do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags, - int (*pincb)(void*, const char *, char **), + gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg) { int rc; @@ -1691,7 +1691,7 @@ get_sig_counter (app_t app) return ul; } -static int +static gpg_error_t compare_fingerprint (app_t app, int keyno, unsigned char *sha1fpr) { const unsigned char *fpr; @@ -1731,7 +1731,7 @@ compare_fingerprint (app_t app, int keyno, unsigned char *sha1fpr) the key on the card has been replaced but the shadow information known to gpg was not updated. If there is no fingerprint we assume that this is okay. */ -static int +static gpg_error_t check_against_given_fingerprint (app_t app, const char *fpr, int keyno) { unsigned char tmp[20]; @@ -1762,9 +1762,9 @@ check_against_given_fingerprint (app_t app, const char *fpr, int keyno) GPG_ERR_WRONG_CARD to indicate that the card currently present does not match the one required for the requested action (e.g. the serial number does not match). */ -static int +static gpg_error_t do_sign (app_t app, const char *keyidstr, int hashalgo, - int (*pincb)(void*, const char *, char **), + gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg, const void *indata, size_t indatalen, unsigned char **outdata, size_t *outdatalen ) @@ -1911,9 +1911,9 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, GPG_ERR_WRONG_CARD to indicate that the card currently present does not match the one required for the requested action (e.g. the serial number does not match). */ -static int +static gpg_error_t do_auth (app_t app, const char *keyidstr, - int (*pincb)(void*, const char *, char **), + gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg, const void *indata, size_t indatalen, unsigned char **outdata, size_t *outdatalen ) @@ -1974,9 +1974,9 @@ do_auth (app_t app, const char *keyidstr, } -static int +static gpg_error_t do_decipher (app_t app, const char *keyidstr, - int (pincb)(void*, const char *, char **), + gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg, const void *indata, size_t indatalen, unsigned char **outdata, size_t *outdatalen ) @@ -2040,9 +2040,9 @@ do_decipher (app_t app, const char *keyidstr, There is a special mode if the keyidstr is "[CHV3]" with the "[CHV3]" being a literal string: The Admin Pin is checked if and only if the retry counter is still at 3. */ -static int +static gpg_error_t do_check_pin (app_t app, const char *keyidstr, - int (pincb)(void*, const char *, char **), + gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg) { unsigned char tmp_sn[20]; @@ -2124,7 +2124,7 @@ do_check_pin (app_t app, const char *keyidstr, /* Select the OpenPGP application on the card in SLOT. This function must be used before any other OpenPGP application functions. */ -int +gpg_error_t app_select_openpgp (app_t app) { static char const aid[] = { 0xD2, 0x76, 0x00, 0x01, 0x24, 0x01 }; @@ -2237,7 +2237,7 @@ leave: LEARN command returns. All parameters return allocated strings or buffers or NULL if the data object is not available. All returned values are sanitized. */ -int +gpg_error_t app_openpgp_cardinfo (app_t app, char **serialno, char **disp_name, @@ -2327,13 +2327,13 @@ app_openpgp_cardinfo (app_t app, create the fingerprint. M, MLEN is the RSA modulus and E, ELEN the RSA public exponent. This function silently overwrites an existing key.*/ -int +gpg_error_t app_openpgp_storekey (app_t app, int keyno, unsigned char *template, size_t template_len, time_t created_at, const unsigned char *m, size_t mlen, const unsigned char *e, size_t elen, - int (*pincb)(void*, const char *, char **), + gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg) { int rc; @@ -2377,7 +2377,7 @@ app_openpgp_storekey (app_t app, int keyno, /* Utility function for external tools: Read the public RSA key at KEYNO and return modulus and exponent in (M,MLEN) and (E,ELEN). */ -int +gpg_error_t app_openpgp_readkey (app_t app, int keyno, unsigned char **m, size_t *mlen, unsigned char **e, size_t *elen) { diff --git a/scd/app-p15.c b/scd/app-p15.c index d2ed15a59..831f0d1f4 100644 --- a/scd/app-p15.c +++ b/scd/app-p15.c @@ -2366,7 +2366,7 @@ send_keypairinfo (app_t app, ctrl_t ctrl, prkdf_object_t keyinfo) /* This is the handler for the LEARN command. */ -static int /* FIXME: change this to gpg_error_t */ +static gpg_error_t do_learn_status (app_t app, ctrl_t ctrl) { gpg_error_t err; @@ -2513,7 +2513,7 @@ readcert_by_cdf (app_t app, cdf_object_t cdf, buffer to be stored at R_CERT and its length at R_CERTLEN. A error code will be returned on failure and R_CERT and R_CERTLEN will be set to NULL/0. */ -static int /* FIXME: change this to gpg_error_t */ +static gpg_error_t do_readcert (app_t app, const char *certid, unsigned char **r_cert, size_t *r_certlen) { @@ -2629,9 +2629,9 @@ micardo_mse (app_t app, unsigned short fid) If a PIN is required, the PINCB will be used to ask for the PIN; that callback should return the PIN in an allocated buffer and store that as the 3rd argument. */ -static int +static gpg_error_t do_sign (app_t app, const char *keyidstr, int hashalgo, - int (pincb)(void*, const char *, char **), + gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg, const void *indata, size_t indatalen, unsigned char **outdata, size_t *outdatalen ) diff --git a/scd/app.c b/scd/app.c index 8e95ef7ef..0a1960267 100644 --- a/scd/app.c +++ b/scd/app.c @@ -23,7 +23,7 @@ #include #include #include - +# include #include "scdaemon.h" #include "app-common.h" @@ -31,7 +31,72 @@ #include "iso7816.h" #include "tlv.h" +/* This table is used to keep track of locks on a per reader base. + The index into the table is the slot number of the reader. The + mutex will be initialized on demand (one of the advantages of a + userland threading system). */ +static struct +{ + int initialized; + pth_mutex_t lock; +} lock_table[10]; + + +/* Lock the reader associated with the APP context. This function + shall be used right before calling any of the actual application + functions to serialize access to the reader. We do this always + even if the reader is not actually used. This allows an actual + application to assume that it never shares a reader (while + performing one command). Returns 0 on success; only then the + unlock_reader function must be called after returning from the + handler. */ +static gpg_error_t +lock_reader (app_t app) +{ + gpg_error_t err; + int slot = app->slot; + + if (slot < 0 || slot >= DIM (lock_table)) + return gpg_error (app->slot<0? GPG_ERR_INV_VALUE : GPG_ERR_RESOURCE_LIMIT); + + if (!lock_table[slot].initialized) + { + if (!pth_mutex_init (&lock_table[slot].lock)) + { + err = gpg_error_from_errno (errno); + log_error ("error initializing mutex: %s\n", strerror (errno)); + return err; + } + lock_table[slot].initialized = 1; + } + + if (!pth_mutex_acquire (&lock_table[slot].lock, 0, NULL)) + { + err = gpg_error_from_errno (errno); + log_error ("failed to acquire APP lock for slot %d: %s\n", + slot, strerror (errno)); + return err; + } + + return 0; +} + +/* Release a lock on the reader. See lock_reader(). */ +static void +unlock_reader (app_t app) +{ + int slot = app->slot; + + if (slot < 0 || slot >= DIM (lock_table) + || !lock_table[slot].initialized) + log_bug ("unlock_reader called for invalid slot %d\n", slot); + if (!pth_mutex_release (&lock_table[slot].lock)) + log_error ("failed to release APP lock for slot %d: %s\n", + slot, strerror (errno)); + +} + /* Check wether the application NAME is allowed. This does not mean we have support for it though. */ static int @@ -54,7 +119,7 @@ is_app_allowed (const char *name) gpg_error_t select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app) { - int rc; + gpg_error_t err; app_t app; unsigned char *result = NULL; size_t resultlen; @@ -63,22 +128,26 @@ select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app) app = xtrycalloc (1, sizeof *app); if (!app) { - rc = gpg_error_from_errno (errno); - log_info ("error allocating context: %s\n", gpg_strerror (rc)); - return rc; + err = gpg_error_from_errno (errno); + log_info ("error allocating context: %s\n", gpg_strerror (err)); + return err; } app->slot = slot; + err = lock_reader (app); + if (err) + return err; + /* Fixme: We should now first check whether a card is at all present. */ /* Try to read the GDO file first to get a default serial number. */ - rc = iso7816_select_file (slot, 0x3F00, 1, NULL, NULL); - if (!rc) - rc = iso7816_select_file (slot, 0x2F02, 0, NULL, NULL); - if (!rc) - rc = iso7816_read_binary (slot, 0, 0, &result, &resultlen); - if (!rc) + err = iso7816_select_file (slot, 0x3F00, 1, NULL, NULL); + if (!err) + err = iso7816_select_file (slot, 0x2F02, 0, NULL, NULL); + if (!err) + err = iso7816_read_binary (slot, 0, 0, &result, &resultlen); + if (!err) { size_t n; const unsigned char *p; @@ -104,8 +173,8 @@ select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app) memmove (result, p, n); app->serialno = result; app->serialnolen = n; - rc = app_munge_serialno (app); - if (rc) + err = app_munge_serialno (app); + if (err) goto leave; } else @@ -114,38 +183,40 @@ select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app) } /* For certain error codes, there is no need to try more. */ - if (gpg_err_code (rc) == GPG_ERR_CARD_NOT_PRESENT) + if (gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT) goto leave; /* Figure out the application to use. */ - rc = gpg_error (GPG_ERR_NOT_FOUND); - - if (rc && is_app_allowed ("openpgp") && (!name || !strcmp (name, "openpgp"))) - rc = app_select_openpgp (app); - if (rc && is_app_allowed ("nks") && (!name || !strcmp (name, "nks"))) - rc = app_select_nks (app); - if (rc && is_app_allowed ("p15") && (!name || !strcmp (name, "p15"))) - rc = app_select_p15 (app); - if (rc && is_app_allowed ("dinsig") && (!name || !strcmp (name, "dinsig"))) - rc = app_select_dinsig (app); - if (rc && name) - rc = gpg_error (GPG_ERR_NOT_SUPPORTED); + err = gpg_error (GPG_ERR_NOT_FOUND); + + if (err && is_app_allowed ("openpgp") + && (!name || !strcmp (name, "openpgp"))) + err = app_select_openpgp (app); + if (err && is_app_allowed ("nks") && (!name || !strcmp (name, "nks"))) + err = app_select_nks (app); + if (err && is_app_allowed ("p15") && (!name || !strcmp (name, "p15"))) + err = app_select_p15 (app); + if (err && is_app_allowed ("dinsig") && (!name || !strcmp (name, "dinsig"))) + err = app_select_dinsig (app); + if (err && name) + err = gpg_error (GPG_ERR_NOT_SUPPORTED); leave: - if (rc) + if (err) { if (name) log_info ("can't select application `%s': %s\n", - name, gpg_strerror (rc)); + name, gpg_strerror (err)); else log_info ("no supported card application found: %s\n", - gpg_strerror (rc)); + gpg_strerror (err)); xfree (app); - return rc; + return err; } app->initialized = 1; + unlock_reader (app); *r_app = app; return 0; } @@ -181,7 +252,7 @@ release_application (app_t app) All other serial number not starting with FF are used as they are. */ -int +gpg_error_t app_munge_serialno (app_t app) { if (app->serialnolen && app->serialno[0] == 0xff) @@ -208,7 +279,7 @@ app_munge_serialno (app_t app) no update time is available the returned value is 0. Caller must free SERIAL unless the function returns an error. If STAMP is not of interest, NULL may be passed. */ -int +gpg_error_t app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp) { unsigned char *buf, *p; @@ -234,9 +305,11 @@ app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp) /* Write out the application specifig status lines for the LEARN command. */ -int -app_write_learn_status (APP app, CTRL ctrl) +gpg_error_t +app_write_learn_status (app_t app, CTRL ctrl) { + gpg_error_t err; + if (!app) return gpg_error (GPG_ERR_INV_VALUE); if (!app->initialized) @@ -247,8 +320,12 @@ app_write_learn_status (APP app, CTRL ctrl) if (app->apptype) send_status_info (ctrl, "APPTYPE", app->apptype, strlen (app->apptype), NULL, 0); - - return app->fnc.learn_status (app, ctrl); + err = lock_reader (app); + if (err) + return err; + err = app->fnc.learn_status (app, ctrl); + unlock_reader (app); + return err; } @@ -256,18 +333,24 @@ app_write_learn_status (APP app, CTRL ctrl) the CERTINFO status lines) and return it in the freshly allocated buffer put into CERT and the length of the certificate put into CERTLEN. */ -int +gpg_error_t app_readcert (app_t app, const char *certid, unsigned char **cert, size_t *certlen) { + gpg_error_t err; + if (!app) return gpg_error (GPG_ERR_INV_VALUE); if (!app->initialized) return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); if (!app->fnc.readcert) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); - - return app->fnc.readcert (app, certid, cert, certlen); + err = lock_reader (app); + if (err) + return err; + err = app->fnc.readcert (app, certid, cert, certlen); + unlock_reader (app); + return err; } @@ -278,9 +361,11 @@ app_readcert (app_t app, const char *certid, code returned. This function might not be supported by all applications. */ -int +gpg_error_t app_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen) { + gpg_error_t err; + if (pk) *pk = NULL; if (pklen) @@ -292,15 +377,21 @@ app_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen) return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); if (!app->fnc.readkey) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); - - return app->fnc.readkey (app, keyid, pk, pklen); + err = lock_reader (app); + if (err) + return err; + err= app->fnc.readkey (app, keyid, pk, pklen); + unlock_reader (app); + return err; } /* Perform a GETATTR operation. */ -int -app_getattr (APP app, CTRL ctrl, const char *name) +gpg_error_t +app_getattr (app_t app, CTRL ctrl, const char *name) { + gpg_error_t err; + if (!app || !name || !*name) return gpg_error (GPG_ERR_INV_VALUE); if (!app->initialized) @@ -328,36 +419,48 @@ app_getattr (APP app, CTRL ctrl, const char *name) if (!app->fnc.getattr) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); - return app->fnc.getattr (app, ctrl, name); + err = lock_reader (app); + if (err) + return err; + err = app->fnc.getattr (app, ctrl, name); + unlock_reader (app); + return err; } /* Perform a SETATTR operation. */ -int -app_setattr (APP app, const char *name, - int (*pincb)(void*, const char *, char **), +gpg_error_t +app_setattr (app_t app, const char *name, + gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg, const unsigned char *value, size_t valuelen) { + gpg_error_t err; + if (!app || !name || !*name || !value) return gpg_error (GPG_ERR_INV_VALUE); if (!app->initialized) return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); if (!app->fnc.setattr) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); - return app->fnc.setattr (app, name, pincb, pincb_arg, value, valuelen); + err = lock_reader (app); + if (err) + return err; + err = app->fnc.setattr (app, name, pincb, pincb_arg, value, valuelen); + unlock_reader (app); + return err; } /* Create the signature and return the allocated result in OUTDATA. If a PIN is required the PINCB will be used to ask for the PIN; it should return the PIN in an allocated buffer and put it into PIN. */ -int -app_sign (APP app, const char *keyidstr, int hashalgo, - int (pincb)(void*, const char *, char **), +gpg_error_t +app_sign (app_t app, const char *keyidstr, int hashalgo, + gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg, const void *indata, size_t indatalen, unsigned char **outdata, size_t *outdatalen ) { - int rc; + gpg_error_t err; if (!app || !indata || !indatalen || !outdata || !outdatalen || !pincb) return gpg_error (GPG_ERR_INV_VALUE); @@ -365,27 +468,31 @@ app_sign (APP app, const char *keyidstr, int hashalgo, return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); if (!app->fnc.sign) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); - rc = app->fnc.sign (app, keyidstr, hashalgo, - pincb, pincb_arg, - indata, indatalen, - outdata, outdatalen); + err = lock_reader (app); + if (err) + return err; + err = app->fnc.sign (app, keyidstr, hashalgo, + pincb, pincb_arg, + indata, indatalen, + outdata, outdatalen); + unlock_reader (app); if (opt.verbose) - log_info ("operation sign result: %s\n", gpg_strerror (rc)); - return rc; + log_info ("operation sign result: %s\n", gpg_strerror (err)); + return err; } /* Create the signature using the INTERNAL AUTHENTICATE command and return the allocated result in OUTDATA. If a PIN is required the PINCB will be used to ask for the PIN; it should return the PIN in an allocated buffer and put it into PIN. */ -int -app_auth (APP app, const char *keyidstr, - int (pincb)(void*, const char *, char **), +gpg_error_t +app_auth (app_t app, const char *keyidstr, + gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg, const void *indata, size_t indatalen, unsigned char **outdata, size_t *outdatalen ) { - int rc; + gpg_error_t err; if (!app || !indata || !indatalen || !outdata || !outdatalen || !pincb) return gpg_error (GPG_ERR_INV_VALUE); @@ -393,27 +500,31 @@ app_auth (APP app, const char *keyidstr, return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); if (!app->fnc.auth) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); - rc = app->fnc.auth (app, keyidstr, - pincb, pincb_arg, - indata, indatalen, - outdata, outdatalen); + err = lock_reader (app); + if (err) + return err; + err = app->fnc.auth (app, keyidstr, + pincb, pincb_arg, + indata, indatalen, + outdata, outdatalen); + unlock_reader (app); if (opt.verbose) - log_info ("operation auth result: %s\n", gpg_strerror (rc)); - return rc; + log_info ("operation auth result: %s\n", gpg_strerror (err)); + return err; } /* Decrypt the data in INDATA and return the allocated result in OUTDATA. If a PIN is required the PINCB will be used to ask for the PIN; it should return the PIN in an allocated buffer and put it into PIN. */ -int -app_decipher (APP app, const char *keyidstr, - int (pincb)(void*, const char *, char **), +gpg_error_t +app_decipher (app_t app, const char *keyidstr, + gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg, const void *indata, size_t indatalen, unsigned char **outdata, size_t *outdatalen ) { - int rc; + gpg_error_t err; if (!app || !indata || !indatalen || !outdata || !outdatalen || !pincb) return gpg_error (GPG_ERR_INV_VALUE); @@ -421,23 +532,27 @@ app_decipher (APP app, const char *keyidstr, return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); if (!app->fnc.decipher) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); - rc = app->fnc.decipher (app, keyidstr, - pincb, pincb_arg, - indata, indatalen, - outdata, outdatalen); + err = lock_reader (app); + if (err) + return err; + err = app->fnc.decipher (app, keyidstr, + pincb, pincb_arg, + indata, indatalen, + outdata, outdatalen); + unlock_reader (app); if (opt.verbose) - log_info ("operation decipher result: %s\n", gpg_strerror (rc)); - return rc; + log_info ("operation decipher result: %s\n", gpg_strerror (err)); + return err; } /* Perform a SETATTR operation. */ -int -app_genkey (APP app, CTRL ctrl, const char *keynostr, unsigned int flags, - int (*pincb)(void*, const char *, char **), +gpg_error_t +app_genkey (app_t app, CTRL ctrl, const char *keynostr, unsigned int flags, + gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg) { - int rc; + gpg_error_t err; if (!app || !keynostr || !*keynostr || !pincb) return gpg_error (GPG_ERR_INV_VALUE); @@ -445,35 +560,46 @@ app_genkey (APP app, CTRL ctrl, const char *keynostr, unsigned int flags, return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); if (!app->fnc.genkey) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); - rc = app->fnc.genkey (app, ctrl, keynostr, flags, pincb, pincb_arg); + err = lock_reader (app); + if (err) + return err; + err = app->fnc.genkey (app, ctrl, keynostr, flags, pincb, pincb_arg); + unlock_reader (app); if (opt.verbose) - log_info ("operation genkey result: %s\n", gpg_strerror (rc)); - return rc; + log_info ("operation genkey result: %s\n", gpg_strerror (err)); + return err; } /* Perform a GET CHALLENGE operation. This fucntion is special as it directly accesses the card without any application specific wrapper. */ -int -app_get_challenge (APP app, size_t nbytes, unsigned char *buffer) +gpg_error_t +app_get_challenge (app_t app, size_t nbytes, unsigned char *buffer) { + gpg_error_t err; + if (!app || !nbytes || !buffer) return gpg_error (GPG_ERR_INV_VALUE); if (!app->initialized) return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); - return iso7816_get_challenge (app->slot, nbytes, buffer); + err = lock_reader (app); + if (err) + return err; + err = iso7816_get_challenge (app->slot, nbytes, buffer); + unlock_reader (app); + return err; } /* Perform a CHANGE REFERENCE DATA or RESET RETRY COUNTER operation. */ -int -app_change_pin (APP app, CTRL ctrl, const char *chvnostr, int reset_mode, - int (*pincb)(void*, const char *, char **), +gpg_error_t +app_change_pin (app_t app, CTRL ctrl, const char *chvnostr, int reset_mode, + gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg) { - int rc; + gpg_error_t err; if (!app || !chvnostr || !*chvnostr || !pincb) return gpg_error (GPG_ERR_INV_VALUE); @@ -481,22 +607,27 @@ app_change_pin (APP app, CTRL ctrl, const char *chvnostr, int reset_mode, return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); if (!app->fnc.change_pin) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); - rc = app->fnc.change_pin (app, ctrl, chvnostr, reset_mode, pincb, pincb_arg); + err = lock_reader (app); + if (err) + return err; + err = app->fnc.change_pin (app, ctrl, chvnostr, reset_mode, + pincb, pincb_arg); + unlock_reader (app); if (opt.verbose) - log_info ("operation change_pin result: %s\n", gpg_strerror (rc)); - return rc; + log_info ("operation change_pin result: %s\n", gpg_strerror (err)); + return err; } /* Perform a VERIFY operation without doing anything lese. This may be used to initialze a the PIN cache for long lasting other operations. Its use is highly application dependent. */ -int -app_check_pin (APP app, const char *keyidstr, - int (*pincb)(void*, const char *, char **), +gpg_error_t +app_check_pin (app_t app, const char *keyidstr, + gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg) { - int rc; + gpg_error_t err; if (!app || !keyidstr || !*keyidstr || !pincb) return gpg_error (GPG_ERR_INV_VALUE); @@ -504,9 +635,13 @@ app_check_pin (APP app, const char *keyidstr, return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); if (!app->fnc.check_pin) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); - rc = app->fnc.check_pin (app, keyidstr, pincb, pincb_arg); + err = lock_reader (app); + if (err) + return err; + err = app->fnc.check_pin (app, keyidstr, pincb, pincb_arg); + unlock_reader (app); if (opt.verbose) - log_info ("operation check_pin result: %s\n", gpg_strerror (rc)); - return rc; + log_info ("operation check_pin result: %s\n", gpg_strerror (err)); + return err; } diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c index e9666ee17..b817452b1 100644 --- a/scd/ccid-driver.c +++ b/scd/ccid-driver.c @@ -986,7 +986,8 @@ do_close_reader (ccid_driver_t handle) } if (handle->idev) { - usb_reset (handle->idev); + if (getenv ("GNUPG_CCID_DRIVER_RESET_BEFORE_CLOSE")) + usb_reset (handle->idev); usb_release_interface (handle->idev, handle->ifc_no); usb_close (handle->idev); handle->idev = NULL; @@ -1274,7 +1275,7 @@ ccid_poll (ccid_driver_t handle) } -/* Note that this function won't return the error codes NO_CARD or +/* Note that this fucntion won't return the error codes NO_CARD or CARD_INACTIVE */ int ccid_slot_status (ccid_driver_t handle, int *statusbits) @@ -1303,12 +1304,12 @@ ccid_slot_status (ccid_driver_t handle, int *statusbits) { if (!retries) { - fprintf (stderr, "CALLING USB_CLEAR_HALT\n"); + DEBUGOUT ("USB: CALLING USB_CLEAR_HALT\n"); usb_clear_halt (handle->idev, handle->ep_bulk_in); usb_clear_halt (handle->idev, handle->ep_bulk_out); } else - fprintf (stderr, "RETRYING AGIAN\n"); + DEBUGOUT ("USB: RETRYING bulk_in AGAIN\n"); retries++; goto retry; } diff --git a/scd/command.c b/scd/command.c index c8eebaac0..5ea3e01db 100644 --- a/scd/command.c +++ b/scd/command.c @@ -122,7 +122,7 @@ has_option (const char *line, const char *name) /* Reset the card and free the application context. With DO_CLOSE set - to true and this is the last session with a reference to teh + to true and this is the last session with a reference to the reader, close the reader and don't do just a reset. */ static void do_reset (ctrl_t ctrl, int do_close) @@ -647,7 +647,7 @@ cmd_setdata (assuan_context_t ctx, char *line) -static int +static gpg_error_t pin_cb (void *opaque, const char *info, char **retstr) { assuan_context_t ctx = opaque; @@ -1171,6 +1171,34 @@ cmd_unlock (assuan_context_t ctx, char *line) } +/* GETINFO + + Multi purpose command to return certain information. + Supported values of WHAT are: + + socket_name - Return the name of the socket. + +*/ + +static int +cmd_getinfo (assuan_context_t ctx, char *line) +{ + int rc = 0; + + if (!strcmp (line, "socket_name")) + { + const char *s = scd_get_socket_name (); + + if (s) + rc = assuan_send_data (ctx, s, strlen (s)); + else + rc = gpg_error (GPG_ERR_NO_DATA); + } + else + rc = set_error (Parameter_Error, "unknown value for WHAT"); + return rc; +} + @@ -1200,6 +1228,7 @@ register_commands (assuan_context_t ctx) { "CHECKPIN", cmd_checkpin }, { "LOCK", cmd_lock }, { "UNLOCK", cmd_unlock }, + { "GETINFO", cmd_getinfo }, { NULL } }; int i, rc; @@ -1218,10 +1247,10 @@ register_commands (assuan_context_t ctx) } -/* Startup the server. If LISTEN_FD is given as -1, this is simple - piper server, otherwise it is a regular server */ +/* Startup the server. If FD is given as -1 this is simple pipe + server, otherwise it is a regular server. */ void -scd_command_handler (int listen_fd) +scd_command_handler (int fd) { int rc; assuan_context_t ctx; @@ -1230,7 +1259,7 @@ scd_command_handler (int listen_fd) memset (&ctrl, 0, sizeof ctrl); scd_init_default_ctrl (&ctrl); - if (listen_fd == -1) + if (fd == -1) { int filedes[2]; @@ -1240,7 +1269,7 @@ scd_command_handler (int listen_fd) } else { - rc = assuan_init_socket_server (&ctx, listen_fd); + rc = assuan_init_connected_socket_server (&ctx, fd); } if (rc) { diff --git a/scd/sc-copykeys.c b/scd/sc-copykeys.c index 78cb2acc8..66b6894e0 100644 --- a/scd/sc-copykeys.c +++ b/scd/sc-copykeys.c @@ -483,7 +483,7 @@ query_card (APP app) /* Callback function to ask for a PIN. */ -static int +static gpg_error_t pincb (void *arg, const char *prompt, char **pinvalue) { char *pin = xstrdup ("12345678"); diff --git a/scd/scdaemon.c b/scd/scdaemon.c index 7b0f31cdb..9a8b31ac5 100644 --- a/scd/scdaemon.c +++ b/scd/scdaemon.c @@ -1,5 +1,5 @@ /* scdaemon.c - The GnuPG Smartcard Daemon - * Copyright (C) 2001, 2002, 2004 Free Software Foundation, Inc. + * Copyright (C) 2001, 2002, 2004, 2005 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -35,9 +35,7 @@ #endif /*HAVE_W32_SYSTEM*/ #include #include -#ifdef USE_GNU_PTH -# include -#endif +#include #define JNLIB_NEED_LOG_LOGV #include "scdaemon.h" @@ -76,6 +74,7 @@ enum cmd_and_opt_values oNoGrab, oLogFile, oServer, + oMultiServer, oDaemon, oBatch, oReaderPort, @@ -110,6 +109,8 @@ static ARGPARSE_OPTS opts[] = { { oDebugWait,"debug-wait",1, "@"}, { oNoDetach, "no-detach" ,0, N_("do not detach from the console")}, { oLogFile, "log-file" ,2, N_("use a log file for the server")}, + { oMultiServer, "multi-server", 0, + N_("allow additional connections in server mode")}, { oReaderPort, "reader-port", 2, N_("|N|connect to reader at port N")}, { octapiDriver, "ctapi-driver", 2, N_("|NAME|use NAME as ct-API driver")}, { opcscDriver, "pcsc-driver", 2, N_("|NAME|use NAME as PC/SC driver")}, @@ -140,8 +141,6 @@ static ARGPARSE_OPTS opts[] = { #endif -static volatile int caught_fatal_sig = 0; - /* Flag to indicate that a shutdown was requested. */ static int shutdown_pending; @@ -149,16 +148,21 @@ static int shutdown_pending; static int maybe_setuid = 1; /* Name of the communication socket */ -static char socket_name[128]; +static char *socket_name; + + +static char *create_socket_name (int use_standard_socket, + char *standard_name, char *template); +static int create_server_socket (int is_standard_name, const char *name); +static void *start_connection_thread (void *arg); +static void handle_connections (int listen_fd); -#ifdef USE_GNU_PTH /* Pth wrapper function definitions. */ GCRY_THREAD_OPTION_PTH_IMPL; -static void *ticker_thread (void *arg); -#endif /*USE_GNU_PTH*/ + static const char * my_strusage (int level) { @@ -265,7 +269,7 @@ set_debug (const char *level) static void cleanup (void) { - if (*socket_name) + if (socket_name && *socket_name) { char *p; @@ -282,27 +286,6 @@ cleanup (void) } -static RETSIGTYPE -cleanup_sh (int sig) -{ - if (caught_fatal_sig) - raise (sig); - caught_fatal_sig = 1; - - /* gcry_control( GCRYCTL_TERM_SECMEM );*/ - cleanup (); - -#ifndef HAVE_DOSISH_SYSTEM - { /* reset action to default action and raise signal again */ - struct sigaction nact; - nact.sa_handler = SIG_DFL; - sigemptyset( &nact.sa_mask ); - nact.sa_flags = 0; - sigaction( sig, &nact, NULL); - } -#endif - raise( sig ); -} int main (int argc, char **argv ) @@ -322,6 +305,7 @@ main (int argc, char **argv ) int greeting = 0; int nogreeting = 0; int pipe_server = 0; + int multi_server = 0; int is_daemon = 0; int nodetach = 0; int csh_style = 0; @@ -343,14 +327,12 @@ main (int argc, char **argv ) /* Libgcrypt requires us to register the threading model first. Note that this will also do the pth_init. */ -#ifdef USE_GNU_PTH err = gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pth); if (err) { log_fatal ("can't register GNU Pth with Libgcrypt: %s\n", gpg_strerror (err)); } -#endif /*USE_GNU_PTH*/ /* Check that the libraries are suitable. Do it here because the option parsing may need services of the library */ @@ -481,6 +463,7 @@ main (int argc, char **argv ) case oCsh: csh_style = 1; break; case oSh: csh_style = 0; break; case oServer: pipe_server = 1; break; + case oMultiServer: multi_server = 1; break; case oDaemon: is_daemon = 1; break; case oReaderPort: opt.reader_port = pargs.r.ret_str; break; @@ -598,24 +581,49 @@ main (int argc, char **argv ) log_set_prefix (NULL, 1|2|4); } - if (pipe_server) - { /* This is the simple pipe based server */ -#ifdef USE_GNU_PTH + { + /* This is the simple pipe based server */ pth_attr_t tattr; - + int fd = -1; + + { + struct sigaction sa; + + sa.sa_handler = SIG_IGN; + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + sigaction (SIGPIPE, &sa, NULL); + } + + /* In multi server mode we need to listen on an additional + socket. Create that socket now before starting the handler + for the pipe connection. This allows that handler to send + back the name of that socket. */ + if (multi_server) + { + socket_name = create_socket_name (0, + "S.scdaemon", + "/tmp/gpg-XXXXXX/S.scdaemon"); + + fd = create_server_socket (0, socket_name); + } + tattr = pth_attr_new(); pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0); pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 512*1024); - pth_attr_set (tattr, PTH_ATTR_NAME, "ticker"); + pth_attr_set (tattr, PTH_ATTR_NAME, "pipe-connection"); - if (!pth_spawn (tattr, ticker_thread, NULL)) + if (!pth_spawn (tattr, start_connection_thread, (void*)(-1))) { - log_error ("error spawning ticker thread: %s\n", strerror (errno)); + log_error ("error spawning pipe connection handler: %s\n", + strerror (errno) ); scd_exit (2); } -#endif /*USE_GNU_PTH*/ - scd_command_handler (-1); + + handle_connections (fd); + if (fd != -1) + close (fd); } else if (!is_daemon) { @@ -623,87 +631,17 @@ main (int argc, char **argv ) " to run the program in the background\n")); } else - { /* regular server mode */ + { /* Regular server mode */ int fd; pid_t pid; int i; - int len; - struct sockaddr_un serv_addr; - char *p; - - /* fixme: if there is already a running gpg-agent we should - share the same directory - and vice versa */ - *socket_name = 0; - snprintf (socket_name, DIM(socket_name)-1, - "/tmp/gpg-XXXXXX/S.scdaemon"); - socket_name[DIM(socket_name)-1] = 0; - p = strrchr (socket_name, '/'); - if (!p) - BUG (); - *p = 0;; - -#ifndef HAVE_W32_SYSTEM - if (!mkdtemp(socket_name)) - { - log_error ("can't create directory `%s': %s\n", - socket_name, strerror(errno) ); - exit (1); - } -#endif - *p = '/'; - - if (strchr (socket_name, ':') ) - { - log_error ("colons are not allowed in the socket name\n"); - exit (1); - } - if (strlen (socket_name)+1 >= sizeof serv_addr.sun_path ) - { - log_error ("name of socket to long\n"); - exit (1); - } - - -#ifdef HAVE_W32_SYSTEM - fd = _w32_sock_new (AF_UNIX, SOCK_STREAM, 0); -#else - fd = socket (AF_UNIX, SOCK_STREAM, 0); -#endif - if (fd == -1) - { - log_error ("can't create socket: %s\n", strerror(errno) ); - exit (1); - } - - memset (&serv_addr, 0, sizeof serv_addr); - serv_addr.sun_family = AF_UNIX; - strcpy (serv_addr.sun_path, socket_name); - len = (offsetof (struct sockaddr_un, sun_path) - + strlen(serv_addr.sun_path) + 1); - if ( -#ifdef HAVE_W32_SYSTEM - _w32_sock_bind -#else - bind -#endif - (fd, (struct sockaddr*)&serv_addr, len) == -1) - { - log_error ("error binding socket to `%s': %s\n", - serv_addr.sun_path, strerror (errno) ); - close (fd); - exit (1); - } - - if (listen (fd, 5 ) == -1) - { - log_error ("listen() failed: %s\n", strerror (errno)); - close (fd); - exit (1); - } + /* Create the socket. */ + socket_name = create_socket_name (0, + "S.scdaemon", + "/tmp/gpg-XXXXXX/S.scdaemon"); - if (opt.verbose) - log_info ("listening on socket `%s'\n", socket_name ); + fd = create_server_socket (0, socket_name); fflush (NULL); @@ -746,7 +684,7 @@ main (int argc, char **argv ) } else { - /* print the environment string, so that the caller can use + /* Print the environment string, so that the caller can use shell's eval to set it */ if (csh_style) { @@ -763,14 +701,15 @@ main (int argc, char **argv ) /* NOTREACHED */ } /* end parent */ - /* this is the child */ + /* This is the child. */ - /* detach from tty and put process into a new session */ + /* Detach from tty and put process into a new session. */ if (!nodetach ) - { /* close stdin, stdout and stderr unless it is the log stream */ + { + /* Close stdin, stdout and stderr unless it is the log stream. */ for (i=0; i <= 2; i++) { - if ( log_get_fd () != i) + if ( log_test_fd (i) && i != fd) close (i); } if (setsid() == -1) @@ -781,23 +720,13 @@ main (int argc, char **argv ) } } - /* setup signals */ { - struct sigaction oact, nact; + struct sigaction sa; - nact.sa_handler = cleanup_sh; - sigemptyset (&nact.sa_mask); - nact.sa_flags = 0; - - sigaction (SIGHUP, NULL, &oact); - if (oact.sa_handler != SIG_IGN) - sigaction (SIGHUP, &nact, NULL); - sigaction( SIGTERM, NULL, &oact ); - if (oact.sa_handler != SIG_IGN) - sigaction (SIGTERM, &nact, NULL); - nact.sa_handler = SIG_IGN; - sigaction (SIGPIPE, &nact, NULL); - sigaction (SIGINT, &nact, NULL); + sa.sa_handler = SIG_IGN; + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + sigaction (SIGPIPE, &sa, NULL); } if (chdir("/")) @@ -808,7 +737,7 @@ main (int argc, char **argv ) #endif /*!HAVE_W32_SYSTEM*/ - scd_command_handler (fd); + handle_connections (fd); close (fd); } @@ -840,13 +769,22 @@ scd_exit (int rc) void -scd_init_default_ctrl (CTRL ctrl) +scd_init_default_ctrl (ctrl_t ctrl) { ctrl->reader_slot = -1; } -#ifdef USE_GNU_PTH +/* Return the name of the socket to be used to connect to this + process. If no socket is available, return NULL. */ +const char * +scd_get_socket_name () +{ + if (socket_name && *socket_name) + return socket_name; + return NULL; +} + static void handle_signal (int signo) @@ -897,18 +835,175 @@ handle_signal (int signo) } } + static void handle_tick (void) { scd_update_reader_status_file (); } + +/* Create a name for the socket. With USE_STANDARD_SOCKET given as + true using STANDARD_NAME in the home directory or if given has + false from the mkdir type name TEMPLATE. In the latter case a + unique name in a unique new directory will be created. In both + cases check for valid characters as well as against a maximum + allowed length for a unix domain socket is done. The function + terminates the process in case of an error. Retunrs: Pointer to an + allcoated string with the absolute name of the socket used. */ +static char * +create_socket_name (int use_standard_socket, + char *standard_name, char *template) +{ + char *name, *p; + + if (use_standard_socket) + name = make_filename (opt.homedir, standard_name, NULL); + else + { + name = xstrdup (template); + p = strrchr (name, '/'); + if (!p) + BUG (); + *p = 0; + if (!mkdtemp (name)) + { + log_error (_("can't create directory `%s': %s\n"), + name, strerror (errno)); + scd_exit (2); + } + *p = '/'; + } + + if (strchr (name, PATHSEP_C)) + { + log_error (("`%s' are not allowed in the socket name\n"), PATHSEP_S); + scd_exit (2); + } + if (strlen (name) + 1 >= DIMof (struct sockaddr_un, sun_path) ) + { + log_error (_("name of socket too long\n")); + scd_exit (2); + } + return name; +} + + + +/* Create a Unix domain socket with NAME. IS_STANDARD_NAME indicates + whether a non-random socket is used. Returns the file descriptor + or terminates the process in case of an error. */ +static int +create_server_socket (int is_standard_name, const char *name) +{ + struct sockaddr_un *serv_addr; + socklen_t len; + int fd; + int rc; + +#ifdef HAVE_W32_SYSTEM + fd = _w32_sock_new (AF_UNIX, SOCK_STREAM, 0); +#else + fd = socket (AF_UNIX, SOCK_STREAM, 0); +#endif + if (fd == -1) + { + log_error (_("can't create socket: %s\n"), strerror (errno)); + scd_exit (2); + } + + serv_addr = xmalloc (sizeof (*serv_addr)); + memset (serv_addr, 0, sizeof *serv_addr); + serv_addr->sun_family = AF_UNIX; + assert (strlen (name) + 1 < sizeof (serv_addr->sun_path)); + strcpy (serv_addr->sun_path, name); + len = (offsetof (struct sockaddr_un, sun_path) + + strlen (serv_addr->sun_path) + 1); + +#ifdef HAVE_W32_SYSTEM + rc = _w32_sock_bind (fd, (struct sockaddr*) serv_addr, len); + if (is_standard_name && rc == -1 ) + { + remove (name); + rc = bind (fd, (struct sockaddr*) serv_addr, len); + } +#else + rc = bind (fd, (struct sockaddr*) serv_addr, len); + if (is_standard_name && rc == -1 && errno == EADDRINUSE) + { + remove (name); + rc = bind (fd, (struct sockaddr*) serv_addr, len); + } +#endif + if (rc == -1) + { + log_error (_("error binding socket to `%s': %s\n"), + serv_addr->sun_path, strerror (errno)); + close (fd); + scd_exit (2); + } + + if (listen (fd, 5 ) == -1) + { + log_error (_("listen() failed: %s\n"), strerror (errno)); + close (fd); + scd_exit (2); + } + + if (opt.verbose) + log_info (_("listening on socket `%s'\n"), serv_addr->sun_path); + + return fd; +} + + + +/* This is the standard connection thread's main function. */ static void * -ticker_thread (void *dummy_arg) +start_connection_thread (void *arg) { - pth_event_t sigs_ev, time_ev = NULL; + int fd = (int)arg; + + if (opt.verbose) + log_info (_("handler for fd %d started\n"), fd); + + scd_command_handler (fd); + + if (opt.verbose) + log_info (_("handler for fd %d terminated\n"), fd); + + /* If this thread is the pipe connection thread, flag that a + shutdown is required. With the next ticker event and given that + no other connections are running the shutdown will then + happen. */ + if (fd == -1) + shutdown_pending = 1; + + return NULL; +} + + +/* Connection handler loop. Wait for connection requests and spawn a + thread after accepting a connection. LISTEN_FD is allowed to be -1 + in which case this code will only do regular timeouts and handle + signals. */ +static void +handle_connections (int listen_fd) +{ + pth_attr_t tattr; + pth_event_t ev, time_ev; sigset_t sigs; int signo; + struct sockaddr_un paddr; + socklen_t plen; + fd_set fdset, read_fdset; + int ret; + int fd; + + tattr = pth_attr_new(); + pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0); + pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 512*1024); + pth_attr_set (tattr, PTH_ATTR_NAME, "scd-connections"); #ifndef HAVE_W32_SYSTEM /* fixme */ sigemptyset (&sigs ); @@ -917,43 +1012,101 @@ ticker_thread (void *dummy_arg) sigaddset (&sigs, SIGUSR2); sigaddset (&sigs, SIGINT); sigaddset (&sigs, SIGTERM); - sigs_ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo); + ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo); #else - sigs_ev = NULL; + ev = NULL; #endif - - while (!shutdown_pending) + time_ev = NULL; + + FD_ZERO (&fdset); + if (listen_fd != -1) + FD_SET (listen_fd, &fdset); + + for (;;) { - if (!time_ev) + if (shutdown_pending) { - time_ev = pth_event (PTH_EVENT_TIME, pth_timeout (2, 0)); - if (time_ev) - pth_event_concat (sigs_ev, time_ev, NULL); - } + if (pth_ctrl (PTH_CTRL_GETTHREADS) == 1) + break; /* ready */ + + /* Do not accept anymore connections but wait for existing + connections to terminate. We do this by clearing out all + file descriptors to wait for, so that the select will be + used to just wait on a signal or timeout event. */ + FD_ZERO (&fdset); + } - if (pth_wait (sigs_ev) < 1) - continue; + /* Create a timeout event if needed. */ + if (!time_ev) + time_ev = pth_event (PTH_EVENT_TIME, pth_timeout (2, 0)); + + /* POSIX says that fd_set should be implemented as a structure, + thus a simple assignment is fine to copy the entire set. */ + read_fdset = fdset; + + if (time_ev) + pth_event_concat (ev, time_ev, NULL); + ret = pth_select_ev (FD_SETSIZE, &read_fdset, NULL, NULL, NULL, ev); + if (time_ev) + pth_event_isolate (time_ev); + + if (ret == -1) + { + if (pth_event_occurred (ev) + || (time_ev && pth_event_occurred (time_ev))) + { + if (pth_event_occurred (ev)) + handle_signal (signo); + if (time_ev && pth_event_occurred (time_ev)) + { + pth_event_free (time_ev, PTH_FREE_ALL); + time_ev = NULL; + handle_tick (); + } + continue; + } + log_error (_("pth_select failed: %s - waiting 1s\n"), + strerror (errno)); + pth_sleep (1); + continue; + } - if ( -#ifdef PTH_STATUS_OCCURRED /* This is Pth 2 */ - pth_event_status (sigs_ev) == PTH_STATUS_OCCURRED -#else - pth_event_occurred (sigs_ev) -#endif - ) - handle_signal (signo); + if (pth_event_occurred (ev)) + { + handle_signal (signo); + } - /* Always run the ticker. */ - if (!shutdown_pending) + if (time_ev && pth_event_occurred (time_ev)) { - pth_event_isolate (sigs_ev); pth_event_free (time_ev, PTH_FREE_ALL); time_ev = NULL; handle_tick (); } + + if (listen_fd != -1 && FD_ISSET (listen_fd, &read_fdset)) + { + plen = sizeof paddr; + fd = pth_accept (listen_fd, (struct sockaddr *)&paddr, &plen); + if (fd == -1) + { + log_error ("accept failed: %s\n", strerror (errno)); + } + else if (!pth_spawn (tattr, start_connection_thread, (void*)fd)) + { + log_error ("error spawning connection handler: %s\n", + strerror (errno) ); + close (fd); + } + fd = -1; + } + } - pth_event_free (sigs_ev, PTH_FREE_ALL); - return NULL; + pth_event_free (ev, PTH_FREE_ALL); + if (time_ev) + pth_event_free (time_ev, PTH_FREE_ALL); + cleanup (); + log_info (_("%s %s stopped\n"), strusage(11), strusage(13)); } -#endif /*USE_GNU_PTH*/ + + diff --git a/scd/scdaemon.h b/scd/scdaemon.h index 5e49f3ae5..eaa9abd35 100644 --- a/scd/scdaemon.h +++ b/scd/scdaemon.h @@ -99,7 +99,8 @@ typedef struct app_ctx_s *app_t; /*-- scdaemon.c --*/ void scd_exit (int rc); -void scd_init_default_ctrl (CTRL ctrl); +void scd_init_default_ctrl (ctrl_t ctrl); +const char *scd_get_socket_name (void); /*-- command.c --*/ void scd_command_handler (int); diff --git a/tools/gpg-connect-agent.c b/tools/gpg-connect-agent.c index 6372954f6..403fa2c45 100644 --- a/tools/gpg-connect-agent.c +++ b/tools/gpg-connect-agent.c @@ -39,6 +39,7 @@ enum cmd_and_opt_values aNull = 0, oQuiet = 'q', oVerbose = 'v', + oRawSocket = 'S', oNoVerbose = 500, oHomedir, @@ -55,6 +56,7 @@ static ARGPARSE_OPTS opts[] = { oVerbose, "verbose", 0, N_("verbose") }, { oQuiet, "quiet", 0, N_("quiet") }, { oHex, "hex", 0, N_("print data out hex encoded") }, + { oRawSocket, "raw-socket", 2, N_("|NAME|connect to Assuan socket NAME")}, /* hidden options */ { oNoVerbose, "no-verbose", 0, "@"}, @@ -70,6 +72,7 @@ struct int quiet; /* Be extra quiet. */ const char *homedir; /* Configuration directory name */ int hex; /* Print data lines in hex format. */ + const char *raw_socket; /* Name of socket to connect in raw mode. */ } opt; @@ -159,6 +162,7 @@ main (int argc, char **argv) case oNoVerbose: opt.verbose = 0; break; case oHomedir: opt.homedir = pargs.r.ret_str; break; case oHex: opt.hex = 1; break; + case oRawSocket: opt.raw_socket = pargs.r.ret_str; break; default: pargs.err = 2; break; } @@ -169,7 +173,21 @@ main (int argc, char **argv) fname = argc ? *argv : NULL; - ctx = start_agent (); + if (opt.raw_socket) + { + rc = assuan_socket_connect (&ctx, opt.raw_socket, 0); + if (rc) + { + log_error ("can't connect to socket `%s': %s\n", + opt.raw_socket, assuan_strerror (rc)); + exit (1); + } + + if (opt.verbose) + log_info ("connection to socket `%s' established\n", opt.raw_socket); + } + else + ctx = start_agent (); line = NULL; linesize = 0; for (;;) -- cgit From 41862f5f13bef8113cf040ecaba34a35c370eeb3 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 20 May 2005 20:39:36 +0000 Subject: * protect-tool.c: New option --canonical. (show_file): Implement it. * keyformat.txt: Define the created-at attribute for keys. * ccid-driver.c: Replaced macro DEBUG_T1 by a new debug level. (parse_ccid_descriptor): Mark SCR335 firmware version 5.18 good. (ccid_transceive): Arghhh. The seqno is another bit in the R-block than in the I block, this was wrong at one place. * scdaemon.c: New options --debug-ccid-driver and --debug-disable-ticker. * app-openpgp.c (do_genkey, do_writekey): Factored code to check for existing key out into .. (does_key_exist): .. New function. * gpg-connect-agent.c (add_definq, show_definq, clear_definq) (handle_inquire): New. (read_and_print_response): Handle INQUIRE command. (main): Implement control commands. --- agent/ChangeLog | 7 + agent/call-scd.c | 7 +- agent/keyformat.txt | 9 +- agent/protect-tool.c | 23 ++- agent/protect.c | 2 +- doc/scdaemon.texi | 50 ++++++- scd/ChangeLog | 27 ++++ scd/app-common.h | 28 +++- scd/app-openpgp.c | 355 +++++++++++++++++++++++++++++++++++++++++----- scd/app.c | 29 ++++ scd/ccid-driver.c | 104 +++++++------- scd/command.c | 81 ++++++++++- scd/scdaemon.c | 33 +++-- scd/tlv.c | 73 ++++++++++ scd/tlv.h | 17 +++ tools/ChangeLog | 9 +- tools/gpg-connect-agent.c | 223 ++++++++++++++++++++++++++++- 17 files changed, 961 insertions(+), 116 deletions(-) (limited to 'scd/app-openpgp.c') diff --git a/agent/ChangeLog b/agent/ChangeLog index 00f019ddc..015b0b6d8 100644 --- a/agent/ChangeLog +++ b/agent/ChangeLog @@ -1,3 +1,10 @@ +2005-05-20 Werner Koch + + * protect-tool.c: New option --canonical. + (show_file): Implement it. + + * keyformat.txt: Define the created-at attribute for keys. + 2005-05-18 Werner Koch * divert-scd.c (ask_for_card): Removed the card reset kludge. diff --git a/agent/call-scd.c b/agent/call-scd.c index 58dd412f0..fc81e2fa3 100644 --- a/agent/call-scd.c +++ b/agent/call-scd.c @@ -158,7 +158,7 @@ start_scd (ctrl_t ctrl) gpg_error_t err = 0; const char *pgmname; assuan_context_t ctx; - const char *argv[4]; + const char *argv[3]; int no_close_list[3]; int i; int rc; @@ -266,9 +266,8 @@ start_scd (ctrl_t ctrl) pgmname++; argv[0] = pgmname; - argv[1] = "--server"; - argv[2] = "--multi-server"; - argv[3] = NULL; + argv[1] = "--multi-server"; + argv[2] = NULL; i=0; if (!opt.running_detached) diff --git a/agent/keyformat.txt b/agent/keyformat.txt index 7bdb94c0e..2fa53adba 100644 --- a/agent/keyformat.txt +++ b/agent/keyformat.txt @@ -30,12 +30,17 @@ Libgcrypt. Here is an example of an unprotected file: (q #00f7a7c..[some bytes not shown]..61#) (u #304559a..[some bytes not shown]..9b#) ) + (created-at timestamp) (uri http://foo.bar x-foo:whatever_you_want) (comment whatever) ) -"comment" and "uri" are optional. "comment" is currently used to keep -track of ssh key comments. +"comment", "created-at" and "uri" are optional. "comment" is +currently used to keep track of ssh key comments. "created-at" is used +to keep track of the creation time stamp used with OpenPGP keys; it is +optional but required for some operations to calculate the fingerprint +of the key. This timestamp should be a string with the number of +seconds since Epoch or an ISO time string (yyyymmddThhmmss). Actually this form should not be used for regular purposes and only accepted by gpg-agent with the configuration option: diff --git a/agent/protect-tool.c b/agent/protect-tool.c index c21aa0517..e8f1d2c10 100644 --- a/agent/protect-tool.c +++ b/agent/protect-tool.c @@ -60,6 +60,7 @@ enum cmd_and_opt_values oShadow, oShowShadowInfo, oShowKeygrip, + oCanonical, oP12Import, oP12Export, @@ -86,6 +87,7 @@ struct rsa_secret_key_s static const char *opt_homedir; static int opt_armor; +static int opt_canonical; static int opt_store; static int opt_force; static int opt_no_fail_on_exist; @@ -107,6 +109,7 @@ static ARGPARSE_OPTS opts[] = { { oVerbose, "verbose", 0, "verbose" }, { oArmor, "armor", 0, "write output in advanced format" }, + { oCanonical, "canonical", 0, "write output in canonical format" }, { oPassphrase, "passphrase", 2, "|STRING|use passphrase STRING" }, { oProtect, "protect", 256, "protect a private key"}, { oUnprotect, "unprotect", 256, "unprotect a private key"}, @@ -508,14 +511,21 @@ show_file (const char *fname) keylen = gcry_sexp_canon_len (key, 0, NULL,NULL); assert (keylen); - - p = make_advanced (key, keylen); - xfree (key); - if (p) + + if (opt_canonical) { - fwrite (p, strlen (p), 1, stdout); - xfree (p); + fwrite (key, keylen, 1, stdout); } + else + { + p = make_advanced (key, keylen); + if (p) + { + fwrite (p, strlen (p), 1, stdout); + xfree (p); + } + } + xfree (key); } static void @@ -1079,6 +1089,7 @@ main (int argc, char **argv ) { case oVerbose: opt.verbose++; break; case oArmor: opt_armor=1; break; + case oCanonical: opt_canonical=1; break; case oHomedir: opt_homedir = pargs.r.ret_str; break; case oProtect: cmd = oProtect; break; diff --git a/agent/protect.c b/agent/protect.c index ae3061c77..658c8c529 100644 --- a/agent/protect.c +++ b/agent/protect.c @@ -60,7 +60,7 @@ hash_passphrase (const char *passphrase, int hashalgo, -/* Calculate the MIC for a private key S-Exp. SHA1HASH should pint to +/* Calculate the MIC for a private key S-Exp. SHA1HASH should point to a 20 byte buffer. This function is suitable for any algorithms. */ static int calculate_mic (const unsigned char *plainkey, unsigned char *sha1hash) diff --git a/doc/scdaemon.texi b/doc/scdaemon.texi index 971234e52..f069a9fb8 100644 --- a/doc/scdaemon.texi +++ b/doc/scdaemon.texi @@ -54,6 +54,12 @@ abbreviate this command. Run in server mode and wait for commands on the @code{stdin}. This is default mode is to create a socket and listen for commands there. +@item --multi-server +@opindex multi-server +Run in server mode and wait for commands on the @code{stdin} as well as +on an additional Unix Domain socket. The server command @code{GETINFO} +may be used to get the name of that extra socket. + @item --daemon @opindex daemon Run the program in the background. This option is required to prevent @@ -120,6 +126,13 @@ How these messages are mapped to the actual debugging flags is not specified and may change with newer releaes of this program. They are however carefully selected to best aid in debugging. +@quotation Note +All debugging options are subject to change and thus should not be used +by any application program. As the name says, they are only used as +helpers to debug problems. +@end quotation + + @item --debug @var{flags} @opindex debug This option is only useful for debugging and the behaviour may change at @@ -128,7 +141,7 @@ usual C-Syntax. The currently defined bits are: @table @code @item 0 (1) - X.509 or OpenPGP protocol related data + command I/O @item 1 (2) values of big number integers @item 2 (4) @@ -143,8 +156,8 @@ usual C-Syntax. The currently defined bits are: write hashed data to files named @code{dbgmd-000*} @item 10 (1024) trace Assuan protocol - @item 12 (4096) - bypass all certificate validation + @item 11 (2048) + trace APDU I/O to the card. This may reveal sensitive data. @end table @item --debug-all @@ -157,6 +170,17 @@ When running in server mode, wait @var{n} seconds before entering the actual processing loop and print the pid. This gives time to attach a debugger. +@item --debug-ccid-driver +@opindex debug-wait +Enable debug output from the included CCID driver for smartcards. +Using this option twice will also enable some tracing of the T=1 +protocol. Note that this option may reveal sensitive data. + +@item --debug-disable-ticker +@opindex debug-disable-ticker +This option disables all ticker functions like checking for card +insertions. + @item --no-detach @opindex no-detach Don't detach the process from the console. This is manly usefule for @@ -286,6 +310,7 @@ syncronizing access to a token between sessions. * Scdaemon PKDECRYPT:: Decrypting data with a Smartcard. * Scdaemon GETATTR:: Read an attribute's value. * Scdaemon SETATTR:: Update an attribute's value. +* Scdaemon WRITEKEY:: Write a key to a card. * Scdaemon GENKEY:: Generate a new key on-card. * Scdaemon RANDOM:: Return random bytes generate on-card. * Scdaemon PASSWD:: Change PINs. @@ -420,6 +445,25 @@ TO BE WRITTEN. TO BE WRITTEN. +@node Scdaemon WRITEKEY +@subsection Write a key to a card. + +@example + WRITEKEY [--force] @var{keyid} +@end example + +This command is used to store a secret key on a a smartcard. The +allowed keyids depend on the currently selected smartcard +application. The actual keydata is requested using the inquiry +@code{KEYDATA} and need to be provided without any protection. With +@option{--force} set an existing key under this @var{keyid} will get +overwritten. The key data is expected to be the usual canonical encoded +S-expression. + +A PIN will be requested in most saes. This however depends on the +actual card application. + + @node Scdaemon GENKEY @subsection Generate a new key on-card. diff --git a/scd/ChangeLog b/scd/ChangeLog index 19bba2bf4..c64fbec7e 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,30 @@ +2005-05-20 Werner Koch + + * ccid-driver.c: Replaced macro DEBUG_T1 by a new debug level. + (parse_ccid_descriptor): Mark SCR335 firmware version 5.18 good. + (ccid_transceive): Arghhh. The seqno is another bit in the + R-block than in the I block, this was wrong at one place. + + * scdaemon.c: New options --debug-ccid-driver and + --debug-disable-ticker. + + * app-openpgp.c (do_genkey, do_writekey): Factored code to check + for existing key out into .. + (does_key_exist): .. New function. + +2005-05-19 Werner Koch + + * tlv.c (parse_sexp): New. + + * command.c (cmd_writekey): New. + * app.c (app_writekey): New. + * app-common.c (app_t): Add function ptr WRITEKEY. + * app-openpgp.c (do_writekey): New. + + * app-openpgp.c (do_readkey) [GNUPG_MAJOR_VERSION==1]: Return error. + * app-common.h (app_t) [GNUPG_MAJOR_VERSION==1]: Add a field to + store the Assuan context. + 2005-05-17 Werner Koch * scdaemon.c: Removed non-pth code paths. diff --git a/scd/app-common.h b/scd/app-common.h index 517286c49..c2c302395 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -23,10 +23,15 @@ #ifndef GNUPG_SCD_APP_COMMON_H #define GNUPG_SCD_APP_COMMON_H -#if GNUPG_MAJOR_VERSION != 1 -#include +#if GNUPG_MAJOR_VERSION == 1 +# ifdef ENABLE_AGENT_SUPPORT +# include "assuan.h" +# endif +#else +# include #endif + struct app_local_s; /* Defined by all app-*.c. */ struct app_ctx_s { @@ -35,6 +40,15 @@ struct app_ctx_s { unsupported operations the particular function pointer is set to NULL */ int slot; /* Used reader. */ + + /* If this is used by GnuPG 1.4 we need to know the assuan context + in case we need to divert the operation to an already running + agent. This if ASSUAN_CTX is not NULL we take this as indication + that all operations are diverted to gpg-agent. */ +#if GNUPG_MAJOR_VERSION == 1 && defined(ENABLE_AGENT_SUPPORT) + assuan_context_t assuan_ctx; +#endif /*GNUPG_MAJOR_VERSION == 1*/ + unsigned char *serialno; /* Serialnumber in raw form, allocated. */ size_t serialnolen; /* Length in octets of serialnumber. */ const char *apptype; @@ -72,6 +86,11 @@ struct app_ctx_s { void *pincb_arg, const void *indata, size_t indatalen, unsigned char **outdata, size_t *outdatalen); + gpg_error_t (*writekey) (app_t app, ctrl_t ctrl, + const char *certid, unsigned int flags, + gpg_error_t (*pincb)(void*,const char *,char **), + void *pincb_arg, + const unsigned char *pk, size_t pklen); gpg_error_t (*genkey) (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags, gpg_error_t (*pincb)(void*, const char *, char **), @@ -134,6 +153,11 @@ gpg_error_t app_decipher (app_t app, const char *keyidstr, void *pincb_arg, const void *indata, size_t indatalen, unsigned char **outdata, size_t *outdatalen ); +gpg_error_t app_writekey (app_t app, ctrl_t ctrl, + const char *keyidstr, unsigned int flags, + gpg_error_t (*pincb)(void*, const char *, char **), + void *pincb_arg, + const unsigned char *keydata, size_t keydatalen); gpg_error_t app_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags, gpg_error_t (*pincb)(void*, const char *, char **), diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index b8060df03..16ebd34c8 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -565,7 +565,7 @@ store_fpr (int slot, int keynumber, u32 timestamp, n = 6 + 2 + mlen + 2 + elen; p = buffer = xtrymalloc (3 + n); if (!buffer) - return gpg_error (gpg_err_code_from_errno (errno)); + return gpg_error_from_errno (errno); *p++ = 0x99; /* ctb */ *p++ = n >> 8; /* 2 byte length header */ @@ -1207,6 +1207,7 @@ do_learn_status (app_t app, ctrl_t ctrl) static gpg_error_t do_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen) { +#if GNUPG_MAJOR_VERSION > 1 gpg_error_t err; int keyno; unsigned char *buf; @@ -1230,6 +1231,9 @@ do_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen) *pk = buf; *pklen = app->app_local->pk[keyno-1].keylen;; return 0; +#else + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); +#endif } @@ -1523,6 +1527,318 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, int reset_mode, } +/* Check whether a key already exists. KEYIDX is the index of the key + (0..2). If FORCE is TRUE a diagnositivc will be printed but no + error returned if the key already exists. */ +static gpg_error_t +does_key_exist (app_t app, int keyidx, int force) +{ + const unsigned char *fpr; + unsigned char *buffer; + size_t buflen, n; + int i; + + assert (keyidx >=0 && keyidx <= 2); + + if (iso7816_get_data (app->slot, 0x006E, &buffer, &buflen)) + { + log_error (_("error reading application data\n")); + return gpg_error (GPG_ERR_GENERAL); + } + fpr = find_tlv (buffer, buflen, 0x00C5, &n); + if (!fpr || n < 60) + { + log_error (_("error reading fingerprint DO\n")); + xfree (buffer); + return gpg_error (GPG_ERR_GENERAL); + } + fpr += 20*keyidx; + for (i=0; i < 20 && !fpr[i]; i++) + ; + xfree (buffer); + if (i!=20 && !force) + { + log_error (_("key already exists\n")); + return gpg_error (GPG_ERR_EEXIST); + } + else if (i!=20) + log_info (_("existing key will be replaced\n")); + else + log_info (_("generating new key\n")); + return 0; +} + + + +/* Handle the WRITEKEY command for OpenPGP. This function expects a + canonical encoded S-expression with the secret key in KEYDATA and + its length (for assertions) in KEYDATALEN. KEYID needs to be the + usual keyid which for OpenPGP is the string "OPENPGP.n" with + n=1,2,3. Bit 0 of FLAGS indicates whether an existing key shall + get overwritten. PINCB and PINCB_ARG are the usual arguments for + the pinentry callback. */ +static gpg_error_t +do_writekey (app_t app, ctrl_t ctrl, + const char *keyid, unsigned int flags, + gpg_error_t (*pincb)(void*, const char *, char **), + void *pincb_arg, + const unsigned char *keydata, size_t keydatalen) +{ + gpg_error_t err; + int force = (flags & 1); + int keyno; + const unsigned char *buf, *tok; + size_t buflen, toklen; + int depth, last_depth1, last_depth2; + const unsigned char *rsa_n = NULL; + const unsigned char *rsa_e = NULL; + const unsigned char *rsa_p = NULL; + const unsigned char *rsa_q = NULL; + size_t rsa_n_len, rsa_e_len, rsa_p_len, rsa_q_len; + unsigned int nbits; + unsigned char *template = NULL; + unsigned char *tp; + size_t template_len; + unsigned char fprbuf[20]; + u32 created_at = 0; + + if (!strcmp (keyid, "OPENPGP.1")) + keyno = 0; + else if (!strcmp (keyid, "OPENPGP.2")) + keyno = 1; + else if (!strcmp (keyid, "OPENPGP.3")) + keyno = 2; + else + return gpg_error (GPG_ERR_INV_ID); + + err = does_key_exist (app, keyno, force); + if (err) + return err; + + + /* + Parse the S-expression + */ + buf = keydata; + buflen = keydatalen; + depth = 0; + if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) + goto leave; + if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) + goto leave; + if (!tok || toklen != 11 || memcmp ("private-key", tok, toklen)) + { + if (!tok) + ; + else if (toklen == 21 && !memcmp ("protected-private-key", tok, toklen)) + log_info ("protected-private-key passed to writekey\n"); + else if (toklen == 20 && !memcmp ("shadowed-private-key", tok, toklen)) + log_info ("shadowed-private-key passed to writekey\n"); + err = gpg_error (GPG_ERR_BAD_KEY); + goto leave; + } + if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) + goto leave; + if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) + goto leave; + if (!tok || toklen != 3 || memcmp ("rsa", tok, toklen)) + { + err = gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO); + goto leave; + } + last_depth1 = depth; + while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)) + && depth && depth >= last_depth1) + { + if (tok) + { + err = gpg_error (GPG_ERR_UNKNOWN_SEXP); + goto leave; + } + if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) + goto leave; + if (tok && toklen == 1) + { + const unsigned char **mpi; + size_t *mpi_len; + + switch (*tok) + { + case 'n': mpi = &rsa_n; mpi_len = &rsa_n_len; break; + case 'e': mpi = &rsa_e; mpi_len = &rsa_e_len; break; + case 'p': mpi = &rsa_p; mpi_len = &rsa_p_len; break; + case 'q': mpi = &rsa_q; mpi_len = &rsa_q_len;break; + default: mpi = NULL; mpi_len = NULL; break; + } + if (mpi && *mpi) + { + err = gpg_error (GPG_ERR_DUP_VALUE); + goto leave; + } + if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) + goto leave; + if (tok && mpi) + { + /* Strip off leading zero bytes and save. */ + for (;toklen && !*tok; toklen--, tok++) + ; + *mpi = tok; + *mpi_len = toklen; + } + } + /* Skip until end of list. */ + last_depth2 = depth; + while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)) + && depth && depth >= last_depth2) + ; + if (err) + goto leave; + } + /* Parse other attributes. */ + last_depth1 = depth; + while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)) + && depth && depth >= last_depth1) + { + if (tok) + { + err = gpg_error (GPG_ERR_UNKNOWN_SEXP); + goto leave; + } + if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) + goto leave; + if (tok && toklen == 10 && !memcmp ("created-at", tok, toklen)) + { + if ((err = parse_sexp (&buf,&buflen,&depth,&tok,&toklen))) + goto leave; + if (tok) + { + for (created_at=0; toklen && *tok && *tok >= '0' && *tok <= '9'; + tok++, toklen--) + created_at = created_at*10 + (*tok - '0'); + } + } + /* Skip until end of list. */ + last_depth2 = depth; + while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)) + && depth && depth >= last_depth2) + ; + if (err) + goto leave; + } + + + /* Check that we have all parameters and that they match the card + description. */ + if (!created_at) + { + log_error (_("creation timestamp missing\n")); + err = gpg_error (GPG_ERR_INV_VALUE); + goto leave; + } + nbits = rsa_n? count_bits (rsa_n, rsa_n_len) : 0; + if (nbits != 1024) + { + log_error (_("RSA modulus missing or not of size %d bits\n"), 1024); + err = gpg_error (GPG_ERR_BAD_SECKEY); + goto leave; + } + nbits = rsa_e? count_bits (rsa_e, rsa_e_len) : 0; + if (nbits < 2 || nbits > 32) + { + log_error (_("RSA public exponent missing or largerr than %d bits\n"), + 32); + err = gpg_error (GPG_ERR_BAD_SECKEY); + goto leave; + } + nbits = rsa_p? count_bits (rsa_p, rsa_p_len) : 0; + if (nbits != 512) + { + log_error (_("RSA prime %s missing or not of size %d bits\n"), "P", 512); + err = gpg_error (GPG_ERR_BAD_SECKEY); + goto leave; + } + nbits = rsa_q? count_bits (rsa_q, rsa_q_len) : 0; + if (nbits != 512) + { + log_error (_("RSA prime %s missing or not of size %d bits\n"), "Q", 512); + err = gpg_error (GPG_ERR_BAD_SECKEY); + goto leave; + } + + + /* Build the private key template as described in section 4.3.3.6 of + the OpenPGP card specs: + 0xC0 public exponent + 0xC1 prime p + 0xC2 prime q + */ + assert (rsa_e_len <= 4); + template_len = (1 + 1 + 4 + + 1 + 1 + rsa_p_len + + 1 + 1 + rsa_q_len); + template = tp = xtrymalloc_secure (template_len); + if (!template) + { + err = gpg_error_from_errno (errno); + goto leave; + } + *tp++ = 0xC0; + *tp++ = 4; + memcpy (tp, rsa_e, rsa_e_len); + if (rsa_e_len < 4) + { + /* Right justify E. */ + memmove (tp+4-rsa_e_len, tp, 4-rsa_e_len); + memset (tp, 0, 4-rsa_e_len); + } + tp += 4; + + *tp++ = 0xC1; + *tp++ = rsa_p_len; + memcpy (tp, rsa_p, rsa_p_len); + tp += rsa_p_len; + + *tp++ = 0xC2; + *tp++ = rsa_q_len; + memcpy (tp, rsa_q, rsa_q_len); + tp += rsa_q_len; + + assert (tp - template == template_len); + + + /* Obviously we need to remove the cached public key. */ + xfree (app->app_local->pk[keyno].key); + app->app_local->pk[keyno].key = NULL; + app->app_local->pk[keyno].keylen = 0; + app->app_local->pk[keyno].read_done = 0; + + /* Prepare for storing the key. */ + err = verify_chv3 (app, pincb, pincb_arg); + if (err) + goto leave; + + /* Store the key. */ + err = iso7816_put_data (app->slot, + (app->card_version > 0x0007? 0xE0 : 0xE9) + keyno, + template, template_len); + if (err) + { + log_error (_("failed to store the key: %s\n"), gpg_strerror (err)); + goto leave; + } + + err = store_fpr (app->slot, keyno, created_at, + rsa_n, rsa_n_len, rsa_e, rsa_e_len, + fprbuf, app->card_version); + if (err) + goto leave; + + + leave: + xfree (template); + return err; +} + /* Handle the GENKEY command. */ static gpg_error_t @@ -1531,13 +1847,11 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags, void *pincb_arg) { int rc; - int i; char numbuf[30]; unsigned char fprbuf[20]; - const unsigned char *fpr; const unsigned char *keydata, *m, *e; - unsigned char *buffer; - size_t buflen, keydatalen, n, mlen, elen; + unsigned char *buffer = NULL; + size_t buflen, keydatalen, mlen, elen; time_t created_at; int keyno = atoi (keynostr); int force = (flags & 1); @@ -1558,41 +1872,15 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags, app->app_local->pk[keyno].read_done = 0; /* Check whether a key already exists. */ - rc = iso7816_get_data (app->slot, 0x006E, &buffer, &buflen); + rc = does_key_exist (app, keyno, force); if (rc) - { - log_error (_("error reading application data\n")); - return gpg_error (GPG_ERR_GENERAL); - } - fpr = find_tlv (buffer, buflen, 0x00C5, &n); - if (!fpr || n != 60) - { - rc = gpg_error (GPG_ERR_GENERAL); - log_error (_("error reading fingerprint DO\n")); - goto leave; - } - fpr += 20*keyno; - for (i=0; i < 20 && !fpr[i]; i++) - ; - if (i!=20 && !force) - { - rc = gpg_error (GPG_ERR_EEXIST); - log_error (_("key already exists\n")); - goto leave; - } - else if (i!=20) - log_info (_("existing key will be replaced\n")); - else - log_info (_("generating new key\n")); + return rc; - /* Prepare for key generation by verifying the ADmin PIN. */ rc = verify_chv3 (app, pincb, pincb_arg); if (rc) goto leave; - xfree (buffer); buffer = NULL; - #if 1 log_info (_("please wait while key is being generated ...\n")); start_at = time (NULL); @@ -2216,6 +2504,7 @@ app_select_openpgp (app_t app) app->fnc.readkey = do_readkey; app->fnc.getattr = do_getattr; app->fnc.setattr = do_setattr; + app->fnc.writekey = do_writekey; app->fnc.genkey = do_genkey; app->fnc.sign = do_sign; app->fnc.auth = do_auth; diff --git a/scd/app.c b/scd/app.c index 0a1960267..f2c427f5b 100644 --- a/scd/app.c +++ b/scd/app.c @@ -546,6 +546,35 @@ app_decipher (app_t app, const char *keyidstr, } +/* Perform the WRITEKEY operation. */ +gpg_error_t +app_writekey (app_t app, ctrl_t ctrl, + const char *keyidstr, unsigned int flags, + gpg_error_t (*pincb)(void*, const char *, char **), + void *pincb_arg, + const unsigned char *keydata, size_t keydatalen) +{ + gpg_error_t err; + + if (!app || !keyidstr || !*keyidstr || !pincb) + return gpg_error (GPG_ERR_INV_VALUE); + if (!app->initialized) + return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); + if (!app->fnc.writekey) + return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); + err = lock_reader (app); + if (err) + return err; + err = app->fnc.writekey (app, ctrl, keyidstr, flags, + pincb, pincb_arg, keydata, keydatalen); + unlock_reader (app); + if (opt.verbose) + log_info ("operation writekey result: %s\n", gpg_strerror (err)); + return err; + +} + + /* Perform a SETATTR operation. */ gpg_error_t app_genkey (app_t app, CTRL ctrl, const char *keynostr, unsigned int flags, diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c index b817452b1..387108559 100644 --- a/scd/ccid-driver.c +++ b/scd/ccid-driver.c @@ -108,9 +108,6 @@ # include "scdaemon.h" #endif -/* Define to print information pertaining the T=1 protocol. */ -#undef DEBUG_T1 - # define DEBUGOUT(t) do { if (debug_level) \ log_debug (DRVNAME t); } while (0) @@ -120,6 +117,8 @@ log_debug (DRVNAME t,(a),(b)); } while (0) # define DEBUGOUT_3(t,a,b,c) do { if (debug_level) \ log_debug (DRVNAME t,(a),(b),(c));} while (0) +# define DEBUGOUT_4(t,a,b,c,d) do { if (debug_level) \ + log_debug (DRVNAME t,(a),(b),(c),(d));} while (0) # define DEBUGOUT_CONT(t) do { if (debug_level) \ log_printf (t); } while (0) # define DEBUGOUT_CONT_1(t,a) do { if (debug_level) \ @@ -141,6 +140,8 @@ fprintf (stderr, DRVNAME t, (a), (b)); } while (0) # define DEBUGOUT_3(t,a,b,c) do { if (debug_level) \ fprintf (stderr, DRVNAME t, (a), (b), (c)); } while (0) +# define DEBUGOUT_4(t,a,b,c,d) do { if (debug_level) \ + fprintf (stderr, DRVNAME t, (a), (b), (c), (d));} while(0) # define DEBUGOUT_CONT(t) do { if (debug_level) \ fprintf (stderr, t); } while (0) # define DEBUGOUT_CONT_1(t,a) do { if (debug_level) \ @@ -216,7 +217,11 @@ struct ccid_driver_s static int initialized_usb; /* Tracks whether USB has been initialized. */ -static int debug_level; /* Flag to control the debug output. */ +static int debug_level; /* Flag to control the debug output. + 0 = No debugging + 1 = USB I/O info + 2 = T=1 protocol tracing + */ static unsigned int compute_edc (const unsigned char *data, size_t datalen, @@ -457,7 +462,7 @@ parse_ccid_descriptor (ccid_driver_t handle, && handle->max_ifsd > 48 && ( (handle->id_product == 0xe001 && handle->bcd_device < 0x0516) ||(handle->id_product == 0x5111 && handle->bcd_device < 0x0620) - ||(handle->id_product == 0x5115 && handle->bcd_device < 0x0519) + ||(handle->id_product == 0x5115 && handle->bcd_device < 0x0518) ||(handle->id_product == 0xe003 && handle->bcd_device < 0x0504) )) { @@ -827,7 +832,8 @@ scan_or_find_devices (int readerno, const char *readerid, /* Set the level of debugging to to usea dn return the old level. -1 just returns the old level. A level of 0 disables debugging, 1 - enables debugging, other values are not yet defined. */ + enables debugging, 2 enables additional tracing of the T=1 + protocol, other values are not yet defined. */ int ccid_set_debug_level (int level) { @@ -1437,12 +1443,13 @@ ccid_get_atr (ccid_driver_t handle, DEBUGOUT_CONT_1 (" %02X", msg[i]); DEBUGOUT_LF (); -#ifdef DEBUG_T1 - fprintf (stderr, "T1: put %c-block seq=%d\n", - ((msg[11] & 0xc0) == 0x80)? 'R' : - (msg[11] & 0x80)? 'S' : 'I', - ((msg[11] & 0x80)? !!(msg[11]& 0x10) : !!(msg[11] & 0x40))); -#endif + if (debug_level > 1) + DEBUGOUT_3 ("T=1: put %c-block seq=%d%s\n", + ((msg[11] & 0xc0) == 0x80)? 'R' : + (msg[11] & 0x80)? 'S' : 'I', + ((msg[11] & 0x80)? !!(msg[11]& 0x10) + : !!(msg[11] & 0x40)), + (!(msg[11] & 0x80) && (msg[11] & 0x20)? " [more]":"")); rc = bulk_out (handle, msg, msglen); if (rc) @@ -1460,14 +1467,15 @@ ccid_get_atr (ccid_driver_t handle, if (tpdulen < 4) return CCID_DRIVER_ERR_ABORTED; -#ifdef DEBUG_T1 - fprintf (stderr, "T1: got %c-block seq=%d err=%d\n", - ((msg[11] & 0xc0) == 0x80)? 'R' : - (msg[11] & 0x80)? 'S' : 'I', - ((msg[11] & 0x80)? !!(msg[11]& 0x10) : !!(msg[11] & 0x40)), - ((msg[11] & 0xc0) == 0x80)? (msg[11] & 0x0f) : 0 - ); -#endif + if (debug_level > 1) + DEBUGOUT_4 ("T=1: got %c-block seq=%d err=%d%s\n", + ((msg[11] & 0xc0) == 0x80)? 'R' : + (msg[11] & 0x80)? 'S' : 'I', + ((msg[11] & 0x80)? !!(msg[11]& 0x10) + : !!(msg[11] & 0x40)), + ((msg[11] & 0xc0) == 0x80)? (msg[11] & 0x0f) : 0, + (!(msg[11] & 0x80) && (msg[11] & 0x20)? " [more]":"")); + if ((tpdu[1] & 0xe0) != 0xe0 || tpdu[2] != 1) { DEBUGOUT ("invalid response for S-block (Change-IFSD)\n"); @@ -1706,12 +1714,13 @@ ccid_transceive (ccid_driver_t handle, DEBUGOUT_CONT_1 (" %02X", msg[i]); DEBUGOUT_LF (); -#ifdef DEBUG_T1 - fprintf (stderr, "T1: put %c-block seq=%d\n", - ((msg[11] & 0xc0) == 0x80)? 'R' : - (msg[11] & 0x80)? 'S' : 'I', - ((msg[11] & 0x80)? !!(msg[11]& 0x10) : !!(msg[11] & 0x40))); -#endif + if (debug_level > 1) + DEBUGOUT_3 ("T=1: put %c-block seq=%d%s\n", + ((msg[11] & 0xc0) == 0x80)? 'R' : + (msg[11] & 0x80)? 'S' : 'I', + ((msg[11] & 0x80)? !!(msg[11]& 0x10) + : !!(msg[11] & 0x40)), + (!(msg[11] & 0x80) && (msg[11] & 0x20)? " [more]":"")); rc = bulk_out (handle, msg, msglen); if (rc) @@ -1731,14 +1740,14 @@ ccid_transceive (ccid_driver_t handle, usb_clear_halt (handle->idev, handle->ep_bulk_in); return CCID_DRIVER_ERR_ABORTED; } -#ifdef DEBUG_T1 - fprintf (stderr, "T1: got %c-block seq=%d err=%d\n", - ((msg[11] & 0xc0) == 0x80)? 'R' : - (msg[11] & 0x80)? 'S' : 'I', - ((msg[11] & 0x80)? !!(msg[11]& 0x10) : !!(msg[11] & 0x40)), - ((msg[11] & 0xc0) == 0x80)? (msg[11] & 0x0f) : 0 - ); -#endif + + if (debug_level > 1) + DEBUGOUT_4 ("T=1: got %c-block seq=%d err=%d%s\n", + ((msg[11] & 0xc0) == 0x80)? 'R' : + (msg[11] & 0x80)? 'S' : 'I', + ((msg[11] & 0x80)? !!(msg[11]& 0x10) : !!(msg[11] & 0x40)), + ((msg[11] & 0xc0) == 0x80)? (msg[11] & 0x0f) : 0, + (!(msg[11] & 0x80) && (msg[11] & 0x20)? " [more]":"")); if (!(tpdu[1] & 0x80)) { /* This is an I-block. */ @@ -1814,8 +1823,8 @@ ccid_transceive (ccid_driver_t handle, msg = send_buffer; tpdulen = last_tpdulen; } - else if (sending && !!(tpdu[1] & 0x40) == handle->t1_ns) - { /* Reponse does not match our sequence number. */ + else if (sending && !!(tpdu[1] & 0x10) == handle->t1_ns) + { /* Response does not match our sequence number. */ DEBUGOUT ("R-block with wrong seqno received on more bit\n"); return CCID_DRIVER_ERR_CARD_IO_ERROR; } @@ -1835,7 +1844,7 @@ ccid_transceive (ccid_driver_t handle, else { /* This is a S-block. */ retries = 0; - DEBUGOUT_2 ("T1 S-block %s received cmd=%d\n", + DEBUGOUT_2 ("T=1 S-block %s received cmd=%d\n", (tpdu[1] & 0x20)? "response": "request", (tpdu[1] & 0x1f)); if ( !(tpdu[1] & 0x20) && (tpdu[1] & 0x1f) == 3 && tpdu[2]) @@ -1853,7 +1862,7 @@ ccid_transceive (ccid_driver_t handle, if (use_crc) tpdu[tpdulen++] = (edc >> 8); tpdu[tpdulen++] = edc; - DEBUGOUT_1 ("T1 waittime extension of bwi=%d\n", bwi); + DEBUGOUT_1 ("T=1 waittime extension of bwi=%d\n", bwi); } else return CCID_DRIVER_ERR_CARD_IO_ERROR; @@ -2008,14 +2017,13 @@ ccid_transceive_secure (ccid_driver_t handle, usb_clear_halt (handle->idev, handle->ep_bulk_in); return CCID_DRIVER_ERR_ABORTED; } -#ifdef DEBUG_T1 - fprintf (stderr, "T1: got %c-block seq=%d err=%d\n", - ((msg[11] & 0xc0) == 0x80)? 'R' : - (msg[11] & 0x80)? 'S' : 'I', - ((msg[11] & 0x80)? !!(msg[11]& 0x10) : !!(msg[11] & 0x40)), - ((msg[11] & 0xc0) == 0x80)? (msg[11] & 0x0f) : 0 - ); -#endif + if (debug_level > 1) + DEBUGOUT_4 ("T=1: got %c-block seq=%d err=%d%s\n", + ((msg[11] & 0xc0) == 0x80)? 'R' : + (msg[11] & 0x80)? 'S' : 'I', + ((msg[11] & 0x80)? !!(msg[11]& 0x10) : !!(msg[11] & 0x40)), + ((msg[11] & 0xc0) == 0x80)? (msg[11] & 0x0f) : 0, + (!(msg[11] & 0x80) && (msg[11] & 0x20)? " [more]":"")); if (!(tpdu[1] & 0x80)) { /* This is an I-block. */ @@ -2062,7 +2070,7 @@ ccid_transceive_secure (ccid_driver_t handle, DEBUGOUT ("No retries supported for Secure operation\n"); return CCID_DRIVER_ERR_CARD_IO_ERROR; } - else if (!!(tpdu[1] & 0x40) == handle->t1_ns) + else if (!!(tpdu[1] & 0x10) == handle->t1_ns) { /* Reponse does not match our sequence number. */ DEBUGOUT ("R-block with wrong seqno received on more bit\n"); return CCID_DRIVER_ERR_CARD_IO_ERROR; @@ -2075,7 +2083,7 @@ ccid_transceive_secure (ccid_driver_t handle, } else { /* This is a S-block. */ - DEBUGOUT_2 ("T1 S-block %s received cmd=%d for Secure operation\n", + DEBUGOUT_2 ("T=1 S-block %s received cmd=%d for Secure operation\n", (tpdu[1] & 0x20)? "response": "request", (tpdu[1] & 0x1f)); return CCID_DRIVER_ERR_CARD_IO_ERROR; diff --git a/scd/command.c b/scd/command.c index 5ea3e01db..c68d0e925 100644 --- a/scd/command.c +++ b/scd/command.c @@ -40,6 +40,9 @@ /* Maximum length allowed as a PIN; used for INQUIRE NEEDPIN */ #define MAXLEN_PIN 100 +/* Maximum allowed size of key data as used in inquiries. */ +#define MAXLEN_KEYDATA 4096 + #define set_error(e,t) assuan_set_error (ctx, ASSUAN_ ## e, (t)) @@ -523,7 +526,7 @@ cmd_readcert (assuan_context_t ctx, char *line) } -/* READKEY +/* READKEY Return the public key for the given cert or key ID as an standard S-Expression. @@ -913,6 +916,79 @@ cmd_setattr (assuan_context_t ctx, char *orig_line) return map_to_assuan_status (rc); } + + +/* WRITEKEY [--force] + + This command is used to store a secret key on a a smartcard. The + allowed keyids depend on the currently selected smartcard + application. The actual keydata is requested using the inquiry + "KETDATA" and need to be provided without any protection. With + --force set an existing key under this KEYID will get overwritten. + The keydata is expected to be the usual canonical encoded + S-expression. + + A PIN will be requested for most NAMEs. See the corresponding + writekey function of the actually used application (app-*.c) for + details. */ +static int +cmd_writekey (assuan_context_t ctx, char *line) +{ + ctrl_t ctrl = assuan_get_pointer (ctx); + int rc; + char *keyid; + int force = has_option (line, "--force"); + unsigned char *keydata; + size_t keydatalen; + + if ( IS_LOCKED (ctrl) ) + return gpg_error (GPG_ERR_LOCKED); + + /* Skip over options. */ + while ( *line == '-' && line[1] == '-' ) + { + while (*line && !spacep (line)) + line++; + while (spacep (line)) + line++; + } + if (!*line) + return set_error (Parameter_Error, "no keyid given"); + keyid = line; + while (*line && !spacep (line)) + line++; + *line = 0; + + if ((rc = open_card (ctrl, NULL))) + return rc; + + if (!ctrl->app_ctx) + return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); + + keyid = xtrystrdup (keyid); + if (!keyid) + return ASSUAN_Out_Of_Core; + + /* Now get the actual keydata. */ + rc = assuan_inquire (ctx, "KEYDATA", &keydata, &keydatalen, MAXLEN_KEYDATA); + if (rc) + { + xfree (keyid); + return rc; + } + + /* Write the key to the card. */ + rc = app_writekey (ctrl->app_ctx, ctrl, keyid, force? 1:0, + pin_cb, ctx, keydata, keydatalen); + xfree (keyid); + xfree (keydata); + + TEST_CARD_REMOVAL (ctrl, rc); + return map_to_assuan_status (rc); +} + + + /* GENKEY [--force] Generate a key on-card identified by NO, which is application @@ -924,7 +1000,7 @@ cmd_setattr (assuan_context_t ctx, char *orig_line) S KEY-DATA [p|n] - --force is required to overwriet an already existing key. The + --force is required to overwrite an already existing key. The KEY-CREATED-AT is required for further processing because it is part of the hashed key material for the fingerprint. @@ -1222,6 +1298,7 @@ register_commands (assuan_context_t ctx) { "OUTPUT", NULL }, { "GETATTR", cmd_getattr }, { "SETATTR", cmd_setattr }, + { "WRITEKEY", cmd_writekey }, { "GENKEY", cmd_genkey }, { "RANDOM", cmd_random }, { "PASSWD", cmd_passwd }, diff --git a/scd/scdaemon.c b/scd/scdaemon.c index 9a8b31ac5..1110d9d76 100644 --- a/scd/scdaemon.c +++ b/scd/scdaemon.c @@ -50,6 +50,7 @@ #ifdef HAVE_W32_SYSTEM #include "../jnlib/w32-afunix.h" #endif +#include "ccid-driver.h" enum cmd_and_opt_values @@ -66,7 +67,7 @@ enum cmd_and_opt_values oDebugAll, oDebugLevel, oDebugWait, - oDebugSC, + oDebugCCIDDriver, oNoGreeting, oNoOptions, oHomedir, @@ -85,8 +86,8 @@ enum cmd_and_opt_values oAllowAdmin, oDenyAdmin, oDisableApplication, - -aTest }; + oDebugDisableTicker +}; @@ -97,6 +98,8 @@ static ARGPARSE_OPTS opts[] = { { 301, NULL, 0, N_("@Options:\n ") }, { oServer, "server", 0, N_("run in server mode (foreground)") }, + { oMultiServer, "multi-server", 0, + N_("run in multi server mode (foreground)") }, { oDaemon, "daemon", 0, N_("run in daemon mode (background)") }, { oVerbose, "verbose", 0, N_("verbose") }, { oQuiet, "quiet", 0, N_("be somewhat more quiet") }, @@ -107,10 +110,10 @@ static ARGPARSE_OPTS opts[] = { { oDebugAll, "debug-all" ,0, "@"}, { oDebugLevel, "debug-level" ,2, "@"}, { oDebugWait,"debug-wait",1, "@"}, + { oDebugCCIDDriver, "debug-ccid-driver", 0, "@"}, + { oDebugDisableTicker, "debug-disable-ticker", 0, "@"}, { oNoDetach, "no-detach" ,0, N_("do not detach from the console")}, { oLogFile, "log-file" ,2, N_("use a log file for the server")}, - { oMultiServer, "multi-server", 0, - N_("allow additional connections in server mode")}, { oReaderPort, "reader-port", 2, N_("|N|connect to reader at port N")}, { octapiDriver, "ctapi-driver", 2, N_("|NAME|use NAME as ct-API driver")}, { opcscDriver, "pcsc-driver", 2, N_("|NAME|use NAME as PC/SC driver")}, @@ -125,10 +128,6 @@ static ARGPARSE_OPTS opts[] = { { oDenyAdmin, "deny-admin", 0, "@" }, { oDisableApplication, "disable-application", 2, "@"}, - /* Dummy options to be removed at some point. */ - { oDebugSC, "debug-sc", 1, "@" }, - { oDisableOpenSC, "disable-opensc", 0, "@" }, - {0} }; @@ -150,6 +149,12 @@ static int maybe_setuid = 1; /* Name of the communication socket */ static char *socket_name; + +/* Debug flag to disable the ticker. The ticker is in fact not + disabled but it won't perform any ticker specific actions. */ +static int ticker_disabled; + + static char *create_socket_name (int use_standard_socket, char *standard_name, char *template); @@ -443,7 +448,10 @@ main (int argc, char **argv ) case oDebugAll: opt.debug = ~0; break; case oDebugLevel: debug_level = pargs.r.ret_str; break; case oDebugWait: debug_wait = pargs.r.ret_int; break; - case oDebugSC: break; + case oDebugCCIDDriver: + ccid_set_debug_level (ccid_set_debug_level (-1)+1); + break; + case oDebugDisableTicker: ticker_disabled = 1; break; case oOptions: /* config files may not be nested (silently ignore them) */ @@ -463,7 +471,7 @@ main (int argc, char **argv ) case oCsh: csh_style = 1; break; case oSh: csh_style = 0; break; case oServer: pipe_server = 1; break; - case oMultiServer: multi_server = 1; break; + case oMultiServer: pipe_server = 1; multi_server = 1; break; case oDaemon: is_daemon = 1; break; case oReaderPort: opt.reader_port = pargs.r.ret_str; break; @@ -839,7 +847,8 @@ handle_signal (int signo) static void handle_tick (void) { - scd_update_reader_status_file (); + if (!ticker_disabled) + scd_update_reader_status_file (); } diff --git a/scd/tlv.c b/scd/tlv.c index 3a81ea6d9..b5dcd4021 100644 --- a/scd/tlv.c +++ b/scd/tlv.c @@ -221,3 +221,76 @@ parse_ber_header (unsigned char const **buffer, size_t *size, *size = length; return 0; } + + +/* FIXME: The following function should not go into this file but for + now it is easier to keep it here. */ + +/* Return the next token of an canconical encoded S-expression. BUF + is the pointer to the S-expression and BUFLEN is a pointer to the + length of this S-expression (used to validate the syntax). Both + are updated to reflect the new position. The token itself is + returned as a pointer into the orginal buffer at TOK and TOKLEN. + If a parentheses is the next token, TOK will be set to NULL. + TOKLEN is checked to be within the bounds. On error a error code + is returned and all pointers should are not guaranteed to point to + a meanigful value. DEPTH should be initialized to 0 and will + reflect on return the actual depth of the tree. To detect the end + of the S-expression it is advisable to check DEPTH after a + successful return: + + depth = 0; + while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)) + && depth) + process_token (tok, toklen); + if (err) + handle_error (); + */ +gpg_error_t +parse_sexp (unsigned char const **buf, size_t *buflen, + int *depth, unsigned char const **tok, size_t *toklen) +{ + const unsigned char *s; + size_t n, vlen; + + s = *buf; + n = *buflen; + *tok = NULL; + *toklen = 0; + if (!n) + return *depth ? gpg_error (GPG_ERR_INV_SEXP) : 0; + if (*s == '(') + { + s++; n--; + (*depth)++; + *buf = s; + *buflen = n; + return 0; + } + if (*s == ')') + { + if (!*depth) + return gpg_error (GPG_ERR_INV_SEXP); + *toklen = 1; + s++; n--; + (*depth)--; + *buf = s; + *buflen = n; + return 0; + } + for (vlen=0; n && *s && *s != ':' && (*s >= '0' && *s <= '9'); s++, n--) + vlen = vlen*10 + (*s - '0'); + if (!n || *s != ':') + return gpg_error (GPG_ERR_INV_SEXP); + s++; n--; + if (vlen > n) + return gpg_error (GPG_ERR_INV_SEXP); + *tok = s; + *toklen = vlen; + s += vlen; + n -= vlen; + *buf = s; + *buflen = n; + return 0; +} + diff --git a/scd/tlv.h b/scd/tlv.h index 628580431..f587dd9df 100644 --- a/scd/tlv.h +++ b/scd/tlv.h @@ -88,4 +88,21 @@ gpg_error_t parse_ber_header (unsigned char const **buffer, size_t *size, +/* Return the next token of an canconical encoded S-expression. BUF + is the pointer to the S-expression and BUFLEN is a pointer to the + length of this S-expression (used to validate the syntax). Both + are updated to reflect the new position. The token itself is + returned as a pointer into the orginal buffer at TOK and TOKLEN. + If a parentheses is the next token, TOK will be set to NULL. + TOKLEN is checked to be within the bounds. On error a error code + is returned and all pointers should are not guaranteed to point to + a meanigful value. DEPTH should be initialized to 0 and will + reflect on return the actual depth of the tree. To detect the end + of the S-expression it is advisable to check DEPTH after a + successful return. */ +gpg_error_t parse_sexp (unsigned char const **buf, size_t *buflen, + int *depth, unsigned char const **tok, size_t *toklen); + + + #endif /* SCD_TLV_H */ diff --git a/tools/ChangeLog b/tools/ChangeLog index 68b62dd30..76505a6bf 100644 --- a/tools/ChangeLog +++ b/tools/ChangeLog @@ -1,3 +1,10 @@ +2005-05-20 Werner Koch + + * gpg-connect-agent.c (add_definq, show_definq, clear_definq) + (handle_inquire): New. + (read_and_print_response): Handle INQUIRE command. + (main): Implement control commands. + 2005-04-21 Werner Koch * symcryptrun.c (main): Optionally allow the input file as command @@ -368,7 +375,7 @@ * watchgnupg.c: New. - Copyright 2003, 2004 Free Software Foundation, Inc. + Copyright 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 diff --git a/tools/gpg-connect-agent.c b/tools/gpg-connect-agent.c index 403fa2c45..bb05030ee 100644 --- a/tools/gpg-connect-agent.c +++ b/tools/gpg-connect-agent.c @@ -76,6 +76,23 @@ struct } opt; + +/* Definitions for /definq commands and a global linked list with all + the definitions. */ +struct definq_s +{ + struct definq_s *next; + char *name; /* Name of inquiry or NULL for any name. */ + int is_prog; /* True if this is a program to run. */ + char file[1]; /* Name of file or program. */ +}; +typedef struct definq_s *definq_t; + +static definq_t definq_list; +static definq_t *definq_list_tail = &definq_list; + + + /*-- local prototypes --*/ static int read_and_print_response (assuan_context_t ctx); static assuan_context_t start_agent (void); @@ -129,6 +146,68 @@ i18n_init(void) #endif } +/* Store an inquire response pattern. Note, that this function may + change the content of LINE. We assume that leading white spaces + are already removed. */ +static void +add_definq (char *line, int is_prog) +{ + definq_t d; + char *name, *p; + + /* Get name. */ + name = line; + for (p=name; *p && !spacep (p); p++) + ; + if (*p) + *p++ = 0; + while (spacep (p)) + p++; + + d = xmalloc (sizeof *d + strlen (p) ); + strcpy (d->file, p); + d->is_prog = is_prog; + if ( !strcmp (name, "*")) + d->name = NULL; + else + d->name = xstrdup (name); + + d->next = NULL; + *definq_list_tail = d; + definq_list_tail = &d->next; +} + + +/* Show all inquiry defintions. */ +static void +show_definq (void) +{ + definq_t d; + + for (d=definq_list; d; d = d->next) + if (d->name) + printf ("%-20s %c %s\n", d->name, d->is_prog? 'p':'f', d->file); + for (d=definq_list; d; d = d->next) + if (!d->name) + printf ("%-20s %c %s\n", "*", d->is_prog? 'p':'f', d->file); +} + + +/* Clear all inquiry definitions. */ +static void +clear_definq (void) +{ + while (definq_list) + { + definq_t tmp = definq_list->next; + xfree (definq_list->name); + xfree (definq_list); + definq_list = tmp; + } + definq_list_tail = &definq_list; +} + + /* gpg-connect-agent's entry point. */ int @@ -138,7 +217,7 @@ main (int argc, char **argv) const char *fname; int no_more_options = 0; assuan_context_t ctx; - char *line; + char *line, *p; size_t linesize; int rc; @@ -213,6 +292,57 @@ main (int argc, char **argv) log_info (_("line shortened due to embedded Nul character\n")); if (line[n-1] == '\n') line[n-1] = 0; + if (*line == '/') + { + /* Handle control commands. */ + char *cmd = line+1; + + for (p=cmd; *p && !spacep (p); p++) + ; + if (*p) + *p++ = 0; + while (spacep (p)) + p++; + if (!strcmp (cmd, "definqfile")) + { + add_definq (p, 0); + } + else if (!strcmp (cmd, "definqprog")) + { + add_definq (p, 1); + } + else if (!strcmp (cmd, "showdef")) + { + show_definq (); + } + else if (!strcmp (cmd, "cleardef")) + { + clear_definq (); + } + else if (!strcmp (cmd, "echo")) + { + puts (p); + } + else if (!strcmp (cmd, "help")) + { + puts ("Available commands:\n" + "/echo ARGS Echo ARGS.\n" + "/definqfile NAME FILE\n" + " Use content of FILE for inquiries with NAME.\n" + " NAME may be \"*\" to match any inquiry.\n" + "/definqprog NAME PGM\n" + " Run PGM for inquiries matching NAME and pass the\n" + " entire line to it as arguments.\n" + "/showdef Print all definitions.\n" + "/cleardef Delete all definitions.\n" + "/help Print this help."); + } + else + log_error (_("unknown command `%s'\n"), cmd ); + + continue; + } + rc = assuan_write_line (ctx, line); if (rc) { @@ -234,6 +364,94 @@ main (int argc, char **argv) } +/* Handle an Inquire from the server. Return False if it could not be + handled; in this case the caller shll complete the operation. LINE + is the complete line as received from the server. This function + may change the content of LINE. */ +static int +handle_inquire (assuan_context_t ctx, char *line) +{ + const char *name; + definq_t d; + FILE *fp; + char buffer[1024]; + int rc, n; + + /* Skip the command and trailing spaces. */ + for (; *line && !spacep (line); line++) + ; + while (spacep (line)) + line++; + /* Get the name. */ + name = line; + for (; *line && !spacep (line); line++) + ; + if (*line) + *line++ = 0; + + /* Now match it against our list. he second loop is todetect the + match all entry. **/ + for (d=definq_list; d; d = d->next) + if (d->name && !strcmp (d->name, name)) + break; + if (!d) + for (d=definq_list; d; d = d->next) + if (!d->name) + break; + if (!d) + { + if (opt.verbose) + log_info ("no handler for inquiry `%s' found\n", name); + return 0; + } + + if (d->is_prog) + { + fp = popen (d->file, "r"); + if (!fp) + log_error ("error executing `%s': %s\n", d->file, strerror (errno)); + else if (opt.verbose) + log_error ("handling inquiry `%s' by running `%s'\n", name, d->file); + } + else + { + fp = fopen (d->file, "rb"); + if (!fp) + log_error ("error opening `%s': %s\n", d->file, strerror (errno)); + else if (opt.verbose) + log_error ("handling inquiry `%s' by returning content of `%s'\n", + name, d->file); + } + if (!fp) + return 0; + + while ( (n = fread (buffer, 1, sizeof buffer, fp)) ) + { + rc = assuan_send_data (ctx, buffer, n); + if (rc) + { + log_error ("sending data back failed: %s\n", assuan_strerror (rc) ); + break; + } + } + if (ferror (fp)) + log_error ("error reading from `%s': %s\n", d->file, strerror (errno)); + + rc = assuan_send_data (ctx, NULL, 0); + if (rc) + log_error ("sending data back failed: %s\n", assuan_strerror (rc) ); + + if (d->is_prog) + { + if (pclose (fp)) + log_error ("error running `%s': %s\n", d->file, strerror (errno)); + } + else + fclose (fp); + return 1; +} + + /* Read all response lines from server and print them. Returns 0 on success or an assuan error code. */ static int @@ -325,7 +543,8 @@ read_and_print_response (assuan_context_t ctx) { fwrite (line, linelen, 1, stdout); putchar ('\n'); - return 0; + if (!handle_inquire (ctx, line)) + assuan_write_line (ctx, "CANCEL"); } else if (linelen >= 3 && line[0] == 'E' && line[1] == 'N' && line[2] == 'D' -- cgit From 05e1dc22f0feef8d5af7c8bbb0c0a5129f2c0b05 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Sat, 21 May 2005 18:49:00 +0000 Subject: * call-scd.c (start_scd): Don't test for an alive scdaemon here. (agent_scd_check_aliveness): New. * gpg-agent.c (handle_tick): Test for an alive scdaemon. (handle_signal): Print thread info on SIGUSR1. * scdaemon.c (handle_signal): Print thread info on SIGUSR1. --- NEWS | 5 ++++ TODO | 15 +++++++++++ agent/ChangeLog | 7 +++++ agent/agent.h | 1 + agent/call-scd.c | 81 ++++++++++++++++++++++++++++++++++++++++--------------- agent/gpg-agent.c | 8 +++++- scd/ChangeLog | 4 +++ scd/app-openpgp.c | 2 +- scd/scdaemon.c | 3 ++- 9 files changed, 101 insertions(+), 25 deletions(-) (limited to 'scd/app-openpgp.c') diff --git a/NEWS b/NEWS index c25bbe08e..79a74cbe4 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,11 @@ Noteworthy changes in version 1.9.17 ------------------------------------------------- + * gpg-connect-agent has now features to handle Assuan INQUIRE + commands. + + * Internal changes for OpenPGP cards. New Assuan command WRITEKEY. + * GNU Pth is now a hard requirement. * [scdaemon] Support for OpenSC has been removed. Instead a new and diff --git a/TODO b/TODO index 6e8951f03..fe10e9f77 100644 --- a/TODO +++ b/TODO @@ -67,6 +67,11 @@ might want to have an agent context for each service request * sm/export.c ** Return an error code or a status info per user ID. +* scd/tlv.c + The parse_sexp fucntion should not go into this file. Check whether + we can change all S-expression handling code to make use of this + function. + * tests ** Makefile.am We use printf(1) to setup the library path, this is not portable. @@ -89,3 +94,13 @@ might want to have an agent context for each service request This means we can't reread a configuration ** No card status notifications. + + +* IMPORTANT: + Check that the PIN cache is cleared after failed card operations. + After receiving a HUP gpg-agent should set a flag to kill scdaemon + as soon as possible, w/o that scdaemon will continue running as a + zombie and gpg-agent won't be able to fire up a new one. + Implement an scd/agent option to wait for a card. + + diff --git a/agent/ChangeLog b/agent/ChangeLog index 015b0b6d8..6c271c8e2 100644 --- a/agent/ChangeLog +++ b/agent/ChangeLog @@ -1,3 +1,10 @@ +2005-05-21 Werner Koch + + * call-scd.c (start_scd): Don't test for an alive scdaemon here. + (agent_scd_check_aliveness): New. + * gpg-agent.c (handle_tick): Test for an alive scdaemon. + (handle_signal): Print thread info on SIGUSR1. + 2005-05-20 Werner Koch * protect-tool.c: New option --canonical. diff --git a/agent/agent.h b/agent/agent.h index 6ab65eeba..7e4f555e8 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -247,6 +247,7 @@ int divert_generic_cmd (ctrl_t ctrl, /*-- call-scd.c --*/ void initialize_module_call_scd (void); +void agent_scd_check_aliveness (void); int agent_reset_scd (ctrl_t ctrl); int agent_card_learn (ctrl_t ctrl, void (*kpinfo_cb)(void*, const char *), diff --git a/agent/call-scd.c b/agent/call-scd.c index fc81e2fa3..617ef0d48 100644 --- a/agent/call-scd.c +++ b/agent/call-scd.c @@ -185,26 +185,15 @@ start_scd (ctrl_t ctrl) } ctrl->scd_local->locked++; - /* If we already have a context, we better do a sanity check now to - see whether it has accidently died. This avoids annoying - timeouts and hung connections. */ if (ctrl->scd_local->ctx) - { - pid_t pid; -#ifndef HAVE_W32_SYSTEM - pid = assuan_get_pid (ctrl->scd_local->ctx); - if (pid != (pid_t)(-1) && pid - && ((rc=waitpid (pid, NULL, WNOHANG))==-1 || (rc == pid)) ) - { - assuan_disconnect (ctrl->scd_local->ctx); - ctrl->scd_local->ctx = NULL; - } - else -#endif - return 0; /* Okay, the context is fine. */ - } + return 0; /* Okay, the context is fine. We used to test for an + alive context here and do an disconnect. How that we + have a ticker function to check for it, it is easier + not to check here but to let the connection run on an + error instead. */ - /* We need to protect the lowwing code. */ + + /* We need to protect the following code. */ if (!pth_mutex_acquire (&start_scd_lock, 0, NULL)) { log_error ("failed to acquire the start_scd lock: %s\n", @@ -350,6 +339,50 @@ start_scd (ctrl_t ctrl) } +/* Check whether the Scdaemon is still alive and clean it up if not. */ +void +agent_scd_check_aliveness (void) +{ + pid_t pid; + int rc; + + /* We can do so only if there is no more active primary connection. + With an active primary connection, this is all no problem because + with the end of gpg-agent's session a disconnect is send and the + this function will be used at a later time. */ + if (!primary_scd_ctx || !primary_scd_ctx_reusable) + return; + + if (!pth_mutex_acquire (&start_scd_lock, 0, NULL)) + { + log_error ("failed to acquire the start_scd lock while" + " doing an aliveness check: %s\n", + strerror (errno)); + return; + } + + if (primary_scd_ctx && primary_scd_ctx_reusable) + { + pid = assuan_get_pid (primary_scd_ctx); + if (pid != (pid_t)(-1) && pid + && ((rc=waitpid (pid, NULL, WNOHANG))==-1 || (rc == pid)) ) + { + /* Okay, scdaemon died. Disconnect the primary connection now + but take care that it won't do another wait. */ + assuan_set_flag (primary_scd_ctx, ASSUAN_NO_WAITPID, 1); + assuan_disconnect (primary_scd_ctx); + primary_scd_ctx = NULL; + primary_scd_ctx_reusable = 0; + xfree (socket_name); + socket_name = NULL; + } + } + + if (!pth_mutex_release (&start_scd_lock)) + log_error ("failed to release the start_scd lock while" + " doing the aliveness check: %s\n", strerror (errno)); +} + /* Reset the SCD if it has been used. */ int @@ -359,15 +392,19 @@ agent_reset_scd (ctrl_t ctrl) { if (ctrl->scd_local->ctx) { - /* We can't disconnect the primary context becuase libassuan + /* We can't disconnect the primary context because libassuan does a waitpid on it and thus the system would hang. Instead we send a reset and keep that connection for reuse. */ if (ctrl->scd_local->ctx == primary_scd_ctx) { - if (!assuan_transact (primary_scd_ctx, "RESET", - NULL, NULL, NULL, NULL, NULL, NULL)) - primary_scd_ctx_reusable = 1; + /* The RESET may fail for example if the scdaemon has + already been terminated. We need to set the reusable + flag anyway to make sure that the aliveness check can + clean it up. */ + assuan_transact (primary_scd_ctx, "RESET", + NULL, NULL, NULL, NULL, NULL, NULL); + primary_scd_ctx_reusable = 1; } else assuan_disconnect (ctrl->scd_local->ctx); diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c index 4ac995c26..e3e952906 100644 --- a/agent/gpg-agent.c +++ b/agent/gpg-agent.c @@ -1270,6 +1270,11 @@ create_directories (void) static void handle_tick (void) { + /* Check whether the scdaemon has dies and cleanup in this case. */ + agent_scd_check_aliveness (); + + /* If we are running as a child of another process, check whether + the parent is still alive and shutdwon if now. */ #ifndef HAVE_W32_SYSTEM if (parent_pid != (pid_t)(-1)) { @@ -1301,7 +1306,8 @@ handle_signal (int signo) break; case SIGUSR1: - log_info ("SIGUSR1 received - no action defined\n"); + log_info ("SIGUSR1 received - printing internal information:\n"); + pth_ctrl (PTH_CTRL_DUMPSTATE, log_get_stream ()); break; case SIGUSR2: diff --git a/scd/ChangeLog b/scd/ChangeLog index c64fbec7e..feeaabfce 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,7 @@ +2005-05-21 Werner Koch + + * scdaemon.c (handle_signal): Print thread info on SIGUSR1. + 2005-05-20 Werner Koch * ccid-driver.c: Replaced macro DEBUG_T1 by a new debug level. diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 16ebd34c8..1165ec683 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -1634,7 +1634,7 @@ do_writekey (app_t app, ctrl_t ctrl, log_info ("protected-private-key passed to writekey\n"); else if (toklen == 20 && !memcmp ("shadowed-private-key", tok, toklen)) log_info ("shadowed-private-key passed to writekey\n"); - err = gpg_error (GPG_ERR_BAD_KEY); + err = gpg_error (GPG_ERR_BAD_SECKEY); goto leave; } if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) diff --git a/scd/scdaemon.c b/scd/scdaemon.c index 1110d9d76..488a4853b 100644 --- a/scd/scdaemon.c +++ b/scd/scdaemon.c @@ -807,7 +807,8 @@ handle_signal (int signo) break; case SIGUSR1: - log_info ("SIGUSR1 received - no action defined\n"); + log_info ("SIGUSR1 received - printing internal information:\n"); + pth_ctrl (PTH_CTRL_DUMPSTATE, log_get_stream ()); break; case SIGUSR2: -- cgit From a43586d0e81b538009fc86f260592e52d54ef42c Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 23 May 2005 20:18:13 +0000 Subject: * Makefile.am: Do not build sc-copykeys anymore. * app-openpgp.c (app_openpgp_storekey, app_openpgp_readkey) (app_openpgp_cardinfo): Removed. --- doc/scdaemon.texi | 31 +++++++- scd/ChangeLog | 6 ++ scd/Makefile.am | 37 +++++----- scd/app-common.h | 17 ----- scd/app-openpgp.c | 212 ------------------------------------------------------ scd/command.c | 20 +++++- 6 files changed, 73 insertions(+), 250 deletions(-) (limited to 'scd/app-openpgp.c') diff --git a/doc/scdaemon.texi b/doc/scdaemon.texi index f069a9fb8..134ca40df 100644 --- a/doc/scdaemon.texi +++ b/doc/scdaemon.texi @@ -478,12 +478,39 @@ TO BE WRITTEN. @node Scdaemon PASSWD @subsection Change PINs. -TO BE WRITTEN. +@example + PASSWD [--reset] @var{chvno} +@end example + +Change the PIN or reset the retry counter of the card holder +verification vector number @var{chvno}. @node Scdaemon CHECKPIN @subsection Perform a VERIFY operation. -TO BE WRITTEN. +@example + CHECKPIN @var{idstr} +@end example + +Perform a VERIFY operation without doing anything else. This may be +used to initialize a the PIN cache earlier to long lasting +operations. Its use is highly application dependent: + +@table @strong +@item OpenPGP + +Perform a simple verify operation for CHV1 and CHV2, so that further +operations won't ask for CHV2 and it is possible to do a cheap check on +the PIN: If there is something wrong with the PIN entry system, only the +regular CHV will get blocked and not the dangerous CHV3. @var{idstr} is +the usual card's serial number in hex notation; an optional fingerprint +part will get ignored. + +There is however a special mode if @var{idstr} is suffixed with the +literal string @code{[CHV3]}: In this case the Admin PIN is checked if +and only if the retry counter is still at 3. + +@end table diff --git a/scd/ChangeLog b/scd/ChangeLog index 91603f61b..64a4a8b72 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,5 +1,10 @@ 2005-05-23 Werner Koch + * Makefile.am: Do not build sc-copykeys anymore. + + * app-openpgp.c (app_openpgp_storekey, app_openpgp_readkey) + (app_openpgp_cardinfo): Removed. + * ccid-driver.c (parse_ccid_descriptor): SCR335 FW version 5.14 is good. (do_close_reader): Never do a reset. The caller should instead @@ -11,6 +16,7 @@ Thanks to Ludovic Rousseau for this hint and the magic numbers. (print_command_failed): New. (bulk_in): Use it here. Add new arg NO_DEBUG. + (ccid_slot_status): Disabled debugging. 2005-05-21 Werner Koch diff --git a/scd/Makefile.am b/scd/Makefile.am index c3688da5f..e76f83ea4 100644 --- a/scd/Makefile.am +++ b/scd/Makefile.am @@ -18,7 +18,7 @@ ## Process this file with automake to produce Makefile.in -bin_PROGRAMS = scdaemon sc-copykeys +bin_PROGRAMS = scdaemon if ! HAVE_W32_SYSTEM pkglib_PROGRAMS = pcsc-wrapper endif @@ -47,22 +47,25 @@ scdaemon_LDADD = ../jnlib/libjnlib.a ../common/libcommon.a \ $(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(PTH_LIBS) $(LIBASSUAN_LIBS) \ $(LIBUSB_LIBS) -lgpg-error $(LIBINTL) $(DL_LIBS) -sc_copykeys_SOURCES = \ - sc-copykeys.c scdaemon.h \ - apdu.c apdu.h \ - ccid-driver.c ccid-driver.h \ - iso7816.c iso7816.h \ - tlv.c tlv.h \ - atr.c atr.h \ - app.c app-common.h app-help.c $(card_apps) - -sc_copykeys_LDADD = \ - ../jnlib/libjnlib.a ../common/libcommon.a \ - ../common/libsimple-pwquery.a \ - $(LIBGCRYPT_LIBS) $(PTH_LIBS) $(KSBA_LIBS) $(LIBASSUAN_LIBS) \ - $(LIBUSB_LIBS) \ - -lgpg-error @LIBINTL@ @DL_LIBS@ - +# Removed for now: We need to decide whether it makes sense to +# continue it at all, given that gpg has now all required +# functionality. +#sc_copykeys_SOURCES = \ +# sc-copykeys.c scdaemon.h \ +# apdu.c apdu.h \ +# ccid-driver.c ccid-driver.h \ +# iso7816.c iso7816.h \ +# tlv.c tlv.h \ +# atr.c atr.h \ +# app.c app-common.h app-help.c $(card_apps) +# +#sc_copykeys_LDADD = \ +# ../jnlib/libjnlib.a ../common/libcommon.a \ +# ../common/libsimple-pwquery.a \ +# $(LIBGCRYPT_LIBS) $(PTH_LIBS) $(KSBA_LIBS) $(LIBASSUAN_LIBS) \ +# $(LIBUSB_LIBS) \ +# -lgpg-error @LIBINTL@ @DL_LIBS@ +# pcsc_wrapper_SOURCES = pcsc-wrapper.c pcsc_wrapper_LDADD = $(DL_LIBS) pcsc_wrapper_CFLAGS = diff --git a/scd/app-common.h b/scd/app-common.h index c2c302395..613ad61f6 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -176,23 +176,6 @@ gpg_error_t app_check_pin (app_t app, const char *keyidstr, /*-- app-openpgp.c --*/ gpg_error_t app_select_openpgp (app_t app); -gpg_error_t app_openpgp_cardinfo (app_t app, - char **serialno, - char **disp_name, - char **pubkey_url, - unsigned char **fpr1, - unsigned char **fpr2, - unsigned char **fpr3); -gpg_error_t app_openpgp_storekey (app_t app, int keyno, - unsigned char *template, size_t template_len, - time_t created_at, - const unsigned char *m, size_t mlen, - const unsigned char *e, size_t elen, - gpg_error_t (*pincb)(void*, const char *, char **), - void *pincb_arg); -gpg_error_t app_openpgp_readkey (app_t app, int keyno, - unsigned char **m, size_t *mlen, - unsigned char **e, size_t *elen); /*-- app-nks.c --*/ gpg_error_t app_select_nks (app_t app); diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 1165ec683..91e208a0a 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -2521,215 +2521,3 @@ leave: -/* This function is a hack to retrieve essential information about the - card to be displayed by simple tools. It mostly resembles what the - LEARN command returns. All parameters return allocated strings or - buffers or NULL if the data object is not available. All returned - values are sanitized. */ -gpg_error_t -app_openpgp_cardinfo (app_t app, - char **serialno, - char **disp_name, - char **pubkey_url, - unsigned char **fpr1, - unsigned char **fpr2, - unsigned char **fpr3) -{ - int rc; - void *relptr; - unsigned char *value; - size_t valuelen; - - if (serialno) - { - time_t dummy; - - *serialno = NULL; - rc = app_get_serial_and_stamp (app, serialno, &dummy); - if (rc) - { - log_error (_("error getting serial number: %s\n"), - gpg_strerror (rc)); - return rc; - } - } - - if (disp_name) - { - *disp_name = NULL; - relptr = get_one_do (app, 0x005B, &value, &valuelen, NULL); - if (relptr) - { - *disp_name = make_printable_string (value, valuelen, 0); - xfree (relptr); - } - } - - if (pubkey_url) - { - *pubkey_url = NULL; - relptr = get_one_do (app, 0x5F50, &value, &valuelen, NULL); - if (relptr) - { - *pubkey_url = make_printable_string (value, valuelen, 0); - xfree (relptr); - } - } - - if (fpr1) - *fpr1 = NULL; - if (fpr2) - *fpr2 = NULL; - if (fpr3) - *fpr3 = NULL; - relptr = get_one_do (app, 0x00C5, &value, &valuelen, NULL); - if (relptr && valuelen >= 60) - { - if (fpr1) - { - *fpr1 = xmalloc (20); - memcpy (*fpr1, value + 0, 20); - } - if (fpr2) - { - *fpr2 = xmalloc (20); - memcpy (*fpr2, value + 20, 20); - } - if (fpr3) - { - *fpr3 = xmalloc (20); - memcpy (*fpr3, value + 40, 20); - } - } - xfree (relptr); - - return 0; -} - - - -/* This function is currently only used by the sc-copykeys program to - store a key on the smartcard. app_t ist the application handle, - KEYNO is the number of the key and PINCB, PINCB_ARG are used to ask - for the SO PIN. TEMPLATE and TEMPLATE_LEN describe a buffer with - the key template to store. CREATED_AT is the timestamp used to - create the fingerprint. M, MLEN is the RSA modulus and E, ELEN the - RSA public exponent. This function silently overwrites an existing - key.*/ -gpg_error_t -app_openpgp_storekey (app_t app, int keyno, - unsigned char *template, size_t template_len, - time_t created_at, - const unsigned char *m, size_t mlen, - const unsigned char *e, size_t elen, - gpg_error_t (*pincb)(void*, const char *, char **), - void *pincb_arg) -{ - int rc; - unsigned char fprbuf[20]; - - if (keyno < 1 || keyno > 3) - return gpg_error (GPG_ERR_INV_ID); - keyno--; - - rc = verify_chv3 (app, pincb, pincb_arg); - if (rc) - goto leave; - - flush_cache (app); - - xfree (app->app_local->pk[keyno].key); - app->app_local->pk[keyno].key = NULL; - app->app_local->pk[keyno].keylen = 0; - app->app_local->pk[keyno].read_done = 0; - - rc = iso7816_put_data (app->slot, - (app->card_version > 0x0007? 0xE0 : 0xE9) + keyno, - template, template_len); - if (rc) - { - log_error (_("failed to store the key: %s\n"), gpg_strerror (rc)); - rc = gpg_error (GPG_ERR_CARD); - goto leave; - } - -/* log_printhex ("RSA n:", m, mlen); */ -/* log_printhex ("RSA e:", e, elen); */ - - rc = store_fpr (app->slot, keyno, (u32)created_at, - m, mlen, e, elen, fprbuf, app->card_version); - - leave: - return rc; -} - - -/* Utility function for external tools: Read the public RSA key at - KEYNO and return modulus and exponent in (M,MLEN) and (E,ELEN). */ -gpg_error_t -app_openpgp_readkey (app_t app, int keyno, unsigned char **m, size_t *mlen, - unsigned char **e, size_t *elen) -{ - int rc; - const unsigned char *keydata, *a; - unsigned char *buffer; - size_t buflen, keydatalen, alen; - - *m = NULL; - *e = NULL; - - if (keyno < 1 || keyno > 3) - return gpg_error (GPG_ERR_INV_ID); - keyno--; - - rc = iso7816_read_public_key(app->slot, - keyno == 0? "\xB6" : - keyno == 1? "\xB8" : "\xA4", - 2, - &buffer, &buflen); - if (rc) - { - rc = gpg_error (GPG_ERR_CARD); - log_error (_("reading the key failed\n")); - goto leave; - } - - keydata = find_tlv (buffer, buflen, 0x7F49, &keydatalen); - if (!keydata) - { - log_error (_("response does not contain the public key data\n")); - rc = gpg_error (GPG_ERR_CARD); - goto leave; - } - - a = find_tlv (keydata, keydatalen, 0x0081, &alen); - if (!a) - { - log_error (_("response does not contain the RSA modulus\n")); - rc = gpg_error (GPG_ERR_CARD); - goto leave; - } - *mlen = alen; - *m = xmalloc (alen); - memcpy (*m, a, alen); - - a = find_tlv (keydata, keydatalen, 0x0082, &alen); - if (!a) - { - log_error (_("response does not contain the RSA public exponent\n")); - rc = gpg_error (GPG_ERR_CARD); - goto leave; - } - *elen = alen; - *e = xmalloc (alen); - memcpy (*e, a, alen); - - leave: - xfree (buffer); - if (rc) - { - xfree (*m); *m = NULL; - xfree (*e); *e = NULL; - } - return rc; -} diff --git a/scd/command.c b/scd/command.c index c68d0e925..738b1f003 100644 --- a/scd/command.c +++ b/scd/command.c @@ -1095,7 +1095,7 @@ cmd_random (assuan_context_t ctx, char *line) /* PASSWD [--reset] - Change the PIN or reset thye retry counter of the card holder + Change the PIN or reset the retry counter of the card holder verfication vector CHVNO. */ static int cmd_passwd (assuan_context_t ctx, char *line) @@ -1142,7 +1142,23 @@ cmd_passwd (assuan_context_t ctx, char *line) } -/* CHECKPIN +/* CHECKPIN + + Perform a VERIFY operation without doing anything else. This may + be used to initialize a the PIN cache earlier to long lasting + operations. Its use is highly application dependent. + + For OpenPGP: + + Perform a simple verify operation for CHV1 and CHV2, so that + further operations won't ask for CHV2 and it is possible to do a + cheap check on the PIN: If there is something wrong with the PIN + entry system, only the regular CHV will get blocked and not the + dangerous CHV3. IDSTR is the usual card's serial number in hex + notation; an optional fingerprint part will get ignored. There + is however a special mode if the IDSTR is sffixed with the + literal string "[CHV3]": In this case the Admin PIN is checked + if and only if the retry counter is still at 3. */ static int -- cgit From e96af3715b9b126b435c7887e47a660a73bf237b Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 24 May 2005 12:37:36 +0000 Subject: * call-scd.c (inq_needpin): Skip leading spaces in of PIN description. * divert-scd.c (getpin_cb): Enhanced to cope with description flags. * query.c (agent_askpin): Add arg PROMPT_TEXT. Changed all callers. --- TODO | 8 ----- agent/ChangeLog | 9 +++++ agent/agent.h | 3 +- agent/call-scd.c | 2 ++ agent/command-ssh.c | 2 +- agent/divert-scd.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++------ agent/findkey.c | 2 +- agent/genkey.c | 8 ++--- agent/query.c | 18 ++++++---- scd/app-openpgp.c | 4 +-- 10 files changed, 121 insertions(+), 35 deletions(-) (limited to 'scd/app-openpgp.c') diff --git a/TODO b/TODO index fe10e9f77..74763a71f 100644 --- a/TODO +++ b/TODO @@ -96,11 +96,3 @@ might want to have an agent context for each service request -* IMPORTANT: - Check that the PIN cache is cleared after failed card operations. - After receiving a HUP gpg-agent should set a flag to kill scdaemon - as soon as possible, w/o that scdaemon will continue running as a - zombie and gpg-agent won't be able to fire up a new one. - Implement an scd/agent option to wait for a card. - - diff --git a/agent/ChangeLog b/agent/ChangeLog index 6c271c8e2..dcf0cdfd3 100644 --- a/agent/ChangeLog +++ b/agent/ChangeLog @@ -1,3 +1,12 @@ +2005-05-24 Werner Koch + + * call-scd.c (inq_needpin): Skip leading spaces in of PIN + description. + * divert-scd.c (getpin_cb): Enhanced to cope with description + flags. + * query.c (agent_askpin): Add arg PROMPT_TEXT. Changed all + callers. + 2005-05-21 Werner Koch * call-scd.c (start_scd): Don't test for an alive scdaemon here. diff --git a/agent/agent.h b/agent/agent.h index 7e4f555e8..e416914cf 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -179,7 +179,8 @@ int agent_key_available (const unsigned char *grip); /*-- query.c --*/ void initialize_module_query (void); int agent_askpin (ctrl_t ctrl, - const char *desc_text, const char *inital_errtext, + const char *desc_text, const char *prompt_text, + const char *inital_errtext, struct pin_entry_info_s *pininfo); int agent_get_passphrase (ctrl_t ctrl, char **retpass, const char *desc, const char *prompt, diff --git a/agent/call-scd.c b/agent/call-scd.c index 617ef0d48..78e28fe97 100644 --- a/agent/call-scd.c +++ b/agent/call-scd.c @@ -601,6 +601,8 @@ inq_needpin (void *opaque, const char *line) return ASSUAN_Inquire_Unknown; } line += 7; + while (*line == ' ') + line++; pinlen = 90; pin = gcry_malloc_secure (pinlen); diff --git a/agent/command-ssh.c b/agent/command-ssh.c index 92a84c662..030cc70a0 100644 --- a/agent/command-ssh.c +++ b/agent/command-ssh.c @@ -2369,7 +2369,7 @@ ssh_identity_register (ctrl_t ctrl, gcry_sexp_t key, int ttl) } pi->max_length = 100; pi->max_tries = 1; - err = agent_askpin (ctrl, description, NULL, pi); + err = agent_askpin (ctrl, description, NULL, NULL, pi); if (err) goto out; diff --git a/agent/divert-scd.c b/agent/divert-scd.c index f460ffe0c..41a5dfcda 100644 --- a/agent/divert-scd.c +++ b/agent/divert-scd.c @@ -168,35 +168,113 @@ encode_md_for_card (const unsigned char *digest, size_t digestlen, int algo, buf has been allocated by the caller and is of size MAXBUF which includes the terminating null. The function should return an UTF-8 string with the passphrase, the buffer may optionally be padded - with arbitrary characters */ + with arbitrary characters. + + INFO gets displayed as part of a generic string. However if the + first character of INFO is a vertical bar all up to the next + verical bar are considered flags and only everything after the + second vertical bar gets displayed as the full prompt. + + Flags: + + 'N' = New PIN, this requests a second prompt to repeat the the + PIN. If the PIN is not correctly repeated it starts from + all over. + 'A' = The PIN is an Admin PIN, SO-PIN, PUK or alike. + + Example: + + "|AN|Please enter the new security officer's PIN" + + The text "Please ..." will get displayed and the flags 'A' and 'N' + are considered. + */ static int getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf) { struct pin_entry_info_s *pi; int rc; - char *desc; - CTRL ctrl = opaque; + ctrl_t ctrl = opaque; + const char *ends, *s; + int any_flags = 0; + int newpin = 0; + const char *again_text = NULL; + const char *prompt = "PIN"; if (maxbuf < 2) return gpg_error (GPG_ERR_INV_VALUE); + /* Parse the flags. */ + if (info && *info =='|' && (ends=strchr (info+1, '|'))) + { + for (s=info+1; s < ends; s++) + { + if (*s == 'A') + prompt = _("Admin PIN"); + else if (*s == 'N') + newpin = 1; + } + info = ends+1; + any_flags = 1; + } + else if (info && *info == '|') + log_debug ("pin_cb called without proper PIN info hack\n"); + /* FIXME: keep PI and TRIES in OPAQUE. Frankly this is a whole mess because we should call the card's verify function from the pinentry check pin CB. */ - pi = gcry_calloc_secure (1, sizeof (*pi) + 100); + again: + pi = gcry_calloc_secure (1, sizeof (*pi) + maxbuf + 10); + if (!pi) + return gpg_error_from_errno (errno); pi->max_length = maxbuf-1; pi->min_digits = 0; /* we want a real passphrase */ pi->max_digits = 8; pi->max_tries = 3; - if ( asprintf (&desc, _("Please enter the PIN%s%s%s to unlock the card"), - info? " (`":"", - info? info:"", - info? "')":"") < 0) - desc = NULL; - rc = agent_askpin (ctrl, desc?desc:info, NULL, pi); - free (desc); + if (any_flags) + { + rc = agent_askpin (ctrl, info, prompt, again_text, pi); + again_text = NULL; + if (!rc && newpin) + { + struct pin_entry_info_s *pi2; + pi2 = gcry_calloc_secure (1, sizeof (*pi) + maxbuf + 10); + if (!pi2) + { + rc = gpg_error_from_errno (errno); + xfree (pi); + return rc; + } + pi2->max_length = maxbuf-1; + pi2->min_digits = 0; + pi2->max_digits = 8; + pi2->max_tries = 1; + rc = agent_askpin (ctrl, _("Repeat this PIN"), prompt, NULL, pi2); + if (!rc && strcmp (pi->pin, pi2->pin)) + { + again_text = N_("PIN not correctly repeated; try again"); + xfree (pi2); + xfree (pi); + goto again; + } + xfree (pi2); + } + } + else + { + char *desc; + if ( asprintf (&desc, + _("Please enter the PIN%s%s%s to unlock the card"), + info? " (`":"", + info? info:"", + info? "')":"") < 0) + desc = NULL; + rc = agent_askpin (ctrl, desc?desc:info, prompt, NULL, pi); + free (desc); + } + if (!rc) { strncpy (buf, pi->pin, maxbuf-1); diff --git a/agent/findkey.c b/agent/findkey.c index 0b5816bf5..999a5d620 100644 --- a/agent/findkey.c +++ b/agent/findkey.c @@ -276,7 +276,7 @@ unprotect (CTRL ctrl, const char *desc_text, arg.unprotected_key = NULL; pi->check_cb_arg = &arg; - rc = agent_askpin (ctrl, desc_text, NULL, pi); + rc = agent_askpin (ctrl, desc_text, NULL, NULL, pi); if (!rc) { assert (arg.unprotected_key); diff --git a/agent/genkey.c b/agent/genkey.c index 17d85f77c..e07518d5a 100644 --- a/agent/genkey.c +++ b/agent/genkey.c @@ -120,11 +120,11 @@ agent_genkey (CTRL ctrl, const char *keyparam, size_t keyparamlen, pi2->check_cb_arg = pi->pin; next_try: - rc = agent_askpin (ctrl, text1, initial_errtext, pi); + rc = agent_askpin (ctrl, text1, NULL, initial_errtext, pi); initial_errtext = NULL; if (!rc) { - rc = agent_askpin (ctrl, text2, NULL, pi2); + rc = agent_askpin (ctrl, text2, NULL, NULL, pi2); if (rc == -1) { /* The re-entered one did not match and the user did not hit cancel. */ @@ -228,10 +228,10 @@ agent_protect_and_store (CTRL ctrl, gcry_sexp_t s_skey) pi2->check_cb_arg = pi->pin; next_try: - rc = agent_askpin (ctrl, text1, initial_errtext, pi); + rc = agent_askpin (ctrl, text1, NULL, initial_errtext, pi); if (!rc) { - rc = agent_askpin (ctrl, text2, NULL, pi2); + rc = agent_askpin (ctrl, text2, NULL, NULL, pi2); if (rc == -1) { /* The re-entered one did not match and the user did not hit cancel. */ diff --git a/agent/query.c b/agent/query.c index 622a2662c..d3b42a416 100644 --- a/agent/query.c +++ b/agent/query.c @@ -288,8 +288,9 @@ all_digitsp( const char *s) number here and repeat it as long as we have invalid formed numbers. */ int -agent_askpin (CTRL ctrl, - const char *desc_text, const char *initial_errtext, +agent_askpin (ctrl_t ctrl, + const char *desc_text, const char *prompt_text, + const char *initial_errtext, struct pin_entry_info_s *pininfo) { int rc; @@ -310,7 +311,10 @@ agent_askpin (CTRL ctrl, desc_text = _("Please enter your passphrase, so that the secret key " "can be unlocked for this session"); - is_pin = desc_text && strstr (desc_text, "PIN"); + if (prompt_text) + is_pin = !!strstr (prompt_text, "PIN"); + else + is_pin = desc_text && strstr (desc_text, "PIN"); rc = start_pinentry (ctrl); if (rc) @@ -322,10 +326,10 @@ agent_askpin (CTRL ctrl, if (rc) return unlock_pinentry (map_assuan_err (rc)); - rc = assuan_transact (entry_ctx, - is_pin? "SETPROMPT PIN:" - : "SETPROMPT Passphrase:", - NULL, NULL, NULL, NULL, NULL, NULL); + snprintf (line, DIM(line)-1, "SETPROMPT %s", + prompt_text? prompt_text : is_pin? "PIN:" : "Passphrase:"); + line[DIM(line)-1] = 0; + rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); if (rc) return unlock_pinentry (map_assuan_err (rc)); diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 91e208a0a..14483869b 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -1528,7 +1528,7 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, int reset_mode, /* Check whether a key already exists. KEYIDX is the index of the key - (0..2). If FORCE is TRUE a diagnositivc will be printed but no + (0..2). If FORCE is TRUE a diagnositic will be printed but no error returned if the key already exists. */ static gpg_error_t does_key_exist (app_t app, int keyidx, int force) @@ -2134,7 +2134,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, { char *prompt; -#define PROMPTSTRING _("PIN [sigs done: %lu]") +#define PROMPTSTRING _("||Please enter the PIN%%0A[sigs done: %lu]") prompt = malloc (strlen (PROMPTSTRING) + 50); if (!prompt) -- cgit From f1dac8851d02a0cb63fc7379ee74692856d0cf39 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 3 Jun 2005 13:57:24 +0000 Subject: * command.c (cmd_updatestartuptty): New. * gpg-agent.c: New option --write-env-file. * gpg-agent.c (handle_connections): Make sure that the signals we are handling are not blocked.Block signals while creating new threads. * estream.c: Use HAVE_CONFIG_H and not USE_CONFIG_H! (es_func_fd_read, es_func_fd_write): Protect against EINTR. * gpg-agent.texi (Agent UPDATESTARTUPTTY): New. * scdaemon.c (handle_connections): Make sure that the signals we are handling are not blocked.Block signals while creating new threads. (handle_connections): Include the file descriptor into the name of the thread. --- ChangeLog | 5 ++ NEWS | 3 + TODO | 7 +++ agent/ChangeLog | 17 ++++++ agent/agent.h | 14 +++-- agent/call-scd.c | 30 ++++++++++ agent/command.c | 34 +++++++++++ agent/gpg-agent.c | 104 ++++++++++++++++++++++++++------- common/ChangeLog | 6 ++ common/estream.c | 10 +++- configure.ac | 3 + doc/ChangeLog | 4 ++ doc/gpg-agent.texi | 60 +++++++++++++++---- scd/ChangeLog | 29 ++++++++++ scd/app-common.h | 6 ++ scd/app-openpgp.c | 2 +- scd/app.c | 167 ++++++++++++++++++++++++++++++++++++++--------------- scd/command.c | 6 +- scd/scdaemon.c | 33 ++++++++--- scd/scdaemon.h | 23 +++++--- 20 files changed, 459 insertions(+), 104 deletions(-) (limited to 'scd/app-openpgp.c') diff --git a/ChangeLog b/ChangeLog index fbd9ad79d..f7efcee89 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2005-06-02 Werner Koch + + * configure.ac (HAVE_PTH): Define as alias for USE_GNU_PTH. It is + used by common/estream.c. + 2005-06-01 Werner Koch * configure.ac (gl_INIT): Add gnulib stuff. diff --git a/NEWS b/NEWS index 79a74cbe4..e28f1284a 100644 --- a/NEWS +++ b/NEWS @@ -13,6 +13,9 @@ Noteworthy changes in version 1.9.17 does allows only signing using TCOS cards but we are going to enhance it to match all the old capabilities. + * [gpg-agent] New option --rite-env-file and Assuan command + UPDATESTARTUPTTY. + Noteworthy changes in version 1.9.16 (2005-04-21) ------------------------------------------------- diff --git a/TODO b/TODO index 74763a71f..5f1b57a0f 100644 --- a/TODO +++ b/TODO @@ -72,6 +72,13 @@ might want to have an agent context for each service request we can change all S-expression handling code to make use of this function. +* scd +** Application context vs. reader slot + We have 2 concurrent method of tracking whether a read is in use: + Using the session_list in command.c and the lock_table in app.c. IT + would be better to do this just at one place. First we need to see + how we can support cards with multiple applications. + * tests ** Makefile.am We use printf(1) to setup the library path, this is not portable. diff --git a/agent/ChangeLog b/agent/ChangeLog index 9c57ad43e..9621e5de0 100644 --- a/agent/ChangeLog +++ b/agent/ChangeLog @@ -1,3 +1,20 @@ +2005-06-03 Werner Koch + + * command.c (cmd_updatestartuptty): New. + + * gpg-agent.c: New option --write-env-file. + + * gpg-agent.c (handle_connections): Make sure that the signals we + are handling are not blocked.Block signals while creating new + threads. + +2005-06-02 Werner Koch + + * call-scd.c (agent_scd_dump_state, dump_mutex_state): New. + * gpg-agent.c (handle_signal): Print it on SIGUSR1. + (handle_connections): Include the file descriptor into the + threadnames. + 2005-06-01 Werner Koch * gpg-agent.c: Include setenv.h. diff --git a/agent/agent.h b/agent/agent.h index a667c0d46..51e66abee 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -54,12 +54,13 @@ struct { int batch; /* Batch mode */ const char *homedir; /* Configuration directory name */ - /* Environment setting gathred at program start. */ - const char *startup_display; - const char *startup_ttyname; - const char *startup_ttytype; - const char *startup_lc_ctype; - const char *startup_lc_messages; + /* Environment setting gathered at program start or hanged using the + Assuan command UPDATESTARTUPTTY. */ + char *startup_display; + char *startup_ttyname; + char *startup_ttytype; + char *startup_lc_ctype; + char *startup_lc_messages; const char *pinentry_program; /* Filename of the program to start as @@ -248,6 +249,7 @@ int divert_generic_cmd (ctrl_t ctrl, /*-- call-scd.c --*/ void initialize_module_call_scd (void); +void agent_scd_dump_state (void); void agent_scd_check_aliveness (void); int agent_reset_scd (ctrl_t ctrl); int agent_card_learn (ctrl_t ctrl, diff --git a/agent/call-scd.c b/agent/call-scd.c index 78e28fe97..00c9df2a7 100644 --- a/agent/call-scd.c +++ b/agent/call-scd.c @@ -116,6 +116,35 @@ initialize_module_call_scd (void) } +static void +dump_mutex_state (pth_mutex_t *m) +{ + if (!(m->mx_state & PTH_MUTEX_INITIALIZED)) + log_printf ("not_initialized"); + else if (!(m->mx_state & PTH_MUTEX_LOCKED)) + log_printf ("not_locked"); + else + log_printf ("locked tid=0x%lx count=%lu", (long)m->mx_owner, m->mx_count); +} + + +/* This function may be called to print infromation pertaining to the + current state of this module to the log. */ +void +agent_scd_dump_state (void) +{ + log_info ("agent_scd_dump_state: scd_lock="); + dump_mutex_state (&start_scd_lock); + log_printf ("\n"); + log_info ("agent_scd_dump_state: primary_scd_ctx=%p pid=%ld reusable=%d\n", + primary_scd_ctx, + (long)assuan_get_pid (primary_scd_ctx), + primary_scd_ctx_reusable); + if (socket_name) + log_info ("agent_scd_dump_state: socket=`%s'\n", socket_name); +} + + /* The unlock_scd function shall be called after having accessed the SCD. It is currently not very useful but gives an opportunity to keep track of connections currently calling SCD. Note that the @@ -384,6 +413,7 @@ agent_scd_check_aliveness (void) } + /* Reset the SCD if it has been used. */ int agent_reset_scd (ctrl_t ctrl) diff --git a/agent/command.c b/agent/command.c index 8af159f6d..56167118d 100644 --- a/agent/command.c +++ b/agent/command.c @@ -867,6 +867,39 @@ cmd_scd (ASSUAN_CONTEXT ctx, char *line) } + +/* UPDATESTARTUPTTY + + Set startup TTY and X DISPLAY variables to the values of this + session. This command is useful to pull future pinentries to + another screen. It is only required because there is no way in the + ssh-agent protocol to convey this information. */ +static int +cmd_updatestartuptty (assuan_context_t ctx, char *line) +{ + ctrl_t ctrl = assuan_get_pointer (ctx); + + xfree (opt.startup_display); opt.startup_display = NULL; + xfree (opt.startup_ttyname); opt.startup_ttyname = NULL; + xfree (opt.startup_ttytype); opt.startup_ttytype = NULL; + xfree (opt.startup_lc_ctype); opt.startup_lc_ctype = NULL; + xfree (opt.startup_lc_messages); opt.startup_lc_messages = NULL; + + if (ctrl->display) + opt.startup_display = xtrystrdup (ctrl->display); + if (ctrl->ttyname) + opt.startup_ttyname = xtrystrdup (ctrl->ttyname); + if (ctrl->ttytype) + opt.startup_ttytype = xtrystrdup (ctrl->ttytype); + if (ctrl->lc_ctype) + opt.startup_lc_ctype = xtrystrdup (ctrl->lc_ctype); + if (ctrl->lc_messages) + opt.startup_lc_messages = xtrystrdup (ctrl->lc_messages); + + return 0; +} + + static int option_handler (ASSUAN_CONTEXT ctx, const char *key, const char *value) @@ -957,6 +990,7 @@ register_commands (ASSUAN_CONTEXT ctx) { "INPUT", NULL }, { "OUTPUT", NULL }, { "SCD", cmd_scd }, + { "UPDATESTARTUPTTY", cmd_updatestartuptty }, { NULL } }; int i, rc; diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c index 3537b07f0..90b071d5e 100644 --- a/agent/gpg-agent.c +++ b/agent/gpg-agent.c @@ -93,7 +93,8 @@ enum cmd_and_opt_values oKeepTTY, oKeepDISPLAY, oSSHSupport, - oDisableScdaemon + oDisableScdaemon, + oWriteEnvFile }; @@ -147,6 +148,8 @@ static ARGPARSE_OPTS opts[] = { { oAllowPresetPassphrase, "allow-preset-passphrase", 0, N_("allow presetting passphrase")}, { oSSHSupport, "enable-ssh-support", 0, N_("enable ssh-agent emulation") }, + { oWriteEnvFile, "write-env-file", 2, + N_("|FILE|write environment settings also to FILE")}, {0} }; @@ -438,6 +441,7 @@ main (int argc, char **argv ) int gpgconf_list = 0; int standard_socket = 0; gpg_error_t err; + const char *env_file_name = NULL; set_strusage (my_strusage); gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN); @@ -501,7 +505,7 @@ main (int argc, char **argv ) opt.startup_ttytype = getenv ("TERM"); if (opt.startup_ttytype) opt.startup_ttytype = xstrdup (opt.startup_ttytype); - /* Fixme: Neen to use the locale fucntion here. */ + /* Fixme: Better use the locale function here. */ opt.startup_lc_ctype = getenv ("LC_CTYPE"); if (opt.startup_lc_ctype) opt.startup_lc_ctype = xstrdup (opt.startup_lc_ctype); @@ -619,6 +623,7 @@ main (int argc, char **argv ) case oKeepDISPLAY: opt.keep_display = 1; break; case oSSHSupport: opt.ssh_support = 1; break; + case oWriteEnvFile: env_file_name = pargs.r.ret_str; break; default : pargs.err = configfp? 1:2; break; } @@ -855,6 +860,29 @@ main (int argc, char **argv ) if (opt.ssh_support) *socket_name_ssh = 0; + if (env_file_name) + { + FILE *fp; + + fp = fopen (env_file_name, "w"); + if (!fp) + log_error (_("error creating `%s': %s\n"), + env_file_name, strerror (errno)); + else + { + fputs (infostr, fp); + putc ('\n', fp); + if (opt.ssh_support) + { + fputs (infostr_ssh_sock, fp); + putc ('\n', fp); + fputs (infostr_ssh_pid, fp); + putc ('\n', fp); + } + fclose (fp); + } + } + if (argc) { /* Run the program given on the commandline. */ @@ -1273,7 +1301,7 @@ create_directories (void) static void handle_tick (void) { - /* Check whether the scdaemon has dies and cleanup in this case. */ + /* Check whether the scdaemon has died and cleanup in this case. */ agent_scd_check_aliveness (); /* If we are running as a child of another process, check whether @@ -1311,6 +1339,7 @@ handle_signal (int signo) case SIGUSR1: log_info ("SIGUSR1 received - printing internal information:\n"); pth_ctrl (PTH_CTRL_DUMPSTATE, log_get_stream ()); + agent_scd_dump_state (); break; case SIGUSR2: @@ -1353,7 +1382,8 @@ start_connection_thread (void *arg) int fd = (int)arg; if (opt.verbose) - log_info (_("handler for fd %d started\n"), fd); + log_info (_("handler 0x%lx for fd %d started\n"), + (long)pth_self (), fd); /* FIXME: Move this housekeeping into a ticker function. Calling it for each connection should work but won't work anymore if our @@ -1362,7 +1392,8 @@ start_connection_thread (void *arg) start_command_handler (-1, fd); if (opt.verbose) - log_info (_("handler for fd %d terminated\n"), fd); + log_info (_("handler 0x%lx for fd %d terminated\n"), + (long)pth_self (), fd); return NULL; } @@ -1375,13 +1406,15 @@ start_connection_thread_ssh (void *arg) int fd = (int)arg; if (opt.verbose) - log_info (_("ssh handler for fd %d started\n"), fd); + log_info (_("ssh handler 0x%lx for fd %d started\n"), + (long)pth_self (), fd); agent_trustlist_housekeeping (); start_command_handler_ssh (fd); if (opt.verbose) - log_info (_("ssh handler for fd %d terminated\n"), fd); + log_info (_("ssh handler 0x%lx for fd %d terminated\n"), + (long)pth_self (), fd); return NULL; } @@ -1405,15 +1438,17 @@ handle_connections (int listen_fd, int listen_fd_ssh) tattr = pth_attr_new(); pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0); pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 256*1024); - pth_attr_set (tattr, PTH_ATTR_NAME, "gpg-agent"); #ifndef HAVE_W32_SYSTEM /* fixme */ + /* Make sure that the signals we are going to handle are not blocked + and create an event object for them. */ sigemptyset (&sigs ); sigaddset (&sigs, SIGHUP); sigaddset (&sigs, SIGUSR1); sigaddset (&sigs, SIGUSR2); sigaddset (&sigs, SIGINT); sigaddset (&sigs, SIGTERM); + pth_sigmask (SIG_UNBLOCK, &sigs, NULL); ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo); #else ev = NULL; @@ -1427,6 +1462,8 @@ handle_connections (int listen_fd, int listen_fd_ssh) for (;;) { + sigset_t oldsigs; + if (shutdown_pending) { if (pth_ctrl (PTH_CTRL_GETTHREADS) == 1) @@ -1488,6 +1525,12 @@ handle_connections (int listen_fd, int listen_fd_ssh) handle_tick (); } + + /* We now might create new threads and because we don't want any + signals - we are handling here - to be delivered to a new + thread. Thus we need to block those signals. */ + pth_sigmask (SIG_BLOCK, &sigs, &oldsigs); + if (FD_ISSET (listen_fd, &read_fdset)) { plen = sizeof paddr; @@ -1496,12 +1539,20 @@ handle_connections (int listen_fd, int listen_fd_ssh) { log_error ("accept failed: %s\n", strerror (errno)); } - else if (!pth_spawn (tattr, start_connection_thread, (void*)fd)) - { - log_error ("error spawning connection handler: %s\n", - strerror (errno) ); - close (fd); - } + else + { + char threadname[50]; + snprintf (threadname, sizeof threadname-1, + "conn fd=%d (gpg)", fd); + threadname[sizeof threadname -1] = 0; + pth_attr_set (tattr, PTH_ATTR_NAME, threadname); + if (!pth_spawn (tattr, start_connection_thread, (void*)fd)) + { + log_error ("error spawning connection handler: %s\n", + strerror (errno) ); + close (fd); + } + } fd = -1; } @@ -1513,14 +1564,27 @@ handle_connections (int listen_fd, int listen_fd_ssh) { log_error ("accept failed for ssh: %s\n", strerror (errno)); } - else if (!pth_spawn (tattr, start_connection_thread_ssh, (void*)fd)) - { - log_error ("error spawning ssh connection handler: %s\n", - strerror (errno) ); - close (fd); - } + else + { + char threadname[50]; + snprintf (threadname, sizeof threadname-1, + "conn fd=%d (ssh)", fd); + threadname[sizeof threadname -1] = 0; + pth_attr_set (tattr, PTH_ATTR_NAME, threadname); + + if (!pth_spawn (tattr, start_connection_thread_ssh, (void*)fd)) + { + log_error ("error spawning ssh connection handler: %s\n", + strerror (errno) ); + close (fd); + } + } fd = -1; } + + /* Restore the signal mask. */ + pth_sigmask (SIG_SETMASK, &oldsigs, NULL); + } pth_event_free (ev, PTH_FREE_ALL); diff --git a/common/ChangeLog b/common/ChangeLog index fccc71d49..08fb06775 100644 --- a/common/ChangeLog +++ b/common/ChangeLog @@ -1,3 +1,9 @@ +2005-06-03 Werner Koch + + * estream.c: Use HAVE_CONFIG_H and not USE_CONFIG_H! + (es_func_fd_read, es_func_fd_write): Protect against EINTR. + + 2005-06-01 Werner Koch * Makefile.am (AM_CPPFLAGS): Added. diff --git a/common/estream.c b/common/estream.c index 00cb749e8..bf5b02001 100644 --- a/common/estream.c +++ b/common/estream.c @@ -22,7 +22,7 @@ # include #endif -#ifdef USE_CONFIG_H +#ifdef HAVE_CONFIG_H # include #endif @@ -597,7 +597,9 @@ es_func_fd_read (void *cookie, char *buffer, size_t size) estream_cookie_fd_t file_cookie = cookie; ssize_t bytes_read; - bytes_read = ESTREAM_SYS_READ (file_cookie->fd, buffer, size); + do + bytes_read = ESTREAM_SYS_READ (file_cookie->fd, buffer, size); + while (bytes_read == -1 && errno == EINTR); return bytes_read; } @@ -610,7 +612,9 @@ es_func_fd_write (void *cookie, const char *buffer, size_t size) estream_cookie_fd_t file_cookie = cookie; ssize_t bytes_written; - bytes_written = ESTREAM_SYS_WRITE (file_cookie->fd, buffer, size); + do + bytes_written = ESTREAM_SYS_WRITE (file_cookie->fd, buffer, size); + while (bytes_written == -1 && errno == EINTR); return bytes_written; } diff --git a/configure.ac b/configure.ac index c1a3d77ea..17465c520 100644 --- a/configure.ac +++ b/configure.ac @@ -531,6 +531,8 @@ if test "$have_w32_system" = no; then PTH_LIBS="$PTH_LIBS `$PTH_CONFIG --libs`" AC_DEFINE(USE_GNU_PTH, 1, [Defined if the GNU Portable Thread Library should be used]) + AC_DEFINE(HAVE_PTH, 1, + [Defined if the GNU Pth is available]) fi fi else @@ -538,6 +540,7 @@ else PTH_CFLAGS="" PTH_LIBS="" AC_DEFINE(USE_GNU_PTH, 1) + AC_DEFINE(HAVE_PTH, 1) fi AC_SUBST(PTH_CFLAGS) AC_SUBST(PTH_LIBS) diff --git a/doc/ChangeLog b/doc/ChangeLog index 25840a5b1..f353bdf03 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,7 @@ +2005-06-03 Werner Koch + + * gpg-agent.texi (Agent UPDATESTARTUPTTY): New. + 2005-05-17 Werner Koch * gpg-agent.texi (Agent Options): Removed --disable-pth. diff --git a/doc/gpg-agent.texi b/doc/gpg-agent.texi index fa005c3b7..5e8c19468 100644 --- a/doc/gpg-agent.texi +++ b/doc/gpg-agent.texi @@ -25,11 +25,11 @@ eval `gpg-agent --daemon` @noindent If you don't use an X server, you can also put this into your regular startup file @code{~/.profile} or @code{.bash_profile}. It is best not -to run multiple instance of the @command{gpg-agent}, so you should make sure that -only is running: @command{gpg-agent} uses an environment variable to inform -clients about the communication parameters. You can write the -content of this environment variable to a file so that you can test for -a running agent. This short script may do the job: +to run multiple instance of the @command{gpg-agent}, so you should make +sure that only one is running: @command{gpg-agent} uses an environment +variable to inform clients about the communication parameters. You can +write the content of this environment variable to a file so that you can +test for a running agent. This short script may do the job: @smallexample if test -f $HOME/.gpg-agent-info && \ @@ -42,6 +42,9 @@ else fi @end smallexample +The new option @option{--write-env-file} may be used instead. + + @noindent You should always add the following lines to your @code{.bashrc} or whatever initialization file is used for all shell invocations: @@ -243,6 +246,21 @@ shell respective the C-shell . The default ist to guess it based on the environment variable @code{SHELL} which is in almost all cases sufficient. +@item --write-env-file @var{file} +@opindex write-env-file +Often it is required to connect to the agent from a process not being an +inferior of @command{gpg-agent} and thus the environment variable with +the socket name is not available. To help setting up those variables in +other sessions, this option may be used to write the information into +@var{file}. The format is suitable to be evaluated by a Bourne shell +like in this simple example: + +@example +eval `cat @var{file}` +eval `cut -d= -f 1 < @var{file} | xargs echo export` +@end example + + @item --no-grab @opindex no-grab Tell the pinentryo not to grab the keyboard and mouse. This option @@ -353,12 +371,19 @@ directory. Once, a key has been added to the gpg-agent this way, the gpg-agent will be ready to use the key. -Note: in case the gpg-agent receives a signature request, the user -might need to be prompted for a passphrase, which is necessary for -decrypting the stored key. Since the ssh-agent protocol does not -contain a mechanism for telling the agent on which display/terminal it -is running, gpg-agent's ssh-support will use the TTY or X display where -gpg-agent has been started. +Note: in case the gpg-agent receives a signature request, the user might +need to be prompted for a passphrase, which is necessary for decrypting +the stored key. Since the ssh-agent protocol does not contain a +mechanism for telling the agent on which display/terminal it is running, +gpg-agent's ssh-support will use the TTY or X display where gpg-agent +has been started. To switch this display to the current one, the +follwing command may be used: + +@smallexample +echo UPDATESTARTUPTTY | gpg-connect-agent +@end smallexample + + @end table @@ -544,6 +569,7 @@ secret keys. * Agent HAVEKEY:: Check whether a key is available * Agent LEARN:: Register a smartcard * Agent PASSWD:: Change a Passphrase +* Agent UPDATESTARTUPTTY:: Change the Standard Display @end menu @node Agent PKDECRYPT @@ -944,4 +970,16 @@ This command is used to interactively change the passphrase of the key indentified by the hex string @var{keygrip}. +@node Agent UPDATESTARTUPTTY +@subsection Change the standard display + +@example + UPDATESTARTUPTTY +@end example + +Set the startup TTY and X-DISPLAY variables to the values of this +session. This command is useful to direct future pinentry invocations +to another screen. It is only required because there is no way in the +ssh-agent protocol to convey this information. + diff --git a/scd/ChangeLog b/scd/ChangeLog index 136ed5618..da433e2f8 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,32 @@ +2005-06-03 Werner Koch + + * scdaemon.c (handle_connections): Make sure that the signals we + are handling are not blocked.Block signals while creating new + threads. + (handle_connections): Include the file descriptor into the name of + the thread. + +2005-06-02 Werner Koch + + * app.c (app_dump_state, dump_mutex_state): New. + * scdaemon.c (handle_signal): Print it on SIGUSR1. + + * app-openpgp.c (do_writekey): Typo fix. + + * command.c (open_card): Check for locked state even if an + application context is available. + + * app-common.h: Add REF_COUNT field. + * app.c (release_application, select_application): Implement + reference counting to share the context beween connections. + + * app.c (lock_reader, unlock_reader): Take SLOT instead of APP as + argument. Changed all callers. + (select_application): Unlock the reader on error. This should fix + the hangs I noticed last week. + + * scdaemon.h: Removed card_ctx_t cruft. + 2005-06-01 Werner Koch * scdaemon.c: Include mkdtemp.h. diff --git a/scd/app-common.h b/scd/app-common.h index 812736ece..94087f221 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -39,6 +39,11 @@ struct app_ctx_s { function pointers may be used. Note that for unsupported operations the particular function pointer is set to NULL */ + + int ref_count; /* Number of connections currently using this + application context. fixme: We might want to + merg this witghn INITIALIZED above. */ + int slot; /* Used reader. */ /* If this is used by GnuPG 1.4 we need to know the assuan context @@ -123,6 +128,7 @@ size_t app_help_read_length_of_cert (int slot, int fid, size_t *r_certoff); /*-- app.c --*/ +void app_dump_state (void); gpg_error_t select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app); void release_application (app_t app); diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 14483869b..1ff096138 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -1745,7 +1745,7 @@ do_writekey (app_t app, ctrl_t ctrl, nbits = rsa_e? count_bits (rsa_e, rsa_e_len) : 0; if (nbits < 2 || nbits > 32) { - log_error (_("RSA public exponent missing or largerr than %d bits\n"), + log_error (_("RSA public exponent missing or larger than %d bits\n"), 32); err = gpg_error (GPG_ERR_BAD_SECKEY); goto leave; diff --git a/scd/app.c b/scd/app.c index f2c427f5b..2c8c915d7 100644 --- a/scd/app.c +++ b/scd/app.c @@ -39,25 +39,24 @@ static struct { int initialized; pth_mutex_t lock; + app_t app; /* Application context in use or NULL. */ } lock_table[10]; -/* Lock the reader associated with the APP context. This function - shall be used right before calling any of the actual application - functions to serialize access to the reader. We do this always - even if the reader is not actually used. This allows an actual - application to assume that it never shares a reader (while - performing one command). Returns 0 on success; only then the - unlock_reader function must be called after returning from the - handler. */ +/* Lock the reader SLOT. This function shall be used right before + calling any of the actual application functions to serialize access + to the reader. We do this always even if the reader is not + actually used. This allows an actual connection to assume that it + never shares a reader (while performing one command). Returns 0 on + success; only then the unlock_reader function must be called after + returning from the handler. */ static gpg_error_t -lock_reader (app_t app) +lock_reader (int slot) { gpg_error_t err; - int slot = app->slot; if (slot < 0 || slot >= DIM (lock_table)) - return gpg_error (app->slot<0? GPG_ERR_INV_VALUE : GPG_ERR_RESOURCE_LIMIT); + return gpg_error (slot<0? GPG_ERR_INV_VALUE : GPG_ERR_RESOURCE_LIMIT); if (!lock_table[slot].initialized) { @@ -68,6 +67,7 @@ lock_reader (app_t app) return err; } lock_table[slot].initialized = 1; + lock_table[slot].app = NULL; } if (!pth_mutex_acquire (&lock_table[slot].lock, 0, NULL)) @@ -83,10 +83,8 @@ lock_reader (app_t app) /* Release a lock on the reader. See lock_reader(). */ static void -unlock_reader (app_t app) +unlock_reader (int slot) { - int slot = app->slot; - if (slot < 0 || slot >= DIM (lock_table) || !lock_table[slot].initialized) log_bug ("unlock_reader called for invalid slot %d\n", slot); @@ -96,6 +94,39 @@ unlock_reader (app_t app) slot, strerror (errno)); } + + +static void +dump_mutex_state (pth_mutex_t *m) +{ + if (!(m->mx_state & PTH_MUTEX_INITIALIZED)) + log_printf ("not_initialized"); + else if (!(m->mx_state & PTH_MUTEX_LOCKED)) + log_printf ("not_locked"); + else + log_printf ("locked tid=0x%lx count=%lu", (long)m->mx_owner, m->mx_count); +} + + +/* This function may be called to print information pertaining to the + current state of this module to the log. */ +void +app_dump_state (void) +{ + int slot; + + for (slot=0; slot < DIM (lock_table); slot++) + if (lock_table[slot].initialized) + { + log_info ("app_dump_state: slot=%d lock=", slot); + dump_mutex_state (&lock_table[slot].lock); + if (lock_table[slot].app) + log_printf (" app=%p type=`%s'", + lock_table[slot].app, lock_table[slot].app->apptype); + log_printf ("\n"); + } +} + /* Check wether the application NAME is allowed. This does not mean we have support for it though. */ @@ -120,23 +151,48 @@ gpg_error_t select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app) { gpg_error_t err; - app_t app; + app_t app = NULL; unsigned char *result = NULL; size_t resultlen; *r_app = NULL; + + err = lock_reader (slot); + if (err) + return err; + + /* First check whether we already have an application to share. */ + app = lock_table[slot].initialized ? lock_table[slot].app : NULL; + if (app && name) + if (!app->apptype || ascii_strcasecmp (app->apptype, name)) + { + unlock_reader (slot); + if (app->apptype) + log_info ("application `%s' in use by reader %d - can't switch\n", + app->apptype, slot); + return gpg_error (GPG_ERR_CONFLICT); + } + + if (app) + { + if (app->slot != slot) + log_bug ("slot mismatch %d/%d\n", app->slot, slot); + app->ref_count++; + *r_app = app; + unlock_reader (slot); + return 0; /* Okay: We share that one. */ + } + app = xtrycalloc (1, sizeof *app); if (!app) { err = gpg_error_from_errno (errno); log_info ("error allocating context: %s\n", gpg_strerror (err)); + unlock_reader (slot); return err; } app->slot = slot; - err = lock_reader (app); - if (err) - return err; /* Fixme: We should now first check whether a card is at all present. */ @@ -162,7 +218,7 @@ select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app) have some test cards with such an invalid encoding and therefore I use this ugly workaround to return something I can further experiment with. */ - log_debug ("enabling BMI testcard workaround\n"); + log_info ("enabling BMI testcard workaround\n"); n--; } @@ -212,22 +268,41 @@ select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app) log_info ("no supported card application found: %s\n", gpg_strerror (err)); xfree (app); + unlock_reader (slot); return err; } app->initialized = 1; - unlock_reader (app); + app->ref_count = 1; + lock_table[slot].app = app; *r_app = app; + unlock_reader (slot); return 0; } +/* Free the resources associated with the application APP. APP is + allowed to be NULL in which case this is a no-op. Note that we are + using reference counting to track the users of the application. */ void release_application (app_t app) { + int slot; + if (!app) return; + if (app->ref_count < 1) + log_bug ("trying to release an already released context\n"); + if (--app->ref_count) + return; + + /* Clear the reference to the application from the lock table. */ + for (slot = 0; slot < DIM (lock_table); slot++) + if (lock_table[slot].initialized && lock_table[slot].app == app) + lock_table[slot].app = NULL; + + /* Deallocate. */ if (app->fnc.deinit) { app->fnc.deinit (app); @@ -320,11 +395,11 @@ app_write_learn_status (app_t app, CTRL ctrl) if (app->apptype) send_status_info (ctrl, "APPTYPE", app->apptype, strlen (app->apptype), NULL, 0); - err = lock_reader (app); + err = lock_reader (app->slot); if (err) return err; err = app->fnc.learn_status (app, ctrl); - unlock_reader (app); + unlock_reader (app->slot); return err; } @@ -345,11 +420,11 @@ app_readcert (app_t app, const char *certid, return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); if (!app->fnc.readcert) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); - err = lock_reader (app); + err = lock_reader (app->slot); if (err) return err; err = app->fnc.readcert (app, certid, cert, certlen); - unlock_reader (app); + unlock_reader (app->slot); return err; } @@ -377,11 +452,11 @@ app_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen) return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); if (!app->fnc.readkey) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); - err = lock_reader (app); + err = lock_reader (app->slot); if (err) return err; err= app->fnc.readkey (app, keyid, pk, pklen); - unlock_reader (app); + unlock_reader (app->slot); return err; } @@ -419,11 +494,11 @@ app_getattr (app_t app, CTRL ctrl, const char *name) if (!app->fnc.getattr) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); - err = lock_reader (app); + err = lock_reader (app->slot); if (err) return err; err = app->fnc.getattr (app, ctrl, name); - unlock_reader (app); + unlock_reader (app->slot); return err; } @@ -442,11 +517,11 @@ app_setattr (app_t app, const char *name, return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); if (!app->fnc.setattr) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); - err = lock_reader (app); + err = lock_reader (app->slot); if (err) return err; err = app->fnc.setattr (app, name, pincb, pincb_arg, value, valuelen); - unlock_reader (app); + unlock_reader (app->slot); return err; } @@ -468,14 +543,14 @@ app_sign (app_t app, const char *keyidstr, int hashalgo, return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); if (!app->fnc.sign) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); - err = lock_reader (app); + err = lock_reader (app->slot); if (err) return err; err = app->fnc.sign (app, keyidstr, hashalgo, pincb, pincb_arg, indata, indatalen, outdata, outdatalen); - unlock_reader (app); + unlock_reader (app->slot); if (opt.verbose) log_info ("operation sign result: %s\n", gpg_strerror (err)); return err; @@ -500,14 +575,14 @@ app_auth (app_t app, const char *keyidstr, return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); if (!app->fnc.auth) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); - err = lock_reader (app); + err = lock_reader (app->slot); if (err) return err; err = app->fnc.auth (app, keyidstr, pincb, pincb_arg, indata, indatalen, outdata, outdatalen); - unlock_reader (app); + unlock_reader (app->slot); if (opt.verbose) log_info ("operation auth result: %s\n", gpg_strerror (err)); return err; @@ -532,14 +607,14 @@ app_decipher (app_t app, const char *keyidstr, return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); if (!app->fnc.decipher) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); - err = lock_reader (app); + err = lock_reader (app->slot); if (err) return err; err = app->fnc.decipher (app, keyidstr, pincb, pincb_arg, indata, indatalen, outdata, outdatalen); - unlock_reader (app); + unlock_reader (app->slot); if (opt.verbose) log_info ("operation decipher result: %s\n", gpg_strerror (err)); return err; @@ -562,12 +637,12 @@ app_writekey (app_t app, ctrl_t ctrl, return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); if (!app->fnc.writekey) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); - err = lock_reader (app); + err = lock_reader (app->slot); if (err) return err; err = app->fnc.writekey (app, ctrl, keyidstr, flags, pincb, pincb_arg, keydata, keydatalen); - unlock_reader (app); + unlock_reader (app->slot); if (opt.verbose) log_info ("operation writekey result: %s\n", gpg_strerror (err)); return err; @@ -589,11 +664,11 @@ app_genkey (app_t app, CTRL ctrl, const char *keynostr, unsigned int flags, return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); if (!app->fnc.genkey) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); - err = lock_reader (app); + err = lock_reader (app->slot); if (err) return err; err = app->fnc.genkey (app, ctrl, keynostr, flags, pincb, pincb_arg); - unlock_reader (app); + unlock_reader (app->slot); if (opt.verbose) log_info ("operation genkey result: %s\n", gpg_strerror (err)); return err; @@ -612,11 +687,11 @@ app_get_challenge (app_t app, size_t nbytes, unsigned char *buffer) return gpg_error (GPG_ERR_INV_VALUE); if (!app->initialized) return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); - err = lock_reader (app); + err = lock_reader (app->slot); if (err) return err; err = iso7816_get_challenge (app->slot, nbytes, buffer); - unlock_reader (app); + unlock_reader (app->slot); return err; } @@ -636,12 +711,12 @@ app_change_pin (app_t app, CTRL ctrl, const char *chvnostr, int reset_mode, return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); if (!app->fnc.change_pin) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); - err = lock_reader (app); + err = lock_reader (app->slot); if (err) return err; err = app->fnc.change_pin (app, ctrl, chvnostr, reset_mode, pincb, pincb_arg); - unlock_reader (app); + unlock_reader (app->slot); if (opt.verbose) log_info ("operation change_pin result: %s\n", gpg_strerror (err)); return err; @@ -664,11 +739,11 @@ app_check_pin (app_t app, const char *keyidstr, return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); if (!app->fnc.check_pin) return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); - err = lock_reader (app); + err = lock_reader (app->slot); if (err) return err; err = app->fnc.check_pin (app, keyidstr, pincb, pincb_arg); - unlock_reader (app); + unlock_reader (app->slot); if (opt.verbose) log_info ("operation check_pin result: %s\n", gpg_strerror (err)); return err; diff --git a/scd/command.c b/scd/command.c index 738b1f003..287f8c921 100644 --- a/scd/command.c +++ b/scd/command.c @@ -253,12 +253,12 @@ open_card (ctrl_t ctrl, const char *apptype) if (ctrl->server_local->card_removed) return map_to_assuan_status (gpg_error (GPG_ERR_CARD_REMOVED)); - if (ctrl->app_ctx) - return 0; /* Already initialized for one specific application. */ - if ( IS_LOCKED (ctrl) ) return gpg_error (GPG_ERR_LOCKED); + if (ctrl->app_ctx) + return 0; /* Already initialized for one specific application. */ + if (ctrl->reader_slot != -1) slot = ctrl->reader_slot; else diff --git a/scd/scdaemon.c b/scd/scdaemon.c index 341719b1e..5b5e09176 100644 --- a/scd/scdaemon.c +++ b/scd/scdaemon.c @@ -809,6 +809,7 @@ handle_signal (int signo) case SIGUSR1: log_info ("SIGUSR1 received - printing internal information:\n"); pth_ctrl (PTH_CTRL_DUMPSTATE, log_get_stream ()); + app_dump_state (); break; case SIGUSR2: @@ -1013,7 +1014,6 @@ handle_connections (int listen_fd) tattr = pth_attr_new(); pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0); pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 512*1024); - pth_attr_set (tattr, PTH_ATTR_NAME, "scd-connections"); #ifndef HAVE_W32_SYSTEM /* fixme */ sigemptyset (&sigs ); @@ -1022,6 +1022,7 @@ handle_connections (int listen_fd) sigaddset (&sigs, SIGUSR2); sigaddset (&sigs, SIGINT); sigaddset (&sigs, SIGTERM); + pth_sigmask (SIG_UNBLOCK, &sigs, NULL); ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo); #else ev = NULL; @@ -1034,6 +1035,8 @@ handle_connections (int listen_fd) for (;;) { + sigset_t oldsigs; + if (shutdown_pending) { if (pth_ctrl (PTH_CTRL_GETTHREADS) == 1) @@ -1093,6 +1096,11 @@ handle_connections (int listen_fd) handle_tick (); } + /* We now might create new threads and because we don't want any + signals - we are handling here - to be delivered to a new + thread. Thus we need to block those signals. */ + pth_sigmask (SIG_BLOCK, &sigs, &oldsigs); + if (listen_fd != -1 && FD_ISSET (listen_fd, &read_fdset)) { plen = sizeof paddr; @@ -1101,15 +1109,26 @@ handle_connections (int listen_fd) { log_error ("accept failed: %s\n", strerror (errno)); } - else if (!pth_spawn (tattr, start_connection_thread, (void*)fd)) - { - log_error ("error spawning connection handler: %s\n", - strerror (errno) ); - close (fd); - } + else + { + char threadname[50]; + snprintf (threadname, sizeof threadname-1, "conn fd=%d", fd); + threadname[sizeof threadname -1] = 0; + pth_attr_set (tattr, PTH_ATTR_NAME, threadname); + + if (!pth_spawn (tattr, start_connection_thread, (void*)fd)) + { + log_error ("error spawning connection handler: %s\n", + strerror (errno) ); + close (fd); + } + } fd = -1; } + /* Restore the signal mask. */ + pth_sigmask (SIG_SETMASK, &oldsigs, NULL); + } pth_event_free (ev, PTH_FREE_ALL); diff --git a/scd/scdaemon.h b/scd/scdaemon.h index eaa9abd35..54566b6ad 100644 --- a/scd/scdaemon.h +++ b/scd/scdaemon.h @@ -77,19 +77,28 @@ struct { #define DBG_CARD_IO (opt.debug & DBG_CARD_IO_VALUE) struct server_local_s; -struct card_ctx_s; struct app_ctx_s; -struct server_control_s { +struct server_control_s +{ + /* Local data of the server; used only in command.c. */ struct server_local_s *server_local; - int reader_slot; /* Slot of the open reader or -1 if not open. */ - struct card_ctx_s *card_ctx; + + /* Slot of the open reader or -1 if not open. */ + int reader_slot; + + /* The application context used with this connection or NULL if none + associated. Note that this is shared with the other connections: + All connections accessing the same reader are using the same + application context. */ struct app_ctx_s *app_ctx; - struct { + + /* Helper to store the value we are going to sign */ + struct + { unsigned char *value; int valuelen; - } in_data; /* helper to store the value we are going to sign */ - + } in_data; }; typedef struct server_control_s *CTRL; -- cgit From deeba405a9a5868ea478db5003be6335ab9aac6f Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 16 Jun 2005 08:12:03 +0000 Subject: gcc-4 defaults forced me to edit many many files to get rid of the char * vs. unsigned char * warnings. The GNU coding standards used to say that these mismatches are okay and better than a bunch of casts. Obviously this has changed now. --- agent/ChangeLog | 46 ++++++++++++++++++++++ agent/agent.h | 15 ++++---- agent/cache.c | 20 +++++++--- agent/call-scd.c | 19 ++++------ agent/command-ssh.c | 75 ++++++++++++++++-------------------- agent/command.c | 4 +- agent/divert-scd.c | 9 +++-- agent/findkey.c | 4 +- agent/genkey.c | 2 +- agent/gpg-agent.c | 11 ++++-- agent/minip12.c | 2 + agent/pkdecrypt.c | 2 +- agent/pksign.c | 2 +- agent/protect-tool.c | 21 +++++----- agent/protect.c | 29 ++++++++------ agent/query.c | 9 +++-- common/ChangeLog | 26 ++++++++++++- common/estream.c | 21 +++++----- common/estream.h | 8 ++-- common/iobuf.c | 19 ++++++---- common/iobuf.h | 4 +- common/miscellaneous.c | 2 +- common/sexputil.c | 9 +++-- common/simple-pwquery.c | 2 +- common/ttyio.c | 2 +- common/util.h | 2 +- doc/gpg-agent.texi | 8 +++- g10/ChangeLog | 5 +++ g10/g10.c | 4 +- g10/misc.c | 5 ++- jnlib/ChangeLog | 13 +++++++ jnlib/argparse.c | 2 +- jnlib/logging.c | 5 ++- jnlib/stringhelp.c | 97 ++++++++++++++++++++++++++++------------------- jnlib/stringhelp.h | 9 ++--- jnlib/utf8conv.c | 21 +++++----- kbx/ChangeLog | 11 ++++++ kbx/kbxutil.c | 2 +- kbx/keybox-blob.c | 45 ++++++++++++---------- kbx/keybox-defs.h | 5 ++- kbx/keybox-file.c | 4 +- scd/apdu.c | 2 +- scd/app-help.c | 2 +- scd/app-openpgp.c | 27 ++++++------- scd/app-p15.c | 28 +++++++------- scd/app.c | 2 +- scd/ccid-driver.c | 14 +++---- scd/command.c | 10 ++--- scd/iso7816.c | 18 +++++---- scd/pcsc-wrapper.c | 4 +- sm/ChangeLog | 32 ++++++++++++++++ sm/base64.c | 14 ++++--- sm/call-agent.c | 25 ++++++------ sm/certcheck.c | 14 ++++--- sm/certdump.c | 28 +++++++------- sm/certreqgen.c | 9 +++-- sm/delete.c | 4 +- sm/encrypt.c | 12 +++--- sm/fingerprint.c | 17 +++++---- sm/gpgsm.h | 10 ++--- sm/keydb.c | 9 +++-- sm/keylist.c | 4 +- sm/server.c | 4 +- sm/sign.c | 2 +- tools/ChangeLog | 5 +++ tools/gpg-connect-agent.c | 2 +- tools/gpgconf-comp.c | 2 +- tools/gpgkey2ssh.c | 3 ++ tools/watchgnupg.c | 2 +- 69 files changed, 558 insertions(+), 348 deletions(-) (limited to 'scd/app-openpgp.c') diff --git a/agent/ChangeLog b/agent/ChangeLog index 1a157fa52..055dbe53e 100644 --- a/agent/ChangeLog +++ b/agent/ChangeLog @@ -1,3 +1,49 @@ +2005-06-16 Werner Koch + + * protect-tool.c (make_advanced): Makde RESULT a plain char. + * call-scd.c (unescape_status_string): Need to cast unsigned char* + for strcpy. + (agent_card_pksign): Made arg R_BUF an unsigned char**. + * divert-scd.c (divert_pksign): Made SIGVAL unsigned char*. + (encode_md_for_card): Initialize R_VAL and R_LEN. + * genkey.c (store_key): Made BUF unsigned. + * protect.c (do_encryption): Ditto. + (do_encryption): Made arg PROTBEGIN unsigned. Initialize RESULT + and RESULTLEN even on error. + (merge_lists): Need to cast unsigned char * for strcpy. Initialize + RESULTand RESULTLEN even on error. + (agent_unprotect): Likewise for strtoul. + (make_shadow_info): Made P and INFO plain char. + (agent_shadow_key): Made P plain char. + +2005-06-15 Werner Koch + + * query.c (agent_get_passphrase): Made HEXSTRING a char*. + * command-ssh.c (ssh_key_grip): Made arg BUFFER unsigned. + (ssh_key_grip): Simplified. + (data_sign): Initialize variables with the definition. + (ssh_convert_key_to_blob): Make sure that BLOB and BLOB_SIZE + are set to NULL on error. Cool, gcc-4 detects uninitialized stuff + beyond function boundaries; well it can't know that we do error + proper error handling so that this was not a real error. + (file_to_buffer): Likewise for BUFFER and BUFFER_N. + (data_sign): Likewise for SIG and SIG_N. + (stream_read_byte): Set B to a value even on error. + * command.c (cmd_genkey): Changed VALUE to char. + (cmd_readkey): Cast arg for gcry_sexp_sprint. + * agent.h (struct server_control_s): Made KEYGRIP unsigned. + +2005-06-13 Werner Koch + + * command-ssh.c (start_command_handler_ssh): Reset the SCD. + +2005-06-09 Werner Koch + + * gpg-agent.c (create_socket_name): New option --max-cache-ttl-ssh. + * cache.c (housekeeping): Use it. + (agent_put_cache): Use a switch to get the default ttl so that it + is easier to add more cases. + 2005-06-06 Werner Koch * gpg-agent.c: New option --default-cache-ttl-ssh. diff --git a/agent/agent.h b/agent/agent.h index 350e5c0d2..7a646a85f 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -71,9 +71,10 @@ struct { int no_grab; /* Don't let the pinentry grab the keyboard */ /* The default and maximum TTL of cache entries. */ - unsigned long def_cache_ttl; /* Normal. */ - unsigned long def_cache_ttl_ssh; /* SSH. */ - unsigned long max_cache_ttl; + unsigned long def_cache_ttl; /* Default. */ + unsigned long def_cache_ttl_ssh; /* for SSH. */ + unsigned long max_cache_ttl; /* Default. */ + unsigned long max_cache_ttl_ssh; /* for SSH. */ int running_detached; /* We are running detached from the tty. */ @@ -107,8 +108,8 @@ struct server_local_s; struct scd_local_s; /* Collection of data per session (aka connection). */ -struct server_control_s { - +struct server_control_s +{ /* Private data of the server (command.c). */ struct server_local_s *server_local; @@ -128,7 +129,7 @@ struct server_control_s { int valuelen; int raw_value: 1; } digest; - char keygrip[20]; + unsigned char keygrip[20]; int have_keygrip; int use_auth_call; /* Hack to send the PKAUTH command instead of the @@ -289,7 +290,7 @@ int agent_card_pksign (ctrl_t ctrl, int (*getpin_cb)(void *, const char *, char*, size_t), void *getpin_cb_arg, const unsigned char *indata, size_t indatalen, - char **r_buf, size_t *r_buflen); + unsigned char **r_buf, size_t *r_buflen); int agent_card_pkdecrypt (ctrl_t ctrl, const char *keyid, int (*getpin_cb)(void *, const char *, char*,size_t), diff --git a/agent/cache.c b/agent/cache.c index a032b4fa7..32b6ac0c7 100644 --- a/agent/cache.c +++ b/agent/cache.c @@ -103,10 +103,17 @@ housekeeping (void) } /* Second, make sure that we also remove them based on the created stamp so - that the user has to enter it from time to time. We do this every hour */ + that the user has to enter it from time to time. */ for (r=thecache; r; r = r->next) { - if (!r->lockcount && r->pw && r->created + opt.max_cache_ttl < current) + unsigned long maxttl; + + switch (r->cache_mode) + { + case CACHE_MODE_SSH: maxttl = opt.max_cache_ttl_ssh; break; + default: maxttl = opt.max_cache_ttl; break; + } + if (!r->lockcount && r->pw && r->created + maxttl < current) { if (DBG_CACHE) log_debug (" expired `%s' (%lus after creation)\n", @@ -203,10 +210,11 @@ agent_put_cache (const char *key, cache_mode_t cache_mode, if (!ttl) { - if (cache_mode == CACHE_MODE_SSH) - ttl = opt.def_cache_ttl_ssh; - else - ttl = opt.def_cache_ttl; + switch(cache_mode) + { + case CACHE_MODE_SSH: ttl = opt.def_cache_ttl_ssh; break; + default: ttl = opt.def_cache_ttl; break; + } } if (!ttl || cache_mode == CACHE_MODE_IGNORE) return 0; diff --git a/agent/call-scd.c b/agent/call-scd.c index 4dff8e3c1..7a623fda4 100644 --- a/agent/call-scd.c +++ b/agent/call-scd.c @@ -465,7 +465,7 @@ unescape_status_string (const unsigned char *s) { char *buffer, *d; - buffer = d = xtrymalloc (strlen (s)+1); + buffer = d = xtrymalloc (strlen ((const char*)s)+1); if (!buffer) return NULL; while (*s) @@ -666,7 +666,7 @@ agent_card_pksign (ctrl_t ctrl, int (*getpin_cb)(void *, const char *, char*, size_t), void *getpin_cb_arg, const unsigned char *indata, size_t indatalen, - char **r_buf, size_t *r_buflen) + unsigned char **r_buf, size_t *r_buflen) { int rc, i; char *p, line[ASSUAN_LINELENGTH]; @@ -714,14 +714,11 @@ agent_card_pksign (ctrl_t ctrl, /* Create an S-expression from it which is formatted like this: "(7:sig-val(3:rsa(1:sSIGBUFLEN:SIGBUF)))" */ *r_buflen = 21 + 11 + sigbuflen + 4; - *r_buf = xtrymalloc (*r_buflen); - if (!*r_buf) - { - gpg_error_t tmperr = out_of_core (); - xfree (*r_buf); - return unlock_scd (ctrl, tmperr); - } - p = stpcpy (*r_buf, "(7:sig-val(3:rsa(1:s" ); + p = xtrymalloc (*r_buflen); + *r_buf = (unsigned char*)p; + if (!p) + return unlock_scd (ctrl, out_of_core ()); + p = stpcpy (p, "(7:sig-val(3:rsa(1:s" ); sprintf (p, "%u:", (unsigned int)sigbuflen); p += strlen (p); memcpy (p, sigbuf, sigbuflen); @@ -895,7 +892,7 @@ card_getattr_cb (void *opaque, const char *line) if (keywordlen == parm->keywordlen && !memcmp (keyword, parm->keyword, keywordlen)) { - parm->data = unescape_status_string (line); + parm->data = unescape_status_string ((const unsigned char*)line); if (!parm->data) parm->error = errno; } diff --git a/agent/command-ssh.c b/agent/command-ssh.c index 870afe059..a43fee24f 100644 --- a/agent/command-ssh.c +++ b/agent/command-ssh.c @@ -297,6 +297,7 @@ stream_read_byte (estream_t stream, unsigned char *b) err = gpg_error_from_errno (errno); else err = gpg_error (GPG_ERR_EOF); + *b = 0; } else { @@ -604,6 +605,9 @@ file_to_buffer (const char *filename, unsigned char **buffer, size_t *buffer_n) gpg_error_t err; int ret; + *buffer = NULL; + *buffer_n = 0; + buffer_new = NULL; err = 0; @@ -1381,6 +1385,9 @@ ssh_convert_key_to_blob (unsigned char **blob, size_t *blob_size, gpg_error_t err; unsigned int i; + *blob = NULL; + *blob_size = 0; + blob_new = NULL; stream = NULL; err = 0; @@ -1535,20 +1542,12 @@ ssh_read_key_public_from_blob (unsigned char *blob, size_t blob_size, S-Expression KEY and writes it to BUFFER, which must be large enough to hold it. Returns usual error code. */ static gpg_error_t -ssh_key_grip (gcry_sexp_t key, char *buffer) +ssh_key_grip (gcry_sexp_t key, unsigned char *buffer) { - gpg_error_t err; - char *p; + if (!gcry_pk_get_keygrip (key, buffer)) + return gpg_error (GPG_ERR_INTERNAL); - /* FIXME: unsigned vs. signed. */ - - p = gcry_pk_get_keygrip (key, buffer); - if (! p) - err = gpg_error (GPG_ERR_INTERNAL); /* FIXME? */ - else - err = 0; - - return err; + return 0; } /* Converts the secret key KEY_SECRET into a public key, storing it in @@ -1654,7 +1653,7 @@ card_key_available (ctrl_t ctrl, gcry_sexp_t *r_pk, char **cardsn) } pkbuflen = gcry_sexp_canon_len (pkbuf, 0, NULL, NULL); - err = gcry_sexp_sscan (&s_pk, NULL, pkbuf, pkbuflen); + err = gcry_sexp_sscan (&s_pk, NULL, (char*)pkbuf, pkbuflen); if (err) { log_error ("failed to build S-Exp from received card key: %s\n", @@ -1877,7 +1876,7 @@ ssh_handler_request_identities (ctrl_t ctrl, if (err) goto out; - err = gcry_sexp_sscan (&key_secret, NULL, buffer, buffer_n); + err = gcry_sexp_sscan (&key_secret, NULL, (char*)buffer, buffer_n); if (err) goto out; @@ -1984,14 +1983,14 @@ data_sign (ctrl_t ctrl, ssh_signature_encoder_t sig_encoder, unsigned char **sig, size_t *sig_n) { gpg_error_t err; - gcry_sexp_t signature_sexp; - estream_t stream; - gcry_sexp_t valuelist; - gcry_sexp_t sublist; - gcry_mpi_t sig_value; - unsigned char *sig_blob; - size_t sig_blob_n; - char *identifier; + gcry_sexp_t signature_sexp = NULL; + estream_t stream = NULL; + gcry_sexp_t valuelist = NULL; + gcry_sexp_t sublist = NULL; + gcry_mpi_t sig_value = NULL; + unsigned char *sig_blob = NULL;; + size_t sig_blob_n = 0; + char *identifier = NULL; const char *identifier_raw; size_t identifier_n; ssh_key_type_spec_t spec; @@ -1999,17 +1998,10 @@ data_sign (ctrl_t ctrl, ssh_signature_encoder_t sig_encoder, unsigned int i; const char *elems; size_t elems_n; - gcry_mpi_t *mpis; + gcry_mpi_t *mpis = NULL; - signature_sexp = NULL; - identifier = NULL; - valuelist = NULL; - sublist = NULL; - sig_blob = NULL; - sig_blob_n = 0; - stream = NULL; - sig_value = NULL; - mpis = NULL; + *sig = NULL; + *sig_n = 0; ctrl->use_auth_call = 1; err = agent_pksign_do (ctrl, @@ -2119,7 +2111,7 @@ data_sign (ctrl_t ctrl, ssh_signature_encoder_t sig_encoder, if (err) goto out; - *sig = (char *) sig_blob; + *sig = sig_blob; *sig_n = sig_blob_n; out: @@ -2684,7 +2676,7 @@ ssh_request_process (ctrl_t ctrl, estream_t stream_sock) secure memory, since we never give out secret keys. FIXME: This is a pretty good DoS. We only have a limited amount - of secure memory, we can't trhow hin everything we get from a + of secure memory, we can't throw in everything we get from a client -wk */ /* Retrieve request. */ @@ -2824,7 +2816,6 @@ start_command_handler_ssh (int sock_client) struct server_control_s ctrl; estream_t stream_sock; gpg_error_t err; - int bad; int ret; /* Setup control structure. */ @@ -2868,15 +2859,15 @@ start_command_handler_ssh (int sock_client) goto out; } - while (1) - { - bad = ssh_request_process (&ctrl, stream_sock); - if (bad) - break; - }; + /* Main processing loop. */ + while ( !ssh_request_process (&ctrl, stream_sock) ) + ; - out: + /* Reset the SCD in case it has been used. */ + agent_reset_scd (&ctrl); + + out: if (stream_sock) es_fclose (stream_sock); diff --git a/agent/command.c b/agent/command.c index ebf3a8220..c39bcc6ab 100644 --- a/agent/command.c +++ b/agent/command.c @@ -168,7 +168,7 @@ parse_keygrip (ASSUAN_CONTEXT ctx, const char *string, unsigned char *buf) if (n != 20) return set_error (Parameter_Error, "invalid length of keygrip"); - for (p=string, n=0; n < 20; p += 2, n++) + for (p=(const unsigned char*)string, n=0; n < 20; p += 2, n++) buf[n] = xtoi_2 (p); return 0; @@ -494,7 +494,7 @@ cmd_genkey (ASSUAN_CONTEXT ctx, char *line) init_membuf (&outbuf, 512); - rc = agent_genkey (ctrl, value, valuelen, &outbuf); + rc = agent_genkey (ctrl, (char*)value, valuelen, &outbuf); xfree (value); if (rc) clear_outbuf (&outbuf); diff --git a/agent/divert-scd.c b/agent/divert-scd.c index 41a5dfcda..9d2fa446c 100644 --- a/agent/divert-scd.c +++ b/agent/divert-scd.c @@ -139,10 +139,13 @@ static int encode_md_for_card (const unsigned char *digest, size_t digestlen, int algo, unsigned char **r_val, size_t *r_len) { - byte *frame; - byte asn[100]; + unsigned char *frame; + unsigned char asn[100]; size_t asnlen; + *r_val = NULL; + *r_len = 0; + asnlen = DIM(asn); if (gcry_md_algo_info (algo, GCRYCTL_GET_ASNOID, asn, &asnlen)) { @@ -295,7 +298,7 @@ divert_pksign (CTRL ctrl, int rc; char *kid; size_t siglen; - char *sigval; + unsigned char *sigval; unsigned char *data; size_t ndata; diff --git a/agent/findkey.c b/agent/findkey.c index 56433c9c4..1cb7efaf3 100644 --- a/agent/findkey.c +++ b/agent/findkey.c @@ -345,7 +345,7 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result) } /* Convert the file into a gcrypt S-expression object. */ - rc = gcry_sexp_sscan (&s_skey, &erroff, buf, buflen); + rc = gcry_sexp_sscan (&s_skey, &erroff, (char*)buf, buflen); xfree (fname); fclose (fp); xfree (buf); @@ -500,7 +500,7 @@ agent_key_from_file (ctrl_t ctrl, const char *desc_text, } buflen = gcry_sexp_canon_len (buf, 0, NULL, NULL); - rc = gcry_sexp_sscan (&s_skey, &erroff, buf, buflen); + rc = gcry_sexp_sscan (&s_skey, &erroff, (char*)buf, buflen); wipememory (buf, buflen); xfree (buf); if (rc) diff --git a/agent/genkey.c b/agent/genkey.c index e07518d5a..d0319f7b4 100644 --- a/agent/genkey.c +++ b/agent/genkey.c @@ -33,7 +33,7 @@ static int store_key (gcry_sexp_t private, const char *passphrase, int force) { int rc; - char *buf; + unsigned char *buf; size_t len; unsigned char grip[20]; diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c index 6cc08f845..8732c98d7 100644 --- a/agent/gpg-agent.c +++ b/agent/gpg-agent.c @@ -85,6 +85,7 @@ enum cmd_and_opt_values oDefCacheTTL, oDefCacheTTLSSH, oMaxCacheTTL, + oMaxCacheTTLSSH, oUseStandardSocket, oNoUseStandardSocket, @@ -143,6 +144,7 @@ static ARGPARSE_OPTS opts[] = { N_("|N|expire cached PINs after N seconds")}, { oDefCacheTTLSSH, "default-cache-ttl-ssh", 4, "@" }, { oMaxCacheTTL, "max-cache-ttl", 4, "@" }, + { oMaxCacheTTLSSH, "max-cache-ttl-ssh", 4, "@" }, { oIgnoreCacheForSigning, "ignore-cache-for-signing", 0, N_("do not use the PIN cache when signing")}, { oAllowMarkTrusted, "allow-mark-trusted", 0, @@ -156,8 +158,9 @@ static ARGPARSE_OPTS opts[] = { }; -#define DEFAULT_CACHE_TTL (10*60) /* 10 minutes */ -#define MAX_CACHE_TTL (120*60) /* 2 hours */ +#define DEFAULT_CACHE_TTL (10*60) /* 10 minutes */ +#define DEFAULT_CACHE_TTL_SSH (30*60) /* 30 minutes */ +#define MAX_CACHE_TTL (120*60) /* 2 hours */ /* flag to indicate that a shutdown was requested */ @@ -369,8 +372,9 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread) opt.pinentry_program = NULL; opt.scdaemon_program = NULL; opt.def_cache_ttl = DEFAULT_CACHE_TTL; - opt.def_cache_ttl_ssh = DEFAULT_CACHE_TTL; + opt.def_cache_ttl_ssh = DEFAULT_CACHE_TTL_SSH; opt.max_cache_ttl = MAX_CACHE_TTL; + opt.max_cache_ttl_ssh = MAX_CACHE_TTL; opt.ignore_cache_for_signing = 0; opt.allow_mark_trusted = 0; opt.disable_scdaemon = 0; @@ -407,6 +411,7 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread) case oDefCacheTTL: opt.def_cache_ttl = pargs->r.ret_ulong; break; case oDefCacheTTLSSH: opt.def_cache_ttl_ssh = pargs->r.ret_ulong; break; case oMaxCacheTTL: opt.max_cache_ttl = pargs->r.ret_ulong; break; + case oMaxCacheTTLSSH: opt.max_cache_ttl_ssh = pargs->r.ret_ulong; break; case oIgnoreCacheForSigning: opt.ignore_cache_for_signing = 1; break; diff --git a/agent/minip12.c b/agent/minip12.c index 5ca85033d..31be15373 100644 --- a/agent/minip12.c +++ b/agent/minip12.c @@ -1552,6 +1552,8 @@ p12_build (gcry_mpi_t *kparms, unsigned char *cert, size_t certlen, struct buffer_s seqlist[2]; int seqlistidx = 0; + n = buflen = 0; /* (avoid compiler warning). */ + if (cert && certlen) { /* Encode the certificate. */ diff --git a/agent/pkdecrypt.c b/agent/pkdecrypt.c index 42ce69697..1d64c1b15 100644 --- a/agent/pkdecrypt.c +++ b/agent/pkdecrypt.c @@ -52,7 +52,7 @@ agent_pkdecrypt (CTRL ctrl, const char *desc_text, goto leave; } - rc = gcry_sexp_sscan (&s_cipher, NULL, ciphertext, ciphertextlen); + rc = gcry_sexp_sscan (&s_cipher, NULL, (char*)ciphertext, ciphertextlen); if (rc) { log_error ("failed to convert ciphertext: %s\n", gpg_strerror (rc)); diff --git a/agent/pksign.c b/agent/pksign.c index 2a355e43e..e9df19351 100644 --- a/agent/pksign.c +++ b/agent/pksign.c @@ -117,7 +117,7 @@ agent_pksign_do (ctrl_t ctrl, const char *desc_text, len = gcry_sexp_canon_len (buf, 0, NULL, NULL); assert (len); - rc = gcry_sexp_sscan (&s_sig, NULL, buf, len); + rc = gcry_sexp_sscan (&s_sig, NULL, (char*)buf, len); xfree (buf); if (rc) { diff --git a/agent/protect-tool.c b/agent/protect-tool.c index e8f1d2c10..5f59d5e06 100644 --- a/agent/protect-tool.c +++ b/agent/protect-tool.c @@ -239,9 +239,9 @@ make_advanced (const unsigned char *buf, size_t buflen) int rc; size_t erroff, len; gcry_sexp_t sexp; - unsigned char *result; + char *result; - rc = gcry_sexp_sscan (&sexp, &erroff, buf, buflen); + rc = gcry_sexp_sscan (&sexp, &erroff, (const char*)buf, buflen); if (rc) { log_error ("invalid canonical S-Expression (off=%u): %s\n", @@ -378,7 +378,7 @@ read_and_protect (const char *fname) xfree (result); if (!p) return; - result = p; + result = (unsigned char*)p; resultlen = strlen (p); } @@ -417,7 +417,7 @@ read_and_unprotect (const char *fname) xfree (result); if (!p) return; - result = p; + result = (unsigned char*)p; resultlen = strlen (p); } @@ -434,12 +434,13 @@ read_and_shadow (const char *fname) unsigned char *key; unsigned char *result; size_t resultlen; + unsigned char dummy_info[] = "(8:313233342:43)"; key = read_key (fname); if (!key) return; - rc = agent_shadow_key (key, "(8:313233342:43)", &result); + rc = agent_shadow_key (key, dummy_info, &result); xfree (key); if (rc) { @@ -455,7 +456,7 @@ read_and_shadow (const char *fname) xfree (result); if (!p) return; - result = p; + result = (unsigned char*)p; resultlen = strlen (p); } @@ -682,7 +683,7 @@ import_p12_file (const char *fname) if (!buf) return; - kparms = p12_parse (buf, buflen, (pw=get_passphrase (2)), + kparms = p12_parse ((unsigned char*)buf, buflen, (pw=get_passphrase (2)), import_p12_cert_cb, NULL); release_passphrase (pw); xfree (buf); @@ -773,7 +774,7 @@ import_p12_file (const char *fname) xfree (result); if (!p) return; - result = p; + result = (unsigned char*)p; resultlen = strlen (p); } @@ -932,7 +933,7 @@ export_p12_file (const char *fname) if (opt_have_cert) { - cert = read_file ("-", &certlen); + cert = (unsigned char*)read_file ("-", &certlen); if (!cert) { wipememory (key, keylen_for_wipe); @@ -1040,7 +1041,7 @@ percent_plus_unescape (unsigned char *string) static char * percent_plus_unescape_string (char *string) { - unsigned char *p = string; + unsigned char *p = (unsigned char*)string; size_t n; n = percent_plus_unescape (p); diff --git a/agent/protect.c b/agent/protect.c index 658c8c529..45bdae496 100644 --- a/agent/protect.c +++ b/agent/protect.c @@ -134,19 +134,22 @@ calculate_mic (const unsigned char *plainkey, unsigned char *sha1hash) */ static int -do_encryption (const char *protbegin, size_t protlen, +do_encryption (const unsigned char *protbegin, size_t protlen, const char *passphrase, const unsigned char *sha1hash, unsigned char **result, size_t *resultlen) { gcry_cipher_hd_t hd; const char *modestr = "openpgp-s2k3-sha1-" PROT_CIPHER_STRING "-cbc"; int blklen, enclen, outlen; - char *iv = NULL; + unsigned char *iv = NULL; int rc; char *outbuf = NULL; char *p; int saltpos, ivpos, encpos; + *resultlen = 0; + *result = NULL; + rc = gcry_cipher_open (&hd, PROT_CIPHER, GCRY_CIPHER_MODE_CBC, GCRY_CIPHER_SECURE); if (rc) @@ -250,7 +253,7 @@ do_encryption (const char *protbegin, size_t protlen, return tmperr; } *resultlen = strlen (p); - *result = p; + *result = (unsigned char*)p; memcpy (p+saltpos, iv+2*blklen, 8); memcpy (p+ivpos, iv, blklen); memcpy (p+encpos, outbuf, enclen); @@ -261,7 +264,7 @@ do_encryption (const char *protbegin, size_t protlen, -/* Protect the key encoded in canonical format in plainkey. We assume +/* Protect the key encoded in canonical format in PLAINKEY. We assume a valid S-Exp here. */ int agent_protect (const unsigned char *plainkey, const char *passphrase, @@ -469,6 +472,9 @@ merge_lists (const unsigned char *protectedkey, const unsigned char *startpos, *endpos; int i, rc; + *result = NULL; + *resultlen = 0; + if (replacepos < 26) return gpg_error (GPG_ERR_BUG); @@ -487,7 +493,7 @@ merge_lists (const unsigned char *protectedkey, return out_of_core (); /* Copy the initial segment */ - strcpy (newlist, "(11:private-key"); + strcpy ((char*)newlist, "(11:private-key"); p = newlist + 15; memcpy (p, protectedkey+15+10, replacepos-15-10); p += replacepos-15-10; @@ -669,7 +675,7 @@ agent_unprotect (const unsigned char *protectedkey, const char *passphrase, is nothing we should worry about */ if (s[n] != ')' ) return gpg_error (GPG_ERR_INV_SEXP); - s2kcount = strtoul (s, NULL, 10); + s2kcount = strtoul ((const char*)s, NULL, 10); if (!s2kcount) return gpg_error (GPG_ERR_CORRUPTED_PROTECTION); s += n; @@ -838,7 +844,7 @@ unsigned char * make_shadow_info (const char *serialno, const char *idstring) { const char *s; - unsigned char *info, *p; + char *info, *p; char numbuf[21]; int n; @@ -853,13 +859,13 @@ make_shadow_info (const char *serialno, const char *idstring) sprintf (numbuf, "%d:", n); p = stpcpy (p, numbuf); for (s=serialno; *s && s[1]; s += 2) - *p++ = xtoi_2 (s); + *(unsigned char *)p++ = xtoi_2 (s); sprintf (numbuf, "%d:", strlen (idstring)); p = stpcpy (p, numbuf); p = stpcpy (p, idstring); *p++ = ')'; *p = 0; - return info; + return (unsigned char *)info; } @@ -878,7 +884,7 @@ agent_shadow_key (const unsigned char *pubkey, const unsigned char *point; size_t n; int depth = 0; - unsigned char *p; + char *p; size_t pubkey_len = gcry_sexp_canon_len (pubkey, 0, NULL,NULL); size_t shadow_info_len = gcry_sexp_canon_len (shadow_info, 0, NULL,NULL); @@ -930,7 +936,8 @@ agent_shadow_key (const unsigned char *pubkey, /* Calculate required length by taking in account: the "shadowed-" prefix, the "shadowed", "t1-v1" as well as some parenthesis */ n = 12 + pubkey_len + 1 + 3+8 + 2+5 + shadow_info_len + 1; - *result = p = xtrymalloc (n); + *result = xtrymalloc (n); + p = (char*)*result; if (!p) return out_of_core (); p = stpcpy (p, "(20:shadowed-private-key"); diff --git a/agent/query.c b/agent/query.c index c1e4dbacc..b231f6fc3 100644 --- a/agent/query.c +++ b/agent/query.c @@ -58,7 +58,7 @@ static pth_mutex_t entry_lock; struct entry_parm_s { int lines; size_t size; - char *buffer; + unsigned char *buffer; }; @@ -372,7 +372,7 @@ agent_askpin (ctrl_t ctrl, { memset (&parm, 0, sizeof parm); parm.size = pininfo->max_length; - parm.buffer = pininfo->pin; + parm.buffer = (unsigned char*)pininfo->pin; if (errtext) { @@ -444,7 +444,8 @@ agent_get_passphrase (CTRL ctrl, int rc; char line[ASSUAN_LINELENGTH]; struct entry_parm_s parm; - unsigned char *p, *hexstring; + unsigned char *p; + char *hexstring; int i; *retpass = NULL; @@ -497,7 +498,7 @@ agent_get_passphrase (CTRL ctrl, return unlock_pinentry (map_assuan_err (rc)); } - hexstring = gcry_malloc_secure (strlen (parm.buffer)*2+1); + hexstring = gcry_malloc_secure (strlen ((char*)parm.buffer)*2+1); if (!hexstring) { gpg_error_t tmperr = out_of_core (); diff --git a/common/ChangeLog b/common/ChangeLog index 08fb06775..e7905ea58 100644 --- a/common/ChangeLog +++ b/common/ChangeLog @@ -1,9 +1,33 @@ +2005-06-15 Werner Koch + + * miscellaneous.c (make_printable_string): Made P a void*. + + * sexputil.c (keygrip_from_canon_sexp, cmp_simple_canon_sexp): + Fixed signed/unsigned pointer mismatch. + (make_simple_sexp_from_hexstr): Ditto. This is all too ugly; I + wonder why gcc-4's default is to warn about them and forcing us to + use cast the warning away. + * iobuf.c (block_filter): Ditto. + (iobuf_flush): Ditto. + (iobuf_read_line): Ditto. + (iobuf_read): Make BUFFER a void *. + (iobuf_write): Make BUFFER a const void *. + * ttyio.c (tty_print_utf8_string2): Ditto. + * estream.c (estream_cookie_mem): Make MEMORY unsigned char*. + (es_write): Make BUFFER a void *. + (es_writen): Ditto. + (es_func_fd_read, es_func_fd_write, es_func_mem_read) + (es_func_mem_write): Ditto. + (es_read, es_readn): Ditto. + (es_func_mem_write): Made MEMORY_NEW an unsigned char *. + * estream.h (es_cookie_read_function_t) + (es_cookie_write_function_t): Changed buffer arg to void*. + 2005-06-03 Werner Koch * estream.c: Use HAVE_CONFIG_H and not USE_CONFIG_H! (es_func_fd_read, es_func_fd_write): Protect against EINTR. - 2005-06-01 Werner Koch * Makefile.am (AM_CPPFLAGS): Added. diff --git a/common/estream.c b/common/estream.c index bf5b02001..70b3d9c6e 100644 --- a/common/estream.c +++ b/common/estream.c @@ -294,7 +294,7 @@ es_init_do (void) typedef struct estream_cookie_mem { unsigned int flags; /* Open flags. */ - char *memory; /* Data. */ + unsigned char *memory; /* Data. */ size_t memory_size; /* Size of MEMORY. */ size_t offset; /* Current offset in MEMORY. */ size_t data_len; /* Length of data in MEMORY. */ @@ -350,7 +350,7 @@ es_func_mem_create (void *ES__RESTRICT *ES__RESTRICT cookie, /* Read function for memory objects. */ static ssize_t -es_func_mem_read (void *cookie, char *buffer, size_t size) +es_func_mem_read (void *cookie, void *buffer, size_t size) { estream_cookie_mem_t mem_cookie = cookie; ssize_t ret; @@ -371,11 +371,11 @@ es_func_mem_read (void *cookie, char *buffer, size_t size) /* Write function for memory objects. */ static ssize_t -es_func_mem_write (void *cookie, const char *buffer, size_t size) +es_func_mem_write (void *cookie, const void *buffer, size_t size) { estream_cookie_mem_t mem_cookie = cookie; func_realloc_t func_realloc = mem_cookie->func_realloc; - char *memory_new; + unsigned char *memory_new; size_t newsize; ssize_t ret; int err; @@ -591,7 +591,7 @@ es_func_fd_create (void **cookie, int fd, unsigned int flags) /* Read function for fd objects. */ static ssize_t -es_func_fd_read (void *cookie, char *buffer, size_t size) +es_func_fd_read (void *cookie, void *buffer, size_t size) { estream_cookie_fd_t file_cookie = cookie; @@ -606,7 +606,7 @@ es_func_fd_read (void *cookie, char *buffer, size_t size) /* Write function for fd objects. */ static ssize_t -es_func_fd_write (void *cookie, const char *buffer, size_t size) +es_func_fd_write (void *cookie, const void *buffer, size_t size) { estream_cookie_fd_t file_cookie = cookie; @@ -1122,9 +1122,10 @@ es_read_lbf (estream_t ES__RESTRICT stream, *the amount of bytes read in BYTES_READ. */ static int es_readn (estream_t ES__RESTRICT stream, - unsigned char *ES__RESTRICT buffer, + void *ES__RESTRICT buffer_arg, size_t bytes_to_read, size_t *ES__RESTRICT bytes_read) { + unsigned char *buffer = (unsigned char *)buffer_arg; size_t data_read_unread, data_read; int err; @@ -1388,7 +1389,7 @@ es_write_lbf (estream_t ES__RESTRICT stream, amount of bytes written in BYTES_WRITTEN. */ static int es_writen (estream_t ES__RESTRICT stream, - const unsigned char *ES__RESTRICT buffer, + const void *ES__RESTRICT buffer, size_t bytes_to_write, size_t *ES__RESTRICT bytes_written) { size_t data_written; @@ -2289,7 +2290,7 @@ es_ungetc (int c, estream_t stream) int es_read (estream_t ES__RESTRICT stream, - char *ES__RESTRICT buffer, size_t bytes_to_read, + void *ES__RESTRICT buffer, size_t bytes_to_read, size_t *ES__RESTRICT bytes_read) { int err; @@ -2309,7 +2310,7 @@ es_read (estream_t ES__RESTRICT stream, int es_write (estream_t ES__RESTRICT stream, - const char *ES__RESTRICT buffer, size_t bytes_to_write, + const void *ES__RESTRICT buffer, size_t bytes_to_write, size_t *ES__RESTRICT bytes_written) { int err; diff --git a/common/estream.h b/common/estream.h index c201b666a..ebe575926 100644 --- a/common/estream.h +++ b/common/estream.h @@ -72,9 +72,9 @@ typedef struct es__stream *estream_t; typedef ssize_t (*es_cookie_read_function_t) (void *cookie, - char *buffer, size_t size); + void *buffer, size_t size); typedef ssize_t (*es_cookie_write_function_t) (void *cookie, - const char *buffer, + const void *buffer, size_t size); typedef int (*es_cookie_seek_function_t) (void *cookie, off_t *pos, int whence); @@ -166,10 +166,10 @@ int _es_putc_overflow (int c, estream_t stream); int es_ungetc (int c, estream_t stream); int es_read (estream_t ES__RESTRICT stream, - char *ES__RESTRICT buffer, size_t bytes_to_read, + void *ES__RESTRICT buffer, size_t bytes_to_read, size_t *ES__RESTRICT bytes_read); int es_write (estream_t ES__RESTRICT stream, - const char *ES__RESTRICT buffer, size_t bytes_to_write, + const void *ES__RESTRICT buffer, size_t bytes_to_write, size_t *ES__RESTRICT bytes_written); size_t es_fread (void *ES__RESTRICT ptr, size_t size, size_t nitems, diff --git a/common/iobuf.c b/common/iobuf.c index 52a388514..32b9e18c6 100644 --- a/common/iobuf.c +++ b/common/iobuf.c @@ -675,10 +675,11 @@ sock_filter (void *opaque, int control, iobuf_t chain, byte * buf, * without a filter */ static int -block_filter (void *opaque, int control, iobuf_t chain, byte * buf, +block_filter (void *opaque, int control, iobuf_t chain, byte * buffer, size_t * ret_len) { block_filter_ctx_t *a = opaque; + char *buf = (char *)buffer; size_t size = *ret_len; int c, needed, rc = 0; char *p; @@ -1762,7 +1763,7 @@ iobuf_flush (iobuf_t a) if (a->use == 3) { /* increase the temp buffer */ - char *newbuf; + unsigned char *newbuf; size_t newsize = a->d.size + 8192; if (DBG_IOBUF) @@ -1829,8 +1830,9 @@ iobuf_readbyte (iobuf_t a) int -iobuf_read (iobuf_t a, byte * buf, unsigned buflen) +iobuf_read (iobuf_t a, void *buffer, unsigned int buflen) { + unsigned char *buf = (unsigned char *)buffer; int c, n; if (a->unget.buf || a->nlimit) @@ -1915,7 +1917,7 @@ iobuf_peek (iobuf_t a, byte * buf, unsigned buflen) int -iobuf_writebyte (iobuf_t a, unsigned c) +iobuf_writebyte (iobuf_t a, unsigned int c) { int rc; @@ -1933,8 +1935,9 @@ iobuf_writebyte (iobuf_t a, unsigned c) int -iobuf_write (iobuf_t a, byte * buf, unsigned buflen) +iobuf_write (iobuf_t a, const void *buffer, unsigned int buflen) { + const unsigned char *buf = (const unsigned char *)buffer; int rc; if (a->directfp) @@ -2311,7 +2314,7 @@ iobuf_read_line (iobuf_t a, byte ** addr_of_buffer, unsigned *length_of_buffer, unsigned *max_length) { int c; - char *buffer = *addr_of_buffer; + char *buffer = (char *)*addr_of_buffer; unsigned length = *length_of_buffer; unsigned nbytes = 0; unsigned maxlen = *max_length; @@ -2321,7 +2324,7 @@ iobuf_read_line (iobuf_t a, byte ** addr_of_buffer, { /* must allocate a new buffer */ length = 256; buffer = xmalloc (length); - *addr_of_buffer = buffer; + *addr_of_buffer = (unsigned char *)buffer; *length_of_buffer = length; } @@ -2344,7 +2347,7 @@ iobuf_read_line (iobuf_t a, byte ** addr_of_buffer, length += 3; /* correct for the reserved byte */ length += length < 1024 ? 256 : 1024; buffer = xrealloc (buffer, length); - *addr_of_buffer = buffer; + *addr_of_buffer = (unsigned char *)buffer; *length_of_buffer = length; length -= 3; /* and reserve again */ p = buffer + nbytes; diff --git a/common/iobuf.h b/common/iobuf.h index 0af94e22d..b991717c2 100644 --- a/common/iobuf.h +++ b/common/iobuf.h @@ -120,12 +120,12 @@ off_t iobuf_tell (iobuf_t a); int iobuf_seek (iobuf_t a, off_t newpos); int iobuf_readbyte (iobuf_t a); -int iobuf_read (iobuf_t a, byte * buf, unsigned buflen); +int iobuf_read (iobuf_t a, void *buf, unsigned buflen); unsigned iobuf_read_line (iobuf_t a, byte ** addr_of_buffer, unsigned *length_of_buffer, unsigned *max_length); int iobuf_peek (iobuf_t a, byte * buf, unsigned buflen); int iobuf_writebyte (iobuf_t a, unsigned c); -int iobuf_write (iobuf_t a, byte * buf, unsigned buflen); +int iobuf_write (iobuf_t a, const void *buf, unsigned buflen); int iobuf_writestr (iobuf_t a, const char *buf); void iobuf_flush_temp (iobuf_t temp); diff --git a/common/miscellaneous.c b/common/miscellaneous.c index 86b0fcb3a..d81213ef9 100644 --- a/common/miscellaneous.c +++ b/common/miscellaneous.c @@ -66,7 +66,7 @@ print_utf8_string( FILE *fp, const byte *p, size_t n ) } char * -make_printable_string( const byte *p, size_t n, int delim ) +make_printable_string (const void *p, size_t n, int delim ) { return sanitize_buffer (p, n, delim); } diff --git a/common/sexputil.c b/common/sexputil.c index 802916b44..8a27ad978 100644 --- a/common/sexputil.c +++ b/common/sexputil.c @@ -52,7 +52,7 @@ keygrip_from_canon_sexp (const unsigned char *key, size_t keylen, if (!grip) return gpg_error (GPG_ERR_INV_VALUE); - err = gcry_sexp_sscan (&sexp, NULL, key, keylen); + err = gcry_sexp_sscan (&sexp, NULL, (const char *)key, keylen); if (err) return err; if (!gcry_pk_get_keygrip (sexp, grip)) @@ -66,8 +66,11 @@ keygrip_from_canon_sexp (const unsigned char *key, size_t keylen, 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) +cmp_simple_canon_sexp (const unsigned char *a_orig, + const unsigned char *b_orig) { + const char *a = (const char *)a_orig; + const char *b = (const char *)b_orig; unsigned long n1, n2; char *endp; @@ -124,7 +127,7 @@ make_simple_sexp_from_hexstr (const char *line, size_t *nscanned) buf = xtrymalloc (strlen (numbuf) + len + 1 + 1); if (!buf) return NULL; - p = stpcpy (buf, numbuf); + p = (unsigned char *)stpcpy ((char *)buf, numbuf); s = line; if ((n&1)) { diff --git a/common/simple-pwquery.c b/common/simple-pwquery.c index 8a027e799..de3689810 100644 --- a/common/simple-pwquery.c +++ b/common/simple-pwquery.c @@ -404,7 +404,7 @@ static char * copy_and_escape (char *buffer, const char *text) { int i; - const unsigned char *s = text; + const unsigned char *s = (unsigned char *)text; char *p = buffer; diff --git a/common/ttyio.c b/common/ttyio.c index eab805e20..5749c59fe 100644 --- a/common/ttyio.c +++ b/common/ttyio.c @@ -322,7 +322,7 @@ tty_print_utf8_string2( const byte *p, size_t n, size_t max_n ) break; } if( i < n ) { - buf = utf8_to_native( p, n, 0 ); + buf = utf8_to_native( (const char *)p, n, 0 ); if( max_n && (strlen( buf ) > max_n )) { buf[max_n] = 0; } diff --git a/common/util.h b/common/util.h index d233dbf5e..1ced59b67 100644 --- a/common/util.h +++ b/common/util.h @@ -153,7 +153,7 @@ const char *print_fname_stdin (const char *s); void print_string (FILE *fp, const byte *p, size_t n, int delim); void print_utf8_string2 ( FILE *fp, const byte *p, size_t n, int delim); void print_utf8_string (FILE *fp, const byte *p, size_t n); -char *make_printable_string (const byte *p, size_t n, int delim); +char *make_printable_string (const void *p, size_t n, int delim); int is_file_compressed (const char *s, int *ret_rc); diff --git a/doc/gpg-agent.texi b/doc/gpg-agent.texi index bad6639e2..144745b4c 100644 --- a/doc/gpg-agent.texi +++ b/doc/gpg-agent.texi @@ -293,7 +293,7 @@ Set the time a cache entry is valid to @var{n} seconds. The default are @item --default-cache-ttl-ssh @var{n} @opindex default-cache-ttl Set the time a cache entry used for SSH keys is valid to @var{n} -seconds. The default are 600 seconds. +seconds. The default are 1800 seconds. @item --max-cache-ttl @var{n} @opindex max-cache-ttl @@ -301,6 +301,12 @@ Set the maximum time a cache entry is valid to @var{n} seconds. After this time a cache entry will get expired even if it has been accessed recently. The default are 2 hours (7200 seconds). +@item --max-cache-ttl-ssh @var{n} +@opindex max-cache-ttl-ssh +Set the maximum time a cache entry used for SSH keys is valid to @var{n} +seconds. After this time a cache entry will get expired even if it has +been accessed recently. The default are 2 hours (7200 seconds). + @item --pinentry-program @var{filename} @opindex pinentry-program Use program @var{filename} as the PIN entry. The default is installation diff --git a/g10/ChangeLog b/g10/ChangeLog index b33735e1f..0ae73b535 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,8 @@ +2005-06-15 Werner Koch + + * g10.c (print_hashline, add_group): Fixes for signed/unsigned + pointer mismatch warnings. + 2005-06-01 Werner Koch * mkdtemp.c: Removed. diff --git a/g10/g10.c b/g10/g10.c index 0be5636a2..234d13f41 100644 --- a/g10/g10.c +++ b/g10/g10.c @@ -933,7 +933,7 @@ static void add_group(char *string) return; } - trim_trailing_ws(name,strlen(name)); + trim_trailing_ws((unsigned char *)name,strlen(name)); /* Break apart the values */ while ((value= strsep(&string," \t"))) @@ -3124,7 +3124,7 @@ print_hashline( MD_HANDLE md, int algo, const char *fname ) const byte *p; if ( fname ) { - for (p = fname; *p; p++ ) { + for (p = (const unsigned char *)fname; *p; p++ ) { if ( *p <= 32 || *p > 127 || *p == ':' || *p == '%' ) printf("%%%02X", *p ); else diff --git a/g10/misc.c b/g10/misc.c index 7012a8a25..516e80bcc 100644 --- a/g10/misc.c +++ b/g10/misc.c @@ -986,9 +986,10 @@ mpi_print( FILE *fp, gcry_mpi_t a, int mode ) } else { int rc; - unsigned char *buffer; + char *buffer; - rc = gcry_mpi_aprint( GCRYMPI_FMT_HEX, &buffer, NULL, a ); + rc = gcry_mpi_aprint( GCRYMPI_FMT_HEX, + &(unsigned char*)buffer, NULL, a ); assert( !rc ); fputs( buffer, fp ); n += strlen(buffer); diff --git a/jnlib/ChangeLog b/jnlib/ChangeLog index f308a7ea3..f0463c5b3 100644 --- a/jnlib/ChangeLog +++ b/jnlib/ChangeLog @@ -1,3 +1,16 @@ +2005-06-15 Werner Koch + + * stringhelp.c (sanitize_buffer): Make P a void*. + (ascii_memistr, memistr): Ditto. + (ascii_memcasecmp): Ditto. + * logging.c (writen): Use void * for arg BUFFER. + * stringhelp.c (memistr): Fixed unsigned/signed pointer conflict. + (ascii_memistr): Ditto. + (ascii_memcasemem): Ditto. + * utf8conv.c (utf8_to_native): Ditto. + (utf8_to_native): Ditto. + * argparse.c (show_version): Removed non-required cast. + 2005-01-19 Werner Koch * logging.c (fun_writer): Don't fallback to stderr. Print to diff --git a/jnlib/argparse.c b/jnlib/argparse.c index 485c60786..980d1186c 100644 --- a/jnlib/argparse.c +++ b/jnlib/argparse.c @@ -852,7 +852,7 @@ show_version() /* additional program info */ for(i=30; i < 40; i++ ) if( (s=strusage(i)) ) - fputs( (const byte*)s, stdout); + fputs (s, stdout); fflush(stdout); } diff --git a/jnlib/logging.c b/jnlib/logging.c index 97a2b9c9e..c944006a5 100644 --- a/jnlib/logging.c +++ b/jnlib/logging.c @@ -87,10 +87,11 @@ struct fun_cookie_s { char name[1]; }; -/* Write NBYTES of BUF to file descriptor FD. */ +/* Write NBYTES of BUFFER to file descriptor FD. */ static int -writen (int fd, const unsigned char *buf, size_t nbytes) +writen (int fd, const void *buffer, size_t nbytes) { + const char *buf = buffer; size_t nleft = nbytes; int nwritten; diff --git a/jnlib/stringhelp.c b/jnlib/stringhelp.c index 5a3b41528..760398b0c 100644 --- a/jnlib/stringhelp.c +++ b/jnlib/stringhelp.c @@ -1,6 +1,6 @@ /* stringhelp.c - standard string helper functions * Copyright (C) 1998, 1999, 2000, 2001, 2003, - * 2004 Free Software Foundation, Inc. + * 2004, 2005 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -35,45 +35,57 @@ /* * Look for the substring SUB in buffer and return a pointer to that - * substring in BUF or NULL if not found. + * substring in BUFFER or NULL if not found. * Comparison is case-insensitive. */ const char * -memistr( const char *buf, size_t buflen, const char *sub ) +memistr (const void *buffer, size_t buflen, const char *sub) { - const byte *t, *s ; - size_t n; + const unsigned char *buf = buffer; + const unsigned char *t = (const unsigned char *)buffer; + const unsigned char *s = (const unsigned char *)sub; + size_t n = buflen; - for( t=buf, n=buflen, s=sub ; n ; t++, n-- ) - if( toupper(*t) == toupper(*s) ) { - for( buf=t++, buflen = n--, s++; - n && toupper(*t) == toupper(*s); t++, s++, n-- ) - ; - if( !*s ) - return buf; - t = buf; n = buflen; s = sub ; + for ( ; n ; t++, n-- ) + { + if ( toupper (*t) == toupper (*s) ) + { + for ( buf=t++, buflen = n--, s++; + n && toupper (*t) == toupper (*s); t++, s++, n-- ) + ; + if (!*s) + return (const char*)buf; + t = buf; + s = (const unsigned char *)sub ; + n = buflen; } - - return NULL ; + } + return NULL; } const char * -ascii_memistr( const char *buf, size_t buflen, const char *sub ) +ascii_memistr ( const void *buffer, size_t buflen, const char *sub ) { - const byte *t, *s ; - size_t n; + const unsigned char *buf = buffer; + const unsigned char *t = (const unsigned char *)buf; + const unsigned char *s = (const unsigned char *)sub; + size_t n = buflen; - for( t=buf, n=buflen, s=sub ; n ; t++, n-- ) - if( ascii_toupper(*t) == ascii_toupper(*s) ) { - for( buf=t++, buflen = n--, s++; - n && ascii_toupper(*t) == ascii_toupper(*s); t++, s++, n-- ) - ; - if( !*s ) - return buf; - t = buf; n = buflen; s = sub ; + for ( ; n ; t++, n-- ) + { + if (ascii_toupper (*t) == ascii_toupper (*s) ) + { + for ( buf=t++, buflen = n--, s++; + n && ascii_toupper (*t) == ascii_toupper (*s); t++, s++, n-- ) + ; + if (!*s) + return (const char*)buf; + t = (const unsigned char *)buf; + s = (const unsigned char *)sub ; + n = buflen; } - - return NULL ; + } + return NULL; } /* This function is similar to strncpy(). However it won't copy more @@ -402,13 +414,14 @@ print_sanitized_utf8_string (FILE *fp, const char *string, int delim) delim) : 0; } -/* Create a string from the buffer P of length N which is suitable for +/* Create a string from the buffer P_ARG of length N which is suitable for printing. Caller must release the created string using xfree. */ char * -sanitize_buffer (const unsigned char *p, size_t n, int delim) +sanitize_buffer (const void *p_arg, size_t n, int delim) { + const unsigned char *p = p_arg; size_t save_n, buflen; - const byte *save_p; + const unsigned char *save_p; char *buffer, *d; /* first count length */ @@ -552,15 +565,19 @@ ascii_strncasecmp (const char *a, const char *b, size_t n) int -ascii_memcasecmp( const char *a, const char *b, size_t n ) +ascii_memcasecmp (const void *a_arg, const void *b_arg, size_t n ) { - if (a == b) - return 0; - for ( ; n; n--, a++, b++ ) { - if( *a != *b && ascii_toupper (*a) != ascii_toupper (*b) ) - return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b)); - } + const char *a = a_arg; + const char *b = b_arg; + + if (a == b) return 0; + for ( ; n; n--, a++, b++ ) + { + if( *a != *b && ascii_toupper (*a) != ascii_toupper (*b) ) + return *a == *b? 0 : (ascii_toupper (*a) - ascii_toupper (*b)); + } + return 0; } int @@ -586,8 +603,8 @@ ascii_memcasemem (const void *haystack, size_t nhaystack, return (void*)haystack; /* finding an empty needle is really easy */ if (nneedle <= nhaystack) { - const unsigned char *a = haystack; - const unsigned char *b = a + nhaystack - nneedle; + const char *a = haystack; + const char *b = a + nhaystack - nneedle; for (; a <= b; a++) { diff --git a/jnlib/stringhelp.h b/jnlib/stringhelp.h index 412da3a0e..bdd7d561c 100644 --- a/jnlib/stringhelp.h +++ b/jnlib/stringhelp.h @@ -23,7 +23,7 @@ #include "types.h" -const char *memistr( const char *buf, size_t buflen, const char *sub ); +const char *memistr (const void *buf, size_t buflen, const char *sub); char *mem2str( char *, const void *, size_t); char *trim_spaces( char *string ); char *trim_trailing_spaces( char *string ); @@ -46,7 +46,7 @@ size_t print_sanitized_utf8_buffer (FILE *fp, const void *buffer, size_t length, int delim); size_t print_sanitized_string (FILE *fp, const char *string, int delim); size_t print_sanitized_utf8_string (FILE *fp, const char *string, int delim); -char *sanitize_buffer (const unsigned char *p, size_t n, int delim); +char *sanitize_buffer (const void *p, size_t n, int delim); #ifdef HAVE_W32_SYSTEM @@ -54,15 +54,14 @@ const char *w32_strerror (int ec); #endif -const char *ascii_memistr( const char *buf, size_t buflen, const char *sub ); int ascii_isupper (int c); int ascii_islower (int c); int ascii_toupper (int c); int ascii_tolower (int c); int ascii_strcasecmp( const char *a, const char *b ); int ascii_strncasecmp (const char *a, const char *b, size_t n); -int ascii_memcasecmp( const char *a, const char *b, size_t n ); -const char *ascii_memistr ( const char *buf, size_t buflen, const char *sub); +int ascii_memcasecmp( const void *a, const void *b, size_t n ); +const char *ascii_memistr ( const void *buf, size_t buflen, const char *sub); void *ascii_memcasemem (const void *haystack, size_t nhaystack, const void *needle, size_t nneedle); diff --git a/jnlib/utf8conv.c b/jnlib/utf8conv.c index 691176766..4df8b7b32 100644 --- a/jnlib/utf8conv.c +++ b/jnlib/utf8conv.c @@ -136,16 +136,17 @@ get_native_charset () * new allocated UTF8 string. */ char * -native_to_utf8 (const char *string) +native_to_utf8 (const char *orig_string) { - const byte *s; + const unsigned char *string = (const unsigned char *)orig_string; + const unsigned char *s; char *buffer; - byte *p; + unsigned char *p; size_t length = 0; if (no_translation) { - buffer = jnlib_xstrdup (string); + buffer = jnlib_xstrdup (orig_string); } else if (active_charset) { @@ -156,7 +157,7 @@ native_to_utf8 (const char *string) length += 2; /* we may need 3 bytes */ } buffer = jnlib_xmalloc (length + 1); - for (p = buffer, s = string; *s; s++) + for (p = (unsigned char *)buffer, s = string; *s; s++) { if ((*s & 0x80)) { @@ -187,7 +188,7 @@ native_to_utf8 (const char *string) length++; } buffer = jnlib_xmalloc (length + 1); - for (p = buffer, s = string; *s; s++) + for (p = (unsigned char *)buffer, s = string; *s; s++) { if (*s & 0x80) { @@ -212,11 +213,12 @@ utf8_to_native (const char *string, size_t length, int delim) { int nleft; int i; - byte encbuf[8]; + unsigned char encbuf[8]; int encidx; const byte *s; size_t n; - byte *buffer = NULL, *p = NULL; + char *buffer = NULL; + char *p = NULL; unsigned long val = 0; size_t slen; int resync = 0; @@ -225,7 +227,8 @@ utf8_to_native (const char *string, size_t length, int delim) /* 2. pass (p!=NULL): create string */ for (;;) { - for (slen = length, nleft = encidx = 0, n = 0, s = string; slen; + for (slen = length, nleft = encidx = 0, n = 0, + s = (const unsigned char *)string; slen; s++, slen--) { if (resync) diff --git a/kbx/ChangeLog b/kbx/ChangeLog index 7c112085c..4fd06d5ca 100644 --- a/kbx/ChangeLog +++ b/kbx/ChangeLog @@ -1,3 +1,14 @@ +2005-06-15 Werner Koch + + * keybox-file.c (_keybox_read_blob2): Make IMAGE unsigned. + (_keybox_write_blob): + + * keybox-blob.c (create_blob_finish, _keybox_create_x509_blob): + Fixed warnings about signed/unsigned pointer mismatches. + (x509_email_kludge): Ditto. + (_keybox_new_blob): Changed arg IMAGE to unsigned char *. + (_keybox_get_blob_image): Changed return type to unsigned char*. + 2005-06-01 Werner Koch * keybox-file.c (ftello) [!HAVE_FSEEKO]: New replacement diff --git a/kbx/kbxutil.c b/kbx/kbxutil.c index 7fe6178d6..0569b5a67 100644 --- a/kbx/kbxutil.c +++ b/kbx/kbxutil.c @@ -386,7 +386,7 @@ import_openpgp (const char *filename) buffer = read_file (filename, &buflen); if (!buffer) return; - p = buffer; + p = (unsigned char *)buffer; for (;;) { err = _keybox_parse_openpgp (p, buflen, &nparsed, &info); diff --git a/kbx/keybox-blob.c b/kbx/keybox-blob.c index 48bce28e2..67c74b777 100644 --- a/kbx/keybox-blob.c +++ b/kbx/keybox-blob.c @@ -646,8 +646,8 @@ static int create_blob_finish (KEYBOXBLOB blob) { struct membuf *a = blob->buf; - byte *p; - char *pp; + unsigned char *p; + unsigned char *pp; int i; size_t n; @@ -656,6 +656,7 @@ create_blob_finish (KEYBOXBLOB blob) put32 (a, 0); /* Hmmm: why put32() ?? */ /* get the memory area */ + n = 0; /* (Just to avoid compiler warning.) */ p = get_membuf (a, &n); if (!p) return gpg_error (GPG_ERR_ENOMEM); @@ -783,7 +784,7 @@ _keybox_create_pgp_blob (KEYBOXBLOB *r_blob, KBNODE keyblock, int as_ephemeral) static char * x509_email_kludge (const char *name) { - const unsigned char *p; + const char *p; unsigned char *buf; int n; @@ -805,7 +806,7 @@ x509_email_kludge (const char *name) buf[n] = xtoi_2 (p); buf[n++] = '>'; buf[n] = 0; - return buf; + return (char *)buf; } @@ -818,8 +819,9 @@ _keybox_create_x509_blob (KEYBOXBLOB *r_blob, ksba_cert_t cert, { int i, rc = 0; KEYBOXBLOB blob; - unsigned char *p; - unsigned char **names = NULL; + unsigned char *sn; + char *p; + char **names = NULL; size_t max_names; *r_blob = NULL; @@ -827,28 +829,28 @@ _keybox_create_x509_blob (KEYBOXBLOB *r_blob, ksba_cert_t cert, if( !blob ) return gpg_error (gpg_err_code_from_errno (errno)); - p = ksba_cert_get_serial (cert); - if (p) + sn = ksba_cert_get_serial (cert); + if (sn) { size_t n, len; - n = gcry_sexp_canon_len (p, 0, NULL, NULL); + n = gcry_sexp_canon_len (sn, 0, NULL, NULL); if (n < 2) { - xfree (p); + xfree (sn); return gpg_error (GPG_ERR_GENERAL); } - blob->serialbuf = p; - p++; n--; /* skip '(' */ - for (len=0; n && *p && *p != ':' && digitp (p); n--, p++) - len = len*10 + atoi_1 (p); - if (*p != ':') + blob->serialbuf = sn; + sn++; n--; /* skip '(' */ + for (len=0; n && *sn && *sn != ':' && digitp (sn); n--, sn++) + len = len*10 + atoi_1 (sn); + if (*sn != ':') { xfree (blob->serialbuf); blob->serialbuf = NULL; return gpg_error (GPG_ERR_GENERAL); } - p++; - blob->serial = p; + sn++; + blob->serial = sn; blob->seriallen = len; } @@ -863,6 +865,7 @@ _keybox_create_x509_blob (KEYBOXBLOB *r_blob, ksba_cert_t cert, rc = gpg_error (gpg_err_code_from_errno (errno)); goto leave; } + p = ksba_cert_get_issuer (cert, 0); if (!p) { @@ -872,10 +875,9 @@ _keybox_create_x509_blob (KEYBOXBLOB *r_blob, ksba_cert_t cert, names[blob->nuids++] = p; for (i=0; (p = ksba_cert_get_subject (cert, i)); i++) { - if (blob->nuids >= max_names) { - unsigned char **tmp; + char **tmp; max_names += 100; tmp = xtryrealloc (names, max_names * sizeof *names); @@ -964,7 +966,8 @@ _keybox_create_x509_blob (KEYBOXBLOB *r_blob, ksba_cert_t cert, int -_keybox_new_blob (KEYBOXBLOB *r_blob, char *image, size_t imagelen, off_t off) +_keybox_new_blob (KEYBOXBLOB *r_blob, + unsigned char *image, size_t imagelen, off_t off) { KEYBOXBLOB blob; @@ -1000,7 +1003,7 @@ _keybox_release_blob (KEYBOXBLOB blob) -const char * +const unsigned char * _keybox_get_blob_image ( KEYBOXBLOB blob, size_t *n ) { *n = blob->bloblen; diff --git a/kbx/keybox-defs.h b/kbx/keybox-defs.h index b58294459..7bbed8519 100644 --- a/kbx/keybox-defs.h +++ b/kbx/keybox-defs.h @@ -140,10 +140,11 @@ int _keybox_create_x509_blob (KEYBOXBLOB *r_blob, ksba_cert_t cert, unsigned char *sha1_digest, int as_ephemeral); #endif /*KEYBOX_WITH_X509*/ -int _keybox_new_blob (KEYBOXBLOB *r_blob, char *image, size_t imagelen, +int _keybox_new_blob (KEYBOXBLOB *r_blob, + unsigned char *image, size_t imagelen, off_t off); void _keybox_release_blob (KEYBOXBLOB blob); -const char *_keybox_get_blob_image (KEYBOXBLOB blob, size_t *n); +const unsigned char *_keybox_get_blob_image (KEYBOXBLOB blob, size_t *n); off_t _keybox_get_blob_fileoffset (KEYBOXBLOB blob); void _keybox_update_header_blob (KEYBOXBLOB blob); diff --git a/kbx/keybox-file.c b/kbx/keybox-file.c index fe02c1f9f..3883ce607 100644 --- a/kbx/keybox-file.c +++ b/kbx/keybox-file.c @@ -48,7 +48,7 @@ ftello (FILE *stream) int _keybox_read_blob2 (KEYBOXBLOB *r_blob, FILE *fp, int *skipped_deleted) { - char *image; + unsigned char *image; size_t imagelen = 0; int c1, c2, c3, c4, type; int rc; @@ -118,7 +118,7 @@ _keybox_read_blob (KEYBOXBLOB *r_blob, FILE *fp) int _keybox_write_blob (KEYBOXBLOB blob, FILE *fp) { - const char *image; + const unsigned char *image; size_t length; image = _keybox_get_blob_image (blob, &length); diff --git a/scd/apdu.c b/scd/apdu.c index 212b9df24..975fffa24 100644 --- a/scd/apdu.c +++ b/scd/apdu.c @@ -2393,7 +2393,7 @@ apdu_activate (int slot) unsigned char * apdu_get_atr (int slot, size_t *atrlen) { - char *buf; + unsigned char *buf; if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used ) return NULL; diff --git a/scd/app-help.c b/scd/app-help.c index 1c3c52b15..27cbea5c7 100644 --- a/scd/app-help.c +++ b/scd/app-help.c @@ -48,7 +48,7 @@ app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip) n = gcry_sexp_canon_len (p, 0, NULL, NULL); if (!n) return gpg_error (GPG_ERR_INV_SEXP); - err = gcry_sexp_sscan (&s_pkey, NULL, p, n); + err = gcry_sexp_sscan (&s_pkey, NULL, (char*)p, n); xfree (p); if (err) return err; /* Can't parse that S-expression. */ diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 1ff096138..11e6eebaf 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -948,8 +948,8 @@ get_public_key (app_t app, int keyno) size_t buflen, keydatalen, mlen, elen; unsigned char *mbuf = NULL; unsigned char *ebuf = NULL; - unsigned char *keybuf = NULL; - unsigned char *keybuf_p; + char *keybuf = NULL; + char *keybuf_p; if (keyno < 1 || keyno > 3) return gpg_error (GPG_ERR_INV_ID); @@ -963,14 +963,16 @@ get_public_key (app_t app, int keyno) app->app_local->pk[keyno].key = NULL; app->app_local->pk[keyno].keylen = 0; + m = e = NULL; /* (avoid cc warning) */ + if (app->card_version > 0x0100) { /* We may simply read the public key out of these cards. */ - err = iso7816_read_public_key (app->slot, - keyno == 0? "\xB6" : - keyno == 1? "\xB8" : "\xA4", - 2, - &buffer, &buflen); + err = iso7816_read_public_key + (app->slot, (const unsigned char*)(keyno == 0? "\xB6" : + keyno == 1? "\xB8" : "\xA4"), + 2, + &buffer, &buflen); if (err) { log_error (_("reading public key failed: %s\n"), gpg_strerror (err)); @@ -1107,7 +1109,7 @@ get_public_key (app_t app, int keyno) strcpy (keybuf_p, ")))"); keybuf_p += strlen (keybuf_p); - app->app_local->pk[keyno].key = keybuf; + app->app_local->pk[keyno].key = (unsigned char*)keybuf; app->app_local->pk[keyno].keylen = (keybuf_p - keybuf); leave: @@ -1889,11 +1891,10 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags, #warning key generation temporary replaced by reading an existing key. rc = iso7816_read_public_key #endif - (app->slot, - keyno == 0? "\xB6" : - keyno == 1? "\xB8" : "\xA4", - 2, - &buffer, &buflen); + (app->slot, (const unsigned char*)(keyno == 0? "\xB6" : + keyno == 1? "\xB8" : "\xA4"), + 2, + &buffer, &buflen); if (rc) { rc = gpg_error (GPG_ERR_CARD); diff --git a/scd/app-p15.c b/scd/app-p15.c index 831f0d1f4..f03e5d5f0 100644 --- a/scd/app-p15.c +++ b/scd/app-p15.c @@ -43,33 +43,35 @@ typedef enum } card_type_t; /* A list card types with ATRs noticed with these cards. */ +#define X(a) ((unsigned char const *)(a)) static struct { size_t atrlen; - unsigned char *atr; + unsigned char const *atr; card_type_t type; } card_atr_list[] = { - { 19, "\x3B\xBA\x13\x00\x81\x31\x86\x5D\x00\x64\x05\x0A\x02\x01\x31\x80" - "\x90\x00\x8B", + { 19, X("\x3B\xBA\x13\x00\x81\x31\x86\x5D\x00\x64\x05\x0A\x02\x01\x31\x80" + "\x90\x00\x8B"), CARD_TYPE_TCOS }, /* SLE44 */ - { 19, "\x3B\xBA\x14\x00\x81\x31\x86\x5D\x00\x64\x05\x14\x02\x02\x31\x80" - "\x90\x00\x91", + { 19, X("\x3B\xBA\x14\x00\x81\x31\x86\x5D\x00\x64\x05\x14\x02\x02\x31\x80" + "\x90\x00\x91"), CARD_TYPE_TCOS }, /* SLE66S */ - { 19, "\x3B\xBA\x96\x00\x81\x31\x86\x5D\x00\x64\x05\x60\x02\x03\x31\x80" - "\x90\x00\x66", + { 19, X("\x3B\xBA\x96\x00\x81\x31\x86\x5D\x00\x64\x05\x60\x02\x03\x31\x80" + "\x90\x00\x66"), CARD_TYPE_TCOS }, /* SLE66P */ - { 27, "\x3B\xFF\x94\x00\xFF\x80\xB1\xFE\x45\x1F\x03\x00\x68\xD2\x76\x00" - "\x00\x28\xFF\x05\x1E\x31\x80\x00\x90\x00\x23", + { 27, X("\x3B\xFF\x94\x00\xFF\x80\xB1\xFE\x45\x1F\x03\x00\x68\xD2\x76\x00" + "\x00\x28\xFF\x05\x1E\x31\x80\x00\x90\x00\x23"), CARD_TYPE_MICARDO }, /* German BMI card */ - { 19, "\x3B\x6F\x00\xFF\x00\x68\xD2\x76\x00\x00\x28\xFF\x05\x1E\x31\x80" - "\x00\x90\x00", + { 19, X("\x3B\x6F\x00\xFF\x00\x68\xD2\x76\x00\x00\x28\xFF\x05\x1E\x31\x80" + "\x00\x90\x00"), CARD_TYPE_MICARDO }, /* German BMI card (ATR due to reader problem) */ - { 26, "\x3B\xFE\x94\x00\xFF\x80\xB1\xFA\x45\x1F\x03\x45\x73\x74\x45\x49" - "\x44\x20\x76\x65\x72\x20\x31\x2E\x30\x43", + { 26, X("\x3B\xFE\x94\x00\xFF\x80\xB1\xFA\x45\x1F\x03\x45\x73\x74\x45\x49" + "\x44\x20\x76\x65\x72\x20\x31\x2E\x30\x43"), CARD_TYPE_MICARDO }, /* EstEID (Estonian Big Brother card) */ { 0 } }; +#undef X /* The Pin Types as defined in pkcs#15 v1.1 */ diff --git a/scd/app.c b/scd/app.c index 2c8c915d7..f27b400b1 100644 --- a/scd/app.c +++ b/scd/app.c @@ -357,7 +357,7 @@ app_munge_serialno (app_t app) gpg_error_t app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp) { - unsigned char *buf, *p; + char *buf, *p; int i; if (!app || !serial) diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c index 9ac655e63..096a6811b 100644 --- a/scd/ccid-driver.c +++ b/scd/ccid-driver.c @@ -555,7 +555,7 @@ get_escaped_usb_string (usb_dev_handle *idev, int idx, all in a 2 bute Unicode encoding using little endian. */ rc = usb_control_msg (idev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8), 0, - buf, sizeof buf, 1000 /* ms timeout */); + (char*)buf, sizeof buf, 1000 /* ms timeout */); if (rc < 4) langid = 0x0409; /* English. */ else @@ -563,7 +563,7 @@ get_escaped_usb_string (usb_dev_handle *idev, int idx, rc = usb_control_msg (idev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) + idx, langid, - buf, sizeof buf, 1000 /* ms timeout */); + (char*)buf, sizeof buf, 1000 /* ms timeout */); if (rc < 2 || buf[1] != USB_DT_STRING) return NULL; /* Error or not a string. */ len = buf[0]; @@ -1155,7 +1155,7 @@ bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen) rc = usb_bulk_write (handle->idev, handle->ep_bulk_out, - msg, msglen, + (char*)msg, msglen, 1000 /* ms timeout */); if (rc == msglen) return 0; @@ -1188,7 +1188,7 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length, retry: rc = usb_bulk_read (handle->idev, handle->ep_bulk_in, - buffer, length, + (char*)buffer, length, timeout); if (rc < 0) { @@ -1300,7 +1300,7 @@ ccid_poll (ccid_driver_t handle) rc = usb_bulk_read (handle->idev, handle->ep_intr, - msg, sizeof msg, + (char*)msg, sizeof msg, 0 /* ms timeout */ ); if (rc < 0 && errno == ETIMEDOUT) return 0; @@ -1444,7 +1444,7 @@ ccid_get_atr (ccid_driver_t handle, { tried_iso = 1; /* Try switching to ISO mode. */ - if (!send_escape_cmd (handle, "\xF1\x01", 2)) + if (!send_escape_cmd (handle, (const unsigned char*)"\xF1\x01", 2)) goto again; } else if (CCID_COMMAND_FAILED (msg)) @@ -2026,7 +2026,7 @@ ccid_transceive_secure (ccid_driver_t handle, if (handle->id_vendor == VENDOR_SCM) { DEBUGOUT ("sending escape sequence to switch to a case 1 APDU\n"); - rc = send_escape_cmd (handle, "\x80\x02\x00", 3); + rc = send_escape_cmd (handle, (const unsigned char*)"\x80\x02\x00", 3); if (rc) return rc; } diff --git a/scd/command.c b/scd/command.c index a308078d3..52a86871e 100644 --- a/scd/command.c +++ b/scd/command.c @@ -679,7 +679,7 @@ pin_cb (void *opaque, const char *info, char **retstr) xfree (value); return gpg_error (GPG_ERR_INV_RESPONSE); } - *retstr = value; + *retstr = (char*)value; return 0; } @@ -844,7 +844,7 @@ cmd_getattr (assuan_context_t ctx, char *line) { ctrl_t ctrl = assuan_get_pointer (ctx); int rc; - char *keyword; + const char *keyword; if ((rc = open_card (ctrl, NULL))) return rc; @@ -860,7 +860,6 @@ cmd_getattr (assuan_context_t ctx, char *line) /* FIXME: Applications should not return sensistive data if the card is locked. */ rc = app_getattr (ctrl->app_ctx, ctrl, keyword); - xfree (keyword); TEST_CARD_REMOVAL (ctrl, rc); return map_to_assuan_status (rc); @@ -908,9 +907,10 @@ cmd_setattr (assuan_context_t ctx, char *orig_line) *line++ = 0; while (spacep (line)) line++; - nbytes = percent_plus_unescape (line); + nbytes = percent_plus_unescape ((unsigned char*)line); - rc = app_setattr (ctrl->app_ctx, keyword, pin_cb, ctx, line, nbytes); + rc = app_setattr (ctrl->app_ctx, keyword, pin_cb, ctx, + (const unsigned char*)line, nbytes); xfree (linebuf); TEST_CARD_REMOVAL (ctrl, rc); diff --git a/scd/iso7816.c b/scd/iso7816.c index e9dc6541c..742ed9433 100644 --- a/scd/iso7816.c +++ b/scd/iso7816.c @@ -153,7 +153,7 @@ iso7816_select_file (int slot, int tag, int is_dir, p0 = (tag == 0x3F00)? 0: is_dir? 1:2; p1 = 0x0c; /* No FC return. */ sw = apdu_send_simple (slot, 0x00, CMD_SELECT_FILE, - p0, p1, 2, tagbuf ); + p0, p1, 2, (char*)tagbuf ); return map_sw (sw); } @@ -285,7 +285,7 @@ iso7816_put_data (int slot, int tag, sw = apdu_send_simple (slot, 0x00, CMD_PUT_DATA, ((tag >> 8) & 0xff), (tag & 0xff), - datalen, data); + datalen, (const char*)data); return map_sw (sw); } @@ -303,7 +303,7 @@ iso7816_manage_security_env (int slot, int p1, int p2, return gpg_error (GPG_ERR_INV_VALUE); sw = apdu_send_simple (slot, 0x00, CMD_MSE, p1, p2, - data? datalen : -1, data); + data? datalen : -1, (const char*)data); return map_sw (sw); } @@ -323,7 +323,7 @@ iso7816_compute_ds (int slot, const unsigned char *data, size_t datalen, *result = NULL; *resultlen = 0; - sw = apdu_send (slot, 0x00, CMD_PSO, 0x9E, 0x9A, datalen, data, + sw = apdu_send (slot, 0x00, CMD_PSO, 0x9E, 0x9A, datalen, (const char*)data, result, resultlen); if (sw != SW_SUCCESS) { @@ -364,13 +364,15 @@ iso7816_decipher (int slot, const unsigned char *data, size_t datalen, *buf = padind; /* Padding indicator. */ memcpy (buf+1, data, datalen); - sw = apdu_send (slot, 0x00, CMD_PSO, 0x80, 0x86, datalen+1, buf, + sw = apdu_send (slot, 0x00, CMD_PSO, 0x80, 0x86, + datalen+1, (char*)buf, result, resultlen); xfree (buf); } else { - sw = apdu_send (slot, 0x00, CMD_PSO, 0x80, 0x86, datalen, data, + sw = apdu_send (slot, 0x00, CMD_PSO, 0x80, 0x86, + datalen, (const char *)data, result, resultlen); } if (sw != SW_SUCCESS) @@ -399,7 +401,7 @@ iso7816_internal_authenticate (int slot, *resultlen = 0; sw = apdu_send (slot, 0x00, CMD_INTERNAL_AUTHENTICATE, 0, 0, - datalen, data, result, resultlen); + datalen, (const char*)data, result, resultlen); if (sw != SW_SUCCESS) { /* Make sure that pending buffers are released. */ @@ -426,7 +428,7 @@ do_generate_keypair (int slot, int readonly, *resultlen = 0; sw = apdu_send (slot, 0x00, CMD_GENERATE_KEYPAIR, readonly? 0x81:0x80, 0, - datalen, data, result, resultlen); + datalen, (const char*)data, result, resultlen); if (sw != SW_SUCCESS) { /* Make sure that pending buffers are released. */ diff --git a/scd/pcsc-wrapper.c b/scd/pcsc-wrapper.c index 93e78fdfe..21af16fba 100644 --- a/scd/pcsc-wrapper.c +++ b/scd/pcsc-wrapper.c @@ -390,9 +390,9 @@ handle_open (unsigned char *argbuf, size_t arglen) unsigned char atr[33]; /* Make sure there is only the port string */ - if (arglen != strlen (argbuf)) + if (arglen != strlen ((char*)argbuf)) bad_request ("OPEN"); - portstr = argbuf; + portstr = (char*)argbuf; if (driver_is_open) { diff --git a/sm/ChangeLog b/sm/ChangeLog index ffb61a294..d9f295e1d 100644 --- a/sm/ChangeLog +++ b/sm/ChangeLog @@ -1,3 +1,35 @@ +2005-06-15 Werner Koch + + * delete.c (delete_one): Changed FPR to unsigned. + * encrypt.c (encrypt_dek): Made ENCVAL unsigned. + (gpgsm_encrypt): Ditto. + * sign.c (gpgsm_sign): Made SIGVAL unsigned. + * base64.c (base64_reader_cb): Need to use some casting to get + around signed/unsigned char* warnings. + * certcheck.c (gpgsm_check_cms_signature): Ditto. + (gpgsm_create_cms_signature): Changed arg R_SIGVAL to unsigned char*. + (do_encode_md): Made NFRAME a size_t. + * certdump.c (gpgsm_print_serial): Fixed signed/unsigned warning. + (gpgsm_dump_serial): Ditto. + (gpgsm_format_serial): Ditto. + (gpgsm_dump_string): Ditto. + (gpgsm_dump_cert): Ditto. + (parse_dn_part): Ditto. + (gpgsm_print_name2): Ditto. + * keylist.c (email_kludge): Ditto. + * certreqgen.c (proc_parameters, create_request): Ditto. + (create_request): Ditto. + * call-agent.c (gpgsm_agent_pksign): Made arg R_BUF unsigned. + (struct cipher_parm_s): Made CIPHERTEXT unsigned. + (struct genkey_parm_s): Ditto. + * server.c (strcpy_escaped_plus): Made arg S signed char*. + * fingerprint.c (gpgsm_get_fingerprint): Made ARRAY unsigned. + (gpgsm_get_keygrip): Ditto. + * keydb.c (keydb_insert_cert): Made DIGEST unsigned. + (keydb_update_cert): Ditto. + (classify_user_id): Apply cast to signed/unsigned assignment. + (hextobyte): Ditto. + 2005-06-01 Werner Koch * misc.c: Include setenv.h. diff --git a/sm/base64.c b/sm/base64.c index 4cc6ffa27..62c2c9ad9 100644 --- a/sm/base64.c +++ b/sm/base64.c @@ -95,7 +95,7 @@ struct base64_context_s { /* The base-64 character list */ -static unsigned char bintoasc[64] = +static char bintoasc[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789+/"; @@ -202,8 +202,9 @@ base64_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread) { /* wait for the header line */ parm->linelen = parm->readpos = 0; - if (!parm->have_lf || strncmp (parm->line, "-----BEGIN ", 11) - || !strncmp (parm->line+11, "PGP ", 4)) + if (!parm->have_lf + || strncmp ((char*)parm->line, "-----BEGIN ", 11) + || !strncmp ((char*)parm->line+11, "PGP ", 4)) goto next; parm->is_pem = 1; } @@ -220,8 +221,9 @@ base64_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread) /* the very first byte does pretty much look like a SEQUENCE tag*/ parm->is_pem = 0; } - else if ( parm->have_lf && !strncmp (parm->line, "-----BEGIN ", 11) - && strncmp (parm->line+11, "PGP ", 4) ) + else if ( parm->have_lf + && !strncmp ((char*)parm->line, "-----BEGIN ", 11) + && strncmp ((char *)parm->line+11, "PGP ", 4) ) { /* Fixme: we must only compare if the line really starts at the beginning */ @@ -268,7 +270,7 @@ base64_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread) if (parm->is_pem || parm->is_base64) { if (parm->is_pem && parm->have_lf - && !strncmp (parm->line, "-----END ", 9)) + && !strncmp ((char*)parm->line, "-----END ", 9)) { parm->identified = 0; parm->linelen = parm->readpos = 0; diff --git a/sm/call-agent.c b/sm/call-agent.c index 885abf421..92a29928c 100644 --- a/sm/call-agent.c +++ b/sm/call-agent.c @@ -39,24 +39,27 @@ #include "../common/membuf.h" -static ASSUAN_CONTEXT agent_ctx = NULL; +static assuan_context_t agent_ctx = NULL; static int force_pipe_server = 0; -struct cipher_parm_s { - ASSUAN_CONTEXT ctx; - const char *ciphertext; +struct cipher_parm_s +{ + assuan_context_t ctx; + const unsigned char *ciphertext; size_t ciphertextlen; }; -struct genkey_parm_s { - ASSUAN_CONTEXT ctx; - const char *sexp; +struct genkey_parm_s +{ + assuan_context_t ctx; + const unsigned char *sexp; size_t sexplen; }; -struct learn_parm_s { +struct learn_parm_s +{ int error; - ASSUAN_CONTEXT ctx; + assuan_context_t ctx; membuf_t *data; }; @@ -204,7 +207,7 @@ membuf_data_cb (void *opaque, const void *buffer, size_t length) int gpgsm_agent_pksign (ctrl_t ctrl, const char *keygrip, const char *desc, unsigned char *digest, size_t digestlen, int digestalgo, - char **r_buf, size_t *r_buflen ) + unsigned char **r_buf, size_t *r_buflen ) { int rc, i; char *p, line[ASSUAN_LINELENGTH]; @@ -392,7 +395,7 @@ gpgsm_agent_genkey (ctrl_t ctrl, struct genkey_parm_s gk_parm; membuf_t data; size_t len; - char *buf; + unsigned char *buf; *r_pubkey = NULL; rc = start_agent (ctrl); diff --git a/sm/certcheck.c b/sm/certcheck.c index 611d3219c..84dfdb9ab 100644 --- a/sm/certcheck.c +++ b/sm/certcheck.c @@ -39,7 +39,8 @@ static int do_encode_md (gcry_md_hd_t md, int algo, int pkalgo, unsigned int nbits, gcry_mpi_t *r_val) { - int n, nframe; + int n; + size_t nframe; unsigned char *frame; if (pkalgo == GCRY_PK_DSA) @@ -205,7 +206,7 @@ gpgsm_check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert) log_printf ("\n"); } - rc = gcry_sexp_sscan ( &s_sig, NULL, p, n); + rc = gcry_sexp_sscan ( &s_sig, NULL, (char*)p, n); ksba_free (p); if (rc) { @@ -224,7 +225,7 @@ gpgsm_check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert) gcry_sexp_release (s_sig); return gpg_error (GPG_ERR_BUG); } - rc = gcry_sexp_sscan ( &s_pkey, NULL, p, n); + rc = gcry_sexp_sscan ( &s_pkey, NULL, (char*)p, n); ksba_free (p); if (rc) { @@ -278,7 +279,7 @@ gpgsm_check_cms_signature (ksba_cert_t cert, ksba_const_sexp_t sigval, log_error ("libksba did not return a proper S-Exp\n"); return gpg_error (GPG_ERR_BUG); } - rc = gcry_sexp_sscan (&s_sig, NULL, sigval, n); + rc = gcry_sexp_sscan (&s_sig, NULL, (char*)sigval, n); if (rc) { log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc)); @@ -297,7 +298,7 @@ gpgsm_check_cms_signature (ksba_cert_t cert, ksba_const_sexp_t sigval, if (DBG_CRYPTO) log_printhex ("public key: ", p, n); - rc = gcry_sexp_sscan ( &s_pkey, NULL, p, n); + rc = gcry_sexp_sscan ( &s_pkey, NULL, (char*)p, n); ksba_free (p); if (rc) { @@ -333,7 +334,8 @@ gpgsm_check_cms_signature (ksba_cert_t cert, ksba_const_sexp_t sigval, int gpgsm_create_cms_signature (ctrl_t ctrl, ksba_cert_t cert, - gcry_md_hd_t md, int mdalgo, char **r_sigval) + gcry_md_hd_t md, int mdalgo, + unsigned char **r_sigval) { int rc; char *grip, *desc; diff --git a/sm/certdump.c b/sm/certdump.c index 26510c70d..98f019c4a 100644 --- a/sm/certdump.c +++ b/sm/certdump.c @@ -50,8 +50,9 @@ struct dn_array_s { /* print the first element of an S-Expression */ void -gpgsm_print_serial (FILE *fp, ksba_const_sexp_t p) +gpgsm_print_serial (FILE *fp, ksba_const_sexp_t sn) { + const char *p = (const char *)sn; unsigned long n; char *endp; @@ -77,8 +78,9 @@ 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) +gpgsm_dump_serial (ksba_const_sexp_t sn) { + const char *p = (const char *)sn; unsigned long n; char *endp; @@ -103,8 +105,9 @@ gpgsm_dump_serial (ksba_const_sexp_t p) char * -gpgsm_format_serial (ksba_const_sexp_t p) +gpgsm_format_serial (ksba_const_sexp_t sn) { + const char *p = (const char *)sn; unsigned long n; char *endp; char *buffer; @@ -168,7 +171,7 @@ gpgsm_dump_string (const char *string) { const unsigned char *s; - for (s=string; *s; s++) + for (s=(const unsigned char*)string; *s; s++) { if (*s < ' ' || (*s >= 0x7f && *s <= 0xa0)) break; @@ -190,7 +193,7 @@ void gpgsm_dump_cert (const char *text, ksba_cert_t cert) { ksba_sexp_t sexp; - unsigned char *p; + char *p; char *dn; ksba_isotime_t t; @@ -260,7 +263,7 @@ parse_dn_part (struct dn_array_s *array, const unsigned char *string) }; const unsigned char *s, *s1; size_t n; - unsigned char *p; + char *p; int i; /* Parse attributeType */ @@ -306,7 +309,7 @@ parse_dn_part (struct dn_array_s *array, const unsigned char *string) return NULL; for (s1=string; n; s1 += 2, n--, p++) { - *p = xtoi_2 (s1); + *(unsigned char *)p = xtoi_2 (s1); if (!*p) *p = 0x01; /* Better print a wrong value than truncating the string. */ @@ -351,7 +354,7 @@ parse_dn_part (struct dn_array_s *array, const unsigned char *string) s++; if (hexdigitp (s)) { - *p++ = xtoi_2 (s); + *(unsigned char *)p++ = xtoi_2 (s); s++; } else @@ -485,23 +488,22 @@ print_dn_parts (FILE *fp, struct dn_array_s *dn, int translate) void gpgsm_print_name2 (FILE *fp, const char *name, int translate) { - const unsigned char *s; + const unsigned char *s = (const unsigned char *)name; int i; - s = name; if (!s) { fputs (_("[Error - No name]"), fp); } else if (*s == '<') { - const unsigned char *s2 = strchr (s+1, '>'); + const char *s2 = strchr ( (char*)s+1, '>'); if (s2) { if (translate) - print_sanitized_utf8_buffer (fp, s + 1, s2 - s - 1, 0); + print_sanitized_utf8_buffer (fp, s + 1, s2 - (char*)s - 1, 0); else - print_sanitized_buffer (fp, s + 1, s2 - s - 1, 0); + print_sanitized_buffer (fp, s + 1, s2 - (char*)s - 1, 0); } } else if (*s == '(') diff --git a/sm/certreqgen.c b/sm/certreqgen.c index 7b29a5b8d..2b920da7e 100644 --- a/sm/certreqgen.c +++ b/sm/certreqgen.c @@ -492,7 +492,7 @@ proc_parameters (ctrl_t ctrl, } sprintf (numbuf, "%u", nbits); - snprintf (keyparms, DIM (keyparms)-1, + snprintf ((char*)keyparms, DIM (keyparms)-1, "(6:genkey(3:rsa(5:nbits%d:%s)))", (int)strlen (numbuf), numbuf); rc = gpgsm_agent_genkey (ctrl, keyparms, &public); if (rc) @@ -627,8 +627,9 @@ create_request (ctrl_t ctrl, { gcry_sexp_t s_pkey; size_t n; - unsigned char grip[20], hexgrip[41]; - char *sigval; + unsigned char grip[20]; + char hexgrip[41]; + unsigned char *sigval; size_t siglen; n = gcry_sexp_canon_len (public, 0, NULL, NULL); @@ -638,7 +639,7 @@ create_request (ctrl_t ctrl, err = gpg_error (GPG_ERR_BUG); goto leave; } - rc = gcry_sexp_sscan (&s_pkey, NULL, public, n); + rc = gcry_sexp_sscan (&s_pkey, NULL, (const char*)public, n); if (rc) { log_error ("gcry_sexp_scan failed: %s\n", gpg_strerror (rc)); diff --git a/sm/delete.c b/sm/delete.c index 11a0a5476..8e06b9489 100644 --- a/sm/delete.c +++ b/sm/delete.c @@ -67,7 +67,7 @@ delete_one (CTRL ctrl, const char *username) rc = keydb_get_cert (kh, &cert); if (!rc) { - char fpr[20]; + unsigned char fpr[20]; gpgsm_get_fingerprint (cert, 0, fpr, NULL); @@ -78,7 +78,7 @@ delete_one (CTRL ctrl, const char *username) else if (!rc) { ksba_cert_t cert2 = NULL; - char fpr2[20]; + unsigned char fpr2[20]; /* We ignore all duplicated certificates which might have been inserted due to program bugs. */ diff --git a/sm/encrypt.c b/sm/encrypt.c index 50da92c32..e4c0d5437 100644 --- a/sm/encrypt.c +++ b/sm/encrypt.c @@ -164,10 +164,10 @@ encode_session_key (DEK dek, gcry_sexp_t * r_data) } -/* encrypt the DEK under the key contained in CERT and return it as a - canonical S-Exp in encval */ +/* Encrypt the DEK under the key contained in CERT and return it as a + canonical S-Exp in encval. */ static int -encrypt_dek (const DEK dek, ksba_cert_t cert, char **encval) +encrypt_dek (const DEK dek, ksba_cert_t cert, unsigned char **encval) { gcry_sexp_t s_ciph, s_data, s_pkey; int rc; @@ -189,7 +189,7 @@ encrypt_dek (const DEK dek, ksba_cert_t cert, char **encval) log_error ("libksba did not return a proper S-Exp\n"); return gpg_error (GPG_ERR_BUG); } - rc = gcry_sexp_sscan (&s_pkey, NULL, buf, len); + rc = gcry_sexp_sscan (&s_pkey, NULL, (char*)buf, len); xfree (buf); buf = NULL; if (rc) { @@ -220,7 +220,7 @@ encrypt_dek (const DEK dek, ksba_cert_t cert, char **encval) gcry_sexp_release (s_ciph); return tmperr; } - len = gcry_sexp_sprint (s_ciph, GCRYSEXP_FMT_CANON, buf, len); + len = gcry_sexp_sprint (s_ciph, GCRYSEXP_FMT_CANON, (char*)buf, len); assert (len); *encval = buf; @@ -437,7 +437,7 @@ gpgsm_encrypt (CTRL ctrl, CERTLIST recplist, int data_fd, FILE *out_fp) each and store them in the CMS object */ for (recpno = 0, cl = recplist; cl; recpno++, cl = cl->next) { - char *encval; + unsigned char *encval; rc = encrypt_dek (dek, cl->cert, &encval); if (rc) diff --git a/sm/fingerprint.c b/sm/fingerprint.c index 7fe619c18..9c3ab85db 100644 --- a/sm/fingerprint.c +++ b/sm/fingerprint.c @@ -42,8 +42,9 @@ If there is a problem , the function does never return NULL but a digest of all 0xff. */ -char * -gpgsm_get_fingerprint (ksba_cert_t cert, int algo, char *array, int *r_len) +unsigned char * +gpgsm_get_fingerprint (ksba_cert_t cert, int algo, + unsigned char *array, int *r_len) { gcry_md_hd_t md; int rc, len; @@ -140,8 +141,8 @@ gpgsm_get_short_fingerprint (ksba_cert_t cert) key parameters expressed as an canoncial encoded S-Exp. array must be 20 bytes long. returns the array or a newly allocated one if the passed one was NULL */ -char * -gpgsm_get_keygrip (ksba_cert_t cert, char *array) +unsigned char * +gpgsm_get_keygrip (ksba_cert_t cert, unsigned char *array) { gcry_sexp_t s_pkey; int rc; @@ -160,7 +161,7 @@ gpgsm_get_keygrip (ksba_cert_t cert, char *array) log_error ("libksba did not return a proper S-Exp\n"); return NULL; } - rc = gcry_sexp_sscan ( &s_pkey, NULL, p, n); + rc = gcry_sexp_sscan ( &s_pkey, NULL, (char*)p, n); xfree (p); if (rc) { @@ -223,7 +224,7 @@ gpgsm_get_key_algo_info (ksba_cert_t cert, unsigned int *nbits) xfree (p); return 0; } - rc = gcry_sexp_sscan (&s_pkey, NULL, p, n); + rc = gcry_sexp_sscan (&s_pkey, NULL, (char *)p, n); xfree (p); if (rc) return 0; @@ -272,7 +273,7 @@ char * gpgsm_get_certid (ksba_cert_t cert) { ksba_sexp_t serial; - unsigned char *p; + char *p; char *endp; unsigned char hash[20]; unsigned long n; @@ -288,7 +289,7 @@ gpgsm_get_certid (ksba_cert_t cert) serial = ksba_cert_get_serial (cert); if (!serial) return NULL; /* oops: no serial number */ - p = serial; + p = (char *)serial; if (*p != '(') { log_error ("Ooops: invalid serial number\n"); diff --git a/sm/gpgsm.h b/sm/gpgsm.h index 1068e9d5e..2f3e83485 100644 --- a/sm/gpgsm.h +++ b/sm/gpgsm.h @@ -181,12 +181,12 @@ gpg_error_t gpgsm_status_with_err_code (ctrl_t ctrl, int no, const char *text, gpg_err_code_t ec); /*-- fingerprint --*/ -char *gpgsm_get_fingerprint (ksba_cert_t cert, int algo, - char *array, int *r_len); +unsigned char *gpgsm_get_fingerprint (ksba_cert_t cert, int algo, + unsigned char *array, int *r_len); char *gpgsm_get_fingerprint_string (ksba_cert_t cert, int algo); char *gpgsm_get_fingerprint_hexstring (ksba_cert_t cert, int algo); unsigned long gpgsm_get_short_fingerprint (ksba_cert_t cert); -char *gpgsm_get_keygrip (ksba_cert_t cert, char *array); +unsigned char *gpgsm_get_keygrip (ksba_cert_t cert, unsigned char *array); char *gpgsm_get_keygrip_hexstring (ksba_cert_t cert); int gpgsm_get_key_algo_info (ksba_cert_t cert, unsigned int *nbits); char *gpgsm_get_certid (ksba_cert_t cert); @@ -229,7 +229,7 @@ int gpgsm_check_cms_signature (ksba_cert_t cert, ksba_const_sexp_t sigval, /* fixme: move create functions to another file */ int gpgsm_create_cms_signature (ctrl_t ctrl, ksba_cert_t cert, gcry_md_hd_t md, int mdalgo, - char **r_sigval); + unsigned char **r_sigval); /*-- certchain.c --*/ @@ -293,7 +293,7 @@ int gpgsm_agent_pksign (ctrl_t ctrl, const char *keygrip, const char *desc, unsigned char *digest, size_t digestlen, int digestalgo, - char **r_buf, size_t *r_buflen); + unsigned char **r_buf, size_t *r_buflen); int gpgsm_agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc, ksba_const_sexp_t ciphertext, char **r_buf, size_t *r_buflen); diff --git a/sm/keydb.c b/sm/keydb.c index 293e5233d..17f04fe4b 100644 --- a/sm/keydb.c +++ b/sm/keydb.c @@ -681,7 +681,7 @@ keydb_insert_cert (KEYDB_HANDLE hd, ksba_cert_t cert) { int rc = -1; int idx; - char digest[20]; + unsigned char digest[20]; if (!hd) return gpg_error (GPG_ERR_INV_VALUE); @@ -723,7 +723,7 @@ int keydb_update_cert (KEYDB_HANDLE hd, ksba_cert_t cert) { int rc = 0; - char digest[20]; + unsigned char digest[20]; if (!hd) return gpg_error (GPG_ERR_INV_VALUE); @@ -1010,8 +1010,9 @@ keydb_search_subject (KEYDB_HANDLE hd, const char *name) static int -hextobyte (const unsigned char *s) +hextobyte (const char *string) { + const unsigned char *s = (const unsigned char *)string; int c; if( *s >= '0' && *s <= '9' ) @@ -1122,7 +1123,7 @@ classify_user_id (const char *name, if (!strchr("01234567890abcdefABCDEF", *si)) return 0; /* invalid digit in serial number*/ } - desc->sn = s; + desc->sn = (const unsigned char*)s; desc->snlen = -1; if (!*si) mode = KEYDB_SEARCH_MODE_SN; diff --git a/sm/keylist.c b/sm/keylist.c index 8e1233341..a0ac73fb3 100644 --- a/sm/keylist.c +++ b/sm/keylist.c @@ -256,7 +256,7 @@ print_time (gnupg_isotime_t t, FILE *fp) static char * email_kludge (const char *name) { - const unsigned char *p; + const char *p; unsigned char *buf; int n; @@ -278,7 +278,7 @@ email_kludge (const char *name) buf[n] = xtoi_2 (p); buf[n++] = '>'; buf[n] = 0; - return buf; + return (char*)buf; } diff --git a/sm/server.c b/sm/server.c index 7bfd3fc20..b3816d3d9 100644 --- a/sm/server.c +++ b/sm/server.c @@ -53,14 +53,14 @@ struct server_local_s { /* Note that it is sufficient to allocate the target string D as long as the source string S, i.e.: strlen(s)+1; */ static void -strcpy_escaped_plus (char *d, const unsigned char *s) +strcpy_escaped_plus (char *d, const char *s) { while (*s) { if (*s == '%' && s[1] && s[2]) { s++; - *d++ = xtoi_2 ( s); + *d++ = xtoi_2 (s); s += 2; } else if (*s == '+') diff --git a/sm/sign.c b/sm/sign.c index 5deef6088..3230a0e98 100644 --- a/sm/sign.c +++ b/sm/sign.c @@ -575,7 +575,7 @@ gpgsm_sign (CTRL ctrl, CERTLIST signerlist, ksba_cms_set_hash_function (cms, HASH_FNC, md); for (cl=signerlist,signer=0; cl; cl = cl->next, signer++) { - char *sigval = NULL; + unsigned char *sigval = NULL; char *buf, *fpr; if (signer) diff --git a/tools/ChangeLog b/tools/ChangeLog index 39f17e2ce..5965b2871 100644 --- a/tools/ChangeLog +++ b/tools/ChangeLog @@ -1,3 +1,8 @@ +2005-06-16 Werner Koch + + * gpg-connect-agent.c (read_and_print_response): Made LINELEN a + size_t. + 2005-06-04 Marcus Brinkmann * symcryptrun.c (main): Allow any number of arguments, don't use diff --git a/tools/gpg-connect-agent.c b/tools/gpg-connect-agent.c index bb05030ee..c9a324fa8 100644 --- a/tools/gpg-connect-agent.c +++ b/tools/gpg-connect-agent.c @@ -458,7 +458,7 @@ static int read_and_print_response (assuan_context_t ctx) { char *line; - int linelen; + size_t linelen; assuan_error_t rc; int i, j; diff --git a/tools/gpgconf-comp.c b/tools/gpgconf-comp.c index c49d1dcbb..e8d9ca27e 100644 --- a/tools/gpgconf-comp.c +++ b/tools/gpgconf-comp.c @@ -2316,7 +2316,7 @@ gc_component_change_options (int component, FILE *in) char *linep; unsigned long flags = 0; char *new_value = ""; - unsigned long new_value_nr; + unsigned long new_value_nr = 0; /* Strip newline and carriage return, if present. */ while (length > 0 diff --git a/tools/gpgkey2ssh.c b/tools/gpgkey2ssh.c index 75b18b29b..e874ab22e 100644 --- a/tools/gpgkey2ssh.c +++ b/tools/gpgkey2ssh.c @@ -249,6 +249,9 @@ main (int argc, char **argv) pkdbuf = NULL; pkdbuf_n = 0; + algorithm_id = 0; /* (avoid cc warning) */ + identifier = NULL; /* (avoid cc warning) */ + assert (argc == 2); keyid = argv[1]; diff --git a/tools/watchgnupg.c b/tools/watchgnupg.c index 25ca8c413..6cb570fbc 100644 --- a/tools/watchgnupg.c +++ b/tools/watchgnupg.c @@ -223,7 +223,7 @@ main (int argc, char **argv) int force = 0; struct sockaddr_un srvr_addr; - int addrlen; + socklen_t addrlen; int server; int flags; client_t client_list = NULL; -- cgit From 68191d0c935719d9ab171e49b6456372c72cf1c4 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 20 Jul 2005 15:05:05 +0000 Subject: * keylist.c (email_kludge): Reworked. * certdump.c (gpgsm_print_serial, gpgsm_dump_serial): Cast printf arg to unsigned. * call-dirmngr.c (gpgsm_dirmngr_run_command): Ditto --- THANKS | 3 ++- TODO | 2 ++ scd/ChangeLog | 13 +++++++++++++ scd/apdu.c | 6 ++++-- scd/app-openpgp.c | 9 ++++++++- scd/scdaemon.c | 2 ++ sm/ChangeLog | 8 ++++++++ sm/call-dirmngr.c | 2 +- sm/certdump.c | 4 ++-- sm/keylist.c | 26 +++++++++++++++++++------- sm/server.c | 2 +- 11 files changed, 62 insertions(+), 15 deletions(-) (limited to 'scd/app-openpgp.c') diff --git a/THANKS b/THANKS index 57add954b..408497046 100644 --- a/THANKS +++ b/THANKS @@ -1,7 +1,8 @@ Alexander Belopolsky belopolsky at mac.com Andrew J. Schorr aschorr at telemetry-investments.com -Kazu Yamamoto kazu@iij.ad.jp +Charly Avital shavital at mac.com +Kazu Yamamoto kazu at iij.ad.jp Michael Nottebrock michaelnottebrock at gmx.net Ray Link rlink at pitt.edu Richard Lefebvre rick at cerca.umontreal.ca diff --git a/TODO b/TODO index 5f1b57a0f..478f437c2 100644 --- a/TODO +++ b/TODO @@ -103,3 +103,5 @@ might want to have an agent context for each service request +* sm/ +** --include-certs seems to be a dummy option. diff --git a/scd/ChangeLog b/scd/ChangeLog index 0f7e4d2fa..970335aef 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,16 @@ +2005-07-05 Werner Koch + + * app-openpgp.c (do_readkey): Return a mallcoed copy of the key as + required by the description. Thanks to Moritz for tracking this + problem down. + +2005-06-21 Werner Koch + + * scdaemon.c (main): ifdef call to ccid_set_debug_level. + + * apdu.c (reset_pcsc_reader, open_pcsc_reader): Cast size_t to + ulong for printf. + 2005-06-06 Werner Koch * scdaemon.c (main): New option --debug-allow-core-dump. diff --git a/scd/apdu.c b/scd/apdu.c index 975fffa24..79022f21b 100644 --- a/scd/apdu.c +++ b/scd/apdu.c @@ -809,7 +809,8 @@ reset_pcsc_reader (int slot) len -= 4; /* Already read the error code. */ if (len > DIM (slotp->atr)) { - log_error ("PC/SC returned a too large ATR (len=%x)\n", len); + log_error ("PC/SC returned a too large ATR (len=%lx)\n", + (unsigned long)len); sw = SW_HOST_GENERAL_ERROR; goto command_failed; } @@ -1425,7 +1426,8 @@ open_pcsc_reader (const char *portstr) len -= 4; /* Already read the error code. */ if (len > DIM (slotp->atr)) { - log_error ("PC/SC returned a too large ATR (len=%x)\n", len); + log_error ("PC/SC returned a too large ATR (len=%lx)\n", + (unsigned long)len); goto command_failed; } err = (msgbuf[5] << 24) | (msgbuf[6] << 16) | (msgbuf[7] << 8 ) | msgbuf[8]; diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 11e6eebaf..bd56fb99d 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -1230,8 +1230,15 @@ do_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen) buf = app->app_local->pk[keyno-1].key; if (!buf) return gpg_error (GPG_ERR_NO_PUBKEY); - *pk = buf; *pklen = app->app_local->pk[keyno-1].keylen;; + *pk = xtrymalloc (*pklen); + if (!*pk) + { + err = gpg_error_from_errno (errno); + *pklen = 0; + return err; + } + memcpy (*pk, buf, *pklen); return 0; #else return gpg_error (GPG_ERR_NOT_IMPLEMENTED); diff --git a/scd/scdaemon.c b/scd/scdaemon.c index c75e87a62..c6995abcc 100644 --- a/scd/scdaemon.c +++ b/scd/scdaemon.c @@ -456,7 +456,9 @@ main (int argc, char **argv ) allow_coredump = 1; break; case oDebugCCIDDriver: +#ifdef HAVE_LIBUSB ccid_set_debug_level (ccid_set_debug_level (-1)+1); +#endif /*HAVE_LIBUSB*/ break; case oDebugDisableTicker: ticker_disabled = 1; break; diff --git a/sm/ChangeLog b/sm/ChangeLog index f1eb49c2c..cefa77e32 100644 --- a/sm/ChangeLog +++ b/sm/ChangeLog @@ -1,3 +1,11 @@ +2005-07-20 Werner Koch + + * keylist.c (email_kludge): Reworked. + + * certdump.c (gpgsm_print_serial, gpgsm_dump_serial): Cast printf + arg to unsigned. + * call-dirmngr.c (gpgsm_dirmngr_run_command): Ditto + 2005-07-19 Werner Koch * fingerprint.c (gpgsm_get_certid): Cast printf arg to unsigned. diff --git a/sm/call-dirmngr.c b/sm/call-dirmngr.c index 847e78490..ead117dfd 100644 --- a/sm/call-dirmngr.c +++ b/sm/call-dirmngr.c @@ -827,7 +827,7 @@ gpgsm_dirmngr_run_command (CTRL ctrl, const char *command, *p++ = '+'; else if (!isprint (*s) || *s == '+') { - sprintf (p, "%%%02X", *s); + sprintf (p, "%%%02X", *(const unsigned char *)s); p += 3; } else diff --git a/sm/certdump.c b/sm/certdump.c index 98f019c4a..aae60e020 100644 --- a/sm/certdump.c +++ b/sm/certdump.c @@ -70,7 +70,7 @@ gpgsm_print_serial (FILE *fp, ksba_const_sexp_t sn) else { for (p++; n; n--, p++) - fprintf (fp, "%02X", *p); + fprintf (fp, "%02X", *(const unsigned char*)p); } } } @@ -98,7 +98,7 @@ gpgsm_dump_serial (ksba_const_sexp_t sn) else { for (p++; n; n--, p++) - log_printf ("%02X", *p); + log_printf ("%02X", *(const unsigned char *)p); } } } diff --git a/sm/keylist.c b/sm/keylist.c index a0ac73fb3..8a4eb3cdb 100644 --- a/sm/keylist.c +++ b/sm/keylist.c @@ -251,30 +251,42 @@ print_time (gnupg_isotime_t t, FILE *fp) } -/* return an allocated string with the email address extracted from a +/* Return an allocated string with the email address extracted from a DN */ static char * email_kludge (const char *name) { - const char *p; + const char *p, *string; unsigned char *buf; int n; - if (strncmp (name, "1.2.840.113549.1.9.1=#", 22)) - return NULL; + string = name; + for (;;) + { + p = strstr (string, "1.2.840.113549.1.9.1=#"); + if (!p) + return NULL; + if (p == name || (p > string+1 && p[-1] == ',' && p[-2] != '\\')) + { + name = p + 22; + break; + } + string = p + 22; + } + + /* 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) + if (!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++) + for (n=1, p=name; hexdigitp (p); p +=2, n++) buf[n] = xtoi_2 (p); buf[n++] = '>'; buf[n] = 0; diff --git a/sm/server.c b/sm/server.c index b3816d3d9..87a06ee4e 100644 --- a/sm/server.c +++ b/sm/server.c @@ -1109,7 +1109,7 @@ write_status_text_and_buffer ( int no, const char *string, if (s != buffer) fwrite (buffer, s-buffer, 1, statusfp ); if ( esc ) { - fprintf (statusfp, "%%%02X", *(const byte*)s ); + fprintf (statusfp, "%%%02X", *(const unsigned char*)s ); s++; n--; } buffer = s; -- cgit From 6f90f05cb2181bc4ab64959c0f3590f48c9c39c6 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 9 Sep 2005 11:18:08 +0000 Subject: Bug fixes and ssh support for the BELPIC. --- NEWS | 4 +- agent/ChangeLog | 14 ++++++ agent/command-ssh.c | 46 ++++++++++--------- agent/minip12.c | 4 +- po/de.po | 70 ++++++++++++++-------------- scd/ChangeLog | 14 +++++- scd/app-openpgp.c | 27 ++++++++++- scd/app-p15.c | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++-- scd/ccid-driver.c | 3 +- scd/ccid-driver.h | 3 +- scd/iso7816.c | 3 +- scd/iso7816.h | 3 +- scd/pcsc-wrapper.c | 1 - sm/ChangeLog | 6 +++ sm/export.c | 1 + 15 files changed, 256 insertions(+), 71 deletions(-) (limited to 'scd/app-openpgp.c') diff --git a/NEWS b/NEWS index 75410e8d5..acc7c25f3 100644 --- a/NEWS +++ b/NEWS @@ -1,8 +1,10 @@ Noteworthy changes in version 1.9.19 ------------------------------------------------- - * The Belgian eID card is now supported. + * The Belgian eID card is now supported for signatures and ssh. + * Fixed bug in --export-secret-key-p12 so that certificates are again + included. Noteworthy changes in version 1.9.18 (2005-08-01) ------------------------------------------------- diff --git a/agent/ChangeLog b/agent/ChangeLog index adb7b1bb6..83e1fe867 100644 --- a/agent/ChangeLog +++ b/agent/ChangeLog @@ -1,3 +1,17 @@ +2005-09-09 Werner Koch + + * minip12.c (p12_build): Oops, array needs to be larger for the + certificate. + + * command-ssh.c (card_key_available): Let the card handler decide + whether the card is supported here. Also get a short serial + number to return from the card handler. + +2005-09-08 Werner Koch + + * minip12.c (build_cert_bag): Use a non constructed object. + i.e. 0x80 and not 0xa0. + 2005-08-16 Werner Koch * gpg-agent.c (main): Use a default file name for --write-env-file. diff --git a/agent/command-ssh.c b/agent/command-ssh.c index 642bcbbba..b8f0d20b0 100644 --- a/agent/command-ssh.c +++ b/agent/command-ssh.c @@ -1583,13 +1583,13 @@ key_secret_to_public (gcry_sexp_t *key_public, /* Check whether a smartcard is available and whether it has a usable key. Store a copy of that key at R_PK and return 0. If no key is available store NULL at R_PK and return an error code. If CARDSN - is no NULL, a string with the serial number of the card will be + is not NULL, a string with the serial number of the card will be a malloced and stored there. */ static gpg_error_t card_key_available (ctrl_t ctrl, gcry_sexp_t *r_pk, char **cardsn) { gpg_error_t err; - char *appname; + char *authkeyid; char *serialno = NULL; unsigned char *pkbuf; size_t pkbuflen; @@ -1602,7 +1602,7 @@ card_key_available (ctrl_t ctrl, gcry_sexp_t *r_pk, char **cardsn) /* First see whether a card is available and whether the application is supported. */ - err = agent_card_getattr (ctrl, "APPTYPE", &appname); + err = agent_card_getattr (ctrl, "$AUTHKEYID", &authkeyid); if ( gpg_err_code (err) == GPG_ERR_CARD_REMOVED ) { /* Ask for the serial number to reset the card. */ @@ -1615,40 +1615,33 @@ card_key_available (ctrl_t ctrl, gcry_sexp_t *r_pk, char **cardsn) return err; } log_info (_("detected card with S/N: %s\n"), serialno); - err = agent_card_getattr (ctrl, "APPTYPE", &appname); + err = agent_card_getattr (ctrl, "$AUTHKEYID", &authkeyid); } if (err) { - log_error (_("error getting application type of card: %s\n"), + log_error (_("error getting default authentication keyID of card: %s\n"), gpg_strerror (err)); xfree (serialno); return err; } - if (strcmp (appname, "OPENPGP")) - { - log_info (_("card application `%s' is not supported\n"), appname); - xfree (appname); - xfree (serialno); - return gpg_error (GPG_ERR_NOT_SUPPORTED); - } - xfree (appname); - appname = NULL; /* Get the S/N if we don't have it yet. Use the fast getattr method. */ if (!serialno && (err = agent_card_getattr (ctrl, "SERIALNO", &serialno)) ) { log_error (_("error getting serial number of card: %s\n"), gpg_strerror (err)); + xfree (authkeyid); return err; } /* Read the public key. */ - err = agent_card_readkey (ctrl, "OPENPGP.3", &pkbuf); + err = agent_card_readkey (ctrl, authkeyid, &pkbuf); if (err) { if (opt.verbose) log_info (_("no suitable card key found: %s\n"), gpg_strerror (err)); xfree (serialno); + xfree (authkeyid); return err; } @@ -1660,6 +1653,7 @@ card_key_available (ctrl_t ctrl, gcry_sexp_t *r_pk, char **cardsn) gpg_strerror (err)); xfree (pkbuf); xfree (serialno); + xfree (authkeyid); return err; } @@ -1671,6 +1665,7 @@ card_key_available (ctrl_t ctrl, gcry_sexp_t *r_pk, char **cardsn) xfree (pkbuf); gcry_sexp_release (s_pk); xfree (serialno); + xfree (authkeyid); return err; } @@ -1680,13 +1675,14 @@ card_key_available (ctrl_t ctrl, gcry_sexp_t *r_pk, char **cardsn) unsigned char *shadow_info; unsigned char *tmp; - shadow_info = make_shadow_info (serialno, "OPENPGP.3"); + shadow_info = make_shadow_info (serialno, authkeyid); if (!shadow_info) { err = gpg_error_from_errno (errno); xfree (pkbuf); gcry_sexp_release (s_pk); xfree (serialno); + xfree (authkeyid); return err; } err = agent_shadow_key (pkbuf, shadow_info, &tmp); @@ -1697,6 +1693,7 @@ card_key_available (ctrl_t ctrl, gcry_sexp_t *r_pk, char **cardsn) xfree (pkbuf); gcry_sexp_release (s_pk); xfree (serialno); + xfree (authkeyid); return err; } xfree (pkbuf); @@ -1711,18 +1708,23 @@ card_key_available (ctrl_t ctrl, gcry_sexp_t *r_pk, char **cardsn) xfree (pkbuf); gcry_sexp_release (s_pk); xfree (serialno); + xfree (authkeyid); return err; } } if (cardsn) { - size_t snlen = strlen (serialno); + char *dispsn; - if (snlen == 32 - && !memcmp (serialno, "D27600012401", 12)) /* OpenPGP card. */ - *cardsn = xtryasprintf ("cardno:%.12s", serialno+16); - else /* Something is wrong: Print all. */ + /* If the card handler is able to return a short serialnumber, + use that one, else use the complete serialno. */ + if (!agent_card_getattr (ctrl, "$DISPSERIALNO", &dispsn)) + { + *cardsn = xtryasprintf ("cardno:%s", dispsn); + xfree (dispsn); + } + else *cardsn = xtryasprintf ("cardno:%s", serialno); if (!*cardsn) { @@ -1730,12 +1732,14 @@ card_key_available (ctrl_t ctrl, gcry_sexp_t *r_pk, char **cardsn) xfree (pkbuf); gcry_sexp_release (s_pk); xfree (serialno); + xfree (authkeyid); return err; } } xfree (pkbuf); xfree (serialno); + xfree (authkeyid); *r_pk = s_pk; return 0; } diff --git a/agent/minip12.c b/agent/minip12.c index 030043962..ea9f9b1b8 100644 --- a/agent/minip12.c +++ b/agent/minip12.c @@ -1409,7 +1409,7 @@ build_cert_bag (unsigned char *buffer, size_t buflen, char *salt, p += DIM (oid_encryptedData); /* 2. Store a [0] tag. */ - p = store_tag_length (p, 0xa0, len[2]); + p = store_tag_length (p, 0x80, len[2]); /* 3. Store a sequence. */ p = store_tag_length (p, TAG_SEQUENCE, len[3]); @@ -1553,7 +1553,7 @@ p12_build (gcry_mpi_t *kparms, unsigned char *cert, size_t certlen, unsigned char *buffer; size_t n, buflen; char salt[8]; - struct buffer_s seqlist[2]; + struct buffer_s seqlist[3]; int seqlistidx = 0; n = buflen = 0; /* (avoid compiler warning). */ diff --git a/po/de.po b/po/de.po index 69606fa8b..11f2c8a36 100644 --- a/po/de.po +++ b/po/de.po @@ -10,7 +10,7 @@ msgid "" msgstr "" "Project-Id-Version: gnupg2 1.9.18\n" "Report-Msgid-Bugs-To: translations@gnupg.org\n" -"POT-Creation-Date: 2005-09-06 20:01+0200\n" +"POT-Creation-Date: 2005-09-09 12:47+0200\n" "PO-Revision-Date: 2005-08-02 17:02+0200\n" "Last-Translator: Werner Koch \n" "Language-Team: de\n" @@ -605,52 +605,52 @@ msgstr "Der Fingerprint kann nicht gespeichert werden: %s\n" msgid "failed to store the creation date: %s\n" msgstr "Das Erzeugungsdatum kann nicht gespeichert werden: %s\n" -#: scd/app-openpgp.c:978 +#: scd/app-openpgp.c:1003 #, c-format msgid "reading public key failed: %s\n" msgstr "Fehler beim Lesen des öffentlichen Schlüssels: %s\n" -#: scd/app-openpgp.c:986 scd/app-openpgp.c:1917 +#: scd/app-openpgp.c:1011 scd/app-openpgp.c:1942 msgid "response does not contain the public key data\n" msgstr "Die Antwort enthält keine Public Key Daten\n" -#: scd/app-openpgp.c:994 scd/app-openpgp.c:1925 +#: scd/app-openpgp.c:1019 scd/app-openpgp.c:1950 msgid "response does not contain the RSA modulus\n" msgstr "Die Antwort enthält keinen RSA Modulus\n" -#: scd/app-openpgp.c:1003 scd/app-openpgp.c:1935 +#: scd/app-openpgp.c:1028 scd/app-openpgp.c:1960 msgid "response does not contain the RSA public exponent\n" msgstr "Die Antwort enthält keinen öffenlichen RSA Exponent\n" -#: scd/app-openpgp.c:1266 scd/app-openpgp.c:1354 scd/app-openpgp.c:2157 +#: scd/app-openpgp.c:1291 scd/app-openpgp.c:1379 scd/app-openpgp.c:2182 #, c-format msgid "PIN callback returned error: %s\n" msgstr "Fehler vom PIN \"callback\": %s\n" -#: scd/app-openpgp.c:1272 scd/app-openpgp.c:1360 scd/app-openpgp.c:2163 +#: scd/app-openpgp.c:1297 scd/app-openpgp.c:1385 scd/app-openpgp.c:2188 #, c-format msgid "PIN for CHV%d is too short; minimum length is %d\n" msgstr "Die PIN für den CHV%d ist zu kurz; Mindestlänge ist %d\n" -#: scd/app-openpgp.c:1281 scd/app-openpgp.c:1295 scd/app-openpgp.c:1370 -#: scd/app-openpgp.c:2172 scd/app-openpgp.c:2186 +#: scd/app-openpgp.c:1306 scd/app-openpgp.c:1320 scd/app-openpgp.c:1395 +#: scd/app-openpgp.c:2197 scd/app-openpgp.c:2211 #, c-format msgid "verify CHV%d failed: %s\n" msgstr "Prüfen von CHV%d fehlgeschlagen: %s\n" -#: scd/app-openpgp.c:1318 +#: scd/app-openpgp.c:1343 msgid "access to admin commands is not configured\n" msgstr "Zugriff auf Admin Kommandos ist nicht konfiguriert\n" -#: scd/app-openpgp.c:1333 scd/app-openpgp.c:2392 +#: scd/app-openpgp.c:1358 scd/app-openpgp.c:2417 msgid "error retrieving CHV status from card\n" msgstr "Fehler beim Holen des CHV Status von der Karte\n" -#: scd/app-openpgp.c:1339 scd/app-openpgp.c:2401 +#: scd/app-openpgp.c:1364 scd/app-openpgp.c:2426 msgid "card is permanently locked!\n" msgstr "Die Karte ist dauerhaft gesperrt!\n" -#: scd/app-openpgp.c:1344 +#: scd/app-openpgp.c:1369 #, c-format msgid "%d Admin PIN attempts remaining before card is permanently locked\n" msgstr "" @@ -659,105 +659,105 @@ msgstr "" #. TRANSLATORS: Do not translate the "|A|" prefix but #. keep it at the start of the string. We need this elsewhere #. to get some infos on the string. -#: scd/app-openpgp.c:1351 +#: scd/app-openpgp.c:1376 msgid "|A|Admin PIN" msgstr "|A|Admin PIN" #. TRANSLATORS: Do not translate the "|*|" prefixes but #. keep it at the start of the string. We need this elsewhere #. to get some infos on the string. -#: scd/app-openpgp.c:1500 +#: scd/app-openpgp.c:1525 msgid "|AN|New Admin PIN" msgstr "|AN|Neue Admin PIN" -#: scd/app-openpgp.c:1500 +#: scd/app-openpgp.c:1525 msgid "|N|New PIN" msgstr "|N|Neue PIN" -#: scd/app-openpgp.c:1504 +#: scd/app-openpgp.c:1529 #, c-format msgid "error getting new PIN: %s\n" msgstr "Fehler beim Holen der neuen PIN: %s\n" -#: scd/app-openpgp.c:1554 scd/app-openpgp.c:2003 +#: scd/app-openpgp.c:1579 scd/app-openpgp.c:2028 msgid "error reading application data\n" msgstr "Fehler beim Lesen der Anwendungsdaten\n" -#: scd/app-openpgp.c:1560 scd/app-openpgp.c:2010 +#: scd/app-openpgp.c:1585 scd/app-openpgp.c:2035 msgid "error reading fingerprint DO\n" msgstr "Fehler beim Lesen des Fingerabdruck Datenobjekts\n" -#: scd/app-openpgp.c:1570 +#: scd/app-openpgp.c:1595 msgid "key already exists\n" msgstr "Schlüssel existiert bereits\n" -#: scd/app-openpgp.c:1574 +#: scd/app-openpgp.c:1599 msgid "existing key will be replaced\n" msgstr "Existierender Schlüssel wird ersetzt\n" -#: scd/app-openpgp.c:1576 +#: scd/app-openpgp.c:1601 msgid "generating new key\n" msgstr "Neuer Schlüssel wird erzeugt\n" -#: scd/app-openpgp.c:1743 +#: scd/app-openpgp.c:1768 msgid "creation timestamp missing\n" msgstr "Erzeugungsdatum fehlt\n" -#: scd/app-openpgp.c:1750 +#: scd/app-openpgp.c:1775 #, c-format msgid "RSA modulus missing or not of size %d bits\n" msgstr "Der RSA Modulus fehlt oder ist nicht %d Bits lang\n" -#: scd/app-openpgp.c:1757 +#: scd/app-openpgp.c:1782 #, c-format msgid "RSA public exponent missing or larger than %d bits\n" msgstr "Der öffentliche RSA Exponent fehlt oder ist länger als %d Bits\n" -#: scd/app-openpgp.c:1765 scd/app-openpgp.c:1772 +#: scd/app-openpgp.c:1790 scd/app-openpgp.c:1797 #, c-format msgid "RSA prime %s missing or not of size %d bits\n" msgstr "Die RSA Primzahl %s fehlt oder ist nicht %d Bits lang\n" -#: scd/app-openpgp.c:1835 +#: scd/app-openpgp.c:1860 #, c-format msgid "failed to store the key: %s\n" msgstr "Fehler beim Speichern des Schlüssels: %s\n" -#: scd/app-openpgp.c:1894 +#: scd/app-openpgp.c:1919 msgid "please wait while key is being generated ...\n" msgstr "Bitte warten bis der Schlüssel erzeugt wurde ...\n" -#: scd/app-openpgp.c:1908 +#: scd/app-openpgp.c:1933 msgid "generating key failed\n" msgstr "Fehler beim Erzeugen des Schlüssels\n" -#: scd/app-openpgp.c:1911 +#: scd/app-openpgp.c:1936 #, c-format msgid "key generation completed (%d seconds)\n" msgstr "Schlüsselerzeugung vollendet (%d Sekunden)\n" -#: scd/app-openpgp.c:1968 +#: scd/app-openpgp.c:1993 msgid "invalid structure of OpenPGP card (DO 0x93)\n" msgstr "Ungültige Struktur der OpenPGP Karte (DO 0x93)\n" -#: scd/app-openpgp.c:2137 +#: scd/app-openpgp.c:2162 #, c-format msgid "signatures created so far: %lu\n" msgstr "Anzahl bereits erzeugter Signaturen: %lu\n" -#: scd/app-openpgp.c:2145 +#: scd/app-openpgp.c:2170 #, c-format msgid "||Please enter the PIN%%0A[sigs done: %lu]" msgstr "||Bitte geben Sie die PIN ein%%0A[Sigs bisher: %lu]" -#: scd/app-openpgp.c:2406 +#: scd/app-openpgp.c:2431 msgid "" "verification of Admin PIN is currently prohibited through this command\n" msgstr "" "Die Überprüfung der Admin PIN is momentan durch ein Kommando verboten " "worden\n" -#: scd/app-openpgp.c:2477 scd/app-openpgp.c:2487 +#: scd/app-openpgp.c:2502 scd/app-openpgp.c:2512 #, c-format msgid "can't access %s - invalid OpenPGP card?\n" msgstr "Zugriff auf %s nicht möglich - ungültige OpenPGP Karte?\n" diff --git a/scd/ChangeLog b/scd/ChangeLog index df22c6bfd..207670072 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,15 @@ +2005-09-09 Werner Koch + + * pcsc-wrapper.c (main): Removed bogus free. + + * app-p15.c (do_auth): New. + (do_getattr): New attribs $AUTHKEYID and $DISPSERIALNO. + * app-openpgp.c (do_getattr): Ditto. + +2005-09-08 Werner Koch + + * app-openpgp.c (do_getattr): New key $AUTHKEYID. + 2005-09-06 Werner Koch * app-p15.c (do_sign): Tweaked for BELPIC cards. @@ -8,7 +20,7 @@ * iso7816.c (iso7816_select_path): New. * app-p15.c (select_ef_by_path): Allow for direct path selection. - (app_select_p15): Try using the beigian variant of pkcs#15. + (app_select_p15): Try using the Belgian variant of pkcs#15. (read_home_df): New. (read_ef_odf): Generalized. (read_ef_tokeninfo): New. diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index bd56fb99d..5625c729b 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -696,6 +696,8 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name) { "PRIVATE-DO-2", 0x0102 }, { "PRIVATE-DO-3", 0x0103 }, { "PRIVATE-DO-4", 0x0104 }, + { "$AUTHKEYID", 0x0000, -3 }, + { "$DISPSERIALNO",0x0000, -4 }, { NULL, 0 } }; int idx, i, rc; @@ -742,6 +744,29 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name) send_status_info (ctrl, table[idx].name, tmp, strlen (tmp), NULL, 0); return 0; } + if (table[idx].special == -3) + { + char const tmp[] = "OPENPGP.3"; + send_status_info (ctrl, table[idx].name, tmp, strlen (tmp), NULL, 0); + return 0; + } + if (table[idx].special == -4) + { + char *serial; + time_t stamp; + + if (!app_get_serial_and_stamp (app, &serial, &stamp)) + { + if (strlen (serial) > 16+12) + { + send_status_info (ctrl, table[idx].name, serial+16, 12, NULL, 0); + xfree (serial); + return 0; + } + xfree (serial); + } + return gpg_error (GPG_ERR_INV_NAME); + } relptr = get_one_do (app, table[idx].tag, &value, &valuelen, &rc); if (relptr) @@ -2203,7 +2228,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, fingerprint delimited by a slash. Optionally the id OPENPGP.3 may be given. - Note that this fucntion may return the error code + Note that this function may return the error code GPG_ERR_WRONG_CARD to indicate that the card currently present does not match the one required for the requested action (e.g. the serial number does not match). */ diff --git a/scd/app-p15.c b/scd/app-p15.c index bf3c4dc1e..739a9ef95 100644 --- a/scd/app-p15.c +++ b/scd/app-p15.c @@ -2629,7 +2629,6 @@ readcert_by_cdf (app_t app, cdf_object_t cdf, } - /* Handler for the READCERT command. Read the certificate with id CERTID (as returned by learn_status in @@ -2653,6 +2652,95 @@ do_readcert (app_t app, const char *certid, } + +/* Implement the GETATTR command. This is similar to the LEARN + command but returns just one value via the status interface. */ +static gpg_error_t +do_getattr (app_t app, ctrl_t ctrl, const char *name) +{ + gpg_error_t err; + int i; + + if (!strcmp (name, "$AUTHKEYID")) + { + char *buf, *p; + prkdf_object_t prkdf; + + /* We return the ID of the first private keycapable of + signing. */ + for (prkdf = app->app_local->private_key_info; prkdf; + prkdf = prkdf->next) + if (prkdf->usageflags.sign) + break; + if (prkdf) + { + buf = xtrymalloc (9 + prkdf->objidlen*2 + 1); + if (!buf) + return gpg_error_from_errno (errno); + p = stpcpy (buf, "P15"); + if (app->app_local->home_df) + { + sprintf (p, "-%04hX", (app->app_local->home_df & 0xffff)); + p += 5; + } + p = stpcpy (p, "."); + for (i=0; i < prkdf->objidlen; i++) + { + sprintf (p, "%02X", prkdf->objid[i]); + p += 2; + } + + send_status_info (ctrl, name, buf, strlen (buf), NULL, 0); + xfree (buf); + return 0; + } + } + else if (!strcmp (name, "$DISPSERIALNO")) + { + /* For certain cards we return special IDs. There is no + general rule for it so we need to decide case by case. */ + if (app->app_local->card_type == CARD_TYPE_BELPIC) + { + /* The eID card has a card number printed on the fron matter + which seems to be a good indication. */ + unsigned char *buffer; + const unsigned char *p; + size_t buflen, n; + unsigned short path[] = { 0x3F00, 0xDF01, 0x4031 }; + + err = select_ef_by_path (app, path, DIM(path) ); + if (!err) + err = iso7816_read_binary (app->slot, 0, 0, &buffer, &buflen); + if (err) + { + log_error ("error accessing EF(ID): %s\n", gpg_strerror (err)); + return err; + } + + p = find_tlv (buffer, buflen, 1, &n); + if (p && n == 12) + { + char tmp[12+2+1]; + memcpy (tmp, p, 3); + tmp[3] = '-'; + memcpy (tmp+4, p+3, 7); + tmp[11] = '-'; + memcpy (tmp+12, p+10, 2); + tmp[14] = 0; + send_status_info (ctrl, name, tmp, strlen (tmp), NULL, 0); + xfree (buffer); + return 0; + } + xfree (buffer); + } + + } + return gpg_error (GPG_ERR_INV_NAME); +} + + + + /* Micardo cards require special treatment. This is a helper for the crypto functions to manage the security environment. We expect that the key file has already been selected. FID is the one of the @@ -3086,6 +3174,38 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, } +/* Handler for the PKAUTH command. + + This is basically the same as the PKSIGN command but we firstcheck + that the requested key is suitable for authentication; that is, it + must match the criteria used for the attribute $AUTHKEYID. See + do_sign for calling conventions; there is no HASHALGO, though. */ +static gpg_error_t +do_auth (app_t app, const char *keyidstr, + gpg_error_t (*pincb)(void*, const char *, char **), + void *pincb_arg, + const void *indata, size_t indatalen, + unsigned char **outdata, size_t *outdatalen ) +{ + gpg_error_t err; + prkdf_object_t prkdf; + + if (!keyidstr || !*keyidstr) + return gpg_error (GPG_ERR_INV_VALUE); + + err = prkdf_object_from_keyidstr (app, keyidstr, &prkdf); + if (err) + return err; + if (!prkdf->usageflags.sign) + { + log_error ("key %s may not be used for authentication\n", keyidstr); + return gpg_error (GPG_ERR_WRONG_KEY_USAGE); + } + return do_sign (app, keyidstr, GCRY_MD_SHA1, pincb, pincb_arg, + indata, indatalen, outdata, outdatalen); +} + + /* Assume that EF(DIR) has been selected. Read its content and figure out the home EF of pkcs#15. Return that home DF or 0 if not found @@ -3270,11 +3390,11 @@ app_select_p15 (app_t app) app->fnc.deinit = do_deinit; app->fnc.learn_status = do_learn_status; app->fnc.readcert = do_readcert; - app->fnc.getattr = NULL; + app->fnc.getattr = do_getattr; app->fnc.setattr = NULL; app->fnc.genkey = NULL; app->fnc.sign = do_sign; - app->fnc.auth = NULL; + app->fnc.auth = do_auth; app->fnc.decipher = NULL; app->fnc.change_pin = NULL; app->fnc.check_pin = NULL; @@ -3286,5 +3406,3 @@ app_select_p15 (app_t app) return rc; } - - diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c index 096a6811b..f82d93b00 100644 --- a/scd/ccid-driver.c +++ b/scd/ccid-driver.c @@ -16,7 +16,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. * * ALTERNATIVELY, this file may be distributed under the terms of the * following license, in which case the provisions of this license are diff --git a/scd/ccid-driver.h b/scd/ccid-driver.h index 82feed5c9..1b9ac2f85 100644 --- a/scd/ccid-driver.h +++ b/scd/ccid-driver.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. * * ALTERNATIVELY, this file may be distributed under the terms of the * following license, in which case the provisions of this license are diff --git a/scd/iso7816.c b/scd/iso7816.c index 484906251..5b985324f 100644 --- a/scd/iso7816.c +++ b/scd/iso7816.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. * * $Id$ */ diff --git a/scd/iso7816.h b/scd/iso7816.h index 828fabb01..04c7ae63e 100644 --- a/scd/iso7816.h +++ b/scd/iso7816.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. * * $Id$ */ diff --git a/scd/pcsc-wrapper.c b/scd/pcsc-wrapper.c index f149e785a..23e8442f7 100644 --- a/scd/pcsc-wrapper.c +++ b/scd/pcsc-wrapper.c @@ -819,7 +819,6 @@ main (int argc, char **argv) fprintf (stderr, PGM ": invalid request 0x%02X\n", c); exit (1); } - free (argbuffer); } return 0; } diff --git a/sm/ChangeLog b/sm/ChangeLog index a76f586eb..41cf7bd35 100644 --- a/sm/ChangeLog +++ b/sm/ChangeLog @@ -1,3 +1,9 @@ +2005-09-08 Werner Koch + + * export.c (popen_protect_tool): Add option --have-cert. We + probably lost this option with 1.9.14 due to restructuring of + export.c. + 2005-07-21 Werner Koch * gpgsm.c (main): New options --no-log-file and --debug-none. diff --git a/sm/export.c b/sm/export.c index b4450b2c2..f9d6dac62 100644 --- a/sm/export.c +++ b/sm/export.c @@ -520,6 +520,7 @@ popen_protect_tool (const char *pgmname, argv[i++] = "--homedir"; argv[i++] = opt.homedir; argv[i++] = "--p12-export"; + argv[i++] = "--have-cert"; argv[i++] = "--prompt"; argv[i++] = prompt?prompt:""; argv[i++] = "--enable-status-msg"; -- cgit From 6a13cf2c3dbacb9f3afd3f64e5d0c78b9c0e77e9 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 28 Nov 2005 11:52:25 +0000 Subject: Preparing an interim release --- ChangeLog | 16 +++++ NEWS | 7 ++ TODO | 1 - agent/ChangeLog | 17 +++++ agent/agent.h | 7 +- agent/call-scd.c | 51 +++++++++----- agent/command.c | 9 ++- agent/divert-scd.c | 19 ++++- agent/minip12.c | 21 ++++-- agent/query.c | 196 +++++++++++++++++++++++++++++++++++++++++++-------- agent/t-protect.c | 3 +- am/cmacros.am | 3 +- configure.ac | 11 +-- kbx/keybox-blob.c | 2 +- po/POTFILES.in | 1 + po/de.po | 16 +++-- scd/ChangeLog | 55 +++++++++++++++ scd/apdu.c | 176 +++++++++++++++++++++++++++++++++++---------- scd/apdu.h | 9 ++- scd/app-dinsig.c | 41 +++++++++-- scd/app-nks.c | 11 +-- scd/app-openpgp.c | 9 ++- scd/app-p15.c | 13 ++-- scd/ccid-driver.c | 64 ++++++++++++++--- scd/ccid-driver.h | 7 +- scd/iso7816.c | 115 +++++++++++++++++++++++++----- scd/iso7816.h | 35 ++++++++- scd/scdaemon.c | 6 +- scd/scdaemon.h | 17 ++--- tools/ChangeLog | 8 +++ tools/gpgconf-comp.c | 7 +- tools/rfc822parse.c | 1 + 32 files changed, 784 insertions(+), 170 deletions(-) (limited to 'scd/app-openpgp.c') diff --git a/ChangeLog b/ChangeLog index f63a035cc..46d66ed47 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2005-11-28 Werner Koch + + * configure.ac: Append the revision to the version string. + +2005-11-13 Werner Koch + + * am/cmacros.am (-DGNUPG_SYSCONFDIR): Define it. + +2005-11-11 Werner Koch + + * configure.ac (NEED_KSBA_VERSION: Require 0.9.13. + +2005-09-12 Werner Koch + + Released 1.9.19. + 2005-08-01 Werner Koch Released 1.9.18. diff --git a/NEWS b/NEWS index 1e1148748..edf29885d 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,10 @@ +Noteworthy changes in version 1.9.20 +------------------------------------------------- + + * [scdaemon] Support for keypads of some readers. Tested only with + SPR532. New option --disable-keypad. + + Noteworthy changes in version 1.9.19 (2005-09-12) ------------------------------------------------- diff --git a/TODO b/TODO index 32b728588..50f58cee9 100644 --- a/TODO +++ b/TODO @@ -26,7 +26,6 @@ might want to have an agent context for each service request * sm/gpgsm.c ** Support --output for all commands ** mark all unimplemented commands and options. -** Print a hint when MD2 is the cause for a problem. ** Implement --default-key ** support the anyPolicy semantic ** Check that we are really following the verification procedures in rfc3280. diff --git a/agent/ChangeLog b/agent/ChangeLog index 975484007..105178730 100644 --- a/agent/ChangeLog +++ b/agent/ChangeLog @@ -1,3 +1,20 @@ +2005-11-24 Werner Koch + + * minip12.c (p12_parse): Fixed for case that the key object comes + prior to the certificate. + +2005-10-19 Werner Koch + + * divert-scd.c (getpin_cb): Hack to use it for a keypad message. + + * call-scd.c (inq_needpin): Reworked to support the new KEYPADINFO. + + * query.c (start_pinentry): Keep track of the owner. + (popup_message_thread, agent_popup_message_start) + (agent_popup_message_stop, agent_reset_query): New. + * command.c (start_command_handler): Make sure a popup window gets + closed. + 2005-10-08 Marcus Brinkmann * Makefile.am (gpg_protect_tool_LDADD): Add ../gl/libgnu.a. diff --git a/agent/agent.h b/agent/agent.h index 7a646a85f..0918395ce 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -133,7 +133,7 @@ struct server_control_s int have_keygrip; int use_auth_call; /* Hack to send the PKAUTH command instead of the - PKSIGN command tro scdaemon. */ + PKSIGN command to the scdaemon. */ }; typedef struct server_control_s *CTRL; typedef struct server_control_s *ctrl_t; @@ -200,6 +200,7 @@ int agent_key_available (const unsigned char *grip); /*-- query.c --*/ void initialize_module_query (void); void agent_query_dump_state (void); +void agent_reset_query (ctrl_t ctrl); int agent_askpin (ctrl_t ctrl, const char *desc_text, const char *prompt_text, const char *inital_errtext, @@ -209,6 +210,10 @@ int agent_get_passphrase (ctrl_t ctrl, char **retpass, const char *errtext); int agent_get_confirmation (ctrl_t ctrl, const char *desc, const char *ok, const char *cancel); +int agent_popup_message_start (ctrl_t ctrl, const char *desc, + const char *ok_btn, const char *cancel_btn); +void agent_popup_message_stop (ctrl_t ctrl); + /*-- cache.c --*/ void agent_flush_cache (void); diff --git a/agent/call-scd.c b/agent/call-scd.c index 7a623fda4..a883f2733 100644 --- a/agent/call-scd.c +++ b/agent/call-scd.c @@ -633,26 +633,43 @@ inq_needpin (void *opaque, const char *line) size_t pinlen; int rc; - if (!(!strncmp (line, "NEEDPIN", 7) && (line[7] == ' ' || !line[7]))) + if (!strncmp (line, "NEEDPIN", 7) && (line[7] == ' ' || !line[7])) { - log_error ("unsupported inquiry `%s'\n", line); - return ASSUAN_Inquire_Unknown; - } - line += 7; - while (*line == ' ') - line++; + line += 7; + while (*line == ' ') + line++; + + pinlen = 90; + pin = gcry_malloc_secure (pinlen); + if (!pin) + return ASSUAN_Out_Of_Core; - pinlen = 90; - pin = gcry_malloc_secure (pinlen); - if (!pin) - return ASSUAN_Out_Of_Core; + rc = parm->getpin_cb (parm->getpin_cb_arg, line, pin, pinlen); + if (rc) + rc = ASSUAN_Canceled; + if (!rc) + rc = assuan_send_data (parm->ctx, pin, pinlen); + xfree (pin); + } + else if (!strncmp (line, "KEYPADINFO", 10) && (line[10] == ' ' || !line[10])) + { + size_t code; + char *endp; - rc = parm->getpin_cb (parm->getpin_cb_arg, line, pin, pinlen); - if (rc) - rc = ASSUAN_Canceled; - if (!rc) - rc = assuan_send_data (parm->ctx, pin, pinlen); - xfree (pin); + code = strtoul (line+10, &endp, 10); + line = endp; + while (*line == ' ') + line++; + + rc = parm->getpin_cb (parm->getpin_cb_arg, line, NULL, code); + if (rc) + rc = ASSUAN_Canceled; + } + else + { + log_error ("unsupported inquiry `%s'\n", line); + rc = ASSUAN_Inquire_Unknown; + } return rc; } diff --git a/agent/command.c b/agent/command.c index c39bcc6ab..daf9b8698 100644 --- a/agent/command.c +++ b/agent/command.c @@ -316,11 +316,11 @@ cmd_sigkey (ASSUAN_CONTEXT ctx, char *line) this command is not used a default text will be used. Note, that this description implictly selects the label used for the entry box; if the string contains the string PIN (which in general will - not be translated), "PIN" is used, other wiese the translation of + not be translated), "PIN" is used, otherwise the translation of 'passphrase" is used. The description string should not contain blanks unless they are percent or '+' escaped. - The descrition is only valid for the next PKSIGN or PKDECRYPT + The description is only valid for the next PKSIGN or PKDECRYPT operation. */ static int @@ -399,7 +399,7 @@ cmd_sethash (ASSUAN_CONTEXT ctx, char *line) /* PKSIGN Perform the actual sign operation. Neither input nor output are - sensitive to eavesdropping */ + sensitive to eavesdropping. */ static int cmd_pksign (ASSUAN_CONTEXT ctx, char *line) { @@ -1085,6 +1085,9 @@ start_command_handler (int listen_fd, int fd) /* Reset the SCD if needed. */ agent_reset_scd (&ctrl); + /* Reset the pinentry (in case of popup messages). */ + agent_reset_query (&ctrl); + assuan_deinit_server (ctx); if (ctrl.display) free (ctrl.display); diff --git a/agent/divert-scd.c b/agent/divert-scd.c index 9d2fa446c..926df2622 100644 --- a/agent/divert-scd.c +++ b/agent/divert-scd.c @@ -204,7 +204,7 @@ getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf) const char *again_text = NULL; const char *prompt = "PIN"; - if (maxbuf < 2) + if (buf && maxbuf < 2) return gpg_error (GPG_ERR_INV_VALUE); /* Parse the flags. */ @@ -223,6 +223,23 @@ getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf) else if (info && *info == '|') log_debug ("pin_cb called without proper PIN info hack\n"); + /* If BUF has been passed as NULL, we are in keypad mode: The + callback opens the popup and immediatley returns. */ + if (!buf) + { + if (maxbuf == 0) /* Close the pinentry. */ + { + agent_popup_message_stop (ctrl); + rc = 0; + } + else if (maxbuf == 1) /* Open the pinentry. */ + { + rc = agent_popup_message_start (ctrl, info, NULL, NULL); + } + else + rc = gpg_error (GPG_ERR_INV_VALUE); + return rc; + } /* FIXME: keep PI and TRIES in OPAQUE. Frankly this is a whole mess because we should call the card's verify function from the diff --git a/agent/minip12.c b/agent/minip12.c index 91eef63f4..55f3946bf 100644 --- a/agent/minip12.c +++ b/agent/minip12.c @@ -511,7 +511,7 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length, goto bailout; } - /* Loop over all certificates inside the bab. */ + /* Loop over all certificates inside the bag. */ while (n) { int isbag = 0; @@ -860,6 +860,7 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw, size_t n = length; const char *where; int bagseqlength, len; + gcry_mpi_t *result = NULL; where = "pfx"; if (parse_tag (&p, &n, &ti)) @@ -936,10 +937,17 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw, else if (ti.tag == TAG_OBJECT_ID && ti.length == DIM(oid_data) && !memcmp (p, oid_data, DIM(oid_data))) { - p += DIM(oid_data); - n -= DIM(oid_data); - len -= DIM(oid_data); - return parse_bag_data (p, n, (p-buffer), pw); + if (result) + log_info ("already got an data object, skipping next one\n"); + else + { + p += DIM(oid_data); + n -= DIM(oid_data); + len -= DIM(oid_data); + result = parse_bag_data (p, n, (p-buffer), pw); + if (!result) + goto bailout; + } } else log_info ( "unknown bag type - skipped\n"); @@ -950,9 +958,10 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw, n -= len; } - return NULL; + return result; bailout: log_error ("error at \"%s\", offset %u\n", where, (p - buffer)); + /* fixme: need to release RESULT. */ return NULL; } diff --git a/agent/query.c b/agent/query.c index b231f6fc3..a5a3d0153 100644 --- a/agent/query.c +++ b/agent/query.c @@ -27,9 +27,10 @@ #include #include #include -#ifdef USE_GNU_PTH -# include +#ifndef HAVE_W32_SYSTEM +#include #endif +#include #include "agent.h" #include "i18n.h" @@ -48,14 +49,30 @@ time. */ #define LOCK_TIMEOUT (1*60) +/* The assuan context of the current pinentry. */ +static assuan_context_t entry_ctx; -static assuan_context_t entry_ctx = NULL; -#ifdef USE_GNU_PTH +/* The control variable of the connection owning the current pinentry. + This is only valid if ENTRY_CTX is not NULL. Note, that we care + only about the value of the pointer and that it should never be + dereferenced. */ +static ctrl_t entry_owner; + +/* A mutex used to serialize access to the pinentry. */ static pth_mutex_t entry_lock; -#endif -/* data to be passed to our callbacks */ -struct entry_parm_s { +/* The thread ID of the popup working thread. */ +static pth_t popup_tid; + +/* A flag used in communication between the popup working thread and + its stop function. */ +static int popup_finished; + + + +/* Data to be passed to our callbacks, */ +struct entry_parm_s +{ int lines; size_t size; unsigned char *buffer; @@ -67,17 +84,17 @@ struct entry_parm_s { /* This function must be called once to initialize this module. This has to be done before a second thread is spawned. We can't do the static initialization because Pth emulation code might not be able - to do a static init; in particualr, it is not possible for W32. */ + to do a static init; in particular, it is not possible for W32. */ void initialize_module_query (void) { -#ifdef USE_GNU_PTH static int initialized; if (!initialized) - if (pth_mutex_init (&entry_lock)) - initialized = 1; -#endif /*USE_GNU_PTH*/ + { + if (pth_mutex_init (&entry_lock)) + initialized = 1; + } } @@ -102,8 +119,19 @@ agent_query_dump_state (void) log_info ("agent_query_dump_state: entry_lock="); dump_mutex_state (&entry_lock); log_printf ("\n"); - log_info ("agent_query_dump_state: entry_ctx=%p pid=%ld\n", - entry_ctx, (long)assuan_get_pid (entry_ctx)); + log_info ("agent_query_dump_state: entry_ctx=%p pid=%ld popup_tid=%p\n", + entry_ctx, (long)assuan_get_pid (entry_ctx), popup_tid); +} + +/* Called to make sure that a popup window owned by the current + connection gets closed. */ +void +agent_reset_query (ctrl_t ctrl) +{ + if (entry_ctx && popup_tid && entry_owner == ctrl) + { + agent_popup_message_stop (ctrl); + } } @@ -117,14 +145,12 @@ unlock_pinentry (int rc) assuan_context_t ctx = entry_ctx; entry_ctx = NULL; -#ifdef USE_GNU_PTH if (!pth_mutex_release (&entry_lock)) { log_error ("failed to release the entry lock\n"); if (!rc) rc = gpg_error (GPG_ERR_INTERNAL); } -#endif assuan_disconnect (ctx); return rc; } @@ -145,7 +171,7 @@ atfork_cb (void *opaque, int where) pinentry - we will serialize _all_ pinentry calls. */ static int -start_pinentry (CTRL ctrl) +start_pinentry (ctrl_t ctrl) { int rc; const char *pgmname; @@ -153,13 +179,10 @@ start_pinentry (CTRL ctrl) const char *argv[5]; int no_close_list[3]; int i; + pth_event_t evt; -#ifdef USE_GNU_PTH - { - pth_event_t evt; - - evt = pth_event (PTH_EVENT_TIME, pth_timeout (LOCK_TIMEOUT, 0)); - if (!pth_mutex_acquire (&entry_lock, 0, evt)) + evt = pth_event (PTH_EVENT_TIME, pth_timeout (LOCK_TIMEOUT, 0)); + if (!pth_mutex_acquire (&entry_lock, 0, evt)) { if (pth_event_occurred (evt)) rc = gpg_error (GPG_ERR_TIMEOUT); @@ -170,9 +193,9 @@ start_pinentry (CTRL ctrl) gpg_strerror (rc)); return rc; } - pth_event_free (evt, PTH_FREE_THIS); - } -#endif + pth_event_free (evt, PTH_FREE_THIS); + + entry_owner = ctrl; if (entry_ctx) return 0; @@ -436,7 +459,7 @@ agent_askpin (ctrl_t ctrl, passphrase is returned in RETPASS as an hex encoded string to be freed by the caller */ int -agent_get_passphrase (CTRL ctrl, +agent_get_passphrase (ctrl_t ctrl, char **retpass, const char *desc, const char *prompt, const char *errtext) { @@ -517,11 +540,11 @@ agent_get_passphrase (CTRL ctrl, /* Pop up the PIN-entry, display the text and the prompt and ask the - user to confirm this. We return 0 for success, ie. the used + user to confirm this. We return 0 for success, ie. the user confirmed it, GPG_ERR_NOT_CONFIRMED for what the text says or an other error. */ int -agent_get_confirmation (CTRL ctrl, +agent_get_confirmation (ctrl_t ctrl, const char *desc, const char *ok, const char *cancel) { int rc; @@ -562,4 +585,119 @@ agent_get_confirmation (CTRL ctrl, } +/* The thread running the popup message. */ +static void * +popup_message_thread (void *arg) +{ + assuan_transact (entry_ctx, "CONFIRM", NULL, NULL, NULL, NULL, NULL, NULL); + popup_finished = 1; + return NULL; +} + + +/* Pop up a message window similar to the confirm one but keep it open + until agent_popup_message_stop has been called. It is crucial for + the caller to make sure that the stop function gets called as soon + as the message is not anymore required becuase the message is + system modal and all other attempts to use the pinentry will fail + (after a timeout). */ +int +agent_popup_message_start (ctrl_t ctrl, const char *desc, + const char *ok_btn, const char *cancel_btn) +{ + int rc; + char line[ASSUAN_LINELENGTH]; + pth_attr_t tattr; + + rc = start_pinentry (ctrl); + if (rc) + return rc; + + if (desc) + snprintf (line, DIM(line)-1, "SETDESC %s", desc); + else + snprintf (line, DIM(line)-1, "RESET"); + line[DIM(line)-1] = 0; + rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); + if (rc) + return unlock_pinentry (map_assuan_err (rc)); + + if (ok_btn) + { + snprintf (line, DIM(line)-1, "SETOK %s", ok_btn); + line[DIM(line)-1] = 0; + rc = assuan_transact (entry_ctx, line, NULL,NULL,NULL,NULL,NULL,NULL); + if (rc) + return unlock_pinentry (map_assuan_err (rc)); + } + if (cancel_btn) + { + snprintf (line, DIM(line)-1, "SETCANCEL %s", cancel_btn); + line[DIM(line)-1] = 0; + rc = assuan_transact (entry_ctx, line, NULL,NULL,NULL,NULL,NULL,NULL); + if (rc) + return unlock_pinentry (map_assuan_err (rc)); + } + + tattr = pth_attr_new(); + pth_attr_set (tattr, PTH_ATTR_JOINABLE, 1); + pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 256*1024); + pth_attr_set (tattr, PTH_ATTR_NAME, "popup-message"); + + popup_finished = 0; + popup_tid = pth_spawn (tattr, popup_message_thread, NULL); + if (!popup_tid) + { + rc = gpg_error_from_errno (errno); + log_error ("error spawning popup message handler: %s\n", + strerror (errno) ); + pth_attr_destroy (tattr); + return unlock_pinentry (rc); + } + pth_attr_destroy (tattr); + + return 0; +} + +/* Close a popup window. */ +void +agent_popup_message_stop (ctrl_t ctrl) +{ + int rc; + pid_t pid; + + if (!popup_tid || !entry_ctx) + { + log_debug ("agent_popup_message_stop called with no active popup\n"); + return; + } + + pid = assuan_get_pid (entry_ctx); + if (pid == (pid_t)(-1)) + ; /* No pid available can't send a kill. */ + else if (popup_finished) + ; /* Already finished and ready for joining. */ + else if (pid && ((rc=waitpid (pid, NULL, WNOHANG))==-1 || (rc == pid)) ) + { /* The daemon already died. No need to send a kill. However + because we already waited for the process, we need to tell + assuan that it should not wait again (done by + unlock_pinentry). */ + if (rc == pid) + assuan_set_flag (entry_ctx, ASSUAN_NO_WAITPID, 1); + } + else + kill (pid, SIGINT); + + /* Now wait for the thread to terminate. */ + rc = pth_join (popup_tid, NULL); + if (!rc) + log_debug ("agent_popup_message_stop: pth_join failed: %s\n", + strerror (errno)); + popup_tid = NULL; + entry_owner = NULL; + + /* Now we can close the connection. */ + unlock_pinentry (0); +} + diff --git a/agent/t-protect.c b/agent/t-protect.c index 5187cf8f7..fee3c561d 100644 --- a/agent/t-protect.c +++ b/agent/t-protect.c @@ -173,7 +173,8 @@ test_agent_protect (void) for (i = 0; i < DIM (specs); i++) { - ret = agent_protect (specs[i].key, specs[i].passphrase, + ret = agent_protect ((const unsigned char*)specs[i].key, + specs[i].passphrase, &specs[i].result, &specs[i].resultlen); if (gpg_err_code (ret) != specs[i].ret_expected) { diff --git a/am/cmacros.am b/am/cmacros.am index 0f7a09fe0..de68b6f31 100644 --- a/am/cmacros.am +++ b/am/cmacros.am @@ -25,7 +25,8 @@ if ! HAVE_DOSISH_SYSTEM AM_CPPFLAGS += -DGNUPG_BINDIR="\"$(bindir)\"" \ -DGNUPG_LIBEXECDIR="\"$(libexecdir)\"" \ -DGNUPG_LIBDIR="\"$(libdir)/@PACKAGE@\"" \ - -DGNUPG_DATADIR="\"$(datadir)/@PACKAGE@\"" + -DGNUPG_DATADIR="\"$(datadir)/@PACKAGE@\"" \ + -DGNUPG_SYSCONFDIR="\"$(sysconfdir)/@PACKAGE@\"" endif if GNUPG_AGENT_PGM diff --git a/configure.ac b/configure.ac index 30b183046..6ba66968d 100644 --- a/configure.ac +++ b/configure.ac @@ -22,9 +22,12 @@ AC_PREREQ(2.52) min_automake_version="1.9.3" -# Version number: Remember to change it immediately *after* a release. -# Add a "-cvs" prefix for non-released code. -AC_INIT(gnupg, 1.9.19, gnupg-devel@gnupg.org) +# Remember to change the version number immediately *after* a release. +# Uncomment the my_iscvs macro for non-released code. +m4_define(my_version, [1.9.20]) +m4_define(my_iscvs, yes) +AC_INIT([gnupg], my_version[]m4_ifdef([my_iscvs], [-cvs[]m4_translit( + [$Revision$],[Ra-z $:])]), [gnupg-devel@gnupg.org]) # Set development_version to yes if the minor number is odd or you # feel that the default check for a development version is not # sufficient. @@ -36,7 +39,7 @@ NEED_LIBGCRYPT_VERSION=1.1.94 NEED_LIBASSUAN_VERSION=0.6.10 -NEED_KSBA_VERSION=0.9.12 +NEED_KSBA_VERSION=0.9.13 PACKAGE=$PACKAGE_NAME diff --git a/kbx/keybox-blob.c b/kbx/keybox-blob.c index 67c74b777..eacc0014a 100644 --- a/kbx/keybox-blob.c +++ b/kbx/keybox-blob.c @@ -61,7 +61,7 @@ X.509 specific are noted like [X.509: xxx] u32 offset to the n-th key's keyID (a keyID is always 8 byte) or 0 if not known which is the case only for X509. u16 special key flags - bit 0 = + bit 0 = qualified signature (not yet implemented} u16 reserved u16 size of serialnumber(may be zero) n u16 (see above) bytes of serial number diff --git a/po/POTFILES.in b/po/POTFILES.in index 8fff858db..eb5711ddb 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -17,6 +17,7 @@ kbx/kbxutil.c scd/scdaemon.c scd/app-openpgp.c +scd/app-nks.c sm/base64.c sm/call-agent.c diff --git a/po/de.po b/po/de.po index 6b28544cb..2201c0429 100644 --- a/po/de.po +++ b/po/de.po @@ -10,8 +10,8 @@ msgid "" msgstr "" "Project-Id-Version: gnupg2 1.9.18\n" "Report-Msgid-Bugs-To: translations@gnupg.org\n" -"POT-Creation-Date: 2005-11-23 13:00+0100\n" -"PO-Revision-Date: 2005-11-23 13:02+0100\n" +"POT-Creation-Date: 2005-11-28 12:14+0100\n" +"PO-Revision-Date: 2005-11-28 12:16+0100\n" "Last-Translator: Werner Koch \n" "Language-Team: de\n" "MIME-Version: 1.0\n" @@ -766,6 +766,10 @@ msgstr "" msgid "can't access %s - invalid OpenPGP card?\n" msgstr "Zugriff auf %s nicht möglich - ungültige OpenPGP Karte?\n" +#: scd/app-nks.c:344 +msgid "the NullPIN has not yet been changed\n" +msgstr "Die Nullpin wurde noch nicht geändert\n" + #: sm/base64.c:317 #, c-format msgid "invalid radix64 character %02x skipped\n" @@ -1369,7 +1373,7 @@ msgstr "Signieren mit `%s' nicht möglich: %s\n" #: sm/gpgsm.c:1475 msgid "this command has not yet been implemented\n" -msgstr "Diee Kommando wurde noch nicht implementiert\n" +msgstr "Dieses Kommando wurde noch nicht implementiert\n" #: sm/gpgsm.c:1705 sm/gpgsm.c:1742 sm/qualified.c:73 #, c-format @@ -1548,10 +1552,10 @@ msgid "" msgstr "" "Sie sind dabei, eine Signatur mit dem Zertifikat:\n" "\"%s\"\n" -"zu erzeugen. Dies wird einen qualifizierte Signatur erzeugen, \n" -"die gesetzlich einer handgeschriebene gleichgestellt ist.\n" +"zu erzeugen. Dies wird eine qualifizierte Signatur erzeugen, \n" +"die gesetzlich einer handgeschriebenen gleichgestellt ist.\n" "\n" -"%s%sSind Sie wirklich sicher, da Sie dies möchten?" +"%s%sSind Sie wirklich sicher, daß Sie dies möchten?" #: sm/qualified.c:224 msgid "" diff --git a/scd/ChangeLog b/scd/ChangeLog index ccea117dd..008d84080 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,8 +1,63 @@ +2005-11-23 Werner Koch + + * app-nks.c (verify_pin): Give a special error message for a Nullpin. + +2005-10-29 Werner Koch + + * ccid-driver.c (send_escape_cmd): New args RESULT, RESULTLEN and + RESULTMAX. Changed all callers. + (ccid_transceive_escape): New. + +2005-10-27 Werner Koch + + * apdu.c [__CYGWIN__]: Make cygwin environment similar to _WIN32. + Suggested by John P. Clizbe. + * scdaemon.c [__CYGWIN__]: Set default PC/SC driver to winscard.dll. + +2005-10-19 Werner Koch + + * ccid-driver.h (CCID_DRIVER_ERR_NO_KEYPAD): New. + * apdu.h (SW_HOST_NO_KEYPAD): New. + * iso7816.h (struct iso7816_pininfo_s): New. + * iso7816.c (map_sw): Support new code. + (iso7816_check_keypad): New. + (iso7816_verify_kp, iso7816_change_reference_data_kp) + (iso7816_reset_retry_counter_kp): New. Extended versions of the + original functions. + * apdu.c (host_sw_string): Support new code. + (reader_table_s): New field CHECK_KEYPAD. + (new_reader_slot, open_ct_reader, open_pcsc_reader) + (open_ccid_reader, open_rapdu_reader): Initialize it. + (check_ccid_keypad): New. + (apdu_check_keypad): New. + (apdu_send_le): Factored all code out to ... + (send_le): .. new. Takes an additional arg; changed all callers + of the orginal function to use this one with a NULL for the new + arg. + (apdu_send_simple_kp): New. + (ct_send_apdu, pcsc_send_apdu, my_rapdu_send_apdu) + (send_apdu_ccid): New arg PININFO. + (send_apdu_ccid): Use the new arg. + + * scdaemon.c: New option --disable-keypad. + 2005-10-08 Marcus Brinkmann * Makefile.am (scdaemon_LDADD): Add ../gl/libgnu.a after ../common/libcommon.a. +2005-09-20 Werner Koch + + * app-dinsig.c (verify_pin): Try ISO 9564 BCD encoding. + + * iso7816.c (iso7816_select_application): Add arg FLAGS. Changed + all callers to pass 0. + * app-openpgp.c (app_select_openpgp): But this one requires a + special flag. + + * app-p15.c (app_select_p15): Don't use select application for the + BELPIC. + 2005-09-09 Werner Koch * pcsc-wrapper.c (main): Removed bogus free. diff --git a/scd/apdu.c b/scd/apdu.c index 678ea12d3..f59d832d4 100644 --- a/scd/apdu.c +++ b/scd/apdu.c @@ -66,10 +66,10 @@ #include "ccid-driver.h" -/* To to conflicting use of threading libraries we usually can't link +/* Due to conflicting use of threading libraries we usually can't link against libpcsclite. Instead we use a wrapper program. */ #ifdef USE_GNU_PTH -#ifndef HAVE_W32_SYSTEM +#if !defined(HAVE_W32_SYSTEM) && !defined(__CYGWIN__) #define NEED_PCSC_WRAPPER 1 #endif #endif @@ -78,7 +78,7 @@ #define MAX_READER 4 /* Number of readers we support concurrently. */ -#ifdef _WIN32 +#if defined(_WIN32) || defined(__CYGWIN__) #define DLSTDCALL __stdcall #else #define DLSTDCALL @@ -90,6 +90,14 @@ #define MAX_OPEN_FDS 20 #endif +/* Helper to pass patrameters related to keypad based operations. */ +struct pininfo_s +{ + int mode; + int minlen; + int maxlen; + int padlen; +}; /* A structure to collect information pertaining to one reader slot. */ @@ -103,7 +111,8 @@ struct reader_table_s { int (*reset_reader)(int); int (*get_status_reader)(int, unsigned int *); int (*send_apdu_reader)(int,unsigned char *,size_t, - unsigned char *, size_t *); + unsigned char *, size_t *, struct pininfo_s *); + int (*check_keypad)(int, int, int, int, int, int); void (*dump_status_reader)(int); struct { @@ -320,6 +329,7 @@ new_reader_slot (void) reader_table[reader].reset_reader = NULL; reader_table[reader].get_status_reader = NULL; reader_table[reader].send_apdu_reader = NULL; + reader_table[reader].check_keypad = NULL; reader_table[reader].dump_status_reader = NULL; reader_table[reader].used = 1; @@ -372,6 +382,7 @@ host_sw_string (long err) case SW_HOST_GENERAL_ERROR: return "general error"; case SW_HOST_NO_READER: return "no reader"; case SW_HOST_ABORTED: return "aborted"; + case SW_HOST_NO_KEYPAD: return "no keypad"; default: return "unknown host status error"; } } @@ -533,7 +544,7 @@ ct_get_status (int slot, unsigned int *status) set to BUFLEN. Returns: CT API error code. */ static int ct_send_apdu (int slot, unsigned char *apdu, size_t apdulen, - unsigned char *buffer, size_t *buflen) + unsigned char *buffer, size_t *buflen, struct pininfo_s *pininfo) { int rc; unsigned char dad[1], sad[1]; @@ -596,6 +607,7 @@ open_ct_reader (int port) reader_table[reader].reset_reader = reset_ct_reader; reader_table[reader].get_status_reader = ct_get_status; reader_table[reader].send_apdu_reader = ct_send_apdu; + reader_table[reader].check_keypad = NULL; reader_table[reader].dump_status_reader = ct_dump_reader_status; dump_reader_status (reader); @@ -1082,7 +1094,8 @@ pcsc_get_status (int slot, unsigned int *status) set to BUFLEN. Returns: CT API error code. */ static int pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen, - unsigned char *buffer, size_t *buflen) + unsigned char *buffer, size_t *buflen, + struct pininfo_s *pininfo) { #ifdef NEED_PCSC_WRAPPER long err; @@ -1479,6 +1492,7 @@ open_pcsc_reader (const char *portstr) reader_table[slot].reset_reader = reset_pcsc_reader; reader_table[slot].get_status_reader = pcsc_get_status; reader_table[slot].send_apdu_reader = pcsc_send_apdu; + reader_table[slot].check_keypad = NULL; reader_table[slot].dump_status_reader = dump_pcsc_reader_status; /* Read the status so that IS_T0 will be set. */ @@ -1625,6 +1639,7 @@ open_pcsc_reader (const char *portstr) reader_table[slot].reset_reader = reset_pcsc_reader; reader_table[slot].get_status_reader = pcsc_get_status; reader_table[slot].send_apdu_reader = pcsc_send_apdu; + reader_table[slot].check_keypad = NULL; reader_table[slot].dump_status_reader = dump_pcsc_reader_status; /* log_debug ("state from pcsc_status: 0x%lx\n", card_state); */ @@ -1713,7 +1728,8 @@ get_status_ccid (int slot, unsigned int *status) set to BUFLEN. Returns: Internal CCID driver error code. */ static int send_apdu_ccid (int slot, unsigned char *apdu, size_t apdulen, - unsigned char *buffer, size_t *buflen) + unsigned char *buffer, size_t *buflen, + struct pininfo_s *pininfo) { long err; size_t maxbuflen; @@ -1727,9 +1743,18 @@ send_apdu_ccid (int slot, unsigned char *apdu, size_t apdulen, log_printhex (" APDU_data:", apdu, apdulen); maxbuflen = *buflen; - err = ccid_transceive (reader_table[slot].ccid.handle, - apdu, apdulen, - buffer, maxbuflen, buflen); + if (pininfo) + err = ccid_transceive_secure (reader_table[slot].ccid.handle, + apdu, apdulen, + pininfo->mode, + pininfo->minlen, + pininfo->maxlen, + pininfo->padlen, + buffer, maxbuflen, buflen); + else + err = ccid_transceive (reader_table[slot].ccid.handle, + apdu, apdulen, + buffer, maxbuflen, buflen); if (err) log_error ("ccid_transceive failed: (0x%lx)\n", err); @@ -1737,6 +1762,24 @@ send_apdu_ccid (int slot, unsigned char *apdu, size_t apdulen, return err; } + +/* Check whether the CCID reader supports the ISO command code COMMAND + on the keypad. Return 0 on success. For a description of the pin + parameters, see ccid-driver.c */ +static int +check_ccid_keypad (int slot, int command, int pin_mode, + int pinlen_min, int pinlen_max, int pin_padlen) +{ + unsigned char apdu[] = { 0, 0, 0, 0x81 }; + + apdu[1] = command; + return ccid_transceive_secure (reader_table[slot].ccid.handle, + apdu, sizeof apdu, + pin_mode, pinlen_min, pinlen_max, pin_padlen, + NULL, 0, NULL); +} + + /* Open the reader and try to read an ATR. */ static int open_ccid_reader (const char *portstr) @@ -1776,6 +1819,7 @@ open_ccid_reader (const char *portstr) reader_table[slot].reset_reader = reset_ccid_reader; reader_table[slot].get_status_reader = get_status_ccid; reader_table[slot].send_apdu_reader = send_apdu_ccid; + reader_table[slot].check_keypad = check_ccid_keypad; reader_table[slot].dump_status_reader = dump_ccid_reader_status; dump_reader_status (slot); @@ -1932,7 +1976,8 @@ my_rapdu_get_status (int slot, unsigned int *status) set to BUFLEN. Returns: APDU error code. */ static int my_rapdu_send_apdu (int slot, unsigned char *apdu, size_t apdulen, - unsigned char *buffer, size_t *buflen) + unsigned char *buffer, size_t *buflen, + struct pininfo_s *pininfo) { int err; reader_table_t slotp; @@ -2063,6 +2108,7 @@ open_rapdu_reader (int portno, reader_table[slot].reset_reader = reset_rapdu_reader; reader_table[slot].get_status_reader = my_rapdu_get_status; reader_table[slot].send_apdu_reader = my_rapdu_send_apdu; + reader_table[slot].check_keypad = NULL; reader_table[slot].dump_status_reader = NULL; dump_reader_status (slot); @@ -2198,28 +2244,28 @@ apdu_open_reader (const char *portstr) pcsc_establish_context = dlsym (handle, "SCardEstablishContext"); pcsc_release_context = dlsym (handle, "SCardReleaseContext"); pcsc_list_readers = dlsym (handle, "SCardListReaders"); -#ifdef _WIN32 +#if defined(_WIN32) || defined(__CYGWIN__) if (!pcsc_list_readers) pcsc_list_readers = dlsym (handle, "SCardListReadersA"); #endif pcsc_get_status_change = dlsym (handle, "SCardGetStatusChange"); -#ifdef _WIN32 +#if defined(_WIN32) || defined(__CYGWIN__) if (!pcsc_get_status_change) pcsc_get_status_change = dlsym (handle, "SCardGetStatusChangeA"); #endif pcsc_connect = dlsym (handle, "SCardConnect"); -#ifdef _WIN32 +#if defined(_WIN32) || defined(__CYGWIN__) if (!pcsc_connect) pcsc_connect = dlsym (handle, "SCardConnectA"); #endif pcsc_reconnect = dlsym (handle, "SCardReconnect"); -#ifdef _WIN32 +#if defined(_WIN32) || defined(__CYGWIN__) if (!pcsc_reconnect) pcsc_reconnect = dlsym (handle, "SCardReconnectA"); #endif pcsc_disconnect = dlsym (handle, "SCardDisconnect"); pcsc_status = dlsym (handle, "SCardStatus"); -#ifdef _WIN32 +#if defined(_WIN32) || defined(__CYGWIN__) if (!pcsc_status) pcsc_status = dlsym (handle, "SCardStatusA"); #endif @@ -2492,11 +2538,30 @@ apdu_get_status (int slot, int hang, } +/* Check whether the reader supports the ISO command code COMMAND on + the keypad. Return 0 on success. For a description of the pin + parameters, see ccid-driver.c */ +int +apdu_check_keypad (int slot, int command, int pin_mode, + int pinlen_min, int pinlen_max, int pin_padlen) +{ + if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used ) + return SW_HOST_NO_DRIVER; + + if (reader_table[slot].check_keypad) + return reader_table[slot].check_keypad (slot, command, + pin_mode, pinlen_min, pinlen_max, + pin_padlen); + else + return SW_HOST_NOT_SUPPORTED; +} + + /* Dispatcher for the actual send_apdu function. Note, that this function should be called in locked state. */ static int send_apdu (int slot, unsigned char *apdu, size_t apdulen, - unsigned char *buffer, size_t *buflen) + unsigned char *buffer, size_t *buflen, struct pininfo_s *pininfo) { if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used ) return SW_HOST_NO_DRIVER; @@ -2504,24 +2569,20 @@ send_apdu (int slot, unsigned char *apdu, size_t apdulen, if (reader_table[slot].send_apdu_reader) return reader_table[slot].send_apdu_reader (slot, apdu, apdulen, - buffer, buflen); + buffer, buflen, pininfo); else return SW_HOST_NOT_SUPPORTED; } -/* Send an APDU to the card in SLOT. The APDU is created from all - given parameters: CLASS, INS, P0, P1, LC, DATA, LE. A value of -1 - for LC won't sent this field and the data field; in this case DATA - must also be passed as NULL. The return value is the status word - or -1 for an invalid SLOT or other non card related error. If - RETBUF is not NULL, it will receive an allocated buffer with the - returned data. The length of that data will be put into - *RETBUFLEN. The caller is reponsible for releasing the buffer even - in case of errors. */ -int -apdu_send_le(int slot, int class, int ins, int p0, int p1, - int lc, const char *data, int le, - unsigned char **retbuf, size_t *retbuflen) + +/* Core APDU trabceiver function. Parameters are described at + apdu_send_le with the exception of PININFO which indicates keypad + related operations if not NULL. */ +static int +send_le (int slot, int class, int ins, int p0, int p1, + int lc, const char *data, int le, + unsigned char **retbuf, size_t *retbuflen, + struct pininfo_s *pininfo) { #define RESULTLEN 256 unsigned char result[RESULTLEN+10]; /* 10 extra in case of bugs in @@ -2570,7 +2631,7 @@ apdu_send_le(int slot, int class, int ins, int p0, int p1, /* As safeguard don't pass any garbage from the stack to the driver. */ memset (apdu+apdulen, 0, sizeof (apdu) - apdulen); resultlen = RESULTLEN; - rc = send_apdu (slot, apdu, apdulen, result, &resultlen); + rc = send_apdu (slot, apdu, apdulen, result, &resultlen, pininfo); if (rc || resultlen < 2) { log_error ("apdu_send_simple(%d) failed: %s\n", @@ -2638,7 +2699,7 @@ apdu_send_le(int slot, int class, int ins, int p0, int p1, apdu[apdulen++] = len; memset (apdu+apdulen, 0, sizeof (apdu) - apdulen); resultlen = RESULTLEN; - rc = send_apdu (slot, apdu, apdulen, result, &resultlen); + rc = send_apdu (slot, apdu, apdulen, result, &resultlen, NULL); if (rc || resultlen < 2) { log_error ("apdu_send_simple(%d) for get response failed: %s\n", @@ -2703,6 +2764,27 @@ apdu_send_le(int slot, int class, int ins, int p0, int p1, #undef RESULTLEN } +/* Send an APDU to the card in SLOT. The APDU is created from all + given parameters: CLASS, INS, P0, P1, LC, DATA, LE. A value of -1 + for LC won't sent this field and the data field; in this case DATA + must also be passed as NULL. The return value is the status word + or -1 for an invalid SLOT or other non card related error. If + RETBUF is not NULL, it will receive an allocated buffer with the + returned data. The length of that data will be put into + *RETBUFLEN. The caller is reponsible for releasing the buffer even + in case of errors. */ +int +apdu_send_le(int slot, int class, int ins, int p0, int p1, + int lc, const char *data, int le, + unsigned char **retbuf, size_t *retbuflen) +{ + return send_le (slot, class, ins, p0, p1, + lc, data, le, + retbuf, retbuflen, + NULL); +} + + /* Send an APDU to the card in SLOT. The APDU is created from all given parameters: CLASS, INS, P0, P1, LC, DATA. A value of -1 for LC won't sent this field and the data field; in this case DATA must @@ -2716,8 +2798,8 @@ int apdu_send (int slot, int class, int ins, int p0, int p1, int lc, const char *data, unsigned char **retbuf, size_t *retbuflen) { - return apdu_send_le (slot, class, ins, p0, p1, lc, data, 256, - retbuf, retbuflen); + return send_le (slot, class, ins, p0, p1, lc, data, 256, + retbuf, retbuflen, NULL); } /* Send an APDU to the card in SLOT. The APDU is created from all @@ -2730,7 +2812,25 @@ int apdu_send_simple (int slot, int class, int ins, int p0, int p1, int lc, const char *data) { - return apdu_send_le (slot, class, ins, p0, p1, lc, data, -1, NULL, NULL); + return send_le (slot, class, ins, p0, p1, lc, data, -1, NULL, NULL, NULL); +} + + +/* Same as apdu_send_simple but uses the keypad of the reader. */ +int +apdu_send_simple_kp (int slot, int class, int ins, int p0, int p1, + int lc, const char *data, + int pin_mode, + int pinlen_min, int pinlen_max, int pin_padlen) +{ + struct pininfo_s pininfo; + + pininfo.mode = pin_mode; + pininfo.minlen = pinlen_min; + pininfo.maxlen = pinlen_max; + pininfo.padlen = pin_padlen; + return send_le (slot, class, ins, p0, p1, lc, data, -1, + NULL, NULL, &pininfo); } @@ -2771,7 +2871,7 @@ apdu_send_direct (int slot, const unsigned char *apdudata, size_t apdudatalen, class = apdulen? *apdu : 0; resultlen = RESULTLEN; - rc = send_apdu (slot, apdu, apdulen, result, &resultlen); + rc = send_apdu (slot, apdu, apdulen, result, &resultlen, NULL); if (rc || resultlen < 2) { log_error ("apdu_send_direct(%d) failed: %s\n", @@ -2825,7 +2925,7 @@ apdu_send_direct (int slot, const unsigned char *apdudata, size_t apdudatalen, apdu[apdulen++] = len; memset (apdu+apdulen, 0, sizeof (apdu) - apdulen); resultlen = RESULTLEN; - rc = send_apdu (slot, apdu, apdulen, result, &resultlen); + rc = send_apdu (slot, apdu, apdulen, result, &resultlen, NULL); if (rc || resultlen < 2) { log_error ("apdu_send_direct(%d) for get response failed: %s\n", diff --git a/scd/apdu.h b/scd/apdu.h index 45388fdd1..c3af82506 100644 --- a/scd/apdu.h +++ b/scd/apdu.h @@ -63,7 +63,8 @@ enum { SW_HOST_CARD_IO_ERROR = 0x1000a, SW_HOST_GENERAL_ERROR = 0x1000b, SW_HOST_NO_READER = 0x1000c, - SW_HOST_ABORTED = 0x1000d + SW_HOST_ABORTED = 0x1000d, + SW_HOST_NO_KEYPAD = 0x1000e }; @@ -96,8 +97,14 @@ int apdu_activate (int slot); int apdu_reset (int slot); int apdu_get_status (int slot, int hang, unsigned int *status, unsigned int *changed); +int apdu_check_keypad (int slot, int command, int pin_mode, + int pinlen_min, int pinlen_max, int pin_padlen); int apdu_send_simple (int slot, int class, int ins, int p0, int p1, int lc, const char *data); +int apdu_send_simple_kp (int slot, int class, int ins, int p0, int p1, + int lc, const char *data, + int pin_mode, + int pinlen_min, int pinlen_max, int pin_padlen); int apdu_send (int slot, int class, int ins, int p0, int p1, int lc, const char *data, unsigned char **retbuf, size_t *retbuflen); diff --git a/scd/app-dinsig.c b/scd/app-dinsig.c index 28b70c466..75cd12c59 100644 --- a/scd/app-dinsig.c +++ b/scd/app-dinsig.c @@ -1,5 +1,5 @@ /* app-dinsig.c - The DINSIG (DIN V 66291-1) card application. - * Copyright (C) 2002, 2004 Free Software Foundation, Inc. + * Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -280,10 +280,11 @@ verify_pin (app_t app, { if (!app->did_chv1 || app->force_chv1 ) { + const char *s; char *pinvalue; int rc; - rc = pincb (pincb_arg, "PIN", &pinvalue); + rc = pincb (pincb_arg, "PIN", &pinvalue); if (rc) { log_info ("PIN callback returned error: %s\n", gpg_strerror (rc)); @@ -291,8 +292,16 @@ verify_pin (app_t app, } /* We require the PIN to be at least 6 and at max 8 bytes. - According to the specs, this should all be ASCII but we don't - check this. */ + According to the specs, this should all be ASCII. */ + for (s=pinvalue; digitp (s); s++) + ; + if (*s) + { + log_error ("Non-numeric digits found in PIN\n"); + xfree (pinvalue); + return gpg_error (GPG_ERR_BAD_PIN); + } + if (strlen (pinvalue) < 6) { log_error ("PIN is too short; minimum length is 6\n"); @@ -307,6 +316,28 @@ verify_pin (app_t app, } rc = iso7816_verify (app->slot, 0x81, pinvalue, strlen (pinvalue)); + if (gpg_err_code (rc) == GPG_ERR_INV_VALUE) + { + /* We assume that ISO 9564-1 encoding is used and we failed + because the first nibble we passed was 3 and not 2. DIN + says something about looking up such an encoding in the + SSD but I was not able to find any tag relevant to + this. */ + char paddedpin[8]; + int i, ndigits; + + for (ndigits=0, s=pinvalue; *s; ndigits++, s++) + ; + i = 0; + paddedpin[i++] = 0x20 | (ndigits & 0x0f); + for (s=pinvalue; i < sizeof paddedpin && *s && s[1]; s = s+2 ) + paddedpin[i++] = (((*s - '0') << 4) | ((s[1] - '0') & 0x0f)); + if (i < sizeof paddedpin && *s) + paddedpin[i++] = (((*s - '0') << 4) | 0x0f); + while (i < sizeof paddedpin) + paddedpin[i++] = 0xff; + rc = iso7816_verify (app->slot, 0x81, paddedpin, sizeof paddedpin); + } if (rc) { log_error ("verify PIN failed\n"); @@ -404,7 +435,7 @@ app_select_dinsig (APP app) int slot = app->slot; int rc; - rc = iso7816_select_application (slot, aid, sizeof aid); + rc = iso7816_select_application (slot, aid, sizeof aid, 0); if (!rc) { app->apptype = "DINSIG"; diff --git a/scd/app-nks.c b/scd/app-nks.c index b6a3037ed..73ec8ea01 100644 --- a/scd/app-nks.c +++ b/scd/app-nks.c @@ -27,7 +27,7 @@ #include #include "scdaemon.h" - +#include "i18n.h" #include "iso7816.h" #include "app-common.h" #include "tlv.h" @@ -320,7 +320,7 @@ verify_pin (app_t app, return rc; } - /* The follwoing limits are due to TCOS but also defined in the + /* The following limits are due to TCOS but also defined in the NKS specs. */ if (strlen (pinvalue) < 6) { @@ -340,7 +340,10 @@ verify_pin (app_t app, rc = iso7816_verify (app->slot, 0, pinvalue, strlen (pinvalue)); if (rc) { - log_error ("verify PIN failed\n"); + if ( gpg_error (rc) == GPG_ERR_USE_CONDITIONS ) + log_error (_("the NullPIN has not yet been changed\n")); + else + log_error ("verify PIN failed\n"); xfree (pinvalue); return rc; } @@ -492,7 +495,7 @@ app_select_nks (APP app) int slot = app->slot; int rc; - rc = iso7816_select_application (slot, aid, sizeof aid); + rc = iso7816_select_application (slot, aid, sizeof aid, 0); if (!rc) { app->apptype = "NKS"; diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 5625c729b..3d04be0be 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -1284,6 +1284,11 @@ verify_chv2 (app_t app, if (!app->did_chv2) { char *pinvalue; + iso7816_pininfo_t pininfo; + + memset (&pininfo, 0, sizeof pininfo); + pininfo.mode = 1; + pininfo.minlen = 6; rc = pincb (pincb_arg, "PIN", &pinvalue); if (rc) @@ -2455,7 +2460,9 @@ app_select_openpgp (app_t app) size_t buflen; void *relptr; - rc = iso7816_select_application (slot, aid, sizeof aid); + /* Note that the card can't cope with P2=0xCO, thus we need to pass a + special flag value. */ + rc = iso7816_select_application (slot, aid, sizeof aid, 0x0001); if (!rc) { unsigned int manufacturer; diff --git a/scd/app-p15.c b/scd/app-p15.c index 739a9ef95..8bb94cfcd 100644 --- a/scd/app-p15.c +++ b/scd/app-p15.c @@ -3268,18 +3268,15 @@ app_select_p15 (app_t app) int direct = 0; int is_belpic = 0; - rc = iso7816_select_application (slot, pkcs15_aid, sizeof pkcs15_aid); - if (rc) - { - rc = iso7816_select_application (slot, pkcs15be_aid,sizeof pkcs15be_aid); - if (!rc) - is_belpic = 1; - } + rc = iso7816_select_application (slot, pkcs15_aid, sizeof pkcs15_aid, 0); if (rc) { /* Not found: Try to locate it from 2F00. We use direct path selection here because it seems that the Belgian eID card does only allow for that. Many other cards supports this - selection method too. */ + selection method too. Note, that we don't use + select_application above for the Belgian card - the call + works but it seems that it did not switch to the correct DF. + Using the 2f02 just works. */ unsigned short path[1] = { 0x2f00 }; rc = iso7816_select_path (app->slot, path, 1, NULL, NULL); diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c index f82d93b00..fee733358 100644 --- a/scd/ccid-driver.c +++ b/scd/ccid-driver.c @@ -1240,7 +1240,9 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length, if (CCID_COMMAND_FAILED (buffer)) print_command_failed (buffer); - /* Check whether a card is at all available. */ + /* Check whether a card is at all available. Note: If you add new + error codes here, check whether they need to be ignored in + send_escape_cmd. */ switch ((buffer[7] & 0x03)) { case 0: /* no error */ break; @@ -1253,16 +1255,23 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length, /* Note that this function won't return the error codes NO_CARD or - CARD_INACTIVE */ + CARD_INACTIVE. IF RESULT is not NULL, the result from the + operation will get returned in RESULT and its length in RESULTLEN. + If the response is larger than RESULTMAX, an error is returned and + the required buffer length returned in RESULTLEN. */ static int send_escape_cmd (ccid_driver_t handle, - const unsigned char *data, size_t datalen) + const unsigned char *data, size_t datalen, + unsigned char *result, size_t resultmax, size_t *resultlen) { int i, rc; unsigned char msg[100]; size_t msglen; unsigned char seqno; + if (resultlen) + *resultlen = 0; + if (datalen > sizeof msg - 10) return CCID_DRIVER_ERR_INV_VALUE; /* Escape data too large. */ @@ -1285,11 +1294,42 @@ send_escape_cmd (ccid_driver_t handle, return rc; rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Escape, seqno, 5000, 0); - + if (result) + switch (rc) + { + /* We need to ignore certain errorcode here. */ + case 0: + case CCID_DRIVER_ERR_CARD_INACTIVE: + case CCID_DRIVER_ERR_NO_CARD: + { + if (msglen > resultmax) + rc = CCID_DRIVER_ERR_INV_VALUE; /* Response too large. */ + else + { + memcpy (result, msg, msglen); + *resultlen = msglen; + } + rc = 0; + } + break; + default: + break; + } + return rc; } +int +ccid_transceive_escape (ccid_driver_t handle, + const unsigned char *data, size_t datalen, + unsigned char *resp, size_t maxresplen, size_t *nresp) +{ + return send_escape_cmd (handle, data, datalen, resp, maxresplen, nresp); +} + + + /* experimental */ int ccid_poll (ccid_driver_t handle) @@ -1445,7 +1485,8 @@ ccid_get_atr (ccid_driver_t handle, { tried_iso = 1; /* Try switching to ISO mode. */ - if (!send_escape_cmd (handle, (const unsigned char*)"\xF1\x01", 2)) + if (!send_escape_cmd (handle, (const unsigned char*)"\xF1\x01", 2, + NULL, 0, NULL)) goto again; } else if (CCID_COMMAND_FAILED (msg)) @@ -1957,14 +1998,16 @@ ccid_transceive (ccid_driver_t handle, } -/* Send the CCID Secure command to the reader. APDU_BUF should contain the APDU template. PIN_MODE defines now the pin gets formatted: +/* Send the CCID Secure command to the reader. APDU_BUF should + contain the APDU template. PIN_MODE defines how the pin gets + formatted: 1 := The PIN is ASCII encoded and of variable length. The length of the PIN entered will be put into Lc by the reader. The APDU should me made up of 4 bytes without Lc. PINLEN_MIN and PINLEN_MAX define the limits for the pin length. 0 - may be used t enable usbale defaults. PIN_PADLEN should be 0 + may be used t enable reasonable defaults. PIN_PADLEN should be 0. When called with RESP and NRESP set to NULL, the function will merely check whether the reader supports the secure command for the @@ -1996,7 +2039,7 @@ ccid_transceive_secure (ccid_driver_t handle, else if (apdu_buflen >= 4 && apdu_buf[1] == 0x24 && (handle->has_pinpad & 2)) return CCID_DRIVER_ERR_NOT_SUPPORTED; /* Not yet by our code. */ else - return CCID_DRIVER_ERR_NOT_SUPPORTED; + return CCID_DRIVER_ERR_NO_KEYPAD; if (pin_mode != 1) return CCID_DRIVER_ERR_NOT_SUPPORTED; @@ -2027,7 +2070,8 @@ ccid_transceive_secure (ccid_driver_t handle, if (handle->id_vendor == VENDOR_SCM) { DEBUGOUT ("sending escape sequence to switch to a case 1 APDU\n"); - rc = send_escape_cmd (handle, (const unsigned char*)"\x80\x02\x00", 3); + rc = send_escape_cmd (handle, (const unsigned char*)"\x80\x02\x00", 3, + NULL, 0, NULL); if (rc) return rc; } @@ -2044,7 +2088,7 @@ ccid_transceive_secure (ccid_driver_t handle, if (handle->id_vendor == VENDOR_SCM) { /* For the SPR532 the next 2 bytes need to be zero. We do this - for all SCM product. Kudos to to Martin Paljak for this + for all SCM product. Kudos to Martin Paljak for this hint. */ msg[13] = msg[14] = 0; } diff --git a/scd/ccid-driver.h b/scd/ccid-driver.h index 1b9ac2f85..6f6527108 100644 --- a/scd/ccid-driver.h +++ b/scd/ccid-driver.h @@ -58,7 +58,7 @@ #ifndef CCID_DRIVER_H #define CCID_DRIVER_H -/* The CID driver returns the same error codes as the statsu words +/* The CID driver returns the same error codes as the status words used by GnuPG's apdu.h. For ease of maintenance they should always match. */ #define CCID_DRIVER_ERR_OUT_OF_CORE 0x10001 @@ -74,6 +74,7 @@ #define CCID_DRIVER_ERR_GENERAL_ERROR 0x1000b #define CCID_DRIVER_ERR_NO_READER 0x1000c #define CCID_DRIVER_ERR_ABORTED 0x1000d +#define CCID_DRIVER_ERR_NO_KEYPAD 0x1000e struct ccid_driver_s; typedef struct ccid_driver_s *ccid_driver_t; @@ -94,6 +95,10 @@ int ccid_transceive_secure (ccid_driver_t handle, int pin_mode, int pinlen_min, int pinlen_max, int pin_padlen, unsigned char *resp, size_t maxresplen, size_t *nresp); +int ccid_transceive_escape (ccid_driver_t handle, + const unsigned char *data, size_t datalen, + unsigned char *resp, size_t maxresplen, + size_t *nresp); diff --git a/scd/iso7816.c b/scd/iso7816.c index 5b985324f..5c62e1371 100644 --- a/scd/iso7816.c +++ b/scd/iso7816.c @@ -47,9 +47,9 @@ #define CMD_SELECT_FILE 0xA4 -#define CMD_VERIFY 0x20 -#define CMD_CHANGE_REFERENCE_DATA 0x24 -#define CMD_RESET_RETRY_COUNTER 0x2C +#define CMD_VERIFY ISO7816_VERIFY +#define CMD_CHANGE_REFERENCE_DATA ISO7816_CHANGE_REFERENCE_DATA +#define CMD_RESET_RETRY_COUNTER ISO7816_RESET_RETRY_COUNTER #define CMD_GET_DATA 0xCA #define CMD_PUT_DATA 0xDA #define CMD_MSE 0x22 @@ -95,6 +95,7 @@ map_sw (int sw) case SW_HOST_GENERAL_ERROR: ec = GPG_ERR_GENERAL; break; case SW_HOST_NO_READER: ec = GPG_ERR_ENODEV; break; case SW_HOST_ABORTED: ec = GPG_ERR_CANCELED; break; + case SW_HOST_NO_KEYPAD: ec = GPG_ERR_NOT_SUPPORTED; break; default: if ((sw & 0x010000)) @@ -124,12 +125,15 @@ iso7816_map_sw (int sw) requested application ID. The function can't be used to enumerate AIDs and won't return the AID on success. The return value is 0 for okay or a GPG error code. Note that ISO error codes are - internally mapped. */ + internally mapped. Bit 0 of FLAGS should be set if the card does + not understand P2=0xC0. */ gpg_error_t -iso7816_select_application (int slot, const char *aid, size_t aidlen) +iso7816_select_application (int slot, const char *aid, size_t aidlen, + unsigned int flags) { int sw; - sw = apdu_send_simple (slot, 0x00, CMD_SELECT_FILE, 4, 0, aidlen, aid); + sw = apdu_send_simple (slot, 0x00, CMD_SELECT_FILE, 4, + (flags&1)? 0 :0x0c, aidlen, aid); return map_sw (sw); } @@ -221,27 +225,59 @@ iso7816_list_directory (int slot, int list_dirs, } +/* Check whether the reader supports the ISO command code COMMAND on + the keypad. Returns 0 on success. */ +gpg_error_t +iso7816_check_keypad (int slot, int command, iso7816_pininfo_t *pininfo) +{ + int sw; + + sw = apdu_check_keypad (slot, command, + pininfo->mode, pininfo->minlen, pininfo->maxlen, + pininfo->padlen); + return map_sw (sw); +} + /* Perform a VERIFY command on SLOT using the card holder verification - vector CHVNO with a CHV of lenght CHVLEN. Returns 0 on success. */ + vector CHVNO with a CHV of lenght CHVLEN. With PININFO non-NULL + the keypad of the reader will be used. Returns 0 on success. */ gpg_error_t -iso7816_verify (int slot, int chvno, const char *chv, size_t chvlen) +iso7816_verify_kp (int slot, int chvno, const char *chv, size_t chvlen, + iso7816_pininfo_t *pininfo) { int sw; - sw = apdu_send_simple (slot, 0x00, CMD_VERIFY, 0, chvno, chvlen, chv); + if (pininfo && pininfo->mode) + sw = apdu_send_simple_kp (slot, 0x00, CMD_VERIFY, 0, chvno, chvlen, chv, + pininfo->mode, + pininfo->minlen, + pininfo->maxlen, + pininfo->padlen); + else + sw = apdu_send_simple (slot, 0x00, CMD_VERIFY, 0, chvno, chvlen, chv); return map_sw (sw); } +/* Perform a VERIFY command on SLOT using the card holder verification + vector CHVNO with a CHV of lenght CHVLEN. Returns 0 on success. */ +gpg_error_t +iso7816_verify (int slot, int chvno, const char *chv, size_t chvlen) +{ + return iso7816_verify_kp (slot, chvno, chv, chvlen, NULL); +} + /* Perform a CHANGE_REFERENCE_DATA command on SLOT for the card holder verification vector CHVNO. If the OLDCHV is NULL (and OLDCHVLEN 0), a "change reference data" is done, otherwise an "exchange reference data". The new reference data is expected in NEWCHV of - length NEWCHVLEN. */ + length NEWCHVLEN. With PININFO non-NULL the keypad of the reader + will be used. */ gpg_error_t -iso7816_change_reference_data (int slot, int chvno, - const char *oldchv, size_t oldchvlen, - const char *newchv, size_t newchvlen) +iso7816_change_reference_data_kp (int slot, int chvno, + const char *oldchv, size_t oldchvlen, + const char *newchv, size_t newchvlen, + iso7816_pininfo_t *pininfo) { int sw; char *buf; @@ -258,28 +294,69 @@ iso7816_change_reference_data (int slot, int chvno, memcpy (buf, oldchv, oldchvlen); memcpy (buf+oldchvlen, newchv, newchvlen); - sw = apdu_send_simple (slot, 0x00, CMD_CHANGE_REFERENCE_DATA, - oldchvlen? 0 : 1, chvno, oldchvlen+newchvlen, buf); + if (pininfo && pininfo->mode) + sw = apdu_send_simple_kp (slot, 0x00, CMD_CHANGE_REFERENCE_DATA, + oldchvlen? 0 : 1, chvno, oldchvlen+newchvlen, buf, + pininfo->mode, + pininfo->minlen, + pininfo->maxlen, + pininfo->padlen); + else + sw = apdu_send_simple (slot, 0x00, CMD_CHANGE_REFERENCE_DATA, + oldchvlen? 0 : 1, chvno, oldchvlen+newchvlen, buf); xfree (buf); return map_sw (sw); } +/* Perform a CHANGE_REFERENCE_DATA command on SLOT for the card holder + verification vector CHVNO. If the OLDCHV is NULL (and OLDCHVLEN + 0), a "change reference data" is done, otherwise an "exchange + reference data". The new reference data is expected in NEWCHV of + length NEWCHVLEN. */ +gpg_error_t +iso7816_change_reference_data (int slot, int chvno, + const char *oldchv, size_t oldchvlen, + const char *newchv, size_t newchvlen) +{ + return iso7816_change_reference_data_kp (slot, chvno, oldchv, oldchvlen, + newchv, newchvlen, NULL); +} + + gpg_error_t -iso7816_reset_retry_counter (int slot, int chvno, - const char *newchv, size_t newchvlen) +iso7816_reset_retry_counter_kp (int slot, int chvno, + const char *newchv, size_t newchvlen, + iso7816_pininfo_t *pininfo) { int sw; if (!newchv || !newchvlen ) return gpg_error (GPG_ERR_INV_VALUE); - sw = apdu_send_simple (slot, 0x00, CMD_RESET_RETRY_COUNTER, - 2, chvno, newchvlen, newchv); + if (pininfo && pininfo->mode) + sw = apdu_send_simple_kp (slot, 0x00, CMD_RESET_RETRY_COUNTER, + 2, chvno, newchvlen, newchv, + pininfo->mode, + pininfo->minlen, + pininfo->maxlen, + pininfo->padlen); + else + sw = apdu_send_simple (slot, 0x00, CMD_RESET_RETRY_COUNTER, + 2, chvno, newchvlen, newchv); return map_sw (sw); } +gpg_error_t +iso7816_reset_retry_counter (int slot, int chvno, + const char *newchv, size_t newchvlen) +{ + return iso7816_reset_retry_counter_kp (slot, chvno, newchv, newchvlen, NULL); +} + + + /* Perform a GET DATA command requesting TAG and storing the result in a newly allocated buffer at the address passed by RESULT. Return the length of this data at the address of RESULTLEN. */ diff --git a/scd/iso7816.h b/scd/iso7816.h index 04c7ae63e..8f7907405 100644 --- a/scd/iso7816.h +++ b/scd/iso7816.h @@ -28,10 +28,30 @@ #include "cardglue.h" #endif +/* Command codes used by iso7816_check_keypad. */ +#define ISO7816_VERIFY 0x20 +#define ISO7816_CHANGE_REFERENCE_DATA 0x24 +#define ISO7816_RESET_RETRY_COUNTER 0x2C + + +/* Information to be passed to keypad equipped readers. See + ccid-driver.c for details. */ +struct iso7816_pininfo_s +{ + int mode; /* A mode of 0 means: Do not use the keypad. */ + int minlen; + int maxlen; + int padlen; + int padchar; +}; +typedef struct iso7816_pininfo_s iso7816_pininfo_t; + + gpg_error_t iso7816_map_sw (int sw); gpg_error_t iso7816_select_application (int slot, - const char *aid, size_t aidlen); + const char *aid, size_t aidlen, + unsigned int flags); gpg_error_t iso7816_select_file (int slot, int tag, int is_dir, unsigned char **result, size_t *resultlen); gpg_error_t iso7816_select_path (int slot, @@ -39,13 +59,26 @@ gpg_error_t iso7816_select_path (int slot, unsigned char **result, size_t *resultlen); gpg_error_t iso7816_list_directory (int slot, int list_dirs, unsigned char **result, size_t *resultlen); +gpg_error_t iso7816_check_keypad (int slot, int command, + iso7816_pininfo_t *pininfo); gpg_error_t iso7816_verify (int slot, int chvno, const char *chv, size_t chvlen); +gpg_error_t iso7816_verify_kp (int slot, + int chvno, const char *chv, size_t chvlen, + iso7816_pininfo_t *pininfo); gpg_error_t iso7816_change_reference_data (int slot, int chvno, const char *oldchv, size_t oldchvlen, const char *newchv, size_t newchvlen); +gpg_error_t iso7816_change_reference_data_kp (int slot, int chvno, + const char *oldchv, size_t oldchvlen, + const char *newchv, size_t newchvlen, + iso7816_pininfo_t *pininfo); gpg_error_t iso7816_reset_retry_counter (int slot, int chvno, const char *newchv, size_t newchvlen); +gpg_error_t iso7816_reset_retry_counter_kp (int slot, int chvno, + const char *newchv, + size_t newchvlen, + iso7816_pininfo_t *pininfo); gpg_error_t iso7816_get_data (int slot, int tag, unsigned char **result, size_t *resultlen); gpg_error_t iso7816_put_data (int slot, int tag, diff --git a/scd/scdaemon.c b/scd/scdaemon.c index c6995abcc..56c0d7600 100644 --- a/scd/scdaemon.c +++ b/scd/scdaemon.c @@ -84,6 +84,7 @@ enum cmd_and_opt_values opcscDriver, oDisableCCID, oDisableOpenSC, + oDisableKeypad, oAllowAdmin, oDenyAdmin, oDisableApplication, @@ -126,6 +127,7 @@ static ARGPARSE_OPTS opts[] = { "@" #endif /* end --disable-ccid */}, + { oDisableKeypad, "disable-keypad", 0, N_("do not use a reader's keypad")}, { oAllowAdmin, "allow-admin", 0, N_("allow the use of admin card commands")}, { oDenyAdmin, "deny-admin", 0, "@" }, { oDisableApplication, "disable-application", 2, "@"}, @@ -135,7 +137,7 @@ static ARGPARSE_OPTS opts[] = { /* The card dirver we use by default for PC/SC. */ -#ifdef HAVE_W32_SYSTEM +#if defined(HAVE_W32_SYSTEM) || defined(__CYGWIN__) #define DEFAULT_PCSC_DRIVER "winscard.dll" #else #define DEFAULT_PCSC_DRIVER "libpcsclite.so" @@ -489,6 +491,8 @@ main (int argc, char **argv ) case oDisableCCID: opt.disable_ccid = 1; break; case oDisableOpenSC: break; + case oDisableKeypad: opt.disable_keypad = 1; break; + case oAllowAdmin: opt.allow_admin = 1; break; case oDenyAdmin: opt.allow_admin = 0; break; diff --git a/scd/scdaemon.h b/scd/scdaemon.h index 54566b6ad..abe9730a7 100644 --- a/scd/scdaemon.h +++ b/scd/scdaemon.h @@ -39,21 +39,22 @@ #define MAX_DIGEST_LEN 24 -/* A large struct name "opt" to keep global flags */ +/* A large struct name "opt" to keep global flags. */ struct { - unsigned int debug; /* debug flags (DBG_foo_VALUE) */ - int verbose; /* verbosity level */ - int quiet; /* be as quiet as possible */ - int dry_run; /* don't change any persistent data */ - int batch; /* batch mode */ - const char *homedir; /* configuration directory name */ + unsigned int debug; /* Debug flags (DBG_foo_VALUE). */ + int verbose; /* Verbosity level. */ + int quiet; /* Be as quiet as possible. */ + int dry_run; /* Don't change any persistent data. */ + int batch; /* Batch mode. */ + const char *homedir; /* Configuration directory name. */ const char *ctapi_driver; /* Library to access the ctAPI. */ const char *pcsc_driver; /* Library to access the PC/SC system. */ const char *reader_port; /* NULL or reder port to use. */ int disable_ccid; /* Disable the use of the internal CCID driver. */ + int disable_keypad; /* Do not use a keypad. */ int allow_admin; /* Allow the use of admin commands for certain cards. */ - strlist_t disabled_applications; /* card applications we do not + strlist_t disabled_applications; /* Card applications we do not want to use. */ } opt; diff --git a/tools/ChangeLog b/tools/ChangeLog index ba4f0ec27..a57a0bccf 100644 --- a/tools/ChangeLog +++ b/tools/ChangeLog @@ -1,3 +1,11 @@ +2005-10-19 Werner Koch + + * gpgconf-comp.c (gc_options_scdaemon): New option --disable-keypad. + +2005-09-22 Werner Koch + + * rfc822parse.c (parse_field): Tread Content-Disposition special. + 2005-10-08 Marcus Brinkmann * Makefile.am (watchgnupg_LDADD): New variable. diff --git a/tools/gpgconf-comp.c b/tools/gpgconf-comp.c index e8d9ca27e..497707532 100644 --- a/tools/gpgconf-comp.c +++ b/tools/gpgconf-comp.c @@ -528,7 +528,9 @@ static gc_option_t gc_options_scdaemon[] = { "disable-ccid", GC_OPT_FLAG_NONE, GC_LEVEL_EXPERT, "gnupg", "do not use the internal CCID driver", GC_ARG_TYPE_NONE, GC_BACKEND_SCDAEMON }, - + { "disable-keypad", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED, + "gnupg", "do not use a reader's keypad", + GC_ARG_TYPE_NONE, GC_BACKEND_SCDAEMON }, { "Debug", GC_OPT_FLAG_GROUP, GC_LEVEL_ADVANCED, @@ -2447,7 +2449,8 @@ gc_component_change_options (int component, FILE *in) { #ifdef HAVE_W32_SYSTEM /* FIXME: Won't work becuase W32 doesn't silently - overwrite. */ + overwrite. Fix it by creating a backup copy and + deliting the orginal file first. */ err = rename (src_pathname[i], dest_pathname[i]); #else /*!HAVE_W32_SYSTEM*/ /* This is a bit safer than rename() because we diff --git a/tools/rfc822parse.c b/tools/rfc822parse.c index 61377e7e6..df3b2e7a4 100644 --- a/tools/rfc822parse.c +++ b/tools/rfc822parse.c @@ -766,6 +766,7 @@ parse_field (HDR_LINE hdr) } tspecial_header[] = { { "Content-Type", 12}, { "Content-Transfer-Encoding", 25}, + { "Content-Disposition", 19}, { NULL, 0} }; const char *delimiters; -- cgit From a5465705fb59789783b5fcb14550eb30e6d863a3 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 6 Feb 2006 16:13:20 +0000 Subject: Support for CardMan 4040 --- scd/ChangeLog | 15 ++ scd/app-openpgp.c | 10 +- scd/ccid-driver.c | 717 +++++++++++++++++++++++++++++++++++++----------------- 3 files changed, 510 insertions(+), 232 deletions(-) (limited to 'scd/app-openpgp.c') diff --git a/scd/ChangeLog b/scd/ChangeLog index 64c3bdc59..359b3f05a 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,18 @@ +2006-02-02 Werner Koch + + * ccid-driver.c (special_transport): New + (ccid_open_reader, do_close_reader, ccid_shutdown_reader) + (bulk_out, bulk_in): Add support for CardMan 4040 reader. + + * ccid-driver.c (scan_or_find_devices): Factored most code out to + (scan_or_find_usb_device): .. new. + (make_reader_id): Fixed vendor mask. + +2006-01-01 Werner Koch + + * app-openpgp.c (do_sign): Give user error if hash algorithm is + not supported by the card. + 2005-12-06 Werner Koch * apdu.c (open_pcsc_reader): Check that pcsc-wrapper is actually diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 3d04be0be..fff709a08 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -484,7 +484,7 @@ count_bits (const unsigned char *a, size_t len) Everything up to a LF is considered a mailbox or account name. If the first LF is followed by DC4 (0x14) control sequence are expected up to the next LF. Control sequences are separated by FS - (0x28) and consist of key=value pairs. There is one key defined: + (0x18) and consist of key=value pairs. There is one key defined: F= @@ -2084,7 +2084,7 @@ check_against_given_fingerprint (app_t app, const char *fpr, int keyno) raw message digest. For this application the KEYIDSTR consists of the serialnumber and the fingerprint delimited by a slash. - Note that this fucntion may return the error code + Note that this function may return the error code GPG_ERR_WRONG_CARD to indicate that the card currently present does not match the one required for the requested action (e.g. the serial number does not match). */ @@ -2120,7 +2120,11 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, && !memcmp (indata, rmd160_prefix, 15)) ; else - return gpg_error (GPG_ERR_INV_VALUE); + { + log_error (_("card does not support digest algorithm %s\n"), + gcry_md_algo_name (hashalgo)); + return gpg_error (GPG_ERR_INV_VALUE); + } /* Check whether an OpenPGP card of any version has been requested. */ if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12)) diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c index fee733358..e884c6624 100644 --- a/scd/ccid-driver.c +++ b/scd/ccid-driver.c @@ -67,8 +67,8 @@ portable access to USB. This driver has been tested with the SCM SCR335 and SPR532 - smartcard readers and requires that a reader implements the TPDU - level exchange and does fully automatic initialization. + smartcard readers and requires that a reader implements APDU or + TPDU level exchange and does fully automatic initialization. */ #ifdef HAVE_CONFIG_H @@ -82,6 +82,9 @@ #include #include #include +#include +#include +#include #include @@ -194,11 +197,29 @@ enum { /* We need to know the vendor to do some hacks. */ enum { - VENDOR_SCM = 0x04e6, VENDOR_CHERRY = 0x046a, + VENDOR_SCM = 0x04e6, + VENDOR_OMNIKEY= 0x076b, VENDOR_GEMPC = 0x08e6 }; +/* A list and a table with special transport descriptions. */ +enum { + TRANSPORT_USB = 0, /* Standard USB transport. */ + TRANSPORT_CM4040 = 1 /* As used by the Cardman 4040. */ +}; + +static struct +{ + char *name; /* Device name. */ + int type; + +} transports[] = { + { "/dev/cmx0", TRANSPORT_CM4040 }, + { "/dev/cmx1", TRANSPORT_CM4040 }, + { NULL }, +}; + /* Store information on the driver's state. A pointer to such a structure is used as handle for most functions. */ @@ -206,6 +227,8 @@ struct ccid_driver_s { usb_dev_handle *idev; char *rid; + int dev_fd; /* -1 for USB transport or file descriptor of the + transport device. */ unsigned short id_vendor; unsigned short id_product; unsigned short bcd_device; @@ -306,7 +329,34 @@ print_command_failed (const unsigned char *msg) } +/* Given a handle used for special transport prepare it for use. In + particular setup all information in way that resembles what + parse_cccid_descriptor does. */ +static void +prepare_special_transport (ccid_driver_t handle) +{ + assert (!handle->id_vendor); + + handle->nonnull_nad = 0; + handle->auto_ifsd = 0; + handle->max_ifsd = 32; + handle->ifsd = 0; + handle->has_pinpad = 0; + handle->apdu_level = 0; + switch (handle->id_product) + { + case TRANSPORT_CM4040: + DEBUGOUT ("setting up transport for CardMan 4040\n"); + /* Most values are guessed. */ + handle->nonnull_nad = 1; + handle->auto_ifsd = 1; + handle->max_ifsd = 254; + handle->apdu_level = 1; + break; + default: assert (!"transport not defined"); + } +} /* Parse a CCID descriptor, optionally print all available features and test whether this reader is usable by this driver. Returns 0 @@ -615,7 +665,7 @@ make_reader_id (usb_dev_handle *idev, char *rid; char prefix[20]; - sprintf (prefix, "%04X:%04X:", (vendor & 0xfff), (product & 0xffff)); + sprintf (prefix, "%04X:%04X:", (vendor & 0xffff), (product & 0xffff)); rid = get_escaped_usb_string (idev, serialno_index, prefix, ":0"); if (!rid) { @@ -658,10 +708,177 @@ find_endpoint (struct usb_interface_descriptor *ifcdesc, int mode) } +/* Helper for scan_or_find_devices. This function returns true if a + requested device has been found or the caller should stop scanning + for other reasons. */ +static int +scan_or_find_usb_device (int scan_mode, + int *readerno, int *count, char **rid_list, + const char *readerid, + struct usb_device *dev, + char **r_rid, + struct usb_device **r_dev, + usb_dev_handle **r_idev, + unsigned char **ifcdesc_extra, + size_t *ifcdesc_extra_len, + int *interface_number, + int *ep_bulk_out, int *ep_bulk_in, int *ep_intr) +{ + int cfg_no; + int ifc_no; + int set_no; + struct usb_config_descriptor *config; + struct usb_interface *interface; + struct usb_interface_descriptor *ifcdesc; + char *rid; + usb_dev_handle *idev; + + *r_idev = NULL; + + for (cfg_no=0; cfg_no < dev->descriptor.bNumConfigurations; cfg_no++) + { + config = dev->config + cfg_no; + if(!config) + continue; + + for (ifc_no=0; ifc_no < config->bNumInterfaces; ifc_no++) + { + interface = config->interface + ifc_no; + if (!interface) + continue; + + for (set_no=0; set_no < interface->num_altsetting; set_no++) + { + ifcdesc = (interface->altsetting + set_no); + /* The second condition is for older SCM SPR 532 who did + not know about the assigned CCID class. Instead of + trying to interpret the strings we simply check the + product ID. */ + if (ifcdesc && ifcdesc->extra + && ((ifcdesc->bInterfaceClass == 11 + && ifcdesc->bInterfaceSubClass == 0 + && ifcdesc->bInterfaceProtocol == 0) + || (ifcdesc->bInterfaceClass == 255 + && dev->descriptor.idVendor == VENDOR_SCM + && dev->descriptor.idProduct == 0xe003))) + { + idev = usb_open (dev); + if (!idev) + { + DEBUGOUT_1 ("usb_open failed: %s\n", + strerror (errno)); + continue; /* with next setting. */ + } + + rid = make_reader_id (idev, + dev->descriptor.idVendor, + dev->descriptor.idProduct, + dev->descriptor.iSerialNumber); + if (rid) + { + if (scan_mode) + { + char *p; + + /* We are collecting infos about all + available CCID readers. Store them and + continue. */ + DEBUGOUT_2 ("found CCID reader %d (ID=%s)\n", + *count, rid ); + p = malloc ((*rid_list? strlen (*rid_list):0) + 1 + + strlen (rid) + 1); + if (p) + { + *p = 0; + if (*rid_list) + { + strcat (p, *rid_list); + free (*rid_list); + } + strcat (p, rid); + strcat (p, "\n"); + *rid_list = p; + } + else /* Out of memory. */ + free (rid); + + rid = NULL; + ++*count; + } + else if (!*readerno + || (*readerno < 0 + && readerid + && !strcmp (readerid, rid))) + { + /* We found the requested reader. */ + if (ifcdesc_extra && ifcdesc_extra_len) + { + *ifcdesc_extra = malloc (ifcdesc + ->extralen); + if (!*ifcdesc_extra) + { + usb_close (idev); + free (rid); + return 1; /* Out of core. */ + } + memcpy (*ifcdesc_extra, ifcdesc->extra, + ifcdesc->extralen); + *ifcdesc_extra_len = ifcdesc->extralen; + } + + if (interface_number) + *interface_number = (ifcdesc->bInterfaceNumber); + + if (ep_bulk_out) + *ep_bulk_out = find_endpoint (ifcdesc, 0); + if (ep_bulk_in) + *ep_bulk_in = find_endpoint (ifcdesc, 1); + if (ep_intr) + *ep_intr = find_endpoint (ifcdesc, 2); + + if (r_dev) + *r_dev = dev; + if (r_rid) + { + *r_rid = rid; + rid = NULL; + } + else + free (rid); + + *r_idev = idev; + return 1; /* Found requested device. */ + } + else + { + /* This is not yet the reader we want. + fixme: We should avoid the extra usb_open + in this case. */ + if (*readerno >= 0) + --*readerno; + } + free (rid); + } + + usb_close (idev); + idev = NULL; + return 0; + } + } + } + } + + return 0; +} /* Combination function to either scan all CCID devices or to find and open one specific device. + The function returns 0 if a reader has been found or when a scan + returned without error. + + FIXME!! + With READERNO = -1 and READERID is NULL, scan mode is used and R_RID should be the address where to store the list of reader_ids we found. If on return this list is empty, no CCID device has been @@ -671,11 +888,11 @@ find_endpoint (struct usb_interface_descriptor *ifcdesc, int mode) With READERNO >= 0 or READERID is not NULL find mode is used. This uses the same algorithm as the scan mode but stops and returns at the entry number READERNO and return the handle for the the opened - USB device. If R_ID is not NULL it will receive the reader ID of + USB device. If R_RID is not NULL it will receive the reader ID of that device. If R_DEV is not NULL it will the device pointer of that device. If IFCDESC_EXTRA is NOT NULL it will receive a malloced copy of the interfaces "extra: data filed; - IFCDESC_EXTRA_LEN receive the lengtyh of this field. If there is + IFCDESC_EXTRA_LEN receive the length of this field. If there is no reader with number READERNO or that reader is not usable by our implementation NULL will be returned. The caller must close a returned USB device handle and free (if not passed as NULL) the @@ -684,17 +901,25 @@ find_endpoint (struct usb_interface_descriptor *ifcdesc, int mode) IFCDESC_EXTRA_LEN. With READERID being -1 the function stops if the READERID was found. + If R_FD is not -1 on return the device is not using USB for + transport but the device associated with that file descriptor. In + this case INTERFACE will receive the transport type and the other + USB specific return values are not used; the return value is + (void*)(1). + Note that the first entry of the returned reader ID list in scan mode corresponds with a READERNO of 0 in find mode. */ -static usb_dev_handle * +static int scan_or_find_devices (int readerno, const char *readerid, char **r_rid, struct usb_device **r_dev, unsigned char **ifcdesc_extra, size_t *ifcdesc_extra_len, int *interface_number, - int *ep_bulk_out, int *ep_bulk_in, int *ep_intr) + int *ep_bulk_out, int *ep_bulk_in, int *ep_intr, + usb_dev_handle **r_idev, + int *r_fd) { char *rid_list = NULL; int count = 0; @@ -702,8 +927,9 @@ scan_or_find_devices (int readerno, const char *readerid, struct usb_device *dev = NULL; usb_dev_handle *idev = NULL; int scan_mode = (readerno == -1 && !readerid); + int i; - /* Set return values to a default. */ + /* Set return values to a default. */ if (r_rid) *r_rid = NULL; if (r_dev) @@ -714,6 +940,10 @@ scan_or_find_devices (int readerno, const char *readerid, *ifcdesc_extra_len = 0; if (interface_number) *interface_number = 0; + if (r_idev) + *r_idev = NULL; + if (r_fd) + *r_fd = -1; /* See whether we want scan or find mode. */ if (scan_mode) @@ -734,161 +964,102 @@ scan_or_find_devices (int readerno, const char *readerid, { for (dev = bus->devices; dev; dev = dev->next) { - int cfg_no; - - for (cfg_no=0; cfg_no < dev->descriptor.bNumConfigurations; cfg_no++) + if (scan_or_find_usb_device (scan_mode, &readerno, &count, &rid_list, + readerid, + dev, + r_rid, + r_dev, + &idev, + ifcdesc_extra, + ifcdesc_extra_len, + interface_number, + ep_bulk_out, ep_bulk_in, ep_intr)) { - struct usb_config_descriptor *config = dev->config + cfg_no; - int ifc_no; - - if(!config) - continue; - - for (ifc_no=0; ifc_no < config->bNumInterfaces; ifc_no++) + /* Found requested device or out of core. */ + if (!idev) { - struct usb_interface *interface - = config->interface + ifc_no; - int set_no; - - if (!interface) - continue; - - for (set_no=0; set_no < interface->num_altsetting; set_no++) - { - struct usb_interface_descriptor *ifcdesc - = interface->altsetting + set_no; - char *rid; - - /* The second condition is for some SCM Micro - SPR 532 which does not know about the - assigned CCID class. Instead of trying to - interpret the strings we simply look at the - product ID. */ - if (ifcdesc && ifcdesc->extra - && ( (ifcdesc->bInterfaceClass == 11 - && ifcdesc->bInterfaceSubClass == 0 - && ifcdesc->bInterfaceProtocol == 0) - || (ifcdesc->bInterfaceClass == 255 - && dev->descriptor.idVendor == 0x04e6 - && dev->descriptor.idProduct == 0xe003))) - { - idev = usb_open (dev); - if (!idev) - { - DEBUGOUT_1 ("usb_open failed: %s\n", - strerror (errno)); - continue; - } - - rid = make_reader_id (idev, - dev->descriptor.idVendor, - dev->descriptor.idProduct, - dev->descriptor.iSerialNumber); - if (rid) - { - if (scan_mode) - { - char *p; - - /* We are collecting infos about all - available CCID readers. Store - them and continue. */ - DEBUGOUT_2 ("found CCID reader %d " - "(ID=%s)\n", - count, rid ); - if ((p = malloc ((rid_list? - strlen (rid_list):0) - + 1 + strlen (rid) - + 1))) - { - *p = 0; - if (rid_list) - { - strcat (p, rid_list); - free (rid_list); - } - strcat (p, rid); - strcat (p, "\n"); - rid_list = p; - } - else /* Out of memory. */ - free (rid); - rid = NULL; - count++; - } - else if (!readerno - || (readerno < 0 - && readerid - && !strcmp (readerid, rid))) - { - /* We found the requested reader. */ - if (ifcdesc_extra && ifcdesc_extra_len) - { - *ifcdesc_extra = malloc (ifcdesc - ->extralen); - if (!*ifcdesc_extra) - { - usb_close (idev); - free (rid); - return NULL; /* Out of core. */ - } - memcpy (*ifcdesc_extra, ifcdesc->extra, - ifcdesc->extralen); - *ifcdesc_extra_len = ifcdesc->extralen; - } - if (interface_number) - *interface_number = (ifcdesc-> - bInterfaceNumber); - if (ep_bulk_out) - *ep_bulk_out = find_endpoint (ifcdesc, 0); - if (ep_bulk_in) - *ep_bulk_in = find_endpoint (ifcdesc, 1); - if (ep_intr) - *ep_intr = find_endpoint (ifcdesc, 2); - - - if (r_dev) - *r_dev = dev; - if (r_rid) - { - *r_rid = rid; - rid = NULL; - } - else - free (rid); - return idev; /* READY. */ - } - else - { - /* This is not yet the reader we - want. fixme: We could avoid the - extra usb_open in this case. */ - if (readerno >= 0) - readerno--; - } - free (rid); - } - - usb_close (idev); - idev = NULL; - goto next_device; - } - } + free (rid_list); + return -1; /* error */ } + *r_idev = idev; + return 0; } - next_device: - ; } } - if (scan_mode) - *r_rid = rid_list; + /* Now check whether there are any devices with special transport types. */ + for (i=0; transports[i].name; i++) + { + int fd; + char *rid, *p; + + fd = open (transports[i].name, O_RDWR); + if (fd == -1) + continue; + + rid = malloc (strlen (transports[i].name) + 30 + 10); + if (!rid) + { + close (fd); + free (rid_list); + return -1; /* Error. */ + } + sprintf (rid, "0000:%04X:%s:0", transports[i].type, transports[i].name); + if (scan_mode) + { + DEBUGOUT_2 ("found CCID reader %d (ID=%s)\n", count, rid); + p = malloc ((rid_list? strlen (rid_list):0) + 1 + strlen (rid) + 1); + if (!p) + { + close (fd); + free (rid_list); + free (rid); + return -1; /* Error. */ + } + *p = 0; + if (rid_list) + { + strcat (p, rid_list); + free (rid_list); + } + strcat (p, rid); + strcat (p, "\n"); + rid_list = p; + ++count; + } + else if (!readerno || + (readerno < 0 && readerid && !strcmp (readerid, rid))) + { + /* Found requested device. */ + if (interface_number) + *interface_number = transports[i].type; + if (r_rid) + *r_rid = rid; + else + free (rid); + *r_fd = fd; + return 0; /* Okay, found device */ + } + else /* This is not yet the reader we want. */ + { + if (readerno >= 0) + --readerno; + } + free (rid); + close (fd); + } - return NULL; + if (scan_mode) + { + *r_rid = rid_list; + return 0; + } + else + return -1; } -/* Set the level of debugging to to usea dn return the old level. -1 +/* Set the level of debugging to LEVEL and return the old level. -1 just returns the old level. A level of 0 disables debugging, 1 enables debugging, 2 enables additional tracing of the T=1 protocol, other values are not yet defined. */ @@ -913,8 +1084,9 @@ ccid_get_reader_list (void) initialized_usb = 1; } - scan_or_find_devices (-1, NULL, &reader_list, NULL, NULL, NULL, NULL, - NULL, NULL, NULL); + if (scan_or_find_devices (-1, NULL, &reader_list, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL)) + return NULL; /* Error. */ return reader_list; } @@ -927,6 +1099,7 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid) int rc = 0; struct usb_device *dev = NULL; usb_dev_handle *idev = NULL; + int dev_fd = -1; char *rid = NULL; unsigned char *ifcdesc_extra = NULL; size_t ifcdesc_extra_len; @@ -959,10 +1132,10 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid) else readerno = 0; /* Default. */ - idev = scan_or_find_devices (readerno, readerid, &rid, &dev, - &ifcdesc_extra, &ifcdesc_extra_len, - &ifc_no, &ep_bulk_out, &ep_bulk_in, &ep_intr); - if (!idev) + if (scan_or_find_devices (readerno, readerid, &rid, &dev, + &ifcdesc_extra, &ifcdesc_extra_len, + &ifc_no, &ep_bulk_out, &ep_bulk_in, &ep_intr, + &idev, &dev_fd) ) { if (readerno == -1) DEBUGOUT_1 ("no CCID reader with ID %s\n", readerid ); @@ -980,34 +1153,52 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid) rc = CCID_DRIVER_ERR_OUT_OF_CORE; goto leave; } - (*handle)->idev = idev; (*handle)->rid = rid; - (*handle)->id_vendor = dev->descriptor.idVendor; - (*handle)->id_product = dev->descriptor.idProduct; - (*handle)->bcd_device = dev->descriptor.bcdDevice; - (*handle)->ifc_no = ifc_no; - (*handle)->ep_bulk_out = ep_bulk_out; - (*handle)->ep_bulk_in = ep_bulk_in; - (*handle)->ep_intr = ep_intr; + if (idev) /* Regular USB transport. */ + { + (*handle)->idev = idev; + (*handle)->dev_fd = -1; + (*handle)->id_vendor = dev->descriptor.idVendor; + (*handle)->id_product = dev->descriptor.idProduct; + (*handle)->bcd_device = dev->descriptor.bcdDevice; + (*handle)->ifc_no = ifc_no; + (*handle)->ep_bulk_out = ep_bulk_out; + (*handle)->ep_bulk_in = ep_bulk_in; + (*handle)->ep_intr = ep_intr; + } + else if (dev_fd != -1) /* Device transport. */ + { + (*handle)->idev = NULL; + (*handle)->dev_fd = dev_fd; + (*handle)->id_vendor = 0; /* Magic vendor for special transport. */ + (*handle)->id_product = ifc_no; /* Transport type */ + prepare_special_transport (*handle); + } + else + { + assert (!"no transport"); /* Bug. */ + } DEBUGOUT_2 ("using CCID reader %d (ID=%s)\n", readerno, rid ); - - if (parse_ccid_descriptor (*handle, ifcdesc_extra, ifcdesc_extra_len)) - { - DEBUGOUT ("device not supported\n"); - rc = CCID_DRIVER_ERR_NO_READER; - goto leave; - } - - rc = usb_claim_interface (idev, ifc_no); - if (rc) + if (idev) { - DEBUGOUT_1 ("usb_claim_interface failed: %d\n", rc); - rc = CCID_DRIVER_ERR_CARD_IO_ERROR; - goto leave; + if (parse_ccid_descriptor (*handle, ifcdesc_extra, ifcdesc_extra_len)) + { + DEBUGOUT ("device not supported\n"); + rc = CCID_DRIVER_ERR_NO_READER; + goto leave; + } + + rc = usb_claim_interface (idev, ifc_no); + if (rc) + { + DEBUGOUT_1 ("usb_claim_interface failed: %d\n", rc); + rc = CCID_DRIVER_ERR_CARD_IO_ERROR; + goto leave; + } } - + leave: free (ifcdesc_extra); if (rc) @@ -1015,6 +1206,8 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid) free (rid); if (idev) usb_close (idev); + if (dev_fd != -1) + close (dev_fd); free (*handle); *handle = NULL; } @@ -1054,6 +1247,11 @@ do_close_reader (ccid_driver_t handle) usb_close (handle->idev); handle->idev = NULL; } + if (handle->dev_fd != -1) + { + close (handle->dev_fd); + handle->dev_fd = -1; + } } @@ -1080,43 +1278,49 @@ ccid_shutdown_reader (ccid_driver_t handle) do_close_reader (handle); - idev = scan_or_find_devices (-1, handle->rid, NULL, &dev, - &ifcdesc_extra, &ifcdesc_extra_len, - &ifc_no, &ep_bulk_out, &ep_bulk_in, &ep_intr); - if (!idev) + if (scan_or_find_devices (-1, handle->rid, NULL, &dev, + &ifcdesc_extra, &ifcdesc_extra_len, + &ifc_no, &ep_bulk_out, &ep_bulk_in, &ep_intr, + &idev, NULL) || !idev) { DEBUGOUT_1 ("no CCID reader with ID %s\n", handle->rid); return CCID_DRIVER_ERR_NO_READER; } - - handle->idev = idev; - handle->ifc_no = ifc_no; - handle->ep_bulk_out = ep_bulk_out; - handle->ep_bulk_in = ep_bulk_in; - handle->ep_intr = ep_intr; - - if (parse_ccid_descriptor (handle, ifcdesc_extra, ifcdesc_extra_len)) + if (idev) { - DEBUGOUT ("device not supported\n"); - rc = CCID_DRIVER_ERR_NO_READER; - goto leave; - } - - rc = usb_claim_interface (idev, ifc_no); - if (rc) - { - DEBUGOUT_1 ("usb_claim_interface failed: %d\n", rc); - rc = CCID_DRIVER_ERR_CARD_IO_ERROR; - goto leave; + handle->idev = idev; + handle->ifc_no = ifc_no; + handle->ep_bulk_out = ep_bulk_out; + handle->ep_bulk_in = ep_bulk_in; + handle->ep_intr = ep_intr; + + if (parse_ccid_descriptor (handle, ifcdesc_extra, ifcdesc_extra_len)) + { + DEBUGOUT ("device not supported\n"); + rc = CCID_DRIVER_ERR_NO_READER; + goto leave; + } + + rc = usb_claim_interface (idev, ifc_no); + if (rc) + { + DEBUGOUT_1 ("usb_claim_interface failed: %d\n", rc); + rc = CCID_DRIVER_ERR_CARD_IO_ERROR; + goto leave; + } } - + leave: free (ifcdesc_extra); if (rc) { - usb_close (handle->idev); + if (handle->idev) + usb_close (handle->idev); handle->idev = NULL; + if (handle->dev_fd != -1) + close (handle->dev_fd); + handle->dev_fd = -1; } return rc; @@ -1147,6 +1351,31 @@ ccid_check_card_presence (ccid_driver_t handle) } +/* Write NBYTES of BUF to file descriptor FD. */ +static int +writen (int fd, const void *buf, size_t nbytes) +{ + size_t nleft = nbytes; + int nwritten; + + while (nleft > 0) + { + nwritten = write (fd, buf, nleft); + if (nwritten < 0) + { + if (errno == EINTR) + nwritten = 0; + else + return -1; + } + nleft -= nwritten; + buf = (const char*)buf + nwritten; + } + + return 0; +} + + /* Write a MSG of length MSGLEN to the designated bulk out endpoint. Returns 0 on success. */ static int @@ -1154,17 +1383,28 @@ bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen) { int rc; - rc = usb_bulk_write (handle->idev, - handle->ep_bulk_out, - (char*)msg, msglen, - 1000 /* ms timeout */); - if (rc == msglen) - return 0; - - if (rc == -1) - DEBUGOUT_1 ("usb_bulk_write error: %s\n", strerror (errno)); + if (handle->idev) + { + rc = usb_bulk_write (handle->idev, + handle->ep_bulk_out, + (char*)msg, msglen, + 1000 /* ms timeout */); + if (rc == msglen) + return 0; + if (rc == -1) + DEBUGOUT_1 ("usb_bulk_write error: %s\n", strerror (errno)); + else + DEBUGOUT_1 ("usb_bulk_write failed: %d\n", rc); + } else - DEBUGOUT_1 ("usb_bulk_write failed: %d\n", rc); + { + rc = writen (handle->dev_fd, msg, msglen); + if (!rc) + return 0; + DEBUGOUT_2 ("writen to %d failed: %s\n", + handle->dev_fd, strerror (errno)); + + } return CCID_DRIVER_ERR_CARD_IO_ERROR; } @@ -1187,17 +1427,31 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length, for USB IOCTLs. */ memset (buffer, 0, length); retry: - rc = usb_bulk_read (handle->idev, - handle->ep_bulk_in, - (char*)buffer, length, - timeout); - if (rc < 0) + if (handle->idev) { - DEBUGOUT_1 ("usb_bulk_read error: %s\n", strerror (errno)); - return CCID_DRIVER_ERR_CARD_IO_ERROR; + rc = usb_bulk_read (handle->idev, + handle->ep_bulk_in, + (char*)buffer, length, + timeout); + if (rc < 0) + { + DEBUGOUT_1 ("usb_bulk_read error: %s\n", strerror (errno)); + return CCID_DRIVER_ERR_CARD_IO_ERROR; + } + *nread = msglen = rc; + } + else + { + rc = read (handle->dev_fd, buffer, length); + if (rc < 0) + { + DEBUGOUT_2 ("read from %d failed: %s\n", + handle->dev_fd, strerror (errno)); + return CCID_DRIVER_ERR_CARD_IO_ERROR; + } + *nread = msglen = rc; } - *nread = msglen = rc; if (msglen < 10) { @@ -1339,11 +1593,16 @@ ccid_poll (ccid_driver_t handle) size_t msglen; int i, j; - rc = usb_bulk_read (handle->idev, - handle->ep_intr, - (char*)msg, sizeof msg, - 0 /* ms timeout */ ); - if (rc < 0 && errno == ETIMEDOUT) + if (handle->idev) + { + rc = usb_bulk_read (handle->idev, + handle->ep_intr, + (char*)msg, sizeof msg, + 0 /* ms timeout */ ); + if (rc < 0 && errno == ETIMEDOUT) + return 0; + } + else return 0; if (rc < 0) -- cgit From c664309a0a9c2cd0aa0b1e10b488818ae7496f60 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 11 Apr 2006 13:53:21 +0000 Subject: Added command APDU --- doc/scdaemon.texi | 46 ++++++++++++++++++++ scd/ChangeLog | 9 ++++ scd/apdu.c | 4 +- scd/app-openpgp.c | 4 +- scd/command.c | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ scd/scdaemon.c | 2 + 6 files changed, 189 insertions(+), 4 deletions(-) (limited to 'scd/app-openpgp.c') diff --git a/doc/scdaemon.texi b/doc/scdaemon.texi index 24a22355e..847001669 100644 --- a/doc/scdaemon.texi +++ b/doc/scdaemon.texi @@ -347,6 +347,8 @@ syncronizing access to a token between sessions. * Scdaemon RANDOM:: Return random bytes generate on-card. * Scdaemon PASSWD:: Change PINs. * Scdaemon CHECKPIN:: Perform a VERIFY operation. +* Scdaemon RESTART:: Restart connection +* Scdaemon APDU:: Send a verbatim APDU to the card @end menu @node Scdaemon SERIALNO @@ -553,3 +555,47 @@ and only if the retry counter is still at 3. @end table + +@node Scdaemon RESTART +@subsection Perform a RESTART operation. + +@example + RESTART +@end example + +Restart the current connection; this is a kind of warm reset. It +deletes the context used by this connection but does not actually +reset the card. + +This is used by gpg-agent to reuse a primary pipe connection and +may be used by clients to backup from a conflict in the serial +command; i.e. to select another application. + + + + +@node Scdaemon APDU +@subsection Send a verbatim APDU to the card. + +@example + APDU [--atr] [--more] [@var{hexstring}] +@end example + + +Send an APDU to the current reader. This command bypasses the high +level functions and sends the data directly to the card. +@var{hexstring} is expected to be a proper APDU. If @var{hexstring} is +not given no commands are send to the card; However the command will +implictly check whether the card is ready for use. + +Using the option @code{--atr} returns the ATR of the card as a status +message before any data like this: +@example + S CARD-ATR 3BFA1300FF813180450031C173C00100009000B1 +@end example + +Using the option @code{--more} handles the card status word MORE_DATA +(61xx) and concatenate all reponses to one block. + + + diff --git a/scd/ChangeLog b/scd/ChangeLog index 27c362d10..53ef676f9 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,12 @@ +2006-04-11 Werner Koch + + * command.c (hex_to_buffer): New. + (cmd_apdu): New. + +2006-04-03 Werner Koch + + * scdaemon.c [__GLIBC__]: Default to libpcsclite.so.1. + 2006-03-21 Werner Koch * command.c (cmd_pksign): Add --hash option. diff --git a/scd/apdu.c b/scd/apdu.c index adaaec612..d6bbdefd5 100644 --- a/scd/apdu.c +++ b/scd/apdu.c @@ -2848,8 +2848,8 @@ apdu_send_simple_kp (int slot, int class, int ins, int p0, int p1, HANDLE_MORE set to true this function will handle the MORE DATA status and return all APDUs concatenated with one status word at the end. The function does not return a regular status word but 0 - on success. If the slot is locked, the fucntion returns - immediately.*/ + on success. If the slot is locked, the function returns + immediately with an error. */ int apdu_send_direct (int slot, const unsigned char *apdudata, size_t apdudatalen, int handle_more, diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index fff709a08..5e9281a38 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -112,8 +112,8 @@ struct app_local_s { encoded S-expression encoding a public key. Might be NULL if key is not available. */ - size_t keylen; /* The length of the above S-expression. Thsi - is usullay only required for corss checks + size_t keylen; /* The length of the above S-expression. This + is usullay only required for cross checks because the length of an S-expression is implicitly available. */ } pk[3]; diff --git a/scd/command.c b/scd/command.c index 70a426959..2ed685587 100644 --- a/scd/command.c +++ b/scd/command.c @@ -156,6 +156,38 @@ has_option (const char *line, const char *name) } +/* Convert the STRING into a newly allocated buffer while translating + the hex numbers. Stops at the first invalid character. Blanks and + colons are allowed to separate the hex digits. Returns NULL on + error or a newly malloced buffer and its length in LENGTH. */ +static unsigned char * +hex_to_buffer (const char *string, size_t *r_length) +{ + unsigned char *buffer; + const char *s; + size_t n; + + buffer = xtrymalloc (strlen (string)+1); + if (!buffer) + return NULL; + for (s=string, n=0; *s; s++) + { + if (spacep (s) || *s == ':') + continue; + if (hexdigitp (s) && hexdigitp (s+1)) + { + buffer[n++] = xtoi_2 (s); + s++; + } + else + break; + } + *r_length = n; + return buffer; +} + + + /* Reset the card and free the application context. With SEND_RESET set to true actually send a RESET to the reader. */ static void @@ -1372,6 +1404,101 @@ cmd_restart (assuan_context_t ctx, char *line) } +/* APDU [--atr] [--more] [hexstring] + + Send an APDU to the current reader. This command bypasses the high + level functions and sends the data directly to the card. HEXSTRING + is expected to be a proper APDU. If HEXSTRING is not given no + commands are set to the card but the command will implictly check + whether the card is ready for use. + + Using the option "--atr" returns the ATR of the card as a status + message before any data like this: + S CARD-ATR 3BFA1300FF813180450031C173C00100009000B1 + + Using the option --more handles the card status word MORE_DATA + (61xx) and concatenate all reponses to one block. + + */ +static int +cmd_apdu (assuan_context_t ctx, char *line) +{ + ctrl_t ctrl = assuan_get_pointer (ctx); + int rc; + int rc_is_assuan = 0; + unsigned char *apdu; + size_t apdulen; + int with_atr; + int handle_more; + + with_atr = has_option (line, "--atr"); + handle_more = has_option (line, "--more"); + + /* Skip over options. */ + while ( *line == '-' && line[1] == '-' ) + { + while (*line && !spacep (line)) + line++; + while (spacep (line)) + line++; + } + + if ( IS_LOCKED (ctrl) ) + return gpg_error (GPG_ERR_LOCKED); + + if ((rc = open_card (ctrl, NULL))) + return rc; + + if (with_atr) + { + unsigned char *atr; + size_t atrlen; + int i; + char hexbuf[400]; + + atr = apdu_get_atr (ctrl->reader_slot, &atrlen); + if (!atr || atrlen > sizeof hexbuf - 2 ) + { + rc = gpg_error (GPG_ERR_INV_CARD); + goto leave; + } + for (i=0; i < atrlen; i++) + sprintf (hexbuf+2*i, "%02X", atr[i]); + xfree (atr); + send_status_info (ctrl, "CARD-ATR", hexbuf, strlen (hexbuf), NULL, 0); + } + + apdu = hex_to_buffer (line, &apdulen); + if (!apdu) + { + rc = gpg_error_from_errno (errno); + goto leave; + } + if (apdulen) + { + unsigned char *result = NULL; + size_t resultlen; + + rc = apdu_send_direct (ctrl->reader_slot, apdu, apdulen, handle_more, + &result, &resultlen); + if (rc) + log_error ("apdu_send_direct failed: %s\n", gpg_strerror (rc)); + else + { + rc_is_assuan = 1; + rc = assuan_send_data (ctx, result, resultlen); + xfree (result); + } + } + xfree (apdu); + + leave: + TEST_CARD_REMOVAL (ctrl, rc); + return rc_is_assuan? rc : map_to_assuan_status (rc); +} + + + /* Tell the assuan library about our commands */ @@ -1403,6 +1530,7 @@ register_commands (assuan_context_t ctx) { "UNLOCK", cmd_unlock }, { "GETINFO", cmd_getinfo }, { "RESTART", cmd_restart }, + { "APDU", cmd_apdu }, { NULL } }; int i, rc; diff --git a/scd/scdaemon.c b/scd/scdaemon.c index 56c0d7600..e24b42132 100644 --- a/scd/scdaemon.c +++ b/scd/scdaemon.c @@ -139,6 +139,8 @@ static ARGPARSE_OPTS opts[] = { /* The card dirver we use by default for PC/SC. */ #if defined(HAVE_W32_SYSTEM) || defined(__CYGWIN__) #define DEFAULT_PCSC_DRIVER "winscard.dll" +#elif defined(__GLIBC__) +#define DEFAULT_PCSC_DRIVER "libpcsclite.so.1" #else #define DEFAULT_PCSC_DRIVER "libpcsclite.so" #endif -- cgit From f98537733ac96fd7e786286944fd3c2696229c4f Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 20 Jun 2006 17:21:37 +0000 Subject: Updated FSF's address. --- Makefile.am | 3 ++- NEWS | 3 +++ TODO | 5 ++--- agent/Makefile.am | 3 ++- agent/agent.h | 3 ++- agent/cache.c | 3 ++- agent/call-scd.c | 3 ++- agent/command-ssh.c | 4 ++-- agent/command.c | 3 ++- agent/divert-scd.c | 3 ++- agent/findkey.c | 3 ++- agent/genkey.c | 3 ++- agent/gpg-agent.c | 3 ++- agent/learncard.c | 3 ++- agent/minip12.c | 3 ++- agent/minip12.h | 3 ++- agent/pkdecrypt.c | 3 ++- agent/pksign.c | 3 ++- agent/preset-passphrase.c | 3 ++- agent/protect-tool.c | 3 ++- agent/protect.c | 3 ++- agent/query.c | 3 ++- agent/t-protect.c | 3 ++- agent/trans.c | 3 ++- agent/trustlist.c | 3 ++- am/cmacros.am | 3 ++- common/Makefile.am | 3 ++- common/asshelp.c | 3 ++- common/asshelp.h | 3 ++- common/b64enc.c | 3 ++- common/dynload.h | 3 ++- common/errors.h | 3 ++- common/estream.c | 37 +++++++++++++++++++------------------ common/estream.h | 37 +++++++++++++++++++------------------ common/exechelp.c | 3 ++- common/exechelp.h | 3 ++- common/gettime.c | 3 ++- common/homedir.c | 3 ++- common/i18n.h | 3 ++- common/iobuf.c | 3 ++- common/iobuf.h | 3 ++- common/isascii.c | 3 ++- common/maperror.c | 3 ++- common/membuf.c | 3 ++- common/membuf.h | 3 ++- common/miscellaneous.c | 3 ++- common/mkerrors | 3 ++- common/mkerrtok | 3 ++- common/sexp-parse.h | 3 ++- common/sexputil.c | 3 ++- common/signal.c | 3 ++- common/simple-gettext.c | 3 ++- common/simple-pwquery.c | 3 ++- common/simple-pwquery.h | 3 ++- common/sysutils.c | 3 ++- common/sysutils.h | 3 ++- common/ttyio.c | 3 ++- common/ttyio.h | 3 ++- common/util.h | 3 ++- common/vasprintf.c | 4 ++-- common/w32reg.c | 3 ++- common/xasprintf.c | 3 ++- common/xreadline.c | 3 ++- common/yesno.c | 3 ++- configure.ac | 3 ++- doc/Makefile.am | 3 ++- doc/gnupg-card-architecture.fig | 3 ++- g10/Makefile.am | 3 ++- g10/call-agent.c | 3 ++- g10/call-agent.h | 3 ++- g10/comment.c | 3 ++- g10/gpg.c | 9 +++++++++ g10/gpg.h | 3 ++- g10/pkglue.c | 3 ++- g10/pkglue.h | 3 ++- include/_regex.h | 4 ++-- include/errors.h | 3 ++- include/memory.h | 3 ++- include/mpi.h | 3 ++- include/util.h | 3 ++- jnlib/Makefile.am | 3 ++- jnlib/argparse.c | 30 ++++++++++++++++-------------- jnlib/argparse.h | 3 ++- jnlib/dotlock.c | 3 ++- jnlib/dotlock.h | 3 ++- jnlib/libjnlib-config.h | 3 ++- jnlib/logging.c | 3 ++- jnlib/logging.h | 3 ++- jnlib/mischelp.h | 3 ++- jnlib/stringhelp.c | 3 ++- jnlib/stringhelp.h | 3 ++- jnlib/strlist.c | 3 ++- jnlib/strlist.h | 3 ++- jnlib/types.h | 3 ++- jnlib/utf8conv.c | 3 ++- jnlib/utf8conv.h | 3 ++- jnlib/w32-afunix.c | 3 ++- jnlib/w32-afunix.h | 3 ++- jnlib/w32-pth.c | 3 ++- jnlib/w32-pth.h | 3 ++- jnlib/xmalloc.c | 3 ++- jnlib/xmalloc.h | 3 ++- kbx/Makefile.am | 3 ++- kbx/kbxutil.c | 3 ++- kbx/keybox-blob.c | 3 ++- kbx/keybox-defs.h | 3 ++- kbx/keybox-dump.c | 3 ++- kbx/keybox-file.c | 3 ++- kbx/keybox-init.c | 3 ++- kbx/keybox-openpgp.c | 3 ++- kbx/keybox-search-desc.h | 3 ++- kbx/keybox-search.c | 3 ++- kbx/keybox-update.c | 3 ++- kbx/keybox-util.c | 3 ++- kbx/keybox.h | 3 ++- kbx/mkerrors | 3 ++- scd/Makefile.am | 3 ++- scd/app-common.h | 3 ++- scd/app-dinsig.c | 3 ++- scd/app-help.c | 3 ++- scd/app-nks.c | 3 ++- scd/app-openpgp.c | 3 ++- scd/app-p15.c | 3 ++- scd/app.c | 3 ++- scd/atr.c | 3 ++- scd/atr.h | 3 ++- scd/card-common.h | 3 ++- scd/card-dinsig.c | 3 ++- scd/card-p15.c | 3 ++- scd/card.c | 3 ++- scd/command.c | 3 ++- scd/sc-copykeys.c | 3 ++- scd/scdaemon.c | 3 ++- scd/scdaemon.h | 3 ++- scd/tlv.c | 3 ++- scd/tlv.h | 3 ++- scripts/compile | 3 ++- scripts/config.guess | 3 ++- sm/ChangeLog | 7 +++++++ sm/Makefile.am | 3 ++- sm/base64.c | 3 ++- sm/call-agent.c | 3 ++- sm/call-dirmngr.c | 3 ++- sm/certchain.c | 3 ++- sm/certcheck.c | 3 ++- sm/certdump.c | 3 ++- sm/certlist.c | 3 ++- sm/certreqgen.c | 3 ++- sm/decrypt.c | 3 ++- sm/delete.c | 3 ++- sm/encrypt.c | 3 ++- sm/export.c | 3 ++- sm/fingerprint.c | 3 ++- sm/gpgsm.c | 16 ++++++++++++---- sm/gpgsm.h | 3 ++- sm/import.c | 3 ++- sm/keydb.c | 3 ++- sm/keydb.h | 3 ++- sm/keylist.c | 7 ++++++- sm/misc.c | 3 ++- sm/qualified.c | 3 ++- sm/server.c | 3 ++- sm/sign.c | 3 ++- sm/verify.c | 3 ++- tests/Makefile.am | 3 ++- tests/asschk.c | 3 ++- tests/pkits/Makefile.am | 3 ++- tests/pkits/common.sh | 3 ++- tests/pkits/import-all-certs | 3 ++- tests/pkits/validate-all-certs | 3 ++- tools/Makefile.am | 3 ++- tools/gpg-connect-agent.c | 3 ++- tools/gpgconf-comp.c | 36 +++++++++++++++++++----------------- tools/gpgconf.c | 3 ++- tools/gpgconf.h | 3 ++- tools/gpgkey2ssh.c | 37 +++++++++++++++++++------------------ tools/gpgparsemail.c | 3 ++- tools/no-libgcrypt.c | 3 ++- tools/symcryptrun.c | 3 ++- tools/watchgnupg.c | 3 ++- 180 files changed, 469 insertions(+), 265 deletions(-) (limited to 'scd/app-openpgp.c') diff --git a/Makefile.am b/Makefile.am index 9fafb1102..0c5fbe4c3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -15,7 +15,8 @@ # # 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 +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +# USA. ## Process this file with automake to produce Makefile.in diff --git a/NEWS b/NEWS index 6413242c6..679bf7d5b 100644 --- a/NEWS +++ b/NEWS @@ -15,6 +15,9 @@ Noteworthy changes in version 1.9.21 * [scdaemon] Added --hash=xxx option to the PKSIGN command. + * [gpg-protect-tool] Does now create a MAC for P12 files. This is for + better interoperability. + Noteworthy changes in version 1.9.20 (2005-12-20) ------------------------------------------------- diff --git a/TODO b/TODO index 7958ed18e..da3a76e06 100644 --- a/TODO +++ b/TODO @@ -21,7 +21,7 @@ might want to have an agent context for each service request ** When a certificate chain was sucessfully verified, make ephemeral certs used in this chain permanent. ** Try to keep certificate references somewhere This will help with some of our caching code. We also need to test - that cachining; in particular "regtp_ca_chainlen". + that caching; in particular "regtp_ca_chainlen". * sm/decrypt.c ** replace leading zero in integer hack by a cleaner solution @@ -101,7 +101,6 @@ might want to have an agent context for each service request * sm/ -** --include-certs is as of now still a dummy command line option ** check that we issue NO_SECKEY xxx if a -u key was not found * gpg/ @@ -117,4 +116,4 @@ might want to have an agent context for each service request ** ttyio Add completion support. ** yesno - Update to gpg 1.4.3 version \ No newline at end of file + Update to gpg 1.4.3 version diff --git a/agent/Makefile.am b/agent/Makefile.am index bc96531e0..961f0bb97 100644 --- a/agent/Makefile.am +++ b/agent/Makefile.am @@ -14,7 +14,8 @@ # # 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 +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +# USA. ## Process this file with automake to produce Makefile.in diff --git a/agent/agent.h b/agent/agent.h index 1542d6b9f..fdfe510fb 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifndef AGENT_H diff --git a/agent/cache.c b/agent/cache.c index 32b6ac0c7..2f468396d 100644 --- a/agent/cache.c +++ b/agent/cache.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/agent/call-scd.c b/agent/call-scd.c index ff241ce41..d0d24f9d5 100644 --- a/agent/call-scd.c +++ b/agent/call-scd.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/agent/command-ssh.c b/agent/command-ssh.c index 23f083c2f..18375a9ae 100644 --- a/agent/command-ssh.c +++ b/agent/command-ssh.c @@ -15,8 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ /* Only v2 of the ssh-agent protocol is implemented. */ diff --git a/agent/command.c b/agent/command.c index daf9b8698..12770dac8 100644 --- a/agent/command.c +++ b/agent/command.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ /* FIXME: we should not use the default assuan buffering but setup diff --git a/agent/divert-scd.c b/agent/divert-scd.c index 926df2622..3dc7984e6 100644 --- a/agent/divert-scd.c +++ b/agent/divert-scd.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/agent/findkey.c b/agent/findkey.c index 73ffb530d..3f793e5dd 100644 --- a/agent/findkey.c +++ b/agent/findkey.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/agent/genkey.c b/agent/genkey.c index d0319f7b4..04ee865f4 100644 --- a/agent/genkey.c +++ b/agent/genkey.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c index 22bd5589d..fc2a2001a 100644 --- a/agent/gpg-agent.c +++ b/agent/gpg-agent.c @@ -16,7 +16,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/agent/learncard.c b/agent/learncard.c index 72238507f..8ddf4ee54 100644 --- a/agent/learncard.c +++ b/agent/learncard.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/agent/minip12.c b/agent/minip12.c index 6f99bf24d..912d387d8 100644 --- a/agent/minip12.c +++ b/agent/minip12.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifdef HAVE_CONFIG_H diff --git a/agent/minip12.h b/agent/minip12.h index 2fbb490d7..6275f9ccb 100644 --- a/agent/minip12.h +++ b/agent/minip12.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifndef MINIP12_H diff --git a/agent/pkdecrypt.c b/agent/pkdecrypt.c index 1d64c1b15..f61f0f844 100644 --- a/agent/pkdecrypt.c +++ b/agent/pkdecrypt.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/agent/pksign.c b/agent/pksign.c index e9df19351..9863f9de0 100644 --- a/agent/pksign.c +++ b/agent/pksign.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/agent/preset-passphrase.c b/agent/preset-passphrase.c index 6a9f07a3e..013c9411d 100644 --- a/agent/preset-passphrase.c +++ b/agent/preset-passphrase.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/agent/protect-tool.c b/agent/protect-tool.c index 5f59d5e06..bb14ca1e1 100644 --- a/agent/protect-tool.c +++ b/agent/protect-tool.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/agent/protect.c b/agent/protect.c index 45bdae496..19f6ccbc6 100644 --- a/agent/protect.c +++ b/agent/protect.c @@ -16,7 +16,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/agent/query.c b/agent/query.c index a5a3d0153..0516bec03 100644 --- a/agent/query.c +++ b/agent/query.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/agent/t-protect.c b/agent/t-protect.c index fee3c561d..9ddd49414 100644 --- a/agent/t-protect.c +++ b/agent/t-protect.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/agent/trans.c b/agent/trans.c index 7fa5e3d6b..5eb7d25c0 100644 --- a/agent/trans.c +++ b/agent/trans.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ /* To avoid any problems with the gettext implementation (there used diff --git a/agent/trustlist.c b/agent/trustlist.c index edb00650d..d234af692 100644 --- a/agent/trustlist.c +++ b/agent/trustlist.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/am/cmacros.am b/am/cmacros.am index de68b6f31..7b449e2c0 100644 --- a/am/cmacros.am +++ b/am/cmacros.am @@ -15,7 +15,8 @@ # # 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 +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +# USA. localedir = $(datadir)/locale diff --git a/common/Makefile.am b/common/Makefile.am index 34819e93f..085440bb3 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -15,7 +15,8 @@ # # 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 +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +# USA. ## Process this file with automake to produce Makefile.in diff --git a/common/asshelp.c b/common/asshelp.c index 0edaeae0e..1da899522 100644 --- a/common/asshelp.c +++ b/common/asshelp.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/common/asshelp.h b/common/asshelp.h index 2d6dc79e6..9f4b5806b 100644 --- a/common/asshelp.h +++ b/common/asshelp.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifndef GNUPG_COMMON_ASSHELP_H diff --git a/common/b64enc.c b/common/b64enc.c index 5b7a42ab3..bfc49deb6 100644 --- a/common/b64enc.c +++ b/common/b64enc.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/common/dynload.h b/common/dynload.h index 2c074141f..9b67fa9ed 100644 --- a/common/dynload.h +++ b/common/dynload.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifndef GNUPG_DYNLOAD_H diff --git a/common/errors.h b/common/errors.h index f34f3ba79..131891f65 100644 --- a/common/errors.h +++ b/common/errors.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifndef GNUPG_COMMON_ERRORS_H diff --git a/common/estream.c b/common/estream.c index 70b3d9c6e..c2030371b 100644 --- a/common/estream.c +++ b/common/estream.c @@ -1,22 +1,23 @@ /* estream.c - Extended stream I/O/ Library - Copyright (C) 2004 g10 Code GmbH - - This file is part of Libestream. - - Libestream 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. - - Libestream 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Libestream; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - 02111-1307, USA. */ + * Copyright (C) 2004 g10 Code GmbH + * + * This file is part of Libestream. + * + * Libestream 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. + * + * Libestream 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Libestream; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ #ifdef USE_ESTREAM_SUPPORT_H # include diff --git a/common/estream.h b/common/estream.h index ebe575926..a9b4847c8 100644 --- a/common/estream.h +++ b/common/estream.h @@ -1,22 +1,23 @@ /* estream.h - Extended stream I/O/ Library - Copyright (C) 2004 g10 Code GmbH - - This file is part of Libestream. - - Libestream 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. - - Libestream 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Libestream; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - 02111-1307, USA. */ + * Copyright (C) 2004 g10 Code GmbH + * + * This file is part of Libestream. + * + * Libestream 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. + * + * Libestream 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Libestream; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ #ifndef ESTREAM_H #define ESTREAM_H diff --git a/common/exechelp.c b/common/exechelp.c index dc0a6b0e1..e64b69022 100644 --- a/common/exechelp.c +++ b/common/exechelp.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/common/exechelp.h b/common/exechelp.h index f00d18dd8..1df029b7e 100644 --- a/common/exechelp.h +++ b/common/exechelp.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifndef GNUPG_COMMON_EXECHELP_H diff --git a/common/gettime.c b/common/gettime.c index ecdc7df95..c4ea3283a 100644 --- a/common/gettime.c +++ b/common/gettime.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/common/homedir.c b/common/homedir.c index a118cbac1..39d6dce20 100644 --- a/common/homedir.c +++ b/common/homedir.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/common/i18n.h b/common/i18n.h index 0e13dca4d..0187ba265 100644 --- a/common/i18n.h +++ b/common/i18n.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifndef GNUPG_COMMON_I18N_H diff --git a/common/iobuf.c b/common/iobuf.c index bbb666f67..8f7374f8c 100644 --- a/common/iobuf.c +++ b/common/iobuf.c @@ -16,7 +16,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/common/iobuf.h b/common/iobuf.h index 3b8f4b572..a3dd7f1c5 100644 --- a/common/iobuf.h +++ b/common/iobuf.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifndef GNUPG_COMMON_IOBUF_H diff --git a/common/isascii.c b/common/isascii.c index 565c71664..b71febe99 100644 --- a/common/isascii.c +++ b/common/isascii.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifdef HAVE_CONFIG_H diff --git a/common/maperror.c b/common/maperror.c index 9efd64338..06546b501 100644 --- a/common/maperror.c +++ b/common/maperror.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/common/membuf.c b/common/membuf.c index 75f6bdb2a..2d35fefab 100644 --- a/common/membuf.c +++ b/common/membuf.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/common/membuf.h b/common/membuf.h index c199363cc..9033be61e 100644 --- a/common/membuf.h +++ b/common/membuf.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifndef GNUPG_COMMON_MEMBUF_H diff --git a/common/miscellaneous.c b/common/miscellaneous.c index e9f8ed27f..da74f65bc 100644 --- a/common/miscellaneous.c +++ b/common/miscellaneous.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/common/mkerrors b/common/mkerrors index 5a1ef33da..994c61352 100755 --- a/common/mkerrors +++ b/common/mkerrors @@ -17,7 +17,8 @@ # # 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 +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +# USA. cat < diff --git a/common/simple-gettext.c b/common/simple-gettext.c index b6b851c77..56a305fd8 100644 --- a/common/simple-gettext.c +++ b/common/simple-gettext.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ /* This is a simplified version of gettext written by Ulrich Drepper. diff --git a/common/simple-pwquery.c b/common/simple-pwquery.c index f156ca3f1..e405c1ec0 100644 --- a/common/simple-pwquery.c +++ b/common/simple-pwquery.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ /* This module is intended as a standalone client implementation to diff --git a/common/simple-pwquery.h b/common/simple-pwquery.h index e3270d6c5..5b941d06f 100644 --- a/common/simple-pwquery.h +++ b/common/simple-pwquery.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifndef SIMPLE_PWQUERY_H diff --git a/common/sysutils.c b/common/sysutils.c index a8f6f6f5d..3e52cdaa3 100644 --- a/common/sysutils.c +++ b/common/sysutils.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/common/sysutils.h b/common/sysutils.h index 08198f685..c40dbfaa9 100644 --- a/common/sysutils.h +++ b/common/sysutils.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifndef GNUPG_COMMON_SYSUTILS_H diff --git a/common/ttyio.c b/common/ttyio.c index c9f41c626..38883afa5 100644 --- a/common/ttyio.c +++ b/common/ttyio.c @@ -16,7 +16,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/common/ttyio.h b/common/ttyio.h index 6148d644a..32d159863 100644 --- a/common/ttyio.h +++ b/common/ttyio.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifndef GNUPG_COMMON_TTYIO_H #define GNUPG_COMMON_TTYIO_H diff --git a/common/util.h b/common/util.h index 295d785c5..29106bf9c 100644 --- a/common/util.h +++ b/common/util.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifndef GNUPG_COMMON_UTIL_H diff --git a/common/vasprintf.c b/common/vasprintf.c index 9efea33f2..4bed8de66 100644 --- a/common/vasprintf.c +++ b/common/vasprintf.c @@ -15,8 +15,8 @@ Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with libiberty; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +not, write to the Free Software Foundation, Inc., 51 Franklin Street, +Fifth Floor, Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H #include diff --git a/common/w32reg.c b/common/w32reg.c index a85ac7348..84308e916 100644 --- a/common/w32reg.c +++ b/common/w32reg.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/common/xasprintf.c b/common/xasprintf.c index 46740a2e6..75ae18072 100644 --- a/common/xasprintf.c +++ b/common/xasprintf.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/common/xreadline.c b/common/xreadline.c index 23aa35269..8400df330 100644 --- a/common/xreadline.c +++ b/common/xreadline.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/common/yesno.c b/common/yesno.c index 737071691..9ca513740 100644 --- a/common/yesno.c +++ b/common/yesno.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/configure.ac b/configure.ac index f3066a0a9..d77093a63 100644 --- a/configure.ac +++ b/configure.ac @@ -16,7 +16,8 @@ # # 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 +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +# USA. # Process this file with autoconf to produce a configure script. AC_PREREQ(2.52) diff --git a/doc/Makefile.am b/doc/Makefile.am index 47dd36208..dae053ec2 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -14,7 +14,8 @@ # # 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 +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +# USA. ## Process this file with automake to produce Makefile.in diff --git a/doc/gnupg-card-architecture.fig b/doc/gnupg-card-architecture.fig index e5772cd0f..49351c720 100644 --- a/doc/gnupg-card-architecture.fig +++ b/doc/gnupg-card-architecture.fig @@ -15,7 +15,8 @@ # # 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 +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +# USA. Landscape Center Metric diff --git a/g10/Makefile.am b/g10/Makefile.am index aeb24d7b3..fb54dd9f0 100644 --- a/g10/Makefile.am +++ b/g10/Makefile.am @@ -15,7 +15,8 @@ # # 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 +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +# USA. ## Process this file with automake to produce Makefile.in diff --git a/g10/call-agent.c b/g10/call-agent.c index 55fc62569..e3bd7ed57 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #if 0 /* let Emacs display a red warning */ diff --git a/g10/call-agent.h b/g10/call-agent.h index 71044e38b..d09b87e3a 100644 --- a/g10/call-agent.h +++ b/g10/call-agent.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifndef GNUPG_G10_CALL_AGENT_H #define GNUPG_G10_CALL_AGENT_H diff --git a/g10/comment.c b/g10/comment.c index b52104cd7..193087107 100644 --- a/g10/comment.c +++ b/g10/comment.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/g10/gpg.c b/g10/gpg.c index 52ae553c1..4235f3f7a 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -356,6 +356,7 @@ enum cmd_and_opt_values oAllowMultisigVerification, oEnableDSA2, oDisableDSA2, + oDebugAllowRun, oNoop }; @@ -701,6 +702,8 @@ static ARGPARSE_OPTS opts[] = { { oNoRequireCrossCert, "no-require-cross-certification", 0, "@"}, { oAutoKeyLocate, "auto-key-locate", 2, "@"}, { oNoAutoKeyLocate, "no-auto-key-locate", 0, "@"}, + + { oDebugAllowRun, "debug_allow_run", 0, "@"}, {0,NULL,0,NULL} }; @@ -1684,6 +1687,7 @@ main (int argc, char **argv ) int with_fpr = 0; /* make an option out of --fingerprint */ int any_explicit_recipient = 0; int require_secmem=0,got_secmem=0; + int allow_run = 0; #ifdef __riscos__ opt.lock_once = 1; @@ -2663,6 +2667,8 @@ main (int argc, char **argv ) case oEnableDSA2: opt.flags.dsa2=1; break; case oDisableDSA2: opt.flags.dsa2=0; break; + case oDebugAllowRun: allow_run = 1; break; + case oNoop: break; default : pargs.err = configfp? 1:2; break; @@ -2716,6 +2722,9 @@ main (int argc, char **argv ) } #endif + if (!allow_run) + log_fatal ("This version of gpg is not ready for use, use gpg 1.4.x\n"); + /* FIXME: We should use logging to a file only in server mode; however we have not yet implemetyed that. Thus we try to get away with --batch as indication for logging to file diff --git a/g10/gpg.h b/g10/gpg.h index 8ef46fdca..100a8e349 100644 --- a/g10/gpg.h +++ b/g10/gpg.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifndef GNUPG_G10_GPG_H #define GNUPG_G10_GPG_H diff --git a/g10/pkglue.c b/g10/pkglue.c index f062d8366..3f9669d27 100644 --- a/g10/pkglue.c +++ b/g10/pkglue.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/g10/pkglue.h b/g10/pkglue.h index 43b82785b..866960bfd 100644 --- a/g10/pkglue.h +++ b/g10/pkglue.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifndef GNUPG_G10_PKGLUE_H diff --git a/include/_regex.h b/include/_regex.h index fac441dc6..ddd002484 100644 --- a/include/_regex.h +++ b/include/_regex.h @@ -16,8 +16,8 @@ You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ + Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. */ #ifndef _REGEX_H #define _REGEX_H 1 diff --git a/include/errors.h b/include/errors.h index ed437fa99..f3269ce5b 100644 --- a/include/errors.h +++ b/include/errors.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifndef GNUPG_INCLUDE_ERRORS_H #define GNUPG_INCLUDE_ERRORS_H diff --git a/include/memory.h b/include/memory.h index 35719da62..2e2f8fdce 100644 --- a/include/memory.h +++ b/include/memory.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifndef G10_MEMORY_H diff --git a/include/mpi.h b/include/mpi.h index b732923a2..7402ef6d3 100644 --- a/include/mpi.h +++ b/include/mpi.h @@ -16,7 +16,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. * * Note: This code is heavily based on the GNU MP Library. * Actually it's the same code with only minor changes in the diff --git a/include/util.h b/include/util.h index c579c152e..1d6d01366 100644 --- a/include/util.h +++ b/include/util.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifndef G10_UTIL_H #define G10_UTIL_H diff --git a/jnlib/Makefile.am b/jnlib/Makefile.am index 69eac4bf7..5fd48495c 100644 --- a/jnlib/Makefile.am +++ b/jnlib/Makefile.am @@ -14,7 +14,8 @@ # # 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 +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +# USA. ## Process this file with automake to produce Makefile.in diff --git a/jnlib/argparse.c b/jnlib/argparse.c index 980d1186c..15a7c546e 100644 --- a/jnlib/argparse.c +++ b/jnlib/argparse.c @@ -1,21 +1,22 @@ /* [argparse.c wk 17.06.97] Argument Parser for option handling * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. * - * This file is part of GnuPG. + * 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 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. + * 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 + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include @@ -904,7 +905,7 @@ strusage( int level ) switch( level ) { case 11: p = "foo"; break; case 13: p = "0.0"; break; - case 14: p = "Copyright (C) 2005 Free Software Foundation, Inc."; break; + case 14: p = "Copyright (C) 2006 Free Software Foundation, Inc."; break; case 15: p = "This program comes with ABSOLUTELY NO WARRANTY.\n" "This is free software, and you are welcome to redistribute it\n" @@ -920,7 +921,8 @@ strusage( int level ) "GNU General Public License for more details.\n\n" "You should have received a copy of the GNU General Public License\n" "along with this program; if not, write to the Free Software\n" -"Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n"; +"Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,\n" +"USA.\n"; break; case 40: /* short and long usage */ case 41: p = ""; break; diff --git a/jnlib/argparse.h b/jnlib/argparse.h index e8922faa4..531622ea5 100644 --- a/jnlib/argparse.h +++ b/jnlib/argparse.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifndef LIBJNLIB_ARGPARSE_H diff --git a/jnlib/dotlock.c b/jnlib/dotlock.c index b7f892717..89edb7b91 100644 --- a/jnlib/dotlock.c +++ b/jnlib/dotlock.c @@ -16,7 +16,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/jnlib/dotlock.h b/jnlib/dotlock.h index 2cb39008a..1c0f05cb2 100644 --- a/jnlib/dotlock.h +++ b/jnlib/dotlock.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifndef LIBJNLIB_DOTLOCK_H diff --git a/jnlib/libjnlib-config.h b/jnlib/libjnlib-config.h index da3991432..ded6e057b 100644 --- a/jnlib/libjnlib-config.h +++ b/jnlib/libjnlib-config.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ /**************** diff --git a/jnlib/logging.c b/jnlib/logging.c index c944006a5..20ba02ccd 100644 --- a/jnlib/logging.c +++ b/jnlib/logging.c @@ -16,7 +16,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ diff --git a/jnlib/logging.h b/jnlib/logging.h index b5c0bd741..3ad43b4ec 100644 --- a/jnlib/logging.h +++ b/jnlib/logging.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifndef LIBJNLIB_LOGGING_H diff --git a/jnlib/mischelp.h b/jnlib/mischelp.h index 54da4cc1f..8e7f9c346 100644 --- a/jnlib/mischelp.h +++ b/jnlib/mischelp.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifndef LIBJNLIB_MISCHELP_H diff --git a/jnlib/stringhelp.c b/jnlib/stringhelp.c index 27b8a25e8..9df852754 100644 --- a/jnlib/stringhelp.c +++ b/jnlib/stringhelp.c @@ -16,7 +16,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/jnlib/stringhelp.h b/jnlib/stringhelp.h index 405d6dbc4..b8f4dbec0 100644 --- a/jnlib/stringhelp.h +++ b/jnlib/stringhelp.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifndef LIBJNLIB_STRINGHELP_H diff --git a/jnlib/strlist.c b/jnlib/strlist.c index 52b4d5869..87e121705 100644 --- a/jnlib/strlist.c +++ b/jnlib/strlist.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/jnlib/strlist.h b/jnlib/strlist.h index 3c1252a44..ee9f1fa60 100644 --- a/jnlib/strlist.h +++ b/jnlib/strlist.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifndef LIBJNLIB_STRLIST_H diff --git a/jnlib/types.h b/jnlib/types.h index 934b7a6ee..89d245943 100644 --- a/jnlib/types.h +++ b/jnlib/types.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifndef LIBJNLIB_TYPES_H diff --git a/jnlib/utf8conv.c b/jnlib/utf8conv.c index 4df8b7b32..9fba1ed4f 100644 --- a/jnlib/utf8conv.c +++ b/jnlib/utf8conv.c @@ -16,7 +16,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/jnlib/utf8conv.h b/jnlib/utf8conv.h index 6e2ce9944..344c47f92 100644 --- a/jnlib/utf8conv.h +++ b/jnlib/utf8conv.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifndef LIBJNLIB_UTF8CONF_H diff --git a/jnlib/w32-afunix.c b/jnlib/w32-afunix.c index c93d389da..84d799f1f 100644 --- a/jnlib/w32-afunix.c +++ b/jnlib/w32-afunix.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifdef _WIN32 #include diff --git a/jnlib/w32-afunix.h b/jnlib/w32-afunix.h index 367832299..d0eb8cf7e 100644 --- a/jnlib/w32-afunix.h +++ b/jnlib/w32-afunix.h @@ -15,7 +15,8 @@ * * You should have received a copy of the GNU Lesser 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifdef _WIN32 #ifndef W32AFUNIX_DEFS_H diff --git a/jnlib/w32-pth.c b/jnlib/w32-pth.c index 2f041c490..4107c7cb3 100644 --- a/jnlib/w32-pth.c +++ b/jnlib/w32-pth.c @@ -16,7 +16,8 @@ * * You should have received a copy of the GNU Lesser 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. * * ------------------------------------------------------------------ * This code is based on Ralf Engelschall's GNU Pth, a non-preemptive diff --git a/jnlib/w32-pth.h b/jnlib/w32-pth.h index 5ef0ab240..524010d92 100644 --- a/jnlib/w32-pth.h +++ b/jnlib/w32-pth.h @@ -16,7 +16,8 @@ * * You should have received a copy of the GNU Lesser 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. * * ------------------------------------------------------------------ * This code is based on Ralf Engelschall's GNU Pth, a non-preemptive diff --git a/jnlib/xmalloc.c b/jnlib/xmalloc.c index 1cfaab9f7..f5b92ba41 100644 --- a/jnlib/xmalloc.c +++ b/jnlib/xmalloc.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/jnlib/xmalloc.h b/jnlib/xmalloc.h index 150ef3664..8bfa7df79 100644 --- a/jnlib/xmalloc.h +++ b/jnlib/xmalloc.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifndef LIBJNLIB_XMALLOC_H diff --git a/kbx/Makefile.am b/kbx/Makefile.am index f42e517bf..063dbb4c0 100644 --- a/kbx/Makefile.am +++ b/kbx/Makefile.am @@ -15,7 +15,8 @@ # # 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 +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +# USA. ## Process this file with automake to produce Makefile.in diff --git a/kbx/kbxutil.c b/kbx/kbxutil.c index 0569b5a67..19d356007 100644 --- a/kbx/kbxutil.c +++ b/kbx/kbxutil.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/kbx/keybox-blob.c b/kbx/keybox-blob.c index eacc0014a..f3fe31617 100644 --- a/kbx/keybox-blob.c +++ b/kbx/keybox-blob.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ diff --git a/kbx/keybox-defs.h b/kbx/keybox-defs.h index 7bbed8519..ad53c71a7 100644 --- a/kbx/keybox-defs.h +++ b/kbx/keybox-defs.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifndef KEYBOX_DEFS_H diff --git a/kbx/keybox-dump.c b/kbx/keybox-dump.c index 495fb249e..d28611377 100644 --- a/kbx/keybox-dump.c +++ b/kbx/keybox-dump.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/kbx/keybox-file.c b/kbx/keybox-file.c index 3883ce607..e68e96cf9 100644 --- a/kbx/keybox-file.c +++ b/kbx/keybox-file.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/kbx/keybox-init.c b/kbx/keybox-init.c index 46a29978a..6c01b4f3a 100644 --- a/kbx/keybox-init.c +++ b/kbx/keybox-init.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/kbx/keybox-openpgp.c b/kbx/keybox-openpgp.c index 7401949c9..8ac713979 100644 --- a/kbx/keybox-openpgp.c +++ b/kbx/keybox-openpgp.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ /* This is a simple OpenPGP parser suitable for all OpenPGP key diff --git a/kbx/keybox-search-desc.h b/kbx/keybox-search-desc.h index 4be59c27d..f3a69d0f1 100644 --- a/kbx/keybox-search-desc.h +++ b/kbx/keybox-search-desc.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ /* diff --git a/kbx/keybox-search.c b/kbx/keybox-search.c index 2ce3c1923..f95e6eb06 100644 --- a/kbx/keybox-search.c +++ b/kbx/keybox-search.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/kbx/keybox-update.c b/kbx/keybox-update.c index a16c18e23..bb43d287b 100644 --- a/kbx/keybox-update.c +++ b/kbx/keybox-update.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/kbx/keybox-util.c b/kbx/keybox-util.c index ed5d93de0..6eb85ba3f 100644 --- a/kbx/keybox-util.c +++ b/kbx/keybox-util.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/kbx/keybox.h b/kbx/keybox.h index af1fc4516..0f97fb7fc 100644 --- a/kbx/keybox.h +++ b/kbx/keybox.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifndef KEYBOX_H diff --git a/kbx/mkerrors b/kbx/mkerrors index 5adb7bfdf..d3d096c5d 100755 --- a/kbx/mkerrors +++ b/kbx/mkerrors @@ -17,7 +17,8 @@ # # 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 +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +# USA. cat < diff --git a/scd/app-nks.c b/scd/app-nks.c index 73ec8ea01..1ca8d4187 100644 --- a/scd/app-nks.c +++ b/scd/app-nks.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 5e9281a38..842881f3a 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. * * $Id$ */ diff --git a/scd/app-p15.c b/scd/app-p15.c index 4203a6840..8a7732c85 100644 --- a/scd/app-p15.c +++ b/scd/app-p15.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ /* Information pertaining to the BELPIC developer card samples: diff --git a/scd/app.c b/scd/app.c index 363e386ce..e3d42054b 100644 --- a/scd/app.c +++ b/scd/app.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/scd/atr.c b/scd/atr.c index 6475e83f8..bd5a22621 100644 --- a/scd/atr.c +++ b/scd/atr.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/scd/atr.h b/scd/atr.h index 5fdd57457..c70089ca5 100644 --- a/scd/atr.h +++ b/scd/atr.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifndef ATR_H diff --git a/scd/card-common.h b/scd/card-common.h index cefaf120f..dd7529d5b 100644 --- a/scd/card-common.h +++ b/scd/card-common.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifndef CARD_COMMON_H diff --git a/scd/card-dinsig.c b/scd/card-dinsig.c index df09bfb57..d50d758f2 100644 --- a/scd/card-dinsig.c +++ b/scd/card-dinsig.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ /* The German signature law and its bylaw (SigG and SigV) is currently diff --git a/scd/card-p15.c b/scd/card-p15.c index ae3ef148f..63d537d5a 100644 --- a/scd/card-p15.c +++ b/scd/card-p15.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/scd/card.c b/scd/card.c index 9ec2a52c5..7a41ab7bb 100644 --- a/scd/card.c +++ b/scd/card.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/scd/command.c b/scd/command.c index 2ed685587..4629d9edf 100644 --- a/scd/command.c +++ b/scd/command.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/scd/sc-copykeys.c b/scd/sc-copykeys.c index 66b6894e0..395b4625a 100644 --- a/scd/sc-copykeys.c +++ b/scd/sc-copykeys.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/scd/scdaemon.c b/scd/scdaemon.c index e24b42132..b11cc7a91 100644 --- a/scd/scdaemon.c +++ b/scd/scdaemon.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/scd/scdaemon.h b/scd/scdaemon.h index abe9730a7..f9689ee09 100644 --- a/scd/scdaemon.h +++ b/scd/scdaemon.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifndef SCDAEMON_H diff --git a/scd/tlv.c b/scd/tlv.c index b436d956a..6ddbeaf1f 100644 --- a/scd/tlv.c +++ b/scd/tlv.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/scd/tlv.h b/scd/tlv.h index f587dd9df..877573d25 100644 --- a/scd/tlv.h +++ b/scd/tlv.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifndef SCD_TLV_H diff --git a/scripts/compile b/scripts/compile index ac07cc541..b6e6dcb0f 100755 --- a/scripts/compile +++ b/scripts/compile @@ -17,7 +17,8 @@ # # 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. +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +# USA.. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a diff --git a/scripts/config.guess b/scripts/config.guess index 77c7cbab0..a4929a979 100755 --- a/scripts/config.guess +++ b/scripts/config.guess @@ -17,7 +17,8 @@ timestamp='2004-08-13' # # 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. +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +# USA.. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a diff --git a/sm/ChangeLog b/sm/ChangeLog index 48e8473fa..f191e7512 100644 --- a/sm/ChangeLog +++ b/sm/ChangeLog @@ -1,3 +1,10 @@ +2006-06-20 Werner Koch + + * gpgsm.c (gpgsm_init_default_ctrl): Take care of the command line + option --include-certs. + + * keylist.c (list_cert_raw): Print the certid. + 2006-05-23 Werner Koch * keydb.c (hextobyte): Deleted as it is now defined in jnlib. diff --git a/sm/Makefile.am b/sm/Makefile.am index b5882ae1d..be53e8d25 100644 --- a/sm/Makefile.am +++ b/sm/Makefile.am @@ -14,7 +14,8 @@ # # 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 +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +# USA. ## Process this file with automake to produce Makefile.in diff --git a/sm/base64.c b/sm/base64.c index 62c2c9ad9..59ab6f24b 100644 --- a/sm/base64.c +++ b/sm/base64.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/sm/call-agent.c b/sm/call-agent.c index 9942672ae..85ec78c63 100644 --- a/sm/call-agent.c +++ b/sm/call-agent.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/sm/call-dirmngr.c b/sm/call-dirmngr.c index 85467d4a2..0de09a9ba 100644 --- a/sm/call-dirmngr.c +++ b/sm/call-dirmngr.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/sm/certchain.c b/sm/certchain.c index 44d72efd3..4a4ac49f6 100644 --- a/sm/certchain.c +++ b/sm/certchain.c @@ -16,7 +16,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/sm/certcheck.c b/sm/certcheck.c index 5fb376712..732356149 100644 --- a/sm/certcheck.c +++ b/sm/certcheck.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/sm/certdump.c b/sm/certdump.c index 1f2ea7b18..0d5146abc 100644 --- a/sm/certdump.c +++ b/sm/certdump.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/sm/certlist.c b/sm/certlist.c index b036a85d7..cde2930ec 100644 --- a/sm/certlist.c +++ b/sm/certlist.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/sm/certreqgen.c b/sm/certreqgen.c index c523c992a..744969719 100644 --- a/sm/certreqgen.c +++ b/sm/certreqgen.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ /* diff --git a/sm/decrypt.c b/sm/decrypt.c index 9e5518b0f..70d48c983 100644 --- a/sm/decrypt.c +++ b/sm/decrypt.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/sm/delete.c b/sm/delete.c index 7533f7291..0d2f1fd9d 100644 --- a/sm/delete.c +++ b/sm/delete.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/sm/encrypt.c b/sm/encrypt.c index e4c0d5437..07c2ba8ce 100644 --- a/sm/encrypt.c +++ b/sm/encrypt.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/sm/export.c b/sm/export.c index f9d6dac62..b08a017d2 100644 --- a/sm/export.c +++ b/sm/export.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/sm/fingerprint.c b/sm/fingerprint.c index 9441483bf..d6a3900f0 100644 --- a/sm/fingerprint.c +++ b/sm/fingerprint.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/sm/gpgsm.c b/sm/gpgsm.c index 7347bf575..5363b8ad6 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -1,5 +1,6 @@ /* gpgsm.c - GnuPG for S/MIME - * Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + * Copyright (C) 2001, 2002, 2003, 2004, 2005, + * 2006 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -15,7 +16,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include @@ -461,6 +463,10 @@ static unsigned int debug_value; /* Option --enable-special-filenames */ static int allow_special_filenames; +/* Default value for include-certs. */ +static int default_include_certs = 1; /* Only include the signer's cert. */ + + static char *build_list (const char *text, const char *(*mapf)(int), int (*chkf)(int)); @@ -998,7 +1004,9 @@ main ( int argc, char **argv) ctrl.use_ocsp = opt.enable_ocsp = 1; break; - case oIncludeCerts: ctrl.include_certs = pargs.r.ret_int; break; + case oIncludeCerts: + ctrl.include_certs = default_include_certs = pargs.r.ret_int; + break; case oPolicyFile: xfree (opt.policy_file); @@ -1657,7 +1665,7 @@ gpgsm_exit (int rc) void gpgsm_init_default_ctrl (struct server_control_s *ctrl) { - ctrl->include_certs = 1; /* only include the signer's cert */ + ctrl->include_certs = default_include_certs; ctrl->use_ocsp = opt.enable_ocsp; } diff --git a/sm/gpgsm.h b/sm/gpgsm.h index 438252050..b49f34640 100644 --- a/sm/gpgsm.h +++ b/sm/gpgsm.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifndef GPGSM_H diff --git a/sm/import.c b/sm/import.c index 6d00e91ea..b56014a1a 100644 --- a/sm/import.c +++ b/sm/import.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/sm/keydb.c b/sm/keydb.c index d5932135d..81936cf6a 100644 --- a/sm/keydb.c +++ b/sm/keydb.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/sm/keydb.h b/sm/keydb.h index fb4001b64..814ae9f1e 100644 --- a/sm/keydb.h +++ b/sm/keydb.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifndef GNUPG_KEYDB_H diff --git a/sm/keylist.c b/sm/keylist.c index b744a157f..9baf065d0 100644 --- a/sm/keylist.c +++ b/sm/keylist.c @@ -16,7 +16,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include @@ -598,6 +599,10 @@ list_cert_raw (ctrl_t ctrl, KEYDB_HANDLE hd, fprintf (fp, " md5_fpr: %s\n", dn?dn:"error"); xfree (dn); + dn = gpgsm_get_certid (cert); + fprintf (fp, " certid: %s\n", dn?dn:"error"); + xfree (dn); + dn = gpgsm_get_keygrip_hexstring (cert); fprintf (fp, " keygrip: %s\n", dn?dn:"error"); xfree (dn); diff --git a/sm/misc.c b/sm/misc.c index cd072ce6b..86cb506d6 100644 --- a/sm/misc.c +++ b/sm/misc.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/sm/qualified.c b/sm/qualified.c index 07abaadc4..474e1488d 100644 --- a/sm/qualified.c +++ b/sm/qualified.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/sm/server.c b/sm/server.c index 87a06ee4e..57e5d8f38 100644 --- a/sm/server.c +++ b/sm/server.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/sm/sign.c b/sm/sign.c index 74bfe41aa..d656825e8 100644 --- a/sm/sign.c +++ b/sm/sign.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/sm/verify.c b/sm/verify.c index f37cf4a75..4e6574078 100644 --- a/sm/verify.c +++ b/sm/verify.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/tests/Makefile.am b/tests/Makefile.am index 5264b8859..38b64c6ea 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -15,7 +15,8 @@ # # 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 +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +# USA. ## Process this file with automake to produce Makefile.in diff --git a/tests/asschk.c b/tests/asschk.c index 6a05fe1a8..40b95ba7d 100644 --- a/tests/asschk.c +++ b/tests/asschk.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ /* This is a simple stand-alone Assuan server test program. We don't diff --git a/tests/pkits/Makefile.am b/tests/pkits/Makefile.am index 41fdec497..d53d35a25 100644 --- a/tests/pkits/Makefile.am +++ b/tests/pkits/Makefile.am @@ -15,7 +15,8 @@ # # 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 +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +# USA. ## Process this file with automake to produce Makefile.in diff --git a/tests/pkits/common.sh b/tests/pkits/common.sh index 5e773ea5d..09fb62bc8 100644 --- a/tests/pkits/common.sh +++ b/tests/pkits/common.sh @@ -16,7 +16,8 @@ # # 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 +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +# USA. # reset some environment variables because we do not want to test locals export LANG=C diff --git a/tests/pkits/import-all-certs b/tests/pkits/import-all-certs index d1af5fb03..2d70d06df 100755 --- a/tests/pkits/import-all-certs +++ b/tests/pkits/import-all-certs @@ -15,7 +15,8 @@ # # 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 +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +# USA. . ${srcdir:-.}/common.sh || exit 2 diff --git a/tests/pkits/validate-all-certs b/tests/pkits/validate-all-certs index f482fdb51..08f72af71 100755 --- a/tests/pkits/validate-all-certs +++ b/tests/pkits/validate-all-certs @@ -16,7 +16,8 @@ # # 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 +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +# USA. . ${srcdir:-.}/common.sh || exit 2 diff --git a/tools/Makefile.am b/tools/Makefile.am index d9ef8812a..6b4767a79 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -15,7 +15,8 @@ # # 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 +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +# USA. EXTRA_DIST = Manifest watchgnupg.c \ addgnupghome gpgsm-gencert.sh diff --git a/tools/gpg-connect-agent.c b/tools/gpg-connect-agent.c index c9a324fa8..90e321000 100644 --- a/tools/gpg-connect-agent.c +++ b/tools/gpg-connect-agent.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/tools/gpgconf-comp.c b/tools/gpgconf-comp.c index 2da88bc49..04a61a193 100644 --- a/tools/gpgconf-comp.c +++ b/tools/gpgconf-comp.c @@ -1,21 +1,23 @@ /* gpgconf-comp.c - Configuration utility for GnuPG. - Copyright (C) 2004 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 GnuPG; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + * Copyright (C) 2004 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 GnuPG; if not, write to the Free Software Foundation, + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ #if HAVE_CONFIG_H #include diff --git a/tools/gpgconf.c b/tools/gpgconf.c index dd505e99d..87ba45ae1 100644 --- a/tools/gpgconf.c +++ b/tools/gpgconf.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/tools/gpgconf.h b/tools/gpgconf.h index 138380b6d..c083c26aa 100644 --- a/tools/gpgconf.h +++ b/tools/gpgconf.h @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifndef GPGCONF_H diff --git a/tools/gpgkey2ssh.c b/tools/gpgkey2ssh.c index e874ab22e..3dcb6516e 100644 --- a/tools/gpgkey2ssh.c +++ b/tools/gpgkey2ssh.c @@ -1,22 +1,23 @@ /* gpgkey2ssh.c - Converter ... - Copyright (C) 2005 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. */ + * Copyright (C) 2005 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ #include diff --git a/tools/gpgparsemail.c b/tools/gpgparsemail.c index 566f5747f..30759f9a4 100644 --- a/tools/gpgparsemail.c +++ b/tools/gpgparsemail.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ diff --git a/tools/no-libgcrypt.c b/tools/no-libgcrypt.c index 82f6a8bb5..636df10c6 100644 --- a/tools/no-libgcrypt.c +++ b/tools/no-libgcrypt.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #include diff --git a/tools/symcryptrun.c b/tools/symcryptrun.c index 075e0b444..406cbb2a2 100644 --- a/tools/symcryptrun.c +++ b/tools/symcryptrun.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ diff --git a/tools/watchgnupg.c b/tools/watchgnupg.c index 6cb570fbc..051ca50fe 100644 --- a/tools/watchgnupg.c +++ b/tools/watchgnupg.c @@ -15,7 +15,8 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. */ #ifdef HAVE_CONFIG_H -- cgit From 6c208fea3275e7d9244842811e8a5eefeb255e5f Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 30 Jun 2006 09:42:08 +0000 Subject: A couple of fixes. gpg2's key generation does now work. --- TODO | 3 +++ g10/ChangeLog | 21 +++++++++++++++++++++ g10/card-util.c | 2 +- g10/keygen.c | 2 +- g10/mainproc.c | 19 ++++++++----------- g10/misc.c | 5 +---- g10/parse-packet.c | 22 +++++++++++++--------- g10/pkclist.c | 8 ++++---- g10/pubkey-enc.c | 2 +- g10/seskey.c | 5 ++--- scd/ChangeLog | 6 ++++++ scd/app-openpgp.c | 2 +- 12 files changed, 62 insertions(+), 35 deletions(-) (limited to 'scd/app-openpgp.c') diff --git a/TODO b/TODO index 0650361c6..672fab9a7 100644 --- a/TODO +++ b/TODO @@ -103,6 +103,9 @@ might want to have an agent context for each service request * sm/ ** check that we issue NO_SECKEY xxx if a -u key was not found +* jnlib/ +** provide jnlib_malloc and try to remove all jnlib_xmalloc. + * gpg/ ** issue a NO_SECKEY xxxx if a -u key was not found. ** Replace DIGEST_ALGO_SHA224 diff --git a/g10/ChangeLog b/g10/ChangeLog index 4a838257e..2fba9c488 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,24 @@ +2006-06-30 Werner Koch + + * misc.c (checksum_mpi): No need for nbits as they are alredy + included in the buffer. + +2006-06-29 Werner Koch + + * parse-packet.c (parse_signature, parse_key): Need store the + length of opaque data as number of bits. + * card-util.c (card_store_subkey): Ditto. + + * mainproc.c (print_pkenc_list, check_sig_and_print): Replaced + log_get_stream by calls to log_printf. This avoids the extra LFs + inserted by the logging function. They are a bit too smart + sometimes. + * pkclist.c (do_show_revocation_reason): Print final LF through + log_printf to avoid extra LFs. + * pubkey-enc.c (get_it): Ditto. + + * seskey.c (encode_md_value): Fix call to gcry. + 2006-06-27 Werner Koch Applied patches from 1.4.x (2006-05-22 to 2006-06-23) from David: diff --git a/g10/card-util.c b/g10/card-util.c index b5a036e54..b7da1ba98 100644 --- a/g10/card-util.c +++ b/g10/card-util.c @@ -1271,7 +1271,7 @@ card_store_subkey (KBNODE node, int use) sk->skey[i] = NULL; } i = pubkey_get_npkey (sk->pubkey_algo); - sk->skey[i] = mpi_set_opaque (NULL, xstrdup ("dummydata"), 10); + sk->skey[i] = gcry_mpi_set_opaque (NULL, xstrdup ("dummydata"), 10*8); sk->is_protected = 1; sk->protect.s2k.mode = 1002; s = info.serialno; diff --git a/g10/keygen.c b/g10/keygen.c index 7a6296974..ff4ce88b4 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -3701,7 +3701,7 @@ gen_card_key_with_backup (int algo, int keyno, int is_primary, sk->skey[i] = NULL; } i = pubkey_get_npkey (sk->pubkey_algo); - sk->skey[i] = mpi_set_opaque (NULL, xstrdup ("dummydata"), 10); + sk->skey[i] = gcry_mpi_set_opaque (NULL, xstrdup ("dummydata"), 10*8); sk->is_protected = 1; sk->protect.s2k.mode = 1002; s = get_parameter_value (para, pSERIALNO); diff --git a/g10/mainproc.c b/g10/mainproc.c index 67ac784dc..ca5ea9ade 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -445,7 +445,7 @@ print_pkenc_list( struct kidlist_item *list, int failed ) nbits_from_pk( pk ), algstr, keystr_from_pk(pk), strtimestamp(pk->timestamp) ); p=get_user_id_native(list->kid); - fprintf(log_get_stream(),_(" \"%s\"\n"),p); + log_printf (_(" \"%s\"\n"),p); xfree(p); } else @@ -1527,7 +1527,7 @@ check_sig_and_print( CTX c, KBNODE node ) not going to even try to make two strings here :) */ log_info(_("Key available at: ") ); print_utf8_string( log_get_stream(), p, n ); - putc( '\n', log_get_stream() ); + log_printf ("\n"); if(opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE && opt.keyserver_options.options&KEYSERVER_HONOR_KEYSERVER_URL) @@ -1667,9 +1667,9 @@ check_sig_and_print( CTX c, KBNODE node ) xfree(p); if(opt.verify_options&VERIFY_SHOW_UID_VALIDITY) - fprintf(log_get_stream()," [%s]\n",trust_value_to_string(valid)); + log_printf (" [%s]\n",trust_value_to_string(valid)); else - fputs("\n", log_get_stream() ); + log_printf ("\n"); count++; } if( !count ) { /* just in case that we have no valid textual @@ -1712,11 +1712,8 @@ check_sig_and_print( CTX c, KBNODE node ) else log_info(_("Good signature from \"%s\""),p); if (opt.trust_model!=TM_ALWAYS && un) - { - putc(' ', log_get_stream() ); - fputs(_("[uncertain]"), log_get_stream() ); - } - fputs("\n", log_get_stream() ); + log_printf (" %s",_("[uncertain]") ); + log_printf ("\n"); } /* If we have a good signature and already printed @@ -1760,10 +1757,10 @@ check_sig_and_print( CTX c, KBNODE node ) valid=trust_value_to_string(get_validity(pk, un->pkt-> pkt.user_id)); - fprintf(log_get_stream()," [%s]\n",valid); + log_printf (" [%s]\n",valid); } else - fputs("\n", log_get_stream() ); + log_printf ("\n"); } } release_kbnode( keyblock ); diff --git a/g10/misc.c b/g10/misc.c index de0a029a4..33b97792c 100644 --- a/g10/misc.c +++ b/g10/misc.c @@ -297,7 +297,6 @@ checksum_mpi (gcry_mpi_t a) u16 csum; byte *buffer; unsigned int nbytes; - unsigned int nbits; if ( gcry_mpi_print (GCRYMPI_FMT_PGP, NULL, 0, &nbytes, a) ) BUG (); @@ -308,9 +307,7 @@ checksum_mpi (gcry_mpi_t a) gcry_xmalloc_secure (nbytes) : gcry_xmalloc (nbytes)); if ( gcry_mpi_print (GCRYMPI_FMT_PGP, buffer, nbytes, NULL, a) ) BUG (); - nbits = gcry_mpi_get_nbits (a); - csum = checksum_u16 (nbits); - csum += checksum (buffer, nbytes); + csum = checksum (buffer, nbytes); xfree (buffer); return csum; } diff --git a/g10/parse-packet.c b/g10/parse-packet.c index d792bfff9..d9a87f108 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -1490,9 +1490,10 @@ parse_signature( IOBUF inp, int pkttype, unsigned long pktlen, if( list_mode ) fprintf (listfp, "\tunknown algorithm %d\n", sig->pubkey_algo ); unknown_pubkey_warning( sig->pubkey_algo ); - /* we store the plain material in data[0], so that we are able + /* We store the plain material in data[0], so that we are able * to write it back with build_packet() */ - sig->data[0]= mpi_set_opaque(NULL, read_rest(inp, pktlen, 0), pktlen ); + sig->data[0]= gcry_mpi_set_opaque (NULL, read_rest(inp, pktlen, 0), + pktlen*8 ); pktlen = 0; } else { @@ -1715,8 +1716,8 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen, size_t snlen = 0; if( !npkey ) { - sk->skey[0] = mpi_set_opaque( NULL, - read_rest(inp, pktlen, 0), pktlen ); + sk->skey[0] = gcry_mpi_set_opaque (NULL, read_rest(inp, pktlen, 0), + pktlen*8 ); pktlen = 0; goto leave; } @@ -1894,15 +1895,17 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen, if( sk->protect.s2k.mode == 1001 || sk->protect.s2k.mode == 1002 ) { /* better set some dummy stuff here */ - sk->skey[npkey] = mpi_set_opaque(NULL, xstrdup("dummydata"), 10); + sk->skey[npkey] = gcry_mpi_set_opaque(NULL, + xstrdup("dummydata"), 10*8); pktlen = 0; } else if( is_v4 && sk->is_protected ) { /* ugly; the length is encrypted too, so we read all * stuff up to the end of the packet into the first * skey element */ - sk->skey[npkey] = mpi_set_opaque(NULL, - read_rest(inp, pktlen, 0),pktlen); + sk->skey[npkey] = gcry_mpi_set_opaque (NULL, + read_rest(inp, pktlen, 0), + pktlen*8); pktlen = 0; if( list_mode ) { fprintf (listfp, "\tencrypted stuff follows\n"); @@ -1942,8 +1945,9 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen, PKT_public_key *pk = pkt->pkt.public_key; if( !npkey ) { - pk->pkey[0] = mpi_set_opaque( NULL, - read_rest(inp, pktlen, 0), pktlen ); + pk->pkey[0] = gcry_mpi_set_opaque ( NULL, + read_rest(inp, pktlen, 0), + pktlen*8 ); pktlen = 0; goto leave; } diff --git a/g10/pkclist.c b/g10/pkclist.c index 4516f6769..d3cda144f 100644 --- a/g10/pkclist.c +++ b/g10/pkclist.c @@ -76,7 +76,7 @@ do_show_revocation_reason( PKT_signature *sig ) fputs( text, log_get_stream() ); else fprintf( log_get_stream(), "code=%02x", *p ); - putc( '\n', log_get_stream() ); + log_printf ("\n"); n--; p++; pp = NULL; do { @@ -88,9 +88,9 @@ do_show_revocation_reason( PKT_signature *sig ) if( n ) { pp = memchr( p, '\n', n ); nn = pp? pp - p : n; - log_info( _("revocation comment: ") ); - print_string( log_get_stream(), p, nn, 0 ); - putc( '\n', log_get_stream() ); + log_info ( _("revocation comment: ") ); + print_string ( log_get_stream(), p, nn, 0 ); + log_printf ("\n"); p += nn; n -= nn; } } while( pp ); diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c index dc0124bd4..47aadc9a7 100644 --- a/g10/pubkey-enc.c +++ b/g10/pubkey-enc.c @@ -308,7 +308,7 @@ get_it( PKT_pubkey_enc *enc, DEK *dek, PKT_secret_key *sk, u32 *keyid ) if ( pk && pk->is_revoked ) { log_info( _("NOTE: key has been revoked") ); - putc( '\n', log_get_stream() ); + log_printf ("\n"); show_revocation_reason( pk, 1 ); } diff --git a/g10/seskey.c b/g10/seskey.c index a31cbb15e..2ef00869f 100644 --- a/g10/seskey.c +++ b/g10/seskey.c @@ -220,8 +220,7 @@ encode_md_value (PKT_public_key *pk, PKT_secret_key *sk, { /* It's a DSA signature, so find out the size of q. */ - unsigned int qbytes = gcry_mpi_get_nbits (pk?pk->pkey[1]:sk->skey[1]); - size_t n; + size_t qbytes = gcry_mpi_get_nbits (pk?pk->pkey[1]:sk->skey[1]); /* Make sure it is a multiple of 8 bits. */ @@ -259,7 +258,7 @@ encode_md_value (PKT_public_key *pk, PKT_secret_key *sk, } if (gcry_mpi_scan (&frame, GCRYMPI_FMT_USG, - gcry_md_read (md, hash_algo), n, &n)) + gcry_md_read (md, hash_algo), qbytes, &qbytes)) BUG(); } else diff --git a/scd/ChangeLog b/scd/ChangeLog index fd2ba5418..ba2ede72c 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,9 @@ +2006-06-28 Werner Koch + + * app-openpgp.c (do_writekey): Fixed computation of memmove + length. This led to garbled keys if E was larger than one byte. + Thanks to Achim Pietig for hinting at the garbled E. + 2006-06-09 Marcus Brinkmann * Makefile.am (scdaemon_LDADD): Add $(NETLIBS). diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 842881f3a..47ff8abc2 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -1828,7 +1828,7 @@ do_writekey (app_t app, ctrl_t ctrl, if (rsa_e_len < 4) { /* Right justify E. */ - memmove (tp+4-rsa_e_len, tp, 4-rsa_e_len); + memmove (tp+4-rsa_e_len, tp, rsa_e_len); memset (tp, 0, 4-rsa_e_len); } tp += 4; -- cgit