summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2014-06-25 20:25:28 +0200
committerWerner Koch <wk@gnupg.org>2014-06-30 16:40:55 +0200
commit03018ef9eec75e4d91ea53c95547a77dedef8f80 (patch)
treeb0d129512c829f5c94f35ce76933861bd44b1d15
parentestream: Fix minor glitch in "%.*s" format. (diff)
downloadgnupg2-03018ef9eec75e4d91ea53c95547a77dedef8f80.tar.xz
gnupg2-03018ef9eec75e4d91ea53c95547a77dedef8f80.zip
gpg: Auto-create revocation certificates.
* configure.ac (GNUPG_OPENPGP_REVOC_DIR): New config define. * g10/revoke.c (create_revocation): Add arg "leadin". (gen_standard_revoke): New. * g10/openfile.c (get_openpgp_revocdir): New. (open_outfile): Add MODE value 3. * g10/keyid.c (hexfingerprint): New. * g10/keygen.c (do_generate_keypair): Call gen_standard_revoke. -- GnuPG-bug-id: 1042
-rw-r--r--configure.ac3
-rw-r--r--doc/gpg.texi9
-rw-r--r--g10/keydb.h1
-rw-r--r--g10/keygen.c2
-rw-r--r--g10/keyid.c14
-rw-r--r--g10/main.h2
-rw-r--r--g10/openfile.c28
-rw-r--r--g10/passphrase.c3
-rw-r--r--g10/revoke.c88
-rw-r--r--tests/openpgp/Makefile.am2
10 files changed, 143 insertions, 9 deletions
diff --git a/configure.ac b/configure.ac
index e26e51b4a..02e02bb1e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -444,7 +444,8 @@ AH_BOTTOM([
#else
#define GNUPG_DEFAULT_HOMEDIR "~/.gnupg"
#endif
-#define GNUPG_PRIVATE_KEYS_DIR "private-keys-v1.d"
+#define GNUPG_PRIVATE_KEYS_DIR "private-keys-v1.d"
+#define GNUPG_OPENPGP_REVOC_DIR "openpgp-revocs.d"
/* For some systems (DOS currently), we hardcode the path here. For
POSIX systems the values are constructed by the Makefiles, so that
diff --git a/doc/gpg.texi b/doc/gpg.texi
index 9c52282cb..5efc16e86 100644
--- a/doc/gpg.texi
+++ b/doc/gpg.texi
@@ -3106,6 +3106,15 @@ files; They all live in in the current home directory (@pxref{option
@item ~/.gnupg/secring.gpg.lock
The lock file for the secret keyring.
+ @item ~/.gnupg/openpgp-revocs.d/
+ This is the directory where gpg stores pre-generated revocation
+ certificates. It is suggested to backup those certificates and if the
+ primary private key is not stored on the disk to move them to an
+ external storage device. Anyone who can access theses files is able to
+ revoke the corresponding key. You may want to print them out. You
+ should backup all files in this directory and take care to keep this
+ backup closed away.
+
@item /usr[/local]/share/gnupg/options.skel
The skeleton options file.
diff --git a/g10/keydb.h b/g10/keydb.h
index b21d9550d..0cf6ca110 100644
--- a/g10/keydb.h
+++ b/g10/keydb.h
@@ -288,6 +288,7 @@ const char *colon_datestr_from_pk (PKT_public_key *pk);
const char *colon_datestr_from_sig (PKT_signature *sig);
const char *colon_expirestr_from_sig (PKT_signature *sig);
byte *fingerprint_from_pk( PKT_public_key *pk, byte *buf, size_t *ret_len );
+char *hexfingerprint (PKT_public_key *pk);
gpg_error_t keygrip_from_pk (PKT_public_key *pk, unsigned char *array);
gpg_error_t hexkeygrip_from_pk (PKT_public_key *pk, char **r_grip);
diff --git a/g10/keygen.c b/g10/keygen.c
index 35c146068..450923144 100644
--- a/g10/keygen.c
+++ b/g10/keygen.c
@@ -4000,6 +4000,8 @@ do_generate_keypair (struct para_data_s *para,
update_ownertrust (pk, ((get_ownertrust (pk) & ~TRUST_MASK)
| TRUST_ULTIMATE ));
+ gen_standard_revoke (pk);
+
if (!opt.batch)
{
tty_printf (_("public and secret key created and signed.\n") );
diff --git a/g10/keyid.c b/g10/keyid.c
index 9c94bd6b2..6ce6f3277 100644
--- a/g10/keyid.c
+++ b/g10/keyid.c
@@ -772,6 +772,20 @@ fingerprint_from_pk (PKT_public_key *pk, byte *array, size_t *ret_len)
}
+/* Return an allocated buffer with the fingerprint of PK formatted as
+ a plain hexstring. */
+char *
+hexfingerprint (PKT_public_key *pk)
+{
+ unsigned char fpr[MAX_FINGERPRINT_LEN];
+ size_t len;
+ char *result;
+
+ fingerprint_from_pk (pk, fpr, &len);
+ result = xmalloc (2 * len + 1);
+ bin2hex (fpr, len, result);
+ return result;
+}
diff --git a/g10/main.h b/g10/main.h
index ae0bc8c26..e75f6168f 100644
--- a/g10/main.h
+++ b/g10/main.h
@@ -274,6 +274,7 @@ int open_outfile (int inp_fd, const char *iname, int mode,
int restrictedperm, iobuf_t *a);
iobuf_t open_sigfile( const char *iname, progress_filter_context_t *pfx );
void try_make_homedir( const char *fname );
+char *get_openpgp_revocdir (const char *home);
/*-- seskey.c --*/
void make_session_key( DEK *dek );
@@ -317,6 +318,7 @@ int enarmor_file( const char *fname );
/*-- revoke.c --*/
struct revocation_reason_info;
+int gen_standard_revoke (PKT_public_key *psk);
int gen_revoke( const char *uname );
int gen_desig_revoke( const char *uname, strlist_t locusr);
int revocation_reason_build_cb( PKT_signature *sig, void *opaque );
diff --git a/g10/openfile.c b/g10/openfile.c
index 901387d31..5a436485b 100644
--- a/g10/openfile.c
+++ b/g10/openfile.c
@@ -174,9 +174,10 @@ ask_outfile_name( const char *name, size_t namelen )
* Mode 0 = use ".gpg"
* 1 = use ".asc"
* 2 = use ".sig"
+ * 3 = use ".rev"
*
* If INP_FD is not -1 the function simply creates an IOBUF for that
- * file descriptor and ignorea INAME and MODE. Note that INP_FD won't
+ * file descriptor and ignore INAME and MODE. Note that INP_FD won't
* be closed if the returned IOBUF is closed. With RESTRICTEDPERM a
* file will be created with mode 700 if possible.
*/
@@ -239,7 +240,8 @@ open_outfile (int inp_fd, const char *iname, int mode, int restrictedperm,
const char *newsfx;
newsfx = (mode==1 ? ".asc" :
- mode==2 ? ".sig" : ".gpg");
+ mode==2 ? ".sig" :
+ mode==3 ? ".rev" : ".gpg");
buf = xmalloc (strlen(iname)+4+1);
strcpy (buf, iname);
@@ -258,6 +260,7 @@ open_outfile (int inp_fd, const char *iname, int mode, int restrictedperm,
buf = xstrconcat (iname,
(mode==1 ? EXTSEP_S "asc" :
mode==2 ? EXTSEP_S "sig" :
+ mode==3 ? EXTSEP_S "rev" :
/* */ EXTSEP_S GPGEXT_GPG),
NULL);
}
@@ -451,3 +454,24 @@ try_make_homedir (const char *fname)
copy_options_file( fname );
}
}
+
+
+/* Get and if needed create a string with the directory used to store
+ openpgp revocations. */
+char *
+get_openpgp_revocdir (const char *home)
+{
+ char *fname;
+ struct stat statbuf;
+
+ fname = make_filename (home, GNUPG_OPENPGP_REVOC_DIR, NULL);
+ if (stat (fname, &statbuf) && errno == ENOENT)
+ {
+ if (gnupg_mkdir (fname, "-rwx"))
+ log_error (_("can't create directory '%s': %s\n"),
+ fname, strerror (errno) );
+ else if (!opt.quiet)
+ log_info (_("directory '%s' created\n"), fname);
+ }
+ return fname;
+}
diff --git a/g10/passphrase.c b/g10/passphrase.c
index 280d8a9b5..9d3f497ba 100644
--- a/g10/passphrase.c
+++ b/g10/passphrase.c
@@ -633,7 +633,8 @@ emit_status_need_passphrase (u32 *keyid, u32 *mainkeyid, int pubkey_algo)
/* Return an allocated utf-8 string describing the key PK. If ESCAPED
is true spaces and control characters are percent or plus escaped.
- MODE 0 is for the common prompt, MODE 1 for the import prompt. */
+ MODE describes the use of the key description; use one of the
+ FORMAT_KEYDESC_ macros. */
char *
gpg_format_keydesc (PKT_public_key *pk, int mode, int escaped)
{
diff --git a/g10/revoke.c b/g10/revoke.c
index 069453ebc..bf5e33b3f 100644
--- a/g10/revoke.c
+++ b/g10/revoke.c
@@ -436,12 +436,14 @@ gen_desig_revoke( const char *uname, strlist_t locusr )
revocation reason. PSK is the public primary key - we expect that
a corresponding secret key is available. KEYBLOCK is the entire
KEYBLOCK which is used in PGP mode to write a a minimal key and not
- just the naked revocation signature; it may be NULL. */
+ just the naked revocation signature; it may be NULL. If LEADINTEXT
+ is not NULL, it is written right before the (armored) output.*/
static int
create_revocation (const char *filename,
struct revocation_reason_info *reason,
PKT_public_key *psk,
- kbnode_t keyblock)
+ kbnode_t keyblock,
+ const char *leadintext, int suffix)
{
int rc;
iobuf_t out = NULL;
@@ -451,9 +453,12 @@ create_revocation (const char *filename,
afx = new_armor_context ();
- if ((rc = open_outfile (-1, filename, 0, 1, &out)))
+ if ((rc = open_outfile (-1, filename, suffix, 1, &out)))
goto leave;
+ if (leadintext )
+ iobuf_writestr (out, leadintext);
+
afx->what = 1;
afx->hdrlines = "Comment: This is a revocation certificate\n";
push_armor_filter (afx, out);
@@ -502,6 +507,81 @@ create_revocation (const char *filename,
}
+/* This function is used to generate a standard revocation certificate
+ by gpg's interactive key generation function. The certificate is
+ stored at a dedicated place in a slightly modified form to avoid an
+ accidental import. PSK is the primary key; a corresponding secret
+ key must be available. */
+int
+gen_standard_revoke (PKT_public_key *psk)
+{
+ int rc;
+ estream_t memfp;
+ struct revocation_reason_info reason;
+ char *dir, *tmpstr, *fname;
+ void *leadin;
+ size_t len;
+ u32 keyid[2];
+ char pkstrbuf[PUBKEY_STRING_SIZE];
+ char *orig_codeset;
+
+ dir = get_openpgp_revocdir (opt.homedir);
+ tmpstr = hexfingerprint (psk);
+ fname = xstrconcat (dir, DIRSEP_S, tmpstr, NULL);
+ xfree (tmpstr);
+ xfree (dir);
+
+ keyid_from_pk (psk, keyid);
+
+ memfp = es_fopenmem (0, "r+");
+ if (!memfp)
+ log_fatal ("error creating memory stream\n");
+
+ orig_codeset = i18n_switchto_utf8 ();
+
+ es_fprintf (memfp, "%s\n\n",
+ _("This is a revocation certificate for the OpenPGP key:"));
+
+ es_fprintf (memfp, "pub %s/%s %s\n",
+ pubkey_string (psk, pkstrbuf, sizeof pkstrbuf),
+ keystr (keyid),
+ datestr_from_pk (psk));
+
+ print_fingerprint (memfp, psk, 3);
+
+ tmpstr = get_user_id (keyid, &len);
+ es_fprintf (memfp, "uid%*s%.*s\n\n",
+ (int)keystrlen () + 10, "",
+ (int)len, tmpstr);
+ xfree (tmpstr);
+
+ es_fprintf (memfp, "%s\n\n%s\n\n:",
+ _("Use it to revoke this key in case of a compromise or loss of\n"
+ "the secret key. However, if the secret key is still accessible,\n"
+ "it is better to generate a new revocation certificate and give\n"
+ "a reason for the revocation."),
+ _("To avoid an accidental use of this file, a colon has been inserted\n"
+ "before the 5 dashes below. Remove this colon with a text editor\n"
+ "before making use of this revocation certificate."));
+
+ es_putc (0, memfp);
+
+ i18n_switchback (orig_codeset);
+
+ if (es_fclose_snatch (memfp, &leadin, NULL))
+ log_fatal ("error snatching memory stream\n");
+
+ reason.code = 0x00; /* No particular reason. */
+ reason.desc = NULL;
+ rc = create_revocation (fname, &reason, psk, NULL, leadin, 3);
+ xfree (leadin);
+ xfree (fname);
+
+ return rc;
+}
+
+
+
/****************
* Generate a revocation certificate for UNAME
*/
@@ -582,7 +662,7 @@ gen_revoke (const char *uname)
if (!opt.armor)
tty_printf (_("ASCII armored output forced.\n"));
- rc = create_revocation (NULL, reason, psk, keyblock);
+ rc = create_revocation (NULL, reason, psk, keyblock, NULL, 0);
if (rc)
goto leave;
diff --git a/tests/openpgp/Makefile.am b/tests/openpgp/Makefile.am
index ea1d54f8b..4b1c219f9 100644
--- a/tests/openpgp/Makefile.am
+++ b/tests/openpgp/Makefile.am
@@ -77,7 +77,7 @@ CLEANFILES = prepared.stamp x y yy z out err $(data_files) \
gnupg-test.stop pubring.gpg~ random_seed gpg-agent.log
clean-local:
- -rm -rf private-keys-v1.d
+ -rm -rf private-keys-v1.d openpgp-revocs.d
# We need to depend on a couple of programs so that the tests don't