1
0
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:
NIIBE Yutaka 2023-03-20 16:40:32 +09:00
commit 01eef54e2c
No known key found for this signature in database
GPG Key ID: 640114AF89DE6054
66 changed files with 1138 additions and 493 deletions

View File

@ -142,13 +142,6 @@ struct
passphrase change. */ passphrase change. */
int enable_passphrase_history; int enable_passphrase_history;
/* If set the extended key format is used for new keys. Note that
* this may have the value 2 in which case
* --disable-extended-key-format won't have any effect and thus
* effectivley locking it. This is required to support existing
* profiles which lock the use of --enable-extended-key-format. */
int enable_extended_key_format;
int running_detached; /* We are running detached from the tty. */ int running_detached; /* We are running detached from the tty. */
/* If this global option is true, the passphrase cache is ignored /* If this global option is true, the passphrase cache is ignored
@ -567,7 +560,7 @@ unsigned char get_standard_s2k_count_rfc4880 (void);
unsigned long get_standard_s2k_time (void); unsigned long get_standard_s2k_time (void);
int agent_protect (const unsigned char *plainkey, const char *passphrase, int agent_protect (const unsigned char *plainkey, const char *passphrase,
unsigned char **result, size_t *resultlen, unsigned char **result, size_t *resultlen,
unsigned long s2k_count, int use_ocb); unsigned long s2k_count);
gpg_error_t agent_unprotect (ctrl_t ctrl, gpg_error_t agent_unprotect (ctrl_t ctrl,
const unsigned char *protectedkey, const char *passphrase, const unsigned char *protectedkey, const char *passphrase,
gnupg_isotime_t protected_at, gnupg_isotime_t protected_at,

View File

@ -1543,6 +1543,17 @@ agent_askpin (ctrl_t ctrl,
NULL, NULL, NULL, NULL, NULL, NULL); NULL, NULL, NULL, NULL, NULL, NULL);
if (rc) if (rc)
pininfo->with_repeat = 0; /* Pinentry does not support it. */ pininfo->with_repeat = 0; /* Pinentry does not support it. */
if (pininfo->with_repeat)
{
snprintf (line, DIM(line), "SETREPEATOK %s",
L_("Passphrases match."));
rc = assuan_transact (entry_ctx, line,
NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
rc = 0; /* Pinentry does not support it. */
}
} }
pininfo->repeat_okay = 0; pininfo->repeat_okay = 0;
pininfo->status = 0; pininfo->status = 0;
@ -1802,6 +1813,16 @@ agent_get_passphrase (ctrl_t ctrl,
if (rc) if (rc)
pininfo->with_repeat = 0; /* Pinentry does not support it. */ pininfo->with_repeat = 0; /* Pinentry does not support it. */
if (pininfo->with_repeat)
{
snprintf (line, DIM(line), "SETREPEATOK %s",
L_("Passphrases match."));
rc = assuan_transact (entry_ctx, line,
NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
rc = 0; /* Pinentry does not support it. */
}
(void)setup_genpin (ctrl); (void)setup_genpin (ctrl);
rc = setup_enforced_constraints (ctrl); rc = setup_enforced_constraints (ctrl);

View File

@ -3142,7 +3142,7 @@ ssh_key_to_protected_buffer (gcry_sexp_t key, const char *passphrase,
buffer_new, buffer_new_n); buffer_new, buffer_new_n);
if (*passphrase) if (*passphrase)
err = agent_protect (buffer_new, passphrase, buffer, buffer_n, 0, -1); err = agent_protect (buffer_new, passphrase, buffer, buffer_n, 0);
else else
{ {
/* The key derivation function does not support zero length /* The key derivation function does not support zero length

View File

@ -1218,12 +1218,6 @@ cmd_keyattr (assuan_context_t ctx, char *line)
if (ctrl->restricted) if (ctrl->restricted)
return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN)); return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
if (!opt.enable_extended_key_format)
{
err = gpg_error (GPG_ERR_NOT_SUPPORTED);
goto leave;
}
opt_delete = has_option (line, "--delete"); opt_delete = has_option (line, "--delete");
line = skip_options (line); line = skip_options (line);
@ -2987,7 +2981,7 @@ cmd_import_key (assuan_context_t ctx, char *line)
if (passphrase) if (passphrase)
{ {
err = agent_protect (key, passphrase, &finalkey, &finalkeylen, err = agent_protect (key, passphrase, &finalkey, &finalkeylen,
ctrl->s2k_count, -1); ctrl->s2k_count);
if (!err) if (!err)
err = agent_write_private_key (grip, finalkey, finalkeylen, force, err = agent_write_private_key (grip, finalkey, finalkeylen, force,
NULL, NULL, opt_timestamp); NULL, NULL, opt_timestamp);

View File

@ -1146,7 +1146,7 @@ convert_from_openpgp_native (ctrl_t ctrl,
if (!agent_protect (*r_key, passphrase, if (!agent_protect (*r_key, passphrase,
&protectedkey, &protectedkeylen, &protectedkey, &protectedkeylen,
ctrl->s2k_count, -1)) ctrl->s2k_count))
agent_write_private_key (grip, protectedkey, protectedkeylen, 1, agent_write_private_key (grip, protectedkey, protectedkeylen, 1,
NULL, NULL, 0); NULL, NULL, 0);
xfree (protectedkey); xfree (protectedkey);

View File

@ -2,6 +2,7 @@
* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007,
* 2010, 2011 Free Software Foundation, Inc. * 2010, 2011 Free Software Foundation, Inc.
* Copyright (C) 2014, 2019 Werner Koch * Copyright (C) 2014, 2019 Werner Koch
* Copyright (C) 2023 g10 Code GmbH
* *
* This file is part of GnuPG. * This file is part of GnuPG.
* *
@ -79,19 +80,114 @@ linefeed_to_percent0A (const char *string)
} }
/* Note: Ownership of FNAME and FP are moved to this function. */ /* Write the S-expression formatted key (BUFFER,LENGTH) to our key
static gpg_error_t * storage. With FORCE passed as true an existing key with the given
write_extended_private_key (char *fname, estream_t fp, int update, int newkey, * GRIP will get overwritten. If SERIALNO and KEYREF are given a
const void *buf, size_t len, * Token line is added to the key if the extended format is used. If
const char *serialno, const char *keyref, * TIMESTAMP is not zero and the key doies not yet exists it will be
time_t timestamp) * recorded as creation date. */
int
agent_write_private_key (const unsigned char *grip,
const void *buffer, size_t length, int force,
const char *serialno, const char *keyref,
time_t timestamp)
{ {
gpg_error_t err; gpg_error_t err;
char *fname;
estream_t fp;
char hexgrip[40+4+1];
int update, newkey;
nvc_t pk = NULL; nvc_t pk = NULL;
gcry_sexp_t key = NULL; gcry_sexp_t key = NULL;
int remove = 0; int remove = 0;
char *token = NULL; char *token = NULL;
bin2hex (grip, 20, hexgrip);
strcpy (hexgrip+40, ".key");
fname = make_filename (gnupg_homedir (), GNUPG_PRIVATE_KEYS_DIR,
hexgrip, NULL);
/* FIXME: Write to a temp file first so that write failures during
key updates won't lead to a key loss. */
if (!force && !gnupg_access (fname, F_OK))
{
log_error ("secret key file '%s' already exists\n", fname);
xfree (fname);
return gpg_error (GPG_ERR_EEXIST);
}
fp = es_fopen (fname, force? "rb+,mode=-rw" : "wbx,mode=-rw");
if (!fp)
{
gpg_error_t tmperr = gpg_error_from_syserror ();
if (force && gpg_err_code (tmperr) == GPG_ERR_ENOENT)
{
fp = es_fopen (fname, "wbx,mode=-rw");
if (!fp)
tmperr = gpg_error_from_syserror ();
}
if (!fp)
{
log_error ("can't create '%s': %s\n", fname, gpg_strerror (tmperr));
xfree (fname);
return tmperr;
}
update = 0;
newkey = 1;
}
else if (force)
{
gpg_error_t rc;
char first;
/* See if an existing key is in extended format. */
if (es_fread (&first, 1, 1, fp) != 1)
{
rc = gpg_error_from_syserror ();
log_error ("error reading first byte from '%s': %s\n",
fname, strerror (errno));
xfree (fname);
es_fclose (fp);
return rc;
}
rc = es_fseek (fp, 0, SEEK_SET);
if (rc)
{
log_error ("error seeking in '%s': %s\n", fname, strerror (errno));
xfree (fname);
es_fclose (fp);
return rc;
}
if (first == '(')
{
/* Key is still in the old format - force it into extended
* format. We do not request an update here because an
* existing key is not yet in extended key format and no
* extended infos are yet available. */
update = 0;
newkey = 0;
}
else
{
/* Key is already in the extended format. */
update = 1;
newkey = 0;
}
}
else
{
/* The key file did not exist: we assume this is a new key and
* write the Created: entry. */
update = 0;
newkey = 1;
}
if (update) if (update)
{ {
int line; int line;
@ -115,10 +211,11 @@ write_extended_private_key (char *fname, estream_t fp, int update, int newkey,
} }
es_clearerr (fp); es_clearerr (fp);
err = gcry_sexp_sscan (&key, NULL, buf, len); /* Turn (BUFFER,LENGTH) into a gcrypt s-expression and set it into
* our name value container. */
err = gcry_sexp_sscan (&key, NULL, buffer, length);
if (err) if (err)
goto leave; goto leave;
err = nvc_set_private_key (pk, key); err = nvc_set_private_key (pk, key);
if (err) if (err)
goto leave; goto leave;
@ -153,7 +250,7 @@ write_extended_private_key (char *fname, estream_t fp, int update, int newkey,
} }
} }
/* If a timestamp has been supplied and the key is new write a /* If a timestamp has been supplied and the key is new, write a
* creation timestamp. (We douple check that there is no Created * creation timestamp. (We douple check that there is no Created
* item yet.)*/ * item yet.)*/
if (timestamp && newkey && !nvc_lookup (pk, "Created:")) if (timestamp && newkey && !nvc_lookup (pk, "Created:"))
@ -166,7 +263,7 @@ write_extended_private_key (char *fname, estream_t fp, int update, int newkey,
goto leave; goto leave;
} }
/* Back to start and write. */
err = es_fseek (fp, 0, SEEK_SET); err = es_fseek (fp, 0, SEEK_SET);
if (err) if (err)
goto leave; goto leave;
@ -212,133 +309,6 @@ write_extended_private_key (char *fname, estream_t fp, int update, int newkey,
return err; return err;
} }
/* Write an S-expression formatted key to our key storage. With FORCE
* passed as true an existing key with the given GRIP will get
* overwritten. If SERIALNO and KEYREF are given a Token line is
* added to the key if the extended format is used. If TIMESTAMP is
* not zero and the key doies not yet exists it will be recorded as
* creation date. */
int
agent_write_private_key (const unsigned char *grip,
const void *buffer, size_t length, int force,
const char *serialno, const char *keyref,
time_t timestamp)
{
char *fname;
estream_t fp;
char hexgrip[40+4+1];
bin2hex (grip, 20, hexgrip);
strcpy (hexgrip+40, ".key");
fname = make_filename (gnupg_homedir (), GNUPG_PRIVATE_KEYS_DIR,
hexgrip, NULL);
/* FIXME: Write to a temp file first so that write failures during
key updates won't lead to a key loss. */
if (!force && !gnupg_access (fname, F_OK))
{
log_error ("secret key file '%s' already exists\n", fname);
xfree (fname);
return gpg_error (GPG_ERR_EEXIST);
}
fp = es_fopen (fname, force? "rb+,mode=-rw" : "wbx,mode=-rw");
if (!fp)
{
gpg_error_t tmperr = gpg_error_from_syserror ();
if (force && gpg_err_code (tmperr) == GPG_ERR_ENOENT)
{
fp = es_fopen (fname, "wbx,mode=-rw");
if (!fp)
tmperr = gpg_error_from_syserror ();
}
if (!fp)
{
log_error ("can't create '%s': %s\n", fname, gpg_strerror (tmperr));
xfree (fname);
return tmperr;
}
}
else if (force)
{
gpg_error_t rc;
char first;
/* See if an existing key is in extended format. */
if (es_fread (&first, 1, 1, fp) != 1)
{
rc = gpg_error_from_syserror ();
log_error ("error reading first byte from '%s': %s\n",
fname, strerror (errno));
xfree (fname);
es_fclose (fp);
return rc;
}
rc = es_fseek (fp, 0, SEEK_SET);
if (rc)
{
log_error ("error seeking in '%s': %s\n", fname, strerror (errno));
xfree (fname);
es_fclose (fp);
return rc;
}
if (first != '(')
{
/* Key is already in the extended format. */
return write_extended_private_key (fname, fp, 1, 0, buffer, length,
serialno, keyref, timestamp);
}
if (first == '(' && opt.enable_extended_key_format)
{
/* Key is in the old format - but we want the extended format. */
return write_extended_private_key (fname, fp, 0, 0, buffer, length,
serialno, keyref, timestamp);
}
}
if (opt.enable_extended_key_format)
return write_extended_private_key (fname, fp, 0, 1, buffer, length,
serialno, keyref, timestamp);
if (es_fwrite (buffer, length, 1, fp) != 1)
{
gpg_error_t tmperr = gpg_error_from_syserror ();
log_error ("error writing '%s': %s\n", fname, gpg_strerror (tmperr));
es_fclose (fp);
gnupg_remove (fname);
xfree (fname);
return tmperr;
}
/* When force is given, the file might have to be truncated. */
if (force && ftruncate (es_fileno (fp), es_ftello (fp)))
{
gpg_error_t tmperr = gpg_error_from_syserror ();
log_error ("error truncating '%s': %s\n", fname, gpg_strerror (tmperr));
es_fclose (fp);
gnupg_remove (fname);
xfree (fname);
return tmperr;
}
if (es_fclose (fp))
{
gpg_error_t tmperr = gpg_error_from_syserror ();
log_error ("error closing '%s': %s\n", fname, gpg_strerror (tmperr));
gnupg_remove (fname);
xfree (fname);
return tmperr;
}
bump_key_eventcounter ();
xfree (fname);
return 0;
}
gpg_error_t gpg_error_t
agent_update_private_key (const unsigned char *grip, nvc_t pk) agent_update_private_key (const unsigned char *grip, nvc_t pk)
@ -393,6 +363,7 @@ agent_update_private_key (const unsigned char *grip, nvc_t pk)
return err; return err;
} }
/* Callback function to try the unprotection from the passphrase query /* Callback function to try the unprotection from the passphrase query
code. */ code. */
static gpg_error_t static gpg_error_t
@ -1186,6 +1157,15 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce,
return gpg_error (GPG_ERR_NO_SECKEY); return gpg_error (GPG_ERR_NO_SECKEY);
err = read_key_file (grip? grip : ctrl->keygrip, &s_skey, &keymeta); err = read_key_file (grip? grip : ctrl->keygrip, &s_skey, &keymeta);
if (err)
{
if (gpg_err_code (err) == GPG_ERR_ENOENT)
err = gpg_error (GPG_ERR_NO_SECKEY);
else
log_error ("findkey: error reading key file: %s\n",
gpg_strerror (err));
return err;
}
/* For use with the protection functions we also need the key as an /* For use with the protection functions we also need the key as an
canonical encoded S-expression in a buffer. Create this buffer canonical encoded S-expression in a buffer. Create this buffer

View File

@ -57,7 +57,7 @@ store_key (gcry_sexp_t private, const char *passphrase, int force,
{ {
unsigned char *p; unsigned char *p;
rc = agent_protect (buf, passphrase, &p, &len, s2k_count, -1); rc = agent_protect (buf, passphrase, &p, &len, s2k_count);
if (rc) if (rc)
{ {
xfree (buf); xfree (buf);

View File

@ -117,8 +117,6 @@ enum cmd_and_opt_values
oCheckSymPassphrasePattern, oCheckSymPassphrasePattern,
oMaxPassphraseDays, oMaxPassphraseDays,
oEnablePassphraseHistory, oEnablePassphraseHistory,
oDisableExtendedKeyFormat,
oEnableExtendedKeyFormat,
oStealSocket, oStealSocket,
oUseStandardSocket, oUseStandardSocket,
oNoUseStandardSocket, oNoUseStandardSocket,
@ -241,8 +239,6 @@ static gpgrt_opt_t opts[] = {
/* */ "@" /* */ "@"
#endif #endif
), ),
ARGPARSE_s_n (oDisableExtendedKeyFormat, "disable-extended-key-format", "@"),
ARGPARSE_s_n (oEnableExtendedKeyFormat, "enable-extended-key-format", "@"),
ARGPARSE_s_i (oListenBacklog, "listen-backlog", "@"), ARGPARSE_s_i (oListenBacklog, "listen-backlog", "@"),
ARGPARSE_op_u (oAutoExpandSecmem, "auto-expand-secmem", "@"), ARGPARSE_op_u (oAutoExpandSecmem, "auto-expand-secmem", "@"),
ARGPARSE_s_s (oFakedSystemTime, "faked-system-time", "@"), ARGPARSE_s_s (oFakedSystemTime, "faked-system-time", "@"),
@ -318,7 +314,8 @@ static gpgrt_opt_t opts[] = {
ARGPARSE_s_n (oNoUseStandardSocket, "no-use-standard-socket", "@"), ARGPARSE_s_n (oNoUseStandardSocket, "no-use-standard-socket", "@"),
/* Dummy options. */ /* Dummy options. */
ARGPARSE_s_n (oNoop, "disable-extended-key-format", "@"),
ARGPARSE_s_n (oNoop, "enable-extended-key-format", "@"),
ARGPARSE_end () /* End of list */ ARGPARSE_end () /* End of list */
}; };
@ -888,7 +885,6 @@ parse_rereadable_options (gpgrt_argparse_t *pargs, int reread)
opt.check_sym_passphrase_pattern = NULL; opt.check_sym_passphrase_pattern = NULL;
opt.max_passphrase_days = MAX_PASSPHRASE_DAYS; opt.max_passphrase_days = MAX_PASSPHRASE_DAYS;
opt.enable_passphrase_history = 0; opt.enable_passphrase_history = 0;
opt.enable_extended_key_format = 1;
opt.ignore_cache_for_signing = 0; opt.ignore_cache_for_signing = 0;
opt.allow_mark_trusted = 1; opt.allow_mark_trusted = 1;
opt.sys_trustlist_name = NULL; opt.sys_trustlist_name = NULL;
@ -980,14 +976,6 @@ parse_rereadable_options (gpgrt_argparse_t *pargs, int reread)
opt.enable_passphrase_history = 1; opt.enable_passphrase_history = 1;
break; break;
case oEnableExtendedKeyFormat:
opt.enable_extended_key_format = 2;
break;
case oDisableExtendedKeyFormat:
if (opt.enable_extended_key_format != 2)
opt.enable_extended_key_format = 0;
break;
case oIgnoreCacheForSigning: opt.ignore_cache_for_signing = 1; break; case oIgnoreCacheForSigning: opt.ignore_cache_for_signing = 1; break;
case oAllowMarkTrusted: opt.allow_mark_trusted = 1; break; case oAllowMarkTrusted: opt.allow_mark_trusted = 1; break;

View File

@ -74,8 +74,7 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
no_shadow_info = 1; no_shadow_info = 1;
else if (err) else if (err)
{ {
if (gpg_err_code (err) != GPG_ERR_NO_SECKEY) log_error ("failed to read the secret key\n");
log_error ("failed to read the secret key\n");
goto leave; goto leave;
} }
@ -88,7 +87,7 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
goto leave; goto leave;
} }
if (agent_is_tpm2_key (s_skey)) if (s_skey && agent_is_tpm2_key (s_skey))
err = divert_tpm2_pkdecrypt (ctrl, ciphertext, shadow_info, err = divert_tpm2_pkdecrypt (ctrl, ciphertext, shadow_info,
&buf, &len, r_padding); &buf, &len, r_padding);
else else
@ -96,7 +95,15 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
&buf, &len, r_padding); &buf, &len, r_padding);
if (err) if (err)
{ {
log_error ("smartcard decryption failed: %s\n", gpg_strerror (err)); /* We restore the original error (ie. no seckey) is no card
* has been found and we have no shadow key. This avoids a
* surprising "card removed" error code. */
if ((gpg_err_code (err) == GPG_ERR_CARD_REMOVED
|| gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT)
&& no_shadow_info)
err = gpg_error (GPG_ERR_NO_SECKEY);
else
log_error ("smartcard decryption failed: %s\n", gpg_strerror (err));
goto leave; goto leave;
} }

