aboutsummaryrefslogtreecommitdiffstats
path: root/g10
diff options
context:
space:
mode:
Diffstat (limited to 'g10')
-rw-r--r--g10/Makefile.am1
-rw-r--r--g10/build-packet.c2
-rw-r--r--g10/call-agent.c27
-rw-r--r--g10/call-agent.h2
-rw-r--r--g10/card-util.c55
-rw-r--r--g10/dek.h6
-rw-r--r--g10/exec.c538
-rw-r--r--g10/exec.h27
-rw-r--r--g10/expand-group.c73
-rw-r--r--g10/export.c190
-rw-r--r--g10/getkey.c77
-rw-r--r--g10/gpg.c33
-rw-r--r--g10/import.c2
-rw-r--r--g10/key-clean.c2
-rw-r--r--g10/keydb.c17
-rw-r--r--g10/keydb.h13
-rw-r--r--g10/keyedit.c14
-rw-r--r--g10/keygen.c349
-rw-r--r--g10/keylist.c15
-rw-r--r--g10/keyserver.c10
-rw-r--r--g10/mainproc.c9
-rw-r--r--g10/options.h6
-rw-r--r--g10/packet.h99
-rw-r--r--g10/parse-packet.c122
-rw-r--r--g10/photoid.c406
-rw-r--r--g10/photoid.h2
-rw-r--r--g10/pkclist.c53
-rw-r--r--g10/sign.c8
-rw-r--r--g10/trustdb.c4
29 files changed, 1178 insertions, 984 deletions
diff --git a/g10/Makefile.am b/g10/Makefile.am
index fd2cd21b9..2b92daf33 100644
--- a/g10/Makefile.am
+++ b/g10/Makefile.am
@@ -99,6 +99,7 @@ common_source = \
filter.h \
free-packet.c \
getkey.c \
+ expand-group.c \
keydb.h \
keydb-private.h \
call-keyboxd.c \
diff --git a/g10/build-packet.c b/g10/build-packet.c
index 2a95df694..865f2b500 100644
--- a/g10/build-packet.c
+++ b/g10/build-packet.c
@@ -1527,7 +1527,7 @@ sig_to_notation(PKT_signature *sig)
- n1 bytes of name data
- n2 bytes of value data
*/
- while((p=enum_sig_subpkt(sig->hashed,SIGSUBPKT_NOTATION,&len,&seq,&crit)))
+ while((p=enum_sig_subpkt (sig, 1, SIGSUBPKT_NOTATION, &len, &seq, &crit)))
{
int n1,n2;
struct notation *n=NULL;
diff --git a/g10/call-agent.c b/g10/call-agent.c
index 19deb73d7..9e510ae98 100644
--- a/g10/call-agent.c
+++ b/g10/call-agent.c
@@ -367,7 +367,9 @@ start_agent (ctrl_t ctrl, int flag_for_card)
if (!(flag_for_card & FLAG_FOR_CARD_SUPPRESS_ERRORS))
rc = warn_version_mismatch (agent_ctx, SCDAEMON_NAME, 2);
if (!rc)
- rc = assuan_transact (agent_ctx, "SCD SERIALNO",
+ rc = assuan_transact (agent_ctx,
+ opt.flags.use_only_openpgp_card?
+ "SCD SERIALNO openpgp" : "SCD SERIALNO",
NULL, NULL, NULL, NULL,
learn_status_cb, &info);
if (rc && !(flag_for_card & FLAG_FOR_CARD_SUPPRESS_ERRORS))
@@ -740,7 +742,15 @@ learn_status_cb (void *opaque, const char *line)
}
else if (keywordlen == 3 && !memcmp (keyword, "KDF", 3))
{
- parm->kdf_do_enabled = 1;
+ unsigned char *data = unescape_status_string (line);
+
+ if (data[2] != 0x03)
+ parm->kdf_do_enabled = 0;
+ else if (data[22] != 0x85)
+ parm->kdf_do_enabled = 1;
+ else
+ parm->kdf_do_enabled = 2;
+ xfree (data);
}
else if (keywordlen == 5 && !memcmp (keyword, "UIF-", 4)
&& strchr("123", keyword[4]))
@@ -2315,25 +2325,28 @@ agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc,
return err;
}
- put_membuf (&data, "", 1); /* Make sure it is 0 terminated. */
buf = get_membuf (&data, &len);
if (!buf)
return gpg_error_from_syserror ();
- log_assert (len); /* (we forced Nul termination.) */
- if (*buf != '(')
+ if (len == 0 || *buf != '(')
{
xfree (buf);
return gpg_error (GPG_ERR_INV_SEXP);
}
- if (len < 13 || memcmp (buf, "(5:value", 8) ) /* "(5:valueN:D)\0" */
+ if (len < 12 || memcmp (buf, "(5:value", 8) ) /* "(5:valueN:D)" */
{
xfree (buf);
return gpg_error (GPG_ERR_INV_SEXP);
}
- len -= 10; /* Count only the data of the second part. */
+ while (buf[len-1] == 0)
+ len--;
+ if (buf[len-1] != ')')
+ return gpg_error (GPG_ERR_INV_SEXP);
+ len--; /* Drop the final close-paren. */
p = buf + 8; /* Skip leading parenthesis and the value tag. */
+ len -= 8; /* Count only the data of the second part. */
n = strtoul (p, &endp, 10);
if (!n || *endp != ':')
diff --git a/g10/call-agent.h b/g10/call-agent.h
index c4d0a9de1..5512fc847 100644
--- a/g10/call-agent.h
+++ b/g10/call-agent.h
@@ -72,7 +72,7 @@ struct agent_card_info_s
unsigned int bt:1; /* Button for confirmation available. */
} extcap;
unsigned int status_indicator;
- int kdf_do_enabled; /* True if card has a KDF object. */
+ int kdf_do_enabled; /* Non-zero if card has a KDF object, 0 if not. */
int uif[3]; /* True if User Interaction Flag is on. */
};
diff --git a/g10/card-util.c b/g10/card-util.c
index 1b9461e0a..78699914f 100644
--- a/g10/card-util.c
+++ b/g10/card-util.c
@@ -521,7 +521,16 @@ current_card_status (ctrl_t ctrl, estream_t fp,
es_fprintf (fp, "sigcount:%lu:::\n", info.sig_counter);
if (info.extcap.kdf)
{
- es_fprintf (fp, "kdf:%s:\n", info.kdf_do_enabled ? "on" : "off");
+ const char *setup;
+
+ if (info.kdf_do_enabled == 0)
+ setup = "off";
+ else if (info.kdf_do_enabled == 1)
+ setup = "single";
+ else
+ setup = "on";
+
+ es_fprintf (fp, "kdf:%s:\n", setup);
}
if (info.extcap.bt)
{
@@ -578,7 +587,7 @@ current_card_status (ctrl_t ctrl, estream_t fp,
print_name (fp, "Language prefs ...: ", info.disp_lang);
tty_fprintf (fp, "Salutation .......: %s\n",
info.disp_sex == 1? _("Mr."):
- info.disp_sex == 2? _("Mrs.") : "");
+ info.disp_sex == 2? _("Ms.") : "");
print_name (fp, "URL of public key : ", info.pubkey_url);
print_name (fp, "Login data .......: ", info.login_data);
if (info.private_do[0])
@@ -636,8 +645,16 @@ current_card_status (ctrl_t ctrl, estream_t fp,
tty_fprintf (fp, "Signature counter : %lu\n", info.sig_counter);
if (info.extcap.kdf)
{
- tty_fprintf (fp, "KDF setting ......: %s\n",
- info.kdf_do_enabled ? "on" : "off");
+ const char *setup;
+
+ if (info.kdf_do_enabled == 0)
+ setup = "off";
+ else if (info.kdf_do_enabled == 1)
+ setup = "single";
+ else
+ setup = "on";
+
+ tty_fprintf (fp, "KDF setting ......: %s\n", setup);
}
if (info.extcap.bt)
{
@@ -1160,7 +1177,7 @@ change_sex (void)
int rc;
data = cpr_get ("cardedit.change_sex",
- _("Salutation (M = Mr., F = Mrs., or space): "));
+ _("Salutation (M = Mr., F = Ms., or space): "));
if (!data)
return -1;
trim_spaces (data);
@@ -2103,7 +2120,7 @@ kdf_setup (const char *args)
struct agent_card_info_s info;
gpg_error_t err;
unsigned char kdf_data[KDF_DATA_LENGTH_MAX];
- int single = (*args != 0);
+ size_t len;
memset (&info, 0, sizeof info);
@@ -2120,12 +2137,25 @@ kdf_setup (const char *args)
goto leave;
}
- err = gen_kdf_data (kdf_data, single);
- if (err)
- goto leave_error;
+ if (!strcmp (args, "off"))
+ {
+ len = 5;
+ memcpy (kdf_data, "\xF9\x03\x81\x01\x00", len);
+ }
+ else
+ {
+ int single = 0;
+
+ if (*args != 0)
+ single = 1;
+
+ len = single ? KDF_DATA_LENGTH_MIN: KDF_DATA_LENGTH_MAX;
+ err = gen_kdf_data (kdf_data, single);
+ if (err)
+ goto leave_error;
+ }
- err = agent_scd_setattr ("KDF", kdf_data,
- single ? KDF_DATA_LENGTH_MIN : KDF_DATA_LENGTH_MAX);
+ err = agent_scd_setattr ("KDF", kdf_data, len);
if (err)
goto leave_error;
@@ -2225,7 +2255,8 @@ static struct
{ "verify" , cmdVERIFY, 0, N_("verify the PIN and list all data")},
{ "unblock" , cmdUNBLOCK,0, N_("unblock the PIN using a Reset Code")},
{ "factory-reset", cmdFACTORYRESET, 1, N_("destroy all keys and data")},
- { "kdf-setup", cmdKDFSETUP, 1, N_("setup KDF for PIN authentication")},
+ { "kdf-setup", cmdKDFSETUP, 1,
+ N_("setup KDF for PIN authentication (on/single/off)")},
{ "key-attr", cmdKEYATTR, 1, N_("change the key attribute")},
{ "uif", cmdUIF, 1, N_("change the User Interaction Flag")},
/* Note, that we do not announce these command yet. */
diff --git a/g10/dek.h b/g10/dek.h
index 1e861f565..88f8bc5f7 100644
--- a/g10/dek.h
+++ b/g10/dek.h
@@ -30,16 +30,16 @@ typedef struct
/* Whether we've already printed information about this key. This
* is currently only used in decrypt_data() and only if we are in
* verbose mode. */
- int algo_info_printed : 1;
+ unsigned int algo_info_printed : 1;
/* AEAD shall be used. The value is the AEAD algo. */
int use_aead : 4;
/* MDC shall be used. */
- int use_mdc : 1;
+ unsigned int use_mdc : 1;
/* This key was read from a SK-ESK packet (see proc_symkey_enc). */
- int symmetric : 1;
+ unsigned int symmetric : 1;
/* This is the largest used keylen (256 bit). */
byte key[32];
diff --git a/g10/exec.c b/g10/exec.c
index 3e5dc278b..f63904b39 100644
--- a/g10/exec.c
+++ b/g10/exec.c
@@ -17,64 +17,29 @@
* along with this program; if not, see <https://www.gnu.org/licenses/>.
*/
-/*
- FIXME: We should replace most code in this module by our
- spawn implementation from common/exechelp.c.
- */
-
-
#include <config.h>
#include <stdlib.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#ifndef EXEC_TEMPFILE_ONLY
-#include <sys/wait.h>
-#endif
#ifdef HAVE_DOSISH_SYSTEM
# ifdef HAVE_WINSOCK2_H
# include <winsock2.h>
# endif
# include <windows.h>
#endif
-#include <fcntl.h>
-#include <unistd.h>
#include <string.h>
-#include <errno.h>
#include "gpg.h"
#include "options.h"
#include "../common/i18n.h"
-#include "../common/iobuf.h"
-#include "../common/util.h"
-#include "../common/membuf.h"
-#include "../common/sysutils.h"
#include "exec.h"
#ifdef NO_EXEC
-int
-exec_write(struct exec_info **info,const char *program,
- const char *args_in,const char *name,int writeonly,int binary)
-{
- log_error(_("no remote program execution supported\n"));
- return GPG_ERR_GENERAL;
-}
-
-int
-exec_read(struct exec_info *info) { return GPG_ERR_GENERAL; }
-int
-exec_finish(struct exec_info *info) { return GPG_ERR_GENERAL; }
-int
-set_exec_path(const char *path) { return GPG_ERR_GENERAL; }
-
-#else /* ! NO_EXEC */
-
+int set_exec_path(const char *path) { return GPG_ERR_GENERAL; }
+#else
#if defined (_WIN32)
/* This is a nicer system() for windows that waits for programs to
return before returning control to the caller. I hate helpful
computers. */
-static int
+int
w32_system(const char *command)
{
if (!strncmp (command, "!ShellExecute ", 14))
@@ -197,501 +162,4 @@ set_exec_path(const char *path)
return 0;
#endif
}
-
-/* Makes a temp directory and filenames */
-static int
-make_tempdir(struct exec_info *info)
-{
- char *tmp=opt.temp_dir,*namein=info->name,*nameout;
-
- if(!namein)
- namein=info->flags.binary?"tempin" EXTSEP_S "bin":"tempin" EXTSEP_S "txt";
-
- nameout=info->flags.binary?"tempout" EXTSEP_S "bin":"tempout" EXTSEP_S "txt";
-
- /* Make up the temp dir and files in case we need them */
-
- if(tmp==NULL)
- {
-#if defined (_WIN32)
- int err;
-
- tmp=xmalloc(MAX_PATH+2);
- err=GetTempPath(MAX_PATH+1,tmp);
- if(err==0 || err>MAX_PATH+1)
- strcpy(tmp,"c:\\windows\\temp");
- else
- {
- int len=strlen(tmp);
-
- /* GetTempPath may return with \ on the end */
- while(len>0 && tmp[len-1]=='\\')
- {
- tmp[len-1]='\0';
- len--;
- }
- }
-#else /* More unixish systems */
- tmp=getenv("TMPDIR");
- if(tmp==NULL)
- {
- tmp=getenv("TMP");
- if(tmp==NULL)
- {
-#ifdef __riscos__
- tmp="<Wimp$ScrapDir>.GnuPG";
- mkdir(tmp,0700); /* Error checks occur later on */
-#else
- tmp="/tmp";
-#endif
- }
- }
-#endif
- }
-
- info->tempdir=xmalloc(strlen(tmp)+strlen(DIRSEP_S)+10+1);
-
- sprintf(info->tempdir,"%s" DIRSEP_S "gpg-XXXXXX",tmp);
-
-#if defined (_WIN32)
- xfree(tmp);
-#endif
-
- if (!gnupg_mkdtemp(info->tempdir))
- log_error(_("can't create directory '%s': %s\n"),
- info->tempdir,strerror(errno));
- else
- {
- info->flags.madedir=1;
-
- info->tempfile_in=xmalloc(strlen(info->tempdir)+
- strlen(DIRSEP_S)+strlen(namein)+1);
- sprintf(info->tempfile_in,"%s" DIRSEP_S "%s",info->tempdir,namein);
-
- if(!info->flags.writeonly)
- {
- info->tempfile_out=xmalloc(strlen(info->tempdir)+
- strlen(DIRSEP_S)+strlen(nameout)+1);
- sprintf(info->tempfile_out,"%s" DIRSEP_S "%s",info->tempdir,nameout);
- }
- }
-
- return info->flags.madedir? 0 : GPG_ERR_GENERAL;
-}
-
-/* Expands %i and %o in the args to the full temp files within the
- temp directory. */
-static int
-expand_args(struct exec_info *info,const char *args_in)
-{
- const char *ch = args_in;
- membuf_t command;
-
- info->flags.use_temp_files=0;
- info->flags.keep_temp_files=0;
-
- if(DBG_EXTPROG)
- log_debug("expanding string \"%s\"\n",args_in);
-
- init_membuf (&command, 100);
-
- while(*ch!='\0')
- {
- if(*ch=='%')
- {
- char *append=NULL;
-
- ch++;
-
- switch(*ch)
- {
- case 'O':
- info->flags.keep_temp_files=1;
- /* fall through */
-
- case 'o': /* out */
- if(!info->flags.madedir)
- {
- if(make_tempdir(info))
- goto fail;
- }
- append=info->tempfile_out;
- info->flags.use_temp_files=1;
- break;
-
- case 'I':
- info->flags.keep_temp_files=1;
- /* fall through */
-
- case 'i': /* in */
- if(!info->flags.madedir)
- {
- if(make_tempdir(info))
- goto fail;
- }
- append=info->tempfile_in;
- info->flags.use_temp_files=1;
- break;
-
- case '%':
- append="%";
- break;
- }
-
- if(append)
- put_membuf_str (&command, append);
- }
- else
- put_membuf (&command, ch, 1);
-
- ch++;
- }
-
- put_membuf (&command, "", 1); /* Terminate string. */
-
- info->command = get_membuf (&command, NULL);
- if (!info->command)
- return gpg_error_from_syserror ();
-
- if(DBG_EXTPROG)
- log_debug("args expanded to \"%s\", use %u, keep %u\n",info->command,
- info->flags.use_temp_files,info->flags.keep_temp_files);
-
- return 0;
-
- fail:
- xfree (get_membuf (&command, NULL));
- return GPG_ERR_GENERAL;
-}
-
-/* Either handles the tempfile creation, or the fork/exec. If it
- returns ok, then info->tochild is a FILE * that can be written to.
- The rules are: if there are no args, then it's a fork/exec/pipe.
- If there are args, but no tempfiles, then it's a fork/exec/pipe via
- shell -c. If there are tempfiles, then it's a system. */
-
-int
-exec_write(struct exec_info **info,const char *program,
- const char *args_in,const char *name,int writeonly,int binary)
-{
- int ret = GPG_ERR_GENERAL;
-
- if(opt.exec_disable && !opt.no_perm_warn)
- {
- log_info(_("external program calls are disabled due to unsafe "
- "options file permissions\n"));
-
- return ret;
- }
-
-#if defined(HAVE_GETUID) && defined(HAVE_GETEUID)
- /* There should be no way to get to this spot while still carrying
- setuid privs. Just in case, bomb out if we are. */
- if ( getuid () != geteuid ())
- BUG ();
-#endif
-
- if(program==NULL && args_in==NULL)
- BUG();
-
- *info=xmalloc_clear(sizeof(struct exec_info));
-
- if(name)
- (*info)->name=xstrdup(name);
- (*info)->flags.binary=binary;
- (*info)->flags.writeonly=writeonly;
-
- /* Expand the args, if any */
- if(args_in && expand_args(*info,args_in))
- goto fail;
-
-#ifdef EXEC_TEMPFILE_ONLY
- if(!(*info)->flags.use_temp_files)
- {
- log_error(_("this platform requires temporary files when calling"
- " external programs\n"));
- goto fail;
- }
-
-#else /* !EXEC_TEMPFILE_ONLY */
-
- /* If there are no args, or there are args, but no temp files, we
- can use fork/exec/pipe */
- if(args_in==NULL || (*info)->flags.use_temp_files==0)
- {
- int to[2],from[2];
-
- if(pipe(to)==-1)
- goto fail;
-
- if(pipe(from)==-1)
- {
- close(to[0]);
- close(to[1]);
- goto fail;
- }
-
- if(((*info)->child=fork())==-1)
- {
- close(to[0]);
- close(to[1]);
- close(from[0]);
- close(from[1]);
- goto fail;
- }
-
- if((*info)->child==0)
- {
- char *shell=getenv("SHELL");
-
- if(shell==NULL)
- shell="/bin/sh";
-
- /* I'm the child */
-
- /* If the program isn't going to respond back, they get to
- keep their stdout/stderr */
- if(!(*info)->flags.writeonly)
- {
- /* implied close of STDERR */
- if(dup2(STDOUT_FILENO,STDERR_FILENO)==-1)
- _exit(1);
-
- /* implied close of STDOUT */
- close(from[0]);
- if(dup2(from[1],STDOUT_FILENO)==-1)
- _exit(1);
- }
-
- /* implied close of STDIN */
- close(to[1]);
- if(dup2(to[0],STDIN_FILENO)==-1)
- _exit(1);
-
- if(args_in==NULL)
- {
- if(DBG_EXTPROG)
- log_debug("execlp: %s\n",program);
-
- execlp(program,program,(void *)NULL);
- }
- else
- {
- if(DBG_EXTPROG)
- log_debug("execlp: %s -c %s\n",shell,(*info)->command);
-
- execlp(shell,shell,"-c",(*info)->command,(void *)NULL);
- }
-
- /* If we get this far the exec failed. Clean up and return. */
-
- if(args_in==NULL)
- log_error(_("unable to execute program '%s': %s\n"),
- program,strerror(errno));
- else
- log_error(_("unable to execute shell '%s': %s\n"),
- shell,strerror(errno));
-
- /* This mimics the POSIX sh behavior - 127 means "not found"
- from the shell. */
- if(errno==ENOENT)
- _exit(127);
-
- _exit(1);
- }
-
- /* I'm the parent */
-
- close(to[0]);
-
- (*info)->tochild=fdopen(to[1],binary?"wb":"w");
- if((*info)->tochild==NULL)
- {
- ret = gpg_error_from_syserror ();
- close(to[1]);
- goto fail;
- }
-
- close(from[1]);
-
- (*info)->fromchild=iobuf_fdopen(from[0],"r");
- if((*info)->fromchild==NULL)
- {
- ret = gpg_error_from_syserror ();
- close(from[0]);
- goto fail;
- }
-
- /* fd iobufs are cached! */
- iobuf_ioctl((*info)->fromchild, IOBUF_IOCTL_NO_CACHE, 1, NULL);
-
- return 0;
- }
-#endif /* !EXEC_TEMPFILE_ONLY */
-
- if(DBG_EXTPROG)
- log_debug("using temp file '%s'\n",(*info)->tempfile_in);
-
- /* It's not fork/exec/pipe, so create a temp file */
- if( is_secured_filename ((*info)->tempfile_in) )
- {
- (*info)->tochild = NULL;
- gpg_err_set_errno (EPERM);
- }
- else
- (*info)->tochild=fopen((*info)->tempfile_in,binary?"wb":"w");
- if((*info)->tochild==NULL)
- {
- ret = gpg_error_from_syserror ();
- log_error(_("can't create '%s': %s\n"),
- (*info)->tempfile_in,strerror(errno));
- goto fail;
- }
-
- ret=0;
-
- fail:
- if (ret)
- {
- xfree (*info);
- *info = NULL;
- }
- return ret;
-}
-
-int
-exec_read(struct exec_info *info)
-{
- int ret = GPG_ERR_GENERAL;
-
- fclose(info->tochild);
- info->tochild=NULL;
-
- if(info->flags.use_temp_files)
- {
- if(DBG_EXTPROG)
- log_debug ("running command: %s\n",info->command);
-
-#if defined (_WIN32)
- info->progreturn=w32_system(info->command);
-#else
- info->progreturn=system(info->command);
-#endif
-
- if(info->progreturn==-1)
- {
- log_error(_("system error while calling external program: %s\n"),
- strerror(errno));
- info->progreturn=127;
- goto fail;
- }
-
-#if defined(WIFEXITED) && defined(WEXITSTATUS)
- if(WIFEXITED(info->progreturn))
- info->progreturn=WEXITSTATUS(info->progreturn);
- else
- {
- log_error(_("unnatural exit of external program\n"));
- info->progreturn=127;
- goto fail;
- }
-#else
- /* If we don't have the macros, do the best we can. */
- info->progreturn = (info->progreturn & 0xff00) >> 8;
-#endif
-
- /* 127 is the magic value returned from system() to indicate
- that the shell could not be executed, or from /bin/sh to
- indicate that the program could not be executed. */
-
- if(info->progreturn==127)
- {
- log_error(_("unable to execute external program\n"));
- goto fail;
- }
-
- if(!info->flags.writeonly)
- {
- info->fromchild=iobuf_open(info->tempfile_out);
- if (info->fromchild
- && is_secured_file (iobuf_get_fd (info->fromchild)))
- {
- iobuf_close (info->fromchild);
- info->fromchild = NULL;
- gpg_err_set_errno (EPERM);
- }
- if(info->fromchild==NULL)
- {
- ret = gpg_error_from_syserror ();
- log_error(_("unable to read external program response: %s\n"),
- strerror(errno));
- goto fail;
- }
-
- /* Do not cache this iobuf on close */
- iobuf_ioctl(info->fromchild, IOBUF_IOCTL_NO_CACHE, 1, NULL);
- }
- }
-
- ret=0;
-
- fail:
- return ret;
-}
-
-int
-exec_finish(struct exec_info *info)
-{
- int ret=info->progreturn;
-
- if(info->fromchild)
- iobuf_close(info->fromchild);
-
- if(info->tochild)
- fclose(info->tochild);
-
-#ifndef EXEC_TEMPFILE_ONLY
- if(info->child>0)
- {
- if(waitpid(info->child,&info->progreturn,0)!=0 &&
- WIFEXITED(info->progreturn))
- ret=WEXITSTATUS(info->progreturn);
- else
- {
- log_error(_("unnatural exit of external program\n"));
- ret=127;
- }
- }
-#endif
-
- if(info->flags.madedir && !info->flags.keep_temp_files)
- {
- if(info->tempfile_in)
- {
- if(unlink(info->tempfile_in)==-1)
- log_info(_("WARNING: unable to remove tempfile (%s) '%s': %s\n"),
- "in",info->tempfile_in,strerror(errno));
- }
-
- if(info->tempfile_out)
- {
- if(unlink(info->tempfile_out)==-1)
- log_info(_("WARNING: unable to remove tempfile (%s) '%s': %s\n"),
- "out",info->tempfile_out,strerror(errno));
- }
-
- if(rmdir(info->tempdir)==-1)
- log_info(_("WARNING: unable to remove temp directory '%s': %s\n"),
- info->tempdir,strerror(errno));
- }
-
- xfree(info->command);
- xfree(info->name);
- xfree(info->tempdir);
- xfree(info->tempfile_in);
- xfree(info->tempfile_out);
- xfree(info);
-
- return ret;
-}
#endif /* ! NO_EXEC */
diff --git a/g10/exec.h b/g10/exec.h
index 1cb1c7208..6b24d1c51 100644
--- a/g10/exec.h
+++ b/g10/exec.h
@@ -20,32 +20,7 @@
#ifndef _EXEC_H_
#define _EXEC_H_
-#include <unistd.h>
-#include <stdio.h>
-
-#include "../common/iobuf.h"
-
-struct exec_info
-{
- int progreturn;
- struct
- {
- unsigned int binary:1;
- unsigned int writeonly:1;
- unsigned int madedir:1;
- unsigned int use_temp_files:1;
- unsigned int keep_temp_files:1;
- } flags;
- pid_t child;
- FILE *tochild;
- iobuf_t fromchild;
- char *command,*name,*tempdir,*tempfile_in,*tempfile_out;
-};
-
-int exec_write(struct exec_info **info,const char *program,
- const char *args_in,const char *name,int writeonly,int binary);
-int exec_read(struct exec_info *info);
-int exec_finish(struct exec_info *info);
int set_exec_path(const char *path);
+int w32_system(const char *command);
#endif /* !_EXEC_H_ */
diff --git a/g10/expand-group.c b/g10/expand-group.c
new file mode 100644
index 000000000..e09a4fff6
--- /dev/null
+++ b/g10/expand-group.c
@@ -0,0 +1,73 @@
+/* expand-group.c - expand GPG group definitions
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
+ * 2008, 2009, 2010 Free Software Foundation, Inc.
+ *
+ * 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/>.
+ */
+
+#include <config.h>
+
+#include "gpg.h"
+#include "options.h"
+#include "keydb.h"
+
+int
+expand_id (const char *id, strlist_t *into, unsigned int flags)
+{
+ struct groupitem *groups;
+ int count=0;
+
+ for (groups = opt.grouplist; groups; groups=groups->next)
+ {
+ /* need strcasecmp() here, as this should be localized */
+ if (strcasecmp (groups->name,id) == 0)
+ {
+ strlist_t each,sl;
+
+ /* This maintains the current utf8-ness */
+ for (each = groups->values; each; each=each->next)
+ {
+ sl = add_to_strlist (into, each->d);
+ sl->flags = flags;
+ count++;
+ }
+
+ break;
+ }
+ }
+
+ return count;
+}
+
+/* For simplicity, and to avoid potential loops, we only expand once -
+ * you can't make an alias that points to an alias. */
+strlist_t
+expand_group (strlist_t input)
+{
+ strlist_t output = NULL;
+ strlist_t sl, rover;
+
+ for (rover = input; rover; rover = rover->next)
+ if (!(rover->flags & PK_LIST_FROM_FILE)
+ && !expand_id (rover->d, &output, rover->flags))
+ {
+ /* Didn't find any groups, so use the existing string */
+ sl = add_to_strlist (&output, rover->d);
+ sl->flags = rover->flags;
+ }
+
+ return output;
+}
diff --git a/g10/export.c b/g10/export.c
index 15861cc0d..3517be72c 100644
--- a/g10/export.c
+++ b/g10/export.c
@@ -2142,6 +2142,105 @@ key_to_sshblob (membuf_t *mb, const char *identifier, ...)
return err;
}
+
+static gpg_error_t
+export_one_ssh_key (estream_t fp, PKT_public_key *pk)
+{
+ gpg_error_t err;
+ const char *identifier = NULL;
+ membuf_t mb;
+ struct b64state b64_state;
+ void *blob;
+ size_t bloblen;
+
+ init_membuf (&mb, 4096);
+
+ switch (pk->pubkey_algo)
+ {
+ case PUBKEY_ALGO_DSA:
+ identifier = "ssh-dss";
+ err = key_to_sshblob (&mb, identifier,
+ pk->pkey[0], pk->pkey[1], pk->pkey[2], pk->pkey[3],
+ NULL);
+ break;
+
+ case PUBKEY_ALGO_RSA:
+ case PUBKEY_ALGO_RSA_S:
+ identifier = "ssh-rsa";
+ err = key_to_sshblob (&mb, identifier, pk->pkey[1], pk->pkey[0], NULL);
+ break;
+
+ case PUBKEY_ALGO_ECDSA:
+ {
+ char *curveoid;
+ const char *curve;
+
+ curveoid = openpgp_oid_to_str (pk->pkey[0]);
+ if (!curveoid)
+ err = gpg_error_from_syserror ();
+ else if (!(curve = openpgp_oid_to_curve (curveoid, 0)))
+ err = gpg_error (GPG_ERR_UNKNOWN_CURVE);
+ else
+ {
+ if (!strcmp (curve, "nistp256"))
+ identifier = "ecdsa-sha2-nistp256";
+ else if (!strcmp (curve, "nistp384"))
+ identifier = "ecdsa-sha2-nistp384";
+ else if (!strcmp (curve, "nistp521"))
+ identifier = "ecdsa-sha2-nistp521";
+
+ if (!identifier)
+ err = gpg_error (GPG_ERR_UNKNOWN_CURVE);
+ else
+ err = key_to_sshblob (&mb, identifier, pk->pkey[1], NULL);
+ }
+ xfree (curveoid);
+ }
+ break;
+
+ case PUBKEY_ALGO_EDDSA:
+ if (!openpgp_oid_is_ed25519 (pk->pkey[0]))
+ err = gpg_error (GPG_ERR_UNKNOWN_CURVE);
+ else
+ {
+ identifier = "ssh-ed25519";
+ err = key_to_sshblob (&mb, identifier, pk->pkey[1], NULL);
+ }
+ break;
+
+ case PUBKEY_ALGO_ELGAMAL_E:
+ case PUBKEY_ALGO_ELGAMAL:
+ err = gpg_error (GPG_ERR_UNUSABLE_PUBKEY);
+ break;
+
+ default:
+ err = GPG_ERR_PUBKEY_ALGO;
+ break;
+ }
+
+ if (err)
+ goto leave;
+
+ err = b64enc_start_es (&b64_state, fp, "");
+ if (err)
+ goto leave;
+
+ blob = get_membuf (&mb, &bloblen);
+ if (blob)
+ {
+ es_fprintf (fp, "%s ", identifier);
+ err = b64enc_write (&b64_state, blob, bloblen);
+ es_fprintf (fp, " openpgp:0x%08lX\n", (ulong)keyid_from_pk (pk, NULL));
+ xfree (blob);
+ }
+
+ b64enc_finish (&b64_state);
+
+ leave:
+ xfree (get_membuf (&mb, NULL));
+ return err;
+}
+
/* Export the key identified by USERID in the SSH public key format.
The function exports the latest subkey with Authentication
capability unless the '!' suffix is used to export a specific
@@ -2156,14 +2255,9 @@ export_ssh_key (ctrl_t ctrl, const char *userid)
u32 curtime = make_timestamp ();
kbnode_t latest_key, node;
PKT_public_key *pk;
- const char *identifier = NULL;
- membuf_t mb;
estream_t fp = NULL;
- struct b64state b64_state;
const char *fname = "-";
- init_membuf (&mb, 4096);
-
/* We need to know whether the key has been specified using the
exact syntax ('!' suffix). Thus we need to run a
classify_user_id on our own. */
@@ -2319,72 +2413,6 @@ export_ssh_key (ctrl_t ctrl, const char *userid)
if (DBG_LOOKUP)
log_debug ("\tusing key %08lX\n", (ulong) keyid_from_pk (pk, NULL));
- switch (pk->pubkey_algo)
- {
- case PUBKEY_ALGO_DSA:
- identifier = "ssh-dss";
- err = key_to_sshblob (&mb, identifier,
- pk->pkey[0], pk->pkey[1], pk->pkey[2], pk->pkey[3],
- NULL);
- break;
-
- case PUBKEY_ALGO_RSA:
- case PUBKEY_ALGO_RSA_S:
- identifier = "ssh-rsa";
- err = key_to_sshblob (&mb, identifier, pk->pkey[1], pk->pkey[0], NULL);
- break;
-
- case PUBKEY_ALGO_ECDSA:
- {
- char *curveoid;
- const char *curve;
-
- curveoid = openpgp_oid_to_str (pk->pkey[0]);
- if (!curveoid)
- err = gpg_error_from_syserror ();
- else if (!(curve = openpgp_oid_to_curve (curveoid, 0)))
- err = gpg_error (GPG_ERR_UNKNOWN_CURVE);
- else
- {
- if (!strcmp (curve, "nistp256"))
- identifier = "ecdsa-sha2-nistp256";
- else if (!strcmp (curve, "nistp384"))
- identifier = "ecdsa-sha2-nistp384";
- else if (!strcmp (curve, "nistp521"))
- identifier = "ecdsa-sha2-nistp521";
-
- if (!identifier)
- err = gpg_error (GPG_ERR_UNKNOWN_CURVE);
- else
- err = key_to_sshblob (&mb, identifier, pk->pkey[1], NULL);
- }
- xfree (curveoid);
- }
- break;
-
- case PUBKEY_ALGO_EDDSA:
- if (!openpgp_oid_is_ed25519 (pk->pkey[0]))
- err = gpg_error (GPG_ERR_UNKNOWN_CURVE);
- else
- {
- identifier = "ssh-ed25519";
- err = key_to_sshblob (&mb, identifier, pk->pkey[1], NULL);
- }
- break;
-
- case PUBKEY_ALGO_ELGAMAL_E:
- case PUBKEY_ALGO_ELGAMAL:
- err = gpg_error (GPG_ERR_UNUSABLE_PUBKEY);
- break;
-
- default:
- err = GPG_ERR_PUBKEY_ALGO;
- break;
- }
-
- if (!identifier)
- goto leave;
-
if (opt.outfile && *opt.outfile && strcmp (opt.outfile, "-"))
fp = es_fopen ((fname = opt.outfile), "w");
else
@@ -2396,26 +2424,9 @@ export_ssh_key (ctrl_t ctrl, const char *userid)
goto leave;
}
- es_fprintf (fp, "%s ", identifier);
- err = b64enc_start_es (&b64_state, fp, "");
- if (!err)
- {
- void *blob;
- size_t bloblen;
-
- blob = get_membuf (&mb, &bloblen);
- if (blob)
- {
- err = b64enc_write (&b64_state, blob, bloblen);
- xfree (blob);
- if (err)
- goto leave;
- }
- err = b64enc_finish (&b64_state);
- }
+ err = export_one_ssh_key (fp, pk);
if (err)
goto leave;
- es_fprintf (fp, " openpgp:0x%08lX\n", (ulong)keyid_from_pk (pk, NULL));
if (es_ferror (fp))
err = gpg_error_from_syserror ();
@@ -2431,7 +2442,6 @@ export_ssh_key (ctrl_t ctrl, const char *userid)
leave:
es_fclose (fp);
- xfree (get_membuf (&mb, NULL));
release_kbnode (keyblock);
return err;
}
diff --git a/g10/getkey.c b/g10/getkey.c
index 2cc56cdbd..de5024198 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -729,7 +729,7 @@ key_byname (ctrl_t ctrl, GETKEY_CTX *retctx, strlist_t namelist,
{
int rc = 0;
int n;
- strlist_t r;
+ strlist_t r, namelist_expanded = NULL, link = NULL;
GETKEY_CTX ctx;
KBNODE help_kb = NULL;
KBNODE found_key = NULL;
@@ -758,6 +758,19 @@ key_byname (ctrl_t ctrl, GETKEY_CTX *retctx, strlist_t namelist,
}
else
{
+ namelist_expanded = expand_group (namelist);
+
+ /* Chain namelist and namelist_expanded */
+ for (r = namelist; r; r = r->next)
+ {
+ if (!r->next)
+ {
+ r->next = namelist_expanded;
+ link = r;
+ break;
+ }
+ }
+
/* Build the search context. */
for (n = 0, r = namelist; r; r = r->next)
n++;
@@ -779,7 +792,8 @@ key_byname (ctrl_t ctrl, GETKEY_CTX *retctx, strlist_t namelist,
if (err)
{
xfree (ctx);
- return gpg_err_code (err); /* FIXME: remove gpg_err_code. */
+ rc = gpg_err_code (err); /* FIXME: remove gpg_err_code. */
+ goto leave;
}
if (!include_unusable
&& ctx->items[n].mode != KEYDB_SEARCH_MODE_SHORT_KID
@@ -798,7 +812,7 @@ key_byname (ctrl_t ctrl, GETKEY_CTX *retctx, strlist_t namelist,
{
rc = gpg_error_from_syserror ();
getkey_end (ctrl, ctx);
- return rc;
+ goto leave;
}
if (!ret_kb)
@@ -829,6 +843,12 @@ key_byname (ctrl_t ctrl, GETKEY_CTX *retctx, strlist_t namelist,
getkey_end (ctrl, ctx);
}
+leave:
+ if (namelist_expanded)
+ free_strlist(namelist_expanded);
+ /* Un-chain namelist and namelist_expanded */
+ if (link)
+ link->next = NULL;
return rc;
}
@@ -2151,7 +2171,7 @@ parse_key_usage (PKT_signature * sig)
size_t n;
byte flags;
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_FLAGS, &n);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_KEY_FLAGS, &n);
if (p && n)
{
/* First octet of the keyflags. */
@@ -2249,7 +2269,7 @@ fixup_uidnode (KBNODE uidnode, KBNODE signode, u32 keycreated)
uid->help_key_usage = parse_key_usage (sig);
/* Ditto for the key expiration. */
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE, NULL);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_KEY_EXPIRE, NULL);
if (p && buf32_to_u32 (p))
uid->help_key_expire = keycreated + buf32_to_u32 (p);
else
@@ -2258,7 +2278,7 @@ fixup_uidnode (KBNODE uidnode, KBNODE signode, u32 keycreated)
/* Set the primary user ID flag - we will later wipe out some
* of them to only have one in our keyblock. */
uid->flags.primary = 0;
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PRIMARY_UID, NULL);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_PRIMARY_UID, NULL);
if (p && *p)
uid->flags.primary = 2;
@@ -2270,16 +2290,16 @@ fixup_uidnode (KBNODE uidnode, KBNODE signode, u32 keycreated)
/* Now build the preferences list. These must come from the
hashed section so nobody can modify the ciphers a key is
willing to accept. */
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_SYM, &n);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_PREF_SYM, &n);
sym = p;
nsym = p ? n : 0;
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_AEAD, &n);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_PREF_AEAD, &n);
aead = p;
naead = p ? n : 0;
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_HASH, &n);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_PREF_HASH, &n);
hash = p;
nhash = p ? n : 0;
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_COMPR, &n);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_PREF_COMPR, &n);
zip = p;
nzip = p ? n : 0;
if (uid->prefs)
@@ -2317,19 +2337,19 @@ fixup_uidnode (KBNODE uidnode, KBNODE signode, u32 keycreated)
/* See whether we have the MDC feature. */
uid->flags.mdc = 0;
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES, &n);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_FEATURES, &n);
if (p && n && (p[0] & 0x01))
uid->flags.mdc = 1;
/* See whether we have the AEAD feature. */
uid->flags.aead = 0;
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES, &n);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_FEATURES, &n);
if (p && n && (p[0] & 0x02))
uid->flags.aead = 1;
/* And the keyserver modify flag. */
uid->flags.ks_modify = 1;
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KS_FLAGS, &n);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_KS_FLAGS, &n);
if (p && n && (p[0] & 0x80))
uid->flags.ks_modify = 0;
}
@@ -2564,7 +2584,7 @@ merge_selfsigs_main (ctrl_t ctrl, kbnode_t keyblock, int *r_revoked,
key_usage = parse_key_usage (sig);
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE, NULL);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_KEY_EXPIRE, NULL);
if (p && buf32_to_u32 (p))
{
key_expire = keytimestamp + buf32_to_u32 (p);
@@ -3052,7 +3072,7 @@ merge_selfsigs_subkey (ctrl_t ctrl, kbnode_t keyblock, kbnode_t subnode)
subpk->pubkey_usage = key_usage;
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE, NULL);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_KEY_EXPIRE, NULL);
if (p && buf32_to_u32 (p))
key_expire = keytimestamp + buf32_to_u32 (p);
else
@@ -3079,8 +3099,8 @@ merge_selfsigs_subkey (ctrl_t ctrl, kbnode_t keyblock, kbnode_t subnode)
/* We do this while() since there may be other embedded
* signatures in the future. We only want 0x19 here. */
- while ((p = enum_sig_subpkt (sig->hashed,
- SIGSUBPKT_SIGNATURE, &n, &seq, NULL)))
+ while ((p = enum_sig_subpkt (sig, 1, SIGSUBPKT_SIGNATURE,
+ &n, &seq, NULL)))
if (n > 3
&& ((p[0] == 3 && p[2] == 0x19) || (p[0] == 4 && p[1] == 0x19)))
{
@@ -3104,8 +3124,7 @@ merge_selfsigs_subkey (ctrl_t ctrl, kbnode_t keyblock, kbnode_t subnode)
/* It is safe to have this in the unhashed area since the 0x19
* is located on the selfsig for convenience, not security. */
-
- while ((p = enum_sig_subpkt (sig->unhashed, SIGSUBPKT_SIGNATURE,
+ while ((p = enum_sig_subpkt (sig, 0, SIGSUBPKT_SIGNATURE,
&n, &seq, NULL)))
if (n > 3
&& ((p[0] == 3 && p[2] == 0x19) || (p[0] == 4 && p[1] == 0x19)))
@@ -3924,6 +3943,26 @@ release_akl (void)
}
}
+
+/* Returns true if the AKL is empty or has only the local method
+ * active. */
+int
+akl_empty_or_only_local (void)
+{
+ struct akl *akl;
+ int any = 0;
+
+ for (akl = opt.auto_key_locate; akl; akl = akl->next)
+ if (akl->type != AKL_NODEFAULT && akl->type != AKL_LOCAL)
+ {
+ any = 1;
+ break;
+ }
+
+ return !any;
+}
+
+
/* Returns false on error. */
int
parse_auto_key_locate (const char *options_arg)
diff --git a/g10/gpg.c b/g10/gpg.c
index 821d3959b..b9b6de4e6 100644
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -429,6 +429,7 @@ enum cmd_and_opt_values
oKeyOrigin,
oRequestOrigin,
oNoSymkeyCache,
+ oUseOnlyOpenPGPCard,
oNoop
};
@@ -714,7 +715,7 @@ static ARGPARSE_OPTS opts[] = {
"delete-secret-and-public-keys", "@"),
ARGPARSE_c (aRebuildKeydbCaches, "rebuild-keydb-caches", "@"),
- ARGPARSE_s_s (oPassphrase, "passphrase", "@"),
+ ARGPARSE_o_s (oPassphrase, "passphrase", "@"),
ARGPARSE_s_i (oPassphraseFD, "passphrase-fd", "@"),
ARGPARSE_s_s (oPassphraseFile, "passphrase-file", "@"),
ARGPARSE_s_i (oPassphraseRepeat,"passphrase-repeat", "@"),
@@ -901,6 +902,10 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_n (oNoSymkeyCache, "no-symkey-cache", "@"),
ARGPARSE_s_n (oUseKeyboxd, "use-keyboxd", "@"),
+ /* Options which can be used in special circumstances. They are not
+ * published and we hope they are never required. */
+ ARGPARSE_s_n (oUseOnlyOpenPGPCard, "use-only-openpgp-card", "@"),
+
/* Dummy options with warnings. */
ARGPARSE_s_n (oUseAgent, "use-agent", "@"),
ARGPARSE_s_n (oNoUseAgent, "no-use-agent", "@"),
@@ -961,6 +966,9 @@ static struct debug_flags_s debug_flags [] =
#define ALWAYS_ADD_KEYRINGS 0
#endif
+/* The list of the default AKL methods. */
+#define DEFAULT_AKL_LIST "local,wkd"
+
int g10_errors_seen = 0;
@@ -2539,7 +2547,7 @@ main (int argc, char **argv)
/* Set default options which require that malloc stuff is ready. */
additional_weak_digest ("MD5");
- parse_auto_key_locate ("local,wkd");
+ parse_auto_key_locate (DEFAULT_AKL_LIST);
/* Try for a version specific config file first */
default_configname = get_default_configname ();
@@ -3178,7 +3186,7 @@ main (int argc, char **argv)
case oBZ2CompressLevel: opt.bz2_compress_level = pargs.r.ret_int; break;
case oBZ2DecompressLowmem: opt.bz2_decompress_lowmem=1; break;
case oPassphrase:
- set_passphrase_from_string(pargs.r.ret_str);
+ set_passphrase_from_string (pargs.r_type ? pargs.r.ret_str : "");
break;
case oPassphraseFD:
pwfd = translate_sys2libc_fd_int (pargs.r.ret_int, 0);
@@ -3657,6 +3665,10 @@ main (int argc, char **argv)
opt.def_new_key_algo = pargs.r.ret_str;
break;
+ case oUseOnlyOpenPGPCard:
+ opt.flags.use_only_openpgp_card = 1;
+ break;
+
case oNoop: break;
default:
@@ -3765,7 +3777,10 @@ main (int argc, char **argv)
log_info(_("WARNING: program may create a core file!\n"));
if (opt.flags.rfc4880bis)
- log_info ("Note: RFC4880bis features are enabled.\n");
+ {
+ if (!opt.quiet)
+ log_info ("Note: RFC4880bis features are enabled.\n");
+ }
else
{
opt.mimemode = 0; /* This will use text mode instead. */
@@ -4555,7 +4570,17 @@ main (int argc, char **argv)
sl = NULL;
for (; argc; argc--, argv++)
add_to_strlist2( &sl, *argv, utf8_strings );
+ if (cmd == aLocateExtKeys && akl_empty_or_only_local ())
+ {
+ /* This is a kludge to let --locate-external-keys even
+ * work if the config file has --no-auto-key-locate. This
+ * better matches the expectations of the user. */
+ release_akl ();
+ parse_auto_key_locate (DEFAULT_AKL_LIST);
+ }
public_key_list (ctrl, sl, 1, cmd == aLocateExtKeys);
+
+
free_strlist (sl);
break;
diff --git a/g10/import.c b/g10/import.c
index 17afaa6f6..47014b948 100644
--- a/g10/import.c
+++ b/g10/import.c
@@ -3151,7 +3151,7 @@ get_revocation_reason (PKT_signature *sig, char **r_reason,
*r_comment = NULL;
/* Skip over empty reason packets. */
- while ((reason_p = enum_sig_subpkt (sig->hashed, SIGSUBPKT_REVOC_REASON,
+ while ((reason_p = enum_sig_subpkt (sig, 1, SIGSUBPKT_REVOC_REASON,
&reason_n, &reason_seq, NULL))
&& !reason_n)
;
diff --git a/g10/key-clean.c b/g10/key-clean.c
index d701a6665..496d0194e 100644
--- a/g10/key-clean.c
+++ b/g10/key-clean.c
@@ -192,7 +192,7 @@ mark_usable_uid_certs (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
const byte *p;
u32 expire;
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIG_EXPIRE, NULL );
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_SIG_EXPIRE, NULL );
expire = p? sig->timestamp + buf32_to_u32(p) : 0;
if (expire==0 || expire > curtime )
diff --git a/g10/keydb.c b/g10/keydb.c
index 39ec5442e..aeb62abfc 100644
--- a/g10/keydb.c
+++ b/g10/keydb.c
@@ -730,14 +730,27 @@ keydb_add_resource (const char *url, unsigned int flags)
err = gpg_error (GPG_ERR_RESOURCE_LIMIT);
else
{
+ KEYBOX_HANDLE kbxhd;
+
if ((flags & KEYDB_RESOURCE_FLAG_PRIMARY))
primary_keydb = token;
all_resources[used_resources].type = rt;
all_resources[used_resources].u.kb = NULL; /* Not used here */
all_resources[used_resources].token = token;
- /* FIXME: Do a compress run if needed and no other
- user is currently using the keybox. */
+ /* Do a compress run if needed and no other user is
+ * currently using the keybox. */
+ kbxhd = keybox_new_openpgp (token, 0);
+ if (kbxhd)
+ {
+ if (!keybox_lock (kbxhd, 1, 0))
+ {
+ keybox_compress (kbxhd);
+ keybox_lock (kbxhd, 0, 0);
+ }
+
+ keybox_release (kbxhd);
+ }
used_resources++;
}
diff --git a/g10/keydb.h b/g10/keydb.h
index cc6f05956..f94b14659 100644
--- a/g10/keydb.h
+++ b/g10/keydb.h
@@ -29,11 +29,17 @@
/* What qualifies as a certification (key-signature in contrast to a
* data signature)? Note that a back signature is special and can be
* made by key and data signatures capable subkeys.) */
-#define IS_CERT(s) (IS_KEY_SIG(s) || IS_UID_SIG(s) || IS_SUBKEY_SIG(s) \
- || IS_KEY_REV(s) || IS_UID_REV(s) || IS_SUBKEY_REV(s))
+#define IS_CERT(s) (IS_KEY_SIG(s) \
+ || IS_UID_SIG(s) \
+ || IS_SUBKEY_SIG(s) \
+ || IS_KEY_REV(s) \
+ || IS_UID_REV(s) \
+ || IS_SUBKEY_REV(s) \
+ || IS_ATTST_SIGS(s) )
#define IS_SIG(s) (!IS_CERT(s))
#define IS_KEY_SIG(s) ((s)->sig_class == 0x1f)
#define IS_UID_SIG(s) (((s)->sig_class & ~3) == 0x10)
+#define IS_ATTST_SIGS(s) ((s)->sig_class == 0x16)
#define IS_SUBKEY_SIG(s) ((s)->sig_class == 0x18)
#define IS_BACK_SIG(s) ((s)->sig_class == 0x19)
#define IS_KEY_REV(s) ((s)->sig_class == 0x20)
@@ -260,6 +266,8 @@ void show_revocation_reason (ctrl_t ctrl, PKT_public_key *pk, int mode );
int check_signatures_trust (ctrl_t ctrl, PKT_signature *sig);
void release_pk_list (PK_LIST pk_list);
+int expand_id (const char *id, strlist_t *into, unsigned int flags);
+strlist_t expand_group (strlist_t input);
int build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list);
gpg_error_t find_and_check_key (ctrl_t ctrl,
const char *name, unsigned int use,
@@ -454,6 +462,7 @@ char *get_user_id_native (ctrl_t ctrl, u32 *keyid);
char *get_user_id_byfpr_native (ctrl_t ctrl, const byte *fpr, size_t fprlen);
void release_akl(void);
+int akl_empty_or_only_local (void);
int parse_auto_key_locate(const char *options);
int parse_key_origin (char *string);
const char *key_origin_string (int origin);
diff --git a/g10/keyedit.c b/g10/keyedit.c
index 9238d5d53..2ac52d315 100644
--- a/g10/keyedit.c
+++ b/g10/keyedit.c
@@ -299,11 +299,11 @@ keyedit_print_one_sig (ctrl_t ctrl, estream_t fp,
PKT_public_key *pk = keyblock->pkt->pkt.public_key;
const unsigned char *s;
- s = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PRIMARY_UID, NULL);
+ s = parse_sig_subpkt (sig, 1, SIGSUBPKT_PRIMARY_UID, NULL);
if (s && *s)
tty_fprintf (fp, " [primary]\n");
- s = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE, NULL);
+ s = parse_sig_subpkt (sig, 1, SIGSUBPKT_KEY_EXPIRE, NULL);
if (s && buf32_to_u32 (s))
tty_fprintf (fp, " [expires: %s]\n",
isotimestamp (pk->timestamp + buf32_to_u32 (s)));
@@ -3158,8 +3158,8 @@ show_prefs (PKT_user_id * uid, PKT_signature * selfsig, int verbose)
const byte *pref_ks;
size_t pref_ks_len;
- pref_ks = parse_sig_subpkt (selfsig->hashed,
- SIGSUBPKT_PREF_KS, &pref_ks_len);
+ pref_ks = parse_sig_subpkt (selfsig, 1,
+ SIGSUBPKT_PREF_KS, &pref_ks_len);
if (pref_ks && pref_ks_len)
{
tty_printf (" ");
@@ -4870,10 +4870,10 @@ menu_set_primary_uid (ctrl_t ctrl, kbnode_t pub_keyblock)
int action;
/* See whether this signature has the primary UID flag. */
- p = parse_sig_subpkt (sig->hashed,
+ p = parse_sig_subpkt (sig, 1,
SIGSUBPKT_PRIMARY_UID, NULL);
if (!p)
- p = parse_sig_subpkt (sig->unhashed,
+ p = parse_sig_subpkt (sig, 0,
SIGSUBPKT_PRIMARY_UID, NULL);
if (p && *p) /* yes */
action = selected ? 0 : -1;
@@ -5086,7 +5086,7 @@ menu_set_keyserver_url (ctrl_t ctrl, const char *url, kbnode_t pub_keyblock)
const byte *p;
size_t plen;
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_KS, &plen);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_PREF_KS, &plen);
if (p && plen)
{
tty_printf ("Current preferred keyserver for user"
diff --git a/g10/keygen.c b/g10/keygen.c
index 5aeda36ce..61682158e 100644
--- a/g10/keygen.c
+++ b/g10/keygen.c
@@ -151,7 +151,8 @@ static gpg_error_t parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
const char *expirestr,
int *r_algo, unsigned int *r_usage,
u32 *r_expire, unsigned int *r_nbits,
- const char **r_curve, int *r_version);
+ const char **r_curve, int *r_version,
+ char **r_keygrip);
static void do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
struct output_control_s *outctrl, int card );
static int write_keyblock (iobuf_t out, kbnode_t node);
@@ -691,7 +692,7 @@ add_feature_mdc (PKT_signature *sig,int enabled)
int i;
char *buf;
- s = parse_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES, &n );
+ s = parse_sig_subpkt (sig, 1, SIGSUBPKT_FEATURES, &n );
/* Already set or cleared */
if (s && n &&
((enabled && (s[0] & 0x01)) || (!enabled && !(s[0] & 0x01))))
@@ -733,7 +734,7 @@ add_feature_aead (PKT_signature *sig, int enabled)
int i;
char *buf;
- s = parse_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES, &n );
+ s = parse_sig_subpkt (sig, 1, SIGSUBPKT_FEATURES, &n );
if (s && n && ((enabled && (s[0] & 0x02)) || (!enabled && !(s[0] & 0x02))))
return; /* Already set or cleared */
@@ -775,7 +776,7 @@ add_feature_v5 (PKT_signature *sig, int enabled)
int i;
char *buf;
- s = parse_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES, &n );
+ s = parse_sig_subpkt (sig, 1, SIGSUBPKT_FEATURES, &n );
if (s && n && ((enabled && (s[0] & 0x04)) || (!enabled && !(s[0] & 0x04))))
return; /* Already set or cleared */
@@ -820,7 +821,7 @@ add_keyserver_modify (PKT_signature *sig,int enabled)
/* The keyserver modify flag is a negative flag (i.e. no-modify) */
enabled=!enabled;
- s = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KS_FLAGS, &n );
+ s = parse_sig_subpkt (sig, 1, SIGSUBPKT_KS_FLAGS, &n );
/* Already set or cleared */
if (s && n &&
((enabled && (s[0] & 0x80)) || (!enabled && !(s[0] & 0x80))))
@@ -2268,6 +2269,12 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
do
{
+ char *authkeyref, *encrkeyref, *signkeyref;
+
+ agent_scd_getattr_one ("$AUTHKEYID", &authkeyref);
+ agent_scd_getattr_one ("$ENCRKEYID", &encrkeyref);
+ agent_scd_getattr_one ("$SIGNKEYID", &signkeyref);
+
tty_printf (_("Available keys:\n"));
for (count=1,sl=keypairlist; sl; sl = sl->next, count++)
{
@@ -2297,6 +2304,10 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
&& algostr && !strncmp (algostr, "nistp", 5)
&& !(sl->flags & GCRY_PK_USAGE_ENCR))
sl->flags |= (PUBKEY_ALGO_ECDSA << 8);
+ else if (algoid == GCRY_PK_ECC
+ && algostr && !strcmp (algostr, "ed25519")
+ && !(sl->flags & GCRY_PK_USAGE_ENCR))
+ sl->flags = (PUBKEY_ALGO_EDDSA << 8);
else
sl->flags |= (map_pk_gcry_to_openpgp (algoid) << 8);
@@ -2308,17 +2319,23 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
}
if ((sl->flags & GCRY_PK_USAGE_SIGN))
{
- tty_printf ("%ssign", any?",":" (");
+ tty_printf ("%ssign%s", any?",":" (",
+ (signkeyref && keyref
+ && !strcmp (signkeyref, keyref))? "*":"");
any = 1;
}
if ((sl->flags & GCRY_PK_USAGE_AUTH))
{
- tty_printf ("%sauth", any?",":" (");
+ tty_printf ("%sauth%s", any?",":" (",
+ (authkeyref && keyref
+ && !strcmp (authkeyref, keyref))? "*":"");
any = 1;
}
if ((sl->flags & GCRY_PK_USAGE_ENCR))
{
- tty_printf ("%sencr", any?",":" (");
+ tty_printf ("%sencr%s", any?",":" (",
+ (encrkeyref && keyref
+ && !strcmp (encrkeyref, keyref))? "*":"");
any = 1;
}
tty_printf ("%s\n", any?")":"");
@@ -2330,6 +2347,10 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
cpr_kill_prompt ();
trim_spaces (answer);
selection = atoi (answer);
+ xfree (authkeyref);
+ xfree (encrkeyref);
+ xfree (signkeyref);
+
}
while (!(selection > 0 && selection < count));
@@ -3210,11 +3231,14 @@ generate_user_id (KBNODE keyblock, const char *uidstr)
* the key; this is currently 4 but can be changed with the flag "v5"
* to create a v5 key. */
static gpg_error_t
-parse_key_parameter_part (char *string, int for_subkey, int clear_cert,
+parse_key_parameter_part (ctrl_t ctrl,
+ char *string, int for_subkey, int clear_cert,
int *r_algo, unsigned int *r_size,
unsigned int *r_keyuse,
- char const **r_curve, int *r_keyversion)
+ char const **r_curve, int *r_keyversion,
+ char **r_keygrip)
{
+ gpg_error_t err;
char *flags;
int algo;
char *endp;
@@ -3225,6 +3249,8 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert,
int keyversion = 4;
int i;
const char *s;
+ int from_card = 0;
+ char *keygrip = NULL;
if (!string || !*string)
return 0; /* Success. */
@@ -3234,7 +3260,9 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert,
*flags++ = 0;
algo = 0;
- if (strlen (string) >= 3 && (digitp (string+3) || !string[3]))
+ if (!ascii_strcasecmp (string, "card"))
+ from_card = 1;
+ else if (strlen (string) >= 3 && (digitp (string+3) || !string[3]))
{
if (!ascii_memcasecmp (string, "rsa", 3))
algo = PUBKEY_ALGO_RSA;
@@ -3243,7 +3271,10 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert,
else if (!ascii_memcasecmp (string, "elg", 3))
algo = PUBKEY_ALGO_ELGAMAL_E;
}
- if (algo)
+
+ if (from_card)
+ ; /* We need the flags before we can figure out the key to use. */
+ else if (algo)
{
if (!string[3])
size = get_keysize_range (algo, NULL, NULL);
@@ -3288,7 +3319,7 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert,
keyuse |= PUBKEY_USAGE_AUTH;
else if (!ascii_strcasecmp (s, "cert"))
keyuse |= PUBKEY_USAGE_CERT;
- else if (!ascii_strcasecmp (s, "ecdsa"))
+ else if (!ascii_strcasecmp (s, "ecdsa") && !from_card)
{
if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA)
algo = PUBKEY_ALGO_ECDSA;
@@ -3299,7 +3330,7 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert,
}
ecdh_or_ecdsa = 0;
}
- else if (!ascii_strcasecmp (s, "ecdh"))
+ else if (!ascii_strcasecmp (s, "ecdh") && !from_card)
{
if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA)
algo = PUBKEY_ALGO_ECDH;
@@ -3310,7 +3341,7 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert,
}
ecdh_or_ecdsa = 0;
}
- else if (!ascii_strcasecmp (s, "eddsa"))
+ else if (!ascii_strcasecmp (s, "eddsa") && !from_card)
{
/* Not required but we allow it for consistency. */
if (algo == PUBKEY_ALGO_EDDSA)
@@ -3338,8 +3369,115 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert,
xfree (tokens);
}
- /* If not yet decided switch between ecdh and ecdsa. */
- if (ecdh_or_ecdsa && keyuse)
+ /* If not yet decided switch between ecdh and ecdsa unless we want
+ * to read the algo from the current card. */
+ if (from_card)
+ {
+ strlist_t keypairlist, sl;
+ char *reqkeyref;
+
+ if (!keyuse)
+ keyuse = (for_subkey? PUBKEY_USAGE_ENC
+ /* */ : (PUBKEY_USAGE_CERT|PUBKEY_USAGE_SIG));
+
+ /* Access the card to make sure we have one and to show the S/N. */
+ {
+ char *serialno;
+
+ err = agent_scd_serialno (&serialno, NULL);
+ if (err)
+ {
+ log_error (_("error reading the card: %s\n"), gpg_strerror (err));
+ return err;
+ }
+ if (!opt.quiet)
+ log_info (_("Serial number of the card: %s\n"), serialno);
+ xfree (serialno);
+ }
+
+ err = agent_scd_keypairinfo (ctrl, NULL, &keypairlist);
+ if (err)
+ {
+ log_error (_("error reading the card: %s\n"), gpg_strerror (err));
+ return err;
+ }
+ agent_scd_getattr_one ((keyuse & (PUBKEY_USAGE_SIG|PUBKEY_USAGE_CERT))
+ ? "$SIGNKEYID":"$ENCRKEYID", &reqkeyref);
+
+ algo = 0; /* Should already be the case. */
+ for (sl=keypairlist; sl && !algo; sl = sl->next)
+ {
+ gcry_sexp_t s_pkey;
+ char *algostr = NULL;
+ enum gcry_pk_algos algoid = 0;
+ const char *keyref;
+
+ if (!reqkeyref)
+ continue; /* Card does not provide the info (skip all). */
+
+ keyref = strchr (sl->d, ' ');
+ if (!keyref)
+ continue; /* Ooops. */
+ keyref++;
+ if (strcmp (reqkeyref, keyref))
+ continue; /* This is not the requested keyref. */
+
+ if ((keyuse & (PUBKEY_USAGE_SIG|PUBKEY_USAGE_CERT))
+ && (sl->flags & (GCRY_PK_USAGE_SIGN|GCRY_PK_USAGE_CERT)))
+ ; /* Okay */
+ else if ((keyuse & PUBKEY_USAGE_ENC)
+ && (sl->flags & GCRY_PK_USAGE_ENCR))
+ ; /* Okay */
+ else
+ continue; /* Not usable for us. */
+
+ if (agent_scd_readkey (keyref, &s_pkey))
+ continue; /* Could not read the key. */
+
+ algostr = pubkey_algo_string (s_pkey, &algoid);
+ gcry_sexp_release (s_pkey);
+
+
+ /* Map to OpenPGP algo number.
+ * We need to tweak the algo in case GCRY_PK_ECC is returned
+ * because pubkey_algo_string is not aware of the OpenPGP
+ * algo mapping. FIXME: This is an ugly hack. */
+ if (algoid == GCRY_PK_ECC
+ && algostr && !strncmp (algostr, "nistp", 5)
+ && !(sl->flags & GCRY_PK_USAGE_ENCR))
+ algo = PUBKEY_ALGO_ECDSA;
+ else if (algoid == GCRY_PK_ECC
+ && algostr && !strcmp (algostr, "ed25519")
+ && !(sl->flags & GCRY_PK_USAGE_ENCR))
+ algo = PUBKEY_ALGO_EDDSA;
+ else
+ algo = map_pk_gcry_to_openpgp (algoid);
+
+ xfree (algostr);
+ xfree (keygrip);
+ keygrip = xtrystrdup (sl->d);
+ if (!keygrip)
+ {
+ err = gpg_error_from_syserror ();
+ xfree (reqkeyref);
+ free_strlist (keypairlist);
+ return err;
+ }
+ if ((endp = strchr (keygrip, ' ')))
+ *endp = 0;
+ }
+
+ xfree (reqkeyref);
+ free_strlist (keypairlist);
+ if (!algo || !keygrip)
+ {
+ err = gpg_error (GPG_ERR_PUBKEY_ALGO);
+ log_error ("no usable key on the card: %s\n", gpg_strerror (err));
+ xfree (keygrip);
+ return err;
+ }
+ }
+ else if (ecdh_or_ecdsa && keyuse)
algo = (keyuse & PUBKEY_USAGE_ENC)? PUBKEY_ALGO_ECDH : PUBKEY_ALGO_ECDSA;
else if (ecdh_or_ecdsa)
algo = for_subkey? PUBKEY_ALGO_ECDH : PUBKEY_ALGO_ECDSA;
@@ -3379,7 +3517,10 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert,
|| ((keyuse & PUBKEY_USAGE_ENC)
&& !pubkey_get_nenc (algo))
|| (for_subkey && (keyuse & PUBKEY_USAGE_CERT)))
- return gpg_error (GPG_ERR_WRONG_KEY_USAGE);
+ {
+ xfree (keygrip);
+ return gpg_error (GPG_ERR_WRONG_KEY_USAGE);
+ }
/* Return values. */
if (r_algo)
@@ -3399,6 +3540,7 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert,
*r_size = fixup_keysize (size, algo, 1);
}
+
if (r_keyuse)
*r_keyuse = keyuse;
if (r_curve)
@@ -3406,6 +3548,11 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert,
if (r_keyversion)
*r_keyversion = keyversion;
+ if (r_keygrip)
+ *r_keygrip = keygrip;
+ else
+ xfree (keygrip);
+
return 0;
}
@@ -3427,7 +3574,7 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert,
*
* All strings with an unknown prefix are considered an elliptic
* curve. Curves which have no implicit algorithm require that FLAGS
- * is given to select whether ECDSA or ECDH is used; this can eoither
+ * is given to select whether ECDSA or ECDH is used; this can either
* be done using an algorithm keyword or usage keywords.
*
* FLAGS is a comma delimited string of keywords:
@@ -3454,16 +3601,19 @@ parse_key_parameter_part (char *string, int for_subkey, int clear_cert,
*
*/
gpg_error_t
-parse_key_parameter_string (const char *string, int part,
+parse_key_parameter_string (ctrl_t ctrl,
+ const char *string, int part,
unsigned int suggested_use,
int *r_algo, unsigned int *r_size,
unsigned int *r_keyuse,
char const **r_curve,
int *r_version,
+ char **r_keygrip,
int *r_subalgo, unsigned int *r_subsize,
unsigned int *r_subkeyuse,
char const **r_subcurve,
- int *r_subversion)
+ int *r_subversion,
+ char **r_subkeygrip)
{
gpg_error_t err = 0;
char *primary, *secondary;
@@ -3478,6 +3628,8 @@ parse_key_parameter_string (const char *string, int part,
*r_curve = NULL;
if (r_version)
*r_version = 4;
+ if (r_keygrip)
+ *r_keygrip = NULL;
if (r_subalgo)
*r_subalgo = 0;
if (r_subsize)
@@ -3488,6 +3640,8 @@ parse_key_parameter_string (const char *string, int part,
*r_subcurve = NULL;
if (r_subversion)
*r_subversion = 4;
+ if (r_subkeygrip)
+ *r_subkeygrip = NULL;
if (!string || !*string
|| !ascii_strcasecmp (string, "default") || !strcmp (string, "-"))
@@ -3495,6 +3649,8 @@ parse_key_parameter_string (const char *string, int part,
else if (!ascii_strcasecmp (string, "future-default")
|| !ascii_strcasecmp (string, "futuredefault"))
string = FUTURE_STD_KEY_PARAM;
+ else if (!ascii_strcasecmp (string, "card"))
+ string = "card/cert,sign+card/encr";
primary = xstrdup (string);
secondary = strchr (primary, '+');
@@ -3502,11 +3658,14 @@ parse_key_parameter_string (const char *string, int part,
*secondary++ = 0;
if (part == -1 || part == 0)
{
- err = parse_key_parameter_part (primary, 0, 0, r_algo, r_size,
- r_keyuse, r_curve, r_version);
+ err = parse_key_parameter_part (ctrl, primary,
+ 0, 0, r_algo, r_size,
+ r_keyuse, r_curve, r_version, r_keygrip);
if (!err && part == -1)
- err = parse_key_parameter_part (secondary, 1, 0, r_subalgo, r_subsize,
- r_subkeyuse, r_subcurve, r_subversion);
+ err = parse_key_parameter_part (ctrl, secondary,
+ 1, 0, r_subalgo, r_subsize,
+ r_subkeyuse, r_subcurve, r_subversion,
+ r_subkeygrip);
}
else if (part == 1)
{
@@ -3518,18 +3677,21 @@ parse_key_parameter_string (const char *string, int part,
* to force clearing the cert usage. */
if (secondary)
{
- err = parse_key_parameter_part (secondary, 1, 0,
+ err = parse_key_parameter_part (ctrl, secondary,
+ 1, 0,
r_algo, r_size, r_keyuse, r_curve,
- r_version);
+ r_version, r_keygrip);
if (!err && suggested_use && r_keyuse && !(suggested_use & *r_keyuse))
- err = parse_key_parameter_part (primary, 1, 1 /*(clear cert)*/,
+ err = parse_key_parameter_part (ctrl, primary,
+ 1, 1 /*(clear cert)*/,
r_algo, r_size, r_keyuse, r_curve,
- r_version);
+ r_version, r_keygrip);
}
else
- err = parse_key_parameter_part (primary, 1, 0,
+ err = parse_key_parameter_part (ctrl, primary,
+ 1, 0,
r_algo, r_size, r_keyuse, r_curve,
- r_version);
+ r_version, r_keygrip);
}
xfree (primary);
@@ -3594,7 +3756,7 @@ get_parameter_passphrase (struct para_data_s *para)
static int
-get_parameter_algo( struct para_data_s *para, enum para_name key,
+get_parameter_algo (ctrl_t ctrl, struct para_data_s *para, enum para_name key,
int *r_default)
{
int i;
@@ -3616,9 +3778,9 @@ get_parameter_algo( struct para_data_s *para, enum para_name key,
* for the curve etc. That is a ugly but demanded for backward
* compatibility with the batch key generation. It would be
* better to make full use of parse_key_parameter_string. */
- parse_key_parameter_string (NULL, 0, 0,
- &i, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL);
+ parse_key_parameter_string (ctrl, NULL, 0, 0,
+ &i, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL);
if (r_default)
*r_default = 1;
}
@@ -3815,7 +3977,7 @@ proc_parameter_file (ctrl_t ctrl, struct para_data_s *para, const char *fname,
r = get_parameter( para, pKEYTYPE );
if(r)
{
- algo = get_parameter_algo (para, pKEYTYPE, &is_default);
+ algo = get_parameter_algo (ctrl, para, pKEYTYPE, &is_default);
if (openpgp_pk_test_algo2 (algo, PUBKEY_USAGE_SIG))
{
log_error ("%s:%d: invalid algorithm\n", fname, r->lnr );
@@ -3857,7 +4019,7 @@ proc_parameter_file (ctrl_t ctrl, struct para_data_s *para, const char *fname,
r = get_parameter( para, pSUBKEYTYPE );
if(r)
{
- algo = get_parameter_algo (para, pSUBKEYTYPE, &is_default);
+ algo = get_parameter_algo (ctrl, para, pSUBKEYTYPE, &is_default);
if (openpgp_pk_test_algo (algo))
{
log_error ("%s:%d: invalid algorithm\n", fname, r->lnr );
@@ -4225,7 +4387,7 @@ read_parameter_file (ctrl_t ctrl, const char *fname )
static struct para_data_s *
quickgen_set_para (struct para_data_s *para, int for_subkey,
int algo, int nbits, const char *curve, unsigned int use,
- int version)
+ int version, const char *keygrip)
{
struct para_data_s *r;
@@ -4247,7 +4409,15 @@ quickgen_set_para (struct para_data_s *para, int for_subkey,
r->next = para;
para = r;
- if (curve)
+ if (keygrip)
+ {
+ r = xmalloc_clear (sizeof *r + strlen (keygrip));
+ r->key = for_subkey? pSUBKEYGRIP : pKEYGRIP;
+ strcpy (r->u.value, keygrip);
+ r->next = para;
+ para = r;
+ }
+ else if (curve)
{
r = xmalloc_clear (sizeof *r + strlen (curve));
r->key = for_subkey? pSUBKEYCURVE : pKEYCURVE;
@@ -4360,7 +4530,8 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr,
if ((!*algostr || !ascii_strcasecmp (algostr, "default")
|| !ascii_strcasecmp (algostr, "future-default")
- || !ascii_strcasecmp (algostr, "futuredefault"))
+ || !ascii_strcasecmp (algostr, "futuredefault")
+ || !ascii_strcasecmp (algostr, "card"))
&& (!*usagestr || !ascii_strcasecmp (usagestr, "default")
|| !strcmp (usagestr, "-")))
{
@@ -4369,23 +4540,25 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr,
unsigned int size, subsize;
unsigned int keyuse, subkeyuse;
const char *curve, *subcurve;
+ char *keygrip, *subkeygrip;
- err = parse_key_parameter_string (algostr, -1, 0,
+ err = parse_key_parameter_string (ctrl, algostr, -1, 0,
&algo, &size, &keyuse, &curve, &version,
+ &keygrip,
&subalgo, &subsize, &subkeyuse,
- &subcurve, &subversion);
+ &subcurve, &subversion, &subkeygrip);
if (err)
{
log_error (_("Key generation failed: %s\n"), gpg_strerror (err));
goto leave;
}
- para = quickgen_set_para (para, 0, algo, size, curve, keyuse, version);
+ para = quickgen_set_para (para, 0, algo, size, curve, keyuse, version,
+ keygrip);
if (subalgo)
para = quickgen_set_para (para, 1,
subalgo, subsize, subcurve, subkeyuse,
- subversion);
-
+ subversion, subkeygrip);
if (*expirestr)
{
u32 expire;
@@ -4403,6 +4576,9 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr,
r->next = para;
para = r;
}
+
+ xfree (keygrip);
+ xfree (subkeygrip);
}
else
{
@@ -4412,22 +4588,26 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr,
u32 expire;
unsigned int nbits;
const char *curve;
+ char *keygrip;
err = parse_algo_usage_expire (ctrl, 0, algostr, usagestr, expirestr,
&algo, &use, &expire, &nbits, &curve,
- &version);
+ &version, &keygrip);
if (err)
{
log_error (_("Key generation failed: %s\n"), gpg_strerror (err) );
goto leave;
}
- para = quickgen_set_para (para, 0, algo, nbits, curve, use, version);
+ para = quickgen_set_para (para, 0, algo, nbits, curve, use, version,
+ keygrip);
r = xmalloc_clear (sizeof *r + 20);
r->key = pKEYEXPIRE;
r->u.expire = expire;
r->next = para;
para = r;
+
+ xfree (keygrip);
}
/* If the pinentry loopback mode is not and we have a static
@@ -4740,6 +4920,7 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
unsigned int size, subsize;
unsigned int keyuse, subkeyuse;
const char *curve, *subcurve;
+ char *keygrip, *subkeygrip;
tty_printf ( _("Note: Use \"%s %s\""
" for a full featured key generation dialog.\n"),
@@ -4750,22 +4931,27 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
#endif
, "--full-generate-key" );
- err = parse_key_parameter_string (NULL, -1, 0,
+ err = parse_key_parameter_string (ctrl, NULL, -1, 0,
&algo, &size, &keyuse, &curve, &version,
+ &keygrip,
&subalgo, &subsize,
- &subkeyuse, &subcurve, &subversion);
+ &subkeyuse, &subcurve, &subversion,
+ &subkeygrip);
if (err)
{
log_error (_("Key generation failed: %s\n"), gpg_strerror (err));
return;
}
- para = quickgen_set_para (para, 0, algo, size, curve, keyuse, version);
+ para = quickgen_set_para (para, 0,
+ algo, size, curve, keyuse,
+ version, keygrip);
if (subalgo)
para = quickgen_set_para (para, 1,
subalgo, subsize, subcurve, subkeyuse,
- subversion);
-
+ subversion, subkeygrip);
+ xfree (keygrip);
+ xfree (subkeygrip);
}
@@ -5049,7 +5235,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
node of the subkey but that is more work than just to pass the
current timestamp. */
- algo = get_parameter_algo( para, pKEYTYPE, NULL );
+ algo = get_parameter_algo (ctrl, para, pKEYTYPE, NULL );
expire = get_parameter_u32( para, pKEYEXPIRE );
key_from_hexgrip = get_parameter_value (para, pKEYGRIP);
@@ -5112,7 +5298,8 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
if (!err && card && get_parameter (para, pAUTHKEYTYPE))
{
- err = gen_card_key (3, get_parameter_algo( para, pAUTHKEYTYPE, NULL ),
+ err = gen_card_key (3, get_parameter_algo (ctrl, para,
+ pAUTHKEYTYPE, NULL ),
0, pub_root, &timestamp, expire, keygen_flags);
if (!err)
err = write_keybinding (ctrl, pub_root, pri_psk, NULL,
@@ -5121,7 +5308,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
if (!err && get_parameter (para, pSUBKEYTYPE))
{
- int subkey_algo = get_parameter_algo (para, pSUBKEYTYPE, NULL);
+ int subkey_algo = get_parameter_algo (ctrl, para, pSUBKEYTYPE, NULL);
s = NULL;
key_from_hexgrip = get_parameter_value (para, pSUBKEYGRIP);
@@ -5216,7 +5403,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
int no_enc_rsa;
PKT_public_key *pk;
- no_enc_rsa = ((get_parameter_algo (para, pKEYTYPE, NULL)
+ no_enc_rsa = ((get_parameter_algo (ctrl, para, pKEYTYPE, NULL)
== PUBKEY_ALGO_RSA)
&& get_parameter_uint (para, pKEYUSAGE)
&& !((get_parameter_uint (para, pKEYUSAGE)
@@ -5249,7 +5436,8 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
if (!opt.batch
- && (get_parameter_algo (para, pKEYTYPE, NULL) == PUBKEY_ALGO_DSA
+ && (get_parameter_algo (ctrl, para,
+ pKEYTYPE, NULL) == PUBKEY_ALGO_DSA
|| no_enc_rsa )
&& !get_parameter (para, pSUBKEYTYPE) )
{
@@ -5289,7 +5477,7 @@ parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
const char *expirestr,
int *r_algo, unsigned int *r_usage, u32 *r_expire,
unsigned int *r_nbits, const char **r_curve,
- int *r_version)
+ int *r_version, char **r_keygrip)
{
gpg_error_t err;
int algo;
@@ -5300,6 +5488,8 @@ parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
const char *curve = NULL;
*r_curve = NULL;
+ if (r_keygrip)
+ *r_keygrip = NULL;
nbits = 0;
@@ -5312,12 +5502,20 @@ parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
}
- err = parse_key_parameter_string (algostr, for_subkey? 1 : 0,
+ err = parse_key_parameter_string (ctrl, algostr, for_subkey? 1 : 0,
usagestr? parse_usagestr (usagestr):0,
&algo, &nbits, &use, &curve, &version,
- NULL, NULL, NULL, NULL, NULL);
+ r_keygrip,
+ NULL, NULL, NULL, NULL, NULL, NULL);
if (err)
- return err;
+ {
+ if (r_keygrip)
+ {
+ xfree (*r_keygrip);
+ *r_keygrip = NULL;
+ }
+ return err;
+ }
/* Parse the usage string. */
if (!usagestr || !*usagestr
@@ -5326,7 +5524,14 @@ parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
else if ((wantuse = parse_usagestr (usagestr)) != -1)
use = wantuse;
else
- return gpg_error (GPG_ERR_INV_VALUE);
+ {
+ if (r_keygrip)
+ {
+ xfree (*r_keygrip);
+ *r_keygrip = NULL;
+ }
+ return gpg_error (GPG_ERR_INV_VALUE);
+ }
/* Make sure a primary key has the CERT usage. */
if (!for_subkey)
@@ -5340,12 +5545,26 @@ parse_algo_usage_expire (ctrl_t ctrl, int for_subkey,
|| ((use & PUBKEY_USAGE_ENC)
&& !pubkey_get_nenc (algo))
|| (for_subkey && (use & PUBKEY_USAGE_CERT)))
- return gpg_error (GPG_ERR_WRONG_KEY_USAGE);
+ {
+ if (r_keygrip)
+ {
+ xfree (*r_keygrip);
+ *r_keygrip = NULL;
+ }
+ return gpg_error (GPG_ERR_WRONG_KEY_USAGE);
+ }
/* Parse the expire string. */
expire = parse_expire_string (expirestr);
if (expire == (u32)-1 )
- return gpg_error (GPG_ERR_INV_VALUE);
+ {
+ if (r_keygrip)
+ {
+ xfree (*r_keygrip);
+ *r_keygrip = NULL;
+ }
+ return gpg_error (GPG_ERR_INV_VALUE);
+ }
if (curve)
*r_curve = curve;
@@ -5467,7 +5686,7 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr,
err = parse_algo_usage_expire (ctrl, 1, algostr, usagestr, expirestr,
&algo, &use, &expire, &nbits, &curve,
- &version);
+ &version, &key_from_hexgrip);
if (err)
goto leave;
diff --git a/g10/keylist.c b/g10/keylist.c
index 5f5fe9d34..dacc13788 100644
--- a/g10/keylist.c
+++ b/g10/keylist.c
@@ -338,8 +338,7 @@ show_policy_url (PKT_signature * sig, int indent, int mode)
int seq = 0, crit;
estream_t fp = mode < 0? NULL : mode ? log_get_stream () : es_stdout;
- while ((p =
- enum_sig_subpkt (sig->hashed, SIGSUBPKT_POLICY, &len, &seq, &crit)))
+ while ((p = enum_sig_subpkt (sig, 1, SIGSUBPKT_POLICY, &len, &seq, &crit)))
{
if (mode != 2)
{
@@ -379,9 +378,7 @@ show_keyserver_url (PKT_signature * sig, int indent, int mode)
int seq = 0, crit;
estream_t fp = mode < 0? NULL : mode ? log_get_stream () : es_stdout;
- while ((p =
- enum_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_KS, &len, &seq,
- &crit)))
+ while ((p = enum_sig_subpkt (sig, 1, SIGSUBPKT_PREF_KS, &len, &seq, &crit)))
{
if (mode != 2)
{
@@ -542,7 +539,11 @@ list_all (ctrl_t ctrl, int secret, int mark_secret)
lastresname = NULL;
do
{
+ if (secret)
+ glo_ctrl.silence_parse_warnings++;
rc = keydb_get_keyblock (hd, &keyblock);
+ if (secret)
+ glo_ctrl.silence_parse_warnings--;
if (rc)
{
if (gpg_err_code (rc) == GPG_ERR_LEGACY_KEY)
@@ -870,12 +871,12 @@ print_subpackets_colon (PKT_signature * sig)
seq = 0;
- while ((p = enum_sig_subpkt (sig->hashed, *i, &len, &seq, &crit)))
+ while ((p = enum_sig_subpkt (sig, 1, *i, &len, &seq, &crit)))
print_one_subpacket (*i, len, 0x01 | (crit ? 0x02 : 0), p);
seq = 0;
- while ((p = enum_sig_subpkt (sig->unhashed, *i, &len, &seq, &crit)))
+ while ((p = enum_sig_subpkt (sig, 0, *i, &len, &seq, &crit)))
print_one_subpacket (*i, len, 0x00 | (crit ? 0x02 : 0), p);
}
}
diff --git a/g10/keyserver.c b/g10/keyserver.c
index 030bc9297..c2e304f09 100644
--- a/g10/keyserver.c
+++ b/g10/keyserver.c
@@ -31,7 +31,6 @@
#include "filter.h"
#include "keydb.h"
#include "../common/status.h"
-#include "exec.h"
#include "main.h"
#include "../common/i18n.h"
#include "../common/ttyio.h"
@@ -453,7 +452,7 @@ parse_preferred_keyserver(PKT_signature *sig)
const byte *p;
size_t plen;
- p=parse_sig_subpkt(sig->hashed,SIGSUBPKT_PREF_KS,&plen);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_PREF_KS, &plen);
if(p && plen)
{
byte *dupe=xmalloc(plen+1);
@@ -1812,9 +1811,10 @@ keyserver_put (ctrl_t ctrl, strlist_t keyspecs)
log_error (_("skipped \"%s\": %s\n"), kspec->d, gpg_strerror (err));
else
{
- log_info (_("sending key %s to %s\n"),
- keystr (keyblock->pkt->pkt.public_key->keyid),
- ksurl?ksurl:"[?]");
+ if (!opt.quiet)
+ log_info (_("sending key %s to %s\n"),
+ keystr (keyblock->pkt->pkt.public_key->keyid),
+ ksurl?ksurl:"[?]");
err = gpg_dirmngr_ks_put (ctrl, data, datalen, keyblock);
release_kbnode (keyblock);
diff --git a/g10/mainproc.c b/g10/mainproc.c
index 8a9005c21..c12039e6d 100644
--- a/g10/mainproc.c
+++ b/g10/mainproc.c
@@ -325,7 +325,8 @@ symkey_decrypt_seskey (DEK *dek, byte *seskey, size_t slen)
* the gnupg < 2.2 bug compatible case which would terminate the
* process on GPG_ERR_CIPHER_ALGO. Note that with AEAD (above)
* we will have a reliable test here. */
- if (openpgp_cipher_test_algo (seskey[0]))
+ if (openpgp_cipher_test_algo (seskey[0])
+ || openpgp_cipher_get_algo_keylen (seskey[0]) != slen - 1)
{
err = gpg_error (GPG_ERR_CHECKSUM);
goto leave;
@@ -583,7 +584,7 @@ proc_encrypted (CTX c, PACKET *pkt)
struct pubkey_enc_list *list;
for (list = c->pkenc_list; list; list = list->next)
- if (list->result != -1)
+ if (list->result && list->result != -1)
{
char buf[20];
snprintf (buf, sizeof buf, "%08lX%08lX",
@@ -1783,7 +1784,7 @@ issuer_fpr_raw (PKT_signature *sig, size_t *r_len)
const byte *p;
size_t n;
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_ISSUER_FPR, &n);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_ISSUER_FPR, &n);
if (p && ((n == 21 && p[0] == 4) || (n == 33 && p[0] == 5)))
{
*r_len = n - 1;
@@ -2016,7 +2017,7 @@ check_sig_and_print (CTX c, kbnode_t node)
size_t n;
int any_pref_ks = 0;
- while ((p=enum_sig_subpkt (sig->hashed,SIGSUBPKT_PREF_KS,&n,&seq,NULL)))
+ while ((p=enum_sig_subpkt (sig, 1, SIGSUBPKT_PREF_KS, &n, &seq, NULL)))
{
/* According to my favorite copy editor, in English grammar,
you say "at" if the key is located on a web page, but
diff --git a/g10/options.h b/g10/options.h
index bfa2cc31e..26c8439b6 100644
--- a/g10/options.h
+++ b/g10/options.h
@@ -252,6 +252,9 @@ struct
unsigned int rfc4880bis:1;
/* Hack: --output is not given but OUTFILE was temporary set to "-". */
unsigned int dummy_outfile:1;
+ /* Force the use of the OpenPGP card and do not allow the use of
+ * another card. */
+ unsigned int use_only_openpgp_card:1;
} flags;
/* Linked list of ways to find a key if the key isn't on the local
@@ -301,6 +304,9 @@ struct {
codes. Thus for the --server purposes we store some of the error
codes here. FIXME! */
gpg_error_t lasterr;
+
+ /* Kludge to silence some warnings using --secret-key-list. */
+ int silence_parse_warnings;
} glo_ctrl;
#define DBG_PACKET_VALUE 1 /* debug packet reading/writing */
diff --git a/g10/packet.h b/g10/packet.h
index 479f25044..5023903d2 100644
--- a/g10/packet.h
+++ b/g10/packet.h
@@ -775,58 +775,61 @@ int skip_some_packets (iobuf_t inp, unsigned int n);
int parse_signature( iobuf_t inp, int pkttype, unsigned long pktlen,
PKT_signature *sig );
-/* Given a subpacket area (typically either PKT_signature.hashed or
- PKT_signature.unhashed), either:
-
- - test whether there are any subpackets with the critical bit set
- that we don't understand,
-
- - list the subpackets, or,
-
- - find a subpacket with a specific type.
-
- REQTYPE indicates the type of operation.
-
- If REQTYPE is SIGSUBPKT_TEST_CRITICAL, then this function checks
- whether there are any subpackets that have the critical bit and
- which GnuPG cannot handle. If GnuPG understands all subpackets
- whose critical bit is set, then this function returns simply
- returns SUBPKTS. If there is a subpacket whose critical bit is set
- and which GnuPG does not understand, then this function returns
- NULL and, if START is not NULL, sets *START to the 1-based index of
- the subpacket that violates the constraint.
-
- If REQTYPE is SIGSUBPKT_LIST_HASHED or SIGSUBPKT_LIST_UNHASHED, the
- packets are dumped. Note: if REQTYPE is SIGSUBPKT_LIST_HASHED,
- this function does not check whether the hash is correct; this is
- merely an indication of the section that the subpackets came from.
-
- If REQTYPE is anything else, then this function interprets the
- values as a subpacket type and looks for the first subpacket with
- that type. If such a packet is found, *CRITICAL (if not NULL) is
- set if the critical bit was set, *RET_N is set to the offset of the
- subpacket's content within the SUBPKTS buffer, *START is set to the
- 1-based index of the subpacket within the buffer, and returns
- &SUBPKTS[*RET_N].
-
- *START is the number of initial subpackets to not consider. Thus,
- if *START is 2, then the first 2 subpackets are ignored. */
-const byte *enum_sig_subpkt ( const subpktarea_t *subpkts,
- sigsubpkttype_t reqtype,
- size_t *ret_n, int *start, int *critical );
+/* Given a signature packet, either:
+ *
+ * - test whether there are any subpackets with the critical bit set
+ * that we don't understand,
+ *
+ * - list the subpackets, or,
+ *
+ * - find a subpacket with a specific type.
+ *
+ * The WANT_HASHED flag indicates that the hashed area shall be
+ * considered.
+ *
+ * REQTYPE indicates the type of operation.
+ *
+ * If REQTYPE is SIGSUBPKT_TEST_CRITICAL, then this function checks
+ * whether there are any subpackets that have the critical bit and
+ * which GnuPG cannot handle. If GnuPG understands all subpackets
+ * whose critical bit is set, then this function returns simply
+ * returns SUBPKTS. If there is a subpacket whose critical bit is set
+ * and which GnuPG does not understand, then this function returns
+ * NULL and, if START is not NULL, sets *START to the 1-based index of
+ * the subpacket that violates the constraint.
+ *
+ * If REQTYPE is SIGSUBPKT_LIST_HASHED or SIGSUBPKT_LIST_UNHASHED, the
+ * packets are dumped. Note: if REQTYPE is SIGSUBPKT_LIST_HASHED,
+ * this function does not check whether the hash is correct; this is
+ * merely an indication of the section that the subpackets came from.
+ *
+ * If REQTYPE is anything else, then this function interprets the
+ * values as a subpacket type and looks for the first subpacket with
+ * that type. If such a packet is found, *CRITICAL (if not NULL) is
+ * set if the critical bit was set, *RET_N is set to the offset of the
+ * subpacket's content within the SUBPKTS buffer, *START is set to the
+ * 1-based index of the subpacket within the buffer, and returns
+ * &SUBPKTS[*RET_N].
+ *
+ * *START is the number of initial subpackets to not consider. Thus,
+ * if *START is 2, then the first 2 subpackets are ignored.
+ */
+const byte *enum_sig_subpkt (PKT_signature *sig, int want_hashed,
+ sigsubpkttype_t reqtype,
+ size_t *ret_n, int *start, int *critical );
/* Shorthand for:
-
- enum_sig_subpkt (buffer, reqtype, ret_n, NULL, NULL); */
-const byte *parse_sig_subpkt ( const subpktarea_t *buffer,
- sigsubpkttype_t reqtype,
- size_t *ret_n );
+ *
+ * enum_sig_subpkt (sig, want_hashed, reqtype, ret_n, NULL, NULL);
+ */
+const byte *parse_sig_subpkt (PKT_signature *sig, int want_hashed,
+ sigsubpkttype_t reqtype,
+ size_t *ret_n );
/* This calls parse_sig_subpkt first on the hashed signature area in
- SIG and then, if that returns NULL, calls parse_sig_subpkt on the
- unhashed subpacket area in SIG. */
-const byte *parse_sig_subpkt2 ( PKT_signature *sig,
- sigsubpkttype_t reqtype);
+ * SIG and then, if that returns NULL, calls parse_sig_subpkt on the
+ * unhashed subpacket area in SIG. */
+const byte *parse_sig_subpkt2 (PKT_signature *sig, sigsubpkttype_t reqtype);
/* Returns whether the N byte large buffer BUFFER is sufficient to
hold a subpacket of type TYPE. Note: the buffer refers to the
diff --git a/g10/parse-packet.c b/g10/parse-packet.c
index ab82d475a..874ff76b0 100644
--- a/g10/parse-packet.c
+++ b/g10/parse-packet.c
@@ -270,7 +270,7 @@ unknown_pubkey_warning (int algo)
encryption/signing. */
if (pubkey_get_npkey (algo))
{
- if (opt.verbose)
+ if (opt.verbose && !glo_ctrl.silence_parse_warnings)
{
if (!pubkey_get_nsig (algo))
log_info ("public key algorithm %s not suitable for %s\n",
@@ -285,7 +285,7 @@ unknown_pubkey_warning (int algo)
algo &= 0xff;
if (!unknown_pubkey_algos[algo])
{
- if (opt.verbose)
+ if (opt.verbose && !glo_ctrl.silence_parse_warnings)
log_info (_("can't handle public key algorithm %d\n"), algo);
unknown_pubkey_algos[algo] = 1;
}
@@ -1360,17 +1360,20 @@ parse_pubkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
/* Dump a subpacket to LISTFP. BUFFER contains the subpacket in
- question and points to the type field in the subpacket header (not
- the start of the header). TYPE is the subpacket's type with the
- critical bit cleared. CRITICAL is the value of the CRITICAL bit.
- BUFLEN is the length of the buffer and LENGTH is the length of the
- subpacket according to the subpacket's header. */
+ * question and points to the type field in the subpacket header (not
+ * the start of the header). TYPE is the subpacket's type with the
+ * critical bit cleared. CRITICAL is the value of the CRITICAL bit.
+ * BUFLEN is the length of the buffer and LENGTH is the length of the
+ * subpacket according to the subpacket's header. DIGEST_ALGO is the
+ * digest algo of the signature. */
static void
dump_sig_subpkt (int hashed, int type, int critical,
- const byte * buffer, size_t buflen, size_t length)
+ const byte * buffer, size_t buflen, size_t length,
+ int digest_algo)
{
const char *p = NULL;
int i;
+ int nprinted;
/* The CERT has warning out with explains how to use GNUPG to detect
* the ARRs - we print our old message here when it is a faked ARR
@@ -1388,9 +1391,11 @@ dump_sig_subpkt (int hashed, int type, int critical,
buffer++;
length--;
- es_fprintf (listfp, "\t%s%ssubpkt %d len %u (", /*) */
- critical ? "critical " : "",
- hashed ? "hashed " : "", type, (unsigned) length);
+ nprinted = es_fprintf (listfp, "\t%s%ssubpkt %d len %u (", /*) */
+ critical ? "critical " : "",
+ hashed ? "hashed " : "", type, (unsigned) length);
+ if (nprinted < 1)
+ nprinted = 1; /*(we use (nprinted-1) later.)*/
if (length > buflen)
{
es_fprintf (listfp, "too short: buffer is only %u)\n", (unsigned) buflen);
@@ -1585,6 +1590,32 @@ dump_sig_subpkt (int hashed, int type, int critical,
buffer[0] == 3 ? buffer[15] : buffer[2],
buffer[0] == 3 ? buffer[16] : buffer[3]);
break;
+
+ case SIGSUBPKT_ATTST_SIGS:
+ {
+ unsigned int hlen;
+
+ es_fputs ("attst-sigs: ", listfp);
+ hlen = gcry_md_get_algo_dlen (map_md_openpgp_to_gcry (digest_algo));
+ if (!hlen)
+ p = "[unknown digest algo]";
+ else if ((length % hlen))
+ p = "[invalid length]";
+ else
+ {
+ es_fprintf (listfp, "%d", length/hlen);
+ while (length)
+ {
+ es_fprintf (listfp, "\n\t%*s", nprinted-1, "");
+ es_write_hexstring (listfp, buffer, hlen, 0, NULL);
+ buffer += hlen;
+ length -= hlen;
+ }
+ }
+ }
+ break;
+
+
default:
if (type >= 100 && type <= 110)
p = "experimental / private subpacket";
@@ -1627,6 +1658,7 @@ parse_one_sig_subpkt (const byte * buffer, size_t n, int type)
case SIGSUBPKT_PREF_KS:
case SIGSUBPKT_FEATURES:
case SIGSUBPKT_REGEXP:
+ case SIGSUBPKT_ATTST_SIGS:
return 0;
case SIGSUBPKT_SIGNATURE:
case SIGSUBPKT_EXPORTABLE:
@@ -1679,7 +1711,7 @@ can_handle_critical_notation (const byte *name, size_t len)
if (sl->flags == len && !memcmp (sl->d, name, len))
return 1; /* Known */
- if (opt.verbose)
+ if (opt.verbose && !glo_ctrl.silence_parse_warnings)
{
log_info(_("Unknown critical signature notation: ") );
print_utf8_buffer (log_get_stream(), name, len);
@@ -1721,6 +1753,7 @@ can_handle_critical (const byte * buffer, size_t n, int type)
case SIGSUBPKT_FEATURES:
case SIGSUBPKT_TRUST:
case SIGSUBPKT_REGEXP:
+ case SIGSUBPKT_ATTST_SIGS:
/* Is it enough to show the policy or keyserver? */
case SIGSUBPKT_POLICY:
case SIGSUBPKT_PREF_KS:
@@ -1734,8 +1767,8 @@ can_handle_critical (const byte * buffer, size_t n, int type)
const byte *
-enum_sig_subpkt (const subpktarea_t * pktbuf, sigsubpkttype_t reqtype,
- size_t * ret_n, int *start, int *critical)
+enum_sig_subpkt (PKT_signature *sig, int want_hashed, sigsubpkttype_t reqtype,
+ size_t *ret_n, int *start, int *critical)
{
const byte *buffer;
int buflen;
@@ -1743,6 +1776,7 @@ enum_sig_subpkt (const subpktarea_t * pktbuf, sigsubpkttype_t reqtype,
int critical_dummy;
int offset;
size_t n;
+ const subpktarea_t *pktbuf = want_hashed? sig->hashed : sig->unhashed;
int seq = 0;
int reqseq = start ? *start : 0;
@@ -1800,7 +1834,7 @@ enum_sig_subpkt (const subpktarea_t * pktbuf, sigsubpkttype_t reqtype,
goto too_short;
if (!can_handle_critical (buffer + 1, n - 1, type))
{
- if (opt.verbose)
+ if (opt.verbose && !glo_ctrl.silence_parse_warnings)
log_info (_("subpacket of type %d has "
"critical bit set\n"), type);
if (start)
@@ -1811,7 +1845,7 @@ enum_sig_subpkt (const subpktarea_t * pktbuf, sigsubpkttype_t reqtype,
}
else if (reqtype < 0) /* List packets. */
dump_sig_subpkt (reqtype == SIGSUBPKT_LIST_HASHED,
- type, *critical, buffer, buflen, n);
+ type, *critical, buffer, buflen, n, sig->digest_algo);
else if (type == reqtype) /* Found. */
{
buffer++;
@@ -1851,14 +1885,14 @@ enum_sig_subpkt (const subpktarea_t * pktbuf, sigsubpkttype_t reqtype,
return NULL; /* End of packets; not found. */
too_short:
- if (opt.verbose)
+ if (opt.verbose && !glo_ctrl.silence_parse_warnings)
log_info ("buffer shorter than subpacket\n");
if (start)
*start = -1;
return NULL;
no_type_byte:
- if (opt.verbose)
+ if (opt.verbose && !glo_ctrl.silence_parse_warnings)
log_info ("type octet missing in subpacket\n");
if (start)
*start = -1;
@@ -1867,21 +1901,21 @@ enum_sig_subpkt (const subpktarea_t * pktbuf, sigsubpkttype_t reqtype,
const byte *
-parse_sig_subpkt (const subpktarea_t * buffer, sigsubpkttype_t reqtype,
- size_t * ret_n)
+parse_sig_subpkt (PKT_signature *sig, int want_hashed, sigsubpkttype_t reqtype,
+ size_t *ret_n)
{
- return enum_sig_subpkt (buffer, reqtype, ret_n, NULL, NULL);
+ return enum_sig_subpkt (sig, want_hashed, reqtype, ret_n, NULL, NULL);
}
const byte *
-parse_sig_subpkt2 (PKT_signature * sig, sigsubpkttype_t reqtype)
+parse_sig_subpkt2 (PKT_signature *sig, sigsubpkttype_t reqtype)
{
const byte *p;
- p = parse_sig_subpkt (sig->hashed, reqtype, NULL);
+ p = parse_sig_subpkt (sig, 1, reqtype, NULL);
if (!p)
- p = parse_sig_subpkt (sig->unhashed, reqtype, NULL);
+ p = parse_sig_subpkt (sig, 0, reqtype, NULL);
return p;
}
@@ -1897,8 +1931,8 @@ parse_revkeys (PKT_signature * sig)
if (sig->sig_class != 0x1F)
return;
- while ((revkey = enum_sig_subpkt (sig->hashed, SIGSUBPKT_REV_KEY,
- &len, &seq, NULL)))
+ while ((revkey = enum_sig_subpkt (sig, 1, SIGSUBPKT_REV_KEY,
+ &len, &seq, NULL)))
{
/* Consider only valid packets. They must have a length of
* either 2+20 or 2+32 octets and bit 7 of the class octet must
@@ -2062,21 +2096,21 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen,
/* Set sig->flags.unknown_critical if there is a critical bit
* set for packets which we do not understand. */
- if (!parse_sig_subpkt (sig->hashed, SIGSUBPKT_TEST_CRITICAL, NULL)
- || !parse_sig_subpkt (sig->unhashed, SIGSUBPKT_TEST_CRITICAL, NULL))
+ if (!parse_sig_subpkt (sig, 1, SIGSUBPKT_TEST_CRITICAL, NULL)
+ || !parse_sig_subpkt (sig, 0, SIGSUBPKT_TEST_CRITICAL, NULL))
sig->flags.unknown_critical = 1;
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIG_CREATED, NULL);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_SIG_CREATED, NULL);
if (p)
sig->timestamp = buf32_to_u32 (p);
else if (!(sig->pubkey_algo >= 100 && sig->pubkey_algo <= 110)
- && opt.verbose)
+ && opt.verbose && !glo_ctrl.silence_parse_warnings)
log_info ("signature packet without timestamp\n");
/* Set the key id. We first try the issuer fingerprint and if
* it is a v4 signature the fallback to the issuer. Note that
* only the issuer packet is also searched in the unhashed area. */
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_ISSUER_FPR, &len);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_ISSUER_FPR, &len);
if (p && len == 21 && p[0] == 4)
{
sig->keyid[0] = buf32_to_u32 (p + 1 + 12);
@@ -2093,24 +2127,24 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen,
sig->keyid[1] = buf32_to_u32 (p + 4);
}
else if (!(sig->pubkey_algo >= 100 && sig->pubkey_algo <= 110)
- && opt.verbose)
+ && opt.verbose && !glo_ctrl.silence_parse_warnings)
log_info ("signature packet without keyid\n");
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIG_EXPIRE, NULL);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_SIG_EXPIRE, NULL);
if (p && buf32_to_u32 (p))
sig->expiredate = sig->timestamp + buf32_to_u32 (p);
if (sig->expiredate && sig->expiredate <= make_timestamp ())
sig->flags.expired = 1;
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_POLICY, NULL);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_POLICY, NULL);
if (p)
sig->flags.policy_url = 1;
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_KS, NULL);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_PREF_KS, NULL);
if (p)
sig->flags.pref_ks = 1;
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIGNERS_UID, &len);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_SIGNERS_UID, &len);
if (p && len)
{
char *mbox;
@@ -2129,15 +2163,15 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen,
}
}
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_NOTATION, NULL);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_NOTATION, NULL);
if (p)
sig->flags.notation = 1;
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_REVOCABLE, NULL);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_REVOCABLE, NULL);
if (p && *p == 0)
sig->flags.revocable = 0;
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_TRUST, &len);
+ p = parse_sig_subpkt (sig, 1, SIGSUBPKT_TRUST, &len);
if (p && len == 2)
{
sig->trust_depth = p[0];
@@ -2146,7 +2180,7 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen,
/* Only look for a regexp if there is also a trust
subpacket. */
sig->trust_regexp =
- parse_sig_subpkt (sig->hashed, SIGSUBPKT_REGEXP, &len);
+ parse_sig_subpkt (sig, 1, SIGSUBPKT_REGEXP, &len);
/* If the regular expression is of 0 length, there is no
regular expression. */
@@ -2179,8 +2213,8 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen,
sig->digest_algo, sig->digest_start[0], sig->digest_start[1]);
if (is_v4or5)
{
- parse_sig_subpkt (sig->hashed, SIGSUBPKT_LIST_HASHED, NULL);
- parse_sig_subpkt (sig->unhashed, SIGSUBPKT_LIST_UNHASHED, NULL);
+ parse_sig_subpkt (sig, 1, SIGSUBPKT_LIST_HASHED, NULL);
+ parse_sig_subpkt (sig, 0, SIGSUBPKT_LIST_UNHASHED, NULL);
}
}
@@ -2344,7 +2378,7 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
{
/* Not anymore supported since 2.1. Use an older gpg version
* (i.e. gpg 1.4) to parse v3 packets. */
- if (opt.verbose > 1)
+ if (opt.verbose > 1 && !glo_ctrl.silence_parse_warnings)
log_info ("packet(%d) with obsolete version %d\n", pkttype, version);
if (list_mode)
es_fprintf (listfp, ":key packet: [obsolete version %d]\n", version);
@@ -2866,7 +2900,7 @@ parse_attribute_subpkts (PKT_user_id * uid)
return count;
too_short:
- if (opt.verbose)
+ if (opt.verbose && !glo_ctrl.silence_parse_warnings)
log_info ("buffer shorter than attribute subpacket\n");
uid->attribs = attribs;
uid->numattribs = count;
diff --git a/g10/photoid.c b/g10/photoid.c
index 9bb4ab58f..f7ada2729 100644
--- a/g10/photoid.c
+++ b/g10/photoid.c
@@ -21,6 +21,7 @@
#include <errno.h>
#include <stdio.h>
#include <string.h>
+#include <unistd.h>
#ifdef _WIN32
# ifdef HAVE_WINSOCK2_H
# include <winsock2.h>
@@ -233,9 +234,10 @@ int parse_image_header(const struct user_attribute *attr,byte *type,u32 *len)
make sure it is not too big (see parse-packet.c:parse_attribute).
Extensions should be 3 characters long for the best cross-platform
compatibility. */
-char *image_type_to_string(byte type,int style)
+const char *
+image_type_to_string(byte type,int style)
{
- char *string;
+ const char *string;
switch(type)
{
@@ -279,8 +281,6 @@ get_default_photo_command(void)
#elif defined(__APPLE__)
/* OS X. This really needs more than just __APPLE__. */
return "open %I";
-#elif defined(__riscos__)
- return "Filer_Run %I";
#else
if (!path_access ("xloadimage", X_OK))
return "xloadimage -fork -quiet -title 'KeyID 0x%k' stdin";
@@ -294,6 +294,322 @@ get_default_photo_command(void)
}
#endif
+#ifndef DISABLE_PHOTO_VIEWER
+struct spawn_info
+{
+ unsigned int keep_temp_file;
+ char *command;
+ char *tempdir;
+ char *tempfile;
+};
+
+#ifdef NO_EXEC
+static void
+show_photo (const char *command, const char *name, const void *image, u32 len)
+{
+ log_error(_("no remote program execution supported\n"));
+ return GPG_ERR_GENERAL;
+}
+#else /* ! NO_EXEC */
+#include "../common/membuf.h"
+#include "../common/exechelp.h"
+
+/* Makes a temp directory and filenames */
+static int
+setup_input_file (struct spawn_info *info, const char *name)
+{
+ char *tmp = opt.temp_dir;
+ int len;
+#define TEMPLATE "gpg-XXXXXX"
+
+ /* Initialize by the length of last part in the path + 1 */
+ len = strlen (DIRSEP_S) + strlen (TEMPLATE) + 1;
+
+ /* Make up the temp dir and file in case we need them */
+ if (tmp)
+ {
+ len += strlen (tmp);
+ info->tempdir = xmalloc (len);
+ }
+ else
+ {
+#if defined (_WIN32)
+ int ret;
+
+ tmp = xmalloc (MAX_PATH+1);
+ if (!tmp)
+ return -1;
+
+ ret = GetTempPath (MAX_PATH-len, tmp);
+ if (ret == 0 || ret >= MAX_PATH-len)
+ strcpy (tmp, "c:\\windows\\temp");
+ else
+ {
+ /* GetTempPath may return with \ on the end */
+ while (ret > 0 && tmp[ret-1] == '\\')
+ {
+ tmp[ret-1]='\0';
+ ret--;
+ }
+ }
+
+ len += ret;
+ info->tempdir = tmp;
+#else /* More unixish systems */
+ if (!(tmp = getenv ("TMPDIR"))
+ && !(tmp = getenv ("TMP")))
+ tmp = "/tmp";
+
+ len += strlen (tmp);
+ info->tempdir = xmalloc (len);
+#endif
+ }
+
+ if (info->tempdir == NULL)
+ return -1;
+
+ sprintf (info->tempdir, "%s" DIRSEP_S TEMPLATE, tmp);
+
+ if (gnupg_mkdtemp (info->tempdir) == NULL)
+ {
+ log_error (_("can't create directory '%s': %s\n"),
+ info->tempdir, strerror (errno));
+ return -1;
+ }
+
+ info->tempfile = xmalloc (strlen (info->tempdir) + strlen (DIRSEP_S)
+ + strlen (name) + 1);
+ if (info->tempfile == NULL)
+ {
+ xfree (info->tempdir);
+ info->tempdir = NULL;
+ return -1;
+ }
+ sprintf (info->tempfile, "%s" DIRSEP_S "%s", info->tempdir, name);
+ return 0;
+}
+
+/* Expands %i or %I in the args to the full temp file within the temp
+ directory. */
+static int
+expand_args (struct spawn_info *info, const char *args_in, const char *name)
+{
+ const char *ch = args_in;
+ membuf_t command;
+
+ info->keep_temp_file = 0;
+
+ if (DBG_EXTPROG)
+ log_debug ("expanding string \"%s\"\n", args_in);
+
+ init_membuf (&command, 100);
+
+ while (*ch != '\0')
+ {
+ if (*ch == '%')
+ {
+ const char *append = NULL;
+
+ ch++;
+
+ switch (*ch)
+ {
+ case 'I':
+ info->keep_temp_file = 1;
+ /* fall through */
+
+ case 'i': /* in */
+ if (info->tempfile == NULL)
+ {
+ if (setup_input_file (info, name) < 0)
+ goto fail;
+ }
+ append = info->tempfile;
+ break;
+
+ case '%':
+ append = "%";
+ break;
+ }
+
+ if (append)
+ put_membuf_str (&command, append);
+ }
+ else
+ put_membuf (&command, ch, 1);
+
+ ch++;
+ }
+
+ put_membuf (&command, "", 1); /* Terminate string. */
+
+ info->command = get_membuf (&command, NULL);
+ if (!info->command)
+ return -1;
+
+ if(DBG_EXTPROG)
+ log_debug("args expanded to \"%s\", use %s, keep %u\n", info->command,
+ info->tempfile, info->keep_temp_file);
+
+ return 0;
+
+ fail:
+ xfree (get_membuf (&command, NULL));
+ return -1;
+}
+
+#ifndef EXEC_TEMPFILE_ONLY
+static void
+fill_command_argv (const char *argv[4], const char *command)
+{
+ argv[0] = getenv ("SHELL");
+ if (argv[0] == NULL)
+ argv[0] = "/bin/sh";
+
+ argv[1] = "-c";
+ argv[2] = command;
+ argv[3] = NULL;
+}
+#endif
+
+static void
+run_with_pipe (struct spawn_info *info, const void *image, u32 len)
+{
+#ifdef EXEC_TEMPFILE_ONLY
+ (void)info;
+ (void)image;
+ (void)len;
+ log_error (_("this platform requires temporary files when calling"
+ " external programs\n"));
+ return;
+#else /* !EXEC_TEMPFILE_ONLY */
+ int to[2];
+ pid_t pid;
+ gpg_error_t err;
+ const char *argv[4];
+
+ err = gnupg_create_pipe (to);
+ if (err)
+ return;
+
+ fill_command_argv (argv, info->command);
+ err = gnupg_spawn_process_fd (argv[0], argv+1, to[0], -1, -1, &pid);
+
+ close (to[0]);
+
+ if (err)
+ {
+ log_error (_("unable to execute shell '%s': %s\n"),
+ argv[0], gpg_strerror (err));
+ close (to[1]);
+ }
+ else
+ {
+ write (to[1], image, len);
+ close (to[1]);
+
+ err = gnupg_wait_process (argv[0], pid, 1, NULL);
+ if (err)
+ log_error (_("unnatural exit of external program\n"));
+ }
+#endif /* !EXEC_TEMPFILE_ONLY */
+}
+
+static int
+create_temp_file (struct spawn_info *info, const void *ptr, u32 len)
+{
+ if (DBG_EXTPROG)
+ log_debug ("using temp file '%s'\n", info->tempfile);
+
+ /* It's not fork/exec/pipe, so create a temp file */
+ if ( is_secured_filename (info->tempfile) )
+ {
+ log_error (_("can't create '%s': %s\n"),
+ info->tempfile, strerror (EPERM));
+ gpg_err_set_errno (EPERM);
+ return -1;
+ }
+ else
+ {
+ FILE *fp = fopen (info->tempfile, "wb");
+
+ if (fp)
+ {
+ fwrite (ptr, len, 1, fp);
+ fclose (fp);
+ return 0;
+ }
+ else
+ {
+ int save = errno;
+ log_error (_("can't create '%s': %s\n"),
+ info->tempfile, strerror(errno));
+ gpg_err_set_errno (save);
+ return -1;
+ }
+ }
+}
+
+static void
+show_photo (const char *command, const char *name, const void *image, u32 len)
+{
+ struct spawn_info *spawn;
+
+ spawn = xmalloc_clear (sizeof (struct spawn_info));
+ if (!spawn)
+ return;
+
+ /* Expand the args */
+ if (expand_args (spawn, command, name) < 0)
+ {
+ xfree (spawn);
+ return;
+ }
+
+ if (DBG_EXTPROG)
+ log_debug ("running command: %s\n", spawn->command);
+
+ if (spawn->tempfile == NULL)
+ run_with_pipe (spawn, image, len);
+ else if (create_temp_file (spawn, image, len) == 0)
+ {
+#if defined (_WIN32)
+ if (w32_system (spawn->command) < 0)
+ log_error (_("system error while calling external program: %s\n"),
+ strerror (errno));
+#else
+ pid_t pid;
+ gpg_error_t err;
+ const char *argv[4];
+
+ fill_command_argv (argv, spawn->command);
+ err = gnupg_spawn_process_fd (argv[0], argv+1, -1, -1, -1, &pid);
+ if (!err)
+ err = gnupg_wait_process (argv[0], pid, 1, NULL);
+ if (err)
+ log_error (_("unnatural exit of external program\n"));
+#endif
+
+ if (!spawn->keep_temp_file)
+ {
+ if (unlink (spawn->tempfile) < 0)
+ log_info (_("WARNING: unable to remove tempfile (%s) '%s': %s\n"),
+ "in", spawn->tempfile, strerror(errno));
+
+ if (rmdir (spawn->tempdir) < 0)
+ log_info (_("WARNING: unable to remove temp directory '%s': %s\n"),
+ spawn->tempdir, strerror(errno));
+ }
+ }
+
+ xfree(spawn->command);
+ xfree(spawn->tempdir);
+ xfree(spawn->tempfile);
+ xfree(spawn);
+}
+#endif
+#endif
+
void
show_photos (ctrl_t ctrl, const struct user_attribute *attrs, int count,
@@ -310,6 +626,20 @@ show_photos (ctrl_t ctrl, const struct user_attribute *attrs, int count,
u32 len;
u32 kid[2]={0,0};
+ if (opt.exec_disable && !opt.no_perm_warn)
+ {
+ log_info (_("external program calls are disabled due to unsafe "
+ "options file permissions\n"));
+ return;
+ }
+
+#if defined(HAVE_GETUID) && defined(HAVE_GETEUID)
+ /* There should be no way to get to this spot while still carrying
+ setuid privs. Just in case, bomb out if we are. */
+ if ( getuid () != geteuid ())
+ BUG ();
+#endif
+
memset (&args, 0, sizeof(args));
args.pk = pk;
args.validity_info = get_validity_info (ctrl, NULL, pk, uid);
@@ -322,28 +652,33 @@ show_photos (ctrl_t ctrl, const struct user_attribute *attrs, int count,
es_fflush (es_stdout);
- for(i=0;i<count;i++)
- if(attrs[i].type==ATTRIB_IMAGE &&
- parse_image_header(&attrs[i],&args.imagetype,&len))
- {
- char *command,*name;
- struct exec_info *spawn;
- int offset=attrs[i].len-len;
-
#ifdef FIXED_PHOTO_VIEWER
- opt.photo_viewer=FIXED_PHOTO_VIEWER;
+ opt.photo_viewer = FIXED_PHOTO_VIEWER;
#else
- if(!opt.photo_viewer)
- opt.photo_viewer=get_default_photo_command();
+ if (!opt.photo_viewer)
+ opt.photo_viewer = get_default_photo_command ();
#endif
+ for (i=0; i<count; i++)
+ if (attrs[i].type == ATTRIB_IMAGE
+ && parse_image_header (&attrs[i], &args.imagetype, &len))
+ {
+ char *command, *name;
+ int offset = attrs[i].len-len;
+
/* make command grow */
- command=pct_expando (ctrl, opt.photo_viewer,&args);
+ command = pct_expando (ctrl, opt.photo_viewer,&args);
if(!command)
goto fail;
- name=xmalloc(16+strlen(EXTSEP_S)+
- strlen(image_type_to_string(args.imagetype,0))+1);
+ name = xmalloc (1 + 16 + strlen(EXTSEP_S)
+ + strlen (image_type_to_string (args.imagetype, 0)));
+
+ if (!name)
+ {
+ xfree (command);
+ goto fail;
+ }
/* Make the filename. Notice we are not using the image
encoding type for more than cosmetics. Most external image
@@ -352,36 +687,17 @@ show_photos (ctrl_t ctrl, const struct user_attribute *attrs, int count,
which. The spec permits this, by the way. -dms */
#ifdef USE_ONLY_8DOT3
- sprintf(name,"%08lX" EXTSEP_S "%s",(ulong)kid[1],
- image_type_to_string(args.imagetype,0));
+ sprintf (name,"%08lX" EXTSEP_S "%s", (ulong)kid[1],
+ image_type_to_string (args.imagetype, 0));
#else
- sprintf(name,"%08lX%08lX" EXTSEP_S "%s",(ulong)kid[0],(ulong)kid[1],
- image_type_to_string(args.imagetype,0));
-#endif
-
- if(exec_write(&spawn,NULL,command,name,1,1)!=0)
- {
- xfree(name);
- goto fail;
- }
-
-#ifdef __riscos__
- riscos_set_filetype_by_mimetype(spawn->tempfile_in,
- image_type_to_string(args.imagetype,2));
+ sprintf (name, "%08lX%08lX" EXTSEP_S "%s",
+ (ulong)kid[0], (ulong)kid[1],
+ image_type_to_string (args.imagetype, 0));
#endif
- xfree(name);
-
- fwrite(&attrs[i].data[offset],attrs[i].len-offset,1,spawn->tochild);
-
- if(exec_read(spawn)!=0)
- {
- exec_finish(spawn);
- goto fail;
- }
-
- if(exec_finish(spawn)!=0)
- goto fail;
+ show_photo (command, name, &attrs[i].data[offset], len);
+ xfree (name);
+ xfree (command);
}
return;
diff --git a/g10/photoid.h b/g10/photoid.h
index fc7ec6fbc..bbf1f493e 100644
--- a/g10/photoid.h
+++ b/g10/photoid.h
@@ -27,7 +27,7 @@
PKT_user_id *generate_photo_id (ctrl_t ctrl,
PKT_public_key *pk,const char *filename);
int parse_image_header(const struct user_attribute *attr,byte *type,u32 *len);
-char *image_type_to_string(byte type,int style);
+const char *image_type_to_string(byte type,int style);
void show_photos (ctrl_t ctrl, const struct user_attribute *attrs, int count,
PKT_public_key *pk, PKT_user_id *uid);
diff --git a/g10/pkclist.c b/g10/pkclist.c
index 1fd23a3e4..996b3ba6e 100644
--- a/g10/pkclist.c
+++ b/g10/pkclist.c
@@ -63,8 +63,8 @@ do_show_revocation_reason( PKT_signature *sig )
int seq = 0;
const char *text;
- while( (p = enum_sig_subpkt (sig->hashed, SIGSUBPKT_REVOC_REASON,
- &n, &seq, NULL )) ) {
+ while ((p = enum_sig_subpkt (sig, 1, SIGSUBPKT_REVOC_REASON,
+ &n, &seq, NULL)) ) {
if( !n )
continue; /* invalid - just skip it */
@@ -759,55 +759,6 @@ default_recipient (ctrl_t ctrl)
}
-static int
-expand_id(const char *id,strlist_t *into,unsigned int flags)
-{
- struct groupitem *groups;
- int count=0;
-
- for(groups=opt.grouplist;groups;groups=groups->next)
- {
- /* need strcasecmp() here, as this should be localized */
- if(strcasecmp(groups->name,id)==0)
- {
- strlist_t each,sl;
-
- /* this maintains the current utf8-ness */
- for(each=groups->values;each;each=each->next)
- {
- sl=add_to_strlist(into,each->d);
- sl->flags=flags;
- count++;
- }
-
- break;
- }
- }
-
- return count;
-}
-
-/* For simplicity, and to avoid potential loops, we only expand once -
- * you can't make an alias that points to an alias. */
-static strlist_t
-expand_group (strlist_t input)
-{
- strlist_t output = NULL;
- strlist_t sl, rover;
-
- for (rover = input; rover; rover = rover->next)
- if (!(rover->flags & PK_LIST_FROM_FILE)
- && !expand_id(rover->d,&output,rover->flags))
- {
- /* Didn't find any groups, so use the existing string */
- sl=add_to_strlist(&output,rover->d);
- sl->flags=rover->flags;
- }
-
- return output;
-}
-
-
/* Helper for build_pk_list to find and check one key. This helper is
* also used directly in server mode by the RECIPIENTS command. On
* success the new key is added to PK_LIST_ADDR. NAME is the user id
diff --git a/g10/sign.c b/g10/sign.c
index 8c70b0a2e..250c0cfeb 100644
--- a/g10/sign.c
+++ b/g10/sign.c
@@ -86,7 +86,9 @@ mk_notation_policy_etc (ctrl_t ctrl, PKT_signature *sig,
args.pksk = pksk;
/* Notation data. */
- if (IS_SIG(sig) && opt.sig_notations)
+ if (IS_ATTST_SIGS(sig))
+ ;
+ else if (IS_SIG(sig) && opt.sig_notations)
nd = opt.sig_notations;
else if (IS_CERT(sig) && opt.cert_notations)
nd = opt.cert_notations;
@@ -113,7 +115,9 @@ mk_notation_policy_etc (ctrl_t ctrl, PKT_signature *sig,
}
/* Set policy URL. */
- if (IS_SIG(sig) && opt.sig_policy_url)
+ if (IS_ATTST_SIGS(sig))
+ ;
+ else if (IS_SIG(sig) && opt.sig_policy_url)
pu = opt.sig_policy_url;
else if (IS_CERT(sig) && opt.cert_policy_url)
pu = opt.cert_policy_url;
diff --git a/g10/trustdb.c b/g10/trustdb.c
index 352aecede..64e6ec349 100644
--- a/g10/trustdb.c
+++ b/g10/trustdb.c
@@ -303,7 +303,9 @@ verify_own_keys (ctrl_t ctrl)
release_public_key_parts (&pk);
}
- log_info (_("key %s marked as ultimately trusted\n"),keystr(k->kid));
+ if (!opt.quiet)
+ log_info (_("key %s marked as ultimately trusted\n"),
+ keystr(k->kid));
}
}