* genkey.c: Store the secret part and return the public part.

This commit is contained in:
Werner Koch 2002-01-10 19:45:32 +00:00
parent 3b8cf6e497
commit 6fd5b6d5ed
7 changed files with 408 additions and 63 deletions

View File

@ -1,3 +1,21 @@
2002-01-07 Werner Koch <wk@gnupg.org>
* genkey.c: Store the secret part and return the public part.
2002-01-03 Werner Koch <wk@gnupg.org>
* command.c (cmd_get_passphrase): New.
(cmd_clear_passphrase): New.
* query.c (agent_get_passphrase): New.
2002-01-02 Werner Koch <wk@gnupg.org>
* genkey.c: New.
* command.c (cmd_genkey): New.
* command.c (rc_to_assuan_status): Removed and changed all callers
to use map_to_assuan_status.
2001-12-19 Werner Koch <wk@gnupg.org>
* keyformat.txt: New.
@ -50,3 +68,13 @@ Fri Aug 18 14:27:14 CEST 2000 Werner Koch <wk@openit.de>
* gpg-agent.c: New.
* Makefile.am: New.
Copyright 2001, 2002 Free Software Foundation, Inc.
This file is free software; as a special exception the author gives
unlimited permission to copy and/or distribute it, with or without
modifications, as long as this notice is preserved.
This file is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

View File

@ -30,7 +30,8 @@ gpg_agent_SOURCES = \
trans.c \
findkey.c \
pksign.c \
pkdecrypt.c
pkdecrypt.c \
genkey.c
gpg_agent_LDADD = ../jnlib/libjnlib.a ../assuan/libassuan.a \
../common/libcommon.a $(LIBGCRYPT_LIBS)

View File

@ -94,6 +94,9 @@ GCRY_SEXP agent_key_from_file (const unsigned char *grip);
/*-- query.c --*/
int agent_askpin (const char *desc_text, struct pin_entry_info_s *pininfo);
int agent_get_passphrase (char **retpass,
const char *desc, const char *prompt,
const char *errtext);
/*-- pksign.c --*/
int agent_pksign (CTRL ctrl, FILE *outfp);
@ -102,5 +105,10 @@ int agent_pksign (CTRL ctrl, FILE *outfp);
int agent_pkdecrypt (CTRL ctrl, const char *ciphertext, size_t ciphertextlen,
FILE *outfp);
/*-- genkey.c --*/
int agent_genkey (CTRL ctrl,
const char *keyparam, size_t keyparmlen, FILE *outfp);
#endif /*AGENT_H*/

View File

@ -1,5 +1,5 @@
/* command.c - gpg-agent command handler
* Copyright (C) 2001 Free Software Foundation, Inc.
* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -34,7 +34,8 @@
/* maximum allowed size of the inquired ciphertext */
#define MAXLEN_CIPHERTEXT 4096
/* maximum allowed size of the key parameters */
#define MAXLEN_KEYPARAM 1024
#define set_error(e,t) assuan_set_error (ctx, ASSUAN_ ## e, (t))
@ -50,50 +51,6 @@ struct server_local_s {
};
/* Map GNUPG_xxx error codes to Assuan status codes
FIXME: duplicated from ../sm/server.c */
static int
rc_to_assuan_status (int rc)
{
switch (rc)
{
case 0: break;
case GNUPG_Bad_Certificate: rc = ASSUAN_Bad_Certificate; break;
case GNUPG_Bad_Certificate_Path: rc = ASSUAN_Bad_Certificate_Path; break;
case GNUPG_Missing_Certificate: rc = ASSUAN_Missing_Certificate; break;
case GNUPG_No_Data: rc = ASSUAN_No_Data_Available; break;
case GNUPG_Bad_Signature: rc = ASSUAN_Bad_Signature; break;
case GNUPG_Not_Implemented: rc = ASSUAN_Not_Implemented; break;
case GNUPG_No_Agent: rc = ASSUAN_No_Agent; break;
case GNUPG_Agent_Error: rc = ASSUAN_Agent_Error; break;
case GNUPG_No_Public_Key: rc = ASSUAN_No_Public_Key; break;
case GNUPG_No_Secret_Key: rc = ASSUAN_No_Secret_Key; break;
case GNUPG_Invalid_Data: rc = ASSUAN_Invalid_Data; break;
case GNUPG_Bad_PIN:
case GNUPG_Bad_Passphrase:
rc = ASSUAN_No_Secret_Key;
break;
case GNUPG_Read_Error:
case GNUPG_Write_Error:
case GNUPG_IO_Error:
rc = ASSUAN_Server_IO_Error;
break;
case GNUPG_Out_Of_Core:
case GNUPG_Resource_Limit:
rc = ASSUAN_Server_Resource_Problem;
break;
case GNUPG_Bug:
case GNUPG_Internal_Error:
rc = ASSUAN_Server_Bug;
break;
default:
rc = ASSUAN_Server_Fault;
break;
}
return rc;
}
@ -193,7 +150,7 @@ cmd_pksign (ASSUAN_CONTEXT ctx, char *line)
CTRL ctrl = assuan_get_pointer (ctx);
rc = agent_pksign (ctrl, assuan_get_data_fp (ctx));
return rc_to_assuan_status (rc);
return map_to_assuan_status (rc);
}
/* PKDECRYPT <options>
@ -216,7 +173,92 @@ cmd_pkdecrypt (ASSUAN_CONTEXT ctx, char *line)
rc = agent_pkdecrypt (ctrl, value, valuelen, assuan_get_data_fp (ctx));
xfree (value);
return rc_to_assuan_status (rc);
return map_to_assuan_status (rc);
}
/* GENKEY
Generate a new key, store the secret part and return the public
part. Here is an example transaction:
C: GENKEY
S: INQUIRE KEYPARM
C: D (genkey (rsa (nbits 1024)))
C: END
S: D (public-key
S: D (rsa (n 326487324683264) (e 10001)))
S OK key created
*/
static int
cmd_genkey (ASSUAN_CONTEXT ctx, char *line)
{
CTRL ctrl = assuan_get_pointer (ctx);
int rc;
char *value;
size_t valuelen;
/* First inquire the parameters */
rc = assuan_inquire (ctx, "KEYPARAM", &value, &valuelen, MAXLEN_KEYPARAM);
if (rc)
return rc;
rc = agent_genkey (ctrl, value, valuelen, assuan_get_data_fp (ctx));
xfree (value);
return map_to_assuan_status (rc);
}
/* GET_PASSPHRASE <cache_id> [<error_message> <prompt> <description>]
This function is usually used to ask for a passphrase to be used
for conventional encryption, but may aslo be used by programs which
need specal handling of passphrases. This command uses a syntax
which helps clients to use the agent with minimum effort. The
agent either returns with an error or with a OK followed by the hex
encoded passphrase. Note that the length of the strings is
implicitly limited by the maximum length of a command.
*/
static int
cmd_get_passphrase (ASSUAN_CONTEXT ctx, char *line)
{
int rc;
char *response;
char *desc, *prompt, *errtext;
/* FIXME: Parse that stuff */
desc = "We need a passphrase";
prompt = NULL;
errtext = "try again";
rc = agent_get_passphrase (&response, desc, prompt, errtext);
if (!rc)
{
rc = assuan_set_okay_line (ctx, response);
xfree (response);
}
return map_to_assuan_status (rc);
}
/* CLEAR_PASSPHRASE <cache_id>
may be used to invalidate the cache entry for a passphrase. The
function returns with OK even when ther eis no cached passphrase.
*/
static int
cmd_clear_passphrase (ASSUAN_CONTEXT ctx, char *line)
{
int rc;
/* fixme: no caching yet. so return with OK */
rc = 0;
return map_to_assuan_status (rc);
}
@ -235,6 +277,9 @@ register_commands (ASSUAN_CONTEXT ctx)
{ "SETHASH", 0, cmd_sethash },
{ "PKSIGN", 0, cmd_pksign },
{ "PKDECRYPT", 0, cmd_pkdecrypt },
{ "GENKEY", 0, cmd_genkey },
{ "GET_PASSPHRASE",0, cmd_get_passphrase },
{ "CLEAR_PASSPHRASE",0, cmd_clear_passphrase },
{ "", ASSUAN_CMD_INPUT, NULL },
{ "", ASSUAN_CMD_OUTPUT, NULL },
{ NULL }

189
agent/genkey.c Normal file
View File

@ -0,0 +1,189 @@
/* pksign.c - Generate a keypair
* Copyright (C) 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include <unistd.h>
#include <sys/stat.h>
#include "agent.h"
static int
store_key (GCRY_SEXP private)
{
int i;
char *fname;
FILE *fp;
char *buf;
size_t len;
unsigned char grip[20];
char hexgrip[41];
if ( !gcry_pk_get_keygrip (private, grip) )
{
log_error ("can't calculate keygrip\n");
return seterr (General_Error);
}
for (i=0; i < 20; i++)
sprintf (hexgrip+2*i, "%02X", grip[i]);
hexgrip[40] = 0;
fname = make_filename (opt.homedir, "private-keys-v1.d", hexgrip, NULL);
if (!access (fname, F_OK))
{
log_error ("secret key file `%s' already exists - very strange\n",
fname);
xfree (fname);
return seterr (General_Error);
}
fp = fopen (fname, "wbx");
if (!fp)
{
log_error ("can't create `%s': %s\n", fname, strerror (errno));
xfree (fname);
return seterr (File_Create_Error);
}
len = gcry_sexp_sprint (private, GCRYSEXP_FMT_CANON, NULL, 0);
assert (len);
buf = gcry_malloc_secure (len);
if (!buf)
{
fclose (fp);
remove (fname);
xfree (fname);
return seterr (Out_Of_Core);
}
len = gcry_sexp_sprint (private, GCRYSEXP_FMT_CANON, buf, len);
assert (len);
if (fwrite (buf, len, 1, fp) != 1)
{
log_error ("error writing `%s': %s\n", fname, strerror (errno));
fclose (fp);
remove (fname);
xfree (fname);
xfree (buf);
return seterr (File_Create_Error);
}
if ( fclose (fp) )
{
log_error ("error closing `%s': %s\n", fname, strerror (errno));
remove (fname);
xfree (fname);
xfree (buf);
return seterr (File_Create_Error);
}
xfree (fname);
xfree (buf);
return 0;
}
/* Generate a new keypair according to the parameters given in
KEYPARAM */
int
agent_genkey (CTRL ctrl, const char *keyparam, size_t keyparamlen,
FILE *outfp)
{
GCRY_SEXP s_keyparam, s_key, s_private, s_public;
int rc;
size_t len;
char *buf;
rc = gcry_sexp_sscan (&s_keyparam, NULL, keyparam, keyparamlen);
if (rc)
{
log_error ("failed to convert keyparam: %s\n", gcry_strerror (rc));
return seterr (Invalid_Data);
}
/* fixme: Get the passphrase now, cause key generation may take a while */
rc = gcry_pk_genkey (&s_key, s_keyparam );
gcry_sexp_release (s_keyparam);
if (rc)
{
log_error ("key generation failed: %s\n", gcry_strerror (rc));
return map_gcry_err (rc);
}
/* break out the parts */
s_private = gcry_sexp_find_token (s_key, "private-key", 0);
if (!s_private)
{
log_error ("key generation failed: invalid return value\n");
gcry_sexp_release (s_key);
return seterr (Invalid_Data);
}
s_public = gcry_sexp_find_token (s_key, "public-key", 0);
if (!s_public)
{
log_error ("key generation failed: invalid return value\n");
gcry_sexp_release (s_private);
gcry_sexp_release (s_key);
return seterr (Invalid_Data);
}
gcry_sexp_release (s_key); s_key = NULL;
/* store the secret key */
log_debug ("storing private key\n");
rc = store_key (s_private);
gcry_sexp_release (s_private);
if (rc)
{
gcry_sexp_release (s_public);
return rc;
}
/* return the public key */
log_debug ("returning public key\n");
len = gcry_sexp_sprint (s_public, GCRYSEXP_FMT_CANON, NULL, 0);
assert (len);
buf = xmalloc (len);
if (!buf)
{
gcry_sexp_release (s_private);
gcry_sexp_release (s_public);
return seterr (Out_Of_Core);
}
len = gcry_sexp_sprint (s_public, GCRYSEXP_FMT_CANON, buf, len);
assert (len);
if (fwrite (buf, len, 1, outfp) != 1)
{
log_error ("error writing public key: %s\n", strerror (errno));
gcry_sexp_release (s_private);
gcry_sexp_release (s_public);
xfree (buf);
return seterr (File_Create_Error);
}
gcry_sexp_release (s_public);
xfree (buf);
return 0;
}

View File

