diff options
-rw-r--r-- | agent/ChangeLog | 3 | ||||
-rw-r--r-- | agent/Makefile.am | 4 | ||||
-rw-r--r-- | agent/agent.h | 3 | ||||
-rw-r--r-- | agent/call-scd.c | 72 | ||||
-rw-r--r-- | agent/command.c | 2 | ||||
-rw-r--r-- | agent/divert-scd.c | 116 | ||||
-rw-r--r-- | agent/pksign.c | 2 | ||||
-rw-r--r-- | agent/protect.c | 76 |
8 files changed, 198 insertions, 80 deletions
diff --git a/agent/ChangeLog b/agent/ChangeLog index 63cc94a84..72d2ba8b0 100644 --- a/agent/ChangeLog +++ b/agent/ChangeLog @@ -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 <[email protected]> diff --git a/agent/Makefile.am b/agent/Makefile.am index d2b01b794..7ee2fb398 100644 --- a/agent/Makefile.am +++ b/agent/Makefile.am @@ -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) diff --git a/agent/agent.h b/agent/agent.h index 875e69bf0..56e89f019 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -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*/ diff --git a/agent/call-scd.c b/agent/call-scd.c index 790587352..af4d59fbd 100644 --- a/agent/call-scd.c +++ b/agent/call-scd.c @@ -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; +} + + + + diff --git a/agent/command.c b/agent/command.c index 4e448f5a1..bed9da648 100644 --- a/agent/command.c +++ b/agent/command.c @@ -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); diff --git a/agent/divert-scd.c b/agent/divert-scd.c index ca819298a..0dc9c121f 100644 --- a/agent/divert-scd.c +++ b/agent/divert-scd.c @@ -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; } + + + diff --git a/agent/pksign.c b/agent/pksign.c index 6ec37cd14..bdf1ff4f3 100644 --- a/agent/pksign.c +++ b/agent/pksign.c @@ -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. */ diff --git a/agent/protect.c b/agent/protect.c index ea8e30496..08f322bac 100644 --- a/agent/protect.c +++ b/agent/protect.c @@ -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. */ |