View File

@ -97,7 +97,6 @@ static const char *opt_passphrase;
static char *opt_prompt; static char *opt_prompt;
static int opt_status_msg; static int opt_status_msg;
static const char *opt_agent_program; static const char *opt_agent_program;
static int opt_debug_use_ocb;
static char *get_passphrase (int promptno); static char *get_passphrase (int promptno);
static void release_passphrase (char *pw); static void release_passphrase (char *pw);
@ -343,8 +342,7 @@ read_and_protect (const char *fname)
return; return;
pw = get_passphrase (1); pw = get_passphrase (1);
rc = agent_protect (key, pw, &result, &resultlen, 0, rc = agent_protect (key, pw, &result, &resultlen, 0);
opt_debug_use_ocb? 1 : -1);
release_passphrase (pw); release_passphrase (pw);
xfree (key); xfree (key);
if (rc) if (rc)
@ -610,7 +608,7 @@ main (int argc, char **argv )
case oHaveCert: opt_have_cert = 1; break; case oHaveCert: opt_have_cert = 1; break;
case oPrompt: opt_prompt = pargs.r.ret_str; break; case oPrompt: opt_prompt = pargs.r.ret_str; break;
case oStatusMsg: opt_status_msg = 1; break; case oStatusMsg: opt_status_msg = 1; break;
case oDebugUseOCB: opt_debug_use_ocb = 1; break; case oDebugUseOCB: /* dummy */; break;
default: pargs.err = ARGPARSE_PRINT_ERROR; break; default: pargs.err = ARGPARSE_PRINT_ERROR; break;
} }

View File

