1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-05-29 21:58:04 +02:00

Changes needed to support smartcards. Well, only _support_. There is

no real code yet.
This commit is contained in:
Werner Koch 2002-02-28 11:07:59 +00:00
parent f8c8ca26d4
commit 56341c289c
23 changed files with 808 additions and 104 deletions

View File

@ -1,3 +1,22 @@
2002-02-28 Werner Koch <wk@gnupg.org>
* pksign.c (agent_pksign): Detect whether a Smartcard is to be
used and divert the operation in this case.
* pkdecrypt.c (agent_pkdecrypt): Likewise
* findkey.c (agent_key_from_file): Add optional arg shadow_info
and have it return information about a shadowed key.
* protect.c (agent_get_shadow_info): New.
* divert-scd.c: New.
2002-02-27 Werner Koch <wk@gnupg.org>
* protect.c (agent_shadow_key): New.
* command.c (cmd_learn): New command LEARN.
* gpg-agent.c: New option --scdaemon-program.
* call-scd.c (start_scd): New. Based on query.c
* query.c: Add 2 more arguments to all uses of assuan_transact.
2002-02-18 Werner Koch <wk@gnupg.org> 2002-02-18 Werner Koch <wk@gnupg.org>
* findkey.c (unprotect): Show an error message for a bad passphrase. * findkey.c (unprotect): Show an error message for a bad passphrase.

View File

@ -35,7 +35,9 @@ gpg_agent_SOURCES = \
pkdecrypt.c \ pkdecrypt.c \
genkey.c \ genkey.c \
protect.c \ protect.c \
trustlist.c trustlist.c \
divert-scd.c \
call-scd.c
gpg_agent_LDADD = ../jnlib/libjnlib.a ../assuan/libassuan.a \ gpg_agent_LDADD = ../jnlib/libjnlib.a ../assuan/libassuan.a \
../common/libcommon.a $(LIBGCRYPT_LIBS) ../common/libcommon.a $(LIBGCRYPT_LIBS)

View File

@ -36,6 +36,7 @@ struct {
int batch; /* batch mode */ int batch; /* batch mode */
const char *homedir; /* configuration directory name */ const char *homedir; /* configuration directory name */
const char *pinentry_program; const char *pinentry_program;
const char *scdaemon_program;
int no_grab; /* don't let the pinentry grab the keyboard */ int no_grab; /* don't let the pinentry grab the keyboard */
unsigned long def_cache_ttl; unsigned long def_cache_ttl;
@ -101,7 +102,8 @@ const char *trans (const char *text);
void start_command_handler (int); void start_command_handler (int);
/*-- findkey.c --*/ /*-- findkey.c --*/
GCRY_SEXP agent_key_from_file (const unsigned char *grip); GCRY_SEXP agent_key_from_file (const unsigned char *grip,
unsigned char **shadow_info);
int agent_key_available (const unsigned char *grip); int agent_key_available (const unsigned char *grip);
/*-- query.c --*/ /*-- query.c --*/
@ -135,6 +137,11 @@ int agent_protect (const unsigned char *plainkey, const char *passphrase,
int agent_unprotect (const unsigned char *protectedkey, const char *passphrase, int agent_unprotect (const unsigned char *protectedkey, const char *passphrase,
unsigned char **result, size_t *resultlen); unsigned char **result, size_t *resultlen);
int agent_private_key_type (const unsigned char *privatekey); int agent_private_key_type (const unsigned char *privatekey);
int agent_shadow_key (const unsigned char *pubkey,
const unsigned char *shadow_info,
unsigned char **result);
int agent_get_shadow_info (const unsigned char *shadowkey,
unsigned char const **shadow_info);
/*-- trustlist.c --*/ /*-- trustlist.c --*/
@ -143,4 +150,14 @@ int agent_listtrusted (void *assuan_context);
int agent_marktrusted (const char *name, const char *fpr, int flag); int agent_marktrusted (const char *name, const char *fpr, int flag);
/*-- divert-scd.c --*/
int divert_pksign (GCRY_SEXP *s_sig, GCRY_SEXP s_hash,
const char *shadow_info);
int divert_pkdecrypt (GCRY_SEXP *s_plain, GCRY_SEXP s_cipher,
const char *shadow_info);
/*-- call-scd.c --*/
int agent_learn_card (void);
#endif /*AGENT_H*/ #endif /*AGENT_H*/

View File

@ -462,6 +462,22 @@ cmd_clear_passphrase (ASSUAN_CONTEXT ctx, char *line)
return 0; return 0;
} }
/* LEARN
Learn something about the currently inserted smartcard
*/
static int
cmd_learn (ASSUAN_CONTEXT ctx, char *line)
{
int rc;
rc = agent_learn_card ();
if (rc)
log_error ("agent_learn_card failed: %s\n", gnupg_strerror (rc));
return map_to_assuan_status (rc);
}
/* Tell the assuan library about our commands */ /* Tell the assuan library about our commands */
@ -485,6 +501,7 @@ register_commands (ASSUAN_CONTEXT ctx)
{ "CLEAR_PASSPHRASE",0, cmd_clear_passphrase }, { "CLEAR_PASSPHRASE",0, cmd_clear_passphrase },
{ "LISTTRUSTED", 0, cmd_listtrusted }, { "LISTTRUSTED", 0, cmd_listtrusted },
{ "MARKTRUSTED", 0, cmd_marktrusted }, { "MARKTRUSTED", 0, cmd_marktrusted },
{ "LEARN", 0, cmd_learn },
{ "", ASSUAN_CMD_INPUT, NULL }, { "", ASSUAN_CMD_INPUT, NULL },
{ "", ASSUAN_CMD_OUTPUT, NULL }, { "", ASSUAN_CMD_OUTPUT, NULL },
{ NULL } { NULL }

View File

@ -95,9 +95,12 @@ unprotect (unsigned char **keybuf, const unsigned char *grip)
/* Return the secret key as an S-Exp after locating it using the grip. /* Return the secret key as an S-Exp after locating it using the grip.
Returns NULL if key is not available. */ Returns NULL if key is not available or the operation should be
diverted to a token. In the latter case shadow_info will point to
an allocated S-Expression with the shadow_info part from the
file. */
GCRY_SEXP GCRY_SEXP
agent_key_from_file (const unsigned char *grip) agent_key_from_file (const unsigned char *grip, unsigned char **shadow_info)
{ {
int i, rc; int i, rc;
char *fname; char *fname;
@ -108,6 +111,9 @@ agent_key_from_file (const unsigned char *grip)
GCRY_SEXP s_skey; GCRY_SEXP s_skey;
char hexgrip[40+4+1]; char hexgrip[40+4+1];
if (shadow_info)
*shadow_info = NULL;
for (i=0; i < 20; i++) for (i=0; i < 20; i++)
sprintf (hexgrip+2*i, "%02X", grip[i]); sprintf (hexgrip+2*i, "%02X", grip[i]);
strcpy (hexgrip+40, ".key"); strcpy (hexgrip+40, ".key");
@ -173,8 +179,30 @@ agent_key_from_file (const unsigned char *grip)
gnupg_strerror (rc)); gnupg_strerror (rc));
break; break;
case PRIVATE_KEY_SHADOWED: case PRIVATE_KEY_SHADOWED:
log_error ("shadowed private keys are not yet supported\n"); if (shadow_info)
rc = GNUPG_Not_Implemented; {
const unsigned char *s;
size_t n;
rc = agent_get_shadow_info (buf, &s);
if (!rc)
{
n = gcry_sexp_canon_len (s, 0, NULL,NULL);
assert (n);
*shadow_info = xtrymalloc (n);
if (!*shadow_info)
rc = GNUPG_Out_Of_Core;
else
{
memcpy (*shadow_info, s, n);
rc = 0;
}
}
if (rc)
log_error ("get_shadow_info failed: %s\n", gnupg_strerror (rc));
}
rc = -1; /* ugly interface: we return an error but keep a value
in shadow_info. */
break; break;
default: default:
log_error ("invalid private key format\n"); log_error ("invalid private key format\n");

