mirror of
git://git.gnupg.org/gnupg.git
synced 2025-07-02 22:46:30 +02:00
More changes on the way to remove secring.gpg.
This commit is contained in:
parent
00f8eafbef
commit
a1412b05de
31 changed files with 843 additions and 936 deletions
|
@ -1,3 +1,13 @@
|
|||
2010-04-19 Werner Koch <wk@g10code.com>
|
||||
|
||||
* 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 <wk@g10code.com>
|
||||
|
||||
* Makefile.am (libexec_PROGRAMS) [W32CE]: Do not build
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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"
|
||||
|
|
154
agent/findkey.c
154
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;
|
||||
if (r_list)
|
||||
*r_list = NULL;
|
||||
|
||||
*result = NULL;
|
||||
|
||||
rc = read_key_file (grip, &s_skey);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
|
108
agent/pksign.c
108
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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue