diff options
Diffstat (limited to 'scd')
-rw-r--r-- | scd/ChangeLog | 22 | ||||
-rw-r--r-- | scd/Makefile.am | 38 | ||||
-rw-r--r-- | scd/apdu.c | 253 | ||||
-rw-r--r-- | scd/apdu.h | 31 | ||||
-rw-r--r-- | scd/card-common.h | 2 | ||||
-rw-r--r-- | scd/card-dinsig.c | 20 | ||||
-rw-r--r-- | scd/card-p15.c | 52 | ||||
-rw-r--r-- | scd/card.c | 98 | ||||
-rw-r--r-- | scd/command.c | 14 | ||||
-rw-r--r-- | scd/scdaemon.c | 12 | ||||
-rw-r--r-- | scd/scdaemon.h | 20 |
11 files changed, 455 insertions, 107 deletions
diff --git a/scd/ChangeLog b/scd/ChangeLog index 807f96888..2ed774f21 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,25 @@ +2003-06-03 Werner Koch <[email protected]> + + Changed all error codes in all files to the new libgpg-error scheme. + + * scdaemon.h: Include gpg-error.h and errno.h + * card.c (map_sc_err): Use unknown for the error source. + * Makefile.am: Link with libgpg-error + +2003-05-14 Werner Koch <[email protected]> + + * atr.c, atr.h: New. + * sc-investigate.c: Dump the ATR in a human readable format. + +2003-05-08 Werner Koch <[email protected]> + + * scdaemon.h (DBG_CARD_IO_VALUE): New. + + * sc-investigate.c: New. + * scdaemon.c (main): Removed --print-atr option. + + * iso7816.c, iso7816.h, app-openpgp.c: New. + 2003-04-29 Werner Koch <[email protected]> * scdaemon.c: New options --print-atr and --reader-port diff --git a/scd/Makefile.am b/scd/Makefile.am index 05f774afb..41353836f 100644 --- a/scd/Makefile.am +++ b/scd/Makefile.am @@ -1,4 +1,4 @@ -# Copyright (C) 2002 Free Software Foundation, Inc. +# Copyright (C) 2002, 2003 Free Software Foundation, Inc. # # This file is part of GnuPG. # @@ -21,7 +21,7 @@ localedir = $(datadir)/locale INCLUDES = -I../intl -DLOCALEDIR=\"$(localedir)\" -bin_PROGRAMS = scdaemon +bin_PROGRAMS = scdaemon sc-investigate sc-genkey AM_CPPFLAGS = -I$(top_srcdir)/common $(OPENSC_CFLAGS) $(LIBGCRYPT_CFLAGS) \ $(KSBA_CFLAGS) $(LIBASSUAN_CFLAGS) @@ -31,7 +31,37 @@ scdaemon_SOURCES = \ command.c card.c \ card-common.h \ card-p15.c card-dinsig.c \ - apdu.c apdu.h + apdu.c apdu.h \ + iso7816.c iso7816.h \ + app-openpgp.c scdaemon_LDADD = ../jnlib/libjnlib.a ../common/libcommon.a \ - $(OPENSC_LIBS) $(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(LIBASSUAN_LIBS) -ldl + $(OPENSC_LIBS) $(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(LIBASSUAN_LIBS) -lgpg-error -ldl + +sc_investigate_SOURCES = \ + sc-investigate.c scdaemon.h \ + apdu.c apdu.h \ + iso7816.c iso7816.h \ + app-openpgp.c \ + atr.c atr.h + +sc_investigate_LDADD = ../jnlib/libjnlib.a ../common/libcommon.a \ + $(LIBGCRYPT_LIBS) -lgpg-error -ldl + +sc_genkey_SOURCES = \ + sc-genkey.c scdaemon.h \ + apdu.c apdu.h \ + iso7816.c iso7816.h \ + app-openpgp.c \ + atr.c atr.h + +sc_genkey_LDADD = ../jnlib/libjnlib.a ../common/libcommon.a \ + $(LIBGCRYPT_LIBS) -lgpg-error -ldl + + + + + + + + diff --git a/scd/apdu.c b/scd/apdu.c index 8fa531926..63dfa0684 100644 --- a/scd/apdu.c +++ b/scd/apdu.c @@ -24,6 +24,7 @@ #include <stdlib.h> #include <string.h> #include <dlfcn.h> +#include <assert.h> #include "scdaemon.h" #include "apdu.h" @@ -243,6 +244,31 @@ open_ct_reader (int port) } +/* Actuall send the APDU of length APDULEN to SLOT and return a + maximum of *BUFLEN data in BUFFER, the actual retruned size will be + 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) +{ + int rc; + unsigned char dad[1], sad[1]; + unsigned short ctbuflen; + + dad[0] = 0; /* Destination address: Card. */ + sad[0] = 2; /* Source address: Host. */ + ctbuflen = *buflen; + if (DBG_CARD_IO) + log_printhex (" CT_data:", apdu, apdulen); + rc = CT_data (slot, dad, sad, apdulen, apdu, &ctbuflen, buffer); + *buflen = ctbuflen; + + /* FIXME: map the errorcodes to GNUPG ones, so that they can be + shared between CTAPI and PCSC. */ + return rc; +} + + #endif /*HAVE_CTAPI*/ @@ -292,8 +318,235 @@ apdu_open_reader (int port) } +unsigned char * +apdu_get_atr (int slot, size_t *atrlen) +{ + char *buf; + + if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used ) + return NULL; + + buf = xtrymalloc (reader_table[slot].atrlen); + if (!buf) + return NULL; + memcpy (buf, reader_table[slot].atr, reader_table[slot].atrlen); + *atrlen = reader_table[slot].atrlen; + return buf; +} + + +static const char * +error_string (int slot, int rc) +{ +#ifdef HAVE_CTAPI + return ct_error_string (rc); +#elif defined(HAVE_PCSC) + return "?"; +#else + return "?"; +#endif +} + + +/* Dispatcher for the actual send_apdu fucntion. */ +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 -1; +#else + return -1; +#endif +} + +/* 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 reposnible 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) +{ + unsigned char result[256+10]; /* 10 extra in case of bugs in the driver. */ + size_t resultlen = 256; + unsigned char apdu[5+256+1]; + size_t apdulen; + int rc, sw; + + if (DBG_CARD_IO) + log_debug ("send apdu: c=%02X i=%02X p0=%02X p1=%02X lc=%d le=%d\n", + class, ins, p0, p1, lc, le); + + if (lc != -1 && (lc > 255 || lc < 0)) + return SW_WRONG_LENGTH; + if (le != -1 && (le > 256 || le < 1)) + return SW_WRONG_LENGTH; + if ((!data && lc != -1) || (data && lc == -1)) + return -1; + + apdulen = 0; + apdu[apdulen++] = class; + apdu[apdulen++] = ins; + apdu[apdulen++] = p0; + apdu[apdulen++] = p1; + if (lc != -1) + { + apdu[apdulen++] = lc; + memcpy (apdu+apdulen, data, lc); + apdulen += lc; + } + if (le != -1) + apdu[apdulen++] = le; /* Truncation is okay becuase 0 means 256. */ + assert (sizeof (apdu) >= apdulen); + /* As safeguard don't pass any garbage from the stack to the driver. */ + memset (apdu+apdulen, 0, sizeof (apdu) - apdulen); + rc = send_apdu (slot, apdu, apdulen, result, &resultlen); + if (rc || resultlen < 2) + { + log_error ("apdu_send_simple(%d) failed: %s\n", + slot, error_string (slot, rc)); + return -1; + } + sw = (result[resultlen-2] << 8) | result[resultlen-1]; + /* store away the returned data but strip the statusword. */ + resultlen -= 2; + if (DBG_CARD_IO) + { + log_debug (" response: sw=%04X datalen=%d\n", sw, resultlen); + if ( !retbuf && (sw == SW_SUCCESS || (sw & 0xff00) == SW_MORE_DATA)) + log_printhex (" dump: ", result, resultlen); + } + + if (sw == SW_SUCCESS) + { + if (retbuf) + { + *retbuf = xtrymalloc (resultlen? resultlen : 1); + if (!*retbuf) + return -1; /* fixme: this is actually out of core. */ + *retbuflen = resultlen; + memcpy (*retbuf, result, resultlen); + } + } + else if ((sw & 0xff00) == SW_MORE_DATA) + { + unsigned char *p = NULL, *tmp; + size_t bufsize = 4096; + /* It is likely that we need to return much more data, so we + start off with a large buffer. */ + if (retbuf) + { + *retbuf = p = xtrymalloc (bufsize); + if (!*retbuf) + return -1; /* fixme: this is actually out of core. */ + assert (resultlen < bufsize); + memcpy (p, result, resultlen); + p += resultlen; + } + do + { + int len = (sw & 0x00ff); + + log_debug ("apdu_send_simple(%d): %d more bytes available\n", + slot, len); + apdulen = 0; + apdu[apdulen++] = class; + apdu[apdulen++] = 0xC0; + apdu[apdulen++] = 0; + apdu[apdulen++] = 0; + apdu[apdulen++] = 64; /* that is 256 bytes for Le */ + memset (apdu+apdulen, 0, sizeof (apdu) - apdulen); + rc = send_apdu (slot, apdu, apdulen, result, &resultlen); + if (rc || resultlen < 2) + { + log_error ("apdu_send_simple(%d) for get response failed: %s\n", + slot, error_string (slot, rc)); + return -1; + } + sw = (result[resultlen-2] << 8) | result[resultlen-1]; + resultlen -= 2; + if (DBG_CARD_IO) + { + log_debug (" more: sw=%04X datalen=%d\n", sw, resultlen); + if (!retbuf && (sw==SW_SUCCESS || (sw&0xff00)==SW_MORE_DATA)) + log_printhex (" dump: ", result, resultlen); + } + if ((sw & 0xff00) == SW_MORE_DATA || sw == SW_SUCCESS) + { + if (retbuf) + { + if (p - *retbuf + resultlen > bufsize) + { + bufsize += resultlen > 4096? resultlen: 4096; + tmp = xtryrealloc (*retbuf, bufsize); + if (!tmp) + return -1; /* fixme: actually this is out of core */ + p = tmp + (p - *retbuf); + *retbuf = tmp; + } + memcpy (p, result, resultlen); + p += resultlen; + } + } + else + log_info ("apdu_send_simple(%d) " + "got unexpected status %04X from get response\n", + slot, sw); + } + while ((sw & 0xff00) == SW_MORE_DATA); + + if (retbuf) + { + *retbuflen = p - *retbuf; + tmp = xtryrealloc (*retbuf, *retbuflen); + if (tmp) + *retbuf = tmp; + } + } + if (DBG_CARD_IO && retbuf && sw == SW_SUCCESS) + log_printhex (" dump: ", *retbuf, *retbuflen); + + return sw; +} +/* 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 + 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(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); +} +/* 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 + 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 +apdu_send_simple (int slot, int class, int ins, int p0, int p1, + int lc, const char *data) +{ + return apdu_send (slot, class, ins, p0, p1, lc, data, NULL, NULL); +} diff --git a/scd/apdu.h b/scd/apdu.h index fc10eed69..47fd1a8f6 100644 --- a/scd/apdu.h +++ b/scd/apdu.h @@ -1,4 +1,4 @@ -/* apdu.c - ISO 7816 APDU functions and low level I/O +/* apdu.h - ISO 7816 APDU functions and low level I/O * Copyright (C) 2003 Free Software Foundation, Inc. * * This file is part of GnuPG. @@ -21,9 +21,38 @@ #ifndef APDU_H #define APDU_H +/* ISO 7816 values for the statusword are defined here because they + should not be visible to the users of the actual iso command + API. */ +enum { + SW_MORE_DATA = 0x6100, /* Note: that the low byte must be + masked of.*/ + SW_EEPROM_FAILURE = 0x6581, + SW_WRONG_LENGTH = 0x6700, + SW_CHV_WRONG = 0x6982, + SW_CHV_BLOCKED = 0x6983, + SW_USE_CONDITIONS = 0x6985, + SW_BAD_PARAMETER = 0x6a80, /* (in the data field) */ + SW_REF_NOT_FOUND = 0x6a88, + SW_BAD_P0_P1 = 0x6b00, + SW_INS_NOT_SUP = 0x6d00, + SW_CLA_NOT_SUP = 0x6e00, + SW_SUCCESS = 0x9000 +}; +int apdu_open_reader (int port); +unsigned char *apdu_get_atr (int slot, size_t *atrlen); + +int apdu_send_simple (int slot, int class, int ins, int p0, int p1, + int lc, const char *data); +int apdu_send (int slot, int class, int ins, int p0, int p1, + int lc, const char *data, + unsigned char **retbuf, size_t *retbuflen); +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); #endif /*APDU_H*/ diff --git a/scd/card-common.h b/scd/card-common.h index 50014cead..7ce2726c3 100644 --- a/scd/card-common.h +++ b/scd/card-common.h @@ -59,7 +59,7 @@ struct card_ctx_s { }; /*-- card.c --*/ -int map_sc_err (int rc); +gpg_error_t map_sc_err (int rc); int card_help_get_keygrip (KsbaCert cert, unsigned char *array); /*-- card-15.c --*/ diff --git a/scd/card-dinsig.c b/scd/card-dinsig.c index a9437e47c..6262ca3bc 100644 --- a/scd/card-dinsig.c +++ b/scd/card-dinsig.c @@ -116,8 +116,9 @@ dinsig_enum_keypairs (CARD card, int idx, cert = ksba_cert_new (); if (!cert) { + gpg_error_t tmperr = out_of_core (); xfree (buf); - return GNUPG_Out_Of_Core; + return tmperr; } krc = ksba_cert_init_from_mem (cert, buf, buflen); @@ -127,13 +128,13 @@ dinsig_enum_keypairs (CARD card, int idx, log_error ("failed to parse the certificate at idx %d: %s\n", idx, ksba_strerror (krc)); ksba_cert_release (cert); - return GNUPG_Card_Error; + return gpg_error (GPG_ERR_CARD_ERROR); } if (card_help_get_keygrip (cert, keygrip)) { log_error ("failed to calculate the keygrip at index %d\n", idx); ksba_cert_release (cert); - return GNUPG_Card_Error; + return gpg_error (GPG_ERR_CARD_ERROR); } ksba_cert_release (cert); @@ -142,7 +143,7 @@ dinsig_enum_keypairs (CARD card, int idx, { *keyid = xtrymalloc (17); if (!*keyid) - return GNUPG_Out_Of_Core; + return out_of_core (); if (!idx) strcpy (*keyid, "DINSIG-DF01.C000"); else @@ -170,7 +171,7 @@ dinsig_read_cert (CARD card, const char *certidstr, else if (!strcmp (certidstr, "DINSIG-DF01.C200")) sc_format_path ("3F00DF01C200", &path); else - return GNUPG_Invalid_Id; + return gpg_error (GPG_ERR_INVALID_ID); rc = sc_select_file (card->scard, &path, &file); if (rc) @@ -183,19 +184,20 @@ dinsig_read_cert (CARD card, const char *certidstr, { log_error ("wrong type or structure of certificate EF\n"); sc_file_free (file); - return GNUPG_Card_Error; + return gpg_error (GPG_ERR_CARD_ERROR); } if (file->size < 20) /* check against a somewhat arbitrary length */ { log_error ("certificate EF too short\n"); sc_file_free (file); - return GNUPG_Card_Error; + return gpg_error (GPG_ERR_CARD_ERROR); } buf = xtrymalloc (file->size); if (!buf) { + gpg_error_t tmperr = out_of_core (); sc_file_free (file); - return GNUPG_Out_Of_Core; + return tmperr; } rc = sc_read_binary (card->scard, 0, buf, file->size, 0); @@ -204,7 +206,7 @@ dinsig_read_cert (CARD card, const char *certidstr, log_error ("short read on certificate EF\n"); sc_file_free (file); xfree (buf); - return GNUPG_Card_Error; + return gpg_error (GPG_ERR_CARD_ERROR); } sc_file_free (file); if (rc < 0) diff --git a/scd/card-p15.c b/scd/card-p15.c index 7fa2d8fe8..e9050faba 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 GNUPG_Out_Of_Core; + return out_of_core (); /* 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 @@ -70,7 +70,7 @@ init_private_data (CARD card) { log_error ("private keys enumeration failed: %s\n", sc_strerror (rc)); xfree (priv); - return GNUPG_Card_Error; + return gpg_error (GPG_ERR_CARD_ERROR); } priv->n_prkey_rsa_objs = rc; @@ -82,7 +82,7 @@ init_private_data (CARD card) { log_error ("private keys enumeration failed: %s\n", sc_strerror (rc)); xfree (priv); - return GNUPG_Card_Error; + return gpg_error (GPG_ERR_CARD_ERROR); } priv->n_cert_objs = rc; @@ -136,7 +136,7 @@ p15_enum_keypairs (CARD card, int idx, log_info ("certificate for private key %d not found: %s\n", idx, sc_strerror (rc)); /* note, that we return the ID anyway */ - rc = GNUPG_Missing_Certificate; + rc = gpg_error (GPG_ERR_MISSING_CERTIFICATE); goto return_keyid; } certinfo = tmpobj->data; @@ -145,14 +145,15 @@ p15_enum_keypairs (CARD card, int idx, { log_info ("failed to read certificate for private key %d: %s\n", idx, sc_strerror (rc)); - return GNUPG_Card_Error; + return gpg_error (GPG_ERR_CARD_ERROR); } cert = ksba_cert_new (); if (!cert) { + gpg_error_t tmperr = out_of_core (); sc_pkcs15_free_certificate (certder); - return GNUPG_Out_Of_Core; + return tmperr; } krc = ksba_cert_init_from_mem (cert, certder->data, certder->data_len); sc_pkcs15_free_certificate (certder); @@ -161,13 +162,13 @@ p15_enum_keypairs (CARD card, int idx, log_error ("failed to parse the certificate for private key %d: %s\n", idx, ksba_strerror (krc)); ksba_cert_release (cert); - return GNUPG_Card_Error; + return gpg_error (GPG_ERR_CARD_ERROR); } if (card_help_get_keygrip (cert, keygrip)) { log_error ("failed to calculate the keygrip of private key %d\n", idx); ksba_cert_release (cert); - return GNUPG_Card_Error; + return gpg_error (GPG_ERR_CARD_ERROR); } ksba_cert_release (cert); @@ -180,7 +181,7 @@ p15_enum_keypairs (CARD card, int idx, *keyid = p = xtrymalloc (9+pinfo->id.len*2+1); if (!*keyid) - return GNUPG_Out_Of_Core; + return out_of_core (); p = stpcpy (p, "P15-5015."); for (i=0; i < pinfo->id.len; i++, p += 2) sprintf (p, "%02X", pinfo->id.value[i]); @@ -218,7 +219,7 @@ p15_enum_certs (CARD card, int idx, char **certid, int *type) *certid = p = xtrymalloc (9+cinfo->id.len*2+1); if (!*certid) - return GNUPG_Out_Of_Core; + return out_of_core (); p = stpcpy (p, "P15-5015."); for (i=0; i < cinfo->id.len; i++, p += 2) sprintf (p, "%02X", cinfo->id.value[i]); @@ -251,14 +252,14 @@ idstr_to_id (const char *idstr, struct sc_pkcs15_id *id) /* For now we only support the standard DF */ if (strncmp (idstr, "P15-5015.", 9) ) - return GNUPG_Invalid_Id; + return gpg_error (GPG_ERR_INVALID_ID); for (s=idstr+9, n=0; hexdigitp (s); s++, n++) ; if (*s || (n&1)) - return GNUPG_Invalid_Id; /* invalid or odd number of digits */ + return gpg_error (GPG_ERR_INVALID_ID); /*invalid or odd number of digits*/ n /= 2; if (!n || n > SC_PKCS15_MAX_ID_SIZE) - return GNUPG_Invalid_Id; /* empty or too large */ + return gpg_error (GPG_ERR_INVALID_ID); /* empty or too large */ for (s=idstr+9, n=0; *s; s += 2, n++) id->value[n] = xtoi_2 (s); id->len = n; @@ -278,9 +279,9 @@ p15_read_cert (CARD card, const char *certidstr, int rc; if (!card || !certidstr || !cert || !ncert) - return GNUPG_Invalid_Value; + return gpg_error (GPG_ERR_INVALID_VALUE); if (!card->p15card) - return GNUPG_No_PKCS15_App; + return gpg_error (GPG_ERR_NO_PKCS15_APP); rc = idstr_to_id (certidstr, &certid); if (rc) @@ -299,14 +300,15 @@ p15_read_cert (CARD card, const char *certidstr, { log_info ("failed to read certificate '%s': %s\n", certidstr, sc_strerror (rc)); - return GNUPG_Card_Error; + return gpg_error (GPG_ERR_CARD_ERROR); } *cert = xtrymalloc (certder->data_len); if (!*cert) { + gpg_error_t tmperr = out_of_core (); sc_pkcs15_free_certificate (certder); - return GNUPG_Out_Of_Core; + return tmperr; } memcpy (*cert, certder->data, certder->data_len); *ncert = certder->data_len; @@ -337,7 +339,7 @@ p15_prepare_key (CARD card, const char *keyidstr, if (rc < 0) { log_error ("private key not found: %s\n", sc_strerror(rc)); - return GNUPG_No_Secret_Key; + return gpg_error (GPG_ERR_NO_SECRET_KEY); } rc = sc_pkcs15_find_pin_by_auth_id (card->p15card, @@ -345,7 +347,7 @@ p15_prepare_key (CARD card, const char *keyidstr, if (rc) { log_error ("failed to find PIN by auth ID: %s\n", sc_strerror (rc)); - return GNUPG_Bad_PIN_Method; + return gpg_error (GPG_ERR_BAD_PIN_METHOD); } pin = pinobj->data; @@ -365,7 +367,7 @@ p15_prepare_key (CARD card, const char *keyidstr, if (rc) { log_info ("PIN verification failed: %s\n", sc_strerror (rc)); - return GNUPG_Bad_PIN; + return gpg_error (GPG_ERR_BAD_PIN); } /* fixme: check wheter we need to release KEYOBJ in case of an error */ @@ -389,7 +391,7 @@ p15_sign (CARD card, const char *keyidstr, int hashalgo, size_t outbuflen; if (hashalgo != GCRY_MD_SHA1) - return GNUPG_Unsupported_Algorithm; + return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); rc = p15_prepare_key (card, keyidstr, pincb, pincb_arg, &keyobj); if (rc) @@ -400,7 +402,7 @@ p15_sign (CARD card, const char *keyidstr, int hashalgo, outbuflen = 1024; outbuf = xtrymalloc (outbuflen); if (!outbuf) - return GNUPG_Out_Of_Core; + return out_of_core (); rc = sc_pkcs15_compute_signature (card->p15card, keyobj, cryptflags, @@ -409,7 +411,7 @@ p15_sign (CARD card, const char *keyidstr, int hashalgo, if (rc < 0) { log_error ("failed to create signature: %s\n", sc_strerror (rc)); - rc = GNUPG_Card_Error; + rc = gpg_error (GPG_ERR_CARD_ERROR); } else { @@ -462,7 +464,7 @@ p15_decipher (CARD card, const char *keyidstr, outbuflen = indatalen < 256? 256 : indatalen; outbuf = xtrymalloc (outbuflen); if (!outbuf) - return GNUPG_Out_Of_Core; + return out_of_core (); rc = sc_pkcs15_decipher (card->p15card, keyobj, 0, @@ -471,7 +473,7 @@ p15_decipher (CARD card, const char *keyidstr, if (rc < 0) { log_error ("failed to decipher the data: %s\n", sc_strerror (rc)); - rc = GNUPG_Card_Error; + rc = gpg_error (GPG_ERR_CARD_ERROR); } else { diff --git a/scd/card.c b/scd/card.c index 998413f7e..682a766f5 100644 --- a/scd/card.c +++ b/scd/card.c @@ -34,23 +34,25 @@ #include "card-common.h" /* Map the SC error codes to the GNUPG ones */ -int +gpg_error_t map_sc_err (int rc) { + gpg_err_code_t e; + switch (rc) { - case 0: rc = 0; break; + case 0: e = 0; break; #ifdef HAVE_OPENSC - case SC_ERROR_NOT_SUPPORTED: rc = GNUPG_Not_Supported; break; - case SC_ERROR_PKCS15_APP_NOT_FOUND: rc = GNUPG_No_PKCS15_App; break; - case SC_ERROR_OUT_OF_MEMORY: rc = GNUPG_Out_Of_Core; break; - case SC_ERROR_CARD_NOT_PRESENT: rc = GNUPG_Card_Not_Present; break; - case SC_ERROR_CARD_REMOVED: rc = GNUPG_Card_Removed; break; - case SC_ERROR_INVALID_CARD: rc = GNUPG_Invalid_Card; break; + case SC_ERROR_NOT_SUPPORTED: e = GPG_ERR_NOT_SUPPORTED; break; + case SC_ERROR_PKCS15_APP_NOT_FOUND: e = GPG_ERR_NO_PKCS15_APP; break; + case SC_ERROR_OUT_OF_MEMORY: e = GPG_ERR_ENOMEM; break; + case SC_ERROR_CARD_NOT_PRESENT: e = GPG_ERR_CARD_NOT_PRESENT; break; + case SC_ERROR_CARD_REMOVED: e = GPG_ERR_CARD_REMOVED; break; + case SC_ERROR_INVALID_CARD: e = GPG_ERR_INVALID_CARD; break; #endif - default: rc = GNUPG_Card_Error; break; + default: e = GPG_ERR_CARD_ERROR; break; } - return rc; + return gpg_make_error (GPG_ERR_SOURCE_UNKNOWN, e); } /* Get the keygrip from CERT, return 0 on success */ @@ -89,7 +91,7 @@ card_help_get_keygrip (KsbaCert cert, unsigned char *array) information of the card. Detects whgether a PKCS_15 application is stored. - Common errors: GNUPG_Card_Not_Present */ + Common errors: GPG_ERR_CARD_NOT_PRESENT */ int card_open (CARD *rcard) { @@ -99,7 +101,7 @@ card_open (CARD *rcard) card = xtrycalloc (1, sizeof *card); if (!card) - return GNUPG_Out_Of_Core; + return out_of_core (); card->reader = 0; rc = sc_establish_context (&card->ctx, "scdaemon"); @@ -112,7 +114,7 @@ card_open (CARD *rcard) if (card->reader >= card->ctx->reader_count) { log_error ("no card reader available\n"); - rc = GNUPG_Card_Error; + rc = gpg_error (GPG_ERR_CARD_ERROR); goto leave; } card->ctx->error_file = log_get_stream (); @@ -121,7 +123,7 @@ card_open (CARD *rcard) if (sc_detect_card_presence (card->ctx->reader[card->reader], 0) != 1) { - rc = GNUPG_Card_Not_Present; + rc = gpg_error (GPG_ERR_CARD_NOT_PRESENT); goto leave; } @@ -155,7 +157,7 @@ card_open (CARD *rcard) return rc; #else - return GNUPG_Not_Supported; + return gpg_error (GPG_ERR_NOT_SUPPORTED); #endif } @@ -240,7 +242,7 @@ find_iccsn (const unsigned char *buffer, size_t length, char **serial) s = find_simple_tlv (buffer, length, 0x5A, &n); if (!s) - return GNUPG_Card_Error; + return gpg_error (GPG_ERR_CARD_ERROR); length -= s - buffer; if (n > length) { @@ -255,14 +257,16 @@ find_iccsn (const unsigned char *buffer, size_t length, char **serial) n--; } else - return GNUPG_Card_Error; /* Bad encoding; does not fit into buffer. */ + return gpg_error (GPG_ERR_CARD_ERROR); /* Bad encoding; does + not fit into + buffer. */ } if (!n) - return GNUPG_Card_Error; /* Well, that is too short. */ + return gpg_error (GPG_ERR_CARD_ERROR); /* Well, that is too short. */ *serial = p = xtrymalloc (2*n+1); if (!*serial) - return GNUPG_Out_Of_Core; + return out_of_core (); for (; n; n--, p += 2, s++) sprintf (p, "%02X", *s); *p = 0; @@ -290,7 +294,7 @@ card_get_serial_and_stamp (CARD card, char **serial, time_t *stamp) #endif if (!card || !serial || !stamp) - return GNUPG_Invalid_Value; + return gpg_error (GPG_ERR_INV_VALUE); *serial = NULL; *stamp = 0; /* not available */ @@ -328,21 +332,21 @@ card_get_serial_and_stamp (CARD card, char **serial, time_t *stamp) if (rc) { log_error ("sc_select_file failed: %s\n", sc_strerror (rc)); - return GNUPG_Card_Error; + return gpg_error (GPG_ERR_CARD_ERROR); } if (file->type != SC_FILE_TYPE_WORKING_EF || file->ef_structure != SC_FILE_EF_TRANSPARENT) { log_error ("wrong type or structure of GDO file\n"); sc_file_free (file); - return GNUPG_Card_Error; + return gpg_error (GPG_ERR_CARD_ERROR); } if (!file->size || file->size >= DIM(buf) ) { /* FIXME: Use a real parser */ log_error ("unsupported size of GDO file (%d)\n", file->size); sc_file_free (file); - return GNUPG_Card_Error; + return gpg_error (GPG_ERR_CARD_ERROR); } buflen = file->size; @@ -351,16 +355,16 @@ card_get_serial_and_stamp (CARD card, char **serial, time_t *stamp) if (rc < 0) { log_error ("error reading GDO file: %s\n", sc_strerror (rc)); - return GNUPG_Card_Error; + return gpg_error (GPG_ERR_CARD_ERROR); } if (rc != buflen) { log_error ("short read on GDO file\n"); - return GNUPG_Card_Error; + return gpg_error (GPG_ERR_CARD_ERROR); } rc = find_iccsn (buf, buflen, serial); - if (rc == GNUPG_Card_Error) + if (gpg_err_code (rc) == GPG_ERR_CARD_ERROR) log_error ("invalid structure of GDO file\n"); if (!rc && card->p15card && !strcmp (*serial, "D27600000000000000000000")) { /* This is a German card with a silly serial number. Try to get @@ -376,7 +380,7 @@ card_get_serial_and_stamp (CARD card, char **serial, time_t *stamp) *serial = NULL; p = xtrymalloc (strlen (efser) + 7); if (!p) - rc = GNUPG_Out_Of_Core; + rc = out_of_core (); else { strcpy (p, "FF0100"); @@ -392,7 +396,7 @@ card_get_serial_and_stamp (CARD card, char **serial, time_t *stamp) { xfree (*serial); *serial = NULL; - rc = GNUPG_Out_Of_Core; + rc = out_of_core (); } else { @@ -404,7 +408,7 @@ card_get_serial_and_stamp (CARD card, char **serial, time_t *stamp) } return rc; #else - return GNUPG_Not_Supported; + return gpg_error (GPG_ERR_NOT_SUPPORTED); #endif } @@ -415,7 +419,7 @@ card_get_serial_and_stamp (CARD card, char **serial, time_t *stamp) the KEYGRIP of the keypair. If KEYID is not NULL, it returns the ID field of the key in allocated memory; this is a string without spaces. The function returns -1 when all keys have been - enumerated. Note that the error GNUPG_Missing_Certificate may be + enumerated. Note that the error GPG_ERR_MISSING_CERTIFICATE may be returned if there is just the private key but no public key (ie.e a certificate) available. Applications might want to continue enumerating after this error.*/ @@ -430,13 +434,13 @@ card_enum_keypairs (CARD card, int idx, *keyid = NULL; if (!card || !keygrip) - return GNUPG_Invalid_Value; + return gpg_error (GPG_ERR_INV_VALUE); if (idx < 0) - return GNUPG_Invalid_Index; + return gpg_error (GPG_ERR_INVALID_INDEX); if (!card->fnc.initialized) - return GNUPG_Card_Not_Initialized; + return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); if (!card->fnc.enum_keypairs) - return GNUPG_Unsupported_Operation; + return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); rc = card->fnc.enum_keypairs (card, idx, keygrip, keyid); if (opt.verbose) log_info ("card operation enum_keypairs result: %s\n", @@ -462,13 +466,13 @@ card_enum_certs (CARD card, int idx, char **certid, int *certtype) *certid = NULL; if (!card) - return GNUPG_Invalid_Value; + return gpg_error (GPG_ERR_INV_VALUE); if (idx < 0) - return GNUPG_Invalid_Index; + return gpg_error (GPG_ERR_INVALID_INDEX); if (!card->fnc.initialized) - return GNUPG_Card_Not_Initialized; + return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); if (!card->fnc.enum_certs) - return GNUPG_Unsupported_Operation; + return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); rc = card->fnc.enum_certs (card, idx, certid, certtype); if (opt.verbose) log_info ("card operation enum_certs result: %s\n", @@ -489,11 +493,11 @@ card_read_cert (CARD card, const char *certidstr, int rc; if (!card || !certidstr || !cert || !ncert) - return GNUPG_Invalid_Value; + return gpg_error (GPG_ERR_INV_VALUE); if (!card->fnc.initialized) - return GNUPG_Card_Not_Initialized; + return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); if (!card->fnc.read_cert) - return GNUPG_Unsupported_Operation; + return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); rc = card->fnc.read_cert (card, certidstr, cert, ncert); if (opt.verbose) log_info ("card operation read_cert result: %s\n", gnupg_strerror (rc)); @@ -514,11 +518,11 @@ card_sign (CARD card, const char *keyidstr, int hashalgo, int rc; if (!card || !indata || !indatalen || !outdata || !outdatalen || !pincb) - return GNUPG_Invalid_Value; + return gpg_error (GPG_ERR_INV_VALUE); if (!card->fnc.initialized) - return GNUPG_Card_Not_Initialized; + return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); if (!card->fnc.sign) - return GNUPG_Unsupported_Operation; + return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); rc = card->fnc.sign (card, keyidstr, hashalgo, pincb, pincb_arg, indata, indatalen, @@ -542,11 +546,11 @@ card_decipher (CARD card, const char *keyidstr, int rc; if (!card || !indata || !indatalen || !outdata || !outdatalen || !pincb) - return GNUPG_Invalid_Value; + return gpg_error (GPG_ERR_INV_VALUE); if (!card->fnc.initialized) - return GNUPG_Card_Not_Initialized; + return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); if (!card->fnc.decipher) - return GNUPG_Unsupported_Operation; + return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION); rc = card->fnc.decipher (card, keyidstr, pincb, pincb_arg, indata, indatalen, diff --git a/scd/command.c b/scd/command.c index d0bbbc518..329fb4d2f 100644 --- a/scd/command.c +++ b/scd/command.c @@ -233,7 +233,7 @@ cmd_learn (ASSUAN_CONTEXT ctx, char *line) buf = xtrymalloc (40 + 1 + strlen (certid) + 1); if (!buf) - rc = GNUPG_Out_Of_Core; + rc = out_of_core (); else { sprintf (buf, "%d %s", certtype, certid); @@ -255,7 +255,7 @@ cmd_learn (ASSUAN_CONTEXT ctx, char *line) int no_cert = 0; rc = card_enum_keypairs (ctrl->card_ctx, idx, keygrip, &keyid); - if (rc == GNUPG_Missing_Certificate && keyid) + if (gpg_err_code (rc) == GPG_ERR_MISSING_CERT && keyid) { /* this does happen with an incomplete personalized card; i.e. during the time we have stored the key on the @@ -271,7 +271,7 @@ cmd_learn (ASSUAN_CONTEXT ctx, char *line) buf = p = xtrymalloc (40 + 1 + strlen (keyid) + 1); if (!buf) - rc = GNUPG_Out_Of_Core; + rc = out_of_core (); else { int i; @@ -358,8 +358,8 @@ cmd_readkey (ASSUAN_CONTEXT ctx, char *line) kc = ksba_cert_new (); if (!kc) { + rc = out_of_core (); xfree (cert); - rc = GNUPG_Out_Of_Core; goto leave; } rc = ksba_cert_init_from_mem (kc, cert, ncert); @@ -373,7 +373,7 @@ cmd_readkey (ASSUAN_CONTEXT ctx, char *line) p = ksba_cert_get_public_key (kc); if (!p) { - rc = GNUPG_No_Public_Key; + rc = gpg_error (GPG_ERR_NO_PUBKEY); goto leave; } @@ -439,7 +439,7 @@ pin_cb (void *opaque, const char *info, char **retstr) rc = asprintf (&command, "NEEDPIN %s", info); if (rc < 0) - return GNUPG_Out_Of_Core; + return out_of_core (); /* FIXME: Write an inquire function which returns the result in secure memory */ @@ -452,7 +452,7 @@ pin_cb (void *opaque, const char *info, char **retstr) { /* We require that the returned value is an UTF-8 string */ xfree (value); - return GNUPG_Invalid_Response; + return gpg_error (GPG_ERR_INVALID_RESPONSE); } *retstr = value; return 0; diff --git a/scd/scdaemon.c b/scd/scdaemon.c index 902324ad7..5ab50a5b4 100644 --- a/scd/scdaemon.c +++ b/scd/scdaemon.c @@ -69,7 +69,6 @@ enum cmd_and_opt_values oDaemon, oBatch, oReaderPort, - oPrintATR, aTest }; @@ -93,7 +92,6 @@ 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", 1, N_("|N|connect to reader at port N")}, - { oPrintATR, "print-atr", 0, N_("print ATR and exit")}, {0} }; @@ -233,9 +231,6 @@ main (int argc, char **argv ) char *logfile = NULL; int debug_wait = 0; int reader_port = 32768; /* First USB reader. */ - int print_atr = 0; - - set_strusage (my_strusage); gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN); @@ -371,7 +366,6 @@ main (int argc, char **argv ) case oDaemon: is_daemon = 1; break; case oReaderPort: reader_port = pargs.r.ret_int; break; - case oPrintATR: print_atr = 1; break; default : pargs.err = configfp? 1:2; break; } @@ -410,12 +404,6 @@ main (int argc, char **argv ) } - if (print_atr) - { - apdu_open_reader (reader_port); - scd_exit (0); - } - if (debug_wait && pipe_server) { log_debug ("waiting for debugger - my pid is %u .....\n", diff --git a/scd/scdaemon.h b/scd/scdaemon.h index 9fbf891bb..59d40e519 100644 --- a/scd/scdaemon.h +++ b/scd/scdaemon.h @@ -1,5 +1,5 @@ /* scdaemon.h - Global definitions for the SCdaemon - * Copyright (C) 2001, 2002 Free Software Foundation, Inc. + * Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -21,11 +21,27 @@ #ifndef SCDAEMON_H #define SCDAEMON_H +#ifdef GPG_ERR_SOURCE_DEFAULT +#error GPG_ERR_SOURCE_DEFAULT already defined +#endif +#define GPG_ERR_SOURCE_DEFAULT GPG_ERR_SOURCE_SCD +#include <gpg-error.h> +#include <errno.h> + #include <time.h> #include <gcrypt.h> #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 /* A large struct name "opt" to keep global flags */ @@ -48,6 +64,7 @@ struct { #define DBG_MEMSTAT_VALUE 128 /* show memory statistics */ #define DBG_HASHING_VALUE 512 /* debug hashing operations */ #define DBG_ASSUAN_VALUE 1024 +#define DBG_CARD_IO_VALUE 2048 #define DBG_COMMAND (opt.debug & DBG_COMMAND_VALUE) #define DBG_CRYPTO (opt.debug & DBG_CRYPTO_VALUE) @@ -55,6 +72,7 @@ struct { #define DBG_CACHE (opt.debug & DBG_CACHE_VALUE) #define DBG_HASHING (opt.debug & DBG_HASHING_VALUE) #define DBG_ASSUAN (opt.debug & DBG_ASSUAN_VALUE) +#define DBG_CARD_IO (opt.debug & DBG_CARD_IO_VALUE) struct server_local_s; struct card_ctx_s; |