View File

@ -69,6 +69,7 @@ enum cmd_and_opt_values
oBatch, oBatch,
oPinentryProgram, oPinentryProgram,
oScdaemonProgram,
oDefCacheTTL, oDefCacheTTL,
aTest }; aTest };
@ -92,7 +93,8 @@ static ARGPARSE_OPTS opts[] = {
{ oNoGrab, "no-grab" ,0, N_("do not grab keyboard and mouse")}, { oNoGrab, "no-grab" ,0, N_("do not grab keyboard and mouse")},
{ oLogFile, "log-file" ,2, N_("use a log file for the server")}, { oLogFile, "log-file" ,2, N_("use a log file for the server")},
{ oPinentryProgram, "pinentry-program", 2 , "path of PIN Entry program" }, { oPinentryProgram, "pinentry-program", 2 , "path to PIN Entry program" },
{ oScdaemonProgram, "scdaemon-program", 2 , "path to SCdaemon program" },
{ oDefCacheTTL, "default-cache-ttl", 4, { oDefCacheTTL, "default-cache-ttl", 4,
"|N|expire cached PINs after N seconds"}, "|N|expire cached PINs after N seconds"},
@ -372,6 +374,7 @@ main (int argc, char **argv )
case oServer: pipe_server = 1; break; case oServer: pipe_server = 1; break;
case oPinentryProgram: opt.pinentry_program = pargs.r.ret_str; break; case oPinentryProgram: opt.pinentry_program = pargs.r.ret_str; break;
case oScdaemonProgram: opt.scdaemon_program = pargs.r.ret_str; break;
case oDefCacheTTL: opt.def_cache_ttl = pargs.r.ret_ulong; break; case oDefCacheTTL: opt.def_cache_ttl = pargs.r.ret_ulong; break;
default : pargs.err = configfp? 1:2; break; default : pargs.err = configfp? 1:2; break;

View File

@ -4,7 +4,8 @@ keyformat.txt (wk 2001-12-18)
Some notes on the format of the secret keys used with gpg-agent. Some notes on the format of the secret keys used with gpg-agent.
Location of keys
================
The secret keys[1] are stored on a per file basis in a directory below The secret keys[1] are stored on a per file basis in a directory below
the ~/.gnupg home directory. This directory is named the ~/.gnupg home directory. This directory is named
@ -13,9 +14,12 @@ the ~/.gnupg home directory. This directory is named
and should have permissions 700. and should have permissions 700.
The secret keys are stored in files with a name matching the The secret keys are stored in files with a name matching the
hexadecimal representation of the keygrip[2]. The content of the file hexadecimal representation of the keygrip[2].
is an S-Expression like the ones used with Libgcrypt. Here is an
example of an unprotected file: Unprotected Private Key Format
==============================
The content of the file is an S-Expression like the ones used with
Libgcrypt. Here is an example of an unprotected file:
(private-key (private-key
(rsa (rsa
@ -47,8 +51,9 @@ keys is in canonical representation[3]:
) )
Protected Private Key Format
This describes an unprotected key; a protected key is like this: ==============================
A protected key is like this:
(protected-private-key (protected-private-key
(rsa (rsa
@ -116,12 +121,35 @@ the stored one - If they don't match the integrity of the key is not
given. given.
Shadowed Private Key Format
============================
To keep track of keys stored on IC cards we use a third format for
private kyes which are called shadow keys as they are only a reference
to keys stored on a token:
(shadowed-private-key
(rsa
(n #00e0ce9..[some bytes not shown]..51#)
(e #010001#)
(shadowed protocol (info))
)
(uri http://foo.bar x-foo:whatever_you_want)
)
The currently used protocol is "ti-v1" (token info version 1). The
second list with the information has this layout:
(card_serial_number id_string_of_key)
More items may be added to the list.
Notes: Notes:
======
[1] I usually use the terms private and secret key exchangeable but prefer the [1] I usually use the terms private and secret key exchangeable but prefer the
term secret key because it can be visually be better distinguished term secret key because it can be visually be better distinguished
from the term public key. from the term public key.

View File

@ -39,6 +39,7 @@ agent_pkdecrypt (CTRL ctrl, const char *ciphertext, size_t ciphertextlen,
FILE *outfp) FILE *outfp)
{ {
GCRY_SEXP s_skey = NULL, s_cipher = NULL, s_plain = NULL; GCRY_SEXP s_skey = NULL, s_cipher = NULL, s_plain = NULL;
unsigned char *shadow_info = NULL;
int rc; int rc;
char *buf = NULL; char *buf = NULL;
size_t len; size_t len;
@ -63,27 +64,38 @@ agent_pkdecrypt (CTRL ctrl, const char *ciphertext, size_t ciphertextlen,
log_printhex ("keygrip:", ctrl->keygrip, 20); log_printhex ("keygrip:", ctrl->keygrip, 20);
log_printhex ("cipher: ", ciphertext, ciphertextlen); log_printhex ("cipher: ", ciphertext, ciphertextlen);
} }
s_skey = agent_key_from_file (ctrl->keygrip); s_skey = agent_key_from_file (ctrl->keygrip, &shadow_info);
if (!s_skey) if (!s_skey && !shadow_info)
{ {
log_error ("failed to read the secret key\n"); log_error ("failed to read the secret key\n");
rc = seterr (No_Secret_Key); rc = seterr (No_Secret_Key);
goto leave; goto leave;
} }
if (!s_skey)
if (DBG_CRYPTO) { /* divert operation to the smartcard */
{ rc = divert_pkdecrypt (&s_plain, s_cipher, shadow_info);
log_debug ("skey: "); if (rc)
gcry_sexp_dump (s_skey); {
log_error ("smartcard decryption failed: %s\n", gnupg_strerror (rc));
goto leave;
}
} }
else
{ /* no smartcard, but a private key */
if (DBG_CRYPTO)
{
log_debug ("skey: ");
gcry_sexp_dump (s_skey);
}
rc = gcry_pk_decrypt (&s_plain, s_cipher, s_skey); rc = gcry_pk_decrypt (&s_plain, s_cipher, s_skey);
if (rc) if (rc)
{ {
log_error ("decryption failed: %s\n", gcry_strerror (rc)); log_error ("decryption failed: %s\n", gcry_strerror (rc));
rc = map_gcry_err (rc); rc = map_gcry_err (rc);
goto leave; goto leave;
} }
}
if (DBG_CRYPTO) if (DBG_CRYPTO)
{ {
@ -106,6 +118,7 @@ agent_pkdecrypt (CTRL ctrl, const char *ciphertext, size_t ciphertextlen,
gcry_sexp_release (s_plain); gcry_sexp_release (s_plain);
gcry_sexp_release (s_cipher); gcry_sexp_release (s_cipher);
xfree (buf); xfree (buf);
xfree (shadow_info);
return rc; return rc;
} }

View File

@ -90,6 +90,7 @@ agent_pksign (CTRL ctrl, FILE *outfp)
{ {
GCRY_SEXP s_skey = NULL, s_hash = NULL, s_sig = NULL; GCRY_SEXP s_skey = NULL, s_hash = NULL, s_sig = NULL;
GCRY_MPI frame = NULL; GCRY_MPI frame = NULL;
unsigned char *shadow_info = NULL;
int rc; int rc;
char *buf = NULL; char *buf = NULL;
size_t len; size_t len;
@ -97,39 +98,50 @@ agent_pksign (CTRL ctrl, FILE *outfp)
if (!ctrl->have_keygrip) if (!ctrl->have_keygrip)
return seterr (No_Secret_Key); return seterr (No_Secret_Key);
s_skey = agent_key_from_file (ctrl->keygrip); s_skey = agent_key_from_file (ctrl->keygrip, &shadow_info);
if (!s_skey) if (!s_skey && !shadow_info)
{ {
log_error ("failed to read the secret key\n"); log_error ("failed to read the secret key\n");
rc = seterr (No_Secret_Key); rc = seterr (No_Secret_Key);
goto leave; goto leave;
} }
/* put the hash into a sexp */ /* put the hash into a sexp FIXME: this belongs into libgcrypt/divert-scd.c*/
rc = do_encode_md (ctrl->digest.value, rc = do_encode_md (ctrl->digest.value,
ctrl->digest.valuelen, ctrl->digest.valuelen,
ctrl->digest.algo, ctrl->digest.algo,
gcry_pk_get_nbits (s_skey), gcry_pk_get_nbits (s_skey),
&frame); &frame);
if (rc) if (rc)
goto leave; goto leave;
if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) ) if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) )
BUG (); BUG ();
if (DBG_CRYPTO) if (!s_skey)
{ { /* divert operation to the smartcard */
log_debug ("skey: "); rc = divert_pksign (&s_sig, s_hash, shadow_info);
gcry_sexp_dump (s_skey); if (rc)
{
log_error ("smartcard signing failed: %s\n", gnupg_strerror (rc));
goto leave;
}
} }
else
{ /* no smartcard, but a private key */
if (DBG_CRYPTO)
{
log_debug ("skey: ");
gcry_sexp_dump (s_skey);
}
/* sign */
/* sign */ rc = gcry_pk_sign (&s_sig, s_hash, s_skey);
rc = gcry_pk_sign (&s_sig, s_hash, s_skey); if (rc)
if (rc) {
{ log_error ("signing failed: %s\n", gcry_strerror (rc));
log_error ("signing failed: %s\n", gcry_strerror (rc)); rc = map_gcry_err (rc);
rc = map_gcry_err (rc); goto leave;
goto leave; }
} }
if (DBG_CRYPTO) if (DBG_CRYPTO)
@ -138,7 +150,6 @@ agent_pksign (CTRL ctrl, FILE *outfp)
gcry_sexp_dump (s_sig); gcry_sexp_dump (s_sig);
} }
len = gcry_sexp_sprint (s_sig, GCRYSEXP_FMT_CANON, NULL, 0); len = gcry_sexp_sprint (s_sig, GCRYSEXP_FMT_CANON, NULL, 0);
assert (len); assert (len);
buf = xmalloc (len); buf = xmalloc (len);
@ -156,6 +167,7 @@ agent_pksign (CTRL ctrl, FILE *outfp)
gcry_sexp_release (s_sig); gcry_sexp_release (s_sig);
gcry_mpi_release (frame); gcry_mpi_release (frame);
xfree (buf); xfree (buf);
xfree (shadow_info);
return rc; return rc;
} }

View File

@ -49,6 +49,8 @@ enum cmd_and_opt_values
oUnprotect = 'u', oUnprotect = 'u',
oNoVerbose = 500, oNoVerbose = 500,
oShadow,
oShowShadowInfo,
aTest }; aTest };
@ -65,6 +67,8 @@ static ARGPARSE_OPTS opts[] = {
{ oPassphrase, "passphrase", 2, "|STRING| Use passphrase STRING" }, { oPassphrase, "passphrase", 2, "|STRING| Use passphrase STRING" },
{ oProtect, "protect", 256, "protect a private key"}, { oProtect, "protect", 256, "protect a private key"},
{ oUnprotect, "unprotect", 256, "unprotect a private key"}, { oUnprotect, "unprotect", 256, "unprotect a private key"},
{ oShadow, "shadow", 256, "create a shadow entry for a priblic key"},
{ oShowShadowInfo, "show-shadow-info", 256, "return the shadow info"},
{0} {0}
}; };
@ -125,8 +129,7 @@ my_gcry_logger (void *dummy, int level, const char *fmt, va_list arg_ptr)
case GCRY_LOG_FATAL:level = JNLIB_LOG_FATAL; break; case GCRY_LOG_FATAL:level = JNLIB_LOG_FATAL; break;
case GCRY_LOG_BUG: level = JNLIB_LOG_BUG; break; case GCRY_LOG_BUG: level = JNLIB_LOG_BUG; break;
case GCRY_LOG_DEBUG:level = JNLIB_LOG_DEBUG; break; case GCRY_LOG_DEBUG:level = JNLIB_LOG_DEBUG; break;
default: level = JNLIB_LOG_ERROR; break; default: level = JNLIB_LOG_ERROR; break; }
}
log_logv (level, fmt, arg_ptr); log_logv (level, fmt, arg_ptr);
} }
@ -291,6 +294,79 @@ read_and_unprotect (const char *fname)
} }
static void
read_and_shadow (const char *fname)
{
int rc;
unsigned char *key;
unsigned char *result;
size_t resultlen;
key = read_key (fname);
if (!key)
return;
rc = agent_shadow_key (key, "(8:313233342:43)", &result);
xfree (key);
if (rc)
{
log_error ("shadowing the key failed: %s\n", gnupg_strerror (rc));
return;
}
resultlen = gcry_sexp_canon_len (result, 0, NULL,NULL);
assert (resultlen);
if (opt_armor)
{
char *p = make_advanced (result, resultlen);
xfree (result);
if (!p)
return;
result = p;
resultlen = strlen (p);
}
fwrite (result, resultlen, 1, stdout);
xfree (result);
}
static void
show_shadow_info (const char *fname)
{
int rc;
unsigned char *key;
const unsigned char *info;
size_t infolen;
key = read_key (fname);
if (!key)
return;
rc = agent_get_shadow_info (key, &info);
xfree (key);
if (rc)
{
log_error ("get_shadow_info failed: %s\n", gnupg_strerror (rc));
return;
}
infolen = gcry_sexp_canon_len (info, 0, NULL,NULL);
assert (infolen);
if (opt_armor)
{
char *p = make_advanced (info, infolen);
if (!p)
return;
fwrite (p, strlen (p), 1, stdout);
xfree (p);
}
else
fwrite (info, infolen, 1, stdout);
}
int int
main (int argc, char **argv ) main (int argc, char **argv )
@ -325,6 +401,8 @@ main (int argc, char **argv )
case oProtect: cmd = oProtect; break; case oProtect: cmd = oProtect; break;
case oUnprotect: cmd = oUnprotect; break; case oUnprotect: cmd = oUnprotect; break;
case oShadow: cmd = oShadow; break;
case oShowShadowInfo: cmd = oShowShadowInfo; break;
case oPassphrase: passphrase = pargs.r.ret_str; break; case oPassphrase: passphrase = pargs.r.ret_str; break;
@ -341,6 +419,10 @@ main (int argc, char **argv )
read_and_protect (*argv); read_and_protect (*argv);
else if (cmd == oUnprotect) else if (cmd == oUnprotect)
read_and_unprotect (*argv); read_and_unprotect (*argv);
else if (cmd == oShadow)
read_and_shadow (*argv);
else if (cmd == oShowShadowInfo)
show_shadow_info (*argv);
else else
log_info ("no action requested\n"); log_info ("no action requested\n");

