* 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.
* protect.c (snext,sskip,smatch): Moved to
* sexp-parse.h: new file.
* divert-scd.c: New.
This commit is contained in:
Werner Koch 2002-03-04 10:34:51 +00:00
parent f8efc7c4ef
commit 9301f1cf69
8 changed files with 198 additions and 80 deletions

View File

@ -6,6 +6,9 @@
* 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.
* protect.c (snext,sskip,smatch): Moved to
* sexp-parse.h: new file.
* divert-scd.c: New.
2002-02-27 Werner Koch <wk@gnupg.org>

View File

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

View File

@ -157,7 +157,8 @@ int divert_pkdecrypt (GCRY_SEXP *s_plain, GCRY_SEXP s_cipher,
const char *shadow_info);
/*-- call-scd.c --*/
int agent_learn_card (void);
int agent_card_learn (void);
int agent_card_serialno (char **r_serialno);
#endif /*AGENT_H*/

View File

@ -102,7 +102,7 @@ start_scd (void)
static AssuanError
learn_status_cb (void *opaque, const char *line)
{
struct learn_parm_s *parm = opaque;
/* struct learn_parm_s *parm = opaque;*/
const char *keyword = line;
int keywordlen;
@ -127,7 +127,7 @@ learn_status_cb (void *opaque, const char *line)
/* Perform the learn command and return a list of all private keys
stored on the card. */
int
agent_learn_card (void)
agent_card_learn (void)
{
int rc;
struct learn_parm_s parm;
@ -151,3 +151,71 @@ agent_learn_card (void)
return 0;
}
static AssuanError
get_serialno_cb (void *opaque, const char *line)
{
char **serialno = opaque;
const char *keyword = line;
const char *s;
int keywordlen, n;
for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
;
while (spacep (line))
line++;
if (keywordlen == 8 && !memcmp (keyword, "SERIALNO", keywordlen))
{
if (*serialno)
return ASSUAN_Unexpected_Status;
for (n=0,s=line; hexdigitp (s); s++, n++)
;
if (!n || (n&1)|| !(spacep (s) || !*s) )
return ASSUAN_Invalid_Status;
*serialno = xtrymalloc (n+1);
if (!*serialno)
return ASSUAN_Out_Of_Core;
memcpy (*serialno, line, n);
(*serialno)[n] = 0;
}
return 0;
}
/* Return the serial number of the card or an appropriate error. The
serial number is returned as a hext string. */
int
agent_card_serialno (char **r_serialno)
{
int rc;
char *serialno = NULL;
rc = start_scd ();
if (rc)
return rc;
/* Hmm, do we really need this reset - scddaemon should do this or
we can do this if we for some reason figure out that the
operation might have failed due to a missing RESET. Hmmm, I feel
this is really SCdaemon's duty */
rc = assuan_transact (scd_ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
return map_assuan_err (rc);
rc = assuan_transact (scd_ctx, "SERIALNO",
NULL, NULL, NULL, NULL,
get_serialno_cb, &serialno);
if (rc)
{
xfree (serialno);
return map_assuan_err (rc);
}
*r_serialno = serialno;
return 0;
}

View File

@ -472,7 +472,7 @@ cmd_learn (ASSUAN_CONTEXT ctx, char *line)
{
int rc;
rc = agent_learn_card ();
rc = agent_card_learn ();
if (rc)
log_error ("agent_learn_card failed: %s\n", gnupg_strerror (rc));
return map_to_assuan_status (rc);

View File

@ -29,12 +29,116 @@
#include <sys/stat.h>
#include "agent.h"
#include "sexp-parse.h"
static int
ask_for_card (const unsigned char *shadow_info, char **r_kid)
{
int rc, i;
const unsigned char *s;
size_t n;
char *serialno;
int no_card = 0;
char *desc;
char *want_sn, *want_kid;
*r_kid = NULL;
s = shadow_info;
if (*s != '(')
return GNUPG_Invalid_Sexp;
s++;
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
want_sn = xtrymalloc (n+1);
if (!want_sn)
return GNUPG_Out_Of_Core;
memcpy (want_sn, s, n);
want_sn[n] = 0;
s += n;
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
want_kid = xtrymalloc (n+1);
if (!want_kid)
{
xfree (want_sn);
return GNUPG_Out_Of_Core;
}
memcpy (want_kid, s, n);
want_kid[n] = 0;
for (;;)
{
rc = agent_card_serialno (&serialno);
if (!rc)
{
log_debug ("detected card with S/N %s\n", serialno);
i = strcmp (serialno, want_sn);
xfree (serialno);
serialno = NULL;
if (!i)
{
xfree (want_sn);
*r_kid = want_kid;
return 0; /* yes, we have the correct card */
}
}
else if (rc == GNUPG_Card_Not_Present)
{
log_debug ("no card present\n");
rc = 0;
no_card = 1;
}
else
{
log_error ("error accesing card: %s\n", gnupg_strerror (rc));
}
if (!rc)
{
if (asprintf (&desc,
"%s:%%0A%%0A"
" \"%s\"",
no_card? "Please insert the card with serial number"
: "Please remove the current card and "
"insert the one with serial number",
want_sn) < 0)
{
rc = GNUPG_Out_Of_Core;
}
else
{
rc = agent_get_confirmation (desc, NULL);
free (desc);
}
}
if (rc)
{
xfree (want_sn);
xfree (want_kid);
return rc;
}
}
}
int
divert_pksign (GCRY_SEXP *s_sig, GCRY_SEXP s_hash, const char *shadow_info)
{
int rc;
char *kid;
rc = ask_for_card (shadow_info, &kid);
if (rc)
return rc;
xfree (kid);
return GNUPG_Not_Implemented;
}
@ -43,5 +147,17 @@ int
divert_pkdecrypt (GCRY_SEXP *s_plain, GCRY_SEXP s_cipher,
const char *shadow_info)
{
int rc;
char *kid;
rc = ask_for_card (shadow_info, &kid);
if (rc)
return rc;
xfree (kid);
return GNUPG_Not_Implemented;
}

View File

@ -57,7 +57,7 @@ do_encode_md (const unsigned char *digest, size_t digestlen, int algo,
/* We encode the MD in this way:
*
* 0 A PAD(n bytes) 0 ASN(asnlen bytes) MD(len bytes)
* 0 1 PAD(n bytes) 0 ASN(asnlen bytes) MD(len bytes)
*
* PAD consists of FF bytes.
*/

View File

@ -30,6 +30,8 @@
#include "agent.h"
#include "sexp-parse.h"
#define PROT_CIPHER GCRY_CIPHER_AES
#define PROT_CIPHER_STRING "aes"
#define PROT_CIPHER_KEYLEN (128/8)
@ -54,80 +56,6 @@ hash_passphrase (const char *passphrase, int hashalgo,
unsigned char *key, size_t keylen);
/* Return the length of the next S-Exp part and update the pointer to
the first data byte. 0 is return on error */
static size_t
snext (unsigned char const **buf)
{
const unsigned char *s;
int n;
s = *buf;
for (n=0; *s && *s != ':' && digitp (s); s++)
n = n*10 + atoi_1 (s);
if (!n || *s != ':')
return 0; /* we don't allow empty lengths */
*buf = s+1;
return n;
}
/* Skip over the S-Expression BUF points to and update BUF to point to
the chacter right behind. DEPTH gives the initial number of open
lists and may be passed as a positive number to skip over the
remainder of an S-Expression if the current position is somewhere
in an S-Expression. The function may return an error code if it
encounters an impossible conditions */
static int
sskip (unsigned char const **buf, int *depth)
{
const unsigned char *s = *buf;
size_t n;
int d = *depth;
while (d > 0)
{
if (*s == '(')
{
d++;
s++;
}
else if (*s == ')')
{
d--;
s++;
}
else
{
if (!d)
return GNUPG_Invalid_Sexp;
n = snext (&s);
if (!n)
return GNUPG_Invalid_Sexp;
s += n;
}
}
*buf = s;
*depth = d;
return 0;
}
/* Check whether the the string at the address BUF points to matches
the token. Return true on match and update BUF to point behind the
token. */
static int
smatch (unsigned char const **buf, size_t buflen, const char *token)
{
size_t toklen = strlen (token);
if (buflen != toklen || memcmp (*buf, token, toklen))
return 0;
*buf += toklen;
return 1;
}
/* Calculate the MIC for a private key S-Exp. SHA1HASH should pint to
a 20 byte buffer. This function is suitable for any algorithms. */