@ -379,12 +379,11 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
const char *passphrase, const char *passphrase,
const char *timestamp_exp, size_t timestamp_exp_len, const char *timestamp_exp, size_t timestamp_exp_len,
unsigned char **result, size_t *resultlen, unsigned char **result, size_t *resultlen,
unsigned long s2k_count, int use_ocb) unsigned long s2k_count)
{ {
gcry_cipher_hd_t hd; gcry_cipher_hd_t hd;
const char *modestr; const char *modestr;
unsigned char hashvalue[20]; int enclen, outlen;
int blklen, enclen, outlen;
unsigned char *iv = NULL; unsigned char *iv = NULL;
unsigned int ivsize; /* Size of the buffer allocated for IV. */ unsigned int ivsize; /* Size of the buffer allocated for IV. */
const unsigned char *s2ksalt; /* Points into IV. */ const unsigned char *s2ksalt; /* Points into IV. */
@ -398,44 +397,26 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
*resultlen = 0; *resultlen = 0;
*result = NULL; *result = NULL;
modestr = (use_ocb? "openpgp-s2k3-ocb-aes" modestr = "openpgp-s2k3-ocb-aes";
/* */: "openpgp-s2k3-sha1-" PROT_CIPHER_STRING "-cbc");
rc = gcry_cipher_open (&hd, PROT_CIPHER, rc = gcry_cipher_open (&hd, PROT_CIPHER,
use_ocb? GCRY_CIPHER_MODE_OCB : GCRY_CIPHER_MODE_OCB,
GCRY_CIPHER_MODE_CBC,
GCRY_CIPHER_SECURE); GCRY_CIPHER_SECURE);
if (rc) if (rc)
return rc; return rc;
/* We need to work on a copy of the data because this makes it /* We need to work on a copy of the data because this makes it
* easier to add the trailer and the padding and more important we * easier to add the trailer and the padding and more important we
* have to prefix the text with 2 parenthesis. In CBC mode we * have to prefix the text with 2 parenthesis. Due to OCB mode we
* have to allocate enough space for:
*
* ((<parameter_list>)(4:hash4:sha120:<hashvalue>)) + padding
*
* we always append a full block of random bytes as padding but
* encrypt only what is needed for a full blocksize. In OCB mode we
* have to allocate enough space for just: * have to allocate enough space for just:
* *
* ((<parameter_list>)) * ((<parameter_list>))
*/ */
blklen = gcry_cipher_get_algo_blklen (PROT_CIPHER);
if (use_ocb) /* (( )) */
{ outlen = 2 + protlen + 2 ;
/* (( )) */ enclen = outlen + 16 /* taglen */;
outlen = 2 + protlen + 2 ; outbuf = gcry_malloc_secure (enclen);
enclen = outlen + 16 /* taglen */;
outbuf = gcry_malloc_secure (enclen);
}
else
{
/* (( )( 4:hash 4:sha1 20:<hash> )) <padding> */
outlen = 2 + protlen + 2 + 6 + 6 + 23 + 2 + blklen;
enclen = outlen/blklen * blklen;
outbuf = gcry_malloc_secure (outlen);
}
if (!outbuf) if (!outbuf)
{ {
rc = out_of_core (); rc = out_of_core ();
@ -445,10 +426,10 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
/* Allocate a buffer for the nonce and the salt. */ /* Allocate a buffer for the nonce and the salt. */
if (!rc) if (!rc)
{ {
/* Allocate random bytes to be used as IV, padding and s2k salt /* Allocate random bytes to be used as nonce and s2k salt. The
* or in OCB mode for a nonce and the s2k salt. The IV/nonce is * nonce is set later because for OCB we need to set the key
* set later because for OCB we need to set the key first. */ * first. */
ivsize = (use_ocb? 12 : (blklen*2)) + 8; ivsize = 12 + 8;
iv = xtrymalloc (ivsize); iv = xtrymalloc (ivsize);
if (!iv) if (!iv)
rc = gpg_error_from_syserror (); rc = gpg_error_from_syserror ();
@ -484,40 +465,17 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
goto leave; goto leave;
/* Set the IV/nonce. */ /* Set the IV/nonce. */
rc = gcry_cipher_setiv (hd, iv, use_ocb? 12 : blklen); rc = gcry_cipher_setiv (hd, iv, 12);
if (rc) if (rc)
goto leave; goto leave;
if (use_ocb) /* In OCB Mode we use only the public key parameters as AAD. */
{ rc = gcry_cipher_authenticate (hd, hashbegin, protbegin - hashbegin);
/* In OCB Mode we use only the public key parameters as AAD. */ if (!rc)
rc = gcry_cipher_authenticate (hd, hashbegin, protbegin - hashbegin); rc = gcry_cipher_authenticate (hd, timestamp_exp, timestamp_exp_len);
if (!rc) if (!rc)
rc = gcry_cipher_authenticate (hd, timestamp_exp, timestamp_exp_len); rc = gcry_cipher_authenticate
if (!rc) (hd, protbegin+protlen, hashlen - (protbegin+protlen - hashbegin));
rc = gcry_cipher_authenticate
(hd, protbegin+protlen, hashlen - (protbegin+protlen - hashbegin));
}
else
{
/* Hash the entire expression for CBC mode. Because
* TIMESTAMP_EXP won't get protected, we can't simply hash a
* continuous buffer but need to call md_write several times. */
gcry_md_hd_t md;
rc = gcry_md_open (&md, GCRY_MD_SHA1, 0 );
if (!rc)
{
gcry_md_write (md, hashbegin, protbegin - hashbegin);
gcry_md_write (md, protbegin, protlen);
gcry_md_write (md, timestamp_exp, timestamp_exp_len);
gcry_md_write (md, protbegin+protlen,
hashlen - (protbegin+protlen - hashbegin));
memcpy (hashvalue, gcry_md_read (md, GCRY_MD_SHA1), 20);
gcry_md_close (md);
}
}
/* Encrypt. */ /* Encrypt. */
if (!rc) if (!rc)
@ -527,36 +485,15 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
*p++ = '('; *p++ = '(';
memcpy (p, protbegin, protlen); memcpy (p, protbegin, protlen);
p += protlen; p += protlen;
if (use_ocb) *p++ = ')';
{ *p++ = ')';
*p++ = ')';
*p++ = ')';
}
else
{
memcpy (p, ")(4:hash4:sha120:", 17);
p += 17;
memcpy (p, hashvalue, 20);
p += 20;
*p++ = ')';
*p++ = ')';
memcpy (p, iv+blklen, blklen); /* Add padding. */
p += blklen;
}
log_assert ( p - outbuf == outlen); log_assert ( p - outbuf == outlen);
if (use_ocb) gcry_cipher_final (hd);
rc = gcry_cipher_encrypt (hd, outbuf, outlen, NULL, 0);
if (!rc)
{ {
gcry_cipher_final (hd); log_assert (outlen + 16 == enclen);
rc = gcry_cipher_encrypt (hd, outbuf, outlen, NULL, 0); rc = gcry_cipher_gettag (hd, outbuf + outlen, 16);
if (!rc)
{
log_assert (outlen + 16 == enclen);
rc = gcry_cipher_gettag (hd, outbuf + outlen, 16);
}
}
else
{
rc = gcry_cipher_encrypt (hd, outbuf, enclen, NULL, 0);
} }
} }
@ -584,7 +521,7 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
(int)strlen (modestr), modestr, (int)strlen (modestr), modestr,
&saltpos, &saltpos,
(unsigned int)strlen (countbuf), countbuf, (unsigned int)strlen (countbuf), countbuf,
use_ocb? 12 : blklen, &ivpos, use_ocb? 12 : blklen, "", 12, &ivpos, 12, "",
enclen, &encpos, enclen, ""); enclen, &encpos, enclen, "");
if (!p) if (!p)
{ {
@ -598,7 +535,7 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
*resultlen = strlen (p); *resultlen = strlen (p);
*result = (unsigned char*)p; *result = (unsigned char*)p;
memcpy (p+saltpos, s2ksalt, 8); memcpy (p+saltpos, s2ksalt, 8);
memcpy (p+ivpos, iv, use_ocb? 12 : blklen); memcpy (p+ivpos, iv, 12);
memcpy (p+encpos, outbuf, enclen); memcpy (p+encpos, outbuf, enclen);
xfree (iv); xfree (iv);
xfree (outbuf); xfree (outbuf);
@ -614,13 +551,11 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
/* Protect the key encoded in canonical format in PLAINKEY. We assume /* Protect the key encoded in canonical format in PLAINKEY. We assume
a valid S-Exp here. With USE_UCB set to -1 the default scheme is * a valid S-Exp here. */
used (ie. either CBC or OCB), set to 0 the old CBC mode is used,
and set to 1 OCB is used. */
int int
agent_protect (const unsigned char *plainkey, const char *passphrase, agent_protect (const unsigned char *plainkey, const char *passphrase,
unsigned char **result, size_t *resultlen, unsigned char **result, size_t *resultlen,
unsigned long s2k_count, int use_ocb) unsigned long s2k_count)
{ {
int rc; int rc;
const char *parmlist; const char *parmlist;
@ -637,9 +572,6 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
unsigned char *p; unsigned char *p;
int have_curve = 0; int have_curve = 0;
if (use_ocb == -1)
use_ocb = !!opt.enable_extended_key_format;
/* Create an S-expression with the protected-at timestamp. */ /* Create an S-expression with the protected-at timestamp. */
memcpy (timestamp_exp, "(12:protected-at15:", 19); memcpy (timestamp_exp, "(12:protected-at15:", 19);
gnupg_get_isotime (timestamp_exp+19); gnupg_get_isotime (timestamp_exp+19);
@ -743,7 +675,7 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
rc = do_encryption (hash_begin, hash_end - hash_begin + 1, rc = do_encryption (hash_begin, hash_end - hash_begin + 1,
prot_begin, prot_end - prot_begin + 1, prot_begin, prot_end - prot_begin + 1,
passphrase, timestamp_exp, sizeof (timestamp_exp), passphrase, timestamp_exp, sizeof (timestamp_exp),
&protected, &protectedlen, s2k_count, use_ocb); &protected, &protectedlen, s2k_count);
if (rc) if (rc)
return rc; return rc;

View File

@ -196,7 +196,7 @@ test_agent_protect (void)
{ {
ret = agent_protect ((const unsigned char*)specs[i].key, ret = agent_protect ((const unsigned char*)specs[i].key,
specs[i].passphrase, specs[i].passphrase,
&specs[i].result, &specs[i].resultlen, 0, -1); &specs[i].result, &specs[i].resultlen, 0);
if (gpg_err_code (ret) != specs[i].ret_expected) if (gpg_err_code (ret) != specs[i].ret_expected)
{ {
printf ("agent_protect(%d) returned '%i/%s'; expected '%i/%s'\n", printf ("agent_protect(%d) returned '%i/%s'; expected '%i/%s'\n",

View File

@ -1109,6 +1109,7 @@ proc_type_verify (audit_ctx_t ctx)
case GPG_ERR_CERT_REVOKED: ok = "bad"; break; case GPG_ERR_CERT_REVOKED: ok = "bad"; break;
case GPG_ERR_NOT_ENABLED: ok = "disabled"; break; case GPG_ERR_NOT_ENABLED: ok = "disabled"; break;
case GPG_ERR_NO_CRL_KNOWN: case GPG_ERR_NO_CRL_KNOWN:
case GPG_ERR_INV_CRL_OBJ:
ok = _("no CRL found for certificate"); ok = _("no CRL found for certificate");
break; break;
case GPG_ERR_CRL_TOO_OLD: case GPG_ERR_CRL_TOO_OLD:

View File

@ -40,6 +40,7 @@
#include "util.h" #include "util.h"
#include "i18n.h" #include "i18n.h"
#include "tlv.h"
#include "ksba-io-support.h" #include "ksba-io-support.h"
@ -65,6 +66,12 @@ struct reader_cb_parm_s
int autodetect; /* Try to detect the input encoding. */ int autodetect; /* Try to detect the input encoding. */
int assume_pem; /* Assume input encoding is PEM. */ int assume_pem; /* Assume input encoding is PEM. */
int assume_base64; /* Assume input is base64 encoded. */ int assume_base64; /* Assume input is base64 encoded. */
int strip_zeroes; /* Expect a SEQUENCE followed by zero padding. */
/* 1 = check state; 2 = reading; 3 = checking */
/* for zeroes. */
int use_maxread; /* If true read not more than MAXREAD. */
unsigned int maxread; /* # of bytes left to read. */
off_t nzeroes; /* Number of padding zeroes red. */
int identified; int identified;
int is_pem; int is_pem;
@ -390,6 +397,55 @@ base64_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
} }
/* Read up to 10 bytes to test whether the data consist of a sequence;
* if that is true, set the limited flag and record the length of the
* entire sequence in PARM. Unget everything then. Return true if we
* have a sequence with a fixed length. */
static int
starts_with_sequence (struct reader_cb_parm_s *parm)
{
gpg_error_t err;
unsigned char peekbuf[10];
int npeeked, c;
int found = 0;
const unsigned char *p;
size_t n, objlen, hdrlen;
int class, tag, constructed, ndef;
for (npeeked=0; npeeked < sizeof peekbuf; npeeked++)
{
c = es_getc (parm->fp);
if (c == EOF)
goto leave;
peekbuf[npeeked] = c;
}
/* Enough to check for a sequence. */
p = peekbuf;
n = npeeked;
err = parse_ber_header (&p, &n, &class, &tag, &constructed,
&ndef, &objlen, &hdrlen);
if (err)
{
log_debug ("%s: error parsing data: %s\n", __func__, gpg_strerror (err));
goto leave;
}
if (class == CLASS_UNIVERSAL && constructed && tag == TAG_SEQUENCE && !ndef)
{
/* We need to add 1 due to the way we implement the limit. */
parm->maxread = objlen + hdrlen + 1;
if (!(parm->maxread < objlen + hdrlen) && parm->maxread)
parm->use_maxread = 1;
found = 1;
}
leave:
while (npeeked)
es_ungetc (peekbuf[--npeeked], parm->fp);
return found;
}
static int static int
simple_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread) simple_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
@ -402,9 +458,55 @@ simple_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
if (!buffer) if (!buffer)
return -1; /* not supported */ return -1; /* not supported */
restart:
if (parm->strip_zeroes)
{
if (parm->strip_zeroes == 1)
{
if (starts_with_sequence (parm))
parm->strip_zeroes = 2; /* Found fixed length sequence. */
else
parm->strip_zeroes = 0; /* Disable zero padding check. */
}
else if (parm->strip_zeroes == 3)
{
/* Limit reached - check that only zeroes follow. */
while (!(c = es_getc (parm->fp)))
parm->nzeroes++;
if (c == EOF)
{ /* only zeroes found. Reset zero padding engine and
* return EOF. */
parm->strip_zeroes = 0;
parm->eof_seen = 1;
return -1;
}
/* Not only zeroes. Reset engine and continue. */
parm->strip_zeroes = 0;
}
}
for (n=0; n < count; n++) for (n=0; n < count; n++)
{ {
c = es_getc (parm->fp); if (parm->use_maxread && !--parm->maxread)
{
parm->use_maxread = 0;
if (parm->strip_zeroes)
{
parm->strip_zeroes = 3;
parm->nzeroes = 0;
if (n)
goto leave; /* Return what we already got. */
goto restart; /* Immediately check for trailing zeroes. */
}
}
if (parm->nzeroes)
{
parm->nzeroes--;
c = 0;
}
else
c = es_getc (parm->fp);
if (c == EOF) if (c == EOF)
{ {
parm->eof_seen = 1; parm->eof_seen = 1;
@ -417,6 +519,7 @@ simple_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
*(byte *)buffer++ = c; *(byte *)buffer++ = c;
} }
leave:
*nread = n; *nread = n;
return 0; return 0;
} }
@ -575,6 +678,7 @@ base64_finish_write (struct writer_cb_parm_s *parm)
* GNUPG_KSBA_IO_MULTIPEM - The reader expects that the caller uses * GNUPG_KSBA_IO_MULTIPEM - The reader expects that the caller uses
* ksba_reader_clear after EOF until no more * ksba_reader_clear after EOF until no more
* objects were found. * objects were found.
* GNUPG_KSBA_IO_STRIP - Strip zero padding from some CMS objects.
* *
* Note that the PEM flag has a higher priority than the BASE64 flag * Note that the PEM flag has a higher priority than the BASE64 flag
* which in turn has a gight priority than the AUTODETECT flag. * which in turn has a gight priority than the AUTODETECT flag.
@ -592,6 +696,7 @@ gnupg_ksba_create_reader (gnupg_ksba_io_t *ctx,
if (!*ctx) if (!*ctx)
return out_of_core (); return out_of_core ();
(*ctx)->u.rparm.allow_multi_pem = !!(flags & GNUPG_KSBA_IO_MULTIPEM); (*ctx)->u.rparm.allow_multi_pem = !!(flags & GNUPG_KSBA_IO_MULTIPEM);
(*ctx)->u.rparm.strip_zeroes = !!(flags & GNUPG_KSBA_IO_STRIP);
rc = ksba_reader_new (&r); rc = ksba_reader_new (&r);
if (rc) if (rc)

View File

@ -36,6 +36,7 @@
#define GNUPG_KSBA_IO_BASE64 2 /* Plain Base64 format. */ #define GNUPG_KSBA_IO_BASE64 2 /* Plain Base64 format. */
#define GNUPG_KSBA_IO_AUTODETECT 4 /* Try to autodetect the format. */ #define GNUPG_KSBA_IO_AUTODETECT 4 /* Try to autodetect the format. */
#define GNUPG_KSBA_IO_MULTIPEM 8 /* Allow more than one PEM chunk. */ #define GNUPG_KSBA_IO_MULTIPEM 8 /* Allow more than one PEM chunk. */
#define GNUPG_KSBA_IO_STRIP 16 /* Strip off zero padding. */
/* Context object. */ /* Context object. */

View File

@ -48,6 +48,8 @@ static struct {
{ "Curve25519", "1.3.6.1.4.1.3029.1.5.1", 255, "cv25519", PUBKEY_ALGO_ECDH }, { "Curve25519", "1.3.6.1.4.1.3029.1.5.1", 255, "cv25519", PUBKEY_ALGO_ECDH },
{ "Ed25519", "1.3.6.1.4.1.11591.15.1", 255, "ed25519", PUBKEY_ALGO_EDDSA }, { "Ed25519", "1.3.6.1.4.1.11591.15.1", 255, "ed25519", PUBKEY_ALGO_EDDSA },
{ "Curve25519", "1.3.101.110", 255, "cv25519", PUBKEY_ALGO_ECDH },
{ "Ed25519", "1.3.101.112", 255, "ed25519", PUBKEY_ALGO_EDDSA },
{ "X448", "1.3.101.111", 448, "cv448", PUBKEY_ALGO_ECDH }, { "X448", "1.3.101.111", 448, "cv448", PUBKEY_ALGO_ECDH },
{ "Ed448", "1.3.101.113", 456, "ed448", PUBKEY_ALGO_EDDSA }, { "Ed448", "1.3.101.113", 456, "ed448", PUBKEY_ALGO_EDDSA },
@ -65,13 +67,17 @@ static struct {
}; };
/* The OID for Curve Ed25519 in OpenPGP format. */ /* The OID for Curve Ed25519 in OpenPGP format. The shorter v5
* variant may only be used with v5 keys. */
static const char oid_ed25519[] = static const char oid_ed25519[] =
{ 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xda, 0x47, 0x0f, 0x01 }; { 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xda, 0x47, 0x0f, 0x01 };
static const char oid_ed25519_v5[] = { 0x03, 0x2b, 0x65, 0x70 };
/* The OID for Curve25519 in OpenPGP format. */ /* The OID for Curve25519 in OpenPGP format. The shorter v5
* variant may only be used with v5 keys. */
static const char oid_cv25519[] = static const char oid_cv25519[] =
{ 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01 }; { 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01 };
static const char oid_cv25519_v5[] = { 0x03, 0x2b, 0x65, 0x6e };
/* The OID for X448 in OpenPGP format. */ /* The OID for X448 in OpenPGP format. */
/* /*
@ -321,8 +327,12 @@ openpgp_oid_to_str (gcry_mpi_t a)
int int
openpgp_oidbuf_is_ed25519 (const void *buf, size_t len) openpgp_oidbuf_is_ed25519 (const void *buf, size_t len)
{ {
return (buf && len == DIM (oid_ed25519) if (!buf)
&& !memcmp (buf, oid_ed25519, DIM (oid_ed25519))); return 0;
return ((len == DIM (oid_ed25519)
&& !memcmp (buf, oid_ed25519, DIM (oid_ed25519)))
|| (len == DIM (oid_ed25519_v5)
&& !memcmp (buf, oid_ed25519_v5, DIM (oid_ed25519_v5))));
} }
@ -345,8 +355,12 @@ openpgp_oid_is_ed25519 (gcry_mpi_t a)
int int
openpgp_oidbuf_is_cv25519 (const void *buf, size_t len) openpgp_oidbuf_is_cv25519 (const void *buf, size_t len)
{ {
return (buf && len == DIM (oid_cv25519) if (!buf)
&& !memcmp (buf, oid_cv25519, DIM (oid_cv25519))); return 0;
return ((len == DIM (oid_cv25519)
&& !memcmp (buf, oid_cv25519, DIM (oid_cv25519)))
|| (len == DIM (oid_cv25519_v5)
&& !memcmp (buf, oid_cv25519_v5, DIM (oid_cv25519_v5))));
} }

View File

@ -174,6 +174,7 @@ find_next_lc (char *string)
* -c The string match in this part is done case-sensitive. * -c The string match in this part is done case-sensitive.
* -t Do not trim leading and trailing spaces from VALUE. * -t Do not trim leading and trailing spaces from VALUE.
* Note that a space after <op> is here required. * Note that a space after <op> is here required.
* -r RFU: String match uses a regular expression
* *
* For example four calls to recsel_parse_expr() with these values for * For example four calls to recsel_parse_expr() with these values for
* EXPR * EXPR
@ -192,7 +193,7 @@ find_next_lc (char *string)
* *
* The caller must pass the address of a selector variable to this * The caller must pass the address of a selector variable to this
* function and initialize the value of the function to NULL before * function and initialize the value of the function to NULL before
* the first call. recset_release needs to be called to free the * the first call. recsel_release needs to be called to free the
* selector. * selector.
*/ */
gpg_error_t gpg_error_t

View File

@ -536,7 +536,8 @@ get_rsa_pk_from_canon_sexp (const unsigned char *keydata, size_t keydatalen,
return err; return err;
if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
return err; return err;
if (!tok || toklen != 10 || memcmp ("public-key", tok, toklen)) if (!tok || !((toklen == 10 && !memcmp ("public-key", tok, toklen))
|| (toklen == 11 && !memcmp ("private-key", tok, toklen))))
return gpg_error (GPG_ERR_BAD_PUBKEY); return gpg_error (GPG_ERR_BAD_PUBKEY);
if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
return err; return err;
@ -1074,6 +1075,8 @@ pubkey_algo_string (gcry_sexp_t s_pkey, enum gcry_pk_algos *r_algoid)
*r_algoid = 0; *r_algoid = 0;
l1 = gcry_sexp_find_token (s_pkey, "public-key", 0); l1 = gcry_sexp_find_token (s_pkey, "public-key", 0);
if (!l1)
l1 = gcry_sexp_find_token (s_pkey, "private-key", 0);
if (!l1) if (!l1)
return xtrystrdup ("E_no_key"); return xtrystrdup ("E_no_key");
{ {

View File

@ -158,7 +158,8 @@ get_inv_recpsgnr_code (gpg_error_t err)
case GPG_ERR_WRONG_KEY_USAGE: errstr = "3"; break; case GPG_ERR_WRONG_KEY_USAGE: errstr = "3"; break;
case GPG_ERR_CERT_REVOKED: errstr = "4"; break; case GPG_ERR_CERT_REVOKED: errstr = "4"; break;
case GPG_ERR_CERT_EXPIRED: errstr = "5"; break; case GPG_ERR_CERT_EXPIRED: errstr = "5"; break;
case GPG_ERR_NO_CRL_KNOWN: errstr = "6"; break; case GPG_ERR_NO_CRL_KNOWN:
case GPG_ERR_INV_CRL_OBJ: errstr = "6"; break;
case GPG_ERR_CRL_TOO_OLD: errstr = "7"; break; case GPG_ERR_CRL_TOO_OLD: errstr = "7"; break;
case GPG_ERR_NO_POLICY_MATCH: errstr = "8"; break; case GPG_ERR_NO_POLICY_MATCH: errstr = "8"; break;

View File

@ -156,8 +156,7 @@ gpg_error_t
parse_ber_header (unsigned char const **buffer, size_t *size, parse_ber_header (unsigned char const **buffer, size_t *size,
int *r_class, int *r_tag, int *r_class, int *r_tag,
int *r_constructed, int *r_ndef, int *r_constructed, int *r_ndef,
size_t *r_length, size_t *r_nhdr) size_t *r_length, size_t *r_nhdr){
{
int c; int c;
unsigned long tag; unsigned long tag;
const unsigned char *buf = *buffer; const unsigned char *buf = *buffer;

View File

@ -58,6 +58,7 @@ endif
noinst_HEADERS = dirmngr.h crlcache.h crlfetch.h misc.h noinst_HEADERS = dirmngr.h crlcache.h crlfetch.h misc.h
dirmngr_SOURCES = dirmngr.c dirmngr.h server.c crlcache.c crlfetch.c \ dirmngr_SOURCES = dirmngr.c dirmngr.h server.c crlcache.c crlfetch.c \
fakecrl.c \
certcache.c certcache.h \ certcache.c certcache.h \
domaininfo.c \ domaininfo.c \
workqueue.c \ workqueue.c \

View File

@ -768,7 +768,7 @@ cert_cache_init (strlist_t hkp_cacerts)
initialization_done = 1; initialization_done = 1;
release_cache_lock (); release_cache_lock ();
cert_cache_print_stats (); cert_cache_print_stats (NULL);
} }
/* Deinitialize the certificate cache. With FULL set to true even the /* Deinitialize the certificate cache. With FULL set to true even the
@ -811,7 +811,7 @@ cert_cache_deinit (int full)
/* Print some statistics to the log file. */ /* Print some statistics to the log file. */
void void
cert_cache_print_stats (void) cert_cache_print_stats (ctrl_t ctrl)
{ {
cert_item_t ci; cert_item_t ci;
int idx; int idx;
@ -848,16 +848,19 @@ cert_cache_print_stats (void)
release_cache_lock (); release_cache_lock ();
log_info (_("permanently loaded certificates: %u\n"), dirmngr_status_helpf (ctrl,
n_permanent); _("permanently loaded certificates: %u\n"),
log_info (_(" runtime cached certificates: %u\n"), n_permanent);
n_nonperm); dirmngr_status_helpf (ctrl,
log_info (_(" trusted certificates: %u (%u,%u,%u,%u)\n"), _(" runtime cached certificates: %u\n"),
n_trusted, n_nonperm);
n_trustclass_system, dirmngr_status_helpf (ctrl,
n_trustclass_config, _(" trusted certificates: %u (%u,%u,%u,%u)\n"),
n_trustclass_hkp, n_trusted,
n_trustclass_hkpspool); n_trustclass_system,
n_trustclass_config,
n_trustclass_hkp,
n_trustclass_hkpspool);
} }

View File

@ -37,7 +37,7 @@ void cert_cache_init (strlist_t hkp_cacerts);
void cert_cache_deinit (int full); void cert_cache_deinit (int full);
/* Print some statistics to the log file. */ /* Print some statistics to the log file. */
void cert_cache_print_stats (void); void cert_cache_print_stats (ctrl_t ctrl);
/* Return true if any cert of a class in MASK is permanently loaded. */ /* Return true if any cert of a class in MASK is permanently loaded. */
int cert_cache_any_in_class (unsigned int mask); int cert_cache_any_in_class (unsigned int mask);

View File

@ -125,6 +125,13 @@
# define O_BINARY 0 # define O_BINARY 0
#endif #endif
/* Reason flags for an invalid CRL. */
#define INVCRL_TOO_OLD 1
#define INVCRL_UNKNOWN_EXTN 2
#define INVCRL_GENERAL 127
static const char oidstr_crlNumber[] = "2.5.29.20"; static const char oidstr_crlNumber[] = "2.5.29.20";
/* static const char oidstr_issuingDistributionPoint[] = "2.5.29.28"; */ /* static const char oidstr_issuingDistributionPoint[] = "2.5.29.28"; */
static const char oidstr_authorityKeyIdentifier[] = "2.5.29.35"; static const char oidstr_authorityKeyIdentifier[] = "2.5.29.35";
@ -157,7 +164,7 @@ struct crl_cache_entry_s
unsigned int cdb_use_count; /* Current use count. */ unsigned int cdb_use_count; /* Current use count. */
unsigned int cdb_lru_count; /* Used for LRU purposes. */ unsigned int cdb_lru_count; /* Used for LRU purposes. */
int dbfile_checked; /* Set to true if the dbfile_hash value has int dbfile_checked; /* Set to true if the dbfile_hash value has
been checked one. */ been checked once. */
}; };
@ -569,8 +576,8 @@ open_dir (crl_cache_t *r_cache)
if (*line == 'i') if (*line == 'i')
{ {
entry->invalid = atoi (line+1); entry->invalid = atoi (line+1);
if (entry->invalid < 1) if (!entry->invalid)
entry->invalid = 1; entry->invalid = INVCRL_GENERAL;
} }
else if (*line == 'u') else if (*line == 'u')
entry->user_trust_req = 1; entry->user_trust_req = 1;
@ -1395,7 +1402,7 @@ cache_isvalid (ctrl_t ctrl, const char *issuer_hash,
{ {
if (opt.verbose) if (opt.verbose)
log_info ("no system trust and client does not trust either\n"); log_info ("no system trust and client does not trust either\n");
retval = CRL_CACHE_CANTUSE; retval = CRL_CACHE_NOTTRUSTED;
} }
else else
{ {
@ -1515,8 +1522,11 @@ crl_cache_cert_isvalid (ctrl_t ctrl, ksba_cert_t cert,
case CRL_CACHE_DONTKNOW: case CRL_CACHE_DONTKNOW:
err = gpg_error (GPG_ERR_NO_CRL_KNOWN); err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
break; break;
case CRL_CACHE_NOTTRUSTED:
err = gpg_error (GPG_ERR_NOT_TRUSTED);
break;
case CRL_CACHE_CANTUSE: case CRL_CACHE_CANTUSE:
err = gpg_error (GPG_ERR_NO_CRL_KNOWN); err = gpg_error (GPG_ERR_INV_CRL_OBJ);
break; break;
default: default:
log_fatal ("cache_isvalid returned invalid status code %d\n", result); log_fatal ("cache_isvalid returned invalid status code %d\n", result);
@ -2097,7 +2107,7 @@ crl_parse_insert (ctrl_t ctrl, ksba_crl_t crl,
} }
} }
while (stopreason != KSBA_SR_READY); while (stopreason != KSBA_SR_READY);
assert (!err); log_assert (!err);
failure: failure:
@ -2338,7 +2348,7 @@ crl_cache_insert (ctrl_t ctrl, const char *url, ksba_reader_t reader)
nextupdate); nextupdate);
if (!err2) if (!err2)
err2 = gpg_error (GPG_ERR_CRL_TOO_OLD); err2 = gpg_error (GPG_ERR_CRL_TOO_OLD);
invalidate_crl |= 1; invalidate_crl |= INVCRL_TOO_OLD;
} }
} }
@ -2353,7 +2363,7 @@ crl_cache_insert (ctrl_t ctrl, const char *url, ksba_reader_t reader)
log_error (_("unknown critical CRL extension %s\n"), oid); log_error (_("unknown critical CRL extension %s\n"), oid);
if (!err2) if (!err2)
err2 = gpg_error (GPG_ERR_INV_CRL); err2 = gpg_error (GPG_ERR_INV_CRL);
invalidate_crl |= 2; invalidate_crl |= INVCRL_UNKNOWN_EXTN;
} }
if (gpg_err_code (err) == GPG_ERR_EOF if (gpg_err_code (err) == GPG_ERR_EOF
|| gpg_err_code (err) == GPG_ERR_NO_DATA ) || gpg_err_code (err) == GPG_ERR_NO_DATA )
@ -2492,6 +2502,7 @@ list_one_crl_entry (crl_cache_t cache, crl_cache_entry_t e, estream_t fp)
int rc; int rc;
int warn = 0; int warn = 0;
const unsigned char *s; const unsigned char *s;
unsigned int invalid;
es_fputs ("--------------------------------------------------------\n", fp ); es_fputs ("--------------------------------------------------------\n", fp );
es_fprintf (fp, _("Begin CRL dump (retrieved via %s)\n"), e->url ); es_fprintf (fp, _("Begin CRL dump (retrieved via %s)\n"), e->url );
@ -2516,13 +2527,20 @@ list_one_crl_entry (crl_cache_t cache, crl_cache_entry_t e, estream_t fp)
!e->user_trust_req? "[system]" : !e->user_trust_req? "[system]" :
e->check_trust_anchor? e->check_trust_anchor:"[missing]"); e->check_trust_anchor? e->check_trust_anchor:"[missing]");
if ((e->invalid & 1)) invalid = e->invalid;
es_fprintf (fp, _(" ERROR: The CRL will not be used " if ((invalid & INVCRL_TOO_OLD))
"because it was still too old after an update!\n")); {
if ((e->invalid & 2)) invalid &= ~INVCRL_TOO_OLD;
es_fprintf (fp, _(" ERROR: The CRL will not be used " es_fprintf (fp, _(" ERROR: The CRL will not be used "
"because it was still too old after an update!\n"));
}
if ((invalid & INVCRL_UNKNOWN_EXTN))
{
invalid &= ~INVCRL_UNKNOWN_EXTN;
es_fprintf (fp, _(" ERROR: The CRL will not be used "
"due to an unknown critical extension!\n")); "due to an unknown critical extension!\n"));
if ((e->invalid & ~3)) }
if (invalid) /* INVCRL_GENERAL or some other bits are set. */
es_fprintf (fp, _(" ERROR: The CRL will not be used\n")); es_fprintf (fp, _(" ERROR: The CRL will not be used\n"));
cdb = lock_db_file (cache, e); cdb = lock_db_file (cache, e);
@ -2714,8 +2732,6 @@ crl_cache_reload_crl (ctrl_t ctrl, ksba_cert_t cert)
any_dist_point = 1; any_dist_point = 1;
if (opt.verbose)
log_info ("fetching CRL from '%s'\n", distpoint_uri);
crl_close_reader (reader); crl_close_reader (reader);
err = crl_fetch (ctrl, distpoint_uri, &reader); err = crl_fetch (ctrl, distpoint_uri, &reader);
if (err) if (err)

View File

@ -27,6 +27,7 @@ typedef enum
CRL_CACHE_VALID = 0, CRL_CACHE_VALID = 0,
CRL_CACHE_INVALID, CRL_CACHE_INVALID,
CRL_CACHE_DONTKNOW, CRL_CACHE_DONTKNOW,
CRL_CACHE_NOTTRUSTED,
CRL_CACHE_CANTUSE CRL_CACHE_CANTUSE
} }
crl_cache_result_t; crl_cache_result_t;
@ -44,6 +45,7 @@ crl_sig_result_t;
struct crl_cache_entry_s; struct crl_cache_entry_s;
typedef struct crl_cache_entry_s *crl_cache_entry_t; typedef struct crl_cache_entry_s *crl_cache_entry_t;
/*-- crlcache.c --*/
void crl_cache_init (void); void crl_cache_init (void);
void crl_cache_deinit (void); void crl_cache_deinit (void);
@ -67,4 +69,11 @@ gpg_error_t crl_cache_load (ctrl_t ctrl, const char *filename);
gpg_error_t crl_cache_reload_crl (ctrl_t ctrl, ksba_cert_t cert); gpg_error_t crl_cache_reload_crl (ctrl_t ctrl, ksba_cert_t cert);
/*-- fakecrl.c --*/
crl_cache_result_t fakecrl_isvalid (ctrl_t ctrl,
const char *issuer_hash,
const char *cert_id);
#endif /* CRLCACHE_H */ #endif /* CRLCACHE_H */

View File

@ -175,6 +175,9 @@ crl_fetch (ctrl_t ctrl, const char *url, ksba_reader_t *reader)
if (!url) if (!url)
return gpg_error (GPG_ERR_INV_ARG); return gpg_error (GPG_ERR_INV_ARG);
if (opt.verbose)
log_info ("fetching CRL from '%s'\n", url);
err = http_parse_uri (&uri, url, 0); err = http_parse_uri (&uri, url, 0);
http_release_parsed_uri (uri); http_release_parsed_uri (uri);
if (!err) /* Yes, our HTTP code groks that. */ if (!err) /* Yes, our HTTP code groks that. */

View File