View File

@ -780,7 +780,7 @@ agent_unprotect (const unsigned char *protectedkey, const char *passphrase,
PRIVATE_KEY_UNKNOWN if we can't figure out the type (this is the PRIVATE_KEY_UNKNOWN if we can't figure out the type (this is the
value 0), PRIVATE_KEY_CLEAR for an unprotected private key. value 0), PRIVATE_KEY_CLEAR for an unprotected private key.
PRIVATE_KEY_PROTECTED for an protected private key or PRIVATE_KEY_PROTECTED for an protected private key or
PRIVATE_KEY_SHADOWED for a sub key where the secret parts are store PRIVATE_KEY_SHADOWED for a sub key where the secret parts are stored
elsewhere. */ elsewhere. */
int int
agent_private_key_type (const unsigned char *privatekey) agent_private_key_type (const unsigned char *privatekey)
@ -886,3 +886,154 @@ hash_passphrase (const char *passphrase, int hashalgo,
} }
/* Create a shadow key from a public key. We use the shadow protocol
"ti-v1" and insert the S-expressionn SHADOW_INFO. The resulting
S-expression is returned in an allocated buffer RESULT will point
to. The input parameters are expected to be valid canonilized
S-expressions */
int
agent_shadow_key (const unsigned char *pubkey,
const unsigned char *shadow_info,
unsigned char **result)
{
const unsigned char *s;
const unsigned char *point;
size_t n;
int depth = 0;
unsigned char *p;
size_t pubkey_len = gcry_sexp_canon_len (pubkey, 0, NULL,NULL);
size_t shadow_info_len = gcry_sexp_canon_len (shadow_info, 0, NULL,NULL);
if (!pubkey_len || !shadow_info_len)
return GNUPG_Invalid_Value;
s = pubkey;
if (*s != '(')
return GNUPG_Invalid_Sexp;
depth++;
s++;
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
if (!smatch (&s, n, "public-key"))
return GNUPG_Unknown_Sexp;
if (*s != '(')
return GNUPG_Unknown_Sexp;
depth++;
s++;
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
s += n; /* skip over the algorithm name */
while (*s != ')')
{
if (*s != '(')
return GNUPG_Invalid_Sexp;
depth++;
s++;
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
s += n;
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
s +=n; /* skip value */
if (*s != ')')
return GNUPG_Invalid_Sexp;
depth--;
s++;
}
point = s; /* insert right before the point */
depth--;
s++;
assert (depth == 1);
/* calculate required length by taking in account: the "shadowed-"
prefix, the "shadowed", "t1-v1" as well as some parenthesis */
n = 12 + pubkey_len + 1 + 3+8 + 2+5 + shadow_info_len + 1;
*result = p = xtrymalloc (n);
if (!p)
return GNUPG_Out_Of_Core;
p = stpcpy (p, "(20:shadowed-private-key");
/* (10:public-key ...)*/
memcpy (p, pubkey+14, point - (pubkey+14));
p += point - (pubkey+14);
p = stpcpy (p, "(8:shadowed5:t1-v1");
memcpy (p, shadow_info, shadow_info_len);
p += shadow_info_len;
*p++ = ')';
memcpy (p, point, pubkey_len - (point - pubkey));
p += pubkey_len - (point - pubkey);
return 0;
}
/* Parse a canonical encoded shadowed key and return a pointer to the
inner list with the shadow_info */
int
agent_get_shadow_info (const unsigned char *shadowkey,
unsigned char const **shadow_info)
{
const unsigned char *s;
size_t n;
int depth = 0;
s = shadowkey;
if (*s != '(')
return GNUPG_Invalid_Sexp;
depth++;
s++;
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
if (!smatch (&s, n, "shadowed-private-key"))
return GNUPG_Unknown_Sexp;
if (*s != '(')
return GNUPG_Unknown_Sexp;
depth++;
s++;
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
s += n; /* skip over the algorithm name */
for (;;)
{
if (*s == ')')
return GNUPG_Unknown_Sexp;
if (*s != '(')
return GNUPG_Invalid_Sexp;
depth++;
s++;
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
if (smatch (&s, n, "shadowed"))
break;
s += n;
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
s +=n; /* skip value */
if (*s != ')')
return GNUPG_Invalid_Sexp;
depth--;
s++;
}
/* found the shadowed list, s points to the protocol */
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
if (smatch (&s, n, "t1-v1"))
{
if (*s != '(')
return GNUPG_Invalid_Sexp;
*shadow_info = s;
}
else
return GNUPG_Unsupported_Protocol;
return 0;
}

