From 97c5d4d312dbb6d6f70d1d8ea88ab6a03f4e2f2a Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 5 Jan 2010 17:36:53 +0000 Subject: [PATCH] Add an API to change passphrases. Currently only implemented for GPGSM. Requires GnuPG 2.1 --- NEWS | 26 +++++++----- README | 2 +- configure.ac | 5 ++- doc/ChangeLog | 4 ++ doc/gpgme.texi | 48 +++++++++++++++++++++- src/ChangeLog | 18 +++++++++ src/Makefile.am | 2 +- src/engine-backend.h | 3 ++ src/engine-gpgsm.c | 43 +++++++++++++++++--- src/engine.c | 18 ++++++++- src/engine.h | 6 ++- src/gpgme-tool.c | 44 +++++++++++++++++--- src/gpgme.c | 6 +++ src/gpgme.def | 3 ++ src/gpgme.h.in | 15 ++++++- src/libgpgme.vers | 3 ++ src/passwd.c | 95 ++++++++++++++++++++++++++++++++++++++++++++ 17 files changed, 312 insertions(+), 29 deletions(-) create mode 100644 src/passwd.c diff --git a/NEWS b/NEWS index 3fcc8dee..a2bc80ff 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,4 @@ -Noteworthy changes in version 1.2.1 (unreleased) +Noteworthy changes in version 1.3.0 (unreleased) ------------------------------------------------ * GPGME does not come with an internal libassuan version anymore. @@ -10,14 +10,21 @@ Noteworthy changes in version 1.2.1 (unreleased) * New engine GPGME_PROTOCOL_UISERVER to support UI Servers. + * New API to change the passpgrase of a key. + * Interface changes relative to the 1.2.0 release: -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -GPGME_STATUS_INV_SGNR NEW -GPGME_STATUS_NO_SGNR NEW -GPGME_PROTOCOL_G13 NEW -gpgme_op_g13_mount NEW -gpgme_g13_result_t NEW -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + GPGME_STATUS_INV_SGNR NEW. + GPGME_STATUS_NO_SGNR NEW. + GPGME_PROTOCOL_G13 NEW. + gpgme_op_g13_mount NEW. + gpgme_g13_result_t NEW. + GPGME_PK_ECDSA NEW. + GPGME_PK_ECDH NEW. + gpgme_op_passwd_start NEW. + gpgme_op_passwd NEW. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Noteworthy changes in version 1.2.0 (2009-06-18) ------------------------------------------------ @@ -1321,7 +1328,8 @@ Noteworthy changes in version 0.2.1 (2001-04-02) * Made the W32 support more robust. - Copyright 2001, 2002, 2003, 2004, 2005, 2007, 2008 g10 Code GmbH + Copyright 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, + 2010 g10 Code GmbH This file is free software; as a special exception the author gives unlimited permission to copy and/or distribute it, with or without diff --git a/README b/README index 7594bda7..01d7d3ac 100644 --- a/README +++ b/README @@ -1,7 +1,7 @@ GPGME - GnuPG Made Easy --------------------------- - Copyright 2004, 2006 g10 Code GmbH + Copyright 2004, 2006, 2010 g10 Code GmbH This file is free software; as a special exception the author gives unlimited permission to copy and/or distribute it, with or without diff --git a/configure.ac b/configure.ac index 90df95f8..c1e28fd2 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,7 @@ # configure.ac for GPGME # Copyright (C) 2000 Werner Koch (dd9jn) -# Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 g10 Code GmbH +# Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, +# 2009, 2010 g10 Code GmbH # # This file is part of GPGME. # @@ -31,7 +32,7 @@ min_automake_version="1.10" # specific feature can already be done under the assumption that the # SVN version is the most recent one in a branch. To disable the SVN # version for the real release, set the my_issvn macro to no. -m4_define(my_version, [1.2.1]) +m4_define(my_version, [1.3.0]) m4_define(my_issvn, [yes]) m4_define([svn_revision], m4_esyscmd([printf "%d" $( (svn info 2>/dev/null \ diff --git a/doc/ChangeLog b/doc/ChangeLog index 34f30bd0..d1ea9439 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,7 @@ +2010-01-05 Werner Koch + + * gpgme.texi (Changing Passphrases): New. + 2009-07-21 Werner Koch * uiserver.texi (UI Server Encrypt): Add --expect-sign option to diff --git a/doc/gpgme.texi b/doc/gpgme.texi index 8cf7c4bf..b98db55d 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -13,7 +13,8 @@ @syncodeindex pg fn @copying -Copyright @copyright{} 2002, 2003, 2004, 2005, 2006, 2007, 2008 g10 Code GmbH. +Copyright @copyright{} 2002, 2003, 2004, 2005, 2006, 2007, +2008, 2010 g10 Code GmbH. @quotation Permission is granted to copy, distribute and/or modify this document @@ -1014,6 +1015,18 @@ This value indicates ElGamal. @item GPGME_PK_ELG_E This value also indicates ElGamal and is used specifically in GnuPG. + +@item GPGME_PK_ELG_E +This value also indicates ElGamal and is used specifically in GnuPG. + +@item GPGME_PK_ECDSA +This value indicates ECDSA, the Elliptic Curve Digital Signature +Algorithm as defined by FIPS 186-2. + +@item GPGME_PK_ECDH +This value indicates ECDH, the Eliptic Curve Diffie-Hellmann encryption +algorithm as defined by the ECC in OpenPGP draft. + @end table @end deftp @@ -2737,6 +2750,7 @@ in the list is the main (or primary) user ID. * Exporting Keys:: Retrieving key data from the key ring. * Importing Keys:: Adding keys to the key ring. * Deleting Keys:: Removing keys from the key ring. +* Changing Passphrases:: Change the passphrase of a key. * Advanced Key Editing:: Advanced key edit operation. @end menu @@ -3715,6 +3729,38 @@ operation was started successfully, and @code{GPG_ERR_INV_VALUE} if @end deftypefun +@node Changing Passphrases +@subsection Changing Passphrases +@cindex passphrase, change + +@deftypefun gpgme_error_t gpgme_op_passwd @ + (@w{gpgme_ctx_t @var{ctx}}, @ + @w{const gpgme_key_t @var{key}}, @ + @w{unsigned int @var{flags}}) + +The function @code{gpgme_op_passwd} changes the passphrase of the +private key associated with @var{key}. The only allowed value for +@var{flags} is @code{0}. The backend engine will usually popup a window +to ask for the old and the new passphrase. Thus this function is not +useful in a server application (where passphrases are not required +anyway). +@end deftypefun + +@deftypefun gpgme_error_t gpgme_op_passwd_start @ + (@w{gpgme_ctx_t @var{ctx}}, @ + @w{const gpgme_key_t @var{key}}, @ + @w{unsigned int @var{flags}}) + +The function @code{gpgme_op_passwd_start} initiates a +@code{gpgme_op_passwd} operation. It can be completed by calling +@code{gpgme_wait} on the context. @xref{Waiting For Completion}. + +The function returns @code{0} if the operation was started successfully, +and an error code if one of the arguments is not valid or the oepration +could not be started. +@end deftypefun + + @node Advanced Key Editing @subsection Advanced Key Editing @cindex key, edit diff --git a/src/ChangeLog b/src/ChangeLog index 4a83b93c..929bbc5f 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,21 @@ +2010-01-05 Werner Koch + + * gpgme-tool.c (gt_passwd, cmd_passwd): New. + (register_commands): Register. + + * gpgme.h.in (gpgme_op_passwd_start, gpgme_op_passwd): New. + * libgpgme.vers, gpgme.def: Add new functions. + * passwd.c: New. + * Makefile.am (main_sources): Add passwd.c + * engine.c, engine.h (_gpgme_engine_op_passwd): New. + * engine-backend.h (struct engine_ops): Add PASSWD. + * engine-gpgsm.c (gpgsm_passwd): New. + (_gpgme_engine_ops_gpgsm): Register. + (gpgsm_reset): Reset only if we have a conenction. + + * gpgme.h.in (GPGME_PK_ECDSA, GPGME_PK_ECDH): New. + * gpgme.c (gpgme_pubkey_algo_name): Add them. + 2009-12-22 Marcus Brinkmann * debug.c: Test for TLS, not __GNUC__ diff --git a/src/Makefile.am b/src/Makefile.am index 41ab762e..1ecb7610 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -115,7 +115,7 @@ main_sources = \ sign.c passphrase.c progress.c \ key.c keylist.c trust-item.c trustlist.c \ import.c export.c genkey.c delete.c edit.c getauditlog.c \ - opassuan.c \ + opassuan.c passwd.c \ engine.h engine-backend.h engine.c engine-gpg.c status-table.h \ $(gpgsm_components) $(assuan_components) $(gpgconf_components) \ $(uiserver_components) \ diff --git a/src/engine-backend.h b/src/engine-backend.h index fa0b4392..e540acb9 100644 --- a/src/engine-backend.h +++ b/src/engine-backend.h @@ -118,6 +118,9 @@ struct engine_ops /* Cancel only the current operation, not the whole session. */ gpgme_error_t (*cancel_op) (void *engine); + + /* Change the passphrase for KEY. */ + gpgme_error_t (*passwd) (void *engine, gpgme_key_t key, unsigned int flags); }; diff --git a/src/engine-gpgsm.c b/src/engine-gpgsm.c index 32294b0b..2dda7339 100644 --- a/src/engine-gpgsm.c +++ b/src/engine-gpgsm.c @@ -1,6 +1,7 @@ /* engine-gpgsm.c - GpgSM engine. Copyright (C) 2000 Werner Koch (dd9jn) - Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2009 g10 Code GmbH + Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2009, + 2010 g10 Code GmbH This file is part of GPGME. @@ -1053,13 +1054,18 @@ gpgsm_reset (void *engine) { engine_gpgsm_t gpgsm = engine; - /* We must send a reset because we need to reset the list of - signers. Note that RESET does not reset OPTION commands. */ - return gpgsm_assuan_simple_command (gpgsm->assuan_ctx, "RESET", NULL, NULL); + /* IF we have an active connection we must send a reset because we + need to reset the list of signers. Note that RESET does not + reset OPTION commands. */ + return (gpgsm->assuan_ctx + ? gpgsm_assuan_simple_command (gpgsm->assuan_ctx, "RESET", + NULL, NULL) + : 0); } #endif + static gpgme_error_t gpgsm_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain) { @@ -1894,6 +1900,32 @@ gpgsm_io_event (void *engine, gpgme_event_io_t type, void *type_data) } +static gpgme_error_t +gpgsm_passwd (void *engine, gpgme_key_t key, unsigned int flags) +{ + engine_gpgsm_t gpgsm = engine; + gpgme_error_t err; + char *line; + + if (!key || !key->subkeys || !key->subkeys->fpr) + return gpg_error (GPG_ERR_INV_VALUE); + + if (asprintf (&line, "PASSWD -- %s", key->subkeys->fpr) < 0) + return gpg_error_from_syserror (); + + gpgsm_clear_fd (gpgsm, OUTPUT_FD); + gpgsm_clear_fd (gpgsm, INPUT_FD); + gpgsm_clear_fd (gpgsm, MESSAGE_FD); + gpgsm->inline_data = NULL; + + err = start (gpgsm, line); + free (line); + + return err; +} + + + struct engine_ops _gpgme_engine_ops_gpgsm = { /* Static functions. */ @@ -1937,5 +1969,6 @@ struct engine_ops _gpgme_engine_ops_gpgsm = gpgsm_set_io_cbs, gpgsm_io_event, gpgsm_cancel, - NULL /* cancel_op */ + NULL, /* cancel_op */ + gpgsm_passwd }; diff --git a/src/engine.c b/src/engine.c index ecf23047..71f0c9c6 100644 --- a/src/engine.c +++ b/src/engine.c @@ -1,6 +1,6 @@ /* engine.c - GPGME engine support. Copyright (C) 2000 Werner Koch (dd9jn) - Copyright (C) 2001, 2002, 2003, 2004, 2006, 2009 g10 Code GmbH + Copyright (C) 2001, 2002, 2003, 2004, 2006, 2009, 2010 g10 Code GmbH This file is part of GPGME. @@ -906,3 +906,19 @@ _gpgme_engine_cancel_op (engine_t engine) return (*engine->ops->cancel_op) (engine->engine); } + + +/* Change the passphrase for KEY. */ +gpgme_error_t +_gpgme_engine_op_passwd (engine_t engine, gpgme_key_t key, + unsigned int flags) +{ + if (!engine) + return gpg_error (GPG_ERR_INV_VALUE); + + if (!engine->ops->passwd) + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); + + return (*engine->ops->passwd) (engine->engine, key, flags); +} + diff --git a/src/engine.h b/src/engine.h index d9119391..dfc73acc 100644 --- a/src/engine.h +++ b/src/engine.h @@ -1,6 +1,6 @@ /* engine.h - GPGME engine interface. Copyright (C) 2000 Werner Koch (dd9jn) - Copyright (C) 2001, 2002, 2003, 2004 g10 Code GmbH + Copyright (C) 2001, 2002, 2003, 2004, 2010 g10 Code GmbH This file is part of GPGME. @@ -157,4 +157,8 @@ gpgme_error_t _gpgme_engine_cancel (engine_t engine); gpgme_error_t _gpgme_engine_cancel_op (engine_t engine); +gpgme_error_t _gpgme_engine_op_passwd (engine_t engine, gpgme_key_t key, + unsigned int flags); + + #endif /* ENGINE_H */ diff --git a/src/gpgme-tool.c b/src/gpgme-tool.c index 0af65c32..ad647fc9 100644 --- a/src/gpgme-tool.c +++ b/src/gpgme-tool.c @@ -1,6 +1,5 @@ /* gpgme-tool.c - GnuPG Made Easy. - Copyright (C) 2000 Werner Koch (dd9jn) - Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007 g10 Code GmbH + Copyright (C) 2009, 2010 g10 Code GmbH This file is part of GPGME. @@ -15,9 +14,8 @@ Lesser General Public License for more details. You should have received a copy of the GNU Lesser 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. */ + License along with this program; if not, see . + */ #if HAVE_CONFIG_H #include @@ -1119,7 +1117,30 @@ gt_vfs_create (gpgme_tool_t gt, const char *container_file, int flags) } -// TODO +static const char hlp_passwd[] = + "PASSWD \n" + "\n" + "Ask the backend to change the passphrase for the key\n" + "specified by USER-ID."; +gpg_error_t +gt_passwd (gpgme_tool_t gt, char *fpr) +{ + gpg_error_t err; + gpgme_key_t key; + + err = gpgme_get_key (gt->ctx, fpr, &key, 0); + if (err) + return err; + + err = gpgme_op_passwd (gt->ctx, key, 0); + gpgme_key_unref (key); + return err; +} + + + + +/* TODO */ #define GT_RESULT_ENCRYPT 0x1 #define GT_RESULT_DECRYPT 0x2 #define GT_RESULT_SIGN 0x4 @@ -1974,6 +1995,16 @@ cmd_vfs_create (assuan_context_t ctx, char *line) } +static gpg_error_t +cmd_passwd (assuan_context_t ctx, char *line) +{ + struct server *server = assuan_get_pointer (ctx); + + return gt_passwd (server->gt, line); +} + + + static gpg_error_t cmd_result (assuan_context_t ctx, char *line) { @@ -2076,6 +2107,7 @@ register_commands (assuan_context_t ctx) { "STRERROR", cmd_strerror }, { "PUBKEY_ALGO_NAME", cmd_pubkey_algo_name }, { "HASH_ALGO_NAME", cmd_hash_algo_name }, + { "PASSWD", cmd_passwd, hlp_passwd }, { NULL } }; int idx; diff --git a/src/gpgme.c b/src/gpgme.c index 2d709e40..fe601a09 100644 --- a/src/gpgme.c +++ b/src/gpgme.c @@ -792,6 +792,12 @@ gpgme_pubkey_algo_name (gpgme_pubkey_algo_t algo) case GPGME_PK_ELG: return "ELG"; + case GPGME_PK_ECDSA: + return "ECDSA"; + + case GPGME_PK_ECDH: + return "ECDH"; + default: return NULL; } diff --git a/src/gpgme.def b/src/gpgme.def index eee25311..1a685ffe 100644 --- a/src/gpgme.def +++ b/src/gpgme.def @@ -196,5 +196,8 @@ EXPORTS gpgme_set_sub_protocol @150 gpgme_get_sub_protocol @151 + gpgme_op_passwd_start @152 + gpgme_op_passwd @153 + ; END diff --git a/src/gpgme.h.in b/src/gpgme.h.in index 13a33992..68ebd1a4 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -1,6 +1,7 @@ /* gpgme.h - Public interface to GnuPG Made Easy. -*- c -*- Copyright (C) 2000 Werner Koch (dd9jn) - Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2009 g10 Code GmbH + Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2009 + 2010 g10 Code GmbH This file is part of GPGME. @@ -209,7 +210,9 @@ typedef enum GPGME_PK_RSA_S = 3, GPGME_PK_ELG_E = 16, GPGME_PK_DSA = 17, - GPGME_PK_ELG = 20 + GPGME_PK_ELG = 20, + GPGME_PK_ECDSA = 301, + GPGME_PK_ECDH = 302 } gpgme_pubkey_algo_t; @@ -1664,6 +1667,14 @@ gpgme_error_t gpgme_op_keylist_next (gpgme_ctx_t ctx, gpgme_key_t *r_key); /* Terminate a pending keylist operation within CTX. */ gpgme_error_t gpgme_op_keylist_end (gpgme_ctx_t ctx); +/* Change the passphrase for KEY. FLAGS is reserved for future use + and must be passed as 0. */ +gpgme_error_t gpgme_op_passwd_start (gpgme_ctx_t ctx, gpgme_key_t key, + unsigned int flags); +gpgme_error_t gpgme_op_passwd (gpgme_ctx_t ctx, gpgme_key_t key, + unsigned int flags); + + /* Trust items and operations. */ diff --git a/src/libgpgme.vers b/src/libgpgme.vers index a9ddfb3c..9d927cef 100644 --- a/src/libgpgme.vers +++ b/src/libgpgme.vers @@ -76,6 +76,9 @@ GPGME_1.1 { gpgme_key_from_uid; gpgme_set_sub_protocol; gpgme_get_sub_protocol; + + gpgme_op_passwd_start; + gpgme_op_passwd; }; diff --git a/src/passwd.c b/src/passwd.c new file mode 100644 index 00000000..d189814d --- /dev/null +++ b/src/passwd.c @@ -0,0 +1,95 @@ +/* passwd.c - Passphrase changing function + Copyright (C) 2010 g10 Code GmbH + + This file is part of GPGME. + + GPGME is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + GPGME 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, see . + */ + +#if HAVE_CONFIG_H +#include +#endif + +#include "gpgme.h" +#include "debug.h" +#include "context.h" +#include "ops.h" + + +static gpgme_error_t +passwd_status_handler (void *priv, gpgme_status_code_t code, char *args) +{ + (void)priv; + (void)code; + (void)args; + return 0; +} + + +static gpgme_error_t +passwd_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t key, + unsigned int flags) +{ + gpgme_error_t err; + + if (!key) + return gpg_error (GPG_ERR_INV_VALUE); + if (flags) + return gpg_error (GPG_ERR_INV_FLAG); + + err = _gpgme_op_reset (ctx, synchronous); + if (err) + return err; + + _gpgme_engine_set_status_handler (ctx->engine, passwd_status_handler, ctx); + + return _gpgme_engine_op_passwd (ctx->engine, key, flags); +} + + + +/* Change the passphrase for KEY. FLAGS is reserved for future use + and must be passed as 0. The engine is expected to present a user + interface to enter the old and the new passphrase. This is the + asynchronous variant. + + Note that if ever the need arises to supply a passphrase we can do + this with a flag value and the passphrase callback feature. */ +gpgme_error_t +gpgme_op_passwd_start (gpgme_ctx_t ctx, gpgme_key_t key, unsigned int flags) +{ + gpg_error_t err; + TRACE_BEG2 (DEBUG_CTX, "gpgme_op_passwd_start", ctx, + "key=%p, flags=0x%x", key, flags); + err = passwd_start (ctx, 0, key, flags); + return TRACE_ERR (err); +} + + +/* Change the passphrase for KEY. FLAGS is reserved for future use + and must be passed as 0. This is the synchronous variant. */ +gpgme_error_t +gpgme_op_passwd (gpgme_ctx_t ctx, gpgme_key_t key, unsigned int flags) +{ + gpgme_error_t err; + + TRACE_BEG2 (DEBUG_CTX, "gpgme_op_passwd", ctx, + "key=%p, flags=0x%x", key, flags); + + err = passwd_start (ctx, 1, key, flags); + if (!err) + err = _gpgme_wait_one (ctx); + return TRACE_ERR (err); +} +