@ -158,6 +158,7 @@ enum cmd_and_opt_values {
oConnectTimeout, oConnectTimeout,
oConnectQuickTimeout, oConnectQuickTimeout,
oListenBacklog, oListenBacklog,
oFakeCRL,
aTest aTest
}; };
@ -274,7 +275,7 @@ static gpgrt_opt_t opts[] = {
" points to serverlist")), " points to serverlist")),
ARGPARSE_s_i (oLDAPTimeout, "ldaptimeout", ARGPARSE_s_i (oLDAPTimeout, "ldaptimeout",
N_("|N|set LDAP timeout to N seconds")), N_("|N|set LDAP timeout to N seconds")),
ARGPARSE_s_s (oFakeCRL, "fake-crl", "@"),
ARGPARSE_header ("OCSP", N_("Configuration for OCSP")), ARGPARSE_header ("OCSP", N_("Configuration for OCSP")),
@ -324,6 +325,7 @@ static struct debug_flags_s debug_flags [] =
{ DBG_NETWORK_VALUE, "network" }, { DBG_NETWORK_VALUE, "network" },
{ DBG_LOOKUP_VALUE , "lookup" }, { DBG_LOOKUP_VALUE , "lookup" },
{ DBG_EXTPROG_VALUE, "extprog" }, { DBG_EXTPROG_VALUE, "extprog" },
{ DBG_KEEPTMP_VALUE, "keeptmp" },
{ 77, NULL } /* 77 := Do not exit on "help" or "?". */ { 77, NULL } /* 77 := Do not exit on "help" or "?". */
}; };
@ -534,7 +536,7 @@ set_debug (void)
select the highest debug value and would then clutter their select the highest debug value and would then clutter their
disk with debug files which may reveal confidential data. */ disk with debug files which may reveal confidential data. */
if (numok) if (numok)
opt.debug &= ~(DBG_HASHING_VALUE); opt.debug &= ~(DBG_HASHING_VALUE|DBG_KEEPTMP_VALUE);
} }
else else
{ {
@ -708,6 +710,8 @@ parse_rereadable_options (gpgrt_argparse_t *pargs, int reread)
opt.ldaptimeout = DEFAULT_LDAP_TIMEOUT; opt.ldaptimeout = DEFAULT_LDAP_TIMEOUT;
ldapserver_list_needs_reset = 1; ldapserver_list_needs_reset = 1;
opt.debug_cache_expired_certs = 0; opt.debug_cache_expired_certs = 0;
xfree (opt.fake_crl);
opt.fake_crl = NULL;
return 1; return 1;
} }
@ -870,6 +874,11 @@ parse_rereadable_options (gpgrt_argparse_t *pargs, int reread)
opt.debug_cache_expired_certs = 0; opt.debug_cache_expired_certs = 0;
break; break;
case oFakeCRL:
xfree (opt.fake_crl);
opt.fake_crl = *pargs->r.ret_str? xstrdup (pargs->r.ret_str) : NULL;
break;
default: default:
return 0; /* Not handled. */ return 0; /* Not handled. */
} }
@ -2030,8 +2039,9 @@ handle_signal (int signo)
break; break;
case SIGUSR1: case SIGUSR1:
cert_cache_print_stats (); /* See also cmd_getinfo:"stats". */
domaininfo_print_stats (); cert_cache_print_stats (NULL);
domaininfo_print_stats (NULL);
break; break;
case SIGUSR2: case SIGUSR2:

View File

@ -104,6 +104,7 @@ struct
int force; /* Force loading outdated CRLs. */ int force; /* Force loading outdated CRLs. */
char *fake_crl; /* Name of a file with faked CRL entries. */
unsigned int connect_timeout; /* Timeout for connect. */ unsigned int connect_timeout; /* Timeout for connect. */
unsigned int connect_quick_timeout; /* Shorter timeout for connect. */ unsigned int connect_quick_timeout; /* Shorter timeout for connect. */
@ -166,6 +167,7 @@ struct
#define DBG_NETWORK_VALUE 2048 /* debug network I/O. */ #define DBG_NETWORK_VALUE 2048 /* debug network I/O. */
#define DBG_LOOKUP_VALUE 8192 /* debug lookup details */ #define DBG_LOOKUP_VALUE 8192 /* debug lookup details */
#define DBG_EXTPROG_VALUE 16384 /* debug external program calls */ #define DBG_EXTPROG_VALUE 16384 /* debug external program calls */
#define DBG_KEEPTMP_VALUE 32768 /* keep some temporary files */
#define DBG_X509 (opt.debug & DBG_X509_VALUE) #define DBG_X509 (opt.debug & DBG_X509_VALUE)
#define DBG_CRYPTO (opt.debug & DBG_CRYPTO_VALUE) #define DBG_CRYPTO (opt.debug & DBG_CRYPTO_VALUE)
@ -177,6 +179,7 @@ struct
#define DBG_NETWORK (opt.debug & DBG_NETWORK_VALUE) #define DBG_NETWORK (opt.debug & DBG_NETWORK_VALUE)
#define DBG_LOOKUP (opt.debug & DBG_LOOKUP_VALUE) #define DBG_LOOKUP (opt.debug & DBG_LOOKUP_VALUE)
#define DBG_EXTPROG (opt.debug & DBG_EXTPROG_VALUE) #define DBG_EXTPROG (opt.debug & DBG_EXTPROG_VALUE)
#define DBG_KEEPTMP (opt.debug & DBG_KEEPTMP_VALUE)
/* A simple list of certificate references. FIXME: Better use /* A simple list of certificate references. FIXME: Better use
certlist_t also for references (Store NULL at .cert) */ certlist_t also for references (Store NULL at .cert) */
@ -264,7 +267,7 @@ gpg_error_t dirmngr_load_swdb (ctrl_t ctrl, int force);
/*-- domaininfo.c --*/ /*-- domaininfo.c --*/
void domaininfo_print_stats (void); void domaininfo_print_stats (ctrl_t ctrl);
int domaininfo_is_wkd_not_supported (const char *domain); int domaininfo_is_wkd_not_supported (const char *domain);
void domaininfo_set_no_name (const char *domain); void domaininfo_set_no_name (const char *domain);
void domaininfo_set_wkd_supported (const char *domain); void domaininfo_set_wkd_supported (const char *domain);

View File

@ -81,7 +81,7 @@ hash_domain (const char *domain)
void void
domaininfo_print_stats (void) domaininfo_print_stats (ctrl_t ctrl)
{ {
int bidx; int bidx;
domaininfo_t di; domaininfo_t di;
@ -112,11 +112,12 @@ domaininfo_print_stats (void)
if (minlen == -1 || len < minlen) if (minlen == -1 || len < minlen)
minlen = len; minlen = len;
} }
log_info ("domaininfo: items=%d chainlen=%d..%d nn=%d nf=%d ns=%d s=%d\n", dirmngr_status_helpf
count, (ctrl, "domaininfo: items=%d chainlen=%d..%d nn=%d nf=%d ns=%d s=%d\n",
minlen > 0? minlen : 0, count,
maxlen, minlen > 0? minlen : 0,
no_name, wkd_not_found, wkd_not_supported, wkd_supported); maxlen,
no_name, wkd_not_found, wkd_not_supported, wkd_supported);
} }

63
dirmngr/fakecrl.c Normal file
View 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;
}

View File

@ -525,7 +525,7 @@ make_one_filter (const char *pattern, char **r_result)
{ {
/* We need just the BaseDN. This assumes that the Subject /* We need just the BaseDN. This assumes that the Subject
* is correcly stored in the DT. This is however not always * is correcly stored in the DT. This is however not always
* the case and the actual DN is different ffrom the * the case and the actual DN is different from the
* subject. In this case we won't find anything. */ * subject. In this case we won't find anything. */
if (extfilt_need_escape (pattern) if (extfilt_need_escape (pattern)
&& !(pattern = pattern_buffer = extfilt_escape (pattern))) && !(pattern = pattern_buffer = extfilt_escape (pattern)))

View File

@ -1339,6 +1339,10 @@ cmd_isvalid (assuan_context_t ctx, char *line)
} }
else if (only_ocsp) else if (only_ocsp)
err = gpg_error (GPG_ERR_NO_CRL_KNOWN); err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
else if (opt.fake_crl && (err = fakecrl_isvalid (ctrl, issuerhash, serialno)))
{
/* We already got the error code. */
}
else else
{ {
switch (crl_cache_isvalid (ctrl, switch (crl_cache_isvalid (ctrl,
@ -1360,8 +1364,11 @@ cmd_isvalid (assuan_context_t ctx, char *line)
goto again; goto again;
} }
break; break;
case CRL_CACHE_NOTTRUSTED:
err = gpg_error (GPG_ERR_NOT_TRUSTED);
break;
case CRL_CACHE_CANTUSE: case CRL_CACHE_CANTUSE:
err = gpg_error (GPG_ERR_NO_CRL_KNOWN); err = gpg_error (GPG_ERR_INV_CRL_OBJ);
break; break;
default: default:
log_fatal ("crl_cache_isvalid returned invalid code\n"); log_fatal ("crl_cache_isvalid returned invalid code\n");
@ -1374,7 +1381,7 @@ cmd_isvalid (assuan_context_t ctx, char *line)
/* If the line contains a SHA-1 fingerprint as the first argument, /* If the line contains a SHA-1 fingerprint as the first argument,
return the FPR vuffer on success. The function checks that the return the FPR buffer on success. The function checks that the
fingerprint consists of valid characters and prints and error fingerprint consists of valid characters and prints and error
message if it does not and returns NULL. Fingerprints are message if it does not and returns NULL. Fingerprints are
considered optional and thus no explicit error is returned. NULL is considered optional and thus no explicit error is returned. NULL is
@ -1469,7 +1476,7 @@ cmd_checkcrl (assuan_context_t ctx, char *line)
goto leave; goto leave;
} }
assert (cert); log_assert (cert);
err = crl_cache_cert_isvalid (ctrl, cert, ctrl->force_crl_refresh); err = crl_cache_cert_isvalid (ctrl, cert, ctrl->force_crl_refresh);
if (gpg_err_code (err) == GPG_ERR_NO_CRL_KNOWN) if (gpg_err_code (err) == GPG_ERR_NO_CRL_KNOWN)
@ -2785,13 +2792,14 @@ static const char hlp_getinfo[] =
"Multi purpose command to return certain information. \n" "Multi purpose command to return certain information. \n"
"Supported values of WHAT are:\n" "Supported values of WHAT are:\n"
"\n" "\n"
"version - Return the version of the program.\n" "version - Return the version of the program\n"
"pid - Return the process id of the server.\n" "pid - Return the process id of the server\n"
"tor - Return OK if running in Tor mode\n" "tor - Return OK if running in Tor mode\n"
"dnsinfo - Return info about the DNS resolver\n" "dnsinfo - Return info about the DNS resolver\n"
"socket_name - Return the name of the socket.\n" "socket_name - Return the name of the socket\n"
"session_id - Return the current session_id.\n" "session_id - Return the current session_id\n"
"workqueue - Inspect the work queue\n" "workqueue - Inspect the work queue\n"
"stats - Print stats\n"
"getenv NAME - Return value of envvar NAME\n"; "getenv NAME - Return value of envvar NAME\n";
static gpg_error_t static gpg_error_t
cmd_getinfo (assuan_context_t ctx, char *line) cmd_getinfo (assuan_context_t ctx, char *line)
@ -2860,6 +2868,12 @@ cmd_getinfo (assuan_context_t ctx, char *line)
workqueue_dump_queue (ctrl); workqueue_dump_queue (ctrl);
err = 0; err = 0;
} }
else if (!strcmp (line, "stats"))
{
cert_cache_print_stats (ctrl);
domaininfo_print_stats (ctrl);
err = 0;
}
else if (!strncmp (line, "getenv", 6) else if (!strncmp (line, "getenv", 6)
&& (line[6] == ' ' || line[6] == '\t' || !line[6])) && (line[6] == ' ' || line[6] == '\t' || !line[6]))
{ {
@ -3218,7 +3232,8 @@ dirmngr_status_help (ctrl_t ctrl, const char *text)
/* Print a help status line using a printf like format. The function /* Print a help status line using a printf like format. The function
* splits text at LFs. */ * splits text at LFs. With CTRL beeing NULL, the function behaves
* like log_info. */
gpg_error_t gpg_error_t
dirmngr_status_helpf (ctrl_t ctrl, const char *format, ...) dirmngr_status_helpf (ctrl_t ctrl, const char *format, ...)
{ {
@ -3227,12 +3242,20 @@ dirmngr_status_helpf (ctrl_t ctrl, const char *format, ...)
char *buf; char *buf;
va_start (arg_ptr, format); va_start (arg_ptr, format);
buf = es_vbsprintf (format, arg_ptr); if (ctrl)
err = buf? 0 : gpg_error_from_syserror (); {
buf = es_vbsprintf (format, arg_ptr);
err = buf? 0 : gpg_error_from_syserror ();
if (!err)
err = dirmngr_status_help (ctrl, buf);
es_free (buf);
}
else
{
log_logv (GPGRT_LOGLVL_INFO, format, arg_ptr);
err = 0;
}
va_end (arg_ptr); va_end (arg_ptr);
if (!err)
err = dirmngr_status_help (ctrl, buf);
es_free (buf);
return err; return err;
} }

View File

@ -255,6 +255,7 @@ check_revocations (ctrl_t ctrl, chain_item_t chain)
int any_revoked = 0; int any_revoked = 0;
int any_no_crl = 0; int any_no_crl = 0;
int any_crl_too_old = 0; int any_crl_too_old = 0;
int any_not_trusted = 0;
chain_item_t ci; chain_item_t ci;
log_assert (ctrl->check_revocations_nest_level >= 0); log_assert (ctrl->check_revocations_nest_level >= 0);
@ -266,7 +267,8 @@ check_revocations (ctrl_t ctrl, chain_item_t chain)
return gpg_error(GPG_ERR_BAD_CERT_CHAIN); return gpg_error(GPG_ERR_BAD_CERT_CHAIN);
} }
ctrl->check_revocations_nest_level++; ctrl->check_revocations_nest_level++;
if (opt.verbose)
log_info ("[%d] start checking CRLs\n", ctrl->check_revocations_nest_level);
for (ci=chain; ci; ci = ci->next) for (ci=chain; ci; ci = ci->next)
{ {
@ -293,17 +295,19 @@ check_revocations (ctrl_t ctrl, chain_item_t chain)
if (!err) if (!err)
err = crl_cache_cert_isvalid (ctrl, ci->cert, 0); err = crl_cache_cert_isvalid (ctrl, ci->cert, 0);
} }
if (opt.verbose)
log_info ("[%d] result of checking this CRL: %s\n",
ctrl->check_revocations_nest_level, gpg_strerror (err));
switch (gpg_err_code (err)) switch (gpg_err_code (err))
{ {
case 0: err = 0; break; case 0: err = 0; break;
case GPG_ERR_CERT_REVOKED: any_revoked = 1; err = 0; break; case GPG_ERR_CERT_REVOKED: any_revoked = 1; err = 0; break;
case GPG_ERR_NO_CRL_KNOWN: any_no_crl = 1; err = 0; break; case GPG_ERR_NO_CRL_KNOWN: any_no_crl = 1; err = 0; break;
case GPG_ERR_NOT_TRUSTED: any_not_trusted = 1; err = 0; break;
case GPG_ERR_CRL_TOO_OLD: any_crl_too_old = 1; err = 0; break; case GPG_ERR_CRL_TOO_OLD: any_crl_too_old = 1; err = 0; break;
default: break; default: break;
} }
} }
ctrl->check_revocations_nest_level--;
if (err) if (err)
; ;
@ -311,10 +315,16 @@ check_revocations (ctrl_t ctrl, chain_item_t chain)
err = gpg_error (GPG_ERR_CERT_REVOKED); err = gpg_error (GPG_ERR_CERT_REVOKED);
else if (any_no_crl) else if (any_no_crl)
err = gpg_error (GPG_ERR_NO_CRL_KNOWN); err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
else if (any_not_trusted)
err = gpg_error (GPG_ERR_NOT_TRUSTED);
else if (any_crl_too_old) else if (any_crl_too_old)
err = gpg_error (GPG_ERR_CRL_TOO_OLD); err = gpg_error (GPG_ERR_CRL_TOO_OLD);
else else
err = 0; err = 0;
if (opt.verbose)
log_info ("[%d] result of checking all CRLs: %s\n",
ctrl->check_revocations_nest_level, gpg_strerror (err));
ctrl->check_revocations_nest_level--;
return err; return err;
} }

View File

@ -59,7 +59,7 @@ workqueue_dump_queue (ctrl_t ctrl)
wqitem_t item; wqitem_t item;
unsigned int count; unsigned int count;
/* Temporarily detach the entiere workqueue so that other threads don't /* Temporarily detach the entire workqueue so that other threads don't
* get into our way. */ * get into our way. */
saved_workqueue = workqueue; saved_workqueue = workqueue;
workqueue = NULL; workqueue = NULL;
@ -74,8 +74,8 @@ workqueue_dump_queue (ctrl_t ctrl)
item->func? item->func (NULL, NULL): "nop", item->func? item->func (NULL, NULL): "nop",
item->args, strlen (item->args) > 100? "[...]":""); item->args, strlen (item->args) > 100? "[...]":"");
/* Restore then workqueue. Actually we append the saved queue do a /* Restore the workqueue. Actually we append the saved queue to
* possibly updated workqueue. */ * handle a possibly updated workqueue. */
if (!(item=workqueue)) if (!(item=workqueue))
workqueue = saved_workqueue; workqueue = saved_workqueue;
else else

View File