View File

@ -97,7 +97,7 @@ start_pinentry (void)
rc = assuan_transact (entry_ctx, rc = assuan_transact (entry_ctx,
opt.no_grab? "OPTION no-grab":"OPTION grab", opt.no_grab? "OPTION no-grab":"OPTION grab",
NULL, NULL, NULL, NULL); NULL, NULL, NULL, NULL, NULL, NULL);
if (rc) if (rc)
return map_assuan_err (rc); return map_assuan_err (rc);
@ -160,14 +160,14 @@ agent_askpin (const char *desc_text, const char *start_err_text,
snprintf (line, DIM(line)-1, "SETDESC %s", desc_text); snprintf (line, DIM(line)-1, "SETDESC %s", desc_text);
line[DIM(line)-1] = 0; line[DIM(line)-1] = 0;
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL); rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc) if (rc)
return map_assuan_err (rc); return map_assuan_err (rc);
rc = assuan_transact (entry_ctx, rc = assuan_transact (entry_ctx,
pininfo->min_digits? "SETPROMPT PIN:" pininfo->min_digits? "SETPROMPT PIN:"
: "SETPROMPT Passphrase:", : "SETPROMPT Passphrase:",
NULL, NULL, NULL, NULL); NULL, NULL, NULL, NULL, NULL, NULL);
if (rc) if (rc)
return map_assuan_err (rc); return map_assuan_err (rc);
@ -189,13 +189,13 @@ agent_askpin (const char *desc_text, const char *start_err_text,
snprintf (line, DIM(line)-1, "SETERROR %s (try %d of %d)", snprintf (line, DIM(line)-1, "SETERROR %s (try %d of %d)",
errtext, pininfo->failed_tries+1, pininfo->max_tries); errtext, pininfo->failed_tries+1, pininfo->max_tries);
line[DIM(line)-1] = 0; line[DIM(line)-1] = 0;
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL); rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc) if (rc)
return map_assuan_err (rc); return map_assuan_err (rc);
errtext = NULL; errtext = NULL;
} }
rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm, NULL, NULL); rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm, NULL, NULL, NULL, NULL);
if (rc == ASSUAN_Too_Much_Data) if (rc == ASSUAN_Too_Much_Data)
errtext = pininfo->min_digits? trans ("PIN too long") errtext = pininfo->min_digits? trans ("PIN too long")
: trans ("Passphrase too long"); : trans ("Passphrase too long");
@ -248,13 +248,13 @@ agent_get_passphrase (char **retpass, const char *desc, const char *prompt,
else else
snprintf (line, DIM(line)-1, "RESET"); snprintf (line, DIM(line)-1, "RESET");
line[DIM(line)-1] = 0; line[DIM(line)-1] = 0;
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL); rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc) if (rc)
return map_assuan_err (rc); return map_assuan_err (rc);
snprintf (line, DIM(line)-1, "SETPROMPT %s", prompt? prompt : "Passphrase"); snprintf (line, DIM(line)-1, "SETPROMPT %s", prompt? prompt : "Passphrase");
line[DIM(line)-1] = 0; line[DIM(line)-1] = 0;
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL); rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc) if (rc)
return map_assuan_err (rc); return map_assuan_err (rc);
@ -262,7 +262,7 @@ agent_get_passphrase (char **retpass, const char *desc, const char *prompt,
{ {
snprintf (line, DIM(line)-1, "SETERROR %s", errtext); snprintf (line, DIM(line)-1, "SETERROR %s", errtext);
line[DIM(line)-1] = 0; line[DIM(line)-1] = 0;
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL); rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc) if (rc)
return map_assuan_err (rc); return map_assuan_err (rc);
} }
@ -274,7 +274,7 @@ agent_get_passphrase (char **retpass, const char *desc, const char *prompt,
return seterr (Out_Of_Core); return seterr (Out_Of_Core);
assuan_begin_confidential (entry_ctx); assuan_begin_confidential (entry_ctx);
rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm, NULL, NULL); rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm, NULL, NULL, NULL, NULL);
if (rc) if (rc)
{ {
xfree (parm.buffer); xfree (parm.buffer);
@ -317,7 +317,7 @@ agent_get_confirmation (const char *desc, const char *prompt)
else else
snprintf (line, DIM(line)-1, "RESET"); snprintf (line, DIM(line)-1, "RESET");
line[DIM(line)-1] = 0; line[DIM(line)-1] = 0;
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL); rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc) if (rc)
return map_assuan_err (rc); return map_assuan_err (rc);
@ -325,12 +325,12 @@ agent_get_confirmation (const char *desc, const char *prompt)
{ {
snprintf (line, DIM(line)-1, "SETPROMPT %s", prompt); snprintf (line, DIM(line)-1, "SETPROMPT %s", prompt);
line[DIM(line)-1] = 0; line[DIM(line)-1] = 0;
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL); rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc) if (rc)
return map_assuan_err (rc); return map_assuan_err (rc);
} }
rc = assuan_transact (entry_ctx, "CONFIRM", NULL, NULL, NULL, NULL); rc = assuan_transact (entry_ctx, "CONFIRM", NULL, NULL, NULL, NULL, NULL, NULL);
return map_assuan_err (rc); return map_assuan_err (rc);
} }

