summaryrefslogtreecommitdiffstats
path: root/scd
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2002-03-04 11:34:09 +0100
committerWerner Koch <wk@gnupg.org>2002-03-04 11:34:09 +0100
commitf8efc7c4ef65a9ec76353247aae837134ad13756 (patch)
tree1aaaab451e9237957dcf366a5f95dc09824208ec /scd
parentChanges needed to support smartcards. Well, only _support_. There is (diff)
downloadgnupg2-f8efc7c4ef65a9ec76353247aae837134ad13756.tar.xz
gnupg2-f8efc7c4ef65a9ec76353247aae837134ad13756.zip
Added more code fragments.
Diffstat (limited to 'scd')
-rw-r--r--scd/card.c110
-rw-r--r--scd/command.c135
-rw-r--r--scd/scdaemon.h4
3 files changed, 220 insertions, 29 deletions
diff --git a/scd/card.c b/scd/card.c
index dbfbe5333..543812d51 100644
--- a/scd/card.c
+++ b/scd/card.c
@@ -359,6 +359,28 @@ card_enum_keypairs (CARD card, int idx,
+static int
+idstr_to_id (const char *idstr, struct sc_pkcs15_id *id)
+{
+ const char *s;
+ int n;
+
+ /* For now we only support the standard DF */
+ if (strncmp (idstr, "3F005015.", 9) )
+ return GNUPG_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 */
+ n /= 2;
+ if (!n || n > SC_PKCS15_MAX_ID_SIZE)
+ return GNUPG_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;
+ return 0;
+}
+
/* Read the certificate identified by CERTIDSTR which is the
hexadecimal encoded ID of the certificate, prefixed with the string
"3F005015.". The certificate is return in DER encoded form in CERT
@@ -370,25 +392,14 @@ card_read_cert (CARD card, const char *certidstr,
struct sc_pkcs15_id certid;
struct sc_pkcs15_cert_info *certinfo;
struct sc_pkcs15_cert *certder;
- const char *s;
- int rc, n;
+ int rc;
if (!card || !certidstr || !card->p15card || !cert || !ncert)
return GNUPG_Invalid_Value;
- /* For now we only support the standard DF */
- if (strncmp (certidstr, "3F005015.", 9) )
- return GNUPG_Invalid_Id;
- for (s=certidstr+9, n=0; hexdigitp (s); s++, n++)
- ;
- if (*s || (n&1))
- return GNUPG_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 */
- for (s=certidstr+9, n=0; *s; s += 2, n++)
- certid.value[n] = xtoi_2 (s);
- certid.len = n;
+ rc = idstr_to_id (certidstr, &certid);
+ if (rc)
+ return rc;
rc = sc_pkcs15_find_cert_by_id (card->p15card, &certid, &certinfo);
if (rc)
@@ -418,6 +429,75 @@ card_read_cert (CARD card, const char *certidstr,
}
+
+/* Create the signature and return the allocated result in OUTDATA. */
+int
+card_create_signature (CARD card, const char *keyidstr, int hashalgo,
+ const void *indata, size_t indatalen,
+ void **outdata, size_t *outdatalen )
+{
+ unsigned int cryptflags = 0;
+ struct sc_pkcs15_id keyid;
+ struct sc_pkcs15_prkey_info *key;
+ /* struct sc_pkcs15_pin_info *pin;*/
+ int rc;
+ unsigned char *outbuf = NULL;
+ size_t outbuflen;
+
+ if (!card || !card->p15card || !indata || !indatalen
+ || !outdata || !outdatalen)
+ return GNUPG_Invalid_Value;
+
+ if (hashalgo != GCRY_MD_SHA1)
+ return GNUPG_Unsupported_Algorithm;
+
+ rc = idstr_to_id (keyidstr, &keyid);
+ if (rc)
+ return rc;
+
+ rc = sc_pkcs15_find_prkey_by_id (card->p15card, &keyid, &key);
+ if (rc < 0)
+ {
+ log_error ("private key not found: %s\n", sc_strerror(rc));
+ rc = GNUPG_No_Secret_Key;
+ goto leave;
+ }
+ rc = 0;
+ key = card->p15card->prkey_info;
+
+
+ /* FIXME: Handle PIN via callback */
+
+ cryptflags |= SC_PKCS15_HASH_SHA1;
+ cryptflags |= SC_PKCS15_PAD_PKCS1_V1_5;
+ outbuflen = 1024;
+ outbuf = xtrymalloc (outbuflen);
+ if (!outbuf)
+ return GNUPG_Out_Of_Core;
+
+ rc = sc_pkcs15_compute_signature (card->p15card, key,
+ cryptflags,
+ indata, indatalen,
+ outbuf, outbuflen );
+ if (rc < 0)
+ {
+ log_error ("failed to create signature: %s\n", sc_strerror (rc));
+ rc = GNUPG_Card_Error;
+ }
+ else
+ {
+ *outdatalen = rc;
+ *outdata = outbuf;
+ outbuf = NULL;
+ rc = 0;
+ }
+
+
+
+leave:
+ xfree (outbuf);
+ return rc;
+}
diff --git a/scd/command.c b/scd/command.c
index b4eaa8a47..e17248439 100644
--- a/scd/command.c
+++ b/scd/command.c
@@ -61,6 +61,8 @@ reset_notify (ASSUAN_CONTEXT ctx)
{
card_close (ctrl->card_ctx);
ctrl->card_ctx = NULL;
+ xfree (ctrl->in_data.value);
+ ctrl->in_data.value = NULL;
}
}
@@ -72,6 +74,63 @@ 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
+open_card (CTRL ctrl)
+{
+ if (!ctrl->card_ctx)
+ {
+ int rc = card_open (&ctrl->card_ctx);
+ if (rc)
+ return map_to_assuan_status (rc);
+ }
+ return 0;
+}
+
+
+/* SERIALNO
+
+ Return the serial number of the card using a status reponse. This
+ functon should be used to check for the presence of a card.
+
+ 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.
+
+ Background: We want to keep the client clear of handling card
+ changes between operations; i.e. the client can assume that all
+ operations are doneon the same card unless he call this function.
+ */
+static int
+cmd_serialno (ASSUAN_CONTEXT ctx, char *line)
+{
+ CTRL ctrl = assuan_get_pointer (ctx);
+ int rc = 0;
+ char *serial_and_stamp;
+ char *serial;
+ time_t stamp;
+
+ if ((rc = open_card (ctrl)))
+ return rc;
+
+ rc = card_get_serial_and_stamp (ctrl->card_ctx, &serial, &stamp);
+ if (rc)
+ return map_to_assuan_status (rc);
+ rc = asprintf (&serial_and_stamp, "%s %lu", serial, (unsigned long)stamp);
+ xfree (serial);
+ if (rc < 0)
+ return ASSUAN_Out_Of_Core;
+ rc = 0;
+ assuan_write_status (ctx, "SERIALNO", serial_and_stamp);
+ free (serial_and_stamp);
+ return 0;
+}
+
+
+
+
/* LEARN [--force]
Learn all useful information of the currently inserted card. When
@@ -98,14 +157,8 @@ cmd_learn (ASSUAN_CONTEXT ctx, char *line)
int rc = 0;
int idx;
- /* if this is the first command issued for a new card, open the card and
- and create a context */
- if (!ctrl->card_ctx)
- {
- rc = card_open (&ctrl->card_ctx);
- if (rc)
- return map_to_assuan_status (rc);
- }
+ if ((rc = open_card (ctrl)))
+ return rc;
/* Unless the force option is used we try a shortcut by identifying
the card using a serial number and inquiring the client with
@@ -221,12 +274,8 @@ cmd_readcert (ASSUAN_CONTEXT ctx, char *line)
unsigned char *cert;
size_t ncert;
- if (!ctrl->card_ctx)
- {
- rc = card_open (&ctrl->card_ctx);
- if (rc)
- return map_to_assuan_status (rc);
- }
+ if ((rc = open_card (ctrl)))
+ return rc;
rc = card_read_cert (ctrl->card_ctx, line, &cert, &ncert);
if (rc)
@@ -244,6 +293,61 @@ cmd_readcert (ASSUAN_CONTEXT ctx, char *line)
return map_to_assuan_status (rc);
}
+
+
+
+/* SETDATA <hexstring>
+
+ The client should use this command to tell us the data he want to
+ sign. */
+static int
+cmd_setdata (ASSUAN_CONTEXT ctx, char *line)
+{
+ CTRL ctrl = assuan_get_pointer (ctx);
+ int n;
+ char *p;
+ unsigned char *buf;
+
+ /* parse the hexstring */
+ for (p=line,n=0; hexdigitp (p); p++, n++)
+ ;
+ if (*p)
+ return set_error (Parameter_Error, "invalid hexstring");
+ if ((n&1))
+ return set_error (Parameter_Error, "odd number of digits");
+ n /= 2;
+ buf = xtrymalloc (n);
+ if (!buf)
+ return ASSUAN_Out_Of_Core;
+
+ ctrl->in_data.value = buf;
+ ctrl->in_data.valuelen = n;
+ for (p=line, n=0; n < ctrl->in_data.valuelen; p += 2, n++)
+ buf[n] = xtoi_2 (p);
+ return 0;
+}
+
+
+
+/* PKSIGN <hexified_id>
+
+ */
+static int
+cmd_pksign (ASSUAN_CONTEXT ctx, char *line)
+{
+ CTRL ctrl = assuan_get_pointer (ctx);
+ int rc;
+
+ if ((rc = open_card (ctrl)))
+ return rc;
+
+
+
+ return map_to_assuan_status (rc);
+}
+
+
+
/* Tell the assuan library about our commands */
static int
@@ -254,8 +358,11 @@ register_commands (ASSUAN_CONTEXT ctx)
int cmd_id;
int (*handler)(ASSUAN_CONTEXT, char *line);
} table[] = {
+ { "SERIALNO", 0, cmd_serialno },
{ "LEARN", 0, cmd_learn },
{ "READCERT", 0, cmd_readcert },
+ { "SETDATA", 0, cmd_setdata },
+ { "PKSIGN", 0, cmd_pksign },
{ "", ASSUAN_CMD_INPUT, NULL },
{ "", ASSUAN_CMD_OUTPUT, NULL },
{ NULL }
diff --git a/scd/scdaemon.h b/scd/scdaemon.h
index e77012416..4104e8753 100644
--- a/scd/scdaemon.h
+++ b/scd/scdaemon.h
@@ -61,6 +61,10 @@ struct card_ctx_s;
struct server_control_s {
struct server_local_s *server_local;
struct card_ctx_s *card_ctx;
+ struct {
+ unsigned char *value;
+ int valuelen;
+ } in_data; /* helper to store the value we are going to sign */
};
typedef struct server_control_s *CTRL;