mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-18 14:17:03 +01:00
This commit was manufactured by cvs2svn to create branch
'GNUPG-1-9-BRANCH'.
This commit is contained in:
parent
a3d4ac6f3e
commit
7250331472
473
agent/query.c
Normal file
473
agent/query.c
Normal file
@ -0,0 +1,473 @@
|
||||
/* query.c - fork of the pinentry to query stuff from the user
|
||||
* Copyright (C) 2001, 2002 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#ifdef USE_GNU_PTH
|
||||
# include <pth.h>
|
||||
#endif
|
||||
|
||||
#include "agent.h"
|
||||
#include "i18n.h"
|
||||
#include <assuan.h>
|
||||
|
||||
#ifdef _POSIX_OPEN_MAX
|
||||
#define MAX_OPEN_FDS _POSIX_OPEN_MAX
|
||||
#else
|
||||
#define MAX_OPEN_FDS 20
|
||||
#endif
|
||||
|
||||
static ASSUAN_CONTEXT entry_ctx = NULL;
|
||||
#ifdef USE_GNU_PTH
|
||||
static pth_mutex_t entry_lock = PTH_MUTEX_INIT;
|
||||
#endif
|
||||
|
||||
/* data to be passed to our callbacks */
|
||||
struct entry_parm_s {
|
||||
int lines;
|
||||
size_t size;
|
||||
char *buffer;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/* Unlock the pinentry so that another thread can start one and
|
||||
disconnect that pinentry - we do this after the unlock so that a
|
||||
stalled pinentry does not block other threads. Fixme: We should
|
||||
have a timeout in Assuan for the disconnetc operation. */
|
||||
static int
|
||||
unlock_pinentry (int rc)
|
||||
{
|
||||
ASSUAN_CONTEXT ctx = entry_ctx;
|
||||
|
||||
#ifdef USE_GNU_PTH
|
||||
if (!pth_mutex_release (&entry_lock))
|
||||
{
|
||||
log_error ("failed to release the entry lock\n");
|
||||
if (!rc)
|
||||
rc = gpg_error (GPG_ERR_INTERNAL);
|
||||
}
|
||||
#endif
|
||||
entry_ctx = NULL;
|
||||
assuan_disconnect (ctx);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Fork off the pin entry if this has not already been done. Note,
|
||||
that this function must always be used to aquire the lock for the
|
||||
pinentry - we will serialize _all_ pinentry calls.
|
||||
*/
|
||||
static int
|
||||
start_pinentry (CTRL ctrl)
|
||||
{
|
||||
int rc;
|
||||
const char *pgmname;
|
||||
ASSUAN_CONTEXT ctx;
|
||||
const char *argv[5];
|
||||
int no_close_list[3];
|
||||
int i;
|
||||
|
||||
#ifdef USE_GNU_PTH
|
||||
if (!pth_mutex_acquire (&entry_lock, 0, NULL))
|
||||
{
|
||||
log_error ("failed to acquire the entry lock\n");
|
||||
return gpg_error (GPG_ERR_INTERNAL);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (entry_ctx)
|
||||
return 0;
|
||||
|
||||
if (opt.verbose)
|
||||
log_info ("starting a new PIN Entry\n");
|
||||
|
||||
if (fflush (NULL))
|
||||
{
|
||||
gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
|
||||
log_error ("error flushing pending output: %s\n", strerror (errno));
|
||||
return unlock_pinentry (tmperr);
|
||||
}
|
||||
|
||||
if (!opt.pinentry_program || !*opt.pinentry_program)
|
||||
opt.pinentry_program = GNUPG_DEFAULT_PINENTRY;
|
||||
if ( !(pgmname = strrchr (opt.pinentry_program, '/')))
|
||||
pgmname = opt.pinentry_program;
|
||||
else
|
||||
pgmname++;
|
||||
|
||||
argv[0] = pgmname;
|
||||
if (ctrl->display && !opt.keep_display)
|
||||
{
|
||||
argv[1] = "--display";
|
||||
argv[2] = ctrl->display;
|
||||
argv[3] = NULL;
|
||||
}
|
||||
else
|
||||
argv[1] = NULL;
|
||||
|
||||
i=0;
|
||||
if (!opt.running_detached)
|
||||
{
|
||||
if (log_get_fd () != -1)
|
||||
no_close_list[i++] = log_get_fd ();
|
||||
no_close_list[i++] = fileno (stderr);
|
||||
}
|
||||
no_close_list[i] = -1;
|
||||
|
||||
/* connect to the pinentry and perform initial handshaking */
|
||||
rc = assuan_pipe_connect (&ctx, opt.pinentry_program, (char**)argv,
|
||||
no_close_list);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("can't connect to the PIN entry module: %s\n",
|
||||
assuan_strerror (rc));
|
||||
return unlock_pinentry (gpg_error (GPG_ERR_NO_PIN_ENTRY));
|
||||
}
|
||||
entry_ctx = ctx;
|
||||
|
||||
if (DBG_ASSUAN)
|
||||
log_debug ("connection to PIN entry established\n");
|
||||
|
||||
rc = assuan_transact (entry_ctx,
|
||||
opt.no_grab? "OPTION no-grab":"OPTION grab",
|
||||
NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
return unlock_pinentry (map_assuan_err (rc));
|
||||
if (ctrl->ttyname)
|
||||
{
|
||||
char *optstr;
|
||||
if (asprintf (&optstr, "OPTION ttyname=%s", ctrl->ttyname) < 0 )
|
||||
return unlock_pinentry (out_of_core ());
|
||||
rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
|
||||
NULL);
|
||||
free (optstr);
|
||||
if (rc)
|
||||
return unlock_pinentry (map_assuan_err (rc));
|
||||
}
|
||||
if (ctrl->ttytype)
|
||||
{
|
||||
char *optstr;
|
||||
if (asprintf (&optstr, "OPTION ttytype=%s", ctrl->ttytype) < 0 )
|
||||
return unlock_pinentry (out_of_core ());
|
||||
rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
|
||||
NULL);
|
||||
if (rc)
|
||||
return unlock_pinentry (map_assuan_err (rc));
|
||||
}
|
||||
if (ctrl->lc_ctype)
|
||||
{
|
||||
char *optstr;
|
||||
if (asprintf (&optstr, "OPTION lc-ctype=%s", ctrl->lc_ctype) < 0 )
|
||||
return unlock_pinentry (out_of_core ());
|
||||
rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
|
||||
NULL);
|
||||
if (rc)
|
||||
return unlock_pinentry (map_assuan_err (rc));
|
||||
}
|
||||
if (ctrl->lc_messages)
|
||||
{
|
||||
char *optstr;
|
||||
if (asprintf (&optstr, "OPTION lc-messages=%s", ctrl->lc_messages) < 0 )
|
||||
return unlock_pinentry (out_of_core ());
|
||||
rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
|
||||
NULL);
|
||||
if (rc)
|
||||
return unlock_pinentry (map_assuan_err (rc));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static AssuanError
|
||||
getpin_cb (void *opaque, const void *buffer, size_t length)
|
||||
{
|
||||
struct entry_parm_s *parm = opaque;
|
||||
|
||||
if (!buffer)
|
||||
return 0;
|
||||
|
||||
/* we expect the pin to fit on one line */
|
||||
if (parm->lines || length >= parm->size)
|
||||
return ASSUAN_Too_Much_Data;
|
||||
|
||||
/* fixme: we should make sure that the assuan buffer is allocated in
|
||||
secure memory or read the response byte by byte */
|
||||
memcpy (parm->buffer, buffer, length);
|
||||
parm->buffer[length] = 0;
|
||||
parm->lines++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
all_digitsp( const char *s)
|
||||
{
|
||||
for (; *s && *s >= '0' && *s <= '9'; s++)
|
||||
;
|
||||
return !*s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Call the Entry and ask for the PIN. We do check for a valid PIN
|
||||
number here and repeat it as long as we have invalid formed
|
||||
numbers. */
|
||||
int
|
||||
agent_askpin (CTRL ctrl,
|
||||
const char *desc_text, struct pin_entry_info_s *pininfo)
|
||||
{
|
||||
int rc;
|
||||
char line[ASSUAN_LINELENGTH];
|
||||
struct entry_parm_s parm;
|
||||
const char *errtext = NULL;
|
||||
int is_pin = 0;
|
||||
|
||||
if (opt.batch)
|
||||
return 0; /* fixme: we should return BAD PIN */
|
||||
|
||||
if (!pininfo || pininfo->max_length < 1)
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
if (!desc_text && pininfo->min_digits)
|
||||
desc_text = _("Please enter your PIN, so that the secret key "
|
||||
"can be unlocked for this session");
|
||||
else if (!desc_text)
|
||||
desc_text = _("Please enter your passphrase, so that the secret key "
|
||||
"can be unlocked for this session");
|
||||
|
||||
is_pin = desc_text && strstr (desc_text, "PIN");
|
||||
|
||||
rc = start_pinentry (ctrl);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
snprintf (line, DIM(line)-1, "SETDESC %s", desc_text);
|
||||
line[DIM(line)-1] = 0;
|
||||
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
return unlock_pinentry (map_assuan_err (rc));
|
||||
|
||||
rc = assuan_transact (entry_ctx,
|
||||
is_pin? "SETPROMPT PIN:"
|
||||
: "SETPROMPT Passphrase:",
|
||||
NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
return unlock_pinentry (map_assuan_err (rc));
|
||||
|
||||
for (;pininfo->failed_tries < pininfo->max_tries; pininfo->failed_tries++)
|
||||
{
|
||||
memset (&parm, 0, sizeof parm);
|
||||
parm.size = pininfo->max_length;
|
||||
parm.buffer = pininfo->pin;
|
||||
|
||||
if (errtext)
|
||||
{
|
||||
/* fixme: should we show the try count? It must be translated */
|
||||
snprintf (line, DIM(line)-1, "SETERROR %s (try %d of %d)",
|
||||
errtext, pininfo->failed_tries+1, pininfo->max_tries);
|
||||
line[DIM(line)-1] = 0;
|
||||
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
return unlock_pinentry (map_assuan_err (rc));
|
||||
errtext = NULL;
|
||||
}
|
||||
|
||||
rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm,
|
||||
NULL, NULL, NULL, NULL);
|
||||
if (rc == ASSUAN_Too_Much_Data)
|
||||
errtext = is_pin? _("PIN too long")
|
||||
: _("Passphrase too long");
|
||||
else if (rc)
|
||||
return unlock_pinentry (map_assuan_err (rc));
|
||||
|
||||
if (!errtext && pininfo->min_digits)
|
||||
{
|
||||
/* do some basic checks on the entered PIN. */
|
||||
if (!all_digitsp (pininfo->pin))
|
||||
errtext = _("Invalid characters in PIN");
|
||||
else if (pininfo->max_digits
|
||||
&& strlen (pininfo->pin) > pininfo->max_digits)
|
||||
errtext = _("PIN too long");
|
||||
else if (strlen (pininfo->pin) < pininfo->min_digits)
|
||||
errtext = _("PIN too short");
|
||||
}
|
||||
|
||||
if (!errtext && pininfo->check_cb)
|
||||
{
|
||||
/* More checks by utilizing the optional callback. */
|
||||
pininfo->cb_errtext = NULL;
|
||||
rc = pininfo->check_cb (pininfo);
|
||||
if (rc == -1 && pininfo->cb_errtext)
|
||||
errtext = pininfo->cb_errtext;
|
||||
else if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
|
||||
|| gpg_err_code (rc) == GPG_ERR_BAD_PIN)
|
||||
errtext = (is_pin? _("Bad PIN")
|
||||
: _("Bad Passphrase"));
|
||||
else if (rc)
|
||||
return unlock_pinentry (map_assuan_err (rc));
|
||||
}
|
||||
|
||||
if (!errtext)
|
||||
return unlock_pinentry (0); /* okay, got a PIN or passphrase */
|
||||
}
|
||||
|
||||
return unlock_pinentry (gpg_error (pininfo->min_digits? GPG_ERR_BAD_PIN
|
||||
: GPG_ERR_BAD_PASSPHRASE));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Ask for the passphrase using the supplied arguments. The
|
||||
passphrase is returned in RETPASS as an hex encoded string to be
|
||||
freed by the caller */
|
||||
int
|
||||
agent_get_passphrase (CTRL ctrl,
|
||||
char **retpass, const char *desc, const char *prompt,
|
||||
const char *errtext)
|
||||
{
|
||||
|
||||
int rc;
|
||||
char line[ASSUAN_LINELENGTH];
|
||||
struct entry_parm_s parm;
|
||||
unsigned char *p, *hexstring;
|
||||
int i;
|
||||
|
||||
*retpass = NULL;
|
||||
if (opt.batch)
|
||||
return gpg_error (GPG_ERR_BAD_PASSPHRASE);
|
||||
|
||||
rc = start_pinentry (ctrl);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (!prompt)
|
||||
prompt = desc && strstr (desc, "PIN")? "PIN": _("Passphrase");
|
||||
|
||||
|
||||
if (desc)
|
||||
snprintf (line, DIM(line)-1, "SETDESC %s", desc);
|
||||
else
|
||||
snprintf (line, DIM(line)-1, "RESET");
|
||||
line[DIM(line)-1] = 0;
|
||||
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
return unlock_pinentry (map_assuan_err (rc));
|
||||
|
||||
snprintf (line, DIM(line)-1, "SETPROMPT %s", prompt);
|
||||
line[DIM(line)-1] = 0;
|
||||
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
return unlock_pinentry (map_assuan_err (rc));
|
||||
|
||||
if (errtext)
|
||||
{
|
||||
snprintf (line, DIM(line)-1, "SETERROR %s", errtext);
|
||||
line[DIM(line)-1] = 0;
|
||||
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
return unlock_pinentry (map_assuan_err (rc));
|
||||
}
|
||||
|
||||
memset (&parm, 0, sizeof parm);
|
||||
parm.size = ASSUAN_LINELENGTH/2 - 5;
|
||||
parm.buffer = gcry_malloc_secure (parm.size+10);
|
||||
if (!parm.buffer)
|
||||
return unlock_pinentry (out_of_core ());
|
||||
|
||||
assuan_begin_confidential (entry_ctx);
|
||||
rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
{
|
||||
xfree (parm.buffer);
|
||||
return unlock_pinentry (map_assuan_err (rc));
|
||||
}
|
||||
|
||||
hexstring = gcry_malloc_secure (strlen (parm.buffer)*2+1);
|
||||
if (!hexstring)
|
||||
{
|
||||
gpg_error_t tmperr = out_of_core ();
|
||||
xfree (parm.buffer);
|
||||
return unlock_pinentry (tmperr);
|
||||
}
|
||||
|
||||
for (i=0, p=parm.buffer; *p; p++, i += 2)
|
||||
sprintf (hexstring+i, "%02X", *p);
|
||||
|
||||
xfree (parm.buffer);
|
||||
*retpass = hexstring;
|
||||
return unlock_pinentry (0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Pop up the PIN-entry, display the text and the prompt and ask the
|
||||
user to confirm this. We return 0 for success, ie. the used
|
||||
confirmed it, GPG_ERR_NOT_CONFIRMED for what the text says or an
|
||||
other error. */
|
||||
int
|
||||
agent_get_confirmation (CTRL ctrl,
|
||||
const char *desc, const char *ok, const char *cancel)
|
||||
{
|
||||
int rc;
|
||||
char line[ASSUAN_LINELENGTH];
|
||||
|
||||
rc = start_pinentry (ctrl);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (desc)
|
||||
snprintf (line, DIM(line)-1, "SETDESC %s", desc);
|
||||
else
|
||||
snprintf (line, DIM(line)-1, "RESET");
|
||||
line[DIM(line)-1] = 0;
|
||||
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
return unlock_pinentry (map_assuan_err (rc));
|
||||
|
||||
if (ok)
|
||||
{
|
||||
snprintf (line, DIM(line)-1, "SETOK %s", ok);
|
||||
line[DIM(line)-1] = 0;
|
||||
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
return unlock_pinentry (map_assuan_err (rc));
|
||||
}
|
||||
if (cancel)
|
||||
{
|
||||
snprintf (line, DIM(line)-1, "SETCANCEL %s", cancel);
|
||||
line[DIM(line)-1] = 0;
|
||||
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
return unlock_pinentry (map_assuan_err (rc));
|
||||
}
|
||||
|
||||
rc = assuan_transact (entry_ctx, "CONFIRM", NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
return unlock_pinentry (map_assuan_err (rc));
|
||||
}
|
||||
|
||||
|
||||
|
98
agent/sexp-parse.h
Normal file
98
agent/sexp-parse.h
Normal file
@ -0,0 +1,98 @@
|
||||
/* sexp-parse.h - S-Exp helper functions
|
||||
* Copyright (C) 2002 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef SEXP_PARSE_H
|
||||
#define SEXP_PARSE_H
|
||||
|
||||
#include "../common/util.h"
|
||||
|
||||
/* Return the length of the next S-Exp part and update the pointer to
|
||||
the first data byte. 0 is return on error */
|
||||
static inline size_t
|
||||
snext (unsigned char const **buf)
|
||||
{
|
||||
const unsigned char *s;
|
||||
int n;
|
||||
|
||||
s = *buf;
|
||||
for (n=0; *s && *s != ':' && digitp (s); s++)
|
||||
n = n*10 + atoi_1 (s);
|
||||
if (!n || *s != ':')
|
||||
return 0; /* we don't allow empty lengths */
|
||||
*buf = s+1;
|
||||
return n;
|
||||
}
|
||||
|
||||
/* Skip over the S-Expression BUF points to and update BUF to point to
|
||||
the chacter right behind. DEPTH gives the initial number of open
|
||||
lists and may be passed as a positive number to skip over the
|
||||
remainder of an S-Expression if the current position is somewhere
|
||||
in an S-Expression. The function may return an error code if it
|
||||
encounters an impossible conditions */
|
||||
static inline int
|
||||
sskip (unsigned char const **buf, int *depth)
|
||||
{
|
||||
const unsigned char *s = *buf;
|
||||
size_t n;
|
||||
int d = *depth;
|
||||
|
||||
while (d > 0)
|
||||
{
|
||||
if (*s == '(')
|
||||
{
|
||||
d++;
|
||||
s++;
|
||||
}
|
||||
else if (*s == ')')
|
||||
{
|
||||
d--;
|
||||
s++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!d)
|
||||
return gpg_error (GPG_ERR_INV_SEXP);
|
||||
n = snext (&s);
|
||||
if (!n)
|
||||
return gpg_error (GPG_ERR_INV_SEXP);
|
||||
s += n;
|
||||
}
|
||||
}
|
||||
*buf = s;
|
||||
*depth = d;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Check whether the the string at the address BUF points to matches
|
||||
the token. Return true on match and update BUF to point behind the
|
||||
token. */
|
||||
static inline int
|
||||
smatch (unsigned char const **buf, size_t buflen, const char *token)
|
||||
{
|
||||
size_t toklen = strlen (token);
|
||||
|
||||
if (buflen != toklen || memcmp (*buf, token, toklen))
|
||||
return 0;
|
||||
*buf += toklen;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /*SEXP_PARSE_H*/
|
306
agent/trustlist.c
Normal file
306
agent/trustlist.c
Normal file
@ -0,0 +1,306 @@
|
||||
/* trustlist.c - Maintain the list of trusted keys
|
||||
* Copyright (C) 2002 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "agent.h"
|
||||
#include <assuan.h> /* fixme: need a way to avoid assuan calls here */
|
||||
|
||||
static const char headerblurb[] =
|
||||
"# This is the list of trusted keys. Comments like this one and empty\n"
|
||||
"# lines are allowed but keep in mind that the entire file is integrity\n"
|
||||
"# protected by the use of a MAC, so changing the file does not make\n"
|
||||
"# much sense without the knowledge of the MAC key. Lines do have a\n"
|
||||
"# length limit but this is not serious limitation as the format of the\n"
|
||||
"# entries is fixed and checked by gpg-agent: A non-comment line starts\n"
|
||||
"# with optional white spaces, followed by exactly 40 hex character,\n"
|
||||
"# optioanlly followed by a flag character which my either be 'P', 'S'\n"
|
||||
"# or '*'. Additional data delimited with by a white space is ignored.\n"
|
||||
"\n";
|
||||
|
||||
|
||||
static FILE *trustfp;
|
||||
|
||||
|
||||
static int
|
||||
open_list (int append)
|
||||
{
|
||||
char *fname;
|
||||
|
||||
fname = make_filename (opt.homedir, "trustlist.txt", NULL);
|
||||
trustfp = fopen (fname, append? "a+":"r");
|
||||
if (!trustfp && errno == ENOENT)
|
||||
{
|
||||
trustfp = fopen (fname, "wx");
|
||||
if (!trustfp)
|
||||
{
|
||||
gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
|
||||
log_error ("can't create `%s': %s\n", fname, strerror (errno));
|
||||
xfree (fname);
|
||||
return tmperr;
|
||||
}
|
||||
fputs (headerblurb, trustfp);
|
||||
fclose (trustfp);
|
||||
trustfp = fopen (fname, append? "a+":"r");
|
||||
}
|
||||
|
||||
if (!trustfp)
|
||||
{
|
||||
gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
|
||||
log_error ("can't open `%s': %s\n", fname, strerror (errno));
|
||||
xfree (fname);
|
||||
return tmperr;
|
||||
}
|
||||
|
||||
/*FIXME: check the MAC */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Read the trustlist and return entry by entry. KEY must point to a
|
||||
buffer of at least 41 characters. KEYFLAG does return either 'P',
|
||||
'S' or '*'.
|
||||
|
||||
Reading a valid entry return 0, EOF returns -1 any other error
|
||||
returns the appropriate error code. */
|
||||
static int
|
||||
read_list (char *key, int *keyflag)
|
||||
{
|
||||
int rc;
|
||||
int c, i;
|
||||
char *p, line[256];
|
||||
|
||||
if (!trustfp)
|
||||
{
|
||||
rc = open_list (0);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
if (!fgets (line, DIM(line)-1, trustfp) )
|
||||
{
|
||||
if (feof (trustfp))
|
||||
return -1;
|
||||
return gpg_error (gpg_err_code_from_errno (errno));
|
||||
}
|
||||
|
||||
if (!*line || line[strlen(line)-1] != '\n')
|
||||
{
|
||||
/* eat until end of line */
|
||||
while ( (c=getc (trustfp)) != EOF && c != '\n')
|
||||
;
|
||||
return gpg_error (*line? GPG_ERR_LINE_TOO_LONG
|
||||
: GPG_ERR_INCOMPLETE_LINE);
|
||||
}
|
||||
|
||||
/* Allow for emty lines and spaces */
|
||||
for (p=line; spacep (p); p++)
|
||||
;
|
||||
}
|
||||
while (!*p || *p == '\n' || *p == '#');
|
||||
|
||||
for (i=0; hexdigitp (p+i) && i < 40; i++)
|
||||
key[i] = p[i] >= 'a'? (p[i] & 0xdf): p[i];
|
||||
key[i] = 0;
|
||||
if (i!=40 || !(spacep (p+i) || p[i] == '\n'))
|
||||
{
|
||||
log_error ("invalid formatted fingerprint in trustlist\n");
|
||||
return gpg_error (GPG_ERR_BAD_DATA);
|
||||
}
|
||||
assert (p[i]);
|
||||
if (p[i] == '\n')
|
||||
*keyflag = '*';
|
||||
else
|
||||
{
|
||||
i++;
|
||||
if ( p[i] == 'P' || p[i] == 'p')
|
||||
*keyflag = 'P';
|
||||
else if ( p[i] == 'S' || p[i] == 's')
|
||||
*keyflag = 'S';
|
||||
else if ( p[i] == '*')
|
||||
*keyflag = '*';
|
||||
else
|
||||
{
|
||||
log_error ("invalid keyflag in trustlist\n");
|
||||
return gpg_error (GPG_ERR_BAD_DATA);
|
||||
}
|
||||
i++;
|
||||
if ( !(spacep (p+i) || p[i] == '\n'))
|
||||
{
|
||||
log_error ("invalid keyflag in trustlist\n");
|
||||
return gpg_error (GPG_ERR_BAD_DATA);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* check whether the given fpr is in our trustdb. We expect FPR to be
|
||||
an all uppercase hexstring of 40 characters. */
|
||||
int
|
||||
agent_istrusted (const char *fpr)
|
||||
{
|
||||
int rc;
|
||||
static char key[41];
|
||||
int keyflag;
|
||||
|
||||
if (trustfp)
|
||||
rewind (trustfp);
|
||||
while (!(rc=read_list (key, &keyflag)))
|
||||
{
|
||||
if (!strcmp (key, fpr))
|
||||
return 0;
|
||||
}
|
||||
if (rc != -1)
|
||||
{
|
||||
/* error in the trustdb - close it to give the user a chance for
|
||||
correction */
|
||||
fclose (trustfp);
|
||||
trustfp = NULL;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* write all trust entries to FP */
|
||||
int
|
||||
agent_listtrusted (void *assuan_context)
|
||||
{
|
||||
int rc;
|
||||
static char key[51];
|
||||
int keyflag;
|
||||
|
||||
if (trustfp)
|
||||
rewind (trustfp);
|
||||
while (!(rc=read_list (key, &keyflag)))
|
||||
{
|
||||
key[40] = ' ';
|
||||
key[41] = keyflag;
|
||||
key[42] = '\n';
|
||||
assuan_send_data (assuan_context, key, 43);
|
||||
assuan_send_data (assuan_context, NULL, 0); /* flush */
|
||||
}
|
||||
if (rc == -1)
|
||||
rc = 0;
|
||||
if (rc)
|
||||
{
|
||||
/* error in the trustdb - close it to give the user a chance for
|
||||
correction */
|
||||
fclose (trustfp);
|
||||
trustfp = NULL;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* Insert the given fpr into our trustdb. We expect FPR to be an all
|
||||
uppercase hexstring of 40 characters. FLAG is either 'P' or 'C'.
|
||||
This function does first check whether that key has alreay ben put
|
||||
into the trustdb and returns success in this case. Before a FPR
|
||||
actually gets inserted, the user is asked by means of the pin-entry
|
||||
whether this is actual wants he want to do.
|
||||
*/
|
||||
int
|
||||
agent_marktrusted (CTRL ctrl, const char *name, const char *fpr, int flag)
|
||||
{
|
||||
int rc;
|
||||
static char key[41];
|
||||
int keyflag;
|
||||
char *desc;
|
||||
|
||||
if (trustfp)
|
||||
rewind (trustfp);
|
||||
while (!(rc=read_list (key, &keyflag)))
|
||||
{
|
||||
if (!strcmp (key, fpr))
|
||||
return 0;
|
||||
}
|
||||
fclose (trustfp);
|
||||
trustfp = NULL;
|
||||
if (rc != -1)
|
||||
return rc; /* error in the trustdb */
|
||||
|
||||
/* insert a new one */
|
||||
if (asprintf (&desc,
|
||||
"Please verify that the certificate identified as:%%0A"
|
||||
" \"%s\"%%0A"
|
||||
"has the fingerprint:%%0A"
|
||||
" %s", name, fpr) < 0 )
|
||||
return out_of_core ();
|
||||
rc = agent_get_confirmation (ctrl, desc, "Correct", "No");
|
||||
free (desc);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (asprintf (&desc,
|
||||
"Do you ultimately trust%%0A"
|
||||
" \"%s\"%%0A"
|
||||
"to correctly certify user certificates?",
|
||||
name) < 0 )
|
||||
return out_of_core ();
|
||||
rc = agent_get_confirmation (ctrl, desc, "Yes", "No");
|
||||
free (desc);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* now check again to avoid duplicates. Also open in append mode now */
|
||||
rc = open_list (1);
|
||||
if (rc)
|
||||
return rc;
|
||||
rewind (trustfp);
|
||||
while (!(rc=read_list (key, &keyflag)))
|
||||
{
|
||||
if (!strcmp (key, fpr))
|
||||
return 0;
|
||||
}
|
||||
if (rc != -1)
|
||||
{
|
||||
fclose (trustfp);
|
||||
trustfp = NULL;
|
||||
return rc; /* error in the trustdb */
|
||||
}
|
||||
rc = 0;
|
||||
|
||||
/* append the key */
|
||||
fflush (trustfp);
|
||||
fputs ("\n# ", trustfp);
|
||||
print_sanitized_string (trustfp, name, 0);
|
||||
fprintf (trustfp, "\n%s %c\n", fpr, flag);
|
||||
if (ferror (trustfp))
|
||||
rc = gpg_error (gpg_err_code_from_errno (errno));
|
||||
|
||||
/* close because we are in append mode */
|
||||
if (fclose (trustfp))
|
||||
rc = gpg_error (gpg_err_code_from_errno (errno));
|
||||
trustfp = NULL;
|
||||
return rc;
|
||||
}
|
8238
g10/ChangeLog
Normal file
8238
g10/ChangeLog
Normal file
File diff suppressed because it is too large
Load Diff
123
g10/Makefile.am
Normal file
123
g10/Makefile.am
Normal file
@ -0,0 +1,123 @@
|
||||
# Copyright (C) 1998, 1999, 2000, 2001, 2002,
|
||||
# 2003 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 2 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, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
|
||||
## Process this file with automake to produce Makefile.in
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/intl
|
||||
EXTRA_DIST = options.skel
|
||||
# it seems that we can't use this with automake 1.5
|
||||
#OMIT_DEPENDENCIES = zlib.h zconf.h
|
||||
libexecdir = @libexecdir@/@PACKAGE@
|
||||
if ! HAVE_DOSISH_SYSTEM
|
||||
AM_CFLAGS = -DGNUPG_LIBEXECDIR="\"$(libexecdir)\""
|
||||
endif
|
||||
needed_libs = ../cipher/libcipher.a ../mpi/libmpi.a ../util/libutil.a
|
||||
|
||||
#noinst_PROGRAMS = gpgd
|
||||
bin_PROGRAMS = gpg gpgv
|
||||
|
||||
common_source = \
|
||||
global.h \
|
||||
build-packet.c \
|
||||
compress.c \
|
||||
filter.h \
|
||||
free-packet.c \
|
||||
getkey.c \
|
||||
keydb.c keydb.h \
|
||||
keyring.c keyring.h \
|
||||
seskey.c \
|
||||
kbnode.c \
|
||||
main.h \
|
||||
mainproc.c \
|
||||
armor.c \
|
||||
mdfilter.c \
|
||||
textfilter.c \
|
||||
progress.c \
|
||||
misc.c \
|
||||
options.h \
|
||||
openfile.c \
|
||||
keyid.c \
|
||||
packet.h \
|
||||
parse-packet.c \
|
||||
comment.c \
|
||||
status.c \
|
||||
status.h \
|
||||
plaintext.c \
|
||||
sig-check.c \
|
||||
keylist.c \
|
||||
signal.c
|
||||
|
||||
gpg_SOURCES = g10.c \
|
||||
$(common_source) \
|
||||
pkclist.c \
|
||||
skclist.c \
|
||||
pubkey-enc.c \
|
||||
passphrase.c \
|
||||
seckey-cert.c \
|
||||
encr-data.c \
|
||||
cipher.c \
|
||||
encode.c \
|
||||
sign.c \
|
||||
verify.c \
|
||||
revoke.c \
|
||||
decrypt.c \
|
||||
keyedit.c \
|
||||
dearmor.c \
|
||||
import.c \
|
||||
export.c \
|
||||
trustdb.c \
|
||||
trustdb.h \
|
||||
tdbdump.c \
|
||||
tdbio.c \
|
||||
tdbio.h \
|
||||
delkey.c \
|
||||
keygen.c \
|
||||
pipemode.c \
|
||||
helptext.c \
|
||||
keyserver.c \
|
||||
keyserver-internal.h \
|
||||
photoid.c photoid.h \
|
||||
exec.c exec.h
|
||||
|
||||
gpgv_SOURCES = gpgv.c \
|
||||
$(common_source) \
|
||||
verify.c
|
||||
|
||||
#gpgd_SOURCES = gpgd.c \
|
||||
# ks-proto.h \
|
||||
# ks-proto.c \
|
||||
# ks-db.c \
|
||||
# ks-db.h \
|
||||
# $(common_source)
|
||||
|
||||
LDADD = $(needed_libs) @INTLLIBS@ @CAPLIBS@ @ZLIBS@
|
||||
# gpg gets LIBOBJS to add in mkdtemp if the platform doesn't have it
|
||||
gpg_LDADD = @LIBOBJS@ $(LDADD) @DLLIBS@ @EGDLIBS@
|
||||
|
||||
$(PROGRAMS): $(needed_libs)
|
||||
|
||||
install-data-local:
|
||||
$(mkinstalldirs) $(DESTDIR)$(pkgdatadir)
|
||||
$(INSTALL_DATA) $(srcdir)/options.skel \
|
||||
$(DESTDIR)$(pkgdatadir)/options.skel
|
||||
@set -e;\
|
||||
if test -f $(DESTDIR)$(bindir)/gpgm ; then \
|
||||
echo "removing obsolete gpgm binary" ; \
|
||||
rm $(DESTDIR)$(bindir)/gpgm ; \
|
||||
fi
|
1336
g10/armor.c
Normal file
1336
g10/armor.c
Normal file
File diff suppressed because it is too large
Load Diff
1196
g10/build-packet.c
Normal file
1196
g10/build-packet.c
Normal file
File diff suppressed because it is too large
Load Diff
152
g10/cipher.c
Normal file
152
g10/cipher.c
Normal file
@ -0,0 +1,152 @@
|
||||
/* cipher.c - En-/De-ciphering filter
|
||||
* Copyright (C) 1998, 1999, 2000, 2001 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "errors.h"
|
||||
#include "iobuf.h"
|
||||
#include "memory.h"
|
||||
#include "util.h"
|
||||
#include "filter.h"
|
||||
#include "packet.h"
|
||||
#include "options.h"
|
||||
#include "main.h"
|
||||
#include "status.h"
|
||||
|
||||
|
||||
#define MIN_PARTIAL_SIZE 512
|
||||
|
||||
|
||||
static void
|
||||
write_header( cipher_filter_context_t *cfx, IOBUF a )
|
||||
{
|
||||
PACKET pkt;
|
||||
PKT_encrypted ed;
|
||||
byte temp[18];
|
||||
unsigned blocksize;
|
||||
unsigned nprefix;
|
||||
|
||||
blocksize = cipher_get_blocksize( cfx->dek->algo );
|
||||
if( blocksize < 8 || blocksize > 16 )
|
||||
log_fatal("unsupported blocksize %u\n", blocksize );
|
||||
|
||||
memset( &ed, 0, sizeof ed );
|
||||
ed.len = cfx->datalen;
|
||||
ed.extralen = blocksize+2;
|
||||
ed.new_ctb = !ed.len && !RFC1991;
|
||||
if( cfx->dek->use_mdc ) {
|
||||
ed.mdc_method = DIGEST_ALGO_SHA1;
|
||||
cfx->mdc_hash = md_open( DIGEST_ALGO_SHA1, 0 );
|
||||
if ( DBG_HASHING )
|
||||
md_start_debug( cfx->mdc_hash, "creatmdc" );
|
||||
}
|
||||
|
||||
{
|
||||
char buf[20];
|
||||
|
||||
sprintf (buf, "%d %d", ed.mdc_method, cfx->dek->algo);
|
||||
write_status_text (STATUS_BEGIN_ENCRYPTION, buf);
|
||||
}
|
||||
|
||||
init_packet( &pkt );
|
||||
pkt.pkttype = cfx->dek->use_mdc? PKT_ENCRYPTED_MDC : PKT_ENCRYPTED;
|
||||
pkt.pkt.encrypted = &ed;
|
||||
if( build_packet( a, &pkt ))
|
||||
log_bug("build_packet(ENCR_DATA) failed\n");
|
||||
nprefix = blocksize;
|
||||
randomize_buffer( temp, nprefix, 1 );
|
||||
temp[nprefix] = temp[nprefix-2];
|
||||
temp[nprefix+1] = temp[nprefix-1];
|
||||
print_cipher_algo_note( cfx->dek->algo );
|
||||
cfx->cipher_hd = cipher_open( cfx->dek->algo,
|
||||
cfx->dek->use_mdc? CIPHER_MODE_CFB
|
||||
: CIPHER_MODE_AUTO_CFB, 1 );
|
||||
/* log_hexdump( "thekey", cfx->dek->key, cfx->dek->keylen );*/
|
||||
cipher_setkey( cfx->cipher_hd, cfx->dek->key, cfx->dek->keylen );
|
||||
cipher_setiv( cfx->cipher_hd, NULL, 0 );
|
||||
/* log_hexdump( "prefix", temp, nprefix+2 ); */
|
||||
if( cfx->mdc_hash ) /* hash the "IV" */
|
||||
md_write( cfx->mdc_hash, temp, nprefix+2 );
|
||||
cipher_encrypt( cfx->cipher_hd, temp, temp, nprefix+2);
|
||||
cipher_sync( cfx->cipher_hd );
|
||||
iobuf_write(a, temp, nprefix+2);
|
||||
cfx->header=1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/****************
|
||||
* This filter is used to en/de-cipher data with a conventional algorithm
|
||||
*/
|
||||
int
|
||||
cipher_filter( void *opaque, int control,
|
||||
IOBUF a, byte *buf, size_t *ret_len)
|
||||
{
|
||||
size_t size = *ret_len;
|
||||
cipher_filter_context_t *cfx = opaque;
|
||||
int rc=0;
|
||||
|
||||
if( control == IOBUFCTRL_UNDERFLOW ) { /* decrypt */
|
||||
rc = -1; /* not yet used */
|
||||
}
|
||||
else if( control == IOBUFCTRL_FLUSH ) { /* encrypt */
|
||||
assert(a);
|
||||
if( !cfx->header ) {
|
||||
write_header( cfx, a );
|
||||
}
|
||||
if( cfx->mdc_hash )
|
||||
md_write( cfx->mdc_hash, buf, size );
|
||||
cipher_encrypt( cfx->cipher_hd, buf, buf, size);
|
||||
if( iobuf_write( a, buf, size ) )
|
||||
rc = G10ERR_WRITE_FILE;
|
||||
}
|
||||
else if( control == IOBUFCTRL_FREE ) {
|
||||
if( cfx->mdc_hash ) {
|
||||
byte *hash;
|
||||
int hashlen = md_digest_length( md_get_algo( cfx->mdc_hash ) );
|
||||
byte temp[22];
|
||||
|
||||
assert( hashlen == 20 );
|
||||
/* we must hash the prefix of the MDC packet here */
|
||||
temp[0] = 0xd3;
|
||||
temp[1] = 0x14;
|
||||
md_putc( cfx->mdc_hash, temp[0] );
|
||||
md_putc( cfx->mdc_hash, temp[1] );
|
||||
|
||||
md_final( cfx->mdc_hash );
|
||||
hash = md_read( cfx->mdc_hash, 0 );
|
||||
memcpy(temp+2, hash, 20);
|
||||
cipher_encrypt( cfx->cipher_hd, temp, temp, 22 );
|
||||
md_close( cfx->mdc_hash ); cfx->mdc_hash = NULL;
|
||||
if( iobuf_write( a, temp, 22 ) )
|
||||
log_error("writing MDC packet failed\n" );
|
||||
}
|
||||
cipher_close(cfx->cipher_hd);
|
||||
}
|
||||
else if( control == IOBUFCTRL_DESC ) {
|
||||
*(char**)buf = "cipher_filter";
|
||||
}
|
||||
return rc;
|
||||
}
|
324
g10/compress.c
Normal file
324
g10/compress.c
Normal file
@ -0,0 +1,324 @@
|
||||
/* compress.c - compress filter
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <zlib.h>
|
||||
#ifdef __riscos__
|
||||
# include "zlib-riscos.h"
|
||||
#endif
|
||||
|
||||
#include "util.h"
|
||||
#include "memory.h"
|
||||
#include "packet.h"
|
||||
#include "filter.h"
|
||||
#include "main.h"
|
||||
#include "options.h"
|
||||
|
||||
static void
|
||||
init_compress( compress_filter_context_t *zfx, z_stream *zs )
|
||||
{
|
||||
int rc;
|
||||
int level;
|
||||
|
||||
#ifdef __riscos__
|
||||
static int zlib_initialized = 0;
|
||||
|
||||
if (!zlib_initialized)
|
||||
zlib_initialized = riscos_load_module("ZLib", zlib_path, 1);
|
||||
#endif
|
||||
|
||||
if( opt.compress >= 0 && opt.compress <= 9 )
|
||||
level = opt.compress;
|
||||
else if( opt.compress == -1 )
|
||||
level = Z_DEFAULT_COMPRESSION;
|
||||
else if( opt.compress == 10 ) /* remove this ! */
|
||||
level = 0;
|
||||
else {
|
||||
log_error("invalid compression level; using default level\n");
|
||||
level = Z_DEFAULT_COMPRESSION;
|
||||
}
|
||||
|
||||
|
||||
if( (rc = zfx->algo == 1? deflateInit2( zs, level, Z_DEFLATED,
|
||||
-13, 8, Z_DEFAULT_STRATEGY)
|
||||
: deflateInit( zs, level )
|
||||
) != Z_OK ) {
|
||||
log_fatal("zlib problem: %s\n", zs->msg? zs->msg :
|
||||
rc == Z_MEM_ERROR ? "out of core" :
|
||||
rc == Z_VERSION_ERROR ? "invalid lib version" :
|
||||
"unknown error" );
|
||||
}
|
||||
|
||||
zfx->outbufsize = 8192;
|
||||
zfx->outbuf = m_alloc( zfx->outbufsize );
|
||||
}
|
||||
|
||||
static int
|
||||
do_compress( compress_filter_context_t *zfx, z_stream *zs, int flush, IOBUF a )
|
||||
{
|
||||
int zrc;
|
||||
unsigned n;
|
||||
|
||||
do {
|
||||
#ifndef __riscos__
|
||||
zs->next_out = zfx->outbuf;
|
||||
#else /* __riscos__ */
|
||||
zs->next_out = (Bytef *) zfx->outbuf;
|
||||
#endif /* __riscos__ */
|
||||
zs->avail_out = zfx->outbufsize;
|
||||
if( DBG_FILTER )
|
||||
log_debug("enter deflate: avail_in=%u, avail_out=%u, flush=%d\n",
|
||||
(unsigned)zs->avail_in, (unsigned)zs->avail_out, flush );
|
||||
zrc = deflate( zs, flush );
|
||||
if( zrc == Z_STREAM_END && flush == Z_FINISH )
|
||||
;
|
||||
else if( zrc != Z_OK ) {
|
||||
if( zs->msg )
|
||||
log_fatal("zlib deflate problem: %s\n", zs->msg );
|
||||
else
|
||||
log_fatal("zlib deflate problem: rc=%d\n", zrc );
|
||||
}
|
||||
n = zfx->outbufsize - zs->avail_out;
|
||||
if( DBG_FILTER )
|
||||
log_debug("leave deflate: "
|
||||
"avail_in=%u, avail_out=%u, n=%u, zrc=%d\n",
|
||||
(unsigned)zs->avail_in, (unsigned)zs->avail_out,
|
||||
(unsigned)n, zrc );
|
||||
|
||||
if( iobuf_write( a, zfx->outbuf, n ) ) {
|
||||
log_debug("deflate: iobuf_write failed\n");
|
||||
return G10ERR_WRITE_FILE;
|
||||
}
|
||||
} while( zs->avail_in || (flush == Z_FINISH && zrc != Z_STREAM_END) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
init_uncompress( compress_filter_context_t *zfx, z_stream *zs )
|
||||
{
|
||||
int rc;
|
||||
|
||||
/****************
|
||||
* PGP uses a windowsize of 13 bits. Using a negative value for
|
||||
* it forces zlib not to expect a zlib header. This is a
|
||||
* undocumented feature Peter Gutmann told me about.
|
||||
*
|
||||
* We must use 15 bits for the inflator because CryptoEx uses 15
|
||||
* bits thus the output would get scrambled w/o error indication
|
||||
* if we would use 13 bits. For the uncompressing this does not
|
||||
* matter at all.
|
||||
*/
|
||||
if( (rc = zfx->algo == 1? inflateInit2( zs, -15)
|
||||
: inflateInit( zs )) != Z_OK ) {
|
||||
log_fatal("zlib problem: %s\n", zs->msg? zs->msg :
|
||||
rc == Z_MEM_ERROR ? "out of core" :
|
||||
rc == Z_VERSION_ERROR ? "invalid lib version" :
|
||||
"unknown error" );
|
||||
}
|
||||
|
||||
zfx->inbufsize = 2048;
|
||||
zfx->inbuf = m_alloc( zfx->inbufsize );
|
||||
zs->avail_in = 0;
|
||||
}
|
||||
|
||||
static int
|
||||
do_uncompress( compress_filter_context_t *zfx, z_stream *zs,
|
||||
IOBUF a, size_t *ret_len )
|
||||
{
|
||||
int zrc;
|
||||
int rc=0;
|
||||
size_t n;
|
||||
int nread, count;
|
||||
int refill = !zs->avail_in;
|
||||
|
||||
if( DBG_FILTER )
|
||||
log_debug("begin inflate: avail_in=%u, avail_out=%u, inbuf=%u\n",
|
||||
(unsigned)zs->avail_in, (unsigned)zs->avail_out,
|
||||
(unsigned)zfx->inbufsize );
|
||||
do {
|
||||
if( zs->avail_in < zfx->inbufsize && refill ) {
|
||||
n = zs->avail_in;
|
||||
if( !n )
|
||||
#ifndef __riscos__
|
||||
zs->next_in = zfx->inbuf;
|
||||
#else /* __riscos__ */
|
||||
zs->next_in = (Bytef *) zfx->inbuf;
|
||||
#endif /* __riscos__ */
|
||||
count = zfx->inbufsize - n;
|
||||
nread = iobuf_read( a, zfx->inbuf + n, count );
|
||||
if( nread == -1 ) nread = 0;
|
||||
n += nread;
|
||||
/* If we use the undocumented feature to suppress
|
||||
* the zlib header, we have to give inflate an
|
||||
* extra dummy byte to read */
|
||||
if( nread < count && zfx->algo == 1 ) {
|
||||
*(zfx->inbuf + n) = 0xFF; /* is it really needed ? */
|
||||
zfx->algo1hack = 1;
|
||||
n++;
|
||||
}
|
||||
zs->avail_in = n;
|
||||
}
|
||||
refill = 1;
|
||||
if( DBG_FILTER )
|
||||
log_debug("enter inflate: avail_in=%u, avail_out=%u\n",
|
||||
(unsigned)zs->avail_in, (unsigned)zs->avail_out);
|
||||
#ifdef Z_SYNC_FLUSH
|
||||
zrc = inflate( zs, Z_SYNC_FLUSH );
|
||||
#else
|
||||
zrc = inflate( zs, Z_PARTIAL_FLUSH );
|
||||
#endif
|
||||
if( DBG_FILTER )
|
||||
log_debug("leave inflate: avail_in=%u, avail_out=%u, zrc=%d\n",
|
||||
(unsigned)zs->avail_in, (unsigned)zs->avail_out, zrc);
|
||||
if( zrc == Z_STREAM_END )
|
||||
rc = -1; /* eof */
|
||||
else if( zrc != Z_OK && zrc != Z_BUF_ERROR ) {
|
||||
if( zs->msg )
|
||||
log_fatal("zlib inflate problem: %s\n", zs->msg );
|
||||
else
|
||||
log_fatal("zlib inflate problem: rc=%d\n", zrc );
|
||||
}
|
||||
} while( zs->avail_out && zrc != Z_STREAM_END && zrc != Z_BUF_ERROR );
|
||||
*ret_len = zfx->outbufsize - zs->avail_out;
|
||||
if( DBG_FILTER )
|
||||
log_debug("do_uncompress: returning %u bytes\n", (unsigned)*ret_len );
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
compress_filter( void *opaque, int control,
|
||||
IOBUF a, byte *buf, size_t *ret_len)
|
||||
{
|
||||
size_t size = *ret_len;
|
||||
compress_filter_context_t *zfx = opaque;
|
||||
z_stream *zs = zfx->opaque;
|
||||
int rc=0;
|
||||
|
||||
if( control == IOBUFCTRL_UNDERFLOW ) {
|
||||
if( !zfx->status ) {
|
||||
zs = zfx->opaque = m_alloc_clear( sizeof *zs );
|
||||
init_uncompress( zfx, zs );
|
||||
zfx->status = 1;
|
||||
}
|
||||
|
||||
#ifndef __riscos__
|
||||
zs->next_out = buf;
|
||||
#else /* __riscos__ */
|
||||
zs->next_out = (Bytef *) buf;
|
||||
#endif /* __riscos__ */
|
||||
zs->avail_out = size;
|
||||
zfx->outbufsize = size; /* needed only for calculation */
|
||||
rc = do_uncompress( zfx, zs, a, ret_len );
|
||||
}
|
||||
else if( control == IOBUFCTRL_FLUSH ) {
|
||||
if( !zfx->status ) {
|
||||
PACKET pkt;
|
||||
PKT_compressed cd;
|
||||
|
||||
if( !zfx->algo )
|
||||
zfx->algo = DEFAULT_COMPRESS_ALGO;
|
||||
if( zfx->algo != 1 && zfx->algo != 2 )
|
||||
BUG();
|
||||
memset( &cd, 0, sizeof cd );
|
||||
cd.len = 0;
|
||||
cd.algorithm = zfx->algo;
|
||||
init_packet( &pkt );
|
||||
pkt.pkttype = PKT_COMPRESSED;
|
||||
pkt.pkt.compressed = &cd;
|
||||
if( build_packet( a, &pkt ))
|
||||
log_bug("build_packet(PKT_COMPRESSED) failed\n");
|
||||
zs = zfx->opaque = m_alloc_clear( sizeof *zs );
|
||||
init_compress( zfx, zs );
|
||||
zfx->status = 2;
|
||||
}
|
||||
|
||||
#ifndef __riscos__
|
||||
zs->next_in = buf;
|
||||
#else /* __riscos__ */
|
||||
zs->next_in = (Bytef *) buf;
|
||||
#endif /* __riscos__ */
|
||||
zs->avail_in = size;
|
||||
rc = do_compress( zfx, zs, Z_NO_FLUSH, a );
|
||||
}
|
||||
else if( control == IOBUFCTRL_FREE ) {
|
||||
if( zfx->status == 1 ) {
|
||||
inflateEnd(zs);
|
||||
m_free(zs);
|
||||
zfx->opaque = NULL;
|
||||
m_free(zfx->outbuf); zfx->outbuf = NULL;
|
||||
}
|
||||
else if( zfx->status == 2 ) {
|
||||
#ifndef __riscos__
|
||||
zs->next_in = buf;
|
||||
#else /* __riscos__ */
|
||||
zs->next_in = (Bytef *) buf;
|
||||
#endif /* __riscos__ */
|
||||
zs->avail_in = 0;
|
||||
do_compress( zfx, zs, Z_FINISH, a );
|
||||
deflateEnd(zs);
|
||||
m_free(zs);
|
||||
zfx->opaque = NULL;
|
||||
m_free(zfx->outbuf); zfx->outbuf = NULL;
|
||||
}
|
||||
if (zfx->release)
|
||||
zfx->release (zfx);
|
||||
}
|
||||
else if( control == IOBUFCTRL_DESC )
|
||||
*(char**)buf = "compress_filter";
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
release_context (compress_filter_context_t *ctx)
|
||||
{
|
||||
m_free (ctx);
|
||||
}
|
||||
|
||||
/****************
|
||||
* Handle a compressed packet
|
||||
*/
|
||||
int
|
||||
handle_compressed( void *procctx, PKT_compressed *cd,
|
||||
int (*callback)(IOBUF, void *), void *passthru )
|
||||
{
|
||||
compress_filter_context_t *cfx;
|
||||
int rc;
|
||||
|
||||
if( cd->algorithm < 1 || cd->algorithm > 2 )
|
||||
return G10ERR_COMPR_ALGO;
|
||||
cfx = m_alloc_clear (sizeof *cfx);
|
||||
cfx->algo = cd->algorithm;
|
||||
cfx->release = release_context;
|
||||
iobuf_push_filter( cd->buf, compress_filter, cfx );
|
||||
if( callback )
|
||||
rc = callback(cd->buf, passthru );
|
||||
else
|
||||
rc = proc_packets(procctx, cd->buf);
|
||||
cd->buf = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
141
g10/decrypt.c
Normal file
141
g10/decrypt.c
Normal file
@ -0,0 +1,141 @@
|
||||
/* decrypt.c - verify signed data
|
||||
* Copyright (C) 1998,1999,2000,2001,2002,2003 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "options.h"
|
||||
#include "packet.h"
|
||||
#include "errors.h"
|
||||
#include "iobuf.h"
|
||||
#include "keydb.h"
|
||||
#include "memory.h"
|
||||
#include "util.h"
|
||||
#include "main.h"
|
||||
#include "status.h"
|
||||
#include "i18n.h"
|
||||
|
||||
|
||||
|
||||
/****************
|
||||
* Assume that the input is an encrypted message and decrypt
|
||||
* (and if signed, verify the signature on) it.
|
||||
* This command differs from the default operation, as it never
|
||||
* writes to the filename which is included in the file and it
|
||||
* rejects files which don't begin with an encrypted message.
|
||||
*/
|
||||
|
||||
int
|
||||
decrypt_message( const char *filename )
|
||||
{
|
||||
IOBUF fp;
|
||||
armor_filter_context_t afx;
|
||||
progress_filter_context_t pfx;
|
||||
int rc;
|
||||
int no_out=0;
|
||||
|
||||
/* open the message file */
|
||||
fp = iobuf_open(filename);
|
||||
if( !fp ) {
|
||||
log_error(_("can't open `%s'\n"), print_fname_stdin(filename));
|
||||
return G10ERR_OPEN_FILE;
|
||||
}
|
||||
|
||||
handle_progress (&pfx, fp, filename);
|
||||
|
||||
if( !opt.no_armor ) {
|
||||
if( use_armor_filter( fp ) ) {
|
||||
memset( &afx, 0, sizeof afx);
|
||||
iobuf_push_filter( fp, armor_filter, &afx );
|
||||
}
|
||||
}
|
||||
|
||||
if( !opt.outfile ) {
|
||||
no_out = 1;
|
||||
opt.outfile = "-";
|
||||
}
|
||||
rc = proc_encryption_packets( NULL, fp );
|
||||
if( no_out )
|
||||
opt.outfile = NULL;
|
||||
iobuf_close(fp);
|
||||
return rc;
|
||||
}
|
||||
|
||||
void
|
||||
decrypt_messages(int nfiles, char **files)
|
||||
{
|
||||
IOBUF fp;
|
||||
armor_filter_context_t afx;
|
||||
progress_filter_context_t pfx;
|
||||
char *p, *output = NULL;
|
||||
int rc = 0;
|
||||
|
||||
if (opt.outfile)
|
||||
{
|
||||
log_error(_("--output doesn't work for this command\n"));
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
while (nfiles--)
|
||||
{
|
||||
print_file_status(STATUS_FILE_START, *files, 3);
|
||||
output = make_outfile_name(*files);
|
||||
if (!output)
|
||||
goto next_file;
|
||||
fp = iobuf_open(*files);
|
||||
if (!fp)
|
||||
{
|
||||
log_error(_("can't open `%s'\n"), print_fname_stdin(*files));
|
||||
goto next_file;
|
||||
}
|
||||
|
||||
handle_progress (&pfx, fp, *files);
|
||||
|
||||
if (!opt.no_armor)
|
||||
{
|
||||
if (use_armor_filter(fp))
|
||||
{
|
||||
memset(&afx, 0, sizeof afx);
|
||||
iobuf_push_filter(fp, armor_filter, &afx);
|
||||
}
|
||||
}
|
||||
rc = proc_packets(NULL, fp);
|
||||
iobuf_close(fp);
|
||||
if (rc)
|
||||
log_error("%s: decryption failed: %s\n", print_fname_stdin(*files),
|
||||
g10_errstr(rc));
|
||||
p = get_last_passphrase();
|
||||
set_next_passphrase(p);
|
||||
m_free (p);
|
||||
|
||||
next_file:
|
||||
/* Note that we emit file_done even after an error. */
|
||||
write_status( STATUS_FILE_DONE );
|
||||
m_free(output);
|
||||
files++;
|
||||
}
|
||||
set_next_passphrase(NULL);
|
||||
}
|
||||
|
811
g10/encode.c
Normal file
811
g10/encode.c
Normal file
@ -0,0 +1,811 @@
|
||||
/* encode.c - encode data
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002,
|
||||
* 2003 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "options.h"
|
||||
#include "packet.h"
|
||||
#include "errors.h"
|
||||
#include "iobuf.h"
|
||||
#include "keydb.h"
|
||||
#include "memory.h"
|
||||
#include "util.h"
|
||||
#include "main.h"
|
||||
#include "filter.h"
|
||||
#include "trustdb.h"
|
||||
#include "i18n.h"
|
||||
#include "status.h"
|
||||
|
||||
static int encode_simple( const char *filename, int mode, int compat );
|
||||
static int write_pubkey_enc_from_list( PK_LIST pk_list, DEK *dek, IOBUF out );
|
||||
|
||||
|
||||
|
||||
/****************
|
||||
* Encode FILENAME with only the symmetric cipher. Take input from
|
||||
* stdin if FILENAME is NULL.
|
||||
*/
|
||||
int
|
||||
encode_symmetric( const char *filename )
|
||||
{
|
||||
int compat = 1;
|
||||
|
||||
#if 0
|
||||
/* We don't want to use it because older gnupg version can't
|
||||
handle it and we can presume that a lot of scripts are running
|
||||
with the expert mode set. Some time in the future we might
|
||||
want to allow for it. */
|
||||
if ( opt.expert )
|
||||
compat = 0; /* PGP knows how to handle this mode. */
|
||||
#endif
|
||||
return encode_simple( filename, 1, compat );
|
||||
}
|
||||
|
||||
/****************
|
||||
* Encode FILENAME as a literal data packet only. Take input from
|
||||
* stdin if FILENAME is NULL.
|
||||
*/
|
||||
int
|
||||
encode_store( const char *filename )
|
||||
{
|
||||
return encode_simple( filename, 0, 1 );
|
||||
}
|
||||
|
||||
static void
|
||||
encode_sesskey( DEK *dek, DEK **ret_dek, byte *enckey )
|
||||
{
|
||||
CIPHER_HANDLE hd;
|
||||
DEK *c;
|
||||
byte buf[33];
|
||||
|
||||
assert ( dek->keylen < 32 );
|
||||
|
||||
c = m_alloc_clear( sizeof *c );
|
||||
c->keylen = dek->keylen;
|
||||
c->algo = dek->algo;
|
||||
make_session_key( c );
|
||||
/*log_hexdump( "thekey", c->key, c->keylen );*/
|
||||
|
||||
buf[0] = c->algo;
|
||||
memcpy( buf + 1, c->key, c->keylen );
|
||||
|
||||
hd = cipher_open( dek->algo, CIPHER_MODE_CFB, 1 );
|
||||
cipher_setkey( hd, dek->key, dek->keylen );
|
||||
cipher_setiv( hd, NULL, 0 );
|
||||
cipher_encrypt( hd, buf, buf, c->keylen + 1 );
|
||||
cipher_close( hd );
|
||||
|
||||
memcpy( enckey, buf, c->keylen + 1 );
|
||||
wipememory( buf, sizeof buf ); /* burn key */
|
||||
*ret_dek = c;
|
||||
}
|
||||
|
||||
/* We try very hard to use a MDC */
|
||||
static int
|
||||
use_mdc(PK_LIST pk_list,int algo)
|
||||
{
|
||||
/* --force-mdc overrides --disable-mdc */
|
||||
if(opt.force_mdc)
|
||||
return 1;
|
||||
|
||||
if(opt.disable_mdc)
|
||||
return 0;
|
||||
|
||||
/* Do the keys really support MDC? */
|
||||
|
||||
if(select_mdc_from_pklist(pk_list))
|
||||
return 1;
|
||||
|
||||
/* The keys don't support MDC, so now we do a bit of a hack - if any
|
||||
of the AESes or TWOFISH are in the prefs, we assume that the user
|
||||
can handle a MDC. This is valid for PGP 7, which can handle MDCs
|
||||
though it will not generate them. 2440bis allows this, by the
|
||||
way. */
|
||||
|
||||
if(select_algo_from_prefs(pk_list,PREFTYPE_SYM,
|
||||
CIPHER_ALGO_AES,NULL)==CIPHER_ALGO_AES)
|
||||
return 1;
|
||||
|
||||
if(select_algo_from_prefs(pk_list,PREFTYPE_SYM,
|
||||
CIPHER_ALGO_AES192,NULL)==CIPHER_ALGO_AES192)
|
||||
return 1;
|
||||
|
||||
if(select_algo_from_prefs(pk_list,PREFTYPE_SYM,
|
||||
CIPHER_ALGO_AES256,NULL)==CIPHER_ALGO_AES256)
|
||||
return 1;
|
||||
|
||||
if(select_algo_from_prefs(pk_list,PREFTYPE_SYM,
|
||||
CIPHER_ALGO_TWOFISH,NULL)==CIPHER_ALGO_TWOFISH)
|
||||
return 1;
|
||||
|
||||
/* Last try. Use MDC for the modern ciphers. */
|
||||
|
||||
if(cipher_get_blocksize(algo)!=8)
|
||||
return 1;
|
||||
|
||||
return 0; /* No MDC */
|
||||
}
|
||||
|
||||
static int
|
||||
encode_simple( const char *filename, int mode, int compat )
|
||||
{
|
||||
IOBUF inp, out;
|
||||
PACKET pkt;
|
||||
DEK *dek = NULL;
|
||||
PKT_plaintext *pt = NULL;
|
||||
STRING2KEY *s2k = NULL;
|
||||
byte enckey[33];
|
||||
int rc = 0;
|
||||
int seskeylen = 0;
|
||||
u32 filesize;
|
||||
cipher_filter_context_t cfx;
|
||||
armor_filter_context_t afx;
|
||||
compress_filter_context_t zfx;
|
||||
text_filter_context_t tfx;
|
||||
progress_filter_context_t pfx;
|
||||
int do_compress = opt.compress && !RFC1991;
|
||||
|
||||
memset( &cfx, 0, sizeof cfx);
|
||||
memset( &afx, 0, sizeof afx);
|
||||
memset( &zfx, 0, sizeof zfx);
|
||||
memset( &tfx, 0, sizeof tfx);
|
||||
init_packet(&pkt);
|
||||
|
||||
/* prepare iobufs */
|
||||
if( !(inp = iobuf_open(filename)) ) {
|
||||
log_error(_("%s: can't open: %s\n"), filename? filename: "[stdin]",
|
||||
strerror(errno) );
|
||||
return G10ERR_OPEN_FILE;
|
||||
}
|
||||
|
||||
handle_progress (&pfx, inp, filename);
|
||||
|
||||
if( opt.textmode )
|
||||
iobuf_push_filter( inp, text_filter, &tfx );
|
||||
|
||||
/* Due the the fact that we use don't use an IV to encrypt the
|
||||
session key we can't use the new mode with RFC1991 because
|
||||
it has no S2K salt. RFC1991 always uses simple S2K. */
|
||||
if ( RFC1991 && !compat )
|
||||
compat = 1;
|
||||
|
||||
cfx.dek = NULL;
|
||||
if( mode ) {
|
||||
s2k = m_alloc_clear( sizeof *s2k );
|
||||
s2k->mode = RFC1991? 0:opt.s2k_mode;
|
||||
s2k->hash_algo = opt.s2k_digest_algo;
|
||||
cfx.dek = passphrase_to_dek( NULL, 0,
|
||||
default_cipher_algo(), s2k, 2,
|
||||
NULL, NULL);
|
||||
if( !cfx.dek || !cfx.dek->keylen ) {
|
||||
rc = G10ERR_PASSPHRASE;
|
||||
m_free(cfx.dek);
|
||||
m_free(s2k);
|
||||
iobuf_close(inp);
|
||||
log_error(_("error creating passphrase: %s\n"), g10_errstr(rc) );
|
||||
return rc;
|
||||
}
|
||||
if (!compat && s2k->mode != 1 && s2k->mode != 3) {
|
||||
compat = 1;
|
||||
log_info (_("can't use a symmetric ESK packet "
|
||||
"due to the S2K mode\n"));
|
||||
}
|
||||
|
||||
if ( !compat ) {
|
||||
seskeylen = cipher_get_keylen( default_cipher_algo() ) / 8;
|
||||
encode_sesskey( cfx.dek, &dek, enckey );
|
||||
m_free( cfx.dek ); cfx.dek = dek;
|
||||
}
|
||||
|
||||
cfx.dek->use_mdc=use_mdc(NULL,cfx.dek->algo);
|
||||
}
|
||||
|
||||
if (opt.compress == -1 && cfx.dek && cfx.dek->use_mdc &&
|
||||
is_file_compressed(filename, &rc))
|
||||
{
|
||||
if (opt.verbose)
|
||||
log_info(_("`%s' already compressed\n"), filename);
|
||||
do_compress = 0;
|
||||
}
|
||||
|
||||
if( rc || (rc = open_outfile( filename, opt.armor? 1:0, &out )) ) {
|
||||
iobuf_cancel(inp);
|
||||
m_free(cfx.dek);
|
||||
m_free(s2k);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if( opt.armor )
|
||||
iobuf_push_filter( out, armor_filter, &afx );
|
||||
#ifdef ENABLE_COMMENT_PACKETS
|
||||
else {
|
||||
write_comment( out, "#created by GNUPG v" VERSION " ("
|
||||
PRINTABLE_OS_NAME ")");
|
||||
if( opt.comment_string )
|
||||
write_comment( out, opt.comment_string );
|
||||
}
|
||||
#endif
|
||||
if( s2k && !RFC1991 ) {
|
||||
PKT_symkey_enc *enc = m_alloc_clear( sizeof *enc + seskeylen + 1 );
|
||||
enc->version = 4;
|
||||
enc->cipher_algo = cfx.dek->algo;
|
||||
enc->s2k = *s2k;
|
||||
if ( !compat && seskeylen ) {
|
||||
enc->seskeylen = seskeylen + 1; /* algo id */
|
||||
memcpy( enc->seskey, enckey, seskeylen + 1 );
|
||||
}
|
||||
pkt.pkttype = PKT_SYMKEY_ENC;
|
||||
pkt.pkt.symkey_enc = enc;
|
||||
if( (rc = build_packet( out, &pkt )) )
|
||||
log_error("build symkey packet failed: %s\n", g10_errstr(rc) );
|
||||
m_free(enc);
|
||||
}
|
||||
|
||||
if (!opt.no_literal) {
|
||||
/* setup the inner packet */
|
||||
if( filename || opt.set_filename ) {
|
||||
char *s = make_basename( opt.set_filename ? opt.set_filename
|
||||
: filename,
|
||||
iobuf_get_real_fname( inp ) );
|
||||
pt = m_alloc( sizeof *pt + strlen(s) - 1 );
|
||||
pt->namelen = strlen(s);
|
||||
memcpy(pt->name, s, pt->namelen );
|
||||
m_free(s);
|
||||
}
|
||||
else { /* no filename */
|
||||
pt = m_alloc( sizeof *pt - 1 );
|
||||
pt->namelen = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Note that PGP 5 has problems decrypting symmetrically encrypted
|
||||
data if the file length is in the inner packet. It works when
|
||||
only partial length headers are use. In the past, we always
|
||||
used partial body length here, but since PGP 2, PGP 6, and PGP
|
||||
7 need the file length, and nobody should be using PGP 5
|
||||
nowadays anyway, this is now set to the file length. Note also
|
||||
that this only applies to the RFC-1991 style symmetric
|
||||
messages, and not the RFC-2440 style. PGP 6 and 7 work with
|
||||
either partial length or fixed length with the new style
|
||||
messages. */
|
||||
|
||||
if (filename && *filename && !(*filename == '-' && !filename[1])
|
||||
&& !opt.textmode ) {
|
||||
off_t tmpsize;
|
||||
|
||||
if ( !(tmpsize = iobuf_get_filelength(inp)) )
|
||||
log_info(_("%s: WARNING: empty file\n"), filename );
|
||||
/* We can't encode the length of very large files because
|
||||
OpenPGP uses only 32 bit for file sizes. So if the the
|
||||
size of a file is larger than 2^32 minus some bytes for
|
||||
packet headers, we switch to partial length encoding. */
|
||||
if ( tmpsize < (IOBUF_FILELENGTH_LIMIT - 65536) )
|
||||
filesize = tmpsize;
|
||||
else
|
||||
filesize = 0;
|
||||
}
|
||||
else
|
||||
filesize = opt.set_filesize ? opt.set_filesize : 0; /* stdin */
|
||||
|
||||
if (!opt.no_literal) {
|
||||
pt->timestamp = make_timestamp();
|
||||
pt->mode = opt.textmode? 't' : 'b';
|
||||
pt->len = filesize;
|
||||
pt->new_ctb = !pt->len && !RFC1991;
|
||||
pt->buf = inp;
|
||||
pkt.pkttype = PKT_PLAINTEXT;
|
||||
pkt.pkt.plaintext = pt;
|
||||
cfx.datalen = filesize && !do_compress ? calc_packet_length( &pkt ) : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
cfx.datalen = filesize && !do_compress ? filesize : 0;
|
||||
pkt.pkttype = 0;
|
||||
pkt.pkt.generic = NULL;
|
||||
}
|
||||
|
||||
/* register the cipher filter */
|
||||
if( mode )
|
||||
iobuf_push_filter( out, cipher_filter, &cfx );
|
||||
/* register the compress filter */
|
||||
if( do_compress )
|
||||
{
|
||||
if (cfx.dek && cfx.dek->use_mdc)
|
||||
zfx.new_ctb = 1;
|
||||
zfx.algo=default_compress_algo();
|
||||
iobuf_push_filter( out, compress_filter, &zfx );
|
||||
}
|
||||
|
||||
/* do the work */
|
||||
if (!opt.no_literal) {
|
||||
if( (rc = build_packet( out, &pkt )) )
|
||||
log_error("build_packet failed: %s\n", g10_errstr(rc) );
|
||||
}
|
||||
else {
|
||||
/* user requested not to create a literal packet,
|
||||
* so we copy the plain data */
|
||||
byte copy_buffer[4096];
|
||||
int bytes_copied;
|
||||
while ((bytes_copied = iobuf_read(inp, copy_buffer, 4096)) != -1)
|
||||
if (iobuf_write(out, copy_buffer, bytes_copied) == -1) {
|
||||
rc = G10ERR_WRITE_FILE;
|
||||
log_error("copying input to output failed: %s\n", g10_errstr(rc) );
|
||||
break;
|
||||
}
|
||||
wipememory(copy_buffer, 4096); /* burn buffer */
|
||||
}
|
||||
|
||||
/* finish the stuff */
|
||||
iobuf_close(inp);
|
||||
if (rc)
|
||||
iobuf_cancel(out);
|
||||
else {
|
||||
iobuf_close(out); /* fixme: check returncode */
|
||||
if (mode)
|
||||
write_status( STATUS_END_ENCRYPTION );
|
||||
}
|
||||
if (pt)
|
||||
pt->buf = NULL;
|
||||
free_packet(&pkt);
|
||||
m_free(cfx.dek);
|
||||
m_free(s2k);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/****************
|
||||
* Encrypt the file with the given userids (or ask if none
|
||||
* is supplied).
|
||||
*/
|
||||
int
|
||||
encode_crypt( const char *filename, STRLIST remusr )
|
||||
{
|
||||
IOBUF inp = NULL, out = NULL;
|
||||
PACKET pkt;
|
||||
PKT_plaintext *pt = NULL;
|
||||
int rc = 0, rc2 = 0;
|
||||
u32 filesize;
|
||||
cipher_filter_context_t cfx;
|
||||
armor_filter_context_t afx;
|
||||
compress_filter_context_t zfx;
|
||||
text_filter_context_t tfx;
|
||||
progress_filter_context_t pfx;
|
||||
PK_LIST pk_list,work_list;
|
||||
int do_compress = opt.compress && !RFC1991;
|
||||
|
||||
|
||||
memset( &cfx, 0, sizeof cfx);
|
||||
memset( &afx, 0, sizeof afx);
|
||||
memset( &zfx, 0, sizeof zfx);
|
||||
memset( &tfx, 0, sizeof tfx);
|
||||
init_packet(&pkt);
|
||||
|
||||
if( (rc=build_pk_list( remusr, &pk_list, PUBKEY_USAGE_ENC)) )
|
||||
return rc;
|
||||
|
||||
if(PGP2) {
|
||||
for(work_list=pk_list; work_list; work_list=work_list->next)
|
||||
if(!(is_RSA(work_list->pk->pubkey_algo) &&
|
||||
nbits_from_pk(work_list->pk)<=2048))
|
||||
{
|
||||
log_info(_("you can only encrypt to RSA keys of 2048 bits or "
|
||||
"less in --pgp2 mode\n"));
|
||||
compliance_failure();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* prepare iobufs */
|
||||
if( !(inp = iobuf_open(filename)) ) {
|
||||
log_error(_("can't open %s: %s\n"), filename? filename: "[stdin]",
|
||||
strerror(errno) );
|
||||
rc = G10ERR_OPEN_FILE;
|
||||
goto leave;
|
||||
}
|
||||
else if( opt.verbose )
|
||||
log_info(_("reading from `%s'\n"), filename? filename: "[stdin]");
|
||||
|
||||
handle_progress (&pfx, inp, filename);
|
||||
|
||||
if( opt.textmode )
|
||||
iobuf_push_filter( inp, text_filter, &tfx );
|
||||
|
||||
if( (rc = open_outfile( filename, opt.armor? 1:0, &out )) )
|
||||
goto leave;
|
||||
|
||||
|
||||
if( opt.armor )
|
||||
iobuf_push_filter( out, armor_filter, &afx );
|
||||
#ifdef ENABLE_COMMENT_PACKETS
|
||||
else {
|
||||
write_comment( out, "#created by GNUPG v" VERSION " ("
|
||||
PRINTABLE_OS_NAME ")");
|
||||
if( opt.comment_string )
|
||||
write_comment( out, opt.comment_string );
|
||||
}
|
||||
#endif
|
||||
/* create a session key */
|
||||
cfx.dek = m_alloc_secure_clear (sizeof *cfx.dek);
|
||||
if( !opt.def_cipher_algo ) { /* try to get it from the prefs */
|
||||
cfx.dek->algo = select_algo_from_prefs(pk_list,PREFTYPE_SYM,-1,NULL);
|
||||
/* The only way select_algo_from_prefs can fail here is when
|
||||
mixing v3 and v4 keys, as v4 keys have an implicit
|
||||
preference entry for 3DES, and the pk_list cannot be empty.
|
||||
In this case, use 3DES anyway as it's the safest choice -
|
||||
perhaps the v3 key is being used in an OpenPGP
|
||||
implementation and we know that the implementation behind
|
||||
any v4 key can handle 3DES. */
|
||||
if( cfx.dek->algo == -1 ) {
|
||||
cfx.dek->algo = CIPHER_ALGO_3DES;
|
||||
|
||||
if( PGP2 ) {
|
||||
log_info(_("unable to use the IDEA cipher for all of the keys "
|
||||
"you are encrypting to.\n"));
|
||||
compliance_failure();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(!opt.expert &&
|
||||
select_algo_from_prefs(pk_list,PREFTYPE_SYM,
|
||||
opt.def_cipher_algo,NULL)!=opt.def_cipher_algo)
|
||||
log_info(_("forcing symmetric cipher %s (%d) "
|
||||
"violates recipient preferences\n"),
|
||||
cipher_algo_to_string(opt.def_cipher_algo),
|
||||
opt.def_cipher_algo);
|
||||
|
||||
cfx.dek->algo = opt.def_cipher_algo;
|
||||
}
|
||||
|
||||
cfx.dek->use_mdc=use_mdc(pk_list,cfx.dek->algo);
|
||||
|
||||
/* Only do the is-file-already-compressed check if we are using a
|
||||
MDC. This forces compressed files to be re-compressed if we do
|
||||
not have a MDC to give some protection against chosen
|
||||
ciphertext attacks. */
|
||||
|
||||
if (opt.compress == -1 && cfx.dek->use_mdc &&
|
||||
is_file_compressed(filename, &rc2) )
|
||||
{
|
||||
if (opt.verbose)
|
||||
log_info(_("`%s' already compressed\n"), filename);
|
||||
do_compress = 0;
|
||||
}
|
||||
if (rc2)
|
||||
{
|
||||
rc = rc2;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
make_session_key( cfx.dek );
|
||||
if( DBG_CIPHER )
|
||||
log_hexdump("DEK is: ", cfx.dek->key, cfx.dek->keylen );
|
||||
|
||||
rc = write_pubkey_enc_from_list( pk_list, cfx.dek, out );
|
||||
if( rc )
|
||||
goto leave;
|
||||
|
||||
if (!opt.no_literal) {
|
||||
/* setup the inner packet */
|
||||
if( filename || opt.set_filename ) {
|
||||
char *s = make_basename( opt.set_filename ? opt.set_filename
|
||||
: filename,
|
||||
iobuf_get_real_fname( inp ) );
|
||||
pt = m_alloc( sizeof *pt + strlen(s) - 1 );
|
||||
pt->namelen = strlen(s);
|
||||
memcpy(pt->name, s, pt->namelen );
|
||||
m_free(s);
|
||||
}
|
||||
else { /* no filename */
|
||||
pt = m_alloc( sizeof *pt - 1 );
|
||||
pt->namelen = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (filename && *filename && !(*filename == '-' && !filename[1])
|
||||
&& !opt.textmode ) {
|
||||
off_t tmpsize;
|
||||
|
||||
if ( !(tmpsize = iobuf_get_filelength(inp)) )
|
||||
log_info(_("%s: WARNING: empty file\n"), filename );
|
||||
/* We can't encode the length of very large files because
|
||||
OpenPGP uses only 32 bit for file sizes. So if the the
|
||||
size of a file is larger than 2^32 minus some bytes for
|
||||
packet headers, we switch to partial length encoding. */
|
||||
if ( tmpsize < (IOBUF_FILELENGTH_LIMIT - 65536) )
|
||||
filesize = tmpsize;
|
||||
else
|
||||
filesize = 0;
|
||||
}
|
||||
else
|
||||
filesize = opt.set_filesize ? opt.set_filesize : 0; /* stdin */
|
||||
|
||||
if (!opt.no_literal) {
|
||||
pt->timestamp = make_timestamp();
|
||||
pt->mode = opt.textmode ? 't' : 'b';
|
||||
pt->len = filesize;
|
||||
pt->new_ctb = !pt->len && !RFC1991;
|
||||
pt->buf = inp;
|
||||
pkt.pkttype = PKT_PLAINTEXT;
|
||||
pkt.pkt.plaintext = pt;
|
||||
cfx.datalen = filesize && !do_compress? calc_packet_length( &pkt ) : 0;
|
||||
}
|
||||
else
|
||||
cfx.datalen = filesize && !do_compress ? filesize : 0;
|
||||
|
||||
/* register the cipher filter */
|
||||
iobuf_push_filter( out, cipher_filter, &cfx );
|
||||
|
||||
/* register the compress filter */
|
||||
if( do_compress ) {
|
||||
int compr_algo = opt.def_compress_algo;
|
||||
|
||||
if(compr_algo==-1)
|
||||
{
|
||||
if((compr_algo=
|
||||
select_algo_from_prefs(pk_list,PREFTYPE_ZIP,-1,NULL))==-1)
|
||||
compr_algo=DEFAULT_COMPRESS_ALGO;
|
||||
/* Theoretically impossible to get here since uncompressed
|
||||
is implicit. */
|
||||
}
|
||||
else if(!opt.expert &&
|
||||
select_algo_from_prefs(pk_list,PREFTYPE_ZIP,
|
||||
compr_algo,NULL)!=compr_algo)
|
||||
log_info(_("forcing compression algorithm %s (%d) "
|
||||
"violates recipient preferences\n"),
|
||||
compress_algo_to_string(compr_algo),compr_algo);
|
||||
|
||||
/* algo 0 means no compression */
|
||||
if( compr_algo )
|
||||
{
|
||||
if (cfx.dek && cfx.dek->use_mdc)
|
||||
zfx.new_ctb = 1;
|
||||
zfx.algo = compr_algo;
|
||||
iobuf_push_filter( out, compress_filter, &zfx );
|
||||
}
|
||||
}
|
||||
|
||||
/* do the work */
|
||||
if (!opt.no_literal) {
|
||||
if( (rc = build_packet( out, &pkt )) )
|
||||
log_error("build_packet failed: %s\n", g10_errstr(rc) );
|
||||
}
|
||||
else {
|
||||
/* user requested not to create a literal packet, so we copy
|
||||
the plain data */
|
||||
byte copy_buffer[4096];
|
||||
int bytes_copied;
|
||||
while ((bytes_copied = iobuf_read(inp, copy_buffer, 4096)) != -1)
|
||||
if (iobuf_write(out, copy_buffer, bytes_copied) == -1) {
|
||||
rc = G10ERR_WRITE_FILE;
|
||||
log_error("copying input to output failed: %s\n",
|
||||
g10_errstr(rc) );
|
||||
break;
|
||||
}
|
||||
wipememory(copy_buffer, 4096); /* burn buffer */
|
||||
}
|
||||
|
||||
/* finish the stuff */
|
||||
leave:
|
||||
iobuf_close(inp);
|
||||
if( rc )
|
||||
iobuf_cancel(out);
|
||||
else {
|
||||
iobuf_close(out); /* fixme: check returncode */
|
||||
write_status( STATUS_END_ENCRYPTION );
|
||||
}
|
||||
if( pt )
|
||||
pt->buf = NULL;
|
||||
free_packet(&pkt);
|
||||
m_free(cfx.dek);
|
||||
release_pk_list( pk_list );
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/****************
|
||||
* Filter to do a complete public key encryption.
|
||||
*/
|
||||
int
|
||||
encrypt_filter( void *opaque, int control,
|
||||
IOBUF a, byte *buf, size_t *ret_len)
|
||||
{
|
||||
size_t size = *ret_len;
|
||||
encrypt_filter_context_t *efx = opaque;
|
||||
int rc=0;
|
||||
|
||||
if( control == IOBUFCTRL_UNDERFLOW ) { /* decrypt */
|
||||
BUG(); /* not used */
|
||||
}
|
||||
else if( control == IOBUFCTRL_FLUSH ) { /* encrypt */
|
||||
if( !efx->header_okay ) {
|
||||
efx->cfx.dek = m_alloc_secure_clear( sizeof *efx->cfx.dek );
|
||||
|
||||
if( !opt.def_cipher_algo ) { /* try to get it from the prefs */
|
||||
efx->cfx.dek->algo =
|
||||
select_algo_from_prefs(efx->pk_list,PREFTYPE_SYM,-1,NULL);
|
||||
if( efx->cfx.dek->algo == -1 ) {
|
||||
/* because 3DES is implicitly in the prefs, this can only
|
||||
* happen if we do not have any public keys in the list */
|
||||
efx->cfx.dek->algo = DEFAULT_CIPHER_ALGO;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(!opt.expert &&
|
||||
select_algo_from_prefs(efx->pk_list,PREFTYPE_SYM,
|
||||
opt.def_cipher_algo,
|
||||
NULL)!=opt.def_cipher_algo)
|
||||
log_info(_("forcing symmetric cipher %s (%d) "
|
||||
"violates recipient preferences\n"),
|
||||
cipher_algo_to_string(opt.def_cipher_algo),
|
||||
opt.def_cipher_algo);
|
||||
|
||||
efx->cfx.dek->algo = opt.def_cipher_algo;
|
||||
}
|
||||
|
||||
efx->cfx.dek->use_mdc = use_mdc(efx->pk_list,efx->cfx.dek->algo);
|
||||
|
||||
make_session_key( efx->cfx.dek );
|
||||
if( DBG_CIPHER )
|
||||
log_hexdump("DEK is: ",
|
||||
efx->cfx.dek->key, efx->cfx.dek->keylen );
|
||||
|
||||
rc = write_pubkey_enc_from_list( efx->pk_list, efx->cfx.dek, a );
|
||||
if( rc )
|
||||
return rc;
|
||||
|
||||
iobuf_push_filter( a, cipher_filter, &efx->cfx );
|
||||
|
||||
efx->header_okay = 1;
|
||||
}
|
||||
rc = iobuf_write( a, buf, size );
|
||||
|
||||
}
|
||||
else if( control == IOBUFCTRL_FREE ) {
|
||||
}
|
||||
else if( control == IOBUFCTRL_DESC ) {
|
||||
*(char**)buf = "encrypt_filter";
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
* Write pubkey-enc packets from the list of PKs to OUT.
|
||||
*/
|
||||
static int
|
||||
write_pubkey_enc_from_list( PK_LIST pk_list, DEK *dek, IOBUF out )
|
||||
{
|
||||
PACKET pkt;
|
||||
PKT_public_key *pk;
|
||||
PKT_pubkey_enc *enc;
|
||||
int rc;
|
||||
|
||||
for( ; pk_list; pk_list = pk_list->next ) {
|
||||
MPI frame;
|
||||
|
||||
pk = pk_list->pk;
|
||||
|
||||
print_pubkey_algo_note( pk->pubkey_algo );
|
||||
enc = m_alloc_clear( sizeof *enc );
|
||||
enc->pubkey_algo = pk->pubkey_algo;
|
||||
keyid_from_pk( pk, enc->keyid );
|
||||
enc->throw_keyid = (opt.throw_keyid || (pk_list->flags&1));
|
||||
|
||||
if(opt.throw_keyid && (PGP2 || PGP6 || PGP7 || PGP8))
|
||||
{
|
||||
log_info(_("you may not use %s while in %s mode\n"),
|
||||
"--throw-keyid",compliance_option_string());
|
||||
compliance_failure();
|
||||
}
|
||||
|
||||
/* Okay, what's going on: We have the session key somewhere in
|
||||
* the structure DEK and want to encode this session key in
|
||||
* an integer value of n bits. pubkey_nbits gives us the
|
||||
* number of bits we have to use. We then encode the session
|
||||
* key in some way and we get it back in the big intger value
|
||||
* FRAME. Then we use FRAME, the public key PK->PKEY and the
|
||||
* algorithm number PK->PUBKEY_ALGO and pass it to pubkey_encrypt
|
||||
* which returns the encrypted value in the array ENC->DATA.
|
||||
* This array has a size which depends on the used algorithm
|
||||
* (e.g. 2 for ElGamal). We don't need frame anymore because we
|
||||
* have everything now in enc->data which is the passed to
|
||||
* build_packet()
|
||||
*/
|
||||
frame = encode_session_key( dek, pubkey_nbits( pk->pubkey_algo,
|
||||
pk->pkey ) );
|
||||
rc = pubkey_encrypt( pk->pubkey_algo, enc->data, frame, pk->pkey );
|
||||
mpi_free( frame );
|
||||
if( rc )
|
||||
log_error("pubkey_encrypt failed: %s\n", g10_errstr(rc) );
|
||||
else {
|
||||
if( opt.verbose ) {
|
||||
char *ustr = get_user_id_string_printable (enc->keyid);
|
||||
log_info(_("%s/%s encrypted for: \"%s\"\n"),
|
||||
pubkey_algo_to_string(enc->pubkey_algo),
|
||||
cipher_algo_to_string(dek->algo), ustr );
|
||||
m_free(ustr);
|
||||
}
|
||||
/* and write it */
|
||||
init_packet(&pkt);
|
||||
pkt.pkttype = PKT_PUBKEY_ENC;
|
||||
pkt.pkt.pubkey_enc = enc;
|
||||
rc = build_packet( out, &pkt );
|
||||
if( rc )
|
||||
log_error("build_packet(pubkey_enc) failed: %s\n", g10_errstr(rc));
|
||||
}
|
||||
free_pubkey_enc(enc);
|
||||
if( rc )
|
||||
return rc;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
encode_crypt_files(int nfiles, char **files, STRLIST remusr)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (opt.outfile)
|
||||
{
|
||||
log_error(_("--output doesn't work for this command\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!nfiles)
|
||||
{
|
||||
char line[2048];
|
||||
unsigned int lno = 0;
|
||||
while ( fgets(line, DIM(line), stdin) )
|
||||
{
|
||||
lno++;
|
||||
if (!*line || line[strlen(line)-1] != '\n')
|
||||
{
|
||||
log_error("input line %u too long or missing LF\n", lno);
|
||||
return;
|
||||
}
|
||||
line[strlen(line)-1] = '\0';
|
||||
print_file_status(STATUS_FILE_START, line, 2);
|
||||
if ( (rc = encode_crypt(line, remusr)) )
|
||||
log_error("%s: encryption failed: %s\n",
|
||||
print_fname_stdin(line), g10_errstr(rc) );
|
||||
write_status( STATUS_FILE_DONE );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (nfiles--)
|
||||
{
|
||||
print_file_status(STATUS_FILE_START, *files, 2);
|
||||
if ( (rc = encode_crypt(*files, remusr)) )
|
||||
log_error("%s: encryption failed: %s\n",
|
||||
print_fname_stdin(*files), g10_errstr(rc) );
|
||||
write_status( STATUS_FILE_DONE );
|
||||
files++;
|
||||
}
|
||||
}
|
||||
}
|
619
g10/exec.c
Normal file
619
g10/exec.c
Normal file
@ -0,0 +1,619 @@
|
||||
/* exec.c - generic call-a-program code
|
||||
* Copyright (C) 2001, 2002 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#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
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "options.h"
|
||||
#include "memory.h"
|
||||
#include "i18n.h"
|
||||
#include "iobuf.h"
|
||||
#include "util.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 G10ERR_GENERAL;
|
||||
}
|
||||
|
||||
int exec_read(struct exec_info *info) { return G10ERR_GENERAL; }
|
||||
int exec_finish(struct exec_info *info) { return G10ERR_GENERAL; }
|
||||
int set_exec_path(const char *path,int method) { return G10ERR_GENERAL; }
|
||||
|
||||
#else /* ! NO_EXEC */
|
||||
|
||||
#ifndef HAVE_MKDTEMP
|
||||
char *mkdtemp(char *template);
|
||||
#endif
|
||||
|
||||
#if defined (__MINGW32__)
|
||||
/* 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 win_system(const char *command)
|
||||
{
|
||||
PROCESS_INFORMATION pi;
|
||||
STARTUPINFO si;
|
||||
char *string;
|
||||
|
||||
/* We must use a copy of the command as CreateProcess modifies this
|
||||
argument. */
|
||||
string=m_strdup(command);
|
||||
|
||||
memset(&pi,0,sizeof(pi));
|
||||
memset(&si,0,sizeof(si));
|
||||
si.cb=sizeof(si);
|
||||
|
||||
if(!CreateProcess(NULL,string,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi))
|
||||
return -1;
|
||||
|
||||
/* Wait for the child to exit */
|
||||
WaitForSingleObject(pi.hProcess,INFINITE);
|
||||
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
m_free(string);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* method==0 to replace current $PATH, and 1 to append to current
|
||||
$PATH. */
|
||||
int set_exec_path(const char *path,int method)
|
||||
{
|
||||
char *p,*curpath=NULL;
|
||||
size_t curlen=0;
|
||||
|
||||
if(method==1 && (curpath=getenv("PATH")))
|
||||
curlen=strlen(curpath)+1;
|
||||
|
||||
p=m_alloc(5+curlen+strlen(path)+1);
|
||||
strcpy(p,"PATH=");
|
||||
|
||||
if(curpath)
|
||||
{
|
||||
strcat(p,curpath);
|
||||
strcat(p,":");
|
||||
}
|
||||
|
||||
strcat(p,path);
|
||||
|
||||
if(DBG_EXTPROG)
|
||||
log_debug("set_exec_path method %d: %s\n",method,p);
|
||||
|
||||
/* Notice that path is never freed. That is intentional due to the
|
||||
way putenv() works. This leaks a few bytes if we call
|
||||
set_exec_path multiple times. */
|
||||
|
||||
if(putenv(p)!=0)
|
||||
return G10ERR_GENERAL;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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->binary?"tempin" EXTSEP_S "bin":"tempin" EXTSEP_S "txt";
|
||||
|
||||
nameout=info->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 (__MINGW32__)
|
||||
tmp=m_alloc(256);
|
||||
if(GetTempPath(256,tmp)==0)
|
||||
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=m_alloc(strlen(tmp)+strlen(DIRSEP_S)+10+1);
|
||||
|
||||
sprintf(info->tempdir,"%s" DIRSEP_S "gpg-XXXXXX",tmp);
|
||||
|
||||
#if defined (__MINGW32__)
|
||||
m_free(tmp);
|
||||
#endif
|
||||
|
||||
if(mkdtemp(info->tempdir)==NULL)
|
||||
log_error(_("can't create directory `%s': %s\n"),
|
||||
info->tempdir,strerror(errno));
|
||||
else
|
||||
{
|
||||
info->madedir=1;
|
||||
|
||||
info->tempfile_in=m_alloc(strlen(info->tempdir)+
|
||||
strlen(DIRSEP_S)+strlen(namein)+1);
|
||||
sprintf(info->tempfile_in,"%s" DIRSEP_S "%s",info->tempdir,namein);
|
||||
|
||||
if(!info->writeonly)
|
||||
{
|
||||
info->tempfile_out=m_alloc(strlen(info->tempdir)+
|
||||
strlen(DIRSEP_S)+strlen(nameout)+1);
|
||||
sprintf(info->tempfile_out,"%s" DIRSEP_S "%s",info->tempdir,nameout);
|
||||
}
|
||||
}
|
||||
|
||||
return info->madedir?0:G10ERR_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;
|
||||
unsigned int size,len;
|
||||
|
||||
info->use_temp_files=0;
|
||||
info->keep_temp_files=0;
|
||||
|
||||
if(DBG_EXTPROG)
|
||||
log_debug("expanding string \"%s\"\n",args_in);
|
||||
|
||||
size=100;
|
||||
info->command=m_alloc(size);
|
||||
len=0;
|
||||
info->command[0]='\0';
|
||||
|
||||
while(*ch!='\0')
|
||||
{
|
||||
if(*ch=='%')
|
||||
{
|
||||
char *append=NULL;
|
||||
|
||||
ch++;
|
||||
|
||||
switch(*ch)
|
||||
{
|
||||
case 'O':
|
||||
info->keep_temp_files=1;
|
||||
/* fall through */
|
||||
|
||||
case 'o': /* out */
|
||||
if(!info->madedir)
|
||||
{
|
||||
if(make_tempdir(info))
|
||||
goto fail;
|
||||
}
|
||||
append=info->tempfile_out;
|
||||
info->use_temp_files=1;
|
||||
break;
|
||||
|
||||
case 'I':
|
||||
info->keep_temp_files=1;
|
||||
/* fall through */
|
||||
|
||||
case 'i': /* in */
|
||||
if(!info->madedir)
|
||||
{
|
||||
if(make_tempdir(info))
|
||||
goto fail;
|
||||
}
|
||||
append=info->tempfile_in;
|
||||
info->use_temp_files=1;
|
||||
break;
|
||||
|
||||
case '%':
|
||||
append="%";
|
||||
break;
|
||||
}
|
||||
|
||||
if(append)
|
||||
{
|
||||
size_t applen=strlen(append);
|
||||
|
||||
if(applen+len>size-1)
|
||||
{
|
||||
if(applen<100)
|
||||
applen=100;
|
||||
|
||||
size+=applen;
|
||||
info->command=m_realloc(info->command,size);
|
||||
}
|
||||
|
||||
strcat(info->command,append);
|
||||
len+=strlen(append);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(len==size-1) /* leave room for the \0 */
|
||||
{
|
||||
size+=100;
|
||||
info->command=m_realloc(info->command,size);
|
||||
}
|
||||
|
||||
info->command[len++]=*ch;
|
||||
info->command[len]='\0';
|
||||
}
|
||||
|
||||
ch++;
|
||||
}
|
||||
|
||||
if(DBG_EXTPROG)
|
||||
log_debug("args expanded to \"%s\", use %d, keep %d\n",
|
||||
info->command,info->use_temp_files,info->keep_temp_files);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
|
||||
m_free(info->command);
|
||||
info->command=NULL;
|
||||
|
||||
return G10ERR_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=G10ERR_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=m_alloc_clear(sizeof(struct exec_info));
|
||||
|
||||
if(name)
|
||||
(*info)->name=m_strdup(name);
|
||||
(*info)->binary=binary;
|
||||
(*info)->writeonly=writeonly;
|
||||
|
||||
/* Expand the args, if any */
|
||||
if(args_in && expand_args(*info,args_in))
|
||||
goto fail;
|
||||
|
||||
#ifdef EXEC_TEMPFILE_ONLY
|
||||
if(!(*info)->use_temp_files)
|
||||
{
|
||||
log_error(_("this platform requires temp 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)->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)->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. */
|
||||
|
||||
log_error(_("unable to execute %s \"%s\": %s\n"),
|
||||
args_in==NULL?"program":"shell",
|
||||
args_in==NULL?program: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)
|
||||
{
|
||||
close(to[1]);
|
||||
ret=G10ERR_WRITE_FILE;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
close(from[1]);
|
||||
|
||||
(*info)->fromchild=iobuf_fdopen(from[0],"r");
|
||||
if((*info)->fromchild==NULL)
|
||||
{
|
||||
close(from[0]);
|
||||
ret=G10ERR_READ_FILE;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* fd iobufs are cached?! */
|
||||
iobuf_ioctl((*info)->fromchild,3,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 */
|
||||
(*info)->tochild=fopen((*info)->tempfile_in,binary?"wb":"w");
|
||||
if((*info)->tochild==NULL)
|
||||
{
|
||||
log_error(_("can't create `%s': %s\n"),
|
||||
(*info)->tempfile_in,strerror(errno));
|
||||
ret=G10ERR_WRITE_FILE;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret=0;
|
||||
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int exec_read(struct exec_info *info)
|
||||
{
|
||||
int ret=G10ERR_GENERAL;
|
||||
|
||||
fclose(info->tochild);
|
||||
info->tochild=NULL;
|
||||
|
||||
if(info->use_temp_files)
|
||||
{
|
||||
if(DBG_EXTPROG)
|
||||
log_debug("system() command is %s\n",info->command);
|
||||
|
||||
#if defined (__MINGW32__)
|
||||
info->progreturn=win_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->writeonly)
|
||||
{
|
||||
info->fromchild=iobuf_open(info->tempfile_out);
|
||||
if(info->fromchild==NULL)
|
||||
{
|
||||
log_error(_("unable to read external program response: %s\n"),
|
||||
strerror(errno));
|
||||
ret=G10ERR_READ_FILE;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Do not cache this iobuf on close */
|
||||
iobuf_ioctl(info->fromchild,3,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->madedir && !info->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));
|
||||
}
|
||||
|
||||
m_free(info->command);
|
||||
m_free(info->name);
|
||||
m_free(info->tempdir);
|
||||
m_free(info->tempfile_in);
|
||||
m_free(info->tempfile_out);
|
||||
m_free(info);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* ! NO_EXEC */
|
43
g10/exec.h
Normal file
43
g10/exec.h
Normal file
@ -0,0 +1,43 @@
|
||||
/* exec.h
|
||||
* Copyright (C) 2001, 2002 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef _EXEC_H_
|
||||
#define _EXEC_H_
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include "iobuf.h"
|
||||
|
||||
struct exec_info
|
||||
{
|
||||
int progreturn,binary,writeonly,madedir,use_temp_files,keep_temp_files;
|
||||
pid_t child;
|
||||
FILE *tochild;
|
||||
IOBUF 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 method);
|
||||
|
||||
#endif /* !_EXEC_H_ */
|
396
g10/export.c
Normal file
396
g10/export.c
Normal file
@ -0,0 +1,396 @@
|
||||
/* export.c
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "options.h"
|
||||
#include "packet.h"
|
||||
#include "errors.h"
|
||||
#include "keydb.h"
|
||||
#include "memory.h"
|
||||
#include "util.h"
|
||||
#include "main.h"
|
||||
#include "i18n.h"
|
||||
|
||||
static int do_export( STRLIST users, int secret, unsigned int options );
|
||||
static int do_export_stream( IOBUF out, STRLIST users, int secret,
|
||||
KBNODE *keyblock_out, unsigned int options,
|
||||
int *any );
|
||||
|
||||
int
|
||||
parse_export_options(char *str,unsigned int *options)
|
||||
{
|
||||
struct parse_options export_opts[]=
|
||||
{
|
||||
{"include-non-rfc",EXPORT_INCLUDE_NON_RFC},
|
||||
{"include-local-sigs",EXPORT_INCLUDE_LOCAL_SIGS},
|
||||
{"include-attributes",EXPORT_INCLUDE_ATTRIBUTES},
|
||||
{"include-sensitive-revkeys",EXPORT_INCLUDE_SENSITIVE_REVKEYS},
|
||||
{NULL,0}
|
||||
/* add tags for include revoked and disabled? */
|
||||
};
|
||||
|
||||
return parse_options(str,options,export_opts);
|
||||
}
|
||||
|
||||
/****************
|
||||
* Export the public keys (to standard out or --output).
|
||||
* Depending on opt.armor the output is armored.
|
||||
* options are defined in main.h.
|
||||
* If USERS is NULL, the complete ring will be exported. */
|
||||
int
|
||||
export_pubkeys( STRLIST users, unsigned int options )
|
||||
{
|
||||
return do_export( users, 0, options );
|
||||
}
|
||||
|
||||
/****************
|
||||
* Export to an already opened stream; return -1 if no keys have
|
||||
* been exported
|
||||
*/
|
||||
int
|
||||
export_pubkeys_stream( IOBUF out, STRLIST users,
|
||||
KBNODE *keyblock_out, unsigned int options )
|
||||
{
|
||||
int any, rc;
|
||||
|
||||
rc = do_export_stream( out, users, 0, keyblock_out, options, &any );
|
||||
if( !rc && !any )
|
||||
rc = -1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
export_seckeys( STRLIST users )
|
||||
{
|
||||
return do_export( users, 1, 0 );
|
||||
}
|
||||
|
||||
int
|
||||
export_secsubkeys( STRLIST users )
|
||||
{
|
||||
return do_export( users, 2, 0 );
|
||||
}
|
||||
|
||||
static int
|
||||
do_export( STRLIST users, int secret, unsigned int options )
|
||||
{
|
||||
IOBUF out = NULL;
|
||||
int any, rc;
|
||||
armor_filter_context_t afx;
|
||||
compress_filter_context_t zfx;
|
||||
|
||||
memset( &afx, 0, sizeof afx);
|
||||
memset( &zfx, 0, sizeof zfx);
|
||||
|
||||
rc = open_outfile( NULL, 0, &out );
|
||||
if( rc )
|
||||
return rc;
|
||||
|
||||
if( opt.armor ) {
|
||||
afx.what = secret?5:1;
|
||||
iobuf_push_filter( out, armor_filter, &afx );
|
||||
}
|
||||
if( opt.compress_keys && opt.compress )
|
||||
iobuf_push_filter( out, compress_filter, &zfx );
|
||||
rc = do_export_stream( out, users, secret, NULL, options, &any );
|
||||
|
||||
if( rc || !any )
|
||||
iobuf_cancel(out);
|
||||
else
|
||||
iobuf_close(out);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* If keyblock_out is non-NULL, AND the exit code is zero, then it
|
||||
contains a pointer to the first keyblock found and exported. No
|
||||
other keyblocks are exported. The caller must free it. */
|
||||
static int
|
||||
do_export_stream( IOBUF out, STRLIST users, int secret,
|
||||
KBNODE *keyblock_out, unsigned int options, int *any )
|
||||
{
|
||||
int rc = 0;
|
||||
PACKET pkt;
|
||||
KBNODE keyblock = NULL;
|
||||
KBNODE kbctx, node;
|
||||
size_t ndesc, descindex;
|
||||
KEYDB_SEARCH_DESC *desc = NULL;
|
||||
KEYDB_HANDLE kdbhd;
|
||||
STRLIST sl;
|
||||
|
||||
*any = 0;
|
||||
init_packet( &pkt );
|
||||
kdbhd = keydb_new (secret);
|
||||
|
||||
if (!users) {
|
||||
ndesc = 1;
|
||||
desc = m_alloc_clear ( ndesc * sizeof *desc);
|
||||
desc[0].mode = KEYDB_SEARCH_MODE_FIRST;
|
||||
}
|
||||
else {
|
||||
for (ndesc=0, sl=users; sl; sl = sl->next, ndesc++)
|
||||
;
|
||||
desc = m_alloc ( ndesc * sizeof *desc);
|
||||
|
||||
for (ndesc=0, sl=users; sl; sl = sl->next) {
|
||||
if (classify_user_id (sl->d, desc+ndesc))
|
||||
ndesc++;
|
||||
else
|
||||
log_error (_("key `%s' not found: %s\n"),
|
||||
sl->d, g10_errstr (G10ERR_INV_USER_ID));
|
||||
}
|
||||
|
||||
/* it would be nice to see which of the given users did
|
||||
actually match one in the keyring. To implement this we
|
||||
need to have a found flag for each entry in desc and to set
|
||||
this we must check all those entries after a match to mark
|
||||
all matched one - currently we stop at the first match. To
|
||||
do this we need an extra flag to enable this feature so */
|
||||
}
|
||||
|
||||
while (!(rc = keydb_search2 (kdbhd, desc, ndesc, &descindex))) {
|
||||
int sha1_warned=0,skip_until_subkey=0;
|
||||
u32 sk_keyid[2];
|
||||
|
||||
if (!users)
|
||||
desc[0].mode = KEYDB_SEARCH_MODE_NEXT;
|
||||
|
||||
/* read the keyblock */
|
||||
rc = keydb_get_keyblock (kdbhd, &keyblock );
|
||||
if( rc ) {
|
||||
log_error (_("error reading keyblock: %s\n"), g10_errstr(rc) );
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* do not export keys which are incompatible with rfc2440 */
|
||||
if( !(options&EXPORT_INCLUDE_NON_RFC) &&
|
||||
(node = find_kbnode( keyblock, PKT_PUBLIC_KEY )) ) {
|
||||
PKT_public_key *pk = node->pkt->pkt.public_key;
|
||||
if( pk->version == 3 && pk->pubkey_algo > 3 ) {
|
||||
log_info(_("key %08lX: not a rfc2440 key - skipped\n"),
|
||||
(ulong)keyid_from_pk( pk, NULL) );
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
node=find_kbnode( keyblock, PKT_SECRET_KEY );
|
||||
if(node)
|
||||
{
|
||||
PKT_secret_key *sk=node->pkt->pkt.secret_key;
|
||||
|
||||
keyid_from_sk(sk,sk_keyid);
|
||||
|
||||
/* we can't apply GNU mode 1001 on an unprotected key */
|
||||
if( secret == 2 && !sk->is_protected )
|
||||
{
|
||||
log_info(_("key %08lX: not protected - skipped\n"),
|
||||
(ulong)sk_keyid[1]);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* no v3 keys with GNU mode 1001 */
|
||||
if( secret == 2 && sk->version == 3 )
|
||||
{
|
||||
log_info(_("key %08lX: PGP 2.x style key - skipped\n"),
|
||||
(ulong)sk_keyid[1]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* and write it */
|
||||
for( kbctx=NULL; (node = walk_kbnode( keyblock, &kbctx, 0 )); ) {
|
||||
if( skip_until_subkey )
|
||||
{
|
||||
if(node->pkt->pkttype==PKT_PUBLIC_SUBKEY
|
||||
|| node->pkt->pkttype==PKT_SECRET_SUBKEY)
|
||||
skip_until_subkey=0;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
/* don't export any comment packets but those in the
|
||||
* secret keyring */
|
||||
if( !secret && node->pkt->pkttype == PKT_COMMENT )
|
||||
continue;
|
||||
|
||||
/* make sure that ring_trust packets never get exported */
|
||||
if (node->pkt->pkttype == PKT_RING_TRUST)
|
||||
continue;
|
||||
|
||||
/* If exact is set, then we only export what was requested
|
||||
(plus the primary key, if the user didn't specifically
|
||||
request it) */
|
||||
if(desc[descindex].exact
|
||||
&& (node->pkt->pkttype==PKT_PUBLIC_SUBKEY
|
||||
|| node->pkt->pkttype==PKT_SECRET_SUBKEY))
|
||||
{
|
||||
u32 kid[2];
|
||||
byte fpr[MAX_FINGERPRINT_LEN];
|
||||
size_t fprlen;
|
||||
|
||||
switch(desc[descindex].mode)
|
||||
{
|
||||
case KEYDB_SEARCH_MODE_SHORT_KID:
|
||||
case KEYDB_SEARCH_MODE_LONG_KID:
|
||||
if(node->pkt->pkttype==PKT_PUBLIC_SUBKEY)
|
||||
keyid_from_pk(node->pkt->pkt.public_key,kid);
|
||||
else
|
||||
keyid_from_sk(node->pkt->pkt.secret_key,kid);
|
||||
break;
|
||||
|
||||
case KEYDB_SEARCH_MODE_FPR16:
|
||||
case KEYDB_SEARCH_MODE_FPR20:
|
||||
case KEYDB_SEARCH_MODE_FPR:
|
||||
if(node->pkt->pkttype==PKT_PUBLIC_SUBKEY)
|
||||
fingerprint_from_pk(node->pkt->pkt.public_key,
|
||||
fpr,&fprlen);
|
||||
else
|
||||
fingerprint_from_sk(node->pkt->pkt.secret_key,
|
||||
fpr,&fprlen);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch(desc[descindex].mode)
|
||||
{
|
||||
case KEYDB_SEARCH_MODE_SHORT_KID:
|
||||
if (desc[descindex].u.kid[1] != kid[1])
|
||||
skip_until_subkey=1;
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_LONG_KID:
|
||||
if (desc[descindex].u.kid[0] != kid[0]
|
||||
|| desc[descindex].u.kid[1] != kid[1])
|
||||
skip_until_subkey=1;
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_FPR16:
|
||||
if (memcmp (desc[descindex].u.fpr, fpr, 16))
|
||||
skip_until_subkey=1;
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_FPR20:
|
||||
case KEYDB_SEARCH_MODE_FPR:
|
||||
if (memcmp (desc[descindex].u.fpr, fpr, 20))
|
||||
skip_until_subkey=1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if(skip_until_subkey)
|
||||
continue;
|
||||
}
|
||||
|
||||
if( node->pkt->pkttype == PKT_SIGNATURE ) {
|
||||
/* do not export packets which are marked as not exportable */
|
||||
if( !(options&EXPORT_INCLUDE_LOCAL_SIGS) &&
|
||||
!node->pkt->pkt.signature->flags.exportable )
|
||||
continue; /* not exportable */
|
||||
|
||||
/* Do not export packets with a "sensitive" revocation
|
||||
key unless the user wants us to. Note that we do
|
||||
export these when issuing the actual revocation (see
|
||||
revoke.c). */
|
||||
if( !(options&EXPORT_INCLUDE_SENSITIVE_REVKEYS) &&
|
||||
node->pkt->pkt.signature->revkey ) {
|
||||
int i;
|
||||
|
||||
for(i=0;i<node->pkt->pkt.signature->numrevkeys;i++)
|
||||
if(node->pkt->pkt.signature->revkey[i]->class & 0x40)
|
||||
break;
|
||||
|
||||
if(i<node->pkt->pkt.signature->numrevkeys)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't export attribs? */
|
||||
if( !(options&EXPORT_INCLUDE_ATTRIBUTES) &&
|
||||
node->pkt->pkttype == PKT_USER_ID &&
|
||||
node->pkt->pkt.user_id->attrib_data ) {
|
||||
/* Skip until we get to something that is not an attrib
|
||||
or a signature on an attrib */
|
||||
while(kbctx->next && kbctx->next->pkt->pkttype==PKT_SIGNATURE) {
|
||||
kbctx=kbctx->next;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if( secret == 2 && node->pkt->pkttype == PKT_SECRET_KEY ) {
|
||||
/* we don't want to export the secret parts of the
|
||||
* primary key, this is done by using GNU protection mode 1001
|
||||
*/
|
||||
int save_mode = node->pkt->pkt.secret_key->protect.s2k.mode;
|
||||
node->pkt->pkt.secret_key->protect.s2k.mode = 1001;
|
||||
rc = build_packet( out, node->pkt );
|
||||
node->pkt->pkt.secret_key->protect.s2k.mode = save_mode;
|
||||
}
|
||||
else {
|
||||
/* Warn the user if the secret key or any of the secret
|
||||
subkeys are protected with SHA1 and we have
|
||||
simple_sk_checksum set. */
|
||||
if(!sha1_warned && opt.simple_sk_checksum &&
|
||||
(node->pkt->pkttype==PKT_SECRET_KEY ||
|
||||
node->pkt->pkttype==PKT_SECRET_SUBKEY) &&
|
||||
node->pkt->pkt.secret_key->protect.sha1chk)
|
||||
{
|
||||
/* I hope this warning doesn't confuse people. */
|
||||
log_info(_("WARNING: secret key %08lX does not have a "
|
||||
"simple SK checksum\n"),(ulong)sk_keyid[1]);
|
||||
|
||||
sha1_warned=1;
|
||||
}
|
||||
|
||||
rc = build_packet( out, node->pkt );
|
||||
}
|
||||
|
||||
if( rc ) {
|
||||
log_error("build_packet(%d) failed: %s\n",
|
||||
node->pkt->pkttype, g10_errstr(rc) );
|
||||
rc = G10ERR_WRITE_FILE;
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
++*any;
|
||||
if(keyblock_out)
|
||||
{
|
||||
*keyblock_out=keyblock;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( rc == -1 )
|
||||
rc = 0;
|
||||
|
||||
leave:
|
||||
m_free(desc);
|
||||
keydb_release (kdbhd);
|
||||
if(rc || keyblock_out==NULL)
|
||||
release_kbnode( keyblock );
|
||||
if( !*any )
|
||||
log_info(_("WARNING: nothing exported\n"));
|
||||
return rc;
|
||||
}
|
154
g10/filter.h
Normal file
154
g10/filter.h
Normal file
@ -0,0 +1,154 @@
|
||||
/* filter.h
|
||||
* Copyright (C) 1998, 1999, 2000, 2001 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifndef G10_FILTER_H
|
||||
#define G10_FILTER_H
|
||||
|
||||
#include "types.h"
|
||||
#include "cipher.h"
|
||||
|
||||
typedef struct {
|
||||
MD_HANDLE md; /* catch all */
|
||||
MD_HANDLE md2; /* if we want to calculate an alternate hash */
|
||||
size_t maxbuf_size;
|
||||
} md_filter_context_t;
|
||||
|
||||
typedef struct {
|
||||
/* these fields may be initialized */
|
||||
int what; /* what kind of armor headers to write */
|
||||
int only_keyblocks; /* skip all headers but ".... key block" */
|
||||
const char *hdrlines; /* write these headerlines */
|
||||
|
||||
/* these fileds must be initialized to zero */
|
||||
int no_openpgp_data; /* output flag: "No valid OpenPGP data found" */
|
||||
|
||||
/* the following fields must be initialized to zero */
|
||||
int inp_checked; /* set if the input has been checked */
|
||||
int inp_bypass; /* set if the input is not armored */
|
||||
int in_cleartext; /* clear text message */
|
||||
int not_dash_escaped; /* clear text is not dash escaped */
|
||||
int hashes; /* detected hash algorithms */
|
||||
int faked; /* we are faking a literal data packet */
|
||||
int truncated; /* number of truncated lines */
|
||||
int qp_detected;
|
||||
int pgp2mode;
|
||||
|
||||
byte *buffer; /* malloced buffer */
|
||||
unsigned buffer_size; /* and size of this buffer */
|
||||
unsigned buffer_len; /* used length of the buffer */
|
||||
unsigned buffer_pos; /* read position */
|
||||
|
||||
byte radbuf[4];
|
||||
int idx, idx2;
|
||||
u32 crc;
|
||||
|
||||
int status; /* an internal state flag */
|
||||
int cancel;
|
||||
int any_data; /* any valid armored data seen */
|
||||
int pending_lf; /* used together with faked */
|
||||
} armor_filter_context_t;
|
||||
|
||||
struct unarmor_pump_s;
|
||||
typedef struct unarmor_pump_s *UnarmorPump;
|
||||
|
||||
|
||||
struct compress_filter_context_s {
|
||||
int status;
|
||||
void *opaque; /* (used for z_stream) */
|
||||
byte *inbuf;
|
||||
unsigned inbufsize;
|
||||
byte *outbuf;
|
||||
unsigned outbufsize;
|
||||
int algo; /* compress algo */
|
||||
int algo1hack;
|
||||
int new_ctb;
|
||||
void (*release)(struct compress_filter_context_s*);
|
||||
};
|
||||
typedef struct compress_filter_context_s compress_filter_context_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
DEK *dek;
|
||||
u32 datalen;
|
||||
CIPHER_HANDLE cipher_hd;
|
||||
int header;
|
||||
MD_HANDLE mdc_hash;
|
||||
byte enchash[20];
|
||||
int create_mdc; /* flag will be set by the cipher filter */
|
||||
} cipher_filter_context_t;
|
||||
|
||||
|
||||
|
||||
typedef struct {
|
||||
byte *buffer; /* malloced buffer */
|
||||
unsigned buffer_size; /* and size of this buffer */
|
||||
unsigned buffer_len; /* used length of the buffer */
|
||||
unsigned buffer_pos; /* read position */
|
||||
int truncated; /* number of truncated lines */
|
||||
int not_dash_escaped;
|
||||
int escape_from;
|
||||
MD_HANDLE md;
|
||||
int pending_lf;
|
||||
int pending_esc;
|
||||
} text_filter_context_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
char *what; /* description */
|
||||
u32 last_time; /* last time reported */
|
||||
unsigned long last; /* last amount reported */
|
||||
unsigned long offset; /* current amount */
|
||||
unsigned long total; /* total amount */
|
||||
} progress_filter_context_t;
|
||||
|
||||
/* encrypt_filter_context_t defined in main.h */
|
||||
|
||||
/*-- mdfilter.c --*/
|
||||
int md_filter( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len);
|
||||
void free_md_filter_context( md_filter_context_t *mfx );
|
||||
|
||||
/*-- armor.c --*/
|
||||
int use_armor_filter( IOBUF a );
|
||||
int armor_filter( void *opaque, int control,
|
||||
IOBUF chain, byte *buf, size_t *ret_len);
|
||||
UnarmorPump unarmor_pump_new (void);
|
||||
void unarmor_pump_release (UnarmorPump x);
|
||||
int unarmor_pump (UnarmorPump x, int c);
|
||||
|
||||
/*-- compress.c --*/
|
||||
int compress_filter( void *opaque, int control,
|
||||
IOBUF chain, byte *buf, size_t *ret_len);
|
||||
|
||||
/*-- cipher.c --*/
|
||||
int cipher_filter( void *opaque, int control,
|
||||
IOBUF chain, byte *buf, size_t *ret_len);
|
||||
|
||||
/*-- textfilter.c --*/
|
||||
int text_filter( void *opaque, int control,
|
||||
IOBUF chain, byte *buf, size_t *ret_len);
|
||||
int copy_clearsig_text( IOBUF out, IOBUF inp, MD_HANDLE md,
|
||||
int escape_dash, int escape_from, int pgp2mode );
|
||||
|
||||
/*-- progress.c --*/
|
||||
int progress_filter (void *opaque, int control,
|
||||
IOBUF a, byte *buf, size_t *ret_len);
|
||||
void handle_progress (progress_filter_context_t *pfx,
|
||||
IOBUF inp, const char *name);
|
||||
|
||||
#endif /*G10_FILTER_H*/
|
542
g10/free-packet.c
Normal file
542
g10/free-packet.c
Normal file
@ -0,0 +1,542 @@
|
||||
/* free-packet.c - cleanup stuff for packets
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "packet.h"
|
||||
#include "iobuf.h"
|
||||
#include "mpi.h"
|
||||
#include "util.h"
|
||||
#include "cipher.h"
|
||||
#include "memory.h"
|
||||
#include "options.h"
|
||||
|
||||
void
|
||||
free_symkey_enc( PKT_symkey_enc *enc )
|
||||
{
|
||||
m_free(enc);
|
||||
}
|
||||
|
||||
void
|
||||
free_pubkey_enc( PKT_pubkey_enc *enc )
|
||||
{
|
||||
int n, i;
|
||||
n = pubkey_get_nenc( enc->pubkey_algo );
|
||||
if( !n )
|
||||
mpi_free(enc->data[0]);
|
||||
for(i=0; i < n; i++ )
|
||||
mpi_free( enc->data[i] );
|
||||
m_free(enc);
|
||||
}
|
||||
|
||||
void
|
||||
free_seckey_enc( PKT_signature *sig )
|
||||
{
|
||||
int n, i;
|
||||
|
||||
n = pubkey_get_nsig( sig->pubkey_algo );
|
||||
if( !n )
|
||||
mpi_free(sig->data[0]);
|
||||
for(i=0; i < n; i++ )
|
||||
mpi_free( sig->data[i] );
|
||||
|
||||
m_free(sig->revkey);
|
||||
m_free(sig->hashed);
|
||||
m_free(sig->unhashed);
|
||||
m_free(sig);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
release_public_key_parts( PKT_public_key *pk )
|
||||
{
|
||||
int n, i;
|
||||
n = pubkey_get_npkey( pk->pubkey_algo );
|
||||
if( !n )
|
||||
mpi_free(pk->pkey[0]);
|
||||
for(i=0; i < n; i++ ) {
|
||||
mpi_free( pk->pkey[i] );
|
||||
pk->pkey[i] = NULL;
|
||||
}
|
||||
if (pk->prefs) {
|
||||
m_free (pk->prefs);
|
||||
pk->prefs = NULL;
|
||||
}
|
||||
if (pk->user_id) {
|
||||
free_user_id (pk->user_id);
|
||||
pk->user_id = NULL;
|
||||
}
|
||||
if (pk->revkey) {
|
||||
m_free(pk->revkey);
|
||||
pk->revkey=NULL;
|
||||
pk->numrevkeys=0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
free_public_key( PKT_public_key *pk )
|
||||
{
|
||||
release_public_key_parts( pk );
|
||||
m_free(pk);
|
||||
}
|
||||
|
||||
|
||||
static subpktarea_t *
|
||||
cp_subpktarea (subpktarea_t *s )
|
||||
{
|
||||
subpktarea_t *d;
|
||||
|
||||
if( !s )
|
||||
return NULL;
|
||||
d = m_alloc (sizeof (*d) + s->size - 1 );
|
||||
d->size = s->size;
|
||||
d->len = s->len;
|
||||
memcpy (d->data, s->data, s->len);
|
||||
return d;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a copy of the preferences
|
||||
*/
|
||||
prefitem_t *
|
||||
copy_prefs (const prefitem_t *prefs)
|
||||
{
|
||||
size_t n;
|
||||
prefitem_t *new;
|
||||
|
||||
if (!prefs)
|
||||
return NULL;
|
||||
|
||||
for (n=0; prefs[n].type; n++)
|
||||
;
|
||||
new = m_alloc ( sizeof (*new) * (n+1));
|
||||
for (n=0; prefs[n].type; n++) {
|
||||
new[n].type = prefs[n].type;
|
||||
new[n].value = prefs[n].value;
|
||||
}
|
||||
new[n].type = PREFTYPE_NONE;
|
||||
new[n].value = 0;
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
|
||||
PKT_public_key *
|
||||
copy_public_key ( PKT_public_key *d, PKT_public_key *s)
|
||||
{
|
||||
int n, i;
|
||||
|
||||
if( !d )
|
||||
d = m_alloc(sizeof *d);
|
||||
memcpy( d, s, sizeof *d );
|
||||
d->user_id = scopy_user_id (s->user_id);
|
||||
d->prefs = copy_prefs (s->prefs);
|
||||
n = pubkey_get_npkey( s->pubkey_algo );
|
||||
if( !n )
|
||||
d->pkey[0] = mpi_copy(s->pkey[0]);
|
||||
else {
|
||||
for(i=0; i < n; i++ )
|
||||
d->pkey[i] = mpi_copy( s->pkey[i] );
|
||||
}
|
||||
if( !s->revkey && s->numrevkeys )
|
||||
BUG();
|
||||
if( s->numrevkeys ) {
|
||||
d->revkey = m_alloc(sizeof(struct revocation_key)*s->numrevkeys);
|
||||
memcpy(d->revkey,s->revkey,sizeof(struct revocation_key)*s->numrevkeys);
|
||||
}
|
||||
else
|
||||
d->revkey = NULL;
|
||||
return d;
|
||||
}
|
||||
|
||||
/****************
|
||||
* Replace all common parts of a sk by the one from the public key.
|
||||
* This is a hack and a better solution will be to just store the real secret
|
||||
* parts somewhere and don't duplicate all the other stuff.
|
||||
*/
|
||||
void
|
||||
copy_public_parts_to_secret_key( PKT_public_key *pk, PKT_secret_key *sk )
|
||||
{
|
||||
sk->expiredate = pk->expiredate;
|
||||
sk->pubkey_algo = pk->pubkey_algo;
|
||||
sk->pubkey_usage= pk->pubkey_usage;
|
||||
sk->req_usage = pk->req_usage;
|
||||
sk->req_algo = pk->req_algo;
|
||||
sk->has_expired = pk->has_expired;
|
||||
sk->is_revoked = pk->is_revoked;
|
||||
sk->is_valid = pk->is_valid;
|
||||
sk->main_keyid[0]= pk->main_keyid[0];
|
||||
sk->main_keyid[1]= pk->main_keyid[1];
|
||||
sk->keyid[0] = pk->keyid[0];
|
||||
sk->keyid[1] = pk->keyid[1];
|
||||
}
|
||||
|
||||
PKT_signature *
|
||||
copy_signature( PKT_signature *d, PKT_signature *s )
|
||||
{
|
||||
int n, i;
|
||||
|
||||
if( !d )
|
||||
d = m_alloc(sizeof *d);
|
||||
memcpy( d, s, sizeof *d );
|
||||
n = pubkey_get_nsig( s->pubkey_algo );
|
||||
if( !n )
|
||||
d->data[0] = mpi_copy(s->data[0]);
|
||||
else {
|
||||
for(i=0; i < n; i++ )
|
||||
d->data[i] = mpi_copy( s->data[i] );
|
||||
}
|
||||
d->hashed = cp_subpktarea (s->hashed);
|
||||
d->unhashed = cp_subpktarea (s->unhashed);
|
||||
if(s->numrevkeys)
|
||||
{
|
||||
d->revkey=NULL;
|
||||
d->numrevkeys=0;
|
||||
parse_revkeys(d);
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* shallow copy of the user ID
|
||||
*/
|
||||
PKT_user_id *
|
||||
scopy_user_id (PKT_user_id *s)
|
||||
{
|
||||
if (s)
|
||||
s->ref++;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
release_secret_key_parts( PKT_secret_key *sk )
|
||||
{
|
||||
int n, i;
|
||||
|
||||
n = pubkey_get_nskey( sk->pubkey_algo );
|
||||
if( !n )
|
||||
mpi_free(sk->skey[0]);
|
||||
for(i=0; i < n; i++ ) {
|
||||
mpi_free( sk->skey[i] );
|
||||
sk->skey[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
free_secret_key( PKT_secret_key *sk )
|
||||
{
|
||||
release_secret_key_parts( sk );
|
||||
m_free(sk);
|
||||
}
|
||||
|
||||
PKT_secret_key *
|
||||
copy_secret_key( PKT_secret_key *d, PKT_secret_key *s )
|
||||
{
|
||||
int n, i;
|
||||
|
||||
if( !d )
|
||||
d = m_alloc(sizeof *d);
|
||||
memcpy( d, s, sizeof *d );
|
||||
n = pubkey_get_nskey( s->pubkey_algo );
|
||||
if( !n )
|
||||
d->skey[0] = mpi_copy(s->skey[0]);
|
||||
else {
|
||||
for(i=0; i < n; i++ )
|
||||
d->skey[i] = mpi_copy( s->skey[i] );
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
void
|
||||
free_comment( PKT_comment *rem )
|
||||
{
|
||||
m_free(rem);
|
||||
}
|
||||
|
||||
void
|
||||
free_attributes(PKT_user_id *uid)
|
||||
{
|
||||
m_free(uid->attribs);
|
||||
m_free(uid->attrib_data);
|
||||
|
||||
uid->attribs=NULL;
|
||||
uid->attrib_data=NULL;
|
||||
uid->attrib_len=0;
|
||||
}
|
||||
|
||||
void
|
||||
free_user_id (PKT_user_id *uid)
|
||||
{
|
||||
assert (uid->ref > 0);
|
||||
if (--uid->ref)
|
||||
return;
|
||||
|
||||
free_attributes(uid);
|
||||
m_free (uid->prefs);
|
||||
m_free (uid->namehash);
|
||||
m_free (uid);
|
||||
}
|
||||
|
||||
void
|
||||
free_compressed( PKT_compressed *zd )
|
||||
{
|
||||
if( zd->buf ) { /* have to skip some bytes */
|
||||
/* don't have any information about the length, so
|
||||
* we assume this is the last packet */
|
||||
while( iobuf_read( zd->buf, NULL, 1<<30 ) != -1 )
|
||||
;
|
||||
}
|
||||
m_free(zd);
|
||||
}
|
||||
|
||||
void
|
||||
free_encrypted( PKT_encrypted *ed )
|
||||
{
|
||||
if( ed->buf ) { /* have to skip some bytes */
|
||||
if( iobuf_in_block_mode(ed->buf) ) {
|
||||
while( iobuf_read( ed->buf, NULL, 1<<30 ) != -1 )
|
||||
;
|
||||
}
|
||||
else {
|
||||
while( ed->len ) { /* skip the packet */
|
||||
int n = iobuf_read( ed->buf, NULL, ed->len );
|
||||
if( n == -1 )
|
||||
ed->len = 0;
|
||||
else
|
||||
ed->len -= n;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_free(ed);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
free_plaintext( PKT_plaintext *pt )
|
||||
{
|
||||
if( pt->buf ) { /* have to skip some bytes */
|
||||
if( iobuf_in_block_mode(pt->buf) ) {
|
||||
while( iobuf_read( pt->buf, NULL, 1<<30 ) != -1 )
|
||||
;
|
||||
}
|
||||
else {
|
||||
while( pt->len ) { /* skip the packet */
|
||||
int n = iobuf_read( pt->buf, NULL, pt->len );
|
||||
if( n == -1 )
|
||||
pt->len = 0;
|
||||
else
|
||||
pt->len -= n;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_free(pt);
|
||||
}
|
||||
|
||||
/****************
|
||||
* Free the packet in pkt.
|
||||
*/
|
||||
void
|
||||
free_packet( PACKET *pkt )
|
||||
{
|
||||
if( !pkt || !pkt->pkt.generic )
|
||||
return;
|
||||
|
||||
if( DBG_MEMORY )
|
||||
log_debug("free_packet() type=%d\n", pkt->pkttype );
|
||||
|
||||
switch( pkt->pkttype ) {
|
||||
case PKT_SIGNATURE:
|
||||
free_seckey_enc( pkt->pkt.signature );
|
||||
break;
|
||||
case PKT_PUBKEY_ENC:
|
||||
free_pubkey_enc( pkt->pkt.pubkey_enc );
|
||||
break;
|
||||
case PKT_SYMKEY_ENC:
|
||||
free_symkey_enc( pkt->pkt.symkey_enc );
|
||||
break;
|
||||
case PKT_PUBLIC_KEY:
|
||||
case PKT_PUBLIC_SUBKEY:
|
||||
free_public_key( pkt->pkt.public_key );
|
||||
break;
|
||||
case PKT_SECRET_KEY:
|
||||
case PKT_SECRET_SUBKEY:
|
||||
free_secret_key( pkt->pkt.secret_key );
|
||||
break;
|
||||
case PKT_COMMENT:
|
||||
free_comment( pkt->pkt.comment );
|
||||
break;
|
||||
case PKT_USER_ID:
|
||||
free_user_id( pkt->pkt.user_id );
|
||||
break;
|
||||
case PKT_COMPRESSED:
|
||||
free_compressed( pkt->pkt.compressed);
|
||||
break;
|
||||
case PKT_ENCRYPTED:
|
||||
case PKT_ENCRYPTED_MDC:
|
||||
free_encrypted( pkt->pkt.encrypted );
|
||||
break;
|
||||
case PKT_PLAINTEXT:
|
||||
free_plaintext( pkt->pkt.plaintext );
|
||||
break;
|
||||
default:
|
||||
m_free( pkt->pkt.generic );
|
||||
break;
|
||||
}
|
||||
pkt->pkt.generic = NULL;
|
||||
}
|
||||
|
||||
/****************
|
||||
* returns 0 if they match.
|
||||
*/
|
||||
int
|
||||
cmp_public_keys( PKT_public_key *a, PKT_public_key *b )
|
||||
{
|
||||
int n, i;
|
||||
|
||||
if( a->timestamp != b->timestamp )
|
||||
return -1;
|
||||
if( a->version < 4 && a->expiredate != b->expiredate )
|
||||
return -1;
|
||||
if( a->pubkey_algo != b->pubkey_algo )
|
||||
return -1;
|
||||
|
||||
n = pubkey_get_npkey( b->pubkey_algo );
|
||||
if( !n )
|
||||
return -1; /* can't compare due to unknown algorithm */
|
||||
for(i=0; i < n; i++ ) {
|
||||
if( mpi_cmp( a->pkey[i], b->pkey[i] ) )
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************
|
||||
* Returns 0 if they match.
|
||||
* We only compare the public parts.
|
||||
*/
|
||||
int
|
||||
cmp_secret_keys( PKT_secret_key *a, PKT_secret_key *b )
|
||||
{
|
||||
int n, i;
|
||||
|
||||
if( a->timestamp != b->timestamp )
|
||||
return -1;
|
||||
if( a->version < 4 && a->expiredate != b->expiredate )
|
||||
return -1;
|
||||
if( a->pubkey_algo != b->pubkey_algo )
|
||||
return -1;
|
||||
|
||||
n = pubkey_get_npkey( b->pubkey_algo );
|
||||
if( !n )
|
||||
return -1; /* can't compare due to unknown algorithm */
|
||||
for(i=0; i < n; i++ ) {
|
||||
if( mpi_cmp( a->skey[i], b->skey[i] ) )
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************
|
||||
* Returns 0 if they match.
|
||||
*/
|
||||
int
|
||||
cmp_public_secret_key( PKT_public_key *pk, PKT_secret_key *sk )
|
||||
{
|
||||
int n, i;
|
||||
|
||||
if( pk->timestamp != sk->timestamp )
|
||||
return -1;
|
||||
if( pk->version < 4 && pk->expiredate != sk->expiredate )
|
||||
return -1;
|
||||
if( pk->pubkey_algo != sk->pubkey_algo )
|
||||
return -1;
|
||||
|
||||
n = pubkey_get_npkey( pk->pubkey_algo );
|
||||
if( !n )
|
||||
return -1; /* can't compare due to unknown algorithm */
|
||||
for(i=0; i < n; i++ ) {
|
||||
if( mpi_cmp( pk->pkey[i] , sk->skey[i] ) )
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
cmp_signatures( PKT_signature *a, PKT_signature *b )
|
||||
{
|
||||
int n, i;
|
||||
|
||||
if( a->keyid[0] != b->keyid[0] )
|
||||
return -1;
|
||||
if( a->keyid[1] != b->keyid[1] )
|
||||
return -1;
|
||||
if( a->pubkey_algo != b->pubkey_algo )
|
||||
return -1;
|
||||
|
||||
n = pubkey_get_nsig( a->pubkey_algo );
|
||||
if( !n )
|
||||
return -1; /* can't compare due to unknown algorithm */
|
||||
for(i=0; i < n; i++ ) {
|
||||
if( mpi_cmp( a->data[i] , b->data[i] ) )
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
* Returns: true if the user ids do not match
|
||||
*/
|
||||
int
|
||||
cmp_user_ids( PKT_user_id *a, PKT_user_id *b )
|
||||
{
|
||||
int res=1;
|
||||
|
||||
if( a == b )
|
||||
return 0;
|
||||
|
||||
if( a->attrib_data && b->attrib_data )
|
||||
{
|
||||
res = a->attrib_len - b->attrib_len;
|
||||
if( !res )
|
||||
res = memcmp( a->attrib_data, b->attrib_data, a->attrib_len );
|
||||
}
|
||||
else if( !a->attrib_data && !b->attrib_data )
|
||||
{
|
||||
res = a->len - b->len;
|
||||
if( !res )
|
||||
res = memcmp( a->name, b->name, a->len );
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
2611
g10/getkey.c
Normal file
2611
g10/getkey.c
Normal file
File diff suppressed because it is too large
Load Diff
396
g10/gpgv.c
Normal file
396
g10/gpgv.c
Normal file
@ -0,0 +1,396 @@
|
||||
/* gpgv.c - The GnuPG signature verify utility
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
#ifdef HAVE_DOSISH_SYSTEM
|
||||
#include <fcntl.h> /* for setmode() */
|
||||
#endif
|
||||
|
||||
#define INCLUDED_BY_MAIN_MODULE 1
|
||||
#include "packet.h"
|
||||
#include "iobuf.h"
|
||||
#include "memory.h"
|
||||
#include "util.h"
|
||||
#include "main.h"
|
||||
#include "options.h"
|
||||
#include "keydb.h"
|
||||
#include "trustdb.h"
|
||||
#include "mpi.h"
|
||||
#include "cipher.h"
|
||||
#include "filter.h"
|
||||
#include "ttyio.h"
|
||||
#include "i18n.h"
|
||||
#include "status.h"
|
||||
#include "g10defs.h"
|
||||
|
||||
|
||||
enum cmd_and_opt_values { aNull = 0,
|
||||
oQuiet = 'q',
|
||||
oVerbose = 'v',
|
||||
oBatch = 500,
|
||||
oKeyring,
|
||||
oIgnoreTimeConflict,
|
||||
oStatusFD,
|
||||
oLoggerFD,
|
||||
oHomedir,
|
||||
aTest };
|
||||
|
||||
|
||||
static ARGPARSE_OPTS opts[] = {
|
||||
|
||||
{ 301, NULL, 0, N_("@\nOptions:\n ") },
|
||||
|
||||
{ oVerbose, "verbose", 0, N_("verbose") },
|
||||
{ oQuiet, "quiet", 0, N_("be somewhat more quiet") },
|
||||
{ oKeyring, "keyring" ,2, N_("take the keys from this keyring")},
|
||||
{ oIgnoreTimeConflict, "ignore-time-conflict", 0,
|
||||
N_("make timestamp conflicts only a warning") },
|
||||
{ oStatusFD, "status-fd" ,1, N_("|FD|write status info to this FD") },
|
||||
{ oLoggerFD, "logger-fd",1, "@" },
|
||||
{ oHomedir, "homedir", 2, "@" }, /* defaults to "~/.gnupg" */
|
||||
|
||||
{0} };
|
||||
|
||||
|
||||
|
||||
int g10_errors_seen = 0;
|
||||
|
||||
#ifdef __riscos__
|
||||
RISCOS_GLOBAL_STATICS("GnuPG (gpgv) Heap")
|
||||
#endif /* __riscos__ */
|
||||
|
||||
const char *
|
||||
strusage( int level )
|
||||
{
|
||||
const char *p;
|
||||
switch( level ) {
|
||||
case 11: p = "gpgv (GnuPG)";
|
||||
break;
|
||||
case 13: p = VERSION; break;
|
||||
case 17: p = PRINTABLE_OS_NAME; break;
|
||||
case 19: p =
|
||||
_("Please report bugs to <gnupg-bugs@gnu.org>.\n");
|
||||
break;
|
||||
case 1:
|
||||
case 40: p =
|
||||
_("Usage: gpgv [options] [files] (-h for help)");
|
||||
break;
|
||||
case 41: p =
|
||||
_("Syntax: gpg [options] [files]\n"
|
||||
"Check signatures against known trusted keys\n");
|
||||
break;
|
||||
|
||||
default: p = default_strusage(level);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static void
|
||||
i18n_init(void)
|
||||
{
|
||||
#ifdef USE_SIMPLE_GETTEXT
|
||||
set_gettext_file( PACKAGE );
|
||||
#else
|
||||
#ifdef ENABLE_NLS
|
||||
#ifdef HAVE_LC_MESSAGES
|
||||
setlocale( LC_TIME, "" );
|
||||
setlocale( LC_MESSAGES, "" );
|
||||
#else
|
||||
setlocale( LC_ALL, "" );
|
||||
#endif
|
||||
bindtextdomain( PACKAGE, G10_LOCALEDIR );
|
||||
textdomain( PACKAGE );
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main( int argc, char **argv )
|
||||
{
|
||||
ARGPARSE_ARGS pargs;
|
||||
int rc=0;
|
||||
STRLIST sl;
|
||||
STRLIST nrings=NULL;
|
||||
unsigned configlineno;
|
||||
|
||||
#ifdef __riscos__
|
||||
riscos_global_defaults();
|
||||
#endif /* __riscos__ */
|
||||
|
||||
log_set_name("gpgv");
|
||||
init_signals();
|
||||
i18n_init();
|
||||
opt.command_fd = -1; /* no command fd */
|
||||
opt.pgp2_workarounds = 1;
|
||||
opt.keyserver_options.auto_key_retrieve = 1;
|
||||
opt.trust_model = TM_ALWAYS;
|
||||
opt.batch = 1;
|
||||
|
||||
#if defined (__MINGW32__)
|
||||
opt.homedir = read_w32_registry_string( NULL, "Software\\GNU\\GnuPG", "HomeDir" );
|
||||
#else
|
||||
opt.homedir = getenv("GNUPGHOME");
|
||||
#endif
|
||||
if( !opt.homedir || !*opt.homedir ) {
|
||||
opt.homedir = GNUPG_HOMEDIR;
|
||||
}
|
||||
tty_no_terminal(1);
|
||||
tty_batchmode(1);
|
||||
disable_dotlock();
|
||||
|
||||
set_native_charset (NULL); /* Try to auto set the character set */
|
||||
|
||||
pargs.argc = &argc;
|
||||
pargs.argv = &argv;
|
||||
pargs.flags= 1; /* do not remove the args */
|
||||
while( optfile_parse( NULL, NULL, &configlineno, &pargs, opts) ) {
|
||||
switch( pargs.r_opt ) {
|
||||
case oQuiet: opt.quiet = 1; break;
|
||||
case oVerbose: g10_opt_verbose++;
|
||||
opt.verbose++; opt.list_sigs=1; break;
|
||||
case oKeyring: append_to_strlist( &nrings, pargs.r.ret_str); break;
|
||||
case oStatusFD: set_status_fd( pargs.r.ret_int ); break;
|
||||
case oLoggerFD: log_set_logfile( NULL, pargs.r.ret_int ); break;
|
||||
case oHomedir: opt.homedir = pargs.r.ret_str; break;
|
||||
case oIgnoreTimeConflict: opt.ignore_time_conflict = 1; break;
|
||||
default : pargs.err = 2; break;
|
||||
}
|
||||
}
|
||||
|
||||
if( log_get_errorcount(0) )
|
||||
g10_exit(2);
|
||||
|
||||
g10_opt_homedir = opt.homedir;
|
||||
|
||||
if( opt.verbose > 1 )
|
||||
set_packet_list_mode(1);
|
||||
|
||||
if( !nrings ) /* no keyring given: use default one */
|
||||
keydb_add_resource ("trustedkeys" EXTSEP_S "gpg", 0, 0);
|
||||
for(sl = nrings; sl; sl = sl->next )
|
||||
keydb_add_resource (sl->d, 0, 0 );
|
||||
|
||||
FREE_STRLIST(nrings);
|
||||
|
||||
if( (rc = verify_signatures( argc, argv ) ))
|
||||
log_error("verify signatures failed: %s\n", g10_errstr(rc) );
|
||||
|
||||
/* cleanup */
|
||||
g10_exit(0);
|
||||
return 8; /*NEVER REACHED*/
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
g10_exit( int rc )
|
||||
{
|
||||
rc = rc? rc : log_get_errorcount(0)? 2 :
|
||||
g10_errors_seen? 1 : 0;
|
||||
exit(rc );
|
||||
}
|
||||
|
||||
|
||||
/* Stub:
|
||||
* We have to override the trustcheck from pkclist.c becuase
|
||||
* this utility assumes that all keys in the keyring are trustworthy
|
||||
*/
|
||||
int
|
||||
check_signatures_trust( PKT_signature *sig )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Stub:
|
||||
* We don't have the trustdb , so we have to provide some stub functions
|
||||
* instead
|
||||
*/
|
||||
|
||||
int
|
||||
cache_disabled_value(PKT_public_key *pk)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
get_validity_info (PKT_public_key *pk, PKT_user_id *uid)
|
||||
{
|
||||
return '?';
|
||||
}
|
||||
|
||||
unsigned int
|
||||
get_validity (PKT_public_key *pk, PKT_user_id *uid)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *
|
||||
trust_value_to_string (unsigned int value)
|
||||
{
|
||||
return "err";
|
||||
}
|
||||
|
||||
/* Stub: */
|
||||
int
|
||||
get_ownertrust_info (PKT_public_key *pk)
|
||||
{
|
||||
return '?';
|
||||
}
|
||||
|
||||
unsigned int
|
||||
get_ownertrust (PKT_public_key *pk)
|
||||
{
|
||||
return TRUST_UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
/* Stub:
|
||||
* Because we only work with trusted keys, it does not make sense to
|
||||
* get them from a keyserver
|
||||
*/
|
||||
int
|
||||
keyserver_import_keyid( u32 *keyid, void *dummy )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Stub:
|
||||
* No encryption here but mainproc links to these functions.
|
||||
*/
|
||||
int
|
||||
get_session_key( PKT_pubkey_enc *k, DEK *dek )
|
||||
{
|
||||
return G10ERR_GENERAL;
|
||||
}
|
||||
/* Stub: */
|
||||
int
|
||||
get_override_session_key( DEK *dek, const char *string )
|
||||
{
|
||||
return G10ERR_GENERAL;
|
||||
}
|
||||
/* Stub: */
|
||||
int
|
||||
decrypt_data( void *procctx, PKT_encrypted *ed, DEK *dek )
|
||||
{
|
||||
return G10ERR_GENERAL;
|
||||
}
|
||||
|
||||
|
||||
/* Stub:
|
||||
* No interactive commnds, so we don't need the helptexts
|
||||
*/
|
||||
void
|
||||
display_online_help( const char *keyword )
|
||||
{
|
||||
}
|
||||
|
||||
/* Stub:
|
||||
* We don't use secret keys, but getkey.c links to this
|
||||
*/
|
||||
int
|
||||
check_secret_key( PKT_secret_key *sk, int n )
|
||||
{
|
||||
return G10ERR_GENERAL;
|
||||
}
|
||||
|
||||
/* Stub:
|
||||
* No secret key, so no passphrase needed
|
||||
*/
|
||||
DEK *
|
||||
passphrase_to_dek( u32 *keyid, int pubkey_algo,
|
||||
int cipher_algo, STRING2KEY *s2k, int mode,
|
||||
const char *tmp, int *canceled)
|
||||
{
|
||||
if (canceled)
|
||||
*canceled = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Stubs to avoid linking to photoid.c */
|
||||
void show_photos(const struct user_attribute *attrs,int count,PKT_public_key *pk) {}
|
||||
int parse_image_header(const struct user_attribute *attr,byte *type,u32 *len) {return 0;}
|
||||
char *image_type_to_string(byte type,int string) {return NULL;}
|
||||
|
||||
/* Stubs to void linking to ../cipher/cipher.c */
|
||||
int string_to_cipher_algo( const char *string ) { return 0; }
|
||||
const char *cipher_algo_to_string( int algo ) { return "?";}
|
||||
void disable_cipher_algo( int algo ) {}
|
||||
int check_cipher_algo( int algo ) { return -1;}
|
||||
unsigned int cipher_get_keylen( int algo ) { return 0; }
|
||||
unsigned int cipher_get_blocksize( int algo ) {return 0;}
|
||||
CIPHER_HANDLE cipher_open( int algo, int mode, int secure ) { return NULL;}
|
||||
void cipher_close( CIPHER_HANDLE c ) {}
|
||||
int cipher_setkey( CIPHER_HANDLE c, byte *key, unsigned keylen ) { return -1;}
|
||||
void cipher_setiv( CIPHER_HANDLE c, const byte *iv, unsigned ivlen ){}
|
||||
void cipher_encrypt( CIPHER_HANDLE c, byte *outbuf,
|
||||
byte *inbuf, unsigned nbytes ) {}
|
||||
void cipher_decrypt( CIPHER_HANDLE c, byte *outbuf,
|
||||
byte *inbuf, unsigned nbytes ) {}
|
||||
void cipher_sync( CIPHER_HANDLE c ) {}
|
||||
|
||||
/* Stubs to avoid linking to ../cipher/random.c */
|
||||
void random_dump_stats(void) {}
|
||||
int quick_random_gen( int onoff ) { return -1;}
|
||||
void randomize_buffer( byte *buffer, size_t length, int level ) {}
|
||||
int random_is_faked() { return -1;}
|
||||
byte *get_random_bits( size_t nbits, int level, int secure ) { return NULL;}
|
||||
void set_random_seed_file( const char *name ) {}
|
||||
void update_random_seed_file() {}
|
||||
void fast_random_poll() {}
|
||||
|
||||
/* Stubs to avoid linking of ../cipher/primegen.c */
|
||||
void register_primegen_progress ( void (*cb)( void *, int), void *cb_data ) {}
|
||||
MPI generate_secret_prime( unsigned nbits ) { return NULL;}
|
||||
MPI generate_public_prime( unsigned nbits ) { return NULL;}
|
||||
MPI generate_elg_prime( int mode, unsigned pbits, unsigned qbits,
|
||||
MPI g, MPI **ret_factors ) { return NULL;}
|
||||
|
||||
/* Do not link to ../cipher/rndlinux.c */
|
||||
void rndlinux_constructor(void) {}
|
||||
|
||||
|
||||
/* Stubs to avoid linking to ../util/ttyio.c */
|
||||
int tty_batchmode( int onoff ) { return 0; }
|
||||
void tty_printf( const char *fmt, ... ) { }
|
||||
void tty_print_string( byte *p, size_t n ) { }
|
||||
void tty_print_utf8_string( byte *p, size_t n ) {}
|
||||
void tty_print_utf8_string2( byte *p, size_t n, size_t max_n ) {}
|
||||
char *tty_get( const char *prompt ) { return NULL;}
|
||||
char *tty_get_hidden( const char *prompt ) {return NULL; }
|
||||
void tty_kill_prompt(void) {}
|
||||
int tty_get_answer_is_yes( const char *prompt ) {return 0;}
|
||||
int tty_no_terminal(int onoff) {return 0;}
|
||||
|
||||
/* We do not do any locking, so use these stubs here */
|
||||
void disable_dotlock(void) {}
|
||||
DOTLOCK create_dotlock( const char *file_to_lock ) { return NULL; }
|
||||
int make_dotlock( DOTLOCK h, long timeout ) { return 0;}
|
||||
int release_dotlock( DOTLOCK h ) {return 0;}
|
||||
void remove_lockfiles(void) {}
|
1879
g10/import.c
Normal file
1879
g10/import.c
Normal file
File diff suppressed because it is too large
Load Diff
399
g10/kbnode.c
Normal file
399
g10/kbnode.c
Normal file
@ -0,0 +1,399 @@
|
||||
/* kbnode.c - keyblock node utility functions
|
||||
* Copyright (C) 1998, 1999, 2000, 2001 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "util.h"
|
||||
#include "memory.h"
|
||||
#include "packet.h"
|
||||
#include "keydb.h"
|
||||
|
||||
#define USE_UNUSED_NODES 1
|
||||
|
||||
static KBNODE unused_nodes;
|
||||
|
||||
static KBNODE
|
||||
alloc_node(void)
|
||||
{
|
||||
KBNODE n;
|
||||
|
||||
n = unused_nodes;
|
||||
if( n )
|
||||
unused_nodes = n->next;
|
||||
else
|
||||
n = m_alloc( sizeof *n );
|
||||
n->next = NULL;
|
||||
n->pkt = NULL;
|
||||
n->flag = 0;
|
||||
n->private_flag=0;
|
||||
n->recno = 0;
|
||||
return n;
|
||||
}
|
||||
|
||||
static void
|
||||
free_node( KBNODE n )
|
||||
{
|
||||
if( n ) {
|
||||
#if USE_UNUSED_NODES
|
||||
n->next = unused_nodes;
|
||||
unused_nodes = n;
|
||||
#else
|
||||
m_free( n );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
KBNODE
|
||||
new_kbnode( PACKET *pkt )
|
||||
{
|
||||
KBNODE n = alloc_node();
|
||||
n->pkt = pkt;
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
KBNODE
|
||||
clone_kbnode( KBNODE node )
|
||||
{
|
||||
KBNODE n = alloc_node();
|
||||
|
||||
n->pkt = node->pkt;
|
||||
n->private_flag = node->private_flag | 2; /* mark cloned */
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
release_kbnode( KBNODE n )
|
||||
{
|
||||
KBNODE n2;
|
||||
|
||||
while( n ) {
|
||||
n2 = n->next;
|
||||
if( !is_cloned_kbnode(n) ) {
|
||||
free_packet( n->pkt );
|
||||
m_free( n->pkt );
|
||||
}
|
||||
free_node( n );
|
||||
n = n2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
* Delete NODE.
|
||||
* Note: This only works with walk_kbnode!!
|
||||
*/
|
||||
void
|
||||
delete_kbnode( KBNODE node )
|
||||
{
|
||||
node->private_flag |= 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/****************
|
||||
* Append NODE to ROOT. ROOT must exist!
|
||||
*/
|
||||
void
|
||||
add_kbnode( KBNODE root, KBNODE node )
|
||||
{
|
||||
KBNODE n1;
|
||||
|
||||
for(n1=root; n1->next; n1 = n1->next)
|
||||
;
|
||||
n1->next = node;
|
||||
}
|
||||
|
||||
/****************
|
||||
* Insert NODE into the list after root but before a packet which is not of
|
||||
* type PKTTYPE
|
||||
* (only if PKTTYPE != 0)
|
||||
*/
|
||||
void
|
||||
insert_kbnode( KBNODE root, KBNODE node, int pkttype )
|
||||
{
|
||||
if( !pkttype ) {
|
||||
node->next = root->next;
|
||||
root->next = node;
|
||||
}
|
||||
else {
|
||||
KBNODE n1;
|
||||
|
||||
for(n1=root; n1->next; n1 = n1->next)
|
||||
if( pkttype != n1->next->pkt->pkttype ) {
|
||||
node->next = n1->next;
|
||||
n1->next = node;
|
||||
return;
|
||||
}
|
||||
/* no such packet, append */
|
||||
node->next = NULL;
|
||||
n1->next = node;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
* Find the previous node (if PKTTYPE = 0) or the previous node
|
||||
* with pkttype PKTTYPE in the list starting with ROOT of NODE.
|
||||
*/
|
||||
KBNODE
|
||||
find_prev_kbnode( KBNODE root, KBNODE node, int pkttype )
|
||||
{
|
||||
KBNODE n1;
|
||||
|
||||
for (n1=NULL; root && root != node; root = root->next ) {
|
||||
if (!pkttype ||root->pkt->pkttype == pkttype)
|
||||
n1 = root;
|
||||
}
|
||||
return n1;
|
||||
}
|
||||
|
||||
/****************
|
||||
* Ditto, but find the next packet. The behaviour is trivial if
|
||||
* PKTTYPE is 0 but if it is specified, the next node with a packet
|
||||
* of this type is returned. The function has some knowledge about
|
||||
* the valid ordering of packets: e.g. if the next signature packet
|
||||
* is requested, the function will not return one if it encounters
|
||||
* a user-id.
|
||||
*/
|
||||
KBNODE
|
||||
find_next_kbnode( KBNODE node, int pkttype )
|
||||
{
|
||||
for( node=node->next ; node; node = node->next ) {
|
||||
if( !pkttype )
|
||||
return node;
|
||||
else if( pkttype == PKT_USER_ID
|
||||
&& ( node->pkt->pkttype == PKT_PUBLIC_KEY
|
||||
|| node->pkt->pkttype == PKT_SECRET_KEY ) )
|
||||
return NULL;
|
||||
else if( pkttype == PKT_SIGNATURE
|
||||
&& ( node->pkt->pkttype == PKT_USER_ID
|
||||
|| node->pkt->pkttype == PKT_PUBLIC_KEY
|
||||
|| node->pkt->pkttype == PKT_SECRET_KEY ) )
|
||||
return NULL;
|
||||
else if( node->pkt->pkttype == pkttype )
|
||||
return node;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
KBNODE
|
||||
find_kbnode( KBNODE node, int pkttype )
|
||||
{
|
||||
for( ; node; node = node->next ) {
|
||||
if( node->pkt->pkttype == pkttype )
|
||||
return node;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/****************
|
||||
* Walk through a list of kbnodes. This function returns
|
||||
* the next kbnode for each call; before using the function the first
|
||||
* time, the caller must set CONTEXT to NULL (This has simply the effect
|
||||
* to start with ROOT).
|
||||
*/
|
||||
KBNODE
|
||||
walk_kbnode( KBNODE root, KBNODE *context, int all )
|
||||
{
|
||||
KBNODE n;
|
||||
|
||||
do {
|
||||
if( !*context ) {
|
||||
*context = root;
|
||||
n = root;
|
||||
}
|
||||
else {
|
||||
n = (*context)->next;
|
||||
*context = n;
|
||||
}
|
||||
} while( !all && n && is_deleted_kbnode(n) );
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void
|
||||
clear_kbnode_flags( KBNODE n )
|
||||
{
|
||||
for( ; n; n = n->next ) {
|
||||
n->flag = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
* Commit changes made to the kblist at ROOT. Note that ROOT my change,
|
||||
* and it is therefore passed by reference.
|
||||
* The function has the effect of removing all nodes marked as deleted.
|
||||
* returns true if any node has been changed
|
||||
*/
|
||||
int
|
||||
commit_kbnode( KBNODE *root )
|
||||
{
|
||||
KBNODE n, nl;
|
||||
int changed = 0;
|
||||
|
||||
for( n = *root, nl=NULL; n; n = nl->next ) {
|
||||
if( is_deleted_kbnode(n) ) {
|
||||
if( n == *root )
|
||||
*root = nl = n->next;
|
||||
else
|
||||
nl->next = n->next;
|
||||
if( !is_cloned_kbnode(n) ) {
|
||||
free_packet( n->pkt );
|
||||
m_free( n->pkt );
|
||||
}
|
||||
free_node( n );
|
||||
changed = 1;
|
||||
}
|
||||
else
|
||||
nl = n;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
void
|
||||
remove_kbnode( KBNODE *root, KBNODE node )
|
||||
{
|
||||
KBNODE n, nl;
|
||||
|
||||
for( n = *root, nl=NULL; n; n = nl->next ) {
|
||||
if( n == node ) {
|
||||
if( n == *root )
|
||||
*root = nl = n->next;
|
||||
else
|
||||
nl->next = n->next;
|
||||
if( !is_cloned_kbnode(n) ) {
|
||||
free_packet( n->pkt );
|
||||
m_free( n->pkt );
|
||||
}
|
||||
free_node( n );
|
||||
}
|
||||
else
|
||||
nl = n;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
* Move NODE behind right after WHERE or to the beginning if WHERE is NULL.
|
||||
*/
|
||||
void
|
||||
move_kbnode( KBNODE *root, KBNODE node, KBNODE where )
|
||||
{
|
||||
KBNODE tmp, prev;
|
||||
|
||||
if( !root || !*root || !node )
|
||||
return; /* sanity check */
|
||||
for( prev = *root; prev && prev->next != node; prev = prev->next )
|
||||
;
|
||||
if( !prev )
|
||||
return; /* node is not in the list */
|
||||
|
||||
if( !where ) { /* move node before root */
|
||||
if( node == *root ) /* move to itself */
|
||||
return;
|
||||
prev->next = node->next;
|
||||
node->next = *root;
|
||||
*root = node;
|
||||
return;
|
||||
}
|
||||
/* move it after where */
|
||||
if( node == where )
|
||||
return;
|
||||
tmp = node->next;
|
||||
node->next = where->next;
|
||||
where->next = node;
|
||||
prev->next = tmp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void
|
||||
dump_kbnode( KBNODE node )
|
||||
{
|
||||
for(; node; node = node->next ) {
|
||||
const char *s;
|
||||
switch( node->pkt->pkttype ) {
|
||||
case 0: s="empty"; break;
|
||||
case PKT_PUBLIC_KEY: s="public-key"; break;
|
||||
case PKT_SECRET_KEY: s="secret-key"; break;
|
||||
case PKT_SECRET_SUBKEY: s= "secret-subkey"; break;
|
||||
case PKT_PUBKEY_ENC: s="public-enc"; break;
|
||||
case PKT_SIGNATURE: s="signature"; break;
|
||||
case PKT_ONEPASS_SIG: s="onepass-sig"; break;
|
||||
case PKT_USER_ID: s="user-id"; break;
|
||||
case PKT_PUBLIC_SUBKEY: s="public-subkey"; break;
|
||||
case PKT_COMMENT: s="comment"; break;
|
||||
case PKT_RING_TRUST: s="trust"; break;
|
||||
case PKT_PLAINTEXT: s="plaintext"; break;
|
||||
case PKT_COMPRESSED: s="compressed"; break;
|
||||
case PKT_ENCRYPTED: s="encrypted"; break;
|
||||
case PKT_GPG_CONTROL: s="gpg-control"; break;
|
||||
default: s="unknown"; break;
|
||||
}
|
||||
fprintf(stderr, "node %p %02x/%02x type=%s",
|
||||
node, node->flag, node->private_flag, s);
|
||||
if( node->pkt->pkttype == PKT_USER_ID ) {
|
||||
PKT_user_id *uid = node->pkt->pkt.user_id;
|
||||
fputs(" \"", stderr);
|
||||
print_string( stderr, uid->name, uid->len, 0 );
|
||||
fprintf (stderr, "\" %c%c%c%c\n",
|
||||
uid->is_expired? 'e':'.',
|
||||
uid->is_revoked? 'r':'.',
|
||||
uid->created? 'v':'.',
|
||||
uid->is_primary? 'p':'.' );
|
||||
}
|
||||
else if( node->pkt->pkttype == PKT_SIGNATURE ) {
|
||||
fprintf(stderr, " class=%02x keyid=%08lX ts=%lu\n",
|
||||
node->pkt->pkt.signature->sig_class,
|
||||
(ulong)node->pkt->pkt.signature->keyid[1],
|
||||
(ulong)node->pkt->pkt.signature->timestamp);
|
||||
}
|
||||
else if( node->pkt->pkttype == PKT_GPG_CONTROL ) {
|
||||
fprintf(stderr, " ctrl=%d len=%u\n",
|
||||
node->pkt->pkt.gpg_control->control,
|
||||
(unsigned int)node->pkt->pkt.gpg_control->datalen);
|
||||
}
|
||||
else if( node->pkt->pkttype == PKT_PUBLIC_KEY
|
||||
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
|
||||
PKT_public_key *pk = node->pkt->pkt.public_key;
|
||||
fprintf(stderr, " keyid=%08lX a=%d u=%d %c%c%c%c\n",
|
||||
(ulong)keyid_from_pk( pk, NULL ),
|
||||
pk->pubkey_algo, pk->pubkey_usage,
|
||||
pk->has_expired? 'e':'.',
|
||||
pk->is_revoked? 'r':'.',
|
||||
pk->is_valid? 'v':'.',
|
||||
pk->mdc_feature? 'm':'.');
|
||||
}
|
||||
else
|
||||
fputs("\n", stderr);
|
||||
}
|
||||
}
|
724
g10/keydb.c
Normal file
724
g10/keydb.c
Normal file
@ -0,0 +1,724 @@
|
||||
/* keydb.c - key database dispatcher
|
||||
* Copyright (C) 2001, 2002, 2003 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "options.h"
|
||||
#include "main.h" /*try_make_homedir ()*/
|
||||
#include "packet.h"
|
||||
#include "keyring.h"
|
||||
#include "keydb.h"
|
||||
#include "i18n.h"
|
||||
|
||||
static int active_handles;
|
||||
|
||||
typedef enum {
|
||||
KEYDB_RESOURCE_TYPE_NONE = 0,
|
||||
KEYDB_RESOURCE_TYPE_KEYRING
|
||||
} KeydbResourceType;
|
||||
#define MAX_KEYDB_RESOURCES 40
|
||||
|
||||
struct resource_item {
|
||||
KeydbResourceType type;
|
||||
union {
|
||||
KEYRING_HANDLE kr;
|
||||
} u;
|
||||
void *token;
|
||||
int secret;
|
||||
};
|
||||
|
||||
static struct resource_item all_resources[MAX_KEYDB_RESOURCES];
|
||||
static int used_resources;
|
||||
static void *primary_keyring=NULL;
|
||||
|
||||
struct keydb_handle {
|
||||
int locked;
|
||||
int found;
|
||||
int current;
|
||||
int used; /* items in active */
|
||||
struct resource_item active[MAX_KEYDB_RESOURCES];
|
||||
};
|
||||
|
||||
|
||||
static int lock_all (KEYDB_HANDLE hd);
|
||||
static void unlock_all (KEYDB_HANDLE hd);
|
||||
|
||||
|
||||
/*
|
||||
* Register a resource (which currently may only be a keyring file).
|
||||
* The first keyring which is added by this function is
|
||||
* created if it does not exist.
|
||||
* Note: this function may be called before secure memory is
|
||||
* available.
|
||||
* Flag 1 == force
|
||||
* Flag 2 == default
|
||||
*/
|
||||
int
|
||||
keydb_add_resource (const char *url, int flags, int secret)
|
||||
{
|
||||
static int any_secret, any_public;
|
||||
const char *resname = url;
|
||||
IOBUF iobuf = NULL;
|
||||
char *filename = NULL;
|
||||
int force=(flags&1);
|
||||
int rc = 0;
|
||||
KeydbResourceType rt = KEYDB_RESOURCE_TYPE_NONE;
|
||||
void *token;
|
||||
|
||||
/* Do we have an URL?
|
||||
* gnupg-ring:filename := this is a plain keyring
|
||||
* filename := See what is is, but create as plain keyring.
|
||||
*/
|
||||
if (strlen (resname) > 11) {
|
||||
if (!strncmp( resname, "gnupg-ring:", 11) ) {
|
||||
rt = KEYDB_RESOURCE_TYPE_KEYRING;
|
||||
resname += 11;
|
||||
}
|
||||
#if !defined(HAVE_DRIVE_LETTERS) && !defined(__riscos__)
|
||||
else if (strchr (resname, ':')) {
|
||||
log_error ("invalid key resource URL `%s'\n", url );
|
||||
rc = G10ERR_GENERAL;
|
||||
goto leave;
|
||||
}
|
||||
#endif /* !HAVE_DRIVE_LETTERS && !__riscos__ */
|
||||
}
|
||||
|
||||
if (*resname != DIRSEP_C ) { /* do tilde expansion etc */
|
||||
if (strchr(resname, DIRSEP_C) )
|
||||
filename = make_filename (resname, NULL);
|
||||
else
|
||||
filename = make_filename (opt.homedir, resname, NULL);
|
||||
}
|
||||
else
|
||||
filename = m_strdup (resname);
|
||||
|
||||
if (!force)
|
||||
force = secret? !any_secret : !any_public;
|
||||
|
||||
/* see whether we can determine the filetype */
|
||||
if (rt == KEYDB_RESOURCE_TYPE_NONE) {
|
||||
FILE *fp = fopen( filename, "rb" );
|
||||
|
||||
if (fp) {
|
||||
u32 magic;
|
||||
|
||||
if (fread( &magic, 4, 1, fp) == 1 ) {
|
||||
if (magic == 0x13579ace || magic == 0xce9a5713)
|
||||
; /* GDBM magic - no more support */
|
||||
else
|
||||
rt = KEYDB_RESOURCE_TYPE_KEYRING;
|
||||
}
|
||||
else /* maybe empty: assume ring */
|
||||
rt = KEYDB_RESOURCE_TYPE_KEYRING;
|
||||
fclose( fp );
|
||||
}
|
||||
else /* no file yet: create ring */
|
||||
rt = KEYDB_RESOURCE_TYPE_KEYRING;
|
||||
}
|
||||
|
||||
switch (rt) {
|
||||
case KEYDB_RESOURCE_TYPE_NONE:
|
||||
log_error ("unknown type of key resource `%s'\n", url );
|
||||
rc = G10ERR_GENERAL;
|
||||
goto leave;
|
||||
|
||||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||||
if (access(filename, F_OK))
|
||||
{ /* file does not exist */
|
||||
mode_t oldmask;
|
||||
char *last_slash_in_filename;
|
||||
|
||||
if (!force)
|
||||
{
|
||||
rc = G10ERR_OPEN_FILE;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
last_slash_in_filename = strrchr (filename, DIRSEP_C);
|
||||
*last_slash_in_filename = 0;
|
||||
if (access(filename, F_OK))
|
||||
{ /* On the first time we try to create the default
|
||||
homedir and check again. */
|
||||
static int tried;
|
||||
|
||||
if (!tried)
|
||||
{
|
||||
tried = 1;
|
||||
try_make_homedir (filename);
|
||||
}
|
||||
if (access (filename, F_OK))
|
||||
{
|
||||
rc = G10ERR_OPEN_FILE;
|
||||
*last_slash_in_filename = DIRSEP_C;
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
*last_slash_in_filename = DIRSEP_C;
|
||||
|
||||
oldmask=umask(077);
|
||||
iobuf = iobuf_create (filename);
|
||||
umask(oldmask);
|
||||
if (!iobuf)
|
||||
{
|
||||
log_error ( _("error creating keyring `%s': %s\n"),
|
||||
filename, strerror(errno));
|
||||
rc = G10ERR_OPEN_FILE;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if (!opt.quiet)
|
||||
log_info (_("keyring `%s' created\n"), filename);
|
||||
iobuf_close (iobuf);
|
||||
iobuf = NULL;
|
||||
/* must invalidate that ugly cache */
|
||||
iobuf_ioctl (NULL, 2, 0, (char*)filename);
|
||||
} /* end file creation */
|
||||
|
||||
if(keyring_register_filename (filename, secret, &token))
|
||||
{
|
||||
if (used_resources >= MAX_KEYDB_RESOURCES)
|
||||
rc = G10ERR_RESOURCE_LIMIT;
|
||||
else
|
||||
{
|
||||
if(flags&2)
|
||||
primary_keyring=token;
|
||||
all_resources[used_resources].type = rt;
|
||||
all_resources[used_resources].u.kr = NULL; /* Not used here */
|
||||
all_resources[used_resources].token = token;
|
||||
all_resources[used_resources].secret = secret;
|
||||
used_resources++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This keyring was already registered, so ignore it.
|
||||
However, we can still mark it as primary even if it was
|
||||
already registered. */
|
||||
if(flags&2)
|
||||
primary_keyring=token;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error ("resource type of `%s' not supported\n", url);
|
||||
rc = G10ERR_GENERAL;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* fixme: check directory permissions and print a warning */
|
||||
|
||||
leave:
|
||||
if (rc)
|
||||
log_error ("keyblock resource `%s': %s\n", filename, g10_errstr(rc));
|
||||
else if (secret)
|
||||
any_secret = 1;
|
||||
else
|
||||
any_public = 1;
|
||||
m_free (filename);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
KEYDB_HANDLE
|
||||
keydb_new (int secret)
|
||||
{
|
||||
KEYDB_HANDLE hd;
|
||||
int i, j;
|
||||
|
||||
hd = m_alloc_clear (sizeof *hd);
|
||||
hd->found = -1;
|
||||
|
||||
assert (used_resources <= MAX_KEYDB_RESOURCES);
|
||||
for (i=j=0; i < used_resources; i++)
|
||||
{
|
||||
if (!all_resources[i].secret != !secret)
|
||||
continue;
|
||||
switch (all_resources[i].type)
|
||||
{
|
||||
case KEYDB_RESOURCE_TYPE_NONE: /* ignore */
|
||||
break;
|
||||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||||
hd->active[j].type = all_resources[i].type;
|
||||
hd->active[j].token = all_resources[i].token;
|
||||
hd->active[j].secret = all_resources[i].secret;
|
||||
hd->active[j].u.kr = keyring_new (all_resources[i].token, secret);
|
||||
if (!hd->active[j].u.kr) {
|
||||
m_free (hd);
|
||||
return NULL; /* fixme: release all previously allocated handles*/
|
||||
}
|
||||
j++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
hd->used = j;
|
||||
|
||||
active_handles++;
|
||||
return hd;
|
||||
}
|
||||
|
||||
void
|
||||
keydb_release (KEYDB_HANDLE hd)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!hd)
|
||||
return;
|
||||
assert (active_handles > 0);
|
||||
active_handles--;
|
||||
|
||||
unlock_all (hd);
|
||||
for (i=0; i < hd->used; i++) {
|
||||
switch (hd->active[i].type) {
|
||||
case KEYDB_RESOURCE_TYPE_NONE:
|
||||
break;
|
||||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||||
keyring_release (hd->active[i].u.kr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_free (hd);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return the name of the current resource. This is function first
|
||||
* looks for the last found found, then for the current search
|
||||
* position, and last returns the first available resource. The
|
||||
* returned string is only valid as long as the handle exists. This
|
||||
* function does only return NULL if no handle is specified, in all
|
||||
* other error cases an empty string is returned.
|
||||
*/
|
||||
const char *
|
||||
keydb_get_resource_name (KEYDB_HANDLE hd)
|
||||
{
|
||||
int idx;
|
||||
const char *s = NULL;
|
||||
|
||||
if (!hd)
|
||||
return NULL;
|
||||
|
||||
if ( hd->found >= 0 && hd->found < hd->used)
|
||||
idx = hd->found;
|
||||
else if ( hd->current >= 0 && hd->current < hd->used)
|
||||
idx = hd->current;
|
||||
else
|
||||
idx = 0;
|
||||
|
||||
switch (hd->active[idx].type) {
|
||||
case KEYDB_RESOURCE_TYPE_NONE:
|
||||
s = NULL;
|
||||
break;
|
||||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||||
s = keyring_get_resource_name (hd->active[idx].u.kr);
|
||||
break;
|
||||
}
|
||||
|
||||
return s? s: "";
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int
|
||||
lock_all (KEYDB_HANDLE hd)
|
||||
{
|
||||
int i, rc = 0;
|
||||
|
||||
for (i=0; !rc && i < hd->used; i++) {
|
||||
switch (hd->active[i].type) {
|
||||
case KEYDB_RESOURCE_TYPE_NONE:
|
||||
break;
|
||||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||||
rc = keyring_lock (hd->active[i].u.kr, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rc) {
|
||||
/* revert the already set locks */
|
||||
for (i--; i >= 0; i--) {
|
||||
switch (hd->active[i].type) {
|
||||
case KEYDB_RESOURCE_TYPE_NONE:
|
||||
break;
|
||||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||||
keyring_lock (hd->active[i].u.kr, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
hd->locked = 1;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
unlock_all (KEYDB_HANDLE hd)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!hd->locked)
|
||||
return;
|
||||
|
||||
for (i=hd->used-1; i >= 0; i--) {
|
||||
switch (hd->active[i].type) {
|
||||
case KEYDB_RESOURCE_TYPE_NONE:
|
||||
break;
|
||||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||||
keyring_lock (hd->active[i].u.kr, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
hd->locked = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return the last found keyring. Caller must free it.
|
||||
* The returned keyblock has the kbode flag bit 0 set for the node with
|
||||
* the public key used to locate the keyblock or flag bit 1 set for
|
||||
* the user ID node.
|
||||
*/
|
||||
int
|
||||
keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (!hd)
|
||||
return G10ERR_INV_ARG;
|
||||
|
||||
if ( hd->found < 0 || hd->found >= hd->used)
|
||||
return -1; /* nothing found */
|
||||
|
||||
switch (hd->active[hd->found].type) {
|
||||
case KEYDB_RESOURCE_TYPE_NONE:
|
||||
rc = G10ERR_GENERAL; /* oops */
|
||||
break;
|
||||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||||
rc = keyring_get_keyblock (hd->active[hd->found].u.kr, ret_kb);
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* update the current keyblock with KB
|
||||
*/
|
||||
int
|
||||
keydb_update_keyblock (KEYDB_HANDLE hd, KBNODE kb)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (!hd)
|
||||
return G10ERR_INV_ARG;
|
||||
|
||||
if ( hd->found < 0 || hd->found >= hd->used)
|
||||
return -1; /* nothing found */
|
||||
|
||||
if( opt.dry_run )
|
||||
return 0;
|
||||
|
||||
rc = lock_all (hd);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
switch (hd->active[hd->found].type) {
|
||||
case KEYDB_RESOURCE_TYPE_NONE:
|
||||
rc = G10ERR_GENERAL; /* oops */
|
||||
break;
|
||||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||||
rc = keyring_update_keyblock (hd->active[hd->found].u.kr, kb);
|
||||
break;
|
||||
}
|
||||
|
||||
unlock_all (hd);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Insert a new KB into one of the resources.
|
||||
*/
|
||||
int
|
||||
keydb_insert_keyblock (KEYDB_HANDLE hd, KBNODE kb)
|
||||
{
|
||||
int rc = -1;
|
||||
int idx;
|
||||
|
||||
if (!hd)
|
||||
return G10ERR_INV_ARG;
|
||||
|
||||
if( opt.dry_run )
|
||||
return 0;
|
||||
|
||||
if ( hd->found >= 0 && hd->found < hd->used)
|
||||
idx = hd->found;
|
||||
else if ( hd->current >= 0 && hd->current < hd->used)
|
||||
idx = hd->current;
|
||||
else
|
||||
return G10ERR_GENERAL;
|
||||
|
||||
rc = lock_all (hd);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
switch (hd->active[idx].type) {
|
||||
case KEYDB_RESOURCE_TYPE_NONE:
|
||||
rc = G10ERR_GENERAL; /* oops */
|
||||
break;
|
||||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||||
rc = keyring_insert_keyblock (hd->active[idx].u.kr, kb);
|
||||
break;
|
||||
}
|
||||
|
||||
unlock_all (hd);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The current keyblock will be deleted.
|
||||
*/
|
||||
int
|
||||
keydb_delete_keyblock (KEYDB_HANDLE hd)
|
||||
{
|
||||
int rc = -1;
|
||||
|
||||
if (!hd)
|
||||
return G10ERR_INV_ARG;
|
||||
|
||||
if ( hd->found < 0 || hd->found >= hd->used)
|
||||
return -1; /* nothing found */
|
||||
|
||||
if( opt.dry_run )
|
||||
return 0;
|
||||
|
||||
rc = lock_all (hd);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
switch (hd->active[hd->found].type) {
|
||||
case KEYDB_RESOURCE_TYPE_NONE:
|
||||
rc = G10ERR_GENERAL; /* oops */
|
||||
break;
|
||||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||||
rc = keyring_delete_keyblock (hd->active[hd->found].u.kr);
|
||||
break;
|
||||
}
|
||||
|
||||
unlock_all (hd);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Locate the default writable key resource, so that the next
|
||||
* operation (which is only relevant for inserts) will be done on this
|
||||
* resource.
|
||||
*/
|
||||
int
|
||||
keydb_locate_writable (KEYDB_HANDLE hd, const char *reserved)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!hd)
|
||||
return G10ERR_INV_ARG;
|
||||
|
||||
rc = keydb_search_reset (hd); /* this does reset hd->current */
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* If we have a primary set, try that one first */
|
||||
if(primary_keyring)
|
||||
{
|
||||
for ( ; hd->current >= 0 && hd->current < hd->used; hd->current++)
|
||||
{
|
||||
if(hd->active[hd->current].token==primary_keyring)
|
||||
{
|
||||
if(keyring_is_writable (hd->active[hd->current].token))
|
||||
return 0;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rc = keydb_search_reset (hd); /* this does reset hd->current */
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
for ( ; hd->current >= 0 && hd->current < hd->used; hd->current++)
|
||||
{
|
||||
switch (hd->active[hd->current].type)
|
||||
{
|
||||
case KEYDB_RESOURCE_TYPE_NONE:
|
||||
BUG();
|
||||
break;
|
||||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||||
if (keyring_is_writable (hd->active[hd->current].token))
|
||||
return 0; /* found (hd->current is set to it) */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Rebuild the caches of all key resources.
|
||||
*/
|
||||
void
|
||||
keydb_rebuild_caches (void)
|
||||
{
|
||||
int i, rc;
|
||||
|
||||
for (i=0; i < used_resources; i++)
|
||||
{
|
||||
if (all_resources[i].secret)
|
||||
continue;
|
||||
switch (all_resources[i].type)
|
||||
{
|
||||
case KEYDB_RESOURCE_TYPE_NONE: /* ignore */
|
||||
break;
|
||||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||||
rc = keyring_rebuild_cache (all_resources[i].token);
|
||||
if (rc)
|
||||
log_error (_("failed to rebuild keyring cache: %s\n"),
|
||||
g10_errstr (rc));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Start the next search on this handle right at the beginning
|
||||
*/
|
||||
int
|
||||
keydb_search_reset (KEYDB_HANDLE hd)
|
||||
{
|
||||
int i, rc = 0;
|
||||
|
||||
if (!hd)
|
||||
return G10ERR_INV_ARG;
|
||||
|
||||
hd->current = 0;
|
||||
hd->found = -1;
|
||||
/* and reset all resources */
|
||||
for (i=0; !rc && i < hd->used; i++) {
|
||||
switch (hd->active[i].type) {
|
||||
case KEYDB_RESOURCE_TYPE_NONE:
|
||||
break;
|
||||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||||
rc = keyring_search_reset (hd->active[i].u.kr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Search through all keydb resources, starting at the current position,
|
||||
* for a keyblock which contains one of the keys described in the DESC array.
|
||||
*/
|
||||
int
|
||||
keydb_search2 (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
|
||||
size_t ndesc, size_t *descindex)
|
||||
{
|
||||
int rc = -1;
|
||||
|
||||
if (!hd)
|
||||
return G10ERR_INV_ARG;
|
||||
|
||||
while (rc == -1 && hd->current >= 0 && hd->current < hd->used) {
|
||||
switch (hd->active[hd->current].type) {
|
||||
case KEYDB_RESOURCE_TYPE_NONE:
|
||||
BUG(); /* we should never see it here */
|
||||
break;
|
||||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||||
rc = keyring_search (hd->active[hd->current].u.kr, desc,
|
||||
ndesc, descindex);
|
||||
break;
|
||||
}
|
||||
if (rc == -1) /* EOF -> switch to next resource */
|
||||
hd->current++;
|
||||
else if (!rc)
|
||||
hd->found = hd->current;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
keydb_search_first (KEYDB_HANDLE hd)
|
||||
{
|
||||
KEYDB_SEARCH_DESC desc;
|
||||
|
||||
memset (&desc, 0, sizeof desc);
|
||||
desc.mode = KEYDB_SEARCH_MODE_FIRST;
|
||||
return keydb_search (hd, &desc, 1);
|
||||
}
|
||||
|
||||
int
|
||||
keydb_search_next (KEYDB_HANDLE hd)
|
||||
{
|
||||
KEYDB_SEARCH_DESC desc;
|
||||
|
||||
memset (&desc, 0, sizeof desc);
|
||||
desc.mode = KEYDB_SEARCH_MODE_NEXT;
|
||||
return keydb_search (hd, &desc, 1);
|
||||
}
|
||||
|
||||
int
|
||||
keydb_search_kid (KEYDB_HANDLE hd, u32 *kid)
|
||||
{
|
||||
KEYDB_SEARCH_DESC desc;
|
||||
|
||||
memset (&desc, 0, sizeof desc);
|
||||
desc.mode = KEYDB_SEARCH_MODE_LONG_KID;
|
||||
desc.u.kid[0] = kid[0];
|
||||
desc.u.kid[1] = kid[1];
|
||||
return keydb_search (hd, &desc, 1);
|
||||
}
|
||||
|
||||
int
|
||||
keydb_search_fpr (KEYDB_HANDLE hd, const byte *fpr)
|
||||
{
|
||||
KEYDB_SEARCH_DESC desc;
|
||||
|
||||
memset (&desc, 0, sizeof desc);
|
||||
desc.mode = KEYDB_SEARCH_MODE_FPR;
|
||||
memcpy (desc.u.fpr, fpr, MAX_FINGERPRINT_LEN);
|
||||
return keydb_search (hd, &desc, 1);
|
||||
}
|
278
g10/keydb.h
Normal file
278
g10/keydb.h
Normal file
@ -0,0 +1,278 @@
|
||||
/* keydb.h - Key database
|
||||
* Copyright (C) 1998, 1999, 2000, 2001 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef G10_KEYDB_H
|
||||
#define G10_KEYDB_H
|
||||
|
||||
#include "types.h"
|
||||
#include "global.h"
|
||||
#include "packet.h"
|
||||
#include "cipher.h"
|
||||
|
||||
/* What qualifies as a certification (rather than a signature?) */
|
||||
#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_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_SUBKEY_SIG(s) ((s)->sig_class == 0x18)
|
||||
#define IS_KEY_REV(s) ((s)->sig_class == 0x20)
|
||||
#define IS_UID_REV(s) ((s)->sig_class == 0x30)
|
||||
#define IS_SUBKEY_REV(s) ((s)->sig_class == 0x28)
|
||||
|
||||
struct getkey_ctx_s;
|
||||
typedef struct getkey_ctx_s *GETKEY_CTX;
|
||||
|
||||
/****************
|
||||
* A Keyblock is all packets which form an entire certificate;
|
||||
* i.e. the public key, certificate, trust packets, user ids,
|
||||
* signatures, and subkey.
|
||||
*
|
||||
* This structure is also used to bind arbitrary packets together.
|
||||
*/
|
||||
|
||||
struct kbnode_struct {
|
||||
KBNODE next;
|
||||
PACKET *pkt;
|
||||
int flag;
|
||||
int private_flag;
|
||||
ulong recno; /* used while updating the trustdb */
|
||||
};
|
||||
|
||||
#define is_deleted_kbnode(a) ((a)->private_flag & 1)
|
||||
#define is_cloned_kbnode(a) ((a)->private_flag & 2)
|
||||
|
||||
|
||||
enum resource_type {
|
||||
rt_UNKNOWN = 0,
|
||||
rt_RING = 1
|
||||
};
|
||||
|
||||
|
||||
/****************
|
||||
* A data structre to hold information about the external position
|
||||
* of a keyblock.
|
||||
*/
|
||||
struct keyblock_pos_struct {
|
||||
int resno; /* resource number */
|
||||
enum resource_type rt;
|
||||
off_t offset; /* position information */
|
||||
unsigned count; /* length of the keyblock in packets */
|
||||
IOBUF fp; /* used by enum_keyblocks */
|
||||
int secret; /* working on a secret keyring */
|
||||
PACKET *pkt; /* ditto */
|
||||
int valid;
|
||||
};
|
||||
typedef struct keyblock_pos_struct KBPOS;
|
||||
|
||||
/* structure to hold a couple of public key certificates */
|
||||
typedef struct pk_list *PK_LIST;
|
||||
struct pk_list {
|
||||
PK_LIST next;
|
||||
PKT_public_key *pk;
|
||||
int flags; /* flag bit 1==throw_keyid */
|
||||
};
|
||||
|
||||
/* structure to hold a couple of secret key certificates */
|
||||
typedef struct sk_list *SK_LIST;
|
||||
struct sk_list {
|
||||
SK_LIST next;
|
||||
PKT_secret_key *sk;
|
||||
int mark; /* not used */
|
||||
};
|
||||
|
||||
/* structure to collect all information which can be used to
|
||||
* identify a public key */
|
||||
typedef struct pubkey_find_info *PUBKEY_FIND_INFO;
|
||||
struct pubkey_find_info {
|
||||
u32 keyid[2];
|
||||
unsigned nbits;
|
||||
byte pubkey_algo;
|
||||
byte fingerprint[MAX_FINGERPRINT_LEN];
|
||||
char userid[1];
|
||||
};
|
||||
|
||||
|
||||
typedef struct keydb_handle *KEYDB_HANDLE;
|
||||
|
||||
typedef enum {
|
||||
KEYDB_SEARCH_MODE_NONE,
|
||||
KEYDB_SEARCH_MODE_EXACT,
|
||||
KEYDB_SEARCH_MODE_SUBSTR,
|
||||
KEYDB_SEARCH_MODE_MAIL,
|
||||
KEYDB_SEARCH_MODE_MAILSUB,
|
||||
KEYDB_SEARCH_MODE_MAILEND,
|
||||
KEYDB_SEARCH_MODE_WORDS,
|
||||
KEYDB_SEARCH_MODE_SHORT_KID,
|
||||
KEYDB_SEARCH_MODE_LONG_KID,
|
||||
KEYDB_SEARCH_MODE_FPR16,
|
||||
KEYDB_SEARCH_MODE_FPR20,
|
||||
KEYDB_SEARCH_MODE_FPR,
|
||||
KEYDB_SEARCH_MODE_FIRST,
|
||||
KEYDB_SEARCH_MODE_NEXT
|
||||
} KeydbSearchMode;
|
||||
|
||||
struct keydb_search_desc {
|
||||
KeydbSearchMode mode;
|
||||
int (*skipfnc)(void *,u32*);
|
||||
void *skipfncvalue;
|
||||
union {
|
||||
const char *name;
|
||||
char fpr[MAX_FINGERPRINT_LEN];
|
||||
u32 kid[2];
|
||||
} u;
|
||||
int exact;
|
||||
};
|
||||
|
||||
/*-- keydb.c --*/
|
||||
|
||||
/*
|
||||
Flag 1 == force
|
||||
Flag 2 == default
|
||||
*/
|
||||
int keydb_add_resource (const char *url, int flags, int secret);
|
||||
KEYDB_HANDLE keydb_new (int secret);
|
||||
void keydb_release (KEYDB_HANDLE hd);
|
||||
const char *keydb_get_resource_name (KEYDB_HANDLE hd);
|
||||
int keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb);
|
||||
int keydb_update_keyblock (KEYDB_HANDLE hd, KBNODE kb);
|
||||
int keydb_insert_keyblock (KEYDB_HANDLE hd, KBNODE kb);
|
||||
int keydb_delete_keyblock (KEYDB_HANDLE hd);
|
||||
int keydb_locate_writable (KEYDB_HANDLE hd, const char *reserved);
|
||||
void keydb_rebuild_caches (void);
|
||||
int keydb_search_reset (KEYDB_HANDLE hd);
|
||||
#define keydb_search(a,b,c) keydb_search2((a),(b),(c),NULL)
|
||||
int keydb_search2 (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
|
||||
size_t ndesc, size_t *descindex);
|
||||
int keydb_search_first (KEYDB_HANDLE hd);
|
||||
int keydb_search_next (KEYDB_HANDLE hd);
|
||||
int keydb_search_kid (KEYDB_HANDLE hd, u32 *kid);
|
||||
int keydb_search_fpr (KEYDB_HANDLE hd, const byte *fpr);
|
||||
|
||||
|
||||
/*-- pkclist.c --*/
|
||||
void show_revocation_reason( PKT_public_key *pk, int mode );
|
||||
int check_signatures_trust( PKT_signature *sig );
|
||||
void release_pk_list( PK_LIST pk_list );
|
||||
int build_pk_list( STRLIST rcpts, PK_LIST *ret_pk_list, unsigned use );
|
||||
int algo_available( preftype_t preftype, int algo, void *hint );
|
||||
int select_algo_from_prefs( PK_LIST pk_list, int preftype,
|
||||
int request, void *hint );
|
||||
int select_mdc_from_pklist (PK_LIST pk_list);
|
||||
|
||||
/*-- skclist.c --*/
|
||||
void release_sk_list( SK_LIST sk_list );
|
||||
int build_sk_list( STRLIST locusr, SK_LIST *ret_sk_list,
|
||||
int unlock, unsigned use );
|
||||
|
||||
/*-- passphrase.h --*/
|
||||
int have_static_passphrase(void);
|
||||
void read_passphrase_from_fd( int fd );
|
||||
void passphrase_clear_cache ( u32 *keyid, int algo );
|
||||
DEK *passphrase_to_dek( u32 *keyid, int pubkey_algo,
|
||||
int cipher_algo, STRING2KEY *s2k, int mode,
|
||||
const char *tryagain_text, int *canceled);
|
||||
void set_next_passphrase( const char *s );
|
||||
char *get_last_passphrase(void);
|
||||
|
||||
/*-- getkey.c --*/
|
||||
int classify_user_id( const char *name, KEYDB_SEARCH_DESC *desc);
|
||||
void cache_public_key( PKT_public_key *pk );
|
||||
void getkey_disable_caches(void);
|
||||
int get_pubkey( PKT_public_key *pk, u32 *keyid );
|
||||
int get_pubkey_fast ( PKT_public_key *pk, u32 *keyid );
|
||||
KBNODE get_pubkeyblock( u32 *keyid );
|
||||
int get_pubkey_byname( PKT_public_key *pk, const char *name,
|
||||
KBNODE *ret_keyblock, KEYDB_HANDLE *ret_kdbhd,
|
||||
int include_disabled );
|
||||
int get_pubkey_bynames( GETKEY_CTX *rx, PKT_public_key *pk,
|
||||
STRLIST names, KBNODE *ret_keyblock );
|
||||
int get_pubkey_next( GETKEY_CTX ctx, PKT_public_key *pk, KBNODE *ret_keyblock );
|
||||
void get_pubkey_end( GETKEY_CTX ctx );
|
||||
int get_seckey( PKT_secret_key *sk, u32 *keyid );
|
||||
int get_primary_seckey( PKT_secret_key *sk, u32 *keyid );
|
||||
int get_pubkey_byfprint( PKT_public_key *pk, const byte *fprint,
|
||||
size_t fprint_len );
|
||||
int get_pubkey_byfprint_fast (PKT_public_key *pk,
|
||||
const byte *fprint, size_t fprint_len);
|
||||
int get_keyblock_byfprint( KBNODE *ret_keyblock, const byte *fprint,
|
||||
size_t fprint_len );
|
||||
int get_keyblock_bylid( KBNODE *ret_keyblock, ulong lid );
|
||||
int seckey_available( u32 *keyid );
|
||||
int get_seckey_byname( PKT_secret_key *sk, const char *name, int unlock );
|
||||
int get_seckey_bynames( GETKEY_CTX *rx, PKT_secret_key *sk,
|
||||
STRLIST names, KBNODE *ret_keyblock );
|
||||
int get_seckey_byfprint( PKT_secret_key *sk,
|
||||
const byte *fprint, size_t fprint_len);
|
||||
int get_seckey_next( GETKEY_CTX ctx, PKT_secret_key *sk, KBNODE *ret_keyblock );
|
||||
void get_seckey_end( GETKEY_CTX ctx );
|
||||
int enum_secret_keys( void **context, PKT_secret_key *sk,
|
||||
int with_subkeys, int with_spm );
|
||||
void merge_keys_and_selfsig( KBNODE keyblock );
|
||||
char*get_user_id_string( u32 *keyid );
|
||||
char*get_user_id_string_printable( u32 *keyid );
|
||||
char*get_long_user_id_string( u32 *keyid );
|
||||
char*get_user_id( u32 *keyid, size_t *rn );
|
||||
char*get_user_id_printable( u32 *keyid );
|
||||
KEYDB_HANDLE get_ctx_handle(GETKEY_CTX ctx);
|
||||
|
||||
/*-- keyid.c --*/
|
||||
int pubkey_letter( int algo );
|
||||
u32 keyid_from_sk( PKT_secret_key *sk, u32 *keyid );
|
||||
u32 keyid_from_pk( PKT_public_key *pk, u32 *keyid );
|
||||
u32 keyid_from_sig( PKT_signature *sig, u32 *keyid );
|
||||
u32 keyid_from_fingerprint( const byte *fprint, size_t fprint_len, u32 *keyid );
|
||||
byte *namehash_from_uid(PKT_user_id *uid);
|
||||
unsigned nbits_from_pk( PKT_public_key *pk );
|
||||
unsigned nbits_from_sk( PKT_secret_key *sk );
|
||||
const char *datestr_from_pk( PKT_public_key *pk );
|
||||
const char *datestr_from_sk( PKT_secret_key *sk );
|
||||
const char *datestr_from_sig( PKT_signature *sig );
|
||||
const char *expirestr_from_pk( PKT_public_key *pk );
|
||||
const char *expirestr_from_sk( PKT_secret_key *sk );
|
||||
const char *expirestr_from_sig( PKT_signature *sig );
|
||||
|
||||
const char *colon_strtime (u32 t);
|
||||
const char *colon_datestr_from_pk (PKT_public_key *pk);
|
||||
const char *colon_datestr_from_sk (PKT_secret_key *sk);
|
||||
const char *colon_datestr_from_sig (PKT_signature *sig);
|
||||
const char *colon_expirestr_from_sig (PKT_signature *sig);
|
||||
|
||||
byte *fingerprint_from_sk( PKT_secret_key *sk, byte *buf, size_t *ret_len );
|
||||
byte *fingerprint_from_pk( PKT_public_key *pk, byte *buf, size_t *ret_len );
|
||||
|
||||
/*-- kbnode.c --*/
|
||||
KBNODE new_kbnode( PACKET *pkt );
|
||||
KBNODE clone_kbnode( KBNODE node );
|
||||
void release_kbnode( KBNODE n );
|
||||
void delete_kbnode( KBNODE node );
|
||||
void add_kbnode( KBNODE root, KBNODE node );
|
||||
void insert_kbnode( KBNODE root, KBNODE node, int pkttype );
|
||||
void move_kbnode( KBNODE *root, KBNODE node, KBNODE where );
|
||||
void remove_kbnode( KBNODE *root, KBNODE node );
|
||||
KBNODE find_prev_kbnode( KBNODE root, KBNODE node, int pkttype );
|
||||
KBNODE find_next_kbnode( KBNODE node, int pkttype );
|
||||
KBNODE find_kbnode( KBNODE node, int pkttype );
|
||||
KBNODE walk_kbnode( KBNODE root, KBNODE *context, int all );
|
||||
void clear_kbnode_flags( KBNODE n );
|
||||
int commit_kbnode( KBNODE *root );
|
||||
void dump_kbnode( KBNODE node );
|
||||
|
||||
#endif /*G10_KEYDB_H*/
|
3672
g10/keyedit.c
Normal file
3672
g10/keyedit.c
Normal file
File diff suppressed because it is too large
Load Diff
2523
g10/keygen.c
Normal file
2523
g10/keygen.c
Normal file
File diff suppressed because it is too large
Load Diff
518
g10/keyid.c
Normal file
518
g10/keyid.c
Normal file
@ -0,0 +1,518 @@
|
||||
/* keyid.c - key ID and fingerprint handling
|
||||
* Copyright (C) 1998, 1999, 2000, 2001 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include "util.h"
|
||||
#include "main.h"
|
||||
#include "packet.h"
|
||||
#include "options.h"
|
||||
#include "mpi.h"
|
||||
#include "keydb.h"
|
||||
#include "i18n.h"
|
||||
|
||||
|
||||
int
|
||||
pubkey_letter( int algo )
|
||||
{
|
||||
switch( algo ) {
|
||||
case PUBKEY_ALGO_RSA: return 'R' ;
|
||||
case PUBKEY_ALGO_RSA_E: return 'r' ;
|
||||
case PUBKEY_ALGO_RSA_S: return 's' ;
|
||||
case PUBKEY_ALGO_ELGAMAL_E: return 'g';
|
||||
case PUBKEY_ALGO_ELGAMAL: return 'G' ;
|
||||
case PUBKEY_ALGO_DSA: return 'D' ;
|
||||
default: return '?';
|
||||
}
|
||||
}
|
||||
|
||||
static MD_HANDLE
|
||||
do_fingerprint_md( PKT_public_key *pk )
|
||||
{
|
||||
MD_HANDLE md;
|
||||
unsigned n;
|
||||
unsigned nb[PUBKEY_MAX_NPKEY];
|
||||
unsigned nn[PUBKEY_MAX_NPKEY];
|
||||
byte *pp[PUBKEY_MAX_NPKEY];
|
||||
int i;
|
||||
int npkey = pubkey_get_npkey( pk->pubkey_algo );
|
||||
|
||||
md = md_open( pk->version < 4 ? DIGEST_ALGO_RMD160 : DIGEST_ALGO_SHA1, 0);
|
||||
n = pk->version < 4 ? 8 : 6;
|
||||
for(i=0; i < npkey; i++ ) {
|
||||
nb[i] = mpi_get_nbits(pk->pkey[i]);
|
||||
pp[i] = mpi_get_buffer( pk->pkey[i], nn+i, NULL );
|
||||
n += 2 + nn[i];
|
||||
}
|
||||
|
||||
md_putc( md, 0x99 ); /* ctb */
|
||||
md_putc( md, n >> 8 ); /* 2 byte length header */
|
||||
md_putc( md, n );
|
||||
if( pk->version < 4 )
|
||||
md_putc( md, 3 );
|
||||
else
|
||||
md_putc( md, 4 );
|
||||
|
||||
{ u32 a = pk->timestamp;
|
||||
md_putc( md, a >> 24 );
|
||||
md_putc( md, a >> 16 );
|
||||
md_putc( md, a >> 8 );
|
||||
md_putc( md, a );
|
||||
}
|
||||
if( pk->version < 4 ) {
|
||||
u16 a;
|
||||
|
||||
if( pk->expiredate )
|
||||
a = (u16)((pk->expiredate - pk->timestamp) / 86400L);
|
||||
else
|
||||
a = 0;
|
||||
md_putc( md, a >> 8 );
|
||||
md_putc( md, a );
|
||||
}
|
||||
md_putc( md, pk->pubkey_algo );
|
||||
for(i=0; i < npkey; i++ ) {
|
||||
md_putc( md, nb[i]>>8);
|
||||
md_putc( md, nb[i] );
|
||||
md_write( md, pp[i], nn[i] );
|
||||
m_free(pp[i]);
|
||||
}
|
||||
md_final( md );
|
||||
|
||||
return md;
|
||||
}
|
||||
|
||||
static MD_HANDLE
|
||||
do_fingerprint_md_sk( PKT_secret_key *sk )
|
||||
{
|
||||
PKT_public_key pk;
|
||||
int npkey = pubkey_get_npkey( sk->pubkey_algo ); /* npkey is correct! */
|
||||
int i;
|
||||
|
||||
pk.pubkey_algo = sk->pubkey_algo;
|
||||
pk.version = sk->version;
|
||||
pk.timestamp = sk->timestamp;
|
||||
pk.expiredate = sk->expiredate;
|
||||
pk.pubkey_algo = sk->pubkey_algo;
|
||||
for( i=0; i < npkey; i++ )
|
||||
pk.pkey[i] = sk->skey[i];
|
||||
return do_fingerprint_md( &pk );
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
* Get the keyid from the secret key and put it into keyid
|
||||
* if this is not NULL. Return the 32 low bits of the keyid.
|
||||
*/
|
||||
u32
|
||||
keyid_from_sk( PKT_secret_key *sk, u32 *keyid )
|
||||
{
|
||||
u32 lowbits;
|
||||
u32 dummy_keyid[2];
|
||||
|
||||
if( !keyid )
|
||||
keyid = dummy_keyid;
|
||||
|
||||
if( sk->version < 4 && is_RSA(sk->pubkey_algo) ) {
|
||||
lowbits = pubkey_get_npkey(sk->pubkey_algo) ?
|
||||
mpi_get_keyid( sk->skey[0], keyid ) : 0; /* take n */
|
||||
}
|
||||
else {
|
||||
const byte *dp;
|
||||
MD_HANDLE md;
|
||||
md = do_fingerprint_md_sk(sk);
|
||||
dp = md_read( md, 0 );
|
||||
keyid[0] = dp[12] << 24 | dp[13] << 16 | dp[14] << 8 | dp[15] ;
|
||||
keyid[1] = dp[16] << 24 | dp[17] << 16 | dp[18] << 8 | dp[19] ;
|
||||
lowbits = keyid[1];
|
||||
md_close(md);
|
||||
}
|
||||
|
||||
return lowbits;
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
* Get the keyid from the public key and put it into keyid
|
||||
* if this is not NULL. Return the 32 low bits of the keyid.
|
||||
*/
|
||||
u32
|
||||
keyid_from_pk( PKT_public_key *pk, u32 *keyid )
|
||||
{
|
||||
u32 lowbits;
|
||||
u32 dummy_keyid[2];
|
||||
|
||||
if( !keyid )
|
||||
keyid = dummy_keyid;
|
||||
|
||||
if( pk->keyid[0] || pk->keyid[1] ) {
|
||||
keyid[0] = pk->keyid[0];
|
||||
keyid[1] = pk->keyid[1];
|
||||
lowbits = keyid[1];
|
||||
}
|
||||
else if( pk->version < 4 && is_RSA(pk->pubkey_algo) ) {
|
||||
lowbits = pubkey_get_npkey(pk->pubkey_algo) ?
|
||||
mpi_get_keyid( pk->pkey[0], keyid ) : 0 ; /* from n */
|
||||
pk->keyid[0] = keyid[0];
|
||||
pk->keyid[1] = keyid[1];
|
||||
}
|
||||
else {
|
||||
const byte *dp;
|
||||
MD_HANDLE md;
|
||||
md = do_fingerprint_md(pk);
|
||||
dp = md_read( md, 0 );
|
||||
keyid[0] = dp[12] << 24 | dp[13] << 16 | dp[14] << 8 | dp[15] ;
|
||||
keyid[1] = dp[16] << 24 | dp[17] << 16 | dp[18] << 8 | dp[19] ;
|
||||
lowbits = keyid[1];
|
||||
md_close(md);
|
||||
pk->keyid[0] = keyid[0];
|
||||
pk->keyid[1] = keyid[1];
|
||||
}
|
||||
|
||||
return lowbits;
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
* Get the keyid from the fingerprint. This function is simple for most
|
||||
* keys, but has to do a keylookup for old stayle keys.
|
||||
*/
|
||||
u32
|
||||
keyid_from_fingerprint( const byte *fprint, size_t fprint_len, u32 *keyid )
|
||||
{
|
||||
u32 dummy_keyid[2];
|
||||
|
||||
if( !keyid )
|
||||
keyid = dummy_keyid;
|
||||
|
||||
if( fprint_len != 20 ) {
|
||||
/* This is special as we have to lookup the key first */
|
||||
PKT_public_key pk;
|
||||
int rc;
|
||||
|
||||
memset( &pk, 0, sizeof pk );
|
||||
rc = get_pubkey_byfprint( &pk, fprint, fprint_len );
|
||||
if( rc ) {
|
||||
log_error("Oops: keyid_from_fingerprint: no pubkey\n");
|
||||
keyid[0] = 0;
|
||||
keyid[1] = 0;
|
||||
}
|
||||
else
|
||||
keyid_from_pk( &pk, keyid );
|
||||
}
|
||||
else {
|
||||
const byte *dp = fprint;
|
||||
keyid[0] = dp[12] << 24 | dp[13] << 16 | dp[14] << 8 | dp[15] ;
|
||||
keyid[1] = dp[16] << 24 | dp[17] << 16 | dp[18] << 8 | dp[19] ;
|
||||
}
|
||||
|
||||
return keyid[1];
|
||||
}
|
||||
|
||||
|
||||
u32
|
||||
keyid_from_sig( PKT_signature *sig, u32 *keyid )
|
||||
{
|
||||
if( keyid ) {
|
||||
keyid[0] = sig->keyid[0];
|
||||
keyid[1] = sig->keyid[1];
|
||||
}
|
||||
return sig->keyid[1];
|
||||
}
|
||||
|
||||
byte *
|
||||
namehash_from_uid(PKT_user_id *uid)
|
||||
{
|
||||
if(uid->namehash==NULL)
|
||||
{
|
||||
uid->namehash=m_alloc(20);
|
||||
|
||||
if(uid->attrib_data)
|
||||
rmd160_hash_buffer(uid->namehash,uid->attrib_data,uid->attrib_len);
|
||||
else
|
||||
rmd160_hash_buffer(uid->namehash,uid->name,uid->len);
|
||||
}
|
||||
|
||||
return uid->namehash;
|
||||
}
|
||||
|
||||
/****************
|
||||
* return the number of bits used in the pk
|
||||
*/
|
||||
unsigned
|
||||
nbits_from_pk( PKT_public_key *pk )
|
||||
{
|
||||
return pubkey_nbits( pk->pubkey_algo, pk->pkey );
|
||||
}
|
||||
|
||||
/****************
|
||||
* return the number of bits used in the sk
|
||||
*/
|
||||
unsigned
|
||||
nbits_from_sk( PKT_secret_key *sk )
|
||||
{
|
||||
return pubkey_nbits( sk->pubkey_algo, sk->skey );
|
||||
}
|
||||
|
||||
static const char *
|
||||
mk_datestr (char *buffer, time_t atime)
|
||||
{
|
||||
struct tm *tp;
|
||||
|
||||
if ( atime < 0 ) /* 32 bit time_t and after 2038-01-19 */
|
||||
strcpy (buffer, "????" "-??" "-??"); /* mark this as invalid */
|
||||
else {
|
||||
tp = gmtime (&atime);
|
||||
sprintf (buffer,"%04d-%02d-%02d",
|
||||
1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday );
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/****************
|
||||
* return a string with the creation date of the pk
|
||||
* Note: this is alloced in a static buffer.
|
||||
* Format is: yyyy-mm-dd
|
||||
*/
|
||||
const char *
|
||||
datestr_from_pk( PKT_public_key *pk )
|
||||
{
|
||||
static char buffer[11+5];
|
||||
time_t atime = pk->timestamp;
|
||||
|
||||
return mk_datestr (buffer, atime);
|
||||
}
|
||||
|
||||
const char *
|
||||
datestr_from_sk( PKT_secret_key *sk )
|
||||
{
|
||||
static char buffer[11+5];
|
||||
time_t atime = sk->timestamp;
|
||||
|
||||
return mk_datestr (buffer, atime);
|
||||
}
|
||||
|
||||
const char *
|
||||
datestr_from_sig( PKT_signature *sig )
|
||||
{
|
||||
static char buffer[11+5];
|
||||
time_t atime = sig->timestamp;
|
||||
|
||||
return mk_datestr (buffer, atime);
|
||||
}
|
||||
|
||||
const char *
|
||||
expirestr_from_pk( PKT_public_key *pk )
|
||||
{
|
||||
static char buffer[11+5];
|
||||
time_t atime;
|
||||
|
||||
if( !pk->expiredate )
|
||||
return _("never ");
|
||||
atime = pk->expiredate;
|
||||
return mk_datestr (buffer, atime);
|
||||
}
|
||||
|
||||
const char *
|
||||
expirestr_from_sk( PKT_secret_key *sk )
|
||||
{
|
||||
static char buffer[11+5];
|
||||
time_t atime;
|
||||
|
||||
if( !sk->expiredate )
|
||||
return _("never ");
|
||||
atime = sk->expiredate;
|
||||
return mk_datestr (buffer, atime);
|
||||
}
|
||||
|
||||
const char *
|
||||
expirestr_from_sig( PKT_signature *sig )
|
||||
{
|
||||
static char buffer[11+5];
|
||||
time_t atime;
|
||||
|
||||
if(!sig->expiredate)
|
||||
return _("never ");
|
||||
atime=sig->expiredate;
|
||||
return mk_datestr (buffer, atime);
|
||||
}
|
||||
|
||||
const char *
|
||||
colon_strtime (u32 t)
|
||||
{
|
||||
if (!t)
|
||||
return "";
|
||||
if (opt.fixed_list_mode) {
|
||||
static char buf[15];
|
||||
sprintf (buf, "%lu", (ulong)t);
|
||||
return buf;
|
||||
}
|
||||
return strtimestamp(t);
|
||||
}
|
||||
|
||||
const char *
|
||||
colon_datestr_from_pk (PKT_public_key *pk)
|
||||
{
|
||||
if (opt.fixed_list_mode) {
|
||||
static char buf[15];
|
||||
sprintf (buf, "%lu", (ulong)pk->timestamp);
|
||||
return buf;
|
||||
}
|
||||
return datestr_from_pk (pk);
|
||||
}
|
||||
|
||||
const char *
|
||||
colon_datestr_from_sk (PKT_secret_key *sk)
|
||||
{
|
||||
if (opt.fixed_list_mode) {
|
||||
static char buf[15];
|
||||
sprintf (buf, "%lu", (ulong)sk->timestamp);
|
||||
return buf;
|
||||
}
|
||||
return datestr_from_sk (sk);
|
||||
}
|
||||
|
||||
const char *
|
||||
colon_datestr_from_sig (PKT_signature *sig)
|
||||
{
|
||||
if (opt.fixed_list_mode) {
|
||||
static char buf[15];
|
||||
sprintf (buf, "%lu", (ulong)sig->timestamp);
|
||||
return buf;
|
||||
}
|
||||
return datestr_from_sig (sig);
|
||||
}
|
||||
|
||||
const char *
|
||||
colon_expirestr_from_sig (PKT_signature *sig)
|
||||
{
|
||||
if(!sig->expiredate)
|
||||
return "";
|
||||
if (opt.fixed_list_mode) {
|
||||
static char buf[15];
|
||||
sprintf (buf, "%lu", (ulong)sig->expiredate);
|
||||
return buf;
|
||||
}
|
||||
return expirestr_from_sig (sig);
|
||||
}
|
||||
|
||||
|
||||
/**************** .
|
||||
* Return a byte array with the fingerprint for the given PK/SK
|
||||
* The length of the array is returned in ret_len. Caller must free
|
||||
* the array or provide an array of length MAX_FINGERPRINT_LEN.
|
||||
*/
|
||||
|
||||
byte *
|
||||
fingerprint_from_pk( PKT_public_key *pk, byte *array, size_t *ret_len )
|
||||
{
|
||||
byte *p, *buf;
|
||||
const byte *dp;
|
||||
size_t len;
|
||||
unsigned int n;
|
||||
|
||||
if( pk->version < 4 && is_RSA(pk->pubkey_algo) ) {
|
||||
/* RSA in version 3 packets is special */
|
||||
MD_HANDLE md;
|
||||
|
||||
md = md_open( DIGEST_ALGO_MD5, 0);
|
||||
if( pubkey_get_npkey( pk->pubkey_algo ) > 1 ) {
|
||||
p = buf = mpi_get_buffer( pk->pkey[0], &n, NULL );
|
||||
md_write( md, p, n );
|
||||
m_free(buf);
|
||||
p = buf = mpi_get_buffer( pk->pkey[1], &n, NULL );
|
||||
md_write( md, p, n );
|
||||
m_free(buf);
|
||||
}
|
||||
md_final(md);
|
||||
if( !array )
|
||||
array = m_alloc( 16 );
|
||||
len = 16;
|
||||
memcpy(array, md_read(md, DIGEST_ALGO_MD5), 16 );
|
||||
md_close(md);
|
||||
}
|
||||
else {
|
||||
MD_HANDLE md;
|
||||
md = do_fingerprint_md(pk);
|
||||
dp = md_read( md, 0 );
|
||||
len = md_digest_length( md_get_algo( md ) );
|
||||
assert( len <= MAX_FINGERPRINT_LEN );
|
||||
if( !array )
|
||||
array = m_alloc( len );
|
||||
memcpy(array, dp, len );
|
||||
pk->keyid[0] = dp[12] << 24 | dp[13] << 16 | dp[14] << 8 | dp[15] ;
|
||||
pk->keyid[1] = dp[16] << 24 | dp[17] << 16 | dp[18] << 8 | dp[19] ;
|
||||
md_close(md);
|
||||
}
|
||||
|
||||
*ret_len = len;
|
||||
return array;
|
||||
}
|
||||
|
||||
byte *
|
||||
fingerprint_from_sk( PKT_secret_key *sk, byte *array, size_t *ret_len )
|
||||
{
|
||||
byte *p, *buf;
|
||||
const char *dp;
|
||||
size_t len;
|
||||
unsigned n;
|
||||
|
||||
if( sk->version < 4 && is_RSA(sk->pubkey_algo) ) {
|
||||
/* RSA in version 3 packets is special */
|
||||
MD_HANDLE md;
|
||||
|
||||
md = md_open( DIGEST_ALGO_MD5, 0);
|
||||
if( pubkey_get_npkey( sk->pubkey_algo ) > 1 ) {
|
||||
p = buf = mpi_get_buffer( sk->skey[0], &n, NULL );
|
||||
md_write( md, p, n );
|
||||
m_free(buf);
|
||||
p = buf = mpi_get_buffer( sk->skey[1], &n, NULL );
|
||||
md_write( md, p, n );
|
||||
m_free(buf);
|
||||
}
|
||||
md_final(md);
|
||||
if( !array )
|
||||
array = m_alloc( 16 );
|
||||
len = 16;
|
||||
memcpy(array, md_read(md, DIGEST_ALGO_MD5), 16 );
|
||||
md_close(md);
|
||||
}
|
||||
else {
|
||||
MD_HANDLE md;
|
||||
md = do_fingerprint_md_sk(sk);
|
||||
dp = md_read( md, 0 );
|
||||
len = md_digest_length( md_get_algo( md ) );
|
||||
assert( len <= MAX_FINGERPRINT_LEN );
|
||||
if( !array )
|
||||
array = m_alloc( len );
|
||||
memcpy(array, dp, len );
|
||||
md_close(md);
|
||||
}
|
||||
|
||||
*ret_len = len;
|
||||
return array;
|
||||
}
|
||||
|
||||
|
||||
|
1287
g10/keylist.c
Normal file
1287
g10/keylist.c
Normal file
File diff suppressed because it is too large
Load Diff
1573
g10/keyring.c
Normal file
1573
g10/keyring.c
Normal file
File diff suppressed because it is too large
Load Diff
46
g10/keyring.h
Normal file
46
g10/keyring.h
Normal file
@ -0,0 +1,46 @@
|
||||
/* keyring.h - Keyring operations
|
||||
* Copyright (C) 2001 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef GPG_KEYRING_H
|
||||
#define GPG_KEYRING_H 1
|
||||
|
||||
#include "global.h"
|
||||
|
||||
|
||||
typedef struct keyring_handle *KEYRING_HANDLE;
|
||||
|
||||
int keyring_register_filename (const char *fname, int secret, void **ptr);
|
||||
int keyring_is_writable (void *token);
|
||||
|
||||
KEYRING_HANDLE keyring_new (void *token, int secret);
|
||||
void keyring_release (KEYRING_HANDLE hd);
|
||||
const char *keyring_get_resource_name (KEYRING_HANDLE hd);
|
||||
int keyring_lock (KEYRING_HANDLE hd, int yes);
|
||||
int keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb);
|
||||
int keyring_update_keyblock (KEYRING_HANDLE hd, KBNODE kb);
|
||||
int keyring_insert_keyblock (KEYRING_HANDLE hd, KBNODE kb);
|
||||
int keyring_locate_writable (KEYRING_HANDLE hd);
|
||||
int keyring_delete_keyblock (KEYRING_HANDLE hd);
|
||||
int keyring_search_reset (KEYRING_HANDLE hd);
|
||||
int keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
|
||||
size_t ndesc, size_t *descindex);
|
||||
int keyring_rebuild_cache (void *);
|
||||
|
||||
#endif /*GPG_KEYRING_H*/
|
1378
g10/keyserver.c
Normal file
1378
g10/keyserver.c
Normal file
File diff suppressed because it is too large
Load Diff
241
g10/main.h
Normal file
241
g10/main.h
Normal file
@ -0,0 +1,241 @@
|
||||
/* main.h
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifndef G10_MAIN_H
|
||||
#define G10_MAIN_H
|
||||
#include "types.h"
|
||||
#include "iobuf.h"
|
||||
#include "mpi.h"
|
||||
#include "cipher.h"
|
||||
#include "keydb.h"
|
||||
|
||||
/* It could be argued that the default cipher should be 3DES rather
|
||||
than CAST5, and the default compression should be 0
|
||||
(i.e. uncompressed) rather than 1 (zip). */
|
||||
#define DEFAULT_CIPHER_ALGO CIPHER_ALGO_CAST5
|
||||
#define DEFAULT_DIGEST_ALGO DIGEST_ALGO_SHA1
|
||||
#define DEFAULT_COMPRESS_ALGO 1
|
||||
|
||||
typedef struct {
|
||||
int header_okay;
|
||||
PK_LIST pk_list;
|
||||
cipher_filter_context_t cfx;
|
||||
} encrypt_filter_context_t;
|
||||
|
||||
struct groupitem
|
||||
{
|
||||
char *name;
|
||||
STRLIST values;
|
||||
struct groupitem *next;
|
||||
};
|
||||
|
||||
/*-- g10.c --*/
|
||||
extern int g10_errors_seen;
|
||||
|
||||
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )
|
||||
void g10_exit(int rc) __attribute__ ((noreturn));
|
||||
#else
|
||||
void g10_exit(int rc);
|
||||
#endif
|
||||
void print_pubkey_algo_note( int algo );
|
||||
void print_cipher_algo_note( int algo );
|
||||
void print_digest_algo_note( int algo );
|
||||
|
||||
/*-- armor.c --*/
|
||||
char *make_radix64_string( const byte *data, size_t len );
|
||||
|
||||
/*-- misc.c --*/
|
||||
void trap_unaligned(void);
|
||||
int disable_core_dumps(void);
|
||||
u16 checksum_u16( unsigned n );
|
||||
u16 checksum( byte *p, unsigned n );
|
||||
u16 checksum_mpi( MPI a );
|
||||
u32 buffer_to_u32( const byte *buffer );
|
||||
const byte *get_session_marker( size_t *rlen );
|
||||
int openpgp_cipher_test_algo( int algo );
|
||||
int openpgp_pk_test_algo( int algo, unsigned int usage_flags );
|
||||
int openpgp_pk_algo_usage ( int algo );
|
||||
int openpgp_md_test_algo( int algo );
|
||||
|
||||
#ifdef USE_IDEA
|
||||
void idea_cipher_warn( int show );
|
||||
#else
|
||||
#define idea_cipher_warn(a)
|
||||
#endif
|
||||
|
||||
struct expando_args
|
||||
{
|
||||
PKT_public_key *pk;
|
||||
PKT_secret_key *sk;
|
||||
byte imagetype;
|
||||
};
|
||||
|
||||
char *pct_expando(const char *string,struct expando_args *args);
|
||||
int hextobyte( const char *s );
|
||||
void deprecated_warning(const char *configname,unsigned int configlineno,
|
||||
const char *option,const char *repl1,const char *repl2);
|
||||
const char *compress_algo_to_string(int algo);
|
||||
int string_to_compress_algo(const char *string);
|
||||
int check_compress_algo(int algo);
|
||||
int default_cipher_algo(void);
|
||||
int default_compress_algo(void);
|
||||
const char *compliance_option_string(void);
|
||||
void compliance_failure(void);
|
||||
|
||||
struct parse_options
|
||||
{
|
||||
char *name;
|
||||
unsigned int bit;
|
||||
};
|
||||
|
||||
int parse_options(char *str,unsigned int *options,struct parse_options *opts);
|
||||
|
||||
/*-- helptext.c --*/
|
||||
void display_online_help( const char *keyword );
|
||||
|
||||
/*-- encode.c --*/
|
||||
int encode_symmetric( const char *filename );
|
||||
int encode_store( const char *filename );
|
||||
int encode_crypt( const char *filename, STRLIST remusr );
|
||||
void encode_crypt_files(int nfiles, char **files, STRLIST remusr);
|
||||
int encrypt_filter( void *opaque, int control,
|
||||
IOBUF a, byte *buf, size_t *ret_len);
|
||||
|
||||
|
||||
/*-- sign.c --*/
|
||||
int complete_sig( PKT_signature *sig, PKT_secret_key *sk, MD_HANDLE md );
|
||||
int sign_file( STRLIST filenames, int detached, STRLIST locusr,
|
||||
int do_encrypt, STRLIST remusr, const char *outfile );
|
||||
int clearsign_file( const char *fname, STRLIST locusr, const char *outfile );
|
||||
int sign_symencrypt_file (const char *fname, STRLIST locusr);
|
||||
|
||||
/*-- sig-check.c --*/
|
||||
int check_revocation_keys (PKT_public_key *pk, PKT_signature *sig);
|
||||
int check_key_signature( KBNODE root, KBNODE node, int *is_selfsig );
|
||||
int check_key_signature2( KBNODE root, KBNODE node, PKT_public_key *check_pk,
|
||||
int *is_selfsig, u32 *r_expiredate, int *r_expired );
|
||||
|
||||
/*-- delkey.c --*/
|
||||
int delete_keys( STRLIST names, int secret, int allow_both );
|
||||
|
||||
/*-- keyedit.c --*/
|
||||
void keyedit_menu( const char *username, STRLIST locusr, STRLIST cmds,
|
||||
int sign_mode );
|
||||
void show_basic_key_info (KBNODE keyblock);
|
||||
|
||||
/*-- keygen.c --*/
|
||||
u32 ask_expire_interval(int object);
|
||||
u32 ask_expiredate(void);
|
||||
void generate_keypair( const char *fname );
|
||||
int keygen_set_std_prefs (const char *string,int personal);
|
||||
PKT_user_id *keygen_get_std_prefs (void);
|
||||
int keygen_add_key_expire( PKT_signature *sig, void *opaque );
|
||||
int keygen_add_std_prefs( PKT_signature *sig, void *opaque );
|
||||
int keygen_upd_std_prefs( PKT_signature *sig, void *opaque );
|
||||
int keygen_add_revkey(PKT_signature *sig, void *opaque);
|
||||
int generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock );
|
||||
|
||||
/*-- openfile.c --*/
|
||||
int overwrite_filep( const char *fname );
|
||||
char *make_outfile_name( const char *iname );
|
||||
char *ask_outfile_name( const char *name, size_t namelen );
|
||||
int open_outfile( const char *iname, int mode, IOBUF *a );
|
||||
IOBUF open_sigfile( const char *iname, progress_filter_context_t *pfx );
|
||||
void try_make_homedir( const char *fname );
|
||||
|
||||
/*-- seskey.c --*/
|
||||
void make_session_key( DEK *dek );
|
||||
MPI encode_session_key( DEK *dek, unsigned nbits );
|
||||
MPI encode_md_value( int pubkey_algo, MD_HANDLE md,
|
||||
int hash_algo, unsigned nbits, int v3compathack );
|
||||
|
||||
/*-- comment.c --*/
|
||||
KBNODE make_comment_node( const char *s );
|
||||
KBNODE make_mpi_comment_node( const char *s, MPI a );
|
||||
|
||||
/*-- import.c --*/
|
||||
int parse_import_options(char *str,unsigned int *options);
|
||||
void import_keys( char **fnames, int nnames,
|
||||
void *stats_hd, unsigned int options );
|
||||
int import_keys_stream( IOBUF inp,
|
||||
void *stats_hd, unsigned int options );
|
||||
void *import_new_stats_handle (void);
|
||||
void import_release_stats_handle (void *p);
|
||||
void import_print_stats (void *hd);
|
||||
|
||||
int collapse_uids( KBNODE *keyblock );
|
||||
|
||||
/*-- export.c --*/
|
||||
int parse_export_options(char *str,unsigned int *options);
|
||||
int export_pubkeys( STRLIST users, unsigned int options );
|
||||
int export_pubkeys_stream( IOBUF out, STRLIST users,
|
||||
KBNODE *keyblock_out, unsigned int options );
|
||||
int export_seckeys( STRLIST users );
|
||||
int export_secsubkeys( STRLIST users );
|
||||
|
||||
/* dearmor.c --*/
|
||||
int dearmor_file( const char *fname );
|
||||
int enarmor_file( const char *fname );
|
||||
|
||||
/*-- revoke.c --*/
|
||||
struct revocation_reason_info;
|
||||
int gen_revoke( const char *uname );
|
||||
int gen_desig_revoke( const char *uname );
|
||||
int revocation_reason_build_cb( PKT_signature *sig, void *opaque );
|
||||
struct revocation_reason_info *
|
||||
ask_revocation_reason( int key_rev, int cert_rev, int hint );
|
||||
void release_revocation_reason_info( struct revocation_reason_info *reason );
|
||||
|
||||
/*-- keylist.c --*/
|
||||
void public_key_list( STRLIST list );
|
||||
void secret_key_list( STRLIST list );
|
||||
void reorder_keyblock (KBNODE keyblock);
|
||||
void list_keyblock( KBNODE keyblock, int secret, int fpr, void *opaque );
|
||||
void print_fingerprint (PKT_public_key *pk, PKT_secret_key *sk, int mode);
|
||||
void show_policy_url(PKT_signature *sig,int indent,int mode);
|
||||
void show_notation(PKT_signature *sig,int indent,int mode);
|
||||
void dump_attribs(const PKT_user_id *uid,
|
||||
PKT_public_key *pk,PKT_secret_key *sk);
|
||||
void set_attrib_fd(int fd);
|
||||
void print_seckey_info (PKT_secret_key *sk);
|
||||
void print_pubkey_info (PKT_public_key *pk);
|
||||
|
||||
/*-- verify.c --*/
|
||||
void print_file_status( int status, const char *name, int what );
|
||||
int verify_signatures( int nfiles, char **files );
|
||||
int verify_files( int nfiles, char **files );
|
||||
|
||||
/*-- decrypt.c --*/
|
||||
int decrypt_message( const char *filename );
|
||||
void decrypt_messages(int nfiles, char **files);
|
||||
|
||||
/*-- plaintext.c --*/
|
||||
int hash_datafiles( MD_HANDLE md, MD_HANDLE md2,
|
||||
STRLIST files, const char *sigfilename, int textmode );
|
||||
|
||||
/*-- pipemode.c --*/
|
||||
void run_in_pipemode (void);
|
||||
|
||||
/*-- signal.c --*/
|
||||
void init_signals(void);
|
||||
void pause_on_sigusr( int which );
|
||||
void block_all_signals(void);
|
||||
void unblock_all_signals(void);
|
||||
|
||||
#endif /*G10_MAIN_H*/
|
1681
g10/mainproc.c
Normal file
1681
g10/mainproc.c
Normal file
File diff suppressed because it is too large
Load Diff
678
g10/misc.c
Normal file
678
g10/misc.c
Normal file
@ -0,0 +1,678 @@
|
||||
/* misc.c - miscellaneous functions
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#if defined(__linux__) && defined(__alpha__) && __GLIBC__ < 2
|
||||
#include <asm/sysinfo.h>
|
||||
#include <asm/unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_SETRLIMIT
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
#include "util.h"
|
||||
#include "main.h"
|
||||
#include "photoid.h"
|
||||
#include "options.h"
|
||||
#include "i18n.h"
|
||||
|
||||
|
||||
const char *g10m_revision_string(int);
|
||||
const char *g10c_revision_string(int);
|
||||
const char *g10u_revision_string(int);
|
||||
|
||||
#ifdef __GNUC__
|
||||
volatile
|
||||
#endif
|
||||
void
|
||||
pull_in_libs(void)
|
||||
{
|
||||
g10m_revision_string(0);
|
||||
g10c_revision_string(0);
|
||||
g10u_revision_string(0);
|
||||
}
|
||||
|
||||
|
||||
#if defined(__linux__) && defined(__alpha__) && __GLIBC__ < 2
|
||||
static int
|
||||
setsysinfo(unsigned long op, void *buffer, unsigned long size,
|
||||
int *start, void *arg, unsigned long flag)
|
||||
{
|
||||
return syscall(__NR_osf_setsysinfo, op, buffer, size, start, arg, flag);
|
||||
}
|
||||
|
||||
void
|
||||
trap_unaligned(void)
|
||||
{
|
||||
unsigned int buf[2];
|
||||
|
||||
buf[0] = SSIN_UACPROC;
|
||||
buf[1] = UAC_SIGBUS | UAC_NOPRINT;
|
||||
setsysinfo(SSI_NVPAIRS, buf, 1, 0, 0, 0);
|
||||
}
|
||||
#else
|
||||
void
|
||||
trap_unaligned(void)
|
||||
{ /* dummy */
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int
|
||||
disable_core_dumps()
|
||||
{
|
||||
#ifdef HAVE_DOSISH_SYSTEM
|
||||
return 0;
|
||||
#else
|
||||
#ifdef HAVE_SETRLIMIT
|
||||
struct rlimit limit;
|
||||
|
||||
limit.rlim_cur = 0;
|
||||
limit.rlim_max = 0;
|
||||
if( !setrlimit( RLIMIT_CORE, &limit ) )
|
||||
return 0;
|
||||
if( errno != EINVAL && errno != ENOSYS )
|
||||
log_fatal(_("can't disable core dumps: %s\n"), strerror(errno) );
|
||||
#endif
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
u16
|
||||
checksum_u16( unsigned n )
|
||||
{
|
||||
u16 a;
|
||||
|
||||
a = (n >> 8) & 0xff;
|
||||
a += n & 0xff;
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
u16
|
||||
checksum( byte *p, unsigned n )
|
||||
{
|
||||
u16 a;
|
||||
|
||||
for(a=0; n; n-- )
|
||||
a += *p++;
|
||||
return a;
|
||||
}
|
||||
|
||||
u16
|
||||
checksum_mpi( MPI a )
|
||||
{
|
||||
u16 csum;
|
||||
byte *buffer;
|
||||
unsigned nbytes;
|
||||
unsigned nbits;
|
||||
|
||||
buffer = mpi_get_buffer( a, &nbytes, NULL );
|
||||
nbits = mpi_get_nbits(a);
|
||||
csum = checksum_u16( nbits );
|
||||
csum += checksum( buffer, nbytes );
|
||||
m_free( buffer );
|
||||
return csum;
|
||||
}
|
||||
|
||||
u32
|
||||
buffer_to_u32( const byte *buffer )
|
||||
{
|
||||
unsigned long a;
|
||||
a = *buffer << 24;
|
||||
a |= buffer[1] << 16;
|
||||
a |= buffer[2] << 8;
|
||||
a |= buffer[3];
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
no_exp_algo(void)
|
||||
{
|
||||
static int did_note = 0;
|
||||
|
||||
if( !did_note ) {
|
||||
did_note = 1;
|
||||
log_info(_("Experimental algorithms should not be used!\n"));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
print_pubkey_algo_note( int algo )
|
||||
{
|
||||
if( algo >= 100 && algo <= 110 )
|
||||
no_exp_algo();
|
||||
}
|
||||
|
||||
void
|
||||
print_cipher_algo_note( int algo )
|
||||
{
|
||||
if( algo >= 100 && algo <= 110 )
|
||||
no_exp_algo();
|
||||
else if( algo == CIPHER_ALGO_3DES
|
||||
|| algo == CIPHER_ALGO_CAST5
|
||||
|| algo == CIPHER_ALGO_BLOWFISH
|
||||
|| algo == CIPHER_ALGO_TWOFISH
|
||||
|| algo == CIPHER_ALGO_RIJNDAEL
|
||||
|| algo == CIPHER_ALGO_RIJNDAEL192
|
||||
|| algo == CIPHER_ALGO_RIJNDAEL256
|
||||
)
|
||||
;
|
||||
else {
|
||||
static int did_note = 0;
|
||||
|
||||
if( !did_note ) {
|
||||
did_note = 1;
|
||||
log_info(_("this cipher algorithm is deprecated; "
|
||||
"please use a more standard one!\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
print_digest_algo_note( int algo )
|
||||
{
|
||||
if( algo >= 100 && algo <= 110 )
|
||||
no_exp_algo();
|
||||
}
|
||||
|
||||
|
||||
/* Return a string which is used as a kind of process ID */
|
||||
const byte *
|
||||
get_session_marker( size_t *rlen )
|
||||
{
|
||||
static byte marker[SIZEOF_UNSIGNED_LONG*2];
|
||||
static int initialized;
|
||||
|
||||
if ( !initialized ) {
|
||||
volatile ulong aa, bb; /* we really want the uninitialized value */
|
||||
ulong a, b;
|
||||
|
||||
initialized = 1;
|
||||
/* also this marker is guessable it is not easy to use this
|
||||
* for a faked control packet because an attacker does not
|
||||
* have enough control about the time the verification does
|
||||
* take place. Of course, we can add just more random but
|
||||
* than we need the random generator even for verification
|
||||
* tasks - which does not make sense. */
|
||||
a = aa ^ (ulong)getpid();
|
||||
b = bb ^ (ulong)time(NULL);
|
||||
memcpy( marker, &a, SIZEOF_UNSIGNED_LONG );
|
||||
memcpy( marker+SIZEOF_UNSIGNED_LONG, &b, SIZEOF_UNSIGNED_LONG );
|
||||
}
|
||||
*rlen = sizeof(marker);
|
||||
return marker;
|
||||
}
|
||||
|
||||
/****************
|
||||
* Wrapper around the libgcrypt function with addional checks on
|
||||
* openPGP contraints for the algo ID.
|
||||
*/
|
||||
int
|
||||
openpgp_cipher_test_algo( int algo )
|
||||
{
|
||||
if( algo < 0 || algo > 110 )
|
||||
return G10ERR_CIPHER_ALGO;
|
||||
return check_cipher_algo(algo);
|
||||
}
|
||||
|
||||
int
|
||||
openpgp_pk_test_algo( int algo, unsigned int usage_flags )
|
||||
{
|
||||
if( algo < 0 || algo > 110 )
|
||||
return G10ERR_PUBKEY_ALGO;
|
||||
return check_pubkey_algo2( algo, usage_flags );
|
||||
}
|
||||
|
||||
int
|
||||
openpgp_pk_algo_usage ( int algo )
|
||||
{
|
||||
int use = 0;
|
||||
|
||||
/* they are hardwired in gpg 1.0 */
|
||||
switch ( algo ) {
|
||||
case PUBKEY_ALGO_RSA:
|
||||
use = PUBKEY_USAGE_SIG | PUBKEY_USAGE_ENC;
|
||||
break;
|
||||
case PUBKEY_ALGO_RSA_E:
|
||||
use = PUBKEY_USAGE_ENC;
|
||||
break;
|
||||
case PUBKEY_ALGO_RSA_S:
|
||||
use = PUBKEY_USAGE_SIG;
|
||||
break;
|
||||
case PUBKEY_ALGO_ELGAMAL_E:
|
||||
use = PUBKEY_USAGE_ENC;
|
||||
break;
|
||||
case PUBKEY_ALGO_DSA:
|
||||
use = PUBKEY_USAGE_SIG;
|
||||
break;
|
||||
case PUBKEY_ALGO_ELGAMAL:
|
||||
use = PUBKEY_USAGE_SIG | PUBKEY_USAGE_ENC;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return use;
|
||||
}
|
||||
|
||||
int
|
||||
openpgp_md_test_algo( int algo )
|
||||
{
|
||||
if( algo < 0 || algo > 110 )
|
||||
return G10ERR_DIGEST_ALGO;
|
||||
return check_digest_algo(algo);
|
||||
}
|
||||
|
||||
#ifdef USE_IDEA
|
||||
/* Special warning for the IDEA cipher */
|
||||
void
|
||||
idea_cipher_warn(int show)
|
||||
{
|
||||
static int warned=0;
|
||||
|
||||
if(!warned || show)
|
||||
{
|
||||
log_info(_("the IDEA cipher plugin is not present\n"));
|
||||
log_info(_("please see http://www.gnupg.org/why-not-idea.html "
|
||||
"for more information\n"));
|
||||
warned=1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Expand %-strings. Returns a string which must be m_freed. Returns
|
||||
NULL if the string cannot be expanded (too large). */
|
||||
char *
|
||||
pct_expando(const char *string,struct expando_args *args)
|
||||
{
|
||||
const char *ch=string;
|
||||
int idx=0,maxlen=0,done=0;
|
||||
u32 pk_keyid[2]={0,0},sk_keyid[2]={0,0};
|
||||
char *ret=NULL;
|
||||
|
||||
if(args->pk)
|
||||
keyid_from_pk(args->pk,pk_keyid);
|
||||
|
||||
if(args->sk)
|
||||
keyid_from_sk(args->sk,sk_keyid);
|
||||
|
||||
if(!args->pk && args->sk)
|
||||
keyid_from_sk(args->sk,pk_keyid);
|
||||
|
||||
while(*ch!='\0')
|
||||
{
|
||||
char *str=NULL;
|
||||
|
||||
if(!done)
|
||||
{
|
||||
/* 8192 is way bigger than we'll need here */
|
||||
if(maxlen>=8192)
|
||||
goto fail;
|
||||
|
||||
maxlen+=1024;
|
||||
ret=m_realloc(ret,maxlen);
|
||||
}
|
||||
|
||||
done=0;
|
||||
|
||||
if(*ch=='%')
|
||||
{
|
||||
switch(*(ch+1))
|
||||
{
|
||||
case 's': /* short key id */
|
||||
if(idx+8<maxlen)
|
||||
{
|
||||
sprintf(&ret[idx],"%08lX",(ulong)sk_keyid[1]);
|
||||
idx+=8;
|
||||
done=1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'S': /* long key id */
|
||||
if(idx+16<maxlen)
|
||||
{
|
||||
sprintf(&ret[idx],"%08lX%08lX",
|
||||
(ulong)sk_keyid[0],(ulong)sk_keyid[1]);
|
||||
idx+=16;
|
||||
done=1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'k': /* short key id */
|
||||
if(idx+8<maxlen)
|
||||
{
|
||||
sprintf(&ret[idx],"%08lX",(ulong)pk_keyid[1]);
|
||||
idx+=8;
|
||||
done=1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'K': /* long key id */
|
||||
if(idx+16<maxlen)
|
||||
{
|
||||
sprintf(&ret[idx],"%08lX%08lX",
|
||||
(ulong)pk_keyid[0],(ulong)pk_keyid[1]);
|
||||
idx+=16;
|
||||
done=1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'f': /* fingerprint */
|
||||
{
|
||||
byte array[MAX_FINGERPRINT_LEN];
|
||||
size_t len;
|
||||
int i;
|
||||
|
||||
if(args->pk)
|
||||
fingerprint_from_pk(args->pk,array,&len);
|
||||
else
|
||||
memset(array,0, (len=MAX_FINGERPRINT_LEN));
|
||||
|
||||
if(idx+(len*2)<maxlen)
|
||||
{
|
||||
for(i=0;i<len;i++)
|
||||
{
|
||||
sprintf(&ret[idx],"%02X",array[i]);
|
||||
idx+=2;
|
||||
}
|
||||
done=1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 't': /* e.g. "jpg" */
|
||||
str=image_type_to_string(args->imagetype,0);
|
||||
/* fall through */
|
||||
|
||||
case 'T': /* e.g. "image/jpeg" */
|
||||
if(str==NULL)
|
||||
str=image_type_to_string(args->imagetype,2);
|
||||
|
||||
if(idx+strlen(str)<maxlen)
|
||||
{
|
||||
strcpy(&ret[idx],str);
|
||||
idx+=strlen(str);
|
||||
done=1;
|
||||
}
|
||||
break;
|
||||
|
||||
case '%':
|
||||
if(idx+1<maxlen)
|
||||
{
|
||||
ret[idx++]='%';
|
||||
ret[idx]='\0';
|
||||
done=1;
|
||||
}
|
||||
break;
|
||||
|
||||
/* Any unknown %-keys (like %i, %o, %I, and %O) are
|
||||
passed through for later expansion. Note this also
|
||||
handles the case where the last character in the
|
||||
string is a '%' - the terminating \0 will end up here
|
||||
and properly terminate the string. */
|
||||
default:
|
||||
if(idx+2<maxlen)
|
||||
{
|
||||
ret[idx++]='%';
|
||||
ret[idx++]=*(ch+1);
|
||||
ret[idx]='\0';
|
||||
done=1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if(done)
|
||||
ch++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(idx+1<maxlen)
|
||||
{
|
||||
ret[idx++]=*ch;
|
||||
ret[idx]='\0';
|
||||
done=1;
|
||||
}
|
||||
}
|
||||
|
||||
if(done)
|
||||
ch++;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
fail:
|
||||
m_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
hextobyte( const char *s )
|
||||
{
|
||||
int c;
|
||||
|
||||
if( *s >= '0' && *s <= '9' )
|
||||
c = 16 * (*s - '0');
|
||||
else if( *s >= 'A' && *s <= 'F' )
|
||||
c = 16 * (10 + *s - 'A');
|
||||
else if( *s >= 'a' && *s <= 'f' )
|
||||
c = 16 * (10 + *s - 'a');
|
||||
else
|
||||
return -1;
|
||||
s++;
|
||||
if( *s >= '0' && *s <= '9' )
|
||||
c += *s - '0';
|
||||
else if( *s >= 'A' && *s <= 'F' )
|
||||
c += 10 + *s - 'A';
|
||||
else if( *s >= 'a' && *s <= 'f' )
|
||||
c += 10 + *s - 'a';
|
||||
else
|
||||
return -1;
|
||||
return c;
|
||||
}
|
||||
|
||||
void
|
||||
deprecated_warning(const char *configname,unsigned int configlineno,
|
||||
const char *option,const char *repl1,const char *repl2)
|
||||
{
|
||||
if(configname)
|
||||
{
|
||||
if(strncmp("--",option,2)==0)
|
||||
option+=2;
|
||||
|
||||
if(strncmp("--",repl1,2)==0)
|
||||
repl1+=2;
|
||||
|
||||
log_info(_("%s:%d: deprecated option \"%s\"\n"),
|
||||
configname,configlineno,option);
|
||||
}
|
||||
else
|
||||
log_info(_("WARNING: \"%s\" is a deprecated option\n"),option);
|
||||
|
||||
log_info(_("please use \"%s%s\" instead\n"),repl1,repl2);
|
||||
}
|
||||
|
||||
const char *
|
||||
compress_algo_to_string(int algo)
|
||||
{
|
||||
const char *s="?";
|
||||
|
||||
switch(algo)
|
||||
{
|
||||
case 0:
|
||||
s="Uncompressed";
|
||||
break;
|
||||
|
||||
case 1:
|
||||
s="ZIP";
|
||||
break;
|
||||
|
||||
case 2:
|
||||
s="ZLIB";
|
||||
break;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int
|
||||
string_to_compress_algo(const char *string)
|
||||
{
|
||||
if(ascii_strcasecmp(string,"uncompressed")==0)
|
||||
return 0;
|
||||
else if(ascii_strcasecmp(string,"zip")==0)
|
||||
return 1;
|
||||
else if(ascii_strcasecmp(string,"zlib")==0)
|
||||
return 2;
|
||||
else if(ascii_strcasecmp(string,"z0")==0)
|
||||
return 0;
|
||||
else if(ascii_strcasecmp(string,"z1")==0)
|
||||
return 1;
|
||||
else if(ascii_strcasecmp(string,"z2")==0)
|
||||
return 2;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
check_compress_algo(int algo)
|
||||
{
|
||||
if(algo>=0 && algo<=2)
|
||||
return 0;
|
||||
|
||||
return G10ERR_COMPR_ALGO;
|
||||
}
|
||||
|
||||
int
|
||||
default_cipher_algo(void)
|
||||
{
|
||||
if(opt.def_cipher_algo)
|
||||
return opt.def_cipher_algo;
|
||||
else if(opt.personal_cipher_prefs)
|
||||
return opt.personal_cipher_prefs[0].value;
|
||||
else
|
||||
return opt.s2k_cipher_algo;
|
||||
}
|
||||
|
||||
/* There is no default_digest_algo function, but see
|
||||
sign.c:hash_for */
|
||||
|
||||
int
|
||||
default_compress_algo(void)
|
||||
{
|
||||
if(opt.def_compress_algo!=-1)
|
||||
return opt.def_compress_algo;
|
||||
else if(opt.personal_compress_prefs)
|
||||
return opt.personal_compress_prefs[0].value;
|
||||
else
|
||||
return DEFAULT_COMPRESS_ALGO;
|
||||
}
|
||||
|
||||
const char *
|
||||
compliance_option_string(void)
|
||||
{
|
||||
switch(opt.compliance)
|
||||
{
|
||||
case CO_RFC2440:
|
||||
return "--openpgp";
|
||||
case CO_PGP2:
|
||||
return "--pgp2";
|
||||
case CO_PGP6:
|
||||
return "--pgp6";
|
||||
case CO_PGP7:
|
||||
return "--pgp7";
|
||||
case CO_PGP8:
|
||||
return "--pgp8";
|
||||
default:
|
||||
return "???";
|
||||
}
|
||||
}
|
||||
|
||||
static const char *
|
||||
compliance_string(void)
|
||||
{
|
||||
switch(opt.compliance)
|
||||
{
|
||||
case CO_RFC2440:
|
||||
return "OpenPGP";
|
||||
case CO_PGP2:
|
||||
return "PGP 2.x";
|
||||
case CO_PGP6:
|
||||
return "PGP 6.x";
|
||||
case CO_PGP7:
|
||||
return "PGP 7.x";
|
||||
case CO_PGP8:
|
||||
return "PGP 8.x";
|
||||
default:
|
||||
return "???";
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
compliance_failure(void)
|
||||
{
|
||||
log_info(_("this message may not be usable by %s\n"),compliance_string());
|
||||
opt.compliance=CO_GNUPG;
|
||||
}
|
||||
|
||||
int
|
||||
parse_options(char *str,unsigned int *options,struct parse_options *opts)
|
||||
{
|
||||
char *tok;
|
||||
|
||||
while((tok=strsep(&str," ,")))
|
||||
{
|
||||
int i,rev=0;
|
||||
|
||||
if(tok[0]=='\0')
|
||||
continue;
|
||||
|
||||
if(ascii_strncasecmp("no-",tok,3)==0)
|
||||
{
|
||||
rev=1;
|
||||
tok+=3;
|
||||
}
|
||||
|
||||
for(i=0;opts[i].name;i++)
|
||||
{
|
||||
if(ascii_strcasecmp(opts[i].name,tok)==0)
|
||||
{
|
||||
if(rev)
|
||||
*options&=~opts[i].bit;
|
||||
else
|
||||
*options|=opts[i].bit;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!opts[i].name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
389
g10/openfile.c
Normal file
389
g10/openfile.c
Normal file
@ -0,0 +1,389 @@
|
||||
/* openfile.c
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2003 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include "util.h"
|
||||
#include "memory.h"
|
||||
#include "ttyio.h"
|
||||
#include "options.h"
|
||||
#include "main.h"
|
||||
#include "status.h"
|
||||
#include "i18n.h"
|
||||
|
||||
#ifdef USE_ONLY_8DOT3
|
||||
#define SKELEXT ".skl"
|
||||
#else
|
||||
#define SKELEXT EXTSEP_S "skel"
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_DRIVE_LETTERS) || defined (__riscos__)
|
||||
#define CMP_FILENAME(a,b) ascii_strcasecmp( (a), (b) )
|
||||
#else
|
||||
#define CMP_FILENAME(a,b) strcmp( (a), (b) )
|
||||
#endif
|
||||
|
||||
#ifdef MKDIR_TAKES_ONE_ARG
|
||||
#undef mkdir
|
||||
#define mkdir(a,b) mkdir(a)
|
||||
#endif
|
||||
|
||||
/* FIXME: Implement opt.interactive. */
|
||||
|
||||
/****************
|
||||
* Check whether FNAME exists and ask if it's okay to overwrite an
|
||||
* existing one.
|
||||
* Returns: True: it's okay to overwrite or the file does not exist
|
||||
* False: Do not overwrite
|
||||
*/
|
||||
int
|
||||
overwrite_filep( const char *fname )
|
||||
{
|
||||
if( !fname || (*fname == '-' && !fname[1]) )
|
||||
return 1; /* writing to stdout is always okay */
|
||||
|
||||
if( access( fname, F_OK ) )
|
||||
return 1; /* does not exist */
|
||||
|
||||
#ifndef HAVE_DOSISH_SYSTEM
|
||||
if ( !strcmp ( fname, "/dev/null" ) )
|
||||
return 1; /* does not do any harm */
|
||||
#endif
|
||||
|
||||
/* fixme: add some backup stuff in case of overwrite */
|
||||
if( opt.answer_yes )
|
||||
return 1;
|
||||
if( opt.answer_no || opt.batch )
|
||||
return 0; /* do not overwrite */
|
||||
|
||||
tty_printf(_("File `%s' exists. "), fname);
|
||||
if( cpr_get_answer_is_yes("openfile.overwrite.okay",
|
||||
_("Overwrite (y/N)? ")) )
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
* Strip know extensions from iname and return a newly allocated
|
||||
* filename. Return NULL if we can't do that.
|
||||
*/
|
||||
char *
|
||||
make_outfile_name( const char *iname )
|
||||
{
|
||||
size_t n;
|
||||
|
||||
if( (!iname || (*iname=='-' && !iname[1]) ))
|
||||
return m_strdup("-");
|
||||
|
||||
n = strlen(iname);
|
||||
if( n > 4 && ( !CMP_FILENAME(iname+n-4, EXTSEP_S "gpg")
|
||||
|| !CMP_FILENAME(iname+n-4, EXTSEP_S "pgp")
|
||||
|| !CMP_FILENAME(iname+n-4, EXTSEP_S "sig")
|
||||
|| !CMP_FILENAME(iname+n-4, EXTSEP_S "asc") ) ) {
|
||||
char *buf = m_strdup( iname );
|
||||
buf[n-4] = 0;
|
||||
return buf;
|
||||
}
|
||||
else if( n > 5 && !CMP_FILENAME(iname+n-5, EXTSEP_S "sign") ) {
|
||||
char *buf = m_strdup( iname );
|
||||
buf[n-5] = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
log_info(_("%s: unknown suffix\n"), iname );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
* Ask for a outputfilename and use the given one as default.
|
||||
* Return NULL if no file has been given or it is not possible to
|
||||
* ask the user.
|
||||
*/
|
||||
char *
|
||||
ask_outfile_name( const char *name, size_t namelen )
|
||||
{
|
||||
size_t n;
|
||||
const char *s;
|
||||
char *prompt;
|
||||
char *fname;
|
||||
char *defname;
|
||||
|
||||
if( opt.batch )
|
||||
return NULL;
|
||||
|
||||
s = _("Enter new filename");
|
||||
|
||||
n = strlen(s) + namelen + 10;
|
||||
defname = name && namelen? make_printable_string( name, namelen, 0): NULL;
|
||||
prompt = m_alloc(n);
|
||||
if( defname )
|
||||
sprintf(prompt, "%s [%s]: ", s, defname );
|
||||
else
|
||||
sprintf(prompt, "%s: ", s );
|
||||
fname = cpr_get("openfile.askoutname", prompt );
|
||||
cpr_kill_prompt();
|
||||
m_free(prompt);
|
||||
if( !*fname ) {
|
||||
m_free( fname ); fname = NULL;
|
||||
fname = defname; defname = NULL;
|
||||
}
|
||||
m_free(defname);
|
||||
if (fname)
|
||||
trim_spaces (fname);
|
||||
return fname;
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
* Make an output filename for the inputfile INAME.
|
||||
* Returns an IOBUF and an errorcode
|
||||
* Mode 0 = use ".gpg"
|
||||
* 1 = use ".asc"
|
||||
* 2 = use ".sig"
|
||||
*/
|
||||
int
|
||||
open_outfile( const char *iname, int mode, IOBUF *a )
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
*a = NULL;
|
||||
if( (!iname || (*iname=='-' && !iname[1])) && !opt.outfile ) {
|
||||
if( !(*a = iobuf_create(NULL)) ) {
|
||||
log_error(_("%s: can't open: %s\n"), "[stdout]", strerror(errno) );
|
||||
rc = G10ERR_CREATE_FILE;
|
||||
}
|
||||
else if( opt.verbose )
|
||||
log_info(_("writing to stdout\n"));
|
||||
}
|
||||
else {
|
||||
char *buf = NULL;
|
||||
const char *name;
|
||||
|
||||
if( opt.dry_run )
|
||||
name = "/dev/null";
|
||||
else if( opt.outfile )
|
||||
name = opt.outfile;
|
||||
else {
|
||||
#ifdef USE_ONLY_8DOT3
|
||||
if (opt.mangle_dos_filenames)
|
||||
{
|
||||
/* It is quite common DOS system to have only one dot in a
|
||||
* a filename So if we have something like this, we simple
|
||||
* replace the suffix execpt in cases where the suffix is
|
||||
* larger than 3 characters and not the same as.
|
||||
* We should really map the filenames to 8.3 but this tends to
|
||||
* be more complicated and is probaly a duty of the filesystem
|
||||
*/
|
||||
char *dot;
|
||||
const char *newsfx = mode==1 ? ".asc" :
|
||||
mode==2 ? ".sig" : ".gpg";
|
||||
|
||||
buf = m_alloc(strlen(iname)+4+1);
|
||||
strcpy(buf,iname);
|
||||
dot = strchr(buf, '.' );
|
||||
if ( dot && dot > buf && dot[1] && strlen(dot) <= 4
|
||||
&& CMP_FILENAME(newsfx, dot) )
|
||||
{
|
||||
strcpy(dot, newsfx );
|
||||
}
|
||||
else if ( dot && !dot[1] ) /* don't duplicate a dot */
|
||||
strcpy( dot, newsfx+1 );
|
||||
else
|
||||
strcat ( buf, newsfx );
|
||||
}
|
||||
if (!buf)
|
||||
#endif /* USE_ONLY_8DOT3 */
|
||||
{
|
||||
buf = m_alloc(strlen(iname)+4+1);
|
||||
strcpy(stpcpy(buf,iname), mode==1 ? EXTSEP_S "asc" :
|
||||
mode==2 ? EXTSEP_S "sig" : EXTSEP_S "gpg");
|
||||
}
|
||||
name = buf;
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
while( !overwrite_filep (name) )
|
||||
{
|
||||
char *tmp = ask_outfile_name (NULL, 0);
|
||||
if ( !tmp || !*tmp )
|
||||
{
|
||||
m_free (tmp);
|
||||
rc = G10ERR_FILE_EXISTS;
|
||||
break;
|
||||
}
|
||||
m_free (buf);
|
||||
name = buf = tmp;
|
||||
}
|
||||
|
||||
if( !rc )
|
||||
{
|
||||
if( !(*a = iobuf_create( name )) )
|
||||
{
|
||||
log_error(_("%s: can't create: %s\n"), name, strerror(errno) );
|
||||
rc = G10ERR_CREATE_FILE;
|
||||
}
|
||||
else if( opt.verbose )
|
||||
log_info(_("writing to `%s'\n"), name );
|
||||
}
|
||||
m_free(buf);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
* Try to open a file without the extension ".sig" or ".asc"
|
||||
* Return NULL if such a file is not available.
|
||||
*/
|
||||
IOBUF
|
||||
open_sigfile( const char *iname, progress_filter_context_t *pfx )
|
||||
{
|
||||
IOBUF a = NULL;
|
||||
size_t len;
|
||||
|
||||
if( iname && !(*iname == '-' && !iname[1]) ) {
|
||||
len = strlen(iname);
|
||||
if( len > 4 && ( !strcmp(iname + len - 4, EXTSEP_S "sig")
|
||||
|| ( len > 5 && !strcmp(iname + len - 5, EXTSEP_S "sign") )
|
||||
|| !strcmp(iname + len - 4, EXTSEP_S "asc")) ) {
|
||||
char *buf;
|
||||
buf = m_strdup(iname);
|
||||
buf[len-(buf[len-1]=='n'?5:4)] = 0 ;
|
||||
a = iobuf_open( buf );
|
||||
if( a && opt.verbose )
|
||||
log_info(_("assuming signed data in `%s'\n"), buf );
|
||||
if (a && pfx)
|
||||
handle_progress (pfx, a, buf);
|
||||
m_free(buf);
|
||||
}
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
/****************
|
||||
* Copy the option file skeleton to the given directory.
|
||||
*/
|
||||
static void
|
||||
copy_options_file( const char *destdir )
|
||||
{
|
||||
const char *datadir = GNUPG_DATADIR;
|
||||
char *fname;
|
||||
FILE *src, *dst;
|
||||
int linefeeds=0;
|
||||
int c;
|
||||
mode_t oldmask;
|
||||
int esc = 0;
|
||||
int any_option = 0;
|
||||
|
||||
if( opt.dry_run )
|
||||
return;
|
||||
|
||||
fname = m_alloc( strlen(datadir) + strlen(destdir) + 15 );
|
||||
strcpy(stpcpy(fname, datadir), DIRSEP_S "options" SKELEXT );
|
||||
src = fopen( fname, "r" );
|
||||
if( !src ) {
|
||||
log_error(_("%s: can't open: %s\n"), fname, strerror(errno) );
|
||||
m_free(fname);
|
||||
return;
|
||||
}
|
||||
strcpy(stpcpy(fname, destdir), DIRSEP_S "gpg" EXTSEP_S "conf" );
|
||||
oldmask=umask(077);
|
||||
dst = fopen( fname, "w" );
|
||||
umask(oldmask);
|
||||
if( !dst ) {
|
||||
log_error(_("%s: can't create: %s\n"), fname, strerror(errno) );
|
||||
fclose( src );
|
||||
m_free(fname);
|
||||
return;
|
||||
}
|
||||
|
||||
while( (c=getc(src)) != EOF ) {
|
||||
if( linefeeds < 3 ) {
|
||||
if( c == '\n' )
|
||||
linefeeds++;
|
||||
}
|
||||
else {
|
||||
putc( c, dst );
|
||||
if (c== '\n')
|
||||
esc = 1;
|
||||
else if (esc == 1) {
|
||||
if (c == ' ' || c == '\t')
|
||||
;
|
||||
else if (c == '#')
|
||||
esc = 2;
|
||||
else
|
||||
any_option = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose( dst );
|
||||
fclose( src );
|
||||
log_info(_("new configuration file `%s' created\n"), fname );
|
||||
if (any_option)
|
||||
log_info (_("WARNING: options in `%s'"
|
||||
" are not yet active during this run\n"),
|
||||
fname);
|
||||
m_free(fname);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
try_make_homedir( const char *fname )
|
||||
{
|
||||
const char *defhome = GNUPG_HOMEDIR;
|
||||
|
||||
/* Create the directory only if the supplied directory name
|
||||
* is the same as the default one. This way we avoid to create
|
||||
* arbitrary directories when a non-default homedirectory is used.
|
||||
* To cope with HOME, we do compare only the suffix if we see that
|
||||
* the default homedir does start with a tilde.
|
||||
*/
|
||||
if( opt.dry_run || opt.no_homedir_creation )
|
||||
return;
|
||||
|
||||
if ( ( *defhome == '~'
|
||||
&& ( strlen(fname) >= strlen (defhome+1)
|
||||
&& !strcmp(fname+strlen(fname)-strlen(defhome+1),
|
||||
defhome+1 ) ))
|
||||
|| ( *defhome != '~'
|
||||
&& !compare_filenames( fname, defhome ) )
|
||||
) {
|
||||
if( mkdir( fname, S_IRUSR|S_IWUSR|S_IXUSR ) )
|
||||
log_fatal( _("%s: can't create directory: %s\n"),
|
||||
fname, strerror(errno) );
|
||||
else if( !opt.quiet )
|
||||
log_info( _("%s: directory created\n"), fname );
|
||||
copy_options_file( fname );
|
||||
/* log_info(_("you have to start GnuPG again, " */
|
||||
/* "so it can read the new configuration file\n") ); */
|
||||
/* g10_exit(1); */
|
||||
}
|
||||
}
|
241
g10/options.h
Normal file
241
g10/options.h
Normal file
@ -0,0 +1,241 @@
|
||||
/* options.h
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002,
|
||||
* 2003 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifndef G10_OPTIONS_H
|
||||
#define G10_OPTIONS_H
|
||||
|
||||
#include <types.h>
|
||||
#include "main.h"
|
||||
#include "packet.h"
|
||||
|
||||
#undef ENABLE_COMMENT_PACKETS /* don't create comment packets */
|
||||
|
||||
#ifndef EXTERN_UNLESS_MAIN_MODULE
|
||||
/* Norcraft can't cope with common symbols */
|
||||
#if defined (__riscos__) && !defined (INCLUDED_BY_MAIN_MODULE)
|
||||
#define EXTERN_UNLESS_MAIN_MODULE extern
|
||||
#else
|
||||
#define EXTERN_UNLESS_MAIN_MODULE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
EXTERN_UNLESS_MAIN_MODULE
|
||||
struct {
|
||||
int verbose;
|
||||
int quiet;
|
||||
unsigned debug;
|
||||
int armor;
|
||||
int compress;
|
||||
char *outfile;
|
||||
int dry_run;
|
||||
int list_only;
|
||||
int textmode;
|
||||
int expert;
|
||||
int ask_sig_expire;
|
||||
int ask_cert_expire;
|
||||
int batch; /* run in batch mode */
|
||||
int answer_yes; /* answer yes on most questions */
|
||||
int answer_no; /* answer no on most questions */
|
||||
int check_sigs; /* check key signatures */
|
||||
int with_colons;
|
||||
int with_key_data;
|
||||
int with_fingerprint; /* opt --with-fingerprint active */
|
||||
int fingerprint; /* list fingerprints */
|
||||
int list_sigs; /* list signatures */
|
||||
int no_armor;
|
||||
int list_packets; /* list-packets mode: 1=normal, 2=invoked by command*/
|
||||
int def_cipher_algo;
|
||||
int force_v3_sigs;
|
||||
int force_v4_certs;
|
||||
int force_mdc;
|
||||
int disable_mdc;
|
||||
int def_digest_algo;
|
||||
int cert_digest_algo;
|
||||
int def_compress_algo;
|
||||
const char *def_secret_key;
|
||||
char *def_recipient;
|
||||
int def_recipient_self;
|
||||
int def_cert_check_level;
|
||||
int sk_comments;
|
||||
int no_version;
|
||||
int marginals_needed;
|
||||
int completes_needed;
|
||||
int max_cert_depth;
|
||||
const char *homedir;
|
||||
|
||||
char *display; /* 5 options to be passed to the gpg-agent */
|
||||
char *ttyname;
|
||||
char *ttytype;
|
||||
char *lc_ctype;
|
||||
char *lc_messages;
|
||||
|
||||
int skip_verify;
|
||||
int compress_keys;
|
||||
int compress_sigs;
|
||||
/* TM_CLASSIC must be zero to accomodate trustdbs generated before
|
||||
we started storing the trust model inside the trustdb. */
|
||||
enum {TM_CLASSIC=0, TM_PGP=1, TM_ALWAYS, TM_AUTO} trust_model;
|
||||
unsigned int force_ownertrust;
|
||||
enum
|
||||
{
|
||||
CO_GNUPG=0, CO_RFC2440, CO_RFC1991, CO_PGP2, CO_PGP6, CO_PGP7, CO_PGP8
|
||||
} compliance;
|
||||
int pgp2_workarounds;
|
||||
unsigned int emulate_bugs; /* bug emulation flags EMUBUG_xxxx */
|
||||
int shm_coprocess;
|
||||
const char *set_filename;
|
||||
const char *comment_string;
|
||||
int throw_keyid;
|
||||
const char *photo_viewer;
|
||||
int s2k_mode;
|
||||
int s2k_digest_algo;
|
||||
int s2k_cipher_algo;
|
||||
int simple_sk_checksum; /* create the deprecated rfc2440 secret
|
||||
key protection*/
|
||||
int not_dash_escaped;
|
||||
int escape_from;
|
||||
int lock_once;
|
||||
char *keyserver_uri;
|
||||
char *keyserver_scheme;
|
||||
char *keyserver_host;
|
||||
char *keyserver_port;
|
||||
char *keyserver_opaque;
|
||||
struct
|
||||
{
|
||||
int verbose;
|
||||
int include_revoked;
|
||||
int include_disabled;
|
||||
int include_subkeys;
|
||||
int honor_http_proxy;
|
||||
int broken_http_proxy;
|
||||
int use_temp_files;
|
||||
int keep_temp_files;
|
||||
int fake_v3_keyids;
|
||||
int auto_key_retrieve;
|
||||
int try_dns_srv;
|
||||
unsigned int import_options;
|
||||
unsigned int export_options;
|
||||
STRLIST other;
|
||||
} keyserver_options;
|
||||
int exec_disable;
|
||||
int exec_path_set;
|
||||
unsigned int import_options;
|
||||
unsigned int export_options;
|
||||
unsigned int list_options;
|
||||
unsigned int verify_options;
|
||||
char *def_preference_list;
|
||||
prefitem_t *personal_cipher_prefs;
|
||||
prefitem_t *personal_digest_prefs;
|
||||
prefitem_t *personal_compress_prefs;
|
||||
int no_perm_warn;
|
||||
int no_mdc_warn;
|
||||
char *temp_dir;
|
||||
int no_encrypt_to;
|
||||
int interactive;
|
||||
STRLIST sig_notation_data;
|
||||
STRLIST cert_notation_data;
|
||||
STRLIST sig_policy_url;
|
||||
STRLIST cert_policy_url;
|
||||
int use_embedded_filename;
|
||||
int allow_non_selfsigned_uid;
|
||||
int allow_freeform_uid;
|
||||
int no_literal;
|
||||
ulong set_filesize;
|
||||
int fast_list_mode;
|
||||
int fixed_list_mode;
|
||||
int ignore_time_conflict;
|
||||
int ignore_valid_from;
|
||||
int ignore_crc_error;
|
||||
int ignore_mdc_error;
|
||||
int command_fd;
|
||||
const char *override_session_key;
|
||||
int show_session_key;
|
||||
int use_agent;
|
||||
const char *gpg_agent_info;
|
||||
int merge_only;
|
||||
int try_all_secrets;
|
||||
int no_expensive_trust_checks;
|
||||
int no_sig_cache;
|
||||
int no_sig_create_check;
|
||||
int no_auto_check_trustdb;
|
||||
int preserve_permissions;
|
||||
int no_homedir_creation;
|
||||
struct groupitem *grouplist;
|
||||
int strict;
|
||||
int mangle_dos_filenames;
|
||||
int enable_progress_filter;
|
||||
} opt;
|
||||
|
||||
|
||||
#define EMUBUG_MDENCODE 4
|
||||
|
||||
#define DBG_PACKET_VALUE 1 /* debug packet reading/writing */
|
||||
#define DBG_MPI_VALUE 2 /* debug mpi details */
|
||||
#define DBG_CIPHER_VALUE 4 /* debug cipher handling */
|
||||
/* (may reveal sensitive data) */
|
||||
#define DBG_FILTER_VALUE 8 /* debug internal filter handling */
|
||||
#define DBG_IOBUF_VALUE 16 /* debug iobuf stuff */
|
||||
#define DBG_MEMORY_VALUE 32 /* debug memory allocation stuff */
|
||||
#define DBG_CACHE_VALUE 64 /* debug the cacheing */
|
||||
#define DBG_MEMSTAT_VALUE 128 /* show memory statistics */
|
||||
#define DBG_TRUST_VALUE 256 /* debug the trustdb */
|
||||
#define DBG_HASHING_VALUE 512 /* debug hashing operations */
|
||||
#define DBG_EXTPROG_VALUE 1024 /* debug external program calls */
|
||||
|
||||
|
||||
#define DBG_PACKET (opt.debug & DBG_PACKET_VALUE)
|
||||
#define DBG_FILTER (opt.debug & DBG_FILTER_VALUE)
|
||||
#define DBG_CACHE (opt.debug & DBG_CACHE_VALUE)
|
||||
#define DBG_TRUST (opt.debug & DBG_TRUST_VALUE)
|
||||
#define DBG_HASHING (opt.debug & DBG_HASHING_VALUE)
|
||||
#define DBG_EXTPROG (opt.debug & DBG_EXTPROG_VALUE)
|
||||
|
||||
#define GNUPG (opt.compliance==CO_GNUPG)
|
||||
#define RFC1991 (opt.compliance==CO_RFC1991 || opt.compliance==CO_PGP2)
|
||||
#define RFC2440 (opt.compliance==CO_RFC2440)
|
||||
#define PGP2 (opt.compliance==CO_PGP2)
|
||||
#define PGP6 (opt.compliance==CO_PGP6)
|
||||
#define PGP7 (opt.compliance==CO_PGP7)
|
||||
#define PGP8 (opt.compliance==CO_PGP8)
|
||||
|
||||
/* Various option flags */
|
||||
|
||||
#define IMPORT_ALLOW_LOCAL_SIGS 1
|
||||
#define IMPORT_REPAIR_PKS_SUBKEY_BUG 2
|
||||
#define IMPORT_FAST_IMPORT 4
|
||||
#define IMPORT_SK2PK 8
|
||||
|
||||
#define EXPORT_INCLUDE_NON_RFC 1
|
||||
#define EXPORT_INCLUDE_LOCAL_SIGS 2
|
||||
#define EXPORT_INCLUDE_ATTRIBUTES 4
|
||||
#define EXPORT_INCLUDE_SENSITIVE_REVKEYS 8
|
||||
|
||||
#define LIST_SHOW_PHOTOS 1
|
||||
#define LIST_SHOW_POLICY 2
|
||||
#define LIST_SHOW_NOTATION 4
|
||||
#define LIST_SHOW_KEYRING 8
|
||||
#define LIST_SHOW_VALIDITY 16
|
||||
#define LIST_SHOW_LONG_KEYID 32
|
||||
|
||||
#define VERIFY_SHOW_PHOTOS 1
|
||||
#define VERIFY_SHOW_POLICY 2
|
||||
#define VERIFY_SHOW_NOTATION 4
|
||||
|
||||
#endif /*G10_OPTIONS_H*/
|
208
g10/options.skel
Normal file
208
g10/options.skel
Normal file
@ -0,0 +1,208 @@
|
||||
# These first three lines are not copied to the gpg.conf file in
|
||||
# the users home directory.
|
||||
# $Id$
|
||||
# Options for GnuPG
|
||||
# Copyright 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; as a special exception the author gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
#
|
||||
# This file is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# Unless you specify which option file to use (with the command line
|
||||
# option "--options filename"), GnuPG uses the file ~/.gnupg/gpg.conf
|
||||
# by default.
|
||||
#
|
||||
# An options file can contain any long options which are available in
|
||||
# GnuPG. If the first non white space character of a line is a '#',
|
||||
# this line is ignored. Empty lines are also ignored.
|
||||
#
|
||||
# See the man page for a list of options.
|
||||
|
||||
# Uncomment the following option to get rid of the copyright notice
|
||||
|
||||
#no-greeting
|
||||
|
||||
# If you have more than 1 secret key in your keyring, you may want to
|
||||
# uncomment the following option and set your preferred keyid.
|
||||
|
||||
#default-key 621CC013
|
||||
|
||||
# If you do not pass a recipient to gpg, it will ask for one. Using
|
||||
# this option you can encrypt to a default key. Key validation will
|
||||
# not be done in this case. The second form uses the default key as
|
||||
# default recipient.
|
||||
|
||||
#default-recipient some-user-id
|
||||
#default-recipient-self
|
||||
|
||||
# By default GnuPG creates version 3 signatures for data files. This
|
||||
# is not strictly OpenPGP compliant but PGP 6 and most versions of PGP
|
||||
# 7 require them. To disable this behavior, you may use this option
|
||||
# or --openpgp.
|
||||
|
||||
#no-force-v3-sigs
|
||||
|
||||
# Because some mailers change lines starting with "From " to ">From "
|
||||
# it is good to handle such lines in a special way when creating
|
||||
# cleartext signatures; all other PGP versions do it this way too.
|
||||
# To enable full OpenPGP compliance you may want to use this option.
|
||||
|
||||
#no-escape-from-lines
|
||||
|
||||
# If you do not use the Latin-1 (ISO-8859-1) charset, you should tell
|
||||
# GnuPG which is the native character set. Please check the man page
|
||||
# for supported character sets. This character set is only used for
|
||||
# metadata and not for the actual message which does not undergo any
|
||||
# translation. Note that future version of GnuPG will change to UTF-8
|
||||
# as default character set.
|
||||
|
||||
#charset utf-8
|
||||
|
||||
# Group names may be defined like this:
|
||||
# group mynames = paige 0x12345678 joe patti
|
||||
#
|
||||
# Any time "mynames" is a recipient (-r or --recipient), it will be
|
||||
# expanded to the names "paige", "joe", and "patti", and the key ID
|
||||
# "0x12345678". Note there is only one level of expansion - you
|
||||
# cannot make an group that points to another group. Note also that
|
||||
# if there are spaces in the recipient name, this will appear as two
|
||||
# recipients. In these cases it is better to use the key ID.
|
||||
|
||||
#group mynames = paige 0x12345678 joe patti
|
||||
|
||||
# Some old Windows platforms require 8.3 filenames. If your system
|
||||
# can handle long filenames, uncomment this.
|
||||
|
||||
#no-mangle-dos-filenames
|
||||
|
||||
# Lock the file only once for the lifetime of a process. If you do
|
||||
# not define this, the lock will be obtained and released every time
|
||||
# it is needed - normally this is not needed.
|
||||
|
||||
#lock-once
|
||||
|
||||
# GnuPG can send and receive keys to and from a keyserver. These
|
||||
# servers can be HKP, email, or LDAP (if GnuPG is built with LDAP
|
||||
# support).
|
||||
#
|
||||
# Example HKP keyserver:
|
||||
# x-hkp://pgp.mit.edu
|
||||
#
|
||||
# Example email keyserver:
|
||||
# mailto:pgp-public-keys@keys.nl.pgp.net
|
||||
#
|
||||
# Example LDAP keyservers:
|
||||
# ldap://pgp.surfnet.nl:11370
|
||||
# ldap://keyserver.pgp.com
|
||||
#
|
||||
# Regular URL syntax applies, and you can set an alternate port
|
||||
# through the usual method:
|
||||
# x-hkp://keyserver.example.net:22742
|
||||
#
|
||||
# If you have problems connecting to a HKP server through a buggy http
|
||||
# proxy, you can use keyserver option broken-http-proxy (see below),
|
||||
# but first you should make sure that you have read the man page
|
||||
# regarding proxies (keyserver option honor-http-proxy)
|
||||
#
|
||||
# Most users just set the name and type of their preferred keyserver.
|
||||
# Most servers do synchronize with each other and DNS round-robin may
|
||||
# give you a quasi-random server each time.
|
||||
|
||||
#keyserver x-hkp://pgp.mit.edu
|
||||
#keyserver mailto:pgp-public-keys@keys.nl.pgp.net
|
||||
#keyserver ldap://pgp.surfnet.nl:11370
|
||||
#keyserver ldap://keyserver.pgp.com
|
||||
|
||||
# Common options for keyserver functions:
|
||||
#
|
||||
# include-disabled = when searching, include keys marked as "disabled"
|
||||
# on the keyserver (not all keyservers support this).
|
||||
#
|
||||
# no-include-revoked = when searching, do not include keys marked as
|
||||
# "revoked" on the keyserver.
|
||||
#
|
||||
# verbose = show more information as the keys are fetched.
|
||||
# Can be used more than once to increase the amount
|
||||
# of information shown.
|
||||
#
|
||||
# use-temp-files = use temporary files instead of a pipe to talk to the
|
||||
# keyserver. Some platforms (Win32 for one) always
|
||||
# have this on.
|
||||
#
|
||||
# keep-temp-files = do not delete temporary files after using them
|
||||
# (really only useful for debugging)
|
||||
#
|
||||
# honor-http-proxy = if the keyserver uses HTTP, honor the http_proxy
|
||||
# environment variable
|
||||
#
|
||||
# broken-http-proxy = try to work around a buggy HTTP proxy
|
||||
#
|
||||
# auto-key-retrieve = automatically fetch keys as needed from the keyserver
|
||||
# when verifying signatures or when importing keys that
|
||||
# have been revoked by a revocation key that is not
|
||||
# present on the keyring.
|
||||
#
|
||||
# no-include-attributes = do not include attribute IDs (aka "photo IDs")
|
||||
# when sending keys to the keyserver.
|
||||
|
||||
#keyserver-options auto-key-retrieve
|
||||
|
||||
# Uncomment this line to display photo user IDs in key listings and
|
||||
# when a signature from a key with a photo is verified.
|
||||
|
||||
#show-photos
|
||||
|
||||
# Use this program to display photo user IDs
|
||||
#
|
||||
# %i is expanded to a temporary file that contains the photo.
|
||||
# %I is the same as %i, but the file isn't deleted afterwards by GnuPG.
|
||||
# %k is expanded to the key ID of the key.
|
||||
# %K is expanded to the long OpenPGP key ID of the key.
|
||||
# %t is expanded to the extension of the image (e.g. "jpg").
|
||||
# %T is expanded to the MIME type of the image (e.g. "image/jpeg").
|
||||
# %f is expanded to the fingerprint of the key.
|
||||
# %% is %, of course.
|
||||
#
|
||||
# If %i or %I are not present, then the photo is supplied to the
|
||||
# viewer on standard input. If your platform supports it, standard
|
||||
# input is the best way to do this as it avoids the time and effort in
|
||||
# generating and then cleaning up a secure temp file.
|
||||
#
|
||||
# The default program is "xloadimage -fork -quiet -title 'KeyID 0x%k' stdin"
|
||||
# On Mac OS X and Windows, the default is to use your regular JPEG image
|
||||
# viewer.
|
||||
#
|
||||
# Some other viewers:
|
||||
# photo-viewer "qiv %i"
|
||||
# photo-viewer "ee %i"
|
||||
# photo-viewer "display -title 'KeyID 0x%k'"
|
||||
#
|
||||
# This one saves a copy of the photo ID in your home directory:
|
||||
# photo-viewer "cat > ~/photoid-for-key-%k.%t"
|
||||
#
|
||||
# Use your MIME handler to view photos:
|
||||
# photo-viewer "metamail -q -d -b -c %T -s 'KeyID 0x%k' -f GnuPG"
|
||||
|
||||
# Passphrase agent
|
||||
#
|
||||
# We support the old experimental passphrase agent protocol as well as
|
||||
# the new Assuan based one (currently available in the "newpg" package
|
||||
# at ftp.gnupg.org/gcrypt/alpha/aegypten/). To make use of the agent,
|
||||
# you have to run an agent as daemon and use the option
|
||||
#
|
||||
# use-agent
|
||||
#
|
||||
# which tries to use the agent but will fallback to the regular mode
|
||||
# if there is a problem connecting to the agent. The normal way to
|
||||
# locate the agent is by looking at the environment variable
|
||||
# GPG_AGENT_INFO which should have been set during gpg-agent startup.
|
||||
# In certain situations the use of this variable is not possible, thus
|
||||
# the option
|
||||
#
|
||||
# --gpg-agent-info=<path>:<pid>:1
|
||||
#
|
||||
# may be used to override it.
|
510
g10/packet.h
Normal file
510
g10/packet.h
Normal file
@ -0,0 +1,510 @@
|
||||
/* packet.h - packet definitions
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef G10_PACKET_H
|
||||
#define G10_PACKET_H
|
||||
|
||||
#include "types.h"
|
||||
#include "iobuf.h"
|
||||
#include "mpi.h"
|
||||
#include "cipher.h"
|
||||
#include "filter.h"
|
||||
#include "global.h"
|
||||
|
||||
#define DEBUG_PARSE_PACKET 1
|
||||
|
||||
typedef enum {
|
||||
PKT_NONE =0,
|
||||
PKT_PUBKEY_ENC =1, /* public key encrypted packet */
|
||||
PKT_SIGNATURE =2, /* secret key encrypted packet */
|
||||
PKT_SYMKEY_ENC =3, /* session key packet (OpenPGP)*/
|
||||
PKT_ONEPASS_SIG =4, /* one pass sig packet (OpenPGP)*/
|
||||
PKT_SECRET_KEY =5, /* secret key */
|
||||
PKT_PUBLIC_KEY =6, /* public key */
|
||||
PKT_SECRET_SUBKEY =7, /* secret subkey (OpenPGP) */
|
||||
PKT_COMPRESSED =8, /* compressed data packet */
|
||||
PKT_ENCRYPTED =9, /* conventional encrypted data */
|
||||
PKT_MARKER =10, /* marker packet (OpenPGP) */
|
||||
PKT_PLAINTEXT =11, /* plaintext data with filename and mode */
|
||||
PKT_RING_TRUST =12, /* keyring trust packet */
|
||||
PKT_USER_ID =13, /* user id packet */
|
||||
PKT_PUBLIC_SUBKEY =14, /* public subkey (OpenPGP) */
|
||||
PKT_OLD_COMMENT =16, /* comment packet from an OpenPGP draft */
|
||||
PKT_ATTRIBUTE =17, /* PGP's attribute packet */
|
||||
PKT_ENCRYPTED_MDC =18, /* integrity protected encrypted data */
|
||||
PKT_MDC =19, /* manipulation detection code packet */
|
||||
PKT_COMMENT =61, /* new comment packet (private) */
|
||||
PKT_GPG_CONTROL =63 /* internal control packet */
|
||||
} pkttype_t;
|
||||
|
||||
typedef struct packet_struct PACKET;
|
||||
|
||||
/* PKT_GPG_CONTROL types */
|
||||
typedef enum {
|
||||
CTRLPKT_CLEARSIGN_START = 1,
|
||||
CTRLPKT_PIPEMODE = 2,
|
||||
CTRLPKT_PLAINTEXT_MARK =3
|
||||
} ctrlpkttype_t;
|
||||
|
||||
typedef enum {
|
||||
PREFTYPE_NONE = 0,
|
||||
PREFTYPE_SYM = 1,
|
||||
PREFTYPE_HASH = 2,
|
||||
PREFTYPE_ZIP = 3
|
||||
} preftype_t;
|
||||
|
||||
typedef struct {
|
||||
byte type;
|
||||
byte value;
|
||||
} prefitem_t;
|
||||
|
||||
typedef struct {
|
||||
int mode;
|
||||
byte hash_algo;
|
||||
byte salt[8];
|
||||
u32 count;
|
||||
} STRING2KEY;
|
||||
|
||||
typedef struct {
|
||||
byte version;
|
||||
byte cipher_algo; /* cipher algorithm used */
|
||||
STRING2KEY s2k;
|
||||
byte seskeylen; /* keylength in byte or 0 for no seskey */
|
||||
byte seskey[1];
|
||||
} PKT_symkey_enc;
|
||||
|
||||
typedef struct {
|
||||
u32 keyid[2]; /* 64 bit keyid */
|
||||
byte version;
|
||||
byte pubkey_algo; /* algorithm used for public key scheme */
|
||||
byte throw_keyid;
|
||||
MPI data[PUBKEY_MAX_NENC];
|
||||
} PKT_pubkey_enc;
|
||||
|
||||
|
||||
typedef struct {
|
||||
u32 keyid[2]; /* 64 bit keyid */
|
||||
byte sig_class; /* sig classification */
|
||||
byte digest_algo; /* algorithm used for digest */
|
||||
byte pubkey_algo; /* algorithm used for public key scheme */
|
||||
byte last; /* a stupid flag */
|
||||
} PKT_onepass_sig;
|
||||
|
||||
|
||||
typedef struct {
|
||||
size_t size; /* allocated */
|
||||
size_t len; /* used */
|
||||
byte data[1];
|
||||
} subpktarea_t;
|
||||
|
||||
struct revocation_key {
|
||||
byte class;
|
||||
byte algid;
|
||||
byte fpr[MAX_FINGERPRINT_LEN];
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
ulong local_id; /* internal use, valid if > 0 */
|
||||
struct {
|
||||
unsigned checked:1; /* signature has been checked */
|
||||
unsigned valid:1; /* signature is good (if checked is set) */
|
||||
unsigned unknown_critical:1;
|
||||
unsigned exportable:1;
|
||||
unsigned revocable:1;
|
||||
unsigned policy_url:1; /* Policy URL is present */
|
||||
unsigned notation:1; /* At least one notation is present */
|
||||
unsigned expired:1;
|
||||
} flags;
|
||||
u32 keyid[2]; /* 64 bit keyid */
|
||||
u32 timestamp; /* signature made */
|
||||
u32 expiredate; /* expires at this date or 0 if not at all */
|
||||
byte version;
|
||||
byte sig_class; /* sig classification, append for MD calculation*/
|
||||
byte pubkey_algo; /* algorithm used for public key scheme */
|
||||
/* (PUBKEY_ALGO_xxx) */
|
||||
byte digest_algo; /* algorithm used for digest (DIGEST_ALGO_xxxx) */
|
||||
byte trust_depth;
|
||||
byte trust_value;
|
||||
const byte *trust_regexp;
|
||||
struct revocation_key **revkey;
|
||||
int numrevkeys;
|
||||
subpktarea_t *hashed; /* all subpackets with hashed data (v4 only) */
|
||||
subpktarea_t *unhashed; /* ditto for unhashed data */
|
||||
byte digest_start[2]; /* first 2 bytes of the digest */
|
||||
MPI data[PUBKEY_MAX_NSIG];
|
||||
} PKT_signature;
|
||||
|
||||
#define ATTRIB_IMAGE 1
|
||||
|
||||
/* This is the cooked form of attributes */
|
||||
struct user_attribute {
|
||||
byte type;
|
||||
const byte *data;
|
||||
u32 len;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int ref; /* reference counter */
|
||||
int len; /* length of the name */
|
||||
struct user_attribute *attribs;
|
||||
int numattribs;
|
||||
byte *attrib_data; /* if this is not NULL, the packet is an attribute */
|
||||
unsigned long attrib_len;
|
||||
byte *namehash;
|
||||
int help_key_usage;
|
||||
u32 help_key_expire;
|
||||
int help_full_count;
|
||||
int help_marginal_count;
|
||||
int is_primary; /* 2 if set via the primary flag, 1 if calculated */
|
||||
int is_revoked;
|
||||
int is_expired;
|
||||
u32 expiredate; /* expires at this date or 0 if not at all */
|
||||
prefitem_t *prefs; /* list of preferences (may be NULL)*/
|
||||
int mdc_feature;
|
||||
int ks_modify;
|
||||
u32 created; /* according to the self-signature */
|
||||
byte selfsigversion;
|
||||
char name[1];
|
||||
} PKT_user_id;
|
||||
|
||||
|
||||
/****************
|
||||
* Note about the pkey/skey elements: We assume that the secret keys
|
||||
* has the same elemts as the public key at the begin of the array, so
|
||||
* that npkey < nskey and it is possible to compare the secret and
|
||||
* public keys by comparing the first npkey elements of pkey againts skey.
|
||||
*/
|
||||
typedef struct {
|
||||
u32 timestamp; /* key made */
|
||||
u32 expiredate; /* expires at this date or 0 if not at all */
|
||||
u32 max_expiredate; /* must not expire past this date */
|
||||
byte hdrbytes; /* number of header bytes */
|
||||
byte version;
|
||||
byte selfsigversion; /* highest version of all of the self-sigs */
|
||||
byte pubkey_algo; /* algorithm used for public key scheme */
|
||||
byte pubkey_usage; /* for now only used to pass it to getkey() */
|
||||
byte req_usage; /* hack to pass a request to getkey() */
|
||||
byte req_algo; /* Ditto */
|
||||
u32 has_expired; /* set to the expiration date if expired */
|
||||
int is_revoked; /* key has been revoked */
|
||||
int is_valid; /* key (especially subkey) is valid */
|
||||
int dont_cache; /* do not cache this */
|
||||
ulong local_id; /* internal use, valid if > 0 */
|
||||
u32 main_keyid[2]; /* keyid of the primary key */
|
||||
u32 keyid[2]; /* calculated by keyid_from_pk() */
|
||||
byte is_primary;
|
||||
byte is_disabled; /* 0 for unset, 1 for enabled, 2 for disabled. */
|
||||
prefitem_t *prefs; /* list of preferences (may be NULL) */
|
||||
int mdc_feature; /* mdc feature set */
|
||||
PKT_user_id *user_id; /* if != NULL: found by that uid */
|
||||
struct revocation_key *revkey;
|
||||
int numrevkeys;
|
||||
u32 trust_timestamp;
|
||||
byte trust_depth;
|
||||
byte trust_value;
|
||||
const byte *trust_regexp;
|
||||
MPI pkey[PUBKEY_MAX_NPKEY];
|
||||
} PKT_public_key;
|
||||
|
||||
/* Evaluates as true if the pk is disabled, and false if it isn't. If
|
||||
there is no disable value cached, fill one in. */
|
||||
#define pk_is_disabled(a) (((a)->is_disabled)?((a)->is_disabled==2):(cache_disabled_value((a))))
|
||||
|
||||
typedef struct {
|
||||
u32 timestamp; /* key made */
|
||||
u32 expiredate; /* expires at this date or 0 if not at all */
|
||||
u32 max_expiredate; /* must not expire past this date */
|
||||
byte hdrbytes; /* number of header bytes */
|
||||
byte version;
|
||||
byte pubkey_algo; /* algorithm used for public key scheme */
|
||||
byte pubkey_usage;
|
||||
byte req_usage;
|
||||
byte req_algo;
|
||||
u32 has_expired; /* set to the expiration date if expired */
|
||||
int is_revoked; /* key has been revoked */
|
||||
int is_valid; /* key (especially subkey) is valid */
|
||||
u32 main_keyid[2]; /* keyid of the primary key */
|
||||
u32 keyid[2];
|
||||
byte is_primary;
|
||||
byte is_protected; /* The secret info is protected and must */
|
||||
/* be decrypted before use, the protected */
|
||||
/* MPIs are simply (void*) pointers to memory */
|
||||
/* and should never be passed to a mpi_xxx() */
|
||||
struct {
|
||||
byte algo; /* cipher used to protect the secret information*/
|
||||
byte sha1chk; /* SHA1 is used instead of a 16 bit checksum */
|
||||
STRING2KEY s2k;
|
||||
byte ivlen; /* used length of the iv */
|
||||
byte iv[16]; /* initialization vector for CFB mode */
|
||||
} protect;
|
||||
MPI skey[PUBKEY_MAX_NSKEY];
|
||||
u16 csum; /* checksum */
|
||||
} PKT_secret_key;
|
||||
|
||||
|
||||
typedef struct {
|
||||
int len; /* length of data */
|
||||
char data[1];
|
||||
} PKT_comment;
|
||||
|
||||
typedef struct {
|
||||
u32 len; /* reserved */
|
||||
byte new_ctb;
|
||||
byte algorithm;
|
||||
IOBUF buf; /* IOBUF reference */
|
||||
} PKT_compressed;
|
||||
|
||||
typedef struct {
|
||||
u32 len; /* length of encrypted data */
|
||||
int extralen; /* this is (blocksize+2) */
|
||||
byte new_ctb; /* uses a new CTB */
|
||||
byte mdc_method; /* > 0: integrity protected encrypted data packet */
|
||||
IOBUF buf; /* IOBUF reference */
|
||||
} PKT_encrypted;
|
||||
|
||||
typedef struct {
|
||||
byte hash[20];
|
||||
} PKT_mdc;
|
||||
|
||||
typedef struct {
|
||||
unsigned int trustval;
|
||||
unsigned int sigcache;
|
||||
} PKT_ring_trust;
|
||||
|
||||
typedef struct {
|
||||
u32 len; /* length of encrypted data */
|
||||
IOBUF buf; /* IOBUF reference */
|
||||
byte new_ctb;
|
||||
byte is_partial; /* partial length encoded */
|
||||
int mode;
|
||||
u32 timestamp;
|
||||
int namelen;
|
||||
char name[1];
|
||||
} PKT_plaintext;
|
||||
|
||||
typedef struct {
|
||||
int control;
|
||||
size_t datalen;
|
||||
char data[1];
|
||||
} PKT_gpg_control;
|
||||
|
||||
/* combine all packets into a union */
|
||||
struct packet_struct {
|
||||
pkttype_t pkttype;
|
||||
union {
|
||||
void *generic;
|
||||
PKT_symkey_enc *symkey_enc; /* PKT_SYMKEY_ENC */
|
||||
PKT_pubkey_enc *pubkey_enc; /* PKT_PUBKEY_ENC */
|
||||
PKT_onepass_sig *onepass_sig; /* PKT_ONEPASS_SIG */
|
||||
PKT_signature *signature; /* PKT_SIGNATURE */
|
||||
PKT_public_key *public_key; /* PKT_PUBLIC_[SUB)KEY */
|
||||
PKT_secret_key *secret_key; /* PKT_SECRET_[SUB]KEY */
|
||||
PKT_comment *comment; /* PKT_COMMENT */
|
||||
PKT_user_id *user_id; /* PKT_USER_ID */
|
||||
PKT_compressed *compressed; /* PKT_COMPRESSED */
|
||||
PKT_encrypted *encrypted; /* PKT_ENCRYPTED[_MDC] */
|
||||
PKT_mdc *mdc; /* PKT_MDC */
|
||||
PKT_ring_trust *ring_trust; /* PKT_RING_TRUST */
|
||||
PKT_plaintext *plaintext; /* PKT_PLAINTEXT */
|
||||
PKT_gpg_control *gpg_control; /* PKT_GPG_CONTROL */
|
||||
} pkt;
|
||||
};
|
||||
|
||||
#define init_packet(a) do { (a)->pkttype = 0; \
|
||||
(a)->pkt.generic = NULL; \
|
||||
} while(0)
|
||||
|
||||
typedef enum {
|
||||
SIGSUBPKT_TEST_CRITICAL=-3,
|
||||
SIGSUBPKT_LIST_UNHASHED=-2,
|
||||
SIGSUBPKT_LIST_HASHED =-1,
|
||||
SIGSUBPKT_NONE = 0,
|
||||
SIGSUBPKT_SIG_CREATED = 2, /* signature creation time */
|
||||
SIGSUBPKT_SIG_EXPIRE = 3, /* signature expiration time */
|
||||
SIGSUBPKT_EXPORTABLE = 4, /* exportable */
|
||||
SIGSUBPKT_TRUST = 5, /* trust signature */
|
||||
SIGSUBPKT_REGEXP = 6, /* regular expression */
|
||||
SIGSUBPKT_REVOCABLE = 7, /* revocable */
|
||||
SIGSUBPKT_KEY_EXPIRE = 9, /* key expiration time */
|
||||
SIGSUBPKT_ARR =10, /* additional recipient request */
|
||||
SIGSUBPKT_PREF_SYM =11, /* preferred symmetric algorithms */
|
||||
SIGSUBPKT_REV_KEY =12, /* revocation key */
|
||||
SIGSUBPKT_ISSUER =16, /* issuer key ID */
|
||||
SIGSUBPKT_NOTATION =20, /* notation data */
|
||||
SIGSUBPKT_PREF_HASH =21, /* preferred hash algorithms */
|
||||
SIGSUBPKT_PREF_COMPR =22, /* preferred compression algorithms */
|
||||
SIGSUBPKT_KS_FLAGS =23, /* key server preferences */
|
||||
SIGSUBPKT_PREF_KS =24, /* preferred key server */
|
||||
SIGSUBPKT_PRIMARY_UID =25, /* primary user id */
|
||||
SIGSUBPKT_POLICY =26, /* policy URL */
|
||||
SIGSUBPKT_KEY_FLAGS =27, /* key flags */
|
||||
SIGSUBPKT_SIGNERS_UID =28, /* signer's user id */
|
||||
SIGSUBPKT_REVOC_REASON =29, /* reason for revocation */
|
||||
SIGSUBPKT_FEATURES =30, /* feature flags */
|
||||
|
||||
SIGSUBPKT_FLAG_CRITICAL=128
|
||||
} sigsubpkttype_t;
|
||||
|
||||
|
||||
/*-- mainproc.c --*/
|
||||
int proc_packets( void *ctx, IOBUF a );
|
||||
int proc_signature_packets( void *ctx, IOBUF a,
|
||||
STRLIST signedfiles, const char *sigfile );
|
||||
int proc_encryption_packets( void *ctx, IOBUF a );
|
||||
int list_packets( IOBUF a );
|
||||
|
||||
/*-- parse-packet.c --*/
|
||||
int set_packet_list_mode( int mode );
|
||||
|
||||
#if DEBUG_PARSE_PACKET
|
||||
int dbg_search_packet( IOBUF inp, PACKET *pkt, off_t *retpos, int with_uid,
|
||||
const char* file, int lineno );
|
||||
int dbg_parse_packet( IOBUF inp, PACKET *ret_pkt,
|
||||
const char* file, int lineno );
|
||||
int dbg_copy_all_packets( IOBUF inp, IOBUF out,
|
||||
const char* file, int lineno );
|
||||
int dbg_copy_some_packets( IOBUF inp, IOBUF out, off_t stopoff,
|
||||
const char* file, int lineno );
|
||||
int dbg_skip_some_packets( IOBUF inp, unsigned n,
|
||||
const char* file, int lineno );
|
||||
#define search_packet( a,b,c,d ) \
|
||||
dbg_search_packet( (a), (b), (c), (d), __FILE__, __LINE__ )
|
||||
#define parse_packet( a, b ) \
|
||||
dbg_parse_packet( (a), (b), __FILE__, __LINE__ )
|
||||
#define copy_all_packets( a,b ) \
|
||||
dbg_copy_all_packets((a),(b), __FILE__, __LINE__ )
|
||||
#define copy_some_packets( a,b,c ) \
|
||||
dbg_copy_some_packets((a),(b),(c), __FILE__, __LINE__ )
|
||||
#define skip_some_packets( a,b ) \
|
||||
dbg_skip_some_packets((a),(b), __FILE__, __LINE__ )
|
||||
#else
|
||||
int search_packet( IOBUF inp, PACKET *pkt, off_t *retpos, int with_uid );
|
||||
int parse_packet( IOBUF inp, PACKET *ret_pkt);
|
||||
int copy_all_packets( IOBUF inp, IOBUF out );
|
||||
int copy_some_packets( IOBUF inp, IOBUF out, off_t stopoff );
|
||||
int skip_some_packets( IOBUF inp, unsigned n );
|
||||
#endif
|
||||
|
||||
const byte *enum_sig_subpkt ( const subpktarea_t *subpkts,
|
||||
sigsubpkttype_t reqtype,
|
||||
size_t *ret_n, int *start, int *critical );
|
||||
const byte *parse_sig_subpkt ( const subpktarea_t *buffer,
|
||||
sigsubpkttype_t reqtype,
|
||||
size_t *ret_n );
|
||||
const byte *parse_sig_subpkt2 ( PKT_signature *sig,
|
||||
sigsubpkttype_t reqtype,
|
||||
size_t *ret_n );
|
||||
int parse_one_sig_subpkt( const byte *buffer, size_t n, int type );
|
||||
void parse_revkeys(PKT_signature *sig);
|
||||
int parse_attribute_subpkts(PKT_user_id *uid);
|
||||
void make_attribute_uidname(PKT_user_id *uid, size_t max_namelen);
|
||||
PACKET *create_gpg_control ( ctrlpkttype_t type,
|
||||
const byte *data,
|
||||
size_t datalen );
|
||||
|
||||
/*-- build-packet.c --*/
|
||||
int build_packet( IOBUF inp, PACKET *pkt );
|
||||
u32 calc_packet_length( PACKET *pkt );
|
||||
void hash_public_key( MD_HANDLE md, PKT_public_key *pk );
|
||||
void build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type,
|
||||
const byte *buffer, size_t buflen );
|
||||
void build_sig_subpkt_from_sig( PKT_signature *sig );
|
||||
int delete_sig_subpkt(subpktarea_t *buffer, sigsubpkttype_t type );
|
||||
void build_attribute_subpkt(PKT_user_id *uid,byte type,
|
||||
const void *buf,u32 buflen,
|
||||
const void *header,u32 headerlen);
|
||||
|
||||
/*-- free-packet.c --*/
|
||||
void free_symkey_enc( PKT_symkey_enc *enc );
|
||||
void free_pubkey_enc( PKT_pubkey_enc *enc );
|
||||
void free_seckey_enc( PKT_signature *enc );
|
||||
int digest_algo_from_sig( PKT_signature *sig );
|
||||
void release_public_key_parts( PKT_public_key *pk );
|
||||
void free_public_key( PKT_public_key *key );
|
||||
void release_secret_key_parts( PKT_secret_key *sk );
|
||||
void free_secret_key( PKT_secret_key *sk );
|
||||
void free_attributes(PKT_user_id *uid);
|
||||
void free_user_id( PKT_user_id *uid );
|
||||
void free_comment( PKT_comment *rem );
|
||||
void free_packet( PACKET *pkt );
|
||||
prefitem_t *copy_prefs (const prefitem_t *prefs);
|
||||
PKT_public_key *copy_public_key( PKT_public_key *d, PKT_public_key *s );
|
||||
void copy_public_parts_to_secret_key( PKT_public_key *pk, PKT_secret_key *sk );
|
||||
PKT_secret_key *copy_secret_key( PKT_secret_key *d, PKT_secret_key *s );
|
||||
PKT_signature *copy_signature( PKT_signature *d, PKT_signature *s );
|
||||
PKT_user_id *scopy_user_id (PKT_user_id *sd );
|
||||
int cmp_public_keys( PKT_public_key *a, PKT_public_key *b );
|
||||
int cmp_secret_keys( PKT_secret_key *a, PKT_secret_key *b );
|
||||
int cmp_signatures( PKT_signature *a, PKT_signature *b );
|
||||
int cmp_public_secret_key( PKT_public_key *pk, PKT_secret_key *sk );
|
||||
int cmp_user_ids( PKT_user_id *a, PKT_user_id *b );
|
||||
|
||||
|
||||
/*-- sig-check.c --*/
|
||||
int signature_check( PKT_signature *sig, MD_HANDLE digest );
|
||||
int signature_check2( PKT_signature *sig, MD_HANDLE digest,
|
||||
u32 *r_expiredate, int *r_expired );
|
||||
|
||||
/*-- seckey-cert.c --*/
|
||||
int is_secret_key_protected( PKT_secret_key *sk );
|
||||
int check_secret_key( PKT_secret_key *sk, int retries );
|
||||
int protect_secret_key( PKT_secret_key *sk, DEK *dek );
|
||||
|
||||
/*-- pubkey-enc.c --*/
|
||||
int get_session_key( PKT_pubkey_enc *k, DEK *dek );
|
||||
int get_override_session_key( DEK *dek, const char *string );
|
||||
|
||||
/*-- compress.c --*/
|
||||
int handle_compressed( void *ctx, PKT_compressed *cd,
|
||||
int (*callback)(IOBUF, void *), void *passthru );
|
||||
|
||||
/*-- encr-data.c --*/
|
||||
int decrypt_data( void *ctx, PKT_encrypted *ed, DEK *dek );
|
||||
|
||||
/*-- plaintext.c --*/
|
||||
int handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx,
|
||||
int nooutput, int clearsig );
|
||||
int ask_for_detached_datafile( MD_HANDLE md, MD_HANDLE md2,
|
||||
const char *inname, int textmode );
|
||||
|
||||
/*-- comment.c --*/
|
||||
int write_comment( IOBUF out, const char *s );
|
||||
|
||||
/*-- sign.c --*/
|
||||
int make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk,
|
||||
PKT_user_id *uid, PKT_public_key *subpk,
|
||||
PKT_secret_key *sk, int sigclass, int digest_algo,
|
||||
int sigversion, u32 timestamp, u32 duration,
|
||||
int (*mksubpkt)(PKT_signature *, void *),
|
||||
void *opaque );
|
||||
int update_keysig_packet( PKT_signature **ret_sig,
|
||||
PKT_signature *orig_sig,
|
||||
PKT_public_key *pk,
|
||||
PKT_user_id *uid,
|
||||
PKT_public_key *subpk,
|
||||
PKT_secret_key *sk,
|
||||
int (*mksubpkt)(PKT_signature *, void *),
|
||||
void *opaque );
|
||||
|
||||
/*-- keygen.c --*/
|
||||
PKT_user_id *generate_user_id(void);
|
||||
|
||||
#endif /*G10_PACKET_H*/
|
2281
g10/parse-packet.c
Normal file
2281
g10/parse-packet.c
Normal file
File diff suppressed because it is too large
Load Diff
1238
g10/passphrase.c
Normal file
1238
g10/passphrase.c
Normal file
File diff suppressed because it is too large
Load Diff
333
g10/photoid.c
Normal file
333
g10/photoid.c
Normal file
@ -0,0 +1,333 @@
|
||||
/* photoid.c - photo ID handling code
|
||||
* Copyright (C) 2001, 2002 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#ifdef __MINGW32__
|
||||
# include <windows.h>
|
||||
# ifndef VER_PLATFORM_WIN32_WINDOWS
|
||||
# define VER_PLATFORM_WIN32_WINDOWS 1
|
||||
# endif
|
||||
#endif
|
||||
#include "packet.h"
|
||||
#include "status.h"
|
||||
#include "exec.h"
|
||||
#include "keydb.h"
|
||||
#include "util.h"
|
||||
#include "i18n.h"
|
||||
#include "iobuf.h"
|
||||
#include "memory.h"
|
||||
#include "options.h"
|
||||
#include "main.h"
|
||||
#include "photoid.h"
|
||||
|
||||
/* Generate a new photo id packet, or return NULL if canceled */
|
||||
PKT_user_id *generate_photo_id(PKT_public_key *pk)
|
||||
{
|
||||
PKT_user_id *uid;
|
||||
int error=1,i;
|
||||
unsigned int len;
|
||||
char *filename=NULL;
|
||||
byte *photo=NULL;
|
||||
byte header[16];
|
||||
IOBUF file;
|
||||
|
||||
header[0]=0x10; /* little side of photo header length */
|
||||
header[1]=0; /* big side of photo header length */
|
||||
header[2]=1; /* 1 == version of photo header */
|
||||
header[3]=1; /* 1 == JPEG */
|
||||
|
||||
for(i=4;i<16;i++) /* The reserved bytes */
|
||||
header[i]=0;
|
||||
|
||||
#define EXTRA_UID_NAME_SPACE 71
|
||||
uid=m_alloc_clear(sizeof(*uid)+71);
|
||||
|
||||
printf(_("\nPick an image to use for your photo ID. "
|
||||
"The image must be a JPEG file.\n"
|
||||
"Remember that the image is stored within your public key. "
|
||||
"If you use a\n"
|
||||
"very large picture, your key will become very large as well!\n"
|
||||
"Keeping the image close to 240x288 is a good size to use.\n"));
|
||||
|
||||
while(photo==NULL)
|
||||
{
|
||||
printf("\n");
|
||||
|
||||
m_free(filename);
|
||||
|
||||
filename=cpr_get("photoid.jpeg.add",
|
||||
_("Enter JPEG filename for photo ID: "));
|
||||
|
||||
if(strlen(filename)==0)
|
||||
goto scram;
|
||||
|
||||
file=iobuf_open(filename);
|
||||
if(!file)
|
||||
{
|
||||
log_error(_("Unable to open photo \"%s\": %s\n"),
|
||||
filename,strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
len=iobuf_get_filelength(file);
|
||||
if(len>6144)
|
||||
{
|
||||
printf("This JPEG is really large (%d bytes) !\n",len);
|
||||
if(!cpr_get_answer_is_yes("photoid.jpeg.size",
|
||||
_("Are you sure you want to use it (y/N)? ")))
|
||||
{
|
||||
iobuf_close(file);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
photo=m_alloc(len);
|
||||
iobuf_read(file,photo,len);
|
||||
iobuf_close(file);
|
||||
|
||||
/* Is it a JPEG? */
|
||||
if(photo[0]!=0xFF || photo[1]!=0xD8 ||
|
||||
photo[6]!='J' || photo[7]!='F' || photo[8]!='I' || photo[9]!='F')
|
||||
{
|
||||
log_error(_("\"%s\" is not a JPEG file\n"),filename);
|
||||
m_free(photo);
|
||||
photo=NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Build the packet */
|
||||
build_attribute_subpkt(uid,1,photo,len,header,16);
|
||||
parse_attribute_subpkts(uid);
|
||||
make_attribute_uidname(uid, EXTRA_UID_NAME_SPACE);
|
||||
|
||||
/* Showing the photo is not safe when noninteractive since the
|
||||
"user" may not be able to dismiss a viewer window! */
|
||||
if(opt.command_fd==-1)
|
||||
{
|
||||
show_photos(uid->attribs,uid->numattribs,pk,NULL);
|
||||
switch(cpr_get_answer_yes_no_quit("photoid.jpeg.okay",
|
||||
_("Is this photo correct (y/N/q)? ")))
|
||||
{
|
||||
case -1:
|
||||
goto scram;
|
||||
case 0:
|
||||
free_attributes(uid);
|
||||
m_free(photo);
|
||||
photo=NULL;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
error=0;
|
||||
uid->ref=1;
|
||||
|
||||
scram:
|
||||
m_free(filename);
|
||||
m_free(photo);
|
||||
|
||||
if(error)
|
||||
{
|
||||
free_attributes(uid);
|
||||
m_free(uid);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return uid;
|
||||
}
|
||||
|
||||
/* Returns 0 for error, 1 for valid */
|
||||
int parse_image_header(const struct user_attribute *attr,byte *type,u32 *len)
|
||||
{
|
||||
u16 headerlen;
|
||||
|
||||
if(attr->len<3)
|
||||
return 0;
|
||||
|
||||
/* For historical reasons (i.e. "oops!"), the header length is
|
||||
little endian. */
|
||||
headerlen=(attr->data[1]<<8) | attr->data[0];
|
||||
|
||||
if(headerlen>attr->len)
|
||||
return 0;
|
||||
|
||||
if(type && attr->len>=4)
|
||||
{
|
||||
if(attr->data[2]==1) /* header version 1 */
|
||||
*type=attr->data[3];
|
||||
else
|
||||
*type=0;
|
||||
}
|
||||
|
||||
*len=attr->len-headerlen;
|
||||
|
||||
if(*len==0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* style==0 for extension, 1 for name, 2 for MIME type. Remember that
|
||||
the "name" style string could be used in a user ID name field, so
|
||||
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)
|
||||
{
|
||||
char *string;
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case 1: /* jpeg */
|
||||
if(style==0)
|
||||
string="jpg";
|
||||
else if(style==1)
|
||||
string="jpeg";
|
||||
else
|
||||
string="image/jpeg";
|
||||
break;
|
||||
|
||||
default:
|
||||
if(style==0)
|
||||
string="bin";
|
||||
else if(style==1)
|
||||
string="unknown";
|
||||
else
|
||||
string="image/x-unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
#if !defined(FIXED_PHOTO_VIEWER) && !defined(DISABLE_PHOTO_VIEWER)
|
||||
static const char *get_default_photo_command(void)
|
||||
{
|
||||
#if defined(__MINGW32__)
|
||||
OSVERSIONINFO osvi;
|
||||
|
||||
memset(&osvi,0,sizeof(osvi));
|
||||
osvi.dwOSVersionInfoSize=sizeof(osvi);
|
||||
GetVersionEx(&osvi);
|
||||
|
||||
if(osvi.dwPlatformId==VER_PLATFORM_WIN32_WINDOWS)
|
||||
return "start /w %i";
|
||||
else
|
||||
return "cmd /c start /w %i";
|
||||
#elif defined(__APPLE__)
|
||||
/* OS X. This really needs more than just __APPLE__. */
|
||||
return "open %I";
|
||||
#elif defined(__riscos__)
|
||||
return "Filer_Run %I";
|
||||
#else
|
||||
return "xloadimage -fork -quiet -title 'KeyID 0x%k' stdin";
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
void show_photos(const struct user_attribute *attrs,
|
||||
int count,PKT_public_key *pk,PKT_secret_key *sk)
|
||||
{
|
||||
#ifndef DISABLE_PHOTO_VIEWER
|
||||
int i;
|
||||
struct expando_args args;
|
||||
u32 len;
|
||||
u32 kid[2]={0,0};
|
||||
|
||||
memset(&args,0,sizeof(args));
|
||||
args.pk=pk;
|
||||
args.sk=sk;
|
||||
|
||||
if(pk)
|
||||
keyid_from_pk(pk,kid);
|
||||
else if(sk)
|
||||
keyid_from_sk(sk,kid);
|
||||
|
||||
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;
|
||||
#else
|
||||
if(!opt.photo_viewer)
|
||||
opt.photo_viewer=get_default_photo_command();
|
||||
#endif
|
||||
|
||||
/* make command grow */
|
||||
command=pct_expando(opt.photo_viewer,&args);
|
||||
if(!command)
|
||||
goto fail;
|
||||
|
||||
name=m_alloc(16+strlen(EXTSEP_S)+
|
||||
strlen(image_type_to_string(args.imagetype,0))+1);
|
||||
|
||||
/* Make the filename. Notice we are not using the image
|
||||
encoding type for more than cosmetics. Most external image
|
||||
viewers can handle a multitude of types, and even if one
|
||||
cannot understand a particular type, we have no way to know
|
||||
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));
|
||||
#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)
|
||||
{
|
||||
m_free(name);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
#ifdef __riscos__
|
||||
riscos_set_filetype_by_mimetype(spawn->tempfile_in,
|
||||
image_type_to_string(args.imagetype,2));
|
||||
#endif
|
||||
|
||||
m_free(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;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
fail:
|
||||
log_error(_("unable to display photo ID!\n"));
|
||||
#endif
|
||||
}
|
34
g10/photoid.h
Normal file
34
g10/photoid.h
Normal file
@ -0,0 +1,34 @@
|
||||
/* photoid.h
|
||||
* Copyright (C) 2001, 2002 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
/* Photo ID functions */
|
||||
|
||||
#ifndef _PHOTOID_H_
|
||||
#define _PHOTOID_H_
|
||||
|
||||
#include "packet.h"
|
||||
|
||||
PKT_user_id *generate_photo_id(PKT_public_key *pk);
|
||||
int parse_image_header(const struct user_attribute *attr,byte *type,u32 *len);
|
||||
char *image_type_to_string(byte type,int style);
|
||||
void show_photos(const struct user_attribute *attrs,
|
||||
int count,PKT_public_key *pk,PKT_secret_key *sk);
|
||||
|
||||
#endif /* !_PHOTOID_H_ */
|
1376
g10/pkclist.c
Normal file
1376
g10/pkclist.c
Normal file
File diff suppressed because it is too large
Load Diff
446
g10/plaintext.c
Normal file
446
g10/plaintext.c
Normal file
@ -0,0 +1,446 @@
|
||||
/* plaintext.c - process plaintext packets
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#ifdef HAVE_DOSISH_SYSTEM
|
||||
#include <fcntl.h> /* for setmode() */
|
||||
#endif
|
||||
|
||||
#include "util.h"
|
||||
#include "memory.h"
|
||||
#include "options.h"
|
||||
#include "packet.h"
|
||||
#include "ttyio.h"
|
||||
#include "filter.h"
|
||||
#include "main.h"
|
||||
#include "status.h"
|
||||
#include "i18n.h"
|
||||
|
||||
|
||||
|
||||
/****************
|
||||
* Handle a plaintext packet. If MFX is not NULL, update the MDs
|
||||
* Note: we should use the filter stuff here, but we have to add some
|
||||
* easy mimic to set a read limit, so we calculate only the
|
||||
* bytes from the plaintext.
|
||||
*/
|
||||
int
|
||||
handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx,
|
||||
int nooutput, int clearsig )
|
||||
{
|
||||
char *fname = NULL;
|
||||
FILE *fp = NULL;
|
||||
int rc = 0;
|
||||
int c;
|
||||
int convert = pt->mode == 't';
|
||||
#ifdef __riscos__
|
||||
int filetype = 0xfff;
|
||||
#endif
|
||||
|
||||
/* create the filename as C string */
|
||||
if( nooutput )
|
||||
;
|
||||
else if( opt.outfile ) {
|
||||
fname = m_alloc( strlen( opt.outfile ) + 1);
|
||||
strcpy(fname, opt.outfile );
|
||||
}
|
||||
else if( pt->namelen == 8 && !memcmp( pt->name, "_CONSOLE", 8 ) ) {
|
||||
log_info(_("data not saved; use option \"--output\" to save it\n"));
|
||||
nooutput = 1;
|
||||
}
|
||||
else if( !opt.use_embedded_filename ) {
|
||||
fname = make_outfile_name( iobuf_get_real_fname(pt->buf) );
|
||||
if( !fname )
|
||||
fname = ask_outfile_name( pt->name, pt->namelen );
|
||||
if( !fname ) {
|
||||
rc = G10ERR_CREATE_FILE;
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
else {
|
||||
fname = make_printable_string( pt->name, pt->namelen, 0 );
|
||||
}
|
||||
|
||||
if( nooutput )
|
||||
;
|
||||
else if( !*fname || (*fname=='-' && !fname[1])) {
|
||||
/* no filename or "-" given; write to stdout */
|
||||
fp = stdout;
|
||||
#ifdef HAVE_DOSISH_SYSTEM
|
||||
setmode ( fileno(fp) , O_BINARY );
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
while( !overwrite_filep (fname) ) {
|
||||
char *tmp = ask_outfile_name (NULL, 0);
|
||||
if ( !tmp || !*tmp ) {
|
||||
m_free (tmp);
|
||||
rc = G10ERR_CREATE_FILE;
|
||||
goto leave;
|
||||
}
|
||||
m_free (fname);
|
||||
fname = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef __riscos__
|
||||
if( fp || nooutput )
|
||||
;
|
||||
else if( !(fp = fopen(fname,"wb")) ) {
|
||||
log_error(_("error creating `%s': %s\n"), fname, strerror(errno) );
|
||||
rc = G10ERR_CREATE_FILE;
|
||||
goto leave;
|
||||
}
|
||||
#else /* __riscos__ */
|
||||
/* Convert all '.' in fname to '/' -- we don't create directories! */
|
||||
for( c=0; fname[c]; ++c )
|
||||
if( fname[c] == '.' )
|
||||
fname[c] = '/';
|
||||
|
||||
if( fp || nooutput )
|
||||
;
|
||||
else {
|
||||
fp = fopen(fname,"wb");
|
||||
if( !fp ) {
|
||||
log_error(_("error creating `%s': %s\n"), fname, strerror(errno) );
|
||||
rc = G10ERR_CREATE_FILE;
|
||||
if (errno == 106)
|
||||
log_info("Do output file and input file have the same name?\n");
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* If there's a ,xxx extension in the embedded filename,
|
||||
use that, else check whether the user input (in fname)
|
||||
has a ,xxx appended, then use that in preference */
|
||||
if( (c = riscos_get_filetype_from_string( pt->name,
|
||||
pt->namelen )) != -1 )
|
||||
filetype = c;
|
||||
if( (c = riscos_get_filetype_from_string( fname,
|
||||
strlen(fname) )) != -1 )
|
||||
filetype = c;
|
||||
riscos_set_filetype_by_number(fname, filetype);
|
||||
}
|
||||
#endif /* __riscos__ */
|
||||
|
||||
if( !pt->is_partial ) {
|
||||
/* we have an actual length (which might be zero). */
|
||||
assert( !clearsig );
|
||||
if( convert ) { /* text mode */
|
||||
for( ; pt->len; pt->len-- ) {
|
||||
if( (c = iobuf_get(pt->buf)) == -1 ) {
|
||||
log_error("Problem reading source (%u bytes remaining)\n",
|
||||
(unsigned)pt->len);
|
||||
rc = G10ERR_READ_FILE;
|
||||
goto leave;
|
||||
}
|
||||
if( mfx->md )
|
||||
md_putc(mfx->md, c );
|
||||
#ifndef HAVE_DOSISH_SYSTEM
|
||||
if( c == '\r' ) /* convert to native line ending */
|
||||
continue; /* fixme: this hack might be too simple */
|
||||
#endif
|
||||
if( fp ) {
|
||||
if( putc( c, fp ) == EOF ) {
|
||||
log_error("Error writing to `%s': %s\n",
|
||||
fname, strerror(errno) );
|
||||
rc = G10ERR_WRITE_FILE;
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else { /* binary mode */
|
||||
byte *buffer = m_alloc( 32768 );
|
||||
while( pt->len ) {
|
||||
int len = pt->len > 32768 ? 32768 : pt->len;
|
||||
len = iobuf_read( pt->buf, buffer, len );
|
||||
if( len == -1 ) {
|
||||
log_error("Problem reading source (%u bytes remaining)\n",
|
||||
(unsigned)pt->len);
|
||||
rc = G10ERR_READ_FILE;
|
||||
m_free( buffer );
|
||||
goto leave;
|
||||
}
|
||||
if( mfx->md )
|
||||
md_write( mfx->md, buffer, len );
|
||||
if( fp ) {
|
||||
if( fwrite( buffer, 1, len, fp ) != len ) {
|
||||
log_error("Error writing to `%s': %s\n",
|
||||
fname, strerror(errno) );
|
||||
rc = G10ERR_WRITE_FILE;
|
||||
m_free( buffer );
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
pt->len -= len;
|
||||
}
|
||||
m_free( buffer );
|
||||
}
|
||||
}
|
||||
else if( !clearsig ) {
|
||||
if( convert ) { /* text mode */
|
||||
while( (c = iobuf_get(pt->buf)) != -1 ) {
|
||||
if( mfx->md )
|
||||
md_putc(mfx->md, c );
|
||||
#ifndef HAVE_DOSISH_SYSTEM
|
||||
if( convert && c == '\r' )
|
||||
continue; /* fixme: this hack might be too simple */
|
||||
#endif
|
||||
if( fp ) {
|
||||
if( putc( c, fp ) == EOF ) {
|
||||
log_error("Error writing to `%s': %s\n",
|
||||
fname, strerror(errno) );
|
||||
rc = G10ERR_WRITE_FILE;
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else { /* binary mode */
|
||||
byte *buffer = m_alloc( 32768 );
|
||||
int eof;
|
||||
for( eof=0; !eof; ) {
|
||||
/* Why do we check for len < 32768:
|
||||
* If we won't, we would practically read 2 EOFs but
|
||||
* the first one has already popped the block_filter
|
||||
* off and therefore we don't catch the boundary.
|
||||
* So, always assume EOF if iobuf_read returns less bytes
|
||||
* then requested */
|
||||
int len = iobuf_read( pt->buf, buffer, 32768 );
|
||||
if( len == -1 )
|
||||
break;
|
||||
if( len < 32768 )
|
||||
eof = 1;
|
||||
if( mfx->md )
|
||||
md_write( mfx->md, buffer, len );
|
||||
if( fp ) {
|
||||
if( fwrite( buffer, 1, len, fp ) != len ) {
|
||||
log_error("Error writing to `%s': %s\n",
|
||||
fname, strerror(errno) );
|
||||
rc = G10ERR_WRITE_FILE;
|
||||
m_free( buffer );
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_free( buffer );
|
||||
}
|
||||
pt->buf = NULL;
|
||||
}
|
||||
else { /* clear text signature - don't hash the last cr,lf */
|
||||
int state = 0;
|
||||
|
||||
while( (c = iobuf_get(pt->buf)) != -1 ) {
|
||||
if( fp ) {
|
||||
if( putc( c, fp ) == EOF ) {
|
||||
log_error("Error writing to `%s': %s\n",
|
||||
fname, strerror(errno) );
|
||||
rc = G10ERR_WRITE_FILE;
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
if( !mfx->md )
|
||||
continue;
|
||||
if( state == 2 ) {
|
||||
md_putc(mfx->md, '\r' );
|
||||
md_putc(mfx->md, '\n' );
|
||||
state = 0;
|
||||
}
|
||||
if( !state ) {
|
||||
if( c == '\r' )
|
||||
state = 1;
|
||||
else if( c == '\n' )
|
||||
state = 2;
|
||||
else
|
||||
md_putc(mfx->md, c );
|
||||
}
|
||||
else if( state == 1 ) {
|
||||
if( c == '\n' )
|
||||
state = 2;
|
||||
else {
|
||||
md_putc(mfx->md, '\r' );
|
||||
if( c == '\r' )
|
||||
state = 1;
|
||||
else {
|
||||
state = 0;
|
||||
md_putc(mfx->md, c );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pt->buf = NULL;
|
||||
}
|
||||
|
||||
if( fp && fp != stdout && fclose(fp) ) {
|
||||
log_error("Error closing `%s': %s\n", fname, strerror(errno) );
|
||||
fp = NULL;
|
||||
rc = G10ERR_WRITE_FILE;
|
||||
goto leave;
|
||||
}
|
||||
fp = NULL;
|
||||
|
||||
leave:
|
||||
if( fp && fp != stdout )
|
||||
fclose(fp);
|
||||
m_free(fname);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
do_hash( MD_HANDLE md, MD_HANDLE md2, IOBUF fp, int textmode )
|
||||
{
|
||||
text_filter_context_t tfx;
|
||||
int c;
|
||||
|
||||
if( textmode ) {
|
||||
memset( &tfx, 0, sizeof tfx);
|
||||
iobuf_push_filter( fp, text_filter, &tfx );
|
||||
}
|
||||
if( md2 ) { /* work around a strange behaviour in pgp2 */
|
||||
/* It seems that at least PGP5 converts a single CR to a CR,LF too */
|
||||
int lc = -1;
|
||||
while( (c = iobuf_get(fp)) != -1 ) {
|
||||
if( c == '\n' && lc == '\r' )
|
||||
md_putc(md2, c);
|
||||
else if( c == '\n' ) {
|
||||
md_putc(md2, '\r');
|
||||
md_putc(md2, c);
|
||||
}
|
||||
else if( c != '\n' && lc == '\r' ) {
|
||||
md_putc(md2, '\n');
|
||||
md_putc(md2, c);
|
||||
}
|
||||
else
|
||||
md_putc(md2, c);
|
||||
|
||||
if( md )
|
||||
md_putc(md, c );
|
||||
lc = c;
|
||||
}
|
||||
}
|
||||
else {
|
||||
while( (c = iobuf_get(fp)) != -1 ) {
|
||||
if( md )
|
||||
md_putc(md, c );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
* Ask for the detached datafile and calculate the digest from it.
|
||||
* INFILE is the name of the input file.
|
||||
*/
|
||||
int
|
||||
ask_for_detached_datafile( MD_HANDLE md, MD_HANDLE md2,
|
||||
const char *inname, int textmode )
|
||||
{
|
||||
progress_filter_context_t pfx;
|
||||
char *answer = NULL;
|
||||
IOBUF fp;
|
||||
int rc = 0;
|
||||
|
||||
fp = open_sigfile( inname, &pfx ); /* open default file */
|
||||
|
||||
if( !fp && !opt.batch ) {
|
||||
int any=0;
|
||||
tty_printf(_("Detached signature.\n"));
|
||||
do {
|
||||
m_free(answer);
|
||||
answer = cpr_get("detached_signature.filename",
|
||||
_("Please enter name of data file: "));
|
||||
cpr_kill_prompt();
|
||||
if( any && !*answer ) {
|
||||
rc = G10ERR_READ_FILE;
|
||||
goto leave;
|
||||
}
|
||||
fp = iobuf_open(answer);
|
||||
if( !fp && errno == ENOENT ) {
|
||||
tty_printf("No such file, try again or hit enter to quit.\n");
|
||||
any++;
|
||||
}
|
||||
else if( !fp ) {
|
||||
log_error("can't open `%s': %s\n", answer, strerror(errno) );
|
||||
rc = G10ERR_READ_FILE;
|
||||
goto leave;
|
||||
}
|
||||
} while( !fp );
|
||||
}
|
||||
|
||||
if( !fp ) {
|
||||
if( opt.verbose )
|
||||
log_info(_("reading stdin ...\n"));
|
||||
fp = iobuf_open( NULL );
|
||||
assert(fp);
|
||||
}
|
||||
do_hash( md, md2, fp, textmode );
|
||||
iobuf_close(fp);
|
||||
|
||||
leave:
|
||||
m_free(answer);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/****************
|
||||
* Hash the given files and append the hash to hash context md.
|
||||
* If FILES is NULL, hash stdin.
|
||||
*/
|
||||
int
|
||||
hash_datafiles( MD_HANDLE md, MD_HANDLE md2, STRLIST files,
|
||||
const char *sigfilename, int textmode )
|
||||
{
|
||||
progress_filter_context_t pfx;
|
||||
IOBUF fp;
|
||||
STRLIST sl;
|
||||
|
||||
if( !files ) {
|
||||
/* check whether we can open the signed material */
|
||||
fp = open_sigfile( sigfilename, &pfx );
|
||||
if( fp ) {
|
||||
do_hash( md, md2, fp, textmode );
|
||||
iobuf_close(fp);
|
||||
return 0;
|
||||
}
|
||||
log_error (_("no signed data\n"));
|
||||
return G10ERR_OPEN_FILE;
|
||||
}
|
||||
|
||||
|
||||
for (sl=files; sl; sl = sl->next ) {
|
||||
fp = iobuf_open( sl->d );
|
||||
if( !fp ) {
|
||||
log_error(_("can't open signed data `%s'\n"),
|
||||
print_fname_stdin(sl->d));
|
||||
return G10ERR_OPEN_FILE;
|
||||
}
|
||||
handle_progress (&pfx, fp, sl->d);
|
||||
do_hash( md, md2, fp, textmode );
|
||||
iobuf_close(fp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
117
g10/progress.c
Normal file
117
g10/progress.c
Normal file
@ -0,0 +1,117 @@
|
||||
/* progress.c
|
||||
* Copyright (C) 2003 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "iobuf.h"
|
||||
#include "filter.h"
|
||||
#include "status.h"
|
||||
#include "util.h"
|
||||
#include "options.h"
|
||||
|
||||
/****************
|
||||
* The filter is used to report progress to the user.
|
||||
*/
|
||||
int
|
||||
progress_filter (void *opaque, int control,
|
||||
IOBUF a, byte *buf, size_t *ret_len)
|
||||
{
|
||||
int rc = 0;
|
||||
progress_filter_context_t *pfx = opaque;
|
||||
|
||||
if (control == IOBUFCTRL_INIT)
|
||||
{
|
||||
char buffer[50];
|
||||
|
||||
pfx->last = 0;
|
||||
pfx->offset = 0;
|
||||
pfx->last_time = make_timestamp ();
|
||||
|
||||
sprintf (buffer, "%.20s ? %lu %lu",
|
||||
pfx->what? pfx->what : "?",
|
||||
pfx->offset,
|
||||
pfx->total);
|
||||
write_status_text (STATUS_PROGRESS, buffer);
|
||||
}
|
||||
else if (control == IOBUFCTRL_UNDERFLOW)
|
||||
{
|
||||
u32 timestamp = make_timestamp ();
|
||||
int len = iobuf_read (a, buf, *ret_len);
|
||||
|
||||
if (len >= 0)
|
||||
{
|
||||
pfx->offset += len;
|
||||
*ret_len = len;
|
||||
}
|
||||
else
|
||||
{
|
||||
*ret_len = 0;
|
||||
rc = -1;
|
||||
}
|
||||
if ((len == -1 && pfx->offset != pfx->last)
|
||||
|| timestamp - pfx->last_time > 0)
|
||||
{
|
||||
char buffer[50];
|
||||
|
||||
sprintf (buffer, "%.20s ? %lu %lu",
|
||||
pfx->what? pfx->what : "?",
|
||||
pfx->offset,
|
||||
pfx->total);
|
||||
write_status_text (STATUS_PROGRESS, buffer);
|
||||
|
||||
pfx->last = pfx->offset;
|
||||
pfx->last_time = timestamp;
|
||||
}
|
||||
}
|
||||
else if (control == IOBUFCTRL_FREE)
|
||||
{
|
||||
/* Note, that we must always dealloc resources of a filter
|
||||
within the filter handler and not anywhere else. (We set it
|
||||
to NULL and check all uses just in case.) */
|
||||
m_free (pfx->what);
|
||||
pfx->what = NULL;
|
||||
}
|
||||
else if (control == IOBUFCTRL_DESC)
|
||||
*(char**)buf = "progress_filter";
|
||||
return rc;
|
||||
}
|
||||
|
||||
void
|
||||
handle_progress (progress_filter_context_t *pfx, IOBUF inp, const char *name)
|
||||
{
|
||||
off_t filesize = 0;
|
||||
|
||||
if (!opt.enable_progress_filter)
|
||||
return;
|
||||
|
||||
if (!is_status_enabled ())
|
||||
return;
|
||||
|
||||
if (name && *name && !(*name == '-' && !name[1]))
|
||||
filesize = iobuf_get_filelength (inp);
|
||||
else if (opt.set_filesize)
|
||||
filesize = opt.set_filesize;
|
||||
|
||||
/* register the progress filter */
|
||||
pfx->what = m_strdup (name ? name : "stdin");
|
||||
pfx->total = filesize;
|
||||
iobuf_push_filter (inp, progress_filter, pfx);
|
||||
}
|
690
g10/revoke.c
Normal file
690
g10/revoke.c
Normal file
@ -0,0 +1,690 @@
|
||||
/* revoke.c
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "options.h"
|
||||
#include "packet.h"
|
||||
#include "errors.h"
|
||||
#include "keydb.h"
|
||||
#include "memory.h"
|
||||
#include "util.h"
|
||||
#include "main.h"
|
||||
#include "ttyio.h"
|
||||
#include "status.h"
|
||||
#include "i18n.h"
|
||||
|
||||
|
||||
struct revocation_reason_info {
|
||||
int code;
|
||||
char *desc;
|
||||
};
|
||||
|
||||
|
||||
int
|
||||
revocation_reason_build_cb( PKT_signature *sig, void *opaque )
|
||||
{
|
||||
struct revocation_reason_info *reason = opaque;
|
||||
char *ud = NULL;
|
||||
byte *buffer;
|
||||
size_t buflen = 1;
|
||||
|
||||
if(!reason)
|
||||
return 0;
|
||||
|
||||
if( reason->desc ) {
|
||||
ud = native_to_utf8( reason->desc );
|
||||
buflen += strlen(ud);
|
||||
}
|
||||
buffer = m_alloc( buflen );
|
||||
*buffer = reason->code;
|
||||
if( ud ) {
|
||||
memcpy(buffer+1, ud, strlen(ud) );
|
||||
m_free( ud );
|
||||
}
|
||||
|
||||
build_sig_subpkt( sig, SIGSUBPKT_REVOC_REASON, buffer, buflen );
|
||||
m_free( buffer );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Outputs a minimal pk (as defined by 2440) from a keyblock. A
|
||||
minimal pk consists of the public key packet and a user ID. We try
|
||||
and pick a user ID that has a uid signature, and include it if
|
||||
possible. */
|
||||
static int
|
||||
export_minimal_pk(IOBUF out,KBNODE keyblock,
|
||||
PKT_signature *revsig,PKT_signature *revkey)
|
||||
{
|
||||
KBNODE node;
|
||||
PACKET pkt;
|
||||
PKT_user_id *uid=NULL;
|
||||
PKT_signature *selfsig=NULL;
|
||||
u32 keyid[2];
|
||||
int rc;
|
||||
|
||||
node=find_kbnode(keyblock,PKT_PUBLIC_KEY);
|
||||
if(!node)
|
||||
{
|
||||
log_error(_("key incomplete\n"));
|
||||
return G10ERR_GENERAL;
|
||||
}
|
||||
|
||||
keyid_from_pk(node->pkt->pkt.public_key,keyid);
|
||||
|
||||
pkt=*node->pkt;
|
||||
rc=build_packet(out,&pkt);
|
||||
if(rc)
|
||||
{
|
||||
log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
init_packet(&pkt);
|
||||
pkt.pkttype=PKT_SIGNATURE;
|
||||
|
||||
/* the revocation itself, if any. 2440 likes this to come first. */
|
||||
if(revsig)
|
||||
{
|
||||
pkt.pkt.signature=revsig;
|
||||
rc=build_packet(out,&pkt);
|
||||
if(rc)
|
||||
{
|
||||
log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
/* If a revkey in a 1F sig is present, include it too */
|
||||
if(revkey)
|
||||
{
|
||||
pkt.pkt.signature=revkey;
|
||||
rc=build_packet(out,&pkt);
|
||||
if(rc)
|
||||
{
|
||||
log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
while(!selfsig)
|
||||
{
|
||||
KBNODE signode;
|
||||
|
||||
node=find_next_kbnode(node,PKT_USER_ID);
|
||||
if(!node)
|
||||
{
|
||||
/* We're out of user IDs - none were self-signed. */
|
||||
if(uid)
|
||||
break;
|
||||
else
|
||||
{
|
||||
log_error(_("key %08lX incomplete\n"),(ulong)keyid[1]);
|
||||
return G10ERR_GENERAL;
|
||||
}
|
||||
}
|
||||
|
||||
if(node->pkt->pkt.user_id->attrib_data)
|
||||
continue;
|
||||
|
||||
uid=node->pkt->pkt.user_id;
|
||||
signode=node;
|
||||
|
||||
while((signode=find_next_kbnode(signode,PKT_SIGNATURE)))
|
||||
{
|
||||
if(keyid[0]==signode->pkt->pkt.signature->keyid[0] &&
|
||||
keyid[1]==signode->pkt->pkt.signature->keyid[1] &&
|
||||
IS_UID_SIG(signode->pkt->pkt.signature))
|
||||
{
|
||||
selfsig=signode->pkt->pkt.signature;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pkt.pkttype=PKT_USER_ID;
|
||||
pkt.pkt.user_id=uid;
|
||||
|
||||
rc=build_packet(out,&pkt);
|
||||
if(rc)
|
||||
{
|
||||
log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
if(selfsig)
|
||||
{
|
||||
pkt.pkttype=PKT_SIGNATURE;
|
||||
pkt.pkt.signature=selfsig;
|
||||
|
||||
rc=build_packet(out,&pkt);
|
||||
if(rc)
|
||||
{
|
||||
log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************
|
||||
* Generate a revocation certificate for UNAME via a designated revoker
|
||||
*/
|
||||
int
|
||||
gen_desig_revoke( const char *uname )
|
||||
{
|
||||
int rc = 0;
|
||||
armor_filter_context_t afx;
|
||||
PKT_public_key *pk = NULL;
|
||||
PKT_secret_key *sk = NULL;
|
||||
PKT_signature *sig = NULL;
|
||||
IOBUF out = NULL;
|
||||
struct revocation_reason_info *reason = NULL;
|
||||
KEYDB_HANDLE kdbhd;
|
||||
KEYDB_SEARCH_DESC desc;
|
||||
KBNODE keyblock=NULL,node;
|
||||
u32 keyid[2];
|
||||
int i,any=0;
|
||||
|
||||
if( opt.batch ) {
|
||||
log_error(_("sorry, can't do this in batch mode\n"));
|
||||
return G10ERR_GENERAL;
|
||||
}
|
||||
|
||||
memset( &afx, 0, sizeof afx);
|
||||
|
||||
kdbhd = keydb_new (0);
|
||||
classify_user_id (uname, &desc);
|
||||
rc = desc.mode? keydb_search (kdbhd, &desc, 1) : G10ERR_INV_USER_ID;
|
||||
if (rc) {
|
||||
log_error (_("key `%s' not found: %s\n"),uname, g10_errstr (rc));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
rc = keydb_get_keyblock (kdbhd, &keyblock );
|
||||
if( rc ) {
|
||||
log_error (_("error reading keyblock: %s\n"), g10_errstr(rc) );
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* To parse the revkeys */
|
||||
merge_keys_and_selfsig(keyblock);
|
||||
|
||||
/* get the key from the keyblock */
|
||||
node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
|
||||
if( !node )
|
||||
BUG ();
|
||||
|
||||
pk=node->pkt->pkt.public_key;
|
||||
|
||||
keyid_from_pk(pk,keyid);
|
||||
|
||||
/* Are we a designated revoker for this key? */
|
||||
|
||||
if(!pk->revkey && pk->numrevkeys)
|
||||
BUG();
|
||||
|
||||
for(i=0;i<pk->numrevkeys;i++)
|
||||
{
|
||||
if(sk)
|
||||
free_secret_key(sk);
|
||||
|
||||
sk=m_alloc_clear(sizeof(*sk));
|
||||
|
||||
rc=get_seckey_byfprint(sk,pk->revkey[i].fpr,MAX_FINGERPRINT_LEN);
|
||||
|
||||
/* We have the revocation key */
|
||||
if(!rc)
|
||||
{
|
||||
PKT_signature *revkey = NULL;
|
||||
|
||||
any = 1;
|
||||
|
||||
print_pubkey_info (pk);
|
||||
tty_printf ("\n");
|
||||
|
||||
tty_printf (_("To be revoked by:\n"));
|
||||
print_seckey_info (sk);
|
||||
|
||||
if(pk->revkey[i].class&0x40)
|
||||
tty_printf(_("(This is a sensitive revocation key)\n"));
|
||||
tty_printf("\n");
|
||||
|
||||
if( !cpr_get_answer_is_yes("gen_desig_revoke.okay",
|
||||
_("Create a revocation certificate for this key? ")) )
|
||||
continue;
|
||||
|
||||
/* get the reason for the revocation (this is always v4) */
|
||||
reason = ask_revocation_reason( 1, 0, 1 );
|
||||
if( !reason )
|
||||
continue;
|
||||
|
||||
rc = check_secret_key( sk, 0 );
|
||||
if( rc )
|
||||
continue;
|
||||
|
||||
if( !opt.armor )
|
||||
tty_printf(_("ASCII armored output forced.\n"));
|
||||
|
||||
if( (rc = open_outfile( NULL, 0, &out )) )
|
||||
goto leave;
|
||||
|
||||
afx.what = 1;
|
||||
afx.hdrlines = "Comment: A revocation certificate should follow\n";
|
||||
iobuf_push_filter( out, armor_filter, &afx );
|
||||
|
||||
/* create it */
|
||||
rc = make_keysig_packet( &sig, pk, NULL, NULL, sk, 0x20, 0,
|
||||
0, 0, 0,
|
||||
revocation_reason_build_cb, reason );
|
||||
if( rc ) {
|
||||
log_error(_("make_keysig_packet failed: %s\n"), g10_errstr(rc));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* Spit out a minimal pk as well, since otherwise there is
|
||||
no way to know which key to attach this revocation to.
|
||||
Also include the direct key signature that contains
|
||||
this revocation key. We're allowed to include
|
||||
sensitive revocation keys along with a revocation, as
|
||||
this may be the only time the recipient has seen it.
|
||||
Note that this means that if we have multiple different
|
||||
sensitive revocation keys in a given direct key
|
||||
signature, we're going to include them all here. This
|
||||
is annoying, but the good outweighs the bad, since
|
||||
without including this a sensitive revoker can't really
|
||||
do their job. People should not include multiple
|
||||
sensitive revocation keys in one signature: 2440 says
|
||||
"Note that it may be appropriate to isolate this
|
||||
subpacket within a separate signature so that it is not
|
||||
combined with other subpackets that need to be
|
||||
exported." -dms */
|
||||
|
||||
while(!revkey)
|
||||
{
|
||||
KBNODE signode;
|
||||
|
||||
signode=find_next_kbnode(node,PKT_SIGNATURE);
|
||||
if(!signode)
|
||||
break;
|
||||
|
||||
node=signode;
|
||||
|
||||
if(keyid[0]==signode->pkt->pkt.signature->keyid[0] &&
|
||||
keyid[1]==signode->pkt->pkt.signature->keyid[1] &&
|
||||
IS_KEY_SIG(signode->pkt->pkt.signature))
|
||||
{
|
||||
int j;
|
||||
|
||||
for(j=0;j<signode->pkt->pkt.signature->numrevkeys;j++)
|
||||
{
|
||||
if(pk->revkey[i].class==
|
||||
signode->pkt->pkt.signature->revkey[j]->class &&
|
||||
pk->revkey[i].algid==
|
||||
signode->pkt->pkt.signature->revkey[j]->algid &&
|
||||
memcmp(pk->revkey[i].fpr,
|
||||
signode->pkt->pkt.signature->revkey[j]->fpr,
|
||||
MAX_FINGERPRINT_LEN)==0)
|
||||
{
|
||||
revkey=signode->pkt->pkt.signature;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!revkey)
|
||||
BUG();
|
||||
|
||||
rc=export_minimal_pk(out,keyblock,sig,revkey);
|
||||
if(rc)
|
||||
goto leave;
|
||||
|
||||
/* and issue a usage notice */
|
||||
tty_printf(_("Revocation certificate created.\n"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!any)
|
||||
log_error(_("no revocation keys found for `%s'\n"),uname);
|
||||
|
||||
leave:
|
||||
if( pk )
|
||||
free_public_key( pk );
|
||||
if( sk )
|
||||
free_secret_key( sk );
|
||||
if( sig )
|
||||
free_seckey_enc( sig );
|
||||
|
||||
if( rc )
|
||||
iobuf_cancel(out);
|
||||
else
|
||||
iobuf_close(out);
|
||||
release_revocation_reason_info( reason );
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
* Generate a revocation certificate for UNAME
|
||||
*/
|
||||
int
|
||||
gen_revoke( const char *uname )
|
||||
{
|
||||
int rc = 0;
|
||||
armor_filter_context_t afx;
|
||||
PACKET pkt;
|
||||
PKT_secret_key *sk; /* used as pointer into a kbnode */
|
||||
PKT_public_key *pk = NULL;
|
||||
PKT_signature *sig = NULL;
|
||||
u32 sk_keyid[2];
|
||||
IOBUF out = NULL;
|
||||
KBNODE keyblock = NULL, pub_keyblock = NULL;
|
||||
KBNODE node;
|
||||
KEYDB_HANDLE kdbhd;
|
||||
struct revocation_reason_info *reason = NULL;
|
||||
KEYDB_SEARCH_DESC desc;
|
||||
|
||||
if( opt.batch ) {
|
||||
log_error(_("sorry, can't do this in batch mode\n"));
|
||||
return G10ERR_GENERAL;
|
||||
}
|
||||
|
||||
memset( &afx, 0, sizeof afx);
|
||||
init_packet( &pkt );
|
||||
|
||||
/* search the userid:
|
||||
* We don't want the whole getkey stuff here but the entire keyblock
|
||||
*/
|
||||
kdbhd = keydb_new (1);
|
||||
classify_user_id (uname, &desc);
|
||||
rc = desc.mode? keydb_search (kdbhd, &desc, 1) : G10ERR_INV_USER_ID;
|
||||
if (rc) {
|
||||
log_error (_("secret key `%s' not found: %s\n"),
|
||||
uname, g10_errstr (rc));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
rc = keydb_get_keyblock (kdbhd, &keyblock );
|
||||
if( rc ) {
|
||||
log_error (_("error reading keyblock: %s\n"), g10_errstr(rc) );
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* get the keyid from the keyblock */
|
||||
node = find_kbnode( keyblock, PKT_SECRET_KEY );
|
||||
if( !node )
|
||||
BUG ();
|
||||
|
||||
/* fixme: should make a function out of this stuff,
|
||||
* it's used all over the source */
|
||||
sk = node->pkt->pkt.secret_key;
|
||||
keyid_from_sk( sk, sk_keyid );
|
||||
print_seckey_info (sk);
|
||||
|
||||
pk = m_alloc_clear( sizeof *pk );
|
||||
|
||||
/* FIXME: We should get the public key direct from the secret one */
|
||||
|
||||
pub_keyblock=get_pubkeyblock(sk_keyid);
|
||||
if(!pub_keyblock)
|
||||
{
|
||||
log_error(_("no corresponding public key: %s\n"), g10_errstr(rc) );
|
||||
goto leave;
|
||||
}
|
||||
|
||||
node=find_kbnode(pub_keyblock,PKT_PUBLIC_KEY);
|
||||
if(!node)
|
||||
BUG();
|
||||
|
||||
pk=node->pkt->pkt.public_key;
|
||||
|
||||
if( cmp_public_secret_key( pk, sk ) ) {
|
||||
log_error(_("public key does not match secret key!\n") );
|
||||
rc = G10ERR_GENERAL;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
tty_printf("\n");
|
||||
if( !cpr_get_answer_is_yes("gen_revoke.okay",
|
||||
_("Create a revocation certificate for this key? ")) ){
|
||||
rc = 0;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if(sk->version>=4 || opt.force_v4_certs) {
|
||||
/* get the reason for the revocation */
|
||||
reason = ask_revocation_reason( 1, 0, 1 );
|
||||
if( !reason ) { /* user decided to cancel */
|
||||
rc = 0;
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
|
||||
switch( is_secret_key_protected( sk ) ) {
|
||||
case -1:
|
||||
log_error(_("unknown protection algorithm\n"));
|
||||
rc = G10ERR_PUBKEY_ALGO;
|
||||
break;
|
||||
case 0:
|
||||
tty_printf(_("NOTE: This key is not protected!\n"));
|
||||
break;
|
||||
default:
|
||||
rc = check_secret_key( sk, 0 );
|
||||
break;
|
||||
}
|
||||
if( rc )
|
||||
goto leave;
|
||||
|
||||
|
||||
if( !opt.armor )
|
||||
tty_printf(_("ASCII armored output forced.\n"));
|
||||
|
||||
if( (rc = open_outfile( NULL, 0, &out )) )
|
||||
goto leave;
|
||||
|
||||
afx.what = 1;
|
||||
afx.hdrlines = "Comment: A revocation certificate should follow\n";
|
||||
iobuf_push_filter( out, armor_filter, &afx );
|
||||
|
||||
/* create it */
|
||||
rc = make_keysig_packet( &sig, pk, NULL, NULL, sk, 0x20, 0,
|
||||
opt.force_v4_certs?4:0, 0, 0,
|
||||
revocation_reason_build_cb, reason );
|
||||
if( rc ) {
|
||||
log_error(_("make_keysig_packet failed: %s\n"), g10_errstr(rc));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if(PGP2 || PGP6 || PGP7 || PGP8)
|
||||
{
|
||||
/* Use a minimal pk for PGPx mode, since PGP can't import bare
|
||||
revocation certificates. */
|
||||
rc=export_minimal_pk(out,pub_keyblock,sig,NULL);
|
||||
if(rc)
|
||||
goto leave;
|
||||
}
|
||||
else
|
||||
{
|
||||
init_packet( &pkt );
|
||||
pkt.pkttype = PKT_SIGNATURE;
|
||||
pkt.pkt.signature = sig;
|
||||
|
||||
rc = build_packet( out, &pkt );
|
||||
if( rc ) {
|
||||
log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
|
||||
/* and issue a usage notice */
|
||||
tty_printf(_("Revocation certificate created.\n\n"
|
||||
"Please move it to a medium which you can hide away; if Mallory gets\n"
|
||||
"access to this certificate he can use it to make your key unusable.\n"
|
||||
"It is smart to print this certificate and store it away, just in case\n"
|
||||
"your media become unreadable. But have some caution: The print system of\n"
|
||||
"your machine might store the data and make it available to others!\n"));
|
||||
|
||||
leave:
|
||||
if( sig )
|
||||
free_seckey_enc( sig );
|
||||
release_kbnode( keyblock );
|
||||
release_kbnode( pub_keyblock );
|
||||
keydb_release (kdbhd);
|
||||
if( rc )
|
||||
iobuf_cancel(out);
|
||||
else
|
||||
iobuf_close(out);
|
||||
release_revocation_reason_info( reason );
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct revocation_reason_info *
|
||||
ask_revocation_reason( int key_rev, int cert_rev, int hint )
|
||||
{
|
||||
int code=-1;
|
||||
char *description = NULL;
|
||||
struct revocation_reason_info *reason;
|
||||
const char *text_0 = _("No reason specified");
|
||||
const char *text_1 = _("Key has been compromised");
|
||||
const char *text_2 = _("Key is superseded");
|
||||
const char *text_3 = _("Key is no longer used");
|
||||
const char *text_4 = _("User ID is no longer valid");
|
||||
const char *code_text = NULL;
|
||||
|
||||
do {
|
||||
code=-1;
|
||||
m_free(description);
|
||||
description = NULL;
|
||||
|
||||
tty_printf(_("Please select the reason for the revocation:\n"));
|
||||
tty_printf( " 0 = %s\n", text_0 );
|
||||
if( key_rev )
|
||||
tty_printf(" 1 = %s\n", text_1 );
|
||||
if( key_rev )
|
||||
tty_printf(" 2 = %s\n", text_2 );
|
||||
if( key_rev )
|
||||
tty_printf(" 3 = %s\n", text_3 );
|
||||
if( cert_rev )
|
||||
tty_printf(" 4 = %s\n", text_4 );
|
||||
tty_printf( " Q = %s\n", _("Cancel") );
|
||||
if( hint )
|
||||
tty_printf(_("(Probably you want to select %d here)\n"), hint );
|
||||
|
||||
while(code==-1) {
|
||||
int n;
|
||||
char *answer = cpr_get("ask_revocation_reason.code",
|
||||
_("Your decision? "));
|
||||
trim_spaces( answer );
|
||||
cpr_kill_prompt();
|
||||
if( *answer == 'q' || *answer == 'Q')
|
||||
return NULL; /* cancel */
|
||||
if( hint && !*answer )
|
||||
n = hint;
|
||||
else if(!isdigit( *answer ) )
|
||||
n = -1;
|
||||
else
|
||||
n = atoi(answer);
|
||||
m_free(answer);
|
||||
if( n == 0 ) {
|
||||
code = 0x00; /* no particular reason */
|
||||
code_text = text_0;
|
||||
}
|
||||
else if( key_rev && n == 1 ) {
|
||||
code = 0x02; /* key has been compromised */
|
||||
code_text = text_1;
|
||||
}
|
||||
else if( key_rev && n == 2 ) {
|
||||
code = 0x01; /* key is superseded */
|
||||
code_text = text_2;
|
||||
}
|
||||
else if( key_rev && n == 3 ) {
|
||||
code = 0x03; /* key is no longer used */
|
||||
code_text = text_3;
|
||||
}
|
||||
else if( cert_rev && n == 4 ) {
|
||||
code = 0x20; /* uid is no longer valid */
|
||||
code_text = text_4;
|
||||
}
|
||||
else
|
||||
tty_printf(_("Invalid selection.\n"));
|
||||
}
|
||||
|
||||
tty_printf(_("Enter an optional description; "
|
||||
"end it with an empty line:\n") );
|
||||
for(;;) {
|
||||
char *answer = cpr_get("ask_revocation_reason.text", "> " );
|
||||
trim_trailing_ws( answer, strlen(answer) );
|
||||
cpr_kill_prompt();
|
||||
if( !*answer ) {
|
||||
m_free(answer);
|
||||
break;
|
||||
}
|
||||
|
||||
{
|
||||
char *p = make_printable_string( answer, strlen(answer), 0 );
|
||||
m_free(answer);
|
||||
answer = p;
|
||||
}
|
||||
|
||||
if( !description )
|
||||
description = m_strdup(answer);
|
||||
else {
|
||||
char *p = m_alloc( strlen(description) + strlen(answer) + 2 );
|
||||
strcpy(stpcpy(stpcpy( p, description),"\n"),answer);
|
||||
m_free(description);
|
||||
description = p;
|
||||
}
|
||||
m_free(answer);
|
||||
}
|
||||
|
||||
tty_printf(_("Reason for revocation: %s\n"), code_text );
|
||||
if( !description )
|
||||
tty_printf(_("(No description given)\n") );
|
||||
else
|
||||
tty_printf("%s\n", description );
|
||||
|
||||
} while( !cpr_get_answer_is_yes("ask_revocation_reason.okay",
|
||||
_("Is this okay? ")) );
|
||||
|
||||
reason = m_alloc( sizeof *reason );
|
||||
reason->code = code;
|
||||
reason->desc = description;
|
||||
return reason;
|
||||
}
|
||||
|
||||
void
|
||||
release_revocation_reason_info( struct revocation_reason_info *reason )
|
||||
{
|
||||
if( reason ) {
|
||||
m_free( reason->desc );
|
||||
m_free( reason );
|
||||
}
|
||||
}
|
400
g10/seckey-cert.c
Normal file
400
g10/seckey-cert.c
Normal file
@ -0,0 +1,400 @@
|
||||
/* seckey-cert.c - secret key certificate packet handling
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "util.h"
|
||||
#include "memory.h"
|
||||
#include "packet.h"
|
||||
#include "mpi.h"
|
||||
#include "keydb.h"
|
||||
#include "cipher.h"
|
||||
#include "main.h"
|
||||
#include "options.h"
|
||||
#include "i18n.h"
|
||||
#include "status.h"
|
||||
|
||||
|
||||
static int
|
||||
do_check( PKT_secret_key *sk, const char *tryagain_text, int mode,
|
||||
int *canceled )
|
||||
{
|
||||
byte *buffer;
|
||||
u16 csum=0;
|
||||
int i, res;
|
||||
unsigned nbytes;
|
||||
|
||||
if( sk->is_protected ) { /* remove the protection */
|
||||
DEK *dek = NULL;
|
||||
u32 keyid[4]; /* 4! because we need two of them */
|
||||
CIPHER_HANDLE cipher_hd=NULL;
|
||||
PKT_secret_key *save_sk;
|
||||
|
||||
if( sk->protect.s2k.mode == 1001 ) {
|
||||
log_info(_("secret key parts are not available\n"));
|
||||
return G10ERR_GENERAL;
|
||||
}
|
||||
if( sk->protect.algo == CIPHER_ALGO_NONE )
|
||||
BUG();
|
||||
if( check_cipher_algo( sk->protect.algo ) ) {
|
||||
log_info(_("protection algorithm %d%s is not supported\n"),
|
||||
sk->protect.algo,sk->protect.algo==1?" (IDEA)":"" );
|
||||
if (sk->protect.algo==CIPHER_ALGO_IDEA)
|
||||
{
|
||||
write_status (STATUS_RSA_OR_IDEA);
|
||||
idea_cipher_warn (0);
|
||||
}
|
||||
return G10ERR_CIPHER_ALGO;
|
||||
}
|
||||
keyid_from_sk( sk, keyid );
|
||||
keyid[2] = keyid[3] = 0;
|
||||
if( !sk->is_primary ) {
|
||||
keyid[2] = sk->main_keyid[0];
|
||||
keyid[3] = sk->main_keyid[1];
|
||||
}
|
||||
dek = passphrase_to_dek( keyid, sk->pubkey_algo, sk->protect.algo,
|
||||
&sk->protect.s2k, mode,
|
||||
tryagain_text, canceled );
|
||||
if (!dek && canceled && *canceled)
|
||||
return G10ERR_GENERAL;
|
||||
|
||||
cipher_hd = cipher_open( sk->protect.algo,
|
||||
CIPHER_MODE_AUTO_CFB, 1);
|
||||
cipher_setkey( cipher_hd, dek->key, dek->keylen );
|
||||
m_free(dek);
|
||||
save_sk = copy_secret_key( NULL, sk );
|
||||
cipher_setiv( cipher_hd, sk->protect.iv, sk->protect.ivlen );
|
||||
csum = 0;
|
||||
if( sk->version >= 4 ) {
|
||||
int ndata;
|
||||
byte *p, *data;
|
||||
u16 csumc = 0;
|
||||
|
||||
i = pubkey_get_npkey(sk->pubkey_algo);
|
||||
assert( mpi_is_opaque( sk->skey[i] ) );
|
||||
p = mpi_get_opaque( sk->skey[i], &ndata );
|
||||
if ( ndata > 1 )
|
||||
csumc = p[ndata-2] << 8 | p[ndata-1];
|
||||
data = m_alloc_secure( ndata );
|
||||
cipher_decrypt( cipher_hd, data, p, ndata );
|
||||
mpi_free( sk->skey[i] ); sk->skey[i] = NULL ;
|
||||
p = data;
|
||||
if (sk->protect.sha1chk) {
|
||||
/* This is the new SHA1 checksum method to detect
|
||||
tampering with the key as used by the Klima/Rosa
|
||||
attack */
|
||||
sk->csum = 0;
|
||||
csum = 1;
|
||||
if( ndata < 20 )
|
||||
log_error("not enough bytes for SHA-1 checksum\n");
|
||||
else {
|
||||
MD_HANDLE h = md_open (DIGEST_ALGO_SHA1, 1);
|
||||
if (!h)
|
||||
BUG(); /* algo not available */
|
||||
md_write (h, data, ndata - 20);
|
||||
md_final (h);
|
||||
if (!memcmp (md_read (h, DIGEST_ALGO_SHA1),
|
||||
data + ndata - 20, 20) ) {
|
||||
/* digest does match. We have to keep the old
|
||||
style checksum in sk->csum, so that the
|
||||
test used for unprotected keys does work.
|
||||
This test gets used when we are adding new
|
||||
keys. */
|
||||
sk->csum = csum = checksum (data, ndata-20);
|
||||
}
|
||||
md_close (h);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if( ndata < 2 ) {
|
||||
log_error("not enough bytes for checksum\n");
|
||||
sk->csum = 0;
|
||||
csum = 1;
|
||||
}
|
||||
else {
|
||||
csum = checksum( data, ndata-2);
|
||||
sk->csum = data[ndata-2] << 8 | data[ndata-1];
|
||||
if ( sk->csum != csum ) {
|
||||
/* This is a PGP 7.0.0 workaround */
|
||||
sk->csum = csumc; /* take the encrypted one */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* must check it here otherwise the mpi_read_xx would fail
|
||||
because the length may have an arbitrary value */
|
||||
if( sk->csum == csum ) {
|
||||
for( ; i < pubkey_get_nskey(sk->pubkey_algo); i++ ) {
|
||||
nbytes = ndata;
|
||||
sk->skey[i] = mpi_read_from_buffer(p, &nbytes, 1 );
|
||||
ndata -= nbytes;
|
||||
p += nbytes;
|
||||
}
|
||||
/* Note: at this point ndata should be 2 for a simple
|
||||
checksum or 20 for the sha1 digest */
|
||||
}
|
||||
m_free(data);
|
||||
}
|
||||
else {
|
||||
for(i=pubkey_get_npkey(sk->pubkey_algo);
|
||||
i < pubkey_get_nskey(sk->pubkey_algo); i++ ) {
|
||||
byte *p;
|
||||
int ndata;
|
||||
unsigned int dummy;
|
||||
|
||||
assert (mpi_is_opaque (sk->skey[i]));
|
||||
p = mpi_get_opaque (sk->skey[i], &ndata);
|
||||
assert (ndata >= 2);
|
||||
assert (ndata == ((p[0] << 8 | p[1]) + 7)/8 + 2);
|
||||
buffer = m_alloc_secure (ndata);
|
||||
cipher_sync (cipher_hd);
|
||||
buffer[0] = p[0];
|
||||
buffer[1] = p[1];
|
||||
cipher_decrypt (cipher_hd, buffer+2, p+2, ndata-2);
|
||||
csum += checksum (buffer, ndata);
|
||||
mpi_free (sk->skey[i]);
|
||||
dummy = ndata;
|
||||
sk->skey[i] = mpi_read_from_buffer (buffer, &dummy, 1);
|
||||
assert (sk->skey[i]);
|
||||
m_free (buffer);
|
||||
/* csum += checksum_mpi (sk->skey[i]); */
|
||||
}
|
||||
}
|
||||
cipher_close( cipher_hd );
|
||||
/* now let's see whether we have used the right passphrase */
|
||||
if( csum != sk->csum ) {
|
||||
copy_secret_key( sk, save_sk );
|
||||
passphrase_clear_cache ( keyid, sk->pubkey_algo );
|
||||
free_secret_key( save_sk );
|
||||
return G10ERR_BAD_PASS;
|
||||
}
|
||||
/* the checksum may fail, so we also check the key itself */
|
||||
res = pubkey_check_secret_key( sk->pubkey_algo, sk->skey );
|
||||
if( res ) {
|
||||
copy_secret_key( sk, save_sk );
|
||||
passphrase_clear_cache ( keyid, sk->pubkey_algo );
|
||||
free_secret_key( save_sk );
|
||||
return G10ERR_BAD_PASS;
|
||||
}
|
||||
free_secret_key( save_sk );
|
||||
sk->is_protected = 0;
|
||||
}
|
||||
else { /* not protected, assume it is okay if the checksum is okay */
|
||||
csum = 0;
|
||||
for(i=pubkey_get_npkey(sk->pubkey_algo);
|
||||
i < pubkey_get_nskey(sk->pubkey_algo); i++ ) {
|
||||
csum += checksum_mpi( sk->skey[i] );
|
||||
}
|
||||
if( csum != sk->csum )
|
||||
return G10ERR_CHECKSUM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/****************
|
||||
* Check the secret key
|
||||
* Ask up to 3 (or n) times for a correct passphrase
|
||||
* If n is negative, disable the key info prompt and make n=abs(n)
|
||||
*/
|
||||
int
|
||||
check_secret_key( PKT_secret_key *sk, int n )
|
||||
{
|
||||
int rc = G10ERR_BAD_PASS;
|
||||
int i,mode;
|
||||
|
||||
if(n<0)
|
||||
{
|
||||
n=abs(n);
|
||||
mode=1;
|
||||
}
|
||||
else
|
||||
mode=0;
|
||||
|
||||
if( n < 1 )
|
||||
n = (opt.batch && !opt.use_agent)? 1 : 3; /* use the default value */
|
||||
|
||||
for(i=0; i < n && rc == G10ERR_BAD_PASS; i++ ) {
|
||||
int canceled = 0;
|
||||
const char *tryagain = NULL;
|
||||
if (i) {
|
||||
tryagain = N_("Invalid passphrase; please try again");
|
||||
log_info (_("%s ...\n"), _(tryagain));
|
||||
}
|
||||
rc = do_check( sk, tryagain, mode, &canceled );
|
||||
if( rc == G10ERR_BAD_PASS && is_status_enabled() ) {
|
||||
u32 kid[2];
|
||||
char buf[50];
|
||||
|
||||
keyid_from_sk( sk, kid );
|
||||
sprintf(buf, "%08lX%08lX", (ulong)kid[0], (ulong)kid[1]);
|
||||
write_status_text( STATUS_BAD_PASSPHRASE, buf );
|
||||
}
|
||||
if( have_static_passphrase() || canceled)
|
||||
break;
|
||||
}
|
||||
|
||||
if( !rc )
|
||||
write_status( STATUS_GOOD_PASSPHRASE );
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/****************
|
||||
* check whether the secret key is protected.
|
||||
* Returns: 0 not protected, -1 on error or the protection algorithm
|
||||
*/
|
||||
int
|
||||
is_secret_key_protected( PKT_secret_key *sk )
|
||||
{
|
||||
return sk->is_protected? sk->protect.algo : 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/****************
|
||||
* Protect the secret key with the passphrase from DEK
|
||||
*/
|
||||
int
|
||||
protect_secret_key( PKT_secret_key *sk, DEK *dek )
|
||||
{
|
||||
int i,j, rc = 0;
|
||||
byte *buffer;
|
||||
unsigned nbytes;
|
||||
u16 csum;
|
||||
|
||||
if( !dek )
|
||||
return 0;
|
||||
|
||||
if( !sk->is_protected ) { /* okay, apply the protection */
|
||||
CIPHER_HANDLE cipher_hd=NULL;
|
||||
|
||||
if( check_cipher_algo( sk->protect.algo ) )
|
||||
rc = G10ERR_CIPHER_ALGO; /* unsupport protection algorithm */
|
||||
else {
|
||||
print_cipher_algo_note( sk->protect.algo );
|
||||
cipher_hd = cipher_open( sk->protect.algo,
|
||||
CIPHER_MODE_AUTO_CFB, 1 );
|
||||
if( cipher_setkey( cipher_hd, dek->key, dek->keylen ) )
|
||||
log_info(_("WARNING: Weak key detected"
|
||||
" - please change passphrase again.\n"));
|
||||
sk->protect.ivlen = cipher_get_blocksize( sk->protect.algo );
|
||||
assert( sk->protect.ivlen <= DIM(sk->protect.iv) );
|
||||
if( sk->protect.ivlen != 8 && sk->protect.ivlen != 16 )
|
||||
BUG(); /* yes, we are very careful */
|
||||
randomize_buffer(sk->protect.iv, sk->protect.ivlen, 1);
|
||||
cipher_setiv( cipher_hd, sk->protect.iv, sk->protect.ivlen );
|
||||
if( sk->version >= 4 ) {
|
||||
byte *bufarr[PUBKEY_MAX_NSKEY];
|
||||
unsigned narr[PUBKEY_MAX_NSKEY];
|
||||
unsigned nbits[PUBKEY_MAX_NSKEY];
|
||||
int ndata=0;
|
||||
byte *p, *data;
|
||||
|
||||
for(j=0, i = pubkey_get_npkey(sk->pubkey_algo);
|
||||
i < pubkey_get_nskey(sk->pubkey_algo); i++, j++ ) {
|
||||
assert( !mpi_is_opaque( sk->skey[i] ) );
|
||||
bufarr[j] = mpi_get_buffer( sk->skey[i], &narr[j], NULL );
|
||||
nbits[j] = mpi_get_nbits( sk->skey[i] );
|
||||
ndata += narr[j] + 2;
|
||||
}
|
||||
for( ; j < PUBKEY_MAX_NSKEY; j++ )
|
||||
bufarr[j] = NULL;
|
||||
ndata += opt.simple_sk_checksum? 2 : 20; /* for checksum */
|
||||
|
||||
data = m_alloc_secure( ndata );
|
||||
p = data;
|
||||
for(j=0; j < PUBKEY_MAX_NSKEY && bufarr[j]; j++ ) {
|
||||
p[0] = nbits[j] >> 8 ;
|
||||
p[1] = nbits[j];
|
||||
p += 2;
|
||||
memcpy(p, bufarr[j], narr[j] );
|
||||
p += narr[j];
|
||||
m_free(bufarr[j]);
|
||||
}
|
||||
|
||||
if (opt.simple_sk_checksum) {
|
||||
log_info (_("generating the deprecated 16-bit checksum"
|
||||
" for secret key protection\n"));
|
||||
csum = checksum( data, ndata-2);
|
||||
sk->csum = csum;
|
||||
*p++ = csum >> 8;
|
||||
*p++ = csum;
|
||||
sk->protect.sha1chk = 0;
|
||||
}
|
||||
else {
|
||||
MD_HANDLE h = md_open (DIGEST_ALGO_SHA1, 1);
|
||||
if (!h)
|
||||
BUG(); /* algo not available */
|
||||
md_write (h, data, ndata - 20);
|
||||
md_final (h);
|
||||
memcpy (p, md_read (h, DIGEST_ALGO_SHA1), 20);
|
||||
p += 20;
|
||||
md_close (h);
|
||||
sk->csum = csum = 0;
|
||||
sk->protect.sha1chk = 1;
|
||||
}
|
||||
assert( p == data+ndata );
|
||||
|
||||
cipher_encrypt( cipher_hd, data, data, ndata );
|
||||
for(i = pubkey_get_npkey(sk->pubkey_algo);
|
||||
i < pubkey_get_nskey(sk->pubkey_algo); i++ ) {
|
||||
mpi_free( sk->skey[i] );
|
||||
sk->skey[i] = NULL;
|
||||
}
|
||||
i = pubkey_get_npkey(sk->pubkey_algo);
|
||||
sk->skey[i] = mpi_set_opaque(NULL, data, ndata );
|
||||
}
|
||||
else {
|
||||
csum = 0;
|
||||
for(i=pubkey_get_npkey(sk->pubkey_algo);
|
||||
i < pubkey_get_nskey(sk->pubkey_algo); i++ ) {
|
||||
byte *data;
|
||||
unsigned int nbits;
|
||||
|
||||
csum += checksum_mpi (sk->skey[i]);
|
||||
buffer = mpi_get_buffer( sk->skey[i], &nbytes, NULL );
|
||||
cipher_sync (cipher_hd);
|
||||
assert ( !mpi_is_opaque (sk->skey[i]) );
|
||||
data = m_alloc (nbytes+2);
|
||||
nbits = mpi_get_nbits (sk->skey[i]);
|
||||
assert (nbytes == (nbits + 7)/8);
|
||||
data[0] = nbits >> 8;
|
||||
data[1] = nbits;
|
||||
cipher_encrypt (cipher_hd, data+2, buffer, nbytes);
|
||||
m_free( buffer );
|
||||
|
||||
mpi_free (sk->skey[i]);
|
||||
sk->skey[i] = mpi_set_opaque (NULL, data, nbytes+2);
|
||||
}
|
||||
sk->csum = csum;
|
||||
}
|
||||
sk->is_protected = 1;
|
||||
cipher_close( cipher_hd );
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
625
g10/sig-check.c
Normal file
625
g10/sig-check.c
Normal file
@ -0,0 +1,625 @@
|
||||
/* sig-check.c - Check a signature
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "util.h"
|
||||
#include "packet.h"
|
||||
#include "memory.h"
|
||||
#include "mpi.h"
|
||||
#include "keydb.h"
|
||||
#include "cipher.h"
|
||||
#include "main.h"
|
||||
#include "status.h"
|
||||
#include "i18n.h"
|
||||
#include "options.h"
|
||||
|
||||
struct cmp_help_context_s {
|
||||
PKT_signature *sig;
|
||||
MD_HANDLE md;
|
||||
};
|
||||
|
||||
static int do_check( PKT_public_key *pk, PKT_signature *sig,
|
||||
MD_HANDLE digest, int *r_expired );
|
||||
|
||||
/****************
|
||||
* Check the signature which is contained in SIG.
|
||||
* The MD_HANDLE should be currently open, so that this function
|
||||
* is able to append some data, before finalizing the digest.
|
||||
*/
|
||||
int
|
||||
signature_check( PKT_signature *sig, MD_HANDLE digest )
|
||||
{
|
||||
u32 dummy;
|
||||
int dum2;
|
||||
return signature_check2( sig, digest, &dummy, &dum2 );
|
||||
}
|
||||
|
||||
int
|
||||
signature_check2( PKT_signature *sig, MD_HANDLE digest,
|
||||
u32 *r_expiredate, int *r_expired )
|
||||
{
|
||||
PKT_public_key *pk = m_alloc_clear( sizeof *pk );
|
||||
int rc=0;
|
||||
|
||||
*r_expiredate = 0;
|
||||
|
||||
/* Sanity check that the md has a context for the hash that the
|
||||
sig is expecting. This can happen if a onepass sig header does
|
||||
not match the actual sig, and also if the clearsign "Hash:"
|
||||
header is missing or does not match the actual sig. */
|
||||
|
||||
if(!md_algo_present(digest,sig->digest_algo)) {
|
||||
log_info(_("WARNING: signature digest conflict in message\n"));
|
||||
rc=G10ERR_GENERAL;
|
||||
}
|
||||
else if( get_pubkey( pk, sig->keyid ) )
|
||||
rc = G10ERR_NO_PUBKEY;
|
||||
else if(!pk->is_valid && !pk->is_primary)
|
||||
rc=G10ERR_BAD_PUBKEY; /* you cannot have a good sig from an
|
||||
invalid subkey */
|
||||
else {
|
||||
*r_expiredate = pk->expiredate;
|
||||
rc = do_check( pk, sig, digest, r_expired );
|
||||
}
|
||||
|
||||
free_public_key( pk );
|
||||
|
||||
if( !rc && sig->sig_class < 2 && is_status_enabled() ) {
|
||||
/* This signature id works best with DLP algorithms because
|
||||
* they use a random parameter for every signature. Instead of
|
||||
* this sig-id we could have also used the hash of the document
|
||||
* and the timestamp, but the drawback of this is, that it is
|
||||
* not possible to sign more than one identical document within
|
||||
* one second. Some remote batch processing applications might
|
||||
* like this feature here */
|
||||
MD_HANDLE md;
|
||||
u32 a = sig->timestamp;
|
||||
int i, nsig = pubkey_get_nsig( sig->pubkey_algo );
|
||||
byte *p, *buffer;
|
||||
|
||||
md = md_open( DIGEST_ALGO_RMD160, 0);
|
||||
md_putc( digest, sig->pubkey_algo );
|
||||
md_putc( digest, sig->digest_algo );
|
||||
md_putc( digest, (a >> 24) & 0xff );
|
||||
md_putc( digest, (a >> 16) & 0xff );
|
||||
md_putc( digest, (a >> 8) & 0xff );
|
||||
md_putc( digest, a & 0xff );
|
||||
for(i=0; i < nsig; i++ ) {
|
||||
unsigned n = mpi_get_nbits( sig->data[i]);
|
||||
|
||||
md_putc( md, n>>8);
|
||||
md_putc( md, n );
|
||||
p = mpi_get_buffer( sig->data[i], &n, NULL );
|
||||
md_write( md, p, n );
|
||||
m_free(p);
|
||||
}
|
||||
md_final( md );
|
||||
p = make_radix64_string( md_read( md, 0 ), 20 );
|
||||
buffer = m_alloc( strlen(p) + 60 );
|
||||
sprintf( buffer, "%s %s %lu",
|
||||
p, strtimestamp( sig->timestamp ), (ulong)sig->timestamp );
|
||||
write_status_text( STATUS_SIG_ID, buffer );
|
||||
m_free(buffer);
|
||||
m_free(p);
|
||||
md_close(md);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
* This function gets called by pubkey_verify() if the algorithm needs it.
|
||||
*/
|
||||
static int
|
||||
cmp_help( void *opaque, MPI result )
|
||||
{
|
||||
#if 0 /* we do not use this anymore */
|
||||
int rc=0, i, j, c, old_enc;
|
||||
byte *dp;
|
||||
const byte *asn;
|
||||
size_t mdlen, asnlen;
|
||||
struct cmp_help_context_s *ctx = opaque;
|
||||
PKT_signature *sig = ctx->sig;
|
||||
MD_HANDLE digest = ctx->md;
|
||||
|
||||
old_enc = 0;
|
||||
for(i=j=0; (c=mpi_getbyte(result, i)) != -1; i++ ) {
|
||||
if( !j ) {
|
||||
if( !i && c != 1 )
|
||||
break;
|
||||
else if( i && c == 0xff )
|
||||
; /* skip the padding */
|
||||
else if( i && !c )
|
||||
j++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
else if( ++j == 18 && c != 1 )
|
||||
break;
|
||||
else if( j == 19 && c == 0 ) {
|
||||
old_enc++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( old_enc ) {
|
||||
log_error("old encoding scheme is not supported\n");
|
||||
return G10ERR_GENERAL;
|
||||
}
|
||||
|
||||
if( (rc=check_digest_algo(sig->digest_algo)) )
|
||||
return rc; /* unsupported algo */
|
||||
asn = md_asn_oid( sig->digest_algo, &asnlen, &mdlen );
|
||||
|
||||
for(i=mdlen,j=asnlen-1; (c=mpi_getbyte(result, i)) != -1 && j >= 0;
|
||||
i++, j-- )
|
||||
if( asn[j] != c )
|
||||
break;
|
||||
if( j != -1 || mpi_getbyte(result, i) )
|
||||
return G10ERR_BAD_PUBKEY; /* ASN is wrong */
|
||||
for(i++; (c=mpi_getbyte(result, i)) != -1; i++ )
|
||||
if( c != 0xff )
|
||||
break;
|
||||
i++;
|
||||
if( c != sig->digest_algo || mpi_getbyte(result, i) ) {
|
||||
/* Padding or leading bytes in signature is wrong */
|
||||
return G10ERR_BAD_PUBKEY;
|
||||
}
|
||||
if( mpi_getbyte(result, mdlen-1) != sig->digest_start[0]
|
||||
|| mpi_getbyte(result, mdlen-2) != sig->digest_start[1] ) {
|
||||
/* Wrong key used to check the signature */
|
||||
return G10ERR_BAD_PUBKEY;
|
||||
}
|
||||
|
||||
dp = md_read( digest, sig->digest_algo );
|
||||
for(i=mdlen-1; i >= 0; i--, dp++ ) {
|
||||
if( mpi_getbyte( result, i ) != *dp )
|
||||
return G10ERR_BAD_SIGN;
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
do_check_messages( PKT_public_key *pk, PKT_signature *sig, int *r_expired )
|
||||
{
|
||||
u32 cur_time;
|
||||
|
||||
*r_expired = 0;
|
||||
if( pk->version == 4 && pk->pubkey_algo == PUBKEY_ALGO_ELGAMAL_E ) {
|
||||
log_info(_("key %08lX: this is a PGP generated "
|
||||
"ElGamal key which is NOT secure for signatures!\n"),
|
||||
(ulong)keyid_from_pk(pk,NULL));
|
||||
return G10ERR_PUBKEY_ALGO;
|
||||
}
|
||||
|
||||
if( pk->timestamp > sig->timestamp ) {
|
||||
ulong d = pk->timestamp - sig->timestamp;
|
||||
log_info( d==1
|
||||
? _("public key %08lX is %lu second newer than the signature\n")
|
||||
: _("public key %08lX is %lu seconds newer than the signature\n"),
|
||||
(ulong)keyid_from_pk(pk,NULL),d );
|
||||
if( !opt.ignore_time_conflict )
|
||||
return G10ERR_TIME_CONFLICT; /* pubkey newer than signature */
|
||||
}
|
||||
|
||||
cur_time = make_timestamp();
|
||||
if( pk->timestamp > cur_time ) {
|
||||
ulong d = pk->timestamp - cur_time;
|
||||
log_info( d==1 ? _("key %08lX has been created %lu second "
|
||||
"in future (time warp or clock problem)\n")
|
||||
: _("key %08lX has been created %lu seconds "
|
||||
"in future (time warp or clock problem)\n"),
|
||||
(ulong)keyid_from_pk(pk,NULL),d );
|
||||
if( !opt.ignore_time_conflict )
|
||||
return G10ERR_TIME_CONFLICT;
|
||||
}
|
||||
|
||||
if( pk->expiredate && pk->expiredate < cur_time ) {
|
||||
char buf[11];
|
||||
if (opt.verbose) {
|
||||
u32 tmp_kid[2];
|
||||
|
||||
keyid_from_pk( pk, tmp_kid );
|
||||
log_info(_("NOTE: signature key %08lX expired %s\n"),
|
||||
(ulong)tmp_kid[1], asctimestamp( pk->expiredate ) );
|
||||
}
|
||||
/* SIGEXPIRED is deprecated. Use KEYEXPIRED. */
|
||||
sprintf(buf,"%lu",(ulong)pk->expiredate);
|
||||
write_status_text(STATUS_KEYEXPIRED,buf);
|
||||
write_status(STATUS_SIGEXPIRED);
|
||||
*r_expired = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
do_check( PKT_public_key *pk, PKT_signature *sig, MD_HANDLE digest,
|
||||
int *r_expired )
|
||||
{
|
||||
MPI result = NULL;
|
||||
int rc=0;
|
||||
struct cmp_help_context_s ctx;
|
||||
|
||||
if( (rc=do_check_messages(pk,sig,r_expired)) )
|
||||
return rc;
|
||||
if( (rc=check_digest_algo(sig->digest_algo)) )
|
||||
return rc;
|
||||
if( (rc=check_pubkey_algo(sig->pubkey_algo)) )
|
||||
return rc;
|
||||
|
||||
/* make sure the digest algo is enabled (in case of a detached signature)*/
|
||||
md_enable( digest, sig->digest_algo );
|
||||
|
||||
/* complete the digest */
|
||||
if( sig->version >= 4 )
|
||||
md_putc( digest, sig->version );
|
||||
md_putc( digest, sig->sig_class );
|
||||
if( sig->version < 4 ) {
|
||||
u32 a = sig->timestamp;
|
||||
md_putc( digest, (a >> 24) & 0xff );
|
||||
md_putc( digest, (a >> 16) & 0xff );
|
||||
md_putc( digest, (a >> 8) & 0xff );
|
||||
md_putc( digest, a & 0xff );
|
||||
}
|
||||
else {
|
||||
byte buf[6];
|
||||
size_t n;
|
||||
md_putc( digest, sig->pubkey_algo );
|
||||
md_putc( digest, sig->digest_algo );
|
||||
if( sig->hashed ) {
|
||||
n = sig->hashed->len;
|
||||
md_putc (digest, (n >> 8) );
|
||||
md_putc (digest, n );
|
||||
md_write (digest, sig->hashed->data, n);
|
||||
n += 6;
|
||||
}
|
||||
else {
|
||||
/* Two octets for the (empty) length of the hashed
|
||||
section. */
|
||||
md_putc (digest, 0);
|
||||
md_putc (digest, 0);
|
||||
n = 6;
|
||||
}
|
||||
/* add some magic */
|
||||
buf[0] = sig->version;
|
||||
buf[1] = 0xff;
|
||||
buf[2] = n >> 24;
|
||||
buf[3] = n >> 16;
|
||||
buf[4] = n >> 8;
|
||||
buf[5] = n;
|
||||
md_write( digest, buf, 6 );
|
||||
}
|
||||
md_final( digest );
|
||||
|
||||
result = encode_md_value( pk->pubkey_algo, digest, sig->digest_algo,
|
||||
mpi_get_nbits(pk->pkey[0]), 0 );
|
||||
if (!result)
|
||||
return G10ERR_GENERAL;
|
||||
ctx.sig = sig;
|
||||
ctx.md = digest;
|
||||
rc = pubkey_verify( pk->pubkey_algo, result, sig->data, pk->pkey,
|
||||
cmp_help, &ctx );
|
||||
mpi_free( result );
|
||||
if( (opt.emulate_bugs & EMUBUG_MDENCODE)
|
||||
&& rc == G10ERR_BAD_SIGN && is_ELGAMAL(pk->pubkey_algo) ) {
|
||||
/* In this case we try again because old GnuPG versions didn't encode
|
||||
* the hash right. There is no problem with DSA however */
|
||||
result = encode_md_value( pk->pubkey_algo, digest, sig->digest_algo,
|
||||
mpi_get_nbits(pk->pkey[0]), (sig->version < 5) );
|
||||
if (!result)
|
||||
rc = G10ERR_GENERAL;
|
||||
else {
|
||||
ctx.sig = sig;
|
||||
ctx.md = digest;
|
||||
rc = pubkey_verify( pk->pubkey_algo, result, sig->data, pk->pkey,
|
||||
cmp_help, &ctx );
|
||||
}
|
||||
}
|
||||
|
||||
if( !rc && sig->flags.unknown_critical ) {
|
||||
log_info(_("assuming bad signature from key %08lX due to an unknown critical bit\n"),(ulong)keyid_from_pk(pk,NULL));
|
||||
rc = G10ERR_BAD_SIGN;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
hash_uid_node( KBNODE unode, MD_HANDLE md, PKT_signature *sig )
|
||||
{
|
||||
PKT_user_id *uid = unode->pkt->pkt.user_id;
|
||||
|
||||
assert( unode->pkt->pkttype == PKT_USER_ID );
|
||||
if( uid->attrib_data ) {
|
||||
if( sig->version >=4 ) {
|
||||
byte buf[5];
|
||||
buf[0] = 0xd1; /* packet of type 17 */
|
||||
buf[1] = uid->attrib_len >> 24; /* always use 4 length bytes */
|
||||
buf[2] = uid->attrib_len >> 16;
|
||||
buf[3] = uid->attrib_len >> 8;
|
||||
buf[4] = uid->attrib_len;
|
||||
md_write( md, buf, 5 );
|
||||
}
|
||||
md_write( md, uid->attrib_data, uid->attrib_len );
|
||||
}
|
||||
else {
|
||||
if( sig->version >=4 ) {
|
||||
byte buf[5];
|
||||
buf[0] = 0xb4; /* indicates a userid packet */
|
||||
buf[1] = uid->len >> 24; /* always use 4 length bytes */
|
||||
buf[2] = uid->len >> 16;
|
||||
buf[3] = uid->len >> 8;
|
||||
buf[4] = uid->len;
|
||||
md_write( md, buf, 5 );
|
||||
}
|
||||
md_write( md, uid->name, uid->len );
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cache_sig_result ( PKT_signature *sig, int result )
|
||||
{
|
||||
if ( !result ) {
|
||||
sig->flags.checked = 1;
|
||||
sig->flags.valid = 1;
|
||||
}
|
||||
else if ( result == G10ERR_BAD_SIGN ) {
|
||||
sig->flags.checked = 1;
|
||||
sig->flags.valid = 0;
|
||||
}
|
||||
else {
|
||||
sig->flags.checked = 0;
|
||||
sig->flags.valid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Check the revocation keys to see if any of them have revoked our
|
||||
pk. sig is the revocation sig. pk is the key it is on. This code
|
||||
will need to be modified if gpg ever becomes multi-threaded. Note
|
||||
that this guarantees that a designated revocation sig will never be
|
||||
considered valid unless it is actually valid, as well as being
|
||||
issued by a revocation key in a valid direct signature. Note that
|
||||
this is written so that a revoked revoker can still issue
|
||||
revocations: i.e. If A revokes B, but A is revoked, B is still
|
||||
revoked. I'm not completely convinced this is the proper behavior,
|
||||
but it matches how PGP does it. -dms */
|
||||
|
||||
/* Returns 0 if sig is valid (i.e. pk is revoked), non-0 if not
|
||||
revoked */
|
||||
int
|
||||
check_revocation_keys(PKT_public_key *pk,PKT_signature *sig)
|
||||
{
|
||||
static int busy=0;
|
||||
int i,rc=G10ERR_GENERAL;
|
||||
|
||||
assert(IS_KEY_REV(sig));
|
||||
assert((sig->keyid[0]!=pk->keyid[0]) || (sig->keyid[0]!=pk->keyid[1]));
|
||||
|
||||
if(busy)
|
||||
{
|
||||
/* return -1 (i.e. not revoked), but mark the pk as uncacheable
|
||||
as we don't really know its revocation status until it is
|
||||
checked directly. */
|
||||
|
||||
pk->dont_cache=1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
busy=1;
|
||||
|
||||
/* printf("looking at %08lX with a sig from %08lX\n",(ulong)pk->keyid[1],
|
||||
(ulong)sig->keyid[1]); */
|
||||
|
||||
/* is the issuer of the sig one of our revokers? */
|
||||
if( !pk->revkey && pk->numrevkeys )
|
||||
BUG();
|
||||
else
|
||||
for(i=0;i<pk->numrevkeys;i++)
|
||||
{
|
||||
u32 keyid[2];
|
||||
|
||||
keyid_from_fingerprint(pk->revkey[i].fpr,MAX_FINGERPRINT_LEN,keyid);
|
||||
|
||||
if(keyid[0]==sig->keyid[0] && keyid[1]==sig->keyid[1])
|
||||
{
|
||||
MD_HANDLE md;
|
||||
|
||||
md=md_open(sig->digest_algo,0);
|
||||
hash_public_key(md,pk);
|
||||
rc=signature_check(sig,md);
|
||||
cache_sig_result(sig,rc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
busy=0;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/****************
|
||||
* check the signature pointed to by NODE. This is a key signature.
|
||||
* If the function detects a self-signature, it uses the PK from
|
||||
* ROOT and does not read any public key.
|
||||
*/
|
||||
int
|
||||
check_key_signature( KBNODE root, KBNODE node, int *is_selfsig )
|
||||
{
|
||||
u32 dummy;
|
||||
int dum2;
|
||||
return check_key_signature2(root, node, NULL, is_selfsig, &dummy, &dum2 );
|
||||
}
|
||||
|
||||
/* If check_pk is set, then use it to check the signature in node
|
||||
rather than getting it from root or the keydb. */
|
||||
int
|
||||
check_key_signature2( KBNODE root, KBNODE node, PKT_public_key *check_pk,
|
||||
int *is_selfsig, u32 *r_expiredate, int *r_expired )
|
||||
{
|
||||
MD_HANDLE md;
|
||||
PKT_public_key *pk;
|
||||
PKT_signature *sig;
|
||||
int algo;
|
||||
int rc;
|
||||
|
||||
if( is_selfsig )
|
||||
*is_selfsig = 0;
|
||||
*r_expiredate = 0;
|
||||
*r_expired = 0;
|
||||
assert( node->pkt->pkttype == PKT_SIGNATURE );
|
||||
assert( root->pkt->pkttype == PKT_PUBLIC_KEY );
|
||||
|
||||
pk = root->pkt->pkt.public_key;
|
||||
sig = node->pkt->pkt.signature;
|
||||
algo = sig->digest_algo;
|
||||
|
||||
/* check whether we have cached the result of a previous signature check.*/
|
||||
if ( !opt.no_sig_cache ) {
|
||||
if (sig->flags.checked) { /*cached status available*/
|
||||
if( is_selfsig ) {
|
||||
u32 keyid[2];
|
||||
|
||||
keyid_from_pk( pk, keyid );
|
||||
if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] )
|
||||
*is_selfsig = 1;
|
||||
}
|
||||
if((rc=do_check_messages(pk,sig,r_expired)))
|
||||
return rc;
|
||||
return sig->flags.valid? 0 : G10ERR_BAD_SIGN;
|
||||
}
|
||||
}
|
||||
|
||||
if( (rc=check_digest_algo(algo)) )
|
||||
return rc;
|
||||
|
||||
if( sig->sig_class == 0x20 ) { /* key revocation */
|
||||
u32 keyid[2];
|
||||
keyid_from_pk( pk, keyid );
|
||||
|
||||
/* is it a designated revoker? */
|
||||
if(keyid[0]!=sig->keyid[0] || keyid[1]!=sig->keyid[1])
|
||||
rc=check_revocation_keys(pk,sig);
|
||||
else
|
||||
{
|
||||
md = md_open( algo, 0 );
|
||||
hash_public_key( md, pk );
|
||||
rc = do_check( pk, sig, md, r_expired );
|
||||
cache_sig_result ( sig, rc );
|
||||
md_close(md);
|
||||
}
|
||||
}
|
||||
else if( sig->sig_class == 0x28 ) { /* subkey revocation */
|
||||
KBNODE snode = find_prev_kbnode( root, node, PKT_PUBLIC_SUBKEY );
|
||||
|
||||
if( snode ) {
|
||||
md = md_open( algo, 0 );
|
||||
hash_public_key( md, pk );
|
||||
hash_public_key( md, snode->pkt->pkt.public_key );
|
||||
rc = do_check( pk, sig, md, r_expired );
|
||||
cache_sig_result ( sig, rc );
|
||||
md_close(md);
|
||||
}
|
||||
else {
|
||||
if (!opt.quiet)
|
||||
log_info (_("key %08lX: no subkey for subkey "
|
||||
"revocation signature\n"),
|
||||
(ulong)keyid_from_pk (pk, NULL));
|
||||
rc = G10ERR_SIG_CLASS;
|
||||
}
|
||||
}
|
||||
else if( sig->sig_class == 0x18 ) { /* key binding */
|
||||
KBNODE snode = find_prev_kbnode( root, node, PKT_PUBLIC_SUBKEY );
|
||||
|
||||
if( snode ) {
|
||||
if( is_selfsig ) { /* does this make sense????? */
|
||||
u32 keyid[2]; /* it should always be a selfsig */
|
||||
|
||||
keyid_from_pk( pk, keyid );
|
||||
if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] )
|
||||
*is_selfsig = 1;
|
||||
}
|
||||
md = md_open( algo, 0 );
|
||||
hash_public_key( md, pk );
|
||||
hash_public_key( md, snode->pkt->pkt.public_key );
|
||||
rc = do_check( pk, sig, md, r_expired );
|
||||
cache_sig_result ( sig, rc );
|
||||
md_close(md);
|
||||
}
|
||||
else {
|
||||
if (opt.verbose)
|
||||
log_info(_("key %08lX: no subkey for subkey "
|
||||
"binding signature\n"),
|
||||
(ulong)keyid_from_pk (pk, NULL));
|
||||
rc = G10ERR_SIG_CLASS;
|
||||
}
|
||||
}
|
||||
else if( sig->sig_class == 0x1f ) { /* direct key signature */
|
||||
md = md_open( algo, 0 );
|
||||
hash_public_key( md, pk );
|
||||
rc = do_check( pk, sig, md, r_expired );
|
||||
cache_sig_result ( sig, rc );
|
||||
md_close(md);
|
||||
}
|
||||
else { /* all other classes */
|
||||
KBNODE unode = find_prev_kbnode( root, node, PKT_USER_ID );
|
||||
|
||||
if( unode ) {
|
||||
u32 keyid[2];
|
||||
|
||||
keyid_from_pk( pk, keyid );
|
||||
md = md_open( algo, 0 );
|
||||
hash_public_key( md, pk );
|
||||
hash_uid_node( unode, md, sig );
|
||||
if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] )
|
||||
{
|
||||
if( is_selfsig )
|
||||
*is_selfsig = 1;
|
||||
rc = do_check( pk, sig, md, r_expired );
|
||||
}
|
||||
else if (check_pk)
|
||||
rc=do_check(check_pk,sig,md,r_expired);
|
||||
else
|
||||
rc = signature_check2( sig, md, r_expiredate, r_expired );
|
||||
|
||||
cache_sig_result ( sig, rc );
|
||||
md_close(md);
|
||||
}
|
||||
else {
|
||||
if (!opt.quiet)
|
||||
log_info ("key %08lX: no user ID for key signature packet "
|
||||
"of class %02x\n",
|
||||
(ulong)keyid_from_pk (pk, NULL), sig->sig_class );
|
||||
rc = G10ERR_SIG_CLASS;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
1358
g10/sign.c
Normal file
1358
g10/sign.c
Normal file
File diff suppressed because it is too large
Load Diff
217
g10/signal.c
Normal file
217
g10/signal.c
Normal file
@ -0,0 +1,217 @@
|
||||
/* signal.c - signal handling
|
||||
* Copyright (C) 1998, 1999, 2000, 2001 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "options.h"
|
||||
#include "errors.h"
|
||||
#include "memory.h"
|
||||
#include "util.h"
|
||||
#include "main.h"
|
||||
#include "ttyio.h"
|
||||
|
||||
|
||||
static volatile int caught_fatal_sig = 0;
|
||||
static volatile int caught_sigusr1 = 0;
|
||||
|
||||
static void
|
||||
init_one_signal (int sig, RETSIGTYPE (*handler)(int), int check_ign )
|
||||
{
|
||||
#ifndef HAVE_DOSISH_SYSTEM
|
||||
#ifdef HAVE_SIGACTION
|
||||
struct sigaction oact, nact;
|
||||
|
||||
if (check_ign) {
|
||||
/* we don't want to change an IGN handler */
|
||||
sigaction (sig, NULL, &oact );
|
||||
if (oact.sa_handler == SIG_IGN )
|
||||
return;
|
||||
}
|
||||
|
||||
nact.sa_handler = handler;
|
||||
sigemptyset (&nact.sa_mask);
|
||||
nact.sa_flags = 0;
|
||||
sigaction ( sig, &nact, NULL);
|
||||
#else
|
||||
RETSIGTYPE (*ohandler)(int);
|
||||
|
||||
ohandler = signal (sig, handler);
|
||||
if (check_ign && ohandler == SIG_IGN) {
|
||||
/* Change it back if it was already set to IGN */
|
||||
signal (sig, SIG_IGN);
|
||||
}
|
||||
#endif
|
||||
#endif /*!HAVE_DOSISH_SYSTEM*/
|
||||
}
|
||||
|
||||
static const char *
|
||||
get_signal_name( int signum )
|
||||
{
|
||||
#if defined(SYS_SIGLIST_DECLARED) && defined(NSIG)
|
||||
return (signum >= 0 && signum < NSIG) ? sys_siglist[signum] : "?";
|
||||
#else
|
||||
return "some signal";
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static RETSIGTYPE
|
||||
got_fatal_signal( int sig )
|
||||
{
|
||||
const char *s;
|
||||
|
||||
if( caught_fatal_sig )
|
||||
raise( sig );
|
||||
caught_fatal_sig = 1;
|
||||
|
||||
secmem_term();
|
||||
/* better don't transtale these messages */
|
||||
write(2, "\n", 1 );
|
||||
s = log_get_name(); if( s ) write(2, s, strlen(s) );
|
||||
write(2, ": ", 2 );
|
||||
s = get_signal_name(sig); write(2, s, strlen(s) );
|
||||
write(2, " caught ... exiting\n", 20 );
|
||||
|
||||
/* reset action to default action and raise signal again */
|
||||
init_one_signal (sig, SIG_DFL, 0);
|
||||
remove_lockfiles ();
|
||||
#ifdef __riscos__
|
||||
riscos_close_fds ();
|
||||
#endif /* __riscos__ */
|
||||
raise( sig );
|
||||
}
|
||||
|
||||
|
||||
static RETSIGTYPE
|
||||
got_usr_signal( int sig )
|
||||
{
|
||||
caught_sigusr1 = 1;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
init_signals()
|
||||
{
|
||||
#ifndef HAVE_DOSISH_SYSTEM
|
||||
init_one_signal (SIGINT, got_fatal_signal, 1 );
|
||||
init_one_signal (SIGHUP, got_fatal_signal, 1 );
|
||||
init_one_signal (SIGTERM, got_fatal_signal, 1 );
|
||||
init_one_signal (SIGQUIT, got_fatal_signal, 1 );
|
||||
init_one_signal (SIGSEGV, got_fatal_signal, 1 );
|
||||
init_one_signal (SIGUSR1, got_usr_signal, 0 );
|
||||
init_one_signal (SIGPIPE, SIG_IGN, 0 );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
pause_on_sigusr( int which )
|
||||
{
|
||||
#ifndef HAVE_DOSISH_SYSTEM
|
||||
#ifdef HAVE_SIGPROCMASK
|
||||
sigset_t mask, oldmask;
|
||||
|
||||
assert( which == 1 );
|
||||
sigemptyset( &mask );
|
||||
sigaddset( &mask, SIGUSR1 );
|
||||
|
||||
sigprocmask( SIG_BLOCK, &mask, &oldmask );
|
||||
while( !caught_sigusr1 )
|
||||
sigsuspend( &oldmask );
|
||||
caught_sigusr1 = 0;
|
||||
sigprocmask( SIG_UNBLOCK, &mask, NULL );
|
||||
#else
|
||||
assert (which == 1);
|
||||
sighold (SIGUSR1);
|
||||
while (!caught_sigusr1)
|
||||
sigpause(SIGUSR1);
|
||||
caught_sigusr1 = 0;
|
||||
sigrelse(SIGUSR1); ????
|
||||
#endif /*!HAVE_SIGPROCMASK*/
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
do_block( int block )
|
||||
{
|
||||
#ifndef HAVE_DOSISH_SYSTEM
|
||||
static int is_blocked;
|
||||
#ifdef HAVE_SIGPROCMASK
|
||||
static sigset_t oldmask;
|
||||
|
||||
if( block ) {
|
||||
sigset_t newmask;
|
||||
|
||||
if( is_blocked )
|
||||
log_bug("signals are already blocked\n");
|
||||
sigfillset( &newmask );
|
||||
sigprocmask( SIG_BLOCK, &newmask, &oldmask );
|
||||
is_blocked = 1;
|
||||
}
|
||||
else {
|
||||
if( !is_blocked )
|
||||
log_bug("signals are not blocked\n");
|
||||
sigprocmask( SIG_SETMASK, &oldmask, NULL );
|
||||
is_blocked = 0;
|
||||
}
|
||||
#else /*!HAVE_SIGPROCMASK*/
|
||||
static void (*disposition[MAXSIG])();
|
||||
int sig;
|
||||
|
||||
if( block ) {
|
||||
if( is_blocked )
|
||||
log_bug("signals are already blocked\n");
|
||||
for (sig=1; sig < MAXSIG; sig++) {
|
||||
disposition[sig] = sigset (sig, SIG_HOLD);
|
||||
}
|
||||
is_blocked = 1;
|
||||
}
|
||||
else {
|
||||
if( !is_blocked )
|
||||
log_bug("signals are not blocked\n");
|
||||
for (sig=1; sig < MAXSIG; sig++) {
|
||||
sigset (sig, disposition[sig]);
|
||||
}
|
||||
is_blocked = 0;
|
||||
}
|
||||
#endif /*!HAVE_SIGPROCMASK*/
|
||||
#endif /*HAVE_DOSISH_SYSTEM*/
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
block_all_signals()
|
||||
{
|
||||
do_block(1);
|
||||
}
|
||||
|
||||
void
|
||||
unblock_all_signals()
|
||||
{
|
||||
do_block(0);
|
||||
}
|
693
g10/status.c
Normal file
693
g10/status.c
Normal file
@ -0,0 +1,693 @@
|
||||
/* status.c
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#ifdef USE_SHM_COPROCESSING
|
||||
#ifdef USE_CAPABILITIES
|
||||
#include <sys/capability.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_IPC_H
|
||||
#include <sys/types.h>
|
||||
#include <sys/ipc.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SHM_H
|
||||
#include <sys/shm.h>
|
||||
#endif
|
||||
#if defined(HAVE_MLOCK)
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
#endif
|
||||
#include "util.h"
|
||||
#include "status.h"
|
||||
#include "ttyio.h"
|
||||
#include "options.h"
|
||||
#include "main.h"
|
||||
#include "i18n.h"
|
||||
#include "cipher.h" /* for progress functions */
|
||||
|
||||
#define CONTROL_D ('D' - 'A' + 1)
|
||||
|
||||
|
||||
|
||||
static FILE *statusfp;
|
||||
|
||||
#ifdef USE_SHM_COPROCESSING
|
||||
static int shm_id = -1;
|
||||
static volatile char *shm_area;
|
||||
static size_t shm_size;
|
||||
static int shm_is_locked;
|
||||
#endif /*USE_SHM_COPROCESSING*/
|
||||
|
||||
|
||||
static void
|
||||
progress_cb ( void *ctx, int c )
|
||||
{
|
||||
char buf[50];
|
||||
|
||||
if ( c == '\n' )
|
||||
sprintf ( buf, "%.20s X 100 100", (char*)ctx );
|
||||
else
|
||||
sprintf ( buf, "%.20s %c 0 0", (char*)ctx, c );
|
||||
write_status_text ( STATUS_PROGRESS, buf );
|
||||
}
|
||||
|
||||
static const char *
|
||||
get_status_string ( int no )
|
||||
{
|
||||
const char *s;
|
||||
|
||||
switch( no ) {
|
||||
case STATUS_ENTER : s = "ENTER"; break;
|
||||
case STATUS_LEAVE : s = "LEAVE"; break;
|
||||
case STATUS_ABORT : s = "ABORT"; break;
|
||||
case STATUS_GOODSIG: s = "GOODSIG"; break;
|
||||
case STATUS_KEYEXPIRED: s = "KEYEXPIRED"; break;
|
||||
case STATUS_KEYREVOKED: s = "KEYREVOKED"; break;
|
||||
case STATUS_BADSIG : s = "BADSIG"; break;
|
||||
case STATUS_ERRSIG : s = "ERRSIG"; break;
|
||||
case STATUS_BADARMOR : s = "BADARMOR"; break;
|
||||
case STATUS_RSA_OR_IDEA : s= "RSA_OR_IDEA"; break;
|
||||
case STATUS_TRUST_UNDEFINED: s = "TRUST_UNDEFINED"; break;
|
||||
case STATUS_TRUST_NEVER : s = "TRUST_NEVER"; break;
|
||||
case STATUS_TRUST_MARGINAL : s = "TRUST_MARGINAL"; break;
|
||||
case STATUS_TRUST_FULLY : s = "TRUST_FULLY"; break;
|
||||
case STATUS_TRUST_ULTIMATE : s = "TRUST_ULTIMATE"; break;
|
||||
case STATUS_GET_BOOL : s = "GET_BOOL"; break;
|
||||
case STATUS_GET_LINE : s = "GET_LINE"; break;
|
||||
case STATUS_GET_HIDDEN : s = "GET_HIDDEN"; break;
|
||||
case STATUS_GOT_IT : s = "GOT_IT"; break;
|
||||
case STATUS_SHM_INFO : s = "SHM_INFO"; break;
|
||||
case STATUS_SHM_GET : s = "SHM_GET"; break;
|
||||
case STATUS_SHM_GET_BOOL : s = "SHM_GET_BOOL"; break;
|
||||
case STATUS_SHM_GET_HIDDEN : s = "SHM_GET_HIDDEN"; break;
|
||||
case STATUS_NEED_PASSPHRASE: s = "NEED_PASSPHRASE"; break;
|
||||
case STATUS_VALIDSIG : s = "VALIDSIG"; break;
|
||||
case STATUS_SIG_ID : s = "SIG_ID"; break;
|
||||
case STATUS_ENC_TO : s = "ENC_TO"; break;
|
||||
case STATUS_NODATA : s = "NODATA"; break;
|
||||
case STATUS_BAD_PASSPHRASE : s = "BAD_PASSPHRASE"; break;
|
||||
case STATUS_NO_PUBKEY : s = "NO_PUBKEY"; break;
|
||||
case STATUS_NO_SECKEY : s = "NO_SECKEY"; break;
|
||||
case STATUS_NEED_PASSPHRASE_SYM: s = "NEED_PASSPHRASE_SYM"; break;
|
||||
case STATUS_DECRYPTION_FAILED: s = "DECRYPTION_FAILED"; break;
|
||||
case STATUS_DECRYPTION_OKAY: s = "DECRYPTION_OKAY"; break;
|
||||
case STATUS_MISSING_PASSPHRASE: s = "MISSING_PASSPHRASE"; break;
|
||||
case STATUS_GOOD_PASSPHRASE : s = "GOOD_PASSPHRASE"; break;
|
||||
case STATUS_GOODMDC : s = "GOODMDC"; break;
|
||||
case STATUS_BADMDC : s = "BADMDC"; break;
|
||||
case STATUS_ERRMDC : s = "ERRMDC"; break;
|
||||
case STATUS_IMPORTED : s = "IMPORTED"; break;
|
||||
case STATUS_IMPORT_OK : s = "IMPORT_OK"; break;
|
||||
case STATUS_IMPORT_CHECK : s = "IMPORT_CHECK"; break;
|
||||
case STATUS_IMPORT_RES : s = "IMPORT_RES"; break;
|
||||
case STATUS_FILE_START : s = "FILE_START"; break;
|
||||
case STATUS_FILE_DONE : s = "FILE_DONE"; break;
|
||||
case STATUS_FILE_ERROR : s = "FILE_ERROR"; break;
|
||||
case STATUS_BEGIN_DECRYPTION:s = "BEGIN_DECRYPTION"; break;
|
||||
case STATUS_END_DECRYPTION : s = "END_DECRYPTION"; break;
|
||||
case STATUS_BEGIN_ENCRYPTION:s = "BEGIN_ENCRYPTION"; break;
|
||||
case STATUS_END_ENCRYPTION : s = "END_ENCRYPTION"; break;
|
||||
case STATUS_DELETE_PROBLEM : s = "DELETE_PROBLEM"; break;
|
||||
case STATUS_PROGRESS : s = "PROGRESS"; break;
|
||||
case STATUS_SIG_CREATED : s = "SIG_CREATED"; break;
|
||||
case STATUS_SESSION_KEY : s = "SESSION_KEY"; break;
|
||||
case STATUS_NOTATION_NAME : s = "NOTATION_NAME" ; break;
|
||||
case STATUS_NOTATION_DATA : s = "NOTATION_DATA" ; break;
|
||||
case STATUS_POLICY_URL : s = "POLICY_URL" ; break;
|
||||
case STATUS_BEGIN_STREAM : s = "BEGIN_STREAM"; break;
|
||||
case STATUS_END_STREAM : s = "END_STREAM"; break;
|
||||
case STATUS_KEY_CREATED : s = "KEY_CREATED"; break;
|
||||
case STATUS_USERID_HINT : s = "USERID_HINT"; break;
|
||||
case STATUS_UNEXPECTED : s = "UNEXPECTED"; break;
|
||||
case STATUS_INV_RECP : s = "INV_RECP"; break;
|
||||
case STATUS_NO_RECP : s = "NO_RECP"; break;
|
||||
case STATUS_ALREADY_SIGNED : s = "ALREADY_SIGNED"; break;
|
||||
case STATUS_SIGEXPIRED : s = "SIGEXPIRED deprecated-use-keyexpired-instead"; break;
|
||||
case STATUS_EXPSIG : s = "EXPSIG"; break;
|
||||
case STATUS_EXPKEYSIG : s = "EXPKEYSIG"; break;
|
||||
case STATUS_ATTRIBUTE : s = "ATTRIBUTE"; break;
|
||||
default: s = "?"; break;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
void
|
||||
set_status_fd ( int fd )
|
||||
{
|
||||
static int last_fd = -1;
|
||||
|
||||
if ( fd != -1 && last_fd == fd )
|
||||
return;
|
||||
|
||||
if ( statusfp && statusfp != stdout && statusfp != stderr )
|
||||
fclose (statusfp);
|
||||
statusfp = NULL;
|
||||
if ( fd == -1 )
|
||||
return;
|
||||
|
||||
if( fd == 1 )
|
||||
statusfp = stdout;
|
||||
else if( fd == 2 )
|
||||
statusfp = stderr;
|
||||
else
|
||||
statusfp = fdopen( fd, "w" );
|
||||
if( !statusfp ) {
|
||||
log_fatal("can't open fd %d for status output: %s\n",
|
||||
fd, strerror(errno));
|
||||
}
|
||||
last_fd = fd;
|
||||
register_primegen_progress ( progress_cb, "primegen" );
|
||||
register_pk_dsa_progress ( progress_cb, "pk_dsa" );
|
||||
register_pk_elg_progress ( progress_cb, "pk_elg" );
|
||||
}
|
||||
|
||||
int
|
||||
is_status_enabled()
|
||||
{
|
||||
return !!statusfp;
|
||||
}
|
||||
|
||||
void
|
||||
write_status ( int no )
|
||||
{
|
||||
write_status_text( no, NULL );
|
||||
}
|
||||
|
||||
void
|
||||
write_status_text ( int no, const char *text)
|
||||
{
|
||||
if( !statusfp )
|
||||
return; /* not enabled */
|
||||
|
||||
fputs ( "[GNUPG:] ", statusfp );
|
||||
fputs ( get_status_string (no), statusfp );
|
||||
if( text ) {
|
||||
putc ( ' ', statusfp );
|
||||
for (; *text; text++) {
|
||||
if (*text == '\n')
|
||||
fputs ( "\\n", statusfp );
|
||||
else if (*text == '\r')
|
||||
fputs ( "\\r", statusfp );
|
||||
else
|
||||
putc ( *(const byte *)text, statusfp );
|
||||
}
|
||||
}
|
||||
putc ('\n',statusfp);
|
||||
fflush (statusfp);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Write a status line with a buffer using %XX escapes. If WRAP is >
|
||||
* 0 wrap the line after this length. If STRING is not NULL it will
|
||||
* be prepended to the buffer, no escaping is done for string.
|
||||
* A wrap of -1 forces spaces not to be encoded as %20.
|
||||
*/
|
||||
void
|
||||
write_status_text_and_buffer ( int no, const char *string,
|
||||
const char *buffer, size_t len, int wrap )
|
||||
{
|
||||
const char *s, *text;
|
||||
int esc, first;
|
||||
int lower_limit = ' ';
|
||||
size_t n, count, dowrap;
|
||||
|
||||
if( !statusfp )
|
||||
return; /* not enabled */
|
||||
|
||||
if (wrap == -1) {
|
||||
lower_limit--;
|
||||
wrap = 0;
|
||||
}
|
||||
|
||||
text = get_status_string (no);
|
||||
count = dowrap = first = 1;
|
||||
do {
|
||||
if (dowrap) {
|
||||
fprintf (statusfp, "[GNUPG:] %s ", text );
|
||||
count = dowrap = 0;
|
||||
if (first && string) {
|
||||
fputs (string, statusfp);
|
||||
count += strlen (string);
|
||||
}
|
||||
first = 0;
|
||||
}
|
||||
for (esc=0, s=buffer, n=len; n && !esc; s++, n-- ) {
|
||||
if ( *s == '%' || *(const byte*)s <= lower_limit
|
||||
|| *(const byte*)s == 127 )
|
||||
esc = 1;
|
||||
if ( wrap && ++count > wrap ) {
|
||||
dowrap=1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (esc) {
|
||||
s--; n++;
|
||||
}
|
||||
if (s != buffer)
|
||||
fwrite (buffer, s-buffer, 1, statusfp );
|
||||
if ( esc ) {
|
||||
fprintf (statusfp, "%%%02X", *(const byte*)s );
|
||||
s++; n--;
|
||||
}
|
||||
buffer = s;
|
||||
len = n;
|
||||
if ( dowrap && len )
|
||||
putc ( '\n', statusfp );
|
||||
} while ( len );
|
||||
|
||||
putc ('\n',statusfp);
|
||||
fflush (statusfp);
|
||||
}
|
||||
|
||||
void
|
||||
write_status_buffer ( int no, const char *buffer, size_t len, int wrap )
|
||||
{
|
||||
write_status_text_and_buffer (no, NULL, buffer, len, wrap);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef USE_SHM_COPROCESSING
|
||||
|
||||
#ifndef IPC_RMID_DEFERRED_RELEASE
|
||||
static void
|
||||
remove_shmid( void )
|
||||
{
|
||||
if( shm_id != -1 ) {
|
||||
shmctl ( shm_id, IPC_RMID, 0);
|
||||
shm_id = -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
init_shm_coprocessing ( ulong requested_shm_size, int lock_mem )
|
||||
{
|
||||
char buf[100];
|
||||
struct shmid_ds shmds;
|
||||
|
||||
#ifndef IPC_RMID_DEFERRED_RELEASE
|
||||
atexit( remove_shmid );
|
||||
#endif
|
||||
requested_shm_size = (requested_shm_size + 4095) & ~4095;
|
||||
if ( requested_shm_size > 2 * 4096 )
|
||||
log_fatal("too much shared memory requested; only 8k are allowed\n");
|
||||
shm_size = 4096 /* one page for us */ + requested_shm_size;
|
||||
|
||||
shm_id = shmget( IPC_PRIVATE, shm_size, IPC_CREAT | 0700 );
|
||||
if ( shm_id == -1 )
|
||||
log_fatal("can't get %uk of shared memory: %s\n",
|
||||
(unsigned)shm_size/1024, strerror(errno));
|
||||
|
||||
#if !defined(IPC_HAVE_SHM_LOCK) \
|
||||
&& defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
|
||||
/* part of the old code which uses mlock */
|
||||
shm_area = shmat( shm_id, 0, 0 );
|
||||
if ( shm_area == (char*)-1 )
|
||||
log_fatal("can't attach %uk shared memory: %s\n",
|
||||
(unsigned)shm_size/1024, strerror(errno));
|
||||
log_debug("mapped %uk shared memory at %p, id=%d\n",
|
||||
(unsigned)shm_size/1024, shm_area, shm_id );
|
||||
if( lock_mem ) {
|
||||
#ifdef USE_CAPABILITIES
|
||||
cap_set_proc( cap_from_text("cap_ipc_lock+ep") );
|
||||
#endif
|
||||
/* (need the cast for Solaris with Sun's workshop compilers) */
|
||||
if ( mlock ( (char*)shm_area, shm_size) )
|
||||
log_info("locking shared memory %d failed: %s\n",
|
||||
shm_id, strerror(errno));
|
||||
else
|
||||
shm_is_locked = 1;
|
||||
#ifdef USE_CAPABILITIES
|
||||
cap_set_proc( cap_from_text("cap_ipc_lock+p") );
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef IPC_RMID_DEFERRED_RELEASE
|
||||
if( shmctl( shm_id, IPC_RMID, 0) )
|
||||
log_fatal("shmctl IPC_RMDID of %d failed: %s\n",
|
||||
shm_id, strerror(errno));
|
||||
#endif
|
||||
|
||||
if( shmctl( shm_id, IPC_STAT, &shmds ) )
|
||||
log_fatal("shmctl IPC_STAT of %d failed: %s\n",
|
||||
shm_id, strerror(errno));
|
||||
if( shmds.shm_perm.uid != getuid() ) {
|
||||
shmds.shm_perm.uid = getuid();
|
||||
if( shmctl( shm_id, IPC_SET, &shmds ) )
|
||||
log_fatal("shmctl IPC_SET of %d failed: %s\n",
|
||||
shm_id, strerror(errno));
|
||||
}
|
||||
|
||||
#else /* this is the new code which handles the changes in the SHM
|
||||
* semantics introduced with Linux 2.4. The changes is that we
|
||||
* now change the permissions and then attach to the memory.
|
||||
*/
|
||||
|
||||
if( lock_mem ) {
|
||||
#ifdef USE_CAPABILITIES
|
||||
cap_set_proc( cap_from_text("cap_ipc_lock+ep") );
|
||||
#endif
|
||||
#ifdef IPC_HAVE_SHM_LOCK
|
||||
if ( shmctl (shm_id, SHM_LOCK, 0) )
|
||||
log_info("locking shared memory %d failed: %s\n",
|
||||
shm_id, strerror(errno));
|
||||
else
|
||||
shm_is_locked = 1;
|
||||
#else
|
||||
log_info("Locking shared memory %d failed: No way to do it\n", shm_id );
|
||||
#endif
|
||||
#ifdef USE_CAPABILITIES
|
||||
cap_set_proc( cap_from_text("cap_ipc_lock+p") );
|
||||
#endif
|
||||
}
|
||||
|
||||
if( shmctl( shm_id, IPC_STAT, &shmds ) )
|
||||
log_fatal("shmctl IPC_STAT of %d failed: %s\n",
|
||||
shm_id, strerror(errno));
|
||||
if( shmds.shm_perm.uid != getuid() ) {
|
||||
shmds.shm_perm.uid = getuid();
|
||||
if( shmctl( shm_id, IPC_SET, &shmds ) )
|
||||
log_fatal("shmctl IPC_SET of %d failed: %s\n",
|
||||
shm_id, strerror(errno));
|
||||
}
|
||||
|
||||
shm_area = shmat( shm_id, 0, 0 );
|
||||
if ( shm_area == (char*)-1 )
|
||||
log_fatal("can't attach %uk shared memory: %s\n",
|
||||
(unsigned)shm_size/1024, strerror(errno));
|
||||
log_debug("mapped %uk shared memory at %p, id=%d\n",
|
||||
(unsigned)shm_size/1024, shm_area, shm_id );
|
||||
|
||||
#ifdef IPC_RMID_DEFERRED_RELEASE
|
||||
if( shmctl( shm_id, IPC_RMID, 0) )
|
||||
log_fatal("shmctl IPC_RMDID of %d failed: %s\n",
|
||||
shm_id, strerror(errno));
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/* write info; Protocol version, id, size, locked size */
|
||||
sprintf( buf, "pv=1 pid=%d shmid=%d sz=%u lz=%u", (int)getpid(),
|
||||
shm_id, (unsigned)shm_size, shm_is_locked? (unsigned)shm_size:0 );
|
||||
write_status_text( STATUS_SHM_INFO, buf );
|
||||
}
|
||||
|
||||
/****************
|
||||
* Request a string from client
|
||||
* If bool, returns static string on true (do not free) or NULL for false
|
||||
*/
|
||||
static char *
|
||||
do_shm_get( const char *keyword, int hidden, int bool )
|
||||
{
|
||||
size_t n;
|
||||
byte *p;
|
||||
char *string;
|
||||
|
||||
if( !shm_area )
|
||||
BUG();
|
||||
|
||||
shm_area[0] = 0; /* msb of length of control block */
|
||||
shm_area[1] = 32; /* and lsb */
|
||||
shm_area[2] = 1; /* indicate that we are waiting on a reply */
|
||||
shm_area[3] = 0; /* clear data available flag */
|
||||
|
||||
write_status_text( bool? STATUS_SHM_GET_BOOL :
|
||||
hidden? STATUS_SHM_GET_HIDDEN : STATUS_SHM_GET, keyword );
|
||||
|
||||
do {
|
||||
pause_on_sigusr(1);
|
||||
if( shm_area[0] || shm_area[1] != 32 || shm_area[2] != 1 )
|
||||
log_fatal("client modified shm control block - abort\n");
|
||||
} while( !shm_area[3] );
|
||||
shm_area[2] = 0; /* reset request flag */
|
||||
p = (byte*)shm_area+32;
|
||||
n = p[0] << 8 | p[1];
|
||||
p += 2;
|
||||
if( n+32+2+1 > 4095 )
|
||||
log_fatal("client returns too large data (%u bytes)\n", (unsigned)n );
|
||||
|
||||
if( bool )
|
||||
return p[0]? "" : NULL;
|
||||
|
||||
string = hidden? m_alloc_secure( n+1 ) : m_alloc( n+1 );
|
||||
memcpy(string, p, n );
|
||||
string[n] = 0; /* make sure it is a string */
|
||||
if( hidden ) /* invalidate the memory */
|
||||
memset( p, 0, n );
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
#endif /* USE_SHM_COPROCESSING */
|
||||
|
||||
static int
|
||||
myread(int fd, void *buf, size_t count)
|
||||
{
|
||||
int rc;
|
||||
do {
|
||||
rc = read( fd, buf, count );
|
||||
} while ( rc == -1 && errno == EINTR );
|
||||
if ( !rc && count ) {
|
||||
static int eof_emmited=0;
|
||||
if ( eof_emmited < 3 ) {
|
||||
*(char*)buf = CONTROL_D;
|
||||
rc = 1;
|
||||
eof_emmited++;
|
||||
}
|
||||
else { /* Ctrl-D not caught - do something reasonable */
|
||||
#ifdef HAVE_DOSISH_SYSTEM
|
||||
raise (SIGINT); /* nothing to hangup under DOS */
|
||||
#else
|
||||
raise (SIGHUP); /* no more input data */
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/****************
|
||||
* Request a string from the client over the command-fd
|
||||
* If bool, returns static string on true (do not free) or NULL for false
|
||||
*/
|
||||
static char *
|
||||
do_get_from_fd( const char *keyword, int hidden, int bool )
|
||||
{
|
||||
int i, len;
|
||||
char *string;
|
||||
|
||||
write_status_text( bool? STATUS_GET_BOOL :
|
||||
hidden? STATUS_GET_HIDDEN : STATUS_GET_LINE, keyword );
|
||||
|
||||
for( string = NULL, i = len = 200; ; i++ ) {
|
||||
if( i >= len-1 ) {
|
||||
char *save = string;
|
||||
len += 100;
|
||||
string = hidden? m_alloc_secure ( len ) : m_alloc ( len );
|
||||
if( save )
|
||||
memcpy(string, save, i );
|
||||
else
|
||||
i=0;
|
||||
}
|
||||
/* Hmmm: why not use our read_line function here */
|
||||
if( myread( opt.command_fd, string+i, 1) != 1 || string[i] == '\n' )
|
||||
break;
|
||||
else if ( string[i] == CONTROL_D ) {
|
||||
/* found ETX - cancel the line and return a sole ETX */
|
||||
string[0] = CONTROL_D;
|
||||
i=1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
string[i] = 0;
|
||||
|
||||
write_status( STATUS_GOT_IT );
|
||||
|
||||
if( bool ) /* Fixme: is this correct??? */
|
||||
return (string[0] == 'Y' || string[0] == 'y') ? "" : NULL;
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
cpr_enabled()
|
||||
{
|
||||
if( opt.command_fd != -1 )
|
||||
return 1;
|
||||
#ifdef USE_SHM_COPROCESSING
|
||||
if( opt.shm_coprocess )
|
||||
return 1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *
|
||||
cpr_get_no_help( const char *keyword, const char *prompt )
|
||||
{
|
||||
char *p;
|
||||
|
||||
if( opt.command_fd != -1 )
|
||||
return do_get_from_fd ( keyword, 0, 0 );
|
||||
#ifdef USE_SHM_COPROCESSING
|
||||
if( opt.shm_coprocess )
|
||||
return do_shm_get( keyword, 0, 0 );
|
||||
#endif
|
||||
for(;;) {
|
||||
p = tty_get( prompt );
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
cpr_get( const char *keyword, const char *prompt )
|
||||
{
|
||||
char *p;
|
||||
|
||||
if( opt.command_fd != -1 )
|
||||
return do_get_from_fd ( keyword, 0, 0 );
|
||||
#ifdef USE_SHM_COPROCESSING
|
||||
if( opt.shm_coprocess )
|
||||
return do_shm_get( keyword, 0, 0 );
|
||||
#endif
|
||||
for(;;) {
|
||||
p = tty_get( prompt );
|
||||
if( *p=='?' && !p[1] && !(keyword && !*keyword)) {
|
||||
m_free(p);
|
||||
display_online_help( keyword );
|
||||
}
|
||||
else
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
cpr_get_utf8( const char *keyword, const char *prompt )
|
||||
{
|
||||
char *p;
|
||||
p = cpr_get( keyword, prompt );
|
||||
if( p ) {
|
||||
char *utf8 = native_to_utf8( p );
|
||||
m_free( p );
|
||||
p = utf8;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
char *
|
||||
cpr_get_hidden( const char *keyword, const char *prompt )
|
||||
{
|
||||
char *p;
|
||||
|
||||
if( opt.command_fd != -1 )
|
||||
return do_get_from_fd ( keyword, 1, 0 );
|
||||
#ifdef USE_SHM_COPROCESSING
|
||||
if( opt.shm_coprocess )
|
||||
return do_shm_get( keyword, 1, 0 );
|
||||
#endif
|
||||
for(;;) {
|
||||
p = tty_get_hidden( prompt );
|
||||
if( *p == '?' && !p[1] ) {
|
||||
m_free(p);
|
||||
display_online_help( keyword );
|
||||
}
|
||||
else
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cpr_kill_prompt(void)
|
||||
{
|
||||
if( opt.command_fd != -1 )
|
||||
return;
|
||||
#ifdef USE_SHM_COPROCESSING
|
||||
if( opt.shm_coprocess )
|
||||
return;
|
||||
#endif
|
||||
tty_kill_prompt();
|
||||
return;
|
||||
}
|
||||
|
||||
int
|
||||
cpr_get_answer_is_yes( const char *keyword, const char *prompt )
|
||||
{
|
||||
int yes;
|
||||
char *p;
|
||||
|
||||
if( opt.command_fd != -1 )
|
||||
return !!do_get_from_fd ( keyword, 0, 1 );
|
||||
#ifdef USE_SHM_COPROCESSING
|
||||
if( opt.shm_coprocess )
|
||||
return !!do_shm_get( keyword, 0, 1 );
|
||||
#endif
|
||||
for(;;) {
|
||||
p = tty_get( prompt );
|
||||
trim_spaces(p); /* it is okay to do this here */
|
||||
if( *p == '?' && !p[1] ) {
|
||||
m_free(p);
|
||||
display_online_help( keyword );
|
||||
}
|
||||
else {
|
||||
tty_kill_prompt();
|
||||
yes = answer_is_yes(p);
|
||||
m_free(p);
|
||||
return yes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
cpr_get_answer_yes_no_quit( const char *keyword, const char *prompt )
|
||||
{
|
||||
int yes;
|
||||
char *p;
|
||||
|
||||
if( opt.command_fd != -1 )
|
||||
return !!do_get_from_fd ( keyword, 0, 1 );
|
||||
#ifdef USE_SHM_COPROCESSING
|
||||
if( opt.shm_coprocess )
|
||||
return !!do_shm_get( keyword, 0, 1 );
|
||||
#endif
|
||||
for(;;) {
|
||||
p = tty_get( prompt );
|
||||
trim_spaces(p); /* it is okay to do this here */
|
||||
if( *p == '?' && !p[1] ) {
|
||||
m_free(p);
|
||||
display_online_help( keyword );
|
||||
}
|
||||
else {
|
||||
tty_kill_prompt();
|
||||
yes = answer_is_yes_no_quit(p);
|
||||
m_free(p);
|
||||
return yes;
|
||||
}
|
||||
}
|
||||
}
|
1624
g10/tdbio.c
Normal file
1624
g10/tdbio.c
Normal file
File diff suppressed because it is too large
Load Diff
117
g10/tdbio.h
Normal file
117
g10/tdbio.h
Normal file
@ -0,0 +1,117 @@
|
||||
/* tdbio.h - Trust database I/O functions
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef G10_TDBIO_H
|
||||
#define G10_TDBIO_H
|
||||
|
||||
#include "host2net.h"
|
||||
|
||||
#define TRUST_RECORD_LEN 40
|
||||
#define SIGS_PER_RECORD ((TRUST_RECORD_LEN-10)/5)
|
||||
#define ITEMS_PER_HTBL_RECORD ((TRUST_RECORD_LEN-2)/4)
|
||||
#define ITEMS_PER_HLST_RECORD ((TRUST_RECORD_LEN-6)/5)
|
||||
#define ITEMS_PER_PREF_RECORD (TRUST_RECORD_LEN-10)
|
||||
#if ITEMS_PER_PREF_RECORD % 2
|
||||
#error ITEMS_PER_PREF_RECORD must be even
|
||||
#endif
|
||||
#define MAX_LIST_SIGS_DEPTH 20
|
||||
|
||||
|
||||
#define RECTYPE_VER 1
|
||||
#define RECTYPE_HTBL 10
|
||||
#define RECTYPE_HLST 11
|
||||
#define RECTYPE_TRUST 12
|
||||
#define RECTYPE_VALID 13
|
||||
#define RECTYPE_FREE 254
|
||||
|
||||
|
||||
struct trust_record {
|
||||
int rectype;
|
||||
int mark;
|
||||
int dirty; /* for now only used internal by functions */
|
||||
struct trust_record *next; /* help pointer to build lists in memory */
|
||||
ulong recnum;
|
||||
union {
|
||||
struct { /* version record: */
|
||||
byte version; /* should be 3 */
|
||||
byte marginals;
|
||||
byte completes;
|
||||
byte cert_depth;
|
||||
byte trust_model;
|
||||
ulong created; /* timestamp of trustdb creation */
|
||||
ulong nextcheck; /* timestamp of next scheduled check */
|
||||
ulong reserved;
|
||||
ulong reserved2;
|
||||
ulong firstfree;
|
||||
ulong reserved3;
|
||||
ulong trusthashtbl;
|
||||
} ver;
|
||||
struct { /* free record */
|
||||
ulong next;
|
||||
} free;
|
||||
struct {
|
||||
ulong item[ITEMS_PER_HTBL_RECORD];
|
||||
} htbl;
|
||||
struct {
|
||||
ulong next;
|
||||
ulong rnum[ITEMS_PER_HLST_RECORD]; /* of another record */
|
||||
} hlst;
|
||||
struct {
|
||||
byte fingerprint[20];
|
||||
byte ownertrust;
|
||||
byte depth;
|
||||
ulong validlist;
|
||||
byte min_ownertrust;
|
||||
} trust;
|
||||
struct {
|
||||
byte namehash[20];
|
||||
ulong next;
|
||||
byte validity;
|
||||
byte full_count;
|
||||
byte marginal_count;
|
||||
} valid;
|
||||
} r;
|
||||
};
|
||||
typedef struct trust_record TRUSTREC;
|
||||
|
||||
/*-- tdbio.c --*/
|
||||
int tdbio_update_version_record(void);
|
||||
int tdbio_set_dbname( const char *new_dbname, int create );
|
||||
const char *tdbio_get_dbname(void);
|
||||
void tdbio_dump_record( TRUSTREC *rec, FILE *fp );
|
||||
int tdbio_read_record( ulong recnum, TRUSTREC *rec, int expected );
|
||||
int tdbio_write_record( TRUSTREC *rec );
|
||||
int tdbio_db_matches_options(void);
|
||||
byte tdbio_read_model(void);
|
||||
ulong tdbio_read_nextcheck (void);
|
||||
int tdbio_write_nextcheck (ulong stamp);
|
||||
int tdbio_is_dirty(void);
|
||||
int tdbio_sync(void);
|
||||
int tdbio_begin_transaction(void);
|
||||
int tdbio_end_transaction(void);
|
||||
int tdbio_cancel_transaction(void);
|
||||
int tdbio_delete_record( ulong recnum );
|
||||
ulong tdbio_new_recnum(void);
|
||||
int tdbio_search_trust_byfpr(const byte *fingerprint, TRUSTREC *rec );
|
||||
int tdbio_search_trust_bypk(PKT_public_key *pk, TRUSTREC *rec );
|
||||
|
||||
void tdbio_invalid(void);
|
||||
|
||||
#endif /*G10_TDBIO_H*/
|
234
g10/textfilter.c
Normal file
234
g10/textfilter.c
Normal file
@ -0,0 +1,234 @@
|
||||
/* textfilter.c
|
||||
* Copyright (C) 1998, 1999, 2000, 2001 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "errors.h"
|
||||
#include "iobuf.h"
|
||||
#include "memory.h"
|
||||
#include "util.h"
|
||||
#include "filter.h"
|
||||
#include "i18n.h"
|
||||
#include "options.h"
|
||||
|
||||
#ifdef HAVE_DOSISH_SYSTEM
|
||||
#define LF "\r\n"
|
||||
#else
|
||||
#define LF "\n"
|
||||
#endif
|
||||
|
||||
#define MAX_LINELEN 19995 /* a little bit smaller than in armor.c */
|
||||
/* to make sure that a warning is displayed while */
|
||||
/* creating a message */
|
||||
|
||||
static unsigned
|
||||
len_without_trailing_chars( byte *line, unsigned len, const char *trimchars )
|
||||
{
|
||||
byte *p, *mark;
|
||||
unsigned n;
|
||||
|
||||
for(mark=NULL, p=line, n=0; n < len; n++, p++ ) {
|
||||
if( strchr( trimchars, *p ) ) {
|
||||
if( !mark )
|
||||
mark = p;
|
||||
}
|
||||
else
|
||||
mark = NULL;
|
||||
}
|
||||
|
||||
return mark? (mark - line) : len;
|
||||
}
|
||||
|
||||
unsigned
|
||||
len_without_trailing_ws( byte *line, unsigned len )
|
||||
{
|
||||
return len_without_trailing_chars( line, len, " \t\r\n" );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static int
|
||||
standard( text_filter_context_t *tfx, IOBUF a,
|
||||
byte *buf, size_t size, size_t *ret_len)
|
||||
{
|
||||
int rc=0;
|
||||
size_t len = 0;
|
||||
unsigned maxlen;
|
||||
|
||||
assert( size > 10 );
|
||||
size -= 2; /* reserve 2 bytes to append CR,LF */
|
||||
while( !rc && len < size ) {
|
||||
int lf_seen;
|
||||
|
||||
while( len < size && tfx->buffer_pos < tfx->buffer_len )
|
||||
buf[len++] = tfx->buffer[tfx->buffer_pos++];
|
||||
if( len >= size )
|
||||
continue;
|
||||
|
||||
/* read the next line */
|
||||
maxlen = MAX_LINELEN;
|
||||
tfx->buffer_pos = 0;
|
||||
tfx->buffer_len = iobuf_read_line( a, &tfx->buffer,
|
||||
&tfx->buffer_size, &maxlen );
|
||||
if( !maxlen )
|
||||
tfx->truncated++;
|
||||
if( !tfx->buffer_len ) {
|
||||
if( !len )
|
||||
rc = -1; /* eof */
|
||||
break;
|
||||
}
|
||||
lf_seen = tfx->buffer[tfx->buffer_len-1] == '\n';
|
||||
tfx->buffer_len = trim_trailing_ws( tfx->buffer, tfx->buffer_len );
|
||||
if( lf_seen ) {
|
||||
tfx->buffer[tfx->buffer_len++] = '\r';
|
||||
tfx->buffer[tfx->buffer_len++] = '\n';
|
||||
}
|
||||
}
|
||||
*ret_len = len;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/****************
|
||||
* The filter is used to make canonical text: Lines are terminated by
|
||||
* CR, LF, trailing white spaces are removed.
|
||||
*/
|
||||
int
|
||||
text_filter( void *opaque, int control,
|
||||
IOBUF a, byte *buf, size_t *ret_len)
|
||||
{
|
||||
size_t size = *ret_len;
|
||||
text_filter_context_t *tfx = opaque;
|
||||
int rc=0;
|
||||
|
||||
if( control == IOBUFCTRL_UNDERFLOW ) {
|
||||
rc = standard( tfx, a, buf, size, ret_len );
|
||||
}
|
||||
else if( control == IOBUFCTRL_FREE ) {
|
||||
if( tfx->truncated )
|
||||
log_error(_("can't handle text lines longer than %d characters\n"),
|
||||
MAX_LINELEN );
|
||||
m_free( tfx->buffer );
|
||||
tfx->buffer = NULL;
|
||||
}
|
||||
else if( control == IOBUFCTRL_DESC )
|
||||
*(char**)buf = "text_filter";
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
* Copy data from INP to OUT and do some escaping if requested.
|
||||
* md is updated as required by rfc2440
|
||||
*/
|
||||
int
|
||||
copy_clearsig_text( IOBUF out, IOBUF inp, MD_HANDLE md,
|
||||
int escape_dash, int escape_from, int pgp2mode )
|
||||
{
|
||||
unsigned maxlen;
|
||||
byte *buffer = NULL; /* malloced buffer */
|
||||
unsigned bufsize; /* and size of this buffer */
|
||||
unsigned n;
|
||||
int truncated = 0;
|
||||
int pending_lf = 0;
|
||||
|
||||
if( !opt.pgp2_workarounds )
|
||||
pgp2mode = 0;
|
||||
|
||||
if( !escape_dash )
|
||||
escape_from = 0;
|
||||
|
||||
for(;;) {
|
||||
maxlen = MAX_LINELEN;
|
||||
n = iobuf_read_line( inp, &buffer, &bufsize, &maxlen );
|
||||
if( !maxlen )
|
||||
truncated++;
|
||||
|
||||
if( !n )
|
||||
break; /* read_line has returned eof */
|
||||
|
||||
/* update the message digest */
|
||||
if( escape_dash ) {
|
||||
if( pending_lf ) {
|
||||
md_putc( md, '\r' );
|
||||
md_putc( md, '\n' );
|
||||
}
|
||||
md_write( md, buffer,
|
||||
len_without_trailing_chars( buffer, n,
|
||||
pgp2mode? " \r\n":" \t\r\n"));
|
||||
}
|
||||
else
|
||||
md_write( md, buffer, n );
|
||||
pending_lf = buffer[n-1] == '\n';
|
||||
|
||||
/* write the output */
|
||||
if( ( escape_dash && *buffer == '-')
|
||||
|| ( escape_from && n > 4 && !memcmp(buffer, "From ", 5 ) ) ) {
|
||||
iobuf_put( out, '-' );
|
||||
iobuf_put( out, ' ' );
|
||||
}
|
||||
|
||||
#if 0 /*defined(HAVE_DOSISH_SYSTEM)*/
|
||||
/* We don't use this anymore because my interpretation of rfc2440 7.1
|
||||
* is that there is no conversion needed. If one decides to
|
||||
* clearsign a unix file on a DOS box he will get a mixed line endings.
|
||||
* If at some point it turns out, that a conversion is a nice feature
|
||||
* we can make an option out of it.
|
||||
*/
|
||||
/* make sure the lines do end in CR,LF */
|
||||
if( n > 1 && ( (buffer[n-2] == '\r' && buffer[n-1] == '\n' )
|
||||
|| (buffer[n-2] == '\n' && buffer[n-1] == '\r'))) {
|
||||
iobuf_write( out, buffer, n-2 );
|
||||
iobuf_put( out, '\r');
|
||||
iobuf_put( out, '\n');
|
||||
}
|
||||
else if( n && buffer[n-1] == '\n' ) {
|
||||
iobuf_write( out, buffer, n-1 );
|
||||
iobuf_put( out, '\r');
|
||||
iobuf_put( out, '\n');
|
||||
}
|
||||
else
|
||||
iobuf_write( out, buffer, n );
|
||||
|
||||
#else
|
||||
iobuf_write( out, buffer, n );
|
||||
#endif
|
||||
}
|
||||
|
||||
/* at eof */
|
||||
if( !pending_lf ) { /* make sure that the file ends with a LF */
|
||||
iobuf_writestr( out, LF );
|
||||
if( !escape_dash )
|
||||
md_putc( md, '\n' );
|
||||
}
|
||||
|
||||
if( truncated )
|
||||
log_info(_("input line longer than %d characters\n"), MAX_LINELEN );
|
||||
|
||||
return 0; /* okay */
|
||||
}
|
2129
g10/trustdb.c
Normal file
2129
g10/trustdb.c
Normal file
File diff suppressed because it is too large
Load Diff
83
g10/trustdb.h
Normal file
83
g10/trustdb.h
Normal file
@ -0,0 +1,83 @@
|
||||
/* trustdb.h - Trust database
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef G10_TRUSTDB_H
|
||||
#define G10_TRUSTDB_H
|
||||
|
||||
|
||||
/* Trust values must be sorted in ascending order */
|
||||
#define TRUST_MASK 15
|
||||
#define TRUST_UNKNOWN 0 /* o: not yet calculated/assigned */
|
||||
#define TRUST_EXPIRED 1 /* e: calculation may be invalid */
|
||||
#define TRUST_UNDEFINED 2 /* q: not enough information for calculation */
|
||||
#define TRUST_NEVER 3 /* n: never trust this pubkey */
|
||||
#define TRUST_MARGINAL 4 /* m: marginally trusted */
|
||||
#define TRUST_FULLY 5 /* f: fully trusted */
|
||||
#define TRUST_ULTIMATE 6 /* u: ultimately trusted */
|
||||
/* trust values not covered by the mask */
|
||||
#define TRUST_FLAG_REVOKED 32 /* r: revoked */
|
||||
#define TRUST_FLAG_SUB_REVOKED 64 /* r: revoked but for subkeys */
|
||||
#define TRUST_FLAG_DISABLED 128 /* d: key/uid disabled */
|
||||
#define TRUST_FLAG_PENDING_CHECK 256 /* a check-trustdb is pending */
|
||||
|
||||
/*-- trustdb.c --*/
|
||||
void register_trusted_key( const char *string );
|
||||
void check_trustdb (void);
|
||||
void update_trustdb (void);
|
||||
int setup_trustdb( int level, const char *dbname );
|
||||
void init_trustdb( void );
|
||||
void sync_trustdb( void );
|
||||
|
||||
const char *trust_value_to_string (unsigned int value);
|
||||
int string_to_trust_value (const char *str);
|
||||
|
||||
void revalidation_mark (void);
|
||||
int trustdb_pending_check(void);
|
||||
|
||||
int cache_disabled_value(PKT_public_key *pk);
|
||||
|
||||
unsigned int get_validity (PKT_public_key *pk, PKT_user_id *uid);
|
||||
int get_validity_info (PKT_public_key *pk, PKT_user_id *uid);
|
||||
const char *get_validity_string (PKT_public_key *pk, PKT_user_id *uid);
|
||||
|
||||
void list_trust_path( const char *username );
|
||||
int enum_cert_paths( void **context, ulong *lid,
|
||||
unsigned *ownertrust, unsigned *validity );
|
||||
void enum_cert_paths_print( void **context, FILE *fp,
|
||||
int refresh, ulong selected_lid );
|
||||
|
||||
unsigned int get_ownertrust (PKT_public_key *pk);
|
||||
unsigned int get_min_ownertrust (PKT_public_key *pk);
|
||||
int get_ownertrust_info (PKT_public_key *pk);
|
||||
const char *get_ownertrust_string (PKT_public_key *pk);
|
||||
|
||||
void update_ownertrust (PKT_public_key *pk, unsigned int new_trust );
|
||||
int clear_ownertrusts (PKT_public_key *pk);
|
||||
|
||||
/*-- tdbdump.c --*/
|
||||
void list_trustdb(const char *username);
|
||||
void export_ownertrust(void);
|
||||
void import_ownertrust(const char *fname);
|
||||
|
||||
/*-- pkclist.c --*/
|
||||
int edit_ownertrust (PKT_public_key *pk, int mode );
|
||||
|
||||
#endif /*G10_TRUSTDB_H*/
|
193
g10/verify.c
Normal file
193
g10/verify.c
Normal file
@ -0,0 +1,193 @@
|
||||
/* verify.c - verify signed data
|
||||
* Copyright (C) 1998, 1999, 2000, 2001 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h> /* for isatty() */
|
||||
|
||||
#include "options.h"
|
||||
#include "packet.h"
|
||||
#include "errors.h"
|
||||
#include "iobuf.h"
|
||||
#include "keydb.h"
|
||||
#include "memory.h"
|
||||
#include "util.h"
|
||||
#include "main.h"
|
||||
#include "status.h"
|
||||
#include "filter.h"
|
||||
#include "ttyio.h"
|
||||
#include "i18n.h"
|
||||
|
||||
|
||||
|
||||
/****************
|
||||
* Assume that the input is a signature and verify it without
|
||||
* generating any output. With no arguments, the signature packet
|
||||
* is read from stdin (it may be a detached signature when not
|
||||
* used in batch mode). If only a sigfile is given, it may be a complete
|
||||
* signature or a detached signature in which case the signed stuff
|
||||
* is expected from stdin. With more than 1 argument, the first should
|
||||
* be a detached signature and the remaining files are the signed stuff.
|
||||
*/
|
||||
|
||||
int
|
||||
verify_signatures( int nfiles, char **files )
|
||||
{
|
||||
IOBUF fp;
|
||||
armor_filter_context_t afx;
|
||||
progress_filter_context_t pfx;
|
||||
const char *sigfile;
|
||||
int i, rc;
|
||||
STRLIST sl;
|
||||
|
||||
memset( &afx, 0, sizeof afx);
|
||||
/* decide whether we should handle a detached or a normal signature,
|
||||
* which is needed so that the code later can hash the correct data and
|
||||
* not have a normal signature act as detached signature and ignoring the
|
||||
* indended signed material from the 2nd file or stdin.
|
||||
* 1. gpg <file - normal
|
||||
* 2. gpg file - normal (or detached)
|
||||
* 3. gpg file <file2 - detached
|
||||
* 4. gpg file file2 - detached
|
||||
* The question is how decide between case 2 and 3? The only way
|
||||
* we can do it is by reading one byte from stdin and the unget
|
||||
* it; the problem here is that we may be reading from the
|
||||
* terminal (which could be detected using isatty() but won't work
|
||||
* when under contol of a pty using program (e.g. expect)) and
|
||||
* might get us in trouble when stdin is used for another purpose
|
||||
* (--passphrase-fd 0). So we have to break with the behaviour
|
||||
* prior to gpg 1.0.4 by assuming that case 3 is a normal
|
||||
* signature (where file2 is ignored and require for a detached
|
||||
* signature to indicate signed material comes from stdin by using
|
||||
* case 4 with a file2 of "-".
|
||||
*
|
||||
* Actually we don't have to change anything here but can handle
|
||||
* that all quite easily in mainproc.c
|
||||
*/
|
||||
|
||||
|
||||
sigfile = nfiles? *files : NULL;
|
||||
|
||||
/* open the signature file */
|
||||
fp = iobuf_open(sigfile);
|
||||
if( !fp ) {
|
||||
log_error(_("can't open `%s'\n"), print_fname_stdin(sigfile));
|
||||
return G10ERR_OPEN_FILE;
|
||||
}
|
||||
handle_progress (&pfx, fp, sigfile);
|
||||
|
||||
if( !opt.no_armor && use_armor_filter( fp ) )
|
||||
iobuf_push_filter( fp, armor_filter, &afx );
|
||||
|
||||
sl = NULL;
|
||||
for(i=1 ; i < nfiles; i++ )
|
||||
add_to_strlist( &sl, files[i] );
|
||||
rc = proc_signature_packets( NULL, fp, sl, sigfile );
|
||||
free_strlist(sl);
|
||||
iobuf_close(fp);
|
||||
if( afx.no_openpgp_data && rc == -1 ) {
|
||||
log_error(_("the signature could not be verified.\n"
|
||||
"Please remember that the signature file (.sig or .asc)\n"
|
||||
"should be the first file given on the command line.\n") );
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
print_file_status( int status, const char *name, int what )
|
||||
{
|
||||
char *p = m_alloc(strlen(name)+10);
|
||||
sprintf(p, "%d %s", what, name );
|
||||
write_status_text( status, p );
|
||||
m_free(p);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
verify_one_file( const char *name )
|
||||
{
|
||||
IOBUF fp;
|
||||
armor_filter_context_t afx;
|
||||
progress_filter_context_t pfx;
|
||||
int rc;
|
||||
|
||||
print_file_status( STATUS_FILE_START, name, 1 );
|
||||
fp = iobuf_open(name);
|
||||
if( !fp ) {
|
||||
print_file_status( STATUS_FILE_ERROR, name, 1 );
|
||||
log_error(_("can't open `%s'\n"), print_fname_stdin(name));
|
||||
return G10ERR_OPEN_FILE;
|
||||
}
|
||||
handle_progress (&pfx, fp, name);
|
||||
|
||||
if( !opt.no_armor ) {
|
||||
if( use_armor_filter( fp ) ) {
|
||||
memset( &afx, 0, sizeof afx);
|
||||
iobuf_push_filter( fp, armor_filter, &afx );
|
||||
}
|
||||
}
|
||||
|
||||
rc = proc_signature_packets( NULL, fp, NULL, name );
|
||||
iobuf_close(fp);
|
||||
write_status( STATUS_FILE_DONE );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/****************
|
||||
* Verify each file given in the files array or read the names of the
|
||||
* files from stdin.
|
||||
* Note: This function can not handle detached signatures.
|
||||
*/
|
||||
int
|
||||
verify_files( int nfiles, char **files )
|
||||
{
|
||||
int i;
|
||||
|
||||
if( !nfiles ) { /* read the filenames from stdin */
|
||||
char line[2048];
|
||||
unsigned int lno = 0;
|
||||
|
||||
while( fgets(line, DIM(line), stdin) ) {
|
||||
lno++;
|
||||
if( !*line || line[strlen(line)-1] != '\n' ) {
|
||||
log_error(_("input line %u too long or missing LF\n"), lno );
|
||||
return G10ERR_GENERAL;
|
||||
}
|
||||
/* This code does not work on MSDOS but how cares there are
|
||||
* also no script languages available. We don't strip any
|
||||
* spaces, so that we can process nearly all filenames */
|
||||
line[strlen(line)-1] = 0;
|
||||
verify_one_file( line );
|
||||
}
|
||||
|
||||
}
|
||||
else { /* take filenames from the array */
|
||||
for(i=0; i < nfiles; i++ )
|
||||
verify_one_file( files[i] );
|
||||
}
|
||||
return 0;
|
||||
}
|
373
include/ChangeLog
Normal file
373
include/ChangeLog
Normal file
@ -0,0 +1,373 @@
|
||||
2003-05-24 David Shaw <dshaw@jabberwocky.com>
|
||||
|
||||
* cipher.h, i18n.h, iobuf.h, memory.h, mpi.h, types.h, util.h:
|
||||
Edit all preprocessor instructions to remove whitespace before the
|
||||
'#'. This is not required by C89, but there are some compilers
|
||||
out there that don't like it.
|
||||
|
||||
2003-05-14 David Shaw <dshaw@jabberwocky.com>
|
||||
|
||||
* types.h: Add initializer macros for 64-bit unsigned type.
|
||||
|
||||
2003-05-02 David Shaw <dshaw@jabberwocky.com>
|
||||
|
||||
* cipher.h: Add constants for compression algorithms.
|
||||
|
||||
2003-03-11 David Shaw <dshaw@jabberwocky.com>
|
||||
|
||||
* http.h: Add HTTP_FLAG_TRY_SRV.
|
||||
|
||||
2003-02-11 David Shaw <dshaw@jabberwocky.com>
|
||||
|
||||
* types.h: Try and use uint64_t for a 64-bit type.
|
||||
|
||||
2003-02-04 David Shaw <dshaw@jabberwocky.com>
|
||||
|
||||
* cipher.h: Add constants for new SHAs.
|
||||
|
||||
2002-11-13 David Shaw <dshaw@jabberwocky.com>
|
||||
|
||||
* util.h [__CYGWIN32__]: Don't need the registry prototypes. From
|
||||
Werner on stable branch.
|
||||
|
||||
2002-11-06 David Shaw <dshaw@jabberwocky.com>
|
||||
|
||||
* util.h: Add wipememory2() macro (same as wipememory, but can
|
||||
specify the byte to wipe with).
|
||||
|
||||
2002-10-31 Stefan Bellon <sbellon@sbellon.de>
|
||||
|
||||
* util.h [__riscos__]: Prefixed all RISC OS prototypes with
|
||||
riscos_*
|
||||
|
||||
* zlib-riscos.h: New. This is macro magic in order to make the
|
||||
zlib library calls indeed call the RISC OS ZLib module.
|
||||
|
||||
2002-10-31 David Shaw <dshaw@jabberwocky.com>
|
||||
|
||||
* util.h: Add wipememory() macro.
|
||||
|
||||
2002-10-29 Stefan Bellon <sbellon@sbellon.de>
|
||||
|
||||
* util.h: Added parameter argument to make_basename() needed for
|
||||
filetype support.
|
||||
[__riscos__]: Added prototype.
|
||||
|
||||
2002-10-28 Stefan Bellon <sbellon@sbellon.de>
|
||||
|
||||
* util.h [__riscos__]: Added prototypes for new filetype support.
|
||||
|
||||
2002-10-19 David Shaw <dshaw@jabberwocky.com>
|
||||
|
||||
* distfiles, _regex.h: Add _regex.h from glibc 2.3.1.
|
||||
|
||||
2002-10-14 David Shaw <dshaw@jabberwocky.com>
|
||||
|
||||
* keyserver.h: Go to KEYSERVER_PROTO_VERSION 1.
|
||||
|
||||
2002-10-08 David Shaw <dshaw@jabberwocky.com>
|
||||
|
||||
* keyserver.h: Add new error code KEYSERVER_UNREACHABLE.
|
||||
|
||||
2002-10-03 David Shaw <dshaw@jabberwocky.com>
|
||||
|
||||
* util.h: Add new log_warning logger command which can be switched
|
||||
between log_info and log_error via log_set_strict.
|
||||
|
||||
2002-09-24 David Shaw <dshaw@jabberwocky.com>
|
||||
|
||||
* keyserver.h: Add some new error codes for better GPA support.
|
||||
|
||||
2002-09-10 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* mpi.h (mpi_is_protected, mpi_set_protect_flag)
|
||||
(mpi_clear_protect_flag): Removed.
|
||||
(mpi_get_nbit_info, mpi_set_nbit_info): Removed.
|
||||
|
||||
2002-08-13 David Shaw <dshaw@jabberwocky.com>
|
||||
|
||||
* cipher.h: Add AES aliases for RIJNDAEL algo numbers.
|
||||
|
||||
2002-08-07 David Shaw <dshaw@jabberwocky.com>
|
||||
|
||||
* cipher.h: Add md_algo_present().
|
||||
|
||||
2002-08-06 Stefan Bellon <sbellon@sbellon.de>
|
||||
|
||||
* util.h [__riscos__]: Added riscos_getchar().
|
||||
|
||||
2002-06-21 Stefan Bellon <sbellon@sbellon.de>
|
||||
|
||||
* util.h [__riscos__]: Further moving away of RISC OS specific
|
||||
stuff from general code.
|
||||
|
||||
2002-06-20 Stefan Bellon <sbellon@sbellon.de>
|
||||
|
||||
* util.h [__riscos__]: Added riscos_set_filetype().
|
||||
|
||||
2002-06-14 David Shaw <dshaw@jabberwocky.com>
|
||||
|
||||
* util.h: Add pop_strlist() from strgutil.c.
|
||||
|
||||
2002-06-07 Stefan Bellon <sbellon@sbellon.de>
|
||||
|
||||
* util.h [__riscos__]: RISC OS needs strings.h for strcasecmp()
|
||||
and strncasecmp().
|
||||
|
||||
2002-05-22 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* util.h: Add strncasecmp. Removed stricmp and memicmp.
|
||||
|
||||
2002-05-10 Stefan Bellon <sbellon@sbellon.de>
|
||||
|
||||
* mpi.h: New function mpi_debug_alloc_like for M_DEBUG.
|
||||
|
||||
* util.h [__riscos__]: Make use of __func__ that later
|
||||
Norcroft compiler provides.
|
||||
|
||||
* memory.h: Fixed wrong definition of m_alloc_secure_clear.
|
||||
|
||||
2002-04-23 David Shaw <dshaw@jabberwocky.com>
|
||||
|
||||
* util.h: New function answer_is_yes_no_default() to give a
|
||||
default answer.
|
||||
|
||||
2002-04-22 Stefan Bellon <sbellon@sbellon.de>
|
||||
|
||||
* util.h [__riscos__]: Removed riscos_open, riscos_fopen and
|
||||
riscos_fstat as those special versions aren't needed anymore.
|
||||
|
||||
2002-02-19 David Shaw <dshaw@jabberwocky.com>
|
||||
|
||||
* keyserver.h: Add KEYSERVER_NOT_SUPPORTED for unsupported actions
|
||||
(say, a keyserver that has no way to search, or a readonly
|
||||
keyserver that has no way to add).
|
||||
|
||||
2002-01-02 Stefan Bellon <sbellon@sbellon.de>
|
||||
|
||||
* util.h [__riscos__]: Updated prototype list.
|
||||
|
||||
* types.h [__riscos__]: Changed comment wording.
|
||||
|
||||
2001-12-27 David Shaw <dshaw@jabberwocky.com>
|
||||
|
||||
* KEYSERVER_SCHEME_NOT_FOUND should be 127 to match the POSIX
|
||||
system() (via /bin/sh) way of signaling this.
|
||||
|
||||
* Added G10ERR_KEYSERVER
|
||||
|
||||
2001-12-27 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* util.h [MINGW32]: Fixed name of include file.
|
||||
|
||||
2001-12-22 Timo Schulz <ts@winpt.org>
|
||||
|
||||
* util.h (is_file_compressed): New.
|
||||
|
||||
2001-12-19 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* util.h [CYGWIN32]: Allow this as an alias for MINGW32. Include
|
||||
stdarg.h becuase we use the va_list type. By Disastry.
|
||||
|
||||
2001-09-28 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* cipher.h (PUBKEY_USAGE_CERT): New.
|
||||
|
||||
2001-09-07 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* util.h: Add strsep().
|
||||
|
||||
2001-08-30 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* cipher.h (DEK): Added use_mdc.
|
||||
|
||||
2001-08-24 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* cipher.h (md_write): Made buf arg const.
|
||||
|
||||
2001-08-20 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* cipher.h (DEK): Added algo_info_printed;
|
||||
|
||||
* util.h [__riscos__]: Added prototypes and made sure that we
|
||||
never use __attribute__.
|
||||
* cipher.h, iobuf.h, memory.h, mpi.h [__riscos__]: extern hack.
|
||||
* i18n.h [__riscos__]: Use another include file
|
||||
|
||||
2001-05-30 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* ttyio.h (tty_printf): Add missing parenthesis for non gcc.
|
||||
* http.h: Removed trailing comma to make old ccs happy. Both are
|
||||
by Albert Chin.
|
||||
|
||||
2001-05-25 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* ttyio.h (tty_printf): Add printf attribute.
|
||||
|
||||
2001-04-23 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* http.h: New flag HTTP_FLAG_NO_SHUTDOWN.
|
||||
|
||||
2001-04-13 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* iobuf.h: Removed iobuf_fopen.
|
||||
|
||||
2001-03-01 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* errors.h (G10ERR_UNU_SECKEY,G10ERR_UNU_PUBKEY): New
|
||||
|
||||
2000-11-30 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* iobuf.h (iobuf_translate_file_handle): Add prototype.
|
||||
|
||||
2000-11-11 Paul Eggert <eggert@twinsun.com>
|
||||
|
||||
* iobuf.h (iobuf_get_filelength): Now returns off_t, not u32.
|
||||
(struct iobuf_struct, iobuf_set_limit,
|
||||
iobuf_tell, iobuf_seek): Use off_t, not ulong, for file offsets.
|
||||
|
||||
2000-10-12 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* mpi.h: Changed the way mpi_limb_t is defined.
|
||||
|
||||
Wed Sep 6 17:55:47 CEST 2000 Werner Koch <wk@openit.de>
|
||||
|
||||
* iobuf.c (IOBUF_FILELENGTH_LIMIT): New.
|
||||
|
||||
2000-03-14 14:03:43 Werner Koch (wk@habibti.openit.de)
|
||||
|
||||
* types.h (HAVE_U64_TYPEDEF): Defined depending on configure test.
|
||||
|
||||
Thu Jan 13 19:31:58 CET 2000 Werner Koch <wk@gnupg.de>
|
||||
|
||||
* types.h (HAVE_U64_TYPEDEF): Add a test for _LONGLONG which fixes
|
||||
this long living SGI bug. Reported by Alec Habig.
|
||||
|
||||
Sat Dec 4 12:30:28 CET 1999 Werner Koch <wk@gnupg.de>
|
||||
|
||||
* iobuf.h (IOBUFCTRL_CANCEL): Nww.
|
||||
|
||||
Mon Oct 4 21:23:04 CEST 1999 Werner Koch <wk@gnupg.de>
|
||||
|
||||
* errors.h (G10ERR_NOT_PROCESSED): New.
|
||||
|
||||
Wed Sep 15 16:22:17 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
|
||||
|
||||
|
||||
* i18n.h: Add support for simple-gettext.
|
||||
|
||||
Tue Jun 29 21:44:25 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
|
||||
|
||||
|
||||
* util.h (stricmp): Use strcasecmp as replacement.
|
||||
|
||||
Sat Jun 26 12:15:59 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
|
||||
|
||||
|
||||
* cipher.h (MD_HANDLE): Assigned a structure name.
|
||||
|
||||
Fri Apr 9 12:26:25 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
|
||||
|
||||
* cipher.h (BLOWFISH160): Removed.
|
||||
|
||||
Tue Apr 6 19:58:12 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
|
||||
|
||||
* cipher.h (DEK): increased max. key length to 32 bytes
|
||||
|
||||
|
||||
Sat Feb 20 21:40:49 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
|
||||
|
||||
* g10lib.h: Removed file and changed all files that includes this.
|
||||
|
||||
Tue Feb 16 14:10:02 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
|
||||
|
||||
* types.h (STRLIST): Add field flags.
|
||||
|
||||
Wed Feb 10 17:15:39 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
|
||||
|
||||
* cipher.h (CIPHER_ALGO_TWOFISH): Chnaged ID to 10 and renamed
|
||||
the old experimenatl algorithm to xx_OLD.
|
||||
|
||||
Thu Jan 7 18:00:58 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
|
||||
|
||||
* cipher.h (MD_BUFFER_SIZE): Removed.
|
||||
|
||||
Mon Dec 14 21:18:49 CET 1998 Werner Koch <wk@isil.d.shuttle.de>
|
||||
|
||||
* types.h: fix for SUNPRO_C
|
||||
|
||||
Tue Dec 8 13:15:16 CET 1998 Werner Koch <wk@isil.d.shuttle.de>
|
||||
|
||||
* mpi.h (MPI): Changed the structure name to gcry_mpi and
|
||||
changed all users.
|
||||
|
||||
Tue Oct 20 11:40:00 1998 Werner Koch (wk@isil.d.shuttle.de)
|
||||
|
||||
* iobuf.h (iobuf_get_temp_buffer): New.
|
||||
|
||||
Tue Oct 13 12:40:48 1998 Werner Koch (wk@isil.d.shuttle.de)
|
||||
|
||||
* iobuf.h (iobuf_get): Now uses .nofast
|
||||
(iobuf_get2): Removed.
|
||||
|
||||
Mon Sep 14 09:17:22 1998 Werner Koch (wk@(none))
|
||||
|
||||
* util.h (HAVE_ATEXIT): New.
|
||||
(HAVE_RAISE): New.
|
||||
|
||||
Mon Jul 6 10:41:55 1998 Werner Koch (wk@isil.d.shuttle.de)
|
||||
|
||||
* cipher.h (PUBKEY_USAGE_): New.
|
||||
|
||||
Mon Jul 6 09:49:51 1998 Werner Koch (wk@isil.d.shuttle.de)
|
||||
|
||||
* iobuf.h (iobuf_set_error): New.
|
||||
(iobuf_error): New.
|
||||
|
||||
Sat Jun 13 17:31:32 1998 Werner Koch (wk@isil.d.shuttle.de)
|
||||
|
||||
* g10lib.h: New as interface for the g10lib.
|
||||
|
||||
Mon Jun 8 22:14:48 1998 Werner Koch (wk@isil.d.shuttle.de)
|
||||
|
||||
* cipher.h (CIPHER_ALGO_CAST5): Changed name from .. CAST
|
||||
|
||||
Thu May 21 13:25:51 1998 Werner Koch (wk@isil.d.shuttle.de)
|
||||
|
||||
* cipher.h: removed ROT 5 and changed one id and add dummy
|
||||
|
||||
Tue May 19 18:09:05 1998 Werner Koch (wk@isil.d.shuttle.de)
|
||||
|
||||
* cipher.h (DIGEST_ALGO_TIGER): Chnaged id from 101 to 6.
|
||||
|
||||
Mon May 4 16:37:17 1998 Werner Koch (wk@isil.d.shuttle.de)
|
||||
|
||||
* cipher.h (PUBKEY_ALGO_ELGAMAL_E): New, with value of the
|
||||
old one.
|
||||
* (is_ELGAMAL, is_RSA): New macros
|
||||
|
||||
Sun Apr 26 14:35:24 1998 Werner Koch (wk@isil.d.shuttle.de)
|
||||
|
||||
* types.h: New type u64
|
||||
|
||||
Mon Mar 9 12:59:55 1998 Werner Koch (wk@isil.d.shuttle.de)
|
||||
|
||||
* cipher.h: Included dsa.h.
|
||||
|
||||
Tue Mar 3 15:11:21 1998 Werner Koch (wk@isil.d.shuttle.de)
|
||||
|
||||
* cipher.h (random.h): Add new header and move all relevalt
|
||||
functions to this header.
|
||||
|
||||
|
||||
Copyright 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
|
||||
|
||||
This file is free software; as a special exception the author gives
|
||||
unlimited permission to copy and/or distribute it, with or without
|
||||
modifications, as long as this notice is preserved.
|
||||
|
||||
This file is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
|
205
include/cipher.h
Normal file
205
include/cipher.h
Normal file
@ -0,0 +1,205 @@
|
||||
/* cipher.h
|
||||
* Copyright (C) 1998, 1999, 2000, 2001 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifndef G10_CIPHER_H
|
||||
#define G10_CIPHER_H
|
||||
|
||||
#define DBG_CIPHER g10c_debug_mode
|
||||
|
||||
#include "mpi.h"
|
||||
#include "../cipher/random.h"
|
||||
|
||||
|
||||
#define CIPHER_ALGO_NONE 0
|
||||
#define CIPHER_ALGO_IDEA 1
|
||||
#define CIPHER_ALGO_3DES 2
|
||||
#define CIPHER_ALGO_CAST5 3
|
||||
#define CIPHER_ALGO_BLOWFISH 4 /* blowfish 128 bit key */
|
||||
#define CIPHER_ALGO_SAFER_SK128 5
|
||||
#define CIPHER_ALGO_DES_SK 6
|
||||
#define CIPHER_ALGO_AES 7
|
||||
#define CIPHER_ALGO_AES192 8
|
||||
#define CIPHER_ALGO_AES256 9
|
||||
#define CIPHER_ALGO_RIJNDAEL CIPHER_ALGO_AES
|
||||
#define CIPHER_ALGO_RIJNDAEL192 CIPHER_ALGO_AES192
|
||||
#define CIPHER_ALGO_RIJNDAEL256 CIPHER_ALGO_AES256
|
||||
#define CIPHER_ALGO_TWOFISH 10 /* twofish 256 bit */
|
||||
#define CIPHER_ALGO_SKIPJACK 101 /* experimental: skipjack */
|
||||
#define CIPHER_ALGO_TWOFISH_OLD 102 /* experimental: twofish 128 bit */
|
||||
#define CIPHER_ALGO_DUMMY 110 /* no encryption at all */
|
||||
|
||||
#define PUBKEY_ALGO_RSA 1
|
||||
#define PUBKEY_ALGO_RSA_E 2 /* RSA encrypt only */
|
||||
#define PUBKEY_ALGO_RSA_S 3 /* RSA sign only */
|
||||
#define PUBKEY_ALGO_ELGAMAL_E 16 /* encrypt only ElGamal (but not for v3)*/
|
||||
#define PUBKEY_ALGO_DSA 17
|
||||
#define PUBKEY_ALGO_ELGAMAL 20 /* sign and encrypt elgamal */
|
||||
|
||||
#define PUBKEY_USAGE_SIG 1 /* key is good for signatures */
|
||||
#define PUBKEY_USAGE_ENC 2 /* key is good for encryption */
|
||||
#define PUBKEY_USAGE_CERT 4 /* key is also good to certify other keys*/
|
||||
|
||||
#define DIGEST_ALGO_MD5 1
|
||||
#define DIGEST_ALGO_SHA1 2
|
||||
#define DIGEST_ALGO_RMD160 3
|
||||
#define DIGEST_ALGO_TIGER 6
|
||||
#define DIGEST_ALGO_SHA256 8
|
||||
#define DIGEST_ALGO_SHA384 9
|
||||
#define DIGEST_ALGO_SHA512 10
|
||||
|
||||
#define COMPRESS_ALGO_NONE 0
|
||||
#define COMPRESS_ALGO_ZIP 1
|
||||
#define COMPRESS_ALGO_ZLIB 2
|
||||
|
||||
#define is_RSA(a) ((a)==PUBKEY_ALGO_RSA || (a)==PUBKEY_ALGO_RSA_E \
|
||||
|| (a)==PUBKEY_ALGO_RSA_S )
|
||||
#define is_ELGAMAL(a) ((a)==PUBKEY_ALGO_ELGAMAL || (a)==PUBKEY_ALGO_ELGAMAL_E)
|
||||
|
||||
typedef struct {
|
||||
int algo;
|
||||
int keylen;
|
||||
int algo_info_printed;
|
||||
int use_mdc;
|
||||
byte key[32]; /* this is the largest used keylen (256 bit) */
|
||||
} DEK;
|
||||
|
||||
struct cipher_handle_s;
|
||||
typedef struct cipher_handle_s *CIPHER_HANDLE;
|
||||
|
||||
|
||||
#define CIPHER_MODE_ECB 1
|
||||
#define CIPHER_MODE_CFB 2
|
||||
#define CIPHER_MODE_PHILS_CFB 3
|
||||
#define CIPHER_MODE_AUTO_CFB 4
|
||||
#define CIPHER_MODE_DUMMY 5 /* used with algo DUMMY for no encryption */
|
||||
#define CIPHER_MODE_CBC 6
|
||||
|
||||
struct md_digest_list_s;
|
||||
|
||||
struct gcry_md_context {
|
||||
int secure;
|
||||
FILE *debug;
|
||||
int finalized;
|
||||
struct md_digest_list_s *list;
|
||||
int bufcount;
|
||||
int bufsize;
|
||||
byte buffer[1];
|
||||
};
|
||||
|
||||
typedef struct gcry_md_context *MD_HANDLE;
|
||||
|
||||
#ifndef EXTERN_UNLESS_MAIN_MODULE
|
||||
#if defined (__riscos__) && !defined (INCLUDED_BY_MAIN_MODULE)
|
||||
#define EXTERN_UNLESS_MAIN_MODULE extern
|
||||
#else
|
||||
#define EXTERN_UNLESS_MAIN_MODULE
|
||||
#endif
|
||||
#endif
|
||||
EXTERN_UNLESS_MAIN_MODULE int g10c_debug_mode;
|
||||
EXTERN_UNLESS_MAIN_MODULE int g10_opt_verbose;
|
||||
EXTERN_UNLESS_MAIN_MODULE const char *g10_opt_homedir;
|
||||
|
||||
|
||||
/*-- dynload.c --*/
|
||||
void register_cipher_extension( const char *mainpgm, const char *fname );
|
||||
|
||||
/*-- md.c --*/
|
||||
int string_to_digest_algo( const char *string );
|
||||
const char * digest_algo_to_string( int algo );
|
||||
int check_digest_algo( int algo );
|
||||
MD_HANDLE md_open( int algo, int secure );
|
||||
void md_enable( MD_HANDLE hd, int algo );
|
||||
MD_HANDLE md_copy( MD_HANDLE a );
|
||||
void md_reset( MD_HANDLE a );
|
||||
void md_close(MD_HANDLE a);
|
||||
void md_write( MD_HANDLE a, const byte *inbuf, size_t inlen);
|
||||
void md_final(MD_HANDLE a);
|
||||
byte *md_read( MD_HANDLE a, int algo );
|
||||
int md_digest( MD_HANDLE a, int algo, byte *buffer, int buflen );
|
||||
int md_get_algo( MD_HANDLE a );
|
||||
int md_algo_present( MD_HANDLE a, int algo );
|
||||
int md_digest_length( int algo );
|
||||
const byte *md_asn_oid( int algo, size_t *asnlen, size_t *mdlen );
|
||||
void md_start_debug( MD_HANDLE a, const char *suffix );
|
||||
void md_stop_debug( MD_HANDLE a );
|
||||
#define md_is_secure(a) ((a)->secure)
|
||||
#define md_putc(h,c) \
|
||||
do { \
|
||||
if( (h)->bufcount == (h)->bufsize ) \
|
||||
md_write( (h), NULL, 0 ); \
|
||||
(h)->buffer[(h)->bufcount++] = (c) & 0xff; \
|
||||
} while(0)
|
||||
|
||||
void rmd160_hash_buffer (char *outbuf, const char *buffer, size_t length);
|
||||
|
||||
|
||||
/*-- cipher.c --*/
|
||||
int string_to_cipher_algo( const char *string );
|
||||
const char * cipher_algo_to_string( int algo );
|
||||
void disable_cipher_algo( int algo );
|
||||
int check_cipher_algo( int algo );
|
||||
unsigned cipher_get_keylen( int algo );
|
||||
unsigned cipher_get_blocksize( int algo );
|
||||
CIPHER_HANDLE cipher_open( int algo, int mode, int secure );
|
||||
void cipher_close( CIPHER_HANDLE c );
|
||||
int cipher_setkey( CIPHER_HANDLE c, byte *key, unsigned keylen );
|
||||
void cipher_setiv( CIPHER_HANDLE c, const byte *iv, unsigned ivlen );
|
||||
void cipher_encrypt( CIPHER_HANDLE c, byte *out, byte *in, unsigned nbytes );
|
||||
void cipher_decrypt( CIPHER_HANDLE c, byte *out, byte *in, unsigned nbytes );
|
||||
void cipher_sync( CIPHER_HANDLE c );
|
||||
|
||||
/*-- pubkey.c --*/
|
||||
#define PUBKEY_MAX_NPKEY 4
|
||||
#define PUBKEY_MAX_NSKEY 6
|
||||
#define PUBKEY_MAX_NSIG 2
|
||||
#define PUBKEY_MAX_NENC 2
|
||||
|
||||
int string_to_pubkey_algo( const char *string );
|
||||
const char * pubkey_algo_to_string( int algo );
|
||||
void disable_pubkey_algo( int algo );
|
||||
int check_pubkey_algo( int algo );
|
||||
int check_pubkey_algo2( int algo, unsigned use );
|
||||
int pubkey_get_npkey( int algo );
|
||||
int pubkey_get_nskey( int algo );
|
||||
int pubkey_get_nsig( int algo );
|
||||
int pubkey_get_nenc( int algo );
|
||||
unsigned pubkey_nbits( int algo, MPI *pkey );
|
||||
int pubkey_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors );
|
||||
int pubkey_check_secret_key( int algo, MPI *skey );
|
||||
int pubkey_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey );
|
||||
int pubkey_decrypt( int algo, MPI *result, MPI *data, MPI *skey );
|
||||
int pubkey_sign( int algo, MPI *resarr, MPI hash, MPI *skey );
|
||||
int pubkey_verify( int algo, MPI hash, MPI *data, MPI *pkey,
|
||||
int (*cmp)(void *, MPI), void *opaque );
|
||||
|
||||
/*-- smallprime.c --*/
|
||||
extern ushort small_prime_numbers[];
|
||||
|
||||
/*-- primegen.c --*/
|
||||
void register_primegen_progress ( void (*cb)( void *, int), void *cb_data );
|
||||
MPI generate_secret_prime( unsigned nbits );
|
||||
MPI generate_public_prime( unsigned nbits );
|
||||
MPI generate_elg_prime( int mode, unsigned pbits, unsigned qbits,
|
||||
MPI g, MPI **factors );
|
||||
|
||||
/*-- elsewhere --*/
|
||||
void register_pk_dsa_progress ( void (*cb)( void *, int), void *cb_data );
|
||||
void register_pk_elg_progress ( void (*cb)( void *, int), void *cb_data );
|
||||
|
||||
#endif /*G10_CIPHER_H*/
|
82
include/http.h
Normal file
82
include/http.h
Normal file
@ -0,0 +1,82 @@
|
||||
/* http.h - HTTP protocol handler
|
||||
* Copyright (C) 1999, 2000, 2001 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifndef G10_HTTP_H
|
||||
#define G10_HTTP_H 1
|
||||
|
||||
#include "iobuf.h"
|
||||
|
||||
struct uri_tuple {
|
||||
struct uri_tuple *next;
|
||||
const char *name; /* a pointer into name */
|
||||
char *value; /* a pointer to value (a Nul is always appended) */
|
||||
size_t valuelen; /* and the real length of the value */
|
||||
/* because the value may contain embedded Nuls */
|
||||
};
|
||||
typedef struct uri_tuple *URI_TUPLE;
|
||||
|
||||
struct parsed_uri {
|
||||
/* all these pointers point into buffer; most stuff is not escaped */
|
||||
char *scheme; /* pointer to the scheme string (lowercase) */
|
||||
char *host; /* host (converted to lowercase) */
|
||||
ushort port; /* port (always set if the host is set) */
|
||||
char *path; /* the path */
|
||||
URI_TUPLE params; /* ";xxxxx" */
|
||||
URI_TUPLE query; /* "?xxx=yyy" */
|
||||
char buffer[1]; /* buffer which holds a (modified) copy of the URI */
|
||||
};
|
||||
typedef struct parsed_uri *PARSED_URI;
|
||||
|
||||
typedef enum {
|
||||
HTTP_REQ_GET = 1,
|
||||
HTTP_REQ_HEAD = 2,
|
||||
HTTP_REQ_POST = 3
|
||||
} HTTP_REQ_TYPE;
|
||||
|
||||
enum { /* put flag values into an enum, so that gdb can display them */
|
||||
HTTP_FLAG_TRY_PROXY = 1,
|
||||
HTTP_FLAG_NO_SHUTDOWN = 2,
|
||||
HTTP_FLAG_TRY_SRV = 3
|
||||
};
|
||||
|
||||
struct http_context {
|
||||
int initialized;
|
||||
unsigned int status_code;
|
||||
int sock;
|
||||
int in_data;
|
||||
IOBUF fp_read;
|
||||
IOBUF fp_write;
|
||||
int is_http_0_9;
|
||||
PARSED_URI uri;
|
||||
HTTP_REQ_TYPE req_type;
|
||||
byte *buffer; /* line buffer */
|
||||
unsigned buffer_size;
|
||||
unsigned int flags;
|
||||
};
|
||||
typedef struct http_context *HTTP_HD;
|
||||
|
||||
int http_open( HTTP_HD hd, HTTP_REQ_TYPE reqtype, const char *url,
|
||||
unsigned int flags );
|
||||
void http_start_data( HTTP_HD hd );
|
||||
int http_wait_response( HTTP_HD hd, unsigned int *ret_status );
|
||||
void http_close( HTTP_HD hd );
|
||||
|
||||
int http_open_document( HTTP_HD hd, const char *document, unsigned int flags );
|
||||
|
||||
#endif /*G10_HTTP_H*/
|
54
include/i18n.h
Normal file
54
include/i18n.h
Normal file
@ -0,0 +1,54 @@
|
||||
/* i18n.h
|
||||
* Copyright (C) 1998, 1999, 2000, 2001 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef G10_I18N_H
|
||||
#define G10_I18N_H
|
||||
|
||||
#ifdef USE_SIMPLE_GETTEXT
|
||||
int set_gettext_file( const char *filename );
|
||||
const char *gettext( const char *msgid );
|
||||
|
||||
#define _(a) gettext (a)
|
||||
#define N_(a) (a)
|
||||
|
||||
#else
|
||||
#ifdef HAVE_LOCALE_H
|
||||
#include <locale.h> /* suggested by Ernst Molitor */
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_NLS
|
||||
#ifndef __riscos__
|
||||
#include <libintl.h>
|
||||
#else
|
||||
#include "libgettext.h"
|
||||
#endif /* __riscos__ */
|
||||
#define _(a) gettext (a)
|
||||
#ifdef gettext_noop
|
||||
#define N_(a) gettext_noop (a)
|
||||
#else
|
||||
#define N_(a) (a)
|
||||
#endif
|
||||
#else
|
||||
#define _(a) (a)
|
||||
#define N_(a) (a)
|
||||
#endif
|
||||
#endif /* !USE_SIMPLE_GETTEXT */
|
||||
|
||||
#endif /*G10_I18N_H*/
|
161
include/iobuf.h
Normal file
161
include/iobuf.h
Normal file
@ -0,0 +1,161 @@
|
||||
/* iobuf.h - I/O buffer
|
||||
* Copyright (C) 1998, 1999, 2000, 2001 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef G10_IOBUF_H
|
||||
#define G10_IOBUF_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
|
||||
#define DBG_IOBUF iobuf_debug_mode
|
||||
|
||||
|
||||
#define IOBUFCTRL_INIT 1
|
||||
#define IOBUFCTRL_FREE 2
|
||||
#define IOBUFCTRL_UNDERFLOW 3
|
||||
#define IOBUFCTRL_FLUSH 4
|
||||
#define IOBUFCTRL_DESC 5
|
||||
#define IOBUFCTRL_CANCEL 6
|
||||
#define IOBUFCTRL_USER 16
|
||||
|
||||
typedef struct iobuf_struct *IOBUF;
|
||||
|
||||
/* fixme: we should hide most of this stuff */
|
||||
struct iobuf_struct {
|
||||
int use; /* 1 input , 2 output, 3 temp */
|
||||
off_t nlimit;
|
||||
off_t nbytes; /* used together with nlimit */
|
||||
off_t ntotal; /* total bytes read (position of stream) */
|
||||
int nofast; /* used by the iobuf_get() */
|
||||
void *directfp;
|
||||
struct {
|
||||
size_t size; /* allocated size */
|
||||
size_t start; /* number of invalid bytes at the begin of the buffer */
|
||||
size_t len; /* currently filled to this size */
|
||||
byte *buf;
|
||||
} d;
|
||||
int filter_eof;
|
||||
int error;
|
||||
int (*filter)( void *opaque, int control,
|
||||
IOBUF chain, byte *buf, size_t *len);
|
||||
void *filter_ov; /* value for opaque */
|
||||
int filter_ov_owner;
|
||||
char *real_fname;
|
||||
IOBUF chain; /* next iobuf used for i/o if any (passed to filter) */
|
||||
int no, subno;
|
||||
const char *desc;
|
||||
void *opaque; /* can be used to hold any information */
|
||||
/* this value is copied to all instances */
|
||||
struct {
|
||||
size_t size; /* allocated size */
|
||||
size_t start; /* number of invalid bytes at the begin of the buffer */
|
||||
size_t len; /* currently filled to this size */
|
||||
byte *buf;
|
||||
} unget;
|
||||
};
|
||||
|
||||
#ifndef EXTERN_UNLESS_MAIN_MODULE
|
||||
#if defined (__riscos__) && !defined (INCLUDED_BY_MAIN_MODULE)
|
||||
#define EXTERN_UNLESS_MAIN_MODULE extern
|
||||
#else
|
||||
#define EXTERN_UNLESS_MAIN_MODULE
|
||||
#endif
|
||||
#endif
|
||||
EXTERN_UNLESS_MAIN_MODULE int iobuf_debug_mode;
|
||||
|
||||
void iobuf_enable_special_filenames ( int yes );
|
||||
IOBUF iobuf_alloc(int use, size_t bufsize);
|
||||
IOBUF iobuf_temp(void);
|
||||
IOBUF iobuf_temp_with_content( const char *buffer, size_t length );
|
||||
IOBUF iobuf_open( const char *fname );
|
||||
IOBUF iobuf_fdopen( int fd, const char *mode );
|
||||
IOBUF iobuf_sockopen( int fd, const char *mode );
|
||||
IOBUF iobuf_create( const char *fname );
|
||||
IOBUF iobuf_append( const char *fname );
|
||||
IOBUF iobuf_openrw( const char *fname );
|
||||
int iobuf_ioctl ( IOBUF a, int cmd, int intval, void *ptrval );
|
||||
int iobuf_close( IOBUF iobuf );
|
||||
int iobuf_cancel( IOBUF iobuf );
|
||||
|
||||
int iobuf_push_filter( IOBUF a, int (*f)(void *opaque, int control,
|
||||
IOBUF chain, byte *buf, size_t *len), void *ov );
|
||||
int iobuf_push_filter2( IOBUF a,
|
||||
int (*f)(void *opaque, int control,
|
||||
IOBUF chain, byte *buf, size_t *len),
|
||||
void *ov, int rel_ov );
|
||||
int iobuf_flush(IOBUF a);
|
||||
void iobuf_clear_eof(IOBUF a);
|
||||
#define iobuf_set_error(a) do { (a)->error = 1; } while(0)
|
||||
#define iobuf_error(a) ((a)->error)
|
||||
|
||||
void iobuf_set_limit( IOBUF a, off_t nlimit );
|
||||
|
||||
off_t iobuf_tell( IOBUF a );
|
||||
int iobuf_seek( IOBUF a, off_t newpos );
|
||||
|
||||
int iobuf_readbyte(IOBUF a);
|
||||
int iobuf_read(IOBUF a, byte *buf, unsigned buflen );
|
||||
unsigned iobuf_read_line( IOBUF a, byte **addr_of_buffer,
|
||||
unsigned *length_of_buffer, unsigned *max_length );
|
||||
int iobuf_peek(IOBUF a, byte *buf, unsigned buflen );
|
||||
int iobuf_writebyte(IOBUF a, unsigned c);
|
||||
int iobuf_write(IOBUF a, byte *buf, unsigned buflen );
|
||||
int iobuf_writestr(IOBUF a, const char *buf );
|
||||
|
||||
void iobuf_flush_temp( IOBUF temp );
|
||||
int iobuf_write_temp( IOBUF a, IOBUF temp );
|
||||
size_t iobuf_temp_to_buffer( IOBUF a, byte *buffer, size_t buflen );
|
||||
void iobuf_unget_and_close_temp( IOBUF a, IOBUF temp );
|
||||
|
||||
off_t iobuf_get_filelength( IOBUF a );
|
||||
#define IOBUF_FILELENGTH_LIMIT 0xffffffff
|
||||
const char *iobuf_get_real_fname( IOBUF a );
|
||||
const char *iobuf_get_fname( IOBUF a );
|
||||
|
||||
void iobuf_set_block_mode( IOBUF a, size_t n );
|
||||
void iobuf_set_partial_block_mode( IOBUF a, size_t len );
|
||||
int iobuf_in_block_mode( IOBUF a );
|
||||
|
||||
int iobuf_translate_file_handle ( int fd, int for_write );
|
||||
|
||||
|
||||
/* get a byte form the iobuf; must check for eof prior to this function
|
||||
* this function returns values in the range 0 .. 255 or -1 to indicate EOF
|
||||
* iobuf_get_noeof() does not return -1 to indicate EOF, but masks the
|
||||
* returned value to be in the range 0 ..255.
|
||||
*/
|
||||
#define iobuf_get(a) \
|
||||
( ((a)->nofast || (a)->d.start >= (a)->d.len )? \
|
||||
iobuf_readbyte((a)) : ( (a)->nbytes++, (a)->d.buf[(a)->d.start++] ) )
|
||||
#define iobuf_get_noeof(a) (iobuf_get((a))&0xff)
|
||||
|
||||
/* write a byte to the iobuf and return true on write error
|
||||
* This macro does only write the low order byte
|
||||
*/
|
||||
#define iobuf_put(a,c) iobuf_writebyte(a,c)
|
||||
|
||||
#define iobuf_where(a) "[don't know]"
|
||||
#define iobuf_id(a) ((a)->no)
|
||||
|
||||
#define iobuf_get_temp_buffer(a) ( (a)->d.buf )
|
||||
#define iobuf_get_temp_length(a) ( (a)->d.len )
|
||||
#define iobuf_is_temp(a) ( (a)->use == 3 )
|
||||
|
||||
#endif /*G10_IOBUF_H*/
|
93
include/memory.h
Normal file
93
include/memory.h
Normal file
@ -0,0 +1,93 @@
|
||||
/* memory.h - memory allocation
|
||||
* Copyright (C) 1998, 1999, 2000, 2001 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef G10_MEMORY_H
|
||||
#define G10_MEMORY_H
|
||||
|
||||
#ifdef M_DEBUG
|
||||
#ifndef STR
|
||||
#define STR(v) #v
|
||||
#endif
|
||||
#ifndef __riscos__
|
||||
#define M_DBGINFO(a) __FUNCTION__ "["__FILE__ ":" STR(a) "]"
|
||||
#else /* __riscos__ */
|
||||
#define M_DBGINFO(a) "["__FILE__ ":" STR(a) "]"
|
||||
#endif /* __riscos__ */
|
||||
#define m_alloc(n) m_debug_alloc((n), M_DBGINFO( __LINE__ ) )
|
||||
#define m_alloc_clear(n) m_debug_alloc_clear((n), M_DBGINFO(__LINE__) )
|
||||
#define m_alloc_secure(n) m_debug_alloc((n), M_DBGINFO(__LINE__) )
|
||||
#define m_alloc_secure_clear(n) m_debug_alloc_secure_clear((n), M_DBGINFO(__LINE__) )
|
||||
#define m_realloc(n,m) m_debug_realloc((n),(m), M_DBGINFO(__LINE__) )
|
||||
#define m_free(n) m_debug_free((n), M_DBGINFO(__LINE__) )
|
||||
#define m_check(n) m_debug_check((n), M_DBGINFO(__LINE__) )
|
||||
/*#define m_copy(a) m_debug_copy((a), M_DBGINFO(__LINE__) )*/
|
||||
#define m_strdup(a) m_debug_strdup((a), M_DBGINFO(__LINE__) )
|
||||
|
||||
void *m_debug_alloc( size_t n, const char *info );
|
||||
void *m_debug_alloc_clear( size_t n, const char *info );
|
||||
void *m_debug_alloc_secure( size_t n, const char *info );
|
||||
void *m_debug_alloc_secure_clear( size_t n, const char *info );
|
||||
void *m_debug_realloc( void *a, size_t n, const char *info );
|
||||
void m_debug_free( void *p, const char *info );
|
||||
void m_debug_check( const void *a, const char *info );
|
||||
/*void *m_debug_copy( const void *a, const char *info );*/
|
||||
char *m_debug_strdup( const char *a, const char *info );
|
||||
|
||||
#else
|
||||
void *m_alloc( size_t n );
|
||||
void *m_alloc_clear( size_t n );
|
||||
void *m_alloc_secure( size_t n );
|
||||
void *m_alloc_secure_clear( size_t n );
|
||||
void *m_realloc( void *a, size_t n );
|
||||
void m_free( void *p );
|
||||
void m_check( const void *a );
|
||||
/*void *m_copy( const void *a );*/
|
||||
char *m_strdup( const char * a);
|
||||
#endif
|
||||
|
||||
size_t m_size( const void *a );
|
||||
void m_print_stats(const char *prefix);
|
||||
|
||||
/*-- secmem.c --*/
|
||||
void secmem_init( size_t npool );
|
||||
void secmem_term( void );
|
||||
void *secmem_malloc( size_t size );
|
||||
void *secmem_realloc( void *a, size_t newsize );
|
||||
void secmem_free( void *a );
|
||||
int m_is_secure( const void *p );
|
||||
void secmem_dump_stats(void);
|
||||
void secmem_set_flags( unsigned flags );
|
||||
unsigned secmem_get_flags(void);
|
||||
|
||||
|
||||
#define DBG_MEMORY memory_debug_mode
|
||||
#define DBG_MEMSTAT memory_stat_debug_mode
|
||||
|
||||
#ifndef EXTERN_UNLESS_MAIN_MODULE
|
||||
#if defined (__riscos__) && !defined (INCLUDED_BY_MAIN_MODULE)
|
||||
#define EXTERN_UNLESS_MAIN_MODULE extern
|
||||
#else
|
||||
#define EXTERN_UNLESS_MAIN_MODULE
|
||||
#endif
|
||||
#endif
|
||||
EXTERN_UNLESS_MAIN_MODULE int memory_debug_mode;
|
||||
EXTERN_UNLESS_MAIN_MODULE int memory_stat_debug_mode;
|
||||
|
||||
#endif /*G10_MEMORY_H*/
|
196
include/mpi.h
Normal file
196
include/mpi.h
Normal file
@ -0,0 +1,196 @@
|
||||
/* mpi.h - Multi Precision Integers
|
||||
* Copyright (C) 1994, 1996, 1998, 1999,
|
||||
* 2000, 2001 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
* Note: This code is heavily based on the GNU MP Library.
|
||||
* Actually it's the same code with only minor changes in the
|
||||
* way the data is stored; this is to support the abstraction
|
||||
* of an optional secure memory allocation which may be used
|
||||
* to avoid revealing of sensitive data due to paging etc.
|
||||
* The GNU MP Library itself is published under the LGPL;
|
||||
* however I decided to publish this code under the plain GPL.
|
||||
*/
|
||||
|
||||
#ifndef G10_MPI_H
|
||||
#define G10_MPI_H
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include "iobuf.h"
|
||||
#include "types.h"
|
||||
#include "memory.h"
|
||||
|
||||
#if BYTES_PER_MPI_LIMB == SIZEOF_UNSIGNED_INT
|
||||
typedef unsigned int mpi_limb_t;
|
||||
typedef signed int mpi_limb_signed_t;
|
||||
#elif BYTES_PER_MPI_LIMB == SIZEOF_UNSIGNED_LONG
|
||||
typedef unsigned long int mpi_limb_t;
|
||||
typedef signed long int mpi_limb_signed_t;
|
||||
#elif BYTES_PER_MPI_LIMB == SIZEOF_UNSIGNED_LONG_LONG
|
||||
typedef unsigned long long int mpi_limb_t;
|
||||
typedef signed long long int mpi_limb_signed_t;
|
||||
#elif BYTES_PER_MPI_LIMB == SIZEOF_UNSIGNED_SHORT
|
||||
typedef unsigned short int mpi_limb_t;
|
||||
typedef signed short int mpi_limb_signed_t;
|
||||
#else
|
||||
#error BYTES_PER_MPI_LIMB does not match any C type
|
||||
#endif
|
||||
#define BITS_PER_MPI_LIMB (8*BYTES_PER_MPI_LIMB)
|
||||
|
||||
#ifndef EXTERN_UNLESS_MAIN_MODULE
|
||||
#if defined (__riscos__) && !defined (INCLUDED_BY_MAIN_MODULE)
|
||||
#define EXTERN_UNLESS_MAIN_MODULE extern
|
||||
#else
|
||||
#define EXTERN_UNLESS_MAIN_MODULE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define DBG_MPI mpi_debug_mode
|
||||
EXTERN_UNLESS_MAIN_MODULE int mpi_debug_mode;
|
||||
|
||||
|
||||
struct gcry_mpi {
|
||||
int alloced; /* array size (# of allocated limbs) */
|
||||
int nlimbs; /* number of valid limbs */
|
||||
int nbits; /* the real number of valid bits (info only) */
|
||||
int sign; /* indicates a negative number */
|
||||
unsigned flags; /* bit 0: array must be allocated in secure memory space */
|
||||
/* bit 1: not used */
|
||||
/* bit 2: the limb is a pointer to some m_alloced data */
|
||||
mpi_limb_t *d; /* array with the limbs */
|
||||
};
|
||||
|
||||
typedef struct gcry_mpi *MPI;
|
||||
|
||||
#define MPI_NULL NULL
|
||||
|
||||
#define mpi_get_nlimbs(a) ((a)->nlimbs)
|
||||
#define mpi_is_neg(a) ((a)->sign)
|
||||
|
||||
/*-- mpiutil.c --*/
|
||||
|
||||
#ifdef M_DEBUG
|
||||
#define mpi_alloc(n) mpi_debug_alloc((n), M_DBGINFO( __LINE__ ) )
|
||||
#define mpi_alloc_secure(n) mpi_debug_alloc_secure((n), M_DBGINFO( __LINE__ ) )
|
||||
#define mpi_alloc_like(n) mpi_debug_alloc_like((n), M_DBGINFO( __LINE__ ) )
|
||||
#define mpi_free(a) mpi_debug_free((a), M_DBGINFO(__LINE__) )
|
||||
#define mpi_resize(a,b) mpi_debug_resize((a),(b), M_DBGINFO(__LINE__) )
|
||||
#define mpi_copy(a) mpi_debug_copy((a), M_DBGINFO(__LINE__) )
|
||||
MPI mpi_debug_alloc( unsigned nlimbs, const char *info );
|
||||
MPI mpi_debug_alloc_secure( unsigned nlimbs, const char *info );
|
||||
MPI mpi_debug_alloc_like( MPI a, const char *info );
|
||||
void mpi_debug_free( MPI a, const char *info );
|
||||
void mpi_debug_resize( MPI a, unsigned nlimbs, const char *info );
|
||||
MPI mpi_debug_copy( MPI a, const char *info );
|
||||
#else
|
||||
MPI mpi_alloc( unsigned nlimbs );
|
||||
MPI mpi_alloc_secure( unsigned nlimbs );
|
||||
MPI mpi_alloc_like( MPI a );
|
||||
void mpi_free( MPI a );
|
||||
void mpi_resize( MPI a, unsigned nlimbs );
|
||||
MPI mpi_copy( MPI a );
|
||||
#endif
|
||||
#define mpi_is_opaque(a) ((a) && ((a)->flags&4))
|
||||
MPI mpi_set_opaque( MPI a, void *p, int len );
|
||||
void *mpi_get_opaque( MPI a, int *len );
|
||||
#define mpi_is_secure(a) ((a) && ((a)->flags&1))
|
||||
void mpi_set_secure( MPI a );
|
||||
void mpi_clear( MPI a );
|
||||
void mpi_set( MPI w, MPI u);
|
||||
void mpi_set_ui( MPI w, ulong u);
|
||||
MPI mpi_alloc_set_ui( unsigned long u);
|
||||
void mpi_m_check( MPI a );
|
||||
void mpi_swap( MPI a, MPI b);
|
||||
|
||||
/*-- mpicoder.c --*/
|
||||
int mpi_write( IOBUF out, MPI a );
|
||||
#ifdef M_DEBUG
|
||||
#define mpi_read(a,b,c) mpi_debug_read((a),(b),(c), M_DBGINFO( __LINE__ ) )
|
||||
MPI mpi_debug_read(IOBUF inp, unsigned *nread, int secure, const char *info);
|
||||
#else
|
||||
MPI mpi_read(IOBUF inp, unsigned *nread, int secure);
|
||||
#endif
|
||||
MPI mpi_read_from_buffer(byte *buffer, unsigned *ret_nread, int secure);
|
||||
int mpi_fromstr(MPI val, const char *str);
|
||||
int mpi_print( FILE *fp, MPI a, int mode );
|
||||
void g10_log_mpidump( const char *text, MPI a );
|
||||
u32 mpi_get_keyid( MPI a, u32 *keyid );
|
||||
byte *mpi_get_buffer( MPI a, unsigned *nbytes, int *sign );
|
||||
byte *mpi_get_secure_buffer( MPI a, unsigned *nbytes, int *sign );
|
||||
void mpi_set_buffer( MPI a, const byte *buffer, unsigned nbytes, int sign );
|
||||
|
||||
#define log_mpidump g10_log_mpidump
|
||||
|
||||
/*-- mpi-add.c --*/
|
||||
void mpi_add_ui(MPI w, MPI u, ulong v );
|
||||
void mpi_add(MPI w, MPI u, MPI v);
|
||||
void mpi_addm(MPI w, MPI u, MPI v, MPI m);
|
||||
void mpi_sub_ui(MPI w, MPI u, ulong v );
|
||||
void mpi_sub( MPI w, MPI u, MPI v);
|
||||
void mpi_subm( MPI w, MPI u, MPI v, MPI m);
|
||||
|
||||
/*-- mpi-mul.c --*/
|
||||
void mpi_mul_ui(MPI w, MPI u, ulong v );
|
||||
void mpi_mul_2exp( MPI w, MPI u, ulong cnt);
|
||||
void mpi_mul( MPI w, MPI u, MPI v);
|
||||
void mpi_mulm( MPI w, MPI u, MPI v, MPI m);
|
||||
|
||||
/*-- mpi-div.c --*/
|
||||
ulong mpi_fdiv_r_ui( MPI rem, MPI dividend, ulong divisor );
|
||||
void mpi_fdiv_r( MPI rem, MPI dividend, MPI divisor );
|
||||
void mpi_fdiv_q( MPI quot, MPI dividend, MPI divisor );
|
||||
void mpi_fdiv_qr( MPI quot, MPI rem, MPI dividend, MPI divisor );
|
||||
void mpi_tdiv_r( MPI rem, MPI num, MPI den);
|
||||
void mpi_tdiv_qr( MPI quot, MPI rem, MPI num, MPI den);
|
||||
void mpi_tdiv_q_2exp( MPI w, MPI u, unsigned count );
|
||||
int mpi_divisible_ui(MPI dividend, ulong divisor );
|
||||
|
||||
/*-- mpi-gcd.c --*/
|
||||
int mpi_gcd( MPI g, MPI a, MPI b );
|
||||
|
||||
/*-- mpi-pow.c --*/
|
||||
void mpi_pow( MPI w, MPI u, MPI v);
|
||||
void mpi_powm( MPI res, MPI base, MPI exp, MPI mod);
|
||||
|
||||
/*-- mpi-mpow.c --*/
|
||||
void mpi_mulpowm( MPI res, MPI *basearray, MPI *exparray, MPI mod);
|
||||
|
||||
/*-- mpi-cmp.c --*/
|
||||
int mpi_cmp_ui( MPI u, ulong v );
|
||||
int mpi_cmp( MPI u, MPI v );
|
||||
|
||||
/*-- mpi-scan.c --*/
|
||||
int mpi_getbyte( MPI a, unsigned idx );
|
||||
void mpi_putbyte( MPI a, unsigned idx, int value );
|
||||
unsigned mpi_trailing_zeros( MPI a );
|
||||
|
||||
/*-- mpi-bit.c --*/
|
||||
void mpi_normalize( MPI a );
|
||||
unsigned mpi_get_nbits( MPI a );
|
||||
int mpi_test_bit( MPI a, unsigned n );
|
||||
void mpi_set_bit( MPI a, unsigned n );
|
||||
void mpi_set_highbit( MPI a, unsigned n );
|
||||
void mpi_clear_highbit( MPI a, unsigned n );
|
||||
void mpi_clear_bit( MPI a, unsigned n );
|
||||
void mpi_rshift( MPI x, MPI a, unsigned n );
|
||||
|
||||
/*-- mpi-inv.c --*/
|
||||
void mpi_invm( MPI x, MPI u, MPI v );
|
||||
|
||||
#endif /*G10_MPI_H*/
|
141
include/types.h
Normal file
141
include/types.h
Normal file
@ -0,0 +1,141 @@
|
||||
/* types.h - some common typedefs
|
||||
* Copyright (C) 1998, 1999, 2000, 2001 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef G10_TYPES_H
|
||||
#define G10_TYPES_H
|
||||
|
||||
#ifdef HAVE_INTTYPES_H
|
||||
/* For uint64_t */
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
|
||||
/* The AC_CHECK_SIZEOF() in configure fails for some machines.
|
||||
* we provide some fallback values here */
|
||||
#if !SIZEOF_UNSIGNED_SHORT
|
||||
#undef SIZEOF_UNSIGNED_SHORT
|
||||
#define SIZEOF_UNSIGNED_SHORT 2
|
||||
#endif
|
||||
#if !SIZEOF_UNSIGNED_INT
|
||||
#undef SIZEOF_UNSIGNED_INT
|
||||
#define SIZEOF_UNSIGNED_INT 4
|
||||
#endif
|
||||
#if !SIZEOF_UNSIGNED_LONG
|
||||
#undef SIZEOF_UNSIGNED_LONG
|
||||
#define SIZEOF_UNSIGNED_LONG 4
|
||||
#endif
|
||||
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
|
||||
#ifndef HAVE_BYTE_TYPEDEF
|
||||
#undef byte /* maybe there is a macro with this name */
|
||||
#ifndef __riscos__
|
||||
typedef unsigned char byte;
|
||||
#else
|
||||
/* Norcroft treats char = unsigned char as legal assignment
|
||||
but char* = unsigned char* as illegal assignment
|
||||
and the same applies to the signed variants as well */
|
||||
typedef char byte;
|
||||
#endif
|
||||
#define HAVE_BYTE_TYPEDEF
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_USHORT_TYPEDEF
|
||||
#undef ushort /* maybe there is a macro with this name */
|
||||
typedef unsigned short ushort;
|
||||
#define HAVE_USHORT_TYPEDEF
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_ULONG_TYPEDEF
|
||||
#undef ulong /* maybe there is a macro with this name */
|
||||
typedef unsigned long ulong;
|
||||
#define HAVE_ULONG_TYPEDEF
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_U16_TYPEDEF
|
||||
#undef u16 /* maybe there is a macro with this name */
|
||||
#if SIZEOF_UNSIGNED_INT == 2
|
||||
typedef unsigned int u16;
|
||||
#elif SIZEOF_UNSIGNED_SHORT == 2
|
||||
typedef unsigned short u16;
|
||||
#else
|
||||
#error no typedef for u16
|
||||
#endif
|
||||
#define HAVE_U16_TYPEDEF
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_U32_TYPEDEF
|
||||
#undef u32 /* maybe there is a macro with this name */
|
||||
#if SIZEOF_UNSIGNED_INT == 4
|
||||
typedef unsigned int u32;
|
||||
#elif SIZEOF_UNSIGNED_LONG == 4
|
||||
typedef unsigned long u32;
|
||||
#else
|
||||
#error no typedef for u32
|
||||
#endif
|
||||
#define HAVE_U32_TYPEDEF
|
||||
#endif
|
||||
|
||||
/****************
|
||||
* Warning: Some systems segfault when this u64 typedef and
|
||||
* the dummy code in cipher/md.c is not available. Examples are
|
||||
* Solaris and IRIX.
|
||||
*/
|
||||
#ifndef HAVE_U64_TYPEDEF
|
||||
#undef u64 /* maybe there is a macro with this name */
|
||||
#if SIZEOF_UNSIGNED_INT == 8
|
||||
typedef unsigned int u64;
|
||||
#define U64_C(c) (c ## U)
|
||||
#define HAVE_U64_TYPEDEF
|
||||
#elif SIZEOF_UNSIGNED_LONG == 8
|
||||
typedef unsigned long u64;
|
||||
#define U64_C(c) (c ## UL)
|
||||
#define HAVE_U64_TYPEDEF
|
||||
#elif SIZEOF_UNSIGNED_LONG_LONG == 8
|
||||
typedef unsigned long long u64;
|
||||
#define U64_C(c) (c ## ULL)
|
||||
#define HAVE_U64_TYPEDEF
|
||||
#elif SIZEOF_UINT64_T == 8
|
||||
typedef uint64_t u64;
|
||||
#define U64_C(c) (UINT64_C(c))
|
||||
#define HAVE_U64_TYPEDEF
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef union {
|
||||
int a;
|
||||
short b;
|
||||
char c[1];
|
||||
long d;
|
||||
#ifdef HAVE_U64_TYPEDEF
|
||||
u64 e;
|
||||
#endif
|
||||
float f;
|
||||
double g;
|
||||
} PROPERLY_ALIGNED_TYPE;
|
||||
|
||||
typedef struct string_list {
|
||||
struct string_list *next;
|
||||
unsigned int flags;
|
||||
char d[1];
|
||||
} *STRLIST;
|
||||
|
||||
#endif /*G10_TYPES_H*/
|
304
include/util.h
Normal file
304
include/util.h
Normal file
@ -0,0 +1,304 @@
|
||||
/* util.h
|
||||
* Copyright (C) 1998, 1999, 2000, 2001 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifndef G10_UTIL_H
|
||||
#define G10_UTIL_H
|
||||
|
||||
#if defined (__MINGW32__) || defined (__CYGWIN32__)
|
||||
#include <stdarg.h>
|
||||
#endif
|
||||
|
||||
#include "types.h"
|
||||
#include "errors.h"
|
||||
#include "types.h"
|
||||
#include "mpi.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
int *argc; /* pointer to argc (value subject to change) */
|
||||
char ***argv; /* pointer to argv (value subject to change) */
|
||||
unsigned flags; /* Global flags (DO NOT CHANGE) */
|
||||
int err; /* print error about last option */
|
||||
/* 1 = warning, 2 = abort */
|
||||
int r_opt; /* return option */
|
||||
int r_type; /* type of return value (0 = no argument found)*/
|
||||
union {
|
||||
int ret_int;
|
||||
long ret_long;
|
||||
ulong ret_ulong;
|
||||
char *ret_str;
|
||||
} r; /* Return values */
|
||||
struct {
|
||||
int idx;
|
||||
int inarg;
|
||||
int stopped;
|
||||
const char *last;
|
||||
void *aliases;
|
||||
const void *cur_alias;
|
||||
} internal; /* DO NOT CHANGE */
|
||||
} ARGPARSE_ARGS;
|
||||
|
||||
typedef struct {
|
||||
int short_opt;
|
||||
const char *long_opt;
|
||||
unsigned flags;
|
||||
const char *description; /* optional option description */
|
||||
} ARGPARSE_OPTS;
|
||||
|
||||
/*-- logger.c --*/
|
||||
void log_set_logfile( const char *name, int fd );
|
||||
FILE *log_stream(void);
|
||||
void g10_log_print_prefix(const char *text);
|
||||
void log_set_name( const char *name );
|
||||
const char *log_get_name(void);
|
||||
void log_set_pid( int pid );
|
||||
int log_get_errorcount( int clear );
|
||||
void log_inc_errorcount(void);
|
||||
int log_set_strict(int val);
|
||||
void g10_log_hexdump( const char *text, const char *buf, size_t len );
|
||||
|
||||
#if defined (__riscos__) \
|
||||
|| (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 ))
|
||||
void g10_log_bug( const char *fmt, ... )
|
||||
__attribute__ ((noreturn, format (printf,1,2)));
|
||||
void g10_log_bug0( const char *, int, const char * ) __attribute__ ((noreturn));
|
||||
void g10_log_fatal( const char *fmt, ... )
|
||||
__attribute__ ((noreturn, format (printf,1,2)));
|
||||
void g10_log_error( const char *fmt, ... ) __attribute__ ((format (printf,1,2)));
|
||||
void g10_log_info( const char *fmt, ... ) __attribute__ ((format (printf,1,2)));
|
||||
void g10_log_warning( const char *fmt, ... ) __attribute__ ((format (printf,1,2)));
|
||||
void g10_log_debug( const char *fmt, ... ) __attribute__ ((format (printf,1,2)));
|
||||
void g10_log_fatal_f( const char *fname, const char *fmt, ... )
|
||||
__attribute__ ((noreturn, format (printf,2,3)));
|
||||
void g10_log_error_f( const char *fname, const char *fmt, ... )
|
||||
__attribute__ ((format (printf,2,3)));
|
||||
void g10_log_info_f( const char *fname, const char *fmt, ... )
|
||||
__attribute__ ((format (printf,2,3)));
|
||||
void g10_log_debug_f( const char *fname, const char *fmt, ... )
|
||||
__attribute__ ((format (printf,2,3)));
|
||||
#ifndef __riscos__
|
||||
#define BUG() g10_log_bug0( __FILE__ , __LINE__, __FUNCTION__ )
|
||||
#else
|
||||
#define BUG() g10_log_bug0( __FILE__ , __LINE__, __func__ )
|
||||
#endif
|
||||
#else
|
||||
void g10_log_bug( const char *fmt, ... );
|
||||
void g10_log_bug0( const char *, int );
|
||||
void g10_log_fatal( const char *fmt, ... );
|
||||
void g10_log_error( const char *fmt, ... );
|
||||
void g10_log_info( const char *fmt, ... );
|
||||
void g10_log_warning( const char *fmt, ... );
|
||||
void g10_log_debug( const char *fmt, ... );
|
||||
void g10_log_fatal_f( const char *fname, const char *fmt, ... );
|
||||
void g10_log_error_f( const char *fname, const char *fmt, ... );
|
||||
void g10_log_info_f( const char *fname, const char *fmt, ... );
|
||||
void g10_log_debug_f( const char *fname, const char *fmt, ... );
|
||||
#define BUG() g10_log_bug0( __FILE__ , __LINE__ )
|
||||
#endif
|
||||
|
||||
#define log_hexdump g10_log_hexdump
|
||||
#define log_bug g10_log_bug
|
||||
#define log_bug0 g10_log_bug0
|
||||
#define log_fatal g10_log_fatal
|
||||
#define log_error g10_log_error
|
||||
#define log_info g10_log_info
|
||||
#define log_warning g10_log_warning
|
||||
#define log_debug g10_log_debug
|
||||
#define log_fatal_f g10_log_fatal_f
|
||||
#define log_error_f g10_log_error_f
|
||||
#define log_info_f g10_log_info_f
|
||||
#define log_debug_f g10_log_debug_f
|
||||
|
||||
|
||||
/*-- errors.c --*/
|
||||
const char * g10_errstr( int no );
|
||||
|
||||
/*-- argparse.c --*/
|
||||
int arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts);
|
||||
int optfile_parse( FILE *fp, const char *filename, unsigned *lineno,
|
||||
ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts);
|
||||
void usage( int level );
|
||||
const char *default_strusage( int level );
|
||||
|
||||
|
||||
/*-- (main program) --*/
|
||||
const char *strusage( int level );
|
||||
|
||||
|
||||
/*-- dotlock.c --*/
|
||||
struct dotlock_handle;
|
||||
typedef struct dotlock_handle *DOTLOCK;
|
||||
|
||||
void disable_dotlock(void);
|
||||
DOTLOCK create_dotlock( const char *file_to_lock );
|
||||
int make_dotlock( DOTLOCK h, long timeout );
|
||||
int release_dotlock( DOTLOCK h );
|
||||
void remove_lockfiles (void);
|
||||
|
||||
/*-- fileutil.c --*/
|
||||
char * make_basename(const char *filepath, const char *inputpath);
|
||||
char * make_dirname(const char *filepath);
|
||||
char *make_filename( const char *first_part, ... );
|
||||
int compare_filenames( const char *a, const char *b );
|
||||
const char *print_fname_stdin( const char *s );
|
||||
const char *print_fname_stdout( const char *s );
|
||||
int is_file_compressed(const char *s, int *r_status);
|
||||
|
||||
|
||||
/*-- miscutil.c --*/
|
||||
u32 make_timestamp(void);
|
||||
u32 scan_isodatestr( const char *string );
|
||||
u32 add_days_to_timestamp( u32 stamp, u16 days );
|
||||
const char *strtimevalue( u32 stamp );
|
||||
const char *strtimestamp( u32 stamp ); /* GMT */
|
||||
const char *asctimestamp( u32 stamp ); /* localized */
|
||||
void print_string( FILE *fp, const byte *p, size_t n, int delim );
|
||||
void print_utf8_string( FILE *fp, const byte *p, size_t n );
|
||||
void print_utf8_string2( FILE *fp, const byte *p, size_t n, int delim);
|
||||
char *make_printable_string( const byte *p, size_t n, int delim );
|
||||
int answer_is_yes_no_default( const char *s, int def_answer );
|
||||
int answer_is_yes( const char *s );
|
||||
int answer_is_yes_no_quit( const char *s );
|
||||
|
||||
/*-- strgutil.c --*/
|
||||
void free_strlist( STRLIST sl );
|
||||
#define FREE_STRLIST(a) do { free_strlist((a)); (a) = NULL ; } while(0)
|
||||
STRLIST add_to_strlist( STRLIST *list, const char *string );
|
||||
STRLIST add_to_strlist2( STRLIST *list, const char *string, int is_utf8 );
|
||||
STRLIST append_to_strlist( STRLIST *list, const char *string );
|
||||
STRLIST append_to_strlist2( STRLIST *list, const char *string, int is_utf8 );
|
||||
STRLIST strlist_prev( STRLIST head, STRLIST node );
|
||||
STRLIST strlist_last( STRLIST node );
|
||||
char *pop_strlist( STRLIST *list );
|
||||
const char *memistr( const char *buf, size_t buflen, const char *sub );
|
||||
const char *ascii_memistr( const char *buf, size_t buflen, const char *sub );
|
||||
char *mem2str( char *, const void *, size_t);
|
||||
char *trim_spaces( char *string );
|
||||
unsigned int trim_trailing_chars( byte *line, unsigned int len,
|
||||
const char *trimchars);
|
||||
unsigned int trim_trailing_ws( byte *line, unsigned len );
|
||||
unsigned int check_trailing_chars( const byte *line, unsigned int len,
|
||||
const char *trimchars );
|
||||
unsigned int check_trailing_ws( const byte *line, unsigned int len );
|
||||
int string_count_chr( const char *string, int c );
|
||||
int set_native_charset( const char *newset );
|
||||
const char* get_native_charset(void);
|
||||
char *native_to_utf8( const char *string );
|
||||
char *utf8_to_native( const char *string, size_t length, int delim);
|
||||
int check_utf8_string( const char *string );
|
||||
|
||||
int ascii_isupper (int c);
|
||||
int ascii_islower (int c);
|
||||
int ascii_toupper (int c);
|
||||
int ascii_tolower (int c);
|
||||
int ascii_strcasecmp( const char *a, const char *b );
|
||||
int ascii_strncasecmp( const char *a, const char *b, size_t n);
|
||||
int ascii_memcasecmp( const char *a, const char *b, size_t n);
|
||||
|
||||
#ifndef HAVE_STPCPY
|
||||
char *stpcpy(char *a,const char *b);
|
||||
#endif
|
||||
#ifndef HAVE_STRLWR
|
||||
char *strlwr(char *a);
|
||||
#endif
|
||||
#ifndef HAVE_STRSEP
|
||||
char *strsep (char **stringp, const char *delim);
|
||||
#endif
|
||||
#ifndef HAVE_STRCASECMP
|
||||
int strcasecmp( const char *, const char *b);
|
||||
#endif
|
||||
#ifndef HAVE_STRNCASECMP
|
||||
int strncasecmp (const char *, const char *b, size_t n);
|
||||
#endif
|
||||
#ifndef HAVE_STRTOUL
|
||||
#define strtoul(a,b,c) ((unsigned long)strtol((a),(b),(c)))
|
||||
#endif
|
||||
#ifndef HAVE_MEMMOVE
|
||||
#define memmove(d, s, n) bcopy((s), (d), (n))
|
||||
#endif
|
||||
|
||||
#if defined (__MINGW32__)
|
||||
/*-- w32reg.c --*/
|
||||
char *read_w32_registry_string( const char *root,
|
||||
const char *dir, const char *name );
|
||||
int write_w32_registry_string(const char *root, const char *dir,
|
||||
const char *name, const char *value);
|
||||
|
||||
/*-- strgutil.c --*/
|
||||
int vasprintf ( char **result, const char *format, va_list args);
|
||||
#endif
|
||||
|
||||
/**** other missing stuff ****/
|
||||
#ifndef HAVE_ATEXIT /* For SunOS */
|
||||
#define atexit(a) (on_exit((a),0))
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_RAISE
|
||||
#define raise(a) kill(getpid(), (a))
|
||||
#endif
|
||||
|
||||
/******** some macros ************/
|
||||
#ifndef STR
|
||||
#define STR(v) #v
|
||||
#endif
|
||||
#define STR2(v) STR(v)
|
||||
#define DIM(v) (sizeof(v)/sizeof((v)[0]))
|
||||
#define DIMof(type,member) DIM(((type *)0)->member)
|
||||
|
||||
#define wipememory2(_ptr,_set,_len) do { volatile char *_vptr=(volatile char *)(_ptr); size_t _vlen=(_len); while(_vlen) { *_vptr=(_set); _vptr++; _vlen--; } } while(0)
|
||||
#define wipememory(_ptr,_len) wipememory2(_ptr,0,_len)
|
||||
|
||||
/******* RISC OS stuff ***********/
|
||||
#ifdef __riscos__
|
||||
/* needed for strcasecmp() */
|
||||
#include <strings.h>
|
||||
/* needed for filename munging */
|
||||
#include <unixlib/local.h>
|
||||
/* needed for image file system feature */
|
||||
#include <unixlib/features.h>
|
||||
void riscos_global_defaults(void);
|
||||
#define RISCOS_GLOBAL_STATICS(a) const char *__dynamic_da_name = (a);
|
||||
int riscos_load_module(const char *name, const char * const path[], int fatal);
|
||||
int riscos_get_filetype_from_string(const char *string, int len);
|
||||
int riscos_get_filetype(const char *filename);
|
||||
void riscos_set_filetype_by_number(const char *filename, int type);
|
||||
void riscos_set_filetype_by_mimetype(const char *filename, const char *mimetype);
|
||||
pid_t riscos_getpid(void);
|
||||
int riscos_kill(pid_t pid, int sig);
|
||||
int riscos_access(const char *path, int amode);
|
||||
int riscos_getchar(void);
|
||||
char *riscos_make_basename(const char *filepath, const char *inputpath);
|
||||
int riscos_check_regexp(const char *exp, const char *string, int debug);
|
||||
int riscos_fdopenfile(const char *filename, const int allow_write);
|
||||
void riscos_close_fds(void);
|
||||
int riscos_renamefile(const char *old, const char *new);
|
||||
char *riscos_gstrans(const char *old);
|
||||
void riscos_not_implemented(const char *feature);
|
||||
#ifdef DEBUG
|
||||
void riscos_dump_fdlist(void);
|
||||
void riscos_list_openfiles(void);
|
||||
#endif
|
||||
#ifndef __RISCOS__C__
|
||||
#define getpid riscos_getpid
|
||||
#define kill(a,b) riscos_kill((a),(b))
|
||||
#define access(a,b) riscos_access((a),(b))
|
||||
#endif /* !__RISCOS__C__ */
|
||||
#endif /* __riscos__ */
|
||||
|
||||
#endif /*G10_UTIL_H*/
|
119
kbx/ChangeLog
Normal file
119
kbx/ChangeLog
Normal file
@ -0,0 +1,119 @@
|
||||
2003-06-03 Werner Koch <wk@gnupg.org>
|
||||
|
||||
Changed all error codes in all files to the new libgpg-error scheme.
|
||||
|
||||
* keybox-defs.h: Include gpg-error.h .
|
||||
(KeyboxError): Removed.
|
||||
* Makefile.am: Removed keybox-error.c stuff.
|
||||
|
||||
2002-11-14 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* keybox-search.c (blob_cmp_name) <compare all names>: Fixed
|
||||
length compare; there is no 0 stored since nearly a year.
|
||||
|
||||
2002-10-31 Neal H. Walfield <neal@g10code.de>
|
||||
|
||||
* Makefile.am (AM_CPPFLAGS): Fix ytpo.
|
||||
|
||||
2002-08-10 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* keybox-search.c (blob_cmp_fpr_part): New.
|
||||
(has_short_kid, has_long_kid): Implemented.
|
||||
|
||||
2002-07-22 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* keybox-defs.h: New BLOBTYPTE_EMPTY.
|
||||
* keybox-dump.c (_keybox_dump_blob): Handle new type.
|
||||
* keybox-file.c (_keybox_read_blob): Skip over empty blobs. Store
|
||||
the file offset.
|
||||
* keybox-blob.c (_keybox_new_blob): Add new arg OFF.
|
||||
(_keybox_get_blob_fileoffset): New.
|
||||
* keybox-update.c (keybox_delete): Implemented.
|
||||
|
||||
2002-06-19 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* keybox-init.c (keybox_set_ephemeral): New.
|
||||
* keybox-blob.c (create_blob_header): Store ephemeral flag.
|
||||
(_keybox_create_x509_blob): Pass epheermal flag on.
|
||||
* keybox-update.c (keybox_insert_cert): Ditto.
|
||||
* keybox-search.c (blob_get_blob_flags): New.
|
||||
(keybox_search): Ignore ephemeral blobs when not in ephemeral mode.
|
||||
|
||||
* keybox-dump.c (_keybox_dump_blob): Print blob flags as strings.
|
||||
|
||||
2002-02-25 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* keybox-search.c (blob_cmp_mail): Use case-insensitive compare
|
||||
because mail addresses are in general case insensitive (well
|
||||
RFC2822 allows for case sensitive mailbox parts, but this is in
|
||||
general considired a Bad Thing). Add additional substr parameter
|
||||
to allow for substring matches within the mail address. Change
|
||||
all callers to pass this along.
|
||||
(blob_cmp_name): Likewise but do the case-insensitive search only
|
||||
in sub string mode.
|
||||
(keybox_search): Implement MAILSUB and SUBSTR mode.
|
||||
|
||||
2002-01-21 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* keybox-search.c (keybox_search): Allow KEYDB_SEARCH_MODE_FPR20.
|
||||
|
||||
2002-01-15 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* keybox-search.c (blob_cmp_fpr): New.
|
||||
(has_fingerprint): Implemented;
|
||||
|
||||
2001-12-20 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* keybox-blob.c (_keybox_create_x509_blob): Skip the leading
|
||||
parenthesis of the serial number's S-exp.
|
||||
(_keybox_create_x509_blob): And fixed length calculation.
|
||||
(create_blob_header): Don't add an offset when writing the serial.
|
||||
|
||||
2001-12-18 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* Makefile.am (AM_CPPFLAGS): Add flags for libksba
|
||||
|
||||
* keybox-blob.c (_keybox_create_x509_blob): Use
|
||||
gcry_sexp_canon_len to get the length of the serial number.
|
||||
(_keybox_release_blob): Need to use a new serialbuf to free the memory.
|
||||
|
||||
2001-12-17 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* keybox-search.c: Changed the way the serial number is
|
||||
represented.
|
||||
|
||||
2001-12-15 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* keybox-search.c (blob_cmp_name): There is no terminating 0 stored
|
||||
for the uid; fixed length compare.
|
||||
|
||||
2001-12-14 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* keybox-blob.c (x509_email_kludge): New.
|
||||
(_keybox_create_x509_blob): Insert an extra email address if the
|
||||
subject's DN has an email part.
|
||||
* keybox-defs.h: Added the xtoi_2 and digitp macros.
|
||||
|
||||
2001-12-13 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* keybox-search.c (blob_cmp_name): Kludge to allow searching for
|
||||
more than one name.
|
||||
(has_subject_or_alt): New.
|
||||
(blob_cmp_mail): New.
|
||||
(has_mail): New.
|
||||
(keybox_search): Implemented exact search and exact mail search.
|
||||
|
||||
* kbx/keybox-blob.c (_keybox_create_x509_blob): Insert alternate
|
||||
names.
|
||||
|
||||
|
||||
Copyright 2001 g10 Code GmbH
|
||||
|
||||
This file is free software; as a special exception the author gives
|
||||
unlimited permission to copy and/or distribute it, with or without
|
||||
modifications, as long as this notice is preserved.
|
||||
|
||||
This file is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
186
kbx/keybox-defs.h
Normal file
186
kbx/keybox-defs.h
Normal file
@ -0,0 +1,186 @@
|
||||
/* keybox-defs.h - interal Keybox defintions
|
||||
* Copyright (C) 2001 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef KEYBOX_DEFS_H
|
||||
#define KEYBOX_DEFS_H 1
|
||||
|
||||
#include <sys/types.h> /* off_t */
|
||||
#include "keybox.h"
|
||||
|
||||
#ifdef GPG_ERR_SOURCE_DEFAULT
|
||||
#error GPG_ERR_SOURCE_DEFAULT already defined
|
||||
#endif
|
||||
#define GPG_ERR_SOURCE_DEFAULT GPG_ERR_SOURCE_KEYBOX
|
||||
#include <gpg-error.h>
|
||||
|
||||
|
||||
#ifndef HAVE_BYTE_TYPEDEF
|
||||
typedef unsigned char byte; /* fixme */
|
||||
#endif
|
||||
#ifndef HAVE_U16_TYPEDEF
|
||||
typedef unsigned short u16; /* fixme */
|
||||
#endif
|
||||
#ifndef HAVE_U32_TYPEDEF
|
||||
typedef unsigned int u32; /* fixme */
|
||||
#endif
|
||||
|
||||
enum {
|
||||
BLOBTYPE_EMPTY = 0,
|
||||
BLOBTYPE_HEADER = 1,
|
||||
BLOBTYPE_PGP = 2,
|
||||
BLOBTYPE_X509 = 3
|
||||
};
|
||||
|
||||
|
||||
typedef struct keyboxblob *KEYBOXBLOB;
|
||||
|
||||
|
||||
typedef struct keybox_name *KB_NAME;
|
||||
typedef struct keybox_name const * CONST_KB_NAME;
|
||||
struct keybox_name {
|
||||
struct keybox_name *next;
|
||||
int secret;
|
||||
/*DOTLOCK lockhd;*/
|
||||
int is_locked;
|
||||
int did_full_scan;
|
||||
char fname[1];
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct keybox_handle {
|
||||
CONST_KB_NAME kb;
|
||||
int secret; /* this is for a secret keybox */
|
||||
FILE *fp;
|
||||
int eof;
|
||||
int error;
|
||||
int ephemeral;
|
||||
struct {
|
||||
KEYBOXBLOB blob;
|
||||
off_t offset;
|
||||
size_t pk_no;
|
||||
size_t uid_no;
|
||||
unsigned int n_packets; /*used for delete and update*/
|
||||
} found;
|
||||
struct {
|
||||
char *name;
|
||||
char *pattern;
|
||||
} word_match;
|
||||
};
|
||||
|
||||
|
||||
/* Don't know whether this is needed: */
|
||||
/* static struct { */
|
||||
/* const char *homedir; */
|
||||
/* int dry_run; */
|
||||
/* int quiet; */
|
||||
/* int verbose; */
|
||||
/* int preserve_permissions; */
|
||||
/* } keybox_opt; */
|
||||
|
||||
|
||||
/*-- keybox-blob.c --*/
|
||||
#ifdef KEYBOX_WITH_OPENPGP
|
||||
/* fixme */
|
||||
#endif /*KEYBOX_WITH_OPENPGP*/
|
||||
#ifdef KEYBOX_WITH_X509
|
||||
int _keybox_create_x509_blob (KEYBOXBLOB *r_blob, KsbaCert cert,
|
||||
unsigned char *sha1_digest, int as_ephemeral);
|
||||
#endif /*KEYBOX_WITH_X509*/
|
||||
|
||||
int _keybox_new_blob (KEYBOXBLOB *r_blob, char *image, size_t imagelen,
|
||||
off_t off);
|
||||
void _keybox_release_blob (KEYBOXBLOB blob);
|
||||
const char *_keybox_get_blob_image (KEYBOXBLOB blob, size_t *n);
|
||||
off_t _keybox_get_blob_fileoffset (KEYBOXBLOB blob);
|
||||
|
||||
/*-- keybox-file.c --*/
|
||||
int _keybox_read_blob (KEYBOXBLOB *r_blob, FILE *fp);
|
||||
int _keybox_write_blob (KEYBOXBLOB blob, FILE *fp);
|
||||
|
||||
/*-- keybox-dump.c --*/
|
||||
int _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp);
|
||||
int _keybox_dump_file (const char *filename, FILE *outfp);
|
||||
|
||||
|
||||
/*-- keybox-util.c --*/
|
||||
void *_keybox_malloc (size_t n);
|
||||
void *_keybox_calloc (size_t n, size_t m);
|
||||
void *_keybox_realloc (void *p, size_t n);
|
||||
void _keybox_free (void *p);
|
||||
|
||||
#define xtrymalloc(a) _keybox_malloc ((a))
|
||||
#define xtrycalloc(a,b) _keybox_calloc ((a),(b))
|
||||
#define xtryrealloc(a,b) _keybox_realloc((a),(b))
|
||||
#define xfree(a) _keybox_free ((a))
|
||||
|
||||
|
||||
#define DIM(v) (sizeof(v)/sizeof((v)[0]))
|
||||
#define DIMof(type,member) DIM(((type *)0)->member)
|
||||
#ifndef STR
|
||||
#define STR(v) #v
|
||||
#endif
|
||||
#define STR2(v) STR(v)
|
||||
|
||||
/*
|
||||
a couple of handy macros
|
||||
*/
|
||||
|
||||
#define return_if_fail(expr) do { \
|
||||
if (!(expr)) { \
|
||||
fprintf (stderr, "%s:%d: assertion `%s' failed\n", \
|
||||
__FILE__, __LINE__, #expr ); \
|
||||
return; \
|
||||
} } while (0)
|
||||
#define return_null_if_fail(expr) do { \
|
||||
if (!(expr)) { \
|
||||
fprintf (stderr, "%s:%d: assertion `%s' failed\n", \
|
||||
__FILE__, __LINE__, #expr ); \
|
||||
return NULL; \
|
||||
} } while (0)
|
||||
#define return_val_if_fail(expr,val) do { \
|
||||
if (!(expr)) { \
|
||||
fprintf (stderr, "%s:%d: assertion `%s' failed\n", \
|
||||
__FILE__, __LINE__, #expr ); \
|
||||
return (val); \
|
||||
} } while (0)
|
||||
#define never_reached() do { \
|
||||
fprintf (stderr, "%s:%d: oops; should never get here\n", \
|
||||
__FILE__, __LINE__ ); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/* some macros to replace ctype ones and avoid locale problems */
|
||||
#define digitp(p) (*(p) >= '0' && *(p) <= '9')
|
||||
#define hexdigitp(a) (digitp (a) \
|
||||
|| (*(a) >= 'A' && *(a) <= 'F') \
|
||||
|| (*(a) >= 'a' && *(a) <= 'f'))
|
||||
/* the atoi macros assume that the buffer has only valid digits */
|
||||
#define atoi_1(p) (*(p) - '0' )
|
||||
#define atoi_2(p) ((atoi_1(p) * 10) + atoi_1((p)+1))
|
||||
#define atoi_4(p) ((atoi_2(p) * 100) + atoi_2((p)+2))
|
||||
#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
|
||||
*(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
|
||||
#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
|
||||
|
||||
|
||||
#endif /*KEYBOX_DEFS_H*/
|
||||
|
||||
|
346
kbx/keybox-dump.c
Normal file
346
kbx/keybox-dump.c
Normal file
@ -0,0 +1,346 @@
|
||||
/* keybox-dump.c - Debug helpers
|
||||
* Copyright (C) 2001, 2003 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "keybox-defs.h"
|
||||
|
||||
static ulong
|
||||
get32 (const byte *buffer)
|
||||
{
|
||||
ulong a;
|
||||
a = *buffer << 24;
|
||||
a |= buffer[1] << 16;
|
||||
a |= buffer[2] << 8;
|
||||
a |= buffer[3];
|
||||
return a;
|
||||
}
|
||||
|
||||
static ulong
|
||||
get16 (const byte *buffer)
|
||||
{
|
||||
ulong a;
|
||||
a = *buffer << 8;
|
||||
a |= buffer[1];
|
||||
return a;
|
||||
}
|
||||
|
||||
void
|
||||
print_string (FILE *fp, const byte *p, size_t n, int delim)
|
||||
{
|
||||
for ( ; n; n--, p++ )
|
||||
{
|
||||
if (*p < 0x20 || (*p >= 0x7f && *p < 0xa0) || *p == delim)
|
||||
{
|
||||
putc('\\', fp);
|
||||
if( *p == '\n' )
|
||||
putc('n', fp);
|
||||
else if( *p == '\r' )
|
||||
putc('r', fp);
|
||||
else if( *p == '\f' )
|
||||
putc('f', fp);
|
||||
else if( *p == '\v' )
|
||||
putc('v', fp);
|
||||
else if( *p == '\b' )
|
||||
putc('b', fp);
|
||||
else if( !*p )
|
||||
putc('0', fp);
|
||||
else
|
||||
fprintf(fp, "x%02x", *p );
|
||||
}
|
||||
else
|
||||
putc(*p, fp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
dump_header_blob (const byte *buffer, size_t length, FILE *fp)
|
||||
{
|
||||
fprintf (fp, "Version: %d\n", buffer[5]);
|
||||
if ( memcmp (buffer+8, "KBXf", 4))
|
||||
fprintf (fp, "[Error: invalid magic number]\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Dump one block to FP */
|
||||
int
|
||||
_keybox_dump_blob (KEYBOXBLOB blob, FILE *fp)
|
||||
{
|
||||
const byte *buffer;
|
||||
size_t length;
|
||||
int type;
|
||||
ulong n, nkeys, keyinfolen;
|
||||
ulong nuids, uidinfolen;
|
||||
ulong nsigs, siginfolen;
|
||||
ulong rawdata_off, rawdata_len;
|
||||
ulong nserial;
|
||||
const byte *p;
|
||||
|
||||
buffer = _keybox_get_blob_image (blob, &length);
|
||||
|
||||
if (length < 40)
|
||||
{
|
||||
fprintf (fp, "[blob too short]\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
n = get32( buffer );
|
||||
if (n > length)
|
||||
fprintf (fp, "[blob larger than length - output truncated]\n");
|
||||
else
|
||||
length = n; /* ignore the rest */
|
||||
|
||||
fprintf (fp, "Length: %lu\n", n );
|
||||
type = buffer[4];
|
||||
switch (type)
|
||||
{
|
||||
case BLOBTYPE_EMPTY:
|
||||
fprintf (fp, "Type: Empty\n");
|
||||
return 0;
|
||||
|
||||
case BLOBTYPE_HEADER:
|
||||
fprintf (fp, "Type: Header\n");
|
||||
return dump_header_blob (buffer, length, fp);
|
||||
case BLOBTYPE_PGP:
|
||||
fprintf (fp, "Type: OpenPGP\n");
|
||||
break;
|
||||
case BLOBTYPE_X509:
|
||||
fprintf (fp, "Type: X.509\n");
|
||||
break;
|
||||
default:
|
||||
fprintf (fp, "Type: %d\n", type);
|
||||
fprintf (fp, "[can't dump this blob type]\n");
|
||||
return 0;
|
||||
}
|
||||
fprintf (fp, "Version: %d\n", buffer[5]);
|
||||
|
||||
n = get16 (buffer + 6);
|
||||
fprintf( fp, "Blob-Flags: %04lX", n);
|
||||
if (n)
|
||||
{
|
||||
int any = 0;
|
||||
|
||||
fputs (" (", fp);
|
||||
if ((n & 1))
|
||||
{
|
||||
fputs ("secret", fp);
|
||||
any++;
|
||||
}
|
||||
if ((n & 2))
|
||||
{
|
||||
if (any)
|
||||
putc (',', fp);
|
||||
fputs ("ephemeral", fp);
|
||||
any++;
|
||||
}
|
||||
putc (')', fp);
|
||||
}
|
||||
putc ('\n', fp);
|
||||
|
||||
rawdata_off = get32 (buffer + 8);
|
||||
rawdata_len = get32 (buffer + 12);
|
||||
|
||||
fprintf( fp, "Data-Offset: %lu\n", rawdata_off );
|
||||
fprintf( fp, "Data-Length: %lu\n", rawdata_len );
|
||||
|
||||
nkeys = get16 (buffer + 16);
|
||||
fprintf (fp, "Key-Count: %lu\n", nkeys );
|
||||
if (!nkeys)
|
||||
fprintf (fp, "[Error: no keys]\n");
|
||||
if (nkeys > 1 && type == BLOBTYPE_X509)
|
||||
fprintf (fp, "[Error: only one key allowed for X509]\n");
|
||||
|
||||
keyinfolen = get16 (buffer + 18 );
|
||||
fprintf (fp, "Key-Info-Length: %lu\n", keyinfolen);
|
||||
/* fixme: check bounds */
|
||||
p = buffer + 20;
|
||||
for (n=0; n < nkeys; n++, p += keyinfolen)
|
||||
{
|
||||
int i;
|
||||
ulong kidoff, kflags;
|
||||
|
||||
fprintf (fp, "Key-Fpr[%lu]: ", n );
|
||||
for (i=0; i < 20; i++ )
|
||||
fprintf (fp, "%02X", p[i]);
|
||||
kidoff = get32 (p + 20);
|
||||
fprintf (fp, "\nKey-Kid-Off[%lu]: %lu\n", n, kidoff );
|
||||
fprintf (fp, "Key-Kid[%lu]: ", n );
|
||||
/* fixme: check bounds */
|
||||
for (i=0; i < 8; i++ )
|
||||
fprintf (fp, "%02X", buffer[kidoff+i] );
|
||||
kflags = get16 (p + 24 );
|
||||
fprintf( fp, "\nKey-Flags[%lu]: %04lX\n", n, kflags);
|
||||
}
|
||||
|
||||
/* serial number */
|
||||
fputs ("Serial-No: ", fp);
|
||||
nserial = get16 (p);
|
||||
p += 2;
|
||||
if (!nserial)
|
||||
fputs ("none", fp);
|
||||
else
|
||||
{
|
||||
for (; nserial; nserial--, p++)
|
||||
fprintf (fp, "%02X", *p);
|
||||
}
|
||||
putc ('\n', fp);
|
||||
|
||||
/* user IDs */
|
||||
nuids = get16 (p);
|
||||
fprintf (fp, "Uid-Count: %lu\n", nuids );
|
||||
uidinfolen = get16 (p + 2);
|
||||
fprintf (fp, "Uid-Info-Length: %lu\n", uidinfolen);
|
||||
/* fixme: check bounds */
|
||||
p += 4;
|
||||
for (n=0; n < nuids; n++, p += uidinfolen)
|
||||
{
|
||||
ulong uidoff, uidlen, uflags;
|
||||
|
||||
uidoff = get32( p );
|
||||
uidlen = get32( p+4 );
|
||||
if (type == BLOBTYPE_X509 && !n)
|
||||
{
|
||||
fprintf (fp, "Issuer-Off: %lu\n", uidoff );
|
||||
fprintf (fp, "Issuer-Len: %lu\n", uidlen );
|
||||
fprintf (fp, "Issuer: \"");
|
||||
}
|
||||
else if (type == BLOBTYPE_X509 && n == 1)
|
||||
{
|
||||
fprintf (fp, "Subject-Off: %lu\n", uidoff );
|
||||
fprintf (fp, "Subject-Len: %lu\n", uidlen );
|
||||
fprintf (fp, "Subject: \"");
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (fp, "Uid-Off[%lu]: %lu\n", n, uidoff );
|
||||
fprintf (fp, "Uid-Len[%lu]: %lu\n", n, uidlen );
|
||||
fprintf (fp, "Uid[%lu]: \"", n );
|
||||
}
|
||||
print_string (fp, buffer+uidoff, uidlen, '\"');
|
||||
fputs ("\"\n", fp);
|
||||
uflags = get16 (p + 8);
|
||||
if (type == BLOBTYPE_X509 && !n)
|
||||
{
|
||||
fprintf (fp, "Issuer-Flags: %04lX\n", uflags );
|
||||
fprintf (fp, "Issuer-Validity: %d\n", p[10] );
|
||||
}
|
||||
else if (type == BLOBTYPE_X509 && n == 1)
|
||||
{
|
||||
fprintf (fp, "Subject-Flags: %04lX\n", uflags );
|
||||
fprintf (fp, "Subject-Validity: %d\n", p[10] );
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (fp, "Uid-Flags[%lu]: %04lX\n", n, uflags );
|
||||
fprintf (fp, "Uid-Validity[%lu]: %d\n", n, p[10] );
|
||||
}
|
||||
}
|
||||
|
||||
nsigs = get16 (p);
|
||||
fprintf (fp, "Sig-Count: %lu\n", nsigs );
|
||||
siginfolen = get16 (p + 2);
|
||||
fprintf (fp, "Sig-Info-Length: %lu\n", siginfolen );
|
||||
/* fixme: check bounds */
|
||||
p += 4;
|
||||
for (n=0; n < nsigs; n++, p += siginfolen)
|
||||
{
|
||||
ulong sflags;
|
||||
|
||||
sflags = get32 (p);
|
||||
fprintf (fp, "Sig-Expire[%lu]: ", n );
|
||||
if (!sflags)
|
||||
fputs ("[not checked]", fp);
|
||||
else if (sflags == 1 )
|
||||
fputs ("[missing key]", fp);
|
||||
else if (sflags == 2 )
|
||||
fputs ("[bad signature]", fp);
|
||||
else if (sflags < 0x10000000)
|
||||
fprintf (fp, "[bad flag %0lx]", sflags);
|
||||
else if (sflags == 0xffffffff)
|
||||
fputs ("0", fp );
|
||||
else
|
||||
fputs ("a time"/*strtimestamp( sflags )*/, fp );
|
||||
putc ('\n', fp );
|
||||
}
|
||||
|
||||
fprintf (fp, "Ownertrust: %d\n", p[0] );
|
||||
fprintf (fp, "All-Validity: %d\n", p[1] );
|
||||
p += 4;
|
||||
n = get32 (p); p += 4;
|
||||
fprintf (fp, "Recheck-After: %s\n", /*n? strtimestamp(n) :*/ "0" );
|
||||
n = get32 (p ); p += 4;
|
||||
fprintf( fp, "Latest-Timestamp: %s\n", "0"/*strtimestamp(n)*/ );
|
||||
n = get32 (p ); p += 4;
|
||||
fprintf (fp, "Created-At: %s\n", "0"/*strtimestamp(n)*/ );
|
||||
n = get32 (p ); p += 4;
|
||||
fprintf (fp, "Reserved-Space: %lu\n", n );
|
||||
|
||||
/* check that the keyblock is at the correct offset and other bounds */
|
||||
/*fprintf (fp, "Blob-Checksum: [MD5-hash]\n");*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
_keybox_dump_file (const char *filename, FILE *outfp)
|
||||
{
|
||||
FILE *fp;
|
||||
KEYBOXBLOB blob;
|
||||
int rc;
|
||||
unsigned long count = 0;
|
||||
|
||||
if (!filename)
|
||||
{
|
||||
filename = "-";
|
||||
fp = stdin;
|
||||
}
|
||||
else
|
||||
fp = fopen (filename, "rb");
|
||||
if (!fp)
|
||||
{
|
||||
gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
|
||||
fprintf (outfp, "can't open `%s': %s\n", filename, strerror(errno));
|
||||
return tmperr;
|
||||
}
|
||||
|
||||
while ( !(rc = _keybox_read_blob (&blob, fp)) )
|
||||
{
|
||||
fprintf (outfp, "BEGIN-RECORD: %lu\n", count );
|
||||
_keybox_dump_blob (blob, outfp);
|
||||
_keybox_release_blob (blob);
|
||||
fprintf (outfp, "END-RECORD\n");
|
||||
count++;
|
||||
}
|
||||
if (rc == -1)
|
||||
rc = 0;
|
||||
if (rc)
|
||||
fprintf (outfp, "error reading `%s': %s\n", filename, gpg_strerror (rc));
|
||||
|
||||
if (fp != stdin)
|
||||
fclose (fp);
|
||||
return rc;
|
||||
}
|
102
kbx/keybox-file.c
Normal file
102
kbx/keybox-file.c
Normal file
@ -0,0 +1,102 @@
|
||||
/* keybox-file.c - file oeprations
|
||||
* Copyright (C) 2001, 2003 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "keybox-defs.h"
|
||||
|
||||
/* Read a block at the current postion and return it in r_blob.
|
||||
r_blob may be NULL to simply skip the current block */
|
||||
int
|
||||
_keybox_read_blob (KEYBOXBLOB *r_blob, FILE *fp)
|
||||
{
|
||||
char *image;
|
||||
size_t imagelen = 0;
|
||||
int c1, c2, c3, c4, type;
|
||||
int rc;
|
||||
off_t off;
|
||||
|
||||
again:
|
||||
*r_blob = NULL;
|
||||
off = ftello (fp);
|
||||
if (off == (off_t)-1)
|
||||
return gpg_error (gpg_err_code_from_errno (errno));
|
||||
|
||||
if ((c1 = getc (fp)) == EOF
|
||||
|| (c2 = getc (fp)) == EOF
|
||||
|| (c3 = getc (fp)) == EOF
|
||||
|| (c4 = getc (fp)) == EOF
|
||||
|| (type = getc (fp)) == EOF)
|
||||
{
|
||||
if ( c1 == EOF && !ferror (fp) )
|
||||
return -1; /* eof */
|
||||
return gpg_error (gpg_err_code_from_errno (errno));
|
||||
}
|
||||
|
||||
imagelen = (c1 << 24) | (c2 << 16) | (c3 << 8 ) | c4;
|
||||
if (imagelen > 500000) /* sanity check */
|
||||
return gpg_error (GPG_ERR_TOO_LARGE);
|
||||
|
||||
if (imagelen < 5)
|
||||
return gpg_error (GPG_ERR_TOO_SHORT);
|
||||
|
||||
if (!type)
|
||||
{
|
||||
/* special treatment for empty blobs. */
|
||||
if (fseek (fp, imagelen-5, SEEK_CUR))
|
||||
return gpg_error (gpg_err_code_from_errno (errno));
|
||||
goto again;
|
||||
}
|
||||
|
||||
image = xtrymalloc (imagelen);
|
||||
if (!image)
|
||||
return gpg_error (gpg_err_code_from_errno (errno));
|
||||
|
||||
image[0] = c1; image[1] = c2; image[2] = c3; image[3] = c4; image[4] = type;
|
||||
if (fread (image+5, imagelen-5, 1, fp) != 1)
|
||||
{
|
||||
gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
|
||||
xfree (image);
|
||||
return tmperr;
|
||||
}
|
||||
|
||||
rc = r_blob? _keybox_new_blob (r_blob, image, imagelen, off) : 0;
|
||||
if (rc || !r_blob)
|
||||
xfree (image);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* Write the block to the current file position */
|
||||
int
|
||||
_keybox_write_blob (KEYBOXBLOB blob, FILE *fp)
|
||||
{
|
||||
const char *image;
|
||||
size_t length;
|
||||
|
||||
image = _keybox_get_blob_image (blob, &length);
|
||||
if (fwrite (image, length, 1, fp) != 1)
|
||||
return gpg_error (gpg_err_code_from_errno (errno));
|
||||
return 0;
|
||||
}
|
127
kbx/keybox-init.c
Normal file
127
kbx/keybox-init.c
Normal file
@ -0,0 +1,127 @@
|
||||
/* keybox-init.c - Initalization of the library
|
||||
* Copyright (C) 2001 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "keybox-defs.h"
|
||||
|
||||
#define compare_filenames strcmp
|
||||
|
||||
static KB_NAME kb_names;
|
||||
|
||||
|
||||
/*
|
||||
Register a filename for plain keybox files. Returns a pointer to be
|
||||
used to create a handles etc or NULL to indicate that it has already
|
||||
been registered */
|
||||
void *
|
||||
keybox_register_file (const char *fname, int secret)
|
||||
{
|
||||
KB_NAME kr;
|
||||
|
||||
for (kr=kb_names; kr; kr = kr->next)
|
||||
{
|
||||
if ( !compare_filenames (kr->fname, fname) )
|
||||
return NULL; /* already registered */
|
||||
}
|
||||
|
||||
kr = xtrymalloc (sizeof *kr + strlen (fname));
|
||||
if (!kr)
|
||||
return NULL;
|
||||
strcpy (kr->fname, fname);
|
||||
kr->secret = !!secret;
|
||||
/* kr->lockhd = NULL;*/
|
||||
kr->is_locked = 0;
|
||||
kr->did_full_scan = 0;
|
||||
/* keep a list of all issued pointers */
|
||||
kr->next = kb_names;
|
||||
kb_names = kr;
|
||||
|
||||
/* create the offset table the first time a function here is used */
|
||||
/* if (!kb_offtbl) */
|
||||
/* kb_offtbl = new_offset_hash_table (); */
|
||||
|
||||
return kr;
|
||||
}
|
||||
|
||||
int
|
||||
keybox_is_writable (void *token)
|
||||
{
|
||||
KB_NAME r = token;
|
||||
|
||||
return r? !access (r->fname, W_OK) : 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Create a new handle for the resource associated with TOKEN. SECRET
|
||||
is just a cross-check.
|
||||
|
||||
The returned handle must be released using keybox_release (). */
|
||||
KEYBOX_HANDLE
|
||||
keybox_new (void *token, int secret)
|
||||
{
|
||||
KEYBOX_HANDLE hd;
|
||||
KB_NAME resource = token;
|
||||
|
||||
assert (resource && !resource->secret == !secret);
|
||||
hd = xtrycalloc (1, sizeof *hd);
|
||||
if (hd)
|
||||
{
|
||||
hd->kb = resource;
|
||||
hd->secret = !!secret;
|
||||
}
|
||||
return hd;
|
||||
}
|
||||
|
||||
void
|
||||
keybox_release (KEYBOX_HANDLE hd)
|
||||
{
|
||||
if (!hd)
|
||||
return;
|
||||
_keybox_release_blob (hd->found.blob);
|
||||
xfree (hd->word_match.name);
|
||||
xfree (hd->word_match.pattern);
|
||||
xfree (hd);
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
keybox_get_resource_name (KEYBOX_HANDLE hd)
|
||||
{
|
||||
if (!hd || !hd->kb)
|
||||
return NULL;
|
||||
return hd->kb->fname;
|
||||
}
|
||||
|
||||
int
|
||||
keybox_set_ephemeral (KEYBOX_HANDLE hd, int yes)
|
||||
{
|
||||
if (!hd)
|
||||
return gpg_error (GPG_ERR_INV_HANDLE);
|
||||
hd->ephemeral = yes;
|
||||
return 0;
|
||||
}
|
||||
|
813
kbx/keybox-search.c
Normal file
813
kbx/keybox-search.c
Normal file
@ -0,0 +1,813 @@
|
||||
/* keybox-search.c - Search operations
|
||||
* Copyright (C) 2001, 2002, 2003 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "../jnlib/stringhelp.h" /* ascii_xxxx() */
|
||||
#include "keybox-defs.h"
|
||||
|
||||
#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
|
||||
*(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
|
||||
#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
|
||||
|
||||
struct sn_array_s {
|
||||
int snlen;
|
||||
unsigned char *sn;
|
||||
};
|
||||
|
||||
|
||||
|
||||
static ulong
|
||||
get32 (const byte *buffer)
|
||||
{
|
||||
ulong a;
|
||||
a = *buffer << 24;
|
||||
a |= buffer[1] << 16;
|
||||
a |= buffer[2] << 8;
|
||||
a |= buffer[3];
|
||||
return a;
|
||||
}
|
||||
|
||||
static ulong
|
||||
get16 (const byte *buffer)
|
||||
{
|
||||
ulong a;
|
||||
a = *buffer << 8;
|
||||
a |= buffer[1];
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int
|
||||
blob_get_type (KEYBOXBLOB blob)
|
||||
{
|
||||
const unsigned char *buffer;
|
||||
size_t length;
|
||||
|
||||
buffer = _keybox_get_blob_image (blob, &length);
|
||||
if (length < 40)
|
||||
return -1; /* blob too short */
|
||||
|
||||
return buffer[4];
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
blob_get_blob_flags (KEYBOXBLOB blob)
|
||||
{
|
||||
const unsigned char *buffer;
|
||||
size_t length;
|
||||
|
||||
buffer = _keybox_get_blob_image (blob, &length);
|
||||
if (length < 8)
|
||||
return 0; /* oops */
|
||||
|
||||
return get16 (buffer + 6);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
blob_cmp_sn (KEYBOXBLOB blob, const unsigned char *sn, int snlen)
|
||||
{
|
||||
const unsigned char *buffer;
|
||||
size_t length;
|
||||
size_t pos, off;
|
||||
size_t nkeys, keyinfolen;
|
||||
size_t nserial;
|
||||
|
||||
buffer = _keybox_get_blob_image (blob, &length);
|
||||
if (length < 40)
|
||||
return 0; /* blob too short */
|
||||
|
||||
/*keys*/
|
||||
nkeys = get16 (buffer + 16);
|
||||
keyinfolen = get16 (buffer + 18 );
|
||||
if (keyinfolen < 28)
|
||||
return 0; /* invalid blob */
|
||||
pos = 20 + keyinfolen*nkeys;
|
||||
if (pos+2 > length)
|
||||
return 0; /* out of bounds */
|
||||
|
||||
/*serial*/
|
||||
nserial = get16 (buffer+pos);
|
||||
off = pos + 2;
|
||||
if (off+nserial > length)
|
||||
return 0; /* out of bounds */
|
||||
|
||||
return nserial == snlen && !memcmp (buffer+off, sn, snlen);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
blob_cmp_fpr (KEYBOXBLOB blob, const unsigned char *fpr)
|
||||
{
|
||||
const unsigned char *buffer;
|
||||
size_t length;
|
||||
size_t pos, off;
|
||||
size_t nkeys, keyinfolen;
|
||||
int idx;
|
||||
|
||||
buffer = _keybox_get_blob_image (blob, &length);
|
||||
if (length < 40)
|
||||
return 0; /* blob too short */
|
||||
|
||||
/*keys*/
|
||||
nkeys = get16 (buffer + 16);
|
||||
keyinfolen = get16 (buffer + 18 );
|
||||
if (keyinfolen < 28)
|
||||
return 0; /* invalid blob */
|
||||
pos = 20;
|
||||
if (pos + keyinfolen*nkeys > length)
|
||||
return 0; /* out of bounds */
|
||||
|
||||
for (idx=0; idx < nkeys; idx++)
|
||||
{
|
||||
off = pos + idx*keyinfolen;
|
||||
if (!memcmp (buffer + off, fpr, 20))
|
||||
return 1; /* found */
|
||||
}
|
||||
return 0; /* not found */
|
||||
}
|
||||
|
||||
static int
|
||||
blob_cmp_fpr_part (KEYBOXBLOB blob, const unsigned char *fpr,
|
||||
int fproff, int fprlen)
|
||||
{
|
||||
const unsigned char *buffer;
|
||||
size_t length;
|
||||
size_t pos, off;
|
||||
size_t nkeys, keyinfolen;
|
||||
int idx;
|
||||
|
||||
buffer = _keybox_get_blob_image (blob, &length);
|
||||
if (length < 40)
|
||||
return 0; /* blob too short */
|
||||
|
||||
/*keys*/
|
||||
nkeys = get16 (buffer + 16);
|
||||
keyinfolen = get16 (buffer + 18 );
|
||||
if (keyinfolen < 28)
|
||||
return 0; /* invalid blob */
|
||||
pos = 20;
|
||||
if (pos + keyinfolen*nkeys > length)
|
||||
return 0; /* out of bounds */
|
||||
|
||||
for (idx=0; idx < nkeys; idx++)
|
||||
{
|
||||
off = pos + idx*keyinfolen;
|
||||
if (!memcmp (buffer + off + fproff, fpr, fprlen))
|
||||
return 1; /* found */
|
||||
}
|
||||
return 0; /* not found */
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
blob_cmp_name (KEYBOXBLOB blob, int idx,
|
||||
const char *name, size_t namelen, int substr)
|
||||
{
|
||||
const unsigned char *buffer;
|
||||
size_t length;
|
||||
size_t pos, off, len;
|
||||
size_t nkeys, keyinfolen;
|
||||
size_t nuids, uidinfolen;
|
||||
size_t nserial;
|
||||
|
||||
buffer = _keybox_get_blob_image (blob, &length);
|
||||
if (length < 40)
|
||||
return 0; /* blob too short */
|
||||
|
||||
/*keys*/
|
||||
nkeys = get16 (buffer + 16);
|
||||
keyinfolen = get16 (buffer + 18 );
|
||||
if (keyinfolen < 28)
|
||||
return 0; /* invalid blob */
|
||||
pos = 20 + keyinfolen*nkeys;
|
||||
if (pos+2 > length)
|
||||
return 0; /* out of bounds */
|
||||
|
||||
/*serial*/
|
||||
nserial = get16 (buffer+pos);
|
||||
pos += 2 + nserial;
|
||||
if (pos+4 > length)
|
||||
return 0; /* out of bounds */
|
||||
|
||||
/* user ids*/
|
||||
nuids = get16 (buffer + pos); pos += 2;
|
||||
uidinfolen = get16 (buffer + pos); pos += 2;
|
||||
if (uidinfolen < 12 /* should add a: || nuidinfolen > MAX_UIDINFOLEN */)
|
||||
return 0; /* invalid blob */
|
||||
if (pos + uidinfolen*nuids > length)
|
||||
return 0; /* out of bounds */
|
||||
|
||||
if (idx < 0)
|
||||
{ /* compare all names starting with that (negated) index */
|
||||
idx = -idx;
|
||||
|
||||
for ( ;idx < nuids; idx++)
|
||||
{
|
||||
size_t mypos = pos;
|
||||
|
||||
mypos += idx*uidinfolen;
|
||||
off = get32 (buffer+mypos);
|
||||
len = get32 (buffer+mypos+4);
|
||||
if (off+len > length)
|
||||
return 0; /* error: better stop here out of bounds */
|
||||
if (len < 1)
|
||||
continue; /* empty name */
|
||||
if (substr)
|
||||
{
|
||||
if (ascii_memcasemem (buffer+off, len, name, namelen))
|
||||
return 1; /* found */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (len == namelen && !memcmp (buffer+off, name, len))
|
||||
return 1; /* found */
|
||||
}
|
||||
}
|
||||
return 0; /* not found */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (idx > nuids)
|
||||
return 0; /* no user ID with that idx */
|
||||
pos += idx*uidinfolen;
|
||||
off = get32 (buffer+pos);
|
||||
len = get32 (buffer+pos+4);
|
||||
if (off+len > length)
|
||||
return 0; /* out of bounds */
|
||||
if (len < 1)
|
||||
return 0; /* empty name */
|
||||
|
||||
if (substr)
|
||||
{
|
||||
return !!ascii_memcasemem (buffer+off, len, name, namelen);
|
||||
}
|
||||
else
|
||||
{
|
||||
return len == namelen && !memcmp (buffer+off, name, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* compare all email addresses of the subject. With SUBSTR given as
|
||||
True a substring search is done in the mail address */
|
||||
static int
|
||||
blob_cmp_mail (KEYBOXBLOB blob, const char *name, size_t namelen, int substr)
|
||||
{
|
||||
const unsigned char *buffer;
|
||||
size_t length;
|
||||
size_t pos, off, len;
|
||||
size_t nkeys, keyinfolen;
|
||||
size_t nuids, uidinfolen;
|
||||
size_t nserial;
|
||||
int idx;
|
||||
|
||||
/* fixme: this code is common to blob_cmp_mail */
|
||||
buffer = _keybox_get_blob_image (blob, &length);
|
||||
if (length < 40)
|
||||
return 0; /* blob too short */
|
||||
|
||||
/*keys*/
|
||||
nkeys = get16 (buffer + 16);
|
||||
keyinfolen = get16 (buffer + 18 );
|
||||
if (keyinfolen < 28)
|
||||
return 0; /* invalid blob */
|
||||
pos = 20 + keyinfolen*nkeys;
|
||||
if (pos+2 > length)
|
||||
return 0; /* out of bounds */
|
||||
|
||||
/*serial*/
|
||||
nserial = get16 (buffer+pos);
|
||||
pos += 2 + nserial;
|
||||
if (pos+4 > length)
|
||||
return 0; /* out of bounds */
|
||||
|
||||
/* user ids*/
|
||||
nuids = get16 (buffer + pos); pos += 2;
|
||||
uidinfolen = get16 (buffer + pos); pos += 2;
|
||||
if (uidinfolen < 12 /* should add a: || nuidinfolen > MAX_UIDINFOLEN */)
|
||||
return 0; /* invalid blob */
|
||||
if (pos + uidinfolen*nuids > length)
|
||||
return 0; /* out of bounds */
|
||||
|
||||
if (namelen < 1)
|
||||
return 0;
|
||||
|
||||
for (idx=1 ;idx < nuids; idx++)
|
||||
{
|
||||
size_t mypos = pos;
|
||||
|
||||
mypos += idx*uidinfolen;
|
||||
off = get32 (buffer+mypos);
|
||||
len = get32 (buffer+mypos+4);
|
||||
if (off+len > length)
|
||||
return 0; /* error: better stop here out of bounds */
|
||||
if (len < 2 || buffer[off] != '<')
|
||||
continue; /* empty name or trailing 0 not stored */
|
||||
len--; /* one back */
|
||||
if ( len < 3 || buffer[off+len] != '>')
|
||||
continue; /* not a proper email address */
|
||||
len--;
|
||||
if (substr)
|
||||
{
|
||||
if (ascii_memcasemem (buffer+off+1, len, name, namelen))
|
||||
return 1; /* found */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (len == namelen && !ascii_memcasecmp (buffer+off+1, name, len))
|
||||
return 1; /* found */
|
||||
}
|
||||
}
|
||||
return 0; /* not found */
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
The has_foo functions are used as helpers for search
|
||||
*/
|
||||
static int
|
||||
has_short_kid (KEYBOXBLOB blob, const unsigned char *kid)
|
||||
{
|
||||
return blob_cmp_fpr_part (blob, kid+4, 16, 4);
|
||||
}
|
||||
|
||||
static int
|
||||
has_long_kid (KEYBOXBLOB blob, const unsigned char *kid)
|
||||
{
|
||||
return blob_cmp_fpr_part (blob, kid, 12, 8);
|
||||
}
|
||||
|
||||
static int
|
||||
has_fingerprint (KEYBOXBLOB blob, const unsigned char *fpr)
|
||||
{
|
||||
return blob_cmp_fpr (blob, fpr);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
has_issuer (KEYBOXBLOB blob, const char *name)
|
||||
{
|
||||
size_t namelen;
|
||||
|
||||
return_val_if_fail (name, 0);
|
||||
|
||||
if (blob_get_type (blob) != BLOBTYPE_X509)
|
||||
return 0;
|
||||
|
||||
namelen = strlen (name);
|
||||
return blob_cmp_name (blob, 0 /* issuer */, name, namelen, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
has_issuer_sn (KEYBOXBLOB blob, const char *name,
|
||||
const unsigned char *sn, int snlen)
|
||||
{
|
||||
size_t namelen;
|
||||
|
||||
return_val_if_fail (name, 0);
|
||||
return_val_if_fail (sn, 0);
|
||||
|
||||
if (blob_get_type (blob) != BLOBTYPE_X509)
|
||||
return 0;
|
||||
|
||||
namelen = strlen (name);
|
||||
|
||||
return (blob_cmp_sn (blob, sn, snlen)
|
||||
&& blob_cmp_name (blob, 0 /* issuer */, name, namelen, 0));
|
||||
}
|
||||
|
||||
static int
|
||||
has_sn (KEYBOXBLOB blob, const unsigned char *sn, int snlen)
|
||||
{
|
||||
return_val_if_fail (sn, 0);
|
||||
|
||||
if (blob_get_type (blob) != BLOBTYPE_X509)
|
||||
return 0;
|
||||
return blob_cmp_sn (blob, sn, snlen);
|
||||
}
|
||||
|
||||
static int
|
||||
has_subject (KEYBOXBLOB blob, const char *name)
|
||||
{
|
||||
size_t namelen;
|
||||
|
||||
return_val_if_fail (name, 0);
|
||||
|
||||
if (blob_get_type (blob) != BLOBTYPE_X509)
|
||||
return 0;
|
||||
|
||||
namelen = strlen (name);
|
||||
return blob_cmp_name (blob, 1 /* subject */, name, namelen, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
has_subject_or_alt (KEYBOXBLOB blob, const char *name, int substr)
|
||||
{
|
||||
size_t namelen;
|
||||
|
||||
return_val_if_fail (name, 0);
|
||||
|
||||
if (blob_get_type (blob) != BLOBTYPE_X509)
|
||||
return 0;
|
||||
|
||||
namelen = strlen (name);
|
||||
return blob_cmp_name (blob, -1 /* all subject names*/, name,
|
||||
namelen, substr);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
has_mail (KEYBOXBLOB blob, const char *name, int substr)
|
||||
{
|
||||
size_t namelen;
|
||||
|
||||
return_val_if_fail (name, 0);
|
||||
|
||||
if (blob_get_type (blob) != BLOBTYPE_X509)
|
||||
return 0;
|
||||
|
||||
namelen = strlen (name);
|
||||
if (namelen && name[namelen-1] == '>')
|
||||
namelen--;
|
||||
return blob_cmp_mail (blob, name, namelen, substr);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
release_sn_array (struct sn_array_s *array, size_t size)
|
||||
{
|
||||
size_t n;
|
||||
|
||||
for (n=0; n < size; n++)
|
||||
xfree (array[n].sn);
|
||||
xfree (array);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
||||
The search API
|
||||
|
||||
*/
|
||||
|
||||
int
|
||||
keybox_search_reset (KEYBOX_HANDLE hd)
|
||||
{
|
||||
if (!hd)
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
|
||||
if (hd->found.blob)
|
||||
{
|
||||
_keybox_release_blob (hd->found.blob);
|
||||
hd->found.blob = NULL;
|
||||
}
|
||||
|
||||
if (hd->fp)
|
||||
{
|
||||
fclose (hd->fp);
|
||||
hd->fp = NULL;
|
||||
}
|
||||
hd->error = 0;
|
||||
hd->eof = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Note: When in ephemeral mode the search function does visit all
|
||||
blobs but in standard mode, blobs flagged as ephemeral are ignored. */
|
||||
int
|
||||
keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc)
|
||||
{
|
||||
int rc;
|
||||
size_t n;
|
||||
int need_words, any_skip;
|
||||
KEYBOXBLOB blob = NULL;
|
||||
struct sn_array_s *sn_array = NULL;
|
||||
|
||||
if (!hd)
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
|
||||
/* clear last found result */
|
||||
if (hd->found.blob)
|
||||
{
|
||||
_keybox_release_blob (hd->found.blob);
|
||||
hd->found.blob = NULL;
|
||||
}
|
||||
|
||||
if (hd->error)
|
||||
return hd->error; /* still in error state */
|
||||
if (hd->eof)
|
||||
return -1; /* still EOF */
|
||||
|
||||
/* figure out what information we need */
|
||||
need_words = any_skip = 0;
|
||||
for (n=0; n < ndesc; n++)
|
||||
{
|
||||
switch (desc[n].mode)
|
||||
{
|
||||
case KEYDB_SEARCH_MODE_WORDS:
|
||||
need_words = 1;
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_FIRST:
|
||||
/* always restart the search in this mode */
|
||||
keybox_search_reset (hd);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (desc[n].skipfnc)
|
||||
any_skip = 1;
|
||||
if (desc[n].snlen == -1 && !sn_array)
|
||||
{
|
||||
sn_array = xtrycalloc (ndesc, sizeof *sn_array);
|
||||
if (!sn_array)
|
||||
return (hd->error = gpg_error (gpg_err_code_from_errno (errno)));
|
||||
}
|
||||
}
|
||||
|
||||
if (!hd->fp)
|
||||
{
|
||||
hd->fp = fopen (hd->kb->fname, "rb");
|
||||
if (!hd->fp)
|
||||
{
|
||||
hd->error = gpg_error (gpg_err_code_from_errno (errno));
|
||||
xfree (sn_array);
|
||||
return hd->error;
|
||||
}
|
||||
}
|
||||
|
||||
/* kludge: we need to convert an SN given as hexstring to it's
|
||||
binary representation - in some cases we are not able to store it
|
||||
in the search descriptor, because due to its usgae it is not
|
||||
possible to free allocated memory */
|
||||
if (sn_array)
|
||||
{
|
||||
const unsigned char *s;
|
||||
int i, odd;
|
||||
size_t snlen;
|
||||
|
||||
for (n=0; n < ndesc; n++)
|
||||
{
|
||||
if (!desc[n].sn)
|
||||
;
|
||||
else if (desc[n].snlen == -1)
|
||||
{
|
||||
unsigned char *sn;
|
||||
|
||||
s = desc[n].sn;
|
||||
for (i=0; *s && *s != '/'; s++, i++)
|
||||
;
|
||||
odd = (i & 1);
|
||||
snlen = (i+1)/2;
|
||||
sn_array[n].sn = xtrymalloc (snlen);
|
||||
if (!sn_array[n].sn)
|
||||
{
|
||||
hd->error = gpg_error (gpg_err_code_from_errno (errno));
|
||||
release_sn_array (sn_array, n);
|
||||
return hd->error;
|
||||
}
|
||||
sn_array[n].snlen = snlen;
|
||||
sn = sn_array[n].sn;
|
||||
s = desc[n].sn;
|
||||
if (odd)
|
||||
{
|
||||
*sn++ = xtoi_1 (s);
|
||||
s++;
|
||||
}
|
||||
for (; *s && *s != '/'; s += 2)
|
||||
*sn++ = xtoi_2 (s);
|
||||
}
|
||||
else
|
||||
{
|
||||
const unsigned char *sn;
|
||||
|
||||
sn = desc[n].sn;
|
||||
snlen = desc[n].snlen;
|
||||
sn_array[n].sn = xtrymalloc (snlen);
|
||||
if (!sn_array[n].sn)
|
||||
{
|
||||
hd->error = gpg_error (gpg_err_code_from_errno (errno));
|
||||
release_sn_array (sn_array, n);
|
||||
return hd->error;
|
||||
}
|
||||
sn_array[n].snlen = snlen;
|
||||
memcpy (sn_array[n].sn, sn, snlen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (;;)
|
||||
{
|
||||
unsigned int blobflags;
|
||||
|
||||
_keybox_release_blob (blob); blob = NULL;
|
||||
rc = _keybox_read_blob (&blob, hd->fp);
|
||||
if (rc)
|
||||
break;
|
||||
|
||||
blobflags = blob_get_blob_flags (blob);
|
||||
if (!hd->ephemeral && (blobflags & 2))
|
||||
continue; /* not in ephemeral mode but blob is flagged ephemeral */
|
||||
|
||||
for (n=0; n < ndesc; n++)
|
||||
{
|
||||
switch (desc[n].mode)
|
||||
{
|
||||
case KEYDB_SEARCH_MODE_NONE:
|
||||
never_reached ();
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_EXACT:
|
||||
if (has_subject_or_alt (blob, desc[n].u.name, 0))
|
||||
goto found;
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_MAIL:
|
||||
if (has_mail (blob, desc[n].u.name, 0))
|
||||
goto found;
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_MAILSUB:
|
||||
if (has_mail (blob, desc[n].u.name, 1))
|
||||
goto found;
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_SUBSTR:
|
||||
if (has_subject_or_alt (blob, desc[n].u.name, 1))
|
||||
goto found;
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_MAILEND:
|
||||
case KEYDB_SEARCH_MODE_WORDS:
|
||||
never_reached (); /* not yet implemented */
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_ISSUER:
|
||||
if (has_issuer (blob, desc[n].u.name))
|
||||
goto found;
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_ISSUER_SN:
|
||||
if (has_issuer_sn (blob, desc[n].u.name,
|
||||
sn_array? sn_array[n].sn : desc[n].sn,
|
||||
sn_array? sn_array[n].snlen : desc[n].snlen))
|
||||
goto found;
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_SN:
|
||||
if (has_sn (blob, sn_array? sn_array[n].sn : desc[n].sn,
|
||||
sn_array? sn_array[n].snlen : desc[n].snlen))
|
||||
goto found;
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_SUBJECT:
|
||||
if (has_subject (blob, desc[n].u.name))
|
||||
goto found;
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_SHORT_KID:
|
||||
if (has_short_kid (blob, desc[n].u.kid))
|
||||
goto found;
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_LONG_KID:
|
||||
if (has_long_kid (blob, desc[n].u.kid))
|
||||
goto found;
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_FPR:
|
||||
case KEYDB_SEARCH_MODE_FPR20:
|
||||
if (has_fingerprint (blob, desc[n].u.fpr))
|
||||
goto found;
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_FIRST:
|
||||
goto found;
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_NEXT:
|
||||
goto found;
|
||||
break;
|
||||
default:
|
||||
rc = gpg_error (GPG_ERR_INV_VALUE);
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
found:
|
||||
for (n=any_skip?0:ndesc; n < ndesc; n++)
|
||||
{
|
||||
/* if (desc[n].skipfnc */
|
||||
/* && desc[n].skipfnc (desc[n].skipfncvalue, aki)) */
|
||||
/* break; */
|
||||
}
|
||||
if (n == ndesc)
|
||||
break; /* got it */
|
||||
}
|
||||
|
||||
if (!rc)
|
||||
{
|
||||
hd->found.blob = blob;
|
||||
}
|
||||
else if (rc == -1)
|
||||
{
|
||||
_keybox_release_blob (blob);
|
||||
hd->eof = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
_keybox_release_blob (blob);
|
||||
hd->error = rc;
|
||||
}
|
||||
|
||||
if (sn_array)
|
||||
release_sn_array (sn_array, ndesc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Functions to return a certificate or a keyblock. To be used after
|
||||
a successful search operation.
|
||||
*/
|
||||
#ifdef KEYBOX_WITH_X509
|
||||
/*
|
||||
Return the last found cert. Caller must free it.
|
||||
*/
|
||||
int
|
||||
keybox_get_cert (KEYBOX_HANDLE hd, KsbaCert *r_cert)
|
||||
{
|
||||
const unsigned char *buffer;
|
||||
size_t length;
|
||||
size_t cert_off, cert_len;
|
||||
KsbaReader reader = NULL;
|
||||
KsbaCert cert = NULL;
|
||||
int rc;
|
||||
|
||||
if (!hd)
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
if (!hd->found.blob)
|
||||
return gpg_error (GPG_ERR_NOTHING_FOUND);
|
||||
|
||||
if (blob_get_type (hd->found.blob) != BLOBTYPE_X509)
|
||||
return gpg_error (GPG_ERR_WRONG_BLOB_TYPE);
|
||||
|
||||
buffer = _keybox_get_blob_image (hd->found.blob, &length);
|
||||
if (length < 40)
|
||||
return gpg_error (GPG_ERR_TOO_SHORT);
|
||||
cert_off = get32 (buffer+8);
|
||||
cert_len = get32 (buffer+12);
|
||||
if (cert_off+cert_len > length)
|
||||
return gpg_error (GPG_ERR_TOO_SHORT);
|
||||
|
||||
reader = ksba_reader_new ();
|
||||
if (!reader)
|
||||
return gpg_error (GPG_ERR_ENOMEM);
|
||||
rc = ksba_reader_set_mem (reader, buffer+cert_off, cert_len);
|
||||
if (rc)
|
||||
{
|
||||
ksba_reader_release (reader);
|
||||
/* fixme: need to map the error codes */
|
||||
return gpg_error (GPG_ERR_GENERAL);
|
||||
}
|
||||
|
||||
cert = ksba_cert_new ();
|
||||
if (!cert)
|
||||
{
|
||||
ksba_reader_release (reader);
|
||||
return gpg_error (GPG_ERR_ENOMEM);
|
||||
}
|
||||
|
||||
rc = ksba_cert_read_der (cert, reader);
|
||||
if (rc)
|
||||
{
|
||||
ksba_cert_release (cert);
|
||||
ksba_reader_release (reader);
|
||||
/* fixme: need to map the error codes */
|
||||
return gpg_error (GPG_ERR_GENERAL);
|
||||
}
|
||||
|
||||
*r_cert = cert;
|
||||
ksba_reader_release (reader);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /*KEYBOX_WITH_X509*/
|
437
kbx/keybox-update.c
Normal file
437
kbx/keybox-update.c
Normal file
@ -0,0 +1,437 @@
|
||||
/* keybox-update.c - keybox update operations
|
||||
* Copyright (C) 2001, 2003 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "keybox-defs.h"
|
||||
|
||||
#define EXTSEP_S "."
|
||||
|
||||
|
||||
static int
|
||||
create_tmp_file (const char *template,
|
||||
char **r_bakfname, char **r_tmpfname, FILE **r_fp)
|
||||
{
|
||||
char *bakfname, *tmpfname;
|
||||
|
||||
*r_bakfname = NULL;
|
||||
*r_tmpfname = NULL;
|
||||
|
||||
# ifdef USE_ONLY_8DOT3
|
||||
/* Here is another Windoze bug?:
|
||||
* you cant rename("pubring.kbx.tmp", "pubring.kbx");
|
||||
* but rename("pubring.kbx.tmp", "pubring.aaa");
|
||||
* works. So we replace .kbx by .bak or .tmp
|
||||
*/
|
||||
if (strlen (template) > 4
|
||||
&& !strcmp (template+strlen(template)-4, EXTSEP_S "kbx") )
|
||||
{
|
||||
bakfname = xtrymalloc (strlen (template) + 1);
|
||||
if (!bakfname)
|
||||
return gpg_error (gpg_err_code_from_errno (errno));
|
||||
strcpy (bakfname, template);
|
||||
strcpy (bakfname+strlen(template)-4, EXTSEP_S "bak");
|
||||
|
||||
tmpfname = xtrymalloc (strlen (template) + 1);
|
||||
if (!tmpfname)
|
||||
{
|
||||
gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
|
||||
xfree (bakfname);
|
||||
return tmperr;
|
||||
}
|
||||
strcpy (tmpfname,template);
|
||||
strcpy (tmpfname + strlen (template)-4, EXTSEP_S "tmp");
|
||||
}
|
||||
else
|
||||
{ /* file does not end with kbx; hmmm */
|
||||
bakfname = xtrymalloc ( strlen (template) + 5);
|
||||
if (!bakfname)
|
||||
return gpg_error (gpg_err_code_from_errno (errno));
|
||||
strcpy (stpcpy (bakfname, template), EXTSEP_S "bak");
|
||||
|
||||
tmpfname = xtrymalloc ( strlen (template) + 5);
|
||||
if (!tmpfname)
|
||||
{
|
||||
gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
|
||||
xfree (bakfname);
|
||||
return tmperr;
|
||||
}
|
||||
strcpy (stpcpy (tmpfname, template), EXTSEP_S "tmp");
|
||||
}
|
||||
# else /* Posix file names */
|
||||
bakfname = xtrymalloc (strlen (template) + 2);
|
||||
if (!bakfname)
|
||||
return gpg_error (gpg_err_code_from_errno (errno));
|
||||
strcpy (stpcpy (bakfname,template),"~");
|
||||
|
||||
tmpfname = xtrymalloc ( strlen (template) + 5);
|
||||
if (!tmpfname)
|
||||
{
|
||||
gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
|
||||
xfree (bakfname);
|
||||
return tmperr;
|
||||
}
|
||||
strcpy (stpcpy (tmpfname,template), EXTSEP_S "tmp");
|
||||
# endif /* Posix filename */
|
||||
|
||||
*r_fp = fopen (tmpfname, "wb");
|
||||
if (!*r_fp)
|
||||
{
|
||||
gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
|
||||
xfree (tmpfname);
|
||||
xfree (bakfname);
|
||||
return tmperr;
|
||||
}
|
||||
|
||||
*r_bakfname = bakfname;
|
||||
*r_tmpfname = tmpfname;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
rename_tmp_file (const char *bakfname, const char *tmpfname,
|
||||
const char *fname, int secret )
|
||||
{
|
||||
int rc=0;
|
||||
|
||||
/* restrict the permissions for secret keyboxs */
|
||||
#ifndef HAVE_DOSISH_SYSTEM
|
||||
/* if (secret && !opt.preserve_permissions) */
|
||||
/* { */
|
||||
/* if (chmod (tmpfname, S_IRUSR | S_IWUSR) ) */
|
||||
/* { */
|
||||
/* log_debug ("chmod of `%s' failed: %s\n", */
|
||||
/* tmpfname, strerror(errno) ); */
|
||||
/* return KEYBOX_Write_File; */
|
||||
/* } */
|
||||
/* } */
|
||||
#endif
|
||||
|
||||
/* fixme: invalidate close caches (not used with stdio)*/
|
||||
/* iobuf_ioctl (NULL, 2, 0, (char*)tmpfname ); */
|
||||
/* iobuf_ioctl (NULL, 2, 0, (char*)bakfname ); */
|
||||
/* iobuf_ioctl (NULL, 2, 0, (char*)fname ); */
|
||||
|
||||
/* first make a backup file except for secret keyboxs */
|
||||
if (!secret)
|
||||
{
|
||||
#if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
|
||||
remove (bakfname);
|
||||
#endif
|
||||
if (rename (fname, bakfname) )
|
||||
{
|
||||
return gpg_error (gpg_err_code_from_errno (errno));
|
||||
}
|
||||
}
|
||||
|
||||
/* then rename the file */
|
||||
#if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
|
||||
remove (fname);
|
||||
#endif
|
||||
if (rename (tmpfname, fname) )
|
||||
{
|
||||
rc = gpg_error (gpg_err_code_from_errno (errno));
|
||||
if (secret)
|
||||
{
|
||||
/* log_info ("WARNING: 2 files with confidential" */
|
||||
/* " information exists.\n"); */
|
||||
/* log_info ("%s is the unchanged one\n", fname ); */
|
||||
/* log_info ("%s is the new one\n", tmpfname ); */
|
||||
/* log_info ("Please fix this possible security flaw\n"); */
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Perform insert/delete/update operation.
|
||||
mode 1 = insert
|
||||
2 = delete
|
||||
3 = update
|
||||
*/
|
||||
static int
|
||||
blob_filecopy (int mode, const char *fname, KEYBOXBLOB blob,
|
||||
int secret, off_t start_offset, unsigned int n_packets )
|
||||
{
|
||||
FILE *fp, *newfp;
|
||||
int rc=0;
|
||||
char *bakfname = NULL;
|
||||
char *tmpfname = NULL;
|
||||
char buffer[4096];
|
||||
int nread, nbytes;
|
||||
|
||||
/* Open the source file. Because we do a rename, we have to check the
|
||||
permissions of the file */
|
||||
if (access (fname, W_OK))
|
||||
return gpg_error (gpg_err_code_from_errno (errno));
|
||||
|
||||
fp = fopen (fname, "rb");
|
||||
if (mode == 1 && !fp && errno == ENOENT)
|
||||
{ /* insert mode but file does not exist: create a new keybox file */
|
||||
newfp = fopen (fname, "wb");
|
||||
if (!newfp )
|
||||
{
|
||||
return gpg_error (gpg_err_code_from_errno (errno));
|
||||
}
|
||||
|
||||
rc = _keybox_write_blob (blob, newfp);
|
||||
if (rc)
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
if ( fclose (newfp) )
|
||||
{
|
||||
return gpg_error (gpg_err_code_from_errno (errno));
|
||||
}
|
||||
|
||||
/* if (chmod( fname, S_IRUSR | S_IWUSR )) */
|
||||
/* { */
|
||||
/* log_debug ("%s: chmod failed: %s\n", fname, strerror(errno) ); */
|
||||
/* return KEYBOX_File_Error; */
|
||||
/* } */
|
||||
return 0; /* ready */
|
||||
}
|
||||
|
||||
if (!fp)
|
||||
{
|
||||
rc = gpg_error (gpg_err_code_from_errno (errno));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* create the new file */
|
||||
rc = create_tmp_file (fname, &bakfname, &tmpfname, &newfp);
|
||||
if (rc)
|
||||
{
|
||||
fclose(fp);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* prepare for insert */
|
||||
if (mode == 1)
|
||||
{
|
||||
/* copy everything to the new file */
|
||||
while ( (nread = fread (buffer, 1, DIM(buffer), fp)) > 0 )
|
||||
{
|
||||
if (fwrite (buffer, nread, 1, newfp) != 1)
|
||||
{
|
||||
rc = gpg_error (gpg_err_code_from_errno (errno));
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
if (ferror (fp))
|
||||
{
|
||||
rc = gpg_error (gpg_err_code_from_errno (errno));
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
|
||||
/* prepare for delete or update */
|
||||
if ( mode == 2 || mode == 3 )
|
||||
{
|
||||
off_t current = 0;
|
||||
|
||||
/* copy first part to the new file */
|
||||
while ( current < start_offset )
|
||||
{
|
||||
nbytes = DIM(buffer);
|
||||
if (current + nbytes > start_offset)
|
||||
nbytes = start_offset - current;
|
||||
nread = fread (buffer, 1, nbytes, fp);
|
||||
if (!fread)
|
||||
break;
|
||||
current += nread;
|
||||
|
||||
if (fwrite (buffer, nread, 1, newfp) != 1)
|
||||
{
|
||||
rc = gpg_error (gpg_err_code_from_errno (errno));
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
if (ferror (fp))
|
||||
{
|
||||
rc = gpg_error (gpg_err_code_from_errno (errno));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* skip this blob */
|
||||
rc = _keybox_read_blob (NULL, fp);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Do an insert or update */
|
||||
if ( mode == 1 || mode == 3 )
|
||||
{
|
||||
rc = _keybox_write_blob (blob, newfp);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* copy the rest of the packet for an delete or update */
|
||||
if (mode == 2 || mode == 3)
|
||||
{
|
||||
while ( (nread = fread (buffer, 1, DIM(buffer), fp)) > 0 )
|
||||
{
|
||||
if (fwrite (buffer, nread, 1, newfp) != 1)
|
||||
{
|
||||
rc = gpg_error (gpg_err_code_from_errno (errno));
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
if (ferror (fp))
|
||||
{
|
||||
rc = gpg_error (gpg_err_code_from_errno (errno));
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
|
||||
/* close both files */
|
||||
if (fclose(fp))
|
||||
{
|
||||
rc = gpg_error (gpg_err_code_from_errno (errno));
|
||||
fclose (newfp);
|
||||
goto leave;
|
||||
}
|
||||
if (fclose(newfp))
|
||||
{
|
||||
rc = gpg_error (gpg_err_code_from_errno (errno));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
rc = rename_tmp_file (bakfname, tmpfname, fname, secret);
|
||||
|
||||
leave:
|
||||
xfree(bakfname);
|
||||
xfree(tmpfname);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef KEYBOX_WITH_X509
|
||||
int
|
||||
keybox_insert_cert (KEYBOX_HANDLE hd, KsbaCert cert,
|
||||
unsigned char *sha1_digest)
|
||||
{
|
||||
int rc;
|
||||
const char *fname;
|
||||
KEYBOXBLOB blob;
|
||||
|
||||
if (!hd)
|
||||
return gpg_error (GPG_ERR_INV_HANDLE);
|
||||
if (!hd->kb)
|
||||
return gpg_error (GPG_ERR_INV_HANDLE);
|
||||
fname = hd->kb->fname;
|
||||
if (!fname)
|
||||
return gpg_error (GPG_ERR_INV_HANDLE);
|
||||
|
||||
/* close this one otherwise we will mess up the position for a next
|
||||
search. Fixme: it would be better to adjust the position after
|
||||
the write opertions. */
|
||||
if (hd->fp)
|
||||
{
|
||||
fclose (hd->fp);
|
||||
hd->fp = NULL;
|
||||
}
|
||||
|
||||
rc = _keybox_create_x509_blob (&blob, cert, sha1_digest, hd->ephemeral);
|
||||
if (!rc)
|
||||
{
|
||||
rc = blob_filecopy (1, fname, blob, hd->secret, 0, 0 );
|
||||
_keybox_release_blob (blob);
|
||||
/* if (!rc && !hd->secret && kb_offtbl) */
|
||||
/* { */
|
||||
/* update_offset_hash_table_from_kb (kb_offtbl, kb, 0); */
|
||||
/* } */
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
keybox_update_cert (KEYBOX_HANDLE hd, KsbaCert cert,
|
||||
unsigned char *sha1_digest)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
#endif /*KEYBOX_WITH_X509*/
|
||||
|
||||
|
||||
int
|
||||
keybox_delete (KEYBOX_HANDLE hd)
|
||||
{
|
||||
off_t off;
|
||||
const char *fname;
|
||||
FILE *fp;
|
||||
int rc;
|
||||
|
||||
if (!hd)
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
if (!hd->found.blob)
|
||||
return gpg_error (GPG_ERR_NOTHING_FOUND);
|
||||
if (!hd->kb)
|
||||
return gpg_error (GPG_ERR_INV_HANDLE);
|
||||
fname = hd->kb->fname;
|
||||
if (!fname)
|
||||
return gpg_error (GPG_ERR_INV_HANDLE);
|
||||
|
||||
off = _keybox_get_blob_fileoffset (hd->found.blob);
|
||||
if (off == (off_t)-1)
|
||||
return gpg_error (GPG_ERR_GENERAL);
|
||||
off += 4;
|
||||
|
||||
if (hd->fp)
|
||||
{
|
||||
fclose (hd->fp);
|
||||
hd->fp = NULL;
|
||||
}
|
||||
|
||||
fp = fopen (hd->kb->fname, "r+b");
|
||||
if (!fp)
|
||||
return gpg_error (gpg_err_code_from_errno (errno));
|
||||
|
||||
if (fseeko (fp, off, SEEK_SET))
|
||||
rc = gpg_error (gpg_err_code_from_errno (errno));
|
||||
else if (putc (0, fp) == EOF)
|
||||
rc = gpg_error (gpg_err_code_from_errno (errno));
|
||||
else
|
||||
rc = 0;
|
||||
|
||||
if (fclose (fp))
|
||||
{
|
||||
if (!rc)
|
||||
rc = gpg_error (gpg_err_code_from_errno (errno));
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
101
kbx/keybox.h
Normal file
101
kbx/keybox.h
Normal file
@ -0,0 +1,101 @@
|
||||
/* keybox.h - Keybox operations
|
||||
* Copyright (C) 2001, 2003 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef KEYBOX_H
|
||||
#define KEYBOX_H 1
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#if 0
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "keybox-search-desc.h"
|
||||
|
||||
#define KEYBOX_WITH_OPENPGP 1
|
||||
#define KEYBOX_WITH_X509 1
|
||||
|
||||
|
||||
#ifdef KEYBOX_WITH_OPENPGP
|
||||
# undef KEYBOX_WITH_OPENPGP
|
||||
/*#include <lib-to-handle-gpg-data-structs.h>*/
|
||||
#endif
|
||||
|
||||
#ifdef KEYBOX_WITH_X509
|
||||
# include <ksba.h>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
typedef struct keybox_handle *KEYBOX_HANDLE;
|
||||
|
||||
|
||||
/*-- keybox-init.c --*/
|
||||
void *keybox_register_file (const char *fname, int secret);
|
||||
int keybox_is_writable (void *token);
|
||||
|
||||
KEYBOX_HANDLE keybox_new (void *token, int secret);
|
||||
void keybox_release (KEYBOX_HANDLE hd);
|
||||
const char *keybox_get_resource_name (KEYBOX_HANDLE hd);
|
||||
int keybox_set_ephemeral (KEYBOX_HANDLE hd, int yes);
|
||||
|
||||
|
||||
/*-- keybox-search.c --*/
|
||||
#ifdef KEYBOX_WITH_X509
|
||||
int keybox_get_cert (KEYBOX_HANDLE hd, KsbaCert *ret_cert);
|
||||
#endif /*KEYBOX_WITH_X509*/
|
||||
|
||||
int keybox_search_reset (KEYBOX_HANDLE hd);
|
||||
int keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc);
|
||||
|
||||
|
||||
/*-- keybox-update.c --*/
|
||||
#ifdef KEYBOX_WITH_X509
|
||||
int keybox_insert_cert (KEYBOX_HANDLE hd, KsbaCert cert,
|
||||
unsigned char *sha1_digest);
|
||||
int keybox_update_cert (KEYBOX_HANDLE hd, KsbaCert cert,
|
||||
unsigned char *sha1_digest);
|
||||
#endif /*KEYBOX_WITH_X509*/
|
||||
|
||||
int keybox_delete (KEYBOX_HANDLE hd);
|
||||
|
||||
|
||||
/*-- --*/
|
||||
|
||||
#if 0
|
||||
int keybox_lock (KEYBOX_HANDLE hd, int yes);
|
||||
int keybox_get_keyblock (KEYBOX_HANDLE hd, KBNODE *ret_kb);
|
||||
int keybox_locate_writable (KEYBOX_HANDLE hd);
|
||||
int keybox_search_reset (KEYBOX_HANDLE hd);
|
||||
int keybox_search (KEYBOX_HANDLE hd, KEYDB_SEARCH_DESC *desc, size_t ndesc);
|
||||
int keybox_rebuild_cache (void *);
|
||||
#endif
|
||||
|
||||
|
||||
/*-- keybox-util.c --*/
|
||||
void keybox_set_malloc_hooks ( void *(*new_alloc_func)(size_t n),
|
||||
void *(*new_realloc_func)(void *p, size_t n),
|
||||
void (*new_free_func)(void*) );
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /*KEYBOX_H*/
|
287
scd/atr.c
Normal file
287
scd/atr.c
Normal file
@ -0,0 +1,287 @@
|
||||
/* atr.c - ISO 7816 ATR fucntions
|
||||
* Copyright (C) 2003 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <dlfcn.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "scdaemon.h"
|
||||
#include "apdu.h"
|
||||
#include "atr.h"
|
||||
|
||||
static int const fi_table[16] = { 0, 372, 558, 744, 1116,1488, 1860, -1,
|
||||
-1, 512, 768, 1024, 1536, 2048, -1, -1 };
|
||||
static int const di_table[16] = { -1, 1, 2, 4, 8, 16, -1, -1,
|
||||
0, -1, -2, -4, -8, -16, -32, -64};
|
||||
|
||||
|
||||
/* Dump the ATR of the card at SLOT in a human readable format to
|
||||
stream FP. */
|
||||
int
|
||||
atr_dump (int slot, FILE *fp)
|
||||
{
|
||||
unsigned char *atrbuffer, *atr;
|
||||
size_t atrlen;
|
||||
int have_ta, have_tb, have_tc, have_td;
|
||||
int n_historical;
|
||||
int idx, val;
|
||||
unsigned char chksum;
|
||||
|
||||
atr = atrbuffer = apdu_get_atr (slot, &atrlen);
|
||||
if (!atr)
|
||||
return gpg_error (GPG_ERR_GENERAL);
|
||||
|
||||
fprintf (fp, "Info on ATR of length %u at slot %d\n",
|
||||
(unsigned int)atrlen, slot);
|
||||
if (!atrlen)
|
||||
{
|
||||
fprintf (fp, "error: empty ATR\n");
|
||||
goto bailout;
|
||||
}
|
||||
|
||||
|
||||
if (*atr == 0x3b)
|
||||
fputs ("direct convention\n", fp);
|
||||
else if (*atr == 0x3f)
|
||||
fputs ("inverse convention\n", fp);
|
||||
else
|
||||
fprintf (fp,"error: invalid TS character 0x%02x\n", *atr);
|
||||
if (!--atrlen)
|
||||
goto bailout;
|
||||
atr++;
|
||||
|
||||
chksum = *atr;
|
||||
for (idx=1; idx < atrlen-1; idx++)
|
||||
chksum ^= atr[idx];
|
||||
|
||||
have_ta = !!(*atr & 0x10);
|
||||
have_tb = !!(*atr & 0x20);
|
||||
have_tc = !!(*atr & 0x40);
|
||||
have_td = !!(*atr & 0x80);
|
||||
n_historical = (*atr & 0x0f);
|
||||
fprintf (fp, "%d historical characters indicated\n", n_historical);
|
||||
|
||||
if (have_ta + have_tb + have_tc + have_td + n_historical > atrlen)
|
||||
fputs ("error: ATR shorter than indicated by format character\n", fp);
|
||||
if (!--atrlen)
|
||||
goto bailout;
|
||||
atr++;
|
||||
|
||||
if (have_ta)
|
||||
{
|
||||
fputs ("TA1: F=", fp);
|
||||
val = fi_table[(*atr >> 4) & 0x0f];
|
||||
if (!val)
|
||||
fputs ("internal clock", fp);
|
||||
else if (val == -1)
|
||||
fputs ("RFU", fp);
|
||||
else
|
||||
fprintf (fp, "%d", val);
|
||||
fputs (" D=", fp);
|
||||
val = di_table[*atr & 0x0f];
|
||||
if (!val)
|
||||
fputs ("[impossible value]\n", fp);
|
||||
else if (val == -1)
|
||||
fputs ("RFU\n", fp);
|
||||
else if (val < 0 )
|
||||
fprintf (fp, "1/%d\n", val);
|
||||
else
|
||||
fprintf (fp, "%d\n", val);
|
||||
|
||||
if (!--atrlen)
|
||||
goto bailout;
|
||||
atr++;
|
||||
}
|
||||
|
||||
if (have_tb)
|
||||
{
|
||||
fprintf (fp, "TB1: II=%d PI1=%d%s\n", (*atr >> 5) & 3, *atr & 0x1f,
|
||||
(*atr & 0x80)? " [high bit not cleared]":"");
|
||||
if (!--atrlen)
|
||||
goto bailout;
|
||||
atr++;
|
||||
}
|
||||
|
||||
if (have_tc)
|
||||
{
|
||||
if (*atr == 255)
|
||||
fputs ("TC1: guard time shortened to 1 etu\n", fp);
|
||||
else
|
||||
fprintf (fp, "TC1: (extra guard time) N=%d\n", *atr);
|
||||
|
||||
if (!--atrlen)
|
||||
goto bailout;
|
||||
atr++;
|
||||
}
|
||||
|
||||
if (have_td)
|
||||
{
|
||||
have_ta = !!(*atr & 0x10);
|
||||
have_tb = !!(*atr & 0x20);
|
||||
have_tc = !!(*atr & 0x40);
|
||||
have_td = !!(*atr & 0x80);
|
||||
fprintf (fp, "TD1: protocol T%d supported\n", *atr & 0x0f);
|
||||
|
||||
if (have_ta + have_tb + have_tc + have_td + n_historical > atrlen)
|
||||
fputs ("error: ATR shorter than indicated by format character\n", fp);
|
||||
|
||||
if (!--atrlen)
|
||||
goto bailout;
|
||||
atr++;
|
||||
}
|
||||
else
|
||||
have_ta = have_tb = have_tc = have_td = 0;
|
||||
|
||||
if (have_ta)
|
||||
{
|
||||
fprintf (fp, "TA2: (PTS) %stoggle, %splicit, T=%02X\n",
|
||||
(*atr & 0x80)? "no-":"",
|
||||
(*atr & 0x10)? "im": "ex",
|
||||
(*atr & 0x0f));
|
||||
if ((*atr & 0x60))
|
||||
fprintf (fp, "note: reserved bits are set (TA2=0x%02X)\n", *atr);
|
||||
if (!--atrlen)
|
||||
goto bailout;
|
||||
atr++;
|
||||
}
|
||||
|
||||
if (have_tb)
|
||||
{
|
||||
fprintf (fp, "TB2: PI2=%d\n", *atr);
|
||||
if (!--atrlen)
|
||||
goto bailout;
|
||||
atr++;
|
||||
}
|
||||
|
||||
if (have_tc)
|
||||
{
|
||||
fprintf (fp, "TC2: PWI=%d\n", *atr);
|
||||
if (!--atrlen)
|
||||
goto bailout;
|
||||
atr++;
|
||||
}
|
||||
|
||||
if (have_td)
|
||||
{
|
||||
have_ta = !!(*atr & 0x10);
|
||||
have_tb = !!(*atr & 0x20);
|
||||
have_tc = !!(*atr & 0x40);
|
||||
have_td = !!(*atr & 0x80);
|
||||
fprintf (fp, "TD2: protocol T%d supported\n", *atr & 0x0f);
|
||||
|
||||
if (have_ta + have_tb + have_tc + have_td + n_historical > atrlen)
|
||||
fputs ("error: ATR shorter than indicated by format character\n", fp);
|
||||
|
||||
if (!--atrlen)
|
||||
goto bailout;
|
||||
atr++;
|
||||
}
|
||||
else
|
||||
have_ta = have_tb = have_tc = have_td = 0;
|
||||
|
||||
for (idx = 3; have_ta || have_tb || have_tc || have_td; idx++)
|
||||
{
|
||||
if (have_ta)
|
||||
{
|
||||
fprintf (fp, "TA%d: IFSC=%d\n", idx, *atr);
|
||||
if (!--atrlen)
|
||||
goto bailout;
|
||||
atr++;
|
||||
}
|
||||
|
||||
if (have_tb)
|
||||
{
|
||||
fprintf (fp, "TB%d: BWI=%d CWI=%d\n",
|
||||
idx, (*atr >> 4) & 0x0f, *atr & 0x0f);
|
||||
if (!--atrlen)
|
||||
goto bailout;
|
||||
atr++;
|
||||
}
|
||||
|
||||
if (have_tc)
|
||||
{
|
||||
fprintf (fp, "TC%d: 0x%02X\n", idx, *atr);
|
||||
if (!--atrlen)
|
||||
goto bailout;
|
||||
atr++;
|
||||
}
|
||||
|
||||
if (have_td)
|
||||
{
|
||||
have_ta = !!(*atr & 0x10);
|
||||
have_tb = !!(*atr & 0x20);
|
||||
have_tc = !!(*atr & 0x40);
|
||||
have_td = !!(*atr & 0x80);
|
||||
fprintf (fp, "TD%d: protocol T%d supported\n", idx, *atr & 0x0f);
|
||||
|
||||
if (have_ta + have_tb + have_tc + have_td + n_historical > atrlen)
|
||||
fputs ("error: ATR shorter than indicated by format character\n",
|
||||
fp);
|
||||
|
||||
if (!--atrlen)
|
||||
goto bailout;
|
||||
atr++;
|
||||
}
|
||||
else
|
||||
have_ta = have_tb = have_tc = have_td = 0;
|
||||
}
|
||||
|
||||
if (n_historical + 1 > atrlen)
|
||||
fputs ("error: ATR shorter than required for historical bytes "
|
||||
"and checksum\n", fp);
|
||||
|
||||
if (n_historical)
|
||||
{
|
||||
fputs ("Historical:", fp);
|
||||
for (; n_historical && atrlen ; n_historical--, atrlen--, atr++)
|
||||
fprintf (fp, " %02X", *atr);
|
||||
putchar ('\n');
|
||||
}
|
||||
|
||||
if (!atrlen)
|
||||
fputs ("error: checksum missing\n", fp);
|
||||
else if (*atr == chksum)
|
||||
fprintf (fp, "TCK: %02X (good)\n", *atr);
|
||||
else
|
||||
fprintf (fp, "TCK: %02X (bad; calculated %02X)\n", *atr, chksum);
|
||||
|
||||
atrlen--;
|
||||
if (atrlen)
|
||||
fprintf (fp, "error: %u bytes garbage at end of ATR\n",
|
||||
(unsigned int)atrlen );
|
||||
|
||||
bailout:
|
||||
xfree (atrbuffer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
28
scd/atr.h
Normal file
28
scd/atr.h
Normal file
@ -0,0 +1,28 @@
|
||||
/* atr.h - ISO 7816 ATR functions
|
||||
* Copyright (C) 2003 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef ATR_H
|
||||
#define ATR_H
|
||||
|
||||
int atr_dump (int slot, FILE *fp);
|
||||
|
||||
|
||||
|
||||
#endif /*ATR_H*/
|
260
scd/card-dinsig.c
Normal file
260
scd/card-dinsig.c
Normal file
@ -0,0 +1,260 @@
|
||||
/* card-dinsig.c - German signature law (DINSIG) functions
|
||||
* Copyright (C) 2002 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
/* The German signature law and its bylaw (SigG and SigV) is currently
|
||||
used with an interface specification described in DIN V 66291-1.
|
||||
The AID to be used is: 'D27600006601'.
|
||||
|
||||
The file IDs for certificates utilize the generic format:
|
||||
Cxyz
|
||||
C being the hex digit 'C' (12).
|
||||
x being the service indicator:
|
||||
'0' := SigG conform digital signature.
|
||||
'1' := entity authentication.
|
||||
'2' := key encipherment.
|
||||
'3' := data encipherment.
|
||||
'4' := key agreement.
|
||||
other values are reserved for future use.
|
||||
y being the security environment number using '0' for cards
|
||||
not supporting a SE number.
|
||||
z being the certificate type:
|
||||
'0' := C.CH (base certificate of ard holder) or C.ICC.
|
||||
'1' .. '7' := C.CH (business or professional certificate
|
||||
of card holder.
|
||||
'8' .. 'D' := C.CA (certificate of a CA issue by the Root-CA).
|
||||
'E' := C.RCA (self certified certificate of the Root-CA).
|
||||
'F' := reserved.
|
||||
|
||||
The file IDs used by default are:
|
||||
'1F00' EF.SSD (security service descriptor). [o,o]
|
||||
'2F02' EF.GDO (global data objects) [m,m]
|
||||
'A000' EF.PROT (signature log). Cyclic file with 20 records of 53 byte.
|
||||
Read and update after user authentication. [o,o]
|
||||
'B000' EF.PK.RCA.DS (public keys of Root-CA). Size is 512b or size
|
||||
of keys. [m (unless a 'C00E' is present),m]
|
||||
'B001' EF.PK.CA.DS (public keys of CAs). Size is 512b or size
|
||||
of keys. [o,o]
|
||||
'C00n' EF.C.CH.DS (digital signature certificate of card holder)
|
||||
with n := 0 .. 7. Size is 2k or size of cert. Read and
|
||||
update allowed after user authentication. [m,m]
|
||||
'C00m' EF.C.CA.DS (digital signature certificate of CA)
|
||||
with m := 8 .. E. Size is 1k or size of cert. Read always
|
||||
allowed, update after uder authentication. [o,o]
|
||||
'C100' EF.C.ICC.AUT (AUT certificate of ICC) [o,m]
|
||||
'C108' EF.C.CA.AUT (AUT certificate of CA) [o,m]
|
||||
'D000' EF.DM (display message) [-,m]
|
||||
|
||||
The letters in brackets indicate optional or mandatory files: The
|
||||
first for card terminals under full control and the second for
|
||||
"business" card terminals.
|
||||
|
||||
FIXME: Needs a lot more explanation.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include <config.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef HAVE_OPENSC
|
||||
#include <opensc/pkcs15.h>
|
||||
#include <ksba.h>
|
||||
|
||||
#include "scdaemon.h"
|
||||
#include "card-common.h"
|
||||
|
||||
static int dinsig_read_cert (CARD card, const char *certidstr,
|
||||
unsigned char **cert, size_t *ncert);
|
||||
|
||||
|
||||
|
||||
/* See card.c for interface description. Frankly we don't do any real
|
||||
enumeration but just check whether the well know files are
|
||||
available. */
|
||||
static int
|
||||
dinsig_enum_keypairs (CARD card, int idx,
|
||||
unsigned char *keygrip, char **keyid)
|
||||
{
|
||||
int rc;
|
||||
unsigned char *buf;
|
||||
size_t buflen;
|
||||
KsbaError krc;
|
||||
KsbaCert cert;
|
||||
|
||||
/* fixme: We should locate the application via the EF(DIR) and not
|
||||
assume a Netkey card */
|
||||
if (!idx)
|
||||
rc = dinsig_read_cert (card, "DINSIG-DF01.C000", &buf, &buflen);
|
||||
else if (idx == 1)
|
||||
rc = dinsig_read_cert (card, "DINSIG-DF01.C200", &buf, &buflen);
|
||||
else
|
||||
rc = -1;
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
cert = ksba_cert_new ();
|
||||
if (!cert)
|
||||
{
|
||||
gpg_error_t tmperr = out_of_core ();
|
||||
xfree (buf);
|
||||
return tmperr;
|
||||
}
|
||||
|
||||
krc = ksba_cert_init_from_mem (cert, buf, buflen);
|
||||
xfree (buf);
|
||||
if (krc)
|
||||
{
|
||||
log_error ("failed to parse the certificate at idx %d: %s\n",
|
||||
idx, ksba_strerror (krc));
|
||||
ksba_cert_release (cert);
|
||||
return gpg_error (GPG_ERR_CARD);
|
||||
}
|
||||
if (card_help_get_keygrip (cert, keygrip))
|
||||
{
|
||||
log_error ("failed to calculate the keygrip at index %d\n", idx);
|
||||
ksba_cert_release (cert);
|
||||
return gpg_error (GPG_ERR_CARD);
|
||||
}
|
||||
ksba_cert_release (cert);
|
||||
|
||||
/* return the iD */
|
||||
if (keyid)
|
||||
{
|
||||
*keyid = xtrymalloc (17);
|
||||
if (!*keyid)
|
||||
return out_of_core ();
|
||||
if (!idx)
|
||||
strcpy (*keyid, "DINSIG-DF01.C000");
|
||||
else
|
||||
strcpy (*keyid, "DINSIG-DF01.C200");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* See card.c for interface description */
|
||||
static int
|
||||
dinsig_read_cert (CARD card, const char *certidstr,
|
||||
unsigned char **cert, size_t *ncert)
|
||||
{
|
||||
int rc;
|
||||
struct sc_path path;
|
||||
struct sc_file *file;
|
||||
unsigned char *buf;
|
||||
int buflen;
|
||||
|
||||
if (!strcmp (certidstr, "DINSIG-DF01.C000"))
|
||||
sc_format_path ("3F00DF01C000", &path);
|
||||
else if (!strcmp (certidstr, "DINSIG-DF01.C200"))
|
||||
sc_format_path ("3F00DF01C200", &path);
|
||||
else
|
||||
return gpg_error (GPG_ERR_INV_ID);
|
||||
|
||||
rc = sc_select_file (card->scard, &path, &file);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("sc_select_file failed: %s\n", sc_strerror (rc));
|
||||
return map_sc_err (rc);
|
||||
}
|
||||
if (file->type != SC_FILE_TYPE_WORKING_EF
|
||||
|| file->ef_structure != SC_FILE_EF_TRANSPARENT)
|
||||
{
|
||||
log_error ("wrong type or structure of certificate EF\n");
|
||||
sc_file_free (file);
|
||||
return gpg_error (GPG_ERR_CARD);
|
||||
}
|
||||
if (file->size < 20) /* check against a somewhat arbitrary length */
|
||||
{
|
||||
log_error ("certificate EF too short\n");
|
||||
sc_file_free (file);
|
||||
return gpg_error (GPG_ERR_CARD);
|
||||
}
|
||||
buf = xtrymalloc (file->size);
|
||||
if (!buf)
|
||||
{
|
||||
gpg_error_t tmperr = out_of_core ();
|
||||
sc_file_free (file);
|
||||
return tmperr;
|
||||
}
|
||||
|
||||
rc = sc_read_binary (card->scard, 0, buf, file->size, 0);
|
||||
if (rc >= 0 && rc != file->size)
|
||||
{
|
||||
log_error ("short read on certificate EF\n");
|
||||
sc_file_free (file);
|
||||
xfree (buf);
|
||||
return gpg_error (GPG_ERR_CARD);
|
||||
}
|
||||
sc_file_free (file);
|
||||
if (rc < 0)
|
||||
{
|
||||
log_error ("error reading certificate EF: %s\n", sc_strerror (rc));
|
||||
xfree (buf);
|
||||
return map_sc_err (rc);
|
||||
}
|
||||
buflen = rc;
|
||||
|
||||
/* The object is not a plain certificate but wrapped into id-at
|
||||
userCertificate - fixme: we should check the specs and decided
|
||||
whether libksba should support it */
|
||||
if (buflen > 9 && buf[0] == 0x30 && buf[4] == 6 && buf[5] == 3
|
||||
&& buf[6] == 0x55 && buf[7] == 4 && buf[8] == 0x24)
|
||||
{
|
||||
/* We have to strip the padding. Although this is a good idea
|
||||
anyway, we have to do it due to a KSBA problem; KSBA does not
|
||||
work correct when the buffer is larger than the ASN.1
|
||||
structure and the certificates here are padded with FF. So
|
||||
as a workaround we look at the outer structure to get the
|
||||
size of the entire thing and adjust the buflen. We can only
|
||||
do this when there is a 2 byte length field */
|
||||
size_t seqlen;
|
||||
if (buf[1] == 0x82)
|
||||
{
|
||||
seqlen = ((buf[2] << 8) | buf[3]) + 4;
|
||||
if (seqlen < buflen)
|
||||
buflen = seqlen;
|
||||
}
|
||||
memmove (buf, buf+9, buflen-9);
|
||||
buflen -= 9;
|
||||
}
|
||||
|
||||
*cert = buf;
|
||||
*ncert = buflen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Bind our operations to the card */
|
||||
void
|
||||
card_dinsig_bind (CARD card)
|
||||
{
|
||||
card->fnc.enum_keypairs = dinsig_enum_keypairs;
|
||||
card->fnc.read_cert = dinsig_read_cert;
|
||||
|
||||
}
|
||||
#endif /*HAVE_OPENSC*/
|
624
sm/base64.c
Normal file
624
sm/base64.c
Normal file
@ -0,0 +1,624 @@
|
||||
/* base64.c
|
||||
* Copyright (C) 2001, 2003 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <ksba.h>
|
||||
|
||||
#include "gpgsm.h"
|
||||
#include "i18n.h"
|
||||
|
||||
#ifdef HAVE_DOSISH_SYSTEM
|
||||
#define LF "\r\n"
|
||||
#else
|
||||
#define LF "\n"
|
||||
#endif
|
||||
|
||||
/* data used by the reader callbacks */
|
||||
struct reader_cb_parm_s {
|
||||
FILE *fp;
|
||||
unsigned char line[1024];
|
||||
int linelen;
|
||||
int readpos;
|
||||
int have_lf;
|
||||
unsigned long line_counter;
|
||||
|
||||
int autodetect; /* try to detect the input encoding */
|
||||
int assume_pem; /* assume input encoding is PEM */
|
||||
int assume_base64; /* assume input is base64 encoded */
|
||||
|
||||
int identified;
|
||||
int is_pem;
|
||||
int is_base64;
|
||||
int stop_seen;
|
||||
int might_be_smime;
|
||||
|
||||
struct {
|
||||
int idx;
|
||||
unsigned char val;
|
||||
int stop_seen;
|
||||
} base64;
|
||||
};
|
||||
|
||||
/* data used by the writer callbacks */
|
||||
struct writer_cb_parm_s {
|
||||
FILE *fp;
|
||||
const char *pem_name;
|
||||
|
||||
int wrote_begin;
|
||||
int did_finish;
|
||||
|
||||
struct {
|
||||
int idx;
|
||||
int quad_count;
|
||||
unsigned char radbuf[4];
|
||||
} base64;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/* context for this module's functions */
|
||||
struct base64_context_s {
|
||||
union {
|
||||
struct reader_cb_parm_s rparm;
|
||||
struct writer_cb_parm_s wparm;
|
||||
} u;
|
||||
};
|
||||
|
||||
|
||||
/* The base-64 character list */
|
||||
static unsigned char bintoasc[64] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789+/";
|
||||
/* The reverse base-64 list */
|
||||
static unsigned char asctobin[256] = {
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
|
||||
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
|
||||
0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
|
||||
0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
|
||||
0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
|
||||
0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff
|
||||
};
|
||||
|
||||
|
||||
static int
|
||||
has_only_base64 (const unsigned char *line, int linelen)
|
||||
{
|
||||
if (linelen < 20)
|
||||
return 0;
|
||||
for (; linelen; line++, linelen--)
|
||||
{
|
||||
if (*line == '\n' || (linelen > 1 && *line == '\r' && line[1] == '\n'))
|
||||
break;
|
||||
if ( !strchr (bintoasc, *line) )
|
||||
return 0;
|
||||
}
|
||||
return 1; /* yes */
|
||||
}
|
||||
|
||||
static int
|
||||
is_empty_line (const unsigned char *line, int linelen)
|
||||
{
|
||||
if (linelen >= 2 && *line == '\r' && line[1] == '\n')
|
||||
return 1;
|
||||
if (linelen >= 1 && *line == '\n')
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
base64_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
|
||||
{
|
||||
struct reader_cb_parm_s *parm = cb_value;
|
||||
size_t n;
|
||||
int c, c2;
|
||||
|
||||
*nread = 0;
|
||||
if (!buffer)
|
||||
return -1; /* not supported */
|
||||
|
||||
next:
|
||||
if (!parm->linelen)
|
||||
{
|
||||
/* read an entire line or up to the size of the buffer */
|
||||
parm->line_counter++;
|
||||
parm->have_lf = 0;
|
||||
for (n=0; n < DIM(parm->line);)
|
||||
{
|
||||
c = getc (parm->fp);
|
||||
if (c == EOF)
|
||||
{
|
||||
if (ferror (parm->fp))
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
parm->line[n++] = c;
|
||||
if (c == '\n')
|
||||
{
|
||||
parm->have_lf = 1;
|
||||
/* Fixme: we need to skip overlong lines while detecting
|
||||
the dashed lines */
|
||||
break;
|
||||
}
|
||||
}
|
||||
parm->linelen = n;
|
||||
if (!n)
|
||||
return -1; /* eof */
|
||||
parm->readpos = 0;
|
||||
}
|
||||
|
||||
if (!parm->identified)
|
||||
{
|
||||
if (!parm->autodetect)
|
||||
{
|
||||
if (parm->assume_pem)
|
||||
{
|
||||
/* wait for the header line */
|
||||
parm->linelen = parm->readpos = 0;
|
||||
if (!parm->have_lf || strncmp (parm->line, "-----BEGIN ", 11)
|
||||
|| !strncmp (parm->line+11, "PGP ", 4))
|
||||
goto next;
|
||||
parm->is_pem = 1;
|
||||
}
|
||||
else if (parm->assume_base64)
|
||||
parm->is_base64 = 1;
|
||||
}
|
||||
else if (parm->line_counter == 1 && !parm->have_lf)
|
||||
{
|
||||
/* first line too long - assume DER encoding */
|
||||
parm->is_pem = 0;
|
||||
}
|
||||
else if (parm->line_counter == 1 && parm->linelen && *parm->line == 0x30)
|
||||
{
|
||||
/* the very first byte does pretty much look like a SEQUENCE tag*/
|
||||
parm->is_pem = 0;
|
||||
}
|
||||
else if ( parm->have_lf && !strncmp (parm->line, "-----BEGIN ", 11)
|
||||
&& strncmp (parm->line+11, "PGP ", 4) )
|
||||
{
|
||||
/* Fixme: we must only compare if the line really starts at
|
||||
the beginning */
|
||||
parm->is_pem = 1;
|
||||
parm->linelen = parm->readpos = 0;
|
||||
}
|
||||
else if ( parm->have_lf && parm->line_counter == 1
|
||||
&& parm->linelen >= 13
|
||||
&& !ascii_memcasecmp (parm->line, "Content-Type:", 13))
|
||||
{ /* might be a S/MIME body */
|
||||
parm->might_be_smime = 1;
|
||||
parm->linelen = parm->readpos = 0;
|
||||
goto next;
|
||||
}
|
||||
else if (parm->might_be_smime == 1
|
||||
&& is_empty_line (parm->line, parm->linelen))
|
||||
{
|
||||
parm->might_be_smime = 2;
|
||||
parm->linelen = parm->readpos = 0;
|
||||
goto next;
|
||||
}
|
||||
else if (parm->might_be_smime == 2)
|
||||
{
|
||||
parm->might_be_smime = 0;
|
||||
if ( !has_only_base64 (parm->line, parm->linelen))
|
||||
{
|
||||
parm->linelen = parm->readpos = 0;
|
||||
goto next;
|
||||
}
|
||||
parm->is_pem = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
parm->linelen = parm->readpos = 0;
|
||||
goto next;
|
||||
}
|
||||
parm->identified = 1;
|
||||
parm->base64.stop_seen = 0;
|
||||
parm->base64.idx = 0;
|
||||
}
|
||||
|
||||
|
||||
n = 0;
|
||||
if (parm->is_pem || parm->is_base64)
|
||||
{
|
||||
if (parm->is_pem && parm->have_lf
|
||||
&& !strncmp (parm->line, "-----END ", 9))
|
||||
{
|
||||
parm->identified = 0;
|
||||
parm->linelen = parm->readpos = 0;
|
||||
/* let us return 0 */
|
||||
}
|
||||
else if (parm->stop_seen)
|
||||
{ /* skip the rest of the line */
|
||||
parm->linelen = parm->readpos = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int idx = parm->base64.idx;
|
||||
unsigned char val = parm->base64.val;
|
||||
|
||||
while (n < count && parm->readpos < parm->linelen )
|
||||
{
|
||||
c = parm->line[parm->readpos++];
|
||||
if (c == '\n' || c == ' ' || c == '\r' || c == '\t')
|
||||
continue;
|
||||
if (c == '=')
|
||||
{ /* pad character: stop */
|
||||
if (idx == 1)
|
||||
buffer[n++] = val;
|
||||
parm->stop_seen = 1;
|
||||
break;
|
||||
}
|
||||
if( (c = asctobin[(c2=c)]) == 255 )
|
||||
{
|
||||
log_error (_("invalid radix64 character %02x skipped\n"),
|
||||
c2);
|
||||
continue;
|
||||
}
|
||||
switch (idx)
|
||||
{
|
||||
case 0:
|
||||
val = c << 2;
|
||||
break;
|
||||
case 1:
|
||||
val |= (c>>4)&3;
|
||||
buffer[n++] = val;
|
||||
val = (c<<4)&0xf0;
|
||||
break;
|
||||
case 2:
|
||||
val |= (c>>2)&15;
|
||||
buffer[n++] = val;
|
||||
val = (c<<6)&0xc0;
|
||||
break;
|
||||
case 3:
|
||||
val |= c&0x3f;
|
||||
buffer[n++] = val;
|
||||
break;
|
||||
}
|
||||
idx = (idx+1) % 4;
|
||||
}
|
||||
if (parm->readpos == parm->linelen)
|
||||
parm->linelen = parm->readpos = 0;
|
||||
|
||||
parm->base64.idx = idx;
|
||||
parm->base64.val = val;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* DER encoded */
|
||||
while (n < count && parm->readpos < parm->linelen)
|
||||
buffer[n++] = parm->line[parm->readpos++];
|
||||
if (parm->readpos == parm->linelen)
|
||||
parm->linelen = parm->readpos = 0;
|
||||
}
|
||||
|
||||
*nread = n;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int
|
||||
simple_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
|
||||
{
|
||||
struct reader_cb_parm_s *parm = cb_value;
|
||||
size_t n;
|
||||
int c = 0;
|
||||
|
||||
*nread = 0;
|
||||
if (!buffer)
|
||||
return -1; /* not supported */
|
||||
|
||||
for (n=0; n < count; n++)
|
||||
{
|
||||
c = getc (parm->fp);
|
||||
if (c == EOF)
|
||||
{
|
||||
if ( ferror (parm->fp) )
|
||||
return -1;
|
||||
if (n)
|
||||
break; /* return what we have before an EOF */
|
||||
return -1;
|
||||
}
|
||||
*(byte *)buffer++ = c;
|
||||
}
|
||||
|
||||
*nread = n;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static int
|
||||
base64_writer_cb (void *cb_value, const void *buffer, size_t count)
|
||||
{
|
||||
struct writer_cb_parm_s *parm = cb_value;
|
||||
unsigned char radbuf[4];
|
||||
int i, c, idx, quad_count;
|
||||
const unsigned char *p;
|
||||
FILE *fp = parm->fp;
|
||||
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
if (!parm->wrote_begin)
|
||||
{
|
||||
if (parm->pem_name)
|
||||
{
|
||||
fputs ("-----BEGIN ", fp);
|
||||
fputs (parm->pem_name, fp);
|
||||
fputs ("-----\n", fp);
|
||||
}
|
||||
parm->wrote_begin = 1;
|
||||
parm->base64.idx = 0;
|
||||
parm->base64.quad_count = 0;
|
||||
}
|
||||
|
||||
idx = parm->base64.idx;
|
||||
quad_count = parm->base64.quad_count;
|
||||
for (i=0; i < idx; i++)
|
||||
radbuf[i] = parm->base64.radbuf[i];
|
||||
|
||||
for (p=buffer; count; p++, count--)
|
||||
{
|
||||
radbuf[idx++] = *p;
|
||||
if (idx > 2)
|
||||
{
|
||||
idx = 0;
|
||||
c = bintoasc[(*radbuf >> 2) & 077];
|
||||
putc (c, fp);
|
||||
c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077];
|
||||
putc (c, fp);
|
||||
c = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
|
||||
putc (c, fp);
|
||||
c = bintoasc[radbuf[2]&077];
|
||||
putc (c, fp);
|
||||
if (++quad_count >= (64/4))
|
||||
{
|
||||
fputs (LF, fp);
|
||||
quad_count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i=0; i < idx; i++)
|
||||
parm->base64.radbuf[i] = radbuf[i];
|
||||
parm->base64.idx = idx;
|
||||
parm->base64.quad_count = quad_count;
|
||||
|
||||
return ferror (fp) ? KSBA_Write_Error:0;
|
||||
}
|
||||
|
||||
static int
|
||||
base64_finish_write (struct writer_cb_parm_s *parm)
|
||||
{
|
||||
unsigned char radbuf[4];
|
||||
int i, c, idx, quad_count;
|
||||
FILE *fp = parm->fp;
|
||||
|
||||
if (!parm->wrote_begin)
|
||||
return 0; /* nothing written */
|
||||
|
||||
/* flush the base64 encoding */
|
||||
idx = parm->base64.idx;
|
||||
quad_count = parm->base64.quad_count;
|
||||
for (i=0; i < idx; i++)
|
||||
radbuf[i] = parm->base64.radbuf[i];
|
||||
|
||||
if (idx)
|
||||
{
|
||||
c = bintoasc[(*radbuf>>2)&077];
|
||||
putc (c, fp);
|
||||
if (idx == 1)
|
||||
{
|
||||
c = bintoasc[((*radbuf << 4) & 060) & 077];
|
||||
putc (c, fp);
|
||||
putc ('=', fp);
|
||||
putc ('=', fp);
|
||||
}
|
||||
else
|
||||
{
|
||||
c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];
|
||||
putc (c, fp);
|
||||
c = bintoasc[((radbuf[1] << 2) & 074) & 077];
|
||||
putc (c, fp);
|
||||
putc ('=', fp);
|
||||
|
||||
}
|
||||
if (++quad_count >= (64/4))
|
||||
{
|
||||
fputs (LF, fp);
|
||||
quad_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (quad_count)
|
||||
fputs (LF, fp);
|
||||
|
||||
if (parm->pem_name)
|
||||
{
|
||||
fputs ("-----END ", fp);
|
||||
fputs (parm->pem_name, fp);
|
||||
fputs ("-----\n", fp);
|
||||
}
|
||||
return ferror (fp)? gpg_error (gpg_err_code_from_errno (errno)) : 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Create a reader for the given file descriptor. Depending on the
|
||||
control information an input decoding is automagically choosen.
|
||||
The function returns a Base64Context object which must be passed to
|
||||
the gpgme_destroy_reader function. The created KsbaReader object
|
||||
is also returned, but the caller must not call the
|
||||
ksba_reader_release function on. */
|
||||
int
|
||||
gpgsm_create_reader (Base64Context *ctx,
|
||||
CTRL ctrl, FILE *fp, KsbaReader *r_reader)
|
||||
{
|
||||
int rc;
|
||||
KsbaReader r;
|
||||
|
||||
*r_reader = NULL;
|
||||
*ctx = xtrycalloc (1, sizeof **ctx);
|
||||
if (!*ctx)
|
||||
return OUT_OF_CORE (errno);
|
||||
|
||||
r = ksba_reader_new ();
|
||||
if (!r)
|
||||
{
|
||||
xfree (*ctx); *ctx = NULL;
|
||||
return gpg_error (GPG_ERR_ENOMEM);
|
||||
}
|
||||
|
||||
(*ctx)->u.rparm.fp = fp;
|
||||
if (ctrl->is_pem)
|
||||
{
|
||||
(*ctx)->u.rparm.assume_pem = 1;
|
||||
(*ctx)->u.rparm.assume_base64 = 1;
|
||||
rc = ksba_reader_set_cb (r, base64_reader_cb, &(*ctx)->u.rparm);
|
||||
}
|
||||
else if (ctrl->is_base64)
|
||||
{
|
||||
(*ctx)->u.rparm.assume_base64 = 1;
|
||||
rc = ksba_reader_set_cb (r, base64_reader_cb, &(*ctx)->u.rparm);
|
||||
}
|
||||
else if (ctrl->autodetect_encoding)
|
||||
{
|
||||
(*ctx)->u.rparm.autodetect = 1;
|
||||
rc = ksba_reader_set_cb (r, base64_reader_cb, &(*ctx)->u.rparm);
|
||||
}
|
||||
else
|
||||
rc = ksba_reader_set_cb (r, simple_reader_cb, &(*ctx)->u.rparm);
|
||||
|
||||
if (rc)
|
||||
{
|
||||
ksba_reader_release (r);
|
||||
xfree (*ctx); *ctx = NULL;
|
||||
return map_ksba_err (rc);
|
||||
}
|
||||
|
||||
*r_reader = r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
gpgsm_destroy_reader (Base64Context ctx)
|
||||
{
|
||||
xfree (ctx);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Create a writer for the given stream. Depending on the control
|
||||
information an output encoding is automagically choosen. The
|
||||
function returns a Base64Context object which must be passed to the
|
||||
gpgme_destroy_writer function. The created KsbaWriter object is
|
||||
also returned, but the caller must not call the ksba_reader_release
|
||||
function on. */
|
||||
int
|
||||
gpgsm_create_writer (Base64Context *ctx,
|
||||
CTRL ctrl, FILE *fp, KsbaWriter *r_writer)
|
||||
{
|
||||
int rc;
|
||||
KsbaWriter w;
|
||||
|
||||
*r_writer = NULL;
|
||||
*ctx = xtrycalloc (1, sizeof **ctx);
|
||||
if (!*ctx)
|
||||
return OUT_OF_CORE (errno);
|
||||
|
||||
w = ksba_writer_new ();
|
||||
if (!w)
|
||||
{
|
||||
xfree (*ctx); *ctx = NULL;
|
||||
return gpg_error (GPG_ERR_ENOMEM);
|
||||
}
|
||||
|
||||
if (ctrl->create_pem || ctrl->create_base64)
|
||||
{
|
||||
(*ctx)->u.wparm.fp = fp;
|
||||
if (ctrl->create_pem)
|
||||
(*ctx)->u.wparm.pem_name = ctrl->pem_name? ctrl->pem_name
|
||||
: "CMS OBJECT";
|
||||
rc = ksba_writer_set_cb (w, base64_writer_cb, &(*ctx)->u.wparm);
|
||||
}
|
||||
else
|
||||
rc = ksba_writer_set_file (w, fp);
|
||||
|
||||
if (rc)
|
||||
{
|
||||
ksba_writer_release (w);
|
||||
xfree (*ctx); *ctx = NULL;
|
||||
return map_ksba_err (rc);
|
||||
}
|
||||
|
||||
*r_writer = w;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
gpgsm_finish_writer (Base64Context ctx)
|
||||
{
|
||||
struct writer_cb_parm_s *parm;
|
||||
|
||||
if (!ctx)
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
parm = &ctx->u.wparm;
|
||||
if (parm->did_finish)
|
||||
return 0; /* already done */
|
||||
parm->did_finish = 1;
|
||||
if (!parm->fp)
|
||||
return 0; /* callback was not used */
|
||||
return base64_finish_write (parm);
|
||||
}
|
||||
|
||||
void
|
||||
gpgsm_destroy_writer (Base64Context ctx)
|
||||
{
|
||||
xfree (ctx);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user