aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2002-03-04 10:34:51 +0000
committerWerner Koch <[email protected]>2002-03-04 10:34:51 +0000
commit9301f1cf6971e8850f316665470b38574b4e5abb (patch)
tree733ad5ba52bfcb10a80989477a64a21a1194918a
parentAdded more code fragments. (diff)
downloadgnupg-9301f1cf6971e8850f316665470b38574b4e5abb.tar.gz
gnupg-9301f1cf6971e8850f316665470b38574b4e5abb.zip
* 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.
-rw-r--r--agent/ChangeLog3
-rw-r--r--agent/Makefile.am4
-rw-r--r--agent/agent.h3
-rw-r--r--agent/call-scd.c72
-rw-r--r--agent/command.c2
-rw-r--r--agent/divert-scd.c116
-rw-r--r--agent/pksign.c2
-rw-r--r--agent/protect.c76
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. */