mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-03 12:11:33 +01:00
Some experimental code - don't use it.
This commit is contained in:
parent
1df38417a3
commit
49b3340e0f
@ -25,7 +25,7 @@ LDFLAGS = @LDFLAGS@
|
||||
|
||||
scdaemon_SOURCES = \
|
||||
scdaemon.c scdaemon.h \
|
||||
command.c
|
||||
command.c card.c
|
||||
|
||||
|
||||
scdaemon_LDADD = ../jnlib/libjnlib.a ../assuan/libassuan.a \
|
||||
|
221
scd/card.c
Normal file
221
scd/card.c
Normal file
@ -0,0 +1,221 @@
|
||||
/* card.c - SCdaemon card functions
|
||||
* Copyright (C) 2002 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 <config.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <opensc-pkcs15.h>
|
||||
|
||||
#include "scdaemon.h"
|
||||
|
||||
|
||||
|
||||
struct card_ctx_s {
|
||||
int reader; /* used reader */
|
||||
struct sc_context *ctx;
|
||||
struct sc_card *scard;
|
||||
struct sc_pkcs15_card *p15card; /* only if there is a pkcs15 application */
|
||||
|
||||
};
|
||||
|
||||
/* Map the SC error codes to the GNUPG ones */
|
||||
static int
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/* Create a new context for the card and figures out some basic
|
||||
information of the card. Detects whether a PKCS_15 application is
|
||||
stored.
|
||||
|
||||
Common errors: GNUPG_Card_Not_Present */
|
||||
int
|
||||
card_open (CARD *rcard)
|
||||
{
|
||||
CARD card;
|
||||
int rc;
|
||||
|
||||
card = xtrycalloc (1, sizeof *card);
|
||||
if (!card)
|
||||
return GNUPG_Out_Of_Core;
|
||||
card->reader = 0;
|
||||
|
||||
rc = sc_establish_context (&card->ctx);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("failed to establish SC context: %s\n", sc_strerror (rc));
|
||||
rc = map_sc_err (rc);
|
||||
goto leave;
|
||||
}
|
||||
if (card->reader >= card->ctx->reader_count)
|
||||
{
|
||||
log_error ("no card reader available\n");
|
||||
rc = GNUPG_Card_Error;
|
||||
}
|
||||
card->ctx->error_file = log_get_stream ();
|
||||
card->ctx->debug_file = log_get_stream ();
|
||||
if (sc_detect_card (card->ctx, card->reader) != 1)
|
||||
{
|
||||
rc = GNUPG_Card_Not_Present;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
rc = sc_connect_card (card->ctx, card->reader, &card->scard);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("failed to connect card in reader %d: %s\n",
|
||||
card->reader, sc_strerror (rc));
|
||||
rc = map_sc_err (rc);
|
||||
goto leave;
|
||||
}
|
||||
if (opt.verbose)
|
||||
log_info ("connected to card in reader %d using driver `%s'\n",
|
||||
card->reader, card->scard->driver->name);
|
||||
|
||||
rc = sc_lock (card->scard);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("can't lock card in reader %d: %s\n",
|
||||
card->reader, sc_strerror (rc));
|
||||
rc = map_sc_err (rc);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
rc = sc_pkcs15_bind (card->scard, &card->p15card);
|
||||
if (rc == SC_ERROR_PKCS15_APP_NOT_FOUND)
|
||||
rc = 0; /* okay */
|
||||
else if (rc)
|
||||
{
|
||||
log_error ("binding of existing PKCS-15 failed in reader %d: %s\n",
|
||||
card->reader, sc_strerror (rc));
|
||||
rc = map_sc_err (rc);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
leave:
|
||||
if (rc)
|
||||
card_close (card);
|
||||
else
|
||||
*rcard = card;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* Close a card and release all resources */
|
||||
void
|
||||
card_close (CARD card)
|
||||
{
|
||||
if (card)
|
||||
{
|
||||
if (card->p15card)
|
||||
{
|
||||
sc_pkcs15_unbind (card->p15card);
|
||||
card->p15card = NULL;
|
||||
}
|
||||
if (card->scard)
|
||||
{
|
||||
sc_unlock (card->scard);
|
||||
sc_disconnect_card (card->scard);
|
||||
card->scard = NULL;
|
||||
}
|
||||
if (card->ctx)
|
||||
{
|
||||
sc_destroy_context (card->ctx);
|
||||
card->ctx = NULL;
|
||||
}
|
||||
xfree (card);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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. The serial
|
||||
is mandatory for a PKCS_15 application and an error will be
|
||||
returned if this value is not availbale. For non-PKCS-15 cards a
|
||||
serial number is constructed by other means. Caller must free
|
||||
SERIAL unless the fucntion returns an error. */
|
||||
int
|
||||
card_get_serial_and_stamp (CARD card, char **serial, time_t *stamp)
|
||||
{
|
||||
char *s;
|
||||
|
||||
if (!card || !serial || !stamp)
|
||||
return GNUPG_Invalid_Value;
|
||||
|
||||
*serial = NULL;
|
||||
*stamp = 0; /* not available */
|
||||
if (!card->p15card)
|
||||
{ /* fixme: construct a serial number */
|
||||
/* We should lookup the iso 7812-1 and 8583-3 - argh ISO practice is
|
||||
suppressing innovation - IETF rules! */
|
||||
return GNUPG_No_PKCS15_App;
|
||||
}
|
||||
s = card->p15card->serial_number;
|
||||
if (!s || !hexdigitp (s) )
|
||||
return GNUPG_Invalid_Card; /* the serial number is mandatory */
|
||||
*serial = xstrdup (s);
|
||||
if (!*serial)
|
||||
return GNUPG_Out_Of_Core;
|
||||
return 0;
|
||||
}
|
@ -18,9 +18,6 @@
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
/* FIXME: we should not use the default assuan buffering but setup
|
||||
some buffering in secure mempory to protect session keys etc. */
|
||||
|
||||
#include <config.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
@ -40,32 +37,103 @@ struct server_local_s {
|
||||
};
|
||||
|
||||
|
||||
/* Check whether the option NAME appears in LINE */
|
||||
static int
|
||||
has_option (const char *line, const char *name)
|
||||
{
|
||||
const char *s;
|
||||
int n = strlen (name);
|
||||
|
||||
s = strstr (line, name);
|
||||
return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Note, that this reset_notify is also used for cleanup purposes. */
|
||||
static void
|
||||
reset_notify (ASSUAN_CONTEXT ctx)
|
||||
{
|
||||
/* CTRL ctrl = assuan_get_pointer (ctx); */
|
||||
|
||||
CTRL ctrl = assuan_get_pointer (ctx);
|
||||
|
||||
if (ctrl->card_ctx)
|
||||
{
|
||||
card_close (ctrl->card_ctx);
|
||||
ctrl->card_ctx = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
option_handler (ASSUAN_CONTEXT ctx, const char *key, const char *value)
|
||||
{
|
||||
/* CTRL ctrl = assuan_get_pointer (ctx); */
|
||||
|
||||
/* if (!strcmp (key, "foo")) */
|
||||
/* { */
|
||||
/* } */
|
||||
/* else */
|
||||
/* return ASSUAN_Invalid_Option; */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* LEARN [--force]
|
||||
|
||||
Learn all useful information of the currently inserted card. When
|
||||
used without the force options, the command might to an INQUIRE
|
||||
like this:
|
||||
|
||||
INQUIRE KNOWNCARDP <hexstring_with_serialNumber> <timestamp>
|
||||
|
||||
The client should just send an "END" if the processing should go on
|
||||
or a "CANCEL" to force the function to terminate with a Cancel
|
||||
error message.
|
||||
|
||||
*/
|
||||
static int
|
||||
cmd_learn (ASSUAN_CONTEXT ctx, char *line)
|
||||
{
|
||||
CTRL ctrl = assuan_get_pointer (ctx);
|
||||
int rc = 0;
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* Unless the force option is used we try a shortcut by identifying
|
||||
the card using a serial number and inquiring the client with
|
||||
that. The client may choose to cancel the operation if he already
|
||||
knows about this card */
|
||||
if (!has_option (line, "--force"))
|
||||
{
|
||||
char *serial;
|
||||
time_t stamp;
|
||||
char *command;
|
||||
|
||||
rc = card_get_serial_and_stamp (ctrl->card_ctx, &serial, &stamp);
|
||||
if (rc)
|
||||
return map_to_assuan_status (rc);
|
||||
|
||||
rc = asprintf (&command, "KNOWNCARDP %s %lu",
|
||||
serial, (unsigned long)stamp);
|
||||
xfree (serial);
|
||||
if (rc < 0)
|
||||
return ASSUAN_Out_Of_Core;
|
||||
rc = 0;
|
||||
rc = assuan_inquire (ctx, command, NULL, NULL, 0);
|
||||
free (command); /* (must use standard free here) */
|
||||
if (rc)
|
||||
{
|
||||
if (rc != ASSUAN_Canceled)
|
||||
log_error ("inquire KNOWNCARDP failed: %s\n",
|
||||
assuan_strerror (rc));
|
||||
return rc;
|
||||
}
|
||||
/* not canceled, so we have to proceeed */
|
||||
}
|
||||
|
||||
return map_to_assuan_status (rc);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -81,6 +149,7 @@ register_commands (ASSUAN_CONTEXT ctx)
|
||||
int cmd_id;
|
||||
int (*handler)(ASSUAN_CONTEXT, char *line);
|
||||
} table[] = {
|
||||
{ "LEARN", 0, cmd_learn },
|
||||
{ "", ASSUAN_CMD_INPUT, NULL },
|
||||
{ "", ASSUAN_CMD_OUTPUT, NULL },
|
||||
{ NULL }
|
||||
@ -168,7 +237,7 @@ scd_command_handler (int listen_fd)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
reset_notify (ctx); /* used for cleanup */
|
||||
|
||||
assuan_deinit_server (ctx);
|
||||
}
|
||||
|
@ -21,6 +21,7 @@
|
||||
#ifndef SCDAEMON_H
|
||||
#define SCDAEMON_H
|
||||
|
||||
#include <time.h>
|
||||
#include <gcrypt.h>
|
||||
#include "../common/util.h"
|
||||
#include "../common/errors.h"
|
||||
@ -55,13 +56,15 @@ struct {
|
||||
#define DBG_ASSUAN (opt.debug & DBG_ASSUAN_VALUE)
|
||||
|
||||
struct server_local_s;
|
||||
struct card_ctx_s;
|
||||
|
||||
struct server_control_s {
|
||||
struct server_local_s *server_local;
|
||||
struct card_ctx_s *card_ctx;
|
||||
|
||||
};
|
||||
typedef struct server_control_s *CTRL;
|
||||
|
||||
typedef struct card_ctx_s *CARD;
|
||||
|
||||
/*-- scdaemon.c --*/
|
||||
void scd_exit (int rc);
|
||||
@ -70,5 +73,11 @@ void scd_init_default_ctrl (CTRL ctrl);
|
||||
/*-- command.c --*/
|
||||
void scd_command_handler (int);
|
||||
|
||||
/*-- card.c --*/
|
||||
int card_open (CARD *rcard);
|
||||
void card_close (CARD card);
|
||||
int card_get_serial_and_stamp (CARD card, char **serial, time_t *stamp);
|
||||
|
||||
|
||||
|
||||
#endif /*SCDAEMON_H*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user