1
0
Fork 0
mirror of git://git.gnupg.org/gnupg.git synced 2025-07-14 21:47:19 +02:00

Key generation and signing using the OpenPGP card does rudimentary work.

This commit is contained in:
Werner Koch 2003-06-27 20:53:09 +00:00
parent ed0d33f1d0
commit f5db59fc21
50 changed files with 1535 additions and 449 deletions

View file

@ -30,6 +30,7 @@
#include <assuan.h>
#include "scdaemon.h"
#include "app-common.h"
/* maximum length aloowed as a PIN; used for INQUIRE NEEDPIN */
#define MAXLEN_PIN 100
@ -69,6 +70,12 @@ reset_notify (ASSUAN_CONTEXT ctx)
xfree (ctrl->in_data.value);
ctrl->in_data.value = NULL;
}
if (ctrl->app_ctx)
{
/* FIXME: close the application. */
xfree (ctrl->app_ctx);
ctrl->app_ctx = NULL;
}
}
@ -85,8 +92,14 @@ option_handler (ASSUAN_CONTEXT ctx, const char *key, const char *value)
static AssuanError
open_card (CTRL ctrl)
{
if (!ctrl->card_ctx)
{
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 ();
if (!ctrl->app_ctx)
{ /* No application found - fall back to old mode. */
int rc = card_open (&ctrl->card_ctx);
if (rc)
return map_to_assuan_status (rc);
@ -95,6 +108,41 @@ open_card (CTRL ctrl)
}
/* Do the percent and plus/space unescaping in place and return tghe
length of the valid buffer. */
static size_t
percent_plus_unescape (unsigned char *string)
{
unsigned char *p = string;
size_t n = 0;
while (*string)
{
if (*string == '%' && string[1] && string[2])
{
string++;
*p++ = xtoi_2 (string);
n++;
string+= 2;
}
else if (*string == '+')
{
*p++ = ' ';
n++;
string++;
}
else
{
*p++ = *string++;
n++;
}
}
return n;
}
/* SERIALNO
Return the serial number of the card using a status reponse. This
@ -106,7 +154,7 @@ open_card (CTRL ctrl)
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.
operations are done on the same card unless he call this function.
*/
static int
cmd_serialno (ASSUAN_CONTEXT ctx, char *line)
@ -120,7 +168,10 @@ cmd_serialno (ASSUAN_CONTEXT ctx, char *line)
if ((rc = open_card (ctrl)))
return rc;
rc = card_get_serial_and_stamp (ctrl->card_ctx, &serial, &stamp);
if (ctrl->app_ctx)
rc = app_get_serial_and_stamp (ctrl->app_ctx, &serial, &stamp);
else
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);
@ -149,6 +200,16 @@ cmd_serialno (ASSUAN_CONTEXT ctx, char *line)
error message. The response of this command is a list of status
lines formatted as this:
S APPTYPE <apptype>
This returns the type of the application, currently the strings:
P15 = PKCS-15 structure used
DINSIG = DIN SIG
OPENPGP = OpenPGP card
are implemented. These strings are aliases for the AID
S KEYPAIRINFO <hexstring_with_keygrip> <hexstring_with_id>
If there is no certificate yet stored on the card a single "X" is
@ -157,13 +218,34 @@ cmd_serialno (ASSUAN_CONTEXT ctx, char *line)
S CERTINFO <certtype> <hexstring_with_id>
Where CERTINFO is a number indicating the type of certificate:
Where CERTTYPE is a number indicating the type of certificate:
0 := Unknown
100 := Regular X.509 cert
101 := Trusted X.509 cert
102 := Useful X.509 cert
For certain cards, more information will be returned:
S KEY-FPR <no> <hexstring>
For OpenPGP cards this returns the stored fingerprints of the
keys. This can be used check whether a key is available on the
card. NO may be 1, 2 or 3.
S CA-FPR <no> <hexstring>
Similar to above, these are the fingerprints of keys assumed to be
ultimately trusted.
S DISP-NAME <name_of_card_holder>
The name of the card holder as stored on the card; percent
aescaping takes place, spaces are encoded as '+'
S PUBKEY-URL <url>
The URL to be used for locating the entire public key.
*/
static int
cmd_learn (ASSUAN_CONTEXT ctx, char *line)
@ -183,8 +265,11 @@ cmd_learn (ASSUAN_CONTEXT ctx, char *line)
char *serial_and_stamp;
char *serial;
time_t stamp;
rc = card_get_serial_and_stamp (ctrl->card_ctx, &serial, &stamp);
if (ctrl->app_ctx)
rc = app_get_serial_and_stamp (ctrl->app_ctx, &serial, &stamp);
else
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);
@ -221,6 +306,8 @@ cmd_learn (ASSUAN_CONTEXT ctx, char *line)
}
/* Return information about the certificates. */
if (ctrl->app_ctx)
rc = -1; /* This information is not yet available for applications. */
for (idx=0; !rc; idx++)
{
char *certid;
@ -248,6 +335,8 @@ cmd_learn (ASSUAN_CONTEXT ctx, char *line)
/* Return information about the keys. */
if (ctrl->app_ctx)
rc = -1; /* This information is not yet available for applications. */
for (idx=0; !rc; idx++)
{
unsigned char keygrip[20];
@ -294,6 +383,9 @@ 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);
}
@ -314,6 +406,9 @@ cmd_readcert (ASSUAN_CONTEXT ctx, char *line)
if ((rc = open_card (ctrl)))
return rc;
if (ctrl->app_ctx)
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
rc = card_read_cert (ctrl->card_ctx, line, &cert, &ncert);
if (rc)
{
@ -348,6 +443,9 @@ cmd_readkey (ASSUAN_CONTEXT ctx, char *line)
if ((rc = open_card (ctrl)))
return rc;
if (ctrl->app_ctx)
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
rc = card_read_cert (ctrl->card_ctx, line, &cert, &ncert);
if (rc)
{
@ -480,11 +578,19 @@ cmd_pksign (ASSUAN_CONTEXT ctx, char *line)
keyidstr = strdup (line);
if (!keyidstr)
return ASSUAN_Out_Of_Core;
rc = card_sign (ctrl->card_ctx,
keyidstr, GCRY_MD_SHA1,
pin_cb, ctx,
ctrl->in_data.value, ctrl->in_data.valuelen,
&outdata, &outdatalen);
if (ctrl->app_ctx)
rc = app_sign (ctrl->app_ctx,
keyidstr, GCRY_MD_SHA1,
pin_cb, ctx,
ctrl->in_data.value, ctrl->in_data.valuelen,
&outdata, &outdatalen);
else
rc = card_sign (ctrl->card_ctx,
keyidstr, GCRY_MD_SHA1,
pin_cb, ctx,
ctrl->in_data.value, ctrl->in_data.valuelen,
&outdata, &outdatalen);
free (keyidstr);
if (rc)
{
@ -519,11 +625,18 @@ cmd_pkdecrypt (ASSUAN_CONTEXT ctx, char *line)
keyidstr = strdup (line);
if (!keyidstr)
return ASSUAN_Out_Of_Core;
rc = card_decipher (ctrl->card_ctx,
keyidstr,
pin_cb, ctx,
ctrl->in_data.value, ctrl->in_data.valuelen,
&outdata, &outdatalen);
if (ctrl->app_ctx)
rc = app_decipher (ctrl->app_ctx,
keyidstr,
pin_cb, ctx,
ctrl->in_data.value, ctrl->in_data.valuelen,
&outdata, &outdatalen);
else
rc = card_decipher (ctrl->card_ctx,
keyidstr,
pin_cb, ctx,
ctrl->in_data.value, ctrl->in_data.valuelen,
&outdata, &outdatalen);
free (keyidstr);
if (rc)
{
@ -541,6 +654,99 @@ cmd_pkdecrypt (ASSUAN_CONTEXT ctx, char *line)
}
/* SETATTR <name> <value>
This command is used to store data on a a smartcard. The allowed
names and values are depend on the currently selected smartcard
application. NAME and VALUE must be percent and '+' escaped.
However, the curent implementation assumes that Name is not escaped;
this works as long as noone uses arbitrary escaping.
A PIN will be requested for most NAMEs. See the corresponding
setattr function of the actually used application (app-*.c) for
details. */
static int
cmd_setattr (ASSUAN_CONTEXT ctx, char *line)
{
CTRL ctrl = assuan_get_pointer (ctx);
int rc;
char *keyword;
int keywordlen;
size_t nbytes;
if ((rc = open_card (ctrl)))
return rc;
keyword = line;
for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
;
if (*line)
*line++ = 0;
while (spacep (line))
line++;
nbytes = percent_plus_unescape (line);
rc = app_setattr (ctrl->app_ctx, keyword, pin_cb, ctx, line, nbytes);
return map_to_assuan_status (rc);
}
/* GENKEY [--force] <no>
Generate a key on-card identified by NO, which is application
specific. Return values are application specific. For OpenPGP
cards 2 status lines are returned:
S KEY-FPR <hexstring>
S KEY-CREATED-AT <seconds_since_epoch>
S KEY-DATA [p|n] <hexdata>
--force is required to overwriet 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.
The public part of the key can also later be retrieved using the
READKEY command.
*/
static int
cmd_genkey (ASSUAN_CONTEXT ctx, char *line)
{
CTRL ctrl = assuan_get_pointer (ctx);
int rc;
char *keyno;
int force = has_option (line, "--force");
/* Skip over options. */
while ( *line == '-' && line[1] == '-' )
{
while (!spacep (line))
line++;
while (spacep (line))
line++;
}
if (!*line)
return set_error (Parameter_Error, "no key number given");
keyno = line;
while (!spacep (line))
line++;
*line = 0;
if ((rc = open_card (ctrl)))
return rc;
if (!ctrl->app_ctx)
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
rc = app_genkey (ctrl->app_ctx, ctrl, keyno, force? 1:0, pin_cb, ctx);
return map_to_assuan_status (rc);
}
/* Tell the assuan library about our commands */
@ -560,6 +766,8 @@ register_commands (ASSUAN_CONTEXT ctx)
{ "PKDECRYPT", cmd_pkdecrypt },
{ "INPUT", NULL },
{ "OUTPUT", NULL },
{ "SETATTR", cmd_setattr },
{ "GENKEY", cmd_genkey },
{ NULL }
};
int i, rc;
@ -646,3 +854,51 @@ scd_command_handler (int listen_fd)
assuan_deinit_server (ctx);
}
/* Send a line with status information via assuan and escape all given
buffers. The variable elements are pairs of (char *, size_t),
terminated with a (NULL, 0). */
void
send_status_info (CTRL 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;
va_start (arg_ptr, keyword);
p = buf;
n = 0;
while ( (value = va_arg (arg_ptr, const unsigned char *)) )
{
valuelen = va_arg (arg_ptr, size_t);
if (!valuelen)
continue; /* empty buffer */
if (n)
{
*p++ = ' ';
n++;
}
for ( ; valuelen && n < DIM (buf)-2; n++, valuelen--, value++)
{
if (*value < ' ' || *value == '+')
{
sprintf (p, "%%%02X", *value);
p += 3;
}
else if (*value == ' ')
*p++ = '+';
else
*p++ = *value;
}
}
*p = 0;
assuan_write_status (ctx, keyword, buf);
va_end (arg_ptr);
}