aboutsummaryrefslogtreecommitdiffstats
path: root/agent
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2010-04-21 16:26:17 +0000
committerWerner Koch <[email protected]>2010-04-21 16:26:17 +0000
commita1412b05debe693e6aabaf2c2c337bc33f7dfd41 (patch)
tree214dc8928b73aaa385d69eaa180164318ff0bb93 /agent
parentDisable card support for now (diff)
downloadgnupg-a1412b05debe693e6aabaf2c2c337bc33f7dfd41.tar.gz
gnupg-a1412b05debe693e6aabaf2c2c337bc33f7dfd41.zip
More changes on the way to remove secring.gpg.
Diffstat (limited to 'agent')
-rw-r--r--agent/ChangeLog10
-rw-r--r--agent/agent.h1
-rw-r--r--agent/command.c5
-rw-r--r--agent/findkey.c154
-rw-r--r--agent/pksign.c108
5 files changed, 228 insertions, 50 deletions
diff --git a/agent/ChangeLog b/agent/ChangeLog
index 46e0b6fe3..6611a35ad 100644
--- a/agent/ChangeLog
+++ b/agent/ChangeLog
@@ -1,3 +1,13 @@
+2010-04-19 Werner Koch <[email protected]>
+
+ * pksign.c (get_dsa_qbits, do_encode_dsa): New.
+ (agent_pksign_do): Detect DSA keys and use do_encode_dsa.
+ * findkey.c (agent_public_key_from_file): Factor some code out to ..
+ (key_parms_from_sexp): New.
+ (agent_is_dsa_key): New.
+
+ * command.c (cmd_sethash): Clear digeest.RAW_VALUE.
+
2010-04-14 Werner Koch <[email protected]>
* Makefile.am (libexec_PROGRAMS) [W32CE]: Do not build
diff --git a/agent/agent.h b/agent/agent.h
index ea0d49465..3f0c19561 100644
--- a/agent/agent.h
+++ b/agent/agent.h
@@ -232,6 +232,7 @@ gpg_error_t agent_key_from_file (ctrl_t ctrl,
gpg_error_t agent_public_key_from_file (ctrl_t ctrl,
const unsigned char *grip,
gcry_sexp_t *result);
+int agent_is_dsa_key (gcry_sexp_t s_key);
int agent_key_available (const unsigned char *grip);
gpg_error_t agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
int *r_keytype,
diff --git a/agent/command.c b/agent/command.c
index 1e0c5e744..b78dc07d9 100644
--- a/agent/command.c
+++ b/agent/command.c
@@ -589,7 +589,7 @@ cmd_setkeydesc (assuan_context_t ctx, char *line)
static const char hlp_sethash[] =
- "SETHASH --hash=<name>|<algonumber> <hexstring>\n"
+ "SETHASH (--hash=<name>)|(<algonumber>) <hexstring>\n"
"\n"
"The client can use this command to tell the server about the data\n"
"(which usually is a hash) to be signed.";
@@ -642,6 +642,7 @@ cmd_sethash (assuan_context_t ctx, char *line)
return set_error (GPG_ERR_UNSUPPORTED_ALGORITHM, NULL);
}
ctrl->digest.algo = algo;
+ ctrl->digest.raw_value = 0;
/* Parse the hash value. */
n = 0;
@@ -848,7 +849,7 @@ static const char hlp_keyinfo[] =
"\n"
"TYPE is describes the type of the key:\n"
" 'D' - Regular key stored on disk,\n"
- " 'T' - Key is stored on a smartcard (token).\n"
+ " 'T' - Key is stored on a smartcard (token),\n"
" '-' - Unknown type.\n"
"\n"
"SERIALNO is an ASCII string with the serial number of the\n"
diff --git a/agent/findkey.c b/agent/findkey.c
index 30aa7c938..d6478ac4d 100644
--- a/agent/findkey.c
+++ b/agent/findkey.c
@@ -1,6 +1,6 @@
/* findkey.c - Locate the secret key
- * Copyright (C) 2001, 2002, 2003, 2004, 2005,
- * 2007 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007,
+ * 2010 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -626,50 +626,32 @@ agent_key_from_file (ctrl_t ctrl, const char *desc_text,
}
-
-/* Return the public key for the keygrip GRIP. The result is stored
- at RESULT. This function extracts the public key from the private
- key database. On failure an error code is returned and NULL stored
- at RESULT. */
-gpg_error_t
-agent_public_key_from_file (ctrl_t ctrl,
- const unsigned char *grip,
- gcry_sexp_t *result)
+/* Return the string name from the S-expression S_KEY as well as a
+ string describing the names of the parameters. ALGONAMESIZE and
+ ELEMSSIZE give the allocated size of the provided buffers. The
+ buffers may be NULL if not required. If R_LIST is not NULL the top
+ level list will be stored tehre; the caller needs to release it in
+ this case. */
+static gpg_error_t
+key_parms_from_sexp (gcry_sexp_t s_key, gcry_sexp_t *r_list,
+ char *r_algoname, size_t algonamesize,
+ char *r_elems, size_t elemssize)
{
- int i, idx, rc;
- gcry_sexp_t s_skey;
- const char *algoname;
- gcry_sexp_t uri_sexp, comment_sexp;
- const char *uri, *comment;
- size_t uri_length, comment_length;
- char *format, *p;
- void *args[4+2+2+1]; /* Size is max. # of elements + 2 for uri + 2
- for comment + end-of-list. */
- int argidx;
gcry_sexp_t list, l2;
- const char *name;
- const char *s;
+ const char *name, *algoname, *elems;
size_t n;
- const char *elems;
- gcry_mpi_t *array;
-
- (void)ctrl;
-
- *result = NULL;
- rc = read_key_file (grip, &s_skey);
- if (rc)
- return rc;
+ if (r_list)
+ *r_list = NULL;
- list = gcry_sexp_find_token (s_skey, "shadowed-private-key", 0 );
+ list = gcry_sexp_find_token (s_key, "shadowed-private-key", 0 );
if (!list)
- list = gcry_sexp_find_token (s_skey, "protected-private-key", 0 );
+ list = gcry_sexp_find_token (s_key, "protected-private-key", 0 );
if (!list)
- list = gcry_sexp_find_token (s_skey, "private-key", 0 );
+ list = gcry_sexp_find_token (s_key, "private-key", 0 );
if (!list)
{
log_error ("invalid private key format\n");
- gcry_sexp_release (s_skey);
return gpg_error (GPG_ERR_BAD_SECKEY);
}
@@ -696,19 +678,99 @@ agent_public_key_from_file (ctrl_t ctrl,
{
log_error ("unknown private key algorithm\n");
gcry_sexp_release (list);
- gcry_sexp_release (s_skey);
return gpg_error (GPG_ERR_BAD_SECKEY);
}
+ if (r_algoname)
+ {
+ if (strlen (algoname) >= algonamesize)
+ return gpg_error (GPG_ERR_BUFFER_TOO_SHORT);
+ strcpy (r_algoname, algoname);
+ }
+ if (r_elems)
+ {
+ if (strlen (elems) >= elemssize)
+ return gpg_error (GPG_ERR_BUFFER_TOO_SHORT);
+ strcpy (r_elems, elems);
+ }
+
+ if (r_list)
+ *r_list = list;
+ else
+ gcry_sexp_release (list);
+
+ return 0;
+}
+
+
+/* Return true if S_KEY is a DSA style key. */
+int
+agent_is_dsa_key (gcry_sexp_t s_key)
+{
+ char algoname[6];
+
+ if (!s_key)
+ return 0;
+
+ if (key_parms_from_sexp (s_key, NULL, algoname, sizeof algoname, NULL, 0))
+ return 0; /* Error - assume it is not an DSA key. */
+
+ return (!strcmp (algoname, "dsa") || !strcmp (algoname, "ecdsa"));
+}
+
+
+
+/* Return the public key for the keygrip GRIP. The result is stored
+ at RESULT. This function extracts the public key from the private
+ key database. On failure an error code is returned and NULL stored
+ at RESULT. */
+gpg_error_t
+agent_public_key_from_file (ctrl_t ctrl,
+ const unsigned char *grip,
+ gcry_sexp_t *result)
+{
+ gpg_error_t err;
+ int i, idx;
+ gcry_sexp_t s_skey;
+ char algoname[6];
+ char elems[6];
+ gcry_sexp_t uri_sexp, comment_sexp;
+ const char *uri, *comment;
+ size_t uri_length, comment_length;
+ char *format, *p;
+ void *args[4+2+2+1]; /* Size is max. # of elements + 2 for uri + 2
+ for comment + end-of-list. */
+ int argidx;
+ gcry_sexp_t list, l2;
+ const char *s;
+ gcry_mpi_t *array;
+
+ (void)ctrl;
+
+ *result = NULL;
+
+ err = read_key_file (grip, &s_skey);
+ if (err)
+ return err;
+
+ err = key_parms_from_sexp (s_skey, &list,
+ algoname, sizeof algoname,
+ elems, sizeof elems);
+ if (err)
+ {
+ gcry_sexp_release (s_skey);
+ return err;
+ }
+
/* Allocate an array for the parameters and copy them out of the
secret key. FIXME: We should have a generic copy function. */
array = xtrycalloc (strlen(elems) + 1, sizeof *array);
if (!array)
{
- rc = gpg_error_from_syserror ();
+ err = gpg_error_from_syserror ();
gcry_sexp_release (list);
gcry_sexp_release (s_skey);
- return rc;
+ return err;
}
for (idx=0, s=elems; *s; s++, idx++ )
@@ -757,8 +819,8 @@ agent_public_key_from_file (ctrl_t ctrl,
/* FIXME: The following thing is pretty ugly code; we should
- investigate how to make it cleaner. Probably code to handle
- canonical S-expressions in a memory buffer is better suioted for
+ investigate how to make it cleaner. Probably code to handle
+ canonical S-expressions in a memory buffer is better suited for
such a task. After all that is what we do in protect.c. Neeed
to find common patterns and write a straightformward API to use
them. */
@@ -767,13 +829,13 @@ agent_public_key_from_file (ctrl_t ctrl,
format = xtrymalloc (15+7*strlen (elems)+10+15+1+1);
if (!format)
{
- rc = gpg_error_from_syserror ();
+ err = gpg_error_from_syserror ();
for (i=0; array[i]; i++)
gcry_mpi_release (array[i]);
xfree (array);
gcry_sexp_release (uri_sexp);
gcry_sexp_release (comment_sexp);
- return rc;
+ return err;
}
argidx = 0;
@@ -806,7 +868,7 @@ agent_public_key_from_file (ctrl_t ctrl,
assert (argidx < DIM (args));
args[argidx] = NULL;
- rc = gcry_sexp_build_array (&list, NULL, format, args);
+ err = gcry_sexp_build_array (&list, NULL, format, args);
xfree (format);
for (i=0; array[i]; i++)
gcry_mpi_release (array[i]);
@@ -814,9 +876,9 @@ agent_public_key_from_file (ctrl_t ctrl,
gcry_sexp_release (uri_sexp);
gcry_sexp_release (comment_sexp);
- if (!rc)
+ if (!err)
*result = list;
- return rc;
+ return err;
}
diff --git a/agent/pksign.c b/agent/pksign.c
index 25cadb29e..7ae50a931 100644
--- a/agent/pksign.c
+++ b/agent/pksign.c
@@ -1,5 +1,5 @@
/* pksign.c - public key signing (well, actually using a secret key)
- * Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2002, 2003, 2004, 2010 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -28,6 +28,7 @@
#include <sys/stat.h>
#include "agent.h"
+#include "i18n.h"
static int
@@ -75,6 +76,104 @@ do_encode_md (const byte * md, size_t mdlen, int algo, gcry_sexp_t * r_hash,
}
+/* Return the number of bits of the Q parameter from the DSA key
+ KEY. */
+static unsigned int
+get_dsa_qbits (gcry_sexp_t key)
+{
+ gcry_sexp_t l1, l2;
+ gcry_mpi_t q;
+ unsigned int nbits;
+
+ l1 = gcry_sexp_find_token (key, "private-key", 0);
+ if (!l1)
+ l1 = gcry_sexp_find_token (key, "protected-private-key", 0);
+ if (!l1)
+ l1 = gcry_sexp_find_token (key, "shadowed-private-key", 0);
+ if (!l1)
+ l1 = gcry_sexp_find_token (key, "public-key", 0);
+ if (!l1)
+ return 0; /* Does not contain a key object. */
+ l2 = gcry_sexp_cadr (l1);
+ gcry_sexp_release (l1);
+ l1 = gcry_sexp_find_token (l2, "q", 1);
+ gcry_sexp_release (l2);
+ if (!l1)
+ return 0; /* Invalid object. */
+ q = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
+ gcry_sexp_release (l1);
+ if (!q)
+ return 0; /* Missing value. */
+ nbits = gcry_mpi_get_nbits (q);
+ gcry_mpi_release (q);
+
+ return nbits;
+}
+
+
+/* Encode a message digest for use with an DSA algorithm. */
+static gpg_error_t
+do_encode_dsa (const byte * md, size_t mdlen, int dsaalgo, gcry_sexp_t pkey,
+ gcry_sexp_t *r_hash)
+{
+ gpg_error_t err;
+ gcry_sexp_t hash;
+ unsigned int qbits;
+
+ *r_hash = NULL;
+
+ if (dsaalgo == GCRY_PK_ECDSA)
+ qbits = gcry_pk_get_nbits (pkey);
+ else if (dsaalgo == GCRY_PK_DSA)
+ qbits = get_dsa_qbits (pkey);
+ else
+ return gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO);
+
+ if ((qbits%8))
+ {
+ log_error (_("DSA requires the hash length to be a"
+ " multiple of 8 bits\n"));
+ return gpg_error (GPG_ERR_INV_LENGTH);
+ }
+
+ /* Don't allow any Q smaller than 160 bits. We don't want someone
+ to issue signatures from a key with a 16-bit Q or something like
+ that, which would look correct but allow trivial forgeries. Yes,
+ I know this rules out using MD5 with DSA. ;) */
+ if (qbits < 160)
+ {
+ log_error (_("%s key uses an unsafe (%u bit) hash\n"),
+ gcry_pk_algo_name (dsaalgo), qbits);
+ return gpg_error (GPG_ERR_INV_LENGTH);
+ }
+
+ /* Check if we're too short. Too long is safe as we'll
+ automatically left-truncate. */
+ if (mdlen < qbits/8)
+ {
+ log_error (_("a %zu bit hash is not valid for a %u bit %s key\n"),
+ mdlen*8,
+ gcry_pk_get_nbits (pkey),
+ gcry_pk_algo_name (dsaalgo));
+ /* FIXME: we need to check the requirements for ECDSA. */
+ if (mdlen < 20 || dsaalgo == GCRY_PK_DSA)
+ return gpg_error (GPG_ERR_INV_LENGTH);
+ }
+
+ /* Truncate. */
+ if (mdlen > qbits/8)
+ mdlen = qbits/8;
+
+ /* Create the S-expression. */
+ err = gcry_sexp_build (&hash, NULL,
+ "(data (flags raw) (value %b))",
+ (int)mdlen, md);
+ if (!err)
+ *r_hash = hash;
+ return err;
+}
+
+
/* Special version of do_encode_md to take care of pkcs#1 padding.
For TLS-MD5SHA1 we need to do the padding ourself as Libgrypt does
not know about this special scheme. Fixme: We should have a
@@ -180,8 +279,8 @@ agent_pksign_do (ctrl_t ctrl, const char *desc_text,
else
{
/* No smartcard, but a private key */
-
gcry_sexp_t s_hash = NULL;
+ int dsaalgo;
/* Put the hash into a sexp */
if (ctrl->digest.algo == MD_USER_TLS_MD5SHA1)
@@ -189,6 +288,11 @@ agent_pksign_do (ctrl_t ctrl, const char *desc_text,
ctrl->digest.valuelen,
gcry_pk_get_nbits (s_skey),
&s_hash);
+ else if ( (dsaalgo = agent_is_dsa_key (s_skey)) )
+ rc = do_encode_dsa (ctrl->digest.value,
+ ctrl->digest.valuelen,
+ dsaalgo, s_skey,
+ &s_hash);
else
rc = do_encode_md (ctrl->digest.value,
ctrl->digest.valuelen,