mirror of
git://git.gnupg.org/gnupg.git
synced 2024-11-10 21:38:50 +01:00
gpgsm: New option --assert-signer
* sm/gpgsm.c (oAssertSigner, oNoop): New. (opts): Add option --assert-signer. (assert_signer_true): New var. (main): Set new option. (gpgsm_exit): Handle assert_signer_true. * sm/gpgsm.h (opt): Add field assert_signer_list. * sm/verify.c (is_x509_fingerprint): New. (check_assert_signer_list): New. (gpgsm_verify): Handle option. -- GnuPG-bug-id: 7286
This commit is contained in:
parent
f7f939234b
commit
54e06273c0
2
NEWS
2
NEWS
@ -22,6 +22,8 @@ Noteworthy changes in version 2.4.6 (unreleased)
|
|||||||
|
|
||||||
* gpg: New option --proc-all-sigs. [T7261]
|
* gpg: New option --proc-all-sigs. [T7261]
|
||||||
|
|
||||||
|
* gpgsm: New option --assert-signer. [T7286]
|
||||||
|
|
||||||
* gpgsm: Emit user IDs with an empty Subject also in colon mode.
|
* gpgsm: Emit user IDs with an empty Subject also in colon mode.
|
||||||
[T7171]
|
[T7171]
|
||||||
|
|
||||||
|
@ -732,6 +732,21 @@ instead to make sure that the gpgsm process exits with a failure if
|
|||||||
the compliance rules are not fulfilled. Note that this option has
|
the compliance rules are not fulfilled. Note that this option has
|
||||||
currently an effect only in "de-vs" mode.
|
currently an effect only in "de-vs" mode.
|
||||||
|
|
||||||
|
@item --assert-signer @var{fpr_or_file}
|
||||||
|
@opindex assert-signer
|
||||||
|
This option checks whether at least one valid signature on a file has
|
||||||
|
been made with the specified key. The key is either specified as a
|
||||||
|
fingerprint or a file listing fingerprints. The fingerprint must be
|
||||||
|
given or listed in compact format (no colons or spaces in between).
|
||||||
|
As of now only SHA-1 fingerprints are allowed. This option can be
|
||||||
|
given multiple times and each fingerprint is checked against the
|
||||||
|
signing key as well as the corresponding primary key. If
|
||||||
|
@var{fpr_or_file} specifies a file, empty lines are ignored as well as
|
||||||
|
all lines starting with a hash sign. With this option gpgsm is
|
||||||
|
guaranteed to return with an exit code of 0 if and only if a signature
|
||||||
|
has been encountered, is valid, and the key matches one of the
|
||||||
|
fingerprints given by this option.
|
||||||
|
|
||||||
@item --always-trust
|
@item --always-trust
|
||||||
@opindex always-trust
|
@opindex always-trust
|
||||||
Force encryption to the specified certificates without any validation
|
Force encryption to the specified certificates without any validation
|
||||||
|
25
sm/gpgsm.c
25
sm/gpgsm.c
@ -216,7 +216,10 @@ enum cmd_and_opt_values {
|
|||||||
oCompatibilityFlags,
|
oCompatibilityFlags,
|
||||||
oKbxBufferSize,
|
oKbxBufferSize,
|
||||||
oAlwaysTrust,
|
oAlwaysTrust,
|
||||||
oNoAutostart
|
oNoAutostart,
|
||||||
|
oAssertSigner,
|
||||||
|
|
||||||
|
oNoop
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -310,6 +313,7 @@ static gpgrt_opt_t opts[] = {
|
|||||||
N_("|FILE|take policy information from FILE")),
|
N_("|FILE|take policy information from FILE")),
|
||||||
ARGPARSE_s_s (oCompliance, "compliance", "@"),
|
ARGPARSE_s_s (oCompliance, "compliance", "@"),
|
||||||
ARGPARSE_p_u (oMinRSALength, "min-rsa-length", "@"),
|
ARGPARSE_p_u (oMinRSALength, "min-rsa-length", "@"),
|
||||||
|
ARGPARSE_s_s (oAssertSigner, "assert-signer", "@"),
|
||||||
ARGPARSE_s_n (oNoCommonCertsImport, "no-common-certs-import", "@"),
|
ARGPARSE_s_n (oNoCommonCertsImport, "no-common-certs-import", "@"),
|
||||||
ARGPARSE_s_s (oIgnoreCertExtension, "ignore-cert-extension", "@"),
|
ARGPARSE_s_s (oIgnoreCertExtension, "ignore-cert-extension", "@"),
|
||||||
ARGPARSE_s_s (oIgnoreCertWithOID, "ignore-cert-with-oid", "@"),
|
ARGPARSE_s_s (oIgnoreCertWithOID, "ignore-cert-with-oid", "@"),
|
||||||
@ -500,6 +504,9 @@ static struct compatibility_flags_s compatibility_flags [] =
|
|||||||
|
|
||||||
/* Global variable to keep an error count. */
|
/* Global variable to keep an error count. */
|
||||||
int gpgsm_errors_seen = 0;
|
int gpgsm_errors_seen = 0;
|
||||||
|
/* If opt.assert_signer_list is used and this variable is not true
|
||||||
|
* gpg will be forced to return EXIT_FAILURE. */
|
||||||
|
int assert_signer_true = 0;
|
||||||
|
|
||||||
/* It is possible that we are currentlu running under setuid permissions */
|
/* It is possible that we are currentlu running under setuid permissions */
|
||||||
static int maybe_setuid = 1;
|
static int maybe_setuid = 1;
|
||||||
@ -1517,6 +1524,12 @@ main ( int argc, char **argv)
|
|||||||
keybox_set_buffersize (pargs.r.ret_ulong, 0);
|
keybox_set_buffersize (pargs.r.ret_ulong, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case oAssertSigner:
|
||||||
|
add_to_strlist (&opt.assert_signer_list, pargs.r.ret_str);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case oNoop: break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (configname)
|
if (configname)
|
||||||
pargs.err = ARGPARSE_PRINT_WARNING;
|
pargs.err = ARGPARSE_PRINT_WARNING;
|
||||||
@ -2265,6 +2278,15 @@ emergency_cleanup (void)
|
|||||||
void
|
void
|
||||||
gpgsm_exit (int rc)
|
gpgsm_exit (int rc)
|
||||||
{
|
{
|
||||||
|
if (rc)
|
||||||
|
;
|
||||||
|
else if (log_get_errorcount(0))
|
||||||
|
rc = 2;
|
||||||
|
else if (gpgsm_errors_seen)
|
||||||
|
rc = 1;
|
||||||
|
else if (opt.assert_signer_list && !assert_signer_true)
|
||||||
|
rc = 1;
|
||||||
|
|
||||||
gcry_control (GCRYCTL_UPDATE_RANDOM_SEED_FILE);
|
gcry_control (GCRYCTL_UPDATE_RANDOM_SEED_FILE);
|
||||||
if (opt.debug & DBG_MEMSTAT_VALUE)
|
if (opt.debug & DBG_MEMSTAT_VALUE)
|
||||||
{
|
{
|
||||||
@ -2274,7 +2296,6 @@ gpgsm_exit (int rc)
|
|||||||
if (opt.debug)
|
if (opt.debug)
|
||||||
gcry_control (GCRYCTL_DUMP_SECMEM_STATS );
|
gcry_control (GCRYCTL_DUMP_SECMEM_STATS );
|
||||||
emergency_cleanup ();
|
emergency_cleanup ();
|
||||||
rc = rc? rc : log_get_errorcount(0)? 2 : gpgsm_errors_seen? 1 : 0;
|
|
||||||
exit (rc);
|
exit (rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,6 +181,10 @@ struct
|
|||||||
* attribute values. */
|
* attribute values. */
|
||||||
strlist_t attributes;
|
strlist_t attributes;
|
||||||
|
|
||||||
|
/* The list of --assert-signer option values. Note: The values are
|
||||||
|
* modified to uppercase if they represent a fingerrint */
|
||||||
|
strlist_t assert_signer_list;
|
||||||
|
|
||||||
/* Compatibility flags (COMPAT_FLAG_xxxx). */
|
/* Compatibility flags (COMPAT_FLAG_xxxx). */
|
||||||
unsigned int compat_flags;
|
unsigned int compat_flags;
|
||||||
} opt;
|
} opt;
|
||||||
@ -312,6 +316,7 @@ struct rootca_flags_s
|
|||||||
|
|
||||||
/*-- gpgsm.c --*/
|
/*-- gpgsm.c --*/
|
||||||
extern int gpgsm_errors_seen;
|
extern int gpgsm_errors_seen;
|
||||||
|
extern int assert_signer_true;
|
||||||
|
|
||||||
void gpgsm_exit (int rc);
|
void gpgsm_exit (int rc);
|
||||||
void gpgsm_init_default_ctrl (struct server_control_s *ctrl);
|
void gpgsm_init_default_ctrl (struct server_control_s *ctrl);
|
||||||
|
134
sm/verify.c
134
sm/verify.c
@ -37,6 +37,11 @@
|
|||||||
#include "../common/i18n.h"
|
#include "../common/i18n.h"
|
||||||
#include "../common/compliance.h"
|
#include "../common/compliance.h"
|
||||||
|
|
||||||
|
|
||||||
|
static void check_assert_signer_list (ctrl_t ctrl, const char *pkhex);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
strtimestamp_r (ksba_isotime_t atime)
|
strtimestamp_r (ksba_isotime_t atime)
|
||||||
{
|
{
|
||||||
@ -665,6 +670,8 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp)
|
|||||||
*keyexptime? keyexptime : "0",
|
*keyexptime? keyexptime : "0",
|
||||||
info_pkalgo, algo);
|
info_pkalgo, algo);
|
||||||
xfree (tstr);
|
xfree (tstr);
|
||||||
|
/* Handle the --assert-signer option. */
|
||||||
|
check_assert_signer_list (ctrl, fpr);
|
||||||
xfree (fpr);
|
xfree (fpr);
|
||||||
gpgsm_status (ctrl, STATUS_VALIDSIG, buf);
|
gpgsm_status (ctrl, STATUS_VALIDSIG, buf);
|
||||||
xfree (buf);
|
xfree (buf);
|
||||||
@ -766,3 +773,130 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp)
|
|||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
is_x509_fingerprint (const char *string)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
|
if (!string || !*string)
|
||||||
|
return 0;
|
||||||
|
for (n=0; hexdigitp (string); string++)
|
||||||
|
n++;
|
||||||
|
if (!*string && (n == 40 || n == 64))
|
||||||
|
return 1; /* SHA1 or SHA256 fingerprint. */
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* This function shall be called with the X.509 fingerprint iff a
|
||||||
|
* signature is fully valid. If the option --assert-signer is active
|
||||||
|
* it check whether the signing key matches one of the keys given by
|
||||||
|
* this option and if so, sets a global flag.
|
||||||
|
*
|
||||||
|
* Note: This function is mainly a copy of the fucntion from gpg. The
|
||||||
|
* status emit function and the single X.509 fingerprint makes the
|
||||||
|
* differences.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
check_assert_signer_list (ctrl_t ctrl, const char *pkhex)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
strlist_t item;
|
||||||
|
const char *fname;
|
||||||
|
estream_t fp = NULL;
|
||||||
|
int lnr;
|
||||||
|
int n, c;
|
||||||
|
char *p, *pend;
|
||||||
|
char line[256];
|
||||||
|
|
||||||
|
if (!opt.assert_signer_list)
|
||||||
|
return; /* Nothing to do. */
|
||||||
|
if (assert_signer_true)
|
||||||
|
return; /* Already one valid signature seen. */
|
||||||
|
|
||||||
|
for (item = opt.assert_signer_list; item; item = item->next)
|
||||||
|
{
|
||||||
|
if (is_x509_fingerprint (item->d))
|
||||||
|
{
|
||||||
|
ascii_strupr (item->d);
|
||||||
|
if (!strcmp (item->d, pkhex))
|
||||||
|
{
|
||||||
|
assert_signer_true = 1;
|
||||||
|
gpgsm_status (ctrl, STATUS_ASSERT_SIGNER, item->d);
|
||||||
|
if (!opt.quiet)
|
||||||
|
log_info ("asserted signer '%s'\n", item->d);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else /* Assume this is a file - read and compare. */
|
||||||
|
{
|
||||||
|
fname = item->d;
|
||||||
|
es_fclose (fp);
|
||||||
|
fp = es_fopen (fname, "r");
|
||||||
|
if (!fp)
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
log_error (_("error opening '%s': %s\n"),
|
||||||
|
fname, gpg_strerror (err));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
lnr = 0;
|
||||||
|
err = 0;
|
||||||
|
while (es_fgets (line, DIM(line)-1, fp))
|
||||||
|
{
|
||||||
|
lnr++;
|
||||||
|
|
||||||
|
n = strlen (line);
|
||||||
|
if (!n || line[n-1] != '\n')
|
||||||
|
{
|
||||||
|
/* Eat until end of line. */
|
||||||
|
while ( (c=es_getc (fp)) != EOF && c != '\n')
|
||||||
|
;
|
||||||
|
err = gpg_error (GPG_ERR_INCOMPLETE_LINE);
|
||||||
|
log_error (_("file '%s', line %d: %s\n"),
|
||||||
|
fname, lnr, gpg_strerror (err));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
line[--n] = 0; /* Chop the LF. */
|
||||||
|
if (n && line[n-1] == '\r')
|
||||||
|
line[--n] = 0; /* Chop an optional CR. */
|
||||||
|
|
||||||
|
/* Allow for empty lines and spaces */
|
||||||
|
for (p=line; spacep (p); p++)
|
||||||
|
;
|
||||||
|
if (!*p || *p == '#')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Get the first token and ignore trailing stuff. */
|
||||||
|
for (pend = p; *pend && !spacep (pend); pend++)
|
||||||
|
;
|
||||||
|
*pend = 0;
|
||||||
|
ascii_strupr (p);
|
||||||
|
|
||||||
|
if (!strcmp (p, pkhex))
|
||||||
|
{
|
||||||
|
assert_signer_true = 1;
|
||||||
|
gpgsm_status (ctrl, STATUS_ASSERT_SIGNER, p);
|
||||||
|
if (!opt.quiet)
|
||||||
|
log_info ("asserted signer '%s' (%s:%d)\n",
|
||||||
|
p, fname, lnr);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!err && !es_feof (fp))
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
log_error (_("error reading '%s', line %d: %s\n"),
|
||||||
|
fname, lnr, gpg_strerror (err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
leave:
|
||||||
|
es_fclose (fp);
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user