diff options
Diffstat (limited to 'g10')
-rw-r--r-- | g10/Makefile.am | 1 | ||||
-rw-r--r-- | g10/build-packet.c | 2 | ||||
-rw-r--r-- | g10/call-agent.c | 27 | ||||
-rw-r--r-- | g10/call-agent.h | 2 | ||||
-rw-r--r-- | g10/card-util.c | 55 | ||||
-rw-r--r-- | g10/dek.h | 6 | ||||
-rw-r--r-- | g10/exec.c | 538 | ||||
-rw-r--r-- | g10/exec.h | 27 | ||||
-rw-r--r-- | g10/expand-group.c | 73 | ||||
-rw-r--r-- | g10/export.c | 190 | ||||
-rw-r--r-- | g10/getkey.c | 77 | ||||
-rw-r--r-- | g10/gpg.c | 33 | ||||
-rw-r--r-- | g10/import.c | 2 | ||||
-rw-r--r-- | g10/key-clean.c | 2 | ||||
-rw-r--r-- | g10/keydb.c | 17 | ||||
-rw-r--r-- | g10/keydb.h | 13 | ||||
-rw-r--r-- | g10/keyedit.c | 14 | ||||
-rw-r--r-- | g10/keygen.c | 349 | ||||
-rw-r--r-- | g10/keylist.c | 15 | ||||
-rw-r--r-- | g10/keyserver.c | 10 | ||||
-rw-r--r-- | g10/mainproc.c | 9 | ||||
-rw-r--r-- | g10/options.h | 6 | ||||
-rw-r--r-- | g10/packet.h | 99 | ||||
-rw-r--r-- | g10/parse-packet.c | 122 | ||||
-rw-r--r-- | g10/photoid.c | 406 | ||||
-rw-r--r-- | g10/photoid.h | 2 | ||||
-rw-r--r-- | g10/pkclist.c | 53 | ||||
-rw-r--r-- | g10/sign.c | 8 | ||||
-rw-r--r-- | g10/trustdb.c | 4 |
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. */ @@ -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) @@ -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, ×tamp, 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)); } } |