View File

@ -94,6 +94,11 @@ enum {
GNUPG_Not_Confirmed = 65, GNUPG_Not_Confirmed = 65,
GNUPG_Configuration_Error = 66, GNUPG_Configuration_Error = 66,
GNUPG_No_Policy_Match = 67, GNUPG_No_Policy_Match = 67,
GNUPG_Invalid_Index = 68,
GNUPG_Invalid_Id = 69,
GNUPG_No_Scdaemon = 70,
GNUPG_Scdaemon_Error = 71,
GNUPG_Unsupported_Protocol = 72,
}; };
/* Status codes - fixme: should go into another file */ /* Status codes - fixme: should go into another file */

View File

@ -44,6 +44,7 @@ map_ksba_err (int err)
break; break;
case KSBA_Unsupported_Algorithm: err = GNUPG_Unsupported_Algorithm; break; case KSBA_Unsupported_Algorithm: err = GNUPG_Unsupported_Algorithm; break;
case KSBA_Invalid_Index: err = GNUPG_Invalid_Index; break;
default: default:
err = seterr (General_Error); err = seterr (General_Error);
@ -136,6 +137,7 @@ map_assuan_err (int err)
break; break;
case ASSUAN_Canceled: err = GNUPG_Canceled; break; case ASSUAN_Canceled: err = GNUPG_Canceled; break;
case ASSUAN_Invalid_Index: err = GNUPG_Invalid_Index; break;
case ASSUAN_Not_Implemented: err = GNUPG_Not_Implemented; break; case ASSUAN_Not_Implemented: err = GNUPG_Not_Implemented; break;
case ASSUAN_Server_Fault: err = GNUPG_Assuan_Server_Fault; break; case ASSUAN_Server_Fault: err = GNUPG_Assuan_Server_Fault; break;
@ -153,6 +155,7 @@ map_assuan_err (int err)
case ASSUAN_No_PKCS15_App: err = GNUPG_No_PKCS15_App; break; case ASSUAN_No_PKCS15_App: err = GNUPG_No_PKCS15_App; break;
case ASSUAN_Card_Not_Present: err= GNUPG_Card_Not_Present; break; case ASSUAN_Card_Not_Present: err= GNUPG_Card_Not_Present; break;
case ASSUAN_Not_Confirmed: err = GNUPG_Not_Confirmed; break; case ASSUAN_Not_Confirmed: err = GNUPG_Not_Confirmed; break;
case ASSUAN_Invalid_Id: err = GNUPG_Invalid_Id; break;
default: default:
err = err < 100? GNUPG_Assuan_Server_Fault : GNUPG_Assuan_Error; err = err < 100? GNUPG_Assuan_Server_Fault : GNUPG_Assuan_Error;
@ -182,6 +185,7 @@ map_to_assuan_status (int rc)
case GNUPG_Invalid_Name: rc = ASSUAN_Invalid_Name; break; case GNUPG_Invalid_Name: rc = ASSUAN_Invalid_Name; break;
case GNUPG_Not_Trusted: rc = ASSUAN_Not_Trusted; break; case GNUPG_Not_Trusted: rc = ASSUAN_Not_Trusted; break;
case GNUPG_Canceled: rc = ASSUAN_Canceled; break; case GNUPG_Canceled: rc = ASSUAN_Canceled; break;
case GNUPG_Invalid_Index: rc = ASSUAN_Invalid_Index; break;
case GNUPG_Card_Error: case GNUPG_Card_Error:
case GNUPG_Card_Reset: case GNUPG_Card_Reset:
@ -194,7 +198,7 @@ map_to_assuan_status (int rc)
case GNUPG_Invalid_Card: rc = ASSUAN_Invalid_Card; break; case GNUPG_Invalid_Card: rc = ASSUAN_Invalid_Card; break;
case GNUPG_No_PKCS15_App: rc = ASSUAN_No_PKCS15_App; break; case GNUPG_No_PKCS15_App: rc = ASSUAN_No_PKCS15_App; break;
case GNUPG_Not_Confirmed: rc = ASSUAN_Not_Confirmed; break; case GNUPG_Not_Confirmed: rc = ASSUAN_Not_Confirmed; break;
case GNUPG_Invalid_Id: rc = ASSUAN_Invalid_Id; break;
case GNUPG_Bad_PIN: case GNUPG_Bad_PIN:
case GNUPG_Bad_Passphrase: case GNUPG_Bad_Passphrase:

