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
This commit is contained in:
Werner Koch 2014-06-25 20:25:28 +02:00
parent aa5b4392aa
commit 03018ef9ee
10 changed files with 143 additions and 9 deletions

View File

@ -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

View File

@ -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.

View File

@ -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);

View File

@ -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") );

View File

@ -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;
}

View File

@ -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 );

View File

@ -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;
}

View File

@ -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)
{

View File

@ -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;

View File

@ -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