@ -1183,6 +1183,17 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
send to the client instead of this status line. Such an inquiry send to the client instead of this status line. Such an inquiry
may be used to sync with Pinentry may be used to sync with Pinentry
*** GPGTAR_EXTRACT <tot> <skp> <bad> <sus> <sym> <hrd> <oth>
This status line is emitted after gpgtar has extracted files.
- tot :: Total number of files extracted and stored
- skp :: Total number of files skipped during extraction
- bad :: Number of files skipped due to a bad file name
- sus :: Number of files skipped due to a suspicious file name
- sym :: Number of symlinks not restored
- hrd :: Number of hard links not restored
- oth :: Number of files not extracted due to other reasons.
** Obsolete status codes ** Obsolete status codes
*** SIGEXPIRED *** SIGEXPIRED
Removed on 2011-02-04. This is deprecated in favor of KEYEXPIRED. Removed on 2011-02-04. This is deprecated in favor of KEYEXPIRED.
@ -1706,15 +1717,21 @@ Description of some debug flags:
- RFC-5915 :: ECC Private Key Structure - RFC-5915 :: ECC Private Key Structure
- RFC-5958 :: Asymmetric Key Packages - RFC-5958 :: Asymmetric Key Packages
- RFC-6337 :: ECC in OpenPGP - RFC-6337 :: ECC in OpenPGP
- RFC-7748 :: Elliptic Curves for Security (X25519 and X448)
- RFC-8410 :: Algorithm Identifiers for Ed25519, Ed448, X25519, and X448
- RFC-7292 :: PKCS #12: Personal Information Exchange Syntax v1.1 - RFC-7292 :: PKCS #12: Personal Information Exchange Syntax v1.1
- RFC-8351 :: The PKCS #8 EncryptedPrivateKeyInfo Media Type - RFC-8351 :: The PKCS #8 EncryptedPrivateKeyInfo Media Type
- RFC-8550 :: S/MIME Version 4.0 Certificate Handling - RFC-8550 :: S/MIME Version 4.0 Certificate Handling
- RFC-8551 :: S/MIME Version 4.0 Message Specification - RFC-8551 :: S/MIME Version 4.0 Message Specification
- RFC-2634 :: Enhanced Security Services for S/MIME - RFC-2634 :: Enhanced Security Services for S/MIME
- RFC-5035 :: Enhanced Security Services (ESS) Update - RFC-5035 :: Enhanced Security Services (ESS) Update
- RFC-7253 :: The OCB Authenticated-Encryption Algorithm
- draft-koch-openpgp-2015-rfc4880bis :: Updates to RFC-4880 - draft-koch-openpgp-2015-rfc4880bis :: Updates to RFC-4880
- T6390 :: Notes on use of X25519 in GnuPG (https://dev.gnupg.org/T6390)
** v3 fingerprints ** v3 fingerprints
For packet version 3 we calculate the keyids this way: For packet version 3 we calculate the keyids this way:
- RSA :: Low 64 bits of n - RSA :: Low 64 bits of n
@ -1724,17 +1741,10 @@ Description of some debug flags:
** gnupg.org notations ** gnupg.org notations
- adsk@gnupg.org :: Additional decryption subkey. This notation - rem@gnupg.org :: Used by Kleopatra to implement the tag feature.
gives a list of keys an implementation SHOULD These tags are used to mark keys for easier
also encrypt to. The data consists of an array searching and grouping.
of eight-octet numbers holding the Key ID of an
encryption subkey. This notation is only valid
on an encryption subkey (i.e. with first octet
of the key flags 0x04 or 0x08). Subkeys not on
the same keyblock MUST NOT be considered. For
interoperability this notation SHOULD NOT be
marked as criticial. Due to its nature it MUST
NOT be marked as human readable.
** Simplified revocation certificates ** Simplified revocation certificates
Revocation certificates consist only of the signature packet; Revocation certificates consist only of the signature packet;

View File

@ -615,15 +615,11 @@ remote machine.
@itemx --disable-extended-key-format @itemx --disable-extended-key-format
@opindex enable-extended-key-format @opindex enable-extended-key-format
@opindex disable-extended-key-format @opindex disable-extended-key-format
Since version 2.3 keys are created in the extended private key format. These options are obsolete and have no effect. The extended key format
Changing the passphrase of a key will also convert the key to that new is used for years now and has been supported since 2.1.12. Existing
format. This new key format is supported since GnuPG version 2.1.12 keys in the old format are migrated to the new format as soon as they
and thus there should be no need to disable it. The disable option are touched.
allows to revert to the old behavior for new keys; be aware that keys
are never migrated back to the old format. However if the enable
option has been used the disable option won't have an effect. The
advantage of the extended private key format is that it is text based
and can carry additional meta data.
@anchor{option --enable-ssh-support} @anchor{option --enable-ssh-support}
@item --enable-ssh-support @item --enable-ssh-support

View File

@ -1067,6 +1067,15 @@ signing.
"sensitive". If a designated revoker is marked as sensitive, it will "sensitive". If a designated revoker is marked as sensitive, it will
not be exported by default (see export-options). not be exported by default (see export-options).
@item addadsk
@opindex keyedit:addadsk
Add an Additional Decryption Subkey. The user is asked to enter the
fingerprint of another encryption subkey. Note that the exact
fingerprint of another key's encryption subkey needs to be entered.
This is because commonly the primary key has no encryption
capability. Use the option @option{--with-subkey-fingerprint} with
a list command to display the subkey fingerprints.
@item passwd @item passwd
@opindex keyedit:passwd @opindex keyedit:passwd
Change the passphrase of the secret key. Change the passphrase of the secret key.
@ -3190,6 +3199,10 @@ Write log output to file descriptor @var{n} and not to STDERR.
Same as @option{--logger-fd}, except the logger data is written to Same as @option{--logger-fd}, except the logger data is written to
file @var{file}. Use @file{socket://} to log to s socket. file @var{file}. Use @file{socket://} to log to s socket.
@item --log-time
@opindex log-time
Prefix all log output with a timestamp even if no log file is used.
@item --attribute-fd @var{n} @item --attribute-fd @var{n}
@opindex attribute-fd @opindex attribute-fd
Write attribute subpackets to the file descriptor @var{n}. This is most Write attribute subpackets to the file descriptor @var{n}. This is most

View File

@ -408,6 +408,10 @@ Do not print a warning when the so called "secure memory" cannot be used.
When running in server mode, append all logging output to @var{file}. When running in server mode, append all logging output to @var{file}.
Use @file{socket://} to log to socket. Use @file{socket://} to log to socket.
@item --log-time
@opindex log-time
Prefix all log output with a timestamp even if no log file is used.
@end table @end table
@ -492,8 +496,10 @@ This usually means that Dirmngr is employed to search for the
certificate. Note that this option makes a "web bug" like behavior certificate. Note that this option makes a "web bug" like behavior
possible. LDAP server operators can see which keys you request, so by possible. LDAP server operators can see which keys you request, so by
sending you a message signed by a brand new key (which you naturally sending you a message signed by a brand new key (which you naturally
will not have on your local keybox), the operator can tell both your IP will not have on your local keybox), the operator can tell both your
address and the time when you verified the signature. IP address and the time when you verified the signature. Note that if
CRL checking is not disabled issuer certificates are retrieved in any
case using the caIssuers authorityInfoAccess method.
@anchor{gpgsm-option --validation-model} @anchor{gpgsm-option --validation-model}
@ -623,6 +629,15 @@ always listed in @option{--with-colons} mode.
Include info about the presence of a secret key in public key listings Include info about the presence of a secret key in public key listings
done with @code{--with-colons}. done with @code{--with-colons}.
@item --no-pretty-dn
@opindex no-pretty-dn
By default gpgsm prints distinguished names (DNs) like the Issuer or
Subject in a more readable format (e.g. using a well defined order of
the parts). However, this format can't be used as input strings.
This option reverts printing to standard RFC-2253 format and thus
avoids the need to use --dump-cert or --with-colons to get the
``real'' name.
@end table @end table
@c ******************************************* @c *******************************************

View File

@ -1345,19 +1345,23 @@ build_sig_subpkt (PKT_signature *sig, sigsubpkttype_t type,
/* /*
* Put all the required stuff from SIG into subpackets of sig. * Put all the required stuff from SIG into subpackets of sig.
* PKSK is the signing key. * PKSK is the signing key. SIGNHINTS are various flags like
* SIGNHINT_ADSK.
* Hmmm, should we delete those subpackets which are in a wrong area? * Hmmm, should we delete those subpackets which are in a wrong area?
*/ */
void void
build_sig_subpkt_from_sig (PKT_signature *sig, PKT_public_key *pksk) build_sig_subpkt_from_sig (PKT_signature *sig, PKT_public_key *pksk,
unsigned int signhints)
{ {
u32 u; u32 u;
byte buf[1+MAX_FINGERPRINT_LEN]; byte buf[1+MAX_FINGERPRINT_LEN];
size_t fprlen; size_t fprlen;
/* For v4 keys we need to write the ISSUER subpacket. We do not /* For v4 keys we need to write the ISSUER subpacket. We do not
* want that for a future v5 format. */ * want that for a future v5 format. We also don't write it if
if (pksk->version < 5) * only the new RENC keyflag is set (implementations with support
* for this key flag should understand the ISSUER_FPR). */
if (pksk->version < 5 && !(signhints & SIGNHINT_ADSK))
{ {
u = sig->keyid[0]; u = sig->keyid[0];
buf[0] = (u >> 24) & 0xff; buf[0] = (u >> 24) & 0xff;

View File

@ -1781,12 +1781,13 @@ card_generate_subkey (ctrl_t ctrl, kbnode_t pub_keyblock)
} }
/* Store the key at NODE into the smartcard and modify NODE to /* Store the key at NODE into the smartcard and modify NODE to carry
carry the serialno stuff instead of the actual secret key the serialno stuff instead of the actual secret key parameters.
parameters. USE is the usage for that key; 0 means any USE is the usage for that key; 0 means any usage. If
usage. */ PROCESSED_KEYS is not NULL it is a poiter to an strlist which will
be filled with the keygrips of successfully stored keys. */
int int
card_store_subkey (KBNODE node, int use) card_store_subkey (KBNODE node, int use, strlist_t *processed_keys)
{ {
struct agent_card_info_s info; struct agent_card_info_s info;
int okay = 0; int okay = 0;
@ -1875,7 +1876,11 @@ card_store_subkey (KBNODE node, int use)
if (rc) if (rc)
log_error (_("KEYTOCARD failed: %s\n"), gpg_strerror (rc)); log_error (_("KEYTOCARD failed: %s\n"), gpg_strerror (rc));
else else
okay = 1; {
okay = 1;
if (processed_keys)
add_to_strlist (processed_keys, hexgrip);
}
xfree (hexgrip); xfree (hexgrip);
leave: leave:

View File

@ -211,10 +211,10 @@ copy_prefs (const prefitem_t *prefs)
/* Copy the public key S to D. If D is NULL allocate a new public key /* Copy the public key S to D. If D is NULL allocate a new public key
structure. If S has seckret key infos, only the public stuff is * structure. Only the basic stuff is copied; not any ancillary
copied. */ * data. */
PKT_public_key * PKT_public_key *
copy_public_key (PKT_public_key *d, PKT_public_key *s) copy_public_key_basics (PKT_public_key *d, PKT_public_key *s)
{ {
int n, i; int n, i;
@ -222,8 +222,8 @@ copy_public_key (PKT_public_key *d, PKT_public_key *s)
d = xmalloc (sizeof *d); d = xmalloc (sizeof *d);
memcpy (d, s, sizeof *d); memcpy (d, s, sizeof *d);
d->seckey_info = NULL; d->seckey_info = NULL;
d->user_id = scopy_user_id (s->user_id); d->user_id = NULL;
d->prefs = copy_prefs (s->prefs); d->prefs = NULL;
n = pubkey_get_npkey (s->pubkey_algo); n = pubkey_get_npkey (s->pubkey_algo);
i = 0; i = 0;
@ -237,6 +237,24 @@ copy_public_key (PKT_public_key *d, PKT_public_key *s)
for (; i < PUBKEY_MAX_NSKEY; i++) for (; i < PUBKEY_MAX_NSKEY; i++)
d->pkey[i] = NULL; d->pkey[i] = NULL;
d->revkey = NULL;
d->serialno = NULL;
d->updateurl = NULL;
return d;
}
/* Copy the public key S to D. If D is NULL allocate a new public key
structure. If S has seckret key infos, only the public stuff is
copied. */
PKT_public_key *
copy_public_key (PKT_public_key *d, PKT_public_key *s)
{
d = copy_public_key_basics (d, s);
d->user_id = scopy_user_id (s->user_id);
d->prefs = copy_prefs (s->prefs);
if (!s->revkey && s->numrevkeys) if (!s->revkey && s->numrevkeys)
BUG(); BUG();
if (s->numrevkeys) if (s->numrevkeys)
@ -244,8 +262,6 @@ copy_public_key (PKT_public_key *d, PKT_public_key *s)
d->revkey = xmalloc(sizeof(struct revocation_key)*s->numrevkeys); d->revkey = xmalloc(sizeof(struct revocation_key)*s->numrevkeys);
memcpy(d->revkey,s->revkey,sizeof(struct revocation_key)*s->numrevkeys); memcpy(d->revkey,s->revkey,sizeof(struct revocation_key)*s->numrevkeys);
} }
else
d->revkey = NULL;
if (s->serialno) if (s->serialno)
d->serialno = xstrdup (s->serialno); d->serialno = xstrdup (s->serialno);

View File

@ -1718,7 +1718,8 @@ get_best_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
* *
* This function returns 0 on success. Otherwise, an error code is * This function returns 0 on success. Otherwise, an error code is
* returned. In particular, GPG_ERR_NO_PUBKEY is returned if the key * returned. In particular, GPG_ERR_NO_PUBKEY is returned if the key
* is not found. * is not found. If R_KEYBLOCK is not NULL and a key was found the
* keyblock is stored there; otherwiese NULL is stored there.
* *
* The self-signed data has already been merged into the public key * The self-signed data has already been merged into the public key
* using merge_selfsigs. The caller must release the content of PK by * using merge_selfsigs. The caller must release the content of PK by
@ -1726,13 +1727,17 @@ get_best_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
* free_public_key). * free_public_key).
*/ */
gpg_error_t gpg_error_t
get_pubkey_fromfile (ctrl_t ctrl, PKT_public_key *pk, const char *fname) get_pubkey_fromfile (ctrl_t ctrl, PKT_public_key *pk, const char *fname,
kbnode_t *r_keyblock)
{ {
gpg_error_t err; gpg_error_t err;
kbnode_t keyblock; kbnode_t keyblock;
kbnode_t found_key; kbnode_t found_key;
unsigned int infoflags; unsigned int infoflags;
if (r_keyblock)
*r_keyblock = NULL;
err = read_key_from_file_or_buffer (ctrl, fname, NULL, 0, &keyblock); err = read_key_from_file_or_buffer (ctrl, fname, NULL, 0, &keyblock);
if (!err) if (!err)
{ {
@ -1747,7 +1752,10 @@ get_pubkey_fromfile (ctrl_t ctrl, PKT_public_key *pk, const char *fname)
err = gpg_error (GPG_ERR_UNUSABLE_PUBKEY); err = gpg_error (GPG_ERR_UNUSABLE_PUBKEY);
} }
release_kbnode (keyblock); if (!err && r_keyblock)
*r_keyblock = keyblock;
else
release_kbnode (keyblock);
return err; return err;
} }
@ -1809,12 +1817,12 @@ get_pubkey_from_buffer (ctrl_t ctrl, PKT_public_key *pkbuf,
* returned public key may be a subkey rather than the primary key. * returned public key may be a subkey rather than the primary key.
* Note: The self-signed data has already been merged into the public * Note: The self-signed data has already been merged into the public
* key using merge_selfsigs. Free *PK by calling * key using merge_selfsigs. Free *PK by calling
* release_public_key_parts (or, if PK was allocated using xfree, you * release_public_key_parts (or, if PK was allocated using xmalloc, you
* can use free_public_key, which calls release_public_key_parts(PK) * can use free_public_key, which calls release_public_key_parts(PK)
* and then xfree(PK)). * and then xfree(PK)).
* *
* If PK->REQ_USAGE is set, it is used to filter the search results. * If PK->REQ_USAGE is set, it is used to filter the search results.
* (Thus, if PK is not NULL, PK->REQ_USAGE must be valid!!!) See the * Thus, if PK is not NULL, PK->REQ_USAGE must be valid! See the
* documentation for finish_lookup to understand exactly how this is * documentation for finish_lookup to understand exactly how this is
* used. * used.
* *
@ -2417,7 +2425,8 @@ merge_keys_and_selfsig (ctrl_t ctrl, kbnode_t keyblock)
} }
static int /* This function parses the key flags and returns PUBKEY_USAGE_ flags. */
unsigned int
parse_key_usage (PKT_signature * sig) parse_key_usage (PKT_signature * sig)
{ {
int key_usage = 0; int key_usage = 0;

View File

@ -337,6 +337,7 @@ enum cmd_and_opt_values
oEncryptToDefaultKey, oEncryptToDefaultKey,
oLoggerFD, oLoggerFD,
oLoggerFile, oLoggerFile,
oLogTime,
oUtf8Strings, oUtf8Strings,
oNoUtf8Strings, oNoUtf8Strings,
oDisableCipherAlgo, oDisableCipherAlgo,
@ -600,6 +601,7 @@ static gpgrt_opt_t opts[] = {
ARGPARSE_s_s (oLoggerFile, "log-file", ARGPARSE_s_s (oLoggerFile, "log-file",
N_("|FILE|write server mode logs to FILE")), N_("|FILE|write server mode logs to FILE")),
ARGPARSE_s_s (oLoggerFile, "logger-file", "@"), /* 1.4 compatibility. */ ARGPARSE_s_s (oLoggerFile, "logger-file", "@"), /* 1.4 compatibility. */
ARGPARSE_s_n (oLogTime, "log-time", "@"),
ARGPARSE_s_n (oQuickRandom, "debug-quick-random", "@"), ARGPARSE_s_n (oQuickRandom, "debug-quick-random", "@"),
@ -1041,6 +1043,7 @@ static int utf8_strings =
static int maybe_setuid = 1; static int maybe_setuid = 1;
static unsigned int opt_set_iobuf_size; static unsigned int opt_set_iobuf_size;
static unsigned int opt_set_iobuf_size_used; static unsigned int opt_set_iobuf_size_used;
static int opt_log_time;
/* Collection of options used only in this module. */ /* Collection of options used only in this module. */
static struct { static struct {
@ -2864,6 +2867,9 @@ main (int argc, char **argv)
case oLoggerFile: case oLoggerFile:
logfile = pargs.r.ret_str; logfile = pargs.r.ret_str;
break; break;
case oLogTime:
opt_log_time = 1;
break;
case oWithFingerprint: case oWithFingerprint:
opt.with_fingerprint = 1; opt.with_fingerprint = 1;
@ -3829,6 +3835,9 @@ main (int argc, char **argv)
| GPGRT_LOG_WITH_TIME | GPGRT_LOG_WITH_TIME
| GPGRT_LOG_WITH_PID )); | GPGRT_LOG_WITH_PID ));
} }
else if (opt_log_time)
log_set_prefix (NULL, (GPGRT_LOG_WITH_PREFIX|GPGRT_LOG_NO_REGISTRY
|GPGRT_LOG_WITH_TIME));
if (opt.verbose > 2) if (opt.verbose > 2)
log_info ("using character set '%s'\n", get_native_charset ()); log_info ("using character set '%s'\n", get_native_charset ());

View File

@ -391,7 +391,8 @@ gpg_error_t get_best_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
/* Get a public key directly from file FNAME. */ /* Get a public key directly from file FNAME. */
gpg_error_t get_pubkey_fromfile (ctrl_t ctrl, gpg_error_t get_pubkey_fromfile (ctrl_t ctrl,
PKT_public_key *pk, const char *fname); PKT_public_key *pk, const char *fname,
kbnode_t *r_keyblock);
/* Get a public key from a buffer. */ /* Get a public key from a buffer. */
gpg_error_t get_pubkey_from_buffer (ctrl_t ctrl, PKT_public_key *pkbuf, gpg_error_t get_pubkey_from_buffer (ctrl_t ctrl, PKT_public_key *pkbuf,
@ -468,6 +469,9 @@ void setup_main_keyids (kbnode_t keyblock);
data structures. */ data structures. */
void merge_keys_and_selfsig (ctrl_t ctrl, kbnode_t keyblock); void merge_keys_and_selfsig (ctrl_t ctrl, kbnode_t keyblock);
/* This function parses the key flags and returns PUBKEY_USAGE_ flags. */
unsigned int parse_key_usage (PKT_signature *sig);
char *get_user_id_string_native (ctrl_t ctrl, u32 *keyid); char *get_user_id_string_native (ctrl_t ctrl, u32 *keyid);
char *get_long_user_id_string (ctrl_t ctrl, u32 *keyid); char *get_long_user_id_string (ctrl_t ctrl, u32 *keyid);
char *get_user_id (ctrl_t ctrl, u32 *keyid, size_t *rn, int *r_nouid); char *get_user_id (ctrl_t ctrl, u32 *keyid, size_t *rn, int *r_nouid);

View File

@ -1,7 +1,7 @@
/* keyedit.c - Edit properties of a key /* keyedit.c - Edit properties of a key
* Copyright (C) 1998-2010 Free Software Foundation, Inc. * Copyright (C) 1998-2010 Free Software Foundation, Inc.
* Copyright (C) 1998-2017 Werner Koch * Copyright (C) 1998-2017 Werner Koch
* Copyright (C) 2015, 2016, 2022 g10 Code GmbH * Copyright (C) 2015, 2016, 2022-2023 g10 Code GmbH
* *
* This file is part of GnuPG. * This file is part of GnuPG.
* *
@ -73,6 +73,7 @@ static int menu_delsig (ctrl_t ctrl, kbnode_t pub_keyblock);
static int menu_clean (ctrl_t ctrl, kbnode_t keyblock, int self_only); static int menu_clean (ctrl_t ctrl, kbnode_t keyblock, int self_only);
static void menu_delkey (KBNODE pub_keyblock); static void menu_delkey (KBNODE pub_keyblock);
static int menu_addrevoker (ctrl_t ctrl, kbnode_t pub_keyblock, int sensitive); static int menu_addrevoker (ctrl_t ctrl, kbnode_t pub_keyblock, int sensitive);
static int menu_addadsk (ctrl_t ctrl, kbnode_t pub_keyblock);
static gpg_error_t menu_expire (ctrl_t ctrl, kbnode_t pub_keyblock, static gpg_error_t menu_expire (ctrl_t ctrl, kbnode_t pub_keyblock,
int unattended, u32 newexpiration); int unattended, u32 newexpiration);
static int menu_changeusage (ctrl_t ctrl, kbnode_t keyblock); static int menu_changeusage (ctrl_t ctrl, kbnode_t keyblock);
@ -1243,7 +1244,7 @@ enum cmdids
cmdREVSIG, cmdREVKEY, cmdREVUID, cmdDELSIG, cmdPRIMARY, cmdDEBUG, cmdREVSIG, cmdREVKEY, cmdREVUID, cmdDELSIG, cmdPRIMARY, cmdDEBUG,
cmdSAVE, cmdADDUID, cmdADDPHOTO, cmdDELUID, cmdADDKEY, cmdDELKEY, cmdSAVE, cmdADDUID, cmdADDPHOTO, cmdDELUID, cmdADDKEY, cmdDELKEY,
cmdADDREVOKER, cmdTOGGLE, cmdSELKEY, cmdPASSWD, cmdTRUST, cmdPREF, cmdADDREVOKER, cmdTOGGLE, cmdSELKEY, cmdPASSWD, cmdTRUST, cmdPREF,
cmdEXPIRE, cmdCHANGEUSAGE, cmdBACKSIGN, cmdEXPIRE, cmdCHANGEUSAGE, cmdBACKSIGN, cmdADDADSK,
#ifndef NO_TRUST_MODELS #ifndef NO_TRUST_MODELS
cmdENABLEKEY, cmdDISABLEKEY, cmdENABLEKEY, cmdDISABLEKEY,
#endif /*!NO_TRUST_MODELS*/ #endif /*!NO_TRUST_MODELS*/
@ -1308,6 +1309,8 @@ static struct
{ "delkey", cmdDELKEY, 0, N_("delete selected subkeys")}, { "delkey", cmdDELKEY, 0, N_("delete selected subkeys")},
{ "addrevoker", cmdADDREVOKER, KEYEDIT_NEED_SK, { "addrevoker", cmdADDREVOKER, KEYEDIT_NEED_SK,
N_("add a revocation key")}, N_("add a revocation key")},
{ "addadsk", cmdADDADSK, KEYEDIT_NEED_SK,
N_("add additional decryption subkeys")},
{ "delsig", cmdDELSIG, 0, { "delsig", cmdDELSIG, 0,
N_("delete signatures from the selected user IDs")}, N_("delete signatures from the selected user IDs")},
{ "expire", cmdEXPIRE, KEYEDIT_NEED_SK | KEYEDIT_NEED_SUBSK, { "expire", cmdEXPIRE, KEYEDIT_NEED_SK | KEYEDIT_NEED_SUBSK,
@ -1421,6 +1424,8 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
int sec_shadowing = 0; int sec_shadowing = 0;
int run_subkey_warnings = 0; int run_subkey_warnings = 0;
int have_commands = !!commands; int have_commands = !!commands;
strlist_t delseckey_list = NULL;
int delseckey_list_warn = 0;
if (opt.command_fd != -1) if (opt.command_fd != -1)
; ;
@ -1497,6 +1502,14 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
subkey_expire_warning (keyblock); subkey_expire_warning (keyblock);
} }
if (delseckey_list_warn)
{
delseckey_list_warn = 0;
tty_printf
(_("Note: the local copy of the secret key"
" will only be deleted with \"save\".\n"));
}
do do
{ {
xfree (answer); xfree (answer);
@ -1869,10 +1882,12 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
if (node) if (node)
{ {
PKT_public_key *xxpk = node->pkt->pkt.public_key; PKT_public_key *xxpk = node->pkt->pkt.public_key;
if (card_store_subkey (node, xxpk ? xxpk->pubkey_usage : 0)) if (card_store_subkey (node, xxpk ? xxpk->pubkey_usage : 0,
&delseckey_list))
{ {
redisplay = 1; redisplay = 1;
sec_shadowing = 1; sec_shadowing = 1;
delseckey_list_warn = 1;
} }
} }
} }
@ -1949,7 +1964,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
pkt->pkttype = PKT_PUBLIC_KEY; pkt->pkttype = PKT_PUBLIC_KEY;
/* Ask gpg-agent to store the secret key to card. */ /* Ask gpg-agent to store the secret key to card. */
if (card_store_subkey (node, 0)) if (card_store_subkey (node, 0, NULL))
{ {
redisplay = 1; redisplay = 1;
sec_shadowing = 1; sec_shadowing = 1;
@ -2000,6 +2015,15 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
} }
break; break;
case cmdADDADSK:
if (menu_addadsk (ctrl, keyblock))
{
redisplay = 1;
modified = 1;
merge_keys_and_selfsig (ctrl, keyblock);
}
break;
case cmdREVUID: case cmdREVUID:
{ {
int n1; int n1;
@ -2250,6 +2274,27 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
} }
} }
if (delseckey_list)
{
strlist_t sl;
for (err = 0, sl = delseckey_list; sl; sl = sl->next)
{
if (*sl->d)
{
err = agent_delete_key (ctrl, sl->d, NULL, 1/*force*/);
if (err)
break;
*sl->d = 0; /* Mark deleted. */
}
}
if (err)
{
log_error (_("deleting copy of secret key failed: %s\n"),
gpg_strerror (err));
break; /* the "save". */
}
}
if (sec_shadowing) if (sec_shadowing)
{ {
err = agent_scd_learn (NULL, 1); err = agent_scd_learn (NULL, 1);
@ -2279,6 +2324,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
} /* End of the main command loop. */ } /* End of the main command loop. */
leave: leave:
free_strlist (delseckey_list);
release_kbnode (keyblock); release_kbnode (keyblock);
keydb_release (kdbhd); keydb_release (kdbhd);
xfree (answer); xfree (answer);
@ -4643,6 +4689,159 @@ fail:
} }
/*
* Ask for a new additional decryption subkey and add it to the key
* block. Returns true if the keybloxk was changed and false
* otherwise.
*/
static int
menu_addadsk (ctrl_t ctrl, kbnode_t pub_keyblock)
{
PKT_public_key *pk;
PKT_public_key *sub_pk;
PKT_public_key *main_pk;
PKT_public_key *adsk_pk = NULL;
kbnode_t adsk_keyblock = NULL;
PKT_signature *sig = NULL;
char *answer = NULL;
gpg_error_t err;
KEYDB_SEARCH_DESC desc;
byte fpr[MAX_FINGERPRINT_LEN];
size_t fprlen;
kbnode_t node, node2;
kbnode_t subkeynode = NULL;
PACKET *pkt; /* (temp. use; will be put into a kbnode_t) */
log_assert (pub_keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
main_pk = pub_keyblock->pkt->pkt.public_key;
for (;;)
{
xfree (answer);
answer = cpr_get_utf8
("keyedit.addadsk",
_("Enter the fingerprint of the additional decryption subkey: "));
if (answer[0] == '\0' || answer[0] == CONTROL_D)
{
err = gpg_error (GPG_ERR_CANCELED);
goto leave;
}
if (classify_user_id (answer, &desc, 1)
|| desc.mode != KEYDB_SEARCH_MODE_FPR)
{
log_info (_("\"%s\" is not a fingerprint\n"), answer);
continue;
}
free_public_key (adsk_pk);
adsk_pk = xcalloc (1, sizeof *adsk_pk);
adsk_pk->req_usage = PUBKEY_USAGE_ENC;
release_kbnode (adsk_keyblock);
adsk_keyblock = NULL;
err = get_pubkey_byname (ctrl, GET_PUBKEY_NO_AKL,
NULL, adsk_pk, answer, &adsk_keyblock, NULL, 1);
if (err)
{
log_info (_("key \"%s\" not found: %s\n"), answer,
gpg_strerror (err));
if (!opt.batch && gpg_err_code (err) == GPG_ERR_UNUSABLE_PUBKEY)
log_info (_("Did you specify the fingerprint of a subkey?\n"));
continue;
}
for (node = adsk_keyblock; node; node = node->next)
{
if (node->pkt->pkttype == PKT_PUBLIC_KEY
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
{
pk = node->pkt->pkt.public_key;
fingerprint_from_pk (pk, fpr, &fprlen);
if (fprlen == desc.fprlen
&& !memcmp (fpr, desc.u.fpr, fprlen)
&& (pk->pubkey_usage & PUBKEY_USAGE_ENC))
break;
}
}
if (!node)
{
err = gpg_error (GPG_ERR_WRONG_KEY_USAGE);
log_info (_("key \"%s\" not found: %s\n"), answer,
gpg_strerror (err));
if (!opt.batch)
log_info (_("Did you specify the fingerprint of a subkey?\n"));
continue;
}
/* Check that the selected subkey is not yet on our keyblock. */
for (node2 = pub_keyblock; node2; node2 = node2->next)
{
if (node2->pkt->pkttype == PKT_PUBLIC_KEY
|| node2->pkt->pkttype == PKT_PUBLIC_SUBKEY)
{
pk = node2->pkt->pkt.public_key;
fingerprint_from_pk (pk, fpr, &fprlen);
if (fprlen == desc.fprlen
&& !memcmp (fpr, desc.u.fpr, fprlen))
break;
}
}
if (node2)
{
log_info (_("key \"%s\" is already on this keyblock\n"), answer);
continue;
}
break;
}
/* Append the subkey.
* Note that we don't use the ADSK_PK directly because this is the
* primary key and in general we use a subkey to which NODE points.
* ADSK_PK has only been used to pass the requested key usage to
* get_pubkey_byname. SUB_PK will point to the actual adsk. */
log_assert (node->pkt->pkttype == PKT_PUBLIC_KEY
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY);
sub_pk = copy_public_key_basics (NULL, node->pkt->pkt.public_key);
keyid_from_pk (main_pk, sub_pk->main_keyid); /* Fixup main keyid. */
log_assert ((sub_pk->pubkey_usage & PUBKEY_USAGE_ENC));
sub_pk->pubkey_usage = PUBKEY_USAGE_RENC; /* 'e' -> 'r' */
pkt = xcalloc (1, sizeof *pkt);
pkt->pkttype = PKT_PUBLIC_SUBKEY; /* Make sure it is a subkey. */
pkt->pkt.public_key = sub_pk;
subkeynode = new_kbnode (pkt);
/* Make the signature. */
err = make_keysig_packet (ctrl, &sig, main_pk, NULL, sub_pk, main_pk, 0x18,
sub_pk->timestamp, 0,
keygen_add_key_flags_and_expire, sub_pk, NULL);
if (err)
{
write_status_error ("keysig", err);
log_error ("creating key binding failed: %s\n", gpg_strerror (err));
goto leave;
}
/* Append the subkey packet and the binding signature. */
add_kbnode (pub_keyblock, subkeynode);
subkeynode = NULL;
pkt = xcalloc (1, sizeof *pkt);
pkt->pkttype = PKT_SIGNATURE;
pkt->pkt.signature = sig;
add_kbnode (pub_keyblock, new_kbnode (pkt));
leave:
xfree (answer);
free_public_key (adsk_pk);
release_kbnode (adsk_keyblock);
release_kbnode (subkeynode);
if (!err)
return 1; /* The keyblock was modified. */
else
return 0; /* Not modified. */
}
/* With FORCE_MAINKEY cleared this function handles the interactive /* With FORCE_MAINKEY cleared this function handles the interactive
* menu option "expire". With UNATTENDED set to 1 this function only * menu option "expire". With UNATTENDED set to 1 this function only
* sets the expiration date of the primary key to NEWEXPIRATION and * sets the expiration date of the primary key to NEWEXPIRATION and

View File

@ -130,12 +130,6 @@ struct output_control_s
}; };
struct opaque_data_usage_and_pk {
unsigned int usage;
PKT_public_key *pk;
};
/* FIXME: These globals vars are ugly. And using MAX_PREFS even for /* FIXME: These globals vars are ugly. And using MAX_PREFS even for
* aeads is useless, given that we don't expects more than a very few * aeads is useless, given that we don't expects more than a very few
* algorithms. */ * algorithms. */
@ -256,22 +250,27 @@ write_uid (kbnode_t root, const char *s)
static void static void
do_add_key_flags (PKT_signature *sig, unsigned int use) do_add_key_flags (PKT_signature *sig, unsigned int use)
{ {
byte buf[1]; byte buf[2] = { 0, 0 };
buf[0] = 0; /* The spec says that all primary keys MUST be able to certify. */
if ( sig->sig_class != 0x18 )
buf[0] |= 0x01;
/* The spec says that all primary keys MUST be able to certify. */ if (use & PUBKEY_USAGE_SIG)
if(sig->sig_class!=0x18) buf[0] |= 0x02;
buf[0] |= 0x01; if (use & PUBKEY_USAGE_ENC)
buf[0] |= 0x04 | 0x08;
if (use & PUBKEY_USAGE_AUTH)
buf[0] |= 0x20;
if (use & PUBKEY_USAGE_GROUP)
buf[0] |= 0x80;
if (use & PUBKEY_USAGE_SIG) if (use & PUBKEY_USAGE_RENC)
buf[0] |= 0x02; buf[1] |= 0x04;
if (use & PUBKEY_USAGE_ENC) if (use & PUBKEY_USAGE_TIME)
buf[0] |= 0x04 | 0x08; buf[1] |= 0x08;
if (use & PUBKEY_USAGE_AUTH)
buf[0] |= 0x20;
build_sig_subpkt (sig, SIGSUBPKT_KEY_FLAGS, buf, 1); build_sig_subpkt (sig, SIGSUBPKT_KEY_FLAGS, buf, buf[1]? 2:1);
} }
@ -318,13 +317,11 @@ keygen_add_key_flags (PKT_signature *sig, void *opaque)
} }
static int int
keygen_add_key_flags_and_expire (PKT_signature *sig, void *opaque) keygen_add_key_flags_and_expire (PKT_signature *sig, void *opaque)
{ {
struct opaque_data_usage_and_pk *oduap = opaque; keygen_add_key_flags (sig, opaque);
return keygen_add_key_expire (sig, opaque);
do_add_key_flags (sig, oduap->usage);
return keygen_add_key_expire (sig, oduap->pk);
} }
@ -1215,7 +1212,6 @@ write_keybinding (ctrl_t ctrl, kbnode_t root,
PKT_signature *sig; PKT_signature *sig;
KBNODE node; KBNODE node;
PKT_public_key *pri_pk, *sub_pk; PKT_public_key *pri_pk, *sub_pk;
struct opaque_data_usage_and_pk oduap;
if (opt.verbose) if (opt.verbose)
log_info(_("writing key binding signature\n")); log_info(_("writing key binding signature\n"));
@ -1241,11 +1237,10 @@ write_keybinding (ctrl_t ctrl, kbnode_t root,
BUG(); BUG();
/* Make the signature. */ /* Make the signature. */
oduap.usage = use; sub_pk->pubkey_usage = use;
oduap.pk = sub_pk;
err = make_keysig_packet (ctrl, &sig, pri_pk, NULL, sub_pk, pri_psk, 0x18, err = make_keysig_packet (ctrl, &sig, pri_pk, NULL, sub_pk, pri_psk, 0x18,
timestamp, 0, timestamp, 0,
keygen_add_key_flags_and_expire, &oduap, keygen_add_key_flags_and_expire, sub_pk,
cache_nonce); cache_nonce);
if (err) if (err)
{ {

View File

@ -315,6 +315,7 @@ int keygen_set_std_prefs (const char *string,int personal);
PKT_user_id *keygen_get_std_prefs (void); PKT_user_id *keygen_get_std_prefs (void);
int keygen_add_key_expire( PKT_signature *sig, void *opaque ); int keygen_add_key_expire( PKT_signature *sig, void *opaque );
int keygen_add_key_flags (PKT_signature *sig, void *opaque); int keygen_add_key_flags (PKT_signature *sig, void *opaque);
int keygen_add_key_flags_and_expire (PKT_signature *sig, void *opaque);
int keygen_add_std_prefs( PKT_signature *sig, void *opaque ); int keygen_add_std_prefs( PKT_signature *sig, void *opaque );
int keygen_upd_std_prefs( PKT_signature *sig, void *opaque ); int keygen_upd_std_prefs( PKT_signature *sig, void *opaque );
int keygen_add_keyserver_url(PKT_signature *sig, void *opaque); int keygen_add_keyserver_url(PKT_signature *sig, void *opaque);
@ -515,7 +516,7 @@ void change_pin (int no, int allow_admin);
void card_status (ctrl_t ctrl, estream_t fp, const char *serialno); void card_status (ctrl_t ctrl, estream_t fp, const char *serialno);
void card_edit (ctrl_t ctrl, strlist_t commands); void card_edit (ctrl_t ctrl, strlist_t commands);
gpg_error_t card_generate_subkey (ctrl_t ctrl, kbnode_t pub_keyblock); gpg_error_t card_generate_subkey (ctrl_t ctrl, kbnode_t pub_keyblock);
int card_store_subkey (KBNODE node, int use); int card_store_subkey (KBNODE node, int use, strlist_t *processed_keys);
#endif #endif
/*-- migrate.c --*/ /*-- migrate.c --*/

View File

@ -777,21 +777,21 @@ openpgp_pk_algo_usage ( int algo )
switch ( algo ) { switch ( algo ) {
case PUBKEY_ALGO_RSA: case PUBKEY_ALGO_RSA:
use = (PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG use = (PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG
| PUBKEY_USAGE_ENC | PUBKEY_USAGE_AUTH); | PUBKEY_USAGE_ENC | PUBKEY_USAGE_RENC | PUBKEY_USAGE_AUTH);
break; break;
case PUBKEY_ALGO_RSA_E: case PUBKEY_ALGO_RSA_E:
case PUBKEY_ALGO_ECDH: case PUBKEY_ALGO_ECDH:
use = PUBKEY_USAGE_ENC; use = PUBKEY_USAGE_ENC | PUBKEY_USAGE_RENC;
break; break;
case PUBKEY_ALGO_RSA_S: case PUBKEY_ALGO_RSA_S:
use = PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG; use = PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG;
break; break;
case PUBKEY_ALGO_ELGAMAL: case PUBKEY_ALGO_ELGAMAL:
if (RFC2440) if (RFC2440)
use = PUBKEY_USAGE_ENC; use = PUBKEY_USAGE_ENC | PUBKEY_USAGE_RENC;
break; break;
case PUBKEY_ALGO_ELGAMAL_E: case PUBKEY_ALGO_ELGAMAL_E:
use = PUBKEY_USAGE_ENC; use = PUBKEY_USAGE_ENC | PUBKEY_USAGE_RENC;
break; break;
case PUBKEY_ALGO_DSA: case PUBKEY_ALGO_DSA:
use = PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG | PUBKEY_USAGE_AUTH; use = PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG | PUBKEY_USAGE_AUTH;

View File

@ -56,9 +56,15 @@
| GCRY_PK_USAGE_AUTH | GCRY_PK_USAGE_UNKN) >= 256 | GCRY_PK_USAGE_AUTH | GCRY_PK_USAGE_UNKN) >= 256
# error Please choose another value for PUBKEY_USAGE_NONE # error Please choose another value for PUBKEY_USAGE_NONE
#endif #endif
#define PUBKEY_USAGE_RENC 512 /* Restricted encryption. */
#define PUBKEY_USAGE_TIME 1024 /* Timestamp use. */
#define PUBKEY_USAGE_GROUP 512 /* Group flag. */ #define PUBKEY_USAGE_GROUP 512 /* Group flag. */
#define PUBKEY_USAGE_RENC 1024 /* Restricted encryption. */
#define PUBKEY_USAGE_TIME 2048 /* Timestamp use. */
/* Bitflags to convey hints on what kind of signature is created. */
#define SIGNHINT_KEYSIG 1
#define SIGNHINT_SELFSIG 2
#define SIGNHINT_ADSK 4
/* Helper macros. */ /* Helper macros. */
#define is_RSA(a) ((a)==PUBKEY_ALGO_RSA || (a)==PUBKEY_ALGO_RSA_E \ #define is_RSA(a) ((a)==PUBKEY_ALGO_RSA || (a)==PUBKEY_ALGO_RSA_E \
@ -287,7 +293,7 @@ typedef struct
/* The length of ATTRIB_DATA. */ /* The length of ATTRIB_DATA. */
unsigned long attrib_len; unsigned long attrib_len;
byte *namehash; byte *namehash;
int help_key_usage; u16 help_key_usage;
u32 help_key_expire; u32 help_key_expire;
int help_full_count; int help_full_count;
int help_marginal_count; int help_marginal_count;
@ -388,7 +394,7 @@ typedef struct
byte selfsigversion; /* highest version of all of the self-sigs */ byte selfsigversion; /* highest version of all of the self-sigs */
/* The public key algorithm. (Serialized.) */ /* The public key algorithm. (Serialized.) */
byte pubkey_algo; byte pubkey_algo;
byte pubkey_usage; /* for now only used to pass it to getkey() */ u16 pubkey_usage; /* carries the usage info. */
byte req_usage; /* hack to pass a request to getkey() */ byte req_usage; /* hack to pass a request to getkey() */
byte fprlen; /* 0 or length of FPR. */ byte fprlen; /* 0 or length of FPR. */
u32 has_expired; /* set to the expiration date if expired */ u32 has_expired; /* set to the expiration date if expired */
@ -861,7 +867,8 @@ gpg_error_t gpg_mpi_write_nohdr (iobuf_t out, gcry_mpi_t a);
u32 calc_packet_length( PACKET *pkt ); u32 calc_packet_length( PACKET *pkt );
void build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type, void build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type,
const byte *buffer, size_t buflen ); const byte *buffer, size_t buflen );
void build_sig_subpkt_from_sig (PKT_signature *sig, PKT_public_key *pksk); void build_sig_subpkt_from_sig (PKT_signature *sig, PKT_public_key *pksk,
unsigned int signhints);
int delete_sig_subpkt(subpktarea_t *buffer, sigsubpkttype_t type ); int delete_sig_subpkt(subpktarea_t *buffer, sigsubpkttype_t type );
void build_attribute_subpkt(PKT_user_id *uid,byte type, void build_attribute_subpkt(PKT_user_id *uid,byte type,
const void *buf,u32 buflen, const void *buf,u32 buflen,
@ -883,6 +890,7 @@ void free_user_id( PKT_user_id *uid );
void free_comment( PKT_comment *rem ); void free_comment( PKT_comment *rem );
void free_packet (PACKET *pkt, parse_packet_ctx_t parsectx); void free_packet (PACKET *pkt, parse_packet_ctx_t parsectx);
prefitem_t *copy_prefs (const prefitem_t *prefs); prefitem_t *copy_prefs (const prefitem_t *prefs);
PKT_public_key *copy_public_key_basics (PKT_public_key *d, PKT_public_key *s);
PKT_public_key *copy_public_key( PKT_public_key *d, PKT_public_key *s ); PKT_public_key *copy_public_key( PKT_public_key *d, PKT_public_key *s );
PKT_signature *copy_signature( PKT_signature *d, PKT_signature *s ); PKT_signature *copy_signature( PKT_signature *d, PKT_signature *s );
PKT_user_id *scopy_user_id (PKT_user_id *sd ); PKT_user_id *scopy_user_id (PKT_user_id *sd );

View File

@ -845,7 +845,8 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
{ {
int rc; int rc;
PKT_public_key *pk; PKT_public_key *pk;
KBNODE keyblock = NULL; kbnode_t keyblock = NULL;
kbnode_t node;
if (!name || !*name) if (!name || !*name)
return gpg_error (GPG_ERR_INV_USER_ID); return gpg_error (GPG_ERR_INV_USER_ID);
@ -856,7 +857,7 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
pk->req_usage = use; pk->req_usage = use;
if (from_file) if (from_file)
rc = get_pubkey_fromfile (ctrl, pk, name); rc = get_pubkey_fromfile (ctrl, pk, name, &keyblock);
else else
rc = get_best_pubkey_byname (ctrl, GET_PUBKEY_NORMAL, rc = get_best_pubkey_byname (ctrl, GET_PUBKEY_NORMAL,
NULL, pk, name, &keyblock, 0); NULL, pk, name, &keyblock, 0);
@ -895,10 +896,10 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
int trustlevel; int trustlevel;
trustlevel = get_validity (ctrl, keyblock, pk, pk->user_id, NULL, 1); trustlevel = get_validity (ctrl, keyblock, pk, pk->user_id, NULL, 1);
release_kbnode (keyblock);
if ( (trustlevel & TRUST_FLAG_DISABLED) ) if ( (trustlevel & TRUST_FLAG_DISABLED) )
{ {
/* Key has been disabled. */ /* Key has been disabled. */
release_kbnode (keyblock);
send_status_inv_recp (13, name); send_status_inv_recp (13, name);
log_info (_("%s: skipped: public key is disabled\n"), name); log_info (_("%s: skipped: public key is disabled\n"), name);
free_public_key (pk); free_public_key (pk);
@ -908,6 +909,7 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
if ( !do_we_trust_pre (ctrl, pk, trustlevel) ) if ( !do_we_trust_pre (ctrl, pk, trustlevel) )
{ {
/* We don't trust this key. */ /* We don't trust this key. */
release_kbnode (keyblock);
send_status_inv_recp (10, name); send_status_inv_recp (10, name);
free_public_key (pk); free_public_key (pk);
return GPG_ERR_UNUSABLE_PUBKEY; return GPG_ERR_UNUSABLE_PUBKEY;
@ -926,19 +928,33 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
{ {
pk_list_t r; pk_list_t r;
r = xtrymalloc (sizeof *r); r = xmalloc (sizeof *r);
if (!r)
{
rc = gpg_error_from_syserror ();
free_public_key (pk);
return rc;
}
r->pk = pk; r->pk = pk;
r->next = *pk_list_addr; r->next = *pk_list_addr;
r->flags = mark_hidden? 1:0; r->flags = mark_hidden? 1:0;
*pk_list_addr = r; *pk_list_addr = r;
} }
for (node = keyblock; node; node = node->next)
if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
&& ((pk=node->pkt->pkt.public_key)->pubkey_usage & PUBKEY_USAGE_RENC)
&& pk->flags.valid
&& !pk->flags.revoked
&& !pk->flags.disabled
&& !pk->has_expired
&& key_present_in_pk_list (*pk_list_addr, pk))
{
pk_list_t r;
r = xmalloc (sizeof *r);
r->pk = copy_public_key (NULL, pk);
r->next = *pk_list_addr;
r->flags = mark_hidden? 1:0; /* FIXME: Use PK_LIST_HIDDEN ? */
*pk_list_addr = r;
}
release_kbnode (keyblock);
return 0; return 0;
} }

View File

@ -363,7 +363,8 @@ check_signature_metadata_validity (PKT_public_key *pk, PKT_signature *sig,
if (r_revoked) if (r_revoked)
*r_revoked = 0; *r_revoked = 0;
if (pk->timestamp > sig->timestamp ) if (pk->timestamp > sig->timestamp
&& !(parse_key_usage (sig) & PUBKEY_USAGE_RENC))
{ {
ulong d = pk->timestamp - sig->timestamp; ulong d = pk->timestamp - sig->timestamp;
if ( d < 86400 ) if ( d < 86400 )

View File

@ -50,11 +50,6 @@
#endif #endif
/* Bitflags to convey hints on what kind of signayire is created. */
#define SIGNHINT_KEYSIG 1
#define SIGNHINT_SELFSIG 2
/* Hack */ /* Hack */
static int recipient_digest_algo; static int recipient_digest_algo;
@ -416,7 +411,10 @@ do_sign (ctrl_t ctrl, PKT_public_key *pksk, PKT_signature *sig,
byte *dp; byte *dp;
char *hexgrip; char *hexgrip;
if (pksk->timestamp > sig->timestamp ) /* An ADSK key commonly has a creation date older than the primary
* key. For example because the ADSK is used as an archive key for
* a group of users. */
if (pksk->timestamp > sig->timestamp && !(signhints & SIGNHINT_ADSK))
{ {
ulong d = pksk->timestamp - sig->timestamp; ulong d = pksk->timestamp - sig->timestamp;
log_info (ngettext("key %s was created %lu second" log_info (ngettext("key %s was created %lu second"
@ -964,7 +962,7 @@ write_signature_packets (ctrl_t ctrl,
if (gcry_md_copy (&md, hash)) if (gcry_md_copy (&md, hash))
BUG (); BUG ();
build_sig_subpkt_from_sig (sig, pk); build_sig_subpkt_from_sig (sig, pk, 0);
mk_notation_policy_etc (ctrl, sig, NULL, pk); mk_notation_policy_etc (ctrl, sig, NULL, pk);
if (opt.flags.include_key_block && IS_SIG (sig)) if (opt.flags.include_key_block && IS_SIG (sig))
err = mk_sig_subpkt_key_block (ctrl, sig, pk); err = mk_sig_subpkt_key_block (ctrl, sig, pk);
@ -1758,14 +1756,14 @@ sign_symencrypt_file (ctrl_t ctrl, const char *fname, strlist_t locusr)
* *
* SIGCLASS is the type of signature to create. * SIGCLASS is the type of signature to create.
* *
* DIGEST_ALGO is the digest algorithm. If it is 0 the function
* selects an appropriate one.
*
* TIMESTAMP is the timestamp to use for the signature. 0 means "now" * TIMESTAMP is the timestamp to use for the signature. 0 means "now"
* *
* DURATION is the amount of time (in seconds) until the signature * DURATION is the amount of time (in seconds) until the signature
* expires. * expires.
* *
* If CACHED_NONCE is not NULL the agent may use it to avoid
* additional pinnetry popups for the same keyblock.
*
* This function creates the following subpackets: issuer, created, * This function creates the following subpackets: issuer, created,
* and expire (if duration is not 0). Additional subpackets can be * and expire (if duration is not 0). Additional subpackets can be
* added using MKSUBPKT, which is called after these subpackets are * added using MKSUBPKT, which is called after these subpackets are
@ -1833,6 +1831,8 @@ make_keysig_packet (ctrl_t ctrl,
{ {
/* Hash the subkey binding/backsig/revocation. */ /* Hash the subkey binding/backsig/revocation. */
hash_public_key (md, subpk); hash_public_key (md, subpk);
if ((subpk->pubkey_usage & PUBKEY_USAGE_RENC))
signhints |= SIGNHINT_ADSK;
} }
else if (sigclass != 0x1F && sigclass != 0x20) else if (sigclass != 0x1F && sigclass != 0x20)
{ {
@ -1852,7 +1852,7 @@ make_keysig_packet (ctrl_t ctrl,
sig->expiredate = sig->timestamp + duration; sig->expiredate = sig->timestamp + duration;
sig->sig_class = sigclass; sig->sig_class = sigclass;
build_sig_subpkt_from_sig (sig, pksk); build_sig_subpkt_from_sig (sig, pksk, signhints);
mk_notation_policy_etc (ctrl, sig, pk, pksk); mk_notation_policy_etc (ctrl, sig, pk, pksk);
/* Crucial that the call to mksubpkt comes LAST before the calls /* Crucial that the call to mksubpkt comes LAST before the calls
@ -1976,6 +1976,12 @@ update_keysig_packet (ctrl_t ctrl,
} }
} }
/* Detect an ADSK key binding signature. */
if ((sig->sig_class == 0x18
|| sig->sig_class == 0x19 || sig->sig_class == 0x28)
&& (pk->pubkey_usage & PUBKEY_USAGE_RENC))
signhints |= SIGNHINT_ADSK;
/* Note that already expired sigs will remain expired (with a /* Note that already expired sigs will remain expired (with a
* duration of 1) since build-packet.c:build_sig_subpkt_from_sig * duration of 1) since build-packet.c:build_sig_subpkt_from_sig
* detects this case. */ * detects this case. */
@ -1984,7 +1990,7 @@ update_keysig_packet (ctrl_t ctrl,
* automagically lower any sig expiration dates to correctly * automagically lower any sig expiration dates to correctly
* correspond to the differences in the timestamps (i.e. the * correspond to the differences in the timestamps (i.e. the
* duration will shrink). */ * duration will shrink). */
build_sig_subpkt_from_sig (sig, pksk); build_sig_subpkt_from_sig (sig, pksk, signhints);
if (mksubpkt) if (mksubpkt)
rc = (*mksubpkt)(sig, opaque); rc = (*mksubpkt)(sig, opaque);

View File

@ -207,6 +207,7 @@ be_is_x509_blob (const unsigned char *blob, size_t bloblen)
* SEQUENCE SEQUENCE [0] INTEGER INTEGER * SEQUENCE SEQUENCE [0] INTEGER INTEGER
* (tbs) (version) (s/n) * (tbs) (version) (s/n)
* *
* Note that v0 certificates don't have an explict version number.
*/ */
p = blob; p = blob;
@ -226,7 +227,11 @@ be_is_x509_blob (const unsigned char *blob, size_t bloblen)
if (parse_ber_header (&p, &n, &class, &tag, &cons, &ndef, &objlen, &hdrlen)) if (parse_ber_header (&p, &n, &class, &tag, &cons, &ndef, &objlen, &hdrlen))
return 0; /* Not a proper BER object. */ return 0; /* Not a proper BER object. */
if (!(class == CLASS_CONTEXT && tag == 0 && cons)) if (!(class == CLASS_CONTEXT && tag == 0 && cons))
return 0; /* No context tag. */ {
if (class == CLASS_UNIVERSAL && tag == TAG_INTEGER && !cons)
return 1; /* Might be a X.509 v0 cert with implict version. */
return 0; /* No context tag. */
}
if (parse_ber_header (&p, &n, &class, &tag, &cons, &ndef, &objlen, &hdrlen)) if (parse_ber_header (&p, &n, &class, &tag, &cons, &ndef, &objlen, &hdrlen))
return 0; /* Not a proper BER object. */ return 0; /* Not a proper BER object. */

View File

@ -1863,7 +1863,7 @@ read_public_key (app_t app, ctrl_t ctrl, u32 created_at, int keyno,
len = gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, NULL, 0); len = gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, NULL, 0);
keybuf = xtrymalloc (len); keybuf = xtrymalloc (len);
if (!data) if (!keybuf)
{ {
err = gpg_error_from_syserror (); err = gpg_error_from_syserror ();
gcry_sexp_release (s_pkey); gcry_sexp_release (s_pkey);
@ -4824,6 +4824,7 @@ do_writekey (app_t app, ctrl_t ctrl,
const unsigned char *buf, *tok; const unsigned char *buf, *tok;
size_t buflen, toklen; size_t buflen, toklen;
int depth; int depth;
char *algostr = NULL;
(void)ctrl; (void)ctrl;
@ -4866,17 +4867,41 @@ do_writekey (app_t app, ctrl_t ctrl,
goto leave; goto leave;
if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))) if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
goto leave; goto leave;
if (tok && toklen == 3 && memcmp ("rsa", tok, toklen) == 0)
err = rsa_writekey (app, ctrl, pincb, pincb_arg, keyno, buf, buflen, depth); if (tok && toklen == 3 && (!memcmp ("rsa", tok, toklen)
else if (tok && toklen == 3 && memcmp ("ecc", tok, toklen) == 0) || !memcmp ("ecc", tok, toklen)))
err = ecc_writekey (app, ctrl, pincb, pincb_arg, keyno, buf, buflen, depth); {
gcry_sexp_t stmp;
if (!gcry_sexp_new (&stmp, keydata, keydatalen, 0))
algostr = pubkey_algo_string (stmp, NULL);
else
algostr = NULL;
gcry_sexp_release (stmp);
if (app->app_local->keyattr[keyno].keyalgo && algostr
&& strcmp (app->app_local->keyattr[keyno].keyalgo, algostr))
{
log_info ("openpgp: changing key attribute from %s to %s\n",
app->app_local->keyattr[keyno].keyalgo, algostr);
err = change_keyattr_from_string (app, ctrl, pincb, pincb_arg,
keyid, algostr, NULL, 0);
if (err)
return err;
}
if (*tok == 'r')
err = rsa_writekey (app, ctrl, pincb, pincb_arg, keyno,
buf,buflen,depth);
else
err = ecc_writekey (app, ctrl, pincb, pincb_arg, keyno,
buf, buflen, depth);
}
else else
{ {
err = gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO); err = gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO);
goto leave;
} }
leave: leave:
xfree (algostr);
return err; return err;
} }

View File

@ -326,7 +326,7 @@ struct prkdf_object_s
char *serial_number; char *serial_number;
/* KDF/KEK parameter for OpenPGP's ECDH. First byte is zero if not /* KDF/KEK parameter for OpenPGP's ECDH. First byte is zero if not
* available. .*/ * available. */
unsigned char ecdh_kdf[4]; unsigned char ecdh_kdf[4];
/* Length and allocated buffer with the Id of this object. */ /* Length and allocated buffer with the Id of this object. */

View File

@ -362,7 +362,7 @@ inq_certificate (void *opaque, const char *line)
} }
else else
{ {
log_error ("unsupported inquiry '%s'\n", line); log_error ("unsupported certificate inquiry '%s'\n", line);
return gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE); return gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
} }
@ -386,8 +386,8 @@ inq_certificate (void *opaque, const char *line)
int err; int err;
ksba_cert_t cert; ksba_cert_t cert;
err = gpgsm_find_cert (parm->ctrl, line, ski, &cert,
err = gpgsm_find_cert (parm->ctrl, line, ski, &cert, 1); FIND_CERT_ALLOW_AMBIG|FIND_CERT_WITH_EPHEM);
if (err) if (err)
{ {
log_error ("certificate not found: %s\n", gpg_strerror (err)); log_error ("certificate not found: %s\n", gpg_strerror (err));
@ -521,6 +521,7 @@ isvalid_status_cb (void *opaque, const char *line)
GPG_ERR_CERTIFICATE_REVOKED GPG_ERR_CERTIFICATE_REVOKED
GPG_ERR_NO_CRL_KNOWN GPG_ERR_NO_CRL_KNOWN
GPG_ERR_INV_CRL_OBJ
GPG_ERR_CRL_TOO_OLD GPG_ERR_CRL_TOO_OLD
Values for USE_OCSP: Values for USE_OCSP:
@ -1014,7 +1015,8 @@ run_command_inq_cb (void *opaque, const char *line)
if (!*line) if (!*line)
return gpg_error (GPG_ERR_ASS_PARAMETER); return gpg_error (GPG_ERR_ASS_PARAMETER);
err = gpgsm_find_cert (parm->ctrl, line, NULL, &cert, 1); err = gpgsm_find_cert (parm->ctrl, line, NULL, &cert,
FIND_CERT_ALLOW_AMBIG);
if (err) if (err)
{ {
log_error ("certificate not found: %s\n", gpg_strerror (err)); log_error ("certificate not found: %s\n", gpg_strerror (err));
@ -1035,9 +1037,33 @@ run_command_inq_cb (void *opaque, const char *line)
line = s; line = s;
log_info ("dirmngr: %s\n", line); log_info ("dirmngr: %s\n", line);
} }
else if ((s = has_leading_keyword (line, "ISTRUSTED")))
{
/* The server is asking us whether the certificate is a trusted
root certificate. */
char fpr[41];
struct rootca_flags_s rootca_flags;
int n;
line = s;
for (s=line,n=0; hexdigitp (s); s++, n++)
;
if (*s || n != 40)
return gpg_error (GPG_ERR_ASS_PARAMETER);
for (s=line, n=0; n < 40; s++, n++)
fpr[n] = (*s >= 'a')? (*s & 0xdf): *s;
fpr[n] = 0;
if (!gpgsm_agent_istrusted (parm->ctrl, NULL, fpr, &rootca_flags))
rc = assuan_send_data (parm->ctx, "1", 1);
else
rc = 0;
return rc;
}
else else
{ {
log_error ("unsupported inquiry '%s'\n", line); log_error ("unsupported command inquiry '%s'\n", line);
rc = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE); rc = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
} }

View File

@ -122,6 +122,7 @@ do_list (int is_error, int listmode, estream_t fp, const char *format, ...)
} }
else else
{ {
es_fflush (es_stdout);
log_logv (is_error? GPGRT_LOGLVL_ERROR: GPGRT_LOGLVL_INFO, log_logv (is_error? GPGRT_LOGLVL_ERROR: GPGRT_LOGLVL_INFO,
format, arg_ptr); format, arg_ptr);
log_printf ("\n"); log_printf ("\n");
@ -1480,6 +1481,7 @@ ask_marktrusted (ctrl_t ctrl, ksba_cert_t cert, int listmode)
int success = 0; int success = 0;
fpr = gpgsm_get_fingerprint_string (cert, GCRY_MD_SHA1); fpr = gpgsm_get_fingerprint_string (cert, GCRY_MD_SHA1);
es_fflush (es_stdout);
log_info (_("fingerprint=%s\n"), fpr? fpr : "?"); log_info (_("fingerprint=%s\n"), fpr? fpr : "?");
xfree (fpr); xfree (fpr);
@ -2277,6 +2279,7 @@ gpgsm_basic_cert_check (ctrl_t ctrl, ksba_cert_t cert)
{ {
if (!opt.quiet) if (!opt.quiet)
{ {
es_fflush (es_stdout);
log_info ("issuer certificate (#/"); log_info ("issuer certificate (#/");
gpgsm_dump_string (issuer); gpgsm_dump_string (issuer);
log_printf (") not found\n"); log_printf (") not found\n");

View File

@ -728,7 +728,14 @@ gpgsm_es_print_name2 (estream_t fp, const char *name, int translate)
void void
gpgsm_es_print_name (estream_t fp, const char *name) gpgsm_es_print_name (estream_t fp, const char *name)
{ {
gpgsm_es_print_name2 (fp, name, 1); if (opt.no_pretty_dn)
{
if (!name)
name = "[error]";
es_write_sanitized (fp, name, strlen (name), NULL, NULL);
}
else
gpgsm_es_print_name2 (fp, name, 1);
} }

View File

@ -508,11 +508,12 @@ gpgsm_release_certlist (certlist_t list)
int int
gpgsm_find_cert (ctrl_t ctrl, gpgsm_find_cert (ctrl_t ctrl,
const char *name, ksba_sexp_t keyid, ksba_cert_t *r_cert, const char *name, ksba_sexp_t keyid, ksba_cert_t *r_cert,
int allow_ambiguous) unsigned int flags)
{ {
int rc; int rc;
KEYDB_SEARCH_DESC desc; KEYDB_SEARCH_DESC desc;
KEYDB_HANDLE kh = NULL; KEYDB_HANDLE kh = NULL;
int allow_ambiguous = (flags & FIND_CERT_ALLOW_AMBIG);
*r_cert = NULL; *r_cert = NULL;
rc = classify_user_id (name, &desc, 0); rc = classify_user_id (name, &desc, 0);
@ -523,6 +524,9 @@ gpgsm_find_cert (ctrl_t ctrl,
rc = gpg_error (GPG_ERR_ENOMEM); rc = gpg_error (GPG_ERR_ENOMEM);
else else
{ {
if ((flags & FIND_CERT_WITH_EPHEM))
keydb_set_ephemeral (kh, 1);
nextone: nextone:
rc = keydb_search (ctrl, kh, &desc, 1); rc = keydb_search (ctrl, kh, &desc, 1);
if (!rc) if (!rc)

View File

@ -114,6 +114,7 @@ enum cmd_and_opt_values {
oNoLogFile, oNoLogFile,
oAuditLog, oAuditLog,
oHtmlAuditLog, oHtmlAuditLog,
oLogTime,
oEnableSpecialFilenames, oEnableSpecialFilenames,
@ -169,6 +170,7 @@ enum cmd_and_opt_values {
oWithKeyScreening, oWithKeyScreening,
oAnswerYes, oAnswerYes,
oAnswerNo, oAnswerNo,
oNoPrettyDN,
oKeyring, oKeyring,
oDefaultKey, oDefaultKey,
oDefRecipient, oDefRecipient,
@ -288,6 +290,7 @@ static gpgrt_opt_t opts[] = {
N_("|FILE|write server mode logs to FILE")), N_("|FILE|write server mode logs to FILE")),
ARGPARSE_s_n (oNoLogFile, "no-log-file", "@"), ARGPARSE_s_n (oNoLogFile, "no-log-file", "@"),
ARGPARSE_s_i (oLoggerFD, "logger-fd", "@"), ARGPARSE_s_i (oLoggerFD, "logger-fd", "@"),
ARGPARSE_s_n (oLogTime, "log-time", "@"),
ARGPARSE_s_n (oNoSecmemWarn, "no-secmem-warning", "@"), ARGPARSE_s_n (oNoSecmemWarn, "no-secmem-warning", "@"),
@ -383,7 +386,7 @@ static gpgrt_opt_t opts[] = {
ARGPARSE_s_n (oWithKeygrip, "with-keygrip", "@"), ARGPARSE_s_n (oWithKeygrip, "with-keygrip", "@"),
ARGPARSE_s_n (oWithSecret, "with-secret", "@"), ARGPARSE_s_n (oWithSecret, "with-secret", "@"),
ARGPARSE_s_n (oWithKeyScreening,"with-key-screening", "@"), ARGPARSE_s_n (oWithKeyScreening,"with-key-screening", "@"),
ARGPARSE_s_n (oNoPrettyDN, "no-pretty-dn", "@"),
ARGPARSE_header ("Security", N_("Options controlling the security")), ARGPARSE_header ("Security", N_("Options controlling the security")),
@ -499,6 +502,9 @@ static int maybe_setuid = 1;
static const char *debug_level; static const char *debug_level;
static unsigned int debug_value; static unsigned int debug_value;
/* Helper for --log-time; */
static int opt_log_time;
/* Default value for include-certs. We need an extra macro for /* Default value for include-certs. We need an extra macro for
gpgconf-list because the variable will be changed by the command gpgconf-list because the variable will be changed by the command
line option. line option.
@ -1247,6 +1253,7 @@ main ( int argc, char **argv)
case oLogFile: logfile = pargs.r.ret_str; break; case oLogFile: logfile = pargs.r.ret_str; break;
case oNoLogFile: logfile = NULL; break; case oNoLogFile: logfile = NULL; break;
case oLogTime: opt_log_time = 1; break;
case oAuditLog: auditlog = pargs.r.ret_str; break; case oAuditLog: auditlog = pargs.r.ret_str; break;
case oHtmlAuditLog: htmlauditlog = pargs.r.ret_str; break; case oHtmlAuditLog: htmlauditlog = pargs.r.ret_str; break;
@ -1312,6 +1319,10 @@ main ( int argc, char **argv)
opt.with_key_screening = 1; opt.with_key_screening = 1;
break; break;
case oNoPrettyDN:
opt.no_pretty_dn = 1;
break;
case oHomedir: gnupg_set_homedir (pargs.r.ret_str); break; case oHomedir: gnupg_set_homedir (pargs.r.ret_str); break;
case oChUid: break; /* Command line only (see above). */ case oChUid: break; /* Command line only (see above). */
case oAgentProgram: opt.agent_program = pargs.r.ret_str; break; case oAgentProgram: opt.agent_program = pargs.r.ret_str; break;
@ -1579,6 +1590,10 @@ main ( int argc, char **argv)
log_set_file (logfile); log_set_file (logfile);
log_set_prefix (NULL, GPGRT_LOG_WITH_PREFIX | GPGRT_LOG_WITH_TIME | GPGRT_LOG_WITH_PID); log_set_prefix (NULL, GPGRT_LOG_WITH_PREFIX | GPGRT_LOG_WITH_TIME | GPGRT_LOG_WITH_PID);
} }
else if (opt_log_time)
log_set_prefix (NULL, (GPGRT_LOG_WITH_PREFIX|GPGRT_LOG_NO_REGISTRY
|GPGRT_LOG_WITH_TIME));
if (gnupg_faked_time_p ()) if (gnupg_faked_time_p ())
{ {

View File

@ -85,6 +85,8 @@ struct
int with_key_screening; /* Option --with-key-screening active. */ int with_key_screening; /* Option --with-key-screening active. */
int no_pretty_dn; /* Option --no-pretty-dn */
int pinentry_mode; int pinentry_mode;
int request_origin; int request_origin;
@ -404,8 +406,11 @@ int gpgsm_add_cert_to_certlist (ctrl_t ctrl, ksba_cert_t cert,
int gpgsm_add_to_certlist (ctrl_t ctrl, const char *name, int secret, int gpgsm_add_to_certlist (ctrl_t ctrl, const char *name, int secret,
certlist_t *listaddr, int is_encrypt_to); certlist_t *listaddr, int is_encrypt_to);
void gpgsm_release_certlist (certlist_t list); void gpgsm_release_certlist (certlist_t list);
#define FIND_CERT_ALLOW_AMBIG 1
#define FIND_CERT_WITH_EPHEM 2
int gpgsm_find_cert (ctrl_t ctrl, const char *name, ksba_sexp_t keyid, int gpgsm_find_cert (ctrl_t ctrl, const char *name, ksba_sexp_t keyid,
ksba_cert_t *r_cert, int allow_ambiguous); ksba_cert_t *r_cert, unsigned int flags);
/*-- keylist.c --*/ /*-- keylist.c --*/
gpg_error_t gpgsm_list_keys (ctrl_t ctrl, strlist_t names, gpg_error_t gpgsm_list_keys (ctrl_t ctrl, strlist_t names,

View File

@ -105,12 +105,17 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp)
int signer; int signer;
const char *algoid; const char *algoid;
int algo; int algo;
int is_detached; int is_detached, maybe_detached;
estream_t in_fp = NULL; estream_t in_fp = NULL;
char *p; char *p;
audit_set_type (ctrl->audit, AUDIT_TYPE_VERIFY); audit_set_type (ctrl->audit, AUDIT_TYPE_VERIFY);
/* Although we detect detached signatures during the parsing phase,
* we need to know it earlier and thus accept the caller idea of
* what to verify. */
maybe_detached = (data_fd != -1);
kh = keydb_new (ctrl); kh = keydb_new (ctrl);
if (!kh) if (!kh)
{ {
@ -131,7 +136,8 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp)
rc = gnupg_ksba_create_reader rc = gnupg_ksba_create_reader
(&b64reader, ((ctrl->is_pem? GNUPG_KSBA_IO_PEM : 0) (&b64reader, ((ctrl->is_pem? GNUPG_KSBA_IO_PEM : 0)
| (ctrl->is_base64? GNUPG_KSBA_IO_BASE64 : 0) | (ctrl->is_base64? GNUPG_KSBA_IO_BASE64 : 0)
| (ctrl->autodetect_encoding? GNUPG_KSBA_IO_AUTODETECT : 0)), | (ctrl->autodetect_encoding? GNUPG_KSBA_IO_AUTODETECT : 0)
| (maybe_detached? GNUPG_KSBA_IO_STRIP : 0)),
in_fp, &reader); in_fp, &reader);
if (rc) if (rc)
{ {

View File

@ -1509,6 +1509,11 @@ show_configs (estream_t outfp)
static const char *names[] = { "common.conf", "gpg-agent.conf", static const char *names[] = { "common.conf", "gpg-agent.conf",
"scdaemon.conf", "dirmngr.conf", "scdaemon.conf", "dirmngr.conf",
"gpg.conf", "gpgsm.conf" }; "gpg.conf", "gpgsm.conf" };
static const char *envvars[] = { "PATH",
"http_proxy", "HTTP_PROXY",
"https_proxy", "HTTPS_PROXY",
"LD_LIBRARY_PATH", "LD_PRELOAD",
"LD_AUDIT", "LD_ORIGIN_PATH" };
gpg_error_t err; gpg_error_t err;
int idx; int idx;
char *fname; char *fname;
@ -1539,6 +1544,11 @@ show_configs (estream_t outfp)
list_dirs (outfp, NULL, 1); list_dirs (outfp, NULL, 1);
es_fprintf (outfp, "\n"); es_fprintf (outfp, "\n");
for (idx=0; idx < DIM(envvars); idx++)
if ((s = getenv (envvars[idx])))
es_fprintf (outfp, "%s=%s\n", envvars[idx], s);
es_fprintf (outfp, "\n");
fname = make_filename (gnupg_sysconfdir (), "gpgconf.conf", NULL); fname = make_filename (gnupg_sysconfdir (), "gpgconf.conf", NULL);
if (!gnupg_access (fname, F_OK)) if (!gnupg_access (fname, F_OK))
{ {

View File

@ -37,7 +37,7 @@
#include "gpgtar.h" #include "gpgtar.h"
static gpg_error_t static gpg_error_t
check_suspicious_name (const char *name) check_suspicious_name (const char *name, tarinfo_t info)
{ {
size_t n; size_t n;
@ -47,6 +47,7 @@ check_suspicious_name (const char *name)
{ {
log_error ("filename '%s' contains a backslash - " log_error ("filename '%s' contains a backslash - "
"can't extract on this system\n", name); "can't extract on this system\n", name);
info->skipped_badname++;
return gpg_error (GPG_ERR_INV_NAME); return gpg_error (GPG_ERR_INV_NAME);
} }
#endif /*HAVE_DOSISH_SYSTEM*/ #endif /*HAVE_DOSISH_SYSTEM*/
@ -59,6 +60,7 @@ check_suspicious_name (const char *name)
{ {
log_error ("filename '%s' has suspicious parts - not extracting\n", log_error ("filename '%s' has suspicious parts - not extracting\n",
name); name);
info->skipped_suspicious++;
return gpg_error (GPG_ERR_INV_NAME); return gpg_error (GPG_ERR_INV_NAME);
} }
@ -83,7 +85,7 @@ extract_regular (estream_t stream, const char *dirname,
if (sl->flags == 1) if (sl->flags == 1)
fname = sl->d; fname = sl->d;
err = check_suspicious_name (fname); err = check_suspicious_name (fname, info);
if (err) if (err)
goto leave; goto leave;
@ -131,8 +133,12 @@ extract_regular (estream_t stream, const char *dirname,
/* Fixme: Set permissions etc. */ /* Fixme: Set permissions etc. */
leave: leave:
if (!err && opt.verbose) if (!err)
log_info ("extracted '%s'\n", fname); {
if (opt.verbose)
log_info ("extracted '%s'\n", fname);
info->nextracted++;
}
es_fclose (outfp); es_fclose (outfp);
if (err && fname && outfp) if (err && fname && outfp)
{ {
@ -146,7 +152,8 @@ extract_regular (estream_t stream, const char *dirname,
static gpg_error_t static gpg_error_t
extract_directory (const char *dirname, tar_header_t hdr, strlist_t exthdr) extract_directory (const char *dirname, tarinfo_t info,
tar_header_t hdr, strlist_t exthdr)
{ {
gpg_error_t err; gpg_error_t err;
const char *name; const char *name;
@ -158,7 +165,7 @@ extract_directory (const char *dirname, tar_header_t hdr, strlist_t exthdr)
if (sl->flags == 1) if (sl->flags == 1)
name = sl->d; name = sl->d;
err = check_suspicious_name (name); err = check_suspicious_name (name, info);
if (err) if (err)
goto leave; goto leave;
@ -230,13 +237,19 @@ extract (estream_t stream, const char *dirname, tarinfo_t info,
if (hdr->typeflag == TF_REGULAR || hdr->typeflag == TF_UNKNOWN) if (hdr->typeflag == TF_REGULAR || hdr->typeflag == TF_UNKNOWN)
err = extract_regular (stream, dirname, info, hdr, exthdr); err = extract_regular (stream, dirname, info, hdr, exthdr);
else if (hdr->typeflag == TF_DIRECTORY) else if (hdr->typeflag == TF_DIRECTORY)
err = extract_directory (dirname, hdr, exthdr); err = extract_directory (dirname, info, hdr, exthdr);
else else
{ {
char record[RECORDSIZE]; char record[RECORDSIZE];
log_info ("unsupported file type %d for '%s' - skipped\n", log_info ("unsupported file type %d for '%s' - skipped\n",
(int)hdr->typeflag, hdr->name); (int)hdr->typeflag, hdr->name);
if (hdr->typeflag == TF_SYMLINK)
info->skipped_symlinks++;
else if (hdr->typeflag == TF_HARDLINK)
info->skipped_hardlinks++;
else
info->skipped_other++;
for (err = 0, n=0; !err && n < hdr->nrecords; n++) for (err = 0, n=0; !err && n < hdr->nrecords; n++)
{ {
err = read_record (stream, record); err = read_record (stream, record);
@ -328,7 +341,7 @@ gpgtar_extract (const char *filename, int decrypt)
tarinfo_t tarinfo = &tarinfo_buffer; tarinfo_t tarinfo = &tarinfo_buffer;
pid_t pid = (pid_t)(-1); pid_t pid = (pid_t)(-1);
char *logfilename = NULL; char *logfilename = NULL;
unsigned long long notextracted;
memset (&tarinfo_buffer, 0, sizeof tarinfo_buffer); memset (&tarinfo_buffer, 0, sizeof tarinfo_buffer);
@ -478,8 +491,37 @@ gpgtar_extract (const char *filename, int decrypt)
} }
} }
leave: leave:
notextracted = tarinfo->skipped_badname;
notextracted += tarinfo->skipped_suspicious;
notextracted += tarinfo->skipped_symlinks;
notextracted += tarinfo->skipped_hardlinks;
notextracted += tarinfo->skipped_other;
if (opt.status_stream)
es_fprintf (opt.status_stream, "[GNUPG:] GPGTAR_EXTRACT"
" %llu %llu %lu %lu %lu %lu %lu\n",
tarinfo->nextracted,
notextracted,
tarinfo->skipped_badname,
tarinfo->skipped_suspicious,
tarinfo->skipped_symlinks,
tarinfo->skipped_hardlinks,
tarinfo->skipped_other);
if (notextracted && !opt.quiet)
{
log_info ("Number of files not extracted: %llu\n", notextracted);
if (tarinfo->skipped_badname)
log_info (" invalid name: %lu\n", tarinfo->skipped_badname);
if (tarinfo->skipped_suspicious)
log_info (" suspicious name: %lu\n", tarinfo->skipped_suspicious);
if (tarinfo->skipped_symlinks)
log_info (" symlink: %lu\n", tarinfo->skipped_symlinks);
if (tarinfo->skipped_hardlinks)
log_info (" hardlink: %lu\n", tarinfo->skipped_hardlinks);
if (tarinfo->skipped_other)
log_info (" other reason: %lu\n", tarinfo->skipped_other);
}
free_strlist (extheader); free_strlist (extheader);
xfree (header); xfree (header);
xfree (dirname); xfree (dirname);

View File

@ -459,7 +459,7 @@ main (int argc, char **argv)
gnupg_reopen_std (GPGTAR_NAME); gnupg_reopen_std (GPGTAR_NAME);
gpgrt_set_strusage (my_strusage); gpgrt_set_strusage (my_strusage);
log_set_prefix (GPGTAR_NAME, GPGRT_LOG_WITH_PREFIX); log_set_prefix (GPGTAR_NAME, GPGRT_LOG_WITH_PREFIX|GPGRT_LOG_NO_REGISTRY);
/* Make sure that our subsystems are ready. */ /* Make sure that our subsystems are ready. */
i18n_init(); i18n_init();
@ -501,7 +501,11 @@ main (int argc, char **argv)
log_fatal ("status-fd is invalid: %s\n", strerror (errno)); log_fatal ("status-fd is invalid: %s\n", strerror (errno));
if (fd == 1) if (fd == 1)
opt.status_stream = es_stdout; {
opt.status_stream = es_stdout;
if (!skip_crypto)
log_fatal ("using stdout for the status-fd is not possible\n");
}
else if (fd == 2) else if (fd == 2)
opt.status_stream = es_stderr; opt.status_stream = es_stderr;
else else

View File

@ -54,8 +54,14 @@ struct
/* An info structure to avoid global variables. */ /* An info structure to avoid global variables. */
struct tarinfo_s struct tarinfo_s
{ {
unsigned long long nblocks; /* Count of processed blocks. */ unsigned long long nblocks; /* Count of processed blocks. */
unsigned long long headerblock; /* Number of current header block. */ unsigned long long headerblock; /* Number of current header block. */
unsigned long long nextracted; /* Number of extracted files. */
unsigned long skipped_badname;
unsigned long skipped_suspicious;
unsigned long skipped_symlinks;
unsigned long skipped_hardlinks;
unsigned long skipped_other;
}; };
typedef struct tarinfo_s *tarinfo_t; typedef struct tarinfo_s *tarinfo_t;