View File

@ -20,7 +20,8 @@
bin_PROGRAMS = scdaemon bin_PROGRAMS = scdaemon
AM_CPPFLAGS = -I$(top_srcdir)/common $(LIBOPENSC_CFLAGS) $(LIBGCRYPT_CFLAGS) AM_CPPFLAGS = -I$(top_srcdir)/common $(LIBOPENSC_CFLAGS) $(LIBGCRYPT_CFLAGS) \
$(LIBKSBA_CFLAGS)
LDFLAGS = @LDFLAGS@ LDFLAGS = @LDFLAGS@
scdaemon_SOURCES = \ scdaemon_SOURCES = \
@ -29,7 +30,8 @@ scdaemon_SOURCES = \
scdaemon_LDADD = ../jnlib/libjnlib.a ../assuan/libassuan.a \ scdaemon_LDADD = ../jnlib/libjnlib.a ../assuan/libassuan.a \
../common/libcommon.a $(LIBOPENSC_LIBS) $(LIBGCRYPT_LIBS) ../common/libcommon.a \
$(LIBOPENSC_LIBS) $(LIBGCRYPT_LIBS) $(LIBKSBA_LIBS)

View File

@ -26,6 +26,7 @@
#include <time.h> #include <time.h>
#include <opensc-pkcs15.h> #include <opensc-pkcs15.h>
#include <ksba.h>
#include "scdaemon.h" #include "scdaemon.h"
@ -114,13 +115,13 @@ card_open (CARD *rcard)
} }
card->ctx->error_file = log_get_stream (); card->ctx->error_file = log_get_stream ();
card->ctx->debug_file = log_get_stream (); card->ctx->debug_file = log_get_stream ();
if (sc_detect_card (card->ctx, card->reader) != 1) if (sc_detect_card_presence (card->ctx->reader[card->reader], 0) != 1)
{ {
rc = GNUPG_Card_Not_Present; rc = GNUPG_Card_Not_Present;
goto leave; goto leave;
} }
rc = sc_connect_card (card->ctx, card->reader, &card->scard); rc = sc_connect_card (card->ctx->reader[card->reader], 0, &card->scard);
if (rc) if (rc)
{ {
log_error ("failed to connect card in reader %d: %s\n", log_error ("failed to connect card in reader %d: %s\n",
@ -175,7 +176,7 @@ card_close (CARD card)
if (card->scard) if (card->scard)
{ {
sc_unlock (card->scard); sc_unlock (card->scard);
sc_disconnect_card (card->scard); sc_disconnect_card (card->scard, 0);
card->scard = NULL; card->scard = NULL;
} }
if (card->ctx) if (card->ctx)
@ -219,3 +220,204 @@ card_get_serial_and_stamp (CARD card, char **serial, time_t *stamp)
return GNUPG_Out_Of_Core; return GNUPG_Out_Of_Core;
return 0; return 0;
} }
/* Get the keygrip from CERT, return 0 on success */
static int
get_keygrip (KsbaCert cert, unsigned char *array)
{
GCRY_SEXP s_pkey;
int rc;
KsbaSexp p;
size_t n;
p = ksba_cert_get_public_key (cert);
if (!p)
return -1; /* oops */
n = gcry_sexp_canon_len (p, 0, NULL, NULL);
if (!n)
return -1; /* libksba did not return a proper S-expression */
rc = gcry_sexp_sscan ( &s_pkey, NULL, p, n);
xfree (p);
if (rc)
return -1; /* can't parse that S-expression */
array = gcry_pk_get_keygrip (s_pkey, array);
gcry_sexp_release (s_pkey);
if (!array)
return -1; /* failed to calculate the keygrip */
return 0;
}
/* Enumerate all keypairs on the card and return the Keygrip as well
as the internal identification of the key. KEYGRIP must be a
caller provided buffer with a size of 20 bytes which will receive
the KEYGRIP of the keypair. If KEYID is not NULL, it returns the
ID field of the key in allocated memory, NKEYID will then receive
the length of it. The function returns -1 when all keys have been
enumerated. Note that the error GNUPG_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.*/
int
card_enum_keypairs (CARD card, int idx,
unsigned char *keygrip,
unsigned char **keyid, size_t *nkeyid)
{
int rc;
KsbaError krc;
struct sc_pkcs15_prkey_info *pinfo;
struct sc_pkcs15_cert_info *certinfo;
struct sc_pkcs15_cert *certder;
KsbaCert cert;
if (keyid)
*keyid = NULL;
if (nkeyid)
*nkeyid = 0;
if (!card || !keygrip || !card->p15card)
return GNUPG_Invalid_Value;
if (idx < 0)
return GNUPG_Invalid_Index;
rc = sc_pkcs15_enum_private_keys (card->p15card);
if (rc < 0)
{
log_error ("sc_pkcs15_enum_private_keys failed: %s\n", sc_strerror (rc));
return GNUPG_Card_Error;
}
if ( idx >= card->p15card->prkey_count)
return -1;
pinfo = card->p15card->prkey_info + idx;
/* now we need to read the certificate so that we can calculate the
keygrip */
rc = sc_pkcs15_find_cert_by_id (card->p15card, &pinfo->id, &certinfo);
if (rc)
{
log_info ("certificate for private key %d not found: %s\n",
idx, sc_strerror (rc));
/* but we should return the ID anyway */
if (keyid)
{
*keyid = xtrymalloc (pinfo->id.len);
if (!*keyid)
return GNUPG_Out_Of_Core;
memcpy (*keyid, pinfo->id.value, pinfo->id.len);
}
if (nkeyid)
*nkeyid = pinfo->id.len;
return GNUPG_Missing_Certificate;
}
rc = sc_pkcs15_read_certificate (card->p15card, certinfo, &certder);
if (rc)
{
log_info ("failed to read certificate for private key %d: %s\n",
idx, sc_strerror (rc));
return GNUPG_Card_Error;
}
cert = ksba_cert_new ();
if (!cert)
{
sc_pkcs15_free_certificate (certder);
return GNUPG_Out_Of_Core;
}
krc = ksba_cert_init_from_mem (cert, certder->data, certder->data_len);
sc_pkcs15_free_certificate (certder);
if (krc)
{
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;
}
if (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;
}
ksba_cert_release (cert);
/* return the iD */
if (keyid)
{
*keyid = xtrymalloc (pinfo->id.len);
if (!*keyid)
return GNUPG_Out_Of_Core;
memcpy (*keyid, pinfo->id.value, pinfo->id.len);
}
if (nkeyid)
*nkeyid = pinfo->id.len;
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
and NCERT. */
int
card_read_cert (CARD card, const char *certidstr,
unsigned char **cert, size_t *ncert)
{
struct sc_pkcs15_id certid;
struct sc_pkcs15_cert_info *certinfo;
struct sc_pkcs15_cert *certder;
const char *s;
int rc, n;
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 = sc_pkcs15_find_cert_by_id (card->p15card, &certid, &certinfo);
if (rc)
{
log_info ("certificate '%s' not found: %s\n",
certidstr, sc_strerror (rc));
return -1;
}
rc = sc_pkcs15_read_certificate (card->p15card, certinfo, &certder);
if (rc)
{
log_info ("failed to read certificate '%s': %s\n",
certidstr, sc_strerror (rc));
return GNUPG_Card_Error;
}
*cert = xtrymalloc (certder->data_len);
if (!*cert)
{
sc_pkcs15_free_certificate (certder);
return GNUPG_Out_Of_Core;
}
memcpy (*cert, certder->data, certder->data_len);
*ncert = certder->data_len;
sc_pkcs15_free_certificate (certder);
return 0;
}

View File

@ -75,14 +75,20 @@ option_handler (ASSUAN_CONTEXT ctx, const char *key, const char *value)
/* LEARN [--force] /* LEARN [--force]
Learn all useful information of the currently inserted card. When Learn all useful information of the currently inserted card. When
used without the force options, the command might to an INQUIRE used without the force options, the command might do an INQUIRE
like this: like this:
INQUIRE KNOWNCARDP <hexstring_with_serialNumber> <timestamp> INQUIRE KNOWNCARDP <hexstring_with_serialNumber> <timestamp>
The client should just send an "END" if the processing should go on 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 or a "CANCEL" to force the function to terminate with a Cancel
error message. error message. The response of this command is a list of status
lines formatted as this:
S KEYPAIRINFO <hexstring_with_keygrip> <hexstring_with_id>
If there is no certificate yet stored on the card a single "X" is
returned as the keygrip.
*/ */
static int static int
@ -90,6 +96,7 @@ cmd_learn (ASSUAN_CONTEXT ctx, char *line)
{ {
CTRL ctrl = assuan_get_pointer (ctx); CTRL ctrl = assuan_get_pointer (ctx);
int rc = 0; int rc = 0;
int idx;
/* if this is the first command issued for a new card, open the card and /* if this is the first command issued for a new card, open the card and
and create a context */ and create a context */
@ -104,40 +111,138 @@ cmd_learn (ASSUAN_CONTEXT ctx, char *line)
the card using a serial number and inquiring the client with the card using a serial number and inquiring the client with
that. The client may choose to cancel the operation if he already that. The client may choose to cancel the operation if he already
knows about this card */ knows about this card */
if (!has_option (line, "--force")) {
char *serial_and_stamp;
char *serial;
time_t stamp;
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);
if (!has_option (line, "--force"))
{
char *command;
rc = asprintf (&command, "KNOWNCARDP %s", serial_and_stamp);
if (rc < 0)
{
free (serial_and_stamp);
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));
free (serial_and_stamp);
return rc;
}
/* not canceled, so we have to proceeed */
}
free (serial_and_stamp);
}
for (idx=0; !rc; idx++)
{ {
char *serial; unsigned char keygrip[20];
time_t stamp; unsigned char *keyid;
char *command; size_t nkeyid;
int no_cert = 0;
rc = card_get_serial_and_stamp (ctrl->card_ctx, &serial, &stamp); rc = card_enum_keypairs (ctrl->card_ctx, idx,
if (rc) keygrip, &keyid, &nkeyid);
return map_to_assuan_status (rc); if (rc == GNUPG_Missing_Certificate && keyid)
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) /* this does happen with an incomplete personalized
log_error ("inquire KNOWNCARDP failed: %s\n", card; i.e. during the time we have stored the key on the
assuan_strerror (rc)); card but not stored the certificate; probably becuase it
return rc; has not yet been received back from the CA. Note that we
must release KEYID in this case. */
rc = 0;
no_cert = 1;
} }
/* not canceled, so we have to proceeed */ if (!rc)
{
char *buf, *p;
buf = p = xtrymalloc (40+1+9+2*nkeyid+1);
if (!buf)
rc = GNUPG_Out_Of_Core;
else
{
int i;
if (no_cert)
*p++ = 'X';
else
{
for (i=0; i < 20; i++, p += 2)
sprintf (p, "%02X", keygrip[i]);
}
*p++ = ' ';
/* fixme: we need to get the pkcs-15 DF from the card function */
p = stpcpy (p, "3F005015.");
for (i=0; i < nkeyid; i++, p += 2)
sprintf (p, "%02X", keyid[i]);
*p = 0;
assuan_write_status (ctx, "KEYPAIRINFO", buf);
xfree (buf);
}
}
xfree (keyid);
} }
if (rc == -1)
rc = 0;
return map_to_assuan_status (rc); return map_to_assuan_status (rc);
} }
/* READCERT <hexified_certid>
*/
static int
cmd_readcert (ASSUAN_CONTEXT ctx, char *line)
{
CTRL ctrl = assuan_get_pointer (ctx);
int rc;
unsigned char *cert;
size_t ncert;
if (!ctrl->card_ctx)
{
rc = card_open (&ctrl->card_ctx);
if (rc)
return map_to_assuan_status (rc);
}
rc = card_read_cert (ctrl->card_ctx, line, &cert, &ncert);
if (rc)
{
log_error ("card_read_cert failed: %s\n", gnupg_strerror (rc));
}
if (!rc)
{
rc = assuan_send_data (ctx, cert, ncert);
xfree (cert);
if (rc)
return rc;
}
return map_to_assuan_status (rc);
}
/* Tell the assuan library about our commands */ /* Tell the assuan library about our commands */
@ -150,6 +255,7 @@ register_commands (ASSUAN_CONTEXT ctx)
int (*handler)(ASSUAN_CONTEXT, char *line); int (*handler)(ASSUAN_CONTEXT, char *line);
} table[] = { } table[] = {
{ "LEARN", 0, cmd_learn }, { "LEARN", 0, cmd_learn },
{ "READCERT", 0, cmd_readcert },
{ "", ASSUAN_CMD_INPUT, NULL }, { "", ASSUAN_CMD_INPUT, NULL },
{ "", ASSUAN_CMD_OUTPUT, NULL }, { "", ASSUAN_CMD_OUTPUT, NULL },
{ NULL } { NULL }

View File

@ -34,6 +34,7 @@
#include <unistd.h> #include <unistd.h>
#include <signal.h> #include <signal.h>
#include <ksba.h>
#include <gcrypt.h> #include <gcrypt.h>
#define JNLIB_NEED_LOG_LOGV #define JNLIB_NEED_LOG_LOGV
@ -242,6 +243,7 @@ main (int argc, char **argv )
"1.1.5", gcry_check_version (NULL) ); "1.1.5", gcry_check_version (NULL) );
} }
ksba_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free);
assuan_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free); assuan_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free);
gcry_set_log_handler (my_gcry_logger, NULL); gcry_set_log_handler (my_gcry_logger, NULL);
gcry_control (GCRYCTL_USE_SECURE_RNDPOOL); gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);

View File

@ -77,6 +77,11 @@ void scd_command_handler (int);
int card_open (CARD *rcard); int card_open (CARD *rcard);
void card_close (CARD card); void card_close (CARD card);
int card_get_serial_and_stamp (CARD card, char **serial, time_t *stamp); int card_get_serial_and_stamp (CARD card, char **serial, time_t *stamp);
int card_enum_keypairs (CARD card, int idx,
unsigned char *keygrip,
unsigned char **keyid, size_t *nkeyid);
int card_read_cert (CARD card, const char *certidstr,
unsigned char **cert, size_t *ncert);

View File

@ -1,3 +1,8 @@
2002-02-27 Werner Koch <wk@gnupg.org>
* call-dirmngr.c, call-agent.c: Add 2 more arguments to all uses
of assuan_transact.
2002-02-25 Werner Koch <wk@gnupg.org> 2002-02-25 Werner Koch <wk@gnupg.org>
* server.c (option_handler): Allow to use -2 for "send all certs * server.c (option_handler): Allow to use -2 for "send all certs

View File

@ -245,13 +245,13 @@ gpgsm_agent_pksign (const char *keygrip,
if (digestlen*2 + 50 > DIM(line)) if (digestlen*2 + 50 > DIM(line))
return seterr (General_Error); return seterr (General_Error);
rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL); rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL);
if (rc) if (rc)
return map_assuan_err (rc); return map_assuan_err (rc);
snprintf (line, DIM(line)-1, "SIGKEY %s", keygrip); snprintf (line, DIM(line)-1, "SIGKEY %s", keygrip);
line[DIM(line)-1] = 0; line[DIM(line)-1] = 0;
rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL); rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc) if (rc)
return map_assuan_err (rc); return map_assuan_err (rc);
@ -259,13 +259,13 @@ gpgsm_agent_pksign (const char *keygrip,
p = line + strlen (line); p = line + strlen (line);
for (i=0; i < digestlen ; i++, p += 2 ) for (i=0; i < digestlen ; i++, p += 2 )
sprintf (p, "%02X", digest[i]); sprintf (p, "%02X", digest[i]);
rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL); rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc) if (rc)
return map_assuan_err (rc); return map_assuan_err (rc);
init_membuf (&data, 1024); init_membuf (&data, 1024);
rc = assuan_transact (agent_ctx, "PKSIGN", rc = assuan_transact (agent_ctx, "PKSIGN",
membuf_data_cb, &data, NULL, NULL); membuf_data_cb, &data, NULL, NULL, NULL, NULL);
if (rc) if (rc)
{ {
xfree (get_membuf (&data, &len)); xfree (get_membuf (&data, &len));
@ -327,14 +327,14 @@ gpgsm_agent_pkdecrypt (const char *keygrip,
if (rc) if (rc)
return rc; return rc;
rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL); rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL);
if (rc) if (rc)
return map_assuan_err (rc); return map_assuan_err (rc);
assert ( DIM(line) >= 50 ); assert ( DIM(line) >= 50 );
snprintf (line, DIM(line)-1, "SETKEY %s", keygrip); snprintf (line, DIM(line)-1, "SETKEY %s", keygrip);
line[DIM(line)-1] = 0; line[DIM(line)-1] = 0;
rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL); rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc) if (rc)
return map_assuan_err (rc); return map_assuan_err (rc);
@ -344,7 +344,7 @@ gpgsm_agent_pkdecrypt (const char *keygrip,
cipher_parm.ciphertextlen = ciphertextlen; cipher_parm.ciphertextlen = ciphertextlen;
rc = assuan_transact (agent_ctx, "PKDECRYPT", rc = assuan_transact (agent_ctx, "PKDECRYPT",
membuf_data_cb, &data, membuf_data_cb, &data,
inq_ciphertext_cb, &cipher_parm); inq_ciphertext_cb, &cipher_parm, NULL, NULL);
if (rc) if (rc)
{ {
xfree (get_membuf (&data, &len)); xfree (get_membuf (&data, &len));
@ -403,7 +403,7 @@ gpgsm_agent_genkey (KsbaConstSexp keyparms, KsbaSexp *r_pubkey)
if (rc) if (rc)
return rc; return rc;
rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL); rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL);
if (rc) if (rc)
return map_assuan_err (rc); return map_assuan_err (rc);
@ -415,7 +415,7 @@ gpgsm_agent_genkey (KsbaConstSexp keyparms, KsbaSexp *r_pubkey)
return GNUPG_Invalid_Value; return GNUPG_Invalid_Value;
rc = assuan_transact (agent_ctx, "GENKEY", rc = assuan_transact (agent_ctx, "GENKEY",
membuf_data_cb, &data, membuf_data_cb, &data,
inq_genkey_parms, &gk_parm); inq_genkey_parms, &gk_parm, NULL, NULL);
if (rc) if (rc)
{ {
xfree (get_membuf (&data, &len)); xfree (get_membuf (&data, &len));
@ -458,7 +458,7 @@ gpgsm_agent_istrusted (KsbaCert cert)
line[DIM(line)-1] = 0; line[DIM(line)-1] = 0;
xfree (fpr); xfree (fpr);
rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL); rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
return map_assuan_err (rc); return map_assuan_err (rc);
} }
@ -492,7 +492,7 @@ gpgsm_agent_marktrusted (KsbaCert cert)
ksba_free (dn); ksba_free (dn);
xfree (fpr); xfree (fpr);
rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL); rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
return map_assuan_err (rc); return map_assuan_err (rc);
} }
@ -516,7 +516,7 @@ gpgsm_agent_havekey (const char *hexkeygrip)
snprintf (line, DIM(line)-1, "HAVEKEY %s", hexkeygrip); snprintf (line, DIM(line)-1, "HAVEKEY %s", hexkeygrip);
line[DIM(line)-1] = 0; line[DIM(line)-1] = 0;
rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL); rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
return map_assuan_err (rc); return map_assuan_err (rc);
} }

View File

@ -227,7 +227,8 @@ gpgsm_dirmngr_isvalid (KsbaCert cert)
line[DIM(line)-1] = 0; line[DIM(line)-1] = 0;
xfree (certid); xfree (certid);
rc = assuan_transact (dirmngr_ctx, line, NULL, NULL, inq_certificate, &parm); rc = assuan_transact (dirmngr_ctx, line, NULL, NULL,
inq_certificate, &parm, NULL, NULL);
return map_assuan_err (rc); return map_assuan_err (rc);
} }

View File

@ -371,7 +371,7 @@ cmd_message (ASSUAN_CONTEXT ctx, char *line)
/* Note that the line contains a space separated list of pappern where /* Note that the line contains a space separated list of pappern where
each pappern is percent escaped and spacesmay be replaced by each pappern is percent escaped and spaces may be replaced by
'+'. */ '+'. */
static int static int
cmd_listkeys (ASSUAN_CONTEXT ctx, char *line) cmd_listkeys (ASSUAN_CONTEXT ctx, char *line)