mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
Merge branch 'master' into gniibe/t6364
This commit is contained in:
commit
01eef54e2c
@ -142,13 +142,6 @@ struct
|
|||||||
passphrase change. */
|
passphrase change. */
|
||||||
int enable_passphrase_history;
|
int enable_passphrase_history;
|
||||||
|
|
||||||
/* If set the extended key format is used for new keys. Note that
|
|
||||||
* this may have the value 2 in which case
|
|
||||||
* --disable-extended-key-format won't have any effect and thus
|
|
||||||
* effectivley locking it. This is required to support existing
|
|
||||||
* profiles which lock the use of --enable-extended-key-format. */
|
|
||||||
int enable_extended_key_format;
|
|
||||||
|
|
||||||
int running_detached; /* We are running detached from the tty. */
|
int running_detached; /* We are running detached from the tty. */
|
||||||
|
|
||||||
/* If this global option is true, the passphrase cache is ignored
|
/* If this global option is true, the passphrase cache is ignored
|
||||||
@ -567,7 +560,7 @@ unsigned char get_standard_s2k_count_rfc4880 (void);
|
|||||||
unsigned long get_standard_s2k_time (void);
|
unsigned long get_standard_s2k_time (void);
|
||||||
int agent_protect (const unsigned char *plainkey, const char *passphrase,
|
int agent_protect (const unsigned char *plainkey, const char *passphrase,
|
||||||
unsigned char **result, size_t *resultlen,
|
unsigned char **result, size_t *resultlen,
|
||||||
unsigned long s2k_count, int use_ocb);
|
unsigned long s2k_count);
|
||||||
gpg_error_t agent_unprotect (ctrl_t ctrl,
|
gpg_error_t agent_unprotect (ctrl_t ctrl,
|
||||||
const unsigned char *protectedkey, const char *passphrase,
|
const unsigned char *protectedkey, const char *passphrase,
|
||||||
gnupg_isotime_t protected_at,
|
gnupg_isotime_t protected_at,
|
||||||
|
@ -1543,6 +1543,17 @@ agent_askpin (ctrl_t ctrl,
|
|||||||
NULL, NULL, NULL, NULL, NULL, NULL);
|
NULL, NULL, NULL, NULL, NULL, NULL);
|
||||||
if (rc)
|
if (rc)
|
||||||
pininfo->with_repeat = 0; /* Pinentry does not support it. */
|
pininfo->with_repeat = 0; /* Pinentry does not support it. */
|
||||||
|
|
||||||
|
if (pininfo->with_repeat)
|
||||||
|
{
|
||||||
|
snprintf (line, DIM(line), "SETREPEATOK %s",
|
||||||
|
L_("Passphrases match."));
|
||||||
|
rc = assuan_transact (entry_ctx, line,
|
||||||
|
NULL, NULL, NULL, NULL, NULL, NULL);
|
||||||
|
if (rc)
|
||||||
|
rc = 0; /* Pinentry does not support it. */
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
pininfo->repeat_okay = 0;
|
pininfo->repeat_okay = 0;
|
||||||
pininfo->status = 0;
|
pininfo->status = 0;
|
||||||
@ -1802,6 +1813,16 @@ agent_get_passphrase (ctrl_t ctrl,
|
|||||||
if (rc)
|
if (rc)
|
||||||
pininfo->with_repeat = 0; /* Pinentry does not support it. */
|
pininfo->with_repeat = 0; /* Pinentry does not support it. */
|
||||||
|
|
||||||
|
if (pininfo->with_repeat)
|
||||||
|
{
|
||||||
|
snprintf (line, DIM(line), "SETREPEATOK %s",
|
||||||
|
L_("Passphrases match."));
|
||||||
|
rc = assuan_transact (entry_ctx, line,
|
||||||
|
NULL, NULL, NULL, NULL, NULL, NULL);
|
||||||
|
if (rc)
|
||||||
|
rc = 0; /* Pinentry does not support it. */
|
||||||
|
}
|
||||||
|
|
||||||
(void)setup_genpin (ctrl);
|
(void)setup_genpin (ctrl);
|
||||||
|
|
||||||
rc = setup_enforced_constraints (ctrl);
|
rc = setup_enforced_constraints (ctrl);
|
||||||
|
@ -3142,7 +3142,7 @@ ssh_key_to_protected_buffer (gcry_sexp_t key, const char *passphrase,
|
|||||||
buffer_new, buffer_new_n);
|
buffer_new, buffer_new_n);
|
||||||
|
|
||||||
if (*passphrase)
|
if (*passphrase)
|
||||||
err = agent_protect (buffer_new, passphrase, buffer, buffer_n, 0, -1);
|
err = agent_protect (buffer_new, passphrase, buffer, buffer_n, 0);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* The key derivation function does not support zero length
|
/* The key derivation function does not support zero length
|
||||||
|
@ -1218,12 +1218,6 @@ cmd_keyattr (assuan_context_t ctx, char *line)
|
|||||||
if (ctrl->restricted)
|
if (ctrl->restricted)
|
||||||
return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
|
return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
|
||||||
|
|
||||||
if (!opt.enable_extended_key_format)
|
|
||||||
{
|
|
||||||
err = gpg_error (GPG_ERR_NOT_SUPPORTED);
|
|
||||||
goto leave;
|
|
||||||
}
|
|
||||||
|
|
||||||
opt_delete = has_option (line, "--delete");
|
opt_delete = has_option (line, "--delete");
|
||||||
|
|
||||||
line = skip_options (line);
|
line = skip_options (line);
|
||||||
@ -2987,7 +2981,7 @@ cmd_import_key (assuan_context_t ctx, char *line)
|
|||||||
if (passphrase)
|
if (passphrase)
|
||||||
{
|
{
|
||||||
err = agent_protect (key, passphrase, &finalkey, &finalkeylen,
|
err = agent_protect (key, passphrase, &finalkey, &finalkeylen,
|
||||||
ctrl->s2k_count, -1);
|
ctrl->s2k_count);
|
||||||
if (!err)
|
if (!err)
|
||||||
err = agent_write_private_key (grip, finalkey, finalkeylen, force,
|
err = agent_write_private_key (grip, finalkey, finalkeylen, force,
|
||||||
NULL, NULL, opt_timestamp);
|
NULL, NULL, opt_timestamp);
|
||||||
|
@ -1146,7 +1146,7 @@ convert_from_openpgp_native (ctrl_t ctrl,
|
|||||||
|
|
||||||
if (!agent_protect (*r_key, passphrase,
|
if (!agent_protect (*r_key, passphrase,
|
||||||
&protectedkey, &protectedkeylen,
|
&protectedkey, &protectedkeylen,
|
||||||
ctrl->s2k_count, -1))
|
ctrl->s2k_count))
|
||||||
agent_write_private_key (grip, protectedkey, protectedkeylen, 1,
|
agent_write_private_key (grip, protectedkey, protectedkeylen, 1,
|
||||||
NULL, NULL, 0);
|
NULL, NULL, 0);
|
||||||
xfree (protectedkey);
|
xfree (protectedkey);
|
||||||
|
254
agent/findkey.c
254
agent/findkey.c
@ -2,6 +2,7 @@
|
|||||||
* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007,
|
* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007,
|
||||||
* 2010, 2011 Free Software Foundation, Inc.
|
* 2010, 2011 Free Software Foundation, Inc.
|
||||||
* Copyright (C) 2014, 2019 Werner Koch
|
* Copyright (C) 2014, 2019 Werner Koch
|
||||||
|
* Copyright (C) 2023 g10 Code GmbH
|
||||||
*
|
*
|
||||||
* This file is part of GnuPG.
|
* This file is part of GnuPG.
|
||||||
*
|
*
|
||||||
@ -79,19 +80,114 @@ linefeed_to_percent0A (const char *string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Note: Ownership of FNAME and FP are moved to this function. */
|
/* Write the S-expression formatted key (BUFFER,LENGTH) to our key
|
||||||
static gpg_error_t
|
* storage. With FORCE passed as true an existing key with the given
|
||||||
write_extended_private_key (char *fname, estream_t fp, int update, int newkey,
|
* GRIP will get overwritten. If SERIALNO and KEYREF are given a
|
||||||
const void *buf, size_t len,
|
* Token line is added to the key if the extended format is used. If
|
||||||
const char *serialno, const char *keyref,
|
* TIMESTAMP is not zero and the key doies not yet exists it will be
|
||||||
time_t timestamp)
|
* recorded as creation date. */
|
||||||
|
int
|
||||||
|
agent_write_private_key (const unsigned char *grip,
|
||||||
|
const void *buffer, size_t length, int force,
|
||||||
|
const char *serialno, const char *keyref,
|
||||||
|
time_t timestamp)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
|
char *fname;
|
||||||
|
estream_t fp;
|
||||||
|
char hexgrip[40+4+1];
|
||||||
|
int update, newkey;
|
||||||
nvc_t pk = NULL;
|
nvc_t pk = NULL;
|
||||||
gcry_sexp_t key = NULL;
|
gcry_sexp_t key = NULL;
|
||||||
int remove = 0;
|
int remove = 0;
|
||||||
char *token = NULL;
|
char *token = NULL;
|
||||||
|
|
||||||
|
bin2hex (grip, 20, hexgrip);
|
||||||
|
strcpy (hexgrip+40, ".key");
|
||||||
|
|
||||||
|
fname = make_filename (gnupg_homedir (), GNUPG_PRIVATE_KEYS_DIR,
|
||||||
|
hexgrip, NULL);
|
||||||
|
|
||||||
|
/* FIXME: Write to a temp file first so that write failures during
|
||||||
|
key updates won't lead to a key loss. */
|
||||||
|
|
||||||
|
if (!force && !gnupg_access (fname, F_OK))
|
||||||
|
{
|
||||||
|
log_error ("secret key file '%s' already exists\n", fname);
|
||||||
|
xfree (fname);
|
||||||
|
return gpg_error (GPG_ERR_EEXIST);
|
||||||
|
}
|
||||||
|
|
||||||
|
fp = es_fopen (fname, force? "rb+,mode=-rw" : "wbx,mode=-rw");
|
||||||
|
if (!fp)
|
||||||
|
{
|
||||||
|
gpg_error_t tmperr = gpg_error_from_syserror ();
|
||||||
|
|
||||||
|
if (force && gpg_err_code (tmperr) == GPG_ERR_ENOENT)
|
||||||
|
{
|
||||||
|
fp = es_fopen (fname, "wbx,mode=-rw");
|
||||||
|
if (!fp)
|
||||||
|
tmperr = gpg_error_from_syserror ();
|
||||||
|
}
|
||||||
|
if (!fp)
|
||||||
|
{
|
||||||
|
log_error ("can't create '%s': %s\n", fname, gpg_strerror (tmperr));
|
||||||
|
xfree (fname);
|
||||||
|
return tmperr;
|
||||||
|
}
|
||||||
|
update = 0;
|
||||||
|
newkey = 1;
|
||||||
|
}
|
||||||
|
else if (force)
|
||||||
|
{
|
||||||
|
gpg_error_t rc;
|
||||||
|
char first;
|
||||||
|
|
||||||
|
/* See if an existing key is in extended format. */
|
||||||
|
if (es_fread (&first, 1, 1, fp) != 1)
|
||||||
|
{
|
||||||
|
rc = gpg_error_from_syserror ();
|
||||||
|
log_error ("error reading first byte from '%s': %s\n",
|
||||||
|
fname, strerror (errno));
|
||||||
|
xfree (fname);
|
||||||
|
es_fclose (fp);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = es_fseek (fp, 0, SEEK_SET);
|
||||||
|
if (rc)
|
||||||
|
{
|
||||||
|
log_error ("error seeking in '%s': %s\n", fname, strerror (errno));
|
||||||
|
xfree (fname);
|
||||||
|
es_fclose (fp);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (first == '(')
|
||||||
|
{
|
||||||
|
/* Key is still in the old format - force it into extended
|
||||||
|
* format. We do not request an update here because an
|
||||||
|
* existing key is not yet in extended key format and no
|
||||||
|
* extended infos are yet available. */
|
||||||
|
update = 0;
|
||||||
|
newkey = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Key is already in the extended format. */
|
||||||
|
update = 1;
|
||||||
|
newkey = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* The key file did not exist: we assume this is a new key and
|
||||||
|
* write the Created: entry. */
|
||||||
|
update = 0;
|
||||||
|
newkey = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (update)
|
if (update)
|
||||||
{
|
{
|
||||||
int line;
|
int line;
|
||||||
@ -115,10 +211,11 @@ write_extended_private_key (char *fname, estream_t fp, int update, int newkey,
|
|||||||
}
|
}
|
||||||
es_clearerr (fp);
|
es_clearerr (fp);
|
||||||
|
|
||||||
err = gcry_sexp_sscan (&key, NULL, buf, len);
|
/* Turn (BUFFER,LENGTH) into a gcrypt s-expression and set it into
|
||||||
|
* our name value container. */
|
||||||
|
err = gcry_sexp_sscan (&key, NULL, buffer, length);
|
||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
err = nvc_set_private_key (pk, key);
|
err = nvc_set_private_key (pk, key);
|
||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
@ -153,7 +250,7 @@ write_extended_private_key (char *fname, estream_t fp, int update, int newkey,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If a timestamp has been supplied and the key is new write a
|
/* If a timestamp has been supplied and the key is new, write a
|
||||||
* creation timestamp. (We douple check that there is no Created
|
* creation timestamp. (We douple check that there is no Created
|
||||||
* item yet.)*/
|
* item yet.)*/
|
||||||
if (timestamp && newkey && !nvc_lookup (pk, "Created:"))
|
if (timestamp && newkey && !nvc_lookup (pk, "Created:"))
|
||||||
@ -166,7 +263,7 @@ write_extended_private_key (char *fname, estream_t fp, int update, int newkey,
|
|||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Back to start and write. */
|
||||||
err = es_fseek (fp, 0, SEEK_SET);
|
err = es_fseek (fp, 0, SEEK_SET);
|
||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
@ -212,133 +309,6 @@ write_extended_private_key (char *fname, estream_t fp, int update, int newkey,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write an S-expression formatted key to our key storage. With FORCE
|
|
||||||
* passed as true an existing key with the given GRIP will get
|
|
||||||
* overwritten. If SERIALNO and KEYREF are given a Token line is
|
|
||||||
* added to the key if the extended format is used. If TIMESTAMP is
|
|
||||||
* not zero and the key doies not yet exists it will be recorded as
|
|
||||||
* creation date. */
|
|
||||||
int
|
|
||||||
agent_write_private_key (const unsigned char *grip,
|
|
||||||
const void *buffer, size_t length, int force,
|
|
||||||
const char *serialno, const char *keyref,
|
|
||||||
time_t timestamp)
|
|
||||||
{
|
|
||||||
char *fname;
|
|
||||||
estream_t fp;
|
|
||||||
char hexgrip[40+4+1];
|
|
||||||
|
|
||||||
bin2hex (grip, 20, hexgrip);
|
|
||||||
strcpy (hexgrip+40, ".key");
|
|
||||||
|
|
||||||
fname = make_filename (gnupg_homedir (), GNUPG_PRIVATE_KEYS_DIR,
|
|
||||||
hexgrip, NULL);
|
|
||||||
|
|
||||||
/* FIXME: Write to a temp file first so that write failures during
|
|
||||||
key updates won't lead to a key loss. */
|
|
||||||
|
|
||||||
if (!force && !gnupg_access (fname, F_OK))
|
|
||||||
{
|
|
||||||
log_error ("secret key file '%s' already exists\n", fname);
|
|
||||||
xfree (fname);
|
|
||||||
return gpg_error (GPG_ERR_EEXIST);
|
|
||||||
}
|
|
||||||
|
|
||||||
fp = es_fopen (fname, force? "rb+,mode=-rw" : "wbx,mode=-rw");
|
|
||||||
if (!fp)
|
|
||||||
{
|
|
||||||
gpg_error_t tmperr = gpg_error_from_syserror ();
|
|
||||||
|
|
||||||
if (force && gpg_err_code (tmperr) == GPG_ERR_ENOENT)
|
|
||||||
{
|
|
||||||
fp = es_fopen (fname, "wbx,mode=-rw");
|
|
||||||
if (!fp)
|
|
||||||
tmperr = gpg_error_from_syserror ();
|
|
||||||
}
|
|
||||||
if (!fp)
|
|
||||||
{
|
|
||||||
log_error ("can't create '%s': %s\n", fname, gpg_strerror (tmperr));
|
|
||||||
xfree (fname);
|
|
||||||
return tmperr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (force)
|
|
||||||
{
|
|
||||||
gpg_error_t rc;
|
|
||||||
char first;
|
|
||||||
|
|
||||||
/* See if an existing key is in extended format. */
|
|
||||||
if (es_fread (&first, 1, 1, fp) != 1)
|
|
||||||
{
|
|
||||||
rc = gpg_error_from_syserror ();
|
|
||||||
log_error ("error reading first byte from '%s': %s\n",
|
|
||||||
fname, strerror (errno));
|
|
||||||
xfree (fname);
|
|
||||||
es_fclose (fp);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = es_fseek (fp, 0, SEEK_SET);
|
|
||||||
if (rc)
|
|
||||||
{
|
|
||||||
log_error ("error seeking in '%s': %s\n", fname, strerror (errno));
|
|
||||||
xfree (fname);
|
|
||||||
es_fclose (fp);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (first != '(')
|
|
||||||
{
|
|
||||||
/* Key is already in the extended format. */
|
|
||||||
return write_extended_private_key (fname, fp, 1, 0, buffer, length,
|
|
||||||
serialno, keyref, timestamp);
|
|
||||||
}
|
|
||||||
if (first == '(' && opt.enable_extended_key_format)
|
|
||||||
{
|
|
||||||
/* Key is in the old format - but we want the extended format. */
|
|
||||||
return write_extended_private_key (fname, fp, 0, 0, buffer, length,
|
|
||||||
serialno, keyref, timestamp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opt.enable_extended_key_format)
|
|
||||||
return write_extended_private_key (fname, fp, 0, 1, buffer, length,
|
|
||||||
serialno, keyref, timestamp);
|
|
||||||
|
|
||||||
if (es_fwrite (buffer, length, 1, fp) != 1)
|
|
||||||
{
|
|
||||||
gpg_error_t tmperr = gpg_error_from_syserror ();
|
|
||||||
log_error ("error writing '%s': %s\n", fname, gpg_strerror (tmperr));
|
|
||||||
es_fclose (fp);
|
|
||||||
gnupg_remove (fname);
|
|
||||||
xfree (fname);
|
|
||||||
return tmperr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* When force is given, the file might have to be truncated. */
|
|
||||||
if (force && ftruncate (es_fileno (fp), es_ftello (fp)))
|
|
||||||
{
|
|
||||||
gpg_error_t tmperr = gpg_error_from_syserror ();
|
|
||||||
log_error ("error truncating '%s': %s\n", fname, gpg_strerror (tmperr));
|
|
||||||
es_fclose (fp);
|
|
||||||
gnupg_remove (fname);
|
|
||||||
xfree (fname);
|
|
||||||
return tmperr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (es_fclose (fp))
|
|
||||||
{
|
|
||||||
gpg_error_t tmperr = gpg_error_from_syserror ();
|
|
||||||
log_error ("error closing '%s': %s\n", fname, gpg_strerror (tmperr));
|
|
||||||
gnupg_remove (fname);
|
|
||||||
xfree (fname);
|
|
||||||
return tmperr;
|
|
||||||
}
|
|
||||||
bump_key_eventcounter ();
|
|
||||||
xfree (fname);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
gpg_error_t
|
gpg_error_t
|
||||||
agent_update_private_key (const unsigned char *grip, nvc_t pk)
|
agent_update_private_key (const unsigned char *grip, nvc_t pk)
|
||||||
@ -393,6 +363,7 @@ agent_update_private_key (const unsigned char *grip, nvc_t pk)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Callback function to try the unprotection from the passphrase query
|
/* Callback function to try the unprotection from the passphrase query
|
||||||
code. */
|
code. */
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
@ -1186,6 +1157,15 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce,
|
|||||||
return gpg_error (GPG_ERR_NO_SECKEY);
|
return gpg_error (GPG_ERR_NO_SECKEY);
|
||||||
|
|
||||||
err = read_key_file (grip? grip : ctrl->keygrip, &s_skey, &keymeta);
|
err = read_key_file (grip? grip : ctrl->keygrip, &s_skey, &keymeta);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
if (gpg_err_code (err) == GPG_ERR_ENOENT)
|
||||||
|
err = gpg_error (GPG_ERR_NO_SECKEY);
|
||||||
|
else
|
||||||
|
log_error ("findkey: error reading key file: %s\n",
|
||||||
|
gpg_strerror (err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
/* For use with the protection functions we also need the key as an
|
/* For use with the protection functions we also need the key as an
|
||||||
canonical encoded S-expression in a buffer. Create this buffer
|
canonical encoded S-expression in a buffer. Create this buffer
|
||||||
|
@ -57,7 +57,7 @@ store_key (gcry_sexp_t private, const char *passphrase, int force,
|
|||||||
{
|
{
|
||||||
unsigned char *p;
|
unsigned char *p;
|
||||||
|
|
||||||
rc = agent_protect (buf, passphrase, &p, &len, s2k_count, -1);
|
rc = agent_protect (buf, passphrase, &p, &len, s2k_count);
|
||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
xfree (buf);
|
xfree (buf);
|
||||||
|
@ -117,8 +117,6 @@ enum cmd_and_opt_values
|
|||||||
oCheckSymPassphrasePattern,
|
oCheckSymPassphrasePattern,
|
||||||
oMaxPassphraseDays,
|
oMaxPassphraseDays,
|
||||||
oEnablePassphraseHistory,
|
oEnablePassphraseHistory,
|
||||||
oDisableExtendedKeyFormat,
|
|
||||||
oEnableExtendedKeyFormat,
|
|
||||||
oStealSocket,
|
oStealSocket,
|
||||||
oUseStandardSocket,
|
oUseStandardSocket,
|
||||||
oNoUseStandardSocket,
|
oNoUseStandardSocket,
|
||||||
@ -241,8 +239,6 @@ static gpgrt_opt_t opts[] = {
|
|||||||
/* */ "@"
|
/* */ "@"
|
||||||
#endif
|
#endif
|
||||||
),
|
),
|
||||||
ARGPARSE_s_n (oDisableExtendedKeyFormat, "disable-extended-key-format", "@"),
|
|
||||||
ARGPARSE_s_n (oEnableExtendedKeyFormat, "enable-extended-key-format", "@"),
|
|
||||||
ARGPARSE_s_i (oListenBacklog, "listen-backlog", "@"),
|
ARGPARSE_s_i (oListenBacklog, "listen-backlog", "@"),
|
||||||
ARGPARSE_op_u (oAutoExpandSecmem, "auto-expand-secmem", "@"),
|
ARGPARSE_op_u (oAutoExpandSecmem, "auto-expand-secmem", "@"),
|
||||||
ARGPARSE_s_s (oFakedSystemTime, "faked-system-time", "@"),
|
ARGPARSE_s_s (oFakedSystemTime, "faked-system-time", "@"),
|
||||||
@ -318,7 +314,8 @@ static gpgrt_opt_t opts[] = {
|
|||||||
ARGPARSE_s_n (oNoUseStandardSocket, "no-use-standard-socket", "@"),
|
ARGPARSE_s_n (oNoUseStandardSocket, "no-use-standard-socket", "@"),
|
||||||
|
|
||||||
/* Dummy options. */
|
/* Dummy options. */
|
||||||
|
ARGPARSE_s_n (oNoop, "disable-extended-key-format", "@"),
|
||||||
|
ARGPARSE_s_n (oNoop, "enable-extended-key-format", "@"),
|
||||||
|
|
||||||
ARGPARSE_end () /* End of list */
|
ARGPARSE_end () /* End of list */
|
||||||
};
|
};
|
||||||
@ -888,7 +885,6 @@ parse_rereadable_options (gpgrt_argparse_t *pargs, int reread)
|
|||||||
opt.check_sym_passphrase_pattern = NULL;
|
opt.check_sym_passphrase_pattern = NULL;
|
||||||
opt.max_passphrase_days = MAX_PASSPHRASE_DAYS;
|
opt.max_passphrase_days = MAX_PASSPHRASE_DAYS;
|
||||||
opt.enable_passphrase_history = 0;
|
opt.enable_passphrase_history = 0;
|
||||||
opt.enable_extended_key_format = 1;
|
|
||||||
opt.ignore_cache_for_signing = 0;
|
opt.ignore_cache_for_signing = 0;
|
||||||
opt.allow_mark_trusted = 1;
|
opt.allow_mark_trusted = 1;
|
||||||
opt.sys_trustlist_name = NULL;
|
opt.sys_trustlist_name = NULL;
|
||||||
@ -980,14 +976,6 @@ parse_rereadable_options (gpgrt_argparse_t *pargs, int reread)
|
|||||||
opt.enable_passphrase_history = 1;
|
opt.enable_passphrase_history = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case oEnableExtendedKeyFormat:
|
|
||||||
opt.enable_extended_key_format = 2;
|
|
||||||
break;
|
|
||||||
case oDisableExtendedKeyFormat:
|
|
||||||
if (opt.enable_extended_key_format != 2)
|
|
||||||
opt.enable_extended_key_format = 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case oIgnoreCacheForSigning: opt.ignore_cache_for_signing = 1; break;
|
case oIgnoreCacheForSigning: opt.ignore_cache_for_signing = 1; break;
|
||||||
|
|
||||||
case oAllowMarkTrusted: opt.allow_mark_trusted = 1; break;
|
case oAllowMarkTrusted: opt.allow_mark_trusted = 1; break;
|
||||||
|
@ -74,8 +74,7 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
|
|||||||
no_shadow_info = 1;
|
no_shadow_info = 1;
|
||||||
else if (err)
|
else if (err)
|
||||||
{
|
{
|
||||||
if (gpg_err_code (err) != GPG_ERR_NO_SECKEY)
|
log_error ("failed to read the secret key\n");
|
||||||
log_error ("failed to read the secret key\n");
|
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,7 +87,7 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
|
|||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (agent_is_tpm2_key (s_skey))
|
if (s_skey && agent_is_tpm2_key (s_skey))
|
||||||
err = divert_tpm2_pkdecrypt (ctrl, ciphertext, shadow_info,
|
err = divert_tpm2_pkdecrypt (ctrl, ciphertext, shadow_info,
|
||||||
&buf, &len, r_padding);
|
&buf, &len, r_padding);
|
||||||
else
|
else
|
||||||
@ -96,7 +95,15 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
|
|||||||
&buf, &len, r_padding);
|
&buf, &len, r_padding);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
log_error ("smartcard decryption failed: %s\n", gpg_strerror (err));
|
/* We restore the original error (ie. no seckey) is no card
|
||||||
|
* has been found and we have no shadow key. This avoids a
|
||||||
|
* surprising "card removed" error code. */
|
||||||
|
if ((gpg_err_code (err) == GPG_ERR_CARD_REMOVED
|
||||||
|
|| gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT)
|
||||||
|
&& no_shadow_info)
|
||||||
|
err = gpg_error (GPG_ERR_NO_SECKEY);
|
||||||
|
else
|
||||||
|
log_error ("smartcard decryption failed: %s\n", gpg_strerror (err));
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,7 +97,6 @@ static const char *opt_passphrase;
|
|||||||
static char *opt_prompt;
|
static char *opt_prompt;
|
||||||
static int opt_status_msg;
|
static int opt_status_msg;
|
||||||
static const char *opt_agent_program;
|
static const char *opt_agent_program;
|
||||||
static int opt_debug_use_ocb;
|
|
||||||
|
|
||||||
static char *get_passphrase (int promptno);
|
static char *get_passphrase (int promptno);
|
||||||
static void release_passphrase (char *pw);
|
static void release_passphrase (char *pw);
|
||||||
@ -343,8 +342,7 @@ read_and_protect (const char *fname)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
pw = get_passphrase (1);
|
pw = get_passphrase (1);
|
||||||
rc = agent_protect (key, pw, &result, &resultlen, 0,
|
rc = agent_protect (key, pw, &result, &resultlen, 0);
|
||||||
opt_debug_use_ocb? 1 : -1);
|
|
||||||
release_passphrase (pw);
|
release_passphrase (pw);
|
||||||
xfree (key);
|
xfree (key);
|
||||||
if (rc)
|
if (rc)
|
||||||
@ -610,7 +608,7 @@ main (int argc, char **argv )
|
|||||||
case oHaveCert: opt_have_cert = 1; break;
|
case oHaveCert: opt_have_cert = 1; break;
|
||||||
case oPrompt: opt_prompt = pargs.r.ret_str; break;
|
case oPrompt: opt_prompt = pargs.r.ret_str; break;
|
||||||
case oStatusMsg: opt_status_msg = 1; break;
|
case oStatusMsg: opt_status_msg = 1; break;
|
||||||
case oDebugUseOCB: opt_debug_use_ocb = 1; break;
|
case oDebugUseOCB: /* dummy */; break;
|
||||||
|
|
||||||
default: pargs.err = ARGPARSE_PRINT_ERROR; break;
|
default: pargs.err = ARGPARSE_PRINT_ERROR; break;
|
||||||
}
|
}
|
||||||
|
136
agent/protect.c
136
agent/protect.c
@ -379,12 +379,11 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
|
|||||||
const char *passphrase,
|
const char *passphrase,
|
||||||
const char *timestamp_exp, size_t timestamp_exp_len,
|
const char *timestamp_exp, size_t timestamp_exp_len,
|
||||||
unsigned char **result, size_t *resultlen,
|
unsigned char **result, size_t *resultlen,
|
||||||
unsigned long s2k_count, int use_ocb)
|
unsigned long s2k_count)
|
||||||
{
|
{
|
||||||
gcry_cipher_hd_t hd;
|
gcry_cipher_hd_t hd;
|
||||||
const char *modestr;
|
const char *modestr;
|
||||||
unsigned char hashvalue[20];
|
int enclen, outlen;
|
||||||
int blklen, enclen, outlen;
|
|
||||||
unsigned char *iv = NULL;
|
unsigned char *iv = NULL;
|
||||||
unsigned int ivsize; /* Size of the buffer allocated for IV. */
|
unsigned int ivsize; /* Size of the buffer allocated for IV. */
|
||||||
const unsigned char *s2ksalt; /* Points into IV. */
|
const unsigned char *s2ksalt; /* Points into IV. */
|
||||||
@ -398,44 +397,26 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
|
|||||||
*resultlen = 0;
|
*resultlen = 0;
|
||||||
*result = NULL;
|
*result = NULL;
|
||||||
|
|
||||||
modestr = (use_ocb? "openpgp-s2k3-ocb-aes"
|
modestr = "openpgp-s2k3-ocb-aes";
|
||||||
/* */: "openpgp-s2k3-sha1-" PROT_CIPHER_STRING "-cbc");
|
|
||||||
|
|
||||||
rc = gcry_cipher_open (&hd, PROT_CIPHER,
|
rc = gcry_cipher_open (&hd, PROT_CIPHER,
|
||||||
use_ocb? GCRY_CIPHER_MODE_OCB :
|
GCRY_CIPHER_MODE_OCB,
|
||||||
GCRY_CIPHER_MODE_CBC,
|
|
||||||
GCRY_CIPHER_SECURE);
|
GCRY_CIPHER_SECURE);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
/* We need to work on a copy of the data because this makes it
|
/* We need to work on a copy of the data because this makes it
|
||||||
* easier to add the trailer and the padding and more important we
|
* easier to add the trailer and the padding and more important we
|
||||||
* have to prefix the text with 2 parenthesis. In CBC mode we
|
* have to prefix the text with 2 parenthesis. Due to OCB mode we
|
||||||
* have to allocate enough space for:
|
|
||||||
*
|
|
||||||
* ((<parameter_list>)(4:hash4:sha120:<hashvalue>)) + padding
|
|
||||||
*
|
|
||||||
* we always append a full block of random bytes as padding but
|
|
||||||
* encrypt only what is needed for a full blocksize. In OCB mode we
|
|
||||||
* have to allocate enough space for just:
|
* have to allocate enough space for just:
|
||||||
*
|
*
|
||||||
* ((<parameter_list>))
|
* ((<parameter_list>))
|
||||||
*/
|
*/
|
||||||
blklen = gcry_cipher_get_algo_blklen (PROT_CIPHER);
|
|
||||||
if (use_ocb)
|
/* (( )) */
|
||||||
{
|
outlen = 2 + protlen + 2 ;
|
||||||
/* (( )) */
|
enclen = outlen + 16 /* taglen */;
|
||||||
outlen = 2 + protlen + 2 ;
|
outbuf = gcry_malloc_secure (enclen);
|
||||||
enclen = outlen + 16 /* taglen */;
|
|
||||||
outbuf = gcry_malloc_secure (enclen);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* (( )( 4:hash 4:sha1 20:<hash> )) <padding> */
|
|
||||||
outlen = 2 + protlen + 2 + 6 + 6 + 23 + 2 + blklen;
|
|
||||||
enclen = outlen/blklen * blklen;
|
|
||||||
outbuf = gcry_malloc_secure (outlen);
|
|
||||||
}
|
|
||||||
if (!outbuf)
|
if (!outbuf)
|
||||||
{
|
{
|
||||||
rc = out_of_core ();
|
rc = out_of_core ();
|
||||||
@ -445,10 +426,10 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
|
|||||||
/* Allocate a buffer for the nonce and the salt. */
|
/* Allocate a buffer for the nonce and the salt. */
|
||||||
if (!rc)
|
if (!rc)
|
||||||
{
|
{
|
||||||
/* Allocate random bytes to be used as IV, padding and s2k salt
|
/* Allocate random bytes to be used as nonce and s2k salt. The
|
||||||
* or in OCB mode for a nonce and the s2k salt. The IV/nonce is
|
* nonce is set later because for OCB we need to set the key
|
||||||
* set later because for OCB we need to set the key first. */
|
* first. */
|
||||||
ivsize = (use_ocb? 12 : (blklen*2)) + 8;
|
ivsize = 12 + 8;
|
||||||
iv = xtrymalloc (ivsize);
|
iv = xtrymalloc (ivsize);
|
||||||
if (!iv)
|
if (!iv)
|
||||||
rc = gpg_error_from_syserror ();
|
rc = gpg_error_from_syserror ();
|
||||||
@ -484,40 +465,17 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
|
|||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
/* Set the IV/nonce. */
|
/* Set the IV/nonce. */
|
||||||
rc = gcry_cipher_setiv (hd, iv, use_ocb? 12 : blklen);
|
rc = gcry_cipher_setiv (hd, iv, 12);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
if (use_ocb)
|
/* In OCB Mode we use only the public key parameters as AAD. */
|
||||||
{
|
rc = gcry_cipher_authenticate (hd, hashbegin, protbegin - hashbegin);
|
||||||
/* In OCB Mode we use only the public key parameters as AAD. */
|
if (!rc)
|
||||||
rc = gcry_cipher_authenticate (hd, hashbegin, protbegin - hashbegin);
|
rc = gcry_cipher_authenticate (hd, timestamp_exp, timestamp_exp_len);
|
||||||
if (!rc)
|
if (!rc)
|
||||||
rc = gcry_cipher_authenticate (hd, timestamp_exp, timestamp_exp_len);
|
rc = gcry_cipher_authenticate
|
||||||
if (!rc)
|
(hd, protbegin+protlen, hashlen - (protbegin+protlen - hashbegin));
|
||||||
rc = gcry_cipher_authenticate
|
|
||||||
(hd, protbegin+protlen, hashlen - (protbegin+protlen - hashbegin));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Hash the entire expression for CBC mode. Because
|
|
||||||
* TIMESTAMP_EXP won't get protected, we can't simply hash a
|
|
||||||
* continuous buffer but need to call md_write several times. */
|
|
||||||
gcry_md_hd_t md;
|
|
||||||
|
|
||||||
rc = gcry_md_open (&md, GCRY_MD_SHA1, 0 );
|
|
||||||
if (!rc)
|
|
||||||
{
|
|
||||||
gcry_md_write (md, hashbegin, protbegin - hashbegin);
|
|
||||||
gcry_md_write (md, protbegin, protlen);
|
|
||||||
gcry_md_write (md, timestamp_exp, timestamp_exp_len);
|
|
||||||
gcry_md_write (md, protbegin+protlen,
|
|
||||||
hashlen - (protbegin+protlen - hashbegin));
|
|
||||||
memcpy (hashvalue, gcry_md_read (md, GCRY_MD_SHA1), 20);
|
|
||||||
gcry_md_close (md);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Encrypt. */
|
/* Encrypt. */
|
||||||
if (!rc)
|
if (!rc)
|
||||||
@ -527,36 +485,15 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
|
|||||||
*p++ = '(';
|
*p++ = '(';
|
||||||
memcpy (p, protbegin, protlen);
|
memcpy (p, protbegin, protlen);
|
||||||
p += protlen;
|
p += protlen;
|
||||||
if (use_ocb)
|
*p++ = ')';
|
||||||
{
|
*p++ = ')';
|
||||||
*p++ = ')';
|
|
||||||
*p++ = ')';
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy (p, ")(4:hash4:sha120:", 17);
|
|
||||||
p += 17;
|
|
||||||
memcpy (p, hashvalue, 20);
|
|
||||||
p += 20;
|
|
||||||
*p++ = ')';
|
|
||||||
*p++ = ')';
|
|
||||||
memcpy (p, iv+blklen, blklen); /* Add padding. */
|
|
||||||
p += blklen;
|
|
||||||
}
|
|
||||||
log_assert ( p - outbuf == outlen);
|
log_assert ( p - outbuf == outlen);
|
||||||
if (use_ocb)
|
gcry_cipher_final (hd);
|
||||||
|
rc = gcry_cipher_encrypt (hd, outbuf, outlen, NULL, 0);
|
||||||
|
if (!rc)
|
||||||
{
|
{
|
||||||
gcry_cipher_final (hd);
|
log_assert (outlen + 16 == enclen);
|
||||||
rc = gcry_cipher_encrypt (hd, outbuf, outlen, NULL, 0);
|
rc = gcry_cipher_gettag (hd, outbuf + outlen, 16);
|
||||||
if (!rc)
|
|
||||||
{
|
|
||||||
log_assert (outlen + 16 == enclen);
|
|
||||||
rc = gcry_cipher_gettag (hd, outbuf + outlen, 16);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rc = gcry_cipher_encrypt (hd, outbuf, enclen, NULL, 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -584,7 +521,7 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
|
|||||||
(int)strlen (modestr), modestr,
|
(int)strlen (modestr), modestr,
|
||||||
&saltpos,
|
&saltpos,
|
||||||
(unsigned int)strlen (countbuf), countbuf,
|
(unsigned int)strlen (countbuf), countbuf,
|
||||||
use_ocb? 12 : blklen, &ivpos, use_ocb? 12 : blklen, "",
|
12, &ivpos, 12, "",
|
||||||
enclen, &encpos, enclen, "");
|
enclen, &encpos, enclen, "");
|
||||||
if (!p)
|
if (!p)
|
||||||
{
|
{
|
||||||
@ -598,7 +535,7 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
|
|||||||
*resultlen = strlen (p);
|
*resultlen = strlen (p);
|
||||||
*result = (unsigned char*)p;
|
*result = (unsigned char*)p;
|
||||||
memcpy (p+saltpos, s2ksalt, 8);
|
memcpy (p+saltpos, s2ksalt, 8);
|
||||||
memcpy (p+ivpos, iv, use_ocb? 12 : blklen);
|
memcpy (p+ivpos, iv, 12);
|
||||||
memcpy (p+encpos, outbuf, enclen);
|
memcpy (p+encpos, outbuf, enclen);
|
||||||
xfree (iv);
|
xfree (iv);
|
||||||
xfree (outbuf);
|
xfree (outbuf);
|
||||||
@ -614,13 +551,11 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
|
|||||||
|
|
||||||
|
|
||||||
/* Protect the key encoded in canonical format in PLAINKEY. We assume
|
/* Protect the key encoded in canonical format in PLAINKEY. We assume
|
||||||
a valid S-Exp here. With USE_UCB set to -1 the default scheme is
|
* a valid S-Exp here. */
|
||||||
used (ie. either CBC or OCB), set to 0 the old CBC mode is used,
|
|
||||||
and set to 1 OCB is used. */
|
|
||||||
int
|
int
|
||||||
agent_protect (const unsigned char *plainkey, const char *passphrase,
|
agent_protect (const unsigned char *plainkey, const char *passphrase,
|
||||||
unsigned char **result, size_t *resultlen,
|
unsigned char **result, size_t *resultlen,
|
||||||
unsigned long s2k_count, int use_ocb)
|
unsigned long s2k_count)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
const char *parmlist;
|
const char *parmlist;
|
||||||
@ -637,9 +572,6 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
|
|||||||
unsigned char *p;
|
unsigned char *p;
|
||||||
int have_curve = 0;
|
int have_curve = 0;
|
||||||
|
|
||||||
if (use_ocb == -1)
|
|
||||||
use_ocb = !!opt.enable_extended_key_format;
|
|
||||||
|
|
||||||
/* Create an S-expression with the protected-at timestamp. */
|
/* Create an S-expression with the protected-at timestamp. */
|
||||||
memcpy (timestamp_exp, "(12:protected-at15:", 19);
|
memcpy (timestamp_exp, "(12:protected-at15:", 19);
|
||||||
gnupg_get_isotime (timestamp_exp+19);
|
gnupg_get_isotime (timestamp_exp+19);
|
||||||
@ -743,7 +675,7 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
|
|||||||
rc = do_encryption (hash_begin, hash_end - hash_begin + 1,
|
rc = do_encryption (hash_begin, hash_end - hash_begin + 1,
|
||||||
prot_begin, prot_end - prot_begin + 1,
|
prot_begin, prot_end - prot_begin + 1,
|
||||||
passphrase, timestamp_exp, sizeof (timestamp_exp),
|
passphrase, timestamp_exp, sizeof (timestamp_exp),
|
||||||
&protected, &protectedlen, s2k_count, use_ocb);
|
&protected, &protectedlen, s2k_count);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
@ -196,7 +196,7 @@ test_agent_protect (void)
|
|||||||
{
|
{
|
||||||
ret = agent_protect ((const unsigned char*)specs[i].key,
|
ret = agent_protect ((const unsigned char*)specs[i].key,
|
||||||
specs[i].passphrase,
|
specs[i].passphrase,
|
||||||
&specs[i].result, &specs[i].resultlen, 0, -1);
|
&specs[i].result, &specs[i].resultlen, 0);
|
||||||
if (gpg_err_code (ret) != specs[i].ret_expected)
|
if (gpg_err_code (ret) != specs[i].ret_expected)
|
||||||
{
|
{
|
||||||
printf ("agent_protect(%d) returned '%i/%s'; expected '%i/%s'\n",
|
printf ("agent_protect(%d) returned '%i/%s'; expected '%i/%s'\n",
|
||||||
|
@ -1109,6 +1109,7 @@ proc_type_verify (audit_ctx_t ctx)
|
|||||||
case GPG_ERR_CERT_REVOKED: ok = "bad"; break;
|
case GPG_ERR_CERT_REVOKED: ok = "bad"; break;
|
||||||
case GPG_ERR_NOT_ENABLED: ok = "disabled"; break;
|
case GPG_ERR_NOT_ENABLED: ok = "disabled"; break;
|
||||||
case GPG_ERR_NO_CRL_KNOWN:
|
case GPG_ERR_NO_CRL_KNOWN:
|
||||||
|
case GPG_ERR_INV_CRL_OBJ:
|
||||||
ok = _("no CRL found for certificate");
|
ok = _("no CRL found for certificate");
|
||||||
break;
|
break;
|
||||||
case GPG_ERR_CRL_TOO_OLD:
|
case GPG_ERR_CRL_TOO_OLD:
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "i18n.h"
|
#include "i18n.h"
|
||||||
|
#include "tlv.h"
|
||||||
#include "ksba-io-support.h"
|
#include "ksba-io-support.h"
|
||||||
|
|
||||||
|
|
||||||
@ -65,6 +66,12 @@ struct reader_cb_parm_s
|
|||||||
int autodetect; /* Try to detect the input encoding. */
|
int autodetect; /* Try to detect the input encoding. */
|
||||||
int assume_pem; /* Assume input encoding is PEM. */
|
int assume_pem; /* Assume input encoding is PEM. */
|
||||||
int assume_base64; /* Assume input is base64 encoded. */
|
int assume_base64; /* Assume input is base64 encoded. */
|
||||||
|
int strip_zeroes; /* Expect a SEQUENCE followed by zero padding. */
|
||||||
|
/* 1 = check state; 2 = reading; 3 = checking */
|
||||||
|
/* for zeroes. */
|
||||||
|
int use_maxread; /* If true read not more than MAXREAD. */
|
||||||
|
unsigned int maxread; /* # of bytes left to read. */
|
||||||
|
off_t nzeroes; /* Number of padding zeroes red. */
|
||||||
|
|
||||||
int identified;
|
int identified;
|
||||||
int is_pem;
|
int is_pem;
|
||||||
@ -390,6 +397,55 @@ base64_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Read up to 10 bytes to test whether the data consist of a sequence;
|
||||||
|
* if that is true, set the limited flag and record the length of the
|
||||||
|
* entire sequence in PARM. Unget everything then. Return true if we
|
||||||
|
* have a sequence with a fixed length. */
|
||||||
|
static int
|
||||||
|
starts_with_sequence (struct reader_cb_parm_s *parm)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
unsigned char peekbuf[10];
|
||||||
|
int npeeked, c;
|
||||||
|
int found = 0;
|
||||||
|
const unsigned char *p;
|
||||||
|
size_t n, objlen, hdrlen;
|
||||||
|
int class, tag, constructed, ndef;
|
||||||
|
|
||||||
|
for (npeeked=0; npeeked < sizeof peekbuf; npeeked++)
|
||||||
|
{
|
||||||
|
c = es_getc (parm->fp);
|
||||||
|
if (c == EOF)
|
||||||
|
goto leave;
|
||||||
|
peekbuf[npeeked] = c;
|
||||||
|
}
|
||||||
|
/* Enough to check for a sequence. */
|
||||||
|
|
||||||
|
p = peekbuf;
|
||||||
|
n = npeeked;
|
||||||
|
err = parse_ber_header (&p, &n, &class, &tag, &constructed,
|
||||||
|
&ndef, &objlen, &hdrlen);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_debug ("%s: error parsing data: %s\n", __func__, gpg_strerror (err));
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (class == CLASS_UNIVERSAL && constructed && tag == TAG_SEQUENCE && !ndef)
|
||||||
|
{
|
||||||
|
/* We need to add 1 due to the way we implement the limit. */
|
||||||
|
parm->maxread = objlen + hdrlen + 1;
|
||||||
|
if (!(parm->maxread < objlen + hdrlen) && parm->maxread)
|
||||||
|
parm->use_maxread = 1;
|
||||||
|
found = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
leave:
|
||||||
|
while (npeeked)
|
||||||
|
es_ungetc (peekbuf[--npeeked], parm->fp);
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
simple_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
|
simple_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
|
||||||
@ -402,9 +458,55 @@ simple_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
|
|||||||
if (!buffer)
|
if (!buffer)
|
||||||
return -1; /* not supported */
|
return -1; /* not supported */
|
||||||
|
|
||||||
|
restart:
|
||||||
|
if (parm->strip_zeroes)
|
||||||
|
{
|
||||||
|
if (parm->strip_zeroes == 1)
|
||||||
|
{
|
||||||
|
if (starts_with_sequence (parm))
|
||||||
|
parm->strip_zeroes = 2; /* Found fixed length sequence. */
|
||||||
|
else
|
||||||
|
parm->strip_zeroes = 0; /* Disable zero padding check. */
|
||||||
|
}
|
||||||
|
else if (parm->strip_zeroes == 3)
|
||||||
|
{
|
||||||
|
/* Limit reached - check that only zeroes follow. */
|
||||||
|
while (!(c = es_getc (parm->fp)))
|
||||||
|
parm->nzeroes++;
|
||||||
|
if (c == EOF)
|
||||||
|
{ /* only zeroes found. Reset zero padding engine and
|
||||||
|
* return EOF. */
|
||||||
|
parm->strip_zeroes = 0;
|
||||||
|
parm->eof_seen = 1;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* Not only zeroes. Reset engine and continue. */
|
||||||
|
parm->strip_zeroes = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (n=0; n < count; n++)
|
for (n=0; n < count; n++)
|
||||||
{
|
{
|
||||||
c = es_getc (parm->fp);
|
if (parm->use_maxread && !--parm->maxread)
|
||||||
|
{
|
||||||
|
parm->use_maxread = 0;
|
||||||
|
if (parm->strip_zeroes)
|
||||||
|
{
|
||||||
|
parm->strip_zeroes = 3;
|
||||||
|
parm->nzeroes = 0;
|
||||||
|
if (n)
|
||||||
|
goto leave; /* Return what we already got. */
|
||||||
|
goto restart; /* Immediately check for trailing zeroes. */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parm->nzeroes)
|
||||||
|
{
|
||||||
|
parm->nzeroes--;
|
||||||
|
c = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
c = es_getc (parm->fp);
|
||||||
if (c == EOF)
|
if (c == EOF)
|
||||||
{
|
{
|
||||||
parm->eof_seen = 1;
|
parm->eof_seen = 1;
|
||||||
@ -417,6 +519,7 @@ simple_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
|
|||||||
*(byte *)buffer++ = c;
|
*(byte *)buffer++ = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
leave:
|
||||||
*nread = n;
|
*nread = n;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -575,6 +678,7 @@ base64_finish_write (struct writer_cb_parm_s *parm)
|
|||||||
* GNUPG_KSBA_IO_MULTIPEM - The reader expects that the caller uses
|
* GNUPG_KSBA_IO_MULTIPEM - The reader expects that the caller uses
|
||||||
* ksba_reader_clear after EOF until no more
|
* ksba_reader_clear after EOF until no more
|
||||||
* objects were found.
|
* objects were found.
|
||||||
|
* GNUPG_KSBA_IO_STRIP - Strip zero padding from some CMS objects.
|
||||||
*
|
*
|
||||||
* Note that the PEM flag has a higher priority than the BASE64 flag
|
* Note that the PEM flag has a higher priority than the BASE64 flag
|
||||||
* which in turn has a gight priority than the AUTODETECT flag.
|
* which in turn has a gight priority than the AUTODETECT flag.
|
||||||
@ -592,6 +696,7 @@ gnupg_ksba_create_reader (gnupg_ksba_io_t *ctx,
|
|||||||
if (!*ctx)
|
if (!*ctx)
|
||||||
return out_of_core ();
|
return out_of_core ();
|
||||||
(*ctx)->u.rparm.allow_multi_pem = !!(flags & GNUPG_KSBA_IO_MULTIPEM);
|
(*ctx)->u.rparm.allow_multi_pem = !!(flags & GNUPG_KSBA_IO_MULTIPEM);
|
||||||
|
(*ctx)->u.rparm.strip_zeroes = !!(flags & GNUPG_KSBA_IO_STRIP);
|
||||||
|
|
||||||
rc = ksba_reader_new (&r);
|
rc = ksba_reader_new (&r);
|
||||||
if (rc)
|
if (rc)
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
#define GNUPG_KSBA_IO_BASE64 2 /* Plain Base64 format. */
|
#define GNUPG_KSBA_IO_BASE64 2 /* Plain Base64 format. */
|
||||||
#define GNUPG_KSBA_IO_AUTODETECT 4 /* Try to autodetect the format. */
|
#define GNUPG_KSBA_IO_AUTODETECT 4 /* Try to autodetect the format. */
|
||||||
#define GNUPG_KSBA_IO_MULTIPEM 8 /* Allow more than one PEM chunk. */
|
#define GNUPG_KSBA_IO_MULTIPEM 8 /* Allow more than one PEM chunk. */
|
||||||
|
#define GNUPG_KSBA_IO_STRIP 16 /* Strip off zero padding. */
|
||||||
|
|
||||||
|
|
||||||
/* Context object. */
|
/* Context object. */
|
||||||
|
@ -48,6 +48,8 @@ static struct {
|
|||||||
|
|
||||||
{ "Curve25519", "1.3.6.1.4.1.3029.1.5.1", 255, "cv25519", PUBKEY_ALGO_ECDH },
|
{ "Curve25519", "1.3.6.1.4.1.3029.1.5.1", 255, "cv25519", PUBKEY_ALGO_ECDH },
|
||||||
{ "Ed25519", "1.3.6.1.4.1.11591.15.1", 255, "ed25519", PUBKEY_ALGO_EDDSA },
|
{ "Ed25519", "1.3.6.1.4.1.11591.15.1", 255, "ed25519", PUBKEY_ALGO_EDDSA },
|
||||||
|
{ "Curve25519", "1.3.101.110", 255, "cv25519", PUBKEY_ALGO_ECDH },
|
||||||
|
{ "Ed25519", "1.3.101.112", 255, "ed25519", PUBKEY_ALGO_EDDSA },
|
||||||
{ "X448", "1.3.101.111", 448, "cv448", PUBKEY_ALGO_ECDH },
|
{ "X448", "1.3.101.111", 448, "cv448", PUBKEY_ALGO_ECDH },
|
||||||
{ "Ed448", "1.3.101.113", 456, "ed448", PUBKEY_ALGO_EDDSA },
|
{ "Ed448", "1.3.101.113", 456, "ed448", PUBKEY_ALGO_EDDSA },
|
||||||
|
|
||||||
@ -65,13 +67,17 @@ static struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* The OID for Curve Ed25519 in OpenPGP format. */
|
/* The OID for Curve Ed25519 in OpenPGP format. The shorter v5
|
||||||
|
* variant may only be used with v5 keys. */
|
||||||
static const char oid_ed25519[] =
|
static const char oid_ed25519[] =
|
||||||
{ 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xda, 0x47, 0x0f, 0x01 };
|
{ 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xda, 0x47, 0x0f, 0x01 };
|
||||||
|
static const char oid_ed25519_v5[] = { 0x03, 0x2b, 0x65, 0x70 };
|
||||||
|
|
||||||
/* The OID for Curve25519 in OpenPGP format. */
|
/* The OID for Curve25519 in OpenPGP format. The shorter v5
|
||||||
|
* variant may only be used with v5 keys. */
|
||||||
static const char oid_cv25519[] =
|
static const char oid_cv25519[] =
|
||||||
{ 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01 };
|
{ 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01 };
|
||||||
|
static const char oid_cv25519_v5[] = { 0x03, 0x2b, 0x65, 0x6e };
|
||||||
|
|
||||||
/* The OID for X448 in OpenPGP format. */
|
/* The OID for X448 in OpenPGP format. */
|
||||||
/*
|
/*
|
||||||
@ -321,8 +327,12 @@ openpgp_oid_to_str (gcry_mpi_t a)
|
|||||||
int
|
int
|
||||||
openpgp_oidbuf_is_ed25519 (const void *buf, size_t len)
|
openpgp_oidbuf_is_ed25519 (const void *buf, size_t len)
|
||||||
{
|
{
|
||||||
return (buf && len == DIM (oid_ed25519)
|
if (!buf)
|
||||||
&& !memcmp (buf, oid_ed25519, DIM (oid_ed25519)));
|
return 0;
|
||||||
|
return ((len == DIM (oid_ed25519)
|
||||||
|
&& !memcmp (buf, oid_ed25519, DIM (oid_ed25519)))
|
||||||
|
|| (len == DIM (oid_ed25519_v5)
|
||||||
|
&& !memcmp (buf, oid_ed25519_v5, DIM (oid_ed25519_v5))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -345,8 +355,12 @@ openpgp_oid_is_ed25519 (gcry_mpi_t a)
|
|||||||
int
|
int
|
||||||
openpgp_oidbuf_is_cv25519 (const void *buf, size_t len)
|
openpgp_oidbuf_is_cv25519 (const void *buf, size_t len)
|
||||||
{
|
{
|
||||||
return (buf && len == DIM (oid_cv25519)
|
if (!buf)
|
||||||
&& !memcmp (buf, oid_cv25519, DIM (oid_cv25519)));
|
return 0;
|
||||||
|
return ((len == DIM (oid_cv25519)
|
||||||
|
&& !memcmp (buf, oid_cv25519, DIM (oid_cv25519)))
|
||||||
|
|| (len == DIM (oid_cv25519_v5)
|
||||||
|
&& !memcmp (buf, oid_cv25519_v5, DIM (oid_cv25519_v5))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -174,6 +174,7 @@ find_next_lc (char *string)
|
|||||||
* -c The string match in this part is done case-sensitive.
|
* -c The string match in this part is done case-sensitive.
|
||||||
* -t Do not trim leading and trailing spaces from VALUE.
|
* -t Do not trim leading and trailing spaces from VALUE.
|
||||||
* Note that a space after <op> is here required.
|
* Note that a space after <op> is here required.
|
||||||
|
* -r RFU: String match uses a regular expression
|
||||||
*
|
*
|
||||||
* For example four calls to recsel_parse_expr() with these values for
|
* For example four calls to recsel_parse_expr() with these values for
|
||||||
* EXPR
|
* EXPR
|
||||||
@ -192,7 +193,7 @@ find_next_lc (char *string)
|
|||||||
*
|
*
|
||||||
* The caller must pass the address of a selector variable to this
|
* The caller must pass the address of a selector variable to this
|
||||||
* function and initialize the value of the function to NULL before
|
* function and initialize the value of the function to NULL before
|
||||||
* the first call. recset_release needs to be called to free the
|
* the first call. recsel_release needs to be called to free the
|
||||||
* selector.
|
* selector.
|
||||||
*/
|
*/
|
||||||
gpg_error_t
|
gpg_error_t
|
||||||
|
@ -536,7 +536,8 @@ get_rsa_pk_from_canon_sexp (const unsigned char *keydata, size_t keydatalen,
|
|||||||
return err;
|
return err;
|
||||||
if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
|
if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
|
||||||
return err;
|
return err;
|
||||||
if (!tok || toklen != 10 || memcmp ("public-key", tok, toklen))
|
if (!tok || !((toklen == 10 && !memcmp ("public-key", tok, toklen))
|
||||||
|
|| (toklen == 11 && !memcmp ("private-key", tok, toklen))))
|
||||||
return gpg_error (GPG_ERR_BAD_PUBKEY);
|
return gpg_error (GPG_ERR_BAD_PUBKEY);
|
||||||
if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
|
if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
|
||||||
return err;
|
return err;
|
||||||
@ -1074,6 +1075,8 @@ pubkey_algo_string (gcry_sexp_t s_pkey, enum gcry_pk_algos *r_algoid)
|
|||||||
*r_algoid = 0;
|
*r_algoid = 0;
|
||||||
|
|
||||||
l1 = gcry_sexp_find_token (s_pkey, "public-key", 0);
|
l1 = gcry_sexp_find_token (s_pkey, "public-key", 0);
|
||||||
|
if (!l1)
|
||||||
|
l1 = gcry_sexp_find_token (s_pkey, "private-key", 0);
|
||||||
if (!l1)
|
if (!l1)
|
||||||
return xtrystrdup ("E_no_key");
|
return xtrystrdup ("E_no_key");
|
||||||
{
|
{
|
||||||
|
@ -158,7 +158,8 @@ get_inv_recpsgnr_code (gpg_error_t err)
|
|||||||
case GPG_ERR_WRONG_KEY_USAGE: errstr = "3"; break;
|
case GPG_ERR_WRONG_KEY_USAGE: errstr = "3"; break;
|
||||||
case GPG_ERR_CERT_REVOKED: errstr = "4"; break;
|
case GPG_ERR_CERT_REVOKED: errstr = "4"; break;
|
||||||
case GPG_ERR_CERT_EXPIRED: errstr = "5"; break;
|
case GPG_ERR_CERT_EXPIRED: errstr = "5"; break;
|
||||||
case GPG_ERR_NO_CRL_KNOWN: errstr = "6"; break;
|
case GPG_ERR_NO_CRL_KNOWN:
|
||||||
|
case GPG_ERR_INV_CRL_OBJ: errstr = "6"; break;
|
||||||
case GPG_ERR_CRL_TOO_OLD: errstr = "7"; break;
|
case GPG_ERR_CRL_TOO_OLD: errstr = "7"; break;
|
||||||
case GPG_ERR_NO_POLICY_MATCH: errstr = "8"; break;
|
case GPG_ERR_NO_POLICY_MATCH: errstr = "8"; break;
|
||||||
|
|
||||||
|
@ -156,8 +156,7 @@ gpg_error_t
|
|||||||
parse_ber_header (unsigned char const **buffer, size_t *size,
|
parse_ber_header (unsigned char const **buffer, size_t *size,
|
||||||
int *r_class, int *r_tag,
|
int *r_class, int *r_tag,
|
||||||
int *r_constructed, int *r_ndef,
|
int *r_constructed, int *r_ndef,
|
||||||
size_t *r_length, size_t *r_nhdr)
|
size_t *r_length, size_t *r_nhdr){
|
||||||
{
|
|
||||||
int c;
|
int c;
|
||||||
unsigned long tag;
|
unsigned long tag;
|
||||||
const unsigned char *buf = *buffer;
|
const unsigned char *buf = *buffer;
|
||||||
|
@ -58,6 +58,7 @@ endif
|
|||||||
noinst_HEADERS = dirmngr.h crlcache.h crlfetch.h misc.h
|
noinst_HEADERS = dirmngr.h crlcache.h crlfetch.h misc.h
|
||||||
|
|
||||||
dirmngr_SOURCES = dirmngr.c dirmngr.h server.c crlcache.c crlfetch.c \
|
dirmngr_SOURCES = dirmngr.c dirmngr.h server.c crlcache.c crlfetch.c \
|
||||||
|
fakecrl.c \
|
||||||
certcache.c certcache.h \
|
certcache.c certcache.h \
|
||||||
domaininfo.c \
|
domaininfo.c \
|
||||||
workqueue.c \
|
workqueue.c \
|
||||||
|
@ -768,7 +768,7 @@ cert_cache_init (strlist_t hkp_cacerts)
|
|||||||
initialization_done = 1;
|
initialization_done = 1;
|
||||||
release_cache_lock ();
|
release_cache_lock ();
|
||||||
|
|
||||||
cert_cache_print_stats ();
|
cert_cache_print_stats (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Deinitialize the certificate cache. With FULL set to true even the
|
/* Deinitialize the certificate cache. With FULL set to true even the
|
||||||
@ -811,7 +811,7 @@ cert_cache_deinit (int full)
|
|||||||
|
|
||||||
/* Print some statistics to the log file. */
|
/* Print some statistics to the log file. */
|
||||||
void
|
void
|
||||||
cert_cache_print_stats (void)
|
cert_cache_print_stats (ctrl_t ctrl)
|
||||||
{
|
{
|
||||||
cert_item_t ci;
|
cert_item_t ci;
|
||||||
int idx;
|
int idx;
|
||||||
@ -848,16 +848,19 @@ cert_cache_print_stats (void)
|
|||||||
|
|
||||||
release_cache_lock ();
|
release_cache_lock ();
|
||||||
|
|
||||||
log_info (_("permanently loaded certificates: %u\n"),
|
dirmngr_status_helpf (ctrl,
|
||||||
n_permanent);
|
_("permanently loaded certificates: %u\n"),
|
||||||
log_info (_(" runtime cached certificates: %u\n"),
|
n_permanent);
|
||||||
n_nonperm);
|
dirmngr_status_helpf (ctrl,
|
||||||
log_info (_(" trusted certificates: %u (%u,%u,%u,%u)\n"),
|
_(" runtime cached certificates: %u\n"),
|
||||||
n_trusted,
|
n_nonperm);
|
||||||
n_trustclass_system,
|
dirmngr_status_helpf (ctrl,
|
||||||
n_trustclass_config,
|
_(" trusted certificates: %u (%u,%u,%u,%u)\n"),
|
||||||
n_trustclass_hkp,
|
n_trusted,
|
||||||
n_trustclass_hkpspool);
|
n_trustclass_system,
|
||||||
|
n_trustclass_config,
|
||||||
|
n_trustclass_hkp,
|
||||||
|
n_trustclass_hkpspool);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ void cert_cache_init (strlist_t hkp_cacerts);
|
|||||||
void cert_cache_deinit (int full);
|
void cert_cache_deinit (int full);
|
||||||
|
|
||||||
/* Print some statistics to the log file. */
|
/* Print some statistics to the log file. */
|
||||||
void cert_cache_print_stats (void);
|
void cert_cache_print_stats (ctrl_t ctrl);
|
||||||
|
|
||||||
/* Return true if any cert of a class in MASK is permanently loaded. */
|
/* Return true if any cert of a class in MASK is permanently loaded. */
|
||||||
int cert_cache_any_in_class (unsigned int mask);
|
int cert_cache_any_in_class (unsigned int mask);
|
||||||
|
@ -125,6 +125,13 @@
|
|||||||
# define O_BINARY 0
|
# define O_BINARY 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Reason flags for an invalid CRL. */
|
||||||
|
#define INVCRL_TOO_OLD 1
|
||||||
|
#define INVCRL_UNKNOWN_EXTN 2
|
||||||
|
#define INVCRL_GENERAL 127
|
||||||
|
|
||||||
|
|
||||||
static const char oidstr_crlNumber[] = "2.5.29.20";
|
static const char oidstr_crlNumber[] = "2.5.29.20";
|
||||||
/* static const char oidstr_issuingDistributionPoint[] = "2.5.29.28"; */
|
/* static const char oidstr_issuingDistributionPoint[] = "2.5.29.28"; */
|
||||||
static const char oidstr_authorityKeyIdentifier[] = "2.5.29.35";
|
static const char oidstr_authorityKeyIdentifier[] = "2.5.29.35";
|
||||||
@ -157,7 +164,7 @@ struct crl_cache_entry_s
|
|||||||
unsigned int cdb_use_count; /* Current use count. */
|
unsigned int cdb_use_count; /* Current use count. */
|
||||||
unsigned int cdb_lru_count; /* Used for LRU purposes. */
|
unsigned int cdb_lru_count; /* Used for LRU purposes. */
|
||||||
int dbfile_checked; /* Set to true if the dbfile_hash value has
|
int dbfile_checked; /* Set to true if the dbfile_hash value has
|
||||||
been checked one. */
|
been checked once. */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -569,8 +576,8 @@ open_dir (crl_cache_t *r_cache)
|
|||||||
if (*line == 'i')
|
if (*line == 'i')
|
||||||
{
|
{
|
||||||
entry->invalid = atoi (line+1);
|
entry->invalid = atoi (line+1);
|
||||||
if (entry->invalid < 1)
|
if (!entry->invalid)
|
||||||
entry->invalid = 1;
|
entry->invalid = INVCRL_GENERAL;
|
||||||
}
|
}
|
||||||
else if (*line == 'u')
|
else if (*line == 'u')
|
||||||
entry->user_trust_req = 1;
|
entry->user_trust_req = 1;
|
||||||
@ -1395,7 +1402,7 @@ cache_isvalid (ctrl_t ctrl, const char *issuer_hash,
|
|||||||
{
|
{
|
||||||
if (opt.verbose)
|
if (opt.verbose)
|
||||||
log_info ("no system trust and client does not trust either\n");
|
log_info ("no system trust and client does not trust either\n");
|
||||||
retval = CRL_CACHE_CANTUSE;
|
retval = CRL_CACHE_NOTTRUSTED;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1515,8 +1522,11 @@ crl_cache_cert_isvalid (ctrl_t ctrl, ksba_cert_t cert,
|
|||||||
case CRL_CACHE_DONTKNOW:
|
case CRL_CACHE_DONTKNOW:
|
||||||
err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
|
err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
|
||||||
break;
|
break;
|
||||||
|
case CRL_CACHE_NOTTRUSTED:
|
||||||
|
err = gpg_error (GPG_ERR_NOT_TRUSTED);
|
||||||
|
break;
|
||||||
case CRL_CACHE_CANTUSE:
|
case CRL_CACHE_CANTUSE:
|
||||||
err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
|
err = gpg_error (GPG_ERR_INV_CRL_OBJ);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
log_fatal ("cache_isvalid returned invalid status code %d\n", result);
|
log_fatal ("cache_isvalid returned invalid status code %d\n", result);
|
||||||
@ -2097,7 +2107,7 @@ crl_parse_insert (ctrl_t ctrl, ksba_crl_t crl,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (stopreason != KSBA_SR_READY);
|
while (stopreason != KSBA_SR_READY);
|
||||||
assert (!err);
|
log_assert (!err);
|
||||||
|
|
||||||
|
|
||||||
failure:
|
failure:
|
||||||
@ -2338,7 +2348,7 @@ crl_cache_insert (ctrl_t ctrl, const char *url, ksba_reader_t reader)
|
|||||||
nextupdate);
|
nextupdate);
|
||||||
if (!err2)
|
if (!err2)
|
||||||
err2 = gpg_error (GPG_ERR_CRL_TOO_OLD);
|
err2 = gpg_error (GPG_ERR_CRL_TOO_OLD);
|
||||||
invalidate_crl |= 1;
|
invalidate_crl |= INVCRL_TOO_OLD;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2353,7 +2363,7 @@ crl_cache_insert (ctrl_t ctrl, const char *url, ksba_reader_t reader)
|
|||||||
log_error (_("unknown critical CRL extension %s\n"), oid);
|
log_error (_("unknown critical CRL extension %s\n"), oid);
|
||||||
if (!err2)
|
if (!err2)
|
||||||
err2 = gpg_error (GPG_ERR_INV_CRL);
|
err2 = gpg_error (GPG_ERR_INV_CRL);
|
||||||
invalidate_crl |= 2;
|
invalidate_crl |= INVCRL_UNKNOWN_EXTN;
|
||||||
}
|
}
|
||||||
if (gpg_err_code (err) == GPG_ERR_EOF
|
if (gpg_err_code (err) == GPG_ERR_EOF
|
||||||
|| gpg_err_code (err) == GPG_ERR_NO_DATA )
|
|| gpg_err_code (err) == GPG_ERR_NO_DATA )
|
||||||
@ -2492,6 +2502,7 @@ list_one_crl_entry (crl_cache_t cache, crl_cache_entry_t e, estream_t fp)
|
|||||||
int rc;
|
int rc;
|
||||||
int warn = 0;
|
int warn = 0;
|
||||||
const unsigned char *s;
|
const unsigned char *s;
|
||||||
|
unsigned int invalid;
|
||||||
|
|
||||||
es_fputs ("--------------------------------------------------------\n", fp );
|
es_fputs ("--------------------------------------------------------\n", fp );
|
||||||
es_fprintf (fp, _("Begin CRL dump (retrieved via %s)\n"), e->url );
|
es_fprintf (fp, _("Begin CRL dump (retrieved via %s)\n"), e->url );
|
||||||
@ -2516,13 +2527,20 @@ list_one_crl_entry (crl_cache_t cache, crl_cache_entry_t e, estream_t fp)
|
|||||||
!e->user_trust_req? "[system]" :
|
!e->user_trust_req? "[system]" :
|
||||||
e->check_trust_anchor? e->check_trust_anchor:"[missing]");
|
e->check_trust_anchor? e->check_trust_anchor:"[missing]");
|
||||||
|
|
||||||
if ((e->invalid & 1))
|
invalid = e->invalid;
|
||||||
es_fprintf (fp, _(" ERROR: The CRL will not be used "
|
if ((invalid & INVCRL_TOO_OLD))
|
||||||
"because it was still too old after an update!\n"));
|
{
|
||||||
if ((e->invalid & 2))
|
invalid &= ~INVCRL_TOO_OLD;
|
||||||
es_fprintf (fp, _(" ERROR: The CRL will not be used "
|
es_fprintf (fp, _(" ERROR: The CRL will not be used "
|
||||||
|
"because it was still too old after an update!\n"));
|
||||||
|
}
|
||||||
|
if ((invalid & INVCRL_UNKNOWN_EXTN))
|
||||||
|
{
|
||||||
|
invalid &= ~INVCRL_UNKNOWN_EXTN;
|
||||||
|
es_fprintf (fp, _(" ERROR: The CRL will not be used "
|
||||||
"due to an unknown critical extension!\n"));
|
"due to an unknown critical extension!\n"));
|
||||||
if ((e->invalid & ~3))
|
}
|
||||||
|
if (invalid) /* INVCRL_GENERAL or some other bits are set. */
|
||||||
es_fprintf (fp, _(" ERROR: The CRL will not be used\n"));
|
es_fprintf (fp, _(" ERROR: The CRL will not be used\n"));
|
||||||
|
|
||||||
cdb = lock_db_file (cache, e);
|
cdb = lock_db_file (cache, e);
|
||||||
@ -2714,8 +2732,6 @@ crl_cache_reload_crl (ctrl_t ctrl, ksba_cert_t cert)
|
|||||||
|
|
||||||
any_dist_point = 1;
|
any_dist_point = 1;
|
||||||
|
|
||||||
if (opt.verbose)
|
|
||||||
log_info ("fetching CRL from '%s'\n", distpoint_uri);
|
|
||||||
crl_close_reader (reader);
|
crl_close_reader (reader);
|
||||||
err = crl_fetch (ctrl, distpoint_uri, &reader);
|
err = crl_fetch (ctrl, distpoint_uri, &reader);
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -27,6 +27,7 @@ typedef enum
|
|||||||
CRL_CACHE_VALID = 0,
|
CRL_CACHE_VALID = 0,
|
||||||
CRL_CACHE_INVALID,
|
CRL_CACHE_INVALID,
|
||||||
CRL_CACHE_DONTKNOW,
|
CRL_CACHE_DONTKNOW,
|
||||||
|
CRL_CACHE_NOTTRUSTED,
|
||||||
CRL_CACHE_CANTUSE
|
CRL_CACHE_CANTUSE
|
||||||
}
|
}
|
||||||
crl_cache_result_t;
|
crl_cache_result_t;
|
||||||
@ -44,6 +45,7 @@ crl_sig_result_t;
|
|||||||
struct crl_cache_entry_s;
|
struct crl_cache_entry_s;
|
||||||
typedef struct crl_cache_entry_s *crl_cache_entry_t;
|
typedef struct crl_cache_entry_s *crl_cache_entry_t;
|
||||||
|
|
||||||
|
/*-- crlcache.c --*/
|
||||||
|
|
||||||
void crl_cache_init (void);
|
void crl_cache_init (void);
|
||||||
void crl_cache_deinit (void);
|
void crl_cache_deinit (void);
|
||||||
@ -67,4 +69,11 @@ gpg_error_t crl_cache_load (ctrl_t ctrl, const char *filename);
|
|||||||
gpg_error_t crl_cache_reload_crl (ctrl_t ctrl, ksba_cert_t cert);
|
gpg_error_t crl_cache_reload_crl (ctrl_t ctrl, ksba_cert_t cert);
|
||||||
|
|
||||||
|
|
||||||
|
/*-- fakecrl.c --*/
|
||||||
|
crl_cache_result_t fakecrl_isvalid (ctrl_t ctrl,
|
||||||
|
const char *issuer_hash,
|
||||||
|
const char *cert_id);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* CRLCACHE_H */
|
#endif /* CRLCACHE_H */
|
||||||
|
@ -175,6 +175,9 @@ crl_fetch (ctrl_t ctrl, const char *url, ksba_reader_t *reader)
|
|||||||
if (!url)
|
if (!url)
|
||||||
return gpg_error (GPG_ERR_INV_ARG);
|
return gpg_error (GPG_ERR_INV_ARG);
|
||||||
|
|
||||||
|
if (opt.verbose)
|
||||||
|
log_info ("fetching CRL from '%s'\n", url);
|
||||||
|
|
||||||
err = http_parse_uri (&uri, url, 0);
|
err = http_parse_uri (&uri, url, 0);
|
||||||
http_release_parsed_uri (uri);
|
http_release_parsed_uri (uri);
|
||||||
if (!err) /* Yes, our HTTP code groks that. */
|
if (!err) /* Yes, our HTTP code groks that. */
|
||||||
|
@ -158,6 +158,7 @@ enum cmd_and_opt_values {
|
|||||||
oConnectTimeout,
|
oConnectTimeout,
|
||||||
oConnectQuickTimeout,
|
oConnectQuickTimeout,
|
||||||
oListenBacklog,
|
oListenBacklog,
|
||||||
|
oFakeCRL,
|
||||||
aTest
|
aTest
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -274,7 +275,7 @@ static gpgrt_opt_t opts[] = {
|
|||||||
" points to serverlist")),
|
" points to serverlist")),
|
||||||
ARGPARSE_s_i (oLDAPTimeout, "ldaptimeout",
|
ARGPARSE_s_i (oLDAPTimeout, "ldaptimeout",
|
||||||
N_("|N|set LDAP timeout to N seconds")),
|
N_("|N|set LDAP timeout to N seconds")),
|
||||||
|
ARGPARSE_s_s (oFakeCRL, "fake-crl", "@"),
|
||||||
|
|
||||||
ARGPARSE_header ("OCSP", N_("Configuration for OCSP")),
|
ARGPARSE_header ("OCSP", N_("Configuration for OCSP")),
|
||||||
|
|
||||||
@ -324,6 +325,7 @@ static struct debug_flags_s debug_flags [] =
|
|||||||
{ DBG_NETWORK_VALUE, "network" },
|
{ DBG_NETWORK_VALUE, "network" },
|
||||||
{ DBG_LOOKUP_VALUE , "lookup" },
|
{ DBG_LOOKUP_VALUE , "lookup" },
|
||||||
{ DBG_EXTPROG_VALUE, "extprog" },
|
{ DBG_EXTPROG_VALUE, "extprog" },
|
||||||
|
{ DBG_KEEPTMP_VALUE, "keeptmp" },
|
||||||
{ 77, NULL } /* 77 := Do not exit on "help" or "?". */
|
{ 77, NULL } /* 77 := Do not exit on "help" or "?". */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -534,7 +536,7 @@ set_debug (void)
|
|||||||
select the highest debug value and would then clutter their
|
select the highest debug value and would then clutter their
|
||||||
disk with debug files which may reveal confidential data. */
|
disk with debug files which may reveal confidential data. */
|
||||||
if (numok)
|
if (numok)
|
||||||
opt.debug &= ~(DBG_HASHING_VALUE);
|
opt.debug &= ~(DBG_HASHING_VALUE|DBG_KEEPTMP_VALUE);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -708,6 +710,8 @@ parse_rereadable_options (gpgrt_argparse_t *pargs, int reread)
|
|||||||
opt.ldaptimeout = DEFAULT_LDAP_TIMEOUT;
|
opt.ldaptimeout = DEFAULT_LDAP_TIMEOUT;
|
||||||
ldapserver_list_needs_reset = 1;
|
ldapserver_list_needs_reset = 1;
|
||||||
opt.debug_cache_expired_certs = 0;
|
opt.debug_cache_expired_certs = 0;
|
||||||
|
xfree (opt.fake_crl);
|
||||||
|
opt.fake_crl = NULL;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -870,6 +874,11 @@ parse_rereadable_options (gpgrt_argparse_t *pargs, int reread)
|
|||||||
opt.debug_cache_expired_certs = 0;
|
opt.debug_cache_expired_certs = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case oFakeCRL:
|
||||||
|
xfree (opt.fake_crl);
|
||||||
|
opt.fake_crl = *pargs->r.ret_str? xstrdup (pargs->r.ret_str) : NULL;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return 0; /* Not handled. */
|
return 0; /* Not handled. */
|
||||||
}
|
}
|
||||||
@ -2030,8 +2039,9 @@ handle_signal (int signo)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SIGUSR1:
|
case SIGUSR1:
|
||||||
cert_cache_print_stats ();
|
/* See also cmd_getinfo:"stats". */
|
||||||
domaininfo_print_stats ();
|
cert_cache_print_stats (NULL);
|
||||||
|
domaininfo_print_stats (NULL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SIGUSR2:
|
case SIGUSR2:
|
||||||
|
@ -104,6 +104,7 @@ struct
|
|||||||
|
|
||||||
int force; /* Force loading outdated CRLs. */
|
int force; /* Force loading outdated CRLs. */
|
||||||
|
|
||||||
|
char *fake_crl; /* Name of a file with faked CRL entries. */
|
||||||
|
|
||||||
unsigned int connect_timeout; /* Timeout for connect. */
|
unsigned int connect_timeout; /* Timeout for connect. */
|
||||||
unsigned int connect_quick_timeout; /* Shorter timeout for connect. */
|
unsigned int connect_quick_timeout; /* Shorter timeout for connect. */
|
||||||
@ -166,6 +167,7 @@ struct
|
|||||||
#define DBG_NETWORK_VALUE 2048 /* debug network I/O. */
|
#define DBG_NETWORK_VALUE 2048 /* debug network I/O. */
|
||||||
#define DBG_LOOKUP_VALUE 8192 /* debug lookup details */
|
#define DBG_LOOKUP_VALUE 8192 /* debug lookup details */
|
||||||
#define DBG_EXTPROG_VALUE 16384 /* debug external program calls */
|
#define DBG_EXTPROG_VALUE 16384 /* debug external program calls */
|
||||||
|
#define DBG_KEEPTMP_VALUE 32768 /* keep some temporary files */
|
||||||
|
|
||||||
#define DBG_X509 (opt.debug & DBG_X509_VALUE)
|
#define DBG_X509 (opt.debug & DBG_X509_VALUE)
|
||||||
#define DBG_CRYPTO (opt.debug & DBG_CRYPTO_VALUE)
|
#define DBG_CRYPTO (opt.debug & DBG_CRYPTO_VALUE)
|
||||||
@ -177,6 +179,7 @@ struct
|
|||||||
#define DBG_NETWORK (opt.debug & DBG_NETWORK_VALUE)
|
#define DBG_NETWORK (opt.debug & DBG_NETWORK_VALUE)
|
||||||
#define DBG_LOOKUP (opt.debug & DBG_LOOKUP_VALUE)
|
#define DBG_LOOKUP (opt.debug & DBG_LOOKUP_VALUE)
|
||||||
#define DBG_EXTPROG (opt.debug & DBG_EXTPROG_VALUE)
|
#define DBG_EXTPROG (opt.debug & DBG_EXTPROG_VALUE)
|
||||||
|
#define DBG_KEEPTMP (opt.debug & DBG_KEEPTMP_VALUE)
|
||||||
|
|
||||||
/* A simple list of certificate references. FIXME: Better use
|
/* A simple list of certificate references. FIXME: Better use
|
||||||
certlist_t also for references (Store NULL at .cert) */
|
certlist_t also for references (Store NULL at .cert) */
|
||||||
@ -264,7 +267,7 @@ gpg_error_t dirmngr_load_swdb (ctrl_t ctrl, int force);
|
|||||||
|
|
||||||
|
|
||||||
/*-- domaininfo.c --*/
|
/*-- domaininfo.c --*/
|
||||||
void domaininfo_print_stats (void);
|
void domaininfo_print_stats (ctrl_t ctrl);
|
||||||
int domaininfo_is_wkd_not_supported (const char *domain);
|
int domaininfo_is_wkd_not_supported (const char *domain);
|
||||||
void domaininfo_set_no_name (const char *domain);
|
void domaininfo_set_no_name (const char *domain);
|
||||||
void domaininfo_set_wkd_supported (const char *domain);
|
void domaininfo_set_wkd_supported (const char *domain);
|
||||||
|
@ -81,7 +81,7 @@ hash_domain (const char *domain)
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
domaininfo_print_stats (void)
|
domaininfo_print_stats (ctrl_t ctrl)
|
||||||
{
|
{
|
||||||
int bidx;
|
int bidx;
|
||||||
domaininfo_t di;
|
domaininfo_t di;
|
||||||
@ -112,11 +112,12 @@ domaininfo_print_stats (void)
|
|||||||
if (minlen == -1 || len < minlen)
|
if (minlen == -1 || len < minlen)
|
||||||
minlen = len;
|
minlen = len;
|
||||||
}
|
}
|
||||||
log_info ("domaininfo: items=%d chainlen=%d..%d nn=%d nf=%d ns=%d s=%d\n",
|
dirmngr_status_helpf
|
||||||
count,
|
(ctrl, "domaininfo: items=%d chainlen=%d..%d nn=%d nf=%d ns=%d s=%d\n",
|
||||||
minlen > 0? minlen : 0,
|
count,
|
||||||
maxlen,
|
minlen > 0? minlen : 0,
|
||||||
no_name, wkd_not_found, wkd_not_supported, wkd_supported);
|
maxlen,
|
||||||
|
no_name, wkd_not_found, wkd_not_supported, wkd_supported);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
63
dirmngr/fakecrl.c
Normal file
63
dirmngr/fakecrl.c
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/* fakecrl.c - Debug code to test revocations.
|
||||||
|
* Copyright (C) 2023 g10 Code GmbH
|
||||||
|
*
|
||||||
|
* 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 3 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, see <https://www.gnu.org/licenses/>.
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For regression testing it is useful to have a way to claim that
|
||||||
|
* certain certificates are revoked. We achieve this with the
|
||||||
|
* --fake-crl option which takes a file name as argument. The format
|
||||||
|
* of the file is: empty lines and lines starting with a hash sign are
|
||||||
|
* ignored. A line with the issuer DN in brackets starts entries for
|
||||||
|
* this issuer. All following lines up to the next line with a
|
||||||
|
* bracket list revoked certificates. For each revoked certificate
|
||||||
|
* the hexadecimal encoded serial number is listed, followed by the
|
||||||
|
* revocation date in ISO 14 byte notation, optionally followed by a
|
||||||
|
* reason keyword. Example:
|
||||||
|
*---------------------
|
||||||
|
* # Sample Fake CRL
|
||||||
|
* [CN=Bayern-Softtoken-Issuing-CA-2019,OU=IT-DLZ,O=Freistaat Bayern,C=DE]
|
||||||
|
* 7FD62B1A9EA5BBC84971183080717004 20221125T074346
|
||||||
|
* 11223344556677 20230101T000000 key_compromise
|
||||||
|
* 0000000000000042 20221206T121200 certificate_hold
|
||||||
|
*
|
||||||
|
* [CN=CA IVBB Deutsche Telekom AG 18,OU=Bund,O=PKI-1-Verwaltung,C=DE]
|
||||||
|
* 735D1B97389F 20230210T083947
|
||||||
|
*---------------------
|
||||||
|
*/
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "dirmngr.h"
|
||||||
|
#include "crlcache.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Returns 0 if the given certificate is not listed in the faked CRL
|
||||||
|
* or no fake CRL is configured. It is expected that the caller then
|
||||||
|
* consults the real CRL. */
|
||||||
|
gpg_error_t
|
||||||
|
fakecrl_isvalid (ctrl_t ctrl, const char *issuer_hash, const char *cert_id)
|
||||||
|
{
|
||||||
|
(void)ctrl;
|
||||||
|
(void)issuer_hash;
|
||||||
|
(void)cert_id;
|
||||||
|
return 0;
|
||||||
|
}
|
@ -525,7 +525,7 @@ make_one_filter (const char *pattern, char **r_result)
|
|||||||
{
|
{
|
||||||
/* We need just the BaseDN. This assumes that the Subject
|
/* We need just the BaseDN. This assumes that the Subject
|
||||||
* is correcly stored in the DT. This is however not always
|
* is correcly stored in the DT. This is however not always
|
||||||
* the case and the actual DN is different ffrom the
|
* the case and the actual DN is different from the
|
||||||
* subject. In this case we won't find anything. */
|
* subject. In this case we won't find anything. */
|
||||||
if (extfilt_need_escape (pattern)
|
if (extfilt_need_escape (pattern)
|
||||||
&& !(pattern = pattern_buffer = extfilt_escape (pattern)))
|
&& !(pattern = pattern_buffer = extfilt_escape (pattern)))
|
||||||
|
@ -1339,6 +1339,10 @@ cmd_isvalid (assuan_context_t ctx, char *line)
|
|||||||
}
|
}
|
||||||
else if (only_ocsp)
|
else if (only_ocsp)
|
||||||
err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
|
err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
|
||||||
|
else if (opt.fake_crl && (err = fakecrl_isvalid (ctrl, issuerhash, serialno)))
|
||||||
|
{
|
||||||
|
/* We already got the error code. */
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
switch (crl_cache_isvalid (ctrl,
|
switch (crl_cache_isvalid (ctrl,
|
||||||
@ -1360,8 +1364,11 @@ cmd_isvalid (assuan_context_t ctx, char *line)
|
|||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case CRL_CACHE_NOTTRUSTED:
|
||||||
|
err = gpg_error (GPG_ERR_NOT_TRUSTED);
|
||||||
|
break;
|
||||||
case CRL_CACHE_CANTUSE:
|
case CRL_CACHE_CANTUSE:
|
||||||
err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
|
err = gpg_error (GPG_ERR_INV_CRL_OBJ);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
log_fatal ("crl_cache_isvalid returned invalid code\n");
|
log_fatal ("crl_cache_isvalid returned invalid code\n");
|
||||||
@ -1374,7 +1381,7 @@ cmd_isvalid (assuan_context_t ctx, char *line)
|
|||||||
|
|
||||||
|
|
||||||
/* If the line contains a SHA-1 fingerprint as the first argument,
|
/* If the line contains a SHA-1 fingerprint as the first argument,
|
||||||
return the FPR vuffer on success. The function checks that the
|
return the FPR buffer on success. The function checks that the
|
||||||
fingerprint consists of valid characters and prints and error
|
fingerprint consists of valid characters and prints and error
|
||||||
message if it does not and returns NULL. Fingerprints are
|
message if it does not and returns NULL. Fingerprints are
|
||||||
considered optional and thus no explicit error is returned. NULL is
|
considered optional and thus no explicit error is returned. NULL is
|
||||||
@ -1469,7 +1476,7 @@ cmd_checkcrl (assuan_context_t ctx, char *line)
|
|||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert (cert);
|
log_assert (cert);
|
||||||
|
|
||||||
err = crl_cache_cert_isvalid (ctrl, cert, ctrl->force_crl_refresh);
|
err = crl_cache_cert_isvalid (ctrl, cert, ctrl->force_crl_refresh);
|
||||||
if (gpg_err_code (err) == GPG_ERR_NO_CRL_KNOWN)
|
if (gpg_err_code (err) == GPG_ERR_NO_CRL_KNOWN)
|
||||||
@ -2785,13 +2792,14 @@ static const char hlp_getinfo[] =
|
|||||||
"Multi purpose command to return certain information. \n"
|
"Multi purpose command to return certain information. \n"
|
||||||
"Supported values of WHAT are:\n"
|
"Supported values of WHAT are:\n"
|
||||||
"\n"
|
"\n"
|
||||||
"version - Return the version of the program.\n"
|
"version - Return the version of the program\n"
|
||||||
"pid - Return the process id of the server.\n"
|
"pid - Return the process id of the server\n"
|
||||||
"tor - Return OK if running in Tor mode\n"
|
"tor - Return OK if running in Tor mode\n"
|
||||||
"dnsinfo - Return info about the DNS resolver\n"
|
"dnsinfo - Return info about the DNS resolver\n"
|
||||||
"socket_name - Return the name of the socket.\n"
|
"socket_name - Return the name of the socket\n"
|
||||||
"session_id - Return the current session_id.\n"
|
"session_id - Return the current session_id\n"
|
||||||
"workqueue - Inspect the work queue\n"
|
"workqueue - Inspect the work queue\n"
|
||||||
|
"stats - Print stats\n"
|
||||||
"getenv NAME - Return value of envvar NAME\n";
|
"getenv NAME - Return value of envvar NAME\n";
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
cmd_getinfo (assuan_context_t ctx, char *line)
|
cmd_getinfo (assuan_context_t ctx, char *line)
|
||||||
@ -2860,6 +2868,12 @@ cmd_getinfo (assuan_context_t ctx, char *line)
|
|||||||
workqueue_dump_queue (ctrl);
|
workqueue_dump_queue (ctrl);
|
||||||
err = 0;
|
err = 0;
|
||||||
}
|
}
|
||||||
|
else if (!strcmp (line, "stats"))
|
||||||
|
{
|
||||||
|
cert_cache_print_stats (ctrl);
|
||||||
|
domaininfo_print_stats (ctrl);
|
||||||
|
err = 0;
|
||||||
|
}
|
||||||
else if (!strncmp (line, "getenv", 6)
|
else if (!strncmp (line, "getenv", 6)
|
||||||
&& (line[6] == ' ' || line[6] == '\t' || !line[6]))
|
&& (line[6] == ' ' || line[6] == '\t' || !line[6]))
|
||||||
{
|
{
|
||||||
@ -3218,7 +3232,8 @@ dirmngr_status_help (ctrl_t ctrl, const char *text)
|
|||||||
|
|
||||||
|
|
||||||
/* Print a help status line using a printf like format. The function
|
/* Print a help status line using a printf like format. The function
|
||||||
* splits text at LFs. */
|
* splits text at LFs. With CTRL beeing NULL, the function behaves
|
||||||
|
* like log_info. */
|
||||||
gpg_error_t
|
gpg_error_t
|
||||||
dirmngr_status_helpf (ctrl_t ctrl, const char *format, ...)
|
dirmngr_status_helpf (ctrl_t ctrl, const char *format, ...)
|
||||||
{
|
{
|
||||||
@ -3227,12 +3242,20 @@ dirmngr_status_helpf (ctrl_t ctrl, const char *format, ...)
|
|||||||
char *buf;
|
char *buf;
|
||||||
|
|
||||||
va_start (arg_ptr, format);
|
va_start (arg_ptr, format);
|
||||||
buf = es_vbsprintf (format, arg_ptr);
|
if (ctrl)
|
||||||
err = buf? 0 : gpg_error_from_syserror ();
|
{
|
||||||
|
buf = es_vbsprintf (format, arg_ptr);
|
||||||
|
err = buf? 0 : gpg_error_from_syserror ();
|
||||||
|
if (!err)
|
||||||
|
err = dirmngr_status_help (ctrl, buf);
|
||||||
|
es_free (buf);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log_logv (GPGRT_LOGLVL_INFO, format, arg_ptr);
|
||||||
|
err = 0;
|
||||||
|
}
|
||||||
va_end (arg_ptr);
|
va_end (arg_ptr);
|
||||||
if (!err)
|
|
||||||
err = dirmngr_status_help (ctrl, buf);
|
|
||||||
es_free (buf);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,6 +255,7 @@ check_revocations (ctrl_t ctrl, chain_item_t chain)
|
|||||||
int any_revoked = 0;
|
int any_revoked = 0;
|
||||||
int any_no_crl = 0;
|
int any_no_crl = 0;
|
||||||
int any_crl_too_old = 0;
|
int any_crl_too_old = 0;
|
||||||
|
int any_not_trusted = 0;
|
||||||
chain_item_t ci;
|
chain_item_t ci;
|
||||||
|
|
||||||
log_assert (ctrl->check_revocations_nest_level >= 0);
|
log_assert (ctrl->check_revocations_nest_level >= 0);
|
||||||
@ -266,7 +267,8 @@ check_revocations (ctrl_t ctrl, chain_item_t chain)
|
|||||||
return gpg_error(GPG_ERR_BAD_CERT_CHAIN);
|
return gpg_error(GPG_ERR_BAD_CERT_CHAIN);
|
||||||
}
|
}
|
||||||
ctrl->check_revocations_nest_level++;
|
ctrl->check_revocations_nest_level++;
|
||||||
|
if (opt.verbose)
|
||||||
|
log_info ("[%d] start checking CRLs\n", ctrl->check_revocations_nest_level);
|
||||||
|
|
||||||
for (ci=chain; ci; ci = ci->next)
|
for (ci=chain; ci; ci = ci->next)
|
||||||
{
|
{
|
||||||
@ -293,17 +295,19 @@ check_revocations (ctrl_t ctrl, chain_item_t chain)
|
|||||||
if (!err)
|
if (!err)
|
||||||
err = crl_cache_cert_isvalid (ctrl, ci->cert, 0);
|
err = crl_cache_cert_isvalid (ctrl, ci->cert, 0);
|
||||||
}
|
}
|
||||||
|
if (opt.verbose)
|
||||||
|
log_info ("[%d] result of checking this CRL: %s\n",
|
||||||
|
ctrl->check_revocations_nest_level, gpg_strerror (err));
|
||||||
switch (gpg_err_code (err))
|
switch (gpg_err_code (err))
|
||||||
{
|
{
|
||||||
case 0: err = 0; break;
|
case 0: err = 0; break;
|
||||||
case GPG_ERR_CERT_REVOKED: any_revoked = 1; err = 0; break;
|
case GPG_ERR_CERT_REVOKED: any_revoked = 1; err = 0; break;
|
||||||
case GPG_ERR_NO_CRL_KNOWN: any_no_crl = 1; err = 0; break;
|
case GPG_ERR_NO_CRL_KNOWN: any_no_crl = 1; err = 0; break;
|
||||||
|
case GPG_ERR_NOT_TRUSTED: any_not_trusted = 1; err = 0; break;
|
||||||
case GPG_ERR_CRL_TOO_OLD: any_crl_too_old = 1; err = 0; break;
|
case GPG_ERR_CRL_TOO_OLD: any_crl_too_old = 1; err = 0; break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctrl->check_revocations_nest_level--;
|
|
||||||
|
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
;
|
;
|
||||||
@ -311,10 +315,16 @@ check_revocations (ctrl_t ctrl, chain_item_t chain)
|
|||||||
err = gpg_error (GPG_ERR_CERT_REVOKED);
|
err = gpg_error (GPG_ERR_CERT_REVOKED);
|
||||||
else if (any_no_crl)
|
else if (any_no_crl)
|
||||||
err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
|
err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
|
||||||
|
else if (any_not_trusted)
|
||||||
|
err = gpg_error (GPG_ERR_NOT_TRUSTED);
|
||||||
else if (any_crl_too_old)
|
else if (any_crl_too_old)
|
||||||
err = gpg_error (GPG_ERR_CRL_TOO_OLD);
|
err = gpg_error (GPG_ERR_CRL_TOO_OLD);
|
||||||
else
|
else
|
||||||
err = 0;
|
err = 0;
|
||||||
|
if (opt.verbose)
|
||||||
|
log_info ("[%d] result of checking all CRLs: %s\n",
|
||||||
|
ctrl->check_revocations_nest_level, gpg_strerror (err));
|
||||||
|
ctrl->check_revocations_nest_level--;
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ workqueue_dump_queue (ctrl_t ctrl)
|
|||||||
wqitem_t item;
|
wqitem_t item;
|
||||||
unsigned int count;
|
unsigned int count;
|
||||||
|
|
||||||
/* Temporarily detach the entiere workqueue so that other threads don't
|
/* Temporarily detach the entire workqueue so that other threads don't
|
||||||
* get into our way. */
|
* get into our way. */
|
||||||
saved_workqueue = workqueue;
|
saved_workqueue = workqueue;
|
||||||
workqueue = NULL;
|
workqueue = NULL;
|
||||||
@ -74,8 +74,8 @@ workqueue_dump_queue (ctrl_t ctrl)
|
|||||||
item->func? item->func (NULL, NULL): "nop",
|
item->func? item->func (NULL, NULL): "nop",
|
||||||
item->args, strlen (item->args) > 100? "[...]":"");
|
item->args, strlen (item->args) > 100? "[...]":"");
|
||||||
|
|
||||||
/* Restore then workqueue. Actually we append the saved queue do a
|
/* Restore the workqueue. Actually we append the saved queue to
|
||||||
* possibly updated workqueue. */
|
* handle a possibly updated workqueue. */
|
||||||
if (!(item=workqueue))
|
if (!(item=workqueue))
|
||||||
workqueue = saved_workqueue;
|
workqueue = saved_workqueue;
|
||||||
else
|
else
|
||||||
|
32
doc/DETAILS
32
doc/DETAILS
@ -1183,6 +1183,17 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
|
|||||||
send to the client instead of this status line. Such an inquiry
|
send to the client instead of this status line. Such an inquiry
|
||||||
may be used to sync with Pinentry
|
may be used to sync with Pinentry
|
||||||
|
|
||||||
|
*** GPGTAR_EXTRACT <tot> <skp> <bad> <sus> <sym> <hrd> <oth>
|
||||||
|
This status line is emitted after gpgtar has extracted files.
|
||||||
|
|
||||||
|
- tot :: Total number of files extracted and stored
|
||||||
|
- skp :: Total number of files skipped during extraction
|
||||||
|
- bad :: Number of files skipped due to a bad file name
|
||||||
|
- sus :: Number of files skipped due to a suspicious file name
|
||||||
|
- sym :: Number of symlinks not restored
|
||||||
|
- hrd :: Number of hard links not restored
|
||||||
|
- oth :: Number of files not extracted due to other reasons.
|
||||||
|
|
||||||
** Obsolete status codes
|
** Obsolete status codes
|
||||||
*** SIGEXPIRED
|
*** SIGEXPIRED
|
||||||
Removed on 2011-02-04. This is deprecated in favor of KEYEXPIRED.
|
Removed on 2011-02-04. This is deprecated in favor of KEYEXPIRED.
|
||||||
@ -1706,15 +1717,21 @@ Description of some debug flags:
|
|||||||
- RFC-5915 :: ECC Private Key Structure
|
- RFC-5915 :: ECC Private Key Structure
|
||||||
- RFC-5958 :: Asymmetric Key Packages
|
- RFC-5958 :: Asymmetric Key Packages
|
||||||
- RFC-6337 :: ECC in OpenPGP
|
- RFC-6337 :: ECC in OpenPGP
|
||||||
|
- RFC-7748 :: Elliptic Curves for Security (X25519 and X448)
|
||||||
|
- RFC-8410 :: Algorithm Identifiers for Ed25519, Ed448, X25519, and X448
|
||||||
- RFC-7292 :: PKCS #12: Personal Information Exchange Syntax v1.1
|
- RFC-7292 :: PKCS #12: Personal Information Exchange Syntax v1.1
|
||||||
- RFC-8351 :: The PKCS #8 EncryptedPrivateKeyInfo Media Type
|
- RFC-8351 :: The PKCS #8 EncryptedPrivateKeyInfo Media Type
|
||||||
- RFC-8550 :: S/MIME Version 4.0 Certificate Handling
|
- RFC-8550 :: S/MIME Version 4.0 Certificate Handling
|
||||||
- RFC-8551 :: S/MIME Version 4.0 Message Specification
|
- RFC-8551 :: S/MIME Version 4.0 Message Specification
|
||||||
- RFC-2634 :: Enhanced Security Services for S/MIME
|
- RFC-2634 :: Enhanced Security Services for S/MIME
|
||||||
- RFC-5035 :: Enhanced Security Services (ESS) Update
|
- RFC-5035 :: Enhanced Security Services (ESS) Update
|
||||||
|
- RFC-7253 :: The OCB Authenticated-Encryption Algorithm
|
||||||
|
|
||||||
- draft-koch-openpgp-2015-rfc4880bis :: Updates to RFC-4880
|
- draft-koch-openpgp-2015-rfc4880bis :: Updates to RFC-4880
|
||||||
|
|
||||||
|
- T6390 :: Notes on use of X25519 in GnuPG (https://dev.gnupg.org/T6390)
|
||||||
|
|
||||||
|
|
||||||
** v3 fingerprints
|
** v3 fingerprints
|
||||||
For packet version 3 we calculate the keyids this way:
|
For packet version 3 we calculate the keyids this way:
|
||||||
- RSA :: Low 64 bits of n
|
- RSA :: Low 64 bits of n
|
||||||
@ -1724,17 +1741,10 @@ Description of some debug flags:
|
|||||||
|
|
||||||
** gnupg.org notations
|
** gnupg.org notations
|
||||||
|
|
||||||
- adsk@gnupg.org :: Additional decryption subkey. This notation
|
- rem@gnupg.org :: Used by Kleopatra to implement the tag feature.
|
||||||
gives a list of keys an implementation SHOULD
|
These tags are used to mark keys for easier
|
||||||
also encrypt to. The data consists of an array
|
searching and grouping.
|
||||||
of eight-octet numbers holding the Key ID of an
|
|
||||||
encryption subkey. This notation is only valid
|
|
||||||
on an encryption subkey (i.e. with first octet
|
|
||||||
of the key flags 0x04 or 0x08). Subkeys not on
|
|
||||||
the same keyblock MUST NOT be considered. For
|
|
||||||
interoperability this notation SHOULD NOT be
|
|
||||||
marked as criticial. Due to its nature it MUST
|
|
||||||
NOT be marked as human readable.
|
|
||||||
|
|
||||||
** Simplified revocation certificates
|
** Simplified revocation certificates
|
||||||
Revocation certificates consist only of the signature packet;
|
Revocation certificates consist only of the signature packet;
|
||||||
|
@ -615,15 +615,11 @@ remote machine.
|
|||||||
@itemx --disable-extended-key-format
|
@itemx --disable-extended-key-format
|
||||||
@opindex enable-extended-key-format
|
@opindex enable-extended-key-format
|
||||||
@opindex disable-extended-key-format
|
@opindex disable-extended-key-format
|
||||||
Since version 2.3 keys are created in the extended private key format.
|
These options are obsolete and have no effect. The extended key format
|
||||||
Changing the passphrase of a key will also convert the key to that new
|
is used for years now and has been supported since 2.1.12. Existing
|
||||||
format. This new key format is supported since GnuPG version 2.1.12
|
keys in the old format are migrated to the new format as soon as they
|
||||||
and thus there should be no need to disable it. The disable option
|
are touched.
|
||||||
allows to revert to the old behavior for new keys; be aware that keys
|
|
||||||
are never migrated back to the old format. However if the enable
|
|
||||||
option has been used the disable option won't have an effect. The
|
|
||||||
advantage of the extended private key format is that it is text based
|
|
||||||
and can carry additional meta data.
|
|
||||||
|
|
||||||
@anchor{option --enable-ssh-support}
|
@anchor{option --enable-ssh-support}
|
||||||
@item --enable-ssh-support
|
@item --enable-ssh-support
|
||||||
|
13
doc/gpg.texi
13
doc/gpg.texi
@ -1067,6 +1067,15 @@ signing.
|
|||||||
"sensitive". If a designated revoker is marked as sensitive, it will
|
"sensitive". If a designated revoker is marked as sensitive, it will
|
||||||
not be exported by default (see export-options).
|
not be exported by default (see export-options).
|
||||||
|
|
||||||
|
@item addadsk
|
||||||
|
@opindex keyedit:addadsk
|
||||||
|
Add an Additional Decryption Subkey. The user is asked to enter the
|
||||||
|
fingerprint of another encryption subkey. Note that the exact
|
||||||
|
fingerprint of another key's encryption subkey needs to be entered.
|
||||||
|
This is because commonly the primary key has no encryption
|
||||||
|
capability. Use the option @option{--with-subkey-fingerprint} with
|
||||||
|
a list command to display the subkey fingerprints.
|
||||||
|
|
||||||
@item passwd
|
@item passwd
|
||||||
@opindex keyedit:passwd
|
@opindex keyedit:passwd
|
||||||
Change the passphrase of the secret key.
|
Change the passphrase of the secret key.
|
||||||
@ -3190,6 +3199,10 @@ Write log output to file descriptor @var{n} and not to STDERR.
|
|||||||
Same as @option{--logger-fd}, except the logger data is written to
|
Same as @option{--logger-fd}, except the logger data is written to
|
||||||
file @var{file}. Use @file{socket://} to log to s socket.
|
file @var{file}. Use @file{socket://} to log to s socket.
|
||||||
|
|
||||||
|
@item --log-time
|
||||||
|
@opindex log-time
|
||||||
|
Prefix all log output with a timestamp even if no log file is used.
|
||||||
|
|
||||||
@item --attribute-fd @var{n}
|
@item --attribute-fd @var{n}
|
||||||
@opindex attribute-fd
|
@opindex attribute-fd
|
||||||
Write attribute subpackets to the file descriptor @var{n}. This is most
|
Write attribute subpackets to the file descriptor @var{n}. This is most
|
||||||
|
@ -408,6 +408,10 @@ Do not print a warning when the so called "secure memory" cannot be used.
|
|||||||
When running in server mode, append all logging output to @var{file}.
|
When running in server mode, append all logging output to @var{file}.
|
||||||
Use @file{socket://} to log to socket.
|
Use @file{socket://} to log to socket.
|
||||||
|
|
||||||
|
@item --log-time
|
||||||
|
@opindex log-time
|
||||||
|
Prefix all log output with a timestamp even if no log file is used.
|
||||||
|
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
|
|
||||||
@ -492,8 +496,10 @@ This usually means that Dirmngr is employed to search for the
|
|||||||
certificate. Note that this option makes a "web bug" like behavior
|
certificate. Note that this option makes a "web bug" like behavior
|
||||||
possible. LDAP server operators can see which keys you request, so by
|
possible. LDAP server operators can see which keys you request, so by
|
||||||
sending you a message signed by a brand new key (which you naturally
|
sending you a message signed by a brand new key (which you naturally
|
||||||
will not have on your local keybox), the operator can tell both your IP
|
will not have on your local keybox), the operator can tell both your
|
||||||
address and the time when you verified the signature.
|
IP address and the time when you verified the signature. Note that if
|
||||||
|
CRL checking is not disabled issuer certificates are retrieved in any
|
||||||
|
case using the caIssuers authorityInfoAccess method.
|
||||||
|
|
||||||
|
|
||||||
@anchor{gpgsm-option --validation-model}
|
@anchor{gpgsm-option --validation-model}
|
||||||
@ -623,6 +629,15 @@ always listed in @option{--with-colons} mode.
|
|||||||
Include info about the presence of a secret key in public key listings
|
Include info about the presence of a secret key in public key listings
|
||||||
done with @code{--with-colons}.
|
done with @code{--with-colons}.
|
||||||
|
|
||||||
|
@item --no-pretty-dn
|
||||||
|
@opindex no-pretty-dn
|
||||||
|
By default gpgsm prints distinguished names (DNs) like the Issuer or
|
||||||
|
Subject in a more readable format (e.g. using a well defined order of
|
||||||
|
the parts). However, this format can't be used as input strings.
|
||||||
|
This option reverts printing to standard RFC-2253 format and thus
|
||||||
|
avoids the need to use --dump-cert or --with-colons to get the
|
||||||
|
``real'' name.
|
||||||
|
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
@c *******************************************
|
@c *******************************************
|
||||||
|
@ -1345,19 +1345,23 @@ build_sig_subpkt (PKT_signature *sig, sigsubpkttype_t type,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Put all the required stuff from SIG into subpackets of sig.
|
* Put all the required stuff from SIG into subpackets of sig.
|
||||||
* PKSK is the signing key.
|
* PKSK is the signing key. SIGNHINTS are various flags like
|
||||||
|
* SIGNHINT_ADSK.
|
||||||
* Hmmm, should we delete those subpackets which are in a wrong area?
|
* Hmmm, should we delete those subpackets which are in a wrong area?
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
build_sig_subpkt_from_sig (PKT_signature *sig, PKT_public_key *pksk)
|
build_sig_subpkt_from_sig (PKT_signature *sig, PKT_public_key *pksk,
|
||||||
|
unsigned int signhints)
|
||||||
{
|
{
|
||||||
u32 u;
|
u32 u;
|
||||||
byte buf[1+MAX_FINGERPRINT_LEN];
|
byte buf[1+MAX_FINGERPRINT_LEN];
|
||||||
size_t fprlen;
|
size_t fprlen;
|
||||||
|
|
||||||
/* For v4 keys we need to write the ISSUER subpacket. We do not
|
/* For v4 keys we need to write the ISSUER subpacket. We do not
|
||||||
* want that for a future v5 format. */
|
* want that for a future v5 format. We also don't write it if
|
||||||
if (pksk->version < 5)
|
* only the new RENC keyflag is set (implementations with support
|
||||||
|
* for this key flag should understand the ISSUER_FPR). */
|
||||||
|
if (pksk->version < 5 && !(signhints & SIGNHINT_ADSK))
|
||||||
{
|
{
|
||||||
u = sig->keyid[0];
|
u = sig->keyid[0];
|
||||||
buf[0] = (u >> 24) & 0xff;
|
buf[0] = (u >> 24) & 0xff;
|
||||||
|
@ -1781,12 +1781,13 @@ card_generate_subkey (ctrl_t ctrl, kbnode_t pub_keyblock)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Store the key at NODE into the smartcard and modify NODE to
|
/* Store the key at NODE into the smartcard and modify NODE to carry
|
||||||
carry the serialno stuff instead of the actual secret key
|
the serialno stuff instead of the actual secret key parameters.
|
||||||
parameters. USE is the usage for that key; 0 means any
|
USE is the usage for that key; 0 means any usage. If
|
||||||
usage. */
|
PROCESSED_KEYS is not NULL it is a poiter to an strlist which will
|
||||||
|
be filled with the keygrips of successfully stored keys. */
|
||||||
int
|
int
|
||||||
card_store_subkey (KBNODE node, int use)
|
card_store_subkey (KBNODE node, int use, strlist_t *processed_keys)
|
||||||
{
|
{
|
||||||
struct agent_card_info_s info;
|
struct agent_card_info_s info;
|
||||||
int okay = 0;
|
int okay = 0;
|
||||||
@ -1875,7 +1876,11 @@ card_store_subkey (KBNODE node, int use)
|
|||||||
if (rc)
|
if (rc)
|
||||||
log_error (_("KEYTOCARD failed: %s\n"), gpg_strerror (rc));
|
log_error (_("KEYTOCARD failed: %s\n"), gpg_strerror (rc));
|
||||||
else
|
else
|
||||||
okay = 1;
|
{
|
||||||
|
okay = 1;
|
||||||
|
if (processed_keys)
|
||||||
|
add_to_strlist (processed_keys, hexgrip);
|
||||||
|
}
|
||||||
xfree (hexgrip);
|
xfree (hexgrip);
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
|
@ -211,10 +211,10 @@ copy_prefs (const prefitem_t *prefs)
|
|||||||
|
|
||||||
|
|
||||||
/* Copy the public key S to D. If D is NULL allocate a new public key
|
/* Copy the public key S to D. If D is NULL allocate a new public key
|
||||||
structure. If S has seckret key infos, only the public stuff is
|
* structure. Only the basic stuff is copied; not any ancillary
|
||||||
copied. */
|
* data. */
|
||||||
PKT_public_key *
|
PKT_public_key *
|
||||||
copy_public_key (PKT_public_key *d, PKT_public_key *s)
|
copy_public_key_basics (PKT_public_key *d, PKT_public_key *s)
|
||||||
{
|
{
|
||||||
int n, i;
|
int n, i;
|
||||||
|
|
||||||
@ -222,8 +222,8 @@ copy_public_key (PKT_public_key *d, PKT_public_key *s)
|
|||||||
d = xmalloc (sizeof *d);
|
d = xmalloc (sizeof *d);
|
||||||
memcpy (d, s, sizeof *d);
|
memcpy (d, s, sizeof *d);
|
||||||
d->seckey_info = NULL;
|
d->seckey_info = NULL;
|
||||||
d->user_id = scopy_user_id (s->user_id);
|
d->user_id = NULL;
|
||||||
d->prefs = copy_prefs (s->prefs);
|
d->prefs = NULL;
|
||||||
|
|
||||||
n = pubkey_get_npkey (s->pubkey_algo);
|
n = pubkey_get_npkey (s->pubkey_algo);
|
||||||
i = 0;
|
i = 0;
|
||||||
@ -237,6 +237,24 @@ copy_public_key (PKT_public_key *d, PKT_public_key *s)
|
|||||||
for (; i < PUBKEY_MAX_NSKEY; i++)
|
for (; i < PUBKEY_MAX_NSKEY; i++)
|
||||||
d->pkey[i] = NULL;
|
d->pkey[i] = NULL;
|
||||||
|
|
||||||
|
d->revkey = NULL;
|
||||||
|
d->serialno = NULL;
|
||||||
|
d->updateurl = NULL;
|
||||||
|
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Copy the public key S to D. If D is NULL allocate a new public key
|
||||||
|
structure. If S has seckret key infos, only the public stuff is
|
||||||
|
copied. */
|
||||||
|
PKT_public_key *
|
||||||
|
copy_public_key (PKT_public_key *d, PKT_public_key *s)
|
||||||
|
{
|
||||||
|
d = copy_public_key_basics (d, s);
|
||||||
|
d->user_id = scopy_user_id (s->user_id);
|
||||||
|
d->prefs = copy_prefs (s->prefs);
|
||||||
|
|
||||||
if (!s->revkey && s->numrevkeys)
|
if (!s->revkey && s->numrevkeys)
|
||||||
BUG();
|
BUG();
|
||||||
if (s->numrevkeys)
|
if (s->numrevkeys)
|
||||||
@ -244,8 +262,6 @@ copy_public_key (PKT_public_key *d, PKT_public_key *s)
|
|||||||
d->revkey = xmalloc(sizeof(struct revocation_key)*s->numrevkeys);
|
d->revkey = xmalloc(sizeof(struct revocation_key)*s->numrevkeys);
|
||||||
memcpy(d->revkey,s->revkey,sizeof(struct revocation_key)*s->numrevkeys);
|
memcpy(d->revkey,s->revkey,sizeof(struct revocation_key)*s->numrevkeys);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
d->revkey = NULL;
|
|
||||||
|
|
||||||
if (s->serialno)
|
if (s->serialno)
|
||||||
d->serialno = xstrdup (s->serialno);
|
d->serialno = xstrdup (s->serialno);
|
||||||
|
21
g10/getkey.c
21
g10/getkey.c
@ -1718,7 +1718,8 @@ get_best_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
|
|||||||
*
|
*
|
||||||
* This function returns 0 on success. Otherwise, an error code is
|
* This function returns 0 on success. Otherwise, an error code is
|
||||||
* returned. In particular, GPG_ERR_NO_PUBKEY is returned if the key
|
* returned. In particular, GPG_ERR_NO_PUBKEY is returned if the key
|
||||||
* is not found.
|
* is not found. If R_KEYBLOCK is not NULL and a key was found the
|
||||||
|
* keyblock is stored there; otherwiese NULL is stored there.
|
||||||
*
|
*
|
||||||
* The self-signed data has already been merged into the public key
|
* The self-signed data has already been merged into the public key
|
||||||
* using merge_selfsigs. The caller must release the content of PK by
|
* using merge_selfsigs. The caller must release the content of PK by
|
||||||
@ -1726,13 +1727,17 @@ get_best_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
|
|||||||
* free_public_key).
|
* free_public_key).
|
||||||
*/
|
*/
|
||||||
gpg_error_t
|
gpg_error_t
|
||||||
get_pubkey_fromfile (ctrl_t ctrl, PKT_public_key *pk, const char *fname)
|
get_pubkey_fromfile (ctrl_t ctrl, PKT_public_key *pk, const char *fname,
|
||||||
|
kbnode_t *r_keyblock)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
kbnode_t keyblock;
|
kbnode_t keyblock;
|
||||||
kbnode_t found_key;
|
kbnode_t found_key;
|
||||||
unsigned int infoflags;
|
unsigned int infoflags;
|
||||||
|
|
||||||
|
if (r_keyblock)
|
||||||
|
*r_keyblock = NULL;
|
||||||
|
|
||||||
err = read_key_from_file_or_buffer (ctrl, fname, NULL, 0, &keyblock);
|
err = read_key_from_file_or_buffer (ctrl, fname, NULL, 0, &keyblock);
|
||||||
if (!err)
|
if (!err)
|
||||||
{
|
{
|
||||||
@ -1747,7 +1752,10 @@ get_pubkey_fromfile (ctrl_t ctrl, PKT_public_key *pk, const char *fname)
|
|||||||
err = gpg_error (GPG_ERR_UNUSABLE_PUBKEY);
|
err = gpg_error (GPG_ERR_UNUSABLE_PUBKEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
release_kbnode (keyblock);
|
if (!err && r_keyblock)
|
||||||
|
*r_keyblock = keyblock;
|
||||||
|
else
|
||||||
|
release_kbnode (keyblock);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1809,12 +1817,12 @@ get_pubkey_from_buffer (ctrl_t ctrl, PKT_public_key *pkbuf,
|
|||||||
* returned public key may be a subkey rather than the primary key.
|
* returned public key may be a subkey rather than the primary key.
|
||||||
* Note: The self-signed data has already been merged into the public
|
* Note: The self-signed data has already been merged into the public
|
||||||
* key using merge_selfsigs. Free *PK by calling
|
* key using merge_selfsigs. Free *PK by calling
|
||||||
* release_public_key_parts (or, if PK was allocated using xfree, you
|
* release_public_key_parts (or, if PK was allocated using xmalloc, you
|
||||||
* can use free_public_key, which calls release_public_key_parts(PK)
|
* can use free_public_key, which calls release_public_key_parts(PK)
|
||||||
* and then xfree(PK)).
|
* and then xfree(PK)).
|
||||||
*
|
*
|
||||||
* If PK->REQ_USAGE is set, it is used to filter the search results.
|
* If PK->REQ_USAGE is set, it is used to filter the search results.
|
||||||
* (Thus, if PK is not NULL, PK->REQ_USAGE must be valid!!!) See the
|
* Thus, if PK is not NULL, PK->REQ_USAGE must be valid! See the
|
||||||
* documentation for finish_lookup to understand exactly how this is
|
* documentation for finish_lookup to understand exactly how this is
|
||||||
* used.
|
* used.
|
||||||
*
|
*
|
||||||
@ -2417,7 +2425,8 @@ merge_keys_and_selfsig (ctrl_t ctrl, kbnode_t keyblock)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
/* This function parses the key flags and returns PUBKEY_USAGE_ flags. */
|
||||||
|
unsigned int
|
||||||
parse_key_usage (PKT_signature * sig)
|
parse_key_usage (PKT_signature * sig)
|
||||||
{
|
{
|
||||||
int key_usage = 0;
|
int key_usage = 0;
|
||||||
|
@ -337,6 +337,7 @@ enum cmd_and_opt_values
|
|||||||
oEncryptToDefaultKey,
|
oEncryptToDefaultKey,
|
||||||
oLoggerFD,
|
oLoggerFD,
|
||||||
oLoggerFile,
|
oLoggerFile,
|
||||||
|
oLogTime,
|
||||||
oUtf8Strings,
|
oUtf8Strings,
|
||||||
oNoUtf8Strings,
|
oNoUtf8Strings,
|
||||||
oDisableCipherAlgo,
|
oDisableCipherAlgo,
|
||||||
@ -600,6 +601,7 @@ static gpgrt_opt_t opts[] = {
|
|||||||
ARGPARSE_s_s (oLoggerFile, "log-file",
|
ARGPARSE_s_s (oLoggerFile, "log-file",
|
||||||
N_("|FILE|write server mode logs to FILE")),
|
N_("|FILE|write server mode logs to FILE")),
|
||||||
ARGPARSE_s_s (oLoggerFile, "logger-file", "@"), /* 1.4 compatibility. */
|
ARGPARSE_s_s (oLoggerFile, "logger-file", "@"), /* 1.4 compatibility. */
|
||||||
|
ARGPARSE_s_n (oLogTime, "log-time", "@"),
|
||||||
ARGPARSE_s_n (oQuickRandom, "debug-quick-random", "@"),
|
ARGPARSE_s_n (oQuickRandom, "debug-quick-random", "@"),
|
||||||
|
|
||||||
|
|
||||||
@ -1041,6 +1043,7 @@ static int utf8_strings =
|
|||||||
static int maybe_setuid = 1;
|
static int maybe_setuid = 1;
|
||||||
static unsigned int opt_set_iobuf_size;
|
static unsigned int opt_set_iobuf_size;
|
||||||
static unsigned int opt_set_iobuf_size_used;
|
static unsigned int opt_set_iobuf_size_used;
|
||||||
|
static int opt_log_time;
|
||||||
|
|
||||||
/* Collection of options used only in this module. */
|
/* Collection of options used only in this module. */
|
||||||
static struct {
|
static struct {
|
||||||
@ -2864,6 +2867,9 @@ main (int argc, char **argv)
|
|||||||
case oLoggerFile:
|
case oLoggerFile:
|
||||||
logfile = pargs.r.ret_str;
|
logfile = pargs.r.ret_str;
|
||||||
break;
|
break;
|
||||||
|
case oLogTime:
|
||||||
|
opt_log_time = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
case oWithFingerprint:
|
case oWithFingerprint:
|
||||||
opt.with_fingerprint = 1;
|
opt.with_fingerprint = 1;
|
||||||
@ -3829,6 +3835,9 @@ main (int argc, char **argv)
|
|||||||
| GPGRT_LOG_WITH_TIME
|
| GPGRT_LOG_WITH_TIME
|
||||||
| GPGRT_LOG_WITH_PID ));
|
| GPGRT_LOG_WITH_PID ));
|
||||||
}
|
}
|
||||||
|
else if (opt_log_time)
|
||||||
|
log_set_prefix (NULL, (GPGRT_LOG_WITH_PREFIX|GPGRT_LOG_NO_REGISTRY
|
||||||
|
|GPGRT_LOG_WITH_TIME));
|
||||||
|
|
||||||
if (opt.verbose > 2)
|
if (opt.verbose > 2)
|
||||||
log_info ("using character set '%s'\n", get_native_charset ());
|
log_info ("using character set '%s'\n", get_native_charset ());
|
||||||
|
@ -391,7 +391,8 @@ gpg_error_t get_best_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
|
|||||||
|
|
||||||
/* Get a public key directly from file FNAME. */
|
/* Get a public key directly from file FNAME. */
|
||||||
gpg_error_t get_pubkey_fromfile (ctrl_t ctrl,
|
gpg_error_t get_pubkey_fromfile (ctrl_t ctrl,
|
||||||
PKT_public_key *pk, const char *fname);
|
PKT_public_key *pk, const char *fname,
|
||||||
|
kbnode_t *r_keyblock);
|
||||||
|
|
||||||
/* Get a public key from a buffer. */
|
/* Get a public key from a buffer. */
|
||||||
gpg_error_t get_pubkey_from_buffer (ctrl_t ctrl, PKT_public_key *pkbuf,
|
gpg_error_t get_pubkey_from_buffer (ctrl_t ctrl, PKT_public_key *pkbuf,
|
||||||
@ -468,6 +469,9 @@ void setup_main_keyids (kbnode_t keyblock);
|
|||||||
data structures. */
|
data structures. */
|
||||||
void merge_keys_and_selfsig (ctrl_t ctrl, kbnode_t keyblock);
|
void merge_keys_and_selfsig (ctrl_t ctrl, kbnode_t keyblock);
|
||||||
|
|
||||||
|
/* This function parses the key flags and returns PUBKEY_USAGE_ flags. */
|
||||||
|
unsigned int parse_key_usage (PKT_signature *sig);
|
||||||
|
|
||||||
char *get_user_id_string_native (ctrl_t ctrl, u32 *keyid);
|
char *get_user_id_string_native (ctrl_t ctrl, u32 *keyid);
|
||||||
char *get_long_user_id_string (ctrl_t ctrl, u32 *keyid);
|
char *get_long_user_id_string (ctrl_t ctrl, u32 *keyid);
|
||||||
char *get_user_id (ctrl_t ctrl, u32 *keyid, size_t *rn, int *r_nouid);
|
char *get_user_id (ctrl_t ctrl, u32 *keyid, size_t *rn, int *r_nouid);
|
||||||
|
207
g10/keyedit.c
207
g10/keyedit.c
@ -1,7 +1,7 @@
|
|||||||
/* keyedit.c - Edit properties of a key
|
/* keyedit.c - Edit properties of a key
|
||||||
* Copyright (C) 1998-2010 Free Software Foundation, Inc.
|
* Copyright (C) 1998-2010 Free Software Foundation, Inc.
|
||||||
* Copyright (C) 1998-2017 Werner Koch
|
* Copyright (C) 1998-2017 Werner Koch
|
||||||
* Copyright (C) 2015, 2016, 2022 g10 Code GmbH
|
* Copyright (C) 2015, 2016, 2022-2023 g10 Code GmbH
|
||||||
*
|
*
|
||||||
* This file is part of GnuPG.
|
* This file is part of GnuPG.
|
||||||
*
|
*
|
||||||
@ -73,6 +73,7 @@ static int menu_delsig (ctrl_t ctrl, kbnode_t pub_keyblock);
|
|||||||
static int menu_clean (ctrl_t ctrl, kbnode_t keyblock, int self_only);
|
static int menu_clean (ctrl_t ctrl, kbnode_t keyblock, int self_only);
|
||||||
static void menu_delkey (KBNODE pub_keyblock);
|
static void menu_delkey (KBNODE pub_keyblock);
|
||||||
static int menu_addrevoker (ctrl_t ctrl, kbnode_t pub_keyblock, int sensitive);
|
static int menu_addrevoker (ctrl_t ctrl, kbnode_t pub_keyblock, int sensitive);
|
||||||
|
static int menu_addadsk (ctrl_t ctrl, kbnode_t pub_keyblock);
|
||||||
static gpg_error_t menu_expire (ctrl_t ctrl, kbnode_t pub_keyblock,
|
static gpg_error_t menu_expire (ctrl_t ctrl, kbnode_t pub_keyblock,
|
||||||
int unattended, u32 newexpiration);
|
int unattended, u32 newexpiration);
|
||||||
static int menu_changeusage (ctrl_t ctrl, kbnode_t keyblock);
|
static int menu_changeusage (ctrl_t ctrl, kbnode_t keyblock);
|
||||||
@ -1243,7 +1244,7 @@ enum cmdids
|
|||||||
cmdREVSIG, cmdREVKEY, cmdREVUID, cmdDELSIG, cmdPRIMARY, cmdDEBUG,
|
cmdREVSIG, cmdREVKEY, cmdREVUID, cmdDELSIG, cmdPRIMARY, cmdDEBUG,
|
||||||
cmdSAVE, cmdADDUID, cmdADDPHOTO, cmdDELUID, cmdADDKEY, cmdDELKEY,
|
cmdSAVE, cmdADDUID, cmdADDPHOTO, cmdDELUID, cmdADDKEY, cmdDELKEY,
|
||||||
cmdADDREVOKER, cmdTOGGLE, cmdSELKEY, cmdPASSWD, cmdTRUST, cmdPREF,
|
cmdADDREVOKER, cmdTOGGLE, cmdSELKEY, cmdPASSWD, cmdTRUST, cmdPREF,
|
||||||
cmdEXPIRE, cmdCHANGEUSAGE, cmdBACKSIGN,
|
cmdEXPIRE, cmdCHANGEUSAGE, cmdBACKSIGN, cmdADDADSK,
|
||||||
#ifndef NO_TRUST_MODELS
|
#ifndef NO_TRUST_MODELS
|
||||||
cmdENABLEKEY, cmdDISABLEKEY,
|
cmdENABLEKEY, cmdDISABLEKEY,
|
||||||
#endif /*!NO_TRUST_MODELS*/
|
#endif /*!NO_TRUST_MODELS*/
|
||||||
@ -1308,6 +1309,8 @@ static struct
|
|||||||
{ "delkey", cmdDELKEY, 0, N_("delete selected subkeys")},
|
{ "delkey", cmdDELKEY, 0, N_("delete selected subkeys")},
|
||||||
{ "addrevoker", cmdADDREVOKER, KEYEDIT_NEED_SK,
|
{ "addrevoker", cmdADDREVOKER, KEYEDIT_NEED_SK,
|
||||||
N_("add a revocation key")},
|
N_("add a revocation key")},
|
||||||
|
{ "addadsk", cmdADDADSK, KEYEDIT_NEED_SK,
|
||||||
|
N_("add additional decryption subkeys")},
|
||||||
{ "delsig", cmdDELSIG, 0,
|
{ "delsig", cmdDELSIG, 0,
|
||||||
N_("delete signatures from the selected user IDs")},
|
N_("delete signatures from the selected user IDs")},
|
||||||
{ "expire", cmdEXPIRE, KEYEDIT_NEED_SK | KEYEDIT_NEED_SUBSK,
|
{ "expire", cmdEXPIRE, KEYEDIT_NEED_SK | KEYEDIT_NEED_SUBSK,
|
||||||
@ -1421,6 +1424,8 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
|
|||||||
int sec_shadowing = 0;
|
int sec_shadowing = 0;
|
||||||
int run_subkey_warnings = 0;
|
int run_subkey_warnings = 0;
|
||||||
int have_commands = !!commands;
|
int have_commands = !!commands;
|
||||||
|
strlist_t delseckey_list = NULL;
|
||||||
|
int delseckey_list_warn = 0;
|
||||||
|
|
||||||
if (opt.command_fd != -1)
|
if (opt.command_fd != -1)
|
||||||
;
|
;
|
||||||
@ -1497,6 +1502,14 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
|
|||||||
subkey_expire_warning (keyblock);
|
subkey_expire_warning (keyblock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (delseckey_list_warn)
|
||||||
|
{
|
||||||
|
delseckey_list_warn = 0;
|
||||||
|
tty_printf
|
||||||
|
(_("Note: the local copy of the secret key"
|
||||||
|
" will only be deleted with \"save\".\n"));
|
||||||
|
}
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
xfree (answer);
|
xfree (answer);
|
||||||
@ -1869,10 +1882,12 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
|
|||||||
if (node)
|
if (node)
|
||||||
{
|
{
|
||||||
PKT_public_key *xxpk = node->pkt->pkt.public_key;
|
PKT_public_key *xxpk = node->pkt->pkt.public_key;
|
||||||
if (card_store_subkey (node, xxpk ? xxpk->pubkey_usage : 0))
|
if (card_store_subkey (node, xxpk ? xxpk->pubkey_usage : 0,
|
||||||
|
&delseckey_list))
|
||||||
{
|
{
|
||||||
redisplay = 1;
|
redisplay = 1;
|
||||||
sec_shadowing = 1;
|
sec_shadowing = 1;
|
||||||
|
delseckey_list_warn = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1949,7 +1964,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
|
|||||||
pkt->pkttype = PKT_PUBLIC_KEY;
|
pkt->pkttype = PKT_PUBLIC_KEY;
|
||||||
|
|
||||||
/* Ask gpg-agent to store the secret key to card. */
|
/* Ask gpg-agent to store the secret key to card. */
|
||||||
if (card_store_subkey (node, 0))
|
if (card_store_subkey (node, 0, NULL))
|
||||||
{
|
{
|
||||||
redisplay = 1;
|
redisplay = 1;
|
||||||
sec_shadowing = 1;
|
sec_shadowing = 1;
|
||||||
@ -2000,6 +2015,15 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case cmdADDADSK:
|
||||||
|
if (menu_addadsk (ctrl, keyblock))
|
||||||
|
{
|
||||||
|
redisplay = 1;
|
||||||
|
modified = 1;
|
||||||
|
merge_keys_and_selfsig (ctrl, keyblock);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case cmdREVUID:
|
case cmdREVUID:
|
||||||
{
|
{
|
||||||
int n1;
|
int n1;
|
||||||
@ -2250,6 +2274,27 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (delseckey_list)
|
||||||
|
{
|
||||||
|
strlist_t sl;
|
||||||
|
for (err = 0, sl = delseckey_list; sl; sl = sl->next)
|
||||||
|
{
|
||||||
|
if (*sl->d)
|
||||||
|
{
|
||||||
|
err = agent_delete_key (ctrl, sl->d, NULL, 1/*force*/);
|
||||||
|
if (err)
|
||||||
|
break;
|
||||||
|
*sl->d = 0; /* Mark deleted. */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error (_("deleting copy of secret key failed: %s\n"),
|
||||||
|
gpg_strerror (err));
|
||||||
|
break; /* the "save". */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (sec_shadowing)
|
if (sec_shadowing)
|
||||||
{
|
{
|
||||||
err = agent_scd_learn (NULL, 1);
|
err = agent_scd_learn (NULL, 1);
|
||||||
@ -2279,6 +2324,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
|
|||||||
} /* End of the main command loop. */
|
} /* End of the main command loop. */
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
|
free_strlist (delseckey_list);
|
||||||
release_kbnode (keyblock);
|
release_kbnode (keyblock);
|
||||||
keydb_release (kdbhd);
|
keydb_release (kdbhd);
|
||||||
xfree (answer);
|
xfree (answer);
|
||||||
@ -4643,6 +4689,159 @@ fail:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ask for a new additional decryption subkey and add it to the key
|
||||||
|
* block. Returns true if the keybloxk was changed and false
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
menu_addadsk (ctrl_t ctrl, kbnode_t pub_keyblock)
|
||||||
|
{
|
||||||
|
PKT_public_key *pk;
|
||||||
|
PKT_public_key *sub_pk;
|
||||||
|
PKT_public_key *main_pk;
|
||||||
|
PKT_public_key *adsk_pk = NULL;
|
||||||
|
kbnode_t adsk_keyblock = NULL;
|
||||||
|
PKT_signature *sig = NULL;
|
||||||
|
char *answer = NULL;
|
||||||
|
gpg_error_t err;
|
||||||
|
KEYDB_SEARCH_DESC desc;
|
||||||
|
byte fpr[MAX_FINGERPRINT_LEN];
|
||||||
|
size_t fprlen;
|
||||||
|
kbnode_t node, node2;
|
||||||
|
kbnode_t subkeynode = NULL;
|
||||||
|
PACKET *pkt; /* (temp. use; will be put into a kbnode_t) */
|
||||||
|
|
||||||
|
log_assert (pub_keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
|
||||||
|
main_pk = pub_keyblock->pkt->pkt.public_key;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
xfree (answer);
|
||||||
|
answer = cpr_get_utf8
|
||||||
|
("keyedit.addadsk",
|
||||||
|
_("Enter the fingerprint of the additional decryption subkey: "));
|
||||||
|
if (answer[0] == '\0' || answer[0] == CONTROL_D)
|
||||||
|
{
|
||||||
|
err = gpg_error (GPG_ERR_CANCELED);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
if (classify_user_id (answer, &desc, 1)
|
||||||
|
|| desc.mode != KEYDB_SEARCH_MODE_FPR)
|
||||||
|
{
|
||||||
|
log_info (_("\"%s\" is not a fingerprint\n"), answer);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
free_public_key (adsk_pk);
|
||||||
|
adsk_pk = xcalloc (1, sizeof *adsk_pk);
|
||||||
|
adsk_pk->req_usage = PUBKEY_USAGE_ENC;
|
||||||
|
release_kbnode (adsk_keyblock);
|
||||||
|
adsk_keyblock = NULL;
|
||||||
|
err = get_pubkey_byname (ctrl, GET_PUBKEY_NO_AKL,
|
||||||
|
NULL, adsk_pk, answer, &adsk_keyblock, NULL, 1);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_info (_("key \"%s\" not found: %s\n"), answer,
|
||||||
|
gpg_strerror (err));
|
||||||
|
if (!opt.batch && gpg_err_code (err) == GPG_ERR_UNUSABLE_PUBKEY)
|
||||||
|
log_info (_("Did you specify the fingerprint of a subkey?\n"));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (node = adsk_keyblock; node; node = node->next)
|
||||||
|
{
|
||||||
|
if (node->pkt->pkttype == PKT_PUBLIC_KEY
|
||||||
|
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
|
||||||
|
{
|
||||||
|
pk = node->pkt->pkt.public_key;
|
||||||
|
fingerprint_from_pk (pk, fpr, &fprlen);
|
||||||
|
if (fprlen == desc.fprlen
|
||||||
|
&& !memcmp (fpr, desc.u.fpr, fprlen)
|
||||||
|
&& (pk->pubkey_usage & PUBKEY_USAGE_ENC))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!node)
|
||||||
|
{
|
||||||
|
err = gpg_error (GPG_ERR_WRONG_KEY_USAGE);
|
||||||
|
log_info (_("key \"%s\" not found: %s\n"), answer,
|
||||||
|
gpg_strerror (err));
|
||||||
|
if (!opt.batch)
|
||||||
|
log_info (_("Did you specify the fingerprint of a subkey?\n"));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that the selected subkey is not yet on our keyblock. */
|
||||||
|
for (node2 = pub_keyblock; node2; node2 = node2->next)
|
||||||
|
{
|
||||||
|
if (node2->pkt->pkttype == PKT_PUBLIC_KEY
|
||||||
|
|| node2->pkt->pkttype == PKT_PUBLIC_SUBKEY)
|
||||||
|
{
|
||||||
|
pk = node2->pkt->pkt.public_key;
|
||||||
|
fingerprint_from_pk (pk, fpr, &fprlen);
|
||||||
|
if (fprlen == desc.fprlen
|
||||||
|
&& !memcmp (fpr, desc.u.fpr, fprlen))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (node2)
|
||||||
|
{
|
||||||
|
log_info (_("key \"%s\" is already on this keyblock\n"), answer);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Append the subkey.
|
||||||
|
* Note that we don't use the ADSK_PK directly because this is the
|
||||||
|
* primary key and in general we use a subkey to which NODE points.
|
||||||
|
* ADSK_PK has only been used to pass the requested key usage to
|
||||||
|
* get_pubkey_byname. SUB_PK will point to the actual adsk. */
|
||||||
|
log_assert (node->pkt->pkttype == PKT_PUBLIC_KEY
|
||||||
|
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY);
|
||||||
|
sub_pk = copy_public_key_basics (NULL, node->pkt->pkt.public_key);
|
||||||
|
keyid_from_pk (main_pk, sub_pk->main_keyid); /* Fixup main keyid. */
|
||||||
|
log_assert ((sub_pk->pubkey_usage & PUBKEY_USAGE_ENC));
|
||||||
|
sub_pk->pubkey_usage = PUBKEY_USAGE_RENC; /* 'e' -> 'r' */
|
||||||
|
pkt = xcalloc (1, sizeof *pkt);
|
||||||
|
pkt->pkttype = PKT_PUBLIC_SUBKEY; /* Make sure it is a subkey. */
|
||||||
|
pkt->pkt.public_key = sub_pk;
|
||||||
|
subkeynode = new_kbnode (pkt);
|
||||||
|
|
||||||
|
/* Make the signature. */
|
||||||
|
err = make_keysig_packet (ctrl, &sig, main_pk, NULL, sub_pk, main_pk, 0x18,
|
||||||
|
sub_pk->timestamp, 0,
|
||||||
|
keygen_add_key_flags_and_expire, sub_pk, NULL);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
write_status_error ("keysig", err);
|
||||||
|
log_error ("creating key binding failed: %s\n", gpg_strerror (err));
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Append the subkey packet and the binding signature. */
|
||||||
|
add_kbnode (pub_keyblock, subkeynode);
|
||||||
|
subkeynode = NULL;
|
||||||
|
pkt = xcalloc (1, sizeof *pkt);
|
||||||
|
pkt->pkttype = PKT_SIGNATURE;
|
||||||
|
pkt->pkt.signature = sig;
|
||||||
|
add_kbnode (pub_keyblock, new_kbnode (pkt));
|
||||||
|
|
||||||
|
leave:
|
||||||
|
xfree (answer);
|
||||||
|
free_public_key (adsk_pk);
|
||||||
|
release_kbnode (adsk_keyblock);
|
||||||
|
release_kbnode (subkeynode);
|
||||||
|
if (!err)
|
||||||
|
return 1; /* The keyblock was modified. */
|
||||||
|
else
|
||||||
|
return 0; /* Not modified. */
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* With FORCE_MAINKEY cleared this function handles the interactive
|
/* With FORCE_MAINKEY cleared this function handles the interactive
|
||||||
* menu option "expire". With UNATTENDED set to 1 this function only
|
* menu option "expire". With UNATTENDED set to 1 this function only
|
||||||
* sets the expiration date of the primary key to NEWEXPIRATION and
|
* sets the expiration date of the primary key to NEWEXPIRATION and
|
||||||
|
49
g10/keygen.c
49
g10/keygen.c
@ -130,12 +130,6 @@ struct output_control_s
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct opaque_data_usage_and_pk {
|
|
||||||
unsigned int usage;
|
|
||||||
PKT_public_key *pk;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/* FIXME: These globals vars are ugly. And using MAX_PREFS even for
|
/* FIXME: These globals vars are ugly. And using MAX_PREFS even for
|
||||||
* aeads is useless, given that we don't expects more than a very few
|
* aeads is useless, given that we don't expects more than a very few
|
||||||
* algorithms. */
|
* algorithms. */
|
||||||
@ -256,22 +250,27 @@ write_uid (kbnode_t root, const char *s)
|
|||||||
static void
|
static void
|
||||||
do_add_key_flags (PKT_signature *sig, unsigned int use)
|
do_add_key_flags (PKT_signature *sig, unsigned int use)
|
||||||
{
|
{
|
||||||
byte buf[1];
|
byte buf[2] = { 0, 0 };
|
||||||
|
|
||||||
buf[0] = 0;
|
/* The spec says that all primary keys MUST be able to certify. */
|
||||||
|
if ( sig->sig_class != 0x18 )
|
||||||
|
buf[0] |= 0x01;
|
||||||
|
|
||||||
/* The spec says that all primary keys MUST be able to certify. */
|
if (use & PUBKEY_USAGE_SIG)
|
||||||
if(sig->sig_class!=0x18)
|
buf[0] |= 0x02;
|
||||||
buf[0] |= 0x01;
|
if (use & PUBKEY_USAGE_ENC)
|
||||||
|
buf[0] |= 0x04 | 0x08;
|
||||||
|
if (use & PUBKEY_USAGE_AUTH)
|
||||||
|
buf[0] |= 0x20;
|
||||||
|
if (use & PUBKEY_USAGE_GROUP)
|
||||||
|
buf[0] |= 0x80;
|
||||||
|
|
||||||
if (use & PUBKEY_USAGE_SIG)
|
if (use & PUBKEY_USAGE_RENC)
|
||||||
buf[0] |= 0x02;
|
buf[1] |= 0x04;
|
||||||
if (use & PUBKEY_USAGE_ENC)
|
if (use & PUBKEY_USAGE_TIME)
|
||||||
buf[0] |= 0x04 | 0x08;
|
buf[1] |= 0x08;
|
||||||
if (use & PUBKEY_USAGE_AUTH)
|
|
||||||
buf[0] |= 0x20;
|
|
||||||
|
|
||||||
build_sig_subpkt (sig, SIGSUBPKT_KEY_FLAGS, buf, 1);
|
build_sig_subpkt (sig, SIGSUBPKT_KEY_FLAGS, buf, buf[1]? 2:1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -318,13 +317,11 @@ keygen_add_key_flags (PKT_signature *sig, void *opaque)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
int
|
||||||
keygen_add_key_flags_and_expire (PKT_signature *sig, void *opaque)
|
keygen_add_key_flags_and_expire (PKT_signature *sig, void *opaque)
|
||||||
{
|
{
|
||||||
struct opaque_data_usage_and_pk *oduap = opaque;
|
keygen_add_key_flags (sig, opaque);
|
||||||
|
return keygen_add_key_expire (sig, opaque);
|
||||||
do_add_key_flags (sig, oduap->usage);
|
|
||||||
return keygen_add_key_expire (sig, oduap->pk);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1215,7 +1212,6 @@ write_keybinding (ctrl_t ctrl, kbnode_t root,
|
|||||||
PKT_signature *sig;
|
PKT_signature *sig;
|
||||||
KBNODE node;
|
KBNODE node;
|
||||||
PKT_public_key *pri_pk, *sub_pk;
|
PKT_public_key *pri_pk, *sub_pk;
|
||||||
struct opaque_data_usage_and_pk oduap;
|
|
||||||
|
|
||||||
if (opt.verbose)
|
if (opt.verbose)
|
||||||
log_info(_("writing key binding signature\n"));
|
log_info(_("writing key binding signature\n"));
|
||||||
@ -1241,11 +1237,10 @@ write_keybinding (ctrl_t ctrl, kbnode_t root,
|
|||||||
BUG();
|
BUG();
|
||||||
|
|
||||||
/* Make the signature. */
|
/* Make the signature. */
|
||||||
oduap.usage = use;
|
sub_pk->pubkey_usage = use;
|
||||||
oduap.pk = sub_pk;
|
|
||||||
err = make_keysig_packet (ctrl, &sig, pri_pk, NULL, sub_pk, pri_psk, 0x18,
|
err = make_keysig_packet (ctrl, &sig, pri_pk, NULL, sub_pk, pri_psk, 0x18,
|
||||||
timestamp, 0,
|
timestamp, 0,
|
||||||
keygen_add_key_flags_and_expire, &oduap,
|
keygen_add_key_flags_and_expire, sub_pk,
|
||||||
cache_nonce);
|
cache_nonce);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
|
@ -315,6 +315,7 @@ int keygen_set_std_prefs (const char *string,int personal);
|
|||||||
PKT_user_id *keygen_get_std_prefs (void);
|
PKT_user_id *keygen_get_std_prefs (void);
|
||||||
int keygen_add_key_expire( PKT_signature *sig, void *opaque );
|
int keygen_add_key_expire( PKT_signature *sig, void *opaque );
|
||||||
int keygen_add_key_flags (PKT_signature *sig, void *opaque);
|
int keygen_add_key_flags (PKT_signature *sig, void *opaque);
|
||||||
|
int keygen_add_key_flags_and_expire (PKT_signature *sig, void *opaque);
|
||||||
int keygen_add_std_prefs( PKT_signature *sig, void *opaque );
|
int keygen_add_std_prefs( PKT_signature *sig, void *opaque );
|
||||||
int keygen_upd_std_prefs( PKT_signature *sig, void *opaque );
|
int keygen_upd_std_prefs( PKT_signature *sig, void *opaque );
|
||||||
int keygen_add_keyserver_url(PKT_signature *sig, void *opaque);
|
int keygen_add_keyserver_url(PKT_signature *sig, void *opaque);
|
||||||
@ -515,7 +516,7 @@ void change_pin (int no, int allow_admin);
|
|||||||
void card_status (ctrl_t ctrl, estream_t fp, const char *serialno);
|
void card_status (ctrl_t ctrl, estream_t fp, const char *serialno);
|
||||||
void card_edit (ctrl_t ctrl, strlist_t commands);
|
void card_edit (ctrl_t ctrl, strlist_t commands);
|
||||||
gpg_error_t card_generate_subkey (ctrl_t ctrl, kbnode_t pub_keyblock);
|
gpg_error_t card_generate_subkey (ctrl_t ctrl, kbnode_t pub_keyblock);
|
||||||
int card_store_subkey (KBNODE node, int use);
|
int card_store_subkey (KBNODE node, int use, strlist_t *processed_keys);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*-- migrate.c --*/
|
/*-- migrate.c --*/
|
||||||
|
@ -777,21 +777,21 @@ openpgp_pk_algo_usage ( int algo )
|
|||||||
switch ( algo ) {
|
switch ( algo ) {
|
||||||
case PUBKEY_ALGO_RSA:
|
case PUBKEY_ALGO_RSA:
|
||||||
use = (PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG
|
use = (PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG
|
||||||
| PUBKEY_USAGE_ENC | PUBKEY_USAGE_AUTH);
|
| PUBKEY_USAGE_ENC | PUBKEY_USAGE_RENC | PUBKEY_USAGE_AUTH);
|
||||||
break;
|
break;
|
||||||
case PUBKEY_ALGO_RSA_E:
|
case PUBKEY_ALGO_RSA_E:
|
||||||
case PUBKEY_ALGO_ECDH:
|
case PUBKEY_ALGO_ECDH:
|
||||||
use = PUBKEY_USAGE_ENC;
|
use = PUBKEY_USAGE_ENC | PUBKEY_USAGE_RENC;
|
||||||
break;
|
break;
|
||||||
case PUBKEY_ALGO_RSA_S:
|
case PUBKEY_ALGO_RSA_S:
|
||||||
use = PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG;
|
use = PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG;
|
||||||
break;
|
break;
|
||||||
case PUBKEY_ALGO_ELGAMAL:
|
case PUBKEY_ALGO_ELGAMAL:
|
||||||
if (RFC2440)
|
if (RFC2440)
|
||||||
use = PUBKEY_USAGE_ENC;
|
use = PUBKEY_USAGE_ENC | PUBKEY_USAGE_RENC;
|
||||||
break;
|
break;
|
||||||
case PUBKEY_ALGO_ELGAMAL_E:
|
case PUBKEY_ALGO_ELGAMAL_E:
|
||||||
use = PUBKEY_USAGE_ENC;
|
use = PUBKEY_USAGE_ENC | PUBKEY_USAGE_RENC;
|
||||||
break;
|
break;
|
||||||
case PUBKEY_ALGO_DSA:
|
case PUBKEY_ALGO_DSA:
|
||||||
use = PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG | PUBKEY_USAGE_AUTH;
|
use = PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG | PUBKEY_USAGE_AUTH;
|
||||||
|
18
g10/packet.h
18
g10/packet.h
@ -56,9 +56,15 @@
|
|||||||
| GCRY_PK_USAGE_AUTH | GCRY_PK_USAGE_UNKN) >= 256
|
| GCRY_PK_USAGE_AUTH | GCRY_PK_USAGE_UNKN) >= 256
|
||||||
# error Please choose another value for PUBKEY_USAGE_NONE
|
# error Please choose another value for PUBKEY_USAGE_NONE
|
||||||
#endif
|
#endif
|
||||||
#define PUBKEY_USAGE_RENC 512 /* Restricted encryption. */
|
|
||||||
#define PUBKEY_USAGE_TIME 1024 /* Timestamp use. */
|
|
||||||
#define PUBKEY_USAGE_GROUP 512 /* Group flag. */
|
#define PUBKEY_USAGE_GROUP 512 /* Group flag. */
|
||||||
|
#define PUBKEY_USAGE_RENC 1024 /* Restricted encryption. */
|
||||||
|
#define PUBKEY_USAGE_TIME 2048 /* Timestamp use. */
|
||||||
|
|
||||||
|
/* Bitflags to convey hints on what kind of signature is created. */
|
||||||
|
#define SIGNHINT_KEYSIG 1
|
||||||
|
#define SIGNHINT_SELFSIG 2
|
||||||
|
#define SIGNHINT_ADSK 4
|
||||||
|
|
||||||
|
|
||||||
/* Helper macros. */
|
/* Helper macros. */
|
||||||
#define is_RSA(a) ((a)==PUBKEY_ALGO_RSA || (a)==PUBKEY_ALGO_RSA_E \
|
#define is_RSA(a) ((a)==PUBKEY_ALGO_RSA || (a)==PUBKEY_ALGO_RSA_E \
|
||||||
@ -287,7 +293,7 @@ typedef struct
|
|||||||
/* The length of ATTRIB_DATA. */
|
/* The length of ATTRIB_DATA. */
|
||||||
unsigned long attrib_len;
|
unsigned long attrib_len;
|
||||||
byte *namehash;
|
byte *namehash;
|
||||||
int help_key_usage;
|
u16 help_key_usage;
|
||||||
u32 help_key_expire;
|
u32 help_key_expire;
|
||||||
int help_full_count;
|
int help_full_count;
|
||||||
int help_marginal_count;
|
int help_marginal_count;
|
||||||
@ -388,7 +394,7 @@ typedef struct
|
|||||||
byte selfsigversion; /* highest version of all of the self-sigs */
|
byte selfsigversion; /* highest version of all of the self-sigs */
|
||||||
/* The public key algorithm. (Serialized.) */
|
/* The public key algorithm. (Serialized.) */
|
||||||
byte pubkey_algo;
|
byte pubkey_algo;
|
||||||
byte pubkey_usage; /* for now only used to pass it to getkey() */
|
u16 pubkey_usage; /* carries the usage info. */
|
||||||
byte req_usage; /* hack to pass a request to getkey() */
|
byte req_usage; /* hack to pass a request to getkey() */
|
||||||
byte fprlen; /* 0 or length of FPR. */
|
byte fprlen; /* 0 or length of FPR. */
|
||||||
u32 has_expired; /* set to the expiration date if expired */
|
u32 has_expired; /* set to the expiration date if expired */
|
||||||
@ -861,7 +867,8 @@ gpg_error_t gpg_mpi_write_nohdr (iobuf_t out, gcry_mpi_t a);
|
|||||||
u32 calc_packet_length( PACKET *pkt );
|
u32 calc_packet_length( PACKET *pkt );
|
||||||
void build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type,
|
void build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type,
|
||||||
const byte *buffer, size_t buflen );
|
const byte *buffer, size_t buflen );
|
||||||
void build_sig_subpkt_from_sig (PKT_signature *sig, PKT_public_key *pksk);
|
void build_sig_subpkt_from_sig (PKT_signature *sig, PKT_public_key *pksk,
|
||||||
|
unsigned int signhints);
|
||||||
int delete_sig_subpkt(subpktarea_t *buffer, sigsubpkttype_t type );
|
int delete_sig_subpkt(subpktarea_t *buffer, sigsubpkttype_t type );
|
||||||
void build_attribute_subpkt(PKT_user_id *uid,byte type,
|
void build_attribute_subpkt(PKT_user_id *uid,byte type,
|
||||||
const void *buf,u32 buflen,
|
const void *buf,u32 buflen,
|
||||||
@ -883,6 +890,7 @@ void free_user_id( PKT_user_id *uid );
|
|||||||
void free_comment( PKT_comment *rem );
|
void free_comment( PKT_comment *rem );
|
||||||
void free_packet (PACKET *pkt, parse_packet_ctx_t parsectx);
|
void free_packet (PACKET *pkt, parse_packet_ctx_t parsectx);
|
||||||
prefitem_t *copy_prefs (const prefitem_t *prefs);
|
prefitem_t *copy_prefs (const prefitem_t *prefs);
|
||||||
|
PKT_public_key *copy_public_key_basics (PKT_public_key *d, PKT_public_key *s);
|
||||||
PKT_public_key *copy_public_key( PKT_public_key *d, PKT_public_key *s );
|
PKT_public_key *copy_public_key( PKT_public_key *d, PKT_public_key *s );
|
||||||
PKT_signature *copy_signature( PKT_signature *d, PKT_signature *s );
|
PKT_signature *copy_signature( PKT_signature *d, PKT_signature *s );
|
||||||
PKT_user_id *scopy_user_id (PKT_user_id *sd );
|
PKT_user_id *scopy_user_id (PKT_user_id *sd );
|
||||||
|
@ -845,7 +845,8 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
|
|||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
PKT_public_key *pk;
|
PKT_public_key *pk;
|
||||||
KBNODE keyblock = NULL;
|
kbnode_t keyblock = NULL;
|
||||||
|
kbnode_t node;
|
||||||
|
|
||||||
if (!name || !*name)
|
if (!name || !*name)
|
||||||
return gpg_error (GPG_ERR_INV_USER_ID);
|
return gpg_error (GPG_ERR_INV_USER_ID);
|
||||||
@ -856,7 +857,7 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
|
|||||||
pk->req_usage = use;
|
pk->req_usage = use;
|
||||||
|
|
||||||
if (from_file)
|
if (from_file)
|
||||||
rc = get_pubkey_fromfile (ctrl, pk, name);
|
rc = get_pubkey_fromfile (ctrl, pk, name, &keyblock);
|
||||||
else
|
else
|
||||||
rc = get_best_pubkey_byname (ctrl, GET_PUBKEY_NORMAL,
|
rc = get_best_pubkey_byname (ctrl, GET_PUBKEY_NORMAL,
|
||||||
NULL, pk, name, &keyblock, 0);
|
NULL, pk, name, &keyblock, 0);
|
||||||
@ -895,10 +896,10 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
|
|||||||
int trustlevel;
|
int trustlevel;
|
||||||
|
|
||||||
trustlevel = get_validity (ctrl, keyblock, pk, pk->user_id, NULL, 1);
|
trustlevel = get_validity (ctrl, keyblock, pk, pk->user_id, NULL, 1);
|
||||||
release_kbnode (keyblock);
|
|
||||||
if ( (trustlevel & TRUST_FLAG_DISABLED) )
|
if ( (trustlevel & TRUST_FLAG_DISABLED) )
|
||||||
{
|
{
|
||||||
/* Key has been disabled. */
|
/* Key has been disabled. */
|
||||||
|
release_kbnode (keyblock);
|
||||||
send_status_inv_recp (13, name);
|
send_status_inv_recp (13, name);
|
||||||
log_info (_("%s: skipped: public key is disabled\n"), name);
|
log_info (_("%s: skipped: public key is disabled\n"), name);
|
||||||
free_public_key (pk);
|
free_public_key (pk);
|
||||||
@ -908,6 +909,7 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
|
|||||||
if ( !do_we_trust_pre (ctrl, pk, trustlevel) )
|
if ( !do_we_trust_pre (ctrl, pk, trustlevel) )
|
||||||
{
|
{
|
||||||
/* We don't trust this key. */
|
/* We don't trust this key. */
|
||||||
|
release_kbnode (keyblock);
|
||||||
send_status_inv_recp (10, name);
|
send_status_inv_recp (10, name);
|
||||||
free_public_key (pk);
|
free_public_key (pk);
|
||||||
return GPG_ERR_UNUSABLE_PUBKEY;
|
return GPG_ERR_UNUSABLE_PUBKEY;
|
||||||
@ -926,19 +928,33 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
|
|||||||
{
|
{
|
||||||
pk_list_t r;
|
pk_list_t r;
|
||||||
|
|
||||||
r = xtrymalloc (sizeof *r);
|
r = xmalloc (sizeof *r);
|
||||||
if (!r)
|
|
||||||
{
|
|
||||||
rc = gpg_error_from_syserror ();
|
|
||||||
free_public_key (pk);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
r->pk = pk;
|
r->pk = pk;
|
||||||
r->next = *pk_list_addr;
|
r->next = *pk_list_addr;
|
||||||
r->flags = mark_hidden? 1:0;
|
r->flags = mark_hidden? 1:0;
|
||||||
*pk_list_addr = r;
|
*pk_list_addr = r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (node = keyblock; node; node = node->next)
|
||||||
|
if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
||||||
|
&& ((pk=node->pkt->pkt.public_key)->pubkey_usage & PUBKEY_USAGE_RENC)
|
||||||
|
&& pk->flags.valid
|
||||||
|
&& !pk->flags.revoked
|
||||||
|
&& !pk->flags.disabled
|
||||||
|
&& !pk->has_expired
|
||||||
|
&& key_present_in_pk_list (*pk_list_addr, pk))
|
||||||
|
{
|
||||||
|
pk_list_t r;
|
||||||
|
|
||||||
|
r = xmalloc (sizeof *r);
|
||||||
|
r->pk = copy_public_key (NULL, pk);
|
||||||
|
r->next = *pk_list_addr;
|
||||||
|
r->flags = mark_hidden? 1:0; /* FIXME: Use PK_LIST_HIDDEN ? */
|
||||||
|
*pk_list_addr = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
release_kbnode (keyblock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,7 +363,8 @@ check_signature_metadata_validity (PKT_public_key *pk, PKT_signature *sig,
|
|||||||
if (r_revoked)
|
if (r_revoked)
|
||||||
*r_revoked = 0;
|
*r_revoked = 0;
|
||||||
|
|
||||||
if (pk->timestamp > sig->timestamp )
|
if (pk->timestamp > sig->timestamp
|
||||||
|
&& !(parse_key_usage (sig) & PUBKEY_USAGE_RENC))
|
||||||
{
|
{
|
||||||
ulong d = pk->timestamp - sig->timestamp;
|
ulong d = pk->timestamp - sig->timestamp;
|
||||||
if ( d < 86400 )
|
if ( d < 86400 )
|
||||||
|
30
g10/sign.c
30
g10/sign.c
@ -50,11 +50,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* Bitflags to convey hints on what kind of signayire is created. */
|
|
||||||
#define SIGNHINT_KEYSIG 1
|
|
||||||
#define SIGNHINT_SELFSIG 2
|
|
||||||
|
|
||||||
|
|
||||||
/* Hack */
|
/* Hack */
|
||||||
static int recipient_digest_algo;
|
static int recipient_digest_algo;
|
||||||
|
|
||||||
@ -416,7 +411,10 @@ do_sign (ctrl_t ctrl, PKT_public_key *pksk, PKT_signature *sig,
|
|||||||
byte *dp;
|
byte *dp;
|
||||||
char *hexgrip;
|
char *hexgrip;
|
||||||
|
|
||||||
if (pksk->timestamp > sig->timestamp )
|
/* An ADSK key commonly has a creation date older than the primary
|
||||||
|
* key. For example because the ADSK is used as an archive key for
|
||||||
|
* a group of users. */
|
||||||
|
if (pksk->timestamp > sig->timestamp && !(signhints & SIGNHINT_ADSK))
|
||||||
{
|
{
|
||||||
ulong d = pksk->timestamp - sig->timestamp;
|
ulong d = pksk->timestamp - sig->timestamp;
|
||||||
log_info (ngettext("key %s was created %lu second"
|
log_info (ngettext("key %s was created %lu second"
|
||||||
@ -964,7 +962,7 @@ write_signature_packets (ctrl_t ctrl,
|
|||||||
if (gcry_md_copy (&md, hash))
|
if (gcry_md_copy (&md, hash))
|
||||||
BUG ();
|
BUG ();
|
||||||
|
|
||||||
build_sig_subpkt_from_sig (sig, pk);
|
build_sig_subpkt_from_sig (sig, pk, 0);
|
||||||
mk_notation_policy_etc (ctrl, sig, NULL, pk);
|
mk_notation_policy_etc (ctrl, sig, NULL, pk);
|
||||||
if (opt.flags.include_key_block && IS_SIG (sig))
|
if (opt.flags.include_key_block && IS_SIG (sig))
|
||||||
err = mk_sig_subpkt_key_block (ctrl, sig, pk);
|
err = mk_sig_subpkt_key_block (ctrl, sig, pk);
|
||||||
@ -1758,14 +1756,14 @@ sign_symencrypt_file (ctrl_t ctrl, const char *fname, strlist_t locusr)
|
|||||||
*
|
*
|
||||||
* SIGCLASS is the type of signature to create.
|
* SIGCLASS is the type of signature to create.
|
||||||
*
|
*
|
||||||
* DIGEST_ALGO is the digest algorithm. If it is 0 the function
|
|
||||||
* selects an appropriate one.
|
|
||||||
*
|
|
||||||
* TIMESTAMP is the timestamp to use for the signature. 0 means "now"
|
* TIMESTAMP is the timestamp to use for the signature. 0 means "now"
|
||||||
*
|
*
|
||||||
* DURATION is the amount of time (in seconds) until the signature
|
* DURATION is the amount of time (in seconds) until the signature
|
||||||
* expires.
|
* expires.
|
||||||
*
|
*
|
||||||
|
* If CACHED_NONCE is not NULL the agent may use it to avoid
|
||||||
|
* additional pinnetry popups for the same keyblock.
|
||||||
|
*
|
||||||
* This function creates the following subpackets: issuer, created,
|
* This function creates the following subpackets: issuer, created,
|
||||||
* and expire (if duration is not 0). Additional subpackets can be
|
* and expire (if duration is not 0). Additional subpackets can be
|
||||||
* added using MKSUBPKT, which is called after these subpackets are
|
* added using MKSUBPKT, which is called after these subpackets are
|
||||||
@ -1833,6 +1831,8 @@ make_keysig_packet (ctrl_t ctrl,
|
|||||||
{
|
{
|
||||||
/* Hash the subkey binding/backsig/revocation. */
|
/* Hash the subkey binding/backsig/revocation. */
|
||||||
hash_public_key (md, subpk);
|
hash_public_key (md, subpk);
|
||||||
|
if ((subpk->pubkey_usage & PUBKEY_USAGE_RENC))
|
||||||
|
signhints |= SIGNHINT_ADSK;
|
||||||
}
|
}
|
||||||
else if (sigclass != 0x1F && sigclass != 0x20)
|
else if (sigclass != 0x1F && sigclass != 0x20)
|
||||||
{
|
{
|
||||||
@ -1852,7 +1852,7 @@ make_keysig_packet (ctrl_t ctrl,
|
|||||||
sig->expiredate = sig->timestamp + duration;
|
sig->expiredate = sig->timestamp + duration;
|
||||||
sig->sig_class = sigclass;
|
sig->sig_class = sigclass;
|
||||||
|
|
||||||
build_sig_subpkt_from_sig (sig, pksk);
|
build_sig_subpkt_from_sig (sig, pksk, signhints);
|
||||||
mk_notation_policy_etc (ctrl, sig, pk, pksk);
|
mk_notation_policy_etc (ctrl, sig, pk, pksk);
|
||||||
|
|
||||||
/* Crucial that the call to mksubpkt comes LAST before the calls
|
/* Crucial that the call to mksubpkt comes LAST before the calls
|
||||||
@ -1976,6 +1976,12 @@ update_keysig_packet (ctrl_t ctrl,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Detect an ADSK key binding signature. */
|
||||||
|
if ((sig->sig_class == 0x18
|
||||||
|
|| sig->sig_class == 0x19 || sig->sig_class == 0x28)
|
||||||
|
&& (pk->pubkey_usage & PUBKEY_USAGE_RENC))
|
||||||
|
signhints |= SIGNHINT_ADSK;
|
||||||
|
|
||||||
/* Note that already expired sigs will remain expired (with a
|
/* Note that already expired sigs will remain expired (with a
|
||||||
* duration of 1) since build-packet.c:build_sig_subpkt_from_sig
|
* duration of 1) since build-packet.c:build_sig_subpkt_from_sig
|
||||||
* detects this case. */
|
* detects this case. */
|
||||||
@ -1984,7 +1990,7 @@ update_keysig_packet (ctrl_t ctrl,
|
|||||||
* automagically lower any sig expiration dates to correctly
|
* automagically lower any sig expiration dates to correctly
|
||||||
* correspond to the differences in the timestamps (i.e. the
|
* correspond to the differences in the timestamps (i.e. the
|
||||||
* duration will shrink). */
|
* duration will shrink). */
|
||||||
build_sig_subpkt_from_sig (sig, pksk);
|
build_sig_subpkt_from_sig (sig, pksk, signhints);
|
||||||
|
|
||||||
if (mksubpkt)
|
if (mksubpkt)
|
||||||
rc = (*mksubpkt)(sig, opaque);
|
rc = (*mksubpkt)(sig, opaque);
|
||||||
|
@ -207,6 +207,7 @@ be_is_x509_blob (const unsigned char *blob, size_t bloblen)
|
|||||||
* SEQUENCE SEQUENCE [0] INTEGER INTEGER
|
* SEQUENCE SEQUENCE [0] INTEGER INTEGER
|
||||||
* (tbs) (version) (s/n)
|
* (tbs) (version) (s/n)
|
||||||
*
|
*
|
||||||
|
* Note that v0 certificates don't have an explict version number.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
p = blob;
|
p = blob;
|
||||||
@ -226,7 +227,11 @@ be_is_x509_blob (const unsigned char *blob, size_t bloblen)
|
|||||||
if (parse_ber_header (&p, &n, &class, &tag, &cons, &ndef, &objlen, &hdrlen))
|
if (parse_ber_header (&p, &n, &class, &tag, &cons, &ndef, &objlen, &hdrlen))
|
||||||
return 0; /* Not a proper BER object. */
|
return 0; /* Not a proper BER object. */
|
||||||
if (!(class == CLASS_CONTEXT && tag == 0 && cons))
|
if (!(class == CLASS_CONTEXT && tag == 0 && cons))
|
||||||
return 0; /* No context tag. */
|
{
|
||||||
|
if (class == CLASS_UNIVERSAL && tag == TAG_INTEGER && !cons)
|
||||||
|
return 1; /* Might be a X.509 v0 cert with implict version. */
|
||||||
|
return 0; /* No context tag. */
|
||||||
|
}
|
||||||
|
|
||||||
if (parse_ber_header (&p, &n, &class, &tag, &cons, &ndef, &objlen, &hdrlen))
|
if (parse_ber_header (&p, &n, &class, &tag, &cons, &ndef, &objlen, &hdrlen))
|
||||||
return 0; /* Not a proper BER object. */
|
return 0; /* Not a proper BER object. */
|
||||||
|
@ -1863,7 +1863,7 @@ read_public_key (app_t app, ctrl_t ctrl, u32 created_at, int keyno,
|
|||||||
|
|
||||||
len = gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, NULL, 0);
|
len = gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, NULL, 0);
|
||||||
keybuf = xtrymalloc (len);
|
keybuf = xtrymalloc (len);
|
||||||
if (!data)
|
if (!keybuf)
|
||||||
{
|
{
|
||||||
err = gpg_error_from_syserror ();
|
err = gpg_error_from_syserror ();
|
||||||
gcry_sexp_release (s_pkey);
|
gcry_sexp_release (s_pkey);
|
||||||
@ -4824,6 +4824,7 @@ do_writekey (app_t app, ctrl_t ctrl,
|
|||||||
const unsigned char *buf, *tok;
|
const unsigned char *buf, *tok;
|
||||||
size_t buflen, toklen;
|
size_t buflen, toklen;
|
||||||
int depth;
|
int depth;
|
||||||
|
char *algostr = NULL;
|
||||||
|
|
||||||
(void)ctrl;
|
(void)ctrl;
|
||||||
|
|
||||||
@ -4866,17 +4867,41 @@ do_writekey (app_t app, ctrl_t ctrl,
|
|||||||
goto leave;
|
goto leave;
|
||||||
if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
|
if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
|
||||||
goto leave;
|
goto leave;
|
||||||
if (tok && toklen == 3 && memcmp ("rsa", tok, toklen) == 0)
|
|
||||||
err = rsa_writekey (app, ctrl, pincb, pincb_arg, keyno, buf, buflen, depth);
|
if (tok && toklen == 3 && (!memcmp ("rsa", tok, toklen)
|
||||||
else if (tok && toklen == 3 && memcmp ("ecc", tok, toklen) == 0)
|
|| !memcmp ("ecc", tok, toklen)))
|
||||||
err = ecc_writekey (app, ctrl, pincb, pincb_arg, keyno, buf, buflen, depth);
|
{
|
||||||
|
gcry_sexp_t stmp;
|
||||||
|
if (!gcry_sexp_new (&stmp, keydata, keydatalen, 0))
|
||||||
|
algostr = pubkey_algo_string (stmp, NULL);
|
||||||
|
else
|
||||||
|
algostr = NULL;
|
||||||
|
gcry_sexp_release (stmp);
|
||||||
|
if (app->app_local->keyattr[keyno].keyalgo && algostr
|
||||||
|
&& strcmp (app->app_local->keyattr[keyno].keyalgo, algostr))
|
||||||
|
{
|
||||||
|
log_info ("openpgp: changing key attribute from %s to %s\n",
|
||||||
|
app->app_local->keyattr[keyno].keyalgo, algostr);
|
||||||
|
err = change_keyattr_from_string (app, ctrl, pincb, pincb_arg,
|
||||||
|
keyid, algostr, NULL, 0);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*tok == 'r')
|
||||||
|
err = rsa_writekey (app, ctrl, pincb, pincb_arg, keyno,
|
||||||
|
buf,buflen,depth);
|
||||||
|
else
|
||||||
|
err = ecc_writekey (app, ctrl, pincb, pincb_arg, keyno,
|
||||||
|
buf, buflen, depth);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
err = gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO);
|
err = gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO);
|
||||||
goto leave;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
|
xfree (algostr);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,7 +326,7 @@ struct prkdf_object_s
|
|||||||
char *serial_number;
|
char *serial_number;
|
||||||
|
|
||||||
/* KDF/KEK parameter for OpenPGP's ECDH. First byte is zero if not
|
/* KDF/KEK parameter for OpenPGP's ECDH. First byte is zero if not
|
||||||
* available. .*/
|
* available. */
|
||||||
unsigned char ecdh_kdf[4];
|
unsigned char ecdh_kdf[4];
|
||||||
|
|
||||||
/* Length and allocated buffer with the Id of this object. */
|
/* Length and allocated buffer with the Id of this object. */
|
||||||
|
@ -362,7 +362,7 @@ inq_certificate (void *opaque, const char *line)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
log_error ("unsupported inquiry '%s'\n", line);
|
log_error ("unsupported certificate inquiry '%s'\n", line);
|
||||||
return gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
|
return gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -386,8 +386,8 @@ inq_certificate (void *opaque, const char *line)
|
|||||||
int err;
|
int err;
|
||||||
ksba_cert_t cert;
|
ksba_cert_t cert;
|
||||||
|
|
||||||
|
err = gpgsm_find_cert (parm->ctrl, line, ski, &cert,
|
||||||
err = gpgsm_find_cert (parm->ctrl, line, ski, &cert, 1);
|
FIND_CERT_ALLOW_AMBIG|FIND_CERT_WITH_EPHEM);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
log_error ("certificate not found: %s\n", gpg_strerror (err));
|
log_error ("certificate not found: %s\n", gpg_strerror (err));
|
||||||
@ -521,6 +521,7 @@ isvalid_status_cb (void *opaque, const char *line)
|
|||||||
|
|
||||||
GPG_ERR_CERTIFICATE_REVOKED
|
GPG_ERR_CERTIFICATE_REVOKED
|
||||||
GPG_ERR_NO_CRL_KNOWN
|
GPG_ERR_NO_CRL_KNOWN
|
||||||
|
GPG_ERR_INV_CRL_OBJ
|
||||||
GPG_ERR_CRL_TOO_OLD
|
GPG_ERR_CRL_TOO_OLD
|
||||||
|
|
||||||
Values for USE_OCSP:
|
Values for USE_OCSP:
|
||||||
@ -1014,7 +1015,8 @@ run_command_inq_cb (void *opaque, const char *line)
|
|||||||
if (!*line)
|
if (!*line)
|
||||||
return gpg_error (GPG_ERR_ASS_PARAMETER);
|
return gpg_error (GPG_ERR_ASS_PARAMETER);
|
||||||
|
|
||||||
err = gpgsm_find_cert (parm->ctrl, line, NULL, &cert, 1);
|
err = gpgsm_find_cert (parm->ctrl, line, NULL, &cert,
|
||||||
|
FIND_CERT_ALLOW_AMBIG);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
log_error ("certificate not found: %s\n", gpg_strerror (err));
|
log_error ("certificate not found: %s\n", gpg_strerror (err));
|
||||||
@ -1035,9 +1037,33 @@ run_command_inq_cb (void *opaque, const char *line)
|
|||||||
line = s;
|
line = s;
|
||||||
log_info ("dirmngr: %s\n", line);
|
log_info ("dirmngr: %s\n", line);
|
||||||
}
|
}
|
||||||
|
else if ((s = has_leading_keyword (line, "ISTRUSTED")))
|
||||||
|
{
|
||||||
|
/* The server is asking us whether the certificate is a trusted
|
||||||
|
root certificate. */
|
||||||
|
char fpr[41];
|
||||||
|
struct rootca_flags_s rootca_flags;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
line = s;
|
||||||
|
|
||||||
|
for (s=line,n=0; hexdigitp (s); s++, n++)
|
||||||
|
;
|
||||||
|
if (*s || n != 40)
|
||||||
|
return gpg_error (GPG_ERR_ASS_PARAMETER);
|
||||||
|
for (s=line, n=0; n < 40; s++, n++)
|
||||||
|
fpr[n] = (*s >= 'a')? (*s & 0xdf): *s;
|
||||||
|
fpr[n] = 0;
|
||||||
|
|
||||||
|
if (!gpgsm_agent_istrusted (parm->ctrl, NULL, fpr, &rootca_flags))
|
||||||
|
rc = assuan_send_data (parm->ctx, "1", 1);
|
||||||
|
else
|
||||||
|
rc = 0;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
log_error ("unsupported inquiry '%s'\n", line);
|
log_error ("unsupported command inquiry '%s'\n", line);
|
||||||
rc = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
|
rc = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,6 +122,7 @@ do_list (int is_error, int listmode, estream_t fp, const char *format, ...)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
es_fflush (es_stdout);
|
||||||
log_logv (is_error? GPGRT_LOGLVL_ERROR: GPGRT_LOGLVL_INFO,
|
log_logv (is_error? GPGRT_LOGLVL_ERROR: GPGRT_LOGLVL_INFO,
|
||||||
format, arg_ptr);
|
format, arg_ptr);
|
||||||
log_printf ("\n");
|
log_printf ("\n");
|
||||||
@ -1480,6 +1481,7 @@ ask_marktrusted (ctrl_t ctrl, ksba_cert_t cert, int listmode)
|
|||||||
int success = 0;
|
int success = 0;
|
||||||
|
|
||||||
fpr = gpgsm_get_fingerprint_string (cert, GCRY_MD_SHA1);
|
fpr = gpgsm_get_fingerprint_string (cert, GCRY_MD_SHA1);
|
||||||
|
es_fflush (es_stdout);
|
||||||
log_info (_("fingerprint=%s\n"), fpr? fpr : "?");
|
log_info (_("fingerprint=%s\n"), fpr? fpr : "?");
|
||||||
xfree (fpr);
|
xfree (fpr);
|
||||||
|
|
||||||
@ -2277,6 +2279,7 @@ gpgsm_basic_cert_check (ctrl_t ctrl, ksba_cert_t cert)
|
|||||||
{
|
{
|
||||||
if (!opt.quiet)
|
if (!opt.quiet)
|
||||||
{
|
{
|
||||||
|
es_fflush (es_stdout);
|
||||||
log_info ("issuer certificate (#/");
|
log_info ("issuer certificate (#/");
|
||||||
gpgsm_dump_string (issuer);
|
gpgsm_dump_string (issuer);
|
||||||
log_printf (") not found\n");
|
log_printf (") not found\n");
|
||||||
|
@ -728,7 +728,14 @@ gpgsm_es_print_name2 (estream_t fp, const char *name, int translate)
|
|||||||
void
|
void
|
||||||
gpgsm_es_print_name (estream_t fp, const char *name)
|
gpgsm_es_print_name (estream_t fp, const char *name)
|
||||||
{
|
{
|
||||||
gpgsm_es_print_name2 (fp, name, 1);
|
if (opt.no_pretty_dn)
|
||||||
|
{
|
||||||
|
if (!name)
|
||||||
|
name = "[error]";
|
||||||
|
es_write_sanitized (fp, name, strlen (name), NULL, NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
gpgsm_es_print_name2 (fp, name, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -508,11 +508,12 @@ gpgsm_release_certlist (certlist_t list)
|
|||||||
int
|
int
|
||||||
gpgsm_find_cert (ctrl_t ctrl,
|
gpgsm_find_cert (ctrl_t ctrl,
|
||||||
const char *name, ksba_sexp_t keyid, ksba_cert_t *r_cert,
|
const char *name, ksba_sexp_t keyid, ksba_cert_t *r_cert,
|
||||||
int allow_ambiguous)
|
unsigned int flags)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
KEYDB_SEARCH_DESC desc;
|
KEYDB_SEARCH_DESC desc;
|
||||||
KEYDB_HANDLE kh = NULL;
|
KEYDB_HANDLE kh = NULL;
|
||||||
|
int allow_ambiguous = (flags & FIND_CERT_ALLOW_AMBIG);
|
||||||
|
|
||||||
*r_cert = NULL;
|
*r_cert = NULL;
|
||||||
rc = classify_user_id (name, &desc, 0);
|
rc = classify_user_id (name, &desc, 0);
|
||||||
@ -523,6 +524,9 @@ gpgsm_find_cert (ctrl_t ctrl,
|
|||||||
rc = gpg_error (GPG_ERR_ENOMEM);
|
rc = gpg_error (GPG_ERR_ENOMEM);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if ((flags & FIND_CERT_WITH_EPHEM))
|
||||||
|
keydb_set_ephemeral (kh, 1);
|
||||||
|
|
||||||
nextone:
|
nextone:
|
||||||
rc = keydb_search (ctrl, kh, &desc, 1);
|
rc = keydb_search (ctrl, kh, &desc, 1);
|
||||||
if (!rc)
|
if (!rc)
|
||||||
|
17
sm/gpgsm.c
17
sm/gpgsm.c
@ -114,6 +114,7 @@ enum cmd_and_opt_values {
|
|||||||
oNoLogFile,
|
oNoLogFile,
|
||||||
oAuditLog,
|
oAuditLog,
|
||||||
oHtmlAuditLog,
|
oHtmlAuditLog,
|
||||||
|
oLogTime,
|
||||||
|
|
||||||
oEnableSpecialFilenames,
|
oEnableSpecialFilenames,
|
||||||
|
|
||||||
@ -169,6 +170,7 @@ enum cmd_and_opt_values {
|
|||||||
oWithKeyScreening,
|
oWithKeyScreening,
|
||||||
oAnswerYes,
|
oAnswerYes,
|
||||||
oAnswerNo,
|
oAnswerNo,
|
||||||
|
oNoPrettyDN,
|
||||||
oKeyring,
|
oKeyring,
|
||||||
oDefaultKey,
|
oDefaultKey,
|
||||||
oDefRecipient,
|
oDefRecipient,
|
||||||
@ -288,6 +290,7 @@ static gpgrt_opt_t opts[] = {
|
|||||||
N_("|FILE|write server mode logs to FILE")),
|
N_("|FILE|write server mode logs to FILE")),
|
||||||
ARGPARSE_s_n (oNoLogFile, "no-log-file", "@"),
|
ARGPARSE_s_n (oNoLogFile, "no-log-file", "@"),
|
||||||
ARGPARSE_s_i (oLoggerFD, "logger-fd", "@"),
|
ARGPARSE_s_i (oLoggerFD, "logger-fd", "@"),
|
||||||
|
ARGPARSE_s_n (oLogTime, "log-time", "@"),
|
||||||
ARGPARSE_s_n (oNoSecmemWarn, "no-secmem-warning", "@"),
|
ARGPARSE_s_n (oNoSecmemWarn, "no-secmem-warning", "@"),
|
||||||
|
|
||||||
|
|
||||||
@ -383,7 +386,7 @@ static gpgrt_opt_t opts[] = {
|
|||||||
ARGPARSE_s_n (oWithKeygrip, "with-keygrip", "@"),
|
ARGPARSE_s_n (oWithKeygrip, "with-keygrip", "@"),
|
||||||
ARGPARSE_s_n (oWithSecret, "with-secret", "@"),
|
ARGPARSE_s_n (oWithSecret, "with-secret", "@"),
|
||||||
ARGPARSE_s_n (oWithKeyScreening,"with-key-screening", "@"),
|
ARGPARSE_s_n (oWithKeyScreening,"with-key-screening", "@"),
|
||||||
|
ARGPARSE_s_n (oNoPrettyDN, "no-pretty-dn", "@"),
|
||||||
|
|
||||||
|
|
||||||
ARGPARSE_header ("Security", N_("Options controlling the security")),
|
ARGPARSE_header ("Security", N_("Options controlling the security")),
|
||||||
@ -499,6 +502,9 @@ static int maybe_setuid = 1;
|
|||||||
static const char *debug_level;
|
static const char *debug_level;
|
||||||
static unsigned int debug_value;
|
static unsigned int debug_value;
|
||||||
|
|
||||||
|
/* Helper for --log-time; */
|
||||||
|
static int opt_log_time;
|
||||||
|
|
||||||
/* Default value for include-certs. We need an extra macro for
|
/* Default value for include-certs. We need an extra macro for
|
||||||
gpgconf-list because the variable will be changed by the command
|
gpgconf-list because the variable will be changed by the command
|
||||||
line option.
|
line option.
|
||||||
@ -1247,6 +1253,7 @@ main ( int argc, char **argv)
|
|||||||
|
|
||||||
case oLogFile: logfile = pargs.r.ret_str; break;
|
case oLogFile: logfile = pargs.r.ret_str; break;
|
||||||
case oNoLogFile: logfile = NULL; break;
|
case oNoLogFile: logfile = NULL; break;
|
||||||
|
case oLogTime: opt_log_time = 1; break;
|
||||||
|
|
||||||
case oAuditLog: auditlog = pargs.r.ret_str; break;
|
case oAuditLog: auditlog = pargs.r.ret_str; break;
|
||||||
case oHtmlAuditLog: htmlauditlog = pargs.r.ret_str; break;
|
case oHtmlAuditLog: htmlauditlog = pargs.r.ret_str; break;
|
||||||
@ -1312,6 +1319,10 @@ main ( int argc, char **argv)
|
|||||||
opt.with_key_screening = 1;
|
opt.with_key_screening = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case oNoPrettyDN:
|
||||||
|
opt.no_pretty_dn = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
case oHomedir: gnupg_set_homedir (pargs.r.ret_str); break;
|
case oHomedir: gnupg_set_homedir (pargs.r.ret_str); break;
|
||||||
case oChUid: break; /* Command line only (see above). */
|
case oChUid: break; /* Command line only (see above). */
|
||||||
case oAgentProgram: opt.agent_program = pargs.r.ret_str; break;
|
case oAgentProgram: opt.agent_program = pargs.r.ret_str; break;
|
||||||
@ -1579,6 +1590,10 @@ main ( int argc, char **argv)
|
|||||||
log_set_file (logfile);
|
log_set_file (logfile);
|
||||||
log_set_prefix (NULL, GPGRT_LOG_WITH_PREFIX | GPGRT_LOG_WITH_TIME | GPGRT_LOG_WITH_PID);
|
log_set_prefix (NULL, GPGRT_LOG_WITH_PREFIX | GPGRT_LOG_WITH_TIME | GPGRT_LOG_WITH_PID);
|
||||||
}
|
}
|
||||||
|
else if (opt_log_time)
|
||||||
|
log_set_prefix (NULL, (GPGRT_LOG_WITH_PREFIX|GPGRT_LOG_NO_REGISTRY
|
||||||
|
|GPGRT_LOG_WITH_TIME));
|
||||||
|
|
||||||
|
|
||||||
if (gnupg_faked_time_p ())
|
if (gnupg_faked_time_p ())
|
||||||
{
|
{
|
||||||
|
@ -85,6 +85,8 @@ struct
|
|||||||
|
|
||||||
int with_key_screening; /* Option --with-key-screening active. */
|
int with_key_screening; /* Option --with-key-screening active. */
|
||||||
|
|
||||||
|
int no_pretty_dn; /* Option --no-pretty-dn */
|
||||||
|
|
||||||
int pinentry_mode;
|
int pinentry_mode;
|
||||||
int request_origin;
|
int request_origin;
|
||||||
|
|
||||||
@ -404,8 +406,11 @@ int gpgsm_add_cert_to_certlist (ctrl_t ctrl, ksba_cert_t cert,
|
|||||||
int gpgsm_add_to_certlist (ctrl_t ctrl, const char *name, int secret,
|
int gpgsm_add_to_certlist (ctrl_t ctrl, const char *name, int secret,
|
||||||
certlist_t *listaddr, int is_encrypt_to);
|
certlist_t *listaddr, int is_encrypt_to);
|
||||||
void gpgsm_release_certlist (certlist_t list);
|
void gpgsm_release_certlist (certlist_t list);
|
||||||
|
|
||||||
|
#define FIND_CERT_ALLOW_AMBIG 1
|
||||||
|
#define FIND_CERT_WITH_EPHEM 2
|
||||||
int gpgsm_find_cert (ctrl_t ctrl, const char *name, ksba_sexp_t keyid,
|
int gpgsm_find_cert (ctrl_t ctrl, const char *name, ksba_sexp_t keyid,
|
||||||
ksba_cert_t *r_cert, int allow_ambiguous);
|
ksba_cert_t *r_cert, unsigned int flags);
|
||||||
|
|
||||||
/*-- keylist.c --*/
|
/*-- keylist.c --*/
|
||||||
gpg_error_t gpgsm_list_keys (ctrl_t ctrl, strlist_t names,
|
gpg_error_t gpgsm_list_keys (ctrl_t ctrl, strlist_t names,
|
||||||
|
10
sm/verify.c
10
sm/verify.c
@ -105,12 +105,17 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp)
|
|||||||
int signer;
|
int signer;
|
||||||
const char *algoid;
|
const char *algoid;
|
||||||
int algo;
|
int algo;
|
||||||
int is_detached;
|
int is_detached, maybe_detached;
|
||||||
estream_t in_fp = NULL;
|
estream_t in_fp = NULL;
|
||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
audit_set_type (ctrl->audit, AUDIT_TYPE_VERIFY);
|
audit_set_type (ctrl->audit, AUDIT_TYPE_VERIFY);
|
||||||
|
|
||||||
|
/* Although we detect detached signatures during the parsing phase,
|
||||||
|
* we need to know it earlier and thus accept the caller idea of
|
||||||
|
* what to verify. */
|
||||||
|
maybe_detached = (data_fd != -1);
|
||||||
|
|
||||||
kh = keydb_new (ctrl);
|
kh = keydb_new (ctrl);
|
||||||
if (!kh)
|
if (!kh)
|
||||||
{
|
{
|
||||||
@ -131,7 +136,8 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp)
|
|||||||
rc = gnupg_ksba_create_reader
|
rc = gnupg_ksba_create_reader
|
||||||
(&b64reader, ((ctrl->is_pem? GNUPG_KSBA_IO_PEM : 0)
|
(&b64reader, ((ctrl->is_pem? GNUPG_KSBA_IO_PEM : 0)
|
||||||
| (ctrl->is_base64? GNUPG_KSBA_IO_BASE64 : 0)
|
| (ctrl->is_base64? GNUPG_KSBA_IO_BASE64 : 0)
|
||||||
| (ctrl->autodetect_encoding? GNUPG_KSBA_IO_AUTODETECT : 0)),
|
| (ctrl->autodetect_encoding? GNUPG_KSBA_IO_AUTODETECT : 0)
|
||||||
|
| (maybe_detached? GNUPG_KSBA_IO_STRIP : 0)),
|
||||||
in_fp, &reader);
|
in_fp, &reader);
|
||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
|
@ -1509,6 +1509,11 @@ show_configs (estream_t outfp)
|
|||||||
static const char *names[] = { "common.conf", "gpg-agent.conf",
|
static const char *names[] = { "common.conf", "gpg-agent.conf",
|
||||||
"scdaemon.conf", "dirmngr.conf",
|
"scdaemon.conf", "dirmngr.conf",
|
||||||
"gpg.conf", "gpgsm.conf" };
|
"gpg.conf", "gpgsm.conf" };
|
||||||
|
static const char *envvars[] = { "PATH",
|
||||||
|
"http_proxy", "HTTP_PROXY",
|
||||||
|
"https_proxy", "HTTPS_PROXY",
|
||||||
|
"LD_LIBRARY_PATH", "LD_PRELOAD",
|
||||||
|
"LD_AUDIT", "LD_ORIGIN_PATH" };
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
int idx;
|
int idx;
|
||||||
char *fname;
|
char *fname;
|
||||||
@ -1539,6 +1544,11 @@ show_configs (estream_t outfp)
|
|||||||
list_dirs (outfp, NULL, 1);
|
list_dirs (outfp, NULL, 1);
|
||||||
es_fprintf (outfp, "\n");
|
es_fprintf (outfp, "\n");
|
||||||
|
|
||||||
|
for (idx=0; idx < DIM(envvars); idx++)
|
||||||
|
if ((s = getenv (envvars[idx])))
|
||||||
|
es_fprintf (outfp, "%s=%s\n", envvars[idx], s);
|
||||||
|
es_fprintf (outfp, "\n");
|
||||||
|
|
||||||
fname = make_filename (gnupg_sysconfdir (), "gpgconf.conf", NULL);
|
fname = make_filename (gnupg_sysconfdir (), "gpgconf.conf", NULL);
|
||||||
if (!gnupg_access (fname, F_OK))
|
if (!gnupg_access (fname, F_OK))
|
||||||
{
|
{
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
#include "gpgtar.h"
|
#include "gpgtar.h"
|
||||||
|
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
check_suspicious_name (const char *name)
|
check_suspicious_name (const char *name, tarinfo_t info)
|
||||||
{
|
{
|
||||||
size_t n;
|
size_t n;
|
||||||
|
|
||||||
@ -47,6 +47,7 @@ check_suspicious_name (const char *name)
|
|||||||
{
|
{
|
||||||
log_error ("filename '%s' contains a backslash - "
|
log_error ("filename '%s' contains a backslash - "
|
||||||
"can't extract on this system\n", name);
|
"can't extract on this system\n", name);
|
||||||
|
info->skipped_badname++;
|
||||||
return gpg_error (GPG_ERR_INV_NAME);
|
return gpg_error (GPG_ERR_INV_NAME);
|
||||||
}
|
}
|
||||||
#endif /*HAVE_DOSISH_SYSTEM*/
|
#endif /*HAVE_DOSISH_SYSTEM*/
|
||||||
@ -59,6 +60,7 @@ check_suspicious_name (const char *name)
|
|||||||
{
|
{
|
||||||
log_error ("filename '%s' has suspicious parts - not extracting\n",
|
log_error ("filename '%s' has suspicious parts - not extracting\n",
|
||||||
name);
|
name);
|
||||||
|
info->skipped_suspicious++;
|
||||||
return gpg_error (GPG_ERR_INV_NAME);
|
return gpg_error (GPG_ERR_INV_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,7 +85,7 @@ extract_regular (estream_t stream, const char *dirname,
|
|||||||
if (sl->flags == 1)
|
if (sl->flags == 1)
|
||||||
fname = sl->d;
|
fname = sl->d;
|
||||||
|
|
||||||
err = check_suspicious_name (fname);
|
err = check_suspicious_name (fname, info);
|
||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
@ -131,8 +133,12 @@ extract_regular (estream_t stream, const char *dirname,
|
|||||||
/* Fixme: Set permissions etc. */
|
/* Fixme: Set permissions etc. */
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
if (!err && opt.verbose)
|
if (!err)
|
||||||
log_info ("extracted '%s'\n", fname);
|
{
|
||||||
|
if (opt.verbose)
|
||||||
|
log_info ("extracted '%s'\n", fname);
|
||||||
|
info->nextracted++;
|
||||||
|
}
|
||||||
es_fclose (outfp);
|
es_fclose (outfp);
|
||||||
if (err && fname && outfp)
|
if (err && fname && outfp)
|
||||||
{
|
{
|
||||||
@ -146,7 +152,8 @@ extract_regular (estream_t stream, const char *dirname,
|
|||||||
|
|
||||||
|
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
extract_directory (const char *dirname, tar_header_t hdr, strlist_t exthdr)
|
extract_directory (const char *dirname, tarinfo_t info,
|
||||||
|
tar_header_t hdr, strlist_t exthdr)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
const char *name;
|
const char *name;
|
||||||
@ -158,7 +165,7 @@ extract_directory (const char *dirname, tar_header_t hdr, strlist_t exthdr)
|
|||||||
if (sl->flags == 1)
|
if (sl->flags == 1)
|
||||||
name = sl->d;
|
name = sl->d;
|
||||||
|
|
||||||
err = check_suspicious_name (name);
|
err = check_suspicious_name (name, info);
|
||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
@ -230,13 +237,19 @@ extract (estream_t stream, const char *dirname, tarinfo_t info,
|
|||||||
if (hdr->typeflag == TF_REGULAR || hdr->typeflag == TF_UNKNOWN)
|
if (hdr->typeflag == TF_REGULAR || hdr->typeflag == TF_UNKNOWN)
|
||||||
err = extract_regular (stream, dirname, info, hdr, exthdr);
|
err = extract_regular (stream, dirname, info, hdr, exthdr);
|
||||||
else if (hdr->typeflag == TF_DIRECTORY)
|
else if (hdr->typeflag == TF_DIRECTORY)
|
||||||
err = extract_directory (dirname, hdr, exthdr);
|
err = extract_directory (dirname, info, hdr, exthdr);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char record[RECORDSIZE];
|
char record[RECORDSIZE];
|
||||||
|
|
||||||
log_info ("unsupported file type %d for '%s' - skipped\n",
|
log_info ("unsupported file type %d for '%s' - skipped\n",
|
||||||
(int)hdr->typeflag, hdr->name);
|
(int)hdr->typeflag, hdr->name);
|
||||||
|
if (hdr->typeflag == TF_SYMLINK)
|
||||||
|
info->skipped_symlinks++;
|
||||||
|
else if (hdr->typeflag == TF_HARDLINK)
|
||||||
|
info->skipped_hardlinks++;
|
||||||
|
else
|
||||||
|
info->skipped_other++;
|
||||||
for (err = 0, n=0; !err && n < hdr->nrecords; n++)
|
for (err = 0, n=0; !err && n < hdr->nrecords; n++)
|
||||||
{
|
{
|
||||||
err = read_record (stream, record);
|
err = read_record (stream, record);
|
||||||
@ -328,7 +341,7 @@ gpgtar_extract (const char *filename, int decrypt)
|
|||||||
tarinfo_t tarinfo = &tarinfo_buffer;
|
tarinfo_t tarinfo = &tarinfo_buffer;
|
||||||
pid_t pid = (pid_t)(-1);
|
pid_t pid = (pid_t)(-1);
|
||||||
char *logfilename = NULL;
|
char *logfilename = NULL;
|
||||||
|
unsigned long long notextracted;
|
||||||
|
|
||||||
memset (&tarinfo_buffer, 0, sizeof tarinfo_buffer);
|
memset (&tarinfo_buffer, 0, sizeof tarinfo_buffer);
|
||||||
|
|
||||||
@ -478,8 +491,37 @@ gpgtar_extract (const char *filename, int decrypt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
|
notextracted = tarinfo->skipped_badname;
|
||||||
|
notextracted += tarinfo->skipped_suspicious;
|
||||||
|
notextracted += tarinfo->skipped_symlinks;
|
||||||
|
notextracted += tarinfo->skipped_hardlinks;
|
||||||
|
notextracted += tarinfo->skipped_other;
|
||||||
|
if (opt.status_stream)
|
||||||
|
es_fprintf (opt.status_stream, "[GNUPG:] GPGTAR_EXTRACT"
|
||||||
|
" %llu %llu %lu %lu %lu %lu %lu\n",
|
||||||
|
tarinfo->nextracted,
|
||||||
|
notextracted,
|
||||||
|
tarinfo->skipped_badname,
|
||||||
|
tarinfo->skipped_suspicious,
|
||||||
|
tarinfo->skipped_symlinks,
|
||||||
|
tarinfo->skipped_hardlinks,
|
||||||
|
tarinfo->skipped_other);
|
||||||
|
if (notextracted && !opt.quiet)
|
||||||
|
{
|
||||||
|
log_info ("Number of files not extracted: %llu\n", notextracted);
|
||||||
|
if (tarinfo->skipped_badname)
|
||||||
|
log_info (" invalid name: %lu\n", tarinfo->skipped_badname);
|
||||||
|
if (tarinfo->skipped_suspicious)
|
||||||
|
log_info (" suspicious name: %lu\n", tarinfo->skipped_suspicious);
|
||||||
|
if (tarinfo->skipped_symlinks)
|
||||||
|
log_info (" symlink: %lu\n", tarinfo->skipped_symlinks);
|
||||||
|
if (tarinfo->skipped_hardlinks)
|
||||||
|
log_info (" hardlink: %lu\n", tarinfo->skipped_hardlinks);
|
||||||
|
if (tarinfo->skipped_other)
|
||||||
|
log_info (" other reason: %lu\n", tarinfo->skipped_other);
|
||||||
|
}
|
||||||
|
|
||||||
free_strlist (extheader);
|
free_strlist (extheader);
|
||||||
xfree (header);
|
xfree (header);
|
||||||
xfree (dirname);
|
xfree (dirname);
|
||||||
|
@ -459,7 +459,7 @@ main (int argc, char **argv)
|
|||||||
|
|
||||||
gnupg_reopen_std (GPGTAR_NAME);
|
gnupg_reopen_std (GPGTAR_NAME);
|
||||||
gpgrt_set_strusage (my_strusage);
|
gpgrt_set_strusage (my_strusage);
|
||||||
log_set_prefix (GPGTAR_NAME, GPGRT_LOG_WITH_PREFIX);
|
log_set_prefix (GPGTAR_NAME, GPGRT_LOG_WITH_PREFIX|GPGRT_LOG_NO_REGISTRY);
|
||||||
|
|
||||||
/* Make sure that our subsystems are ready. */
|
/* Make sure that our subsystems are ready. */
|
||||||
i18n_init();
|
i18n_init();
|
||||||
@ -501,7 +501,11 @@ main (int argc, char **argv)
|
|||||||
log_fatal ("status-fd is invalid: %s\n", strerror (errno));
|
log_fatal ("status-fd is invalid: %s\n", strerror (errno));
|
||||||
|
|
||||||
if (fd == 1)
|
if (fd == 1)
|
||||||
opt.status_stream = es_stdout;
|
{
|
||||||
|
opt.status_stream = es_stdout;
|
||||||
|
if (!skip_crypto)
|
||||||
|
log_fatal ("using stdout for the status-fd is not possible\n");
|
||||||
|
}
|
||||||
else if (fd == 2)
|
else if (fd == 2)
|
||||||
opt.status_stream = es_stderr;
|
opt.status_stream = es_stderr;
|
||||||
else
|
else
|
||||||
|
@ -54,8 +54,14 @@ struct
|
|||||||
/* An info structure to avoid global variables. */
|
/* An info structure to avoid global variables. */
|
||||||
struct tarinfo_s
|
struct tarinfo_s
|
||||||
{
|
{
|
||||||
unsigned long long nblocks; /* Count of processed blocks. */
|
unsigned long long nblocks; /* Count of processed blocks. */
|
||||||
unsigned long long headerblock; /* Number of current header block. */
|
unsigned long long headerblock; /* Number of current header block. */
|
||||||
|
unsigned long long nextracted; /* Number of extracted files. */
|
||||||
|
unsigned long skipped_badname;
|
||||||
|
unsigned long skipped_suspicious;
|
||||||
|
unsigned long skipped_symlinks;
|
||||||
|
unsigned long skipped_hardlinks;
|
||||||
|
unsigned long skipped_other;
|
||||||
};
|
};
|
||||||
typedef struct tarinfo_s *tarinfo_t;
|
typedef struct tarinfo_s *tarinfo_t;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user