@ -5,8 +5,8 @@ keyformat.txt (wk 2001-12-18)
Some notes on the format of the secret keys used with gpg-agent.
The secret[1] keys are store one per file in a directory below
the .gnupg homedirectory. This directory is named
The secret keys[1] are stored on a per file basis in a directory below
the .gnupg home directory. This directory is named
private-keys-v1.d
@ -14,7 +14,7 @@ and should have permissions 700.
The secret keys are stored in files with a name matching the
hexadecimal representation of the keygrip[2]. The content of the file
is an S-Expression like tyhe ones used with Libgcrypt. Here is the
is an S-Expression like the ones used with Libgcrypt. Here is an
example of an unprotected file:
(private-key
@ -33,7 +33,8 @@ accepted by gpg-agent with the configuration option:
--allow-non-canonical-key-format.
The regular way to represent the keys is in canonical representation
with the additional requirement of an extra object around it[3]:
with the additional requirement of an extra object container around
it[3]:
(oid.1.3.6.1.4.1.11591.2.2.2
(keyinfo human_readable_information_to_decribe_this_key)
@ -74,8 +75,8 @@ Defined protection methods are:
1.3.6.1.4.1.gnu(11591).aegypten(2)
.algorithms(1).keyprotection(1).s2k3-sha1-aes-cbc(1)
This uses AES in CBS mode for encryption, SHA-1 fro integrity
protecion and the String to Key algorithm 3 from OpenPGP (rfc2440).
This uses AES in CBC mode for encryption, SHA-1 for integrity
protection and the String to Key algorithm 3 from OpenPGP (rfc2440).
Example:
@ -94,6 +95,9 @@ representation) after decryption:
(u #304559a..[some bytes not shown]..9b#)
)
For padding reasons, random bytes are appended to this list - they can
easily be stripped by looking for the end of the list.
The first element is the SHA-1 hash calculated on the concatenation of the
public key and secret key parameter lists: i.e one has to hash the
concatenatiohn of these 6 canonical encoded lists for RSA, including
@ -112,13 +116,7 @@ the stored one - If they don't match the integrity of the key is not
given.
TODO: write a more elaborated version.
@ -135,4 +133,4 @@ different protocols. PKCS-15 calls this a subjectKeyHash; it can be
calculate using Libgcrypt's gcry_pk_get_keygrip().
[3] Even when canonical representation is required we will show the
S-expression here in a more readable representation.
S-expression here in a more readable representation.

View File

@ -215,6 +215,82 @@ agent_askpin (const char *desc_text,
}
/* Ask for the passphrase using the supplied arguments. The
passphrase is returned in RETPASS as an hex encoded string to be
freed by the caller */
int
agent_get_passphrase (char **retpass, const char *desc, const char *prompt,
const char *errtext)
{
int rc;
char line[ASSUAN_LINELENGTH];
struct entry_parm_s parm;
unsigned char *p, *hexstring;
int i;
*retpass = NULL;
if (opt.batch)
return GNUPG_Bad_Passphrase;
rc = start_pinentry ();
if (rc)
return rc;
if (desc)
snprintf (line, DIM(line)-1, "SETDESC %s", desc);
else
snprintf (line, DIM(line)-1, "RESET");
line[DIM(line)-1] = 0;
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL);
if (rc)
return map_assuan_err (rc);
snprintf (line, DIM(line)-1, "SETPROMPT %s", prompt? prompt : "Passphrase");
line[DIM(line)-1] = 0;
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL);
if (rc)
return map_assuan_err (rc);
if (errtext)
{
snprintf (line, DIM(line)-1, "SETERROR %s", errtext);
line[DIM(line)-1] = 0;
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL);
if (rc)
return map_assuan_err (rc);
}
memset (&parm, 0, sizeof parm);
parm.size = ASSUAN_LINELENGTH/2 - 5;
parm.buffer = gcry_malloc_secure (parm.size+10);
if (!parm.buffer)
return seterr (Out_Of_Core);
rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm, NULL, NULL);
if (rc)
{
xfree (parm.buffer);
return map_assuan_err (rc);
}
hexstring = gcry_malloc_secure (strlen (parm.buffer)*2+1);
if (!hexstring)
{
xfree (parm.buffer);
return seterr (Out_Of_Core);
}
for (i=0, p=parm.buffer; *p; p++, i += 2)
sprintf (hexstring+i, "%02X", *p);
xfree (parm.buffer);
*retpass = hexstring;
return 0;
}