aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--scd/ChangeLog22
-rw-r--r--scd/card-dinsig.c2
-rw-r--r--scd/card-p15.c3
-rw-r--r--scd/card.c179
-rw-r--r--scd/scdaemon.c4
5 files changed, 158 insertions, 52 deletions
diff --git a/scd/ChangeLog b/scd/ChangeLog
index b06603315..e0cfda805 100644
--- a/scd/ChangeLog
+++ b/scd/ChangeLog
@@ -1,3 +1,25 @@
+2002-08-09 Werner Koch <[email protected]>
+
+ * card.c (card_get_serial_and_stamp): Use the tokeinfo serial
+ number as a fallback. Add a special prefix for serial numbers.
+
+2002-07-30 Werner Koch <[email protected]>
+
+ Changes to cope with OpenSC 0.7.0:
+
+ * card.c: Removed the check for the packed opensc version.
+ Changed include file names of opensc.
+ (map_sc_err): Adjusted error codes for new opensc version.
+ * card-p15.c: Changed include filename of opensc.
+ * card-dinsig.c: Ditto.
+
+ * card-p15.c (p15_decipher): Add flags argument to OpenSC call.
+
+2002-07-24 Werner Koch <[email protected]>
+
+ * card.c (find_simple_tlv, find_iccsn): New.
+ (card_get_serial_and_stamp): Improved serial number parser.
+
2002-06-27 Werner Koch <[email protected]>
* scdaemon.c (main): Use GNUPG_DEFAULT_HOMEDIR constant.
diff --git a/scd/card-dinsig.c b/scd/card-dinsig.c
index 4080350c6..161d5dbfc 100644
--- a/scd/card-dinsig.c
+++ b/scd/card-dinsig.c
@@ -77,7 +77,7 @@
#include <string.h>
#include <time.h>
-#include <opensc-pkcs15.h>
+#include <opensc/pkcs15.h>
#include <ksba.h>
#include "scdaemon.h"
diff --git a/scd/card-p15.c b/scd/card-p15.c
index a70bc665e..6248ddfe2 100644
--- a/scd/card-p15.c
+++ b/scd/card-p15.c
@@ -25,7 +25,7 @@
#include <string.h>
#include <time.h>
-#include <opensc-pkcs15.h>
+#include <opensc/pkcs15.h>
#include <ksba.h>
#include "scdaemon.h"
@@ -345,6 +345,7 @@ p15_decipher (CARD card, const char *keyidstr,
return GNUPG_Out_Of_Core;
rc = sc_pkcs15_decipher (card->p15card, keyobj,
+ 0,
indata, indatalen,
outbuf, outbuflen);
if (rc < 0)
diff --git a/scd/card.c b/scd/card.c
index d17ae1947..9c22867a1 100644
--- a/scd/card.c
+++ b/scd/card.c
@@ -25,13 +25,9 @@
#include <string.h>
#include <time.h>
-#include <opensc-pkcs15.h>
+#include <opensc/pkcs15.h>
#include <ksba.h>
-#if SC_MAX_SEC_ATTR_SIZE < 36
-# error This is not the patched OpenSC version
-#endif
-
#include "scdaemon.h"
#include "card-common.h"
@@ -42,38 +38,12 @@ map_sc_err (int rc)
switch (rc)
{
case 0: rc = 0; break;
- case SC_ERROR_CMD_TOO_SHORT: rc = GNUPG_Card_Error; break;
- case SC_ERROR_CMD_TOO_LONG: rc = GNUPG_Card_Error; break;
case SC_ERROR_NOT_SUPPORTED: rc = GNUPG_Not_Supported; break;
- case SC_ERROR_TRANSMIT_FAILED: rc = GNUPG_Card_Error; break;
- case SC_ERROR_FILE_NOT_FOUND: rc = GNUPG_Card_Error; break;
- case SC_ERROR_INVALID_ARGUMENTS: rc = GNUPG_Card_Error; break;
case SC_ERROR_PKCS15_APP_NOT_FOUND: rc = GNUPG_No_PKCS15_App; break;
- case SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND: rc = GNUPG_Card_Error; break;
case SC_ERROR_OUT_OF_MEMORY: rc = GNUPG_Out_Of_Core; break;
- case SC_ERROR_NO_READERS_FOUND: rc = GNUPG_Card_Error; break;
- case SC_ERROR_OBJECT_NOT_VALID: rc = GNUPG_Card_Error; break;
- case SC_ERROR_ILLEGAL_RESPONSE: rc = GNUPG_Card_Error; break;
- case SC_ERROR_PIN_CODE_INCORRECT: rc = GNUPG_Card_Error; break;
- case SC_ERROR_SECURITY_STATUS_NOT_SATISFIED: rc = GNUPG_Card_Error; break;
- case SC_ERROR_CONNECTING_TO_RES_MGR: rc = GNUPG_Card_Error; break;
- case SC_ERROR_INVALID_ASN1_OBJECT: rc = GNUPG_Card_Error; break;
- case SC_ERROR_BUFFER_TOO_SMALL: rc = GNUPG_Card_Error; break;
case SC_ERROR_CARD_NOT_PRESENT: rc = GNUPG_Card_Not_Present; break;
- case SC_ERROR_RESOURCE_MANAGER: rc = GNUPG_Card_Error; break;
case SC_ERROR_CARD_REMOVED: rc = GNUPG_Card_Removed; break;
- case SC_ERROR_INVALID_PIN_LENGTH: rc = GNUPG_Card_Error; break;
- case SC_ERROR_UNKNOWN_SMARTCARD: rc = GNUPG_Card_Error; break;
- case SC_ERROR_UNKNOWN_REPLY: rc = GNUPG_Card_Error; break;
- case SC_ERROR_OBJECT_NOT_FOUND: rc = GNUPG_Card_Error; break;
- case SC_ERROR_CARD_RESET: rc = GNUPG_Card_Reset; break;
- case SC_ERROR_ASN1_OBJECT_NOT_FOUND: rc = GNUPG_Card_Error; break;
- case SC_ERROR_ASN1_END_OF_CONTENTS: rc = GNUPG_Card_Error; break;
- case SC_ERROR_TOO_MANY_OBJECTS: rc = GNUPG_Card_Error; break;
case SC_ERROR_INVALID_CARD: rc = GNUPG_Invalid_Card; break;
- case SC_ERROR_WRONG_LENGTH: rc = GNUPG_Card_Error; break;
- case SC_ERROR_RECORD_NOT_FOUND: rc = GNUPG_Card_Error; break;
- case SC_ERROR_INTERNAL: rc = GNUPG_Card_Error; break;
default: rc = GNUPG_Card_Error; break;
}
return rc;
@@ -207,6 +177,84 @@ card_close (CARD card)
}
}
+/* Locate a simple 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. */
+static const char *
+find_simple_tlv (const unsigned char *buffer, size_t length,
+ int tag, size_t *nbytes)
+{
+ const char *s = buffer;
+ size_t n = length;
+ size_t len;
+
+ for (;;)
+ {
+ buffer = s;
+ if (n < 2)
+ return NULL; /* buffer too short for tag and length. */
+ len = s[1];
+ s += 2; n -= 2;
+ if (len == 255)
+ {
+ if (n < 2)
+ return NULL; /* we expected 2 more bytes with the length. */
+ len = (s[0] << 8) | s[1];
+ s += 2; n -= 2;
+ }
+ if (*buffer == tag)
+ {
+ *nbytes = len;
+ return s;
+ }
+ if (len > n)
+ return NULL; /* buffer too short to skip to the next tag. */
+ s += len; n -= len;
+ }
+}
+
+/* Find the ICC Serial Number within the provided BUFFER of LENGTH
+ (which should contain the GDO file) and return it as a hex encoded
+ string and allocated string in SERIAL. Return an error code when
+ the ICCSN was not found. */
+static int
+find_iccsn (const unsigned char *buffer, size_t length, char **serial)
+{
+ size_t n;
+ const unsigned char *s;
+ char *p;
+
+ s = find_simple_tlv (buffer, length, 0x5A, &n);
+ if (!s)
+ return GNUPG_Card_Error;
+ length -= s - buffer;
+ if (n > length)
+ {
+ /* Oops, 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. */
+ if (n == 0x0D && length+1 == n)
+ {
+ log_debug ("enabling BMI testcard workaround\n");
+ n--;
+ }
+ else
+ return GNUPG_Card_Error; /* Bad encoding; does not fit into buffer. */
+ }
+ if (!n)
+ return GNUPG_Card_Error; /* Well, that is too short. */
+
+ *serial = p = xtrymalloc (2*n+1);
+ if (!*serial)
+ return GNUPG_Out_Of_Core;
+ for (; n; n--, p += 2, s++)
+ sprintf (p, "%02X", *s);
+ *p = 0;
+ return 0;
+}
/* Retrieve the serial number and the time of the last update of the
@@ -220,12 +268,11 @@ card_close (CARD card)
int
card_get_serial_and_stamp (CARD card, char **serial, time_t *stamp)
{
- char *s;
int rc;
struct sc_path path;
struct sc_file *file;
- unsigned char buf[12];
- int i;
+ unsigned char buf[256];
+ int buflen;
if (!card || !serial || !stamp)
return GNUPG_Invalid_Value;
@@ -274,36 +321,72 @@ card_get_serial_and_stamp (CARD card, char **serial, time_t *stamp)
sc_file_free (file);
return GNUPG_Card_Error;
}
- if (file->size != 12)
+
+ if (!file->size || file->size >= DIM(buf) )
{ /* FIXME: Use a real parser */
- log_error ("unsupported size of GDO file\n");
+ log_error ("unsupported size of GDO file (%d)\n", file->size);
sc_file_free (file);
return GNUPG_Card_Error;
}
+ buflen = file->size;
- rc = sc_read_binary (card->scard, 0, buf, DIM (buf), 0);
+ rc = sc_read_binary (card->scard, 0, buf, buflen, 0);
sc_file_free (file);
if (rc < 0)
{
log_error ("error reading GDO file: %s\n", sc_strerror (rc));
return GNUPG_Card_Error;
}
- if (rc != file->size)
+ if (rc != buflen)
{
log_error ("short read on GDO file\n");
return GNUPG_Card_Error;
}
- if (buf[0] != 0x5a || buf[1] != 10)
- {
- log_error ("invalid structure of GDO file\n");
- return GNUPG_Card_Error;
+
+ rc = find_iccsn (buf, buflen, serial);
+ if (rc == GNUPG_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
+ the serial number from the EF(TokenInfo). We indicate such a
+ serial number by the using the prefix: "FF0100". */
+ const char *efser = card->p15card->serial_number;
+ char *p;
+
+ if (!efser)
+ efser = "";
+
+ xfree (*serial);
+ *serial = NULL;
+ p = xtrymalloc (strlen (efser) + 7);
+ if (!p)
+ rc = GNUPG_Out_Of_Core;
+ else
+ {
+ strcpy (p, "FF0100");
+ strcpy (p+6, efser);
+ *serial = p;
+ }
}
- *serial = s = xtrymalloc (21);
- if (!*serial)
- return GNUPG_Out_Of_Core;
- for (i=0; i < 10; i++, s += 2)
- sprintf (s, "%02X", buf[2+i]);
- return 0;
+ else if (!rc && **serial == 'F' && (*serial)[1] == 'F')
+ { /* The serial number starts with our special prefix. This
+ requires that we put our default prefix "FF0000" in front. */
+ char *p = xtrymalloc (strlen (*serial) + 7);
+ if (!p)
+ {
+ xfree (*serial);
+ *serial = NULL;
+ rc = GNUPG_Out_Of_Core;
+ }
+ else
+ {
+ strcpy (p, "FF0000");
+ strcpy (p+6, *serial);
+ xfree (*serial);
+ *serial = p;
+ }
+ }
+ return rc;
}
diff --git a/scd/scdaemon.c b/scd/scdaemon.c
index d1402b5ee..1d8bad21d 100644
--- a/scd/scdaemon.c
+++ b/scd/scdaemon.c
@@ -87,9 +87,9 @@ static ARGPARSE_OPTS opts[] = {
{ oDebug, "debug" ,4|16, N_("set debugging flags")},
{ oDebugAll, "debug-all" ,0, N_("enable full debugging")},
{ oDebugWait,"debug-wait",1, "@"},
- { oDebugSC, "debug-sc", 1, N_("N|set OpenSC debug level to N")},
+ { 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")},
+ { oLogFile, "log-file" ,2, N_("use a log file for the server")},
{0}