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. */
|
||||
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. */
|
||||
|
||||
/* 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);
|
||||
int agent_protect (const unsigned char *plainkey, const char *passphrase,
|
||||
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,
|
||||
const unsigned char *protectedkey, const char *passphrase,
|
||||
gnupg_isotime_t protected_at,
|
||||
|
@ -1543,6 +1543,17 @@ agent_askpin (ctrl_t ctrl,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
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->status = 0;
|
||||
@ -1802,6 +1813,16 @@ agent_get_passphrase (ctrl_t ctrl,
|
||||
if (rc)
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
if (*passphrase)
|
||||
err = agent_protect (buffer_new, passphrase, buffer, buffer_n, 0, -1);
|
||||
err = agent_protect (buffer_new, passphrase, buffer, buffer_n, 0);
|
||||
else
|
||||
{
|
||||
/* The key derivation function does not support zero length
|
||||
|
@ -1218,12 +1218,6 @@ cmd_keyattr (assuan_context_t ctx, char *line)
|
||||
if (ctrl->restricted)
|
||||
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");
|
||||
|
||||
line = skip_options (line);
|
||||
@ -2987,7 +2981,7 @@ cmd_import_key (assuan_context_t ctx, char *line)
|
||||
if (passphrase)
|
||||
{
|
||||
err = agent_protect (key, passphrase, &finalkey, &finalkeylen,
|
||||
ctrl->s2k_count, -1);
|
||||
ctrl->s2k_count);
|
||||
if (!err)
|
||||
err = agent_write_private_key (grip, finalkey, finalkeylen, force,
|
||||
NULL, NULL, opt_timestamp);
|
||||
|
@ -1146,7 +1146,7 @@ convert_from_openpgp_native (ctrl_t ctrl,
|
||||
|
||||
if (!agent_protect (*r_key, passphrase,
|
||||
&protectedkey, &protectedkeylen,
|
||||
ctrl->s2k_count, -1))
|
||||
ctrl->s2k_count))
|
||||
agent_write_private_key (grip, protectedkey, protectedkeylen, 1,
|
||||
NULL, NULL, 0);
|
||||
xfree (protectedkey);
|
||||
|
250
agent/findkey.c
250
agent/findkey.c
@ -2,6 +2,7 @@
|
||||
* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007,
|
||||
* 2010, 2011 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2014, 2019 Werner Koch
|
||||
* Copyright (C) 2023 g10 Code GmbH
|
||||
*
|
||||
* 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. */
|
||||
static gpg_error_t
|
||||
write_extended_private_key (char *fname, estream_t fp, int update, int newkey,
|
||||
const void *buf, size_t len,
|
||||
/* Write the S-expression formatted key (BUFFER,LENGTH) 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)
|
||||
{
|
||||
gpg_error_t err;
|
||||
char *fname;
|
||||
estream_t fp;
|
||||
char hexgrip[40+4+1];
|
||||
int update, newkey;
|
||||
nvc_t pk = NULL;
|
||||
gcry_sexp_t key = NULL;
|
||||
int remove = 0;
|
||||
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)
|
||||
{
|
||||
int line;
|
||||
@ -115,10 +211,11 @@ write_extended_private_key (char *fname, estream_t fp, int update, int newkey,
|
||||
}
|
||||
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)
|
||||
goto leave;
|
||||
|
||||
err = nvc_set_private_key (pk, key);
|
||||
if (err)
|
||||
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
|
||||
* item yet.)*/
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/* Back to start and write. */
|
||||
err = es_fseek (fp, 0, SEEK_SET);
|
||||
if (err)
|
||||
goto leave;
|
||||
@ -212,133 +309,6 @@ write_extended_private_key (char *fname, estream_t fp, int update, int newkey,
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/* Callback function to try the unprotection from the passphrase query
|
||||
code. */
|
||||
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);
|
||||
|
||||
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
|
||||
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;
|
||||
|
||||
rc = agent_protect (buf, passphrase, &p, &len, s2k_count, -1);
|
||||
rc = agent_protect (buf, passphrase, &p, &len, s2k_count);
|
||||
if (rc)
|
||||
{
|
||||
xfree (buf);
|
||||
|
@ -117,8 +117,6 @@ enum cmd_and_opt_values
|
||||
oCheckSymPassphrasePattern,
|
||||
oMaxPassphraseDays,
|
||||
oEnablePassphraseHistory,
|
||||
oDisableExtendedKeyFormat,
|
||||
oEnableExtendedKeyFormat,
|
||||
oStealSocket,
|
||||
oUseStandardSocket,
|
||||
oNoUseStandardSocket,
|
||||
@ -241,8 +239,6 @@ static gpgrt_opt_t opts[] = {
|
||||
/* */ "@"
|
||||
#endif
|
||||
),
|
||||
ARGPARSE_s_n (oDisableExtendedKeyFormat, "disable-extended-key-format", "@"),
|
||||
ARGPARSE_s_n (oEnableExtendedKeyFormat, "enable-extended-key-format", "@"),
|
||||
ARGPARSE_s_i (oListenBacklog, "listen-backlog", "@"),
|
||||
ARGPARSE_op_u (oAutoExpandSecmem, "auto-expand-secmem", "@"),
|
||||
ARGPARSE_s_s (oFakedSystemTime, "faked-system-time", "@"),
|
||||
@ -318,7 +314,8 @@ static gpgrt_opt_t opts[] = {
|
||||
ARGPARSE_s_n (oNoUseStandardSocket, "no-use-standard-socket", "@"),
|
||||
|
||||
/* Dummy options. */
|
||||
|
||||
ARGPARSE_s_n (oNoop, "disable-extended-key-format", "@"),
|
||||
ARGPARSE_s_n (oNoop, "enable-extended-key-format", "@"),
|
||||
|
||||
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.max_passphrase_days = MAX_PASSPHRASE_DAYS;
|
||||
opt.enable_passphrase_history = 0;
|
||||
opt.enable_extended_key_format = 1;
|
||||
opt.ignore_cache_for_signing = 0;
|
||||
opt.allow_mark_trusted = 1;
|
||||
opt.sys_trustlist_name = NULL;
|
||||
@ -980,14 +976,6 @@ parse_rereadable_options (gpgrt_argparse_t *pargs, int reread)
|
||||
opt.enable_passphrase_history = 1;
|
||||
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 oAllowMarkTrusted: opt.allow_mark_trusted = 1; break;
|
||||
|
@ -74,7 +74,6 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
|
||||
no_shadow_info = 1;
|
||||
else if (err)
|
||||
{
|
||||
if (gpg_err_code (err) != GPG_ERR_NO_SECKEY)
|
||||
log_error ("failed to read the secret key\n");
|
||||
goto leave;
|
||||
}
|
||||
@ -88,7 +87,7 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
|
||||
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,
|
||||
&buf, &len, r_padding);
|
||||
else
|
||||
@ -96,6 +95,14 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
|
||||
&buf, &len, r_padding);
|
||||
if (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;
|
||||
}
|
||||
|
@ -97,7 +97,6 @@ static const char *opt_passphrase;
|
||||
static char *opt_prompt;
|
||||
static int opt_status_msg;
|
||||
static const char *opt_agent_program;
|
||||
static int opt_debug_use_ocb;
|
||||
|
||||
static char *get_passphrase (int promptno);
|
||||
static void release_passphrase (char *pw);
|
||||
@ -343,8 +342,7 @@ read_and_protect (const char *fname)
|
||||
return;
|
||||
|
||||
pw = get_passphrase (1);
|
||||
rc = agent_protect (key, pw, &result, &resultlen, 0,
|
||||
opt_debug_use_ocb? 1 : -1);
|
||||
rc = agent_protect (key, pw, &result, &resultlen, 0);
|
||||
release_passphrase (pw);
|
||||
xfree (key);
|
||||
if (rc)
|
||||
@ -610,7 +608,7 @@ main (int argc, char **argv )
|
||||
case oHaveCert: opt_have_cert = 1; break;
|
||||
case oPrompt: opt_prompt = pargs.r.ret_str; 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;
|
||||
}
|
||||
|
100
agent/protect.c
100
agent/protect.c
@ -379,12 +379,11 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
|
||||
const char *passphrase,
|
||||
const char *timestamp_exp, size_t timestamp_exp_len,
|
||||
unsigned char **result, size_t *resultlen,
|
||||
unsigned long s2k_count, int use_ocb)
|
||||
unsigned long s2k_count)
|
||||
{
|
||||
gcry_cipher_hd_t hd;
|
||||
const char *modestr;
|
||||
unsigned char hashvalue[20];
|
||||
int blklen, enclen, outlen;
|
||||
int enclen, outlen;
|
||||
unsigned char *iv = NULL;
|
||||
unsigned int ivsize; /* Size of the buffer allocated for IV. */
|
||||
const unsigned char *s2ksalt; /* Points into IV. */
|
||||
@ -398,44 +397,26 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
|
||||
*resultlen = 0;
|
||||
*result = NULL;
|
||||
|
||||
modestr = (use_ocb? "openpgp-s2k3-ocb-aes"
|
||||
/* */: "openpgp-s2k3-sha1-" PROT_CIPHER_STRING "-cbc");
|
||||
modestr = "openpgp-s2k3-ocb-aes";
|
||||
|
||||
rc = gcry_cipher_open (&hd, PROT_CIPHER,
|
||||
use_ocb? GCRY_CIPHER_MODE_OCB :
|
||||
GCRY_CIPHER_MODE_CBC,
|
||||
GCRY_CIPHER_MODE_OCB,
|
||||
GCRY_CIPHER_SECURE);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* 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
|
||||
* have to prefix the text with 2 parenthesis. In CBC 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 prefix the text with 2 parenthesis. Due to OCB mode we
|
||||
* have to allocate enough space for just:
|
||||
*
|
||||
* ((<parameter_list>))
|
||||
*/
|
||||
blklen = gcry_cipher_get_algo_blklen (PROT_CIPHER);
|
||||
if (use_ocb)
|
||||
{
|
||||
|
||||
/* (( )) */
|
||||
outlen = 2 + protlen + 2 ;
|
||||
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)
|
||||
{
|
||||
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. */
|
||||
if (!rc)
|
||||
{
|
||||
/* Allocate random bytes to be used as IV, padding and s2k salt
|
||||
* or in OCB mode for a nonce and the s2k salt. The IV/nonce is
|
||||
* set later because for OCB we need to set the key first. */
|
||||
ivsize = (use_ocb? 12 : (blklen*2)) + 8;
|
||||
/* Allocate random bytes to be used as nonce and s2k salt. The
|
||||
* nonce is set later because for OCB we need to set the key
|
||||
* first. */
|
||||
ivsize = 12 + 8;
|
||||
iv = xtrymalloc (ivsize);
|
||||
if (!iv)
|
||||
rc = gpg_error_from_syserror ();
|
||||
@ -484,12 +465,10 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
|
||||
goto leave;
|
||||
|
||||
/* Set the IV/nonce. */
|
||||
rc = gcry_cipher_setiv (hd, iv, use_ocb? 12 : blklen);
|
||||
rc = gcry_cipher_setiv (hd, iv, 12);
|
||||
if (rc)
|
||||
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);
|
||||
if (!rc)
|
||||
@ -497,27 +476,6 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
|
||||
if (!rc)
|
||||
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. */
|
||||
if (!rc)
|
||||
@ -527,25 +485,9 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
|
||||
*p++ = '(';
|
||||
memcpy (p, protbegin, protlen);
|
||||
p += protlen;
|
||||
if (use_ocb)
|
||||
{
|
||||
*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);
|
||||
if (use_ocb)
|
||||
{
|
||||
gcry_cipher_final (hd);
|
||||
rc = gcry_cipher_encrypt (hd, outbuf, outlen, NULL, 0);
|
||||
if (!rc)
|
||||
@ -554,11 +496,6 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
|
||||
rc = gcry_cipher_gettag (hd, outbuf + outlen, 16);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = gcry_cipher_encrypt (hd, outbuf, enclen, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (rc)
|
||||
goto leave;
|
||||
@ -584,7 +521,7 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
|
||||
(int)strlen (modestr), modestr,
|
||||
&saltpos,
|
||||
(unsigned int)strlen (countbuf), countbuf,
|
||||
use_ocb? 12 : blklen, &ivpos, use_ocb? 12 : blklen, "",
|
||||
12, &ivpos, 12, "",
|
||||
enclen, &encpos, enclen, "");
|
||||
if (!p)
|
||||
{
|
||||
@ -598,7 +535,7 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
|
||||
*resultlen = strlen (p);
|
||||
*result = (unsigned char*)p;
|
||||
memcpy (p+saltpos, s2ksalt, 8);
|
||||
memcpy (p+ivpos, iv, use_ocb? 12 : blklen);
|
||||
memcpy (p+ivpos, iv, 12);
|
||||
memcpy (p+encpos, outbuf, enclen);
|
||||
xfree (iv);
|
||||
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
|
||||
a valid S-Exp here. With USE_UCB set to -1 the default scheme is
|
||||
used (ie. either CBC or OCB), set to 0 the old CBC mode is used,
|
||||
and set to 1 OCB is used. */
|
||||
* a valid S-Exp here. */
|
||||
int
|
||||
agent_protect (const unsigned char *plainkey, const char *passphrase,
|
||||
unsigned char **result, size_t *resultlen,
|
||||
unsigned long s2k_count, int use_ocb)
|
||||
unsigned long s2k_count)
|
||||
{
|
||||
int rc;
|
||||
const char *parmlist;
|
||||
@ -637,9 +572,6 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
|
||||
unsigned char *p;
|
||||
int have_curve = 0;
|
||||
|
||||
if (use_ocb == -1)
|
||||
use_ocb = !!opt.enable_extended_key_format;
|
||||
|
||||
/* Create an S-expression with the protected-at timestamp. */
|
||||
memcpy (timestamp_exp, "(12:protected-at15:", 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,
|
||||
prot_begin, prot_end - prot_begin + 1,
|
||||
passphrase, timestamp_exp, sizeof (timestamp_exp),
|
||||
&protected, &protectedlen, s2k_count, use_ocb);
|
||||
&protected, &protectedlen, s2k_count);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
@ -196,7 +196,7 @@ test_agent_protect (void)
|
||||
{
|
||||
ret = agent_protect ((const unsigned char*)specs[i].key,
|
||||
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)
|
||||
{
|
||||
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_NOT_ENABLED: ok = "disabled"; break;
|
||||
case GPG_ERR_NO_CRL_KNOWN:
|
||||
case GPG_ERR_INV_CRL_OBJ:
|
||||
ok = _("no CRL found for certificate");
|
||||
break;
|
||||
case GPG_ERR_CRL_TOO_OLD:
|
||||
|
@ -40,6 +40,7 @@
|
||||
|
||||
#include "util.h"
|
||||
#include "i18n.h"
|
||||
#include "tlv.h"
|
||||
#include "ksba-io-support.h"
|
||||
|
||||
|
||||
@ -65,6 +66,12 @@ struct reader_cb_parm_s
|
||||
int autodetect; /* Try to detect the input encoding. */
|
||||
int assume_pem; /* Assume input encoding is PEM. */
|
||||
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 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
|
||||
simple_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
|
||||
@ -402,8 +458,54 @@ simple_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
|
||||
if (!buffer)
|
||||
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++)
|
||||
{
|
||||
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)
|
||||
{
|
||||
@ -417,6 +519,7 @@ simple_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
|
||||
*(byte *)buffer++ = c;
|
||||
}
|
||||
|
||||
leave:
|
||||
*nread = n;
|
||||
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
|
||||
* ksba_reader_clear after EOF until no more
|
||||
* 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
|
||||
* 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)
|
||||
return out_of_core ();
|
||||
(*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);
|
||||
if (rc)
|
||||
|
@ -36,6 +36,7 @@
|
||||
#define GNUPG_KSBA_IO_BASE64 2 /* Plain Base64 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_STRIP 16 /* Strip off zero padding. */
|
||||
|
||||
|
||||
/* Context object. */
|
||||
|
@ -48,6 +48,8 @@ static struct {
|
||||
|
||||
{ "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 },
|
||||
{ "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 },
|
||||
{ "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[] =
|
||||
{ 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[] =
|
||||
{ 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. */
|
||||
/*
|
||||
@ -321,8 +327,12 @@ openpgp_oid_to_str (gcry_mpi_t a)
|
||||
int
|
||||
openpgp_oidbuf_is_ed25519 (const void *buf, size_t len)
|
||||
{
|
||||
return (buf && len == DIM (oid_ed25519)
|
||||
&& !memcmp (buf, oid_ed25519, DIM (oid_ed25519)));
|
||||
if (!buf)
|
||||
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
|
||||
openpgp_oidbuf_is_cv25519 (const void *buf, size_t len)
|
||||
{
|
||||
return (buf && len == DIM (oid_cv25519)
|
||||
&& !memcmp (buf, oid_cv25519, DIM (oid_cv25519)));
|
||||
if (!buf)
|
||||
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.
|
||||
* -t Do not trim leading and trailing spaces from VALUE.
|
||||
* 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
|
||||
* EXPR
|
||||
@ -192,7 +193,7 @@ find_next_lc (char *string)
|
||||
*
|
||||
* The caller must pass the address of a selector variable to this
|
||||
* 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.
|
||||
*/
|
||||
gpg_error_t
|
||||
|
@ -536,7 +536,8 @@ get_rsa_pk_from_canon_sexp (const unsigned char *keydata, size_t keydatalen,
|
||||
return err;
|
||||
if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
|
||||
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);
|
||||
if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
|
||||
return err;
|
||||
@ -1074,6 +1075,8 @@ pubkey_algo_string (gcry_sexp_t s_pkey, enum gcry_pk_algos *r_algoid)
|
||||
*r_algoid = 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)
|
||||
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_CERT_REVOKED: errstr = "4"; 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_NO_POLICY_MATCH: errstr = "8"; break;
|
||||
|
||||
|
@ -156,8 +156,7 @@ gpg_error_t
|
||||
parse_ber_header (unsigned char const **buffer, size_t *size,
|
||||
int *r_class, int *r_tag,
|
||||
int *r_constructed, int *r_ndef,
|
||||
size_t *r_length, size_t *r_nhdr)
|
||||
{
|
||||
size_t *r_length, size_t *r_nhdr){
|
||||
int c;
|
||||
unsigned long tag;
|
||||
const unsigned char *buf = *buffer;
|
||||
|
@ -58,6 +58,7 @@ endif
|
||||
noinst_HEADERS = dirmngr.h crlcache.h crlfetch.h misc.h
|
||||
|
||||
dirmngr_SOURCES = dirmngr.c dirmngr.h server.c crlcache.c crlfetch.c \
|
||||
fakecrl.c \
|
||||
certcache.c certcache.h \
|
||||
domaininfo.c \
|
||||
workqueue.c \
|
||||
|
@ -768,7 +768,7 @@ cert_cache_init (strlist_t hkp_cacerts)
|
||||
initialization_done = 1;
|
||||
release_cache_lock ();
|
||||
|
||||
cert_cache_print_stats ();
|
||||
cert_cache_print_stats (NULL);
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
void
|
||||
cert_cache_print_stats (void)
|
||||
cert_cache_print_stats (ctrl_t ctrl)
|
||||
{
|
||||
cert_item_t ci;
|
||||
int idx;
|
||||
@ -848,11 +848,14 @@ cert_cache_print_stats (void)
|
||||
|
||||
release_cache_lock ();
|
||||
|
||||
log_info (_("permanently loaded certificates: %u\n"),
|
||||
dirmngr_status_helpf (ctrl,
|
||||
_("permanently loaded certificates: %u\n"),
|
||||
n_permanent);
|
||||
log_info (_(" runtime cached certificates: %u\n"),
|
||||
dirmngr_status_helpf (ctrl,
|
||||
_(" runtime cached certificates: %u\n"),
|
||||
n_nonperm);
|
||||
log_info (_(" trusted certificates: %u (%u,%u,%u,%u)\n"),
|
||||
dirmngr_status_helpf (ctrl,
|
||||
_(" trusted certificates: %u (%u,%u,%u,%u)\n"),
|
||||
n_trusted,
|
||||
n_trustclass_system,
|
||||
n_trustclass_config,
|
||||
|
@ -37,7 +37,7 @@ void cert_cache_init (strlist_t hkp_cacerts);
|
||||
void cert_cache_deinit (int full);
|
||||
|
||||
/* 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. */
|
||||
int cert_cache_any_in_class (unsigned int mask);
|
||||
|
@ -125,6 +125,13 @@
|
||||
# define O_BINARY 0
|
||||
#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_issuingDistributionPoint[] = "2.5.29.28"; */
|
||||
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_lru_count; /* Used for LRU purposes. */
|
||||
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')
|
||||
{
|
||||
entry->invalid = atoi (line+1);
|
||||
if (entry->invalid < 1)
|
||||
entry->invalid = 1;
|
||||
if (!entry->invalid)
|
||||
entry->invalid = INVCRL_GENERAL;
|
||||
}
|
||||
else if (*line == 'u')
|
||||
entry->user_trust_req = 1;
|
||||
@ -1395,7 +1402,7 @@ cache_isvalid (ctrl_t ctrl, const char *issuer_hash,
|
||||
{
|
||||
if (opt.verbose)
|
||||
log_info ("no system trust and client does not trust either\n");
|
||||
retval = CRL_CACHE_CANTUSE;
|
||||
retval = CRL_CACHE_NOTTRUSTED;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1515,8 +1522,11 @@ crl_cache_cert_isvalid (ctrl_t ctrl, ksba_cert_t cert,
|
||||
case CRL_CACHE_DONTKNOW:
|
||||
err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
|
||||
break;
|
||||
case CRL_CACHE_NOTTRUSTED:
|
||||
err = gpg_error (GPG_ERR_NOT_TRUSTED);
|
||||
break;
|
||||
case CRL_CACHE_CANTUSE:
|
||||
err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
|
||||
err = gpg_error (GPG_ERR_INV_CRL_OBJ);
|
||||
break;
|
||||
default:
|
||||
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);
|
||||
assert (!err);
|
||||
log_assert (!err);
|
||||
|
||||
|
||||
failure:
|
||||
@ -2338,7 +2348,7 @@ crl_cache_insert (ctrl_t ctrl, const char *url, ksba_reader_t reader)
|
||||
nextupdate);
|
||||
if (!err2)
|
||||
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);
|
||||
if (!err2)
|
||||
err2 = gpg_error (GPG_ERR_INV_CRL);
|
||||
invalidate_crl |= 2;
|
||||
invalidate_crl |= INVCRL_UNKNOWN_EXTN;
|
||||
}
|
||||
if (gpg_err_code (err) == GPG_ERR_EOF
|
||||
|| 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 warn = 0;
|
||||
const unsigned char *s;
|
||||
unsigned int invalid;
|
||||
|
||||
es_fputs ("--------------------------------------------------------\n", fp );
|
||||
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->check_trust_anchor? e->check_trust_anchor:"[missing]");
|
||||
|
||||
if ((e->invalid & 1))
|
||||
invalid = e->invalid;
|
||||
if ((invalid & INVCRL_TOO_OLD))
|
||||
{
|
||||
invalid &= ~INVCRL_TOO_OLD;
|
||||
es_fprintf (fp, _(" ERROR: The CRL will not be used "
|
||||
"because it was still too old after an update!\n"));
|
||||
if ((e->invalid & 2))
|
||||
}
|
||||
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"));
|
||||
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"));
|
||||
|
||||
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;
|
||||
|
||||
if (opt.verbose)
|
||||
log_info ("fetching CRL from '%s'\n", distpoint_uri);
|
||||
crl_close_reader (reader);
|
||||
err = crl_fetch (ctrl, distpoint_uri, &reader);
|
||||
if (err)
|
||||
|
@ -27,6 +27,7 @@ typedef enum
|
||||
CRL_CACHE_VALID = 0,
|
||||
CRL_CACHE_INVALID,
|
||||
CRL_CACHE_DONTKNOW,
|
||||
CRL_CACHE_NOTTRUSTED,
|
||||
CRL_CACHE_CANTUSE
|
||||
}
|
||||
crl_cache_result_t;
|
||||
@ -44,6 +45,7 @@ crl_sig_result_t;
|
||||
struct crl_cache_entry_s;
|
||||
typedef struct crl_cache_entry_s *crl_cache_entry_t;
|
||||
|
||||
/*-- crlcache.c --*/
|
||||
|
||||
void crl_cache_init (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);
|
||||
|
||||
|
||||
/*-- fakecrl.c --*/
|
||||
crl_cache_result_t fakecrl_isvalid (ctrl_t ctrl,
|
||||
const char *issuer_hash,
|
||||
const char *cert_id);
|
||||
|
||||
|
||||
|
||||
#endif /* CRLCACHE_H */
|
||||
|
@ -175,6 +175,9 @@ crl_fetch (ctrl_t ctrl, const char *url, ksba_reader_t *reader)
|
||||
if (!url)
|
||||
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);
|
||||
http_release_parsed_uri (uri);
|
||||
if (!err) /* Yes, our HTTP code groks that. */
|
||||
|
@ -158,6 +158,7 @@ enum cmd_and_opt_values {
|
||||
oConnectTimeout,
|
||||
oConnectQuickTimeout,
|
||||
oListenBacklog,
|
||||
oFakeCRL,
|
||||
aTest
|
||||
};
|
||||
|
||||
@ -274,7 +275,7 @@ static gpgrt_opt_t opts[] = {
|
||||
" points to serverlist")),
|
||||
ARGPARSE_s_i (oLDAPTimeout, "ldaptimeout",
|
||||
N_("|N|set LDAP timeout to N seconds")),
|
||||
|
||||
ARGPARSE_s_s (oFakeCRL, "fake-crl", "@"),
|
||||
|
||||
ARGPARSE_header ("OCSP", N_("Configuration for OCSP")),
|
||||
|
||||
@ -324,6 +325,7 @@ static struct debug_flags_s debug_flags [] =
|
||||
{ DBG_NETWORK_VALUE, "network" },
|
||||
{ DBG_LOOKUP_VALUE , "lookup" },
|
||||
{ DBG_EXTPROG_VALUE, "extprog" },
|
||||
{ DBG_KEEPTMP_VALUE, "keeptmp" },
|
||||
{ 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
|
||||
disk with debug files which may reveal confidential data. */
|
||||
if (numok)
|
||||
opt.debug &= ~(DBG_HASHING_VALUE);
|
||||
opt.debug &= ~(DBG_HASHING_VALUE|DBG_KEEPTMP_VALUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -708,6 +710,8 @@ parse_rereadable_options (gpgrt_argparse_t *pargs, int reread)
|
||||
opt.ldaptimeout = DEFAULT_LDAP_TIMEOUT;
|
||||
ldapserver_list_needs_reset = 1;
|
||||
opt.debug_cache_expired_certs = 0;
|
||||
xfree (opt.fake_crl);
|
||||
opt.fake_crl = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -870,6 +874,11 @@ parse_rereadable_options (gpgrt_argparse_t *pargs, int reread)
|
||||
opt.debug_cache_expired_certs = 0;
|
||||
break;
|
||||
|
||||
case oFakeCRL:
|
||||
xfree (opt.fake_crl);
|
||||
opt.fake_crl = *pargs->r.ret_str? xstrdup (pargs->r.ret_str) : NULL;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0; /* Not handled. */
|
||||
}
|
||||
@ -2030,8 +2039,9 @@ handle_signal (int signo)
|
||||
break;
|
||||
|
||||
case SIGUSR1:
|
||||
cert_cache_print_stats ();
|
||||
domaininfo_print_stats ();
|
||||
/* See also cmd_getinfo:"stats". */
|
||||
cert_cache_print_stats (NULL);
|
||||
domaininfo_print_stats (NULL);
|
||||
break;
|
||||
|
||||
case SIGUSR2:
|
||||
|
@ -104,6 +104,7 @@ struct
|
||||
|
||||
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_quick_timeout; /* Shorter timeout for connect. */
|
||||
@ -166,6 +167,7 @@ struct
|
||||
#define DBG_NETWORK_VALUE 2048 /* debug network I/O. */
|
||||
#define DBG_LOOKUP_VALUE 8192 /* debug lookup details */
|
||||
#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_CRYPTO (opt.debug & DBG_CRYPTO_VALUE)
|
||||
@ -177,6 +179,7 @@ struct
|
||||
#define DBG_NETWORK (opt.debug & DBG_NETWORK_VALUE)
|
||||
#define DBG_LOOKUP (opt.debug & DBG_LOOKUP_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
|
||||
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 --*/
|
||||
void domaininfo_print_stats (void);
|
||||
void domaininfo_print_stats (ctrl_t ctrl);
|
||||
int domaininfo_is_wkd_not_supported (const char *domain);
|
||||
void domaininfo_set_no_name (const char *domain);
|
||||
void domaininfo_set_wkd_supported (const char *domain);
|
||||
|
@ -81,7 +81,7 @@ hash_domain (const char *domain)
|
||||
|
||||
|
||||
void
|
||||
domaininfo_print_stats (void)
|
||||
domaininfo_print_stats (ctrl_t ctrl)
|
||||
{
|
||||
int bidx;
|
||||
domaininfo_t di;
|
||||
@ -112,7 +112,8 @@ domaininfo_print_stats (void)
|
||||
if (minlen == -1 || len < minlen)
|
||||
minlen = len;
|
||||
}
|
||||
log_info ("domaininfo: items=%d chainlen=%d..%d nn=%d nf=%d ns=%d s=%d\n",
|
||||
dirmngr_status_helpf
|
||||
(ctrl, "domaininfo: items=%d chainlen=%d..%d nn=%d nf=%d ns=%d s=%d\n",
|
||||
count,
|
||||
minlen > 0? minlen : 0,
|
||||
maxlen,
|
||||
|
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
|
||||
* 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. */
|
||||
if (extfilt_need_escape (pattern)
|
||||
&& !(pattern = pattern_buffer = extfilt_escape (pattern)))
|
||||
|
@ -1339,6 +1339,10 @@ cmd_isvalid (assuan_context_t ctx, char *line)
|
||||
}
|
||||
else if (only_ocsp)
|
||||
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
|
||||
{
|
||||
switch (crl_cache_isvalid (ctrl,
|
||||
@ -1360,8 +1364,11 @@ cmd_isvalid (assuan_context_t ctx, char *line)
|
||||
goto again;
|
||||
}
|
||||
break;
|
||||
case CRL_CACHE_NOTTRUSTED:
|
||||
err = gpg_error (GPG_ERR_NOT_TRUSTED);
|
||||
break;
|
||||
case CRL_CACHE_CANTUSE:
|
||||
err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
|
||||
err = gpg_error (GPG_ERR_INV_CRL_OBJ);
|
||||
break;
|
||||
default:
|
||||
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,
|
||||
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
|
||||
message if it does not and returns NULL. Fingerprints are
|
||||
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;
|
||||
}
|
||||
|
||||
assert (cert);
|
||||
log_assert (cert);
|
||||
|
||||
err = crl_cache_cert_isvalid (ctrl, cert, ctrl->force_crl_refresh);
|
||||
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"
|
||||
"Supported values of WHAT are:\n"
|
||||
"\n"
|
||||
"version - Return the version of the program.\n"
|
||||
"pid - Return the process id of the server.\n"
|
||||
"version - Return the version of the program\n"
|
||||
"pid - Return the process id of the server\n"
|
||||
"tor - Return OK if running in Tor mode\n"
|
||||
"dnsinfo - Return info about the DNS resolver\n"
|
||||
"socket_name - Return the name of the socket.\n"
|
||||
"session_id - Return the current session_id.\n"
|
||||
"socket_name - Return the name of the socket\n"
|
||||
"session_id - Return the current session_id\n"
|
||||
"workqueue - Inspect the work queue\n"
|
||||
"stats - Print stats\n"
|
||||
"getenv NAME - Return value of envvar NAME\n";
|
||||
static gpg_error_t
|
||||
cmd_getinfo (assuan_context_t ctx, char *line)
|
||||
@ -2860,6 +2868,12 @@ cmd_getinfo (assuan_context_t ctx, char *line)
|
||||
workqueue_dump_queue (ctrl);
|
||||
err = 0;
|
||||
}
|
||||
else if (!strcmp (line, "stats"))
|
||||
{
|
||||
cert_cache_print_stats (ctrl);
|
||||
domaininfo_print_stats (ctrl);
|
||||
err = 0;
|
||||
}
|
||||
else if (!strncmp (line, "getenv", 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
|
||||
* splits text at LFs. */
|
||||
* splits text at LFs. With CTRL beeing NULL, the function behaves
|
||||
* like log_info. */
|
||||
gpg_error_t
|
||||
dirmngr_status_helpf (ctrl_t ctrl, const char *format, ...)
|
||||
{
|
||||
@ -3227,12 +3242,20 @@ dirmngr_status_helpf (ctrl_t ctrl, const char *format, ...)
|
||||
char *buf;
|
||||
|
||||
va_start (arg_ptr, format);
|
||||
if (ctrl)
|
||||
{
|
||||
buf = es_vbsprintf (format, arg_ptr);
|
||||
err = buf? 0 : gpg_error_from_syserror ();
|
||||
va_end (arg_ptr);
|
||||
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);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -255,6 +255,7 @@ check_revocations (ctrl_t ctrl, chain_item_t chain)
|
||||
int any_revoked = 0;
|
||||
int any_no_crl = 0;
|
||||
int any_crl_too_old = 0;
|
||||
int any_not_trusted = 0;
|
||||
chain_item_t ci;
|
||||
|
||||
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);
|
||||
}
|
||||
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)
|
||||
{
|
||||
@ -293,17 +295,19 @@ check_revocations (ctrl_t ctrl, chain_item_t chain)
|
||||
if (!err)
|
||||
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))
|
||||
{
|
||||
case 0: 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_NOT_TRUSTED: any_not_trusted = 1; err = 0; break;
|
||||
case GPG_ERR_CRL_TOO_OLD: any_crl_too_old = 1; err = 0; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
ctrl->check_revocations_nest_level--;
|
||||
|
||||
|
||||
if (err)
|
||||
;
|
||||
@ -311,10 +315,16 @@ check_revocations (ctrl_t ctrl, chain_item_t chain)
|
||||
err = gpg_error (GPG_ERR_CERT_REVOKED);
|
||||
else if (any_no_crl)
|
||||
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)
|
||||
err = gpg_error (GPG_ERR_CRL_TOO_OLD);
|
||||
else
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -59,7 +59,7 @@ workqueue_dump_queue (ctrl_t ctrl)
|
||||
wqitem_t item;
|
||||
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. */
|
||||
saved_workqueue = workqueue;
|
||||
workqueue = NULL;
|
||||
@ -74,8 +74,8 @@ workqueue_dump_queue (ctrl_t ctrl)
|
||||
item->func? item->func (NULL, NULL): "nop",
|
||||
item->args, strlen (item->args) > 100? "[...]":"");
|
||||
|
||||
/* Restore then workqueue. Actually we append the saved queue do a
|
||||
* possibly updated workqueue. */
|
||||
/* Restore the workqueue. Actually we append the saved queue to
|
||||
* handle a possibly updated workqueue. */
|
||||
if (!(item=workqueue))
|
||||
workqueue = saved_workqueue;
|
||||
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
|
||||
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
|
||||
*** SIGEXPIRED
|
||||
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-5958 :: Asymmetric Key Packages
|
||||
- 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-8351 :: The PKCS #8 EncryptedPrivateKeyInfo Media Type
|
||||
- RFC-8550 :: S/MIME Version 4.0 Certificate Handling
|
||||
- RFC-8551 :: S/MIME Version 4.0 Message Specification
|
||||
- RFC-2634 :: Enhanced Security Services for S/MIME
|
||||
- RFC-5035 :: Enhanced Security Services (ESS) Update
|
||||
- RFC-7253 :: The OCB Authenticated-Encryption Algorithm
|
||||
|
||||
- draft-koch-openpgp-2015-rfc4880bis :: Updates to RFC-4880
|
||||
|
||||
- T6390 :: Notes on use of X25519 in GnuPG (https://dev.gnupg.org/T6390)
|
||||
|
||||
|
||||
** v3 fingerprints
|
||||
For packet version 3 we calculate the keyids this way:
|
||||
- RSA :: Low 64 bits of n
|
||||
@ -1724,17 +1741,10 @@ Description of some debug flags:
|
||||
|
||||
** gnupg.org notations
|
||||
|
||||
- adsk@gnupg.org :: Additional decryption subkey. This notation
|
||||
gives a list of keys an implementation SHOULD
|
||||
also encrypt to. The data consists of an array
|
||||
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.
|
||||
- rem@gnupg.org :: Used by Kleopatra to implement the tag feature.
|
||||
These tags are used to mark keys for easier
|
||||
searching and grouping.
|
||||
|
||||
|
||||
** Simplified revocation certificates
|
||||
Revocation certificates consist only of the signature packet;
|
||||
|
@ -615,15 +615,11 @@ remote machine.
|
||||
@itemx --disable-extended-key-format
|
||||
@opindex enable-extended-key-format
|
||||
@opindex disable-extended-key-format
|
||||
Since version 2.3 keys are created in the extended private key format.
|
||||
Changing the passphrase of a key will also convert the key to that new
|
||||
format. This new key format is supported since GnuPG version 2.1.12
|
||||
and thus there should be no need to disable it. The disable option
|
||||
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.
|
||||
These options are obsolete and have no effect. The extended key format
|
||||
is used for years now and has been supported since 2.1.12. Existing
|
||||
keys in the old format are migrated to the new format as soon as they
|
||||
are touched.
|
||||
|
||||
|
||||
@anchor{option --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
|
||||
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
|
||||
@opindex keyedit:passwd
|
||||
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
|
||||
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}
|
||||
@opindex attribute-fd
|
||||
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}.
|
||||
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
|
||||
|
||||
|
||||
@ -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
|
||||
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
|
||||
will not have on your local keybox), the operator can tell both your IP
|
||||
address and the time when you verified the signature.
|
||||
will not have on your local keybox), the operator can tell both your
|
||||
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}
|
||||
@ -623,6 +629,15 @@ always listed in @option{--with-colons} mode.
|
||||
Include info about the presence of a secret key in public key listings
|
||||
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
|
||||
|
||||
@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.
|
||||
* 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?
|
||||
*/
|
||||
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;
|
||||
byte buf[1+MAX_FINGERPRINT_LEN];
|
||||
size_t fprlen;
|
||||
|
||||
/* For v4 keys we need to write the ISSUER subpacket. We do not
|
||||
* want that for a future v5 format. */
|
||||
if (pksk->version < 5)
|
||||
* want that for a future v5 format. We also don't write it if
|
||||
* 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];
|
||||
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
|
||||
carry the serialno stuff instead of the actual secret key
|
||||
parameters. USE is the usage for that key; 0 means any
|
||||
usage. */
|
||||
/* Store the key at NODE into the smartcard and modify NODE to carry
|
||||
the serialno stuff instead of the actual secret key parameters.
|
||||
USE is the usage for that key; 0 means any usage. If
|
||||
PROCESSED_KEYS is not NULL it is a poiter to an strlist which will
|
||||
be filled with the keygrips of successfully stored keys. */
|
||||
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;
|
||||
int okay = 0;
|
||||
@ -1875,7 +1876,11 @@ card_store_subkey (KBNODE node, int use)
|
||||
if (rc)
|
||||
log_error (_("KEYTOCARD failed: %s\n"), gpg_strerror (rc));
|
||||
else
|
||||
{
|
||||
okay = 1;
|
||||
if (processed_keys)
|
||||
add_to_strlist (processed_keys, hexgrip);
|
||||
}
|
||||
xfree (hexgrip);
|
||||
|
||||
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
|
||||
structure. If S has seckret key infos, only the public stuff is
|
||||
copied. */
|
||||
* structure. Only the basic stuff is copied; not any ancillary
|
||||
* data. */
|
||||
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;
|
||||
|
||||
@ -222,8 +222,8 @@ copy_public_key (PKT_public_key *d, PKT_public_key *s)
|
||||
d = xmalloc (sizeof *d);
|
||||
memcpy (d, s, sizeof *d);
|
||||
d->seckey_info = NULL;
|
||||
d->user_id = scopy_user_id (s->user_id);
|
||||
d->prefs = copy_prefs (s->prefs);
|
||||
d->user_id = NULL;
|
||||
d->prefs = NULL;
|
||||
|
||||
n = pubkey_get_npkey (s->pubkey_algo);
|
||||
i = 0;
|
||||
@ -237,6 +237,24 @@ copy_public_key (PKT_public_key *d, PKT_public_key *s)
|
||||
for (; i < PUBKEY_MAX_NSKEY; i++)
|
||||
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)
|
||||
BUG();
|
||||
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);
|
||||
memcpy(d->revkey,s->revkey,sizeof(struct revocation_key)*s->numrevkeys);
|
||||
}
|
||||
else
|
||||
d->revkey = NULL;
|
||||
|
||||
if (s->serialno)
|
||||
d->serialno = xstrdup (s->serialno);
|
||||
|
19
g10/getkey.c
19
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
|
||||
* 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
|
||||
* 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).
|
||||
*/
|
||||
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;
|
||||
kbnode_t keyblock;
|
||||
kbnode_t found_key;
|
||||
unsigned int infoflags;
|
||||
|
||||
if (r_keyblock)
|
||||
*r_keyblock = NULL;
|
||||
|
||||
err = read_key_from_file_or_buffer (ctrl, fname, NULL, 0, &keyblock);
|
||||
if (!err)
|
||||
{
|
||||
@ -1747,6 +1752,9 @@ get_pubkey_fromfile (ctrl_t ctrl, PKT_public_key *pk, const char *fname)
|
||||
err = gpg_error (GPG_ERR_UNUSABLE_PUBKEY);
|
||||
}
|
||||
|
||||
if (!err && r_keyblock)
|
||||
*r_keyblock = keyblock;
|
||||
else
|
||||
release_kbnode (keyblock);
|
||||
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.
|
||||
* Note: The self-signed data has already been merged into the public
|
||||
* 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)
|
||||
* and then xfree(PK)).
|
||||
*
|
||||
* 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
|
||||
* 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)
|
||||
{
|
||||
int key_usage = 0;
|
||||
|
@ -337,6 +337,7 @@ enum cmd_and_opt_values
|
||||
oEncryptToDefaultKey,
|
||||
oLoggerFD,
|
||||
oLoggerFile,
|
||||
oLogTime,
|
||||
oUtf8Strings,
|
||||
oNoUtf8Strings,
|
||||
oDisableCipherAlgo,
|
||||
@ -600,6 +601,7 @@ static gpgrt_opt_t opts[] = {
|
||||
ARGPARSE_s_s (oLoggerFile, "log-file",
|
||||
N_("|FILE|write server mode logs to FILE")),
|
||||
ARGPARSE_s_s (oLoggerFile, "logger-file", "@"), /* 1.4 compatibility. */
|
||||
ARGPARSE_s_n (oLogTime, "log-time", "@"),
|
||||
ARGPARSE_s_n (oQuickRandom, "debug-quick-random", "@"),
|
||||
|
||||
|
||||
@ -1041,6 +1043,7 @@ static int utf8_strings =
|
||||
static int maybe_setuid = 1;
|
||||
static unsigned int opt_set_iobuf_size;
|
||||
static unsigned int opt_set_iobuf_size_used;
|
||||
static int opt_log_time;
|
||||
|
||||
/* Collection of options used only in this module. */
|
||||
static struct {
|
||||
@ -2864,6 +2867,9 @@ main (int argc, char **argv)
|
||||
case oLoggerFile:
|
||||
logfile = pargs.r.ret_str;
|
||||
break;
|
||||
case oLogTime:
|
||||
opt_log_time = 1;
|
||||
break;
|
||||
|
||||
case oWithFingerprint:
|
||||
opt.with_fingerprint = 1;
|
||||
@ -3829,6 +3835,9 @@ main (int argc, char **argv)
|
||||
| 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 (opt.verbose > 2)
|
||||
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. */
|
||||
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. */
|
||||
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. */
|
||||
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_long_user_id_string (ctrl_t ctrl, u32 *keyid);
|
||||
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
|
||||
* Copyright (C) 1998-2010 Free Software Foundation, Inc.
|
||||
* 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.
|
||||
*
|
||||
@ -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 void menu_delkey (KBNODE pub_keyblock);
|
||||
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,
|
||||
int unattended, u32 newexpiration);
|
||||
static int menu_changeusage (ctrl_t ctrl, kbnode_t keyblock);
|
||||
@ -1243,7 +1244,7 @@ enum cmdids
|
||||
cmdREVSIG, cmdREVKEY, cmdREVUID, cmdDELSIG, cmdPRIMARY, cmdDEBUG,
|
||||
cmdSAVE, cmdADDUID, cmdADDPHOTO, cmdDELUID, cmdADDKEY, cmdDELKEY,
|
||||
cmdADDREVOKER, cmdTOGGLE, cmdSELKEY, cmdPASSWD, cmdTRUST, cmdPREF,
|
||||
cmdEXPIRE, cmdCHANGEUSAGE, cmdBACKSIGN,
|
||||
cmdEXPIRE, cmdCHANGEUSAGE, cmdBACKSIGN, cmdADDADSK,
|
||||
#ifndef NO_TRUST_MODELS
|
||||
cmdENABLEKEY, cmdDISABLEKEY,
|
||||
#endif /*!NO_TRUST_MODELS*/
|
||||
@ -1308,6 +1309,8 @@ static struct
|
||||
{ "delkey", cmdDELKEY, 0, N_("delete selected subkeys")},
|
||||
{ "addrevoker", cmdADDREVOKER, KEYEDIT_NEED_SK,
|
||||
N_("add a revocation key")},
|
||||
{ "addadsk", cmdADDADSK, KEYEDIT_NEED_SK,
|
||||
N_("add additional decryption subkeys")},
|
||||
{ "delsig", cmdDELSIG, 0,
|
||||
N_("delete signatures from the selected user IDs")},
|
||||
{ "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 run_subkey_warnings = 0;
|
||||
int have_commands = !!commands;
|
||||
strlist_t delseckey_list = NULL;
|
||||
int delseckey_list_warn = 0;
|
||||
|
||||
if (opt.command_fd != -1)
|
||||
;
|
||||
@ -1497,6 +1502,14 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
|
||||
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
|
||||
{
|
||||
xfree (answer);
|
||||
@ -1869,10 +1882,12 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
|
||||
if (node)
|
||||
{
|
||||
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;
|
||||
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;
|
||||
|
||||
/* 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;
|
||||
sec_shadowing = 1;
|
||||
@ -2000,6 +2015,15 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
|
||||
}
|
||||
break;
|
||||
|
||||
case cmdADDADSK:
|
||||
if (menu_addadsk (ctrl, keyblock))
|
||||
{
|
||||
redisplay = 1;
|
||||
modified = 1;
|
||||
merge_keys_and_selfsig (ctrl, keyblock);
|
||||
}
|
||||
break;
|
||||
|
||||
case cmdREVUID:
|
||||
{
|
||||
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)
|
||||
{
|
||||
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. */
|
||||
|
||||
leave:
|
||||
free_strlist (delseckey_list);
|
||||
release_kbnode (keyblock);
|
||||
keydb_release (kdbhd);
|
||||
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
|
||||
* menu option "expire". With UNATTENDED set to 1 this function only
|
||||
* sets the expiration date of the primary key to NEWEXPIRATION and
|
||||
|
35
g10/keygen.c
35
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
|
||||
* aeads is useless, given that we don't expects more than a very few
|
||||
* algorithms. */
|
||||
@ -256,12 +250,10 @@ write_uid (kbnode_t root, const char *s)
|
||||
static void
|
||||
do_add_key_flags (PKT_signature *sig, unsigned int use)
|
||||
{
|
||||
byte buf[1];
|
||||
|
||||
buf[0] = 0;
|
||||
byte buf[2] = { 0, 0 };
|
||||
|
||||
/* The spec says that all primary keys MUST be able to certify. */
|
||||
if(sig->sig_class!=0x18)
|
||||
if ( sig->sig_class != 0x18 )
|
||||
buf[0] |= 0x01;
|
||||
|
||||
if (use & PUBKEY_USAGE_SIG)
|
||||
@ -270,8 +262,15 @@ do_add_key_flags (PKT_signature *sig, unsigned int use)
|
||||
buf[0] |= 0x04 | 0x08;
|
||||
if (use & PUBKEY_USAGE_AUTH)
|
||||
buf[0] |= 0x20;
|
||||
if (use & PUBKEY_USAGE_GROUP)
|
||||
buf[0] |= 0x80;
|
||||
|
||||
build_sig_subpkt (sig, SIGSUBPKT_KEY_FLAGS, buf, 1);
|
||||
if (use & PUBKEY_USAGE_RENC)
|
||||
buf[1] |= 0x04;
|
||||
if (use & PUBKEY_USAGE_TIME)
|
||||
buf[1] |= 0x08;
|
||||
|
||||
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)
|
||||
{
|
||||
struct opaque_data_usage_and_pk *oduap = opaque;
|
||||
|
||||
do_add_key_flags (sig, oduap->usage);
|
||||
return keygen_add_key_expire (sig, oduap->pk);
|
||||
keygen_add_key_flags (sig, opaque);
|
||||
return keygen_add_key_expire (sig, opaque);
|
||||
}
|
||||
|
||||
|
||||
@ -1215,7 +1212,6 @@ write_keybinding (ctrl_t ctrl, kbnode_t root,
|
||||
PKT_signature *sig;
|
||||
KBNODE node;
|
||||
PKT_public_key *pri_pk, *sub_pk;
|
||||
struct opaque_data_usage_and_pk oduap;
|
||||
|
||||
if (opt.verbose)
|
||||
log_info(_("writing key binding signature\n"));
|
||||
@ -1241,11 +1237,10 @@ write_keybinding (ctrl_t ctrl, kbnode_t root,
|
||||
BUG();
|
||||
|
||||
/* Make the signature. */
|
||||
oduap.usage = use;
|
||||
oduap.pk = sub_pk;
|
||||
sub_pk->pubkey_usage = use;
|
||||
err = make_keysig_packet (ctrl, &sig, pri_pk, NULL, sub_pk, pri_psk, 0x18,
|
||||
timestamp, 0,
|
||||
keygen_add_key_flags_and_expire, &oduap,
|
||||
keygen_add_key_flags_and_expire, sub_pk,
|
||||
cache_nonce);
|
||||
if (err)
|
||||
{
|
||||
|
@ -315,6 +315,7 @@ int keygen_set_std_prefs (const char *string,int personal);
|
||||
PKT_user_id *keygen_get_std_prefs (void);
|
||||
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_and_expire (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_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_edit (ctrl_t ctrl, strlist_t commands);
|
||||
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
|
||||
|
||||
/*-- migrate.c --*/
|
||||
|
@ -777,21 +777,21 @@ openpgp_pk_algo_usage ( int algo )
|
||||
switch ( algo ) {
|
||||
case PUBKEY_ALGO_RSA:
|
||||
use = (PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG
|
||||
| PUBKEY_USAGE_ENC | PUBKEY_USAGE_AUTH);
|
||||
| PUBKEY_USAGE_ENC | PUBKEY_USAGE_RENC | PUBKEY_USAGE_AUTH);
|
||||
break;
|
||||
case PUBKEY_ALGO_RSA_E:
|
||||
case PUBKEY_ALGO_ECDH:
|
||||
use = PUBKEY_USAGE_ENC;
|
||||
use = PUBKEY_USAGE_ENC | PUBKEY_USAGE_RENC;
|
||||
break;
|
||||
case PUBKEY_ALGO_RSA_S:
|
||||
use = PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG;
|
||||
break;
|
||||
case PUBKEY_ALGO_ELGAMAL:
|
||||
if (RFC2440)
|
||||
use = PUBKEY_USAGE_ENC;
|
||||
use = PUBKEY_USAGE_ENC | PUBKEY_USAGE_RENC;
|
||||
break;
|
||||
case PUBKEY_ALGO_ELGAMAL_E:
|
||||
use = PUBKEY_USAGE_ENC;
|
||||
use = PUBKEY_USAGE_ENC | PUBKEY_USAGE_RENC;
|
||||
break;
|
||||
case PUBKEY_ALGO_DSA:
|
||||
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
|
||||
# error Please choose another value for PUBKEY_USAGE_NONE
|
||||
#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_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. */
|
||||
#define is_RSA(a) ((a)==PUBKEY_ALGO_RSA || (a)==PUBKEY_ALGO_RSA_E \
|
||||
@ -287,7 +293,7 @@ typedef struct
|
||||
/* The length of ATTRIB_DATA. */
|
||||
unsigned long attrib_len;
|
||||
byte *namehash;
|
||||
int help_key_usage;
|
||||
u16 help_key_usage;
|
||||
u32 help_key_expire;
|
||||
int help_full_count;
|
||||
int help_marginal_count;
|
||||
@ -388,7 +394,7 @@ typedef struct
|
||||
byte selfsigversion; /* highest version of all of the self-sigs */
|
||||
/* The public key algorithm. (Serialized.) */
|
||||
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 fprlen; /* 0 or length of FPR. */
|
||||
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 );
|
||||
void build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type,
|
||||
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 );
|
||||
void build_attribute_subpkt(PKT_user_id *uid,byte type,
|
||||
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_packet (PACKET *pkt, parse_packet_ctx_t parsectx);
|
||||
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_signature *copy_signature( PKT_signature *d, PKT_signature *s );
|
||||
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;
|
||||
PKT_public_key *pk;
|
||||
KBNODE keyblock = NULL;
|
||||
kbnode_t keyblock = NULL;
|
||||
kbnode_t node;
|
||||
|
||||
if (!name || !*name)
|
||||
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;
|
||||
|
||||
if (from_file)
|
||||
rc = get_pubkey_fromfile (ctrl, pk, name);
|
||||
rc = get_pubkey_fromfile (ctrl, pk, name, &keyblock);
|
||||
else
|
||||
rc = get_best_pubkey_byname (ctrl, GET_PUBKEY_NORMAL,
|
||||
NULL, pk, name, &keyblock, 0);
|
||||
@ -895,10 +896,10 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
|
||||
int trustlevel;
|
||||
|
||||
trustlevel = get_validity (ctrl, keyblock, pk, pk->user_id, NULL, 1);
|
||||
release_kbnode (keyblock);
|
||||
if ( (trustlevel & TRUST_FLAG_DISABLED) )
|
||||
{
|
||||
/* Key has been disabled. */
|
||||
release_kbnode (keyblock);
|
||||
send_status_inv_recp (13, name);
|
||||
log_info (_("%s: skipped: public key is disabled\n"), name);
|
||||
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) )
|
||||
{
|
||||
/* We don't trust this key. */
|
||||
release_kbnode (keyblock);
|
||||
send_status_inv_recp (10, name);
|
||||
free_public_key (pk);
|
||||
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;
|
||||
|
||||
r = xtrymalloc (sizeof *r);
|
||||
if (!r)
|
||||
{
|
||||
rc = gpg_error_from_syserror ();
|
||||
free_public_key (pk);
|
||||
return rc;
|
||||
}
|
||||
r = xmalloc (sizeof *r);
|
||||
r->pk = pk;
|
||||
r->next = *pk_list_addr;
|
||||
r->flags = mark_hidden? 1:0;
|
||||
*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;
|
||||
}
|
||||
|
||||
|
@ -363,7 +363,8 @@ check_signature_metadata_validity (PKT_public_key *pk, PKT_signature *sig,
|
||||
if (r_revoked)
|
||||
*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;
|
||||
if ( d < 86400 )
|
||||
|
30
g10/sign.c
30
g10/sign.c
@ -50,11 +50,6 @@
|
||||
#endif
|
||||
|
||||
|
||||
/* Bitflags to convey hints on what kind of signayire is created. */
|
||||
#define SIGNHINT_KEYSIG 1
|
||||
#define SIGNHINT_SELFSIG 2
|
||||
|
||||
|
||||
/* Hack */
|
||||
static int recipient_digest_algo;
|
||||
|
||||
@ -416,7 +411,10 @@ do_sign (ctrl_t ctrl, PKT_public_key *pksk, PKT_signature *sig,
|
||||
byte *dp;
|
||||
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;
|
||||
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))
|
||||
BUG ();
|
||||
|
||||
build_sig_subpkt_from_sig (sig, pk);
|
||||
build_sig_subpkt_from_sig (sig, pk, 0);
|
||||
mk_notation_policy_etc (ctrl, sig, NULL, pk);
|
||||
if (opt.flags.include_key_block && IS_SIG (sig))
|
||||
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.
|
||||
*
|
||||
* 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"
|
||||
*
|
||||
* DURATION is the amount of time (in seconds) until the signature
|
||||
* 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,
|
||||
* and expire (if duration is not 0). Additional subpackets can be
|
||||
* 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_public_key (md, subpk);
|
||||
if ((subpk->pubkey_usage & PUBKEY_USAGE_RENC))
|
||||
signhints |= SIGNHINT_ADSK;
|
||||
}
|
||||
else if (sigclass != 0x1F && sigclass != 0x20)
|
||||
{
|
||||
@ -1852,7 +1852,7 @@ make_keysig_packet (ctrl_t ctrl,
|
||||
sig->expiredate = sig->timestamp + duration;
|
||||
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);
|
||||
|
||||
/* 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
|
||||
* duration of 1) since build-packet.c:build_sig_subpkt_from_sig
|
||||
* detects this case. */
|
||||
@ -1984,7 +1990,7 @@ update_keysig_packet (ctrl_t ctrl,
|
||||
* automagically lower any sig expiration dates to correctly
|
||||
* correspond to the differences in the timestamps (i.e. the
|
||||
* duration will shrink). */
|
||||
build_sig_subpkt_from_sig (sig, pksk);
|
||||
build_sig_subpkt_from_sig (sig, pksk, signhints);
|
||||
|
||||
if (mksubpkt)
|
||||
rc = (*mksubpkt)(sig, opaque);
|
||||
|
@ -207,6 +207,7 @@ be_is_x509_blob (const unsigned char *blob, size_t bloblen)
|
||||
* SEQUENCE SEQUENCE [0] INTEGER INTEGER
|
||||
* (tbs) (version) (s/n)
|
||||
*
|
||||
* Note that v0 certificates don't have an explict version number.
|
||||
*/
|
||||
|
||||
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))
|
||||
return 0; /* Not a proper BER object. */
|
||||
if (!(class == CLASS_CONTEXT && tag == 0 && cons))
|
||||
{
|
||||
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))
|
||||
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);
|
||||
keybuf = xtrymalloc (len);
|
||||
if (!data)
|
||||
if (!keybuf)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
gcry_sexp_release (s_pkey);
|
||||
@ -4824,6 +4824,7 @@ do_writekey (app_t app, ctrl_t ctrl,
|
||||
const unsigned char *buf, *tok;
|
||||
size_t buflen, toklen;
|
||||
int depth;
|
||||
char *algostr = NULL;
|
||||
|
||||
(void)ctrl;
|
||||
|
||||
@ -4866,17 +4867,41 @@ do_writekey (app_t app, ctrl_t ctrl,
|
||||
goto leave;
|
||||
if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
|
||||
goto leave;
|
||||
if (tok && toklen == 3 && memcmp ("rsa", tok, toklen) == 0)
|
||||
err = rsa_writekey (app, ctrl, pincb, pincb_arg, keyno, buf, buflen, depth);
|
||||
else if (tok && toklen == 3 && memcmp ("ecc", tok, toklen) == 0)
|
||||
err = ecc_writekey (app, ctrl, pincb, pincb_arg, keyno, buf, buflen, depth);
|
||||
|
||||
if (tok && toklen == 3 && (!memcmp ("rsa", tok, toklen)
|
||||
|| !memcmp ("ecc", tok, toklen)))
|
||||
{
|
||||
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
|
||||
{
|
||||
err = gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
leave:
|
||||
xfree (algostr);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -326,7 +326,7 @@ struct prkdf_object_s
|
||||
char *serial_number;
|
||||
|
||||
/* KDF/KEK parameter for OpenPGP's ECDH. First byte is zero if not
|
||||
* available. .*/
|
||||
* available. */
|
||||
unsigned char ecdh_kdf[4];
|
||||
|
||||
/* Length and allocated buffer with the Id of this object. */
|
||||
|
@ -362,7 +362,7 @@ inq_certificate (void *opaque, const char *line)
|
||||
}
|
||||
else
|
||||
{
|
||||
log_error ("unsupported inquiry '%s'\n", line);
|
||||
log_error ("unsupported certificate inquiry '%s'\n", line);
|
||||
return gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
|
||||
}
|
||||
|
||||
@ -386,8 +386,8 @@ inq_certificate (void *opaque, const char *line)
|
||||
int err;
|
||||
ksba_cert_t cert;
|
||||
|
||||
|
||||
err = gpgsm_find_cert (parm->ctrl, line, ski, &cert, 1);
|
||||
err = gpgsm_find_cert (parm->ctrl, line, ski, &cert,
|
||||
FIND_CERT_ALLOW_AMBIG|FIND_CERT_WITH_EPHEM);
|
||||
if (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_NO_CRL_KNOWN
|
||||
GPG_ERR_INV_CRL_OBJ
|
||||
GPG_ERR_CRL_TOO_OLD
|
||||
|
||||
Values for USE_OCSP:
|
||||
@ -1014,7 +1015,8 @@ run_command_inq_cb (void *opaque, const char *line)
|
||||
if (!*line)
|
||||
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)
|
||||
{
|
||||
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;
|
||||
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
|
||||
{
|
||||
log_error ("unsupported inquiry '%s'\n", line);
|
||||
log_error ("unsupported command inquiry '%s'\n", line);
|
||||
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
|
||||
{
|
||||
es_fflush (es_stdout);
|
||||
log_logv (is_error? GPGRT_LOGLVL_ERROR: GPGRT_LOGLVL_INFO,
|
||||
format, arg_ptr);
|
||||
log_printf ("\n");
|
||||
@ -1480,6 +1481,7 @@ ask_marktrusted (ctrl_t ctrl, ksba_cert_t cert, int listmode)
|
||||
int success = 0;
|
||||
|
||||
fpr = gpgsm_get_fingerprint_string (cert, GCRY_MD_SHA1);
|
||||
es_fflush (es_stdout);
|
||||
log_info (_("fingerprint=%s\n"), fpr? fpr : "?");
|
||||
xfree (fpr);
|
||||
|
||||
@ -2277,6 +2279,7 @@ gpgsm_basic_cert_check (ctrl_t ctrl, ksba_cert_t cert)
|
||||
{
|
||||
if (!opt.quiet)
|
||||
{
|
||||
es_fflush (es_stdout);
|
||||
log_info ("issuer certificate (#/");
|
||||
gpgsm_dump_string (issuer);
|
||||
log_printf (") not found\n");
|
||||
|
@ -728,6 +728,13 @@ gpgsm_es_print_name2 (estream_t fp, const char *name, int translate)
|
||||
void
|
||||
gpgsm_es_print_name (estream_t fp, const char *name)
|
||||
{
|
||||
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
|
||||
gpgsm_find_cert (ctrl_t ctrl,
|
||||
const char *name, ksba_sexp_t keyid, ksba_cert_t *r_cert,
|
||||
int allow_ambiguous)
|
||||
unsigned int flags)
|
||||
{
|
||||
int rc;
|
||||
KEYDB_SEARCH_DESC desc;
|
||||
KEYDB_HANDLE kh = NULL;
|
||||
int allow_ambiguous = (flags & FIND_CERT_ALLOW_AMBIG);
|
||||
|
||||
*r_cert = NULL;
|
||||
rc = classify_user_id (name, &desc, 0);
|
||||
@ -523,6 +524,9 @@ gpgsm_find_cert (ctrl_t ctrl,
|
||||
rc = gpg_error (GPG_ERR_ENOMEM);
|
||||
else
|
||||
{
|
||||
if ((flags & FIND_CERT_WITH_EPHEM))
|
||||
keydb_set_ephemeral (kh, 1);
|
||||
|
||||
nextone:
|
||||
rc = keydb_search (ctrl, kh, &desc, 1);
|
||||
if (!rc)
|
||||
|
17
sm/gpgsm.c
17
sm/gpgsm.c
@ -114,6 +114,7 @@ enum cmd_and_opt_values {
|
||||
oNoLogFile,
|
||||
oAuditLog,
|
||||
oHtmlAuditLog,
|
||||
oLogTime,
|
||||
|
||||
oEnableSpecialFilenames,
|
||||
|
||||
@ -169,6 +170,7 @@ enum cmd_and_opt_values {
|
||||
oWithKeyScreening,
|
||||
oAnswerYes,
|
||||
oAnswerNo,
|
||||
oNoPrettyDN,
|
||||
oKeyring,
|
||||
oDefaultKey,
|
||||
oDefRecipient,
|
||||
@ -288,6 +290,7 @@ static gpgrt_opt_t opts[] = {
|
||||
N_("|FILE|write server mode logs to FILE")),
|
||||
ARGPARSE_s_n (oNoLogFile, "no-log-file", "@"),
|
||||
ARGPARSE_s_i (oLoggerFD, "logger-fd", "@"),
|
||||
ARGPARSE_s_n (oLogTime, "log-time", "@"),
|
||||
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 (oWithSecret, "with-secret", "@"),
|
||||
ARGPARSE_s_n (oWithKeyScreening,"with-key-screening", "@"),
|
||||
|
||||
ARGPARSE_s_n (oNoPrettyDN, "no-pretty-dn", "@"),
|
||||
|
||||
|
||||
ARGPARSE_header ("Security", N_("Options controlling the security")),
|
||||
@ -499,6 +502,9 @@ static int maybe_setuid = 1;
|
||||
static const char *debug_level;
|
||||
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
|
||||
gpgconf-list because the variable will be changed by the command
|
||||
line option.
|
||||
@ -1247,6 +1253,7 @@ main ( int argc, char **argv)
|
||||
|
||||
case oLogFile: logfile = pargs.r.ret_str; break;
|
||||
case oNoLogFile: logfile = NULL; break;
|
||||
case oLogTime: opt_log_time = 1; break;
|
||||
|
||||
case oAuditLog: auditlog = 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;
|
||||
break;
|
||||
|
||||
case oNoPrettyDN:
|
||||
opt.no_pretty_dn = 1;
|
||||
break;
|
||||
|
||||
case oHomedir: gnupg_set_homedir (pargs.r.ret_str); break;
|
||||
case oChUid: break; /* Command line only (see above). */
|
||||
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_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 ())
|
||||
{
|
||||
|
@ -85,6 +85,8 @@ struct
|
||||
|
||||
int with_key_screening; /* Option --with-key-screening active. */
|
||||
|
||||
int no_pretty_dn; /* Option --no-pretty-dn */
|
||||
|
||||
int pinentry_mode;
|
||||
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,
|
||||
certlist_t *listaddr, int is_encrypt_to);
|
||||
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,
|
||||
ksba_cert_t *r_cert, int allow_ambiguous);
|
||||
ksba_cert_t *r_cert, unsigned int flags);
|
||||
|
||||
/*-- keylist.c --*/
|
||||
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;
|
||||
const char *algoid;
|
||||
int algo;
|
||||
int is_detached;
|
||||
int is_detached, maybe_detached;
|
||||
estream_t in_fp = NULL;
|
||||
char *p;
|
||||
|
||||
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);
|
||||
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
|
||||
(&b64reader, ((ctrl->is_pem? GNUPG_KSBA_IO_PEM : 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);
|
||||
if (rc)
|
||||
{
|
||||
|
@ -1509,6 +1509,11 @@ show_configs (estream_t outfp)
|
||||
static const char *names[] = { "common.conf", "gpg-agent.conf",
|
||||
"scdaemon.conf", "dirmngr.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;
|
||||
int idx;
|
||||
char *fname;
|
||||
@ -1539,6 +1544,11 @@ show_configs (estream_t outfp)
|
||||
list_dirs (outfp, NULL, 1);
|
||||
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);
|
||||
if (!gnupg_access (fname, F_OK))
|
||||
{
|
||||
|
@ -37,7 +37,7 @@
|
||||
#include "gpgtar.h"
|
||||
|
||||
static gpg_error_t
|
||||
check_suspicious_name (const char *name)
|
||||
check_suspicious_name (const char *name, tarinfo_t info)
|
||||
{
|
||||
size_t n;
|
||||
|
||||
@ -47,6 +47,7 @@ check_suspicious_name (const char *name)
|
||||
{
|
||||
log_error ("filename '%s' contains a backslash - "
|
||||
"can't extract on this system\n", name);
|
||||
info->skipped_badname++;
|
||||
return gpg_error (GPG_ERR_INV_NAME);
|
||||
}
|
||||
#endif /*HAVE_DOSISH_SYSTEM*/
|
||||
@ -59,6 +60,7 @@ check_suspicious_name (const char *name)
|
||||
{
|
||||
log_error ("filename '%s' has suspicious parts - not extracting\n",
|
||||
name);
|
||||
info->skipped_suspicious++;
|
||||
return gpg_error (GPG_ERR_INV_NAME);
|
||||
}
|
||||
|
||||
@ -83,7 +85,7 @@ extract_regular (estream_t stream, const char *dirname,
|
||||
if (sl->flags == 1)
|
||||
fname = sl->d;
|
||||
|
||||
err = check_suspicious_name (fname);
|
||||
err = check_suspicious_name (fname, info);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
@ -131,8 +133,12 @@ extract_regular (estream_t stream, const char *dirname,
|
||||
/* Fixme: Set permissions etc. */
|
||||
|
||||
leave:
|
||||
if (!err && opt.verbose)
|
||||
if (!err)
|
||||
{
|
||||
if (opt.verbose)
|
||||
log_info ("extracted '%s'\n", fname);
|
||||
info->nextracted++;
|
||||
}
|
||||
es_fclose (outfp);
|
||||
if (err && fname && outfp)
|
||||
{
|
||||
@ -146,7 +152,8 @@ extract_regular (estream_t stream, const char *dirname,
|
||||
|
||||
|
||||
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;
|
||||
const char *name;
|
||||
@ -158,7 +165,7 @@ extract_directory (const char *dirname, tar_header_t hdr, strlist_t exthdr)
|
||||
if (sl->flags == 1)
|
||||
name = sl->d;
|
||||
|
||||
err = check_suspicious_name (name);
|
||||
err = check_suspicious_name (name, info);
|
||||
if (err)
|
||||
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)
|
||||
err = extract_regular (stream, dirname, info, hdr, exthdr);
|
||||
else if (hdr->typeflag == TF_DIRECTORY)
|
||||
err = extract_directory (dirname, hdr, exthdr);
|
||||
err = extract_directory (dirname, info, hdr, exthdr);
|
||||
else
|
||||
{
|
||||
char record[RECORDSIZE];
|
||||
|
||||
log_info ("unsupported file type %d for '%s' - skipped\n",
|
||||
(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++)
|
||||
{
|
||||
err = read_record (stream, record);
|
||||
@ -328,7 +341,7 @@ gpgtar_extract (const char *filename, int decrypt)
|
||||
tarinfo_t tarinfo = &tarinfo_buffer;
|
||||
pid_t pid = (pid_t)(-1);
|
||||
char *logfilename = NULL;
|
||||
|
||||
unsigned long long notextracted;
|
||||
|
||||
memset (&tarinfo_buffer, 0, sizeof tarinfo_buffer);
|
||||
|
||||
@ -478,8 +491,37 @@ gpgtar_extract (const char *filename, int decrypt)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
xfree (header);
|
||||
xfree (dirname);
|
||||
|
@ -459,7 +459,7 @@ main (int argc, char **argv)
|
||||
|
||||
gnupg_reopen_std (GPGTAR_NAME);
|
||||
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. */
|
||||
i18n_init();
|
||||
@ -501,7 +501,11 @@ main (int argc, char **argv)
|
||||
log_fatal ("status-fd is invalid: %s\n", strerror (errno));
|
||||
|
||||
if (fd == 1)
|
||||
{
|
||||
opt.status_stream = es_stdout;
|
||||
if (!skip_crypto)
|
||||
log_fatal ("using stdout for the status-fd is not possible\n");
|
||||
}
|
||||
else if (fd == 2)
|
||||
opt.status_stream = es_stderr;
|
||||
else
|
||||
|
@ -56,6 +56,12 @@ struct tarinfo_s
|
||||
{
|
||||
unsigned long long nblocks; /* Count of processed blocks. */
|
||||
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;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user